Compare commits
376 Commits
2.2402.5-2
...
r2.2405.4-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
618499e777 | ||
|
|
71c0306587 | ||
|
|
a3cd8f05fb | ||
|
|
d8ca0ca5ef | ||
|
|
da08e1cc5b | ||
|
|
8e4c5d0b90 | ||
|
|
467c93f710 | ||
|
|
22ced8bdb2 | ||
|
|
2ee26a6958 | ||
|
|
c63e892544 | ||
|
|
cce3088f73 | ||
|
|
2211896768 | ||
|
|
5bb3cd814c | ||
|
|
266d816a21 | ||
|
|
90c64c029a | ||
|
|
d06e2da72e | ||
|
|
7714d506c4 | ||
|
|
0b7a198235 | ||
|
|
68362ba3e3 | ||
|
|
a9633e652f | ||
|
|
6592561bca | ||
|
|
09e0353053 | ||
|
|
c1e95fd1e9 | ||
|
|
89857e0c1b | ||
|
|
7aa37ee330 | ||
|
|
4c16888184 | ||
|
|
a61716d40d | ||
|
|
3f02cb628b | ||
|
|
22805924fb | ||
|
|
e00229e5ff | ||
|
|
939a235a87 | ||
|
|
cd49162dfc | ||
|
|
b7f2df5d1c | ||
|
|
8b24bc55b9 | ||
|
|
9f2b80718e | ||
|
|
38cb406687 | ||
|
|
c25fe63a26 | ||
|
|
b84d6bb9fc | ||
|
|
b325cde5c0 | ||
|
|
34266da44e | ||
|
|
d82d6b7b47 | ||
|
|
b1c7a068cf | ||
|
|
c155160cf7 | ||
|
|
2ae4559958 | ||
|
|
782283bba6 | ||
|
|
1b50708786 | ||
|
|
206d3755a0 | ||
|
|
6470effbda | ||
|
|
f94b1ef44a | ||
|
|
7c78eab431 | ||
|
|
814b7b0058 | ||
|
|
624f67ecca | ||
|
|
c1a9497b77 | ||
|
|
1ad2ed2d26 | ||
|
|
48f278997f | ||
|
|
9b9d6222e1 | ||
|
|
2e8a878365 | ||
|
|
bc59dc67e6 | ||
|
|
df6022b4a8 | ||
|
|
f2c67d087b | ||
|
|
7a0298a419 | ||
|
|
b40e798090 | ||
|
|
d48d5d6c95 | ||
|
|
69f3347a4d | ||
|
|
85ae7dc5ea | ||
|
|
531cd6d03d | ||
|
|
9fd8c4597a | ||
|
|
7060a3d887 | ||
|
|
c12ffa583c | ||
|
|
05aabb8c61 | ||
|
|
6b461ead7c | ||
|
|
7c54e372e5 | ||
|
|
5be95a7af6 | ||
|
|
08515541b4 | ||
|
|
3948924f61 | ||
|
|
ce1944881a | ||
|
|
f6122c0758 | ||
|
|
3d3f4c2cc6 | ||
|
|
e8e5b92a57 | ||
|
|
4ad704398d | ||
|
|
26289b7787 | ||
|
|
7ad8c1706e | ||
|
|
424a596613 | ||
|
|
6d5b9f417c | ||
|
|
7278e24dce | ||
|
|
76839ae18a | ||
|
|
c8a6aa3210 | ||
|
|
9b4bbcedc5 | ||
|
|
3b793c107c | ||
|
|
a076e6d079 | ||
|
|
fb2a7c51f9 | ||
|
|
1e2c2b5170 | ||
|
|
56833b654e | ||
|
|
f50e02e6e7 | ||
|
|
52cc24813f | ||
|
|
c8a0d4c3f7 | ||
|
|
7560f21f11 | ||
|
|
8a5f80fe47 | ||
|
|
29eb1f08b1 | ||
|
|
9981de2271 | ||
|
|
207acb3f3d | ||
|
|
873a76f48f | ||
|
|
4ca700092a | ||
|
|
ad9f8574bd | ||
|
|
75faae6d7c | ||
|
|
c88c146a5e | ||
|
|
c65cda1468 | ||
|
|
d8059341fe | ||
|
|
ad86bee5f9 | ||
|
|
f44cc44a1b | ||
|
|
ad93588796 | ||
|
|
b5f6a5d24a | ||
|
|
fa4be253f7 | ||
|
|
2db0220c98 | ||
|
|
05fd678ce2 | ||
|
|
165b28bab1 | ||
|
|
dc67cdc262 | ||
|
|
c97394a0ed | ||
|
|
6b9297d30e | ||
|
|
ace7f26b53 | ||
|
|
976f72f79a | ||
|
|
530e7fd43f | ||
|
|
b76fed7dcf | ||
|
|
60a26dd015 | ||
|
|
7bdfc257c1 | ||
|
|
e3395b47cf | ||
|
|
4c9b4de12f | ||
|
|
1cfe5e2777 | ||
|
|
0cae26a1ee | ||
|
|
ed4d556384 | ||
|
|
6d9d7362a4 | ||
|
|
5a40733f20 | ||
|
|
45ee884529 | ||
|
|
7de3f7f05d | ||
|
|
97bb4db1eb | ||
|
|
fc6dfe9894 | ||
|
|
607660124a | ||
|
|
c50b3add95 | ||
|
|
2f7f0e9e20 | ||
|
|
6875ffd113 | ||
|
|
44844bfa7f | ||
|
|
21ab066761 | ||
|
|
83bdf289fa | ||
|
|
d7aa0fc91a | ||
|
|
a6be5190ec | ||
|
|
03cd06e835 | ||
|
|
2d7fe5a73b | ||
|
|
dd5604c8b7 | ||
|
|
7bf2672981 | ||
|
|
6e616c63f0 | ||
|
|
3ded481cce | ||
|
|
1baff582d8 | ||
|
|
957868cc27 | ||
|
|
efb98ac577 | ||
|
|
ff228daae7 | ||
|
|
c93e693517 | ||
|
|
55863c1c58 | ||
|
|
8a2d6c91ba | ||
|
|
86a939f206 | ||
|
|
2b86f724b1 | ||
|
|
68fbc45b7c | ||
|
|
4629ef28ff | ||
|
|
e3a11b0ede | ||
|
|
3df9ee4f3a | ||
|
|
e64d558c27 | ||
|
|
5a2aa383fe | ||
|
|
fe9f458465 | ||
|
|
8e2e9aec67 | ||
|
|
ad48e8e2e1 | ||
|
|
6f8b1000ba | ||
|
|
f5549992c2 | ||
|
|
19771ea6dc | ||
|
|
5965737384 | ||
|
|
b3cb40fd8c | ||
|
|
0ab5141369 | ||
|
|
a23284da4c | ||
|
|
1c8cc13436 | ||
|
|
e6a439faea | ||
|
|
f8b1b1f6c3 | ||
|
|
3844e07258 | ||
|
|
1fab9b3d97 | ||
|
|
1bfacbf2e0 | ||
|
|
c01f9f3830 | ||
|
|
28f9d365fd | ||
|
|
1085fa16aa | ||
|
|
e351960229 | ||
|
|
03caa354da | ||
|
|
34754ea0b6 | ||
|
|
86e1f07f08 | ||
|
|
2add7547d6 | ||
|
|
ecb89e9f26 | ||
|
|
7a9b38dc66 | ||
|
|
979b18092d | ||
|
|
ba43a647dd | ||
|
|
3be14590c6 | ||
|
|
857f8c4313 | ||
|
|
c9c39d2d4a | ||
|
|
845084f77f | ||
|
|
becba4919e | ||
|
|
b797055df9 | ||
|
|
8101c852c8 | ||
|
|
9bbeb9fc9a | ||
|
|
19a9bd3f5c | ||
|
|
399bddc635 | ||
|
|
5a67a1a51c | ||
|
|
9a168d2ba0 | ||
|
|
e42a620aed | ||
|
|
eb902594b8 | ||
|
|
817fd97496 | ||
|
|
96aab47003 | ||
|
|
432666b1ab | ||
|
|
662583c73b | ||
|
|
f73c21e6e6 | ||
|
|
17e72f1db1 | ||
|
|
55d4a36efb | ||
|
|
d3794ba904 | ||
|
|
832f18e2ee | ||
|
|
cd2e282624 | ||
|
|
3db88f1d3a | ||
|
|
f291bb0907 | ||
|
|
69c32b2593 | ||
|
|
1a2939ab01 | ||
|
|
8bf4a2a9ce | ||
|
|
efd389f98a | ||
|
|
f1125cc042 | ||
|
|
f1a0e200dc | ||
|
|
70c025f0f5 | ||
|
|
b9f0a3923d | ||
|
|
5c942c9ef7 | ||
|
|
4294fe82c5 | ||
|
|
4e7fb90544 | ||
|
|
f050e500e9 | ||
|
|
6bc10babba | ||
|
|
4d36f9952a | ||
|
|
b03f4bb1d6 | ||
|
|
4aaedf0f77 | ||
|
|
c1ea851705 | ||
|
|
47103249ef | ||
|
|
2642f18204 | ||
|
|
e2e22eabf5 | ||
|
|
325ecc8029 | ||
|
|
dc6f4560d5 | ||
|
|
3970797d5b | ||
|
|
73776ed0f9 | ||
|
|
aca842f8c2 | ||
|
|
612fb77861 | ||
|
|
6ba695ceaf | ||
|
|
070f77d3b8 | ||
|
|
15de63212f | ||
|
|
2202540763 | ||
|
|
c674b9b3f9 | ||
|
|
43d30e7bfa | ||
|
|
cd0633d519 | ||
|
|
b8bff2a159 | ||
|
|
638f890228 | ||
|
|
4460f7201c | ||
|
|
d0bbfafedc | ||
|
|
16dc1c2e20 | ||
|
|
73ed5f5285 | ||
|
|
50cb92a95b | ||
|
|
3888fd2bca | ||
|
|
4194d8cca6 | ||
|
|
ac84a0ca0a | ||
|
|
e6faa59f32 | ||
|
|
65fab4de1b | ||
| b044f01b1d | |||
|
|
f4ed68fc44 | ||
|
|
4de98923b7 | ||
|
|
1e0e3a89cf | ||
|
|
edabd9a104 | ||
|
|
c11893566a | ||
|
|
c88bef959a | ||
|
|
ffd1b02bf9 | ||
|
|
075ad76d19 | ||
|
|
fbbd0496de | ||
|
|
00e8b7acbb | ||
|
|
3d40e0856e | ||
|
|
32d7897818 | ||
|
|
fa14f50e2d | ||
|
|
4eff5d48cd | ||
|
|
5380c4fb3f | ||
|
|
e10a82ff35 | ||
|
|
f85535672e | ||
|
|
3c1c0620d1 | ||
|
|
9531230fc0 | ||
|
|
151175fb3f | ||
|
|
9faf02a1a6 | ||
|
|
c2e95f607b | ||
|
|
3a50300bf9 | ||
|
|
188a108d87 | ||
|
|
11e788cb8f | ||
|
|
74195bc88b | ||
|
|
2a622aa1d6 | ||
|
|
d15b75e8fd | ||
|
|
4ae5f64da3 | ||
|
|
16ab366136 | ||
|
|
85abd7bca4 | ||
|
|
cd66ff927d | ||
|
|
d242a87191 | ||
|
|
e1eaba0d68 | ||
|
|
5a7c161ed2 | ||
|
|
a0a4e65d5e | ||
|
|
a6751424a5 | ||
|
|
8abaff86e5 | ||
|
|
e7442bf750 | ||
|
|
dce068fcb1 | ||
| 249d89af88 | |||
|
|
0f3a689b04 | ||
|
|
569eea08cb | ||
|
|
3cb80bbd85 | ||
|
|
e0d590724b | ||
|
|
2cfab00e8f | ||
|
|
06170ba38f | ||
|
|
7e28df210d | ||
|
|
a69e8c89f8 | ||
|
|
f5544c66bd | ||
|
|
7339f45193 | ||
|
|
739025935a | ||
|
|
eaa0e2d70c | ||
|
|
2bffdaef3a | ||
|
|
79809b56e9 | ||
|
|
e5896c8513 | ||
|
|
104041eea5 | ||
|
|
0b576ed446 | ||
|
|
c1174fc273 | ||
|
|
90e1cd022b | ||
|
|
001e5e887b | ||
|
|
8230dbf257 | ||
|
|
49fa7bdec8 | ||
|
|
bd13b70a88 | ||
|
|
9b5b43c2bf | ||
|
|
dee4733ad0 | ||
|
|
c07c1dfde3 | ||
|
|
181da5836b | ||
|
|
7a787db45d | ||
|
|
49c98697e1 | ||
|
|
7dedbb927c | ||
|
|
c2cc81fccf | ||
|
|
92b2a4fb37 | ||
|
|
b7d02ff669 | ||
|
|
b4179b4c60 | ||
|
|
d7e08a1fff | ||
|
|
d52fdc115c | ||
|
|
e86ae12801 | ||
|
|
87b2fd965c | ||
|
|
8397847e66 | ||
|
|
84b0575ab4 | ||
|
|
f19e5e48f3 | ||
|
|
073f17b61f | ||
|
|
4cdfe6097d | ||
|
|
d55a4e3da7 | ||
|
|
dd6c38c57e | ||
|
|
f705ba3a2e | ||
|
|
8721aa3a49 | ||
|
|
d2507e4706 | ||
| 0937efc6e6 | |||
| 57445cd48f | |||
| a193655353 | |||
|
|
10b150f13c | ||
|
|
c9fdd1785a | ||
|
|
a821d49eed | ||
|
|
28122bbfae | ||
|
|
3b4b085499 | ||
|
|
51b3388cdc | ||
|
|
908d9341db | ||
|
|
82a2ab158f | ||
|
|
ce893f32e0 | ||
|
|
65696dee09 | ||
|
|
625b39d901 | ||
|
|
4c20e639d8 | ||
|
|
f28dfeb9b4 | ||
|
|
a75c89c451 | ||
|
|
883816c540 | ||
|
|
24ba825365 | ||
|
|
accb02963c | ||
|
|
abe5595fa7 |
@@ -11,7 +11,7 @@ VITE_APP_NAME = "Core Network EMS"
|
||||
VITE_APP_CODE = "CN EMS"
|
||||
|
||||
# 应用版本
|
||||
VITE_APP_VERSION = "2.2402.5"
|
||||
VITE_APP_VERSION = "2.240530.1"
|
||||
|
||||
# 接口基础URL地址-不带/后缀
|
||||
VITE_API_BASE_URL = "/omc-api"
|
||||
|
||||
@@ -11,7 +11,7 @@ VITE_APP_NAME = "Core Network EMS"
|
||||
VITE_APP_CODE = "CN EMS"
|
||||
|
||||
# 应用版本
|
||||
VITE_APP_VERSION = "2.240205.5"
|
||||
VITE_APP_VERSION = "2.240530.1"
|
||||
|
||||
# 接口基础URL地址-不带/后缀
|
||||
VITE_API_BASE_URL = "/omc-api"
|
||||
|
||||
61
CHANGELOG.md
61
CHANGELOG.md
@@ -1,5 +1,52 @@
|
||||
# 版本发布日志
|
||||
|
||||
## 2.2404.1-20240402
|
||||
|
||||
- 新增 网元安装流程相关页面与操作相关接口联调
|
||||
- 新增 终端远程连接组件添加消息监听和发送句柄
|
||||
- 优化 移除vue-codemirror库改为codemirror,编辑输入支持 yaml语法
|
||||
- 优化 终端-基站信息Radio Name列宽调整
|
||||
- 更新 依赖版本
|
||||
|
||||
## 2.2403.1-20240319
|
||||
|
||||
- 新增 ws 工具连接状态函数
|
||||
- 新增 终端主机配置页面
|
||||
- 新增 终端主机命令页面
|
||||
- 新增 网元信息关联主机页面,表格支持勾选删除记录并展开看网元资源 sn
|
||||
- 新增 数据级缓存工具,支持表格字段排序状态缓存记录,表格字段排序支持缓存变更状态
|
||||
- 新增 网元主机操作翻译提示,网元主机操作 Hooks 包
|
||||
- 新增 IMS-CDR 和 AMF-UE 页面,以及翻译
|
||||
- 新增 网元快速安装页面,网元安装步骤页面模块
|
||||
- 新增 MML 网元操作 UPF 支持区分 telnet 发送端
|
||||
- 新增 网元快速安装步骤选择安装包界面
|
||||
- 新增 网元版本接口/网元软件包接口
|
||||
- 新增 自定义指标界面
|
||||
- 修复 帮助文档中英标题翻译文件名称指定《5G 核心网网管操作手册.pdf》
|
||||
- 修复 ws 函数发送消息判断是否连接正常
|
||||
- 修复 网元管理表单主键 id 重置失效导致新增操作为更新操作
|
||||
- 修复 网元选择列表不进行可操作使用网元状态过滤
|
||||
- 修复 移除获取网元列表,取消 status 状态过滤
|
||||
- 修复 缓存信息页面标题翻译,图表 Echart 语言数据设置
|
||||
- 修复 性能门限提交失败异常
|
||||
- 修复 提交异常并去除对 smdata 的校验
|
||||
- 优化 全局缓存网元列表,接口改换查询网元列表全部无分页
|
||||
- 优化 网元默认可选常量值,删除无效变量声明
|
||||
- 优化 UE-PCF 页面提示信息、网元信息页面样式、网元主机表单校验和提示翻译
|
||||
- 优化 拖动框地脚 null 类型异常,不支持 footer 插槽
|
||||
- 优化 切片文件上传文件名去除非法字符和空格,开发服务端口改为 33020
|
||||
- 更新 包依赖版本
|
||||
|
||||
## 2.2402.6-20240222
|
||||
|
||||
- 修复 UDM 用户数据超时时间 180s
|
||||
- 修复 UDM 鉴权 ki 和 opc 显示禁用输入
|
||||
- 新增 MML 命令输入框 shift+回车进行换行,回车直接发送
|
||||
- 修复 文档查看下载文件名称?显示问题
|
||||
- 修复 看板栏目添加跳转事件
|
||||
- 修复 看板用户行为字典数据翻译
|
||||
- 优化 看板用户行为 CDR 短信号码显示区间样式
|
||||
|
||||
## 2.2402.5-20240205
|
||||
|
||||
- 修复 拓扑架构图调整缺失的节点非网元元素,看板拓扑非网元点击排除
|
||||
@@ -17,14 +64,14 @@
|
||||
- 优化 配置参数编辑页面记录类型多语言是否系统内置
|
||||
- 优化 看板用户行为小屏幕换行显示字内容,格子高度百分比充满
|
||||
- 优化 看板推送用户行为插入又弹出减少渲染数量
|
||||
- 修复 看班告警统计判断修复,超时30秒,图渲染逻辑优化
|
||||
- 修复 参数配置DNN List参数显示null问题
|
||||
- 优化 ws消息队列延迟处理
|
||||
- 新增 看板用户事件CDR短信类型,短信结果200显示成功
|
||||
- 优化 看板告警统计0数字不显示
|
||||
- 优化 看板用户事件CDR指定类型MOC/MTSM
|
||||
- 修复 看班告警统计判断修复,超时 30 秒,图渲染逻辑优化
|
||||
- 修复 参数配置 DNN List 参数显示 null 问题
|
||||
- 优化 ws 消息队列延迟处理
|
||||
- 新增 看板用户事件 CDR 短信类型,短信结果 200 显示成功
|
||||
- 优化 看板告警统计 0 数字不显示
|
||||
- 优化 看板用户事件 CDR 指定类型 MOC/MTSM
|
||||
- 新增 黄金指标项图表显示全部开关控制
|
||||
- 新增 黄金指标项随机颜色,图表实时5s动态显示
|
||||
- 新增 黄金指标项随机颜色,图表实时 5s 动态显示
|
||||
|
||||
## 2.2401.4-20240130
|
||||
|
||||
|
||||
38
package.json
38
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "ems_frontend_vue3",
|
||||
"type": "module",
|
||||
"description": "核心网管理平台",
|
||||
"description": "Core Network EMS",
|
||||
"author": "TsMask",
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
@@ -15,39 +15,43 @@
|
||||
"@ant-design/icons-vue": "^7.0.1",
|
||||
"@antv/g6": "~4.8.24",
|
||||
"@codemirror/lang-javascript": "^6.2.1",
|
||||
"@codemirror/merge": "^6.5.0",
|
||||
"@codemirror/lang-yaml": "^6.1.1",
|
||||
"@codemirror/merge": "^6.6.1",
|
||||
"@codemirror/theme-one-dark": "^6.1.2",
|
||||
"@tato30/vue-pdf": "^1.9.3",
|
||||
"@vueuse/core": "^10.7.0",
|
||||
"@tato30/vue-pdf": "^1.9.6",
|
||||
"@vueuse/core": "~10.9.0",
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
"ant-design-vue": "^3.2.20",
|
||||
"antdv-pro-layout": "^3.2.6",
|
||||
"codemirror": "^6.0.1",
|
||||
"dayjs": "^1.11.10",
|
||||
"echarts": "~5.4.2",
|
||||
"dayjs": "^1.11.11",
|
||||
"echarts": "~5.5.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"js-base64": "^3.7.5",
|
||||
"intl-tel-input": "~22.0.2",
|
||||
"js-base64": "^3.7.7",
|
||||
"js-cookie": "^3.0.5",
|
||||
"localforage": "^1.10.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"p-queue": "^8.0.1",
|
||||
"pinia": "^2.1.7",
|
||||
"vue": "~3.3.13",
|
||||
"vue-codemirror": "^6.1.1",
|
||||
"vue-i18n": "~9.9.0",
|
||||
"vue-router": "^4.2.5",
|
||||
"vue-i18n": "^9.13.1",
|
||||
"vue-router": "^4.3.2",
|
||||
"vue3-smooth-dnd": "^0.0.6",
|
||||
"xlsx": "^0.18.5"
|
||||
"xlsx": "~0.18.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/node": "^18.0.0",
|
||||
"@types/nprogress": "^0.2.3",
|
||||
"@vitejs/plugin-vue": "^5.0.2",
|
||||
"@vitejs/plugin-vue": "^5.0.4",
|
||||
"less": "^4.2.0",
|
||||
"typescript": "^5.3.3",
|
||||
"unplugin-vue-components": "^0.26.0",
|
||||
"vite": "^5.0.10",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vue-tsc": "^1.8.27"
|
||||
"typescript": "~5.4.5",
|
||||
"unplugin-vue-components": "~0.26.0",
|
||||
"vite": "~5.2.10",
|
||||
"vite-plugin-compression": "~0.5.1",
|
||||
"vue-tsc": "~1.8.27"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
(function () {
|
||||
// host = ip:port
|
||||
const host = '192.168.8.100:3030';
|
||||
const host = '192.168.8.100:33030';
|
||||
|
||||
// Service Address
|
||||
sessionStorage.setItem('baseUrl', `http://${host}`);
|
||||
|
||||
@@ -155,7 +155,7 @@
|
||||
}
|
||||
</style>`;
|
||||
|
||||
const lang = localStorage.getItem('cache:local:i18n');
|
||||
const lang = localStorage.getItem('cache:local:i18n') || 'en_US';
|
||||
// 根据浏览器选择语言
|
||||
// if (!lang) {
|
||||
// let preferredLanguage = navigator.language;
|
||||
|
||||
@@ -4,13 +4,15 @@ import { usePrimaryColor } from '@/hooks/useTheme';
|
||||
import zhCN from 'ant-design-vue/lib/locale/zh_CN';
|
||||
import enUS from 'ant-design-vue/lib/locale/en_US';
|
||||
import dayjs from 'dayjs';
|
||||
import advancedFormat from 'dayjs/plugin/advancedFormat';
|
||||
import 'dayjs/locale/zh-cn';
|
||||
import { ref, watch } from 'vue';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
const { t, currentLocale } = useI18n();
|
||||
const appStore = useAppStore();
|
||||
|
||||
|
||||
dayjs.extend(advancedFormat)
|
||||
dayjs.locale('zh-cn'); // 默认中文
|
||||
usePrimaryColor(); // 载入用户自定义主题色
|
||||
|
||||
|
||||
@@ -38,13 +38,13 @@ export async function getParamConfigTopTab(neType: string) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询配置参数标签栏对应信息
|
||||
* 查询配置参数标签栏对应信息和规则
|
||||
* @param neType 网元类型
|
||||
* @param topTag
|
||||
* @param neId
|
||||
* @returns object { wrRule, dataArr }
|
||||
*/
|
||||
async function getParamConfigInfo(
|
||||
async function getParamConfigInfoAndRule(
|
||||
neType: string,
|
||||
topTag: string,
|
||||
neId: string
|
||||
@@ -57,7 +57,6 @@ async function getParamConfigInfo(
|
||||
params: {
|
||||
SQL: `SELECT param_json FROM param_config WHERE ne_type = '${neType}' AND top_tag='${topTag}'`,
|
||||
},
|
||||
timeout: 1_000,
|
||||
}),
|
||||
// 获取对应信息
|
||||
request({
|
||||
@@ -66,7 +65,6 @@ async function getParamConfigInfo(
|
||||
params: {
|
||||
ne_id: neId,
|
||||
},
|
||||
timeout: 1_000,
|
||||
}),
|
||||
]).then(resArr => {
|
||||
let wrRule: Record<string, any> = {};
|
||||
@@ -108,159 +106,6 @@ async function getParamConfigInfo(
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询配置参数标签栏对应信息-表格处理
|
||||
* @param neType 网元类型
|
||||
* @param topTag
|
||||
* @param neId
|
||||
* @returns object
|
||||
*/
|
||||
export async function getParamConfigInfoTable(
|
||||
neType: string,
|
||||
topTag: string,
|
||||
neId: string
|
||||
) {
|
||||
const { wrRule, dataArr } = await getParamConfigInfo(neType, topTag, neId);
|
||||
|
||||
// UPF参数不统一
|
||||
// if (neType === 'UPF') {
|
||||
// if (Reflect.has(wrRule, 'list')) {
|
||||
// for (const arr of wrRule['list']) {
|
||||
// arr['name'] = parseFirstLower(arr['name']);
|
||||
// }
|
||||
// for (const item of dataArr) {
|
||||
// for (const k in item) {
|
||||
// item[parseFirstLower(k)] = item[k];
|
||||
// Reflect.deleteProperty(item, k);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (Reflect.has(wrRule, 'array')) {
|
||||
// for (const arr of wrRule['array']) {
|
||||
// if (Array.isArray(arr['array'])) {
|
||||
// for (const child of arr['array']) {
|
||||
// child['name'] = parseFirstLower(child['name']);
|
||||
// }
|
||||
// }
|
||||
// arr['name'] = parseFirstLower(arr['name']);
|
||||
// }
|
||||
// for (const item of dataArr) {
|
||||
// for (const k in item) {
|
||||
// // 处理子列表
|
||||
// if (Array.isArray(item[k])) {
|
||||
// for (const child of item[k]) {
|
||||
// for (const childKey in child) {
|
||||
// child[parseFirstLower(childKey)] = child[childKey];
|
||||
// Reflect.deleteProperty(child, childKey);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// item[parseFirstLower(k)] = item[k];
|
||||
// Reflect.deleteProperty(item, k);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// 拼装数据
|
||||
const result = {
|
||||
code: RESULT_CODE_SUCCESS,
|
||||
msg: RESULT_MSG_SUCCESS,
|
||||
data: {
|
||||
type: 'list' as 'list' | 'array',
|
||||
data: [] as any[],
|
||||
dataRule: {},
|
||||
columns: [] as any[],
|
||||
},
|
||||
};
|
||||
|
||||
// kv单列表
|
||||
if (Reflect.has(wrRule, 'list')) {
|
||||
result.data.type = 'list';
|
||||
const ruleArr = Object.freeze(wrRule['list']);
|
||||
|
||||
// 列表项数据
|
||||
let dataList = [];
|
||||
for (const item of dataArr) {
|
||||
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],
|
||||
});
|
||||
dataList.push(ruleItem);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result.data.data = dataList;
|
||||
|
||||
// 列表字段
|
||||
result.data.columns = [
|
||||
{
|
||||
title: 'Key',
|
||||
dataIndex: 'display',
|
||||
align: 'left',
|
||||
width: '30%',
|
||||
},
|
||||
{
|
||||
title: 'Value',
|
||||
dataIndex: 'value',
|
||||
align: 'left',
|
||||
width: '70%',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
// 多列表
|
||||
if (Reflect.has(wrRule, 'array')) {
|
||||
result.data.type = 'array';
|
||||
const ruleArr = Object.freeze(wrRule['array']);
|
||||
|
||||
// 列表项数据
|
||||
const dataArray = [];
|
||||
for (const item of dataArr) {
|
||||
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[ruleItem.name] = ruleItem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
dataArray.push(record);
|
||||
}
|
||||
result.data.data = dataArray;
|
||||
|
||||
// 无数据时,用于新增
|
||||
let dataRule: Record<string, any> = {};
|
||||
for (const rule of ruleArr) {
|
||||
dataRule[rule.name] = rule;
|
||||
}
|
||||
result.data.dataRule = dataRule;
|
||||
|
||||
// 列表字段
|
||||
const columns: Record<string, any>[] = [];
|
||||
for (const rule of ruleArr) {
|
||||
columns.push({
|
||||
title: rule.display,
|
||||
dataIndex: rule.name,
|
||||
align: 'left',
|
||||
width: 5,
|
||||
});
|
||||
}
|
||||
result.data.columns = columns;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询配置参数标签栏对应信息-表单结构处理
|
||||
* @param neType 网元类型
|
||||
@@ -273,7 +118,11 @@ export async function getParamConfigInfoForm(
|
||||
topTag: string,
|
||||
neId: string
|
||||
) {
|
||||
const { wrRule, dataArr } = await getParamConfigInfo(neType, topTag, neId);
|
||||
const { wrRule, dataArr } = await getParamConfigInfoAndRule(
|
||||
neType,
|
||||
topTag,
|
||||
neId
|
||||
);
|
||||
|
||||
// 拼装数据
|
||||
const result = {
|
||||
@@ -340,6 +189,35 @@ export async function getParamConfigInfoForm(
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询配置参数标签栏对应信息
|
||||
* @param neType 网元类型
|
||||
* @param topTag
|
||||
* @param neId
|
||||
* @returns object
|
||||
*/
|
||||
export async function getParamConfigInfo(
|
||||
neType: string,
|
||||
topTag: string,
|
||||
neId: string
|
||||
) {
|
||||
// 发起请求
|
||||
const result = await request({
|
||||
url: `/api/rest/systemManagement/v1/elementType/${neType.toLowerCase()}/objectType/config/${topTag}`,
|
||||
method: 'get',
|
||||
params: {
|
||||
ne_id: neId,
|
||||
},
|
||||
});
|
||||
// 解析数据
|
||||
if (result.code === RESULT_CODE_SUCCESS && Array.isArray(result.data.data)) {
|
||||
return Object.assign(result, {
|
||||
data: parseObjLineToHump(result.data.data),
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询配置参数标签栏对应信息子节点
|
||||
* @param neType 网元类型
|
||||
@@ -462,3 +340,144 @@ export async function updateNeConfigReload(neType: string, neId: string) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从参数配置PCF中获取对应信息提供给PCC用户策略输入框
|
||||
* @param neType 网元类型
|
||||
* @param topTag
|
||||
* @param neId
|
||||
* @returns object { wrRule, dataArr }
|
||||
*/
|
||||
export async function getPCCRule(neId: any) {
|
||||
return await Promise.allSettled([
|
||||
// 获取参数规则
|
||||
request({
|
||||
url: `/api/rest/systemManagement/v1/elementType/pcf/objectType/config/pccRules`,
|
||||
method: 'get',
|
||||
params: {
|
||||
ne_id: neId,
|
||||
},
|
||||
timeout: 1_000,
|
||||
}),
|
||||
// 获取对应信息
|
||||
request({
|
||||
url: `/api/rest/systemManagement/v1/elementType/pcf/objectType/config/sessionRules`,
|
||||
method: 'get',
|
||||
params: {
|
||||
ne_id: neId,
|
||||
},
|
||||
timeout: 1_000,
|
||||
}),
|
||||
request({
|
||||
url: `/api/rest/systemManagement/v1/elementType/pcf/objectType/config/qosTemplate`,
|
||||
method: 'get',
|
||||
params: {
|
||||
ne_id: neId,
|
||||
},
|
||||
timeout: 1_000,
|
||||
}),
|
||||
request({
|
||||
url: `/api/rest/systemManagement/v1/elementType/pcf/objectType/config/headerEnrichTemplate`,
|
||||
method: 'get',
|
||||
params: {
|
||||
ne_id: neId,
|
||||
},
|
||||
timeout: 1_000,
|
||||
}),
|
||||
request({
|
||||
url: `/api/rest/systemManagement/v1/elementType/pcf/objectType/config/serviceAreaRestriction`,
|
||||
method: 'get',
|
||||
params: {
|
||||
ne_id: neId,
|
||||
},
|
||||
timeout: 1_000,
|
||||
}),
|
||||
]).then(resArr => {
|
||||
let pccJson: any = new Map();
|
||||
let sessJson: any = new Map();
|
||||
let qosJson: any = new Map();
|
||||
let headerJson: any = new Map();
|
||||
let sarJson: any = new Map();
|
||||
// 规则数据
|
||||
if (resArr[0].status === 'fulfilled') {
|
||||
const itemV = resArr[0].value;
|
||||
// 解析数据
|
||||
if (
|
||||
itemV.code === RESULT_CODE_SUCCESS &&
|
||||
Array.isArray(itemV.data?.data)
|
||||
) {
|
||||
let itemData = itemV.data.data;
|
||||
itemData.forEach((item: any) => {
|
||||
pccJson.set(item.ruleId, { value: item.ruleId, label: item.ruleId });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (resArr[1].status === 'fulfilled') {
|
||||
const itemV = resArr[1].value;
|
||||
// 解析数据
|
||||
if (
|
||||
itemV.code === RESULT_CODE_SUCCESS &&
|
||||
Array.isArray(itemV.data?.data)
|
||||
) {
|
||||
let itemData = itemV.data.data;
|
||||
itemData.forEach((item: any) => {
|
||||
sessJson.set(item.ruleId, { value: item.ruleId, label: item.ruleId });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (resArr[2].status === 'fulfilled') {
|
||||
const itemV = resArr[2].value;
|
||||
// 解析数据
|
||||
if (
|
||||
itemV.code === RESULT_CODE_SUCCESS &&
|
||||
Array.isArray(itemV.data?.data)
|
||||
) {
|
||||
let itemData = itemV.data.data;
|
||||
itemData.forEach((item: any) => {
|
||||
qosJson.set(item.qosId, { value: item.qosId, label: item.qosId });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (resArr[3].status === 'fulfilled') {
|
||||
const itemV = resArr[3].value;
|
||||
// 解析数据
|
||||
if (
|
||||
itemV.code === RESULT_CODE_SUCCESS &&
|
||||
Array.isArray(itemV.data?.data)
|
||||
) {
|
||||
let itemData = itemV.data.data;
|
||||
itemData.forEach((item: any) => {
|
||||
headerJson.set(item.templateName, {
|
||||
value: item.templateName,
|
||||
label: item.templateName,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (resArr[4].status === 'fulfilled') {
|
||||
const itemV = resArr[4].value;
|
||||
// 解析数据
|
||||
if (
|
||||
itemV.code === RESULT_CODE_SUCCESS &&
|
||||
Array.isArray(itemV.data?.data)
|
||||
) {
|
||||
let itemData = itemV.data.data;
|
||||
itemData.forEach((item: any) => {
|
||||
sarJson.set(item.name, { value: item.name, label: item.name });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pccJson = Array.from(pccJson.values());
|
||||
sessJson = Array.from(sessJson.values());
|
||||
qosJson = Array.from(qosJson.values());
|
||||
headerJson = Array.from(headerJson.values());
|
||||
sarJson = Array.from(sarJson.values());
|
||||
|
||||
return { pccJson, sessJson, qosJson, headerJson, sarJson };
|
||||
});
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ export async function listLicense(query: Record<string, any>) {
|
||||
|
||||
// 分页
|
||||
const pageNum = (query.pageNum - 1) * query.pageSize;
|
||||
const limtSql = ` order by created_at desc limit ${pageNum},${query.pageSize} `;
|
||||
const limtSql = ` order by create_time desc limit ${pageNum},${query.pageSize} `;
|
||||
|
||||
// 发起请求
|
||||
const result = await request({
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import { request } from '@/plugins/http-fetch';
|
||||
import {
|
||||
RESULT_CODE_ERROR,
|
||||
RESULT_CODE_SUCCESS,
|
||||
RESULT_MSG_ERROR,
|
||||
} from '@/constants/result-constants';
|
||||
import { language, request } from '@/plugins/http-fetch';
|
||||
import { parseObjLineToHump } from '@/utils/parse-utils';
|
||||
import { NE_TYPE_LIST } from '@/constants/ne-constants';
|
||||
|
||||
/**
|
||||
* 查询网元列表
|
||||
@@ -8,27 +13,8 @@ import { parseObjLineToHump } from '@/utils/parse-utils';
|
||||
* @returns object
|
||||
*/
|
||||
export async function listNeInfo(query: Record<string, any>) {
|
||||
let totalSQL =
|
||||
'select count(*) as total from ne_info where (status=0 or status=3)';
|
||||
let rowsSQL = 'select * from ne_info where (status=0 or status=3) ';
|
||||
|
||||
// 系统特定顺序
|
||||
const specificOrder = [
|
||||
'OMC',
|
||||
'MME',
|
||||
'AMF',
|
||||
'AUSF',
|
||||
'UDM',
|
||||
'SMF',
|
||||
'PCF',
|
||||
'UPF',
|
||||
'NRF',
|
||||
'NSSF',
|
||||
'IMS',
|
||||
'N3IWF',
|
||||
'NEF',
|
||||
'LMF',
|
||||
];
|
||||
let totalSQL = 'select count(*) as total from ne_info where 1=1 ';
|
||||
let rowsSQL = 'select * from ne_info where 1=1 ';
|
||||
|
||||
// 查询
|
||||
let querySQL = '';
|
||||
@@ -67,8 +53,8 @@ export async function listNeInfo(query: Record<string, any>) {
|
||||
data.rows = itemData.map(v => parseObjLineToHump(v));
|
||||
//通过sort进行冒泡排序
|
||||
data.rows.sort((a: any, b: any) => {
|
||||
const typeA = specificOrder.indexOf(a.neType);
|
||||
const typeB = specificOrder.indexOf(b.neType);
|
||||
const typeA = NE_TYPE_LIST.indexOf(a.neType);
|
||||
const typeB = NE_TYPE_LIST.indexOf(b.neType);
|
||||
if (typeA === -1) return 1; // 如果不在特定顺序中,排到后面
|
||||
if (typeB === -1) return -1; // 如果不在特定顺序中,排到后面
|
||||
return typeA - typeB;
|
||||
@@ -92,15 +78,18 @@ export async function getNeInfo(id: string | number) {
|
||||
url: `/api/rest/databaseManagement/v1/select/omc_db/ne_info`,
|
||||
method: 'get',
|
||||
params: {
|
||||
SQL: `select * from ne_info where (status=0 or status=3) and id = ${id}`,
|
||||
SQL: `select * from ne_info 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['ne_info'][0]),
|
||||
});
|
||||
let neInfo = result.data.data[0]['ne_info'];
|
||||
if (neInfo) {
|
||||
return Object.assign(result, {
|
||||
data: parseObjLineToHump(neInfo[0]),
|
||||
});
|
||||
}
|
||||
return { code: RESULT_CODE_ERROR, msg: RESULT_MSG_ERROR[language] };
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -148,57 +137,9 @@ export async function delNeInfo(data: Record<string, any>) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取网元网元列表
|
||||
* @returns object
|
||||
*/
|
||||
export async function getNelistAll() {
|
||||
// 系统特定顺序
|
||||
const specificOrder = [
|
||||
'OMC',
|
||||
'MME',
|
||||
'AMF',
|
||||
'AUSF',
|
||||
'UDM',
|
||||
'SMF',
|
||||
'PCF',
|
||||
'UPF',
|
||||
'NRF',
|
||||
'NSSF',
|
||||
'IMS',
|
||||
'N3IWF',
|
||||
'NEF',
|
||||
'LMF',
|
||||
];
|
||||
// 发起请求
|
||||
const result = await request({
|
||||
url: `/api/rest/databaseManagement/v1/elementType/omc_db/objectType/ne_info`,
|
||||
method: 'get',
|
||||
params: {
|
||||
SQL: `SELECT ne_type,ne_name,ne_id,ip FROM ne_info WHERE status in ('0','3')`,
|
||||
},
|
||||
});
|
||||
// 解析数据
|
||||
if (result.code === RESULT_CODE_SUCCESS && Array.isArray(result.data.data)) {
|
||||
let data = result.data.data[0];
|
||||
//通过sort进行冒泡排序
|
||||
data['ne_info'].sort((a: any, b: any) => {
|
||||
const typeA = specificOrder.indexOf(a.ne_type);
|
||||
const typeB = specificOrder.indexOf(b.ne_type);
|
||||
if (typeA === -1) return 1;
|
||||
if (typeB === -1) return -1;
|
||||
return typeA - typeB;
|
||||
});
|
||||
return Object.assign(result, {
|
||||
data: parseObjLineToHump(data['ne_info']),
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出网元配置文件
|
||||
* @param
|
||||
* @param data data {neType neId}
|
||||
* @returns bolb
|
||||
*/
|
||||
export function exportSet(data: Record<string, any>) {
|
||||
|
||||
@@ -111,6 +111,7 @@ export async function sendNeSoftware(data: Record<string, any>) {
|
||||
url: `/api/rest/systemManagement/v1/${data.neType}/software/${data.version}/${data.neId}`,
|
||||
method: 'post',
|
||||
timeout: 180_000,
|
||||
repeatSubmit: false,
|
||||
});
|
||||
// 解析数据
|
||||
if (result.code === RESULT_CODE_SUCCESS) {
|
||||
@@ -130,6 +131,7 @@ export async function runNeSoftware(data: Record<string, any>) {
|
||||
url: `/api/rest/systemManagement/v1/${data.neType}/software/${data.version}/${data.neId}`,
|
||||
method: 'put',
|
||||
timeout: 180_000,
|
||||
repeatSubmit: false,
|
||||
});
|
||||
// 解析数据
|
||||
if (result.code === RESULT_CODE_SUCCESS) {
|
||||
@@ -149,6 +151,7 @@ export async function backNeSoftware(data: Record<string, any>) {
|
||||
url: `/api/rest/systemManagement/v1/${data.neType}/software/${data.version}/${data.neId}`,
|
||||
method: 'PATCH',
|
||||
timeout: 180_000,
|
||||
repeatSubmit: false,
|
||||
});
|
||||
// 解析数据
|
||||
if (result.code === RESULT_CODE_SUCCESS) {
|
||||
|
||||
@@ -294,7 +294,7 @@ export async function exportAll(query: Record<string, any>) {
|
||||
* @returns bolb
|
||||
*/
|
||||
export async function origGet() {
|
||||
let totalSQL = `select count(*) as value,orig_severity as name from alarm group by orig_severity`;
|
||||
let totalSQL = `select count(*) as value,orig_severity as name from alarm WHERE alarm_status='1' and orig_severity!='Event' group by orig_severity`;
|
||||
|
||||
// 发起请求
|
||||
const result = await request({
|
||||
@@ -329,10 +329,10 @@ export async function origGet() {
|
||||
* @returns object
|
||||
*/
|
||||
export async function top3Sel(filterFlag?: string) {
|
||||
let filter = ` WHERE orig_severity='${filterFlag}'`;
|
||||
if (!filterFlag) filter = '';
|
||||
let filter = ` WHERE alarm_status='1'and orig_severity='${filterFlag}'`;
|
||||
if (!filterFlag) filter = "WHERE alarm_status='1'";
|
||||
|
||||
let top3SQL = `select count(*) as value,ne_type as name from alarm ${filter} group by ne_type ORDER BY value desc limit 0,3 `;
|
||||
let top3SQL = `select count(*) as value,ne_type as name from alarm ${filter} and orig_severity!='Event' group by ne_type ORDER BY value desc limit 0,3 `;
|
||||
|
||||
// 发起请求
|
||||
const result = await request({
|
||||
|
||||
139
src/api/faultManage/eventAlarm.ts
Normal file
139
src/api/faultManage/eventAlarm.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
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';
|
||||
import useUserStore from '@/store/modules/user';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 查询列表
|
||||
* @param query 查询参数
|
||||
* @returns object
|
||||
*/
|
||||
export async function listAct(query: Record<string, any>) {
|
||||
let totalSQL = `select count(*) as total from alarm_event where 1=1 `;
|
||||
let rowsSQL = `select * from alarm_event where 1=1 `;
|
||||
// 查询
|
||||
let querySQL = '';
|
||||
if (query.alarmCode) {
|
||||
querySQL += ` and alarm_code = '${query.alarmCode}' `;
|
||||
}
|
||||
|
||||
if (query.alarmType) {
|
||||
querySQL += ` and alarm_type = '${query.alarmType}' `;
|
||||
}
|
||||
|
||||
if (query.pvFlag) {
|
||||
querySQL += ` and pv_flag = '${query.pvFlag}' `;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (query.neId) {
|
||||
querySQL += ` and ne_id like '%${query.neId}%' `;
|
||||
}
|
||||
|
||||
if (query.neName) {
|
||||
querySQL += ` and ne_name like '%${query.neName}%' `;
|
||||
}
|
||||
|
||||
if (query.neType) {
|
||||
querySQL += ` and ne_type like '%${query.neType}%' `;
|
||||
}
|
||||
|
||||
if (query.beginTime && query.endTime) {
|
||||
querySQL += ` and event_time BETWEEN '${query.beginTime}' and ' ${query.endTime}'`;
|
||||
}
|
||||
|
||||
// 分页
|
||||
const pageNum = (query.pageNum - 1) * query.pageSize;
|
||||
const limtSql = ` order by event_time desc limit ${pageNum},${query.pageSize} `;
|
||||
|
||||
// 发起请求
|
||||
const result = await request({
|
||||
url: `/api/rest/databaseManagement/v1/select/omc_db/alarm_event`,
|
||||
method: 'get',
|
||||
params: {
|
||||
SQL: totalSQL + querySQL,
|
||||
rowsSQL: rowsSQL + querySQL + 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) => {
|
||||
console.log(item)
|
||||
const itemData = item['alarm_event'];
|
||||
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 bolb
|
||||
*/
|
||||
export async function exportAll(query: Record<string, any>) {
|
||||
let rowsSQL = `select * from alarm_event where 1=1`;
|
||||
// 查询
|
||||
let querySQL = '';
|
||||
querySQL += query.alarm_code
|
||||
? ` and alarm_code = '${query.alarm_code}' `
|
||||
: '';
|
||||
querySQL += query.alarm_type
|
||||
? ` and alarm_type = '${query.alarm_type}' `
|
||||
: '';
|
||||
querySQL += query.pv_flag ? ` and pv_flag = '${query.pv_flag}' ` : '';
|
||||
querySQL += query.orig_severity
|
||||
? ` and orig_severity in('${query.orig_severity}' )`
|
||||
: '';
|
||||
querySQL += query.ne_id ? ` and ne_id like '%${query.ne_id}%' ` : '';
|
||||
querySQL += query.ne_name ? ` and ne_name like '%${query.ne_name}%' ` : '';
|
||||
querySQL += query.ne_type ? ` and ne_type like '%${query.ne_type}%' ` : '';
|
||||
querySQL +=
|
||||
query.beginTime && query.endTime
|
||||
? ` and event_time BETWEEN '${query.beginTime}' and ' ${query.endTime}'`
|
||||
: '';
|
||||
|
||||
// 发起请求
|
||||
const result = await request({
|
||||
url: `/api/rest/databaseManagement/v1/select/omc_db/alarm_event`,
|
||||
method: 'get',
|
||||
params: {
|
||||
rowsSQL: rowsSQL + querySQL,
|
||||
},
|
||||
});
|
||||
|
||||
if (result.code === RESULT_CODE_SUCCESS) {
|
||||
let v = result.data.data[0];
|
||||
const vArr = parseObjLineToHump(v['alarm_event']);
|
||||
result.data = vArr == null ? [] : vArr;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,29 +1,14 @@
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import { request } from '@/plugins/http-fetch';
|
||||
import { parseDateToStr } from '@/utils/date-utils';
|
||||
import { NE_TYPE_LIST } from '@/constants/ne-constants';
|
||||
|
||||
/**
|
||||
* 查询公告列表
|
||||
* @param query 查询参数
|
||||
* @returns object
|
||||
*/
|
||||
export async function listMain() {
|
||||
// 系统特定顺序
|
||||
const specificOrder = [
|
||||
'OMC',
|
||||
'MME',
|
||||
'AMF',
|
||||
'AUSF',
|
||||
'UDM',
|
||||
'SMF',
|
||||
'PCF',
|
||||
'UPF',
|
||||
'NRF',
|
||||
'NSSF',
|
||||
'IMS',
|
||||
'N3IWF',
|
||||
'NEF',
|
||||
'LMF',
|
||||
];
|
||||
const result = await request({
|
||||
url: '/api/rest/systemManagement/v1/elementType/all/objectType/systemState',
|
||||
method: 'get',
|
||||
@@ -39,7 +24,6 @@ export async function listMain() {
|
||||
const serialNum = (value as any).serialNum;
|
||||
const version = (value as any).version;
|
||||
|
||||
|
||||
const errCode = systemState && systemState['errorCode'];
|
||||
var time = new Date();
|
||||
// console.log(key, value);
|
||||
@@ -59,21 +43,20 @@ export async function listMain() {
|
||||
ipAddress,
|
||||
serialNum,
|
||||
name: key.split('/').join('_'),
|
||||
expiryDate: '-',
|
||||
status: 'Abnormal',
|
||||
};
|
||||
}
|
||||
return mergedObj;
|
||||
});
|
||||
|
||||
//通过sort进行冒泡排序
|
||||
mergedData.sort((a: any, b: any) => {
|
||||
const typeA = specificOrder.indexOf(a.name.split('_')[0]);
|
||||
const typeB = specificOrder.indexOf(b.name.split('_')[0]);
|
||||
const typeA = NE_TYPE_LIST.indexOf(a.name.split('_')[0]);
|
||||
const typeB = NE_TYPE_LIST.indexOf(b.name.split('_')[0]);
|
||||
if (typeA === -1) return 1; // 如果不在特定顺序中,排到后面
|
||||
if (typeB === -1) return -1; // 如果不在特定顺序中,排到后面
|
||||
return typeA - typeB;
|
||||
});
|
||||
//console.log(mergedData);
|
||||
|
||||
return mergedData;
|
||||
}
|
||||
@@ -105,5 +88,6 @@ export function getSysConf() {
|
||||
return request({
|
||||
url: `/sys-conf`,
|
||||
method: 'get',
|
||||
whithToken: false,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -30,17 +30,19 @@ export async function getMMLByNE(neType: string) {
|
||||
* 发送网元的mml命令
|
||||
* @param neType 网元类型
|
||||
* @param neId 网元ID
|
||||
* @param objectType 接口类型
|
||||
* @param cmdStr 命令串
|
||||
* @returns
|
||||
*/
|
||||
export async function sendMMlByNE(
|
||||
neType: string,
|
||||
neId: string,
|
||||
objectType: string,
|
||||
cmdArr: string[]
|
||||
) {
|
||||
// 发起请求
|
||||
const result = await request({
|
||||
url: `/api/rest/operationManagement/v1/elementType/${neType}/objectType/mml?ne_id=${neId}`,
|
||||
url: `/api/rest/operationManagement/v1/elementType/${neType}/objectType/${objectType}?ne_id=${neId}`,
|
||||
method: 'post',
|
||||
data: { mml: cmdArr },
|
||||
timeout: 180_000,
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
import {
|
||||
RESULT_CODE_ERROR,
|
||||
RESULT_CODE_SUCCESS,
|
||||
RESULT_MSG_ERROR,
|
||||
} from '@/constants/result-constants';
|
||||
import { language, request } from '@/plugins/http-fetch';
|
||||
import { parseObjLineToHump } from '@/utils/parse-utils';
|
||||
|
||||
/**
|
||||
* 查询用户会话列表
|
||||
* @param query 查询参数
|
||||
* @returns object
|
||||
*/
|
||||
export async function listSession(query: Record<string, any>) {
|
||||
let totalSQL = 'select count(*) as total from session where 1=1 ';
|
||||
let rowsSQL = 'select * from session where 1=1 ';
|
||||
|
||||
// 查询
|
||||
let querySQL = '';
|
||||
if (query.accountId) {
|
||||
querySQL += ` and account_id like '%${query.accountId}%' `;
|
||||
}
|
||||
if (query.ip) {
|
||||
querySQL += ` and host like '%${query.ip}%' `;
|
||||
}
|
||||
|
||||
// 分页
|
||||
const pageNum = (query.pageNum - 1) * query.pageSize;
|
||||
const limtSql = ` limit ${pageNum},${query.pageSize} `;
|
||||
|
||||
// 排序
|
||||
let sortSql = ' order by login_time ';
|
||||
if (query.sortOrder === 'desc') {
|
||||
sortSql += ' desc ';
|
||||
} else {
|
||||
sortSql += ' asc ';
|
||||
}
|
||||
|
||||
// 发起请求
|
||||
const result = await request({
|
||||
url: `/api/rest/databaseManagement/v1/omc_db/session`,
|
||||
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['session'];
|
||||
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 tokenId 授权标识
|
||||
* @returns object
|
||||
*/
|
||||
export async function logoutSession(id: string) {
|
||||
const result = await request({
|
||||
url: `/api/rest/databaseManagement/v1/omc_db/session?WHERE=id='${id}'`,
|
||||
method: 'delete',
|
||||
});
|
||||
// 解析数据
|
||||
if (result.code === RESULT_CODE_SUCCESS && result.data.data) {
|
||||
let rows = result.data.data.affectedRows;
|
||||
if (rows) {
|
||||
delete result.data;
|
||||
return result;
|
||||
} else {
|
||||
return { code: RESULT_CODE_ERROR, msg: RESULT_MSG_ERROR[language] };
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import { request } from '@/plugins/http-fetch';
|
||||
|
||||
/**
|
||||
* 查询网元列表
|
||||
* @param query 查询参数
|
||||
* @returns object
|
||||
*/
|
||||
export function listNe(query: Record<string, any>) {
|
||||
return request({
|
||||
url: '/ne/list',
|
||||
method: 'get',
|
||||
params: query,
|
||||
timeout: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询网元状态
|
||||
* @param neType 网元类型
|
||||
* @param neId 网元ID
|
||||
* @returns object
|
||||
*/
|
||||
export function stateNe(neType: string, neId: string) {
|
||||
return request({
|
||||
url: '/ne/state',
|
||||
method: 'get',
|
||||
params: { neType, neId },
|
||||
});
|
||||
}
|
||||
103
src/api/ne/neHost.ts
Normal file
103
src/api/ne/neHost.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { request } from '@/plugins/http-fetch';
|
||||
|
||||
/**
|
||||
* 查询网元主机列表
|
||||
* @param query 查询参数
|
||||
* @returns object
|
||||
*/
|
||||
export function listNeHost(query: Record<string, any>) {
|
||||
return request({
|
||||
url: '/ne/host/list',
|
||||
method: 'get',
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询网元主机详细
|
||||
* @param hostId 网元主机ID
|
||||
* @returns object
|
||||
*/
|
||||
export function getNeHost(hostId: string | number) {
|
||||
return request({
|
||||
url: `/ne/host/${hostId}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增网元主机
|
||||
* @param data 网元主机对象
|
||||
* @returns object
|
||||
*/
|
||||
export function addNeHost(data: Record<string, any>) {
|
||||
return request({
|
||||
url: '/ne/host',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改网元主机
|
||||
* @param data 网元主机对象
|
||||
* @returns object
|
||||
*/
|
||||
export function updateNeHost(data: Record<string, any>) {
|
||||
return request({
|
||||
url: '/ne/host',
|
||||
method: 'put',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除网元主机
|
||||
* @param hostId 网元主机ID
|
||||
* @returns object
|
||||
*/
|
||||
export function delNeHost(hostId: string | number) {
|
||||
return request({
|
||||
url: `/ne/host/${hostId}`,
|
||||
method: 'delete',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试连接网元主机
|
||||
* @param data 网元主机对象
|
||||
* @returns object
|
||||
*/
|
||||
export function testNeHost(data: Record<string, any>) {
|
||||
return request({
|
||||
url: '/ne/host/test',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 网元主机SSH方式检查服务器环境
|
||||
* @param data 网元主机对象
|
||||
* @returns object
|
||||
*/
|
||||
export function neHostCheckInfo(data: Record<string, any>) {
|
||||
return request({
|
||||
url: '/ne/host/checkBySSH',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 网元主机SSH方式授权免密发送
|
||||
* @param data 网元主机对象
|
||||
* @returns object
|
||||
*/
|
||||
export function neHostAuthorizedRSA(data: Record<string, any>) {
|
||||
return request({
|
||||
url: '/ne/host/authorizedBySSH',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
64
src/api/ne/neHostCmd.ts
Normal file
64
src/api/ne/neHostCmd.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { request } from '@/plugins/http-fetch';
|
||||
|
||||
/**
|
||||
* 查询网元主机命令列表
|
||||
* @param query 查询参数
|
||||
* @returns object
|
||||
*/
|
||||
export function listNeHostCmd(query: Record<string, any>) {
|
||||
return request({
|
||||
url: '/ne/hostCmd/list',
|
||||
method: 'get',
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询网元主机命令详细
|
||||
* @param cmdId 网元主机命令ID
|
||||
* @returns object
|
||||
*/
|
||||
export function getNeHostCmd(cmdId: string | number) {
|
||||
return request({
|
||||
url: `/ne/hostCmd/${cmdId}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增网元主机命令
|
||||
* @param data 网元主机命令对象
|
||||
* @returns object
|
||||
*/
|
||||
export function addNeHostCmd(data: Record<string, any>) {
|
||||
return request({
|
||||
url: '/ne/hostCmd',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改网元主机命令
|
||||
* @param data 网元主机命令对象
|
||||
* @returns object
|
||||
*/
|
||||
export function updateNeHostCmd(data: Record<string, any>) {
|
||||
return request({
|
||||
url: '/ne/hostCmd',
|
||||
method: 'put',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除网元主机命令
|
||||
* @param cmdId 网元主机命令ID
|
||||
* @returns object
|
||||
*/
|
||||
export function delNeHostCmd(cmdId: string | number) {
|
||||
return request({
|
||||
url: `/ne/hostCmd/${cmdId}`,
|
||||
method: 'delete',
|
||||
});
|
||||
}
|
||||
177
src/api/ne/neInfo.ts
Normal file
177
src/api/ne/neInfo.ts
Normal file
@@ -0,0 +1,177 @@
|
||||
import { request } from '@/plugins/http-fetch';
|
||||
|
||||
/**
|
||||
* 查询网元列表
|
||||
* @param query 查询参数
|
||||
* @returns object
|
||||
*/
|
||||
export function listNeInfo(query: Record<string, any>) {
|
||||
return request({
|
||||
url: '/ne/info/list',
|
||||
method: 'get',
|
||||
params: query,
|
||||
timeout: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询网元信息详细
|
||||
* @param infoId 信息ID
|
||||
* @returns object
|
||||
*/
|
||||
export function getNeInfo(infoId: string | number) {
|
||||
return request({
|
||||
url: `/ne/info/${infoId}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 网元信息新增
|
||||
* @param data 网元对象
|
||||
* @returns object
|
||||
*/
|
||||
export function addNeInfo(data: Record<string, any>) {
|
||||
return request({
|
||||
url: `/ne/info`,
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 网元信息修改
|
||||
* @param data 网元对象
|
||||
* @returns object
|
||||
*/
|
||||
export function updateNeInfo(data: Record<string, any>) {
|
||||
return request({
|
||||
url: `/ne/info`,
|
||||
method: 'put',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 网元信息删除
|
||||
* @param id 信息ID
|
||||
* @returns object
|
||||
*/
|
||||
export function delNeInfo(infoIds: string | number) {
|
||||
return request({
|
||||
url: `/ne/info/${infoIds}`,
|
||||
method: 'delete',
|
||||
timeout: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询网元列表全部无分页
|
||||
* @param query 查询参数 neType neId bandStatus bandHost
|
||||
* @returns object
|
||||
*/
|
||||
export function listAllNeInfo(query: Record<string, any>) {
|
||||
return request({
|
||||
url: '/ne/info/listAll',
|
||||
method: 'get',
|
||||
params: query,
|
||||
timeout: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询网元状态
|
||||
* @param neType 网元类型
|
||||
* @param neId 网元ID
|
||||
* @returns object
|
||||
*/
|
||||
export function stateNeInfo(neType: string, neId: string) {
|
||||
return request({
|
||||
url: '/ne/info/state',
|
||||
method: 'get',
|
||||
params: { neType, neId },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询网元信息
|
||||
* @param neType 网元类型
|
||||
* @param neId 网元ID
|
||||
* @returns object
|
||||
*/
|
||||
export function getNeInfoByTypeAndID(neType: string, neId: string) {
|
||||
return request({
|
||||
url: '/ne/info/byTypeAndID',
|
||||
method: 'get',
|
||||
params: { neType, neId },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 网元端OAM配置文件读取
|
||||
* @param neType 网元类型
|
||||
* @param neId 网元ID
|
||||
* @returns object
|
||||
*/
|
||||
export function getOAMFile(neType: string, neId: string) {
|
||||
return request({
|
||||
url: '/ne/info/oamFile',
|
||||
method: 'get',
|
||||
params: { neType, neId },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 网元端配置文件写入
|
||||
* @param neType 网元类型
|
||||
* @param neId 网元ID
|
||||
* @param content 用json对象
|
||||
* @param sync 同步到网元
|
||||
* @returns object
|
||||
*/
|
||||
export function saveOAMFile(data: Record<string, any>) {
|
||||
return request({
|
||||
url: `/ne/info/oamFile`,
|
||||
method: 'put',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 网元端公共配置文件读取
|
||||
* @returns object
|
||||
*/
|
||||
export function getPara5GFilee() {
|
||||
return request({
|
||||
url: '/ne/info/para5GFile',
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 网元端公共配置文件写入
|
||||
* @param content txt内容为字符串 其他文件格式都用json对象
|
||||
* @param syncNe 同步到网元端 NeType@ NeId
|
||||
* @returns object
|
||||
*/
|
||||
export function savePara5GFile(data: Record<string, any>) {
|
||||
return request({
|
||||
url: `/ne/info/para5GFile`,
|
||||
method: 'put',
|
||||
data: data,
|
||||
timeout: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 网元服务操作
|
||||
* @param data 对象 {neType,neId,action}
|
||||
* @returns object
|
||||
*/
|
||||
export function serviceNeAction(data: Record<string, any>) {
|
||||
return request({
|
||||
url: `/ne/action/service`,
|
||||
method: 'put',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
83
src/api/ne/neLicense.ts
Normal file
83
src/api/ne/neLicense.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { request } from '@/plugins/http-fetch';
|
||||
|
||||
/**
|
||||
* 查询网元授权列表
|
||||
* @param query 查询参数
|
||||
* @returns object
|
||||
*/
|
||||
export function listNeLicense(query: Record<string, any>) {
|
||||
return request({
|
||||
url: '/ne/license/list',
|
||||
method: 'get',
|
||||
params: query,
|
||||
timeout: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询网元授权详细
|
||||
* @param licenseId 信息ID
|
||||
* @returns object
|
||||
*/
|
||||
export function getNeLicense(licenseId: string | number) {
|
||||
return request({
|
||||
url: `/ne/license/${licenseId}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 网元neType和neID查询
|
||||
* @param neType 网元类型
|
||||
* @param neId 网元ID
|
||||
* @returns object
|
||||
*/
|
||||
export function getNeLicenseByTypeAndID(neType: string, neId: string) {
|
||||
return request({
|
||||
url: `/ne/license/byTypeAndID`,
|
||||
method: 'get',
|
||||
params: { neType, neId },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 网元授权激活授权申请码
|
||||
* @param neType 网元类型
|
||||
* @param neId 网元id
|
||||
* @returns object
|
||||
*/
|
||||
export function codeNeLicense(neType: string, neId: string) {
|
||||
return request({
|
||||
url: `/ne/license/code`,
|
||||
method: 'get',
|
||||
params: { neType, neId },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 网元授权激活授权文件替换
|
||||
* @param data 网元对象 {"neType": "", "neId": "", "licensePath": "", "reload": true}
|
||||
* @returns object
|
||||
*/
|
||||
export function changeNeLicense(data: Record<string, any>) {
|
||||
return request({
|
||||
url: `/ne/license/change`,
|
||||
method: 'post',
|
||||
data: data,
|
||||
timeout: 180_000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 网元授权激活状态
|
||||
* @param neType 网元类型
|
||||
* @param neId 网元id
|
||||
* @returns object
|
||||
*/
|
||||
export function stateNeLicense(neType: string, neId: string) {
|
||||
return request({
|
||||
url: `/ne/license/state`,
|
||||
method: 'get',
|
||||
params: { neType, neId },
|
||||
});
|
||||
}
|
||||
80
src/api/ne/neSoftware.ts
Normal file
80
src/api/ne/neSoftware.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { request } from '@/plugins/http-fetch';
|
||||
|
||||
/**
|
||||
* 查询网元版本列表
|
||||
* @param query 查询参数
|
||||
* @returns object
|
||||
*/
|
||||
export function listNeSoftware(query: Record<string, any>) {
|
||||
return request({
|
||||
url: '/ne/software/list',
|
||||
method: 'get',
|
||||
params: query,
|
||||
timeout: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询网元软件包详细
|
||||
* @param softwareId 信息ID
|
||||
* @returns object
|
||||
*/
|
||||
export function getNeSoftware(softwareId: string | number) {
|
||||
return request({
|
||||
url: `/ne/software/${softwareId}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 网元软件包新增
|
||||
* @param data 网元对象
|
||||
* @returns object
|
||||
*/
|
||||
export function addNeSoftware(data: Record<string, any>) {
|
||||
return request({
|
||||
url: `/ne/software`,
|
||||
method: 'post',
|
||||
data: data,
|
||||
repeatSubmit: false,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 网元软件包修改
|
||||
* @param data 网元对象
|
||||
* @returns object
|
||||
*/
|
||||
export function updateNeSoftware(data: Record<string, any>) {
|
||||
return request({
|
||||
url: `/ne/software`,
|
||||
method: 'put',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 网元软件包删除
|
||||
* @param id 信息ID
|
||||
* @returns object
|
||||
*/
|
||||
export function delNeSoftware(softwareIds: string | number) {
|
||||
return request({
|
||||
url: `/ne/software/${softwareIds}`,
|
||||
method: 'delete',
|
||||
timeout: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 网元软件包设为网元新版本
|
||||
* @param data data { "version": "2.2404.18", "neType": "SMF", "name": "smf-r2.2404.18-ub22.deb"}
|
||||
* @returns object
|
||||
*/
|
||||
export function newNeVersion(data: Record<string, any>) {
|
||||
return request({
|
||||
url: `/ne/software/newNeVersion`,
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
41
src/api/ne/neVersion.ts
Normal file
41
src/api/ne/neVersion.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { request } from '@/plugins/http-fetch';
|
||||
|
||||
/**
|
||||
* 查询网元版本列表
|
||||
* @param query 查询参数
|
||||
* @returns object
|
||||
*/
|
||||
export function listNeVersion(query: Record<string, any>) {
|
||||
return request({
|
||||
url: '/ne/version/list',
|
||||
method: 'get',
|
||||
params: query,
|
||||
timeout: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询网元版本详细
|
||||
* @param versionId 信息ID
|
||||
* @returns object
|
||||
*/
|
||||
export function getNeVersion(versionId: string | number) {
|
||||
return request({
|
||||
url: `/ne/version/${versionId}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 网元版本操作
|
||||
* @param data {neType,neId,preinput:{参数},action:"upgrade"}
|
||||
* @returns object
|
||||
*/
|
||||
export function operateNeVersion(data: Record<string, any>) {
|
||||
return request({
|
||||
url: `/ne/version/operate`,
|
||||
method: 'post',
|
||||
data: data,
|
||||
timeout: 180_000,
|
||||
});
|
||||
}
|
||||
28
src/api/neData/amf.ts
Normal file
28
src/api/neData/amf.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { request } from '@/plugins/http-fetch';
|
||||
|
||||
/**
|
||||
* 查询AMF-UE会话事件列表
|
||||
* @param query 查询参数
|
||||
* @returns object
|
||||
*/
|
||||
export function listAMFDataUE(query: Record<string, any>) {
|
||||
return request({
|
||||
url: '/neData/amf/ue/list',
|
||||
method: 'get',
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* AMF-UE会话删除
|
||||
* @param id 信息ID
|
||||
* @returns object
|
||||
*/
|
||||
export function delAMFDataUE(ueIds: string | number) {
|
||||
return request({
|
||||
url: `/neData/amf/ue/${ueIds}`,
|
||||
method: 'delete',
|
||||
timeout: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
28
src/api/neData/ims.ts
Normal file
28
src/api/neData/ims.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { request } from '@/plugins/http-fetch';
|
||||
|
||||
/**
|
||||
* 查询IMS-CDR会话事件
|
||||
* @param query 查询参数
|
||||
* @returns object
|
||||
*/
|
||||
export function listIMSDataCDR(query: Record<string, any>) {
|
||||
return request({
|
||||
url: '/neData/ims/cdr/list',
|
||||
method: 'get',
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* IMS-CDR会话删除
|
||||
* @param id 信息ID
|
||||
* @returns object
|
||||
*/
|
||||
export function delIMSDataCDR(cdrIds: string | number) {
|
||||
return request({
|
||||
url: `/neData/ims/cdr/${cdrIds}`,
|
||||
method: 'delete',
|
||||
timeout: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ export function exportAuth(query: Record<string, any>) {
|
||||
method: 'post',
|
||||
data: query,
|
||||
responseType: 'blob',
|
||||
timeout: 180_000,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -78,6 +79,7 @@ export function updateAuth(data: Record<string, any>) {
|
||||
url: `/ne/udm/auth/${data.neId}`,
|
||||
method: 'put',
|
||||
data: data,
|
||||
timeout: 180_000,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -91,6 +93,7 @@ export function addAuth(data: Record<string, any>) {
|
||||
url: `/ne/udm/auth/${data.neId}`,
|
||||
method: 'post',
|
||||
data: data,
|
||||
timeout: 180_000,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -104,6 +107,7 @@ export function batchAuth(data: Record<string, any>) {
|
||||
url: `/ne/udm/auth/${data.neID}/${data.num}`,
|
||||
method: 'post',
|
||||
data: data,
|
||||
timeout: 180_000,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -129,5 +133,6 @@ export function batchDelAuth(data: Record<string, any>) {
|
||||
return request({
|
||||
url: `/ne/udm/auth/${data.neID}/${data.imsi}/${data.num}`,
|
||||
method: 'delete',
|
||||
timeout: 180_000,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ export async function listBase5G(query: Record<string, any>) {
|
||||
data.rows = rows;
|
||||
}
|
||||
// 模拟数据
|
||||
// data.rows =[{"address":"192.168.1.137:38412","id":"217","name":"","ueNum":0}]
|
||||
// data.rows =[{"address":"192.168.1.137:38412","id":"217","name":"attach-enb-100000-20","ueNum":0}]
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -136,14 +136,21 @@ export async function batchUpdateRule(data: Record<string, any>) {
|
||||
url: `/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo/batch/${data.num}?neId=${data.neId}`,
|
||||
method: 'put',
|
||||
data: data,
|
||||
timeout: 60_000,
|
||||
});
|
||||
// 解析数据
|
||||
if (result.code === RESULT_CODE_SUCCESS && result.data?.status) {
|
||||
return {
|
||||
code: RESULT_CODE_ERROR,
|
||||
msg: result.data?.cause,
|
||||
data: result.data,
|
||||
};
|
||||
if (result.code === RESULT_CODE_SUCCESS) {
|
||||
if (result.data?.status) {
|
||||
return {
|
||||
code: RESULT_CODE_ERROR,
|
||||
msg: result.data?.cause,
|
||||
data: result.data,
|
||||
};
|
||||
}
|
||||
if (result.data?.data) {
|
||||
result.data = result.data.data;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -158,6 +165,7 @@ export async function addRule(data: Record<string, any>) {
|
||||
url: `/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo?neId=${data.neId}`,
|
||||
method: 'post',
|
||||
data: data,
|
||||
timeout: 60_000,
|
||||
});
|
||||
// 解析数据
|
||||
if (result.code === RESULT_CODE_SUCCESS && result.data?.status) {
|
||||
@@ -180,14 +188,21 @@ export async function batchAddRule(data: Record<string, any>) {
|
||||
url: `/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo/batch/${data.num}?neId=${data.neId}`,
|
||||
method: 'post',
|
||||
data: data,
|
||||
timeout: 60_000,
|
||||
});
|
||||
// 解析数据
|
||||
if (result.code === RESULT_CODE_SUCCESS && result.data?.status) {
|
||||
return {
|
||||
code: RESULT_CODE_ERROR,
|
||||
msg: result.data?.cause,
|
||||
data: result.data,
|
||||
};
|
||||
if (result.code === RESULT_CODE_SUCCESS) {
|
||||
if (result.data?.status) {
|
||||
return {
|
||||
code: RESULT_CODE_ERROR,
|
||||
msg: result.data?.cause,
|
||||
data: result.data,
|
||||
};
|
||||
}
|
||||
if (result.data?.data) {
|
||||
result.data = result.data.data;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -197,10 +212,11 @@ export async function batchAddRule(data: Record<string, any>) {
|
||||
* @param data 规则对象
|
||||
* @returns object
|
||||
*/
|
||||
export function delRule(neId: string, data: Record<string, any>) {
|
||||
export function delRule(neId: string, imsi: string) {
|
||||
return request({
|
||||
url: `/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo?neId=${neId}&imsi=${data.imsi}`,
|
||||
url: `/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo?neId=${neId}&imsi=${imsi}`,
|
||||
method: 'delete',
|
||||
timeout: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -213,5 +229,6 @@ export async function batchDelRule(data: Record<string, any>) {
|
||||
return request({
|
||||
url: `/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo/batch/${data.num}?neId=${data.neId}&imsi=${data.imsi}`,
|
||||
method: 'delete',
|
||||
timeout: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -28,35 +28,38 @@ export async function listUEInfoBySMF(query: Record<string, any>) {
|
||||
}
|
||||
|
||||
// 模拟数据
|
||||
// data.code = RESULT_CODE_SUCCESS;
|
||||
// data.rows = [
|
||||
// {
|
||||
// imsi: 'imsi-460029004200044',
|
||||
// msisdn: 'msisdn-12346002044',
|
||||
// imsi: 'imsi-460002082101038',
|
||||
// msisdn: 'msisdn-12307550000',
|
||||
// pduSessionInfo: [
|
||||
// {
|
||||
// activeTime: '2023-11-29 18:39:06',
|
||||
// activeTime: '2024-05-08 11:08:22',
|
||||
// dnn: 'ims',
|
||||
// ipv4: '10.10.48.97',
|
||||
// ipv6: '',
|
||||
// pduSessionID: 6,
|
||||
// ranN3IP: '192.168.8.223',
|
||||
// sstSD: '1-000001',
|
||||
// tai: '46000-0001',
|
||||
// upfN3IP: '192.168.1.161',
|
||||
// },
|
||||
// {
|
||||
// activeTime: '2023-11-29 18:39:05',
|
||||
// dnn: 'cmnet',
|
||||
// ipv4: '10.10.48.62',
|
||||
// ipv4: '10.10.86.2',
|
||||
// ipv6: '',
|
||||
// pduSessionID: 5,
|
||||
// ranN3IP: '192.168.8.223',
|
||||
// ranN3IP: '192.168.5.100',
|
||||
// sstSD: '1-000001',
|
||||
// tai: '46000-0001',
|
||||
// upfN3IP: '192.168.1.163',
|
||||
// tai: '46000-001124',
|
||||
// upState: 'Active',
|
||||
// upfN3IP: '192.168.14.201',
|
||||
// },
|
||||
// {
|
||||
// activeTime: '2024-05-08 11:08:23',
|
||||
// dnn: 'cmnet',
|
||||
// ipv4: '10.10.86.201',
|
||||
// ipv6: '',
|
||||
// pduSessionID: 6,
|
||||
// ranN3IP: '192.168.5.100',
|
||||
// sstSD: '1-000001',
|
||||
// tai: '46000-001124',
|
||||
// upState: 'Active',
|
||||
// upfN3IP: '192.168.14.201',
|
||||
// },
|
||||
// ],
|
||||
// ratType: 'EUTRAN',
|
||||
// ratType: 'NR',
|
||||
// },
|
||||
// ];
|
||||
return data;
|
||||
|
||||
@@ -80,6 +80,7 @@ export function updateSub(neId: string, data: Record<string, any>) {
|
||||
url: `/ne/udm/sub/${neId}`,
|
||||
method: 'put',
|
||||
data: data,
|
||||
timeout: 180_000,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -93,6 +94,7 @@ export function addSub(neID: string, data: Record<string, any>) {
|
||||
url: `/ne/udm/sub/${neID}`,
|
||||
method: 'post',
|
||||
data: data,
|
||||
timeout: 180_000,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -106,6 +108,7 @@ export function batchAddSub(data: Record<string, any>) {
|
||||
url: `/ne/udm/sub/${data.neID}/${data.num}`,
|
||||
method: 'post',
|
||||
data: data,
|
||||
timeout: 180_000,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -131,5 +134,6 @@ export function batchDelSub(data: Record<string, any>) {
|
||||
return request({
|
||||
url: `/ne/udm/sub/${data.neID}/${data.imsi}/${data.num}`,
|
||||
method: 'delete',
|
||||
timeout: 180_000,
|
||||
});
|
||||
}
|
||||
|
||||
146
src/api/perfManage/customTarget.ts
Normal file
146
src/api/perfManage/customTarget.ts
Normal file
@@ -0,0 +1,146 @@
|
||||
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 listCustom(query: Record<string, any>) {
|
||||
let totalSQL = 'select count(*) as total from pm_custom_title where 1=1 ';
|
||||
let rowsSQL = 'select * from pm_custom_title where 1=1 ';
|
||||
|
||||
// 查询
|
||||
let querySQL = '';
|
||||
if (query.neType) {
|
||||
querySQL += ` and ne_type like '%${query.neType}%' `;
|
||||
}
|
||||
|
||||
// 排序
|
||||
let sortSql = ' order by update_time ';
|
||||
if (query.sortOrder === 'asc') {
|
||||
sortSql += ' asc ';
|
||||
} else {
|
||||
sortSql += ' desc ';
|
||||
}
|
||||
// 分页
|
||||
const pageNum = (query.pageNum - 1) * 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 id 网元ID
|
||||
* @returns object
|
||||
*/
|
||||
export async function getCustom(id: string | number) {
|
||||
// 发起请求
|
||||
const result = await request({
|
||||
url: `/api/rest/databaseManagement/v1/select/omc_db/pm_custom_title`,
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增自定义指标
|
||||
* @param data 网元对象
|
||||
* @returns object
|
||||
*/
|
||||
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({
|
||||
url: `/api/rest/databaseManagement/v1/omc_db/pm_custom_title`,
|
||||
method: 'post',
|
||||
data: { 'data': [obj] },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改自定义指标
|
||||
* @param data 网元对象
|
||||
* @returns object
|
||||
*/
|
||||
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({
|
||||
url: `/api/rest/databaseManagement/v1/omc_db/pm_custom_title?WHERE=id=${data.id}`,
|
||||
method: 'put',
|
||||
data: { data: obj },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除自定义指标
|
||||
* @returns object
|
||||
*/
|
||||
export async function delCustom(data: Record<string, any>) {
|
||||
return request({
|
||||
url: `/api/rest/databaseManagement/v1/omc_db/pm_custom_title?WHERE=id=${data.id}`,
|
||||
method: 'delete',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import { request } from '@/plugins/http-fetch';
|
||||
import { parseDateToStr } from '@/utils/date-utils';
|
||||
import { parseObjLineToHump } from '@/utils/parse-utils';
|
||||
|
||||
/**
|
||||
* Todo 废弃
|
||||
* 查询黄金指标数据
|
||||
* @param query 查询参数
|
||||
* @returns object
|
||||
@@ -110,6 +110,7 @@ export async function getKPITitle(neType: string) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Todo 废弃
|
||||
* 查询UPF上下行速率数据
|
||||
* @param query 查询参数
|
||||
* @returns object
|
||||
@@ -126,9 +127,7 @@ export async function listUPFData(timeArr: any) {
|
||||
url: `/api/rest/databaseManagement/v1/select/omc_db/gold_kpi`,
|
||||
method: 'get',
|
||||
params: {
|
||||
SQL: `SELECT gold_kpi.*,kpi_title.en_title FROM gold_kpi LEFT JOIN kpi_title on gold_kpi.kpi_id=kpi_title.kpi_id where 1=1 and gold_kpi.kpi_id ='UPF.03' and timestamp BETWEEN '${parseDateToStr(
|
||||
twentyFourHoursAgo
|
||||
)}' AND '${parseDateToStr(initTime)}' `,
|
||||
SQL: `SELECT gold_kpi.*,kpi_title.en_title FROM gold_kpi LEFT JOIN kpi_title on gold_kpi.kpi_id=kpi_title.kpi_id where 1=1 and gold_kpi.kpi_id ='UPF.03' AND timestamp BETWEEN DATE_SUB(NOW(), INTERVAL 10 MINUTE) AND NOW()`,
|
||||
},
|
||||
timeout: 60_000,
|
||||
}),
|
||||
@@ -137,9 +136,7 @@ export async function listUPFData(timeArr: any) {
|
||||
url: `/api/rest/databaseManagement/v1/select/omc_db/gold_kpi`,
|
||||
method: 'get',
|
||||
params: {
|
||||
SQL: `SELECT gold_kpi.*,kpi_title.en_title FROM gold_kpi LEFT JOIN kpi_title on gold_kpi.kpi_id=kpi_title.kpi_id where 1=1 and gold_kpi.kpi_id ='UPF.06' and timestamp BETWEEN '${parseDateToStr(
|
||||
twentyFourHoursAgo
|
||||
)}' AND '${parseDateToStr(initTime)}' `,
|
||||
SQL: `SELECT gold_kpi.*,kpi_title.en_title FROM gold_kpi LEFT JOIN kpi_title on gold_kpi.kpi_id=kpi_title.kpi_id where 1=1 and gold_kpi.kpi_id ='UPF.06' AND timestamp BETWEEN DATE_SUB(NOW(), INTERVAL 10 MINUTE) AND NOW()`,
|
||||
},
|
||||
timeout: 60_000,
|
||||
}),
|
||||
|
||||
@@ -103,7 +103,7 @@ export function addPerfThre(data: Record<string, any>) {
|
||||
return request({
|
||||
url: `/api/rest/databaseManagement/v1/omc_db/measure_threshold`,
|
||||
method: 'post',
|
||||
data: { measure_task: [obj] },
|
||||
data: { measure_threshold: [obj] },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -115,15 +115,15 @@ export function addPerfThre(data: Record<string, any>) {
|
||||
export function updatePerfThre(data: Record<string, any>) {
|
||||
let obj: any = {
|
||||
ne_type: data.neType,
|
||||
kpi_set: data.performanceArr,
|
||||
kpi_set: data.kpiSet,
|
||||
status: 'Inactive',
|
||||
orig_severity: data.origSeverity,
|
||||
threshold: data.threshold,
|
||||
threshold: ''+data.threshold,
|
||||
};
|
||||
return request({
|
||||
url: `/api/rest/databaseManagement/v1/omc_db/measure_task?WHERE=id=${data.id}`,
|
||||
url: `/api/rest/databaseManagement/v1/omc_db/measure_threshold?WHERE=id=${data.id}`,
|
||||
method: 'put',
|
||||
data: { data: obj },
|
||||
data: { measure_threshold: obj },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
52
src/api/system/quick-start/bootloader.ts
Normal file
52
src/api/system/quick-start/bootloader.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { request } from '@/plugins/http-fetch';
|
||||
|
||||
/**
|
||||
* 首次引导开始
|
||||
* @returns object
|
||||
*/
|
||||
export function bootloaderStart() {
|
||||
return request({
|
||||
url: `/bootloader`,
|
||||
method: 'post',
|
||||
whithToken: false,
|
||||
repeatSubmit: false,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 首次引导完成
|
||||
* @returns object
|
||||
*/
|
||||
export function bootloaderDone() {
|
||||
return request({
|
||||
url: `/bootloader`,
|
||||
method: 'put',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 引导系统数据重置
|
||||
* @returns object
|
||||
*/
|
||||
export function bootloaderReset() {
|
||||
return request({
|
||||
url: `/bootloader`,
|
||||
method: 'delete',
|
||||
timeout: 180_000
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理员账号变更
|
||||
* @returns object
|
||||
*/
|
||||
export function bootloaderAccount(username: string, password: string) {
|
||||
return request({
|
||||
url: `/bootloader/account`,
|
||||
method: 'put',
|
||||
data: {
|
||||
username,
|
||||
password,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -18,6 +18,7 @@ export async function downloadFile(filePath: string, range?: string) {
|
||||
method: 'get',
|
||||
headers: range ? { range } : {},
|
||||
responseType: 'blob',
|
||||
timeout: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -79,6 +80,7 @@ export function uploadFile(data: FormData) {
|
||||
method: 'post',
|
||||
data,
|
||||
dataType: 'form-data',
|
||||
timeout: 180_000,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -94,7 +96,12 @@ export async function uploadFileChunk(
|
||||
chunkSize: number = 1,
|
||||
subPath: string = 'default'
|
||||
) {
|
||||
const { name, size } = fileData;
|
||||
let { name, size } = fileData;
|
||||
// 去除非法字符
|
||||
const cleanedFilename = name.replace(/[\\/:*?"<>|]/g, '');
|
||||
// 去除空格
|
||||
name = cleanedFilename.replace(/\s/g, '_');
|
||||
// 数据块大小
|
||||
const chunkSizeInBytes = chunkSize * 1024 * 1024;
|
||||
// 文件标识使用唯一编码 MD5(文件名+文件大小)
|
||||
const fileIdentifier = `${name}-${size}`;
|
||||
@@ -125,6 +132,7 @@ export async function uploadFileChunk(
|
||||
const chunksIndex = `${index}`;
|
||||
// 跳过已上传块
|
||||
if (resCheck.data.includes(chunksIndex)) {
|
||||
uploadedSize += chunk.size;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -163,6 +171,7 @@ export function chunkCheck(identifier: string, fileName: string) {
|
||||
url: '/file/chunkCheck',
|
||||
method: 'post',
|
||||
data: { identifier, fileName },
|
||||
timeout: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -182,6 +191,7 @@ export function chunkMerge(
|
||||
url: '/file/chunkMerge',
|
||||
method: 'post',
|
||||
data: { identifier, fileName, subPath },
|
||||
timeout: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -196,6 +206,7 @@ export function chunkUpload(data: FormData) {
|
||||
method: 'post',
|
||||
data,
|
||||
dataType: 'form-data',
|
||||
timeout: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -208,6 +219,7 @@ export function transferStaticFile(data: Record<string, any>) {
|
||||
url: `/file/transferStaticFile`,
|
||||
method: 'post',
|
||||
data,
|
||||
timeout: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -235,6 +247,7 @@ export async function uploadFileToNE(
|
||||
neType,
|
||||
neId,
|
||||
},
|
||||
timeout: 60_000,
|
||||
});
|
||||
return transferToNeFileRes;
|
||||
}
|
||||
|
||||
@@ -1,70 +1,117 @@
|
||||
<template>
|
||||
<codemirror
|
||||
:model-value="modelValue"
|
||||
:placeholder="props.placeholder"
|
||||
:style="props.editorStyle"
|
||||
:disabled="props.disabled"
|
||||
:autofocus="false"
|
||||
:indent-with-tab="true"
|
||||
:tab-size="props.tabSize"
|
||||
:extensions="[javascript(), oneDark]"
|
||||
@ready="fnReady"
|
||||
@change="fnChange"
|
||||
/>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { Codemirror } from 'vue-codemirror';
|
||||
import { javascript } from '@codemirror/lang-javascript';
|
||||
import { yaml } from '@codemirror/lang-yaml';
|
||||
import { oneDark } from '@codemirror/theme-one-dark';
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
const emit = defineEmits(['update:value']);
|
||||
import { basicSetup, EditorView } from 'codemirror';
|
||||
import { indentWithTab } from '@codemirror/commands';
|
||||
import { keymap } from '@codemirror/view';
|
||||
import { EditorState } from '@codemirror/state';
|
||||
import { ref, watch, onMounted, onBeforeUnmount } from 'vue';
|
||||
const emit = defineEmits(['update:value', 'change']);
|
||||
const props = defineProps({
|
||||
/**禁用输入使用v-model:value时不生效 */
|
||||
value: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
placeholder: {
|
||||
/**编辑框高度 */
|
||||
height: {
|
||||
type: String,
|
||||
default: 'input context here...',
|
||||
},
|
||||
/**是否禁止输入 */
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
editorStyle: {
|
||||
type: Object,
|
||||
default: () => ({ height: '400px !important' }),
|
||||
default: '400px',
|
||||
},
|
||||
/**缩进2空格 */
|
||||
tabSize: {
|
||||
type: Number,
|
||||
default: 2,
|
||||
},
|
||||
/**是否禁止输入 */
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
/**高亮语言 支持javascript、yaml */
|
||||
lang: {
|
||||
type: String,
|
||||
default: 'javascript',
|
||||
},
|
||||
});
|
||||
|
||||
// 绑定值
|
||||
const modelValue = ref<string>('');
|
||||
/**视图容器 */
|
||||
const viewContainerDom = ref<HTMLElement | undefined>(undefined);
|
||||
let viewContainer: EditorView | null = null;
|
||||
|
||||
/**变更时更新绑定值 */
|
||||
function fnChange(value: string, viewUpdate: any) {
|
||||
if (props.disabled) return;
|
||||
emit('update:value', value);
|
||||
/**高亮语言拓展 */
|
||||
function fnLangExtension() {
|
||||
if (props.lang === 'yaml') {
|
||||
return yaml();
|
||||
}
|
||||
return javascript();
|
||||
}
|
||||
|
||||
/**组件渲染后 */
|
||||
function fnReady(payload: any) {
|
||||
modelValue.value = props.value;
|
||||
/**初始化渲染视图 */
|
||||
function handleRanderView(container: HTMLElement | undefined) {
|
||||
if (!container) return;
|
||||
viewContainer = new EditorView({
|
||||
doc: props.value,
|
||||
extensions: [
|
||||
oneDark,
|
||||
basicSetup,
|
||||
keymap.of([indentWithTab]),
|
||||
fnLangExtension(),
|
||||
EditorView.editable.of(!props.disabled),
|
||||
EditorState.readOnly.of(props.disabled),
|
||||
EditorState.tabSize.of(props.tabSize),
|
||||
EditorView.updateListener.of(v => {
|
||||
if (v.docChanged) {
|
||||
const docStr = v.state.doc.toString();
|
||||
emit('change', docStr, v.state.doc);
|
||||
// 禁用时不双向绑定,防止监听重复变化数值
|
||||
if (!props.disabled) {
|
||||
emit('update:value', docStr);
|
||||
}
|
||||
}
|
||||
}),
|
||||
],
|
||||
parent: container,
|
||||
});
|
||||
}
|
||||
|
||||
/**监听是否value改变 */
|
||||
watch(
|
||||
() => props.value,
|
||||
val => {
|
||||
modelValue.value = val;
|
||||
// 禁用时无输入靠外部值变化改变数值
|
||||
if (props.disabled && viewContainer) {
|
||||
const docLine = viewContainer.state.doc.length;
|
||||
viewContainer.dispatch({
|
||||
changes: { from: 0, to: docLine, insert: val },
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
handleRanderView(viewContainerDom.value);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
viewContainer?.destroy();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
<template>
|
||||
<div
|
||||
ref="viewContainerDom"
|
||||
class="container"
|
||||
:style="{ '--editor-height': height }"
|
||||
></div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
--editor-height: 400px;
|
||||
}
|
||||
.container :deep(.cm-editor) {
|
||||
height: var(--editor-height);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,116 +1,131 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:title="props.title"
|
||||
width="80%"
|
||||
:visible="props.visible"
|
||||
:body-style="{ padding: '0 24px' }"
|
||||
:destroy-on-close="true"
|
||||
@cancel="fnCronModal(false)"
|
||||
@ok="fnCronModal(true)"
|
||||
>
|
||||
<div ref="mergeViewContainer" class="mergeViewContainer"></div>
|
||||
</a-modal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { javascript } from '@codemirror/lang-javascript';
|
||||
import { yaml } from '@codemirror/lang-yaml';
|
||||
import { oneDark } from '@codemirror/theme-one-dark';
|
||||
import { MergeView } from '@codemirror/merge';
|
||||
import { EditorView, basicSetup } from 'codemirror';
|
||||
import { EditorState } from '@codemirror/state';
|
||||
|
||||
import { watch, ref } from 'vue';
|
||||
import { nextTick } from 'vue';
|
||||
|
||||
const emit = defineEmits(['cancel', 'ok', 'update:visible']);
|
||||
import { ref, onMounted, onBeforeUnmount, watch } from 'vue';
|
||||
const emit = defineEmits(['update:newArea', 'change']);
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: '内容比较',
|
||||
},
|
||||
newArea: {
|
||||
type: String,
|
||||
default: '当前内容',
|
||||
},
|
||||
oldArea: {
|
||||
type: String,
|
||||
default: '原始内容',
|
||||
},
|
||||
/**当前变更内容 */
|
||||
newArea: {
|
||||
type: String,
|
||||
default: '当前内容',
|
||||
},
|
||||
/**编辑框高度 */
|
||||
height: {
|
||||
type: String,
|
||||
default: '400px !important',
|
||||
default: '400px',
|
||||
},
|
||||
/**缩进2空格 */
|
||||
tabSize: {
|
||||
type: Number,
|
||||
default: 2,
|
||||
},
|
||||
/**是否禁止输入 */
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
/**高亮语言 */
|
||||
lang: {
|
||||
type: String,
|
||||
default: 'javascript',
|
||||
},
|
||||
});
|
||||
|
||||
const mergeViewContainer = ref();
|
||||
/**视图容器 */
|
||||
const viewContainerDom = ref<HTMLElement | undefined>(undefined);
|
||||
let viewContainer: MergeView | null = null;
|
||||
|
||||
/**监听是否显示,初始cron属性 */
|
||||
/**高亮语言拓展 */
|
||||
function fnLangExtension() {
|
||||
if (props.lang === 'yaml') {
|
||||
return yaml();
|
||||
}
|
||||
return javascript();
|
||||
}
|
||||
|
||||
/**初始化渲染视图 */
|
||||
function handleRanderView(container: HTMLElement | undefined) {
|
||||
if (!container) return;
|
||||
viewContainer = new MergeView({
|
||||
a: {
|
||||
doc: props.oldArea,
|
||||
extensions: [
|
||||
fnLangExtension(),
|
||||
oneDark,
|
||||
basicSetup,
|
||||
EditorView.editable.of(false),
|
||||
EditorState.readOnly.of(true),
|
||||
],
|
||||
},
|
||||
b: {
|
||||
doc: props.newArea,
|
||||
extensions: [
|
||||
fnLangExtension(),
|
||||
oneDark,
|
||||
basicSetup,
|
||||
EditorView.editable.of(!props.disabled),
|
||||
EditorState.readOnly.of(props.disabled),
|
||||
EditorState.tabSize.of(props.tabSize),
|
||||
EditorView.updateListener.of(v => {
|
||||
if (v.docChanged) {
|
||||
const docStr = v.state.doc.toString();
|
||||
emit('change', docStr, v.state.doc);
|
||||
// 禁用时不双向绑定,防止监听重复变化数值
|
||||
if (!props.disabled) {
|
||||
emit('update:newArea', docStr);
|
||||
}
|
||||
}
|
||||
}),
|
||||
],
|
||||
},
|
||||
parent: container,
|
||||
});
|
||||
}
|
||||
|
||||
/**监听是否value改变 */
|
||||
watch(
|
||||
() => props.visible,
|
||||
() => props.newArea,
|
||||
val => {
|
||||
if (val) {
|
||||
// 开启时等待dom完成
|
||||
|
||||
nextTick(() => {
|
||||
// 设置高度
|
||||
mergeViewContainer.value.style.height = props.height;
|
||||
// 实例到dom
|
||||
new MergeView({
|
||||
a: {
|
||||
doc: props.oldArea,
|
||||
extensions: [
|
||||
javascript(),
|
||||
oneDark,
|
||||
basicSetup,
|
||||
EditorView.editable.of(false),
|
||||
EditorState.readOnly.of(true),
|
||||
],
|
||||
},
|
||||
b: {
|
||||
doc: props.newArea,
|
||||
extensions: [
|
||||
javascript(),
|
||||
oneDark,
|
||||
basicSetup,
|
||||
EditorView.editable.of(!props.disabled),
|
||||
EditorState.readOnly.of(props.disabled),
|
||||
],
|
||||
},
|
||||
parent: mergeViewContainer.value,
|
||||
});
|
||||
// 禁用时无输入靠外部值变化改变数值
|
||||
if (props.disabled && viewContainer) {
|
||||
const docLine = viewContainer.b.state.doc.length;
|
||||
viewContainer.b.dispatch({
|
||||
changes: { from: 0, to: docLine, insert: val },
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* 窗口事件
|
||||
* @param val modal触发事件
|
||||
*/
|
||||
function fnCronModal(val: boolean) {
|
||||
emit('update:visible', false);
|
||||
if (val) {
|
||||
emit('ok', true);
|
||||
} else {
|
||||
emit('cancel');
|
||||
}
|
||||
}
|
||||
onMounted(() => {
|
||||
handleRanderView(viewContainerDom.value);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
viewContainer?.destroy();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
ref="viewContainerDom"
|
||||
class="container"
|
||||
:style="{ '--editor-height': height }"
|
||||
></div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.mergeViewContainer {
|
||||
height: 400px;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
color: #abb2bf;
|
||||
background-color: #282c34;
|
||||
.container {
|
||||
--editor-height: 400px;
|
||||
}
|
||||
.container :deep(.cm-editor) {
|
||||
height: var(--editor-height);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -15,14 +15,24 @@ const props = defineProps({
|
||||
type: [Number, String],
|
||||
default: '',
|
||||
},
|
||||
/**数据默认值,当前值不存在时 */
|
||||
valueOption: {
|
||||
type: [Number, String],
|
||||
},
|
||||
});
|
||||
|
||||
/**遍历找到对应值数据项 */
|
||||
const item = computed(() => {
|
||||
if (Array.isArray(props.options) && props.options.length > 0) {
|
||||
const option = (props.options as any[]).find(
|
||||
let option = (props.options as any[]).find(
|
||||
item => `${item[props.valueField]}` === `${props.value}`
|
||||
);
|
||||
// 数据默认值
|
||||
if (props.valueOption != undefined && !option) {
|
||||
option = (props.options as any[]).find(
|
||||
item => `${item[props.valueField]}` === `${props.valueOption }`
|
||||
);
|
||||
}
|
||||
return option;
|
||||
}
|
||||
return undefined;
|
||||
|
||||
@@ -48,7 +48,7 @@ const props = defineProps({
|
||||
default: false,
|
||||
},
|
||||
footer: {
|
||||
type: Object,
|
||||
type: Object as any,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
252
src/components/IntlTelInput/i18n/en/countries.ts
Normal file
252
src/components/IntlTelInput/i18n/en/countries.ts
Normal file
@@ -0,0 +1,252 @@
|
||||
//* THIS FILE IS AUTO-GENERATED. DO NOT EDIT.
|
||||
export default {
|
||||
af: "Afghanistan",
|
||||
ax: "Åland Islands",
|
||||
al: "Albania",
|
||||
dz: "Algeria",
|
||||
as: "American Samoa",
|
||||
ad: "Andorra",
|
||||
ao: "Angola",
|
||||
ai: "Anguilla",
|
||||
aq: "Antarctica",
|
||||
ag: "Antigua & Barbuda",
|
||||
ar: "Argentina",
|
||||
am: "Armenia",
|
||||
aw: "Aruba",
|
||||
au: "Australia",
|
||||
at: "Austria",
|
||||
az: "Azerbaijan",
|
||||
bs: "Bahamas",
|
||||
bh: "Bahrain",
|
||||
bd: "Bangladesh",
|
||||
bb: "Barbados",
|
||||
by: "Belarus",
|
||||
be: "Belgium",
|
||||
bz: "Belize",
|
||||
bj: "Benin",
|
||||
bm: "Bermuda",
|
||||
bt: "Bhutan",
|
||||
bo: "Bolivia",
|
||||
ba: "Bosnia & Herzegovina",
|
||||
bw: "Botswana",
|
||||
bv: "Bouvet Island",
|
||||
br: "Brazil",
|
||||
io: "British Indian Ocean Territory",
|
||||
vg: "British Virgin Islands",
|
||||
bn: "Brunei",
|
||||
bg: "Bulgaria",
|
||||
bf: "Burkina Faso",
|
||||
bi: "Burundi",
|
||||
kh: "Cambodia",
|
||||
cm: "Cameroon",
|
||||
ca: "Canada",
|
||||
cv: "Cape Verde",
|
||||
bq: "Caribbean Netherlands",
|
||||
ky: "Cayman Islands",
|
||||
cf: "Central African Republic",
|
||||
td: "Chad",
|
||||
cl: "Chile",
|
||||
cn: "China",
|
||||
cx: "Christmas Island",
|
||||
cc: "Cocos (Keeling) Islands",
|
||||
co: "Colombia",
|
||||
km: "Comoros",
|
||||
cg: "Congo - Brazzaville",
|
||||
cd: "Congo - Kinshasa",
|
||||
ck: "Cook Islands",
|
||||
cr: "Costa Rica",
|
||||
ci: "Côte d’Ivoire",
|
||||
hr: "Croatia",
|
||||
cu: "Cuba",
|
||||
cw: "Curaçao",
|
||||
cy: "Cyprus",
|
||||
cz: "Czechia",
|
||||
dk: "Denmark",
|
||||
dj: "Djibouti",
|
||||
dm: "Dominica",
|
||||
do: "Dominican Republic",
|
||||
ec: "Ecuador",
|
||||
eg: "Egypt",
|
||||
sv: "El Salvador",
|
||||
gq: "Equatorial Guinea",
|
||||
er: "Eritrea",
|
||||
ee: "Estonia",
|
||||
sz: "Eswatini",
|
||||
et: "Ethiopia",
|
||||
fk: "Falkland Islands",
|
||||
fo: "Faroe Islands",
|
||||
fj: "Fiji",
|
||||
fi: "Finland",
|
||||
fr: "France",
|
||||
gf: "French Guiana",
|
||||
pf: "French Polynesia",
|
||||
tf: "French Southern Territories",
|
||||
ga: "Gabon",
|
||||
gm: "Gambia",
|
||||
ge: "Georgia",
|
||||
de: "Germany",
|
||||
gh: "Ghana",
|
||||
gi: "Gibraltar",
|
||||
gr: "Greece",
|
||||
gl: "Greenland",
|
||||
gd: "Grenada",
|
||||
gp: "Guadeloupe",
|
||||
gu: "Guam",
|
||||
gt: "Guatemala",
|
||||
gg: "Guernsey",
|
||||
gn: "Guinea",
|
||||
gw: "Guinea-Bissau",
|
||||
gy: "Guyana",
|
||||
ht: "Haiti",
|
||||
hm: "Heard & McDonald Islands",
|
||||
hn: "Honduras",
|
||||
hk: "Hong Kong SAR China",
|
||||
hu: "Hungary",
|
||||
is: "Iceland",
|
||||
in: "India",
|
||||
id: "Indonesia",
|
||||
ir: "Iran",
|
||||
iq: "Iraq",
|
||||
ie: "Ireland",
|
||||
im: "Isle of Man",
|
||||
il: "Israel",
|
||||
it: "Italy",
|
||||
jm: "Jamaica",
|
||||
jp: "Japan",
|
||||
je: "Jersey",
|
||||
jo: "Jordan",
|
||||
kz: "Kazakhstan",
|
||||
ke: "Kenya",
|
||||
ki: "Kiribati",
|
||||
kw: "Kuwait",
|
||||
kg: "Kyrgyzstan",
|
||||
la: "Laos",
|
||||
lv: "Latvia",
|
||||
lb: "Lebanon",
|
||||
ls: "Lesotho",
|
||||
lr: "Liberia",
|
||||
ly: "Libya",
|
||||
li: "Liechtenstein",
|
||||
lt: "Lithuania",
|
||||
lu: "Luxembourg",
|
||||
mo: "Macao SAR China",
|
||||
mg: "Madagascar",
|
||||
mw: "Malawi",
|
||||
my: "Malaysia",
|
||||
mv: "Maldives",
|
||||
ml: "Mali",
|
||||
mt: "Malta",
|
||||
mh: "Marshall Islands",
|
||||
mq: "Martinique",
|
||||
mr: "Mauritania",
|
||||
mu: "Mauritius",
|
||||
yt: "Mayotte",
|
||||
mx: "Mexico",
|
||||
fm: "Micronesia",
|
||||
md: "Moldova",
|
||||
mc: "Monaco",
|
||||
mn: "Mongolia",
|
||||
me: "Montenegro",
|
||||
ms: "Montserrat",
|
||||
ma: "Morocco",
|
||||
mz: "Mozambique",
|
||||
mm: "Myanmar (Burma)",
|
||||
na: "Namibia",
|
||||
nr: "Nauru",
|
||||
np: "Nepal",
|
||||
nl: "Netherlands",
|
||||
nc: "New Caledonia",
|
||||
nz: "New Zealand",
|
||||
ni: "Nicaragua",
|
||||
ne: "Niger",
|
||||
ng: "Nigeria",
|
||||
nu: "Niue",
|
||||
nf: "Norfolk Island",
|
||||
kp: "North Korea",
|
||||
mk: "North Macedonia",
|
||||
mp: "Northern Mariana Islands",
|
||||
no: "Norway",
|
||||
om: "Oman",
|
||||
pk: "Pakistan",
|
||||
pw: "Palau",
|
||||
ps: "Palestinian Territories",
|
||||
pa: "Panama",
|
||||
pg: "Papua New Guinea",
|
||||
py: "Paraguay",
|
||||
pe: "Peru",
|
||||
ph: "Philippines",
|
||||
pn: "Pitcairn Islands",
|
||||
pl: "Poland",
|
||||
pt: "Portugal",
|
||||
pr: "Puerto Rico",
|
||||
qa: "Qatar",
|
||||
re: "Réunion",
|
||||
ro: "Romania",
|
||||
ru: "Russia",
|
||||
rw: "Rwanda",
|
||||
ws: "Samoa",
|
||||
sm: "San Marino",
|
||||
st: "São Tomé & Príncipe",
|
||||
sa: "Saudi Arabia",
|
||||
sn: "Senegal",
|
||||
rs: "Serbia",
|
||||
sc: "Seychelles",
|
||||
sl: "Sierra Leone",
|
||||
sg: "Singapore",
|
||||
sx: "Sint Maarten",
|
||||
sk: "Slovakia",
|
||||
si: "Slovenia",
|
||||
sb: "Solomon Islands",
|
||||
so: "Somalia",
|
||||
za: "South Africa",
|
||||
gs: "South Georgia & South Sandwich Islands",
|
||||
kr: "South Korea",
|
||||
ss: "South Sudan",
|
||||
es: "Spain",
|
||||
lk: "Sri Lanka",
|
||||
bl: "St. Barthélemy",
|
||||
sh: "St. Helena",
|
||||
kn: "St. Kitts & Nevis",
|
||||
lc: "St. Lucia",
|
||||
mf: "St. Martin",
|
||||
pm: "St. Pierre & Miquelon",
|
||||
vc: "St. Vincent & Grenadines",
|
||||
sd: "Sudan",
|
||||
sr: "Suriname",
|
||||
sj: "Svalbard & Jan Mayen",
|
||||
se: "Sweden",
|
||||
ch: "Switzerland",
|
||||
sy: "Syria",
|
||||
tw: "Taiwan",
|
||||
tj: "Tajikistan",
|
||||
tz: "Tanzania",
|
||||
th: "Thailand",
|
||||
tl: "Timor-Leste",
|
||||
tg: "Togo",
|
||||
tk: "Tokelau",
|
||||
to: "Tonga",
|
||||
tt: "Trinidad & Tobago",
|
||||
tn: "Tunisia",
|
||||
tr: "Turkey",
|
||||
tm: "Turkmenistan",
|
||||
tc: "Turks & Caicos Islands",
|
||||
tv: "Tuvalu",
|
||||
um: "U.S. Outlying Islands",
|
||||
vi: "U.S. Virgin Islands",
|
||||
ug: "Uganda",
|
||||
ua: "Ukraine",
|
||||
ae: "United Arab Emirates",
|
||||
gb: "United Kingdom",
|
||||
us: "United States",
|
||||
uy: "Uruguay",
|
||||
uz: "Uzbekistan",
|
||||
vu: "Vanuatu",
|
||||
va: "Vatican City",
|
||||
ve: "Venezuela",
|
||||
vn: "Vietnam",
|
||||
wf: "Wallis & Futuna",
|
||||
eh: "Western Sahara",
|
||||
ye: "Yemen",
|
||||
zm: "Zambia",
|
||||
zw: "Zimbabwe",
|
||||
};
|
||||
4
src/components/IntlTelInput/i18n/en/index.ts
Normal file
4
src/components/IntlTelInput/i18n/en/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import countryTranslations from './countries';
|
||||
import interfaceTranslations from './interface';
|
||||
|
||||
export default { ...countryTranslations, ...interfaceTranslations };
|
||||
14
src/components/IntlTelInput/i18n/en/interface.ts
Normal file
14
src/components/IntlTelInput/i18n/en/interface.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
//* English. Translated by: Jack O'Connor (jackocnr).
|
||||
export default {
|
||||
selectedCountryAriaLabel: "Selected country",
|
||||
noCountrySelected: "No country selected",
|
||||
countryListAriaLabel: "List of countries",
|
||||
searchPlaceholder: "Search",
|
||||
zeroSearchResults: "No results found",
|
||||
oneSearchResult: "1 result found",
|
||||
multipleSearchResults: "${count} results found",
|
||||
|
||||
// additional countries (not supported by country-list library)
|
||||
ac: "Ascension Island",
|
||||
xk: "Kosovo",
|
||||
};
|
||||
252
src/components/IntlTelInput/i18n/zh/countries.ts
Normal file
252
src/components/IntlTelInput/i18n/zh/countries.ts
Normal file
@@ -0,0 +1,252 @@
|
||||
//* THIS FILE IS AUTO-GENERATED. DO NOT EDIT.
|
||||
export default {
|
||||
al: "阿尔巴尼亚",
|
||||
dz: "阿尔及利亚",
|
||||
af: "阿富汗",
|
||||
ar: "阿根廷",
|
||||
ae: "阿拉伯联合酋长国",
|
||||
aw: "阿鲁巴",
|
||||
om: "阿曼",
|
||||
az: "阿塞拜疆",
|
||||
eg: "埃及",
|
||||
et: "埃塞俄比亚",
|
||||
ie: "爱尔兰",
|
||||
ee: "爱沙尼亚",
|
||||
ad: "安道尔",
|
||||
ao: "安哥拉",
|
||||
ai: "安圭拉",
|
||||
ag: "安提瓜和巴布达",
|
||||
at: "奥地利",
|
||||
ax: "奥兰群岛",
|
||||
au: "澳大利亚",
|
||||
bb: "巴巴多斯",
|
||||
pg: "巴布亚新几内亚",
|
||||
bs: "巴哈马",
|
||||
pk: "巴基斯坦",
|
||||
py: "巴拉圭",
|
||||
ps: "巴勒斯坦领土",
|
||||
bh: "巴林",
|
||||
pa: "巴拿马",
|
||||
br: "巴西",
|
||||
by: "白俄罗斯",
|
||||
bm: "百慕大",
|
||||
bg: "保加利亚",
|
||||
mp: "北马里亚纳群岛",
|
||||
mk: "北马其顿",
|
||||
bj: "贝宁",
|
||||
be: "比利时",
|
||||
is: "冰岛",
|
||||
pr: "波多黎各",
|
||||
pl: "波兰",
|
||||
ba: "波斯尼亚和黑塞哥维那",
|
||||
bo: "玻利维亚",
|
||||
bz: "伯利兹",
|
||||
bw: "博茨瓦纳",
|
||||
bt: "不丹",
|
||||
bf: "布基纳法索",
|
||||
bi: "布隆迪",
|
||||
bv: "布韦岛",
|
||||
kp: "朝鲜",
|
||||
gq: "赤道几内亚",
|
||||
dk: "丹麦",
|
||||
de: "德国",
|
||||
tl: "东帝汶",
|
||||
tg: "多哥",
|
||||
do: "多米尼加共和国",
|
||||
dm: "多米尼克",
|
||||
ru: "俄罗斯",
|
||||
ec: "厄瓜多尔",
|
||||
er: "厄立特里亚",
|
||||
fr: "法国",
|
||||
fo: "法罗群岛",
|
||||
pf: "法属波利尼西亚",
|
||||
gf: "法属圭亚那",
|
||||
tf: "法属南部领地",
|
||||
mf: "法属圣马丁",
|
||||
va: "梵蒂冈",
|
||||
ph: "菲律宾",
|
||||
fj: "斐济",
|
||||
fi: "芬兰",
|
||||
cv: "佛得角",
|
||||
fk: "福克兰群岛",
|
||||
gm: "冈比亚",
|
||||
cg: "刚果(布)",
|
||||
cd: "刚果(金)",
|
||||
co: "哥伦比亚",
|
||||
cr: "哥斯达黎加",
|
||||
gd: "格林纳达",
|
||||
gl: "格陵兰",
|
||||
ge: "格鲁吉亚",
|
||||
gg: "根西岛",
|
||||
cu: "古巴",
|
||||
gp: "瓜德罗普",
|
||||
gu: "关岛",
|
||||
gy: "圭亚那",
|
||||
kz: "哈萨克斯坦",
|
||||
ht: "海地",
|
||||
kr: "韩国",
|
||||
nl: "荷兰",
|
||||
bq: "荷属加勒比区",
|
||||
sx: "荷属圣马丁",
|
||||
hm: "赫德岛和麦克唐纳群岛",
|
||||
me: "黑山",
|
||||
hn: "洪都拉斯",
|
||||
ki: "基里巴斯",
|
||||
dj: "吉布提",
|
||||
kg: "吉尔吉斯斯坦",
|
||||
gn: "几内亚",
|
||||
gw: "几内亚比绍",
|
||||
ca: "加拿大",
|
||||
gh: "加纳",
|
||||
ga: "加蓬",
|
||||
kh: "柬埔寨",
|
||||
cz: "捷克",
|
||||
zw: "津巴布韦",
|
||||
cm: "喀麦隆",
|
||||
qa: "卡塔尔",
|
||||
ky: "开曼群岛",
|
||||
cc: "科科斯(基林)群岛",
|
||||
km: "科摩罗",
|
||||
ci: "科特迪瓦",
|
||||
kw: "科威特",
|
||||
hr: "克罗地亚",
|
||||
ke: "肯尼亚",
|
||||
ck: "库克群岛",
|
||||
cw: "库拉索",
|
||||
lv: "拉脱维亚",
|
||||
ls: "莱索托",
|
||||
la: "老挝",
|
||||
lb: "黎巴嫩",
|
||||
lt: "立陶宛",
|
||||
lr: "利比里亚",
|
||||
ly: "利比亚",
|
||||
li: "列支敦士登",
|
||||
re: "留尼汪",
|
||||
lu: "卢森堡",
|
||||
rw: "卢旺达",
|
||||
ro: "罗马尼亚",
|
||||
mg: "马达加斯加",
|
||||
im: "马恩岛",
|
||||
mv: "马尔代夫",
|
||||
mt: "马耳他",
|
||||
mw: "马拉维",
|
||||
my: "马来西亚",
|
||||
ml: "马里",
|
||||
mh: "马绍尔群岛",
|
||||
mq: "马提尼克",
|
||||
yt: "马约特",
|
||||
mu: "毛里求斯",
|
||||
mr: "毛里塔尼亚",
|
||||
us: "美国",
|
||||
um: "美国本土外小岛屿",
|
||||
as: "美属萨摩亚",
|
||||
vi: "美属维尔京群岛",
|
||||
mn: "蒙古",
|
||||
ms: "蒙特塞拉特",
|
||||
bd: "孟加拉国",
|
||||
pe: "秘鲁",
|
||||
fm: "密克罗尼西亚",
|
||||
mm: "缅甸",
|
||||
md: "摩尔多瓦",
|
||||
ma: "摩洛哥",
|
||||
mc: "摩纳哥",
|
||||
mz: "莫桑比克",
|
||||
mx: "墨西哥",
|
||||
na: "纳米比亚",
|
||||
za: "南非",
|
||||
aq: "南极洲",
|
||||
gs: "南乔治亚和南桑威奇群岛",
|
||||
ss: "南苏丹",
|
||||
nr: "瑙鲁",
|
||||
ni: "尼加拉瓜",
|
||||
np: "尼泊尔",
|
||||
ne: "尼日尔",
|
||||
ng: "尼日利亚",
|
||||
nu: "纽埃",
|
||||
no: "挪威",
|
||||
nf: "诺福克岛",
|
||||
pw: "帕劳",
|
||||
pn: "皮特凯恩群岛",
|
||||
pt: "葡萄牙",
|
||||
jp: "日本",
|
||||
se: "瑞典",
|
||||
ch: "瑞士",
|
||||
sv: "萨尔瓦多",
|
||||
ws: "萨摩亚",
|
||||
rs: "塞尔维亚",
|
||||
sl: "塞拉利昂",
|
||||
sn: "塞内加尔",
|
||||
cy: "塞浦路斯",
|
||||
sc: "塞舌尔",
|
||||
sa: "沙特阿拉伯",
|
||||
bl: "圣巴泰勒米",
|
||||
cx: "圣诞岛",
|
||||
st: "圣多美和普林西比",
|
||||
sh: "圣赫勒拿",
|
||||
kn: "圣基茨和尼维斯",
|
||||
lc: "圣卢西亚",
|
||||
sm: "圣马力诺",
|
||||
pm: "圣皮埃尔和密克隆群岛",
|
||||
vc: "圣文森特和格林纳丁斯",
|
||||
lk: "斯里兰卡",
|
||||
sk: "斯洛伐克",
|
||||
si: "斯洛文尼亚",
|
||||
sj: "斯瓦尔巴和扬马延",
|
||||
sz: "斯威士兰",
|
||||
sd: "苏丹",
|
||||
sr: "苏里南",
|
||||
sb: "所罗门群岛",
|
||||
so: "索马里",
|
||||
tj: "塔吉克斯坦",
|
||||
tw: "台湾",
|
||||
th: "泰国",
|
||||
tz: "坦桑尼亚",
|
||||
to: "汤加",
|
||||
tc: "特克斯和凯科斯群岛",
|
||||
tt: "特立尼达和多巴哥",
|
||||
tn: "突尼斯",
|
||||
tv: "图瓦卢",
|
||||
tr: "土耳其",
|
||||
tm: "土库曼斯坦",
|
||||
tk: "托克劳",
|
||||
wf: "瓦利斯和富图纳",
|
||||
vu: "瓦努阿图",
|
||||
gt: "危地马拉",
|
||||
ve: "委内瑞拉",
|
||||
bn: "文莱",
|
||||
ug: "乌干达",
|
||||
ua: "乌克兰",
|
||||
uy: "乌拉圭",
|
||||
uz: "乌兹别克斯坦",
|
||||
es: "西班牙",
|
||||
eh: "西撒哈拉",
|
||||
gr: "希腊",
|
||||
sg: "新加坡",
|
||||
nc: "新喀里多尼亚",
|
||||
nz: "新西兰",
|
||||
hu: "匈牙利",
|
||||
sy: "叙利亚",
|
||||
jm: "牙买加",
|
||||
am: "亚美尼亚",
|
||||
ye: "也门",
|
||||
iq: "伊拉克",
|
||||
ir: "伊朗",
|
||||
il: "以色列",
|
||||
it: "意大利",
|
||||
in: "印度",
|
||||
id: "印度尼西亚",
|
||||
gb: "英国",
|
||||
vg: "英属维尔京群岛",
|
||||
io: "英属印度洋领地",
|
||||
jo: "约旦",
|
||||
vn: "越南",
|
||||
zm: "赞比亚",
|
||||
je: "泽西岛",
|
||||
td: "乍得",
|
||||
gi: "直布罗陀",
|
||||
cl: "智利",
|
||||
cf: "中非共和国",
|
||||
cn: "中国",
|
||||
mo: "中国澳门特别行政区",
|
||||
hk: "中国香港特别行政区",
|
||||
};
|
||||
4
src/components/IntlTelInput/i18n/zh/index.ts
Normal file
4
src/components/IntlTelInput/i18n/zh/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import countryTranslations from './countries';
|
||||
import interfaceTranslations from './interface';
|
||||
|
||||
export default { ...countryTranslations, ...interfaceTranslations };
|
||||
15
src/components/IntlTelInput/i18n/zh/interface.ts
Normal file
15
src/components/IntlTelInput/i18n/zh/interface.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
//* Chinese (Simplified). Translated by: Google Translate.
|
||||
export default {
|
||||
selectedCountryAriaLabel: "所选国家",
|
||||
noCountrySelected: "未选择国家/地区",
|
||||
countryListAriaLabel: "国家名单",
|
||||
searchPlaceholder: "搜索",
|
||||
zeroSearchResults: "未找到结果",
|
||||
oneSearchResult: "找到 1 个结果",
|
||||
multipleSearchResults: "找到 ${count} 个结果",
|
||||
|
||||
// additional countries (not supported by country-list library)
|
||||
ac: "阿森松岛",
|
||||
xk: "科索沃",
|
||||
};
|
||||
|
||||
145
src/components/IntlTelInput/index.vue
Normal file
145
src/components/IntlTelInput/index.vue
Normal file
@@ -0,0 +1,145 @@
|
||||
<!-- https://github.com/jackocnr/intl-tel-input/blob/master/react/src/intl-tel-input/react.tsx -->
|
||||
<script lang="ts" setup>
|
||||
import intlTelInput, { Iti, SomeOptions } from 'intl-tel-input';
|
||||
import 'intl-tel-input/build/css/intlTelInput.min.css';
|
||||
import 'intl-tel-input/build/js/utils.js';
|
||||
import { ref, onMounted, onBeforeUnmount, nextTick, watch } from 'vue';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
const { currentLocale } = useI18n();
|
||||
const emit = defineEmits(['update:value', 'update:change']);
|
||||
const props = defineProps({
|
||||
/**有效检验 */
|
||||
preciseValidation: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**手机号 */
|
||||
value: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
/**禁用输入 */
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**手机号输入提示 */
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
/**手机号输入最大字符串长度 */
|
||||
maxlength: {
|
||||
type: Number,
|
||||
default: 255,
|
||||
},
|
||||
/**允许清空手机号输入框 */
|
||||
allowClear: {
|
||||
type: Boolean,
|
||||
},
|
||||
});
|
||||
|
||||
const inputRef = ref<HTMLInputElement | null>(null);
|
||||
const itiRef = ref<Iti | null>(null);
|
||||
|
||||
function fnChange() {
|
||||
if (!itiRef.value) return;
|
||||
|
||||
const num = itiRef.value?.getNumber() || '';
|
||||
const countryIso = itiRef.value?.getSelectedCountryData().iso2 || '';
|
||||
// note: this number will be in standard E164 format, but any container component can use
|
||||
// intlTelInputUtils.formatNumber() to convert this to another format
|
||||
// as well as intlTelInputUtils.getNumberType() etc. if need be
|
||||
let data = {
|
||||
num,
|
||||
countryIso,
|
||||
validity: false,
|
||||
errorCode: -1,
|
||||
};
|
||||
|
||||
const isValid = props.preciseValidation
|
||||
? itiRef.value.isValidNumberPrecise()
|
||||
: itiRef.value.isValidNumber();
|
||||
if (isValid) {
|
||||
data.validity = true;
|
||||
data.errorCode = 0;
|
||||
} else {
|
||||
const errorCode = itiRef.value.getValidationError();
|
||||
data.validity = false;
|
||||
data.errorCode = errorCode;
|
||||
}
|
||||
// console.log(data);
|
||||
emit('update:value', num);
|
||||
emit('update:change', data);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
v => {
|
||||
if (v) {
|
||||
itiRef.value?.setNumber(v);
|
||||
} else {
|
||||
itiRef.value?.setNumber('');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(async () => {
|
||||
if (inputRef.value) {
|
||||
let i18n = undefined;
|
||||
let initialCountry = 'us';
|
||||
// 语言文件导入问题只能复制到项目内处理
|
||||
// import fr from "intl-tel-input/i18n/fr";
|
||||
if (currentLocale.value.startsWith('zh')) {
|
||||
const { default: zh } = await import('./i18n/zh');
|
||||
i18n = zh;
|
||||
initialCountry = 'cn';
|
||||
} else {
|
||||
const { default: en } = await import('./i18n/en');
|
||||
i18n = en;
|
||||
initialCountry = 'us';
|
||||
}
|
||||
|
||||
itiRef.value = intlTelInput(inputRef.value, {
|
||||
initialCountry: initialCountry,
|
||||
formatOnDisplay: true,
|
||||
autoPlaceholder: 'polite',
|
||||
i18n: i18n,
|
||||
} as SomeOptions);
|
||||
inputRef.value.addEventListener('countrychange', fnChange);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (inputRef.value) {
|
||||
inputRef.value.removeEventListener('countrychange', fnChange);
|
||||
}
|
||||
itiRef.value?.destroy();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<input
|
||||
type="tel"
|
||||
class="ant-input"
|
||||
ref="inputRef"
|
||||
:value="value"
|
||||
:disabled="disabled"
|
||||
:placeholder="placeholder"
|
||||
:maxlength="maxlength"
|
||||
:allow-clear="allowClear"
|
||||
@input="fnChange"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style lang="css">
|
||||
.iti {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.iti .iti__country-container .iti__search-input {
|
||||
padding: 4px 8px;
|
||||
}
|
||||
</style>
|
||||
@@ -53,30 +53,32 @@ function backLogin() {
|
||||
const isLocked = computed(() => lockedStore.type !== 'none');
|
||||
|
||||
onMounted(() => {
|
||||
getConfigKey('sys.lockTime')
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS && res.data) {
|
||||
lockedStore.lockTimeout = res.data;
|
||||
timeoutDuration = res.data * 1000;
|
||||
}
|
||||
// 本地锁定类型设置
|
||||
lockedStore.fnLock(lockedStore.type);
|
||||
})
|
||||
.finally(() => {
|
||||
if (timeoutDuration !== 0) {
|
||||
resetTimeout();
|
||||
// 监听用户的操作,重置超时时间
|
||||
window.addEventListener('mousemove', resetTimeout);
|
||||
window.addEventListener('keydown', resetTimeout);
|
||||
}
|
||||
});
|
||||
// 本地锁定类型设置;
|
||||
lockedStore.fnLock(lockedStore.type);
|
||||
// getConfigKey('sys.lockTime')
|
||||
// .then(res => {
|
||||
// if (res.code === RESULT_CODE_SUCCESS && res.data) {
|
||||
// lockedStore.lockTimeout = res.data;
|
||||
// timeoutDuration = res.data * 1000;
|
||||
// }
|
||||
// // 本地锁定类型设置
|
||||
// lockedStore.fnLock(lockedStore.type);
|
||||
// })
|
||||
// .finally(() => {
|
||||
// if (timeoutDuration !== 0) {
|
||||
// resetTimeout();
|
||||
// // 监听用户的操作,重置超时时间
|
||||
// window.addEventListener('mousemove', resetTimeout);
|
||||
// window.addEventListener('keydown', resetTimeout);
|
||||
// }
|
||||
// });
|
||||
});
|
||||
|
||||
/**组件实例被卸载之后调用 */
|
||||
onUnmounted(() => {
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
// if (timeoutId) {
|
||||
// clearTimeout(timeoutId);
|
||||
// }
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
@@ -141,6 +143,17 @@ onUnmounted(() => {
|
||||
{{ t('components.LockScreen.backReload2') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 锁屏-OMC系统重置 -->
|
||||
<div class="lock-screen_reload" v-if="lockedStore.type === 'reset'">
|
||||
<LoadingOutlined style="font-size: 56px" />
|
||||
<div class="text">
|
||||
{{ t('components.LockScreen.systemReset') }}
|
||||
</div>
|
||||
<div class="desc">
|
||||
{{ t('components.LockScreen.systemReset2') }}
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, watch, onMounted, PropType } from 'vue';
|
||||
import { reactive, watch, onMounted, PropType, nextTick } from 'vue';
|
||||
import { Container, Draggable } from 'vue3-smooth-dnd';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
import { type ColumnsType } from 'ant-design-vue/lib/table';
|
||||
const { t } = useI18n();
|
||||
import { dbGetJSON, dbSetJSON } from '@/utils/cache-db-utils';
|
||||
import { CACHE_DB_TABLE_DND } from '@/constants/cache-keys-constants';
|
||||
const { t, currentLocale } = useI18n();
|
||||
|
||||
const emit = defineEmits(['update:columns-dnd']);
|
||||
const props = defineProps({
|
||||
@@ -16,7 +18,8 @@ const props = defineProps({
|
||||
type: Array<any>,
|
||||
required: true,
|
||||
},
|
||||
/**按钮类型
|
||||
/**
|
||||
* 按钮类型
|
||||
* text 图标
|
||||
* ghost 图标按钮带文字
|
||||
*/
|
||||
@@ -24,16 +27,29 @@ const props = defineProps({
|
||||
type: String as PropType<'text' | 'ghost'>,
|
||||
default: 'text',
|
||||
},
|
||||
/**
|
||||
* 缓存列变更数据标识,不传则不缓存
|
||||
*/
|
||||
cacheId: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
|
||||
/**表格字段列 */
|
||||
const tableColumns = reactive<ColumnsType>(props.columns);
|
||||
|
||||
/**表格字段列勾选状态 */
|
||||
const state = reactive({
|
||||
const state = reactive<{
|
||||
indeterminate: boolean;
|
||||
/**是否全选 */
|
||||
checkAll: boolean;
|
||||
/**字段标题列表 */
|
||||
columnsTitleList: string[];
|
||||
}>({
|
||||
indeterminate: false,
|
||||
checkAll: true,
|
||||
columnsTitleList: tableColumns.map(s => `${s.title}`),
|
||||
columnsTitleList: [],
|
||||
});
|
||||
|
||||
/**表格字段列全选操作 */
|
||||
@@ -46,12 +62,13 @@ function fnTableColumnsCheckAllChange(e: any) {
|
||||
/**表格字段列拖拽操作 */
|
||||
function fnTableColumnsDrop(dropResult: any) {
|
||||
const { removedIndex, addedIndex, payload } = dropResult;
|
||||
if (removedIndex !== null && addedIndex !== null) {
|
||||
let itemToAdd = payload;
|
||||
itemToAdd = tableColumns.splice(removedIndex, 1)[0];
|
||||
tableColumns.splice(addedIndex, 0, itemToAdd);
|
||||
fnUpdateColumns();
|
||||
if (removedIndex === null || addedIndex === null) {
|
||||
return;
|
||||
}
|
||||
let itemToAdd = payload;
|
||||
itemToAdd = tableColumns.splice(removedIndex, 1)[0];
|
||||
tableColumns.splice(addedIndex, 0, itemToAdd);
|
||||
fnUpdateColumns();
|
||||
}
|
||||
|
||||
/**表格字段列固定操作 */
|
||||
@@ -66,6 +83,7 @@ function fnTableColumnsFixed(row: Record<string, any>) {
|
||||
} else {
|
||||
row.fixed = !row.fixed;
|
||||
}
|
||||
fnUpdateColumns();
|
||||
}
|
||||
|
||||
/**表格字段列勾选字段变化 */
|
||||
@@ -77,7 +95,18 @@ function fnUpdateColumns() {
|
||||
if (list.length === 0) {
|
||||
list = [tableColumns[0]];
|
||||
}
|
||||
emit('update:columns-dnd', list);
|
||||
|
||||
if (props.cacheId) {
|
||||
// 存入数据
|
||||
dbSetJSON(
|
||||
CACHE_DB_TABLE_DND,
|
||||
`${props.cacheId}#${currentLocale.value}`,
|
||||
list
|
||||
);
|
||||
}
|
||||
nextTick(() => {
|
||||
emit('update:columns-dnd', list);
|
||||
});
|
||||
}
|
||||
|
||||
/**表格字段列勾选监听 */
|
||||
@@ -92,7 +121,34 @@ watch(
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
fnUpdateColumns();
|
||||
if (props.cacheId) {
|
||||
// 读取数据后响应
|
||||
dbGetJSON(CACHE_DB_TABLE_DND, `${props.cacheId}#${currentLocale.value}`)
|
||||
.then(data => {
|
||||
if (data) {
|
||||
const titleList: string[] = [];
|
||||
for (const item of data) {
|
||||
titleList.push(`${item.title}`);
|
||||
// 固定标记还原
|
||||
if (item.fixed !== undefined) {
|
||||
const fixedItem = tableColumns.find(s => s.title === item.title);
|
||||
if (fixedItem) {
|
||||
fixedItem.fixed = item.fixed;
|
||||
}
|
||||
}
|
||||
}
|
||||
state.columnsTitleList = titleList;
|
||||
} else {
|
||||
state.columnsTitleList = tableColumns.map(s => `${s.title}`);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
fnUpdateColumns();
|
||||
});
|
||||
} else {
|
||||
state.columnsTitleList = tableColumns.map(s => `${s.title}`);
|
||||
fnUpdateColumns();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -128,6 +184,7 @@ onMounted(() => {
|
||||
<a-button
|
||||
v-if="c.fixed !== undefined"
|
||||
size="small"
|
||||
:title="c.fixed ? `Fixed ${c.fixed} side` : ''"
|
||||
:type="c.fixed ? 'primary' : 'dashed'"
|
||||
@click="fnTableColumnsFixed(c)"
|
||||
>
|
||||
|
||||
258
src/components/TerminalSSH/index.vue
Normal file
258
src/components/TerminalSSH/index.vue
Normal file
@@ -0,0 +1,258 @@
|
||||
<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,
|
||||
},
|
||||
/**连接主机ID,必传 */
|
||||
hostId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
/**窗口单行字符数 */
|
||||
cols: {
|
||||
type: Number,
|
||||
default: 80,
|
||||
},
|
||||
/**窗口行数 */
|
||||
rows: {
|
||||
type: Number,
|
||||
default: 40,
|
||||
},
|
||||
/**禁止输入 */
|
||||
disable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**初始发送命令 */
|
||||
initCmd: {
|
||||
type: [String, Boolean],
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
/**终端输入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,
|
||||
scrollSensitivity: 15,
|
||||
tabStopWidth: 4,
|
||||
disableStdin: props.disable, // 禁止输入
|
||||
});
|
||||
// 挂载
|
||||
xterm.open(container);
|
||||
// 自适应尺寸
|
||||
const fitAddon = new FitAddon();
|
||||
xterm.loadAddon(fitAddon);
|
||||
// 终端输入字符按键监听
|
||||
xterm.onData(char => {
|
||||
ws.send({
|
||||
requestId: `ssh_${props.hostId}`,
|
||||
type: 'ssh',
|
||||
data: char,
|
||||
});
|
||||
// const printable = char.match(/[\x20-\x7E]/); // 匹配可打印字符的正则表达式
|
||||
// if (char === '\r' || char === '\x0D') {
|
||||
// // 处理回车键,添加换行
|
||||
// xterm.writeln('');
|
||||
// } else if (char === '\x08' || char === '\x7F') {
|
||||
// // 处理退格键,删除最后一个字符
|
||||
// xterm.write('\b \b');
|
||||
// } else if (printable) {
|
||||
// // 处理可打印字符
|
||||
// xterm.write(char);
|
||||
// }
|
||||
});
|
||||
// 终端输入按键监听
|
||||
// xterm.onKey(({ key, domEvent }) => {
|
||||
// // console.log(key, domEvent);
|
||||
// // 单键输入
|
||||
// // switch (domEvent.key) {
|
||||
// // case 'ArrowUp':
|
||||
// // // 按“↑”方向键时要做的事。
|
||||
// // break;
|
||||
// // case 'ArrowDown':
|
||||
// // // 按“↓”方向键时要做的事。
|
||||
// // break;
|
||||
// // case 'ArrowLeft':
|
||||
// // // 按“←”方向键时要做的事。
|
||||
// // break;
|
||||
// // case 'ArrowRight':
|
||||
// // // 按“→”方向键时要做的事。
|
||||
// // break;
|
||||
// // case 'Enter':
|
||||
// // // 处理回车键,添加换行
|
||||
// // term.writeln('');
|
||||
// // break;
|
||||
// // case 'Backspace':
|
||||
// // // 处理退格键,删除最后一个字符
|
||||
// // term.write('\b \b');
|
||||
// // break;
|
||||
// // case 'Escape':
|
||||
// // // 按“ESC”键时要做的事。
|
||||
// // break;
|
||||
// // default:
|
||||
// // return; // 什么都没按就退出吧。
|
||||
// // }
|
||||
// });
|
||||
// 终端尺寸变化触发
|
||||
xterm.onResize(({ cols, rows }) => {
|
||||
// console.log('尺寸', cols, rows);
|
||||
ws.send({
|
||||
requestId: `ssh_resize_${props.hostId}`,
|
||||
type: 'ssh_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,
|
||||
hostId: props.hostId,
|
||||
id: props.id,
|
||||
});
|
||||
// 初始发送命令
|
||||
if (typeof props.initCmd === 'string') {
|
||||
ws.send({
|
||||
requestId: `ssh_${props.hostId}`,
|
||||
type: 'ssh',
|
||||
data: `${props.initCmd}\n`,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**连接错误后回调 */
|
||||
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';
|
||||
terminal.value.write(`\x1b[31m${message}\x1b[m\r\n`);
|
||||
}
|
||||
// 关闭事件
|
||||
emit('close', {
|
||||
code: code,
|
||||
hostId: props.hostId,
|
||||
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) {
|
||||
terminal.value.write(data);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (props.hostId) {
|
||||
// 建立链接
|
||||
const options: OptionsType = {
|
||||
url: '/ws/ssh',
|
||||
params: {
|
||||
hostId: props.hostId,
|
||||
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({
|
||||
/**发送方法 */
|
||||
send: (data: string) => {
|
||||
ws.send({
|
||||
requestId: `ssh_${props.hostId}`,
|
||||
type: 'ssh',
|
||||
data: `${data}\n`,
|
||||
});
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="terminalDom" :id="id" class="terminal"></div>
|
||||
</template>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.terminal {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
305
src/components/TerminalTelnet/index.vue
Normal file
305
src/components/TerminalTelnet/index.vue
Normal file
@@ -0,0 +1,305 @@
|
||||
<script lang="ts" setup>
|
||||
import { message } from 'ant-design-vue/lib';
|
||||
import { ref, reactive, 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,
|
||||
},
|
||||
/**连接主机ID,必传 */
|
||||
hostId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
/**窗口单行字符数 */
|
||||
cols: {
|
||||
type: Number,
|
||||
default: 100,
|
||||
},
|
||||
/**窗口行数 */
|
||||
rows: {
|
||||
type: Number,
|
||||
default: 128,
|
||||
},
|
||||
/**禁止输入 */
|
||||
disable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**初始发送命令 */
|
||||
initCmd: {
|
||||
type: [String, Boolean],
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
/**终端输入DOM节点实例对象 */
|
||||
const terminalDom = ref<HTMLElement | undefined>(undefined);
|
||||
|
||||
/**终端输入实例对象 */
|
||||
const terminal = ref<any>(null);
|
||||
|
||||
/**终端输入文字状态 */
|
||||
const terminalState = reactive<{
|
||||
/**输入值 */
|
||||
text: string;
|
||||
/**历史 */
|
||||
history: {
|
||||
label?: string;
|
||||
value: string;
|
||||
}[];
|
||||
}>({
|
||||
text: '',
|
||||
history: [
|
||||
{
|
||||
value: 'help',
|
||||
},
|
||||
{
|
||||
value: 'quit',
|
||||
},
|
||||
{
|
||||
value: 'list ver',
|
||||
},
|
||||
{
|
||||
value: 'list lic',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
/**自动完成根据输入项进行筛选 */
|
||||
function fnAutoCompleteFilter(input: string, option: any) {
|
||||
return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
||||
}
|
||||
|
||||
/**自动完成按键触发 */
|
||||
function fnAutoCompleteKeydown(evt: any) {
|
||||
if (evt.key === 'Enter') {
|
||||
// 阻止默认的换行行为
|
||||
evt.preventDefault();
|
||||
// 按下 Shift + Enter 键时换行
|
||||
if (evt.shiftKey) {
|
||||
// 插入换行符
|
||||
const textarea = evt.target;
|
||||
const start = textarea.selectionStart;
|
||||
const end = textarea.selectionEnd;
|
||||
const text = textarea.value;
|
||||
textarea.value = text.substring(0, start) + '\n' + text.substring(end);
|
||||
terminalState.text = textarea.value;
|
||||
// 更新光标位置
|
||||
textarea.selectionStart = textarea.selectionEnd = start + 1;
|
||||
} else {
|
||||
// ws未连接
|
||||
if (ws.state() !== WebSocket.OPEN) {
|
||||
message.error('disconnected');
|
||||
return;
|
||||
}
|
||||
|
||||
// 输入历史
|
||||
const cmdStr = terminalState.text.trim().replace(/\n/g, '\r\n');
|
||||
const hisIndex = terminalState.history.findIndex(
|
||||
item => item.value === cmdStr
|
||||
);
|
||||
if (hisIndex === -1) {
|
||||
terminalState.history.push({
|
||||
value: cmdStr,
|
||||
});
|
||||
}
|
||||
|
||||
// 发送文本
|
||||
terminal.value.scrollToBottom();
|
||||
terminal.value.writeln(cmdStr);
|
||||
ws.send({
|
||||
requestId: `telnet_${props.hostId}`,
|
||||
type: 'telnet',
|
||||
data: `${cmdStr}\r\n'`,
|
||||
});
|
||||
terminalState.text = ' ';
|
||||
|
||||
// 退出登录
|
||||
if (['q', 'quit', 'exit'].includes(cmdStr)) {
|
||||
setTimeout(() => {
|
||||
ws.close();
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**终端输入渲染 */
|
||||
function handleRanderXterm(container: HTMLElement | undefined) {
|
||||
if (!container) return;
|
||||
const xterm = new Terminal({
|
||||
lineHeight: 1.2,
|
||||
fontSize: 12,
|
||||
fontFamily: "Monaco, Menlo, Consolas, 'Courier New', monospace",
|
||||
theme: {
|
||||
background: '#000000',
|
||||
},
|
||||
cursorBlink: true, // 光标闪烁
|
||||
cursorStyle: 'block',
|
||||
scrollback: 1000,
|
||||
scrollSensitivity: 15,
|
||||
tabStopWidth: 4,
|
||||
disableStdin: props.disable, // 禁止输入
|
||||
});
|
||||
// 挂载
|
||||
xterm.open(container);
|
||||
// 自适应尺寸
|
||||
const fitAddon = new FitAddon();
|
||||
xterm.loadAddon(fitAddon);
|
||||
|
||||
// 创建 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,
|
||||
hostId: props.hostId,
|
||||
id: props.id,
|
||||
});
|
||||
// 初始发送命令
|
||||
if (typeof props.initCmd === 'string') {
|
||||
ws.send({
|
||||
requestId: `telnet_${props.hostId}`,
|
||||
type: 'telnet',
|
||||
data: `${props.initCmd}\r\n`,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**连接错误后回调 */
|
||||
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';
|
||||
terminal.value.write(`\x1b[31m${message}\x1b[m\r\n`);
|
||||
}
|
||||
// 关闭事件
|
||||
emit('close', {
|
||||
code: code,
|
||||
hostId: props.hostId,
|
||||
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) {
|
||||
// terminal.value.write(data.trim().replace(/\n/g, "\r\n"));
|
||||
// 是否n结尾
|
||||
if (/[\r\n]$/.test(data)) {
|
||||
terminal.value.writeln(data.trim().replace(/\n/g, '\r\n'));
|
||||
} else {
|
||||
terminal.value.write(data.replace(/\n/g, '\r\n'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (props.hostId) {
|
||||
// 建立链接
|
||||
const options: OptionsType = {
|
||||
url: '/ws/telnet',
|
||||
params: {
|
||||
hostId: props.hostId,
|
||||
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({
|
||||
/**发送方法 */
|
||||
send: (data: string) => {
|
||||
ws.send({
|
||||
requestId: `telnet_${props.hostId}`,
|
||||
type: 'telnet',
|
||||
data: `${data}\r\n`,
|
||||
});
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="terminal">
|
||||
<div ref="terminalDom" style="height: 78%" :id="id"></div>
|
||||
<a-auto-complete
|
||||
v-model:value="terminalState.text"
|
||||
:dropdown-match-select-width="500"
|
||||
style="width: 100%"
|
||||
:options="terminalState.history"
|
||||
:filter-option="fnAutoCompleteFilter"
|
||||
@keydown="fnAutoCompleteKeydown"
|
||||
>
|
||||
<a-textarea
|
||||
:auto-size="{ minRows: 1, maxRows: 6 }"
|
||||
placeholder="Execute command. Shift+Enter to line feed, Enter to send"
|
||||
/>
|
||||
</a-auto-complete>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.terminal {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
97
src/components/TerminalText/index.vue
Normal file
97
src/components/TerminalText/index.vue
Normal file
@@ -0,0 +1,97 @@
|
||||
<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';
|
||||
const emit = defineEmits(['update:value']);
|
||||
const props = defineProps({
|
||||
/**终端ID,必传 */
|
||||
id: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
/**窗口单行字符数 */
|
||||
cols: {
|
||||
type: Number,
|
||||
default: 80,
|
||||
},
|
||||
/**窗口行数 */
|
||||
rows: {
|
||||
type: Number,
|
||||
default: 40,
|
||||
},
|
||||
/**信息 */
|
||||
value: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
|
||||
/**终端输入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: false, // 光标闪烁
|
||||
cursorStyle: 'block',
|
||||
scrollback: 1000,
|
||||
scrollSensitivity: 15,
|
||||
tabStopWidth: 4,
|
||||
disableStdin: true, // 禁止输入
|
||||
});
|
||||
// 挂载
|
||||
xterm.open(container);
|
||||
// 自适应尺寸
|
||||
const fitAddon = new FitAddon();
|
||||
xterm.loadAddon(fitAddon);
|
||||
|
||||
// 创建 ResizeObserver 实例
|
||||
var observer = new ResizeObserver(entries => {
|
||||
fitAddon.fit();
|
||||
});
|
||||
// 监听元素大小变化
|
||||
observer.observe(container);
|
||||
|
||||
terminal.value = xterm;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
handleRanderXterm(terminalDom.value);
|
||||
// 初始发送命令
|
||||
if (typeof props.value === 'string') {
|
||||
terminal.value.write(props.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (terminal.value != null) {
|
||||
terminal.value.dispose();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="terminalDom" :id="id" class="terminal"></div>
|
||||
</template>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.terminal {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -12,3 +12,6 @@ export const CACHE_LOCAL_I18N = 'cache:local:i18n';
|
||||
|
||||
/**本地缓存-锁屏设置 */
|
||||
export const CACHE_LOCAL_LOCK = 'cache:local:Lock';
|
||||
|
||||
/**数据缓存表-表格排序 */
|
||||
export const CACHE_DB_TABLE_DND = 'tbl_dnd';
|
||||
|
||||
26
src/constants/ne-constants.ts
Normal file
26
src/constants/ne-constants.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
/**网元列表,默认顺序 */
|
||||
export const NE_TYPE_LIST = [
|
||||
'OMC',
|
||||
'IMS',
|
||||
'AMF',
|
||||
'AUSF',
|
||||
'UDM',
|
||||
'SMF',
|
||||
'PCF',
|
||||
'NSSF',
|
||||
'NRF',
|
||||
'UPF',
|
||||
'LMF',
|
||||
'NEF',
|
||||
'MME',
|
||||
'N3IWF',
|
||||
'MOCNGW',
|
||||
'SMSC',
|
||||
];
|
||||
|
||||
/**
|
||||
* 网元拓展包列表,默认顺序
|
||||
* IMS-adb/rtproxy/mf
|
||||
* UDM-adb
|
||||
*/
|
||||
export const NE_EXPAND_LIST = ['ADB', 'RTPROXY', 'MF'];
|
||||
@@ -2,6 +2,7 @@ export default {
|
||||
// 语言
|
||||
i18n: 'English',
|
||||
hello: 'Hello',
|
||||
welcome: 'Welcome, Core Network Management Platform',
|
||||
|
||||
// 通用
|
||||
common: {
|
||||
@@ -34,7 +35,6 @@ export default {
|
||||
unableNull:' Cannot be empty',
|
||||
moreText: 'More',
|
||||
searchBarText: 'Search bar',
|
||||
tableStripedText: 'Form Zebra',
|
||||
reloadText: 'Refresh',
|
||||
columnSetText: 'Column Setting',
|
||||
columnSetTitle: 'Column Display / Sorting',
|
||||
@@ -53,7 +53,15 @@ export default {
|
||||
fold: 'Fold',
|
||||
},
|
||||
rowId: 'ID',
|
||||
createTime: 'Create Time',
|
||||
updateTime: 'Update Time',
|
||||
remark: 'Remark',
|
||||
description: 'Description',
|
||||
operate: 'Operation',
|
||||
operateOk: 'Operation Successful!',
|
||||
operateErr: 'Operation Failed!',
|
||||
copyText: "Copy",
|
||||
copyOk: 'Copy Successful!',
|
||||
units: {
|
||||
second: 'Second',
|
||||
minute: 'Minute',
|
||||
@@ -127,7 +135,9 @@ export default {
|
||||
validError:'Validation Failure',
|
||||
backLogin:'Logout to Relogin',
|
||||
backReload:'Restarting now, please wait...',
|
||||
backReload2:'When ready, your browser will automatically refresh.',
|
||||
backReload2:'When ready, Your browser will automatically refresh.',
|
||||
systemReset:'Resetting now, please wait...',
|
||||
systemReset2:'Data information is being reset.',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -162,6 +172,9 @@ export default {
|
||||
codeHit: 'Verification code',
|
||||
codeText: 'Obtain verification code',
|
||||
codeSmsSend: 'Successfully sent, please pay attention to checking the SMS',
|
||||
ipPlease: 'Please enter a valid IP address',
|
||||
ipv4Reg: 'Not a valid IPv4 address',
|
||||
ipv6Reg: 'Not a valid IPv6 address',
|
||||
},
|
||||
|
||||
// 布局
|
||||
@@ -354,7 +367,7 @@ export default {
|
||||
pvflag:'PV Flag',
|
||||
pnf:'Physical Network Element',
|
||||
vnf:'Virtual Network Element',
|
||||
province:'Province',
|
||||
province:'Region',
|
||||
vendorName:'Vendor Name',
|
||||
dn:'Network Identification',
|
||||
reload: 'Reload',
|
||||
@@ -362,6 +375,7 @@ export default {
|
||||
totalSure:'Confirm the network element with {operator} network element name {msg}',
|
||||
stop: 'Stop',
|
||||
start: 'Start',
|
||||
log: 'Logs',
|
||||
export: 'Export',
|
||||
import: 'Import',
|
||||
fileForm:'File Source',
|
||||
@@ -421,15 +435,14 @@ export default {
|
||||
letUpTime:'Activation time',
|
||||
createTime:'Creation time',
|
||||
onlyAble:'Only upload file format {fileText} is supported',
|
||||
nullData:'No network element list data yet',
|
||||
nullVersion:'There is no rollback version for the current network element.',
|
||||
},
|
||||
license: {
|
||||
neTypePlease: 'Select network element type',
|
||||
neType: 'NE Type',
|
||||
fileName: 'File Name',
|
||||
createTime: 'Uploaded Time',
|
||||
comment: 'File Description',
|
||||
serialNum: 'Serial Num',
|
||||
createTime: 'Time',
|
||||
comment: 'Description',
|
||||
updateComment: 'License Description',
|
||||
updateCommentPlease: 'Please enter a license description',
|
||||
updateFile: 'License File',
|
||||
@@ -468,21 +481,21 @@ export default {
|
||||
neType: 'NE Type',
|
||||
neTypePleace: "Please select the network element type",
|
||||
noConfigData: "No data on configuration items",
|
||||
updateValue: "The value of the {num} attribute was modified successfully.",
|
||||
updateValue: "[ {num} ] parameter value modified successfully.",
|
||||
updateValueErr: "Attribute value modification failure",
|
||||
updateItem: "Modify Index to {num}.",
|
||||
updateItemErr: "Record modification failure",
|
||||
delItemOk: "Deleting Index as {num} succeeded",
|
||||
addItemOk: "Add Index as {num} Record Succeeded",
|
||||
addItemErr: "Record addition failure",
|
||||
requireUn: "{display} input value is of unknown type",
|
||||
requireString: "The {display} parameter value is invalid.",
|
||||
requireInt: "{display} Parameter value not in reasonable range {filter}",
|
||||
requireIpv4: "{display} not a legitimate IPV4 address",
|
||||
requireIpv6: "{display} Not a legitimate IPV6 address.",
|
||||
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?",
|
||||
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",
|
||||
@@ -492,20 +505,25 @@ export default {
|
||||
overview:{
|
||||
title: "Core Network Dashboard",
|
||||
fullscreen: "Click on the full-screen display",
|
||||
toRouter: "Click to jump to the detail page",
|
||||
skim: {
|
||||
users: "Users",
|
||||
userTitle:'User Information',
|
||||
session: "Sessions",
|
||||
base: "Base Stations",
|
||||
baseTitle:'Radios Information',
|
||||
imsUeNum: "VoNR/VoLTE",
|
||||
smfUeNum: "Data Sessions",
|
||||
gnbBase: "Online gNodeB",
|
||||
enbBase: "Online eNodeB",
|
||||
gnbUeNum:'5G Active Users',
|
||||
enbUeNum:'4G Active Users',
|
||||
baseTitle:'Online Information',
|
||||
},
|
||||
upfFlow:{
|
||||
title: "User Plane Throughput",
|
||||
title: "UPF Throughput",
|
||||
up:'Uplink',
|
||||
down:'Downlink'
|
||||
},
|
||||
upfFlowTotal:{
|
||||
title:'Traffic Information',
|
||||
title:'Traffic Summary',
|
||||
up:'Uplink',
|
||||
down:'Downlink'
|
||||
},
|
||||
@@ -514,14 +532,14 @@ export default {
|
||||
topTitle:"TOP 3",
|
||||
},
|
||||
resources: {
|
||||
title: "Resource Summary",
|
||||
title: "Resource Usage",
|
||||
sysMem: "SYS Mem",
|
||||
sysCpu: "SYS CPU",
|
||||
sysDisk: "SYS Store",
|
||||
neCpu: "NE CPU",
|
||||
},
|
||||
topology: {
|
||||
title: "Network Topology",
|
||||
title: "Network Status",
|
||||
normal: "Normal",
|
||||
abnormal: "Abnormal",
|
||||
},
|
||||
@@ -536,6 +554,267 @@ export default {
|
||||
resultOK: "Success",
|
||||
},
|
||||
},
|
||||
cdr: {
|
||||
recordType: "Recording Behavior",
|
||||
realTimeDataStart: "Turn on real-time data",
|
||||
realTimeDataStop: "Turn off real-time data",
|
||||
cdrInfo: "CDR Info",
|
||||
neName: "NE name",
|
||||
rmUID: "UID",
|
||||
time: "Time",
|
||||
rowInfo: "Info",
|
||||
type: "Type",
|
||||
duration: "Duration",
|
||||
caller: "Caller",
|
||||
called: "Called",
|
||||
result: "Result",
|
||||
delTip: "Confirm deletion of the data item numbered [{msg}]?",
|
||||
},
|
||||
ue: {
|
||||
eventType: "Event Type",
|
||||
realTimeDataStart: "Turn on real-time data",
|
||||
realTimeDataStop: "Turn off real-time data",
|
||||
ueInfo: "UE Info",
|
||||
neName: "NE name",
|
||||
rmUID: "UID",
|
||||
time: "Time",
|
||||
rowInfo: "Info",
|
||||
result: "Result",
|
||||
resultOk: "Successes",
|
||||
delTip: "Confirm deletion of the data item numbered [{msg}]?",
|
||||
},
|
||||
},
|
||||
ne: {
|
||||
common: {
|
||||
neType: 'NE Type',
|
||||
neTypePlease: "Please select network element type",
|
||||
neTypeTip: 'Fill in the type of network element to be created, e.g. SMF.',
|
||||
neId: 'NE ID',
|
||||
neIdPlease: 'Please enter the network element identification',
|
||||
neIdTip: 'Fill in the unique identifier of the network element binding',
|
||||
rmUid: 'Resource Unique ID',
|
||||
rmUidPlease: 'Please enter a resource unique ID',
|
||||
rmUidTip: "Tagging for data reporting of network element logs, alarms, metrics, etc.",
|
||||
neName: 'NE Name',
|
||||
neNamePlease: 'Please enter the name of the network element',
|
||||
ipAddr: 'IP Addr',
|
||||
ipAddrPlease: 'Please enter the IP address of the network element',
|
||||
ipAddrTip: "Support IPV4/IPV6, synchronized change of configuration address",
|
||||
port: 'Port',
|
||||
portTip: "Network element port default:33030",
|
||||
serialNum: 'Serial Number',
|
||||
expiryDate: 'Expiry Date',
|
||||
normalcy: 'Normal',
|
||||
exceptions: 'Abnormal',
|
||||
restart: 'Restart',
|
||||
restartTip: 'Are you sure you want to restart the network element service?',
|
||||
start: 'Start',
|
||||
startTip: 'Are you sure you want to start the network element service?',
|
||||
stop: 'Stop',
|
||||
stopTip: 'Are you sure you want to stop the network element service?',
|
||||
reload: 'Reload',
|
||||
reloadTip: 'Confirm that you want to reload the network element configuration information?',
|
||||
oam: 'OAM',
|
||||
log: 'Logs',
|
||||
},
|
||||
neInfo: {
|
||||
version: "Version",
|
||||
state: "State",
|
||||
serviceState: "Service Status",
|
||||
info: 'Status Message',
|
||||
resourceInfo: 'Resource Situation',
|
||||
sysMem: "SYS Mem",
|
||||
sysCpu: "SYS CPU",
|
||||
sysDisk: "SYS Store",
|
||||
neCpu: "NE CPU",
|
||||
hostConfig: "Connection Configuration",
|
||||
pvflag: 'NE Virtualization',
|
||||
pnf: 'physical network element',
|
||||
vnf: 'virtual network element',
|
||||
neAddress: 'MAC',
|
||||
neAddressTip: 'Record the physical address (MAC) of the network card of the network element',
|
||||
dn: 'network identifier',
|
||||
vendorName: 'provider',
|
||||
province: 'Service Area',
|
||||
addTitle: 'New network element information',
|
||||
editTitle: 'Edit network element information',
|
||||
delTip: 'Confirm deletion of network element information data items?',
|
||||
oam: {
|
||||
title: 'OAM Configuration',
|
||||
sync: 'Sync to NE',
|
||||
oamEnable: 'Service',
|
||||
oamPort: 'Port',
|
||||
snmpEnable: 'Service',
|
||||
snmpPort: 'Port',
|
||||
kpiEnable: 'Report',
|
||||
kpiTimer: 'Reporting Cycle',
|
||||
kpiTimerPlease: 'Please enter the reporting period (in seconds)',
|
||||
},
|
||||
backConf: {
|
||||
export: 'Config Export',
|
||||
import: 'Config Import',
|
||||
title: 'Configuration File Import',
|
||||
importType: 'Source of File',
|
||||
server:'Server File',
|
||||
local:'Local File',
|
||||
localUpload:'Local Upload',
|
||||
exportTip:'Confirm that you want to export the network element configuration file?',
|
||||
exportMsg:'Exported successfully, please download from [Backup Management].',
|
||||
filePlease: "Please upload a file",
|
||||
fileNamePlease: 'Please select the server file',
|
||||
},
|
||||
},
|
||||
neHost: {
|
||||
hostType: "Type",
|
||||
groupId: "Group",
|
||||
title: "Host Name",
|
||||
titlePlease: "Please fill in the host name correctly",
|
||||
addr: "IP Addr",
|
||||
addrPlease: "Please fill in the host IP address correctly",
|
||||
port: "Port",
|
||||
portPlease: "Please fill in the host port number correctly",
|
||||
user: "Login User",
|
||||
userPlease: "Please fill in the host login user correctly",
|
||||
authMode: "Auth Mode",
|
||||
password: "Password",
|
||||
passwordPlease: "Please fill in the host login password correctly",
|
||||
privateKey: "Private Key",
|
||||
privateKeyPlease: "Please fill in the private key characters correctly ~/.ssh/id_rsa",
|
||||
passPhrase: "Private Key Cipher",
|
||||
delTip: "Confirm that you want to delete the host number [{num}]?",
|
||||
addTitle: "Add Host Connection",
|
||||
editTitle: "Edit Host Connection",
|
||||
test: "Test Connection",
|
||||
testOk: "Test Connection Successful",
|
||||
authRSA: 'Secret Authorization',
|
||||
authRSATip: "Do I have to configure secret-free authorization?",
|
||||
},
|
||||
neHostCmd: {
|
||||
cmdType: "Type",
|
||||
groupId: "Group",
|
||||
title: "Title",
|
||||
titlePlease: "Please fill in the command name correctly",
|
||||
command: "Command",
|
||||
commandPlease: "Please enter a valid command string correctly",
|
||||
delTip: "Are you sure you want to delete the message with command number [{num}]?",
|
||||
addTitle: "New Host Commands",
|
||||
editTitle: "Edit Host Commands",
|
||||
},
|
||||
neSoftware: {
|
||||
uploadTitle: "Update Software",
|
||||
upload: "Upload",
|
||||
uploadNotFile: "No software files uploaded",
|
||||
uploadBatch: "Update Softwares",
|
||||
uploadBatchMax: "Multiple packages can be uploaded, with up to {txt} selected at the same time.",
|
||||
uploadFileName: "Parses file names in the format of: amf-r2.240x.xx-xxx",
|
||||
name: "File Name",
|
||||
path: "Software File",
|
||||
pathPlease: "Please upload the software package file",
|
||||
version: "Software Version",
|
||||
versionPlease: "Please enter the software version number",
|
||||
delTip: "Confirmed to remove the package?",
|
||||
downTip: "Confirmation to download package [{txt}]?",
|
||||
fileCheckType: 'The corresponding network element type is not resolved',
|
||||
fileCheckVer: 'The corresponding version number is not resolved',
|
||||
fileTypeNotEq: 'Not a specified network element type {txt}',
|
||||
fileTypeExists: 'Same type of file already exists',
|
||||
fileNameExists: 'File with same name already exists',
|
||||
fileCheckTypeDep: 'The specified dependency package type is not resolved',
|
||||
dependFile: 'Software Dependencies',
|
||||
dependFileTip: 'File name resolution is the same as above, and installation is based on the order of uploading.',
|
||||
},
|
||||
neVersion: {
|
||||
upgrade: "Upgrade To New Version",
|
||||
upgradeTip: "Confirmed to upgrade to the new version?",
|
||||
upgradeTipEmpty: "There are currently no new versions available",
|
||||
upgradeTipEqual: "Current version is the same as the new version",
|
||||
rollback: 'Switch to previous version',
|
||||
rollbackTip: "Confirm switching to the previous version?",
|
||||
rollbackTipEmpty: "There is currently no previous version available",
|
||||
rollbackTipEqual: 'The current version is the same as the previous version',
|
||||
version: "Current Version",
|
||||
preVersion: "Previous Version",
|
||||
newVersion: "New Version",
|
||||
status: "Revision Status",
|
||||
upgradeBatch: "Batch Upgrade",
|
||||
upgradeBatchTip: "Do you perform new version upgrades on checked records?",
|
||||
upgradeNotNewVer: 'No new version found',
|
||||
upgradeDone: 'Update complete, service being reloaded',
|
||||
upgradeFail: 'The update failed, check if the service terminal environment is available!',
|
||||
upgradeModal: 'Network Element Version Updates',
|
||||
},
|
||||
neLicense: {
|
||||
status: "License Status",
|
||||
change: "Change License",
|
||||
reload: "Refresh Info",
|
||||
reloadTip: "Confirmed to refresh license information?",
|
||||
reloadBatch: "Batch Refresh",
|
||||
reloadBatchTip: "Do you do an information refresh on checked records?",
|
||||
updateTtile: "Update License",
|
||||
downCodeTop: "Confirmed to save the license activation code to a file?",
|
||||
activationRequestCode: "License Activation Code",
|
||||
licensePath: "License File",
|
||||
licensePathTip: "Please upload license file",
|
||||
upload: 'Upload',
|
||||
uploadBatch: "Upload License",
|
||||
uploadChangeFail: "Some network elements failed to update the license, please check whether the service terminal environment is available!",
|
||||
},
|
||||
neConfPara5G: {
|
||||
save: 'Save',
|
||||
reload: 'Reload',
|
||||
title: 'Save Info',
|
||||
sync: 'Sync to NE',
|
||||
syncNe: 'Select NE',
|
||||
syncNeDone: 'Synchronization to network element terminals complete',
|
||||
saveOk: 'Save Success!',
|
||||
},
|
||||
neQuickSetup: {
|
||||
stepPrev: 'Previous',
|
||||
stepPrevTip: 'Confirm that you want to abandon the current change and return to the previous step?',
|
||||
stepNext: 'Next',
|
||||
stepSave: 'Save',
|
||||
startTitle: 'Service Terminal Environment',
|
||||
startDesc: 'Test connectivity to network element services',
|
||||
startStepNext: 'Confirm that you want to proceed to the next step to configure the network element information?',
|
||||
addr: 'Terminal IP',
|
||||
kernelName: 'System',
|
||||
kernelRelease: 'Kernel',
|
||||
machine: 'Framework',
|
||||
prettyName: 'Platform',
|
||||
prettyNameTip: 'Support Ubuntu',
|
||||
nodename: 'Node Name',
|
||||
auth: 'Competence Grant',
|
||||
sudo: 'sudo',
|
||||
sudoErr: 'To ensure that you have permission to install packages, configure to grant the current user permission to allow passwordless sudo privileges.',
|
||||
sshLink: 'confidentiality',
|
||||
configTitle: "Configuring Network Elements",
|
||||
configDesc: "Fill in the basic information of the network element",
|
||||
configAddTitle: 'New Tips',
|
||||
configAddTip: 'Is it added as new network element information and continue?',
|
||||
configUpdateTitle: 'Update Tips',
|
||||
configUpdateTip: 'Does it update to the already existing network element information and continue?',
|
||||
configStepNext: 'Confirm that you want to proceed to the next step for the Network Element software installation?',
|
||||
installTitle: "Network Element Installation",
|
||||
installDesc: "Installation to Service Terminal",
|
||||
installConfirmTip: 'Are you sure you want to install package [{name}]?',
|
||||
installStepNext: 'Confirm that you want to proceed to the next step for network element authorization?',
|
||||
installSource: 'Software Source',
|
||||
installSourceOption: 'Uploaded',
|
||||
installSourceUpload: 'New Upload',
|
||||
installSelect: 'Select Record',
|
||||
installUpload: 'Upload File',
|
||||
installText: 'Installed',
|
||||
licenseTitle: "Licenses",
|
||||
licenseDesc: "Network element service authorization certification",
|
||||
licenseResultTitle: "Whether to authorize activation immediately",
|
||||
licenseResultTitleOk: 'Successful Activation',
|
||||
licenseUpload: 'License',
|
||||
licenseEnd: 'Finish',
|
||||
licenseEndTip: "Confirmed to end the installation?",
|
||||
licenseCheack: 'Waiting for network element validation',
|
||||
licenseTip1: '1. Click [License] to get the license activation code, and then contact the network element vendor for activation.',
|
||||
licenseTip2: '2. Clicking [Finish] will end the installation process.',
|
||||
},
|
||||
},
|
||||
neUser: {
|
||||
auth: {
|
||||
@@ -549,7 +828,7 @@ export default {
|
||||
import: 'Import',
|
||||
loadDataConfirm: 'Are you sure you want to reload the data?',
|
||||
loadData: 'Load Data',
|
||||
loadDataTip: 'Successfully fetched load data: {num} entries, the system is internally updating the data. You can click reset to refresh the data list after the loading is finished, please don it repeat click to get update!!!!',
|
||||
loadDataTip: 'Successfully fetched load data: {num} entries, the system is internally updating the data. Please wait a moment!!!!',
|
||||
startIMSI: 'Start IMSI',
|
||||
batchAddText: 'Batch Add',
|
||||
batchDelText: 'Batch Delete',
|
||||
@@ -576,7 +855,7 @@ export default {
|
||||
import: 'Import',
|
||||
loadDataConfirm: 'Are you sure you want to reload the data?',
|
||||
loadData: 'Load Data',
|
||||
loadDataTip: 'Successfully fetched load data: {num} entries, the system is internally updating the data. You can click reset to refresh the data list after the loading is finished, please don it repeat click to get update!!!!',
|
||||
loadDataTip: 'Successfully fetched load data: {num} entries, the system is internally updating the data. Please wait a moment!!!!',
|
||||
numAdd: 'Number of releases',
|
||||
numDel: 'Number of deleted',
|
||||
checkDel: 'Check Delete',
|
||||
@@ -603,7 +882,8 @@ export default {
|
||||
epsOdbTip: 'ODB (Operator-Determined Barring) Operator-determined blocking, i.e. the ability of a subscriber to access the EPS network is determined by the operator.',
|
||||
hplmnOdbTip: 'HPLMN-ODB homing operator-determined blocking, i.e., the ability of a subscriber to access services in the EPS network is determined by the subscriber is homing operator',
|
||||
ardTip:'Access-Restriction-Data (Access-Restriction-Data), can be used to distinguish between 2G/3G/LTE users, to facilitate the coexistence of 2G/3G/LTE network for different types of users to distinguish between the service',
|
||||
smDataTip:'The IP in sm_data=1-000001&internet-1.2.3.4&ims-1.2.3.5: 1.2.3.4 is the static IP assigned to the APN of 5G user internet, and 1.2.3.5 is the static IP assigned to the APN of 5G user ims. If it is dynamic allocation, just remove the IP and the previous connector. Need to support multiple dnn uses & connections'
|
||||
smDataTip:'The IP in sm_data=1-000001&internet-1.2.3.4&ims-1.2.3.5: 1.2.3.4 is the static IP assigned to the APN of 5G user internet, and 1.2.3.5 is the static IP assigned to the APN of 5G user ims. If it is dynamic allocation, just remove the IP and the previous connector. Need to support multiple dnn uses & connections',
|
||||
smDataArrTip:'SST,DNN/APN is required',
|
||||
},
|
||||
pcf: {
|
||||
neType: 'PCF Object',
|
||||
@@ -613,6 +893,7 @@ export default {
|
||||
addTitle: 'Adding Policy Control Information',
|
||||
updateTitle: '{imsi} Policy control information',
|
||||
startIMSI: 'Start IMSI',
|
||||
batchOper: 'Batch Operations',
|
||||
batchAddText: 'Batch Add',
|
||||
batchDelText: 'Batch Delete',
|
||||
batchUpdateText: 'Batch Modify',
|
||||
@@ -621,9 +902,19 @@ export default {
|
||||
imsiTip1: 'MCC=Mobile Country Code, consisting of three digits.',
|
||||
imsiTip2: 'MNC = Mobile Network Number, consisting of two digits',
|
||||
imsiTip3: 'MSIN = Mobile Subscriber Identification Number, consisting of 10 equal digits.',
|
||||
checkDel: 'Check Delete',
|
||||
delSure:'Are you sure you want to delete the user with IMSI number: {imsi}?',
|
||||
uploadFileOk: 'File Upload Successful',
|
||||
uploadFileErr: 'File Upload Failed',
|
||||
pccRuleTip:'PCC policy rule template (corresponding to parameter configuration -PCC Rules)',
|
||||
sessRuleTip:' Session policy rule template (corresponding to parameter configuration-session Rules)',
|
||||
qosAudioTip:' Voice call QoS(corresponding parameter configuration -QoS Template QoS ID)',
|
||||
qosVideoTip:' Video call QoS(corresponding parameter configuration -QoS Template QoS ID)',
|
||||
hdrTip:'HTTP Header enhancement (corresponding parameter configuration -Header Enrich Template)',
|
||||
ueTip:'UE policy template (example: uep_001)',
|
||||
sarTip1:' Service area Restriction ',
|
||||
sarTip2:'(corresponding parameter setting -Service Area Restriction)',
|
||||
rfsfTip:'RAT Frequency Selection Priority',
|
||||
},
|
||||
base5G: {
|
||||
neType: 'NE Object',
|
||||
@@ -659,7 +950,7 @@ export default {
|
||||
viewTask:'View Task',
|
||||
editTask:'Edit Task',
|
||||
addTask:'Add Task',
|
||||
stopTask:'Pending',
|
||||
stopTask:'Stop',
|
||||
errorTaskInfo: 'Failed to obtain task information',
|
||||
granulOptionPlease:'Please select the measurement granularity',
|
||||
letupSure:'Confirm activation of task with number [{id}]?',
|
||||
@@ -719,7 +1010,21 @@ export default {
|
||||
exportSure:'Confirm whether to export all statistical data',
|
||||
exportEmpty: "Export data is empty",
|
||||
showChartSelected: "Show All",
|
||||
realTimeData: "Real Time 5s Data",
|
||||
realTimeData: "Real Time Data",
|
||||
},
|
||||
customTarget:{
|
||||
kpiId:' Custom Indicator',
|
||||
period:' Granularity',
|
||||
title:' Custom Indicator Title',
|
||||
objectType:' Object type',
|
||||
expression:'Expression',
|
||||
description:' Description',
|
||||
kpiSet:' Statistical Settings',
|
||||
delCustomTip:'Confirm deletion of data item with record number {num}?',
|
||||
delCustom:' Successfully delete record number {num} custom indicator',
|
||||
addCustom:' Add custom indicator',
|
||||
editCustom:' Edit Custom indicator',
|
||||
errorCustomInfo: 'Failed to get information',
|
||||
}
|
||||
},
|
||||
traceManage: {
|
||||
@@ -834,7 +1139,7 @@ export default {
|
||||
alarmSeq:'Sequence Number',
|
||||
objectName:'Object Name',
|
||||
locationInfo:'Location Info',
|
||||
province:'Province',
|
||||
province:'Region',
|
||||
addInfo:'Additional Info',
|
||||
specificProblemId:'Cause ID',
|
||||
specificProblem:'Cause',
|
||||
@@ -855,6 +1160,7 @@ export default {
|
||||
showSet:'Show filter settings',
|
||||
exportSure:'Confirm whether to export all active alarm information',
|
||||
viewIdInfo:'View {alarmId} record information',
|
||||
closeModal:'Close',
|
||||
},
|
||||
historyAlarm:{
|
||||
exportSure:'Confirm whether to export all historical alarm information',
|
||||
@@ -867,15 +1173,18 @@ export default {
|
||||
noChange:'There is no change in the alarm forwarding settings.',
|
||||
forwardSet:'Alarm Forwarding Setting',
|
||||
},
|
||||
eventAlarm:{
|
||||
exportSure:'Confirm whether to export all event alarm information',
|
||||
}
|
||||
},
|
||||
logManage:{
|
||||
alarm:{
|
||||
type:'NE Type',
|
||||
neId:'NE UID',
|
||||
alarmId:'Alarm ID',
|
||||
alarmSeq:'Sequece Number',
|
||||
alarmSeq:'Sequence Number',
|
||||
alarmCode:'Alarm Code',
|
||||
alarmStatus:'Severity',
|
||||
alarmStatus:'Status',
|
||||
eventTime:'Event Time',
|
||||
logTime:'Recording Time',
|
||||
status:'Status',
|
||||
@@ -892,12 +1201,13 @@ export default {
|
||||
type:'NE Type',
|
||||
neId:'NE UID',
|
||||
alarmId:'Alarm ID',
|
||||
alarmSeq:'Sequece Number',
|
||||
alarmObj:'Object',
|
||||
alarmSeq:'Sequence Number',
|
||||
alarmObj:'Forward Users',
|
||||
alarmInter:'Forward Interface',
|
||||
alarmTitle:'Alarm Title',
|
||||
alarmInfo:'Alarm Content',
|
||||
eventTime:'Generation Time',
|
||||
logTime:'Record Time'
|
||||
alarmInfo:'Operation Results',
|
||||
eventTime:'Event Time',
|
||||
logTime:'Log Time'
|
||||
},
|
||||
neFile: {
|
||||
neType:'NE Type',
|
||||
@@ -1042,12 +1352,12 @@ export default {
|
||||
jobLog: {
|
||||
jobName: "Job Name",
|
||||
jobGroup: "Job Group",
|
||||
invokeTarget: "Invoke Target",
|
||||
invokeTarget: "Job Invoke",
|
||||
status: "Status",
|
||||
status0: "Failures",
|
||||
status1: "Active",
|
||||
createTime: "Create Time",
|
||||
costTime: "Cost Time",
|
||||
createTime: "Time",
|
||||
costTime: "Time Consumption",
|
||||
viewLog: "Scheduling log Info",
|
||||
delTip: "Are you sure you want to delete the scheduling log entry with the number [{num}]?",
|
||||
delOk: "Deleted Successfully",
|
||||
@@ -1079,8 +1389,9 @@ export default {
|
||||
keyContent: "Cached content",
|
||||
},
|
||||
cacheInfo: {
|
||||
baseInfo: "Basic Info",
|
||||
version: "Service Versions",
|
||||
mode: "Perating Mode",
|
||||
mode: "Operating Mode",
|
||||
modeStandalone: "stand-alone",
|
||||
modeClusters: "clusters",
|
||||
port: "Port",
|
||||
@@ -1111,7 +1422,6 @@ export default {
|
||||
serialNum: 'Serial Number',
|
||||
expiryDate: 'Expiry Date',
|
||||
switchLayout: "Switch Layout",
|
||||
viewLogFile: "Viewing Log Files",
|
||||
noData: "Can't find the corresponding plot data",
|
||||
},
|
||||
topologyBuild: {
|
||||
@@ -1282,15 +1592,15 @@ export default {
|
||||
userInfo:' User Info',
|
||||
userNum: 'User Number',
|
||||
account: 'Account',
|
||||
userName: 'User Name',
|
||||
userName: 'Nick Name',
|
||||
permission: 'Role',
|
||||
className: 'Department',
|
||||
loginIp: 'Login Address',
|
||||
loginTime: 'Login Time',
|
||||
status: 'Status',
|
||||
userNameTip:'The account cannot start with a number and can contain uppercase and lowercase letters, numbers, and no less than 5 digits',
|
||||
pwdTip:'The password should contain at least uppercase and lowercase letters, numbers, special symbols, and no less than 6 digits',
|
||||
nickNameTip:'Nicknames can only contain letters, numbers, Chinese characters, and underscores, with no less than 2 digits',
|
||||
passwdTip:'The password should contain at least uppercase and lowercase letters, numbers, special symbols, and no less than 6 digits',
|
||||
nickNameTip:'Nicknames no less than 2 digits',
|
||||
emailTip:'Please enter the correct email address',
|
||||
phoneTip:'Please enter the correct phone number',
|
||||
resetPwd:'Reset Password',
|
||||
@@ -1313,7 +1623,7 @@ export default {
|
||||
userWork:'User position',
|
||||
userWorkPlease: 'Please select user post',
|
||||
userTip:'User Description',
|
||||
loginPwd:'Login password',
|
||||
loginPwd:'Password',
|
||||
updateSure:'Do you want to update existing data',
|
||||
downloadObj:'Download Tpl',
|
||||
importTitle:'User Import',
|
||||
@@ -1399,6 +1709,9 @@ export default {
|
||||
i18nOpen: "Display Switch",
|
||||
i18nDefault: "Default Languages",
|
||||
i18nInstruction: 'Whether to display the internationalization switch and set the system default language',
|
||||
reset: "System Reset",
|
||||
resetInstruction: "A system reset will erase all data in the current system, please proceed with caution!!!!",
|
||||
resetTipContent: 'Are you sure you want to clear all data from the current system and insist on continuing?',
|
||||
},
|
||||
role:{
|
||||
allScopeOptions:'All data permissions',
|
||||
@@ -1406,11 +1719,11 @@ export default {
|
||||
onlyClassScopeOptions:'Data permissions of this department',
|
||||
classAllScopeOptions:'Data permissions for this department and the following',
|
||||
myselfScopeOptions:'Only personal data permissions',
|
||||
roleId:'Role ID',
|
||||
roleId:'Role Number',
|
||||
roleName:'Role Name',
|
||||
roleKey:'Role Key',
|
||||
roleSort:'Role Order',
|
||||
roleStatus:'Status',
|
||||
roleSort:'Role Sort',
|
||||
roleStatus:'Role Status',
|
||||
createTime:'Creation Time',
|
||||
trueValue:'Please enter {msg} correctly',
|
||||
roleInfo:'Role information',
|
||||
@@ -1423,10 +1736,10 @@ export default {
|
||||
distributeUser:'Assign Users',
|
||||
roleMark:'Role Description',
|
||||
menu:'Menu Permissions',
|
||||
roleKeyTip:"Example of permission identification: Use permission identification in dba controller, such as: @PreAuthorize({ hasRoles: ['dba'] })",
|
||||
roleKeyTip:"Privilege identifiers are used to control page controls or routing interfaces",
|
||||
openSwitch:'Expand/Collapse',
|
||||
selAllSwitch:'Select all/Deselect all',
|
||||
relationSwitch:'Father and son linkage',
|
||||
selAllSwitch:'Select All/Deselect All',
|
||||
relationSwitch:'Node Linkage',
|
||||
normal:'Active',
|
||||
stop:'Pending',
|
||||
preScope:'Scope of authority',
|
||||
@@ -1468,7 +1781,7 @@ export default {
|
||||
positionId:'Position Number',
|
||||
positionCode:'Position Code',
|
||||
positionName:'Position Name',
|
||||
positionSort:'Position Sorting',
|
||||
positionSort:'Position Sort',
|
||||
positionStatus:'Position Status',
|
||||
positionMark:'Position Description',
|
||||
createTime:'Creation Time',
|
||||
@@ -1478,15 +1791,15 @@ export default {
|
||||
},
|
||||
log:{
|
||||
operate:{
|
||||
operId:'ID',
|
||||
operId:'Log ID',
|
||||
moduleName:'Module Name',
|
||||
workType:'Business Type',
|
||||
operUser:'Operator',
|
||||
requestMe:'Request Method',
|
||||
host:'Request Host',
|
||||
operStatus:'Operation Status',
|
||||
operDate:'Operation Date',
|
||||
useTime:'Consumption Time',
|
||||
operStatus:'Status',
|
||||
operDate:'Time',
|
||||
useTime:'Time Consumption',
|
||||
logInfo:'Operation Log Information',
|
||||
delSure:'Are you sure to delete the data item with access number [{ids}]?',
|
||||
delAllSure:'Confirm to clear all login log data items?',
|
||||
@@ -1593,6 +1906,65 @@ export default {
|
||||
exportOk: "Completed export",
|
||||
typeDataErr: "Failed to get dictionary type information",
|
||||
},
|
||||
quickStart: {
|
||||
start: 'Start Setup',
|
||||
skip: 'Skip',
|
||||
finish: 'Complete Setup',
|
||||
stepPrev: 'Previous',
|
||||
stepNext: 'Next',
|
||||
exit: 'Exit',
|
||||
save: 'Save Info',
|
||||
sysTitle: 'System Configuration',
|
||||
sysAdmin: 'Administrator',
|
||||
sysInfo: 'System Info',
|
||||
sysLogo: 'System Logo',
|
||||
sysLogoTip: 'Show the image to the system logo area to see the effect, please use a transparent background, the size of the proportion to adapt to the size of the area',
|
||||
sysName: 'System Name',
|
||||
sysNameTip: 'Limit system name to 20 characters in length',
|
||||
sysUploadLogo: 'Confirmation of uploading the system logo file?',
|
||||
sysUploadOk: 'File uploaded successfully, please save the information',
|
||||
sysSave: 'Save',
|
||||
sysSaveOk: 'Info saved successfully!',
|
||||
sysPrevTip: 'Confirmed to go back to the previous step?',
|
||||
sysNextNe: 'Confirming that you want to do a network element installation?',
|
||||
sysNextDone: 'Confirmed to skip the network element installation?',
|
||||
stepNeInfoTitle: "Service Configuration",
|
||||
stepNeInfoDesc: "Setting the service terminal corresponding to a network element",
|
||||
stepNeInfoStepPrev: 'Confirming that you want to exit the network element installation step?',
|
||||
stepNeInfoStepNext: 'Confirm that you want to proceed to the next step to configure the parameters of the network element?',
|
||||
stepPara5GTitle: "Configuration Parameter",
|
||||
stepPara5GDesc: "Setting network element global parameter information",
|
||||
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?',
|
||||
stepInstallTitle: "Service Install",
|
||||
stepInstallDesc: "Installation of network element services to service terminals",
|
||||
stepInstallStepPrev: 'Confirm that you want to abandon the current change and return to the previous step?',
|
||||
stepInstallStepNext: 'Confirm that you want to proceed to the next step for network element license authorization?',
|
||||
stepInstallText: 'Select Install',
|
||||
stepInstallTip: 'Confirm the installation of the new version of the chosen Net Meta?',
|
||||
stepInstallModal: 'Network Element For Install',
|
||||
stepInstallNotNewVer: 'No new version found',
|
||||
stepInstallDone: 'Installation complete, service initialized',
|
||||
stepInstallFail: 'Installation fails, check if the service terminal environment is available!',
|
||||
stepLicenseTitle: "Service License",
|
||||
stepLicenseDesc: "Obtaining a license activation code for authorization authentication",
|
||||
stepLicenseReload: 'Select Refresh',
|
||||
stepLicenseReloadTip: 'Confirm refreshing selected license information?',
|
||||
stepLicenseDownCode: 'Select Download Activation Code',
|
||||
stepLicenseDownCodeTip: 'Confirmed to download the selected network element license activation code to a text file?',
|
||||
stepLicenseStepPrev: 'Confirm that you want to abandon the current change and return to the previous step?',
|
||||
stepLicenseStepNext: 'Confirmed to end the network element installation step?',
|
||||
stepLicenseStepNext2: 'Please download the Net Element License Authorization Code file to save it and contact the Net Element vendor to get the authorization license',
|
||||
stepLicenseEnd: 'End',
|
||||
doneTitle: "Completing the Configuration",
|
||||
doneTip: 'Please enter the system and configure it as appropriate.',
|
||||
doneNETitle: 'Configuration of the network element installation has been performed',
|
||||
doneNEDesc: 'In case of abnormal network elements, the license can be reinstalled in the system',
|
||||
doneSkipTitle: 'No network element installation configuration',
|
||||
doneSkipDesc: 'The system will initialize the network element information by default, which can be modified or installed within the system.',
|
||||
donePrevTip: 'Confirmed to go back to the previous step?',
|
||||
doneOkTip: 'Confirm that you have completed the setup and started using it?',
|
||||
},
|
||||
},
|
||||
mmlManage: {
|
||||
cmdTitle: "Command Navigator",
|
||||
@@ -1600,22 +1972,27 @@ export default {
|
||||
cmdOpTip: "Select the item to be operated in the left command navigation!",
|
||||
cmdNoTip: "{num} no optional command operation",
|
||||
require: "Mandatory parameter: {num}",
|
||||
requireUn: "{display} input value is of unknown type",
|
||||
requireString: "The {display} parameter value is invalid.",
|
||||
requireInt: "{display} Parameter value not in reasonable range {filter}",
|
||||
requireIpv4: "{display} not a legitimate IPV4 address",
|
||||
requireIpv6: "{display} Not a legitimate IPV6 address.",
|
||||
requireEnum: "{display} is not a reasonable enumeration value.",
|
||||
requireBool: "{display} is not a reasonable boolean value.",
|
||||
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.",
|
||||
requireFile: "[ {display} ] is not a value that matches the parameter file type.",
|
||||
cmdQuickEntry: "Command Quick Entry",
|
||||
cmdQuickEntryHelp: "Line feed (Shift + Enter), Execute (Enter)",
|
||||
cmdParamPanel: "Parameter Panel",
|
||||
clearForm: "Reset",
|
||||
clearLog: "Clear Logs",
|
||||
exec: "Execute",
|
||||
cmdAwait: "Waiting for a command to be sent",
|
||||
uploadFileTip: 'Are you sure you want to upload the file?',
|
||||
uploadFileOk: 'File Upload Successful',
|
||||
uploadFileErr: 'File Upload Failed',
|
||||
neOperate:{
|
||||
mml: "General",
|
||||
mml2: "Standard",
|
||||
},
|
||||
omcOperate:{
|
||||
noOMC: "No OMC network elements",
|
||||
},
|
||||
@@ -1635,10 +2012,28 @@ export default {
|
||||
},
|
||||
tool: {
|
||||
help: {
|
||||
fileName: "5G Core Network Network Management Operations Manual.pdf",
|
||||
download: "Download",
|
||||
pdfViewer: "In-browser preview",
|
||||
pdfViewerErr: "Sorry, your browser does not support PDF preview!",
|
||||
}
|
||||
},
|
||||
terminal: {
|
||||
start: "Start Page",
|
||||
new: "To Create",
|
||||
more: "More",
|
||||
reload: "Reload Current Tab",
|
||||
reloadTip: "Are you sure you want to refresh and reconnect the current [{num}] terminal link?",
|
||||
current: "Close Current Tab",
|
||||
other: "Close Other Tabs",
|
||||
otherTip: "Confirm that you want to close other terminal links?",
|
||||
all: "Close All Tabs",
|
||||
allTip: "Confirmed to close all terminal links?",
|
||||
closeTip: "Confirm that you want to close the [{num}] terminal link?",
|
||||
hostSelectTitle: "Select the created host to connect to",
|
||||
hostSelectShow: "Open Selection",
|
||||
hostSelectMore: "Load More {num}",
|
||||
hostSelectHeader: "Host List",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@ export default {
|
||||
// 语言
|
||||
i18n: '中文',
|
||||
hello: '你好',
|
||||
welcome: '欢迎使用,核心网管理平台',
|
||||
|
||||
// 通用
|
||||
common: {
|
||||
@@ -34,7 +35,6 @@ export default {
|
||||
unableNull:'不能为空',
|
||||
moreText: '更多',
|
||||
searchBarText: '搜索栏',
|
||||
tableStripedText: '表格斑马纹',
|
||||
reloadText: '刷新',
|
||||
columnSetText: '列设置',
|
||||
columnSetTitle: '列展示/排序',
|
||||
@@ -53,7 +53,15 @@ export default {
|
||||
fold: '折叠',
|
||||
},
|
||||
rowId: '编号',
|
||||
createTime: '创建时间',
|
||||
updateTime: '更新时间',
|
||||
remark: '备注',
|
||||
description: '说明',
|
||||
operate: '操作',
|
||||
operateOk: '操作成功!',
|
||||
operateErr: '操作失败!',
|
||||
copyText: "复制",
|
||||
copyOk: '复制成功!',
|
||||
units: {
|
||||
second: '秒',
|
||||
minute: '分钟',
|
||||
@@ -128,6 +136,8 @@ export default {
|
||||
backLogin:'退出并重新登录',
|
||||
backReload:'正在重启,请稍等...',
|
||||
backReload2:'当准备就绪的时候,你的浏览器会自动刷新。',
|
||||
systemReset:'正在重置,请稍等...',
|
||||
systemReset2:'数据信息正在重置',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -162,6 +172,9 @@ export default {
|
||||
codeHit: '验证码',
|
||||
codeText: '获取验证码',
|
||||
codeSmsSend: '发送成功,请注意查看短信',
|
||||
ipPlease: '请输入有效的IP地址',
|
||||
ipv4Reg: '不是有效IPv4地址',
|
||||
ipv6Reg: '不是有效IPv6地址',
|
||||
},
|
||||
|
||||
// 布局
|
||||
@@ -260,10 +273,10 @@ export default {
|
||||
email: "电子邮箱",
|
||||
emailPleace: "请输入正确的电子邮箱",
|
||||
phonenumber: "手机号码",
|
||||
phonenumberPleace: "请输入正确的电子邮箱",
|
||||
phonenumberPleace: "请输入正确的手机号码",
|
||||
nick: "用户昵称",
|
||||
nickPleace: "请输入用户昵称",
|
||||
nickTip: "昵称只能包含字母、数字、中文和下划线,且不少于2位",
|
||||
nickTip: "昵称少于2位",
|
||||
profileTip: "确认要提交修改用户基本信息吗?",
|
||||
profileOk: "用户基本信息修改成功!",
|
||||
know: "我知道了",
|
||||
@@ -362,6 +375,7 @@ export default {
|
||||
totalSure:'确认{oper}网元名称为 {msg} 的网元',
|
||||
stop: '停止',
|
||||
start: '启动',
|
||||
log: '日志',
|
||||
export: '导出',
|
||||
import: '导入',
|
||||
fileForm:'文件来源',
|
||||
@@ -421,15 +435,14 @@ export default {
|
||||
letUpTime:'激活时间',
|
||||
createTime:'创建时间',
|
||||
onlyAble:'只支持上传文件格式 {fileText}',
|
||||
nullData:'暂无网元列表数据',
|
||||
nullVersion:'当前网元无可回退版本',
|
||||
},
|
||||
license: {
|
||||
neTypePlease: '选择网元类型',
|
||||
neType: '网元类型',
|
||||
fileName: '文件名',
|
||||
createTime: '上传时间',
|
||||
comment: '文件说明',
|
||||
serialNum: '序列号',
|
||||
createTime: '时间',
|
||||
comment: '说明',
|
||||
updateComment: 'License说明',
|
||||
updateCommentPlease: '请输入License说明',
|
||||
updateFile: 'License文件',
|
||||
@@ -468,21 +481,21 @@ export default {
|
||||
neType: "网元类型",
|
||||
neTypePleace: "请选择网元类型",
|
||||
noConfigData: "暂无配置项数据",
|
||||
updateValue: "{num} 属性值修改成功",
|
||||
updateValue: "【 {num} 】 属性值修改成功",
|
||||
updateValueErr: "属性值修改失败",
|
||||
updateItem: "修改 Index 为 {num} 记录成功",
|
||||
updateItemErr: "记录修改失败",
|
||||
delItemOk: "删除 Index 为 {num} 记录成功",
|
||||
addItemOk: "新增 Index 为 {num} 记录成功",
|
||||
addItemErr: "记录新增失败",
|
||||
requireUn: "{display} 输入值是未知类型",
|
||||
requireString: "{display} 参数值不合理",
|
||||
requireInt: "{display} 参数值不在合理范围 {filter}",
|
||||
requireIpv4: "{display} 不是合法的IPV4地址",
|
||||
requireIpv6: "{display} 不是合法的IPV6地址",
|
||||
requireEnum: "{display} 不是合理的枚举值",
|
||||
requireBool: "{display} 不是合理的布尔类型的值",
|
||||
editOkTip: "确认更新该{num}属性值吗?",
|
||||
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: "展开",
|
||||
@@ -492,12 +505,17 @@ export default {
|
||||
overview:{
|
||||
title: "核心网系统看板",
|
||||
fullscreen: "点击全屏显示",
|
||||
toRouter: "点击跳转详情页面",
|
||||
skim: {
|
||||
users: "用户数",
|
||||
userTitle:'用户信息',
|
||||
session: "会话数",
|
||||
base: "基站数",
|
||||
baseTitle:'基站信息',
|
||||
imsUeNum: "IMS 会话数",
|
||||
smfUeNum: "Data 会话数",
|
||||
gnbBase: "5G 基站数",
|
||||
gnbUeNum:'5G 用户数',
|
||||
enbBase: "4G 基站数",
|
||||
enbUeNum:'4G 用户数',
|
||||
baseTitle:'在线信息',
|
||||
},
|
||||
upfFlow:{
|
||||
title: "用户面吞吐量",
|
||||
@@ -535,7 +553,268 @@ export default {
|
||||
time: "时间",
|
||||
resultOK: "成功",
|
||||
},
|
||||
}
|
||||
},
|
||||
cdr: {
|
||||
recordType: "记录行为",
|
||||
realTimeDataStart: "开启实时数据",
|
||||
realTimeDataStop: "关闭实时数据",
|
||||
cdrInfo: "CDR信息",
|
||||
neName: "网元名称",
|
||||
rmUID: "资源标识",
|
||||
time: "记录时间",
|
||||
rowInfo: "记录信息",
|
||||
type: "记录类型",
|
||||
duration: "通话时长",
|
||||
caller: "主叫",
|
||||
called: "被叫",
|
||||
result: "结果",
|
||||
delTip: "确认删除编号为【{msg}】的数据项?",
|
||||
},
|
||||
ue: {
|
||||
eventType: "事件类型",
|
||||
realTimeDataStart: "开启实时数据",
|
||||
realTimeDataStop: "关闭实时数据",
|
||||
ueInfo: "UE信息",
|
||||
neName: "网元名称",
|
||||
rmUID: "资源标识",
|
||||
rowInfo: "记录信息",
|
||||
time: "记录时间",
|
||||
result: "结果",
|
||||
resultOk: "成功",
|
||||
delTip: "确认删除编号为【{msg}】的数据项?",
|
||||
},
|
||||
},
|
||||
ne: {
|
||||
common: {
|
||||
neType: '网元类型',
|
||||
neTypePlease: "请选择网元类型",
|
||||
neTypeTip: '填写创建的网元类型,如:SMF',
|
||||
neId: '网元标识',
|
||||
neIdPlease: '请输入网元标识',
|
||||
neIdTip: '填写网元绑定的唯一标识',
|
||||
rmUid: '资源唯一标识',
|
||||
rmUidPlease: '请输入资源唯一标识',
|
||||
rmUidTip: "用于网元日志、告警、指标等数据上报的标记",
|
||||
neName: '网元名称',
|
||||
neNamePlease: '请输入网元名称',
|
||||
ipAddr: '服务IP',
|
||||
ipAddrPlease: '请输入网元服务IP地址',
|
||||
ipAddrTip: "支持IPV4/IPV6,同步变更配置地址",
|
||||
port: '服务端口',
|
||||
portTip: "网元服务端口,默认:33030",
|
||||
serialNum: '序列号',
|
||||
expiryDate: '许可证到期日期',
|
||||
normalcy: '正常',
|
||||
exceptions: '异常',
|
||||
restart: '重启',
|
||||
restartTip: '确认要重新启动网元服务吗?',
|
||||
start: '启动',
|
||||
startTip: '确认要启动网元服务吗?',
|
||||
stop: '停止',
|
||||
stopTip: '确认要停止网元服务吗?',
|
||||
reload: '重载',
|
||||
reloadTip: '确认要重载网元配置信息吗?',
|
||||
oam: 'OAM',
|
||||
log: '日志',
|
||||
},
|
||||
neInfo: {
|
||||
version: "网元版本",
|
||||
state: "网元状态",
|
||||
serviceState: "服务状态",
|
||||
info: '状态信息',
|
||||
resourceInfo: '资源情况',
|
||||
sysMem: "系统内存",
|
||||
sysCpu: "系统CPU",
|
||||
sysDisk: "系统存储",
|
||||
neCpu: "网元CPU",
|
||||
hostConfig: "终端连接配置",
|
||||
pvflag: '网元虚拟化标识',
|
||||
pnf: '物理网元',
|
||||
vnf: '虚拟网元',
|
||||
neAddress: '物理地址(MAC)',
|
||||
neAddressTip: '记录网元的网卡物理地址(MAC)',
|
||||
dn: '网络标识',
|
||||
vendorName: '提供厂商',
|
||||
province: '服务地域',
|
||||
addTitle: '新增网元信息',
|
||||
editTitle: '编辑网元信息',
|
||||
delTip: '确认删除网元信息数据项吗?',
|
||||
oam: {
|
||||
title: 'OAM配置',
|
||||
sync: '同步到网元',
|
||||
oamEnable: '服务',
|
||||
oamPort: '端口',
|
||||
snmpEnable: '服务',
|
||||
snmpPort: '端口',
|
||||
kpiEnable: '上报',
|
||||
kpiTimer: '上报周期',
|
||||
kpiTimerPlease: '请输入上报周期(单位秒)',
|
||||
},
|
||||
backConf: {
|
||||
export: '配置导出',
|
||||
import: '配置导入',
|
||||
title: '配置文件导入',
|
||||
importType: '文件来源',
|
||||
server:'服务器文件',
|
||||
local:'本地文件',
|
||||
localUpload:'本地上传',
|
||||
exportTip:'确认要导出网元配置信息到文件?',
|
||||
exportMsg:'导出成功,请到【备份管理】进行下载',
|
||||
filePlease: "请上传文件",
|
||||
fileNamePlease: '请选择服务器文件',
|
||||
},
|
||||
},
|
||||
neHost: {
|
||||
hostType: "主机类型",
|
||||
groupId: "分组",
|
||||
title: "主机名称",
|
||||
titlePlease: "请正确填写主机名称",
|
||||
addr: "IP地址",
|
||||
addrPlease: "请正确填写主机IP地址",
|
||||
port: "端口",
|
||||
portPlease: "请正确填写主机端口号",
|
||||
user: "用户名",
|
||||
userPlease: "请正确填写主机登录用户",
|
||||
authMode: "认证模式",
|
||||
password: "密码",
|
||||
passwordPlease: "请正确填写主机登录密码",
|
||||
privateKey: "私钥",
|
||||
privateKeyPlease: "请正确填写私钥字符内容 ~/.ssh/id_rsa",
|
||||
passPhrase: "私钥密码",
|
||||
delTip: "确认要删除主机编号为【{num}】的信息吗?",
|
||||
addTitle: "新增主机连接",
|
||||
editTitle: "编辑主机连接",
|
||||
test: "测试连接",
|
||||
testOk: "测试连接成功",
|
||||
authRSA: "免密授权",
|
||||
authRSATip: "是否要配置免密授权?",
|
||||
},
|
||||
neHostCmd: {
|
||||
cmdType: "命令类型",
|
||||
groupId: "分组",
|
||||
title: "名称",
|
||||
titlePlease: "请正确填写命令名称",
|
||||
command: "命令",
|
||||
commandPlease: "请正确输入有效命令字符串",
|
||||
delTip: "确认要删除命令编号为【{num}】的信息吗?",
|
||||
addTitle: "新增主机命令",
|
||||
editTitle: "编辑主机命令",
|
||||
},
|
||||
neSoftware: {
|
||||
uploadTitle: "上传软件",
|
||||
upload: "上传",
|
||||
uploadNotFile: "未上传软件文件",
|
||||
uploadBatch: "上传软件包",
|
||||
uploadBatchMax: "可上传多个软件包,最多同时选择{txt}个。",
|
||||
uploadFileName: "解析文件名称格式如: amf-r2.240x.xx-xxx",
|
||||
name: "文件名",
|
||||
path: "软件文件",
|
||||
pathPlease: "请上传软件包文件",
|
||||
version: "软件版本",
|
||||
versionPlease: "请输入软件版本号",
|
||||
delTip: "确认要删除软件包吗?",
|
||||
downTip: "确认要下载软件包【{txt}】吗?",
|
||||
fileCheckType: '未解析出对应的网元类型',
|
||||
fileCheckVer: '未解析出对应的版本号',
|
||||
fileTypeNotEq: '不是指定网元类型 {txt}',
|
||||
fileTypeExists: '已存在相同类型文件',
|
||||
fileNameExists: '已存在相同名称文件',
|
||||
fileCheckTypeDep: '未解析出对应指定的依赖包类型',
|
||||
dependFile: '软件包依赖',
|
||||
dependFileTip: '文件名解析同上,依据上传顺序安装',
|
||||
},
|
||||
neVersion: {
|
||||
upgrade: "升级到新版本",
|
||||
upgradeTip: "确认要升级到新版本吗?",
|
||||
upgradeTipEmpty: "当前没有可用的新版本",
|
||||
upgradeTipEqual: "当前版本与新版本相同",
|
||||
rollback: '切换到上一个版本',
|
||||
rollbackTip: "确认切换到上一个版本吗?",
|
||||
rollbackTipEmpty: "目前没有可用的上一个版本",
|
||||
rollbackTipEqual: '当前版本与之前版本相同',
|
||||
version: "当前版本",
|
||||
preVersion: "上一个版本",
|
||||
newVersion: "新版本",
|
||||
status: "版本状态",
|
||||
upgradeBatch: "批量更新",
|
||||
upgradeBatchTip: "对勾选的记录进行新版本升级吗?",
|
||||
upgradeNotNewVer: '没有发现新版本',
|
||||
upgradeDone: '更新完成,服务正在重载',
|
||||
upgradeFail: '更新失败,请检查服务终端环境是否可用!',
|
||||
upgradeModal: '网元版本更新',
|
||||
},
|
||||
neLicense: {
|
||||
status: "许可证状态",
|
||||
change: "变更许可证",
|
||||
reload: "刷新信息",
|
||||
reloadTip: "确认要刷新许可证信息吗?",
|
||||
reloadBatch: "批量刷新",
|
||||
reloadBatchTip: "对勾选的记录进行信息刷新吗?",
|
||||
updateTtile: "更新许可证",
|
||||
downCodeTop: "确认要将许可激活码保存到文件吗?",
|
||||
activationRequestCode: "许可激活码",
|
||||
licensePath: "许可证文件",
|
||||
licensePathTip: "请上传许可证文件",
|
||||
upload: '上传',
|
||||
uploadBatch: "上传许可证",
|
||||
uploadChangeFail: "部分网元更新许可证失败,请检查服务终端环境是否可用!",
|
||||
},
|
||||
neConfPara5G: {
|
||||
save: '保存',
|
||||
reload: '刷新',
|
||||
title: '保存信息',
|
||||
sync: '同步到网元',
|
||||
syncNe: '选择网元',
|
||||
syncNeDone: '同步到网元终端完成',
|
||||
saveOk: '保存成功!',
|
||||
},
|
||||
neQuickSetup: {
|
||||
stepPrev: '上一步',
|
||||
stepPrevTip: '确认要放弃当前变更返回上一步吗?',
|
||||
stepNext: '下一步',
|
||||
stepSave: '保存信息',
|
||||
startTitle: '服务终端环境',
|
||||
startDesc: '测试连接网元服务',
|
||||
startStepNext: '确认要下一步进行配置网元信息?',
|
||||
addr: '终端IP',
|
||||
kernelName: '系统',
|
||||
kernelRelease: '内核',
|
||||
machine: '架构',
|
||||
prettyName: '平台',
|
||||
prettyNameTip: '支持 Ubuntu',
|
||||
nodename: '主机名',
|
||||
auth: '权限授予',
|
||||
sudo: '提权',
|
||||
sudoErr: '确保有权限进行软件包安装,请配置授予当前用户允许无密码 sudo 权限。',
|
||||
sshLink: '免密直连',
|
||||
configTitle: "配置网元",
|
||||
configDesc: "填写网元基础信息",
|
||||
configAddTitle: '新增提示',
|
||||
configAddTip: '是否新增为新的网元信息并继续?',
|
||||
configUpdateTitle: '更新提示',
|
||||
configUpdateTip: '是否更新到已存在网元信息并继续?',
|
||||
configStepNext: '确认要下一步进行网元软件安装?',
|
||||
installTitle: "网元安装",
|
||||
installDesc: "安装到服务终端",
|
||||
installConfirmTip: '确认要安装软件包【{name}】吗?',
|
||||
installStepNext: '确认要下一步进行网元授权吗?',
|
||||
installSource: '软件来源',
|
||||
installSourceOption: '已上传',
|
||||
installSourceUpload: '新上传',
|
||||
installSelect: '选择记录',
|
||||
installUpload: '上传文件',
|
||||
installText: '安装',
|
||||
licenseTitle: "授权许可",
|
||||
licenseDesc: "网元服务授权认证",
|
||||
licenseResultTitle: "是否立即授权激活",
|
||||
licenseResultTitleOk: '成功激活',
|
||||
licenseUpload: '许可证',
|
||||
licenseEnd: '结束',
|
||||
licenseEndTip: "确认要结束安装吗?",
|
||||
licenseCheack: '等待网元验证',
|
||||
licenseTip1: '1. 点击【许可证】可获取许可激活码,随后联系网元厂商进行激活',
|
||||
licenseTip2: '2. 点击【结束】将结束安装过程',
|
||||
},
|
||||
},
|
||||
neUser: {
|
||||
auth: {
|
||||
@@ -549,7 +828,7 @@ export default {
|
||||
import: '导入',
|
||||
loadDataConfirm: '确认要重新加载数据吗?',
|
||||
loadData: '加载数据',
|
||||
loadDataTip: '成功获取加载数据:{num}条,系统内部正在进行数据更新。加载结束后可点击重置刷新数据列表,请勿重复点击获取更新!!!',
|
||||
loadDataTip: '成功获取加载数据:{num}条,系统内部正在进行数据更新,请稍候!!!',
|
||||
startIMSI: '起始IMSI',
|
||||
batchAddText: '批量新增',
|
||||
batchDelText: '批量删除',
|
||||
@@ -576,7 +855,7 @@ export default {
|
||||
import: '导入',
|
||||
loadDataConfirm: '确认要重新加载数据吗?',
|
||||
loadData: '加载数据',
|
||||
loadDataTip: '成功获取加载数据:{num}条,系统内部正在进行数据更新。加载结束后可点击重置刷新数据列表,请勿重复点击获取更新!!!',
|
||||
loadDataTip: '成功获取加载数据:{num}条,系统内部正在进行数据更新,请稍候!!!',
|
||||
numAdd: '放号个数',
|
||||
numDel: '删除个数',
|
||||
checkDel:'勾选删除',
|
||||
@@ -603,7 +882,8 @@ export default {
|
||||
epsOdbTip: 'ODB(Operator-Determined Barring)运营商决定的闭锁,即用户接入EPS网络的业务能力由运营商决定.选中 ---对应服务被允许 未选 --- 对应服务被禁止',
|
||||
hplmnOdbTip: 'HPLMN-ODB归属运营商决定的闭锁,即用户接入EPS网络的业务能力由用户归宿运营商决定.选中 --- 对应服务被允许 未选 -- 对应服务被禁止',
|
||||
ardTip:'接入控制标志(Access-Restriction-Data),可用于区分2G/3G/LTE用户,便于为2G/3G/LTE网络共存时,对不同类型用户进行区分服务',
|
||||
smDataTip:'sm_data=1-000001&internet-1.2.3.4&ims-1.2.3.5中的IP:1.2.3.4为5G用户internet这个APN分配的静态IP,1.2.3.5为5G用户ims这个APN分配的静态IP。如果是动态分配,把IP以及前面一个连接符去掉即可。需支持多个dnn用&连接'
|
||||
smDataTip:'sm_data=1-000001&internet-1.2.3.4&ims-1.2.3.5中的IP:1.2.3.4为5G用户internet这个APN分配的静态IP,1.2.3.5为5G用户ims这个APN分配的静态IP。如果是动态分配,把IP以及前面一个连接符去掉即可。需支持多个dnn用&连接',
|
||||
smDataArrTip:'SST,DNN/APN为必填项',
|
||||
},
|
||||
pcf: {
|
||||
neType: 'PCF网元对象',
|
||||
@@ -613,6 +893,7 @@ export default {
|
||||
addTitle: '新增策略控制信息',
|
||||
updateTitle: '{imsi} 策略控制信息',
|
||||
startIMSI: '起始IMSI',
|
||||
batchOper: '批量操作',
|
||||
batchAddText: '批量新增',
|
||||
batchDelText: '批量删除',
|
||||
batchUpdateText: '批量更新',
|
||||
@@ -621,9 +902,19 @@ export default {
|
||||
imsiTip1: 'MCC=移动国家号码, 由三位数字组成',
|
||||
imsiTip2: 'MNC=移动网络号,由两位数字组成',
|
||||
imsiTip3: 'MSIN=移动客户识别码,采用等长10位数字构成',
|
||||
delSure:'确认删除IMSI编号为: {imsi} 的用户吗?',
|
||||
checkDel:'勾选删除',
|
||||
delSure:'确认删除IMSI编号为: {imsi} 的数据项吗?',
|
||||
uploadFileOk: '文件上传成功',
|
||||
uploadFileErr: '文件上传失败',
|
||||
pccRuleTip:'PCC策略规则模板(对应参数配置-PCC Rules)',
|
||||
sessRuleTip:'会话策略规则模板(对应参数配置-Session Rules)',
|
||||
qosAudioTip:'语音呼叫QoS(对应参数配置-QoS Template的QoS ID)',
|
||||
qosVideoTip:'视频呼叫QoS(对应参数配置-QoS Template的QoS ID)',
|
||||
hdrTip:'HTTP头增强(对应参数配置-Header Enrich Template)',
|
||||
ueTip:'UE策略模板(样例: uep_001)',
|
||||
sarTip1:'服务区限制',
|
||||
sarTip2:'(对应参数配置-Service Area Restriction)',
|
||||
rfsfTip:'无线频率选择优先级',
|
||||
},
|
||||
base5G: {
|
||||
neType: '网元对象',
|
||||
@@ -659,7 +950,7 @@ export default {
|
||||
viewTask:'查看任务',
|
||||
editTask:'修改任务',
|
||||
addTask:'新增任务',
|
||||
stopTask:'挂起',
|
||||
stopTask:'停止',
|
||||
errorTaskInfo: '获取任务信息失败',
|
||||
granulOptionPlease:'请选择测量粒度',
|
||||
letupSure:'确认激活编号为 【{id}】 的任务?',
|
||||
@@ -719,8 +1010,22 @@ export default {
|
||||
exportSure:'确认是否导出全部统计数据',
|
||||
exportEmpty: "导出数据为空",
|
||||
showChartSelected: "显示全部",
|
||||
realTimeData: "实时5s数据",
|
||||
}
|
||||
realTimeData: "实时数据",
|
||||
},
|
||||
customTarget:{
|
||||
kpiId:'自定义指标项',
|
||||
period:'颗粒度',
|
||||
title:'自定义指标项标题',
|
||||
objectType:'对象类型',
|
||||
expression:'计算公式',
|
||||
description:'描述',
|
||||
kpiSet:'统计设置',
|
||||
delCustomTip:'确认删除记录编号为 {num} 的数据项?',
|
||||
delCustom:'成功删除记录编号为 {num} 自定义指标',
|
||||
addCustom:'添加自定义指标',
|
||||
editCustom:'编辑自定义指标',
|
||||
errorCustomInfo: '获取信息失败',
|
||||
}
|
||||
},
|
||||
traceManage: {
|
||||
analysis: {
|
||||
@@ -855,6 +1160,7 @@ export default {
|
||||
showSet:'显示过滤设置',
|
||||
exportSure:'确认是否导出全部活动告警信息',
|
||||
viewIdInfo:'查看{alarmId} 记录信息',
|
||||
closeModal:'关闭',
|
||||
},
|
||||
historyAlarm:{
|
||||
exportSure:'确认是否导出全部历史告警信息?',
|
||||
@@ -866,6 +1172,9 @@ export default {
|
||||
save:'保存设置',
|
||||
noChange:'告警前转接口设置无变更',
|
||||
forwardSet:'告警前转接口设置',
|
||||
},
|
||||
eventAlarm:{
|
||||
exportSure:'确认是否导出全部事件告警信息?',
|
||||
}
|
||||
},
|
||||
logManage:{
|
||||
@@ -875,7 +1184,7 @@ export default {
|
||||
alarmId:'告警唯一标识',
|
||||
alarmSeq:'告警流水号',
|
||||
alarmCode:'告警编号',
|
||||
alarmStatus:'原始告警级别',
|
||||
alarmStatus:'告警状态',
|
||||
eventTime:'告警产生时间',
|
||||
logTime:'记录时间',
|
||||
status:'告警状态'
|
||||
@@ -894,8 +1203,9 @@ export default {
|
||||
alarmId:'告警唯一标识',
|
||||
alarmSeq:'告警流水号',
|
||||
alarmObj:'告警前转对象',
|
||||
alarmInter:'告警前转接口',
|
||||
alarmTitle:'告警标题',
|
||||
alarmInfo:'告警内容',
|
||||
alarmInfo:'操作结果',
|
||||
eventTime:'告警产生时间',
|
||||
logTime:'记录时间'
|
||||
},
|
||||
@@ -1079,6 +1389,7 @@ export default {
|
||||
keyContent: "缓存内容",
|
||||
},
|
||||
cacheInfo: {
|
||||
baseInfo: "基本信息",
|
||||
version: "服务版本",
|
||||
mode: "运行模式",
|
||||
modeStandalone: "单机",
|
||||
@@ -1111,7 +1422,6 @@ export default {
|
||||
serialNum: '序列号',
|
||||
expiryDate: '许可证到期日期',
|
||||
switchLayout: "切换布局",
|
||||
viewLogFile: "查看日志文件",
|
||||
noData: "找不到对应的图组数据",
|
||||
},
|
||||
topologyBuild: {
|
||||
@@ -1289,8 +1599,8 @@ export default {
|
||||
loginTime: '登录时间',
|
||||
status: '用户状态',
|
||||
userNameTip:'账号不能以数字开头,可包含大写小写字母,数字,且不少于5位',
|
||||
pwdTip:'密码至少包含大小写字母、数字、特殊符号,且不少于6位',
|
||||
nickNameTip:'昵称只能包含字母、数字、中文和下划线,且不少于2位',
|
||||
passwdTip:'密码至少包含大小写字母、数字、特殊符号,且不少于6位',
|
||||
nickNameTip:'昵称不少于2位',
|
||||
emailTip:'请输入正确的邮箱地址',
|
||||
phoneTip:'请输入正确的手机号码',
|
||||
resetPwd:'重置密码',
|
||||
@@ -1313,7 +1623,7 @@ export default {
|
||||
userWork:'用户岗位',
|
||||
userWorkPlease: '请选择用户岗位',
|
||||
userTip:'用户说明',
|
||||
loginPwd:'登入密码',
|
||||
loginPwd:'登录密码',
|
||||
updateSure:'是否更新已经存在的数据',
|
||||
downloadObj:'下载模板',
|
||||
importTitle:'用户导入',
|
||||
@@ -1399,6 +1709,9 @@ export default {
|
||||
i18nOpen: "显示切换",
|
||||
i18nDefault: "默认语言",
|
||||
i18nInstruction: '是否显示国际化切换,设置系统默认语言',
|
||||
reset: "系统重置",
|
||||
resetInstruction: "系统重置将会清除当前系统内所有数据,请谨慎操作!!!",
|
||||
resetTipContent: '确认要清除当前系统内所有数据并坚持继续吗?',
|
||||
},
|
||||
role:{
|
||||
allScopeOptions:'全部数据权限',
|
||||
@@ -1423,10 +1736,10 @@ export default {
|
||||
distributeUser:'分配用户',
|
||||
roleMark:'角色说明',
|
||||
menu:'菜单权限',
|
||||
roleKeyTip:"权限标识示例:dba 控制器中使用权限标识,如: @PreAuthorize({ hasRoles: ['dba'] })",
|
||||
roleKeyTip:"权限标识用于控制页面控件或路由接口",
|
||||
openSwitch:'展开/折叠',
|
||||
selAllSwitch:'全选/全不选',
|
||||
relationSwitch:'父子联动',
|
||||
relationSwitch:'节点联动',
|
||||
normal:'正常',
|
||||
stop:'暂停',
|
||||
preScope:'权限范围',
|
||||
@@ -1593,6 +1906,65 @@ export default {
|
||||
exportOk: "已完成导出",
|
||||
typeDataErr: "获取字典类型信息失败",
|
||||
},
|
||||
quickStart: {
|
||||
start: '开始设置',
|
||||
skip: '跳过',
|
||||
finish: '完成设置',
|
||||
stepPrev: '上一步',
|
||||
stepNext: '下一步',
|
||||
exit: '退出',
|
||||
save: '保存信息',
|
||||
sysTitle: '系统配置',
|
||||
sysAdmin: '管理员',
|
||||
sysInfo: '系统信息',
|
||||
sysLogo: '系统LOGO',
|
||||
sysLogoTip: '将图片展示到系统LOGO区域查看效果,请使用透明背景,尺寸比例适应区域大小',
|
||||
sysName: '系统名称',
|
||||
sysNameTip: '系统名称限制20个字符长度',
|
||||
sysUploadLogo: '确认要上传系统LOGO文件吗?',
|
||||
sysUploadOk: '文件上传成功,请进行保存信息',
|
||||
sysSave: '保存',
|
||||
sysSaveOk: '信息保存成功!',
|
||||
sysPrevTip: '确认要返回上一个步骤吗?',
|
||||
sysNextNe: '确认要进行网元安装吗?',
|
||||
sysNextDone: '确认要跳过网元安装吗?',
|
||||
stepNeInfoTitle: "网元服务配置",
|
||||
stepNeInfoDesc: "设置网元对应的服务终端",
|
||||
stepNeInfoStepPrev: '确认要退出网元安装步骤吗?',
|
||||
stepNeInfoStepNext: '确认要下一步进行网元配置参数?',
|
||||
stepPara5GTitle: "网元配置参数",
|
||||
stepPara5GDesc: "设置网元全局参数信息",
|
||||
stepPara5GStepPrev: '确认要放弃当前变更返回上一步吗?',
|
||||
stepPara5GStepNext: '确认要下一步进行网元服务安装吗?',
|
||||
stepInstallTitle: "网元服务安装",
|
||||
stepInstallDesc: "将网元服务安装到服务终端",
|
||||
stepInstallStepPrev: '确认要放弃当前变更返回上一步吗?',
|
||||
stepInstallStepNext: '确认要下一步进行网元许可授权吗?',
|
||||
stepInstallText: '选择安装',
|
||||
stepInstallTip: '确认安装选择的网元新版本吗?',
|
||||
stepInstallModal: '网元进行安装',
|
||||
stepInstallNotNewVer: '没有发现新版本',
|
||||
stepInstallDone: '安装完成,服务进入初始化',
|
||||
stepInstallFail: '安装失败,请检查服务终端环境是否可用!',
|
||||
stepLicenseTitle: "网元许可授权",
|
||||
stepLicenseDesc: "获取网元许可激活码进行授权认证",
|
||||
stepLicenseReload: '选择刷新许可证',
|
||||
stepLicenseReloadTip: '确认刷新选择的许可证信息吗?',
|
||||
stepLicenseDownCode: '选择下载网元许可激活码',
|
||||
stepLicenseDownCodeTip: '确认下载选择的网元许可激活码到文本文件吗?',
|
||||
stepLicenseStepPrev: '确认要放弃当前变更返回上一步吗?',
|
||||
stepLicenseStepNext: '确认要结束网元安装步骤吗?',
|
||||
stepLicenseStepNext2: '请下载网元许可授权码文件保存,并联系网元厂商获取授权许可证',
|
||||
stepLicenseEnd: '结束',
|
||||
doneTitle: "完成配置",
|
||||
doneTip: '请进入系统后,根据情况进行更多相关配置',
|
||||
doneNETitle: '已经进行网元安装配置',
|
||||
doneNEDesc: '如有异常网元,可在系统内重新安装授权许可',
|
||||
doneSkipTitle: '未进行网元安装配置',
|
||||
doneSkipDesc: '系统将会默认初始网元信息,可在系统内自行修改或进行安装',
|
||||
donePrevTip: '确认要返回上一个步骤吗?',
|
||||
doneOkTip: '确认完成设置并开始使用吗?',
|
||||
},
|
||||
},
|
||||
mmlManage: {
|
||||
cmdTitle: "命令导航",
|
||||
@@ -1600,22 +1972,27 @@ export default {
|
||||
cmdOpTip: "左侧命令导航中选择要操作项!",
|
||||
cmdNoTip: "{num} 无可选命令操作",
|
||||
require: "必填参数:{num}",
|
||||
requireUn: "{display} 输入值是未知类型",
|
||||
requireString: "{display} 参数值不合理",
|
||||
requireInt: "{display} 参数值不在合理范围 {filter}",
|
||||
requireIpv4: "{display} 不是合法的IPV4地址",
|
||||
requireIpv6: "{display} 不是合法的IPV6地址",
|
||||
requireEnum: "{display} 不是合理的枚举值",
|
||||
requireBool: "{display} 不是合理的布尔类型的值",
|
||||
requireUn: "【 {display} 】输入值是未知类型",
|
||||
requireString: "【 {display} 】参数值不合理",
|
||||
requireInt: "【 {display} 】参数值不在合理范围 {filter}",
|
||||
requireIpv4: "【 {display} 】不是合法的IPV4地址",
|
||||
requireIpv6: "【 {display} 】不是合法的IPV6地址",
|
||||
requireEnum: "【 {display} 】不是合理的枚举值",
|
||||
requireBool: "【 {display} 】不是合理的布尔类型的值",
|
||||
requireFile: "【 {display} 】不是符合参数文件类型的值",
|
||||
cmdQuickEntry: "命令快速输入",
|
||||
cmdQuickEntryHelp: "换行(Shift + Enter) 执行发送(Enter)",
|
||||
cmdParamPanel: "参数面板",
|
||||
clearForm: "重置",
|
||||
clearLog: "清除日志",
|
||||
exec: "执行",
|
||||
cmdAwait: "等待发送命令",
|
||||
uploadFileTip: '确认要上传文件吗?',
|
||||
uploadFileOk: '文件上传成功',
|
||||
uploadFileErr: '文件上传失败',
|
||||
neOperate:{
|
||||
mml: "通用",
|
||||
mml2: "标准版",
|
||||
},
|
||||
omcOperate:{
|
||||
noOMC: "暂无OMC网元",
|
||||
},
|
||||
@@ -1635,10 +2012,28 @@ export default {
|
||||
},
|
||||
tool: {
|
||||
help: {
|
||||
fileName: "5G核心网网管操作手册.pdf",
|
||||
download: "下载",
|
||||
pdfViewer: "浏览器内预览",
|
||||
pdfViewerErr: "很抱歉,您的浏览器不支持 PDF 预览!",
|
||||
}
|
||||
},
|
||||
terminal: {
|
||||
start: "开始页",
|
||||
new: "去创建",
|
||||
more: "更多",
|
||||
reload: "断开重连",
|
||||
reloadTip: "确认要刷新重连当前 【{num}】 终端链接?",
|
||||
current: "关闭当前",
|
||||
other: "关闭其他",
|
||||
otherTip: "确认要关闭其他终端链接?",
|
||||
all: "关闭全部",
|
||||
allTip: "确认要关闭全部终端链接?",
|
||||
closeTip: "确认要关闭 【{num}】 终端链接?",
|
||||
hostSelectTitle: "选择已创建的主机进行连接",
|
||||
hostSelectShow: "打开选择",
|
||||
hostSelectMore: "加载更多 {num}",
|
||||
hostSelectHeader: "主机列表",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
import RightContent from './components/RightContent.vue';
|
||||
import Tabs from './components/Tabs.vue';
|
||||
import { scriptUrl } from '@/assets/js/icon_font_8d5l8fzk5b87iudi';
|
||||
import { computed, reactive, watch } from 'vue';
|
||||
import { computed, reactive, watch, onMounted, onUnmounted } from 'vue';
|
||||
import useLayoutStore from '@/store/modules/layout';
|
||||
import useRouterStore from '@/store/modules/router';
|
||||
import useTabsStore from '@/store/modules/tabs';
|
||||
@@ -21,7 +21,6 @@ const { proConfig, waterMarkContent } = useLayoutStore();
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
import { getServerTime } from '@/api';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import { onMounted } from 'vue';
|
||||
import { parseDateToStr } from '@/utils/date-utils';
|
||||
import { parseUrlPath } from '@/plugins/file-static-url';
|
||||
const { t, currentLocale } = useI18n();
|
||||
@@ -170,7 +169,7 @@ onMounted(() => {
|
||||
let serverTime = reactive({
|
||||
timestamp: 0,
|
||||
zone: 'UTC', // 时区 UTC
|
||||
interval: 0 as any, // 定时器
|
||||
interval: null as any, // 定时器
|
||||
});
|
||||
|
||||
// 获取服务器时间
|
||||
@@ -178,6 +177,9 @@ function fnGetServerTime() {
|
||||
getServerTime().then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS && res.data) {
|
||||
const serverTimeDom = document.getElementById('serverTimeDom');
|
||||
// 时区
|
||||
const utcOffset = res.data.timeZone / 3600;
|
||||
serverTime.zone = `UTC ${utcOffset}`;
|
||||
// 时间戳
|
||||
serverTime.timestamp = parseInt(res.data.timestamp);
|
||||
serverTime.interval = setInterval(() => {
|
||||
@@ -188,10 +190,6 @@ function fnGetServerTime() {
|
||||
serverTimeDom.innerText = parseDateToStr(serverTime.timestamp);
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
// 时区
|
||||
const offsetHours = res.data.timeZone / 3600;
|
||||
serverTime.zone = `UTC ${offsetHours}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -201,14 +199,21 @@ document.addEventListener('visibilitychange', function () {
|
||||
if (document.visibilityState == 'hidden') {
|
||||
//切离该页面时执行
|
||||
clearInterval(serverTime.interval);
|
||||
serverTime.interval = null;
|
||||
}
|
||||
if (document.visibilityState == 'visible') {
|
||||
//切换到该页面时执行
|
||||
clearInterval(serverTime.interval);
|
||||
serverTime.interval = null;
|
||||
fnGetServerTime();
|
||||
useAlarmStore().fnGetActiveAlarmInfo();
|
||||
}
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
clearInterval(serverTime.interval);
|
||||
serverTime.interval = null;
|
||||
});
|
||||
// ==== 服务器时间显示 end
|
||||
</script>
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ function fnChangeLocale(e: any) {
|
||||
</template>
|
||||
</a-button>
|
||||
|
||||
<a-tooltip placement="bottom">
|
||||
<a-tooltip placement="bottom" v-if="false">
|
||||
<template #title>{{ t('loayouts.rightContent.lock') }}</template>
|
||||
<a-button type="text" @click="fnClickLock">
|
||||
<template #icon>
|
||||
@@ -107,7 +107,7 @@ function fnChangeLocale(e: any) {
|
||||
|
||||
<a-dropdown
|
||||
placement="bottom"
|
||||
:trigger="['click', 'hover']"
|
||||
trigger="click"
|
||||
v-if="appStore.i18nOpen && hasPermissions(['system:setting:i18n'])"
|
||||
>
|
||||
<a-button size="small" type="default">
|
||||
@@ -123,7 +123,7 @@ function fnChangeLocale(e: any) {
|
||||
</template>
|
||||
</a-dropdown>
|
||||
|
||||
<a-dropdown placement="bottomRight" :trigger="['click', 'hover']">
|
||||
<a-dropdown placement="bottomRight" trigger="click">
|
||||
<div class="user">
|
||||
<a-avatar
|
||||
shape="circle"
|
||||
|
||||
@@ -95,7 +95,7 @@ function fnTabClose(path: string) {
|
||||
/**
|
||||
* 国际化翻译转换
|
||||
*/
|
||||
function fnLocale(title: string) {
|
||||
function fnLocale(title: string) {
|
||||
if (title.indexOf('router.') !== -1) {
|
||||
title = t(title);
|
||||
}
|
||||
@@ -150,7 +150,7 @@ watch(router.currentRoute, v => tabsStore.tabOpen(v), { immediate: true });
|
||||
</a-tooltip>
|
||||
<a-tooltip placement="topRight">
|
||||
<template #title>{{ t('loayouts.tabs.more') }}</template>
|
||||
<a-dropdown :trigger="['click', 'hover']" placement="bottomRight">
|
||||
<a-dropdown trigger="click" placement="bottomRight">
|
||||
<a-button type="ghost" shape="circle" size="small">
|
||||
<template #icon><DownOutlined /></template>
|
||||
</a-button>
|
||||
|
||||
@@ -11,7 +11,7 @@ export type OptionsType = {
|
||||
/**地址栏参数 */
|
||||
params?: Record<string, string | number | boolean | undefined>;
|
||||
/**onopen事件的回调函数 */
|
||||
onopen?: () => void;
|
||||
onopen?: Function;
|
||||
/**message事件的回调函数 */
|
||||
onmessage: (data: Record<string, any>) => void;
|
||||
/**error事件的回调函数 */
|
||||
@@ -114,7 +114,7 @@ export class WS {
|
||||
this.heartCheck(options.heartTimer);
|
||||
}
|
||||
if (typeof options.onopen === 'function') {
|
||||
options.onopen();
|
||||
options.onopen(ev);
|
||||
}
|
||||
};
|
||||
// 用于指定当从服务器接受到信息时的回调函数。
|
||||
@@ -160,23 +160,49 @@ export class WS {
|
||||
}
|
||||
}
|
||||
|
||||
// 发送消息
|
||||
public send(data: Record<string, any>) {
|
||||
/**
|
||||
* 发送消息
|
||||
* @param data JSON数据
|
||||
* @returns
|
||||
*/
|
||||
public send(data: Record<string, any>): boolean {
|
||||
if (!this.ws) {
|
||||
console.warn('websocket unavailable');
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// 非正常状态关闭
|
||||
if (
|
||||
this.ws.readyState === WebSocket.CLOSED ||
|
||||
this.ws.readyState === WebSocket.CLOSING
|
||||
) {
|
||||
this.close();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
// 正在连接时
|
||||
if (this.ws.readyState === WebSocket.CONNECTING) {
|
||||
setTimeout(() => {
|
||||
this.ws && this.ws.send(JSON.stringify(data));
|
||||
}, 1000);
|
||||
}
|
||||
// 在连接的
|
||||
if (this.ws.readyState === WebSocket.OPEN) {
|
||||
this.ws.send(JSON.stringify(data));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
this.ws.send(JSON.stringify(data));
|
||||
/**连接状态
|
||||
*
|
||||
* WebSocket.OPEN
|
||||
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/WebSocket/readyState)
|
||||
*/
|
||||
public state(): number {
|
||||
if (!this.ws) {
|
||||
return -1;
|
||||
}
|
||||
return this.ws.readyState;
|
||||
}
|
||||
|
||||
// 手动关闭socket
|
||||
|
||||
@@ -87,6 +87,12 @@ const constantRoutes: RouteRecordRaw[] = [
|
||||
meta: { title: 'router.helpDoc' },
|
||||
component: () => import('@/views/tool/help/index.vue'),
|
||||
},
|
||||
{
|
||||
path: '/quick-start',
|
||||
name: 'QuickStart',
|
||||
meta: { title: 'router.quickStart' },
|
||||
component: () => import('@/views/system/quick-start/index.vue'),
|
||||
},
|
||||
{
|
||||
path: '/redirect',
|
||||
name: 'Redirect',
|
||||
@@ -136,17 +142,30 @@ router.afterEach((to, from, failure) => {
|
||||
});
|
||||
|
||||
/**无Token可访问页面地址白名单 */
|
||||
const WHITE_LIST: string[] = ['/login', '/auth-redirect', '/help', '/register'];
|
||||
const WHITE_LIST: string[] = [
|
||||
'/login',
|
||||
'/auth-redirect',
|
||||
'/help',
|
||||
'/register',
|
||||
'/quick-start',
|
||||
];
|
||||
|
||||
/**全局路由-前置守卫 */
|
||||
router.beforeEach((to, from, next) => {
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
NProgress.start();
|
||||
const token = getToken();
|
||||
|
||||
// 获取系统配置信息
|
||||
const appStore = useAppStore();
|
||||
if (!appStore.loginBackground) {
|
||||
appStore.fnSysConf();
|
||||
await appStore.fnSysConf();
|
||||
}
|
||||
|
||||
// 需要系统引导跳转
|
||||
if (appStore.bootloader && to.path !== '/quick-start') {
|
||||
next({ name: 'QuickStart' });
|
||||
}
|
||||
|
||||
const token = getToken();
|
||||
|
||||
// 没有token
|
||||
if (!token) {
|
||||
@@ -168,31 +187,27 @@ router.beforeEach((to, from, next) => {
|
||||
// 判断当前用户是否有角色信息
|
||||
const user = useUserStore();
|
||||
if (user.roles && user.roles.length === 0) {
|
||||
// 获取用户信息
|
||||
user
|
||||
.fnGetInfo()
|
||||
.then(() => {
|
||||
return useRouterStore().generateRoutes();
|
||||
})
|
||||
.then(accessRoutes => {
|
||||
// 根据后台配置生成可访问的路由表
|
||||
if (accessRoutes && accessRoutes.length !== 0) {
|
||||
for (const route of accessRoutes) {
|
||||
// 动态添加可访问路由表,http开头会异常
|
||||
if (!validHttp(route.path)) {
|
||||
router.addRoute(route);
|
||||
}
|
||||
try {
|
||||
// 获取用户信息
|
||||
await user.fnGetInfo();
|
||||
// 获取路由信息
|
||||
const accessRoutes = await useRouterStore().generateRoutes();
|
||||
// 根据后台配置生成可访问的路由表
|
||||
if (accessRoutes && accessRoutes.length !== 0) {
|
||||
for (const route of accessRoutes) {
|
||||
// 动态添加可访问路由表,http开头会异常
|
||||
if (!validHttp(route.path)) {
|
||||
router.addRoute(route);
|
||||
}
|
||||
}
|
||||
// 刷新替换原先路由,确保addRoutes已完成
|
||||
next({ ...to, replace: true });
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(`[${to.path}]: ${e.message}`);
|
||||
user.fnLogOut().finally(() => {
|
||||
next({ name: 'Login' });
|
||||
});
|
||||
});
|
||||
}
|
||||
// 刷新替换原先路由,确保addRoutes已完成
|
||||
next({ ...to, replace: true });
|
||||
} catch (error: any) {
|
||||
console.error(`[${to.path}]: ${error.message}`);
|
||||
await user.fnLogOut();
|
||||
next({ name: 'Login' });
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { getSysConf } from '@/api';
|
||||
import { CACHE_LOCAL_I18N } from '@/constants/cache-keys-constants';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import { removeToken } from '@/plugins/auth-token';
|
||||
import { parseUrlPath } from '@/plugins/file-static-url';
|
||||
import { localGet, localSet } from '@/utils/cache-local-utils';
|
||||
import { defineStore } from 'pinia';
|
||||
@@ -17,6 +18,8 @@ type AppStore = {
|
||||
/**服务版本 */
|
||||
version: string;
|
||||
buildTime: string;
|
||||
/**系统引导使用 */
|
||||
bootloader: boolean;
|
||||
// 序列号
|
||||
serialNum: string;
|
||||
/**应用版权声明 */
|
||||
@@ -48,6 +51,7 @@ const useAppStore = defineStore('app', {
|
||||
|
||||
version: `-`,
|
||||
buildTime: `-`,
|
||||
bootloader: false,
|
||||
serialNum: `-`,
|
||||
copyright: `Copyright ©2023 For ${import.meta.env.VITE_APP_NAME}`,
|
||||
logoType: 'icon',
|
||||
@@ -57,7 +61,7 @@ const useAppStore = defineStore('app', {
|
||||
loginBackground: '',
|
||||
helpDoc: '',
|
||||
officialUrl: '',
|
||||
i18nOpen: true,
|
||||
i18nOpen: false,
|
||||
i18nDefault: 'en_US',
|
||||
}),
|
||||
getters: {},
|
||||
@@ -70,16 +74,17 @@ const useAppStore = defineStore('app', {
|
||||
document.title = this.appName;
|
||||
}
|
||||
},
|
||||
/**设置版权声明 */
|
||||
setCopyright(text: string) {
|
||||
this.copyright = text;
|
||||
},
|
||||
// 获取系统配置信息
|
||||
async fnSysConf() {
|
||||
const res = await getSysConf();
|
||||
if (res.code === RESULT_CODE_SUCCESS && res.data) {
|
||||
this.version = res.data.version;
|
||||
this.buildTime = res.data.buildTime;
|
||||
this.bootloader = res.data.bootloader === 'true';
|
||||
// 引导时
|
||||
if (this.bootloader) {
|
||||
removeToken();
|
||||
}
|
||||
this.serialNum = res.data.serialNum;
|
||||
this.appName = res.data.title;
|
||||
this.copyright = res.data.copyright;
|
||||
|
||||
@@ -7,14 +7,14 @@ import { defineStore } from 'pinia';
|
||||
/**锁屏信息类型 */
|
||||
type Locked = {
|
||||
/**锁屏类型 */
|
||||
type: 'none' | 'lock' | 'reload' | string;
|
||||
type: 'none' | 'lock' | 'reload' | 'reset';
|
||||
/**lock 超时锁屏时间,秒*/
|
||||
lockTimeout: number;
|
||||
};
|
||||
|
||||
const useLockedStore = defineStore('locked', {
|
||||
state: (): Locked => ({
|
||||
type: localGet(CACHE_LOCAL_LOCK) || 'none',
|
||||
type: (localGet(CACHE_LOCAL_LOCK) || 'none') as Locked['type'],
|
||||
lockTimeout: 0,
|
||||
}),
|
||||
getters: {},
|
||||
@@ -24,8 +24,16 @@ const useLockedStore = defineStore('locked', {
|
||||
try {
|
||||
const res = await getSysConf();
|
||||
if (res.code === RESULT_CODE_SUCCESS && res.data) {
|
||||
this.fnLock('none');
|
||||
window.location.reload();
|
||||
// 延迟5秒
|
||||
setTimeout(() => {
|
||||
this.fnLock('none');
|
||||
window.location.reload();
|
||||
}, 2_000);
|
||||
} else {
|
||||
// 延迟5秒
|
||||
setTimeout(() => {
|
||||
this.relaodWait();
|
||||
}, 5_000);
|
||||
}
|
||||
} catch (error) {
|
||||
// 延迟5秒
|
||||
@@ -35,7 +43,7 @@ const useLockedStore = defineStore('locked', {
|
||||
}
|
||||
},
|
||||
// 设置锁定
|
||||
async fnLock(type: 'none' | 'lock' | 'reload' | string) {
|
||||
async fnLock(type: Locked['type']) {
|
||||
this.type = type;
|
||||
localSet(CACHE_LOCAL_LOCK, type);
|
||||
if (type === 'reload') {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import { getNelistAll } from '@/api/configManage/neManage';
|
||||
import { listAllNeInfo } from '@/api/ne/neInfo';
|
||||
import { parseDataToOptions } from '@/utils/parse-tree-utils';
|
||||
import { getNeTraceInterfaceAll } from '@/api/traceManage/task';
|
||||
import { getNePerformanceList } from '@/api/perfManage/taskManage';
|
||||
@@ -58,10 +58,12 @@ const useNeInfoStore = defineStore('neinfo', {
|
||||
if (this.neList.length > 0) {
|
||||
return { code: 1, data: this.neList, msg: 'success' };
|
||||
}
|
||||
const res = await getNelistAll();
|
||||
const res = await listAllNeInfo({
|
||||
bandStatus: false,
|
||||
});
|
||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||
// 原始列表
|
||||
this.neList = res.data;
|
||||
this.neList = JSON.parse(JSON.stringify(res.data));
|
||||
|
||||
// 转级联数据
|
||||
const options = parseDataToOptions(
|
||||
|
||||
@@ -9,8 +9,6 @@ import { parseUrlPath } from '@/plugins/file-static-url';
|
||||
|
||||
/**用户信息类型 */
|
||||
type UserInfo = {
|
||||
/**授权凭证 */
|
||||
token: string;
|
||||
/**登录账号 */
|
||||
userName: string;
|
||||
/**用户角色 字符串数组 */
|
||||
@@ -27,13 +25,12 @@ type UserInfo = {
|
||||
email: string;
|
||||
/**用户性别 */
|
||||
sex: string | undefined;
|
||||
/**个人化设置 */
|
||||
/**其他信息 */
|
||||
profile: Record<string, any>;
|
||||
};
|
||||
|
||||
const useUserStore = defineStore('user', {
|
||||
state: (): UserInfo => ({
|
||||
token: getToken(),
|
||||
userName: '',
|
||||
roles: [],
|
||||
permissions: [],
|
||||
@@ -104,7 +101,6 @@ const useUserStore = defineStore('user', {
|
||||
if (res.code === RESULT_CODE_SUCCESS && res.data) {
|
||||
const token = res.data[TOKEN_RESPONSE_FIELD];
|
||||
setToken(token);
|
||||
this.token = token;
|
||||
}
|
||||
return res;
|
||||
},
|
||||
@@ -154,7 +150,6 @@ const useUserStore = defineStore('user', {
|
||||
} catch (error) {
|
||||
throw error;
|
||||
} finally {
|
||||
this.token = '';
|
||||
this.roles = [];
|
||||
this.permissions = [];
|
||||
removeToken();
|
||||
|
||||
70
src/utils/cache-db-utils.ts
Normal file
70
src/utils/cache-db-utils.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
// 文档 https://localforage.docschina.org/
|
||||
import localforage from 'localforage';
|
||||
|
||||
/**数据级缓存设置 */
|
||||
export async function dbSet(storeName: string, key: string, value: any) {
|
||||
if (!storeName || !key || !value) {
|
||||
return false;
|
||||
}
|
||||
localforage.config({
|
||||
name: import.meta.env.VITE_APP_CODE,
|
||||
storeName: storeName,
|
||||
});
|
||||
try {
|
||||
await localforage.setItem(key, value);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**数据级缓存获取 */
|
||||
export async function dbGet(storeName: string, key: string) {
|
||||
if (!storeName || !key) {
|
||||
return null;
|
||||
}
|
||||
localforage.config({
|
||||
name: import.meta.env.VITE_APP_CODE,
|
||||
storeName: storeName,
|
||||
});
|
||||
let value: any = null;
|
||||
try {
|
||||
value = await localforage.getItem(key);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**数据级缓存移除 */
|
||||
export async function dbRemove(storeName: string, key: string) {
|
||||
if (!storeName || !key) {
|
||||
return false;
|
||||
}
|
||||
localforage.config({
|
||||
name: import.meta.env.VITE_APP_CODE,
|
||||
storeName: storeName,
|
||||
});
|
||||
try {
|
||||
await localforage.removeItem(key);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**数据级缓存设置JSON */
|
||||
export function dbSetJSON(storeName: string, key: string, jsonValue: object) {
|
||||
return dbSet(storeName, key, JSON.stringify(jsonValue));
|
||||
}
|
||||
|
||||
/**数据级缓存获取JSON */
|
||||
export async function dbGetJSON(storeName: string, key: string) {
|
||||
const value = await dbGet(storeName, key);
|
||||
if (typeof value === 'string') {
|
||||
return JSON.parse(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -83,7 +83,7 @@ export function parseDuration(seconds: number | string) {
|
||||
const duration = new Date(seconds * 1000);
|
||||
const hours = duration.getUTCHours();
|
||||
const minutes = duration.getUTCMinutes();
|
||||
const secondsLeft = duration.getUTCSeconds();
|
||||
const secondsLeft = duration.getUTCSeconds();
|
||||
if (+hours > 0) {
|
||||
return `${hours}h${minutes}m${secondsLeft}s`;
|
||||
}
|
||||
|
||||
@@ -122,9 +122,11 @@ export function parseSizeFromKBs(size: number): string {
|
||||
/**
|
||||
* 字节数转换速率
|
||||
* @param sizeByte 数值大小
|
||||
* @returns
|
||||
* @returns [值,单位]
|
||||
*/
|
||||
export function parseSizeFromKbs(sizeByte: number, timeInterval: number): any {
|
||||
sizeByte = Number(sizeByte) || 0;
|
||||
timeInterval = Number(timeInterval) || 1;
|
||||
// let realBit:any=((sizeByte * 8) / timeInterval);
|
||||
// if (realBit >= 0 && realBit < 1000) {
|
||||
// return [realBit.toFixed(2),' bits/sec'];
|
||||
|
||||
@@ -34,7 +34,7 @@ export const regExpPasswd =
|
||||
/**
|
||||
* 有效手机号格式
|
||||
*/
|
||||
export const regExpMobile = /^1[3|4|5|6|7|8|9][0-9]\d{8}$/;
|
||||
export const regExpMobile = /^.{3,}$/; // /^1[3|4|5|6|7|8|9][0-9]\d{8}$/;
|
||||
|
||||
/**
|
||||
* 有效邮箱格式
|
||||
@@ -47,7 +47,7 @@ export const regExpEmail =
|
||||
*
|
||||
* 用户昵称只能包含字母、数字、中文和下划线,且不少于2位
|
||||
*/
|
||||
export const regExpNick = /^[\w\u4e00-\u9fa5-]{2,}$/;
|
||||
export const regExpNick = /^.{2,}$/; // /^[\w\u4e00-\u9fa5-]{2,}$/;
|
||||
|
||||
/**
|
||||
* 是否为http(s)://开头
|
||||
@@ -84,13 +84,14 @@ export function validURL(str: string) {
|
||||
// http:// is appended so url.Parse will succeed, strTemp used so it does not impact rxURL.MatchString
|
||||
strTemp = 'http://' + str;
|
||||
}
|
||||
debugger;
|
||||
|
||||
let u = { host: '', pathname: '' };
|
||||
try {
|
||||
new URL(strTemp);
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
const u = new URL(strTemp);
|
||||
|
||||
if (u.host.startsWith('.')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -166,12 +166,12 @@ onMounted(() => {
|
||||
},
|
||||
]"
|
||||
>
|
||||
<a-input
|
||||
<IntlTelInput
|
||||
v-model:value="stateForm.form.phonenumber"
|
||||
allow-clear
|
||||
:maxlength="11"
|
||||
:maxlength="16"
|
||||
:placeholder="t('views.account.settings.phonenumberPleace')"
|
||||
></a-input>
|
||||
></IntlTelInput>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
|
||||
@@ -227,7 +227,11 @@ function fnGetList(pageNum?: number) {
|
||||
}
|
||||
tablePagination.total = res.total;
|
||||
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;
|
||||
fnGetList(queryParams.pageNum - 1);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
157
src/views/configManage/configParamTreeTable/hooks/useOptions.ts
Normal file
157
src/views/configManage/configParamTreeTable/hooks/useOptions.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
import { regExpIPv4, regExpIPv6, validURL } from '@/utils/regular-utils';
|
||||
|
||||
export default function useOptions() {
|
||||
const { t } = useI18n();
|
||||
|
||||
/**规则校验 */
|
||||
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':
|
||||
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.configManage.configParamForm.requireInt', {
|
||||
display,
|
||||
filter,
|
||||
}),
|
||||
];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'ipv4':
|
||||
if (!regExpIPv4.test(value)) {
|
||||
return [
|
||||
false,
|
||||
t('views.configManage.configParamForm.requireIpv4', { display }),
|
||||
];
|
||||
}
|
||||
break;
|
||||
case 'ipv6':
|
||||
if (!regExpIPv6.test(value)) {
|
||||
return [
|
||||
false,
|
||||
t('views.configManage.configParamForm.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.configManage.configParamForm.requireEnum', { display }),
|
||||
];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'bool':
|
||||
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.configManage.configParamForm.requireBool', { display }),
|
||||
];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'string':
|
||||
// 字符串长度判断
|
||||
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.configManage.configParamForm.requireString', {
|
||||
display,
|
||||
}),
|
||||
];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
// 字符串http判断
|
||||
if (value.startsWith('http')) {
|
||||
try {
|
||||
if (!validURL(value)) {
|
||||
return [
|
||||
false,
|
||||
t('views.configManage.configParamForm.requireString', {
|
||||
display,
|
||||
}),
|
||||
];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 'regex':
|
||||
if (filter) {
|
||||
try {
|
||||
let regex = new RegExp(filter);
|
||||
if (!regex.test(value)) {
|
||||
return [
|
||||
false,
|
||||
t('views.configManage.configParamForm.requireString', {
|
||||
display,
|
||||
}),
|
||||
];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return [
|
||||
false,
|
||||
t('views.configManage.configParamForm.requireUn', { display }),
|
||||
];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return { ruleVerification };
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { getParamConfigInfo } from '@/api/configManage/configParam';
|
||||
import { ref } from 'vue';
|
||||
|
||||
export default function useSMFOptions() {
|
||||
/**upfId可选择 */
|
||||
const optionsUPFIds = ref<{ value: string; label: string }[]>([]);
|
||||
|
||||
/**初始加载upfId */
|
||||
function initUPFIds() {
|
||||
getParamConfigInfo('smf', 'upfConfig', '001').then(res => {
|
||||
optionsUPFIds.value = [];
|
||||
for (const s of res.data) {
|
||||
optionsUPFIds.value.push({
|
||||
value: s.id,
|
||||
label: s.id,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return { initUPFIds, optionsUPFIds };
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, onMounted, watch, toRaw, nextTick } from 'vue';
|
||||
import { reactive, ref, onMounted, toRaw, nextTick, watch } from 'vue';
|
||||
import { PageContainer } from 'antdv-pro-layout';
|
||||
import { Modal, message } from 'ant-design-vue/lib';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
@@ -13,11 +13,14 @@ import {
|
||||
addParamConfigInfo,
|
||||
} from '@/api/configManage/configParam';
|
||||
import useNeInfoStore from '@/store/modules/neinfo';
|
||||
import { regExpIPv4, regExpIPv6, validURL } from '@/utils/regular-utils';
|
||||
import useOptions from './hooks/useOptions';
|
||||
import useSMFOptions from './hooks/useSMFOptions';
|
||||
import { SizeType } from 'ant-design-vue/lib/config-provider';
|
||||
import { DataNode } from 'ant-design-vue/lib/tree';
|
||||
const neInfoStore = useNeInfoStore();
|
||||
const { t } = useI18n();
|
||||
const { ruleVerification } = useOptions();
|
||||
const { initUPFIds, optionsUPFIds } = useSMFOptions();
|
||||
|
||||
/**网元参数 */
|
||||
let neCascaderOptions = ref<Record<string, any>[]>([]);
|
||||
@@ -25,6 +28,14 @@ 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 */
|
||||
@@ -43,7 +54,7 @@ let treeState: TreeStateType = reactive({
|
||||
selectNode: {
|
||||
topDisplay: '' as string,
|
||||
topTag: '' as string,
|
||||
method: '' as string,
|
||||
method: [] as string[],
|
||||
//
|
||||
title: '' as string,
|
||||
key: '' as string,
|
||||
@@ -57,7 +68,11 @@ function fnSelectConfigNode(_: any, info: any) {
|
||||
const { title, key, method } = info.node;
|
||||
treeState.selectNode.topDisplay = title;
|
||||
treeState.selectNode.topTag = key;
|
||||
treeState.selectNode.method = method;
|
||||
if (method) {
|
||||
treeState.selectNode.method = method.split(',');
|
||||
} else {
|
||||
treeState.selectNode.method = ['post', 'put', 'delete'];
|
||||
}
|
||||
treeState.selectNode.title = title;
|
||||
treeState.selectNode.key = key;
|
||||
fnActiveConfigNode(key);
|
||||
@@ -329,14 +344,6 @@ let arrayState: ArrayStateType = reactive({
|
||||
dataRule: {},
|
||||
});
|
||||
|
||||
/**监听表格字段列排序变化关闭展开 */
|
||||
watch(
|
||||
() => arrayState.columnsDnd,
|
||||
() => {
|
||||
arrayEditClose();
|
||||
}
|
||||
);
|
||||
|
||||
/**多列表编辑 */
|
||||
function arrayEdit(rowIndex: Record<string, any>) {
|
||||
const item = arrayState.data.find((s: any) => s.key === rowIndex.value);
|
||||
@@ -941,155 +948,6 @@ function arrayAddInit(data: any[], dataRule: any) {
|
||||
return ruleFrom;
|
||||
}
|
||||
|
||||
/**规则校验 */
|
||||
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':
|
||||
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.configManage.configParamForm.requireInt', {
|
||||
display,
|
||||
filter,
|
||||
}),
|
||||
];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'ipv4':
|
||||
if (!regExpIPv4.test(value)) {
|
||||
return [
|
||||
false,
|
||||
t('views.configManage.configParamForm.requireIpv4', { display }),
|
||||
];
|
||||
}
|
||||
break;
|
||||
case 'ipv6':
|
||||
if (!regExpIPv6.test(value)) {
|
||||
return [
|
||||
false,
|
||||
t('views.configManage.configParamForm.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.configManage.configParamForm.requireEnum', { display }),
|
||||
];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'bool':
|
||||
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.configManage.configParamForm.requireBool', { display }),
|
||||
];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'string':
|
||||
// 字符串长度判断
|
||||
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.configManage.configParamForm.requireString', {
|
||||
display,
|
||||
}),
|
||||
];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
// 字符串http判断
|
||||
if (value.startsWith('http')) {
|
||||
try {
|
||||
if (!validURL(value)) {
|
||||
return [
|
||||
false,
|
||||
t('views.configManage.configParamForm.requireString', {
|
||||
display,
|
||||
}),
|
||||
];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 'regex':
|
||||
if (filter) {
|
||||
try {
|
||||
let regex = new RegExp(filter);
|
||||
if (!regex.test(value)) {
|
||||
return [
|
||||
false,
|
||||
t('views.configManage.configParamForm.requireString', {
|
||||
display,
|
||||
}),
|
||||
];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return [
|
||||
false,
|
||||
t('views.configManage.configParamForm.requireUn', { display }),
|
||||
];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**对话框对象信息状态类型 */
|
||||
type ModalStateType = {
|
||||
/**添加框是否显示 */
|
||||
@@ -1151,6 +1009,25 @@ function fnModalCancel() {
|
||||
modalState.data = [];
|
||||
}
|
||||
|
||||
// 监听表格字段列排序变化关闭展开
|
||||
watch(
|
||||
() => arrayState.columnsDnd,
|
||||
() => {
|
||||
arrayEditClose();
|
||||
}
|
||||
);
|
||||
|
||||
// 监听新增编辑弹窗
|
||||
watch(
|
||||
() => modalState.visible,
|
||||
val => {
|
||||
// SMF需要选择配置的UPF id
|
||||
if (val && neTypeSelect.value[0] === 'SMF') {
|
||||
initUPFIds();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
// 获取网元网元列表
|
||||
neInfoStore.fnNelist().then(res => {
|
||||
@@ -1170,7 +1047,7 @@ onMounted(() => {
|
||||
return;
|
||||
}
|
||||
// 默认选择AMF
|
||||
const item = neCascaderOptions.value.find(s => s.value === 'UPF');
|
||||
const item = neCascaderOptions.value.find(s => s.value === 'AMF');
|
||||
if (item && item.children) {
|
||||
const info = item.children[0];
|
||||
neTypeSelect.value = [info.neType, info.neId];
|
||||
@@ -1193,7 +1070,13 @@ onMounted(() => {
|
||||
<template>
|
||||
<PageContainer>
|
||||
<a-row :gutter="16">
|
||||
<a-col :lg="6" :md="6" :xs="24" style="margin-bottom: 24px">
|
||||
<a-col
|
||||
:lg="6"
|
||||
:md="6"
|
||||
:xs="24"
|
||||
style="margin-bottom: 24px"
|
||||
v-show="collapsible"
|
||||
>
|
||||
<!-- 网元类型 -->
|
||||
<a-card
|
||||
size="small"
|
||||
@@ -1221,7 +1104,7 @@ onMounted(() => {
|
||||
</a-form>
|
||||
</a-card>
|
||||
</a-col>
|
||||
<a-col :lg="18" :md="18" :xs="24">
|
||||
<a-col :lg="collapsible ? 18 : 24" :md="collapsible ? 18 : 24" :xs="24">
|
||||
<a-card
|
||||
size="small"
|
||||
:bordered="false"
|
||||
@@ -1229,6 +1112,13 @@ onMounted(() => {
|
||||
:loading="treeState.selectLoading"
|
||||
>
|
||||
<template #title>
|
||||
<a-button type="text" @click.prevent="changeCollapsible()">
|
||||
<template #icon>
|
||||
<MenuFoldOutlined v-show="collapsible" />
|
||||
<MenuUnfoldOutlined v-show="!collapsible" />
|
||||
</template>
|
||||
</a-button>
|
||||
|
||||
<a-typography-text strong v-if="treeState.selectNode.topDisplay">
|
||||
{{ treeState.selectNode.topDisplay }}
|
||||
</a-typography-text>
|
||||
@@ -1349,7 +1239,9 @@ onMounted(() => {
|
||||
<EditOutlined
|
||||
class="editable-cell__icon"
|
||||
@click="listEdit(record)"
|
||||
v-if="!['read-only', 'ro'].includes(record.access)"
|
||||
v-if="
|
||||
!['read-only', 'read', 'ro'].includes(record.access)
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1363,7 +1255,7 @@ onMounted(() => {
|
||||
<a-table
|
||||
class="table"
|
||||
row-key="index"
|
||||
:columns="treeState.selectNode.method === 'get' ? arrayState.columnsDnd.filter((s:any)=>s.key !== 'index') : arrayState.columnsDnd"
|
||||
:columns="treeState.selectNode.method.includes('get') ? arrayState.columnsDnd.filter((s:any)=>s.key !== 'index') : arrayState.columnsDnd"
|
||||
:data-source="arrayState.columnsData"
|
||||
:size="arrayState.size"
|
||||
:pagination="tablePagination"
|
||||
@@ -1380,14 +1272,15 @@ onMounted(() => {
|
||||
type="primary"
|
||||
@click.prevent="arrayAdd()"
|
||||
size="small"
|
||||
v-if="treeState.selectNode.method !== 'get'"
|
||||
v-if="treeState.selectNode.method.includes('post')"
|
||||
>
|
||||
<template #icon> <PlusOutlined /> </template>
|
||||
{{ t('common.addText') }}
|
||||
</a-button>
|
||||
<TableColumnsDnd
|
||||
type="ghost"
|
||||
:columns="treeState.selectNode.method === 'get' ? [...arrayState.columns.filter((s:any)=>s.key !== 'index')] : arrayState.columns"
|
||||
:cache-id="treeState.selectNode.key"
|
||||
:columns="treeState.selectNode.method.includes('get') ? [...arrayState.columns.filter((s:any)=>s.key !== 'index')] : arrayState.columns"
|
||||
v-model:columns-dnd="arrayState.columnsDnd"
|
||||
></TableColumnsDnd>
|
||||
</a-space>
|
||||
@@ -1397,13 +1290,17 @@ onMounted(() => {
|
||||
<template #bodyCell="{ column, text, record }">
|
||||
<template v-if="column?.key === 'index'">
|
||||
<a-space :size="16" align="center">
|
||||
<a-tooltip>
|
||||
<a-tooltip
|
||||
v-if="treeState.selectNode.method.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>
|
||||
<a-tooltip
|
||||
v-if="treeState.selectNode.method.includes('delete')"
|
||||
>
|
||||
<template #title>{{ t('common.deleteText') }}</template>
|
||||
<a-button type="link" @click.prevent="arrayDelete(text)">
|
||||
<template #icon><DeleteOutlined /></template>
|
||||
@@ -1488,6 +1385,7 @@ onMounted(() => {
|
||||
</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"
|
||||
@@ -1507,9 +1405,9 @@ onMounted(() => {
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip>
|
||||
<template #title>{{
|
||||
t('common.deleteText')
|
||||
}}</template>
|
||||
<template #title>
|
||||
{{ t('common.deleteText') }}
|
||||
</template>
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="arrayChildDelete(text)"
|
||||
@@ -1596,10 +1494,24 @@ onMounted(() => {
|
||||
modalState.from[item.name] !== undefined
|
||||
"
|
||||
>
|
||||
<a-input-number
|
||||
v-if="item['type'] === 'int'"
|
||||
<!-- 特殊SMF-upfid选择 -->
|
||||
<a-select
|
||||
v-if="
|
||||
neTypeSelect[0] === 'SMF' &&
|
||||
modalState.from[item.name]['name'] === 'upfId'
|
||||
"
|
||||
v-model:value="modalState.from[item.name]['value']"
|
||||
:disabled="['read-only', 'ro'].includes(item.access)"
|
||||
:options="optionsUPFIds"
|
||||
:disabled="['read-only', 'read', 'ro'].includes(item.access)"
|
||||
: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
|
||||
@@ -1607,12 +1519,12 @@ onMounted(() => {
|
||||
v-model:checked="modalState.from[item.name]['value']"
|
||||
:checked-children="t('common.switch.open')"
|
||||
:un-checked-children="t('common.switch.shut')"
|
||||
:disabled="['read-only', 'ro'].includes(item.access)"
|
||||
: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', 'ro'].includes(item.access)"
|
||||
:disabled="['read-only', 'read', 'ro'].includes(item.access)"
|
||||
:allow-clear="true"
|
||||
style="width: 100%"
|
||||
>
|
||||
@@ -1627,7 +1539,7 @@ onMounted(() => {
|
||||
<a-input
|
||||
v-else
|
||||
v-model:value="modalState.from[item.name]['value']"
|
||||
:disabled="['read-only', 'ro'].includes(item.access)"
|
||||
:disabled="['read-only', 'read', 'ro'].includes(item.access)"
|
||||
></a-input>
|
||||
</div>
|
||||
<div v-else>
|
||||
|
||||
@@ -11,6 +11,7 @@ import useI18n from '@/hooks/useI18n';
|
||||
import useNeInfoStore from '@/store/modules/neinfo';
|
||||
import { FileType } from 'ant-design-vue/lib/upload/interface';
|
||||
import { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
|
||||
import { parseDateToStr } from '@/utils/date-utils';
|
||||
const neInfoStore = useNeInfoStore();
|
||||
const { t } = useI18n();
|
||||
|
||||
@@ -74,21 +75,25 @@ let tableColumns: ColumnsType = [
|
||||
width: 2,
|
||||
},
|
||||
{
|
||||
title: t('views.configManage.license.fileName'),
|
||||
dataIndex: 'fileName',
|
||||
title: t('views.configManage.license.serialNum'),
|
||||
dataIndex: 'serialNum',
|
||||
align: 'center',
|
||||
width: 3,
|
||||
},
|
||||
{
|
||||
title: t('views.configManage.license.comment'),
|
||||
dataIndex: 'comment',
|
||||
dataIndex: 'remark',
|
||||
align: 'center',
|
||||
width: 5,
|
||||
},
|
||||
{
|
||||
title: t('views.configManage.license.createTime'),
|
||||
dataIndex: 'createdAt',
|
||||
dataIndex: 'createTime',
|
||||
align: 'center',
|
||||
customRender(opt) {
|
||||
if (!opt.value) return '';
|
||||
return parseDateToStr(opt.value);
|
||||
},
|
||||
width: 2,
|
||||
},
|
||||
];
|
||||
@@ -141,7 +146,11 @@ function fnGetList(pageNum?: number) {
|
||||
}
|
||||
tablePagination.total = res.total;
|
||||
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;
|
||||
fnGetList(queryParams.pageNum - 1);
|
||||
}
|
||||
@@ -301,7 +310,7 @@ onMounted(() => {
|
||||
fnGetList();
|
||||
} else {
|
||||
message.warning({
|
||||
content: t('views.configManage.softwareManage.nullData'),
|
||||
content: t('common.noData'),
|
||||
duration: 2,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, onMounted, toRaw } from 'vue';
|
||||
import { reactive, onMounted, toRaw, ref } from 'vue';
|
||||
import { PageContainer } from 'antdv-pro-layout';
|
||||
import { message, Modal, Form } from 'ant-design-vue/lib';
|
||||
import { SizeType } from 'ant-design-vue/lib/config-provider';
|
||||
@@ -22,8 +22,12 @@ import { updateNeConfigReload } from '@/api/configManage/configParam';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
import { FileType } from 'ant-design-vue/lib/upload/interface';
|
||||
import { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
|
||||
import TableColumnsDnd from '@/components/TableColumnsDnd/index.vue';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import { NE_TYPE_LIST } from '@/constants/ne-constants';
|
||||
import useNeInfoStore from '@/store/modules/neinfo';
|
||||
import useLockedStore from '@/store/modules/locked';
|
||||
const lockedStore = useLockedStore();
|
||||
const { t } = useI18n();
|
||||
|
||||
/**表格所需option */
|
||||
@@ -86,71 +90,74 @@ let tableColumns: ColumnsType = [
|
||||
title: t('views.configManage.neManage.neType'),
|
||||
dataIndex: 'neType',
|
||||
align: 'center',
|
||||
width: 3,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: t('views.configManage.neManage.neId'),
|
||||
dataIndex: 'neId',
|
||||
align: 'center',
|
||||
width: 3,
|
||||
},
|
||||
{
|
||||
title: t('views.configManage.neManage.uid'),
|
||||
dataIndex: 'rmUid',
|
||||
align: 'center',
|
||||
width: 5,
|
||||
},
|
||||
{
|
||||
title: t('views.configManage.neManage.neName'),
|
||||
dataIndex: 'neName',
|
||||
align: 'center',
|
||||
width: 5,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: t('views.configManage.neManage.ip'),
|
||||
dataIndex: 'ip',
|
||||
align: 'center',
|
||||
width: 5,
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: t('views.configManage.neManage.port'),
|
||||
dataIndex: 'port',
|
||||
align: 'center',
|
||||
width: 3,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: t('views.configManage.neManage.neName'),
|
||||
dataIndex: 'neName',
|
||||
align: 'center',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: t('views.configManage.neManage.uid'),
|
||||
dataIndex: 'rmUid',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: t('views.configManage.neManage.pvflag'),
|
||||
dataIndex: 'pvFlag',
|
||||
align: 'center',
|
||||
width: 5,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: t('views.configManage.neManage.province'),
|
||||
dataIndex: 'province',
|
||||
align: 'center',
|
||||
width: 5,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: t('views.configManage.neManage.vendorName'),
|
||||
dataIndex: 'vendorName',
|
||||
align: 'center',
|
||||
width: 5,
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: t('views.configManage.neManage.dn'),
|
||||
dataIndex: 'dn',
|
||||
align: 'center',
|
||||
width: 5,
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: t('common.operate'),
|
||||
key: 'id',
|
||||
align: 'center',
|
||||
fixed: 'right',
|
||||
width: 5,
|
||||
width: 150,
|
||||
},
|
||||
];
|
||||
|
||||
/**表格字段列排序 */
|
||||
let tableColumnsDnd = ref<ColumnsType>([]);
|
||||
|
||||
/**表格分页器参数 */
|
||||
let tablePagination = reactive({
|
||||
/**当前页数 */
|
||||
@@ -209,16 +216,17 @@ let modalState: ModalStateType = reactive({
|
||||
visibleByImport: false,
|
||||
title: '网元',
|
||||
from: {
|
||||
id: undefined,
|
||||
dn: '',
|
||||
ip: '',
|
||||
neAddress: '',
|
||||
neId: '',
|
||||
neName: '',
|
||||
neType: '',
|
||||
port: '',
|
||||
neType: 'AMF',
|
||||
port: '33030',
|
||||
province: '',
|
||||
pvFlag: '',
|
||||
rmUid: '',
|
||||
pvFlag: 'PNF',
|
||||
rmUid: '4400HX1AMF001',
|
||||
vendorName: '',
|
||||
sync: true,
|
||||
},
|
||||
@@ -540,6 +548,11 @@ function fnRecordRestart(row: Record<string, any>) {
|
||||
restartNf(row)
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
// OMC自升级
|
||||
if (row.neType.toLowerCase() === 'omc') {
|
||||
lockedStore.fnLock('reload');
|
||||
return;
|
||||
}
|
||||
message.success({
|
||||
content: t('common.msgSuccess', {
|
||||
msg: t('views.configManage.neManage.restart'),
|
||||
@@ -784,11 +797,12 @@ onMounted(() => {
|
||||
:label="t('views.configManage.neManage.neType')"
|
||||
name="neType "
|
||||
>
|
||||
<a-input
|
||||
<a-auto-complete
|
||||
v-model:value="queryParams.neType"
|
||||
:options="NE_TYPE_LIST.map(v => ({ value: v }))"
|
||||
allow-clear
|
||||
:placeholder="t('views.configManage.neManage.neTypePlease')"
|
||||
></a-input>
|
||||
:placeholder="t('common.inputPlease')"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="6" :md="12" :xs="24">
|
||||
@@ -838,6 +852,11 @@ onMounted(() => {
|
||||
<template #icon><ReloadOutlined /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<TableColumnsDnd
|
||||
cache-id="neManageData"
|
||||
:columns="tableColumns"
|
||||
v-model:columns-dnd="tableColumnsDnd"
|
||||
></TableColumnsDnd>
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.sizeText') }}</template>
|
||||
<a-dropdown trigger="click" placement="bottomRight">
|
||||
@@ -869,15 +888,15 @@ onMounted(() => {
|
||||
<a-table
|
||||
class="table"
|
||||
row-key="id"
|
||||
:columns="tableColumns"
|
||||
:columns="tableColumnsDnd"
|
||||
:loading="tableState.loading"
|
||||
:data-source="tableState.data"
|
||||
:size="tableState.size"
|
||||
:pagination="tablePagination"
|
||||
:scroll="{ x: 2000, y: 480 }"
|
||||
:scroll="{ y: 'calc(100vh - 480px)' }"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'id'">
|
||||
<template v-if="column?.key === 'id'">
|
||||
<a-space :size="8" align="center">
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.editText') }}</template>
|
||||
@@ -901,10 +920,7 @@ onMounted(() => {
|
||||
</a-tooltip>
|
||||
<a-tooltip placement="left">
|
||||
<template #title>{{ t('common.moreText') }}</template>
|
||||
<a-dropdown
|
||||
placement="bottomRight"
|
||||
:trigger="['hover', 'click']"
|
||||
>
|
||||
<a-dropdown placement="bottomRight" trigger="click">
|
||||
<a-button type="link">
|
||||
<template #icon><EllipsisOutlined /> </template>
|
||||
</a-button>
|
||||
@@ -918,11 +934,17 @@ onMounted(() => {
|
||||
<ImportOutlined />
|
||||
{{ t('views.configManage.neManage.import') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="start">
|
||||
<a-menu-item
|
||||
key="start"
|
||||
v-if="!['OMC'].includes(record.neType)"
|
||||
>
|
||||
<thunderbolt-outlined />
|
||||
{{ t('views.configManage.neManage.start') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="stop">
|
||||
<a-menu-item
|
||||
key="stop"
|
||||
v-if="!['OMC'].includes(record.neType)"
|
||||
>
|
||||
<pause-outlined />
|
||||
{{ t('views.configManage.neManage.stop') }}
|
||||
</a-menu-item>
|
||||
@@ -973,20 +995,21 @@ onMounted(() => {
|
||||
name="neType"
|
||||
v-bind="modalStateFrom.validateInfos.neType"
|
||||
>
|
||||
<a-input
|
||||
<a-auto-complete
|
||||
v-model:value="modalState.from.neType"
|
||||
allow-clear
|
||||
:placeholder="t('views.configManage.neManage.neTypePlease')"
|
||||
:options="NE_TYPE_LIST.map(v => ({ value: v }))"
|
||||
>
|
||||
<template #prefix>
|
||||
<a-tooltip placement="topLeft">
|
||||
<template #title>{{
|
||||
t('views.configManage.neManage.neTypeTip')
|
||||
}}</template>
|
||||
<InfoCircleOutlined style="color: rgba(0, 0, 0, 0.45)" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-input>
|
||||
<a-input allow-clear :placeholder="t('common.inputPlease')">
|
||||
<template #prefix>
|
||||
<a-tooltip placement="topLeft">
|
||||
<template #title>{{
|
||||
t('views.configManage.neManage.neTypeTip')
|
||||
}}</template>
|
||||
<InfoCircleOutlined style="color: rgba(0, 0, 0, 0.45)" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-auto-complete>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
@@ -1134,7 +1157,7 @@ onMounted(() => {
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.configManage.neManage.sync')"
|
||||
name="province"
|
||||
name="sync"
|
||||
>
|
||||
<a-switch
|
||||
v-model:checked="modalState.from.sync"
|
||||
|
||||
@@ -82,7 +82,7 @@ let tableColumns: ColumnsType = [
|
||||
},
|
||||
{
|
||||
title: t('views.configManage.softwareManage.fileName'),
|
||||
dataIndex: 'fileName',
|
||||
dataIndex: 'name',
|
||||
align: 'center',
|
||||
width: 2,
|
||||
},
|
||||
@@ -94,7 +94,7 @@ let tableColumns: ColumnsType = [
|
||||
},
|
||||
{
|
||||
title: t('views.configManage.softwareManage.updateTime'),
|
||||
dataIndex: 'updateTime',
|
||||
dataIndex: 'createTime',
|
||||
align: 'center',
|
||||
customRender(opt) {
|
||||
if (!opt.value) return '';
|
||||
@@ -104,7 +104,7 @@ let tableColumns: ColumnsType = [
|
||||
},
|
||||
{
|
||||
title: t('views.configManage.softwareManage.description'),
|
||||
dataIndex: 'comment',
|
||||
dataIndex: 'name',
|
||||
align: 'center',
|
||||
width: 2,
|
||||
},
|
||||
@@ -274,6 +274,7 @@ function fnFileModalVisible(type: string | number, row: Record<string, any>) {
|
||||
* 进行表达规则校验
|
||||
*/
|
||||
function fnFileModalOk() {
|
||||
if (fileModalState.confirmLoading) return;
|
||||
fileModalStateFrom
|
||||
.validate()
|
||||
.then(e => {
|
||||
@@ -730,13 +731,15 @@ onMounted(() => {
|
||||
}
|
||||
} else {
|
||||
message.warning({
|
||||
content: t('views.configManage.softwareManage.nullData'),
|
||||
content: t('common.noData'),
|
||||
duration: 2,
|
||||
});
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
// 获取列表数据
|
||||
fnGetList();
|
||||
});
|
||||
// 获取列表数据
|
||||
fnGetList();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -889,10 +892,7 @@ onMounted(() => {
|
||||
</a-tooltip>
|
||||
<a-tooltip placement="left">
|
||||
<template #title>{{ t('common.moreText') }}</template>
|
||||
<a-dropdown
|
||||
placement="bottomRight"
|
||||
:trigger="['hover', 'click']"
|
||||
>
|
||||
<a-dropdown placement="bottomRight" trigger="click">
|
||||
<a-button type="link">
|
||||
<template #icon><EllipsisOutlined /> </template>
|
||||
</a-button>
|
||||
|
||||
659
src/views/dashboard/amfUE/index.vue
Normal file
659
src/views/dashboard/amfUE/index.vue
Normal file
@@ -0,0 +1,659 @@
|
||||
<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 useI18n from '@/hooks/useI18n';
|
||||
import {
|
||||
RESULT_CODE_ERROR,
|
||||
RESULT_CODE_SUCCESS,
|
||||
} from '@/constants/result-constants';
|
||||
import useDictStore from '@/store/modules/dict';
|
||||
import { listAMFDataUE, delAMFDataUE } from '@/api/neData/amf';
|
||||
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||
import PQueue from 'p-queue';
|
||||
const { t } = useI18n();
|
||||
const { getDict } = useDictStore();
|
||||
const ws = new WS();
|
||||
const queue = new PQueue({ concurrency: 1, autoStart: true });
|
||||
|
||||
/**字典数据 */
|
||||
let dict: {
|
||||
/**UE 事件认证代码类型 */
|
||||
ueAauthCode: DictType[];
|
||||
/**UE 事件类型 */
|
||||
ueEventType: DictType[];
|
||||
/**UE 事件CM状态 */
|
||||
ueEventCmState: DictType[];
|
||||
} = reactive({
|
||||
ueAauthCode: [],
|
||||
ueEventType: [],
|
||||
ueEventCmState: [],
|
||||
});
|
||||
|
||||
/**查询参数 */
|
||||
let queryParams = reactive({
|
||||
/**网元类型 */
|
||||
neType: 'AMF',
|
||||
neId: '001',
|
||||
eventType: 'auth-result',
|
||||
imsi: '',
|
||||
sortField: 'timestamp',
|
||||
sortOrder: 'desc',
|
||||
/**当前页数 */
|
||||
pageNum: 1,
|
||||
/**每页条数 */
|
||||
pageSize: 20,
|
||||
});
|
||||
|
||||
/**查询参数重置 */
|
||||
function fnQueryReset() {
|
||||
eventTypes.value = ['auth-result'];
|
||||
queryParams = Object.assign(queryParams, {
|
||||
eventType: 'auth-result',
|
||||
imsi: '',
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
});
|
||||
tablePagination.current = 1;
|
||||
tablePagination.pageSize = 20;
|
||||
fnGetList();
|
||||
}
|
||||
|
||||
/**记录类型 */
|
||||
const eventTypes = ref<string[]>(['auth-result']);
|
||||
|
||||
/**查询记录类型变更 */
|
||||
function fnQueryEventTypeChange(value: any) {
|
||||
if (Array.isArray(value)) {
|
||||
queryParams.eventType = 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: 'IMSI',
|
||||
dataIndex: 'eventJSON',
|
||||
align: 'left',
|
||||
width: 150,
|
||||
customRender(opt) {
|
||||
const eventJSON = opt.value;
|
||||
return eventJSON.imsi;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.ue.eventType'),
|
||||
dataIndex: 'eventType',
|
||||
key: 'eventType',
|
||||
align: 'left',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.ue.result'),
|
||||
dataIndex: 'eventJSON',
|
||||
key: 'result',
|
||||
align: 'left',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.ue.time'),
|
||||
dataIndex: 'eventJSON',
|
||||
key: 'time',
|
||||
align: 'left',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
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.ue.delTip', { msg }),
|
||||
onOk() {
|
||||
modalState.confirmLoading = true;
|
||||
const hide = message.loading(t('common.loading'), 0);
|
||||
delAMFDataUE(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;
|
||||
}
|
||||
listAMFDataUE(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 eventJSON = item.eventJSON;
|
||||
if (!eventJSON) {
|
||||
Reflect.set(item, 'eventJSON', {});
|
||||
}
|
||||
|
||||
try {
|
||||
eventJSON = JSON.parse(eventJSON);
|
||||
Reflect.set(item, 'eventJSON', eventJSON);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Reflect.set(item, 'eventJSON', {});
|
||||
}
|
||||
|
||||
return item;
|
||||
});
|
||||
|
||||
// 取最大值ID用作实时累加
|
||||
if (res.total > 0) {
|
||||
modalState.maxId = Number(res.rows[0].id);
|
||||
}
|
||||
}
|
||||
tableState.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
/**实时数据开关 */
|
||||
const realTimeData = ref<boolean>(false);
|
||||
|
||||
/**
|
||||
* 实时数据
|
||||
*/
|
||||
function fnRealTime() {
|
||||
realTimeData.value = !realTimeData.value;
|
||||
if (realTimeData.value) {
|
||||
// 建立链接
|
||||
const options: OptionsType = {
|
||||
url: '/ws',
|
||||
params: {
|
||||
/**订阅通道组
|
||||
*
|
||||
* UE会话事件-AMF (GroupID:1010)
|
||||
*/
|
||||
subGroupID: '1010',
|
||||
},
|
||||
onmessage: wsMessage,
|
||||
onerror: wsError,
|
||||
};
|
||||
ws.connect(options);
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
// ueEvent CDR会话事件
|
||||
if (data.groupId === '1010') {
|
||||
const ueEvent = data.data;
|
||||
queue.add(async () => {
|
||||
modalState.maxId += 1;
|
||||
tableState.data.unshift({
|
||||
id: modalState.maxId,
|
||||
neType: ueEvent.neType,
|
||||
neName: ueEvent.neName, // 空
|
||||
rmUID: ueEvent.rmUID, // 空
|
||||
timestamp: ueEvent.timestamp,
|
||||
eventType: ueEvent.eventType,
|
||||
eventJSON: ueEvent.eventJSON,
|
||||
});
|
||||
tablePagination.total += 1;
|
||||
if (tableState.data.length > 100) {
|
||||
tableState.data.pop();
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 800));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 初始字典数据
|
||||
Promise.allSettled([
|
||||
getDict('ue_auth_code'),
|
||||
getDict('ue_event_type'),
|
||||
getDict('ue_event_cm_state'),
|
||||
])
|
||||
.then(resArr => {
|
||||
if (resArr[0].status === 'fulfilled') {
|
||||
dict.ueAauthCode = resArr[0].value;
|
||||
}
|
||||
if (resArr[1].status === 'fulfilled') {
|
||||
dict.ueEventType = resArr[1].value;
|
||||
}
|
||||
if (resArr[2].status === 'fulfilled') {
|
||||
dict.ueEventCmState = resArr[2].value;
|
||||
}
|
||||
})
|
||||
.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="t('views.dashboard.ue.eventType')"
|
||||
name="eventType "
|
||||
>
|
||||
<a-select
|
||||
v-model:value="eventTypes"
|
||||
mode="multiple"
|
||||
:options="dict.ueEventType"
|
||||
:placeholder="t('common.selectPlease')"
|
||||
@change="fnQueryEventTypeChange"
|
||||
></a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="6" :md="12" :xs="24">
|
||||
<a-form-item label="IMSI" name="imsi ">
|
||||
<a-input
|
||||
v-model:value="queryParams.imsi"
|
||||
allow-clear
|
||||
: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-popconfirm
|
||||
placement="bottomLeft"
|
||||
:title="
|
||||
!realTimeData
|
||||
? t('views.dashboard.ue.realTimeDataStart')
|
||||
: t('views.dashboard.ue.realTimeDataStop')
|
||||
"
|
||||
ok-text="Yes"
|
||||
cancel-text="No"
|
||||
@confirm="fnRealTime()"
|
||||
>
|
||||
<a-button type="primary" :danger="realTimeData">
|
||||
<template #icon><FundOutlined /> </template>
|
||||
{{
|
||||
!realTimeData
|
||||
? t('views.dashboard.ue.realTimeDataStart')
|
||||
: t('views.dashboard.ue.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-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>
|
||||
<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 * 120, y: 'calc(100vh - 480px)' }"
|
||||
:row-selection="{
|
||||
type: 'checkbox',
|
||||
columnWidth: '48px',
|
||||
selectedRowKeys: tableState.selectedRowKeys,
|
||||
onChange: fnTableSelectedRowKeys,
|
||||
}"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'eventType'">
|
||||
<DictTag :options="dict.ueEventType" :value="record.eventType" />
|
||||
</template>
|
||||
<template v-if="column.key === 'result'">
|
||||
<span v-if="record.eventType === 'auth-result'">
|
||||
<DictTag
|
||||
:options="dict.ueAauthCode"
|
||||
:value="record.eventJSON.authCode"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
v-if="record.eventType === 'detach'"
|
||||
:title="record.eventJSON.detachTime"
|
||||
>
|
||||
<span>{{ t('views.dashboard.ue.resultOk') }}</span>
|
||||
</span>
|
||||
<span v-if="record.eventType === 'cm-state'">
|
||||
<DictTag
|
||||
:options="dict.ueEventCmState"
|
||||
:value="record.eventJSON.status"
|
||||
/>
|
||||
</span>
|
||||
</template>
|
||||
<template v-if="column.key === 'time'">
|
||||
<span
|
||||
v-if="record.eventType === 'auth-result'"
|
||||
:title="record.eventJSON.authTime"
|
||||
>
|
||||
{{ record.eventJSON.authTime }}
|
||||
</span>
|
||||
<span
|
||||
v-if="record.eventType === 'detach'"
|
||||
:title="record.eventJSON.detachTime"
|
||||
>
|
||||
{{ record.eventJSON.detachTime }}
|
||||
</span>
|
||||
<span
|
||||
v-if="record.eventType === 'cm-state'"
|
||||
:title="record.eventJSON.changeTime"
|
||||
>
|
||||
{{ record.eventJSON.changeTime }}
|
||||
</span>
|
||||
</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.ue.ueInfo') }}
|
||||
</a-divider>
|
||||
<div>
|
||||
<span>{{ t('views.dashboard.ue.neName') }}: </span>
|
||||
<span>{{ record.neName }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('views.dashboard.ue.rmUID') }}: </span>
|
||||
<span>{{ record.rmUID }}</span>
|
||||
</div>
|
||||
<a-divider orientation="left">
|
||||
{{ t('views.dashboard.ue.rowInfo') }}
|
||||
</a-divider>
|
||||
<div>
|
||||
<span>{{ t('views.dashboard.ue.time') }}: </span>
|
||||
<span
|
||||
v-if="record.eventType === 'auth-result'"
|
||||
:title="record.eventJSON.authTime"
|
||||
>
|
||||
{{ record.eventJSON.authTime }}
|
||||
</span>
|
||||
<span
|
||||
v-if="record.eventType === 'detach'"
|
||||
:title="record.eventJSON.detachTime"
|
||||
>
|
||||
{{ record.eventJSON.detachTime }}
|
||||
</span>
|
||||
<span
|
||||
v-if="record.eventType === 'cm-state'"
|
||||
:title="record.eventJSON.changeTime"
|
||||
>
|
||||
{{ record.eventJSON.changeTime }}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('views.dashboard.ue.eventType') }}: </span>
|
||||
<DictTag :options="dict.ueEventType" :value="record.eventType" />
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('views.dashboard.ue.result') }}: </span>
|
||||
<span v-if="record.eventType === 'auth-result'">
|
||||
<DictTag
|
||||
:options="dict.ueAauthCode"
|
||||
:value="record.eventJSON.authCode"
|
||||
/>
|
||||
</span>
|
||||
<span v-if="record.eventType === 'detach'">
|
||||
{{ t('views.dashboard.ue.resultOK') }}
|
||||
</span>
|
||||
<span v-if="record.eventType === 'cm-state'">
|
||||
<DictTag
|
||||
:options="dict.ueEventCmState"
|
||||
:value="record.eventJSON.status"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
</PageContainer>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.table :deep(.ant-pagination) {
|
||||
padding: 0 24px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,53 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, onMounted, onBeforeUnmount } from 'vue';
|
||||
import {
|
||||
listCacheName,
|
||||
listCacheKey,
|
||||
getCacheValue,
|
||||
clearCacheName,
|
||||
clearCacheKey,
|
||||
clearCacheSafe,
|
||||
} from '@/api/monitor/cache';
|
||||
import { PageContainer } from 'antdv-pro-layout';
|
||||
import { ColumnsType } from 'ant-design-vue/lib/table/Table';
|
||||
import { message } from 'ant-design-vue/lib';
|
||||
import { hasPermissions } from '@/plugins/auth-user';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import { WS, OptionsType } from '@/plugins/ws-websocket';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
const { t } = useI18n();
|
||||
|
||||
const ws = new WS();
|
||||
|
||||
onMounted(() => {
|
||||
const options: OptionsType = {
|
||||
url: '/ws',
|
||||
params: {
|
||||
subGroupID: '1005',
|
||||
},
|
||||
onmessage: ev => {
|
||||
// 接收数据后回调
|
||||
console.log(ev);
|
||||
},
|
||||
onerror: (ev: any) => {
|
||||
// 接收数据后回调
|
||||
console.log(ev);
|
||||
},
|
||||
};
|
||||
ws.connect(options);
|
||||
|
||||
setInterval(() => {
|
||||
ws.send({ a: 1 });
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
ws.close();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
677
src/views/dashboard/imsCDR/index.vue
Normal file
677
src/views/dashboard/imsCDR/index.vue
Normal file
@@ -0,0 +1,677 @@
|
||||
<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 useI18n from '@/hooks/useI18n';
|
||||
import {
|
||||
RESULT_CODE_ERROR,
|
||||
RESULT_CODE_SUCCESS,
|
||||
} from '@/constants/result-constants';
|
||||
import useDictStore from '@/store/modules/dict';
|
||||
import { delIMSDataCDR, listIMSDataCDR } from '@/api/neData/ims';
|
||||
import { parseDateToStr, parseDuration } from '@/utils/date-utils';
|
||||
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||
import PQueue from 'p-queue';
|
||||
const { t } = useI18n();
|
||||
const { getDict } = useDictStore();
|
||||
const ws = new WS();
|
||||
const queue = new PQueue({ concurrency: 1, autoStart: true });
|
||||
|
||||
/**字典数据 */
|
||||
let dict: {
|
||||
/**CDR SIP响应代码类别类型 */
|
||||
cdrSipCode: DictType[];
|
||||
/**CDR 呼叫类型 */
|
||||
cdrCallType: DictType[];
|
||||
} = reactive({
|
||||
cdrSipCode: [],
|
||||
cdrCallType: [],
|
||||
});
|
||||
|
||||
/**查询参数 */
|
||||
let queryParams = reactive({
|
||||
/**网元类型 */
|
||||
neType: 'IMS',
|
||||
neId: '001',
|
||||
recordType: 'MOC',
|
||||
callerParty: '',
|
||||
calledParty: '',
|
||||
sortField: 'timestamp',
|
||||
sortOrder: 'desc',
|
||||
/**当前页数 */
|
||||
pageNum: 1,
|
||||
/**每页条数 */
|
||||
pageSize: 20,
|
||||
});
|
||||
|
||||
/**查询参数重置 */
|
||||
function fnQueryReset() {
|
||||
recordTypes.value = ['MOC'];
|
||||
queryParams = Object.assign(queryParams, {
|
||||
recordType: 'MOC',
|
||||
callerParty: '',
|
||||
calledParty: '',
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
});
|
||||
tablePagination.current = 1;
|
||||
tablePagination.pageSize = 20;
|
||||
fnGetList();
|
||||
}
|
||||
|
||||
/**记录类型 */
|
||||
const recordTypes = ref<string[]>(['MOC']);
|
||||
|
||||
/**查询记录类型变更 */
|
||||
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',
|
||||
key: 'callType',
|
||||
align: 'left',
|
||||
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'),
|
||||
dataIndex: 'cdrJSON',
|
||||
key: 'callerParty',
|
||||
align: 'left',
|
||||
width: 120,
|
||||
customRender(opt) {
|
||||
const cdrJSON = opt.value;
|
||||
return cdrJSON.callerParty;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.duration'),
|
||||
dataIndex: 'cdrJSON',
|
||||
key: 'callDuration',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
customRender(opt) {
|
||||
const cdrJSON = opt.value;
|
||||
return cdrJSON.callType === 'sms'
|
||||
? '-'
|
||||
: parseDuration(cdrJSON.callDuration);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.result'),
|
||||
dataIndex: 'cdrJSON',
|
||||
key: 'cause',
|
||||
align: 'left',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.time'),
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'center',
|
||||
width: 150,
|
||||
customRender(opt) {
|
||||
const cdrJSON = opt.value;
|
||||
return parseDateToStr(+cdrJSON.releaseTime * 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);
|
||||
delIMSDataCDR(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;
|
||||
}
|
||||
listIMSDataCDR(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;
|
||||
});
|
||||
}
|
||||
|
||||
/**实时数据开关 */
|
||||
const realTimeData = ref<boolean>(false);
|
||||
|
||||
/**
|
||||
* 实时数据
|
||||
*/
|
||||
function fnRealTime() {
|
||||
realTimeData.value = !realTimeData.value;
|
||||
if (realTimeData.value) {
|
||||
// 建立链接
|
||||
const options: OptionsType = {
|
||||
url: '/ws',
|
||||
params: {
|
||||
/**订阅通道组
|
||||
*
|
||||
* CDR会话事件-IMS (GroupID:1005)
|
||||
*/
|
||||
subGroupID: '1005',
|
||||
},
|
||||
onmessage: wsMessage,
|
||||
onerror: wsError,
|
||||
};
|
||||
ws.connect(options);
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
// cdrEvent CDR会话事件
|
||||
if (data.groupId === '1005') {
|
||||
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_sip_code'), getDict('cdr_call_type')])
|
||||
.then(resArr => {
|
||||
if (resArr[0].status === 'fulfilled') {
|
||||
dict.cdrSipCode = resArr[0].value;
|
||||
}
|
||||
if (resArr[1].status === 'fulfilled') {
|
||||
dict.cdrCallType = resArr[1].value;
|
||||
}
|
||||
})
|
||||
.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="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="
|
||||
['MOC', 'MTC', 'MOSM', 'MTSM'].map(v => ({ value: v }))
|
||||
"
|
||||
:placeholder="t('common.selectPlease')"
|
||||
@change="fnQueryRecordTypeChange"
|
||||
></a-select>
|
||||
</a-form-item>
|
||||
</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="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-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-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>
|
||||
<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 * 120, y: 'calc(100vh - 480px)' }"
|
||||
:row-selection="{
|
||||
type: 'checkbox',
|
||||
columnWidth: '48px',
|
||||
selectedRowKeys: tableState.selectedRowKeys,
|
||||
onChange: fnTableSelectedRowKeys,
|
||||
}"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'callType'">
|
||||
<DictTag
|
||||
:options="dict.cdrCallType"
|
||||
:value="record.cdrJSON.callType"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="column.key === 'cause'">
|
||||
<span v-if="record.cdrJSON.callType !== 'sms'">
|
||||
<DictTag
|
||||
:options="dict.cdrSipCode"
|
||||
:value="record.cdrJSON.cause"
|
||||
value-option="0"
|
||||
/>
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ t('views.dashboard.overview.userActivity.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.dashboard.cdr.neName') }}: </span>
|
||||
<span>{{ record.neName }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('views.dashboard.cdr.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>
|
||||
<DictTag
|
||||
:options="dict.cdrCallType"
|
||||
:value="record.cdrJSON.callType"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('views.dashboard.cdr.duration') }}: </span>
|
||||
<span v-if="record.cdrJSON.callType !== 'sms'">
|
||||
{{ parseDuration(record.cdrJSON.callDuration) }}
|
||||
</span>
|
||||
<span v-else> - </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.callType !== 'sms'">
|
||||
<DictTag
|
||||
:options="dict.cdrSipCode"
|
||||
:value="record.cdrJSON.cause"
|
||||
value-option="0"
|
||||
/>
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ t('views.dashboard.overview.userActivity.resultOK') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
</PageContainer>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.table :deep(.ant-pagination) {
|
||||
padding: 0 24px;
|
||||
}
|
||||
</style>
|
||||
202
src/views/dashboard/mocn/components/AlarnTypeBar/index.vue
Normal file
202
src/views/dashboard/mocn/components/AlarnTypeBar/index.vue
Normal file
@@ -0,0 +1,202 @@
|
||||
<script setup lang="ts">
|
||||
import * as echarts from 'echarts/core';
|
||||
import {
|
||||
TitleComponent,
|
||||
TitleComponentOption,
|
||||
TooltipComponent,
|
||||
TooltipComponentOption,
|
||||
GridComponent,
|
||||
GridComponentOption,
|
||||
LegendComponent,
|
||||
LegendComponentOption,
|
||||
} from 'echarts/components';
|
||||
import {
|
||||
PieChart,
|
||||
PieSeriesOption,
|
||||
BarChart,
|
||||
BarSeriesOption,
|
||||
} from 'echarts/charts';
|
||||
import { LabelLayout } from 'echarts/features';
|
||||
import { CanvasRenderer } from 'echarts/renderers';
|
||||
|
||||
import { markRaw, onMounted, ref } from 'vue';
|
||||
import { origGet, top3Sel } from '@/api/faultManage/actAlarm';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
echarts.use([
|
||||
TitleComponent,
|
||||
TooltipComponent,
|
||||
GridComponent,
|
||||
LegendComponent,
|
||||
PieChart,
|
||||
BarChart,
|
||||
CanvasRenderer,
|
||||
LabelLayout,
|
||||
]);
|
||||
|
||||
type EChartsOption = echarts.ComposeOption<
|
||||
| TitleComponentOption
|
||||
| TooltipComponentOption
|
||||
| GridComponentOption
|
||||
| LegendComponentOption
|
||||
| PieSeriesOption
|
||||
| BarSeriesOption
|
||||
>;
|
||||
|
||||
/**图DOM节点实例对象 */
|
||||
const alarmTypeBar = ref<HTMLElement | undefined>(undefined);
|
||||
|
||||
/**图实例对象 */
|
||||
const alarmTypeBarChart = ref<any>(null);
|
||||
|
||||
/**告警类型数据 */
|
||||
const alarmTypeType = ref<any>([
|
||||
{
|
||||
value: 0,
|
||||
name: t('views.index.Critical'),
|
||||
},
|
||||
{
|
||||
value: 0,
|
||||
name: t('views.index.Major'),
|
||||
},
|
||||
{
|
||||
value: 0,
|
||||
name: t('views.index.Minor'),
|
||||
},
|
||||
{
|
||||
value: 0,
|
||||
name: t('views.index.Warning'),
|
||||
},
|
||||
{
|
||||
value: 0,
|
||||
name: t('views.index.Event'),
|
||||
},
|
||||
]);
|
||||
|
||||
//
|
||||
function initPicture() {
|
||||
Promise.allSettled([origGet()])
|
||||
.then(resArr => {
|
||||
if (resArr[0].status === 'fulfilled') {
|
||||
const res0 = resArr[0].value;
|
||||
if (res0.code === RESULT_CODE_SUCCESS && Array.isArray(res0.data)) {
|
||||
for (const item of res0.data) {
|
||||
let index = 0;
|
||||
switch (item.name) {
|
||||
case 'Critical':
|
||||
index = 0;
|
||||
break;
|
||||
case 'Major':
|
||||
index = 1;
|
||||
break;
|
||||
case 'Minor':
|
||||
index = 2;
|
||||
break;
|
||||
case 'Warning':
|
||||
index = 3;
|
||||
break;
|
||||
case 'Event':
|
||||
index = 4;
|
||||
break;
|
||||
}
|
||||
alarmTypeType.value[index].value = Number(item.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
const optionData: EChartsOption = {
|
||||
title: [
|
||||
{
|
||||
show: false,
|
||||
},
|
||||
],
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{b} : {c}',
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
right: '2%',
|
||||
top: '10%',
|
||||
data: alarmTypeType.value.map((item: any) => item.name), //label数组
|
||||
textStyle: {
|
||||
color: '#A7D6F4', // 设置图例文字颜色
|
||||
},
|
||||
},
|
||||
grid: [
|
||||
{
|
||||
top: '60%',
|
||||
left: '15%',
|
||||
right: '25%',
|
||||
bottom: '10%',
|
||||
},
|
||||
],
|
||||
series: [
|
||||
//饼图:
|
||||
{
|
||||
type: 'pie',
|
||||
radius: '60%',
|
||||
color: ['#f5222d', '#fa8c16', '#fadb14', '#1677ff', '#13c2c2'],
|
||||
label: {
|
||||
show: true,
|
||||
position: 'inner',
|
||||
formatter: (params: any) => {
|
||||
if (!params.value) return '';
|
||||
return `${params.value}`;
|
||||
},
|
||||
},
|
||||
labelLine: {
|
||||
show: false,
|
||||
},
|
||||
center: ['30%', '40%'],
|
||||
data: alarmTypeType.value,
|
||||
zlevel: 2, // 设置zlevel为1,使得柱状图在下层显示
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
fnDesign(alarmTypeBar.value, optionData);
|
||||
});
|
||||
}
|
||||
|
||||
function fnDesign(container: HTMLElement | undefined, option: any) {
|
||||
if (!container) return;
|
||||
|
||||
alarmTypeBarChart.value = markRaw(echarts.init(container, 'light'));
|
||||
option && alarmTypeBarChart.value.setOption(option);
|
||||
|
||||
// 创建 ResizeObserver 实例
|
||||
var observer = new ResizeObserver(entries => {
|
||||
if (alarmTypeBarChart.value) {
|
||||
alarmTypeBarChart.value.resize();
|
||||
}
|
||||
});
|
||||
// 监听元素大小变化
|
||||
observer.observe(container);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initPicture();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="alarmTypeBar" class="chart-container"></div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.chart-container {
|
||||
/* 设置图表容器大小和位置 */
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
90
src/views/dashboard/mocn/components/setting.vue
Normal file
90
src/views/dashboard/mocn/components/setting.vue
Normal file
@@ -0,0 +1,90 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, toRaw, watch } from 'vue';
|
||||
import { dbGetJSON, dbSetJSON } from '@/utils/cache-db-utils';
|
||||
const emit = defineEmits(['ok', 'cancel', 'update:visible']);
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: '标题',
|
||||
},
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
/**数据参数 */
|
||||
let dataState = reactive({
|
||||
/**基站数 */
|
||||
baseNum: 0,
|
||||
/**核心网数 */
|
||||
coreNetNum: 0,
|
||||
/**在线用户数 */
|
||||
onlineUserNum: 0,
|
||||
});
|
||||
|
||||
/**弹框取消按钮事件 */
|
||||
function fnModalOk() {
|
||||
dbSetJSON('tbl_mocn', `tmp`, toRaw(dataState));
|
||||
emit('ok');
|
||||
emit('update:visible', false);
|
||||
}
|
||||
|
||||
/**弹框取消按钮事件 */
|
||||
function fnModalCancel() {
|
||||
emit('cancel');
|
||||
emit('update:visible', false);
|
||||
}
|
||||
|
||||
/**显示弹框时初始数据 */
|
||||
function init() {
|
||||
// 读取数据
|
||||
dbGetJSON('tbl_mocn', `tmp`).then(data => {
|
||||
if (data) {
|
||||
Object.assign(dataState, data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**监听是否显示,初始数据 */
|
||||
watch(
|
||||
() => props.visible,
|
||||
val => {
|
||||
if (val) init();
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<a-modal
|
||||
width="800px"
|
||||
:title="props.title"
|
||||
:visible="props.visible"
|
||||
:keyboard="false"
|
||||
:mask-closable="false"
|
||||
@cancel="fnModalCancel"
|
||||
@ok="fnModalOk"
|
||||
>
|
||||
<a-form
|
||||
name="dataState"
|
||||
layout="horizontal"
|
||||
:label-col="{ span: 6 }"
|
||||
:labelWrap="true"
|
||||
>
|
||||
<a-form-item label="baseNum" name="baseNum">
|
||||
<a-input-number v-model:value="dataState.baseNum"> </a-input-number>
|
||||
</a-form-item>
|
||||
<a-form-item label="coreNetNum" name="coreNetNum">
|
||||
<a-input-number v-model:value="dataState.coreNetNum"> </a-input-number>
|
||||
</a-form-item>
|
||||
<a-form-item label="onlineUserNum" name="onlineUserNum">
|
||||
<a-input-number v-model:value="dataState.onlineUserNum">
|
||||
</a-input-number>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
567
src/views/dashboard/mocn/index.vue
Normal file
567
src/views/dashboard/mocn/index.vue
Normal file
@@ -0,0 +1,567 @@
|
||||
<script setup lang="ts">
|
||||
import { onBeforeUnmount, onMounted, reactive, ref } from 'vue';
|
||||
import svgBase from '@/assets/svg/base.svg';
|
||||
import svgUserIMS from '@/assets/svg/userIMS.svg';
|
||||
import svgUserSMF from '@/assets/svg/userSMF.svg';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
import Topology from '../overview/components/Topology/index.vue';
|
||||
import NeResources from '../overview/components/NeResources/index.vue';
|
||||
import UserActivity from '../overview/components/UserActivity/index.vue';
|
||||
import AlarnTypeBar from './components/AlarnTypeBar/index.vue';
|
||||
import setting from './components/setting.vue';
|
||||
import UPFFlow from '../overview/components/UPFFlow/index.vue';
|
||||
import { listSub } from '@/api/neUser/sub';
|
||||
import { listUENumBySMF } from '@/api/neUser/smf';
|
||||
import { listUENumByIMS } from '@/api/neUser/ims';
|
||||
import { listBase5G } from '@/api/neUser/base5G';
|
||||
import {
|
||||
graphNodeClickID,
|
||||
graphState,
|
||||
notNeNodes,
|
||||
graphNodeStateNum,
|
||||
neStateRequestMap,
|
||||
} from '../overview/hooks/useTopology';
|
||||
import { upfTotalFlow, upfTFActive } from '../overview/hooks/useUPFTotalFlow';
|
||||
import { useFullscreen } from '@vueuse/core';
|
||||
import useWS from '../overview/hooks/useWS';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { dbGetJSON } from '@/utils/cache-db-utils';
|
||||
const router = useRouter();
|
||||
const appStore = useAppStore();
|
||||
const { t } = useI18n();
|
||||
const { wsSend, cdrEventSend, ueEventSend, upfTFSend } = useWS();
|
||||
|
||||
/**概览状态类型 */
|
||||
type SkimStateType = {
|
||||
/**UDM签约用户数量 */
|
||||
udmSubNum: number;
|
||||
/**SMF在线用户数 */
|
||||
smfUeNum: number;
|
||||
/**IMS在线用户数 */
|
||||
imsUeNum: number;
|
||||
/**5G基站数量 */
|
||||
gnbNum: number;
|
||||
/**5G在线用户数量 */
|
||||
gnbUeNum: number;
|
||||
/**4G基站数量 */
|
||||
enbNum: number;
|
||||
/**4G在线用户数量 */
|
||||
enbUeNum: number;
|
||||
};
|
||||
|
||||
/**概览状态信息 */
|
||||
let skimState: SkimStateType = reactive({
|
||||
udmSubNum: 0,
|
||||
smfUeNum: 0,
|
||||
imsUeNum: 0,
|
||||
gnbNum: 0,
|
||||
gnbUeNum: 0,
|
||||
enbNum: 0,
|
||||
enbUeNum: 0,
|
||||
});
|
||||
|
||||
/**总览节点 */
|
||||
const viewportDom = ref<HTMLElement | null>(null);
|
||||
const { isFullscreen, toggle } = useFullscreen(viewportDom);
|
||||
|
||||
/**10s调度器 */
|
||||
const interval10s = ref<any>(null);
|
||||
|
||||
/**5s调度器 */
|
||||
const interval5s = ref<any>(null);
|
||||
|
||||
/**查询网元状态 */
|
||||
function fnGetNeState() {
|
||||
// 获取节点状态
|
||||
for (const node of graphState.data.nodes) {
|
||||
if (notNeNodes.includes(node.id)) continue;
|
||||
const { neType, neId } = node.neInfo;
|
||||
if (!neType || !neId) continue;
|
||||
// 请求标记检查避免重复发送
|
||||
if (neStateRequestMap.value.get(neType)) continue;
|
||||
neStateRequestMap.value.set(neType, true);
|
||||
|
||||
wsSend({
|
||||
requestId: `neState_${neType}_${neId}`,
|
||||
type: 'ne_state',
|
||||
data: {
|
||||
neType: neType,
|
||||
neId: neId,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**获取概览信息 */
|
||||
async function fnGetSkim() {
|
||||
const resArr = await Promise.allSettled([
|
||||
listSub({
|
||||
neid: '001',
|
||||
pageNum: 1,
|
||||
pageSize: 1,
|
||||
}),
|
||||
listUENumBySMF('001'),
|
||||
listUENumByIMS('001'),
|
||||
listBase5G({
|
||||
neType: 'AMF',
|
||||
neId: '001',
|
||||
}),
|
||||
listBase5G({
|
||||
neType: 'MME',
|
||||
neId: '001',
|
||||
}),
|
||||
]);
|
||||
|
||||
if (resArr[0].status === 'fulfilled') {
|
||||
const res0 = resArr[0].value;
|
||||
if (res0.code === RESULT_CODE_SUCCESS) {
|
||||
skimState.udmSubNum = res0.total;
|
||||
}
|
||||
}
|
||||
if (resArr[1].status === 'fulfilled') {
|
||||
const res1 = resArr[1].value;
|
||||
if (res1.code === RESULT_CODE_SUCCESS) {
|
||||
skimState.smfUeNum = res1.data;
|
||||
}
|
||||
}
|
||||
if (resArr[2].status === 'fulfilled') {
|
||||
const res2 = resArr[2].value;
|
||||
if (res2.code === RESULT_CODE_SUCCESS) {
|
||||
skimState.imsUeNum = res2.data;
|
||||
}
|
||||
}
|
||||
if (resArr[3].status === 'fulfilled') {
|
||||
const res3 = resArr[3].value;
|
||||
if (res3.code === RESULT_CODE_SUCCESS) {
|
||||
skimState.gnbNum = res3.total;
|
||||
skimState.gnbUeNum = 0;
|
||||
res3.rows.map((item: any) => {
|
||||
skimState.gnbUeNum += item.ueNum;
|
||||
});
|
||||
}
|
||||
}
|
||||
if (resArr[4].status === 'fulfilled') {
|
||||
const res4 = resArr[4].value;
|
||||
if (res4.code === RESULT_CODE_SUCCESS) {
|
||||
skimState.enbNum = res4.total;
|
||||
skimState.enbUeNum = 0;
|
||||
res4.rows.map((item: any) => {
|
||||
skimState.enbUeNum += item.ueNum;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**初始数据函数 */
|
||||
function loadData() {
|
||||
fnGetNeState(); // 获取网元状态
|
||||
cdrEventSend();
|
||||
ueEventSend();
|
||||
upfTFSend(0);
|
||||
upfTFSend(7);
|
||||
upfTFSend(30);
|
||||
|
||||
interval10s.value = setInterval(() => {
|
||||
upfTFActive.value = upfTFActive.value >= 2 ? 0 : upfTFActive.value + 1;
|
||||
if (upfTFActive.value === 0) {
|
||||
upfTFSend(7);
|
||||
} else if (upfTFActive.value === 1) {
|
||||
upfTFSend(30);
|
||||
} else if (upfTFActive.value === 2) {
|
||||
upfTFSend(0);
|
||||
}
|
||||
}, 10_000);
|
||||
|
||||
interval5s.value = setInterval(() => {
|
||||
fnGetSkim(); // 获取概览信息
|
||||
fnGetNeState(); // 获取网元状态
|
||||
}, 5_000);
|
||||
}
|
||||
|
||||
/**栏目信息跳转 */
|
||||
function fnToRouter(name: string, query?: any) {
|
||||
router.push({ name, query });
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fnGetSkim().then(() => {
|
||||
loadData();
|
||||
});
|
||||
// 读取数据
|
||||
dbGetJSON('tbl_mocn', `tmp`).then(data => {
|
||||
if (data) {
|
||||
Object.assign(mocnState.data, data);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearInterval(interval10s.value);
|
||||
clearInterval(interval5s.value);
|
||||
});
|
||||
|
||||
/**MOCN状态 */
|
||||
const mocnState = reactive({
|
||||
title: 'Set MOCN Data',
|
||||
visible: false,
|
||||
data: {
|
||||
/**基站数 */
|
||||
baseNum: 0,
|
||||
/**核心网数 */
|
||||
coreNetNum: 0,
|
||||
/**在线用户数 */
|
||||
onlineUserNum: 0,
|
||||
},
|
||||
});
|
||||
/**MOCN 右击设置 */
|
||||
function fnRightClick() {
|
||||
mocnState.visible = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="viewport" ref="viewportDom">
|
||||
<div class="brand">
|
||||
<div
|
||||
class="brand-title"
|
||||
@click="toggle"
|
||||
:title="t('views.dashboard.overview.fullscreen')"
|
||||
>
|
||||
{{ t('views.dashboard.overview.title') }}
|
||||
<FullscreenExitOutlined v-if="isFullscreen" />
|
||||
<FullscreenOutlined v-else />
|
||||
</div>
|
||||
<div class="brand-desc">{{ appStore.appName }}</div>
|
||||
</div>
|
||||
|
||||
<div class="column">
|
||||
<!--概览-->
|
||||
<div class="skim panel">
|
||||
<div class="inner">
|
||||
<h3>
|
||||
<IdcardOutlined style="color: #68d8fe" />
|
||||
{{ t('views.dashboard.overview.skim.userTitle') }}
|
||||
</h3>
|
||||
<div class="data">
|
||||
<div
|
||||
class="item toRouter"
|
||||
@click="fnToRouter('Sub_2010')"
|
||||
:title="t('views.dashboard.overview.toRouter')"
|
||||
>
|
||||
<div>
|
||||
<UserOutlined
|
||||
style="color: #4096ff; margin-right: 8px; font-size: 1.1rem"
|
||||
/>
|
||||
{{ skimState.udmSubNum }}
|
||||
</div>
|
||||
<span>
|
||||
{{ t('views.dashboard.overview.skim.users') }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="item toRouter"
|
||||
@click="fnToRouter('Ims_2080')"
|
||||
:title="t('views.dashboard.overview.toRouter')"
|
||||
style="margin: 0 12px"
|
||||
>
|
||||
<div>
|
||||
<img :src="svgUserIMS" style="width: 18px; margin-right: 8px" />
|
||||
{{ skimState.imsUeNum }}
|
||||
</div>
|
||||
<span>
|
||||
{{ t('views.dashboard.overview.skim.imsUeNum') }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="item toRouter"
|
||||
@click="fnToRouter('Ue_2081')"
|
||||
:title="t('views.dashboard.overview.toRouter')"
|
||||
>
|
||||
<div>
|
||||
<img :src="svgUserSMF" style="width: 18px; margin-right: 8px" />
|
||||
{{ skimState.smfUeNum }}
|
||||
</div>
|
||||
<span>
|
||||
{{ t('views.dashboard.overview.skim.smfUeNum') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="skim panel base">
|
||||
<div class="inner">
|
||||
<h3>
|
||||
<GlobalOutlined style="color: #68d8fe" />
|
||||
{{ t('views.dashboard.overview.skim.baseTitle') }}
|
||||
</h3>
|
||||
<div class="data">
|
||||
<div
|
||||
class="item toRouter"
|
||||
@click="fnToRouter('Base5G_2082', { neType: 'AMF' })"
|
||||
:title="t('views.dashboard.overview.toRouter')"
|
||||
>
|
||||
<div style="align-items: flex-start">
|
||||
<img
|
||||
:src="svgBase"
|
||||
style="width: 18px; margin-right: 8px; height: 2rem"
|
||||
/>
|
||||
{{ skimState.gnbNum }}
|
||||
</div>
|
||||
<span>{{ t('views.dashboard.overview.skim.gnbBase') }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="item toRouter"
|
||||
@click="fnToRouter('Base5G_2082', { neType: 'AMF' })"
|
||||
:title="t('views.dashboard.overview.toRouter')"
|
||||
>
|
||||
<div style="align-items: flex-start">
|
||||
<UserOutlined
|
||||
style="color: #4096ff; margin-right: 8px; font-size: 1.1rem"
|
||||
/>
|
||||
{{ skimState.gnbUeNum }}
|
||||
</div>
|
||||
<span>{{ t('views.dashboard.overview.skim.gnbUeNum') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data">
|
||||
<div
|
||||
class="item toRouter"
|
||||
@click="fnToRouter('Base5G_2082', { neType: 'MME' })"
|
||||
:title="t('views.dashboard.overview.toRouter')"
|
||||
>
|
||||
<div style="align-items: flex-start">
|
||||
<img
|
||||
:src="svgBase"
|
||||
style="width: 18px; margin-right: 8px; height: 2rem"
|
||||
/>
|
||||
{{ skimState.enbNum }}
|
||||
</div>
|
||||
<span>{{ t('views.dashboard.overview.skim.enbBase') }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="item toRouter"
|
||||
@click="fnToRouter('Base5G_2082', { neType: 'MME' })"
|
||||
:title="t('views.dashboard.overview.toRouter')"
|
||||
>
|
||||
<div style="align-items: flex-start">
|
||||
<UserOutlined
|
||||
style="color: #4096ff; margin-right: 8px; font-size: 1.1rem"
|
||||
/>
|
||||
{{ skimState.enbUeNum }}
|
||||
</div>
|
||||
<span>{{ t('views.dashboard.overview.skim.enbUeNum') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 用户行为 -->
|
||||
<div class="userActivity panel">
|
||||
<div class="inner">
|
||||
<h3>
|
||||
<WhatsAppOutlined style="color: #68d8fe" />
|
||||
{{ t('views.dashboard.overview.userActivity.title') }}
|
||||
</h3>
|
||||
<div class="chart">
|
||||
<UserActivity />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column" style="flex: 4; margin: 1.333rem 0.833rem 0">
|
||||
<!-- 实时流量 -->
|
||||
<div class="upfFlow panel">
|
||||
<div class="inner">
|
||||
<h3
|
||||
class="toRouter"
|
||||
@click="fnToRouter('GoldTarget_2104')"
|
||||
:title="t('views.dashboard.overview.toRouter')"
|
||||
>
|
||||
<AreaChartOutlined style="color: #68d8fe" />
|
||||
{{ t('views.dashboard.overview.upfFlow.title') }}
|
||||
</h3>
|
||||
<div class="chart">
|
||||
<UPFFlow />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 网络拓扑 -->
|
||||
<div class="topology panel">
|
||||
<div class="inner">
|
||||
<h3
|
||||
class="toRouter"
|
||||
@click="fnToRouter('TopologyArchitecture_2128')"
|
||||
:title="t('views.dashboard.overview.toRouter')"
|
||||
>
|
||||
<span>
|
||||
<ApartmentOutlined style="color: #68d8fe" />
|
||||
{{ t('views.dashboard.overview.topology.title') }}
|
||||
</span>
|
||||
<span>
|
||||
{{ t('views.dashboard.overview.topology.normal') }}:
|
||||
<span class="normal"> {{ graphNodeStateNum[0] }} </span>
|
||||
{{ t('views.dashboard.overview.topology.abnormal') }}:
|
||||
<span class="abnormal"> {{ graphNodeStateNum[1] }} </span>
|
||||
</span>
|
||||
</h3>
|
||||
<div class="chart">
|
||||
<Topology />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<!-- 流量统计 -->
|
||||
<div class="upfFlowTotal panel">
|
||||
<div class="inner">
|
||||
<h3>
|
||||
<span>
|
||||
<SwapOutlined style="color: #68d8fe" />
|
||||
{{ t('views.dashboard.overview.upfFlowTotal.title') }}
|
||||
</span>
|
||||
|
||||
<!-- 筛选 -->
|
||||
<div class="filter">
|
||||
<span
|
||||
:data-key="v"
|
||||
:class="{ active: upfTFActive === i }"
|
||||
v-for="(v, i) in ['0', '7', '30']"
|
||||
:key="v"
|
||||
@click="
|
||||
() => {
|
||||
upfTFActive = i;
|
||||
}
|
||||
"
|
||||
>
|
||||
{{
|
||||
v === '0'
|
||||
? '24' + t('common.units.hour')
|
||||
: v + t('common.units.day')
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
</h3>
|
||||
<div class="chart">
|
||||
<!-- 数据 -->
|
||||
<div class="data">
|
||||
<div class="item">
|
||||
<span>
|
||||
<ArrowUpOutlined style="color: #597ef7" />
|
||||
{{ t('views.dashboard.overview.upfFlowTotal.up') }}
|
||||
</span>
|
||||
<h4>{{ upfTotalFlow[upfTFActive].up }}</h4>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span>
|
||||
<ArrowDownOutlined style="color: #52c41a" />
|
||||
{{ t('views.dashboard.overview.upfFlowTotal.down') }}
|
||||
</span>
|
||||
<h4>{{ upfTotalFlow[upfTFActive].down }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- MOCN -->
|
||||
<div class="skim panel mocn">
|
||||
<div class="inner">
|
||||
<h3
|
||||
class="toRouter"
|
||||
@contextmenu.prevent="fnRightClick()"
|
||||
@click="fnToRouter('GoldTarget_2104', { neType: 'MOCNGW' })"
|
||||
:title="t('views.dashboard.overview.toRouter')"
|
||||
>
|
||||
<PieChartOutlined style="color: #68d8fe" /> MOCN
|
||||
Information
|
||||
</h3>
|
||||
<div class="chart">
|
||||
<div class="data">
|
||||
<div class="item" title="NodeB">
|
||||
<div>
|
||||
<img :src="svgBase" style="width: 18px; margin-right: 8px" />
|
||||
{{ mocnState.data.baseNum }}
|
||||
</div>
|
||||
<span> NodeB </span>
|
||||
</div>
|
||||
<div class="item" title="CoreNet">
|
||||
<div>
|
||||
<img
|
||||
:src="svgUserSMF"
|
||||
style="width: 18px; margin-right: 8px"
|
||||
/>
|
||||
{{ mocnState.data.coreNetNum }}
|
||||
</div>
|
||||
<span> CoreNet </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data">
|
||||
<div class="item" title="OnlineUser">
|
||||
<div>
|
||||
<UserOutlined
|
||||
style="color: #4096ff; margin-right: 8px; font-size: 1.1rem"
|
||||
/>
|
||||
{{ mocnState.data.onlineUserNum }}
|
||||
</div>
|
||||
<span> OnlineUser </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 告警统计 -->
|
||||
<div class="alarmType panel">
|
||||
<div class="inner">
|
||||
<h3
|
||||
class="toRouter"
|
||||
@click="fnToRouter('HistoryAlarm_2097')"
|
||||
:title="t('views.dashboard.overview.toRouter')"
|
||||
>
|
||||
<PieChartOutlined style="color: #68d8fe" />
|
||||
{{ t('views.dashboard.overview.alarmTypeBar.alarmSum') }}
|
||||
</h3>
|
||||
<div class="chart">
|
||||
<AlarnTypeBar />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 资源情况 -->
|
||||
<div class="resources panel">
|
||||
<div class="inner">
|
||||
<h3>
|
||||
<DashboardOutlined style="color: #68d8fe" />
|
||||
{{ t('views.dashboard.overview.resources.title') }}:
|
||||
{{ graphNodeClickID }}
|
||||
</h3>
|
||||
<div class="chart">
|
||||
<NeResources />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<setting
|
||||
:title="mocnState.title"
|
||||
v-model:visible="mocnState.visible"
|
||||
></setting>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import url('../overview/css/index.css');
|
||||
|
||||
.mocn {
|
||||
height: 20.6%;
|
||||
}
|
||||
.mocn .inner .chart .data {
|
||||
height: unset;
|
||||
}
|
||||
|
||||
.mocn .inner .chart .data .item {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.alarmType {
|
||||
height: 24.4%;
|
||||
}
|
||||
</style>
|
||||
@@ -70,10 +70,10 @@ const alarmTypeType = ref<any>([
|
||||
value: 0,
|
||||
name: t('views.index.Warning'),
|
||||
},
|
||||
{
|
||||
value: 0,
|
||||
name: t('views.index.Event'),
|
||||
},
|
||||
// {
|
||||
// value: 0,
|
||||
// name: t('views.index.Event'),
|
||||
// },
|
||||
]);
|
||||
|
||||
/**告警类型Top数据 */
|
||||
@@ -105,9 +105,9 @@ function initPicture() {
|
||||
case 'Warning':
|
||||
index = 3;
|
||||
break;
|
||||
case 'Event':
|
||||
index = 4;
|
||||
break;
|
||||
// case 'Event':
|
||||
// index = 4;
|
||||
// break;
|
||||
}
|
||||
alarmTypeType.value[index].value = Number(item.value);
|
||||
}
|
||||
@@ -149,7 +149,7 @@ function initPicture() {
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
right: '2%',
|
||||
top: '10%',
|
||||
top: '12%',
|
||||
data: alarmTypeType.value.map((item: any) => item.name), //label数组
|
||||
textStyle: {
|
||||
color: '#A7D6F4', // 设置图例文字颜色
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, onBeforeUnmount, nextTick, watch } from 'vue';
|
||||
import { onMounted, ref, nextTick, watch } from 'vue';
|
||||
import * as echarts from 'echarts/core';
|
||||
import { GridComponent, GridComponentOption } from 'echarts/components';
|
||||
import {
|
||||
@@ -98,7 +98,7 @@ const optionData: EChartsOption = {
|
||||
itemStyle: {
|
||||
color: function (params) {
|
||||
// 红色
|
||||
if (+params.value >= 70) {
|
||||
if (params.value && +params.value >= 70) {
|
||||
return new echarts.graphic.LinearGradient(0, 0, 1, 0, [
|
||||
{ offset: 0, color: '#fff1f0' },
|
||||
{ offset: 0.5, color: '#ffa39e' },
|
||||
@@ -106,7 +106,7 @@ const optionData: EChartsOption = {
|
||||
]);
|
||||
}
|
||||
// 蓝色
|
||||
if (+params.value >= 30) {
|
||||
if (params.value && +params.value >= 30) {
|
||||
return new echarts.graphic.LinearGradient(0, 0, 1, 0, [
|
||||
{ offset: 0, color: '#f0f5ff' },
|
||||
{ offset: 0.5, color: '#adc6ff' },
|
||||
@@ -161,9 +161,9 @@ const optionData: EChartsOption = {
|
||||
label: {
|
||||
formatter: params => {
|
||||
var text = `{a| ${params.value}%} `;
|
||||
if (+params.value >= 70) {
|
||||
if (params.value && +params.value >= 70) {
|
||||
text = `{c| ${params.value}%} `;
|
||||
} else if (+params.value >= 30) {
|
||||
} else if (params.value && +params.value >= 30) {
|
||||
text = `{b| ${params.value}%} `;
|
||||
}
|
||||
return text;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, onBeforeUnmount } from 'vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import { listNe } from '@/api/ne/ne';
|
||||
import { listAllNeInfo } from '@/api/ne/neInfo';
|
||||
import { message } from 'ant-design-vue/lib';
|
||||
import { getGraphData } from '@/api/monitor/topology';
|
||||
import { Graph, GraphData, Tooltip } from '@antv/g6';
|
||||
@@ -76,7 +76,7 @@ function fnGraphEvent(graph: Graph) {
|
||||
// 节点点击
|
||||
graph.on('node:click', evt => {
|
||||
// 获得鼠标当前目标节点
|
||||
const node = evt.item?.getModel();
|
||||
const node = evt.item?.getModel();
|
||||
if (node && node.id && !notNeNodes.includes(node.id)) {
|
||||
graphNodeClickID.value = node.id;
|
||||
}
|
||||
@@ -129,6 +129,9 @@ function handleRanderGraph(
|
||||
var observer = new ResizeObserver(function (entries) {
|
||||
// 当元素大小发生变化时触发回调函数
|
||||
entries.forEach(function (entry) {
|
||||
if (!graphG6.value) {
|
||||
return;
|
||||
}
|
||||
graphG6.value.changeSize(
|
||||
entry.contentRect.width,
|
||||
entry.contentRect.height - 30
|
||||
@@ -149,7 +152,7 @@ function handleRanderGraph(
|
||||
function fnGraphDataLoad(reload: boolean = false) {
|
||||
Promise.all([
|
||||
getGraphData(graphState.group),
|
||||
listNe({
|
||||
listAllNeInfo({
|
||||
bandStatus: false,
|
||||
}),
|
||||
])
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
<template>
|
||||
<div ref="upfFlow" class="chart-container"></div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, ref } from 'vue';
|
||||
import { listUPFData } from '@/api/perfManage/goldTarget';
|
||||
import { parseSizeFromKbs } from '@/utils/parse-utils';
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
import { listKPIData } from '@/api/perfManage/goldTarget';
|
||||
import * as echarts from 'echarts/core';
|
||||
import {
|
||||
TooltipComponent,
|
||||
@@ -20,6 +16,8 @@ import { CanvasRenderer } from 'echarts/renderers';
|
||||
import { markRaw } from 'vue';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
import { parseDateToStr } from '@/utils/date-utils';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import { upfFlowData, upfFlowParse } from '../../hooks/useUPFTotalFlow';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
@@ -39,9 +37,6 @@ type EChartsOption = echarts.ComposeOption<
|
||||
| LineSeriesOption
|
||||
>;
|
||||
|
||||
/**定时器ID */
|
||||
const timeoutId = ref<any>(null);
|
||||
|
||||
/**图DOM节点实例对象 */
|
||||
const upfFlow = ref<HTMLElement | undefined>(undefined);
|
||||
|
||||
@@ -57,132 +52,142 @@ function fnDesign(container: HTMLElement | undefined, option: EChartsOption) {
|
||||
}
|
||||
|
||||
option && upfFlowChart.value.setOption(option);
|
||||
window.onresize = function () {
|
||||
// echarts 窗口缩放自适应 随着div--echarts-records的大小来适应
|
||||
upfFlowChart.value.resize();
|
||||
};
|
||||
|
||||
// 创建 ResizeObserver 实例
|
||||
var observer = new ResizeObserver(entries => {
|
||||
if (upfFlowChart.value) {
|
||||
upfFlowChart.value.resize();
|
||||
}
|
||||
});
|
||||
// 监听元素大小变化
|
||||
observer.observe(container);
|
||||
}
|
||||
|
||||
//渲染速率图
|
||||
function initPicture() {
|
||||
clearTimeout(timeoutId.value);
|
||||
function handleRanderChart() {
|
||||
const { lineXTime, lineYUp, lineYDown } = upfFlowData.value;
|
||||
|
||||
let queryArr: any = [];
|
||||
const initTime: Date = new Date();
|
||||
const startTime: Date = new Date(initTime);
|
||||
startTime.setHours(0, 0, 0, 0); // 设置为今天的0点
|
||||
const endTime: Date = new Date(initTime);
|
||||
endTime.setHours(23, 59, 59, 59); // 设置为今天的12点
|
||||
queryArr = [parseDateToStr(startTime), parseDateToStr(endTime)];
|
||||
|
||||
listUPFData(queryArr).then(res => {
|
||||
timeoutId.value = setTimeout(() => {
|
||||
initPicture(); // 5秒后再次获取数据
|
||||
}, 5000);
|
||||
let timeArr: any = [];
|
||||
let upValue: any = [];
|
||||
let downValue: any = [];
|
||||
|
||||
res.upData.map((item: any) => {
|
||||
timeArr.push(item.timestamp);
|
||||
upValue.push(parseSizeFromKbs(item.value, item.granularity)[0]);
|
||||
});
|
||||
res.downData.map((item: any) => {
|
||||
downValue.push(parseSizeFromKbs(item.value, item.granularity)[0]);
|
||||
});
|
||||
|
||||
var charts = {
|
||||
unit: '(Mbps)',
|
||||
names: [
|
||||
t('views.dashboard.overview.upfFlow.up'),
|
||||
t('views.dashboard.overview.upfFlow.down'),
|
||||
],
|
||||
|
||||
lineX: timeArr,
|
||||
value: [upValue, downValue],
|
||||
};
|
||||
|
||||
var color = ['rgba(250, 219, 20', 'rgba(92, 123, 217'];
|
||||
var lineY: any = [];
|
||||
|
||||
for (var i = 0; i < charts.names.length; i++) {
|
||||
var x = i;
|
||||
if (x > color.length - 1) {
|
||||
x = color.length - 1;
|
||||
}
|
||||
var data = {
|
||||
name: charts.names[i],
|
||||
type: 'line',
|
||||
color: color[x] + ')',
|
||||
smooth: true,
|
||||
areaStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: color[x] + ', .5)',
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: color[x] + ', 0.5)',
|
||||
},
|
||||
]),
|
||||
shadowColor: 'rgba(0, 0, 0, 0.1)',
|
||||
shadowBlur: 10,
|
||||
},
|
||||
symbol: 'circle',
|
||||
symbolSize: 5,
|
||||
formatter: '{b}',
|
||||
data: charts.value[i],
|
||||
};
|
||||
lineY.push(data);
|
||||
}
|
||||
|
||||
const optionData: EChartsOption = {
|
||||
tooltip: {
|
||||
show: true, //是否显示提示框组件
|
||||
trigger: 'axis',
|
||||
//formatter:'{a0}:{c0}<br>{a1}:{c1}'
|
||||
formatter: function (param: any) {
|
||||
var tip = '';
|
||||
if (param !== null && param.length > 0) {
|
||||
tip += param[0].name + '<br />';
|
||||
for (var i = 0; i < param.length; i++) {
|
||||
tip +=
|
||||
param[i].marker +
|
||||
param[i].seriesName +
|
||||
': ' +
|
||||
param[i].value +
|
||||
'<br />';
|
||||
}
|
||||
}
|
||||
return tip;
|
||||
},
|
||||
var yAxisSeries: any = [
|
||||
{
|
||||
name: t('views.dashboard.overview.upfFlow.up'),
|
||||
type: 'line',
|
||||
color: 'rgba(250, 219, 20)',
|
||||
smooth: true,
|
||||
areaStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgba(250, 219, 20, .5)',
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgba(250, 219, 20, 0.5)',
|
||||
},
|
||||
]),
|
||||
shadowColor: 'rgba(0, 0, 0, 0.1)',
|
||||
shadowBlur: 10,
|
||||
},
|
||||
legend: {
|
||||
data: charts.names,
|
||||
textStyle: {
|
||||
fontSize: 12,
|
||||
symbol: 'circle',
|
||||
symbolSize: 5,
|
||||
formatter: '{b}',
|
||||
data: lineYUp,
|
||||
},
|
||||
{
|
||||
name: t('views.dashboard.overview.upfFlow.down'),
|
||||
type: 'line',
|
||||
color: 'rgba(92, 123, 217)',
|
||||
smooth: true,
|
||||
areaStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgba(92, 123, 217, .5)',
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgba(92, 123, 217, 0.5)',
|
||||
},
|
||||
]),
|
||||
shadowColor: 'rgba(0, 0, 0, 0.1)',
|
||||
shadowBlur: 10,
|
||||
},
|
||||
symbol: 'circle',
|
||||
symbolSize: 5,
|
||||
formatter: '{b}',
|
||||
data: lineYDown,
|
||||
},
|
||||
];
|
||||
|
||||
const optionData: EChartsOption = {
|
||||
tooltip: {
|
||||
show: true, //是否显示提示框组件
|
||||
trigger: 'axis',
|
||||
//formatter:'{a0}:{c0}<br>{a1}:{c1}'
|
||||
formatter: function (param: any) {
|
||||
var tip = '';
|
||||
if (param !== null && param.length > 0) {
|
||||
tip += param[0].name + '<br />';
|
||||
for (var i = 0; i < param.length; i++) {
|
||||
tip +=
|
||||
param[i].marker +
|
||||
param[i].seriesName +
|
||||
': ' +
|
||||
param[i].value +
|
||||
'<br />';
|
||||
}
|
||||
}
|
||||
return tip;
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
data: yAxisSeries.map((s: any) => s.name),
|
||||
textStyle: {
|
||||
fontSize: 12,
|
||||
color: 'rgb(0,253,255,0.6)',
|
||||
},
|
||||
left: 'center', // 设置图例居中
|
||||
},
|
||||
grid: {
|
||||
top: '14%',
|
||||
left: '4%',
|
||||
right: '4%',
|
||||
bottom: '12%',
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: lineXTime,
|
||||
axisLabel: {
|
||||
formatter: function (params: any) {
|
||||
return params.split(' ')[1];
|
||||
},
|
||||
fontSize: 14,
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: 'rgb(0,253,255,0.6)',
|
||||
},
|
||||
left: 'center',
|
||||
}, // 设置图例居中
|
||||
|
||||
grid: {
|
||||
top: '14%',
|
||||
left: '4%',
|
||||
right: '4%',
|
||||
bottom: '12%',
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: charts.lineX,
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
name: '(Mbps)',
|
||||
nameTextStyle: {
|
||||
fontSize: 12, // 设置文字距离x轴的距离
|
||||
padding: [0, -10, 0, 0], // 设置名称在x轴方向上的偏移
|
||||
},
|
||||
type: 'value',
|
||||
// splitNumber: 4,
|
||||
min: 0,
|
||||
//max: 300,
|
||||
axisLabel: {
|
||||
formatter: function (params: any) {
|
||||
return params.split(' ')[1];
|
||||
formatter: '{value}',
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: 'rgb(23,255,243,0.3)',
|
||||
},
|
||||
fontSize: 14,
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
@@ -190,44 +195,95 @@ function initPicture() {
|
||||
},
|
||||
},
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
name: charts.unit,
|
||||
type: 'value',
|
||||
// splitNumber: 4,
|
||||
min: 0,
|
||||
//max: 300,
|
||||
axisLabel: {
|
||||
formatter: '{value}',
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: 'rgb(23,255,243,0.3)',
|
||||
},
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: 'rgb(0,253,255,0.6)',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
series: lineY,
|
||||
};
|
||||
fnDesign(upfFlow.value, optionData);
|
||||
});
|
||||
],
|
||||
series: yAxisSeries,
|
||||
};
|
||||
fnDesign(upfFlow.value, optionData);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initPicture();
|
||||
});
|
||||
/**查询初始UPF数据 */
|
||||
function fnGetInitData() {
|
||||
// 查询10分钟前的
|
||||
const nowDate: Date = new Date();
|
||||
const tenMinutesAgo = new Date(nowDate.getTime() - 5 * 60 * 1000);
|
||||
|
||||
/**组件实例被卸载之后调用 */
|
||||
onUnmounted(() => {
|
||||
clearTimeout(timeoutId.value);
|
||||
listKPIData({
|
||||
neType: 'UPF',
|
||||
neId: '001',
|
||||
startTime: parseDateToStr(tenMinutesAgo),
|
||||
endTime: parseDateToStr(nowDate),
|
||||
// startTime: '2024-03-20 19:50:00',
|
||||
// endTime: '2024-03-20 19:55:00',
|
||||
interval: 5, // 5秒
|
||||
sortField: 'timeGroup',
|
||||
sortOrder: 'asc',
|
||||
})
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||
for (const item of res.data) {
|
||||
upfFlowParse(item);
|
||||
}
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
handleRanderChart();
|
||||
});
|
||||
}
|
||||
|
||||
watch(
|
||||
() => upfFlowData.value,
|
||||
v => {
|
||||
if (upfFlowChart.value == null) return;
|
||||
upfFlowChart.value.setOption({
|
||||
xAxis: {
|
||||
data: v.lineXTime,
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: v.lineYUp,
|
||||
},
|
||||
{
|
||||
data: v.lineYDown,
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
fnGetInitData();
|
||||
|
||||
// setInterval(() => {
|
||||
// upfFlowData.value.lineXTime.push(parseDateToStr(new Date()));
|
||||
// const upN3 = parseSizeFromKbs(+145452, 5);
|
||||
// upfFlowData.value.lineYUp.push(upN3[0]);
|
||||
// const downN6 = parseSizeFromKbs(+232343, 5);
|
||||
// upfFlowData.value.lineYDown.push(downN6[0]);
|
||||
|
||||
// upfFlowChart.value.setOption({
|
||||
// xAxis: {
|
||||
// data: upfFlowData.value.lineXTime,
|
||||
// },
|
||||
// series: [
|
||||
// {
|
||||
// data: upfFlowData.value.lineYUp,
|
||||
// },
|
||||
// {
|
||||
// data: upfFlowData.value.lineYDown,
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
// }, 5000);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="upfFlow" class="chart-container"></div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.chart-container {
|
||||
/* 设置图表容器大小和位置 */
|
||||
|
||||
@@ -85,9 +85,9 @@ onMounted(() => {
|
||||
<div class="card-cdr-item">
|
||||
<div>
|
||||
{{ t('views.dashboard.overview.userActivity.caller') }}:
|
||||
<span :title="item.data.callerParty">{{
|
||||
item.data.callerParty
|
||||
}}</span>
|
||||
<span :title="item.data.callerParty">
|
||||
{{ item.data.callerParty }}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
{{ t('views.dashboard.overview.userActivity.called') }}:
|
||||
@@ -99,11 +99,12 @@ onMounted(() => {
|
||||
{{ t('views.dashboard.overview.userActivity.duration') }}:
|
||||
<span>{{ parseDuration(item.data.callDuration) }}</span>
|
||||
</div>
|
||||
<div v-else></div>
|
||||
</div>
|
||||
<div>
|
||||
{{ t('views.dashboard.overview.userActivity.result') }}:
|
||||
<span v-if="item.data.callType !== 'sms'">
|
||||
<DictTag :options="dict.cdrSipCode" :value="item.data.cause" />
|
||||
<DictTag :options="dict.cdrSipCode" :value="item.data.cause" value-option="0" />
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ t('views.dashboard.overview.userActivity.resultOK') }}
|
||||
|
||||
@@ -157,10 +157,28 @@
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* 概览区域 衍生基站信息 */
|
||||
.skim.base {
|
||||
height: 20.6%;
|
||||
}
|
||||
|
||||
.skim.base .inner .data {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
height: 45%;
|
||||
}
|
||||
.skim.base .inner .data .item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: baseline;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
/* 用户行为 */
|
||||
.userActivity {
|
||||
/* min-height: 35.8rem; */
|
||||
height: 66%;
|
||||
height: 60%;
|
||||
}
|
||||
.userActivity .inner .chart {
|
||||
width: 100%;
|
||||
@@ -203,7 +221,7 @@
|
||||
.upfFlowTotal .inner .chart {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-top: 1rem;
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
.upfFlowTotal .inner .chart .data {
|
||||
display: flex;
|
||||
@@ -247,3 +265,13 @@
|
||||
height: 100%;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
/* 跳转鼠标悬浮 */
|
||||
.toRouter:hover {
|
||||
cursor: pointer;
|
||||
color: #fff !important;
|
||||
}
|
||||
.toRouter:hover > *,
|
||||
.toRouter:hover > * > * {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
@@ -158,3 +158,15 @@ export function neStateParse(neType: string, data: Record<string, any>) {
|
||||
// 请求标记复位
|
||||
neStateRequestMap.value.set(neType, false);
|
||||
}
|
||||
|
||||
/**属性复位 */
|
||||
export function topologyReset() {
|
||||
graphState.data = {
|
||||
combos: [],
|
||||
edges: [],
|
||||
nodes: [],
|
||||
};
|
||||
graphG6.value = null;
|
||||
graphNodeClickID.value = 'UPF';
|
||||
neStateRequestMap.value = new Map();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,42 @@
|
||||
import { parseSizeFromBits } from '@/utils/parse-utils';
|
||||
import { parseSizeFromBits, parseSizeFromKbs } from '@/utils/parse-utils';
|
||||
import { ref } from 'vue';
|
||||
|
||||
type FDType = {
|
||||
/**时间 */
|
||||
lineXTime: string[];
|
||||
/**上行 N3 */
|
||||
lineYUp: number[];
|
||||
/**下行 N6 */
|
||||
lineYDown: number[];
|
||||
/**容量 */
|
||||
cap: number;
|
||||
};
|
||||
|
||||
/**UPF-流量数据 */
|
||||
export const upfFlowData = ref<FDType>({
|
||||
lineXTime: [],
|
||||
lineYUp: [],
|
||||
lineYDown: [],
|
||||
cap: 0,
|
||||
});
|
||||
|
||||
/**UPF-流量数据 数据解析 */
|
||||
export function upfFlowParse(data: Record<string, string>) {
|
||||
upfFlowData.value.lineXTime.push(data['timeGroup']);
|
||||
const upN3 = parseSizeFromKbs(+data['UPF.03'], 5);
|
||||
upfFlowData.value.lineYUp.push(upN3[0]);
|
||||
const downN6 = parseSizeFromKbs(+data['UPF.06'], 5);
|
||||
upfFlowData.value.lineYDown.push(downN6[0]);
|
||||
upfFlowData.value.cap += 1;
|
||||
// 超过 25 弹出
|
||||
if (upfFlowData.value.cap > 25) {
|
||||
upfFlowData.value.lineXTime.shift();
|
||||
upfFlowData.value.lineYUp.shift();
|
||||
upfFlowData.value.lineYDown.shift();
|
||||
upfFlowData.value.cap -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
type TFType = {
|
||||
/**上行 N3 */
|
||||
up: string;
|
||||
@@ -40,3 +76,32 @@ export function upfTFParse(data: Record<string, string>) {
|
||||
|
||||
/**UPF-总流量数 选中 */
|
||||
export const upfTFActive = ref<number>(0);
|
||||
|
||||
/**属性复位 */
|
||||
export function upfTotalFlowReset() {
|
||||
upfFlowData.value = {
|
||||
lineXTime: [],
|
||||
lineYUp: [],
|
||||
lineYDown: [],
|
||||
cap: 0,
|
||||
};
|
||||
upfTotalFlow.value = [
|
||||
// 0天 当天24小时
|
||||
{
|
||||
up: '0 B',
|
||||
down: '0 B',
|
||||
requestFlag: false,
|
||||
},
|
||||
{
|
||||
up: '0 B',
|
||||
down: '0 B',
|
||||
requestFlag: false,
|
||||
},
|
||||
{
|
||||
up: '0 B',
|
||||
down: '0 B',
|
||||
requestFlag: false,
|
||||
},
|
||||
];
|
||||
upfTFActive.value = 0;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
import { ref } from 'vue';
|
||||
|
||||
/**UE事件数据 */
|
||||
export const ueEventData = ref<Record<string, any>[]>([]);
|
||||
|
||||
/**UE事件总量 */
|
||||
export const ueEventTotal = ref<number>(0);
|
||||
|
||||
/**UE事件推送id */
|
||||
export const ueEventId = ref<string>('');
|
||||
|
||||
/**ueEvent UE会话事件 数据解析 */
|
||||
export function ueEventParse(item: Record<string, any>) {
|
||||
let evData: Record<string, any> = item.eventJSON;
|
||||
@@ -23,21 +14,13 @@ export function ueEventParse(item: Record<string, any>) {
|
||||
return {
|
||||
eType: 'ue',
|
||||
eId: `ue_${item.id}_${Date.now()}`,
|
||||
eTime: +item.timestamp,
|
||||
id: item.id,
|
||||
type: item.eventType,
|
||||
data: evData,
|
||||
};
|
||||
}
|
||||
|
||||
/**CDR事件数据 */
|
||||
export const cdrEventData = ref<Record<string, any>[]>([]);
|
||||
|
||||
/**CDR事件总量 */
|
||||
export const cdrEventTotal = ref<number>(0);
|
||||
|
||||
/**CDR事件推送id */
|
||||
export const cdrEventId = ref<string>('');
|
||||
|
||||
/**cdrEvent CDR会话事件 数据解析 */
|
||||
export function cdrEventParse(item: Record<string, any>) {
|
||||
let evData: Record<string, any> = item.cdrJSON || item.CDR;
|
||||
@@ -58,6 +41,7 @@ export function cdrEventParse(item: Record<string, any>) {
|
||||
return {
|
||||
eType: 'cdr',
|
||||
eId: `cdr_${item.id}_${Date.now()}`,
|
||||
eTime: +item.timestamp,
|
||||
id: item.id,
|
||||
data: evData,
|
||||
};
|
||||
@@ -69,3 +53,10 @@ export const eventData = ref<Record<string, any>[]>([]);
|
||||
export const eventTotal = ref<number>(0);
|
||||
/**CDR/UE事件推送id */
|
||||
export const eventId = ref<string>('');
|
||||
|
||||
/**属性复位 */
|
||||
export function userActivityReset() {
|
||||
eventData.value = [];
|
||||
eventTotal.value = 0;
|
||||
eventId.value = '';
|
||||
}
|
||||
|
||||
@@ -7,9 +7,15 @@ import {
|
||||
eventData,
|
||||
eventTotal,
|
||||
eventId,
|
||||
userActivityReset,
|
||||
} from './useUserActivity';
|
||||
import { upfTotalFlow, upfTFParse } from './useUPFTotalFlow';
|
||||
import { neStateParse } from './useTopology';
|
||||
import {
|
||||
upfTotalFlow,
|
||||
upfTFParse,
|
||||
upfFlowParse,
|
||||
upfTotalFlowReset,
|
||||
} from './useUPFTotalFlow';
|
||||
import { topologyReset, neStateParse } from './useTopology';
|
||||
import PQueue from 'p-queue';
|
||||
|
||||
/**websocket连接 */
|
||||
@@ -56,6 +62,11 @@ export default function useWS() {
|
||||
eventData.value.push(v);
|
||||
}
|
||||
}
|
||||
|
||||
// 有数据进行排序
|
||||
if (eventData.value.length > 10) {
|
||||
eventData.value.sort((a, b) => b.eTime - a.eTime);
|
||||
}
|
||||
if (eventData.value.length > 0) {
|
||||
eventId.value = eventData.value[0].eId;
|
||||
}
|
||||
@@ -71,6 +82,11 @@ export default function useWS() {
|
||||
eventData.value.push(v);
|
||||
}
|
||||
}
|
||||
|
||||
// 有数据进行排序
|
||||
if (eventData.value.length > 10) {
|
||||
eventData.value.sort((a, b) => b.eTime - a.eTime);
|
||||
}
|
||||
if (eventData.value.length > 0) {
|
||||
eventId.value = eventData.value[0].eId;
|
||||
}
|
||||
@@ -102,6 +118,12 @@ export default function useWS() {
|
||||
return;
|
||||
}
|
||||
switch (data.groupId) {
|
||||
// kpiEvent 指标UPF
|
||||
case '12':
|
||||
if (data.data) {
|
||||
upfFlowParse(data.data);
|
||||
}
|
||||
break;
|
||||
// ueEvent UE会话事件
|
||||
case '1010':
|
||||
if (data.data) {
|
||||
@@ -112,7 +134,9 @@ export default function useWS() {
|
||||
eventTotal.value += 1;
|
||||
eventId.value = v.eId;
|
||||
await new Promise(resolve => setTimeout(resolve, 800));
|
||||
eventData.value.pop();
|
||||
if (eventData.value.length > 20) {
|
||||
eventData.value.pop();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -127,7 +151,9 @@ export default function useWS() {
|
||||
eventTotal.value += 1;
|
||||
eventId.value = v.eId;
|
||||
await new Promise(resolve => setTimeout(resolve, 800));
|
||||
eventData.value.pop();
|
||||
if (eventData.value.length > 20) {
|
||||
eventData.value.pop();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -201,10 +227,11 @@ export default function useWS() {
|
||||
params: {
|
||||
/**订阅通道组
|
||||
*
|
||||
* 指标UPF (GroupID:12)
|
||||
* UE会话事件-AMF (GroupID:1010)
|
||||
* CDR会话事件-IMS (GroupID:1005)
|
||||
*/
|
||||
subGroupID: '1010,1005',
|
||||
subGroupID: '12,1010,1005',
|
||||
},
|
||||
onmessage: wsMessage,
|
||||
onerror: wsError,
|
||||
@@ -214,6 +241,9 @@ export default function useWS() {
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
ws.close();
|
||||
userActivityReset();
|
||||
upfTotalFlowReset();
|
||||
topologyReset();
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
@@ -13,7 +13,6 @@ import { listSub } from '@/api/neUser/sub';
|
||||
import { listUENumBySMF } from '@/api/neUser/smf';
|
||||
import { listUENumByIMS } from '@/api/neUser/ims';
|
||||
import { listBase5G } from '@/api/neUser/base5G';
|
||||
|
||||
import {
|
||||
graphNodeClickID,
|
||||
graphState,
|
||||
@@ -26,7 +25,8 @@ import { useFullscreen } from '@vueuse/core';
|
||||
import useWS from './hooks/useWS';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
|
||||
import { useRouter } from 'vue-router';
|
||||
const router = useRouter();
|
||||
const appStore = useAppStore();
|
||||
const { t } = useI18n();
|
||||
const { wsSend, cdrEventSend, ueEventSend, upfTFSend } = useWS();
|
||||
@@ -39,8 +39,14 @@ type SkimStateType = {
|
||||
smfUeNum: number;
|
||||
/**IMS在线用户数 */
|
||||
imsUeNum: number;
|
||||
/**基站数量 */
|
||||
nbNum: number;
|
||||
/**5G基站数量 */
|
||||
gnbNum: number;
|
||||
/**5G在线用户数量 */
|
||||
gnbUeNum: number;
|
||||
/**4G基站数量 */
|
||||
enbNum: number;
|
||||
/**4G在线用户数量 */
|
||||
enbUeNum: number;
|
||||
};
|
||||
|
||||
/**概览状态信息 */
|
||||
@@ -48,7 +54,10 @@ let skimState: SkimStateType = reactive({
|
||||
udmSubNum: 0,
|
||||
smfUeNum: 0,
|
||||
imsUeNum: 0,
|
||||
nbNum: 0,
|
||||
gnbNum: 0,
|
||||
gnbUeNum: 0,
|
||||
enbNum: 0,
|
||||
enbUeNum: 0,
|
||||
});
|
||||
|
||||
/**总览节点 */
|
||||
@@ -56,14 +65,13 @@ const viewportDom = ref<HTMLElement | null>(null);
|
||||
const { isFullscreen, toggle } = useFullscreen(viewportDom);
|
||||
|
||||
/**10s调度器 */
|
||||
const stateInterval = ref<any>(null);
|
||||
const interval10s = ref<any>(null);
|
||||
|
||||
/**网元状态定时器 */
|
||||
const stateTimeout = ref<any>(null);
|
||||
/**5s调度器 */
|
||||
const interval5s = ref<any>(null);
|
||||
|
||||
/**查询网元状态 */
|
||||
function fnGetState() {
|
||||
clearTimeout(stateTimeout.value);
|
||||
function fnGetNeState() {
|
||||
// 获取节点状态
|
||||
for (const node of graphState.data.nodes) {
|
||||
if (notNeNodes.includes(node.id)) continue;
|
||||
@@ -82,11 +90,6 @@ function fnGetState() {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
stateTimeout.value = setTimeout(() => {
|
||||
fnGetSkim(); // 获取概览信息
|
||||
fnGetState();
|
||||
}, 5_000);
|
||||
}
|
||||
|
||||
/**获取概览信息 */
|
||||
@@ -97,16 +100,16 @@ async function fnGetSkim() {
|
||||
pageNum: 1,
|
||||
pageSize: 1,
|
||||
}),
|
||||
listUENumBySMF('001'),
|
||||
listUENumByIMS('001'),
|
||||
listBase5G({
|
||||
neType: 'AMF',
|
||||
neId: '001',
|
||||
id: '',
|
||||
pageNum: 1,
|
||||
/**每页条数 */
|
||||
pageSize: 20,
|
||||
}),
|
||||
listUENumBySMF('001'),
|
||||
listUENumByIMS('001'),
|
||||
listBase5G({
|
||||
neType: 'MME',
|
||||
neId: '001',
|
||||
}),
|
||||
]);
|
||||
|
||||
if (resArr[0].status === 'fulfilled') {
|
||||
@@ -118,33 +121,48 @@ async function fnGetSkim() {
|
||||
if (resArr[1].status === 'fulfilled') {
|
||||
const res1 = resArr[1].value;
|
||||
if (res1.code === RESULT_CODE_SUCCESS) {
|
||||
skimState.nbNum = res1.total;
|
||||
skimState.smfUeNum = res1.data;
|
||||
}
|
||||
}
|
||||
if (resArr[2].status === 'fulfilled') {
|
||||
const res2 = resArr[2].value;
|
||||
if (res2.code === RESULT_CODE_SUCCESS) {
|
||||
skimState.smfUeNum = res2.data;
|
||||
skimState.imsUeNum = res2.data;
|
||||
}
|
||||
}
|
||||
if (resArr[3].status === 'fulfilled') {
|
||||
const res3 = resArr[3].value;
|
||||
if (res3.code === RESULT_CODE_SUCCESS) {
|
||||
skimState.imsUeNum = res3.data;
|
||||
skimState.gnbNum = res3.total;
|
||||
skimState.gnbUeNum = 0;
|
||||
res3.rows.map((item: any) => {
|
||||
skimState.gnbUeNum += item.ueNum;
|
||||
});
|
||||
}
|
||||
}
|
||||
if (resArr[4].status === 'fulfilled') {
|
||||
const res4 = resArr[4].value;
|
||||
if (res4.code === RESULT_CODE_SUCCESS) {
|
||||
skimState.enbNum = res4.total;
|
||||
skimState.enbUeNum = 0;
|
||||
res4.rows.map((item: any) => {
|
||||
skimState.enbUeNum += item.ueNum;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**初始数据函数 */
|
||||
function loadData() {
|
||||
fnGetState(); // 获取网元状态
|
||||
fnGetNeState(); // 获取网元状态
|
||||
cdrEventSend();
|
||||
ueEventSend();
|
||||
upfTFSend(0);
|
||||
upfTFSend(7);
|
||||
upfTFSend(30);
|
||||
|
||||
stateInterval.value = setInterval(() => {
|
||||
clearInterval(interval10s.value);
|
||||
interval10s.value = setInterval(() => {
|
||||
upfTFActive.value = upfTFActive.value >= 2 ? 0 : upfTFActive.value + 1;
|
||||
if (upfTFActive.value === 0) {
|
||||
upfTFSend(7);
|
||||
@@ -154,6 +172,17 @@ function loadData() {
|
||||
upfTFSend(0);
|
||||
}
|
||||
}, 10_000);
|
||||
|
||||
clearInterval(interval5s.value);
|
||||
interval5s.value = setInterval(() => {
|
||||
fnGetSkim(); // 获取概览信息
|
||||
fnGetNeState(); // 获取网元状态
|
||||
}, 5_000);
|
||||
}
|
||||
|
||||
/**栏目信息跳转 */
|
||||
function fnToRouter(name: string, query?: any) {
|
||||
router.push({ name, query });
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
@@ -163,8 +192,10 @@ onMounted(() => {
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearTimeout(stateTimeout.value);
|
||||
clearTimeout(stateInterval.value);
|
||||
clearInterval(interval10s.value);
|
||||
interval10s.value = null;
|
||||
clearInterval(interval5s.value);
|
||||
interval5s.value = null;
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -192,7 +223,11 @@ onBeforeUnmount(() => {
|
||||
{{ t('views.dashboard.overview.skim.userTitle') }}
|
||||
</h3>
|
||||
<div class="data">
|
||||
<div class="item">
|
||||
<div
|
||||
class="item toRouter"
|
||||
@click="fnToRouter('Sub_2010')"
|
||||
:title="t('views.dashboard.overview.toRouter')"
|
||||
>
|
||||
<div>
|
||||
<UserOutlined
|
||||
style="color: #4096ff; margin-right: 8px; font-size: 1.1rem"
|
||||
@@ -203,45 +238,98 @@ onBeforeUnmount(() => {
|
||||
{{ t('views.dashboard.overview.skim.users') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="item" style="margin: 0 12px">
|
||||
<div
|
||||
class="item toRouter"
|
||||
@click="fnToRouter('Ims_2080')"
|
||||
:title="t('views.dashboard.overview.toRouter')"
|
||||
style="margin: 0 12px"
|
||||
>
|
||||
<div>
|
||||
<img :src="svgUserIMS" style="width: 18px; margin-right: 8px" />
|
||||
{{ skimState.imsUeNum }}
|
||||
</div>
|
||||
<span>
|
||||
IMS {{ t('views.dashboard.overview.skim.session') }}
|
||||
{{ t('views.dashboard.overview.skim.imsUeNum') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div
|
||||
class="item toRouter"
|
||||
@click="fnToRouter('Ue_2081')"
|
||||
:title="t('views.dashboard.overview.toRouter')"
|
||||
>
|
||||
<div>
|
||||
<img :src="svgUserSMF" style="width: 18px; margin-right: 8px" />
|
||||
{{ skimState.smfUeNum }}
|
||||
</div>
|
||||
<span>
|
||||
Data {{ t('views.dashboard.overview.skim.session') }}
|
||||
{{ t('views.dashboard.overview.skim.smfUeNum') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="skim panel">
|
||||
<div class="skim panel base">
|
||||
<div class="inner">
|
||||
<h3>
|
||||
<GlobalOutlined style="color: #68d8fe" />
|
||||
{{ t('views.dashboard.overview.skim.baseTitle') }}
|
||||
</h3>
|
||||
<div class="data">
|
||||
<div class="item">
|
||||
<div
|
||||
class="item toRouter"
|
||||
@click="fnToRouter('Base5G_2082', { neType: 'AMF' })"
|
||||
:title="t('views.dashboard.overview.toRouter')"
|
||||
>
|
||||
<div style="align-items: flex-start">
|
||||
<img
|
||||
:src="svgBase"
|
||||
style="width: 18px; margin-right: 8px; height: 2rem"
|
||||
/>
|
||||
{{ skimState.nbNum }}
|
||||
{{ skimState.gnbNum }}
|
||||
</div>
|
||||
<span>
|
||||
{{ t('views.dashboard.overview.skim.base') }}
|
||||
</span>
|
||||
<span>{{ t('views.dashboard.overview.skim.gnbBase') }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="item toRouter"
|
||||
@click="fnToRouter('Base5G_2082', { neType: 'AMF' })"
|
||||
:title="t('views.dashboard.overview.toRouter')"
|
||||
>
|
||||
<div style="align-items: flex-start">
|
||||
<UserOutlined
|
||||
style="color: #4096ff; margin-right: 8px; font-size: 1.1rem"
|
||||
/>
|
||||
{{ skimState.gnbUeNum }}
|
||||
</div>
|
||||
<span>{{ t('views.dashboard.overview.skim.gnbUeNum') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data">
|
||||
<div
|
||||
class="item toRouter"
|
||||
@click="fnToRouter('Base5G_2082', { neType: 'MME' })"
|
||||
:title="t('views.dashboard.overview.toRouter')"
|
||||
>
|
||||
<div style="align-items: flex-start">
|
||||
<img
|
||||
:src="svgBase"
|
||||
style="width: 18px; margin-right: 8px; height: 2rem"
|
||||
/>
|
||||
{{ skimState.enbNum }}
|
||||
</div>
|
||||
<span>{{ t('views.dashboard.overview.skim.enbBase') }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="item toRouter"
|
||||
@click="fnToRouter('Base5G_2082', { neType: 'MME' })"
|
||||
:title="t('views.dashboard.overview.toRouter')"
|
||||
>
|
||||
<div style="align-items: flex-start">
|
||||
<UserOutlined
|
||||
style="color: #4096ff; margin-right: 8px; font-size: 1.1rem"
|
||||
/>
|
||||
{{ skimState.enbUeNum }}
|
||||
</div>
|
||||
<span>{{ t('views.dashboard.overview.skim.enbUeNum') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -264,7 +352,11 @@ onBeforeUnmount(() => {
|
||||
<!-- 实时流量 -->
|
||||
<div class="upfFlow panel">
|
||||
<div class="inner">
|
||||
<h3>
|
||||
<h3
|
||||
class="toRouter"
|
||||
@click="fnToRouter('GoldTarget_2104')"
|
||||
:title="t('views.dashboard.overview.toRouter')"
|
||||
>
|
||||
<AreaChartOutlined style="color: #68d8fe" />
|
||||
{{ t('views.dashboard.overview.upfFlow.title') }}
|
||||
</h3>
|
||||
@@ -276,7 +368,11 @@ onBeforeUnmount(() => {
|
||||
<!-- 网络拓扑 -->
|
||||
<div class="topology panel">
|
||||
<div class="inner">
|
||||
<h3>
|
||||
<h3
|
||||
class="toRouter"
|
||||
@click="fnToRouter('TopologyArchitecture_2128')"
|
||||
:title="t('views.dashboard.overview.toRouter')"
|
||||
>
|
||||
<span>
|
||||
<ApartmentOutlined style="color: #68d8fe" />
|
||||
{{ t('views.dashboard.overview.topology.title') }}
|
||||
@@ -349,7 +445,11 @@ onBeforeUnmount(() => {
|
||||
<!-- 告警统计 -->
|
||||
<div class="alarmType panel">
|
||||
<div class="inner">
|
||||
<h3>
|
||||
<h3
|
||||
class="toRouter"
|
||||
@click="fnToRouter('HistoryAlarm_2097')"
|
||||
:title="t('views.dashboard.overview.toRouter')"
|
||||
>
|
||||
<PieChartOutlined style="color: #68d8fe" />
|
||||
{{ t('views.dashboard.overview.alarmTypeBar.alarmSum') }}
|
||||
</h3>
|
||||
|
||||
@@ -960,6 +960,7 @@ onMounted(() => {
|
||||
</a-dropdown>
|
||||
</a-tooltip>
|
||||
<TableColumnsDnd
|
||||
cache-id="alarmActive"
|
||||
:columns="tableColumns"
|
||||
v-model:columns-dnd="tableColumnsDnd"
|
||||
></TableColumnsDnd>
|
||||
|
||||
858
src/views/faultManage/event/index.vue
Normal file
858
src/views/faultManage/event/index.vue
Normal file
@@ -0,0 +1,858 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, onMounted, toRaw } 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 { listAct, exportAll } from '@/api/faultManage/eventAlarm';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
import useDictStore from '@/store/modules/dict';
|
||||
import saveAs from 'file-saver';
|
||||
import TableColumnsDnd from '@/components/TableColumnsDnd/index.vue';
|
||||
import { writeSheet } from '@/utils/execl-utils';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import { readLoalXlsx } from '@/utils/execl-utils';
|
||||
const { getDict } = useDictStore();
|
||||
const { t, currentLocale } = useI18n();
|
||||
|
||||
/**字典数据 */
|
||||
let dict: {
|
||||
/**活动告警类型 */
|
||||
activeAlarmType: DictType[];
|
||||
/**告警清除类型 */
|
||||
activeClearType: DictType[];
|
||||
/**告警清除类型 */
|
||||
activeAckState: DictType[];
|
||||
/**原始严重程度 */
|
||||
activeAlarmSeverity: DictType[];
|
||||
} = reactive({
|
||||
activeAlarmType: [],
|
||||
activeClearType: [],
|
||||
activeAckState: [],
|
||||
activeAlarmSeverity: [],
|
||||
});
|
||||
|
||||
/**表格字段列排序 */
|
||||
let tableColumnsDnd = ref<ColumnsType>([]);
|
||||
|
||||
/**记录开始结束时间 */
|
||||
let queryRangePicker = ref<[string, string]>(['', '']);
|
||||
|
||||
/**查询参数 */
|
||||
let queryParams = reactive({
|
||||
/**告警设备类型 */
|
||||
neType: '',
|
||||
/**告警网元名称 */
|
||||
neName: '',
|
||||
/**告警网元标识 */
|
||||
neId: '',
|
||||
/**告警编号 */
|
||||
alarmCode: '',
|
||||
/**告警级别 */
|
||||
origSeverity: undefined,
|
||||
beginTime: '',
|
||||
endTime: '',
|
||||
/**告警产生时间 */
|
||||
eventTime: '',
|
||||
/**虚拟化标识 */
|
||||
pvFlag: undefined,
|
||||
/**告警类型 */
|
||||
alarmType: undefined,
|
||||
/**当前页数 */
|
||||
pageNum: 1,
|
||||
/**每页条数 */
|
||||
pageSize: 20,
|
||||
});
|
||||
|
||||
/**查询参数重置 */
|
||||
function fnQueryReset() {
|
||||
queryParams = Object.assign(queryParams, {
|
||||
/**告警设备类型 */
|
||||
neType: '',
|
||||
/**告警网元名称 */
|
||||
neName: '',
|
||||
/**告警网元标识 */
|
||||
neId: '',
|
||||
/**告警编号 */
|
||||
alarmCode: '',
|
||||
/**告警级别 */
|
||||
origSeverity: undefined,
|
||||
/**告警产生时间 */
|
||||
eventTime: '',
|
||||
/**虚拟化标识 */
|
||||
pvFlag: undefined,
|
||||
/**告警类型 */
|
||||
alarmType: undefined,
|
||||
/**当前页数 */
|
||||
});
|
||||
tablePagination.current = 1;
|
||||
tablePagination.pageSize = 20;
|
||||
fnGetList();
|
||||
}
|
||||
|
||||
/**表格状态类型 */
|
||||
type TabeStateType = {
|
||||
/**加载等待 */
|
||||
loading: boolean;
|
||||
/**紧凑型 */
|
||||
size: SizeType;
|
||||
/**搜索栏 */
|
||||
seached: boolean;
|
||||
/**记录数据 */
|
||||
data: object[];
|
||||
/**勾选记录 */
|
||||
selectedRowKeys: (string | number)[];
|
||||
};
|
||||
|
||||
/**表格状态 */
|
||||
let tableState: TabeStateType = reactive({
|
||||
loading: false,
|
||||
size: 'middle',
|
||||
seached: false,
|
||||
data: [],
|
||||
selectedRowKeys: [],
|
||||
});
|
||||
|
||||
/**表格字段列 */
|
||||
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.alarmCode'),
|
||||
dataIndex: 'alarmCode',
|
||||
align: 'center',
|
||||
width: 5,
|
||||
},
|
||||
{
|
||||
title: t('views.faultManage.activeAlarm.alarmTitle'),
|
||||
dataIndex: 'alarmTitle',
|
||||
align: 'left',
|
||||
width: 5,
|
||||
},
|
||||
{
|
||||
title: t('views.faultManage.activeAlarm.eventTime'),
|
||||
dataIndex: 'eventTime',
|
||||
align: 'center',
|
||||
sorter: (a: any, b: any) => 1,
|
||||
width: 5,
|
||||
},
|
||||
{
|
||||
title: t('views.faultManage.activeAlarm.pvFlag'),
|
||||
dataIndex: 'pvFlag',
|
||||
align: 'center',
|
||||
width: 5,
|
||||
},
|
||||
{
|
||||
title: t('common.operate'),
|
||||
key: 'alarm_id',
|
||||
align: 'center',
|
||||
fixed: 'right',
|
||||
width: 5,
|
||||
},
|
||||
];
|
||||
|
||||
/**表格分页器参数 */
|
||||
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;
|
||||
}
|
||||
|
||||
/**对话框对象信息状态类型 */
|
||||
type ModalStateType = {
|
||||
/**详情框是否显示 */
|
||||
visibleByView: boolean;
|
||||
/**新增框或修改框是否显示 */
|
||||
visibleByEdit: boolean;
|
||||
/**显示过滤设置是否显示 */
|
||||
visibleByShowSet: boolean;
|
||||
/**个性化设置置是否显示 */
|
||||
visibleByMyselfSet: boolean;
|
||||
/**标题 */
|
||||
title: string;
|
||||
/**表单数据 */
|
||||
from: Record<string, any>;
|
||||
/**表单数据 */
|
||||
showSetFrom: Record<string, any>;
|
||||
/**确定按钮 loading */
|
||||
confirmLoading: boolean;
|
||||
};
|
||||
|
||||
/**对话框对象信息状态 */
|
||||
let modalState: ModalStateType = reactive({
|
||||
visibleByView: false,
|
||||
visibleByEdit: false,
|
||||
visibleByShowSet: false,
|
||||
visibleByMyselfSet: false,
|
||||
title: '全部信息',
|
||||
from: {
|
||||
alarmId: '',
|
||||
alarmSeq: '',
|
||||
neId: '',
|
||||
neName: '',
|
||||
neType: '',
|
||||
alarmCode: '',
|
||||
alarmTitle: '',
|
||||
eventTime: '',
|
||||
alarmType: '',
|
||||
pvFlag: '',
|
||||
objectName: '',
|
||||
locationInfo: '',
|
||||
province: '',
|
||||
alarmStatus: '',
|
||||
specificProblemId: '',
|
||||
specificProblem: '',
|
||||
addInfo: '',
|
||||
clearType: '',
|
||||
clearTime: '',
|
||||
ackState: '',
|
||||
ackUser: '',
|
||||
ackTime: '',
|
||||
origSeverity: '',
|
||||
},
|
||||
showSetFrom: {
|
||||
ne_type: '',
|
||||
ne_id: '',
|
||||
alarm_type: '',
|
||||
orig_severity: '',
|
||||
alarm_code: '',
|
||||
pv_flag: '',
|
||||
},
|
||||
// myselfSetFrom:{
|
||||
|
||||
// }
|
||||
confirmLoading: false,
|
||||
});
|
||||
|
||||
/**
|
||||
* 对话框弹出显示为 查看
|
||||
* @param row 单行记录信息
|
||||
*/
|
||||
function fnModalVisibleByVive(row: Record<string, any>) {
|
||||
modalState.from = Object.assign(modalState.from, row);
|
||||
modalState.from.clearType = `${modalState.from.clearType}`;
|
||||
modalState.from.ackState = `${modalState.from.ackState}`;
|
||||
modalState.title = t('views.faultManage.activeAlarm.viewIdInfo', {
|
||||
alarmId: row.alarmId,
|
||||
});
|
||||
modalState.visibleByView = true;
|
||||
}
|
||||
|
||||
/**表格状态 */
|
||||
const state = reactive<{
|
||||
selectedRowKeys: (string | number)[];
|
||||
selectedRow: Record<string, any>;
|
||||
loading: boolean;
|
||||
}>({
|
||||
selectedRowKeys: [], // Check here to configure the default column
|
||||
selectedRow: {},
|
||||
loading: false,
|
||||
});
|
||||
|
||||
/**监听多选 */
|
||||
const onSelectChange = (
|
||||
keys: (string | number)[],
|
||||
record: Record<string, any>
|
||||
) => {
|
||||
state.selectedRowKeys = keys;
|
||||
state.selectedRow = record;
|
||||
};
|
||||
|
||||
/**
|
||||
* 导出全部
|
||||
*/
|
||||
function fnExportAll() {
|
||||
Modal.confirm({
|
||||
title: 'Tip',
|
||||
content: t('views.faultManage.eventAlarm.exportSure'),
|
||||
onOk() {
|
||||
const key = 'exportAlarm';
|
||||
message.loading({ content: t('common.loading'), key });
|
||||
let sortArr: any = [];
|
||||
tableColumnsDnd.value.forEach((item: any) => {
|
||||
if (item.dataIndex) sortArr.push(item.dataIndex);
|
||||
});
|
||||
|
||||
// 排序字段
|
||||
const sortData = {
|
||||
header: sortArr,
|
||||
};
|
||||
|
||||
exportAll(queryParams).then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS) {
|
||||
res.data = res.data.map((objA: any) => {
|
||||
let filteredObj: any = {};
|
||||
sortArr.forEach((key: any) => {
|
||||
if (objA.hasOwnProperty(key)) {
|
||||
filteredObj[key] = objA[key];
|
||||
}
|
||||
});
|
||||
dict.activeAckState.map((item: any) => {
|
||||
if (item.value === `${filteredObj.ackState}`)
|
||||
filteredObj.ackState = item.label;
|
||||
});
|
||||
|
||||
return filteredObj;
|
||||
});
|
||||
message.success({
|
||||
content: t('common.msgSuccess', { msg: t('common.export') }),
|
||||
key,
|
||||
duration: 3,
|
||||
});
|
||||
writeSheet(res.data, 'alarm', sortData).then(fileBlob =>
|
||||
saveAs(fileBlob, `evnet_${Date.now()}.xlsx`)
|
||||
);
|
||||
} else {
|
||||
message.error({
|
||||
content: `${res.msg}`,
|
||||
key,
|
||||
duration: 3,
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 对话框弹出关闭执行函数
|
||||
* 进行表达规则校验
|
||||
*/
|
||||
function fnModalCancel() {
|
||||
modalState.visibleByEdit = false;
|
||||
modalState.visibleByView = false;
|
||||
}
|
||||
|
||||
/**查询列表, pageNum初始页数 */
|
||||
function fnGetList(pageNum?: number) {
|
||||
if (tableState.loading) return;
|
||||
tableState.loading = true;
|
||||
if (pageNum) {
|
||||
queryParams.pageNum = pageNum;
|
||||
}
|
||||
if (!queryRangePicker.value) {
|
||||
queryRangePicker.value = ['', ''];
|
||||
}
|
||||
queryParams.beginTime = queryRangePicker.value[0];
|
||||
queryParams.endTime = queryRangePicker.value[1];
|
||||
|
||||
listAct(toRaw(queryParams)).then((res: any) => {
|
||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
|
||||
// 取消勾选
|
||||
if (state.selectedRowKeys.length > 0) {
|
||||
state.selectedRowKeys = [];
|
||||
}
|
||||
////
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
tablePagination.total = 0;
|
||||
tableState.data = [];
|
||||
}
|
||||
tableState.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 初始字典数据
|
||||
Promise.allSettled([
|
||||
getDict('active_alarm_type'),
|
||||
getDict('active_clear_type'),
|
||||
getDict('active_ack_state'),
|
||||
getDict('active_alarm_severity'),
|
||||
]).then(resArr => {
|
||||
if (resArr[0].status === 'fulfilled') {
|
||||
dict.activeAlarmType = resArr[0].value;
|
||||
}
|
||||
if (resArr[1].status === 'fulfilled') {
|
||||
dict.activeClearType = resArr[1].value;
|
||||
}
|
||||
if (resArr[2].status === 'fulfilled') {
|
||||
dict.activeAckState = resArr[2].value;
|
||||
}
|
||||
if (resArr[3].status === 'fulfilled') {
|
||||
dict.activeAlarmSeverity = resArr[3].value;
|
||||
}
|
||||
});
|
||||
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.faultManage.activeAlarm.neType')"
|
||||
name="ne_type"
|
||||
>
|
||||
<a-input v-model:value="queryParams.neType" allow-clear></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="6" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.faultManage.activeAlarm.neName')"
|
||||
name="ne_name"
|
||||
>
|
||||
<a-input v-model:value="queryParams.neName" allow-clear></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="6" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.faultManage.activeAlarm.neId')"
|
||||
name="ne_id"
|
||||
>
|
||||
<a-input v-model:value="queryParams.neId" allow-clear></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-row :gutter="16">
|
||||
<a-col :lg="6" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.faultManage.activeAlarm.alarmCode')"
|
||||
name="alarm_code"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="queryParams.alarmCode"
|
||||
allow-clear
|
||||
></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="6" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.faultManage.activeAlarm.pvFlag')"
|
||||
name="pv_flag"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="queryParams.pvFlag"
|
||||
:placeholder="t('common.selectPlease')"
|
||||
:options="[
|
||||
{ label: 'PNF', value: 'PNF' },
|
||||
{ label: 'VNF', value: 'VNF' },
|
||||
]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="6" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.faultManage.activeAlarm.eventTime')"
|
||||
name="eventTime"
|
||||
>
|
||||
<a-range-picker
|
||||
v-model:value="queryRangePicker"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
show-time
|
||||
style="width: 400px"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="16">
|
||||
<a-col :lg="6" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.faultManage.activeAlarm.alarmType')"
|
||||
name="alarm_type"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="queryParams.alarmType"
|
||||
:placeholder="t('common.selectPlease')"
|
||||
:options="dict.activeAlarmType"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</a-card>
|
||||
|
||||
<a-card :bordered="false" :body-style="{ padding: '0px' }">
|
||||
<!-- 插槽-卡片左侧侧 -->
|
||||
<template #title>
|
||||
<div class="button-container">
|
||||
<a-button
|
||||
type="primary"
|
||||
@click.prevent="fnExportAll()"
|
||||
:disabled="tableState.data.length <= 0"
|
||||
>
|
||||
<template #icon> <export-outlined /> </template>
|
||||
{{ t('views.faultManage.activeAlarm.exportAll') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 插槽-卡片右侧 -->
|
||||
<template #extra>
|
||||
<div class="button-container">
|
||||
<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>
|
||||
<TableColumnsDnd
|
||||
cache-id="alarmActive"
|
||||
:columns="tableColumns"
|
||||
v-model:columns-dnd="tableColumnsDnd"
|
||||
></TableColumnsDnd>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 表格列表 -->
|
||||
<a-table
|
||||
class="table"
|
||||
row-key="id"
|
||||
:columns="tableColumnsDnd"
|
||||
:loading="tableState.loading"
|
||||
:data-source="tableState.data"
|
||||
:size="tableState.size"
|
||||
:row-selection="{
|
||||
columnWidth: 2,
|
||||
selectedRowKeys: state.selectedRowKeys,
|
||||
onChange: onSelectChange,
|
||||
}"
|
||||
:pagination="tablePagination"
|
||||
:scroll="{ x: 2500, y: 400 }"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'origSeverity'">
|
||||
<DictTag
|
||||
:options="dict.activeAlarmSeverity"
|
||||
:value="record.origSeverity"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="column.key === 'alarmType'">
|
||||
<DictTag
|
||||
:options="dict.activeAlarmType"
|
||||
:value="record.alarmType"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="column.key === 'clearType'">
|
||||
<DictTag
|
||||
:options="dict.activeClearType"
|
||||
:value="record.clearType"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="column.key === 'ackState'">
|
||||
<DictTag :options="dict.activeAckState" :value="record.ackState" />
|
||||
</template>
|
||||
<template v-if="column.key === 'alarm_id'">
|
||||
<a-space :size="8" align="center">
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.viewText') }}</template>
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnModalVisibleByVive(record)"
|
||||
>
|
||||
<template #icon><InfoCircleOutlined /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
|
||||
<!-- 详情框 -->
|
||||
<a-modal
|
||||
width="800px"
|
||||
:body-style="{ height: '520px', overflowY: 'scroll' }"
|
||||
:keyboard="false"
|
||||
:mask-closable="false"
|
||||
:visible="modalState.visibleByView"
|
||||
:title="modalState.title"
|
||||
:confirm-loading="modalState.confirmLoading"
|
||||
@cancel="fnModalCancel"
|
||||
>
|
||||
<template v-slot:footer>
|
||||
<a-button @click="fnModalCancel">{{
|
||||
t('views.faultManage.activeAlarm.closeModal')
|
||||
}}</a-button>
|
||||
</template>
|
||||
|
||||
<a-form
|
||||
name="modalStateFrom"
|
||||
layout="horizontal"
|
||||
:label-col="{ span: 8 }"
|
||||
:label-wrap="true"
|
||||
>
|
||||
<a-row :gutter="16">
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.faultManage.activeAlarm.alarmId')"
|
||||
name="alarmId"
|
||||
>
|
||||
{{ modalState.from.alarmId }}
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.faultManage.activeAlarm.alarmSeq')"
|
||||
name="alarmSeq"
|
||||
>
|
||||
{{ modalState.from.alarmSeq }}
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-row :gutter="16">
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.faultManage.activeAlarm.neId')"
|
||||
name="neId"
|
||||
>
|
||||
{{ modalState.from.neId }}
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.faultManage.activeAlarm.neName')"
|
||||
name="neName"
|
||||
>
|
||||
{{ modalState.from.neName }}
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-row :gutter="16">
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.faultManage.activeAlarm.neType')"
|
||||
name="neType"
|
||||
>
|
||||
{{ modalState.from.neType }}
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.faultManage.activeAlarm.alarmCode')"
|
||||
name="alarmCode"
|
||||
>
|
||||
{{ modalState.from.alarmCode }}
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-row :gutter="16">
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.faultManage.activeAlarm.alarmTitle')"
|
||||
name="alarmTitle"
|
||||
>
|
||||
{{ modalState.from.alarmTitle }}
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.faultManage.activeAlarm.eventTime')"
|
||||
name="eventTime"
|
||||
>
|
||||
{{ modalState.from.eventTime }}
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-form-item
|
||||
:label="t('views.faultManage.activeAlarm.locationInfo')"
|
||||
name="locationInfo"
|
||||
:label-col="{ span: 4 }"
|
||||
>
|
||||
{{ modalState.from.locationInfo }}
|
||||
</a-form-item>
|
||||
|
||||
<a-row :gutter="16"> </a-row>
|
||||
|
||||
<a-row :gutter="16">
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.faultManage.activeAlarm.province')"
|
||||
name="province"
|
||||
>
|
||||
{{ modalState.from.province }}
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.faultManage.activeAlarm.alarmType')"
|
||||
name="alarmType"
|
||||
>
|
||||
{{ modalState.from.alarmType }}
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-form-item
|
||||
:label="t('views.faultManage.activeAlarm.addInfo')"
|
||||
name="addInfo"
|
||||
:label-col="{ span: 4 }"
|
||||
>
|
||||
{{ modalState.from.addInfo }}
|
||||
</a-form-item>
|
||||
|
||||
<a-row :gutter="16">
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.faultManage.activeAlarm.specificProblemId')"
|
||||
name="specificProblemId"
|
||||
>
|
||||
{{ modalState.from.specificProblemId }}
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col :lg="12" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.faultManage.activeAlarm.objectName')"
|
||||
name="objectName"
|
||||
>
|
||||
{{ modalState.from.objectName }}
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-form-item
|
||||
:label="t('views.faultManage.activeAlarm.specificProblem')"
|
||||
name="specificProblem"
|
||||
:label-col="{ span: 4 }"
|
||||
>
|
||||
{{ modalState.from.specificProblem }}
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</PageContainer>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.table :deep(.ant-pagination) {
|
||||
padding: 0 24px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
.full-modal {
|
||||
.ant-modal {
|
||||
max-width: 100%;
|
||||
top: 0;
|
||||
padding-bottom: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.ant-modal-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: calc(100vh);
|
||||
}
|
||||
.ant-modal-body {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -755,6 +755,7 @@ onMounted(() => {
|
||||
</a-dropdown>
|
||||
</a-tooltip>
|
||||
<TableColumnsDnd
|
||||
cache-id="alarmHistory"
|
||||
:columns="tableColumns"
|
||||
v-model:columns-dnd="tableColumnsDnd"
|
||||
></TableColumnsDnd>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { PageContainer } from 'antdv-pro-layout';
|
||||
import { ColumnsType } from 'ant-design-vue/lib/table';
|
||||
import { message } from 'ant-design-vue/lib';
|
||||
import { reactive, toRaw, ref, onMounted, onBeforeUnmount } from 'vue';
|
||||
import { reactive, toRaw, ref, onMounted, onBeforeUnmount, markRaw } from 'vue';
|
||||
import { listMain } from '@/api/index';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
import { TooltipComponent } from 'echarts/components';
|
||||
@@ -30,6 +30,12 @@ echarts.use([
|
||||
LabelLayout,
|
||||
]);
|
||||
|
||||
/**图DOM节点实例对象 */
|
||||
const statusBar = ref<HTMLElement | undefined>(undefined);
|
||||
|
||||
/**图实例对象 */
|
||||
const statusBarChart = ref<any>(null);
|
||||
|
||||
/**网元状态字典数据 */
|
||||
let indexColor = ref<DictType[]>([
|
||||
{ label: 'Normal', value: 'normal', elTagType: '', elTagClass: '#91cc75' },
|
||||
@@ -74,6 +80,11 @@ let tableColumns: ColumnsType = [
|
||||
dataIndex: 'serialNum',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: t('views.index.expiryDate'),
|
||||
dataIndex: 'expiryDate',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: t('views.index.ipAddress'),
|
||||
dataIndex: 'ipAddress',
|
||||
@@ -87,8 +98,6 @@ type TabeStateType = {
|
||||
loading: boolean;
|
||||
/**紧凑型 */
|
||||
size: string;
|
||||
/**斑马纹 */
|
||||
striped: boolean;
|
||||
/**搜索栏 */
|
||||
seached: boolean;
|
||||
/**记录数据 */
|
||||
@@ -101,7 +110,6 @@ type TabeStateType = {
|
||||
let tableState: TabeStateType = reactive({
|
||||
loading: false,
|
||||
size: 'middle',
|
||||
striped: false,
|
||||
seached: false,
|
||||
data: [],
|
||||
selectedRowKeys: [],
|
||||
@@ -176,17 +184,7 @@ function fnGetList(one: boolean) {
|
||||
}
|
||||
}
|
||||
|
||||
var chartDom: any = document.getElementById('echarts-records');
|
||||
var existingChart = echarts.getInstanceByDom(chartDom);
|
||||
var myChart: any;
|
||||
if (existingChart) {
|
||||
myChart = existingChart;
|
||||
myChart.clear(); // 清空图表,重新设置数据
|
||||
} else {
|
||||
myChart = echarts.init(chartDom);
|
||||
}
|
||||
|
||||
var option = {
|
||||
const optionData: any = {
|
||||
title: {
|
||||
text: '',
|
||||
subtext: '',
|
||||
@@ -223,14 +221,28 @@ function fnGetList(one: boolean) {
|
||||
],
|
||||
};
|
||||
|
||||
option && myChart.setOption(option);
|
||||
window.onresize = function () {
|
||||
// echarts 窗口缩放自适应 随着div--echarts-records的大小来适应
|
||||
myChart.resize();
|
||||
};
|
||||
fnDesign(statusBar.value, optionData);
|
||||
});
|
||||
}
|
||||
|
||||
function fnDesign(container: HTMLElement | undefined, option: any) {
|
||||
if (!container) return;
|
||||
|
||||
if (!statusBarChart.value) {
|
||||
statusBarChart.value = markRaw(echarts.init(container, 'light'));
|
||||
}
|
||||
option && statusBarChart.value.setOption(option);
|
||||
|
||||
// 创建 ResizeObserver 实例
|
||||
var observer = new ResizeObserver(entries => {
|
||||
if (statusBarChart.value) {
|
||||
statusBarChart.value.resize();
|
||||
}
|
||||
});
|
||||
// 监听元素大小变化
|
||||
observer.observe(container);
|
||||
}
|
||||
|
||||
/**抽屉 网元详细信息 */
|
||||
const visible = ref(false);
|
||||
const closeDrawer = () => {
|
||||
@@ -250,6 +262,16 @@ function rowClick(record: any, index: any) {
|
||||
return false;
|
||||
} else {
|
||||
let pronData = toRaw(record);
|
||||
const totalMemInKB = pronData.memUsage?.totalMem;
|
||||
const nfUsedMemInKB = pronData.memUsage?.nfUsedMem;
|
||||
const sysMemUsageInKB = pronData.memUsage?.sysMemUsage;
|
||||
|
||||
// 将KB转换为MB
|
||||
const totalMemInMB = Math.round((totalMemInKB / 1024) * 100) / 100;
|
||||
const nfUsedMemInMB = Math.round((nfUsedMemInKB / 1024) * 100) / 100;
|
||||
const sysMemUsageInMB =
|
||||
Math.round((sysMemUsageInKB / 1024) * 100) / 100;
|
||||
|
||||
//渲染详细信息
|
||||
pronInfo = {
|
||||
hostName: pronData.hostName,
|
||||
@@ -268,14 +290,14 @@ function rowClick(record: any, index: any) {
|
||||
'%',
|
||||
memoryUse:
|
||||
'Total:' +
|
||||
pronData.memUsage?.totalMem +
|
||||
'KB; ' +
|
||||
totalMemInMB +
|
||||
'MB; ' +
|
||||
pronData.name +
|
||||
':' +
|
||||
pronData.memUsage?.nfUsedMem +
|
||||
'KB; SYS:' +
|
||||
pronData.memUsage?.sysMemUsage +
|
||||
'KB',
|
||||
nfUsedMemInMB +
|
||||
'MB; SYS:' +
|
||||
sysMemUsageInMB +
|
||||
'MB',
|
||||
capability: pronData.capability,
|
||||
serialNum: pronData.serialNum,
|
||||
expiryDate: pronData.expiryDate,
|
||||
@@ -389,8 +411,8 @@ onBeforeUnmount(() => {
|
||||
<a-col :lg="10" :md="8" :xs="24">
|
||||
<a-card :title="t('views.index.runStatus')" style="margin-bottom: 16px">
|
||||
<div
|
||||
id="echarts-records"
|
||||
style="width: 100%; min-height: 200px"
|
||||
ref="statusBar"
|
||||
></div>
|
||||
</a-card>
|
||||
<a-card :title="t('views.index.mark')" style="margin-top: 16px">
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user