diff --git a/src/views/dashboard/overview/components/Topology/index.vue b/src/views/dashboard/overview/components/Topology/index.vue index 12e9d763..775b7455 100644 --- a/src/views/dashboard/overview/components/Topology/index.vue +++ b/src/views/dashboard/overview/components/Topology/index.vue @@ -22,18 +22,24 @@ const graphG6Dom = ref(undefined); /**图节点展示 */ const graphNodeTooltip = new Tooltip({ - offsetX: 20, + offsetX: 10, offsetY: 20, getContent(evt) { if (!evt) return t('views.monitor.topologyBuild.graphNotInfo'); - const { id, label, neState }: any = evt.item?.getModel(); + const { id, label, neState, neInfoList, neStateMap }: any = evt.item?.getModel(); if (notNeNodes.includes(id)) { return `
${label || id}
`; } if (!neState) { return `
${label || id}
`; } - return ` + + // 获取同类型网元列表 + const sameTypeNes = neInfoList || []; + + // 如果没有网元或只有一个网元,显示原来的信息 + if (sameTypeNes.length <= 1) { + return `
+
${t('views.monitor.topology.state')}: + ${ + neState.online + ? t('views.monitor.topology.normalcy') + : t('views.monitor.topology.exceptions') + } +
+
${t('views.monitor.topology.refreshTime')}: + ${neState.refreshTime ?? '--'} +
+
========================
`; + + // 为每个同类型网元添加信息 + sameTypeNes.forEach((ne: any, index: number) => { + // 获取该网元的状态信息 + const neStateInfo = neStateMap?.[ne.neId] || + (ne.neId === neState.neId ? neState : {}); + + content += ` +
${t('views.monitor.topology.name')}:${ne.neName || id + '_' + ne.neId}
+
ID:${ne.neId || '--'}
+
IP:${neStateInfo.neIP || ne.neIP || '--'}
+
${t('views.monitor.topology.version')}: + ${neStateInfo.version || ne.version || '--'} +
+
${t('views.monitor.topology.serialNum')}: + ${neStateInfo.sn || ne.sn || '--'} +
+
${t('views.monitor.topology.expiryDate')}: + ${neStateInfo.expire || ne.expire || '--'} +
+
${t('views.monitor.topology.state')}: + ${ + neStateInfo.online !== undefined + ? (neStateInfo.online + ? t('views.monitor.topology.normalcy') + : t('views.monitor.topology.exceptions')) + : '未知' + } +
+ ${index < sameTypeNes.length - 1 ? '
------------------------
' : ''} + `; + }); + + content += '
'; + return content; }, itemTypes: ['node'], }); -/**图绑定事件 */ -function fnGraphEvent(graph: Graph) { - // 节点点击 - graph.on('node:click', evt => { - // 获得鼠标当前目标节点 - const node = evt.item?.getModel(); - if (node && node.id && !notNeNodes.includes(node.id)) { - graphNodeClickID.value = node.id; - } - }); -} + /**图数据渲染 */ function handleRanderGraph( @@ -122,7 +175,6 @@ function handleRanderGraph( graph.data(data); graph.render(); - fnGraphEvent(graph); graphG6.value = graph; @@ -150,14 +202,14 @@ function handleRanderGraph( * 获取图组数据渲染到画布 * @param reload 是否重载数据 */ -function fnGraphDataLoad(reload: boolean = false) { + function fnGraphDataLoad(reload: boolean = false) { Promise.all([ getGraphData(graphState.group), listAllNeInfo({ bandStatus: false, }), ]) - .then(resArr => { + .then(resArr => { const graphRes = resArr[0]; const neRes = resArr[1]; if ( @@ -183,27 +235,43 @@ function fnGraphDataLoad(reload: boolean = false) { 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[] = nodes.filter( (node: Record) => { 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) { + if (node.icon && node.icon.show && node.icon?.img) node.icon.img = parseBasePath(node.icon.img); - } + // 遍历是否有网元数据 const nodeID: string = node.id; - const hasNe = res.neList.some(ne => { - Reflect.set(node, 'neInfo', ne.neType === nodeID ? ne : {}); - return ne.neType === nodeID; - }); - if (hasNe) { - return true; - } + + // 处理非网元节点 if (notNeNodes.includes(nodeID)) { return true; } + + // 处理网元节点 + 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; } ); @@ -215,7 +283,6 @@ function fnGraphDataLoad(reload: boolean = false) { const edgeTarget: string = edge.target; const hasNeS = nf.some(n => n.id === edgeSource); const hasNeT = nf.some(n => n.id === edgeTarget); - // console.log(hasNeS, edgeSource, hasNeT, edgeTarget); if (hasNeS && hasNeT) { return true; } diff --git a/src/views/dashboard/overview/hooks/useTopology.ts b/src/views/dashboard/overview/hooks/useTopology.ts index 64c01c68..c4c1b64d 100644 --- a/src/views/dashboard/overview/hooks/useTopology.ts +++ b/src/views/dashboard/overview/hooks/useTopology.ts @@ -68,47 +68,59 @@ export const graphNodeStateNum = computed(() => { export const neStateRequestMap = ref>(new Map()); /**neStateParse 网元状态 数据解析 */ -export function neStateParse(neType: string, data: Record) { +export function neStateParse(neType: string, data: Record,neId: string) { const { combos, edges, nodes } = graphState.data; const node = nodes.find((item: Record) => item.id === neType); + if (!node) return; + + // 初始化状态映射 + if (!node.neStateMap) node.neStateMap = {}; // 更新网元状态 - const newNeState = Object.assign(node.neState, data, { + const newNeState :any = { + ...data, // 先展开data对象 refreshTime: parseDateToStr(data.refreshTime, 'HH:mm:ss'), online: !!data.cpu, - }); + neId: neId + }; + + // 如果是主要网元,更新节点状态 + if (node.neInfo && node.neInfo.neId === neId) { + // 使用Object.assign更新状态,确保所有字段都被正确复制 + Object.assign(node.neState, newNeState); + } + + // 无论是否为主要网元,都更新状态映射 + node.neStateMap[neId] = {...newNeState}; // 创建副本存储 // 通过 ID 查询节点实例 const item = graphG6.value.findById(node.id); if (item) { - const stateColor = newNeState.online ? '#52c41a' : '#f5222d'; // 状态颜色 - // 图片类型不能填充 - if (node.type.startsWith('image')) { - // 更新节点 - if (node.label !== newNeState.neName) { + // 如果是主要网元,更新节点显示状态 + if (node.neInfo && node.neInfo.neId === neId) { + const stateColor = newNeState.online ? '#52c41a' : '#f5222d'; // 状态颜色 + // 图片类型不能填充 + if (node.type && node.type.startsWith('image')) { + // 更新节点 + if (node.label !== newNeState.neName) { + graphG6.value.updateItem(item, { + label: newNeState.neName, + }); + } + // 设置状态 + graphG6.value.setItemState(item, 'top-right-dot', stateColor); + } else { + // 更新节点 graphG6.value.updateItem(item, { label: newNeState.neName, + style: { + fill: stateColor, // 填充色 + stroke: stateColor, // 填充色 + }, }); + // 设置状态 + graphG6.value.setItemState(item, 'stroke', newNeState.online); } - // 设置状态 - graphG6.value.setItemState(item, 'top-right-dot', stateColor); - } else { - // 更新节点 - graphG6.value.updateItem(item, { - label: newNeState.neName, - // neState: newNeState, - style: { - fill: stateColor, // 填充色 - stroke: stateColor, // 填充色 - }, - // labelCfg: { - // style: { - // fill: '#ffffff', // 标签文本色 - // }, - // }, - }); - // 设置状态 - graphG6.value.setItemState(item, 'stroke', newNeState.online); } } diff --git a/src/views/dashboard/overview/hooks/useWS.ts b/src/views/dashboard/overview/hooks/useWS.ts index 0810be2e..6b589dd1 100644 --- a/src/views/dashboard/overview/hooks/useWS.ts +++ b/src/views/dashboard/overview/hooks/useWS.ts @@ -34,7 +34,6 @@ export default function useWS() { /**接收数据后回调 */ function wsMessage(res: Record) { - //console.log(res); const { code, requestId, data } = res; if (code === RESULT_CODE_ERROR) { console.warn(res.msg); @@ -43,7 +42,8 @@ export default function useWS() { // 网元状态 if (requestId && requestId.startsWith('neState')) { const neType = requestId.split('_')[1]; - neStateParse(neType, data); + const neId = requestId.split('_')[2]; + neStateParse(neType, data,neId); return; } diff --git a/src/views/dashboard/overview/index.vue b/src/views/dashboard/overview/index.vue index b19477d1..8d3e2637 100644 --- a/src/views/dashboard/overview/index.vue +++ b/src/views/dashboard/overview/index.vue @@ -84,20 +84,24 @@ function fnGetNeState() { // 获取节点状态 for (const node of graphState.data.nodes) { if (notNeNodes.includes(node.id)) continue; - const { neType, neId } = node.neInfo; - if (!neType || !neId) continue; - // 请求标记检查避免重复发送 - if (neStateRequestMap.value.get(neType)) continue; - neStateRequestMap.value.set(neType, true); - wsSend({ - requestId: `neState_${neType}_${neId}`, - type: 'ne_state', - data: { - neType: neType, - neId: neId, - }, - }); + + const neInfoList = node.neInfoList || []; + if (neInfoList.length === 0) continue; + + + for (const neInfo of neInfoList) { + if (!neInfo.neType || !neInfo.neId) continue; + + wsSend({ + requestId: `neState_${neInfo.neType}_${neInfo.neId}`, + type: 'ne_state', + data: { + neType: neInfo.neType, + neId: neInfo.neId, + }, + }); + } } } diff --git a/src/views/monitor/topologyArchitecture/index.vue b/src/views/monitor/topologyArchitecture/index.vue index b7f25f9b..b85f218f 100644 --- a/src/views/monitor/topologyArchitecture/index.vue +++ b/src/views/monitor/topologyArchitecture/index.vue @@ -127,14 +127,20 @@ const graphNodeTooltip = new Tooltip({ offsetY: 20, getContent(evt) { if (!evt) return t('views.monitor.topologyBuild.graphNotInfo'); - const { id, label, neState }: any = evt.item?.getModel(); + const { id, label, neState, neInfoList, neStateMap }: any = evt.item?.getModel(); if (notNeNodes.includes(id)) { return `
${label || id}
`; } if (!neState) { return `
${label || id}
`; } - return ` + + // 获取同类型网元列表 + const sameTypeNes = neInfoList || []; + + // 如果没有网元或只有一个网元,显示原来的信息 + if (sameTypeNes.length <= 1) { + return `
+
${t('views.monitor.topology.state')}: + ${ + neState.online + ? t('views.monitor.topology.normalcy') + : t('views.monitor.topology.exceptions') + } +
+
${t('views.monitor.topology.refreshTime')}: + ${neState.refreshTime ?? '--'} +
+
========================
`; + + // 为每个同类型网元添加信息 + sameTypeNes.forEach((ne: any, index: number) => { + // 获取该网元的状态信息 + const neStateInfo = neStateMap?.[ne.neId] || + (ne.neId === neState.neId ? neState : {}); + + content += ` +
${t('views.monitor.topology.name')}:${ne.neName || id + '_' + ne.neId}
+
ID:${ne.neId || '--'}
+
IP:${neStateInfo.neIP || ne.neIP || '--'}
+
${t('views.monitor.topology.version')}: + ${neStateInfo.version || ne.version || '--'} +
+
${t('views.monitor.topology.serialNum')}: + ${neStateInfo.sn || ne.sn || '--'} +
+
${t('views.monitor.topology.expiryDate')}: + ${neStateInfo.expire || ne.expire || '--'} +
+
${t('views.monitor.topology.state')}: + ${ + neStateInfo.online !== undefined + ? (neStateInfo.online + ? t('views.monitor.topology.normalcy') + : t('views.monitor.topology.exceptions')) + : '未知' + } +
+ ${index < sameTypeNes.length - 1 ? '
------------------------
' : ''} + `; + }); + + content += '
'; + return content; }, itemTypes: ['node'], }); @@ -262,7 +325,7 @@ function fnGraphDataLoad(reload: boolean = false) { bandStatus: false, }), ]) - .then(resArr => { + .then(resArr => { const graphRes = resArr[0]; const neRes = resArr[1]; if ( @@ -288,26 +351,43 @@ function fnGraphDataLoad(reload: boolean = false) { 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[] = nodes.filter( (node: Record) => { 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) + if (node.icon && node.icon.show && node.icon?.img) node.icon.img = parseBasePath(node.icon.img); + // 遍历是否有网元数据 const nodeID: string = node.id; - const hasNe = res.neList.some(ne => { - Reflect.set(node, 'neInfo', ne.neType === nodeID ? ne : {}); - return ne.neType === nodeID; - }); - if (hasNe) { - return true; - } + + // 处理非网元节点 if (notNeNodes.includes(nodeID)) { return true; } + + // 处理网元节点 + 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; } ); @@ -319,7 +399,6 @@ function fnGraphDataLoad(reload: boolean = false) { const edgeTarget: string = edge.target; const hasNeS = nf.some(n => n.id === edgeSource); const hasNeT = nf.some(n => n.id === edgeTarget); - // console.log(hasNeS, edgeSource, hasNeT, edgeTarget); if (hasNeS && hasNeT) { return true; } @@ -366,19 +445,27 @@ const interval10s = ref(null); /**查询网元状态 */ function fnGetState() { - // 获取节点状态 + // 遍历所有节点 for (const node of graphState.data.nodes) { if (notNeNodes.includes(node.id)) continue; - const { neType, neId } = node.neInfo; - if (!neType || !neId) continue; - ws.send({ - requestId: `${neType}_${neId}`, - type: 'ne_state', - data: { - neType: neType, - neId: neId, - }, - }); + + + const neInfoList = node.neInfoList || []; + if (neInfoList.length === 0) continue; + + + for (const neInfo of neInfoList) { + if (!neInfo.neType || !neInfo.neId) continue; + + ws.send({ + requestId: `${neInfo.neType}_${neInfo.neId}`, + type: 'ne_state', + data: { + neType: neInfo.neType, + neId: neInfo.neId, + }, + }); + } } } @@ -397,25 +484,64 @@ function wsMessage(res: Record) { } if (!requestId) return; const [neType, neId] = requestId.split('_'); - const { combos, edges, nodes } = graphState.data; - const node = nodes.find((item: Record) => item.id === neType); + const { edges, nodes } = graphState.data; - // 更新网元状态 - const newNeState = Object.assign(node.neState, data, { + const node = nodes.find((item: Record) => item.id === neType); + if (!node) return; + + if (!node.neStateMap) node.neStateMap = {}; + + const newNeState = { + ...data, refreshTime: parseDateToStr(data.refreshTime, 'HH:mm:ss'), online: !!data.cpu, - }); + neId: neId + }; + + + + if (node.neInfo && node.neInfo.neId === neId) { + Object.assign(node.neState, newNeState); + } + + node.neStateMap[neId] = {...newNeState}; // 通过 ID 查询节点实例 const item = graphG6.value.findById(node.id); if (item) { - const stateColor = newNeState.online ? '#52c41a' : '#f5222d'; // 状态颜色 + const neInfoList = node.neInfoList || []; + let allOnline = true; + let allOffline = true; + let mixedState = false; + + for (const ne of neInfoList) { + const neState = node.neStateMap[ne.neId]; + if (neState) { + if (neState.online) { + allOffline = false; + } else { + allOnline = false; + } + } + } + + // 如果既不是全部在线也不是全部离线,则是混合状态 + mixedState = !allOnline && !allOffline; + + // 根据状态设置颜色 + let stateColor = '#52c41a'; // 默认绿色(全部正常) + if (allOffline) { + stateColor = '#f5222d'; // 红色(全部异常) + } else if (mixedState) { + stateColor = '#faad14'; // 黄色(部分正常部分异常) + } + // 图片类型不能填充 - if (node.type.startsWith('image')) { + if (node.type && node.type.startsWith('image')) { // 更新节点 - if (node.label !== newNeState.neName) { + if (node.label !== node.neInfo.neName) { graphG6.value.updateItem(item, { - label: newNeState.neName, + label: node.neInfo.neType, }); } // 设置状态 @@ -423,63 +549,43 @@ function wsMessage(res: Record) { } else { // 更新节点 graphG6.value.updateItem(item, { - label: newNeState.neName, - // neState: newNeState, + label: node.neInfo.neType, style: { fill: stateColor, // 填充色 stroke: stateColor, // 填充色 }, - // labelCfg: { - // style: { - // fill: '#ffffff', // 标签文本色 - // }, - // }, }); - // 设置状态 - graphG6.value.setItemState(item, 'stroke', newNeState.online); + // 设置状态 - 使用混合状态 + graphG6.value.setItemState(item, 'stroke', !allOffline); } } - // 设置边状态 + // 设置边状态 - 也需要考虑混合状态 for (const edge of edges) { const edgeSource: string = edge.source; const edgeTarget: string = edge.target; const neS = nodes.find((n: any) => n.id === edgeSource); const neT = nodes.find((n: any) => n.id === edgeTarget); - // console.log(neS, edgeSource, neT, edgeTarget); if (neS && neT) { - // 通过 ID 查询节点实例 - // const item = graphG6.value.findById(edge.id); - // console.log( - // `${edgeSource} - ${edgeTarget}`, - // neS.neState.online && neT.neState.online - // ); - // const stateColor = neS.neState.online && neT.neState.online ? '#000000' : '#ff4d4f'; // 状态颜色 - // 更新边 - // graphG6.value.updateItem(item, { - // label: `${edgeSource} - ${edgeTarget}`, - // style: { - // stroke: stateColor, // 填充色 - // }, - // labelCfg: { - // style: { - // fill: '#ffffff', // 标签文本色 - // }, - // }, - // }); - // 设置状态 + // 计算源节点和目标节点的状态 + const sourceHasOnline = neS.neInfoList?.some((ne: any) => neS.neStateMap?.[ne.neId]?.online) || false; + const targetHasOnline = neT.neInfoList?.some((ne: any) => neT.neStateMap?.[ne.neId]?.online) || false; + + // 只要有一个实例在线,边就应该显示为活动状态 graphG6.value.setItemState( edge.id, 'circle-move', - neS.neState.online && neT.neState.online + sourceHasOnline && targetHasOnline ); } if (neS && notNeNodes.includes(edgeTarget)) { - graphG6.value.setItemState(edge.id, 'line-dash', neS.neState.online); + const sourceHasOnline = neS.neInfoList?.some((ne: any) => neS.neStateMap?.[ne.neId]?.online) || false; + graphG6.value.setItemState(edge.id, 'line-dash', sourceHasOnline); } if (neT && notNeNodes.includes(edgeSource)) { - graphG6.value.setItemState(edge.id, 'line-dash', neT.neState.online); + const targetHasOnline = neT.neInfoList?.some((ne: any) => neT.neStateMap?.[ne.neId]?.online) || false; + graphG6.value.setItemState(edge.id, 'line-dash', targetHasOnline); } } }