hi-ucs/front/src/views/abilityStatistics/components/AtlasResources.vue

792 lines
23 KiB
Vue

<template>
<div class="atlas-resources">
<div class="title">资源图谱</div>
<p class="line"></p>
<div class="main">
<div class="left">
<div
v-for="name in navList"
:key="name"
:class="{ select: name == navSelect }"
@click="selectNav(name)"
>
{{ name }}
</div>
</div>
<div
class="right"
:class="
navSelect.indexOf('应用领域') !== -1 &&
navSelect !== '应用领域-能力集'
? 'right-special'
: ''
"
>
<div
class="bubble"
v-if="navSelect.indexOf('能力集') > 0"
@click="changeDepartmentListFlag()"
>
<div
v-for="(item, index) in bubbleList"
:key="item.id"
class="bubble-item"
@click.stop.prevent="index == 0 ? showDepartmentList() : ''"
>
<a-tooltip>
<template #title>{{ item.name }}</template>
<span>
{{ item.name }}
</span>
</a-tooltip>
</div>
<article class="box">
<nav class="departmentList" v-show="departmentListFlag">
<span
v-for="dept in departmentList"
:key="dept.deptId || dept.type"
@click.stop.prevent="changeDept(dept)"
>
<a-tooltip>
<template #title>
{{ (dept.deptName || dept.type) + '(' + dept.total + ')' }}
</template>
<span>
{{ (dept.deptName || dept.type) + '(' + dept.total + ')' }}
</span>
</a-tooltip>
</span>
</nav>
</article>
<p>查看更多&gt;</p>
</div>
<div class="itemList" v-else-if="navSelect.indexOf('应用领域') > 0">
<div class="item" v-for="item in dataList" :key="item.deptId">
<div class="top" :class="item.show ? 'showBottom' : ''">
<div class="name">{{ item.deptName }}</div>
<a-progress
:percent="((item.provide.length / 15) * 100).toFixed(2)"
:showInfo="false"
/>
<div class="num">{{ item.provide.length }}个</div>
<div class="percentage">
{{ ((item.provide.length / 15) * 100).toFixed(2) }}%
</div>
<div class="img">
<down-outlined v-show="!item.show" @click="showDetails(item)" />
<up-outlined v-show="item.show" @click="showDetails(item)" />
</div>
</div>
<div class="bottom" v-show="item.show">
<div class="up">
<span>{{ item.deptName }}</span>
<span>{{ item.provide.length }}个</span>
<span>
{{ ((item.provide.length / 15) * 100).toFixed(2) }}%
</span>
</div>
<div class="down">
<div
class="type"
v-for="(type, index2) in allType"
:key="index2"
>
<a-radio
:checked="item.provide.indexOf(type) !== -1"
:disabled="true"
></a-radio>
{{ type }}
</div>
</div>
</div>
</div>
</div>
<div class="tableList" v-else-if="navSelect.indexOf('能力类型') > 0">
<a-table
:columns="columns"
:data-source="dataSource"
:pagination="false"
>
<template #bodyCell="{ column, text }">
<template v-if="column.dataIndex !== 'name'">
{{ text || 0 }}
</template>
</template>
</a-table>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { nextTick, ref } from 'vue'
import { UpOutlined, DownOutlined } from '@ant-design/icons-vue'
import {
capabilityShareCapabilitySet,
selectResourceListByDept,
competencyApplicantCompetencySet,
selectResourceListByApplyDept,
capabilityTypeCapabilitySet,
selectResourceListByType,
applicationAreaCapabilitySet,
selectResourceListByAppArea,
capabilitySharingPartyCapabilityType,
competencyApplicantCapabilityType,
provideDeptTopN,
applyDeptTopN,
} from '@/api/abilityStatistics'
// 左侧导航
const navList = ref([
'能力共享方-应用领域',
'能力共享方-能力类型',
'能力共享方-能力集',
'能力申请方-应用领域',
'能力申请方-能力类型',
'能力申请方-能力集',
'应用领域-能力集',
'能力类型-能力集',
])
const navSelect = ref('能力共享方-应用领域')
const departmentListFlag = ref(false)
// 点击导航
const selectNav = (name) => {
navSelect.value = name
departmentListFlag.value = false
if (name.indexOf('能力集') > 0) {
bubbleList.value = []
coordinate.value = []
switch (name) {
case '能力共享方-能力集':
capabilityShareCapabilitySet().then((res) => {
initBubbleList(res)
})
break
case '能力申请方-能力集':
competencyApplicantCompetencySet().then((res) => {
initBubbleList(res)
})
break
case '能力类型-能力集':
capabilityTypeCapabilitySet().then((res) => {
initBubbleList(res)
})
break
case '应用领域-能力集':
applicationAreaCapabilitySet().then((res) => {
initBubbleList(res)
})
break
}
} else if (name.indexOf('应用领域') > 0) {
if (name === '能力共享方-应用领域') {
provideDeptTopN().then((res) => {
console.log(res)
res.data.data.forEach((item) => {
item.show = false
})
dataList.value = res.data.data
})
} else {
applyDeptTopN().then((res) => {
console.log(res)
res.data.data.forEach((item) => {
item.show = false
})
dataList.value = res.data.data
})
}
} else if (name.indexOf('能力类型') > 0) {
if (name === '能力共享方-能力类型') {
capabilitySharingPartyCapabilityType().then((res) => {
if (res.data.data.length > 10) {
dataSource.value = res.data.data.slice(0, 10)
} else {
dataSource.value = res.data.data
}
})
} else {
competencyApplicantCapabilityType().then((res) => {
if (res.data.data.length > 10) {
dataSource.value = res.data.data.slice(0, 10)
} else {
dataSource.value = res.data.data
}
})
}
}
}
const initBubbleList = (res) => {
if (navSelect.value === '能力类型-能力集') {
bubbleList.value = res.data.data.maxDept.resourceList.slice(0, 20)
console.log('能力类型============>', res.data.data.typeList)
bubbleList.value.unshift({
id: res.data.data.maxDept.typeName,
name: res.data.data.maxDept.typeName,
})
departmentList.value = res.data.data.typeList
} else if (navSelect.value === '应用领域-能力集') {
bubbleList.value = res.data.data.maxAppArea.resourceList.slice(0, 20)
bubbleList.value.unshift({
id: res.data.data.maxAppArea.typeName,
name: res.data.data.maxAppArea.typeName,
})
departmentList.value = res.data.data.appAreaList
} else {
bubbleList.value = res.data.data.maxDept.resourceList.slice(0, 20)
console.log('其它 ============>', res.data.data.deptList)
bubbleList.value.unshift({
id: res.data.data.maxDept.deptId,
name: res.data.data.maxDept.deptName,
})
departmentList.value = res.data.data.deptList
}
nextTick(() => {
console.log('生成气泡=================>', res, navSelect.value)
coordinate.value = []
bubbleRandom(1)
bubbleRandom(2)
bubbleRandom(3)
bubbleRandom(4)
generateBubble()
})
}
selectNav('能力共享方-应用领域')
const changeDepartmentListFlag = () => {
departmentListFlag.value = false
}
const changeDept = (item) => {
bubbleList.value = []
coordinate.value = []
console.log('变更部门', item)
switch (navSelect.value) {
case '能力共享方-能力集':
selectResourceListByDept({ deptId: item.deptId }).then((res) => {
initBubble(res, item)
})
break
case '能力申请方-能力集':
selectResourceListByApplyDept({ deptId: item.deptId }).then((res) => {
initBubble(res, item)
})
break
case '能力类型-能力集':
selectResourceListByType({ type: item.type }).then((res) => {
initBubble(res, item)
})
break
case '应用领域-能力集':
selectResourceListByAppArea({ appArea: item.type }).then((res) => {
initBubble(res, item)
})
break
}
}
const initBubble = (res, item) => {
console.log('生成气泡=================>', res, item, navSelect.value)
bubbleList.value = []
if (res.data.data.length > 20) {
bubbleList.value = res.data.data.slice(0, 20)
} else {
bubbleList.value = res.data.data
}
if (
navSelect.value === '能力类型-能力集' ||
navSelect.value === '应用领域-能力集'
) {
bubbleList.value.unshift({
id: item.type,
name: item.type,
})
} else {
bubbleList.value.unshift({
id: item.deptId,
name: item.deptName,
})
}
nextTick(() => {
coordinate.value = []
bubbleRandom(1)
bubbleRandom(2)
bubbleRandom(3)
bubbleRandom(4)
generateBubble()
changeDepartmentListFlag()
departmentListFlag.value = false
})
}
// 右侧列表
const dataList = ref([])
// 所有领域类型
const allType = ref([
'社会治安',
'城市管理',
'疫情防控',
'危化品管理',
'交通运输',
'森林防火',
'防汛抗旱',
'文化旅游',
'非煤矿山',
'医疗卫生',
'安全生产',
'生态环境',
'农业农村',
'市场监管',
'政务服务',
])
const flag = ref('')
const nowShow = ref(false)
const showDetails = (item) => {
console.log(item, flag, nowShow)
if (nowShow.value) {
if (flag.value == item.deptId) {
item.show = !item.show
if (item.show) {
flag.value = item.deptId
nowShow.value = true
} else {
nowShow.value = false
}
}
} else {
item.show = !item.show
if (item.show) {
flag.value = item.deptId
nowShow.value = true
} else {
nowShow.value = false
}
}
console.log('展示详情================>', item, flag.value, nowShow.value)
}
// 能力集 971px 560px
const bubbleList = ref([])
// 所有坐标
const coordinate = ref([])
// const coordinate = ref([[425, 545], [220, 340], 120])
const bubbleRandom = (quadrant) => {
// 数据平均分为四个区域
// w h 宽高 t l 定位 s 大小
const w = 1089 / 2
const h = 680 / 2
const count = (bubbleList.value.length - 1) / 4
if (coordinate.value.length == 0) {
coordinate.value.push([
[w - 80, w - 80 + 160],
[h - 80, h - 80 + 160],
160,
])
}
for (let index = 0; index < count; index++) {
// 随机生成一个数字
// 向下取整
let t
let l
const s = Math.floor(Math.random() * 4 + 9) * 10
switch (quadrant) {
case 1:
t = Math.floor(Math.random() * h)
l = Math.floor(Math.random() * w + w)
break
case 2:
t = Math.floor(Math.random() * h)
l = Math.floor(Math.random() * w)
break
case 3:
t = Math.floor(Math.random() * h + h)
l = Math.floor(Math.random() * w)
break
case 4:
t = Math.floor(Math.random() * h + h)
l = Math.floor(Math.random() * w + w)
break
}
let flag = true
console.log(t, l, s)
coordinate.value.forEach((val) => {
if (
(l <= val[0][0] && l + s >= val[0][0]) ||
(l >= val[0][0] && l <= val[0][1])
) {
if (
(t <= val[1][0] && t + s >= val[1][0]) ||
(t >= val[1][0] && t <= val[1][1]) ||
(t + s <= val[1][0] && t + s >= val[1][1])
) {
flag = false
}
} else if (l + s >= w * 2 || t + s >= h * 2) {
flag = false
} else if (l + s >= w * 2 - 100 && t + s >= h * 2 - 40) {
flag = false
}
})
if (flag) {
coordinate.value.push([[l, l + s], [t, t + s], s])
} else {
index--
}
}
}
// 显示企业列表
const departmentList = ref([])
const showDepartmentList = () => {
departmentListFlag.value = true
console.log('显示部门列表~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
}
// 生成气泡
const generateBubble = () => {
const arr = document.querySelectorAll('.bubble-item')
// 删除class
arr.forEach((item) => {
item.classList.remove('blue')
item.classList.remove('white')
})
arr.forEach((val, index) => {
if (index != 0) {
val.style.left = 471.5 + 'px'
val.style.top = 259 + 'px'
val.style.opacity = 0
setTimeout(() => {
val.style.left = coordinate.value[index][0][0] + 'px'
val.style.top = coordinate.value[index][1][0] + 'px'
val.style.opacity = 1
}, index * 100)
val.style.width = coordinate.value[index][2] + 'px'
val.style.height = coordinate.value[index][2] + 'px'
val.style.fontSize = '14px'
if (index % 2 == 0) {
val.classList.add('blue')
} else {
val.classList.add('white')
}
} else {
val.style.opacity = 1
}
})
}
console.log('所有坐标======================>', coordinate.value)
// 能力类型
const columns = [
{
title: '部门名称',
dataIndex: 'name',
width: '30%',
},
{
title: '组件服务',
dataIndex: 'zjfw',
width: '14%',
},
{
title: '应用资源',
dataIndex: 'yyzy',
width: '14%',
},
{
title: '基础设施',
dataIndex: 'jcss',
width: '14%',
},
{
title: '数据资源',
dataIndex: 'sjzy',
width: '14%',
},
{
title: '知识库',
dataIndex: 'zsk',
width: '14%',
},
]
const dataSource = ref([])
</script>
<style lang="less" scoped>
.atlas-resources {
height: 970px;
width: 100%;
padding: 80px 0 50px;
.title {
font-size: 32px;
text-align: center;
margin-bottom: 15px;
}
.line {
width: 35px;
height: 4px;
background: #1890ff;
margin-bottom: 20px;
margin-left: 930px;
}
.main {
width: 100%;
height: 800px;
margin-top: 10px;
padding: 60px 302px;
background: url('~@/assets/abilityStatistics/tp-bg.png') no-repeat;
display: flex;
.left {
div {
width: 178px;
height: 84px;
font-size: 16px;
line-height: 84px;
text-align: center;
color: rgba(255, 255, 255, 0.6);
background: rgba(255, 255, 255, 0.08);
margin-bottom: 1px;
border-right: 2px solid rgba(233, 233, 233, 0.3);
cursor: pointer;
}
.select {
background: rgba(255, 255, 255, 0.18) !important;
border-right: 2px solid #fff;
}
}
.right {
width: 100%;
margin-left: 30px;
background: #fff;
.itemList {
width: 100%;
display: flex;
flex-wrap: wrap;
font-size: 16px;
padding: 20px;
.item {
width: 48%;
height: 40px;
margin-top: 7px;
padding: 10px;
.top {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 10px;
.name {
width: 300px;
text-align: right;
margin-right: 10px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
}
.num {
width: 100px;
margin-left: 10px;
}
.percentage {
width: 100px;
margin-left: 10px;
}
.img {
width: 20px;
}
}
.showBottom {
background: rgba(0, 88, 225, 0.1);
border-radius: 2px;
}
.bottom {
width: 527px;
height: 165px;
margin-top: 5px;
background: #fff;
border: 1px solid #0058e1;
position: absolute;
z-index: 1000;
.up {
margin: 10px;
font-size: 16px;
span {
margin-right: 9px;
font-weight: 600;
font-size: 16px;
}
span:nth-of-type(2),
span:nth-of-type(3) {
margin-right: 0;
background: url('~@/assets/abilityStatistics/bq-bg.png')
no-repeat;
background-size: 100%;
padding: 0 15px;
color: #0058e1;
}
}
.down {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
padding: 0 10px;
.type {
width: 20%;
margin-bottom: 15px;
font-size: 14px;
:deep(.ant-radio-inner::after) {
background-color: #1890ff;
}
:deep(.ant-radio-checked) {
border-color: #1890ff;
}
:deep(.ant-radio-wrapper-disabled) {
cursor: unset;
.ant-radio-disabled {
cursor: unset;
.ant-radio-input {
cursor: unset;
}
}
.ant-radio-inner {
cursor: unset;
background-color: #fff;
}
.ant-radio-checked {
border-color: #1890ff;
}
}
}
}
}
}
.item:nth-child(2n) {
margin-left: 40px;
}
}
.bubble {
width: 100%;
height: 100%;
background: url('~@/assets/abilityStatistics/bubble-bg.png') no-repeat;
display: flex;
position: relative;
div {
width: 160px;
height: 160px;
display: flex;
align-items: center;
justify-content: center;
padding: 15px;
text-align: center;
// background: radial-gradient(
// closest-side at 50% 50%,
// rgb(192, 237, 255) 0%,
// rgb(146, 205, 228) 40%,
// rgb(141, 200, 223) 60%,
// rgb(129, 192, 218) 75%,
// rgb(106, 178, 206) 100%
// );
color: #fff;
font-size: 18px;
border-radius: 50%;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
position: absolute;
opacity: 0;
top: 259px;
left: 471.5px;
transition: all 1s;
span {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
}
div:nth-of-type(1) {
cursor: pointer;
}
p {
cursor: pointer;
position: absolute;
right: 10px;
bottom: 0;
}
.box {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
.departmentList {
width: 150px;
max-height: 400px;
background: rgba(130, 191, 255, 0.79);
border-radius: 5px;
position: absolute;
padding: 10px;
display: flex;
flex-wrap: wrap;
align-items: center;
overflow-y: scroll;
span {
color: rgb(8, 40, 128);
width: 100%;
cursor: pointer;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
}
span:hover {
border: 1px solid #147ad8;
}
}
}
// 隐藏滚动条
.departmentList::-webkit-scrollbar {
display: none;
}
.blue {
background: radial-gradient(
closest-side at 50% 50%,
#71a8ff 0%,
#5e97f4 40%,
#4284ee 60%,
#2b7bf3 75%,
#1b6deb 100%
);
color: #fff;
}
.white {
background: radial-gradient(
closest-side at 50% 50%,
#fcfdff 0%,
#f4f7fd 40%,
#eff4ff 60%,
#e8efff 75%,
#dbeaff 95%,
#cce0ff 100%
);
border: 1px solid #bed7ff;
color: #000;
}
}
}
.right-special {
background: linear-gradient(
to right,
rgb(255, 255, 255) 0%,
rgb(255, 255, 255) 50%,
#eef4fd 50%,
#eef4fd 100%
);
}
}
}
:deep(.ant-table-cell) {
text-align: center;
}
:deep(.ant-progress-inner) {
background-color: #eceef2;
}
:deep(.ant-progress-success-bg),
:deep(.ant-progress-bg) {
background-color: #fc774d;
}
</style>