Merge remote-tracking branch 'origin/main-v2' into main-v2

This commit is contained in:
zhongzm
2025-07-30 18:34:50 +08:00
22 changed files with 276 additions and 527 deletions

View File

@@ -11,7 +11,7 @@ VITE_APP_NAME = "Core Network OMC"
VITE_APP_CODE = "OMC" VITE_APP_CODE = "OMC"
# 应用版本 # 应用版本
VITE_APP_VERSION = "2.2507.1" VITE_APP_VERSION = "2.2507.3"
# 接口基础URL地址-不带/后缀 # 接口基础URL地址-不带/后缀
VITE_API_BASE_URL = "/omc-api" VITE_API_BASE_URL = "/omc-api"

View File

@@ -11,7 +11,7 @@ VITE_APP_NAME = "Core Network OMC"
VITE_APP_CODE = "OMC" VITE_APP_CODE = "OMC"
# 应用版本 # 应用版本
VITE_APP_VERSION = "2.2507.1" VITE_APP_VERSION = "2.2507.3"
# 接口基础URL地址-不带/后缀 # 接口基础URL地址-不带/后缀
VITE_API_BASE_URL = "/omc-api" VITE_API_BASE_URL = "/omc-api"

View File

@@ -1,5 +1,24 @@
# 版本发布日志 # 版本发布日志
## 2.2507.3-20250725
- 优化 将UDM鉴权导出按钮隐藏
- 修复 自定义指标数值格式处理,导出表格修复
- 修复 仪表盘2用户事件显示不正常
- 修复 自定义指标数值格式化保留3位小数
- 优化 参数配置AMF导入Index字段存在更新不存在默认新增
## 2.2507.2-20250718
- 优化 变更nssf/n3iwf接口调用
- 优化 调整告警类型参数值,参数配置列表项不记录勾选状态
- 优化 调整UE数据返回参数
- 修复 基站状态拓扑图显示失败
- 修复 基站状态记录和smscCDR导出改为get行为
- 新增 mt版本移动过来的的告警/仪表/性能大屏页面
- 移除 删除无用文件
- 修复 指标页面数据获取异常接口调整
## 2.2507.1-20250705 ## 2.2507.1-20250705
- 修复 缓存管理列表key查询URL路径错误 - 修复 缓存管理列表key查询URL路径错误

View File

@@ -1,55 +0,0 @@
import { CACHE_SESSION_CRYPTO_API } from '@/constants/cache-keys-constants';
import { sessionGet } from '@/utils/cache-session-utils';
import { request } from '@/plugins/http-fetch';
/**
* 获取下拉框数据
* @returns object
*/
export function getBakFile() {
return request({
url: '/lm/table/list',
method: 'GET',
});
}
/**
* 获取对应类型的文件列表
* @param query 查询参数
* @returns object
*/
export function getBakFileList(query: Record<string, any>) {
return request({
url: '/lm/file/list',
method: 'GET',
params: query,
});
}
/**
* 下载远端文件
* @param query 查询参数
* @returns object
*/
export function downFile(query: Record<string, any>) {
return request({
url: `/lm/file/${query.fileName}`,
method: 'GET',
params: query,
responseType: 'blob',
timeout: 180_000,
});
}
/**
* 删除远端获取文件
* @param query 查询参数
* @returns object
*/
export function delFile(query: Record<string, any>) {
return request({
url: `/lm/file/${query.fileName}`,
method: 'DELETE',
params: query,
});
}

View File

@@ -1,34 +0,0 @@
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { request } from '@/plugins/http-fetch';
import { parseObjLineToHump } from '@/utils/parse-utils';
/**
* 查询列表
* @param query 查询参数
* @returns object
*/
export async function listBase5G(query: Record<string, any>) {
const result = await request({
url: `/api/rest/ueManagement/v1/elementType/${query.neType.toLowerCase()}/objectType/nbInfo`,
method: 'GET',
params: query,
});
let data: DataList = {
total: 0,
rows: [],
code: result.code,
msg: result.msg,
};
// 解析数据
if (result.code === RESULT_CODE_SUCCESS && Array.isArray(result.data.data)) {
const rows = parseObjLineToHump(result.data.data);
data.total = rows.length;
data.rows = rows;
}
// 模拟数据
// data.rows = [{"address":"192.168.1.137:38412","id":"217","name":"attach-enb-100000-20","ueNum":0}]
// data.rows = [{address: "192.168.8.223", id: 257, name: "SmallCell", ueNum: 0}]
return data;
}

View File

@@ -1,66 +0,0 @@
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { request } from '@/plugins/http-fetch';
import { parseObjLineToHump } from '@/utils/parse-utils';
/**
* 查询列表
* @param query 查询参数
* @returns object
*/
export async function listUEInfoByIMS(query: Record<string, any>) {
query.nbId = query.id;
const result = await request({
url: '/api/rest/ueManagement/v1/elementType/ims/objectType/ueInfo',
method: 'GET',
params: query,
});
let data: DataList = {
total: 0,
rows: [],
code: result.code,
msg: result.msg,
};
// 解析数据
if (result.code === RESULT_CODE_SUCCESS && Array.isArray(result.data.data)) {
const rows = parseObjLineToHump(result.data.data);
data.total = rows.length;
data.rows = rows;
}
// 测试数据
// data.rows = [
// {
// activeTime: '2023-11-29 17:04:54',
// barring: 0,
// impu: 'sip:12307551232@ims.mnc000.mcc460.3gppnetwork.org',
// imsi: '460001230000002',
// msisdn: '12307551232',
// regState: 1,
// },
// ];
return data;
}
/**
* 首页查询IMS在线用户数
* @param query 查询参数
* @returns neId
*/
export async function listUENumByIMS(neId: String) {
const result = await request({
url: `/api/rest/ueManagement/v1/elementType/ims/objectType/ueNum?neId=${neId}`,
method: 'GET',
});
if (result.code === RESULT_CODE_SUCCESS) {
let num = result.data['ueNum'] || 0;
if (num === 0) {
num = result.data.data['ueNum'] || 0;
}
return Object.assign(result, { data: num });
}
// 模拟数据
// { "ueNum": 0 }
// result.data = 0
return result;
}

View File

@@ -1,113 +0,0 @@
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { request } from '@/plugins/http-fetch';
/**
* 查询列表
* @param query 查询参数
* @returns object
*/
export async function listUEInfoBySMF(query: Record<string, any>) {
query.nbId = query.id;
const result = await request({
url: '/api/rest/ueManagement/v1/elementType/smf/objectType/ueInfo',
method: 'GET',
params: query,
});
let data: DataList = {
total: 0,
rows: [],
code: result.code,
msg: result.msg,
};
// 解析数据
if (result.code === RESULT_CODE_SUCCESS && result.data) {
if (result.data.total && result.data.data) {
data.total = result.data.total;
data.rows = result.data.data;
} else {
Object.assign(data, {
total: result.data.length,
rows: result.data,
});
}
}
// 模拟数据
// data.code = RESULT_CODE_SUCCESS;
// data.total = 2;
// data.rows = [
// {
// imsi: 'imsi-460000100000090',
// msisdn: 'msisdn-12307550090',
// pduSessionInfo: [
// {
// activeTime: '2024-06-19 14:35:26',
// dnn: 'ims',
// ipv4: '10.10.48.8',
// ipv6: '',
// pduSessionID: 6,
// ranN3IP: '192.168.1.137',
// sstSD: '1-000001',
// tai: '46000-001124',
// upState: 'Active',
// upfN3IP: '192.168.1.161',
// },
// {
// activeTime: '2024-06-19 14:35:26',
// dnn: 'cmnet',
// ipv4: '10.10.48.9',
// ipv6: '2001:4860:4860::/64',
// pduSessionID: 7,
// ranN3IP: '192.168.1.137',
// sstSD: '1-000001',
// tai: '46000-001124',
// upState: 'Active',
// upfN3IP: '192.168.1.161',
// },
// ],
// ratType: 'NR',
// },
// {
// imsi: 'imsi-460602072701180',
// msisdn: 'msisdn-123460600080',
// pduSessionInfo: [
// {
// activeTime: '2024-06-19 14:31:09',
// dnn: 'cmnet',
// ipv4: '10.10.48.4',
// ipv6: '',
// pduSessionID: 5,
// ranN3IP: '192.168.8.223',
// sstSD: '1-000001',
// tai: '46060-0001',
// upState: 'Active',
// upfN3IP: '192.168.1.161',
// },
// ],
// ratType: 'EUTRAN',
// },
// ];
return data;
}
/**
* 首页查询SMF在线用户数
* @param query 查询参数
* @returns neId
*/
export async function listUENumBySMF(neId: String) {
const result = await request({
url: `/api/rest/ueManagement/v1/elementType/smf/objectType/ueNum?neId=${neId}`,
method: 'GET',
});
if (result.code === RESULT_CODE_SUCCESS) {
return Object.assign(result, {
data: result.data.data['ueNum'],
});
}
// 模拟数据
// { "data": { "ueNum": 0 } }
// result.data = 0
return result;
}

View File

@@ -8,7 +8,7 @@ import { request } from '@/plugins/http-fetch';
export async function listCustomData(query: Record<string, any>) { export async function listCustomData(query: Record<string, any>) {
// 发起请求 // 发起请求
const result = await request({ const result = await request({
url: `/pm/kpiC/report`, url: `/neData/kpic/data`,
method: 'GET', method: 'GET',
params: query, params: query,
timeout: 60_000, timeout: 60_000,

View File

@@ -1,30 +1,16 @@
import { request } from '@/plugins/http-fetch'; import { request } from '@/plugins/http-fetch';
/** /**
* 查询自定义指标 * 查询自定义指标
* @param query 查询参数 * @param query 查询参数
* @returns object * @returns object
*/ */
export async function listCustom(query?: Record<string, any>) { export async function listCustom(query?: Record<string, any>) {
// 发起请求 return await request({
const result = await request({ url: `/neData/kpic/title/list`,
url: `/pm/kpiC/title/totalList`,
method: 'GET', method: 'GET',
params: query, params: query,
}); });
return result;
}
/**
* 查询自定义指标详细
* @param id 网元ID
* @returns object
*/
export async function getCustom(id: string | number) {
return request({
url: `/pm/kpiC/title/${id}`,
method: 'GET',
});
} }
/** /**
@@ -34,7 +20,7 @@ export async function getCustom(id: string | number) {
*/ */
export function addCustom(data: Record<string, any>) { export function addCustom(data: Record<string, any>) {
return request({ return request({
url: `/pm/kpiC/title`, url: `/neData/kpic/title`,
method: 'POST', method: 'POST',
data: data, data: data,
}); });
@@ -47,7 +33,7 @@ export function addCustom(data: Record<string, any>) {
*/ */
export function updateCustom(data: Record<string, any>) { export function updateCustom(data: Record<string, any>) {
return request({ return request({
url: `/pm/kpiC/title/${data.id}`, url: `/neData/kpic/title`,
method: 'PUT', method: 'PUT',
data: data, data: data,
}); });
@@ -59,7 +45,7 @@ export function updateCustom(data: Record<string, any>) {
*/ */
export async function delCustom(data: Record<string, any>) { export async function delCustom(data: Record<string, any>) {
return request({ return request({
url: `/pm/kpiC/title/${data.id}`, url: `/neData/kpic/title?id=${data.id}`,
method: 'DELETE', method: 'DELETE',
}); });
} }

View File

@@ -1,93 +0,0 @@
import { defineStore } from 'pinia';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { listAllNeInfo } from '@/api/ne/neInfo';
import { parseDataToOptions } from '@/utils/parse-tree-utils';
import { getNePerformanceList } from '@/api/perfManage/taskManage';
/**网元信息类型 */
type NeInfo = {
/**网元列表 */
neList: Record<string, any>[];
/**级联options树结构 */
neCascaderOptions: Record<string, any>[];
/**选择器单级父类型 */
neSelectOtions: Record<string, any>[];
/**性能测量数据集 */
perMeasurementList: Record<string, any>[];
};
const useNeInfoStore = defineStore('neinfo', {
state: (): NeInfo => ({
neList: [],
neCascaderOptions: [],
neSelectOtions: [],
perMeasurementList: [],
}),
getters: {
/**
* 获取级联options树结构
* @param state 内部属性不用传入
* @returns 级联options
*/
getNeCascaderOptions(state) {
return state.neCascaderOptions;
},
/**
* 选择器单级父类型
* @param state 内部属性不用传入
* @returns 级联options
*/
getNeSelectOtions(state) {
return state.neSelectOtions;
},
},
actions: {
// 刷新网元列表
async fnRefreshNelist() {
this.neList = [];
const res = await this.fnNelist();
return res;
},
// 获取网元列表
async fnNelist() {
// 有数据不请求
if (this.neList.length > 0) {
return { code: 1, data: this.neList, msg: 'success' };
}
const res = await listAllNeInfo({
bandStatus: false,
});
if (res.code === RESULT_CODE_SUCCESS) {
// 原始列表
this.neList = JSON.parse(JSON.stringify(res.data));
// 转级联数据
const options = parseDataToOptions(
res.data,
'neType',
'neName',
'neId'
);
this.neCascaderOptions = options;
// 转选择器单级父类型
this.neSelectOtions = options.map(item => item);
}
return res;
},
// 获取性能测量数据集列表
async fnNeTaskPerformance() {
// 有数据不请求
if (this.perMeasurementList.length > 0) {
return { code: 1, data: this.perMeasurementList, msg: 'success' };
}
const res = await getNePerformanceList();
if (res.code === RESULT_CODE_SUCCESS) {
this.perMeasurementList = res.data;
}
return res;
},
},
});
export default useNeInfoStore;

View File

@@ -66,12 +66,19 @@ onMounted(() => {
<div class="activty"> <div class="activty">
<template v-for="item in eventData" :key="item.eId"> <template v-for="item in eventData" :key="item.eId">
<!-- CDR事件IMS --> <!-- CDR事件IMS -->
<div class="card-cdr" :class="{ active: item.eId === eventId }" v-if="item.eType === 'ims_cdr'"> <div
class="card-cdr"
:class="{ active: item.eId === eventId }"
v-if="item.eType === 'ims_cdr'"
>
<div class="card-cdr-item"> <div class="card-cdr-item">
<div> <div>
{{ t('views.dashboard.overview.userActivity.type') }}:&nbsp; {{ t('views.dashboard.overview.userActivity.type') }}:&nbsp;
<span> <span>
<DictTag :options="dict.cdrCallType" :value="item.data.callType" /> <DictTag
:options="dict.cdrCallType"
:value="item.data.callType"
/>
</span> </span>
</div> </div>
<div></div> <div></div>
@@ -109,8 +116,17 @@ onMounted(() => {
<div> <div>
{{ t('views.dashboard.overview.userActivity.result') }}:&nbsp; {{ t('views.dashboard.overview.userActivity.result') }}:&nbsp;
<span v-if="item.data.callType !== 'sms'"> <span v-if="item.data.callType !== 'sms'">
<DictTag :options="dict.cdrSipCode" :value="item.data.cause" value-default="0" />&nbsp;&nbsp; <DictTag
<DictTag :options="dict.cdrSipCodeCause" :value="item.data.cause" value-default="0" /> :options="dict.cdrSipCode"
:value="item.data.cause"
value-default="0"
/>
&nbsp;-&nbsp;
<DictTag
:options="dict.cdrSipCodeCause"
:value="item.data.cause"
value-default="0"
/>
</span> </span>
<span v-else> <span v-else>
{{ t('views.dashboard.overview.userActivity.resultOK') }} {{ t('views.dashboard.overview.userActivity.resultOK') }}
@@ -145,7 +161,7 @@ onMounted(() => {
flex-direction: row; flex-direction: row;
justify-content: flex-start; justify-content: flex-start;
&>div { & > div {
width: 50%; width: 50%;
white-space: nowrap; white-space: nowrap;
text-align: start; text-align: start;
@@ -159,7 +175,7 @@ onMounted(() => {
flex-direction: row; flex-direction: row;
justify-content: flex-start; justify-content: flex-start;
&>div { & > div {
width: 33%; width: 33%;
} }
} }
@@ -181,7 +197,7 @@ onMounted(() => {
flex-direction: row; flex-direction: row;
justify-content: flex-start; justify-content: flex-start;
&>div { & > div {
flex: 1; flex: 1;
white-space: nowrap; white-space: nowrap;
text-align: start; text-align: start;
@@ -207,7 +223,7 @@ onMounted(() => {
&-item { &-item {
display: block; display: block;
&>div { & > div {
width: 100%; width: 100%;
} }
} }
@@ -217,7 +233,7 @@ onMounted(() => {
&-item { &-item {
display: block; display: block;
&>div { & > div {
width: 100%; width: 100%;
} }
} }

View File

@@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref, nextTick, watch } from 'vue'; import { onMounted, ref, nextTick, watch } from 'vue';
import * as echarts from 'echarts/core'; import * as echarts from 'echarts/core';
import { GridComponent, GridComponentOption, TooltipComponent } from 'echarts/components'; import { GridComponent, TooltipComponent } from 'echarts/components';
import { CanvasRenderer } from 'echarts/renderers'; import { CanvasRenderer } from 'echarts/renderers';
import { graphNodeClickID, graphNodeState } from '../../hooks/useTopology'; import { graphNodeClickID, graphNodeState } from '../../hooks/useTopology';
import useI18n from '@/hooks/useI18n'; import useI18n from '@/hooks/useI18n';
@@ -13,8 +13,6 @@ const { t } = useI18n();
echarts.use([GridComponent, TooltipComponent, CanvasRenderer]); echarts.use([GridComponent, TooltipComponent, CanvasRenderer]);
type EChartsOption = echarts.ComposeOption<GridComponentOption>;
/**图DOM节点实例对象 */ /**图DOM节点实例对象 */
const neResourcesDom = ref<HTMLElement | undefined>(undefined); const neResourcesDom = ref<HTMLElement | undefined>(undefined);
@@ -29,7 +27,7 @@ const resourceData = ref({
neCpu: 1, neCpu: 1,
sysCpu: 1, sysCpu: 1,
sysMem: 1, sysMem: 1,
sysDisk: 1 sysDisk: 1,
}); });
// 获取颜色 // 获取颜色
@@ -47,14 +45,14 @@ function getColorByValue(value: number) {
const optionData: any = { const optionData: any = {
tooltip: { tooltip: {
trigger: 'item', trigger: 'item',
formatter: '{b}: {c}%' formatter: '{b}: {c}%',
}, },
grid: { grid: {
top: '10%', top: '10%',
bottom: '5%', bottom: '5%',
left: '5%', left: '5%',
right: '5%', right: '5%',
containLabel: true containLabel: true,
}, },
series: [ series: [
{ {
@@ -65,27 +63,29 @@ const optionData: any = {
name: t('views.dashboard.overview.resources.neCpu'), name: t('views.dashboard.overview.resources.neCpu'),
color: getColorByValue(resourceData.value.neCpu), color: getColorByValue(resourceData.value.neCpu),
backgroundStyle: { backgroundStyle: {
color: 'rgba(10, 60, 160, 0.1)' color: 'rgba(10, 60, 160, 0.1)',
}, },
label: { label: {
normal: { normal: {
formatter: () => { formatter: () => {
return `${t('views.dashboard.overview.resources.neCpu')}\n${resourceData.value.neCpu}%`; return `${t('views.dashboard.overview.resources.neCpu')}\n${
resourceData.value.neCpu
}%`;
}, },
textStyle: { textStyle: {
fontSize: 12, fontSize: 12,
color: '#fff' color: '#fff',
} },
} },
}, },
outline: { outline: {
show: true, show: true,
borderDistance: 2, borderDistance: 2,
itemStyle: { itemStyle: {
borderColor: '#0a3ca0', borderColor: '#0a3ca0',
borderWidth: 1 borderWidth: 1,
} },
} },
}, },
{ {
type: 'liquidFill', type: 'liquidFill',
@@ -95,27 +95,29 @@ const optionData: any = {
name: t('views.dashboard.overview.resources.sysCpu'), name: t('views.dashboard.overview.resources.sysCpu'),
color: getColorByValue(resourceData.value.sysCpu), color: getColorByValue(resourceData.value.sysCpu),
backgroundStyle: { backgroundStyle: {
color: 'rgba(10, 60, 160, 0.1)' color: 'rgba(10, 60, 160, 0.1)',
}, },
label: { label: {
normal: { normal: {
formatter: () => { formatter: () => {
return `${t('views.dashboard.overview.resources.sysCpu')}\n${resourceData.value.sysCpu}%`; return `${t('views.dashboard.overview.resources.sysCpu')}\n${
resourceData.value.sysCpu
}%`;
}, },
textStyle: { textStyle: {
fontSize: 12, fontSize: 12,
color: '#fff' color: '#fff',
} },
} },
}, },
outline: { outline: {
show: true, show: true,
borderDistance: 2, borderDistance: 2,
itemStyle: { itemStyle: {
borderColor: '#0a3ca0', borderColor: '#0a3ca0',
borderWidth: 1 borderWidth: 1,
} },
} },
}, },
{ {
type: 'liquidFill', type: 'liquidFill',
@@ -125,27 +127,29 @@ const optionData: any = {
name: t('views.dashboard.overview.resources.sysMem'), name: t('views.dashboard.overview.resources.sysMem'),
color: getColorByValue(resourceData.value.sysMem), color: getColorByValue(resourceData.value.sysMem),
backgroundStyle: { backgroundStyle: {
color: 'rgba(10, 60, 160, 0.1)' color: 'rgba(10, 60, 160, 0.1)',
}, },
label: { label: {
normal: { normal: {
formatter: () => { formatter: () => {
return `${t('views.dashboard.overview.resources.sysMem')}\n${resourceData.value.sysMem}%`; return `${t('views.dashboard.overview.resources.sysMem')}\n${
resourceData.value.sysMem
}%`;
}, },
textStyle: { textStyle: {
fontSize: 12, fontSize: 12,
color: '#fff' color: '#fff',
} },
} },
}, },
outline: { outline: {
show: true, show: true,
borderDistance: 2, borderDistance: 2,
itemStyle: { itemStyle: {
borderColor: '#0a3ca0', borderColor: '#0a3ca0',
borderWidth: 1 borderWidth: 1,
} },
} },
}, },
{ {
type: 'liquidFill', type: 'liquidFill',
@@ -155,36 +159,35 @@ const optionData: any = {
name: t('views.dashboard.overview.resources.sysDisk'), name: t('views.dashboard.overview.resources.sysDisk'),
color: getColorByValue(resourceData.value.sysDisk), color: getColorByValue(resourceData.value.sysDisk),
backgroundStyle: { backgroundStyle: {
color: 'rgba(10, 60, 160, 0.1)' color: 'rgba(10, 60, 160, 0.1)',
}, },
label: { label: {
normal: { normal: {
formatter: () => { formatter: () => {
return `${t('views.dashboard.overview.resources.sysDisk')}\n${resourceData.value.sysDisk}%`; return `${t('views.dashboard.overview.resources.sysDisk')}\n${
resourceData.value.sysDisk
}%`;
}, },
textStyle: { textStyle: {
fontSize: 12, fontSize: 12,
color: '#fff' color: '#fff',
} },
} },
}, },
outline: { outline: {
show: true, show: true,
borderDistance: 2, borderDistance: 2,
itemStyle: { itemStyle: {
borderColor: '#0a3ca0', borderColor: '#0a3ca0',
borderWidth: 1 borderWidth: 1,
} },
} },
} },
] ],
}; };
/**图数据渲染 */ /**图数据渲染 */
function handleRanderChart( function handleRanderChart(container: HTMLElement | undefined, option: any) {
container: HTMLElement | undefined,
option: any
) {
if (!container) return; if (!container) return;
neResourcesChart.value = markRaw(echarts.init(container)); neResourcesChart.value = markRaw(echarts.init(container));
option && neResourcesChart.value.setOption(option); option && neResourcesChart.value.setOption(option);
@@ -235,7 +238,10 @@ function fnChangeData(data: any[], itemID: string) {
} }
let sysDiskUsage = 0; let sysDiskUsage = 0;
if (info.neStateMap[neID].disk && Array.isArray(info.neStateMap[neID].disk.partitionInfo)) { if (
info.neStateMap[neID].disk &&
Array.isArray(info.neStateMap[neID].disk.partitionInfo)
) {
let disks: any[] = info.neStateMap[neID].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) {
@@ -248,7 +254,7 @@ function fnChangeData(data: any[], itemID: string) {
neCpu: nfCpuUsage, neCpu: nfCpuUsage,
sysCpu: sysCpuUsage, sysCpu: sysCpuUsage,
sysMem: sysMemUsage, sysMem: sysMemUsage,
sysDisk: sysDiskUsage sysDisk: sysDiskUsage,
}; };
// 更新图表数据 // 更新图表数据
@@ -260,10 +266,12 @@ function fnChangeData(data: any[], itemID: string) {
label: { label: {
normal: { normal: {
formatter: () => { formatter: () => {
return `${t('views.dashboard.overview.resources.neCpu')}\n${resourceData.value.neCpu}%`; return `${t('views.dashboard.overview.resources.neCpu')}\n${
} resourceData.value.neCpu
} }%`;
} },
},
},
}, },
{ {
data: [resourceData.value.sysCpu / 100], data: [resourceData.value.sysCpu / 100],
@@ -271,10 +279,12 @@ function fnChangeData(data: any[], itemID: string) {
label: { label: {
normal: { normal: {
formatter: () => { formatter: () => {
return `${t('views.dashboard.overview.resources.sysCpu')}\n${resourceData.value.sysCpu}%`; return `${t('views.dashboard.overview.resources.sysCpu')}\n${
} resourceData.value.sysCpu
} }%`;
} },
},
},
}, },
{ {
data: [resourceData.value.sysMem / 100], data: [resourceData.value.sysMem / 100],
@@ -282,10 +292,12 @@ function fnChangeData(data: any[], itemID: string) {
label: { label: {
normal: { normal: {
formatter: () => { formatter: () => {
return `${t('views.dashboard.overview.resources.sysMem')}\n${resourceData.value.sysMem}%`; return `${t('views.dashboard.overview.resources.sysMem')}\n${
} resourceData.value.sysMem
} }%`;
} },
},
},
}, },
{ {
data: [resourceData.value.sysDisk / 100], data: [resourceData.value.sysDisk / 100],
@@ -293,12 +305,14 @@ function fnChangeData(data: any[], itemID: string) {
label: { label: {
normal: { normal: {
formatter: () => { formatter: () => {
return `${t('views.dashboard.overview.resources.sysDisk')}\n${resourceData.value.sysDisk}%`; return `${t('views.dashboard.overview.resources.sysDisk')}\n${
} resourceData.value.sysDisk
} }%`;
} },
} },
] },
},
],
}); });
} }

View File

@@ -208,10 +208,9 @@ function fnGetInitData() {
listKPIData({ listKPIData({
neType: 'UPF', neType: 'UPF',
neId: upfWhoId.value, neId: '001',
startTime: nowDate - 5 * 60 * 1000, beginTime: nowDate - 5 * 60 * 1000,
endTime: nowDate, endTime: nowDate,
interval: 5, // 5秒 interval: 5, // 5秒
sortField: 'timeGroup', sortField: 'timeGroup',
sortOrder: 'asc', sortOrder: 'asc',

View File

@@ -84,38 +84,35 @@ onMounted(() => {
<div></div> <div></div>
</div> </div>
<div class="card-ue-w33" v-if="item.type === 'auth-result'"> <div class="card-ue-w33" v-if="item.type === 'Auth'">
<div> <div>
GNB ID: <span>{{ item.data.gNBID }}</span> GNB ID: <span>{{ item.data.nbId }}</span>
</div> </div>
<div> <div>
Cell ID: <span>{{ item.data.cellID }}</span> Cell ID: <span>{{ item.data.cellId }}</span>
</div> </div>
<div> <div>
TAC ID: <span>{{ item.data.tacID }}</span> TAC ID: <span>{{ item.data.tac }}</span>
</div> </div>
</div> </div>
<div> <div>
{{ t('views.dashboard.overview.userActivity.time') }}: {{ t('views.dashboard.overview.userActivity.time') }}:
<template v-if="item.data?.time"> <template v-if="item.data?.recordTime">
{{ parseDateToStr(item.data.time) }} {{ parseDateToStr(item.data.recordTime) }}
</template>
<template v-else-if="item.data?.timestamp">
{{ parseDateToStr(+item.data.timestamp * 1000) }}
</template> </template>
<template v-else> - </template> <template v-else> - </template>
</div> </div>
<div v-if="item.type === 'auth-result'"> <div v-if="item.type === 'Auth'">
{{ t('views.dashboard.overview.userActivity.result') }}:&nbsp; {{ t('views.dashboard.overview.userActivity.result') }}:&nbsp;
<span> <span>
<DictTag :options="dict.ueAauthCode" :value="item.data.result" /> <DictTag :options="dict.ueAauthCode" :value="item.data.result" />
</span> </span>
</div> </div>
<div v-if="item.type === 'detach'"> <div v-if="item.type === 'Detach'">
{{ t('views.dashboard.overview.userActivity.result') }}: {{ t('views.dashboard.overview.userActivity.result') }}:
<span>{{ t('views.dashboard.overview.userActivity.resultOK') }}</span> <span>{{ t('views.dashboard.overview.userActivity.resultOK') }}</span>
</div> </div>
<div class="card-ue-w33" v-if="item.type === 'cm-state'"> <div class="card-ue-w33" v-if="item.type === 'CM'">
{{ t('views.dashboard.overview.userActivity.result') }}:&nbsp; {{ t('views.dashboard.overview.userActivity.result') }}:&nbsp;
<span> <span>
<DictTag :options="dict.ueEventCmState" :value="item.data.result" /> <DictTag :options="dict.ueEventCmState" :value="item.data.result" />
@@ -131,7 +128,7 @@ onMounted(() => {
<div class="card-ue-item"> <div class="card-ue-item">
<div> <div>
{{ t('views.dashboard.overview.userActivity.type') }}:&nbsp; {{ t('views.dashboard.overview.userActivity.type') }}:&nbsp;
<span v-if="item.type === 'cm-state'"> <span v-if="item.type === 'CM'">
{{ {{
dict.ueEventType dict.ueEventType
.find(s => s.value === item.type) .find(s => s.value === item.type)
@@ -148,42 +145,35 @@ onMounted(() => {
<div></div> <div></div>
</div> </div>
<div class="card-ue-w33" v-if="item.type === 'auth-result'"> <div class="card-ue-w33" v-if="item.type === 'Auth'">
<div> <div>
ENB ID: <span>{{ item.data.eNBID }}</span> ENB ID: <span>{{ item.data.nbId }}</span>
</div> </div>
<div> <div>
Cell ID: <span>{{ item.data.cellID }}</span> Cell ID: <span>{{ item.data.cellId }}</span>
</div> </div>
<div> <div>
TAC ID: <span>{{ item.data.tacID }}</span> TAC ID: <span>{{ item.data.tac }}</span>
</div> </div>
</div> </div>
<div> <div>
{{ t('views.dashboard.overview.userActivity.time') }}: {{ t('views.dashboard.overview.userActivity.time') }}:
<template v-if="item.data?.time"> <template v-if="item.data?.recordTime">
{{ parseDateToStr(item.data.time) }} {{ parseDateToStr(item.data.recordTime) }}
</template>
<template v-else-if="item.data?.timestamp">
{{
typeof item.data?.timestamp === 'number'
? parseDateToStr(+item.data?.timestamp * 1000)
: parseDateToStr(item.data?.timestamp)
}}
</template> </template>
<template v-else> - </template> <template v-else> - </template>
</div> </div>
<div v-if="item.type === 'auth-result'"> <div v-if="item.type === 'Auth'">
{{ t('views.dashboard.overview.userActivity.result') }}:&nbsp; {{ t('views.dashboard.overview.userActivity.result') }}:&nbsp;
<span> <span>
<DictTag :options="dict.ueAauthCode" :value="item.data.result" /> <DictTag :options="dict.ueAauthCode" :value="item.data.result" />
</span> </span>
</div> </div>
<div v-if="item.type === 'detach'"> <div v-if="item.type === 'Detach'">
{{ t('views.dashboard.overview.userActivity.result') }}: {{ t('views.dashboard.overview.userActivity.result') }}:
<span>{{ t('views.dashboard.overview.userActivity.resultOK') }}</span> <span>{{ t('views.dashboard.overview.userActivity.resultOK') }}</span>
</div> </div>
<div class="card-ue-w33" v-if="item.type === 'cm-state'"> <div class="card-ue-w33" v-if="item.type === 'CM'">
{{ t('views.dashboard.overview.userActivity.result') }}:&nbsp; {{ t('views.dashboard.overview.userActivity.result') }}:&nbsp;
<span> <span>
<DictTag :options="dict.ueEventCmState" :value="item.data.result" /> <DictTag :options="dict.ueEventCmState" :value="item.data.result" />

View File

@@ -2,7 +2,7 @@ import { addNeConfigData, editNeConfigData } from '@/api/ne/neConfig';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants'; import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { readSheet } from '@/utils/execl-utils'; import { readSheet } from '@/utils/execl-utils';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import { reactive, toRaw } from 'vue'; import { reactive } from 'vue';
import saveAs from 'file-saver'; import saveAs from 'file-saver';
/** /**
@@ -22,23 +22,25 @@ export default function useArrayImport({
imeiWhitelist: { imeiWhitelist: {
filename: 'import_amf_imeiWhitelist_template', filename: 'import_amf_imeiWhitelist_template',
fileetx: '.xlsx', fileetx: '.xlsx',
itemKey: 'imeiPrefixValue', itemKey: 'index',
item: (row: Record<string, any>) => { item: (row: Record<string, any>) => {
const index = row['Index'] || 0;
return { return {
imeiPrefixValue: row['IMEI Prefix'], imeiPrefixValue: `${row['IMEI Prefix']}`,
index: 0, index: parseInt(index),
}; };
}, },
}, },
whitelist: { whitelist: {
filename: 'import_amf_whitelist_template', filename: 'import_amf_whitelist_template',
fileetx: '.xlsx', fileetx: '.xlsx',
itemKey: 'imsiValue', itemKey: 'index',
item: (row: Record<string, any>) => { item: (row: Record<string, any>) => {
const index = row['Index'] || 0;
return { return {
imsiValue: row['IMSI Value'], imsiValue: `${row['IMSI Value']}`,
imeiValue: row['IMEI Value/Prefix'], imeiValue: `${row['IMEI Value/Prefix']}`,
index: 0, index: parseInt(index),
}; };
}, },
}, },
@@ -47,11 +49,12 @@ export default function useArrayImport({
white_list: { white_list: {
filename: 'import_mme_imeiWhitelist_template', filename: 'import_mme_imeiWhitelist_template',
fileetx: '.xlsx', fileetx: '.xlsx',
itemKey: 'imei', itemKey: 'index',
item: (row: Record<string, any>) => { item: (row: Record<string, any>) => {
const index = row['Index'] || 0;
return { return {
imei: row['IMEI'], imei: `${row['IMEI']}`,
index: 0, index: parseInt(index),
}; };
}, },
}, },
@@ -125,7 +128,7 @@ export default function useArrayImport({
importState.loading = true; importState.loading = true;
for (const row of rows) { for (const row of rows) {
const rowItem = importState.item(row); const rowItem = importState.item(row);
const rowKey = rowItem[importState.itemKey]; const rowKey = rowItem[importState.itemKey] || -1;
let result: any = null; let result: any = null;
// 检查index是否定义 // 检查index是否定义
const has = arrayState.columnsData.find( const has = arrayState.columnsData.find(

View File

@@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref, onMounted, toRaw, watch } from 'vue'; import { reactive, ref, onMounted, toRaw, watch } from 'vue';
import { useRoute } from 'vue-router';
import { PageContainer } from 'antdv-pro-layout'; import { PageContainer } from 'antdv-pro-layout';
import { ProModal } from 'antdv-pro-modal'; import { ProModal } from 'antdv-pro-modal';
import { message } from 'ant-design-vue/es'; import { message } from 'ant-design-vue/es';
@@ -17,6 +18,7 @@ import useArrayBatchDel from './hooks/useArrayBatchDel';
import { getAllNeConfig, getNeConfigData } from '@/api/ne/neConfig'; import { getAllNeConfig, getNeConfigData } from '@/api/ne/neConfig';
const neListStore = useNeListStore(); const neListStore = useNeListStore();
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute();
const { ruleVerification, smfByUPFIdLoadData, smfByUPFIdOptions } = useOptions({ const { ruleVerification, smfByUPFIdLoadData, smfByUPFIdOptions } = useOptions({
t, t,
}); });
@@ -404,10 +406,20 @@ onMounted(() => {
return; return;
} }
// 默认选择AMF // 默认选择AMF
const item = neCascaderOptions.value.find(s => s.value === 'AMF'); const queryNeType = (route.query.neType as string) || 'AMF';
const queryNeId = (route.query.neId as string) || '001';
const item = neCascaderOptions.value.find(s => s.value === queryNeType);
if (item && item.children) { if (item && item.children) {
const info = item.children[0]; const info = item.children.find((s: any) => s.neId === queryNeId);
neTypeSelect.value = [info.neType, info.neId]; if (info) {
neTypeSelect.value = [info.neType, info.neId];
} else {
// 默认取第一个网元ID
const info = item.children[0];
if (info) {
neTypeSelect.value = [info.neType, info.neId];
}
}
} else { } else {
const info = neCascaderOptions.value[0].children[0]; const info = neCascaderOptions.value[0].children[0];
neTypeSelect.value = [info.neType, info.neId]; neTypeSelect.value = [info.neType, info.neId];

View File

@@ -865,6 +865,7 @@ onMounted(() => {
ok-text="TXT" ok-text="TXT"
ok-type="default" ok-type="default"
@confirm="fnExportList('txt')" @confirm="fnExportList('txt')"
v-if="false"
> >
<a-button type="dashed"> <a-button type="dashed">
<template #icon><ExportOutlined /></template> <template #icon><ExportOutlined /></template>
@@ -890,6 +891,7 @@ onMounted(() => {
ok-type="default" ok-type="default"
@confirm="fnRecordExport('txt')" @confirm="fnRecordExport('txt')"
:disabled="tableState.selectedRowKeys.length <= 0" :disabled="tableState.selectedRowKeys.length <= 0"
v-if="false"
> >
<a-button <a-button
type="default" type="default"

View File

@@ -92,8 +92,8 @@ let tableColumns: ColumnsType = [
}, },
{ {
title: t('views.perfManage.customTarget.expression'), title: t('views.perfManage.customTarget.expression'),
dataIndex: 'exprAlias', dataIndex: 'expression',
align: 'center', align: 'left',
}, },
{ {
title: t('views.perfManage.customTarget.description'), title: t('views.perfManage.customTarget.description'),
@@ -354,7 +354,6 @@ function fnModalVisibleByEdit(row?: any, id?: any) {
} else { } else {
fnSelectPerformanceInit(row.neType); fnSelectPerformanceInit(row.neType);
modalState.from = Object.assign(modalState.from, row); modalState.from = Object.assign(modalState.from, row);
modalState.from.expression = modalState.from.exprAlias;
modalState.title = t('views.perfManage.customTarget.editCustom'); modalState.title = t('views.perfManage.customTarget.editCustom');
modalState.openByEdit = true; modalState.openByEdit = true;
} }

View File

@@ -166,13 +166,14 @@ let queryParams: any = reactive({
/**网元标识 */ /**网元标识 */
neId: '', neId: '',
/**开始时间 */ /**开始时间 */
startTime: '', beginTime: '',
/**结束时间 */ /**结束时间 */
endTime: '', endTime: '',
/**排序字段 */ /**排序字段 */
sortField: 'created_at', sortField: 'timeGroup',
/**排序方式 */ /**排序方式 */
sortOrder: 'desc', sortOrder: 'desc',
interval: 60,
}); });
/**表格分页、排序、筛选变化时触发操作, 排序方式,取值为 ascend descend */ /**表格分页、排序、筛选变化时触发操作, 排序方式,取值为 ascend descend */
@@ -306,7 +307,21 @@ function fnRecordExport() {
for (const key of keys) { for (const key of keys) {
if (tableColumnsKeyArr[i] === key) { if (tableColumnsKeyArr[i] === key) {
const title = tableColumnsTitleArr[i]; const title = tableColumnsTitleArr[i];
kpiData[title] = item[key]; if (key == 'timeGroup') {
kpiData[title] = parseDateToStr(item[key]);
} else if (key === 'neName' || key === 'startIndex') {
kpiData[title] = item[key];
} else {
const v = parseFloat(item[key]);
let kpiV = v.toFixed(3); // 有小数部分,保留 3 位小数
// 判断数字是否有小数部分
if (Math.abs(v) < 0.001) {
kpiV = '0'; // 如果数字非常小,返回 0
} else if (v % 1 === 0) {
kpiV = v.toFixed(0); // 没有小数部分,保留 0 位小数
}
kpiData[title] = kpiV;
}
} }
} }
} }
@@ -335,7 +350,7 @@ function fnGetListTitle() {
if (!state.neType[0]) return false; if (!state.neType[0]) return false;
// 获取表头文字 // 获取表头文字
listCustom({ neType: state.neType[0], status: '1' }) listCustom({ neType: state.neType[0], status: '1', pageNum: 1, pageSize: 50 })
.then(res => { .then(res => {
if (res.code === RESULT_CODE_SUCCESS) { if (res.code === RESULT_CODE_SUCCESS) {
if (res.data.rows.length === 0) { if (res.data.rows.length === 0) {
@@ -367,6 +382,16 @@ function fnGetListTitle() {
width: 100, width: 100,
minWidth: 150, minWidth: 150,
maxWidth: 300, maxWidth: 300,
customRender: (opt: any) => {
const num = parseFloat(opt.text);
// 判断数字是否有小数部分
if (Math.abs(num) < 0.001) {
return '0'; // 如果数字非常小,返回 0
} else if (num % 1 === 0) {
return num.toFixed(0); // 没有小数部分,保留 0 位小数
}
return num.toFixed(3); // 有小数部分,保留 3 位小数
},
}); });
} }
columns.push({ columns.push({
@@ -384,6 +409,9 @@ function fnGetListTitle() {
key: 'timeGroup', key: 'timeGroup',
sorter: true, sorter: true,
width: 100, width: 100,
customRender: (opt: any) => {
return parseDateToStr(opt.text);
},
}); });
nextTick(() => { nextTick(() => {
@@ -409,7 +437,7 @@ function fnGetList() {
tableState.loading = true; tableState.loading = true;
queryParams.neType = state.neType[0]; queryParams.neType = state.neType[0];
queryParams.neId = state.neType[1]; queryParams.neId = state.neType[1];
queryParams.startTime = queryRangePicker.value[0]; queryParams.beginTime = queryRangePicker.value[0];
queryParams.endTime = queryRangePicker.value[1]; queryParams.endTime = queryRangePicker.value[1];
listCustomData(toRaw(queryParams)) listCustomData(toRaw(queryParams))
.then(res => { .then(res => {
@@ -452,20 +480,53 @@ function fnGetList() {
}); });
// 计算总值 // 计算总值
const total = Number( const totalV = values.reduce((sum, val) => sum + val, 0);
values.reduce((sum, val) => sum + val, 0).toFixed(2) let total = totalV.toFixed(3);
); // 判断数字是否有小数部分
if (Math.abs(totalV) < 0.001) {
total = '0'; // 如果数字非常小,返回 0
} else if (totalV % 1 === 0) {
total = totalV.toFixed(0); // 没有小数部分,保留 0 位小数
}
// 计算平均值 // 计算平均值
const avg = const avgV = values.length > 0 ? totalV / values.length : 0;
values.length > 0 ? Number((total / values.length).toFixed(2)) : 0; let avg = avgV.toFixed(3);
// 判断数字是否有小数部分
if (Math.abs(avgV) < 0.001) {
avg = '0'; // 如果数字非常小,返回 0
} else if (avgV % 1 === 0) {
avg = avgV.toFixed(0); // 没有小数部分,保留 0 位小数
}
// 计算最大值
const maxV = values.length > 0 ? Math.max(...values) : 0;
let max = maxV.toFixed(3);
// 判断数字是否有小数部分
if (Math.abs(maxV) < 0.001) {
max = '0'; // 如果数字非常小,返回 0
} else if (maxV % 1 === 0) {
max = maxV.toFixed(0); // 没有小数部分,保留 0 位小数
}
// 计算最小值
const minV = values.length > 0 ? Math.min(...values) : 0;
let min = minV.toFixed(3);
// 判断数字是否有小数部分
if (Math.abs(minV) < 0.001) {
min = '0'; // 如果数字非常小,返回 0
} else if (minV % 1 === 0) {
min = minV.toFixed(0); // 没有小数部分,保留 0 位小数
}
kpiStats.value.push({ kpiStats.value.push({
kpiId: columns.key, kpiId: columns.key,
title: columns.title, title: columns.title,
unit: columns.unit, unit: columns.unit,
max: values.length > 0 ? Math.max(...values) : 0, max,
min: values.length > 0 ? Math.min(...values) : 0, min,
avg, avg,
total: total, total,
}); });
} }
} else { } else {
@@ -638,8 +699,17 @@ function fnRanderChartData() {
for (const y of chartDataYSeriesData) { for (const y of chartDataYSeriesData) {
for (const key of keys) { for (const key of keys) {
if (y.key === key) { if (y.key === key) {
y.data.push(+item[key]); // 计算最小值
chartDataXAxisData.push(item['timeGroup']); const v = parseFloat(item[key]);
let kpiV = v.toFixed(3);
// 判断数字是否有小数部分
if (Math.abs(v) < 0.001) {
kpiV = '0'; // 如果数字非常小,返回 0
} else if (v % 1 === 0) {
kpiV = v.toFixed(0); // 没有小数部分,保留 0 位小数
}
y.data.push(kpiV);
chartDataXAxisData.push(parseDateToStr(item['timeGroup']));
} }
} }
} }
@@ -749,7 +819,7 @@ function wsMessage(res: Record<string, any>) {
// x轴 // x轴
if (key === 'timeGroup') { if (key === 'timeGroup') {
// chartDataXAxisData.shift(); // chartDataXAxisData.shift();
chartDataXAxisData.push(v); chartDataXAxisData.push(parseDateToStr(v));
continue; continue;
} }
// y轴 // y轴
@@ -879,7 +949,7 @@ watch(
onMounted(() => { onMounted(() => {
// 目前支持的 AMF AUSF MME MOCNGW NSSF SMF UDM UPF PCF // 目前支持的 AMF AUSF MME MOCNGW NSSF SMF UDM UPF PCF
// 获取网元网元列表 // 获取网元网元列表
listCustom({ status: '1' }).then((res: any) => { listCustom({ status: '1', pageNum: 1, pageSize: 200 }).then((res: any) => {
if (res.code === RESULT_CODE_SUCCESS) { if (res.code === RESULT_CODE_SUCCESS) {
if (!res.data.rows.length) { if (!res.data.rows.length) {
message.warning({ message.warning({
@@ -925,9 +995,9 @@ onMounted(() => {
const now = new Date(); const now = new Date();
now.setMinutes(0, 0, 0); now.setMinutes(0, 0, 0);
// 设置起始时间为整点前一小时 // 设置起始时间为整点前一小时
const startTime = new Date(now); const beginTime = new Date(now);
startTime.setHours(now.getHours() - 1); beginTime.setHours(now.getHours() - 1);
queryRangePicker.value[0] = `${startTime.getTime()}`; queryRangePicker.value[0] = `${beginTime.getTime()}`;
// 设置结束时间为整点 // 设置结束时间为整点
const endTime = new Date(now); const endTime = new Date(now);
endTime.setMinutes(59, 59, 59); endTime.setMinutes(59, 59, 59);