Merge remote-tracking branch 'origin/main' into multi-tenant
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# 历史路径-哈希带井号标识
|
||||
VITE_HISTORY_HASH = false
|
||||
VITE_HISTORY_HASH = true
|
||||
|
||||
# 历史路径-前缀URL如:/h5
|
||||
VITE_HISTORY_BASE_URL = "/"
|
||||
|
||||
38
package.json
38
package.json
@@ -15,32 +15,32 @@
|
||||
"@ant-design/icons-vue": "^7.0.1",
|
||||
"@antv/g6": "~4.8.24",
|
||||
"@codemirror/lang-javascript": "^6.2.2",
|
||||
"@codemirror/lang-yaml": "^6.1.1",
|
||||
"@codemirror/merge": "^6.7.2",
|
||||
"@codemirror/lang-yaml": "^6.1.2",
|
||||
"@codemirror/merge": "^6.7.4",
|
||||
"@codemirror/theme-one-dark": "^6.1.2",
|
||||
"@tato30/vue-pdf": "^1.11.2",
|
||||
"@vueuse/core": "11.2.0",
|
||||
"@tato30/vue-pdf": "^1.11.3",
|
||||
"@vueuse/core": "^12.0.0",
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"ant-design-vue": "^4.2.5",
|
||||
"antdv-pro-layout": "^4.1.9",
|
||||
"ant-design-vue": "^4.2.6",
|
||||
"antdv-pro-layout": "^4.2.0",
|
||||
"antdv-pro-modal": "^4.0.5",
|
||||
"codemirror": "^6.0.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.11",
|
||||
"echarts": "~5.5.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"grid-layout-plus": "^1.0.5",
|
||||
"intl-tel-input": "^24.6.0",
|
||||
"grid-layout-plus": "^1.0.6",
|
||||
"intl-tel-input": "^25.2.0",
|
||||
"js-base64": "^3.7.7",
|
||||
"js-cookie": "^3.0.5",
|
||||
"localforage": "^1.10.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"p-queue": "~8.0.1",
|
||||
"pinia": "2.2.6",
|
||||
"vue": "^3.5.12",
|
||||
"vue-i18n": "^10.0.4",
|
||||
"vue-router": "^4.4.5",
|
||||
"pinia": "^2.3.0",
|
||||
"vue": "^3.5.13",
|
||||
"vue-i18n": "^10.0.5",
|
||||
"vue-router": "^4.5.0",
|
||||
"vue3-smooth-dnd": "^0.0.6",
|
||||
"xlsx": "~0.18.5"
|
||||
},
|
||||
@@ -48,14 +48,14 @@
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/node": "^22.7.7",
|
||||
"@types/node": "^18.0.0",
|
||||
"@types/nprogress": "^0.2.3",
|
||||
"@vitejs/plugin-vue": "^5.1.4",
|
||||
"less": "^4.2.0",
|
||||
"typescript": "^5.6.3",
|
||||
"unplugin-vue-components": "^0.27.4",
|
||||
"vite": "5.4.10",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"less": "^4.2.1",
|
||||
"typescript": "~5.6.3",
|
||||
"unplugin-vue-components": "^0.27.5",
|
||||
"vite": "^6.0.3",
|
||||
"vite-plugin-compression": "~0.5.1",
|
||||
"vue-tsc": "^2.1.8"
|
||||
"vue-tsc": "~2.1.10"
|
||||
}
|
||||
}
|
||||
|
||||
42
src/api/neData/sgwc.ts
Normal file
42
src/api/neData/sgwc.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { request } from '@/plugins/http-fetch';
|
||||
|
||||
/**
|
||||
* 查询SGWC-CDR会话事件
|
||||
* @param query 查询参数
|
||||
* @returns object
|
||||
*/
|
||||
export function listSGWCDataCDR(query: Record<string, any>) {
|
||||
return request({
|
||||
url: '/neData/sgwc/cdr/list',
|
||||
method: 'get',
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* SGWC-CDR会话删除
|
||||
* @param id 信息ID
|
||||
* @returns object
|
||||
*/
|
||||
export function delSGWCDataCDR(cdrIds: string | number) {
|
||||
return request({
|
||||
url: `/neData/sgwc/cdr/${cdrIds}`,
|
||||
method: 'delete',
|
||||
timeout: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* SGWC-CDR会话列表导出
|
||||
* @param data 查询列表条件
|
||||
* @returns object
|
||||
*/
|
||||
export function exportSGWCDataCDR(data: Record<string, any>) {
|
||||
return request({
|
||||
url: '/neData/sgwc/cdr/export',
|
||||
method: 'post',
|
||||
data,
|
||||
responseType: 'blob',
|
||||
timeout: 60_000,
|
||||
});
|
||||
}
|
||||
@@ -41,14 +41,27 @@ export function exportSMFDataCDR(data: Record<string, any>) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* SMF-在线订阅用户数量
|
||||
* @param query 查询参数
|
||||
* @returns object
|
||||
*/
|
||||
export function listSMFSubNum(neId: string) {
|
||||
return request({
|
||||
url: '/neData/smf/sub/num',
|
||||
method: 'get',
|
||||
params: { neId },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* SMF-在线订阅用户列表信息
|
||||
* @param query 查询参数
|
||||
* @returns object
|
||||
*/
|
||||
export function listSMFSubscribers(query: Record<string, any>) {
|
||||
export function listSMFSubList(query: Record<string, any>) {
|
||||
return request({
|
||||
url: '/neData/smf/subscribers',
|
||||
url: '/neData/smf/sub/list',
|
||||
method: 'get',
|
||||
params: query,
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ export const NE_TYPE_LIST = [
|
||||
'IMS',
|
||||
'AMF',
|
||||
'AUSF',
|
||||
'UDR',
|
||||
'UDM',
|
||||
'SMF',
|
||||
'PCF',
|
||||
@@ -19,6 +20,8 @@ export const NE_TYPE_LIST = [
|
||||
'SMSF',
|
||||
'CBC',
|
||||
'CHF',
|
||||
'HLR',
|
||||
'SGWC',
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -222,12 +222,11 @@ export default {
|
||||
capability: 'Capability',
|
||||
serialNum: 'Serial Number',
|
||||
expiryDate: 'Expiry Date',
|
||||
neStatus: 'NE status is abnormal',
|
||||
runStatus:'Running Status',
|
||||
mark:'Brief Information',
|
||||
neStatus: 'Status Abnormal',
|
||||
runStatus:'Status',
|
||||
mark:'Information',
|
||||
object:'Object',
|
||||
versionNum:'Version',
|
||||
systemStatus:'Status',
|
||||
realNeStatus:'Status',
|
||||
reloadTime:'Refresh Time',
|
||||
Critical:'Critical',
|
||||
@@ -351,163 +350,6 @@ export default {
|
||||
description: "No data yet, try refreshing",
|
||||
},
|
||||
},
|
||||
configManage: {
|
||||
neManage: {
|
||||
addNe:'Add Network Element',
|
||||
delSure:'Confirm deleting the data item with network element name {msg}',
|
||||
editNe:'Edit Network Element',
|
||||
exportSure:'Confirm exporting the configuration information with the network element name {msg}',
|
||||
exportTip:'Export successful, please go to backup management for download',
|
||||
getInfo:'Failed to get network element information',
|
||||
neType:'NE Type',
|
||||
neTypePlease: 'Select network element type',
|
||||
neId:'NE ID',
|
||||
neName:'NE Name',
|
||||
neTypeTip:'Fill in the type of network element created, such as:SMF',
|
||||
uid:'RM UID',
|
||||
uidTip:'Please enter a unique resource identifier',
|
||||
ip:'IP Address',
|
||||
mac:'NE MAC address',
|
||||
macTip:'Able to locate the physical address (MAC) of the network element',
|
||||
port:'Port',
|
||||
portTip:'Maximum range 0~65535',
|
||||
pvflag:'PV Flag',
|
||||
pnf:'Physical Network Element',
|
||||
vnf:'Virtual Network Element',
|
||||
province:'Region',
|
||||
vendorName:'Vendor Name',
|
||||
dn:'Network Identification',
|
||||
reload: 'Reload',
|
||||
restart: 'Restart',
|
||||
totalSure:'Confirm the network element with {operator} network element name {msg}',
|
||||
stop: 'Stop',
|
||||
start: 'Start',
|
||||
log: 'Logs',
|
||||
export: 'Export',
|
||||
import: 'Import',
|
||||
fileForm:'File Source',
|
||||
selectPlease:'Please select the source of the import file',
|
||||
server:'Server File',
|
||||
local:'Local File',
|
||||
fileSelect:'Please select the current import file',
|
||||
sync:'Synchronize to NE',
|
||||
open:'Open',
|
||||
close:'Close',
|
||||
addFail:'Add failed',
|
||||
operFail:'Operation Failed'
|
||||
},
|
||||
backupManage: {
|
||||
setBackupTask: 'Set automatic backup time',
|
||||
neTypePlease: 'Query network element type',
|
||||
neType: 'NE Type',
|
||||
neID: 'NE ID',
|
||||
fileName: 'File Name',
|
||||
createAt: 'Create at',
|
||||
remark:'Remark',
|
||||
edit:'Edit Backup File',
|
||||
totalSure:'Confirm that {oper} records item number {id}?',
|
||||
},
|
||||
softwareManage: {
|
||||
sendBtn: 'Distribute',
|
||||
runBtn: 'Activate',
|
||||
backBtn: 'Rollback',
|
||||
historyBtn: 'Distribution Record',
|
||||
neTypePlease: 'Select network element type',
|
||||
neType: 'NE Type',
|
||||
fileName: 'File Name',
|
||||
version: 'Version',
|
||||
versionPlease: 'Version number cannot be empty',
|
||||
updateTime: 'Uploaded Time',
|
||||
description: 'Description',
|
||||
deleteTip: 'Are you sure to delete the data item with software [{fileName}]?',
|
||||
downloadTip: 'Are you sure to download the data item with software [{fileName}]?',
|
||||
updateComment: 'Comment',
|
||||
updateCommentPlease: 'Please enter the software description',
|
||||
updateFile: 'Software File',
|
||||
updateFilePlease: 'Please upload the updated software file',
|
||||
verifyFile: 'Verify File',
|
||||
selectFile: 'SELECT FILE',
|
||||
sendTitle: 'Distribute software version',
|
||||
sendContent: 'Are you sure to send the file with the software package [{fileName}] to the corresponding network element?',
|
||||
runTitle: 'Activate software version',
|
||||
runContent: 'Are you sure to activate the software version of [{fileName}] that has been issued to the corresponding network element?',
|
||||
backTitle: 'Fallback software version',
|
||||
backContent: 'Confirm that the software version of [{fileName}] has been issued for the corresponding network element rollback?',
|
||||
neId: 'Corresponding network element',
|
||||
neIdPlease: 'Please select the corresponding network element',
|
||||
versions:'Version',
|
||||
upVersions:'Version before upgrade',
|
||||
backVersions:'Version before rollback',
|
||||
status:'Status',
|
||||
letUpTime:'Activation time',
|
||||
createTime:'Creation time',
|
||||
onlyAble:'Only upload file format {fileText} is supported',
|
||||
nullVersion:'There is no rollback version for the current network element.',
|
||||
},
|
||||
license: {
|
||||
neTypePlease: 'Select network element type',
|
||||
neType: 'NE Type',
|
||||
serialNum: 'Serial Num',
|
||||
createTime: 'Time',
|
||||
comment: 'Description',
|
||||
updateComment: 'License Description',
|
||||
updateCommentPlease: 'Please enter a license description',
|
||||
updateFile: 'License File',
|
||||
updateFilePlease: 'Please upload and update the License file',
|
||||
selectFile: 'SELECT FILE',
|
||||
neId: 'NE ID',
|
||||
neIdPlease: 'Please select the corresponding network element',
|
||||
},
|
||||
configParam:{
|
||||
dataNull:'No configuration item data yet',
|
||||
editSuss:'Modification successful',
|
||||
editFail:'Edit failed',
|
||||
Unable:'Illegal operation of attribute value',
|
||||
delSure:'Confirm to delete the data item with Index [{value}]?',
|
||||
addSuss:'Add successfully',
|
||||
addFail:'Add failed',
|
||||
delArraySure:'Confirm to delete the data item with {arrayChildTitle} Index as [{value}]?',
|
||||
parUnable:'The parameter value is not within the reasonable range',
|
||||
ipv4Tip:'Not a legal IPV4 address',
|
||||
ipv6Tip:'Not a legal IPV6 address',
|
||||
enumTip:'Not a reasonable enumeration value',
|
||||
boolTip:'Not a reasonable Boolean value',
|
||||
default:'The input value is of unknown type',
|
||||
reloadSuss:'Network element reloading completed',
|
||||
reloadFail:'Network element reloading failed',
|
||||
neNUll:'No network element list data yet',
|
||||
reload:'Reload',
|
||||
post:'Submit',
|
||||
editSure:'Are you sure you want to update this attribute value? ',
|
||||
arraryEdit:'Are you sure to submit the record whose updated Index is [{value}]? ',
|
||||
addSure:'Are you sure to submit the new record of Index: [{value}]? '
|
||||
},
|
||||
configParamForm: {
|
||||
treeTitle: "Navigation Configuration",
|
||||
treeSelectTip: "Select configuration item information in the left configuration navigation!",
|
||||
neType: 'NE Type',
|
||||
neTypePleace: "Please select the network element type",
|
||||
noConfigData: "No data on configuration items",
|
||||
updateValue: "[ {num} ] parameter value modified successfully.",
|
||||
updateValueErr: "Attribute value modification failure",
|
||||
updateItem: "Modify Index to {num}.",
|
||||
updateItemErr: "Record modification failure",
|
||||
delItemOk: "Deleting Index as {num} succeeded",
|
||||
addItemOk: "Add Index as {num} Record Succeeded",
|
||||
addItemErr: "Record addition failure",
|
||||
requireUn: "[ {display} ] input value is of unknown type",
|
||||
requireString: "[ {display} ] parameter value is invalid.",
|
||||
requireInt: "[ {display} ] parameter value not in reasonable range {filter}",
|
||||
requireIpv4: "[ {display} ] not a legitimate IPV4 address",
|
||||
requireIpv6: "[ {display} ] not a legitimate IPV6 address.",
|
||||
requireEnum: "[ {display} ] is not a reasonable enumeration value.",
|
||||
requireBool: "[ {display} ] is not a reasonable boolean value.",
|
||||
editOkTip: "Confirm updating the value of this [ {num} ] attribute?",
|
||||
updateItemTip: "Confirm updating the data item with Index [{num}]?",
|
||||
delItemTip: "Confirm deleting the data item with Index [{num}]?",
|
||||
arrayMore: "Expand",
|
||||
},
|
||||
},
|
||||
dashboard: {
|
||||
overview:{
|
||||
title: "Core Network Dashboard",
|
||||
@@ -580,14 +422,18 @@ export default {
|
||||
delTip: "Confirm deletion of the data item numbered [{msg}]?",
|
||||
tenantName: "Tenant Name",
|
||||
exportTip: "Do you confirm to export the current query conditions of the CDR data? (Maximum 10,000 items can be exported.)",
|
||||
smfChargingID: 'Charging ID',
|
||||
chargingID: 'Charging ID',
|
||||
smfSubscriptionIDData: 'Subscription ID Data',
|
||||
smfSubscriptionIDType: 'Subscription ID Type',
|
||||
smfDataVolumeUplink: 'Data Volume Uplink',
|
||||
smfDataVolumeDownlink: 'Data Volume Downlink',
|
||||
smfDataTotalVolume: 'Data Total Volume',
|
||||
smfDuration: 'Duration',
|
||||
smfInvocationTime: 'Invocation Time',
|
||||
durationTime: 'Duration',
|
||||
invocationTime: 'Invocation Time',
|
||||
sgwcServedIMSI: 'IMSI',
|
||||
sgwcServedMSISDN: 'MSISDN',
|
||||
sgwcVolumeGPRSUplink: 'GPRS Uplink',
|
||||
sgwcVolumeGPRSDownlink: 'GPRS Downlink',
|
||||
},
|
||||
ue: {
|
||||
eventType: "Event Type",
|
||||
@@ -785,7 +631,9 @@ export default {
|
||||
treeSelectTip: "Select configuration item information in the left configuration navigation!",
|
||||
neType: 'NE Type',
|
||||
neTypePleace: "Please select the network element type",
|
||||
neIdSyncPleace: "Please select the synchronized network element",
|
||||
noConfigData: "No data on configuration items",
|
||||
noConfigdDisabled: "The configuration item is not normal",
|
||||
updateValue: "[ {num} ] parameter value modified successfully.",
|
||||
updateValueErr: "Attribute value modification failure",
|
||||
updateItem: "Modify Index to {num}.",
|
||||
|
||||
@@ -222,13 +222,12 @@ export default {
|
||||
capability: '用户容量',
|
||||
serialNum: '序列号',
|
||||
expiryDate: '许可证到期日期',
|
||||
neStatus:'网元状态异常',
|
||||
neStatus:'状态异常',
|
||||
runStatus:'运行状态',
|
||||
mark:'简略信息',
|
||||
mark:'信息',
|
||||
object:'对象',
|
||||
versionNum:'版本号',
|
||||
systemStatus:'系统状态',
|
||||
realNeStatus:'网元状态',
|
||||
realNeStatus:'状态',
|
||||
reloadTime:'刷新时间',
|
||||
Critical:'严重告警',
|
||||
Major:'主要告警',
|
||||
@@ -351,163 +350,6 @@ export default {
|
||||
description: "暂无数据,尝试刷新看看",
|
||||
},
|
||||
},
|
||||
configManage: {
|
||||
neManage: {
|
||||
addNe:'添加网元',
|
||||
delSure:'确认删除网元名称为{msg}的数据项 ',
|
||||
editNe:'修改网元',
|
||||
exportSure:'确认导出网元名称为 {msg} 的配置信息',
|
||||
exportTip:'导出成功,请到备份管理进行下载',
|
||||
getInfo:'获取网元信息失败',
|
||||
neType:'网元类型',
|
||||
neTypePlease: '请输入网元类型',
|
||||
neId:'网元内部标识',
|
||||
neName:'网元名称',
|
||||
neTypeTip:'填写创建的网元类型,如:SMF',
|
||||
uid:'资源唯一标识',
|
||||
uidTip:'请输入资源唯一标识',
|
||||
ip:'IP地址',
|
||||
mac:'网元物理地址',
|
||||
macTip:'能够定位网元的物理地址(MAC)',
|
||||
port:'端口',
|
||||
portTip:'最大范围0~65535',
|
||||
pvflag:'网元虚拟化标识',
|
||||
pnf:'物理网元',
|
||||
vnf:'虚拟网元',
|
||||
province:'网元服务省份',
|
||||
vendorName:'厂商名称',
|
||||
dn:'网络标识',
|
||||
reload: '重载',
|
||||
restart: '重启',
|
||||
totalSure:'确认{oper}网元名称为 {msg} 的网元',
|
||||
stop: '停止',
|
||||
start: '启动',
|
||||
log: '日志',
|
||||
export: '导出',
|
||||
import: '导入',
|
||||
fileForm:'文件来源',
|
||||
selectPlease:'请选择导入文件来源',
|
||||
server:'服务器文件',
|
||||
local:'本地文件',
|
||||
fileSelect:'请选择当前导入文件',
|
||||
sync:'同步到网元',
|
||||
open:'开',
|
||||
close:'关',
|
||||
addFail:'新增失败',
|
||||
operFail:'操作失败'
|
||||
},
|
||||
backupManage: {
|
||||
setBackupTask: '设置自动备份时间',
|
||||
neTypePlease: '查询网元类型',
|
||||
neType: '网元类型',
|
||||
neID: '网元内部标识',
|
||||
fileName: '文件名',
|
||||
createAt: '创建时间',
|
||||
remark:'备份说明',
|
||||
edit:'编辑备份文件',
|
||||
totalSure:'确认{oper}记录编号为 {id} 的数据项?',
|
||||
},
|
||||
softwareManage: {
|
||||
sendBtn: '下发',
|
||||
runBtn: '激活',
|
||||
backBtn: '回退',
|
||||
historyBtn: '下发记录',
|
||||
neTypePlease: '选择网元类型',
|
||||
neType: '网元类型',
|
||||
fileName: '文件名',
|
||||
version: '版本号',
|
||||
versionPlease: '版本号不能为空',
|
||||
updateTime: '上传时间',
|
||||
description: '功能描述',
|
||||
deleteTip: '确认删除 【{fileName}】 的软件数据项?',
|
||||
downloadTip: '确认下载 【{fileName}】 的软件数据项?',
|
||||
updateComment: '软件说明',
|
||||
updateCommentPlease: '请输入软件说明',
|
||||
updateFile: '软件文件',
|
||||
updateFilePlease: '请上传更新软件文件',
|
||||
verifyFile: '校验文件',
|
||||
selectFile: '选择文件',
|
||||
sendTitle: '下发软件版本',
|
||||
sendContent: '确认下发软件包为【{fileName}】的文件到对应网元?',
|
||||
runTitle: '激活软件版本',
|
||||
runContent: '确认在对应网元激活已下发【{fileName}】的软件版本?',
|
||||
backTitle: '回退软件版本',
|
||||
backContent: '确认在对应网元回退已下发【{fileName}】的软件版本?',
|
||||
neId: '对应网元',
|
||||
neIdPlease: '请选择对应网元',
|
||||
versions:'版本',
|
||||
upVersions:'升级前版本',
|
||||
backVersions:'回退前版本',
|
||||
status:'状态',
|
||||
letUpTime:'激活时间',
|
||||
createTime:'创建时间',
|
||||
onlyAble:'只支持上传文件格式 {fileText}',
|
||||
nullVersion:'当前网元无可回退版本',
|
||||
},
|
||||
license: {
|
||||
neTypePlease: '选择网元类型',
|
||||
neType: '网元类型',
|
||||
serialNum: '序列号',
|
||||
createTime: '时间',
|
||||
comment: '说明',
|
||||
updateComment: 'License说明',
|
||||
updateCommentPlease: '请输入License说明',
|
||||
updateFile: 'License文件',
|
||||
updateFilePlease: '请上传更新License文件',
|
||||
selectFile: '选择文件',
|
||||
neId: '网元内部标识',
|
||||
neIdPlease: '请选择对应网元',
|
||||
},
|
||||
configParam:{
|
||||
dataNull:'暂无配置项数据',
|
||||
editSuss:'修改成功',
|
||||
editFail:'修改失败',
|
||||
unable:'非法操作属性值',
|
||||
delSure:'确认删除Index为 【{value}】 的数据项?',
|
||||
addSuss:'新增成功',
|
||||
addFail:'新增失败',
|
||||
delArraySure:'确认删除{arrayChildTitle} Index 为 【{value}】 的数据项?',
|
||||
parUnable:'参数值不在合理范围',
|
||||
ipv4Tip:'不是合法的IPV4地址',
|
||||
ipv6Tip:'不是合法的IPV6地址',
|
||||
enumTip:'不是合理的枚举值',
|
||||
boolTip:'不是合理的布尔类型的值',
|
||||
default:'输入值是未知类型',
|
||||
reloadSuss:'网元重新加载完成',
|
||||
reloadFail:'网元重新加载失败',
|
||||
neNUll:'暂无网元列表数据',
|
||||
reload:'重载',
|
||||
post:'提交',
|
||||
editSure:'确认更新该属性值吗?',
|
||||
arraryEdit:'确认提交更新 Index 为 【{value}】 的记录吗?',
|
||||
addSure:'确认提交新增 Index :【{value}】 的记录吗?',
|
||||
},
|
||||
configParamForm: {
|
||||
treeTitle: "配置导航",
|
||||
treeSelectTip: "左侧配置导航中选择配置项信息!",
|
||||
neType: "网元类型",
|
||||
neTypePleace: "请选择网元类型",
|
||||
noConfigData: "暂无配置项数据",
|
||||
updateValue: "【 {num} 】 属性值修改成功",
|
||||
updateValueErr: "属性值修改失败",
|
||||
updateItem: "修改 Index 为 {num} 记录成功",
|
||||
updateItemErr: "记录修改失败",
|
||||
delItemOk: "删除 Index 为 {num} 记录成功",
|
||||
addItemOk: "新增 Index 为 {num} 记录成功",
|
||||
addItemErr: "记录新增失败",
|
||||
requireUn: "【 {display} 】输入值是未知类型",
|
||||
requireString: "【 {display} 】参数值不合理",
|
||||
requireInt: "【 {display} 】参数值不在合理范围 {filter}",
|
||||
requireIpv4: "【 {display} 】不是合法的IPV4地址",
|
||||
requireIpv6: "【 {display} 】不是合法的IPV6地址",
|
||||
requireEnum: "【 {display} 】不是合理的枚举值",
|
||||
requireBool: "【 {display} 】不是合理的布尔类型的值",
|
||||
editOkTip: "确认更新该【 {num} 】属性值吗?",
|
||||
updateItemTip: "确认更新Index为 【{num}】 的数据项?",
|
||||
delItemTip: "确认删除Index为 【{num}】 的数据项?",
|
||||
arrayMore: "展开",
|
||||
},
|
||||
},
|
||||
dashboard: {
|
||||
overview:{
|
||||
title: "核心网系统看板",
|
||||
@@ -580,14 +422,18 @@ export default {
|
||||
delTip: "确认删除编号为【{msg}】的数据项?",
|
||||
tenantName: "租户名称",
|
||||
exportTip: "确认导出当前查询条件的话单数据吗?(导出最大支持一万条)",
|
||||
smfChargingID: '计费ID',
|
||||
chargingID: '计费ID',
|
||||
smfSubscriptionIDData: '订阅 ID 数据',
|
||||
smfSubscriptionIDType: '订阅 ID 类型',
|
||||
smfDataVolumeUplink: '数据量上行链路',
|
||||
smfDataVolumeDownlink: '数据量下行链路',
|
||||
smfDataTotalVolume: '数据总量',
|
||||
smfDuration: '持续时间',
|
||||
smfInvocationTime: '调用时间',
|
||||
durationTime: '持续时间',
|
||||
invocationTime: '调用时间',
|
||||
sgwcServedIMSI: 'IMSI',
|
||||
sgwcServedMSISDN: 'MSISDN',
|
||||
sgwcVolumeGPRSUplink: 'GPRS 上行链路',
|
||||
sgwcVolumeGPRSDownlink: 'GPRS 下行链路',
|
||||
},
|
||||
ue: {
|
||||
eventType: "事件类型",
|
||||
@@ -785,7 +631,9 @@ export default {
|
||||
treeSelectTip: "左侧配置导航中选择配置项信息!",
|
||||
neType: "网元类型",
|
||||
neTypePleace: "请选择网元类型",
|
||||
neIdSyncPleace: "请选择同步网元",
|
||||
noConfigData: "暂无配置项数据",
|
||||
noConfigdDisabled: "配置项网元未正常服务",
|
||||
updateValue: "【 {num} 】 属性值修改成功",
|
||||
updateValueErr: "属性值修改失败",
|
||||
updateItem: "修改 Index 为 {num} 记录成功",
|
||||
|
||||
@@ -54,7 +54,7 @@ const useAppStore = defineStore('app', {
|
||||
version: `-`,
|
||||
buildTime: `-`,
|
||||
bootloader: false,
|
||||
loginAuth: false,
|
||||
loginAuth: true,
|
||||
serialNum: `-`,
|
||||
copyright: `Copyright ©2023 For ${import.meta.env.VITE_APP_NAME}`,
|
||||
logoType: 'icon',
|
||||
@@ -88,7 +88,7 @@ const useAppStore = defineStore('app', {
|
||||
if (this.bootloader) {
|
||||
removeToken();
|
||||
}
|
||||
this.loginAuth = res.data.loginAuth === 'true';
|
||||
this.loginAuth = res.data.loginAuth !== 'false' ;
|
||||
this.serialNum = res.data.serialNum;
|
||||
this.appName = res.data.title;
|
||||
this.copyright = res.data.copyright;
|
||||
|
||||
@@ -126,7 +126,7 @@ export function parseDataToTreeExclude(
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析树结构数据转出一维id数组
|
||||
* 解析树结构数据转出所有一维id数组
|
||||
*
|
||||
* @param data 数组数据
|
||||
* @param fieldId 读取节点字段 默认 'id'
|
||||
@@ -158,7 +158,7 @@ export function parseTreeKeys(
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析树结构数据转出含子节点的一维id数组
|
||||
* 解析树结构数据转出根节点的一维id数组
|
||||
*
|
||||
* @param data 数组数据
|
||||
* @param fieldId 读取节点字段 默认 'id'
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -49,7 +49,6 @@ let indexColor = ref<DictType[]>([
|
||||
]);
|
||||
|
||||
/**表格字段列 */
|
||||
//customRender(){} ----单元格处理
|
||||
let tableColumns: ColumnsType = [
|
||||
{
|
||||
title: t('views.index.object'),
|
||||
@@ -67,7 +66,9 @@ let tableColumns: ColumnsType = [
|
||||
dataIndex: 'serverState',
|
||||
align: 'left',
|
||||
customRender(opt) {
|
||||
if (opt.value?.refreshTime) return parseDateToStr(opt.value?.refreshTime);
|
||||
if (opt.value?.refreshTime) {
|
||||
return parseDateToStr(opt.value?.refreshTime, 'HH:mm:ss');
|
||||
}
|
||||
return '-';
|
||||
},
|
||||
},
|
||||
@@ -104,12 +105,13 @@ let tableColumns: ColumnsType = [
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
/**表格状态类型 */
|
||||
type TabeStateType = {
|
||||
/**加载等待 */
|
||||
loading: boolean;
|
||||
/**记录数据 */
|
||||
data: object[];
|
||||
data: Record<string, any>[];
|
||||
/**勾选记录 */
|
||||
selectedRowKeys: (string | number)[];
|
||||
};
|
||||
@@ -121,105 +123,75 @@ let tableState: TabeStateType = reactive({
|
||||
selectedRowKeys: [],
|
||||
});
|
||||
|
||||
/**表格状态 */
|
||||
let nfInfo: any = reactive({
|
||||
obj: 'OMC',
|
||||
version: appStore.version,
|
||||
status: t('views.index.normal'),
|
||||
outTimeDate: '',
|
||||
serialNum: appStore.serialNum,
|
||||
});
|
||||
|
||||
/**表格状态类型 */
|
||||
type nfStateType = {
|
||||
/**主机名 */
|
||||
hostName: string;
|
||||
/**操作系统信息 */
|
||||
osInfo: string;
|
||||
/**IP地址 */
|
||||
ipAddress: string;
|
||||
/**版本 */
|
||||
version: string;
|
||||
/**CPU利用率 */
|
||||
cpuUse: string;
|
||||
/**内存使用 */
|
||||
memoryUse: string;
|
||||
/**用户容量 */
|
||||
capability: number;
|
||||
/**序列号 */
|
||||
serialNum: string;
|
||||
/**许可证到期日期 */
|
||||
/* selectedRowKeys: (string | number)[];*/
|
||||
expiryDate: string;
|
||||
};
|
||||
/**网元详细信息 */
|
||||
let pronInfo: nfStateType = reactive({
|
||||
hostName: '5gc',
|
||||
osInfo: 'Linux 5gc 4.15.0-112-generic 2020 x86_64 GNU/Linux',
|
||||
ipAddress: '-',
|
||||
version: '-',
|
||||
cpuUse: '-',
|
||||
memoryUse: '-',
|
||||
capability: 0,
|
||||
serialNum: '-',
|
||||
expiryDate: '-',
|
||||
});
|
||||
/**状态 */
|
||||
let serverState: any = ref({});
|
||||
|
||||
/**查询网元状态列表 */
|
||||
function fnGetList(one: boolean) {
|
||||
if (tableState.loading) return;
|
||||
one && (tableState.loading = true);
|
||||
listAllNeInfo({ bandStatus: true }).then(res => {
|
||||
tableState.data = res.data;
|
||||
tableState.loading = false;
|
||||
var rightNum = 0;
|
||||
var errorNum = 0;
|
||||
res.data.forEach((item: any) => {
|
||||
if (item.serverState.online) {
|
||||
rightNum++;
|
||||
if (one) {
|
||||
tableState.loading = true;
|
||||
}
|
||||
listAllNeInfo({ bandStatus: true })
|
||||
.then(res => {
|
||||
tableState.data = res.data;
|
||||
tableState.loading = false;
|
||||
if (one && res.data.length > 0) {
|
||||
const id = res.data[0].id;
|
||||
fnTableSelectedRowKeys([id]);
|
||||
} else {
|
||||
errorNum++;
|
||||
fnTableSelectedRowKeys(tableState.selectedRowKeys);
|
||||
}
|
||||
});
|
||||
const optionData: any = {
|
||||
title: {
|
||||
text: '',
|
||||
subtext: '',
|
||||
left: 'center',
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
left: 'left',
|
||||
},
|
||||
color: indexColor.value.map(item => item.tagClass),
|
||||
series: [
|
||||
{
|
||||
name: t('views.index.realNeStatus'),
|
||||
type: 'pie',
|
||||
radius: '70%',
|
||||
center: ['50%', '50%'],
|
||||
data: [
|
||||
{ value: rightNum, name: t('views.index.normal') },
|
||||
{ value: errorNum, name: t('views.index.abnormal') },
|
||||
],
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
||||
},
|
||||
},
|
||||
|
||||
label: {},
|
||||
})
|
||||
.finally(() => {
|
||||
var rightNum = 0;
|
||||
var errorNum = 0;
|
||||
for (const v of tableState.data) {
|
||||
if (v?.serverState?.online) {
|
||||
rightNum++;
|
||||
} else {
|
||||
errorNum++;
|
||||
}
|
||||
}
|
||||
/// 图表数据
|
||||
const optionData: any = {
|
||||
title: {
|
||||
text: '',
|
||||
subtext: '',
|
||||
left: 'center',
|
||||
},
|
||||
],
|
||||
};
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
left: 'left',
|
||||
},
|
||||
color: indexColor.value.map(item => item.tagClass),
|
||||
series: [
|
||||
{
|
||||
name: t('views.index.realNeStatus'),
|
||||
type: 'pie',
|
||||
radius: '70%',
|
||||
center: ['50%', '50%'],
|
||||
data: [
|
||||
{ value: rightNum, name: t('views.index.normal') },
|
||||
{ value: errorNum, name: t('views.index.abnormal') },
|
||||
],
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
||||
},
|
||||
},
|
||||
|
||||
fnDesign(statusBar.value, optionData);
|
||||
});
|
||||
label: {},
|
||||
},
|
||||
],
|
||||
};
|
||||
fnDesign(statusBar.value, optionData);
|
||||
});
|
||||
}
|
||||
|
||||
function fnDesign(container: HTMLElement | undefined, option: any) {
|
||||
@@ -240,66 +212,43 @@ function fnDesign(container: HTMLElement | undefined, option: any) {
|
||||
observer.observe(container);
|
||||
}
|
||||
|
||||
/**抽屉 网元详细信息 */
|
||||
const open = ref(false);
|
||||
const closeDrawer = () => {
|
||||
open.value = false;
|
||||
};
|
||||
/**抽屉 网元详细信息 */
|
||||
/**表格多选 */
|
||||
function fnTableSelectedRowKeys(keys: (string | number)[]) {
|
||||
if (keys.length <= 0) return;
|
||||
const id = keys[0];
|
||||
const row: any = tableState.data.find((item: any) => item.id === id);
|
||||
if (!row) {
|
||||
message.error(t('views.index.neStatus'), 2);
|
||||
return;
|
||||
}
|
||||
const neState = row.serverState;
|
||||
if (!neState?.online) {
|
||||
message.error(t('views.index.neStatus'), 2);
|
||||
return;
|
||||
}
|
||||
tableState.selectedRowKeys = keys;
|
||||
// Mem 将KB转换为MB
|
||||
const totalMemInKB = neState.mem?.totalMem;
|
||||
const nfUsedMemInKB = neState.mem?.nfUsedMem;
|
||||
const sysMemUsageInKB = neState.mem?.sysMemUsage;
|
||||
const totalMemInMB = Math.round((totalMemInKB / 1024) * 100) / 100;
|
||||
const nfUsedMemInMB = Math.round((nfUsedMemInKB / 1024) * 100) / 100;
|
||||
const sysMemUsageInMB = Math.round((sysMemUsageInKB / 1024) * 100) / 100;
|
||||
|
||||
/**监听表格行事件*/
|
||||
function rowClick(record: any, index: any) {
|
||||
return {
|
||||
onClick: (event: any) => {
|
||||
let pronData = JSON.parse(JSON.stringify(record.serverState));
|
||||
if (!pronData.online) {
|
||||
message.error(t('views.index.neStatus'), 2);
|
||||
return false;
|
||||
} else {
|
||||
const totalMemInKB = pronData.mem?.totalMem;
|
||||
const nfUsedMemInKB = pronData.mem?.nfUsedMem;
|
||||
const sysMemUsageInKB = pronData.mem?.sysMemUsage;
|
||||
// CPU
|
||||
const nfCpu = neState.cpu?.nfCpuUsage;
|
||||
const sysCpu = neState.cpu?.sysCpuUsage;
|
||||
const nfCpuP = Math.round(nfCpu) / 100;
|
||||
const sysCpuP = Math.round(sysCpu) / 100;
|
||||
|
||||
// 将KB转换为MB
|
||||
const totalMemInMB = Math.round((totalMemInKB / 1024) * 100) / 100;
|
||||
const nfUsedMemInMB = Math.round((nfUsedMemInKB / 1024) * 100) / 100;
|
||||
const sysMemUsageInMB =
|
||||
Math.round((sysMemUsageInKB / 1024) * 100) / 100;
|
||||
|
||||
//渲染详细信息
|
||||
pronInfo = {
|
||||
hostName: pronData.hostname,
|
||||
osInfo: pronData.os,
|
||||
ipAddress: pronData.neIP,
|
||||
version: pronData.version,
|
||||
cpuUse:
|
||||
pronData.neName +
|
||||
':' +
|
||||
pronData.cpu?.nfCpuUsage / 100 +
|
||||
'%; ' +
|
||||
'SYS:' +
|
||||
pronData.cpu?.sysCpuUsage / 100 +
|
||||
'%',
|
||||
memoryUse:
|
||||
'Total:' +
|
||||
totalMemInMB +
|
||||
'MB; ' +
|
||||
pronData.name +
|
||||
':' +
|
||||
nfUsedMemInMB +
|
||||
'MB; SYS:' +
|
||||
sysMemUsageInMB +
|
||||
'MB',
|
||||
capability: pronData.capability,
|
||||
serialNum: pronData.sn,
|
||||
expiryDate: pronData.expire,
|
||||
};
|
||||
}
|
||||
open.value = true;
|
||||
serverState.value = Object.assign(
|
||||
{
|
||||
cpuUse: `NE:${nfCpuP}%; SYS:${sysCpuP}%`,
|
||||
memoryUse: `Total: ${totalMemInMB}MB; NE: ${nfUsedMemInMB}MB; SYS: ${sysMemUsageInMB}MB`,
|
||||
},
|
||||
};
|
||||
neState
|
||||
);
|
||||
}
|
||||
let timer: any;
|
||||
|
||||
/**
|
||||
* 国际化翻译转换
|
||||
@@ -312,6 +261,7 @@ function fnLocale() {
|
||||
appStore.setTitle(title);
|
||||
}
|
||||
|
||||
let timer: any;
|
||||
onMounted(() => {
|
||||
getDict('index_status')
|
||||
.then(res => {
|
||||
@@ -322,12 +272,11 @@ onMounted(() => {
|
||||
.finally(() => {
|
||||
fnLocale();
|
||||
fnGetList(true);
|
||||
timer = setInterval(() => fnGetList(false), 10000); // 每隔10秒执行一次
|
||||
timer = setInterval(() => fnGetList(false), 10_000); // 每隔10秒执行一次
|
||||
});
|
||||
});
|
||||
|
||||
// 在组件卸载之前清除定时器
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearInterval(timer);
|
||||
});
|
||||
@@ -335,40 +284,6 @@ onBeforeUnmount(() => {
|
||||
|
||||
<template>
|
||||
<PageContainer :breadcrumb="{}">
|
||||
<div>
|
||||
<a-drawer :open="open" @close="closeDrawer" :width="700">
|
||||
<a-descriptions bordered :column="1" :label-style="{ width: '160px' }">
|
||||
<a-descriptions-item :label="t('views.index.hostName')">{{
|
||||
pronInfo.hostName
|
||||
}}</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('views.index.osInfo')">{{
|
||||
pronInfo.osInfo
|
||||
}}</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('views.index.ipAddress')">{{
|
||||
pronInfo.ipAddress
|
||||
}}</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('views.index.version')">{{
|
||||
pronInfo.version
|
||||
}}</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('views.index.capability')">{{
|
||||
pronInfo.capability
|
||||
}}</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('views.index.cpuUse')">{{
|
||||
pronInfo.cpuUse
|
||||
}}</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('views.index.memoryUse')">{{
|
||||
pronInfo.memoryUse
|
||||
}}</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('views.index.serialNum')">{{
|
||||
pronInfo.serialNum
|
||||
}}</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('views.index.expiryDate')">{{
|
||||
pronInfo.expiryDate
|
||||
}}</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-drawer>
|
||||
</div>
|
||||
|
||||
<a-row :gutter="16">
|
||||
<a-col :lg="14" :md="16" :xs="24">
|
||||
<!-- 表格列表 -->
|
||||
@@ -381,7 +296,12 @@ onBeforeUnmount(() => {
|
||||
:data-source="tableState.data"
|
||||
:pagination="false"
|
||||
:scroll="{ x: true }"
|
||||
:customRow="rowClick"
|
||||
:row-selection="{
|
||||
type: 'radio',
|
||||
columnWidth: '48px',
|
||||
selectedRowKeys: tableState.selectedRowKeys,
|
||||
onChange: fnTableSelectedRowKeys,
|
||||
}"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'status'">
|
||||
@@ -404,7 +324,7 @@ onBeforeUnmount(() => {
|
||||
<div style="width: 100%; min-height: 200px" ref="statusBar"></div>
|
||||
</a-card>
|
||||
<a-card
|
||||
:title="t('views.index.mark')"
|
||||
:title="`${t('views.index.mark')} - ${serverState.neName || ''}`"
|
||||
style="margin-top: 16px"
|
||||
size="small"
|
||||
>
|
||||
@@ -413,25 +333,33 @@ onBeforeUnmount(() => {
|
||||
:column="1"
|
||||
:label-style="{ width: '160px' }"
|
||||
>
|
||||
<a-descriptions-item :label="t('views.index.object')">{{
|
||||
nfInfo.obj
|
||||
}}</a-descriptions-item>
|
||||
<template v-if="nfInfo.obj === 'OMC'">
|
||||
<a-descriptions-item :label="t('views.index.versionNum')">{{
|
||||
nfInfo.version
|
||||
}}</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('views.index.systemStatus')">{{
|
||||
nfInfo.status
|
||||
}}</a-descriptions-item>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a-descriptions-item :label="t('views.index.serialNum')">{{
|
||||
nfInfo.serialNum
|
||||
}}</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('views.index.expiryDate')">{{
|
||||
nfInfo.outTimeDate
|
||||
}}</a-descriptions-item>
|
||||
</template>
|
||||
<a-descriptions-item :label="t('views.index.hostName')">
|
||||
{{ serverState.hostname }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('views.index.osInfo')">
|
||||
{{ serverState.os }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('views.index.ipAddress')">
|
||||
{{ serverState.neIP }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('views.index.version')">
|
||||
{{ serverState.version }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('views.index.capability')">
|
||||
{{ serverState.capability }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('views.index.cpuUse')">
|
||||
{{ serverState.cpuUse }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('views.index.memoryUse')">
|
||||
{{ serverState.memoryUse }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('views.index.serialNum')">
|
||||
{{ serverState.sn }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('views.index.expiryDate')">
|
||||
{{ serverState.expire }}
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-card>
|
||||
</a-col>
|
||||
|
||||
@@ -581,7 +581,7 @@ onBeforeUnmount(() => {
|
||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||
:loading="modalState.confirmLoading"
|
||||
@click.prevent="fnRecordDelete('0')"
|
||||
v-roles:has="[TENANTADMIN_ROLE_KEY]"
|
||||
v-perms:has="['cdr:ne:remove']"
|
||||
>
|
||||
<template #icon><DeleteOutlined /></template>
|
||||
{{ t('common.deleteText') }}
|
||||
@@ -709,7 +709,7 @@ onBeforeUnmount(() => {
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordDelete(record.id)"
|
||||
v-roles:has="[TENANTADMIN_ROLE_KEY]"
|
||||
v-perms:has="['cdr:ne:remove']"
|
||||
>
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
@@ -720,65 +720,59 @@ onBeforeUnmount(() => {
|
||||
</template>
|
||||
</template>
|
||||
<template #expandedRowRender="{ record }">
|
||||
<div style="width: 46%; padding-left: 32px; padding-bottom: 16px">
|
||||
<a-divider orientation="left">
|
||||
{{ t('views.dashboard.ue.ueInfo') }}
|
||||
</a-divider>
|
||||
<div>
|
||||
<span>{{ t('views.ne.common.neName') }}: </span>
|
||||
<span>{{ record.neName }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('views.ne.common.rmUid') }}: </span>
|
||||
<span>{{ record.rmUID }}</span>
|
||||
</div>
|
||||
<a-divider orientation="left">
|
||||
{{ t('views.dashboard.ue.rowInfo') }}
|
||||
</a-divider>
|
||||
<div>
|
||||
<span>{{ t('views.dashboard.ue.time') }}: </span>
|
||||
<span
|
||||
v-if="record.eventType === 'auth-result'"
|
||||
:title="record.eventJSON.authTime"
|
||||
>
|
||||
{{ record.eventJSON.authTime }}
|
||||
</span>
|
||||
<span
|
||||
v-if="record.eventType === 'detach'"
|
||||
:title="record.eventJSON.detachTime"
|
||||
>
|
||||
{{ record.eventJSON.detachTime }}
|
||||
</span>
|
||||
<span
|
||||
v-if="record.eventType === 'cm-state'"
|
||||
:title="record.eventJSON.changeTime"
|
||||
>
|
||||
{{ record.eventJSON.changeTime }}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('views.dashboard.ue.eventType') }}: </span>
|
||||
<DictTag :options="dict.ueEventType" :value="record.eventType" />
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('views.dashboard.ue.result') }}: </span>
|
||||
<span v-if="record.eventType === 'auth-result'">
|
||||
<a-row :gutter="16">
|
||||
<a-col :lg="8" :md="12" :xs="24" :offset="2">
|
||||
<a-divider orientation="left">
|
||||
{{ t('views.dashboard.ue.rowInfo') }}
|
||||
</a-divider>
|
||||
<div>
|
||||
<span>{{ t('views.dashboard.ue.time') }}: </span>
|
||||
<span
|
||||
v-if="record.eventType === 'auth-result'"
|
||||
:title="record.eventJSON.authTime"
|
||||
>
|
||||
{{ record.eventJSON.authTime }}
|
||||
</span>
|
||||
<span
|
||||
v-if="record.eventType === 'detach'"
|
||||
:title="record.eventJSON.detachTime"
|
||||
>
|
||||
{{ record.eventJSON.detachTime }}
|
||||
</span>
|
||||
<span
|
||||
v-if="record.eventType === 'cm-state'"
|
||||
:title="record.eventJSON.changeTime"
|
||||
>
|
||||
{{ record.eventJSON.changeTime }}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('views.dashboard.ue.eventType') }}: </span>
|
||||
<DictTag
|
||||
:options="dict.ueAauthCode"
|
||||
:value="record.eventJSON.authCode"
|
||||
:options="dict.ueEventType"
|
||||
:value="record.eventType"
|
||||
/>
|
||||
</span>
|
||||
<span v-if="record.eventType === 'detach'">
|
||||
{{ t('views.dashboard.ue.resultOk') }}
|
||||
</span>
|
||||
<span v-if="record.eventType === 'cm-state'">
|
||||
<DictTag
|
||||
:options="dict.ueEventCmState"
|
||||
:value="record.eventJSON.status"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('views.dashboard.ue.result') }}: </span>
|
||||
<span v-if="record.eventType === 'auth-result'">
|
||||
<DictTag
|
||||
:options="dict.ueAauthCode"
|
||||
:value="record.eventJSON.authCode"
|
||||
/>
|
||||
</span>
|
||||
<span v-if="record.eventType === 'detach'">
|
||||
{{ t('views.dashboard.ue.resultOk') }}
|
||||
</span>
|
||||
<span v-if="record.eventType === 'cm-state'">
|
||||
<DictTag
|
||||
:options="dict.ueEventCmState"
|
||||
:value="record.eventJSON.status"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
|
||||
@@ -23,7 +23,8 @@ import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||
import saveAs from 'file-saver';
|
||||
import PQueue from 'p-queue';
|
||||
import { listTenant } from '@/api/system/tenant';
|
||||
import useUserStore from '@/store/modules/user';
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
const { copy } = useClipboard({ legacy: true });
|
||||
const { t } = useI18n();
|
||||
const { getDict } = useDictStore();
|
||||
const ws = new WS();
|
||||
@@ -323,6 +324,18 @@ function fnRecordDelete(id: string) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制CDR
|
||||
* @param jsonStr JSON字符串
|
||||
*/
|
||||
function fnRecordCopy(jsonStr: string) {
|
||||
if (!jsonStr) return;
|
||||
const text = JSON.stringify(jsonStr, null, 2);
|
||||
copy(text).then(() => {
|
||||
message.success(t('common.copyOk'), 3);
|
||||
});
|
||||
}
|
||||
|
||||
/**查询列表, pageNum初始页数 */
|
||||
function fnGetList(pageNum?: number) {
|
||||
if (tableState.loading) return;
|
||||
@@ -424,7 +437,9 @@ function fnRealTime() {
|
||||
subGroupID: `1005_${queryParams.neId}`,
|
||||
},
|
||||
onmessage: wsMessage,
|
||||
onerror: wsError,
|
||||
onerror: (ev: any) => {
|
||||
console.error(ev);
|
||||
},
|
||||
};
|
||||
ws.connect(options);
|
||||
} else {
|
||||
@@ -434,12 +449,6 @@ function fnRealTime() {
|
||||
}
|
||||
}
|
||||
|
||||
/**接收数据后回调 */
|
||||
function wsError(ev: any) {
|
||||
// 接收数据后回调
|
||||
console.error(ev);
|
||||
}
|
||||
|
||||
/**接收数据后回调 */
|
||||
function wsMessage(res: Record<string, any>) {
|
||||
const { code, requestId, data } = res;
|
||||
@@ -554,6 +563,7 @@ onBeforeUnmount(() => {
|
||||
v-model:value="queryParams.neId"
|
||||
:options="neOtions"
|
||||
:placeholder="t('common.selectPlease')"
|
||||
@change="fnQueryReset()"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
@@ -671,6 +681,7 @@ onBeforeUnmount(() => {
|
||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||
:loading="modalState.confirmLoading"
|
||||
@click.prevent="fnRecordDelete('0')"
|
||||
v-perms:has="['cdr:ne:remove']"
|
||||
>
|
||||
<template #icon><DeleteOutlined /></template>
|
||||
{{ t('common.deleteText') }}
|
||||
@@ -772,11 +783,23 @@ onBeforeUnmount(() => {
|
||||
</template>
|
||||
<template v-if="column.key === 'id'">
|
||||
<a-space :size="8" align="center">
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.copyText') }}</template>
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordCopy(record.cdrJSON)"
|
||||
>
|
||||
<template #icon>
|
||||
<CopyOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.deleteText') }}</template>
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordDelete(record.id)"
|
||||
v-perms:has="['cdr:ne:remove']"
|
||||
>
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
|
||||
@@ -610,6 +610,7 @@ onBeforeUnmount(() => {
|
||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||
:loading="modalState.confirmLoading"
|
||||
@click.prevent="fnRecordDelete('0')"
|
||||
v-perms:has="['cdr:ne:remove']"
|
||||
>
|
||||
<template #icon><DeleteOutlined /></template>
|
||||
{{ t('common.deleteText') }}
|
||||
@@ -713,6 +714,7 @@ onBeforeUnmount(() => {
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordDelete(record.id)"
|
||||
v-perms:has="['cdr:ne:remove']"
|
||||
>
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
|
||||
@@ -77,8 +77,12 @@ onMounted(() => {
|
||||
<div></div>
|
||||
<div>
|
||||
{{ t('views.dashboard.overview.userActivity.time') }}:
|
||||
<span :title="parseDateToStr(item.data.releaseTime * 1000)">
|
||||
{{ parseDateToStr(item.data.releaseTime * 1000) }}
|
||||
<span :title="item.data.releaseTime">
|
||||
{{
|
||||
typeof item.data.releaseTime === 'number'
|
||||
? parseDateToStr(+item.data.releaseTime * 1000)
|
||||
: item.data.releaseTime
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -198,12 +202,16 @@ onMounted(() => {
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
IMSI: <span :title="item.data.imsi">{{ item.data.imsi }}</span>
|
||||
IMSI: <span :title="item.data?.imsi">{{ item.data?.imsi }}</span>
|
||||
</div>
|
||||
<div>
|
||||
{{ t('views.dashboard.overview.userActivity.time') }}:
|
||||
<span :title="item.data.timestamp">
|
||||
{{ parseDateToStr(+item.data.timestamp * 1000) }}
|
||||
<span :title="item.data?.timestamp">
|
||||
{{
|
||||
typeof item.data?.timestamp === 'number'
|
||||
? parseDateToStr(+item.data?.timestamp * 1000)
|
||||
: item.data?.timestamp
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
.upfFlow .inner .chart {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-top: 1rem;
|
||||
margin-top: 0rem;
|
||||
}
|
||||
|
||||
/* 网络拓扑 */
|
||||
|
||||
@@ -20,17 +20,15 @@ import {
|
||||
graphNodeStateNum,
|
||||
neStateRequestMap,
|
||||
} from './hooks/useTopology';
|
||||
import { upfTotalFlow, upfTFActive } from './hooks/useUPFTotalFlow';
|
||||
import { upfWhoId } from './hooks/useWS';
|
||||
|
||||
import { upfTotalFlow, upfTFActive } from './hooks/useUPFTotalFlow';
|
||||
import { useFullscreen } from '@vueuse/core';
|
||||
import useWS from './hooks/useWS';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { message } from 'ant-design-vue/lib/components';
|
||||
import useNeInfoStore from '@/store/modules/neinfo';
|
||||
|
||||
import { useRouter } from 'vue-router';
|
||||
import useNeInfoStore from '@/store/modules/neinfo';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { upfWhoId } from './hooks/useWS';
|
||||
const router = useRouter();
|
||||
const appStore = useAppStore();
|
||||
const { t } = useI18n();
|
||||
@@ -74,6 +72,9 @@ let skimState: SkimStateType = reactive({
|
||||
enbUeNum: 0,
|
||||
});
|
||||
|
||||
/**网元参数 */
|
||||
let neCascaderOptions = ref<Record<string, any>[]>([]);
|
||||
|
||||
/**总览节点 */
|
||||
const viewportDom = ref<HTMLElement | null>(null);
|
||||
const { isFullscreen, toggle } = useFullscreen(viewportDom);
|
||||
@@ -108,62 +109,97 @@ function fnGetNeState() {
|
||||
|
||||
/**获取概览信息 */
|
||||
async function fnGetSkim() {
|
||||
const resArr = await Promise.allSettled([
|
||||
listUDMSub({
|
||||
neid: '001',
|
||||
pageNum: 1,
|
||||
pageSize: 1,
|
||||
}),
|
||||
listUENumBySMF('001'),
|
||||
listUENumByIMS('001'),
|
||||
listBase5G({
|
||||
neType: 'AMF',
|
||||
neId: '001',
|
||||
}),
|
||||
listBase5G({
|
||||
neType: 'MME',
|
||||
neId: '001',
|
||||
}),
|
||||
const neHandlers = new Map([
|
||||
[
|
||||
'UDM',
|
||||
{
|
||||
request: (neId: string) =>
|
||||
listUDMSub({ neId: neId, pageNum: 1, pageSize: 1 }),
|
||||
process: (res: any) =>
|
||||
res.code === RESULT_CODE_SUCCESS &&
|
||||
(skimState.udmSubNum += res.total),
|
||||
},
|
||||
],
|
||||
[
|
||||
'SMF',
|
||||
{
|
||||
request: (neId: string) => listUENumBySMF(neId),
|
||||
process: (res: any) =>
|
||||
res.code === RESULT_CODE_SUCCESS && (skimState.smfUeNum += res.data),
|
||||
},
|
||||
],
|
||||
[
|
||||
'IMS',
|
||||
{
|
||||
request: (neId: string) => listUENumByIMS(neId),
|
||||
process: (res: any) =>
|
||||
res.code === RESULT_CODE_SUCCESS && (skimState.imsUeNum += res.data),
|
||||
},
|
||||
],
|
||||
[
|
||||
'AMF',
|
||||
{
|
||||
request: (neId: string) => listBase5G({ neType: 'AMF', neId }),
|
||||
process: (res: any) => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
skimState.gnbNum += res.total;
|
||||
skimState.gnbUeNum += res.rows.reduce(
|
||||
(sum: number, item: any) => sum + item.ueNum,
|
||||
0
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
'MME',
|
||||
{
|
||||
request: (neId: string) => listBase5G({ neType: 'MME', neId }),
|
||||
process: (res: any) => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
skimState.enbNum += res.total;
|
||||
skimState.enbUeNum += res.rows.reduce(
|
||||
(sum: number, item: any) => sum + item.ueNum,
|
||||
0
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
if (resArr[0].status === 'fulfilled') {
|
||||
const res0 = resArr[0].value;
|
||||
if (res0.code === RESULT_CODE_SUCCESS) {
|
||||
skimState.udmSubNum = res0.total;
|
||||
const requests = neCascaderOptions.value.flatMap(
|
||||
(ne: any) =>
|
||||
ne.children
|
||||
?.map((child: any) => {
|
||||
const handler = neHandlers.get(child.neType);
|
||||
return handler
|
||||
? {
|
||||
promise: handler.request(child.neId),
|
||||
process: handler.process,
|
||||
}
|
||||
: null;
|
||||
})
|
||||
.filter(Boolean) || []
|
||||
);
|
||||
|
||||
const results = await Promise.allSettled(requests.map(r => r.promise));
|
||||
|
||||
// 重置
|
||||
Object.assign(skimState, {
|
||||
udmSubNum: 0,
|
||||
smfUeNum: 0,
|
||||
imsUeNum: 0,
|
||||
gnbNum: 0,
|
||||
gnbUeNum: 0,
|
||||
enbNum: 0,
|
||||
enbUeNum: 0,
|
||||
});
|
||||
results.forEach((result, index) => {
|
||||
if (result.status === 'fulfilled') {
|
||||
requests[index].process(result.value);
|
||||
}
|
||||
}
|
||||
if (resArr[1].status === 'fulfilled') {
|
||||
const res1 = resArr[1].value;
|
||||
if (res1.code === RESULT_CODE_SUCCESS) {
|
||||
skimState.smfUeNum = res1.data;
|
||||
}
|
||||
}
|
||||
if (resArr[2].status === 'fulfilled') {
|
||||
const res2 = resArr[2].value;
|
||||
if (res2.code === RESULT_CODE_SUCCESS) {
|
||||
skimState.imsUeNum = res2.data;
|
||||
}
|
||||
}
|
||||
if (resArr[3].status === 'fulfilled') {
|
||||
const res3 = resArr[3].value;
|
||||
if (res3.code === RESULT_CODE_SUCCESS) {
|
||||
skimState.gnbNum = res3.total;
|
||||
skimState.gnbUeNum = 0;
|
||||
res3.rows.map((item: any) => {
|
||||
skimState.gnbUeNum += item.ueNum;
|
||||
});
|
||||
}
|
||||
}
|
||||
if (resArr[4].status === 'fulfilled') {
|
||||
const res4 = resArr[4].value;
|
||||
if (res4.code === RESULT_CODE_SUCCESS) {
|
||||
skimState.enbNum = res4.total;
|
||||
skimState.enbUeNum = 0;
|
||||
res4.rows.map((item: any) => {
|
||||
skimState.enbUeNum += item.ueNum;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**初始数据函数 */
|
||||
@@ -176,7 +212,7 @@ function loadData() {
|
||||
|
||||
clearInterval(interval10s.value);
|
||||
interval10s.value = setInterval(() => {
|
||||
if (!interval10s.value) return
|
||||
if (!interval10s.value) return;
|
||||
if (upfTFActive.value === '0') {
|
||||
upfTFSend('7');
|
||||
upfTFActive.value = '7';
|
||||
@@ -191,7 +227,7 @@ function loadData() {
|
||||
|
||||
clearInterval(interval5s.value);
|
||||
interval5s.value = setInterval(() => {
|
||||
if (!interval5s.value) return
|
||||
if (!interval5s.value) return;
|
||||
fnGetSkim(); // 获取概览信息
|
||||
fnGetNeState(); // 获取网元状态
|
||||
}, 5_000);
|
||||
|
||||
817
src/views/dashboard/sgwcCDR/index.vue
Normal file
817
src/views/dashboard/sgwcCDR/index.vue
Normal file
@@ -0,0 +1,817 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, onMounted, toRaw, onBeforeUnmount, ref } from 'vue';
|
||||
import { PageContainer } from 'antdv-pro-layout';
|
||||
import { Modal, message } from 'ant-design-vue/es';
|
||||
import { SizeType } from 'ant-design-vue/es/config-provider';
|
||||
import { MenuInfo } from 'ant-design-vue/es/menu/src/interface';
|
||||
import { ColumnsType } from 'ant-design-vue/es/table';
|
||||
import useNeInfoStore from '@/store/modules/neinfo';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
import {
|
||||
RESULT_CODE_ERROR,
|
||||
RESULT_CODE_SUCCESS,
|
||||
} from '@/constants/result-constants';
|
||||
import {
|
||||
delSGWCDataCDR,
|
||||
exportSGWCDataCDR,
|
||||
listSGWCDataCDR,
|
||||
} from '@/api/neData/sgwc';
|
||||
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||
import PQueue from 'p-queue';
|
||||
import saveAs from 'file-saver';
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
const { copy } = useClipboard({ legacy: true });
|
||||
const { t } = useI18n();
|
||||
const ws = new WS();
|
||||
const queue = new PQueue({ concurrency: 1, autoStart: true });
|
||||
|
||||
/**网元可选 */
|
||||
let neOtions = ref<Record<string, any>[]>([]);
|
||||
|
||||
/**开始结束时间 */
|
||||
let queryRangePicker = ref<[string, string]>(['', '']);
|
||||
|
||||
/**查询参数 */
|
||||
let queryParams = reactive({
|
||||
/**网元类型 */
|
||||
neType: 'SGWC',
|
||||
neId: '001',
|
||||
imsi: '',
|
||||
msisdn: '',
|
||||
sortField: 'timestamp',
|
||||
sortOrder: 'desc',
|
||||
/**开始时间 */
|
||||
startTime: '',
|
||||
/**结束时间 */
|
||||
endTime: '',
|
||||
/**当前页数 */
|
||||
pageNum: 1,
|
||||
/**每页条数 */
|
||||
pageSize: 20,
|
||||
});
|
||||
|
||||
/**查询参数重置 */
|
||||
function fnQueryReset() {
|
||||
queryParams = Object.assign(queryParams, {
|
||||
imsi: '',
|
||||
msisdn: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
});
|
||||
queryRangePicker.value = ['', ''];
|
||||
tablePagination.current = 1;
|
||||
tablePagination.pageSize = 20;
|
||||
fnGetList();
|
||||
}
|
||||
|
||||
/**表格状态类型 */
|
||||
type TabeStateType = {
|
||||
/**加载等待 */
|
||||
loading: boolean;
|
||||
/**紧凑型 */
|
||||
size: SizeType;
|
||||
/**搜索栏 */
|
||||
seached: boolean;
|
||||
/**记录数据 */
|
||||
data: object[];
|
||||
/**勾选记录 */
|
||||
selectedRowKeys: (string | number)[];
|
||||
};
|
||||
|
||||
/**表格状态 */
|
||||
let tableState: TabeStateType = reactive({
|
||||
loading: false,
|
||||
size: 'middle',
|
||||
seached: true,
|
||||
data: [],
|
||||
selectedRowKeys: [],
|
||||
});
|
||||
|
||||
/**表格字段列 */
|
||||
let tableColumns: ColumnsType = [
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'id',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.chargingID'), // 计费ID
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
customRender(opt) {
|
||||
const cdrJSON = opt.value;
|
||||
return cdrJSON.chargingID;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.sgwcServedIMSI'), // IMSI
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'left',
|
||||
width: 150,
|
||||
customRender(opt) {
|
||||
const cdrJSON = opt.value;
|
||||
return cdrJSON.servedIMSI;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.sgwcServedMSISDN'), // MSISDN
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'left',
|
||||
width: 150,
|
||||
customRender(opt) {
|
||||
const cdrJSON = opt.value;
|
||||
return cdrJSON.servedMSISDN;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.sgwcVolumeGPRSUplink'), // GPRS 上行链路
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'left',
|
||||
width: 150,
|
||||
customRender(opt) {
|
||||
const cdrJSON = opt.value;
|
||||
const listOfTrafficVolumes = cdrJSON.listOfTrafficVolumes;
|
||||
if (
|
||||
!Array.isArray(listOfTrafficVolumes) ||
|
||||
listOfTrafficVolumes.length < 1
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
let dataVolumeGPRSUplink = 0;
|
||||
for (const used of listOfTrafficVolumes) {
|
||||
const v = +used.dataVolumeGPRSUplink;
|
||||
dataVolumeGPRSUplink += isNaN(v) ? 0 : v;
|
||||
}
|
||||
return dataVolumeGPRSUplink;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.sgwcVolumeGPRSDownlink'), // GPRS 下行链路
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'left',
|
||||
width: 180,
|
||||
customRender(opt) {
|
||||
const cdrJSON = opt.value;
|
||||
const listOfTrafficVolumes = cdrJSON.listOfTrafficVolumes;
|
||||
if (
|
||||
!Array.isArray(listOfTrafficVolumes) ||
|
||||
listOfTrafficVolumes.length < 1
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
let dataVolumeGPRSDownlink = 0;
|
||||
for (const used of listOfTrafficVolumes) {
|
||||
const v = +used.dataVolumeGPRSDownlink;
|
||||
dataVolumeGPRSDownlink += isNaN(v) ? 0 : v;
|
||||
}
|
||||
return dataVolumeGPRSDownlink;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.durationTime'), // 持续时间
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
customRender(opt) {
|
||||
const cdrJSON = opt.value;
|
||||
return cdrJSON.duration;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.invocationTime'), // 操作时间
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'left',
|
||||
width: 200,
|
||||
customRender(opt) {
|
||||
const cdrJSON = opt.value;
|
||||
return cdrJSON.recordOpeningTime;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('common.operate'),
|
||||
key: 'id',
|
||||
align: 'left',
|
||||
},
|
||||
];
|
||||
|
||||
/**表格分页器参数 */
|
||||
let tablePagination = reactive({
|
||||
/**当前页数 */
|
||||
current: 1,
|
||||
/**每页条数 */
|
||||
pageSize: 20,
|
||||
/**默认的每页条数 */
|
||||
defaultPageSize: 20,
|
||||
/**指定每页可以显示多少条 */
|
||||
pageSizeOptions: ['10', '20', '50', '100'],
|
||||
/**只有一页时是否隐藏分页器 */
|
||||
hideOnSinglePage: false,
|
||||
/**是否可以快速跳转至某页 */
|
||||
showQuickJumper: true,
|
||||
/**是否可以改变 pageSize */
|
||||
showSizeChanger: true,
|
||||
/**数据总数 */
|
||||
total: 0,
|
||||
showTotal: (total: number) => t('common.tablePaginationTotal', { total }),
|
||||
onChange: (page: number, pageSize: number) => {
|
||||
tablePagination.current = page;
|
||||
tablePagination.pageSize = pageSize;
|
||||
queryParams.pageNum = page;
|
||||
queryParams.pageSize = pageSize;
|
||||
fnGetList();
|
||||
},
|
||||
});
|
||||
|
||||
/**表格紧凑型变更操作 */
|
||||
function fnTableSize({ key }: MenuInfo) {
|
||||
tableState.size = key as SizeType;
|
||||
}
|
||||
|
||||
/**表格多选 */
|
||||
function fnTableSelectedRowKeys(keys: (string | number)[]) {
|
||||
tableState.selectedRowKeys = keys;
|
||||
}
|
||||
|
||||
/**对话框对象信息状态类型 */
|
||||
type ModalStateType = {
|
||||
/**确定按钮 loading */
|
||||
confirmLoading: boolean;
|
||||
/**最大ID值 */
|
||||
maxId: number;
|
||||
};
|
||||
|
||||
/**对话框对象信息状态 */
|
||||
let modalState: ModalStateType = reactive({
|
||||
confirmLoading: false,
|
||||
maxId: 0,
|
||||
});
|
||||
|
||||
/**
|
||||
* 记录删除
|
||||
* @param id 编号
|
||||
*/
|
||||
function fnRecordDelete(id: string) {
|
||||
if (!id || modalState.confirmLoading) return;
|
||||
let msg = id;
|
||||
if (id === '0') {
|
||||
msg = `${id}... ${tableState.selectedRowKeys.length}`;
|
||||
id = tableState.selectedRowKeys.join(',');
|
||||
}
|
||||
|
||||
Modal.confirm({
|
||||
title: t('common.tipTitle'),
|
||||
content: t('views.dashboard.cdr.delTip', { msg }),
|
||||
onOk() {
|
||||
modalState.confirmLoading = true;
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
delSGWCDataCDR(id)
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
message.success({
|
||||
content: t('common.operateOk'),
|
||||
duration: 3,
|
||||
});
|
||||
fnGetList(1);
|
||||
} else {
|
||||
message.error({
|
||||
content: `${res.msg}`,
|
||||
duration: 3,
|
||||
});
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
hide();
|
||||
modalState.confirmLoading = false;
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制CDR
|
||||
* @param jsonStr JSON字符串
|
||||
*/
|
||||
function fnRecordCopy(jsonStr: string) {
|
||||
if (!jsonStr) return;
|
||||
const text = JSON.stringify(jsonStr, null, 2);
|
||||
copy(text).then(() => {
|
||||
message.success(t('common.copyOk'), 3);
|
||||
});
|
||||
}
|
||||
|
||||
/**查询列表, pageNum初始页数 */
|
||||
function fnGetList(pageNum?: number) {
|
||||
if (tableState.loading) return;
|
||||
tableState.loading = true;
|
||||
if (pageNum) {
|
||||
queryParams.pageNum = pageNum;
|
||||
}
|
||||
if (!queryRangePicker.value) {
|
||||
queryRangePicker.value = ['', ''];
|
||||
}
|
||||
queryParams.startTime = queryRangePicker.value[0];
|
||||
queryParams.endTime = queryRangePicker.value[1];
|
||||
listSGWCDataCDR(toRaw(queryParams)).then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
|
||||
// 取消勾选
|
||||
if (tableState.selectedRowKeys.length > 0) {
|
||||
tableState.selectedRowKeys = [];
|
||||
}
|
||||
tablePagination.total = res.total;
|
||||
// 遍历处理cdr字符串数据
|
||||
tableState.data = res.rows.map(item => {
|
||||
let cdrJSON = item.cdrJSON;
|
||||
if (!cdrJSON) {
|
||||
Reflect.set(item, 'cdrJSON', {});
|
||||
}
|
||||
|
||||
try {
|
||||
cdrJSON = JSON.parse(cdrJSON);
|
||||
Reflect.set(item, 'cdrJSON', cdrJSON);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Reflect.set(item, 'cdrJSON', {});
|
||||
}
|
||||
|
||||
return item;
|
||||
});
|
||||
|
||||
// 取最大值ID用作实时累加
|
||||
if (res.total > 0) {
|
||||
modalState.maxId = Number(res.rows[0].id);
|
||||
}
|
||||
}
|
||||
tableState.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
/**列表导出 */
|
||||
function fnExportList() {
|
||||
if (modalState.confirmLoading) return;
|
||||
Modal.confirm({
|
||||
title: t('common.tipTitle'),
|
||||
content: t('views.dashboard.cdr.exportTip'),
|
||||
onOk() {
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
const querys = toRaw(queryParams);
|
||||
querys.pageSize = 10000;
|
||||
exportSGWCDataCDR(querys)
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
message.success({
|
||||
content: t('common.operateOk'),
|
||||
duration: 3,
|
||||
});
|
||||
saveAs(res.data, `sgwc_cdr_event_export_${Date.now()}.xlsx`);
|
||||
} else {
|
||||
message.error({
|
||||
content: `${res.msg}`,
|
||||
duration: 3,
|
||||
});
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
hide();
|
||||
modalState.confirmLoading = false;
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**实时数据开关 */
|
||||
const realTimeData = ref<boolean>(false);
|
||||
|
||||
/**
|
||||
* 实时数据
|
||||
*/
|
||||
function fnRealTime() {
|
||||
realTimeData.value = !realTimeData.value;
|
||||
if (realTimeData.value) {
|
||||
tableState.seached = false;
|
||||
// 建立链接
|
||||
const options: OptionsType = {
|
||||
url: '/ws',
|
||||
params: {
|
||||
/**订阅通道组
|
||||
*
|
||||
* CDR会话事件-SGWC (GroupID:1008)
|
||||
*/
|
||||
subGroupID: `1008_${queryParams.neId}`,
|
||||
},
|
||||
onmessage: wsMessage,
|
||||
onerror: (ev: any) => {
|
||||
console.error(ev);
|
||||
},
|
||||
};
|
||||
ws.connect(options);
|
||||
} else {
|
||||
ws.close();
|
||||
tableState.seached = true;
|
||||
fnGetList(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**接收数据后回调 */
|
||||
function wsMessage(res: Record<string, any>) {
|
||||
const { code, requestId, data } = res;
|
||||
if (code === RESULT_CODE_ERROR) {
|
||||
console.warn(res.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
// 订阅组信息
|
||||
if (!data?.groupId) {
|
||||
return;
|
||||
}
|
||||
// cdrEvent CDR会话事件
|
||||
if (data.groupId === `1008_${queryParams.neId}`) {
|
||||
const cdrEvent = data.data;
|
||||
queue.add(async () => {
|
||||
modalState.maxId += 1;
|
||||
tableState.data.unshift({
|
||||
id: modalState.maxId,
|
||||
neType: cdrEvent.neType,
|
||||
neName: cdrEvent.neName,
|
||||
rmUID: cdrEvent.rmUID,
|
||||
timestamp: cdrEvent.timestamp,
|
||||
cdrJSON: cdrEvent.CDR,
|
||||
});
|
||||
tablePagination.total += 1;
|
||||
if (tableState.data.length > 100) {
|
||||
tableState.data.pop();
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 800));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 获取网元网元列表
|
||||
useNeInfoStore()
|
||||
.fnNelist()
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||
if (res.data.length > 0) {
|
||||
let arr: Record<string, any>[] = [];
|
||||
res.data.forEach(i => {
|
||||
if (i.neType === 'SGWC') {
|
||||
arr.push({ value: i.neId, label: i.neName });
|
||||
}
|
||||
});
|
||||
neOtions.value = arr;
|
||||
if (arr.length > 0) {
|
||||
queryParams.neId = arr[0].value;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
message.warning({
|
||||
content: t('common.noData'),
|
||||
duration: 2,
|
||||
});
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
// 获取列表数据
|
||||
fnGetList();
|
||||
});
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (ws.state() !== -1) {
|
||||
ws.close();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PageContainer>
|
||||
<a-card
|
||||
v-show="tableState.seached"
|
||||
:bordered="false"
|
||||
:body-style="{ marginBottom: '24px', paddingBottom: 0 }"
|
||||
>
|
||||
<!-- 表格搜索栏 -->
|
||||
<a-form :model="queryParams" name="queryParams" layout="horizontal">
|
||||
<a-row :gutter="16">
|
||||
<a-col :lg="6" :md="12" :xs="24">
|
||||
<a-form-item label="SGWC" name="neId ">
|
||||
<a-select
|
||||
v-model:value="queryParams.neId"
|
||||
:options="neOtions"
|
||||
:placeholder="t('common.selectPlease')"
|
||||
@change="fnQueryReset()"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="6" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.dashboard.cdr.sgwcServedIMSI')"
|
||||
name="imsi"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="queryParams.imsi"
|
||||
allow-clear
|
||||
:placeholder="t('common.inputPlease')"
|
||||
:maxlength="40"
|
||||
></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="6" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.dashboard.cdr.sgwcServedMSISDN')"
|
||||
name="msisdn"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="queryParams.msisdn"
|
||||
allow-clear
|
||||
:placeholder="t('common.inputPlease')"
|
||||
:maxlength="40"
|
||||
></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="4" :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-col :lg="8" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.dashboard.cdr.time')"
|
||||
name="queryRangePicker"
|
||||
>
|
||||
<a-range-picker
|
||||
v-model:value="queryRangePicker"
|
||||
allow-clear
|
||||
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-form>
|
||||
</a-card>
|
||||
|
||||
<a-card :bordered="false" :body-style="{ padding: '0px' }">
|
||||
<!-- 插槽-卡片左侧侧 -->
|
||||
<template #title>
|
||||
<a-space :size="8" align="center">
|
||||
<a-popconfirm
|
||||
placement="bottomLeft"
|
||||
:title="
|
||||
!realTimeData
|
||||
? t('views.dashboard.cdr.realTimeDataStart')
|
||||
: t('views.dashboard.cdr.realTimeDataStop')
|
||||
"
|
||||
ok-text="Yes"
|
||||
cancel-text="No"
|
||||
@confirm="fnRealTime()"
|
||||
>
|
||||
<a-button type="primary" :danger="realTimeData">
|
||||
<template #icon><FundOutlined /> </template>
|
||||
{{
|
||||
!realTimeData
|
||||
? t('views.dashboard.cdr.realTimeDataStart')
|
||||
: t('views.dashboard.cdr.realTimeDataStop')
|
||||
}}
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
|
||||
<a-button
|
||||
type="default"
|
||||
danger
|
||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||
:loading="modalState.confirmLoading"
|
||||
@click.prevent="fnRecordDelete('0')"
|
||||
v-perms:has="['cdr:ne:remove']"
|
||||
>
|
||||
<template #icon><DeleteOutlined /></template>
|
||||
{{ t('common.deleteText') }}
|
||||
</a-button>
|
||||
|
||||
<a-button type="dashed" @click.prevent="fnExportList()">
|
||||
<template #icon><ExportOutlined /></template>
|
||||
{{ t('common.export') }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
|
||||
<!-- 插槽-卡片右侧 -->
|
||||
<template #extra>
|
||||
<a-space :size="8" align="center">
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.searchBarText') }}</template>
|
||||
<a-switch
|
||||
v-model:checked="tableState.seached"
|
||||
:checked-children="t('common.switch.show')"
|
||||
:un-checked-children="t('common.switch.hide')"
|
||||
size="small"
|
||||
:disabled="realTimeData"
|
||||
/>
|
||||
</a-tooltip>
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.reloadText') }}</template>
|
||||
<a-button type="text" @click.prevent="fnGetList()">
|
||||
<template #icon><ReloadOutlined /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.sizeText') }}</template>
|
||||
<a-dropdown trigger="click" placement="bottomRight">
|
||||
<a-button type="text">
|
||||
<template #icon><ColumnHeightOutlined /></template>
|
||||
</a-button>
|
||||
<template #overlay>
|
||||
<a-menu
|
||||
:selected-keys="[tableState.size as string]"
|
||||
@click="fnTableSize"
|
||||
>
|
||||
<a-menu-item key="default">
|
||||
{{ t('common.size.default') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="middle">
|
||||
{{ t('common.size.middle') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="small">
|
||||
{{ t('common.size.small') }}
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</template>
|
||||
|
||||
<!-- 表格列表 -->
|
||||
<a-table
|
||||
class="table"
|
||||
row-key="id"
|
||||
:columns="tableColumns"
|
||||
:loading="tableState.loading"
|
||||
:data-source="tableState.data"
|
||||
:size="tableState.size"
|
||||
:pagination="tablePagination"
|
||||
:scroll="{ x: tableColumns.length * 150, y: 'calc(100vh - 480px)' }"
|
||||
:row-selection="{
|
||||
type: 'checkbox',
|
||||
columnWidth: '48px',
|
||||
selectedRowKeys: tableState.selectedRowKeys,
|
||||
onChange: fnTableSelectedRowKeys,
|
||||
}"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'id'">
|
||||
<a-space :size="8" align="center">
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.copyText') }}</template>
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordCopy(record.cdrJSON)"
|
||||
>
|
||||
<template #icon>
|
||||
<CopyOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.deleteText') }}</template>
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordDelete(record.id)"
|
||||
v-perms:has="['cdr:ne:remove']"
|
||||
>
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</template>
|
||||
</template>
|
||||
<template #expandedRowRender="{ record }">
|
||||
<a-row :gutter="16">
|
||||
<a-col :lg="8" :md="12" :xs="24" :offset="2">
|
||||
<a-divider orientation="left">
|
||||
{{ t('views.dashboard.cdr.cdrInfo') }}
|
||||
</a-divider>
|
||||
<div>
|
||||
<span>{{ t('views.ne.common.neName') }}: </span>
|
||||
<span>{{ record.neName }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('views.ne.common.rmUid') }}: </span>
|
||||
<span>{{ record.rmUID }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('views.dashboard.cdr.time') }}: </span>
|
||||
<span>{{ record.cdrJSON.recordOpeningTime }}</span>
|
||||
</div>
|
||||
<a-divider orientation="left">
|
||||
{{ t('views.dashboard.cdr.rowInfo') }}
|
||||
</a-divider>
|
||||
<div>
|
||||
<span>Record Type: </span>
|
||||
<span>{{ record.cdrJSON.recordType }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Record Opening Time: </span>
|
||||
<span>{{ record.cdrJSON.recordOpeningTime }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Charging ID: </span>
|
||||
<span>{{ record.cdrJSON.chargingID }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Duration: </span>
|
||||
<span>{{ record.cdrJSON.duration }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Record Access Point Name NI: </span>
|
||||
<span>{{ record.cdrJSON.accessPointNameNI }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Record Cause For Rec Closing: </span>
|
||||
<span>{{ record.cdrJSON.causeForRecClosing }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Record Sequence Number: </span>
|
||||
<span>{{ record.cdrJSON.recordSequenceNumber }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Local Record Sequence Number: </span>
|
||||
<span>{{ record.cdrJSON.localRecordSequenceNumber }}</span>
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col :lg="8" :md="12" :xs="24">
|
||||
<a-divider orientation="left"> Server Information </a-divider>
|
||||
<div>
|
||||
<span>IMSI: </span>
|
||||
<span> {{ record.cdrJSON.servedIMSI }} </span>
|
||||
</div>
|
||||
<div>
|
||||
<span>MSISDN: </span>
|
||||
<span> {{ record.cdrJSON.servedMSISDN }} </span>
|
||||
</div>
|
||||
<div>
|
||||
<span>PGW Address Used: </span>
|
||||
<span> {{ record.cdrJSON.pGWAddressUsed }} </span>
|
||||
</div>
|
||||
<div>
|
||||
<span>SGW Address: </span>
|
||||
<span> {{ record.cdrJSON.sGWAddress }} </span>
|
||||
</div>
|
||||
<div>
|
||||
<span>RAT Type: </span>
|
||||
<span> {{ record.cdrJSON.rATType }} </span>
|
||||
</div>
|
||||
<a-divider orientation="left"> PDPPD Information </a-divider>
|
||||
<div>
|
||||
<span>PDPPDN Type: </span>
|
||||
<span> {{ record.cdrJSON.pdpPDNType }} </span>
|
||||
</div>
|
||||
<div>
|
||||
<span>PDPPDN Address: </span>
|
||||
<span> {{ record.cdrJSON.servedPDPPDNAddress }} </span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Node Address: </span>
|
||||
<span>
|
||||
{{ record.cdrJSON.servingNodeAddress?.join(', ') }}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Node Type: </span>
|
||||
<span>
|
||||
<template v-for="item in record.cdrJSON.servingNodeType">
|
||||
{{ item.servingNodeType }}
|
||||
</template>
|
||||
</span>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
</PageContainer>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.table :deep(.ant-pagination) {
|
||||
padding: 0 24px;
|
||||
}
|
||||
</style>
|
||||
@@ -20,7 +20,8 @@ import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||
import PQueue from 'p-queue';
|
||||
import saveAs from 'file-saver';
|
||||
import { listTenant } from '@/api/system/tenant';
|
||||
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
const { copy } = useClipboard({ legacy: true });
|
||||
const { t } = useI18n();
|
||||
const ws = new WS();
|
||||
const queue = new PQueue({ concurrency: 1, autoStart: true });
|
||||
@@ -101,7 +102,7 @@ let tableColumns: ColumnsType = [
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.smfChargingID'), // 计费ID
|
||||
title: t('views.dashboard.cdr.chargingID'), // 计费ID
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
@@ -144,11 +145,15 @@ let tableColumns: ColumnsType = [
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
const usedUnitContainer = listOfMultipleUnitUsage[0].usedUnitContainer;
|
||||
if (!Array.isArray(usedUnitContainer) || usedUnitContainer.length < 1) {
|
||||
return 0;
|
||||
let dataVolumeUplink = 0;
|
||||
for (const v of listOfMultipleUnitUsage) {
|
||||
if (Array.isArray(v.usedUnitContainer)) {
|
||||
for (const used of v.usedUnitContainer) {
|
||||
dataVolumeUplink += +used.dataVolumeUplink;
|
||||
}
|
||||
}
|
||||
}
|
||||
return usedUnitContainer[0].dataVolumeUplink;
|
||||
return dataVolumeUplink;
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -165,11 +170,15 @@ let tableColumns: ColumnsType = [
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
const usedUnitContainer = listOfMultipleUnitUsage[0].usedUnitContainer;
|
||||
if (!Array.isArray(usedUnitContainer) || usedUnitContainer.length < 1) {
|
||||
return 0;
|
||||
let dataVolumeDownlink = 0;
|
||||
for (const v of listOfMultipleUnitUsage) {
|
||||
if (Array.isArray(v.usedUnitContainer)) {
|
||||
for (const used of v.usedUnitContainer) {
|
||||
dataVolumeDownlink += +used.dataVolumeDownlink;
|
||||
}
|
||||
}
|
||||
}
|
||||
return usedUnitContainer[0].dataVolumeDownlink;
|
||||
return dataVolumeDownlink;
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -186,15 +195,19 @@ let tableColumns: ColumnsType = [
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
const usedUnitContainer = listOfMultipleUnitUsage[0].usedUnitContainer;
|
||||
if (!Array.isArray(usedUnitContainer) || usedUnitContainer.length < 1) {
|
||||
return 0;
|
||||
let dataTotalVolume = 0;
|
||||
for (const v of listOfMultipleUnitUsage) {
|
||||
if (Array.isArray(v.usedUnitContainer)) {
|
||||
for (const used of v.usedUnitContainer) {
|
||||
dataTotalVolume += +used.dataTotalVolume;
|
||||
}
|
||||
}
|
||||
}
|
||||
return usedUnitContainer[0].dataTotalVolume;
|
||||
return dataTotalVolume;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.smfDuration'), // 持续时间
|
||||
title: t('views.dashboard.cdr.durationTime'), // 持续时间
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
@@ -204,7 +217,7 @@ let tableColumns: ColumnsType = [
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.smfInvocationTime'), // 调用时间
|
||||
title: t('views.dashboard.cdr.invocationTime'), // 调用时间
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'left',
|
||||
width: 200,
|
||||
@@ -320,6 +333,18 @@ function fnRecordDelete(id: string) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制CDR
|
||||
* @param jsonStr JSON字符串
|
||||
*/
|
||||
function fnRecordCopy(jsonStr: string) {
|
||||
if (!jsonStr) return;
|
||||
const text = JSON.stringify(jsonStr, null, 2);
|
||||
copy(text).then(() => {
|
||||
message.success(t('common.copyOk'), 3);
|
||||
});
|
||||
}
|
||||
|
||||
/**查询列表, pageNum初始页数 */
|
||||
function fnGetList(pageNum?: number) {
|
||||
if (tableState.loading) return;
|
||||
@@ -420,7 +445,9 @@ function fnRealTime() {
|
||||
subGroupID: `1006_${queryParams.neId}`,
|
||||
},
|
||||
onmessage: wsMessage,
|
||||
onerror: wsError,
|
||||
onerror: (ev: any) => {
|
||||
console.error(ev);
|
||||
},
|
||||
};
|
||||
ws.connect(options);
|
||||
} else {
|
||||
@@ -430,12 +457,6 @@ function fnRealTime() {
|
||||
}
|
||||
}
|
||||
|
||||
/**接收数据后回调 */
|
||||
function wsError(ev: any) {
|
||||
// 接收数据后回调
|
||||
console.error(ev);
|
||||
}
|
||||
|
||||
/**接收数据后回调 */
|
||||
function wsMessage(res: Record<string, any>) {
|
||||
const { code, requestId, data } = res;
|
||||
@@ -538,6 +559,7 @@ onBeforeUnmount(() => {
|
||||
v-model:value="queryParams.neId"
|
||||
:options="neOtions"
|
||||
:placeholder="t('common.selectPlease')"
|
||||
@change="fnQueryReset()"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
@@ -630,6 +652,7 @@ onBeforeUnmount(() => {
|
||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||
:loading="modalState.confirmLoading"
|
||||
@click.prevent="fnRecordDelete('0')"
|
||||
v-perms:has="['cdr:ne:remove']"
|
||||
>
|
||||
<template #icon><DeleteOutlined /></template>
|
||||
{{ t('common.deleteText') }}
|
||||
@@ -708,11 +731,23 @@ onBeforeUnmount(() => {
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'id'">
|
||||
<a-space :size="8" align="center">
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.copyText') }}</template>
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordCopy(record.cdrJSON)"
|
||||
>
|
||||
<template #icon>
|
||||
<CopyOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.deleteText') }}</template>
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordDelete(record.id)"
|
||||
v-perms:has="['cdr:ne:remove']"
|
||||
>
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
@@ -781,24 +816,33 @@ onBeforeUnmount(() => {
|
||||
<a-divider orientation="left">
|
||||
List Of Multiple Unit Usage
|
||||
</a-divider>
|
||||
|
||||
<div v-for="u in record.cdrJSON.listOfMultipleUnitUsage">
|
||||
<!-- <div>RatingGroup: {{ u.ratingGroup }}</div> -->
|
||||
<div v-for="udata in u.usedUnitContainer">
|
||||
<div>RatingGroup: {{ u.ratingGroup }}</div>
|
||||
<div
|
||||
v-for="(udata, i) in u.usedUnitContainer"
|
||||
style="display: flex"
|
||||
>
|
||||
<strong style="margin-right: 12px">
|
||||
{{ i }}
|
||||
</strong>
|
||||
<div>
|
||||
<span>Data Total Volume: </span>
|
||||
<span>{{ udata.dataTotalVolume }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Data Volume Downlink: </span>
|
||||
<span>{{ udata.dataVolumeDownlink }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Data Volume Uplink: </span>
|
||||
<span>{{ udata.dataVolumeUplink }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Time: </span>
|
||||
<span>{{ udata.time }}</span>
|
||||
<div>
|
||||
<span>Data Total Volume: </span>
|
||||
<span>{{ udata.dataTotalVolume }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Data Volume Downlink: </span>
|
||||
<span>{{ udata.dataVolumeDownlink }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Data Volume Uplink: </span>
|
||||
<span>{{ udata.dataVolumeUplink }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Time: </span>
|
||||
<span>{{ udata.time }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -22,7 +22,9 @@ import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||
import saveAs from 'file-saver';
|
||||
import PQueue from 'p-queue';
|
||||
import { listTenant } from '@/api/system/tenant';
|
||||
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
import { hasPermissions } from '@/plugins/auth-user';
|
||||
const { copy } = useClipboard({ legacy: true });
|
||||
const { getDict } = useDictStore();
|
||||
const { t } = useI18n();
|
||||
const ws = new WS();
|
||||
@@ -296,6 +298,18 @@ function fnRecordDelete(id: string) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制CDR
|
||||
* @param jsonStr JSON字符串
|
||||
*/
|
||||
function fnRecordCopy(jsonStr: string) {
|
||||
if (!jsonStr) return;
|
||||
const text = JSON.stringify(jsonStr, null, 2);
|
||||
copy(text).then(() => {
|
||||
message.success(t('common.copyOk'), 3);
|
||||
});
|
||||
}
|
||||
|
||||
/**查询列表, pageNum初始页数 */
|
||||
function fnGetList(pageNum?: number) {
|
||||
if (tableState.loading) return;
|
||||
@@ -396,7 +410,9 @@ function fnRealTime() {
|
||||
subGroupID: `1007_${queryParams.neId}`,
|
||||
},
|
||||
onmessage: wsMessage,
|
||||
onerror: wsError,
|
||||
onerror: (ev: any) => {
|
||||
console.error(ev);
|
||||
},
|
||||
};
|
||||
ws.connect(options);
|
||||
} else {
|
||||
@@ -406,12 +422,6 @@ function fnRealTime() {
|
||||
}
|
||||
}
|
||||
|
||||
/**接收数据后回调 */
|
||||
function wsError(ev: any) {
|
||||
// 接收数据后回调
|
||||
console.error(ev);
|
||||
}
|
||||
|
||||
/**接收数据后回调 */
|
||||
function wsMessage(res: Record<string, any>) {
|
||||
const { code, requestId, data } = res;
|
||||
@@ -520,6 +530,7 @@ onBeforeUnmount(() => {
|
||||
v-model:value="queryParams.neId"
|
||||
:options="neOtions"
|
||||
:placeholder="t('common.selectPlease')"
|
||||
@change="fnQueryReset()"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
@@ -638,6 +649,7 @@ onBeforeUnmount(() => {
|
||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||
:loading="modalState.confirmLoading"
|
||||
@click.prevent="fnRecordDelete('0')"
|
||||
v-perms:has="['cdr:ne:remove']"
|
||||
>
|
||||
<template #icon><DeleteOutlined /></template>
|
||||
{{ t('common.deleteText') }}
|
||||
@@ -705,7 +717,7 @@ onBeforeUnmount(() => {
|
||||
:data-source="tableState.data"
|
||||
:size="tableState.size"
|
||||
:pagination="tablePagination"
|
||||
:scroll="{ x: tableColumns.length * 150, y: 'calc(100vh - 480px)' }"
|
||||
:scroll="{ x: tableColumns.length * 180, y: 'calc(100vh - 480px)' }"
|
||||
:row-selection="{
|
||||
type: 'checkbox',
|
||||
columnWidth: '48px',
|
||||
@@ -729,11 +741,23 @@ onBeforeUnmount(() => {
|
||||
</template>
|
||||
<template v-if="column.key === 'id'">
|
||||
<a-space :size="8" align="center">
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.copyText') }}</template>
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordCopy(record.cdrJSON)"
|
||||
>
|
||||
<template #icon>
|
||||
<CopyOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.deleteText') }}</template>
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordDelete(record.id)"
|
||||
v-perms:has="['cdr:ne:remove']"
|
||||
>
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
@@ -799,6 +823,23 @@ onBeforeUnmount(() => {
|
||||
</span>
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col
|
||||
:lg="16"
|
||||
:md="16"
|
||||
:xs="22"
|
||||
:offset="2"
|
||||
v-if="
|
||||
record.cdrJSON?.smsContent &&
|
||||
hasPermissions(['cdr:smsc:content'])
|
||||
"
|
||||
>
|
||||
<a-divider orientation="left"> Content </a-divider>
|
||||
<a-typography-paragraph
|
||||
copyable
|
||||
:content="record.cdrJSON.smsContent"
|
||||
>
|
||||
</a-typography-paragraph>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
</a-table>
|
||||
|
||||
@@ -11,8 +11,6 @@ import {
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import useUserStore from '@/store/modules/user';
|
||||
import useLayoutStore from '@/store/modules/layout';
|
||||
import useRouterStore from '@/store/modules/router';
|
||||
const routerStore = useRouterStore();
|
||||
const currentComponent = shallowRef<Component | null>(null);
|
||||
|
||||
const spinning = ref<boolean>(false);
|
||||
|
||||
@@ -92,13 +92,13 @@ const graphNodeMenu = new Menu({
|
||||
${neState.neName ?? '--'}
|
||||
</h3>
|
||||
<div id="restart" style="cursor: pointer; margin-bottom: 4px">
|
||||
> ${t('views.configManage.neManage.restart')}
|
||||
> ${t('views.ne.common.restart')}
|
||||
</div>
|
||||
<div id="stop" style="cursor: pointer; margin-bottom: 4px;">
|
||||
> ${t('views.configManage.neManage.stop')}
|
||||
> ${t('views.ne.common.stop')}
|
||||
</div>
|
||||
<div id="log" style="cursor: pointer; margin-bottom: 4px;">
|
||||
> ${t('views.configManage.neManage.log')}
|
||||
> ${t('views.ne.common.log')}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -4,19 +4,20 @@ import {
|
||||
editNeConfigData,
|
||||
} from '@/api/ne/neConfig';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import { Modal,message } from 'ant-design-vue/es';
|
||||
import { Modal, message } from 'ant-design-vue/es';
|
||||
import { SizeType } from 'ant-design-vue/es/config-provider';
|
||||
import { reactive, watch } from 'vue';
|
||||
|
||||
/**
|
||||
* 参数配置array类型
|
||||
* @param param 父级传入 { t, treeState, neTypeSelect, fnActiveConfigNode, ruleVerification, modalState, fnModalCancel}
|
||||
* @param param 父级传入 { t, treeState, neTypeSelect, neIdSelect, fnActiveConfigNode, ruleVerification, modalState, fnModalCancel}
|
||||
* @returns
|
||||
*/
|
||||
export default function useConfigArray({
|
||||
t,
|
||||
treeState,
|
||||
neTypeSelect,
|
||||
neIdSelect,
|
||||
fnActiveConfigNode,
|
||||
ruleVerification,
|
||||
modalState,
|
||||
@@ -130,29 +131,61 @@ export default function useConfigArray({
|
||||
data[key] = from[key]['value'];
|
||||
}
|
||||
|
||||
// 发送
|
||||
// 请求
|
||||
const reqArr = [];
|
||||
if (neTypeSelect.value[1].startsWith('SYNC')) {
|
||||
for (const neId of neIdSelect.value) {
|
||||
reqArr.push(
|
||||
editNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neId,
|
||||
paramName: treeState.selectNode.paramName,
|
||||
paramData: data,
|
||||
loc: loc,
|
||||
})
|
||||
);
|
||||
}
|
||||
} else {
|
||||
reqArr.push(
|
||||
editNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neTypeSelect.value[1],
|
||||
paramName: treeState.selectNode.paramName,
|
||||
paramData: data,
|
||||
loc: loc,
|
||||
})
|
||||
);
|
||||
}
|
||||
// 无请求提示
|
||||
if (reqArr.length === 0) {
|
||||
message.warning({
|
||||
content: t('views.ne.neConfig.neIdSyncPleace'),
|
||||
duration: 3,
|
||||
});
|
||||
arrayEditClose();
|
||||
return;
|
||||
}
|
||||
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
editNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neTypeSelect.value[1],
|
||||
paramName: treeState.selectNode.paramName,
|
||||
paramData: data,
|
||||
loc: loc,
|
||||
})
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
Promise.allSettled(reqArr)
|
||||
.then(resArr => {
|
||||
const rejected = resArr.find(res => res.status === 'rejected');
|
||||
if (rejected) {
|
||||
message.warning({
|
||||
content: t('views.ne.neConfig.updateItemErr'),
|
||||
duration: 3,
|
||||
});
|
||||
} else {
|
||||
message.success({
|
||||
content: t('views.ne.neConfig.updateItem', {
|
||||
num: modalState.title,
|
||||
}),
|
||||
duration: 3,
|
||||
});
|
||||
}
|
||||
const fulfilled = resArr.find(res => res.status === 'fulfilled');
|
||||
if (fulfilled) {
|
||||
fnActiveConfigNode('#');
|
||||
} else {
|
||||
message.warning({
|
||||
content: t('views.ne.neConfig.updateItemErr'),
|
||||
duration: 3,
|
||||
});
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
@@ -172,28 +205,65 @@ export default function useConfigArray({
|
||||
num: title,
|
||||
}),
|
||||
onOk() {
|
||||
delNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neTypeSelect.value[1],
|
||||
paramName: treeState.selectNode.paramName,
|
||||
loc: loc,
|
||||
}).then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
message.success({
|
||||
content: t('views.ne.neConfig.delItemOk', {
|
||||
num: title,
|
||||
}),
|
||||
duration: 2,
|
||||
});
|
||||
arrayEditClose();
|
||||
fnActiveConfigNode('#');
|
||||
} else {
|
||||
message.error({
|
||||
content: `${res.msg}`,
|
||||
duration: 2,
|
||||
});
|
||||
// 请求
|
||||
const reqArr = [];
|
||||
if (neTypeSelect.value[1].startsWith('SYNC')) {
|
||||
for (const neId of neIdSelect.value) {
|
||||
reqArr.push(
|
||||
delNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neId,
|
||||
paramName: treeState.selectNode.paramName,
|
||||
loc: loc,
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
reqArr.push(
|
||||
delNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neTypeSelect.value[1],
|
||||
paramName: treeState.selectNode.paramName,
|
||||
loc: loc,
|
||||
})
|
||||
);
|
||||
}
|
||||
// 无请求提示
|
||||
if (reqArr.length === 0) {
|
||||
message.warning({
|
||||
content: t('views.ne.neConfig.neIdSyncPleace'),
|
||||
duration: 3,
|
||||
});
|
||||
arrayEditClose();
|
||||
return;
|
||||
}
|
||||
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
Promise.allSettled(reqArr)
|
||||
.then(resArr => {
|
||||
const rejected = resArr.find(res => res.status === 'rejected');
|
||||
if (rejected) {
|
||||
message.error({
|
||||
content: `${rejected.reason}`,
|
||||
duration: 2,
|
||||
});
|
||||
} else {
|
||||
message.success({
|
||||
content: t('views.ne.neConfig.delItemOk', {
|
||||
num: title,
|
||||
}),
|
||||
duration: 2,
|
||||
});
|
||||
}
|
||||
const fulfilled = resArr.find(res => res.status === 'fulfilled');
|
||||
if (fulfilled) {
|
||||
fnActiveConfigNode('#');
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
hide();
|
||||
arrayEditClose();
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -264,29 +334,61 @@ export default function useConfigArray({
|
||||
data[key] = from[key]['value'];
|
||||
}
|
||||
|
||||
// 发送
|
||||
// 请求
|
||||
const reqArr = [];
|
||||
if (neTypeSelect.value[1].startsWith('SYNC')) {
|
||||
for (const neId of neIdSelect.value) {
|
||||
reqArr.push(
|
||||
addNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neId,
|
||||
paramName: treeState.selectNode.paramName,
|
||||
paramData: data,
|
||||
loc: `${from['index']['value']}`,
|
||||
})
|
||||
);
|
||||
}
|
||||
} else {
|
||||
reqArr.push(
|
||||
addNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neTypeSelect.value[1],
|
||||
paramName: treeState.selectNode.paramName,
|
||||
paramData: data,
|
||||
loc: `${from['index']['value']}`,
|
||||
})
|
||||
);
|
||||
}
|
||||
// 无请求提示
|
||||
if (reqArr.length === 0) {
|
||||
message.warning({
|
||||
content: t('views.ne.neConfig.neIdSyncPleace'),
|
||||
duration: 3,
|
||||
});
|
||||
arrayEditClose();
|
||||
return;
|
||||
}
|
||||
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
addNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neTypeSelect.value[1],
|
||||
paramName: treeState.selectNode.paramName,
|
||||
paramData: data,
|
||||
loc: `${from['index']['value']}`,
|
||||
})
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
Promise.allSettled(reqArr)
|
||||
.then(resArr => {
|
||||
const rejected = resArr.find(res => res.status === 'rejected');
|
||||
if (rejected) {
|
||||
message.warning({
|
||||
content: t('views.ne.neConfig.addItemErr'),
|
||||
duration: 3,
|
||||
});
|
||||
} else {
|
||||
message.success({
|
||||
content: t('views.ne.neConfig.addItemOk', {
|
||||
num: modalState.title,
|
||||
}),
|
||||
duration: 3,
|
||||
});
|
||||
}
|
||||
const fulfilled = resArr.find(res => res.status === 'fulfilled');
|
||||
if (fulfilled) {
|
||||
fnActiveConfigNode('#');
|
||||
} else {
|
||||
message.warning({
|
||||
content: t('views.ne.neConfig.addItemErr'),
|
||||
duration: 3,
|
||||
});
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
|
||||
@@ -10,13 +10,14 @@ import { nextTick, reactive } from 'vue';
|
||||
|
||||
/**
|
||||
* 参数配置array类型的嵌套array
|
||||
* @param param 父级传入 { t, treeState, neTypeSelect, fnActiveConfigNode, ruleVerification, modalState, arrayState, arrayInitEdit, arrayInitAdd, arrayEditClose}
|
||||
* @param param 父级传入 { t, treeState, neTypeSelect, neIdSelect, fnActiveConfigNode, ruleVerification, modalState, arrayState, arrayInitEdit, arrayInitAdd, arrayEditClose}
|
||||
* @returns
|
||||
*/
|
||||
export default function useConfigArrayChild({
|
||||
t,
|
||||
treeState,
|
||||
neTypeSelect,
|
||||
neIdSelect,
|
||||
fnActiveConfigNode,
|
||||
ruleVerification,
|
||||
modalState,
|
||||
@@ -198,29 +199,61 @@ export default function useConfigArrayChild({
|
||||
data[key] = from[key]['value'];
|
||||
}
|
||||
|
||||
// 发送
|
||||
// 请求
|
||||
const reqArr = [];
|
||||
if (neTypeSelect.value[1].startsWith('SYNC')) {
|
||||
for (const neId of neIdSelect.value) {
|
||||
reqArr.push(
|
||||
editNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neId,
|
||||
paramName: treeState.selectNode.paramName,
|
||||
paramData: data,
|
||||
loc,
|
||||
})
|
||||
);
|
||||
}
|
||||
} else {
|
||||
reqArr.push(
|
||||
editNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neTypeSelect.value[1],
|
||||
paramName: treeState.selectNode.paramName,
|
||||
paramData: data,
|
||||
loc,
|
||||
})
|
||||
);
|
||||
}
|
||||
// 无请求提示
|
||||
if (reqArr.length === 0) {
|
||||
message.warning({
|
||||
content: t('views.ne.neConfig.neIdSyncPleace'),
|
||||
duration: 3,
|
||||
});
|
||||
arrayEditClose();
|
||||
return;
|
||||
}
|
||||
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
editNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neTypeSelect.value[1],
|
||||
paramName: treeState.selectNode.paramName,
|
||||
paramData: data,
|
||||
loc,
|
||||
})
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
Promise.allSettled(reqArr)
|
||||
.then(resArr => {
|
||||
const rejected = resArr.find(res => res.status === 'rejected');
|
||||
if (rejected) {
|
||||
message.warning({
|
||||
content: t('views.ne.neConfig.updateItemErr'),
|
||||
duration: 3,
|
||||
});
|
||||
} else {
|
||||
message.success({
|
||||
content: t('views.ne.neConfig.updateItem', {
|
||||
num: modalState.title,
|
||||
}),
|
||||
duration: 3,
|
||||
});
|
||||
}
|
||||
const fulfilled = resArr.find(res => res.status === 'fulfilled');
|
||||
if (fulfilled) {
|
||||
fnActiveConfigNode('#');
|
||||
} else {
|
||||
message.warning({
|
||||
content: t('views.ne.neConfig.updateItemErr'),
|
||||
duration: 3,
|
||||
});
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
@@ -241,28 +274,65 @@ export default function useConfigArrayChild({
|
||||
num: title,
|
||||
}),
|
||||
onOk() {
|
||||
delNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neTypeSelect.value[1],
|
||||
paramName: treeState.selectNode.paramName,
|
||||
loc,
|
||||
}).then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
message.success({
|
||||
content: t('views.ne.neConfig.delItemOk', {
|
||||
num: title,
|
||||
}),
|
||||
duration: 2,
|
||||
});
|
||||
arrayEditClose();
|
||||
fnActiveConfigNode('#');
|
||||
} else {
|
||||
message.error({
|
||||
content: `${res.msg}`,
|
||||
duration: 2,
|
||||
});
|
||||
// 请求
|
||||
const reqArr = [];
|
||||
if (neTypeSelect.value[1].startsWith('SYNC')) {
|
||||
for (const neId of neIdSelect.value) {
|
||||
reqArr.push(
|
||||
delNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neId,
|
||||
paramName: treeState.selectNode.paramName,
|
||||
loc,
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
reqArr.push(
|
||||
delNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neTypeSelect.value[1],
|
||||
paramName: treeState.selectNode.paramName,
|
||||
loc,
|
||||
})
|
||||
);
|
||||
}
|
||||
// 无请求提示
|
||||
if (reqArr.length === 0) {
|
||||
message.warning({
|
||||
content: t('views.ne.neConfig.neIdSyncPleace'),
|
||||
duration: 3,
|
||||
});
|
||||
arrayEditClose();
|
||||
return;
|
||||
}
|
||||
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
Promise.allSettled(reqArr)
|
||||
.then(resArr => {
|
||||
const rejected = resArr.find(res => res.status === 'rejected');
|
||||
if (rejected) {
|
||||
message.error({
|
||||
content: `${rejected.reason}`,
|
||||
duration: 2,
|
||||
});
|
||||
} else {
|
||||
message.success({
|
||||
content: t('views.ne.neConfig.delItemOk', {
|
||||
num: title,
|
||||
}),
|
||||
duration: 2,
|
||||
});
|
||||
}
|
||||
const fulfilled = resArr.find(res => res.status === 'fulfilled');
|
||||
if (fulfilled) {
|
||||
fnActiveConfigNode('#');
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
hide();
|
||||
arrayEditClose();
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -309,29 +379,61 @@ export default function useConfigArrayChild({
|
||||
data[key] = from[key]['value'];
|
||||
}
|
||||
|
||||
// 发送
|
||||
// 请求
|
||||
const reqArr = [];
|
||||
if (neTypeSelect.value[1].startsWith('SYNC')) {
|
||||
for (const neId of neIdSelect.value) {
|
||||
reqArr.push(
|
||||
addNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neId,
|
||||
paramName: treeState.selectNode.paramName,
|
||||
paramData: data,
|
||||
loc,
|
||||
})
|
||||
);
|
||||
}
|
||||
} else {
|
||||
reqArr.push(
|
||||
addNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neTypeSelect.value[1],
|
||||
paramName: treeState.selectNode.paramName,
|
||||
paramData: data,
|
||||
loc,
|
||||
})
|
||||
);
|
||||
}
|
||||
// 无请求提示
|
||||
if (reqArr.length === 0) {
|
||||
message.warning({
|
||||
content: t('views.ne.neConfig.neIdSyncPleace'),
|
||||
duration: 3,
|
||||
});
|
||||
arrayEditClose();
|
||||
return;
|
||||
}
|
||||
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
addNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neTypeSelect.value[1],
|
||||
paramName: treeState.selectNode.paramName,
|
||||
paramData: data,
|
||||
loc,
|
||||
})
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
Promise.allSettled(reqArr)
|
||||
.then(resArr => {
|
||||
const rejected = resArr.find(res => res.status === 'rejected');
|
||||
if (rejected) {
|
||||
message.warning({
|
||||
content: t('views.ne.neConfig.addItemErr'),
|
||||
duration: 3,
|
||||
});
|
||||
} else {
|
||||
message.success({
|
||||
content: t('views.ne.neConfig.addItemOk', {
|
||||
num: modalState.title,
|
||||
}),
|
||||
duration: 3,
|
||||
});
|
||||
}
|
||||
const fulfilled = resArr.find(res => res.status === 'fulfilled');
|
||||
if (fulfilled) {
|
||||
fnActiveConfigNode('#');
|
||||
} else {
|
||||
message.warning({
|
||||
content: t('views.ne.neConfig.addItemErr'),
|
||||
duration: 3,
|
||||
});
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
|
||||
@@ -6,13 +6,14 @@ import { reactive, toRaw } from 'vue';
|
||||
|
||||
/**
|
||||
* list类型参数处理
|
||||
* @param param 父级传入 {t, treeState, neTypeSelect, ruleVerification}
|
||||
* @param param 父级传入 {t, treeState, neTypeSelect, neIdSelect, ruleVerification}
|
||||
* @returns
|
||||
*/
|
||||
export default function useConfigList({
|
||||
t,
|
||||
treeState,
|
||||
neTypeSelect,
|
||||
neIdSelect,
|
||||
ruleVerification,
|
||||
}: any) {
|
||||
/**单列表状态类型 */
|
||||
@@ -83,25 +84,64 @@ export default function useConfigList({
|
||||
return;
|
||||
}
|
||||
|
||||
// 发送
|
||||
// 请求
|
||||
const reqArr = [];
|
||||
if (neTypeSelect.value[1].startsWith('SYNC')) {
|
||||
for (const neId of neIdSelect.value) {
|
||||
reqArr.push(
|
||||
editNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neId,
|
||||
paramName: treeState.selectNode.paramName,
|
||||
paramData: {
|
||||
[from['name']]: from['value'],
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
} else {
|
||||
reqArr.push(
|
||||
editNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neTypeSelect.value[1],
|
||||
paramName: treeState.selectNode.paramName,
|
||||
paramData: {
|
||||
[from['name']]: from['value'],
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
// 无请求提示
|
||||
if (reqArr.length === 0) {
|
||||
message.warning({
|
||||
content: t('views.ne.neConfig.neIdSyncPleace'),
|
||||
duration: 3,
|
||||
});
|
||||
listState.confirmLoading = false;
|
||||
listState.editRecord = {};
|
||||
return;
|
||||
}
|
||||
|
||||
listState.confirmLoading = true;
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
editNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neTypeSelect.value[1],
|
||||
paramName: treeState.selectNode.paramName,
|
||||
paramData: {
|
||||
[from['name']]: from['value'],
|
||||
},
|
||||
})
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
Promise.allSettled(reqArr)
|
||||
.then(resArr => {
|
||||
const rejected = resArr.find(res => res.status === 'rejected');
|
||||
if (rejected) {
|
||||
message.warning({
|
||||
content: t('views.ne.neConfig.updateValueErr'),
|
||||
duration: 3,
|
||||
});
|
||||
} else {
|
||||
message.success({
|
||||
content: t('views.ne.neConfig.updateValue', {
|
||||
num: from['display'],
|
||||
}),
|
||||
duration: 3,
|
||||
});
|
||||
}
|
||||
const fulfilled = resArr.find(res => res.status === 'fulfilled');
|
||||
if (fulfilled) {
|
||||
// 改变表格数据
|
||||
const item = listState.data.find(
|
||||
(item: Record<string, any>) => from['name'] === item['name']
|
||||
@@ -109,11 +149,6 @@ export default function useConfigList({
|
||||
if (item) {
|
||||
Object.assign(item, listState.editRecord);
|
||||
}
|
||||
} else {
|
||||
message.warning({
|
||||
content: t('views.ne.neConfig.updateValueErr'),
|
||||
duration: 3,
|
||||
});
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, onMounted, toRaw, watch } from 'vue';
|
||||
import { reactive, ref, onMounted, toRaw, watch, computed } from 'vue';
|
||||
import { PageContainer } from 'antdv-pro-layout';
|
||||
import { ProModal } from 'antdv-pro-modal';
|
||||
import { message } from 'ant-design-vue/es';
|
||||
import { message, TreeSelect, type TreeSelectProps } 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';
|
||||
@@ -19,11 +19,102 @@ const { ruleVerification, smfByUPFIdLoadData, smfByUPFIdOptions } = useOptions({
|
||||
t,
|
||||
});
|
||||
|
||||
/**网元类型_多neId */
|
||||
/**网元类型 type,[](type,id) */
|
||||
let neCascaderOptions = ref<Record<string, any>[]>([]);
|
||||
|
||||
/**网元类型 [](label,value,children) */
|
||||
let neSelectTreeDate = ref<TreeSelectProps['treeData']>([]);
|
||||
/**网元类型选择 type,id */
|
||||
let neTypeSelect = ref<string[]>(['', '']);
|
||||
/**网元类型选择 id */
|
||||
let neIdSelect = ref<string[]>([]);
|
||||
let neTypeSelectStatus = ref(true);
|
||||
/**网元类型neType选择 */
|
||||
async function fnSelectNeType(_: any, info: any) {
|
||||
if (!info) return;
|
||||
await fnGetNeConfig(info.value);
|
||||
if (treeState.data.length === 0) {
|
||||
message.warning({
|
||||
content: `${t('views.ne.neConfig.noConfigData')}`,
|
||||
duration: 3,
|
||||
});
|
||||
treeState.selectLoading = true;
|
||||
neIdSelect.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
neTypeSelect.value[0] = info.value;
|
||||
neTypeSelect.value[1] = 'SYNC';
|
||||
treeState.selectLoading = true;
|
||||
neTypeSelectStatus.value = true;
|
||||
neIdSelect.value = [];
|
||||
// 构建可选树形数据
|
||||
if (Array.isArray(info.children) && info.children.length > 0) {
|
||||
const neArr = info.children.concat();
|
||||
for (let index = 0; index < neArr.length; index++) {
|
||||
const v = neArr[index];
|
||||
const ne = {
|
||||
label: v.neName,
|
||||
value: v.neId,
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
// 检查下级网元是否可用
|
||||
const res = await getNeConfigData({
|
||||
neType: v.neType,
|
||||
neId: v.neId,
|
||||
paramName: `${treeState.data[0].key}`,
|
||||
});
|
||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||
ne.disabled = !res.data.length;
|
||||
} else {
|
||||
ne.disabled = true;
|
||||
}
|
||||
|
||||
// 添加到树形数据
|
||||
const root = neSelectTreeDate.value?.find(s => s.label === v.province);
|
||||
if (root && Array.isArray(root.children)) {
|
||||
root.children.push(ne);
|
||||
} else {
|
||||
neSelectTreeDate.value?.push({
|
||||
label: v.province,
|
||||
value: 'SYNC_' + v.province,
|
||||
children: [ne],
|
||||
});
|
||||
}
|
||||
|
||||
const key = 'SYNC_' + v.province;
|
||||
// 初始区域
|
||||
if (neIdSelect.value.length === 0) {
|
||||
neTypeSelect.value[1] = key;
|
||||
}
|
||||
// 同区域内添加
|
||||
if (neTypeSelect.value[1] === key) {
|
||||
neIdSelect.value.push(v.neId);
|
||||
}
|
||||
}
|
||||
}
|
||||
fnActiveConfigNode(treeState.data[0].key);
|
||||
neTypeSelectStatus.value = false;
|
||||
}
|
||||
/**网元类型neId选择 */
|
||||
function fnSelectNeId(_: any, info: any) {
|
||||
if (info.children && Array.isArray(info.children)) {
|
||||
const okArr = info.children.filter((item: any) => !item.disabled);
|
||||
if (Array.isArray(okArr) && okArr.length === 0) {
|
||||
message.warning({
|
||||
content: `${t('views.ne.neConfig.noConfigdDisabled')}`,
|
||||
duration: 3,
|
||||
});
|
||||
neIdSelect.value = [];
|
||||
return;
|
||||
}
|
||||
neTypeSelect.value[1] = info.value;
|
||||
neIdSelect.value = okArr.map((item: any) => item.value);
|
||||
} else {
|
||||
neTypeSelect.value[1] = info.value;
|
||||
}
|
||||
fnActiveConfigNode(treeState.data[0].key);
|
||||
}
|
||||
|
||||
/**左侧导航是否可收起 */
|
||||
let collapsible = ref<boolean>(true);
|
||||
@@ -49,6 +140,7 @@ type TreeStateType = {
|
||||
paramType: string;
|
||||
paramPerms: string[];
|
||||
paramData: Record<string, any>[];
|
||||
visible: string;
|
||||
};
|
||||
/**选择 loading */
|
||||
selectLoading: boolean;
|
||||
@@ -63,6 +155,7 @@ let treeState: TreeStateType = reactive({
|
||||
paramType: '',
|
||||
paramPerms: [],
|
||||
paramData: [],
|
||||
visible: 'public',
|
||||
// 树形节点需要有
|
||||
title: '',
|
||||
key: '',
|
||||
@@ -100,22 +193,134 @@ function fnActiveConfigNode(key: string | number) {
|
||||
}
|
||||
treeState.selectNode = JSON.parse(JSON.stringify(param));
|
||||
|
||||
let neId = neTypeSelect.value[1];
|
||||
// 无neId时取首个可连接的
|
||||
if (neId.startsWith('SYNC')) {
|
||||
const oneNeId = neIdSelect.value[0];
|
||||
if (oneNeId) {
|
||||
neId = oneNeId;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取网元端的配置数据
|
||||
getNeConfigData({
|
||||
neType: neTypeSelect.value[0],
|
||||
neId: neTypeSelect.value[1],
|
||||
paramName: key,
|
||||
}).then(res => {
|
||||
fnGetNeConfigData(neTypeSelect.value[0], neId, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询配置可选属性值列表
|
||||
* neTypeSelect.value[0]
|
||||
*/
|
||||
async function fnGetNeConfig(neType: string) {
|
||||
if (!neType) {
|
||||
message.warning({
|
||||
content: t('views.ne.neConfig.neTypePleace'),
|
||||
duration: 3,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
treeState.loading = true;
|
||||
// 获取数据
|
||||
const res = await getAllNeConfig(neType);
|
||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||
const arr = [];
|
||||
for (const v of res.data) {
|
||||
const item = JSON.parse(JSON.stringify(v));
|
||||
// 规则项
|
||||
let paramData: Record<string, string>[] = [];
|
||||
for (let index = 0; index < item.paramData.length; index++) {
|
||||
const element = item.paramData[index];
|
||||
if (!element['visible']) {
|
||||
element['visible'] = 'public';
|
||||
}
|
||||
paramData.push(element);
|
||||
}
|
||||
// 权限控制
|
||||
let paramPerms: string[] = [];
|
||||
if (item.paramPerms) {
|
||||
paramPerms = item.paramPerms.split(',');
|
||||
} else {
|
||||
paramPerms = ['post', 'put', 'delete'];
|
||||
}
|
||||
arr.push({
|
||||
children: undefined,
|
||||
title: item.paramDisplay,
|
||||
key: item.paramName,
|
||||
paramName: item.paramName,
|
||||
paramDisplay: item.paramDisplay,
|
||||
paramType: item.paramType,
|
||||
paramPerms: paramPerms,
|
||||
paramData: paramData,
|
||||
visible: item.visible,
|
||||
});
|
||||
}
|
||||
treeState.data = arr;
|
||||
treeState.loading = false;
|
||||
} else {
|
||||
treeState.data = [];
|
||||
neTypeSelectStatus.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**过滤可见项 */
|
||||
const treeStateData = computed(() => {
|
||||
// 公共
|
||||
if (neTypeSelect.value[1].startsWith('SYNC')) {
|
||||
return treeState.data.filter(item => item.visible === 'public');
|
||||
}
|
||||
// 具体网元
|
||||
const arr: DataNode[] = [];
|
||||
for (const item of treeState.data) {
|
||||
if (item.visible === 'self') {
|
||||
arr.push(item);
|
||||
} else if (item.paramType === 'list') {
|
||||
for (let index = 0; index < item.paramData.length; index++) {
|
||||
const element = item.paramData[index];
|
||||
if (element['visible'] === 'self') {
|
||||
arr.push(item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
});
|
||||
|
||||
/**
|
||||
* 查询配置属性值数据
|
||||
* paramName = treeState.data[0].key
|
||||
*/
|
||||
function fnGetNeConfigData(
|
||||
neType: string,
|
||||
neId: string,
|
||||
paramName: string | number
|
||||
) {
|
||||
const param = treeState.selectNode;
|
||||
// 获取网元端的配置数据
|
||||
getNeConfigData({ neType, neId, paramName }).then(res => {
|
||||
// 数据处理
|
||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||
const ruleArr = param.paramData;
|
||||
const ruleArr: Record<string, any>[] = JSON.parse(
|
||||
JSON.stringify(param.paramData)
|
||||
);
|
||||
const dataArr = res.data;
|
||||
if (param.paramType === 'list') {
|
||||
// 过滤可见规则项
|
||||
let ruleArrFilter: Record<string, any>[] = [];
|
||||
if (neTypeSelect.value[1].startsWith('SYNC')) {
|
||||
ruleArrFilter = ruleArr.filter(item => item['visible'] === 'public');
|
||||
} else {
|
||||
ruleArrFilter = ruleArr.filter(item => item['visible'] === 'self');
|
||||
}
|
||||
// 列表项数据
|
||||
const dataList = [];
|
||||
for (const item of dataArr) {
|
||||
for (const key in item) {
|
||||
// 规则为准
|
||||
for (const rule of ruleArr) {
|
||||
for (const rule of ruleArrFilter) {
|
||||
// 取到对应规则key设置值
|
||||
if (rule['name'] === key) {
|
||||
const ruleItem = Object.assign(rule, {
|
||||
optional: 'true',
|
||||
@@ -190,64 +395,19 @@ function fnActiveConfigNode(key: string | number) {
|
||||
tablePagination.current = 1;
|
||||
arrayEditClose();
|
||||
}
|
||||
// 有数据关闭loading
|
||||
setTimeout(() => {
|
||||
treeState.selectLoading = false;
|
||||
}, 300);
|
||||
} else {
|
||||
message.warning({
|
||||
content: `${param.paramDisplay} ${t(
|
||||
'views.configManage.configParamForm.noConfigData'
|
||||
)}`,
|
||||
content: `${param.paramDisplay} ${t('views.ne.neConfig.noConfigData')}`,
|
||||
duration: 3,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**查询配置可选属性值列表 */
|
||||
function fnGetNeConfig() {
|
||||
const neType = neTypeSelect.value[0];
|
||||
if (!neType) {
|
||||
message.warning({
|
||||
content: t('views.configManage.configParamForm.neTypePleace'),
|
||||
duration: 3,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
treeState.loading = true;
|
||||
// 获取数据
|
||||
getAllNeConfig(neType).then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||
const arr = [];
|
||||
for (const item of res.data) {
|
||||
let paramPerms: string[] = [];
|
||||
if (item.paramPerms) {
|
||||
paramPerms = item.paramPerms.split(',');
|
||||
} else {
|
||||
paramPerms = ['post', 'put', 'delete'];
|
||||
}
|
||||
arr.push({
|
||||
...item,
|
||||
children: undefined,
|
||||
title: item.paramDisplay,
|
||||
key: item.paramName,
|
||||
paramPerms,
|
||||
});
|
||||
}
|
||||
treeState.data = arr;
|
||||
treeState.loading = false;
|
||||
// 取首个tag
|
||||
if (res.data.length > 0) {
|
||||
const item = JSON.parse(JSON.stringify(treeState.data[0]));
|
||||
treeState.selectNode = item;
|
||||
treeState.selectLoading = false;
|
||||
fnActiveConfigNode(item.key);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**对话框对象信息状态类型 */
|
||||
type ModalStateType = {
|
||||
/**添加框是否显示 */
|
||||
@@ -315,13 +475,18 @@ watch(
|
||||
val => {
|
||||
// SMF需要选择配置的UPF id
|
||||
if (val && neTypeSelect.value[0] === 'SMF') {
|
||||
smfByUPFIdLoadData(neTypeSelect.value[1]);
|
||||
if (neTypeSelect.value[1].startsWith('SYNC')) {
|
||||
smfByUPFIdLoadData(neTypeSelect.value[1]);
|
||||
return;
|
||||
} else {
|
||||
smfByUPFIdLoadData(neTypeSelect.value[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const { tablePagination, listState, listEdit, listEditClose, listEditOk } =
|
||||
useConfigList({ t, treeState, neTypeSelect, ruleVerification });
|
||||
useConfigList({ t, treeState, neTypeSelect, neIdSelect, ruleVerification });
|
||||
|
||||
const {
|
||||
arrayState,
|
||||
@@ -337,6 +502,7 @@ const {
|
||||
t,
|
||||
treeState,
|
||||
neTypeSelect,
|
||||
neIdSelect,
|
||||
fnActiveConfigNode,
|
||||
ruleVerification,
|
||||
modalState,
|
||||
@@ -355,6 +521,7 @@ const {
|
||||
t,
|
||||
treeState,
|
||||
neTypeSelect,
|
||||
neIdSelect,
|
||||
fnActiveConfigNode,
|
||||
ruleVerification,
|
||||
modalState,
|
||||
@@ -385,13 +552,14 @@ onMounted(() => {
|
||||
// 默认选择AMF
|
||||
const item = neCascaderOptions.value.find(s => s.value === 'AMF');
|
||||
if (item && item.children) {
|
||||
const info = item.children[0];
|
||||
neTypeSelect.value = [info.neType, info.neId];
|
||||
fnSelectNeType(null, item);
|
||||
// const info = item.children[0];
|
||||
// neTypeSelect.value = [info.neType, info.neId];
|
||||
} else {
|
||||
const info = neCascaderOptions.value[0].children[0];
|
||||
neTypeSelect.value = [info.neType, info.neId];
|
||||
fnSelectNeType(null, neCascaderOptions.value[0]);
|
||||
// const info = neCascaderOptions.value[0].children[0];
|
||||
// neTypeSelect.value = [info.neType, info.neId];
|
||||
}
|
||||
fnGetNeConfig();
|
||||
}
|
||||
} else {
|
||||
message.warning({
|
||||
@@ -416,20 +584,43 @@ onMounted(() => {
|
||||
<!-- 网元类型 -->
|
||||
<a-card size="small" :bordered="false" :loading="treeState.loading">
|
||||
<template #title>
|
||||
{{ t('views.configManage.configParamForm.treeTitle') }}
|
||||
{{ t('views.ne.neConfig.treeTitle') }}
|
||||
</template>
|
||||
<a-form layout="vertical" autocomplete="off">
|
||||
<a-form-item name="neId ">
|
||||
<a-cascader
|
||||
v-model:value="neTypeSelect"
|
||||
:options="neCascaderOptions"
|
||||
:allow-clear="false"
|
||||
@change="fnGetNeConfig"
|
||||
/>
|
||||
<a-form-item name="neTypeSelect ">
|
||||
<a-input-group compact>
|
||||
<a-select
|
||||
:disabled="neTypeSelectStatus"
|
||||
:value="neTypeSelect[0]"
|
||||
:options="neCascaderOptions"
|
||||
:allow-clear="false"
|
||||
@change="fnSelectNeType"
|
||||
style="width: 40%"
|
||||
>
|
||||
</a-select>
|
||||
<a-tree-select
|
||||
v-model:value="neTypeSelect[1]"
|
||||
:status="neIdSelect.length === 0 ? 'warning' : ''"
|
||||
:disabled="treeState.selectLoading"
|
||||
:tree-data="neSelectTreeDate"
|
||||
:maxTagCount="1"
|
||||
:show-search="true"
|
||||
:allow-clear="false"
|
||||
:tree-default-expand-all="true"
|
||||
:tree-checkable="false"
|
||||
:show-checked-strategy="TreeSelect.SHOW_PARENT"
|
||||
placement="bottomRight"
|
||||
tree-node-filter-prop="label"
|
||||
style="width: 60%"
|
||||
@select="fnSelectNeId"
|
||||
>
|
||||
</a-tree-select>
|
||||
</a-input-group>
|
||||
</a-form-item>
|
||||
<a-form-item name="listeningPort">
|
||||
<a-form-item name="treeStateData">
|
||||
<a-tree
|
||||
:tree-data="treeState.data"
|
||||
:disabled="neTypeSelectStatus"
|
||||
:tree-data="treeStateData"
|
||||
:selected-keys="[treeState.selectNode.paramName]"
|
||||
@select="fnSelectConfigNode"
|
||||
>
|
||||
@@ -461,12 +652,12 @@ onMounted(() => {
|
||||
{{ treeState.selectNode.paramDisplay }}
|
||||
</a-typography-text>
|
||||
<a-typography-text type="danger" v-else>
|
||||
{{ t('views.configManage.configParamForm.treeSelectTip') }}
|
||||
{{ t('views.ne.neConfig.treeSelectTip') }}
|
||||
</a-typography-text>
|
||||
</template>
|
||||
<template #extra>
|
||||
<a-space :size="8" align="center" v-show="!treeState.selectLoading">
|
||||
<a-tooltip>
|
||||
<a-tooltip placement="topRight">
|
||||
<template #title>{{ t('common.reloadText') }}</template>
|
||||
<a-button
|
||||
type="default"
|
||||
@@ -549,10 +740,9 @@ onMounted(() => {
|
||||
<template #title> {{ t('common.ok') }} </template>
|
||||
<a-popconfirm
|
||||
:title="
|
||||
t(
|
||||
'views.configManage.configParamForm.editOkTip',
|
||||
{ num: record['display'] }
|
||||
)
|
||||
t('views.ne.neConfig.editOkTip', {
|
||||
num: record['display'],
|
||||
})
|
||||
"
|
||||
placement="topRight"
|
||||
:disabled="listState.confirmLoading"
|
||||
@@ -610,7 +800,7 @@ onMounted(() => {
|
||||
</a-table>
|
||||
|
||||
<!-- array类型 -->
|
||||
<template v-if="treeState.selectNode.paramType === 'array'">
|
||||
<template v-else-if="treeState.selectNode.paramType === 'array'">
|
||||
<a-table
|
||||
class="table"
|
||||
row-key="index"
|
||||
@@ -689,9 +879,7 @@ onMounted(() => {
|
||||
"
|
||||
>
|
||||
<template #icon><BarsOutlined /></template>
|
||||
{{
|
||||
t('views.configManage.configParamForm.arrayMore')
|
||||
}}
|
||||
{{ t('views.ne.neConfig.arrayMore') }}
|
||||
</a-button>
|
||||
<!--特殊字段拓展显示-->
|
||||
<span
|
||||
@@ -792,11 +980,7 @@ onMounted(() => {
|
||||
<template v-if="text.array">
|
||||
<a-button type="default" size="small">
|
||||
<template #icon><BarsOutlined /></template>
|
||||
{{
|
||||
t(
|
||||
'views.configManage.configParamForm.arrayMore'
|
||||
)
|
||||
}}
|
||||
{{ t('views.ne.neConfig.arrayMore') }}
|
||||
</a-button>
|
||||
</template>
|
||||
|
||||
@@ -816,6 +1000,10 @@ onMounted(() => {
|
||||
</template>
|
||||
</a-table>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<a-alert type="warning" show-icon message="No Data" />
|
||||
</template>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
@@ -166,8 +166,8 @@ function fnBeforeUploadFile(file: FileType) {
|
||||
const suff = fileName.substring(fileName.lastIndexOf('.'));
|
||||
if (!['.deb', '.rpm'].includes(suff)) {
|
||||
message.error(
|
||||
t('views.configManage.softwareManage.onlyAble', {
|
||||
fileText: '(.deb、.rpm)',
|
||||
t('views.ne.neSoftware.fileTypeNotEq', {
|
||||
txt: '(.deb、.rpm)',
|
||||
}),
|
||||
3
|
||||
);
|
||||
@@ -238,8 +238,8 @@ function fnBeforeUploadFileDep(file: FileType) {
|
||||
const suff = fileName.substring(fileName.lastIndexOf('.'));
|
||||
if (!['.deb', '.rpm'].includes(suff)) {
|
||||
message.error(
|
||||
t('views.configManage.softwareManage.onlyAble', {
|
||||
fileText: '(.deb、.rpm)',
|
||||
t('views.ne.neSoftware.fileTypeNotEq', {
|
||||
txt: '(.deb、.rpm)',
|
||||
}),
|
||||
3
|
||||
);
|
||||
|
||||
@@ -171,8 +171,8 @@ function fnBeforeUploadFile(file: FileType) {
|
||||
const suff = fileName.substring(fileName.lastIndexOf('.'));
|
||||
if (!['.deb', '.rpm'].includes(suff)) {
|
||||
message.error(
|
||||
t('views.configManage.softwareManage.onlyAble', {
|
||||
fileText: '(.deb、.rpm)',
|
||||
t('views.ne.neSoftware.fileTypeNotEq', {
|
||||
txt: '(.deb、.rpm)',
|
||||
}),
|
||||
3
|
||||
);
|
||||
@@ -286,8 +286,8 @@ function fnBeforeUploadFileDep(file: FileType) {
|
||||
const suff = fileName.substring(fileName.lastIndexOf('.'));
|
||||
if (!['.deb', '.rpm'].includes(suff)) {
|
||||
message.error(
|
||||
t('views.configManage.softwareManage.onlyAble', {
|
||||
fileText: '(.deb、.rpm)',
|
||||
t('views.ne.neSoftware.fileTypeNotEq', {
|
||||
txt: '(.deb、.rpm)',
|
||||
}),
|
||||
3
|
||||
);
|
||||
|
||||
@@ -565,8 +565,21 @@ function transformFormData(data: any) {
|
||||
smStaticIpArr.push(dnnParts);
|
||||
}
|
||||
if (!dnnParts.includes('/') && !dnnParts.includes(':')) {
|
||||
//IPV4 没有/ 也没有:
|
||||
smStaticIpArr.push(dnnParts);
|
||||
const pattern = /^(\d{1,3}\.){3}\d{1,3}$/;
|
||||
if (pattern.test(dnnParts)) {
|
||||
// 验证数值范围
|
||||
const isValid = dnnParts.split('.').every((num: any) => {
|
||||
const n = parseInt(num, 10);
|
||||
return n >= 0 && n <= 255;
|
||||
});
|
||||
|
||||
// 只有当验证通过时才添加 IP
|
||||
if (isValid) {
|
||||
smStaticIpArr.push(dnnParts);
|
||||
}
|
||||
} else {//无/ 无:也有可能为dnn的字符串
|
||||
smallRowJson.dnn += '-' + dnnParts;
|
||||
}
|
||||
}
|
||||
|
||||
if (dnnParts.includes('/') && !dnnParts.includes(':')) {
|
||||
@@ -655,8 +668,8 @@ function fnModalOk() {
|
||||
const result = from.id
|
||||
? updateUDMSub(from)
|
||||
: from.num === 1
|
||||
? addUDMSub(from)
|
||||
: batchAddUDMSub(from, from.num);
|
||||
? addUDMSub(from)
|
||||
: batchAddUDMSub(from, from.num);
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
result
|
||||
.then(res => {
|
||||
@@ -986,7 +999,7 @@ function fnGetList(pageNum?: number) {
|
||||
tableState.data = res.rows;
|
||||
if (
|
||||
tablePagination.total <=
|
||||
(queryParams.pageNum - 1) * tablePagination.pageSize &&
|
||||
(queryParams.pageNum - 1) * tablePagination.pageSize &&
|
||||
queryParams.pageNum !== 1
|
||||
) {
|
||||
tableState.loading = false;
|
||||
@@ -1161,22 +1174,14 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<PageContainer>
|
||||
<a-card
|
||||
v-show="tableState.seached"
|
||||
:bordered="false"
|
||||
:body-style="{ marginBottom: '24px', paddingBottom: 0 }"
|
||||
>
|
||||
<a-card v-show="tableState.seached" :bordered="false" :body-style="{ marginBottom: '24px', paddingBottom: 0 }">
|
||||
<!-- 表格搜索栏 -->
|
||||
<a-form :model="queryParams" name="queryParams" layout="horizontal">
|
||||
<a-row :gutter="16">
|
||||
<a-col :lg="6" :md="12" :xs="24">
|
||||
<a-form-item :label="t('views.neUser.sub.neType')" name="neId ">
|
||||
<a-select
|
||||
v-model:value="queryParams.neId"
|
||||
:options="neOtions"
|
||||
:placeholder="t('common.selectPlease')"
|
||||
@change="fnGetList(1)"
|
||||
/>
|
||||
<a-select v-model:value="queryParams.neId" :options="neOtions" :placeholder="t('common.selectPlease')"
|
||||
@change="fnGetList(1)" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
@@ -1204,12 +1209,8 @@ onMounted(() => {
|
||||
|
||||
<a-col :lg="8" :md="12" :xs="24">
|
||||
<a-form-item label="MSISDN" name="msisdn">
|
||||
<a-input
|
||||
v-model:value="queryParams.msisdn"
|
||||
allow-clear
|
||||
:maxlength="32"
|
||||
:placeholder="t('common.inputPlease')"
|
||||
></a-input>
|
||||
<a-input v-model:value="queryParams.msisdn" allow-clear :maxlength="32"
|
||||
:placeholder="t('common.inputPlease')"></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="6" :md="12" :xs="24">
|
||||
@@ -1257,31 +1258,16 @@ onMounted(() => {
|
||||
{{ t('common.addText') }}
|
||||
</a-button>
|
||||
|
||||
<a-button
|
||||
type="primary"
|
||||
danger
|
||||
ghost
|
||||
@click.prevent="fnModalVisibleByBatch()"
|
||||
>
|
||||
<a-button type="primary" danger ghost @click.prevent="fnModalVisibleByBatch()">
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
</template>
|
||||
{{ t('views.neUser.auth.batchDelText') }}
|
||||
</a-button>
|
||||
|
||||
<a-popconfirm
|
||||
:title="t('views.neUser.sub.loadDataConfirm')"
|
||||
:ok-text="t('common.ok')"
|
||||
:cancel-text="t('common.cancel')"
|
||||
:disabled="modalState.loadDataLoading"
|
||||
@confirm="fnLoadData"
|
||||
>
|
||||
<a-button
|
||||
type="dashed"
|
||||
danger
|
||||
:disabled="modalState.loadDataLoading"
|
||||
:loading="modalState.loadDataLoading"
|
||||
>
|
||||
<a-popconfirm :title="t('views.neUser.sub.loadDataConfirm')" :ok-text="t('common.ok')"
|
||||
:cancel-text="t('common.cancel')" :disabled="modalState.loadDataLoading" @confirm="fnLoadData">
|
||||
<a-button type="dashed" danger :disabled="modalState.loadDataLoading" :loading="modalState.loadDataLoading">
|
||||
<template #icon>
|
||||
<SyncOutlined />
|
||||
</template>
|
||||
@@ -1296,13 +1282,8 @@ onMounted(() => {
|
||||
{{ t('views.neUser.sub.import') }}
|
||||
</a-button>
|
||||
|
||||
<a-popconfirm
|
||||
:title="t('views.neUser.sub.exportConfirm')"
|
||||
placement="topRight"
|
||||
ok-text="TXT"
|
||||
ok-type="default"
|
||||
@confirm="fnExportList('txt')"
|
||||
>
|
||||
<a-popconfirm :title="t('views.neUser.sub.exportConfirm')" placement="topRight" ok-text="TXT"
|
||||
ok-type="default" @confirm="fnExportList('txt')">
|
||||
<a-button type="dashed">
|
||||
<template #icon>
|
||||
<ExportOutlined />
|
||||
@@ -1311,30 +1292,20 @@ onMounted(() => {
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
|
||||
<a-button
|
||||
type="default"
|
||||
danger
|
||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||
:loading="modalState.loadDataLoading"
|
||||
@click.prevent="fnRecordDelete('0')"
|
||||
>
|
||||
<template #icon><DeleteOutlined /></template>
|
||||
<a-button type="default" danger :disabled="tableState.selectedRowKeys.length <= 0"
|
||||
:loading="modalState.loadDataLoading" @click.prevent="fnRecordDelete('0')">
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
</template>
|
||||
{{ t('views.neUser.sub.checkDel') }}
|
||||
</a-button>
|
||||
|
||||
<a-popconfirm
|
||||
:title="t('views.neUser.sub.checkExportConfirm')"
|
||||
placement="topRight"
|
||||
ok-text="TXT"
|
||||
ok-type="default"
|
||||
@confirm="fnRecordExport('txt')"
|
||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||
>
|
||||
<a-button
|
||||
type="default"
|
||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||
>
|
||||
<template #icon><ExportOutlined /></template>
|
||||
<a-popconfirm :title="t('views.neUser.sub.checkExportConfirm')" placement="topRight" ok-text="TXT"
|
||||
ok-type="default" @confirm="fnRecordExport('txt')" :disabled="tableState.selectedRowKeys.length <= 0">
|
||||
<a-button type="default" :disabled="tableState.selectedRowKeys.length <= 0">
|
||||
<template #icon>
|
||||
<ExportOutlined />
|
||||
</template>
|
||||
{{ t('views.neUser.sub.checkExport') }}
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
@@ -1346,35 +1317,29 @@ onMounted(() => {
|
||||
<a-space :size="8" align="center">
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.searchBarText') }}</template>
|
||||
<a-switch
|
||||
v-model:checked="tableState.seached"
|
||||
:checked-children="t('common.switch.show')"
|
||||
:un-checked-children="t('common.switch.hide')"
|
||||
size="small"
|
||||
/>
|
||||
<a-switch v-model:checked="tableState.seached" :checked-children="t('common.switch.show')"
|
||||
:un-checked-children="t('common.switch.hide')" size="small" />
|
||||
</a-tooltip>
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.reloadText') }}</template>
|
||||
<a-button type="text" @click.prevent="fnGetList()">
|
||||
<template #icon><ReloadOutlined /></template>
|
||||
<template #icon>
|
||||
<ReloadOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<TableColumnsDnd
|
||||
cache-id="udmSubData"
|
||||
:columns="tableColumns"
|
||||
v-model:columns-dnd="tableColumnsDnd"
|
||||
></TableColumnsDnd>
|
||||
<TableColumnsDnd cache-id="udmSubData" :columns="tableColumns" v-model:columns-dnd="tableColumnsDnd">
|
||||
</TableColumnsDnd>
|
||||
<a-tooltip placement="topRight">
|
||||
<template #title>{{ t('common.sizeText') }}</template>
|
||||
<a-dropdown placement="bottomRight" trigger="click">
|
||||
<a-button type="text">
|
||||
<template #icon><ColumnHeightOutlined /></template>
|
||||
<template #icon>
|
||||
<ColumnHeightOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
<template #overlay>
|
||||
<a-menu
|
||||
:selected-keys="[tableState.size as string]"
|
||||
@click="fnTableSize"
|
||||
>
|
||||
<a-menu :selected-keys="[tableState.size as string]" @click="fnTableSize">
|
||||
<a-menu-item key="default">
|
||||
{{ t('common.size.default') }}
|
||||
</a-menu-item>
|
||||
@@ -1392,23 +1357,14 @@ onMounted(() => {
|
||||
</template>
|
||||
|
||||
<!-- 表格列表 -->
|
||||
<a-table
|
||||
class="table"
|
||||
row-key="imsi"
|
||||
:columns="tableColumnsDnd"
|
||||
:loading="tableState.loading"
|
||||
:data-source="tableState.data"
|
||||
:size="tableState.size"
|
||||
:pagination="tablePagination"
|
||||
:scroll="{ y: 'calc(100vh - 480px)' }"
|
||||
@change="fnTableChange"
|
||||
@resizeColumn="(w:number, col:any) => (col.width = w)"
|
||||
:row-selection="{
|
||||
<a-table class="table" row-key="imsi" :columns="tableColumnsDnd" :loading="tableState.loading"
|
||||
:data-source="tableState.data" :size="tableState.size" :pagination="tablePagination"
|
||||
:scroll="{ y: 'calc(100vh - 480px)' }" @change="fnTableChange"
|
||||
@resizeColumn="(w: number, col: any) => (col.width = w)" :row-selection="{
|
||||
type: 'checkbox',
|
||||
selectedRowKeys: tableState.selectedRowKeys,
|
||||
onChange: fnTableSelectedRowKeys,
|
||||
}"
|
||||
>
|
||||
}">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'cnFlag'">
|
||||
{{
|
||||
@@ -1428,10 +1384,7 @@ onMounted(() => {
|
||||
<a-space :size="8" align="center">
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.editText') }}</template>
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnModalVisibleByEdit(record.imsi)"
|
||||
>
|
||||
<a-button type="link" @click.prevent="fnModalVisibleByEdit(record.imsi)">
|
||||
<template #icon>
|
||||
<FormOutlined />
|
||||
</template>
|
||||
@@ -1439,10 +1392,7 @@ onMounted(() => {
|
||||
</a-tooltip>
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.deleteText') }}</template>
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordDelete(record.imsi)"
|
||||
>
|
||||
<a-button type="link" @click.prevent="fnRecordDelete(record.imsi)">
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
</template>
|
||||
@@ -1455,58 +1405,26 @@ onMounted(() => {
|
||||
</a-card>
|
||||
|
||||
<!-- 新增框或修改框 -->
|
||||
<ProModal
|
||||
:drag="true"
|
||||
:width="800"
|
||||
:destroyOnClose="true"
|
||||
style="top: 0px"
|
||||
:body-style="{ maxHeight: '600px', 'overflow-y': 'auto' }"
|
||||
: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"
|
||||
>
|
||||
<ProModal :drag="true" :width="800" :destroyOnClose="true" style="top: 0px"
|
||||
:body-style="{ maxHeight: '600px', 'overflow-y': 'auto' }" :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-row>
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.neUser.sub.numAdd')"
|
||||
name="num"
|
||||
v-bind="modalStateFrom.validateInfos.num"
|
||||
v-show="!modalState.from.id"
|
||||
>
|
||||
<a-input-number
|
||||
v-model:value="modalState.from.num"
|
||||
style="width: 100%"
|
||||
:min="1"
|
||||
:max="10000"
|
||||
placeholder="<=10000"
|
||||
></a-input-number>
|
||||
<a-form-item :label="t('views.neUser.sub.numAdd')" name="num" v-bind="modalStateFrom.validateInfos.num"
|
||||
v-show="!modalState.from.id">
|
||||
<a-input-number v-model:value="modalState.from.num" style="width: 100%" :min="1" :max="10000"
|
||||
placeholder="<=10000"></a-input-number>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-row>
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
label="IMSI"
|
||||
name="imsi"
|
||||
v-bind="modalStateFrom.validateInfos.imsi"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="modalState.from.imsi"
|
||||
allow-clear
|
||||
:maxlength="15"
|
||||
:disabled="!!modalState.from.id"
|
||||
>
|
||||
<a-form-item label="IMSI" name="imsi" v-bind="modalStateFrom.validateInfos.imsi">
|
||||
<a-input v-model:value="modalState.from.imsi" allow-clear :maxlength="15"
|
||||
:disabled="!!modalState.from.id">
|
||||
<template #prefix>
|
||||
<a-tooltip placement="topLeft">
|
||||
<template #title>
|
||||
@@ -1522,16 +1440,8 @@ onMounted(() => {
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
label="MSISDN"
|
||||
name="msisdn"
|
||||
v-bind="modalStateFrom.validateInfos.msisdn"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="modalState.from.msisdn"
|
||||
allow-clear
|
||||
:maxlength="32"
|
||||
>
|
||||
<a-form-item label="MSISDN" name="msisdn" v-bind="modalStateFrom.validateInfos.msisdn">
|
||||
<a-input v-model:value="modalState.from.msisdn" allow-clear :maxlength="32">
|
||||
<template #prefix>
|
||||
<a-tooltip placement="topLeft">
|
||||
<template #title>
|
||||
@@ -1545,49 +1455,24 @@ onMounted(() => {
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-form-item
|
||||
:label="t('common.remark')"
|
||||
:label-col="{ span: 3 }"
|
||||
:label-wrap="true"
|
||||
>
|
||||
<a-textarea
|
||||
v-model:value="modalState.from.remark"
|
||||
:auto-size="{ minRows: 1, maxRows: 6 }"
|
||||
:maxlength="500"
|
||||
:show-count="true"
|
||||
:placeholder="t('common.inputPlease')"
|
||||
/>
|
||||
<a-form-item :label="t('common.remark')" :label-col="{ span: 3 }" :label-wrap="true">
|
||||
<a-textarea v-model:value="modalState.from.remark" :auto-size="{ minRows: 1, maxRows: 6 }" :maxlength="500"
|
||||
:show-count="true" :placeholder="t('common.inputPlease')" />
|
||||
</a-form-item>
|
||||
|
||||
<!-- SM Data ---- S -->
|
||||
<a-divider orientation="left">
|
||||
Subscribed SM Data
|
||||
<a-tooltip title="Add SM Data">
|
||||
<a-button
|
||||
shape="circle"
|
||||
@click="addBigRow"
|
||||
style="margin-left: 10px"
|
||||
>
|
||||
<a-button shape="circle" @click="addBigRow" style="margin-left: 10px">
|
||||
<template #icon><plus-outlined /></template>
|
||||
</a-button> </a-tooltip
|
||||
></a-divider>
|
||||
</a-button> </a-tooltip></a-divider>
|
||||
<!-- 大数组布局 -->
|
||||
<div v-for="(row, index) in bigRows" :key="String(row.id)">
|
||||
<a-row>
|
||||
<a-col :lg="6" :md="6" :xs="24">
|
||||
<a-form-item
|
||||
label="SST"
|
||||
name="row.sst"
|
||||
:label-col="{ span: 12 }"
|
||||
:validateTrigger="[]"
|
||||
:required="true"
|
||||
>
|
||||
<a-input-number
|
||||
v-model:value="row.sst"
|
||||
:min="1"
|
||||
:max="3"
|
||||
:step="1"
|
||||
/>
|
||||
<a-form-item label="SST" name="row.sst" :label-col="{ span: 12 }" :validateTrigger="[]" :required="true">
|
||||
<a-input-number v-model:value="row.sst" :min="1" :max="3" :step="1" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
@@ -1600,7 +1485,7 @@ onMounted(() => {
|
||||
<a-row>
|
||||
<a-col :span="4">
|
||||
<a-tooltip title="Add DNN">
|
||||
<a-button shape="circle" @click="addSmallRow(row.id)">
|
||||
<a-button shape="circle" @click="addSmallRow(row.id)" style="margin-left:10px ;">
|
||||
<template #icon><plus-square-outlined /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
@@ -1617,46 +1502,27 @@ onMounted(() => {
|
||||
</a-row>
|
||||
|
||||
<!-- 小数组布局 -->
|
||||
<div
|
||||
v-for="(smallRow, smallIndex) in row.smallRows"
|
||||
:key="String(smallRow.id)"
|
||||
>
|
||||
<div v-for="(smallRow, smallIndex) in row.smallRows" :key="String(smallRow.id)">
|
||||
<a-row>
|
||||
<a-col :lg="6" :md="7" :xs="24">
|
||||
<a-form-item
|
||||
label="DNN/APN"
|
||||
name="dnn"
|
||||
:validateTrigger="[]"
|
||||
:required="true"
|
||||
:label-col="{ span: 12 }"
|
||||
>
|
||||
<a-col :lg="6" :md="6" :xs="24">
|
||||
<a-form-item label="DNN/APN" name="dnn" :validateTrigger="[]" :required="true"
|
||||
:label-col="{ span: 12 }">
|
||||
<a-input v-model:value="smallRow.dnn" allow-clear></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="8" :md="6" :xs="24">
|
||||
<a-form-item
|
||||
label="Static IP"
|
||||
name="smStaticIp"
|
||||
:label-col="{ span: 5 }"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="smallRow.smStaticIp"
|
||||
allow-clear
|
||||
></a-input>
|
||||
<a-col :lg="8" :md="8" :xs="24">
|
||||
<a-form-item label="Static IP" name="smStaticIp" :label-col="{ span: 5 }">
|
||||
<a-input v-model:value="smallRow.smStaticIp" allow-clear></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="8" :md="8" :xs="24">
|
||||
<a-form-item label="Routing Behind MS IP" name="msIp">
|
||||
<a-form-item label="Routing Behind MS IP" style="margin-left:10px ;" name="msIp">
|
||||
<a-input v-model:value="smallRow.msIp" allow-clear></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="1" :md="1" :xs="24" v-if="smallIndex !== 0">
|
||||
<a-col :lg="2" :md="2" :xs="24" v-if="smallIndex !== 0">
|
||||
<a-tooltip title="Delete DNN">
|
||||
<a-button
|
||||
danger
|
||||
shape="circle"
|
||||
@click="delDNN(smallIndex, row.id)"
|
||||
>
|
||||
<a-button danger shape="circle" @click="delDNN(smallIndex, row.id)" style="margin-left:10px ;">
|
||||
<template #icon><close-square-outlined /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
@@ -1673,11 +1539,7 @@ onMounted(() => {
|
||||
</template>
|
||||
<a-row>
|
||||
<a-col :lg="24" :md="24" :xs="24">
|
||||
<a-form-item
|
||||
label="5GC Flag"
|
||||
name="cnFlag"
|
||||
:help="t('views.neUser.sub.cnFlag')"
|
||||
>
|
||||
<a-form-item label="5GC Flag" name="cnFlag" :help="t('views.neUser.sub.cnFlag')">
|
||||
<a-select v-model:value="modalState.from.cnType">
|
||||
<a-select-option value="3">
|
||||
{{ t('views.neUser.sub.enable') }}
|
||||
@@ -1689,71 +1551,44 @@ onMounted(() => {
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="24" :md="24" :xs="24">
|
||||
<a-form-item
|
||||
label="5G Subscribed UE AMBR Template"
|
||||
name="ambr"
|
||||
v-bind="modalStateFrom.validateInfos.ambr"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="modalState.from.ambr"
|
||||
allow-clear
|
||||
:maxlength="50"
|
||||
>
|
||||
<a-form-item label="5G Subscribed UE AMBR Template" name="ambr"
|
||||
v-bind="modalStateFrom.validateInfos.ambr">
|
||||
<a-input v-model:value="modalState.from.ambr" allow-clear :maxlength="50">
|
||||
<template #prefix>
|
||||
<a-tooltip placement="topLeft">
|
||||
<template #title>
|
||||
{{ t('views.neUser.sub.inputTip', { num: '50' }) }}
|
||||
</template>
|
||||
<InfoCircleOutlined
|
||||
style="opacity: 0.45; color: inherit"
|
||||
/>
|
||||
<InfoCircleOutlined style="opacity: 0.45; color: inherit" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="24" :md="24" :xs="24">
|
||||
<a-form-item
|
||||
label="5G Subscribed SNSSAIs Template"
|
||||
name="nssai"
|
||||
v-bind="modalStateFrom.validateInfos.nssai"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="modalState.from.nssai"
|
||||
allow-clear
|
||||
:maxlength="50"
|
||||
>
|
||||
<a-form-item label="5G Subscribed SNSSAIs Template" name="nssai"
|
||||
v-bind="modalStateFrom.validateInfos.nssai">
|
||||
<a-input v-model:value="modalState.from.nssai" allow-clear :maxlength="50">
|
||||
<template #prefix>
|
||||
<a-tooltip placement="topLeft">
|
||||
<template #title>
|
||||
{{ t('views.neUser.sub.inputTip', { num: '50' }) }}
|
||||
</template>
|
||||
<InfoCircleOutlined
|
||||
style="opacity: 0.45; color: inherit"
|
||||
/>
|
||||
<InfoCircleOutlined style="opacity: 0.45; color: inherit" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="24" :md="24" :xs="24">
|
||||
<a-form-item
|
||||
label="5G Subscribed SMF Selection Data Template"
|
||||
name="smfSel"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="modalState.from.smfSel"
|
||||
allow-clear
|
||||
:maxlength="50"
|
||||
>
|
||||
<a-form-item label="5G Subscribed SMF Selection Data Template" name="smfSel">
|
||||
<a-input v-model:value="modalState.from.smfSel" allow-clear :maxlength="50">
|
||||
<template #prefix>
|
||||
<a-tooltip placement="topLeft">
|
||||
<template #title>
|
||||
{{ t('views.neUser.sub.inputTip', { num: '50' }) }}
|
||||
</template>
|
||||
<InfoCircleOutlined
|
||||
style="opacity: 0.45; color: inherit"
|
||||
/>
|
||||
<InfoCircleOutlined style="opacity: 0.45; color: inherit" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-input>
|
||||
@@ -1761,77 +1596,48 @@ onMounted(() => {
|
||||
</a-col>
|
||||
<a-col :lg="24" :md="24" :xs="24">
|
||||
<a-form-item label="5G Forbidden Areas Template" name="arfb">
|
||||
<a-input
|
||||
v-model:value="modalState.from.arfb"
|
||||
allow-clear
|
||||
:maxlength="50"
|
||||
>
|
||||
<a-input v-model:value="modalState.from.arfb" allow-clear :maxlength="50">
|
||||
<template #prefix>
|
||||
<a-tooltip placement="topLeft">
|
||||
<template #title>
|
||||
{{ t('views.neUser.sub.arfbTip') }}
|
||||
</template>
|
||||
<InfoCircleOutlined
|
||||
style="opacity: 0.45; color: inherit"
|
||||
/>
|
||||
<InfoCircleOutlined style="opacity: 0.45; color: inherit" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="24" :md="24" :xs="24">
|
||||
<a-form-item
|
||||
label="5G CAG Template"
|
||||
name="cag"
|
||||
v-bind="modalStateFrom.validateInfos.cag"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="modalState.from.cag"
|
||||
allow-clear
|
||||
:maxlength="50"
|
||||
>
|
||||
<a-form-item label="5G CAG Template" name="cag" v-bind="modalStateFrom.validateInfos.cag">
|
||||
<a-input v-model:value="modalState.from.cag" allow-clear :maxlength="50">
|
||||
<template #prefix>
|
||||
<a-tooltip placement="topLeft">
|
||||
<template #title>
|
||||
{{ t('views.neUser.sub.inputTip', { num: '50' }) }}
|
||||
</template>
|
||||
<InfoCircleOutlined
|
||||
style="opacity: 0.45; color: inherit"
|
||||
/>
|
||||
<InfoCircleOutlined style="opacity: 0.45; color: inherit" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="24" :md="24" :xs="24">
|
||||
<a-form-item
|
||||
label="5G Service Area Restriction Template"
|
||||
name="sar"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="modalState.from.sar"
|
||||
allow-clear
|
||||
:maxlength="50"
|
||||
>
|
||||
<a-form-item label="5G Service Area Restriction Template" name="sar">
|
||||
<a-input v-model:value="modalState.from.sar" allow-clear :maxlength="50">
|
||||
<template #prefix>
|
||||
<a-tooltip placement="topLeft">
|
||||
<template #title>
|
||||
{{ t('views.neUser.sub.sarTip') }}
|
||||
</template>
|
||||
<InfoCircleOutlined
|
||||
style="opacity: 0.45; color: inherit"
|
||||
/>
|
||||
<InfoCircleOutlined style="opacity: 0.45; color: inherit" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="24" :md="24" :xs="24">
|
||||
<a-form-item
|
||||
label="5G MICO Mode"
|
||||
name="mico"
|
||||
:help="t('views.neUser.sub.micoTip')"
|
||||
>
|
||||
<a-form-item label="5G MICO Mode" name="mico" :help="t('views.neUser.sub.micoTip')">
|
||||
<a-select v-model:value="modalState.from.mico">
|
||||
<a-select-option value="1">
|
||||
{{ t('views.neUser.sub.enable') }}
|
||||
@@ -1854,21 +1660,14 @@ onMounted(() => {
|
||||
</a-col>
|
||||
<a-col :lg="24" :md="24" :xs="24">
|
||||
<a-form-item label="5G UE Usage Type" name="ueUsageType">
|
||||
<a-input-number
|
||||
v-model:value="modalState.from.ueUsageType"
|
||||
style="width: 100%"
|
||||
:min="0"
|
||||
:max="127"
|
||||
placeholder="0 ~ 127"
|
||||
>
|
||||
<a-input-number v-model:value="modalState.from.ueUsageType" style="width: 100%" :min="0" :max="127"
|
||||
placeholder="0 ~ 127">
|
||||
<template #prefix>
|
||||
<a-tooltip placement="topLeft">
|
||||
<template #title>
|
||||
{{ t('views.neUser.sub.ueTypeTip') }}
|
||||
</template>
|
||||
<InfoCircleOutlined
|
||||
style="opacity: 0.45; color: inherit"
|
||||
/>
|
||||
<InfoCircleOutlined style="opacity: 0.45; color: inherit" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-input-number>
|
||||
@@ -1876,21 +1675,14 @@ onMounted(() => {
|
||||
</a-col>
|
||||
<a-col :lg="24" :md="24" :xs="24">
|
||||
<a-form-item label="5G RFSP Index" name="rfspIndex">
|
||||
<a-input-number
|
||||
v-model:value="modalState.from.rfspIndex"
|
||||
style="width: 100%"
|
||||
:min="0"
|
||||
:max="127"
|
||||
placeholder="0 ~ 127"
|
||||
>
|
||||
<a-input-number v-model:value="modalState.from.rfspIndex" style="width: 100%" :min="0" :max="127"
|
||||
placeholder="0 ~ 127">
|
||||
<template #prefix>
|
||||
<a-tooltip placement="topLeft">
|
||||
<template #title>
|
||||
{{ t('views.neUser.sub.rfspTip') }}
|
||||
</template>
|
||||
<InfoCircleOutlined
|
||||
style="opacity: 0.45; color: inherit"
|
||||
/>
|
||||
<InfoCircleOutlined style="opacity: 0.45; color: inherit" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-input-number>
|
||||
@@ -1905,11 +1697,7 @@ onMounted(() => {
|
||||
</template>
|
||||
<a-row>
|
||||
<a-col :lg="24" :md="24" :xs="24">
|
||||
<a-form-item
|
||||
label="4G EPS Flag"
|
||||
name="epsFlag"
|
||||
:help="t('views.neUser.sub.epsFlagTip')"
|
||||
>
|
||||
<a-form-item label="4G EPS Flag" name="epsFlag" :help="t('views.neUser.sub.epsFlagTip')">
|
||||
<a-select v-model:value="modalState.from.epsFlag">
|
||||
<a-select-option value="1">
|
||||
{{ t('views.neUser.sub.enable') }}
|
||||
@@ -1921,24 +1709,15 @@ onMounted(() => {
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="24" :md="24" :xs="24">
|
||||
<a-form-item
|
||||
label="4G EPS User Template Name"
|
||||
name="epstpl"
|
||||
v-bind="modalStateFrom.validateInfos.epstpl"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="modalState.from.epstpl"
|
||||
allow-clear
|
||||
:maxlength="50"
|
||||
>
|
||||
<a-form-item label="4G EPS User Template Name" name="epstpl"
|
||||
v-bind="modalStateFrom.validateInfos.epstpl">
|
||||
<a-input v-model:value="modalState.from.epstpl" allow-clear :maxlength="50">
|
||||
<template #prefix>
|
||||
<a-tooltip placement="topLeft">
|
||||
<template #title>
|
||||
{{ t('views.neUser.sub.inputTip', { num: '50' }) }}
|
||||
</template>
|
||||
<InfoCircleOutlined
|
||||
style="opacity: 0.45; color: inherit"
|
||||
/>
|
||||
<InfoCircleOutlined style="opacity: 0.45; color: inherit" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-input>
|
||||
@@ -1947,20 +1726,14 @@ onMounted(() => {
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col :lg="24" :md="24" :xs="24">
|
||||
<a-form-item
|
||||
label="4G Static IP"
|
||||
v-bind="modalStateFrom.validateInfos.staticIp"
|
||||
name="staticIp"
|
||||
>
|
||||
<a-form-item label="4G Static IP" v-bind="modalStateFrom.validateInfos.staticIp" name="staticIp">
|
||||
<a-input v-model:value="modalState.from.staticIp" allow-clear>
|
||||
<template #prefix>
|
||||
<a-tooltip placement="topLeft">
|
||||
<template #title>
|
||||
{{ t('views.neUser.sub.staticIpTip') }}
|
||||
</template>
|
||||
<InfoCircleOutlined
|
||||
style="opacity: 0.45; color: inherit"
|
||||
/>
|
||||
<InfoCircleOutlined style="opacity: 0.45; color: inherit" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-input>
|
||||
@@ -1980,73 +1753,33 @@ onMounted(() => {
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
label="4G APN Context List"
|
||||
name="apnContext"
|
||||
:help="t('views.neUser.sub.apnContextTip')"
|
||||
>
|
||||
<a-form-item label="4G APN Context List" name="apnContext" :help="t('views.neUser.sub.apnContextTip')">
|
||||
<a-input-group compact>
|
||||
<a-input-number
|
||||
v-for="(_, i) in modalState.from.apnContext"
|
||||
:key="i"
|
||||
:title="i"
|
||||
style="width: 16.5%"
|
||||
:min="0"
|
||||
:max="99"
|
||||
v-model:value="modalState.from.apnContext[i]"
|
||||
></a-input-number>
|
||||
<a-input-number v-for="(_, i) in modalState.from.apnContext" :key="i" :title="i" style="width: 16.5%"
|
||||
:min="0" :max="99" v-model:value="modalState.from.apnContext[i]"></a-input-number>
|
||||
</a-input-group>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
label="4G EPS ODB"
|
||||
name="epsOdb"
|
||||
v-bind="modalStateFrom.validateInfos.epsOdb"
|
||||
>
|
||||
<a-tooltip
|
||||
:title="t('views.neUser.sub.epsOdbTip')"
|
||||
placement="topLeft"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="modalState.from.epsOdb"
|
||||
mode="multiple"
|
||||
style="width: 100%"
|
||||
placeholder="Please select"
|
||||
:options="modalStateFromOption.odbJson"
|
||||
@change=""
|
||||
>
|
||||
<a-form-item label="4G EPS ODB" name="epsOdb" v-bind="modalStateFrom.validateInfos.epsOdb">
|
||||
<a-tooltip :title="t('views.neUser.sub.epsOdbTip')" placement="topLeft">
|
||||
<a-select v-model:value="modalState.from.epsOdb" mode="multiple" style="width: 100%"
|
||||
placeholder="Please select" :options="modalStateFromOption.odbJson" @change="">
|
||||
</a-select>
|
||||
</a-tooltip>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="4G HPLMN ODB" name="hplmnOdb">
|
||||
<a-tooltip
|
||||
:title="t('views.neUser.sub.hplmnOdbTip')"
|
||||
placement="topLeft"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="modalState.from.hplmnOdb"
|
||||
mode="multiple"
|
||||
style="width: 100%"
|
||||
:options="modalStateFromOption.hplmnOdb"
|
||||
@change=""
|
||||
>
|
||||
<a-tooltip :title="t('views.neUser.sub.hplmnOdbTip')" placement="topLeft">
|
||||
<a-select v-model:value="modalState.from.hplmnOdb" mode="multiple" style="width: 100%"
|
||||
:options="modalStateFromOption.hplmnOdb" @change="">
|
||||
</a-select>
|
||||
</a-tooltip>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="4G Access Restriction Data" name="ard">
|
||||
<a-tooltip
|
||||
:title="t('views.neUser.sub.ardTip')"
|
||||
placement="topLeft"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="modalState.from.ard"
|
||||
mode="multiple"
|
||||
style="width: 100%"
|
||||
:options="modalStateFromOption.ardJson"
|
||||
@change=""
|
||||
>
|
||||
<a-tooltip :title="t('views.neUser.sub.ardTip')" placement="topLeft">
|
||||
<a-select v-model:value="modalState.from.ard" mode="multiple" style="width: 100%"
|
||||
:options="modalStateFromOption.ardJson" @change="">
|
||||
</a-select>
|
||||
</a-tooltip>
|
||||
</a-form-item>
|
||||
@@ -2056,36 +1789,15 @@ onMounted(() => {
|
||||
</ProModal>
|
||||
|
||||
<!-- 批量删除框 -->
|
||||
<ProModal
|
||||
:drag="true"
|
||||
:destroyOnClose="true"
|
||||
style="top: 0px"
|
||||
:keyboard="false"
|
||||
:mask-closable="false"
|
||||
:open="modalState.openByBatchDel"
|
||||
:title="modalState.title"
|
||||
:confirm-loading="modalState.confirmLoading"
|
||||
@ok="fnBatchDelModalOk"
|
||||
@cancel="fnBatchDelModalCancel"
|
||||
>
|
||||
<a-form
|
||||
name="modalStateBatchDelFrom"
|
||||
layout="horizontal"
|
||||
:label-col="{ span: 6 }"
|
||||
:labelWrap="true"
|
||||
>
|
||||
<ProModal :drag="true" :destroyOnClose="true" style="top: 0px" :keyboard="false" :mask-closable="false"
|
||||
:open="modalState.openByBatchDel" :title="modalState.title" :confirm-loading="modalState.confirmLoading"
|
||||
@ok="fnBatchDelModalOk" @cancel="fnBatchDelModalCancel">
|
||||
<a-form name="modalStateBatchDelFrom" layout="horizontal" :label-col="{ span: 6 }" :labelWrap="true">
|
||||
<a-row>
|
||||
<a-col :lg="24" :md="24" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.neUser.sub.startIMSI')"
|
||||
name="imsi"
|
||||
v-bind="modalStateBatchDelFrom.validateInfos.imsi"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="modalState.BatchDelForm.imsi"
|
||||
allow-clear
|
||||
:maxlength="15"
|
||||
>
|
||||
<a-form-item :label="t('views.neUser.sub.startIMSI')" name="imsi"
|
||||
v-bind="modalStateBatchDelFrom.validateInfos.imsi">
|
||||
<a-input v-model:value="modalState.BatchDelForm.imsi" allow-clear :maxlength="15">
|
||||
<template #prefix>
|
||||
<a-tooltip placement="topLeft">
|
||||
<template #title>
|
||||
@@ -2101,18 +1813,10 @@ onMounted(() => {
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="24" :md="24" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.neUser.sub.numDel')"
|
||||
name="num"
|
||||
v-bind="modalStateBatchDelFrom.validateInfos.num"
|
||||
>
|
||||
<a-input-number
|
||||
v-model:value="modalState.BatchDelForm.num"
|
||||
style="width: 100%"
|
||||
:min="1"
|
||||
:max="10000"
|
||||
placeholder="<=10000"
|
||||
></a-input-number>
|
||||
<a-form-item :label="t('views.neUser.sub.numDel')" name="num"
|
||||
v-bind="modalStateBatchDelFrom.validateInfos.num">
|
||||
<a-input-number v-model:value="modalState.BatchDelForm.num" style="width: 100%" :min="1" :max="10000"
|
||||
placeholder="<=10000"></a-input-number>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
@@ -2120,23 +1824,12 @@ onMounted(() => {
|
||||
</ProModal>
|
||||
|
||||
<!-- 上传导入表格数据文件框 -->
|
||||
<UploadModal
|
||||
:title="uploadImportState.title"
|
||||
:loading="uploadImportState.loading"
|
||||
@upload="fnModalUploadImportUpload"
|
||||
@close="fnModalUploadImportClose"
|
||||
v-model:open="uploadImportState.open"
|
||||
:ext="['.txt']"
|
||||
:size="10"
|
||||
>
|
||||
<UploadModal :title="uploadImportState.title" :loading="uploadImportState.loading"
|
||||
@upload="fnModalUploadImportUpload" @close="fnModalUploadImportClose" v-model:open="uploadImportState.open"
|
||||
:ext="['.txt']" :size="10">
|
||||
<template #default>
|
||||
<a-textarea
|
||||
:disabled="true"
|
||||
:hidden="!uploadImportState.msg"
|
||||
:value="uploadImportState.msg"
|
||||
:auto-size="{ minRows: 2, maxRows: 8 }"
|
||||
style="background-color: transparent; color: rgba(0, 0, 0, 0.85)"
|
||||
/>
|
||||
<a-textarea :disabled="true" :hidden="!uploadImportState.msg" :value="uploadImportState.msg"
|
||||
:auto-size="{ minRows: 2, maxRows: 8 }" style="background-color: transparent; color: rgba(0, 0, 0, 0.85)" />
|
||||
</template>
|
||||
</UploadModal>
|
||||
</PageContainer>
|
||||
|
||||
@@ -387,8 +387,10 @@ function fnModalOk() {
|
||||
message.error(t('views.perfManage.customTarget.expressionNoIdTip'), 3);
|
||||
return false;
|
||||
}
|
||||
modalState.from.expression = result;
|
||||
const from = toRaw(modalState.from);
|
||||
//modalState.from.expression = result;
|
||||
//const from = toRaw(modalState.from);
|
||||
const from = { ...toRaw(modalState.from) };
|
||||
from.expression = result;
|
||||
//return false;
|
||||
modalState.confirmLoading = true;
|
||||
const perfTask = from.id ? updateCustom(from) : addCustom(from);
|
||||
|
||||
@@ -391,9 +391,7 @@ function fnRecordRun(row: Record<string, any>) {
|
||||
threRun(row).then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
message.success({
|
||||
content: t('common.msgSuccess', {
|
||||
msg: t('views.configManage.softwareManage.runBtn'),
|
||||
}),
|
||||
content: 'Run',
|
||||
key,
|
||||
duration: 2,
|
||||
});
|
||||
@@ -610,7 +608,7 @@ onMounted(() => {
|
||||
<a-space :size="8" align="center">
|
||||
<a-tooltip>
|
||||
<template #title>
|
||||
{{ t('views.configManage.softwareManage.runBtn') }}
|
||||
Run
|
||||
</template>
|
||||
<a-button
|
||||
type="link"
|
||||
|
||||
@@ -616,9 +616,7 @@ function fnRecordRun(row: Record<string, any>) {
|
||||
taskRun(row).then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
message.success({
|
||||
content: t('common.msgSuccess', {
|
||||
msg: t('views.configManage.softwareManage.runBtn'),
|
||||
}),
|
||||
content: 'Run',
|
||||
key,
|
||||
duration: 2,
|
||||
});
|
||||
@@ -861,7 +859,7 @@ onMounted(() => {
|
||||
>
|
||||
<a-menu-item key="run">
|
||||
<ThunderboltOutlined />
|
||||
{{ t('views.configManage.softwareManage.runBtn') }}
|
||||
Run
|
||||
</a-menu-item>
|
||||
<a-menu-item key="stop">
|
||||
<UndoOutlined />
|
||||
|
||||
@@ -230,7 +230,7 @@ function fnNeTypeChange(v: any, data: any) {
|
||||
function fnModalVisibleByEdit(record?: any) {
|
||||
if (!record) {
|
||||
//modalStateFrom.resetFields();
|
||||
modalState.title = t('views.configManage.neManage.addNe');
|
||||
modalState.title = t('views.ne.neInfo.addTitle');
|
||||
const neId = `${new Date().getMilliseconds()}`.padStart(3, '0');
|
||||
modalState.from = {
|
||||
id: undefined,
|
||||
@@ -287,7 +287,7 @@ function fnModalVisibleByEdit(record?: any) {
|
||||
hide();
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
Object.assign(modalState.from, res.data);
|
||||
modalState.title = t('views.configManage.neManage.editNe');
|
||||
modalState.title = t('views.ne.neInfo.editTitle');
|
||||
modalState.openByEdit = true;
|
||||
} else {
|
||||
message.error(t('common.getInfoFail'), 2);
|
||||
|
||||
Reference in New Issue
Block a user