feat:告警模块优化

This commit is contained in:
zhongzm
2025-08-01 16:44:20 +08:00
parent e190379468
commit 6572fd13b1
3 changed files with 127 additions and 52 deletions

View File

@@ -131,7 +131,7 @@ function initPicture() {
{ {
text: 'Top3', text: 'Top3',
left: 'center', left: 'center',
top: '36%', top: '48%',
textStyle: { textStyle: {
color: '#fff', color: '#fff',
fontSize: 16, fontSize: 16,
@@ -144,19 +144,34 @@ function initPicture() {
top: '5%', top: '5%',
left: '20%', left: '20%',
right: '10%', right: '10%',
height: '35%' height: '38%'
}, },
{ // Top3 { // Top3
top: '50%', top: '58%',
left: '20%', left: '20%',
right: '10%', right: '10%',
height: '30%' height: '32%'
} }
], ],
tooltip: { tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' }, axisPointer: { type: 'shadow' },
formatter: '{b} : {c}', formatter: function(params: any) {
if (Array.isArray(params) && params.length > 0) {
const param = params[0];
// 获取真实值而不是0.1的占位值
let realValue = 0;
if (param.seriesIndex === 0) {
// 第一个系列(告警类型)
realValue = alarmTypeType.value[param.dataIndex]?.value || 0;
} else if (param.seriesIndex === 1) {
// 第二个系列Top3
realValue = alarmTypeTypeTop.value[param.dataIndex]?.value || 0;
}
return `${param.name}: ${realValue}`;
}
return '';
},
}, },
legend: { legend: {
show: false show: false
@@ -178,7 +193,12 @@ function initPicture() {
type: 'category', type: 'category',
gridIndex: 0, gridIndex: 0,
data: alarmTypeType.value.map((item: any) => item.name), data: alarmTypeType.value.map((item: any) => item.name),
axisLabel: { color: '#fff', fontSize: 14,fontWeight: 'bold' }, axisLabel: {
color: '#fff',
fontSize: 12,
fontWeight: 'bold',
interval: 0 // 确保显示所有标签
},
axisLine: { show: false }, axisLine: { show: false },
axisTick: { show: false }, axisTick: { show: false },
inverse: true inverse: true
@@ -187,7 +207,12 @@ function initPicture() {
type: 'category', type: 'category',
gridIndex: 1, gridIndex: 1,
data: alarmTypeTypeTop.value.map((item: any) => item.name), data: alarmTypeTypeTop.value.map((item: any) => item.name),
axisLabel: { color: '#fff', fontSize: 14,fontWeight: 'bold' }, axisLabel: {
color: '#fff',
fontSize: 12,
fontWeight: 'bold',
interval: 0 // 确保显示所有标签
},
axisLine: { show: false }, axisLine: { show: false },
axisTick: { show: false }, axisTick: { show: false },
inverse: true inverse: true
@@ -199,10 +224,15 @@ function initPicture() {
type: 'bar', type: 'bar',
xAxisIndex: 0, xAxisIndex: 0,
yAxisIndex: 0, yAxisIndex: 0,
barWidth: 18, barWidth: 16,
barCategoryGap: '20%', // 添加柱状图间隙
itemStyle: { itemStyle: {
borderRadius: [0, 8, 8, 0], borderRadius: [0, 8, 8, 0],
color: function (params: any) { color: function (params: any) {
// 如果值为0显示透明背景但有边框效果
if (params.value === 0.1) {
return 'rgba(0,0,0,0.1)';
}
// 渐变色 // 渐变色
const colorArr = [ const colorArr = [
new echarts.graphic.LinearGradient(0, 0, 1, 0, [ new echarts.graphic.LinearGradient(0, 0, 1, 0, [
@@ -223,20 +253,23 @@ function initPicture() {
]) ])
]; ];
return colorArr[params.dataIndex] || colorArr[3]; return colorArr[params.dataIndex] || colorArr[3];
} },
borderColor: '#666',
borderWidth: 1
}, },
label: { label: {
show: true, show: true,
position: 'right', position: 'right',
color: '#fff', //淡蓝色 color: '#fff',
fontWeight: 'bold', fontWeight: 'bold',
fontSize: 16, fontSize: 14,
formatter: (params: any) => { formatter: (params: any) => {
if (!params.value) return ''; // 如果是最小值0.1显示为0
return `${params.value}`; const realValue = alarmTypeType.value[params.dataIndex]?.value || 0;
return `${realValue}`;
}, },
}, },
data: alarmTypeType.value.map((item: any) => item.value), data: alarmTypeType.value.map((item: any) => Math.max(item.value || 0, 0.1)),
zlevel: 2 zlevel: 2
}, },
// Top3横向柱状图 // Top3横向柱状图
@@ -245,24 +278,37 @@ function initPicture() {
type: 'bar', type: 'bar',
xAxisIndex: 1, xAxisIndex: 1,
yAxisIndex: 1, yAxisIndex: 1,
barWidth: 18, barWidth: 16,
barCategoryGap: '20%', // 添加柱状图间隙
itemStyle: { itemStyle: {
borderRadius: [0, 20, 20, 0], // 圆角(左上、右上、右下、左下) borderRadius: [0, 20, 20, 0],
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [ color: function (params: any) {
{ offset: 0, color: '#f0f5ff' }, // 如果值为0显示透明背景但有边框效果
{ offset: 0.5, color: '#adc6ff' }, if (params.value === 0 || params.value === 0.1) {
{ offset: 1, color: '#2f54eb' }, return 'rgba(0,0,0,0.1)';
]), // 渐变 }
return new echarts.graphic.LinearGradient(0, 0, 1, 0, [
{ offset: 0, color: '#f0f5ff' },
{ offset: 0.5, color: '#adc6ff' },
{ offset: 1, color: '#2f54eb' },
]);
},
borderColor: '#666',
borderWidth: 1
}, },
label: { label: {
show: true, show: true,
position: 'right', position: 'right',
color: '#fff', //淡蓝色 color: '#fff',
fontWeight: 'bold', fontWeight: 'bold',
fontSize: 16, fontSize: 14,
formatter: '{c}' formatter: (params: any) => {
// 如果是最小值0.1显示为0
const realValue = alarmTypeTypeTop.value[params.dataIndex]?.value || 0;
return `${realValue}`;
}
}, },
data: alarmTypeTypeTop.value.map((item: any) => item.value), data: alarmTypeTypeTop.value.map((item: any) => Math.max(item.value || 0, 0.1)),
zlevel: 1 zlevel: 1
} }
] ]

View File

@@ -18,7 +18,7 @@
-webkit-background-size: cover; -webkit-background-size: cover;
} }
.column { .column {
flex: 3; flex: 2;
position: relative; position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -41,6 +41,7 @@
position: absolute; position: absolute;
pointer-events: none; pointer-events: none;
z-index: 10; z-index: 10;
display: none; /* 隐藏所有角框 */
} }
/* 左上角L形 - 相对于inner的实际边界 */ /* 左上角L形 - 相对于inner的实际边界 */
@@ -75,6 +76,7 @@
border-right: 3px solid #4c9bfd; border-right: 3px solid #4c9bfd;
pointer-events: none; pointer-events: none;
z-index: 10; z-index: 10;
display: none; /* 隐藏所有角框 */
} }
/* 左下角L形 - 相对于inner的实际边界 */ /* 左下角L形 - 相对于inner的实际边界 */
@@ -89,6 +91,7 @@
border-left: 3px solid #4c9bfd; border-left: 3px solid #4c9bfd;
pointer-events: none; pointer-events: none;
z-index: 10; z-index: 10;
display: none; /* 隐藏所有角框 */
} }
/* 为base模块调整角框显示 */ /* 为base模块调整角框显示 */
@@ -111,17 +114,23 @@
right: -1.583rem; right: -1.583rem;
bottom: -0.875rem; bottom: -0.875rem;
left: -5.5rem; left: -5.5rem;
padding: 1rem 1.5rem; padding: 1rem 0.3rem;
} }
.panel h3 { .panel h3 {
font-size: 0.833rem; font-size: 0.833rem;
color: #fff; color: #fff;
background: rgba(76, 155, 253, 0.1); /* 为所有模块标题添加淡蓝色背景 */
padding: 0.5rem 1.2rem;
border-radius: 0.7rem 0.7rem 0 0;
margin: 0;
box-sizing: border-box;
} }
.leftright { .leftright {
width: 100%; width: 100%;
min-height: 2.5rem; min-height: 2.5rem;
/*background: url(../images/title.png) no-repeat center center;*/ /*background: url(../images/title.png) no-repeat center center;*/
background: rgba(76, 155, 253, 0.1); /* 添加淡蓝色背景 */
background-size: 100%; background-size: 100%;
color: #4c9bfd; color: #4c9bfd;
display: flex; display: flex;
@@ -150,6 +159,7 @@
width: 100%; width: 100%;
min-height: 2.5rem; min-height: 2.5rem;
/*background: url(../images/title.png) no-repeat center center;*/ /*background: url(../images/title.png) no-repeat center center;*/
background: rgba(76, 155, 253, 0.1); /* 添加淡蓝色背景 */
background-size: 90%; background-size: 90%;
color: #4c9bfd; color: #4c9bfd;
display: flex; display: flex;
@@ -225,6 +235,11 @@
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;
align-items: baseline; align-items: baseline;
background: rgba(76, 155, 253, 0.1); /* 为网络拓扑模块标题添加淡蓝色背景 */
padding: 0.5rem 1.2rem;
border-radius: 0.7rem 0.7rem 0 0;
margin: 0;
box-sizing: border-box;
} }
.topology .inner h3 .normal { .topology .inner h3 .normal {
color: #52c41a; color: #52c41a;
@@ -238,7 +253,7 @@
.topology .inner .chart { .topology .inner .chart {
width: 100%; width: 100%;
height: 100%; height: 100%;
margin-top: 1rem; margin-top: 0.1rem;
} }
/* 概览区域 */ /* 概览区域 */
@@ -318,6 +333,8 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
margin-top: 1rem; margin-top: 1rem;
padding-bottom: 1rem;
box-sizing: border-box;/*不知道为啥没生效*/
} }
/* 流量统计 */ /* 流量统计 */
@@ -328,6 +345,11 @@
.upfFlowTotal1 .inner h3 { .upfFlowTotal1 .inner h3 {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
background: rgba(76, 155, 253, 0.1); /* 为流量统计模块标题添加淡蓝色背景 */
padding: 0.5rem 1.2rem;
border-radius: 0.7rem 0.7rem 0 0;
margin: 0;
box-sizing: border-box;
} }
.upfFlowTotal1 .inner h3 .filter { .upfFlowTotal1 .inner h3 .filter {
display: flex; display: flex;
@@ -387,6 +409,11 @@
.upfFlowTotal .inner h3 { .upfFlowTotal .inner h3 {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
background: rgba(76, 155, 253, 0.1); /* 为流量统计模块标题添加淡蓝色背景 */
padding: 0.5rem 1.2rem;
border-radius: 0.7rem 0.7rem 0 0;
margin: 0;
box-sizing: border-box;
} }
.upfFlowTotal .inner h3 .filter { .upfFlowTotal .inner h3 .filter {
display: flex; display: flex;
@@ -445,7 +472,7 @@
.resources .inner .chart { .resources .inner .chart {
width: 100%; width: 100%;
height: 100%; height: 100%;
margin-top: 1rem; margin-top: 2rem;
} }
@@ -459,6 +486,15 @@
height: 100%; height: 100%;
} }
/* 为base模块的第二个模块4G部分添加标题样式 */
.skim.panel.base:not(:first-of-type) h3 {
background: transparent; /* 移除背景,避免阴影问题 */
padding: 0;
margin: 0;
min-height: 0;
display: none; /* 完全隐藏空的h3元素 */
}
/* 跳转鼠标悬浮 */ /* 跳转鼠标悬浮 */
.toRouter:hover { .toRouter:hover {
cursor: pointer; cursor: pointer;

View File

@@ -127,22 +127,15 @@ async function fnGetSkim() {
let tempEnbSumNum = 0; let tempEnbSumNum = 0;
const neHandlers = new Map([ const neHandlers = new Map([
// [
// 'UDM',
// {
// request: (neId: string) =>
// listUDMSub({ neId: neId, pageNum: 1, pageSize: 1 }),
// process: (res: any) =>
// res.code === RESULT_CODE_SUCCESS &&
// (skimState.udmSubNum += res.total),
// },
// ],
[ [
'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.data.total), if (res.code === RESULT_CODE_SUCCESS && typeof res.data === 'number') {
skimState.udmSubNum += res.data;
}
},
}, },
], ],
[ [
@@ -340,15 +333,15 @@ 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 && typeof res.data === 'number') {
skimState.udmSubNum = res.data.total; skimState.udmSubNum = res.data;
}else{ }else{
skimState.udmSubNum = 0; skimState.udmSubNum = 0;
} }
// }).catch(() => { // }).catch(() => {
// skimState.udmSubNum = 0; // skimState.udmSubNum = 0;
// }); // });
} catch (error) { } catch (error) {
skimState.udmSubNum = 0; skimState.udmSubNum = 0;
} }
@@ -478,7 +471,7 @@ onBeforeUnmount(() => {
<div class="item toRouter" :title="t('views.dashboard.overview.toRouter')" v-if="neListStore.fnHasNe(['udm'])"> <div class="item toRouter" :title="t('views.dashboard.overview.toRouter')" v-if="neListStore.fnHasNe(['udm'])">
<div @click="fnToRouter('UdmSub_2001')"> <div @click="fnToRouter('UdmSub_2001')">
<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 || 0 }}
</div> </div>
<span> <span>
<a-dropdown :trigger="['click']" :get-Popup-Container="getPopupContainer"> <a-dropdown :trigger="['click']" :get-Popup-Container="getPopupContainer">
@@ -500,7 +493,7 @@ onBeforeUnmount(() => {
style="margin: 0 12px" v-perms:has="['dashboard:overview:imsUeNum']" v-if="neListStore.fnHasNe(['ims'])"> style="margin: 0 12px" v-perms:has="['dashboard:overview:imsUeNum']" v-if="neListStore.fnHasNe(['ims'])">
<div> <div>
<img :src="svgUserIMS" style="width: 18px; margin-right: 8px" /> <img :src="svgUserIMS" style="width: 18px; margin-right: 8px" />
{{ skimState.imsUeNum }} {{ skimState.imsUeNum || 0 }}
</div> </div>
<span> <span>
{{ t('views.dashboard.overview.skim.imsUeNum') }} {{ t('views.dashboard.overview.skim.imsUeNum') }}
@@ -510,7 +503,7 @@ onBeforeUnmount(() => {
v-perms:has="['dashboard:overview:smfUeNum']" v-if="neListStore.fnHasNe(['smf'])"> v-perms:has="['dashboard:overview:smfUeNum']" v-if="neListStore.fnHasNe(['smf'])">
<div> <div>
<img :src="svgUserSMF" style="width: 18px; margin-right: 8px" /> <img :src="svgUserSMF" style="width: 18px; margin-right: 8px" />
{{ skimState.smfUeNum }} {{ skimState.smfUeNum || 0 }}
</div> </div>
<span> <span>
{{ t('views.dashboard.overview.skim.smfUeNum') }} {{ t('views.dashboard.overview.skim.smfUeNum') }}
@@ -692,7 +685,7 @@ onBeforeUnmount(() => {
<h3 class="resources leftright"> <h3 class="resources leftright">
<span class="title"> <span class="title">
<DashboardOutlined style="color: #68d8fe;font-size: 20px;" />&nbsp;&nbsp; <DashboardOutlined style="color: #68d8fe;font-size: 20px;" />&nbsp;&nbsp;
<div style="margin-left: -3px"> {{ t('views.dashboard.overview.resources.title') }}</div> <div style="margin-left: -3px">{{ t('views.dashboard.overview.resources.title') }}</div>
<a-dropdown :trigger="['click']" :get-Popup-Container="getPopupContainer"> <a-dropdown :trigger="['click']" :get-Popup-Container="getPopupContainer">
<div class="toDeep-text"> <div class="toDeep-text">
{{ graphNodeClickID }} {{ graphNodeClickID }}