diff --git a/src/views/dashboard/overview/components/NeResources/index.vue b/src/views/dashboard/overview/components/NeResources/index.vue index a50a6a20..fb32626f 100644 --- a/src/views/dashboard/overview/components/NeResources/index.vue +++ b/src/views/dashboard/overview/components/NeResources/index.vue @@ -236,8 +236,11 @@ function handleRanderChart( } function fnChangeData(data: any[], itemID: string) { - let info = data.find((item: any) => item.id === itemID); - if (!info || !info.neState.online) return; + const neType=itemID.split('_')[0]; + const neID=itemID.split('_')[1]; + let info = data.find((item: any) => item.id === neType); + + if (!info || !info.neStateMap[neID]?.online) return; // if (!info.neState.online) { // info = data.find((item: any) => item.id === itemID); // graphNodeClickID.value = itemID; @@ -249,16 +252,16 @@ function fnChangeData(data: any[], itemID: string) { // console.log(info.neState.disk); let sysCpuUsage = 0; let nfCpuUsage = 0; - if (info.neState.cpu) { - nfCpuUsage = info.neState.cpu.nfCpuUsage; - const nfCpu = +(info.neState.cpu.nfCpuUsage / 100); + if (info.neStateMap[neID].cpu) { + nfCpuUsage = info.neStateMap[neID].cpu.nfCpuUsage; + const nfCpu = +(info.neStateMap[neID].cpu.nfCpuUsage / 100); nfCpuUsage = +nfCpu.toFixed(2); if (nfCpuUsage > 100) { nfCpuUsage = 100; } - sysCpuUsage = info.neState.cpu.sysCpuUsage; - let sysCpu = +(info.neState.cpu.sysCpuUsage / 100); + sysCpuUsage = info.neStateMap[neID].cpu.sysCpuUsage; + let sysCpu = +(info.neStateMap[neID].cpu.sysCpuUsage / 100); sysCpuUsage = +sysCpu.toFixed(2); if (sysCpuUsage > 100) { sysCpuUsage = 100; @@ -266,8 +269,8 @@ function fnChangeData(data: any[], itemID: string) { } let sysMemUsage = 0; - if (info.neState.mem) { - const men = info.neState.mem.sysMemUsage; + if (info.neStateMap[neID].mem) { + const men = info.neStateMap[neID].mem.sysMemUsage; sysMemUsage = +(men / 100).toFixed(2); if (sysMemUsage > 100) { sysMemUsage = 100; @@ -275,8 +278,8 @@ function fnChangeData(data: any[], itemID: string) { } let sysDiskUsage = 0; - if (info.neState.disk && Array.isArray(info.neState.disk.partitionInfo)) { - let disks: any[] = info.neState.disk.partitionInfo; + if (info.neStateMap[neID].disk && Array.isArray(info.neStateMap[neID].disk.partitionInfo)) { + let disks: any[] = info.neStateMap[neID].disk.partitionInfo; disks = disks.sort((a, b) => +b.used - +a.used); if (disks.length > 0) { const { total, used } = disks[0]; diff --git a/src/views/dashboard/overview/components/Topology/index.vue b/src/views/dashboard/overview/components/Topology/index.vue index 12e9d763..51e55688 100644 --- a/src/views/dashboard/overview/components/Topology/index.vue +++ b/src/views/dashboard/overview/components/Topology/index.vue @@ -22,18 +22,25 @@ 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(); + //console.log(neInfoList,neState,neInfoList); 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')) + : 'undefined' + } +
+ ${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 +176,6 @@ function handleRanderGraph( graph.data(data); graph.render(); - fnGraphEvent(graph); graphG6.value = graph; @@ -150,14 +203,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 +236,45 @@ 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.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; } + //(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; } ); @@ -215,7 +286,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/components/UserActivity/index.vue b/src/views/dashboard/overview/components/UserActivity/index.vue index 7bd187c1..37c50eaf 100644 --- a/src/views/dashboard/overview/components/UserActivity/index.vue +++ b/src/views/dashboard/overview/components/UserActivity/index.vue @@ -201,7 +201,7 @@ onMounted(() => { {{ dict.ueEventType - .find(s => s.value === item.type) + .find((s: any) => s.value === item.type) ?.label.replace('CM', 'ECM') }} diff --git a/src/views/dashboard/overview/hooks/useTopology.ts b/src/views/dashboard/overview/hooks/useTopology.ts index 64c01c68..ff83a840 100644 --- a/src/views/dashboard/overview/hooks/useTopology.ts +++ b/src/views/dashboard/overview/hooks/useTopology.ts @@ -35,16 +35,20 @@ export const graphState = reactive>({ export const graphG6 = ref(null); /**图点击选择 */ -export const graphNodeClickID = ref('UPF'); +export const graphNodeClickID = ref('UPF_001'); /**图节点网元信息状态 */ -export const graphNodeState = computed(() => - graphState.data.nodes.map((item: any) => ({ +export const graphNodeState = computed(() =>{ + return graphState.data.nodes.map((item: any) => ({ id: item.id, label: item.label, neInfo: item.neInfo, neState: item.neState, + neInfoList:item.neInfoList, + neStateMap: item.neStateMap, })) +} + ); /**图节点网元状态数量 */ @@ -68,48 +72,69 @@ 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) { + // console.log('neStateParse',neType, data, neId); + const { combos, edges, nodes } = graphState.data; + const node = nodes.find((item: Record) => item.id === neType); + //console.log('neStateParse',node); + + 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 + }; + // 如果是001,更新节点状态。neInfo为主要的网元信息 + if (node.neInfo && node.neInfo.neId === neId) { + Object.assign(node.neState, newNeState); + } - // 通过 ID 查询节点实例 + //console.log(node.neState) + // 无论是否为主要网元,都更新状态映射 + 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) { - graphG6.value.updateItem(item, { - label: newNeState.neName, - }); - } - // 设置状态 - 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); + // 检查当前节点下所有网元的状态 + const allStates = Object.values(node.neStateMap); + // 判断状态颜色 + let stateColor = '#52c41a'; // 默认绿色(所有网元都正常) + if (allStates.some((state: any) => !state.online)) { + // 如果有任何一个网元不正常 + stateColor = allStates.every((state: any) => !state.online) ? '#f5222d' : '#faad14'; // 红色(全部不正常)或黄色(部分不正常) } + + // 图片类型不能填充 + if (node.type && node.type.startsWith('image')) { + // 更新节点 + if (node.label !== newNeState.neType) { + graphG6.value.updateItem(item, { + label: newNeState.neType, + }); + } + // 设置状态 + graphG6.value.setItemState(item, 'top-right-dot', stateColor); + } else { + // 更新节点 + graphG6.value.updateItem(item, { + label: newNeState.neType, + style: { + fill: stateColor, // 填充色 + stroke: stateColor, // 填充色 + }, + }); + // 设置状态 + graphG6.value.setItemState(item, 'stroke', newNeState.online); + } + } // 设置边状态 @@ -167,6 +192,6 @@ export function topologyReset() { nodes: [], }; graphG6.value = null; - graphNodeClickID.value = 'UPF'; + graphNodeClickID.value = 'UPF_001'; neStateRequestMap.value = new Map(); } diff --git a/src/views/dashboard/overview/hooks/useWS.ts b/src/views/dashboard/overview/hooks/useWS.ts index 0810be2e..abd41b13 100644 --- a/src/views/dashboard/overview/hooks/useWS.ts +++ b/src/views/dashboard/overview/hooks/useWS.ts @@ -17,10 +17,7 @@ import { topologyReset, neStateParse, neStateRequestMap } from './useTopology'; import PQueue from 'p-queue'; /**UPF-的Id */ -export const upfWhoId = ref(''); - -/**UPF-的RmUid */ -export const upfWhoRmUid = ref(''); +export const upfWhoId = ref('001'); /**websocket连接 */ export default function useWS() { @@ -34,7 +31,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 +39,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; } @@ -71,13 +68,13 @@ export default function useWS() { } break; //UPF-总流量数 - case 'upf_001_0': + case `upf_${upfWhoId.value}_0`: upfTFParse('0', data); break; - case 'upf_001_7': + case `upf_${upfWhoId.value}_7`: upfTFParse('7', data); break; - case 'upf_001_30': + case `upf_${upfWhoId.value}_30`: upfTFParse('30', data); break; } @@ -87,7 +84,7 @@ export default function useWS() { } switch (data.groupId) { // kpiEvent 指标UPF - case '10_UPF_' + upfWhoId.value: + case `10_UPF_${upfWhoId.value}`: if (data.data) { upfFlowParse(data.data); } @@ -122,11 +119,11 @@ export default function useWS() { upfTotalFlow.value[day].requestFlag = true; ws.send({ - requestId: `upf_001_${day}`, + requestId: `upf_${upfWhoId.value}_${day}`, type: 'upf_tf', data: { neType: 'UPF', - neId: '001', + neId: upfWhoId.value, day: Number(day), }, }); @@ -197,7 +194,7 @@ export default function useWS() { * MME_UE会话事件(GroupID:1011_neId) * IMS_CDR会话事件(GroupID:1005_neId) */ - subGroupID: '10_UPF_' + neId + ',1010_001,1011_001,1005_001', + subGroupID: `10_UPF_${neId},1010_001,1011_001,1005_001`, }, onmessage: wsMessage, onerror: (ev: any) => { @@ -212,7 +209,7 @@ export default function useWS() { userActivityReset(); upfTotalFlowReset(); topologyReset(); - upfWhoRmUid.value = ''; + upfWhoId.value = ''; }); return { diff --git a/src/views/dashboard/overview/index.vue b/src/views/dashboard/overview/index.vue index b19477d1..b29531b2 100644 --- a/src/views/dashboard/overview/index.vue +++ b/src/views/dashboard/overview/index.vue @@ -84,20 +84,22 @@ 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, + }, + }); + } } } @@ -189,7 +191,7 @@ async function fnGetSkim() { enbNum: 0, enbUeNum: 0, }); - results.forEach((result, index) => { + results.forEach((result: any, index: any) => { if (result.status === 'fulfilled') { requests[index].process(result.value); } else { @@ -233,7 +235,7 @@ function loadData() { if (!interval5s.value || !initFlag) return; fnGetSkim(); // 获取概览信息 fnGetNeState(); // 获取网元状态 - }, 5_000); + }, 10_000); } /**栏目信息跳转 */ @@ -260,6 +262,8 @@ function fnSelectNe(value: any, option: any) { let udmNeId = ref('001'); let udmOtions = ref[]>([]); +let onlineOtions = ref[]>([]); + /**用户数量-选择UDM */ function fnSelectUDM(e: any) { udmNeId.value = e.key; @@ -269,7 +273,11 @@ function fnSelectUDM(e: any) { } }); } - +/**资源控制-选择NE */ +function fnSelectNeRe(e: any) { + graphNodeClickID.value = e.key; +} +// // 定义一个方法返回 views 容器 const getPopupContainer = () => { // 使用 ref 或其他方式来引用你的 views 容器 @@ -296,19 +304,47 @@ onMounted(() => { //queryParams.neRealId = arr[0].value; fnSelectNe(arr[0].value, arr[0]); } + //online Ne + let onlineArr: Record[] = []; // UDM let arr1: Record[] = []; res.data.forEach((v: any) => { + if ( + v.status && + [ + 'UDM', + 'UPF', + 'AUSF', + 'PCF', + 'SMF', + 'AMF', + 'OMC', + 'SMSC', + 'IMS', + 'MME', + ].includes(v.neType) + ) { + onlineArr.push({ + value: v.neType + '_' + v.neId, + label: v.neName, + rmUid: v.rmUid, + }); + } if (v.neType === 'UDM') { arr1.push({ value: v.neId, label: v.neName, rmUid: v.rmUid }); } }); udmOtions.value = arr1; + onlineOtions.value = onlineArr; if (arr1.length > 0) { fnSelectUDM({ key: arr1[0].value }); } + if (onlineArr.length > 0) { + fnSelectNeRe({ key: onlineArr[0].value }); + } + // 过滤不可用的网元 neCascaderOptions.value = neInfoStore.getNeCascaderOptions.filter( (item: any) => { @@ -382,7 +418,10 @@ onBeforeUnmount(() => { {{ skimState.udmSubNum }} - +
{{ t('views.dashboard.overview.skim.users') }} @@ -645,10 +684,25 @@ onBeforeUnmount(() => {
-

+

   {{ t('views.dashboard.overview.resources.title') }}: - {{ graphNodeClickID }} + +
+ {{ graphNodeClickID }} + +
+ +

@@ -661,6 +715,7 @@ onBeforeUnmount(() => {