rev: 回退看板,修复切换upf的流量统计显示

This commit is contained in:
TsMask
2025-08-07 15:46:01 +08:00
parent 678bfce993
commit 246bb9a7e0
8 changed files with 431 additions and 203 deletions

View File

@@ -236,8 +236,11 @@ function handleRanderChart(
} }
function fnChangeData(data: any[], itemID: string) { function fnChangeData(data: any[], itemID: string) {
let info = data.find((item: any) => item.id === itemID); const neType=itemID.split('_')[0];
if (!info || !info.neState.online) return; 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) { // if (!info.neState.online) {
// info = data.find((item: any) => item.id === itemID); // info = data.find((item: any) => item.id === itemID);
// graphNodeClickID.value = itemID; // graphNodeClickID.value = itemID;
@@ -249,16 +252,16 @@ function fnChangeData(data: any[], itemID: string) {
// console.log(info.neState.disk); // console.log(info.neState.disk);
let sysCpuUsage = 0; let sysCpuUsage = 0;
let nfCpuUsage = 0; let nfCpuUsage = 0;
if (info.neState.cpu) { if (info.neStateMap[neID].cpu) {
nfCpuUsage = info.neState.cpu.nfCpuUsage; nfCpuUsage = info.neStateMap[neID].cpu.nfCpuUsage;
const nfCpu = +(info.neState.cpu.nfCpuUsage / 100); const nfCpu = +(info.neStateMap[neID].cpu.nfCpuUsage / 100);
nfCpuUsage = +nfCpu.toFixed(2); nfCpuUsage = +nfCpu.toFixed(2);
if (nfCpuUsage > 100) { if (nfCpuUsage > 100) {
nfCpuUsage = 100; nfCpuUsage = 100;
} }
sysCpuUsage = info.neState.cpu.sysCpuUsage; sysCpuUsage = info.neStateMap[neID].cpu.sysCpuUsage;
let sysCpu = +(info.neState.cpu.sysCpuUsage / 100); let sysCpu = +(info.neStateMap[neID].cpu.sysCpuUsage / 100);
sysCpuUsage = +sysCpu.toFixed(2); sysCpuUsage = +sysCpu.toFixed(2);
if (sysCpuUsage > 100) { if (sysCpuUsage > 100) {
sysCpuUsage = 100; sysCpuUsage = 100;
@@ -266,8 +269,8 @@ function fnChangeData(data: any[], itemID: string) {
} }
let sysMemUsage = 0; let sysMemUsage = 0;
if (info.neState.mem) { if (info.neStateMap[neID].mem) {
const men = info.neState.mem.sysMemUsage; const men = info.neStateMap[neID].mem.sysMemUsage;
sysMemUsage = +(men / 100).toFixed(2); sysMemUsage = +(men / 100).toFixed(2);
if (sysMemUsage > 100) { if (sysMemUsage > 100) {
sysMemUsage = 100; sysMemUsage = 100;
@@ -275,8 +278,8 @@ function fnChangeData(data: any[], itemID: string) {
} }
let sysDiskUsage = 0; let sysDiskUsage = 0;
if (info.neState.disk && Array.isArray(info.neState.disk.partitionInfo)) { if (info.neStateMap[neID].disk && Array.isArray(info.neStateMap[neID].disk.partitionInfo)) {
let disks: any[] = info.neState.disk.partitionInfo; let disks: any[] = info.neStateMap[neID].disk.partitionInfo;
disks = disks.sort((a, b) => +b.used - +a.used); disks = disks.sort((a, b) => +b.used - +a.used);
if (disks.length > 0) { if (disks.length > 0) {
const { total, used } = disks[0]; const { total, used } = disks[0];

View File

@@ -22,17 +22,24 @@ const graphG6Dom = ref<HTMLElement | undefined>(undefined);
/**图节点展示 */ /**图节点展示 */
const graphNodeTooltip = new Tooltip({ const graphNodeTooltip = new Tooltip({
offsetX: 20, offsetX: 10,
offsetY: 20, offsetY: 20,
getContent(evt) { getContent(evt) {
if (!evt) return t('views.monitor.topologyBuild.graphNotInfo'); 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)) { if (notNeNodes.includes(id)) {
return `<div><span>${label || id}</span></div>`; return `<div><span>${label || id}</span></div>`;
} }
if (!neState) { if (!neState) {
return `<div><span>${label || id}</span></div>`; return `<div><span>${label || id}</span></div>`;
} }
// 获取同类型网元列表
const sameTypeNes = neInfoList || [];
// 如果没有网元或只有一个网元,显示原来的信息
if (sameTypeNes.length <= 1) {
return ` return `
<div <div
style=" style="
@@ -56,7 +63,7 @@ const graphNodeTooltip = new Tooltip({
<div><strong>${t('views.monitor.topology.name')}</strong><span> <div><strong>${t('views.monitor.topology.name')}</strong><span>
${neState.neName ?? '--'} ${neState.neName ?? '--'}
</span></div> </span></div>
<div><strong>IP</strong><span>${neState.neIP}</span></div> <div><strong>IP</strong><span>${neState.neIP ?? '--'}</span></div>
<div><strong>${t('views.monitor.topology.version')}</strong><span> <div><strong>${t('views.monitor.topology.version')}</strong><span>
${neState.version ?? '--'} ${neState.version ?? '--'}
</span></div> </span></div>
@@ -68,21 +75,68 @@ const graphNodeTooltip = new Tooltip({
</span></div> </span></div>
</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'], 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( function handleRanderGraph(
@@ -122,7 +176,6 @@ function handleRanderGraph(
graph.data(data); graph.data(data);
graph.render(); graph.render();
fnGraphEvent(graph);
graphG6.value = graph; graphG6.value = graph;
@@ -183,27 +236,45 @@ function fnGraphDataLoad(reload: boolean = false) {
if (!res) return; if (!res) return;
const { combos, edges, nodes } = res.graphData; 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( const nf: Record<string, any>[] = nodes.filter(
(node: Record<string, any>) => { (node: Record<string, any>) => {
Reflect.set(node, 'neState', { online: false }); Reflect.set(node, 'neState', { online: false });
Reflect.set(node, 'neStateMap', {}); // 初始化状态映射
// 图片路径处理 // 图片路径处理
if (node.img) node.img = parseBasePath(node.img); 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); node.icon.img = parseBasePath(node.icon.img);
} }
// 遍历是否有网元数据 // 遍历是否有网元数据
const nodeID: string = node.id; 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)) { if (notNeNodes.includes(nodeID)) {
return true; 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; return false;
} }
); );
@@ -215,7 +286,6 @@ function fnGraphDataLoad(reload: boolean = false) {
const edgeTarget: string = edge.target; const edgeTarget: string = edge.target;
const hasNeS = nf.some(n => n.id === edgeSource); const hasNeS = nf.some(n => n.id === edgeSource);
const hasNeT = nf.some(n => n.id === edgeTarget); const hasNeT = nf.some(n => n.id === edgeTarget);
// console.log(hasNeS, edgeSource, hasNeT, edgeTarget);
if (hasNeS && hasNeT) { if (hasNeS && hasNeT) {
return true; return true;
} }

View File

@@ -201,7 +201,7 @@ onMounted(() => {
<span v-if="item.type === 'cm-state'"> <span v-if="item.type === 'cm-state'">
{{ {{
dict.ueEventType dict.ueEventType
.find(s => s.value === item.type) .find((s: any) => s.value === item.type)
?.label.replace('CM', 'ECM') ?.label.replace('CM', 'ECM')
}} }}
</span> </span>

View File

@@ -35,16 +35,20 @@ export const graphState = reactive<Record<string, any>>({
export const graphG6 = ref<any>(null); export const graphG6 = ref<any>(null);
/**图点击选择 */ /**图点击选择 */
export const graphNodeClickID = ref<string>('UPF'); export const graphNodeClickID = ref<string>('UPF_001');
/**图节点网元信息状态 */ /**图节点网元信息状态 */
export const graphNodeState = computed(() => export const graphNodeState = computed(() =>{
graphState.data.nodes.map((item: any) => ({ return graphState.data.nodes.map((item: any) => ({
id: item.id, id: item.id,
label: item.label, label: item.label,
neInfo: item.neInfo, neInfo: item.neInfo,
neState: item.neState, neState: item.neState,
neInfoList:item.neInfoList,
neStateMap: item.neStateMap,
})) }))
}
); );
/**图节点网元状态数量 */ /**图节点网元状态数量 */
@@ -68,26 +72,52 @@ export const graphNodeStateNum = computed(() => {
export const neStateRequestMap = ref<Map<string, boolean>>(new Map()); export const neStateRequestMap = ref<Map<string, boolean>>(new Map());
/**neStateParse 网元状态 数据解析 */ /**neStateParse 网元状态 数据解析 */
export function neStateParse(neType: string, data: Record<string, any>) { export function neStateParse(neType: string, data: Record<string, any>,neId: string) {
// console.log('neStateParse',neType, data, neId);
const { combos, edges, nodes } = graphState.data; const { combos, edges, nodes } = graphState.data;
const node = nodes.find((item: Record<string, any>) => item.id === neType); const node = nodes.find((item: Record<string, any>) => 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'), refreshTime: parseDateToStr(data.refreshTime, 'HH:mm:ss'),
online: !!data.cpu, online: !!data.cpu,
}); neId: neId
};
// 如果是001更新节点状态。neInfo为主要的网元信息
if (node.neInfo && node.neInfo.neId === neId) {
Object.assign(node.neState, newNeState);
}
//console.log(node.neState)
// 无论是否为主要网元,都更新状态映射
node.neStateMap[neId] = {...newNeState};
// 通过 ID 查询节点实例 // 通过 ID 查询节点实例
const item = graphG6.value.findById(node.id); const item = graphG6.value.findById(node.id);
if (item) { if (item) {
const stateColor = newNeState.online ? '#52c41a' : '#f5222d'; // 状态颜色 // 检查当前节点下所有网元的状态
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.startsWith('image')) { if (node.type && node.type.startsWith('image')) {
// 更新节点 // 更新节点
if (node.label !== newNeState.neName) { if (node.label !== newNeState.neType) {
graphG6.value.updateItem(item, { graphG6.value.updateItem(item, {
label: newNeState.neName, label: newNeState.neType,
}); });
} }
// 设置状态 // 设置状态
@@ -95,21 +125,16 @@ export function neStateParse(neType: string, data: Record<string, any>) {
} else { } else {
// 更新节点 // 更新节点
graphG6.value.updateItem(item, { graphG6.value.updateItem(item, {
label: newNeState.neName, label: newNeState.neType,
// neState: newNeState,
style: { style: {
fill: stateColor, // 填充色 fill: stateColor, // 填充色
stroke: stateColor, // 填充色 stroke: stateColor, // 填充色
}, },
// labelCfg: {
// style: {
// fill: '#ffffff', // 标签文本色
// },
// },
}); });
// 设置状态 // 设置状态
graphG6.value.setItemState(item, 'stroke', newNeState.online); graphG6.value.setItemState(item, 'stroke', newNeState.online);
} }
} }
// 设置边状态 // 设置边状态
@@ -167,6 +192,6 @@ export function topologyReset() {
nodes: [], nodes: [],
}; };
graphG6.value = null; graphG6.value = null;
graphNodeClickID.value = 'UPF'; graphNodeClickID.value = 'UPF_001';
neStateRequestMap.value = new Map(); neStateRequestMap.value = new Map();
} }

View File

@@ -17,10 +17,7 @@ import { topologyReset, neStateParse, neStateRequestMap } from './useTopology';
import PQueue from 'p-queue'; import PQueue from 'p-queue';
/**UPF-的Id */ /**UPF-的Id */
export const upfWhoId = ref<any>(''); export const upfWhoId = ref<any>('001');
/**UPF-的RmUid */
export const upfWhoRmUid = ref<any>('');
/**websocket连接 */ /**websocket连接 */
export default function useWS() { export default function useWS() {
@@ -34,7 +31,6 @@ export default function useWS() {
/**接收数据后回调 */ /**接收数据后回调 */
function wsMessage(res: Record<string, any>) { function wsMessage(res: Record<string, any>) {
//console.log(res);
const { code, requestId, data } = res; const { code, requestId, data } = res;
if (code === RESULT_CODE_ERROR) { if (code === RESULT_CODE_ERROR) {
console.warn(res.msg); console.warn(res.msg);
@@ -43,7 +39,8 @@ export default function useWS() {
// 网元状态 // 网元状态
if (requestId && requestId.startsWith('neState')) { if (requestId && requestId.startsWith('neState')) {
const neType = requestId.split('_')[1]; const neType = requestId.split('_')[1];
neStateParse(neType, data); const neId = requestId.split('_')[2];
neStateParse(neType, data, neId);
return; return;
} }
@@ -71,13 +68,13 @@ export default function useWS() {
} }
break; break;
//UPF-总流量数 //UPF-总流量数
case 'upf_001_0': case `upf_${upfWhoId.value}_0`:
upfTFParse('0', data); upfTFParse('0', data);
break; break;
case 'upf_001_7': case `upf_${upfWhoId.value}_7`:
upfTFParse('7', data); upfTFParse('7', data);
break; break;
case 'upf_001_30': case `upf_${upfWhoId.value}_30`:
upfTFParse('30', data); upfTFParse('30', data);
break; break;
} }
@@ -87,7 +84,7 @@ export default function useWS() {
} }
switch (data.groupId) { switch (data.groupId) {
// kpiEvent 指标UPF // kpiEvent 指标UPF
case '10_UPF_' + upfWhoId.value: case `10_UPF_${upfWhoId.value}`:
if (data.data) { if (data.data) {
upfFlowParse(data.data); upfFlowParse(data.data);
} }
@@ -122,11 +119,11 @@ export default function useWS() {
upfTotalFlow.value[day].requestFlag = true; upfTotalFlow.value[day].requestFlag = true;
ws.send({ ws.send({
requestId: `upf_001_${day}`, requestId: `upf_${upfWhoId.value}_${day}`,
type: 'upf_tf', type: 'upf_tf',
data: { data: {
neType: 'UPF', neType: 'UPF',
neId: '001', neId: upfWhoId.value,
day: Number(day), day: Number(day),
}, },
}); });
@@ -197,7 +194,7 @@ export default function useWS() {
* MME_UE会话事件(GroupID:1011_neId) * MME_UE会话事件(GroupID:1011_neId)
* IMS_CDR会话事件(GroupID:1005_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, onmessage: wsMessage,
onerror: (ev: any) => { onerror: (ev: any) => {
@@ -212,7 +209,7 @@ export default function useWS() {
userActivityReset(); userActivityReset();
upfTotalFlowReset(); upfTotalFlowReset();
topologyReset(); topologyReset();
upfWhoRmUid.value = ''; upfWhoId.value = '';
}); });
return { return {

View File

@@ -84,22 +84,24 @@ function fnGetNeState() {
// 获取节点状态 // 获取节点状态
for (const node of graphState.data.nodes) { for (const node of graphState.data.nodes) {
if (notNeNodes.includes(node.id)) continue; if (notNeNodes.includes(node.id)) continue;
const { neType, neId } = node.neInfo;
if (!neType || !neId) continue; const neInfoList = node.neInfoList || [];
// 请求标记检查避免重复发送 if (neInfoList.length === 0) continue;
if (neStateRequestMap.value.get(neType)) continue;
neStateRequestMap.value.set(neType, true); for (const neInfo of neInfoList) {
if (!neInfo.neType || !neInfo.neId) continue;
wsSend({ wsSend({
requestId: `neState_${neType}_${neId}`, requestId: `neState_${neInfo.neType}_${neInfo.neId}`,
type: 'ne_state', type: 'ne_state',
data: { data: {
neType: neType, neType: neInfo.neType,
neId: neId, neId: neInfo.neId,
}, },
}); });
} }
} }
}
/**获取概览信息 */ /**获取概览信息 */
async function fnGetSkim() { async function fnGetSkim() {
@@ -189,7 +191,7 @@ async function fnGetSkim() {
enbNum: 0, enbNum: 0,
enbUeNum: 0, enbUeNum: 0,
}); });
results.forEach((result, index) => { results.forEach((result: any, index: any) => {
if (result.status === 'fulfilled') { if (result.status === 'fulfilled') {
requests[index].process(result.value); requests[index].process(result.value);
} else { } else {
@@ -233,7 +235,7 @@ function loadData() {
if (!interval5s.value || !initFlag) return; if (!interval5s.value || !initFlag) return;
fnGetSkim(); // 获取概览信息 fnGetSkim(); // 获取概览信息
fnGetNeState(); // 获取网元状态 fnGetNeState(); // 获取网元状态
}, 5_000); }, 10_000);
} }
/**栏目信息跳转 */ /**栏目信息跳转 */
@@ -260,6 +262,8 @@ function fnSelectNe(value: any, option: any) {
let udmNeId = ref<string>('001'); let udmNeId = ref<string>('001');
let udmOtions = ref<Record<string, any>[]>([]); let udmOtions = ref<Record<string, any>[]>([]);
let onlineOtions = ref<Record<string, any>[]>([]);
/**用户数量-选择UDM */ /**用户数量-选择UDM */
function fnSelectUDM(e: any) { function fnSelectUDM(e: any) {
udmNeId.value = e.key; udmNeId.value = e.key;
@@ -269,7 +273,11 @@ function fnSelectUDM(e: any) {
} }
}); });
} }
/**资源控制-选择NE */
function fnSelectNeRe(e: any) {
graphNodeClickID.value = e.key;
}
//
// 定义一个方法返回 views 容器 // 定义一个方法返回 views 容器
const getPopupContainer = () => { const getPopupContainer = () => {
// 使用 ref 或其他方式来引用你的 views 容器 // 使用 ref 或其他方式来引用你的 views 容器
@@ -296,19 +304,47 @@ onMounted(() => {
//queryParams.neRealId = arr[0].value; //queryParams.neRealId = arr[0].value;
fnSelectNe(arr[0].value, arr[0]); fnSelectNe(arr[0].value, arr[0]);
} }
//online Ne
let onlineArr: Record<string, any>[] = [];
// UDM // UDM
let arr1: Record<string, any>[] = []; let arr1: Record<string, any>[] = [];
res.data.forEach((v: any) => { 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') { if (v.neType === 'UDM') {
arr1.push({ value: v.neId, label: v.neName, rmUid: v.rmUid }); arr1.push({ value: v.neId, label: v.neName, rmUid: v.rmUid });
} }
}); });
udmOtions.value = arr1; udmOtions.value = arr1;
onlineOtions.value = onlineArr;
if (arr1.length > 0) { if (arr1.length > 0) {
fnSelectUDM({ key: arr1[0].value }); fnSelectUDM({ key: arr1[0].value });
} }
if (onlineArr.length > 0) {
fnSelectNeRe({ key: onlineArr[0].value });
}
// 过滤不可用的网元 // 过滤不可用的网元
neCascaderOptions.value = neInfoStore.getNeCascaderOptions.filter( neCascaderOptions.value = neInfoStore.getNeCascaderOptions.filter(
(item: any) => { (item: any) => {
@@ -382,7 +418,10 @@ onBeforeUnmount(() => {
{{ skimState.udmSubNum }} {{ skimState.udmSubNum }}
</div> </div>
<span> <span>
<a-dropdown :trigger="['click']"> <a-dropdown
:trigger="['click']"
:get-Popup-Container="getPopupContainer"
>
<div class="toDeep-text"> <div class="toDeep-text">
{{ t('views.dashboard.overview.skim.users') }} {{ t('views.dashboard.overview.skim.users') }}
<DownOutlined style="margin-left: 12px; font-size: 12px" /> <DownOutlined style="margin-left: 12px; font-size: 12px" />
@@ -645,10 +684,25 @@ onBeforeUnmount(() => {
<!-- 资源情况 --> <!-- 资源情况 -->
<div class="resources panel"> <div class="resources panel">
<div class="inner"> <div class="inner">
<h3> <h3 style="display: flex; align-items: center">
<DashboardOutlined style="color: #68d8fe" />&nbsp;&nbsp; <DashboardOutlined style="color: #68d8fe" />&nbsp;&nbsp;
{{ t('views.dashboard.overview.resources.title') }} {{ t('views.dashboard.overview.resources.title') }}
<a-dropdown
:trigger="['click']"
:get-Popup-Container="getPopupContainer"
>
<div class="toDeep-text">
{{ graphNodeClickID }} {{ graphNodeClickID }}
<DownOutlined style="margin-left: 12px; font-size: 12px" />
</div>
<template #overlay>
<a-menu @click="fnSelectNeRe">
<a-menu-item v-for="v in onlineOtions" :key="v.value">
{{ v.label }}
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</h3> </h3>
<div class="chart"> <div class="chart">
<NeResources /> <NeResources />
@@ -661,6 +715,7 @@ onBeforeUnmount(() => {
<style lang="less" scoped> <style lang="less" scoped>
@import url('./css/index.css'); @import url('./css/index.css');
.toDeep { .toDeep {
--editor-background-color: blue; --editor-background-color: blue;
} }
@@ -677,6 +732,7 @@ onBeforeUnmount(() => {
.toDeep :deep(.ant-select-selection-item) { .toDeep :deep(.ant-select-selection-item) {
color: #fff; color: #fff;
} }
.toDeep-text { .toDeep-text {
color: #4c9bfd !important; color: #4c9bfd !important;
font-size: 0.844rem !important; font-size: 0.844rem !important;

View File

@@ -19,9 +19,6 @@ import PQueue from 'p-queue';
/**UPF-的Id */ /**UPF-的Id */
export const upfWhoId = ref<any>(''); export const upfWhoId = ref<any>('');
/**UPF-的RmUid */
export const upfWhoRmUid = ref<any>('');
/**websocket连接 */ /**websocket连接 */
export default function useWS() { export default function useWS() {
const ws = new WS(); const ws = new WS();
@@ -212,7 +209,7 @@ export default function useWS() {
userActivityReset(); userActivityReset();
upfTotalFlowReset(); upfTotalFlowReset();
topologyReset(); topologyReset();
upfWhoRmUid.value = ''; upfWhoId.value = '';
}); });
return { return {

View File

@@ -14,13 +14,7 @@ import { listUDMSub } from '@/api/neData/udm_sub';
import { listUENumBySMF } from '@/api/neUser/smf'; import { listUENumBySMF } from '@/api/neUser/smf';
import { listUENumByIMS } from '@/api/neUser/ims'; import { listUENumByIMS } from '@/api/neUser/ims';
import { listBase5G } from '@/api/neUser/base5G'; import { listBase5G } from '@/api/neUser/base5G';
import { import { graphNodeClickID, graphState, notNeNodes } from './hooks/useTopology';
graphNodeClickID,
graphState,
notNeNodes,
graphNodeStateNum,
neStateRequestMap,
} from './hooks/useTopology';
import { upfTotalFlow, upfTFActive } from './hooks/useUPFTotalFlow'; import { upfTotalFlow, upfTFActive } from './hooks/useUPFTotalFlow';
import { useFullscreen } from '@vueuse/core'; import { useFullscreen } from '@vueuse/core';
import useWS from './hooks/useWS'; import useWS from './hooks/useWS';
@@ -30,12 +24,9 @@ import { useRouter } from 'vue-router';
import useNeInfoStore from '@/store/modules/neinfo'; import useNeInfoStore from '@/store/modules/neinfo';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import { upfWhoId } from './hooks/useWS'; import { upfWhoId } from './hooks/useWS';
import { import { listAMFNbStatelist } from '@/api/neData/amf';
listAMFNbStatelist,
} from '@/api/neData/amf';
import { listMMENbStatelist } from '@/api/neData/mme'; import { listMMENbStatelist } from '@/api/neData/mme';
const neInfoStore = useNeInfoStore(); const neInfoStore = useNeInfoStore();
const router = useRouter(); const router = useRouter();
const appStore = useAppStore(); const appStore = useAppStore();
@@ -74,7 +65,6 @@ let skimState: SkimStateType = reactive({
enbUeNum: 0, enbUeNum: 0,
gNbSumNum: 0, gNbSumNum: 0,
eNbSumNum: 0, eNbSumNum: 0,
}); });
/**网元参数 */ /**网元参数 */
@@ -97,13 +87,10 @@ function fnGetNeState() {
for (const node of graphState.data.nodes) { for (const node of graphState.data.nodes) {
if (notNeNodes.includes(node.id)) continue; if (notNeNodes.includes(node.id)) continue;
const neInfoList = node.neInfoList || []; const neInfoList = node.neInfoList || [];
if (neInfoList.length === 0) continue; if (neInfoList.length === 0) continue;
for (const neInfo of neInfoList) { for (const neInfo of neInfoList) {
if (!neInfo.neType || !neInfo.neId) continue; if (!neInfo.neType || !neInfo.neId) continue;
wsSend({ wsSend({
@@ -120,7 +107,6 @@ function fnGetNeState() {
/**获取概览信息 */ /**获取概览信息 */
async function fnGetSkim() { async function fnGetSkim() {
let tempGnbSumNum = 0; let tempGnbSumNum = 0;
let tempEnbSumNum = 0; let tempEnbSumNum = 0;
@@ -138,7 +124,8 @@ async function fnGetSkim() {
[ [
'UDM', 'UDM',
{ {
request: (neId: string) => listUDMSub({ neId: neId, pageNum: 1, pageSize: 1 }), request: (neId: string) =>
listUDMSub({ neId: neId, pageNum: 1, pageSize: 1 }),
process: (res: any) => process: (res: any) =>
res.code === RESULT_CODE_SUCCESS && (skimState.udmSubNum = res.total), res.code === RESULT_CODE_SUCCESS && (skimState.udmSubNum = res.total),
}, },
@@ -171,10 +158,12 @@ async function fnGetSkim() {
0 0
); );
const amfNbRes = await listAMFNbStatelist({ neId }); const amfNbRes = await listAMFNbStatelist({ neId });
if (amfNbRes.code === RESULT_CODE_SUCCESS && Array.isArray(amfNbRes.data)) { if (
amfNbRes.code === RESULT_CODE_SUCCESS &&
Array.isArray(amfNbRes.data)
) {
// skimState.gNbSumNum += amfNbRes.data.length; // skimState.gNbSumNum += amfNbRes.data.length;
tempGnbSumNum += amfNbRes.data.length; tempGnbSumNum += amfNbRes.data.length;
} }
} }
}, },
@@ -193,11 +182,13 @@ async function fnGetSkim() {
); );
const mmeNbRes = await listMMENbStatelist({ neId }); const mmeNbRes = await listMMENbStatelist({ neId });
if (mmeNbRes.code === RESULT_CODE_SUCCESS && Array.isArray(mmeNbRes.data)) { if (
mmeNbRes.code === RESULT_CODE_SUCCESS &&
Array.isArray(mmeNbRes.data)
) {
// skimState.eNbSumNum += mmeNbRes.data.length; // skimState.eNbSumNum += mmeNbRes.data.length;
tempEnbSumNum += mmeNbRes.data.length; tempEnbSumNum += mmeNbRes.data.length;
} }
} }
}, },
}, },
@@ -220,7 +211,7 @@ async function fnGetSkim() {
.filter(Boolean) || [] .filter(Boolean) || []
); );
const results = await Promise.allSettled(requests.map(r => r.promise)); const results = await Promise.allSettled(requests.map((r: any) => r.promise));
// 重置 // 重置
Object.assign(skimState, { Object.assign(skimState, {
@@ -232,7 +223,7 @@ async function fnGetSkim() {
enbNum: 0, enbNum: 0,
enbUeNum: 0, enbUeNum: 0,
}); });
const processPromises = results.map((result, index) => { const processPromises = results.map((result: any, index: any) => {
const req = requests[index]; const req = requests[index];
if (result.status === 'fulfilled') { if (result.status === 'fulfilled') {
return req.process(result.value, req.neId); return req.process(result.value, req.neId);
@@ -271,8 +262,6 @@ async function fnGetSkim() {
// }); // });
} }
/**初始数据函数 */ /**初始数据函数 */
function loadData() { function loadData() {
fnGetNeState(); // 获取网元状态 fnGetNeState(); // 获取网元状态
@@ -344,7 +333,11 @@ let onlineOtions = ref<Record<string, any>[]>([]);
async function fnSelectUDM(e: any) { async function fnSelectUDM(e: any) {
udmNeId.value = e.key; udmNeId.value = e.key;
try { try {
const res = await listUDMSub({ neId: udmNeId.value, pageNum: 1, pageSize: 1 }); const res = await listUDMSub({
neId: udmNeId.value,
pageNum: 1,
pageSize: 1,
});
// listUDMSub({ neId: udmNeId.value, pageNum: 1, pageSize: 1 }).then(res => { // listUDMSub({ neId: udmNeId.value, pageNum: 1, pageSize: 1 }).then(res => {
if (res.code === RESULT_CODE_SUCCESS) { if (res.code === RESULT_CODE_SUCCESS) {
skimState.udmSubNum = res.total; skimState.udmSubNum = res.total;
@@ -395,8 +388,26 @@ onMounted(() => {
// UDM // UDM
let arr1: Record<string, any>[] = []; let arr1: Record<string, any>[] = [];
res.data.forEach((v: any) => { res.data.forEach((v: any) => {
if (v.status && ['UDM', 'UPF', 'AUSF', 'PCF', 'SMF', 'AMF', 'OMC', 'SMSC', 'IMS', 'MME'].includes(v.neType)) { if (
onlineArr.push({ value: v.neType + '_' + v.neId, label: v.neName, rmUid: v.rmUid }); 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') { if (v.neType === 'UDM') {
arr1.push({ value: v.neId, label: v.neName, rmUid: v.rmUid }); arr1.push({ value: v.neId, label: v.neName, rmUid: v.rmUid });
@@ -461,7 +472,11 @@ onBeforeUnmount(() => {
<template> <template>
<div class="viewport" ref="viewportDom"> <div class="viewport" ref="viewportDom">
<div class="brand"> <div class="brand">
<div class="brand-title" @click="toggle" :title="t('views.dashboard.overview.fullscreen')"> <div
class="brand-title"
@click="toggle"
:title="t('views.dashboard.overview.fullscreen')"
>
{{ t('views.dashboard.overview.title') }} {{ t('views.dashboard.overview.title') }}
<FullscreenExitOutlined v-if="isFullscreen" /> <FullscreenExitOutlined v-if="isFullscreen" />
<FullscreenOutlined v-else /> <FullscreenOutlined v-else />
@@ -470,7 +485,6 @@ onBeforeUnmount(() => {
</div> </div>
<div class="column"> <div class="column">
<div class="skim panel"> <div class="skim panel">
<div class="inner"> <div class="inner">
<h3 class="leftright"> <h3 class="leftright">
@@ -480,20 +494,32 @@ onBeforeUnmount(() => {
</span> </span>
</h3> </h3>
<div class="data"> <div class="data">
<div class="item toRouter" :title="t('views.dashboard.overview.toRouter')"> <div
class="item toRouter"
:title="t('views.dashboard.overview.toRouter')"
>
<div @click="fnToRouter('Sub_2010')"> <div @click="fnToRouter('Sub_2010')">
<UserOutlined style="color: #4096ff; margin-right: 8px; font-size: 1.1rem" /> <UserOutlined
style="color: #4096ff; margin-right: 8px; font-size: 1.1rem"
/>
{{ skimState.udmSubNum }} {{ skimState.udmSubNum }}
</div> </div>
<span> <span>
<a-dropdown :trigger="['click']" :get-Popup-Container="getPopupContainer"> <a-dropdown
:trigger="['click']"
:get-Popup-Container="getPopupContainer"
>
<div class="toDeep-text"> <div class="toDeep-text">
{{ t('views.dashboard.overview.skim.users') }} {{ t('views.dashboard.overview.skim.users') }}
<DownOutlined style="margin-left: 12px; font-size: 12px" /> <DownOutlined style="margin-left: 12px; font-size: 12px" />
</div> </div>
<template #overlay> <template #overlay>
<a-menu @click="fnSelectUDM"> <a-menu @click="fnSelectUDM">
<a-menu-item v-for="v in udmOtions" :key="v.value" :disabled="udmNeId === v.value"> <a-menu-item
v-for="v in udmOtions"
:key="v.value"
:disabled="udmNeId === v.value"
>
{{ v.label }} {{ v.label }}
</a-menu-item> </a-menu-item>
</a-menu> </a-menu>
@@ -501,8 +527,13 @@ onBeforeUnmount(() => {
</a-dropdown> </a-dropdown>
</span> </span>
</div> </div>
<div class="item toRouter" @click="fnToRouter('Ims_2080')" :title="t('views.dashboard.overview.toRouter')" <div
style="margin: 0 12px" v-perms:has="['dashboard:overview:imsUeNum']"> class="item toRouter"
@click="fnToRouter('Ims_2080')"
:title="t('views.dashboard.overview.toRouter')"
style="margin: 0 12px"
v-perms:has="['dashboard:overview:imsUeNum']"
>
<div> <div>
<img :src="svgUserIMS" style="width: 18px; margin-right: 8px" /> <img :src="svgUserIMS" style="width: 18px; margin-right: 8px" />
{{ skimState.imsUeNum }} {{ skimState.imsUeNum }}
@@ -511,8 +542,12 @@ onBeforeUnmount(() => {
{{ t('views.dashboard.overview.skim.imsUeNum') }} {{ t('views.dashboard.overview.skim.imsUeNum') }}
</span> </span>
</div> </div>
<div class="item toRouter" @click="fnToRouter('Ue_2081')" :title="t('views.dashboard.overview.toRouter')" <div
v-perms:has="['dashboard:overview:smfUeNum']"> class="item toRouter"
@click="fnToRouter('Ue_2081')"
:title="t('views.dashboard.overview.toRouter')"
v-perms:has="['dashboard:overview:smfUeNum']"
>
<div> <div>
<img :src="svgUserSMF" style="width: 18px; margin-right: 8px" /> <img :src="svgUserSMF" style="width: 18px; margin-right: 8px" />
{{ skimState.smfUeNum }} {{ skimState.smfUeNum }}
@@ -525,11 +560,13 @@ onBeforeUnmount(() => {
</div> </div>
</div> </div>
<!--告警统计--> <!--告警统计-->
<div class="alarmType panel"> <div class="alarmType panel">
<div class="inner"> <div class="inner">
<h3 class="toRouter leftright" :title="t('views.dashboard.overview.toRouter')"> <h3
class="toRouter leftright"
:title="t('views.dashboard.overview.toRouter')"
>
<span class="title" @click="fnToRouter('HistoryAlarm_2097')"> <span class="title" @click="fnToRouter('HistoryAlarm_2097')">
<PieChartOutlined style="color: #68d8fe" />&nbsp;&nbsp; <PieChartOutlined style="color: #68d8fe" />&nbsp;&nbsp;
{{ t('views.dashboard.overview.alarmTypeBar.alarmSum') }} {{ t('views.dashboard.overview.alarmTypeBar.alarmSum') }}
@@ -558,24 +595,29 @@ onBeforeUnmount(() => {
</div> </div>
<div class="column" style="flex: 4; margin: 1.333rem 0.833rem 0"> <div class="column" style="flex: 4; margin: 1.333rem 0.833rem 0">
<!-- 实时流量 --> <!-- 实时流量 -->
<div class="upfFlow panel"> <div class="upfFlow panel">
<div class="inner"> <div class="inner">
<h3 class="centerStyle"> <h3 class="centerStyle">
<span class="title"> <span class="title">
<div class="toRouter" @click="fnToRouter('GoldTarget_2104')" :title="t('views.dashboard.overview.toRouter')"> <div
class="toRouter"
@click="fnToRouter('GoldTarget_2104')"
:title="t('views.dashboard.overview.toRouter')"
>
<AreaChartOutlined style="color: #68d8fe" />&nbsp;&nbsp; <AreaChartOutlined style="color: #68d8fe" />&nbsp;&nbsp;
{{ {{ t('views.dashboard.overview.upfFlow.title') }}
t('views.dashboard.overview.upfFlow.title') </div>
}} &nbsp;&nbsp;&nbsp;&nbsp;
</div>&nbsp;&nbsp;&nbsp;&nbsp;
<a-dropdown <a-dropdown
:trigger="['click']" :trigger="['click']"
:get-Popup-Container="getPopupContainer" :get-Popup-Container="getPopupContainer"
> >
<div class="toDeep-text"> <div class="toDeep-text">
{{ neOtions.find(item => item.value === upfWhoId)?.label || 'Select UPF' }} {{
neOtions.find((item: any) => item.value === upfWhoId)
?.label || 'Select UPF'
}}
<DownOutlined style="margin-left: -2px; font-size: 12px" /> <DownOutlined style="margin-left: -2px; font-size: 12px" />
</div> </div>
<template #overlay> <template #overlay>
@@ -586,11 +628,7 @@ onBeforeUnmount(() => {
</a-menu> </a-menu>
</template> </template>
</a-dropdown> </a-dropdown>
</span> </span>
</h3> </h3>
<div class="chart"> <div class="chart">
@@ -602,8 +640,11 @@ onBeforeUnmount(() => {
<!-- 网络拓扑 --> <!-- 网络拓扑 -->
<div class="topology panel"> <div class="topology panel">
<div class="inner"> <div class="inner">
<h3 class="toRouter centerStyle" @click="fnToRouter('TopologyArchitecture_2128')" <h3
:title="t('views.dashboard.overview.toRouter')"> class="toRouter centerStyle"
@click="fnToRouter('TopologyArchitecture_2128')"
:title="t('views.dashboard.overview.toRouter')"
>
<span class="title"> <span class="title">
<ApartmentOutlined style="color: #68d8fe" />&nbsp;&nbsp; <ApartmentOutlined style="color: #68d8fe" />&nbsp;&nbsp;
{{ t('views.dashboard.overview.topology.title') }} {{ t('views.dashboard.overview.topology.title') }}
@@ -626,27 +667,44 @@ onBeforeUnmount(() => {
{{ t('views.dashboard.overview.skim.nodeBInfo') }} {{ t('views.dashboard.overview.skim.nodeBInfo') }}
</span> </span>
</h3> </h3>
<div class="data" style="margin-top: 20px;"> <div class="data" style="margin-top: 20px">
<div class="item toRouter" @click="fnToRouter('BaseStation_2096', { neType: 'AMF' })" <div
:title="t('views.dashboard.overview.toRouter')"> class="item toRouter"
@click="fnToRouter('BaseStation_2096', { neType: 'AMF' })"
:title="t('views.dashboard.overview.toRouter')"
>
<div style="align-items: flex-start"> <div style="align-items: flex-start">
<img :src="svgBase" style="width: 18px; margin-right: 8px; height: 2rem" /> <img
:src="svgBase"
style="width: 18px; margin-right: 8px; height: 2rem"
/>
{{ skimState.gNbSumNum }} {{ skimState.gNbSumNum }}
</div> </div>
<span>{{ t('views.dashboard.overview.skim.gnbSumBase') }}</span> <span>{{ t('views.dashboard.overview.skim.gnbSumBase') }}</span>
</div> </div>
<div class="item toRouter" @click="fnToRouter('BaseStation_2096', { neType: 'AMF' })" <div
:title="t('views.dashboard.overview.toRouter')"> class="item toRouter"
@click="fnToRouter('BaseStation_2096', { neType: 'AMF' })"
:title="t('views.dashboard.overview.toRouter')"
>
<div style="align-items: flex-start"> <div style="align-items: flex-start">
<img :src="svgBase" style="width: 18px; margin-right: 8px; height: 2rem" /> <img
:src="svgBase"
style="width: 18px; margin-right: 8px; height: 2rem"
/>
{{ skimState.gnbNum }} {{ skimState.gnbNum }}
</div> </div>
<span>{{ t('views.dashboard.overview.skim.gnbBase') }}</span> <span>{{ t('views.dashboard.overview.skim.gnbBase') }}</span>
</div> </div>
<div class="item toRouter" @click="fnToRouter('BaseStation_2096', { neType: 'AMF' })" <div
:title="t('views.dashboard.overview.toRouter')"> class="item toRouter"
@click="fnToRouter('BaseStation_2096', { neType: 'AMF' })"
:title="t('views.dashboard.overview.toRouter')"
>
<div style="align-items: flex-start"> <div style="align-items: flex-start">
<UserOutlined style="color: #4096ff; margin-right: 8px; font-size: 1.1rem" /> <UserOutlined
style="color: #4096ff; margin-right: 8px; font-size: 1.1rem"
/>
{{ skimState.gnbUeNum }} {{ skimState.gnbUeNum }}
</div> </div>
<span>{{ t('views.dashboard.overview.skim.gnbUeNum') }}</span> <span>{{ t('views.dashboard.overview.skim.gnbUeNum') }}</span>
@@ -657,29 +715,45 @@ onBeforeUnmount(() => {
<div class="skim panel base" v-perms:has="['dashboard:overview:enbBase']"> <div class="skim panel base" v-perms:has="['dashboard:overview:enbBase']">
<div class="inner"> <div class="inner">
<h3> <h3></h3>
</h3> <div class="data" style="margin-top: 40px">
<div class="data" style="margin-top: 40px;"> <div
<div class="item toRouter" @click="fnToRouter('BaseStation_2096', { neType: 'MME' })" class="item toRouter"
:title="t('views.dashboard.overview.toRouter')"> @click="fnToRouter('BaseStation_2096', { neType: 'MME' })"
:title="t('views.dashboard.overview.toRouter')"
>
<div style="align-items: flex-start"> <div style="align-items: flex-start">
<img :src="svgBase" style="width: 18px; margin-right: 8px; height: 2rem" /> <img
:src="svgBase"
style="width: 18px; margin-right: 8px; height: 2rem"
/>
{{ skimState.eNbSumNum }} {{ skimState.eNbSumNum }}
</div> </div>
<span>{{ t('views.dashboard.overview.skim.enbSumBase') }}</span> <span>{{ t('views.dashboard.overview.skim.enbSumBase') }}</span>
</div> </div>
<div class="item toRouter" @click="fnToRouter('BaseStation_2096', { neType: 'MME' })" <div
:title="t('views.dashboard.overview.toRouter')"> class="item toRouter"
@click="fnToRouter('BaseStation_2096', { neType: 'MME' })"
:title="t('views.dashboard.overview.toRouter')"
>
<div style="align-items: flex-start"> <div style="align-items: flex-start">
<img :src="svgBase" style="width: 18px; margin-right: 8px; height: 2rem" /> <img
:src="svgBase"
style="width: 18px; margin-right: 8px; height: 2rem"
/>
{{ skimState.enbNum }} {{ skimState.enbNum }}
</div> </div>
<span>{{ t('views.dashboard.overview.skim.enbBase') }}</span> <span>{{ t('views.dashboard.overview.skim.enbBase') }}</span>
</div> </div>
<div class="item toRouter" @click="fnToRouter('BaseStation_2096', { neType: 'MME' })" <div
:title="t('views.dashboard.overview.toRouter')"> class="item toRouter"
@click="fnToRouter('BaseStation_2096', { neType: 'MME' })"
:title="t('views.dashboard.overview.toRouter')"
>
<div style="align-items: flex-start"> <div style="align-items: flex-start">
<UserOutlined style="color: #4096ff; margin-right: 8px; font-size: 1.1rem" /> <UserOutlined
style="color: #4096ff; margin-right: 8px; font-size: 1.1rem"
/>
{{ skimState.enbUeNum }} {{ skimState.enbUeNum }}
</div> </div>
<span>{{ t('views.dashboard.overview.skim.enbUeNum') }}</span> <span>{{ t('views.dashboard.overview.skim.enbUeNum') }}</span>
@@ -688,17 +762,21 @@ onBeforeUnmount(() => {
</div> </div>
</div> </div>
<!-- 资源情况 --> <!-- 资源情况 -->
<div class="resources panel"> <div class="resources panel">
<div class="inner"> <div class="inner">
<h3 class="resources leftright"> <h3 class="resources leftright">
<span class="title"> <span class="title">
<DashboardOutlined style="color: #68d8fe;font-size: 20px;" />&nbsp;&nbsp; <DashboardOutlined
<div style="margin-left: -3px"> {{ t('views.dashboard.overview.resources.title') }}</div> style="color: #68d8fe; font-size: 20px"
<a-dropdown :trigger="['click']" :get-Popup-Container="getPopupContainer"> />&nbsp;&nbsp;
<div style="margin-left: -3px">
{{ t('views.dashboard.overview.resources.title') }}
</div>
<a-dropdown
:trigger="['click']"
:get-Popup-Container="getPopupContainer"
>
<div class="toDeep-text"> <div class="toDeep-text">
{{ graphNodeClickID }} {{ graphNodeClickID }}
<DownOutlined style="margin-left: -2px; font-size: 12px" /> <DownOutlined style="margin-left: -2px; font-size: 12px" />
@@ -724,8 +802,10 @@ onBeforeUnmount(() => {
<div class="inner"> <div class="inner">
<h3 class="leftright"> <h3 class="leftright">
<span class="title"> <span class="title">
<WhatsAppOutlined style="color: #68d8fe;font-size: 20px;" />&nbsp;&nbsp; {{ <WhatsAppOutlined
t('views.dashboard.overview.userActivity.imsTitle') }} style="color: #68d8fe; font-size: 20px"
/>&nbsp;&nbsp;
{{ t('views.dashboard.overview.userActivity.imsTitle') }}
</span> </span>
</h3> </h3>
<div class="chart"> <div class="chart">
@@ -745,7 +825,7 @@ onBeforeUnmount(() => {
} }
.toDeep :deep(.ant-select-selector) { .toDeep :deep(.ant-select-selector) {
background-color: #050F23; background-color: #050f23;
border: none; border: none;
} }