Compare commits
138 Commits
2.2407.1-2
...
2.2409.4-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3a452cfd8 | ||
|
|
d81b8cdf38 | ||
|
|
39a417368a | ||
|
|
adfce5d2f7 | ||
|
|
977286d6b3 | ||
|
|
c33000045a | ||
|
|
b995ac378a | ||
|
|
6bea64f345 | ||
|
|
94886e255e | ||
|
|
45f66afe52 | ||
|
|
b9105c1e77 | ||
|
|
909d306942 | ||
|
|
f7273457e9 | ||
|
|
2e5ad2f65d | ||
|
|
776e9c5837 | ||
|
|
0d4979d3d9 | ||
|
|
686c7dd273 | ||
|
|
d41b308c6d | ||
|
|
84dac247d2 | ||
|
|
f8439bb40a | ||
|
|
d268d920e7 | ||
|
|
f730ef1e3a | ||
|
|
af1ce32063 | ||
|
|
678ff2d09d | ||
|
|
48f674b6ef | ||
|
|
02f0820a69 | ||
|
|
ca8605fd6e | ||
|
|
6d5e96421b | ||
|
|
bcc29007bf | ||
|
|
bdf904078d | ||
|
|
e37cfa5066 | ||
|
|
f1bff23bbc | ||
|
|
53106ddb5c | ||
|
|
3a04882fe5 | ||
|
|
19202a5e81 | ||
|
|
7b311ff673 | ||
|
|
9dba98e0ee | ||
|
|
71338670f0 | ||
|
|
7dcdfabce2 | ||
|
|
ddfe1723c9 | ||
|
|
57b5f76db7 | ||
|
|
9ac3524877 | ||
|
|
ca82a0a74b | ||
|
|
23007c3bf2 | ||
|
|
5d69d7612a | ||
|
|
ddd8930af4 | ||
|
|
757f2ec20a | ||
|
|
30caa79424 | ||
|
|
e3f83a0b98 | ||
|
|
147a3ed77b | ||
|
|
5d35d950b3 | ||
|
|
6874508d3f | ||
|
|
33f468209a | ||
|
|
e8ef2816df | ||
|
|
e38d7bbffa | ||
|
|
2f1265c47a | ||
|
|
66b6b60505 | ||
|
|
249d14320d | ||
|
|
313b90ad31 | ||
|
|
2ebc90e974 | ||
|
|
640257dd55 | ||
|
|
c1a3ce8068 | ||
|
|
0080e9c26e | ||
|
|
2ccafe622d | ||
|
|
d7a515ed9a | ||
| cd82b71b77 | |||
|
|
9d6a7dcd9c | ||
|
|
46c2affcc8 | ||
|
|
3d00a80588 | ||
|
|
a3c1fe154f | ||
|
|
07dce5a27e | ||
|
|
255cf026a6 | ||
|
|
840ea56c42 | ||
|
|
09917cc9c9 | ||
|
|
4c9fe192f2 | ||
|
|
32ec55d44e | ||
|
|
527cf89d1a | ||
|
|
ac7b57c0ae | ||
|
|
8be1a8968e | ||
|
|
999ccf64ad | ||
|
|
03352f3aa8 | ||
|
|
61a58fc661 | ||
|
|
4268fa3198 | ||
|
|
f6b62c6c7e | ||
|
|
b4cbc1c190 | ||
|
|
1871f6f656 | ||
|
|
409f9836a6 | ||
|
|
b3f40ee683 | ||
|
|
aa07b51663 | ||
|
|
19b77ed005 | ||
|
|
06503fd079 | ||
|
|
2321dacd2a | ||
|
|
a8b4e91b95 | ||
|
|
a5075bef43 | ||
|
|
f4ffbc1c86 | ||
|
|
6cafa284c7 | ||
|
|
049c0e7a0f | ||
|
|
377ffc6e10 | ||
|
|
858431e86e | ||
|
|
70fca5ca41 | ||
|
|
e972d14a9a | ||
|
|
c1187383b6 | ||
|
|
8d8605e0cd | ||
|
|
8af48936e5 | ||
|
|
e21a8dc898 | ||
|
|
3c1ee63359 | ||
|
|
bc3940016a | ||
|
|
6ab4fbea6f | ||
|
|
c73fcbd91c | ||
|
|
023e317b0d | ||
|
|
543a2b7434 | ||
|
|
4ae9051411 | ||
|
|
532546c3f5 | ||
|
|
ab0d26513c | ||
|
|
8e9498ec83 | ||
|
|
ca048f223c | ||
|
|
e9ff6493dd | ||
|
|
396fb0b124 | ||
|
|
3a854be8fe | ||
|
|
c1f34f56ac | ||
|
|
b80bae0126 | ||
|
|
6c383b58c8 | ||
|
|
06db1344c3 | ||
|
|
fac47279b5 | ||
|
|
a36a12f783 | ||
|
|
acd19ebdbd | ||
|
|
d53c4c34f0 | ||
|
|
2d9011cf6b | ||
|
|
fcf53d0995 | ||
|
|
a2d93ddafe | ||
|
|
79920542c1 | ||
|
|
6efd9cb61a | ||
|
|
4dc6699974 | ||
|
|
3bdae264e1 | ||
|
|
9e0a99d160 | ||
|
|
5ac0ca41eb | ||
|
|
a7de701d4d | ||
|
|
f0561242ca |
@@ -5,13 +5,13 @@ VITE_HISTORY_HASH = false
|
|||||||
VITE_HISTORY_BASE_URL = "/"
|
VITE_HISTORY_BASE_URL = "/"
|
||||||
|
|
||||||
# 应用名称
|
# 应用名称
|
||||||
VITE_APP_NAME = "Core Network EMS"
|
VITE_APP_NAME = "Core Network OMC"
|
||||||
|
|
||||||
# 应用标识
|
# 应用标识
|
||||||
VITE_APP_CODE = "CN EMS"
|
VITE_APP_CODE = "OMC"
|
||||||
|
|
||||||
# 应用版本
|
# 应用版本
|
||||||
VITE_APP_VERSION = "2.240704"
|
VITE_APP_VERSION = "2.240927"
|
||||||
|
|
||||||
# 接口基础URL地址-不带/后缀
|
# 接口基础URL地址-不带/后缀
|
||||||
VITE_API_BASE_URL = "/omc-api"
|
VITE_API_BASE_URL = "/omc-api"
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ VITE_HISTORY_HASH = true
|
|||||||
VITE_HISTORY_BASE_URL = "/"
|
VITE_HISTORY_BASE_URL = "/"
|
||||||
|
|
||||||
# 应用名称
|
# 应用名称
|
||||||
VITE_APP_NAME = "Core Network EMS"
|
VITE_APP_NAME = "Core Network OMC"
|
||||||
|
|
||||||
# 应用标识
|
# 应用标识
|
||||||
VITE_APP_CODE = "CN EMS"
|
VITE_APP_CODE = "OMC"
|
||||||
|
|
||||||
# 应用版本
|
# 应用版本
|
||||||
VITE_APP_VERSION = "2.240704"
|
VITE_APP_VERSION = "2.240927"
|
||||||
|
|
||||||
# 接口基础URL地址-不带/后缀
|
# 接口基础URL地址-不带/后缀
|
||||||
VITE_API_BASE_URL = "/omc-api"
|
VITE_API_BASE_URL = "/omc-api"
|
||||||
|
|||||||
19
README.md
19
README.md
@@ -8,14 +8,8 @@
|
|||||||
## 测试环境
|
## 测试环境
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Jenkins: http://192.168.2.166:3185/
|
|
||||||
Nginx: http://192.168.2.166:3188/#/index
|
Nginx: http://192.168.2.166:3188/#/index
|
||||||
后端暴露端口: http://192.168.2.166:33030
|
后端暴露端口: http://192.168.2.166:33030
|
||||||
|
|
||||||
|
|
||||||
新网管:192.168.5.13
|
|
||||||
旧网管:192.168.5.14
|
|
||||||
登录账户:manager/manager
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 程序命令
|
## 程序命令
|
||||||
@@ -59,16 +53,5 @@ export NODE_OPTIONS=--max-old-space-size=50000
|
|||||||
|
|
||||||
```text
|
```text
|
||||||
https://192.168.5.23/
|
https://192.168.5.23/
|
||||||
admin
|
admin / admin
|
||||||
admin
|
|
||||||
```
|
|
||||||
|
|
||||||
## k8s
|
|
||||||
|
|
||||||
master 192.168.5.27 agtuser/admin123
|
|
||||||
|
|
||||||
https://192.168.5.27:31325/#/workloads?namespace=default
|
|
||||||
|
|
||||||
```text
|
|
||||||
eyJhbGciOiJSUzI1NiIsImtpZCI6ImZFVUhIb1puLW04M1dfSUYyRU8zWlZueXBpNUh4T0hTRVlzU19jNlVGQ0kifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi11c2VyLXRva2VuLW44ZzRtIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImFkbWluLXVzZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI2M2NmYjAyNS01ZmQ0LTQ0ZTgtOTdiNC0yYWRiYWIxNzc5M2MiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZXJuZXRlcy1kYXNoYm9hcmQ6YWRtaW4tdXNlciJ9.R3GRygFOjngTj-mEMBAHDeBxm3lpsXZYvC6cdTxByONtLrcMXDebwNVeKtAZ1V9qh2OrjD8n9CIygjULGPdfV6S520vjMh7Oa2q68nOyW49DNWQyYD8xLo-dQ6sX07fI7X_I3H35YUWW80jJAXjJawqIGXBSMG5intlo4tLTUSXmjCfhoQvFsgeRWu0j76pDvhMAvLPcgEXfTCi9tyL3yqJBIKONcKwmMlJeaKSR3pQk3KiibqrBO0MZclRozpke6J0ulfzTemwDDyCqBZmLsRPZ2yDd5hVBIJ9bHEcK0a25NmSFFzmd8XWQPZwg3Y4IbbY-8UhByGq0p9xS-7pGCQ
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"@codemirror/lang-yaml": "^6.1.1",
|
"@codemirror/lang-yaml": "^6.1.1",
|
||||||
"@codemirror/merge": "^6.6.3",
|
"@codemirror/merge": "^6.6.3",
|
||||||
"@codemirror/theme-one-dark": "^6.1.2",
|
"@codemirror/theme-one-dark": "^6.1.2",
|
||||||
"@tato30/vue-pdf": "~1.9.7",
|
"@tato30/vue-pdf": "^1.10.0",
|
||||||
"@vueuse/core": "~10.10.1",
|
"@vueuse/core": "~10.10.1",
|
||||||
"@xterm/addon-fit": "^0.10.0",
|
"@xterm/addon-fit": "^0.10.0",
|
||||||
"@xterm/xterm": "^5.5.0",
|
"@xterm/xterm": "^5.5.0",
|
||||||
@@ -26,10 +26,11 @@
|
|||||||
"antdv-pro-layout": "~3.3.5",
|
"antdv-pro-layout": "~3.3.5",
|
||||||
"antdv-pro-modal": "^3.1.0",
|
"antdv-pro-modal": "^3.1.0",
|
||||||
"codemirror": "^6.0.1",
|
"codemirror": "^6.0.1",
|
||||||
|
"crypto-js": "^4.2.0",
|
||||||
"dayjs": "^1.11.11",
|
"dayjs": "^1.11.11",
|
||||||
"echarts": "~5.5.0",
|
"echarts": "~5.5.0",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"intl-tel-input": "~23.0.12",
|
"intl-tel-input": "^23.8.1",
|
||||||
"js-base64": "^3.7.7",
|
"js-base64": "^3.7.7",
|
||||||
"js-cookie": "^3.0.5",
|
"js-cookie": "^3.0.5",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
@@ -43,6 +44,7 @@
|
|||||||
"xlsx": "~0.18.5"
|
"xlsx": "~0.18.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/crypto-js": "^4.2.2",
|
||||||
"@types/file-saver": "^2.0.7",
|
"@types/file-saver": "^2.0.7",
|
||||||
"@types/js-cookie": "^3.0.6",
|
"@types/js-cookie": "^3.0.6",
|
||||||
"@types/node": "^18.0.0",
|
"@types/node": "^18.0.0",
|
||||||
|
|||||||
@@ -11,7 +11,8 @@
|
|||||||
*/
|
*/
|
||||||
(function () {
|
(function () {
|
||||||
// host = ip:port
|
// host = ip:port
|
||||||
const host = '192.168.8.100:33030';
|
// const host = '192.168.8.100:33030';
|
||||||
|
const host = `${window.location.hostname}:33030`;
|
||||||
|
|
||||||
// Service Address
|
// Service Address
|
||||||
sessionStorage.setItem('baseUrl', `http://${host}`);
|
sessionStorage.setItem('baseUrl', `http://${host}`);
|
||||||
|
|||||||
BIN
public/wiregasm/test_ethernet.pcap
Normal file
BIN
public/wiregasm/test_ethernet.pcap
Normal file
Binary file not shown.
BIN
public/wiregasm/wiregasm.data.gz
Normal file
BIN
public/wiregasm/wiregasm.data.gz
Normal file
Binary file not shown.
BIN
public/wiregasm/wiregasm.wasm.gz
Normal file
BIN
public/wiregasm/wiregasm.wasm.gz
Normal file
Binary file not shown.
9768
public/wiregasm/wiregasm_load.js
Normal file
9768
public/wiregasm/wiregasm_load.js
Normal file
File diff suppressed because one or more lines are too long
166
public/wiregasm/wiregasm_new.js
Normal file
166
public/wiregasm/wiregasm_new.js
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
/**
|
||||||
|
* Wraps the WiregasmLib lib functionality and manages a single DissectSession
|
||||||
|
*/
|
||||||
|
class Wiregasm {
|
||||||
|
constructor() {
|
||||||
|
this.initialized = false;
|
||||||
|
this.session = null;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Initialize the wrapper and the Wiregasm module
|
||||||
|
*
|
||||||
|
* @param loader Loader function for the Emscripten module
|
||||||
|
* @param overrides Overrides
|
||||||
|
*/
|
||||||
|
async init(loader, overrides = {}, beforeInit = null) {
|
||||||
|
if (this.initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.lib = await loader(overrides);
|
||||||
|
this.uploadDir = this.lib.getUploadDirectory();
|
||||||
|
this.pluginsDir = this.lib.getPluginsDirectory();
|
||||||
|
if (beforeInit !== null) {
|
||||||
|
await beforeInit(this.lib);
|
||||||
|
}
|
||||||
|
this.lib.init();
|
||||||
|
this.initialized = true;
|
||||||
|
}
|
||||||
|
list_modules() {
|
||||||
|
return this.lib.listModules();
|
||||||
|
}
|
||||||
|
list_prefs(module) {
|
||||||
|
return this.lib.listPreferences(module);
|
||||||
|
}
|
||||||
|
apply_prefs() {
|
||||||
|
this.lib.applyPreferences();
|
||||||
|
}
|
||||||
|
set_pref(module, key, value) {
|
||||||
|
const ret = this.lib.setPref(module, key, value);
|
||||||
|
if (ret.code != PrefSetResult.PREFS_SET_OK) {
|
||||||
|
const message =
|
||||||
|
ret.error != '' ? ret.error : preferenceSetCodeToError(ret.code);
|
||||||
|
throw new Error(
|
||||||
|
`Failed to set preference (${module}.${key}): ${message}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get_pref(module, key) {
|
||||||
|
const response = this.lib.getPref(module, key);
|
||||||
|
if (response.code != 0) {
|
||||||
|
throw new Error(`Failed to get preference (${module}.${key})`);
|
||||||
|
}
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Check the validity of a filter expression.
|
||||||
|
*
|
||||||
|
* @param filter A display filter expression
|
||||||
|
*/
|
||||||
|
test_filter(filter) {
|
||||||
|
return this.lib.checkFilter(filter);
|
||||||
|
}
|
||||||
|
complete_filter(filter) {
|
||||||
|
const out = this.lib.completeFilter(filter);
|
||||||
|
return {
|
||||||
|
err: out.err,
|
||||||
|
fields: vectorToArray(out.fields),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
reload_lua_plugins() {
|
||||||
|
this.lib.reloadLuaPlugins();
|
||||||
|
}
|
||||||
|
add_plugin(name, data, opts = {}) {
|
||||||
|
const path = this.pluginsDir + '/' + name;
|
||||||
|
this.lib.FS.writeFile(path, data, opts);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Load a packet trace file for analysis.
|
||||||
|
*
|
||||||
|
* @returns Response containing the status and summary
|
||||||
|
*/
|
||||||
|
load(name, data, opts = {}) {
|
||||||
|
if (this.session != null) {
|
||||||
|
this.session.delete();
|
||||||
|
}
|
||||||
|
const path = this.uploadDir + '/' + name;
|
||||||
|
this.lib.FS.writeFile(path, data, opts);
|
||||||
|
this.session = new this.lib.DissectSession(path);
|
||||||
|
return this.session.load();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get Packet List information for a range of packets.
|
||||||
|
*
|
||||||
|
* @param filter Output those frames that pass this filter expression
|
||||||
|
* @param skip Skip N frames
|
||||||
|
* @param limit Limit the output to N frames
|
||||||
|
*/
|
||||||
|
frames(filter, skip = 0, limit = 0) {
|
||||||
|
return this.session.getFrames(filter, skip, limit);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get full information about a frame including the protocol tree.
|
||||||
|
*
|
||||||
|
* @param number Frame number
|
||||||
|
*/
|
||||||
|
frame(num) {
|
||||||
|
return this.session.getFrame(num);
|
||||||
|
}
|
||||||
|
follow(follow, filter) {
|
||||||
|
return this.session.follow(follow, filter);
|
||||||
|
}
|
||||||
|
destroy() {
|
||||||
|
if (this.initialized) {
|
||||||
|
if (this.session !== null) {
|
||||||
|
this.session.delete();
|
||||||
|
this.session = null;
|
||||||
|
}
|
||||||
|
this.lib.destroy();
|
||||||
|
this.initialized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns the column headers
|
||||||
|
*/
|
||||||
|
columns() {
|
||||||
|
const vec = this.lib.getColumns();
|
||||||
|
// convert it from a vector to array
|
||||||
|
return vectorToArray(vec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a Vector to a JS array
|
||||||
|
*
|
||||||
|
* @param vec Vector
|
||||||
|
* @returns JS array of the Vector contents
|
||||||
|
*/
|
||||||
|
function vectorToArray(vec) {
|
||||||
|
return new Array(vec.size()).fill(0).map((_, id) => vec.get(id));
|
||||||
|
}
|
||||||
|
function preferenceSetCodeToError(code) {
|
||||||
|
switch (code) {
|
||||||
|
case PrefSetResult.PREFS_SET_SYNTAX_ERR:
|
||||||
|
return 'Syntax error in string';
|
||||||
|
case PrefSetResult.PREFS_SET_NO_SUCH_PREF:
|
||||||
|
return 'No such preference';
|
||||||
|
case PrefSetResult.PREFS_SET_OBSOLETE:
|
||||||
|
return 'Preference used to exist but no longer does';
|
||||||
|
default:
|
||||||
|
return 'Unknown error';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof exports === 'object' && typeof module === 'object') {
|
||||||
|
module.exports = Wiregasm;
|
||||||
|
module.exports = vectorToArray;
|
||||||
|
} else if (typeof define === 'function' && define['amd']) {
|
||||||
|
define([], function () {
|
||||||
|
return Wiregasm;
|
||||||
|
});
|
||||||
|
define([], function () {
|
||||||
|
return vectorToArray;
|
||||||
|
});
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
exports['loadWiregasm'] = Wiregasm;
|
||||||
|
exports['vectorToArray'] = vectorToArray;
|
||||||
|
}
|
||||||
162
public/wiregasm/worker.js
Normal file
162
public/wiregasm/worker.js
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
// load the Wiregasm library
|
||||||
|
importScripts(
|
||||||
|
'/wiregasm/wiregasm_new.js', // self-compilation es5
|
||||||
|
'/wiregasm/wiregasm_load.js'
|
||||||
|
// 'https://cdn.jsdelivr.net/npm/@goodtools/wiregasm/dist/wiregasm.js'
|
||||||
|
);
|
||||||
|
|
||||||
|
const wg = new Wiregasm();
|
||||||
|
|
||||||
|
const inflateRemoteBuffer = async url => {
|
||||||
|
const res = await fetch(url);
|
||||||
|
return await res.arrayBuffer();
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchPackages = async () => {
|
||||||
|
console.log('Fetching packages');
|
||||||
|
let [wasmBuffer, dataBuffer] = await Promise.all([
|
||||||
|
await inflateRemoteBuffer(
|
||||||
|
'/wiregasm/wiregasm.wasm.gz'
|
||||||
|
// 'https://cdn.jsdelivr.net/npm/@goodtools/wiregasm/dist/wiregasm.wasm.gz'
|
||||||
|
),
|
||||||
|
await inflateRemoteBuffer(
|
||||||
|
'/wiregasm/wiregasm.data.gz'
|
||||||
|
// 'https://cdn.jsdelivr.net/npm/@goodtools/wiregasm/dist/wiregasm.data.gz'
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return { wasmBuffer, dataBuffer };
|
||||||
|
};
|
||||||
|
|
||||||
|
// Load the Wiregasm Wasm data
|
||||||
|
fetchPackages()
|
||||||
|
.then(({ wasmBuffer, dataBuffer }) => {
|
||||||
|
return wg.init(loadWiregasm, {
|
||||||
|
wasmBinary: wasmBuffer,
|
||||||
|
getPreloadedPackage() {
|
||||||
|
return dataBuffer;
|
||||||
|
},
|
||||||
|
handleStatus: (type, status) => {
|
||||||
|
postMessage({ type: 'status', code: type, status: status });
|
||||||
|
},
|
||||||
|
printErr: error => {
|
||||||
|
postMessage({ type: 'error', error: error });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
postMessage({ type: 'init' });
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
postMessage({ type: 'error', error: e });
|
||||||
|
});
|
||||||
|
|
||||||
|
/**Converts a Vector to a JS array */
|
||||||
|
function replacer(key, value) {
|
||||||
|
if (value.constructor.name.startsWith('Vector')) {
|
||||||
|
return vectorToArray(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event listener to receive messages from the main script
|
||||||
|
this.onmessage = ev => {
|
||||||
|
const data = ev.data;
|
||||||
|
switch (data.type) {
|
||||||
|
case 'close':
|
||||||
|
wg.destroy();
|
||||||
|
break;
|
||||||
|
case 'columns':
|
||||||
|
const columns = wg.columns();
|
||||||
|
if (Array.isArray(columns)) {
|
||||||
|
this.postMessage({ type: 'columns', data: columns });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'select': // select a frame
|
||||||
|
const number = data.number;
|
||||||
|
const frameData = wg.frame(number);
|
||||||
|
const frameDataToJSON = JSON.parse(JSON.stringify(frameData, replacer));
|
||||||
|
this.postMessage({
|
||||||
|
type: 'selected',
|
||||||
|
data: frameDataToJSON,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 'frames': // get frames list
|
||||||
|
const skip = data.skip;
|
||||||
|
const limit = data.limit;
|
||||||
|
const filter = data.filter;
|
||||||
|
const framesData = wg.frames(filter, skip, limit);
|
||||||
|
const framesDataToJSON = JSON.parse(JSON.stringify(framesData, replacer));
|
||||||
|
this.postMessage({
|
||||||
|
type: 'frames',
|
||||||
|
data: framesDataToJSON,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 'process-data':
|
||||||
|
const loadData = wg.load(data.name, new Uint8Array(data.data));
|
||||||
|
this.postMessage({ type: 'processed', data: loadData });
|
||||||
|
break;
|
||||||
|
case 'process':
|
||||||
|
const f = data.file;
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.addEventListener('load', event => {
|
||||||
|
// XXX: this blocks the worker thread
|
||||||
|
const loadData = wg.load(f.name, new Uint8Array(event.target.result));
|
||||||
|
postMessage({ type: 'processed', data: loadData });
|
||||||
|
});
|
||||||
|
reader.readAsArrayBuffer(f);
|
||||||
|
break;
|
||||||
|
case 'check-filter':
|
||||||
|
const filterStr = data.filter;
|
||||||
|
const checkFilterRes = wg.lib.checkFilter(filterStr);
|
||||||
|
this.postMessage({ type: 'filter', data: checkFilterRes });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.type === 'reload-quick') {
|
||||||
|
if (wg.session) {
|
||||||
|
// TODO: this is a hack, we should be able to reload the session
|
||||||
|
const name = data.name;
|
||||||
|
const res = wg.session.load();
|
||||||
|
|
||||||
|
postMessage({ type: 'processed', name: name, data: res });
|
||||||
|
}
|
||||||
|
} else if (data.type === 'module-tree') {
|
||||||
|
const res = wg.list_modules();
|
||||||
|
// send it to the correct port
|
||||||
|
event.ports[0].postMessage({
|
||||||
|
result: JSON.parse(JSON.stringify(res, replacer)),
|
||||||
|
});
|
||||||
|
} else if (data.type === 'module-prefs') {
|
||||||
|
const res = wg.list_prefs(data.name);
|
||||||
|
// send it to the correct port
|
||||||
|
event.ports[0].postMessage({
|
||||||
|
result: JSON.parse(JSON.stringify(res, replacer)),
|
||||||
|
});
|
||||||
|
} else if (data.type === 'upload-file') {
|
||||||
|
const f = data.file;
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.addEventListener('load', e => {
|
||||||
|
// XXX: this blocks the worker thread
|
||||||
|
const path = '/uploads/' + f.name;
|
||||||
|
wg.lib.FS.writeFile(path, Buffer.from(e.target.result));
|
||||||
|
event.ports[0].postMessage({ result: path });
|
||||||
|
});
|
||||||
|
reader.readAsArrayBuffer(f);
|
||||||
|
} else if (data.type === 'update-pref') {
|
||||||
|
try {
|
||||||
|
console.log(`set_pref(${data.module}, ${data.key}, ${data.value})`);
|
||||||
|
wg.set_pref(data.module, data.key, data.value);
|
||||||
|
event.ports[0].postMessage({ result: 'ok' });
|
||||||
|
} catch (e) {
|
||||||
|
console.error(
|
||||||
|
`set_pref(${data.module}, ${data.key}, ${data.value}) failed: ${e.message}`
|
||||||
|
);
|
||||||
|
event.ports[0].postMessage({ error: e.message });
|
||||||
|
}
|
||||||
|
} else if (data.type === 'apply-prefs') {
|
||||||
|
console.log(`apply_prefs()`);
|
||||||
|
wg.apply_prefs();
|
||||||
|
event.ports[0].postMessage({ result: 'ok' });
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -241,6 +241,7 @@ export function listSync() {
|
|||||||
return request({
|
return request({
|
||||||
url: `/api/rest/faultManagement/v1/elementType/all/objectType/alarms`,
|
url: `/api/rest/faultManagement/v1/elementType/all/objectType/alarms`,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
|
timeout: 180_000,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import { parseObjLineToHump } from '@/utils/parse-utils';
|
|||||||
import { parseDateToStr } from '@/utils/date-utils';
|
import { parseDateToStr } from '@/utils/date-utils';
|
||||||
import useUserStore from '@/store/modules/user';
|
import useUserStore from '@/store/modules/user';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询列表
|
* 查询列表
|
||||||
* @param query 查询参数
|
* @param query 查询参数
|
||||||
@@ -28,8 +26,6 @@ export async function listAct(query: Record<string, any>) {
|
|||||||
querySQL += ` and pv_flag = '${query.pvFlag}' `;
|
querySQL += ` and pv_flag = '${query.pvFlag}' `;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (query.neId) {
|
if (query.neId) {
|
||||||
querySQL += ` and ne_id like '%${query.neId}%' `;
|
querySQL += ` and ne_id like '%${query.neId}%' `;
|
||||||
}
|
}
|
||||||
@@ -69,7 +65,6 @@ export async function listAct(query: Record<string, any>) {
|
|||||||
msg: result.msg,
|
msg: result.msg,
|
||||||
};
|
};
|
||||||
result.data.data.forEach((item: any) => {
|
result.data.data.forEach((item: any) => {
|
||||||
console.log(item)
|
|
||||||
const itemData = item['alarm_event'];
|
const itemData = item['alarm_event'];
|
||||||
if (Array.isArray(itemData)) {
|
if (Array.isArray(itemData)) {
|
||||||
if (itemData.length === 1 && itemData[0]['total'] >= 0) {
|
if (itemData.length === 1 && itemData[0]['total'] >= 0) {
|
||||||
@@ -84,12 +79,6 @@ export async function listAct(query: Record<string, any>) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 事件告警导出
|
* 事件告警导出
|
||||||
* @param query 查询参数
|
* @param query 查询参数
|
||||||
@@ -133,7 +122,3 @@ export async function exportAll(query: Record<string, any>) {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
53
src/api/logManage/exportFile.ts
Normal file
53
src/api/logManage/exportFile.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import { request } from '@/plugins/http-fetch';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取下拉框数据
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function getBakFile() {
|
||||||
|
return request({
|
||||||
|
url: '/lm/table/list',
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取对应类型的文件列表
|
||||||
|
* @param query 查询参数
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function getBakFileList(query: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/lm/file/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载远端文件
|
||||||
|
* @param query 查询参数
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function downFile(query: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: `/lm/file/${query.fileName}`,
|
||||||
|
method: 'get',
|
||||||
|
params: query,
|
||||||
|
responseType: 'blob',
|
||||||
|
timeout: 180_000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除远端获取文件
|
||||||
|
* @param query 查询参数
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function delFile(query: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: `/lm/file/${query.fileName}`,
|
||||||
|
method: 'delete',
|
||||||
|
params: query,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ export function login(data: Record<string, string>) {
|
|||||||
method: 'post',
|
method: 'post',
|
||||||
data: data,
|
data: data,
|
||||||
whithToken: false,
|
whithToken: false,
|
||||||
|
crypto: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,6 +22,7 @@ export function register(data: Record<string, any>) {
|
|||||||
method: 'post',
|
method: 'post',
|
||||||
data: data,
|
data: data,
|
||||||
whithToken: false,
|
whithToken: false,
|
||||||
|
crypto: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,5 +6,6 @@ export function getLoad(query: Record<string, any>) {
|
|||||||
url: '/monitor/load',
|
url: '/monitor/load',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query,
|
params: query,
|
||||||
|
timeout: 60_000,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,5 +5,6 @@ export function getSystemInfo() {
|
|||||||
return request({
|
return request({
|
||||||
url: '/monitor/system-info',
|
url: '/monitor/system-info',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
|
timeout: 60_000,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
66
src/api/ne/neConfig.ts
Normal file
66
src/api/ne/neConfig.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import { request } from '@/plugins/http-fetch';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网元参数配置可用属性值列表指定网元类型全部无分页
|
||||||
|
* @param query 查询参数
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function getAllNeConfig(neType: string) {
|
||||||
|
return request({
|
||||||
|
url: `/ne/config/list/${neType}`,
|
||||||
|
method: 'get',
|
||||||
|
timeout: 60_000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网元参数配置数据信息
|
||||||
|
* @param params 数据 {neType,neId,paramName}
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function getNeConfigData(params: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: `/ne/config/data`,
|
||||||
|
params,
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网元参数配置数据更新
|
||||||
|
* @param data 数据 {neType,neId,paramName:"参数名",paramData:{参数},loc:"层级index仅array"}
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function editNeConfigData(data: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: `/ne/config/data`,
|
||||||
|
method: 'put',
|
||||||
|
data: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网元参数配置数据新增(array)
|
||||||
|
* @param data 数据 {neType,neId,paramName:"参数名",paramData:{参数},loc:"层级index"}
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function addNeConfigData(data: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: `/ne/config/data`,
|
||||||
|
method: 'post',
|
||||||
|
data: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网元参数配置数据删除(array)
|
||||||
|
* @param params 数据 {neType,neId,paramName:"参数名",loc:"层级index"}
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function delNeConfigData(params: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: `/ne/config/data`,
|
||||||
|
method: 'delete',
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
83
src/api/ne/neConfigBackup.ts
Normal file
83
src/api/ne/neConfigBackup.ts
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import { request } from '@/plugins/http-fetch';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网元配置文件备份记录列表
|
||||||
|
* @param query 查询参数
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function listNeConfigBackup(query: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/ne/config/backup/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网元配置文件备份记录修改
|
||||||
|
* @param data 数据 { id, name, remark }
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function updateNeConfigBackup(data: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/ne/config/backup',
|
||||||
|
method: 'put',
|
||||||
|
data: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网元配置文件备份记录下载
|
||||||
|
* @param id 记录ID
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export async function downNeConfigBackup(id: string) {
|
||||||
|
return await request({
|
||||||
|
url: '/ne/config/backup/download',
|
||||||
|
method: 'get',
|
||||||
|
params: { id },
|
||||||
|
responseType: 'blob',
|
||||||
|
timeout: 180_000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网元配置文件备份记录删除
|
||||||
|
* @param id 记录ID
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export async function delNeConfigBackup(id: string) {
|
||||||
|
return request({
|
||||||
|
url: '/ne/config/backup',
|
||||||
|
method: 'delete',
|
||||||
|
params: { id },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网元配置文件备份导出
|
||||||
|
* @param data 数据 { neType, neId }
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function exportNeConfigBackup(data: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/ne/config/backup/export',
|
||||||
|
method: 'post',
|
||||||
|
data: data,
|
||||||
|
responseType: 'blob',
|
||||||
|
timeout: 180_000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网元配置文件备份导入
|
||||||
|
* @param data 数据 { neType, neId, type, path }
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function importNeConfigBackup(data: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/ne/config/backup/import',
|
||||||
|
method: 'post',
|
||||||
|
data: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -36,6 +36,8 @@ export function addNeInfo(data: Record<string, any>) {
|
|||||||
url: `/ne/info`,
|
url: `/ne/info`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data,
|
data: data,
|
||||||
|
crypto: true,
|
||||||
|
timeout: 30_000,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,6 +51,8 @@ export function updateNeInfo(data: Record<string, any>) {
|
|||||||
url: `/ne/info`,
|
url: `/ne/info`,
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: data,
|
data: data,
|
||||||
|
crypto: true,
|
||||||
|
timeout: 30_000,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,3 +40,16 @@ export function exportSMFDataCDR(data: Record<string, any>) {
|
|||||||
timeout: 60_000,
|
timeout: 60_000,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SMF-在线订阅用户列表信息
|
||||||
|
* @param query 查询参数
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function listSMFSubscribers(query: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/neData/smf/subscribers',
|
||||||
|
method: 'get',
|
||||||
|
params: query,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
42
src/api/neData/smsc.ts
Normal file
42
src/api/neData/smsc.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { request } from '@/plugins/http-fetch';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询SMSC-CDR会话事件
|
||||||
|
* @param query 查询参数
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function listSMSCDataCDR(query: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/neData/smsc/cdr/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SMSC-CDR会话删除
|
||||||
|
* @param id 信息ID
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function delSMSCDataCDR(cdrIds: string | number) {
|
||||||
|
return request({
|
||||||
|
url: `/neData/smsc/cdr/${cdrIds}`,
|
||||||
|
method: 'delete',
|
||||||
|
timeout: 60_000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SMSC-CDR会话列表导出
|
||||||
|
* @param data 查询列表条件
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function exportSMSCDataCDR(data: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/neData/smsc/cdr/export',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
responseType: 'blob',
|
||||||
|
timeout: 60_000,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -113,7 +113,6 @@ export function batchDelUDMAuth(neId: string, imsi: string, num: number) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* UDM鉴权用户导入
|
* UDM鉴权用户导入
|
||||||
* @param neId 网元ID
|
|
||||||
* @param data 表单数据对象
|
* @param data 表单数据对象
|
||||||
* @returns object
|
* @returns object
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -52,9 +52,11 @@ export async function listUENumByIMS(neId: String) {
|
|||||||
method: 'get',
|
method: 'get',
|
||||||
});
|
});
|
||||||
if (result.code === RESULT_CODE_SUCCESS) {
|
if (result.code === RESULT_CODE_SUCCESS) {
|
||||||
return Object.assign(result, {
|
let num = result.data['ueNum'] || 0;
|
||||||
data: result.data['ueNum'],
|
if (num === 0) {
|
||||||
});
|
num = result.data.data['ueNum'] || 0;
|
||||||
|
}
|
||||||
|
return Object.assign(result, { data: num });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 模拟数据
|
// 模拟数据
|
||||||
|
|||||||
19
src/api/perfManage/customData.ts
Normal file
19
src/api/perfManage/customData.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
|
import { request } from '@/plugins/http-fetch';
|
||||||
|
import { parseObjLineToHump } from '@/utils/parse-utils';
|
||||||
|
import { parseDateToStr } from '@/utils/date-utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新 查询自定义指标数据
|
||||||
|
* @param query 查询参数
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export async function listCustomData(query: Record<string, any>) {
|
||||||
|
// 发起请求
|
||||||
|
const result = await request({
|
||||||
|
url: `/pm/kpiC/report`,
|
||||||
|
method: 'get',
|
||||||
|
params: query,
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -8,57 +8,72 @@ import { parseDateToStr } from '@/utils/date-utils';
|
|||||||
* @param query 查询参数
|
* @param query 查询参数
|
||||||
* @returns object
|
* @returns object
|
||||||
*/
|
*/
|
||||||
export async function listCustom(query: Record<string, any>) {
|
// export async function listCustom(query: Record<string, any>) {
|
||||||
let totalSQL = 'select count(*) as total from pm_custom_title where 1=1 ';
|
// let totalSQL = 'select count(*) as total from pm_custom_title where 1=1 ';
|
||||||
let rowsSQL = 'select * from pm_custom_title where 1=1 ';
|
// let rowsSQL = 'select * from pm_custom_title where 1=1 ';
|
||||||
|
|
||||||
// 查询
|
// // 查询
|
||||||
let querySQL = '';
|
// let querySQL = '';
|
||||||
if (query.neType) {
|
// if (query.neType) {
|
||||||
querySQL += ` and ne_type like '%${query.neType}%' `;
|
// querySQL += ` and ne_type like '%${query.neType}%' `;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 排序
|
// // 排序
|
||||||
let sortSql = ' order by update_time ';
|
// let sortSql = ' order by update_time ';
|
||||||
if (query.sortOrder === 'asc') {
|
// if (query.sortOrder === 'asc') {
|
||||||
sortSql += ' asc ';
|
// sortSql += ' asc ';
|
||||||
} else {
|
// } else {
|
||||||
sortSql += ' desc ';
|
// sortSql += ' desc ';
|
||||||
}
|
// }
|
||||||
// 分页
|
// // 分页
|
||||||
const pageNum = (query.pageNum - 1) * query.pageSize;
|
// const pageNum = (query.pageNum - 1) * query.pageSize;
|
||||||
const limtSql = ` limit ${pageNum},${query.pageSize} `;
|
// const limtSql = ` limit ${pageNum},${query.pageSize} `;
|
||||||
|
|
||||||
|
// // 发起请求
|
||||||
|
// const result = await request({
|
||||||
|
// url: `/api/rest/databaseManagement/v1/select/omc_db/pm_custom_title`,
|
||||||
|
// method: 'get',
|
||||||
|
// params: {
|
||||||
|
// totalSQL: totalSQL + querySQL,
|
||||||
|
// rowsSQL: rowsSQL + querySQL + sortSql + limtSql,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // 解析数据
|
||||||
|
// if (result.code === RESULT_CODE_SUCCESS) {
|
||||||
|
// const data: DataList = {
|
||||||
|
// total: 0,
|
||||||
|
// rows: [],
|
||||||
|
// code: result.code,
|
||||||
|
// msg: result.msg,
|
||||||
|
// };
|
||||||
|
// result.data.data.forEach((item: any) => {
|
||||||
|
// const itemData = item['pm_custom_title'];
|
||||||
|
// if (Array.isArray(itemData)) {
|
||||||
|
// if (itemData.length === 1 && itemData[0]['total'] >= 0) {
|
||||||
|
// data.total = itemData[0]['total'];
|
||||||
|
// } else {
|
||||||
|
// data.rows = itemData.map(v => parseObjLineToHump(v));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// return data;
|
||||||
|
// }
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新 查询自定义指标
|
||||||
|
* @param query 查询参数
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export async function listCustom(query?: Record<string, any>) {
|
||||||
// 发起请求
|
// 发起请求
|
||||||
const result = await request({
|
const result = await request({
|
||||||
url: `/api/rest/databaseManagement/v1/select/omc_db/pm_custom_title`,
|
url: `/pm/kpiC/title/totalList`,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: {
|
params: query,
|
||||||
totalSQL: totalSQL + querySQL,
|
|
||||||
rowsSQL: rowsSQL + querySQL + sortSql + limtSql,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 解析数据
|
|
||||||
if (result.code === RESULT_CODE_SUCCESS) {
|
|
||||||
const data: DataList = {
|
|
||||||
total: 0,
|
|
||||||
rows: [],
|
|
||||||
code: result.code,
|
|
||||||
msg: result.msg,
|
|
||||||
};
|
|
||||||
result.data.data.forEach((item: any) => {
|
|
||||||
const itemData = item['pm_custom_title'];
|
|
||||||
if (Array.isArray(itemData)) {
|
|
||||||
if (itemData.length === 1 && itemData[0]['total'] >= 0) {
|
|
||||||
data.total = itemData[0]['total'];
|
|
||||||
} else {
|
|
||||||
data.rows = itemData.map(v => parseObjLineToHump(v));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,22 +83,10 @@ export async function listCustom(query: Record<string, any>) {
|
|||||||
* @returns object
|
* @returns object
|
||||||
*/
|
*/
|
||||||
export async function getCustom(id: string | number) {
|
export async function getCustom(id: string | number) {
|
||||||
// 发起请求
|
return request({
|
||||||
const result = await request({
|
url: `/pm/kpiC/title/${id}`,
|
||||||
url: `/api/rest/databaseManagement/v1/select/omc_db/pm_custom_title`,
|
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: {
|
|
||||||
SQL: `select * from pm_custom_title where id = ${id}`,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
// 解析数据
|
|
||||||
if (result.code === RESULT_CODE_SUCCESS && Array.isArray(result.data.data)) {
|
|
||||||
let data = result.data.data[0];
|
|
||||||
return Object.assign(result, {
|
|
||||||
data: parseObjLineToHump(data['pm_custom_title'][0]),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -92,21 +95,10 @@ export async function getCustom(id: string | number) {
|
|||||||
* @returns object
|
* @returns object
|
||||||
*/
|
*/
|
||||||
export function addCustom(data: Record<string, any>) {
|
export function addCustom(data: Record<string, any>) {
|
||||||
let obj: any = {
|
|
||||||
title: data.title,
|
|
||||||
ne_type: data.neType,
|
|
||||||
kpi_id: data.kpiId,
|
|
||||||
object_type: data.objectType,
|
|
||||||
expression: data.expression,
|
|
||||||
period: data.period,
|
|
||||||
description: data.description,
|
|
||||||
kpi_set: data.kpiSet,
|
|
||||||
};
|
|
||||||
|
|
||||||
return request({
|
return request({
|
||||||
url: `/api/rest/databaseManagement/v1/omc_db/pm_custom_title`,
|
url: `/pm/kpiC/title`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: { 'data': [obj] },
|
data: data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,20 +108,10 @@ export function addCustom(data: Record<string, any>) {
|
|||||||
* @returns object
|
* @returns object
|
||||||
*/
|
*/
|
||||||
export function updateCustom(data: Record<string, any>) {
|
export function updateCustom(data: Record<string, any>) {
|
||||||
let obj: any = {
|
|
||||||
title: data.title,
|
|
||||||
ne_type: data.neType,
|
|
||||||
kpi_id: data.kpiId,
|
|
||||||
object_type: data.objectType,
|
|
||||||
expression: data.expression,
|
|
||||||
period: data.period,
|
|
||||||
description: data.description,
|
|
||||||
kpi_set: data.kpiSet,
|
|
||||||
};
|
|
||||||
return request({
|
return request({
|
||||||
url: `/api/rest/databaseManagement/v1/omc_db/pm_custom_title?WHERE=id=${data.id}`,
|
url: `/pm/kpiC/title/${data.id}`,
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: { data: obj },
|
data: data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,8 +121,7 @@ export function updateCustom(data: Record<string, any>) {
|
|||||||
*/
|
*/
|
||||||
export async function delCustom(data: Record<string, any>) {
|
export async function delCustom(data: Record<string, any>) {
|
||||||
return request({
|
return request({
|
||||||
url: `/api/rest/databaseManagement/v1/omc_db/pm_custom_title?WHERE=id=${data.id}`,
|
url: `/pm/kpiC/title/${data.id}`,
|
||||||
method: 'delete',
|
method: 'delete',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,10 +18,21 @@ export function dumpStop(data: Record<string, string>) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 网元抓包PACP 下载
|
||||||
|
export function dumpDownload(data: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/trace/tcpdump/download',
|
||||||
|
method: 'get',
|
||||||
|
params: data,
|
||||||
|
responseType: 'blob',
|
||||||
|
timeout: 60_000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// UPF标准版内部抓包
|
// UPF标准版内部抓包
|
||||||
export function traceUPF(data: Record<string, string>) {
|
export function traceUPF(data: Record<string, string>) {
|
||||||
return request({
|
return request({
|
||||||
url: '/trace/tcpdump/traceUPF',
|
url: '/trace/tcpdump/upf',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data,
|
data: data,
|
||||||
});
|
});
|
||||||
104
src/api/trace/task.ts
Normal file
104
src/api/trace/task.ts
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
|
import { request } from '@/plugins/http-fetch';
|
||||||
|
import { parseObjLineToHump } from '@/utils/parse-utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询跟踪任务列表
|
||||||
|
* @param query 查询参数
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export async function listTraceTask(query: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/trace/task/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询跟踪任务信息
|
||||||
|
* @param id 网元ID
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export async function getTraceTask(id: string | number) {
|
||||||
|
return request({
|
||||||
|
url: `/trace/task/${id}`,
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增任务
|
||||||
|
* @param data 网元对象
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function addTraceTask(data: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: `/trace/task`,
|
||||||
|
method: 'post',
|
||||||
|
data: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改任务
|
||||||
|
* @param data 网元对象
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function updateTraceTask(data: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: `/trace/task`,
|
||||||
|
method: 'put',
|
||||||
|
data: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跟踪任务删除
|
||||||
|
* @param ids ID多个逗号分隔
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export async function delTraceTask(ids: string) {
|
||||||
|
return request({
|
||||||
|
url: `/trace/task/${ids}`,
|
||||||
|
method: 'delete',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跟踪任务文件
|
||||||
|
* @param query 对象
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function filePullTask(traceId: string) {
|
||||||
|
return request({
|
||||||
|
url: '/trace/task/filePull',
|
||||||
|
method: 'get',
|
||||||
|
params: { traceId },
|
||||||
|
responseType: 'blob',
|
||||||
|
timeout: 60_000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取网元跟踪接口列表
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export async function getNeTraceInterfaceAll() {
|
||||||
|
// 发起请求
|
||||||
|
const result = await request({
|
||||||
|
url: `/api/rest/databaseManagement/v1/elementType/omc_db/objectType/ne_info`,
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
SQL: `SELECT ne_type,interface FROM trace_info GROUP BY ne_type,interface`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// 解析数据
|
||||||
|
if (result.code === RESULT_CODE_SUCCESS && Array.isArray(result.data.data)) {
|
||||||
|
let data = result.data.data[0];
|
||||||
|
return Object.assign(result, {
|
||||||
|
data: parseObjLineToHump(data['trace_info']),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
83
src/api/trace/taskHLR.ts
Normal file
83
src/api/trace/taskHLR.ts
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import { request } from '@/plugins/http-fetch';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询跟踪任务列表
|
||||||
|
* @param query 查询参数
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function listTaskHLR(query: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/trace/task/hlr/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跟踪任务删除
|
||||||
|
* @param ids 任务ID
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function delTaskHLR(ids: string | number) {
|
||||||
|
return request({
|
||||||
|
url: `/trace/task/hlr/${ids}`,
|
||||||
|
method: 'delete',
|
||||||
|
timeout: 60_000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跟踪任务创建
|
||||||
|
* @param data 对象
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function startTaskHLR(data: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/trace/task/hlr/start',
|
||||||
|
method: 'post',
|
||||||
|
data: data,
|
||||||
|
timeout: 60_000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跟踪任务停止
|
||||||
|
* @param data 对象
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function stopTaskHLR(data: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/trace/task/hlr/stop',
|
||||||
|
method: 'post',
|
||||||
|
data: data,
|
||||||
|
timeout: 60_000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跟踪任务文件
|
||||||
|
* @param data 对象
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function fileTaskHLR(data: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/trace/task/hlr/file',
|
||||||
|
method: 'post',
|
||||||
|
data: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跟踪任务文件从网元到本地
|
||||||
|
* @param query 对象
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function filePullTaskHLR(query: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/trace/task/hlr/filePull',
|
||||||
|
method: 'get',
|
||||||
|
params: query,
|
||||||
|
responseType: 'blob',
|
||||||
|
timeout: 60_000,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
|
||||||
import { request } from '@/plugins/http-fetch';
|
|
||||||
import { parseObjLineToHump } from '@/utils/parse-utils';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询任务列表
|
|
||||||
* @param query 查询参数
|
|
||||||
* @returns object
|
|
||||||
*/
|
|
||||||
export async function listTraceTask(query: Record<string, any>) {
|
|
||||||
let totalSQL = 'select count(*) as total from trace_task where 1=1 ';
|
|
||||||
let rowsSQL = 'select * from trace_task where 1=1 ';
|
|
||||||
|
|
||||||
// 查询
|
|
||||||
let querySQL = '';
|
|
||||||
if (query.imsi) {
|
|
||||||
querySQL += ` and imsi like '%${query.imsi}%' `;
|
|
||||||
}
|
|
||||||
if (query.beginTime) {
|
|
||||||
querySQL += ` and start_time >= '${query.beginTime}' `;
|
|
||||||
}
|
|
||||||
if (query.endTime) {
|
|
||||||
querySQL += ` and end_time <= '${query.endTime}' `;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 分页
|
|
||||||
const pageNum = (query.pageNum - 1) * query.pageSize;
|
|
||||||
const limtSql = ` limit ${pageNum},${query.pageSize} `;
|
|
||||||
|
|
||||||
// 排序
|
|
||||||
let sortSql = ' order by start_time ';
|
|
||||||
if (query.sortOrder === 'asc') {
|
|
||||||
sortSql += ' asc ';
|
|
||||||
} else {
|
|
||||||
sortSql += ' desc ';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 发起请求
|
|
||||||
const result = await request({
|
|
||||||
url: `/api/rest/databaseManagement/v1/select/omc_db/trace_task`,
|
|
||||||
method: 'get',
|
|
||||||
params: {
|
|
||||||
totalSQL: totalSQL + querySQL,
|
|
||||||
rowsSQL: rowsSQL + querySQL + sortSql + limtSql,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// 解析数据
|
|
||||||
if (result.code === RESULT_CODE_SUCCESS) {
|
|
||||||
const data: DataList = {
|
|
||||||
total: 0,
|
|
||||||
rows: [],
|
|
||||||
code: result.code,
|
|
||||||
msg: result.msg,
|
|
||||||
};
|
|
||||||
result.data.data.forEach((item: any) => {
|
|
||||||
const itemData = item['trace_task'];
|
|
||||||
if (Array.isArray(itemData)) {
|
|
||||||
if (itemData.length === 1 && itemData[0]['total'] >= 0) {
|
|
||||||
data.total = itemData[0]['total'];
|
|
||||||
} else {
|
|
||||||
data.rows = itemData.map(v => parseObjLineToHump(v));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询任务详细
|
|
||||||
* @param id 网元ID
|
|
||||||
* @returns object
|
|
||||||
*/
|
|
||||||
export async function getTraceTask(id: string | number) {
|
|
||||||
// 发起请求
|
|
||||||
const result = await request({
|
|
||||||
url: `/api/rest/databaseManagement/v1/select/omc_db/trace_task`,
|
|
||||||
method: 'get',
|
|
||||||
params: {
|
|
||||||
SQL: `select * from trace_task where id = ${id}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
// 解析数据
|
|
||||||
if (result.code === RESULT_CODE_SUCCESS && Array.isArray(result.data.data)) {
|
|
||||||
let data = result.data.data[0];
|
|
||||||
return Object.assign(result, {
|
|
||||||
data: parseObjLineToHump(data['trace_task'][0]),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新增任务
|
|
||||||
* @param data 网元对象
|
|
||||||
* @returns object
|
|
||||||
*/
|
|
||||||
export function addTraceTask(data: Record<string, any>) {
|
|
||||||
return request({
|
|
||||||
url: `/api/rest/traceManagement/v1/subscriptions`,
|
|
||||||
method: 'post',
|
|
||||||
data: data,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改任务
|
|
||||||
* @param data 网元对象
|
|
||||||
* @returns object
|
|
||||||
*/
|
|
||||||
export function updateTraceTask(data: Record<string, any>) {
|
|
||||||
return request({
|
|
||||||
url: `/api/rest/traceManagement/v1/subscriptions`,
|
|
||||||
method: 'put',
|
|
||||||
data: data,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除任务
|
|
||||||
* @param noticeId 网元ID
|
|
||||||
* @returns object
|
|
||||||
*/
|
|
||||||
export async function delTraceTask(id: string) {
|
|
||||||
return request({
|
|
||||||
url: `/api/rest/traceManagement/v1/subscriptions?id=${id}`,
|
|
||||||
method: 'delete',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取网元跟踪接口列表
|
|
||||||
* @returns object
|
|
||||||
*/
|
|
||||||
export async function getNeTraceInterfaceAll() {
|
|
||||||
// 发起请求
|
|
||||||
const result = await request({
|
|
||||||
url: `/api/rest/databaseManagement/v1/elementType/omc_db/objectType/ne_info`,
|
|
||||||
method: 'get',
|
|
||||||
params: {
|
|
||||||
SQL: `SELECT ne_type,interface FROM trace_info GROUP BY ne_type,interface`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
// 解析数据
|
|
||||||
if (result.code === RESULT_CODE_SUCCESS && Array.isArray(result.data.data)) {
|
|
||||||
let data = result.data.data[0];
|
|
||||||
return Object.assign(result, {
|
|
||||||
data: parseObjLineToHump(data['trace_info']),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
11
src/assets/js/wiregasm_worker.ts
Normal file
11
src/assets/js/wiregasm_worker.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* worker文件-静态资源文件路径
|
||||||
|
*/
|
||||||
|
const baseUrl = import.meta.env.VITE_HISTORY_BASE_URL;
|
||||||
|
export const scriptUrl = `${
|
||||||
|
baseUrl.length === 1 && baseUrl.indexOf('/') === 0
|
||||||
|
? ''
|
||||||
|
: baseUrl.indexOf('/') === -1
|
||||||
|
? '/' + baseUrl
|
||||||
|
: baseUrl
|
||||||
|
}/wiregasm/worker.js`;
|
||||||
227
src/components/TerminalSSHView/index.vue
Normal file
227
src/components/TerminalSSHView/index.vue
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue';
|
||||||
|
import { FitAddon } from '@xterm/addon-fit';
|
||||||
|
import { Terminal } from '@xterm/xterm';
|
||||||
|
import '@xterm/xterm/css/xterm.css';
|
||||||
|
import { RESULT_CODE_ERROR } from '@/constants/result-constants';
|
||||||
|
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||||
|
const ws = new WS();
|
||||||
|
const emit = defineEmits(['connect', 'close', 'message']);
|
||||||
|
const props = defineProps({
|
||||||
|
/**终端ID,必传 */
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
/**网元类型,必传 */
|
||||||
|
neType: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
/**网元ID,必传 */
|
||||||
|
neId: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
/**窗口单行字符数 */
|
||||||
|
cols: {
|
||||||
|
type: Number,
|
||||||
|
default: 80,
|
||||||
|
},
|
||||||
|
/**窗口行数 */
|
||||||
|
rows: {
|
||||||
|
type: Number,
|
||||||
|
default: 40,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**终端输入DOM节点实例对象 */
|
||||||
|
const terminalDom = ref<HTMLElement | undefined>(undefined);
|
||||||
|
|
||||||
|
/**终端输入实例对象 */
|
||||||
|
const terminal = ref<any>(null);
|
||||||
|
|
||||||
|
/**终端输入渲染 */
|
||||||
|
function handleRanderXterm(container: HTMLElement | undefined) {
|
||||||
|
if (!container) return;
|
||||||
|
const xterm = new Terminal({
|
||||||
|
cols: props.cols,
|
||||||
|
rows: props.rows,
|
||||||
|
lineHeight: 1.2,
|
||||||
|
fontSize: 12,
|
||||||
|
fontFamily: "Monaco, Menlo, Consolas, 'Courier New', monospace",
|
||||||
|
theme: {
|
||||||
|
background: '#000000',
|
||||||
|
},
|
||||||
|
cursorBlink: true, // 光标闪烁
|
||||||
|
cursorStyle: 'block',
|
||||||
|
scrollback: 1000, // 设置历史缓冲区大小为 1000 行
|
||||||
|
scrollSensitivity: 15,
|
||||||
|
tabStopWidth: 4,
|
||||||
|
disableStdin: true, // 禁止输入
|
||||||
|
});
|
||||||
|
// 挂载
|
||||||
|
xterm.open(container);
|
||||||
|
// 自适应尺寸
|
||||||
|
const fitAddon = new FitAddon();
|
||||||
|
xterm.loadAddon(fitAddon);
|
||||||
|
// 终端尺寸变化触发
|
||||||
|
xterm.onResize(({ cols, rows }) => {
|
||||||
|
// console.log('尺寸', cols, rows);
|
||||||
|
ws.send({
|
||||||
|
requestId: `resize_${props.id}`,
|
||||||
|
type: 'resize',
|
||||||
|
data: { cols, rows },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 创建 ResizeObserver 实例
|
||||||
|
var observer = new ResizeObserver(entries => {
|
||||||
|
fitAddon.fit();
|
||||||
|
});
|
||||||
|
// 监听元素大小变化
|
||||||
|
observer.observe(container);
|
||||||
|
|
||||||
|
terminal.value = xterm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**连接打开后回调 */
|
||||||
|
function wsOpen(ev: any) {
|
||||||
|
// console.info('wsOpen', ev);
|
||||||
|
nextTick(() => {
|
||||||
|
handleRanderXterm(terminalDom.value);
|
||||||
|
// 连接事件
|
||||||
|
emit('connect', {
|
||||||
|
timeStamp: ev.timeStamp,
|
||||||
|
cols: terminal.value.cols,
|
||||||
|
rows: terminal.value.rows,
|
||||||
|
neType: props.neType,
|
||||||
|
neId: props.neId,
|
||||||
|
id: props.id,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**连接错误后回调 */
|
||||||
|
function wsError(ev: any) {
|
||||||
|
console.error('wsError', ev);
|
||||||
|
if (terminal.value != null) {
|
||||||
|
let message = 'disconnected';
|
||||||
|
terminal.value.write(`\x1b[31m${message}\x1b[m\r\n`);
|
||||||
|
} else if (terminalDom.value) {
|
||||||
|
terminalDom.value.style.background = '#000';
|
||||||
|
terminalDom.value.style.color = '#ff4d4f';
|
||||||
|
terminalDom.value.style.height = '60%';
|
||||||
|
terminalDom.value.innerText = 'disconnected';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**连接关闭后回调 */
|
||||||
|
function wsClose(code: number) {
|
||||||
|
// console.warn('wsClose', code);
|
||||||
|
if (terminal.value != null) {
|
||||||
|
let message = 'disconnected ' + code;
|
||||||
|
terminal.value.write(`\x1b[31m${message}\x1b[m\r\n`);
|
||||||
|
}
|
||||||
|
// 关闭事件
|
||||||
|
emit('close', {
|
||||||
|
code: code,
|
||||||
|
neType: props.neType,
|
||||||
|
neId: props.neId,
|
||||||
|
id: props.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**接收消息后回调 */
|
||||||
|
function wsMessage(res: Record<string, any>) {
|
||||||
|
emit('message', res);
|
||||||
|
// console.log('wsMessage', res);
|
||||||
|
const { code, requestId, data } = res;
|
||||||
|
if (code === RESULT_CODE_ERROR) {
|
||||||
|
console.warn(res.msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!requestId) return;
|
||||||
|
if (terminal.value != null) {
|
||||||
|
// 查找的开始输出标记
|
||||||
|
const parts: string[] = data.split('\u001b[?2004l\r');
|
||||||
|
if (parts.length > 0) {
|
||||||
|
let text = parts[parts.length - 1];
|
||||||
|
// 找到最后输出标记
|
||||||
|
const lestIndex = text.lastIndexOf('\u001b[?2004h\u001b]0;');
|
||||||
|
if (lestIndex !== -1) {
|
||||||
|
text = text.substring(0, lestIndex);
|
||||||
|
}
|
||||||
|
if (text === '' || text === '\r\n' || text.startsWith("^C\r\n") ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// console.log({ parts, text });
|
||||||
|
terminal.value.write(text);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 无标记
|
||||||
|
terminal.value.write(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (props.neType && props.neId) {
|
||||||
|
// 建立链接
|
||||||
|
const options: OptionsType = {
|
||||||
|
url: '/ws/view',
|
||||||
|
params: {
|
||||||
|
neType: props.neType,
|
||||||
|
neId: props.neId,
|
||||||
|
cols: props.cols,
|
||||||
|
rows: props.rows,
|
||||||
|
},
|
||||||
|
onmessage: wsMessage,
|
||||||
|
onerror: wsError,
|
||||||
|
onopen: wsOpen,
|
||||||
|
onclose: wsClose,
|
||||||
|
};
|
||||||
|
ws.connect(options);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
ws.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 给组件设置属性 ref="xxxTerminal"
|
||||||
|
// setup内使用 const xxxTerminal = ref();
|
||||||
|
defineExpose({
|
||||||
|
/**清除 */
|
||||||
|
clear: () => {
|
||||||
|
if (terminal.value != null) {
|
||||||
|
terminal.value.clear();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**发送命令 */
|
||||||
|
send: (type: string, data: Record<string, any>) => {
|
||||||
|
ws.send({
|
||||||
|
requestId: `ssh_${props.id}`,
|
||||||
|
type,
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**模拟按下 Ctrl+C */
|
||||||
|
ctrlC: () => {
|
||||||
|
ws.send({
|
||||||
|
requestId: `ssh_${props.id}`,
|
||||||
|
type: 'ctrl-c',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div ref="terminalDom" :id="id" class="terminal"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="css" scoped>
|
||||||
|
.terminal {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -119,7 +119,7 @@ function fnAutoCompleteKeydown(evt: any) {
|
|||||||
ws.send({
|
ws.send({
|
||||||
requestId: `telnet_${props.hostId}`,
|
requestId: `telnet_${props.hostId}`,
|
||||||
type: 'telnet',
|
type: 'telnet',
|
||||||
data: `${cmdStr}\r\n'`,
|
data: `${cmdStr}\r\n`,
|
||||||
});
|
});
|
||||||
terminalState.text = ' ';
|
terminalState.text = ' ';
|
||||||
|
|
||||||
@@ -155,6 +155,15 @@ function handleRanderXterm(container: HTMLElement | undefined) {
|
|||||||
// 自适应尺寸
|
// 自适应尺寸
|
||||||
const fitAddon = new FitAddon();
|
const fitAddon = new FitAddon();
|
||||||
xterm.loadAddon(fitAddon);
|
xterm.loadAddon(fitAddon);
|
||||||
|
// 终端尺寸变化触发
|
||||||
|
xterm.onResize(({ cols, rows }) => {
|
||||||
|
// console.log('尺寸', cols, rows);
|
||||||
|
ws.send({
|
||||||
|
requestId: `telnet_resize_${props.hostId}`,
|
||||||
|
type: 'telnet_resize',
|
||||||
|
data: { cols, rows },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// 创建 ResizeObserver 实例
|
// 创建 ResizeObserver 实例
|
||||||
var observer = new ResizeObserver(entries => {
|
var observer = new ResizeObserver(entries => {
|
||||||
@@ -280,7 +289,7 @@ defineExpose({
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="terminal">
|
<div class="terminal">
|
||||||
<div ref="terminalDom" style="height: 78%" :id="id"></div>
|
<div ref="terminalDom" style="height: calc(100% - 36px)" :id="id"></div>
|
||||||
<a-auto-complete
|
<a-auto-complete
|
||||||
v-model:value="terminalState.text"
|
v-model:value="terminalState.text"
|
||||||
:dropdown-match-select-width="500"
|
:dropdown-match-select-width="500"
|
||||||
|
|||||||
204
src/components/VirtualList/index.vue
Normal file
204
src/components/VirtualList/index.vue
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { reactive, ref, computed, unref, onUpdated, watchEffect } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
/**列表高度 */
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 300,
|
||||||
|
},
|
||||||
|
/**列表项高度 */
|
||||||
|
itemHeight: {
|
||||||
|
type: Number,
|
||||||
|
default: 30,
|
||||||
|
},
|
||||||
|
/**数据 */
|
||||||
|
data: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
/**预先兜底缓存数量 */
|
||||||
|
cache: {
|
||||||
|
type: Number,
|
||||||
|
default: 2,
|
||||||
|
},
|
||||||
|
/**是否动态加载 */
|
||||||
|
dynamic: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const state = reactive<any>({
|
||||||
|
start: 0,
|
||||||
|
end: 10,
|
||||||
|
scrollOffset: 0,
|
||||||
|
cacheData: [],
|
||||||
|
});
|
||||||
|
const virtualListRef = ref();
|
||||||
|
|
||||||
|
const getWrapperStyle = computed(() => {
|
||||||
|
const { height } = props;
|
||||||
|
return {
|
||||||
|
height: `${height}px`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const getInnerStyle = computed(() => {
|
||||||
|
return {
|
||||||
|
height: `${unref(getTotalHeight)}px`,
|
||||||
|
width: '100%',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const getListStyle = computed(() => {
|
||||||
|
return {
|
||||||
|
willChange: 'transform',
|
||||||
|
transform: `translateY(${state.scrollOffset}px)`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// 数据数量
|
||||||
|
const total = computed(() => {
|
||||||
|
return props.data.length;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 总体高度
|
||||||
|
const getTotalHeight = computed(() => {
|
||||||
|
if (!props.dynamic) return unref(total) * props.itemHeight;
|
||||||
|
return getCurrentTop(unref(total));
|
||||||
|
});
|
||||||
|
|
||||||
|
// 当前屏幕显示的数量
|
||||||
|
const clientCount = computed(() => {
|
||||||
|
return Math.ceil(props.height / props.itemHeight);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 当前屏幕显示的数据
|
||||||
|
const clientData = computed(() => {
|
||||||
|
return props.data.slice(state.start, state.end);
|
||||||
|
});
|
||||||
|
|
||||||
|
const onScroll = (e: any) => {
|
||||||
|
const { scrollTop } = e.target;
|
||||||
|
if (state.scrollOffset === scrollTop) return;
|
||||||
|
const { cache, dynamic, itemHeight } = props;
|
||||||
|
const cacheCount = Math.max(1, cache);
|
||||||
|
|
||||||
|
let startIndex = dynamic
|
||||||
|
? getStartIndex(scrollTop)
|
||||||
|
: Math.floor(scrollTop / itemHeight);
|
||||||
|
|
||||||
|
const endIndex = Math.max(
|
||||||
|
0,
|
||||||
|
Math.min(unref(total), startIndex + unref(clientCount) + cacheCount)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (startIndex > cacheCount) {
|
||||||
|
startIndex = startIndex - cacheCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 偏移量
|
||||||
|
const offset = dynamic
|
||||||
|
? getCurrentTop(startIndex)
|
||||||
|
: scrollTop - (scrollTop % itemHeight);
|
||||||
|
|
||||||
|
Object.assign(state, {
|
||||||
|
start: startIndex,
|
||||||
|
end: endIndex,
|
||||||
|
scrollOffset: offset,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 二分法去查找对应的index
|
||||||
|
const getStartIndex = (scrollTop = 0): number => {
|
||||||
|
let low = 0;
|
||||||
|
let high = state.cacheData.length - 1;
|
||||||
|
while (low <= high) {
|
||||||
|
const middle = low + Math.floor((high - low) / 2);
|
||||||
|
const middleTopValue = getCurrentTop(middle);
|
||||||
|
const middleBottomValue = getCurrentTop(middle + 1);
|
||||||
|
|
||||||
|
if (middleTopValue <= scrollTop && scrollTop <= middleBottomValue) {
|
||||||
|
return middle;
|
||||||
|
} else if (middleBottomValue < scrollTop) {
|
||||||
|
low = middle + 1;
|
||||||
|
} else if (middleBottomValue > scrollTop) {
|
||||||
|
high = middle - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Math.min(
|
||||||
|
unref(total) - unref(clientCount),
|
||||||
|
Math.floor(scrollTop / props.itemHeight)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCurrentTop = (index: number) => {
|
||||||
|
const lastIndex = state.cacheData.length - 1;
|
||||||
|
|
||||||
|
if (Object.hasOwn(state.cacheData, index)) {
|
||||||
|
return state.cacheData[index].top;
|
||||||
|
} else if (Object.hasOwn(state.cacheData, index - 1)) {
|
||||||
|
return state.cacheData[index - 1].bottom;
|
||||||
|
} else if (index > lastIndex) {
|
||||||
|
return (
|
||||||
|
state.cacheData[lastIndex].bottom +
|
||||||
|
Math.max(0, index - state.cacheData[lastIndex].index) * props.itemHeight
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return index * props.itemHeight;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onUpdated(() => {
|
||||||
|
if (!props.dynamic) return;
|
||||||
|
const childrenList = virtualListRef.value.children || [];
|
||||||
|
[...childrenList].forEach((node: any, index: number) => {
|
||||||
|
const height = node.getBoundingClientRect().height;
|
||||||
|
const currentIndex = state.start + index;
|
||||||
|
if (state.cacheData[currentIndex].height === height) return;
|
||||||
|
|
||||||
|
state.cacheData[currentIndex].height = height;
|
||||||
|
state.cacheData[currentIndex].top = getCurrentTop(currentIndex);
|
||||||
|
state.cacheData[currentIndex].bottom =
|
||||||
|
state.cacheData[currentIndex].top + state.cacheData[currentIndex].height;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
clientData.value.forEach((_, index) => {
|
||||||
|
const currentIndex = state.start + index;
|
||||||
|
if (Object.hasOwn(state.cacheData, currentIndex)) return;
|
||||||
|
state.cacheData[currentIndex] = {
|
||||||
|
top: currentIndex * props.itemHeight,
|
||||||
|
height: props.itemHeight,
|
||||||
|
bottom: (currentIndex + 1) * props.itemHeight,
|
||||||
|
index: currentIndex,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="virtual-list-wrapper"
|
||||||
|
ref="wrapperRef"
|
||||||
|
:style="getWrapperStyle"
|
||||||
|
@scroll="onScroll"
|
||||||
|
>
|
||||||
|
<div class="virtual-list-inner" ref="innerRef" :style="getInnerStyle">
|
||||||
|
<div class="virtual-list" :style="getListStyle" ref="virtualListRef">
|
||||||
|
<div v-for="(item, index) in clientData" :key="index + state.start">
|
||||||
|
<slot name="default" :item="item"></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="css" scoped>
|
||||||
|
.virtual-list-wrapper {
|
||||||
|
position: relative;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -3,3 +3,6 @@ export const APP_REQUEST_HEADER_CODE = 'X-App-Code';
|
|||||||
|
|
||||||
/**应用-请求头-系统版本 */
|
/**应用-请求头-系统版本 */
|
||||||
export const APP_REQUEST_HEADER_VERSION = 'X-App-Version';
|
export const APP_REQUEST_HEADER_VERSION = 'X-App-Version';
|
||||||
|
|
||||||
|
/**应用-请求数据-密钥 */
|
||||||
|
export const APP_DATA_API_KEY = 'T9ox2DCzpLfJIPzkH9pKhsOTMOEMJcFv';
|
||||||
|
|||||||
@@ -16,11 +16,12 @@ export const NE_TYPE_LIST = [
|
|||||||
'N3IWF',
|
'N3IWF',
|
||||||
'MOCNGW',
|
'MOCNGW',
|
||||||
'SMSC',
|
'SMSC',
|
||||||
|
'CBC',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 网元拓展包列表,默认顺序
|
* 网元拓展包列表,默认顺序
|
||||||
* IMS-adb/rtproxy/mf
|
* IMS-adb/kvdb/rtproxy/mf
|
||||||
* UDM-adb
|
* UDM-adb/kvdb
|
||||||
*/
|
*/
|
||||||
export const NE_EXPAND_LIST = ['ADB', 'RTPROXY', 'MF'];
|
export const NE_EXPAND_LIST = ['ADB', 'KVDB', 'RTPROXY', 'MF'];
|
||||||
|
|||||||
@@ -1,3 +1,12 @@
|
|||||||
|
/**响应-code加密数据 */
|
||||||
|
export const RESULT_CODE_ENCRYPT = 2;
|
||||||
|
|
||||||
|
/**响应-msg加密数据 */
|
||||||
|
export const RESULT_MSG_ENCRYPT: Record<string, string> = {
|
||||||
|
zh_CN: '加密!',
|
||||||
|
en_US: 'encrypt!',
|
||||||
|
};
|
||||||
|
|
||||||
/**响应-code正常成功 */
|
/**响应-code正常成功 */
|
||||||
export const RESULT_CODE_SUCCESS = 1;
|
export const RESULT_CODE_SUCCESS = 1;
|
||||||
|
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ export default {
|
|||||||
page403: 'No Access',
|
page403: 'No Access',
|
||||||
page404: 'Match Page Not Found',
|
page404: 'Match Page Not Found',
|
||||||
helpDoc: 'System User Documentation',
|
helpDoc: 'System User Documentation',
|
||||||
|
traceTaskHLR: 'Tracking Tasks HLR',
|
||||||
lockScreen: 'Lock Screen',
|
lockScreen: 'Lock Screen',
|
||||||
account: {
|
account: {
|
||||||
index: "Personal Center",
|
index: "Personal Center",
|
||||||
@@ -185,11 +186,11 @@ export default {
|
|||||||
helpDoc: 'Doc',
|
helpDoc: 'Doc',
|
||||||
},
|
},
|
||||||
rightContent: {
|
rightContent: {
|
||||||
|
alarm: "Active Alarms",
|
||||||
lock: "Lock Screen",
|
lock: "Lock Screen",
|
||||||
lockTip: "Confirmation of the lock screen?",
|
lockTip: "Confirmation of the lock screen?",
|
||||||
lockPasswd: "Unlock Password",
|
lockPasswd: "Unlock Password",
|
||||||
lockPasswdTip: "No password can be set",
|
lockPasswdTip: "No password can be set",
|
||||||
helpDoc: "System User Documentation",
|
|
||||||
fullscreen: "Full Screen",
|
fullscreen: "Full Screen",
|
||||||
logout: "Logout",
|
logout: "Logout",
|
||||||
profile: "Profile",
|
profile: "Profile",
|
||||||
@@ -569,6 +570,8 @@ export default {
|
|||||||
caller: "Caller",
|
caller: "Caller",
|
||||||
called: "Called",
|
called: "Called",
|
||||||
result: "Result",
|
result: "Result",
|
||||||
|
resultOk: "Success",
|
||||||
|
resultFail: "Fail",
|
||||||
delTip: "Confirm deletion of the data item numbered [{msg}]?",
|
delTip: "Confirm deletion of the data item numbered [{msg}]?",
|
||||||
exportTip: "Do you confirm to export the current query conditions of the CDR data? (Maximum 10,000 items can be exported.)",
|
exportTip: "Do you confirm to export the current query conditions of the CDR data? (Maximum 10,000 items can be exported.)",
|
||||||
smfChargingID: 'Charging ID',
|
smfChargingID: 'Charging ID',
|
||||||
@@ -658,6 +661,7 @@ export default {
|
|||||||
kpiEnable: 'Report',
|
kpiEnable: 'Report',
|
||||||
kpiTimer: 'Reporting Cycle',
|
kpiTimer: 'Reporting Cycle',
|
||||||
kpiTimerPlease: 'Please enter the reporting period (in seconds)',
|
kpiTimerPlease: 'Please enter the reporting period (in seconds)',
|
||||||
|
omcIP: 'OMC IP',
|
||||||
},
|
},
|
||||||
backConf: {
|
backConf: {
|
||||||
export: 'Config Export',
|
export: 'Config Export',
|
||||||
@@ -668,9 +672,8 @@ export default {
|
|||||||
local:'Local File',
|
local:'Local File',
|
||||||
localUpload:'Local Upload',
|
localUpload:'Local Upload',
|
||||||
exportTip:'Confirm that you want to export the network element configuration file?',
|
exportTip:'Confirm that you want to export the network element configuration file?',
|
||||||
exportMsg:'Exported successfully, please download from [Backup Management].',
|
exportMsg:'Exporting Network Element Configuration Information to a File Succeeded',
|
||||||
filePlease: "Please upload a file",
|
pathPlease: 'No Backup File Found',
|
||||||
fileNamePlease: 'Please select the server file',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
neHost: {
|
neHost: {
|
||||||
@@ -736,11 +739,11 @@ export default {
|
|||||||
upgrade: "Upgrade To New Version",
|
upgrade: "Upgrade To New Version",
|
||||||
upgradeTip: "Confirmed to upgrade to the new version?",
|
upgradeTip: "Confirmed to upgrade to the new version?",
|
||||||
upgradeTipEmpty: "There are currently no new versions available",
|
upgradeTipEmpty: "There are currently no new versions available",
|
||||||
upgradeTipEqual: "Current version is the same as the new version",
|
upgradeTipEqual: "The current version is the same as the new version, confirmed to update?",
|
||||||
rollback: 'Switch to previous version',
|
rollback: 'Switch to previous version',
|
||||||
rollbackTip: "Confirm switching to the previous version?",
|
rollbackTip: "Confirm switching to the previous version?",
|
||||||
rollbackTipEmpty: "There is currently no previous version available",
|
rollbackTipEmpty: "There is currently no previous version available",
|
||||||
rollbackTipEqual: 'The current version is the same as the previous version',
|
rollbackTipEqual: 'The current version is the same as the previous version, are you sure you want to make the switch?',
|
||||||
version: "Current Version",
|
version: "Current Version",
|
||||||
preVersion: "Previous Version",
|
preVersion: "Previous Version",
|
||||||
newVersion: "New Version",
|
newVersion: "New Version",
|
||||||
@@ -770,18 +773,38 @@ export default {
|
|||||||
uploadChangeOk: 'Network Element renewed license successfully and is being calibrated in the background!',
|
uploadChangeOk: 'Network Element renewed license successfully and is being calibrated in the background!',
|
||||||
uploadChangeFail: "Some network elements failed to update the license, please check whether the service terminal environment is available!",
|
uploadChangeFail: "Some network elements failed to update the license, please check whether the service terminal environment is available!",
|
||||||
},
|
},
|
||||||
neConfPara5G: {
|
neConfig: {
|
||||||
headerTip: 'Check and save the public parameter properties of the network element before performing the installation of the network element, and make sure that the latest parameter properties are applied.',
|
treeTitle: "Navigation Configuration",
|
||||||
headerTipToPage: 'Jump Installation',
|
treeSelectTip: "Select configuration item information in the left configuration navigation!",
|
||||||
save: 'Save',
|
neType: 'NE Type',
|
||||||
reload: 'Reload',
|
neTypePleace: "Please select the network element type",
|
||||||
title: 'Save Info',
|
noConfigData: "No data on configuration items",
|
||||||
sync: 'Sync to NE',
|
updateValue: "[ {num} ] parameter value modified successfully.",
|
||||||
syncNe: 'Select NE',
|
updateValueErr: "Attribute value modification failure",
|
||||||
syncNeDone: 'Synchronization to network element terminals complete',
|
updateItem: "Modify Index to {num}.",
|
||||||
saveOk: 'Save Success!',
|
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",
|
||||||
|
},
|
||||||
|
neConfigBackup: {
|
||||||
|
name: "Name",
|
||||||
|
downTip: 'Confirmed to download the backup file [{txt}]?',
|
||||||
|
title: "Modify Backup {txt}",
|
||||||
},
|
},
|
||||||
neQuickSetup: {
|
neQuickSetup: {
|
||||||
|
reloadPara5G: 'Reload',
|
||||||
stepPrev: 'Previous',
|
stepPrev: 'Previous',
|
||||||
stepPrevTip: 'Confirm that you want to abandon the current change and return to the previous step?',
|
stepPrevTip: 'Confirm that you want to abandon the current change and return to the previous step?',
|
||||||
stepNext: 'Next',
|
stepNext: 'Next',
|
||||||
@@ -831,7 +854,7 @@ export default {
|
|||||||
},
|
},
|
||||||
neUser: {
|
neUser: {
|
||||||
auth: {
|
auth: {
|
||||||
authInfo:'Authentication Info',
|
authInfo:' Authentication Info',
|
||||||
neTypePlease: 'Query network element Object',
|
neTypePlease: 'Query network element Object',
|
||||||
neType: 'UDM Object',
|
neType: 'UDM Object',
|
||||||
export: 'Export',
|
export: 'Export',
|
||||||
@@ -854,9 +877,10 @@ export default {
|
|||||||
imsiTip3: 'MSIN = Mobile Subscriber Identification Number, consisting of 10 equal digits.',
|
imsiTip3: 'MSIN = Mobile Subscriber Identification Number, consisting of 10 equal digits.',
|
||||||
amfTip: 'Authentication management field, maximum parameter length is 4',
|
amfTip: 'Authentication management field, maximum parameter length is 4',
|
||||||
algoIndexTip: 'Algorithm index, between 0 and 15',
|
algoIndexTip: 'Algorithm index, between 0 and 15',
|
||||||
kiTip: 'User signing key information, the maximum length of 32',
|
kiTip: 'User signing key information, the length can only be 32',
|
||||||
opcTip: 'The authentication key, OPC, is calculated from Ki and OP, OP is the root key of the operator, ki is the authentication key, and the maximum length is 32.',
|
opcTip: 'The authentication key, OPC, is calculated from Ki and OP, OP is the root key of the operator, ki is the authentication key, and the maximum length is 32.',
|
||||||
delSure:'Are you sure you want to delete the user with IMSI number: {imsi} ?',
|
delSure:'Are you sure you want to delete the user with IMSI number: {imsi} ?',
|
||||||
|
imsiConfirm:'The length of the IMSI must be 15',
|
||||||
},
|
},
|
||||||
sub: {
|
sub: {
|
||||||
subInfo:' Subscription Info',
|
subInfo:' Subscription Info',
|
||||||
@@ -874,8 +898,8 @@ export default {
|
|||||||
checkDel: 'Check Delete',
|
checkDel: 'Check Delete',
|
||||||
batchAddText: 'Batch Add',
|
batchAddText: 'Batch Add',
|
||||||
batchDelText: 'Batch Delete',
|
batchDelText: 'Batch Delete',
|
||||||
enable:'Enable',
|
enable:'Enabled',
|
||||||
disable:'Disable',
|
disable:'Disabled',
|
||||||
startIMSI: 'Start IMSI',
|
startIMSI: 'Start IMSI',
|
||||||
imsiTip: 'IMSI=MCC+MNC+MSIN',
|
imsiTip: 'IMSI=MCC+MNC+MSIN',
|
||||||
imsiTip1: 'MCC=Mobile Country Code, consisting of three digits.',
|
imsiTip1: 'MCC=Mobile Country Code, consisting of three digits.',
|
||||||
@@ -888,7 +912,8 @@ export default {
|
|||||||
micoTip: 'Signed MICO business flag bits',
|
micoTip: 'Signed MICO business flag bits',
|
||||||
rfspTip:'RFSP index, in NG-RAN, the index of a specific RRM configuration, parameter between 0 and 127',
|
rfspTip:'RFSP index, in NG-RAN, the index of a specific RRM configuration, parameter between 0 and 127',
|
||||||
ueTypeTip: 'Operator-defined subscriber UE Usage Type, integer, parameter between 0 and 127',
|
ueTypeTip: 'Operator-defined subscriber UE Usage Type, integer, parameter between 0 and 127',
|
||||||
epsFlagTip: 'Enable or disable 4G EPS service',
|
cnFlag: 'Whether to enable 5G Core Network service',
|
||||||
|
epsFlagTip: 'Whether to enable 4G EPS service',
|
||||||
contextIdTip: 'To sign up for an APN Context ID, you must select it from the APN Context list.',
|
contextIdTip: 'To sign up for an APN Context ID, you must select it from the APN Context list.',
|
||||||
apnContextTip: 'The list of APNs available to the phone, up to six, is defined in the HSS.',
|
apnContextTip: 'The list of APNs available to the phone, up to six, is defined in the HSS.',
|
||||||
staticIpTip: 'Specify the static IP address to be used by the cell phone user to access the Internet, and "-" means dynamic IP address is used.',
|
staticIpTip: 'Specify the static IP address to be used by the cell phone user to access the Internet, and "-" means dynamic IP address is used.',
|
||||||
@@ -1027,6 +1052,7 @@ export default {
|
|||||||
},
|
},
|
||||||
customTarget:{
|
customTarget:{
|
||||||
kpiId:' Custom Indicator',
|
kpiId:' Custom Indicator',
|
||||||
|
kpiIdTip:'This Ne has no custom indicators',
|
||||||
period:' Granularity',
|
period:' Granularity',
|
||||||
title:' Custom Indicator Title',
|
title:' Custom Indicator Title',
|
||||||
objectType:' Object type',
|
objectType:' Object type',
|
||||||
@@ -1038,6 +1064,13 @@ export default {
|
|||||||
addCustom:' Add custom indicator',
|
addCustom:' Add custom indicator',
|
||||||
editCustom:' Edit Custom indicator',
|
editCustom:' Edit Custom indicator',
|
||||||
errorCustomInfo: 'Failed to get information',
|
errorCustomInfo: 'Failed to get information',
|
||||||
|
status: 'Status',
|
||||||
|
active:'Active',
|
||||||
|
inactive:'Inactive',
|
||||||
|
symbol:'Symbol',
|
||||||
|
element:'Element',
|
||||||
|
granularity:'Granularity',
|
||||||
|
unit:'Unit',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
traceManage: {
|
traceManage: {
|
||||||
@@ -1063,18 +1096,23 @@ export default {
|
|||||||
pcap: {
|
pcap: {
|
||||||
capArgPlease: 'Please enter tcpdump -i any support parameter',
|
capArgPlease: 'Please enter tcpdump -i any support parameter',
|
||||||
cmd: 'Command',
|
cmd: 'Command',
|
||||||
execCmd: "Generic tcpdump packet capture command",
|
execCmd: "Common Command Options",
|
||||||
execCmdsSctp: "Generic tcpdump filter sctp and port commands",
|
execCmd2: "Filter Protocol Port Command",
|
||||||
execUPFCmdA: 'Suitable for anomalous packet capture of other NE',
|
execCmd3: "File Split By Time units of seconds (-G 10), Generated Max File Number (-W 7)",
|
||||||
execUPFCmdB: 'Suitable for UPF anomaly packet capture analysis',
|
execUPFCmdA: 'Standard Edition - UPF with other NE anomalous packet capture analysis',
|
||||||
|
execUPFCmdB: 'Standard Edition - UPF anomalies requiring packet capture analysis',
|
||||||
|
batchOper: 'Batch Operations',
|
||||||
|
batchStartText: 'Batch Start',
|
||||||
|
batchStopText: 'Batch Stop',
|
||||||
|
batchDownText: 'Batch Download',
|
||||||
|
fileView: 'Historical Packet Capture Files',
|
||||||
|
fileUPF: 'Standard Edition',
|
||||||
|
fileUPFTip: 'UPF internal packet capture and analysis packet',
|
||||||
textStart: "Start",
|
textStart: "Start",
|
||||||
textStartBatch: "Batch Start",
|
|
||||||
textStop: "Stop",
|
textStop: "Stop",
|
||||||
textStopBatch: "Batch Stop",
|
|
||||||
textLog: "Log",
|
textLog: "Log",
|
||||||
textLogMsg: "Log Info",
|
textLogMsg: "Log Info",
|
||||||
textDown: "Download",
|
textDown: "Download",
|
||||||
textDownBatch: "Batch Download",
|
|
||||||
downTip: "Are you sure you want to download the {title} capture data file?",
|
downTip: "Are you sure you want to download the {title} capture data file?",
|
||||||
downOk: "{title} file download complete",
|
downOk: "{title} file download complete",
|
||||||
downErr: "{title} file download exception",
|
downErr: "{title} file download exception",
|
||||||
@@ -1088,12 +1126,13 @@ export default {
|
|||||||
stopNotRun: "{title} not running",
|
stopNotRun: "{title} not running",
|
||||||
},
|
},
|
||||||
task: {
|
task: {
|
||||||
neTypePlease: 'Query network element type',
|
traceId: 'Tracing No',
|
||||||
neType: 'NE Type',
|
|
||||||
neID: 'NE ID',
|
|
||||||
trackType: 'Tracing Type',
|
trackType: 'Tracing Type',
|
||||||
trackTypePlease: 'Please select a tracing type',
|
trackTypePlease: 'Please select a tracing type',
|
||||||
creater: 'Created by',
|
creater: 'Created by',
|
||||||
|
textStop: "Stop",
|
||||||
|
status: 'Status',
|
||||||
|
time: 'Time',
|
||||||
startTime: 'Start Time',
|
startTime: 'Start Time',
|
||||||
endTime: 'End Time',
|
endTime: 'End Time',
|
||||||
msisdn: 'MSISDN',
|
msisdn: 'MSISDN',
|
||||||
@@ -1103,26 +1142,31 @@ export default {
|
|||||||
imsiPlease: 'Please enter IMSI',
|
imsiPlease: 'Please enter IMSI',
|
||||||
imsiTip: 'Mobile communication IMSI number',
|
imsiTip: 'Mobile communication IMSI number',
|
||||||
srcIp: 'Source IP Address',
|
srcIp: 'Source IP Address',
|
||||||
srcIpPlease: 'Please enter the source IP address',
|
srcIpPlease: 'Please enter the IP address',
|
||||||
srcIpTip: 'Current sender IPv4 address',
|
srcIpTip: 'Current sender IPv4 address',
|
||||||
dstIp: 'Destination IP Address',
|
dstIp: 'Destination IP Address',
|
||||||
dstIpPlease: 'Please enter the destination IP address',
|
dstIpPlease: 'Please enter the IP address',
|
||||||
dstIpTip: 'IPv4 address of the receiving end of the other party',
|
dstIpTip: 'IPv4 address of the receiving end of the other party',
|
||||||
interfaces: 'Signaling Interface',
|
interfaces: 'Signaling Interface',
|
||||||
interfacesPlease: 'Please enter the signaling interface',
|
interfacesPlease: 'Please enter the signaling interface',
|
||||||
signalPort: 'Signal Port',
|
signalPort: 'Signal Port',
|
||||||
signalPortPlease: 'Please enter the signaling port',
|
signalPortPlease: 'Please enter the signaling port',
|
||||||
signalPortTip: 'Port corresponding to the interface',
|
signalPortTip: 'Port of the side corresponding to the destination IP address or source IP address',
|
||||||
rangePicker: 'Start/End Time',
|
rangePicker: 'Start/End Time',
|
||||||
rangePickerPlease: 'Please select the start and end time of the task',
|
rangePickerPlease: 'Please select the start and end time of the task',
|
||||||
comment: 'Task Description',
|
remark: 'Remark',
|
||||||
commentPlease: 'Task description can be entered',
|
remarkPlease: 'Task description can be entered',
|
||||||
addTask: 'Add Task',
|
addTask: 'Add Task',
|
||||||
editTask: 'Modify Task',
|
editTask: 'Modify Task',
|
||||||
viewTask: 'View Task',
|
viewTask: 'View Task',
|
||||||
errorTaskInfo: 'Failed to obtain task information',
|
errorTaskInfo: 'Failed to obtain task information',
|
||||||
delTask: 'Successfully deleted task {num}',
|
delTaskTip: 'Are you sure to delete the data item with record ID {id} ?',
|
||||||
delTaskTip: 'Are you sure to delete the data item with record number {num}?',
|
stopTask: 'Successful cessation of tasks {id}',
|
||||||
|
stopTaskTip: 'Confirm stopping the task with record ID {id} ?',
|
||||||
|
pcapView: "Tracking Data Analysis",
|
||||||
|
traceFile: "Tracking File",
|
||||||
|
errMsg: "Error Message",
|
||||||
|
imsiORmsisdn: "imsi or msisdn is null, cannot start task",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
faultManage: {
|
faultManage: {
|
||||||
@@ -1235,7 +1279,20 @@ export default {
|
|||||||
downTip: "Confirm the download file name is [{fileName}] File?",
|
downTip: "Confirm the download file name is [{fileName}] File?",
|
||||||
downTipErr: "Failed to get file",
|
downTipErr: "Failed to get file",
|
||||||
dirCd: "Enter Dir",
|
dirCd: "Enter Dir",
|
||||||
|
viewAs: 'View Action',
|
||||||
|
reload: "Reload",
|
||||||
|
follow: 'Monitoring Content',
|
||||||
|
tailChar: 'End Characters',
|
||||||
|
tailLines: 'End Lines',
|
||||||
},
|
},
|
||||||
|
exportFile:{
|
||||||
|
fileName:'File Source',
|
||||||
|
downTip: "Confirm the download file name is [{fileName}] File?",
|
||||||
|
downTipErr: "Failed to get file",
|
||||||
|
deleteTip: "Confirm the delete file name is [{fileName}] File?",
|
||||||
|
deleteTipErr: "Failed to delete file",
|
||||||
|
selectTip:"Please select File Name",
|
||||||
|
}
|
||||||
},
|
},
|
||||||
monitor: {
|
monitor: {
|
||||||
session: {
|
session: {
|
||||||
@@ -1947,6 +2004,7 @@ export default {
|
|||||||
stepNeInfoStepNext: 'Confirm that you want to proceed to the next step to configure the parameters of the network element?',
|
stepNeInfoStepNext: 'Confirm that you want to proceed to the next step to configure the parameters of the network element?',
|
||||||
stepPara5GTitle: "Configuration Parameter",
|
stepPara5GTitle: "Configuration Parameter",
|
||||||
stepPara5GDesc: "Setting network element global parameter information",
|
stepPara5GDesc: "Setting network element global parameter information",
|
||||||
|
savePara5GOk: 'Save Success!',
|
||||||
stepPara5GStepPrev: 'Confirm that you want to abandon the current change and return to the previous step?',
|
stepPara5GStepPrev: 'Confirm that you want to abandon the current change and return to the previous step?',
|
||||||
stepPara5GStepNext: 'Confirm that you want to proceed to the next step for the network element service installation?',
|
stepPara5GStepNext: 'Confirm that you want to proceed to the next step for the network element service installation?',
|
||||||
stepInstallTitle: "Service Install",
|
stepInstallTitle: "Service Install",
|
||||||
@@ -2047,6 +2105,30 @@ export default {
|
|||||||
hostSelectMore: "Load More {num}",
|
hostSelectMore: "Load More {num}",
|
||||||
hostSelectHeader: "Host List",
|
hostSelectHeader: "Host List",
|
||||||
},
|
},
|
||||||
|
ps:{
|
||||||
|
realTimeHigh:"High",
|
||||||
|
realTimeLow:"Low",
|
||||||
|
realTimeRegular:"Regular",
|
||||||
|
realTimeStop:"Stop",
|
||||||
|
realTime:"Real Time Speed",
|
||||||
|
pid:"PID",
|
||||||
|
name:"APP Name",
|
||||||
|
username:"User Name",
|
||||||
|
runTime:"Run Time",
|
||||||
|
numThreads:"Thread",
|
||||||
|
cpuPercent:"CPU Percent",
|
||||||
|
diskRead:"Disk Read",
|
||||||
|
diskWrite:"Disk Write",
|
||||||
|
},
|
||||||
|
net:{
|
||||||
|
PID:"PID",
|
||||||
|
name:"name",
|
||||||
|
localAddr:"localAddr",
|
||||||
|
remoteAddr:"remoteAddr",
|
||||||
|
status:"status",
|
||||||
|
type:"type",
|
||||||
|
port:"port",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ export default {
|
|||||||
page403: '没有访问权限',
|
page403: '没有访问权限',
|
||||||
page404: '找不到匹配页面',
|
page404: '找不到匹配页面',
|
||||||
helpDoc: '系统使用文档',
|
helpDoc: '系统使用文档',
|
||||||
|
traceTaskHLR: '跟踪任务 HLR',
|
||||||
lockScreen: '锁屏',
|
lockScreen: '锁屏',
|
||||||
account: {
|
account: {
|
||||||
index: "个人中心",
|
index: "个人中心",
|
||||||
@@ -185,11 +186,11 @@ export default {
|
|||||||
helpDoc: '使用手册',
|
helpDoc: '使用手册',
|
||||||
},
|
},
|
||||||
rightContent: {
|
rightContent: {
|
||||||
|
alarm: "活动告警",
|
||||||
lock: "锁屏",
|
lock: "锁屏",
|
||||||
lockTip: "确认要进行锁屏吗?",
|
lockTip: "确认要进行锁屏吗?",
|
||||||
lockPasswd: "解锁密码",
|
lockPasswd: "解锁密码",
|
||||||
lockPasswdTip: "可不设置密码",
|
lockPasswdTip: "可不设置密码",
|
||||||
helpDoc: "系统使用文档",
|
|
||||||
fullscreen: "全屏显示",
|
fullscreen: "全屏显示",
|
||||||
logout: "退出登录",
|
logout: "退出登录",
|
||||||
profile: "个人中心",
|
profile: "个人中心",
|
||||||
@@ -569,6 +570,8 @@ export default {
|
|||||||
caller: "主叫",
|
caller: "主叫",
|
||||||
called: "被叫",
|
called: "被叫",
|
||||||
result: "结果",
|
result: "结果",
|
||||||
|
resultOk: "成功",
|
||||||
|
resultFail: "失败",
|
||||||
delTip: "确认删除编号为【{msg}】的数据项?",
|
delTip: "确认删除编号为【{msg}】的数据项?",
|
||||||
exportTip: "确认导出当前查询条件的话单数据吗?(导出最大支持一万条)",
|
exportTip: "确认导出当前查询条件的话单数据吗?(导出最大支持一万条)",
|
||||||
smfChargingID: '计费ID',
|
smfChargingID: '计费ID',
|
||||||
@@ -658,6 +661,7 @@ export default {
|
|||||||
kpiEnable: '上报',
|
kpiEnable: '上报',
|
||||||
kpiTimer: '上报周期',
|
kpiTimer: '上报周期',
|
||||||
kpiTimerPlease: '请输入上报周期(单位秒)',
|
kpiTimerPlease: '请输入上报周期(单位秒)',
|
||||||
|
omcIP: 'OMC IP',
|
||||||
},
|
},
|
||||||
backConf: {
|
backConf: {
|
||||||
export: '配置导出',
|
export: '配置导出',
|
||||||
@@ -668,9 +672,8 @@ export default {
|
|||||||
local:'本地文件',
|
local:'本地文件',
|
||||||
localUpload:'本地上传',
|
localUpload:'本地上传',
|
||||||
exportTip:'确认要导出网元配置信息到文件?',
|
exportTip:'确认要导出网元配置信息到文件?',
|
||||||
exportMsg:'导出成功,请到【备份管理】进行下载',
|
exportMsg:'导出网元配置信息到文件成功',
|
||||||
filePlease: "请上传文件",
|
pathPlease: '未发现文件',
|
||||||
fileNamePlease: '请选择服务器文件',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
neHost: {
|
neHost: {
|
||||||
@@ -736,11 +739,11 @@ export default {
|
|||||||
upgrade: "升级到新版本",
|
upgrade: "升级到新版本",
|
||||||
upgradeTip: "确认要升级到新版本吗?",
|
upgradeTip: "确认要升级到新版本吗?",
|
||||||
upgradeTipEmpty: "当前没有可用的新版本",
|
upgradeTipEmpty: "当前没有可用的新版本",
|
||||||
upgradeTipEqual: "当前版本与新版本相同",
|
upgradeTipEqual: "当前版本与新版本相同,确认要进行更新吗?",
|
||||||
rollback: '切换到上一个版本',
|
rollback: '切换到上一个版本',
|
||||||
rollbackTip: "确认切换到上一个版本吗?",
|
rollbackTip: "确认切换到上一个版本吗?",
|
||||||
rollbackTipEmpty: "目前没有可用的上一个版本",
|
rollbackTipEmpty: "目前没有可用的上一个版本",
|
||||||
rollbackTipEqual: '当前版本与之前版本相同',
|
rollbackTipEqual: '当前版本与之前版本相同,确认要进行切换吗?',
|
||||||
version: "当前版本",
|
version: "当前版本",
|
||||||
preVersion: "上一个版本",
|
preVersion: "上一个版本",
|
||||||
newVersion: "新版本",
|
newVersion: "新版本",
|
||||||
@@ -770,18 +773,38 @@ export default {
|
|||||||
uploadChangeOk: '网元更新许可证成功,正在后台校验!',
|
uploadChangeOk: '网元更新许可证成功,正在后台校验!',
|
||||||
uploadChangeFail: "部分网元更新许可证失败,请检查服务终端环境是否可用!",
|
uploadChangeFail: "部分网元更新许可证失败,请检查服务终端环境是否可用!",
|
||||||
},
|
},
|
||||||
neConfPara5G: {
|
neConfig: {
|
||||||
headerTip: '进行网元安装前检查并保存网元公共参数属性,确认应用为最新参数属性',
|
treeTitle: "配置导航",
|
||||||
headerTipToPage: '跳转安装',
|
treeSelectTip: "左侧配置导航中选择配置项信息!",
|
||||||
save: '保存',
|
neType: "网元类型",
|
||||||
reload: '刷新',
|
neTypePleace: "请选择网元类型",
|
||||||
title: '保存信息',
|
noConfigData: "暂无配置项数据",
|
||||||
sync: '同步到网元',
|
updateValue: "【 {num} 】 属性值修改成功",
|
||||||
syncNe: '选择网元',
|
updateValueErr: "属性值修改失败",
|
||||||
syncNeDone: '同步到网元终端完成',
|
updateItem: "修改 Index 为 {num} 记录成功",
|
||||||
saveOk: '保存成功!',
|
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: "展开",
|
||||||
|
},
|
||||||
|
neConfigBackup: {
|
||||||
|
name: "名称",
|
||||||
|
downTip: '确认要下载备份文件【{txt}】吗?',
|
||||||
|
title: "修改备份信息 {txt}",
|
||||||
},
|
},
|
||||||
neQuickSetup: {
|
neQuickSetup: {
|
||||||
|
reloadPara5G: '刷新',
|
||||||
stepPrev: '上一步',
|
stepPrev: '上一步',
|
||||||
stepPrevTip: '确认要放弃当前变更返回上一步吗?',
|
stepPrevTip: '确认要放弃当前变更返回上一步吗?',
|
||||||
stepNext: '下一步',
|
stepNext: '下一步',
|
||||||
@@ -854,9 +877,10 @@ export default {
|
|||||||
imsiTip3: 'MSIN=移动客户识别码,采用等长10位数字构成',
|
imsiTip3: 'MSIN=移动客户识别码,采用等长10位数字构成',
|
||||||
amfTip: '鉴权管理域,参数最大长度为 4',
|
amfTip: '鉴权管理域,参数最大长度为 4',
|
||||||
algoIndexTip: '算法索引,介于0到15之间',
|
algoIndexTip: '算法索引,介于0到15之间',
|
||||||
kiTip: '用户签权密钥信息,最大长度为32',
|
kiTip: '用户签权密钥信息,长度只能是32',
|
||||||
opcTip: '鉴权秘钥,OPC是由Ki和OP经过计算得来的,OP为运营商的根秘钥,ki是鉴权秘钥,最大长度为32',
|
opcTip: '鉴权秘钥,OPC是由Ki和OP经过计算得来的,OP为运营商的根秘钥,ki是鉴权秘钥,最大长度为32',
|
||||||
delSure:'确认删除IMSI编号为: {imsi} 的用户吗?',
|
delSure:'确认删除IMSI编号为: {imsi} 的用户吗?',
|
||||||
|
imsiConfirm:'IMSI的长度必须为15',
|
||||||
},
|
},
|
||||||
sub: {
|
sub: {
|
||||||
subInfo:'签约信息',
|
subInfo:'签约信息',
|
||||||
@@ -888,7 +912,8 @@ export default {
|
|||||||
micoTip: '签约的 MICO 业务标志位',
|
micoTip: '签约的 MICO 业务标志位',
|
||||||
rfspTip:'RFSP 索引,在 NG-RAN 中,特定 RRM 配置的索引,参数介于0到127之间',
|
rfspTip:'RFSP 索引,在 NG-RAN 中,特定 RRM 配置的索引,参数介于0到127之间',
|
||||||
ueTypeTip: '运营商定义的用户 UE Usage Type,整型,参数介于0到127之间',
|
ueTypeTip: '运营商定义的用户 UE Usage Type,整型,参数介于0到127之间',
|
||||||
epsFlagTip: '是否开启4G EPS 服务',
|
cnFlag: '是否开启 5G Core Network 服务',
|
||||||
|
epsFlagTip: '是否开启 4G EPS 服务',
|
||||||
contextIdTip: '签约APN 上下文ID,必须从APN Context list 中选择。',
|
contextIdTip: '签约APN 上下文ID,必须从APN Context list 中选择。',
|
||||||
apnContextTip: '手机可用的APN列表,最多六个,在HSS中定义。',
|
apnContextTip: '手机可用的APN列表,最多六个,在HSS中定义。',
|
||||||
staticIpTip: '指定手机用户上网时使用的静态IP地址,为"-"时表示使用动态IP地址',
|
staticIpTip: '指定手机用户上网时使用的静态IP地址,为"-"时表示使用动态IP地址',
|
||||||
@@ -1027,6 +1052,7 @@ export default {
|
|||||||
},
|
},
|
||||||
customTarget:{
|
customTarget:{
|
||||||
kpiId:'自定义指标项',
|
kpiId:'自定义指标项',
|
||||||
|
kpiIdTip:'该网元没有自定义指标',
|
||||||
period:'颗粒度',
|
period:'颗粒度',
|
||||||
title:'自定义指标项标题',
|
title:'自定义指标项标题',
|
||||||
objectType:'对象类型',
|
objectType:'对象类型',
|
||||||
@@ -1038,6 +1064,13 @@ export default {
|
|||||||
addCustom:'添加自定义指标',
|
addCustom:'添加自定义指标',
|
||||||
editCustom:'编辑自定义指标',
|
editCustom:'编辑自定义指标',
|
||||||
errorCustomInfo: '获取信息失败',
|
errorCustomInfo: '获取信息失败',
|
||||||
|
status: '状态',
|
||||||
|
active:'正常',
|
||||||
|
inactive:'停用',
|
||||||
|
symbol:"符号",
|
||||||
|
element:'元素',
|
||||||
|
granularity:'颗粒度',
|
||||||
|
unit:'单位',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
traceManage: {
|
traceManage: {
|
||||||
@@ -1063,18 +1096,23 @@ export default {
|
|||||||
pcap: {
|
pcap: {
|
||||||
capArgPlease: '请输入tcpdump -i any支持参数',
|
capArgPlease: '请输入tcpdump -i any支持参数',
|
||||||
cmd: '命令',
|
cmd: '命令',
|
||||||
execCmd: "通用tcpdump抓包命令",
|
execCmd: "通用命令选项",
|
||||||
execCmdsSctp: "过滤sctp和port命令",
|
execCmd2: "过滤协议端口命令",
|
||||||
execUPFCmdA: '适合其他网元异常,UPF配合抓包的情况',
|
execCmd3: "分割文件按时间单位秒 (-G 10 ),最多生成文件数量 (-W 7)",
|
||||||
execUPFCmdB: '适合UPF异常需要抓包分析的情况',
|
execUPFCmdA: '标准版-UPF配合其他网元异常抓包分析',
|
||||||
|
execUPFCmdB: '标准版-UPF异常需要抓包分析',
|
||||||
|
batchOper: '批量操作',
|
||||||
|
batchStartText: '批量开始',
|
||||||
|
batchStopText: '批量停止',
|
||||||
|
batchDownText: '批量下载',
|
||||||
|
fileView: '历史抓包文件',
|
||||||
|
fileUPF: '标准版',
|
||||||
|
fileUPFTip: 'UPF内部抓包分析包',
|
||||||
textStart: "开始",
|
textStart: "开始",
|
||||||
textStartBatch: "批量开始",
|
|
||||||
textStop: "停止",
|
textStop: "停止",
|
||||||
textStopBatch: "批量停止",
|
|
||||||
textLog: "日志",
|
textLog: "日志",
|
||||||
textLogMsg: "日志信息",
|
textLogMsg: "日志信息",
|
||||||
textDown: "下载",
|
textDown: "下载",
|
||||||
textDownBatch: "批量下载",
|
|
||||||
downTip: "确认要下载 {title} 抓包数据文件吗?",
|
downTip: "确认要下载 {title} 抓包数据文件吗?",
|
||||||
downOk: "{title} 文件下载完成",
|
downOk: "{title} 文件下载完成",
|
||||||
downErr: "{title} 文件下载异常",
|
downErr: "{title} 文件下载异常",
|
||||||
@@ -1088,12 +1126,13 @@ export default {
|
|||||||
stopNotRun: "{title} 任务未运行",
|
stopNotRun: "{title} 任务未运行",
|
||||||
},
|
},
|
||||||
task: {
|
task: {
|
||||||
neTypePlease: '请选择网元类型',
|
traceId: '跟踪编号',
|
||||||
neType: '网元类型',
|
|
||||||
neID: '网元内部标识',
|
|
||||||
trackType: '跟踪类型',
|
trackType: '跟踪类型',
|
||||||
trackTypePlease: '请选择跟踪类型',
|
trackTypePlease: '请选择跟踪类型',
|
||||||
creater: '创建人',
|
creater: '创建人',
|
||||||
|
textStop: "停止",
|
||||||
|
status: '状态',
|
||||||
|
time: '时间',
|
||||||
startTime: '开始时间',
|
startTime: '开始时间',
|
||||||
endTime: '结束时间',
|
endTime: '结束时间',
|
||||||
msisdn: 'MSISDN',
|
msisdn: 'MSISDN',
|
||||||
@@ -1112,17 +1151,22 @@ export default {
|
|||||||
interfacesPlease: '请输入信令接口',
|
interfacesPlease: '请输入信令接口',
|
||||||
signalPort: '信令端口',
|
signalPort: '信令端口',
|
||||||
signalPortPlease: '请输入信令端口',
|
signalPortPlease: '请输入信令端口',
|
||||||
signalPortTip: '接口对应的端口',
|
signalPortTip: '目标IP地址或源IP地址对应一方的端口',
|
||||||
rangePicker: '开始结束时间',
|
rangePicker: '开始结束时间',
|
||||||
rangePickerPlease: '请选择任务时间开始结束时间',
|
rangePickerPlease: '请选择任务时间开始结束时间',
|
||||||
comment: '任务说明',
|
remark: '说明',
|
||||||
commentPlease: '可输入任务说明',
|
remarkPlease: '可输入任务说明',
|
||||||
addTask: '添加任务',
|
addTask: '添加任务',
|
||||||
editTask: '修改任务',
|
editTask: '修改任务',
|
||||||
viewTask: '查看任务',
|
viewTask: '查看任务',
|
||||||
errorTaskInfo: '获取任务信息失败',
|
errorTaskInfo: '获取任务信息失败',
|
||||||
delTask: '成功删除任务 {num}',
|
delTaskTip: '确认删除记录编号为 {id} 的数据项?',
|
||||||
delTaskTip: '确认删除记录编号为 {num} 的数据项?',
|
stopTask: '成功停止任务 {id}',
|
||||||
|
stopTaskTip: '确认停止记录编号为 {id} 的任务?',
|
||||||
|
pcapView: "跟踪数据分析",
|
||||||
|
traceFile: "跟踪文件",
|
||||||
|
errMsg: "错误信息",
|
||||||
|
imsiORmsisdn: "imsi 或 msisdn 是空值,不能开始任务",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
faultManage: {
|
faultManage: {
|
||||||
@@ -1235,7 +1279,20 @@ export default {
|
|||||||
downTip: "确认下载文件名为 【{fileName}】 文件?",
|
downTip: "确认下载文件名为 【{fileName}】 文件?",
|
||||||
downTipErr: "文件获取失败",
|
downTipErr: "文件获取失败",
|
||||||
dirCd: "进入目录",
|
dirCd: "进入目录",
|
||||||
|
viewAs: '查看操作',
|
||||||
|
reload: "重载",
|
||||||
|
follow: '监视内容变化',
|
||||||
|
tailChar: '末尾字数',
|
||||||
|
tailLines: '末尾行数',
|
||||||
},
|
},
|
||||||
|
exportFile:{
|
||||||
|
fileName:'文件来源',
|
||||||
|
downTip: "确认下载文件名为 【{fileName}】 文件?",
|
||||||
|
downTipErr: "文件获取失败",
|
||||||
|
deleteTip: "确认删除文件名为 【{fileName}】 文件?",
|
||||||
|
deleteTipErr: "文件删除失败",
|
||||||
|
selectTip:"请选择文件名",
|
||||||
|
}
|
||||||
},
|
},
|
||||||
monitor: {
|
monitor: {
|
||||||
session: {
|
session: {
|
||||||
@@ -1947,6 +2004,7 @@ export default {
|
|||||||
stepNeInfoStepNext: '确认要下一步进行网元配置参数?',
|
stepNeInfoStepNext: '确认要下一步进行网元配置参数?',
|
||||||
stepPara5GTitle: "网元配置参数",
|
stepPara5GTitle: "网元配置参数",
|
||||||
stepPara5GDesc: "设置网元全局参数信息",
|
stepPara5GDesc: "设置网元全局参数信息",
|
||||||
|
savePara5GOk: '保存成功!',
|
||||||
stepPara5GStepPrev: '确认要放弃当前变更返回上一步吗?',
|
stepPara5GStepPrev: '确认要放弃当前变更返回上一步吗?',
|
||||||
stepPara5GStepNext: '确认要下一步进行网元服务安装吗?',
|
stepPara5GStepNext: '确认要下一步进行网元服务安装吗?',
|
||||||
stepInstallTitle: "网元服务安装",
|
stepInstallTitle: "网元服务安装",
|
||||||
@@ -2047,6 +2105,30 @@ export default {
|
|||||||
hostSelectMore: "加载更多 {num}",
|
hostSelectMore: "加载更多 {num}",
|
||||||
hostSelectHeader: "主机列表",
|
hostSelectHeader: "主机列表",
|
||||||
},
|
},
|
||||||
|
ps:{
|
||||||
|
realTimeHigh:"高",
|
||||||
|
realTimeLow:"低",
|
||||||
|
realTimeRegular:"常规",
|
||||||
|
realTimeStop:"已暂停",
|
||||||
|
realTime:"实时更新速度",
|
||||||
|
pid:"PID",
|
||||||
|
name:"应用名称",
|
||||||
|
username:"用户名",
|
||||||
|
runTime:"运行时间",
|
||||||
|
numThreads:"线程数",
|
||||||
|
cpuPercent:"CPU使用率",
|
||||||
|
diskRead:"磁盘读取",
|
||||||
|
diskWrite:"磁盘写入",
|
||||||
|
},
|
||||||
|
net:{
|
||||||
|
PID:"PID",
|
||||||
|
name:"名称",
|
||||||
|
localAddr:"localAddr",
|
||||||
|
remoteAddr:"remoteAddr",
|
||||||
|
status:"状态",
|
||||||
|
type:"类型",
|
||||||
|
port:"接口",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ watch(
|
|||||||
// 路由地址含有内嵌地址标识又是隐藏菜单需要处理打开高亮菜单栏
|
// 路由地址含有内嵌地址标识又是隐藏菜单需要处理打开高亮菜单栏
|
||||||
if (v.path.includes(MENU_PATH_INLINE) && v.meta.hideInMenu) {
|
if (v.path.includes(MENU_PATH_INLINE) && v.meta.hideInMenu) {
|
||||||
const idx = v.path.lastIndexOf(MENU_PATH_INLINE);
|
const idx = v.path.lastIndexOf(MENU_PATH_INLINE);
|
||||||
layoutState.openKeys.splice(-1);
|
layoutState.openKeys = layoutState.selectedKeys.slice(0, -1);
|
||||||
layoutState.selectedKeys[matched.length - 1] = v.path.slice(0, idx);
|
layoutState.selectedKeys[matched.length - 1] = v.path.slice(0, idx);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -176,6 +176,7 @@ function fnCheckAppNameOverflow() {
|
|||||||
if (!text) return;
|
if (!text) return;
|
||||||
if (text.offsetWidth > container.offsetWidth) {
|
if (text.offsetWidth > container.offsetWidth) {
|
||||||
text.classList.add('app-name_scrollable');
|
text.classList.add('app-name_scrollable');
|
||||||
|
text.setAttribute('data-content', text.innerText);
|
||||||
} else {
|
} else {
|
||||||
text.classList.remove('app-name_scrollable');
|
text.classList.remove('app-name_scrollable');
|
||||||
}
|
}
|
||||||
@@ -342,11 +343,17 @@ onUnmounted(() => {
|
|||||||
:href="appStore.officialUrl"
|
:href="appStore.officialUrl"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
size="small"
|
size="small"
|
||||||
|
v-perms:has="['system:setting:official']"
|
||||||
v-if="appStore.officialUrl !== '#'"
|
v-if="appStore.officialUrl !== '#'"
|
||||||
>
|
>
|
||||||
{{ t('loayouts.basic.officialUrl') }}
|
{{ t('loayouts.basic.officialUrl') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button type="link" size="small" @click="fnClickHelpDoc()">
|
<a-button
|
||||||
|
type="link"
|
||||||
|
size="small"
|
||||||
|
v-perms:has="['system:setting:doc']"
|
||||||
|
@click="fnClickHelpDoc()"
|
||||||
|
>
|
||||||
{{ t('loayouts.basic.helpDoc') }}
|
{{ t('loayouts.basic.helpDoc') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-space>
|
</a-space>
|
||||||
@@ -382,20 +389,26 @@ onUnmounted(() => {
|
|||||||
// text-overflow: ellipsis;
|
// text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
width: 148px;
|
width: 148px;
|
||||||
|
> .app-name_scrollable {
|
||||||
&_scrollable {
|
padding-right: 12px;
|
||||||
// padding-left: 100%;
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
animation: scrollable-animation linear 6s infinite both;
|
animation: scrollable-animation linear 6s infinite both;
|
||||||
|
&::after {
|
||||||
|
content: attr(data-content);
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: -100%;
|
||||||
|
transition: right 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes scrollable-animation {
|
@keyframes scrollable-animation {
|
||||||
0% {
|
0% {
|
||||||
transform: translate3d(0, 0, 0);
|
transform: translateX(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
transform: translate3d(-100%, 0, 0);
|
transform: translateX(calc(-100% - 12px));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -422,7 +435,8 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
& #serverTimeDom {
|
& #serverTimeDom {
|
||||||
color: #00000085;
|
color: inherit;
|
||||||
|
opacity: 0.85;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,16 +57,6 @@ function fnClickAlarm() {
|
|||||||
router.push({ name: 'ActiveAlarm_2088' });
|
router.push({ name: 'ActiveAlarm_2088' });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**系统使用手册跳转 */
|
|
||||||
function fnClickHelpDoc(language?: string) {
|
|
||||||
const routeData = router.resolve({ name: 'HelpDoc' });
|
|
||||||
let href = routeData.href;
|
|
||||||
if (language) {
|
|
||||||
href = `${routeData.href}?language=${language}`;
|
|
||||||
}
|
|
||||||
window.open(href, '_blank');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**改变多语言 */
|
/**改变多语言 */
|
||||||
function fnChangeLocale(e: any) {
|
function fnChangeLocale(e: any) {
|
||||||
changeLocale(e.key);
|
changeLocale(e.key);
|
||||||
@@ -75,6 +65,8 @@ function fnChangeLocale(e: any) {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<a-space :size="12" align="center">
|
<a-space :size="12" align="center">
|
||||||
|
<a-tooltip placement="bottom">
|
||||||
|
<template #title>{{ t('loayouts.rightContent.alarm') }}</template>
|
||||||
<a-button type="text" style="color: inherit" @click="fnClickAlarm">
|
<a-button type="text" style="color: inherit" @click="fnClickAlarm">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<a-badge
|
<a-badge
|
||||||
@@ -87,8 +79,10 @@ function fnChangeLocale(e: any) {
|
|||||||
</a-badge>
|
</a-badge>
|
||||||
</template>
|
</template>
|
||||||
</a-button>
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
|
||||||
<!-- 锁屏操作 -->
|
<!-- 锁屏操作 -->
|
||||||
|
<span v-perms:has="['system:setting:lock']">
|
||||||
<a-tooltip placement="bottom">
|
<a-tooltip placement="bottom">
|
||||||
<template #title>{{ t('loayouts.rightContent.lock') }}</template>
|
<template #title>{{ t('loayouts.rightContent.lock') }}</template>
|
||||||
<a-button type="text" style="color: inherit" @click="fnClickLock()">
|
<a-button type="text" style="color: inherit" @click="fnClickLock()">
|
||||||
@@ -123,15 +117,7 @@ function fnChangeLocale(e: any) {
|
|||||||
</a-space>
|
</a-space>
|
||||||
</ProModal>
|
</ProModal>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
|
</span>
|
||||||
<a-tooltip placement="bottom">
|
|
||||||
<template #title>{{ t('loayouts.rightContent.helpDoc') }}</template>
|
|
||||||
<a-button type="text" style="color: inherit" @click="fnClickHelpDoc()">
|
|
||||||
<template #icon>
|
|
||||||
<QuestionCircleOutlined />
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</a-tooltip>
|
|
||||||
|
|
||||||
<a-tooltip placement="bottom">
|
<a-tooltip placement="bottom">
|
||||||
<template #title>{{ t('loayouts.rightContent.fullscreen') }}</template>
|
<template #title>{{ t('loayouts.rightContent.fullscreen') }}</template>
|
||||||
|
|||||||
@@ -13,10 +13,13 @@ import {
|
|||||||
import {
|
import {
|
||||||
APP_REQUEST_HEADER_CODE,
|
APP_REQUEST_HEADER_CODE,
|
||||||
APP_REQUEST_HEADER_VERSION,
|
APP_REQUEST_HEADER_VERSION,
|
||||||
|
APP_DATA_API_KEY,
|
||||||
} from '@/constants/app-constants';
|
} from '@/constants/app-constants';
|
||||||
import {
|
import {
|
||||||
|
RESULT_CODE_ENCRYPT,
|
||||||
RESULT_CODE_ERROR,
|
RESULT_CODE_ERROR,
|
||||||
RESULT_CODE_SUCCESS,
|
RESULT_CODE_SUCCESS,
|
||||||
|
RESULT_MSG_ENCRYPT,
|
||||||
RESULT_MSG_ERROR,
|
RESULT_MSG_ERROR,
|
||||||
RESULT_MSG_NOT_TYPE,
|
RESULT_MSG_NOT_TYPE,
|
||||||
RESULT_MSG_SERVER_ERROR,
|
RESULT_MSG_SERVER_ERROR,
|
||||||
@@ -25,11 +28,12 @@ import {
|
|||||||
RESULT_MSG_URL_NOTFOUND,
|
RESULT_MSG_URL_NOTFOUND,
|
||||||
RESULT_MSG_URL_RESUBMIT,
|
RESULT_MSG_URL_RESUBMIT,
|
||||||
} from '@/constants/result-constants';
|
} from '@/constants/result-constants';
|
||||||
|
import { decryptAES, encryptAES } from '@/utils/encrypt-utils';
|
||||||
|
|
||||||
/**响应结果类型 */
|
/**响应结果类型 */
|
||||||
export type ResultType = {
|
export type ResultType = {
|
||||||
/**响应码 */
|
/**响应码 */
|
||||||
code: number | 1 | 0;
|
code: number;
|
||||||
/**信息 */
|
/**信息 */
|
||||||
msg: string;
|
msg: string;
|
||||||
/**数据 */
|
/**数据 */
|
||||||
@@ -76,6 +80,8 @@ type OptionsType = {
|
|||||||
body?: BodyInit;
|
body?: BodyInit;
|
||||||
/**防止数据重复提交 */
|
/**防止数据重复提交 */
|
||||||
repeatSubmit?: boolean;
|
repeatSubmit?: boolean;
|
||||||
|
/**接口数据加密 */
|
||||||
|
crypto?: boolean;
|
||||||
/**携带授权Token请求头 */
|
/**携带授权Token请求头 */
|
||||||
whithToken?: boolean;
|
whithToken?: boolean;
|
||||||
/**中断控制信号,timeout不会生效 */
|
/**中断控制信号,timeout不会生效 */
|
||||||
@@ -165,26 +171,44 @@ function beforeRequest(options: OptionsType): OptionsType | Promise<any> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get请求拼接地址栏参数
|
// 请求拼接地址栏参数
|
||||||
if (options.method === 'get' && options.params) {
|
if (options.params) {
|
||||||
let paramStr = '';
|
|
||||||
const params = options.params;
|
const params = options.params;
|
||||||
|
const queryParams: string[] = [];
|
||||||
for (const key in params) {
|
for (const key in params) {
|
||||||
const value = params[key];
|
const value = params[key];
|
||||||
// 空字符或未定义的值不作为参数发送
|
// 空字符或未定义的值不作为参数发送
|
||||||
if (value === '' || value === undefined) continue;
|
if (value === '' || value === undefined) continue;
|
||||||
paramStr += `&${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
|
const str = `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
|
||||||
|
queryParams.push(str);
|
||||||
|
}
|
||||||
|
const paramStr = queryParams.join('&');
|
||||||
|
if (paramStr) {
|
||||||
|
const separator = options.url.includes('?') ? '&' : '?';
|
||||||
|
// 请求加密
|
||||||
|
if (options.crypto) {
|
||||||
|
debugger;
|
||||||
|
const data = encryptAES(JSON.stringify(paramStr), APP_DATA_API_KEY);
|
||||||
|
options.url += `${separator}data=${encodeURIComponent(data)}`;
|
||||||
|
} else {
|
||||||
|
options.url += `${separator}${paramStr}`;
|
||||||
}
|
}
|
||||||
if (paramStr && paramStr.startsWith('&')) {
|
|
||||||
options.url = `${options.url}?${paramStr.substring(1)}`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.method === 'get') return options;
|
||||||
|
|
||||||
// 非get参数提交
|
// 非get参数提交
|
||||||
if (options.data instanceof FormData) {
|
let body = options.data
|
||||||
options.body = options.data;
|
if (body instanceof FormData) {
|
||||||
} else {
|
options.body = body;
|
||||||
options.body = JSON.stringify(options.data);
|
} else if (body) {
|
||||||
|
// 请求加密
|
||||||
|
if (options.crypto) {
|
||||||
|
const data = encryptAES(JSON.stringify(body), APP_DATA_API_KEY);
|
||||||
|
body = { data };
|
||||||
|
}
|
||||||
|
options.body = JSON.stringify(body);
|
||||||
}
|
}
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
@@ -199,6 +223,28 @@ function interceptorResponse(res: ResultType): ResultType | Promise<any> {
|
|||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 响应数据解密
|
||||||
|
if (res.code === RESULT_CODE_ENCRYPT) {
|
||||||
|
const str = decryptAES(res.data, APP_DATA_API_KEY);
|
||||||
|
let data = {};
|
||||||
|
try {
|
||||||
|
data = JSON.parse(str);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
if (Object.keys(data).length === 0) {
|
||||||
|
return Promise.resolve({
|
||||||
|
code: RESULT_CODE_ERROR,
|
||||||
|
msg: RESULT_MSG_ENCRYPT[language],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve({
|
||||||
|
code: RESULT_CODE_SUCCESS,
|
||||||
|
msg: RESULT_MSG_SUCCESS[language],
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 风格处理
|
// 风格处理
|
||||||
if (!Reflect.has(res, 'code')) {
|
if (!Reflect.has(res, 'code')) {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
@@ -266,7 +312,7 @@ export async function request(options: OptionsType): Promise<ResultType> {
|
|||||||
case 'text': // 文本数据
|
case 'text': // 文本数据
|
||||||
const str = await res.text();
|
const str = await res.text();
|
||||||
return {
|
return {
|
||||||
code: 1,
|
code: RESULT_CODE_SUCCESS,
|
||||||
msg: str,
|
msg: str,
|
||||||
};
|
};
|
||||||
case 'json': // json格式数据
|
case 'json': // json格式数据
|
||||||
|
|||||||
124
src/plugins/wk-worker.ts
Normal file
124
src/plugins/wk-worker.ts
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
/**连接参数类型 */
|
||||||
|
export type OptionsType = {
|
||||||
|
/**
|
||||||
|
* 线路工作服务地址
|
||||||
|
*
|
||||||
|
* self.onmessage = error => {} - 接收消息
|
||||||
|
*
|
||||||
|
* self.postMessage() -回复消息
|
||||||
|
*/
|
||||||
|
url: string;
|
||||||
|
/**message事件的回调函数 */
|
||||||
|
onmessage: (data: any) => void;
|
||||||
|
/**error事件的回调函数 */
|
||||||
|
onerror: Function;
|
||||||
|
/**close事件的回调函数 */
|
||||||
|
onclose?: (code: number) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Web Worker 使用方法
|
||||||
|
*
|
||||||
|
* import { WK, OptionsType } from '@/plugins/wk-worker';
|
||||||
|
*
|
||||||
|
* const wk = new WK();
|
||||||
|
*
|
||||||
|
* 创建连接
|
||||||
|
* const options: OptionsType = { };
|
||||||
|
* wk.connect(options);
|
||||||
|
*
|
||||||
|
* 手动关闭
|
||||||
|
* wk.close();
|
||||||
|
*/
|
||||||
|
export class WK {
|
||||||
|
/**wk 实例 */
|
||||||
|
private wk: Worker | null = null;
|
||||||
|
/**wk 连接参数 */
|
||||||
|
private options: OptionsType | null = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数
|
||||||
|
* @param {object} params 构造函数参数
|
||||||
|
*/
|
||||||
|
constructor(options?: OptionsType) {
|
||||||
|
if (!window.Worker) {
|
||||||
|
// 检测浏览器支持
|
||||||
|
console.error('Sorry! Browser does not support Web Workers');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
options && this.connect(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建链接
|
||||||
|
* @param {object} options 连接参数
|
||||||
|
*/
|
||||||
|
public connect(options: OptionsType) {
|
||||||
|
this.options = options;
|
||||||
|
try {
|
||||||
|
const wk = new Worker(options.url);
|
||||||
|
// 用于收到来自其消息时的回调函数。
|
||||||
|
wk.onmessage = ev => {
|
||||||
|
// 解析文本消息
|
||||||
|
if (ev.type === 'message') {
|
||||||
|
try {
|
||||||
|
if (typeof options.onmessage === 'function') {
|
||||||
|
options.onmessage(ev.data);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('worker message formatting error', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 用于发生错误关闭后的回调函数。
|
||||||
|
wk.onmessageerror = ev => {
|
||||||
|
console.error('worker message error anomaly', ev);
|
||||||
|
|
||||||
|
if (typeof options.onclose === 'function') {
|
||||||
|
options.onerror(ev);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 用于发生错误后的回调函数。
|
||||||
|
wk.onerror = ev => {
|
||||||
|
console.error('worker error anomaly', ev);
|
||||||
|
|
||||||
|
if (typeof options.onerror === 'function') {
|
||||||
|
options.onerror(ev);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.wk = wk;
|
||||||
|
} catch (error) {
|
||||||
|
if (typeof options.onerror === 'function') {
|
||||||
|
options.onerror(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息
|
||||||
|
* @param data JSON数据
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
public send(data: Record<string, any>): boolean {
|
||||||
|
if (!this.wk) {
|
||||||
|
console.warn('worker unavailable');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.wk.postMessage(data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 手动关闭会被立即终止
|
||||||
|
public close() {
|
||||||
|
if (!this.wk) {
|
||||||
|
console.warn('worker unavailable');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.wk.terminate();
|
||||||
|
// 用于关闭后的回调函数。
|
||||||
|
if (this.options && typeof this.options.onclose === 'function') {
|
||||||
|
this.options.onclose(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,7 +27,7 @@ export type OptionsType = {
|
|||||||
/**
|
/**
|
||||||
* WebSocket 使用方法
|
* WebSocket 使用方法
|
||||||
*
|
*
|
||||||
* import WS from '@/plugins/ws-websocket.ts';
|
* import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||||
*
|
*
|
||||||
* const ws = new WS();
|
* const ws = new WS();
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -87,6 +87,12 @@ const constantRoutes: RouteRecordRaw[] = [
|
|||||||
meta: { title: 'router.helpDoc' },
|
meta: { title: 'router.helpDoc' },
|
||||||
component: () => import('@/views/tool/help/index.vue'),
|
component: () => import('@/views/tool/help/index.vue'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/trace-task-hlr',
|
||||||
|
name: 'TraceTaskHLR',
|
||||||
|
meta: { title: 'router.traceTaskHLR' },
|
||||||
|
component: () => import('@/views/traceManage/task-hlr/index.vue'),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/quick-start',
|
path: '/quick-start',
|
||||||
name: 'QuickStart',
|
name: 'QuickStart',
|
||||||
@@ -154,6 +160,7 @@ const WHITE_LIST: string[] = [
|
|||||||
'/help',
|
'/help',
|
||||||
'/register',
|
'/register',
|
||||||
'/quick-start',
|
'/quick-start',
|
||||||
|
'/trace-task-hlr',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**全局路由-前置守卫 */
|
/**全局路由-前置守卫 */
|
||||||
@@ -170,6 +177,10 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
if (appStore.bootloader && to.path !== '/quick-start') {
|
if (appStore.bootloader && to.path !== '/quick-start') {
|
||||||
next({ name: 'QuickStart' });
|
next({ name: 'QuickStart' });
|
||||||
}
|
}
|
||||||
|
// 不重复引导
|
||||||
|
if (!appStore.bootloader && to.path === '/quick-start') {
|
||||||
|
next({ name: 'Index' });
|
||||||
|
}
|
||||||
|
|
||||||
const token = getToken();
|
const token = getToken();
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { defineStore } from 'pinia';
|
|||||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
import { listAllNeInfo } from '@/api/ne/neInfo';
|
import { listAllNeInfo } from '@/api/ne/neInfo';
|
||||||
import { parseDataToOptions } from '@/utils/parse-tree-utils';
|
import { parseDataToOptions } from '@/utils/parse-tree-utils';
|
||||||
import { getNeTraceInterfaceAll } from '@/api/traceManage/task';
|
import { getNeTraceInterfaceAll } from '@/api/trace/task';
|
||||||
import { getNePerformanceList } from '@/api/perfManage/taskManage';
|
import { getNePerformanceList } from '@/api/perfManage/taskManage';
|
||||||
|
|
||||||
/**网元信息类型 */
|
/**网元信息类型 */
|
||||||
|
|||||||
50
src/utils/encrypt-utils.ts
Normal file
50
src/utils/encrypt-utils.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import CryptoJS from 'crypto-js';
|
||||||
|
import { isValid, decode } from 'js-base64';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AES 加密并转为 base64
|
||||||
|
* @param plaintext 数据字符串
|
||||||
|
* @param aeskey 密钥
|
||||||
|
* @returns 加密字符串
|
||||||
|
*/
|
||||||
|
export function encryptAES(plaintext: string, aeskey: string): string {
|
||||||
|
const nowRoaund = new Date().getTime().toString(6);
|
||||||
|
const key = CryptoJS.enc.Utf8.parse(aeskey);
|
||||||
|
const iv = CryptoJS.enc.Utf8.parse(nowRoaund);
|
||||||
|
const encrypted = CryptoJS.AES.encrypt(`${nowRoaund}${plaintext}`, key, {
|
||||||
|
iv: iv,
|
||||||
|
blockSize: 16,
|
||||||
|
mode: CryptoJS.mode.CBC,
|
||||||
|
padding: CryptoJS.pad.Pkcs7,
|
||||||
|
format: CryptoJS.format.OpenSSL,
|
||||||
|
});
|
||||||
|
return encrypted.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AES 解密
|
||||||
|
* @param ciphertext 加密字符串
|
||||||
|
* @param aeskey 密钥
|
||||||
|
* @returns 数据字符串
|
||||||
|
*/
|
||||||
|
export function decryptAES(ciphertext: string, aeskey: string): string {
|
||||||
|
const nowRoaund = new Date().getTime().toString(6);
|
||||||
|
const key = CryptoJS.enc.Utf8.parse(aeskey);
|
||||||
|
const iv = CryptoJS.enc.Utf8.parse(nowRoaund);
|
||||||
|
const decrypted = CryptoJS.AES.decrypt(ciphertext, key, {
|
||||||
|
iv: iv,
|
||||||
|
blockSize: 16,
|
||||||
|
mode: CryptoJS.mode.CBC,
|
||||||
|
padding: CryptoJS.pad.Pkcs7,
|
||||||
|
format: CryptoJS.format.OpenSSL,
|
||||||
|
});
|
||||||
|
const base64Str = decrypted.toString(CryptoJS.enc.Base64);
|
||||||
|
if (isValid(base64Str)) {
|
||||||
|
const str = decode(base64Str);
|
||||||
|
const idx = str.indexOf(':)', 10);
|
||||||
|
if (idx > 10) {
|
||||||
|
return str.substring(idx + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
@@ -37,7 +37,10 @@ export function parseStrLineToHump(str: string): string {
|
|||||||
*/
|
*/
|
||||||
export function parseStrHumpToLine(str: string): string {
|
export function parseStrHumpToLine(str: string): string {
|
||||||
if (!str) return str;
|
if (!str) return str;
|
||||||
return str.replace(/([A-Z])/g, '_$1').toLowerCase();
|
return str
|
||||||
|
.replace(/([A-Z])/g, '_$1')
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/^_/, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -92,6 +95,22 @@ export function parseObjLineToHump(obj: any): any {
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化文件大小
|
||||||
|
* @param bytes 字节数
|
||||||
|
* @param decimalPlaces 保留小数位,默认2位
|
||||||
|
* @returns 单位 xB
|
||||||
|
*/
|
||||||
|
export function parseSizeFromFile(bytes: number, decimalPlaces: number = 2) {
|
||||||
|
const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||||
|
let i = 0;
|
||||||
|
while (bytes >= 1024 && i < units.length - 1) {
|
||||||
|
bytes /= 1024;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return `${bytes.toFixed(decimalPlaces || 1)} ${units[i]}`;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转换磁盘容量
|
* 转换磁盘容量
|
||||||
* @param size 数值大小
|
* @param size 数值大小
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ let queryParams = reactive({
|
|||||||
/**网元类型 */
|
/**网元类型 */
|
||||||
neType: 'AMF',
|
neType: 'AMF',
|
||||||
neId: '001',
|
neId: '001',
|
||||||
eventType: 'auth-result',
|
eventType: '',
|
||||||
imsi: '',
|
imsi: '',
|
||||||
sortField: 'timestamp',
|
sortField: 'timestamp',
|
||||||
sortOrder: 'desc',
|
sortOrder: 'desc',
|
||||||
@@ -58,9 +58,9 @@ let queryParams = reactive({
|
|||||||
|
|
||||||
/**查询参数重置 */
|
/**查询参数重置 */
|
||||||
function fnQueryReset() {
|
function fnQueryReset() {
|
||||||
eventTypes.value = ['auth-result'];
|
eventTypes.value = [];
|
||||||
queryParams = Object.assign(queryParams, {
|
queryParams = Object.assign(queryParams, {
|
||||||
eventType: 'auth-result',
|
eventType: '',
|
||||||
imsi: '',
|
imsi: '',
|
||||||
startTime: '',
|
startTime: '',
|
||||||
endTime: '',
|
endTime: '',
|
||||||
@@ -74,7 +74,7 @@ function fnQueryReset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**记录类型 */
|
/**记录类型 */
|
||||||
const eventTypes = ref<string[]>(['auth-result']);
|
const eventTypes = ref<string[]>([]);
|
||||||
|
|
||||||
/**查询记录类型变更 */
|
/**查询记录类型变更 */
|
||||||
function fnQueryEventTypeChange(value: any) {
|
function fnQueryEventTypeChange(value: any) {
|
||||||
@@ -607,10 +607,7 @@ onBeforeUnmount(() => {
|
|||||||
:value="record.eventJSON.authCode"
|
:value="record.eventJSON.authCode"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span v-if="record.eventType === 'detach'">
|
||||||
v-if="record.eventType === 'detach'"
|
|
||||||
:title="record.eventJSON.detachTime"
|
|
||||||
>
|
|
||||||
<span>{{ t('views.dashboard.ue.resultOk') }}</span>
|
<span>{{ t('views.dashboard.ue.resultOk') }}</span>
|
||||||
</span>
|
</span>
|
||||||
<span v-if="record.eventType === 'cm-state'">
|
<span v-if="record.eventType === 'cm-state'">
|
||||||
@@ -706,7 +703,7 @@ onBeforeUnmount(() => {
|
|||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span v-if="record.eventType === 'detach'">
|
<span v-if="record.eventType === 'detach'">
|
||||||
{{ t('views.dashboard.ue.resultOK') }}
|
{{ t('views.dashboard.ue.resultOk') }}
|
||||||
</span>
|
</span>
|
||||||
<span v-if="record.eventType === 'cm-state'">
|
<span v-if="record.eventType === 'cm-state'">
|
||||||
<DictTag
|
<DictTag
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
RESULT_CODE_SUCCESS,
|
RESULT_CODE_SUCCESS,
|
||||||
} from '@/constants/result-constants';
|
} from '@/constants/result-constants';
|
||||||
import useDictStore from '@/store/modules/dict';
|
import useDictStore from '@/store/modules/dict';
|
||||||
|
import useNeInfoStore from '@/store/modules/neinfo';
|
||||||
import {
|
import {
|
||||||
delIMSDataCDR,
|
delIMSDataCDR,
|
||||||
exportIMSDataCDR,
|
exportIMSDataCDR,
|
||||||
@@ -36,6 +37,9 @@ let dict: {
|
|||||||
cdrCallType: [],
|
cdrCallType: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**网元可选 */
|
||||||
|
let neOtions = ref<Record<string, any>[]>([]);
|
||||||
|
|
||||||
/**开始结束时间 */
|
/**开始结束时间 */
|
||||||
let queryRangePicker = ref<[string, string]>(['', '']);
|
let queryRangePicker = ref<[string, string]>(['', '']);
|
||||||
|
|
||||||
@@ -44,7 +48,7 @@ let queryParams = reactive({
|
|||||||
/**网元类型 */
|
/**网元类型 */
|
||||||
neType: 'IMS',
|
neType: 'IMS',
|
||||||
neId: '001',
|
neId: '001',
|
||||||
recordType: 'MOC',
|
recordType: '',
|
||||||
callerParty: '',
|
callerParty: '',
|
||||||
calledParty: '',
|
calledParty: '',
|
||||||
sortField: 'timestamp',
|
sortField: 'timestamp',
|
||||||
@@ -61,9 +65,9 @@ let queryParams = reactive({
|
|||||||
|
|
||||||
/**查询参数重置 */
|
/**查询参数重置 */
|
||||||
function fnQueryReset() {
|
function fnQueryReset() {
|
||||||
recordTypes.value = ['MOC'];
|
recordTypes.value = [];
|
||||||
queryParams = Object.assign(queryParams, {
|
queryParams = Object.assign(queryParams, {
|
||||||
recordType: 'MOC',
|
recordType: '',
|
||||||
callerParty: '',
|
callerParty: '',
|
||||||
calledParty: '',
|
calledParty: '',
|
||||||
startTime: '',
|
startTime: '',
|
||||||
@@ -78,7 +82,7 @@ function fnQueryReset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**记录类型 */
|
/**记录类型 */
|
||||||
const recordTypes = ref<string[]>(['MOC']);
|
const recordTypes = ref<string[]>([]);
|
||||||
|
|
||||||
/**查询记录类型变更 */
|
/**查询记录类型变更 */
|
||||||
function fnQueryRecordTypeChange(value: any) {
|
function fnQueryRecordTypeChange(value: any) {
|
||||||
@@ -135,17 +139,6 @@ let tableColumns: ColumnsType = [
|
|||||||
align: 'left',
|
align: 'left',
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: t('views.dashboard.cdr.called'),
|
|
||||||
dataIndex: 'cdrJSON',
|
|
||||||
key: 'calledParty',
|
|
||||||
align: 'left',
|
|
||||||
width: 120,
|
|
||||||
customRender(opt) {
|
|
||||||
const cdrJSON = opt.value;
|
|
||||||
return cdrJSON.calledParty;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: t('views.dashboard.cdr.caller'),
|
title: t('views.dashboard.cdr.caller'),
|
||||||
dataIndex: 'cdrJSON',
|
dataIndex: 'cdrJSON',
|
||||||
@@ -157,6 +150,17 @@ let tableColumns: ColumnsType = [
|
|||||||
return cdrJSON.callerParty;
|
return cdrJSON.callerParty;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: t('views.dashboard.cdr.called'),
|
||||||
|
dataIndex: 'cdrJSON',
|
||||||
|
key: 'calledParty',
|
||||||
|
align: 'left',
|
||||||
|
width: 120,
|
||||||
|
customRender(opt) {
|
||||||
|
const cdrJSON = opt.value;
|
||||||
|
return cdrJSON.calledParty;
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: t('views.dashboard.cdr.duration'),
|
title: t('views.dashboard.cdr.duration'),
|
||||||
dataIndex: 'cdrJSON',
|
dataIndex: 'cdrJSON',
|
||||||
@@ -375,6 +379,7 @@ const realTimeData = ref<boolean>(false);
|
|||||||
function fnRealTime() {
|
function fnRealTime() {
|
||||||
realTimeData.value = !realTimeData.value;
|
realTimeData.value = !realTimeData.value;
|
||||||
if (realTimeData.value) {
|
if (realTimeData.value) {
|
||||||
|
tableState.seached = false;
|
||||||
// 建立链接
|
// 建立链接
|
||||||
const options: OptionsType = {
|
const options: OptionsType = {
|
||||||
url: '/ws',
|
url: '/ws',
|
||||||
@@ -383,7 +388,7 @@ function fnRealTime() {
|
|||||||
*
|
*
|
||||||
* IMS_CDR会话事件(GroupID:1005)
|
* IMS_CDR会话事件(GroupID:1005)
|
||||||
*/
|
*/
|
||||||
subGroupID: '1005',
|
subGroupID: `1005_${queryParams.neId}`,
|
||||||
},
|
},
|
||||||
onmessage: wsMessage,
|
onmessage: wsMessage,
|
||||||
onerror: wsError,
|
onerror: wsError,
|
||||||
@@ -391,6 +396,8 @@ function fnRealTime() {
|
|||||||
ws.connect(options);
|
ws.connect(options);
|
||||||
} else {
|
} else {
|
||||||
ws.close();
|
ws.close();
|
||||||
|
tableState.seached = true;
|
||||||
|
fnGetList(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,7 +420,7 @@ function wsMessage(res: Record<string, any>) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// cdrEvent CDR会话事件
|
// cdrEvent CDR会话事件
|
||||||
if (data.groupId === '1005') {
|
if (data.groupId === `1005_${queryParams.neId}`) {
|
||||||
const cdrEvent = data.data;
|
const cdrEvent = data.data;
|
||||||
queue.add(async () => {
|
queue.add(async () => {
|
||||||
modalState.maxId += 1;
|
modalState.maxId += 1;
|
||||||
@@ -436,14 +443,39 @@ function wsMessage(res: Record<string, any>) {
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 初始字典数据
|
// 初始字典数据
|
||||||
Promise.allSettled([getDict('cdr_sip_code'), getDict('cdr_call_type')])
|
Promise.allSettled([getDict('cdr_sip_code'), getDict('cdr_call_type')]).then(
|
||||||
.then(resArr => {
|
resArr => {
|
||||||
if (resArr[0].status === 'fulfilled') {
|
if (resArr[0].status === 'fulfilled') {
|
||||||
dict.cdrSipCode = resArr[0].value;
|
dict.cdrSipCode = resArr[0].value;
|
||||||
}
|
}
|
||||||
if (resArr[1].status === 'fulfilled') {
|
if (resArr[1].status === 'fulfilled') {
|
||||||
dict.cdrCallType = resArr[1].value;
|
dict.cdrCallType = resArr[1].value;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// 获取网元网元列表
|
||||||
|
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 === 'IMS') {
|
||||||
|
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(() => {
|
.finally(() => {
|
||||||
// 获取列表数据
|
// 获取列表数据
|
||||||
@@ -468,10 +500,57 @@ onBeforeUnmount(() => {
|
|||||||
<!-- 表格搜索栏 -->
|
<!-- 表格搜索栏 -->
|
||||||
<a-form :model="queryParams" name="queryParams" layout="horizontal">
|
<a-form :model="queryParams" name="queryParams" layout="horizontal">
|
||||||
<a-row :gutter="16">
|
<a-row :gutter="16">
|
||||||
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
|
<a-form-item label="IMS" name="neId ">
|
||||||
|
<a-select
|
||||||
|
v-model:value="queryParams.neId"
|
||||||
|
:options="neOtions"
|
||||||
|
:placeholder="t('common.selectPlease')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
|
<a-form-item
|
||||||
|
:label="t('views.dashboard.cdr.called')"
|
||||||
|
name="calledParty"
|
||||||
|
>
|
||||||
|
<a-input
|
||||||
|
v-model:value="queryParams.calledParty"
|
||||||
|
allow-clear
|
||||||
|
:placeholder="t('common.inputPlease')"
|
||||||
|
></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
|
<a-form-item
|
||||||
|
:label="t('views.dashboard.cdr.caller')"
|
||||||
|
name="callerParty "
|
||||||
|
>
|
||||||
|
<a-input
|
||||||
|
v-model:value="queryParams.callerParty"
|
||||||
|
allow-clear
|
||||||
|
:placeholder="t('common.inputPlease')"
|
||||||
|
></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-col :lg="8" :md="12" :xs="24">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label="t('views.dashboard.cdr.recordType')"
|
:label="t('views.dashboard.cdr.recordType')"
|
||||||
name="recordType "
|
name="recordType"
|
||||||
>
|
>
|
||||||
<a-select
|
<a-select
|
||||||
v-model:value="recordTypes"
|
v-model:value="recordTypes"
|
||||||
@@ -484,30 +563,6 @@ onBeforeUnmount(() => {
|
|||||||
></a-select>
|
></a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :lg="4" :md="12" :xs="24">
|
|
||||||
<a-form-item
|
|
||||||
:label="t('views.dashboard.cdr.called')"
|
|
||||||
name="calledParty "
|
|
||||||
>
|
|
||||||
<a-input
|
|
||||||
v-model:value="queryParams.calledParty"
|
|
||||||
allow-clear
|
|
||||||
:placeholder="t('common.inputPlease')"
|
|
||||||
></a-input>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
<a-col :lg="4" :md="12" :xs="24">
|
|
||||||
<a-form-item
|
|
||||||
:label="t('views.dashboard.cdr.caller')"
|
|
||||||
name="callerParty "
|
|
||||||
>
|
|
||||||
<a-input
|
|
||||||
v-model:value="queryParams.callerParty"
|
|
||||||
allow-clear
|
|
||||||
:placeholder="t('common.inputPlease')"
|
|
||||||
></a-input>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
<a-col :lg="8" :md="12" :xs="24">
|
<a-col :lg="8" :md="12" :xs="24">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label="t('views.dashboard.cdr.time')"
|
:label="t('views.dashboard.cdr.time')"
|
||||||
@@ -524,20 +579,6 @@ onBeforeUnmount(() => {
|
|||||||
></a-range-picker>
|
></a-range-picker>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</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-row>
|
</a-row>
|
||||||
</a-form>
|
</a-form>
|
||||||
</a-card>
|
</a-card>
|
||||||
@@ -595,6 +636,7 @@ onBeforeUnmount(() => {
|
|||||||
:checked-children="t('common.switch.show')"
|
:checked-children="t('common.switch.show')"
|
||||||
:un-checked-children="t('common.switch.hide')"
|
:un-checked-children="t('common.switch.hide')"
|
||||||
size="small"
|
size="small"
|
||||||
|
:disabled="realTimeData"
|
||||||
/>
|
/>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
@@ -639,7 +681,7 @@ onBeforeUnmount(() => {
|
|||||||
:data-source="tableState.data"
|
:data-source="tableState.data"
|
||||||
:size="tableState.size"
|
:size="tableState.size"
|
||||||
:pagination="tablePagination"
|
:pagination="tablePagination"
|
||||||
:scroll="{ x: tableColumns.length * 120, y: 'calc(100vh - 480px)' }"
|
:scroll="{ x: tableColumns.length * 150, y: 'calc(100vh - 480px)' }"
|
||||||
:row-selection="{
|
:row-selection="{
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
columnWidth: '48px',
|
columnWidth: '48px',
|
||||||
@@ -663,7 +705,7 @@ onBeforeUnmount(() => {
|
|||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span v-else>
|
<span v-else>
|
||||||
{{ t('views.dashboard.overview.userActivity.resultOK') }}
|
{{ t('views.dashboard.cdr.resultOk') }}
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="column.key === 'id'">
|
<template v-if="column.key === 'id'">
|
||||||
@@ -734,7 +776,7 @@ onBeforeUnmount(() => {
|
|||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span v-else>
|
<span v-else>
|
||||||
{{ t('views.dashboard.overview.userActivity.resultOK') }}
|
{{ t('views.dashboard.cdr.resultOk') }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
RESULT_CODE_SUCCESS,
|
RESULT_CODE_SUCCESS,
|
||||||
} from '@/constants/result-constants';
|
} from '@/constants/result-constants';
|
||||||
import useDictStore from '@/store/modules/dict';
|
import useDictStore from '@/store/modules/dict';
|
||||||
|
import useNeInfoStore from '@/store/modules/neinfo';
|
||||||
import { listMMEDataUE, delMMEDataUE, exportMMEDataUE } from '@/api/neData/mme';
|
import { listMMEDataUE, delMMEDataUE, exportMMEDataUE } from '@/api/neData/mme';
|
||||||
import { parseDateToStr } from '@/utils/date-utils';
|
import { parseDateToStr } from '@/utils/date-utils';
|
||||||
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||||
@@ -21,6 +22,9 @@ const { getDict } = useDictStore();
|
|||||||
const ws = new WS();
|
const ws = new WS();
|
||||||
const queue = new PQueue({ concurrency: 1, autoStart: true });
|
const queue = new PQueue({ concurrency: 1, autoStart: true });
|
||||||
|
|
||||||
|
/**网元可选 */
|
||||||
|
let neOtions = ref<Record<string, any>[]>([]);
|
||||||
|
|
||||||
/**字典数据 */
|
/**字典数据 */
|
||||||
let dict: {
|
let dict: {
|
||||||
/**UE 事件认证代码类型 */
|
/**UE 事件认证代码类型 */
|
||||||
@@ -43,7 +47,7 @@ let queryParams = reactive({
|
|||||||
/**网元类型 */
|
/**网元类型 */
|
||||||
neType: 'MME',
|
neType: 'MME',
|
||||||
neId: '001',
|
neId: '001',
|
||||||
eventType: 'auth-result',
|
eventType: '',
|
||||||
imsi: '',
|
imsi: '',
|
||||||
sortField: 'timestamp',
|
sortField: 'timestamp',
|
||||||
sortOrder: 'desc',
|
sortOrder: 'desc',
|
||||||
@@ -59,9 +63,9 @@ let queryParams = reactive({
|
|||||||
|
|
||||||
/**查询参数重置 */
|
/**查询参数重置 */
|
||||||
function fnQueryReset() {
|
function fnQueryReset() {
|
||||||
eventTypes.value = ['auth-result'];
|
eventTypes.value = [];
|
||||||
queryParams = Object.assign(queryParams, {
|
queryParams = Object.assign(queryParams, {
|
||||||
eventType: 'auth-result',
|
eventType: '',
|
||||||
imsi: '',
|
imsi: '',
|
||||||
startTime: '',
|
startTime: '',
|
||||||
endTime: '',
|
endTime: '',
|
||||||
@@ -75,7 +79,7 @@ function fnQueryReset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**记录类型 */
|
/**记录类型 */
|
||||||
const eventTypes = ref<string[]>(['auth-result']);
|
const eventTypes = ref<string[]>([]);
|
||||||
|
|
||||||
/**查询记录类型变更 */
|
/**查询记录类型变更 */
|
||||||
function fnQueryEventTypeChange(value: any) {
|
function fnQueryEventTypeChange(value: any) {
|
||||||
@@ -337,6 +341,7 @@ const realTimeData = ref<boolean>(false);
|
|||||||
function fnRealTime() {
|
function fnRealTime() {
|
||||||
realTimeData.value = !realTimeData.value;
|
realTimeData.value = !realTimeData.value;
|
||||||
if (realTimeData.value) {
|
if (realTimeData.value) {
|
||||||
|
tableState.seached = false;
|
||||||
// 建立链接
|
// 建立链接
|
||||||
const options: OptionsType = {
|
const options: OptionsType = {
|
||||||
url: '/ws',
|
url: '/ws',
|
||||||
@@ -345,7 +350,7 @@ function fnRealTime() {
|
|||||||
*
|
*
|
||||||
* MME_UE会话事件(GroupID:1011)
|
* MME_UE会话事件(GroupID:1011)
|
||||||
*/
|
*/
|
||||||
subGroupID: '1011',
|
subGroupID: `1011_${queryParams.neId}`,
|
||||||
},
|
},
|
||||||
onmessage: wsMessage,
|
onmessage: wsMessage,
|
||||||
onerror: wsError,
|
onerror: wsError,
|
||||||
@@ -353,6 +358,8 @@ function fnRealTime() {
|
|||||||
ws.connect(options);
|
ws.connect(options);
|
||||||
} else {
|
} else {
|
||||||
ws.close();
|
ws.close();
|
||||||
|
tableState.seached = true;
|
||||||
|
fnGetList(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,7 +382,7 @@ function wsMessage(res: Record<string, any>) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// ueEvent MME_UE会话事件
|
// ueEvent MME_UE会话事件
|
||||||
if (data.groupId === '1011') {
|
if (data.groupId === `1011_${queryParams.neId}`) {
|
||||||
const ueEvent = data.data;
|
const ueEvent = data.data;
|
||||||
queue.add(async () => {
|
queue.add(async () => {
|
||||||
modalState.maxId += 1;
|
modalState.maxId += 1;
|
||||||
@@ -403,17 +410,46 @@ onMounted(() => {
|
|||||||
getDict('ue_auth_code'),
|
getDict('ue_auth_code'),
|
||||||
getDict('ue_event_type'),
|
getDict('ue_event_type'),
|
||||||
getDict('ue_event_cm_state'),
|
getDict('ue_event_cm_state'),
|
||||||
])
|
]).then(resArr => {
|
||||||
.then(resArr => {
|
|
||||||
if (resArr[0].status === 'fulfilled') {
|
if (resArr[0].status === 'fulfilled') {
|
||||||
dict.ueAauthCode = resArr[0].value;
|
dict.ueAauthCode = resArr[0].value;
|
||||||
}
|
}
|
||||||
if (resArr[1].status === 'fulfilled') {
|
if (resArr[1].status === 'fulfilled') {
|
||||||
dict.ueEventType = resArr[1].value;
|
dict.ueEventType = resArr[1].value.map(item => {
|
||||||
|
if (item.value === 'cm-state') {
|
||||||
|
item.label = item.label.replace('CM', 'ECM');
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (resArr[2].status === 'fulfilled') {
|
if (resArr[2].status === 'fulfilled') {
|
||||||
dict.ueEventCmState = resArr[2].value;
|
dict.ueEventCmState = resArr[2].value;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取网元网元列表
|
||||||
|
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 === 'MME') {
|
||||||
|
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(() => {
|
.finally(() => {
|
||||||
// 获取列表数据
|
// 获取列表数据
|
||||||
@@ -438,6 +474,15 @@ onBeforeUnmount(() => {
|
|||||||
<!-- 表格搜索栏 -->
|
<!-- 表格搜索栏 -->
|
||||||
<a-form :model="queryParams" name="queryParams" layout="horizontal">
|
<a-form :model="queryParams" name="queryParams" layout="horizontal">
|
||||||
<a-row :gutter="16">
|
<a-row :gutter="16">
|
||||||
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
|
<a-form-item label="MME" name="neId ">
|
||||||
|
<a-select
|
||||||
|
v-model:value="queryParams.neId"
|
||||||
|
:options="neOtions"
|
||||||
|
:placeholder="t('common.selectPlease')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
<a-col :lg="6" :md="12" :xs="24">
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label="t('views.dashboard.ue.eventType')"
|
:label="t('views.dashboard.ue.eventType')"
|
||||||
@@ -548,6 +593,7 @@ onBeforeUnmount(() => {
|
|||||||
:checked-children="t('common.switch.show')"
|
:checked-children="t('common.switch.show')"
|
||||||
:un-checked-children="t('common.switch.hide')"
|
:un-checked-children="t('common.switch.hide')"
|
||||||
size="small"
|
size="small"
|
||||||
|
:disabled="realTimeData"
|
||||||
/>
|
/>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
@@ -670,7 +716,7 @@ onBeforeUnmount(() => {
|
|||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span v-if="record.eventType === 'detach'">
|
<span v-if="record.eventType === 'detach'">
|
||||||
{{ t('views.dashboard.ue.resultOK') }}
|
{{ t('views.dashboard.ue.resultOk') }}
|
||||||
</span>
|
</span>
|
||||||
<span v-if="record.eventType === 'cm-state'">
|
<span v-if="record.eventType === 'cm-state'">
|
||||||
<DictTag
|
<DictTag
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ function handleRanderChart(
|
|||||||
|
|
||||||
function fnChangeData(data: any[], itemID: string) {
|
function fnChangeData(data: any[], itemID: string) {
|
||||||
let info = data.find((item: any) => item.id === itemID);
|
let info = data.find((item: any) => item.id === itemID);
|
||||||
if (!info.neState.online) return;
|
if (!info || !info.neState.online) return;
|
||||||
// if (!info.neState.online) {
|
// if (!info.neState.online) {
|
||||||
// info = data.find((item: any) => item.id === itemID);
|
// info = data.find((item: any) => item.id === itemID);
|
||||||
// graphNodeClickID.value = itemID;
|
// graphNodeClickID.value = itemID;
|
||||||
@@ -251,36 +251,27 @@ function fnChangeData(data: any[], itemID: string) {
|
|||||||
let nfCpuUsage = 0;
|
let nfCpuUsage = 0;
|
||||||
if (info.neState.cpu) {
|
if (info.neState.cpu) {
|
||||||
nfCpuUsage = info.neState.cpu.nfCpuUsage;
|
nfCpuUsage = info.neState.cpu.nfCpuUsage;
|
||||||
if (nfCpuUsage > 100) {
|
|
||||||
const nfCpu = +(info.neState.cpu.nfCpuUsage / 100);
|
const nfCpu = +(info.neState.cpu.nfCpuUsage / 100);
|
||||||
if (nfCpu > 100) {
|
|
||||||
nfCpuUsage = 100;
|
|
||||||
} else {
|
|
||||||
nfCpuUsage = +nfCpu.toFixed(2);
|
nfCpuUsage = +nfCpu.toFixed(2);
|
||||||
}
|
if (nfCpuUsage > 100) {
|
||||||
|
nfCpuUsage = 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
sysCpuUsage = info.neState.cpu.sysCpuUsage;
|
sysCpuUsage = info.neState.cpu.sysCpuUsage;
|
||||||
if (sysCpuUsage > 100) {
|
let sysCpu = +(info.neState.cpu.sysCpuUsage / 100);
|
||||||
const sysCpu = +(info.neState.cpu.sysCpuUsage / 100);
|
|
||||||
if (sysCpu > 100) {
|
|
||||||
sysCpuUsage = 100;
|
|
||||||
} else {
|
|
||||||
sysCpuUsage = +sysCpu.toFixed(2);
|
sysCpuUsage = +sysCpu.toFixed(2);
|
||||||
}
|
if (sysCpuUsage > 100) {
|
||||||
|
sysCpuUsage = 100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let sysMemUsage = 0;
|
let sysMemUsage = 0;
|
||||||
if (info.neState.mem) {
|
if (info.neState.mem) {
|
||||||
let men = info.neState.mem.sysMemUsage;
|
const men = info.neState.mem.sysMemUsage;
|
||||||
if (men > 100) {
|
sysMemUsage = +(men / 100).toFixed(2);
|
||||||
men = +(men / 100).toFixed(2);
|
if (sysMemUsage > 100) {
|
||||||
|
sysMemUsage = 100;
|
||||||
}
|
}
|
||||||
if (men > 100) {
|
|
||||||
men = 100;
|
|
||||||
}
|
|
||||||
sysMemUsage = men;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let sysDiskUsage = 0;
|
let sysDiskUsage = 0;
|
||||||
|
|||||||
@@ -203,17 +203,14 @@ function handleRanderChart() {
|
|||||||
|
|
||||||
/**查询初始UPF数据 */
|
/**查询初始UPF数据 */
|
||||||
function fnGetInitData() {
|
function fnGetInitData() {
|
||||||
// 查询10分钟前的
|
// 查询5分钟前的
|
||||||
const nowDate: Date = new Date();
|
const nowDate = new Date().getTime();
|
||||||
const tenMinutesAgo = new Date(nowDate.getTime() - 5 * 60 * 1000);
|
|
||||||
|
|
||||||
listKPIData({
|
listKPIData({
|
||||||
neType: 'UPF',
|
neType: 'UPF',
|
||||||
neId: '001',
|
neId: '001',
|
||||||
startTime: parseDateToStr(tenMinutesAgo),
|
startTime: nowDate - 5 * 60 * 1000,
|
||||||
endTime: parseDateToStr(nowDate),
|
endTime: nowDate,
|
||||||
// startTime: '2024-03-20 19:50:00',
|
|
||||||
// endTime: '2024-03-20 19:55:00',
|
|
||||||
interval: 5, // 5秒
|
interval: 5, // 5秒
|
||||||
sortField: 'timeGroup',
|
sortField: 'timeGroup',
|
||||||
sortOrder: 'asc',
|
sortOrder: 'asc',
|
||||||
|
|||||||
@@ -186,7 +186,14 @@ onMounted(() => {
|
|||||||
<div class="card-ue-item">
|
<div class="card-ue-item">
|
||||||
<div>
|
<div>
|
||||||
{{ t('views.dashboard.overview.userActivity.type') }}:
|
{{ t('views.dashboard.overview.userActivity.type') }}:
|
||||||
<span>
|
<span v-if="item.type === 'cm-state'">
|
||||||
|
{{
|
||||||
|
dict.ueEventType
|
||||||
|
.find(s => s.value === item.type)
|
||||||
|
?.label.replace('CM', 'ECM')
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
<DictTag :options="dict.ueEventType" :value="item.type" />
|
<DictTag :options="dict.ueEventType" :value="item.type" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -159,14 +159,14 @@
|
|||||||
|
|
||||||
/* 概览区域 衍生基站信息 */
|
/* 概览区域 衍生基站信息 */
|
||||||
.skim.base {
|
.skim.base {
|
||||||
height: 20.6%;
|
height: 12%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skim.base .inner .data {
|
.skim.base .inner .data {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 45%;
|
height: 75%;
|
||||||
}
|
}
|
||||||
.skim.base .inner .data .item {
|
.skim.base .inner .data .item {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -178,7 +178,7 @@
|
|||||||
/* 用户行为 */
|
/* 用户行为 */
|
||||||
.userActivity {
|
.userActivity {
|
||||||
/* min-height: 35.8rem; */
|
/* min-height: 35.8rem; */
|
||||||
height: 60%;
|
height: 54.6%;
|
||||||
}
|
}
|
||||||
.userActivity .inner .chart {
|
.userActivity .inner .chart {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export const notNeNodes = [
|
|||||||
/**图状态 */
|
/**图状态 */
|
||||||
export const graphState = reactive<Record<string, any>>({
|
export const graphState = reactive<Record<string, any>>({
|
||||||
/**当前图组名 */
|
/**当前图组名 */
|
||||||
group: '5GC System Architecture5',
|
group: '5GC System Architecture',
|
||||||
/**图数据 */
|
/**图数据 */
|
||||||
data: {
|
data: {
|
||||||
combos: [],
|
combos: [],
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { parseDateToStr } from '@/utils/date-utils';
|
||||||
import { parseSizeFromBits, parseSizeFromKbs } from '@/utils/parse-utils';
|
import { parseSizeFromBits, parseSizeFromKbs } from '@/utils/parse-utils';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ export const upfFlowData = ref<FDType>({
|
|||||||
|
|
||||||
/**UPF-流量数据 数据解析 */
|
/**UPF-流量数据 数据解析 */
|
||||||
export function upfFlowParse(data: Record<string, string>) {
|
export function upfFlowParse(data: Record<string, string>) {
|
||||||
upfFlowData.value.lineXTime.push(data['timeGroup']);
|
upfFlowData.value.lineXTime.push(parseDateToStr(+data['timeGroup']));
|
||||||
const upN3 = parseSizeFromKbs(+data['UPF.03'], 5);
|
const upN3 = parseSizeFromKbs(+data['UPF.03'], 5);
|
||||||
upfFlowData.value.lineYUp.push(upN3[0]);
|
upfFlowData.value.lineYUp.push(upN3[0]);
|
||||||
const downN6 = parseSizeFromKbs(+data['UPF.06'], 5);
|
const downN6 = parseSizeFromKbs(+data['UPF.06'], 5);
|
||||||
|
|||||||
@@ -50,37 +50,37 @@ export default function useWS() {
|
|||||||
// 普通信息
|
// 普通信息
|
||||||
switch (requestId) {
|
switch (requestId) {
|
||||||
// AMF_UE会话事件
|
// AMF_UE会话事件
|
||||||
case '1010':
|
case 'amf_1010_001':
|
||||||
if (Array.isArray(data.rows)) {
|
if (Array.isArray(data.rows)) {
|
||||||
eventListParse('amf_ue', data);
|
eventListParse('amf_ue', data);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// MME_UE会话事件
|
// MME_UE会话事件
|
||||||
case '1011':
|
case 'mme_1011_001':
|
||||||
if (Array.isArray(data.rows)) {
|
if (Array.isArray(data.rows)) {
|
||||||
eventListParse('mme_ue', data);
|
eventListParse('mme_ue', data);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// IMS_CDR会话事件
|
// IMS_CDR会话事件
|
||||||
case '1005':
|
case 'ims_1005_001':
|
||||||
if (Array.isArray(data.rows)) {
|
if (Array.isArray(data.rows)) {
|
||||||
eventListParse('ims_cdr', data);
|
eventListParse('ims_cdr', data);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
//UPF-总流量数
|
//UPF-总流量数
|
||||||
case '1030_0':
|
case 'upf_001_0':
|
||||||
const v0 = upfTFParse(data);
|
const v0 = upfTFParse(data);
|
||||||
upfTotalFlow.value[0].up = v0.up;
|
upfTotalFlow.value[0].up = v0.up;
|
||||||
upfTotalFlow.value[0].down = v0.down;
|
upfTotalFlow.value[0].down = v0.down;
|
||||||
upfTotalFlow.value[0].requestFlag = false;
|
upfTotalFlow.value[0].requestFlag = false;
|
||||||
break;
|
break;
|
||||||
case '1030_7':
|
case 'upf_001_7':
|
||||||
const v7 = upfTFParse(data);
|
const v7 = upfTFParse(data);
|
||||||
upfTotalFlow.value[1].up = v7.up;
|
upfTotalFlow.value[1].up = v7.up;
|
||||||
upfTotalFlow.value[1].down = v7.down;
|
upfTotalFlow.value[1].down = v7.down;
|
||||||
upfTotalFlow.value[1].requestFlag = false;
|
upfTotalFlow.value[1].requestFlag = false;
|
||||||
break;
|
break;
|
||||||
case '1030_30':
|
case 'upf_001_30':
|
||||||
const v30 = upfTFParse(data);
|
const v30 = upfTFParse(data);
|
||||||
upfTotalFlow.value[2].up = v30.up;
|
upfTotalFlow.value[2].up = v30.up;
|
||||||
upfTotalFlow.value[2].down = v30.down;
|
upfTotalFlow.value[2].down = v30.down;
|
||||||
@@ -94,25 +94,25 @@ export default function useWS() {
|
|||||||
}
|
}
|
||||||
switch (data.groupId) {
|
switch (data.groupId) {
|
||||||
// kpiEvent 指标UPF
|
// kpiEvent 指标UPF
|
||||||
case '12':
|
case '12_001':
|
||||||
if (data.data) {
|
if (data.data) {
|
||||||
upfFlowParse(data.data);
|
upfFlowParse(data.data);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// AMF_UE会话事件
|
// AMF_UE会话事件
|
||||||
case '1010':
|
case '1010_001':
|
||||||
if (data.data) {
|
if (data.data) {
|
||||||
queue.add(() => eventItemParseAndPush('amf_ue', data.data));
|
queue.add(() => eventItemParseAndPush('amf_ue', data.data));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// MME_UE会话事件
|
// MME_UE会话事件
|
||||||
case '1011':
|
case '1011_001':
|
||||||
if (data.data) {
|
if (data.data) {
|
||||||
queue.add(() => eventItemParseAndPush('mme_ue', data.data));
|
queue.add(() => eventItemParseAndPush('mme_ue', data.data));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// IMS_CDR会话事件
|
// IMS_CDR会话事件
|
||||||
case '1005':
|
case '1005_001':
|
||||||
if (data.data) {
|
if (data.data) {
|
||||||
queue.add(() => eventItemParseAndPush('ims_cdr', data.data));
|
queue.add(() => eventItemParseAndPush('ims_cdr', data.data));
|
||||||
}
|
}
|
||||||
@@ -137,7 +137,7 @@ export default function useWS() {
|
|||||||
upfTotalFlow.value[index].requestFlag = true;
|
upfTotalFlow.value[index].requestFlag = true;
|
||||||
|
|
||||||
ws.send({
|
ws.send({
|
||||||
requestId: `1030_${day}`,
|
requestId: `upf_001_${day}`,
|
||||||
type: 'upf_tf',
|
type: 'upf_tf',
|
||||||
data: {
|
data: {
|
||||||
neType: 'UPF',
|
neType: 'UPF',
|
||||||
@@ -151,7 +151,7 @@ export default function useWS() {
|
|||||||
function userActivitySend() {
|
function userActivitySend() {
|
||||||
// AMF_UE会话事件
|
// AMF_UE会话事件
|
||||||
ws.send({
|
ws.send({
|
||||||
requestId: '1010',
|
requestId: 'amf_1010_001',
|
||||||
type: 'amf_ue',
|
type: 'amf_ue',
|
||||||
data: {
|
data: {
|
||||||
neType: 'AMF',
|
neType: 'AMF',
|
||||||
@@ -164,7 +164,7 @@ export default function useWS() {
|
|||||||
});
|
});
|
||||||
// MME_UE会话事件
|
// MME_UE会话事件
|
||||||
ws.send({
|
ws.send({
|
||||||
requestId: '1011',
|
requestId: 'mme_1011_001',
|
||||||
type: 'mme_ue',
|
type: 'mme_ue',
|
||||||
data: {
|
data: {
|
||||||
neType: 'MME',
|
neType: 'MME',
|
||||||
@@ -177,7 +177,7 @@ export default function useWS() {
|
|||||||
});
|
});
|
||||||
// IMS_CDR会话事件
|
// IMS_CDR会话事件
|
||||||
ws.send({
|
ws.send({
|
||||||
requestId: '1005',
|
requestId: 'ims_1005_001',
|
||||||
type: 'ims_cdr',
|
type: 'ims_cdr',
|
||||||
data: {
|
data: {
|
||||||
neType: 'IMS',
|
neType: 'IMS',
|
||||||
@@ -197,12 +197,12 @@ export default function useWS() {
|
|||||||
params: {
|
params: {
|
||||||
/**订阅通道组
|
/**订阅通道组
|
||||||
*
|
*
|
||||||
* 指标UPF (GroupID:12)
|
* 指标UPF (GroupID:12_neId)
|
||||||
* AMF_UE会话事件(GroupID:1010)
|
* AMF_UE会话事件(GroupID:1010_neId)
|
||||||
* MME_UE会话事件(GroupID:1011)
|
* MME_UE会话事件(GroupID:1011_neId)
|
||||||
* IMS_CDR会话事件(GroupID:1005)
|
* IMS_CDR会话事件(GroupID:1005_neId)
|
||||||
*/
|
*/
|
||||||
subGroupID: '12,1010,1011,1005',
|
subGroupID: '12_001,1010_001,1011_001,1005_001',
|
||||||
},
|
},
|
||||||
onmessage: wsMessage,
|
onmessage: wsMessage,
|
||||||
onerror: wsError,
|
onerror: wsError,
|
||||||
|
|||||||
@@ -270,7 +270,7 @@ onBeforeUnmount(() => {
|
|||||||
<div class="skim panel base">
|
<div class="skim panel base">
|
||||||
<div class="inner">
|
<div class="inner">
|
||||||
<h3>
|
<h3>
|
||||||
<GlobalOutlined style="color: #68d8fe" />
|
<GlobalOutlined style="color: #68d8fe" /> 5G
|
||||||
{{ t('views.dashboard.overview.skim.baseTitle') }}
|
{{ t('views.dashboard.overview.skim.baseTitle') }}
|
||||||
</h3>
|
</h3>
|
||||||
<div class="data">
|
<div class="data">
|
||||||
@@ -302,6 +302,14 @@ onBeforeUnmount(() => {
|
|||||||
<span>{{ t('views.dashboard.overview.skim.gnbUeNum') }}</span>
|
<span>{{ t('views.dashboard.overview.skim.gnbUeNum') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="skim panel base">
|
||||||
|
<div class="inner">
|
||||||
|
<h3>
|
||||||
|
<GlobalOutlined style="color: #68d8fe" /> 4G
|
||||||
|
{{ t('views.dashboard.overview.skim.baseTitle') }}
|
||||||
|
</h3>
|
||||||
<div class="data">
|
<div class="data">
|
||||||
<div
|
<div
|
||||||
class="item toRouter"
|
class="item toRouter"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Modal, message } from 'ant-design-vue/lib';
|
|||||||
import { SizeType } from 'ant-design-vue/lib/config-provider';
|
import { SizeType } from 'ant-design-vue/lib/config-provider';
|
||||||
import { MenuInfo } from 'ant-design-vue/lib/menu/src/interface';
|
import { MenuInfo } from 'ant-design-vue/lib/menu/src/interface';
|
||||||
import { ColumnsType } from 'ant-design-vue/lib/table';
|
import { ColumnsType } from 'ant-design-vue/lib/table';
|
||||||
|
import useNeInfoStore from '@/store/modules/neinfo';
|
||||||
import useI18n from '@/hooks/useI18n';
|
import useI18n from '@/hooks/useI18n';
|
||||||
import {
|
import {
|
||||||
RESULT_CODE_ERROR,
|
RESULT_CODE_ERROR,
|
||||||
@@ -23,6 +24,9 @@ const { t } = useI18n();
|
|||||||
const ws = new WS();
|
const ws = new WS();
|
||||||
const queue = new PQueue({ concurrency: 1, autoStart: true });
|
const queue = new PQueue({ concurrency: 1, autoStart: true });
|
||||||
|
|
||||||
|
/**网元可选 */
|
||||||
|
let neOtions = ref<Record<string, any>[]>([]);
|
||||||
|
|
||||||
/**开始结束时间 */
|
/**开始结束时间 */
|
||||||
let queryRangePicker = ref<[string, string]>(['', '']);
|
let queryRangePicker = ref<[string, string]>(['', '']);
|
||||||
|
|
||||||
@@ -197,7 +201,7 @@ let tableColumns: ColumnsType = [
|
|||||||
title: t('views.dashboard.cdr.smfInvocationTime'), // 调用时间
|
title: t('views.dashboard.cdr.smfInvocationTime'), // 调用时间
|
||||||
dataIndex: 'cdrJSON',
|
dataIndex: 'cdrJSON',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
width: 250,
|
width: 200,
|
||||||
customRender(opt) {
|
customRender(opt) {
|
||||||
const cdrJSON = opt.value;
|
const cdrJSON = opt.value;
|
||||||
return cdrJSON.invocationTimestamp;
|
return cdrJSON.invocationTimestamp;
|
||||||
@@ -391,6 +395,7 @@ const realTimeData = ref<boolean>(false);
|
|||||||
function fnRealTime() {
|
function fnRealTime() {
|
||||||
realTimeData.value = !realTimeData.value;
|
realTimeData.value = !realTimeData.value;
|
||||||
if (realTimeData.value) {
|
if (realTimeData.value) {
|
||||||
|
tableState.seached = false;
|
||||||
// 建立链接
|
// 建立链接
|
||||||
const options: OptionsType = {
|
const options: OptionsType = {
|
||||||
url: '/ws',
|
url: '/ws',
|
||||||
@@ -399,7 +404,7 @@ function fnRealTime() {
|
|||||||
*
|
*
|
||||||
* CDR会话事件-SMF (GroupID:1006)
|
* CDR会话事件-SMF (GroupID:1006)
|
||||||
*/
|
*/
|
||||||
subGroupID: '1006',
|
subGroupID: `1006_${queryParams.neId}`,
|
||||||
},
|
},
|
||||||
onmessage: wsMessage,
|
onmessage: wsMessage,
|
||||||
onerror: wsError,
|
onerror: wsError,
|
||||||
@@ -407,6 +412,8 @@ function fnRealTime() {
|
|||||||
ws.connect(options);
|
ws.connect(options);
|
||||||
} else {
|
} else {
|
||||||
ws.close();
|
ws.close();
|
||||||
|
tableState.seached = true;
|
||||||
|
fnGetList(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,7 +436,7 @@ function wsMessage(res: Record<string, any>) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// cdrEvent CDR会话事件
|
// cdrEvent CDR会话事件
|
||||||
if (data.groupId === '1006') {
|
if (data.groupId === `1006_${queryParams.neId}`) {
|
||||||
const cdrEvent = data.data;
|
const cdrEvent = data.data;
|
||||||
queue.add(async () => {
|
queue.add(async () => {
|
||||||
modalState.maxId += 1;
|
modalState.maxId += 1;
|
||||||
@@ -451,8 +458,34 @@ function wsMessage(res: Record<string, any>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
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 === 'SMF') {
|
||||||
|
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();
|
fnGetList();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
@@ -472,10 +505,19 @@ onBeforeUnmount(() => {
|
|||||||
<!-- 表格搜索栏 -->
|
<!-- 表格搜索栏 -->
|
||||||
<a-form :model="queryParams" name="queryParams" layout="horizontal">
|
<a-form :model="queryParams" name="queryParams" layout="horizontal">
|
||||||
<a-row :gutter="16">
|
<a-row :gutter="16">
|
||||||
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
|
<a-form-item label="SMF" name="neId ">
|
||||||
|
<a-select
|
||||||
|
v-model:value="queryParams.neId"
|
||||||
|
:options="neOtions"
|
||||||
|
:placeholder="t('common.selectPlease')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
<a-col :lg="6" :md="12" :xs="24">
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label="t('views.dashboard.cdr.smfSubscriptionIDData')"
|
:label="t('views.dashboard.cdr.smfSubscriptionIDData')"
|
||||||
name="calledParty "
|
name="subscriberID"
|
||||||
>
|
>
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="queryParams.subscriberID"
|
v-model:value="queryParams.subscriberID"
|
||||||
@@ -572,6 +614,7 @@ onBeforeUnmount(() => {
|
|||||||
:checked-children="t('common.switch.show')"
|
:checked-children="t('common.switch.show')"
|
||||||
:un-checked-children="t('common.switch.hide')"
|
:un-checked-children="t('common.switch.hide')"
|
||||||
size="small"
|
size="small"
|
||||||
|
:disabled="realTimeData"
|
||||||
/>
|
/>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
@@ -616,7 +659,7 @@ onBeforeUnmount(() => {
|
|||||||
:data-source="tableState.data"
|
:data-source="tableState.data"
|
||||||
:size="tableState.size"
|
:size="tableState.size"
|
||||||
:pagination="tablePagination"
|
:pagination="tablePagination"
|
||||||
:scroll="{ x: tableColumns.length * 120, y: 'calc(100vh - 480px)' }"
|
:scroll="{ x: tableColumns.length * 150, y: 'calc(100vh - 480px)' }"
|
||||||
:row-selection="{
|
:row-selection="{
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
columnWidth: '48px',
|
columnWidth: '48px',
|
||||||
|
|||||||
760
src/views/dashboard/smscCDR/index.vue
Normal file
760
src/views/dashboard/smscCDR/index.vue
Normal file
@@ -0,0 +1,760 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, onMounted, toRaw, ref, onBeforeUnmount } from 'vue';
|
||||||
|
import { PageContainer } from 'antdv-pro-layout';
|
||||||
|
import { message, Modal } from 'ant-design-vue/lib';
|
||||||
|
import { SizeType } from 'ant-design-vue/lib/config-provider';
|
||||||
|
import { MenuInfo } from 'ant-design-vue/lib/menu/src/interface';
|
||||||
|
import { ColumnsType } from 'ant-design-vue/lib/table';
|
||||||
|
import useDictStore from '@/store/modules/dict';
|
||||||
|
import useI18n from '@/hooks/useI18n';
|
||||||
|
import {
|
||||||
|
RESULT_CODE_ERROR,
|
||||||
|
RESULT_CODE_SUCCESS,
|
||||||
|
} from '@/constants/result-constants';
|
||||||
|
import useNeInfoStore from '@/store/modules/neinfo';
|
||||||
|
import {
|
||||||
|
delSMSCDataCDR,
|
||||||
|
exportSMSCDataCDR,
|
||||||
|
listSMSCDataCDR,
|
||||||
|
} from '@/api/neData/smsc';
|
||||||
|
import { parseDateToStr } from '@/utils/date-utils';
|
||||||
|
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||||
|
import saveAs from 'file-saver';
|
||||||
|
import PQueue from 'p-queue';
|
||||||
|
const { getDict } = useDictStore();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const ws = new WS();
|
||||||
|
const queue = new PQueue({ concurrency: 1, autoStart: true });
|
||||||
|
|
||||||
|
/**字典数据 */
|
||||||
|
let dict: {
|
||||||
|
/**CDR 响应原因代码类别类型 */
|
||||||
|
cdrCauseCode: DictType[];
|
||||||
|
} = reactive({
|
||||||
|
cdrCauseCode: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
/**网元可选 */
|
||||||
|
let neOtions = ref<Record<string, any>[]>([]);
|
||||||
|
|
||||||
|
/**开始结束时间 */
|
||||||
|
let queryRangePicker = ref<[string, string]>(['', '']);
|
||||||
|
|
||||||
|
/**查询参数 */
|
||||||
|
let queryParams = reactive({
|
||||||
|
/**网元类型 */
|
||||||
|
neType: 'SMSC',
|
||||||
|
neId: '001',
|
||||||
|
recordType: '',
|
||||||
|
callerParty: '',
|
||||||
|
calledParty: '',
|
||||||
|
sortField: 'timestamp',
|
||||||
|
sortOrder: 'desc',
|
||||||
|
/**开始时间 */
|
||||||
|
startTime: '',
|
||||||
|
/**结束时间 */
|
||||||
|
endTime: '',
|
||||||
|
/**当前页数 */
|
||||||
|
pageNum: 1,
|
||||||
|
/**每页条数 */
|
||||||
|
pageSize: 20,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**查询参数重置 */
|
||||||
|
function fnQueryReset() {
|
||||||
|
recordTypes.value = [];
|
||||||
|
queryParams = Object.assign(queryParams, {
|
||||||
|
recordType: '',
|
||||||
|
callerParty: '',
|
||||||
|
calledParty: '',
|
||||||
|
startTime: '',
|
||||||
|
endTime: '',
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
});
|
||||||
|
queryRangePicker.value = ['', ''];
|
||||||
|
tablePagination.current = 1;
|
||||||
|
tablePagination.pageSize = 20;
|
||||||
|
fnGetList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**记录类型 */
|
||||||
|
const recordTypes = ref<string[]>([]);
|
||||||
|
|
||||||
|
/**查询记录类型变更 */
|
||||||
|
function fnQueryRecordTypeChange(value: any) {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
queryParams.recordType = value.join(',');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**表格状态类型 */
|
||||||
|
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.recordType'),
|
||||||
|
dataIndex: 'cdrJSON',
|
||||||
|
align: 'left',
|
||||||
|
width: 150,
|
||||||
|
customRender(opt) {
|
||||||
|
const cdrJSON = opt.value;
|
||||||
|
return cdrJSON.recordType;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('views.dashboard.cdr.type'),
|
||||||
|
dataIndex: 'cdrJSON',
|
||||||
|
align: 'left',
|
||||||
|
width: 150,
|
||||||
|
customRender(opt) {
|
||||||
|
const cdrJSON = opt.value;
|
||||||
|
return cdrJSON.serviceType;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('views.dashboard.cdr.caller'),
|
||||||
|
dataIndex: 'cdrJSON',
|
||||||
|
key: 'callerParty',
|
||||||
|
align: 'left',
|
||||||
|
width: 120,
|
||||||
|
customRender(opt) {
|
||||||
|
const cdrJSON = opt.value;
|
||||||
|
return cdrJSON.callerParty;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('views.dashboard.cdr.called'),
|
||||||
|
dataIndex: 'cdrJSON',
|
||||||
|
key: 'calledParty',
|
||||||
|
align: 'left',
|
||||||
|
width: 120,
|
||||||
|
customRender(opt) {
|
||||||
|
const cdrJSON = opt.value;
|
||||||
|
return cdrJSON.calledParty;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: t('views.dashboard.cdr.result'),
|
||||||
|
dataIndex: 'cdrJSON',
|
||||||
|
key: 'cause',
|
||||||
|
align: 'left',
|
||||||
|
width: 200,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('views.dashboard.cdr.time'),
|
||||||
|
dataIndex: 'cdrJSON',
|
||||||
|
align: 'left',
|
||||||
|
width: 150,
|
||||||
|
customRender(opt) {
|
||||||
|
const cdrJSON = opt.value;
|
||||||
|
return parseDateToStr(+cdrJSON.updateTime * 1000);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
delSMSCDataCDR(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;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**查询列表, 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];
|
||||||
|
listSMSCDataCDR(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;
|
||||||
|
exportSMSCDataCDR(querys)
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
|
message.success({
|
||||||
|
content: t('common.operateOk'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
saveAs(res.data, `smsc_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: {
|
||||||
|
/**订阅通道组
|
||||||
|
*
|
||||||
|
* SMSC_CDR会话事件(GroupID:1007_neId)
|
||||||
|
*/
|
||||||
|
subGroupID: `1007_${queryParams.neId}`,
|
||||||
|
},
|
||||||
|
onmessage: wsMessage,
|
||||||
|
onerror: wsError,
|
||||||
|
};
|
||||||
|
ws.connect(options);
|
||||||
|
} else {
|
||||||
|
ws.close();
|
||||||
|
tableState.seached = true;
|
||||||
|
fnGetList(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**接收数据后回调 */
|
||||||
|
function wsError(ev: any) {
|
||||||
|
// 接收数据后回调
|
||||||
|
console.error(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**接收数据后回调 */
|
||||||
|
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 === `1007_${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(() => {
|
||||||
|
// 初始字典数据
|
||||||
|
Promise.allSettled([getDict('cdr_cause_code')]).then(resArr => {
|
||||||
|
if (resArr[0].status === 'fulfilled') {
|
||||||
|
dict.cdrCauseCode = resArr[0].value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 获取网元网元列表
|
||||||
|
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 === 'SMSC') {
|
||||||
|
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="SMSC" name="neId ">
|
||||||
|
<a-select
|
||||||
|
v-model:value="queryParams.neId"
|
||||||
|
:options="neOtions"
|
||||||
|
:placeholder="t('common.selectPlease')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
|
<a-form-item
|
||||||
|
:label="t('views.dashboard.cdr.called')"
|
||||||
|
name="calledParty"
|
||||||
|
>
|
||||||
|
<a-input
|
||||||
|
v-model:value="queryParams.calledParty"
|
||||||
|
allow-clear
|
||||||
|
:placeholder="t('common.inputPlease')"
|
||||||
|
></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
|
<a-form-item
|
||||||
|
:label="t('views.dashboard.cdr.caller')"
|
||||||
|
name="callerParty "
|
||||||
|
>
|
||||||
|
<a-input
|
||||||
|
v-model:value="queryParams.callerParty"
|
||||||
|
allow-clear
|
||||||
|
:placeholder="t('common.inputPlease')"
|
||||||
|
></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.recordType')"
|
||||||
|
name="recordType"
|
||||||
|
>
|
||||||
|
<a-select
|
||||||
|
v-model:value="recordTypes"
|
||||||
|
mode="multiple"
|
||||||
|
:options="['MOSM', 'MTSM'].map(v => ({ value: v }))"
|
||||||
|
:placeholder="t('common.selectPlease')"
|
||||||
|
@change="fnQueryRecordTypeChange"
|
||||||
|
></a-select>
|
||||||
|
</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')"
|
||||||
|
>
|
||||||
|
<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 === 'cause'">
|
||||||
|
<span v-if="record.cdrJSON.result === 0">
|
||||||
|
{{ t('views.dashboard.cdr.resultFail') }},
|
||||||
|
<DictTag
|
||||||
|
:options="dict.cdrCauseCode"
|
||||||
|
:value="record.cdrJSON.cause"
|
||||||
|
value-default="0"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
|
{{ t('views.dashboard.cdr.resultOk') }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'id'">
|
||||||
|
<a-space :size="8" align="center">
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>{{ t('common.deleteText') }}</template>
|
||||||
|
<a-button
|
||||||
|
type="link"
|
||||||
|
@click.prevent="fnRecordDelete(record.id)"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<DeleteOutlined />
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
<template #expandedRowRender="{ record }">
|
||||||
|
<div style="width: 46%; padding-left: 32px; padding-bottom: 16px">
|
||||||
|
<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>{{ parseDateToStr(+record.timestamp * 1000) }}</span>
|
||||||
|
</div>
|
||||||
|
<a-divider orientation="left">
|
||||||
|
{{ t('views.dashboard.cdr.rowInfo') }}
|
||||||
|
</a-divider>
|
||||||
|
<div>
|
||||||
|
<span>{{ t('views.dashboard.cdr.type') }}: </span>
|
||||||
|
<span>{{ record.cdrJSON.serviceType }}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>{{ t('views.dashboard.cdr.caller') }}: </span>
|
||||||
|
<span>{{ record.cdrJSON.callerParty }}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>{{ t('views.dashboard.cdr.called') }}: </span>
|
||||||
|
<span>{{ record.cdrJSON.calledParty }}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>{{ t('views.dashboard.cdr.result') }}: </span>
|
||||||
|
<span v-if="record.cdrJSON.result === 0">
|
||||||
|
{{ t('views.dashboard.cdr.resultFail') }},
|
||||||
|
<DictTag
|
||||||
|
:options="dict.cdrCauseCode"
|
||||||
|
:value="record.cdrJSON.cause"
|
||||||
|
value-default="0"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
|
{{ t('views.dashboard.cdr.resultOk') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</a-card>
|
||||||
|
</PageContainer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.table :deep(.ant-pagination) {
|
||||||
|
padding: 0 24px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -142,30 +142,6 @@ let alarmTableState: TabeStateType = reactive({
|
|||||||
|
|
||||||
/**表格字段列 */
|
/**表格字段列 */
|
||||||
let tableColumns: ColumnsType = [
|
let tableColumns: ColumnsType = [
|
||||||
{
|
|
||||||
title: t('views.faultManage.activeAlarm.alarmId'),
|
|
||||||
dataIndex: 'alarmId',
|
|
||||||
align: 'center',
|
|
||||||
width: 5,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('views.faultManage.activeAlarm.neId'),
|
|
||||||
dataIndex: 'neId',
|
|
||||||
align: 'center',
|
|
||||||
width: 5,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('views.faultManage.activeAlarm.neName'),
|
|
||||||
dataIndex: 'neName',
|
|
||||||
align: 'center',
|
|
||||||
width: 5,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('views.faultManage.activeAlarm.neType'),
|
|
||||||
dataIndex: 'neType',
|
|
||||||
align: 'center',
|
|
||||||
width: 5,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: t('views.faultManage.activeAlarm.origLevel'),
|
title: t('views.faultManage.activeAlarm.origLevel'),
|
||||||
align: 'center',
|
align: 'center',
|
||||||
@@ -173,18 +149,18 @@ let tableColumns: ColumnsType = [
|
|||||||
dataIndex: 'origSeverity',
|
dataIndex: 'origSeverity',
|
||||||
width: 5,
|
width: 5,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: t('views.faultManage.activeAlarm.alarmCode'),
|
|
||||||
dataIndex: 'alarmCode',
|
|
||||||
align: 'center',
|
|
||||||
width: 5,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: t('views.faultManage.activeAlarm.alarmTitle'),
|
title: t('views.faultManage.activeAlarm.alarmTitle'),
|
||||||
dataIndex: 'alarmTitle',
|
dataIndex: 'alarmTitle',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
width: 5,
|
width: 5,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: t('views.faultManage.activeAlarm.neType'),
|
||||||
|
dataIndex: 'neType',
|
||||||
|
align: 'center',
|
||||||
|
width: 5,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: t('views.faultManage.activeAlarm.eventTime'),
|
title: t('views.faultManage.activeAlarm.eventTime'),
|
||||||
dataIndex: 'eventTime',
|
dataIndex: 'eventTime',
|
||||||
@@ -192,6 +168,12 @@ let tableColumns: ColumnsType = [
|
|||||||
sorter: (a: any, b: any) => 1,
|
sorter: (a: any, b: any) => 1,
|
||||||
width: 5,
|
width: 5,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: t('views.faultManage.activeAlarm.alarmCode'),
|
||||||
|
dataIndex: 'alarmCode',
|
||||||
|
align: 'center',
|
||||||
|
width: 5,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: t('views.faultManage.activeAlarm.alarmType'),
|
title: t('views.faultManage.activeAlarm.alarmType'),
|
||||||
dataIndex: 'alarmType',
|
dataIndex: 'alarmType',
|
||||||
@@ -199,12 +181,31 @@ let tableColumns: ColumnsType = [
|
|||||||
align: 'left',
|
align: 'left',
|
||||||
width: 5,
|
width: 5,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: t('views.faultManage.activeAlarm.neName'),
|
||||||
|
dataIndex: 'neName',
|
||||||
|
align: 'center',
|
||||||
|
width: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('views.faultManage.activeAlarm.neId'),
|
||||||
|
dataIndex: 'neId',
|
||||||
|
align: 'center',
|
||||||
|
width: 5,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: t('views.faultManage.activeAlarm.pvFlag'),
|
title: t('views.faultManage.activeAlarm.pvFlag'),
|
||||||
dataIndex: 'pvFlag',
|
dataIndex: 'pvFlag',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: 5,
|
width: 5,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: t('views.faultManage.activeAlarm.alarmId'),
|
||||||
|
dataIndex: 'alarmId',
|
||||||
|
align: 'center',
|
||||||
|
width: 5,
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
title: t('views.faultManage.activeAlarm.ackState'),
|
title: t('views.faultManage.activeAlarm.ackState'),
|
||||||
dataIndex: 'ackState',
|
dataIndex: 'ackState',
|
||||||
@@ -610,6 +611,17 @@ function fnShowSet() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// key替换中文title
|
||||||
|
function mapKeysWithReduce(data: any, titleMapping: any) {
|
||||||
|
return data.map((item:any) => {
|
||||||
|
return Object.keys(item).reduce((newItem:any, key:any) => {
|
||||||
|
const title = titleMapping[key] || key;
|
||||||
|
newItem[title] = item[key];
|
||||||
|
return newItem;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导出全部
|
* 导出全部
|
||||||
*/
|
*/
|
||||||
@@ -621,39 +633,56 @@ function fnExportAll() {
|
|||||||
const key = 'exportAlarm';
|
const key = 'exportAlarm';
|
||||||
message.loading({ content: t('common.loading'), key });
|
message.loading({ content: t('common.loading'), key });
|
||||||
let sortArr: any = [];
|
let sortArr: any = [];
|
||||||
|
let writeSheetOpt: any = [];
|
||||||
|
let mappArr: any = {};
|
||||||
tableColumnsDnd.value.forEach((item: any) => {
|
tableColumnsDnd.value.forEach((item: any) => {
|
||||||
if (item.dataIndex) sortArr.push(item.dataIndex);
|
if (item.dataIndex) {
|
||||||
|
sortArr.push(item.dataIndex);
|
||||||
|
writeSheetOpt.push(item.title);
|
||||||
|
mappArr[item.dataIndex] = item.title;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
//提供给writeSheet排序参数
|
||||||
// 排序字段
|
|
||||||
const sortData = {
|
const sortData = {
|
||||||
header: sortArr,
|
header: writeSheetOpt,
|
||||||
};
|
};
|
||||||
|
|
||||||
exportAll(queryParams).then(res => {
|
exportAll(queryParams).then(res => {
|
||||||
if (res.code === RESULT_CODE_SUCCESS) {
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
res.data = res.data.map((objA: any) => {
|
res.data = res.data.map((objA: any) => {
|
||||||
let filteredObj: any = {};
|
let filteredObj: any = {};
|
||||||
|
//sort Data
|
||||||
sortArr.forEach((key: any) => {
|
sortArr.forEach((key: any) => {
|
||||||
if (objA.hasOwnProperty(key)) {
|
if (objA.hasOwnProperty(key)) {
|
||||||
filteredObj[key] = objA[key];
|
filteredObj[key] = objA[key];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
dict.activeAckState.map((item: any) => {
|
const mapProps = (dict: any, key: string) => {
|
||||||
if (item.value === `${filteredObj.ackState}`)
|
const item = dict.find(
|
||||||
filteredObj.ackState = item.label;
|
(item: any) => item.value === `${filteredObj[key]}`
|
||||||
});
|
);
|
||||||
|
if (item) {
|
||||||
|
filteredObj[key] = item.label;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mapProps(dict.activeAckState, 'ackState');
|
||||||
|
mapProps(dict.activeClearType, 'clearType');
|
||||||
|
mapProps(dict.activeAlarmSeverity, 'origSeverity');
|
||||||
|
mapProps(dict.activeAlarmType, 'alarmType');
|
||||||
|
|
||||||
return filteredObj;
|
return filteredObj;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
res.data = mapKeysWithReduce(res.data, mappArr);
|
||||||
|
writeSheet(res.data, 'alarm', sortData).then(fileBlob => {
|
||||||
|
saveAs(fileBlob, `alarm_${Date.now()}.xlsx`);
|
||||||
message.success({
|
message.success({
|
||||||
content: t('common.msgSuccess', { msg: t('common.export') }),
|
content: t('common.msgSuccess', { msg: t('common.export') }),
|
||||||
key,
|
key,
|
||||||
duration: 3,
|
duration: 3,
|
||||||
});
|
});
|
||||||
writeSheet(res.data, 'alarm', sortData).then(fileBlob =>
|
});
|
||||||
saveAs(fileBlob, `alarm_${Date.now()}.xlsx`)
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
message.error({
|
message.error({
|
||||||
content: `${res.msg}`,
|
content: `${res.msg}`,
|
||||||
|
|||||||
@@ -308,6 +308,17 @@ const onSelectChange = (
|
|||||||
state.selectedRow = record;
|
state.selectedRow = record;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// key替换中文title
|
||||||
|
function mapKeysWithReduce(data: any, titleMapping: any) {
|
||||||
|
return data.map((item:any) => {
|
||||||
|
return Object.keys(item).reduce((newItem:any, key:any) => {
|
||||||
|
const title = titleMapping[key] || key;
|
||||||
|
newItem[title] = item[key];
|
||||||
|
return newItem;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导出全部
|
* 导出全部
|
||||||
*/
|
*/
|
||||||
@@ -319,13 +330,18 @@ function fnExportAll() {
|
|||||||
const key = 'exportAlarm';
|
const key = 'exportAlarm';
|
||||||
message.loading({ content: t('common.loading'), key });
|
message.loading({ content: t('common.loading'), key });
|
||||||
let sortArr: any = [];
|
let sortArr: any = [];
|
||||||
|
let writeSheetOpt: any = [];
|
||||||
|
let mappArr: any = {};
|
||||||
tableColumnsDnd.value.forEach((item: any) => {
|
tableColumnsDnd.value.forEach((item: any) => {
|
||||||
if (item.dataIndex) sortArr.push(item.dataIndex);
|
if (item.dataIndex) {
|
||||||
|
sortArr.push(item.dataIndex);
|
||||||
|
writeSheetOpt.push(item.title);
|
||||||
|
mappArr[item.dataIndex] = item.title;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 排序字段
|
// 排序字段
|
||||||
const sortData = {
|
const sortData = {
|
||||||
header: sortArr,
|
header: writeSheetOpt,
|
||||||
};
|
};
|
||||||
|
|
||||||
exportAll(queryParams).then(res => {
|
exportAll(queryParams).then(res => {
|
||||||
@@ -337,21 +353,20 @@ function fnExportAll() {
|
|||||||
filteredObj[key] = objA[key];
|
filteredObj[key] = objA[key];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
dict.activeAckState.map((item: any) => {
|
|
||||||
if (item.value === `${filteredObj.ackState}`)
|
|
||||||
filteredObj.ackState = item.label;
|
|
||||||
});
|
|
||||||
|
|
||||||
return filteredObj;
|
return filteredObj;
|
||||||
});
|
});
|
||||||
|
res.data = mapKeysWithReduce(res.data, mappArr);
|
||||||
|
|
||||||
|
writeSheet(res.data, 'alarm', sortData).then(fileBlob => {
|
||||||
|
saveAs(fileBlob, `evnet_${Date.now()}.xlsx`);
|
||||||
|
|
||||||
message.success({
|
message.success({
|
||||||
content: t('common.msgSuccess', { msg: t('common.export') }),
|
content: t('common.msgSuccess', { msg: t('common.export') }),
|
||||||
key,
|
key,
|
||||||
duration: 3,
|
duration: 3,
|
||||||
});
|
});
|
||||||
writeSheet(res.data, 'alarm', sortData).then(fileBlob =>
|
});
|
||||||
saveAs(fileBlob, `evnet_${Date.now()}.xlsx`)
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
message.error({
|
message.error({
|
||||||
content: `${res.msg}`,
|
content: `${res.msg}`,
|
||||||
@@ -625,11 +640,6 @@ onMounted(() => {
|
|||||||
:loading="tableState.loading"
|
:loading="tableState.loading"
|
||||||
:data-source="tableState.data"
|
:data-source="tableState.data"
|
||||||
:size="tableState.size"
|
:size="tableState.size"
|
||||||
:row-selection="{
|
|
||||||
columnWidth: 2,
|
|
||||||
selectedRowKeys: state.selectedRowKeys,
|
|
||||||
onChange: onSelectChange,
|
|
||||||
}"
|
|
||||||
:pagination="tablePagination"
|
:pagination="tablePagination"
|
||||||
:scroll="{ x: 2500, y: 400 }"
|
:scroll="{ x: 2500, y: 400 }"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -426,6 +426,17 @@ function fnCancelConfirm() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// key替换中文title
|
||||||
|
function mapKeysWithReduce(data: any, titleMapping: any) {
|
||||||
|
return data.map((item:any) => {
|
||||||
|
return Object.keys(item).reduce((newItem:any, key:any) => {
|
||||||
|
const title = titleMapping[key] || key;
|
||||||
|
newItem[title] = item[key];
|
||||||
|
return newItem;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导出全部
|
* 导出全部
|
||||||
*/
|
*/
|
||||||
@@ -437,12 +448,18 @@ function fnExportAll() {
|
|||||||
const key = 'exportAlarmHis';
|
const key = 'exportAlarmHis';
|
||||||
message.loading({ content: t('common.loading'), key });
|
message.loading({ content: t('common.loading'), key });
|
||||||
let sortArr: any = [];
|
let sortArr: any = [];
|
||||||
|
let writeSheetOpt: any = [];
|
||||||
|
let mappArr: any = {};
|
||||||
tableColumnsDnd.value.forEach((item: any) => {
|
tableColumnsDnd.value.forEach((item: any) => {
|
||||||
if (item.dataIndex) sortArr.push(item.dataIndex);
|
if (item.dataIndex) {
|
||||||
|
sortArr.push(item.dataIndex);
|
||||||
|
writeSheetOpt.push(item.title);
|
||||||
|
mappArr[item.dataIndex] = item.title;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
// 排序字段
|
//提供给writeSheet排序参数
|
||||||
const sortData = {
|
const sortData = {
|
||||||
header: sortArr,
|
header: writeSheetOpt,
|
||||||
};
|
};
|
||||||
exportAll(queryParams).then(res => {
|
exportAll(queryParams).then(res => {
|
||||||
if (res.code === RESULT_CODE_SUCCESS) {
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
@@ -470,14 +487,17 @@ function fnExportAll() {
|
|||||||
|
|
||||||
return filteredObj;
|
return filteredObj;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
res.data = mapKeysWithReduce(res.data, mappArr);
|
||||||
|
|
||||||
|
writeSheet(res.data, 'alarm', sortData).then(fileBlob => {
|
||||||
|
saveAs(fileBlob, `history-alarm_${Date.now()}.xlsx`);
|
||||||
message.success({
|
message.success({
|
||||||
content: t('common.msgSuccess', { msg: t('common.export') }),
|
content: t('common.msgSuccess', { msg: t('common.export') }),
|
||||||
key,
|
key,
|
||||||
duration: 3,
|
duration: 3,
|
||||||
});
|
});
|
||||||
writeSheet(res.data, 'alarm', sortData).then(fileBlob =>
|
});
|
||||||
saveAs(fileBlob, `history-alarm_${Date.now()}.xlsx`)
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
message.error({
|
message.error({
|
||||||
content: `${res.msg}`,
|
content: `${res.msg}`,
|
||||||
|
|||||||
@@ -153,11 +153,10 @@ type nfStateType = {
|
|||||||
/**网元详细信息 */
|
/**网元详细信息 */
|
||||||
let pronInfo: nfStateType = reactive({
|
let pronInfo: nfStateType = reactive({
|
||||||
hostName: '5gc',
|
hostName: '5gc',
|
||||||
osInfo:
|
osInfo: 'Linux 5gc 4.15.0-112-generic 2020 x86_64 GNU/Linux',
|
||||||
'Linux 5gc 4.15.0-112-generic #113-Ubuntu SMP Thu Jul 9 23:41:39 UTC 2020 x86_64 GNU/Linux',
|
dbInfo: 'db v9.9.9',
|
||||||
dbInfo: 'adb v1.0.1',
|
|
||||||
ipAddress: '-',
|
ipAddress: '-',
|
||||||
port: 3030,
|
port: 33030,
|
||||||
version: '-',
|
version: '-',
|
||||||
cpuUse: '-',
|
cpuUse: '-',
|
||||||
memoryUse: '-',
|
memoryUse: '-',
|
||||||
|
|||||||
362
src/views/logManage/exportFile/index.vue
Normal file
362
src/views/logManage/exportFile/index.vue
Normal file
@@ -0,0 +1,362 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, ref, onMounted, toRaw } from 'vue';
|
||||||
|
import { PageContainer } from 'antdv-pro-layout';
|
||||||
|
import { SizeType } from 'ant-design-vue/lib/config-provider';
|
||||||
|
import { ColumnsType } from 'ant-design-vue/lib/table';
|
||||||
|
import { Modal, message } from 'ant-design-vue/lib';
|
||||||
|
import { parseDateToStr } from '@/utils/date-utils';
|
||||||
|
import {
|
||||||
|
getBakFile,
|
||||||
|
getBakFileList,
|
||||||
|
downFile,
|
||||||
|
delFile,
|
||||||
|
} from '@/api/logManage/exportFile';
|
||||||
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
|
import useI18n from '@/hooks/useI18n';
|
||||||
|
import saveAs from 'file-saver';
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
/**网元参数 */
|
||||||
|
let logSelect = ref<string[]>([]);
|
||||||
|
|
||||||
|
/**文件列表 */
|
||||||
|
let fileList = ref<any>([]);
|
||||||
|
|
||||||
|
/**查询参数 */
|
||||||
|
let queryParams = reactive({
|
||||||
|
/**读取路径 */
|
||||||
|
path: '',
|
||||||
|
/**表名 */
|
||||||
|
tableName: '',
|
||||||
|
/**当前页数 */
|
||||||
|
pageNum: 1,
|
||||||
|
/**每页条数 */
|
||||||
|
pageSize: 20,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**表格状态类型 */
|
||||||
|
type TabeStateType = {
|
||||||
|
/**加载等待 */
|
||||||
|
loading: boolean;
|
||||||
|
/**紧凑型 */
|
||||||
|
size: SizeType;
|
||||||
|
/**记录数据 */
|
||||||
|
data: object[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**表格状态 */
|
||||||
|
let tableState: TabeStateType = reactive({
|
||||||
|
loading: false,
|
||||||
|
size: 'small',
|
||||||
|
data: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
/**表格字段列 */
|
||||||
|
let tableColumns: ColumnsType = [
|
||||||
|
{
|
||||||
|
title: t('views.logManage.neFile.fileMode'),
|
||||||
|
dataIndex: 'fileMode',
|
||||||
|
align: 'center',
|
||||||
|
width: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('views.logManage.neFile.owner'),
|
||||||
|
dataIndex: 'owner',
|
||||||
|
align: 'left',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('views.logManage.neFile.group'),
|
||||||
|
dataIndex: 'group',
|
||||||
|
align: 'left',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('views.logManage.neFile.size'),
|
||||||
|
dataIndex: 'size',
|
||||||
|
align: 'left',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('views.logManage.neFile.modifiedTime'),
|
||||||
|
dataIndex: 'modifiedTime',
|
||||||
|
align: 'left',
|
||||||
|
customRender(opt) {
|
||||||
|
if (!opt.value) return '';
|
||||||
|
return parseDateToStr(opt.value * 1000);
|
||||||
|
},
|
||||||
|
width: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('views.logManage.neFile.fileName'),
|
||||||
|
dataIndex: 'fileName',
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('common.operate'),
|
||||||
|
key: 'fileName',
|
||||||
|
align: 'center',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
/**表格分页器参数 */
|
||||||
|
let tablePagination = reactive({
|
||||||
|
/**当前页数 */
|
||||||
|
current: 1,
|
||||||
|
/**每页条数 */
|
||||||
|
pageSize: 20,
|
||||||
|
/**默认的每页条数 */
|
||||||
|
defaultPageSize: 20,
|
||||||
|
/**指定每页可以显示多少条 */
|
||||||
|
pageSizeOptions: ['10', '20', '50', '100'],
|
||||||
|
/**只有一页时是否隐藏分页器 */
|
||||||
|
hideOnSinglePage: false,
|
||||||
|
/**是否可以快速跳转至某页 */
|
||||||
|
showQuickJumper: true,
|
||||||
|
/**是否可以改变 pageSize */
|
||||||
|
showSizeChanger: true,
|
||||||
|
/**数据总数 */
|
||||||
|
total: 0,
|
||||||
|
showTotal: (total: number) => t('common.tablePaginationTotal', { total }),
|
||||||
|
onChange: (page: number, pageSize: number) => {
|
||||||
|
tablePagination.current = page;
|
||||||
|
tablePagination.pageSize = pageSize;
|
||||||
|
queryParams.pageNum = page;
|
||||||
|
queryParams.pageSize = pageSize;
|
||||||
|
fnGetList();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**下载触发等待 */
|
||||||
|
let downLoading = ref<boolean>(false);
|
||||||
|
|
||||||
|
/**删除触发等待 */
|
||||||
|
let delLoading = ref<boolean>(false);
|
||||||
|
|
||||||
|
/**信息文件下载 */
|
||||||
|
function fnDownloadFile(row: Record<string, any>) {
|
||||||
|
if (downLoading.value) return;
|
||||||
|
Modal.confirm({
|
||||||
|
title: t('common.tipTitle'),
|
||||||
|
content: t('views.logManage.exportFile.downTip', {
|
||||||
|
fileName: row.fileName,
|
||||||
|
}),
|
||||||
|
onOk() {
|
||||||
|
downLoading.value = true;
|
||||||
|
const hide = message.loading(t('common.loading'), 0);
|
||||||
|
downFile({
|
||||||
|
path: queryParams.path,
|
||||||
|
fileName: row.fileName,
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
|
message.success({
|
||||||
|
content: t('common.msgSuccess', {
|
||||||
|
msg: t('common.downloadText'),
|
||||||
|
}),
|
||||||
|
duration: 2,
|
||||||
|
});
|
||||||
|
saveAs(res.data, `${row.fileName}`);
|
||||||
|
} else {
|
||||||
|
message.error({
|
||||||
|
content: t('views.logManage.exportFile.downTipErr'),
|
||||||
|
duration: 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hide();
|
||||||
|
downLoading.value = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function fnRecordDelete(row: Record<string, any>) {
|
||||||
|
if (delLoading.value) return;
|
||||||
|
Modal.confirm({
|
||||||
|
title: t('common.tipTitle'),
|
||||||
|
content: t('views.logManage.exportFile.deleteTip', {
|
||||||
|
fileName: row.fileName,
|
||||||
|
}),
|
||||||
|
onOk() {
|
||||||
|
const key = 'delFile';
|
||||||
|
delLoading.value = true;
|
||||||
|
message.loading({ content: t('common.loading'), key });
|
||||||
|
delFile({
|
||||||
|
fileName: row.fileName,
|
||||||
|
path: queryParams.path,
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
|
message.success({
|
||||||
|
content: t('views.system.user.delSuss'),
|
||||||
|
key,
|
||||||
|
duration: 2,
|
||||||
|
});
|
||||||
|
fnGetList();
|
||||||
|
} else {
|
||||||
|
message.error({
|
||||||
|
content: `${res.msg}`,
|
||||||
|
key: key,
|
||||||
|
duration: 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
delLoading.value = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**网元类型选择对应修改 */
|
||||||
|
function fnNeChange(keys: any, opt: any) {
|
||||||
|
queryParams.tableName = keys;
|
||||||
|
queryParams.path = opt.path;
|
||||||
|
fnGetList(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**查询备份信息列表, pageNum初始页数 */
|
||||||
|
function fnGetList(pageNum?: number) {
|
||||||
|
if (queryParams.tableName === '') {
|
||||||
|
message.warning({
|
||||||
|
content: t('views.logManage.exportFile.selectTip'),
|
||||||
|
duration: 2,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (tableState.loading) return;
|
||||||
|
tableState.loading = true;
|
||||||
|
if (pageNum) {
|
||||||
|
queryParams.pageNum = pageNum;
|
||||||
|
}
|
||||||
|
getBakFileList(toRaw(queryParams)).then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||||
|
tablePagination.total = res.total;
|
||||||
|
tableState.data = res.data;
|
||||||
|
if (
|
||||||
|
tablePagination.total <=
|
||||||
|
(queryParams.pageNum - 1) * tablePagination.pageSize &&
|
||||||
|
queryParams.pageNum !== 1
|
||||||
|
) {
|
||||||
|
tableState.loading = false;
|
||||||
|
fnGetList(queryParams.pageNum - 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.error(res.msg, 3);
|
||||||
|
tablePagination.total = 0;
|
||||||
|
tableState.data = [];
|
||||||
|
}
|
||||||
|
tableState.loading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getBakFile().then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||||
|
res.data.forEach((item: any) => {
|
||||||
|
fileList.value.push({
|
||||||
|
value: item.tableName,
|
||||||
|
label: item.tableDisplay,
|
||||||
|
path: item.filePath,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// .finally(() => {
|
||||||
|
// fnGetList();
|
||||||
|
// });
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PageContainer>
|
||||||
|
<a-card :bordered="false" :body-style="{ padding: '0px' }">
|
||||||
|
<!-- 插槽-卡片左侧侧 -->
|
||||||
|
<template #title>
|
||||||
|
<a-form :model="queryParams" name="queryParams" layout="horizontal">
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :lg="8" :md="12" :xs="24">
|
||||||
|
<a-form-item
|
||||||
|
:label="t('views.logManage.exportFile.fileName')"
|
||||||
|
name="fileName"
|
||||||
|
style="margin-bottom: 0"
|
||||||
|
>
|
||||||
|
<a-select
|
||||||
|
v-model:value="logSelect"
|
||||||
|
:options="fileList"
|
||||||
|
@change="fnNeChange"
|
||||||
|
:allow-clear="false"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="16" :md="18" :xs="24" v-if="queryParams.path">
|
||||||
|
<a-form-item
|
||||||
|
:label="t('views.logManage.neFile.nePath')"
|
||||||
|
name="configName"
|
||||||
|
style="margin-bottom: 0"
|
||||||
|
>
|
||||||
|
<a-breadcrumb>
|
||||||
|
<a-breadcrumb-item>
|
||||||
|
{{ queryParams.path }}
|
||||||
|
</a-breadcrumb-item>
|
||||||
|
</a-breadcrumb>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 插槽-卡片右侧 -->
|
||||||
|
<template #extra>
|
||||||
|
<a-space :size="8" align="center">
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>{{ t('common.reloadText') }}</template>
|
||||||
|
<a-button type="text" @click.prevent="fnGetList()">
|
||||||
|
<template #icon><ReloadOutlined /></template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 表格列表 -->
|
||||||
|
<a-table
|
||||||
|
class="table"
|
||||||
|
row-key="fileName"
|
||||||
|
:columns="tableColumns"
|
||||||
|
:loading="tableState.loading"
|
||||||
|
:data-source="tableState.data"
|
||||||
|
:size="tableState.size"
|
||||||
|
:pagination="tablePagination"
|
||||||
|
:scroll="{ x: 800 }"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'fileName'">
|
||||||
|
<a-space :size="8" align="center">
|
||||||
|
<a-button
|
||||||
|
type="link"
|
||||||
|
:loading="downLoading"
|
||||||
|
@click.prevent="fnDownloadFile(record)"
|
||||||
|
v-if="record.fileType === 'file'"
|
||||||
|
>
|
||||||
|
<template #icon><DownloadOutlined /></template>
|
||||||
|
</a-button>
|
||||||
|
<a-button
|
||||||
|
type="link"
|
||||||
|
:loading="delLoading"
|
||||||
|
@click.prevent="fnRecordDelete(record)"
|
||||||
|
v-if="record.fileType === 'file'"
|
||||||
|
>
|
||||||
|
<template #icon><DeleteOutlined /></template>
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</a-card>
|
||||||
|
</PageContainer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped></style>
|
||||||
174
src/views/logManage/neFile/components/ViewDrawer.vue
Normal file
174
src/views/logManage/neFile/components/ViewDrawer.vue
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, onMounted, watch, ref, nextTick } from 'vue';
|
||||||
|
import { ProModal } from 'antdv-pro-modal';
|
||||||
|
import TerminalSSHView from '@/components/TerminalSSHView/index.vue';
|
||||||
|
import useI18n from '@/hooks/useI18n';
|
||||||
|
const { t } = useI18n();
|
||||||
|
const emit = defineEmits(['ok', 'cancel', 'update:visible']);
|
||||||
|
const props = defineProps({
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
/**文件地址 */
|
||||||
|
filePath: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
/**网元类型 */
|
||||||
|
neType: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
/**网元ID */
|
||||||
|
neId: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**对话框对象信息状态类型 */
|
||||||
|
type StateType = {
|
||||||
|
/**框是否显示 */
|
||||||
|
visible: boolean;
|
||||||
|
/**标题 */
|
||||||
|
title: string;
|
||||||
|
/**查看命令 */
|
||||||
|
form: Record<string, any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**对话框对象信息状态 */
|
||||||
|
let state: StateType = reactive({
|
||||||
|
visible: false,
|
||||||
|
title: '文件查看',
|
||||||
|
form: {
|
||||||
|
follow: true,
|
||||||
|
showType: 'lines', // lines/char
|
||||||
|
lines: 10,
|
||||||
|
char: 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
function onClose() {
|
||||||
|
state.visible = false;
|
||||||
|
emit('cancel');
|
||||||
|
emit('update:visible', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**监听是否显示,初始数据 */
|
||||||
|
watch(
|
||||||
|
() => props.visible,
|
||||||
|
val => {
|
||||||
|
if (val) {
|
||||||
|
if (props.neType && props.neId) {
|
||||||
|
const filePath = props.filePath;
|
||||||
|
const fileName = filePath.substring(filePath.lastIndexOf('/') + 1);
|
||||||
|
state.title = fileName;
|
||||||
|
state.visible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**终端实例 */
|
||||||
|
const viewTerminal = ref();
|
||||||
|
|
||||||
|
/**终端初始连接 */
|
||||||
|
function fnInit() {
|
||||||
|
setTimeout(fnReload, 1_500);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**重载查看方式 */
|
||||||
|
function fnReload() {
|
||||||
|
if (!viewTerminal.value) return;
|
||||||
|
viewTerminal.value.ctrlC();
|
||||||
|
|
||||||
|
if (state.form.showType !== 'lines') {
|
||||||
|
state.form.lines = 10;
|
||||||
|
} else {
|
||||||
|
state.form.char = 0;
|
||||||
|
}
|
||||||
|
viewTerminal.value.clear();
|
||||||
|
viewTerminal.value.send('tail', {
|
||||||
|
filePath: props.filePath,
|
||||||
|
lines: state.form.lines,
|
||||||
|
char: state.form.char,
|
||||||
|
follow: state.form.follow,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ProModal
|
||||||
|
:drag="true"
|
||||||
|
:fullscreen="true"
|
||||||
|
:borderDraw="true"
|
||||||
|
:min-width="800"
|
||||||
|
:min-height="500"
|
||||||
|
:center-y="true"
|
||||||
|
:destroyOnClose="true"
|
||||||
|
:keyboard="false"
|
||||||
|
:mask-closable="false"
|
||||||
|
:visible="state.visible"
|
||||||
|
:title="state.title"
|
||||||
|
:body-style="{ padding: '12px', overflow: 'hidden' }"
|
||||||
|
:footer="null"
|
||||||
|
@cancel="onClose"
|
||||||
|
>
|
||||||
|
<TerminalSSHView
|
||||||
|
ref="viewTerminal"
|
||||||
|
:id="`V${Date.now()}`"
|
||||||
|
style="height: calc(100% - 36px)"
|
||||||
|
:ne-type="neType"
|
||||||
|
:ne-id="neId"
|
||||||
|
@connect="fnInit()"
|
||||||
|
></TerminalSSHView>
|
||||||
|
<!-- 命令控制属性 -->
|
||||||
|
<a-form name="form" layout="horizontal">
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item :label="t('views.logManage.neFile.viewAs')">
|
||||||
|
<a-input-group compact>
|
||||||
|
<a-select v-model:value="state.form.showType" style="width: 50%">
|
||||||
|
<a-select-option value="lines">
|
||||||
|
{{ t('views.logManage.neFile.tailLines') }}
|
||||||
|
</a-select-option>
|
||||||
|
<a-select-option value="char">
|
||||||
|
{{ t('views.logManage.neFile.tailChar') }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
<a-input-number
|
||||||
|
style="width: 25%"
|
||||||
|
v-model:value="state.form[state.form.showType]"
|
||||||
|
:min="0"
|
||||||
|
:max="1000"
|
||||||
|
:placeholder="t('common.inputPlease')"
|
||||||
|
></a-input-number>
|
||||||
|
<a-button type="primary" style="width: 25%" @click="fnReload()">
|
||||||
|
{{ t('views.logManage.neFile.reload') }}
|
||||||
|
</a-button>
|
||||||
|
</a-input-group>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
|
<a-form-item
|
||||||
|
:label="t('views.logManage.neFile.follow')"
|
||||||
|
name="follow"
|
||||||
|
>
|
||||||
|
<a-switch v-model:checked="state.form.follow" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-form>
|
||||||
|
</ProModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.ant-form :deep(.ant-form-item) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -3,12 +3,13 @@ import { reactive, ref, onMounted, toRaw } from 'vue';
|
|||||||
import { PageContainer } from 'antdv-pro-layout';
|
import { PageContainer } from 'antdv-pro-layout';
|
||||||
import { SizeType } from 'ant-design-vue/lib/config-provider';
|
import { SizeType } from 'ant-design-vue/lib/config-provider';
|
||||||
import { ColumnsType } from 'ant-design-vue/lib/table';
|
import { ColumnsType } from 'ant-design-vue/lib/table';
|
||||||
|
import { Modal, message } from 'ant-design-vue/lib';
|
||||||
import { parseDateToStr } from '@/utils/date-utils';
|
import { parseDateToStr } from '@/utils/date-utils';
|
||||||
import { getNeFile, listNeFiles } from '@/api/tool/neFile';
|
import { getNeFile, listNeFiles } from '@/api/tool/neFile';
|
||||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
import useNeInfoStore from '@/store/modules/neinfo';
|
import useNeInfoStore from '@/store/modules/neinfo';
|
||||||
import useI18n from '@/hooks/useI18n';
|
import useI18n from '@/hooks/useI18n';
|
||||||
import { Modal, message } from 'ant-design-vue/lib';
|
import ViewDrawer from './components/ViewDrawer.vue';
|
||||||
import saveAs from 'file-saver';
|
import saveAs from 'file-saver';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
const neInfoStore = useNeInfoStore();
|
const neInfoStore = useNeInfoStore();
|
||||||
@@ -19,11 +20,7 @@ const route = useRoute();
|
|||||||
const routeParams = route.query as Record<string, any>;
|
const routeParams = route.query as Record<string, any>;
|
||||||
|
|
||||||
/**网元参数 */
|
/**网元参数 */
|
||||||
let neType = ref<string[]>([]);
|
let neTypeSelect = ref<string[]>([]);
|
||||||
/**下载触发等待 */
|
|
||||||
let loading = ref(false);
|
|
||||||
/**访问路径 */
|
|
||||||
let nePathArr = ref<string[]>([]);
|
|
||||||
|
|
||||||
/**查询参数 */
|
/**查询参数 */
|
||||||
let queryParams = reactive({
|
let queryParams = reactive({
|
||||||
@@ -134,20 +131,24 @@ let tablePagination = reactive({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**下载触发等待 */
|
||||||
|
let downLoading = ref<boolean>(false);
|
||||||
|
|
||||||
/**信息文件下载 */
|
/**信息文件下载 */
|
||||||
function fnDownloadFile(row: Record<string, any>) {
|
function fnDownloadFile(row: Record<string, any>) {
|
||||||
if (loading.value) return;
|
if (downLoading.value) return;
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: t('common.tipTitle'),
|
title: t('common.tipTitle'),
|
||||||
content: t('views.logManage.neFile.downTip', { fileName: row.fileName }),
|
content: t('views.logManage.neFile.downTip', { fileName: row.fileName }),
|
||||||
onOk() {
|
onOk() {
|
||||||
loading.value = true;
|
downLoading.value = true;
|
||||||
const hide = message.loading(t('common.loading'), 0);
|
const hide = message.loading(t('common.loading'), 0);
|
||||||
getNeFile({
|
getNeFile({
|
||||||
neType: queryParams.neType,
|
neType: queryParams.neType,
|
||||||
neId: queryParams.neId,
|
neId: queryParams.neId,
|
||||||
path: queryParams.path,
|
path: queryParams.path,
|
||||||
fileName: row.fileName,
|
fileName: row.fileName,
|
||||||
|
delTemp: true,
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (res.code === RESULT_CODE_SUCCESS) {
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
@@ -167,12 +168,15 @@ function fnDownloadFile(row: Record<string, any>) {
|
|||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
hide();
|
hide();
|
||||||
loading.value = false;
|
downLoading.value = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**访问路径 */
|
||||||
|
let nePathArr = ref<string[]>([]);
|
||||||
|
|
||||||
/**进入目录 */
|
/**进入目录 */
|
||||||
function fnDirCD(dir: string, index?: number) {
|
function fnDirCD(dir: string, index?: number) {
|
||||||
if (index === undefined) {
|
if (index === undefined) {
|
||||||
@@ -235,15 +239,42 @@ function fnGetList(pageNum?: number) {
|
|||||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
|
||||||
tablePagination.total = res.total;
|
tablePagination.total = res.total;
|
||||||
tableState.data = res.rows;
|
tableState.data = res.rows;
|
||||||
if (tablePagination.total <=(queryParams.pageNum - 1) * tablePagination.pageSize &&queryParams.pageNum !== 1) {
|
if (
|
||||||
|
tablePagination.total <=
|
||||||
|
(queryParams.pageNum - 1) * tablePagination.pageSize &&
|
||||||
|
queryParams.pageNum !== 1
|
||||||
|
) {
|
||||||
tableState.loading = false;
|
tableState.loading = false;
|
||||||
fnGetList(queryParams.pageNum - 1);
|
fnGetList(queryParams.pageNum - 1);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
message.error(res.msg, 3);
|
||||||
|
tablePagination.total = 0;
|
||||||
|
tableState.data = [];
|
||||||
}
|
}
|
||||||
tableState.loading = false;
|
tableState.loading = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**抽屉状态 */
|
||||||
|
const viewDrawerState = reactive({
|
||||||
|
visible: false,
|
||||||
|
/**文件路径 /var/log/amf.log */
|
||||||
|
filePath: '',
|
||||||
|
/**网元类型 */
|
||||||
|
neType: '',
|
||||||
|
/**网元ID */
|
||||||
|
neId: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
/**打开抽屉查看 */
|
||||||
|
function fnDrawerOpen(row: Record<string, any>) {
|
||||||
|
viewDrawerState.filePath = [...nePathArr.value, row.fileName].join('/');
|
||||||
|
viewDrawerState.neType = neTypeSelect.value[0];
|
||||||
|
viewDrawerState.neId = neTypeSelect.value[1];
|
||||||
|
viewDrawerState.visible = !viewDrawerState.visible;
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 获取网元网元列表
|
// 获取网元网元列表
|
||||||
neInfoStore.fnNelist().then(res => {
|
neInfoStore.fnNelist().then(res => {
|
||||||
@@ -254,8 +285,8 @@ onMounted(() => {
|
|||||||
duration: 2,
|
duration: 2,
|
||||||
});
|
});
|
||||||
} else if (routeParams.neType) {
|
} else if (routeParams.neType) {
|
||||||
neType.value = [routeParams.neType, routeParams.neId]
|
neTypeSelect.value = [routeParams.neType, routeParams.neId];
|
||||||
fnNeChange(neType.value, undefined);
|
fnNeChange(neTypeSelect.value, undefined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -276,12 +307,12 @@ onMounted(() => {
|
|||||||
style="margin-bottom: 0"
|
style="margin-bottom: 0"
|
||||||
>
|
>
|
||||||
<a-cascader
|
<a-cascader
|
||||||
v-model:value="neType"
|
v-model:value="neTypeSelect"
|
||||||
:options="neInfoStore.getNeCascaderOptions"
|
:options="neInfoStore.getNeCascaderOptions"
|
||||||
@change="fnNeChange"
|
@change="fnNeChange"
|
||||||
:allow-clear="false"
|
:allow-clear="false"
|
||||||
:placeholder="t('views.logManage.neFile.neTypePlease')"
|
:placeholder="t('views.logManage.neFile.neTypePlease')"
|
||||||
:disabled="loading || tableState.loading"
|
:disabled="downLoading || tableState.loading"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
@@ -332,8 +363,15 @@ onMounted(() => {
|
|||||||
<template #bodyCell="{ column, record }">
|
<template #bodyCell="{ column, record }">
|
||||||
<template v-if="column.key === 'fileName'">
|
<template v-if="column.key === 'fileName'">
|
||||||
<a-space :size="8" align="center">
|
<a-space :size="8" align="center">
|
||||||
|
<a-tooltip v-if="record.fileType === 'file'">
|
||||||
|
<template #title>{{ t('common.viewText') }}</template>
|
||||||
|
<a-button type="link" @click.prevent="fnDrawerOpen(record)">
|
||||||
|
<template #icon><ProfileOutlined /></template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
<a-button
|
<a-button
|
||||||
type="link"
|
type="link"
|
||||||
|
:loading="downLoading"
|
||||||
@click.prevent="fnDownloadFile(record)"
|
@click.prevent="fnDownloadFile(record)"
|
||||||
v-if="record.fileType === 'file'"
|
v-if="record.fileType === 'file'"
|
||||||
>
|
>
|
||||||
@@ -342,6 +380,7 @@ onMounted(() => {
|
|||||||
</a-button>
|
</a-button>
|
||||||
<a-button
|
<a-button
|
||||||
type="link"
|
type="link"
|
||||||
|
:loading="downLoading"
|
||||||
@click.prevent="fnDirCD(record.fileName)"
|
@click.prevent="fnDirCD(record.fileName)"
|
||||||
v-if="record.fileType === 'dir'"
|
v-if="record.fileType === 'dir'"
|
||||||
>
|
>
|
||||||
@@ -353,6 +392,14 @@ onMounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
</a-table>
|
</a-table>
|
||||||
</a-card>
|
</a-card>
|
||||||
|
|
||||||
|
<!-- 文件内容查看抽屉 -->
|
||||||
|
<ViewDrawer
|
||||||
|
v-model:visible="viewDrawerState.visible"
|
||||||
|
:file-path="viewDrawerState.filePath"
|
||||||
|
:ne-type="viewDrawerState.neType"
|
||||||
|
:ne-id="viewDrawerState.neId"
|
||||||
|
></ViewDrawer>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -134,16 +134,6 @@ onMounted(() => {
|
|||||||
function fnChangeLocale(e: any) {
|
function fnChangeLocale(e: any) {
|
||||||
changeLocale(e.key);
|
changeLocale(e.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**系统使用手册跳转 */
|
|
||||||
function fnClickHelpDoc(language?: string) {
|
|
||||||
const routeData = router.resolve({ name: 'HelpDoc' });
|
|
||||||
let href = routeData.href;
|
|
||||||
if (language) {
|
|
||||||
href = `${routeData.href}?language=${language}`;
|
|
||||||
}
|
|
||||||
window.open(href, '_blank');
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -166,23 +156,6 @@ function fnClickHelpDoc(language?: string) {
|
|||||||
<img :src="logoUrl" class="logo-brand" :alt="appStore.appName" />
|
<img :src="logoUrl" class="logo-brand" :alt="appStore.appName" />
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
|
||||||
<a-space direction="horizontal" :size="8">
|
|
||||||
<a-button
|
|
||||||
type="link"
|
|
||||||
:href="appStore.officialUrl"
|
|
||||||
target="_blank"
|
|
||||||
size="small"
|
|
||||||
v-if="appStore.officialUrl !== '#'"
|
|
||||||
>
|
|
||||||
{{ t('loayouts.basic.officialUrl') }}
|
|
||||||
</a-button>
|
|
||||||
|
|
||||||
<a-button type="link" size="small" @click="fnClickHelpDoc()">
|
|
||||||
{{ t('loayouts.basic.helpDoc') }}
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
</div>
|
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<a-card :bordered="false" class="login-card">
|
<a-card :bordered="false" class="login-card">
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ const graphG6Dom = ref<HTMLElement | undefined>(undefined);
|
|||||||
/**图状态 */
|
/**图状态 */
|
||||||
const graphState = reactive<Record<string, any>>({
|
const graphState = reactive<Record<string, any>>({
|
||||||
/**当前图组名 */
|
/**当前图组名 */
|
||||||
group: '5GC System Architecture5',
|
group: '5GC System Architecture',
|
||||||
/**图数据 */
|
/**图数据 */
|
||||||
data: {
|
data: {
|
||||||
combos: [],
|
combos: [],
|
||||||
|
|||||||
@@ -1,296 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { reactive, onMounted, toRaw } from 'vue';
|
|
||||||
import { PageContainer } from 'antdv-pro-layout';
|
|
||||||
import { message } from 'ant-design-vue/lib';
|
|
||||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
|
||||||
import useI18n from '@/hooks/useI18n';
|
|
||||||
import {
|
|
||||||
getPara5GFilee,
|
|
||||||
listNeInfo,
|
|
||||||
savePara5GFile,
|
|
||||||
updateNeInfo,
|
|
||||||
} from '@/api/ne/neInfo';
|
|
||||||
import useNeInfoStore from '@/store/modules/neinfo';
|
|
||||||
import Para5GForm from './components/Para5GForm.vue';
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
/**对象信息信息状态类型 */
|
|
||||||
type StateType = {
|
|
||||||
/**保存选择同步到网元窗 */
|
|
||||||
visible: boolean;
|
|
||||||
/**网元选择 */
|
|
||||||
neSelectOtions: any[];
|
|
||||||
/**同步到网元 */
|
|
||||||
sync: boolean;
|
|
||||||
syncNe: string[];
|
|
||||||
syncMsg: string;
|
|
||||||
/**表单数据 */
|
|
||||||
from: Record<string, any>;
|
|
||||||
/**OMC信息,需修改当前的IP */
|
|
||||||
omcInfo: Record<string, any>;
|
|
||||||
/**根据网元显示配置项 */
|
|
||||||
hasNE: {
|
|
||||||
amf: boolean;
|
|
||||||
upf: boolean;
|
|
||||||
ims: boolean;
|
|
||||||
mme: boolean;
|
|
||||||
};
|
|
||||||
/**确定按钮 loading */
|
|
||||||
confirmLoading: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**对象信息状态 */
|
|
||||||
let state: StateType = reactive({
|
|
||||||
visible: false,
|
|
||||||
neSelectOtions: [],
|
|
||||||
sync: false,
|
|
||||||
syncNe: [],
|
|
||||||
syncMsg: '',
|
|
||||||
from: {},
|
|
||||||
omcInfo: {},
|
|
||||||
hasNE: {
|
|
||||||
amf: false,
|
|
||||||
upf: false,
|
|
||||||
ims: false,
|
|
||||||
mme: false,
|
|
||||||
},
|
|
||||||
confirmLoading: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
/**对话框弹出确认执行函数*/
|
|
||||||
function fnModalOk() {
|
|
||||||
if (state.confirmLoading) return;
|
|
||||||
state.confirmLoading = true;
|
|
||||||
savePara5GFile({
|
|
||||||
content: toRaw(state.from),
|
|
||||||
syncNe: state.sync ? state.syncNe : [],
|
|
||||||
})
|
|
||||||
.then(res => {
|
|
||||||
if (state.sync) {
|
|
||||||
if (res.code === RESULT_CODE_SUCCESS) {
|
|
||||||
state.syncMsg = t('views.ne.neConfPara5G.syncNeDone');
|
|
||||||
} else {
|
|
||||||
state.syncMsg = res.msg;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
message.success(t('views.ne.neConfPara5G.saveOk'));
|
|
||||||
// 更新omc_ip
|
|
||||||
state.omcInfo.ip = state.from.sbi.omc_ip;
|
|
||||||
updateNeInfo(toRaw(state.omcInfo));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
state.confirmLoading = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**对话框弹出关闭执行函数*/
|
|
||||||
function fnModalCancel() {
|
|
||||||
state.visible = false;
|
|
||||||
state.sync = false;
|
|
||||||
state.syncNe = [];
|
|
||||||
state.syncMsg = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**保存文件数据*/
|
|
||||||
function fnSaveData() {
|
|
||||||
state.visible = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**获取文件数据*/
|
|
||||||
function fnGetData() {
|
|
||||||
state.confirmLoading = true;
|
|
||||||
Promise.all([
|
|
||||||
getPara5GFilee(),
|
|
||||||
listNeInfo({
|
|
||||||
pageNum: 1,
|
|
||||||
pageSize: 20,
|
|
||||||
}),
|
|
||||||
]).then(resArr => {
|
|
||||||
// 已保存的配置
|
|
||||||
if (resArr[0].code === RESULT_CODE_SUCCESS) {
|
|
||||||
Object.assign(state.from, resArr[0].data);
|
|
||||||
}
|
|
||||||
// 填充固定网元类型的ip
|
|
||||||
if (
|
|
||||||
resArr[1].code === RESULT_CODE_SUCCESS &&
|
|
||||||
Array.isArray(resArr[1].rows)
|
|
||||||
) {
|
|
||||||
for (const item of resArr[1].rows) {
|
|
||||||
switch (item.neType) {
|
|
||||||
case 'OMC':
|
|
||||||
// state.from.sbi.omc_ip = item.ip;
|
|
||||||
Object.assign(state.omcInfo, item); // 主动改OMC_IP
|
|
||||||
break;
|
|
||||||
case 'IMS':
|
|
||||||
state.from.sbi.ims_ip = item.ip;
|
|
||||||
// state.from.external.ims_sip_ip = item.ip;
|
|
||||||
state.hasNE.ims = true;
|
|
||||||
break;
|
|
||||||
case 'AMF':
|
|
||||||
state.from.sbi.amf_ip = item.ip;
|
|
||||||
state.hasNE.amf = true;
|
|
||||||
break;
|
|
||||||
case 'AUSF':
|
|
||||||
state.from.sbi.ausf_ip = item.ip;
|
|
||||||
break;
|
|
||||||
case 'UDM':
|
|
||||||
state.from.sbi.udm_ip = item.ip;
|
|
||||||
state.from.sbi.adb_ip = '0.0.0.0';
|
|
||||||
break;
|
|
||||||
case 'SMF':
|
|
||||||
state.from.sbi.smf_ip = item.ip;
|
|
||||||
break;
|
|
||||||
case 'PCF':
|
|
||||||
state.from.sbi.pcf_ip = item.ip;
|
|
||||||
break;
|
|
||||||
case 'NSSF':
|
|
||||||
state.from.sbi.nssf_ip = item.ip;
|
|
||||||
break;
|
|
||||||
case 'NRF':
|
|
||||||
state.from.sbi.nrf_ip = item.ip;
|
|
||||||
break;
|
|
||||||
case 'UPF':
|
|
||||||
state.from.sbi.upf_ip = item.ip;
|
|
||||||
state.hasNE.upf = true;
|
|
||||||
break;
|
|
||||||
case 'LMF':
|
|
||||||
state.from.sbi.lmf_ip = item.ip;
|
|
||||||
break;
|
|
||||||
case 'NEF':
|
|
||||||
state.from.sbi.nef_ip = item.ip;
|
|
||||||
break;
|
|
||||||
case 'MME':
|
|
||||||
state.from.sbi.mme_ip = item.ip;
|
|
||||||
if (item.ip.includes('.')) {
|
|
||||||
state.from.external.mmes11_ip = item.ip + '/24';
|
|
||||||
}
|
|
||||||
state.hasNE.mme = true;
|
|
||||||
break;
|
|
||||||
case 'N3IWF':
|
|
||||||
state.from.sbi.n3iwf_ip = item.ip;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state.confirmLoading = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
useNeInfoStore()
|
|
||||||
.fnNelist()
|
|
||||||
.then(res => {
|
|
||||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
|
||||||
for (const row of res.data) {
|
|
||||||
state.neSelectOtions.push({
|
|
||||||
label: `[${row.neType} ${row.neId}] ${row.neName}`,
|
|
||||||
value: `${row.neType}@${row.neId}`,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
message.warning({
|
|
||||||
content: t('common.noData'),
|
|
||||||
duration: 2,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
// 获取文件数据
|
|
||||||
fnGetData();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<PageContainer>
|
|
||||||
<template #content>
|
|
||||||
{{ t('views.ne.neConfPara5G.headerTip') }}
|
|
||||||
<RouterLink :to="{ name: 'NeQuickSetup_2142' }">
|
|
||||||
{{ t('views.ne.neConfPara5G.headerTipToPage') }}
|
|
||||||
</RouterLink>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<a-card :bordered="false">
|
|
||||||
<!-- 公共参数表单 -->
|
|
||||||
<Para5GForm v-model:data="state.from" :ne="state.hasNE"></Para5GForm>
|
|
||||||
|
|
||||||
<div style="padding: 24px 12px 0; text-align: end">
|
|
||||||
<a-space :size="8" align="center">
|
|
||||||
<a-button
|
|
||||||
type="primary"
|
|
||||||
:loading="state.confirmLoading"
|
|
||||||
@click="fnSaveData()"
|
|
||||||
>
|
|
||||||
<template #icon><SaveOutlined /></template>
|
|
||||||
{{ t('views.ne.neConfPara5G.save') }}
|
|
||||||
</a-button>
|
|
||||||
<a-button
|
|
||||||
type="default"
|
|
||||||
:loading="state.confirmLoading"
|
|
||||||
@click.prevent="fnGetData()"
|
|
||||||
>
|
|
||||||
<template #icon><ReloadOutlined /></template>
|
|
||||||
{{ t('views.ne.neConfPara5G.reload') }}
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
</div>
|
|
||||||
</a-card>
|
|
||||||
|
|
||||||
<!-- 保存选择同步网元 -->
|
|
||||||
<ProModal
|
|
||||||
:drag="true"
|
|
||||||
:minHeight="0"
|
|
||||||
:keyboard="false"
|
|
||||||
:mask-closable="false"
|
|
||||||
:visible="state.visible"
|
|
||||||
:title="t('views.ne.neConfPara5G.title')"
|
|
||||||
:confirm-loading="state.confirmLoading"
|
|
||||||
@ok="fnModalOk"
|
|
||||||
@cancel="fnModalCancel"
|
|
||||||
>
|
|
||||||
<a-form
|
|
||||||
name="syncNeModal"
|
|
||||||
layout="horizontal"
|
|
||||||
:label-col="{ span: 5 }"
|
|
||||||
:label-wrap="true"
|
|
||||||
>
|
|
||||||
<a-form-item :label="t('views.ne.neConfPara5G.sync')" name="sync">
|
|
||||||
<a-switch
|
|
||||||
:checked-children="t('common.switch.open')"
|
|
||||||
:un-checked-children="t('common.switch.shut')"
|
|
||||||
v-model:checked="state.sync"
|
|
||||||
:disabled="state.confirmLoading"
|
|
||||||
></a-switch>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item
|
|
||||||
:label="t('views.ne.neConfPara5G.syncNe')"
|
|
||||||
name="syncNe"
|
|
||||||
v-if="state.sync"
|
|
||||||
>
|
|
||||||
<a-select
|
|
||||||
v-model:value="state.syncNe"
|
|
||||||
mode="multiple"
|
|
||||||
:placeholder="t('common.selectPlease')"
|
|
||||||
:max-tag-count="3"
|
|
||||||
:options="state.neSelectOtions"
|
|
||||||
>
|
|
||||||
<template #maxTagPlaceholder="omittedValues">
|
|
||||||
<span>+ {{ omittedValues.length }} ...</span>
|
|
||||||
</template>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="Sync Msg" name="syncMsg" v-if="state.syncMsg">
|
|
||||||
<a-textarea
|
|
||||||
:disabled="true"
|
|
||||||
:value="state.syncMsg"
|
|
||||||
:auto-size="{ minRows: 2, maxRows: 8 }"
|
|
||||||
style="background-color: transparent; color: rgba(0, 0, 0, 0.85)"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
</ProModal>
|
|
||||||
</PageContainer>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
|
||||||
412
src/views/ne/neConfig/hooks/useConfigArray.ts
Normal file
412
src/views/ne/neConfig/hooks/useConfigArray.ts
Normal file
@@ -0,0 +1,412 @@
|
|||||||
|
import {
|
||||||
|
addNeConfigData,
|
||||||
|
delNeConfigData,
|
||||||
|
editNeConfigData,
|
||||||
|
} from '@/api/ne/neConfig';
|
||||||
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
|
import { Modal } from 'ant-design-vue/lib';
|
||||||
|
import { SizeType } from 'ant-design-vue/lib/config-provider';
|
||||||
|
import message from 'ant-design-vue/lib/message';
|
||||||
|
import { reactive, watch } from 'vue';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数配置array类型
|
||||||
|
* @param param 父级传入 { t, treeState, neTypeSelect, fnActiveConfigNode, ruleVerification, modalState, fnModalCancel}
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function useConfigArray({
|
||||||
|
t,
|
||||||
|
treeState,
|
||||||
|
neTypeSelect,
|
||||||
|
fnActiveConfigNode,
|
||||||
|
ruleVerification,
|
||||||
|
modalState,
|
||||||
|
fnModalCancel,
|
||||||
|
}: any) {
|
||||||
|
/**多列列表状态类型 */
|
||||||
|
type ArrayStateType = {
|
||||||
|
/**紧凑型 */
|
||||||
|
size: SizeType;
|
||||||
|
/**多列嵌套记录字段 */
|
||||||
|
columns: Record<string, any>[];
|
||||||
|
/**表格字段列排序 */
|
||||||
|
columnsDnd: Record<string, any>[];
|
||||||
|
/**多列记录数据 */
|
||||||
|
columnsData: Record<string, any>[];
|
||||||
|
/**多列嵌套展开key */
|
||||||
|
arrayChildExpandKeys: any[];
|
||||||
|
|
||||||
|
/**多列记录数据 */
|
||||||
|
data: Record<string, any>[];
|
||||||
|
/**多列记录规则 */
|
||||||
|
dataRule: Record<string, any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**多列列表状态 */
|
||||||
|
let arrayState: ArrayStateType = reactive({
|
||||||
|
size: 'small',
|
||||||
|
columns: [],
|
||||||
|
columnsDnd: [],
|
||||||
|
columnsData: [],
|
||||||
|
arrayChildExpandKeys: [],
|
||||||
|
data: [],
|
||||||
|
dataRule: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**多列表编辑 */
|
||||||
|
function arrayEdit(rowIndex: Record<string, any>) {
|
||||||
|
const item = arrayState.data.find((s: any) => s.key === rowIndex.value);
|
||||||
|
if (!item) return;
|
||||||
|
const from = arrayInitEdit(item, arrayState.dataRule);
|
||||||
|
// 处理信息
|
||||||
|
const row: Record<string, any> = {};
|
||||||
|
for (const v of from.record) {
|
||||||
|
if (Array.isArray(v.array)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
row[v.name] = Object.assign({}, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 特殊SMF-upfid选择
|
||||||
|
if (neTypeSelect.value[0] === 'SMF' && Reflect.has(row, 'upfId')) {
|
||||||
|
const v = row.upfId.value;
|
||||||
|
if (typeof v === 'string') {
|
||||||
|
if (v === '') {
|
||||||
|
row.upfId.value = [];
|
||||||
|
} else if (v.includes(';')) {
|
||||||
|
row.upfId.value = v.split(';');
|
||||||
|
} else if (v.includes(',')) {
|
||||||
|
row.upfId.value = v.split(',');
|
||||||
|
} else {
|
||||||
|
row.upfId.value = [v];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
modalState.from = row;
|
||||||
|
modalState.type = 'arrayEdit';
|
||||||
|
modalState.title = `${treeState.selectNode.paramDisplay} ${from.title}`;
|
||||||
|
modalState.key = from.key;
|
||||||
|
modalState.data = from.record.filter((v: any) => !Array.isArray(v.array));
|
||||||
|
modalState.visible = true;
|
||||||
|
|
||||||
|
// 关闭嵌套
|
||||||
|
arrayState.arrayChildExpandKeys = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表编辑关闭 */
|
||||||
|
function arrayEditClose() {
|
||||||
|
arrayState.arrayChildExpandKeys = [];
|
||||||
|
fnModalCancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表编辑确认 */
|
||||||
|
function arrayEditOk(from: Record<string, any>) {
|
||||||
|
const loc = `${from['index']['value']}`;
|
||||||
|
|
||||||
|
// 特殊SMF-upfid选择
|
||||||
|
if (neTypeSelect.value[0] === 'SMF' && Reflect.has(from, 'upfId')) {
|
||||||
|
const v = from.upfId.value;
|
||||||
|
if (Array.isArray(v)) {
|
||||||
|
from.upfId.value = v.join(';');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历提取属性和值
|
||||||
|
let data: Record<string, any> = {};
|
||||||
|
for (const key in from) {
|
||||||
|
// 子嵌套的不插入
|
||||||
|
if (from[key]['array']) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 检查规则
|
||||||
|
const [ok, msg] = ruleVerification(from[key]);
|
||||||
|
if (!ok) {
|
||||||
|
message.warning({
|
||||||
|
content: `${msg}`,
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data[key] = from[key]['value'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送
|
||||||
|
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) {
|
||||||
|
message.success({
|
||||||
|
content: t('views.ne.neConfig.updateItem', {
|
||||||
|
num: modalState.title,
|
||||||
|
}),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
fnActiveConfigNode('#');
|
||||||
|
} else {
|
||||||
|
message.warning({
|
||||||
|
content: t('views.ne.neConfig.updateItemErr'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hide();
|
||||||
|
arrayEditClose();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表删除单行 */
|
||||||
|
function arrayDelete(rowIndex: Record<string, any>) {
|
||||||
|
const loc = `${rowIndex.value}`;
|
||||||
|
const title = `${treeState.selectNode.paramDisplay} Index-${loc}`;
|
||||||
|
|
||||||
|
Modal.confirm({
|
||||||
|
title: t('common.tipTitle'),
|
||||||
|
content: t('views.ne.neConfig.delItemTip', {
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表新增单行 */
|
||||||
|
function arrayAdd() {
|
||||||
|
const from = arrayInitAdd(arrayState.data, arrayState.dataRule);
|
||||||
|
|
||||||
|
// 处理信息
|
||||||
|
const row: Record<string, any> = {};
|
||||||
|
for (const v of from.record) {
|
||||||
|
if (Array.isArray(v.array)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
row[v.name] = Object.assign({}, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 特殊SMF-upfid选择
|
||||||
|
if (neTypeSelect.value[0] === 'SMF' && Reflect.has(row, 'upfId')) {
|
||||||
|
const v = row.upfId.value;
|
||||||
|
if (typeof v === 'string') {
|
||||||
|
if (v === '') {
|
||||||
|
row.upfId.value = [];
|
||||||
|
} else if (v.includes(';')) {
|
||||||
|
row.upfId.value = v.split(';');
|
||||||
|
} else if (v.includes(',')) {
|
||||||
|
row.upfId.value = v.split(',');
|
||||||
|
} else {
|
||||||
|
row.upfId.value = [v];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
modalState.from = row;
|
||||||
|
modalState.type = 'arrayAdd';
|
||||||
|
modalState.title = `${treeState.selectNode.paramDisplay} ${from.title}`;
|
||||||
|
modalState.key = from.key;
|
||||||
|
modalState.data = from.record.filter((v: any) => !Array.isArray(v.array));
|
||||||
|
modalState.visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表新增单行确认 */
|
||||||
|
function arrayAddOk(from: Record<string, any>) {
|
||||||
|
// 特殊SMF-upfid选择
|
||||||
|
if (neTypeSelect.value[0] === 'SMF' && Reflect.has(from, 'upfId')) {
|
||||||
|
const v = from.upfId.value;
|
||||||
|
if (Array.isArray(v)) {
|
||||||
|
from.upfId.value = v.join(';');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历提取属性和值
|
||||||
|
let data: Record<string, any> = {};
|
||||||
|
for (const key in from) {
|
||||||
|
// 子嵌套的不插入
|
||||||
|
if (from[key]['array']) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 检查规则
|
||||||
|
const [ok, msg] = ruleVerification(from[key]);
|
||||||
|
if (!ok) {
|
||||||
|
message.warning({
|
||||||
|
content: `${msg}`,
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data[key] = from[key]['value'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送
|
||||||
|
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) {
|
||||||
|
message.success({
|
||||||
|
content: t('views.ne.neConfig.addItemOk', {
|
||||||
|
num: modalState.title,
|
||||||
|
}),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
fnActiveConfigNode('#');
|
||||||
|
} else {
|
||||||
|
message.warning({
|
||||||
|
content: t('views.ne.neConfig.addItemErr'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hide();
|
||||||
|
arrayEditClose();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表编辑行数据初始化 */
|
||||||
|
function arrayInitEdit(data: Record<string, any>, dataRule: any) {
|
||||||
|
const dataFrom = data.record;
|
||||||
|
const ruleFrom = Object.assign({}, JSON.parse(JSON.stringify(dataRule)));
|
||||||
|
for (const row of ruleFrom.record) {
|
||||||
|
// 子嵌套的不初始
|
||||||
|
if (row.array) {
|
||||||
|
row.value = [];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 查找项的值
|
||||||
|
const item = dataFrom.find((s: any) => s.name === row.name);
|
||||||
|
if (!item) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 可选的
|
||||||
|
row.optional = 'true';
|
||||||
|
// 根据规则类型转值
|
||||||
|
if (['enum', 'int'].includes(row.type)) {
|
||||||
|
row.value = Number(item.value);
|
||||||
|
} else if ('bool' === row.type) {
|
||||||
|
row.value = Boolean(item.value);
|
||||||
|
} else {
|
||||||
|
row.value = item.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ruleFrom.key = data.key;
|
||||||
|
ruleFrom.title = data.title;
|
||||||
|
return ruleFrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表新增行数据初始化 */
|
||||||
|
function arrayInitAdd(data: any[], dataRule: any) {
|
||||||
|
// 有数据时取得最后的index
|
||||||
|
let dataLastIndex = 0;
|
||||||
|
if (data.length !== 0) {
|
||||||
|
const lastFrom = Object.assign(
|
||||||
|
{},
|
||||||
|
JSON.parse(JSON.stringify(data.at(-1)))
|
||||||
|
);
|
||||||
|
if (lastFrom.record.length > 0) {
|
||||||
|
dataLastIndex = parseInt(lastFrom.key);
|
||||||
|
dataLastIndex += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ruleFrom = Object.assign({}, JSON.parse(JSON.stringify(dataRule)));
|
||||||
|
for (const row of ruleFrom.record) {
|
||||||
|
// 子嵌套的不初始
|
||||||
|
if (row.array) {
|
||||||
|
row.value = [];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 可选的
|
||||||
|
row.optional = 'true';
|
||||||
|
// index值
|
||||||
|
if (row.name === 'index') {
|
||||||
|
let newIndex =
|
||||||
|
dataLastIndex !== 0 ? dataLastIndex : parseInt(row.value);
|
||||||
|
if (isNaN(newIndex)) {
|
||||||
|
newIndex = 0;
|
||||||
|
}
|
||||||
|
row.value = newIndex;
|
||||||
|
ruleFrom.key = newIndex;
|
||||||
|
ruleFrom.title = `Index-${newIndex}`;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 根据规则类型转值
|
||||||
|
if (['enum', 'int'].includes(row.type)) {
|
||||||
|
row.value = Number(row.value);
|
||||||
|
}
|
||||||
|
if ('bool' === row.type) {
|
||||||
|
row.value = Boolean(row.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 特殊SMF-upfid选择
|
||||||
|
if (neTypeSelect.value[0] === 'SMF' && row.name === 'upfId') {
|
||||||
|
const v = row.value;
|
||||||
|
if (typeof v === 'string') {
|
||||||
|
if (v === '') {
|
||||||
|
row.value = [];
|
||||||
|
} else if (v.includes(';')) {
|
||||||
|
row.value = v.split(';');
|
||||||
|
} else if (v.includes(',')) {
|
||||||
|
row.value = v.split(',');
|
||||||
|
} else {
|
||||||
|
row.value = [v];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ruleFrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听表格字段列排序变化关闭展开
|
||||||
|
watch(
|
||||||
|
() => arrayState.columnsDnd,
|
||||||
|
() => {
|
||||||
|
arrayEditClose();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
arrayState,
|
||||||
|
arrayEdit,
|
||||||
|
arrayEditClose,
|
||||||
|
arrayEditOk,
|
||||||
|
arrayDelete,
|
||||||
|
arrayAdd,
|
||||||
|
arrayAddOk,
|
||||||
|
arrayInitEdit,
|
||||||
|
arrayInitAdd,
|
||||||
|
};
|
||||||
|
}
|
||||||
353
src/views/ne/neConfig/hooks/useConfigArrayChild.ts
Normal file
353
src/views/ne/neConfig/hooks/useConfigArrayChild.ts
Normal file
@@ -0,0 +1,353 @@
|
|||||||
|
import {
|
||||||
|
addNeConfigData,
|
||||||
|
editNeConfigData,
|
||||||
|
delNeConfigData,
|
||||||
|
} from '@/api/ne/neConfig';
|
||||||
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
|
import { Modal } from 'ant-design-vue/lib';
|
||||||
|
import { SizeType } from 'ant-design-vue/lib/config-provider';
|
||||||
|
import message from 'ant-design-vue/lib/message';
|
||||||
|
import { nextTick, reactive } from 'vue';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数配置array类型的嵌套array
|
||||||
|
* @param param 父级传入 { t, treeState, neTypeSelect, fnActiveConfigNode, ruleVerification, modalState, arrayState, arrayInitEdit, arrayInitAdd, arrayEditClose}
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function useConfigArrayChild({
|
||||||
|
t,
|
||||||
|
treeState,
|
||||||
|
neTypeSelect,
|
||||||
|
fnActiveConfigNode,
|
||||||
|
ruleVerification,
|
||||||
|
modalState,
|
||||||
|
arrayState,
|
||||||
|
arrayInitEdit,
|
||||||
|
arrayInitAdd,
|
||||||
|
arrayEditClose,
|
||||||
|
}: any) {
|
||||||
|
/**多列嵌套列表状态类型 */
|
||||||
|
type ArrayChildStateType = {
|
||||||
|
/**标题 */
|
||||||
|
title: string;
|
||||||
|
/**层级index */
|
||||||
|
loc: string;
|
||||||
|
/**紧凑型 */
|
||||||
|
size: SizeType;
|
||||||
|
/**多列嵌套记录字段 */
|
||||||
|
columns: Record<string, any>[];
|
||||||
|
/**表格字段列排序 */
|
||||||
|
columnsDnd: Record<string, any>[];
|
||||||
|
/**多列记录数据 */
|
||||||
|
columnsData: Record<string, any>[];
|
||||||
|
|
||||||
|
/**多列嵌套记录数据 */
|
||||||
|
data: Record<string, any>[];
|
||||||
|
/**多列嵌套记录规则 */
|
||||||
|
dataRule: Record<string, any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**多列嵌套表格状态 */
|
||||||
|
let arrayChildState: ArrayChildStateType = reactive({
|
||||||
|
title: '',
|
||||||
|
loc: '',
|
||||||
|
size: 'small',
|
||||||
|
columns: [],
|
||||||
|
columnsDnd: [],
|
||||||
|
columnsData: [],
|
||||||
|
data: [],
|
||||||
|
dataRule: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**多列表展开嵌套行 */
|
||||||
|
function arrayChildExpand(
|
||||||
|
indexRow: Record<string, any>,
|
||||||
|
row: Record<string, any>
|
||||||
|
) {
|
||||||
|
const loc = indexRow.value;
|
||||||
|
if (arrayChildState.loc === `${loc}/${row.name}`) {
|
||||||
|
arrayChildState.loc = '';
|
||||||
|
arrayState.arrayChildExpandKeys = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
arrayChildState.loc = '';
|
||||||
|
arrayState.arrayChildExpandKeys = [];
|
||||||
|
const from = Object.assign({}, JSON.parse(JSON.stringify(row)));
|
||||||
|
// 无数据时
|
||||||
|
if (!Array.isArray(from.value)) {
|
||||||
|
from.value = [];
|
||||||
|
}
|
||||||
|
const dataArr = Object.freeze(from.value);
|
||||||
|
const ruleArr = Object.freeze(from.array);
|
||||||
|
|
||||||
|
// 列表项数据
|
||||||
|
const dataArray: Record<string, any>[] = [];
|
||||||
|
for (const item of dataArr) {
|
||||||
|
const index = item['index'];
|
||||||
|
let record: Record<string, any>[] = [];
|
||||||
|
for (const key of Object.keys(item)) {
|
||||||
|
// 规则为准
|
||||||
|
for (const rule of ruleArr) {
|
||||||
|
if (rule['name'] === key) {
|
||||||
|
const ruleItem = Object.assign({ optional: 'true' }, rule, {
|
||||||
|
value: item[key],
|
||||||
|
});
|
||||||
|
record.push(ruleItem);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// dataArray.push(record);
|
||||||
|
dataArray.push({ title: `Index-${index}`, key: index, record });
|
||||||
|
}
|
||||||
|
arrayChildState.data = dataArray;
|
||||||
|
|
||||||
|
// 无数据时,用于新增
|
||||||
|
arrayChildState.dataRule = {
|
||||||
|
title: `Index-0`,
|
||||||
|
key: 0,
|
||||||
|
record: ruleArr,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 列表数据
|
||||||
|
const columnsData: Record<string, any>[] = [];
|
||||||
|
for (const v of arrayChildState.data) {
|
||||||
|
const row: Record<string, any> = {};
|
||||||
|
for (const item of v.record) {
|
||||||
|
row[item.name] = item;
|
||||||
|
}
|
||||||
|
columnsData.push(row);
|
||||||
|
}
|
||||||
|
arrayChildState.columnsData = columnsData;
|
||||||
|
|
||||||
|
// 列表字段
|
||||||
|
const columns: Record<string, any>[] = [];
|
||||||
|
for (const rule of arrayChildState.dataRule.record) {
|
||||||
|
columns.push({
|
||||||
|
title: rule.display,
|
||||||
|
dataIndex: rule.name,
|
||||||
|
align: 'left',
|
||||||
|
resizable: true,
|
||||||
|
width: 50,
|
||||||
|
minWidth: 50,
|
||||||
|
maxWidth: 250,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
columns.push({
|
||||||
|
title: t('common.operate'),
|
||||||
|
dataIndex: 'index',
|
||||||
|
key: 'index',
|
||||||
|
align: 'center',
|
||||||
|
fixed: 'right',
|
||||||
|
width: 100,
|
||||||
|
});
|
||||||
|
arrayChildState.columns = columns;
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
// 设置展开key
|
||||||
|
arrayState.arrayChildExpandKeys = [indexRow];
|
||||||
|
// 层级标识
|
||||||
|
arrayChildState.loc = `${loc}/${from['name']}`;
|
||||||
|
// 设置展开列表标题
|
||||||
|
arrayChildState.title = `${from['display']}`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表嵌套行编辑 */
|
||||||
|
function arrayChildEdit(rowIndex: Record<string, any>) {
|
||||||
|
const item = arrayChildState.data.find(
|
||||||
|
(s: any) => s.key === rowIndex.value
|
||||||
|
);
|
||||||
|
if (!item) return;
|
||||||
|
const from = arrayInitEdit(item, arrayChildState.dataRule);
|
||||||
|
// 处理信息
|
||||||
|
const row: Record<string, any> = {};
|
||||||
|
for (const v of from.record) {
|
||||||
|
if (Array.isArray(v.array)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
row[v.name] = Object.assign({}, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
modalState.from = row;
|
||||||
|
modalState.type = 'arrayChildEdit';
|
||||||
|
modalState.title = `${arrayChildState.title} ${from.title}`;
|
||||||
|
modalState.key = from.key;
|
||||||
|
modalState.data = from.record.filter((v: any) => !Array.isArray(v.array));
|
||||||
|
modalState.visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表嵌套行编辑确认 */
|
||||||
|
function arrayChildEditOk(from: Record<string, any>) {
|
||||||
|
const loc = `${arrayChildState.loc}/${from['index']['value']}`;
|
||||||
|
|
||||||
|
let data: Record<string, any> = {};
|
||||||
|
for (const key in from) {
|
||||||
|
// 子嵌套的不插入
|
||||||
|
if (from[key]['array']) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 检查规则
|
||||||
|
const [ok, msg] = ruleVerification(from[key]);
|
||||||
|
if (!ok) {
|
||||||
|
message.warning({
|
||||||
|
content: `${msg}`,
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data[key] = from[key]['value'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送
|
||||||
|
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) {
|
||||||
|
message.success({
|
||||||
|
content: t('views.ne.neConfig.updateItem', {
|
||||||
|
num: modalState.title,
|
||||||
|
}),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
fnActiveConfigNode('#');
|
||||||
|
} else {
|
||||||
|
message.warning({
|
||||||
|
content: t('views.ne.neConfig.updateItemErr'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hide();
|
||||||
|
arrayEditClose();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表嵌套行删除单行 */
|
||||||
|
function arrayChildDelete(rowIndex: Record<string, any>) {
|
||||||
|
const index = rowIndex.value;
|
||||||
|
const loc = `${arrayChildState.loc}/${index}`;
|
||||||
|
const title = `${arrayChildState.title} Index-${index}`;
|
||||||
|
|
||||||
|
Modal.confirm({
|
||||||
|
title: t('common.tipTitle'),
|
||||||
|
content: t('views.ne.neConfig.delItemTip', {
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表嵌套行新增单行 */
|
||||||
|
function arrayChildAdd() {
|
||||||
|
const from = arrayInitAdd(arrayChildState.data, arrayChildState.dataRule);
|
||||||
|
// 处理信息
|
||||||
|
const row: Record<string, any> = {};
|
||||||
|
for (const v of from.record) {
|
||||||
|
if (Array.isArray(v.array)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
row[v.name] = Object.assign({}, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
modalState.from = row;
|
||||||
|
modalState.type = 'arrayChildAdd';
|
||||||
|
modalState.title = `${arrayChildState.title} ${from.title}`;
|
||||||
|
modalState.key = from.key;
|
||||||
|
modalState.data = from.record.filter((v: any) => !Array.isArray(v.array));
|
||||||
|
modalState.visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表新增单行确认 */
|
||||||
|
function arrayChildAddOk(from: Record<string, any>) {
|
||||||
|
const loc = `${arrayChildState.loc}/${from['index']['value']}`;
|
||||||
|
|
||||||
|
let data: Record<string, any> = {};
|
||||||
|
for (const key in from) {
|
||||||
|
// 子嵌套的不插入
|
||||||
|
if (from[key]['array']) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 检查规则
|
||||||
|
const [ok, msg] = ruleVerification(from[key]);
|
||||||
|
if (!ok) {
|
||||||
|
message.warning({
|
||||||
|
content: `${msg}`,
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data[key] = from[key]['value'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送
|
||||||
|
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) {
|
||||||
|
message.success({
|
||||||
|
content: t('views.ne.neConfig.addItemOk', {
|
||||||
|
num: modalState.title,
|
||||||
|
}),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
fnActiveConfigNode('#');
|
||||||
|
} else {
|
||||||
|
message.warning({
|
||||||
|
content: t('views.ne.neConfig.addItemErr'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hide();
|
||||||
|
arrayEditClose();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
arrayChildState,
|
||||||
|
arrayChildExpand,
|
||||||
|
arrayChildEdit,
|
||||||
|
arrayChildEditOk,
|
||||||
|
arrayChildDelete,
|
||||||
|
arrayChildAdd,
|
||||||
|
arrayChildAddOk,
|
||||||
|
};
|
||||||
|
}
|
||||||
152
src/views/ne/neConfig/hooks/useConfigList.ts
Normal file
152
src/views/ne/neConfig/hooks/useConfigList.ts
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
import { editNeConfigData } from '@/api/ne/neConfig';
|
||||||
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
|
import { SizeType } from 'ant-design-vue/lib/config-provider';
|
||||||
|
import message from 'ant-design-vue/lib/message';
|
||||||
|
import { reactive, toRaw } from 'vue';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list类型参数处理
|
||||||
|
* @param param 父级传入 {t, treeState, neTypeSelect, ruleVerification}
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function useConfigList({
|
||||||
|
t,
|
||||||
|
treeState,
|
||||||
|
neTypeSelect,
|
||||||
|
ruleVerification,
|
||||||
|
}: any) {
|
||||||
|
/**单列表状态类型 */
|
||||||
|
type ListStateType = {
|
||||||
|
/**紧凑型 */
|
||||||
|
size: SizeType;
|
||||||
|
/**单列记录字段 */
|
||||||
|
columns: Record<string, any>[];
|
||||||
|
/**单列记录数据 */
|
||||||
|
data: Record<string, any>[];
|
||||||
|
/**编辑行记录 */
|
||||||
|
editRecord: Record<string, any>;
|
||||||
|
/**确认提交等待 */
|
||||||
|
confirmLoading: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**单列表状态 */
|
||||||
|
let listState: ListStateType = reactive({
|
||||||
|
size: 'small',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
title: 'Key',
|
||||||
|
dataIndex: 'display',
|
||||||
|
align: 'left',
|
||||||
|
width: '30%',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Value',
|
||||||
|
dataIndex: 'value',
|
||||||
|
align: 'left',
|
||||||
|
width: '70%',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
data: [],
|
||||||
|
confirmLoading: false,
|
||||||
|
editRecord: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**单列表编辑 */
|
||||||
|
function listEdit(row: Record<string, any>) {
|
||||||
|
if (
|
||||||
|
listState.confirmLoading ||
|
||||||
|
['read-only', 'read', 'ro'].includes(row.access)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
listState.editRecord = Object.assign({}, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**单列表编辑关闭 */
|
||||||
|
function listEditClose() {
|
||||||
|
listState.confirmLoading = false;
|
||||||
|
listState.editRecord = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**单列表编辑确认 */
|
||||||
|
function listEditOk() {
|
||||||
|
if (listState.confirmLoading) return;
|
||||||
|
const from = toRaw(listState.editRecord);
|
||||||
|
// 检查规则
|
||||||
|
const [ok, msg] = ruleVerification(from);
|
||||||
|
if (!ok) {
|
||||||
|
message.warning({
|
||||||
|
content: `${msg}`,
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
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) {
|
||||||
|
message.success({
|
||||||
|
content: t('views.ne.neConfig.updateValue', {
|
||||||
|
num: from['display'],
|
||||||
|
}),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
// 改变表格数据
|
||||||
|
const item = listState.data.find(
|
||||||
|
(item: Record<string, any>) => from['name'] === item['name']
|
||||||
|
);
|
||||||
|
if (item) {
|
||||||
|
Object.assign(item, listState.editRecord);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.warning({
|
||||||
|
content: t('views.ne.neConfig.updateValueErr'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hide();
|
||||||
|
listState.confirmLoading = false;
|
||||||
|
listState.editRecord = {};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**表格分页器参数 */
|
||||||
|
let tablePagination = reactive({
|
||||||
|
/**当前页数 */
|
||||||
|
current: 1,
|
||||||
|
/**每页条数 */
|
||||||
|
pageSize: 10,
|
||||||
|
/**默认的每页条数 */
|
||||||
|
defaultPageSize: 10,
|
||||||
|
/**指定每页可以显示多少条 */
|
||||||
|
pageSizeOptions: ['10', '20', '50', '100'],
|
||||||
|
/**只有一页时是否隐藏分页器 */
|
||||||
|
hideOnSinglePage: true,
|
||||||
|
/**是否可以快速跳转至某页 */
|
||||||
|
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;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { tablePagination, listState, listEdit, listEditClose, listEditOk };
|
||||||
|
}
|
||||||
192
src/views/ne/neConfig/hooks/useOptions.ts
Normal file
192
src/views/ne/neConfig/hooks/useOptions.ts
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
import { getNeConfigData } from '@/api/ne/neConfig';
|
||||||
|
import { regExpIPv4, regExpIPv6, validURL } from '@/utils/regular-utils';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数公共函数
|
||||||
|
* @param param 父级传入 {t}
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function useOptions({ t }: any) {
|
||||||
|
/**规则校验 */
|
||||||
|
function ruleVerification(row: Record<string, any>): (string | boolean)[] {
|
||||||
|
let result = [true, ''];
|
||||||
|
const type = row.type;
|
||||||
|
const value = row.value;
|
||||||
|
const filter = row.filter;
|
||||||
|
const display = row.display;
|
||||||
|
|
||||||
|
// 子嵌套的不检查
|
||||||
|
if (row.array) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 可选的同时没有值不检查
|
||||||
|
if (row.optional === 'true' && !value) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
switch (type) {
|
||||||
|
case 'int':
|
||||||
|
// filter: "0~128"
|
||||||
|
|
||||||
|
if (filter && filter.indexOf('~') !== -1) {
|
||||||
|
const filterArr = filter.split('~');
|
||||||
|
const minInt = parseInt(filterArr[0]);
|
||||||
|
const maxInt = parseInt(filterArr[1]);
|
||||||
|
const valueInt = parseInt(value);
|
||||||
|
if (valueInt < minInt || valueInt > maxInt) {
|
||||||
|
return [
|
||||||
|
false,
|
||||||
|
t('views.ne.neConfig.requireInt', {
|
||||||
|
display,
|
||||||
|
filter,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'ipv4':
|
||||||
|
if (!regExpIPv4.test(value)) {
|
||||||
|
return [
|
||||||
|
false,
|
||||||
|
t('views.ne.neConfig.requireIpv4', { display }),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'ipv6':
|
||||||
|
if (!regExpIPv6.test(value)) {
|
||||||
|
return [
|
||||||
|
false,
|
||||||
|
t('views.ne.neConfig.requireIpv6', { display }),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'enum':
|
||||||
|
if (filter && filter.indexOf('{') === 1) {
|
||||||
|
let filterJson: Record<string, any> = {};
|
||||||
|
try {
|
||||||
|
filterJson = JSON.parse(filter); //string---json
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Object.keys(filterJson).includes(`${value}`)) {
|
||||||
|
return [
|
||||||
|
false,
|
||||||
|
t('views.ne.neConfig.requireEnum', { display }),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'bool':
|
||||||
|
// filter: '{"0":"false", "1":"true"}'
|
||||||
|
|
||||||
|
if (filter && filter.indexOf('{') === 1) {
|
||||||
|
let filterJson: Record<string, any> = {};
|
||||||
|
try {
|
||||||
|
filterJson = JSON.parse(filter); //string---json
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Object.values(filterJson).includes(`${value}`)) {
|
||||||
|
return [
|
||||||
|
false,
|
||||||
|
t('views.ne.neConfig.requireBool', { display }),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'string':
|
||||||
|
// filter: "0~128"
|
||||||
|
|
||||||
|
// 字符串长度判断
|
||||||
|
if (filter && filter.indexOf('~') !== -1) {
|
||||||
|
try {
|
||||||
|
const filterArr = filter.split('~');
|
||||||
|
let rule = new RegExp(
|
||||||
|
'^\\S{' + filterArr[0] + ',' + filterArr[1] + '}$'
|
||||||
|
);
|
||||||
|
if (!rule.test(value)) {
|
||||||
|
return [
|
||||||
|
false,
|
||||||
|
t('views.ne.neConfig.requireString', {
|
||||||
|
display,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 字符串http判断
|
||||||
|
if (value.startsWith('http')) {
|
||||||
|
try {
|
||||||
|
if (!validURL(value)) {
|
||||||
|
return [
|
||||||
|
false,
|
||||||
|
t('views.ne.neConfig.requireString', {
|
||||||
|
display,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'regex':
|
||||||
|
// filter: "^[0-9]{3}$"
|
||||||
|
|
||||||
|
if (filter) {
|
||||||
|
try {
|
||||||
|
let regex = new RegExp(filter);
|
||||||
|
if (!regex.test(value)) {
|
||||||
|
return [
|
||||||
|
false,
|
||||||
|
t('views.ne.neConfig.requireString', {
|
||||||
|
display,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return [
|
||||||
|
false,
|
||||||
|
t('views.ne.neConfig.requireUn', { display }),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**upfId可选择 */
|
||||||
|
const smfByUPFIdOptions = ref<{ value: string; label: string }[]>([]);
|
||||||
|
/**加载smf配置的upfId */
|
||||||
|
function smfByUPFIdLoadData(neId: string) {
|
||||||
|
getNeConfigData({
|
||||||
|
neType: 'SMF',
|
||||||
|
neId: neId,
|
||||||
|
paramName: 'upfConfig',
|
||||||
|
}).then(res => {
|
||||||
|
smfByUPFIdOptions.value = [];
|
||||||
|
for (const s of res.data) {
|
||||||
|
smfByUPFIdOptions.value.push({
|
||||||
|
value: s.id,
|
||||||
|
label: s.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
ruleVerification,
|
||||||
|
smfByUPFIdLoadData,
|
||||||
|
smfByUPFIdOptions,
|
||||||
|
};
|
||||||
|
}
|
||||||
951
src/views/ne/neConfig/index.vue
Normal file
951
src/views/ne/neConfig/index.vue
Normal file
@@ -0,0 +1,951 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, ref, onMounted, toRaw, watch } from 'vue';
|
||||||
|
import { PageContainer } from 'antdv-pro-layout';
|
||||||
|
import { message } from 'ant-design-vue/lib';
|
||||||
|
import { DataNode } from 'ant-design-vue/lib/tree';
|
||||||
|
import useI18n from '@/hooks/useI18n';
|
||||||
|
import TableColumnsDnd from '@/components/TableColumnsDnd/index.vue';
|
||||||
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
|
import useNeInfoStore from '@/store/modules/neinfo';
|
||||||
|
import useOptions from './hooks/useOptions';
|
||||||
|
import useConfigList from './hooks/useConfigList';
|
||||||
|
import useConfigArray from './hooks/useConfigArray';
|
||||||
|
import useConfigArrayChild from './hooks/useConfigArrayChild';
|
||||||
|
import { getAllNeConfig, getNeConfigData } from '@/api/ne/neConfig';
|
||||||
|
const neInfoStore = useNeInfoStore();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const { ruleVerification, smfByUPFIdLoadData, smfByUPFIdOptions } = useOptions({
|
||||||
|
t,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**网元类型_多neId */
|
||||||
|
let neCascaderOptions = ref<Record<string, any>[]>([]);
|
||||||
|
|
||||||
|
/**网元类型选择 type,id */
|
||||||
|
let neTypeSelect = ref<string[]>(['', '']);
|
||||||
|
|
||||||
|
/**左侧导航是否可收起 */
|
||||||
|
let collapsible = ref<boolean>(true);
|
||||||
|
|
||||||
|
/**改变收起状态 */
|
||||||
|
function changeCollapsible() {
|
||||||
|
collapsible.value = !collapsible.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**对象信息状态类型 */
|
||||||
|
type TreeStateType = {
|
||||||
|
/**网元 loading */
|
||||||
|
loading: boolean;
|
||||||
|
/**网元配置 tree */
|
||||||
|
data: DataNode[];
|
||||||
|
/**选择对应Node一级 tree */
|
||||||
|
selectNode: {
|
||||||
|
title: string;
|
||||||
|
key: string;
|
||||||
|
// 可选属性数据
|
||||||
|
paramName: string;
|
||||||
|
paramDisplay: string;
|
||||||
|
paramType: string;
|
||||||
|
paramPerms: string[];
|
||||||
|
paramData: Record<string, any>[];
|
||||||
|
};
|
||||||
|
/**选择 loading */
|
||||||
|
selectLoading: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
let treeState: TreeStateType = reactive({
|
||||||
|
loading: true,
|
||||||
|
data: [],
|
||||||
|
selectNode: {
|
||||||
|
paramName: '',
|
||||||
|
paramDisplay: '',
|
||||||
|
paramType: '',
|
||||||
|
paramPerms: [],
|
||||||
|
paramData: [],
|
||||||
|
// 树形节点需要有
|
||||||
|
title: '',
|
||||||
|
key: '',
|
||||||
|
},
|
||||||
|
selectLoading: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**查询可选命令列表 */
|
||||||
|
function fnSelectConfigNode(_: any, info: any) {
|
||||||
|
const { key } = info.node;
|
||||||
|
if (treeState.selectNode.paramName == key) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fnActiveConfigNode(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**列表项点击监听 */
|
||||||
|
function fnActiveConfigNode(key: string | number) {
|
||||||
|
listState.data = [];
|
||||||
|
arrayState.data = [];
|
||||||
|
treeState.selectLoading = true;
|
||||||
|
if (key === '#') {
|
||||||
|
key = treeState.selectNode.paramName;
|
||||||
|
} else {
|
||||||
|
treeState.selectNode.paramName = key as string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const param = treeState.data.find(item => item.key === key);
|
||||||
|
if (!param) {
|
||||||
|
message.warning({
|
||||||
|
content: t('common.noData'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
treeState.selectNode = JSON.parse(JSON.stringify(param));
|
||||||
|
|
||||||
|
// 获取网元端的配置数据
|
||||||
|
getNeConfigData({
|
||||||
|
neType: neTypeSelect.value[0],
|
||||||
|
neId: neTypeSelect.value[1],
|
||||||
|
paramName: key,
|
||||||
|
}).then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||||
|
const ruleArr = param.paramData;
|
||||||
|
const dataArr = res.data;
|
||||||
|
if (param.paramType === 'list') {
|
||||||
|
// 列表项数据
|
||||||
|
const dataList = [];
|
||||||
|
for (const item of dataArr) {
|
||||||
|
for (const key in item) {
|
||||||
|
// 规则为准
|
||||||
|
for (const rule of ruleArr) {
|
||||||
|
if (rule['name'] === key) {
|
||||||
|
const ruleItem = Object.assign(rule, {
|
||||||
|
optional: 'true',
|
||||||
|
value: item[key],
|
||||||
|
});
|
||||||
|
dataList.push(ruleItem);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
listState.data = dataList;
|
||||||
|
tablePagination.current = 1;
|
||||||
|
listEditClose();
|
||||||
|
}
|
||||||
|
if (param.paramType === 'array') {
|
||||||
|
// 列表项数据
|
||||||
|
const dataArray = [];
|
||||||
|
for (const item of dataArr) {
|
||||||
|
const index = item['index'];
|
||||||
|
let record: Record<string, any>[] = [];
|
||||||
|
for (const key in item) {
|
||||||
|
// 规则为准
|
||||||
|
for (const rule of ruleArr) {
|
||||||
|
if (rule['name'] === key) {
|
||||||
|
const ruleItem = Object.assign({ optional: 'true' }, rule, {
|
||||||
|
value: item[key],
|
||||||
|
});
|
||||||
|
record.push(ruleItem);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dataArray.push({ title: `Index-${index}`, key: index, record });
|
||||||
|
}
|
||||||
|
arrayState.data = dataArray;
|
||||||
|
// 无数据时,用于新增
|
||||||
|
arrayState.dataRule = { title: `Index-0`, key: 0, record: ruleArr };
|
||||||
|
|
||||||
|
// 列表数据
|
||||||
|
const columnsData: Record<string, any>[] = [];
|
||||||
|
for (const v of arrayState.data) {
|
||||||
|
const row: Record<string, any> = {};
|
||||||
|
for (const item of v.record) {
|
||||||
|
row[item.name] = item;
|
||||||
|
}
|
||||||
|
columnsData.push(row);
|
||||||
|
}
|
||||||
|
arrayState.columnsData = columnsData;
|
||||||
|
// 列表字段
|
||||||
|
const columns: Record<string, any>[] = [];
|
||||||
|
for (const rule of arrayState.dataRule.record) {
|
||||||
|
columns.push({
|
||||||
|
title: rule.display,
|
||||||
|
dataIndex: rule.name,
|
||||||
|
align: 'left',
|
||||||
|
resizable: true,
|
||||||
|
width: 150,
|
||||||
|
minWidth: 100,
|
||||||
|
maxWidth: 350,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
columns.push({
|
||||||
|
title: t('common.operate'),
|
||||||
|
dataIndex: 'index',
|
||||||
|
key: 'index',
|
||||||
|
align: 'center',
|
||||||
|
fixed: 'right',
|
||||||
|
width: 100,
|
||||||
|
});
|
||||||
|
arrayState.columns = columns;
|
||||||
|
tablePagination.current = 1;
|
||||||
|
arrayEditClose();
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
treeState.selectLoading = false;
|
||||||
|
}, 300);
|
||||||
|
} else {
|
||||||
|
message.warning({
|
||||||
|
content: `${param.paramDisplay} ${t(
|
||||||
|
'views.configManage.configParamForm.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 = {
|
||||||
|
/**添加框是否显示 */
|
||||||
|
visible: boolean;
|
||||||
|
/**标题 */
|
||||||
|
title: string;
|
||||||
|
/**表单数据 */
|
||||||
|
from: Record<string, any>;
|
||||||
|
/**确定按钮 loading */
|
||||||
|
confirmLoading: boolean;
|
||||||
|
/**项类型 */
|
||||||
|
type: 'arrayAdd' | 'arrayEdit' | 'arrayChildAdd' | 'arrayChildEdit';
|
||||||
|
/**项Key */
|
||||||
|
key: string | number;
|
||||||
|
/**项数据 */
|
||||||
|
data: Record<string, any>[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**对话框对象信息状态 */
|
||||||
|
let modalState: ModalStateType = reactive({
|
||||||
|
visible: false,
|
||||||
|
title: 'Item',
|
||||||
|
from: {},
|
||||||
|
confirmLoading: false,
|
||||||
|
type: 'arrayAdd',
|
||||||
|
key: '',
|
||||||
|
data: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对话框弹出确认执行函数
|
||||||
|
* 进行表达规则校验
|
||||||
|
*/
|
||||||
|
function fnModalOk() {
|
||||||
|
const from = toRaw(modalState.from);
|
||||||
|
if (modalState.type === 'arrayAdd') {
|
||||||
|
arrayAddOk(from);
|
||||||
|
}
|
||||||
|
if (modalState.type === 'arrayEdit') {
|
||||||
|
arrayEditOk(from);
|
||||||
|
}
|
||||||
|
if (modalState.type === 'arrayChildAdd') {
|
||||||
|
arrayChildAddOk(from);
|
||||||
|
}
|
||||||
|
if (modalState.type === 'arrayChildEdit') {
|
||||||
|
arrayChildEditOk(from);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对话框弹出关闭执行函数
|
||||||
|
* 进行表达规则校验
|
||||||
|
*/
|
||||||
|
function fnModalCancel() {
|
||||||
|
modalState.visible = false;
|
||||||
|
modalState.from = {};
|
||||||
|
modalState.type = 'arrayAdd';
|
||||||
|
modalState.key = '';
|
||||||
|
modalState.data = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听新增编辑弹窗
|
||||||
|
watch(
|
||||||
|
() => modalState.visible,
|
||||||
|
val => {
|
||||||
|
// SMF需要选择配置的UPF id
|
||||||
|
if (val && neTypeSelect.value[0] === 'SMF') {
|
||||||
|
smfByUPFIdLoadData(neTypeSelect.value[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const { tablePagination, listState, listEdit, listEditClose, listEditOk } =
|
||||||
|
useConfigList({ t, treeState, neTypeSelect, ruleVerification });
|
||||||
|
|
||||||
|
const {
|
||||||
|
arrayState,
|
||||||
|
arrayEdit,
|
||||||
|
arrayEditClose,
|
||||||
|
arrayEditOk,
|
||||||
|
arrayDelete,
|
||||||
|
arrayAdd,
|
||||||
|
arrayAddOk,
|
||||||
|
arrayInitEdit,
|
||||||
|
arrayInitAdd,
|
||||||
|
} = useConfigArray({
|
||||||
|
t,
|
||||||
|
treeState,
|
||||||
|
neTypeSelect,
|
||||||
|
fnActiveConfigNode,
|
||||||
|
ruleVerification,
|
||||||
|
modalState,
|
||||||
|
fnModalCancel,
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
arrayChildState,
|
||||||
|
arrayChildExpand,
|
||||||
|
arrayChildEdit,
|
||||||
|
arrayChildEditOk,
|
||||||
|
arrayChildDelete,
|
||||||
|
arrayChildAdd,
|
||||||
|
arrayChildAddOk,
|
||||||
|
} = useConfigArrayChild({
|
||||||
|
t,
|
||||||
|
treeState,
|
||||||
|
neTypeSelect,
|
||||||
|
fnActiveConfigNode,
|
||||||
|
ruleVerification,
|
||||||
|
modalState,
|
||||||
|
arrayState,
|
||||||
|
arrayInitEdit,
|
||||||
|
arrayInitAdd,
|
||||||
|
arrayEditClose,
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 获取网元网元列表
|
||||||
|
neInfoStore.fnNelist().then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||||
|
if (res.data.length > 0) {
|
||||||
|
// 过滤不可用的网元
|
||||||
|
neCascaderOptions.value = neInfoStore.getNeSelectOtions.filter(
|
||||||
|
(item: any) => {
|
||||||
|
return !['LMF', 'NEF'].includes(item.value);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (neCascaderOptions.value.length === 0) {
|
||||||
|
message.warning({
|
||||||
|
content: t('common.noData'),
|
||||||
|
duration: 2,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 默认选择AMF
|
||||||
|
const item = neCascaderOptions.value.find(s => s.value === 'AMF');
|
||||||
|
if (item && item.children) {
|
||||||
|
const info = item.children[0];
|
||||||
|
neTypeSelect.value = [info.neType, info.neId];
|
||||||
|
} else {
|
||||||
|
const info = neCascaderOptions.value[0].children[0];
|
||||||
|
neTypeSelect.value = [info.neType, info.neId];
|
||||||
|
}
|
||||||
|
fnGetNeConfig();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.warning({
|
||||||
|
content: t('common.noData'),
|
||||||
|
duration: 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PageContainer>
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col
|
||||||
|
:lg="6"
|
||||||
|
:md="6"
|
||||||
|
:xs="24"
|
||||||
|
style="margin-bottom: 24px"
|
||||||
|
v-show="collapsible"
|
||||||
|
>
|
||||||
|
<!-- 网元类型 -->
|
||||||
|
<a-card size="small" :bordered="false" :loading="treeState.loading">
|
||||||
|
<template #title>
|
||||||
|
{{ t('views.configManage.configParamForm.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>
|
||||||
|
<a-form-item name="listeningPort">
|
||||||
|
<a-tree
|
||||||
|
:tree-data="treeState.data"
|
||||||
|
:selected-keys="[treeState.selectNode.paramName]"
|
||||||
|
@select="fnSelectConfigNode"
|
||||||
|
>
|
||||||
|
</a-tree>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="collapsible ? 18 : 24" :md="collapsible ? 18 : 24" :xs="24">
|
||||||
|
<a-card
|
||||||
|
size="small"
|
||||||
|
:bordered="false"
|
||||||
|
:body-style="{ maxHeight: '650px', 'overflow-y': 'auto' }"
|
||||||
|
:loading="treeState.selectLoading"
|
||||||
|
>
|
||||||
|
<template #title>
|
||||||
|
<a-button
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
@click.prevent="changeCollapsible()"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<MenuFoldOutlined v-show="collapsible" />
|
||||||
|
<MenuUnfoldOutlined v-show="!collapsible" />
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
|
||||||
|
<a-typography-text strong v-if="treeState.selectNode.paramDisplay">
|
||||||
|
{{ treeState.selectNode.paramDisplay }}
|
||||||
|
</a-typography-text>
|
||||||
|
<a-typography-text type="danger" v-else>
|
||||||
|
{{ t('views.configManage.configParamForm.treeSelectTip') }}
|
||||||
|
</a-typography-text>
|
||||||
|
</template>
|
||||||
|
<template #extra>
|
||||||
|
<a-space :size="8" align="center" v-show="!treeState.selectLoading">
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>{{ t('common.reloadText') }}</template>
|
||||||
|
<a-button
|
||||||
|
type="default"
|
||||||
|
size="small"
|
||||||
|
@click.prevent="fnActiveConfigNode('#')"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<ReloadOutlined />
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 单列表格列表 -->
|
||||||
|
<a-table
|
||||||
|
v-if="treeState.selectNode.paramType === 'list'"
|
||||||
|
class="table"
|
||||||
|
row-key="name"
|
||||||
|
:size="listState.size"
|
||||||
|
:columns="listState.columns"
|
||||||
|
:data-source="listState.data"
|
||||||
|
:pagination="tablePagination"
|
||||||
|
:bordered="true"
|
||||||
|
:scroll="{ x: true, y: '500px' }"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, text, record }">
|
||||||
|
<template v-if="column.dataIndex === 'value'">
|
||||||
|
<a-tooltip placement="topLeft">
|
||||||
|
<template #title v-if="record.comment">
|
||||||
|
{{ record.comment }}
|
||||||
|
</template>
|
||||||
|
<div class="editable-cell">
|
||||||
|
<div
|
||||||
|
v-if="
|
||||||
|
listState.editRecord['display'] === record['display']
|
||||||
|
"
|
||||||
|
class="editable-cell__input-wrapper"
|
||||||
|
>
|
||||||
|
<a-input-number
|
||||||
|
v-if="record['type'] === 'int'"
|
||||||
|
v-model:value="listState.editRecord['value']"
|
||||||
|
:disabled="listState.confirmLoading"
|
||||||
|
style="width: 100%"
|
||||||
|
></a-input-number>
|
||||||
|
<a-switch
|
||||||
|
v-else-if="record['type'] === 'bool'"
|
||||||
|
v-model:checked="listState.editRecord['value']"
|
||||||
|
:checked-children="t('common.switch.open')"
|
||||||
|
:un-checked-children="t('common.switch.shut')"
|
||||||
|
:disabled="listState.confirmLoading"
|
||||||
|
></a-switch>
|
||||||
|
<a-select
|
||||||
|
v-else-if="record['type'] === 'enum'"
|
||||||
|
v-model:value="listState.editRecord['value']"
|
||||||
|
:allow-clear="true"
|
||||||
|
:disabled="listState.confirmLoading"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
:value="+v"
|
||||||
|
:key="+v"
|
||||||
|
v-for="(k, v) in JSON.parse(record['filter'])"
|
||||||
|
>
|
||||||
|
{{ k }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
<a-input
|
||||||
|
v-else
|
||||||
|
v-model:value="listState.editRecord['value']"
|
||||||
|
:disabled="listState.confirmLoading"
|
||||||
|
></a-input>
|
||||||
|
<a-space
|
||||||
|
:size="8"
|
||||||
|
align="center"
|
||||||
|
direction="horizontal"
|
||||||
|
style="margin-left: 18px"
|
||||||
|
>
|
||||||
|
<a-tooltip placement="bottomRight">
|
||||||
|
<template #title> {{ t('common.ok') }} </template>
|
||||||
|
<a-popconfirm
|
||||||
|
:title="
|
||||||
|
t(
|
||||||
|
'views.configManage.configParamForm.editOkTip',
|
||||||
|
{ num: record['display'] }
|
||||||
|
)
|
||||||
|
"
|
||||||
|
placement="topRight"
|
||||||
|
:disabled="listState.confirmLoading"
|
||||||
|
@confirm="listEditOk()"
|
||||||
|
>
|
||||||
|
<a-button
|
||||||
|
type="text"
|
||||||
|
class="editable-cell__icon-edit"
|
||||||
|
:disabled="listState.confirmLoading"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<CheckOutlined />
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-popconfirm>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip placement="bottomRight">
|
||||||
|
<template #title> {{ t('common.cancel') }} </template>
|
||||||
|
<a-button
|
||||||
|
type="text"
|
||||||
|
class="editable-cell__icon-edit"
|
||||||
|
:disabled="listState.confirmLoading"
|
||||||
|
@click.prevent="listEditClose()"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<CloseOutlined />
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-space>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="editable-cell__text-wrapper"
|
||||||
|
@dblclick="listEdit(record)"
|
||||||
|
>
|
||||||
|
<template v-if="record['type'] === 'enum'">
|
||||||
|
{{ JSON.parse(record['filter'])[text] || ' ' }}
|
||||||
|
</template>
|
||||||
|
<template v-else>{{ `${text}` || ' ' }}</template>
|
||||||
|
<EditOutlined
|
||||||
|
class="editable-cell__icon"
|
||||||
|
@click="listEdit(record)"
|
||||||
|
style="margin-left: 18px"
|
||||||
|
v-if="
|
||||||
|
!listState.confirmLoading &&
|
||||||
|
!['read-only', 'read', 'ro'].includes(record.access)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
|
||||||
|
<!-- array类型 -->
|
||||||
|
<template v-if="treeState.selectNode.paramType === 'array'">
|
||||||
|
<a-table
|
||||||
|
class="table"
|
||||||
|
row-key="index"
|
||||||
|
:columns="treeState.selectNode.paramPerms.includes('get') ? arrayState.columnsDnd.filter((s:any)=>s.key !== 'index') : arrayState.columnsDnd"
|
||||||
|
:data-source="arrayState.columnsData"
|
||||||
|
:size="arrayState.size"
|
||||||
|
:pagination="tablePagination"
|
||||||
|
:bordered="true"
|
||||||
|
:scroll="{ x: arrayState.columnsDnd.length * 200, y: 480 }"
|
||||||
|
@resizeColumn="(w:number, col:any) => (col.width = w)"
|
||||||
|
:show-expand-column="false"
|
||||||
|
v-model:expanded-row-keys="arrayState.arrayChildExpandKeys"
|
||||||
|
>
|
||||||
|
<!-- 多列新增操作 -->
|
||||||
|
<template #title>
|
||||||
|
<a-space :size="16" align="center">
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
@click.prevent="arrayAdd()"
|
||||||
|
size="small"
|
||||||
|
v-if="treeState.selectNode.paramPerms.includes('post')"
|
||||||
|
>
|
||||||
|
<template #icon> <PlusOutlined /> </template>
|
||||||
|
{{ t('common.addText') }}
|
||||||
|
</a-button>
|
||||||
|
<TableColumnsDnd
|
||||||
|
type="ghost"
|
||||||
|
:cache-id="treeState.selectNode.key"
|
||||||
|
:columns="treeState.selectNode.paramPerms.includes('get') ? [...arrayState.columns.filter((s:any)=>s.key !== 'index')] : arrayState.columns"
|
||||||
|
v-model:columns-dnd="arrayState.columnsDnd"
|
||||||
|
></TableColumnsDnd>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 多列数据渲染 -->
|
||||||
|
<template #bodyCell="{ column, text, record }">
|
||||||
|
<template v-if="column?.key === 'index'">
|
||||||
|
<a-space :size="16" align="center">
|
||||||
|
<a-tooltip
|
||||||
|
v-if="treeState.selectNode.paramPerms.includes('put')"
|
||||||
|
>
|
||||||
|
<template #title>{{ t('common.editText') }}</template>
|
||||||
|
<a-button type="link" @click.prevent="arrayEdit(text)">
|
||||||
|
<template #icon><FormOutlined /></template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip
|
||||||
|
v-if="
|
||||||
|
treeState.selectNode.paramPerms.includes('delete') &&
|
||||||
|
!(
|
||||||
|
neTypeSelect[0] === 'IMS' &&
|
||||||
|
treeState.selectNode.paramName === 'plmn' &&
|
||||||
|
text['value'] === 0
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<template #title>{{ t('common.deleteText') }}</template>
|
||||||
|
<a-button type="link" @click.prevent="arrayDelete(text)">
|
||||||
|
<template #icon><DeleteOutlined /></template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="text">
|
||||||
|
<a-tooltip placement="topLeft">
|
||||||
|
<template #title v-if="text.comment">
|
||||||
|
{{ text.comment }}
|
||||||
|
</template>
|
||||||
|
<div class="editable-cell">
|
||||||
|
<template v-if="text.array">
|
||||||
|
<a-button
|
||||||
|
type="default"
|
||||||
|
size="small"
|
||||||
|
@click.prevent="
|
||||||
|
arrayChildExpand(record['index'], text)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<template #icon><BarsOutlined /></template>
|
||||||
|
{{
|
||||||
|
t('views.configManage.configParamForm.arrayMore')
|
||||||
|
}}
|
||||||
|
</a-button>
|
||||||
|
<!--特殊字段拓展显示-->
|
||||||
|
<span
|
||||||
|
v-if="
|
||||||
|
text.name === 'dnnList' && Array.isArray(text.value)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
({{
|
||||||
|
text.value.length > 4
|
||||||
|
? `${text.value
|
||||||
|
.slice(0, 3)
|
||||||
|
.map((s: any) => s.dnn)
|
||||||
|
.join()}...${text.value.length}`
|
||||||
|
: text.value.map((s: any) => s.dnn).join()
|
||||||
|
}})
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div v-else class="editable-cell__text-wrapper">
|
||||||
|
<template v-if="text['type'] === 'enum'">
|
||||||
|
{{ JSON.parse(text['filter'])[text.value] }}
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
{{ `${text.value}` || ' ' }}
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 多列嵌套类型 -->
|
||||||
|
<template #expandedRowRender>
|
||||||
|
<a-table
|
||||||
|
class="table"
|
||||||
|
row-key="index"
|
||||||
|
:columns="arrayChildState.columnsDnd"
|
||||||
|
:data-source="arrayChildState.columnsData"
|
||||||
|
:size="arrayChildState.size"
|
||||||
|
:pagination="tablePagination"
|
||||||
|
:bordered="true"
|
||||||
|
:scroll="{
|
||||||
|
x: arrayChildState.columnsDnd.length * 200,
|
||||||
|
y: 200,
|
||||||
|
}"
|
||||||
|
@resizeColumn="(w:number, col:any) => (col.width = w)"
|
||||||
|
>
|
||||||
|
<template #title>
|
||||||
|
<a-space :size="16" align="center">
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
@click.prevent="arrayChildAdd"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<template #icon> <PlusOutlined /> </template>
|
||||||
|
{{ t('common.addText') }} {{ arrayChildState.title }}
|
||||||
|
</a-button>
|
||||||
|
<TableColumnsDnd
|
||||||
|
type="ghost"
|
||||||
|
:cache-id="`${treeState.selectNode.key}:${arrayChildState.loc}`"
|
||||||
|
:columns="[...arrayChildState.columns]"
|
||||||
|
v-model:columns-dnd="arrayChildState.columnsDnd"
|
||||||
|
v-if="arrayChildState.loc"
|
||||||
|
></TableColumnsDnd>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
<template #bodyCell="{ column, text, record }">
|
||||||
|
<template v-if="column?.key === 'index'">
|
||||||
|
<a-space :size="8" align="center">
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>{{ t('common.editText') }}</template>
|
||||||
|
<a-button
|
||||||
|
type="link"
|
||||||
|
@click.prevent="arrayChildEdit(text)"
|
||||||
|
>
|
||||||
|
<template #icon><FormOutlined /></template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>
|
||||||
|
{{ t('common.deleteText') }}
|
||||||
|
</template>
|
||||||
|
<a-button
|
||||||
|
type="link"
|
||||||
|
@click.prevent="arrayChildDelete(text)"
|
||||||
|
>
|
||||||
|
<template #icon><DeleteOutlined /></template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="text">
|
||||||
|
<a-tooltip placement="topLeft">
|
||||||
|
<template #title v-if="text.comment">
|
||||||
|
{{ text.comment }}
|
||||||
|
</template>
|
||||||
|
<div class="editable-cell">
|
||||||
|
<template v-if="text.array">
|
||||||
|
<a-button type="default" size="small">
|
||||||
|
<template #icon><BarsOutlined /></template>
|
||||||
|
{{
|
||||||
|
t(
|
||||||
|
'views.configManage.configParamForm.arrayMore'
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
|
<template v-if="text['type'] === 'enum'">
|
||||||
|
{{ JSON.parse(text['filter'])[text.value] }}
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
{{ `${text.value}` || ' ' }}
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</template>
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<!-- 新增框或修改框 -->
|
||||||
|
<ProModal
|
||||||
|
:drag="true"
|
||||||
|
:width="800"
|
||||||
|
:destroyOnClose="true"
|
||||||
|
:body-style="{ maxHeight: '650px', 'overflow-y': 'auto' }"
|
||||||
|
:keyboard="false"
|
||||||
|
:mask-closable="false"
|
||||||
|
:visible="modalState.visible"
|
||||||
|
:title="modalState.title"
|
||||||
|
:confirm-loading="modalState.confirmLoading"
|
||||||
|
@ok="fnModalOk"
|
||||||
|
@cancel="fnModalCancel"
|
||||||
|
>
|
||||||
|
<a-form
|
||||||
|
class="form"
|
||||||
|
layout="horizontal"
|
||||||
|
autocomplete="off"
|
||||||
|
:validate-on-rule-change="false"
|
||||||
|
:validateTrigger="[]"
|
||||||
|
:label-col="{ span: 6 }"
|
||||||
|
:labelWrap="true"
|
||||||
|
>
|
||||||
|
<a-form-item
|
||||||
|
v-for="item in modalState.data"
|
||||||
|
:label="item.display"
|
||||||
|
:name="item.name"
|
||||||
|
:required="item.optional === 'false'"
|
||||||
|
style="margin-bottom: 4px"
|
||||||
|
>
|
||||||
|
<a-tooltip placement="topLeft">
|
||||||
|
<template #title v-if="item.comment">
|
||||||
|
{{ item.comment }}
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
v-if="
|
||||||
|
!Array.isArray(item.array) &&
|
||||||
|
modalState.from[item.name] !== undefined
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<!-- 特殊SMF-upfid选择 -->
|
||||||
|
<a-select
|
||||||
|
v-if="
|
||||||
|
neTypeSelect[0] === 'SMF' &&
|
||||||
|
modalState.from[item.name]['name'] === 'upfId'
|
||||||
|
"
|
||||||
|
v-model:value="modalState.from[item.name]['value']"
|
||||||
|
:options="smfByUPFIdOptions"
|
||||||
|
:disabled="['read-only', 'read', 'ro'].includes(item.access)"
|
||||||
|
:token-separators="[',', ';']"
|
||||||
|
mode="multiple"
|
||||||
|
:max-tag-count="5"
|
||||||
|
:allow-clear="true"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
</a-select>
|
||||||
|
<!-- 常规 -->
|
||||||
|
<a-input-number
|
||||||
|
v-else-if="item['type'] === 'int'"
|
||||||
|
v-model:value="modalState.from[item.name]['value']"
|
||||||
|
:disabled="['read-only', 'read', 'ro'].includes(item.access)"
|
||||||
|
style="width: 100%"
|
||||||
|
></a-input-number>
|
||||||
|
<a-switch
|
||||||
|
v-else-if="item['type'] === 'bool'"
|
||||||
|
v-model:checked="modalState.from[item.name]['value']"
|
||||||
|
:checked-children="t('common.switch.open')"
|
||||||
|
:un-checked-children="t('common.switch.shut')"
|
||||||
|
:disabled="['read-only', 'read', 'ro'].includes(item.access)"
|
||||||
|
></a-switch>
|
||||||
|
<a-select
|
||||||
|
v-else-if="item['type'] === 'enum'"
|
||||||
|
v-model:value="modalState.from[item.name]['value']"
|
||||||
|
:disabled="['read-only', 'read', 'ro'].includes(item.access)"
|
||||||
|
:allow-clear="true"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
:value="+v"
|
||||||
|
:key="+v"
|
||||||
|
v-for="(k, v) in JSON.parse(item['filter'])"
|
||||||
|
>
|
||||||
|
{{ k }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
<a-input
|
||||||
|
v-else
|
||||||
|
v-model:value="modalState.from[item.name]['value']"
|
||||||
|
:disabled="['read-only', 'read', 'ro'].includes(item.access)"
|
||||||
|
></a-input>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
{{ `${item.value || ' '}` }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</ProModal>
|
||||||
|
</PageContainer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.editable-cell {
|
||||||
|
&__icon {
|
||||||
|
display: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
&__icon:hover {
|
||||||
|
color: var(--ant-primary-color);
|
||||||
|
}
|
||||||
|
&__icon-edit:hover {
|
||||||
|
color: var(--ant-primary-color);
|
||||||
|
}
|
||||||
|
&__text-wrapper {
|
||||||
|
font-size: 16px;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
&__text-wrapper:hover &__icon {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
&__input-wrapper {
|
||||||
|
display: flex;
|
||||||
|
justify-content: start;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
605
src/views/ne/neConfigBackup/index.vue
Normal file
605
src/views/ne/neConfigBackup/index.vue
Normal file
@@ -0,0 +1,605 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, ref, onMounted, toRaw } from 'vue';
|
||||||
|
import { PageContainer } from 'antdv-pro-layout';
|
||||||
|
import { Form, Modal, TableColumnsType, message } from 'ant-design-vue/lib';
|
||||||
|
import { SizeType } from 'ant-design-vue/lib/config-provider';
|
||||||
|
import { MenuInfo } from 'ant-design-vue/lib/menu/src/interface';
|
||||||
|
import useNeInfoStore from '@/store/modules/neinfo';
|
||||||
|
import useI18n from '@/hooks/useI18n';
|
||||||
|
import useDictStore from '@/store/modules/dict';
|
||||||
|
import { NE_TYPE_LIST } from '@/constants/ne-constants';
|
||||||
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
|
import { parseDateToStr } from '@/utils/date-utils';
|
||||||
|
import {
|
||||||
|
delNeConfigBackup,
|
||||||
|
downNeConfigBackup,
|
||||||
|
listNeConfigBackup,
|
||||||
|
updateNeConfigBackup,
|
||||||
|
} from '@/api/ne/neConfigBackup';
|
||||||
|
import saveAs from 'file-saver';
|
||||||
|
const { t } = useI18n();
|
||||||
|
const { getDict } = useDictStore();
|
||||||
|
|
||||||
|
/**字典数据-状态 */
|
||||||
|
let dictStatus = ref<DictType[]>([]);
|
||||||
|
|
||||||
|
/**网元参数 */
|
||||||
|
let neOtions = ref<Record<string, any>[]>([]);
|
||||||
|
|
||||||
|
/**查询参数 */
|
||||||
|
let queryParams = reactive({
|
||||||
|
/**网元类型 */
|
||||||
|
neType: undefined,
|
||||||
|
/**名称 */
|
||||||
|
name: '',
|
||||||
|
/**当前页数 */
|
||||||
|
pageNum: 1,
|
||||||
|
/**每页条数 */
|
||||||
|
pageSize: 20,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**查询参数重置 */
|
||||||
|
function fnQueryReset() {
|
||||||
|
queryParams = Object.assign(queryParams, {
|
||||||
|
neType: undefined,
|
||||||
|
name: '',
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
});
|
||||||
|
tablePagination.current = 1;
|
||||||
|
tablePagination.pageSize = 20;
|
||||||
|
fnGetList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**表格状态类型 */
|
||||||
|
type TabeStateType = {
|
||||||
|
/**加载等待 */
|
||||||
|
loading: boolean;
|
||||||
|
/**紧凑型 */
|
||||||
|
size: SizeType;
|
||||||
|
/**搜索栏 */
|
||||||
|
seached: boolean;
|
||||||
|
/**记录数据 */
|
||||||
|
data: any[];
|
||||||
|
/**勾选记录 */
|
||||||
|
selectedRowKeys: (string | number)[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**表格状态 */
|
||||||
|
let tableState: TabeStateType = reactive({
|
||||||
|
loading: false,
|
||||||
|
size: 'middle',
|
||||||
|
seached: false,
|
||||||
|
data: [],
|
||||||
|
selectedRowKeys: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
/**表格字段列 */
|
||||||
|
let tableColumns = ref<TableColumnsType>([
|
||||||
|
{
|
||||||
|
title: t('common.rowId'),
|
||||||
|
dataIndex: 'id',
|
||||||
|
align: 'left',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('views.ne.common.neType'),
|
||||||
|
dataIndex: 'neType',
|
||||||
|
align: 'left',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('views.ne.common.neId'),
|
||||||
|
dataIndex: 'neId',
|
||||||
|
align: 'left',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('common.createTime'),
|
||||||
|
dataIndex: 'createTime',
|
||||||
|
align: 'center',
|
||||||
|
customRender(opt) {
|
||||||
|
if (!opt.value) return '';
|
||||||
|
return parseDateToStr(opt.value);
|
||||||
|
},
|
||||||
|
width: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('views.ne.neConfigBackup.name'),
|
||||||
|
dataIndex: 'name',
|
||||||
|
align: 'left',
|
||||||
|
width: 200,
|
||||||
|
resizable: true,
|
||||||
|
minWidth: 100,
|
||||||
|
maxWidth: 300,
|
||||||
|
ellipsis: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('common.remark'),
|
||||||
|
dataIndex: 'remark',
|
||||||
|
key: 'remark',
|
||||||
|
align: 'left',
|
||||||
|
width: 150,
|
||||||
|
resizable: true,
|
||||||
|
minWidth: 100,
|
||||||
|
maxWidth: 300,
|
||||||
|
ellipsis: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**查询列表, pageNum初始页数 */
|
||||||
|
function fnGetList(pageNum?: number) {
|
||||||
|
if (tableState.loading) return;
|
||||||
|
tableState.loading = true;
|
||||||
|
if (pageNum) {
|
||||||
|
queryParams.pageNum = pageNum;
|
||||||
|
}
|
||||||
|
listNeConfigBackup(toRaw(queryParams)).then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
|
||||||
|
tablePagination.total = res.total;
|
||||||
|
tableState.data = res.rows;
|
||||||
|
if (
|
||||||
|
tablePagination.total <=
|
||||||
|
(queryParams.pageNum - 1) * tablePagination.pageSize &&
|
||||||
|
queryParams.pageNum !== 1
|
||||||
|
) {
|
||||||
|
tableState.loading = false;
|
||||||
|
fnGetList(queryParams.pageNum - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tableState.loading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**信息文件下载 */
|
||||||
|
function fnDownloadFile(row: Record<string, any>) {
|
||||||
|
Modal.confirm({
|
||||||
|
title: t('common.tipTitle'),
|
||||||
|
content: t('views.ne.neConfigBackup.downTip', { txt: row.name }),
|
||||||
|
onOk() {
|
||||||
|
const hide = message.loading(t('common.loading'), 0);
|
||||||
|
downNeConfigBackup(row.id)
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
|
message.success({
|
||||||
|
content: t('common.operateOk'),
|
||||||
|
duration: 2,
|
||||||
|
});
|
||||||
|
saveAs(res.data, `${row.name}`);
|
||||||
|
} else {
|
||||||
|
message.error({
|
||||||
|
content: `${res.msg}`,
|
||||||
|
duration: 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hide();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录删除
|
||||||
|
* @param id 编号
|
||||||
|
*/
|
||||||
|
function fnRecordDelete(id: string) {
|
||||||
|
if (!id || modalState.confirmLoading) return;
|
||||||
|
let msg = id;
|
||||||
|
if (id === '0') {
|
||||||
|
msg = `...${tableState.selectedRowKeys.length}`;
|
||||||
|
id = tableState.selectedRowKeys.join(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
Modal.confirm({
|
||||||
|
title: t('common.tipTitle'),
|
||||||
|
content: t('views.dashboard.ue.delTip', { msg }),
|
||||||
|
onOk() {
|
||||||
|
modalState.confirmLoading = true;
|
||||||
|
const hide = message.loading(t('common.loading'), 0);
|
||||||
|
delNeConfigBackup(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;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**对话框对象信息状态类型 */
|
||||||
|
type ModalStateType = {
|
||||||
|
/**新增框或修改框是否显示 */
|
||||||
|
visibleByEdit: boolean;
|
||||||
|
/**标题 */
|
||||||
|
title: string;
|
||||||
|
/**表单数据 */
|
||||||
|
from: Record<string, any>;
|
||||||
|
/**确定按钮 loading */
|
||||||
|
confirmLoading: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**对话框对象信息状态 */
|
||||||
|
let modalState: ModalStateType = reactive({
|
||||||
|
visibleByEdit: false,
|
||||||
|
title: '备份记录',
|
||||||
|
from: {
|
||||||
|
id: undefined,
|
||||||
|
name: '',
|
||||||
|
remark: '',
|
||||||
|
},
|
||||||
|
confirmLoading: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对话框弹出显示为 新增或者修改
|
||||||
|
* @param noticeId 网元id, 不传为新增
|
||||||
|
*/
|
||||||
|
function fnModalVisibleByEdit(row: Record<string, any>) {
|
||||||
|
if (modalState.confirmLoading) return;
|
||||||
|
modalState.from.id = row.id;
|
||||||
|
modalState.from.name = row.name;
|
||||||
|
modalState.from.remark = row.remark;
|
||||||
|
modalState.title = t('views.ne.neConfigBackup.title', { txt: row.id });
|
||||||
|
modalState.visibleByEdit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**对话框内表单属性和校验规则 */
|
||||||
|
const modalStateFrom = Form.useForm(
|
||||||
|
modalState.from,
|
||||||
|
reactive({
|
||||||
|
name: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入名称',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对话框弹出确认执行函数
|
||||||
|
* 进行表达规则校验
|
||||||
|
*/
|
||||||
|
function fnModalOk() {
|
||||||
|
modalStateFrom
|
||||||
|
.validate()
|
||||||
|
.then(e => {
|
||||||
|
modalState.confirmLoading = true;
|
||||||
|
const from = toRaw(modalState.from);
|
||||||
|
const hide = message.loading(t('common.loading'), 0);
|
||||||
|
updateNeConfigBackup(from)
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
|
message.success({
|
||||||
|
content: t('common.msgSuccess', { msg: modalState.title }),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
modalState.visibleByEdit = false;
|
||||||
|
modalStateFrom.resetFields();
|
||||||
|
fnGetList();
|
||||||
|
} else {
|
||||||
|
message.error({
|
||||||
|
content: `${res.msg}`,
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
fnGetList();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hide();
|
||||||
|
modalState.confirmLoading = false;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
message.error(t('common.errorFields', { num: e.errorFields.length }), 3);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对话框弹出关闭执行函数
|
||||||
|
* 进行表达规则校验
|
||||||
|
*/
|
||||||
|
function fnModalCancel() {
|
||||||
|
modalState.visibleByEdit = false;
|
||||||
|
modalStateFrom.resetFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 初始字典数据
|
||||||
|
getDict('ne_license_status').then(res => {
|
||||||
|
dictStatus.value = res;
|
||||||
|
});
|
||||||
|
// 获取网元网元列表
|
||||||
|
useNeInfoStore()
|
||||||
|
.fnNelist()
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||||
|
neOtions.value = useNeInfoStore().getNeSelectOtions;
|
||||||
|
} else {
|
||||||
|
message.warning({
|
||||||
|
content: t('common.noData'),
|
||||||
|
duration: 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
// 获取列表数据
|
||||||
|
fnGetList();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PageContainer>
|
||||||
|
<a-card
|
||||||
|
v-show="tableState.seached"
|
||||||
|
:bordered="false"
|
||||||
|
:body-style="{ marginBottom: '24px', paddingBottom: 0 }"
|
||||||
|
>
|
||||||
|
<!-- 表格搜索栏 -->
|
||||||
|
<a-form :model="queryParams" name="queryParams" layout="horizontal">
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
|
<a-form-item :label="t('views.ne.common.neType')" name="neType ">
|
||||||
|
<a-auto-complete
|
||||||
|
v-model:value="queryParams.neType"
|
||||||
|
:options="NE_TYPE_LIST.map(v => ({ value: v }))"
|
||||||
|
:allow-clear="true"
|
||||||
|
:placeholder="t('common.inputPlease')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
|
<a-form-item :label="t('views.ne.neConfigBackup.name')" name="name">
|
||||||
|
<a-input
|
||||||
|
v-model:value="queryParams.name"
|
||||||
|
:allow-clear="true"
|
||||||
|
:placeholder="t('common.inputPlease')"
|
||||||
|
></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
|
<a-form-item>
|
||||||
|
<a-space :size="8">
|
||||||
|
<a-button type="primary" @click.prevent="fnGetList(1)">
|
||||||
|
<template #icon><SearchOutlined /></template>
|
||||||
|
{{ t('common.search') }}
|
||||||
|
</a-button>
|
||||||
|
<a-button type="default" @click.prevent="fnQueryReset">
|
||||||
|
<template #icon><ClearOutlined /></template>
|
||||||
|
{{ t('common.reset') }}
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-form>
|
||||||
|
</a-card>
|
||||||
|
|
||||||
|
<a-card :bordered="false" :body-style="{ padding: '0px' }">
|
||||||
|
<!-- 插槽-卡片左侧侧 -->
|
||||||
|
<template #title>
|
||||||
|
<a-space :size="8" align="center">
|
||||||
|
<a-button
|
||||||
|
type="default"
|
||||||
|
danger
|
||||||
|
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||||
|
:loading="modalState.confirmLoading"
|
||||||
|
@click.prevent="fnRecordDelete('0')"
|
||||||
|
v-perms:has="['ne:neConfigBackup:remove']"
|
||||||
|
>
|
||||||
|
<template #icon><DeleteOutlined /></template>
|
||||||
|
{{ t('common.deleteText') }}
|
||||||
|
</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"
|
||||||
|
/>
|
||||||
|
</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 placement="topRight">
|
||||||
|
<template #title>{{ t('common.sizeText') }}</template>
|
||||||
|
<a-dropdown placement="bottomRight" trigger="click">
|
||||||
|
<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 * 180 }"
|
||||||
|
@resizeColumn="(w:number, col:any) => (col.width = w)"
|
||||||
|
: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.downloadText') }}</template>
|
||||||
|
<a-button type="link" @click.prevent="fnDownloadFile(record)">
|
||||||
|
<template #icon><DownloadOutlined /></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="['ne:neConfigBackup:remove']"
|
||||||
|
>
|
||||||
|
<template #icon><DeleteOutlined /></template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>{{ t('common.editText') }}</template>
|
||||||
|
<a-button
|
||||||
|
type="link"
|
||||||
|
@click.prevent="fnModalVisibleByEdit(record)"
|
||||||
|
v-perms:has="['ne:neConfigBackup:edit']"
|
||||||
|
>
|
||||||
|
<template #icon><FormOutlined /></template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</a-card>
|
||||||
|
|
||||||
|
<!-- 新增框或修改框 -->
|
||||||
|
<ProModal
|
||||||
|
:drag="true"
|
||||||
|
:width="512"
|
||||||
|
:destroyOnClose="true"
|
||||||
|
:keyboard="false"
|
||||||
|
:mask-closable="false"
|
||||||
|
:visible="modalState.visibleByEdit"
|
||||||
|
:title="modalState.title"
|
||||||
|
:confirm-loading="modalState.confirmLoading"
|
||||||
|
@ok="fnModalOk"
|
||||||
|
@cancel="fnModalCancel"
|
||||||
|
>
|
||||||
|
<a-form
|
||||||
|
name="modalStateFrom"
|
||||||
|
layout="horizontal"
|
||||||
|
:wrapper-col="{ span: 18 }"
|
||||||
|
:label-col="{ span: 6 }"
|
||||||
|
:labelWrap="true"
|
||||||
|
>
|
||||||
|
<a-form-item
|
||||||
|
:label="t('views.ne.neConfigBackup.name')"
|
||||||
|
name="name"
|
||||||
|
v-bind="modalStateFrom.validateInfos.name"
|
||||||
|
>
|
||||||
|
<a-input
|
||||||
|
v-model:value="modalState.from.name"
|
||||||
|
:allow-clear="true"
|
||||||
|
:placeholder="t('common.inputPlease')"
|
||||||
|
></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
:label="t('common.remark')"
|
||||||
|
name="remark"
|
||||||
|
v-bind="modalStateFrom.validateInfos.remark"
|
||||||
|
>
|
||||||
|
<a-textarea
|
||||||
|
v-model:value="modalState.from.remark"
|
||||||
|
:auto-size="{ minRows: 2, maxRows: 6 }"
|
||||||
|
:maxlength="400"
|
||||||
|
:show-count="true"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</ProModal>
|
||||||
|
</PageContainer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.table :deep(.ant-pagination) {
|
||||||
|
padding: 0 24px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive, toRaw, watch } from 'vue';
|
import { reactive, toRaw, watch } from 'vue';
|
||||||
import { Form, Modal, Upload, message } from 'ant-design-vue/lib';
|
import { Form, Modal, Upload, message, notification } from 'ant-design-vue/lib';
|
||||||
import useI18n from '@/hooks/useI18n';
|
import useI18n from '@/hooks/useI18n';
|
||||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
import { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
|
import { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
|
||||||
import { FileType } from 'ant-design-vue/lib/upload/interface';
|
import { FileType, UploadFile } from 'ant-design-vue/lib/upload/interface';
|
||||||
import {
|
import {
|
||||||
exportSet,
|
exportNeConfigBackup,
|
||||||
importFile,
|
importNeConfigBackup,
|
||||||
listServerFile,
|
listNeConfigBackup,
|
||||||
} from '@/api/configManage/neManage';
|
} from '@/api/ne/neConfigBackup';
|
||||||
|
import saveAs from 'file-saver';
|
||||||
|
import { uploadFile } from '@/api/tool/file';
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const emit = defineEmits(['ok', 'cancel', 'update:visible']);
|
const emit = defineEmits(['ok', 'cancel', 'update:visible']);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -28,32 +30,49 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/**表格所需option */
|
/**导入状态数据 */
|
||||||
const neManageOption = reactive({
|
const importState = reactive({
|
||||||
importType: [
|
typeOption: [
|
||||||
{ label: t('views.ne.neInfo.backConf.server'), value: 'server' },
|
{ label: t('views.ne.neInfo.backConf.server'), value: 'backup' },
|
||||||
{ label: t('views.ne.neInfo.backConf.local'), value: 'local' },
|
{ label: t('views.ne.neInfo.backConf.local'), value: 'upload' },
|
||||||
],
|
],
|
||||||
serverFileName: <any[]>[],
|
backupData: <any[]>[],
|
||||||
});
|
});
|
||||||
|
|
||||||
/**查询网元远程服务器备份文件 */
|
/**查询网元远程服务器备份文件 */
|
||||||
function typeChange(value: any) {
|
function backupSearch(name?: string) {
|
||||||
if (value === 'server') {
|
const { neType, neId } = modalState.from;
|
||||||
modalState.from.fileName = undefined;
|
listNeConfigBackup({
|
||||||
listServerFile(modalState.from).then(res => {
|
neType,
|
||||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
neId,
|
||||||
neManageOption.serverFileName = [];
|
name,
|
||||||
res.data.forEach((item: any) => {
|
pageNum: 1,
|
||||||
neManageOption.serverFileName.push({
|
pageSize: 20,
|
||||||
label: item.fileName,
|
}).then(res => {
|
||||||
value: item.fileName,
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
|
||||||
|
importState.backupData = [];
|
||||||
|
res.rows.forEach((item: any) => {
|
||||||
|
importState.backupData.push({
|
||||||
|
label: item.name,
|
||||||
|
value: item.path,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
}
|
||||||
modalState.from.file = null;
|
|
||||||
|
/**服务器备份文件选择切换 */
|
||||||
|
function backupChange(value: any) {
|
||||||
|
if (!value) {
|
||||||
|
backupSearch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**类型切换 */
|
||||||
|
function typeChange(value: any) {
|
||||||
|
modalState.from.path = undefined;
|
||||||
|
if (value === 'backup') {
|
||||||
|
backupSearch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,9 +86,8 @@ type ModalStateType = {
|
|||||||
from: {
|
from: {
|
||||||
neType: string;
|
neType: string;
|
||||||
neId: string;
|
neId: string;
|
||||||
importType: 'local' | 'server';
|
type: 'upload' | 'backup';
|
||||||
file: File | null;
|
path: string | undefined;
|
||||||
fileName: string | undefined;
|
|
||||||
};
|
};
|
||||||
/**确定按钮 loading */
|
/**确定按钮 loading */
|
||||||
confirmLoading: boolean;
|
confirmLoading: boolean;
|
||||||
@@ -84,9 +102,8 @@ let modalState: ModalStateType = reactive({
|
|||||||
from: {
|
from: {
|
||||||
neType: '',
|
neType: '',
|
||||||
neId: '',
|
neId: '',
|
||||||
importType: 'local',
|
type: 'upload',
|
||||||
file: null,
|
path: undefined,
|
||||||
fileName: undefined,
|
|
||||||
},
|
},
|
||||||
confirmLoading: false,
|
confirmLoading: false,
|
||||||
uploadFiles: [],
|
uploadFiles: [],
|
||||||
@@ -96,16 +113,10 @@ let modalState: ModalStateType = reactive({
|
|||||||
const modalStateFrom = Form.useForm(
|
const modalStateFrom = Form.useForm(
|
||||||
modalState.from,
|
modalState.from,
|
||||||
reactive({
|
reactive({
|
||||||
file: [
|
path: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: t('views.ne.neInfo.backConf.filePlease'),
|
message: t('views.ne.neInfo.backConf.pathPlease'),
|
||||||
},
|
|
||||||
],
|
|
||||||
fileName: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: t('views.ne.neInfo.backConf.fileNamePlease'),
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
@@ -117,21 +128,13 @@ const modalStateFrom = Form.useForm(
|
|||||||
*/
|
*/
|
||||||
function fnModalOk() {
|
function fnModalOk() {
|
||||||
if (modalState.confirmLoading) return;
|
if (modalState.confirmLoading) return;
|
||||||
|
|
||||||
const from = toRaw(modalState.from);
|
const from = toRaw(modalState.from);
|
||||||
let validateName = ['importType'];
|
|
||||||
if (from.importType === 'local') {
|
|
||||||
validateName.push('file');
|
|
||||||
} else {
|
|
||||||
validateName.push('fileName');
|
|
||||||
}
|
|
||||||
|
|
||||||
modalStateFrom
|
modalStateFrom
|
||||||
.validate(validateName)
|
.validate()
|
||||||
.then(e => {
|
.then(e => {
|
||||||
modalState.confirmLoading = true;
|
modalState.confirmLoading = true;
|
||||||
const hide = message.loading(t('common.loading'), 0);
|
const hide = message.loading(t('common.loading'), 0);
|
||||||
importFile(from)
|
importNeConfigBackup(from)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (res.code === RESULT_CODE_SUCCESS) {
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
message.success(t('common.operateOk'), 3);
|
message.success(t('common.operateOk'), 3);
|
||||||
@@ -168,6 +171,12 @@ function fnModalCancel() {
|
|||||||
emit('update:visible', false);
|
emit('update:visible', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**表单上传前删除 */
|
||||||
|
function fnBeforeRemoveFile(file: UploadFile) {
|
||||||
|
modalState.from.path = undefined;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**表单上传前检查或转换压缩 */
|
/**表单上传前检查或转换压缩 */
|
||||||
function fnBeforeUploadFile(file: FileType) {
|
function fnBeforeUploadFile(file: FileType) {
|
||||||
if (modalState.confirmLoading) return false;
|
if (modalState.confirmLoading) return false;
|
||||||
@@ -187,12 +196,30 @@ function fnBeforeUploadFile(file: FileType) {
|
|||||||
|
|
||||||
/**表单上传文件 */
|
/**表单上传文件 */
|
||||||
function fnUploadFile(up: UploadRequestOption) {
|
function fnUploadFile(up: UploadRequestOption) {
|
||||||
|
// 发送请求
|
||||||
|
const hide = message.loading(t('common.loading'), 0);
|
||||||
|
modalState.confirmLoading = true;
|
||||||
|
let formData = new FormData();
|
||||||
|
formData.append('file', up.file);
|
||||||
|
formData.append('subPath', 'import');
|
||||||
|
uploadFile(formData)
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
// 改为完成状态
|
// 改为完成状态
|
||||||
const file = modalState.uploadFiles[0];
|
const file = modalState.uploadFiles[0];
|
||||||
file.percent = 100;
|
file.percent = 100;
|
||||||
file.status = 'done';
|
file.status = 'done';
|
||||||
// 预置到表单
|
// 预置到表单
|
||||||
modalState.from.file = up.file as File;
|
const { fileName } = res.data;
|
||||||
|
modalState.from.path = fileName;
|
||||||
|
} else {
|
||||||
|
message.error(res.msg, 3);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hide();
|
||||||
|
modalState.confirmLoading = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**监听是否显示,初始数据 */
|
/**监听是否显示,初始数据 */
|
||||||
@@ -220,10 +247,17 @@ function fnExportConf(neType: string, neId: string) {
|
|||||||
content: t('views.ne.neInfo.backConf.exportTip'),
|
content: t('views.ne.neInfo.backConf.exportTip'),
|
||||||
onOk() {
|
onOk() {
|
||||||
const hide = message.loading(t('common.loading'), 0);
|
const hide = message.loading(t('common.loading'), 0);
|
||||||
exportSet({ neType, neId })
|
exportNeConfigBackup({ neType, neId })
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (res.code === RESULT_CODE_SUCCESS) {
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
message.success(t('views.ne.neInfo.backConf.exportMsg'), 3);
|
notification.success({
|
||||||
|
message: t('common.tipTitle'),
|
||||||
|
description: t('views.ne.neInfo.backConf.exportMsg'),
|
||||||
|
});
|
||||||
|
saveAs(
|
||||||
|
res.data,
|
||||||
|
`${neType}_${neId}_config_backup_${Date.now()}.zip`
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
message.error(`${res.msg}`, 3);
|
message.error(`${res.msg}`, 3);
|
||||||
}
|
}
|
||||||
@@ -258,44 +292,44 @@ defineExpose({
|
|||||||
<a-form name="modalStateFrom" layout="horizontal" :label-col="{ span: 6 }">
|
<a-form name="modalStateFrom" layout="horizontal" :label-col="{ span: 6 }">
|
||||||
<a-row :gutter="16">
|
<a-row :gutter="16">
|
||||||
<a-col :lg="12" :md="12" :xs="24">
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
<a-form-item
|
<a-form-item :label="t('views.ne.common.neType')" name="neType">
|
||||||
:label="t('views.ne.common.neType')"
|
|
||||||
name="neType"
|
|
||||||
v-bind="modalStateFrom.validateInfos.neType"
|
|
||||||
>
|
|
||||||
{{ modalState.from.neType }}
|
{{ modalState.from.neType }}
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label="t('views.ne.neInfo.backConf.importType')"
|
:label="t('views.ne.neInfo.backConf.importType')"
|
||||||
name="importType"
|
name="type"
|
||||||
>
|
>
|
||||||
<a-select
|
<a-select
|
||||||
v-model:value="modalState.from.importType"
|
v-model:value="modalState.from.type"
|
||||||
default-value="server"
|
default-value="server"
|
||||||
:options="neManageOption.importType"
|
:options="importState.typeOption"
|
||||||
@change="typeChange"
|
@change="typeChange"
|
||||||
>
|
>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :lg="12" :md="12" :xs="24">
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
<a-form-item
|
<a-form-item :label="t('views.ne.common.neId')" name="neId">
|
||||||
:label="t('views.ne.common.neId')"
|
|
||||||
name="neId"
|
|
||||||
v-bind="modalStateFrom.validateInfos.neId"
|
|
||||||
>
|
|
||||||
{{ modalState.from.neId }}
|
{{ modalState.from.neId }}
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label="t('views.ne.neInfo.backConf.server')"
|
:label="t('views.ne.neInfo.backConf.server')"
|
||||||
name="fileName"
|
name="fileName"
|
||||||
v-bind="modalStateFrom.validateInfos.fileName"
|
v-bind="modalStateFrom.validateInfos.path"
|
||||||
v-if="modalState.from.importType === 'server'"
|
v-if="modalState.from.type === 'backup'"
|
||||||
>
|
>
|
||||||
<a-select
|
<a-select
|
||||||
v-model:value="modalState.from.fileName"
|
v-model:value="modalState.from.path"
|
||||||
:options="neManageOption.serverFileName"
|
:options="importState.backupData"
|
||||||
:placeholder="t('common.selectPlease')"
|
:placeholder="t('common.selectPlease')"
|
||||||
|
:show-search="true"
|
||||||
|
:default-active-first-option="false"
|
||||||
|
:show-arrow="false"
|
||||||
|
:allow-clear="true"
|
||||||
|
:filter-option="false"
|
||||||
|
:not-found-content="null"
|
||||||
|
@search="backupSearch"
|
||||||
|
@change="backupChange"
|
||||||
>
|
>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
@@ -303,8 +337,8 @@ defineExpose({
|
|||||||
<a-form-item
|
<a-form-item
|
||||||
:label="t('views.ne.neInfo.backConf.local')"
|
:label="t('views.ne.neInfo.backConf.local')"
|
||||||
name="file"
|
name="file"
|
||||||
v-bind="modalStateFrom.validateInfos.file"
|
v-bind="modalStateFrom.validateInfos.path"
|
||||||
v-if="modalState.from.importType === 'local'"
|
v-if="modalState.from.type === 'upload'"
|
||||||
>
|
>
|
||||||
<a-upload
|
<a-upload
|
||||||
name="file"
|
name="file"
|
||||||
@@ -314,9 +348,10 @@ defineExpose({
|
|||||||
:max-count="1"
|
:max-count="1"
|
||||||
:show-upload-list="{
|
:show-upload-list="{
|
||||||
showPreviewIcon: false,
|
showPreviewIcon: false,
|
||||||
showRemoveIcon: false,
|
showRemoveIcon: true,
|
||||||
showDownloadIcon: false,
|
showDownloadIcon: false,
|
||||||
}"
|
}"
|
||||||
|
:remove="fnBeforeRemoveFile"
|
||||||
:before-upload="fnBeforeUploadFile"
|
:before-upload="fnBeforeUploadFile"
|
||||||
:custom-request="fnUploadFile"
|
:custom-request="fnUploadFile"
|
||||||
:disabled="modalState.confirmLoading"
|
:disabled="modalState.confirmLoading"
|
||||||
|
|||||||
@@ -124,8 +124,8 @@ let modalState: ModalStateType = reactive({
|
|||||||
addr: '',
|
addr: '',
|
||||||
port: 22,
|
port: 22,
|
||||||
user: 'omcuser',
|
user: 'omcuser',
|
||||||
authMode: '2',
|
authMode: '0',
|
||||||
password: '',
|
password: 'a9tU53r',
|
||||||
privateKey: '',
|
privateKey: '',
|
||||||
passPhrase: '',
|
passPhrase: '',
|
||||||
remark: '',
|
remark: '',
|
||||||
@@ -281,9 +281,7 @@ function fnModalCancel() {
|
|||||||
emit('update:visible', false);
|
emit('update:visible', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**表单修改网元类型 */
|
||||||
* 表单修改网元类型
|
|
||||||
*/
|
|
||||||
function fnNeTypeChange(v: any) {
|
function fnNeTypeChange(v: any) {
|
||||||
const hostsLen = modalState.from.hosts.length;
|
const hostsLen = modalState.from.hosts.length;
|
||||||
// 网元默认只含22和4100
|
// 网元默认只含22和4100
|
||||||
@@ -305,11 +303,18 @@ function fnNeTypeChange(v: any) {
|
|||||||
remark: '',
|
remark: '',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
modalState.from.rmUid = `4400HX${v}${modalState.from.neId}`; // 4400HX1AMF001
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**表单修改网元neId */
|
||||||
* 表单修改网元IP
|
function fnNeIdChange(e: any) {
|
||||||
*/
|
const v = e.target.value;
|
||||||
|
if (v.length < 1) return;
|
||||||
|
modalState.from.rmUid = `4400HX${modalState.from.neType}${v}`; // 4400HX1AMF001
|
||||||
|
}
|
||||||
|
|
||||||
|
/**表单修改网元IP */
|
||||||
function fnNeIPChange(e: any) {
|
function fnNeIPChange(e: any) {
|
||||||
const v = e.target.value;
|
const v = e.target.value;
|
||||||
if (v.length < 7) return;
|
if (v.length < 7) return;
|
||||||
@@ -428,6 +433,7 @@ onMounted(() => {
|
|||||||
allow-clear
|
allow-clear
|
||||||
:placeholder="t('common.inputPlease')"
|
:placeholder="t('common.inputPlease')"
|
||||||
:maxlength="32"
|
:maxlength="32"
|
||||||
|
@change="fnNeIdChange"
|
||||||
>
|
>
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<a-tooltip placement="topLeft">
|
<a-tooltip placement="topLeft">
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ let modalState: ModalStateType = reactive({
|
|||||||
title: 'OAM Configuration',
|
title: 'OAM Configuration',
|
||||||
sync: true,
|
sync: true,
|
||||||
from: {
|
from: {
|
||||||
|
omcIP: '',
|
||||||
oamEnable: true,
|
oamEnable: true,
|
||||||
oamPort: 33030,
|
oamPort: 33030,
|
||||||
snmpEnable: true,
|
snmpEnable: true,
|
||||||
@@ -77,6 +78,7 @@ function fnModalVisibleByTypeAndId(neType: string, neId: string) {
|
|||||||
if (res.code === RESULT_CODE_SUCCESS) {
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
const data = res.data;
|
const data = res.data;
|
||||||
Object.assign(modalState.from, {
|
Object.assign(modalState.from, {
|
||||||
|
omcIP: data.oamConfig[data.oamConfig.ipType],
|
||||||
oamEnable: data.oamConfig.enable,
|
oamEnable: data.oamConfig.enable,
|
||||||
oamPort: data.oamConfig.port,
|
oamPort: data.oamConfig.port,
|
||||||
snmpEnable: data.snmpConfig.enable,
|
snmpEnable: data.snmpConfig.enable,
|
||||||
@@ -224,6 +226,17 @@ watch(
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
|
<a-form-item
|
||||||
|
:label="t('views.ne.neInfo.oam.omcIP')"
|
||||||
|
name="omcIP"
|
||||||
|
:label-col="{ span: 6 }"
|
||||||
|
:labelWrap="true"
|
||||||
|
>
|
||||||
|
<a-input
|
||||||
|
v-model:value="modalState.from.omcIP"
|
||||||
|
:maxlength="128"
|
||||||
|
></a-input>
|
||||||
|
</a-form-item>
|
||||||
</a-collapse-panel>
|
</a-collapse-panel>
|
||||||
<a-collapse-panel header="SNMP">
|
<a-collapse-panel header="SNMP">
|
||||||
<a-row :gutter="16">
|
<a-row :gutter="16">
|
||||||
|
|||||||
@@ -233,9 +233,13 @@ function fnModalEditOk(from: Record<string, any>) {
|
|||||||
if (item && res.code === RESULT_CODE_SUCCESS) {
|
if (item && res.code === RESULT_CODE_SUCCESS) {
|
||||||
item.neType = from.neType;
|
item.neType = from.neType;
|
||||||
item.neId = from.neId;
|
item.neId = from.neId;
|
||||||
item.ip = from.ip;
|
item.rmUid = from.rmUid;
|
||||||
item.neName = from.neName;
|
item.neName = from.neName;
|
||||||
|
item.ip = from.ip;
|
||||||
|
item.port = from.port;
|
||||||
|
if (item.status !== '2') {
|
||||||
item.status = res.data.online ? '1' : '0';
|
item.status = res.data.online ? '1' : '0';
|
||||||
|
}
|
||||||
Object.assign(item.serverState, res.data);
|
Object.assign(item.serverState, res.data);
|
||||||
const resouresUsage = parseResouresUsage(item.serverState);
|
const resouresUsage = parseResouresUsage(item.serverState);
|
||||||
Reflect.set(item, 'resoures', resouresUsage);
|
Reflect.set(item, 'resoures', resouresUsage);
|
||||||
@@ -281,10 +285,10 @@ function fnRecordDelete(id: string) {
|
|||||||
message.success(t('common.operateOk'), 3);
|
message.success(t('common.operateOk'), 3);
|
||||||
// 过滤掉删除的id
|
// 过滤掉删除的id
|
||||||
tableState.data = tableState.data.filter(item => {
|
tableState.data = tableState.data.filter(item => {
|
||||||
if (id.indexOf(',')) {
|
if (id.indexOf(',') > -1) {
|
||||||
return !tableState.selectedRowKeys.includes(item.id);
|
return !tableState.selectedRowKeys.includes(item.id);
|
||||||
} else {
|
} else {
|
||||||
return item.id != id;
|
return item.id !== id;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// 刷新缓存
|
// 刷新缓存
|
||||||
@@ -362,8 +366,18 @@ function fnGetList(pageNum?: number) {
|
|||||||
tablePagination.total = res.total;
|
tablePagination.total = res.total;
|
||||||
// 遍历处理资源情况数值
|
// 遍历处理资源情况数值
|
||||||
tableState.data = res.rows.map(item => {
|
tableState.data = res.rows.map(item => {
|
||||||
|
let resouresUsage = {
|
||||||
|
sysDiskUsage: 0,
|
||||||
|
sysMemUsage: 0,
|
||||||
|
sysCpuUsage: 0,
|
||||||
|
nfCpuUsage: 0,
|
||||||
|
};
|
||||||
const neState = item.serverState;
|
const neState = item.serverState;
|
||||||
const resouresUsage = parseResouresUsage(neState);
|
if (neState) {
|
||||||
|
resouresUsage = parseResouresUsage(neState);
|
||||||
|
} else {
|
||||||
|
item.serverState = { online: false };
|
||||||
|
}
|
||||||
Reflect.set(item, 'resoures', resouresUsage);
|
Reflect.set(item, 'resoures', resouresUsage);
|
||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
@@ -378,33 +392,27 @@ function parseResouresUsage(neState: Record<string, any>) {
|
|||||||
let nfCpuUsage = 0;
|
let nfCpuUsage = 0;
|
||||||
if (neState.cpu) {
|
if (neState.cpu) {
|
||||||
nfCpuUsage = neState.cpu.nfCpuUsage;
|
nfCpuUsage = neState.cpu.nfCpuUsage;
|
||||||
if (nfCpuUsage > 100) {
|
const nfCpu = +(nfCpuUsage / 100);
|
||||||
const nfCpu = +(neState.cpu.nfCpuUsage / 100);
|
|
||||||
if (nfCpu > 100) {
|
|
||||||
nfCpuUsage = 100;
|
|
||||||
} else {
|
|
||||||
nfCpuUsage = +nfCpu.toFixed(2);
|
nfCpuUsage = +nfCpu.toFixed(2);
|
||||||
}
|
if (nfCpuUsage > 100) {
|
||||||
|
nfCpuUsage = 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
sysCpuUsage = neState.cpu.sysCpuUsage;
|
sysCpuUsage = neState.cpu.sysCpuUsage;
|
||||||
if (sysCpuUsage > 100) {
|
const sysCpu = +(sysCpuUsage / 100);
|
||||||
const sysCpu = +(neState.cpu.sysCpuUsage / 100);
|
|
||||||
if (sysCpu > 100) {
|
|
||||||
sysCpuUsage = 100;
|
|
||||||
} else {
|
|
||||||
sysCpuUsage = +sysCpu.toFixed(2);
|
sysCpuUsage = +sysCpu.toFixed(2);
|
||||||
}
|
if (sysCpuUsage > 100) {
|
||||||
|
sysCpuUsage = 100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let sysMemUsage = 0;
|
let sysMemUsage = 0;
|
||||||
if (neState.mem) {
|
if (neState.mem) {
|
||||||
let men = neState.mem.sysMemUsage;
|
const men = neState.mem.sysMemUsage;
|
||||||
if (men > 100) {
|
sysMemUsage = +(men / 100).toFixed(2);
|
||||||
men = +(men / 100).toFixed(2);
|
if (sysMemUsage > 100) {
|
||||||
|
sysMemUsage = 100;
|
||||||
}
|
}
|
||||||
sysMemUsage = men;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let sysDiskUsage = 0;
|
let sysDiskUsage = 0;
|
||||||
@@ -556,7 +564,7 @@ onMounted(() => {
|
|||||||
:data-source="tableState.data"
|
:data-source="tableState.data"
|
||||||
:size="tableState.size"
|
:size="tableState.size"
|
||||||
:pagination="tablePagination"
|
:pagination="tablePagination"
|
||||||
:scroll="{ x: tableColumns.length * 150 }"
|
:scroll="{ x: tableColumns.length * 120 }"
|
||||||
:row-selection="{
|
:row-selection="{
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
columnWidth: '48px',
|
columnWidth: '48px',
|
||||||
@@ -623,7 +631,10 @@ onMounted(() => {
|
|||||||
<DeleteOutlined />
|
<DeleteOutlined />
|
||||||
{{ t('common.deleteText') }}
|
{{ t('common.deleteText') }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item key="oam">
|
<a-menu-item
|
||||||
|
key="oam"
|
||||||
|
v-if="!['OMC'].includes(record.neType)"
|
||||||
|
>
|
||||||
<FileTextOutlined />
|
<FileTextOutlined />
|
||||||
{{ t('views.ne.common.oam') }}
|
{{ t('views.ne.common.oam') }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
|
|||||||
@@ -157,11 +157,7 @@ type StateType = {
|
|||||||
optionType: 'upload' | 'option';
|
optionType: 'upload' | 'option';
|
||||||
/**文件上传 */
|
/**文件上传 */
|
||||||
visibleByFile: boolean;
|
visibleByFile: boolean;
|
||||||
/**
|
/**网元拓展包列表类型 */
|
||||||
* 依赖包类型
|
|
||||||
* IMS-rtproxy/mf/adb
|
|
||||||
* UDM-adb
|
|
||||||
*/
|
|
||||||
depType: string[];
|
depType: string[];
|
||||||
/**软件包信息数据 */
|
/**软件包信息数据 */
|
||||||
from: {
|
from: {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive, onMounted, watch } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
import useI18n from '@/hooks/useI18n';
|
import useI18n from '@/hooks/useI18n';
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const emit = defineEmits(['update:data']);
|
const emit = defineEmits(['update:data']);
|
||||||
@@ -21,22 +21,8 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/**对话框对象信息状态类型 */
|
/**表单信息状态 */
|
||||||
type StateType = {
|
let fromState = ref({
|
||||||
/**表单数据 */
|
|
||||||
from: Record<string, any>;
|
|
||||||
/**根据网元显示配置项 */
|
|
||||||
hasNE: {
|
|
||||||
amf: boolean;
|
|
||||||
upf: boolean;
|
|
||||||
ims: boolean;
|
|
||||||
mme: boolean;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**对话框对象信息状态 */
|
|
||||||
let state: StateType = reactive({
|
|
||||||
from: {
|
|
||||||
basic: {
|
basic: {
|
||||||
plmnId: {
|
plmnId: {
|
||||||
mcc: '001',
|
mcc: '001',
|
||||||
@@ -74,7 +60,7 @@ let state: StateType = reactive({
|
|||||||
amf_ip: '172.16.5.120',
|
amf_ip: '172.16.5.120',
|
||||||
ausf_ip: '172.16.5.130',
|
ausf_ip: '172.16.5.130',
|
||||||
udm_ip: '172.16.5.140',
|
udm_ip: '172.16.5.140',
|
||||||
adb_ip: '0.0.0.0',
|
db_ip: '0.0.0.0',
|
||||||
smf_ip: '172.16.5.150',
|
smf_ip: '172.16.5.150',
|
||||||
pcf_ip: '172.16.5.160',
|
pcf_ip: '172.16.5.160',
|
||||||
nssf_ip: '172.16.5.170',
|
nssf_ip: '172.16.5.170',
|
||||||
@@ -85,45 +71,16 @@ let state: StateType = reactive({
|
|||||||
mme_ip: '172.16.5.220',
|
mme_ip: '172.16.5.220',
|
||||||
n3iwf_ip: '172.16.5.230',
|
n3iwf_ip: '172.16.5.230',
|
||||||
},
|
},
|
||||||
},
|
|
||||||
hasNE: {
|
|
||||||
amf: false,
|
|
||||||
upf: false,
|
|
||||||
ims: false,
|
|
||||||
mme: false,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**监听数据 */
|
/**监听数据 */
|
||||||
watch(
|
watch(
|
||||||
() => props.data,
|
() => fromState,
|
||||||
val => {
|
|
||||||
if (val) {
|
|
||||||
Object.assign(state.from, val);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ deep: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.ne,
|
|
||||||
val => {
|
|
||||||
if (val) {
|
|
||||||
Object.assign(state.hasNE, val);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ deep: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => state.from,
|
|
||||||
val => {
|
val => {
|
||||||
if (val) emit('update:data', val);
|
if (val) emit('update:data', val);
|
||||||
},
|
},
|
||||||
{ deep: true, immediate: true }
|
{ deep: true, immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(() => {});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -140,7 +97,7 @@ onMounted(() => {});
|
|||||||
<a-col :lg="12" :md="12" :xs="24">
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
<a-form-item label="DNN_DATA" name="basic.dnn_data">
|
<a-form-item label="DNN_DATA" name="basic.dnn_data">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="state.from.basic.dnn_data"
|
v-model:value="fromState.basic.dnn_data"
|
||||||
allow-clear
|
allow-clear
|
||||||
:placeholder="t('common.inputPlease')"
|
:placeholder="t('common.inputPlease')"
|
||||||
:maxlength="50"
|
:maxlength="50"
|
||||||
@@ -155,13 +112,13 @@ onMounted(() => {});
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="MCC" name="basic.plmnId.mcc">
|
<a-form-item label="MCC" name="basic.plmnId.mcc">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="state.from.basic.plmnId.mcc"
|
v-model:value="fromState.basic.plmnId.mcc"
|
||||||
placeholder="1-65535"
|
placeholder="1-65535"
|
||||||
></a-input>
|
></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="SST" name="basic.snssai.sst">
|
<a-form-item label="SST" name="basic.snssai.sst">
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-model:value="state.from.basic.snssai.sst"
|
v-model:value="fromState.basic.snssai.sst"
|
||||||
:min="1"
|
:min="1"
|
||||||
:max="3"
|
:max="3"
|
||||||
placeholder="1-3"
|
placeholder="1-3"
|
||||||
@@ -177,7 +134,7 @@ onMounted(() => {});
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="TAC" name="basic.tac">
|
<a-form-item label="TAC" name="basic.tac">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="state.from.basic.tac"
|
v-model:value="fromState.basic.tac"
|
||||||
placeholder="1-65535"
|
placeholder="1-65535"
|
||||||
></a-input>
|
></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
@@ -185,7 +142,7 @@ onMounted(() => {});
|
|||||||
<a-col :lg="12" :md="12" :xs="24">
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
<a-form-item label="DNN_IMS" name="basic.dnn_ims">
|
<a-form-item label="DNN_IMS" name="basic.dnn_ims">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="state.from.basic.dnn_ims"
|
v-model:value="fromState.basic.dnn_ims"
|
||||||
allow-clear
|
allow-clear
|
||||||
:placeholder="t('common.inputPlease')"
|
:placeholder="t('common.inputPlease')"
|
||||||
:maxlength="50"
|
:maxlength="50"
|
||||||
@@ -194,13 +151,13 @@ onMounted(() => {});
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="MNC" name="basic.plmnId.mnc">
|
<a-form-item label="MNC" name="basic.plmnId.mnc">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="state.from.basic.plmnId.mnc"
|
v-model:value="fromState.basic.plmnId.mnc"
|
||||||
placeholder="1-65535"
|
placeholder="1-65535"
|
||||||
></a-input>
|
></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="SD" name="basic.snssai.sd">
|
<a-form-item label="SD" name="basic.snssai.sd">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="state.from.basic.snssai.sd"
|
v-model:value="fromState.basic.snssai.sd"
|
||||||
placeholder="1-65535"
|
placeholder="1-65535"
|
||||||
></a-input>
|
></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
@@ -220,7 +177,7 @@ onMounted(() => {});
|
|||||||
:validateTrigger="[]"
|
:validateTrigger="[]"
|
||||||
>
|
>
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="state.from.sbi.omc_ip"
|
v-model:value="fromState.sbi.omc_ip"
|
||||||
allow-clear
|
allow-clear
|
||||||
:placeholder="t('common.inputPlease')"
|
:placeholder="t('common.inputPlease')"
|
||||||
:maxlength="50"
|
:maxlength="50"
|
||||||
@@ -237,14 +194,13 @@ onMounted(() => {});
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
|
<template v-if="props.ne.amf">
|
||||||
<template v-if="state.hasNE.amf">
|
|
||||||
<a-divider orientation="left">AMF</a-divider>
|
<a-divider orientation="left">AMF</a-divider>
|
||||||
<a-row :gutter="16">
|
<a-row :gutter="16">
|
||||||
<a-col :lg="24" :md="24" :xs="24">
|
<a-col :lg="24" :md="24" :xs="24">
|
||||||
<a-form-item label="N2_IP" name="external.amfn2_ip">
|
<a-form-item label="N2_IP" name="external.amfn2_ip">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="state.from.external.amfn2_ip"
|
v-model:value="fromState.external.amfn2_ip"
|
||||||
allow-clear
|
allow-clear
|
||||||
:placeholder="t('common.inputPlease')"
|
:placeholder="t('common.inputPlease')"
|
||||||
:maxlength="50"
|
:maxlength="50"
|
||||||
@@ -262,7 +218,7 @@ onMounted(() => {});
|
|||||||
</template>
|
</template>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
|
||||||
<a-col :lg="16" :md="16" :xs="24" v-if="state.hasNE.upf">
|
<a-col :lg="16" :md="16" :xs="24" v-if="props.ne.upf">
|
||||||
<a-divider orientation="left">UPF</a-divider>
|
<a-divider orientation="left">UPF</a-divider>
|
||||||
<a-row :gutter="16">
|
<a-row :gutter="16">
|
||||||
<a-col :lg="12" :md="12" :xs="24">
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
@@ -272,7 +228,7 @@ onMounted(() => {});
|
|||||||
help="Install of Standard or Light"
|
help="Install of Standard or Light"
|
||||||
>
|
>
|
||||||
<a-select
|
<a-select
|
||||||
v-model:value="state.from.external.upf_type"
|
v-model:value="fromState.external.upf_type"
|
||||||
:placeholder="t('common.selectPlease')"
|
:placeholder="t('common.selectPlease')"
|
||||||
>
|
>
|
||||||
<a-select-option value="StandardUPF">
|
<a-select-option value="StandardUPF">
|
||||||
@@ -285,7 +241,7 @@ onMounted(() => {});
|
|||||||
<a-col :lg="12" :md="12" :xs="24">
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
<a-form-item label="UE_POOL" name="external.ue_pool">
|
<a-form-item label="UE_POOL" name="external.ue_pool">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="state.from.external.ue_pool"
|
v-model:value="fromState.external.ue_pool"
|
||||||
allow-clear
|
allow-clear
|
||||||
:placeholder="t('common.inputPlease')"
|
:placeholder="t('common.inputPlease')"
|
||||||
:maxlength="50"
|
:maxlength="50"
|
||||||
@@ -305,7 +261,7 @@ onMounted(() => {});
|
|||||||
<a-col :lg="12" :md="12" :xs="24">
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
<a-form-item label="N3_IP" name="external.upfn3_ip">
|
<a-form-item label="N3_IP" name="external.upfn3_ip">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="state.from.external.upfn3_ip"
|
v-model:value="fromState.external.upfn3_ip"
|
||||||
allow-clear
|
allow-clear
|
||||||
:placeholder="t('common.inputPlease')"
|
:placeholder="t('common.inputPlease')"
|
||||||
:maxlength="50"
|
:maxlength="50"
|
||||||
@@ -320,7 +276,7 @@ onMounted(() => {});
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="N3_GW" name="external.upfn3_gw">
|
<a-form-item label="N3_GW" name="external.upfn3_gw">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="state.from.external.upfn3_gw"
|
v-model:value="fromState.external.upfn3_gw"
|
||||||
allow-clear
|
allow-clear
|
||||||
:placeholder="t('common.inputPlease')"
|
:placeholder="t('common.inputPlease')"
|
||||||
:maxlength="50"
|
:maxlength="50"
|
||||||
@@ -338,11 +294,11 @@ onMounted(() => {});
|
|||||||
:lg="12"
|
:lg="12"
|
||||||
:md="12"
|
:md="12"
|
||||||
:xs="24"
|
:xs="24"
|
||||||
v-if="state.from.external.upf_type === 'StandardUPF'"
|
v-if="fromState.external.upf_type === 'StandardUPF'"
|
||||||
>
|
>
|
||||||
<a-form-item label="N3_PCI" name="external.upfn3_pci">
|
<a-form-item label="N3_PCI" name="external.upfn3_pci">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="state.from.external.upfn3_pci"
|
v-model:value="fromState.external.upfn3_pci"
|
||||||
allow-clear
|
allow-clear
|
||||||
:placeholder="t('common.inputPlease')"
|
:placeholder="t('common.inputPlease')"
|
||||||
:maxlength="50"
|
:maxlength="50"
|
||||||
@@ -359,7 +315,7 @@ onMounted(() => {});
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="N3_MAC" name="external.upfn3_mac">
|
<a-form-item label="N3_MAC" name="external.upfn3_mac">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="state.from.external.upfn3_mac"
|
v-model:value="fromState.external.upfn3_mac"
|
||||||
allow-clear
|
allow-clear
|
||||||
:placeholder="t('common.inputPlease')"
|
:placeholder="t('common.inputPlease')"
|
||||||
:maxlength="50"
|
:maxlength="50"
|
||||||
@@ -376,12 +332,12 @@ onMounted(() => {});
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
<template v-if="state.from.external.upf_type === 'StandardUPF'">
|
<template v-if="fromState.external.upf_type === 'StandardUPF'">
|
||||||
<a-row :gutter="16">
|
<a-row :gutter="16">
|
||||||
<a-col :lg="12" :md="12" :xs="24">
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
<a-form-item label="N6_IP" name="external.upfn6_ip">
|
<a-form-item label="N6_IP" name="external.upfn6_ip">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="state.from.external.upfn6_ip"
|
v-model:value="fromState.external.upfn6_ip"
|
||||||
allow-clear
|
allow-clear
|
||||||
:placeholder="t('common.inputPlease')"
|
:placeholder="t('common.inputPlease')"
|
||||||
:maxlength="50"
|
:maxlength="50"
|
||||||
@@ -390,7 +346,7 @@ onMounted(() => {});
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="N6_GW" name="external.upfn6_gw">
|
<a-form-item label="N6_GW" name="external.upfn6_gw">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="state.from.external.upfn6_gw"
|
v-model:value="fromState.external.upfn6_gw"
|
||||||
allow-clear
|
allow-clear
|
||||||
:placeholder="t('common.inputPlease')"
|
:placeholder="t('common.inputPlease')"
|
||||||
:maxlength="50"
|
:maxlength="50"
|
||||||
@@ -401,7 +357,7 @@ onMounted(() => {});
|
|||||||
<a-col :lg="12" :md="12" :xs="24">
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
<a-form-item label="N6_PCI" name="external.upfn6_pci">
|
<a-form-item label="N6_PCI" name="external.upfn6_pci">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="state.from.external.upfn6_pci"
|
v-model:value="fromState.external.upfn6_pci"
|
||||||
allow-clear
|
allow-clear
|
||||||
:placeholder="t('common.inputPlease')"
|
:placeholder="t('common.inputPlease')"
|
||||||
:maxlength="50"
|
:maxlength="50"
|
||||||
@@ -410,7 +366,7 @@ onMounted(() => {});
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="N6_MAC" name="external.upfn6_mac">
|
<a-form-item label="N6_MAC" name="external.upfn6_mac">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="state.from.external.upfn6_mac"
|
v-model:value="fromState.external.upfn6_mac"
|
||||||
allow-clear
|
allow-clear
|
||||||
:placeholder="t('common.inputPlease')"
|
:placeholder="t('common.inputPlease')"
|
||||||
:maxlength="50"
|
:maxlength="50"
|
||||||
@@ -423,13 +379,13 @@ onMounted(() => {});
|
|||||||
</a-col>
|
</a-col>
|
||||||
|
|
||||||
<a-col :lg="8" :md="8" :xs="24">
|
<a-col :lg="8" :md="8" :xs="24">
|
||||||
<template v-if="state.hasNE.ims">
|
<template v-if="props.ne.ims">
|
||||||
<a-divider orientation="left">IMS</a-divider>
|
<a-divider orientation="left">IMS</a-divider>
|
||||||
<a-row :gutter="16">
|
<a-row :gutter="16">
|
||||||
<a-col :lg="24" :md="24" :xs="24">
|
<a-col :lg="24" :md="24" :xs="24">
|
||||||
<a-form-item label="SIP_IP" name="external.ims_sip_ip">
|
<a-form-item label="SIP_IP" name="external.ims_sip_ip">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="state.from.external.ims_sip_ip"
|
v-model:value="fromState.external.ims_sip_ip"
|
||||||
allow-clear
|
allow-clear
|
||||||
:placeholder="t('common.inputPlease')"
|
:placeholder="t('common.inputPlease')"
|
||||||
:maxlength="50"
|
:maxlength="50"
|
||||||
@@ -446,13 +402,13 @@ onMounted(() => {});
|
|||||||
</a-row>
|
</a-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-if="state.hasNE.mme">
|
<template v-if="props.ne.mme">
|
||||||
<a-divider orientation="left">MME</a-divider>
|
<a-divider orientation="left">MME</a-divider>
|
||||||
<a-row :gutter="16">
|
<a-row :gutter="16">
|
||||||
<a-col :lg="24" :md="24" :xs="24">
|
<a-col :lg="24" :md="24" :xs="24">
|
||||||
<a-form-item label="S1_IP" name="external.mmes1_ip">
|
<a-form-item label="S1_IP" name="external.mmes1_ip">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="state.from.external.mmes1_ip"
|
v-model:value="fromState.external.mmes1_ip"
|
||||||
allow-clear
|
allow-clear
|
||||||
:placeholder="t('common.inputPlease')"
|
:placeholder="t('common.inputPlease')"
|
||||||
:maxlength="50"
|
:maxlength="50"
|
||||||
@@ -471,7 +427,7 @@ onMounted(() => {});
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="S10_IP" name="external.mmes10_ip">
|
<a-form-item label="S10_IP" name="external.mmes10_ip">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="state.from.external.mmes10_ip"
|
v-model:value="fromState.external.mmes10_ip"
|
||||||
allow-clear
|
allow-clear
|
||||||
:placeholder="t('common.inputPlease')"
|
:placeholder="t('common.inputPlease')"
|
||||||
:maxlength="50"
|
:maxlength="50"
|
||||||
@@ -486,7 +442,7 @@ onMounted(() => {});
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="S11_IP" name="external.mmes11_ip">
|
<a-form-item label="S11_IP" name="external.mmes11_ip">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="state.from.external.mmes11_ip"
|
v-model:value="fromState.external.mmes11_ip"
|
||||||
allow-clear
|
allow-clear
|
||||||
:placeholder="t('common.inputPlease')"
|
:placeholder="t('common.inputPlease')"
|
||||||
:maxlength="50"
|
:maxlength="50"
|
||||||
@@ -231,6 +231,17 @@ function fnHostAuthorized() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**返回上一步 */
|
||||||
|
function fnStepPrev() {
|
||||||
|
Modal.confirm({
|
||||||
|
title: t('common.tipTitle'),
|
||||||
|
content: t('views.ne.neQuickSetup.stepPrevTip'),
|
||||||
|
onOk() {
|
||||||
|
fnToStepName('Para5G');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**下一步操作 */
|
/**下一步操作 */
|
||||||
function fnStepNext() {
|
function fnStepNext() {
|
||||||
if (!state.stepNext) return;
|
if (!state.stepNext) return;
|
||||||
@@ -254,6 +265,7 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<div class="ne">
|
||||||
<a-descriptions :column="{ lg: 3, md: 2, sm: 2, xs: 1 }" bordered>
|
<a-descriptions :column="{ lg: 3, md: 2, sm: 2, xs: 1 }" bordered>
|
||||||
<a-descriptions-item :label="t('views.ne.neQuickSetup.addr')" :span="3">
|
<a-descriptions-item :label="t('views.ne.neQuickSetup.addr')" :span="3">
|
||||||
{{ state.info.addr }}
|
{{ state.info.addr }}
|
||||||
@@ -299,14 +311,16 @@ onMounted(() => {
|
|||||||
{{ t('views.ne.neQuickSetup.sshLink') }}
|
{{ t('views.ne.neQuickSetup.sshLink') }}
|
||||||
</a-tag>
|
</a-tag>
|
||||||
</a-descriptions-item>
|
</a-descriptions-item>
|
||||||
<a-descriptions-item :span="2">
|
</a-descriptions>
|
||||||
|
|
||||||
<a-form
|
<a-form
|
||||||
name="checkStateFrom"
|
name="checkStateFrom"
|
||||||
layout="horizontal"
|
layout="horizontal"
|
||||||
:label-col="{ span: 6 }"
|
:label-col="{ span: 6 }"
|
||||||
:label-wrap="false"
|
:label-wrap="true"
|
||||||
|
style="margin-top: 20px; width: 68%"
|
||||||
>
|
>
|
||||||
<a-row :gutter="16">
|
<a-row :gutter="8">
|
||||||
<a-col :lg="12" :md="12" :xs="24">
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label="t('views.ne.neHost.addr')"
|
:label="t('views.ne.neHost.addr')"
|
||||||
@@ -415,7 +429,7 @@ onMounted(() => {
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<a-form-item :wrapper-col="{ span: 10, offset: 3 }">
|
<a-form-item :wrapper-col="{ span: 8, offset: 3 }">
|
||||||
<a-space direction="horizontal" :size="18">
|
<a-space direction="horizontal" :size="18">
|
||||||
<a-button
|
<a-button
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -426,13 +440,6 @@ onMounted(() => {
|
|||||||
>
|
>
|
||||||
{{ t('views.ne.neHost.test') }}
|
{{ t('views.ne.neHost.test') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button
|
|
||||||
type="primary"
|
|
||||||
@click="fnStepNext()"
|
|
||||||
:disabled="!state.stepNext"
|
|
||||||
>
|
|
||||||
{{ t('views.ne.neQuickSetup.stepNext') }}
|
|
||||||
</a-button>
|
|
||||||
|
|
||||||
<a-button
|
<a-button
|
||||||
type="dashed"
|
type="dashed"
|
||||||
@@ -453,8 +460,37 @@ onMounted(() => {
|
|||||||
</a-space>
|
</a-space>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
</a-descriptions-item>
|
|
||||||
</a-descriptions>
|
<div class="ne-oper">
|
||||||
|
<a-space direction="horizontal" :size="18">
|
||||||
|
<a-button @click="fnStepPrev()">
|
||||||
|
{{ t('views.ne.neQuickSetup.stepPrev') }}
|
||||||
|
</a-button>
|
||||||
|
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
@click="fnStepNext()"
|
||||||
|
:disabled="!state.stepNext"
|
||||||
|
>
|
||||||
|
{{ t('views.ne.neQuickSetup.stepNext') }}
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped>
|
||||||
|
.ne {
|
||||||
|
min-height: 400px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
& .ant-form {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-oper {
|
||||||
|
text-align: end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
137
src/views/ne/neQuickSetup/hooks/usePara5G.ts
Normal file
137
src/views/ne/neQuickSetup/hooks/usePara5G.ts
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
import { reactive, toRaw } from 'vue';
|
||||||
|
import { getPara5GFilee, savePara5GFile, updateNeInfo } from '@/api/ne/neInfo';
|
||||||
|
import useNeInfoStore from '@/store/modules/neinfo';
|
||||||
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
|
|
||||||
|
/**对象信息信息状态类型 */
|
||||||
|
type StateType = {
|
||||||
|
/**表单数据 */
|
||||||
|
from: Record<string, any>;
|
||||||
|
/**OMC信息,需修改当前的IP */
|
||||||
|
omcInfo: Record<string, any>;
|
||||||
|
/**根据网元显示配置项 */
|
||||||
|
hasNE: {
|
||||||
|
amf: boolean;
|
||||||
|
upf: boolean;
|
||||||
|
ims: boolean;
|
||||||
|
mme: boolean;
|
||||||
|
};
|
||||||
|
/**确定按钮 loading */
|
||||||
|
confirmLoading: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function usePara5G() {
|
||||||
|
/**对象信息状态 */
|
||||||
|
let state: StateType = reactive({
|
||||||
|
from: {},
|
||||||
|
omcInfo: {},
|
||||||
|
hasNE: {
|
||||||
|
amf: false,
|
||||||
|
upf: false,
|
||||||
|
ims: false,
|
||||||
|
mme: false,
|
||||||
|
},
|
||||||
|
confirmLoading: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**载入数据*/
|
||||||
|
function fnReloadData() {
|
||||||
|
state.confirmLoading = true;
|
||||||
|
Promise.all([getPara5GFilee(), useNeInfoStore().fnRefreshNelist()]).then(
|
||||||
|
resArr => {
|
||||||
|
// 已保存的配置
|
||||||
|
if (resArr[0].code === RESULT_CODE_SUCCESS) {
|
||||||
|
Object.assign(state.from, resArr[0].data);
|
||||||
|
}
|
||||||
|
// 填充固定网元类型的ip
|
||||||
|
if (
|
||||||
|
resArr[1].code === RESULT_CODE_SUCCESS &&
|
||||||
|
Array.isArray(resArr[1].data)
|
||||||
|
) {
|
||||||
|
for (const item of resArr[1].data) {
|
||||||
|
// 公共配置文件sbi的各网元IP
|
||||||
|
switch (item.neType) {
|
||||||
|
case 'OMC':
|
||||||
|
state.from.sbi.omc_ip = item.ip;
|
||||||
|
Object.assign(state.omcInfo, item); // 主动改OMC_IP
|
||||||
|
break;
|
||||||
|
case 'IMS':
|
||||||
|
state.from.sbi.ims_ip = item.ip;
|
||||||
|
state.hasNE.ims = true;
|
||||||
|
break;
|
||||||
|
case 'AMF':
|
||||||
|
state.from.sbi.amf_ip = item.ip;
|
||||||
|
state.hasNE.amf = true;
|
||||||
|
break;
|
||||||
|
case 'AUSF':
|
||||||
|
state.from.sbi.ausf_ip = item.ip;
|
||||||
|
break;
|
||||||
|
case 'UDM':
|
||||||
|
state.from.sbi.udm_ip = item.ip;
|
||||||
|
state.from.sbi.db_ip = '0.0.0.0';
|
||||||
|
break;
|
||||||
|
case 'SMF':
|
||||||
|
state.from.sbi.smf_ip = item.ip;
|
||||||
|
break;
|
||||||
|
case 'PCF':
|
||||||
|
state.from.sbi.pcf_ip = item.ip;
|
||||||
|
break;
|
||||||
|
case 'NSSF':
|
||||||
|
state.from.sbi.nssf_ip = item.ip;
|
||||||
|
break;
|
||||||
|
case 'NRF':
|
||||||
|
state.from.sbi.nrf_ip = item.ip;
|
||||||
|
break;
|
||||||
|
case 'UPF':
|
||||||
|
state.from.sbi.upf_ip = item.ip;
|
||||||
|
state.hasNE.upf = true;
|
||||||
|
break;
|
||||||
|
case 'LMF':
|
||||||
|
state.from.sbi.lmf_ip = item.ip;
|
||||||
|
break;
|
||||||
|
case 'NEF':
|
||||||
|
state.from.sbi.nef_ip = item.ip;
|
||||||
|
break;
|
||||||
|
case 'MME':
|
||||||
|
state.from.sbi.mme_ip = item.ip;
|
||||||
|
if (item.ip.includes('.')) {
|
||||||
|
state.from.external.mmes11_ip = item.ip + '/24';
|
||||||
|
}
|
||||||
|
state.hasNE.mme = true;
|
||||||
|
break;
|
||||||
|
case 'N3IWF':
|
||||||
|
state.from.sbi.n3iwf_ip = item.ip;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.confirmLoading = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**保存数据 */
|
||||||
|
async function fnSaveData() {
|
||||||
|
if (state.confirmLoading) return;
|
||||||
|
state.confirmLoading = true;
|
||||||
|
const res = await savePara5GFile({
|
||||||
|
content: toRaw(state.from),
|
||||||
|
syncNe: [],
|
||||||
|
});
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
|
// 更新omc_ip
|
||||||
|
if (state.omcInfo.id) {
|
||||||
|
state.omcInfo.ip = state.from.sbi.omc_ip;
|
||||||
|
await updateNeInfo(toRaw(state.omcInfo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.confirmLoading = false;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
state,
|
||||||
|
fnReloadData,
|
||||||
|
fnSaveData,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,4 +1,10 @@
|
|||||||
import { reactive } from 'vue';
|
import {
|
||||||
|
defineAsyncComponent,
|
||||||
|
onMounted,
|
||||||
|
reactive,
|
||||||
|
shallowRef,
|
||||||
|
watch,
|
||||||
|
} from 'vue';
|
||||||
|
|
||||||
/**步骤信息状态类型 */
|
/**步骤信息状态类型 */
|
||||||
type StepStateType = {
|
type StepStateType = {
|
||||||
@@ -16,7 +22,7 @@ type StepStateType = {
|
|||||||
|
|
||||||
/**步骤信息状态 */
|
/**步骤信息状态 */
|
||||||
export const stepState: StepStateType = reactive({
|
export const stepState: StepStateType = reactive({
|
||||||
stepName: 'Start',
|
stepName: 'Para5G',
|
||||||
steps: [
|
steps: [
|
||||||
{
|
{
|
||||||
title: '服务器环境',
|
title: '服务器环境',
|
||||||
@@ -35,15 +41,15 @@ export const stepState: StepStateType = reactive({
|
|||||||
description: '网元服务授权激活',
|
description: '网元服务授权激活',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
current: 0,
|
current: -1,
|
||||||
neHost: {},
|
neHost: {},
|
||||||
neInfo: {},
|
neInfo: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
/**步骤信息状态复位 */
|
/**步骤信息状态复位 */
|
||||||
export function fnRestStepState(t?: any) {
|
export function fnRestStepState(t?: any) {
|
||||||
stepState.stepName = 'Start';
|
stepState.stepName = 'Para5G';
|
||||||
stepState.current = 0;
|
stepState.current = -1;
|
||||||
stepState.neHost = {};
|
stepState.neHost = {};
|
||||||
stepState.neInfo = {};
|
stepState.neInfo = {};
|
||||||
// 多语言翻译
|
// 多语言翻译
|
||||||
@@ -80,3 +86,26 @@ export function fnToStepName(stepName: string) {
|
|||||||
|
|
||||||
stepState.stepName = stepName;
|
stepState.stepName = stepName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useStep({ t }: any) {
|
||||||
|
// 异步加载组件
|
||||||
|
const Start = defineAsyncComponent(() => import('../components/Start.vue'));
|
||||||
|
|
||||||
|
// 当前组件
|
||||||
|
const currentComponent = shallowRef(Start);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => stepState.stepName,
|
||||||
|
v => {
|
||||||
|
const loadComponent = defineAsyncComponent(
|
||||||
|
() => import(`../components/${v}.vue`)
|
||||||
|
);
|
||||||
|
currentComponent.value = loadComponent;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fnRestStepState(t);
|
||||||
|
});
|
||||||
|
return { currentComponent };
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,34 +1,71 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { PageContainer } from 'antdv-pro-layout';
|
import { PageContainer } from 'antdv-pro-layout';
|
||||||
import { defineAsyncComponent, watch, shallowRef, onMounted } from 'vue';
|
import Para5GForm from './components/Para5GForm.vue';
|
||||||
import { stepState, fnRestStepState } from './hooks/useStep';
|
import {
|
||||||
|
stepState,
|
||||||
|
fnToStepName,
|
||||||
|
fnRestStepState,
|
||||||
|
useStep,
|
||||||
|
} from './hooks/useStep';
|
||||||
|
import { usePara5G } from './hooks/usePara5G';
|
||||||
import useI18n from '@/hooks/useI18n';
|
import useI18n from '@/hooks/useI18n';
|
||||||
|
import { onMounted, onUnmounted, watch } from 'vue';
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const { currentComponent } = useStep(t);
|
||||||
// 异步加载组件
|
const { state, fnReloadData, fnSaveData } = usePara5G();
|
||||||
const Start = defineAsyncComponent(() => import('./components/Start.vue'));
|
|
||||||
|
|
||||||
// 当前组件
|
|
||||||
const currentComponent = shallowRef(Start);
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => stepState.stepName,
|
() => stepState.stepName,
|
||||||
v => {
|
v => {
|
||||||
const loadComponent = defineAsyncComponent(
|
if (v === 'Para5G') {
|
||||||
() => import(`./components/${v}.vue`)
|
fnReloadData();
|
||||||
);
|
}
|
||||||
currentComponent.value = loadComponent;
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
fnReloadData();
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
fnRestStepState(t);
|
fnRestStepState(t);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**公共参数保存前下一步进行网元安装 */
|
||||||
|
function fnNext() {
|
||||||
|
fnSaveData().then(() => {
|
||||||
|
fnToStepName('Start');
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<PageContainer>
|
<PageContainer>
|
||||||
<a-card :bordered="false">
|
<a-card :bordered="false" v-if="stepState.stepName === 'Para5G'">
|
||||||
|
<!-- 公共参数表单 -->
|
||||||
|
<Para5GForm v-model:data="state.from" :ne="state.hasNE"></Para5GForm>
|
||||||
|
|
||||||
|
<div style="padding: 24px 12px 0; text-align: end">
|
||||||
|
<a-space :size="8" align="center">
|
||||||
|
<a-button
|
||||||
|
type="default"
|
||||||
|
:disabled="state.confirmLoading"
|
||||||
|
@click.prevent="fnReloadData()"
|
||||||
|
>
|
||||||
|
<template #icon><ReloadOutlined /></template>
|
||||||
|
{{ t('views.ne.neQuickSetup.reloadPara5G') }}
|
||||||
|
</a-button>
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
:loading="state.confirmLoading"
|
||||||
|
@click="fnNext()"
|
||||||
|
>
|
||||||
|
{{ t('views.ne.neQuickSetup.stepNext') }}
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
<a-card :bordered="false" v-else>
|
||||||
<!-- 插槽-卡片左侧 -->
|
<!-- 插槽-卡片左侧 -->
|
||||||
<template #title>
|
<template #title>
|
||||||
<!-- 步骤进度 -->
|
<!-- 步骤进度 -->
|
||||||
|
|||||||
@@ -91,6 +91,9 @@ async function fnModalOk() {
|
|||||||
if (expandFile['ADB']) {
|
if (expandFile['ADB']) {
|
||||||
pkgArr.push(expandFile['ADB']);
|
pkgArr.push(expandFile['ADB']);
|
||||||
}
|
}
|
||||||
|
if (expandFile['KVDB']) {
|
||||||
|
pkgArr.push(expandFile['KVDB']);
|
||||||
|
}
|
||||||
if (expandFile['RTPROXY']) {
|
if (expandFile['RTPROXY']) {
|
||||||
pkgArr.push(expandFile['RTPROXY']);
|
pkgArr.push(expandFile['RTPROXY']);
|
||||||
}
|
}
|
||||||
@@ -104,6 +107,8 @@ async function fnModalOk() {
|
|||||||
const udm = from.find(s => s.neType === 'UDM');
|
const udm = from.find(s => s.neType === 'UDM');
|
||||||
if (udm && expandFile['ADB']) {
|
if (udm && expandFile['ADB']) {
|
||||||
udm.path = [expandFile['ADB'], udm.path].join(',');
|
udm.path = [expandFile['ADB'], udm.path].join(',');
|
||||||
|
} else if (udm && expandFile['KVDB']) {
|
||||||
|
udm.path = [expandFile['KVDB'], udm.path].join(',');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 安装带依赖包-指定网元时
|
// 安装带依赖包-指定网元时
|
||||||
|
|||||||
@@ -294,8 +294,7 @@ function fnRecordVersion(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (row.newVersion === row.version) {
|
if (row.newVersion === row.version) {
|
||||||
message.warning(t('views.ne.neVersion.upgradeTipEqual'), 3);
|
contentTip = t('views.ne.neVersion.upgradeTipEqual');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (action === 'rollback') {
|
if (action === 'rollback') {
|
||||||
@@ -305,8 +304,7 @@ function fnRecordVersion(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (row.preVersion === row.version) {
|
if (row.preVersion === row.version) {
|
||||||
message.warning(t('views.ne.neVersion.rollbackTipEqual'), 3);
|
contentTip = t('views.ne.neVersion.rollbackTipEqual');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -194,8 +194,6 @@ type ModalStateType = {
|
|||||||
/**表单数据 */
|
/**表单数据 */
|
||||||
from: Record<string, any>;
|
from: Record<string, any>;
|
||||||
/**表单数据 */
|
/**表单数据 */
|
||||||
BatchForm: Record<string, any>;
|
|
||||||
/**表单数据 */
|
|
||||||
BatchDelForm: Record<string, any>;
|
BatchDelForm: Record<string, any>;
|
||||||
/**确定按钮 loading */
|
/**确定按钮 loading */
|
||||||
confirmLoading: boolean;
|
confirmLoading: boolean;
|
||||||
@@ -210,15 +208,8 @@ let modalState: ModalStateType = reactive({
|
|||||||
visibleByBatchDel: false,
|
visibleByBatchDel: false,
|
||||||
title: 'UDM鉴权用户',
|
title: 'UDM鉴权用户',
|
||||||
from: {
|
from: {
|
||||||
id: '',
|
|
||||||
imsi: '',
|
|
||||||
amf: '8000',
|
|
||||||
ki: '',
|
|
||||||
algoIndex: 0,
|
|
||||||
opc: '',
|
|
||||||
},
|
|
||||||
BatchForm: {
|
|
||||||
num: 1,
|
num: 1,
|
||||||
|
id: '',
|
||||||
imsi: '',
|
imsi: '',
|
||||||
amf: '8000',
|
amf: '8000',
|
||||||
ki: '',
|
ki: '',
|
||||||
@@ -236,19 +227,6 @@ let modalState: ModalStateType = reactive({
|
|||||||
/**对话框内表单属性和校验规则 */
|
/**对话框内表单属性和校验规则 */
|
||||||
const modalStateFrom = Form.useForm(
|
const modalStateFrom = Form.useForm(
|
||||||
modalState.from,
|
modalState.from,
|
||||||
reactive({
|
|
||||||
imsi: [{ required: true, message: 'IMSI' + t('common.unableNull') }],
|
|
||||||
amf: [{ required: true, message: 'AMF' + t('common.unableNull') }],
|
|
||||||
ki: [{ required: true, message: 'KI' + t('common.unableNull') }],
|
|
||||||
algoIndex: [
|
|
||||||
{ required: true, message: 'algoIndex' + t('common.unableNull') },
|
|
||||||
],
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
/**对话框内批量添加表单属性和校验规则 */
|
|
||||||
const modalStateBatchFrom = Form.useForm(
|
|
||||||
modalState.BatchForm,
|
|
||||||
reactive({
|
reactive({
|
||||||
num: [
|
num: [
|
||||||
{
|
{
|
||||||
@@ -256,9 +234,15 @@ const modalStateBatchFrom = Form.useForm(
|
|||||||
message: t('views.neUser.auth.numAdd') + t('common.unableNull'),
|
message: t('views.neUser.auth.numAdd') + t('common.unableNull'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
imsi: [{ required: true, message: 'IMSI' + t('common.unableNull') }],
|
imsi: [
|
||||||
|
{ required: true, message: 'IMSI' + t('common.unableNull') },
|
||||||
|
{ min: 15, max: 15, message: t('views.neUser.auth.imsiConfirm') },
|
||||||
|
],
|
||||||
amf: [{ required: true, message: 'AMF' + t('common.unableNull') }],
|
amf: [{ required: true, message: 'AMF' + t('common.unableNull') }],
|
||||||
ki: [{ required: true, message: 'KI' + t('common.unableNull') }],
|
ki: [
|
||||||
|
{ required: true, message: 'KI' + t('common.unableNull') },
|
||||||
|
{ min: 32, max: 32, message: t('views.neUser.auth.kiTip') },
|
||||||
|
],
|
||||||
algoIndex: [
|
algoIndex: [
|
||||||
{ required: true, message: 'algoIndex' + t('common.unableNull') },
|
{ required: true, message: 'algoIndex' + t('common.unableNull') },
|
||||||
],
|
],
|
||||||
@@ -312,21 +296,14 @@ function fnModalVisibleByEdit(row?: Record<string, any>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对话框弹出显示为 批量新增,批量删除
|
* 对话框弹出显示为 批量删除
|
||||||
* @param noticeId 网元id, 不传为新增
|
* @param noticeId 网元id, 不传为新增
|
||||||
*/
|
*/
|
||||||
function fnModalVisibleByBatch(batchFlag?: number) {
|
function fnModalVisibleByBatch() {
|
||||||
if (batchFlag) {
|
modalStateBatchDelFrom.resetFields(); //重置表单
|
||||||
modalStateBatchFrom.resetFields(); //重置表单
|
|
||||||
modalState.title =
|
|
||||||
t('views.neUser.auth.batchAddText') + t('views.neUser.auth.authInfo');
|
|
||||||
modalState.visibleByBatch = true;
|
|
||||||
} else {
|
|
||||||
modalStateBatchFrom.resetFields(); //重置表单
|
|
||||||
modalState.title =
|
modalState.title =
|
||||||
t('views.neUser.auth.batchDelText') + t('views.neUser.auth.authInfo');
|
t('views.neUser.auth.batchDelText') + t('views.neUser.auth.authInfo');
|
||||||
modalState.visibleByBatchDel = true;
|
modalState.visibleByBatchDel = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -341,50 +318,24 @@ function fnModalOk() {
|
|||||||
const from = toRaw(modalState.from);
|
const from = toRaw(modalState.from);
|
||||||
from.neId = queryParams.neId || '-';
|
from.neId = queryParams.neId || '-';
|
||||||
from.algoIndex = `${from.algoIndex}`;
|
from.algoIndex = `${from.algoIndex}`;
|
||||||
const result = from.id ? updateUDMAuth(from) : addUDMAuth(from);
|
const result = from.id
|
||||||
|
? updateUDMAuth(from)
|
||||||
|
: from.num === 1
|
||||||
|
? addUDMAuth(from)
|
||||||
|
: batchAddUDMAuth(from, from.num);
|
||||||
const hide = message.loading(t('common.loading'), 0);
|
const hide = message.loading(t('common.loading'), 0);
|
||||||
result
|
result
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (res.code === RESULT_CODE_SUCCESS) {
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
|
if (from.num === 1) {
|
||||||
|
//新增时
|
||||||
message.success({
|
message.success({
|
||||||
content: t('common.msgSuccess', { msg: modalState.title }),
|
content: t('common.msgSuccess', { msg: modalState.title }),
|
||||||
duration: 3,
|
duration: 3,
|
||||||
});
|
});
|
||||||
modalState.visibleByEdit = false;
|
|
||||||
modalStateFrom.resetFields();
|
|
||||||
fnGetList();
|
fnGetList();
|
||||||
} else {
|
} else {
|
||||||
message.error({
|
//批量新增时
|
||||||
content: `${res.msg}`,
|
|
||||||
duration: 3,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
hide();
|
|
||||||
modalState.confirmLoading = false;
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
message.error(t('common.errorFields', { num: e.errorFields.length }), 3);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对话框弹出 批量新增操作确认执行函数
|
|
||||||
* 进行表达规则校验
|
|
||||||
*/
|
|
||||||
function fnBatchModalOk() {
|
|
||||||
modalStateBatchFrom
|
|
||||||
.validate()
|
|
||||||
.then(e => {
|
|
||||||
modalState.confirmLoading = true;
|
|
||||||
const from = toRaw(modalState.BatchForm);
|
|
||||||
from.neId = queryParams.neId || '-';
|
|
||||||
from.algoIndex = `${from.algoIndex}`;
|
|
||||||
const result = batchAddUDMAuth(from, from.num);
|
|
||||||
result.then(res => {
|
|
||||||
if (res.code === RESULT_CODE_SUCCESS) {
|
|
||||||
const timerS = Math.max(
|
const timerS = Math.max(
|
||||||
Math.ceil(+from.num / 500),
|
Math.ceil(+from.num / 500),
|
||||||
`${from.num}`.length
|
`${from.num}`.length
|
||||||
@@ -395,19 +346,29 @@ function fnBatchModalOk() {
|
|||||||
duration: timerS,
|
duration: timerS,
|
||||||
});
|
});
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
modalState.confirmLoading = false;
|
|
||||||
modalState.visibleByBatch = false;
|
|
||||||
modalStateBatchFrom.resetFields();
|
|
||||||
fnGetList(1);
|
fnGetList(1);
|
||||||
}, timerS * 1000);
|
}, timerS * 1000);
|
||||||
|
}
|
||||||
|
modalState.visibleByEdit = false;
|
||||||
|
modalStateFrom.resetFields();
|
||||||
|
} else {
|
||||||
|
if (from.num === 1) {
|
||||||
|
message.error({
|
||||||
|
content: `${res.msg}`,
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
modalState.confirmLoading = false;
|
|
||||||
notification.error({
|
notification.error({
|
||||||
message: modalState.title,
|
message: modalState.title,
|
||||||
description: res.msg,
|
description: res.msg,
|
||||||
duration: 3,
|
duration: 3,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hide();
|
||||||
|
modalState.confirmLoading = false;
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
@@ -455,15 +416,6 @@ function fnBatchDelModalOk() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量添加对话框弹出关闭执行函数
|
|
||||||
* 进行表达规则校验
|
|
||||||
*/
|
|
||||||
function fnBatchModalCancel() {
|
|
||||||
modalState.visibleByBatch = false;
|
|
||||||
modalStateBatchFrom.resetFields();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量删除对话框弹出关闭执行函数
|
* 批量删除对话框弹出关闭执行函数
|
||||||
* 进行表达规则校验
|
* 进行表达规则校验
|
||||||
@@ -530,7 +482,7 @@ function fnRecordDelete(imsi: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UDM鉴权用户导出
|
* UDM鉴权用户勾选导出
|
||||||
*/
|
*/
|
||||||
function fnRecordExport(type: string = 'txt') {
|
function fnRecordExport(type: string = 'txt') {
|
||||||
const selectLen = tableState.selectedRowKeys.length;
|
const selectLen = tableState.selectedRowKeys.length;
|
||||||
@@ -543,13 +495,15 @@ function fnRecordExport(type: string = 'txt') {
|
|||||||
let content = '';
|
let content = '';
|
||||||
if (type == 'txt') {
|
if (type == 'txt') {
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
content += `${row.imsi},${row.ki},${row.algoIndex},${row.amf},${row.opc}\r\n`;
|
const opc = row.opc === '-' ? '' : `,${row.opc}`;
|
||||||
|
content += `${row.imsi},${row.ki},${row.algoIndex},${row.amf}${opc}\r\n`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (type == 'csv') {
|
if (type == 'csv') {
|
||||||
content = `IMSI,ki,Algo Index,AMF,OPC\r\n`;
|
content = `IMSI,ki,Algo Index,AMF,OPC\r\n`;
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
content += `${row.imsi},${row.ki},${row.algoIndex},${row.amf},${row.opc}\r\n`;
|
const opc = row.opc === '-' ? '' : `,${row.opc}`;
|
||||||
|
content += `${row.imsi},${row.ki},${row.algoIndex},${row.amf}${opc}\r\n`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -557,7 +511,7 @@ function fnRecordExport(type: string = 'txt') {
|
|||||||
saveAs(blob, `UDMAuth_${Date.now()}.${type}`);
|
saveAs(blob, `UDMAuth_${Date.now()}.${type}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**列表导出 */
|
/**列表导出全部数据 */
|
||||||
function fnExportList(type: string) {
|
function fnExportList(type: string) {
|
||||||
const neId = queryParams.neId;
|
const neId = queryParams.neId;
|
||||||
if (!neId) return;
|
if (!neId) return;
|
||||||
@@ -651,6 +605,10 @@ type ModalUploadImportStateType = {
|
|||||||
loading: boolean;
|
loading: boolean;
|
||||||
/**上传结果信息 */
|
/**上传结果信息 */
|
||||||
msg: string;
|
msg: string;
|
||||||
|
/**导入类型 */
|
||||||
|
typeOptions: { label: string; value: string }[];
|
||||||
|
/**表单 */
|
||||||
|
from: { typeVal: string; typeData: any };
|
||||||
};
|
};
|
||||||
|
|
||||||
/**对话框表格信息导入对象信息状态 */
|
/**对话框表格信息导入对象信息状态 */
|
||||||
@@ -659,11 +617,27 @@ let uploadImportState: ModalUploadImportStateType = reactive({
|
|||||||
title: t('components.UploadModal.uploadTitle'),
|
title: t('components.UploadModal.uploadTitle'),
|
||||||
loading: false,
|
loading: false,
|
||||||
msg: '',
|
msg: '',
|
||||||
|
typeOptions: [
|
||||||
|
{ label: 'Default', value: 'default' },
|
||||||
|
{ label: 'K4', value: 'k4' },
|
||||||
|
],
|
||||||
|
from: {
|
||||||
|
typeVal: 'default',
|
||||||
|
typeData: undefined,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**对话框表格信息导入类型选择 */
|
||||||
|
function fnModalUploadImportTypeChange() {
|
||||||
|
uploadImportState.from.typeData = '';
|
||||||
|
uploadImportState.msg = '';
|
||||||
|
}
|
||||||
|
|
||||||
/**对话框表格信息导入弹出窗口 */
|
/**对话框表格信息导入弹出窗口 */
|
||||||
function fnModalUploadImportOpen() {
|
function fnModalUploadImportOpen() {
|
||||||
uploadImportState.msg = '';
|
uploadImportState.msg = '';
|
||||||
|
uploadImportState.from.typeVal = 'default';
|
||||||
|
uploadImportState.from.typeData = undefined;
|
||||||
uploadImportState.loading = false;
|
uploadImportState.loading = false;
|
||||||
uploadImportState.visible = true;
|
uploadImportState.visible = true;
|
||||||
}
|
}
|
||||||
@@ -702,6 +676,7 @@ function fnModalUploadImportUpload(file: File) {
|
|||||||
return importUDMAuth({
|
return importUDMAuth({
|
||||||
neId: neId,
|
neId: neId,
|
||||||
uploadPath: filePath,
|
uploadPath: filePath,
|
||||||
|
...uploadImportState.from,
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
@@ -770,6 +745,7 @@ onMounted(() => {
|
|||||||
<a-input
|
<a-input
|
||||||
v-model:value="queryParams.imsi"
|
v-model:value="queryParams.imsi"
|
||||||
allow-clear
|
allow-clear
|
||||||
|
:maxlength="15"
|
||||||
:placeholder="t('common.inputPlease')"
|
:placeholder="t('common.inputPlease')"
|
||||||
></a-input>
|
></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
@@ -807,29 +783,11 @@ onMounted(() => {
|
|||||||
{{ t('common.addText') }}
|
{{ t('common.addText') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
|
|
||||||
<a-button type="primary" @click.prevent="fnModalVisibleByBatch(1)">
|
|
||||||
<template #icon>
|
|
||||||
<PlusOutlined />
|
|
||||||
</template>
|
|
||||||
{{ t('views.neUser.auth.batchAddText') }}
|
|
||||||
</a-button>
|
|
||||||
|
|
||||||
<a-button
|
|
||||||
type="default"
|
|
||||||
danger
|
|
||||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
|
||||||
:loading="modalState.loadDataLoading"
|
|
||||||
@click.prevent="fnRecordDelete('0')"
|
|
||||||
>
|
|
||||||
<template #icon><DeleteOutlined /></template>
|
|
||||||
{{ t('views.neUser.auth.checkDel') }}
|
|
||||||
</a-button>
|
|
||||||
|
|
||||||
<a-button
|
<a-button
|
||||||
type="primary"
|
type="primary"
|
||||||
danger
|
danger
|
||||||
ghost
|
ghost
|
||||||
@click.prevent="fnModalVisibleByBatch(0)"
|
@click.prevent="fnModalVisibleByBatch()"
|
||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<DeleteOutlined />
|
<DeleteOutlined />
|
||||||
@@ -876,6 +834,17 @@ onMounted(() => {
|
|||||||
</a-button>
|
</a-button>
|
||||||
</a-popconfirm>
|
</a-popconfirm>
|
||||||
|
|
||||||
|
<a-button
|
||||||
|
type="default"
|
||||||
|
danger
|
||||||
|
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||||
|
:loading="modalState.loadDataLoading"
|
||||||
|
@click.prevent="fnRecordDelete('0')"
|
||||||
|
>
|
||||||
|
<template #icon><DeleteOutlined /></template>
|
||||||
|
{{ t('views.neUser.auth.checkDel') }}
|
||||||
|
</a-button>
|
||||||
|
|
||||||
<a-popconfirm
|
<a-popconfirm
|
||||||
:title="t('views.neUser.auth.checkExportConfirm')"
|
:title="t('views.neUser.auth.checkExportConfirm')"
|
||||||
placement="topRight"
|
placement="topRight"
|
||||||
@@ -1016,6 +985,24 @@ onMounted(() => {
|
|||||||
:label-col="{ span: 6 }"
|
:label-col="{ span: 6 }"
|
||||||
:labelWrap="true"
|
:labelWrap="true"
|
||||||
>
|
>
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item
|
||||||
|
:label="t('views.neUser.auth.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 :gutter="16">
|
<a-row :gutter="16">
|
||||||
<a-col :lg="12" :md="12" :xs="24">
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
@@ -1026,6 +1013,7 @@ onMounted(() => {
|
|||||||
<a-input
|
<a-input
|
||||||
v-model:value="modalState.from.imsi"
|
v-model:value="modalState.from.imsi"
|
||||||
allow-clear
|
allow-clear
|
||||||
|
:maxlength="15"
|
||||||
:disabled="!!modalState.from.id"
|
:disabled="!!modalState.from.id"
|
||||||
>
|
>
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
@@ -1101,12 +1089,12 @@ onMounted(() => {
|
|||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
|
|
||||||
<a-row :gutter="16">
|
|
||||||
<a-col :lg="12" :md="12" :xs="24">
|
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="KI"
|
label="KI"
|
||||||
name="ki"
|
name="ki"
|
||||||
v-bind="modalStateFrom.validateInfos.ki"
|
v-bind="modalStateFrom.validateInfos.ki"
|
||||||
|
:label-col="{ span: 3 }"
|
||||||
|
:labelWrap="true"
|
||||||
>
|
>
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="modalState.from.ki"
|
v-model:value="modalState.from.ki"
|
||||||
@@ -1124,12 +1112,12 @@ onMounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
</a-input>
|
</a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
|
||||||
<a-col :lg="12" :md="12" :xs="24">
|
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="OPC"
|
label="OPC"
|
||||||
name="opc"
|
name="opc"
|
||||||
v-bind="modalStateFrom.validateInfos.opc"
|
v-bind="modalStateFrom.validateInfos.opc"
|
||||||
|
:label-col="{ span: 3 }"
|
||||||
|
:labelWrap="true"
|
||||||
>
|
>
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="modalState.from.opc"
|
v-model:value="modalState.from.opc"
|
||||||
@@ -1147,175 +1135,6 @@ onMounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
</a-input>
|
</a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
</a-form>
|
|
||||||
</ProModal>
|
|
||||||
|
|
||||||
<!-- 批量新增框 -->
|
|
||||||
<ProModal
|
|
||||||
:drag="true"
|
|
||||||
:width="800"
|
|
||||||
:destroyOnClose="true"
|
|
||||||
:keyboard="false"
|
|
||||||
:mask-closable="false"
|
|
||||||
:visible="modalState.visibleByBatch"
|
|
||||||
:title="modalState.title"
|
|
||||||
:confirm-loading="modalState.confirmLoading"
|
|
||||||
@ok="fnBatchModalOk"
|
|
||||||
@cancel="fnBatchModalCancel"
|
|
||||||
>
|
|
||||||
<a-form
|
|
||||||
name="modalStateBatchFrom"
|
|
||||||
layout="horizontal"
|
|
||||||
:label-col="{ span: 6 }"
|
|
||||||
:labelWrap="true"
|
|
||||||
>
|
|
||||||
<a-row :gutter="16">
|
|
||||||
<a-col :lg="12" :md="12" :xs="24">
|
|
||||||
<a-form-item
|
|
||||||
:label="t('views.neUser.auth.numAdd')"
|
|
||||||
name="num"
|
|
||||||
v-bind="modalStateBatchFrom.validateInfos.num"
|
|
||||||
>
|
|
||||||
<a-input-number
|
|
||||||
v-model:value="modalState.BatchForm.num"
|
|
||||||
style="width: 100%"
|
|
||||||
:min="1"
|
|
||||||
:max="10000"
|
|
||||||
placeholder="<=10000"
|
|
||||||
></a-input-number>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
|
|
||||||
<a-row :gutter="16">
|
|
||||||
<a-col :lg="12" :md="12" :xs="24">
|
|
||||||
<a-form-item
|
|
||||||
label="IMSI"
|
|
||||||
name="imsi"
|
|
||||||
v-bind="modalStateBatchFrom.validateInfos.imsi"
|
|
||||||
>
|
|
||||||
<a-input v-model:value="modalState.BatchForm.imsi" allow-clear>
|
|
||||||
<template #prefix>
|
|
||||||
<a-tooltip placement="topLeft">
|
|
||||||
<template #title>
|
|
||||||
{{ t('views.neUser.auth.imsiTip') }}<br />
|
|
||||||
{{ t('views.neUser.auth.imsiTip1') }}<br />
|
|
||||||
{{ t('views.neUser.auth.imsiTip2') }}<br />
|
|
||||||
{{ t('views.neUser.auth.imsiTip3') }}
|
|
||||||
</template>
|
|
||||||
<InfoCircleOutlined style="color: rgba(0, 0, 0, 0.45)" />
|
|
||||||
</a-tooltip>
|
|
||||||
</template>
|
|
||||||
</a-input>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
<a-col :lg="12" :md="12" :xs="24">
|
|
||||||
<a-form-item label="Status" name="status">
|
|
||||||
<a-select value="1">
|
|
||||||
<a-select-option value="1">Active</a-select-option>
|
|
||||||
<a-select-option value="0">Inactive</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
|
|
||||||
<a-row :gutter="16">
|
|
||||||
<a-col :lg="12" :md="12" :xs="24">
|
|
||||||
<a-form-item
|
|
||||||
label="AMF"
|
|
||||||
name="amf"
|
|
||||||
v-bind="modalStateBatchFrom.validateInfos.amf"
|
|
||||||
>
|
|
||||||
<a-input
|
|
||||||
v-model:value="modalState.BatchForm.amf"
|
|
||||||
allow-clear
|
|
||||||
:maxlength="4"
|
|
||||||
>
|
|
||||||
<template #prefix>
|
|
||||||
<a-tooltip placement="topLeft">
|
|
||||||
<template #title>
|
|
||||||
{{ t('views.neUser.auth.amfTip') }}
|
|
||||||
</template>
|
|
||||||
<InfoCircleOutlined style="color: rgba(0, 0, 0, 0.45)" />
|
|
||||||
</a-tooltip>
|
|
||||||
</template>
|
|
||||||
</a-input>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
<a-col :lg="12" :md="12" :xs="24">
|
|
||||||
<a-form-item
|
|
||||||
label="Algo Index"
|
|
||||||
name="algo"
|
|
||||||
v-bind="modalStateBatchFrom.validateInfos.algoIndex"
|
|
||||||
>
|
|
||||||
<a-input-number
|
|
||||||
v-model:value="modalState.BatchForm.algoIndex"
|
|
||||||
style="width: 100%"
|
|
||||||
:min="0"
|
|
||||||
:max="15"
|
|
||||||
placeholder="0 ~ 15"
|
|
||||||
>
|
|
||||||
<template #prefix>
|
|
||||||
<a-tooltip placement="topLeft">
|
|
||||||
<template #title>
|
|
||||||
{{ t('views.neUser.auth.algoIndexTip') }}
|
|
||||||
</template>
|
|
||||||
<InfoCircleOutlined style="color: rgba(0, 0, 0, 0.45)" />
|
|
||||||
</a-tooltip>
|
|
||||||
</template>
|
|
||||||
</a-input-number>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
|
|
||||||
<a-row :gutter="16">
|
|
||||||
<a-col :lg="12" :md="12" :xs="24">
|
|
||||||
<a-form-item
|
|
||||||
label="KI"
|
|
||||||
name="ki"
|
|
||||||
v-bind="modalStateBatchFrom.validateInfos.ki"
|
|
||||||
>
|
|
||||||
<a-input
|
|
||||||
v-model:value="modalState.BatchForm.ki"
|
|
||||||
allow-clear
|
|
||||||
:maxlength="32"
|
|
||||||
>
|
|
||||||
<template #prefix>
|
|
||||||
<a-tooltip placement="topLeft">
|
|
||||||
<template #title>
|
|
||||||
{{ t('views.neUser.auth.kiTip') }}
|
|
||||||
</template>
|
|
||||||
<InfoCircleOutlined style="color: rgba(0, 0, 0, 0.45)" />
|
|
||||||
</a-tooltip>
|
|
||||||
</template>
|
|
||||||
</a-input>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
<a-col :lg="12" :md="12" :xs="24">
|
|
||||||
<a-form-item
|
|
||||||
label="OPC"
|
|
||||||
name="opc"
|
|
||||||
v-bind="modalStateBatchFrom.validateInfos.opc"
|
|
||||||
>
|
|
||||||
<a-input
|
|
||||||
v-model:value="modalState.BatchForm.opc"
|
|
||||||
allow-clear
|
|
||||||
:maxlength="32"
|
|
||||||
>
|
|
||||||
<template #prefix>
|
|
||||||
<a-tooltip placement="topLeft">
|
|
||||||
<template #title>
|
|
||||||
{{ t('views.neUser.auth.opcTip') }}
|
|
||||||
</template>
|
|
||||||
<InfoCircleOutlined style="color: rgba(0, 0, 0, 0.45)" />
|
|
||||||
</a-tooltip>
|
|
||||||
</template>
|
|
||||||
</a-input>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
</a-form>
|
</a-form>
|
||||||
</ProModal>
|
</ProModal>
|
||||||
|
|
||||||
@@ -1344,7 +1163,11 @@ onMounted(() => {
|
|||||||
name="imsi"
|
name="imsi"
|
||||||
v-bind="modalStateBatchDelFrom.validateInfos.imsi"
|
v-bind="modalStateBatchDelFrom.validateInfos.imsi"
|
||||||
>
|
>
|
||||||
<a-input v-model:value="modalState.BatchDelForm.imsi" allow-clear>
|
<a-input
|
||||||
|
v-model:value="modalState.BatchDelForm.imsi"
|
||||||
|
allow-clear
|
||||||
|
:maxlength="15"
|
||||||
|
>
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<a-tooltip placement="topLeft">
|
<a-tooltip placement="topLeft">
|
||||||
<template #title>
|
<template #title>
|
||||||
@@ -1389,6 +1212,16 @@ onMounted(() => {
|
|||||||
:size="10"
|
:size="10"
|
||||||
>
|
>
|
||||||
<template #default>
|
<template #default>
|
||||||
|
<a-radio-group
|
||||||
|
v-model:value="uploadImportState.from.typeVal"
|
||||||
|
:options="uploadImportState.typeOptions"
|
||||||
|
@change="fnModalUploadImportTypeChange"
|
||||||
|
/>
|
||||||
|
<a-input-password
|
||||||
|
v-if="uploadImportState.from.typeVal === 'k4'"
|
||||||
|
v-model:value="uploadImportState.from.typeData"
|
||||||
|
:placeholder="t('common.inputPlease')"
|
||||||
|
/>
|
||||||
<a-textarea
|
<a-textarea
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
:hidden="!uploadImportState.msg"
|
:hidden="!uploadImportState.msg"
|
||||||
|
|||||||
@@ -74,6 +74,15 @@ let tableColumns = ref<TableColumnsType>([
|
|||||||
align: 'center',
|
align: 'center',
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'NE Name',
|
||||||
|
dataIndex: 'neName',
|
||||||
|
align: 'left',
|
||||||
|
resizable: true,
|
||||||
|
width: 200,
|
||||||
|
minWidth: 150,
|
||||||
|
maxWidth: 400,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'UE Number',
|
title: 'UE Number',
|
||||||
dataIndex: 'ueNum',
|
dataIndex: 'ueNum',
|
||||||
@@ -89,6 +98,7 @@ let tableColumns = ref<TableColumnsType>([
|
|||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
maxWidth: 400,
|
maxWidth: 400,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
title: 'Radio Address',
|
title: 'Radio Address',
|
||||||
dataIndex: 'address',
|
dataIndex: 'address',
|
||||||
@@ -129,6 +139,7 @@ function fnTableSize({ key }: MenuInfo) {
|
|||||||
tableState.size = key as SizeType;
|
tableState.size = key as SizeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let promises = ref<any[]>([]);
|
||||||
/**查询列表, pageNum初始页数 */
|
/**查询列表, pageNum初始页数 */
|
||||||
function fnGetList(pageNum?: number) {
|
function fnGetList(pageNum?: number) {
|
||||||
if (tableState.loading) return;
|
if (tableState.loading) return;
|
||||||
@@ -136,6 +147,63 @@ function fnGetList(pageNum?: number) {
|
|||||||
if (pageNum) {
|
if (pageNum) {
|
||||||
queryParams.pageNum = pageNum;
|
queryParams.pageNum = pageNum;
|
||||||
}
|
}
|
||||||
|
if (!queryParams.neType) {
|
||||||
|
tableState.data = [];
|
||||||
|
promises.value = [];
|
||||||
|
//同时获取45G基站信息 且在每条信息中添加45G字段(原始数据没有) 已经筛选后的
|
||||||
|
neCascaderOptions.value.map((item: any) => {
|
||||||
|
item.children.forEach((child: any) => {
|
||||||
|
promises.value.push(
|
||||||
|
listBase5G({
|
||||||
|
neId: child.neId,
|
||||||
|
neType: child.neType,
|
||||||
|
nbId: queryParams.id,
|
||||||
|
pageNum: queryParams.pageNum,
|
||||||
|
pageSize: 10000,
|
||||||
|
}).then(res => {
|
||||||
|
// 添加 neName 字段到每一项数据
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
|
||||||
|
res.rows.forEach(row => {
|
||||||
|
row.neName = `${child.neType}_${child.neId}`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Promise.allSettled(promises.value).then(results => {
|
||||||
|
results.forEach(result => {
|
||||||
|
if (result.status === 'fulfilled') {
|
||||||
|
const allBaseData = result.value;
|
||||||
|
if (
|
||||||
|
allBaseData.code === RESULT_CODE_SUCCESS &&
|
||||||
|
Array.isArray(allBaseData.rows)
|
||||||
|
) {
|
||||||
|
// 处理成功结果
|
||||||
|
tablePagination.total += allBaseData.total;
|
||||||
|
tableState.data = [...tableState.data, ...allBaseData.rows];
|
||||||
|
if (
|
||||||
|
tablePagination.total <=
|
||||||
|
(queryParams.pageNum - 1) * tablePagination.pageSize &&
|
||||||
|
queryParams.pageNum !== 1
|
||||||
|
) {
|
||||||
|
tableState.loading = false;
|
||||||
|
fnGetList(queryParams.pageNum - 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//AMF返回404是代表没找到这个数据 GNB_NOT_FOUND
|
||||||
|
tablePagination.total = 0;
|
||||||
|
tableState.data = [];
|
||||||
|
}
|
||||||
|
tableState.loading = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let toBack: Record<string, any> = {
|
let toBack: Record<string, any> = {
|
||||||
neType: queryParams.neType[0],
|
neType: queryParams.neType[0],
|
||||||
@@ -152,6 +220,11 @@ function fnGetList(pageNum?: number) {
|
|||||||
}
|
}
|
||||||
tablePagination.total = res.total;
|
tablePagination.total = res.total;
|
||||||
tableState.data = res.rows;
|
tableState.data = res.rows;
|
||||||
|
|
||||||
|
res.rows.forEach((item: any) => {
|
||||||
|
item.neName = queryParams.neType.join('_');
|
||||||
|
});
|
||||||
|
|
||||||
if (
|
if (
|
||||||
tablePagination.total <=
|
tablePagination.total <=
|
||||||
(queryParams.pageNum - 1) * tablePagination.pageSize &&
|
(queryParams.pageNum - 1) * tablePagination.pageSize &&
|
||||||
@@ -160,7 +233,8 @@ function fnGetList(pageNum?: number) {
|
|||||||
tableState.loading = false;
|
tableState.loading = false;
|
||||||
fnGetList(queryParams.pageNum - 1);
|
fnGetList(queryParams.pageNum - 1);
|
||||||
}
|
}
|
||||||
} else {//AMF返回404是代表没找到这个数据 GNB_NOT_FOUND
|
} else {
|
||||||
|
//AMF返回404是代表没找到这个数据 GNB_NOT_FOUND
|
||||||
tablePagination.total = 0;
|
tablePagination.total = 0;
|
||||||
tableState.data = [];
|
tableState.data = [];
|
||||||
}
|
}
|
||||||
@@ -176,11 +250,19 @@ onMounted(() => {
|
|||||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||||
if (res.data.length > 0) {
|
if (res.data.length > 0) {
|
||||||
// 过滤不可用的网元
|
// 过滤不可用的网元
|
||||||
neCascaderOptions.value = neInfoStore.getNeCascaderOptions.filter(
|
for (const item of neInfoStore.getNeCascaderOptions) {
|
||||||
(item: any) => {
|
if (!['AMF', 'MME'].includes(item.value)) continue;
|
||||||
return ['AMF', 'MME'].includes(item.value);
|
const v = JSON.parse(JSON.stringify(item));
|
||||||
|
|
||||||
|
if (v.label === 'AMF') {
|
||||||
|
v.label = '5G';
|
||||||
}
|
}
|
||||||
);
|
if (v.label === 'MME') {
|
||||||
|
v.label = '4G';
|
||||||
|
}
|
||||||
|
neCascaderOptions.value.push(v);
|
||||||
|
}
|
||||||
|
|
||||||
if (neCascaderOptions.value.length === 0) {
|
if (neCascaderOptions.value.length === 0) {
|
||||||
message.warning({
|
message.warning({
|
||||||
content: t('common.noData'),
|
content: t('common.noData'),
|
||||||
@@ -188,8 +270,9 @@ onMounted(() => {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 无查询参数neType时 默认选择AMF
|
// 无查询参数neType时 默认选择AMF
|
||||||
const queryNeType = (route.query.neType as string) || 'AMF';
|
const queryNeType = (route.query.neType as string) || '5G';
|
||||||
const item = neCascaderOptions.value.find(
|
const item = neCascaderOptions.value.find(
|
||||||
s => s.value === queryNeType
|
s => s.value === queryNeType
|
||||||
);
|
);
|
||||||
@@ -230,7 +313,6 @@ onMounted(() => {
|
|||||||
<a-cascader
|
<a-cascader
|
||||||
v-model:value="queryParams.neType"
|
v-model:value="queryParams.neType"
|
||||||
:options="neCascaderOptions"
|
:options="neCascaderOptions"
|
||||||
:allow-clear="false"
|
|
||||||
:placeholder="t('common.selectPlease')"
|
:placeholder="t('common.selectPlease')"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ onMounted(() => {
|
|||||||
</a-col>
|
</a-col>
|
||||||
<a-col :lg="6" :md="12" :xs="24">
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
<a-form-item label="IMSI" name="imsi">
|
<a-form-item label="IMSI" name="imsi">
|
||||||
<a-input v-model:value="queryParams.imsi" allow-clear></a-input>
|
<a-input v-model:value="queryParams.imsi" allow-clear :maxlength="15"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :lg="6" :md="12" :xs="24">
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@ import { message } from 'ant-design-vue/lib';
|
|||||||
import { SizeType } from 'ant-design-vue/lib/config-provider';
|
import { SizeType } from 'ant-design-vue/lib/config-provider';
|
||||||
import { MenuInfo } from 'ant-design-vue/lib/menu/src/interface';
|
import { MenuInfo } from 'ant-design-vue/lib/menu/src/interface';
|
||||||
import { ColumnsType } from 'ant-design-vue/lib/table';
|
import { ColumnsType } from 'ant-design-vue/lib/table';
|
||||||
import { listUEInfoBySMF } from '@/api/neUser/smf';
|
import { listSMFSubscribers } from '@/api/neData/smf';
|
||||||
import useNeInfoStore from '@/store/modules/neinfo';
|
import useNeInfoStore from '@/store/modules/neinfo';
|
||||||
import useI18n from '@/hooks/useI18n';
|
import useI18n from '@/hooks/useI18n';
|
||||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
@@ -51,8 +51,6 @@ type TabeStateType = {
|
|||||||
seached: boolean;
|
seached: boolean;
|
||||||
/**记录数据 */
|
/**记录数据 */
|
||||||
data: object[];
|
data: object[];
|
||||||
/**勾选记录 */
|
|
||||||
selectedRowKeys: (string | number)[];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**表格状态 */
|
/**表格状态 */
|
||||||
@@ -61,7 +59,6 @@ let tableState: TabeStateType = reactive({
|
|||||||
size: 'middle',
|
size: 'middle',
|
||||||
seached: true,
|
seached: true,
|
||||||
data: [],
|
data: [],
|
||||||
selectedRowKeys: [],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**表格字段列 */
|
/**表格字段列 */
|
||||||
@@ -69,7 +66,7 @@ let tableColumns: ColumnsType = [
|
|||||||
{
|
{
|
||||||
title: 'IMSI',
|
title: 'IMSI',
|
||||||
dataIndex: 'imsi',
|
dataIndex: 'imsi',
|
||||||
align: 'center',
|
align: 'left',
|
||||||
sorter: (a: any, b: any) => Number(a.imsi) - Number(b.imsi),
|
sorter: (a: any, b: any) => Number(a.imsi) - Number(b.imsi),
|
||||||
customRender(opt) {
|
customRender(opt) {
|
||||||
const idx = opt.value.lastIndexOf('-');
|
const idx = opt.value.lastIndexOf('-');
|
||||||
@@ -83,7 +80,7 @@ let tableColumns: ColumnsType = [
|
|||||||
{
|
{
|
||||||
title: 'MSISDN',
|
title: 'MSISDN',
|
||||||
dataIndex: 'msisdn',
|
dataIndex: 'msisdn',
|
||||||
align: 'center',
|
align: 'left',
|
||||||
sorter: (a: any, b: any) => Number(a.msisdn) - Number(b.msisdn),
|
sorter: (a: any, b: any) => Number(a.msisdn) - Number(b.msisdn),
|
||||||
customRender(opt) {
|
customRender(opt) {
|
||||||
const idx = opt.value.lastIndexOf('-');
|
const idx = opt.value.lastIndexOf('-');
|
||||||
@@ -97,7 +94,7 @@ let tableColumns: ColumnsType = [
|
|||||||
{
|
{
|
||||||
title: 'RAT Type',
|
title: 'RAT Type',
|
||||||
dataIndex: 'ratType',
|
dataIndex: 'ratType',
|
||||||
align: 'center',
|
align: 'left',
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -116,12 +113,18 @@ let tableColumns: ColumnsType = [
|
|||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
width: 150,
|
width: 200,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('common.operate'),
|
title: t('common.operate'),
|
||||||
key: 'imsi',
|
key: 'imsi',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Remark',
|
||||||
|
dataIndex: 'remark',
|
||||||
|
align: 'left',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -220,12 +223,8 @@ function fnGetList(pageNum?: number) {
|
|||||||
if (pageNum) {
|
if (pageNum) {
|
||||||
queryParams.pageNum = pageNum;
|
queryParams.pageNum = pageNum;
|
||||||
}
|
}
|
||||||
listUEInfoBySMF(toRaw(queryParams)).then(res => {
|
listSMFSubscribers(toRaw(queryParams)).then(res => {
|
||||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
|
||||||
// 取消勾选
|
|
||||||
if (tableState.selectedRowKeys.length > 0) {
|
|
||||||
tableState.selectedRowKeys = [];
|
|
||||||
}
|
|
||||||
tablePagination.total = res.total;
|
tablePagination.total = res.total;
|
||||||
tableState.data = res.rows;
|
tableState.data = res.rows;
|
||||||
if (
|
if (
|
||||||
@@ -286,7 +285,7 @@ onMounted(() => {
|
|||||||
<!-- 表格搜索栏 -->
|
<!-- 表格搜索栏 -->
|
||||||
<a-form :model="queryParams" name="queryParams" layout="horizontal">
|
<a-form :model="queryParams" name="queryParams" layout="horizontal">
|
||||||
<a-row :gutter="16">
|
<a-row :gutter="16">
|
||||||
<a-col :lg="8" :md="12" :xs="24">
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
<a-form-item :label="t('views.neUser.ue.neType')" name="neId ">
|
<a-form-item :label="t('views.neUser.ue.neType')" name="neId ">
|
||||||
<a-select
|
<a-select
|
||||||
v-model:value="queryParams.neId"
|
v-model:value="queryParams.neId"
|
||||||
@@ -295,18 +294,17 @@ onMounted(() => {
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :lg="8" :md="12" :xs="24">
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
<a-form-item label="IMSI" name="imsi">
|
<a-form-item label="IMSI" name="imsi">
|
||||||
<a-input v-model:value="queryParams.imsi" allow-clear></a-input>
|
<a-input v-model:value="queryParams.imsi" allow-clear></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :lg="8" :md="12" :xs="24">
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
<a-form-item label="MSISDN" name="msisdn">
|
<a-form-item label="MSISDN" name="msisdn">
|
||||||
<a-input v-model:value="queryParams.msisdn" allow-clear></a-input>
|
<a-input v-model:value="queryParams.msisdn" allow-clear></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
<a-col :lg="8" :md="12" :xs="24">
|
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<a-space :size="8">
|
<a-space :size="8">
|
||||||
<a-button type="primary" @click.prevent="fnGetList(1)">
|
<a-button type="primary" @click.prevent="fnGetList(1)">
|
||||||
@@ -382,7 +380,7 @@ onMounted(() => {
|
|||||||
:data-source="tableState.data"
|
:data-source="tableState.data"
|
||||||
:size="tableState.size"
|
:size="tableState.size"
|
||||||
:pagination="tablePagination"
|
:pagination="tablePagination"
|
||||||
:scroll="{ x: 1000, y: 400 }"
|
:scroll="{ x: true, y: 400 }"
|
||||||
>
|
>
|
||||||
<template #bodyCell="{ column, record }">
|
<template #bodyCell="{ column, record }">
|
||||||
<template v-if="column.key === 'imsi'">
|
<template v-if="column.key === 'imsi'">
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import { MenuInfo } from 'ant-design-vue/lib/menu/src/interface';
|
|||||||
import { ColumnsType } from 'ant-design-vue/lib/table';
|
import { ColumnsType } from 'ant-design-vue/lib/table';
|
||||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
import useI18n from '@/hooks/useI18n';
|
import useI18n from '@/hooks/useI18n';
|
||||||
import useDictStore from '@/store/modules/dict';
|
|
||||||
import useNeInfoStore from '@/store/modules/neinfo';
|
import useNeInfoStore from '@/store/modules/neinfo';
|
||||||
|
import { parseObjLineToHump } from '@/utils/parse-utils';
|
||||||
import {
|
import {
|
||||||
addCustom,
|
addCustom,
|
||||||
delCustom,
|
delCustom,
|
||||||
@@ -16,15 +16,17 @@ import {
|
|||||||
listCustom,
|
listCustom,
|
||||||
updateCustom,
|
updateCustom,
|
||||||
} from '@/api/perfManage/customTarget';
|
} from '@/api/perfManage/customTarget';
|
||||||
const { getDict } = useDictStore();
|
import { getKPITitle } from '@/api/perfManage/goldTarget';
|
||||||
|
import useDictStore from '@/store/modules/dict';
|
||||||
const { t, currentLocale } = useI18n();
|
const { t, currentLocale } = useI18n();
|
||||||
|
const { getDict } = useDictStore();
|
||||||
|
|
||||||
/**字典数据 */
|
/**字典数据 */
|
||||||
let dict: {
|
let dict: {
|
||||||
/**原始严重程度 */
|
/**状态 */
|
||||||
activeAlarmSeverity: DictType[];
|
sysNormalDisable: DictType[];
|
||||||
} = reactive({
|
} = reactive({
|
||||||
activeAlarmSeverity: [],
|
sysNormalDisable: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
/**查询参数 */
|
/**查询参数 */
|
||||||
@@ -85,15 +87,22 @@ let tableColumns: ColumnsType = [
|
|||||||
align: 'center',
|
align: 'center',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('views.perfManage.customTarget.kpiSet'),
|
title: t('views.perfManage.customTarget.title'),
|
||||||
dataIndex: 'kpiSet',
|
dataIndex: 'title',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('views.perfManage.customTarget.period'),
|
title: t('views.perfManage.customTarget.description'),
|
||||||
dataIndex: 'threshold',
|
dataIndex: 'description',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: t('views.perfManage.customTarget.status'),
|
||||||
|
dataIndex: 'status',
|
||||||
|
key: 'status',
|
||||||
|
align: 'left',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: t('common.operate'),
|
title: t('common.operate'),
|
||||||
key: 'id',
|
key: 'id',
|
||||||
@@ -175,13 +184,14 @@ function fnGetList(pageNum?: number) {
|
|||||||
queryParams.pageNum = pageNum;
|
queryParams.pageNum = pageNum;
|
||||||
}
|
}
|
||||||
listCustom(toRaw(queryParams)).then(res => {
|
listCustom(toRaw(queryParams)).then(res => {
|
||||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||||
// 取消勾选
|
// 取消勾选
|
||||||
if (tableState.selectedRowKeys.length > 0) {
|
if (tableState.selectedRowKeys.length > 0) {
|
||||||
tableState.selectedRowKeys = [];
|
tableState.selectedRowKeys = [];
|
||||||
}
|
}
|
||||||
tablePagination.total = res.total;
|
tablePagination.total = res.total;
|
||||||
tableState.data = res.rows;
|
tableState.data = res.data;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
tablePagination.total <=
|
tablePagination.total <=
|
||||||
(queryParams.pageNum - 1) * tablePagination.pageSize &&
|
(queryParams.pageNum - 1) * tablePagination.pageSize &&
|
||||||
@@ -207,8 +217,6 @@ type ModalStateType = {
|
|||||||
neType: string[];
|
neType: string[];
|
||||||
/**网元类型性能测量集 */
|
/**网元类型性能测量集 */
|
||||||
neTypPerformance: Record<string, any>[];
|
neTypPerformance: Record<string, any>[];
|
||||||
/**网元类型对象类型集 */
|
|
||||||
objectTypeArr: Record<string, any>[];
|
|
||||||
/**已选择性能测量项 */
|
/**已选择性能测量项 */
|
||||||
selectedPre: string[];
|
selectedPre: string[];
|
||||||
/**表单数据 */
|
/**表单数据 */
|
||||||
@@ -224,21 +232,32 @@ let modalState: ModalStateType = reactive({
|
|||||||
title: '',
|
title: '',
|
||||||
neType: [],
|
neType: [],
|
||||||
neTypPerformance: [],
|
neTypPerformance: [],
|
||||||
objectTypeArr: [],
|
|
||||||
selectedPre: [],
|
selectedPre: [],
|
||||||
from: {
|
from: {
|
||||||
id: '',
|
id: undefined,
|
||||||
neType: '',
|
neType: 'UDM',
|
||||||
objectType: '',
|
|
||||||
expression: '',
|
|
||||||
kpiSet: '',
|
|
||||||
title: '',
|
|
||||||
kpiId: '',
|
kpiId: '',
|
||||||
period: 900,
|
title: '',
|
||||||
|
expression: '',
|
||||||
|
status: 'Active',
|
||||||
|
unit: '',
|
||||||
|
description: '',
|
||||||
},
|
},
|
||||||
confirmLoading: false,
|
confirmLoading: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**表单中多选的OPTION */
|
||||||
|
const modalStateFromOption = reactive({
|
||||||
|
symbolJson: [
|
||||||
|
{ label: '(', value: '(' },
|
||||||
|
{ label: ')', value: ')' },
|
||||||
|
{ label: '+', value: '+' },
|
||||||
|
{ label: '-', value: '-' },
|
||||||
|
{ label: '*', value: '*' },
|
||||||
|
{ label: '/', value: '/' },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
/**对话框内表单属性和校验规则 */
|
/**对话框内表单属性和校验规则 */
|
||||||
const modalStateFrom = Form.useForm(
|
const modalStateFrom = Form.useForm(
|
||||||
modalState.from,
|
modalState.from,
|
||||||
@@ -246,15 +265,7 @@ const modalStateFrom = Form.useForm(
|
|||||||
neType: [
|
neType: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: t('views.traceManage.task.neTypePlease'),
|
message: t('views.ne.common.neTypePlease'),
|
||||||
},
|
|
||||||
],
|
|
||||||
objectType: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message:
|
|
||||||
t('views.perfManage.customTarget.objectType') +
|
|
||||||
t('common.unableNull'),
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
expression: [
|
expression: [
|
||||||
@@ -279,60 +290,45 @@ const modalStateFrom = Form.useForm(
|
|||||||
t('views.perfManage.customTarget.title') + t('common.unableNull'),
|
t('views.perfManage.customTarget.title') + t('common.unableNull'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
period: [
|
unit: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message:
|
message:
|
||||||
t('views.perfManage.customTarget.period') + t('common.unableNull'),
|
t('views.perfManage.customTarget.unit') + t('common.unableNull'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
/**性能测量数据集选择初始 */
|
/**性能测量数据集选择初始 value:neType*/
|
||||||
function fnSelectPerformanceInit(value: any) {
|
function fnSelectPerformanceInit(value: any) {
|
||||||
const performance = useNeInfoStore().perMeasurementList.filter(
|
|
||||||
i => i.neType === value
|
|
||||||
);
|
|
||||||
if (modalState.from.objectType) modalState.from.objectType = '';
|
|
||||||
if (modalState.selectedPre.length > 0) modalState.selectedPre = [];
|
|
||||||
|
|
||||||
modalState.from.expression = '';
|
modalState.from.expression = '';
|
||||||
const arrSet = new Set<string>();
|
modalState.neTypPerformance = [
|
||||||
performance.forEach((data: any) => {
|
{
|
||||||
arrSet.add(data.objectType);
|
value: 'granularity',
|
||||||
|
label: t('views.perfManage.customTarget.granularity'),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
// 当前语言
|
||||||
|
var language = currentLocale.value.split('_')[0];
|
||||||
|
if (language === 'zh') language = 'cn';
|
||||||
|
// 获取表头文字
|
||||||
|
getKPITitle(value).then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||||
|
for (const item of res.data) {
|
||||||
|
const kpiDisplay = item[`${language}Title`];
|
||||||
|
const kpiValue = item[`kpiId`];
|
||||||
|
modalState.neTypPerformance.push({
|
||||||
|
value: kpiValue,
|
||||||
|
label: kpiDisplay,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.warning({
|
||||||
|
content: t('common.getInfoFail'),
|
||||||
|
duration: 2,
|
||||||
});
|
});
|
||||||
// 组装对象类型options
|
|
||||||
modalState.objectTypeArr = Array.from(arrSet).map((value: any) => ({
|
|
||||||
label: value,
|
|
||||||
value: value,
|
|
||||||
}));
|
|
||||||
|
|
||||||
//进行分组选择
|
|
||||||
const groupedData = performance.reduce((groups: any, item: any) => {
|
|
||||||
const { kpiCode, ...rest } = item;
|
|
||||||
if (!groups[kpiCode]) {
|
|
||||||
groups[kpiCode] = [];
|
|
||||||
}
|
}
|
||||||
groups[kpiCode].push(rest);
|
|
||||||
return groups;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
//渲染出性能测量集的选择项
|
|
||||||
modalState.neTypPerformance = Object.keys(groupedData).map(kpiCode => {
|
|
||||||
return {
|
|
||||||
label: kpiCode,
|
|
||||||
options: groupedData[kpiCode].map((item: any) => {
|
|
||||||
return {
|
|
||||||
value: item.kpiId,
|
|
||||||
label:
|
|
||||||
currentLocale.value === 'zh_CN'
|
|
||||||
? JSON.parse(item.titleJson).cn
|
|
||||||
: JSON.parse(item.titleJson).en,
|
|
||||||
kpiCode: kpiCode,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,30 +336,17 @@ function fnSelectPerformanceInit(value: any) {
|
|||||||
* 对话框弹出显示为 新增或者修改
|
* 对话框弹出显示为 新增或者修改
|
||||||
* @param noticeId 网元id, 不传为新增
|
* @param noticeId 网元id, 不传为新增
|
||||||
*/
|
*/
|
||||||
function fnModalVisibleByEdit(id?: string) {
|
function fnModalVisibleByEdit(row?: any, id?: any) {
|
||||||
if (!id) {
|
if (!id) {
|
||||||
modalStateFrom.resetFields();
|
modalStateFrom.resetFields();
|
||||||
modalState.title = t('views.perfManage.customTarget.addCustom');
|
modalState.title = t('views.perfManage.customTarget.addCustom');
|
||||||
modalState.visibleByEdit = true;
|
modalState.visibleByEdit = true;
|
||||||
|
fnSelectPerformanceInit(modalState.from.neType);
|
||||||
} else {
|
} else {
|
||||||
if (modalState.confirmLoading) return;
|
fnSelectPerformanceInit(row.neType);
|
||||||
const hide = message.loading(t('common.loading'), 0);
|
modalState.from = Object.assign(modalState.from, row);
|
||||||
modalState.confirmLoading = true;
|
|
||||||
getCustom(id).then(res => {
|
|
||||||
modalState.confirmLoading = false;
|
|
||||||
hide();
|
|
||||||
if (res.code === RESULT_CODE_SUCCESS && res.data) {
|
|
||||||
fnSelectPerformanceInit(res.data.neType);
|
|
||||||
modalState.selectedPre = res.data.kpiSet
|
|
||||||
? res.data.kpiSet.split(',')
|
|
||||||
: [];
|
|
||||||
modalState.from = Object.assign(modalState.from, res.data);
|
|
||||||
modalState.title = t('views.perfManage.customTarget.editCustom');
|
modalState.title = t('views.perfManage.customTarget.editCustom');
|
||||||
modalState.visibleByEdit = true;
|
modalState.visibleByEdit = true;
|
||||||
} else {
|
|
||||||
message.error(t('views.perfManage.customTarget.errorCustomInfo'), 3);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,13 +358,6 @@ function fnModalOk() {
|
|||||||
modalStateFrom
|
modalStateFrom
|
||||||
.validate()
|
.validate()
|
||||||
.then(e => {
|
.then(e => {
|
||||||
// if (modalState.selectedPre.length === 0) {
|
|
||||||
// message.error({
|
|
||||||
// content: `${res.msg}`,
|
|
||||||
// duration: 3,
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
modalState.from.kpiSet = modalState.selectedPre.join(',');
|
|
||||||
const from = toRaw(modalState.from);
|
const from = toRaw(modalState.from);
|
||||||
//return false;
|
//return false;
|
||||||
modalState.confirmLoading = true;
|
modalState.confirmLoading = true;
|
||||||
@@ -424,43 +400,54 @@ function fnModalCancel() {
|
|||||||
modalStateFrom.resetFields();
|
modalStateFrom.resetFields();
|
||||||
modalState.neType = [];
|
modalState.neType = [];
|
||||||
modalState.neTypPerformance = [];
|
modalState.neTypPerformance = [];
|
||||||
modalState.selectedPre = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 选择性能指标,填充进当前计算公式的值
|
* 选择性能指标,填充进当前计算公式的值
|
||||||
*/
|
*/
|
||||||
function fnSelectPer(s: any, option: any) {
|
function fnSelectPer(s: any, option: any) {
|
||||||
|
modalState.from.expression += `'${s}'`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fnSelectSymbol(s: any) {
|
||||||
modalState.from.expression += s;
|
modalState.from.expression += s;
|
||||||
}
|
}
|
||||||
|
/**网元参数 */
|
||||||
/**
|
let neCascaderOptions = ref<Record<string, any>[]>([]);
|
||||||
* 多选框取消性能指标 表达式的变化
|
|
||||||
*/
|
|
||||||
function fnDelPer(s: any, option: any) {
|
|
||||||
modalState.from.expression = modalState.from.expression.replace(s, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
// function checkText(e:any){
|
|
||||||
// console.log(e);
|
|
||||||
// const reg = /^[*+-/]*$/;
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 初始字典数据
|
|
||||||
Promise.allSettled([getDict('active_alarm_severity')]).then(resArr => {
|
|
||||||
if (resArr[0].status === 'fulfilled') {
|
|
||||||
dict.activeAlarmSeverity = resArr[0].value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Promise.allSettled([
|
Promise.allSettled([
|
||||||
// 获取网元网元列表
|
// 获取网元网元列表
|
||||||
|
getDict('sys_normal_disable'),
|
||||||
useNeInfoStore().fnNelist(),
|
useNeInfoStore().fnNelist(),
|
||||||
// 获取性能测量集列表
|
])
|
||||||
useNeInfoStore().fnNeTaskPerformance(),
|
.then(resArr => {
|
||||||
]).finally(() => {
|
if (resArr[0].status === 'fulfilled') {
|
||||||
|
dict.sysNormalDisable = resArr[0].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
resArr[1].status === 'fulfilled' &&
|
||||||
|
Array.isArray(resArr[1].value.data)
|
||||||
|
) {
|
||||||
|
if (resArr[1].value.data.length > 0) {
|
||||||
|
// 过滤不可用的网元
|
||||||
|
neCascaderOptions.value =
|
||||||
|
useNeInfoStore().getNeCascaderOptions.filter((item: any) => {
|
||||||
|
return !['OMC', 'NSSF', 'NEF', 'NRF', 'LMF', 'N3IWF'].includes(
|
||||||
|
item.value
|
||||||
|
);
|
||||||
|
});
|
||||||
|
if (neCascaderOptions.value.length === 0) {
|
||||||
|
message.warning({
|
||||||
|
content: t('common.noData'),
|
||||||
|
duration: 2,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
// 获取列表数据
|
// 获取列表数据
|
||||||
fnGetList();
|
fnGetList();
|
||||||
});
|
});
|
||||||
@@ -479,14 +466,14 @@ onMounted(() => {
|
|||||||
<a-row :gutter="16">
|
<a-row :gutter="16">
|
||||||
<a-col :lg="6" :md="12" :xs="24">
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label="t('views.traceManage.task.neType')"
|
:label="t('views.ne.common.neType')"
|
||||||
name="neType "
|
name="neType "
|
||||||
>
|
>
|
||||||
<a-auto-complete
|
<a-auto-complete
|
||||||
v-model:value="queryParams.neType"
|
v-model:value="queryParams.neType"
|
||||||
:options="useNeInfoStore().getNeSelectOtions"
|
:options="neCascaderOptions"
|
||||||
allow-clear
|
allow-clear
|
||||||
:placeholder="t('views.traceManage.task.neTypePlease')"
|
:placeholder="t('views.ne.common.neTypePlease')"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
@@ -580,7 +567,7 @@ onMounted(() => {
|
|||||||
<template #title>{{ t('common.editText') }}</template>
|
<template #title>{{ t('common.editText') }}</template>
|
||||||
<a-button
|
<a-button
|
||||||
type="link"
|
type="link"
|
||||||
@click.prevent="fnModalVisibleByEdit(record.id)"
|
@click.prevent="fnModalVisibleByEdit(record, record.id)"
|
||||||
>
|
>
|
||||||
<template #icon><FormOutlined /></template>
|
<template #icon><FormOutlined /></template>
|
||||||
</a-button>
|
</a-button>
|
||||||
@@ -593,6 +580,24 @@ onMounted(() => {
|
|||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</a-space>
|
</a-space>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template v-if="column.key === 'status'">
|
||||||
|
<DictTag
|
||||||
|
:options="[
|
||||||
|
{
|
||||||
|
label: t('views.perfManage.customTarget.active'),
|
||||||
|
value: 'Active',
|
||||||
|
tagType: 'success',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('views.perfManage.customTarget.inactive'),
|
||||||
|
value: 'Inactive',
|
||||||
|
tagType: 'error',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
:value="record.status"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</a-table>
|
</a-table>
|
||||||
</a-card>
|
</a-card>
|
||||||
@@ -610,35 +615,25 @@ onMounted(() => {
|
|||||||
@ok="fnModalOk"
|
@ok="fnModalOk"
|
||||||
@cancel="fnModalCancel"
|
@cancel="fnModalCancel"
|
||||||
>
|
>
|
||||||
<a-form name="modalStateFrom" layout="horizontal">
|
<a-form
|
||||||
|
name="modalStateFrom"
|
||||||
|
layout="horizontal"
|
||||||
|
:label-col="{ span: 6 }"
|
||||||
|
:label-wrap="true"
|
||||||
|
>
|
||||||
<a-row :gutter="16">
|
<a-row :gutter="16">
|
||||||
<a-col :lg="12" :md="12" :xs="24">
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label="t('views.traceManage.task.neType')"
|
:label="t('views.ne.common.neType')"
|
||||||
name="neType"
|
name="neType"
|
||||||
v-bind="modalStateFrom.validateInfos.neType"
|
v-bind="modalStateFrom.validateInfos.neType"
|
||||||
>
|
>
|
||||||
<a-select
|
<a-select
|
||||||
v-model:value="modalState.from.neType"
|
v-model:value="modalState.from.neType"
|
||||||
:options="useNeInfoStore().getNeSelectOtions"
|
:options="neCascaderOptions"
|
||||||
@change="fnSelectPerformanceInit"
|
@change="fnSelectPerformanceInit"
|
||||||
:allow-clear="false"
|
:allow-clear="false"
|
||||||
:placeholder="t('views.traceManage.task.neTypePlease')"
|
:placeholder="t('views.ne.common.neTypePlease')"
|
||||||
>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
<a-col :lg="12" :md="12" :xs="24">
|
|
||||||
<a-form-item
|
|
||||||
:label="t('views.perfManage.customTarget.objectType')"
|
|
||||||
name="kpiSobjectTypeet"
|
|
||||||
v-show="modalState.from.neType"
|
|
||||||
v-bind="modalStateFrom.validateInfos.objectType"
|
|
||||||
>
|
|
||||||
<a-select
|
|
||||||
placeholder="Please select"
|
|
||||||
v-model:value="modalState.from.objectType"
|
|
||||||
:options="modalState.objectTypeArr"
|
|
||||||
>
|
>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
@@ -646,6 +641,16 @@ onMounted(() => {
|
|||||||
</a-row>
|
</a-row>
|
||||||
|
|
||||||
<a-row :gutter="16">
|
<a-row :gutter="16">
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item
|
||||||
|
:label="t('views.perfManage.customTarget.title')"
|
||||||
|
name="title"
|
||||||
|
v-bind="modalStateFrom.validateInfos.title"
|
||||||
|
>
|
||||||
|
<a-input v-model:value="modalState.from.title" allow-clear>
|
||||||
|
</a-input>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
<a-col :lg="12" :md="12" :xs="24">
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label="t('views.perfManage.customTarget.kpiId')"
|
:label="t('views.perfManage.customTarget.kpiId')"
|
||||||
@@ -656,64 +661,96 @@ onMounted(() => {
|
|||||||
</a-input>
|
</a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :lg="12" :md="12" :xs="24">
|
|
||||||
<a-form-item
|
|
||||||
:label="t('views.perfManage.customTarget.period')"
|
|
||||||
name="period"
|
|
||||||
v-bind="modalStateFrom.validateInfos.period"
|
|
||||||
>
|
|
||||||
<a-select
|
|
||||||
v-model:value="modalState.from.period"
|
|
||||||
:placeholder="t('common.selectPlease')"
|
|
||||||
:options="[
|
|
||||||
{ label: '5S', value: 5 },
|
|
||||||
{ label: '1M', value: 60 },
|
|
||||||
{ label: '5M', value: 300 },
|
|
||||||
{ label: '15M', value: 900 },
|
|
||||||
{ label: '30M', value: 1800 },
|
|
||||||
{ label: '60M', value: 3600 },
|
|
||||||
]"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
</a-row>
|
||||||
|
|
||||||
<a-form-item
|
|
||||||
:label="t('views.perfManage.customTarget.title')"
|
|
||||||
name="title"
|
|
||||||
v-bind="modalStateFrom.validateInfos.title"
|
|
||||||
>
|
|
||||||
<a-input v-model:value="modalState.from.title" allow-clear> </a-input>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label="t('views.perfManage.customTarget.expression')"
|
:label="t('views.perfManage.customTarget.expression')"
|
||||||
name="expression"
|
name="expression"
|
||||||
|
:label-col="{ span: 3 }"
|
||||||
v-bind="modalStateFrom.validateInfos.expression"
|
v-bind="modalStateFrom.validateInfos.expression"
|
||||||
>
|
>
|
||||||
<a-input v-model:value="modalState.from.expression" allow-clear>
|
<a-input v-model:value="modalState.from.expression" allow-clear>
|
||||||
</a-input>
|
</a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<a-row :gutter="16">
|
<a-row :gutter="16">
|
||||||
<a-col :lg="21" :md="21" :xs="24">
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
<a-form-item name="perSelect">
|
<a-form-item
|
||||||
|
name="perSelect"
|
||||||
|
:label="t('views.perfManage.customTarget.symbol')"
|
||||||
|
>
|
||||||
|
<a-select
|
||||||
|
placeholder="Please select"
|
||||||
|
:options="modalStateFromOption.symbolJson"
|
||||||
|
@select="fnSelectSymbol"
|
||||||
|
></a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item
|
||||||
|
name="perSelect"
|
||||||
|
:label="t('views.perfManage.customTarget.element')"
|
||||||
|
>
|
||||||
<a-select
|
<a-select
|
||||||
mode="multiple"
|
|
||||||
style="margin-left: 80px"
|
|
||||||
placeholder="Please select"
|
placeholder="Please select"
|
||||||
allow-clear
|
|
||||||
v-model:value="modalState.selectedPre"
|
|
||||||
:options="modalState.neTypPerformance"
|
:options="modalState.neTypPerformance"
|
||||||
@select="fnSelectPer"
|
@select="fnSelectPer"
|
||||||
@deselect="fnDelPer"
|
|
||||||
></a-select>
|
></a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item
|
||||||
|
:label="t('views.perfManage.customTarget.unit')"
|
||||||
|
name="expression"
|
||||||
|
v-bind="modalStateFrom.validateInfos.unit"
|
||||||
|
>
|
||||||
|
<a-auto-complete
|
||||||
|
v-model:value="modalState.from.unit"
|
||||||
|
:options="[
|
||||||
|
{
|
||||||
|
label: 'Mbps',
|
||||||
|
value: 'Mbps',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '%',
|
||||||
|
value: '%',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
></a-auto-complete>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item
|
||||||
|
:label="t('views.perfManage.customTarget.status')"
|
||||||
|
name="status"
|
||||||
|
>
|
||||||
|
<a-select
|
||||||
|
v-model:value="modalState.from.status"
|
||||||
|
default-value="0"
|
||||||
|
:options="[
|
||||||
|
{
|
||||||
|
label: t('views.perfManage.customTarget.active'),
|
||||||
|
value: 'Active',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('views.perfManage.customTarget.inactive'),
|
||||||
|
value: 'Inactive',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
:placeholder="t('common.selectPlease')"
|
||||||
|
>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label="t('views.perfManage.customTarget.description')"
|
:label="t('views.perfManage.customTarget.description')"
|
||||||
name="description"
|
name="description"
|
||||||
|
:label-col="{ span: 3 }"
|
||||||
>
|
>
|
||||||
<a-textarea
|
<a-textarea
|
||||||
v-model:value="modalState.from.description"
|
v-model:value="modalState.from.description"
|
||||||
|
|||||||
@@ -254,15 +254,7 @@ function fnGetListTitle() {
|
|||||||
.then(res => {
|
.then(res => {
|
||||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||||
tableColumns.value = [];
|
tableColumns.value = [];
|
||||||
const columns: ColumnsType = [
|
const columns: ColumnsType = [];
|
||||||
{
|
|
||||||
title: t('views.perfManage.perfData.neName'),
|
|
||||||
dataIndex: 'neName',
|
|
||||||
key: 'neName',
|
|
||||||
align: 'left',
|
|
||||||
width: 100,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
for (const item of res.data) {
|
for (const item of res.data) {
|
||||||
const kpiDisplay = item[`${language}Title`];
|
const kpiDisplay = item[`${language}Title`];
|
||||||
const kpiValue = item[`kpiId`];
|
const kpiValue = item[`kpiId`];
|
||||||
@@ -277,6 +269,13 @@ function fnGetListTitle() {
|
|||||||
maxWidth: 300,
|
maxWidth: 300,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
columns.push({
|
||||||
|
title: t('views.perfManage.perfData.neName'),
|
||||||
|
dataIndex: 'neName',
|
||||||
|
key: 'neName',
|
||||||
|
align: 'left',
|
||||||
|
width: 100,
|
||||||
|
});
|
||||||
columns.push({
|
columns.push({
|
||||||
title: t('views.perfManage.goldTarget.time'),
|
title: t('views.perfManage.goldTarget.time'),
|
||||||
dataIndex: 'timeGroup',
|
dataIndex: 'timeGroup',
|
||||||
@@ -458,7 +457,7 @@ function fnRanderChartData() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const item of orgData) {
|
for (const item of orgData) {
|
||||||
chartDataXAxisData.push(item['timeGroup']);
|
chartDataXAxisData.push(parseDateToStr(+item['timeGroup']));
|
||||||
const keys = Object.keys(item);
|
const keys = Object.keys(item);
|
||||||
for (const y of chartDataYSeriesData) {
|
for (const y of chartDataYSeriesData) {
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
@@ -505,21 +504,23 @@ function fnLegendSelected(bool: any) {
|
|||||||
/**图表实时统计 */
|
/**图表实时统计 */
|
||||||
function fnRealTimeSwitch(bool: any) {
|
function fnRealTimeSwitch(bool: any) {
|
||||||
if (bool) {
|
if (bool) {
|
||||||
|
tableState.seached = false;
|
||||||
// 建立链接
|
// 建立链接
|
||||||
const options: OptionsType = {
|
const options: OptionsType = {
|
||||||
url: '/ws',
|
url: '/ws',
|
||||||
params: {
|
params: {
|
||||||
/**订阅通道组
|
/**订阅通道组
|
||||||
*
|
*
|
||||||
* 指标(GroupID:10)
|
* 指标(GroupID:10_neType_neId)
|
||||||
*/
|
*/
|
||||||
subGroupID: '10',
|
subGroupID: `10_${queryParams.neType}_${queryParams.neId}`,
|
||||||
},
|
},
|
||||||
onmessage: wsMessage,
|
onmessage: wsMessage,
|
||||||
onerror: wsError,
|
onerror: wsError,
|
||||||
};
|
};
|
||||||
ws.connect(options);
|
ws.connect(options);
|
||||||
} else {
|
} else {
|
||||||
|
tableState.seached = true;
|
||||||
ws.close();
|
ws.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -543,8 +544,10 @@ function wsMessage(res: Record<string, any>) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// kpiEvent 黄金指标指标事件
|
// kpiEvent 黄金指标指标事件
|
||||||
if (data.groupId === '10') {
|
|
||||||
const kpiEvent = data.data;
|
const kpiEvent = data.data;
|
||||||
|
tableState.data.unshift(kpiEvent);
|
||||||
|
tablePagination.total++;
|
||||||
|
|
||||||
// 非对应网元类型
|
// 非对应网元类型
|
||||||
if (kpiEvent.neType !== queryParams.neType) return;
|
if (kpiEvent.neType !== queryParams.neType) return;
|
||||||
|
|
||||||
@@ -553,14 +556,14 @@ function wsMessage(res: Record<string, any>) {
|
|||||||
// x轴
|
// x轴
|
||||||
if (key === 'timeGroup') {
|
if (key === 'timeGroup') {
|
||||||
// chartDataXAxisData.shift();
|
// chartDataXAxisData.shift();
|
||||||
chartDataXAxisData.push(v);
|
chartDataXAxisData.push(parseDateToStr(+v));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// y轴
|
// y轴
|
||||||
const yItem = chartDataYSeriesData.find(item => item.key === key);
|
const yItem = chartDataYSeriesData.find(item => item.key === key);
|
||||||
if (yItem) {
|
if (yItem) {
|
||||||
// yItem.data.shift();
|
// yItem.data.shift();
|
||||||
yItem.data.push(v);
|
yItem.data.push(+v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -571,11 +574,10 @@ function wsMessage(res: Record<string, any>) {
|
|||||||
},
|
},
|
||||||
series: chartDataYSeriesData,
|
series: chartDataYSeriesData,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 目前支持的 AMF AUSF MME MOCNGW NSSF SMF UDM UPF
|
// 目前支持的 AMF AUSF MME MOCNGW NSSF SMF UDM UPF PCF
|
||||||
// 获取网元网元列表
|
// 获取网元网元列表
|
||||||
neInfoStore.fnNelist().then(res => {
|
neInfoStore.fnNelist().then(res => {
|
||||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||||
@@ -583,15 +585,9 @@ onMounted(() => {
|
|||||||
// 过滤不可用的网元
|
// 过滤不可用的网元
|
||||||
neCascaderOptions.value = neInfoStore.getNeCascaderOptions.filter(
|
neCascaderOptions.value = neInfoStore.getNeCascaderOptions.filter(
|
||||||
(item: any) => {
|
(item: any) => {
|
||||||
return ![
|
return !['OMC', 'NSSF', 'NEF', 'NRF', 'LMF', 'N3IWF'].includes(
|
||||||
'OMC',
|
item.value
|
||||||
'PCF',
|
);
|
||||||
'NSSF',
|
|
||||||
'NEF',
|
|
||||||
'NRF',
|
|
||||||
'LMF',
|
|
||||||
'N3IWF',
|
|
||||||
].includes(item.value);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if (neCascaderOptions.value.length === 0) {
|
if (neCascaderOptions.value.length === 0) {
|
||||||
@@ -619,9 +615,9 @@ onMounted(() => {
|
|||||||
// 查询当前小时
|
// 查询当前小时
|
||||||
const nowDate: Date = new Date();
|
const nowDate: Date = new Date();
|
||||||
nowDate.setMinutes(0, 0, 0);
|
nowDate.setMinutes(0, 0, 0);
|
||||||
queryRangePicker.value[0] = parseDateToStr(nowDate);
|
queryRangePicker.value[0] = `${nowDate.getTime()}`;
|
||||||
nowDate.setMinutes(59, 59, 59);
|
nowDate.setMinutes(59, 59, 59);
|
||||||
queryRangePicker.value[1] = parseDateToStr(nowDate);
|
queryRangePicker.value[1] = `${nowDate.getTime()}`;
|
||||||
fnGetListTitle();
|
fnGetListTitle();
|
||||||
// 绘图
|
// 绘图
|
||||||
fnRanderChart();
|
fnRanderChart();
|
||||||
@@ -653,7 +649,7 @@ onBeforeUnmount(() => {
|
|||||||
<a-col :lg="6" :md="12" :xs="24">
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
name="neType"
|
name="neType"
|
||||||
:label="t('views.traceManage.task.neType')"
|
:label="t('views.ne.common.neType')"
|
||||||
>
|
>
|
||||||
<a-cascader
|
<a-cascader
|
||||||
v-model:value="state.neType"
|
v-model:value="state.neType"
|
||||||
@@ -666,15 +662,17 @@ onBeforeUnmount(() => {
|
|||||||
<a-col :lg="10" :md="12" :xs="24">
|
<a-col :lg="10" :md="12" :xs="24">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label="t('views.perfManage.goldTarget.timeFrame')"
|
:label="t('views.perfManage.goldTarget.timeFrame')"
|
||||||
name="eventTime"
|
name="timeFrame"
|
||||||
>
|
>
|
||||||
<a-range-picker
|
<a-range-picker
|
||||||
v-model:value="queryRangePicker"
|
v-model:value="queryRangePicker"
|
||||||
value-format="YYYY-MM-DD HH:mm:ss"
|
bordered
|
||||||
format="YYYY-MM-DD HH:mm:ss"
|
|
||||||
:allow-clear="false"
|
:allow-clear="false"
|
||||||
show-time
|
: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-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :lg="4" :md="12" :xs="24">
|
<a-col :lg="4" :md="12" :xs="24">
|
||||||
@@ -747,15 +745,6 @@ onBeforeUnmount(() => {
|
|||||||
<!-- 插槽-卡片右侧 -->
|
<!-- 插槽-卡片右侧 -->
|
||||||
<template #extra>
|
<template #extra>
|
||||||
<a-space :size="8" align="center" v-show="tableState.showTable">
|
<a-space :size="8" align="center" v-show="tableState.showTable">
|
||||||
<a-tooltip>
|
|
||||||
<template #title>{{ t('common.searchBarText') }}</template>
|
|
||||||
<a-switch
|
|
||||||
v-model:checked="tableState.seached"
|
|
||||||
:checked-children="t('common.switch.show')"
|
|
||||||
:un-checked-children="t('common.switch.hide')"
|
|
||||||
size="small"
|
|
||||||
/>
|
|
||||||
</a-tooltip>
|
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template #title>{{ t('common.reloadText') }}</template>
|
<template #title>{{ t('common.reloadText') }}</template>
|
||||||
<a-button type="text" @click.prevent="fnGetList()">
|
<a-button type="text" @click.prevent="fnGetList()">
|
||||||
@@ -833,11 +822,16 @@ onBeforeUnmount(() => {
|
|||||||
:data-source="tableState.data"
|
:data-source="tableState.data"
|
||||||
:size="tableState.size"
|
:size="tableState.size"
|
||||||
:pagination="tablePagination"
|
:pagination="tablePagination"
|
||||||
:scroll="{ x: tableColumnsDnd.length * 200, y: 450 }"
|
:scroll="{ x: tableColumnsDnd.length * 200, y: 'calc(100vh - 480px)' }"
|
||||||
@resizeColumn="(w:number, col:any) => (col.width = w)"
|
@resizeColumn="(w:number, col:any) => (col.width = w)"
|
||||||
:show-expand-column="false"
|
:show-expand-column="false"
|
||||||
@change="fnTableChange"
|
@change="fnTableChange"
|
||||||
>
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'timeGroup'">
|
||||||
|
{{ parseDateToStr(+record.timeGroup) }}
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
</a-table>
|
</a-table>
|
||||||
|
|
||||||
<!-- 图表 -->
|
<!-- 图表 -->
|
||||||
|
|||||||
834
src/views/perfManage/kpiCReport/index.vue
Normal file
834
src/views/perfManage/kpiCReport/index.vue
Normal file
@@ -0,0 +1,834 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import * as echarts from 'echarts/core';
|
||||||
|
import {
|
||||||
|
TooltipComponent,
|
||||||
|
TooltipComponentOption,
|
||||||
|
GridComponent,
|
||||||
|
GridComponentOption,
|
||||||
|
LegendComponent,
|
||||||
|
LegendComponentOption,
|
||||||
|
DataZoomComponent,
|
||||||
|
DataZoomComponentOption,
|
||||||
|
} from 'echarts/components';
|
||||||
|
import { LineChart, LineSeriesOption } from 'echarts/charts';
|
||||||
|
import { UniversalTransition } from 'echarts/features';
|
||||||
|
import { CanvasRenderer } from 'echarts/renderers';
|
||||||
|
|
||||||
|
import {
|
||||||
|
reactive,
|
||||||
|
ref,
|
||||||
|
onMounted,
|
||||||
|
toRaw,
|
||||||
|
markRaw,
|
||||||
|
nextTick,
|
||||||
|
onBeforeUnmount,
|
||||||
|
} from 'vue';
|
||||||
|
import { PageContainer } from 'antdv-pro-layout';
|
||||||
|
import { message, Modal } from 'ant-design-vue/lib';
|
||||||
|
import { ColumnsType } from 'ant-design-vue/lib/table';
|
||||||
|
import { SizeType } from 'ant-design-vue/lib/config-provider';
|
||||||
|
import { MenuInfo } from 'ant-design-vue/lib/menu/src/interface';
|
||||||
|
import TableColumnsDnd from '@/components/TableColumnsDnd/index.vue';
|
||||||
|
import {
|
||||||
|
RESULT_CODE_ERROR,
|
||||||
|
RESULT_CODE_SUCCESS,
|
||||||
|
} from '@/constants/result-constants';
|
||||||
|
import useNeInfoStore from '@/store/modules/neinfo';
|
||||||
|
import useI18n from '@/hooks/useI18n';
|
||||||
|
import { listCustom } from '@/api/perfManage/customTarget';
|
||||||
|
import { listCustomData } from '@/api/perfManage/customData';
|
||||||
|
import { parseDateToStr } from '@/utils/date-utils';
|
||||||
|
import { writeSheet } from '@/utils/execl-utils';
|
||||||
|
import saveAs from 'file-saver';
|
||||||
|
import { generateColorRGBA } from '@/utils/generate-utils';
|
||||||
|
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
const neInfoStore = useNeInfoStore();
|
||||||
|
const route = useRoute();
|
||||||
|
const { t, currentLocale } = useI18n();
|
||||||
|
const ws = new WS();
|
||||||
|
|
||||||
|
echarts.use([
|
||||||
|
TooltipComponent,
|
||||||
|
GridComponent,
|
||||||
|
LegendComponent,
|
||||||
|
DataZoomComponent,
|
||||||
|
LineChart,
|
||||||
|
CanvasRenderer,
|
||||||
|
UniversalTransition,
|
||||||
|
]);
|
||||||
|
|
||||||
|
type EChartsOption = echarts.ComposeOption<
|
||||||
|
| TooltipComponentOption
|
||||||
|
| GridComponentOption
|
||||||
|
| LegendComponentOption
|
||||||
|
| DataZoomComponentOption
|
||||||
|
| LineSeriesOption
|
||||||
|
>;
|
||||||
|
|
||||||
|
/**图DOM节点实例对象 */
|
||||||
|
const kpiChartDom = ref<HTMLElement | undefined>(undefined);
|
||||||
|
|
||||||
|
/**图实例对象 */
|
||||||
|
const kpiChart = ref<any>(null);
|
||||||
|
|
||||||
|
/**网元参数 */
|
||||||
|
let neCascaderOptions = ref<Record<string, any>[]>([]);
|
||||||
|
|
||||||
|
/**记录开始结束时间 */
|
||||||
|
let queryRangePicker = ref<[string, string]>(['', '']);
|
||||||
|
|
||||||
|
/**表格字段列 */
|
||||||
|
let tableColumns = ref<ColumnsType>([]);
|
||||||
|
|
||||||
|
/**表格字段列排序 */
|
||||||
|
let tableColumnsDnd = ref<ColumnsType>([]);
|
||||||
|
|
||||||
|
/**表格分页器参数 */
|
||||||
|
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;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**表格状态类型 */
|
||||||
|
type TabeStateType = {
|
||||||
|
/**加载等待 */
|
||||||
|
loading: boolean;
|
||||||
|
/**紧凑型 */
|
||||||
|
size: SizeType;
|
||||||
|
/**搜索栏 */
|
||||||
|
seached: boolean;
|
||||||
|
/**记录数据 */
|
||||||
|
data: Record<string, any>[];
|
||||||
|
/**显示表格 */
|
||||||
|
showTable: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**表格状态 */
|
||||||
|
let tableState: TabeStateType = reactive({
|
||||||
|
tableColumns: [],
|
||||||
|
loading: false,
|
||||||
|
size: 'middle',
|
||||||
|
seached: true,
|
||||||
|
data: [],
|
||||||
|
showTable: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**表格紧凑型变更操作 */
|
||||||
|
function fnTableSize({ key }: MenuInfo) {
|
||||||
|
tableState.size = key as SizeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**查询参数 */
|
||||||
|
let queryParams: any = reactive({
|
||||||
|
/**网元类型 */
|
||||||
|
neType: '',
|
||||||
|
/**网元标识 */
|
||||||
|
neId: '',
|
||||||
|
/**开始时间 */
|
||||||
|
startTime: '',
|
||||||
|
/**结束时间 */
|
||||||
|
endTime: '',
|
||||||
|
/**排序字段 */
|
||||||
|
sortField: 'created_at',
|
||||||
|
/**排序方式 */
|
||||||
|
sortOrder: 'desc',
|
||||||
|
});
|
||||||
|
|
||||||
|
/**表格分页、排序、筛选变化时触发操作, 排序方式,取值为 ascend descend */
|
||||||
|
function fnTableChange(pagination: any, filters: any, sorter: any, extra: any) {
|
||||||
|
const { columnKey, order } = sorter;
|
||||||
|
if (!order) return;
|
||||||
|
if (order.startsWith(queryParams.sortOrder)) return;
|
||||||
|
|
||||||
|
if (order) {
|
||||||
|
queryParams.sortField = columnKey;
|
||||||
|
queryParams.sortOrder = order.replace('end', '');
|
||||||
|
} else {
|
||||||
|
queryParams.sortOrder = 'asc';
|
||||||
|
}
|
||||||
|
|
||||||
|
fnGetList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**对象信息状态类型 */
|
||||||
|
type StateType = {
|
||||||
|
/**网元类型 */
|
||||||
|
neType: string[];
|
||||||
|
/**图表实时统计 */
|
||||||
|
chartRealTime: boolean;
|
||||||
|
/**图表标签选择 */
|
||||||
|
chartLegendSelectedFlag: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**对象信息状态 */
|
||||||
|
let state: StateType = reactive({
|
||||||
|
neType: [],
|
||||||
|
chartRealTime: false,
|
||||||
|
chartLegendSelectedFlag: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据列表导出
|
||||||
|
*/
|
||||||
|
function fnRecordExport() {
|
||||||
|
Modal.confirm({
|
||||||
|
title: 'Tip',
|
||||||
|
content: t('views.perfManage.goldTarget.exportSure'),
|
||||||
|
onOk() {
|
||||||
|
const key = 'exportKPI';
|
||||||
|
message.loading({ content: t('common.loading'), key });
|
||||||
|
|
||||||
|
if (tableState.data.length <= 0) {
|
||||||
|
message.error({
|
||||||
|
content: t('views.perfManage.goldTarget.exportEmpty'),
|
||||||
|
key,
|
||||||
|
duration: 2,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableColumnsTitleArr: string[] = [];
|
||||||
|
const tableColumnsKeyArr: string[] = [];
|
||||||
|
for (const columns of tableColumnsDnd.value) {
|
||||||
|
tableColumnsTitleArr.push(`${columns.title}`);
|
||||||
|
tableColumnsKeyArr.push(`${columns.key}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const kpiDataArr = [];
|
||||||
|
for (const item of tableState.data) {
|
||||||
|
const kpiData: Record<string, any> = {};
|
||||||
|
const keys = Object.keys(item);
|
||||||
|
for (let i = 0; i <= tableColumnsKeyArr.length; i++) {
|
||||||
|
for (const key of keys) {
|
||||||
|
if (tableColumnsKeyArr[i] === key) {
|
||||||
|
const title = tableColumnsTitleArr[i];
|
||||||
|
kpiData[title] = item[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kpiDataArr.push(kpiData);
|
||||||
|
}
|
||||||
|
|
||||||
|
writeSheet(kpiDataArr, 'KPI', { header: tableColumnsTitleArr })
|
||||||
|
.then(fileBlob => saveAs(fileBlob, `kpi_data_${Date.now()}.xlsx`))
|
||||||
|
.finally(() => {
|
||||||
|
message.success({
|
||||||
|
content: t('common.msgSuccess', { msg: t('common.export') }),
|
||||||
|
key,
|
||||||
|
duration: 2,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**查询数据列表表头 */
|
||||||
|
function fnGetListTitle() {
|
||||||
|
// 当前语言
|
||||||
|
var language = currentLocale.value.split('_')[0];
|
||||||
|
if (language === 'zh') language = 'cn';
|
||||||
|
|
||||||
|
// 获取表头文字
|
||||||
|
listCustom({ neType: state.neType[0], status: 'Active' })
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||||
|
if (res.data.length === 0) {
|
||||||
|
message.error({
|
||||||
|
content: t('views.perfManage.customTarget.kpiIdTip'),
|
||||||
|
duration: 2,
|
||||||
|
});
|
||||||
|
tableState.data = [];
|
||||||
|
tableColumns.value = [];
|
||||||
|
tableColumnsDnd.value = [];
|
||||||
|
fnRanderChartData();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
tableColumns.value = [];
|
||||||
|
const columns: ColumnsType = [];
|
||||||
|
for (const item of res.data) {
|
||||||
|
const kpiDisplay = item[`unit`]? item[`title`]+ `(${item['unit']})`:item[`title`];
|
||||||
|
const kpiValue = item[`kpiId`];
|
||||||
|
columns.push({
|
||||||
|
title: kpiDisplay,
|
||||||
|
dataIndex: kpiValue,
|
||||||
|
align: 'left',
|
||||||
|
key: kpiValue,
|
||||||
|
resizable: true,
|
||||||
|
width: 100,
|
||||||
|
minWidth: 150,
|
||||||
|
maxWidth: 300,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
columns.push({
|
||||||
|
title: t('views.perfManage.perfData.neName'),
|
||||||
|
dataIndex: 'neName',
|
||||||
|
key: 'neName',
|
||||||
|
align: 'left',
|
||||||
|
width: 100,
|
||||||
|
});
|
||||||
|
columns.push({
|
||||||
|
title: t('views.perfManage.goldTarget.time'),
|
||||||
|
dataIndex: 'timeGroup',
|
||||||
|
align: 'left',
|
||||||
|
fixed: 'right',
|
||||||
|
key: 'timeGroup',
|
||||||
|
sorter: true,
|
||||||
|
width: 100,
|
||||||
|
});
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
tableColumns.value = columns;
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
message.warning({
|
||||||
|
content: t('common.getInfoFail'),
|
||||||
|
duration: 2,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(result => {
|
||||||
|
result && fnGetList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**查询数据列表 */
|
||||||
|
function fnGetList() {
|
||||||
|
if (tableState.loading) return;
|
||||||
|
tableState.loading = true;
|
||||||
|
queryParams.neType = state.neType[0];
|
||||||
|
queryParams.neId = state.neType[1];
|
||||||
|
queryParams.startTime = queryRangePicker.value[0];
|
||||||
|
queryParams.endTime = queryRangePicker.value[1];
|
||||||
|
listCustomData(toRaw(queryParams))
|
||||||
|
.then(res => {
|
||||||
|
tableState.loading = false;
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||||
|
tablePagination.total = res.data.length;
|
||||||
|
tableState.data = res.data;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
.then(result => {
|
||||||
|
if (result) {
|
||||||
|
fnRanderChartData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**切换显示类型 图或表格 */
|
||||||
|
function fnChangShowType() {
|
||||||
|
tableState.showTable = !tableState.showTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**绘制图表 */
|
||||||
|
function fnRanderChart() {
|
||||||
|
const container: HTMLElement | undefined = kpiChartDom.value;
|
||||||
|
if (!container) return;
|
||||||
|
kpiChart.value = markRaw(echarts.init(container, 'light'));
|
||||||
|
|
||||||
|
const option: EChartsOption = {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
position: function (pt: any) {
|
||||||
|
return [pt[0], '10%'];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
data: [], // 数据x轴
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
boundaryGap: [0, '100%'],
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
type: 'scroll',
|
||||||
|
orient: 'vertical',
|
||||||
|
top: 40,
|
||||||
|
right: 20,
|
||||||
|
itemWidth: 20,
|
||||||
|
itemGap: 25,
|
||||||
|
textStyle: {
|
||||||
|
color: '#646A73',
|
||||||
|
},
|
||||||
|
icon: 'circle',
|
||||||
|
selected: {},
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '10%',
|
||||||
|
right: '30%',
|
||||||
|
bottom: '20%',
|
||||||
|
},
|
||||||
|
dataZoom: [
|
||||||
|
{
|
||||||
|
type: 'inside',
|
||||||
|
start: 90,
|
||||||
|
end: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
start: 90,
|
||||||
|
end: 100,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
series: [], // 数据y轴
|
||||||
|
};
|
||||||
|
kpiChart.value.setOption(option);
|
||||||
|
|
||||||
|
// 创建 ResizeObserver 实例
|
||||||
|
var observer = new ResizeObserver(entries => {
|
||||||
|
if (kpiChart.value) {
|
||||||
|
kpiChart.value.resize();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 监听元素大小变化
|
||||||
|
observer.observe(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**图表标签选择 */
|
||||||
|
let chartLegendSelected: Record<string, boolean> = {};
|
||||||
|
/**图表配置数据x轴 */
|
||||||
|
let chartDataXAxisData: string[] = [];
|
||||||
|
/**图表配置数据y轴 */
|
||||||
|
let chartDataYSeriesData: Record<string, any>[] = [];
|
||||||
|
|
||||||
|
/**图表数据渲染 */
|
||||||
|
function fnRanderChartData() {
|
||||||
|
if (kpiChart.value == null && tableState.data.length <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置
|
||||||
|
chartLegendSelected = {};
|
||||||
|
chartDataXAxisData = [];
|
||||||
|
chartDataYSeriesData = [];
|
||||||
|
|
||||||
|
for (var columns of tableColumns.value) {
|
||||||
|
if (
|
||||||
|
columns.key === 'neName' ||
|
||||||
|
columns.key === 'startIndex' ||
|
||||||
|
columns.key === 'timeGroup'
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const color = generateColorRGBA();
|
||||||
|
chartDataYSeriesData.push({
|
||||||
|
name: `${columns.title}`,
|
||||||
|
key: `${columns.key}`,
|
||||||
|
type: 'line',
|
||||||
|
symbol: 'none',
|
||||||
|
sampling: 'lttb',
|
||||||
|
itemStyle: {
|
||||||
|
color: color,
|
||||||
|
},
|
||||||
|
areaStyle: {
|
||||||
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||||
|
{
|
||||||
|
offset: 0,
|
||||||
|
color: color.replace(')', ',0.8)'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: 1,
|
||||||
|
color: color.replace(')', ',0.3)'),
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
data: [],
|
||||||
|
});
|
||||||
|
chartLegendSelected[`${columns.title}`] = state.chartLegendSelectedFlag;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用降序就反转
|
||||||
|
let orgData = tableState.data;
|
||||||
|
if (queryParams.sortOrder === 'desc') {
|
||||||
|
orgData = orgData.toReversed();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of orgData) {
|
||||||
|
chartDataXAxisData.push(item['timeGroup']);
|
||||||
|
const keys = Object.keys(item);
|
||||||
|
for (const y of chartDataYSeriesData) {
|
||||||
|
for (const key of keys) {
|
||||||
|
if (y.key === key) {
|
||||||
|
y.data.push(+item[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// console.log(queryParams.sortOrder, chartLegendSelected);
|
||||||
|
// console.log(chartDataXAxisData, chartDataYSeriesData);
|
||||||
|
|
||||||
|
// 绘制图数据
|
||||||
|
kpiChart.value.setOption(
|
||||||
|
{
|
||||||
|
legend: {
|
||||||
|
selected: chartLegendSelected,
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
data: chartDataXAxisData,
|
||||||
|
},
|
||||||
|
series: chartDataYSeriesData,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
replaceMerge: ['xAxis', 'series'],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**图表折线显示全部 */
|
||||||
|
function fnLegendSelected(bool: any) {
|
||||||
|
for (const key of Object.keys(chartLegendSelected)) {
|
||||||
|
chartLegendSelected[key] = bool;
|
||||||
|
}
|
||||||
|
kpiChart.value.setOption({
|
||||||
|
legend: {
|
||||||
|
selected: chartLegendSelected,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**图表实时统计 */
|
||||||
|
function fnRealTimeSwitch(bool: any) {
|
||||||
|
if (bool) {
|
||||||
|
tableState.seached = false;
|
||||||
|
// 建立链接
|
||||||
|
const options: OptionsType = {
|
||||||
|
url: '/ws',
|
||||||
|
params: {
|
||||||
|
/**订阅通道组
|
||||||
|
*
|
||||||
|
* 指标(GroupID:10_neType_neId)
|
||||||
|
*/
|
||||||
|
subGroupID: `20_${queryParams.neType}_${queryParams.neId}`,
|
||||||
|
},
|
||||||
|
onmessage: wsMessage,
|
||||||
|
onerror: wsError,
|
||||||
|
};
|
||||||
|
ws.connect(options);
|
||||||
|
} else {
|
||||||
|
tableState.seached = true;
|
||||||
|
ws.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**接收数据后回调 */
|
||||||
|
function wsError(ev: any) {
|
||||||
|
// 接收数据后回调
|
||||||
|
console.error(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**接收数据后回调 */
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
// kpiEvent 黄金指标指标事件
|
||||||
|
const kpiEvent = data.data;
|
||||||
|
tableState.data.unshift(kpiEvent);
|
||||||
|
tablePagination.total++;
|
||||||
|
|
||||||
|
// 非对应网元类型
|
||||||
|
if (kpiEvent.neType !== queryParams.neType) return;
|
||||||
|
|
||||||
|
for (const key of Object.keys(data.data)) {
|
||||||
|
const v = kpiEvent[key];
|
||||||
|
// x轴
|
||||||
|
if (key === 'timeGroup') {
|
||||||
|
// chartDataXAxisData.shift();
|
||||||
|
chartDataXAxisData.push(v);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// y轴
|
||||||
|
const yItem = chartDataYSeriesData.find(item => item.key === key);
|
||||||
|
if (yItem) {
|
||||||
|
// yItem.data.shift();
|
||||||
|
yItem.data.push(+v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绘制图数据
|
||||||
|
kpiChart.value.setOption({
|
||||||
|
xAxis: {
|
||||||
|
data: chartDataXAxisData,
|
||||||
|
},
|
||||||
|
series: chartDataYSeriesData,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 目前支持的 AMF AUSF MME MOCNGW NSSF SMF UDM UPF PCF
|
||||||
|
// 获取网元网元列表
|
||||||
|
neInfoStore.fnNelist().then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||||
|
if (res.data.length > 0) {
|
||||||
|
// 过滤不可用的网元
|
||||||
|
neCascaderOptions.value = neInfoStore.getNeCascaderOptions.filter(
|
||||||
|
(item: any) => {
|
||||||
|
return !['OMC', 'NSSF', 'NEF', 'NRF', 'LMF', 'N3IWF'].includes(
|
||||||
|
item.value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (neCascaderOptions.value.length === 0) {
|
||||||
|
message.warning({
|
||||||
|
content: t('common.noData'),
|
||||||
|
duration: 2,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 无查询参数neType时 默认选择UPF
|
||||||
|
const queryNeType = (route.query.neType as string) || 'UPF';
|
||||||
|
const item = neCascaderOptions.value.find(s => s.value === queryNeType);
|
||||||
|
if (item && item.children) {
|
||||||
|
const info = item.children[0];
|
||||||
|
state.neType = [info.neType, info.neId];
|
||||||
|
queryParams.neType = info.neType;
|
||||||
|
queryParams.neId = info.neId;
|
||||||
|
} else {
|
||||||
|
const info = neCascaderOptions.value[0].children[0];
|
||||||
|
state.neType = [info.neType, info.neId];
|
||||||
|
queryParams.neType = info.neType;
|
||||||
|
queryParams.neId = info.neId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询当前小时
|
||||||
|
|
||||||
|
const now = new Date();
|
||||||
|
now.setMinutes(0, 0, 0);
|
||||||
|
queryRangePicker.value[0] = parseDateToStr(now.getTime());
|
||||||
|
now.setMinutes(59, 59, 59);
|
||||||
|
queryRangePicker.value[1] = parseDateToStr(now.getTime());
|
||||||
|
fnGetListTitle();
|
||||||
|
// 绘图
|
||||||
|
fnRanderChart();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.warning({
|
||||||
|
content: t('common.noData'),
|
||||||
|
duration: 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
ws.close();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PageContainer>
|
||||||
|
<a-card
|
||||||
|
v-show="tableState.seached"
|
||||||
|
:bordered="false"
|
||||||
|
:body-style="{ marginBottom: '24px', paddingBottom: 0 }"
|
||||||
|
>
|
||||||
|
<!-- 表格搜索栏 -->
|
||||||
|
<a-form :model="queryParams" name="queryParamsFrom" layout="horizontal">
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
|
<a-form-item
|
||||||
|
name="neType"
|
||||||
|
:label="t('views.ne.common.neType')"
|
||||||
|
>
|
||||||
|
<a-cascader
|
||||||
|
v-model:value="state.neType"
|
||||||
|
:options="neCascaderOptions"
|
||||||
|
:allow-clear="false"
|
||||||
|
:placeholder="t('common.selectPlease')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="10" :md="12" :xs="24">
|
||||||
|
<a-form-item
|
||||||
|
:label="t('views.perfManage.goldTarget.timeFrame')"
|
||||||
|
name="timeFrame"
|
||||||
|
>
|
||||||
|
<a-range-picker
|
||||||
|
v-model:value="queryRangePicker"
|
||||||
|
bordered
|
||||||
|
:allow-clear="false"
|
||||||
|
:show-time="{ format: 'HH:mm:ss' }"
|
||||||
|
format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
style="width: 100%"
|
||||||
|
></a-range-picker>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
|
||||||
|
<a-col :lg="2" :md="12" :xs="24">
|
||||||
|
<a-form-item>
|
||||||
|
<a-space :size="8">
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
:loading="tableState.loading"
|
||||||
|
@click.prevent="fnGetListTitle()"
|
||||||
|
>
|
||||||
|
<template #icon><SearchOutlined /></template>
|
||||||
|
{{ t('common.search') }}
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-form>
|
||||||
|
</a-card>
|
||||||
|
|
||||||
|
<a-card :bordered="false" :body-style="{ padding: '0px' }">
|
||||||
|
<!-- 插槽-卡片左侧侧 -->
|
||||||
|
<template #title>
|
||||||
|
<a-space :size="8" align="center">
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
:loading="tableState.loading"
|
||||||
|
@click.prevent="fnChangShowType()"
|
||||||
|
>
|
||||||
|
<template #icon> <AreaChartOutlined /> </template>
|
||||||
|
{{
|
||||||
|
tableState.showTable
|
||||||
|
? t('views.perfManage.goldTarget.kpiChartTitle')
|
||||||
|
: t('views.perfManage.goldTarget.kpiTableTitle')
|
||||||
|
}}
|
||||||
|
</a-button>
|
||||||
|
<a-button
|
||||||
|
type="dashed"
|
||||||
|
:loading="tableState.loading"
|
||||||
|
@click.prevent="fnRecordExport()"
|
||||||
|
v-show="tableState.showTable"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<ExportOutlined />
|
||||||
|
</template>
|
||||||
|
{{ t('common.export') }}
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 插槽-卡片右侧 -->
|
||||||
|
<template #extra>
|
||||||
|
<a-space :size="8" align="center" v-show="tableState.showTable">
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>{{ t('common.reloadText') }}</template>
|
||||||
|
<a-button type="text" @click.prevent="fnGetList()">
|
||||||
|
<template #icon><ReloadOutlined /></template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
<TableColumnsDnd
|
||||||
|
v-if="tableColumns.length > 0"
|
||||||
|
:cache-id="`kpiTarget_${state.neType[0]}`"
|
||||||
|
:columns="tableColumns"
|
||||||
|
v-model:columns-dnd="tableColumnsDnd"
|
||||||
|
></TableColumnsDnd>
|
||||||
|
<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>
|
||||||
|
<a-form layout="inline" v-show="!tableState.showTable">
|
||||||
|
<a-form-item
|
||||||
|
:label="t('views.perfManage.goldTarget.showChartSelected')"
|
||||||
|
name="chartLegendSelectedFlag"
|
||||||
|
>
|
||||||
|
<a-switch
|
||||||
|
:disabled="tableState.loading"
|
||||||
|
v-model:checked="state.chartLegendSelectedFlag"
|
||||||
|
:checked-children="t('common.switch.open')"
|
||||||
|
:un-checked-children="t('common.switch.shut')"
|
||||||
|
@change="fnLegendSelected"
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
:label="t('views.perfManage.goldTarget.realTimeData')"
|
||||||
|
name="chartRealTime"
|
||||||
|
>
|
||||||
|
<a-switch
|
||||||
|
:disabled="tableState.loading"
|
||||||
|
v-model:checked="state.chartRealTime"
|
||||||
|
:checked-children="t('common.switch.open')"
|
||||||
|
:un-checked-children="t('common.switch.shut')"
|
||||||
|
@change="fnRealTimeSwitch"
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 表格列表 -->
|
||||||
|
<a-table
|
||||||
|
v-show="tableState.showTable"
|
||||||
|
class="table"
|
||||||
|
row-key="id"
|
||||||
|
:columns="tableColumnsDnd"
|
||||||
|
:loading="tableState.loading"
|
||||||
|
:data-source="tableState.data"
|
||||||
|
:size="tableState.size"
|
||||||
|
:pagination="tablePagination"
|
||||||
|
:scroll="{ x: tableColumnsDnd.length * 200, y: 'calc(100vh - 480px)' }"
|
||||||
|
@resizeColumn="(w:number, col:any) => (col.width = w)"
|
||||||
|
:show-expand-column="false"
|
||||||
|
@change="fnTableChange"
|
||||||
|
>
|
||||||
|
</a-table>
|
||||||
|
|
||||||
|
<!-- 图表 -->
|
||||||
|
<div style="padding: 24px" v-show="!tableState.showTable">
|
||||||
|
<div ref="kpiChartDom" style="height: 450px; width: 100%"></div>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
</PageContainer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped></style>
|
||||||
@@ -1,543 +1,16 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive, onMounted, toRaw } from 'vue';
|
import { onMounted } from 'vue';
|
||||||
import { PageContainer } from 'antdv-pro-layout';
|
import { PageContainer } from 'antdv-pro-layout';
|
||||||
import { Modal } from 'ant-design-vue/lib';
|
|
||||||
import { SizeType } from 'ant-design-vue/lib/config-provider';
|
|
||||||
import { MenuInfo } from 'ant-design-vue/lib/menu/src/interface';
|
|
||||||
import { ColumnsType } from 'ant-design-vue/lib/table';
|
|
||||||
import { parseDateToStr } from '@/utils/date-utils';
|
|
||||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
|
||||||
import { saveAs } from 'file-saver';
|
|
||||||
import useI18n from '@/hooks/useI18n';
|
|
||||||
import { getTraceRawInfo, listTraceData } from '@/api/traceManage/analysis';
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
/**查询参数 */
|
onMounted(() => {});
|
||||||
let queryParams = reactive({
|
|
||||||
/**移动号 */
|
|
||||||
imsi: '',
|
|
||||||
/**移动号 */
|
|
||||||
msisdn: '',
|
|
||||||
/**当前页数 */
|
|
||||||
pageNum: 1,
|
|
||||||
/**每页条数 */
|
|
||||||
pageSize: 20,
|
|
||||||
});
|
|
||||||
|
|
||||||
/**查询参数重置 */
|
|
||||||
function fnQueryReset() {
|
|
||||||
queryParams = Object.assign(queryParams, {
|
|
||||||
imsi: '',
|
|
||||||
pageNum: 1,
|
|
||||||
pageSize: 20,
|
|
||||||
});
|
|
||||||
tablePagination.current = 1;
|
|
||||||
tablePagination.pageSize = 20;
|
|
||||||
fnGetList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**表格状态类型 */
|
|
||||||
type TabeStateType = {
|
|
||||||
/**加载等待 */
|
|
||||||
loading: boolean;
|
|
||||||
/**紧凑型 */
|
|
||||||
size: SizeType;
|
|
||||||
/**搜索栏 */
|
|
||||||
seached: boolean;
|
|
||||||
/**记录数据 */
|
|
||||||
data: object[];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**表格状态 */
|
|
||||||
let tableState: TabeStateType = reactive({
|
|
||||||
loading: false,
|
|
||||||
size: 'middle',
|
|
||||||
seached: true,
|
|
||||||
data: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
/**表格字段列 */
|
|
||||||
let tableColumns: ColumnsType = [
|
|
||||||
{
|
|
||||||
title: t('views.traceManage.analysis.trackTaskId'),
|
|
||||||
dataIndex: 'taskId',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('views.traceManage.analysis.imsi'),
|
|
||||||
dataIndex: 'imsi',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('views.traceManage.analysis.msisdn'),
|
|
||||||
dataIndex: 'msisdn',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('views.traceManage.analysis.srcIp'),
|
|
||||||
dataIndex: 'srcAddr',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('views.traceManage.analysis.dstIp'),
|
|
||||||
dataIndex: 'dstAddr',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('views.traceManage.analysis.signalType'),
|
|
||||||
dataIndex: 'ifType',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('views.traceManage.analysis.msgType'),
|
|
||||||
dataIndex: 'msgType',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('views.traceManage.analysis.msgDirect'),
|
|
||||||
dataIndex: 'msgDirect',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('views.traceManage.analysis.rowTime'),
|
|
||||||
dataIndex: 'timestamp',
|
|
||||||
align: 'center',
|
|
||||||
customRender(opt) {
|
|
||||||
if (!opt.value) return '';
|
|
||||||
return parseDateToStr(opt.value);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('common.operate'),
|
|
||||||
key: 'id',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
/**表格分页器参数 */
|
|
||||||
let tablePagination = reactive({
|
|
||||||
/**当前页数 */
|
|
||||||
current: 1,
|
|
||||||
/**每页条数 */
|
|
||||||
pageSize: 20,
|
|
||||||
/**默认的每页条数 */
|
|
||||||
defaultPageSize: 20,
|
|
||||||
/**指定每页可以显示多少条 */
|
|
||||||
pageSizeOptions: ['10', '20', '50', '100'],
|
|
||||||
/**只有一页时是否隐藏分页器 */
|
|
||||||
hideOnSinglePage: false,
|
|
||||||
/**是否可以快速跳转至某页 */
|
|
||||||
showQuickJumper: true,
|
|
||||||
/**是否可以改变 pageSize */
|
|
||||||
showSizeChanger: true,
|
|
||||||
/**数据总数 */
|
|
||||||
total: 0,
|
|
||||||
showTotal: (total: number) => t('common.tablePaginationTotal', { total }),
|
|
||||||
onChange: (page: number, pageSize: number) => {
|
|
||||||
tablePagination.current = page;
|
|
||||||
tablePagination.pageSize = pageSize;
|
|
||||||
queryParams.pageNum = page;
|
|
||||||
queryParams.pageSize = pageSize;
|
|
||||||
fnGetList();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
/**表格紧凑型变更操作 */
|
|
||||||
function fnTableSize({ key }: MenuInfo) {
|
|
||||||
tableState.size = key as SizeType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**查询备份信息列表, pageNum初始页数 */
|
|
||||||
function fnGetList(pageNum?: number) {
|
|
||||||
if (tableState.loading) return;
|
|
||||||
tableState.loading = true;
|
|
||||||
if (pageNum) {
|
|
||||||
queryParams.pageNum = pageNum;
|
|
||||||
}
|
|
||||||
listTraceData(toRaw(queryParams)).then(res => {
|
|
||||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
|
|
||||||
tablePagination.total = res.total;
|
|
||||||
tableState.data = res.rows;
|
|
||||||
if (
|
|
||||||
tablePagination.total <=
|
|
||||||
(queryParams.pageNum - 1) * tablePagination.pageSize &&
|
|
||||||
queryParams.pageNum !== 1
|
|
||||||
) {
|
|
||||||
tableState.loading = false;
|
|
||||||
fnGetList(queryParams.pageNum - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tableState.loading = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**抽屉对象信息状态类型 */
|
|
||||||
type ModalStateType = {
|
|
||||||
/**抽屉框是否显示 */
|
|
||||||
visible: boolean;
|
|
||||||
/**标题 */
|
|
||||||
title: string;
|
|
||||||
/**表单数据 */
|
|
||||||
from: Record<string, any>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**抽屉对象信息状态 */
|
|
||||||
let modalState: ModalStateType = reactive({
|
|
||||||
visible: false,
|
|
||||||
title: '',
|
|
||||||
from: {
|
|
||||||
rawData: '',
|
|
||||||
rawDataHTML: '',
|
|
||||||
downBtn: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对话框弹出显示
|
|
||||||
* @param row 记录信息
|
|
||||||
*/
|
|
||||||
function fnModalVisible(row: Record<string, any>) {
|
|
||||||
// 进制转数据
|
|
||||||
const hexString = parseBase64Data(row.rawMsg);
|
|
||||||
const rawData = convertToReadableFormat(hexString);
|
|
||||||
modalState.from.rawData = rawData;
|
|
||||||
// RAW解析HTML
|
|
||||||
getTraceRawInfo(row.id).then(res => {
|
|
||||||
if (res.code === RESULT_CODE_SUCCESS) {
|
|
||||||
const htmlString = rawDataHTMLScript(res.msg);
|
|
||||||
modalState.from.rawDataHTML = htmlString;
|
|
||||||
modalState.from.downBtn = true;
|
|
||||||
} else {
|
|
||||||
modalState.from.rawDataHTML = t('views.traceManage.analysis.noData');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
modalState.title = t('views.traceManage.analysis.taskTitle', {
|
|
||||||
num: row.imsi,
|
|
||||||
});
|
|
||||||
modalState.visible = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对话框弹出关闭
|
|
||||||
*/
|
|
||||||
function fnModalVisibleClose() {
|
|
||||||
modalState.visible = false;
|
|
||||||
modalState.from.downBtn = false;
|
|
||||||
modalState.from.rawDataHTML = '';
|
|
||||||
modalState.from.rawData = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将Base64编码解码为字节数组
|
|
||||||
function parseBase64Data(hexData: string) {
|
|
||||||
// 将Base64编码解码为字节数组
|
|
||||||
const byteString = atob(hexData);
|
|
||||||
const byteArray = new Uint8Array(byteString.length);
|
|
||||||
for (let i = 0; i < byteString.length; i++) {
|
|
||||||
byteArray[i] = byteString.charCodeAt(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将每一个字节转换为2位16进制数表示,并拼接起来
|
|
||||||
let hexString = '';
|
|
||||||
for (let i = 0; i < byteArray.length; i++) {
|
|
||||||
const hex = byteArray[i].toString(16);
|
|
||||||
hexString += hex.length === 1 ? '0' + hex : hex;
|
|
||||||
}
|
|
||||||
return hexString;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 转换十六进制字节流为可读格式和ASCII码表示
|
|
||||||
function convertToReadableFormat(hexString: string) {
|
|
||||||
let result = '';
|
|
||||||
let asciiResult = '';
|
|
||||||
let arr = [];
|
|
||||||
let row = 100;
|
|
||||||
for (let i = 0; i < hexString.length; i += 2) {
|
|
||||||
const hexChars = hexString.substring(i, i + 2);
|
|
||||||
const decimal = parseInt(hexChars, 16);
|
|
||||||
const asciiChar =
|
|
||||||
decimal >= 32 && decimal <= 126 ? String.fromCharCode(decimal) : '.';
|
|
||||||
|
|
||||||
result += hexChars + ' ';
|
|
||||||
asciiResult += asciiChar;
|
|
||||||
|
|
||||||
if ((i + 2) % 32 === 0) {
|
|
||||||
arr.push({
|
|
||||||
row: row,
|
|
||||||
code: result,
|
|
||||||
asciiText: asciiResult,
|
|
||||||
});
|
|
||||||
result = '';
|
|
||||||
asciiResult = '';
|
|
||||||
row += 10;
|
|
||||||
}
|
|
||||||
if (2 + i == hexString.length) {
|
|
||||||
arr.push({
|
|
||||||
row: row,
|
|
||||||
code: result,
|
|
||||||
asciiText: asciiResult,
|
|
||||||
});
|
|
||||||
result = '';
|
|
||||||
asciiResult = '';
|
|
||||||
row += 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 信息详情HTMl内容处理
|
|
||||||
function rawDataHTMLScript(htmlString: string) {
|
|
||||||
// 删除所有 <a> 标签
|
|
||||||
// const withoutATags = htmlString.replace(/<a\b[^>]*>(.*?)<\/a>/gi, '');
|
|
||||||
// 删除所有 <script> 标签
|
|
||||||
let withoutScriptTags = htmlString.replace(
|
|
||||||
/<script\b[^>]*>([\s\S]*?)<\/script>/gi,
|
|
||||||
''
|
|
||||||
);
|
|
||||||
// 默认全展开
|
|
||||||
// const withoutHiddenElements = withoutScriptTags.replace(
|
|
||||||
// /style="display:none"/gi,
|
|
||||||
// 'style="background:#ffffff"'
|
|
||||||
// );
|
|
||||||
|
|
||||||
function set_node(node: any, str: string) {
|
|
||||||
if (!node) return;
|
|
||||||
node.style.display = str;
|
|
||||||
node.style.background = '#ffffff';
|
|
||||||
}
|
|
||||||
Reflect.set(window, 'set_node', set_node);
|
|
||||||
function toggle_node(node: any) {
|
|
||||||
node = document.getElementById(node);
|
|
||||||
if (!node) return;
|
|
||||||
set_node(node, node.style.display != 'none' ? 'none' : 'block');
|
|
||||||
}
|
|
||||||
Reflect.set(window, 'toggle_node', toggle_node);
|
|
||||||
function hide_node(node: any) {
|
|
||||||
node = document.getElementById(node);
|
|
||||||
if (!node) return;
|
|
||||||
set_node(node, 'none');
|
|
||||||
}
|
|
||||||
Reflect.set(window, 'hide_node', hide_node);
|
|
||||||
|
|
||||||
// 展开第一个
|
|
||||||
withoutScriptTags = withoutScriptTags.replace(
|
|
||||||
'id="f1c" style="display:none"',
|
|
||||||
'id="f1c" style="display:block"'
|
|
||||||
);
|
|
||||||
return withoutScriptTags;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**信息文件下载 */
|
|
||||||
function fnDownloadFile() {
|
|
||||||
Modal.confirm({
|
|
||||||
title: t('common.tipTitle'),
|
|
||||||
content: t('views.traceManage.analysis.taskDownTip'),
|
|
||||||
onOk() {
|
|
||||||
const blob = new Blob([modalState.from.rawDataHTML], {
|
|
||||||
type: 'text/plain',
|
|
||||||
});
|
|
||||||
saveAs(blob, `${modalState.title}_${Date.now()}.html`);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
// 获取列表数据
|
|
||||||
fnGetList();
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<PageContainer>
|
<PageContainer>
|
||||||
<a-card
|
|
||||||
v-show="tableState.seached"
|
|
||||||
:bordered="false"
|
|
||||||
:body-style="{ marginBottom: '24px', paddingBottom: 0 }"
|
|
||||||
>
|
|
||||||
<!-- 表格搜索栏 -->
|
|
||||||
<a-form :model="queryParams" name="queryParams" layout="horizontal">
|
|
||||||
<a-row :gutter="16">
|
|
||||||
<a-col :lg="6" :md="12" :xs="24">
|
|
||||||
<a-form-item
|
|
||||||
:label="t('views.traceManage.analysis.imsi')"
|
|
||||||
name="imsi"
|
|
||||||
>
|
|
||||||
<a-input
|
|
||||||
v-model:value="queryParams.imsi"
|
|
||||||
:allow-clear="true"
|
|
||||||
:placeholder="t('views.traceManage.analysis.imsiPlease')"
|
|
||||||
></a-input>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
<a-col :lg="6" :md="12" :xs="24">
|
|
||||||
<a-form-item
|
|
||||||
:label="t('views.traceManage.analysis.msisdn')"
|
|
||||||
name="imsi"
|
|
||||||
>
|
|
||||||
<a-input
|
|
||||||
v-model:value="queryParams.msisdn"
|
|
||||||
:allow-clear="true"
|
|
||||||
:placeholder="t('views.traceManage.analysis.msisdnPlease')"
|
|
||||||
></a-input>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
<a-col :lg="6" :md="12" :xs="24">
|
|
||||||
<a-form-item>
|
|
||||||
<a-space :size="8">
|
|
||||||
<a-button type="primary" @click.prevent="fnGetList(1)">
|
|
||||||
<template #icon><SearchOutlined /></template>
|
|
||||||
{{ t('common.search') }}
|
|
||||||
</a-button>
|
|
||||||
<a-button type="default" @click.prevent="fnQueryReset">
|
|
||||||
<template #icon><ClearOutlined /></template>
|
|
||||||
{{ t('common.reset') }}
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
</a-form>
|
|
||||||
</a-card>
|
|
||||||
|
|
||||||
<a-card :bordered="false" :body-style="{ padding: '0px' }">
|
<a-card :bordered="false" :body-style="{ padding: '0px' }">
|
||||||
<!-- 插槽-卡片左侧侧 -->
|
<h1>Perf Report</h1>
|
||||||
<template #title> </template>
|
|
||||||
|
|
||||||
<!-- 插槽-卡片右侧 -->
|
|
||||||
<template #extra>
|
|
||||||
<a-space :size="8" align="center">
|
|
||||||
<a-tooltip>
|
|
||||||
<template #title>{{ t('common.searchBarText') }}</template>
|
|
||||||
<a-switch
|
|
||||||
v-model:checked="tableState.seached"
|
|
||||||
:checked-children="t('common.switch.show')"
|
|
||||||
:un-checked-children="t('common.switch.hide')"
|
|
||||||
size="small"
|
|
||||||
/>
|
|
||||||
</a-tooltip>
|
|
||||||
<a-tooltip>
|
|
||||||
<template #title>{{ t('common.reloadText') }}</template>
|
|
||||||
<a-button type="text" @click.prevent="fnGetList()">
|
|
||||||
<template #icon><ReloadOutlined /></template>
|
|
||||||
</a-button>
|
|
||||||
</a-tooltip>
|
|
||||||
<a-tooltip>
|
|
||||||
<template #title>{{ t('common.sizeText') }}</template>
|
|
||||||
<a-dropdown trigger="click">
|
|
||||||
<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: true }"
|
|
||||||
>
|
|
||||||
<template #bodyCell="{ column, record }">
|
|
||||||
<template v-if="column.key === 'id'">
|
|
||||||
<a-space :size="8" align="center">
|
|
||||||
<a-tooltip>
|
|
||||||
<template #title>查看详情</template>
|
|
||||||
<a-button type="link" @click.prevent="fnModalVisible(record)">
|
|
||||||
<template #icon><ProfileOutlined /></template>
|
|
||||||
</a-button>
|
|
||||||
</a-tooltip>
|
|
||||||
</a-space>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
</a-table>
|
|
||||||
</a-card>
|
</a-card>
|
||||||
|
|
||||||
<!-- 详情框 -->
|
|
||||||
<ProModal
|
|
||||||
:drag="true"
|
|
||||||
:width="800"
|
|
||||||
:title="modalState.title"
|
|
||||||
:visible="modalState.visible"
|
|
||||||
@cancel="fnModalVisibleClose"
|
|
||||||
>
|
|
||||||
<div class="raw-title">
|
|
||||||
{{ t('views.traceManage.analysis.signalData') }}
|
|
||||||
</div>
|
|
||||||
<a-row
|
|
||||||
class="raw"
|
|
||||||
:gutter="16"
|
|
||||||
v-for="v in modalState.from.rawData"
|
|
||||||
:key="v.row"
|
|
||||||
>
|
|
||||||
<a-col class="num" :span="2">{{ v.row }}</a-col>
|
|
||||||
<a-col class="code" :span="12">{{ v.code }}</a-col>
|
|
||||||
<a-col class="txt" :span="10">{{ v.asciiText }}</a-col>
|
|
||||||
</a-row>
|
|
||||||
<a-divider />
|
|
||||||
<div class="raw-title">
|
|
||||||
{{ t('views.traceManage.analysis.signalDetail') }}
|
|
||||||
<a-button
|
|
||||||
type="dashed"
|
|
||||||
size="small"
|
|
||||||
@click.prevent="fnDownloadFile"
|
|
||||||
v-if="modalState.from.downBtn"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<DownloadOutlined />
|
|
||||||
</template>
|
|
||||||
{{ t('views.traceManage.analysis.taskDownText') }}
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
<div class="raw-html" v-html="modalState.from.rawDataHTML"></div>
|
|
||||||
</ProModal>
|
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped></style>
|
||||||
.table :deep(.ant-pagination) {
|
|
||||||
padding: 0 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.raw {
|
|
||||||
&-title {
|
|
||||||
color: #000000d9;
|
|
||||||
font-size: 24px;
|
|
||||||
line-height: 1.8;
|
|
||||||
}
|
|
||||||
.num {
|
|
||||||
background-color: #e5e5e5;
|
|
||||||
}
|
|
||||||
.code {
|
|
||||||
background-color: #e7e6ff;
|
|
||||||
}
|
|
||||||
.txt {
|
|
||||||
background-color: #ffe3e5;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-html {
|
|
||||||
max-height: 300px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1,543 +1,16 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive, onMounted, toRaw } from 'vue';
|
import { onMounted } from 'vue';
|
||||||
import { PageContainer } from 'antdv-pro-layout';
|
import { PageContainer } from 'antdv-pro-layout';
|
||||||
import { Modal } from 'ant-design-vue/lib';
|
|
||||||
import { SizeType } from 'ant-design-vue/lib/config-provider';
|
|
||||||
import { MenuInfo } from 'ant-design-vue/lib/menu/src/interface';
|
|
||||||
import { ColumnsType } from 'ant-design-vue/lib/table';
|
|
||||||
import { parseDateToStr } from '@/utils/date-utils';
|
|
||||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
|
||||||
import { saveAs } from 'file-saver';
|
|
||||||
import useI18n from '@/hooks/useI18n';
|
|
||||||
import { getTraceRawInfo, listTraceData } from '@/api/traceManage/analysis';
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
/**查询参数 */
|
onMounted(() => {});
|
||||||
let queryParams = reactive({
|
|
||||||
/**移动号 */
|
|
||||||
imsi: '',
|
|
||||||
/**移动号 */
|
|
||||||
msisdn: '',
|
|
||||||
/**当前页数 */
|
|
||||||
pageNum: 1,
|
|
||||||
/**每页条数 */
|
|
||||||
pageSize: 20,
|
|
||||||
});
|
|
||||||
|
|
||||||
/**查询参数重置 */
|
|
||||||
function fnQueryReset() {
|
|
||||||
queryParams = Object.assign(queryParams, {
|
|
||||||
imsi: '',
|
|
||||||
pageNum: 1,
|
|
||||||
pageSize: 20,
|
|
||||||
});
|
|
||||||
tablePagination.current = 1;
|
|
||||||
tablePagination.pageSize = 20;
|
|
||||||
fnGetList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**表格状态类型 */
|
|
||||||
type TabeStateType = {
|
|
||||||
/**加载等待 */
|
|
||||||
loading: boolean;
|
|
||||||
/**紧凑型 */
|
|
||||||
size: SizeType;
|
|
||||||
/**搜索栏 */
|
|
||||||
seached: boolean;
|
|
||||||
/**记录数据 */
|
|
||||||
data: object[];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**表格状态 */
|
|
||||||
let tableState: TabeStateType = reactive({
|
|
||||||
loading: false,
|
|
||||||
size: 'middle',
|
|
||||||
seached: true,
|
|
||||||
data: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
/**表格字段列 */
|
|
||||||
let tableColumns: ColumnsType = [
|
|
||||||
{
|
|
||||||
title: t('views.traceManage.analysis.trackTaskId'),
|
|
||||||
dataIndex: 'taskId',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('views.traceManage.analysis.imsi'),
|
|
||||||
dataIndex: 'imsi',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('views.traceManage.analysis.msisdn'),
|
|
||||||
dataIndex: 'msisdn',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('views.traceManage.analysis.srcIp'),
|
|
||||||
dataIndex: 'srcAddr',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('views.traceManage.analysis.dstIp'),
|
|
||||||
dataIndex: 'dstAddr',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('views.traceManage.analysis.signalType'),
|
|
||||||
dataIndex: 'ifType',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('views.traceManage.analysis.msgType'),
|
|
||||||
dataIndex: 'msgType',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('views.traceManage.analysis.msgDirect'),
|
|
||||||
dataIndex: 'msgDirect',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('views.traceManage.analysis.rowTime'),
|
|
||||||
dataIndex: 'timestamp',
|
|
||||||
align: 'center',
|
|
||||||
customRender(opt) {
|
|
||||||
if (!opt.value) return '';
|
|
||||||
return parseDateToStr(opt.value);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('common.operate'),
|
|
||||||
key: 'id',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
/**表格分页器参数 */
|
|
||||||
let tablePagination = reactive({
|
|
||||||
/**当前页数 */
|
|
||||||
current: 1,
|
|
||||||
/**每页条数 */
|
|
||||||
pageSize: 20,
|
|
||||||
/**默认的每页条数 */
|
|
||||||
defaultPageSize: 20,
|
|
||||||
/**指定每页可以显示多少条 */
|
|
||||||
pageSizeOptions: ['10', '20', '50', '100'],
|
|
||||||
/**只有一页时是否隐藏分页器 */
|
|
||||||
hideOnSinglePage: false,
|
|
||||||
/**是否可以快速跳转至某页 */
|
|
||||||
showQuickJumper: true,
|
|
||||||
/**是否可以改变 pageSize */
|
|
||||||
showSizeChanger: true,
|
|
||||||
/**数据总数 */
|
|
||||||
total: 0,
|
|
||||||
showTotal: (total: number) => t('common.tablePaginationTotal', { total }),
|
|
||||||
onChange: (page: number, pageSize: number) => {
|
|
||||||
tablePagination.current = page;
|
|
||||||
tablePagination.pageSize = pageSize;
|
|
||||||
queryParams.pageNum = page;
|
|
||||||
queryParams.pageSize = pageSize;
|
|
||||||
fnGetList();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
/**表格紧凑型变更操作 */
|
|
||||||
function fnTableSize({ key }: MenuInfo) {
|
|
||||||
tableState.size = key as SizeType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**查询备份信息列表, pageNum初始页数 */
|
|
||||||
function fnGetList(pageNum?: number) {
|
|
||||||
if (tableState.loading) return;
|
|
||||||
tableState.loading = true;
|
|
||||||
if (pageNum) {
|
|
||||||
queryParams.pageNum = pageNum;
|
|
||||||
}
|
|
||||||
listTraceData(toRaw(queryParams)).then(res => {
|
|
||||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
|
|
||||||
tablePagination.total = res.total;
|
|
||||||
tableState.data = res.rows;
|
|
||||||
if (
|
|
||||||
tablePagination.total <=
|
|
||||||
(queryParams.pageNum - 1) * tablePagination.pageSize &&
|
|
||||||
queryParams.pageNum !== 1
|
|
||||||
) {
|
|
||||||
tableState.loading = false;
|
|
||||||
fnGetList(queryParams.pageNum - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tableState.loading = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**抽屉对象信息状态类型 */
|
|
||||||
type ModalStateType = {
|
|
||||||
/**抽屉框是否显示 */
|
|
||||||
visible: boolean;
|
|
||||||
/**标题 */
|
|
||||||
title: string;
|
|
||||||
/**表单数据 */
|
|
||||||
from: Record<string, any>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**抽屉对象信息状态 */
|
|
||||||
let modalState: ModalStateType = reactive({
|
|
||||||
visible: false,
|
|
||||||
title: '',
|
|
||||||
from: {
|
|
||||||
rawData: '',
|
|
||||||
rawDataHTML: '',
|
|
||||||
downBtn: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对话框弹出显示
|
|
||||||
* @param row 记录信息
|
|
||||||
*/
|
|
||||||
function fnModalVisible(row: Record<string, any>) {
|
|
||||||
// 进制转数据
|
|
||||||
const hexString = parseBase64Data(row.rawMsg);
|
|
||||||
const rawData = convertToReadableFormat(hexString);
|
|
||||||
modalState.from.rawData = rawData;
|
|
||||||
// RAW解析HTML
|
|
||||||
getTraceRawInfo(row.id).then(res => {
|
|
||||||
if (res.code === RESULT_CODE_SUCCESS) {
|
|
||||||
const htmlString = rawDataHTMLScript(res.msg);
|
|
||||||
modalState.from.rawDataHTML = htmlString;
|
|
||||||
modalState.from.downBtn = true;
|
|
||||||
} else {
|
|
||||||
modalState.from.rawDataHTML = t('views.traceManage.analysis.noData');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
modalState.title = t('views.traceManage.analysis.taskTitle', {
|
|
||||||
num: row.imsi,
|
|
||||||
});
|
|
||||||
modalState.visible = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对话框弹出关闭
|
|
||||||
*/
|
|
||||||
function fnModalVisibleClose() {
|
|
||||||
modalState.visible = false;
|
|
||||||
modalState.from.downBtn = false;
|
|
||||||
modalState.from.rawDataHTML = '';
|
|
||||||
modalState.from.rawData = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将Base64编码解码为字节数组
|
|
||||||
function parseBase64Data(hexData: string) {
|
|
||||||
// 将Base64编码解码为字节数组
|
|
||||||
const byteString = atob(hexData);
|
|
||||||
const byteArray = new Uint8Array(byteString.length);
|
|
||||||
for (let i = 0; i < byteString.length; i++) {
|
|
||||||
byteArray[i] = byteString.charCodeAt(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将每一个字节转换为2位16进制数表示,并拼接起来
|
|
||||||
let hexString = '';
|
|
||||||
for (let i = 0; i < byteArray.length; i++) {
|
|
||||||
const hex = byteArray[i].toString(16);
|
|
||||||
hexString += hex.length === 1 ? '0' + hex : hex;
|
|
||||||
}
|
|
||||||
return hexString;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 转换十六进制字节流为可读格式和ASCII码表示
|
|
||||||
function convertToReadableFormat(hexString: string) {
|
|
||||||
let result = '';
|
|
||||||
let asciiResult = '';
|
|
||||||
let arr = [];
|
|
||||||
let row = 100;
|
|
||||||
for (let i = 0; i < hexString.length; i += 2) {
|
|
||||||
const hexChars = hexString.substring(i, i + 2);
|
|
||||||
const decimal = parseInt(hexChars, 16);
|
|
||||||
const asciiChar =
|
|
||||||
decimal >= 32 && decimal <= 126 ? String.fromCharCode(decimal) : '.';
|
|
||||||
|
|
||||||
result += hexChars + ' ';
|
|
||||||
asciiResult += asciiChar;
|
|
||||||
|
|
||||||
if ((i + 2) % 32 === 0) {
|
|
||||||
arr.push({
|
|
||||||
row: row,
|
|
||||||
code: result,
|
|
||||||
asciiText: asciiResult,
|
|
||||||
});
|
|
||||||
result = '';
|
|
||||||
asciiResult = '';
|
|
||||||
row += 10;
|
|
||||||
}
|
|
||||||
if (2 + i == hexString.length) {
|
|
||||||
arr.push({
|
|
||||||
row: row,
|
|
||||||
code: result,
|
|
||||||
asciiText: asciiResult,
|
|
||||||
});
|
|
||||||
result = '';
|
|
||||||
asciiResult = '';
|
|
||||||
row += 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 信息详情HTMl内容处理
|
|
||||||
function rawDataHTMLScript(htmlString: string) {
|
|
||||||
// 删除所有 <a> 标签
|
|
||||||
// const withoutATags = htmlString.replace(/<a\b[^>]*>(.*?)<\/a>/gi, '');
|
|
||||||
// 删除所有 <script> 标签
|
|
||||||
let withoutScriptTags = htmlString.replace(
|
|
||||||
/<script\b[^>]*>([\s\S]*?)<\/script>/gi,
|
|
||||||
''
|
|
||||||
);
|
|
||||||
// 默认全展开
|
|
||||||
// const withoutHiddenElements = withoutScriptTags.replace(
|
|
||||||
// /style="display:none"/gi,
|
|
||||||
// 'style="background:#ffffff"'
|
|
||||||
// );
|
|
||||||
|
|
||||||
function set_node(node: any, str: string) {
|
|
||||||
if (!node) return;
|
|
||||||
node.style.display = str;
|
|
||||||
node.style.background = '#ffffff';
|
|
||||||
}
|
|
||||||
Reflect.set(window, 'set_node', set_node);
|
|
||||||
function toggle_node(node: any) {
|
|
||||||
node = document.getElementById(node);
|
|
||||||
if (!node) return;
|
|
||||||
set_node(node, node.style.display != 'none' ? 'none' : 'block');
|
|
||||||
}
|
|
||||||
Reflect.set(window, 'toggle_node', toggle_node);
|
|
||||||
function hide_node(node: any) {
|
|
||||||
node = document.getElementById(node);
|
|
||||||
if (!node) return;
|
|
||||||
set_node(node, 'none');
|
|
||||||
}
|
|
||||||
Reflect.set(window, 'hide_node', hide_node);
|
|
||||||
|
|
||||||
// 展开第一个
|
|
||||||
withoutScriptTags = withoutScriptTags.replace(
|
|
||||||
'id="f1c" style="display:none"',
|
|
||||||
'id="f1c" style="display:block"'
|
|
||||||
);
|
|
||||||
return withoutScriptTags;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**信息文件下载 */
|
|
||||||
function fnDownloadFile() {
|
|
||||||
Modal.confirm({
|
|
||||||
title: t('common.tipTitle'),
|
|
||||||
content: t('views.traceManage.analysis.taskDownTip'),
|
|
||||||
onOk() {
|
|
||||||
const blob = new Blob([modalState.from.rawDataHTML], {
|
|
||||||
type: 'text/plain',
|
|
||||||
});
|
|
||||||
saveAs(blob, `${modalState.title}_${Date.now()}.html`);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
// 获取列表数据
|
|
||||||
fnGetList();
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<PageContainer>
|
<PageContainer>
|
||||||
<a-card
|
|
||||||
v-show="tableState.seached"
|
|
||||||
:bordered="false"
|
|
||||||
:body-style="{ marginBottom: '24px', paddingBottom: 0 }"
|
|
||||||
>
|
|
||||||
<!-- 表格搜索栏 -->
|
|
||||||
<a-form :model="queryParams" name="queryParams" layout="horizontal">
|
|
||||||
<a-row :gutter="16">
|
|
||||||
<a-col :lg="6" :md="12" :xs="24">
|
|
||||||
<a-form-item
|
|
||||||
:label="t('views.traceManage.analysis.imsi')"
|
|
||||||
name="imsi"
|
|
||||||
>
|
|
||||||
<a-input
|
|
||||||
v-model:value="queryParams.imsi"
|
|
||||||
:allow-clear="true"
|
|
||||||
:placeholder="t('views.traceManage.analysis.imsiPlease')"
|
|
||||||
></a-input>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
<a-col :lg="6" :md="12" :xs="24">
|
|
||||||
<a-form-item
|
|
||||||
:label="t('views.traceManage.analysis.msisdn')"
|
|
||||||
name="imsi"
|
|
||||||
>
|
|
||||||
<a-input
|
|
||||||
v-model:value="queryParams.msisdn"
|
|
||||||
:allow-clear="true"
|
|
||||||
:placeholder="t('views.traceManage.analysis.msisdnPlease')"
|
|
||||||
></a-input>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
<a-col :lg="6" :md="12" :xs="24">
|
|
||||||
<a-form-item>
|
|
||||||
<a-space :size="8">
|
|
||||||
<a-button type="primary" @click.prevent="fnGetList(1)">
|
|
||||||
<template #icon><SearchOutlined /></template>
|
|
||||||
{{ t('common.search') }}
|
|
||||||
</a-button>
|
|
||||||
<a-button type="default" @click.prevent="fnQueryReset">
|
|
||||||
<template #icon><ClearOutlined /></template>
|
|
||||||
{{ t('common.reset') }}
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
</a-form>
|
|
||||||
</a-card>
|
|
||||||
|
|
||||||
<a-card :bordered="false" :body-style="{ padding: '0px' }">
|
<a-card :bordered="false" :body-style="{ padding: '0px' }">
|
||||||
<!-- 插槽-卡片左侧侧 -->
|
<h1>Perf Set</h1>
|
||||||
<template #title> </template>
|
|
||||||
|
|
||||||
<!-- 插槽-卡片右侧 -->
|
|
||||||
<template #extra>
|
|
||||||
<a-space :size="8" align="center">
|
|
||||||
<a-tooltip>
|
|
||||||
<template #title>{{ t('common.searchBarText') }}</template>
|
|
||||||
<a-switch
|
|
||||||
v-model:checked="tableState.seached"
|
|
||||||
:checked-children="t('common.switch.show')"
|
|
||||||
:un-checked-children="t('common.switch.hide')"
|
|
||||||
size="small"
|
|
||||||
/>
|
|
||||||
</a-tooltip>
|
|
||||||
<a-tooltip>
|
|
||||||
<template #title>{{ t('common.reloadText') }}</template>
|
|
||||||
<a-button type="text" @click.prevent="fnGetList()">
|
|
||||||
<template #icon><ReloadOutlined /></template>
|
|
||||||
</a-button>
|
|
||||||
</a-tooltip>
|
|
||||||
<a-tooltip>
|
|
||||||
<template #title>{{ t('common.sizeText') }}</template>
|
|
||||||
<a-dropdown trigger="click">
|
|
||||||
<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: true }"
|
|
||||||
>
|
|
||||||
<template #bodyCell="{ column, record }">
|
|
||||||
<template v-if="column.key === 'id'">
|
|
||||||
<a-space :size="8" align="center">
|
|
||||||
<a-tooltip>
|
|
||||||
<template #title>查看详情</template>
|
|
||||||
<a-button type="link" @click.prevent="fnModalVisible(record)">
|
|
||||||
<template #icon><ProfileOutlined /></template>
|
|
||||||
</a-button>
|
|
||||||
</a-tooltip>
|
|
||||||
</a-space>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
</a-table>
|
|
||||||
</a-card>
|
</a-card>
|
||||||
|
|
||||||
<!-- 详情框 -->
|
|
||||||
<ProModal
|
|
||||||
:drag="true"
|
|
||||||
:width="800"
|
|
||||||
:title="modalState.title"
|
|
||||||
:visible="modalState.visible"
|
|
||||||
@cancel="fnModalVisibleClose"
|
|
||||||
>
|
|
||||||
<div class="raw-title">
|
|
||||||
{{ t('views.traceManage.analysis.signalData') }}
|
|
||||||
</div>
|
|
||||||
<a-row
|
|
||||||
class="raw"
|
|
||||||
:gutter="16"
|
|
||||||
v-for="v in modalState.from.rawData"
|
|
||||||
:key="v.row"
|
|
||||||
>
|
|
||||||
<a-col class="num" :span="2">{{ v.row }}</a-col>
|
|
||||||
<a-col class="code" :span="12">{{ v.code }}</a-col>
|
|
||||||
<a-col class="txt" :span="10">{{ v.asciiText }}</a-col>
|
|
||||||
</a-row>
|
|
||||||
<a-divider />
|
|
||||||
<div class="raw-title">
|
|
||||||
{{ t('views.traceManage.analysis.signalDetail') }}
|
|
||||||
<a-button
|
|
||||||
type="dashed"
|
|
||||||
size="small"
|
|
||||||
@click.prevent="fnDownloadFile"
|
|
||||||
v-if="modalState.from.downBtn"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<DownloadOutlined />
|
|
||||||
</template>
|
|
||||||
{{ t('views.traceManage.analysis.taskDownText') }}
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
<div class="raw-html" v-html="modalState.from.rawDataHTML"></div>
|
|
||||||
</ProModal>
|
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped></style>
|
||||||
.table :deep(.ant-pagination) {
|
|
||||||
padding: 0 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.raw {
|
|
||||||
&-title {
|
|
||||||
color: #000000d9;
|
|
||||||
font-size: 24px;
|
|
||||||
line-height: 1.8;
|
|
||||||
}
|
|
||||||
.num {
|
|
||||||
background-color: #e5e5e5;
|
|
||||||
}
|
|
||||||
.code {
|
|
||||||
background-color: #e7e6ff;
|
|
||||||
}
|
|
||||||
.txt {
|
|
||||||
background-color: #ffe3e5;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-html {
|
|
||||||
max-height: 300px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user