feat: mt版本移动过来的的告警/仪表/性能大屏页面
This commit is contained in:
337
src/views/dashboard/overview2/components/Topology/index.vue
Normal file
337
src/views/dashboard/overview2/components/Topology/index.vue
Normal file
@@ -0,0 +1,337 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import { listAllNeInfo } from '@/api/ne/neInfo';
|
||||
import { message } from 'ant-design-vue/es';
|
||||
import { getGraphData } from '@/api/monitor/topology';
|
||||
import { Graph, GraphData, Tooltip } from '@antv/g6';
|
||||
import { parseBasePath } from '@/plugins/file-static-url';
|
||||
import { edgeLineAnimateState } from '@/views/monitor/topologyBuild/hooks/registerEdge';
|
||||
import { nodeImageAnimateState } from '@/views/monitor/topologyBuild/hooks/registerNode';
|
||||
import {
|
||||
graphG6,
|
||||
graphState,
|
||||
graphNodeClickID,
|
||||
notNeNodes,
|
||||
} from '../../hooks/useTopology';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
const { t } = useI18n();
|
||||
|
||||
/**图DOM节点实例对象 */
|
||||
const graphG6Dom = ref<HTMLElement | undefined>(undefined);
|
||||
|
||||
/**图节点展示 */
|
||||
const graphNodeTooltip = new Tooltip({
|
||||
offsetX: 10,
|
||||
offsetY: 20,
|
||||
getContent(evt) {
|
||||
if (!evt) return t('views.monitor.topologyBuild.graphNotInfo');
|
||||
const { id, label, neState, neInfoList, neStateMap }: any = evt.item?.getModel();
|
||||
//console.log(neInfoList,neState,neInfoList);
|
||||
if (notNeNodes.includes(id)) {
|
||||
return `<div><span>${label || id}</span></div>`;
|
||||
}
|
||||
if (!neState) {
|
||||
return `<div><span>${label || id}</span></div>`;
|
||||
}
|
||||
|
||||
// 获取同类型网元列表
|
||||
const sameTypeNes = neInfoList || [];
|
||||
|
||||
// 如果没有网元或只有一个网元,显示原来的信息
|
||||
if (sameTypeNes.length <= 1) {
|
||||
return `
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 200px;
|
||||
"
|
||||
>
|
||||
<div><strong>${t('views.monitor.topology.state')}:</strong><span>
|
||||
${
|
||||
neState.online
|
||||
? t('views.monitor.topology.normalcy')
|
||||
: t('views.monitor.topology.exceptions')
|
||||
}
|
||||
</span></div>
|
||||
<div><strong>${t('views.monitor.topology.refreshTime')}:</strong><span>
|
||||
${neState.refreshTime ?? '--'}
|
||||
</span></div>
|
||||
<div>========================</div>
|
||||
<div><strong>ID:</strong><span>${neState.neId}</span></div>
|
||||
<div><strong>${t('views.monitor.topology.name')}:</strong><span>
|
||||
${neState.neName ?? '--'}
|
||||
</span></div>
|
||||
<div><strong>IP:</strong><span>${neState.neIP ?? '--'}</span></div>
|
||||
<div><strong>${t('views.monitor.topology.version')}:</strong><span>
|
||||
${neState.version ?? '--'}
|
||||
</span></div>
|
||||
<div><strong>${t('views.monitor.topology.serialNum')}:</strong><span>
|
||||
${neState.sn ?? '--'}
|
||||
</span></div>
|
||||
<div><strong>${t('views.monitor.topology.expiryDate')}:</strong><span>
|
||||
${neState.expire ?? '--'}
|
||||
</span></div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// 如果有多个网元,聚合显示
|
||||
let content = `
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 300px;
|
||||
"
|
||||
>
|
||||
<div><strong>${t('views.monitor.topology.state')}:</strong><span>
|
||||
${
|
||||
neState.online
|
||||
? t('views.monitor.topology.normalcy')
|
||||
: t('views.monitor.topology.exceptions')
|
||||
}
|
||||
</span></div>
|
||||
<div><strong>${t('views.monitor.topology.refreshTime')}:</strong><span>
|
||||
${neState.refreshTime ?? '--'}
|
||||
</span></div>
|
||||
<div>========================</div>`;
|
||||
|
||||
// 为每个同类型网元添加信息
|
||||
sameTypeNes.forEach((ne: any, index: number) => {
|
||||
// 获取该网元的状态信息
|
||||
const neStateInfo = neStateMap?.[ne.neId] ||
|
||||
(ne.neId === neState.neId ? neState : {});
|
||||
|
||||
content += `
|
||||
<div style="margin-top: 8px;"><strong>${t('views.monitor.topology.name')}:${ne.neName || id + '_' + ne.neId}</strong></div>
|
||||
<div><strong>ID:</strong><span>${ne.neId || '--'}</span></div>
|
||||
<div><strong>IP:</strong><span>${neStateInfo.neIP || ne.neIP || '--'}</span></div>
|
||||
<div><strong>${t('views.monitor.topology.version')}:</strong><span>
|
||||
${neStateInfo.version || ne.version || '--'}
|
||||
</span></div>
|
||||
<div><strong>${t('views.monitor.topology.serialNum')}:</strong><span>
|
||||
${neStateInfo.sn || ne.sn || '--'}
|
||||
</span></div>
|
||||
<div><strong>${t('views.monitor.topology.expiryDate')}:</strong><span>
|
||||
${neStateInfo.expire || ne.expire || '--'}
|
||||
</span></div>
|
||||
<div><strong>${t('views.monitor.topology.state')}:</strong><span>
|
||||
${
|
||||
neStateInfo.online !== undefined
|
||||
? (neStateInfo.online
|
||||
? t('views.monitor.topology.normalcy')
|
||||
: t('views.monitor.topology.exceptions'))
|
||||
: 'undefined'
|
||||
}
|
||||
</span></div>
|
||||
${index < sameTypeNes.length - 1 ? '<div>------------------------</div>' : ''}
|
||||
`;
|
||||
});
|
||||
|
||||
content += '</div>';
|
||||
return content;
|
||||
},
|
||||
itemTypes: ['node'],
|
||||
});
|
||||
|
||||
|
||||
|
||||
/**图数据渲染 */
|
||||
function handleRanderGraph(
|
||||
container: HTMLElement | undefined,
|
||||
data: GraphData
|
||||
) {
|
||||
if (!container) return;
|
||||
const { clientHeight, clientWidth } = container;
|
||||
|
||||
edgeLineAnimateState();
|
||||
nodeImageAnimateState();
|
||||
|
||||
const graph = new Graph({
|
||||
container: container,
|
||||
width: clientWidth,
|
||||
height: clientHeight - 36,
|
||||
fitCenter: true,
|
||||
fitView: true,
|
||||
fitViewPadding: [20],
|
||||
autoPaint: true,
|
||||
modes: {
|
||||
// default: ['drag-canvas', 'zoom-canvas'],
|
||||
},
|
||||
groupByTypes: false,
|
||||
nodeStateStyles: {
|
||||
selected: {
|
||||
fill: 'transparent',
|
||||
},
|
||||
},
|
||||
plugins: [graphNodeTooltip],
|
||||
animate: true, // 是否使用动画过度,默认为 false
|
||||
animateCfg: {
|
||||
duration: 500, // Number,一次动画的时长
|
||||
easing: 'linearEasing', // String,动画函数
|
||||
},
|
||||
});
|
||||
graph.data(data);
|
||||
graph.render();
|
||||
|
||||
|
||||
graphG6.value = graph;
|
||||
|
||||
// 创建 ResizeObserver 实例
|
||||
var observer = new ResizeObserver(function (entries) {
|
||||
// 当元素大小发生变化时触发回调函数
|
||||
entries.forEach(function (entry) {
|
||||
if (!graphG6.value) {
|
||||
return;
|
||||
}
|
||||
graphG6.value.changeSize(
|
||||
entry.contentRect.width,
|
||||
entry.contentRect.height - 20
|
||||
);
|
||||
graphG6.value.fitCenter();
|
||||
});
|
||||
});
|
||||
// 监听元素大小变化
|
||||
observer.observe(container);
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取图组数据渲染到画布
|
||||
* @param reload 是否重载数据
|
||||
*/
|
||||
function fnGraphDataLoad(reload: boolean = false) {
|
||||
Promise.all([
|
||||
getGraphData(graphState.group),
|
||||
listAllNeInfo({
|
||||
bandStatus: false,
|
||||
}),
|
||||
])
|
||||
.then(resArr => {
|
||||
const graphRes = resArr[0];
|
||||
const neRes = resArr[1];
|
||||
if (
|
||||
graphRes.code === RESULT_CODE_SUCCESS &&
|
||||
Array.isArray(graphRes.data.nodes) &&
|
||||
graphRes.data.nodes.length > 0 &&
|
||||
neRes.code === RESULT_CODE_SUCCESS &&
|
||||
Array.isArray(neRes.data) &&
|
||||
neRes.data.length > 0
|
||||
) {
|
||||
return {
|
||||
graphData: graphRes.data,
|
||||
neList: neRes.data,
|
||||
};
|
||||
} else {
|
||||
message.warning({
|
||||
content: t('views.monitor.topology.noData'),
|
||||
duration: 5,
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
if (!res) return;
|
||||
const { combos, edges, nodes } = res.graphData;
|
||||
|
||||
// 按网元类型分组
|
||||
const neTypeMap = new Map();
|
||||
res.neList.forEach(ne => {
|
||||
if (!ne.neType) return;
|
||||
if (!neTypeMap.has(ne.neType)) {
|
||||
neTypeMap.set(ne.neType, []);
|
||||
}
|
||||
neTypeMap.get(ne.neType).push(ne);
|
||||
});
|
||||
|
||||
// 节点过滤
|
||||
const nf: Record<string, any>[] = nodes.filter(
|
||||
(node: Record<string, any>) => {
|
||||
Reflect.set(node, 'neState', { online: false });
|
||||
Reflect.set(node, 'neStateMap', {}); // 初始化状态映射
|
||||
|
||||
// 图片路径处理
|
||||
if (node.img) node.img = parseBasePath(node.img);
|
||||
if (node.icon.show && node.icon?.img){
|
||||
node.icon.img = parseBasePath(node.icon.img);
|
||||
}
|
||||
|
||||
// 遍历是否有网元数据
|
||||
const nodeID: string = node.id;
|
||||
|
||||
// 处理非网元节点
|
||||
if (notNeNodes.includes(nodeID)) {
|
||||
return true;
|
||||
}
|
||||
//(neTypeMap.get(nodeID),nodeID,node.neState)
|
||||
// 处理网元节点
|
||||
if (neTypeMap.has(nodeID)) {
|
||||
// all NeInfo
|
||||
Reflect.set(node, 'neInfoList', neTypeMap.get(nodeID));
|
||||
|
||||
Reflect.set(node, 'neInfo', neTypeMap.get(nodeID)[0] || {});
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
// 边过滤
|
||||
const ef: Record<string, any>[] = edges.filter(
|
||||
(edge: Record<string, any>) => {
|
||||
const edgeSource: string = edge.source;
|
||||
const edgeTarget: string = edge.target;
|
||||
const hasNeS = nf.some(n => n.id === edgeSource);
|
||||
const hasNeT = nf.some(n => n.id === edgeTarget);
|
||||
if (hasNeS && hasNeT) {
|
||||
return true;
|
||||
}
|
||||
if (hasNeS && notNeNodes.includes(edgeTarget)) {
|
||||
return true;
|
||||
}
|
||||
if (hasNeT && notNeNodes.includes(edgeSource)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
// 分组过滤
|
||||
combos.forEach((combo: Record<string, any>) => {
|
||||
const comboChildren: Record<string, any>[] = combo.children;
|
||||
combo.children = comboChildren.filter(c => nf.some(n => n.id === c.id));
|
||||
return combo;
|
||||
});
|
||||
|
||||
// 图数据
|
||||
graphState.data = { combos, edges: ef, nodes: nf };
|
||||
})
|
||||
.finally(() => {
|
||||
if (graphState.data.length < 0) return;
|
||||
// 重载数据
|
||||
if (reload) {
|
||||
graphG6.value.read(graphState.data);
|
||||
} else {
|
||||
handleRanderGraph(graphG6Dom.value, graphState.data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fnGraphDataLoad(false);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="graphG6Dom" class="chart"></div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.chart {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user