Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33558d3f00 | ||
|
|
0b15ff1476 | ||
|
|
5061f16fe7 | ||
|
|
8ced920aec | ||
|
|
22201bbb2d | ||
|
|
4ae74103f1 | ||
|
|
1c4c1a796d | ||
|
|
a658852772 | ||
|
|
aa842e246b | ||
|
|
0d13400229 | ||
|
|
7491ccc00b | ||
|
|
fc64460870 | ||
|
|
323da55c9d | ||
|
|
52528343bf | ||
|
|
26cf7fa560 | ||
|
|
5ea56e779a | ||
|
|
174a7afc47 | ||
|
|
b53426550d | ||
|
|
f4e61a0ebc | ||
|
|
b5d7ce8685 | ||
|
|
19d563af75 | ||
|
|
97e5533d6e | ||
|
|
48c6434e65 | ||
|
|
e1c4229e58 | ||
|
|
b1c96bb123 | ||
|
|
c6e21c6c38 | ||
|
|
b1d0771d56 | ||
|
|
22b0b7e204 | ||
|
|
93f31eded4 | ||
|
|
1eec47f410 | ||
|
|
d9bc5b9f02 | ||
|
|
3116e51338 | ||
|
|
c4273c2074 | ||
|
|
3026ac1dd8 | ||
|
|
c01380da6b | ||
|
|
98e4d39cdf | ||
|
|
1c025c2cc1 | ||
|
|
20a12eba56 | ||
|
|
904488f59a | ||
|
|
a2f93f7862 | ||
|
|
d249d14c49 | ||
|
|
58d0e6e884 | ||
|
|
510e3e1006 | ||
|
|
02b12d76a7 | ||
|
|
5839aa3cb1 | ||
|
|
83a289492d | ||
|
|
05d59ec526 | ||
|
|
c22d7604cf | ||
|
|
6f9639d3d4 | ||
|
|
5932662e7c | ||
|
|
cdbe9a1e42 | ||
|
|
2d09be6341 | ||
|
|
a032236d7d | ||
|
|
1dcd8a6e25 | ||
|
|
e075779b91 | ||
|
|
e5ce2ebb02 | ||
|
|
3da786f6b9 | ||
|
|
d4e603be63 | ||
|
|
a7024df325 | ||
|
|
b525b92163 | ||
|
|
457bf02452 | ||
|
|
011c74d8d7 | ||
|
|
06c72a914e | ||
|
|
94b0f46195 | ||
|
|
55216fe6cf | ||
|
|
3eafac4ad3 | ||
|
|
50892af7a8 | ||
|
|
93e455f645 | ||
|
|
34c57803a1 | ||
|
|
708eb6535e | ||
|
|
e66e645866 | ||
|
|
d31bfe02ee | ||
|
|
be5f4be75f | ||
|
|
50bf0c27c0 | ||
|
|
4f47eebb1e | ||
|
|
9286efa59b | ||
|
|
1e2154c2ae | ||
|
|
af10003b25 | ||
|
|
4aca6823d3 | ||
|
|
7376b20352 | ||
|
|
6fcc6eb5e1 | ||
|
|
52e22cd3a9 | ||
|
|
a86e9aa219 | ||
|
|
1b7d5fc85c | ||
|
|
2fb7a74426 | ||
|
|
c5c7c2c3e0 | ||
|
|
7331624b9b | ||
|
|
cc74e9f84d | ||
|
|
b0d3cec1fa | ||
|
|
3a0d47b596 | ||
|
|
1932795955 | ||
|
|
8d8a710a8f | ||
|
|
a0b0f76e23 | ||
|
|
97bf5994c8 | ||
|
|
667d3b61aa | ||
|
|
28334b2acc | ||
|
|
efec69eb28 | ||
|
|
ccfee93a91 | ||
|
|
58f2fee781 | ||
|
|
df8f75e16f | ||
|
|
f0e299b704 | ||
|
|
77fb580aea | ||
|
|
b72ff26e4f | ||
|
|
4bd46f64a4 | ||
|
|
dc0379a581 | ||
|
|
d5f744bffc | ||
|
|
30a8fc2dc8 | ||
|
|
0e38f24f85 | ||
|
|
96e728a1eb | ||
|
|
665946c4c2 | ||
|
|
05d4b0cd3e | ||
|
|
95394a4b5e | ||
|
|
78ebb6a0fc | ||
|
|
221c39995f | ||
|
|
c184357b73 | ||
|
|
995da7162f | ||
|
|
1d457fff46 | ||
|
|
d12b34087e | ||
|
|
bce9a8e923 | ||
|
|
fa38b9502f | ||
|
|
50d3cd72de | ||
|
|
1db9d09a79 | ||
|
|
720d7d3b99 | ||
|
|
e5a6987eae | ||
|
|
080b84ed6f | ||
|
|
64f812cc7f | ||
|
|
a4d7c60118 | ||
|
|
52a24871c3 | ||
|
|
df6bfd0414 | ||
|
|
7099bd7349 |
No files matched your search
@@ -1,5 +1,52 @@
|
||||
# 版本发布日志
|
||||
|
||||
## 2.2510.4-20251024
|
||||
|
||||
- 新增 同步语音仪表盘:修改useNeInfoStore导入地址、补充接口导入、修改ims请求参数、修改响应码
|
||||
- 新增 基站状态补充randId列
|
||||
|
||||
## 2.2510.3-20251018
|
||||
|
||||
- 新增 备份网元日志文件数据查看
|
||||
- 修复 更新根网管节点处理逻辑,支持无OMC情况
|
||||
- 新增 网元配置选择传入neId查询相应版本配置数据
|
||||
- 修复 网元配置备份修改表单校验规则,添加备注字段必填项
|
||||
|
||||
## 2.2510.2-20251011
|
||||
|
||||
- 新增 UDM-auth数据导出按钮权限定义
|
||||
- 新增 SMSC-CDR添加结果原因说明
|
||||
- 优化 移除CDR/UE/网元版本/授权列表显示ID列
|
||||
- 修复 MML回车undefined问题,关闭搜索匹配
|
||||
|
||||
## 2.2509.4-20250926
|
||||
|
||||
- 优化 UDM数据显示创建时间列
|
||||
- 优化 中英文补充
|
||||
- 新增 添加系统备份功能,包括导入导出OMC的API和界面支持
|
||||
- 新增 日志备份文件查看kpi文件记录
|
||||
- 优化 根据搜索条件导出,去除最大记录限制
|
||||
- 新增 添加活动告警自动刷新功能并优化代码结构
|
||||
- 修复 奇安信浏览器时区格式错误
|
||||
- 新增 添加网元配置快速PLMN修改框
|
||||
- 新增 ue和ne模块权限按钮
|
||||
- 新增 监控模块按钮权限
|
||||
- 修复 UDM数据导出提示信息,导出总数
|
||||
- 新增 网元许可快速上传功能
|
||||
- 新增 网元信息快速OAM功能
|
||||
|
||||
## 2.2508.4-20250829
|
||||
|
||||
- 新增 网元授权显示用户数/基站数
|
||||
- 优化 网元当前版本显示是否有包存在
|
||||
- 优化 cdr/ue导出操作后锁定按钮事件防重发
|
||||
- 优化 网元可选静态可选项添加PGWC
|
||||
- 优化 参数配置添加校验过滤长度~和-定义范围
|
||||
- 修复 UPF流量统计数据同时获取刷新
|
||||
- 修复 UPF流量统计字节数据格式化显示不一致问题
|
||||
- 新增 指标Title管理页面功能
|
||||
- 新增 增加多个导出操作的超时时间至180秒
|
||||
|
||||
## 2.2508.2-20250815
|
||||
|
||||
- 优化 给config.js加随机数避免缓存
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
const protocol = window.location.protocol
|
||||
let wsprotocol = "ws:"
|
||||
const hostname = window.location.hostname
|
||||
let host = `${hostname}:33030`;
|
||||
let host = `${hostname}:33080`;
|
||||
if (protocol === 'https:') {
|
||||
host = `${hostname}:33443`;
|
||||
wsprotocol = "wss:"
|
||||
@@ -25,4 +25,4 @@
|
||||
sessionStorage.setItem('baseUrl', `${protocol}//${host}`);
|
||||
// websocket Address
|
||||
sessionStorage.setItem('wsUrl', `${wsprotocol}//${host}`);
|
||||
})();
|
||||
})();
|
||||
@@ -1,2 +1,2 @@
|
||||
#imsi,msisdn,sess_rules,pcc_rules,hdr_enrich,rfsp,sar,qos_audio,qos_video,online,offline
|
||||
460996650000580,62357000580,internet|ims_sig,internet|ims_sig,dnn,1,def_sar,qos_audio,qos_video,0,0
|
||||
imsi,msisdn,sess_rules,pcc_rules,hdr_enrich,rfsp,sar,qos_audio,qos_video
|
||||
001012082101039,1234,internet|ims_sig,internet|ims_sig,321321,255,321312,32131,32131
|
||||
@@ -1,2 +1,2 @@
|
||||
460996650000580,1234567890ABCDEF1234567890ABCDEF,0,8000
|
||||
460996650000581,1234567890ABCDEF1234567890ABCDEF,0,8000
|
||||
001011100001157,1234567890ABCDEF1234567890ABCDEF,0,8000,11111111111111111111111111111111
|
||||
001011100001158,1234567890ABCDEF1234567890ABCDEF,0,8000,11111111111111111111111111111111
|
||||
@@ -1,2 +1,2 @@
|
||||
460996650000580,62357000580,def_ambr,def_nssai,def_arfb,def_sar,0,3,def_snssai,1-000001&content&ims,1,64,24,65,def_eps,1,010200000000,-
|
||||
460996650000581,62357000581,def_ambr,def_nssai,def_arfb,def_sar,0,3,def_snssai,1-000001&content&ims,1,64,24,65,def_eps,1,010200000000,-
|
||||
001011100001157,62357000583,def_ambr,def_nssai,def_arfb,def_sar,0,3,def_snssai,1-000001&internet&ims,1,64,24,65,def_eps,1,010200000000,-
|
||||
001011100001158,62357000585,def_ambr,def_nssai,def_arfb,def_sar,0,3,def_snssai,1-000001&internet&ims,1,64,24,65,def_eps,1,010200000000,-
|
||||
@@ -6,10 +6,11 @@ import { request } from '@/plugins/http-fetch';
|
||||
* @param query 查询参数
|
||||
* @returns object
|
||||
*/
|
||||
export function getAllNeConfig(neType: string) {
|
||||
export function getAllNeConfig(neType: string, neId: string) {
|
||||
return request({
|
||||
url: `/ne/config/list/${neType}`,
|
||||
method: 'GET',
|
||||
params: { neId },
|
||||
timeout: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -36,3 +36,33 @@ export function updateBackupFTP(data: Record<string, any>) {
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 备份文件-导出OMC
|
||||
* @returns object
|
||||
*/
|
||||
export function exportBackupOMC() {
|
||||
return request({
|
||||
url: '/neData/backup/export-omc',
|
||||
method: 'POST',
|
||||
responseType: 'blob',
|
||||
timeout: 180_000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 备份文件-导入OMC
|
||||
* @param filePath 备份文件上传返回的/upload 路径
|
||||
* @returns object
|
||||
*/
|
||||
export function importBackupOMC(filePath: string) {
|
||||
return request({
|
||||
url: '/neData/backup/import-omc',
|
||||
method: 'POST',
|
||||
data: {
|
||||
neType: 'OMC',
|
||||
path: filePath,
|
||||
},
|
||||
timeout: 180_000,
|
||||
});
|
||||
}
|
||||
@@ -140,3 +140,17 @@ export function exportUDMAuth(data: Record<string, any>) {
|
||||
timeout: 180_000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* UDM鉴权用户导出DecAuth
|
||||
* @param neId 网元ID
|
||||
* @returns bolb
|
||||
*/
|
||||
export function exportUDMDecAuth(neId: string) {
|
||||
return request({
|
||||
url: `/neData/udm/auth/export-dec?neId=${neId}`,
|
||||
method: 'GET',
|
||||
responseType: 'blob',
|
||||
timeout: 180_000,
|
||||
});
|
||||
}
|
||||
@@ -33,3 +33,28 @@ export async function getKPITitle(neType: string) {
|
||||
// 解析数据//
|
||||
return result;
|
||||
}
|
||||
//忙时呼叫
|
||||
export async function getbusyhour(query: Record<string, any>) {
|
||||
return request({
|
||||
url: '/neData/ims/kpi/busy-hour',
|
||||
method: 'GET',
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
//MOS指标
|
||||
export async function getMosHour(query: Record<string, any>) {
|
||||
return request({
|
||||
url: '/neData/ims/cdr/mos-hour',
|
||||
method: 'GET',
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
|
||||
//CCT指标
|
||||
export async function getCctHour(query: Record<string, any>) {
|
||||
return request({
|
||||
url: '/neData/ims/cdr/cct-hour',
|
||||
method: 'GET',
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
@@ -22,6 +22,12 @@ export const NE_TYPE_LIST = [
|
||||
'CHF',
|
||||
'HLR',
|
||||
'SGWC',
|
||||
'PGWC',
|
||||
'IP-SM-GW',
|
||||
'MMTel-AS',
|
||||
'I-CSCF',
|
||||
'P-CSCF',
|
||||
'S-CSCF',
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
+46
-10
@@ -485,7 +485,7 @@ export default {
|
||||
resultOk: "Success",
|
||||
resultFail: "Fail",
|
||||
delTip: "Confirm deletion of the data item numbered [{msg}]?",
|
||||
exportTip: "Do you confirm to export the current query conditions of the CDR data? (Maximum 10,000 items can be exported.)",
|
||||
exportTip: "Do you confirm to export the current query conditions of the CDR data?",
|
||||
chargingID: 'Charging ID',
|
||||
smfSubscriptionIDData: 'Subscription ID Data',
|
||||
smfSubscriptionIDType: 'Subscription ID Type',
|
||||
@@ -517,7 +517,7 @@ export default {
|
||||
result: "Result",
|
||||
resultOk: "Successes",
|
||||
delTip: "Confirm deletion of the data item numbered [{msg}]?",
|
||||
exportTip: "Do you confirm to export the event data of the current query condition? (Maximum 10,000 items can be exported.)",
|
||||
exportTip: "Do you confirm to export the event data of the current query condition?",
|
||||
},
|
||||
},
|
||||
ne: {
|
||||
@@ -539,6 +539,8 @@ export default {
|
||||
port: 'Port',
|
||||
portTip: "Network element port default:33030",
|
||||
capability: 'Capability',
|
||||
ueNumber: 'UE Number',
|
||||
nbNumber: 'Radio Number',
|
||||
serialNum: 'Serial Number',
|
||||
expiryDate: 'Expiry Date',
|
||||
normalcy: 'Normal',
|
||||
@@ -588,6 +590,22 @@ export default {
|
||||
kpiTimerPlease: 'Please enter the reporting period (in seconds)',
|
||||
omcIP: 'OMC IP',
|
||||
},
|
||||
quickOam: {
|
||||
title: 'Quick OAM Configuration',
|
||||
selectNe: 'Select NE',
|
||||
omcIP: 'OMC IP',
|
||||
oamPort: 'OAM Port',
|
||||
progress:'Progress',
|
||||
processing:'Progressing',
|
||||
result:'Result',
|
||||
success:'Success',
|
||||
default:'Default',
|
||||
allsuccess:'All NE have been configured successfully!',
|
||||
},
|
||||
quickUpload: {
|
||||
title: 'Quick License Upload',
|
||||
selectNe: 'Select NE',
|
||||
},
|
||||
backConf: {
|
||||
export: 'Config Export',
|
||||
import: 'Config Import',
|
||||
@@ -699,6 +717,10 @@ export default {
|
||||
uploadFile: "Upload License",
|
||||
uploadChangeOk: 'Network Element renewed license successfully and is being calibrated in the background!',
|
||||
uploadChangeFail: "Some network elements failed to update the license, please check whether the service terminal environment is available!",
|
||||
quickUpload: {
|
||||
title: 'Quick License Upload',
|
||||
selectNe: 'Select NE',
|
||||
},
|
||||
},
|
||||
neConfig: {
|
||||
treeTitle: "Navigation Configuration",
|
||||
@@ -824,7 +846,7 @@ export default {
|
||||
passwordPlease: "Please enter your password correctly",
|
||||
addTitle: 'Add VOIP subscriber',
|
||||
delTip: 'Confirm that you want to delete the information of VOIP user as [{num}]?',
|
||||
exportTip: "Confirm exporting xlsx table files based on search criteria?",
|
||||
exportTip: "Confirm exporting all VOIP user data based on the current search criteria?",
|
||||
},
|
||||
udmVolteIMS: {
|
||||
startMSISDN: 'Starting MSISDN',
|
||||
@@ -833,7 +855,7 @@ export default {
|
||||
vniTip: 'Example: ims.mnc000.mcc000.3gppnetwork.org',
|
||||
vniPlease: 'Please enter VNI correctly',
|
||||
delTip: 'Are you sure you want to delete the information of IMS signing as [{num}]?',
|
||||
exportTip: "Confirm exporting xlsx table files based on search criteria?",
|
||||
exportTip: "Confirm exporting all VoLTE user data based on the current search criteria?",
|
||||
},
|
||||
pcfSub: {
|
||||
exportTip: 'Confirm exporting all user policy control information data?',
|
||||
@@ -853,6 +875,7 @@ export default {
|
||||
list: "List",
|
||||
topology: "Topology",
|
||||
nbName: "RAN Node Name",
|
||||
nbId: "RAN Node ID",
|
||||
ueNum: "UE Number",
|
||||
topologyTitle: "Radio State Graph",
|
||||
name: "Name",
|
||||
@@ -884,7 +907,7 @@ export default {
|
||||
neTypePlease: 'Query network element Object',
|
||||
neType: 'UDM Object',
|
||||
export: 'Export',
|
||||
exportConfirm: 'Are you sure to export all authentication user data?',
|
||||
exportConfirm: 'Confirm exporting all Authentication user data based on the current search criteria?',
|
||||
checkExport : 'Check Export',
|
||||
checkExportConfirm: 'Confirm exporting the checked authenticated user data?',
|
||||
import: 'Import',
|
||||
@@ -913,7 +936,7 @@ export default {
|
||||
subInfo:' Subscription Info',
|
||||
neType: 'UDM Object',
|
||||
export: 'Export',
|
||||
exportConfirm: 'Are you sure to export all signed user data?',
|
||||
exportConfirm: 'Confirm exporting all Subscribers user data based on the current search criteria?',
|
||||
checkExport : 'Check Export',
|
||||
checkExportConfirm: 'Are you sure to export the data of the checked subscribers?',
|
||||
import: 'Import',
|
||||
@@ -1339,10 +1362,19 @@ export default {
|
||||
deleteTipErr: "Failed to delete file",
|
||||
sysloginLog:'System Login Log',
|
||||
sysOperateLog:'System Operation Log',
|
||||
cdrIMS:'CDR Voice',
|
||||
cdrSMF:'CDR Data',
|
||||
cdrSMSC:'CDR SMS',
|
||||
cdrSGWC:'CDR Roaming Data',
|
||||
neLog:'NE Log',
|
||||
cdrIMS:'CDR IMS Voice',
|
||||
cdrSMF:'CDR SMF Data',
|
||||
cdrSMSC:'CDR SMSC SMS',
|
||||
cdrSGWC:'CDR SGWC Roaming Data',
|
||||
kpiIMS:'KPI IMS',
|
||||
kpiAMF:'KPI AMF',
|
||||
kpiUDM:'KPI UDM',
|
||||
kpiSMF:'KPI SMF',
|
||||
kpiPCF:'KPI PCF',
|
||||
kpiUPF:'KPI UPF',
|
||||
kpiMME:'KPI MME',
|
||||
kpiSMSC:'KPI SMSC',
|
||||
}
|
||||
},
|
||||
monitor: {
|
||||
@@ -1887,6 +1919,10 @@ export default {
|
||||
home: 'Home Page',
|
||||
homeTip:'Do you want to submit the current interface as the system interface?',
|
||||
homeSet:'Home Page Settings',
|
||||
backup: 'System Backup',
|
||||
backupInstruction: 'System backup will back up the net element information records and configuration files running on the current system, and can restore the system to the previous state!',
|
||||
backupExportTip: 'Confirm to export system backup?',
|
||||
backupImportTip: 'Confirm to import system backup?',
|
||||
},
|
||||
role:{
|
||||
allScopeOptions:'All data permissions',
|
||||
|
||||
+46
-10
@@ -485,7 +485,7 @@ export default {
|
||||
resultOk: "成功",
|
||||
resultFail: "失败",
|
||||
delTip: "确认删除编号为【{msg}】的数据项?",
|
||||
exportTip: "确认导出当前查询条件的话单数据吗?(导出最大支持一万条)",
|
||||
exportTip: "确认导出当前查询条件的话单数据吗?",
|
||||
chargingID: '计费ID',
|
||||
smfSubscriptionIDData: '订阅 ID 数据',
|
||||
smfSubscriptionIDType: '订阅 ID 类型',
|
||||
@@ -517,7 +517,7 @@ export default {
|
||||
result: "结果",
|
||||
resultOk: "成功",
|
||||
delTip: "确认删除编号为【{msg}】的数据项?",
|
||||
exportTip: "确认导出当前查询条件的事件数据吗?(导出最大支持一万条)",
|
||||
exportTip: "确认导出当前查询条件的事件数据吗?",
|
||||
},
|
||||
},
|
||||
ne: {
|
||||
@@ -539,6 +539,8 @@ export default {
|
||||
port: '服务端口',
|
||||
portTip: "网元服务端口,默认:33030",
|
||||
capability: '容量',
|
||||
ueNumber: '用户数',
|
||||
nbNumber: '基站数',
|
||||
serialNum: '序列号',
|
||||
expiryDate: '许可证到期日期',
|
||||
normalcy: '正常',
|
||||
@@ -588,6 +590,22 @@ export default {
|
||||
kpiTimerPlease: '请输入上报周期(单位秒)',
|
||||
omcIP: 'OMC IP',
|
||||
},
|
||||
quickOam: {
|
||||
title: '快速OAM配置',
|
||||
selectNe: '选择网元',
|
||||
omcIP: 'OMC IP地址',
|
||||
oamPort: 'OAM端口',
|
||||
progress:'配置进度',
|
||||
processing:'正在处理',
|
||||
result:'操作结果',
|
||||
success:'成功',
|
||||
default:'失败',
|
||||
allsuccess:'所有网元配置成功!',
|
||||
},
|
||||
quickUpload: {
|
||||
title: '快速许可证上传',
|
||||
selectNe: '选择网元',
|
||||
},
|
||||
backConf: {
|
||||
export: '配置导出',
|
||||
import: '配置导入',
|
||||
@@ -699,6 +717,10 @@ export default {
|
||||
uploadFile: "上传许可证",
|
||||
uploadChangeOk: '网元更新许可证成功,正在后台校验!',
|
||||
uploadChangeFail: "部分网元更新许可证失败,请检查服务终端环境是否可用!",
|
||||
quickUpload: {
|
||||
title: '快速许可证上传',
|
||||
selectNe: '选择网元',
|
||||
},
|
||||
},
|
||||
neConfig: {
|
||||
treeTitle: "配置导航",
|
||||
@@ -824,7 +846,7 @@ export default {
|
||||
passwordPlease: "请正确输入密码",
|
||||
addTitle: '新增VOIP用户',
|
||||
delTip: '确认要删除VOIP用户为【{num}】的信息吗?',
|
||||
exportTip: "确认根据搜索条件导出xlsx表格文件吗?",
|
||||
exportTip: "确认根据当前搜索条件导出全部VoIP用户数据吗?",
|
||||
},
|
||||
udmVolteIMS: {
|
||||
startMSISDN: '起始MSISDN',
|
||||
@@ -833,7 +855,7 @@ export default {
|
||||
vniTip: '示例:ims.mnc000.mcc000.3gppnetwork.org',
|
||||
vniPlease: '请正确输入VNI',
|
||||
delTip: '确认要删除IMS签约为【{num}】的信息吗?',
|
||||
exportTip: "确认根据搜索条件导出xlsx表格文件吗?",
|
||||
exportTip: "确认根据当前搜索条件导出全部VoLTE用户数据吗?",
|
||||
},
|
||||
pcfSub: {
|
||||
exportTip: '确认导出全部用户策略控制信息数据吗?',
|
||||
@@ -853,6 +875,7 @@ export default {
|
||||
list: "列表",
|
||||
topology: "拓扑图",
|
||||
nbName: "设备名称",
|
||||
nbId: "设备ID",
|
||||
ueNum: "在线用户数",
|
||||
topologyTitle: "基站状态关系图",
|
||||
name: "基站名称",
|
||||
@@ -884,7 +907,7 @@ export default {
|
||||
neTypePlease: '查询网元类型',
|
||||
neType: 'UDM网元对象',
|
||||
export: '导出',
|
||||
exportConfirm: '确认导出全部鉴权用户数据吗?',
|
||||
exportConfirm: '确认根据当前搜索条件导出全部鉴权用户数据吗?',
|
||||
checkExport : '勾选导出',
|
||||
checkExportConfirm: '确认导出已勾选的鉴权用户数据吗?',
|
||||
import: '导入',
|
||||
@@ -915,7 +938,7 @@ export default {
|
||||
export: '导出',
|
||||
exportConfirm: '确认导出全部签约用户数据吗?',
|
||||
checkExport : '勾选导出',
|
||||
checkExportConfirm: '确认导出已勾选的签约用户数据吗?',
|
||||
checkExportConfirm: '确认根据当前搜索条件导出全部签约用户数据吗?',
|
||||
import: '导入',
|
||||
importFail: '失败记录',
|
||||
loadDataConfirm: '确认要重新加载数据吗?',
|
||||
@@ -1339,10 +1362,19 @@ export default {
|
||||
deleteTipErr: "文件删除失败",
|
||||
sysloginLog:'系统登录日志',
|
||||
sysOperateLog:'系统操作日志',
|
||||
cdrIMS:'语音话单',
|
||||
cdrSMF:'数据话单',
|
||||
cdrSMSC:'短信话单',
|
||||
cdrSGWC:'漫游数据话单',
|
||||
neLog:'网元日志',
|
||||
cdrIMS:'话单 IMS 语音',
|
||||
cdrSMF:'话单 SMF 数据',
|
||||
cdrSMSC:'话单 SMSC 短信',
|
||||
cdrSGWC:'话单 SGWC 漫游数据',
|
||||
kpiIMS:'KPI IMS',
|
||||
kpiAMF:'KPI AMF',
|
||||
kpiUDM:'KPI UDM',
|
||||
kpiSMF:'KPI SMF',
|
||||
kpiPCF:'KPI PCF',
|
||||
kpiUPF:'KPI UPF',
|
||||
kpiMME:'KPI MME',
|
||||
kpiSMSC:'KPI SMSC',
|
||||
}
|
||||
},
|
||||
monitor: {
|
||||
@@ -1887,6 +1919,10 @@ export default {
|
||||
home: '系统首页',
|
||||
homeTip:'确认要提交当前界面为系统界面吗?',
|
||||
homeSet:'系统首页设置',
|
||||
backup: '系统备份',
|
||||
backupInstruction: '系统备份将会对当前系统上运行的网元信息记录及配置文件进行备份,可进行系统的恢复操作!',
|
||||
backupExportTip: '确认要导出系统备份吗?',
|
||||
backupImportTip: '确认要导入系统备份吗?',
|
||||
},
|
||||
role:{
|
||||
allScopeOptions:'全部数据权限',
|
||||
|
||||
@@ -217,6 +217,7 @@ onMounted(() => {
|
||||
let serverTimeInterval: any = null;
|
||||
let serverTime = 0;
|
||||
let serverTimeZone = getTimezoneOffset();
|
||||
let activeAlarmRefresh = 0;
|
||||
|
||||
// 获取服务器时间
|
||||
function fnGetServerTime() {
|
||||
@@ -230,6 +231,7 @@ function fnGetServerTime() {
|
||||
const serverTimeDom = document.getElementById('serverTimeDom');
|
||||
serverTimeInterval = setInterval(() => {
|
||||
serverTime += 1000;
|
||||
activeAlarmRefresh += 1;
|
||||
if (serverTimeDom) {
|
||||
serverTimeDom.innerText = parseDateUTCToStr(
|
||||
serverTime,
|
||||
@@ -239,6 +241,10 @@ function fnGetServerTime() {
|
||||
clearInterval(serverTimeInterval);
|
||||
serverTimeInterval = null;
|
||||
}
|
||||
if (activeAlarmRefresh === 5) {
|
||||
useAlarmStore().fnGetActiveAlarmInfo();
|
||||
activeAlarmRefresh = 0;
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
|
||||
+8
-8
@@ -66,14 +66,14 @@ router.beforeEach(async (to, from, next) => {
|
||||
await appStore.fnSysConf();
|
||||
}
|
||||
|
||||
// 需要系统引导跳转
|
||||
if (appStore.bootloader && to.path !== '/quick-start') {
|
||||
next({ name: 'QuickStart' });
|
||||
}
|
||||
// 不重复引导
|
||||
if (!appStore.bootloader && to.path === '/quick-start') {
|
||||
next({ name: 'Index' });
|
||||
}
|
||||
// // 需要系统引导跳转
|
||||
// if (appStore.bootloader && to.path !== '/quick-start') {
|
||||
// next({ name: 'QuickStart' });
|
||||
// }
|
||||
// // 不重复引导
|
||||
// if (!appStore.bootloader && to.path === '/quick-start') {
|
||||
// next({ name: 'Index' });
|
||||
// }
|
||||
|
||||
let token = getAccessToken();
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ type AppStore = {
|
||||
/**版本号 */
|
||||
version: string;
|
||||
/**系统引导使用 */
|
||||
bootloader: boolean;
|
||||
// bootloader: boolean;
|
||||
/**服务版本 */
|
||||
serverVersion: string;
|
||||
// 用户登录认证
|
||||
@@ -59,7 +59,7 @@ const useAppStore = defineStore('app', {
|
||||
appVersion: import.meta.env.VITE_APP_VERSION,
|
||||
|
||||
version: '-',
|
||||
bootloader: false,
|
||||
// bootloader: false,
|
||||
serverVersion: '-',
|
||||
loginAuth: true,
|
||||
cryptoApi: true,
|
||||
@@ -91,12 +91,12 @@ const useAppStore = defineStore('app', {
|
||||
if (res.code === RESULT_CODE_SUCCESS && res.data) {
|
||||
this.version = res.data.version;
|
||||
this.serverVersion = res.data.serverVersion;
|
||||
this.bootloader = res.data.bootloader === 'true';
|
||||
// 引导时
|
||||
if (this.bootloader) {
|
||||
delAccessToken();
|
||||
delRefreshToken();
|
||||
}
|
||||
// this.bootloader = res.data.bootloader === 'true';
|
||||
// // 引导时
|
||||
// if (this.bootloader) {
|
||||
// delAccessToken();
|
||||
// delRefreshToken();
|
||||
// }
|
||||
this.loginAuth = res.data.loginAuth !== 'false';
|
||||
this.cryptoApi = res.data.cryptoApi !== 'false';
|
||||
sessionSet(CACHE_SESSION_CRYPTO_API, res.data.cryptoApi);
|
||||
|
||||
+31
-1
@@ -17,6 +17,35 @@ export const RFC3339 = 'YYYY-MM-DDTHH:mm:ssZ';
|
||||
/**国际时间 列如:Thu, Nov 14 2024 10:19 GMT+08:00 */
|
||||
export const RFC822Z = 'ddd, MMM DD YYYY HH:mm [GMT]Z';
|
||||
|
||||
// 映射时区偏移量与IANA时区名称关联
|
||||
export const offsetToIanaMap: Record<string, string> = {
|
||||
'+0000': 'UTC',
|
||||
'+0100': 'Europe/London',
|
||||
'+0200': 'Europe/Paris',
|
||||
'+0300': 'Europe/Moscow',
|
||||
'+0400': 'Asia/Dubai',
|
||||
'+0500': 'Asia/Karachi',
|
||||
'+0600': 'Asia/Almaty',
|
||||
'+0700': 'Asia/Bangkok',
|
||||
'+0800': 'Asia/Shanghai',
|
||||
'+0900': 'Asia/Tokyo',
|
||||
'+1000': 'Australia/Sydney',
|
||||
'+1100': 'Pacific/Noumea',
|
||||
'+1200': 'Pacific/Fiji',
|
||||
'-0100': 'America/Noronha',
|
||||
'-0200': 'Atlantic/Azores',
|
||||
'-0300': 'America/Argentina/Buenos_Aires',
|
||||
'-0400': 'America/New_York',
|
||||
'-0500': 'America/New_York',
|
||||
'-0600': 'America/Chicago',
|
||||
'-0700': 'America/Denver',
|
||||
'-0800': 'America/Los_Angeles',
|
||||
'-0900': 'Pacific/Honolulu',
|
||||
'-1000': 'Pacific/Honolulu',
|
||||
'-1100': 'Pacific/Pago_Pago',
|
||||
'-1200': 'Pacific/Kwajalein',
|
||||
};
|
||||
|
||||
/**
|
||||
* 格式时间字符串
|
||||
* @param dateStr 时间字符串
|
||||
@@ -53,9 +82,10 @@ export function parseDateUTCToStr(
|
||||
date: string | number | Date,
|
||||
offset: string = '+0000'
|
||||
): string {
|
||||
const ianaTimezone = offsetToIanaMap[offset] || 'UTC';
|
||||
return dayjs
|
||||
.utc(date) // 将时间戳按 UTC 时间
|
||||
.tz(offset) // 使用时区偏移
|
||||
.tz(ianaTimezone) // 使用时区偏移
|
||||
.format(`YYYY-MM-DD HH:mm:ss [UTC${offset}]`); // 格式化时间
|
||||
}
|
||||
|
||||
|
||||
@@ -177,25 +177,6 @@ export function parseSizeFromKbs(sizeByte: number, timeInterval: number): any {
|
||||
return [(realBit / 1000 / 1000).toFixed(2), ' Mbits/sec'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 位数据转换单位
|
||||
* @param bits 位Bit大小 64009540 = 512.08 MB
|
||||
* @returns xx B / KB / MB / GB / TB / PB / EB / ZB / YB
|
||||
*/
|
||||
export function parseSizeFromBits(bits: number | string): string {
|
||||
bits = Number(bits) || 0;
|
||||
if (bits <= 0) return '0 B';
|
||||
bits = bits * 8;
|
||||
const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
const unitIndex = Math.floor(Math.log2(bits) / 10);
|
||||
const value = bits / Math.pow(1000, unitIndex);
|
||||
const unti = units[unitIndex];
|
||||
if (unitIndex > 0) {
|
||||
return `${value.toFixed(2)} ${unti}`;
|
||||
}
|
||||
return `${value} ${unti}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字节数转换单位
|
||||
* @param byte 字节Byte大小 64009540 = 512.08 MB
|
||||
|
||||
@@ -90,7 +90,7 @@ function fnFinish() {
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
min: 6,
|
||||
min: 5,
|
||||
max: 26,
|
||||
message: t('views.account.settings.oldPasswordTip'),
|
||||
},
|
||||
|
||||
@@ -88,12 +88,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns: ColumnsType = [
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'left',
|
||||
// width: 100,
|
||||
// },
|
||||
{
|
||||
title: t('views.cbc.cbe.eventName'),
|
||||
dataIndex: 'messageJson',
|
||||
|
||||
@@ -324,12 +324,6 @@ onBeforeUnmount(() => {
|
||||
:loading="tableState.loading"
|
||||
:pagination="false"
|
||||
:scroll="{ x: true }"
|
||||
:row-selection="{
|
||||
type: 'radio',
|
||||
columnWidth: '48px',
|
||||
selectedRowKeys: tableState.selectedRowKeys,
|
||||
onChange: fnTableSelectedRowKeys,
|
||||
}"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'status'">
|
||||
@@ -351,6 +345,7 @@ onBeforeUnmount(() => {
|
||||
:title="`${t('views.index.mark')} - ${serverState.neName || 'OMC'}`"
|
||||
style="margin-top: 16px"
|
||||
size="small"
|
||||
v-if="false"
|
||||
>
|
||||
<a-descriptions
|
||||
bordered
|
||||
|
||||
@@ -134,12 +134,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns: ColumnsType = [
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'left',
|
||||
// width: 100,
|
||||
// },
|
||||
{
|
||||
title: 'IMSI',
|
||||
dataIndex: 'eventJSON',
|
||||
@@ -339,9 +339,11 @@ function fnExportList() {
|
||||
title: t('common.tipTitle'),
|
||||
content: t('views.dashboard.ue.exportTip'),
|
||||
onOk() {
|
||||
modalState.confirmLoading = true;
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
const querys = toRaw(queryParams);
|
||||
querys.pageSize = 10000;
|
||||
querys.pageNum = 1;
|
||||
querys.pageSize = tablePagination.total;
|
||||
exportAMFDataUE(querys)
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
|
||||
@@ -141,12 +141,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns: ColumnsType = [
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'left',
|
||||
// width: 100,
|
||||
// },
|
||||
{
|
||||
title: t('views.dashboard.cdr.recordType'),
|
||||
dataIndex: 'cdrJSON',
|
||||
@@ -408,9 +408,11 @@ function fnExportList() {
|
||||
title: t('common.tipTitle'),
|
||||
content: t('views.dashboard.cdr.exportTip'),
|
||||
onOk() {
|
||||
modalState.confirmLoading = true;
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
const querys = toRaw(queryParams);
|
||||
querys.pageSize = 10000;
|
||||
querys.pageNum = 1;
|
||||
querys.pageSize = tablePagination.total;
|
||||
exportIMSDataCDR(querys)
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
|
||||
@@ -135,12 +135,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns: ColumnsType = [
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'left',
|
||||
// width: 100,
|
||||
// },
|
||||
{
|
||||
title: 'IMSI',
|
||||
dataIndex: 'eventJSON',
|
||||
@@ -341,9 +341,11 @@ function fnExportList() {
|
||||
title: t('common.tipTitle'),
|
||||
content: t('views.dashboard.ue.exportTip'),
|
||||
onOk() {
|
||||
modalState.confirmLoading = true;
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
const querys = toRaw(queryParams);
|
||||
querys.pageSize = 10000;
|
||||
querys.pageNum = 1;
|
||||
querys.pageSize = tablePagination.total;
|
||||
exportMMEDataUE(querys)
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { parseDateToStr } from '@/utils/date-utils';
|
||||
import { parseSizeFromBits, parseSizeFromKbs } from '@/utils/parse-utils';
|
||||
import { parseSizeFromByte, parseSizeFromKbs } from '@/utils/parse-utils';
|
||||
import { ref } from 'vue';
|
||||
|
||||
type FDType = {
|
||||
@@ -81,9 +81,9 @@ export function upfTFParse(day: string, data: Record<string, number>) {
|
||||
let { up, down } = data;
|
||||
upfTotalFlow.value[day] = {
|
||||
up: up,
|
||||
upFrom: parseSizeFromBits(up),
|
||||
upFrom: parseSizeFromByte(up),
|
||||
down: down,
|
||||
downFrom: parseSizeFromBits(down),
|
||||
downFrom: parseSizeFromByte(down),
|
||||
requestFlag: false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -229,15 +229,15 @@ function loadData() {
|
||||
interval10s.value = setInterval(() => {
|
||||
if (!interval10s.value || !initFlag) return;
|
||||
if (upfTFActive.value === '0') {
|
||||
upfTFSend('7');
|
||||
upfTFActive.value = '7';
|
||||
} else if (upfTFActive.value === '7') {
|
||||
upfTFSend('30');
|
||||
upfTFActive.value = '30';
|
||||
} else if (upfTFActive.value === '30') {
|
||||
upfTFSend('0');
|
||||
upfTFActive.value = '0';
|
||||
}
|
||||
upfTFSend('0');
|
||||
upfTFSend('7');
|
||||
upfTFSend('30');
|
||||
}, 10_000);
|
||||
|
||||
clearInterval(interval5s.value);
|
||||
@@ -679,7 +679,6 @@ onBeforeUnmount(() => {
|
||||
.toDeep :deep(.ant-select-selection-item) {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.toDeep-text {
|
||||
color: #4c9bfd !important;
|
||||
font-size: 0.844rem !important;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { parseDateToStr } from '@/utils/date-utils';
|
||||
import { parseSizeFromBits, parseSizeFromKbs } from '@/utils/parse-utils';
|
||||
import { parseSizeFromByte, parseSizeFromKbs } from '@/utils/parse-utils';
|
||||
import { ref } from 'vue';
|
||||
|
||||
type FDType = {
|
||||
@@ -79,9 +79,9 @@ export function upfTFParse(day: string, data: Record<string, number>) {
|
||||
let { up, down } = data;
|
||||
upfTotalFlow.value[day] = {
|
||||
up: up,
|
||||
upFrom: parseSizeFromBits(up),
|
||||
upFrom: parseSizeFromByte(up),
|
||||
down: down,
|
||||
downFrom: parseSizeFromBits(down),
|
||||
downFrom: parseSizeFromByte(down),
|
||||
requestFlag: false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -176,15 +176,15 @@ async function fnGetSkim() {
|
||||
{
|
||||
request: (neId: string) => listAMFNblist({ neId }),
|
||||
process: async (res: any, neId: any) => {
|
||||
console.log(neId)
|
||||
if (res.code === RESULT_CODE_SUCCESS&& Array.isArray(res.data)) {
|
||||
console.log(neId);
|
||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||
skimState.gnbNum += res.data.length;
|
||||
skimState.gnbUeNum += res.data.reduce(
|
||||
(sum: number, item: any) => sum + item.ueNum,
|
||||
0
|
||||
);
|
||||
const amfNbRes = await listAMFNbStatelist({ neId });
|
||||
console.log(amfNbRes)
|
||||
console.log(amfNbRes);
|
||||
if (
|
||||
amfNbRes.code === RESULT_CODE_SUCCESS &&
|
||||
Array.isArray(amfNbRes.data)
|
||||
@@ -224,13 +224,13 @@ async function fnGetSkim() {
|
||||
);
|
||||
|
||||
const mmeNbRes = await listMMENbStatelist({ neId });
|
||||
console.log(mmeNbRes)
|
||||
console.log(mmeNbRes);
|
||||
if (
|
||||
mmeNbRes.code === RESULT_CODE_SUCCESS &&
|
||||
Array.isArray(mmeNbRes.data)
|
||||
) {
|
||||
// skimState.eNbSumNum += mmeNbRes.data.length;
|
||||
console.log(mmeNbRes)
|
||||
console.log(mmeNbRes);
|
||||
tempEnbSumNum += mmeNbRes.data.length;
|
||||
}
|
||||
}
|
||||
@@ -238,21 +238,20 @@ async function fnGetSkim() {
|
||||
},
|
||||
],
|
||||
]);
|
||||
console.log(neCascaderOptions)
|
||||
console.log(neCascaderOptions);
|
||||
|
||||
const requests = neCascaderOptions.value.flatMap(
|
||||
(ne: any) =>
|
||||
ne.children
|
||||
?.map((child: any) => {
|
||||
console.log(child.neId)
|
||||
console.log(child.neId);
|
||||
const handler = neHandlers.get(child.neType);
|
||||
return handler
|
||||
? {
|
||||
promise: handler.request(child.neId),
|
||||
process: handler.process,
|
||||
neId: child.neId, // 这里加上neId
|
||||
|
||||
}
|
||||
neId: child.neId, // 这里加上neId
|
||||
}
|
||||
: null;
|
||||
})
|
||||
.filter(Boolean) || []
|
||||
@@ -311,15 +310,15 @@ function loadData() {
|
||||
interval10s.value = setInterval(() => {
|
||||
if (!interval10s.value || !initFlag) return;
|
||||
if (upfTFActive.value === '0') {
|
||||
upfTFSend('7');
|
||||
upfTFActive.value = '7';
|
||||
} else if (upfTFActive.value === '7') {
|
||||
upfTFSend('30');
|
||||
upfTFActive.value = '30';
|
||||
} else if (upfTFActive.value === '30') {
|
||||
upfTFSend('0');
|
||||
upfTFActive.value = '0';
|
||||
}
|
||||
upfTFSend('0');
|
||||
upfTFSend('7');
|
||||
upfTFSend('30');
|
||||
}, 10_000);
|
||||
|
||||
clearInterval(interval5s.value);
|
||||
@@ -375,12 +374,14 @@ async function fnSelectUDM(e: any) {
|
||||
pageNum: 1,
|
||||
pageSize: 1,
|
||||
});
|
||||
console.log(res)
|
||||
console.log(res);
|
||||
// listUDMSub({ neId: udmNeId.value, pageNum: 1, pageSize: 1 }).then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS && typeof res.data.total === 'number') {
|
||||
if (
|
||||
res.code === RESULT_CODE_SUCCESS &&
|
||||
typeof res.data.total === 'number'
|
||||
) {
|
||||
skimState.udmSubNum = res.data.total;
|
||||
console.log(res)
|
||||
|
||||
console.log(res);
|
||||
} else {
|
||||
skimState.udmSubNum = 0;
|
||||
}
|
||||
@@ -393,7 +394,7 @@ async function fnSelectUDM(e: any) {
|
||||
}
|
||||
/**资源控制-选择NE */
|
||||
function fnSelectNeRe(e: any) {
|
||||
console.log(e)
|
||||
console.log(e);
|
||||
graphNodeClickID.value = e.key;
|
||||
}
|
||||
//
|
||||
@@ -408,7 +409,7 @@ const getPopupContainer = () => {
|
||||
onMounted(() => {
|
||||
// 获取网元网元列表
|
||||
neListStore.neCascaderOptions.forEach(item => {
|
||||
console.log(item)
|
||||
console.log(item);
|
||||
if (item.value === 'UPF') {
|
||||
neOtions.value = JSON.parse(JSON.stringify(item.children));
|
||||
}
|
||||
|
||||
@@ -111,12 +111,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns: ColumnsType = [
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'left',
|
||||
// width: 100,
|
||||
// },
|
||||
{
|
||||
title: t('views.dashboard.cdr.chargingID'), // 计费ID
|
||||
dataIndex: 'cdrJSON',
|
||||
@@ -378,9 +378,11 @@ function fnExportList() {
|
||||
title: t('common.tipTitle'),
|
||||
content: t('views.dashboard.cdr.exportTip'),
|
||||
onOk() {
|
||||
modalState.confirmLoading = true;
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
const querys = toRaw(queryParams);
|
||||
querys.pageSize = 10000;
|
||||
querys.pageNum = 1;
|
||||
querys.pageSize = tablePagination.total;
|
||||
exportSGWCDataCDR(querys)
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
|
||||
@@ -20,6 +20,7 @@ import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||
import PQueue from 'p-queue';
|
||||
import saveAs from 'file-saver';
|
||||
import dayjs, { type Dayjs } from 'dayjs';
|
||||
import { parseSizeFromByte } from '@/utils/parse-utils';
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
const { copy } = useClipboard({ legacy: true });
|
||||
const { t } = useI18n();
|
||||
@@ -107,12 +108,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns = ref<ColumnsType>([
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'center',
|
||||
width: 100,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'center',
|
||||
// width: 100,
|
||||
// },
|
||||
{
|
||||
title: t('views.dashboard.cdr.chargingID'), // 计费ID
|
||||
dataIndex: 'cdrJSON',
|
||||
@@ -165,7 +166,7 @@ let tableColumns = ref<ColumnsType>([
|
||||
}
|
||||
}
|
||||
}
|
||||
return dataVolumeUplink;
|
||||
return parseSizeFromByte(dataVolumeUplink);
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -190,7 +191,7 @@ let tableColumns = ref<ColumnsType>([
|
||||
}
|
||||
}
|
||||
}
|
||||
return dataVolumeDownlink;
|
||||
return parseSizeFromByte(dataVolumeDownlink);
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -215,7 +216,7 @@ let tableColumns = ref<ColumnsType>([
|
||||
}
|
||||
}
|
||||
}
|
||||
return dataTotalVolume;
|
||||
return parseSizeFromByte(dataTotalVolume);
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -405,9 +406,11 @@ function fnExportList() {
|
||||
title: t('common.tipTitle'),
|
||||
content: t('views.dashboard.cdr.exportTip'),
|
||||
onOk() {
|
||||
modalState.confirmLoading = true;
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
const querys = toRaw(queryParams);
|
||||
querys.pageSize = 10000;
|
||||
querys.pageNum = 1;
|
||||
querys.pageSize = tablePagination.total;
|
||||
exportSMFDataCDR(querys)
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
@@ -810,15 +813,21 @@ onBeforeUnmount(() => {
|
||||
<div>
|
||||
<div>
|
||||
<span>Data Total Volume: </span>
|
||||
<span>{{ udata.dataTotalVolume }}</span>
|
||||
<span>
|
||||
{{ parseSizeFromByte(udata.dataTotalVolume || 0) }}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Data Volume Downlink: </span>
|
||||
<span>{{ udata.dataVolumeDownlink }}</span>
|
||||
<span>
|
||||
{{ parseSizeFromByte(udata.dataVolumeDownlink || 0) }}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Data Volume Uplink: </span>
|
||||
<span>{{ udata.dataVolumeUplink }}</span>
|
||||
<span>
|
||||
{{ parseSizeFromByte(udata.dataVolumeUplink || 0) }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- <div>
|
||||
<span>Time: </span>
|
||||
|
||||
@@ -33,10 +33,10 @@ const queue = new PQueue({ concurrency: 1, autoStart: true });
|
||||
|
||||
/**字典数据 */
|
||||
let dict: {
|
||||
/**CDR 响应原因代码类别类型 */
|
||||
cdrCauseCode: DictType[];
|
||||
/**CDR SMSC 响应原因代码类别类型 */
|
||||
cdrSMSCCauseCode: DictType[];
|
||||
} = reactive({
|
||||
cdrCauseCode: [],
|
||||
cdrSMSCCauseCode: [],
|
||||
});
|
||||
|
||||
/**网元可选 */
|
||||
@@ -136,12 +136,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns: ColumnsType = [
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'left',
|
||||
// width: 100,
|
||||
// },
|
||||
{
|
||||
title: t('views.dashboard.cdr.recordType'),
|
||||
dataIndex: 'cdrJSON',
|
||||
@@ -186,12 +186,19 @@ let tableColumns: ColumnsType = [
|
||||
},
|
||||
|
||||
{
|
||||
title: t('views.dashboard.cdr.result'),
|
||||
title: t('views.dashboard.cdr.resultCode'),
|
||||
dataIndex: 'cdrJSON',
|
||||
key: 'cause',
|
||||
align: 'left',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.resultCause'),
|
||||
dataIndex: 'cdrJSON',
|
||||
key: 'result',
|
||||
align: 'left',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.time'),
|
||||
dataIndex: 'cdrJSON',
|
||||
@@ -372,9 +379,11 @@ function fnExportList() {
|
||||
title: t('common.tipTitle'),
|
||||
content: t('views.dashboard.cdr.exportTip'),
|
||||
onOk() {
|
||||
modalState.confirmLoading = true;
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
const querys = toRaw(queryParams);
|
||||
querys.pageSize = 10000;
|
||||
querys.pageNum = 1;
|
||||
querys.pageSize = tablePagination.total;
|
||||
exportSMSCDataCDR(querys)
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
@@ -470,9 +479,9 @@ function wsMessage(res: Record<string, any>) {
|
||||
|
||||
onMounted(() => {
|
||||
// 初始字典数据
|
||||
Promise.allSettled([getDict('cdr_cause_code')]).then(resArr => {
|
||||
Promise.allSettled([getDict('cdr_cause_smsc')]).then(resArr => {
|
||||
if (resArr[0].status === 'fulfilled') {
|
||||
dict.cdrCauseCode = resArr[0].value;
|
||||
dict.cdrSMSCCauseCode = resArr[0].value;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -710,17 +719,15 @@ onBeforeUnmount(() => {
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'cause'">
|
||||
<span v-if="record.cdrJSON.result === 0">
|
||||
{{ t('views.dashboard.cdr.resultFail') }},
|
||||
<DictTag
|
||||
:options="dict.cdrCauseCode"
|
||||
:value="record.cdrJSON.cause"
|
||||
value-default="0"
|
||||
/>
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ t('views.dashboard.cdr.resultOk') }}
|
||||
</span>
|
||||
<span v-if="record.cdrJSON.result === 0"> FAILED </span>
|
||||
<span v-else> SUCCESS </span>
|
||||
</template>
|
||||
<template v-if="column.key === 'result'">
|
||||
<DictTag
|
||||
:options="dict.cdrSMSCCauseCode"
|
||||
:value="record.cdrJSON.cause"
|
||||
value-default="0"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="column.key === 'id'">
|
||||
<a-space :size="8" align="center">
|
||||
@@ -792,18 +799,19 @@ onBeforeUnmount(() => {
|
||||
<span>{{ record.cdrJSON.calledParty }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('views.dashboard.cdr.result') }}: </span>
|
||||
<span v-if="record.cdrJSON.result === 0">
|
||||
{{ t('views.dashboard.cdr.resultFail') }},
|
||||
<span>{{ t('views.dashboard.cdr.resultCode') }}: </span>
|
||||
<span v-if="record.cdrJSON.result === 0"> FAILED </span>
|
||||
<span v-else> SUCCESS </span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('views.dashboard.cdr.resultCause') }}: </span>
|
||||
<span>
|
||||
<DictTag
|
||||
:options="dict.cdrCauseCode"
|
||||
:options="dict.cdrSMSCCauseCode"
|
||||
:value="record.cdrJSON.cause"
|
||||
value-default="0"
|
||||
/>
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ t('views.dashboard.cdr.resultOk') }}
|
||||
</span>
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, onMounted, toRaw } from 'vue';
|
||||
import { reactive, ref, onMounted, toRaw, onBeforeUnmount } from 'vue';
|
||||
import { PageContainer } from 'antdv-pro-layout';
|
||||
import { ProModal } from 'antdv-pro-modal';
|
||||
import { message, Modal } from 'ant-design-vue/es';
|
||||
@@ -560,22 +560,24 @@ function fnCancelConfirm() {
|
||||
*/
|
||||
function fnSync() {
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
listSync().then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
message.success({
|
||||
content: t('views.faultManage.activeAlarm.sysncSuss'),
|
||||
duration: 2,
|
||||
});
|
||||
fnGetList();
|
||||
} else {
|
||||
message.error({
|
||||
content: `${res.msg}`,
|
||||
duration: 2,
|
||||
});
|
||||
}
|
||||
}).finally(()=>{
|
||||
hide();
|
||||
});
|
||||
listSync()
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
message.success({
|
||||
content: t('views.faultManage.activeAlarm.sysncSuss'),
|
||||
duration: 2,
|
||||
});
|
||||
fnGetList();
|
||||
} else {
|
||||
message.error({
|
||||
content: `${res.msg}`,
|
||||
duration: 2,
|
||||
});
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
hide();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -821,6 +823,24 @@ function fnGetList(pageNum?: number) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
let interval: any = null;
|
||||
/**自动刷新 */
|
||||
function AutoRefresh() {
|
||||
interval = setInterval(() => {
|
||||
listAct(toRaw(queryParams)).then((res: any) => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
const { total, rows } = res.data;
|
||||
tablePagination.total = total;
|
||||
tableState.data = rows;
|
||||
} else {
|
||||
tablePagination.total = 0;
|
||||
tableState.data = [];
|
||||
}
|
||||
});
|
||||
}, 5_000);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 初始字典数据
|
||||
Promise.allSettled([
|
||||
@@ -844,7 +864,12 @@ onMounted(() => {
|
||||
});
|
||||
// 获取列表
|
||||
fnGetList();
|
||||
// 自动刷新
|
||||
AutoRefresh();
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
clearInterval(interval);
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -957,7 +982,11 @@ onMounted(() => {
|
||||
{{ t('views.faultManage.activeAlarm.updateConfirm') }}
|
||||
</a-button>
|
||||
|
||||
<a-button type="primary" @click.prevent="fnSync()">
|
||||
<a-button
|
||||
type="primary"
|
||||
@click.prevent="fnSync()"
|
||||
v-perms:has="['faultManage:active-alarm:async']"
|
||||
>
|
||||
<template #icon>
|
||||
<ReloadOutlined />
|
||||
</template>
|
||||
@@ -974,6 +1003,7 @@ onMounted(() => {
|
||||
danger
|
||||
@click.prevent="fnClear()"
|
||||
:disabled="state.selectedRowKeys.length <= 0"
|
||||
v-perms:has="['faultManage:active-alarm:delete']"
|
||||
>
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
@@ -981,7 +1011,11 @@ onMounted(() => {
|
||||
{{ t('views.faultManage.activeAlarm.clear') }}
|
||||
</a-button>
|
||||
|
||||
<a-button type="dashed" @click.prevent="fnExportList()">
|
||||
<a-button
|
||||
type="dashed"
|
||||
@click.prevent="fnExportList()"
|
||||
v-perms:has="['faultManage:active-alarm:export']"
|
||||
>
|
||||
<template #icon><ExportOutlined /></template>
|
||||
{{ t('common.export') }}
|
||||
</a-button>
|
||||
|
||||
@@ -744,7 +744,7 @@ onMounted(() => {
|
||||
<!-- 插槽-卡片左侧侧 -->
|
||||
<template #title>
|
||||
<a-space :size="8" align="center">
|
||||
<a-button type="dashed" @click.prevent="fnExportList()">
|
||||
<a-button type="dashed" @click.prevent="fnExportList()" v-perms:has="['faultManage:history-alarm:export']">
|
||||
<template #icon><ExportOutlined /></template>
|
||||
{{ t('common.export') }}
|
||||
</a-button>
|
||||
|
||||
@@ -104,12 +104,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns: ColumnsType = [
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'left',
|
||||
// width: 100,
|
||||
// },
|
||||
{
|
||||
title: t('views.ne.common.neType'),
|
||||
dataIndex: 'neType',
|
||||
|
||||
@@ -30,29 +30,78 @@ let sourceState = reactive({
|
||||
label: t('views.logManage.exportFile.sysOperateLog'),
|
||||
path: '/usr/local/omc/backup',
|
||||
},
|
||||
|
||||
{
|
||||
value: '/cdr/ims_cdr_event',
|
||||
value: '/log/ne_log',
|
||||
label: t('views.logManage.exportFile.neLog'),
|
||||
path: '/usr/local/omc/backup',
|
||||
},
|
||||
|
||||
{
|
||||
value: '/cdr/ims',
|
||||
label: t('views.logManage.exportFile.cdrIMS'),
|
||||
path: '/usr/local/omc/backup',
|
||||
neType: 'IMS',
|
||||
},
|
||||
{
|
||||
value: '/cdr/smf_cdr_event',
|
||||
value: '/cdr/smf',
|
||||
label: t('views.logManage.exportFile.cdrSMF'),
|
||||
path: '/usr/local/omc/backup',
|
||||
neType: 'SMF',
|
||||
},
|
||||
{
|
||||
value: '/cdr/smsc_cdr_event',
|
||||
value: '/cdr/smsc',
|
||||
label: t('views.logManage.exportFile.cdrSMSC'),
|
||||
path: '/usr/local/omc/backup',
|
||||
neType: 'SMSC',
|
||||
},
|
||||
{
|
||||
value: '/cdr/sgwc_cdr_event',
|
||||
label: t('views.logManage.exportFile.cdrSGWC'),
|
||||
value: '/kpi/ims',
|
||||
label: t('views.logManage.exportFile.kpiIMS'),
|
||||
path: '/usr/local/omc/backup',
|
||||
neType: 'SGWC',
|
||||
neType: 'IMS',
|
||||
},
|
||||
{
|
||||
value: '/kpi/amf',
|
||||
label: t('views.logManage.exportFile.kpiAMF'),
|
||||
path: '/usr/local/omc/backup',
|
||||
neType: 'AMF',
|
||||
},
|
||||
{
|
||||
value: '/kpi/udm',
|
||||
label: t('views.logManage.exportFile.kpiUDM'),
|
||||
path: '/usr/local/omc/backup',
|
||||
neType: 'UDM',
|
||||
},
|
||||
{
|
||||
value: '/kpi/smf',
|
||||
label: t('views.logManage.exportFile.kpiSMF'),
|
||||
path: '/usr/local/omc/backup',
|
||||
neType: 'SMF',
|
||||
},
|
||||
{
|
||||
value: '/kpi/pcf',
|
||||
label: t('views.logManage.exportFile.kpiPCF'),
|
||||
path: '/usr/local/omc/backup',
|
||||
neType: 'PCF',
|
||||
},
|
||||
{
|
||||
value: '/kpi/upf',
|
||||
label: t('views.logManage.exportFile.kpiUPF'),
|
||||
path: '/usr/local/omc/backup',
|
||||
neType: 'UPF',
|
||||
},
|
||||
{
|
||||
value: '/kpi/mme',
|
||||
label: t('views.logManage.exportFile.kpiMME'),
|
||||
path: '/usr/local/omc/backup',
|
||||
neType: 'MME',
|
||||
},
|
||||
{
|
||||
value: '/kpi/smsc',
|
||||
label: t('views.logManage.exportFile.kpiSMSC'),
|
||||
path: '/usr/local/omc/backup',
|
||||
neType: 'SMSC',
|
||||
},
|
||||
],
|
||||
/**选择value */
|
||||
@@ -242,9 +291,31 @@ function fnRecordDelete(row: Record<string, any>) {
|
||||
});
|
||||
}
|
||||
|
||||
/**访问路径 */
|
||||
let nePathArr = ref<string[]>([]);
|
||||
/**进入目录 */
|
||||
function fnDirCD(dir: string, index?: number) {
|
||||
if (index === undefined) {
|
||||
nePathArr.value.push(dir);
|
||||
queryParams.path = nePathArr.value.join('/');
|
||||
fnGetList(1);
|
||||
return;
|
||||
}
|
||||
if (index === 0) {
|
||||
nePathArr.value = [nePathArr.value[0]];
|
||||
queryParams.path = nePathArr.value.join('/');
|
||||
fnGetList(1);
|
||||
} else {
|
||||
nePathArr.value = nePathArr.value.slice(0, index + 1);
|
||||
queryParams.path = nePathArr.value.join('/');
|
||||
fnGetList(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**网元类型选择对应修改 */
|
||||
function fnNeChange(_: any, opt: any) {
|
||||
queryParams.path = `${opt.path}${opt.value}`;
|
||||
nePathArr.value = [`${opt.path}${opt.value}`];
|
||||
queryParams.path = nePathArr.value.join('/');
|
||||
ftpInfo.path = queryParams.path;
|
||||
ftpInfo.tag = opt.value;
|
||||
fnGetList(1);
|
||||
@@ -346,8 +417,12 @@ onMounted(() => {
|
||||
<span>{{ t('views.logManage.neFile.nePath') }}:</span>
|
||||
<a-col>
|
||||
<a-breadcrumb>
|
||||
<a-breadcrumb-item>
|
||||
{{ queryParams.path }}
|
||||
<a-breadcrumb-item
|
||||
v-for="(path, index) in nePathArr"
|
||||
:key="path"
|
||||
@click="fnDirCD(path, index)"
|
||||
>
|
||||
{{ path }}
|
||||
</a-breadcrumb-item>
|
||||
</a-breadcrumb>
|
||||
</a-col>
|
||||
@@ -421,6 +496,15 @@ onMounted(() => {
|
||||
<template #icon><DeleteOutlined /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-button
|
||||
type="link"
|
||||
:loading="downLoading"
|
||||
@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>
|
||||
|
||||
@@ -99,12 +99,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns: ColumnsType = reactive([
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'left',
|
||||
// width: 100,
|
||||
// },
|
||||
{
|
||||
title: t('views.logManage.forwarding.alarmInter'),
|
||||
dataIndex: 'type',
|
||||
|
||||
@@ -63,12 +63,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns: ColumnsType = reactive([
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'left',
|
||||
width: 80,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'left',
|
||||
// width: 80,
|
||||
// },
|
||||
{
|
||||
title: t('views.logManage.mml.account'),
|
||||
dataIndex: 'user',
|
||||
|
||||
@@ -165,7 +165,7 @@ onMounted(() => {
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
min: 6,
|
||||
min: 5,
|
||||
max: 26,
|
||||
message: t('valid.passwordPlease'),
|
||||
},
|
||||
|
||||
@@ -87,7 +87,7 @@ function fnFinish() {
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
min: 6,
|
||||
min: 5,
|
||||
max: 26,
|
||||
message: t('valid.passwordPlease'),
|
||||
},
|
||||
|
||||
@@ -87,7 +87,7 @@ function fnFinish() {
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
min: 6,
|
||||
min: 5,
|
||||
max: 26,
|
||||
message: t('valid.passwordPlease'),
|
||||
},
|
||||
|
||||
@@ -442,6 +442,7 @@ function fnGetList() {
|
||||
/**自动完成搜索匹配前缀 */
|
||||
function fnAutoCompleteSearch(value: string) {
|
||||
state.autoCompleteSearch = [];
|
||||
return; // 回车undefined问题,关闭搜索匹配
|
||||
for (const item of state.autoCompleteData) {
|
||||
const filterOptions = item.options.filter((s: any) => {
|
||||
return `${s.operation} ${s.object}`.indexOf(value.toLowerCase()) >= 0;
|
||||
|
||||
@@ -408,6 +408,7 @@ function fnGetList() {
|
||||
/**自动完成搜索匹配前缀 */
|
||||
function fnAutoCompleteSearch(value: string) {
|
||||
state.autoCompleteSearch = [];
|
||||
return; // 回车undefined问题,关闭搜索匹配
|
||||
for (const item of state.autoCompleteData) {
|
||||
const filterOptions = item.options.filter((s: any) => {
|
||||
return `${s.operation} ${s.object}`.indexOf(value.toLowerCase()) >= 0;
|
||||
|
||||
Vendored
+18
-18
@@ -49,15 +49,15 @@ function fnCacheKeyInfo(cacheKey: string) {
|
||||
|
||||
/**键名列表表格字段列 */
|
||||
let cacheKeyTableColumns: ColumnsType = [
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'num',
|
||||
width: '50px',
|
||||
align: 'center',
|
||||
customRender(opt) {
|
||||
return opt.index + 1;
|
||||
},
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'num',
|
||||
// width: '50px',
|
||||
// align: 'center',
|
||||
// customRender(opt) {
|
||||
// return opt.index + 1;
|
||||
// },
|
||||
// },
|
||||
{
|
||||
title: t('views.monitor.cache.cacheKey'),
|
||||
dataIndex: 'cacheKey',
|
||||
@@ -152,15 +152,15 @@ let cacheNameTable = reactive({
|
||||
|
||||
/**缓存列表表格字段列 */
|
||||
let cacheNameTableColumns: ColumnsType = [
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'num',
|
||||
width: '50px',
|
||||
align: 'center',
|
||||
customRender(opt) {
|
||||
return opt.index + 1;
|
||||
},
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'num',
|
||||
// width: '50px',
|
||||
// align: 'center',
|
||||
// customRender(opt) {
|
||||
// return opt.index + 1;
|
||||
// },
|
||||
// },
|
||||
{
|
||||
title: t('views.monitor.cache.cacheName'),
|
||||
dataIndex: 'cacheName',
|
||||
|
||||
@@ -98,11 +98,11 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns: ColumnsType = [
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'jobId',
|
||||
align: 'center',
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'jobId',
|
||||
// align: 'center',
|
||||
// },
|
||||
{
|
||||
title: t('views.monitor.job.jobName'),
|
||||
dataIndex: 'jobName',
|
||||
@@ -680,14 +680,14 @@ onMounted(() => {
|
||||
<template #icon><ExportOutlined /></template>
|
||||
{{ t('common.export') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
<!-- <a-button
|
||||
type="default"
|
||||
@click.prevent="fnJobLogView()"
|
||||
v-perms:has="['monitor:job:query']"
|
||||
>
|
||||
<template #icon><ContainerOutlined /></template>
|
||||
{{ t('views.monitor.job.jobLog') }}
|
||||
</a-button>
|
||||
</a-button> -->
|
||||
<a-button
|
||||
type="dashed"
|
||||
danger
|
||||
@@ -755,11 +755,13 @@ onMounted(() => {
|
||||
:size="tableState.size"
|
||||
:pagination="tablePagination"
|
||||
:scroll="{ x: tableColumns.length * 120 }"
|
||||
:row-selection="{
|
||||
type: 'checkbox',
|
||||
selectedRowKeys: tableState.selectedRowKeys,
|
||||
onChange: fnTableSelectedRowKeys,
|
||||
}"
|
||||
:row-selection="hasPermissions(['monitor:job:remove'])
|
||||
? {
|
||||
type: 'checkbox',
|
||||
selectedRowKeys: tableState.selectedRowKeys,
|
||||
onChange: fnTableSelectedRowKeys,
|
||||
}
|
||||
: undefined"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'jobGroup'">
|
||||
|
||||
@@ -117,12 +117,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns: ColumnsType = [
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'logId',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'logId',
|
||||
// align: 'left',
|
||||
// width: 100,
|
||||
// },
|
||||
{
|
||||
title: t('views.monitor.jobLog.jobName'),
|
||||
dataIndex: 'jobName',
|
||||
@@ -247,6 +247,13 @@ let modalState: ModalStateType = reactive({
|
||||
*/
|
||||
function fnModalVisibleByVive(row: Record<string, string>) {
|
||||
modalState.from = Object.assign(modalState.from, row);
|
||||
try {
|
||||
modalState.from.jobMsg = JSON.stringify(
|
||||
JSON.parse(modalState.from.jobMsg),
|
||||
null,
|
||||
4
|
||||
);
|
||||
} catch (_) {}
|
||||
modalState.title = t('views.monitor.jobLog.viewLog');
|
||||
modalState.open = true;
|
||||
}
|
||||
|
||||
@@ -41,16 +41,16 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns: ColumnsType = [
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'num',
|
||||
width: '50px',
|
||||
align: 'left',
|
||||
customRender(opt) {
|
||||
const idxNum = (tablePagination.current - 1) * tablePagination.pageSize;
|
||||
return idxNum + opt.index + 1;
|
||||
},
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'num',
|
||||
// width: '50px',
|
||||
// align: 'left',
|
||||
// customRender(opt) {
|
||||
// const idxNum = (tablePagination.current - 1) * tablePagination.pageSize;
|
||||
// return idxNum + opt.index + 1;
|
||||
// },
|
||||
// },
|
||||
{
|
||||
title: t('views.monitor.online.mettingId'),
|
||||
dataIndex: 'tokenId',
|
||||
|
||||
@@ -64,10 +64,50 @@ function fnGetList(refresh: boolean = false) {
|
||||
Array.isArray(res.data) &&
|
||||
res.data.length > 0
|
||||
) {
|
||||
// 根网管
|
||||
let rootNodeInfo = { neName: 'OMC_001' };
|
||||
const nodes = [];
|
||||
const edges = [];
|
||||
|
||||
// 根网管
|
||||
let rootNodeInfo = {
|
||||
neName: 'ROOT',
|
||||
serverState: {
|
||||
online: true,
|
||||
},
|
||||
};
|
||||
// 处理没有OMC的情况
|
||||
const omcFilter = res.data.filter(v => v.neType === 'OMC');
|
||||
if (omcFilter.length === 1) {
|
||||
rootNodeInfo.neName = omcFilter[0].neName;
|
||||
} else {
|
||||
nodes.unshift({
|
||||
id: rootNodeInfo.neName,
|
||||
label: rootNodeInfo.neName,
|
||||
info: rootNodeInfo,
|
||||
labelCfg: {
|
||||
position: 'bottom',
|
||||
offset: 8,
|
||||
style: {
|
||||
fill: '#fff',
|
||||
fontSize: 14,
|
||||
},
|
||||
},
|
||||
size: 60,
|
||||
icon: {
|
||||
x: -30,
|
||||
y: -30,
|
||||
// 可更换为其他图片地址
|
||||
img: parseBasePath('/svg/service_db.svg'),
|
||||
width: 60,
|
||||
height: 60,
|
||||
},
|
||||
});
|
||||
edges.push({
|
||||
source: rootNodeInfo.neName,
|
||||
target: rootNodeInfo.neName,
|
||||
label: `${rootNodeInfo.neName}-${rootNodeInfo.neName}`,
|
||||
});
|
||||
}
|
||||
|
||||
for (const item of res.data) {
|
||||
item.serverState = {};
|
||||
// 节点
|
||||
@@ -96,7 +136,6 @@ function fnGetList(refresh: boolean = false) {
|
||||
height: 60,
|
||||
},
|
||||
});
|
||||
!rootNodeInfo.neName && (rootNodeInfo = item);
|
||||
} else {
|
||||
nodes.push({
|
||||
id: item.neName,
|
||||
|
||||
@@ -0,0 +1,592 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, toRaw, watch, ref } from 'vue';
|
||||
import { ProModal } from 'antdv-pro-modal';
|
||||
import { Form, message } from 'ant-design-vue/es';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
import useNeListStore from '@/store/modules/ne_list';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import {
|
||||
getNeConfigData,
|
||||
addNeConfigData,
|
||||
editNeConfigData,
|
||||
} from '@/api/ne/neConfig';
|
||||
const { t } = useI18n();
|
||||
const neListStore = useNeListStore();
|
||||
const emit = defineEmits(['ok', 'cancel', 'update:open']);
|
||||
const props = defineProps({
|
||||
open: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
/**网元类型_多neId */
|
||||
let neCascaderOptions = ref<Record<string, any>[]>([]);
|
||||
|
||||
/**对话框对象信息状态类型 */
|
||||
type ModalStateType = {
|
||||
/**新增框或修改框是否显示 */
|
||||
openByEdit: boolean;
|
||||
/**标题 */
|
||||
title: string;
|
||||
/**表单数据 */
|
||||
from: Record<string, any>;
|
||||
/**网元类型 */
|
||||
neType: string[];
|
||||
/**需要配置的网元列表 */
|
||||
toNe: {
|
||||
neType: string;
|
||||
neId: string;
|
||||
}[];
|
||||
/**提示信息 */
|
||||
msg: string;
|
||||
/**确定按钮 loading */
|
||||
confirmLoading: boolean;
|
||||
};
|
||||
|
||||
/**对话框对象信息状态 */
|
||||
let modalState: ModalStateType = reactive({
|
||||
openByEdit: false,
|
||||
title: 'PLMN Info',
|
||||
from: {
|
||||
plmnId: {
|
||||
mcc: '001',
|
||||
mnc: '01',
|
||||
},
|
||||
tac: '4388',
|
||||
snssai: {
|
||||
sst: '1',
|
||||
sd: '000001',
|
||||
},
|
||||
dnn_data: 'internet',
|
||||
dnn_ims: 'ims',
|
||||
},
|
||||
neType: [],
|
||||
toNe: [],
|
||||
msg: '',
|
||||
confirmLoading: false,
|
||||
});
|
||||
|
||||
/**对话框内表单属性和校验规则 */
|
||||
const modalStateFrom = Form.useForm(
|
||||
modalState.from.plmnId,
|
||||
reactive({
|
||||
mcc: [
|
||||
{
|
||||
required: true,
|
||||
message: t('common.inputPlease'),
|
||||
},
|
||||
],
|
||||
mnc: [
|
||||
{
|
||||
required: true,
|
||||
message: t('common.inputPlease'),
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
/**网元类型选择对应修改 */
|
||||
function fnNeChange(p: any, c: any) {
|
||||
let neList: { neType: string; neId: string }[] = [];
|
||||
for (let i = 0; i < p.length; i++) {
|
||||
const v = p[i];
|
||||
if (v.length === 1) {
|
||||
c[i][0].children.forEach((item: any) => {
|
||||
neList.push({
|
||||
neType: item.neType,
|
||||
neId: item.neId,
|
||||
});
|
||||
});
|
||||
} else if (v.length === 2) {
|
||||
neList.push({
|
||||
neType: v[0],
|
||||
neId: v[1],
|
||||
});
|
||||
}
|
||||
}
|
||||
if (neList.length > 0) {
|
||||
modalState.toNe = neList;
|
||||
} else {
|
||||
modalState.toNe = [];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 对话框弹出确认执行函数
|
||||
* 进行表达规则校验
|
||||
*/
|
||||
function fnModalOk() {
|
||||
if (modalState.confirmLoading) return;
|
||||
if (modalState.toNe.length === 0) {
|
||||
message.warning({
|
||||
content: 'Please select NE',
|
||||
duration: 3,
|
||||
});
|
||||
return;
|
||||
}
|
||||
const form = toRaw(modalState.from);
|
||||
// console.log(form);
|
||||
|
||||
modalStateFrom
|
||||
.validate()
|
||||
.then(async () => {
|
||||
modalState.confirmLoading = true;
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
let errArr = [];
|
||||
for (const item of modalState.toNe) {
|
||||
const err = await toConfig(item.neType, item.neId, form);
|
||||
if (err.length > 0) {
|
||||
errArr.push(...err);
|
||||
}
|
||||
}
|
||||
modalState.msg = errArr.join('\n');
|
||||
modalState.confirmLoading = false;
|
||||
emit('ok', JSON.parse(JSON.stringify(form)));
|
||||
hide();
|
||||
})
|
||||
.catch(e => {
|
||||
message.error(t('common.errorFields', { num: e.errorFields.length }), 3);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 对话框弹出关闭执行函数
|
||||
* 进行表达规则校验
|
||||
*/
|
||||
function fnModalCancel() {
|
||||
modalState.openByEdit = false;
|
||||
modalState.confirmLoading = false;
|
||||
modalStateFrom.resetFields();
|
||||
emit('cancel');
|
||||
emit('update:open', false);
|
||||
// 还原默认值
|
||||
modalState.from = {
|
||||
plmnId: {
|
||||
mcc: '001',
|
||||
mnc: '01',
|
||||
},
|
||||
tac: '4388',
|
||||
snssai: {
|
||||
sst: '1',
|
||||
sd: '000001',
|
||||
},
|
||||
dnn_data: 'internet',
|
||||
dnn_ims: 'ims',
|
||||
};
|
||||
modalState.neType = [];
|
||||
modalState.toNe = [];
|
||||
modalState.msg = '';
|
||||
}
|
||||
|
||||
/**监听是否显示,初始数据 */
|
||||
watch(
|
||||
() => props.open,
|
||||
val => {
|
||||
if (val) {
|
||||
// 获取网元网元列表
|
||||
neCascaderOptions.value = neListStore.getNeCascaderOptions.filter(
|
||||
(item: any) => {
|
||||
return ['MME', 'AMF', 'UDM', 'IMS'].includes(item.value); // 过滤不可用的网元
|
||||
}
|
||||
);
|
||||
if (neCascaderOptions.value.length === 0) {
|
||||
message.warning({
|
||||
content: t('common.noData'),
|
||||
duration: 3,
|
||||
});
|
||||
return;
|
||||
}
|
||||
modalState.openByEdit = true;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// =============== 处理函数
|
||||
|
||||
const supportMapper: Record<string, any> = {
|
||||
AMF: [
|
||||
{
|
||||
type: 'array',
|
||||
name: 'guami',
|
||||
display: 'GUAMI List',
|
||||
key: ['plmnId'],
|
||||
item: (index: any, param: any, lastItem: any) => {
|
||||
const plmn = `${param.plmnId.mcc}${param.plmnId.mnc}`;
|
||||
return {
|
||||
index: index,
|
||||
plmnId: plmn,
|
||||
pointer: lastItem.pointer,
|
||||
regionId: lastItem.regionId,
|
||||
setId: lastItem.setId,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'array',
|
||||
name: 'tai',
|
||||
display: 'TAI List',
|
||||
key: ['plmnId'],
|
||||
item: (index: any, param: any, lastItem: any) => {
|
||||
const plmn = `${param.plmnId.mcc}${param.plmnId.mnc}`;
|
||||
return {
|
||||
index: index,
|
||||
plmnId: plmn,
|
||||
tac: param.tac,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'array',
|
||||
name: 'slice',
|
||||
display: 'Slice List',
|
||||
key: ['plmnId'],
|
||||
item: (index: any, param: any, lastItem: any) => {
|
||||
const plmn = `${param.plmnId.mcc}${param.plmnId.mnc}`;
|
||||
const sdStr = param.snssai.sd.padStart(6, '0');
|
||||
return {
|
||||
index: index,
|
||||
plmnId: plmn,
|
||||
sst: parseInt(param.snssai.sst),
|
||||
sd: sdStr,
|
||||
};
|
||||
},
|
||||
},
|
||||
],
|
||||
IMS: [
|
||||
{
|
||||
type: 'array',
|
||||
name: 'plmn',
|
||||
display: 'PLMN List',
|
||||
key: ['mcc', 'mnc'],
|
||||
item: (index: any, param: any, lastItem: any) => {
|
||||
const plmn = `${param.plmnId.mcc}${param.plmnId.mnc}`;
|
||||
const mccDomain = param.plmnId.mcc.padStart(3, '0');
|
||||
const domain = `ims.mnc${param.plmnId.mnc}.mcc${mccDomain}.3gppnetwork.org`;
|
||||
return {
|
||||
index: index,
|
||||
domain: domain,
|
||||
mcc: param.plmnId.mcc,
|
||||
mnc: param.plmnId.mnc,
|
||||
};
|
||||
},
|
||||
},
|
||||
],
|
||||
UDM: [
|
||||
{
|
||||
type: 'list',
|
||||
name: 'system',
|
||||
display: 'System',
|
||||
key: [
|
||||
'supportedPlmn1',
|
||||
'supportedPlmn2',
|
||||
'supportedPlmn3',
|
||||
'supportedPlmn4',
|
||||
],
|
||||
},
|
||||
],
|
||||
MME: [
|
||||
{
|
||||
type: 'array',
|
||||
name: 'gummei',
|
||||
display: 'Gummei List',
|
||||
key: ['plmnId'],
|
||||
item: (index: any, param: any, lastItem: any) => {
|
||||
const plmn = `${param.plmnId.mcc}${param.plmnId.mnc}`;
|
||||
return Object.assign(lastItem, {
|
||||
index: index,
|
||||
plmnId: plmn,
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'array',
|
||||
name: 'tai',
|
||||
display: 'TAI List',
|
||||
key: ['plmnId'],
|
||||
item: (index: any, param: any, lastItem: any) => {
|
||||
const plmn = `${param.plmnId.mcc}${param.plmnId.mnc}`;
|
||||
return {
|
||||
index: index,
|
||||
plmnId: plmn,
|
||||
tac: parseInt(param.tac),
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'array',
|
||||
name: 'hss',
|
||||
display: 'HSS List',
|
||||
key: ['imsiPre'],
|
||||
item: (index: any, param: any, lastItem: any) => {
|
||||
const plmn = `${param.plmnId.mcc}${param.plmnId.mnc}`;
|
||||
return Object.assign(lastItem, {
|
||||
index: index,
|
||||
imsiPre: plmn,
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'array',
|
||||
name: 'sgw',
|
||||
display: 'SGW List',
|
||||
key: ['plmnId'],
|
||||
item: (index: any, param: any, lastItem: any) => {
|
||||
const plmn = `${param.plmnId.mcc}${param.plmnId.mnc}`;
|
||||
return Object.assign(lastItem, {
|
||||
index: index,
|
||||
plmnId: plmn,
|
||||
tac: parseInt(param.tac),
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
async function toConfig(
|
||||
ntType: string,
|
||||
neId: string,
|
||||
param: Record<string, any>
|
||||
) {
|
||||
let errMsgArr = [];
|
||||
const plmn = `${param.plmnId.mcc}${param.plmnId.mnc}`;
|
||||
for (const rule of supportMapper[ntType]) {
|
||||
const res = await getNeConfigData({
|
||||
neType: ntType,
|
||||
neId: neId,
|
||||
paramName: rule.name,
|
||||
});
|
||||
if (res.code != RESULT_CODE_SUCCESS) {
|
||||
// console.log('获取数据失败', rule);
|
||||
errMsgArr.push(`${ntType}_${neId} ${rule.display} get data failed`);
|
||||
continue;
|
||||
}
|
||||
if (res.data.length === 0) {
|
||||
// console.log('数据为空', rule);
|
||||
errMsgArr.push(`${ntType}_${neId} ${rule.display} data empty`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rule.type === 'list') {
|
||||
// key
|
||||
const data = res.data[0];
|
||||
let vArr = [];
|
||||
for (const k of rule.key) {
|
||||
vArr.push(data[k]);
|
||||
}
|
||||
if (vArr.includes(plmn)) {
|
||||
// console.log('存在跳过', rule.name, vArr, plmn);
|
||||
errMsgArr.push(`${ntType}_${neId} ${rule.display} already exists`);
|
||||
continue;
|
||||
}
|
||||
if (vArr.includes('')) {
|
||||
const index = vArr.findIndex(s => s == '');
|
||||
// console.log('空白新增', rule.name, rule.key[index], plmn);
|
||||
const resList = await editNeConfigData({
|
||||
neType: ntType,
|
||||
neId: neId,
|
||||
paramName: rule.name,
|
||||
paramData: {
|
||||
[rule.key[index]]: plmn,
|
||||
},
|
||||
});
|
||||
const state =
|
||||
resList.code != RESULT_CODE_SUCCESS ? 'failed' : 'success';
|
||||
errMsgArr.push(
|
||||
`${ntType}_${neId} ${rule.display} blank items added ${state}`
|
||||
);
|
||||
} else {
|
||||
// console.log(
|
||||
// '不存在替换最后的',
|
||||
// rule.name,
|
||||
// rule.key[rule.key.length - 1],
|
||||
// plmn
|
||||
// );
|
||||
const resList = await editNeConfigData({
|
||||
neType: ntType,
|
||||
neId: neId,
|
||||
paramName: rule.name,
|
||||
paramData: {
|
||||
[rule.key[rule.key.length - 1]]: plmn,
|
||||
},
|
||||
});
|
||||
const state =
|
||||
resList.code != RESULT_CODE_SUCCESS ? 'failed' : 'success';
|
||||
errMsgArr.push(
|
||||
`${ntType}_${neId} ${rule.display} replace the final ${state}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (rule.type === 'array') {
|
||||
// item
|
||||
let vArr = [];
|
||||
for (const item of res.data) {
|
||||
vArr.push(item[rule.key]);
|
||||
}
|
||||
if (vArr.includes(plmn)) {
|
||||
const item = res.data.find((s: any) => s[rule.key] == plmn);
|
||||
if (!item) {
|
||||
// console.log('没有找到', rule.name, index);
|
||||
errMsgArr.push(`${ntType}_${neId} ${rule.display} not found`);
|
||||
continue;
|
||||
}
|
||||
const index = item.index;
|
||||
const updateItem = rule.item(index, param, item);
|
||||
// console.log('存在修改', rule.name, index, updateItem);
|
||||
const resList = await editNeConfigData({
|
||||
neType: ntType,
|
||||
neId: neId,
|
||||
paramName: rule.name,
|
||||
paramData: updateItem,
|
||||
loc: `${index}`,
|
||||
});
|
||||
const state =
|
||||
resList.code != RESULT_CODE_SUCCESS ? 'failed' : 'success';
|
||||
errMsgArr.push(`${ntType}_${neId} ${rule.display} modify ${state}`);
|
||||
} else {
|
||||
let lastIndex = 0;
|
||||
const arr = res.data.sort((a: any, b: any) => b.index - a.index);
|
||||
if (arr.length != 0) {
|
||||
lastIndex = arr[0].index + 1;
|
||||
}
|
||||
const addItem = rule.item(lastIndex, param, arr[0]);
|
||||
// console.log('不存在新增', rule.name, lastIndex, addItem);
|
||||
const resList = await addNeConfigData({
|
||||
neType: ntType,
|
||||
neId: neId,
|
||||
paramName: rule.name,
|
||||
paramData: addItem,
|
||||
loc: `${lastIndex}`,
|
||||
});
|
||||
const state =
|
||||
resList.code != RESULT_CODE_SUCCESS ? 'failed' : 'success';
|
||||
errMsgArr.push(`${ntType}_${neId} ${rule.display} added ${state}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
return errMsgArr;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProModal
|
||||
:drag="true"
|
||||
:width="800"
|
||||
:destroyOnClose="true"
|
||||
:keyboard="false"
|
||||
:mask-closable="false"
|
||||
:open="modalState.openByEdit"
|
||||
:title="modalState.title"
|
||||
:confirm-loading="modalState.confirmLoading"
|
||||
@ok="fnModalOk"
|
||||
@cancel="fnModalCancel"
|
||||
>
|
||||
<a-form
|
||||
name="modalStateFromByEdit"
|
||||
layout="horizontal"
|
||||
:label-col="{ span: 6 }"
|
||||
:label-wrap="true"
|
||||
>
|
||||
<a-row>
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
<a-form-item label="DNN_DATA" name="basic.dnn_data" v-if="false">
|
||||
<a-input
|
||||
v-model:value="modalState.from.dnn_data"
|
||||
allow-clear
|
||||
:placeholder="t('common.inputPlease')"
|
||||
:maxlength="50"
|
||||
>
|
||||
<template #prefix>
|
||||
<a-tooltip placement="topLeft">
|
||||
<template #title> DNN </template>
|
||||
<InfoCircleOutlined style="opacity: 0.45; color: inherit" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="MCC"
|
||||
name="basic.plmnId.mcc"
|
||||
v-bind="modalStateFrom.validateInfos.mcc"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="modalState.from.plmnId.mcc"
|
||||
placeholder="1-65535"
|
||||
></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="SST" name="basic.snssai.sst">
|
||||
<a-input-number
|
||||
v-model:value="modalState.from.snssai.sst"
|
||||
:min="1"
|
||||
:max="3"
|
||||
placeholder="1-3"
|
||||
style="width: 100%"
|
||||
>
|
||||
</a-input-number>
|
||||
</a-form-item>
|
||||
<a-form-item label="TAC" name="basic.tac">
|
||||
<a-input
|
||||
v-model:value="modalState.from.tac"
|
||||
placeholder="1-65535"
|
||||
></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
<a-form-item label="DNN_IMS" name="basic.dnn_ims" v-if="false">
|
||||
<a-input
|
||||
v-model:value="modalState.from.dnn_ims"
|
||||
allow-clear
|
||||
:placeholder="t('common.inputPlease')"
|
||||
:maxlength="50"
|
||||
>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="MNC"
|
||||
name="basic.plmnId.mnc"
|
||||
v-bind="modalStateFrom.validateInfos.mnc"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="modalState.from.plmnId.mnc"
|
||||
placeholder="1-65535"
|
||||
></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item label="SD" name="basic.snssai.sd">
|
||||
<a-input
|
||||
v-model:value="modalState.from.snssai.sd"
|
||||
placeholder="1-65535"
|
||||
></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-divider orientation="left">To NE</a-divider>
|
||||
|
||||
<a-form-item
|
||||
:label="t('views.ne.common.neType')"
|
||||
name="neType"
|
||||
:label-col="{ span: 3 }"
|
||||
:label-wrap="true"
|
||||
>
|
||||
<a-cascader
|
||||
v-model:value="modalState.neType"
|
||||
:options="neCascaderOptions"
|
||||
@change="fnNeChange"
|
||||
multiple
|
||||
:allow-clear="false"
|
||||
:placeholder="t('views.ne.common.neTypePlease')"
|
||||
/>
|
||||
<a-textarea
|
||||
:disabled="true"
|
||||
:hidden="!modalState.msg"
|
||||
:value="modalState.msg"
|
||||
:auto-size="{ minRows: 2, maxRows: 8 }"
|
||||
style="margin-top: 8px"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</ProModal>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
@@ -24,7 +24,7 @@ export default function useArrayImport({
|
||||
fileetx: '.xlsx',
|
||||
itemKey: 'index',
|
||||
item: (row: Record<string, any>) => {
|
||||
const index = row['Index'] || 0;
|
||||
const index = row['Index'] ?? -1;
|
||||
return {
|
||||
imeiPrefixValue: `${row['IMEI Prefix']}`,
|
||||
index: parseInt(index),
|
||||
@@ -36,7 +36,7 @@ export default function useArrayImport({
|
||||
fileetx: '.xlsx',
|
||||
itemKey: 'index',
|
||||
item: (row: Record<string, any>) => {
|
||||
const index = row['Index'] || 0;
|
||||
const index = row['Index'] ?? -1;
|
||||
return {
|
||||
imsiValue: `${row['IMSI Value']}`,
|
||||
imeiValue: `${row['IMEI Value/Prefix']}`,
|
||||
@@ -51,7 +51,7 @@ export default function useArrayImport({
|
||||
fileetx: '.xlsx',
|
||||
itemKey: 'index',
|
||||
item: (row: Record<string, any>) => {
|
||||
const index = row['Index'] || 0;
|
||||
const index = row['Index'] ?? -1;
|
||||
return {
|
||||
imei: `${row['IMEI']}`,
|
||||
index: parseInt(index),
|
||||
@@ -128,7 +128,7 @@ export default function useArrayImport({
|
||||
importState.loading = true;
|
||||
for (const row of rows) {
|
||||
const rowItem = importState.item(row);
|
||||
const rowKey = rowItem[importState.itemKey] || -1;
|
||||
const rowKey = rowItem[importState.itemKey];
|
||||
let result: any = null;
|
||||
// 检查index是否定义
|
||||
const has = arrayState.columnsData.find(
|
||||
|
||||
@@ -29,8 +29,13 @@ export default function useOptions({ t }: any) {
|
||||
case 'int':
|
||||
// filter: "0~128"
|
||||
|
||||
if (filter && filter.indexOf('~') !== -1) {
|
||||
const filterArr = filter.split('~');
|
||||
if (filter) {
|
||||
let filterArr = ['0', '1'];
|
||||
if (filter.indexOf('-') !== -1) {
|
||||
filterArr = filter.split('-');
|
||||
} else if (filter.indexOf('~') !== -1) {
|
||||
filterArr = filter.split('~');
|
||||
}
|
||||
const minInt = parseInt(filterArr[0]);
|
||||
const maxInt = parseInt(filterArr[1]);
|
||||
const valueInt = parseInt(value);
|
||||
@@ -47,18 +52,12 @@ export default function useOptions({ t }: any) {
|
||||
break;
|
||||
case 'ipv4':
|
||||
if (!regExpIPv4.test(value)) {
|
||||
return [
|
||||
false,
|
||||
t('views.ne.neConfig.requireIpv4', { display }),
|
||||
];
|
||||
return [false, t('views.ne.neConfig.requireIpv4', { display })];
|
||||
}
|
||||
break;
|
||||
case 'ipv6':
|
||||
if (!regExpIPv6.test(value)) {
|
||||
return [
|
||||
false,
|
||||
t('views.ne.neConfig.requireIpv6', { display }),
|
||||
];
|
||||
return [false, t('views.ne.neConfig.requireIpv6', { display })];
|
||||
}
|
||||
break;
|
||||
case 'enum':
|
||||
@@ -71,10 +70,7 @@ export default function useOptions({ t }: any) {
|
||||
}
|
||||
|
||||
if (!Object.keys(filterJson).includes(`${value}`)) {
|
||||
return [
|
||||
false,
|
||||
t('views.ne.neConfig.requireEnum', { display }),
|
||||
];
|
||||
return [false, t('views.ne.neConfig.requireEnum', { display })];
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -90,10 +86,7 @@ export default function useOptions({ t }: any) {
|
||||
}
|
||||
|
||||
if (!Object.values(filterJson).includes(`${value}`)) {
|
||||
return [
|
||||
false,
|
||||
t('views.ne.neConfig.requireBool', { display }),
|
||||
];
|
||||
return [false, t('views.ne.neConfig.requireBool', { display })];
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -101,12 +94,20 @@ export default function useOptions({ t }: any) {
|
||||
// filter: "0~128"
|
||||
|
||||
// 字符串长度判断
|
||||
if (filter && filter.indexOf('~') !== -1) {
|
||||
if (filter) {
|
||||
try {
|
||||
const filterArr = filter.split('~');
|
||||
let rule = new RegExp(
|
||||
'^\\S{' + filterArr[0] + ',' + filterArr[1] + '}$'
|
||||
);
|
||||
let rule: RegExp = new RegExp('^.*$');
|
||||
if (filter.indexOf('-') !== -1) {
|
||||
const filterArr = filter.split('-');
|
||||
rule = new RegExp(
|
||||
'^.{' + filterArr[0] + ',' + filterArr[1] + '}$'
|
||||
);
|
||||
} else if (filter.indexOf('~') !== -1) {
|
||||
const filterArr = filter.split('~');
|
||||
rule = new RegExp(
|
||||
'^\\S{' + filterArr[0] + ',' + filterArr[1] + '}$'
|
||||
);
|
||||
}
|
||||
if (!rule.test(value)) {
|
||||
return [
|
||||
false,
|
||||
@@ -157,10 +158,7 @@ export default function useOptions({ t }: any) {
|
||||
break;
|
||||
|
||||
default:
|
||||
return [
|
||||
false,
|
||||
t('views.ne.neConfig.requireUn', { display }),
|
||||
];
|
||||
return [false, t('views.ne.neConfig.requireUn', { display })];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { message } from 'ant-design-vue/es';
|
||||
import { DataNode } from 'ant-design-vue/es/tree';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
import TableColumnsDnd from '@/components/TableColumnsDnd/index.vue';
|
||||
import QuickSetup from './components/QuickSetup.vue';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import useNeListStore from '@/store/modules/ne_list';
|
||||
import useOptions from './hooks/useOptions';
|
||||
@@ -208,7 +209,7 @@ function fnActiveConfigNode(key: string | number) {
|
||||
|
||||
/**查询配置可选属性值列表 */
|
||||
function fnGetNeConfig() {
|
||||
const neType = neTypeSelect.value[0];
|
||||
const [neType, neId] = neTypeSelect.value ;
|
||||
if (!neType) {
|
||||
message.warning({
|
||||
content: t('views.ne.neConfig.neTypePleace'),
|
||||
@@ -219,7 +220,7 @@ function fnGetNeConfig() {
|
||||
|
||||
treeState.loading = true;
|
||||
// 获取数据
|
||||
getAllNeConfig(neType).then(res => {
|
||||
getAllNeConfig(neType, neId).then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||
const arr = [];
|
||||
for (const item of res.data) {
|
||||
@@ -391,6 +392,12 @@ const { batchState, modalBatchOpen, modalBatchClose, modalBatchOk } =
|
||||
fnActiveConfigNode,
|
||||
});
|
||||
|
||||
/**快速修改编辑框 */
|
||||
const quickOpen = ref(false);
|
||||
function fnQuickOpen() {
|
||||
quickOpen.value = !quickOpen.value;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 获取网元网元列表
|
||||
neCascaderOptions.value = neListStore.getNeCascaderOptions.filter(
|
||||
@@ -430,6 +437,13 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<PageContainer>
|
||||
<template #content> </template>
|
||||
<template #contentExtra>
|
||||
<a-button type="primary" @click="fnQuickOpen">
|
||||
Quickly Modify PLMN
|
||||
</a-button>
|
||||
</template>
|
||||
|
||||
<a-row :gutter="16">
|
||||
<a-col
|
||||
:lg="6"
|
||||
@@ -1053,6 +1067,9 @@ onMounted(() => {
|
||||
</a-row>
|
||||
</a-form>
|
||||
</ProModal>
|
||||
|
||||
<!-- 快速修改 -->
|
||||
<QuickSetup v-model:open="quickOpen"></QuickSetup>
|
||||
</PageContainer>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -73,12 +73,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns = ref<TableColumnsType>([
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'left',
|
||||
// width: 100,
|
||||
// },
|
||||
{
|
||||
title: t('views.ne.common.neType'),
|
||||
dataIndex: 'neType',
|
||||
@@ -303,12 +303,8 @@ function fnModalVisibleByEdit(row: Record<string, any>) {
|
||||
const modalStateFrom = Form.useForm(
|
||||
modalState.from,
|
||||
reactive({
|
||||
name: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入名称',
|
||||
},
|
||||
],
|
||||
name: [{ required: true, message: t('common.inputPlease') }],
|
||||
remark: [{ required: true, message: t('common.inputPlease') }],
|
||||
})
|
||||
);
|
||||
|
||||
@@ -462,7 +458,11 @@ function fnSyncFileToFTP(row: Record<string, any>) {
|
||||
<template #title>
|
||||
{{ t('views.ne.neConfigBackup.backupModal.title') }}
|
||||
</template>
|
||||
<a-button type="text" @click.prevent="fnFTPModalOpen()">
|
||||
<a-button
|
||||
type="text"
|
||||
@click.prevent="fnFTPModalOpen()"
|
||||
v-perms:has="['ne:neConfigBackup:ftp']"
|
||||
>
|
||||
<template #icon><DeliveredProcedureOutlined /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
@@ -524,13 +524,21 @@ function fnSyncFileToFTP(row: Record<string, any>) {
|
||||
<template #title>
|
||||
{{ t('views.ne.neConfigBackup.backupModal.pushFileOper') }}
|
||||
</template>
|
||||
<a-button type="link" @click.prevent="fnSyncFileToFTP(record)">
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnSyncFileToFTP(record)"
|
||||
v-perms:has="['ne:neConfigBackup:ftpSync']"
|
||||
>
|
||||
<template #icon><CloudServerOutlined /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.downloadText') }}</template>
|
||||
<a-button type="link" @click.prevent="fnDownloadFile(record)">
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnDownloadFile(record)"
|
||||
v-perms:has="['ne:neConfigBackup:download']"
|
||||
>
|
||||
<template #icon><DownloadOutlined /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
|
||||
@@ -30,7 +30,7 @@ let neIdSelect = ref<string[]>([]);
|
||||
let neTypeSelectStatus = ref(true);
|
||||
/**网元类型neType选择 */
|
||||
async function fnSelectNeType(_: any, info: any) {
|
||||
if (!info) return;
|
||||
if (!info) return;
|
||||
await fnGetNeConfig(info.value);
|
||||
if (treeState.data.length === 0) {
|
||||
message.warning({
|
||||
@@ -226,7 +226,8 @@ async function fnGetNeConfig(neType: string) {
|
||||
|
||||
treeState.loading = true;
|
||||
// 获取数据
|
||||
const res = await getAllNeConfig(neType);
|
||||
let neId = neTypeSelect.value[1];
|
||||
const res = await getAllNeConfig(neType, neId);
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
const arr = [];
|
||||
for (const v of res.data) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import useNeListStore from '@/store/modules/ne_list';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
import ViewDrawer from './components/ViewDrawer.vue';
|
||||
import BackupModal from '@/views/ne/neConfigBackup/components/BackupModal.vue';
|
||||
import saveAs from 'file-saver';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { parseSizeFromFile } from '@/utils/parse-utils';
|
||||
@@ -282,6 +283,12 @@ function fnDrawerOpen(row: Record<string, any>) {
|
||||
viewDrawerState.open = !viewDrawerState.open;
|
||||
}
|
||||
|
||||
/**打开FTP配置窗口 */
|
||||
const openFTPModal = ref<boolean>(false);
|
||||
function fnFTPModalOpen() {
|
||||
openFTPModal.value = !openFTPModal.value;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (routeParams.neType) {
|
||||
neTypeSelect.value = [routeParams.neType, routeParams.neId];
|
||||
@@ -327,6 +334,18 @@ onMounted(() => {
|
||||
<!-- 插槽-卡片右侧 -->
|
||||
<template #extra>
|
||||
<a-space :size="8" align="center">
|
||||
<a-tooltip placement="topRight">
|
||||
<template #title>
|
||||
{{ t('views.ne.neConfigBackup.backupModal.title') }}
|
||||
</template>
|
||||
<a-button
|
||||
type="text"
|
||||
@click.prevent="fnFTPModalOpen()"
|
||||
v-perms:has="['ne-data:backup-data:ftp']"
|
||||
>
|
||||
<template #icon><DeliveredProcedureOutlined /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.reloadText') }}</template>
|
||||
<a-button type="text" @click.prevent="fnGetList()">
|
||||
@@ -387,6 +406,9 @@ onMounted(() => {
|
||||
:ne-type="viewDrawerState.neType"
|
||||
:ne-id="viewDrawerState.neId"
|
||||
></ViewDrawer>
|
||||
|
||||
<!-- FTP配置窗口 -->
|
||||
<BackupModal v-model:open="openFTPModal"></BackupModal>
|
||||
</PageContainer>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -80,12 +80,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns: ColumnsType = [
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'center',
|
||||
width: 50,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'center',
|
||||
// width: 50,
|
||||
// },
|
||||
{
|
||||
title: t('views.ne.neHost.hostType'),
|
||||
dataIndex: 'hostType',
|
||||
|
||||
@@ -78,12 +78,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns: ColumnsType = [
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'cmdId',
|
||||
align: 'center',
|
||||
width: 50,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'cmdId',
|
||||
// align: 'center',
|
||||
// width: 50,
|
||||
// },
|
||||
{
|
||||
title: t('views.ne.neHostCmd.cmdType'),
|
||||
dataIndex: 'cmdType',
|
||||
|
||||
@@ -636,10 +636,10 @@ onMounted(() => {
|
||||
</a-form-item>
|
||||
|
||||
<!-- 主机连接配置 -->
|
||||
<a-divider orientation="left">
|
||||
<a-divider orientation="left" v-if="false">
|
||||
{{ t('views.ne.neInfo.hostConfig') }}
|
||||
</a-divider>
|
||||
<a-collapse class="collapse" ghost>
|
||||
<a-collapse class="collapse" ghost v-if="false">
|
||||
<a-collapse-panel
|
||||
v-for="host in modalState.from.hosts.filter(
|
||||
(s:any) => !(s.hostType === 'telnet' && modalState.from.neType === 'OMC')
|
||||
|
||||
@@ -0,0 +1,435 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, toRaw, watch, ref } from 'vue';
|
||||
import { ProModal } from 'antdv-pro-modal';
|
||||
import { message, Form, Progress } from 'ant-design-vue/es';
|
||||
import { CheckCircleOutlined, CloseCircleOutlined } from '@ant-design/icons-vue';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import { getOAMFile, saveOAMFile, serviceNeAction } from '@/api/ne/neInfo';
|
||||
import useNeListStore from '@/store/modules/ne_list';
|
||||
|
||||
const { t } = useI18n();
|
||||
const neListStore = useNeListStore();
|
||||
const emit = defineEmits(['ok', 'cancel', 'update:open']);
|
||||
|
||||
const props = defineProps({
|
||||
open: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
/**对话框对象信息状态类型 */
|
||||
type ModalStateType = {
|
||||
/**是否显示 */
|
||||
openByEdit: boolean;
|
||||
/**标题 */
|
||||
title: string;
|
||||
/**表单数据 */
|
||||
from: {
|
||||
selectedNeList: string[];
|
||||
omcIP: string;
|
||||
oamPort: number;
|
||||
restart: boolean;
|
||||
};
|
||||
/**确定按钮 loading */
|
||||
confirmLoading: boolean;
|
||||
/**进度显示 */
|
||||
progress: {
|
||||
visible: boolean;
|
||||
current: number;
|
||||
total: number;
|
||||
currentNe: string;
|
||||
};
|
||||
/**操作结果 */
|
||||
results: Array<{
|
||||
neType: string;
|
||||
neId: string;
|
||||
neName: string;
|
||||
success: boolean;
|
||||
message: string;
|
||||
}>;
|
||||
};
|
||||
|
||||
/**对话框对象信息状态 */
|
||||
let modalState: ModalStateType = reactive({
|
||||
openByEdit: false,
|
||||
title: '快速OAM配置',
|
||||
from: {
|
||||
selectedNeList: [],
|
||||
omcIP: '127.0.0.1',
|
||||
oamPort: 33030,
|
||||
restart: false,
|
||||
},
|
||||
confirmLoading: false,
|
||||
progress: {
|
||||
visible: false,
|
||||
current: 0,
|
||||
total: 0,
|
||||
currentNe: '',
|
||||
},
|
||||
results: [],
|
||||
});
|
||||
|
||||
/**对话框内表单属性和校验规则 */
|
||||
const modalStateFrom = Form.useForm(
|
||||
modalState.from,
|
||||
reactive({
|
||||
selectedNeList: [
|
||||
{
|
||||
required: true,
|
||||
message: t('views.ne.neInfo.quickOam.selectNe'),
|
||||
},
|
||||
],
|
||||
omcIP: [
|
||||
{
|
||||
required: true,
|
||||
|
||||
},
|
||||
{
|
||||
pattern: /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/,
|
||||
|
||||
},
|
||||
],
|
||||
oamPort: [
|
||||
{
|
||||
required: true,
|
||||
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
/**获取网元列表选项 */
|
||||
const neOptions = ref<Array<{ label: string; value: string; neType: string; neId: string; neName: string }>>([]);
|
||||
|
||||
/**
|
||||
* 初始化网元选项
|
||||
*/
|
||||
async function initNeOptions() {
|
||||
// 确保网元列表已加载
|
||||
await neListStore.fnNelistRefresh();
|
||||
// 从store获取网元列表,过滤掉OMC类型
|
||||
const neList = neListStore.getNeList.filter((ne: any) => ne.neType !== 'OMC');
|
||||
neOptions.value = neList.map((ne: any) => ({
|
||||
label: `${ne.neType}-${ne.neId} (${ne.neName})`,
|
||||
value: `${ne.neType}@${ne.neId}`,
|
||||
neType: ne.neType,
|
||||
neId: ne.neId,
|
||||
neName: ne.neName,
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* 单个网元OAM配置(复用OAMModal的逻辑)
|
||||
* @param neType 网元类型
|
||||
* @param neId 网元ID
|
||||
* @param omcIP OMC IP地址
|
||||
* @param oamPort OAM端口
|
||||
* @param restart 是否重启网元
|
||||
* @returns Promise<{success: boolean, message: string}>
|
||||
*/
|
||||
async function configureSingleNeOAM(neType: string, neId: string, omcIP: string, oamPort: number, restart: boolean = false) {
|
||||
try {
|
||||
// 1. 获取当前OAM配置(复用OAMModal的获取逻辑)
|
||||
const getRes = await getOAMFile(neType, neId);
|
||||
|
||||
if (getRes.code !== RESULT_CODE_SUCCESS) {
|
||||
return {
|
||||
success: false,
|
||||
message: `${getRes.msg}`,
|
||||
};
|
||||
}
|
||||
|
||||
// 2. 构建保存数据(复用OAMModal的数据结构转换逻辑)
|
||||
const data = getRes.data;
|
||||
const ipType = data?.oamConfig?.ipType || 'ipv4';
|
||||
|
||||
const saveContent = {
|
||||
omcIP: omcIP,
|
||||
oamEnable: data?.oamConfig?.enable || false,
|
||||
oamPort: oamPort,
|
||||
snmpEnable: data?.snmpConfig?.enable || false,
|
||||
snmpPort: data?.snmpConfig?.port || 4957,
|
||||
kpiEnable: data?.kpiConfig?.enable || false,
|
||||
kpiTimer: data?.kpiConfig?.timer || 60,
|
||||
};
|
||||
|
||||
// 3. 保存配置(复用OAMModal的保存逻辑)
|
||||
const saveRes = await saveOAMFile({
|
||||
neType,
|
||||
neId,
|
||||
content: saveContent,
|
||||
sync: true,
|
||||
});
|
||||
|
||||
if (saveRes.code === RESULT_CODE_SUCCESS) {
|
||||
// 如果需要重启网元,调用重启服务(复用OAMModal的重启逻辑)
|
||||
if (restart) {
|
||||
try {
|
||||
await serviceNeAction({
|
||||
neType,
|
||||
neId,
|
||||
action: 'restart',
|
||||
});
|
||||
} catch (restartError: any) {
|
||||
return {
|
||||
success: true,
|
||||
message: `${restartError.message || restartError}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: restart ? `${t('views.ne.neInfo.quickOam.success')}` : `${t('views.ne.neInfo.quickOam.success')}`,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
success: false,
|
||||
message: `${saveRes.msg}`,
|
||||
};
|
||||
}
|
||||
} catch (error: any) {
|
||||
return {
|
||||
success: false,
|
||||
message: `${error.message || error}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对话框弹出确认执行函数
|
||||
* 进行表达规则校验
|
||||
*/
|
||||
async function fnModalOk() {
|
||||
try {
|
||||
await modalStateFrom.validate();
|
||||
|
||||
modalState.confirmLoading = true;
|
||||
modalState.progress.visible = true;
|
||||
modalState.progress.current = 0;
|
||||
modalState.progress.total = modalState.from.selectedNeList.length;
|
||||
modalState.results = [];
|
||||
|
||||
const { omcIP, oamPort, restart } = modalState.from;
|
||||
|
||||
// 循环处理每个选中的网元
|
||||
for (let i = 0; i < modalState.from.selectedNeList.length; i++) {
|
||||
const neInfo = modalState.from.selectedNeList[i];
|
||||
const [neType, neId] = neInfo.split('@');
|
||||
const neName = neOptions.value.find(opt => opt.value === neInfo)?.neName || neId;
|
||||
|
||||
modalState.progress.current = i + 1;
|
||||
modalState.progress.currentNe = `${neType}-${neId}`;
|
||||
|
||||
// 调用单个网元配置函数
|
||||
const result = await configureSingleNeOAM(neType, neId, omcIP, oamPort, restart);
|
||||
|
||||
modalState.results.push({
|
||||
neType,
|
||||
neId,
|
||||
neName,
|
||||
success: result.success,
|
||||
message: result.message,
|
||||
});
|
||||
}
|
||||
|
||||
// 显示操作结果
|
||||
const successCount = modalState.results.filter(r => r.success).length;
|
||||
const failCount = modalState.results.length - successCount;
|
||||
|
||||
if (failCount === 0) {
|
||||
message.success(`${t('views.ne.neInfo.quickOam.success')} ${successCount} `, 5);
|
||||
} else {
|
||||
message.warning(`${t('views.ne.neInfo.quickOam.success')} ${successCount} ,${t('views.ne.neInfo.quickOam.default')} ${failCount} `, 5);
|
||||
}
|
||||
|
||||
// 不自动关闭弹窗,让用户查看结果
|
||||
// emit('ok');
|
||||
// fnModalCancel();
|
||||
} catch (error: any) {
|
||||
message.error(t('common.errorFields', { num: error.errorFields?.length || 0 }), 3);
|
||||
} finally {
|
||||
modalState.confirmLoading = false;
|
||||
modalState.progress.visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对话框弹出关闭执行函数
|
||||
*/
|
||||
function fnModalCancel() {
|
||||
modalState.openByEdit = false;
|
||||
modalState.confirmLoading = false;
|
||||
modalState.progress.visible = false;
|
||||
modalState.progress.current = 0;
|
||||
modalState.progress.total = 0;
|
||||
modalState.progress.currentNe = '';
|
||||
modalState.results = [];
|
||||
modalStateFrom.resetFields();
|
||||
emit('cancel');
|
||||
emit('update:open', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动关闭弹窗(用于操作完成后)
|
||||
*/
|
||||
function fnModalClose() {
|
||||
fnModalCancel();
|
||||
}
|
||||
|
||||
/**监听是否显示,初始数据 */
|
||||
watch(
|
||||
() => props.open,
|
||||
val => {
|
||||
if (val) {
|
||||
initNeOptions();
|
||||
modalState.title = t('views.ne.neInfo.quickOam.title');
|
||||
modalState.openByEdit = true;
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProModal
|
||||
:drag="true"
|
||||
:destroyOnClose="true"
|
||||
:body-style="{ maxHeight: '600px', 'overflow-y': 'auto' }"
|
||||
:keyboard="false"
|
||||
:mask-closable="false"
|
||||
:open="modalState.openByEdit"
|
||||
:title="modalState.title"
|
||||
:confirm-loading="modalState.confirmLoading"
|
||||
:width='500'
|
||||
@ok="fnModalOk"
|
||||
@cancel="fnModalCancel"
|
||||
>
|
||||
<a-form
|
||||
name="modalStateFrom"
|
||||
layout="horizontal"
|
||||
:label-col="{ span: 8 }"
|
||||
:labelWrap="true"
|
||||
>
|
||||
<a-form-item
|
||||
:label="t('views.ne.neInfo.oam.restart')"
|
||||
name="restart"
|
||||
>
|
||||
<a-switch
|
||||
:checked-children="t('common.switch.open')"
|
||||
:un-checked-children="t('common.switch.shut')"
|
||||
v-model:checked="modalState.from.restart"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
:label="t('views.ne.neInfo.quickOam.omcIP')"
|
||||
name="omcIP"
|
||||
v-bind="modalStateFrom.validateInfos.omcIP"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="modalState.from.omcIP"
|
||||
:maxlength="128"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
:label="t('views.ne.neInfo.quickOam.oamPort')"
|
||||
name="oamPort"
|
||||
v-bind="modalStateFrom.validateInfos.oamPort"
|
||||
>
|
||||
<a-input-number
|
||||
v-model:value="modalState.from.oamPort"
|
||||
:min="3000"
|
||||
:max="65535"
|
||||
:step="1"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
:label="t('views.ne.neInfo.quickOam.selectNe')"
|
||||
name="selectedNeList"
|
||||
v-bind="modalStateFrom.validateInfos.selectedNeList"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="modalState.from.selectedNeList"
|
||||
mode="multiple"
|
||||
:options="neOptions"
|
||||
:placeholder="t('common.selectPlease')"
|
||||
:max-tag-count="3"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- 进度显示 -->
|
||||
<div v-if="modalState.progress.visible || modalState.results.length > 0" style="margin-top: 20px;">
|
||||
<a-divider>{{ t('views.ne.neInfo.quickOam.progress') }}</a-divider>
|
||||
<div style="margin-bottom: 10px;">
|
||||
<span>{{ t('views.ne.neInfo.quickOam.processing') }}: {{ modalState.progress.currentNe }}</span>
|
||||
<span style="float: right;">
|
||||
{{ modalState.progress.current }} / {{ modalState.progress.total }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- <Progress-->
|
||||
<!-- :percent="Math.round((modalState.progress.current / modalState.progress.total) * 100)"-->
|
||||
<!-- :status="modalState.progress.current === modalState.progress.total ? 'success' : 'active'"-->
|
||||
<!-- :show-info="false"-->
|
||||
<!-- style="overflow: hidden;"-->
|
||||
<!-- />-->
|
||||
<div style="width: 100%; overflow: hidden;">
|
||||
<Progress
|
||||
:percent="Math.round((modalState.progress.current / modalState.progress.total) * 100)"
|
||||
:status="modalState.progress.current === modalState.progress.total ? 'success' : 'active'"
|
||||
:show-info="false"
|
||||
style="width: 100%;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 操作结果 -->
|
||||
<div v-if="modalState.results.length > 0" style="margin-top: 20px;">
|
||||
<a-divider>{{ t('views.ne.neInfo.quickOam.result') }}</a-divider>
|
||||
<div style="max-height: 200px; overflow-y: auto;">
|
||||
<!-- 只显示失败的网元 -->
|
||||
<div
|
||||
v-for="(result, index) in modalState.results.filter(r => !r.success)"
|
||||
:key="index"
|
||||
style="margin-bottom: 8px; padding: 8px; border-radius: 4px;"
|
||||
:style="{
|
||||
backgroundColor: '#fff2f0',
|
||||
border: '1px solid #ffccc7',
|
||||
}"
|
||||
>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<span>
|
||||
<CloseCircleOutlined
|
||||
:style="{ color: '#ff4d4f', marginRight: '8px' }"
|
||||
/>
|
||||
{{ result.neType }}-{{ result.neId }} ({{ result.neName }})
|
||||
</span>
|
||||
<span :style="{ color: '#ff4d4f', fontSize: '12px' }">
|
||||
{{ result.message }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 如果没有失败的网元,显示提示信息 -->
|
||||
<div
|
||||
v-if="modalState.results.filter(r => !r.success).length === 0"
|
||||
style="text-align: center; padding: 20px; color: #52c41a;"
|
||||
>
|
||||
<CheckCircleOutlined :style="{ marginRight: '8px' }" />
|
||||
{{ t('views.ne.neInfo.quickOam.allsuccess') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ProModal>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ant-progress-text {
|
||||
color: #1890ff;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, onMounted, toRaw, defineAsyncComponent, ref } from 'vue';
|
||||
import {
|
||||
reactive,
|
||||
onMounted,
|
||||
toRaw,
|
||||
defineAsyncComponent,
|
||||
ref,
|
||||
computed,
|
||||
} from 'vue';
|
||||
import { PageContainer } from 'antdv-pro-layout';
|
||||
import { message, Modal } from 'ant-design-vue/es';
|
||||
import { SizeType } from 'ant-design-vue/es/config-provider';
|
||||
@@ -11,6 +18,7 @@ import useNeListStore from '@/store/modules/ne_list';
|
||||
import { listNeInfo, delNeInfo, stateNeInfo } from '@/api/ne/neInfo';
|
||||
import useDictStore from '@/store/modules/dict';
|
||||
import useNeOptions from './hooks/useNeOptions';
|
||||
import { hasPermissions } from '@/plugins/auth-user';
|
||||
const { getDict } = useDictStore();
|
||||
const neListStore = useNeListStore();
|
||||
const { t } = useI18n();
|
||||
@@ -33,6 +41,10 @@ const OAMModal = defineAsyncComponent(
|
||||
const BackConfModal = defineAsyncComponent(
|
||||
() => import('./components/BackConfModal.vue')
|
||||
);
|
||||
// 快速OAM配置
|
||||
const QuickOAMModal = defineAsyncComponent(
|
||||
() => import('./components/QuickOAMModal.vue')
|
||||
);
|
||||
const backConf = ref(); // 引用句柄,取导出函数
|
||||
|
||||
/**字典数据 */
|
||||
@@ -186,6 +198,8 @@ type ModalStateType = {
|
||||
openByBackConf: boolean;
|
||||
/**OAM文件配置框是否显示 */
|
||||
openByOAM: boolean;
|
||||
/**快速OAM配置框是否显示 */
|
||||
openByQuickOAM: boolean;
|
||||
/**新增框或修改框是否显示 */
|
||||
openByEdit: boolean;
|
||||
/**新增框或修改框ID */
|
||||
@@ -201,6 +215,7 @@ type ModalStateType = {
|
||||
let modalState: ModalStateType = reactive({
|
||||
openByBackConf: false,
|
||||
openByOAM: false,
|
||||
openByQuickOAM: false,
|
||||
openByEdit: false,
|
||||
editId: 0,
|
||||
neId: '',
|
||||
@@ -275,6 +290,7 @@ function fnModalEditCancel() {
|
||||
modalState.openByEdit = false;
|
||||
modalState.openByOAM = false;
|
||||
modalState.openByBackConf = false;
|
||||
modalState.openByQuickOAM = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -360,6 +376,9 @@ function fnRecordMore(type: string | number, row: Record<string, any>) {
|
||||
modalState.neType = row.neType;
|
||||
modalState.openByBackConf = !modalState.openByBackConf;
|
||||
break;
|
||||
case 'quickOAM':
|
||||
modalState.openByQuickOAM = !modalState.openByQuickOAM;
|
||||
break;
|
||||
default:
|
||||
console.warn(type);
|
||||
break;
|
||||
@@ -463,16 +482,30 @@ onMounted(() => {
|
||||
<!-- 插槽-卡片左侧侧 -->
|
||||
<template #title>
|
||||
<a-space :size="8" align="center">
|
||||
<a-button type="primary" @click.prevent="fnModalVisibleByEdit()">
|
||||
<a-button
|
||||
type="primary"
|
||||
@click.prevent="fnModalVisibleByEdit()"
|
||||
v-perms:has="['ne:neInfo:add']"
|
||||
>
|
||||
<template #icon><PlusOutlined /></template>
|
||||
{{ t('common.addText') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="default"
|
||||
:loading="modalState.confirmLoading"
|
||||
@click.prevent="fnRecordMore('quickOAM', {})"
|
||||
v-perms:has="['ne:neInfo:oam']"
|
||||
>
|
||||
<template #icon><SettingOutlined /></template>
|
||||
{{ t('views.ne.neInfo.quickOam.title') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="default"
|
||||
danger
|
||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||
:loading="modalState.confirmLoading"
|
||||
@click.prevent="fnRecordDelete('0')"
|
||||
v-perms:has="['ne:neInfo:delete']"
|
||||
>
|
||||
<template #icon><DeleteOutlined /></template>
|
||||
{{ t('common.deleteText') }}
|
||||
@@ -553,6 +586,7 @@ onMounted(() => {
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnModalVisibleByEdit(record)"
|
||||
v-perms:has="['ne:neInfo:edit']"
|
||||
>
|
||||
<template #icon><FormOutlined /></template>
|
||||
</a-button>
|
||||
@@ -564,6 +598,7 @@ onMounted(() => {
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordMore('restart', record)"
|
||||
v-perms:has="['ne:neInfo:restart']"
|
||||
>
|
||||
<template #icon><UndoOutlined /></template>
|
||||
</a-button>
|
||||
@@ -580,11 +615,17 @@ onMounted(() => {
|
||||
<FileTextOutlined />
|
||||
{{ t('views.ne.common.log') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="start">
|
||||
<a-menu-item
|
||||
key="start"
|
||||
v-if="hasPermissions(['ne:neInfo:start'])"
|
||||
>
|
||||
<ThunderboltOutlined />
|
||||
{{ t('views.ne.common.start') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="stop">
|
||||
<a-menu-item
|
||||
key="stop"
|
||||
v-if="hasPermissions(['ne:neInfo:stop'])"
|
||||
>
|
||||
<CloseSquareOutlined />
|
||||
{{ t('views.ne.common.stop') }}
|
||||
</a-menu-item>
|
||||
@@ -592,23 +633,35 @@ onMounted(() => {
|
||||
<SyncOutlined />
|
||||
{{ t('views.ne.common.reload') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="delete">
|
||||
<a-menu-item
|
||||
key="delete"
|
||||
v-if="hasPermissions(['ne:neInfo:delete'])"
|
||||
>
|
||||
<DeleteOutlined />
|
||||
{{ t('common.deleteText') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item
|
||||
key="oam"
|
||||
v-if="!['OMC'].includes(record.neType)"
|
||||
v-if="
|
||||
!['OMC'].includes(record.neType) ||
|
||||
hasPermissions(['ne:neInfo:oam'])
|
||||
"
|
||||
>
|
||||
<FileTextOutlined />
|
||||
{{ t('views.ne.common.oam') }}
|
||||
</a-menu-item>
|
||||
<!-- 配置备份 -->
|
||||
<a-menu-item key="backConfExport">
|
||||
<a-menu-item
|
||||
key="backConfExport"
|
||||
v-if="hasPermissions(['ne:neInfo:export'])"
|
||||
>
|
||||
<ExportOutlined />
|
||||
{{ t('views.ne.neInfo.backConf.export') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="backConfImport">
|
||||
<a-menu-item
|
||||
key="backConfImport"
|
||||
v-if="hasPermissions(['ne:neInfo:import'])"
|
||||
>
|
||||
<ImportOutlined />
|
||||
{{ t('views.ne.neInfo.backConf.import') }}
|
||||
</a-menu-item>
|
||||
@@ -732,6 +785,12 @@ onMounted(() => {
|
||||
:ne-type="modalState.neType"
|
||||
@cancel="fnModalEditCancel"
|
||||
></BackConfModal>
|
||||
|
||||
<!-- 快速OAM配置框 -->
|
||||
<QuickOAMModal
|
||||
v-model:open="modalState.openByQuickOAM"
|
||||
@cancel="fnModalEditCancel"
|
||||
></QuickOAMModal>
|
||||
</PageContainer>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -0,0 +1,449 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, toRaw, watch, ref } from 'vue';
|
||||
import { ProModal } from 'antdv-pro-modal';
|
||||
import { message, Form, Progress, Upload } from 'ant-design-vue/es';
|
||||
import { UploadRequestOption } from 'ant-design-vue/es/vc-upload/interface';
|
||||
import { FileType } from 'ant-design-vue/es/upload/interface';
|
||||
import { UploadOutlined, CheckCircleOutlined, CloseCircleOutlined } from '@ant-design/icons-vue';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import { changeNeLicense, getNeLicenseByTypeAndID } from '@/api/ne/neLicense';
|
||||
import { uploadFile } from '@/api/tool/file';
|
||||
import useNeListStore from '@/store/modules/ne_list';
|
||||
|
||||
const { t } = useI18n();
|
||||
const neListStore = useNeListStore();
|
||||
const emit = defineEmits(['ok', 'cancel', 'update:open']);
|
||||
|
||||
const props = defineProps({
|
||||
open: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
/**对话框对象信息状态类型 */
|
||||
type ModalStateType = {
|
||||
/**是否显示 */
|
||||
openByEdit: boolean;
|
||||
/**标题 */
|
||||
title: string;
|
||||
/**表单数据 */
|
||||
from: {
|
||||
selectedNeList: string[];
|
||||
licensePath: string;
|
||||
remark: string;
|
||||
};
|
||||
/**确定按钮 loading */
|
||||
confirmLoading: boolean;
|
||||
/**上传文件 */
|
||||
uploadFiles: any[];
|
||||
/**进度显示 */
|
||||
progress: {
|
||||
visible: boolean;
|
||||
current: number;
|
||||
total: number;
|
||||
currentNe: string;
|
||||
};
|
||||
/**操作结果 */
|
||||
results: Array<{
|
||||
neType: string;
|
||||
neId: string;
|
||||
neName: string;
|
||||
success: boolean;
|
||||
message: string;
|
||||
}>;
|
||||
};
|
||||
|
||||
/**对话框对象信息状态 */
|
||||
let modalState: ModalStateType = reactive({
|
||||
openByEdit: false,
|
||||
title: t('views.ne.neLicense.quickUpload.title'),
|
||||
from: {
|
||||
selectedNeList: [],
|
||||
licensePath: '',
|
||||
remark: '',
|
||||
},
|
||||
confirmLoading: false,
|
||||
uploadFiles: [],
|
||||
progress: {
|
||||
visible: false,
|
||||
current: 0,
|
||||
total: 0,
|
||||
currentNe: '',
|
||||
},
|
||||
results: [],
|
||||
});
|
||||
|
||||
/**对话框内表单属性和校验规则 */
|
||||
const modalStateFrom = Form.useForm(
|
||||
modalState.from,
|
||||
reactive({
|
||||
selectedNeList: [
|
||||
{
|
||||
required: true,
|
||||
|
||||
},
|
||||
],
|
||||
licensePath: [
|
||||
{
|
||||
required: true,
|
||||
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
/**获取网元列表选项 */
|
||||
const neOptions = ref<Array<{ label: string; value: string; neType: string; neId: string; neName: string }>>([]);
|
||||
|
||||
/**
|
||||
* 初始化网元选项
|
||||
*/
|
||||
async function initNeOptions() {
|
||||
// 确保网元列表已加载
|
||||
await neListStore.fnNelistRefresh();
|
||||
// 从store获取网元列表,过滤掉OMC类型
|
||||
const neList = neListStore.getNeList.filter((ne: any) => ne.neType !== 'OMC');
|
||||
neOptions.value = neList.map((ne: any) => ({
|
||||
label: `${ne.neType}-${ne.neId} (${ne.neName})`,
|
||||
value: `${ne.neType}@${ne.neId}`,
|
||||
neType: ne.neType,
|
||||
neId: ne.neId,
|
||||
neName: ne.neName,
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* 单个网元许可证上传(复用EditModal的逻辑)
|
||||
* @param neType 网元类型
|
||||
* @param neId 网元ID
|
||||
* @param licensePath 许可证文件路径
|
||||
* @param remark 备注
|
||||
* @returns Promise<{success: boolean, message: string}>
|
||||
*/
|
||||
async function uploadSingleNeLicense(neType: string, neId: string, licensePath: string, remark: string = '') {
|
||||
try {
|
||||
// 1. 获取网元许可证信息(复用EditModal的获取逻辑)
|
||||
const getRes = await getNeLicenseByTypeAndID(neType, neId);
|
||||
|
||||
if (getRes.code !== RESULT_CODE_SUCCESS) {
|
||||
return {
|
||||
success: false,
|
||||
message: ` ${getRes.msg}`,
|
||||
};
|
||||
}
|
||||
|
||||
// 2. 构建上传数据(复用EditModal的数据结构)
|
||||
const uploadData = {
|
||||
id: getRes.data.id,
|
||||
neType: neType,
|
||||
neId: neId,
|
||||
licensePath: licensePath,
|
||||
remark: remark,
|
||||
reload: false, // 网元授权不允许操作重启
|
||||
};
|
||||
|
||||
// 3. 上传许可证(复用EditModal的上传逻辑)
|
||||
const uploadRes = await changeNeLicense(uploadData);
|
||||
|
||||
if (uploadRes.code === RESULT_CODE_SUCCESS) {
|
||||
return {
|
||||
success: true,
|
||||
message: t('views.ne.neInfo.quickOam.success'),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
success: false,
|
||||
message: ` ${uploadRes.msg}`,
|
||||
};
|
||||
}
|
||||
} catch (error: any) {
|
||||
return {
|
||||
success: false,
|
||||
message: ` ${error.message || error}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对话框弹出确认执行函数
|
||||
* 进行表达规则校验
|
||||
*/
|
||||
async function fnModalOk() {
|
||||
try {
|
||||
await modalStateFrom.validate();
|
||||
|
||||
modalState.confirmLoading = true;
|
||||
modalState.progress.visible = true;
|
||||
modalState.progress.current = 0;
|
||||
modalState.progress.total = modalState.from.selectedNeList.length;
|
||||
modalState.results = [];
|
||||
|
||||
const { licensePath, remark } = modalState.from;
|
||||
|
||||
// 循环处理每个选中的网元
|
||||
for (let i = 0; i < modalState.from.selectedNeList.length; i++) {
|
||||
const neInfo = modalState.from.selectedNeList[i];
|
||||
const [neType, neId] = neInfo.split('@');
|
||||
const neName = neOptions.value.find(opt => opt.value === neInfo)?.neName || neId;
|
||||
|
||||
modalState.progress.current = i + 1;
|
||||
modalState.progress.currentNe = `${neType}-${neId}`;
|
||||
|
||||
// 调用单个网元许可证上传函数
|
||||
const result = await uploadSingleNeLicense(neType, neId, licensePath, remark);
|
||||
|
||||
modalState.results.push({
|
||||
neType,
|
||||
neId,
|
||||
neName,
|
||||
success: result.success,
|
||||
message: result.message,
|
||||
});
|
||||
}
|
||||
|
||||
// 显示操作结果
|
||||
const successCount = modalState.results.filter(r => r.success).length;
|
||||
const failCount = modalState.results.length - successCount;
|
||||
|
||||
if (failCount === 0) {
|
||||
message.success(`${t('views.ne.neInfo.quickOam.success')} ${successCount} `, 5);
|
||||
} else {
|
||||
message.warning(`${t('views.ne.neInfo.quickOam.success')} ${successCount} ,${t('views.ne.neInfo.quickOam.default')} ${failCount} `, 5);
|
||||
}
|
||||
|
||||
const firstSuccessNe = modalState.results.find(r => r.success);
|
||||
const paramForMain = firstSuccessNe ? {
|
||||
neType: firstSuccessNe.neType,
|
||||
neId: firstSuccessNe.neId
|
||||
} : {
|
||||
neType: 'BATCH', // 批量操作
|
||||
neId: 'OPERATION'
|
||||
};
|
||||
|
||||
emit('ok', paramForMain);
|
||||
fnModalCancel();
|
||||
} catch (error: any) {
|
||||
message.error(t('common.errorFields', { num: error.errorFields?.length || 0 }), 3);
|
||||
} finally {
|
||||
modalState.confirmLoading = false;
|
||||
modalState.progress.visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对话框弹出关闭执行函数
|
||||
*/
|
||||
function fnModalCancel() {
|
||||
modalState.openByEdit = false;
|
||||
modalState.confirmLoading = false;
|
||||
modalState.progress.visible = false;
|
||||
modalState.progress.current = 0;
|
||||
modalState.progress.total = 0;
|
||||
modalState.progress.currentNe = '';
|
||||
modalState.results = [];
|
||||
modalStateFrom.resetFields();
|
||||
modalState.uploadFiles = [];
|
||||
modalState.from.licensePath = '';
|
||||
emit('cancel');
|
||||
emit('update:open', false);
|
||||
}
|
||||
|
||||
/**表单上传前删除 */
|
||||
function fnBeforeRemoveFile(file: any) {
|
||||
modalState.from.licensePath = '';
|
||||
return true;
|
||||
}
|
||||
|
||||
/**表单上传前检查或转换压缩 */
|
||||
function fnBeforeUploadFile(file: FileType) {
|
||||
if (modalState.confirmLoading) return false;
|
||||
if (!file.name.endsWith('.ini')) {
|
||||
const msg = `${t('components.UploadModal.onlyAllow')} .ini`;
|
||||
message.error(msg, 3);
|
||||
return Upload.LIST_IGNORE;
|
||||
}
|
||||
const isLt3M = file.size / 1024 / 1024 < 3;
|
||||
if (!isLt3M) {
|
||||
const msg = `${t('components.UploadModal.allowFilter')} 3MB`;
|
||||
message.error(msg, 3);
|
||||
return Upload.LIST_IGNORE;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**表单上传文件 */
|
||||
function fnUploadFile(up: UploadRequestOption) {
|
||||
// 发送请求
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
modalState.confirmLoading = true;
|
||||
let formData = new FormData();
|
||||
formData.append('file', up.file);
|
||||
formData.append('subPath', 'license');
|
||||
uploadFile(formData)
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
// 改为完成状态
|
||||
const file = modalState.uploadFiles[0];
|
||||
file.percent = 100;
|
||||
file.status = 'done';
|
||||
// 预置到表单
|
||||
modalState.from.licensePath = res.data.filePath;
|
||||
} else {
|
||||
message.error(res.msg, 3);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
hide();
|
||||
modalState.confirmLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
/**监听是否显示,初始数据 */
|
||||
watch(
|
||||
() => props.open,
|
||||
val => {
|
||||
if (val) {
|
||||
initNeOptions();
|
||||
modalState.title = t('views.ne.neLicense.quickUpload.title');
|
||||
modalState.openByEdit = true;
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProModal
|
||||
:drag="true"
|
||||
:destroyOnClose="true"
|
||||
:body-style="{ maxHeight: '600px', 'overflow-y': 'auto' }"
|
||||
:keyboard="false"
|
||||
:mask-closable="false"
|
||||
:open="modalState.openByEdit"
|
||||
:title="modalState.title"
|
||||
:confirm-loading="modalState.confirmLoading"
|
||||
:width="500"
|
||||
@ok="fnModalOk"
|
||||
@cancel="fnModalCancel"
|
||||
>
|
||||
<a-form
|
||||
name="modalStateFrom"
|
||||
layout="horizontal"
|
||||
:label-col="{ span: 8 }"
|
||||
:labelWrap="true"
|
||||
>
|
||||
<a-form-item
|
||||
:label="t('views.ne.neLicense.licensePath')"
|
||||
name="file"
|
||||
v-bind="modalStateFrom.validateInfos.licensePath"
|
||||
>
|
||||
<a-upload
|
||||
name="file"
|
||||
v-model:file-list="modalState.uploadFiles"
|
||||
accept=".ini"
|
||||
list-type="text"
|
||||
:max-count="1"
|
||||
:show-upload-list="{
|
||||
showPreviewIcon: false,
|
||||
showRemoveIcon: true,
|
||||
showDownloadIcon: false,
|
||||
}"
|
||||
@remove="fnBeforeRemoveFile"
|
||||
:before-upload="fnBeforeUploadFile"
|
||||
:custom-request="fnUploadFile"
|
||||
:disabled="modalState.confirmLoading"
|
||||
>
|
||||
<a-button type="primary">
|
||||
<template #icon>
|
||||
<UploadOutlined />
|
||||
</template>
|
||||
{{ t('views.ne.neLicense.upload') }}
|
||||
</a-button>
|
||||
</a-upload>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item :label="t('common.remark')" name="remark">
|
||||
<a-textarea
|
||||
v-model:value="modalState.from.remark"
|
||||
:maxlength="200"
|
||||
:show-count="true"
|
||||
:placeholder="t('common.inputPlease')"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
:label="t('views.ne.neLicense.quickUpload.selectNe')"
|
||||
name="selectedNeList"
|
||||
v-bind="modalStateFrom.validateInfos.selectedNeList"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="modalState.from.selectedNeList"
|
||||
mode="multiple"
|
||||
:options="neOptions"
|
||||
:placeholder="t('common.selectPlease')"
|
||||
:max-tag-count="3"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<!-- 进度显示 -->
|
||||
<div v-if="modalState.progress.visible || modalState.results.length > 0" style="margin-top: 20px; overflow: hidden;">
|
||||
<a-divider>{{ t('views.ne.neInfo.quickOam.progress') }}</a-divider>
|
||||
<div style="margin-bottom: 10px;">
|
||||
<span>{{ t('views.ne.neInfo.quickOam.processing') }}: {{ modalState.progress.currentNe }}</span>
|
||||
<span style="float: right;">
|
||||
{{ modalState.progress.current }} / {{ modalState.progress.total }}
|
||||
</span>
|
||||
</div>
|
||||
<div style="width: 100%; overflow: hidden;">
|
||||
<Progress
|
||||
:percent="Math.round((modalState.progress.current / modalState.progress.total) * 100)"
|
||||
:status="modalState.progress.current === modalState.progress.total ? 'success' : 'active'"
|
||||
:show-info="false"
|
||||
style="width: 100%;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 操作结果 -->
|
||||
<div v-if="modalState.results.length > 0" style="margin-top: 20px;">
|
||||
<a-divider>{{ t('views.ne.neInfo.quickOam.result') }}</a-divider>
|
||||
<div style="max-height: 200px; overflow-y: auto;">
|
||||
<div
|
||||
v-for="(result, index) in modalState.results"
|
||||
:key="index"
|
||||
style="margin-bottom: 8px; padding: 8px; border-radius: 4px;"
|
||||
:style="{
|
||||
backgroundColor: result.success ? '#f6ffed' : '#fff2f0',
|
||||
border: `1px solid ${result.success ? '#b7eb8f' : '#ffccc7'}`,
|
||||
}"
|
||||
>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<span>
|
||||
<CheckCircleOutlined
|
||||
v-if="result.success"
|
||||
:style="{ color: '#52c41a', marginRight: '8px' }"
|
||||
/>
|
||||
<CloseCircleOutlined
|
||||
v-else
|
||||
:style="{ color: '#ff4d4f', marginRight: '8px' }"
|
||||
/>
|
||||
{{ result.neType }}-{{ result.neId }} ({{ result.neName }})
|
||||
</span>
|
||||
<span :style="{ color: result.success ? '#52c41a' : '#ff4d4f', fontSize: '12px' }">
|
||||
{{ result.message }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ProModal>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ant-progress-text {
|
||||
color: #1890ff;
|
||||
}
|
||||
</style>
|
||||
@@ -16,6 +16,10 @@ const neListStore = useNeListStore();
|
||||
const EditModal = defineAsyncComponent(
|
||||
() => import('./components/EditModal.vue')
|
||||
);
|
||||
// 快速许可证上传
|
||||
const QuickLicenseModal = defineAsyncComponent(
|
||||
() => import('./components/QuickLicenseModal.vue')
|
||||
);
|
||||
|
||||
/**字典数据-状态 */
|
||||
let dictStatus = ref<DictType[]>([]);
|
||||
@@ -67,12 +71,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns = ref<TableColumnsType>([
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'left',
|
||||
// width: 100,
|
||||
// },
|
||||
{
|
||||
title: t('views.ne.common.neType'),
|
||||
dataIndex: 'neType',
|
||||
@@ -105,8 +109,8 @@ let tableColumns = ref<TableColumnsType>([
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: t('views.ne.common.capability'),
|
||||
dataIndex: 'capability',
|
||||
title: t('views.ne.common.ueNumber'),
|
||||
dataIndex: 'ueNumber',
|
||||
align: 'left',
|
||||
customRender(opt) {
|
||||
if (['UDM', 'AMF', 'MME'].includes(opt.record.neType)) {
|
||||
@@ -116,6 +120,18 @@ let tableColumns = ref<TableColumnsType>([
|
||||
},
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: t('views.ne.common.nbNumber'),
|
||||
dataIndex: 'nbNumber',
|
||||
align: 'left',
|
||||
customRender(opt) {
|
||||
if (['AMF', 'MME'].includes(opt.record.neType)) {
|
||||
return opt.value;
|
||||
}
|
||||
return '-';
|
||||
},
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: t('common.remark'),
|
||||
dataIndex: 'remark',
|
||||
@@ -198,7 +214,7 @@ function fnGetList(pageNum?: number) {
|
||||
tablePagination.total = totalV;
|
||||
if (
|
||||
tablePagination.total <=
|
||||
(queryParams.pageNum - 1) * tablePagination.pageSize &&
|
||||
(queryParams.pageNum - 1) * tablePagination.pageSize &&
|
||||
queryParams.pageNum !== 1
|
||||
) {
|
||||
tableState.loading = false;
|
||||
@@ -216,6 +232,8 @@ function fnGetList(pageNum?: number) {
|
||||
type ModalStateType = {
|
||||
/**新增框或修改框是否显示 */
|
||||
openByEdit: boolean;
|
||||
/**快速许可证上传框是否显示 */
|
||||
openByQuickUpload: boolean;
|
||||
/**授权记录ID */
|
||||
licenseId: number;
|
||||
/**确定按钮 loading */
|
||||
@@ -225,6 +243,7 @@ type ModalStateType = {
|
||||
/**对话框对象信息状态 */
|
||||
let modalState: ModalStateType = reactive({
|
||||
openByEdit: false,
|
||||
openByQuickUpload: false,
|
||||
licenseId: 0,
|
||||
confirmLoading: false,
|
||||
});
|
||||
@@ -258,6 +277,7 @@ function fnModalOk(e: any) {
|
||||
*/
|
||||
function fnModalCancel() {
|
||||
modalState.openByEdit = false;
|
||||
modalState.openByQuickUpload = false;
|
||||
modalState.licenseId = 0;
|
||||
}
|
||||
|
||||
@@ -276,7 +296,8 @@ function fnRecordState(row: Record<string, any>) {
|
||||
row.status = '1';
|
||||
row.serialNum = res.data.sn;
|
||||
row.expiryDate = res.data.expire;
|
||||
row.capability = res.data.capability;
|
||||
row.ueNumber = res.data.ueNumber;
|
||||
row.nbNumber = res.data.nbNumber;
|
||||
row.updateTime = new Date().getTime();
|
||||
message.success(
|
||||
`${row.neType} ${row.neId} ${dictStatus.value[1].label}`,
|
||||
@@ -397,10 +418,20 @@ onMounted(() => {
|
||||
<!-- 插槽-卡片左侧侧 -->
|
||||
<template #title>
|
||||
<a-space :size="8" align="center">
|
||||
<a-button
|
||||
type="primary"
|
||||
:loading="modalState.confirmLoading"
|
||||
@click.prevent="modalState.openByQuickUpload = true"
|
||||
v-perms:has="['ne:neLicense:upload']"
|
||||
>
|
||||
<template #icon><UploadOutlined /></template>
|
||||
{{ t('views.ne.neLicense.quickUpload.title') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="default"
|
||||
:loading="modalState.confirmLoading"
|
||||
@click.prevent="fnRecordStateReload()"
|
||||
v-perms:has="['ne:neLicense:reload']"
|
||||
>
|
||||
<template #icon><SyncOutlined /></template>
|
||||
{{ t('views.ne.neLicense.reloadBatch') }}
|
||||
@@ -475,7 +506,7 @@ onMounted(() => {
|
||||
<a-space :size="8" align="center">
|
||||
<a-tooltip placement="topRight">
|
||||
<template #title>{{ t('views.ne.neLicense.reload') }}</template>
|
||||
<a-button type="link" @click.prevent="fnRecordState(record)">
|
||||
<a-button type="link" @click.prevent="fnRecordState(record)" v-perms:has="['ne:neLicense:sync']">
|
||||
<template #icon><SyncOutlined /> </template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
@@ -484,6 +515,7 @@ onMounted(() => {
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnModalVisibleByEdit(record.id)"
|
||||
v-perms:has="['ne:neLicense:edit']"
|
||||
>
|
||||
<template #icon><UploadOutlined /> </template>
|
||||
</a-button>
|
||||
@@ -501,6 +533,13 @@ onMounted(() => {
|
||||
@ok="fnModalOk"
|
||||
@cancel="fnModalCancel"
|
||||
></EditModal>
|
||||
|
||||
<!-- 快速许可证上传框 -->
|
||||
<QuickLicenseModal
|
||||
v-model:open="modalState.openByQuickUpload"
|
||||
@ok="fnModalOk"
|
||||
@cancel="fnModalCancel"
|
||||
></QuickLicenseModal>
|
||||
</PageContainer>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -18,12 +18,12 @@ const EditModal = defineAsyncComponent(
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns: ColumnsType = [
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'left',
|
||||
width: 50,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'left',
|
||||
// width: 50,
|
||||
// },
|
||||
{
|
||||
title: t('views.ne.common.neType'),
|
||||
dataIndex: 'neType',
|
||||
|
||||
@@ -45,8 +45,8 @@ let fromState = ref({
|
||||
ue_pool: '10.2.1.0/24',
|
||||
// 非指定属性
|
||||
mmes1_ip: '192.168.8.220/20',
|
||||
mmes10_ip: '172.16.5.221/24',
|
||||
mmes11_ip: '172.16.5.220/24',
|
||||
mmes10_ip: '127.0.0.221/24',
|
||||
mmes11_ip: '127.0.0.220/24',
|
||||
ims_sip_ip: '192.168.8.110',
|
||||
upf_type: 'LightUPF',
|
||||
upf_driver_type: 'vmxnet3',
|
||||
@@ -58,22 +58,22 @@ let fromState = ref({
|
||||
upfn6_mac: '00:00:00:00:00:00',
|
||||
},
|
||||
sbi: {
|
||||
omc_ip: '172.16.5.100',
|
||||
ims_ip: '172.16.5.110',
|
||||
amf_ip: '172.16.5.120',
|
||||
ausf_ip: '172.16.5.130',
|
||||
udm_ip: '172.16.5.140',
|
||||
db_ip: '0.0.0.0',
|
||||
smf_ip: '172.16.5.150',
|
||||
pcf_ip: '172.16.5.160',
|
||||
nssf_ip: '172.16.5.170',
|
||||
nrf_ip: '172.16.5.180',
|
||||
upf_ip: '172.16.5.190',
|
||||
lmf_ip: '172.16.5.200',
|
||||
nef_ip: '172.16.5.210',
|
||||
mme_ip: '172.16.5.220',
|
||||
n3iwf_ip: '172.16.5.230',
|
||||
smsc_ip: '172.16.5.240',
|
||||
omc_ip: '127.0.0.100',
|
||||
ims_ip: '127.0.0.110',
|
||||
amf_ip: '127.0.0.120',
|
||||
ausf_ip: '127.0.0.130',
|
||||
udm_ip: '127.0.0.140',
|
||||
db_ip: '127.0.0.1',
|
||||
smf_ip: '127.0.0.150',
|
||||
pcf_ip: '127.0.0.160',
|
||||
nssf_ip: '127.0.0.170',
|
||||
nrf_ip: '127.0.0.180',
|
||||
upf_ip: '127.0.0.190',
|
||||
lmf_ip: '127.0.0.200',
|
||||
nef_ip: '127.0.0.210',
|
||||
mme_ip: '127.0.0.220',
|
||||
n3iwf_ip: '127.0.0.230',
|
||||
smsc_ip: '127.0.0.240',
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, onMounted, toRaw, defineAsyncComponent } from 'vue';
|
||||
import { reactive, ref, onMounted, toRaw, defineAsyncComponent,computed } from 'vue';
|
||||
import { PageContainer } from 'antdv-pro-layout';
|
||||
import { Modal, TableColumnsType, message } from 'ant-design-vue/es';
|
||||
import { SizeType } from 'ant-design-vue/es/config-provider';
|
||||
@@ -11,6 +11,7 @@ import { listNeSoftware, delNeSoftware } from '@/api/ne/neSoftware';
|
||||
import { parseDateToStr } from '@/utils/date-utils';
|
||||
import { downloadFile } from '@/api/tool/file';
|
||||
import { saveAs } from 'file-saver';
|
||||
import { hasPermissions } from '@/plugins/auth-user';
|
||||
const neListStore = useNeListStore();
|
||||
const { t } = useI18n();
|
||||
|
||||
@@ -21,7 +22,10 @@ const EditModal = defineAsyncComponent(
|
||||
const UploadMoreFile = defineAsyncComponent(
|
||||
() => import('./components/UploadMoreFile.vue')
|
||||
);
|
||||
|
||||
const hasAnyBatchPermission = computed(() => {
|
||||
return hasPermissions(['ne:neSoftware:download']) ||
|
||||
hasPermissions(['ne:neSoftware:delete']) ;
|
||||
});
|
||||
/**查询参数 */
|
||||
let queryParams = reactive({
|
||||
/**网元类型 */
|
||||
@@ -79,12 +83,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns = ref<TableColumnsType>([
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'left',
|
||||
// width: 100,
|
||||
// },
|
||||
{
|
||||
title: t('views.ne.common.neType'),
|
||||
dataIndex: 'neType',
|
||||
@@ -400,7 +404,7 @@ onMounted(() => {
|
||||
<!-- 插槽-卡片左侧侧 -->
|
||||
<template #title>
|
||||
<a-space :size="8" align="center">
|
||||
<a-button type="primary" @click.prevent="fnModalVisibleByEdit(0)">
|
||||
<a-button type="primary" @click.prevent="fnModalVisibleByEdit(0)" v-perms:has="['ne:neSoftware:upload']">
|
||||
<template #icon><UploadOutlined /></template>
|
||||
{{ t('views.ne.neSoftware.upload') }}
|
||||
</a-button>
|
||||
@@ -410,6 +414,7 @@ onMounted(() => {
|
||||
@click.prevent="
|
||||
() => (modalState.openByMoreFile = !modalState.openByMoreFile)
|
||||
"
|
||||
v-perms:has="['ne:neSoftware:upload']"
|
||||
>
|
||||
<template #icon><UploadOutlined /></template>
|
||||
<template v-if="tableState.selectedRowOne.neType">
|
||||
@@ -426,6 +431,7 @@ onMounted(() => {
|
||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||
:loading="modalState.confirmLoading"
|
||||
@click.prevent="fnRecordDelete('0')"
|
||||
v-perms:has="['ne:neSoftware:delete']"
|
||||
>
|
||||
<template #icon><DeleteOutlined /></template>
|
||||
{{ t('common.deleteText') }}
|
||||
@@ -521,6 +527,7 @@ onMounted(() => {
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnModalVisibleByEdit(record.id)"
|
||||
v-perms:has="['ne:neSoftware:edit']"
|
||||
>
|
||||
<template #icon> <ProfileOutlined /></template>
|
||||
</a-button>
|
||||
@@ -528,17 +535,17 @@ onMounted(() => {
|
||||
|
||||
<a-tooltip placement="left">
|
||||
<template #title>{{ t('common.moreText') }}</template>
|
||||
<a-dropdown placement="bottomRight" trigger="click">
|
||||
<a-dropdown placement="bottomRight" trigger="click" v-if="hasAnyBatchPermission">
|
||||
<a-button type="link">
|
||||
<template #icon><EllipsisOutlined /> </template>
|
||||
</a-button>
|
||||
<template #overlay>
|
||||
<a-menu @click="({ key }:any) => fnRecordMore(key, record)">
|
||||
<a-menu-item key="download">
|
||||
<a-menu-item key="download" v-if="hasPermissions(['ne:neSoftware:download'])">
|
||||
<DownloadOutlined />
|
||||
{{ t('common.downloadText') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="delete">
|
||||
<a-menu-item key="delete" v-if="hasPermissions(['ne:neSoftware:delete'])">
|
||||
<DeleteOutlined />
|
||||
{{ t('common.deleteText') }}
|
||||
</a-menu-item>
|
||||
|
||||
@@ -87,12 +87,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns = ref<TableColumnsType>([
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'left',
|
||||
// width: 100,
|
||||
// },
|
||||
{
|
||||
title: t('views.ne.common.neType'),
|
||||
dataIndex: 'neType',
|
||||
@@ -108,6 +108,7 @@ let tableColumns = ref<TableColumnsType>([
|
||||
{
|
||||
title: t('views.ne.neVersion.version'),
|
||||
dataIndex: 'version',
|
||||
key: 'version',
|
||||
align: 'left',
|
||||
width: 150,
|
||||
resizable: true,
|
||||
@@ -505,6 +506,7 @@ onMounted(() => {
|
||||
@click.prevent="
|
||||
() => (modalState.openByEdit = !modalState.openByEdit)
|
||||
"
|
||||
v-perms:has="['ne:neVersion:upload']"
|
||||
>
|
||||
<template #icon><UploadOutlined /></template>
|
||||
{{ t('views.ne.neSoftware.upload') }}
|
||||
@@ -515,6 +517,7 @@ onMounted(() => {
|
||||
@click.prevent="
|
||||
() => (modalState.openByMoreFile = !modalState.openByMoreFile)
|
||||
"
|
||||
v-perms:has="['ne:neVersion:upload']"
|
||||
>
|
||||
<template #icon><UploadOutlined /></template>
|
||||
<template v-if="tableState.selectedRowOne.neType">
|
||||
@@ -531,6 +534,7 @@ onMounted(() => {
|
||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||
:loading="modalState.confirmLoading"
|
||||
@click.prevent="fnRecordUpgradeConfirm()"
|
||||
v-perms:has="['ne:neVersion:upgrade']"
|
||||
>
|
||||
<template #icon><ThunderboltOutlined /></template>
|
||||
{{ t('views.ne.neVersion.upgradeBatch') }}
|
||||
@@ -605,6 +609,21 @@ onMounted(() => {
|
||||
<template v-if="column.key === 'status'">
|
||||
<DictTag :options="dictStatus" :value="record.status" />
|
||||
</template>
|
||||
<template v-if="column.key === 'version'">
|
||||
{{ record.version }}
|
||||
<a-tooltip
|
||||
placement="topRight"
|
||||
v-if="
|
||||
record.version &&
|
||||
(record.path === '' || record.path === '-')
|
||||
"
|
||||
>
|
||||
<template #title>
|
||||
{{ t('views.ne.neVersion.noPath') }}
|
||||
</template>
|
||||
<InfoCircleOutlined />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template v-if="column.key === 'preVersion'">
|
||||
{{ record.preVersion }}
|
||||
<a-tooltip
|
||||
@@ -629,6 +648,7 @@ onMounted(() => {
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordVersion('upgrade', record)"
|
||||
v-perms:has="['ne:neVersion:upgrade']"
|
||||
>
|
||||
<template #icon><ThunderboltOutlined /></template>
|
||||
</a-button>
|
||||
@@ -640,6 +660,7 @@ onMounted(() => {
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordVersion('rollback', record)"
|
||||
v-perms:has="['ne:neVersion:rollback']"
|
||||
>
|
||||
<template #icon><RollbackOutlined /></template>
|
||||
</a-button>
|
||||
|
||||
@@ -21,27 +21,27 @@ let sourceState = reactive({
|
||||
/**文件列表 */
|
||||
list: [
|
||||
{
|
||||
value: '/auth',
|
||||
value: '/udm/auth',
|
||||
label: t('views.neData.backupData.auth'),
|
||||
path: '/usr/local/omc/backup/udm_data',
|
||||
path: '/usr/local/omc/backup',
|
||||
neType: 'UDM',
|
||||
},
|
||||
{
|
||||
value: '/sub',
|
||||
value: '/udm/sub',
|
||||
label: t('views.neData.backupData.sub'),
|
||||
path: '/usr/local/omc/backup/udm_data',
|
||||
path: '/usr/local/omc/backup',
|
||||
neType: 'UDM',
|
||||
},
|
||||
{
|
||||
value: '/voip',
|
||||
value: '/udm/voip',
|
||||
label: t('views.neData.backupData.voip'),
|
||||
path: '/usr/local/omc/backup/udm_data',
|
||||
path: '/usr/local/omc/backup',
|
||||
neType: 'UDM',
|
||||
},
|
||||
{
|
||||
value: '/volte',
|
||||
value: '/udm/volte',
|
||||
label: t('views.neData.backupData.volte'),
|
||||
path: '/usr/local/omc/backup/udm_data',
|
||||
path: '/usr/local/omc/backup',
|
||||
neType: 'UDM+IMS',
|
||||
},
|
||||
],
|
||||
@@ -353,7 +353,11 @@ onMounted(() => {
|
||||
<template #title>
|
||||
{{ t('views.ne.neConfigBackup.backupModal.title') }}
|
||||
</template>
|
||||
<a-button type="text" @click.prevent="fnFTPModalOpen()">
|
||||
<a-button
|
||||
type="text"
|
||||
@click.prevent="fnFTPModalOpen()"
|
||||
v-perms:has="['ne-data:backup-data:ftp']"
|
||||
>
|
||||
<template #icon><DeliveredProcedureOutlined /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
@@ -387,6 +391,7 @@ onMounted(() => {
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnSyncFileToFTP(record.fileName)"
|
||||
v-perms:has="['ne-data:backup-data:ftpSync']"
|
||||
>
|
||||
<template #icon><CloudServerOutlined /></template>
|
||||
</a-button>
|
||||
@@ -397,6 +402,7 @@ onMounted(() => {
|
||||
type="link"
|
||||
:loading="downLoading"
|
||||
@click.prevent="fnDownloadFile(record)"
|
||||
v-perms:has="['ne-data:backup-data:download']"
|
||||
>
|
||||
<template #icon><DownloadOutlined /></template>
|
||||
</a-button>
|
||||
@@ -407,6 +413,7 @@ onMounted(() => {
|
||||
type="link"
|
||||
:loading="delLoading"
|
||||
@click.prevent="fnRecordDelete(record)"
|
||||
v-perms:has="['ne-data:backup-data:delete']"
|
||||
>
|
||||
<template #icon><DeleteOutlined /></template>
|
||||
</a-button>
|
||||
|
||||
@@ -109,12 +109,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns = ref<ColumnsType>([
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'left',
|
||||
width: 80,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'left',
|
||||
// width: 80,
|
||||
// },
|
||||
{
|
||||
title: t('views.neData.baseStation.name'),
|
||||
dataIndex: 'name',
|
||||
@@ -150,6 +150,15 @@ let tableColumns = ref<ColumnsType>([
|
||||
minWidth: 100,
|
||||
maxWidth: 200,
|
||||
},
|
||||
{
|
||||
title: t('views.neData.baseStation.nbId'),
|
||||
dataIndex: 'nbId',
|
||||
align: 'left',
|
||||
resizable: true,
|
||||
width: 100,
|
||||
minWidth: 100,
|
||||
maxWidth: 200,
|
||||
},
|
||||
{
|
||||
title: t('views.neData.baseStation.state'),
|
||||
dataIndex: 'state',
|
||||
@@ -202,6 +211,8 @@ function fnExportList() {
|
||||
onOk() {
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
const querys = toRaw(queryParams);
|
||||
querys.pageNum = 1;
|
||||
querys.pageSize = tablePagination.total;
|
||||
exportNBState(querys)
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
@@ -245,7 +256,7 @@ function fnGetList(pageNum?: number) {
|
||||
}
|
||||
|
||||
listNBState(toRaw(queryParams)).then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
// 取消勾选
|
||||
if (tableState.selectedRowKeys.length > 0) {
|
||||
tableState.selectedRowKeys = [];
|
||||
@@ -256,7 +267,7 @@ function fnGetList(pageNum?: number) {
|
||||
tableState.data = rows;
|
||||
if (
|
||||
tablePagination.total <=
|
||||
(queryParams.pageNum - 1) * tablePagination.pageSize &&
|
||||
(queryParams.pageNum - 1) * tablePagination.pageSize &&
|
||||
queryParams.pageNum !== 1
|
||||
) {
|
||||
tableState.loading = false;
|
||||
@@ -288,62 +299,43 @@ watch(
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProModal
|
||||
:drag="true"
|
||||
:destroyOnClose="true"
|
||||
:width="1200"
|
||||
:title="props.title"
|
||||
:open="props.open"
|
||||
:keyboard="false"
|
||||
:mask-closable="false"
|
||||
@cancel="fnModalCancel"
|
||||
:footer="null"
|
||||
>
|
||||
<ProModal :drag="true" :destroyOnClose="true" :width="1200" :title="props.title" :open="props.open" :keyboard="false"
|
||||
:mask-closable="false" @cancel="fnModalCancel" :footer="null">
|
||||
<!-- 表格搜索栏 -->
|
||||
<a-form :model="queryParams" name="queryParams" layout="horizontal">
|
||||
<a-row :gutter="16" style="margin-left: 0; margin-right: 0">
|
||||
<a-col :lg="6" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.neData.baseStation.state')"
|
||||
name="status"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="queryParams.status"
|
||||
allow-clear
|
||||
:placeholder="t('common.selectPlease')"
|
||||
:options="nbStateOptions"
|
||||
>
|
||||
<a-form-item :label="t('views.neData.baseStation.state')" name="status">
|
||||
<a-select v-model:value="queryParams.status" allow-clear :placeholder="t('common.selectPlease')"
|
||||
:options="nbStateOptions">
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="16" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.neData.baseStation.time')"
|
||||
name="queryRangePicker"
|
||||
>
|
||||
<a-range-picker
|
||||
v-model:value="queryRangePicker"
|
||||
:bordered="true"
|
||||
:allow-clear="true"
|
||||
style="width: 100%"
|
||||
:show-time="{ format: 'HH:mm:ss' }"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
></a-range-picker>
|
||||
<a-form-item :label="t('views.neData.baseStation.time')" name="queryRangePicker">
|
||||
<a-range-picker v-model:value="queryRangePicker" :bordered="true" :allow-clear="true" style="width: 100%"
|
||||
:show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss"></a-range-picker>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="24" :md="24" :xs="24">
|
||||
<a-form-item>
|
||||
<a-space :size="8">
|
||||
<a-button type="primary" @click.prevent="fnGetList(1)">
|
||||
<template #icon><SearchOutlined /></template>
|
||||
<template #icon>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
{{ t('common.search') }}
|
||||
</a-button>
|
||||
<a-button type="default" @click.prevent="fnQueryReset">
|
||||
<template #icon><ClearOutlined /></template>
|
||||
<template #icon>
|
||||
<ClearOutlined />
|
||||
</template>
|
||||
{{ t('common.reset') }}
|
||||
</a-button>
|
||||
<a-button type="dashed" @click.prevent="fnExportList()">
|
||||
<template #icon><ExportOutlined /></template>
|
||||
<template #icon>
|
||||
<ExportOutlined />
|
||||
</template>
|
||||
{{ t('common.export') }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
@@ -353,24 +345,13 @@ watch(
|
||||
</a-form>
|
||||
|
||||
<!-- 表格列表 -->
|
||||
<a-table
|
||||
class="table"
|
||||
row-key="id"
|
||||
:columns="tableColumns"
|
||||
:loading="tableState.loading"
|
||||
:data-source="tableState.data"
|
||||
:size="tableState.size"
|
||||
:pagination="tablePagination"
|
||||
<a-table class="table" row-key="id" :columns="tableColumns" :loading="tableState.loading"
|
||||
:data-source="tableState.data" :size="tableState.size" :pagination="tablePagination"
|
||||
:scroll="{ x: tableColumns.length * 120, y: 'calc(100vh - 480px)' }"
|
||||
@resizeColumn="(w:number, col:any) => (col.width = w)"
|
||||
>
|
||||
@resizeColumn="(w: number, col: any) => (col.width = w)">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'state'">
|
||||
<DictTag
|
||||
:options="nbStateOptions"
|
||||
:value="record.state"
|
||||
value-default="OFF"
|
||||
/>
|
||||
<DictTag :options="nbStateOptions" :value="record.state" value-default="OFF" />
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
|
||||
@@ -140,6 +140,12 @@ let tableColumns = ref<ColumnsType>([
|
||||
minWidth: 100,
|
||||
maxWidth: 200,
|
||||
},
|
||||
{
|
||||
title: t('views.neData.baseStation.nbId'),
|
||||
dataIndex: 'ranId',
|
||||
align: 'left',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: t('views.neData.baseStation.ueNum'),
|
||||
dataIndex: 'ueNum',
|
||||
@@ -641,13 +647,12 @@ function fnModalImportUpload(file: File) {
|
||||
/**对话框表格信息导入模板 */
|
||||
async function fnModalImportTemplate() {
|
||||
const baseUrl = import.meta.env.VITE_HISTORY_BASE_URL;
|
||||
const xlsxUrl = `${
|
||||
baseUrl.length === 1 && baseUrl.indexOf('/') === 0
|
||||
const xlsxUrl = `${baseUrl.length === 1 && baseUrl.indexOf('/') === 0
|
||||
? ''
|
||||
: baseUrl.indexOf('/') === -1
|
||||
? '/' + baseUrl
|
||||
: baseUrl
|
||||
}/nbStateImput`;
|
||||
? '/' + baseUrl
|
||||
: baseUrl
|
||||
}/nbStateImput`;
|
||||
const lang = currentLocale.value.split('_')[0];
|
||||
saveAs(
|
||||
`${xlsxUrl}/${lang}.xlsx`,
|
||||
@@ -669,7 +674,7 @@ onMounted(() => {
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 无查询参数neType时 默认选择AMF
|
||||
const queryNeType = (route.query.neType as string) || 'AMF';
|
||||
const item = neCascaderOptions.value.find(s => s.value === queryNeType);
|
||||
@@ -688,46 +693,35 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<a-card
|
||||
:bordered="false"
|
||||
:body-style="{ marginBottom: '24px', paddingBottom: 0 }"
|
||||
>
|
||||
<a-card :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.ne.common.neType')" name="neType ">
|
||||
<a-cascader
|
||||
v-model:value="neTypeAndId"
|
||||
:options="neCascaderOptions"
|
||||
:allow-clear="false"
|
||||
:placeholder="t('common.selectPlease')"
|
||||
@change="fnGetList"
|
||||
/>
|
||||
<a-cascader v-model:value="neTypeAndId" :options="neCascaderOptions" :allow-clear="false"
|
||||
:placeholder="t('common.selectPlease')" @change="fnGetList" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="4" :md="6" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.neData.baseStation.state')"
|
||||
name="state"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="queryParams.state"
|
||||
:options="nbState"
|
||||
:placeholder="t('common.selectPlease')"
|
||||
@change="fnGetList"
|
||||
/>
|
||||
<a-form-item :label="t('views.neData.baseStation.state')" name="state">
|
||||
<a-select v-model:value="queryParams.state" :options="nbState" :placeholder="t('common.selectPlease')"
|
||||
@change="fnGetList" />
|
||||
</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>
|
||||
<template #icon>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
{{ t('common.search') }}
|
||||
</a-button>
|
||||
<a-button type="default" @click.prevent="fnQueryReset">
|
||||
<template #icon><ClearOutlined /></template>
|
||||
<template #icon>
|
||||
<ClearOutlined />
|
||||
</template>
|
||||
{{ t('common.reset') }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
@@ -747,35 +741,36 @@ onMounted(() => {
|
||||
</template>
|
||||
{{ t('common.addText') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="default"
|
||||
:disabled="tableState.selectedRowKeys.length != 1"
|
||||
:loading="modalState.confirmLoading"
|
||||
@click.prevent="fnModalVisibleByEdit('0')"
|
||||
>
|
||||
<template #icon><FormOutlined /></template>
|
||||
<a-button type="default" :disabled="tableState.selectedRowKeys.length != 1"
|
||||
:loading="modalState.confirmLoading" @click.prevent="fnModalVisibleByEdit('0')">
|
||||
<template #icon>
|
||||
<FormOutlined />
|
||||
</template>
|
||||
{{ t('common.editText') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="default"
|
||||
danger
|
||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||
:loading="modalState.confirmLoading"
|
||||
@click.prevent="fnRecordDelete('0')"
|
||||
>
|
||||
<template #icon><DeleteOutlined /></template>
|
||||
<a-button type="default" danger :disabled="tableState.selectedRowKeys.length <= 0"
|
||||
:loading="modalState.confirmLoading" @click.prevent="fnRecordDelete('0')">
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
</template>
|
||||
{{ t('common.deleteText') }}
|
||||
</a-button>
|
||||
<a-button type="dashed" @click.prevent="fnModalImportOpen()">
|
||||
<template #icon><ImportOutlined /></template>
|
||||
<template #icon>
|
||||
<ImportOutlined />
|
||||
</template>
|
||||
{{ t('common.import') }}
|
||||
</a-button>
|
||||
<a-button type="dashed" @click.prevent="fnExportList()">
|
||||
<template #icon><ExportOutlined /></template>
|
||||
<template #icon>
|
||||
<ExportOutlined />
|
||||
</template>
|
||||
{{ t('common.export') }}
|
||||
</a-button>
|
||||
<a-button type="default" @click.prevent="fnHistoryView()">
|
||||
<template #icon><ContainerOutlined /></template>
|
||||
<template #icon>
|
||||
<ContainerOutlined />
|
||||
</template>
|
||||
{{ t('views.neData.baseStation.history') }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
@@ -785,19 +780,15 @@ onMounted(() => {
|
||||
<template #extra>
|
||||
<a-space :size="8" align="center">
|
||||
<div>
|
||||
<template
|
||||
v-if="
|
||||
queryParams.state === undefined || queryParams.state === 'ON'
|
||||
"
|
||||
>
|
||||
<template v-if="
|
||||
queryParams.state === undefined || queryParams.state === 'ON'
|
||||
">
|
||||
{{ t('views.neData.baseStation.online') }}:
|
||||
<strong style="color: green">{{ stateNum[0] }} </strong>
|
||||
</template>
|
||||
<template
|
||||
v-if="
|
||||
queryParams.state === undefined || queryParams.state === 'OFF'
|
||||
"
|
||||
>
|
||||
<template v-if="
|
||||
queryParams.state === undefined || queryParams.state === 'OFF'
|
||||
">
|
||||
|
||||
{{ t('views.neData.baseStation.offline') }}:
|
||||
<strong style="color: red">
|
||||
@@ -808,139 +799,72 @@ onMounted(() => {
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.reloadText') }}</template>
|
||||
<a-button type="text" @click.prevent="fnGetList()">
|
||||
<template #icon><ReloadOutlined /></template>
|
||||
<template #icon>
|
||||
<ReloadOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</template>
|
||||
|
||||
<!-- 表格列表 -->
|
||||
<a-table
|
||||
class="table"
|
||||
row-key="index"
|
||||
:columns="tableColumns"
|
||||
:loading="tableState.loading"
|
||||
:data-source="tableState.data"
|
||||
:size="tableState.size"
|
||||
:pagination="tablePagination"
|
||||
:row-selection="{
|
||||
<a-table class="table" row-key="index" :columns="tableColumns" :loading="tableState.loading"
|
||||
:data-source="tableState.data" :size="tableState.size" :pagination="tablePagination" :row-selection="{
|
||||
type: 'checkbox',
|
||||
selectedRowKeys: tableState.selectedRowKeys,
|
||||
onChange: fnTableSelectedRowKeys,
|
||||
}"
|
||||
:scroll="{ x: tableColumns.length * 120, y: 'calc(100vh - 480px)' }"
|
||||
@resizeColumn="(w:number, col:any) => (col.width = w)"
|
||||
>
|
||||
}" :scroll="{ x: tableColumns.length * 120, y: 'calc(100vh - 480px)' }"
|
||||
@resizeColumn="(w: number, col: any) => (col.width = w)">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'state'">
|
||||
<DictTag
|
||||
:options="nbState"
|
||||
:value="record.state"
|
||||
value-default="OFF"
|
||||
/>
|
||||
<DictTag :options="nbState" :value="record.state" value-default="OFF" />
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
|
||||
<!-- 新增框或修改框 -->
|
||||
<ProModal
|
||||
:drag="true"
|
||||
:width="500"
|
||||
:destroyOnClose="true"
|
||||
:keyboard="false"
|
||||
:mask-closable="false"
|
||||
:open="modalState.openByEdit"
|
||||
:title="modalState.title"
|
||||
:confirm-loading="modalState.confirmLoading"
|
||||
@ok="fnModalOk"
|
||||
@cancel="fnModalCancel"
|
||||
>
|
||||
<a-form
|
||||
name="modalStateFrom"
|
||||
layout="horizontal"
|
||||
:label-col="{ span: 6 }"
|
||||
:labelWrap="true"
|
||||
>
|
||||
<a-form-item
|
||||
:label="t('views.neData.baseStation.name')"
|
||||
name="name"
|
||||
v-bind="modalStateFrom.validateInfos.name"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="modalState.from.name"
|
||||
allow-clear
|
||||
:maxlength="64"
|
||||
>
|
||||
<ProModal :drag="true" :width="500" :destroyOnClose="true" :keyboard="false" :mask-closable="false"
|
||||
:open="modalState.openByEdit" :title="modalState.title" :confirm-loading="modalState.confirmLoading"
|
||||
@ok="fnModalOk" @cancel="fnModalCancel">
|
||||
<a-form name="modalStateFrom" layout="horizontal" :label-col="{ span: 6 }" :labelWrap="true">
|
||||
<a-form-item :label="t('views.neData.baseStation.name')" name="name" v-bind="modalStateFrom.validateInfos.name">
|
||||
<a-input v-model:value="modalState.from.name" allow-clear :maxlength="64">
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
:label="t('views.neData.baseStation.position')"
|
||||
name="position"
|
||||
v-bind="modalStateFrom.validateInfos.position"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="modalState.from.position"
|
||||
allow-clear
|
||||
:maxlength="64"
|
||||
>
|
||||
<a-form-item :label="t('views.neData.baseStation.position')" name="position"
|
||||
v-bind="modalStateFrom.validateInfos.position">
|
||||
<a-input v-model:value="modalState.from.position" allow-clear :maxlength="64">
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
v-if="!modalState.from.state"
|
||||
:label="t('views.neData.baseStation.address')"
|
||||
name="address"
|
||||
v-bind="modalStateFrom.validateInfos.address"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="modalState.from.address"
|
||||
allow-clear
|
||||
:maxlength="64"
|
||||
>
|
||||
<a-form-item v-if="!modalState.from.state" :label="t('views.neData.baseStation.address')" name="address"
|
||||
v-bind="modalStateFrom.validateInfos.address">
|
||||
<a-input v-model:value="modalState.from.address" allow-clear :maxlength="64">
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</ProModal>
|
||||
|
||||
<!-- 状态历史框 -->
|
||||
<HistoryModal
|
||||
v-if="neTypeAndId.length > 1"
|
||||
v-model:open="modalState.openByHistory"
|
||||
:title="t('views.neData.baseStation.history')"
|
||||
:ne-type="neTypeAndId[0]"
|
||||
:ne-id="neTypeAndId[1]"
|
||||
@cancel="fnModalCancel"
|
||||
></HistoryModal>
|
||||
<HistoryModal v-if="neTypeAndId.length > 1" v-model:open="modalState.openByHistory"
|
||||
:title="t('views.neData.baseStation.history')" :ne-type="neTypeAndId[0]" :ne-id="neTypeAndId[1]"
|
||||
@cancel="fnModalCancel"></HistoryModal>
|
||||
|
||||
<!-- 上传导入表格数据文件框 -->
|
||||
<UploadModal
|
||||
:title="t('common.import')"
|
||||
@upload="fnModalImportUpload"
|
||||
@close="fnModalImportClose"
|
||||
v-model:open="modalState.openByImport"
|
||||
:ext="['.xls', '.xlsx']"
|
||||
:size="10"
|
||||
>
|
||||
<UploadModal :title="t('common.import')" @upload="fnModalImportUpload" @close="fnModalImportClose"
|
||||
v-model:open="modalState.openByImport" :ext="['.xls', '.xlsx']" :size="10">
|
||||
<template #default>
|
||||
<a-row justify="space-between" align="middle">
|
||||
<a-col :span="12"> </a-col>
|
||||
<a-col :span="6">
|
||||
<a-button
|
||||
type="link"
|
||||
:title="t('views.system.user.downloadObj')"
|
||||
@click.prevent="fnModalImportTemplate"
|
||||
>
|
||||
<a-button type="link" :title="t('views.system.user.downloadObj')" @click.prevent="fnModalImportTemplate">
|
||||
{{ t('views.system.user.downloadObj') }}
|
||||
</a-button>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-textarea
|
||||
:disabled="true"
|
||||
:hidden="modalState.importMsgArr.length <= 0"
|
||||
:value="modalState.importMsgArr.join('\r\n')"
|
||||
:auto-size="{ minRows: 2, maxRows: 8 }"
|
||||
style="background-color: transparent; color: rgba(0, 0, 0, 0.85)"
|
||||
/>
|
||||
<a-textarea :disabled="true" :hidden="modalState.importMsgArr.length <= 0"
|
||||
:value="modalState.importMsgArr.join('\r\n')" :auto-size="{ minRows: 2, maxRows: 8 }"
|
||||
style="background-color: transparent; color: rgba(0, 0, 0, 0.85)" />
|
||||
</template>
|
||||
</UploadModal>
|
||||
</div>
|
||||
|
||||
@@ -132,10 +132,9 @@ const graphNodeTooltip = new Tooltip({
|
||||
"
|
||||
>
|
||||
<div><strong>${t('views.neData.baseStation.state')}:</strong><span>
|
||||
${
|
||||
nInfo.state === 'ON'
|
||||
? t('views.neData.baseStation.online')
|
||||
: t('views.neData.baseStation.offline')
|
||||
${nInfo.state === 'ON'
|
||||
? t('views.neData.baseStation.online')
|
||||
: t('views.neData.baseStation.offline')
|
||||
}
|
||||
</span></div>
|
||||
<div><strong>${t('views.neData.baseStation.time')}:</strong><span>
|
||||
@@ -147,6 +146,8 @@ const graphNodeTooltip = new Tooltip({
|
||||
${nInfo.address ?? '--'}</span></div>
|
||||
<div><strong>${t('views.neData.baseStation.nbName')}:</strong><span>
|
||||
${nInfo.nbName ?? '--'}</span></div>
|
||||
<div><strong>${t('views.neData.baseStation.nbId')}:</strong><span>
|
||||
${nInfo.ranId ?? '--'}</span></div>
|
||||
<div><strong>${t('views.neData.baseStation.ueNum')}:</strong><span>
|
||||
${nInfo.ueNum ?? '--'}</span></div>
|
||||
<div><strong>${t('views.neData.baseStation.name')}:</strong><span>
|
||||
@@ -169,11 +170,10 @@ const graphNodeTooltip = new Tooltip({
|
||||
"
|
||||
>
|
||||
<div><strong>${t('views.monitor.topology.state')}:</strong><span>
|
||||
${
|
||||
nInfo.online
|
||||
? t('views.monitor.topology.normalcy')
|
||||
: t('views.monitor.topology.exceptions')
|
||||
}
|
||||
${nInfo.online
|
||||
? t('views.monitor.topology.normalcy')
|
||||
: t('views.monitor.topology.exceptions')
|
||||
}
|
||||
</span></div>
|
||||
<div><strong>${t('views.monitor.topology.refreshTime')}:</strong><span>
|
||||
${nInfo.refreshTime ?? '--'}
|
||||
@@ -359,7 +359,7 @@ function handleRanderGraph(container: HTMLElement | null, data: GraphData) {
|
||||
/**
|
||||
* 获取图组数据渲染到画布
|
||||
*/
|
||||
async function fnGraphDataLoad() {
|
||||
async function fnGraphDataLoad() {
|
||||
const dataNe = await fnGraphDataBase();
|
||||
Object.assign(graphData, dataNe);
|
||||
graphG6.value = handleRanderGraph(graphG6Dom.value, dataNe);
|
||||
@@ -417,7 +417,7 @@ async function fnGraphDataBase() {
|
||||
target: id,
|
||||
});
|
||||
}
|
||||
item.children.forEach((v: any) => {});
|
||||
item.children.forEach((v: any) => { });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,9 +23,11 @@ import {
|
||||
importUDMAuth,
|
||||
resetUDMAuth,
|
||||
listUDMAuth,
|
||||
exportUDMDecAuth,
|
||||
} from '@/api/neData/udm_auth';
|
||||
import { uploadFile } from '@/api/tool/file';
|
||||
import { getNeViewFile } from '@/api/tool/neFile';
|
||||
import { parseDateToStr } from '@/utils/date-utils';
|
||||
const { t } = useI18n();
|
||||
const neListStore = useNeListStore();
|
||||
/**网元参数 */
|
||||
@@ -117,6 +119,16 @@ let tableColumns = ref<ColumnsType>([
|
||||
align: 'center',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'Create Time',
|
||||
dataIndex: 'createTime',
|
||||
align: 'left',
|
||||
width: 250,
|
||||
customRender(opt) {
|
||||
if (!opt.value) return '';
|
||||
return parseDateToStr(+opt.value);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('common.operate'),
|
||||
key: 'imsi',
|
||||
@@ -505,6 +517,8 @@ function fnExportList(type: string) {
|
||||
const neId = queryParams.neId;
|
||||
if (!neId) return;
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
queryParams.pageNum = 1;
|
||||
queryParams.pageSize = tablePagination.total;
|
||||
exportUDMAuth(Object.assign({ type: type }, queryParams))
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
@@ -519,6 +533,25 @@ function fnExportList(type: string) {
|
||||
});
|
||||
}
|
||||
|
||||
/** UDM鉴权用户导出DecAuth */
|
||||
function fnExportDec() {
|
||||
const neId = queryParams.neId;
|
||||
if (!neId) return;
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
exportUDMDecAuth(neId)
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
message.success(t('common.msgSuccess', { msg: t('common.export') }), 3);
|
||||
saveAs(res.data, `UDMAuth_dec_${Date.now()}.txt`);
|
||||
} else {
|
||||
message.error(`${res.msg}`, 3);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
hide();
|
||||
});
|
||||
}
|
||||
|
||||
/**重新加载数据 */
|
||||
function fnLoadData() {
|
||||
const neId = queryParams.neId;
|
||||
@@ -817,7 +850,11 @@ onMounted(() => {
|
||||
<!-- 插槽-卡片左侧侧 -->
|
||||
<template #title>
|
||||
<a-flex wrap="wrap" gap="small">
|
||||
<a-button type="primary" @click.prevent="fnModalVisibleByEdit()">
|
||||
<a-button
|
||||
type="primary"
|
||||
@click.prevent="fnModalVisibleByEdit()"
|
||||
v-perms:has="['neData:udm-auth:add']"
|
||||
>
|
||||
<template #icon>
|
||||
<PlusOutlined />
|
||||
</template>
|
||||
@@ -829,6 +866,7 @@ onMounted(() => {
|
||||
danger
|
||||
ghost
|
||||
@click.prevent="fnModalVisibleByBatch()"
|
||||
v-perms:has="['neData:udm-auth:delete']"
|
||||
>
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
@@ -848,13 +886,18 @@ onMounted(() => {
|
||||
danger
|
||||
:disabled="modalState.loadDataLoading"
|
||||
:loading="modalState.loadDataLoading"
|
||||
v-perms:has="['neData:udm-auth:reload']"
|
||||
>
|
||||
<template #icon><SyncOutlined /></template>
|
||||
{{ t('views.neUser.auth.loadData') }}
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
|
||||
<a-button type="dashed" @click.prevent="fnModalUploadImportOpen">
|
||||
<a-button
|
||||
type="dashed"
|
||||
@click.prevent="fnModalUploadImportOpen"
|
||||
v-perms:has="['neData:udm-auth:import']"
|
||||
>
|
||||
<template #icon><ImportOutlined /></template>
|
||||
{{ t('views.neUser.auth.import') }}
|
||||
</a-button>
|
||||
@@ -865,13 +908,20 @@ onMounted(() => {
|
||||
ok-text="TXT"
|
||||
ok-type="default"
|
||||
@confirm="fnExportList('txt')"
|
||||
v-if="false"
|
||||
>
|
||||
<a-button type="dashed">
|
||||
<a-button type="dashed" v-perms:has="['neData:udm-auth:export']">
|
||||
<template #icon><ExportOutlined /></template>
|
||||
{{ t('views.neUser.auth.export') }}
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
<a-button
|
||||
type="dashed"
|
||||
@click="fnExportDec()"
|
||||
v-perms:has="['neData:udm-auth:export-dec']"
|
||||
>
|
||||
<template #icon><ExportOutlined /></template>
|
||||
{{ t('views.neUser.auth.export') }}
|
||||
</a-button>
|
||||
|
||||
<a-button
|
||||
type="default"
|
||||
@@ -879,6 +929,7 @@ onMounted(() => {
|
||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||
:loading="modalState.loadDataLoading"
|
||||
@click.prevent="fnRecordDelete('0')"
|
||||
v-perms:has="['neData:udm-auth:delete']"
|
||||
>
|
||||
<template #icon><DeleteOutlined /></template>
|
||||
{{ t('views.neUser.auth.checkDel') }}
|
||||
@@ -891,11 +942,11 @@ onMounted(() => {
|
||||
ok-type="default"
|
||||
@confirm="fnRecordExport('txt')"
|
||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||
v-if="false"
|
||||
>
|
||||
<a-button
|
||||
type="default"
|
||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||
v-perms:has="['neData:udm-auth:export']"
|
||||
>
|
||||
<template #icon><ExportOutlined /></template>
|
||||
{{ t('views.neUser.auth.checkExport') }}
|
||||
@@ -980,6 +1031,7 @@ onMounted(() => {
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnModalVisibleByEdit(record)"
|
||||
v-perms:has="['neData:udm-auth:edit']"
|
||||
>
|
||||
<template #icon>
|
||||
<FormOutlined />
|
||||
@@ -991,6 +1043,7 @@ onMounted(() => {
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordDelete(record.imsi)"
|
||||
v-perms:has="['neData:udm-auth:delete']"
|
||||
>
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
|
||||
+282
-110
@@ -24,8 +24,10 @@ import {
|
||||
resetUDMSub,
|
||||
updateUDMSub,
|
||||
} from '@/api/neData/udm_sub';
|
||||
import { getNeConfigData, addNeConfigData } from '@/api/ne/neConfig';
|
||||
import { uploadFile } from '@/api/tool/file';
|
||||
import { getNeViewFile } from '@/api/tool/neFile';
|
||||
import { parseDateToStr } from '@/utils/date-utils';
|
||||
const { t } = useI18n();
|
||||
const neListStore = useNeListStore();
|
||||
/**网元参数 */
|
||||
@@ -111,39 +113,42 @@ let tableColumns = ref<ColumnsType>([
|
||||
{
|
||||
title: 'Subscribed AMBR',
|
||||
dataIndex: 'ambr',
|
||||
align: 'center',
|
||||
width: 100,
|
||||
align: 'left',
|
||||
resizable: true,
|
||||
width: 150,
|
||||
minWidth: 150,
|
||||
maxWidth: 300,
|
||||
},
|
||||
{
|
||||
title: 'Subscribed SNSSAIs',
|
||||
dataIndex: 'nssai',
|
||||
align: 'center',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'Forbidden Areas',
|
||||
dataIndex: 'arfb',
|
||||
align: 'center',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'Service Area Restrict',
|
||||
dataIndex: 'sar',
|
||||
align: 'center',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '5G',
|
||||
dataIndex: 'cn',
|
||||
key: 'cnFlag',
|
||||
align: 'center',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '4G',
|
||||
dataIndex: 'epsFlag',
|
||||
key: 'epsFlag',
|
||||
align: 'center',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
@@ -155,6 +160,16 @@ let tableColumns = ref<ColumnsType>([
|
||||
minWidth: 150,
|
||||
maxWidth: 500,
|
||||
},
|
||||
{
|
||||
title: 'Create Time',
|
||||
dataIndex: 'createTime',
|
||||
align: 'left',
|
||||
width: 250,
|
||||
customRender(opt) {
|
||||
if (!opt.value) return '';
|
||||
return parseDateToStr(+opt.value);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('common.operate'),
|
||||
key: 'imsi',
|
||||
@@ -237,6 +252,10 @@ type ModalStateType = {
|
||||
confirmLoading: boolean;
|
||||
/**更新加载数据按钮 loading */
|
||||
loadDataLoading: boolean;
|
||||
/**5G Subscribed UE AMBR 模板对象 */
|
||||
ambr: Record<string, any>;
|
||||
/**已有AMBE数据 */
|
||||
ambrData: Record<string, any>[];
|
||||
};
|
||||
|
||||
/**对话框对象信息状态 */
|
||||
@@ -288,6 +307,36 @@ let modalState: ModalStateType = reactive({
|
||||
},
|
||||
confirmLoading: false,
|
||||
loadDataLoading: false,
|
||||
// 5G Subscribed UE AMBR
|
||||
ambr: {
|
||||
uplink: 1,
|
||||
uplinkUnit: 'Gbps',
|
||||
downlink: 2,
|
||||
downlinkUnit: 'Gbps',
|
||||
options: [
|
||||
{
|
||||
label: 'bps',
|
||||
value: 'bps',
|
||||
},
|
||||
{
|
||||
label: 'Kbps',
|
||||
value: 'Kbps',
|
||||
},
|
||||
{
|
||||
label: 'Mbps',
|
||||
value: 'Mbps',
|
||||
},
|
||||
{
|
||||
label: 'Gbps',
|
||||
value: 'Gbps',
|
||||
},
|
||||
{
|
||||
label: 'Tbps',
|
||||
value: 'Tbps',
|
||||
},
|
||||
],
|
||||
},
|
||||
ambrData: [],
|
||||
});
|
||||
|
||||
/**表单中多选的OPTION */
|
||||
@@ -386,7 +435,23 @@ function fnModalVisibleByBatch() {
|
||||
* 对话框弹出显示为 新增或者修改
|
||||
* @param noticeId 网元id, 不传为新增
|
||||
*/
|
||||
function fnModalVisibleByEdit(imsi?: string) {
|
||||
async function fnModalVisibleByEdit(imsi?: string) {
|
||||
const neId = queryParams.neId || '-';
|
||||
|
||||
// 获取AMBR数据
|
||||
const ambrRes = await getNeConfigData({
|
||||
neType: 'UDM',
|
||||
neId: neId,
|
||||
paramName: 'subsUEAmbr',
|
||||
});
|
||||
if (ambrRes.code === RESULT_CODE_SUCCESS) {
|
||||
modalState.ambr.uplink = 1;
|
||||
modalState.ambr.uplinkUnit = 'Gbps';
|
||||
modalState.ambr.downlink = 2;
|
||||
modalState.ambr.downlinkUnit = 'Gbps';
|
||||
modalState.ambrData = ambrRes.data;
|
||||
}
|
||||
|
||||
if (!imsi) {
|
||||
modalStateFrom.resetFields();
|
||||
modalState.title = t('common.addText') + t('views.neUser.sub.subInfo');
|
||||
@@ -395,60 +460,68 @@ function fnModalVisibleByEdit(imsi?: string) {
|
||||
if (modalState.confirmLoading) return;
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
modalState.confirmLoading = true;
|
||||
const neId = queryParams.neId || '-';
|
||||
getUDMSub(neId, imsi)
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
transformFormData(res.data.smData);
|
||||
let ardAll = parseInt(res.data.ard).toString(2).padStart(8, '0');
|
||||
let hplAll = parseInt(res.data.hplmnOdb).toString(2).padStart(8, '0');
|
||||
let odbAll = parseInt(res.data.epsOdb).toString(2).padStart(9, '0');
|
||||
const ardArray: any[] = [];
|
||||
const hplmnArray: any[] = [];
|
||||
const epsOdbArray: any[] = [];
|
||||
for (let i = 0; i < ardAll.length; i++) {
|
||||
if (PrefixZero(ardAll, ardAll.length).charAt(i) === '1') {
|
||||
ardArray.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < hplAll.length; i++) {
|
||||
if (PrefixZero(hplAll, hplAll.length).charAt(i) === '1') {
|
||||
hplmnArray.push(i);
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < odbAll.length; i++) {
|
||||
if (PrefixZero(odbAll, odbAll.length).charAt(i) === '1') {
|
||||
epsOdbArray.push(i);
|
||||
}
|
||||
}
|
||||
res.data.ard = ardArray;
|
||||
res.data.hplmnOdb = hplmnArray;
|
||||
res.data.epsOdb = epsOdbArray;
|
||||
|
||||
// 4G APN Context List
|
||||
const apnContextStr = res.data.apnContext;
|
||||
const apnContextArr = [];
|
||||
for (let i = 0; i < apnContextStr.length; i += 2) {
|
||||
const num = Number(`${apnContextStr[i]}${apnContextStr[i + 1]}`);
|
||||
apnContextArr.push(num);
|
||||
}
|
||||
|
||||
modalState.from = Object.assign(modalState.from, res.data, {
|
||||
apnContext: apnContextArr,
|
||||
});
|
||||
|
||||
modalState.title =
|
||||
t('common.editText') + t('views.neUser.sub.subInfo');
|
||||
modalState.openByEdit = true;
|
||||
} else {
|
||||
message.error(t('common.getInfoFail'), 2);
|
||||
// 获取IMSI数据
|
||||
const res = await getUDMSub(neId, imsi);
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
transformFormData(res.data.smData);
|
||||
let ardAll = parseInt(res.data.ard).toString(2).padStart(8, '0');
|
||||
let hplAll = parseInt(res.data.hplmnOdb).toString(2).padStart(8, '0');
|
||||
let odbAll = parseInt(res.data.epsOdb).toString(2).padStart(9, '0');
|
||||
const ardArray: any[] = [];
|
||||
const hplmnArray: any[] = [];
|
||||
const epsOdbArray: any[] = [];
|
||||
for (let i = 0; i < ardAll.length; i++) {
|
||||
if (PrefixZero(ardAll, ardAll.length).charAt(i) === '1') {
|
||||
ardArray.push(i);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
hide();
|
||||
modalState.confirmLoading = false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < hplAll.length; i++) {
|
||||
if (PrefixZero(hplAll, hplAll.length).charAt(i) === '1') {
|
||||
hplmnArray.push(i);
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < odbAll.length; i++) {
|
||||
if (PrefixZero(odbAll, odbAll.length).charAt(i) === '1') {
|
||||
epsOdbArray.push(i);
|
||||
}
|
||||
}
|
||||
res.data.ard = ardArray;
|
||||
res.data.hplmnOdb = hplmnArray;
|
||||
res.data.epsOdb = epsOdbArray;
|
||||
|
||||
// 4G APN Context List
|
||||
const apnContextStr = res.data.apnContext;
|
||||
const apnContextArr = [];
|
||||
for (let i = 0; i < apnContextStr.length; i += 2) {
|
||||
const num = Number(`${apnContextStr[i]}${apnContextStr[i + 1]}`);
|
||||
apnContextArr.push(num);
|
||||
}
|
||||
|
||||
modalState.from = Object.assign(modalState.from, res.data, {
|
||||
apnContext: apnContextArr,
|
||||
});
|
||||
|
||||
// AMBR数据
|
||||
const ambrItem = modalState.ambrData.find(
|
||||
item => item.name === modalState.from.ambr
|
||||
);
|
||||
if (ambrItem) {
|
||||
const uplinkItme = ambrItem.uplink.split(' ');
|
||||
modalState.ambr.uplink = uplinkItme[0] || 1;
|
||||
modalState.ambr.uplinkUnit = uplinkItme[1] || 'Gbps';
|
||||
const downlinkItme = ambrItem.downlink.split(' ');
|
||||
modalState.ambr.downlink = downlinkItme[0] || 2;
|
||||
modalState.ambr.downlinkUnit = downlinkItme[1] || 'Gbps';
|
||||
}
|
||||
|
||||
modalState.title = t('common.editText') + t('views.neUser.sub.subInfo');
|
||||
modalState.openByEdit = true;
|
||||
} else {
|
||||
message.error(t('common.getInfoFail'), 2);
|
||||
}
|
||||
hide();
|
||||
modalState.confirmLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -614,7 +687,7 @@ function fnModalOk() {
|
||||
|
||||
modalStateFrom
|
||||
.validate()
|
||||
.then(e => {
|
||||
.then(async e => {
|
||||
modalState.confirmLoading = true;
|
||||
let ardArr = [0, 0, 0, 0, 0, 0, 0, 0];
|
||||
let hplmnArr = [0, 0, 0, 0, 0, 0, 0, 0];
|
||||
@@ -646,58 +719,107 @@ function fnModalOk() {
|
||||
from.regTimer = `${from.regTimer}`;
|
||||
from.ueUsageType = `${from.ueUsageType}`;
|
||||
from.neId = queryParams.neId || '-';
|
||||
const result = from.id
|
||||
? updateUDMSub(from)
|
||||
: from.num === 1
|
||||
? addUDMSub(from)
|
||||
: batchAddUDMSub(from, from.num);
|
||||
|
||||
// 组合检查ambr
|
||||
from.ambr = await fnAMBRName();
|
||||
|
||||
let res = null;
|
||||
if (from.id) {
|
||||
res = await updateUDMSub(from);
|
||||
} else {
|
||||
if (from.num === 1) {
|
||||
res = await addUDMSub(from);
|
||||
} else {
|
||||
res = await batchAddUDMSub(from, from.num);
|
||||
}
|
||||
}
|
||||
if (!res) return;
|
||||
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
result
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
if (from.num === 1) {
|
||||
message.success({
|
||||
content: t('common.msgSuccess', { msg: modalState.title }),
|
||||
duration: 3,
|
||||
});
|
||||
fnGetList(1);
|
||||
} else {
|
||||
const timerS = Math.ceil(+from.num / 800) + 1;
|
||||
notification.success({
|
||||
message: modalState.title,
|
||||
description: t('common.operateOk'),
|
||||
duration: timerS,
|
||||
});
|
||||
setTimeout(() => {
|
||||
fnGetList(1);
|
||||
}, timerS * 1000);
|
||||
}
|
||||
} else {
|
||||
if (from.num === 1) {
|
||||
message.error({
|
||||
content: `${res.msg}`,
|
||||
duration: 3,
|
||||
});
|
||||
} else {
|
||||
notification.error({
|
||||
message: modalState.title,
|
||||
description: res.msg,
|
||||
duration: 3,
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
hide();
|
||||
fnModalCancel();
|
||||
modalState.confirmLoading = false;
|
||||
});
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
if (from.num === 1) {
|
||||
message.success({
|
||||
content: t('common.msgSuccess', { msg: modalState.title }),
|
||||
duration: 3,
|
||||
});
|
||||
fnGetList(1);
|
||||
} else {
|
||||
const timerS = Math.ceil(+from.num / 800) + 1;
|
||||
notification.success({
|
||||
message: modalState.title,
|
||||
description: t('common.operateOk'),
|
||||
duration: timerS,
|
||||
});
|
||||
setTimeout(() => {
|
||||
fnGetList(1);
|
||||
}, timerS * 1000);
|
||||
}
|
||||
} else {
|
||||
if (from.num === 1) {
|
||||
message.error({
|
||||
content: `${res.msg}`,
|
||||
duration: 3,
|
||||
});
|
||||
} else {
|
||||
notification.error({
|
||||
message: modalState.title,
|
||||
description: res.msg,
|
||||
duration: 3,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
hide();
|
||||
fnModalCancel();
|
||||
modalState.confirmLoading = false;
|
||||
})
|
||||
.catch(e => {
|
||||
message.error(t('common.errorFields', { num: e.errorFields.length }), 3);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查ambr是否存在,不存在则新增
|
||||
*/
|
||||
async function fnAMBRName() {
|
||||
const ambrItem = modalState.ambrData.find(
|
||||
item =>
|
||||
item.downlink ===
|
||||
`${modalState.ambr.downlink} ${modalState.ambr.downlinkUnit}` &&
|
||||
item.uplink === `${modalState.ambr.uplink} ${modalState.ambr.uplinkUnit}`
|
||||
);
|
||||
if (ambrItem) {
|
||||
return ambrItem.name;
|
||||
} else {
|
||||
// 新增
|
||||
const ambrData = modalState.ambrData.sort((a: any, b: any) => {
|
||||
return b.index - a.index;
|
||||
});
|
||||
if (ambrData.length > 0) {
|
||||
const neId = queryParams.neId || '-';
|
||||
const loc = ambrData[0].index + 1;
|
||||
const name = `ambr_${modalState.ambr.uplink}${modalState.ambr.uplinkUnit}_${modalState.ambr.downlink}${modalState.ambr.downlinkUnit}`;
|
||||
const ambrRes = await addNeConfigData({
|
||||
neType: 'UDM',
|
||||
neId: neId,
|
||||
paramName: 'subsUEAmbr',
|
||||
paramData: {
|
||||
index: loc,
|
||||
name: name,
|
||||
uplink: `${modalState.ambr.uplink} ${modalState.ambr.uplinkUnit}`,
|
||||
downlink: `${modalState.ambr.downlink} ${modalState.ambr.downlinkUnit}`,
|
||||
},
|
||||
loc: `${loc}`,
|
||||
});
|
||||
if (ambrRes.code === RESULT_CODE_SUCCESS) {
|
||||
return name;
|
||||
}
|
||||
} else {
|
||||
return 'def_ambr';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**对话框内批量添加表单属性和校验规则 */
|
||||
const modalStateBatchDelFrom = Form.useForm(
|
||||
modalState.BatchDelForm,
|
||||
@@ -875,6 +997,8 @@ function fnExportList(type: string) {
|
||||
const neId = queryParams.neId;
|
||||
if (!neId) return;
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
queryParams.pageNum = 1;
|
||||
queryParams.pageSize = tablePagination.total;
|
||||
exportUDMSub(Object.assign({ type: type }, queryParams))
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
@@ -1218,7 +1342,11 @@ onMounted(() => {
|
||||
<!-- 插槽-卡片左侧侧 -->
|
||||
<template #title>
|
||||
<a-flex wrap="wrap" gap="small">
|
||||
<a-button type="primary" @click.prevent="fnModalVisibleByEdit()">
|
||||
<a-button
|
||||
type="primary"
|
||||
@click.prevent="fnModalVisibleByEdit()"
|
||||
v-perms:has="['neData:udm-sub:add']"
|
||||
>
|
||||
<template #icon>
|
||||
<PlusOutlined />
|
||||
</template>
|
||||
@@ -1230,6 +1358,7 @@ onMounted(() => {
|
||||
danger
|
||||
ghost
|
||||
@click.prevent="fnModalVisibleByBatch()"
|
||||
v-perms:has="['neData:udm-sub:delete']"
|
||||
>
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
@@ -1249,6 +1378,7 @@ onMounted(() => {
|
||||
danger
|
||||
:disabled="modalState.loadDataLoading"
|
||||
:loading="modalState.loadDataLoading"
|
||||
v-perms:has="['neData:udm-sub:reload']"
|
||||
>
|
||||
<template #icon>
|
||||
<SyncOutlined />
|
||||
@@ -1257,7 +1387,11 @@ onMounted(() => {
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
|
||||
<a-button type="dashed" @click.prevent="fnModalUploadImportOpen">
|
||||
<a-button
|
||||
type="dashed"
|
||||
@click.prevent="fnModalUploadImportOpen"
|
||||
v-perms:has="['neData:udm-sub:import']"
|
||||
>
|
||||
<template #icon>
|
||||
<ImportOutlined />
|
||||
</template>
|
||||
@@ -1271,7 +1405,7 @@ onMounted(() => {
|
||||
ok-type="default"
|
||||
@confirm="fnExportList('txt')"
|
||||
>
|
||||
<a-button type="dashed">
|
||||
<a-button type="dashed" v-perms:has="['neData:udm-sub:export']">
|
||||
<template #icon>
|
||||
<ExportOutlined />
|
||||
</template>
|
||||
@@ -1285,6 +1419,7 @@ onMounted(() => {
|
||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||
:loading="modalState.loadDataLoading"
|
||||
@click.prevent="fnRecordDelete('0')"
|
||||
v-perms:has="['neData:udm-sub:delete']"
|
||||
>
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
@@ -1303,6 +1438,7 @@ onMounted(() => {
|
||||
<a-button
|
||||
type="default"
|
||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||
v-perms:has="['neData:udm-sub:export']"
|
||||
>
|
||||
<template #icon>
|
||||
<ExportOutlined />
|
||||
@@ -1408,6 +1544,7 @@ onMounted(() => {
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnModalVisibleByEdit(record.imsi)"
|
||||
v-perms:has="['neData:udm-sub:edit']"
|
||||
>
|
||||
<template #icon>
|
||||
<FormOutlined />
|
||||
@@ -1419,6 +1556,7 @@ onMounted(() => {
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordDelete(record.imsi)"
|
||||
v-perms:has="['neData:udm-sub:delete']"
|
||||
>
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
@@ -1682,7 +1820,7 @@ onMounted(() => {
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="24" :md="24" :xs="24">
|
||||
<!-- <a-col :lg="24" :md="24" :xs="24">
|
||||
<a-form-item
|
||||
label="5G Subscribed UE AMBR Template"
|
||||
name="ambr"
|
||||
@@ -1705,7 +1843,41 @@ onMounted(() => {
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
</a-col> -->
|
||||
|
||||
<a-col :lg="24" :md="24" :xs="24">
|
||||
<a-form-item label="5G Subscribed UE AMBR" name="ambr">
|
||||
<a-row :gutter="8">
|
||||
<a-col :span="12">
|
||||
<a-input v-model:value="modalState.ambr.uplink">
|
||||
<template #addonBefore>Uplink</template>
|
||||
<template #addonAfter>
|
||||
<a-select
|
||||
v-model:value="modalState.ambr.uplinkUnit"
|
||||
style="width: 100px"
|
||||
:options="modalState.ambr.options"
|
||||
>
|
||||
</a-select>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-input v-model:value="modalState.ambr.downlink">
|
||||
<template #addonBefore>Downlink</template>
|
||||
<template #addonAfter>
|
||||
<a-select
|
||||
v-model:value="modalState.ambr.downlinkUnit"
|
||||
style="width: 100px"
|
||||
:options="modalState.ambr.options"
|
||||
>
|
||||
</a-select>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col :lg="24" :md="24" :xs="24">
|
||||
<a-form-item
|
||||
label="5G Subscribed SNSSAIs Template"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, onMounted, toRaw } from 'vue';
|
||||
import { reactive, ref, onMounted, toRaw, computed } from 'vue';
|
||||
import { PageContainer } from 'antdv-pro-layout';
|
||||
import { ProModal } from 'antdv-pro-modal';
|
||||
import {
|
||||
@@ -28,6 +28,8 @@ import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import { saveAs } from 'file-saver';
|
||||
import { uploadFile } from '@/api/tool/file';
|
||||
import { getNeViewFile } from '@/api/tool/neFile';
|
||||
import { hasPermissions } from '@/plugins/auth-user';
|
||||
import { parseDateToStr } from '@/utils/date-utils';
|
||||
const { t } = useI18n();
|
||||
const neListStore = useNeListStore();
|
||||
/**网元参数 */
|
||||
@@ -49,6 +51,13 @@ let queryParams = reactive({
|
||||
pageSize: 20,
|
||||
});
|
||||
|
||||
const hasAnyBatchPermission = computed(() => {
|
||||
return (
|
||||
hasPermissions(['neData:udm-voip:add']) ||
|
||||
hasPermissions(['neData:udm-voip:delete'])
|
||||
);
|
||||
});
|
||||
|
||||
/**查询参数重置 */
|
||||
function fnQueryReset() {
|
||||
queryParams = Object.assign(queryParams, {
|
||||
@@ -94,6 +103,16 @@ let tableColumns = ref<TableColumnsType>([
|
||||
minWidth: 100,
|
||||
maxWidth: 300,
|
||||
},
|
||||
{
|
||||
title: 'Create Time',
|
||||
dataIndex: 'createTime',
|
||||
align: 'left',
|
||||
width: 250,
|
||||
customRender(opt) {
|
||||
if (!opt.value) return '';
|
||||
return parseDateToStr(+opt.value);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('common.operate'),
|
||||
key: 'id',
|
||||
@@ -363,6 +382,8 @@ function fnExportList(type: string) {
|
||||
const neId = queryParams.neId;
|
||||
if (!neId) return;
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
queryParams.pageNum = 1;
|
||||
queryParams.pageSize = tablePagination.total;
|
||||
exportUDMVOIP(Object.assign({ type: type }, queryParams))
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
@@ -659,7 +680,11 @@ onMounted(() => {
|
||||
<!-- 插槽-卡片左侧侧 -->
|
||||
<template #title>
|
||||
<a-space :size="8" align="center">
|
||||
<a-button type="primary" @click.prevent="fnModalVisibleByEdit()">
|
||||
<a-button
|
||||
type="primary"
|
||||
@click.prevent="fnModalVisibleByEdit()"
|
||||
v-perms:has="['neData:udm-voip:add']"
|
||||
>
|
||||
<template #icon>
|
||||
<PlusOutlined />
|
||||
</template>
|
||||
@@ -672,23 +697,30 @@ onMounted(() => {
|
||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||
:loading="modalState.confirmLoading"
|
||||
@click.prevent="fnRecordDelete('0')"
|
||||
v-perms:has="['neData:udm-voip:delete']"
|
||||
>
|
||||
<template #icon><DeleteOutlined /></template>
|
||||
{{ t('views.neData.common.checkDel') }}
|
||||
</a-button>
|
||||
|
||||
<a-dropdown trigger="click">
|
||||
<a-dropdown trigger="click" v-if="hasAnyBatchPermission">
|
||||
<a-button>
|
||||
{{ t('views.neData.common.batchOper') }}
|
||||
<DownOutlined />
|
||||
</a-button>
|
||||
<template #overlay>
|
||||
<a-menu @click="({ key }:any) => fnModalVisibleByBatch(key)">
|
||||
<a-menu-item key="add">
|
||||
<a-menu-item
|
||||
key="add"
|
||||
v-if="hasPermissions(['neData:udm-voip:add'])"
|
||||
>
|
||||
<PlusOutlined />
|
||||
{{ t('views.neData.common.batchAddText') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="delete">
|
||||
<a-menu-item
|
||||
key="delete"
|
||||
v-if="hasPermissions(['neData:udm-voip:delete'])"
|
||||
>
|
||||
<DeleteOutlined />
|
||||
{{ t('views.neData.common.batchDelText') }}
|
||||
</a-menu-item>
|
||||
@@ -709,13 +741,18 @@ onMounted(() => {
|
||||
danger
|
||||
:disabled="modalState.loadDataLoading"
|
||||
:loading="modalState.loadDataLoading"
|
||||
v-perms:has="['neData:udm-voip:reload']"
|
||||
>
|
||||
<template #icon><SyncOutlined /></template>
|
||||
{{ t('views.neData.common.loadData') }}
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
|
||||
<a-button type="dashed" @click.prevent="fnModalUploadImportOpen">
|
||||
<a-button
|
||||
type="dashed"
|
||||
@click.prevent="fnModalUploadImportOpen"
|
||||
v-perms:has="['neData:udm-voip:import']"
|
||||
>
|
||||
<template #icon><ImportOutlined /></template>
|
||||
{{ t('common.import') }}
|
||||
</a-button>
|
||||
@@ -726,7 +763,7 @@ onMounted(() => {
|
||||
ok-type="default"
|
||||
@confirm="fnExportList('txt')"
|
||||
>
|
||||
<a-button type="dashed">
|
||||
<a-button type="dashed" v-perms:has="['neData:udm-voip:export']">
|
||||
<template #icon><ExportOutlined /></template>
|
||||
{{ t('common.export') }}
|
||||
</a-button>
|
||||
@@ -816,6 +853,7 @@ onMounted(() => {
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordDelete(record.username)"
|
||||
v-perms:has="['neData:udm-voip:delete']"
|
||||
>
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, onMounted, toRaw } from 'vue';
|
||||
import { reactive, ref, onMounted, toRaw, computed } from 'vue';
|
||||
import { PageContainer } from 'antdv-pro-layout';
|
||||
import { ProModal } from 'antdv-pro-modal';
|
||||
import {
|
||||
@@ -28,8 +28,16 @@ import {
|
||||
listUDMVolteIMS,
|
||||
resetUDMVolteIMS,
|
||||
} from '@/api/neData/udm_volte_ims';
|
||||
import { hasPermissions } from '@/plugins/auth-user';
|
||||
import { parseDateToStr } from '@/utils/date-utils';
|
||||
const { t } = useI18n();
|
||||
const neListStore = useNeListStore();
|
||||
const hasAnyBatchPermission = computed(() => {
|
||||
return (
|
||||
hasPermissions(['neData:udm-volte:add']) ||
|
||||
hasPermissions(['neData:udm-volte:delete'])
|
||||
);
|
||||
});
|
||||
/**字典数据 */
|
||||
let dict: {
|
||||
/**Tag标签类型 0=VoIP, 1=VoLTE */
|
||||
@@ -145,6 +153,16 @@ let tableColumns = ref<TableColumnsType>([
|
||||
minWidth: 250,
|
||||
maxWidth: 400,
|
||||
},
|
||||
{
|
||||
title: 'Create Time',
|
||||
dataIndex: 'createTime',
|
||||
align: 'left',
|
||||
width: 250,
|
||||
customRender(opt) {
|
||||
if (!opt.value) return '';
|
||||
return parseDateToStr(+opt.value);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('common.operate'),
|
||||
key: 'id',
|
||||
@@ -442,6 +460,8 @@ function fnExportList(type: string) {
|
||||
const neId = queryParams.neId;
|
||||
if (!neId) return;
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
queryParams.pageNum = 1;
|
||||
queryParams.pageSize = tablePagination.total;
|
||||
exportUDMVolteIMS(Object.assign({ type: type }, queryParams))
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
@@ -449,7 +469,7 @@ function fnExportList(type: string) {
|
||||
content: t('common.operateOk'),
|
||||
duration: 2,
|
||||
});
|
||||
saveAs(res.data, `UDM_VOLTE_${neId}_${Date.now()}.${type}`);
|
||||
saveAs(res.data, `UDM_VoLTE_${neId}_${Date.now()}.${type}`);
|
||||
} else {
|
||||
message.error({
|
||||
content: `${res.msg}`,
|
||||
@@ -755,7 +775,11 @@ onMounted(() => {
|
||||
<!-- 插槽-卡片左侧侧 -->
|
||||
<template #title>
|
||||
<a-space :size="8" align="center">
|
||||
<a-button type="primary" @click.prevent="fnModalVisibleByEdit()">
|
||||
<a-button
|
||||
type="primary"
|
||||
@click.prevent="fnModalVisibleByEdit()"
|
||||
v-perms:has="['neData:udm-volte:add']"
|
||||
>
|
||||
<template #icon>
|
||||
<PlusOutlined />
|
||||
</template>
|
||||
@@ -768,23 +792,30 @@ onMounted(() => {
|
||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||
:loading="modalState.confirmLoading"
|
||||
@click.prevent="fnRecordDelete('0')"
|
||||
v-perms:has="['neData:udm-volte:delete']"
|
||||
>
|
||||
<template #icon><DeleteOutlined /></template>
|
||||
{{ t('views.neData.common.checkDel') }}
|
||||
</a-button>
|
||||
|
||||
<a-dropdown trigger="click">
|
||||
<a-dropdown trigger="click" v-if="hasAnyBatchPermission">
|
||||
<a-button>
|
||||
{{ t('views.neData.common.batchOper') }}
|
||||
<DownOutlined />
|
||||
</a-button>
|
||||
<template #overlay>
|
||||
<a-menu @click="({ key }:any) => fnModalVisibleByBatch(key)">
|
||||
<a-menu-item key="add">
|
||||
<a-menu-item
|
||||
key="add"
|
||||
v-if="hasPermissions(['neData:udm-volte:add'])"
|
||||
>
|
||||
<PlusOutlined />
|
||||
{{ t('views.neData.common.batchAddText') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="delete">
|
||||
<a-menu-item
|
||||
key="delete"
|
||||
v-if="hasPermissions(['neData:udm-volte:delete'])"
|
||||
>
|
||||
<DeleteOutlined />
|
||||
{{ t('views.neData.common.batchDelText') }}
|
||||
</a-menu-item>
|
||||
@@ -805,13 +836,18 @@ onMounted(() => {
|
||||
danger
|
||||
:disabled="modalState.loadDataLoading"
|
||||
:loading="modalState.loadDataLoading"
|
||||
v-perms:has="['neData:udm-volte:reload']"
|
||||
>
|
||||
<template #icon><SyncOutlined /></template>
|
||||
{{ t('views.neData.common.loadData') }}
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
|
||||
<a-button type="dashed" @click.prevent="fnModalUploadImportOpen">
|
||||
<a-button
|
||||
type="dashed"
|
||||
@click.prevent="fnModalUploadImportOpen"
|
||||
v-perms:has="['neData:udm-volte:import']"
|
||||
>
|
||||
<template #icon><ImportOutlined /></template>
|
||||
{{ t('common.import') }}
|
||||
</a-button>
|
||||
@@ -822,7 +858,7 @@ onMounted(() => {
|
||||
ok-type="default"
|
||||
@confirm="fnExportList('txt')"
|
||||
>
|
||||
<a-button type="dashed">
|
||||
<a-button type="dashed" v-perms:has="['neData:udm-volte:export']">
|
||||
<template #icon><ExportOutlined /></template>
|
||||
{{ t('common.export') }}
|
||||
</a-button>
|
||||
@@ -915,6 +951,7 @@ onMounted(() => {
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordDelete(record.id)"
|
||||
v-perms:has="['neData:udm-volte:delete']"
|
||||
>
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
|
||||
@@ -80,12 +80,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns = ref<ColumnsType>([
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'left',
|
||||
// width: 100,
|
||||
// },
|
||||
{
|
||||
title: 'NE Type',
|
||||
dataIndex: 'neType',
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+1357
-851
File diff suppressed because it is too large.
Load diff
@@ -77,11 +77,11 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns: ColumnsType = [
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'center',
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'center',
|
||||
// },
|
||||
{
|
||||
title: t('views.perfManage.taskManage.neType'),
|
||||
dataIndex: 'neType',
|
||||
|
||||
@@ -169,7 +169,7 @@ onMounted(() => {
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
min: 6,
|
||||
min: 5,
|
||||
max: 26,
|
||||
validator: fnEqualToPassword,
|
||||
},
|
||||
|
||||
@@ -21,6 +21,7 @@ import useDictStore from '@/store/modules/dict';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
import type { Dayjs } from 'dayjs';
|
||||
import { hasPermissions } from '@/plugins/auth-user';
|
||||
const { t } = useI18n();
|
||||
const { getDict } = useDictStore();
|
||||
|
||||
@@ -95,12 +96,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns = ref<ColumnsType>([
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'configId',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'configId',
|
||||
// align: 'left',
|
||||
// width: 100,
|
||||
// },
|
||||
{
|
||||
title: t('views.system.config.configName'),
|
||||
dataIndex: 'configName',
|
||||
@@ -665,11 +666,11 @@ onMounted(() => {
|
||||
:size="tableState.size"
|
||||
:pagination="tablePagination"
|
||||
:scroll="{ x: tableColumns.length * 120 }"
|
||||
:row-selection="{
|
||||
:row-selection="hasPermissions(['system:config:remove']) ? {
|
||||
type: 'checkbox',
|
||||
selectedRowKeys: tableState.selectedRowKeys,
|
||||
onChange: fnTableSelectedRowKeys,
|
||||
}"
|
||||
}: undefined"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'configType'">
|
||||
|
||||
@@ -83,12 +83,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns = ref<ColumnsType>([
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'left',
|
||||
// width: 100,
|
||||
// },
|
||||
{
|
||||
title: t('views.system.loginSource.uid'),
|
||||
dataIndex: 'uid',
|
||||
|
||||
@@ -4,7 +4,6 @@ import { Modal } from 'ant-design-vue/es';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import { delAccessToken, delRefreshToken } from '@/plugins/auth-token';
|
||||
import { useRouter } from 'vue-router';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { bootloaderDone } from '@/api/system/quick-start/bootloader';
|
||||
@@ -56,8 +55,9 @@ function fnGuideDone() {
|
||||
bootloaderDone()
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
useAppStore().bootloader = false;
|
||||
// useAppStore().bootloader = false;
|
||||
delAccessToken();
|
||||
delRefreshToken();
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
<script lang="ts" setup>
|
||||
import { message, Modal } from 'ant-design-vue/es';
|
||||
import { reactive } from 'vue';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import { FileType } from 'ant-design-vue/es/upload/interface';
|
||||
import { UploadRequestOption } from 'ant-design-vue/es/vc-upload/interface';
|
||||
import { uploadFileChunk } from '@/api/tool/file';
|
||||
import { exportBackupOMC, importBackupOMC } from '@/api/neData/backup';
|
||||
import saveAs from 'file-saver';
|
||||
const { t } = useI18n();
|
||||
|
||||
type StateType = {
|
||||
loading: boolean;
|
||||
};
|
||||
|
||||
let state: StateType = reactive({
|
||||
loading: false,
|
||||
});
|
||||
|
||||
/**导出 */
|
||||
function fnExport() {
|
||||
Modal.confirm({
|
||||
title: t('common.tipTitle'),
|
||||
content: t('views.system.setting.backupExportTip'),
|
||||
onOk() {
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
exportBackupOMC()
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
message.success({
|
||||
content: t('common.operateOk'),
|
||||
duration: 3,
|
||||
});
|
||||
saveAs(res.data, `BackupOMC-${Date.now()}.zip`);
|
||||
} else {
|
||||
message.error({
|
||||
content: `${res.msg}`,
|
||||
duration: 3,
|
||||
});
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
hide();
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**上传前检查或转换压缩 */
|
||||
function fnBeforeUpload(file: FileType) {
|
||||
if (state.loading) return false;
|
||||
console.log(file);
|
||||
if (file.type !== 'application/x-zip-compressed') {
|
||||
message.error(
|
||||
t('views.system.setting.uploadFormat', { format: 'zip' }),
|
||||
3
|
||||
);
|
||||
}
|
||||
// const isLt10M = file.size / 1024 / 1024 < 10;
|
||||
// if (!isLt10M) {
|
||||
// message.error(t('views.system.setting.uploadSize', { size: 10 }), 3);
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
/**上传变更 */
|
||||
function fnUpload(up: UploadRequestOption) {
|
||||
Modal.confirm({
|
||||
title: t('common.tipTitle'),
|
||||
content: t('views.system.setting.backupImportTip'),
|
||||
onOk() {
|
||||
// 发送请求
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
state.loading = true;
|
||||
uploadFileChunk(up.file as File, 5, 'import')
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
return importBackupOMC(res.data.filePath);
|
||||
}
|
||||
return undefined;
|
||||
})
|
||||
.then(res => {
|
||||
if (!res) {
|
||||
return;
|
||||
}
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
message.success({
|
||||
content: t('common.operateOk'),
|
||||
duration: 3,
|
||||
});
|
||||
} else {
|
||||
message.error({
|
||||
content: `${res.msg}`,
|
||||
duration: 3,
|
||||
});
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
state.loading = false;
|
||||
hide();
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<a-row>
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
<a-button type="default" @click="fnExport()">
|
||||
{{ t('common.export') }}
|
||||
</a-button>
|
||||
<a-upload
|
||||
name="file"
|
||||
list-type="picture"
|
||||
accept=".zip"
|
||||
:max-count="1"
|
||||
:show-upload-list="false"
|
||||
:before-upload="fnBeforeUpload"
|
||||
:custom-request="fnUpload"
|
||||
style="margin-left: 10px"
|
||||
>
|
||||
<a-button type="link" :disabled="state.loading">
|
||||
{{ t('common.import') }}
|
||||
</a-button>
|
||||
</a-upload>
|
||||
</a-col>
|
||||
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
<a-typography>
|
||||
<a-typography-paragraph>
|
||||
{{ t('views.system.setting.backupInstruction') }}
|
||||
</a-typography-paragraph>
|
||||
</a-typography>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
@@ -8,6 +8,7 @@ import ChangeHelpDoc from './components/change-help-doc.vue';
|
||||
import ChangeOfficialUrl from './components/change-official-url.vue';
|
||||
import ChangeI18n from './components/change-i18n.vue';
|
||||
import SystemReset from './components/system-reset.vue';
|
||||
import SystemBackup from './components/system-backup.vue';
|
||||
import ChangeHome from './components/change-home-index.vue';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
const { t } = useI18n();
|
||||
@@ -50,14 +51,24 @@ const { t } = useI18n();
|
||||
</a-divider>
|
||||
<ChangeI18n></ChangeI18n>
|
||||
</div>
|
||||
<a-divider orientation="left">
|
||||
{{ t('views.system.setting.homeSet') }}
|
||||
</a-divider>
|
||||
<ChangeHome></ChangeHome>
|
||||
<a-divider orientation="left">
|
||||
{{ t('views.system.setting.reset') }}
|
||||
</a-divider>
|
||||
<SystemReset></SystemReset>
|
||||
<div v-perms:has="['system:setting:homeSet']">
|
||||
<a-divider orientation="left">
|
||||
{{ t('views.system.setting.homeSet') }}
|
||||
</a-divider>
|
||||
<ChangeHome></ChangeHome>
|
||||
</div>
|
||||
<div v-perms:has="['system:setting:backup']">
|
||||
<a-divider orientation="left">
|
||||
{{ t('views.system.setting.backup') }}
|
||||
</a-divider>
|
||||
<SystemBackup></SystemBackup>
|
||||
</div>
|
||||
<div v-perms:has="['system:setting:reset']">
|
||||
<a-divider orientation="left">
|
||||
{{ t('views.system.setting.reset') }}
|
||||
</a-divider>
|
||||
<SystemReset></SystemReset>
|
||||
</div>
|
||||
</a-card>
|
||||
</PageContainer>
|
||||
</template>
|
||||
|
||||
@@ -834,46 +834,6 @@ onMounted(() => {
|
||||
>
|
||||
<!-- 表格搜索栏 -->
|
||||
<a-form :model="queryParams" name="queryParams" layout="horizontal">
|
||||
<a-row :gutter="16">
|
||||
<a-col :lg="18" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.system.user.className')"
|
||||
name="deptId"
|
||||
>
|
||||
<a-tree-select
|
||||
v-model:value="queryParams.deptId"
|
||||
show-search
|
||||
tree-default-expand-all
|
||||
:tree-data="deptTreeData"
|
||||
:field-names="{
|
||||
children: 'children',
|
||||
label: 'label',
|
||||
value: 'id',
|
||||
}"
|
||||
tree-node-label-prop="label"
|
||||
tree-node-filter-prop="label"
|
||||
style="width: 100%"
|
||||
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
|
||||
:placeholder="t('common.selectPlease')"
|
||||
>
|
||||
</a-tree-select>
|
||||
</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-row :gutter="16">
|
||||
<a-col :lg="6" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
@@ -937,11 +897,52 @@ onMounted(() => {
|
||||
bordered
|
||||
:show-time="{ format: 'HH:mm:ss' }"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
value-format="x"
|
||||
style="width: 100%"
|
||||
></a-range-picker>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="16">
|
||||
<a-col :lg="18" :md="12" :xs="24" v-if="false">
|
||||
<a-form-item
|
||||
:label="t('views.system.user.className')"
|
||||
name="deptId"
|
||||
>
|
||||
<a-tree-select
|
||||
v-model:value="queryParams.deptId"
|
||||
show-search
|
||||
tree-default-expand-all
|
||||
:tree-data="deptTreeData"
|
||||
:field-names="{
|
||||
children: 'children',
|
||||
label: 'label',
|
||||
value: 'id',
|
||||
}"
|
||||
tree-node-label-prop="label"
|
||||
tree-node-filter-prop="label"
|
||||
style="width: 100%"
|
||||
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
|
||||
:placeholder="t('common.selectPlease')"
|
||||
>
|
||||
</a-tree-select>
|
||||
</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>
|
||||
|
||||
@@ -971,6 +972,7 @@ onMounted(() => {
|
||||
type="dashed"
|
||||
@click.prevent="fnModalUploadImportOpen()"
|
||||
v-perms:has="['system:user:import']"
|
||||
v-if="false"
|
||||
>
|
||||
<template #icon><ImportOutlined /></template>
|
||||
{{ t('common.import') }}
|
||||
@@ -979,6 +981,7 @@ onMounted(() => {
|
||||
type="dashed"
|
||||
@click.prevent="fnExportList()"
|
||||
v-perms:has="['system:user:export']"
|
||||
v-if="false"
|
||||
>
|
||||
<template #icon><ExportOutlined /></template>
|
||||
{{ t('common.export') }}
|
||||
@@ -1255,6 +1258,7 @@ onMounted(() => {
|
||||
name="deptId"
|
||||
:label-col="{ span: 3 }"
|
||||
:label-wrap="true"
|
||||
v-if="false"
|
||||
>
|
||||
<a-tree-select
|
||||
:value="modalState.from.deptId"
|
||||
@@ -1274,7 +1278,7 @@ onMounted(() => {
|
||||
</a-form-item>
|
||||
|
||||
<a-row>
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
<a-col :lg="12" :md="12" :xs="24" v-if="false">
|
||||
<a-form-item
|
||||
:label="t('views.system.user.userWork')"
|
||||
name="postIds"
|
||||
@@ -1407,6 +1411,7 @@ onMounted(() => {
|
||||
:md="12"
|
||||
:xs="24"
|
||||
v-perms:has="['system:user:editPost']"
|
||||
v-if="false"
|
||||
>
|
||||
<a-form-item
|
||||
:label="t('views.system.user.userWork')"
|
||||
@@ -1519,6 +1524,7 @@ onMounted(() => {
|
||||
:label="t('views.system.user.fromClass')"
|
||||
name="deptId"
|
||||
:label-col="{ span: 3 }"
|
||||
v-if="false"
|
||||
>
|
||||
<a-tree-select
|
||||
v-model:value="modalState.from.deptId"
|
||||
|
||||
+6
-6
@@ -65,12 +65,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns: ColumnsType = [
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'center',
|
||||
width: 50,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'center',
|
||||
// width: 50,
|
||||
// },
|
||||
{
|
||||
title: t('views.ne.neHost.hostType'),
|
||||
dataIndex: 'hostType',
|
||||
@@ -0,0 +1,339 @@
|
||||
<script lang="ts" setup>
|
||||
import { PageContainer } from 'antdv-pro-layout';
|
||||
import { Modal } from 'ant-design-vue/es';
|
||||
import { useFullscreen } from '@vueuse/core';
|
||||
import { defineAsyncComponent, reactive, ref } from 'vue';
|
||||
import { parseDuration } from '@/utils/date-utils';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
const { t } = useI18n();
|
||||
const TerminalSSH = defineAsyncComponent(
|
||||
() => import('@/components/TerminalSSH/index.vue')
|
||||
);
|
||||
const TerminalTelnet = defineAsyncComponent(
|
||||
() => import('@/components/TerminalTelnet/index.vue')
|
||||
);
|
||||
const TerminalRedis = defineAsyncComponent(
|
||||
() => import('@/components/TerminalRedis/index.vue')
|
||||
);
|
||||
const HostList = defineAsyncComponent(
|
||||
() => import('./components/hostList.vue')
|
||||
);
|
||||
|
||||
// 全屏
|
||||
const terminalCard = ref<HTMLElement | null>(null);
|
||||
const { isFullscreen, toggle } = useFullscreen(terminalCard);
|
||||
|
||||
/**主机对象信息状态类型 */
|
||||
type HostStateType = {
|
||||
/**显示主机列表 */
|
||||
show: boolean;
|
||||
/**加载等待 */
|
||||
loading: boolean;
|
||||
/**查询参数 */
|
||||
params: {
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
};
|
||||
/**数据总数 */
|
||||
total: number;
|
||||
data: Record<string, any>[];
|
||||
};
|
||||
|
||||
/**主机对象信息状态 */
|
||||
const hostState: HostStateType = reactive({
|
||||
show: false,
|
||||
loading: false,
|
||||
params: {
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
},
|
||||
total: 0,
|
||||
data: [],
|
||||
});
|
||||
|
||||
/**连接主机 */
|
||||
function fnConnectHost(data: Record<string, any>) {
|
||||
const id = `${Date.now()}`;
|
||||
tabState.panes.push({
|
||||
id,
|
||||
status: false,
|
||||
host: data,
|
||||
});
|
||||
tabState.activeKey = id;
|
||||
}
|
||||
|
||||
/**标签对象信息状态类型 */
|
||||
type TabStateType = {
|
||||
/**激活选中 */
|
||||
activeKey: string;
|
||||
/**页签数据 */
|
||||
panes: {
|
||||
id: string;
|
||||
status: boolean;
|
||||
host: Record<string, any>;
|
||||
connectStamp?: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
/**标签对象信息状态 */
|
||||
const tabState: TabStateType = reactive({
|
||||
activeKey: '0',
|
||||
panes: [
|
||||
{
|
||||
id: '0',
|
||||
host: {
|
||||
id: 0,
|
||||
title: t('views.tool.terminal.start'),
|
||||
type: '0',
|
||||
},
|
||||
status: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
/**
|
||||
* 终端连接状态
|
||||
* @param data 主机连接结果
|
||||
*/
|
||||
function fnTerminalConnect(data: Record<string, any>) {
|
||||
const { id, timeStamp } = data;
|
||||
const seconds = timeStamp / 1000;
|
||||
// 获取当前项下标
|
||||
const tab = tabState.panes.find(item => item.id === id);
|
||||
if (tab) {
|
||||
tab.status = true;
|
||||
tab.connectStamp = parseDuration(seconds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 终端关闭状态
|
||||
* @param data 主机连接结果
|
||||
*/
|
||||
function fnTerminalClose(data: Record<string, any>) {
|
||||
const { id } = data;
|
||||
// 获取当前项下标
|
||||
const tab = tabState.panes.find(item => item.id === id);
|
||||
if (tab) {
|
||||
tab.status = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 标签更多菜单项
|
||||
* @param key 菜单key
|
||||
*/
|
||||
function fnTabMenu(key: string | number) {
|
||||
// 刷新当前
|
||||
if (key === 'reload') {
|
||||
const tabIndex = tabState.panes.findIndex(
|
||||
item => item.id === tabState.activeKey
|
||||
);
|
||||
if (tabIndex) {
|
||||
const tab = tabState.panes[tabIndex];
|
||||
Modal.confirm({
|
||||
title: t('common.tipTitle'),
|
||||
content: t('views.tool.terminal.reloadTip', {
|
||||
num: `${tab.host.hostType} - ${tab.host.title}`,
|
||||
}),
|
||||
onOk() {
|
||||
tabState.panes.splice(tabIndex, 1);
|
||||
tab.host && fnConnectHost(tab.host);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
// 关闭当前
|
||||
if (key === 'current') {
|
||||
fnTabClose(tabState.activeKey);
|
||||
}
|
||||
// 关闭其他
|
||||
if (key === 'other') {
|
||||
Modal.confirm({
|
||||
title: t('common.tipTitle'),
|
||||
content: t('views.tool.terminal.otherTip'),
|
||||
onOk() {
|
||||
hostState.show = false;
|
||||
tabState.panes = tabState.panes.filter(
|
||||
tab => tab.id === '0' || tab.id === tabState.activeKey
|
||||
);
|
||||
tabState.activeKey = tabState.activeKey;
|
||||
},
|
||||
});
|
||||
}
|
||||
// 关闭全部
|
||||
if (key === 'all') {
|
||||
Modal.confirm({
|
||||
title: t('common.tipTitle'),
|
||||
content: t('views.tool.terminal.allTip'),
|
||||
onOk() {
|
||||
hostState.show = false;
|
||||
tabState.panes.splice(1);
|
||||
tabState.activeKey = '0';
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航标签关闭
|
||||
* @param id 标签的key
|
||||
*/
|
||||
function fnTabClose(id: string) {
|
||||
if (isFullscreen.value) toggle();
|
||||
|
||||
// 获取当前项下标
|
||||
const tabIndex = tabState.panes.findIndex(tab => tab.id === id);
|
||||
if (tabIndex === -1) return;
|
||||
const item = tabState.panes[tabIndex];
|
||||
Modal.confirm({
|
||||
title: t('common.tipTitle'),
|
||||
content: t('views.tool.terminal.closeTip', {
|
||||
num: `${item.host.hostType.toUpperCase()} - ${item.host.title}`,
|
||||
}),
|
||||
onOk() {
|
||||
tabState.panes.splice(tabIndex, 1);
|
||||
// 激活前一项标签
|
||||
tabState.activeKey = tabState.panes[tabIndex - 1].id;
|
||||
},
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PageContainer>
|
||||
<a-card
|
||||
:bordered="false"
|
||||
size="small"
|
||||
:body-style="{ padding: '12px' }"
|
||||
ref="terminalCard"
|
||||
>
|
||||
<a-tabs
|
||||
class="terminal-tabs"
|
||||
hide-add
|
||||
size="small"
|
||||
tab-position="top"
|
||||
type="editable-card"
|
||||
:tab-bar-gutter="8"
|
||||
:tab-bar-style="{ margin: '0' }"
|
||||
v-model:activeKey="tabState.activeKey"
|
||||
@edit="(id:any) => fnTabClose(id)"
|
||||
>
|
||||
<a-tab-pane
|
||||
v-for="pane in tabState.panes"
|
||||
:key="pane.id"
|
||||
:closable="pane.id !== '0'"
|
||||
>
|
||||
<template #tab>
|
||||
<a-badge
|
||||
:status="pane.status ? 'success' : 'error'"
|
||||
:text="pane.host.title"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<div class="pane-box">
|
||||
<!-- 非开始页的ssh主机 -->
|
||||
<TerminalSSH
|
||||
v-if="pane.id !== '0' && pane.host.hostType === 'ssh'"
|
||||
:id="pane.id"
|
||||
:hostId="pane.host.id"
|
||||
@connect="fnTerminalConnect"
|
||||
@close="fnTerminalClose"
|
||||
>
|
||||
</TerminalSSH>
|
||||
|
||||
<!-- 非开始页的telnet主机 -->
|
||||
<TerminalTelnet
|
||||
v-if="pane.id !== '0' && pane.host.hostType === 'telnet'"
|
||||
:id="pane.id"
|
||||
:hostId="pane.host.id"
|
||||
init-cmd="help"
|
||||
:disable="true"
|
||||
@connect="fnTerminalConnect"
|
||||
@close="fnTerminalClose"
|
||||
>
|
||||
</TerminalTelnet>
|
||||
|
||||
<!-- 非开始页的redis主机 -->
|
||||
<TerminalRedis
|
||||
v-if="pane.id !== '0' && pane.host.hostType === 'redis'"
|
||||
:id="pane.id"
|
||||
:hostId="pane.host.id"
|
||||
@connect="fnTerminalConnect"
|
||||
@close="fnTerminalClose"
|
||||
>
|
||||
</TerminalRedis>
|
||||
|
||||
<!-- 开始页 -->
|
||||
<div v-if="pane.id === '0'">
|
||||
<!-- 主机列表 -->
|
||||
<HostList
|
||||
v-show="tabState.activeKey === '0'"
|
||||
@modal="() => (isFullscreen ? toggle() : null)"
|
||||
@link="fnConnectHost"
|
||||
></HostList>
|
||||
</div>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
|
||||
<template #rightExtra>
|
||||
<a-space :size="8" align="center">
|
||||
<a-tooltip placement="topRight">
|
||||
<template #title>
|
||||
{{ t('loayouts.rightContent.fullscreen') }}
|
||||
</template>
|
||||
<a-button
|
||||
type="default"
|
||||
shape="circle"
|
||||
size="small"
|
||||
style="color: inherit"
|
||||
@click="toggle"
|
||||
>
|
||||
<template #icon>
|
||||
<FullscreenExitOutlined v-if="isFullscreen" />
|
||||
<FullscreenOutlined v-else />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<!-- 非开始页的更多操作 -->
|
||||
<div v-show="tabState.activeKey !== '0'">
|
||||
<a-tooltip placement="topRight">
|
||||
<template #title>
|
||||
{{ t('views.tool.terminal.more') }}
|
||||
</template>
|
||||
<a-dropdown trigger="click" placement="bottomRight">
|
||||
<a-button type="ghost" shape="circle" size="small">
|
||||
<template #icon><EllipsisOutlined /></template>
|
||||
</a-button>
|
||||
<template #overlay>
|
||||
<a-menu @click="({ key }:any) => fnTabMenu(key)">
|
||||
<a-menu-item key="reload">
|
||||
{{ t('views.tool.terminal.reload') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="current">
|
||||
{{ t('views.tool.terminal.current') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="other">
|
||||
{{ t('views.tool.terminal.other') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="all">
|
||||
{{ t('views.tool.terminal.all') }}
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</a-space>
|
||||
</template>
|
||||
</a-tabs>
|
||||
</a-card>
|
||||
</PageContainer>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.pane-box {
|
||||
height: calc(100vh - 200px);
|
||||
overflow-x: hidden;
|
||||
}
|
||||
</style>
|
||||
@@ -1,203 +1,76 @@
|
||||
<script lang="ts" setup>
|
||||
import { PageContainer } from 'antdv-pro-layout';
|
||||
import { Modal } from 'ant-design-vue/es';
|
||||
import { useFullscreen } from '@vueuse/core';
|
||||
import { defineAsyncComponent, reactive, ref } from 'vue';
|
||||
import { parseDuration } from '@/utils/date-utils';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
const { t } = useI18n();
|
||||
import { listNeHost } from '@/api/ne/neHost';
|
||||
import { defineAsyncComponent, onMounted, reactive } from 'vue';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
const TerminalSSH = defineAsyncComponent(
|
||||
() => import('@/components/TerminalSSH/index.vue')
|
||||
);
|
||||
const TerminalTelnet = defineAsyncComponent(
|
||||
() => import('@/components/TerminalTelnet/index.vue')
|
||||
);
|
||||
const TerminalRedis = defineAsyncComponent(
|
||||
() => import('@/components/TerminalRedis/index.vue')
|
||||
);
|
||||
const HostList = defineAsyncComponent(
|
||||
() => import('./components/hostList.vue')
|
||||
);
|
||||
|
||||
// 全屏
|
||||
const terminalCard = ref<HTMLElement | null>(null);
|
||||
const { isFullscreen, toggle } = useFullscreen(terminalCard);
|
||||
|
||||
/**主机对象信息状态类型 */
|
||||
type HostStateType = {
|
||||
/**显示主机列表 */
|
||||
show: boolean;
|
||||
/**加载等待 */
|
||||
loading: boolean;
|
||||
/**查询参数 */
|
||||
params: {
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
/**主机类型 */
|
||||
hostType: 'ssh';
|
||||
/**分组 */
|
||||
groupId: '1';
|
||||
/**名称 */
|
||||
title: 'OMC';
|
||||
/**当前页数 */
|
||||
pageNum: 1;
|
||||
/**每页条数 */
|
||||
pageSize: 10;
|
||||
sortField: 'createTime';
|
||||
sortOrder: 'desc';
|
||||
};
|
||||
/**数据总数 */
|
||||
total: number;
|
||||
data: Record<string, any>[];
|
||||
/**OMC主机 */
|
||||
host: Record<string, any>;
|
||||
};
|
||||
|
||||
/**主机对象信息状态 */
|
||||
const hostState: HostStateType = reactive({
|
||||
show: false,
|
||||
loading: false,
|
||||
params: {
|
||||
/**主机类型 */
|
||||
hostType: 'ssh',
|
||||
/**分组 */
|
||||
groupId: '1',
|
||||
/**名称 */
|
||||
title: 'OMC',
|
||||
/**当前页数 */
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
/**每页条数 */
|
||||
pageSize: 10,
|
||||
sortField: 'createTime',
|
||||
sortOrder: 'desc',
|
||||
},
|
||||
total: 0,
|
||||
data: [],
|
||||
host: {},
|
||||
});
|
||||
|
||||
/**连接主机 */
|
||||
function fnConnectHost(data: Record<string, any>) {
|
||||
const id = `${Date.now()}`;
|
||||
tabState.panes.push({
|
||||
id,
|
||||
status: false,
|
||||
host: data,
|
||||
});
|
||||
tabState.activeKey = id;
|
||||
/**查询信息列表, pageNum初始页数 */
|
||||
function fnGetList() {
|
||||
hostState.loading = true;
|
||||
listNeHost(hostState.params)
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
const { total, rows } = res.data;
|
||||
if (total > 0) {
|
||||
hostState.host = rows[0];
|
||||
}
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
hostState.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
/**标签对象信息状态类型 */
|
||||
type TabStateType = {
|
||||
/**激活选中 */
|
||||
activeKey: string;
|
||||
/**页签数据 */
|
||||
panes: {
|
||||
id: string;
|
||||
status: boolean;
|
||||
host: Record<string, any>;
|
||||
connectStamp?: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
/**标签对象信息状态 */
|
||||
const tabState: TabStateType = reactive({
|
||||
activeKey: '0',
|
||||
panes: [
|
||||
{
|
||||
id: '0',
|
||||
host: {
|
||||
id: 0,
|
||||
title: t('views.tool.terminal.start'),
|
||||
type: '0',
|
||||
},
|
||||
status: true,
|
||||
},
|
||||
],
|
||||
onMounted(() => {
|
||||
// 获取列表数据
|
||||
fnGetList();
|
||||
});
|
||||
|
||||
/**
|
||||
* 终端连接状态
|
||||
* @param data 主机连接结果
|
||||
*/
|
||||
function fnTerminalConnect(data: Record<string, any>) {
|
||||
const { id, timeStamp } = data;
|
||||
const seconds = timeStamp / 1000;
|
||||
// 获取当前项下标
|
||||
const tab = tabState.panes.find(item => item.id === id);
|
||||
if (tab) {
|
||||
tab.status = true;
|
||||
tab.connectStamp = parseDuration(seconds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 终端关闭状态
|
||||
* @param data 主机连接结果
|
||||
*/
|
||||
function fnTerminalClose(data: Record<string, any>) {
|
||||
const { id } = data;
|
||||
// 获取当前项下标
|
||||
const tab = tabState.panes.find(item => item.id === id);
|
||||
if (tab) {
|
||||
tab.status = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 标签更多菜单项
|
||||
* @param key 菜单key
|
||||
*/
|
||||
function fnTabMenu(key: string | number) {
|
||||
// 刷新当前
|
||||
if (key === 'reload') {
|
||||
const tabIndex = tabState.panes.findIndex(
|
||||
item => item.id === tabState.activeKey
|
||||
);
|
||||
if (tabIndex) {
|
||||
const tab = tabState.panes[tabIndex];
|
||||
Modal.confirm({
|
||||
title: t('common.tipTitle'),
|
||||
content: t('views.tool.terminal.reloadTip', {
|
||||
num: `${tab.host.hostType} - ${tab.host.title}`,
|
||||
}),
|
||||
onOk() {
|
||||
tabState.panes.splice(tabIndex, 1);
|
||||
tab.host && fnConnectHost(tab.host);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
// 关闭当前
|
||||
if (key === 'current') {
|
||||
fnTabClose(tabState.activeKey);
|
||||
}
|
||||
// 关闭其他
|
||||
if (key === 'other') {
|
||||
Modal.confirm({
|
||||
title: t('common.tipTitle'),
|
||||
content: t('views.tool.terminal.otherTip'),
|
||||
onOk() {
|
||||
hostState.show = false;
|
||||
tabState.panes = tabState.panes.filter(
|
||||
tab => tab.id === '0' || tab.id === tabState.activeKey
|
||||
);
|
||||
tabState.activeKey = tabState.activeKey;
|
||||
},
|
||||
});
|
||||
}
|
||||
// 关闭全部
|
||||
if (key === 'all') {
|
||||
Modal.confirm({
|
||||
title: t('common.tipTitle'),
|
||||
content: t('views.tool.terminal.allTip'),
|
||||
onOk() {
|
||||
hostState.show = false;
|
||||
tabState.panes.splice(1);
|
||||
tabState.activeKey = '0';
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航标签关闭
|
||||
* @param id 标签的key
|
||||
*/
|
||||
function fnTabClose(id: string) {
|
||||
if (isFullscreen.value) toggle();
|
||||
|
||||
// 获取当前项下标
|
||||
const tabIndex = tabState.panes.findIndex(tab => tab.id === id);
|
||||
if (tabIndex === -1) return;
|
||||
const item = tabState.panes[tabIndex];
|
||||
Modal.confirm({
|
||||
title: t('common.tipTitle'),
|
||||
content: t('views.tool.terminal.closeTip', {
|
||||
num: `${item.host.hostType.toUpperCase()} - ${item.host.title}`,
|
||||
}),
|
||||
onOk() {
|
||||
tabState.panes.splice(tabIndex, 1);
|
||||
// 激活前一项标签
|
||||
tabState.activeKey = tabState.panes[tabIndex - 1].id;
|
||||
},
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -205,136 +78,13 @@ function fnTabClose(id: string) {
|
||||
<a-card
|
||||
:bordered="false"
|
||||
size="small"
|
||||
:body-style="{ padding: '12px' }"
|
||||
ref="terminalCard"
|
||||
:body-style="{ padding: '12px', height: 'calc(100vh - 200px)' }"
|
||||
:loading="hostState.loading"
|
||||
>
|
||||
<a-tabs
|
||||
class="terminal-tabs"
|
||||
hide-add
|
||||
size="small"
|
||||
tab-position="top"
|
||||
type="editable-card"
|
||||
:tab-bar-gutter="8"
|
||||
:tab-bar-style="{ margin: '0' }"
|
||||
v-model:activeKey="tabState.activeKey"
|
||||
@edit="(id:any) => fnTabClose(id)"
|
||||
>
|
||||
<a-tab-pane
|
||||
v-for="pane in tabState.panes"
|
||||
:key="pane.id"
|
||||
:closable="pane.id !== '0'"
|
||||
>
|
||||
<template #tab>
|
||||
<a-badge
|
||||
:status="pane.status ? 'success' : 'error'"
|
||||
:text="pane.host.title"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<div class="pane-box">
|
||||
<!-- 非开始页的ssh主机 -->
|
||||
<TerminalSSH
|
||||
v-if="pane.id !== '0' && pane.host.hostType === 'ssh'"
|
||||
:id="pane.id"
|
||||
:hostId="pane.host.id"
|
||||
@connect="fnTerminalConnect"
|
||||
@close="fnTerminalClose"
|
||||
>
|
||||
</TerminalSSH>
|
||||
|
||||
<!-- 非开始页的telnet主机 -->
|
||||
<TerminalTelnet
|
||||
v-if="pane.id !== '0' && pane.host.hostType === 'telnet'"
|
||||
:id="pane.id"
|
||||
:hostId="pane.host.id"
|
||||
init-cmd="help"
|
||||
:disable="true"
|
||||
@connect="fnTerminalConnect"
|
||||
@close="fnTerminalClose"
|
||||
>
|
||||
</TerminalTelnet>
|
||||
|
||||
<!-- 非开始页的redis主机 -->
|
||||
<TerminalRedis
|
||||
v-if="pane.id !== '0' && pane.host.hostType === 'redis'"
|
||||
:id="pane.id"
|
||||
:hostId="pane.host.id"
|
||||
init-cmd="PING"
|
||||
@connect="fnTerminalConnect"
|
||||
@close="fnTerminalClose"
|
||||
>
|
||||
</TerminalRedis>
|
||||
|
||||
<!-- 开始页 -->
|
||||
<div v-if="pane.id === '0'">
|
||||
<!-- 主机列表 -->
|
||||
<HostList
|
||||
v-show="tabState.activeKey === '0'"
|
||||
@modal="() => (isFullscreen ? toggle() : null)"
|
||||
@link="fnConnectHost"
|
||||
></HostList>
|
||||
</div>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
|
||||
<template #rightExtra>
|
||||
<a-space :size="8" align="center">
|
||||
<a-tooltip placement="topRight">
|
||||
<template #title>
|
||||
{{ t('loayouts.rightContent.fullscreen') }}
|
||||
</template>
|
||||
<a-button
|
||||
type="default"
|
||||
shape="circle"
|
||||
size="small"
|
||||
style="color: inherit"
|
||||
@click="toggle"
|
||||
>
|
||||
<template #icon>
|
||||
<FullscreenExitOutlined v-if="isFullscreen" />
|
||||
<FullscreenOutlined v-else />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<!-- 非开始页的更多操作 -->
|
||||
<div v-show="tabState.activeKey !== '0'">
|
||||
<a-tooltip placement="topRight">
|
||||
<template #title>
|
||||
{{ t('views.tool.terminal.more') }}
|
||||
</template>
|
||||
<a-dropdown trigger="click" placement="bottomRight">
|
||||
<a-button type="ghost" shape="circle" size="small">
|
||||
<template #icon><EllipsisOutlined /></template>
|
||||
</a-button>
|
||||
<template #overlay>
|
||||
<a-menu @click="({ key }:any) => fnTabMenu(key)">
|
||||
<a-menu-item key="reload">
|
||||
{{ t('views.tool.terminal.reload') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="current">
|
||||
{{ t('views.tool.terminal.current') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="other">
|
||||
{{ t('views.tool.terminal.other') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="all">
|
||||
{{ t('views.tool.terminal.all') }}
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</a-space>
|
||||
</template>
|
||||
</a-tabs>
|
||||
<TerminalSSH :id="hostState.host.title" :hostId="hostState.host.id">
|
||||
</TerminalSSH>
|
||||
</a-card>
|
||||
</PageContainer>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.pane-box {
|
||||
height: calc(100vh - 200px);
|
||||
overflow-x: hidden;
|
||||
}
|
||||
</style>
|
||||
<style lang="less" scoped></style>
|
||||
@@ -593,13 +593,13 @@ onMounted(() => {
|
||||
<!-- 插槽-卡片左侧侧 -->
|
||||
<template #title>
|
||||
<a-space :size="8" align="center">
|
||||
<a-button @click="fnFileView()">
|
||||
<a-button @click="fnFileView()" v-perms:has="['traceManage:pcap:fileview']">
|
||||
<FileSearchOutlined />
|
||||
{{ t('views.traceManage.pcap.fileView') }}
|
||||
</a-button>
|
||||
|
||||
<a-dropdown trigger="click">
|
||||
<a-button :disabled="tableState.selectedRowKeys.length <= 0">
|
||||
<a-button :disabled="tableState.selectedRowKeys.length <= 0" >
|
||||
{{ t('views.traceManage.pcap.batchOper') }}
|
||||
<DownOutlined />
|
||||
</a-button>
|
||||
@@ -678,6 +678,7 @@ onMounted(() => {
|
||||
size="small"
|
||||
:disabled="modalState.from[record.id].loading"
|
||||
@click.prevent="fnRecordStart(record)"
|
||||
v-perms:has="['traceManage:pcap:start']"
|
||||
>
|
||||
<template #icon><PlayCircleOutlined /> </template>
|
||||
</a-button>
|
||||
@@ -697,6 +698,7 @@ onMounted(() => {
|
||||
danger
|
||||
size="small"
|
||||
@click.prevent="fnRecordStop(record)"
|
||||
v-perms:has="['traceManage:pcap:stop']"
|
||||
>
|
||||
<template #icon><StopOutlined /> </template>
|
||||
</a-button>
|
||||
@@ -736,6 +738,7 @@ onMounted(() => {
|
||||
ghost
|
||||
size="small"
|
||||
@click.prevent="fnDownPCAP(record)"
|
||||
v-perms:has="['traceManage:pcap:download']"
|
||||
>
|
||||
<template #icon><DownloadOutlined /> </template>
|
||||
</a-button>
|
||||
|
||||
@@ -83,12 +83,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns: ColumnsType = reactive([
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'right',
|
||||
width: 50,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'right',
|
||||
// width: 50,
|
||||
// },
|
||||
{
|
||||
title: t('views.traceManage.task.imsi'),
|
||||
dataIndex: 'imsi',
|
||||
|
||||
@@ -95,12 +95,12 @@ let tableState: TabeStateType = reactive({
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns: ColumnsType = [
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
// {
|
||||
// title: t('common.rowId'),
|
||||
// dataIndex: 'id',
|
||||
// align: 'left',
|
||||
// width: 100,
|
||||
// },
|
||||
{
|
||||
title: t('views.traceManage.task.msgNe'),
|
||||
dataIndex: 'msgNe',
|
||||
|
||||
@@ -701,7 +701,7 @@ onMounted(() => {
|
||||
<!-- 插槽-卡片左侧侧 -->
|
||||
<template #title>
|
||||
<a-space :size="8" align="center">
|
||||
<a-button type="primary" @click.prevent="fnModalOpenByEdit()">
|
||||
<a-button type="primary" @click.prevent="fnModalOpenByEdit()" v-perms:has="['traceManage:task:add']">
|
||||
<template #icon><PlusOutlined /></template>
|
||||
{{ t('common.addText') }}
|
||||
</a-button>
|
||||
@@ -712,6 +712,7 @@ onMounted(() => {
|
||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||
:loading="modalState.confirmLoading"
|
||||
@click.prevent="fnRecordDelete('0')"
|
||||
v-perms:has="['traceManage:task:delete']"
|
||||
>
|
||||
<template #icon><DeleteOutlined /></template>
|
||||
{{ t('common.deleteText') }}
|
||||
@@ -796,6 +797,7 @@ onMounted(() => {
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordView(record, 'data')"
|
||||
v-perms:has="['traceManage:task:dataview']"
|
||||
>
|
||||
<template #icon><ContainerOutlined /></template>
|
||||
</a-button>
|
||||
@@ -809,6 +811,7 @@ onMounted(() => {
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordView(record, 'analyze')"
|
||||
v-perms:has="['traceManage:task:pcapview']"
|
||||
>
|
||||
<template #icon><BarsOutlined /></template>
|
||||
</a-button>
|
||||
@@ -820,6 +823,7 @@ onMounted(() => {
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnModalOpenByEdit(record.id)"
|
||||
v-perms:has="['traceManage:task:edit']"
|
||||
>
|
||||
<template #icon><ProfileOutlined /></template>
|
||||
</a-button>
|
||||
@@ -830,6 +834,7 @@ onMounted(() => {
|
||||
type="link"
|
||||
danger
|
||||
@click.prevent="fnRecordDelete(record.id)"
|
||||
v-perms:has="['traceManage:task:delete']"
|
||||
>
|
||||
<template #icon><DeleteOutlined /></template>
|
||||
</a-button>
|
||||
|
||||
@@ -582,6 +582,7 @@ onBeforeUnmount(() => {
|
||||
type="primary"
|
||||
@click="fnStart"
|
||||
:disabled="!taskState.stop && taskState.task.taskNo !== ''"
|
||||
v-perms:has="['traceManage:wireshark:start']"
|
||||
>
|
||||
<PlayCircleOutlined />
|
||||
Start Trace
|
||||
@@ -610,6 +611,7 @@ onBeforeUnmount(() => {
|
||||
danger
|
||||
@click.prevent="fnStop()"
|
||||
:disabled="taskState.stop || taskState.task.taskNo === ''"
|
||||
v-perms:has="['traceManage:wireshark:stop']"
|
||||
>
|
||||
<template #icon><CloseCircleOutlined /></template>
|
||||
Stop Trace
|
||||
@@ -701,7 +703,7 @@ onBeforeUnmount(() => {
|
||||
:data-source="tableState.data"
|
||||
size="small"
|
||||
:pagination="false"
|
||||
:row-class-name="(record:any) => {
|
||||
:row-class-name="(record:any) => {
|
||||
return `table-striped-${record.protocol}`
|
||||
}"
|
||||
:customRow="
|
||||
|
||||
Reference in new issue
Block a user