194 lines
5.2 KiB
Vue
194 lines
5.2 KiB
Vue
<script setup lang="ts">
|
|
import { reactive, onMounted, ref, onBeforeUnmount } from 'vue';
|
|
import { PageContainer } from 'antdv-pro-layout';
|
|
import useI18n from '@/hooks/useI18n';
|
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
|
import { listNe, stateNe } from '@/api/ne/ne';
|
|
import message from 'ant-design-vue/lib/message';
|
|
import { randerGroph, switchLayout } from './graph';
|
|
import { parseDateToStr } from '@/utils/date-utils';
|
|
const { t } = useI18n();
|
|
|
|
/**图DOM节点实例对象 */
|
|
const graphG6Dom = ref<HTMLElement | undefined>(undefined);
|
|
|
|
/**图实例对象 */
|
|
const graphG6 = ref<any>(null);
|
|
|
|
/**图数据 */
|
|
const graphG6Data = reactive<Record<string, any>>({
|
|
nodes: [],
|
|
edges: [],
|
|
});
|
|
|
|
/**查询全部网元数据列表 */
|
|
function fnRanderData() {
|
|
if (!graphG6Dom.value) return;
|
|
graphG6.value = randerGroph(t, graphG6Dom.value, graphG6Data);
|
|
}
|
|
|
|
/**网元状态定时器 */
|
|
const stateTimeout = ref<any>(null);
|
|
|
|
/**查询网元状态 */
|
|
async function fnGetState() {
|
|
clearTimeout(stateTimeout.value);
|
|
for (const node of graphG6Data.nodes) {
|
|
const ne = node.info;
|
|
// if (ne.neType === 'OMC') continue;
|
|
const result = await stateNe(ne.neType, ne.neId);
|
|
if (result.code === RESULT_CODE_SUCCESS) {
|
|
ne.serverState = result.data;
|
|
ne.serverState.refreshTime = parseDateToStr(
|
|
ne.serverState.refreshTime,
|
|
'HH:mm:ss'
|
|
);
|
|
// 修改网元状态颜色
|
|
const neShape = graphG6.value.findById(ne.neName);
|
|
graphG6.value.setItemState(neShape, 'neState', ne.serverState.online);
|
|
}
|
|
}
|
|
stateTimeout.value = setTimeout(() => fnGetState(), 30_000);
|
|
}
|
|
|
|
/**查询全部网元数据列表 */
|
|
function fnGetList(refresh: boolean = false) {
|
|
listNe({
|
|
bandStatus: false,
|
|
})
|
|
.then(res => {
|
|
if (
|
|
res.code === RESULT_CODE_SUCCESS &&
|
|
Array.isArray(res.data) &&
|
|
res.data.length > 0
|
|
) {
|
|
// 根网管
|
|
let rootNodeInfo = { neName: undefined };
|
|
const nodes = [];
|
|
const edges = [];
|
|
for (const item of res.data) {
|
|
item.serverState = {};
|
|
// 节点
|
|
const nodeIndex = nodes.findIndex(v => v.id === item.neName);
|
|
if (nodeIndex === -1) {
|
|
if (item.neType === 'OMC') {
|
|
nodes.push({
|
|
id: item.neName,
|
|
label: item.neName,
|
|
info: item,
|
|
labelCfg: {
|
|
position: 'bottom',
|
|
offset: 8,
|
|
style: {
|
|
fill: '#fff',
|
|
fontSize: 14,
|
|
},
|
|
},
|
|
size: 60,
|
|
icon: {
|
|
x: -30,
|
|
y: -30,
|
|
// 可更换为其他图片地址
|
|
img: '/svg/service_db.svg',
|
|
width: 60,
|
|
height: 60,
|
|
},
|
|
});
|
|
!rootNodeInfo.neName && (rootNodeInfo = item);
|
|
} else {
|
|
nodes.push({
|
|
id: item.neName,
|
|
label: item.neName,
|
|
info: item,
|
|
size: 48,
|
|
icon: {
|
|
x: -24,
|
|
y: -24,
|
|
img: '/svg/service.svg',
|
|
width: 48,
|
|
height: 48,
|
|
},
|
|
});
|
|
}
|
|
}
|
|
// 边
|
|
if (item.neType !== 'OMC') {
|
|
const edgeIndex = edges.findIndex(v => v.source === item.neName);
|
|
if (edgeIndex === -1) {
|
|
edges.push({
|
|
source: item.neName,
|
|
target: rootNodeInfo.neName,
|
|
label: `${item.neName}-${rootNodeInfo.neName}`,
|
|
});
|
|
}
|
|
} else {
|
|
edges.push({
|
|
source: item.neName,
|
|
target: rootNodeInfo.neName,
|
|
label: `${item.neName}-${rootNodeInfo.neName}`,
|
|
});
|
|
}
|
|
}
|
|
graphG6Data.nodes = nodes;
|
|
graphG6Data.edges = edges;
|
|
return true;
|
|
} else {
|
|
message.warning({
|
|
content: t('common.noData'),
|
|
duration: 2,
|
|
});
|
|
return false;
|
|
}
|
|
})
|
|
.then(hasNeList => {
|
|
if (!hasNeList) return;
|
|
if (refresh) {
|
|
// graphG6.value.get('canvas').set('localRefresh', true);
|
|
graphG6.value.destroy();
|
|
// graphG6.value.clear();
|
|
}
|
|
fnRanderData();
|
|
fnGetState();
|
|
});
|
|
}
|
|
|
|
onMounted(() => {
|
|
// 获取网元列表G
|
|
fnGetList();
|
|
});
|
|
|
|
onBeforeUnmount(() => {
|
|
clearTimeout(stateTimeout.value);
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<PageContainer>
|
|
<a-card
|
|
:bordered="false"
|
|
:body-style="{ marginBottom: '24px' }"
|
|
size="small"
|
|
>
|
|
<!-- 插槽-卡片左侧侧 -->
|
|
<template #title> </template>
|
|
<!-- 插槽-卡片右侧 -->
|
|
<template #extra>
|
|
<a-button type="default" @click.prevent="switchLayout()">
|
|
<template #icon><RetweetOutlined /></template>
|
|
{{ t('views.monitor.topology.switchLayout') }}
|
|
</a-button>
|
|
</template>
|
|
|
|
<div ref="graphG6Dom" class="chart"></div>
|
|
</a-card>
|
|
</PageContainer>
|
|
</template>
|
|
|
|
<style lang="less" scoped>
|
|
.chart {
|
|
width: 100%;
|
|
height: calc(100vh - 300px);
|
|
background-color: rgb(43, 47, 51);
|
|
}
|
|
</style>
|