41 Commits

Author SHA1 Message Date
lai
5124c0c04a Merge branch 'main' of http://192.168.2.166:3180/OMC/ems_frontend_vue3 2023-12-14 11:33:49 +08:00
TsMask
d56c293ef5 fix: MML必填初始值的设置 2023-12-14 11:11:02 +08:00
TsMask
e90bc539e9 fix: udm签约用户新增必填msisdn 2023-12-14 11:01:57 +08:00
TsMask
7edcf1703e fix: 静态文件地址追加随机戳避免缓存 2023-12-14 11:01:19 +08:00
lai
8ee0a4d191 Merge branch 'main' of http://192.168.2.166:3180/OMC/ems_frontend_vue3 2023-12-14 10:05:12 +08:00
TsMask
bc1f897660 feat: 新增网元日志文件页面功能 2023-12-13 21:21:42 +08:00
lai
ba47d3a303 --调整删除请求网元超时时间 2023-12-13 19:47:41 +08:00
TsMask
38e5e4a9e0 fix: 参数配置index为0新增不累加问题 2023-12-13 12:49:24 +08:00
lai
15d7d118c4 调整英文翻译,添加活动告警的可伸缩列 2023-12-13 10:40:41 +08:00
lai
69d4348df7 媒体查询调整 2023-12-13 10:40:06 +08:00
TsMask
fe81a2d924 fix: 移动端适配样式调整 2023-12-12 19:30:44 +08:00
TsMask
cd53fab1f9 fix: 文件转存接口移动 2023-12-12 19:29:49 +08:00
lai
e6d62da386 网元列表进行特制化排序-初版 2023-12-12 16:44:56 +08:00
lai
752f8ccc70 批量新增时EPSODB转换十六进制问题 2023-12-12 15:34:53 +08:00
lai
3a0c85169e 修复设置显示过滤的sql 2023-12-12 15:22:27 +08:00
lai
f845f3f4de --修正后的小屏按钮挤兑问题 2023-12-12 14:55:07 +08:00
TsMask
63e3f352b2 style: 表格头按钮响应式 2023-12-12 12:14:20 +08:00
lai
d9ec9fd1e1 修复当小屏时按钮显示不出问题 2023-12-12 11:27:27 +08:00
lai
f198d2b9a2 新增媒体查询 2023-12-12 11:25:33 +08:00
TsMask
1c3e6db4bc fix: 参数配置修复根据规则取值导致的类型问题 2023-12-12 11:09:09 +08:00
TsMask
8199e16a17 fix: 主页的状态图表颜色默认值 2023-12-11 20:15:26 +08:00
TsMask
0d736966dd feat: 国际化切换判断权限去隐藏控件 2023-12-11 20:14:40 +08:00
TsMask
fe5905ee35 chore: 控制台版本号 2023-12-11 19:22:25 +08:00
TsMask
9c27c32e26 fix: 参数配置根据规则布尔类型转换 2023-12-11 19:21:32 +08:00
TsMask
4208ccc358 style: 拓扑基础节点 2023-12-08 21:16:37 +08:00
lai
51a190771d 调整后的黄金指标,首页状态颜色自定义 2023-12-08 19:19:06 +08:00
TsMask
3376d90b96 fix: 缓存网元类型获取数据判断 2023-12-08 18:52:33 +08:00
TsMask
4105f4ef33 fix: 缓存网元类型获取级联数据判断 2023-12-08 18:38:46 +08:00
TsMask
e6a4591fb6 fix: 缓存网元类型获取级联数据判断 2023-12-08 18:20:21 +08:00
TsMask
fafe604323 fix: 类型异常导致编译失败 2023-12-08 17:26:40 +08:00
TsMask
f110d0e697 fix: 配置文件key为字符串 2023-12-08 17:17:00 +08:00
TsMask
6210b87c84 style: 补充节点,鼠标悬浮动画 2023-12-08 16:30:20 +08:00
TsMask
5a761ece4e chore: 更新依赖包 2023-12-07 20:16:04 +08:00
TsMask
3fa2cffc82 fix: 拓扑图基础 2023-12-07 20:15:18 +08:00
TsMask
e92004a69a style: 文件上传网元端失败固定提示 2023-12-07 18:27:40 +08:00
lai
a612d05429 修正 2023-12-07 17:36:10 +08:00
TsMask
c93dabc6cf fix: PCF查询无数据清空表不提示警告 2023-12-07 17:16:27 +08:00
TsMask
5056de2c1a fix: 参数配置新增根据规则类型转值 2023-12-07 17:15:50 +08:00
8725518450 Merge branch 'main' of http://192.168.2.166:3180/OMC/ems_frontend_vue3 2023-12-07 15:06:45 +08:00
596ee0bb8d fix: prot to port 2023-12-07 15:06:43 +08:00
lai
d5f593647e 修复告警确认告警机制 2023-12-07 10:25:51 +08:00
51 changed files with 2255 additions and 328 deletions

View File

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

View File

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

View File

@@ -12,6 +12,11 @@
Jenkins: http://192.168.2.166:3185/
Nginx: http://192.168.2.166:3188/#/index
后端暴露端口: http://192.168.2.166:3186 \ http://192.168.2.166:3187
新网管192.168.5.13
旧网管192.168.5.14
登录账户manager/manager
```
## 程序命令
@@ -52,6 +57,6 @@ eyJhbGciOiJSUzI1NiIsImtpZCI6ImZFVUhIb1puLW04M1dfSUYyRU8zWlZueXBpNUh4T0hTRVlzU19j
```ssh
sudo chmod 700 -/.ssh/
sudochmod 700 /home/ubuntu #这个尤其容易忽视掉,我就是从这个坑里爬出来。有木有很高兴呀!
3sudochmod 600 -/ssh/authorized keys
sudo chmod 700 /home/mask/.ssh #这个尤其容易忽视掉,我就是从这个坑里爬出来。有木有很高兴呀!
sudo chmod 600 ~/.ssh/authorized_keys
```

View File

@@ -12,8 +12,8 @@
"preview": "vite preview"
},
"dependencies": {
"antdv-pro-layout": "^3.2.6",
"@ant-design/icons-vue": "^7.0.1",
"@antv/g6": "^5.0.0-beta.27",
"@codemirror/lang-javascript": "^6.2.1",
"@codemirror/merge": "^6.1.2",
"@codemirror/theme-one-dark": "^6.1.2",
@@ -21,6 +21,7 @@
"@vueuse/components": "^10.6.1",
"@vueuse/core": "^10.6.1",
"ant-design-vue": "^3.2.20",
"antdv-pro-layout": "^3.2.6",
"codemirror": "^6.0.1",
"dayjs": "^1.11.10",
"echarts": "^5.4.2",
@@ -29,24 +30,24 @@
"js-cookie": "^3.0.5",
"nprogress": "^0.2.0",
"pinia": "^2.1.7",
"vue": "^3.3.6",
"vue": "^3.3.10",
"vue-codemirror": "^6.1.1",
"vue-i18n": "^9.5.0",
"vue-i18n": "^9.8.0",
"vue-router": "^4.2.5",
"vue3-smooth-dnd": "^0.0.6",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@types/file-saver": "^2.0.5",
"@types/js-cookie": "^3.0.3",
"@types/file-saver": "^2.0.7",
"@types/js-cookie": "^3.0.6",
"@types/node": "^18.0.0",
"@types/nprogress": "^0.2.0",
"@vitejs/plugin-vue": "^4.3.4",
"@vitejs/plugin-vue": "^4.5.1",
"less": "^4.2.0",
"typescript": "^5.2.2",
"unplugin-vue-components": "^0.25.2",
"vite": "^4.5.0",
"unplugin-vue-components": "^0.26.0",
"vite": "^5.0.5",
"vite-plugin-compression": "^0.5.1",
"vue-tsc": "^1.8.19"
"vue-tsc": "^1.8.25"
}
}

View File

@@ -17,11 +17,11 @@
*
*/
(function () {
// host = ip:prot
// host = ip:port
const host = '192.168.8.100:3030';
// Service Address 服务地址
sessionStorage.setItem(baseUrl, `http://${host}`);
sessionStorage.setItem('baseUrl', `http://${host}`);
// websocket Address
sessionStorage.setItem(wsUrl, `ws://${host}`);
sessionStorage.setItem('wsUrl', `ws://${host}`);
})();

View File

@@ -92,4 +92,47 @@ body .ant-pro-basicLayout {
.ant-table.ant-table-small .ant-table-thead > tr > th {
padding: 6px !important;
}
/** ==== 表格头按钮区域 S === **/
/* 默认 */
.button-container {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
align-items: center;
}
.button-container > button {
margin-right: 12px;
margin-bottom: 12px;
}
.button-container > button:last-child {
margin-right: 0;
}
/* 平板端 */
@media (max-width: 992px) {
.button-container {
flex-direction: row;
align-items: flex-start;
align-items: left;
}
.button-container > button {
margin-right: 12px;
margin-bottom: 12px;
}
}
/* 手机端 */
@media (max-width: 576px) {
.button-container {
flex-direction: column;
align-items: flex-start;
align-items: left;
}
.button-container > button {
margin-right: 0px;
margin-bottom: 12px;
}
}
/** ==== 表格头按钮区域 E === **/
</style>

View File

@@ -11,6 +11,24 @@ export async function listNeInfo(query: Record<string, any>) {
let totalSQL = 'select count(*) as total from ne_info where status=0 ';
let rowsSQL = 'select * from ne_info where status=0 ';
// 系统特定顺序
const specificOrder = [
'OMC',
'MME',
'AMF',
'AUSF',
'UDM',
'SMF',
'PCF',
'UPF',
'NRF',
'NSSF',
'IMS',
'N3IWF',
'NEF',
'LMF',
];
// 查询
let querySQL = '';
if (query.neType) {
@@ -46,6 +64,14 @@ export async function listNeInfo(query: Record<string, any>) {
data.total = itemData[0]['total'];
} else {
data.rows = itemData.map(v => parseObjLineToHump(v));
//通过sort进行冒泡排序
data.rows.sort((a: any, b: any) => {
const typeA = specificOrder.indexOf(a.neType);
const typeB = specificOrder.indexOf(b.neType);
if (typeA === -1) return 1; // 如果不在特定顺序中,排到后面
if (typeB === -1) return -1; // 如果不在特定顺序中,排到后面
return typeA - typeB;
});
}
}
});
@@ -115,6 +141,7 @@ export async function delNeInfo(data: Record<string, any>) {
return request({
url: `/api/rest/systemManagement/v1/elementType/${data.neType}/objectType/neInfo?ne_id=${data.neId}`,
method: 'delete',
timeout:60*1000,
});
}
@@ -123,6 +150,23 @@ export async function delNeInfo(data: Record<string, any>) {
* @returns object
*/
export async function getNelistAll() {
// 系统特定顺序
const specificOrder = [
'OMC',
'MME',
'AMF',
'AUSF',
'UDM',
'SMF',
'PCF',
'UPF',
'NRF',
'NSSF',
'IMS',
'N3IWF',
'NEF',
'LMF',
];
// 发起请求
const result = await request({
url: `/api/rest/databaseManagement/v1/elementType/omc_db/objectType/ne_info`,
@@ -134,6 +178,14 @@ export async function getNelistAll() {
// 解析数据
if (result.code === RESULT_CODE_SUCCESS && Array.isArray(result.data.data)) {
let data = result.data.data[0];
//通过sort进行冒泡排序
data['ne_info'].sort((a: any, b: any) => {
const typeA = specificOrder.indexOf(a.ne_type);
const typeB = specificOrder.indexOf(b.ne_type);
if (typeA === -1) return 1;
if (typeB === -1) return -1;
return typeA - typeB;
});
return Object.assign(result, {
data: parseObjLineToHump(data['ne_info']),
});

View File

@@ -169,7 +169,7 @@ export function showPass(data: Record<string, any>) {
let querySQL = '';
querySQL += data.alarm_code ? ` and alarm_code != ${data.alarm_code} ` : '';
querySQL += data.alarm_type
? ` and alarm_type !=\\' ${data.alarm_type} \\'`
? ` and alarm_type !=\\'${data.alarm_type}\\'`
: '';
querySQL += data.pv_flag ? ` and pv_flag !=\\'${data.pv_flag} \\'` : '';
querySQL += data.orig_severity

View File

@@ -7,6 +7,23 @@ import { parseDateToStr } from '@/utils/date-utils';
* @returns object
*/
export async function listMain() {
// 系统特定顺序
const specificOrder = [
'OMC',
'MME',
'AMF',
'AUSF',
'UDM',
'SMF',
'PCF',
'UPF',
'NRF',
'NSSF',
'IMS',
'N3IWF',
'NEF',
'LMF',
];
const result = await request({
url: '/api/rest/systemManagement/v1/elementType/all/objectType/systemState',
method: 'get',
@@ -43,8 +60,16 @@ export async function listMain() {
return mergedObj;
});
// console.log(mergedData);
// console.log(rowArr)
//通过sort进行冒泡排序
mergedData.sort((a: any, b: any) => {
const typeA = specificOrder.indexOf(a.name.split('_')[0]);
const typeB = specificOrder.indexOf(b.name.split('_')[0]);
if (typeA === -1) return 1; // 如果不在特定顺序中,排到后面
if (typeB === -1) return -1; // 如果不在特定顺序中,排到后面
return typeA - typeB;
});
//console.log(mergedData);
return mergedData;
}
@@ -77,15 +102,3 @@ export function getSysConf() {
method: 'get',
});
}
/**
* 转存上传文件到静态资源
* @returns object
*/
export function transferStaticFile(data: Record<string, any>) {
return request({
url: `/transferStaticFile`,
method: 'post',
data,
});
}

View File

@@ -199,6 +199,18 @@ export function chunkUpload(data: FormData) {
});
}
/**
* 转存上传文件到静态资源
* @returns object
*/
export function transferStaticFile(data: Record<string, any>) {
return request({
url: `/file/transferStaticFile`,
method: 'post',
data,
});
}
/**
* 上传切片文件并发送文件到网元端
* @param neType 网元类型, UPF

29
src/api/tool/neFile.ts Normal file
View File

@@ -0,0 +1,29 @@
import { request } from '@/plugins/http-fetch';
/**
* 查询文件列表列表
* @param query 查询参数
* @returns object
*/
export function listNeFiles(query: Record<string, any>) {
return request({
url: '/ne/action/files',
method: 'get',
params: query,
});
}
/**
* 获取文件
* @param query 查询参数
* @returns object
*/
export function getNeFile(query: Record<string, any>) {
return request({
url: '/ne/action/pullFile',
method: 'get',
params: query,
responseType: 'blob',
timeout: 180_000,
});
}

View File

@@ -0,0 +1,775 @@
<template>
<div>
<div ref="g6Dom" :style="{ height: height, width: width }"></div>
<button @click="actions['Enable/Disable Node States'].Breathing()">
Breathing()
</button>
<button @click="actions['Enable/Disable Node States'].Scaling()">
Scaling()
</button>
<button @click="actions['Enable/Disable Edge States'].Growing()">
Growing()
</button>
<button @click="actions['Enable/Disable Edge States'].Running()">
Running()
</button>
</div>
</template>
<script lang="ts" setup>
import { nextTick, watch, onMounted, onBeforeUnmount, ref } from 'vue';
import { Graph, extend, Extensions } from '@antv/g6';
const props = defineProps({
/**
* 图表主题
*
* 'dark' | 'light'
*/
theme: {
type: String,
default: 'light', // 'dark' | 'light'
},
/**宽度默认100% */
width: {
type: String,
default: '100%',
},
/**高度 */
height: {
type: String,
default: '500px',
},
});
const g6Dom = ref<HTMLElement | undefined>(undefined);
const ExtGraph = extend(Graph, {
layouts: {},
edges: {
'polyline-edge': Extensions.PolylineEdge,
'cubic-edge': Extensions.CubicEdge,
// 'custom-edge': Extensions.CubicEdge,
},
});
const data = {
nodes: [
// 0 基站
{
id: '0',
data: {
x: 80,
y: 150,
type: 'circle-node',
color: '#fffff',
keyShape: {
r: 24,
width: 48,
height: 48,
fill: '#9EC9FF',
stroke: '#5B8FF9',
lineWidth: 2,
},
labelShape: {
text: '基站',
position: 'bottom',
maxWidth: '200%',
offsetY: 10,
},
labelBackgroundShape: {},
iconShape: {
img: 'https://gw.alipayobjects.com/zos/basement_prod/012bcf4f-423b-4922-8c24-32a89f8c41ce.svg',
width: 24,
height: 24,
},
},
},
// 1 DM
{
id: '1',
data: {
label: 'DM',
x: 600,
y: 350,
},
},
// 2 O&M
{
id: '2',
data: {
label: 'O&M',
x: 900,
y: 100,
},
},
// 5GC控制面
{
id: '170',
data: {
label: 'NSSF',
parentId: 'combo-5gc',
x: 300,
y: 50,
},
},
{
id: '130',
data: {
label: 'AUSF',
parentId: 'combo-5gc',
x: 400,
y: 50,
},
},
{
id: '140',
data: {
label: 'UDM',
parentId: 'combo-5gc',
x: 500,
y: 50,
},
},
{
id: '120',
data: {
label: 'AMF',
parentId: 'combo-5gc',
x: 300,
y: 150,
},
},
{
id: '180',
data: {
label: 'NRF',
parentId: 'combo-5gc',
x: 400,
y: 150,
},
},
{
id: '150',
data: {
label: 'SMF',
parentId: 'combo-5gc',
x: 500,
y: 250,
},
},
{
id: '160',
data: {
label: 'PCF',
parentId: 'combo-5gc',
x: 600,
y: 250,
},
},
// 5GC用户面
{
id: '190',
data: {
label: 'UPF',
parentId: 'combo-upf',
x: 300,
y: 350,
},
},
// EP-IMS
{
id: '110',
data: {
label: 'I/S-CSCF',
parentId: 'combo-ims',
x: 800,
y: 350,
},
},
{
id: '111',
data: {
label: 'P-CSCF',
parentId: 'combo-ims',
x: 800,
y: 400,
},
},
// O&M
{
id: '100',
data: {
label: 'EMS',
parentId: 'combo-ems',
x: 800,
y: 100,
},
},
],
edges: [
{
id: '0-5gc',
source: '0',
target: 'combo-5gc',
data: {
type: 'cubic-edge',
animates: {
update: [
{
// 在 selected 和 active 状态变化导致的 haloShape opacity 变化时,使 opacity 带动画地更新
fields: ['opacity'],
shapeId: 'haloShape',
states: ['selected', 'active'],
duration: 500,
},
],
},
},
},
{
id: '5gc-ems',
source: 'combo-5gc',
target: 'combo-ems',
data: {},
},
{
id: 'upf-ems',
source: 'combo-upf',
target: 'combo-ems',
data: {},
},
{
id: 'ims-ems',
source: 'combo-ims',
target: 'combo-ems',
data: {},
},
{
id: 'ems-2',
source: 'combo-ems',
target: '2',
data: {},
},
{
id: '170-120',
source: '170',
target: '120',
data: {},
},
{
id: '130-120',
source: '130',
target: '120',
data: {},
},
{
id: '140-120',
source: '140',
target: '120',
data: {},
},
{
id: '140-180',
source: '140',
target: '180',
data: {},
},
{
id: '120-180',
source: '120',
target: '180',
data: {
type: 'polyline-edge',
keyShape: {
endArrow: true,
routeCfg: {
/**
* 目前支持正交路由 'orth' 和地铁路由 'er'
*/
// name: 'er',
/**
* 是否开启自动避障,默认为 false
* Whether to enable automatic obstacle avoidance, default is false
*/
enableObstacleAvoidance: true,
},
/**
* 拐弯处的圆角弧度,默认为直角,值为 0
* The radius of the corner rounding, defaults to a right angle
*/
// radius: 20,
/**
* 拐弯处距离节点最小距离, 默认为 2
* Minimum distance from the node at the corner, default is 5.
*/
// offset: 0,
/**
* 控制点数组,不指定时根据 A* 算法自动生成折线。若指定了,则按照 controlPoints 指定的位置进行弯折
* An array of control points that, when not specified, automatically generates the bends according to the A* algorithm. If specified, bends are made at the position specified by controlPoints.
*/
// controlPoints: [],
},
},
},
{
id: '130-180',
source: '130',
target: '180',
data: {
type: 'polyline-edge',
},
},
{
id: '140-150',
source: '140',
target: '150',
data: {
type: 'polyline-edge',
},
},
{
id: '140-110',
source: '140',
target: '110',
data: {
type: 'polyline-edge',
},
},
{
id: '120-150',
source: '120',
target: '150',
data: {},
},
{
id: '150-180',
source: '150',
target: '180',
data: {},
},
{
id: '150-160',
source: '150',
target: '160',
data: { type: 'polyline-edge' },
},
{
id: '160-120',
source: '160',
target: '120',
data: {},
},
{
id: '160-180',
source: '160',
target: '180',
data: {
keyShape: {
endArrow: true,
},
labelShape: {
text: 'asdf-arrow',
},
},
},
{
id: '160-111',
source: '160',
target: '111',
data: {},
},
{
id: '0-upf',
source: '0',
target: 'combo-upf',
data: {},
},
{
id: '150-190',
source: '150',
target: '190',
data: {},
},
{
id: 'upf-1',
source: 'combo-upf',
target: '1',
data: {},
},
{
id: 'upf-ims',
source: 'combo-upf',
target: 'combo-ims',
data: {},
},
],
combos: [
{
id: 'combo-5gc',
data: {
text: '5GC控制面',
},
},
{
id: 'combo-upf',
data: {
label: '5GC用户面',
},
},
{
id: 'combo-ims',
data: {
label: 'EP-IMS用户面',
},
},
{
id: 'combo-ems',
data: {
label: 'EMS',
},
},
],
};
let graph: any = null;
/**初始化渲染图表 */
function initChart() {
if (!g6Dom.value) return;
graph = new ExtGraph({
container: g6Dom.value,
height: 500,
modes: {
default: [
{
type: 'drag-node',
enableTransient: false,
updateComboStructure: false,
},
{
type: 'click-select',
itemTypes: ['node', 'edge', 'combo'],
},
{
type: 'drag-combo',
enableTransient: true,
updateComboStructure: true,
},
// 'drag-combo',
'drag-canvas',
// 'click-select',
'zoom-canvas',
] as any,
},
// 布局 力向吸引
layout: {
type: 'force',
animated: true,
linkDistance: 280,
maxSpeed: 100,
clustering: true,
nodeClusterBy: 'parentId',
clusterNodeStrength: 80,
},
// 主题
theme: {
type: 'spec',
base: 'light',
specification: {
node: {
dataTypeField: 'parentId',
},
},
} as any,
// 插件
plugins: [
{
// 避免文本过于密集导致的视觉混乱
type: 'lod-controller',
disableLod: true,
},
] as any,
// 全局节点 矩形
node: model => {
const { id, data } = model;
return {
id,
data: {
type: 'rect-node',
keyShape: {
width: 80,
height: 40,
radius: 8,
},
labelShape: {
position: 'center',
text: data.label,
},
animates: {
update: [
{
fields: ['opacity'],
shapeId: 'haloShape',
states: ['breathing'],
iterations: Infinity,
direction: 'alternate',
duration: 500,
},
{
fields: ['lineWidth'],
shapeId: 'keyShape',
states: ['breathing'],
iterations: Infinity,
direction: 'alternate',
duration: 500,
},
{
fields: ['height', 'width'],
shapeId: 'keyShape',
states: ['scaling'],
iterations: Infinity,
direction: 'alternate',
duration: 500,
},
],
},
...data,
},
};
},
// 全局边 三次贝塞尔曲线
edge: model => {
const { id, source, target, data } = model;
return {
id,
source,
target,
data: {
type: 'cubic-edge',
animates: {
update: [
{
fields: ['lineDash'],
shapeId: 'keyShape',
states: ['growing', 'running'],
iterations: Infinity,
duration: 2000,
},
{
fields: ['offsetDistance'],
shapeId: 'buShape',
states: ['circleRunning'],
iterations: Infinity,
duration: 2000,
},
],
},
...data,
},
};
},
// 全局框节点 矩形
combo: model => {
const { id, data } = model;
return {
id,
data: {
type: 'rect-combo',
keyShape: {
opacity: 0.8,
padding: [20, 20, 20, 20],
radius: 8,
},
labelShape: {
text: data.label,
offsetY: 8,
},
labelBackgroundShape: {},
buildIn: [
{
fields: ['opacity'],
duration: 500,
delay: 500 + Math.random() * 500,
},
],
buildOut: [
{
fields: ['opacity'],
duration: 200,
},
],
animates: {
update: [
{
fields: ['width', 'height', 'x', 'y'],
shapeId: 'keyShape',
},
],
},
...data,
},
};
},
// 节点状态
nodeState: {
breathing: {
haloShape: {
opacity: 0.25,
lineWidth: 20,
visible: true,
},
keyShape: {
radius: 4,
},
},
scaling: {
keyShape: {
width: 100,
height: 60,
},
},
} as any,
edgeState: {
growing: {
keyShape: {
lineWidth: 2,
lineDash: ['100%', 0],
},
},
running: {
keyShape: {
lineWidth: 2,
lineDash: [2, 2],
// TODO: lineDashOffset
},
},
},
data,
});
graph.on('node:click', (e: any) => {
const s = graph.getItemState(e.itemId);
console.log(s);
// graph.updateData('node', {
// id: e.itemId,
// data: {
// cluster: Math.random(),
// keyShape: {
// r: 32 + Math.random() * 10 - 5,
// lineWidth: 6 + Math.random() * 6 - 3,
// stroke: '#000',
// },
// labelShape: {
// fontWeight: 700,
// },
// },
// });
});
graph.on('node:pointerenter', (e: any) => {
const { itemId } = e;
if (graph.getItemState(itemId, 'breathing')) {
graph.setItemState(itemId, 'breathing', false);
} else {
graph.setItemState(itemId, 'scaling', false);
graph.setItemState(itemId, 'breathing', true);
}
// graph.updateData('node', {
// id: itemId,
// data: {
// label: `after been hovered ${itemId}`,
// labelShape: {
// fill: '#0f0',
// },
// },
// });
});
graph.on('node:pointerleave', (e: any) => {
const { itemId } = e;
if (graph.getItemState(itemId, 'breathing')) {
graph.setItemState(itemId, 'breathing', false);
} else {
graph.setItemState(itemId, 'scaling', false);
graph.setItemState(itemId, 'breathing', true);
}
// graph.updateData('node', {
// id: itemId,
// data: {
// label: 'label before been hovered',
// labelShape: {
// fill: '#000',
// },
// },
// });
});
}
const actions = {
'Enable/Disable Node States': {
Breathing: () => {
graph.getAllNodesData().forEach((node: any) => {
if (graph.getItemState(node.id, 'breathing')) {
graph.setItemState(node.id, 'breathing', false);
} else {
graph.setItemState(node.id, 'scaling', false);
graph.setItemState(node.id, 'breathing', true);
}
});
},
Scaling: () => {
graph.getAllNodesData().forEach((node: any) => {
if (graph.getItemState(node.id, 'scaling')) {
graph.setItemState(node.id, 'scaling', false);
} else {
graph.setItemState(node.id, 'breathing', false);
graph.setItemState(node.id, 'scaling', true);
}
});
},
},
'Enable/Disable Edge States': {
Growing: () => {
graph.getAllEdgesData().forEach((edge: any) => {
if (graph.getItemState(edge.id, 'growing')) {
graph.setItemState(edge.id, 'growing', false);
} else {
graph.setItemState(edge.id, 'running', false);
graph.setItemState(edge.id, 'growing', true);
}
});
},
Running: () => {
graph.getAllEdgesData().forEach((edge: any) => {
if (graph.getItemState(edge.id, 'running')) {
graph.setItemState(edge.id, 'running', false);
} else {
graph.setItemState(edge.id, 'growing', false);
graph.setItemState(edge.id, 'running', true);
}
});
},
},
};
// watch(
// () => props.option,
// val => {
// if (val) {
// nextTick(() => {
// initChart();
// });
// }
// }
// );
onMounted(() => {
nextTick(() => {
initChart();
});
});
onBeforeUnmount(() => {});
</script>
<style lang="less" scoped></style>

View File

@@ -455,7 +455,7 @@ export default {
addItemOk: "Add Index as {num} Record Succeeded",
addItemErr: "Record addition failure",
requireUn: "{display} input value is of unknown type",
requireString: "The {display} parameter value does not make sense.",
requireString: "The {display} parameter value is invalid.",
requireInt: "{display} Parameter value not in reasonable range {filter}",
requireIpv4: "{display} not a legitimate IPV4 address",
requireIpv6: "{display} Not a legitimate IPV6 address.",
@@ -545,6 +545,7 @@ export default {
imsiTip2: 'MNC = Mobile Network Number, consisting of two digits',
imsiTip3: 'MSIN = Mobile Subscriber Identification Number, consisting of 10 equal digits.',
delSure:'Are you sure you want to delete the user with IMSI number: {imsi}?',
uploadFileErr: 'File Upload Failed',
},
base5G: {
neType: 'AMF Object',
@@ -746,7 +747,7 @@ export default {
alarmTitle:'Title',
clearUser:'Clear User',
clearType:'Clear Type',
ackState: 'Ack Status',
ackState: 'Alarm Status',
ackUser:'Ack User',
alarmSeq:'Sequence Number',
objectName:'Object Name',
@@ -815,7 +816,21 @@ export default {
alarmInfo:'Alarm Content',
eventTime:'Generation Time',
logTime:'Record Time'
}
},
neFile: {
neType:'NE Type',
neTypePlease:'Please select NE Type',
nePath: "Directory Path",
fileMode: "File Mode",
owner: "Owner",
group: "Group",
size: "Size",
modifiedTime: "Modified Time",
fileName: "File Name",
downTip: "Confirm the download file name is [{fileName}] File?",
downTipErr: "Failed to get file",
dirCd: "Enter Dir",
},
},
monitor: {
session: {
@@ -1320,7 +1335,7 @@ export default {
cmdNoTip: "{num} no optional command operation",
require: "Mandatory parameter: {num}",
requireUn: "{display} input value is of unknown type",
requireString: "The {display} parameter value does not make sense.",
requireString: "The {display} parameter value is invalid.",
requireInt: "{display} Parameter value not in reasonable range {filter}",
requireIpv4: "{display} not a legitimate IPV4 address",
requireIpv6: "{display} Not a legitimate IPV6 address.",
@@ -1334,6 +1349,7 @@ export default {
cmdAwait: "Waiting for a command to be sent",
uploadFileTip: 'Are you sure you want to upload the file?',
uploadFileOk: 'File Upload Successful',
uploadFileErr: 'File Upload Failed',
omcOperate:{
noOMC: "No OMC network elements",
},

View File

@@ -545,6 +545,7 @@ export default {
imsiTip2: 'MNC=移动网络号,由两位数字组成',
imsiTip3: 'MSIN=移动客户识别码采用等长10位数字构成',
delSure:'确认删除IMSI编号为: {imsi} 的用户吗?',
uploadFileErr: '文件上传失败',
},
base5G: {
neType: 'AMF网元对象',
@@ -815,7 +816,21 @@ export default {
alarmInfo:'告警内容',
eventTime:'告警产生时间',
logTime:'记录时间'
}
},
neFile: {
neType:'网元',
neTypePlease:'请选择网元',
nePath: "目录路径",
fileMode: "文件权限",
owner: "所属用户",
group: "所属组",
size: "文件大小",
modifiedTime: "修改时间",
fileName: "文件名称",
downTip: "确认下载文件名为 【{fileName}】 文件?",
downTipErr: "文件获取失败",
dirCd: "进入目录",
},
},
monitor: {
session: {
@@ -1334,6 +1349,7 @@ export default {
cmdAwait: "等待发送命令",
uploadFileTip: '确认要上传文件吗?',
uploadFileOk: '文件上传成功',
uploadFileErr: '文件上传失败',
omcOperate:{
noOMC: "暂无OMC网元",
},

View File

@@ -312,7 +312,7 @@ document.addEventListener('visibilitychange', function () {
<template #footerRender="{ width }">
<footer class="footer">
<div class="footer-fixed" :style="{ width }">
<div>
<div style="flex: 1;">
<span>{{ appStore.copyright }}</span>
</div>
<a-space direction="horizontal" :size="8">
@@ -364,7 +364,7 @@ document.addEventListener('visibilitychange', function () {
.footer {
z-index: 16;
margin: 0px;
width: auto;
width: auto;
margin-top: 52px;
&-fixed {
position: fixed;
@@ -379,6 +379,7 @@ document.addEventListener('visibilitychange', function () {
background: #fff;
box-shadow: 0 1px 4px #0015291f;
transition: background 0.3s, width 0.2s;
height: 32px;
}
& #serverTimeDom {

View File

@@ -6,7 +6,6 @@ import useI18n from '@/hooks/useI18n';
import useAppStore from '@/store/modules/app';
import useUserStore from '@/store/modules/user';
import useAlarmStore from '@/store/modules/alarm';
import { sessionGet } from '@/utils/cache-session-utils';
const { isFullscreen, toggle } = useFullscreen();
const { t, changeLocale, optionsLocale } = useI18n();
const userStore = useUserStore();

View File

@@ -17,5 +17,5 @@ export function parseUrlPath(path: string) {
const baseUrl = import.meta.env.PROD
? sessionGet('baseUrl') || import.meta.env.VITE_API_BASE_URL
: import.meta.env.VITE_API_BASE_URL;
return `${baseUrl}${path}`;
return `${baseUrl}${path}?r=${Math.random().toFixed(2)}`;
}

View File

@@ -10,7 +10,7 @@ type NeInfo = {
/**网元列表 */
neList: Record<string, any>[];
/**级联options树结构 */
neCascaderOtions: Record<string, any>[];
neCascaderOptions: Record<string, any>[];
/**选择器单级父类型 */
neSelectOtions: Record<string, any>[];
/**跟踪接口列表 */
@@ -22,7 +22,7 @@ type NeInfo = {
const useNeInfoStore = defineStore('neinfo', {
state: (): NeInfo => ({
neList: [],
neCascaderOtions: [],
neCascaderOptions: [],
neSelectOtions: [],
traceInterfaceList: [],
perMeasurementList: [],
@@ -33,8 +33,8 @@ const useNeInfoStore = defineStore('neinfo', {
* @param state 内部属性不用传入
* @returns 级联options
*/
getNeCascaderOtions(state) {
return state.neCascaderOtions;
getNeCascaderOptions(state) {
return state.neCascaderOptions;
},
/**
* 选择器单级父类型
@@ -70,7 +70,7 @@ const useNeInfoStore = defineStore('neinfo', {
'neName',
'neId'
);
this.neCascaderOtions = options;
this.neCascaderOptions = options;
// 转选择器单级父类型
this.neSelectOtions = options.map(item => item);

View File

@@ -20,7 +20,7 @@ import { regExpIPv4, regExpIPv6 } from '@/utils/regular-utils';
const { t } = useI18n();
/**网元参数 */
let neCascaderOtions = ref<Record<string, any>[]>([]);
let neCascaderOptions = ref<Record<string, any>[]>([]);
/**网元类型选择 type,id */
let neTypeSelect = ref<string[]>(['', '']);
@@ -1068,18 +1068,25 @@ onMounted(() => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
if (res.data.length > 0) {
// 过滤不可用的网元
neCascaderOtions.value = useNeInfoStore().getNeCascaderOtions.filter(
neCascaderOptions.value = useNeInfoStore().getNeCascaderOptions.filter(
(item: any) => {
return !['OMC'].includes(item.value);
}
);
if (neCascaderOptions.value.length === 0) {
message.warning({
content: t('common.noData'),
duration: 2,
});
return;
}
// 默认选择AMF
const item = neCascaderOtions.value.find(s => s.value === 'AMF');
const item = neCascaderOptions.value.find(s => s.value === 'AMF');
if (item && item.children) {
const info = item.children[0];
neTypeSelect.value = [info.neType, info.neId];
} else {
const info = neCascaderOtions.value[0].children[0];
const info = neCascaderOptions.value[0]?.children[0];
neTypeSelect.value = [info.neType, info.neId];
}
fnGetParamConfigTopTab();
@@ -1110,7 +1117,7 @@ onMounted(() => {
>
<a-cascader
v-model:value="neTypeSelect"
:options="neCascaderOtions"
:options="neCascaderOptions"
:allow-clear="false"
@change="fnGetParamConfigTopTab"
/>

View File

@@ -19,7 +19,7 @@ import { SizeType } from 'ant-design-vue/lib/config-provider';
const { t } = useI18n();
/**网元参数 */
let neCascaderOtions = ref<Record<string, any>[]>([]);
let neCascaderOptions = ref<Record<string, any>[]>([]);
/**网元类型选择 type,id */
let neTypeSelect = ref<string[]>(['', '']);
@@ -989,18 +989,25 @@ onMounted(() => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
if (res.data.length > 0) {
// 过滤不可用的网元
neCascaderOtions.value = useNeInfoStore().getNeCascaderOtions.filter(
neCascaderOptions.value = useNeInfoStore().getNeCascaderOptions.filter(
(item: any) => {
return !['OMC'].includes(item.value);
}
);
if (neCascaderOptions.value.length === 0) {
message.warning({
content: t('common.noData'),
duration: 2,
});
return;
}
// 默认选择AMF
const item = neCascaderOtions.value.find(s => s.value === 'AMF');
const item = neCascaderOptions.value.find(s => s.value === 'AMF');
if (item && item.children) {
const info = item.children[0];
neTypeSelect.value = [info.neType, info.neId];
} else {
const info = neCascaderOtions.value[0].children[0];
const info = neCascaderOptions.value[0].children[0];
neTypeSelect.value = [info.neType, info.neId];
}
fnGetParamConfigTopTab();
@@ -1035,7 +1042,7 @@ onMounted(() => {
>
<a-cascader
v-model:value="neTypeSelect"
:options="neCascaderOtions"
:options="neCascaderOptions"
:allow-clear="false"
@change="fnGetParamConfigTopTab"
/>

View File

@@ -16,10 +16,11 @@ import { toRaw } from 'vue';
import { regExpIPv4, regExpIPv6 } from '@/utils/regular-utils';
import { SizeType } from 'ant-design-vue/lib/config-provider';
import { DataNode } from 'ant-design-vue/lib/tree';
const neInfoStore = useNeInfoStore();
const { t } = useI18n();
/**网元参数 */
let neCascaderOtions = ref<Record<string, any>[]>([]);
let neCascaderOptions = ref<Record<string, any>[]>([]);
/**网元类型选择 type,id */
let neTypeSelect = ref<string[]>(['', '']);
@@ -1011,35 +1012,40 @@ function fnModalCancel() {
onMounted(() => {
// 获取网元网元列表
useNeInfoStore()
.fnNelist()
.then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
if (res.data.length > 0) {
// 过滤不可用的网元
neCascaderOtions.value = useNeInfoStore().getNeCascaderOtions.filter(
(item: any) => {
return !['OMC'].includes(item.value);
}
);
// 默认选择AMF
const item = neCascaderOtions.value.find(s => s.value === 'AMF');
if (item && item.children) {
const info = item.children[0];
neTypeSelect.value = [info.neType, info.neId];
} else {
const info = neCascaderOtions.value[0].children[0];
neTypeSelect.value = [info.neType, info.neId];
neInfoStore.fnNelist().then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
if (res.data.length > 0) {
// 过滤不可用的网元
neCascaderOptions.value = neInfoStore.getNeCascaderOptions.filter(
(item: any) => {
return !['OMC'].includes(item.value);
}
fnGetParamConfigTopTab();
);
if (neCascaderOptions.value.length === 0) {
message.warning({
content: t('common.noData'),
duration: 2,
});
return;
}
} else {
message.warning({
content: t('common.noData'),
duration: 2,
});
// 默认选择AMF
const item = neCascaderOptions.value.find(s => s.value === 'AMF');
if (item && item.children) {
const info = item.children[0];
neTypeSelect.value = [info.neType, info.neId];
} else {
const info = neCascaderOptions.value[0].children[0];
neTypeSelect.value = [info.neType, info.neId];
}
fnGetParamConfigTopTab();
}
});
} else {
message.warning({
content: t('common.noData'),
duration: 2,
});
}
});
});
</script>
@@ -1058,7 +1064,7 @@ onMounted(() => {
<a-form-item name="neId ">
<a-cascader
v-model:value="neTypeSelect"
:options="neCascaderOtions"
:options="neCascaderOptions"
:allow-clear="false"
@change="fnGetParamConfigTopTab"
/>

View File

@@ -16,10 +16,11 @@ import useNeInfoStore from '@/store/modules/neinfo';
import { regExpIPv4, regExpIPv6 } from '@/utils/regular-utils';
import { SizeType } from 'ant-design-vue/lib/config-provider';
import { DataNode } from 'ant-design-vue/lib/tree';
const neInfoStore = useNeInfoStore();
const { t } = useI18n();
/**网元参数 */
let neCascaderOtions = ref<Record<string, any>[]>([]);
let neCascaderOptions = ref<Record<string, any>[]>([]);
/**网元类型选择 type,id */
let neTypeSelect = ref<string[]>(['', '']);
@@ -315,17 +316,21 @@ watch(
function arrayEdit(rowIndex: Record<string, any>) {
const item = arrayState.data.find((s: any) => s.key === rowIndex.value);
if (!item) return;
const from = arrayEditInit(item, arrayState.dataRule);
// 处理信息
const row: Record<string, any> = {};
for (const v of item.record) {
for (const v of from.record) {
if (Array.isArray(v.array)) {
continue;
}
row[v.name] = Object.assign({}, v);
}
modalState.from = row;
modalState.type = 'arrayEdit';
modalState.title = `${treeState.selectNode.topDisplay} ${item.title}`;
modalState.key = item.key;
modalState.data = item.record.filter((v: any) => !Array.isArray(v.array));
modalState.title = `${treeState.selectNode.topDisplay} ${from.title}`;
modalState.key = from.key;
modalState.data = from.record.filter((v: any) => !Array.isArray(v.array));
modalState.visible = true;
// 关闭嵌套
@@ -636,17 +641,21 @@ function arrayChildExpandClose() {
function arrayChildEdit(rowIndex: Record<string, any>) {
const item = arrayChildState.data.find((s: any) => s.key === rowIndex.value);
if (!item) return;
const from = arrayEditInit(item, arrayChildState.dataRule);
// 处理信息
const row: Record<string, any> = {};
for (const v of item.record) {
for (const v of from.record) {
if (Array.isArray(v.array)) {
continue;
}
row[v.name] = Object.assign({}, v);
}
modalState.from = row;
modalState.type = 'arrayChildEdit';
modalState.title = `${arrayChildState.title} ${item.title}`;
modalState.key = item.key;
modalState.data = item.record.filter((v: any) => !Array.isArray(v.array));
modalState.title = `${arrayChildState.title} ${from.title}`;
modalState.key = from.key;
modalState.data = from.record.filter((v: any) => !Array.isArray(v.array));
modalState.visible = true;
}
@@ -813,27 +822,57 @@ function arrayChildAddOk(from: Record<string, any>) {
});
}
/**多列表编辑行数据初始化 */
function arrayEditInit(data: Record<string, any>, dataRule: any) {
const dataFrom = data.record;
const ruleFrom = Object.assign({}, JSON.parse(JSON.stringify(dataRule)));
for (const row of ruleFrom.record) {
// 子嵌套的不初始
if (row.array) {
row.value = [];
continue;
}
// 查找项的值
const item = dataFrom.find((s: any) => s.name === row.name);
if (!item) {
continue;
}
// 根据规则类型转值
if (['enum', 'int'].includes(row.type)) {
row.value = Number(item.value);
} else if ('bool' === row.type) {
row.value = Boolean(item.value);
} else {
row.value = item.value;
}
}
ruleFrom.key = data.key;
ruleFrom.title = data.title;
return ruleFrom;
}
/**多列表新增行数据初始化 */
function arrayAddInit(data: any[], dataRule: any) {
let newIndex = 0;
// 有数据时取得最后的index
let dataLastIndex = 0;
if (data.length !== 0) {
const lastFrom = Object.assign({}, JSON.parse(JSON.stringify(data.at(-1))));
if (lastFrom.record.length > 0) {
newIndex = parseInt(lastFrom.key);
dataLastIndex = parseInt(lastFrom.key);
dataLastIndex += 1;
}
}
const ruleFrom = Object.assign({}, JSON.parse(JSON.stringify(dataRule)));
for (const row of ruleFrom.record) {
const value = row.value;
// 子嵌套的不初始
if (row.array) {
row.value = [];
continue;
}
// index值
if (row.name === 'index') {
if (newIndex !== 0) {
newIndex += 1;
} else {
newIndex = parseInt(value);
}
let newIndex = dataLastIndex !== 0 ? dataLastIndex : parseInt(row.value);
if (isNaN(newIndex)) {
newIndex = 0;
}
@@ -842,10 +881,12 @@ function arrayAddInit(data: any[], dataRule: any) {
ruleFrom.title = `Index-${newIndex}`;
continue;
}
// 子嵌套的不初始
if (row.array) {
row.value = [];
continue;
// 根据规则类型转值
if (['enum', 'int'].includes(row.type)) {
row.value = Number(row.value);
}
if ('bool' === row.type) {
row.value = Boolean(row.value);
}
}
return ruleFrom;
@@ -1048,42 +1089,47 @@ function fnModalCancel() {
onMounted(() => {
// 获取网元网元列表
useNeInfoStore()
.fnNelist()
.then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
if (res.data.length > 0) {
// 过滤不可用的网元
neCascaderOtions.value = useNeInfoStore().getNeCascaderOtions.filter(
(item: any) => {
return !['OMC'].includes(item.value);
}
);
// 默认选择AMF
const item = neCascaderOtions.value.find(s => s.value === 'UPF');
if (item && item.children) {
const info = item.children[0];
neTypeSelect.value = [info.neType, info.neId];
} else {
const info = neCascaderOtions.value[0].children[0];
neTypeSelect.value = [info.neType, info.neId];
neInfoStore.fnNelist().then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
if (res.data.length > 0) {
// 过滤不可用的网元
neCascaderOptions.value = neInfoStore.getNeCascaderOptions.filter(
(item: any) => {
return !['OMC'].includes(item.value);
}
fnGetParamConfigTopTab();
);
if (neCascaderOptions.value.length === 0) {
message.warning({
content: t('common.noData'),
duration: 2,
});
return;
}
} else {
message.warning({
content: t('common.noData'),
duration: 2,
});
// 默认选择AMF
const item = neCascaderOptions.value.find(s => s.value === 'UPF');
if (item && item.children) {
const info = item.children[0];
neTypeSelect.value = [info.neType, info.neId];
} else {
const info = neCascaderOptions.value[0].children[0];
neTypeSelect.value = [info.neType, info.neId];
}
fnGetParamConfigTopTab();
}
});
} else {
message.warning({
content: t('common.noData'),
duration: 2,
});
}
});
});
</script>
<template>
<PageContainer>
<a-row :gutter="16">
<a-col :span="6">
<a-col :lg="6" :md="6" :xs="24" style="margin-bottom: 24px">
<!-- 网元类型 -->
<a-card
size="small"
@@ -1095,7 +1141,7 @@ onMounted(() => {
<a-form-item name="neId ">
<a-cascader
v-model:value="neTypeSelect"
:options="neCascaderOtions"
:options="neCascaderOptions"
:allow-clear="false"
@change="fnGetParamConfigTopTab"
/>
@@ -1111,7 +1157,7 @@ onMounted(() => {
</a-form>
</a-card>
</a-col>
<a-col :span="18">
<a-col :lg="18" :md="18" :xs="24">
<a-card
size="small"
:bordered="false"
@@ -1264,19 +1310,20 @@ onMounted(() => {
v-model:expanded-row-keys="arrayState.arrayChildExpandKeys"
>
<!-- 多列新增操作 -->
<template #title v-if="treeState.selectNode.method !== 'get'">
<template #title>
<a-space :size="16" align="center">
<a-button
type="primary"
@click.prevent="arrayAdd()"
size="small"
v-if="treeState.selectNode.method !== 'get'"
>
<template #icon> <PlusOutlined /> </template>
{{ t('common.addText') }}
</a-button>
<TableColumnsDnd
type="ghost"
:columns="[...arrayState.columns]"
:columns="treeState.selectNode.method === 'get' ? [...arrayState.columns.filter((s:any)=>s.key !== 'index')] : arrayState.columns"
v-model:columns-dnd="arrayState.columnsDnd"
></TableColumnsDnd>
</a-space>

View File

@@ -11,6 +11,7 @@ import useI18n from '@/hooks/useI18n';
import useNeInfoStore from '@/store/modules/neinfo';
import { FileType } from 'ant-design-vue/lib/upload/interface';
import { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
const neInfoStore = useNeInfoStore();
const { t } = useI18n();
/**查询参数 */
@@ -129,7 +130,7 @@ function fnTableSize({ key }: MenuInfo) {
function fnGetList(pageNum?: number) {
if (tableState.loading) return;
tableState.loading = true;
if(pageNum){
if (pageNum) {
queryParams.pageNum = pageNum;
}
listLicense(toRaw(queryParams)).then(res => {
@@ -267,7 +268,10 @@ function fnBeforeUploadFile(file: FileType) {
const fileName = file.name;
const suff = fileName.substring(fileName.lastIndexOf('.'));
if (!['.ini'].includes(suff)) {
message.error(t('views.configManage.softwareManage.onlyAble',{fileText:'(.ini)'}), 3);
message.error(
t('views.configManage.softwareManage.onlyAble', { fileText: '(.ini)' }),
3
);
return false;
}
@@ -287,19 +291,17 @@ function fnUploadFile(up: UploadRequestOption) {
onMounted(() => {
// 获取网元网元列表
useNeInfoStore()
.fnNelist()
.then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
// 获取列表数据
fnGetList();
} else {
message.warning({
content: t('views.configManage.softwareManage.nullData'),
duration: 2,
});
}
});
neInfoStore.fnNelist().then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
// 获取列表数据
fnGetList();
} else {
message.warning({
content: t('views.configManage.softwareManage.nullData'),
duration: 2,
});
}
});
});
</script>
@@ -320,7 +322,7 @@ onMounted(() => {
>
<a-auto-complete
v-model:value="queryParams.neType"
:options="useNeInfoStore().getNeSelectOtions"
:options="neInfoStore.getNeSelectOtions"
allow-clear
:placeholder="t('views.configManage.license.neTypePlease')"
/>
@@ -425,10 +427,7 @@ onMounted(() => {
@ok="fnModalOk"
@cancel="fnModalCancel"
>
<a-form
name="modalStateFrom"
layout="horizontal"
>
<a-form name="modalStateFrom" layout="horizontal">
<a-form-item
:label="t('views.configManage.license.neType')"
name="neType"
@@ -436,7 +435,7 @@ onMounted(() => {
>
<a-cascader
v-model:value="modalState.from.neType"
:options="useNeInfoStore().getNeCascaderOtions"
:options="useNeInfoStore().getNeCascaderOptions"
:allow-clear="false"
:placeholder="t('views.configManage.license.neTypePlease')"
/>

View File

@@ -18,11 +18,12 @@ import {
import useI18n from '@/hooks/useI18n';
import useDictStore from '@/store/modules/dict';
import saveAs from 'file-saver';
import TableColumnsDnd from '@/components/TableColumnsDnd/index.vue';
import { writeSheet } from '@/utils/execl-utils';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { readLoalXlsx } from '@/utils/execl-utils';
const { getDict } = useDictStore();
const { t,currentLocale } = useI18n();
const { t, currentLocale } = useI18n();
/**字典数据 */
let dict: {
@@ -41,6 +42,9 @@ let dict: {
activeAlarmSeverity: [],
});
/**表格字段列排序 */
let tableColumnsDnd = ref<ColumnsType>([]);
/**记录开始结束时间 */
let queryRangePicker = ref<[string, string]>(['', '']);
@@ -233,9 +237,6 @@ let tableColumns: ColumnsType = [
},
];
/**帮助文档表格字段列 */
let alarmTableColumns: ColumnsType = [
{
@@ -246,19 +247,19 @@ let alarmTableColumns: ColumnsType = [
},
{
title: t('views.faultManage.activeAlarm.locationInfo'),
dataIndex: 'alarmInfo',
dataIndex: 'alarmInfo',
align: 'center',
width: 5,
},
{
title: t('views.faultManage.activeAlarm.addInfo'),
dataIndex:'helpInfo',
dataIndex: 'helpInfo',
align: 'center',
width: 8,
},
{
title: t('views.faultManage.activeAlarm.alarmType'),
dataIndex: 'alarmType',
dataIndex: 'alarmType',
align: 'center',
width: 5,
},
@@ -294,7 +295,7 @@ let alarmTableColumns: ColumnsType = [
},
{
title: t('views.faultManage.activeAlarm.objectNf'),
dataIndex:'objNf',
dataIndex: 'objNf',
align: 'center',
width: 2,
},
@@ -416,14 +417,12 @@ function fnModalVisibleByVive(row: Record<string, any>) {
modalState.visibleByView = true;
}
/** 告警帮助文档详细信息 */
function fnModalVisibleBy(code: string) {
modalState.helpShowView = false;
const lang=currentLocale.value.split('_')[0];
modalState.title=t('views.faultManage.activeAlarm.helpFile');
readLoalXlsx(lang,code)
const lang = currentLocale.value.split('_')[0];
modalState.title = t('views.faultManage.activeAlarm.helpFile');
readLoalXlsx(lang, code)
.then(res => {
alarmTableState.data = res;
modalState.helpShowView = true;
@@ -438,7 +437,7 @@ function fnModalVisibleBy(code: string) {
function fnModalOk() {
modalState.confirmLoading = true;
const from = toRaw(modalState.from);
if (from.ackState) {
if (from.ackState === '1') {
message.error({
content: t('views.faultManage.activeAlarm.ackError'),
duration: 3,
@@ -661,7 +660,7 @@ function fnModalCancel() {
modalState.visibleByEdit = false;
modalState.visibleByView = false;
modalState.visibleByShowSet = false;
modalState.helpShowView=false;
modalState.helpShowView = false;
}
/**查询列表, pageNum初始页数 */
@@ -850,7 +849,7 @@ onMounted(() => {
<a-card :bordered="false" :body-style="{ padding: '0px' }">
<!-- 插槽-卡片左侧侧 -->
<template #title>
<a-space :size="8" align="center">
<div class="button-container">
<a-button
type="primary"
@click.prevent="fnCancelConfirm()"
@@ -890,12 +889,12 @@ onMounted(() => {
<template #icon> <export-outlined /> </template>
{{ t('views.faultManage.activeAlarm.exportAll') }}
</a-button>
</a-space>
</div>
</template>
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8" align="center">
<div class="button-container">
<a-tooltip>
<template #title>{{ t('common.searchBarText') }}</template>
<a-switch
@@ -935,14 +934,18 @@ onMounted(() => {
</template>
</a-dropdown>
</a-tooltip>
</a-space>
<TableColumnsDnd
:columns="tableColumns"
v-model:columns-dnd="tableColumnsDnd"
></TableColumnsDnd>
</div>
</template>
<!-- 表格列表 -->
<a-table
class="table"
row-key="id"
:columns="tableColumns"
:columns="tableColumnsDnd"
:loading="tableState.loading"
:data-source="tableState.data"
:size="tableState.size"
@@ -1006,7 +1009,6 @@ onMounted(() => {
</a-table>
</a-card>
<!-- 帮助文档 -->
<a-modal
width="100%"
@@ -1027,7 +1029,7 @@ onMounted(() => {
:data-source="alarmTableState.data"
:size="alarmTableState.size"
:pagination="false"
:scroll="{ x: 1700, y: 560 }"
:scroll="{ x: 1700, y: 560 }"
>
</a-table>
</a-modal>

View File

@@ -14,6 +14,8 @@ import { PieChart } from 'echarts/charts';
import { LabelLayout } from 'echarts/features';
import { useRoute } from 'vue-router';
import useAppStore from '@/store/modules/app';
import useDictStore from '@/store/modules/dict';
const { getDict } = useDictStore();
const appStore = useAppStore();
const route = useRoute();
const { t } = useI18n();
@@ -28,6 +30,13 @@ echarts.use([
LabelLayout,
]);
/**字典数据 */
/**用户性别字典 */
let indexColor = ref<DictType[]>([
{ label: 'normal', value: 'normal', elTagType: '', elTagClass: '#91cc75' },
{ label: 'abnormal', value: 'abnormal', elTagType: '', elTagClass: '#ee6666' },
]);
/**表格字段列 */
//customRender(){} ----单元格处理
let tableColumns: ColumnsType = [
@@ -174,7 +183,10 @@ function fnGetList(one: boolean) {
orient: 'vertical',
left: 'left',
},
color: ['#91cc75', '#ee6666'],
color: [
'' + indexColor.value[0]['elTagClass'],
'' + indexColor.value[1]['elTagClass'],
],
series: [
{
name: t('views.index.realNeStatus'),
@@ -393,6 +405,12 @@ function fnLocale() {
}
onMounted(() => {
getDict('index_status').then(res => {
if (res.length > 0) {
indexColor.value = res;
}
});
//console.log(indexColor)
fnLocale();
fnGetList(true);
timer = setInterval(() => fnGetList(false), 10000); // 每隔10秒执行一次

View File

@@ -0,0 +1,346 @@
<script setup lang="ts">
import { reactive, ref, onMounted, toRaw } from 'vue';
import { PageContainer } from 'antdv-pro-layout';
import { SizeType } from 'ant-design-vue/lib/config-provider';
import { ColumnsType } from 'ant-design-vue/lib/table';
import { parseDateToStr } from '@/utils/date-utils';
import { getNeFile, listNeFiles } from '@/api/tool/neFile';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import useNeInfoStore from '@/store/modules/neinfo';
import useI18n from '@/hooks/useI18n';
import { Modal, message } from 'ant-design-vue/lib';
import saveAs from 'file-saver';
const neInfoStore = useNeInfoStore();
const { t } = useI18n();
/**网元参数 */
let neType = ref([]);
/**下载触发等待 */
let loading = ref(false);
/**访问路径 */
let nePathArr = ref<string[]>([]);
/**查询参数 */
let queryParams = reactive({
/**网元类型 */
neType: '',
neId: '',
/**读取路径 */
path: '',
/**前缀过滤 */
search: '',
/**当前页数 */
pageNum: 1,
/**每页条数 */
pageSize: 20,
});
/**表格状态类型 */
type TabeStateType = {
/**加载等待 */
loading: boolean;
/**紧凑型 */
size: SizeType;
/**记录数据 */
data: object[];
};
/**表格状态 */
let tableState: TabeStateType = reactive({
loading: false,
size: 'small',
data: [],
});
/**表格字段列 */
let tableColumns: ColumnsType = [
{
title: t('views.logManage.neFile.fileMode'),
dataIndex: 'fileMode',
align: 'center',
width: 150,
},
{
title: t('views.logManage.neFile.owner'),
dataIndex: 'owner',
align: 'left',
width: 100,
},
{
title: t('views.logManage.neFile.group'),
dataIndex: 'group',
align: 'left',
width: 100,
},
{
title: t('views.logManage.neFile.size'),
dataIndex: 'size',
align: 'left',
width: 100,
},
{
title: t('views.logManage.neFile.modifiedTime'),
dataIndex: 'modifiedTime',
align: 'left',
customRender(opt) {
if (!opt.value) return '';
return parseDateToStr(opt.value * 1000);
},
width: 150,
},
{
title: t('views.logManage.neFile.fileName'),
dataIndex: 'fileName',
align: 'left',
},
{
title: t('common.operate'),
key: 'fileName',
align: 'center',
width: 100,
},
];
/**表格分页器参数 */
let tablePagination = reactive({
/**当前页数 */
current: 1,
/**每页条数 */
pageSize: 20,
/**默认的每页条数 */
defaultPageSize: 20,
/**指定每页可以显示多少条 */
pageSizeOptions: ['10', '20', '50', '100'],
/**只有一页时是否隐藏分页器 */
hideOnSinglePage: false,
/**是否可以快速跳转至某页 */
showQuickJumper: true,
/**是否可以改变 pageSize */
showSizeChanger: true,
/**数据总数 */
total: 0,
showTotal: (total: number) => t('common.tablePaginationTotal', { total }),
onChange: (page: number, pageSize: number) => {
tablePagination.current = page;
tablePagination.pageSize = pageSize;
queryParams.pageNum = page;
queryParams.pageSize = pageSize;
fnGetList();
},
});
/**信息文件下载 */
function fnDownloadFile(row: Record<string, any>) {
if (loading.value) return;
Modal.confirm({
title: t('common.tipTitle'),
content: t('views.logManage.neFile.downTip', { fileName: row.fileName }),
onOk() {
loading.value = true;
const hide = message.loading(t('common.loading'), 0);
getNeFile({
neType: queryParams.neType,
neId: queryParams.neId,
path: queryParams.path,
fileName: row.fileName,
})
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success({
content: t('common.msgSuccess', {
msg: t('common.downloadText'),
}),
duration: 2,
});
saveAs(res.data, `${row.fileName}`);
} else {
message.error({
content: t('views.logManage.neFile.downTipErr'),
duration: 2,
});
}
})
.finally(() => {
hide();
loading.value = false;
});
},
});
}
/**进入目录 */
function fnDirCD(dir: string, index?: number) {
if (index === undefined) {
nePathArr.value.push(dir);
queryParams.search = '';
fnGetList(1);
return;
}
if (index === 0) {
const neType = queryParams.neType;
if (neType === 'IMS') {
nePathArr.value = ['/var/log/ims'];
queryParams.search = '';
} else {
nePathArr.value = ['/var/log'];
queryParams.search = neType.toLowerCase();
}
fnGetList(1);
} else {
nePathArr.value = nePathArr.value.slice(0, index + 1);
queryParams.search = '';
fnGetList(1);
}
}
/**网元类型选择对应修改 */
function fnNeChange(keys: any, _: any) {
// 不是同类型时需要重新加载
if (Array.isArray(keys) && queryParams.neType !== keys[0]) {
const neType = keys[0];
queryParams.neType = neType;
queryParams.neId = keys[1];
if (neType === 'IMS') {
nePathArr.value = ['/var/log/ims'];
} else {
nePathArr.value = ['/var/log'];
queryParams.search = neType.toLowerCase();
}
fnGetList(1);
}
}
/**查询备份信息列表, pageNum初始页数 */
function fnGetList(pageNum?: number) {
if (queryParams.neId === '') {
message.warning({
content: t('views.logManage.neFile.neTypePlease'),
duration: 2,
});
return;
}
if (tableState.loading) return;
tableState.loading = true;
if (pageNum) {
queryParams.pageNum = pageNum;
}
queryParams.path = nePathArr.value.join('/');
listNeFiles(toRaw(queryParams)).then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
tablePagination.total = res.total;
tableState.data = res.rows;
}
tableState.loading = false;
});
}
onMounted(() => {
// 获取网元网元列表
neInfoStore.fnNelist().then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
if (res.data.length === 0) {
message.warning({
content: t('common.noData'),
duration: 2,
});
}
}
});
});
</script>
<template>
<PageContainer>
<a-card :bordered="false" :body-style="{ padding: '0px' }">
<!-- 插槽-卡片左侧侧 -->
<template #title>
<a-form :model="queryParams" name="queryParams" layout="horizontal">
<a-row :gutter="16">
<a-col :lg="8" :md="12" :xs="24">
<a-form-item
:label="t('views.logManage.neFile.neType')"
name="neType"
style="margin-bottom: 0"
>
<a-cascader
v-model:value="neType"
:options="neInfoStore.getNeCascaderOptions"
@change="fnNeChange"
:allow-clear="false"
:placeholder="t('views.logManage.neFile.neTypePlease')"
:disabled="loading || tableState.loading"
/>
</a-form-item>
</a-col>
<a-col :lg="16" :md="18" :xs="24" v-if="nePathArr.length > 0">
<a-form-item
:label="t('views.logManage.neFile.nePath')"
name="configName"
style="margin-bottom: 0"
>
<a-breadcrumb>
<a-breadcrumb-item
v-for="(path, index) in nePathArr"
:key="path"
@click="fnDirCD(path, index)"
>
{{ path }}
</a-breadcrumb-item>
</a-breadcrumb>
</a-form-item>
</a-col>
</a-row>
</a-form>
</template>
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8" align="center">
<a-tooltip>
<template #title>{{ t('common.reloadText') }}</template>
<a-button type="text" @click.prevent="fnGetList()">
<template #icon><ReloadOutlined /></template>
</a-button>
</a-tooltip>
</a-space>
</template>
<!-- 表格列表 -->
<a-table
class="table"
row-key="fileName"
:columns="tableColumns"
:loading="tableState.loading"
:data-source="tableState.data"
:size="tableState.size"
:pagination="tablePagination"
:scroll="{ x: 800 }"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'fileName'">
<a-space :size="8" align="center">
<a-button
type="link"
@click.prevent="fnDownloadFile(record)"
v-if="record.fileType === 'file'"
>
<template #icon><DownloadOutlined /></template>
{{ t('common.downloadText') }}
</a-button>
<a-button
type="link"
@click.prevent="fnDirCD(record.fileName)"
v-if="record.fileType === 'dir'"
>
<template #icon><FolderOutlined /></template>
{{ t('views.logManage.neFile.dirCd') }}
</a-button>
</a-space>
</template>
</template>
</a-table>
</a-card>
</PageContainer>
</template>
<style lang="less" scoped></style>

View File

@@ -10,6 +10,7 @@ import useI18n from '@/hooks/useI18n';
import { getMMLByNE, sendMMlByNE } from '@/api/mmlManage/neOperate';
import { uploadFileToNE } from '@/api/tool/file';
import { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
const neInfoStore = useNeInfoStore();
const { t } = useI18n();
/**网元参数 */
@@ -63,9 +64,30 @@ let state: StateType = reactive({
function fnTreeSelect(_: any, info: any) {
state.mmlSelect = info.node.dataRef;
state.from = {};
// 遍历判断是否有初始value
if (Array.isArray(state.mmlSelect.param)) {
for (const param of state.mmlSelect.param) {
if (typeof param.value !== 'undefined' && param.value != '') {
const valueType = param.type;
if (['enum', 'int'].includes(valueType)) {
state.from[param.name] = Number(param.value);
} else if (valueType === 'bool') {
state.from[param.name] = Boolean(param.value);
} else {
state.from[param.name] = param.value;
}
}
}
}
state.autoCompleteValue =
`${state.mmlSelect.operation} ${state.mmlSelect.object}`.trim();
// state.mmlCmdLog = '';
// 回到顶部
window.scrollTo({
top: 0,
behavior: 'smooth', // 平滑滚动到顶部,如果不需要平滑效果可以将此行代码删除
});
}
/**清空控制台日志 */
@@ -185,7 +207,7 @@ function fnUpload(up: UploadRequestOption, name: string) {
message.success(t('views.mmlManage.uploadFileOk'), 3);
state.from[name] = res.data;
} else {
message.error(res.msg, 3);
message.error(t('views.mmlManage.uploadFileErr'), 3);
}
})
.finally(() => {
@@ -455,42 +477,47 @@ function fnAutoCompleteChange(value: any, _: any) {
onMounted(() => {
// 获取网元网元列表
useNeInfoStore()
.fnNelist()
.then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
if (res.data.length > 0) {
// 过滤不可用的网元
neCascaderOptions.value = useNeInfoStore().getNeCascaderOtions.filter(
(item: any) => {
return !['OMC'].includes(item.value);
}
);
// 默认选择AMF
const item = neCascaderOptions.value.find(s => s.value === 'AMF');
if (item && item.children) {
const info = item.children[0];
state.neType = [info.neType, info.neId];
} else {
const info = neCascaderOptions.value[0].children[0];
state.neType = [info.neType, info.neId];
neInfoStore.fnNelist().then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
if (res.data.length > 0) {
// 过滤不可用的网元
neCascaderOptions.value = neInfoStore.getNeCascaderOptions.filter(
(item: any) => {
return !['OMC'].includes(item.value);
}
fnGetList();
);
if (neCascaderOptions.value.length === 0) {
message.warning({
content: t('common.noData'),
duration: 2,
});
return;
}
} else {
message.warning({
content: t('common.noData'),
duration: 2,
});
// 默认选择AMF
const item = neCascaderOptions.value.find(s => s.value === 'AMF');
if (item && item.children) {
const info = item.children[0];
state.neType = [info.neType, info.neId];
} else {
const info = neCascaderOptions.value[0].children[0];
state.neType = [info.neType, info.neId];
}
fnGetList();
}
});
} else {
message.warning({
content: t('common.noData'),
duration: 2,
});
}
});
});
</script>
<template>
<PageContainer>
<a-row :gutter="16">
<a-col :span="6">
<a-col :lg="6" :md="6" :xs="24" style="margin-bottom: 24px">
<!-- 命令导航 -->
<a-card
size="small"
@@ -518,7 +545,7 @@ onMounted(() => {
</a-form>
</a-card>
</a-col>
<a-col :span="18">
<a-col :lg="18" :md="18" :xs="24">
<!-- 命令参数输入 -->
<a-card size="small" :bordered="false">
<template #title>
@@ -558,7 +585,7 @@ onMounted(() => {
</template>
<a-form
layout="vertical"
layout="horizontal"
autocomplete="off"
:validate-on-rule-change="false"
:validateTrigger="[]"
@@ -576,8 +603,15 @@ onMounted(() => {
<a-textarea :placeholder="t('common.ipnutPlease')" auto-size />
</a-auto-complete>
</a-form-item>
</a-form>
<template v-if="state.mmlSelect.operation && state.mmlSelect.param">
<template v-if="state.mmlSelect.operation && state.mmlSelect.param">
<a-form
layout="vertical"
autocomplete="off"
:validate-on-rule-change="false"
:validateTrigger="[]"
>
<a-divider orientation="left">
{{ t('views.mmlManage.cmdParamPanel') }}
</a-divider>
@@ -653,8 +687,8 @@ onMounted(() => {
</a-form-item>
</a-col>
</a-row>
</template>
</a-form>
</a-form>
</template>
</a-card>
<!-- 命令展示 -->

View File

@@ -60,9 +60,30 @@ let state: StateType = reactive({
function fnTreeSelect(_: any, info: any) {
state.mmlSelect = info.node.dataRef;
state.from = {};
// 遍历判断是否有初始value
if (Array.isArray(state.mmlSelect.param)) {
for (const param of state.mmlSelect.param) {
if (typeof param.value !== 'undefined' && param.value != '') {
const valueType = param.type;
if (['enum', 'int'].includes(valueType)) {
state.from[param.name] = Number(param.value);
} else if (valueType === 'bool') {
state.from[param.name] = Boolean(param.value);
} else {
state.from[param.name] = param.value;
}
}
}
}
state.autoCompleteValue =
`${state.mmlSelect.operation} ${state.mmlSelect.object}`.trim();
// state.mmlCmdLog = '';
// 回到顶部
window.scrollTo({
top: 0,
behavior: 'smooth', // 平滑滚动到顶部,如果不需要平滑效果可以将此行代码删除
});
}
/**清空控制台日志 */
@@ -156,8 +177,8 @@ function fnSendMML() {
for (let i = 0; i < resultArr.length; i++) {
const str = resultArr[i];
const logStr = str.replace(/(\r\n|\n)/g, '\n');
const cmdStr = cmdArr[i]
state.mmlCmdLog += `${cmdStr}\n${logStr}\n`;
const cmdStr = cmdArr[i];
state.mmlCmdLog += `${cmdStr}\n${logStr}\n`;
}
} else {
state.mmlCmdLog += `${res.msg}\n`;
@@ -180,7 +201,7 @@ function fnUpload(up: UploadRequestOption, name: string) {
message.success(t('views.mmlManage.uploadFileOk'), 3);
state.from[name] = res.data;
} else {
message.error(res.msg, 3);
message.error(t('views.mmlManage.uploadFileErr'), 3);
}
})
.finally(() => {
@@ -466,7 +487,7 @@ onMounted(() => {
<template>
<PageContainer>
<a-row :gutter="16">
<a-col :span="6">
<a-col :lg="6" :md="6" :xs="24" style="margin-bottom: 24px">
<!-- 命令导航 -->
<a-card
size="small"
@@ -492,7 +513,7 @@ onMounted(() => {
</a-form>
</a-card>
</a-col>
<a-col :span="18">
<a-col :lg="18" :md="18" :xs="24">
<!-- 命令参数输入 -->
<a-card size="small" :bordered="false">
<template #title>
@@ -532,7 +553,7 @@ onMounted(() => {
</template>
<a-form
layout="vertical"
layout="horizontal"
autocomplete="off"
:validate-on-rule-change="false"
:validateTrigger="[]"
@@ -550,8 +571,15 @@ onMounted(() => {
<a-textarea :placeholder="t('common.ipnutPlease')" auto-size />
</a-auto-complete>
</a-form-item>
</a-form>
<template v-if="state.mmlSelect.operation && state.mmlSelect.param">
<template v-if="state.mmlSelect.operation && state.mmlSelect.param">
<a-form
layout="vertical"
autocomplete="off"
:validate-on-rule-change="false"
:validateTrigger="[]"
>
<a-divider orientation="left">
{{ t('views.mmlManage.cmdParamPanel') }}
</a-divider>
@@ -627,8 +655,8 @@ onMounted(() => {
</a-form-item>
</a-col>
</a-row>
</template>
</a-form>
</a-form>
</template>
</a-card>
<!-- 命令展示 -->

View File

@@ -60,9 +60,30 @@ let state: StateType = reactive({
function fnTreeSelect(_: any, info: any) {
state.mmlSelect = info.node.dataRef;
state.from = {};
// 遍历判断是否有初始value
if (Array.isArray(state.mmlSelect.param)) {
for (const param of state.mmlSelect.param) {
if (typeof param.value !== 'undefined' && param.value != '') {
const valueType = param.type;
if (['enum', 'int'].includes(valueType)) {
state.from[param.name] = Number(param.value);
} else if (valueType === 'bool') {
state.from[param.name] = Boolean(param.value);
} else {
state.from[param.name] = param.value;
}
}
}
}
state.autoCompleteValue =
`${state.mmlSelect.operation} ${state.mmlSelect.object}`.trim();
// state.mmlCmdLog = '';
// 回到顶部
window.scrollTo({
top: 0,
behavior: 'smooth', // 平滑滚动到顶部,如果不需要平滑效果可以将此行代码删除
});
}
/**清空控制台日志 */
@@ -180,7 +201,7 @@ function fnUpload(up: UploadRequestOption, name: string) {
message.success(t('views.mmlManage.uploadFileOk'), 3);
state.from[name] = res.data;
} else {
message.error(res.msg, 3);
message.error(t('views.mmlManage.uploadFileErr'), 3);
}
})
.finally(() => {
@@ -446,6 +467,11 @@ onMounted(() => {
state.neId = arr[0].value;
// 获取列表数据
fnGetList();
} else {
message.warning({
content: t('views.mmlManage.udmOpesrate.noUDM'),
duration: 5,
});
}
} else {
message.warning({
@@ -466,7 +492,7 @@ onMounted(() => {
<template>
<PageContainer>
<a-row :gutter="16">
<a-col :span="6">
<a-col :lg="6" :md="6" :xs="24" style="margin-bottom: 24px">
<!-- 命令导航 -->
<a-card
size="small"
@@ -492,7 +518,7 @@ onMounted(() => {
</a-form>
</a-card>
</a-col>
<a-col :span="18">
<a-col :lg="18" :md="18" :xs="24">
<!-- 命令参数输入 -->
<a-card size="small" :bordered="false">
<template #title>
@@ -532,7 +558,7 @@ onMounted(() => {
</template>
<a-form
layout="vertical"
layout="horizontal"
autocomplete="off"
:validate-on-rule-change="false"
:validateTrigger="[]"
@@ -550,8 +576,15 @@ onMounted(() => {
<a-textarea :placeholder="t('common.ipnutPlease')" auto-size />
</a-auto-complete>
</a-form-item>
</a-form>
<template v-if="state.mmlSelect.operation && state.mmlSelect.param">
<template v-if="state.mmlSelect.operation && state.mmlSelect.param">
<a-form
layout="vertical"
autocomplete="off"
:validate-on-rule-change="false"
:validateTrigger="[]"
>
<a-divider orientation="left">
{{ t('views.mmlManage.cmdParamPanel') }}
</a-divider>
@@ -627,8 +660,8 @@ onMounted(() => {
</a-form-item>
</a-col>
</a-row>
</template>
</a-form>
</a-form>
</template>
</a-card>
<!-- 命令展示 -->

View File

@@ -645,7 +645,7 @@ onMounted(() => {
<a-card :bordered="false" :body-style="{ padding: '0px' }">
<!-- 插槽-卡片左侧侧 -->
<template #title>
<a-space :size="8" align="center">
<div class="button-container">
<a-button
type="primary"
@click.prevent="fnModalVisibleByEdit()"
@@ -689,12 +689,12 @@ onMounted(() => {
<template #icon><SyncOutlined /></template>
{{ t('views.monitor.job.resetQueue') }}
</a-button>
</a-space>
</div>
</template>
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8" align="center">
<div class="button-container">
<a-tooltip>
<template #title>{{ t('common.searchBarText') }}</template>
<a-switch
@@ -743,7 +743,7 @@ onMounted(() => {
</template>
</a-dropdown>
</a-tooltip>
</a-space>
</div>
</template>
<!-- 表格列表 -->
@@ -866,7 +866,8 @@ onMounted(() => {
<a-col :lg="12" :md="12" :xs="24">
<a-form-item :label="t('views.monitor.job.status')" name="status">
{{
dict.sysJobStatus.find(s => s.value === modalState.from.status)?.label
dict.sysJobStatus.find(s => s.value === modalState.from.status)
?.label
}}
</a-form-item>
</a-col>

View File

@@ -491,7 +491,7 @@ onMounted(() => {
<a-card :bordered="false" :body-style="{ padding: '0px' }">
<!-- 插槽-卡片左侧侧 -->
<template #title>
<a-space :size="8" align="center">
<div class="button-container">
<a-button type="default" @click.prevent="fnClose()">
<template #icon><CloseOutlined /></template>
{{ t('common.close') }}
@@ -523,12 +523,12 @@ onMounted(() => {
<template #icon><ExportOutlined /></template>
{{ t('common.export') }}
</a-button>
</a-space>
</div>
</template>
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8" align="center">
<div class="button-container">
<a-tooltip>
<template #title>{{ t('common.searchBarText') }}</template>
<a-switch
@@ -577,7 +577,7 @@ onMounted(() => {
</template>
</a-dropdown>
</a-tooltip>
</a-space>
</div>
</template>
<!-- 表格列表 -->

View File

@@ -0,0 +1,68 @@
<script setup lang="ts">
import { reactive, onMounted } from 'vue';
import { PageContainer } from 'antdv-pro-layout';
import ChartGraphG6 from '@/components/ChartGraphG6/index.vue';
import useI18n from '@/hooks/useI18n';
const { t } = useI18n();
/**查询全部网元数据列表 */
function fnGetList() {}
onMounted(() => {});
</script>
<template>
<PageContainer>
<a-card
:bordered="false"
:body-style="{ marginBottom: '24px', paddingBottom: 0 }"
>
<!-- 表格搜索栏 -->
<a-form name="queryParams" layout="horizontal">
<a-row :gutter="16">
<a-col :lg="10" :md="10" :xs="24">
<a-form-item
:label="t('views.monitor.monitor.filter')"
name="neTypeSelect"
>
ssdf
</a-form-item>
</a-col>
<a-col :lg="6" :md="12" :xs="24">
<a-form-item>
<a-space :size="8">
<a-button type="primary" @click.prevent="fnGetList()">
<template #icon><SearchOutlined /></template>
{{ t('common.search') }}
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-card>
<a-row :gutter="16">
<a-col :lg="24" :md="24" :xs="24">
<a-card :bordered="false" :body-style="{ marginBottom: '24px' }">
<!-- 插槽-卡片左侧侧 -->
<template #title>asdf</template>
<!-- 插槽-卡片右侧 -->
<template #extra> adf </template>
<div class="chart">
<ChartGraphG6 :option="{}"></ChartGraphG6>
</div>
</a-card>
</a-col>
</a-row>
</PageContainer>
</template>
<style lang="less" scoped>
.chart {
width: 100%;
height: 500px;
background-color: rgb(238, 237, 237);
}
</style>

View File

@@ -728,7 +728,7 @@ onMounted(() => {
<a-card :bordered="false" :body-style="{ padding: '0px' }">
<!-- 插槽-卡片左侧侧 -->
<template #title>
<a-space :size="8" align="center">
<div class="button-container">
<a-button type="primary" @click.prevent="fnModalVisibleByEdit()">
<template #icon>
<PlusOutlined />
@@ -790,12 +790,12 @@ onMounted(() => {
{{ t('views.neUser.auth.export') }}
</a-button>
</a-popconfirm>
</a-space>
</div>
</template>
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8" align="center">
<div class="button-container">
<a-tooltip>
<template #title>{{ t('common.searchBarText') }}</template>
<a-switch
@@ -848,7 +848,7 @@ onMounted(() => {
</template>
</a-dropdown>
</a-tooltip>
</a-space>
</div>
</template>
<!-- 表格列表 -->

View File

@@ -410,10 +410,7 @@ function fnGetList() {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
tableState.data = res.rows;
} else {
message.warning({
content: `${res.msg}`,
duration: 3,
});
tableState.data = [];
}
tableState.loading = false;
});
@@ -475,7 +472,7 @@ function fnModalUploadImportUpload(file: File) {
if (res.code === RESULT_CODE_SUCCESS && res.data?.detail) {
uploadImportState.msg = res.data?.detail;
} else {
uploadImportState.msg = res.msg;
uploadImportState.msg = t('views.neUser.pcf.uploadFileErr');
}
})
.finally(() => {
@@ -570,7 +567,7 @@ onMounted(() => {
<a-card :bordered="false" :body-style="{ padding: '0px' }">
<!-- 插槽-卡片左侧侧 -->
<template #title>
<a-space :size="8" align="center">
<div class="button-container">
<a-button type="primary" @click.prevent="fnModalVisibleByEdit()">
<template #icon>
<PlusOutlined />
@@ -628,12 +625,12 @@ onMounted(() => {
{{ t('views.neUser.pcf.export') }}
</a-button>
</a-popconfirm>
</a-space>
</div>
</template>
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8" align="center">
<div class="button-container">
<a-tooltip>
<template #title>
{{
@@ -694,7 +691,7 @@ onMounted(() => {
</template>
</a-dropdown>
</a-tooltip>
</a-space>
</div>
</template>
<!-- 表格列表 -->

View File

@@ -454,6 +454,7 @@ const modalStateFrom = Form.useForm(
modalState.from,
reactive({
imsi: [{ required: true, message: 'IMSI' + t('common.unableNull') }],
msisdn: [{ required: true, message: 'MSISDN' + t('common.unableNull') }],
staticIp: [
{ required: true, message: 'static ip' + t('common.unableNull') },
],
@@ -473,7 +474,7 @@ const modalStateFrom = Form.useForm(
function fnModalOk() {
const from = Object.assign({}, toRaw(modalState.from));
let validateNames = ['imsi', 'staticIp'];
let validateNames = ['imsi', 'msisdn', 'staticIp'];
if (from.id === '') {
validateNames.push('smData');
@@ -573,7 +574,7 @@ function fnBatchModalOk() {
modalState.confirmLoading = true;
let ardArr = [0, 0, 0, 0, 0, 0, 0, 0];
let hplmnArr = [0, 0, 0, 0, 0, 0, 0, 0];
let odbArr = [0, 0, 0, 0, 0, 0, 0, 0];
let odbArr = [0, 0, 0, 0, 0, 0, 0, 0, 0];
from.ard.forEach((item: any) => {
ardArr[item] = 1;
@@ -962,7 +963,7 @@ onMounted(() => {
<a-card :bordered="false" :body-style="{ padding: '0px' }">
<!-- 插槽-卡片左侧侧 -->
<template #title>
<a-space :size="8" align="center">
<div class="button-container">
<a-button type="primary" @click.prevent="fnModalVisibleByEdit()">
<template #icon>
<PlusOutlined />
@@ -1030,12 +1031,12 @@ onMounted(() => {
{{ t('views.neUser.sub.export') }}
</a-button>
</a-popconfirm>
</a-space>
</div>
</template>
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8" align="center">
<div class="button-container">
<a-tooltip>
<template #title>{{ t('common.searchBarText') }}</template>
<a-switch
@@ -1088,7 +1089,7 @@ onMounted(() => {
</template>
</a-dropdown>
</a-tooltip>
</a-space>
</div>
</template>
<!-- 表格列表 -->

View File

@@ -12,7 +12,7 @@ import useNeInfoStore from '@/store/modules/neinfo';
import useI18n from '@/hooks/useI18n';
import { getGoldTitleByNE, goldData } from '@/api/perfManage/goldTarget';
import { parseDateToStr } from '@/utils/date-utils';
const neInfoStore = useNeInfoStore();
const { t, currentLocale } = useI18n();
/**网元参数 */
@@ -83,7 +83,7 @@ function fnTableSize({ key }: MenuInfo) {
/**查询参数 */
let queryParams: any = reactive({
/**卡片切换Flag */
cardFlag: 0, //0-显示统计图 1-显示统计表
cardFlag: 0, //0-显示统计图 1-显示统计表
/**告警设备类型 */
neType: '',
/**告警网元标识 */
@@ -195,6 +195,7 @@ function fnDesign() {
title: t('views.perfManage.goldTarget.time'),
dataIndex: 'timeGroup',
align: 'center',
fixed: 'right',
});
if (!queryRangePicker.value) {
queryRangePicker.value = ['', ''];
@@ -204,6 +205,7 @@ function fnDesign() {
const neType = queryParams.neType[0];
let goldXDate: any = [];
let goldYData: any = [];
let hideAll: any = {};
goldData(queryParams).then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
if (res.data.length > 0) {
@@ -214,6 +216,7 @@ function fnDesign() {
.filter(key => !['timeGroup', 'neName', 'startIndex'].includes(key))
.map(key => {
const title: any = findTitleByKey(key);
hideAll[title]=false;
return {
name: title,
data: res.data.map((item: any) => parseInt(item[key])),
@@ -246,20 +249,26 @@ function fnDesign() {
},
},
legend: {
right: 10,
itemWidth: 8,
// orient: 'vertical',
// left: 'left',
type: 'scroll',
orient: 'vertical', // vertical
right: 20,
//itemWidth: 20,
itemGap: 25,
textStyle: {
color: '#646A73',
},
icon: 'circle',
selected:hideAll,
},
grid: {
left: '10%',
right: '5%',
right: '30%',
bottom: '20%',
},
yAxis: [
{ type: 'value', axisLabel: { fontSize: 10 } },
{ type: 'value', splitNumber: 4, axisLabel: { fontSize: 10 } },
{
type: 'value',
position: 'right',
@@ -284,17 +293,24 @@ function fnDesign() {
onMounted(() => {
// 获取网元网元列表
useNeInfoStore()
neInfoStore
.fnNelist()
.then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
if (res.data.length > 0) {
// 过滤不可用的网元
neCascaderOptions.value = useNeInfoStore().getNeCascaderOtions.filter(
neCascaderOptions.value = neInfoStore.getNeCascaderOptions.filter(
(item: any) => {
return !['OMC'].includes(item.value);
}
);
if (neCascaderOptions.value.length === 0) {
message.warning({
content: t('common.noData'),
duration: 2,
});
return;
}
// 默认选择AMF
const item = neCascaderOptions.value.find(s => s.value === 'UPF');
if (item && item.children) {
@@ -462,7 +478,9 @@ onMounted(() => {
:data-source="tableState.data"
:size="tableState.size"
:pagination="tablePagination"
:scroll="{ x: true }"
:scroll="{ x: tableColumnsDnd.length * 200, y: 450 }"
@resizeColumn="(w:number, col:any) => (col.width = w)"
:show-expand-column="false"
>
</a-table>
</a-card>
@@ -487,7 +505,7 @@ onMounted(() => {
<div class="chart">
<ChartLine
:option="chartsOption.perfChart"
:dataZoom="true"
:dataZoom="false"
height="400px"
></ChartLine>
</div>

View File

@@ -0,0 +1,334 @@
<script setup lang="ts">
import { useRoute } from 'vue-router';
import { reactive, ref, onMounted, toRaw } from 'vue';
import { PageContainer } from 'antdv-pro-layout';
import { Modal } from 'ant-design-vue/lib';
import { SizeType } from 'ant-design-vue/lib/config-provider';
import { MenuInfo } from 'ant-design-vue/lib/menu/src/interface';
import { ColumnsType } from 'ant-design-vue/lib/table';
import { parseDateToStr } from '@/utils/date-utils';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { listgoldData } from '@/api/perfManage/goldTarget';
import useNeInfoStore from '@/store/modules/neinfo';
import useDictStore from '@/store/modules/dict';
import useI18n from '@/hooks/useI18n';
const { getDict } = useDictStore();
const { t } = useI18n();
const route = useRoute();
/**路由标题 */
let title = ref<string>((route.meta.title as string) ?? '标题');
/**记录开始结束时间 */
let queryRangePicker = ref<[string, string]>(['', '']);
/**查询参数 */
let queryParams = reactive({
/**网元类型 */
neType: '',
/**记录时间 */
beginTime: '',
endTime: '',
/**排序字段 */
sortField: 'value',
/**排序方式 */
sortOrder: 'asc',
/**当前页数 */
pageNum: 1,
/**每页条数 */
pageSize: 20,
});
/**查询参数重置 */
function fnQueryReset() {
queryParams = Object.assign(queryParams, {
neType: '',
beginTime: '',
endTime: '',
sortField: 'value',
sortOrder: 'asc',
pageNum: 1,
pageSize: 20,
});
queryRangePicker.value = ['', ''];
tablePagination.current = 1;
tablePagination.pageSize = 20;
fnGetList();
}
/**表格状态类型 */
type TabeStateType = {
/**加载等待 */
loading: boolean;
/**紧凑型 */
size: SizeType;
/**搜索栏 */
seached: boolean;
/**记录数据 */
data: object[];
};
/**表格状态 */
let tableState: TabeStateType = reactive({
loading: false,
size: 'middle',
seached: true,
data: [],
});
/**表格字段列 */
let tableColumns: ColumnsType = [
{
title: t('views.perfManage.goldTarget.type'),
dataIndex: 'neType',
align: 'center',
},
{
title: t('views.perfManage.goldTarget.enTitle'),
dataIndex: 'enTitle',
align: 'center',
},
{
title: t('views.perfManage.goldTarget.value'),
dataIndex: 'value',
key: 'value',
align: 'center',
sorter: true,
},
{
title: t('views.perfManage.goldTarget.startTime'),
dataIndex: 'startTime',
key: 'start_time',
align: 'center',
customRender(opt) {
if (!opt.value) return '';
return parseDateToStr(opt.value);
},
sorter: true,
},
{
title: t('views.perfManage.goldTarget.endTime'),
dataIndex: 'endTime',
align: 'center',
customRender(opt) {
if (!opt.value) return '';
return parseDateToStr(opt.value);
},
},
];
/**表格分页器参数 */
let tablePagination = reactive({
/**当前页数 */
current: 1,
/**每页条数 */
pageSize: 20,
/**默认的每页条数 */
defaultPageSize: 20,
/**指定每页可以显示多少条 */
pageSizeOptions: ['10', '20', '50', '100'],
/**只有一页时是否隐藏分页器 */
hideOnSinglePage: false,
/**是否可以快速跳转至某页 */
showQuickJumper: true,
/**是否可以改变 pageSize */
showSizeChanger: true,
/**数据总数 */
total: 0,
showTotal: (total: number) => t('common.tablePaginationTotal', { total }),
onChange: (page: number, pageSize: number) => {
tablePagination.current = page;
tablePagination.pageSize = pageSize;
queryParams.pageNum = page;
queryParams.pageSize = pageSize;
fnGetList();
},
});
/**表格紧凑型变更操作 */
function fnTableSize({ key }: MenuInfo) {
tableState.size = key as SizeType;
}
/**查询黄金指标列表, pageNum初始页数 */
function fnGetList(pageNum?: number) {
if (tableState.loading) return;
tableState.loading = true;
if (pageNum) {
queryParams.pageNum = pageNum;
}
if (!queryRangePicker.value) {
queryRangePicker.value = ['', ''];
}
queryParams.beginTime = queryRangePicker.value[0];
queryParams.endTime = queryRangePicker.value[1];
listgoldData(toRaw(queryParams)).then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
tablePagination.total = res.total;
tableState.data = res.rows;
}
tableState.loading = false;
});
}
/**表格分页、排序、筛选变化时触发操作, 排序方式,取值为 ascend descend */
function fnTableChange(pagination: any, filters: any, sorter: any, extra: any) {
console.log(sorter);
const { columnKey, order } = sorter;
if (order) {
queryParams.sortField = columnKey;
queryParams.sortOrder = order.replace('end', '');
} else {
queryParams.sortOrder = 'asc';
}
fnGetList(1);
}
onMounted(() => {
// 获取网元网元列表
useNeInfoStore().fnNelist();
// 获取列表数据
fnGetList();
});
</script>
<template>
<PageContainer>
<a-card
v-show="tableState.seached"
:bordered="false"
:body-style="{ marginBottom: '24px', paddingBottom: 0 }"
>
<!-- 表格搜索栏 -->
<a-form :model="queryParams" name="queryParams" layout="horizontal">
<a-row :gutter="16">
<a-col :lg="6" :md="12" :xs="24">
<a-form-item
:label="t('views.perfManage.goldTarget.type')"
name="neType"
>
<a-auto-complete
v-model:value="queryParams.neType"
:options="useNeInfoStore().getNeSelectOtions"
allow-clear
/>
</a-form-item>
</a-col>
<a-col :lg="8" :md="12" :xs="24">
<a-form-item
:label="t('views.perfManage.goldTarget.startTime')"
name="queryRangePicker"
>
<a-range-picker
v-model:value="queryRangePicker"
allow-clear
bordered
show-time
value-format="YYYY-MM-DD HH:mm:ss"
format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
></a-range-picker>
</a-form-item>
</a-col>
<a-col :lg="6" :md="12" :xs="24">
<a-form-item>
<a-space :size="8">
<a-button type="primary" @click.prevent="fnGetList(1)">
<template #icon><SearchOutlined /></template>
{{ t('common.search') }}
</a-button>
<a-button type="default" @click.prevent="fnQueryReset">
<template #icon><ClearOutlined /></template>
{{ t('common.reset') }}
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false" :body-style="{ padding: '0px' }">
<!-- 插槽-卡片左侧侧 -->
<template #title> </template>
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8" align="center">
<a-tooltip>
<template #title>{{ t('common.searchBarText') }}</template>
<a-switch
v-model:checked="tableState.seached"
:checked-children="t('common.switch.show')"
:un-checked-children="t('common.switch.hide')"
size="small"
/>
</a-tooltip>
<a-tooltip>
<template #title>{{ t('common.reloadText') }}</template>
<a-button type="text" @click.prevent="fnGetList()">
<template #icon><ReloadOutlined /></template>
</a-button>
</a-tooltip>
<a-tooltip>
<template #title>{{ t('common.sizeText') }}</template>
<a-dropdown trigger="click" placement="bottomRight">
<a-button type="text">
<template #icon><ColumnHeightOutlined /></template>
</a-button>
<template #overlay>
<a-menu
:selected-keys="[tableState.size as string]"
@click="fnTableSize"
>
<a-menu-item key="default">
{{ t('common.size.default') }}
</a-menu-item>
<a-menu-item key="middle">
{{ t('common.size.middle') }}
</a-menu-item>
<a-menu-item key="small">
{{ t('common.size.small') }}
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</a-tooltip>
</a-space>
</template>
<!-- 表格列表 -->
<a-table
class="table"
row-key="id"
:columns="tableColumns"
:loading="tableState.loading"
:data-source="tableState.data"
:size="tableState.size"
@change="fnTableChange"
:pagination="tablePagination"
:scroll="{ x: true }"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'alarmTitle'">
<a-tooltip>
<template #title>{{ record.operResult }}</template>
<div class="alarmTitleText">{{ record.alarmTitle }}</div>
</a-tooltip>
</template>
</template>
</a-table>
</a-card>
</PageContainer>
</template>
<style lang="less" scoped>
.table :deep(.ant-pagination) {
padding: 0 24px;
}
.alarmTitleText {
max-width: 300px;
cursor: pointer;
}
</style>

View File

@@ -19,6 +19,7 @@ import {
taskStop,
taskRun,
} from '@/api/perfManage/taskManage';
const neInfoStore = useNeInfoStore();
const { t, currentLocale } = useI18n();
const generateOptions = (start: any, end: any) => {
@@ -378,7 +379,7 @@ function fnSelectPer(s: any, option: any) {
/**性能测量数据集选择初始 */
function fnSelectPerformanceInit(neType: string) {
//console.logg(currentLocale.value); //当前语言
const performance = useNeInfoStore().perMeasurementList.filter(
const performance = neInfoStore.perMeasurementList.filter(
i => i.neType === neType
);
//进行分组选择
@@ -692,9 +693,9 @@ onMounted(() => {
Promise.allSettled([
// 获取网元网元列表
useNeInfoStore().fnNelist(),
neInfoStore.fnNelist(),
// 获取性能测量集列表
useNeInfoStore().fnNeTaskPerformance(),
neInfoStore.fnNeTaskPerformance(),
]).finally(() => {
// 获取列表数据
fnGetList();
@@ -719,7 +720,7 @@ onMounted(() => {
>
<a-auto-complete
v-model:value="queryParams.neType"
:options="useNeInfoStore().getNeSelectOtions"
:options="neInfoStore.getNeSelectOtions"
allow-clear
:placeholder="t('views.traceManage.task.neTypePlease')"
/>
@@ -887,7 +888,7 @@ onMounted(() => {
>
<a-cascader
:value="modalState.neType"
:options="useNeInfoStore().getNeCascaderOtions"
:options="neInfoStore.getNeCascaderOptions"
disabled
/>
</a-form-item>
@@ -1002,7 +1003,7 @@ onMounted(() => {
>
<a-cascader
v-model:value="modalState.neType"
:options="useNeInfoStore().getNeCascaderOtions"
:options="neInfoStore.getNeCascaderOptions"
@change="fnNeChange"
:allow-clear="false"
:placeholder="t('views.traceManage.task.neTypePlease')"

View File

@@ -552,7 +552,7 @@ onMounted(() => {
<a-card :bordered="false" :body-style="{ padding: '0px' }">
<!-- 插槽-卡片左侧侧 -->
<template #title>
<a-space :size="8" align="center">
<div class="button-container">
<a-button
type="primary"
@click.prevent="fnModalVisibleByEdit()"
@@ -588,12 +588,12 @@ onMounted(() => {
<template #icon><ExportOutlined /></template>
{{ t('common.export') }}
</a-button>
</a-space>
</div>
</template>
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8" align="center">
<div class="button-container">
<a-tooltip>
<template #title>{{ t('common.searchBarText') }}</template>
<a-switch
@@ -642,7 +642,7 @@ onMounted(() => {
</template>
</a-dropdown>
</a-tooltip>
</a-space>
</div>
</template>
<!-- 表格列表 -->

View File

@@ -561,7 +561,7 @@ onMounted(() => {
<a-card :bordered="false" :body-style="{ padding: '0px' }">
<!-- 插槽-卡片左侧侧 -->
<template #title>
<a-space :size="8" align="center">
<div class="button-container">
<a-button type="default" @click.prevent="fnClose()">
<template #icon><CloseOutlined /></template>
{{ t('common.close') }}
@@ -592,12 +592,12 @@ onMounted(() => {
<template #icon><ExportOutlined /></template>
{{ t('common.export') }}
</a-button>
</a-space>
</div>
</template>
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8" align="center">
<div class="button-container">
<a-tooltip>
<template #title>{{ t('common.searchBarText') }}</template>
<a-switch
@@ -646,7 +646,7 @@ onMounted(() => {
</template>
</a-dropdown>
</a-tooltip>
</a-space>
</div>
</template>
<!-- 表格列表 -->

View File

@@ -552,7 +552,7 @@ onMounted(() => {
<a-card :bordered="false" :body-style="{ padding: '0px' }">
<!-- 插槽-卡片左侧侧 -->
<template #title>
<a-space :size="8" align="center">
<div class="button-container">
<a-button
type="primary"
@click.prevent="fnModalVisibleByEdit()"
@@ -596,12 +596,12 @@ onMounted(() => {
<template #icon><ExportOutlined /></template>
{{ t('common.export') }}
</a-button>
</a-space>
</div>
</template>
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8" align="center">
<div class="button-container">
<a-tooltip>
<template #title>{{ t('common.searchBarText') }}</template>
<a-switch
@@ -650,7 +650,7 @@ onMounted(() => {
</template>
</a-dropdown>
</a-tooltip>
</a-space>
</div>
</template>
<!-- 表格列表 -->

View File

@@ -491,7 +491,7 @@ onMounted(() => {
<a-card :bordered="false" :body-style="{ padding: '0px' }">
<!-- 插槽-卡片左侧侧 -->
<template #title>
<a-space :size="8" align="center">
<div class="button-container">
<a-button
type="primary"
@click.prevent="fnModalVisibleByEdit()"
@@ -518,12 +518,12 @@ onMounted(() => {
<template #icon><ExportOutlined /></template>
{{ t('common.export') }}
</a-button>
</a-space>
</div>
</template>
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8" align="center">
<div class="button-container">
<a-tooltip>
<template #title>{{ t('common.searchBarText') }}</template>
<a-switch
@@ -572,7 +572,7 @@ onMounted(() => {
</template>
</a-dropdown>
</a-tooltip>
</a-space>
</div>
</template>
<!-- 表格列表 -->

View File

@@ -394,7 +394,7 @@ onMounted(() => {
<a-card :bordered="false" :body-style="{ padding: '0px' }">
<!-- 插槽-卡片左侧侧 -->
<template #title>
<a-space :size="8" align="center">
<div class="button-container">
<a-button type="default" @click.prevent="fnClose()">
<template #icon><CloseOutlined /></template>
{{ t('common.cancel') }}
@@ -417,12 +417,12 @@ onMounted(() => {
<template #icon><UsergroupDeleteOutlined /></template>
{{ t('views.system.role.batchCancel') }}
</a-button>
</a-space>
</div>
</template>
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8" align="center">
<div class="button-container">
<a-tooltip>
<template #title>{{ t('common.searchBarText') }}</template>
<a-switch
@@ -471,7 +471,7 @@ onMounted(() => {
</template>
</a-dropdown>
</a-tooltip>
</a-space>
</div>
</template>
<!-- 表格列表 -->
@@ -498,7 +498,9 @@ onMounted(() => {
<template v-if="column.key === 'userId'">
<a-space :size="8" align="center">
<a-tooltip>
<template #title>{{t('views.system.role.cancelGive')}}</template>
<template #title>{{
t('views.system.role.cancelGive')
}}</template>
<a-button
type="link"
@click.prevent="fnRecordDelete(record.userId)"

View File

@@ -815,7 +815,7 @@ onMounted(() => {
<a-card :bordered="false" :body-style="{ padding: '0px' }">
<!-- 插槽-卡片左侧侧 -->
<template #title>
<a-space :size="8" align="center">
<div class="button-container">
<a-button
type="primary"
@click.prevent="fnModalVisibleByEdit()"
@@ -842,7 +842,7 @@ onMounted(() => {
<template #icon><ExportOutlined /></template>
{{ t('common.export') }}
</a-button>
</a-space>
</div>
</template>
<!-- 插槽-卡片右侧 -->
@@ -1236,7 +1236,10 @@ onMounted(() => {
</a-form-item>
</a-col>
<a-col :lg="12" :md="12" :xs="24">
<a-form-item :label="t('views.system.role.createTime')" name="createTime">
<a-form-item
:label="t('views.system.role.createTime')"
name="createTime"
>
<span v-if="+modalState.from.createTime > 0">
{{ parseDateToStr(+modalState.from.createTime) }}
</span>
@@ -1245,12 +1248,18 @@ onMounted(() => {
</a-row>
<a-row :gutter="16">
<a-col :lg="12" :md="12" :xs="24">
<a-form-item :label="t('views.system.role.roleSort')" name="roleSort">
<a-form-item
:label="t('views.system.role.roleSort')"
name="roleSort"
>
{{ modalState.from.roleSort }}
</a-form-item>
</a-col>
<a-col :lg="12" :md="12" :xs="24">
<a-form-item :label="t('views.system.role.roleStatus')" name="status">
<a-form-item
:label="t('views.system.role.roleStatus')"
name="status"
>
<DictTag
:options="dict.sysNormalDisable"
:value="modalState.from.status"
@@ -1260,17 +1269,20 @@ onMounted(() => {
</a-row>
<a-row :gutter="16">
<a-col :lg="12" :md="12" :xs="24">
<a-form-item :label="t('views.system.role.roleName')" name="roleName">
<a-form-item
:label="t('views.system.role.roleName')"
name="roleName"
>
{{ modalState.from.roleName }}
</a-form-item>
</a-col>
<a-col :lg="12" :md="12" :xs="24">
<a-form-item :label="t('views.system.role.roleKey')" name="roleKey">
<a-form-item :label="t('views.system.role.roleKey')" name="roleKey">
{{ modalState.from.roleKey }}
</a-form-item>
</a-col>
</a-row>
<a-form-item :label="t('views.system.role.roleMark')" name="remark">
<a-form-item :label="t('views.system.role.roleMark')" name="remark">
{{ modalState.from.remark }}
</a-form-item>
@@ -1293,21 +1305,21 @@ onMounted(() => {
:checked="modalState.deptTree.expandedKeys.length > 0"
@change="(e:any) => fnModalExpandedKeys(e.target.checked, 'dept')"
>
{{t('views.system.role.openSwitch')}}
{{ t('views.system.role.openSwitch') }}
</a-checkbox>
<a-checkbox
id="dept_2"
:checked="modalState.from.deptIds.length > 0"
@change="(e:any) => fnModalCheckedKeys(e.target.checked, 'dept')"
>
{{t('views.system.role.selAllSwitch')}}
{{ t('views.system.role.selAllSwitch') }}
</a-checkbox>
<a-checkbox
id="dept_1"
:checked="modalState.from.deptCheckStrictly === '1'"
@change="(e:any) => fnModalCheckStrictly(e.target.checked, 'dept')"
>
{{t('views.system.role.relationSwitch')}}
{{ t('views.system.role.relationSwitch') }}
</a-checkbox>
</a-space>
<a-tree

View File

@@ -4,8 +4,7 @@ import { onMounted, reactive } from 'vue';
import useAppStore from '@/store/modules/app';
import useI18n from '@/hooks/useI18n';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { transferStaticFile } from '@/api/index';
import { uploadFileChunk } from '@/api/tool/file';
import { transferStaticFile, uploadFileChunk } from '@/api/tool/file';
import { FileType } from 'ant-design-vue/lib/upload/interface';
import { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
import { useRouter } from 'vue-router';
@@ -124,6 +123,7 @@ onMounted(() => {
v-model:value="state.language"
style="width: 100px"
size="small"
v-perms:has="['system:setting:i18n']"
>
<a-select-option
v-for="opt in optionsLocale"
@@ -169,6 +169,7 @@ onMounted(() => {
v-model:value="state.language"
style="width: 100px"
size="small"
v-perms:has="['system:setting:i18n']"
>
<a-select-option
v-for="opt in optionsLocale"

View File

@@ -7,10 +7,9 @@ import { onMounted, reactive, watch, computed } from 'vue';
import useAppStore from '@/store/modules/app';
import useI18n from '@/hooks/useI18n';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { uploadFile } from '@/api/tool/file';
import { transferStaticFile, uploadFile } from '@/api/tool/file';
import { changeValue } from '@/api/system/config';
import { sessionGet } from '@/utils/cache-session-utils';
import { transferStaticFile } from '@/api';
import { parseUrlPath } from '@/plugins/file-static-url';
const appStore = useAppStore();
const { t, currentLocale, optionsLocale } = useI18n();
@@ -219,7 +218,7 @@ onMounted(() => {
</div>
</div>
</a-form-item>
<a-form-item>
<a-form-item v-perms:has="['system:setting:i18n']">
<a-select v-model:value="state.language" style="width: 100px">
<a-select-option
v-for="opt in optionsLocale"

View File

@@ -38,10 +38,12 @@ const { t } = useI18n();
{{ t('views.system.setting.sysOfficialUrl') }}
</a-divider>
<ChangeOfficialUrl></ChangeOfficialUrl>
<a-divider orientation="left">
{{ t('views.system.setting.i18n') }}
</a-divider>
<ChangeI18n></ChangeI18n>
<div v-perms:has="['system:setting:i18n']">
<a-divider orientation="left">
{{ t('views.system.setting.i18n') }}
</a-divider>
<ChangeI18n></ChangeI18n>
</div>
</a-card>
</PageContainer>
</template>

View File

@@ -889,7 +889,7 @@ onMounted(() => {
<a-card :bordered="false" :body-style="{ padding: '0px' }">
<!-- 插槽-卡片左侧侧 -->
<template #title>
<a-space :size="8" align="center">
<div class="button-container">
<a-button
type="primary"
@click.prevent="fnModalVisibleByEdit()"
@@ -924,12 +924,12 @@ onMounted(() => {
<template #icon><ExportOutlined /></template>
{{ t('common.export') }}
</a-button>
</a-space>
</div>
</template>
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8" align="center">
<div class="button-container">
<a-tooltip>
<template #title>{{ t('common.searchBarText') }}</template>
<a-switch
@@ -978,7 +978,7 @@ onMounted(() => {
</template>
</a-dropdown>
</a-tooltip>
</a-space>
</div>
</template>
<!-- 表格列表 -->

View File

@@ -15,6 +15,7 @@ import {
tcpdumpPcapDownload,
} from '@/api/traceManage/pcap';
import { ref } from 'vue';
const neInfoStore = useNeInfoStore();
const { t } = useI18n();
/**对话框对象信息状态类型 */
@@ -338,7 +339,7 @@ onUnmounted(() => {
>
<a-cascader
v-model:value="modalState.neType"
:options="useNeInfoStore().getNeCascaderOtions"
:options="neInfoStore.getNeCascaderOptions"
@change="fnNeChange"
:allow-clear="false"
:placeholder="t('views.traceManage.pcap.neTypePlease')"

View File

@@ -19,6 +19,7 @@ import {
} from '@/api/traceManage/task';
import useDictStore from '@/store/modules/dict';
import { regExpIPv4, regExpPort } from '@/utils/regular-utils';
const neInfoStore = useNeInfoStore();
const { getDict } = useDictStore();
const { t } = useI18n();
@@ -382,7 +383,7 @@ function fnSelectInterface(s: any, _: any) {
/**信令接口选择初始 */
function fnSelectInterfaceInit(neType: string) {
const interfaces = useNeInfoStore().traceInterfaceList;
const interfaces = neInfoStore.traceInterfaceList;
modalState.neTypeInterface = interfaces
.filter(i => i.neType === neType)
.map(i => {
@@ -535,9 +536,9 @@ onMounted(() => {
});
Promise.allSettled([
// 获取网元网元列表
useNeInfoStore().fnNelist(),
neInfoStore.fnNelist(),
// 获取跟踪接口列表
useNeInfoStore().fnNeTraceInterface(),
neInfoStore.fnNeTraceInterface(),
]).finally(() => {
// 获取列表数据
fnGetList();
@@ -562,7 +563,7 @@ onMounted(() => {
>
<a-auto-complete
v-model:value="queryParams.neType"
:options="useNeInfoStore().getNeSelectOtions"
:options="neInfoStore.getNeSelectOtions"
allow-clear
:placeholder="t('views.traceManage.task.neTypePlease')"
/>
@@ -748,7 +749,7 @@ onMounted(() => {
>
<a-cascader
:value="modalState.neType"
:options="useNeInfoStore().getNeCascaderOtions"
:options="neInfoStore.getNeCascaderOptions"
disabled
/>
</a-form-item>
@@ -866,7 +867,7 @@ onMounted(() => {
>
<a-cascader
v-model:value="modalState.neType"
:options="useNeInfoStore().getNeCascaderOtions"
:options="neInfoStore.getNeCascaderOptions"
@change="fnNeChange"
:allow-clear="false"
:placeholder="t('views.traceManage.task.neTypePlease')"

View File

@@ -21,7 +21,7 @@ export default defineConfig(({ mode }) => {
// https://cn.vitejs.dev/config/#server-proxy
[env.VITE_API_BASE_URL]: {
// target: 'http://192.168.2.166:3030',
target: 'http://192.168.2.114:3040',
target: 'http://192.168.5.58:3040',
changeOrigin: true,
rewrite: p => p.replace(env.VITE_API_BASE_URL, ''),
},