Compare commits

...

157 Commits

Author SHA1 Message Date
chenj
c7366ef745 fix: 图表重复点击tab坍缩问题 2022-12-05 20:12:04 +08:00
陈劲松
064001c4ab Merge branch 'cherry-pick-ed6e1f26' into 'dev-22.11'
fix:优化LinkBlock右侧蜂窝图数据去重

See merge request cyber-narrator/cn-ui!17
2022-12-05 11:59:17 +00:00
刘洪洪
eb92ef9ea8 fix:优化LinkBlock右侧蜂窝图数据去重
(cherry picked from commit ed6e1f26fb)
2022-12-05 19:59:10 +08:00
陈劲松
cb0546ebb2 Merge branch 'cherry-pick-aa1c16ab' into 'dev-22.11'
fix:修复LinkBlock右侧蜂窝图不显示的问题

See merge request cyber-narrator/cn-ui!16
2022-12-05 11:58:56 +00:00
刘洪洪
9ca2950d68 fix:修复LinkBlock右侧蜂窝图不显示的问题
(cherry picked from commit aa1c16aba3)
2022-12-05 19:58:50 +08:00
陈劲松
533f7d357d Merge branch 'cherry-pick-31187404' into 'dev-22.11'
fix:修复NetworkOverviewTabs报错时message字段使用

See merge request cyber-narrator/cn-ui!15
2022-12-05 11:58:36 +00:00
刘洪洪
efa899da2c fix:修复NetworkOverviewTabs报错时message字段使用
(cherry picked from commit 31187404f2)
2022-12-05 19:57:54 +08:00
陈劲松
c35965061f Merge branch 'cherry-pick-e026fb3c' into 'dev-22.11'
style: el-tab组件table列表首列标题向左顶格

See merge request cyber-narrator/cn-ui!14
2022-12-05 11:57:34 +00:00
changcode
19677ba521 style: el-tab组件table列表首列标题向左顶格
(cherry picked from commit e026fb3cfd)
2022-12-05 19:57:27 +08:00
陈劲松
7c1729ca63 Merge branch 'cherry-pick-7ec4ab62' into 'dev-22.11'
fix: CN-817 下钻table的error交互实施:错误图标显示后消失问题修正

See merge request cyber-narrator/cn-ui!13
2022-12-05 07:39:57 +00:00
hyx
1c6e28a200 fix: CN-817 下钻table的error交互实施:错误图标显示后消失问题修正
(cherry picked from commit 7ec4ab62ff)
2022-12-05 15:39:34 +08:00
陈劲松
fa746fd95b Merge branch 'cherry-pick-5818485f' into 'dev-22.11'
CN-820 npm 下钻ip维度:直接进入as a client时没数据

See merge request cyber-narrator/cn-ui!12
2022-12-05 07:04:56 +00:00
hyx
0a5fe3029c CN-820 npm 下钻ip维度:直接进入as a client时没数据
(cherry picked from commit 5818485f3f)
2022-12-05 15:04:09 +08:00
陈劲松
61357f2720 Merge branch 'cherry-pick-49e08f72' into 'dev-22.11'
CN-817 下钻table的error交互实施

See merge request cyber-narrator/cn-ui!11
2022-12-05 07:03:16 +00:00
hyx
9bc9103925 CN-817 下钻table的error交互实施
(cherry picked from commit 49e08f723a)
2022-12-05 15:03:01 +08:00
陈劲松
f0ea7e28fc Merge branch 'cherry-pick-e89fc78a' into 'dev-22.11'
CN-815: 前端内存占用分析

See merge request cyber-narrator/cn-ui!10
2022-12-05 07:02:31 +00:00
刘洪洪
cf5bfb4136 CN-815: 前端内存占用分析
(cherry picked from commit e89fc78aca)
2022-12-05 15:02:14 +08:00
陈劲松
ef6c95e536 Merge branch 'cherry-pick-2cf206de' into 'dev-22.11'
CN-816 下钻table分数列排序功能无法使用

See merge request cyber-narrator/cn-ui!9
2022-12-05 03:42:21 +00:00
hyx
29fe3bc3ef CN-816 下钻table分数列排序功能无法使用
(cherry picked from commit 2cf206de5a)
2022-12-05 11:42:14 +08:00
陈劲松
85830dc7ca Merge branch 'cherry-pick-82bd184b' into 'dev-22.11'
fix: 解决链路图切换时间后接口无数据,界面仍保留之前数据的问题

See merge request cyber-narrator/cn-ui!8
2022-12-05 03:41:38 +00:00
刘洪洪
f1423b6b62 fix: 解决链路图切换时间后接口无数据,界面仍保留之前数据的问题
(cherry picked from commit 82bd184bdd)
2022-12-05 11:41:28 +08:00
chenj
8b2e1e95db CN-820 fix: 修复地图报错问题 2022-12-01 17:00:48 +08:00
陈劲松
a1b7527496 Merge branch 'cherry-pick-0f600b44' into 'dev-22.11'
fix: npm ip下钻补充默认值

See merge request cyber-narrator/cn-ui!7
2022-12-01 08:39:59 +00:00
@changcode
e93345ea2a fix: npm ip下钻补充默认值
(cherry picked from commit 0f600b44ac)
2022-12-01 16:39:49 +08:00
changcode
2b3e5ca360 fix: 修复npm下钻 时间变化后,顶部的分数计算方法未能触发问题 2022-11-28 16:41:31 +08:00
changcode
8f045125ea fix: 修复 npm下钻和非下钻 性能统计父组件数据变化后子组件无法获取问题 2022-11-28 16:36:05 +08:00
hyx
aa06553b17 CN-813 NPM的IP下钻页,TAB在as server上时,url不能保留这个状态 2022-11-28 09:20:41 +08:00
hyx
9e2aa20303 Revert "CN-733 完成链路页面下钻后的表格"
This reverts commit 1e77c694
2022-11-28 09:18:33 +08:00
hyx
1e77c69460 CN-733 完成链路页面下钻后的表格 2022-11-28 09:09:44 +08:00
changcode
d25912b2ce CN-812 feat: npm下钻三级菜单网络性能接口,前端对应逻辑优化调整 2022-11-25 16:08:32 +08:00
changcode
c7eacdd6f6 fix: npm 下钻相关会话计算逻辑调整 2022-11-25 11:10:08 +08:00
刘洪洪
09edc8961c fix: NpmAppEventTable去除error模拟数据 2022-11-24 15:26:14 +08:00
刘洪洪
8e698f3b78 fix: 部分文件添加error处理 2022-11-24 14:10:28 +08:00
刘洪洪
e2d6707249 fix: NpmNetworkQuantity模块去除模拟数据 2022-11-24 11:03:53 +08:00
刘洪洪
a381f5a01b fix: NpmNetworkQuantity模块添加error处理 2022-11-24 11:02:06 +08:00
刘洪洪
1ac910fc54 feat: SingleValue精简代码 2022-11-24 09:48:17 +08:00
刘洪洪
7d9829ae27 fix: npm模块下文件请求做error处理 2022-11-23 17:20:37 +08:00
changcode
16a255be50 CN-811 feat: networkoverview下钻第三级菜单折线图请求参数调整 2022-11-23 16:51:38 +08:00
@changcode
ae4ce44eff fix: tab选项卡折线图,数据为空时去除移入点击效果 2022-11-22 17:58:15 +08:00
@changcode
bf008fe944 fix: 修复tab选项卡平局数为0时消毁当前tab选项卡时,参考线无默认值问题 2022-11-22 15:01:30 +08:00
刘洪洪
2cae53e83a fix: Detection模块修改icon图标名 2022-11-22 10:52:30 +08:00
刘洪洪
fa8ea9dce0 fix: Error组件修改提示框窗样式 2022-11-22 10:49:35 +08:00
hyx
d5298347d8 fix:DNS下钻表格的流入流出查询次数百分比图显示,在0%的时候仍然有显示 2022-11-21 18:34:07 +08:00
刘洪洪
248075cd81 fix: Error组件修改调用方式注释 2022-11-21 17:39:35 +08:00
刘洪洪
c3ffd01363 fix: 请求添加error处理 2022-11-21 17:31:30 +08:00
hyx
69735e438f DNS的qtype和rcode维度信息查询优化 2022-11-21 11:28:56 +08:00
刘洪洪
8e221414b8 fix: 通用Error组件添加注释 2022-11-18 16:59:37 +08:00
刘洪洪
8d461ef200 fix: Related sessions模块精简代码 2022-11-18 16:39:10 +08:00
刘洪洪
0f5bd8a7a7 fix: Related sessions模块精简代码 2022-11-18 16:37:11 +08:00
刘洪洪
ebf1228c68 fix: 修复当数据返回为-时,Related sessions灰条不显示的问题,以及切换时间,dom未做修改的问题 2022-11-18 16:25:55 +08:00
@changcode
cdd48102a5 style: 修复npm下钻 关联session图样式问题 2022-11-18 16:14:00 +08:00
@changcode
6ba21507f7 Merge branch 'dev' of https://git.mesalab.cn/cyber-narrator/cn-ui into dev 2022-11-18 15:18:41 +08:00
@changcode
90ee54c3ad fix: 1.npm tab为location折线图数据为空时ecahrts图加载报错2.npm 下钻世界地图接口参数错误和tab切换未正常禁用问题 2022-11-18 15:18:12 +08:00
刘洪洪
5e03847a42 CN-802:error交互实施 2022-11-18 15:18:05 +08:00
hyx
4c107704e7 CN-801 下钻table的配置增加版本属性 2022-11-18 14:21:23 +08:00
@changcode
4975f2425d fix: 1.npm地图分数补充占位复2.npm下钻3级菜单接口请求错误修复 2022-11-17 15:55:34 +08:00
hyx
2b34f8bc26 对数据中的双引号和&进行特殊处理;panelName显示异常; 2022-11-17 15:21:17 +08:00
刘洪洪
7c4b16d443 fix: 更新iconfont图标 2022-11-16 18:20:19 +08:00
@changcode
57b607fca5 CN-803 fix: 批量查询参数格式变更 2022-11-16 18:10:48 +08:00
hyx
c30f6e642a CN-799 部分接口param参数内容本身带逗号时查询不准确的问题 2022-11-16 16:59:52 +08:00
@changcode
8416060fc4 fix: 修复 npm下钻tab为 Client Cities和Server Cities时,接口请求参数错误问题 2022-11-16 11:55:11 +08:00
@changcode
45c318b391 fix: 修复echarts 配置误删问题 2022-11-16 11:16:46 +08:00
@changcode
3ec3873860 fix: 修复npm location 地图国家切换后,有为空的折线图报错不展示问题 2022-11-16 10:33:52 +08:00
刘洪洪
5a1f177ae1 fix: Detection模块右侧tab的图标自适应居中 2022-11-15 18:33:07 +08:00
刘洪洪
820c86a3d3 fix: Detection模块中的筛选模块名称换i18n 2022-11-15 17:09:35 +08:00
hyx
b4b7edb18f CN-798:1.npm clientip serverip下钻后应该跳到和ip一样的二级页面,默认高亮与之对应的顶部tab 2022-11-15 17:06:47 +08:00
刘洪洪
0a3cf92ce9 fix: Detection模块按UI调整部分样式 2022-11-15 17:00:12 +08:00
刘洪洪
5ecf096e40 fix:Detection模块调整部分样式 2022-11-15 11:36:40 +08:00
@changcode
aee521d5bc fix: npm下钻tab为client ip和server ip接口请求参数调整 2022-11-15 11:13:11 +08:00
@changcode
35fcbab852 fix: 修复apps tab切换判断导致的loading一直存在,apps列表删除问题 2022-11-14 17:12:13 +08:00
hyx
9f6a98779b CN-798 下钻table新增一系列维度后的问题:npm在customize里勾选client ip、client country等新增的维度后,没有被缓存;新增client asn和server asn维度; 2022-11-14 14:35:14 +08:00
@changcode
d44b406222 fix: npm顶部分数计算方法,限制为只有在npm下钻时才触发 2022-11-11 17:37:07 +08:00
@changcode
37ce944dc1 fix: npm 下钻接口请求 side 参数根据 tabIndex 判断赋值 2022-11-11 15:25:12 +08:00
liuhonghong
c322059c97 fix:回退保留状态弃用window,使用store 2022-11-11 15:17:44 +08:00
@changcode
323ccae196 fix: 折线图,tab展示判断逻辑使用 parseFloat 函数 2022-11-11 10:33:00 +08:00
hyx
d1beba7782 CN-774 维度表相关优化:除DNS Dashboard之外,其他各界面的维度表增加以下可选维度的统计(默认不显示,支持用户勾选) 2022-11-11 09:37:32 +08:00
@changcode
0fb496c349 CN-789 fix: 修复NPM ip下钻后,顶部的分数问题 2022-11-10 17:20:00 +08:00
chenjinsong
ef069e7fbc fix: 修复下钻table配置bug 2022-11-10 15:29:12 +08:00
@changcode
40e1e5da16 Merge branch 'dev' of https://git.mesalab.cn/cyber-narrator/cn-ui into dev 2022-11-09 17:44:59 +08:00
@changcode
e996963635 fix: 修复Network Overview apps 部分逻辑及折线图移入弹出框样式 2022-11-09 17:44:48 +08:00
刘洪洪
aa6d5f1598 fix: 隐藏框选工具栏 2022-11-09 17:41:19 +08:00
刘洪洪
39edceb0dd CN-773: 曲线图支持框选缩放 2022-11-09 17:23:31 +08:00
刘洪洪
e355eb31cd fix: detection模块中,调整因修改公共class导致的其他界面样式错乱,以及tab图标不居中的问题 2022-11-09 15:42:36 +08:00
hyx
3e4cc199a6 CN-774 维度表相关优化:Top选择50后,由于增加了滑动条,宽度和高度产生变化;排序功能,不论是否显示Top50,都按50条数据来排序; 2022-11-09 15:22:09 +08:00
陈劲松
faabc949c0 Update gitlab-ci.yml file 隐藏左上角的更新记录链接 2022-11-09 02:44:27 +00:00
刘洪洪
809a6b5562 fix: 将class移入公共css中,修改编辑器报红线的代码格式 2022-11-07 15:48:46 +08:00
刘洪洪
21e0f94d19 CN-772: 解决状态保留相关bug 2022-11-07 15:28:25 +08:00
刘洪洪
ec98178d45 CN-784: Detection列表样式按新版UI图修改 2022-11-07 15:25:00 +08:00
@changcode
32a2359e0d fix: 修复npm 折线图和下钻折线图,因名称判断错误导致的移入弹窗样式问题 2022-11-07 10:17:24 +08:00
chenjinsong
c425d87b00 fix: 临时性调整npm line和npm traffic line的legend名字 2022-11-04 12:52:12 +08:00
hyx
34e16fc890 CN-762 DNS service insights 显示建议:修改由dns的qtype及rcode维度转换对应名称的问题所影响的部分(panel名称,顶部四级菜单显示及下拉显示等) 2022-11-04 12:18:26 +08:00
chenjinsong
c0487a708a fix: 修复地图报错 2022-11-04 11:32:49 +08:00
chenjinsong
68596189b4 fix: 删除npm流量曲线标题 2022-11-04 11:26:46 +08:00
@changcode
29d89ee6e4 fix: 去除无用组件,修复部分折线图Reference line闪动问题 2022-11-04 10:31:10 +08:00
@changcode
14c53bd5ad fix: 修复折线图判断逻辑当字段不存在导致的折线图展示错误问题 2022-11-04 10:24:22 +08:00
@changcode
f39c4d8fc4 CN-790 fix: 修复NPM overview折线图metric、legend、内容 对应不上 2022-11-04 10:22:32 +08:00
hyx
6827d4f031 CN-762 DNS service insights 显示建议(dns qtype和rcode维度数据映射及自定义metric名称修改) 2022-11-03 17:51:53 +08:00
@changcode
1cb4c43b9e fix: 修复NetWork OVerview Providers and Applications 时间范围变化后,之前时间范围数据为清除问题 2022-11-03 16:01:32 +08:00
@changcode
e1bf796f0c fix: 修复 Network Overview 指标下拉为sessions/s时,切换其他选项lineTab一直为total问题 2022-11-03 15:36:36 +08:00
chenjinsong
94c15e0933 CN-775 fix: 修改图表标题 2022-11-03 14:49:55 +08:00
@changcode
043b785547 Merge branch 'dev' of https://git.mesalab.cn/cyber-narrator/cn-ui into dev 2022-11-03 11:21:53 +08:00
@changcode
b0b8de2712 fix: 修复折线图表tab反选错误 2022-11-03 11:21:39 +08:00
chenjinsong
93933502e4 CN-775 fix: 修改图表标题 2022-11-03 11:00:41 +08:00
@changcode
e5b636905f fix: 修复link下钻列表分数计算逻辑 2022-11-03 10:56:06 +08:00
@changcode
078ec2f69f CN-787 feat: Dashboard - npm - overview增加一个曲线图 2022-11-02 19:28:11 +08:00
@changcode
7c77c3c79a fix: 修复link下钻折线图左侧列表错误问题 2022-11-02 18:52:33 +08:00
hyx
0d89b3c23b CN-788 下钻table的分数样式、内容展示等调整 2022-11-02 16:26:31 +08:00
@changcode
a6ea1fa4e6 CN-771 feat: network overview metric统一顶部触发 2022-11-02 11:28:25 +08:00
@changcode
70c38fe2de fix: 修复npm下钻网络性能统计数据展示错误问题 2022-11-02 10:59:21 +08:00
@changcode
12b7290ecd fix: 修复折线图数据为空后,保留之前数据的问题 2022-11-01 19:23:17 +08:00
chenjinsong
60cbebe1cc CN-771 fix: metric下拉框背景色调整 2022-11-01 18:05:45 +08:00
chenjinsong
096517e34f fix: 更改app列表环比0的描述 2022-11-01 17:11:55 +08:00
chenjinsong
2020423c0a fix: metric下拉限定在networkoverview 2022-11-01 16:47:42 +08:00
chenjinsong
da03a3658c fix: networkoverview的metric提至顶部 2022-11-01 16:46:11 +08:00
@changcode
45de9c8107 fix: 分数计算方法逻辑错误修复 2022-11-01 14:31:28 +08:00
@changcode
14f661b78f Merge branch 'dev' of https://git.mesalab.cn/cyber-narrator/cn-ui into dev 2022-11-01 14:13:55 +08:00
@changcode
b5718a039f fix: 分数计算逻辑调整 2022-11-01 14:13:47 +08:00
@changcode
6845bb4ea4 fix: 修复network apps 移入效果错误 2022-11-01 14:13:03 +08:00
hyx
5f448c0ccb CN-778 下钻table取值变更: npm、dns、link的throughput列取值改为totalBytes,单位改为byte
CN-776 NPM Dashboard维度表中分数添加颜色标识
2022-11-01 10:33:23 +08:00
hyx
d568c748db CN-748 下钻table缓存功能优化(包括metric和tab结构的变化)
CN-778 总流量、总包、比特速率字段名前端统一
2022-11-01 09:12:14 +08:00
chenjinsong
07e137d5e0 fix: 调整networkoverview provider改为providers 2022-10-31 17:18:00 +08:00
@changcode
3093c3e3a8 fix: network app 更多点击事件切换为鼠标悬浮触发 2022-10-28 15:30:16 +08:00
刘洪洪
db105804b3 fix: 隐藏timeRange时间弹窗的方向标识 2022-10-28 14:46:04 +08:00
刘洪洪
49eb4d42ce fix:解决timeRange刷新后下钻返回时间被重置 2022-10-28 10:28:12 +08:00
刘洪洪
e019f8a02e fix: timeRange添加注释 2022-10-27 16:32:16 +08:00
刘洪洪
e7cf758ffd fix: 解决timeRange下钻后返回时间被重置的问题 2022-10-27 15:47:38 +08:00
@changcode
64610304c1 fix: 修复npm location 折线图,因字段改变导致的报错 2022-10-27 10:47:38 +08:00
刘洪洪
2da2172f03 fix: $dayJs改为全局引用,去除不必要组件引入 2022-10-27 09:48:31 +08:00
刘洪洪
c2c3898d5b CN-746: 更换时间选择器实现方案 2022-10-26 18:59:53 +08:00
@changcode
04e4371ac1 fix: 折线图多个 tab 无数据时,只保留total时默认选中 2022-10-26 18:20:31 +08:00
@changcode
06c86b8172 CN-768 fix: 1.app卡片Bit/s时底下的流量总数的单位需要使用byte2.折线图单个情况默认选中3.network overview 的右上角图表的按钮点击跳转到npm的events 2022-10-25 19:42:48 +08:00
chenjinsong
ced28fd3e7 fix: 调整networkoverview的图表位置,增加app-card图的resize逻辑 2022-10-25 18:41:27 +08:00
@changcode
943d64918d fix: 优化报告列表下拉 loading 位置 2022-10-25 10:31:47 +08:00
@changcode
de5040d9f4 fix: 注释页面中的打印 2022-10-24 18:40:57 +08:00
刘洪洪
64e41c3170 fix: 解决实体界面初始化时,接口会被调用三次的问题 2022-10-24 18:37:10 +08:00
hyx
8bee5301bc CN-760 score跳动问题 2022-10-24 16:51:41 +08:00
hyx
b75e975421 CN-754 下钻table的一些bug:NPM、DNS、Link的throughput列有值,但是显示横杠(我刚更新配置,这个字段的prop改为totalBitsRate,需清一下indexdb缓存) 2022-10-24 14:08:24 +08:00
@changcode
21c3ead654 fix: 修复折线图百分比数据与坐标对不上问题 2022-10-23 10:17:26 +08:00
hyx
74cbcf0d46 CN-754 下钻table的一些bug:城市单引号问题 2022-10-21 21:26:39 +08:00
chenjinsong
2e27cd5add fix: 关闭mock,解决下载pdf空白的问题 2022-10-21 18:10:12 +08:00
@changcode
e2b03c5d7f fix:修复domain 和 app, npm 下钻地图标题问题 2022-10-21 11:52:46 +08:00
hyx
a87b096c1c CN-754 下钻table的一些bug 2022-10-21 10:08:49 +08:00
@changcode
2a6958f61b fix: npm 地理位置折线图 弹框颜色错误问题 2022-10-20 20:13:09 +08:00
刘洪洪
ae8918f7f7 fix: Provider和Applications快捷图表添加标题,以及修改增加提示框名称问题 2022-10-20 16:13:05 +08:00
chenjinsong
f9e6250e2a fix: 下钻表格首列标题为单数 2022-10-20 14:53:50 +08:00
@changcode
bb81059529 CN-758 fix: 修复NPM下钻折线图bug 2022-10-20 14:41:48 +08:00
@changcode
c38b5ef000 fix: npm 下钻折线图切换数据展示错误问题 2022-10-20 13:56:39 +08:00
@changcode
75dd68f403 fix: npm 折线图移入弹框颜色补充 2022-10-20 11:23:32 +08:00
@changcode
e39e24258b fix; 修复折线图因数据问题导致移入弹框颜色错误问题 2022-10-20 11:19:58 +08:00
@changcode
5767fe896b fix: 修复报告Box侧滑Time limit 为 customize,时间限制错误问题 2022-10-19 17:19:39 +08:00
chenjinsong
53fc6475e2 feat: 更改评分规则 2022-10-19 15:55:23 +08:00
hyx
59ae26e078 CN-752 dns下钻后q查询条件有些与文档不符 2022-10-19 15:45:31 +08:00
刘洪洪
15cfd48770 CN-747: http请求支持取消 2022-10-19 15:27:26 +08:00
@changcode
111f731712 fix: 报告Box Time limit 时间限制逻辑调整 2022-10-19 11:16:38 +08:00
@changcode
c5a78887cb fix: 报告box Time limit 为 customize的时候,时间选择器增加限制 2022-10-19 09:57:51 +08:00
chenjinsong
add13f463d fix: 修正dns下钻后折线图的url 2022-10-18 19:14:08 +08:00
@changcode
c1dd39fb66 fix: 报告box time limit 为 customize 时增加时间范围限制 2022-10-18 17:38:37 +08:00
87 changed files with 4682 additions and 2480 deletions

View File

@@ -18,7 +18,7 @@ before_script:
generate_git-log:
stage: gen_git-log
script:
- if (( `grep git-log.html ./public/index.html | wc -l` == 0 )); then sed -i 's+</body>+<a style="position:fixed;top:0;left:0;z-index:999;font-size:12px;color:darkblue;text-decoration:none;" target="_blank" href="./git-log.html">R</a>\n</body>+g' ./public/index.html; echo "添加更新记录链接"; fi;
- if (( `grep git-log.html ./public/index.html | wc -l` == 0 )); then sed -i 's+</body>+<a style="position:fixed;top:0;left:0;z-index:999;font-size:12px;color:transparent;text-decoration:none;display:none;" target="_blank" href="./git-log.html">R</a>\n</body>+g' ./public/index.html; echo "添加更新记录链接"; fi;
- echo "最近的100个提交记录"
- echo "<!DOCTYPE html><html><head><meta charset='utf-8'></head><body><pre>" > ./public/git-log.html
- "git log -100 --pretty=format:'%ad : %s' >> ./public/git-log.html"

View File

@@ -5,6 +5,17 @@
</template>
<script>
import { storageKey } from '@/utils/constants'
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
const timezone = require('dayjs/plugin/timezone')
const advancedFormat = require('dayjs/plugin/advancedFormat')
const weekday = require('dayjs/plugin/weekday')
dayjs.extend(utc)
dayjs.extend(timezone)
dayjs.extend(advancedFormat)
dayjs.extend(weekday)
window.$dayJs = dayjs
export default {
name: 'App',
setup () {

View File

@@ -4,7 +4,7 @@
display: none !important;
}
* {
font-family: NotoSansSChineseRegular;
font-family: NotoSansSChineseRegular, serif;
box-sizing: border-box;
}
html, body, #app {
@@ -43,3 +43,20 @@ body {
.el-form-item__error {
padding-top: 0 !important;
}
/* 请求报错样式关于popover的修改 */
.error-popover {
//min-width: 30px !important;
display: inline-block;
background: #FFE7E6 !important;
border: 1px solid rgba(226,97,84,0.42) !important;
padding: 6.6px 12px !important;
border-radius: 4px !important;
font-size: 14px !important;
color: #F53A19 !important;
font-weight: 400 !important;
line-height: 1.2 !important;
.el-popper__arrow {
display: none !important;
}
}

View File

@@ -71,6 +71,7 @@
white-space: nowrap;
display: inline-block;
margin: 0 5px;
color: #353636;
.cn-icon-Data {
color: #575757;
}
@@ -122,7 +123,8 @@
}
.date-range-history {
height: 116px;
height: 140px;
line-height: 24px;
overflow-y: auto;
.date-range-history-item {

View File

@@ -0,0 +1,80 @@
.error-component {
position: absolute;
//width: 100%;
//height: 100%;
left: 0;
top: 0;
}
.error-block {
display: inline-block;
//width: 100%;
//max-width: calc(100% - 24px);
//max-height: calc(100% - 24px);
//line-height: 24px;
background: #FFE7E6;
font-size: 14px;
color: #F53A19;
font-weight: 400;
padding: 7.6px 12px;
margin: 12px;
z-index: 3;
overflow: hidden;
text-overflow: ellipsis;
//white-space: nowrap;
word-break: break-all;
border: 1px solid rgba(226,97,84,0.42);
border-radius: 4px;
}
.error-block-info {
position: absolute;
width: calc(100% - 20px);
height: calc(100% - 20px);
display: flex;
align-items: center;
justify-content: center;
padding: 10px;
font-size: 14px;
color: #575757;
line-height: 24px;
font-weight: 400;
font-family: NotoSansSChineseRegular, serif;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
}
.new-error-icon {
position: relative;
display: inline-block;
}
.new-error-icon .error-content {
position: absolute;
z-index: 2;
top: -42px;
left: 0;
visibility: hidden;
max-width: 220px;
overflow: scroll;
height: auto;
background: #FFE7E6;
border: 1px solid rgba(226,97,84,0.42);
border-radius: 4px;
font-size: 14px;
color: #F53A19;
font-weight: 400;
padding: 5px 12px;
}
.error-icon-default {
font-size: 16px;
margin-left: -2px;
margin-right: 8px;
}
.error-icon-tooltip {
font-size: 16px !important;
margin-bottom: -1px;
margin-left: 6px;
}

View File

@@ -72,3 +72,4 @@
@import 'views/charts2/dnsEventChart';
@import './views/charts2/dnsEventChartByPie';
//@import '../chart';
@import './components/common/chart-error';

View File

@@ -13,6 +13,13 @@
font-size: 14px;
color: #046ECA;
}
.link-block-error {
position: absolute;
width: calc(100% - 20px);
height: calc(100% - 60px);
margin-left: -12px;
margin-top: 10px;
}
.data-grid {
height: 100px;
.egress-row {

View File

@@ -1,46 +1,58 @@
.network-overview-apps {
height: 100%;
.line-select-metric {
.network-overview-apps-header {
display: flex;
justify-content: flex-end;
align-items: center;
//justify-content: space-between;
&>span {
font-size: 12px;
color: #575757;
font-weight: 400;
margin-right: 3px;
.network-overview-apps-title {
font-size: 14px;
color: #353636;
font-weight: 600;
display: flex;
align-items: flex-end;
}
.line-select__operation {
height: 24px;
margin-left: 3px;
box-shadow: none;
border-radius: 2px;
.el-input__inner {
width: 100px;
height: 24px;
padding-left: 4px;
line-height: 24px;
.line-select-metric {
display: flex;
justify-content: flex-end;
align-items: center;
&>span {
font-size: 12px;
color: #2C72C6;
color: #575757;
font-weight: 400;
margin-right: 3px;
}
.el-input__suffix {
display: flex;
.el-input__suffix-inner {
.line-select__operation {
height: 24px;
margin-left: 3px;
box-shadow: none;
border-radius: 2px;
.el-input__inner {
width: 100px;
height: 24px;
padding-left: 4px;
line-height: 24px;
.el-select__caret {
font-size: 12px;
color: #2C72C6;
font-weight: 400;
}
.el-input__suffix {
display: flex;
.el-input__suffix-inner {
line-height: 24px;
width: 16px;
color: #575757;
.el-select__caret {
line-height: 24px;
width: 16px;
color: #575757;
}
}
}
}
}
}
.app-cards {
display: grid;
grid-template-rows: repeat(auto-fill, 100px);
@@ -48,7 +60,6 @@
grid-gap: 20px;
width: 100%;
padding-top: 10px;
height: calc(100% - 24px);
.app-card {
border: 1px solid #E2E5EC;

View File

@@ -4,7 +4,7 @@
height:calc(100% - 64px);
font-size:12px;
.tab-hide{
margin-top:40px;
margin-top:42px;
}
.cn-chart__tabs {
height:100%;
@@ -32,13 +32,11 @@
.div-yellow {
height: 12px;
background: #e5a219;
border: 1px solid #e5a219;
border-left: none;
}
.div-green {
height: 12px;
background: #749f4d;
border: 1px solid #749f4d;
border-right: none;
}
}
@@ -115,6 +113,41 @@
.el-table thead {
color: $grey;
}
.el-table__empty-text{
line-height:20px !important;
}
.el-table__header th .cell {
display:flex;
flex-direction:row;
justify-content: center;
align-items: center;
}
.el-table__header tr th:nth-of-type(1) .cell {
justify-content: start;
}
.score-cell {
display: flex !important;
justify-content: center;
.data-score {
border-radius: 10px;
font-size: 12px;
color: #FFFFFF;
font-weight: 500;
height: 20px;
width: 34px;
line-height: 20px;
text-align: center;
}
.data-score-red {
background: #E26154;
}
.data-score-yellow {
background: #E5A219;
}
.data-score-green {
background: #749F4D;
}
}
}
.el-tabs__header {
margin-bottom: 10px;

View File

@@ -179,3 +179,6 @@
color: $grey;
}
}
.npm-app-border {
border: 1px solid #E2E5EC;
}

View File

@@ -110,4 +110,10 @@
.el-table--group::after,.el-table--border::after,.el-table::before {
height: 0px;
}
.table-error {
position: absolute;
width: 100%;
left: 0;
top: 68px;
}
}

View File

@@ -3,6 +3,7 @@
width: 100%;
height: 100%;
.npm-event-title {
display: flex;
font-size: 14px;
color: #353636;
font-weight: 600;

View File

@@ -4,6 +4,7 @@
width: 100%;
border: 1px solid #f0f0f0;
.npm-line-title {
display: flex;
font-size: 14px;
color: #353636;
font-weight: 500;
@@ -14,6 +15,7 @@
margin: 20px 20px 0 20px;
justify-content: space-between;
.npm-line-header-title {
display: flex;
font-size: 14px;
color: #353636;
font-weight: 500;

View File

@@ -1,4 +1,5 @@
.cn-chart__map-title {
display: flex;
font-size: 14px;
color: #353636;
font-weight: 600;

View File

@@ -2,6 +2,7 @@
height: 100%;
width: 100%;
.npm-recent-title {
display: flex;
font-size: 14px;
color: #353636;
font-weight: 600;

View File

@@ -2,6 +2,7 @@
height: 100%;
width: 100%;
.npm-sessions-title {
display: flex;
font-size: 14px;
color: #353636;
font-weight: 500;
@@ -27,6 +28,14 @@
border-bottom-left-radius: 4px;
border-right: none;
}
.npm-sessions-div-gray {
height: 100%;
background: rgba(113,113,113,0.30);
border: 1px solid rgba(113,113,113,0.30);
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
border-right: none;
}
}
.npm-sessions-body {
@@ -45,15 +54,10 @@
display: flex;
align-items: center;
.npm-sessions-as-client-i18n {
ont-size: 12px;
font-size: 12px;
color: #717171;
font-weight: 400;
}
.npm-sessions-as-client-percent {
font-size: 18px;
color: #353636;
font-weight: 700;
}
.npm-sessions-as-client-green,.npm-sessions-as-client-red {
width: 8px;
height: 8px;
@@ -66,6 +70,11 @@
background: red;
}
}
.npm-sessions-as-client-percent {
font-size: 18px;
color: #353636;
font-weight: 700;
}
}
}
.npm-sessions-body-right {

View File

@@ -53,6 +53,9 @@
border-radius: 4px;
height: calc(100% - 32px);
width: 100%;
.panel-chart__no-data {
height: calc(100% - 32px);
}
.chart-drawing {
height: 100%;
width: 100%;

View File

@@ -31,7 +31,6 @@
background: #749F4D;
}
height:24px;
font-family: NotoSansHans-Medium;
font-size: 12px;
color: #353636;
font-weight: 500;
@@ -46,8 +45,30 @@
justify-content: center;
}
}
.panel__time {
.panel__tools {
display: flex;
&>.el-select {
width: 162px;
margin-right: 10px;
.select-prefix {
font-size: 14px;
color: #999;
padding: 0 6px 0 3px;
}
.el-input__inner {
font-size: 14px;
color: #353636;
background-color: #F5F8FA;
}
.common-select {
top: 32px !important;
}
}
.panel__time {
display: flex;
}
}
}
.chart-list {

View File

@@ -18,7 +18,7 @@
align-items: center;
padding-left: 10px;
color: #666;
background-color: #F3F7FA;
//background-color: #F3F7FA;
cursor: pointer;
span {
@@ -33,7 +33,18 @@
i.arrow-rotate {
transform: rotate(90deg) translate(2px, 3px);
}
.new-detection-filter-header-title {
font-size: 14px;
color: #353636;
font-weight: 600;
}
.new-detection-filter-icon {
margin-left: 8px;
margin-bottom: 2px;
font-weight: bold !important;
}
}
.filter__body {
padding: 5px 0 0 15px;
@@ -69,4 +80,17 @@
}
}
}
.new-detection-filter-title {
display: flex;
flex: 0 0 32px;
align-items: center;
padding-left: 27px;
background-color: #EFF2F5;
cursor: pointer;
font-size: 14px;
color: #353636;
font-weight: 600;
margin: -10px;
margin-bottom: 10px;
}
}

View File

@@ -40,7 +40,7 @@
height: 100%;
overflow: auto;
.cn-detection__shadow {
.cn-detection__shadow, .new-cn-detection__shadow {
position: fixed;
height: 100vh;
width:100vw;
@@ -49,6 +49,10 @@
z-index: 1;
background-color: rgba(0, 0, 0, .2);
}
.new-cn-detection__shadow {
z-index: 4;
}
}
}

View File

@@ -2,13 +2,22 @@
display: flex;
.cn-detection__collapse {
margin-bottom: 1px;
padding-top: 18px;
width: 24px;
display: flex;
justify-content: center;
align-items: flex-start;
background-color: #F3F7FA;
margin-bottom: 1px;
//padding-top: 18px;
background-color: #EFF2F5;
.cn-detection__collapse-block {
min-height: 66px;
height: 100%;
max-height: 88px;
display: flex;
align-items: center;
cursor: pointer;
}
span {
transform: rotate(0);
@@ -99,6 +108,25 @@
line-height: 14px;
margin-left: 5px;
}
.detection-event-severity-color-block {
width: 5px;
height: 20px;
border-radius: 2.5px;
margin-left: -16px;
margin-right: 12px;
}
.detection-event-severity-block {
font-family: NotoSansHans-Medium;
font-size: 12px;
color: #046EC9;
font-weight: 500;
padding: 2px 10px;
background: rgba(56,172,210,0.10);
border: 1px solid #ADC7DB;
box-shadow: 0 2px 4px 0 rgba(51,51,51,0.02);
border-radius: 3px;
margin-right: 10px;
}
}
.cn-detection__body {

View File

@@ -62,8 +62,11 @@
.row__content {
display: flex;
color: #3976CB;
//color: #3976CB;
color: #046ECA;
font-weight: 500;
font-size: 14px;
&.row__content--link {
font-style: italic;
text-decoration: underline;
@@ -77,6 +80,10 @@
cursor: pointer;
}
span{
font-style: italic;
color: #046ECA;
}
.row__content--span {
font-style: italic;
color: #1890FF;
}
@@ -169,13 +176,16 @@
span {
padding-left: 5px;
font-size: 14px;
color: #3976CB;
//color: #3976CB;
color: #046ECA;
font-weight: 600 !important;
}
}
.timeline__security-type {
font-size: 12px;
color: #3976CB;
color: #046ECA;
margin-bottom: 10px;
font-weight: 500;
}
.timeline__start-time {
font-size: 12px;

View File

@@ -26,7 +26,7 @@
justify-content: flex-start;
}
.explorer-top-tools {
.explorer-top-tools, .explorer-detection-top-tools {
display: flex;
justify-content: flex-end;
align-items: center;
@@ -46,6 +46,38 @@
}
}
}
.explorer-detection-top-tools {
display: flex;
justify-content: space-between;
}
.explorer-top-tools-title {
font-size: 24px;
line-height: 24px;
font-weight: 900;
color: #353636;
}
.explorer-top-tools-block {
font-family: NotoSansHans-Medium;
height: 28px;
line-height: 28px;
background: #F5F8FA;
font-size: 14px;
color: #353636;
font-weight: 500;
padding: 0 10px;
margin-right: 10px;
border: 1px solid #E2E5EC;
border-radius: 2px;
cursor: pointer;
}
.detection-icon-setting {
margin-right: 10px;
font-size: 14px;
}
.detection-border {
border: 1px solid #E2E5EC;
border-radius: 4px;
}
.explorer-container {
display: flex;
overflow: visible; /*overflow: hidden;*/

View File

@@ -1,8 +1,8 @@
@font-face {
font-family: "cn-icon"; /* Project id 2614877 */
src: url('iconfont.woff2?t=1663570533591') format('woff2'),
url('iconfont.woff?t=1663570533591') format('woff'),
url('iconfont.ttf?t=1663570533591') format('truetype');
src: url('iconfont.woff2?t=1668593055875') format('woff2'),
url('iconfont.woff?t=1668593055875') format('woff'),
url('iconfont.ttf?t=1668593055875') format('truetype');
}
.cn-icon {
@@ -13,6 +13,46 @@
-moz-osx-font-smoothing: grayscale;
}
.cn-icon-baocuo:before {
content: "\e7b7";
}
.cn-icon-a-SecurityEvent:before {
content: "\e7ae";
}
.cn-icon-bianji1:before {
content: "\e7af";
}
.cn-icon-a-PerformanceEvent:before {
content: "\e7b0";
}
.cn-icon-xinjian:before {
content: "\e7b1";
}
.cn-icon-a-RegulatoryRiskEvent:before {
content: "\e7b2";
}
.cn-icon-Delete1:before {
content: "\e7b3";
}
.cn-icon-a-EvaluatedTarget:before {
content: "\e7b4";
}
.cn-icon-a-GeneralSettings:before {
content: "\e7b5";
}
.cn-icon-Thresholds:before {
content: "\e7b6";
}
.cn-icon-good:before {
content: "\e7ad";
}

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,149 @@
<template>
<div v-if="showDefault" class="error-component">
<div class="error-block" :style="{'max-width': localMaxWidth, 'width': localWidth}">
<svg class="icon error-icon-default" aria-hidden="true">
<use xlink:href="#cn-icon-baocuo"></use>
</svg>
{{ content }}
</div>
</div>
<div id="error-com">
<div v-if="tooltip !== undefined">
<el-popover
:width="localPopoverWidth"
placement="top-start"
trigger="hover"
:visible-arrow="false"
popper-class="error-popover"
:content="content">
<template #reference>
<span>
<svg class="icon error-icon-tooltip" aria-hidden="true">
<use xlink:href="#cn-icon-baocuo"></use>
</svg>
<!-- 为后续自定义icon插槽做预备-->
<!-- <i v-if="icon" :class="`icon cn-icon-${icon}`"></i>-->
</span>
</template>
</el-popover>
<!-- 不使用popover实现hover后续考虑替换为该方案-->
<!-- <span class="new-error-icon" @mouseenter="hoverError">-->
<!-- <svg class="icon item-popover-up" aria-hidden="true">-->
<!-- <use xlink:href="#cn-icon-baocuo"></use>-->
<!-- </svg>-->
<!-- <div id="error-content" class="error-content">-->
<!-- rview/appCompanyCyclrview/appCompanyCycleTrafficTotal?startTime=getSecond(this.timeFilter.startTime)&endTime=getSecond(this.timeFilter.endTime)&appCompanies=%27Tencent%27,%27Jingdong%27,%27Akamai%27,%27Bytedance%27,%27Baidu%27,%27Huawei%27,%27Beike%27,%27Aiqiyi%27,%27Ctrip%27,%27Meituan%27-->
<!-- </div>-->
<!-- </span>-->
</div>
<div class="error-block-info" v-if="info !== undefined">
<div>
<svg class="icon error-icon-default" aria-hidden="true">
<use xlink:href="#cn-icon-baocuo"></use>
</svg>
{{ content }}
</div>
</div>
</div>
</template>
<!-- start----------------调用方式----------------start -->
<!--
组件在全局注册了调用时: <chart-error :content="content"></chart-error>
-->
<!--
目前有三种形式分别是defaulttooltipinfo
默认即红框展示<chart-error :content="content" />
在标题之后显示需要鼠标移动到图标上显示弹窗<chart-error tooltip :content="content" />
文字提示<chart-error info :content="content" />
-->
<!--
自定义宽度<chart-error width="300" :content="content" />
自定义弹窗宽度<chart-error tooltip width="300" :content="content" />
注意info模式不支持宽度设置
-->
<!--
自定义icon图标<chart-error tooltip icon="baocuo" :content="content" />此时icon全称为'cn-icon-baocuo'
-->
<!-- end----------------调用方式----------------end -->
<script>
export default {
name: 'Error',
props: {
// 工具栏提示类型
tooltip: {
type: String
},
// 文字提示类型
info: {
type: String
},
// 报错信息内容,如果不传,默认为"Error"
content: {
type: String,
default: 'Error'
},
// 报错信息模块宽度如果类型选择tooltip则为弹窗宽度info模式没有宽度设置
width: {
type: String
},
// 报错信息模块最大宽度
maxWidth: {
type: String
// default: '350'
},
// 自定义icon图标
icon: {
type: String
},
// 自定义svg图标
svg: {
type: String
}
},
data () {
return {
showDefault: false, // 是否显示default分别是default、tooltip、info
showSmall: false, // 显示错误的类型true为图表模块内显示报错false为标题后显示报错
localWidth: '',
localMaxWidth: '',
localPopoverWidth: ''
}
},
mounted () {
this.initData()
},
methods: {
initData () {
if (this.tooltip !== undefined) {
this.showDefault = false
this.localPopoverWidth = this.width !== undefined
}
// 默认default模式
this.showDefault = this.tooltip === undefined && this.info === undefined
if (this.width) {
// 避免宽度出现负数的情况
this.localWidth = Math.abs(parseFloat(this.width)) + 'px'
}
if (this.maxWidth) {
// 避免宽度出现负数的情况
this.localMaxWidth = Math.abs(parseFloat(this.maxWidth)) + 'px'
}
},
/**
* 鼠标移入事件用于获取弹窗dom修改距离父元素的top
*/
hoverError (e) {
// const dom = document.getElementById('error-content')
// if (dom) {
// console.log('---', dom.clientHeight)
// }
}
}
}
</script>

View File

@@ -1,5 +1,5 @@
<template>
<div v-ele-click-outside="changeDropdown" style="position: relative" class="date-range-box">
<div v-ele-click-outside="changeDropdown" style="position: relative;z-index: 2" class="date-range-box">
<div @click="showDropdown" class="date-range-text">
<div class="calendar-popover-text"><i class="cn-icon cn-icon-Data"></i></div>
<div class="calendar-popover-text" style="display: flex" v-if="isCustom">
@@ -10,25 +10,22 @@
<div class="calendar-popover-text" v-else>
{{ showDetail }}
</div>
<div class="calendar-popover-text calendar-popover__small"><i class="cn-icon cn-icon-dropdown"
:class="dropdownFlag ? 'cn-icon-up' : ''"></i></div>
<div class="calendar-popover-text calendar-popover__small">
<i class="cn-icon cn-icon-dropdown" :class="dropdownFlag ? 'cn-icon-up' : ''"></i>
</div>
</div>
<transition name="el-zoom-in-top">
<div v-if="dropdownFlag" class="date-range-panel">
<el-row class="date-range-panel-top" style="position: relative">
<el-col :span="16" class="date-range-panel-content date-range-panel-content-left">
<div class="date-range-title" style="padding-left: 0">Absolute time range</div>
<MyDatePicker
:clearable='false'
:editable='false'
v-model="timeArr"
<el-date-picker
v-model="newDateValue"
ref="newDatePicker"
class="date_style"
style="position: absolute;top: -53px;left: -536px;"
:clearable="false"
type="datetimerange"
ref="myDatePicker"
:popper-class="'myDatePicker'"
class="panel-time-picker-hidden"
:size="'small'"
placement="left-start"
style="position: absolute"
@change="timeArrChange"
/>
<div class="content-title">From</div>
@@ -39,9 +36,7 @@
<div @click="myDatePickerShow" tabindex="2" class="content-input">
{{ dateFormatByAppearance(getMillisecond(myEndTime)) }}
</div>
<div>
<el-button @click="timeRange" type="primary" size="mini">Apply time range</el-button>
</div>
<div class="date-range-title" style="padding-left: 0">Recently used absolute ranges</div>
<div class="date-range-history">
<div v-for="(item, index) in rangeHistoryArr" :key="index" class="date-range-history-item"
@@ -52,23 +47,26 @@
</div>
</div>
</el-col>
<el-col :span="8" class="date-range-panel-content date-range-panel-content-right"
style="border-left: 1px solid rgba(0,0,0,0.09);">
<el-col
:span="8"
class="date-range-panel-content date-range-panel-content-right"
style="border-left: 1px solid rgba(0,0,0,0.09);">
<div class="date-range-title">Relatime time ranges</div>
<ul class="date-range-item">
<li v-for="item in dateRangeArr" @click="quickChange(item.value)"
:class="(item.value==dateRangeValue.value || item.value==dateRangeValue)?'active':''"
<li v-for="item in dateRangeArr"
@click="quickChange(item.value)"
:class="(item.value===dateRangeValue.value || item.value===dateRangeValue)?'active':''"
:key="item.value">
<span style="position: relative">
{{ item.name }}
<i v-if="(item.value==dateRangeValue.value || item.value==dateRangeValue)"
<i v-if="(item.value===dateRangeValue.value || item.value===dateRangeValue)"
class="cn-icon cn-icon-check"></i>
</span>
</li>
</ul>
</el-col>
</el-row>
<el-row class="date-range-panel-bottom" style="">
<el-row class="date-range-panel-bottom">
<el-col :span="12">{{ address }}</el-col>
<el-col :span="12" class="utc-str">{{ utcStr }}</el-col>
</el-row>
@@ -78,10 +76,10 @@
</template>
<script>
import { ref, computed } from 'vue'
import MyDatePicker from '../MyDatePicker'
import { ref, computed, watch, reactive } from 'vue'
import { storageKey } from '@/utils/constants'
import { getMillisecond } from '@/utils/date-util'
import { getMillisecond, timestampToList } from '@/utils/date-util'
import { useStore } from 'vuex'
export default {
name: 'DateTimeRange',
@@ -97,68 +95,39 @@ export default {
dateRange: {
type: Number
}
/* useRefresh: {
type: Boolean,
default: true
},
useDateRange: {
type: Boolean,
default: true
} */
},
emits: ['change'],
components: {
MyDatePicker
},
setup (props, ctx) {
// data
const store = useStore()
const myStartTime = ref(props.startTime)
const myEndTime = ref(props.endTime)
const timeArr = ref([myStartTime.value, myEndTime.value])
// 时间选择器绑定的值
const newDateValue = ref([
new Date(...timestampToList(myStartTime.value)),
new Date(...timestampToList(myEndTime.value))
])
// 时区地址
const address = localStorage.getItem(storageKey.sysTimezone)
// 当前所在时区
const utc = localStorage.getItem(storageKey.timezoneOffset)
// 历史选择时间
const rangeHistory = ref(localStorage.getItem(storageKey.dataRangeHistory) ? JSON.parse(localStorage.getItem(storageKey.dataRangeHistory)) : [])
const dateRangeValue = props.dateRange ? ref(props.dateRange) : ref(60)
const isCustom = ref(dateRangeValue.value === -1)
const dateRangeArr = [
{
value: 5,
name: 'last 5 Min'
},
{
value: 15,
name: 'last 15 Min'
},
{
value: 30,
name: 'last 30 Min'
},
{
value: 60,
name: 'last 1 hour'
},
{
value: 180,
name: 'last 3 hour'
},
{
value: 360,
name: 'last 6 hour'
},
{
value: 720,
name: 'last 12 hour'
},
{
value: 1440,
name: 'last 1 days'
},
{
value: 2880,
name: 'last 2 days'
}
{ value: 5, name: 'last 5 Min' },
{ value: 15, name: 'last 15 Min' },
{ value: 30, name: 'last 30 Min' },
{ value: 60, name: 'last 1 hour' },
{ value: 180, name: 'last 3 hour' },
{ value: 360, name: 'last 6 hour' },
{ value: 720, name: 'last 12 hour' },
{ value: 1440, name: 'last 1 days' },
{ value: 2880, name: 'last 2 days' }
]
const dropdownFlag = ref(false)
// computed
const utcStr = computed(() => {
let str = 'UTC '
@@ -183,20 +152,40 @@ export default {
}
return str
})
const rangeHistoryArr = computed(() => {
return rangeHistory.value.slice(0, 4)
})
const rangeHistoryArr = rangeHistory
// refs
const myDatePicker = ref(null)
const newDatePicker = ref(null)
// echarts框选时间范围
const rangeEchartsData = reactive({
value: computed(() => store.state.panel.rangeEchartsData)
})
watch(() => rangeEchartsData.value, (newVal, oldVal) => {
if (newVal) {
myStartTime.value = getMillisecond(newVal.startTime)
myEndTime.value = getMillisecond(newVal.endTime)
isCustom.value = true
dateRangeValue.value = -1
returnValue()
}
})
// methods
/**
* 打开/关闭时间面板
*/
const showDropdown = () => {
dropdownFlag.value = !dropdownFlag.value
if (dropdownFlag.value) {
myStartTime.value = props.startTime
myEndTime.value = props.endTime
timeArr.value = [getMillisecond(myStartTime.value), getMillisecond(myEndTime.value)]
}
}
/**
* 点击空白处隐藏时间面板
*/
const changeDropdown = () => {
if (dropdownFlag.value) {
dropdownFlag.value = false
@@ -205,19 +194,36 @@ export default {
dropdownFlag.value = false
}
}
/**
* 打开时间选择器,从时间面板的“开始时间”、“结束时间”调用
*/
const myDatePickerShow = () => {
myDatePicker.value.focus()
myDatePicker.value.pickerVisible = true
newDateValue.value = [
new Date(...timestampToList(myStartTime.value)),
new Date(...timestampToList(myEndTime.value))
]
newDatePicker.value.focus()
// todo 此处为弹窗打开的方向标识控制css的position修改其left与top属性未生效只好隐藏后续有更好的处理办法再修改
const dom = document.getElementsByClassName('el-picker__popper el-popper is-light is-pure')
const dom1 = dom[0].getElementsByClassName('el-popper__arrow')
dom1[0].style.display = 'none'
}
/**
* 时间选择器选择时间点击OK后的回调
* @param val开始/结束时间数组
*/
const timeArrChange = (val) => {
myStartTime.value = getMillisecond(val[0])
myEndTime.value = getMillisecond(val[1])
}
const timeRange = () => {
isCustom.value = true
dateRangeValue.value = -1
returnValue()
}
/**
* 历史时间列表中点击一项,对时间进行赋值
* @param item
*/
const historyChange = (item) => {
myStartTime.value = item.start
myEndTime.value = item.end
@@ -232,39 +238,64 @@ export default {
myStartTime.value = myEndTime.value - value * 60 * 1000
returnValue()
}
/**
* 重置时间,将时间存入缓存,并触发方法请求接口刷新界面
*/
const returnValue = () => {
cancelHttp()
rangeHistory.value.unshift({
start: myStartTime.value,
end: myEndTime.value
})
if (rangeHistory.value.length > 4) {
rangeHistory.value.splice(4, rangeHistory.value.length - 1)
}
localStorage.setItem(storageKey.dataRangeHistory, JSON.stringify(rangeHistory.value))
ctx.emit('change', myStartTime.value, myEndTime.value, dateRangeValue)
dropdownFlag.value = false
}
/**
* 终止http请求
*/
const cancelHttp = () => {
const cancelList = store.state.panel.httpCancel
if (cancelList.length > 0) {
cancelList.forEach((cancel, index) => {
cancel()
delete cancelList[index]
})
}
}
return {
myStartTime,
myEndTime,
getMillisecond,
dropdownFlag,
utcStr,
rangeEchartsData,
address,
dateRangeArr,
dateRangeValue,
isCustom,
timeArr,
myDatePicker,
newDateValue,
newDatePicker,
showDetail,
rangeHistory,
rangeHistoryArr,
getMillisecond,
myDatePickerShow,
showDropdown,
changeDropdown,
timeArrChange,
returnValue,
quickChange,
timeRange,
historyChange
}
}
}
</script>
<style scoped>
/deep/.el-input__inner {
visibility: hidden !important;
}
</style>

View File

@@ -12,8 +12,8 @@
<transition name="el-zoom-in-top">
<div v-if="dropdownShow" class="refresh-list">
<div v-for="(item, index) in refreshArr" :key="index" @click="setRefresh(item)" class="refresh-list-item" :class="item.value==interval ? 'active' : ''">
{{item.label}}
<i v-if="item.value==interval" class="cn-icon cn-icon-check"></i>
{{ item.label }}
<i v-if="item.value===interval" class="cn-icon cn-icon-check"></i>
</div>
</div>
</transition>
@@ -103,7 +103,16 @@ export default {
this.interLabel = val.value == -1 ? '' : val.label
this.dropdownShow = false
const now = window.$dayJs.tz().valueOf()
if (val && val.value != -1) {
if (val && val.value !== -1) {
// 切换轮询请求时间频率时,发现有未结束的请求,终止请求
const cancelList = this.$store.state.panel.httpCancel
// console.log('timeRefresh.vue------setRefresh------查看终止数量', cancelList, cancelList.length)
if (cancelList.length > 0) {
cancelList.forEach((cancel, index) => {
cancel()
delete cancelList[index]
})
}
// 向地址栏添加自动刷新频率
const dateParam = {
refreshTime: val.value
@@ -121,7 +130,7 @@ export default {
}
return
}
if (val && val.value == -1) {
if (val && val.value === -1) {
// 清除定时器
clearInterval(this.intervalTimer)

View File

@@ -20,7 +20,8 @@ export default {
entityDetectionStyle () {
const route = this.$route.name !== undefined ? this.$route.name : this.$route
if (listScrollPath.indexOf(route.path) > -1) {
return 'overflow:auto;background-color: #EFF2F5;'
const style = route.path === listScrollPath[0] ? 'overflow:auto;background-color: #EFF2F5;' : 'overflow:auto;'
return style
} else {
return ''
}

View File

@@ -2,7 +2,8 @@
<div class="cn-header">
<div class="cn-header__banner">
<div class="banner__left">
<span @click="shrink" class="shrink-button" :class="{'shrink-button--collapse': showMenu}"><i class="cn-icon cn-icon-navigation"></i></span>
<span @click="shrink" class="shrink-button" :class="{'shrink-button--collapse': showMenu}"><i
class="cn-icon cn-icon-navigation"></i></span>
<img alt="loading..." height="26" :src="logo?logo:require('../../assets/img/logo-header.svg')"/>
</div>
<!--个人操作-->
@@ -12,23 +13,27 @@
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>
<div id="header-to-english" :style="language === 'en'?'color:#0091ff':''" @click="changeLocal('en')">English</div>
<div id="header-to-english" :style="language === 'en'?'color:#0091ff':''" @click="changeLocal('en')">
English
</div>
</el-dropdown-item>
<el-dropdown-item>
<div id="header-to-chinese" :style="language === 'cn'?'color:#0091ff':''" @click="changeLocal('cn')">中文</div>
<div id="header-to-chinese" :style="language === 'cn'?'color:#0091ff':''" @click="changeLocal('cn')">
中文
</div>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<el-dropdown>
<div class='login-user header-menu--item'>{{username}}&nbsp;<i class="cn-icon cn-icon-arrow-down"></i></div>
<div class='login-user header-menu--item'>{{ username }}&nbsp;<i class="cn-icon cn-icon-arrow-down"></i></div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>
<div id="header-to-changepin" @click="showPinDialog">{{$t('overall.changePassword')}}</div>
<div id="header-to-changepin" @click="showPinDialog">{{ $t('overall.changePassword') }}</div>
</el-dropdown-item>
<el-dropdown-item>
<div id="header-to-logout" @click="logout">{{$t('overall.logout')}}</div>
<div id="header-to-logout" @click="logout">{{ $t('overall.logout') }}</div>
</el-dropdown-item>
</el-dropdown-menu>
</template>
@@ -37,8 +42,9 @@
</div>
<div class="cn-header__nav">
<i class="cn-icon cn-icon-a-NetworkAnalytics"></i>
<el-breadcrumb class="header__left-breadcrumb" separator=">">
<el-breadcrumb-item class="header__left-breadcrumb-item" :id="`breadcrumb${item}`" :title="item" v-for="(item,index) in breadcrumb" :key="item">
<el-breadcrumb class="header__left-breadcrumb" :separator="route.indexOf('detection') === -1 ? '>' : ''">
<el-breadcrumb-item class="header__left-breadcrumb-item" :id="`breadcrumb${item}`" :title="item"
v-for="(item,index) in breadcrumb" :key="item">
<template v-if="index===3">
<div class="header__left-breadcrumb-item-select">
<el-popover placement="bottom-start"
@@ -52,8 +58,19 @@
@hide="hideBreadcrumbPopover()"
trigger="click">
<template #reference>
<div class="breadcrumb-button" id="breadcrumbButton" :class="showBackground?'breadcrumb-button__active':''" >
<span id="breadcrumbValue"> {{item}}</span><i class="cn-icon-xiala cn-icon"></i>
<div class="breadcrumb-button" id="breadcrumbButton"
:class="showBackground?'breadcrumb-button__active':''">
<span id="breadcrumbValue">
<template v-if="curTabProp === 'qtype'">
<span>{{ dnsQtypeMapData.get(item)}}</span>
</template>
<template v-else-if="curTabProp === 'rcode'">
<span>{{ dnsRcodeMapData.get(item)}}</span>
</template>
<template v-else>
<span>{{ item }}</span>
</template>
</span><i class="cn-icon-xiala cn-icon"></i>
</div>
</template>
<el-row type="flex" justify="center" style="width: fit-content;flex-direction: column;">
@@ -63,9 +80,18 @@
v-model="dropDownValue"
@input="dropDownSearch"></el-input>
</div>
<ul class="select-dropdown" id="breadcrumbSelectDropdown" @scroll="scrollList()">
<li v-for="item in breadcrumbColumnValueListShow" title='' :key="item" :id="item" class="select-dropdown__item" @click="changeValue(item)" :class="selected?'':''">
<span>{{item}}</span>
<ul class="select-dropdown" id="breadcrumbSelectDropdown" @scroll="scrollList()">
<li v-for="item in breadcrumbColumnValueListShow" title='' :key="item" :id="item"
class="select-dropdown__item" @click="changeValue(item)" :class="selected?'':''">
<template v-if="curTabProp === 'qtype'">
<span>{{ dnsQtypeMapData.get(item) }}</span>
</template>
<template v-else-if="curTabProp === 'rcode'">
<span>{{ dnsRcodeMapData.get(item) }}</span>
</template>
<template v-else>
<span>{{ item }}</span>
</template>
</li>
</ul>
</el-row>
@@ -73,38 +99,39 @@
</div>
</template>
<template v-else-if="index===2">
<span v-if="route===wholeScreenRouterMapping.dns" >{{$t(item)}}</span>
<span v-else class="route-menu" @click="jump(route,item,'',3)">{{$t(item)}}</span>
<span v-if="route===wholeScreenRouterMapping.dns">{{ $t(item) }}</span>
<span v-else class="route-menu" @click="jump(route,item,'',3)">{{ $t(item) }}</span>
</template>
<template v-else-if="index===1">
<span class="route-menu" @click="jump(route,'','',2)" v-if="route.indexOf('detection') === -1">{{item}}</span>
<div class="header__left-breadcrumb-item-select" v-if="route.indexOf('detection') > -1">
<el-popover placement="bottom-start"
v-if="route.indexOf('detection') > -1"
ref="breadcrumbPopover"
:show-arrow="false"
:append-to-body="false"
:hide-after="0"
:show-after="0"
popper-class="breadcrumb__popper"
trigger="click">
<template #reference>
<div class="breadcrumb-button" id="breadcrumbButton2" :class="showBackground?'breadcrumb-button__active':''" v-if="route.indexOf('detection') > -1">
<span id="breadcrumbValue2"> {{item}}</span><i class="cn-icon-xiala cn-icon"></i>
</div>
</template>
<el-row type="flex" justify="center" style="width: fit-content;flex-direction: column;">
<ul class="select-dropdown" id="breadcrumbSelectDropdown2">
<li v-for="item in detectionMenuList" title='' :key="item.name" :id="item.name" class="select-dropdown__item" @click="jump(item.path,'','',2)">
<span>{{$t(item.i18n)}}</span>
</li>
</ul>
</el-row>
</el-popover>
</div>
<span class="route-menu" @click="jump(route,'','',2)"
v-if="route.indexOf('detection') === -1">{{ item }}</span>
<!-- <div class="header__left-breadcrumb-item-select" v-if="route.indexOf('detection') > -1">-->
<!-- <el-popover placement="bottom-start"-->
<!-- v-if="route.indexOf('detection') > -1"-->
<!-- ref="breadcrumbPopover"-->
<!-- :show-arrow="false"-->
<!-- :append-to-body="false"-->
<!-- :hide-after="0"-->
<!-- :show-after="0"-->
<!-- popper-class="breadcrumb__popper"-->
<!-- trigger="click">-->
<!-- <template #reference>-->
<!-- <div class="breadcrumb-button" id="breadcrumbButton2" :class="showBackground?'breadcrumb-button__active':''" v-if="route.indexOf('detection') > -1">-->
<!-- <span id="breadcrumbValue2"> {{item}}</span><i class="cn-icon-xiala cn-icon"></i>-->
<!-- </div>-->
<!-- </template>-->
<!-- <el-row type="flex" justify="center" style="width: fit-content;flex-direction: column;">-->
<!-- <ul class="select-dropdown" id="breadcrumbSelectDropdown2">-->
<!-- <li v-for="item in detectionMenuList" title='' :key="item.name" :id="item.name" class="select-dropdown__item" @click="jump(item.path,'','',2)">-->
<!-- <span>{{$t(item.i18n)}}</span>-->
<!-- </li>-->
<!-- </ul>-->
<!-- </el-row>-->
<!-- </el-popover>-->
<!-- </div>-->
</template>
<template v-else>
<span>{{item}}</span>
<span>{{ item }}</span>
</template>
</el-breadcrumb-item>
</el-breadcrumb>
@@ -122,22 +149,26 @@
<div class="cn-menu__left">
<div class="left-menu" v-for="menu in otherMenu" :key="menu.id" @click="jump(menu.route,'','',0)">
<i :class="menu.icon"></i>
<span>{{$t(menu.i18n || menu.name)}}</span>
<span>{{ $t(menu.i18n || menu.name) }}</span>
<i class="cn-icon cn-icon-right"></i>
</div>
</div>
<div class="cn-menu__middle">
<div class="middle-menus middle-menus--network-analytics">
<div class="middle-menus__header">{{$t('overall.networkAnalytics')}}</div>
<div class="middle-menus__header">{{ $t('overall.networkAnalytics') }}</div>
<div class="middle-menus__body">
<div style="width: 260px;">
<template v-for="(menu, index) in networkAnalyticsMenu.children" :key="index">
<div class="middle-menu" v-if="index < 5" @click="jump(menu.route,'','',2)">{{$t(menu.i18n || menu.name)}}</div>
<div class="middle-menu" v-if="index < 5" @click="jump(menu.route,'','',2)">
{{ $t(menu.i18n || menu.name) }}
</div>
</template>
</div>
<div>
<template v-for="(menu, index) in networkAnalyticsMenu.children" :key="index">
<div class="middle-menu" v-if="index >= 5 && index < 10" @click="jump(menu.route,'','',2)">{{$t(menu.i18n || menu.name)}}</div>
<div class="middle-menu" v-if="index >= 5 && index < 10" @click="jump(menu.route,'','',2)">
{{ $t(menu.i18n || menu.name) }}
</div>
</template>
</div>
</div>
@@ -149,12 +180,12 @@
<el-dialog v-model="showChangePin"
width="30%"
:before-close="handleClose">
<el-form :rules="changePassFormRules" :model="changePassForm" ref="changePassForm">
<el-form :rules="changePassFormRules" :model="changePassForm" ref="changePassForm">
<el-row :gutter="20">
<el-col :span="24">
<el-form-item :label="$t('overall.currentPassword')" prop="oldPwd">
<el-input v-model="changePassForm.oldPwd" type="password"></el-input>
</el-form-item>
<el-col :span="24">
<el-form-item :label="$t('overall.currentPassword')" prop="oldPwd">
<el-input v-model="changePassForm.oldPwd" type="password"></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item :label="$t('overall.newPassword')" prop="newPwd">
@@ -170,8 +201,8 @@
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showChangePin = false">{{$t('overall.cancel')}}</el-button>
<el-button type="primary" @click="submit">{{$t('overall.update')}}</el-button>
<el-button @click="showChangePin = false">{{ $t('overall.cancel') }}</el-button>
<el-button type="primary" @click="submit">{{ $t('overall.update') }}</el-button>
</span>
</template>
</el-dialog>
@@ -179,24 +210,29 @@
</template>
<script>
import { useRoute } from 'vue-router'
import { get, put } from '@/utils/http'
import {
curTabState,
dbDrilldownTableConfig,
entityType,
networkOverviewSearchUrl,
networkOverviewTabList,
networkTable,
operationType,
storageKey,
wholeScreenRouterMapping
wholeScreenRouterMapping,
fromRoute
} from '@/utils/constants'
import { api } from '@/utils/api'
import { ref } from 'vue'
import { combineTabList, getDefaultCurTab, getTabList, overwriteUrl, urlParamsHandler } from '@/utils/tools'
import {
combineTabList,
getDefaultCurTab,
getTabList,
overwriteUrl,
urlParamsHandler,
combinDrilldownTableWithUserConfig,
getDnsMapData,
handleSpecialValue
} from '@/utils/tools'
import { getNowTime, getSecond } from '@/utils/date-util'
import { db } from '@/indexedDB'
export default {
name: 'Header',
@@ -219,17 +255,37 @@ export default {
newPwd2: ''
},
changePassFormRules: {
oldPwd: [{ required: true, message: this.$t('validate.required'), trigger: 'blur' }],
newPwd: [{ required: true, message: this.$t('validate.required'), trigger: 'blur' }],
newPwd2: [{ required: true, message: this.$t('validate.required'), trigger: 'blur' }, { validator: passwordComparison, trigger: 'blur' }]
oldPwd: [{
required: true,
message: this.$t('validate.required'),
trigger: 'blur'
}],
newPwd: [{
required: true,
message: this.$t('validate.required'),
trigger: 'blur'
}],
newPwd2: [{
required: true,
message: this.$t('validate.required'),
trigger: 'blur'
}, {
validator: passwordComparison,
trigger: 'blur'
}]
},
showMenu: false,
dropDownValue: '',
breadcrumbColumnValueListShow: [],
curTabProp: '',
dnsRcodeMapData: new Map(),
dnsQtypeMapData: new Map(),
isDnsMapType: false,
valueMeta: [],
showBackground: false,
selected: false,
valueMenuId: '',
fromRoute: fromRoute,
detectionMenuList: [
{
name: 'securityEvents',
@@ -270,12 +326,24 @@ export default {
},
breadcrumb () {
const breadcrumbMap = []
this.curTabProp = this.$route.query.dimensionType ? this.$route.query.dimensionType : null
this.$store.getters.menuList.forEach(menu => {
if (this.$_.isEmpty(menu.children) && menu.route) {
breadcrumbMap.push({ name: this.$t(menu.i18n), path: menu.route, columnName: menu.columnName, columnValue: menu.columnValue })
breadcrumbMap.push({
name: this.$t(menu.i18n),
path: menu.route,
columnName: menu.columnName,
columnValue: menu.columnValue
})
} else if (!this.$_.isEmpty(menu.children)) {
menu.children.forEach(child => {
breadcrumbMap.push({ name: child.i18n ? this.$t(child.i18n) : child.name, parentName: menu.i18n ? this.$t(menu.i18n) : menu.name, path: child.route, columnName: child.columnName, columnValue: child.columnValue })
breadcrumbMap.push({
name: child.i18n ? this.$t(child.i18n) : child.name,
parentName: menu.i18n ? this.$t(menu.i18n) : menu.name,
path: child.route,
columnName: child.columnName,
columnValue: child.columnValue
})
})
}
})
@@ -312,14 +380,26 @@ export default {
}
}
},
mounted () {
async mounted () {
this.from = Object.keys(this.entityType)[0]
// 是否需要dns的qtype和rcode的数据字典
if(this.$route.params.typeName === fromRoute.dnsServiceInsights) {
this.dnsQtypeMapData = await getDnsMapData('dnsQtype')
this.dnsRcodeMapData = await getDnsMapData('dnsRcode')
}
this.initDropdownList()
},
setup () {
const dateRangeValue = 60
const { startTime, endTime } = getNowTime(dateRangeValue)
const chartTimeFilter = ref({ startTime, endTime, dateRangeValue })
const {
startTime,
endTime
} = getNowTime(dateRangeValue)
const chartTimeFilter = ref({
startTime,
endTime,
dateRangeValue
})
return {
chartTimeFilter,
entityType // 所有entity类型用于header下拉框选择
@@ -350,7 +430,18 @@ export default {
window.location.reload()
})
},
initDropdownList () {
getCurTabByLabel (label) {
let curTab = null
const tableType = this.$route.params ? this.$route.params.typeName : 'networkOverview'
const curTableInCode = networkTable[tableType] ? networkTable[tableType] : networkTable.networkOverview
if (curTableInCode && curTableInCode.tabList) {
curTab = curTableInCode.tabList.find(item => item.label == label)
}
return curTab
},
async initDropdownList () {
// 是否需要dns的qtype和rcode的数据字典
this.curTabProp = this.$route.query.dimensionType ? this.$route.query.dimensionType : null
const currentValue = document.getElementById('breadcrumbValue') ? document.getElementById('breadcrumbValue').innerText : ''
const columnName = this.getUrlParam(this.curTabState.thirdMenu, '')
let type = 'ip'
@@ -369,14 +460,24 @@ export default {
type: type,
name: this.dropDownValue ? this.dropDownValue : ''
}
get(curTableInCode.url.drilldownList, params).then(response => {
get(curTableInCode.url.drilldownList, params).then(async response => {
if (response.code === 200) {
this.breadcrumbColumnValueListShow = response.data.result
if(this.from === fromRoute.dnsServiceInsights) {
this.dnsQtypeMapData = await getDnsMapData('dnsQtype')
this.dnsRcodeMapData = await getDnsMapData('dnsRcode')
}
this.$nextTick(() => {
this.breadcrumbColumnValueListShow.forEach(item => {
const selectedDom = document.getElementById(item)
if (selectedDom) {
if (item === currentValue) {
let itemName = item
if (this.curTabProp === 'qtype') {
itemName = this.dnsQtypeMapData.get(item)
} else if (this.curTabProp === 'rcode') {
itemName = this.dnsRcodeMapData.get(item)
}
if (itemName === currentValue) {
selectedDom.style.cssText = 'color:#0091ff;font-weight: bold;'
} else {
selectedDom.style.cssText = ''
@@ -407,32 +508,34 @@ export default {
},
changeValue (value) {
// 设置面包屑显示的内容及hover时的title
let valName = value
if (this.tab === 'qtype') {
valName = this.dnsQtypeMapData.get(value)
} else if (this.tab === 'rcode') {
valName = this.dnsRcodeMapData.get(value)
}
this.curTabProp = this.$route.query.dimensionType ? this.$route.query.dimensionType : null
document.getElementById('breadcrumbValue').innerText = value
document.getElementById('breadcrumbButton').setAttribute('title', value)
document.getElementById(this.valueMenuId).setAttribute('title', value)
document.getElementById(this.valueMenuId).setAttribute('title', valName)
document.getElementById('breadcrumbButton').click()
// const columnName = this.$store.getters.getBreadcrumbColumnName
const columnName = this.getUrlParam(this.curTabState.thirdMenu, '')
const tabObjGroup = networkOverviewTabList.filter(item => item.label == columnName)
if (tabObjGroup && tabObjGroup.length > 0) {
const curTab = tabObjGroup[0]
if (curTab) {
const queryCondition = []
const searchProps = curTab.dillDownProp
if (curTab.prop === 'protocolPort') {
const valueGroup = value.split(':')
if (valueGroup) {
queryCondition.push("common_l7_protocol='" + valueGroup[0] + "'")
queryCondition.push('common_server_port=' + valueGroup[1])
}
console.log(queryCondition.join(' AND '))
this.urlChangeParams[this.curTabState.queryCondition] = queryCondition.join(' AND ')
} else {
searchProps.forEach(item => {
queryCondition.push(item + "='" + value + "'")
})
this.urlChangeParams[this.curTabState.queryCondition] = queryCondition.join(' OR ')
const curTab = this.getCurTabByLabel(columnName)
if (curTab) {
const queryCondition = []
const searchProps = curTab.dillDownProp
if (curTab.prop === 'protocolPort') {
const valueGroup = value.split(':')
if (valueGroup) {
queryCondition.push('common_l7_protocol=\'' + valueGroup[0] + '\'')
queryCondition.push('common_server_port=' + valueGroup[1])
}
console.log(queryCondition.join(' AND '))
this.urlChangeParams[this.curTabState.queryCondition] = queryCondition.join(' AND ')
} else {
searchProps.forEach(item => {
queryCondition.push(item + '=\'' + handleSpecialValue(value) + '\'')
})
this.urlChangeParams[this.curTabState.queryCondition] = queryCondition.join(' OR ')
}
}
this.changeUrlTabState()
@@ -444,7 +547,10 @@ export default {
submit () {
this.$refs.changePassForm.validate((valid) => {
if (valid) {
put(api.pin, { oldPin: this.changePassForm.oldPwd, newPin: this.changePassForm.newPwd }).then(res => {
put(api.pin, {
oldPin: this.changePassForm.oldPwd,
newPin: this.changePassForm.newPwd
}).then(res => {
if (res.code === 200) {
this.$message.success('Success')
this.showChangePin = false
@@ -466,21 +572,9 @@ export default {
this.urlChangeParams = {}
},
async handleCurDrilldownTableConfig (thirdMenu, fourthMenu) {
const userId = localStorage.getItem(storageKey.userId)
// const userId = localStorage.getItem(storageKey.userId)
const tableType = this.$route.params ? this.$route.params.typeName : 'networkOverview'
// 先从localStorage中获取用户定制的自定义配置如果没有则使用默认的自定义配置
const userLocalConfig = await db[dbDrilldownTableConfig].get({ id: userId })
let drillDownTableConfigs = []
if (userLocalConfig) {
drillDownTableConfigs = userLocalConfig.config
}
if (!drillDownTableConfigs || drillDownTableConfigs.length === 0) { // 未找到当前用户的配置,使用默认配置
const defaultConfig = await db[dbDrilldownTableConfig].get({ id: 'default' })
if (defaultConfig) {
drillDownTableConfigs = defaultConfig.config
}
}
const drillDownTableConfigs = await combinDrilldownTableWithUserConfig()
const currentTableConfig = drillDownTableConfigs.find(config => config.route === tableType)
const tables = currentTableConfig ? currentTableConfig.tables : []
const commonTabList = currentTableConfig ? currentTableConfig.tabs : []
@@ -499,10 +593,6 @@ export default {
}
}
}
await db[dbDrilldownTableConfig].put({
id: userId,
config: this.$_.cloneDeep(drillDownTableConfigs)
})
},
jump (route, columnName, columnValue, opeType) {
this.showMenu = false
@@ -511,7 +601,9 @@ export default {
this.urlChangeParams[this.curTabState.tabOperationBeforeType] = this.getUrlParam(this.curTabState.tabOperationType, '', true)
this.urlChangeParams[this.curTabState.tabOperationType] = opeType
if (opeType === 3) {
this.urlChangeParams.queryCondition = ''
if (route !== '/panel/networkOverview') {
this.urlChangeParams.queryCondition = ''
}
}
} else {
this.urlChangeParams[this.curTabState.tabOperationType] = operationType.mainMenu
@@ -519,7 +611,6 @@ export default {
if (!columnName) { // 点击第二级菜单
this.$store.commit('setNetworkOverviewTabList', [])
}
// 清空网络概况的特殊面包屑
this.$store.getters.menuList.forEach(menu => {
if (!this.$_.isEmpty(menu.children)) {
@@ -530,9 +621,11 @@ export default {
child.columnName = columnName
this.urlChangeParams[this.curTabState.thirdMenu] = columnName
this.urlChangeParams[this.curTabState.fourthMenu] = columnValue
const tabObjGroup = networkOverviewTabList.filter(item => item.label == columnName)
const type = tabObjGroup && tabObjGroup[0] ? tabObjGroup[0].prop : ''
this.urlChangeParams[this.curTabState.dimensionType] = type
// const tabObjGroup = networkOverviewTabList.filter(item => item.label == columnName)
// let curTab = this.getCurTabByLabel()
// const type = curTab ? curTab.prop : ''
// this.curTabProp = this.$route.query.dimensionType ? this.$route.query.dimensionType : null
// this.urlChangeParams[this.curTabState.dimensionType] = type
this.urlChangeParams[this.curTabState.panelName] = columnValue
} else if (columnName) { // 点击的为列名
child.columnValue = ''
@@ -569,11 +662,20 @@ export default {
})
} else if (opeType === 3) {
this.$router.push({
query: { ...this.$route.query, fourthPanel: '', t: +new Date() }
query: {
...this.$route.query,
fourthPanel: '',
t: +new Date()
}
})
} else if (opeType != 4) {
this.$router.push({
query: { ...this.$route.query, fourthPanel: '', thirdPanel: '', t: +new Date() }
query: {
...this.$route.query,
fourthPanel: '',
thirdPanel: '',
t: +new Date()
}
})
}
if (route === this.route) {

View File

@@ -74,6 +74,9 @@
size="small"
:format="dateFormat"
:disabled="!!editObject.id"
:disabled-date="startDisabledDate"
@change="startTimeChang"
@focus="startFocus"
prefix-icon="cn-icon cn-icon-shijian"
type="datetime"
placeholder=" "
@@ -91,6 +94,9 @@
size="small"
:format="dateFormat"
:disabled="!!editObject.id"
:disabled-date="endDisabledDate"
@change="endTimeChange"
@focus="endFocus"
prefix-icon="cn-icon cn-icon-shijian"
type="datetime"
placeholder=" "
@@ -277,6 +283,7 @@ import { api } from '@/utils/api'
import _ from 'lodash'
import { get, post, put } from '@/utils/http'
import { dateFormat, getMillisecond } from '@/utils/date-util'
import { ref } from 'vue'
const paramValidator = (rule, value, callback) => {
let validate = true
if (value && value.length > 0) {
@@ -305,6 +312,58 @@ export default {
categoryList: Array,
currentCategoryId: Number
},
setup () {
const startTime = ref('')
const endTime = ref('')
const focus = ref('')
const focusDate = ref('')
function endTimeChange (val) {
endTime.value = val
}
function startTimeChang (val) {
startTime.value = val
}
function startFocus (val) {
focus.value = val.target.value
}
function endFocus (val) {
focusDate.value = val.target.value
}
const endDisabledDate = (time) => {
if (time.getTime() > new Date()) {
return true
}
if (startTime.value != '' && startTime.value > time) {
return true
}
if (focusDate.value != '' && endTime.value > time) {
return false
} else if (endTime.value != '' && endTime.value < time) {
return true
}
}
const startDisabledDate = (time) => {
if (time.getTime() > new Date()) {
return true
}
if (focus.value != '' && startTime.value > time) {
return false
} else if (startTime.value != '' && startTime.value > time) {
return true
}
if (endTime.value != '' && endTime.value < time) {
return true
}
}
return {
endDisabledDate,
startDisabledDate,
startTimeChang,
endTimeChange,
startFocus,
endFocus
}
},
data () {
return {
url: api.reportTemp,

View File

@@ -19,7 +19,6 @@
<el-table-column type="expand" width="30">
<template #default="props">
<div class="down">
<loading :loading="loadingDown"></loading>
<div class="block drop-down-time">
<el-date-picker
v-model="timeRange"
@@ -34,6 +33,7 @@
/>
</div>
<div class="expand">
<loading :loading="loadingDown"></loading>
<chart-no-data v-if="downDataList.length === 0 && !loadingDown"></chart-no-data>
<div class="expand-cell" v-for="(item, index) in downDataList" :key="index">
<div class="expand-right">

View File

@@ -9,7 +9,7 @@ import commonMixin from '@/mixins/common'
import { cancelWithChange, noData } from '@/utils/tools'
import { ClickOutside } from 'element-plus/lib/directives'
import i18n from '@/i18n'
import '@/mock/index.js'
// import '@/mock/index.js'
import hljsVuePlugin from '@highlightjs/vue-plugin'
import 'highlight.js/styles/color-brewer.css'
import '@/assets/css/main.scss' // 样式入口
@@ -20,18 +20,13 @@ import bus from 'tiny-emitter'
import DateTimeRange from '@/components/common/TimeRange/DateTimeRange'
import TimeRefresh from '@/components/common/TimeRange/TimeRefresh'
import PanelChartList from '@/views/charts/PanelChartList'
import Error from '@/components/common/Error'
import 'lib-flexible'
const emitter = new bus()
const _ = require('lodash') // lodash工具
/* dayjs.extend(utc)
dayjs.extend(timezone)
dayjs.extend(advancedFormat)
dayjs.extend(weekday)
window.$dayJs = dayjs */
const app = createApp(App)
app.use(router)
@@ -52,6 +47,7 @@ app.mixin(commonMixin)
app.component('date-time-range', DateTimeRange)
app.component('time-refresh', TimeRefresh)
app.component('panel-chart-list', PanelChartList)
app.component('chart-error', Error)
app.mount('#app')

View File

@@ -51,7 +51,15 @@ const panel = {
npmLocationCountry: '', // npm location的查询条件--国家
npmLocationSide: 'server', // npm location的查询条件--方向
refreshTime: null, // 自动刷新时间的秒数
refreshFlag: true // 关闭自动刷新标志true为offfalse即开启自动刷新
refreshFlag: true, // 关闭自动刷新标志true为offfalse即开启自动刷新
timeRangeArray: [], // 时间范围列表:开始/结束时间
timeRangeFlag: null, // 时间范围标志默认60即一小时-1为手动选择的时间范围
routerPath: '', // 当前路由路径
httpCancel: null, // 终止http请求
rangeEchartsData: {}, // 框选echarts图表
routerHistoryList: [], // 路由跳转记录列表
dnsQtypeMapData:[],
dnsRcodeMapData:[]
},
mutations: {
setShowRightBox (state, flag) {
@@ -102,36 +110,15 @@ const panel = {
setCurrentMap (state, currentMap) {
state.currentMap = currentMap
},
// setPanelName (state, panelName) {
// state.panelName = panelName
// },
// setBreadcrumbColumnName (state, breadcrumbColumnName) {
// state.breadcrumbColumnName = breadcrumbColumnName
// },
// setDimensionType (state, dimensionType) {
// state.dimensionType = dimensionType
// },
// setBreadcrumbColumnValue (state, breadcrumbColumnValue) {
// state.breadcrumbColumnValue = breadcrumbColumnValue
// },
// setNetworkOverviewCurrentTab (state, networkOverviewCurrentTab) {
// state.networkOverviewCurrentTab = networkOverviewCurrentTab
// },
// setQueryCondition (state, queryCondition) {
// state.queryCondition = queryCondition
// },
setDnsQtypeMapData (state, dnsQtypeMapData) {
state.dnsQtypeMapData = dnsQtypeMapData
},
setDnsRcodeMapData (state, dnsRcodeMapData) {
state.dnsRcodeMapData = dnsRcodeMapData
},
setNetworkOverviewTabList (state, networkOverviewTabList) {
state.networkOverviewTabList = networkOverviewTabList
},
// setTabOperationType (state, tabOperationType) {
// state.tabOperationType = tabOperationType
// },
// setNetworkOverviewBeforeTab (state, networkOverviewBeforeTab) {
// state.networkOverviewBeforeTab = networkOverviewBeforeTab
// },
// setTabOperationBeforeType (state, tabOperationBeforeType) {
// state.tabOperationBeforeType = tabOperationBeforeType
// },
setNpmLocationCountry (state, country) {
state.npmLocationCountry = country
},
@@ -146,6 +133,24 @@ const panel = {
},
setRefreshFlag (state, flag) {
state.refreshFlag = flag
},
setTimeRangeArray (state, array) {
state.timeRangeArray = array
},
setTimeRangeFlag (state, flag) {
state.timeRangeFlag = flag
},
setRouterPath (state, path) {
state.routerPath = path
},
setHttpCancel (state, cancel) {
state.httpCancel = cancel
},
setRangeEchartsData (state, data) {
state.rangeEchartsData = data
},
setRouterHistoryList (state, list) {
state.routerHistoryList = list
}
},
getters: {
@@ -191,36 +196,15 @@ const panel = {
getCurrentMap (state) {
return state.currentMap
},
// getPanelName (state) {
// return state.panelName
// },
// getBreadcrumbColumnName (state) {
// return state.breadcrumbColumnName
// },
// getDimensionType (state) {
// return state.dimensionType
// },
// getBreadcrumbColumnValue (state) {
// return state.breadcrumbColumnValue
// },
// getNetworkOverviewCurrentTab (state) {
// return state.networkOverviewCurrentTab
// },
// getQueryCondition (state) {
// return state.queryCondition
// },
getDnsQtypeMapData (state) {
return state.dnsQtypeMapData
},
getDnsRcodeMapData (state) {
return state.dnsRcodeMapData
},
getNetworkOverviewTabList (state) {
return state.networkOverviewTabList
},
// getTabOperationType (state) {
// return state.tabOperationType
// },
// getNetworkOverviewBeforeTab (state) {
// return state.networkOverviewBeforeTab
// },
// getTabOperationBeforeType (state) {
// return state.tabOperationBeforeType
// },
getNpmLocationCountry (state) {
return state.npmLocationCountry
},
@@ -229,6 +213,18 @@ const panel = {
},
getNpmThirdLevelMenuScore (state) {
return state.npmThirdLevelMenuScore
},
getTimeRangeArray (state) {
return state.timeRangeArray
},
getTimeRangeFlag (state) {
return state.timeRangeFlag
},
getRouterPath (state) {
return state.routerPath
},
getRouterHistoryList (state) {
return state.routerHistoryList
}
},
actions: {

View File

@@ -3,6 +3,7 @@ import router from '@/router'
import { sortByOrderNum, getWelcomeMenu } from '@/permission'
import { ElMessage } from 'element-plus' // dependent on utc plugin
import { storageKey, dbDrilldownTableConfig } from '@/utils/constants'
import { getConfigVersion } from '@/utils/tools'
import { api } from '@/utils/api'
import { db } from '@/indexedDB'
@@ -11,7 +12,8 @@ const user = {
return {
menuList: [],
buttonList: [],
roleList: []
roleList: [],
drilldownTableConfigList: []
}
},
mutations: {
@@ -24,6 +26,9 @@ const user = {
setRoleList (state, roleList) {
state.roleList = [...roleList]
},
setDrilldownTableList (state, drilldownTableConfigList) {
state.drilldownTableConfigList = [...drilldownTableConfigList]
},
clean (state) {
state.menuList = []
state.buttonList = []
@@ -39,6 +44,9 @@ const user = {
},
roleList (state) {
return state.roleList
},
drilldownTableConfigList (state) {
return state.drilldownTableConfigList
}
},
actions: {
@@ -82,13 +90,18 @@ const user = {
})
get(api.config, { ckey: 'drill_down_table_config' }).then(async res => {
if (res.code === 200 && res.page.list && res.page.list.length > 0) {
// 从接口返回整体配置,再读取用户缓存,将对应条目覆盖,作为使用的配置
const defaultConfigs = JSON.parse(res.page.list[0].cvalue)
await db[dbDrilldownTableConfig].put({
id: 'default',
config: JSON.parse(res.page.list[0].cvalue)
version: defaultConfigs.version,
config: defaultConfigs.config
})
// const a = await db[dbDrilldownTableConfig].get({ id: 'default' })
// console.info(a)
// localStorage.setItem(storageKey.drillDownTableConfig, res.page.list[0].cvalue)
let userId = localStorage.getItem(storageKey.userId)
let oldVersion = await getConfigVersion(userId)
if(oldVersion !== defaultConfigs.version ){
db[dbDrilldownTableConfig].delete(userId)
}
}
})
get(api.config, { ckey: 'link_info' }).then(res => {

View File

@@ -161,12 +161,19 @@ export const api = {
appSslConDelay: '/interface/application/performance/overview/appSslConDelay',
appTcpLostlenPercent: '/interface/application/performance/overview/appTcpLostlenPercent',
appPacketRetransPercent: '/interface/application/performance/overview/appPacketRetransPercent',
// 整体流量折线图
totalTrafficAnalysis: '/interface/application/performance/overview/totalTrafficAnalysis',
totalNetworkAnalysis: '/interface/application/performance/overview/totalNetworkAnalysis',
totalHttpResponseDelay: '/interface/application/performance/overview/totalHttpResponseDelay',
totalSslConDelay: '/interface/application/performance/overview/totalSslConDelay',
// 各维度下钻会话统计
relatedSessions: '/interface/application/performance/relatedSessions',
// 各维度下钻流量曲线图
trafficGraph: '/interface/application/performance/overview/drilldown/drilldown/dimension/trafficGraph',
// 各维度下钻网络性能
networkAnalysis: '/interface/application/performance/overview/drilldown/dimension/networkAnalysis',
// 各维度下钻网络性能 三级菜单
allNetworkAnalysis: '/interface/application/performance/overview/drilldown/dimension/allNetworkAnalysis',
// 下钻地图
map: '/interface/application/performance/overview/drilldown/dimension/clientLocations/world/trafficAnalysis',
mapTcp: '/interface/application/performance/overview/drilldown/dimension/clientLocations/world/tcpSessionDelay',
@@ -220,7 +227,8 @@ export const api = {
recentEvents: '/interface/dnsInsight/recentEvents',
activeMaliciousDomain: '/interface/dnsInsight/activeMaliciousDomain',
totalTrafficAnalysis: '/interface/dns/overview/totalTrafficAnalysis',
eventChart: '/interface/dnsInsight/eventChart'
eventChart: '/interface/dnsInsight/eventChart',
drilldownTrafficAnalysis: '/interface/dns/overview/drilldown/trafficAnalysis'
}
}

View File

@@ -31,7 +31,7 @@ export const storageKey = {
echartLegendFontSize: 'echartLegendFontSize',
echartLabelFontSize: 'echartLabelFontSize',
tokenExpireCurrentPath: 'token-expire-current-path',
drillDownTableConfig: 'cn-drill-down-table-config',
drillDownTableConfig: 'drilldownTableConfig',
userCustomizationConfig: 'userCustomizationConfig',
linkInfo: 'cn-link-info',
history: 'cn-history'
@@ -186,6 +186,21 @@ export const networkOverviewTabs = [
'network.protocolPorts'
] */
export const metricOptions = [
{
value: 'Bits/s',
label: 'Bits/s'
},
{
value: 'Packets/s',
label: 'Packets/s'
},
{
value: 'Sessions/s',
label: 'Sessions/s'
}
]
export const operationType = {
mainMenu: 0, // 菜单
secondMenu: 2, // 二级菜单
@@ -276,7 +291,8 @@ export const curTabState = {
fourthPanel: 'fourthPanel',
networkOverviewBeforeTab: 'networkOverviewBeforeTab',
tabOperationType: 'tabOperationType',
tabOperationBeforeType: 'tabOperationBeforeType'
tabOperationBeforeType: 'tabOperationBeforeType',
tabIndex: 'tabIndex'
}
export const scoreUrl = [
@@ -287,11 +303,11 @@ export const scoreUrl = [
// AppPerformance类型表格的列有属性cycleDataUrl的代表此数据的来源为对应接口返回的数据无cycleDataUrl的属性代表数据来源于主urlnpmSearchUrl.curUrl、npmSearchUrl.cycleUrl、npmSearchUrl.drilldownCurUrl、npmSearchUrl.drilldownCycleUrl
export const customTableTitlesForAppPerformance = [
{ label: 'network.ips', prop: 'tab', checked: true, tabColumn: true, columnType: tableColumnType.dillDown },
{ label: 'IP', prop: 'tab', checked: true, tabColumn: true, columnType: tableColumnType.dillDown },
{ label: 'network.score', prop: 'score', checked: true, tabColumn: false, columnType: tableColumnType.normal },
{
label: 'networkAppPerformance.throughput',
prop: 'through',
prop: 'totalBytes',
checked: true,
tabColumn: false,
columnType: tableColumnType.chainRatio,
@@ -375,11 +391,11 @@ export const customTableTitlesForAppPerformance = [
}
]
export const customTableTitlesForLinkMonitor = [
{ label: 'network.ips', prop: 'tab', checked: true, tabColumn: true, columnType: tableColumnType.dillDown },
{ label: 'IP', prop: 'tab', checked: true, tabColumn: true, columnType: tableColumnType.dillDown },
{ label: 'network.score', prop: 'score', checked: true, tabColumn: false, columnType: tableColumnType.normal },
{
label: 'networkAppPerformance.throughput',
prop: 'through',
prop: 'totalBytes',
checked: true,
tabColumn: false,
columnType: tableColumnType.chainRatio,
@@ -479,7 +495,7 @@ export const customTableTitlesForDns = [
]
// NetworkOverview类型表格的列:prop 为接口响应数据中的属性名
export const customTableTitlesForNetworkOverview = [
{ label: 'network.ips', prop: 'tab', checked: true, tabColumn: true, columnType: tableColumnType.dillDown },
{ label: 'IP', prop: 'tab', checked: true, tabColumn: true, columnType: tableColumnType.dillDown },
{
label: 'network.total',
prop: 'total',
@@ -637,6 +653,118 @@ export const networkOverviewTabList = [
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.networkOverview
}, {
label: 'network.clientIps',
prop: 'clientIp',
queryCycleTotalProp: 'clientIps',
dillDownProp: ['common_client_ip'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.networkOverview
}, {
label: 'network.serverIps',
prop: 'serverIp',
queryCycleTotalProp: 'serverIps',
dillDownProp: ['common_server_ip'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.networkOverview
}, {
label: 'network.clientCountries',
prop: 'clientCountry',
queryCycleTotalProp: 'clientCountries',
dillDownProp: ['client_country'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.networkOverview
}, {
label: 'network.serverCountries',
prop: 'serverCountry',
queryCycleTotalProp: 'serverCountries',
dillDownProp: ['server_country'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.networkOverview
}, {
label: 'network.clientProvinces',
prop: 'clientProvince',
queryCycleTotalProp: 'clientProvinces',
dillDownProp: ['client_province'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.networkOverview
}, {
label: 'network.serverProvinces',
prop: 'serverProvince',
queryCycleTotalProp: 'serverProvinces',
dillDownProp: ['server_province'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.networkOverview
}, {
label: 'network.clientCities',
prop: 'clientCity',
queryCycleTotalProp: 'clientCities',
dillDownProp: ['client_region'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.networkOverview
}, {
label: 'network.serverCities',
prop: 'serverCity',
queryCycleTotalProp: 'serverCities',
dillDownProp: ['server_region'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.networkOverview
}, {
label: 'network.clientIsps',
prop: 'clientIsp',
queryCycleTotalProp: 'clientIsps',
dillDownProp: ['client_isp'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.networkOverview
}, {
label: 'network.serverIsps',
prop: 'serverIsp',
queryCycleTotalProp: 'serverIsps',
dillDownProp: ['server_isp'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.networkOverview
}, {
label: 'network.clientIdcRenters',
prop: 'clientIdcRenter',
queryCycleTotalProp: 'clientIdcRenters',
dillDownProp: ['client_idc_renter'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.networkOverview
}, {
label: 'network.serverIdcRenters',
prop: 'serverIdcRenter',
queryCycleTotalProp: 'serverIdcRenters',
dillDownProp: ['server_idc_renter'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.networkOverview
}, {
label: 'network.clientAsns',
prop: 'clientAsn',
queryCycleTotalProp: 'clientAsns',
dillDownProp: ['client_asn'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.networkOverview
}, {
label: 'network.serverAsns',
prop: 'serverAsn',
queryCycleTotalProp: 'serverAsns',
dillDownProp: ['server_asn'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.networkOverview
}
]
@@ -769,6 +897,118 @@ export const networkAppPerformanceTabList = [
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.npmOverviewCommon
}, {
label: 'network.clientIps',
prop: 'clientIp',
queryCycleTotalProp: 'clientIps',
dillDownProp: ['common_client_ip'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.npmOverviewCommon
}, {
label: 'network.serverIps',
prop: 'serverIp',
queryCycleTotalProp: 'serverIps',
dillDownProp: ['common_server_ip'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.npmOverviewCommon
}, {
label: 'network.clientCountries',
prop: 'clientCountry',
queryCycleTotalProp: 'clientCountries',
dillDownProp: ['client_country'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.npmOverviewCommon
}, {
label: 'network.serverCountries',
prop: 'serverCountry',
queryCycleTotalProp: 'serverCountries',
dillDownProp: ['server_country'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.npmOverviewCommon
}, {
label: 'network.clientProvinces',
prop: 'clientProvince',
queryCycleTotalProp: 'clientProvinces',
dillDownProp: ['client_province'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.npmOverviewCommon
}, {
label: 'network.serverProvinces',
prop: 'serverProvince',
queryCycleTotalProp: 'serverProvinces',
dillDownProp: ['server_province'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.npmOverviewCommon
}, {
label: 'network.clientCities',
prop: 'clientCity',
queryCycleTotalProp: 'clientCities',
dillDownProp: ['client_region'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.npmOverviewCommon
}, {
label: 'network.serverCities',
prop: 'serverCity',
queryCycleTotalProp: 'serverCities',
dillDownProp: ['server_region'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.npmOverviewCommon
}, {
label: 'network.clientIsps',
prop: 'clientIsp',
queryCycleTotalProp: 'clientIsps',
dillDownProp: ['client_isp'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.npmOverviewCommon
}, {
label: 'network.serverIsps',
prop: 'serverIsp',
queryCycleTotalProp: 'serverIsps',
dillDownProp: ['server_isp'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.npmOverviewCommon
}, {
label: 'network.clientIdcRenters',
prop: 'clientIdcRenter',
queryCycleTotalProp: 'clientIdcRenters',
dillDownProp: ['client_idc_renter'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.npmOverviewCommon
}, {
label: 'network.serverIdcRenters',
prop: 'serverIdcRenter',
queryCycleTotalProp: 'serverIdcRenters',
dillDownProp: ['server_idc_renter'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.npmOverviewCommon
}, {
label: 'network.clientAsns',
prop: 'clientAsn',
queryCycleTotalProp: 'clientAsns',
dillDownProp: ['client_asn'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.npmOverviewCommon
}, {
label: 'network.serverAsns',
prop: 'serverAsn',
queryCycleTotalProp: 'serverAsns',
dillDownProp: ['server_asn'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.npmOverviewCommon
}
]
export const linkMonitorTabList = [
@@ -900,6 +1140,118 @@ export const linkMonitorTabList = [
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.linkMonitor
}, {
label: 'network.clientIps',
prop: 'clientIp',
queryCycleTotalProp: 'clientIps',
dillDownProp: ['common_client_ip'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.linkMonitor
}, {
label: 'network.serverIps',
prop: 'serverIp',
queryCycleTotalProp: 'serverIps',
dillDownProp: ['common_server_ip'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.linkMonitor
}, {
label: 'network.clientCountries',
prop: 'clientCountry',
queryCycleTotalProp: 'clientCountries',
dillDownProp: ['client_country'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.linkMonitor
}, {
label: 'network.serverCountries',
prop: 'serverCountry',
queryCycleTotalProp: 'serverCountries',
dillDownProp: ['server_country'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.linkMonitor
}, {
label: 'network.clientProvinces',
prop: 'clientProvince',
queryCycleTotalProp: 'clientProvinces',
dillDownProp: ['client_province'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.linkMonitor
}, {
label: 'network.serverProvinces',
prop: 'serverProvince',
queryCycleTotalProp: 'serverProvinces',
dillDownProp: ['server_province'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.linkMonitor
}, {
label: 'network.clientCities',
prop: 'clientCity',
queryCycleTotalProp: 'clientCities',
dillDownProp: ['client_region'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.linkMonitor
}, {
label: 'network.serverCities',
prop: 'serverCity',
queryCycleTotalProp: 'serverCities',
dillDownProp: ['server_region'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.linkMonitor
}, {
label: 'network.clientIsps',
prop: 'clientIsp',
queryCycleTotalProp: 'clientIsps',
dillDownProp: ['client_isp'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.linkMonitor
}, {
label: 'network.serverIsps',
prop: 'serverIsp',
queryCycleTotalProp: 'serverIsps',
dillDownProp: ['server_isp'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.linkMonitor
}, {
label: 'network.clientIdcRenters',
prop: 'clientIdcRenter',
queryCycleTotalProp: 'clientIdcRenters',
dillDownProp: ['client_idc_renter'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.linkMonitor
}, {
label: 'network.serverIdcRenters',
prop: 'serverIdcRenter',
queryCycleTotalProp: 'serverIdcRenters',
dillDownProp: ['server_idc_renter'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.linkMonitor
}, {
label: 'network.clientAsns',
prop: 'clientAsn',
queryCycleTotalProp: 'clientAsns',
dillDownProp: ['client_asn'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.linkMonitor
}, {
label: 'network.serverAsns',
prop: 'serverAsn',
queryCycleTotalProp: 'serverAsns',
dillDownProp: ['server_asn'],
checked: false,
disabled: false,
panelId: drillDownPanelTypeMapping.linkMonitor
}
]
export const dnsServiceInsightsTabList = [
@@ -953,6 +1305,7 @@ export const dnsServiceInsightsTabList = [
prop: 'dnsServerRole',
queryCycleTotalProp: 'roles',
dillDownProp: ['dns_server_role'],
queryCondition: ['has(dns_server_role,\'$param\')'],
checked: true,
disabled: false,
panelId: drillDownPanelTypeMapping.dnsFourthMenu
@@ -971,6 +1324,7 @@ export const dnsServiceInsightsTabList = [
prop: 'sld',
queryCycleTotalProp: 'slds',
dillDownProp: ['dns_qname'],
queryCondition: ['cutToFirstSignificantSubdomain(dns_qname) = \'$param\''],
checked: true,
disabled: false,
panelId: drillDownPanelTypeMapping.dnsFourthMenu
@@ -980,6 +1334,7 @@ export const dnsServiceInsightsTabList = [
prop: 'tld',
queryCycleTotalProp: 'tlds',
dillDownProp: ['dns_qname'],
queryCondition: [' topLevelDomain(dns_qname) = \'$param\''],
checked: true,
disabled: false,
panelId: drillDownPanelTypeMapping.dnsFourthMenu
@@ -989,6 +1344,7 @@ export const dnsServiceInsightsTabList = [
prop: 'qtype',
queryCycleTotalProp: 'qtypes',
dillDownProp: ['dns_qtype'],
queryCondition: ['dns_qtype = $param'],
checked: true,
disabled: false,
panelId: drillDownPanelTypeMapping.dnsFourthMenu
@@ -998,6 +1354,7 @@ export const dnsServiceInsightsTabList = [
prop: 'rcode',
queryCycleTotalProp: 'rcodes',
dillDownProp: ['dns_rcode'],
queryCondition: ['dns_rcode = $param'],
checked: true,
disabled: false,
panelId: drillDownPanelTypeMapping.dnsFourthMenu
@@ -1007,6 +1364,7 @@ export const dnsServiceInsightsTabList = [
prop: 'a',
queryCycleTotalProp: 'a',
dillDownProp: ['rr_a'],
queryCondition: ['notEmpty(dns_rr) AND has(JSONExtractArrayRaw(JSON_QUERY(\'$.rr[*].type\', dns_rr) ), \'1\') AND arrayJoin(tupleElement(tupleElement(JSONExtract(dns_rr,\'Tuple(rr Nested(name String, type UInt32, a String))\'), \'rr\'), \'a\')) = \'$param\''],
checked: true,
disabled: false,
panelId: drillDownPanelTypeMapping.dnsFourthMenu
@@ -1016,6 +1374,7 @@ export const dnsServiceInsightsTabList = [
prop: 'aaaa',
queryCycleTotalProp: 'aaaa',
dillDownProp: ['rr_aaaa'],
queryCondition: ['notEmpty(dns_rr) and has(JSONExtractArrayRaw(JSON_QUERY(\'$.rr[*].type\', dns_rr) ), \'28\') AND arrayJoin(tupleElement(tupleElement(JSONExtract(dns_rr,\'Tuple(rr Nested(name String, type UInt32, aaaa String))\'), \'rr\'), \'aaaa\')) = \'$param\''],
checked: true,
disabled: false,
panelId: drillDownPanelTypeMapping.dnsFourthMenu
@@ -1025,6 +1384,7 @@ export const dnsServiceInsightsTabList = [
prop: 'cname',
queryCycleTotalProp: 'cnames',
dillDownProp: ['rr_cname'],
queryCondition: ['notEmpty(dns_rr) and has(JSONExtractArrayRaw(JSON_QUERY(\'$.rr[*].type\', dns_rr) ), \'5\') AND arrayJoin(tupleElement(tupleElement(JSONExtract(dns_rr,\'Tuple(rr Nested(name String, type UInt32, cname String))\'), \'rr\'), \'cname\')) = \'$param\''],
checked: true,
disabled: false,
panelId: drillDownPanelTypeMapping.dnsFourthMenu
@@ -1033,7 +1393,7 @@ export const dnsServiceInsightsTabList = [
// 用于组织数据时的名称,对应的属性名称
export const bytesColumnNameGroupForNpm = {
through: 'throughBitsRate',
totalBytes: 'totalBytes',
tcpConEstLatency: 'establishLatencyMs',
packetLoss: 'tcpLostlenPercent',
packetRetrans: 'pktRetransPercent',
@@ -1041,8 +1401,8 @@ export const bytesColumnNameGroupForNpm = {
httpResponseLatency: 'httpResponseLatency'
}
export const bytesCycleColumnNameGroupForNmp = {
through: 'throughBitsRate'
export const bytesCycleColumnNameGroupForNpm = {
totalBytes: 'totalBytes'
}
// 用于组织数据时的名称,对应的属性名称
@@ -1059,14 +1419,14 @@ export const bytesCycleColumnNameGroupForDns = {
// networkOverview 当前周期返回数据对应的属性名称(与上一周期中的属性名称不一致,total,之所以写在这里是因为有bytepacketssessions3种如果只有一种可以直接写在customTableTitlesForAppPerformance
export const bytesColumnNameGroup = {
total: 'bytesTotalRate',
total: 'totalBitsRate',
inbound: 'inboundBitsRate',
outbound: 'outboundBitsRate',
internal: 'internalBitsRate',
through: 'throughBitsRate'
}
export const packetsColumnNameGroup = {
total: 'packetsTotalRate',
total: 'totalPacketsRate',
inbound: 'inboundPacketsRate',
outbound: 'outboundPacketsRate',
internal: 'internalPacketsRate',
@@ -1077,7 +1437,7 @@ export const sessionsColumnNameGroup = {
}
export const bytesCycleColumnNameGroup = {
total: 'bytesRate'
total: 'bitsRate'
}
export const packetsCycleColumnNameGroup = {
total: 'packetsRate'
@@ -1110,7 +1470,7 @@ export const networkTable = {
bytesColumnNameGroup: bytesColumnNameGroupForNpm,
packetsColumnNameGroup: {}, // 无metric下拉列表条件用不到此属性
sessionsColumnNameGroup: {}, // 无metric下拉列表条件用不到此属性
bytesCycleColumnNameGroup: bytesCycleColumnNameGroupForNmp,
bytesCycleColumnNameGroup: bytesCycleColumnNameGroupForNpm,
packetsCycleColumnNameGroup: {},
sessionsCycleColumnNameGroup: {}
},
@@ -1131,7 +1491,7 @@ export const networkTable = {
hasMetricSearch: false, // 是否有metric下拉列表
panelIdOfThirdMenu: drillDownPanelTypeMapping.linkMonitor,
bytesColumnNameGroup: bytesColumnNameGroupForNpm,
bytesCycleColumnNameGroup: bytesCycleColumnNameGroupForNmp
bytesCycleColumnNameGroup: bytesCycleColumnNameGroupForNpm
}
}

View File

@@ -69,3 +69,26 @@ export function dateFormatToUTC (date, format = 'YYYY-MM-DD HH:mm:ss') {
d = window.$dayJs(d).tz().format(format)
return d
}
/**
* 时间戳转年月日时分秒置于数组中配合el-date-picker使用
* @param time
* @returns {number[]}
*/
export function timestampToList (time) {
// 根据地址获取当前时区
const newTimezone = window.$dayJs.tz().utcOffset() / 60
// 缓存的本地时区
const localTimezone = parseInt(localStorage.getItem(storageKey.timezoneLocalOffset))
const date = new Date(getMillisecond(time + (newTimezone - localTimezone) * 3600))
const Y = date.getFullYear()
const M = date.getMonth()
const D = date.getDate()
const H = date.getHours()
const m = date.getMinutes()
const s = date.getSeconds()
const arr = [Y, M, D, H, m, s]
return arr
}

View File

@@ -1,8 +1,20 @@
import axios from 'axios'
import { storageKey } from '@/utils/constants'
import store from '@/store'
const CancelToken = axios.CancelToken
axios.interceptors.request.use(config => {
const token = localStorage.getItem(storageKey.token)
// 添加http请求终止方法
const arr = []
const cancelToken = new CancelToken(function executor (c) {
arr.push(c)
store.commit('setHttpCancel', arr)
})
config.cancelToken = cancelToken
if (token) {
config.headers['Cn-Authorization'] = token // 请求头token
}

View File

@@ -2,7 +2,7 @@ import { ElMessageBox, ElMessage } from 'element-plus'
import i18n from '@/i18n'
import _ from 'lodash'
import { storageKey, iso36112, topDomain, echartsFontSize, dbGeoDataTableName, networkTable, dbDrilldownTableConfig } from '@/utils/constants'
import { getIso36112JsonData } from '@/utils/api'
import { getIso36112JsonData, getDictList } from '@/utils/api'
import { format } from 'echarts'
import router from '@/router'
import { db } from '@/indexedDB'
@@ -780,66 +780,55 @@ export function getChainRatio (current, prev) {
}
}
export function computeScore (data, index) {
export function computeScore (data) {
let score = 0
let k = 0
if (index === 0) {
k = 0.3
if (!data.establishLatencyMs && data.establishLatencyMs !== 0) {
score = 0
} else if (data.establishLatencyMs <= 50) {
score = 1
} else if (data.establishLatencyMs > 500) {
score = 0
} else {
score = (data.establishLatencyMs - 500) / (50 - 500)
let totalScore = 0
const scoreArr = []
let num = 0
Object.keys(data).forEach(t => {
if (!data[t]) {
num += 1
}
} else if (index === 1) {
k = 0.05
if (!data.httpResponseLatency && data.httpResponseLatency !== 0) {
score = 1
} else if (data.httpResponseLatency <= 50) {
score = 1
} else if (data.httpResponseLatency > 500) {
score = 0
} else {
score = (data.httpResponseLatency - 500) / (50 - 500)
if (t === 'establishLatencyMs' || t === 'tcpLostlenPercent' || t === 'pktRetransPercent') {
k = 0.3
} else if (t === 'httpResponseLatency' || t === 'sslConLatency') {
k = 0.05
}
} else if (index === 2) {
k = 0.05
if (!data.sslConLatency && data.sslConLatency !== 0) {
score = 1
} else if (data.sslConLatency <= 50) {
score = 1
} else if (data.sslConLatency > 500) {
score = 0
} else {
score = (data.sslConLatency - 500) / (50 - 500)
}
} else if (index === 3) {
k = 0.3
if (!data.tcpLostlenPercent && data.tcpLostlenPercent !== 0) {
score = 0
} else if (data.tcpLostlenPercent <= 0.01) {
score = 1
} else if (data.tcpLostlenPercent > 0.5) {
score = 0
} else {
score = (data.tcpLostlenPercent - 0.5) / (0.01 - 0.5)
}
} else if (index === 4) {
k = 0.3
if (!data.pktRetransPercent && data.pktRetransPercent !== 0) {
score = 0
} else if (data.pktRetransPercent <= 0.01) {
score = 1
} else if (data.pktRetransPercent > 0.5) {
score = 0
} else {
score = (data.pktRetransPercent - 0.5) / (0.01 - 0.5)
if (t === 'establishLatencyMs' || t === 'httpResponseLatency' || t === 'sslConLatency') {
if (!data[t] && data[t] !== 0) {
score = 1
} else if (data[t] <= 50) {
score = 1
} else if (data[t] > 200) {
score = 0
} else {
score = (data[t] - 200) / (50 - 200)
}
} else if (t === 'tcpLostlenPercent' || t === 'pktRetransPercent') {
if (!data[t] && data[t] !== 0) {
score = 1
} else if (data[t] <= 0.01) {
score = 1
} else if (data[t] > 0.05) {
score = 0
} else {
score = (data[t] - 0.05) / (0.01 - 0.05)
}
}
scoreArr.push(score * k)
})
scoreArr.forEach(t => {
totalScore += t
})
totalScore = Math.ceil(totalScore * 6)
if (totalScore > 6) {
totalScore = 6
}
return score * k
if (num === 5) {
return '-'
}
return totalScore
}
// 改变tab状态(url中)当前tab
@@ -851,7 +840,6 @@ export function changeTabState (param, value) {
})
}
export function getTabList (curTable, curMetric) {
console.log('getTabList--------------')
let tabs = []
if (curTable.hasMetricSearch) { // 有metric
const metricsList = curTable ? curTable.metrics : []
@@ -866,35 +854,61 @@ export function getTabList (curTable, curMetric) {
}
return tabs
}
export async function getDnsMapData (type) {
const codeValueMap = new Map()
const dnsData = await getDictList({ type: type, pageSize: -1 })
if (dnsData && dnsData.length > 0) {
dnsData.forEach(mapData => {
const code = mapData.code
if (code.indexOf('-') > -1) {
const range = mapData.code.split('-')
if (range && range.length >= 2) {
const start = range[0].trim()
const eEnd = range[1].trim()
mapData.value = (start <= code && code <= eEnd) ? mapData.value : code
for (let i = start; i <= eEnd; i++) {
codeValueMap.set(i, mapData.value)
}
}
} else {
codeValueMap.set(code, mapData.value)
}
})
}
return codeValueMap
}
export function handleSpecialValue(value){
value = value.replaceAll("'", "\\\\'")
.replaceAll('"','\\"')
.replaceAll('&','%26')
return value
}
export function combineTabList (tableType, list, commonTabList) {
const curTableInCode = networkTable[tableType] ? networkTable[tableType] : networkTable.networkOverview
const listInCode = curTableInCode ? curTableInCode.tabList : []
list.forEach(tab => {
// 配置的内容
const tabName = tab ? (tab.name ? tab.name : tab) : ''
// 配置的内容
const commonTab = commonTabList.find(item => item.name === tabName)
tab.label = commonTab ? commonTab.i18n : ''
tab.prop = commonTab ? commonTab.prop : ''
if (!tab.hasOwnProperty('checked')) {
const tabName = tab ? (tab.name ? tab.name : tab) : ''
// 配置的内容
tab = {}
const commonTab = commonTabList.find(item => item.name === tabName)
tab.label = commonTab ? commonTab.i18n : ''
tab.prop = commonTab ? commonTab.prop : ''
if (!tab.hasOwnProperty('checked')) {
tab.checked = tab ? tab.show : true
}
if (!tab.hasOwnProperty('disabled')) {
tab.disabled = tab ? !tab.enable : false
}
if (!tab.hasOwnProperty('panelId')) {
tab.panelId = tab ? tab.panelIdOfFourthMenu : null
}
// 代码里写死的
const tabInCode = listInCode ? listInCode.find(item => item.label === tab.label) : {}
tab.queryCycleTotalProp = tabInCode ? tabInCode.queryCycleTotalProp : null
tab.dillDownProp = tabInCode ? tabInCode.dillDownProp : []
tab.checked = tab ? tab.show : true
}
if (!tab.hasOwnProperty('disabled')) {
tab.disabled = tab ? !tab.enable : false
}
if (!tab.hasOwnProperty('panelId')) {
tab.panelId = tab ? tab.panelIdOfFourthMenu : null
}
// 代码里写死的
const tabInCode = listInCode ? listInCode.find(item => item.label === tab.label) : {}
tab.queryCycleTotalProp = tabInCode ? tabInCode.queryCycleTotalProp : null
tab.dillDownProp = tabInCode ? tabInCode.dillDownProp : []
})
}
/*
export function setUserConfig () {
const userTableConfig = this.getUserLocalConfig()
if (userTableConfig) {
@@ -911,45 +925,71 @@ export function setUserConfig () {
this.list = newTabConfigs
}
}
*/
export async function getDefaultCurTab (tableType, metric, columnName) {
const tabList = await getUserDrilldownTableConfig(tableType, metric)
const curTab = tabList.filter(item => item.label === columnName)[0]
return curTab
}
export async function getUserDrilldownTableConfig (tableType, curMetric) {
let list = []
// 先从localStorage中获取用户定制的自定义配置如果没有则使用默认的自定义配置
export async function readDrilldownTableConfigByUser () {
// 获取用户定制的自定义配置
const userId = localStorage.getItem(storageKey.userId)
const userLocalCongfig = await db[dbDrilldownTableConfig].get({ id: userId })
let defaultDrillDownTableConfigs = []
if (userLocalCongfig) {
defaultDrillDownTableConfigs = userLocalCongfig.config
}
if (!defaultDrillDownTableConfigs || defaultDrillDownTableConfigs.length === 0) { // 未找到当前用户的配置,使用默认配置
console.log('default..............')
const defaultCongfig = await db[dbDrilldownTableConfig].get({ id: 'default' })
if (defaultCongfig) {
defaultDrillDownTableConfigs = defaultCongfig.config
}
return defaultDrillDownTableConfigs
}
export async function getConfigVersion (id) {
let defaultCongfigInDb = await db[dbDrilldownTableConfig].get({ id: id })
let version
if(defaultCongfigInDb) {
version = defaultCongfigInDb ? defaultCongfigInDb.version : ''
}else {
defaultCongfigInDb = await db[dbDrilldownTableConfig].get({ id: 'default' })
}
const currentTableConfig = defaultDrillDownTableConfigs.find(config => config.route === tableType)
return version
}
export async function combinDrilldownTableWithUserConfig () {
const defaultCongfigInDb = await db[dbDrilldownTableConfig].get({ id: 'default' })
const defaultConfigs = defaultCongfigInDb ? defaultCongfigInDb.config : []
const curUserConfig = await readDrilldownTableConfigByUser()
if (defaultConfigs && curUserConfig && curUserConfig.length > 0) {
defaultConfigs.forEach(defaultConfig => {
const currentTableConfig = curUserConfig.find(config => config.route === defaultConfig.route)
if (currentTableConfig) {
const tableConfig = defaultConfig.tables.find(table => table.id === defaultConfig.route)
const newTableConfig = currentTableConfig.tables.find(table => table.id === defaultConfig.route)
tableConfig.hiddenColumns = newTableConfig.hiddenColumns
tableConfig.tabs.forEach(tab => {
const newTab = newTableConfig.tabs.find(newTab => newTab.name === tab.name)
if (newTab) {
tab.hiddenDrilldownTabs = newTab.hiddenDrilldownTabs
tab.checked = newTab.checked
}
})
}
})
}
return defaultConfigs
}
export async function getUserDrilldownTableConfig (tableType, curMetric) {
let list = []
// 获取用户定制的自定义配置,如果没有,则使用默认的自定义配置
const drillDownTableConfigs = await combinDrilldownTableWithUserConfig()
const currentTableConfig = drillDownTableConfigs.find(config => config.route === tableType)
const commonTabList = currentTableConfig ? currentTableConfig.tabs : []
const tables = currentTableConfig ? currentTableConfig.tables : []
if (tables && tables.length > 0) {
const curTableOldConfig = tables.find(table => table.id === tableType)
const curTable = curTableOldConfig || null
if (curTable) {
if (curTable.hasMetricSearch) { // 有metric
const metricsList = curTable ? curTable.metrics : []
if (metricsList && metricsList.length > 0) {
const metricTab = metricsList.find(metric => metric.name === curMetric)
list = metricTab ? metricTab.tabs : []
}
} else { // 无metric
list = curTable ? curTable.tabs : []
}
list = curTable ? curTable.tabs : []
combineTabList(tableType, list, commonTabList)
}
}

View File

@@ -162,6 +162,12 @@ export function valueToRangeValue (value, unitType) {
}
break
}
case unitTypes.qps: {
if (values[0] < 0.01) {
return ['<0.01', 'qps']
}
break
}
default: break
}
}

View File

@@ -150,14 +150,14 @@ export default {
if (panels && panels.length > 0) {
this.panel = panels[0]
}
console.log(this.panel)
// console.log(this.panel)
if (this.panel.id) {
if (this.panel.params) {
this.panel.params = JSON.parse(this.panel.params)
} else {
this.panel.params = {}
}
console.log(this.panel)
// console.log(this.panel)
const allCharts = (await getChartList({ panelId: this.panel.id, pageSize: -1 })).map(chart => {
chart.i = chart.id
this.recursionParamsConvert(chart)

View File

@@ -1,5 +1,5 @@
<template>
<div v-if="activeTab !== 709 && activeTab !== 710" class="panel-chart__no-data">No data</div>
<div v-if="activeTab !== 709 && activeTab !== 710" class="panel-chart__no-data">{{ $t('npm.noData') }}</div>
<div v-else class="panel-chart__no-data all-clear">
<div class="no-recent-alerts">
<i class="el-icon-circle-check"></i>

View File

@@ -474,10 +474,8 @@ export function stackedLineTooltipFormatter (params) {
str += '<div class="cn-chart-tooltip">'
params.forEach((item, i) => {
str += '<span class="cn-chart-tooltip-box">'
str += item.marker
str += `<span class="cn-chart-tooltip-content">
${item.seriesName}
</span>`
str += `<span style="display:inline-block;margin-right:4px;border-radius:10px;width:10px;height:10px;background-color:${item.borderColor};"></span>`
str += `<span class="cn-chart-tooltip-content">${item.seriesName.split('(')[0]}</span>`
str += '</span>'
})
str += '</div>'

View File

@@ -4,6 +4,7 @@
<network-overview-line
v-if="chart.type === typeMapping.networkOverview.line"
:chart="chart"
:metric="metric"
:time-filter="timeFilter"
ref="networkLine"
@toggleLoading="toggleLoading"
@@ -23,6 +24,7 @@
<network-overview-tabs
v-else-if="chart.type === typeMapping.networkOverview.table"
:time-filter="timeFilter"
:metric="metric"
:chart="chart"
:ref="`tab${chart.id}`"
@toggleLoading="toggleLoading"
@@ -38,6 +40,7 @@
<network-overview-apps
v-else-if="chart.type === typeMapping.networkOverview.appList"
:chart="chart"
:metric="metric"
:time-filter="timeFilter"
@toggleLoading="toggleLoading"
>
@@ -188,8 +191,7 @@ import DnsEventChart from '@/views/charts2/charts/dnsInsight/DnsEventChart'
import DnsRecentEvents from '@/views/charts2/charts/dnsInsight/DnsRecentEvents'
import DnsTrafficLine from '@/views/charts2/charts/dnsInsight/DnsTrafficLine'
import { get } from '@/utils/http'
import { getNowTime, getSecond } from '@/utils/date-util'
import { getNowTime } from '@/utils/date-util'
import { ref } from 'vue'
import LinkDirectionGrid from '@/views/charts2/charts/linkMonitor/LinkDirectionGrid'
export default {
@@ -224,6 +226,7 @@ export default {
},
props: {
chart: Object,
metric: String,
timeFilter: Object,
extraParams: Object
},

View File

@@ -7,8 +7,8 @@
:col-num="24"
:is-draggable="!panelLock"
:is-resizable="!panelLock"
:margin="[20, 20]"
:row-height="40"
:margin="[rowMargin, colMargin]"
:row-height="rowHeight"
:vertical-compact="true"
:use-css-transforms="false"
>
@@ -21,6 +21,7 @@
:key="item.i">
<chart
:time-filter="timeFilter"
:metric="metric"
:extra-params="extraParams"
:id="item.id"
ref="chartGrid"
@@ -36,7 +37,7 @@
import VueGridLayout from 'vue-grid-layout'
import _ from 'lodash'
import Chart from '@/views/charts2/Chart'
import { panelTypeAndRouteMapping, storageKey, drillDownPanelTypeMapping } from '@/utils/constants'
import { panelTypeAndRouteMapping, drillDownPanelTypeMapping } from '@/utils/constants'
import { typeMapping } from '@/views/charts2/chart-tools'
import { useRoute } from 'vue-router'
import { ref } from 'vue'
@@ -44,6 +45,7 @@ export default {
name: 'ChartList',
props: {
timeFilter: Object,
metric: String,
panelType: Number,
chartList: Array,
panelLock: Boolean,
@@ -54,7 +56,11 @@ export default {
return {
panelTypeAndRouteMapping,
typeMapping,
layout: []
layout: [],
rowHeight: 40,
rowMargin: 20,
colMargin: 20,
debounceFunc: null
}
},
components: {
@@ -73,14 +79,16 @@ export default {
watch: {
chartList (n) {
if (!_.isEmpty(n)) {
let layout = []
if (this.panelType === panelTypeAndRouteMapping.networkAppPerformance) {
this.layout = n.filter(c => c.type === typeMapping.npm.npmTabs || c.params.tabIndex === this.npmTabIndex)
layout = n.filter(c => c.type === typeMapping.npm.npmTabs || c.params.tabIndex === this.npmTabIndex)
} else if (Object.values(drillDownPanelTypeMapping).indexOf(this.panelType) >= -1) {
this.layout = n.filter(c => c.type === typeMapping.npm.npmTabs || c.params.tabIndex === this.npmTabIndex || !c.params.hasOwnProperty('tabIndex'))
layout = n.filter(c => c.type === typeMapping.npm.npmTabs || c.params.tabIndex === this.npmTabIndex || !c.params.hasOwnProperty('tabIndex'))
} else {
this.layout = [...n]
layout = [...n]
}
const overviewAppChart = n.find(c => c.type === typeMapping.networkOverview.appList)
/*const overviewAppChart = layout.find(c => c.type === typeMapping.networkOverview.appList)
let actuallyLength = 0
if (overviewAppChart) {
const params = overviewAppChart.params.app ? overviewAppChart.params : { app: [] }
@@ -90,6 +98,13 @@ export default {
actuallyLength = params.app.find(p => p.user === 'default').list.length + 1
}
overviewAppChart.h = actuallyLength % 3 > 0 ? (Math.floor(actuallyLength / 3) + 1) * 2 + 2 : Math.floor(actuallyLength / 3) * 2 + 2
}*/
this.layout = layout
const overviewAppChart = layout.find(c => c.type === typeMapping.networkOverview.appList)
if (overviewAppChart) {
this.$nextTick(() => {
this.resizeAppChart()
})
}
}
},
@@ -106,11 +121,27 @@ export default {
},
resizeLine () {
this.$refs.chartGrid.resizeLine()
},
resizeAppChart () {
const appCardsDom = document.querySelector('.app-cards')
const layout = _.cloneDeep(this.layout)
const overviewAppChart = layout.find(c => c.type === typeMapping.networkOverview.appList)
if (appCardsDom) {
const cardsHeight = appCardsDom.offsetHeight
if (cardsHeight) {
const headerHeight = 24
overviewAppChart.h = (cardsHeight + headerHeight + this.rowMargin) / (this.rowHeight + this.rowMargin)
this.layout = layout
}
}
}
},
mounted () {
this.debounceFunc = _.debounce(this.resizeAppChart, 400)
window.addEventListener('resize', this.debounceFunc)
},
beforeUnmount () {
window.removeEventListener('resize', this.debounceFunc)
}
}
</script>
<style scoped>
</style>

View File

@@ -3,31 +3,48 @@
<div class="panel__header">
<div class="panel__title">{{panelName?panelName:(panel.i18n ? $t(panel.i18n) : panel.name)}}
<div v-if="showScore" class="score">
<div class="circle-icon" v-if="score <= 2" :class="{'data-score-red': score <= 2}" ></div>
<div class="circle-icon" v-if="score <= 2 || score === '-'" :class="{'data-score-red': score <= 2 || score === '-'}" ></div>
<div class="circle-icon" v-else-if="score <= 4" :class="{'data-score-yellow': score <= 4}" ></div>
<div class="circle-icon" v-else-if="score <= 6" :class="{'data-score-green': score <= 6}" ></div>
Score:{{score}}
</div>
</div>
<div class="panel__time">
<date-time-range
class="date-time-range"
:start-time="timeFilter.startTime"
:end-time="timeFilter.endTime"
:date-range="timeFilter.dateRangeValue"
ref="dateTimeRange"
@change="reload"
/>
<time-refresh
class="date-time-range"
@change="timeRefreshChange"
:end-time="timeFilter.endTime"
/>
<div class="panel__tools">
<el-select
size="mini"
v-model="metric"
placeholder=""
popper-class="common-select"
v-if="panelType === panelTypeAndRouteMapping.networkOverview"
:popper-append-to-body="false"
@change="metricChange"
>
<template #prefix>
<span class="select-prefix">Metric:</span>
</template>
<el-option v-for="item in metricOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
<div class="panel__time">
<date-time-range
class="date-time-range"
:start-time="timeFilter.startTime"
:end-time="timeFilter.endTime"
:date-range="timeFilter.dateRangeValue"
ref="dateTimeRange"
@change="reload"
/>
<time-refresh
class="date-time-range"
@change="timeRefreshChange"
:end-time="timeFilter.endTime"
/>
</div>
</div>
</div>
<chart-list
ref="chartList"
:time-filter="timeFilter"
:metric="metric"
:chart-list="chartList"
:panel-type="panelType"
:panel-lock="panelLock"
@@ -42,18 +59,17 @@ import { useRoute } from 'vue-router'
import { ref } from 'vue'
import {
panelTypeAndRouteMapping,
bytesColumnNameGroupForNpm,
scoreUrl,
customTableTitlesForAppPerformance,
operationType,
curTabState,
drillDownPanelTypeMapping
drillDownPanelTypeMapping,
metricOptions,
fromRoute
} from '@/utils/constants'
import { getPanelList, getChartList } from '@/utils/api'
import { getPanelList, getChartList, api } from '@/utils/api'
import { getNowTime, getSecond } from '@/utils/date-util'
import { getTypeCategory } from '@/views/charts/charts/tools'
import { computeScore, urlParamsHandler, overwriteUrl } from '@/utils/tools'
import { urlParamsHandler, overwriteUrl, getDnsMapData, computeScore } from '@/utils/tools'
import ChartList from '@/views/charts2/ChartList'
import { useStore } from 'vuex'
import { get } from '@/utils/http'
export default {
@@ -67,31 +83,57 @@ export default {
},
data () {
return {
panelTypeAndRouteMapping,
metricOptions,
chartList: [], // 普通panel的chart
panelLock: true,
extraParams: {},
panelName: '',
dnsRcodeMapData: [],
dnsQtypeMapData: [],
score: null,
curTabState: curTabState
}
},
computed: {
npmThirdLevelMenuScore () {
return this.$store.getters.getNpmThirdLevelMenuScore
}
// npmThirdLevelMenuScore () {
// return this.$store.getters.getNpmThirdLevelMenuScore
// }
},
watch: {
npmThirdLevelMenuScore: {
deep: true,
immediate: true,
handler (n) {
this.score = n
// npmThirdLevelMenuScore: {
// deep: true,
// immediate: true,
// handler (n) {
// this.score = n
// }
// }
timeFilter: {
handler () {
if (this.$route.path === '/panel/networkAppPerformance' && (this.queryCondition || this.networkOverviewBeforeTab)) {
this.scoreCalculation()
}
}
}
},
async mounted () {
// this.panelName = this.$store.getters.getPanelName
this.panelName = this.$route.query.panelName ? this.$t(this.$route.query.panelName) : ''
const pName = this.$route.query.panelName ? this.$t(this.$route.query.panelName) : ''
const curTabProp = this.$route.query.dimensionType ? this.$route.query.dimensionType : null
if (this.$route.params.typeName === fromRoute.dnsServiceInsights) {
this.dnsQtypeMapData = await getDnsMapData('dnsQtype')
this.dnsRcodeMapData = await getDnsMapData('dnsRcode')
this.$store.commit('setDnsQtypeMapData', this.dnsQtypeMapData)
this.$store.commit('setDnsRcodeMapData', this.dnsRcodeMapData)
}
if (curTabProp === 'qtype') {
this.panelName = this.dnsQtypeMapData.get(pName)
} else if (curTabProp === 'rcode') {
this.panelName = this.dnsRcodeMapData.get(pName)
} else {
this.panelName = pName
}
// const curOperationType = this.$store.getters.getTabOperationType
/* const curOperationType = this.getUrlParam(this.curTabState.tabOperationType, '', true)
if (this.panelName && this.$route.path === '/panel/networkAppPerformance' && curOperationType !== operationType.thirdMenu) {
@@ -154,11 +196,39 @@ export default {
return chart
})
})
if (this.$route.path === '/panel/networkAppPerformance' && (this.queryCondition || this.networkOverviewBeforeTab)) {
this.scoreCalculation()
}
},
setup (props, ctx) {
setup (props) {
// todo 目前在panel页面测试后续会挪到router里
const store = useStore()
const cancelList = store.state.panel.httpCancel
// 进入页面时,发现有未结束的请求,终止请求
if (cancelList.length > 0) {
cancelList.forEach((cancel, index) => {
cancel()
delete cancelList[index]
})
}
const panel = ref({})
let panelType = 1 // 取得panel的type
const { params, query } = useRoute()
let { params, query, path } = useRoute()
// 获取路由跳转过的历史状态,赋值给当前界面,起到保留状态的作用,如浏览器的回退前进等
const routerObj = store.getters.getRouterHistoryList.find(item => item.t === query.t)
if (routerObj) {
params = routerObj.params
query = routerObj.query
path = routerObj.path
// 如果当前界面之前载入过,获取状态后更新地址栏,以便后续的赋值操作
const newUrl = urlParamsHandler(window.location.href, useRoute().query, query)
overwriteUrl(newUrl)
}
const thirdPanel = query.thirdPanel
const fourthPanel = query.fourthPanel
if (fourthPanel) {
@@ -177,6 +247,7 @@ export default {
const startTimeParam = query.startTime
const endTimeParam = query.endTime
// 若url携带了使用携带的值否则使用默认值。
const dateRangeValue = rangeParam ? parseInt(query.range) : (isEntityDetail(panelType) ? 60 * 24 : 60)
const timeFilter = ref({ dateRangeValue })
if (!startTimeParam || !endTimeParam) {
@@ -191,11 +262,25 @@ export default {
// npm是否展示分数
const showScorePanel = [drillDownPanelTypeMapping.npmOverviewIp, drillDownPanelTypeMapping.npmOverviewDomain, drillDownPanelTypeMapping.npmOverviewApp, drillDownPanelTypeMapping.npmOverviewCommon, drillDownPanelTypeMapping.npmThirdMenu]
const showScore = showScorePanel.indexOf(panelType) > -1
const metric = ref(query.metric || 'Bits/s')
const queryCondition = ref(query.queryCondition || '')
const dimensionType = ref(query.dimensionType || '')
// 三级菜单判断
const tabOperationType = ref(query.tabOperationType)
const networkOverviewBeforeTab = ref(query.networkOverviewBeforeTab || '')
return {
panelType,
panel,
timeFilter,
showScore
showScore,
metric,
path,
queryCondition,
dimensionType,
tabOperationType,
networkOverviewBeforeTab
}
},
methods: {
@@ -233,6 +318,9 @@ export default {
reload (startTime, endTime, dateRangeValue) {
this.timeFilter = { startTime: getSecond(startTime), endTime: getSecond(endTime), dateRangeValue: dateRangeValue }
const { query } = this.$route
this.$store.commit('setTimeRangeArray', [this.timeFilter.startTime, this.timeFilter.endTime])
this.$store.commit('setTimeRangeFlag', dateRangeValue.value)
const newUrl = urlParamsHandler(window.location.href, query, {
startTime: this.timeFilter.startTime,
endTime: this.timeFilter.endTime,
@@ -255,7 +343,95 @@ export default {
} else {
return this.$route.query[param] ? this.$route.query[param] : defaultValue
}
},
metricChange (value) {
const { query } = this.$route
const newUrl = urlParamsHandler(window.location.href, query, {
metric: value
})
overwriteUrl(newUrl)
},
scoreCalculation () {
let condition = ''
let url = ''
if (this.queryCondition.indexOf(' OR ') > -1) {
condition = this.queryCondition.split(/["|'](.*?)["|']/)
} else {
condition = this.queryCondition
}
const type = this.dimensionType || this.networkOverviewBeforeTab
const params = {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
cycle: 0
}
if (condition && (typeof condition !== 'object') && type) {
if (type === 'clientIp') {
params.q = `ip='${condition.split(/'(.*?)'/)[1]}' and side='client'`
} else if (type === 'serverIp') {
params.q = `ip='${condition.split(/'(.*?)'/)[1]}' and side='server'`
} else if (type === 'clientCity') {
params.q = `client_city='${condition.split(/'(.*?)'/)[1]}'`
} else if (type === 'serverCity') {
params.q = `server_city='${condition.split(/'(.*?)'/)[1]}'`
} else {
params.q = condition
}
params.type = type
} else if (condition.length > 1 && type && type === 'ip') {
params.q = `${type}='${condition[1]}'`
params.type = type
} else if (condition.length > 1 && type && type !== 'ip') {
if (type === 'country' || type === 'asn' || type === 'province' || type === 'city' || type === 'isp') {
params.q = `${type}='${condition[1]}'`
params.type = type
} else if (type === 'idcRenter') {
params.q = `idc_renter='${condition[1]}'`
params.type = type
} else {
params.q = `${condition[0]}'${condition[1]}'`
params.type = type
}
}
if (parseFloat(this.tabOperationType) === 3) {
url = api.npm.overview.allNetworkAnalysis
} else {
url = api.npm.overview.networkAnalysis
}
if ((type && condition) || type) {
params.type = params.type || type
get(url, params).then(res => {
if (res.code === 200) {
const data = {
establishLatencyMs: res.data.result.establishLatencyMsAvg || null,
httpResponseLatency: res.data.result.httpResponseLatencyAvg || null,
sslConLatency: res.data.result.sslConLatencyAvg || null,
tcpLostlenPercent: res.data.result.tcpLostlenPercentAvg || null,
pktRetransPercent: res.data.result.pktRetransPercentAvg || null
}
this.score = computeScore(data)
}
})
}
}
},
/**
* 页面销毁前,更新历史中已保存的状态
* 之所以会在下钻时、销毁前保存状态是因为panel第一次下钻时beforeUnmount获取不到下钻前参数
*/
beforeUnmount () {
const query = this.$_.cloneDeep(this.$route.query)
const routerObj = this.$store.getters.getRouterHistoryList.find(item => item.t === query.t)
// const routerObj = window.localRouterHistoryList.find(item => item.t === query.t)
if (routerObj !== undefined) {
if (Object.getOwnPropertyNames(query).length >= Object.getOwnPropertyNames(routerObj.query).length) {
routerObj.query = query
}
}
this.emitter.off('reloadChartList')
this.$store = null
this.emitter = null
}
}
</script>

View File

@@ -1,6 +1,7 @@
<template>
<div class="line network dns-traffic-line">
<div class="line-header">
<chart-error v-if="showError" :content="errorMsg" />
<div class="line-header" v-if="!showError">
<div class="line-header-left">
<div class="line-value-active" v-if="lineTab"></div>
<div class="line-value">
@@ -138,7 +139,9 @@ export default {
leftOffset: 0,
sizes: [3, 4, 6, 8, 9, 10],
dynamicVariable: '',
showMarkLine: true
showMarkLine: true,
showError: false,
errorMsg: ''
}
},
watch: {
@@ -167,7 +170,7 @@ export default {
overwriteUrl(newUrl)
},
timeFilter: {
handler (n) {
handler () {
if (this.lineTab) {
this.init(this.lineMetric, this.showMarkLine, 'active')
} else {
@@ -189,10 +192,23 @@ export default {
params.q = this.queryCondition
}
this.toggleLoading(true)
get(api.dnsInsight.totalTrafficAnalysis, params).then((res) => {
let url = api.dnsInsight.totalTrafficAnalysis
if (this.queryCondition) {
url = api.dnsInsight.drilldownTrafficAnalysis
}
get(url, params).then((res) => {
if (res.code === 200) {
this.showError = false
this.isNoData = res.data.result.length === 0
res.data.result.forEach((t, i) => {
if (this.isNoData) {
this.lineTab = ''
this.mpackets = [
{ analysis: {}, name: 'network.total', class: 'total', show: true, invertTab: true, positioning: 0, data: [], unitType: '' },
{ analysis: {}, name: 'network.inbound', class: 'inbound', show: true, invertTab: true, positioning: 1, data: [], unitType: '' },
{ analysis: {}, name: 'network.outbound', class: 'outbound', show: true, invertTab: true, positioning: 2, data: [], unitType: '' }
]
}
res.data.result.forEach((t) => {
if (t.type === 'bytes' && val === 'Bits/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalBitsRate.analysis
@@ -201,10 +217,12 @@ export default {
mpackets[0].data = t.totalBitsRate.values ? t.totalBitsRate.values : []
mpackets[1].data = t.inboundBitsRate.values ? t.inboundBitsRate.values : []
mpackets[2].data = t.outboundBitsRate.values ? t.outboundBitsRate.values : []
let num = 0
mpackets.forEach(e => {
e.unitType = 'bps'
if (e.name !== 'network.total' && e.analysis.avg == 0) {
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) === 0) {
e.show = false
num += 1
} else {
e.show = true
if (!active && show !== this.lineRefer) {
@@ -212,16 +230,27 @@ export default {
}
}
if (this.lineTab === e.class) {
if (e.analysis.avg < 0) {
if (parseFloat(e.analysis.avg) <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
}
}
})
this.mpackets = mpackets
this.$nextTick(() => {
this.echartsInit(this.mpackets, show)
})
if (num === 3) {
mpackets[0].invertTab = false
this.lineTab = 'total'
this.legendSelectChange(mpackets[0], 0)
this.$nextTick(() => {
this.echartsInit(this.mpackets)
})
} else {
this.$nextTick(() => {
this.echartsInit(this.mpackets, show)
if (!this.lineRefer) this.lineRefer = 'Average'
})
}
} else if (t.type === 'queries' && val === 'Queries/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalQueryRate.analysis
@@ -231,20 +260,26 @@ export default {
e.show = false
}
e.unitType = 'queries/s'
if (show !== this.lineRefer) {
this.legendSelectChange(e, 0)
}
e.invertTab = false
this.lineTab = 'total'
this.legendSelectChange(e, 0)
})
this.mpackets = mpackets
this.$nextTick(() => {
this.echartsInit(this.mpackets, show)
this.echartsInit(this.mpackets, true)
})
}
})
} else {
this.isNoData = false
this.showError = true
this.errorMsg = res.message
}
}).catch(e => {
console.error(e)
this.isNoData = true
this.isNoData = false
this.showError = true
this.errorMsg = e.message
}).finally(() => {
this.toggleLoading(false)
})
@@ -270,7 +305,7 @@ export default {
width: 1
},
stack: t.name !== 'network.total' ? 'network.total' : '',
symbolSize: function (value, params) {
symbolSize: function (value) {
return _this.symbolSizeSortChange(i, value[0])
},
itemStyle: {
@@ -314,7 +349,7 @@ export default {
}
})
if (!show) {
this.chartOption.series.forEach((t, i) => {
this.chartOption.series.forEach((t) => {
t.markLine.label.show = false
t.markLine = []
})
@@ -346,20 +381,26 @@ export default {
this.chartOption.tooltip.formatter = (params) => {
params.forEach(t => {
t.seriesName = this.$t(t.seriesName)
this.mpackets.forEach(e => {
if (this.$t(e.name) === t.seriesName) {
t.borderColor = chartColor3[e.positioning]
}
})
})
const str = stackedLineTooltipFormatter(params)
return str
return stackedLineTooltipFormatter(params)
}
this.showMarkLine = true
this.myChart.setOption(this.chartOption)
},
activeChange (item, index) {
if (this.isNoData) return
this.lineTab = item.class
this.legendSelectChange(item, index, 'active')
this.showMarkLine = !item.invertTab
this.init(this.lineMetric, this.showMarkLine, 'active')
},
mouseenter (item) {
if (this.isNoData) return
this.mousemoveCursor = item.class
this.handleActiveBar(item.class)
},
@@ -409,7 +450,7 @@ export default {
})
}
},
handleActiveBar (value) {
handleActiveBar () {
if (document.querySelector('.network .line-value-mpackets.is-active')) {
const { offsetLeft, clientWidth, clientLeft } = document.querySelector('.network .line-value-mpackets.is-active')
const activeBar = document.querySelector('.network .line-value-active')
@@ -424,7 +465,7 @@ export default {
this.lineTab = ''
this.handleActiveBar()
this.showMarkLine = !this.showMarkLine
this.mpackets.forEach((e, i) => {
this.mpackets.forEach((e) => {
if (!e.invertTab) {
e.invertTab = true
}

View File

@@ -1,13 +1,15 @@
<template>
<div class="link-blocks">
<div class="block-list" style="position: relative">
<div class="block-list__title">{{ $t('linkMonitor.links') }}</div>
<div class="block-list__title" v-if="!showError">{{ $t('linkMonitor.links') }}</div>
<!--无数据noData-->
<chart-no-data v-if="isNoData"></chart-no-data>
<div class="block-list__list" v-show="!isNoData">
<chart-error v-if="showError" :content="errorMsg1" />
<el-popover
v-else
placement="bottom"
trigger="hover"
popper-class="link-block__popper"
@@ -54,13 +56,15 @@
</div>
</div>
<div class="block-list" style="position: relative">
<div class="block-list__title">{{ $t('linkMonitor.nextHopInternet') }}</div>
<div class="block-list" >
<div class="block-list__title" v-if="!showError">{{ $t('linkMonitor.nextHopInternet') }}</div>
<chart-no-data v-if="isNoData"></chart-no-data>
<div class="block-list__list" v-show="!isNoData">
<chart-error v-if="showError" :content="errorMsg2" />
<el-popover
v-else
placement="bottom"
trigger="hover"
popper-class="link-block__popper"
@@ -120,11 +124,13 @@ import { colorGradientCalculation } from '@/utils/tools'
import unitConvert from '@/utils/unit-convert'
import { drillDownPanelTypeMapping, storageKey, unitTypes } from '@/utils/constants'
import { getSecond } from '@/utils/date-util'
import ChartError from '@/components/common/Error'
export default {
name: 'LinkBlock',
mixins: [chartMixin],
components: {
ChartError,
ChartNoData
},
data () {
@@ -133,7 +139,10 @@ export default {
unitTypes,
linkData: [],
nextHopData: [],
gradientColor: ['#FF005C', '#40537E'] // [start, end]
gradientColor: ['#FF005C', '#40537E'], // [start, end]
showError: false,
errorMsg1: '',
errorMsg2: ''
}
},
setup () {
@@ -145,7 +154,7 @@ export default {
},
watch: {
timeFilter: {
handler (n) {
handler () {
this.init()
}
}
@@ -158,7 +167,8 @@ export default {
init () {
this.toggleLoading(true)
// 链路基本信息
let linkInfo = localStorage.getItem(storageKey.linkInfo)
let linkInfo = null
linkInfo = localStorage.getItem(storageKey.linkInfo)
linkInfo = JSON.parse(linkInfo)
const params = {
startTime: getSecond(this.timeFilter.startTime),
@@ -170,6 +180,8 @@ export default {
Promise.all([dataRequest, nextHopRequest]).then(res => {
if (res[0].code === 200 && res[1].code === 200) {
this.showError = false
const linkData = res[0].data.result
const nextHopData = res[1].data.result
@@ -223,7 +235,6 @@ export default {
})
this.linkData = sorted
// todo 此处去重不优美,后续再处理
let directionArr = []
nextHopData.forEach((item) => {
if (item.egressLinkDirection !== '' && item.ingressLinkDirection !== '') {
@@ -231,7 +242,7 @@ export default {
directionArr.push(item.ingressLinkDirection)
}
})
directionArr = [...new Set(directionArr)]
directionArr = Array.from(new Set(directionArr))
const newNextHopData = []
@@ -275,11 +286,18 @@ export default {
this.nextHopData = nextHopSorted
} else {
this.isNoData = true
this.isNoData = false
this.showError = true
this.errorMsg1 = res[0].message
this.errorMsg2 = res[1].message
}
}).catch(e => {
console.error(e)
this.isNoData = true
this.isNoData = false
this.showError = true
// todo 此处数据还待验证
this.errorMsg1 = e.message
this.errorMsg2 = e.message
}).finally(() => {
this.toggleLoading(false)
})
@@ -366,6 +384,9 @@ export default {
return newValue
}
},
beforeUnmount () {
this.unitConvert = null
}
}
</script>

View File

@@ -1,10 +1,10 @@
<template>
<div class="link-direction-grid">
<!--左侧链路出入口-->
<popover-content :isNoData="isNoData" :gridData="gridData" style="width: 900px;"/>
<popover-content :isNoData="isLinkNoData" :gridData="linkGridData" :showError="isLinkShowError" :content="linkErrorMsg" style="width: 900px;"/>
<!--右侧链路下一跳-->
<popover-content :isNoData="isNoData" :gridData="gridData2"/>
<popover-content :isNoData="isNextNoData" :gridData="nextGridData" :showError="isNextShowError" :content="nextErrorMsg" />
</div>
</template>
@@ -22,9 +22,14 @@ export default {
mixins: [chartMixin],
data () {
return {
gridData: [],
gridData2: [],
isNoData: false
linkGridData: [],
nextGridData: [],
isLinkNoData: false,
isNextNoData: false,
isLinkShowError: false, // 显示左侧链路报错标识
linkErrorMsg: '', // 左侧链路的报错信息
isNextShowError: false, // 显示右侧下一跳报错标识
nextErrorMsg: '' // 右侧下一跳的报错信息
}
},
components: {
@@ -32,7 +37,7 @@ export default {
},
watch: {
timeFilter: {
handler (n) {
handler () {
this.init()
}
}
@@ -45,7 +50,6 @@ export default {
// 链路基本信息
let linkInfo = localStorage.getItem(storageKey.linkInfo)
linkInfo = JSON.parse(linkInfo)
// console.log('LinkDirectionGrid.vue---init--获取链路基本信息缓存', linkInfo)
const params = {
startTime: getSecond(this.timeFilter.startTime),
@@ -57,7 +61,8 @@ export default {
this.toggleLoading(true)
Promise.all([dataRequest, nextHopRequest]).then(res => {
if (res[0].code === 200 && res[1].code === 200) {
if (res[0].code === 200) {
this.isLinkShowError = false
// 链路流量数据
const linkData = res[0].data.result
// 接口数据乱序根据入链路idingressLinkId大小排序之后
@@ -69,6 +74,70 @@ export default {
return a.egressLinkId - b.egressLinkId
})
this.isLinkNoData = linkData.length === 0
if (!this.isLinkNoData) {
// 链路流量数据
const linkGridData = []
linkData.forEach(d => {
const ingressLink = linkInfo.find(l => l.originalLinkId === d.ingressLinkId)
const egressLink = linkInfo.find(l => l.originalLinkId === d.egressLinkId)
if (ingressLink && egressLink) {
const data = linkGridData.find(g => g.linkId === ingressLink.linkId)
// 上行使用情况计算
const egressUsage = this.computeUsage(d.egressBitsRate, egressLink.bandwidth)
// 下行使用情况计算
const ingressUsage = this.computeUsage(d.ingressBitsRate, ingressLink.bandwidth)
// 宽带使用超过90%,赋红点
d.usageMore90 = egressUsage >= 0.9 || ingressUsage >= 0.9
// 计算npm分数
// 分数低于3分赋红点
d.score = this.localComputeScore(d)
d.scoreLow3 = d.score < 3
if (data) {
const existedEgressLink = data.egress.find(e => e.linkId === egressLink.linkId)
if (!existedEgressLink) {
data.egress.push({
linkId: egressLink.linkId,
egressUsage: egressUsage,
ingressUsage: ingressUsage,
popoverWidth: this.computeWidth(egressUsage, ingressUsage, 'popover'),
valueWidth: this.computeWidth(egressUsage, ingressUsage, 'value'),
totalBitsRate: d.totalBitsRate,
...d
})
}
} else {
linkGridData.push({
linkId: ingressLink.linkId,
egress: [{
linkId: egressLink.linkId,
egressUsage: egressUsage,
ingressUsage: ingressUsage,
popoverWidth: this.computeWidth(egressUsage, ingressUsage, 'popover'),
valueWidth: this.computeWidth(egressUsage, ingressUsage, 'value'),
totalBitsRate: d.totalBitsRate,
...d
}]
})
}
}
})
this.linkGridData = linkGridData
}
} else {
this.isLinkNoData = false
this.isLinkShowError = true
this.linkErrorMsg = res[0].message
}
if (res[1].code === 200) {
this.isNextShowError = false
// 链路下一跳信息
const nextLinkData = res[1].data.result
// 接口数据乱序,根据出方向排序,再根据同个出方向下的入进行排序
@@ -79,145 +148,92 @@ export default {
return a.egressLinkDirection.localeCompare(b.egressLinkDirection)
})
this.isNoData = linkData.length === 0 && nextLinkData.length === 0
if (this.isNoData) {
return
}
this.isNextNoData = nextLinkData.length === 0
if (!this.isNextNoData) {
// 链路下一跳数据
const nextGridData = []
// 链路流量数据
const gridData = []
// 链路下一跳数据
const gridData2 = []
linkData.forEach(d => {
const ingressLink = linkInfo.find(l => l.originalLinkId === d.ingressLinkId)
const egressLink = linkInfo.find(l => l.originalLinkId === d.egressLinkId)
if (ingressLink && egressLink) {
const data = gridData.find(g => g.linkId === ingressLink.linkId)
nextLinkData.forEach(d => {
const ingressLink = linkInfo.find(l => l.nextHop === d.ingressLinkDirection && l.direction === 'ingress')
const egressLink = linkInfo.find(l => l.nextHop === d.egressLinkDirection && l.direction === 'egress')
// 上行使用情况计算
const egressUsage = this.computeUsage(d.egressBitsRate, egressLink.bandwidth)
// 下行使用情况计算
const ingressUsage = this.computeUsage(d.ingressBitsRate, ingressLink.bandwidth)
// 宽带使用超过90%,赋红点
d.usageMore90 = false
if (egressUsage >= 0.9 || ingressUsage >= 0.9) {
d.usageMore90 = true
}
// 计算npm分数
// 分数低于3分赋红点
d.score = this.localComputeScore(d)
d.scoreLow3 = false
if (d.score < 3) {
d.scoreLow3 = true
}
if (ingressLink && egressLink) {
const data = nextGridData.find(g => g.linkId === ingressLink.linkId)
if (data) {
const existedEgressLink = data.egress.find(e => e.linkId === egressLink.linkId)
if (!existedEgressLink) {
data.egress.push({
linkId: egressLink.linkId,
egressUsage: egressUsage,
ingressUsage: ingressUsage,
popoverWidth: this.computeWidth(egressUsage, ingressUsage, 'popover'),
valueWidth: this.computeWidth(egressUsage, ingressUsage, 'value'),
totalBitsRate: d.totalBitsRate,
...d
})
}
} else {
gridData.push({
linkId: ingressLink.linkId,
egress: [{
linkId: egressLink.linkId,
egressUsage: egressUsage,
ingressUsage: ingressUsage,
popoverWidth: this.computeWidth(egressUsage, ingressUsage, 'popover'),
valueWidth: this.computeWidth(egressUsage, ingressUsage, 'value'),
totalBitsRate: d.totalBitsRate,
...d
}]
let egressBanwidth = 0
let ingressBanwidth = 0
linkInfo.forEach((item) => {
if (item.nextHop === d.egressLinkDirection && item.direction === 'egress') {
egressBanwidth += item.bandwidth
}
if (item.nextHop === d.ingressLinkDirection && item.direction === 'ingress') {
ingressBanwidth += item.bandwidth
}
})
}
}
})
this.gridData = gridData
// 上行使用情况计算
const egressUsage = this.computeUsage(d.egressBitsRate, egressBanwidth)
// 下行使用情况计算
const ingressUsage = this.computeUsage(d.ingressBitsRate, ingressBanwidth)
// 宽带使用超过90%,赋红点
nextLinkData.forEach(d => {
const ingressLink = linkInfo.find(l => l.nextHop === d.ingressLinkDirection && l.direction === 'ingress')
const egressLink = linkInfo.find(l => l.nextHop === d.egressLinkDirection && l.direction === 'egress')
d.usageMore90 = egressUsage >= 0.9 || ingressUsage >= 0.9
// 计算npm分数
// 分数低于3分赋红点
d.score = this.localComputeScore(d)
if (ingressLink && egressLink) {
const data = gridData2.find(g => g.linkId === ingressLink.linkId)
d.scoreLow3 = d.score < 3
let egressBanwidth = 0
let ingressBanwidth = 0
linkInfo.forEach((item) => {
if (item.nextHop === d.egressLinkDirection && item.direction === 'egress') {
egressBanwidth += item.bandwidth
}
if (item.nextHop === d.ingressLinkDirection && item.direction === 'ingress') {
ingressBanwidth += item.bandwidth
}
})
// 上行使用情况计算
const egressUsage = this.computeUsage(d.egressBitsRate, egressBanwidth)
// 下行使用情况计算
const ingressUsage = this.computeUsage(d.ingressBitsRate, ingressBanwidth)
// 宽带使用超过90%,赋红点
d.usageMore90 = false
if (egressUsage >= 0.9 || ingressUsage >= 0.9) {
d.usageMore90 = true
}
// 计算npm分数
// 分数低于3分赋红点
d.score = this.localComputeScore(d)
d.scoreLow3 = false
if (d.score < 3) {
d.scoreLow3 = true
}
if (data) {
const existedEgressLink = data.egress.find(e => e.linkId === egressLink.linkId)
if (!existedEgressLink) {
data.egress.push({
linkId: egressLink.linkId,
nextHop: egressLink.nextHop,
egressUsage: egressUsage,
ingressUsage: ingressUsage,
popoverWidth: this.computeWidth(egressUsage, ingressUsage, 'popover'),
valueWidth: this.computeWidth(egressUsage, ingressUsage, 'value'),
totalBitsRate: d.totalBitsRate,
...d
})
}
} else {
gridData2.push({
linkId: ingressLink.linkId,
nextHop: ingressLink.nextHop,
egress: [{
linkId: egressLink.linkId,
if (data) {
const existedEgressLink = data.egress.find(e => e.linkId === egressLink.linkId)
if (!existedEgressLink) {
data.egress.push({
linkId: egressLink.linkId,
nextHop: egressLink.nextHop,
egressUsage: egressUsage,
ingressUsage: ingressUsage,
popoverWidth: this.computeWidth(egressUsage, ingressUsage, 'popover'),
valueWidth: this.computeWidth(egressUsage, ingressUsage, 'value'),
totalBitsRate: d.totalBitsRate,
...d
})
}
} else {
nextGridData.push({
linkId: ingressLink.linkId,
nextHop: ingressLink.nextHop,
egressUsage: egressUsage,
ingressUsage: ingressUsage,
popoverWidth: this.computeWidth(egressUsage, ingressUsage, 'popover'),
valueWidth: this.computeWidth(egressUsage, ingressUsage, 'value'),
totalBitsRate: d.totalBitsRate,
...d
}]
})
egress: [{
linkId: egressLink.linkId,
nextHop: ingressLink.nextHop,
egressUsage: egressUsage,
ingressUsage: ingressUsage,
popoverWidth: this.computeWidth(egressUsage, ingressUsage, 'popover'),
valueWidth: this.computeWidth(egressUsage, ingressUsage, 'value'),
totalBitsRate: d.totalBitsRate,
...d
}]
})
}
}
}
})
})
this.gridData2 = gridData2
this.nextGridData = nextGridData
}
} else {
this.isNoData = true
this.isNextNoData = false
this.isNextShowError = true
// todo 此时返回的是msg后期记得改为message
this.nextErrorMsg = res[1].msg
}
}).catch(e => {
console.error(e)
this.isNoData = true
this.isLinkShowError = true
// todo 此时返回的是msg后期记得改为message
this.linkErrorMsg = e[0].msg
this.isNextShowError = true
this.nextErrorMsg = e[1].msg
}).finally(() => {
this.toggleLoading(false)
})
@@ -235,18 +251,17 @@ export default {
/**
* 本地计算npm分数
*/
localComputeScore (data, bandwidth) {
const keyPre = ['tcp', 'http', 'ssl', 'tcpLost', 'packetRetrans']
localComputeScore (data) {
let score = 0
keyPre.forEach((item, index) => {
score = computeScore(data, index)
data[keyPre[index] + 'Score'] = score
})
let npmScore = Math.ceil((data.tcpScore + data.httpScore + data.sslScore + data.tcpLostScore + data.packetRetransScore) * 6)
if (npmScore > 6) {
npmScore = 6
const dataScore = {
establishLatencyMs: data.establishLatencyMs || null,
httpResponseLatency: data.httpResponseLatency || null,
sslConLatency: data.sslConLatency || null,
tcpLostlenPercent: data.tcpLostlenPercent || null,
pktRetransPercent: data.pktRetransPercent || null
}
return npmScore
score = computeScore(dataScore)
return score
},
/**
* 计算popover弹窗和右侧数据模块的宽度

View File

@@ -5,7 +5,9 @@
<chart-no-data v-if="isNoData"></chart-no-data>
<div class="data-grid" v-show="!isNoData">
<chart-error class="link-block-error" v-if="showError" :content="content"/>
<div class="data-grid" v-show="!isNoData && !showError">
<div class="egress-row">
<div class="egress-id" v-for="(item, index) in gridData" :key="index">
<!--兼容下一跳情况-->
@@ -73,7 +75,7 @@
<div class="block-content-item-name">{{ $t('linkMonitor.linkBlock.total') }}</div>
<div class="block-content-item-value" :style="{width: row.egress[index2].valueWidth + 'px'}">
{{unitConvert(row.egress[index2].totalBitsRate, unitTypes.bps).join('')}}
{{ unitConvert(row.egress[index2].totalBitsRate, unitTypes.bps).join('') }}
</div>
</div>
</div>
@@ -146,13 +148,18 @@
import unitConvert from '@/utils/unit-convert'
import { unitTypes } from '@/utils/constants'
import ChartNoData from '@/views/charts/charts/ChartNoData'
import ChartError from '@/components/common/Error'
export default {
name: 'PopoverContent',
props: {
gridData: Array,
isNoData: Boolean
isNoData: Boolean,
showError: Boolean,
content: String
},
components: {
ChartError,
ChartNoData
},
data () {

View File

@@ -7,7 +7,8 @@
</link-traffic-drill-down-list>
<div class="line network link-traffic">
<loading :loading="loading"></loading>
<div class="line-header">
<chart-error v-if="showError" :content="errorMsg" />
<div class="line-header" v-if="!showError">
<div class="line-header-left">
<div class="line-value-active" v-if="lineTab"></div>
<div class="line-value">
@@ -59,22 +60,21 @@
<script>
import chartMixin from '@/views/charts2/chart-mixin'
import linkTrafficDrillDownLine from '@/views/charts2/charts/linkMonitor/localComponents/LinkTrafficDrillDownLine'
import LinkTrafficDrillDownList from '@/views/charts2/charts/linkMonitor/localComponents/LinkTrafficDrillDownList'
import ChartNoData from '@/views/charts/charts/ChartNoData'
import Loading from '@/components/common/Loading'
import {useRoute} from 'vue-router'
import {ref, shallowRef} from 'vue'
import { useRoute } from 'vue-router'
import { ref, shallowRef } from 'vue'
import unitConvert from '@/utils/unit-convert'
import {chartColor3, chartColor4, unitTypes} from '@/utils/constants'
import {overwriteUrl, urlParamsHandler} from '@/utils/tools'
import {getSecond} from '@/utils/date-util'
import {get} from '@/utils/http'
import {api} from '@/utils/api'
import { chartColor3, chartColor4, unitTypes } from '@/utils/constants'
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
import { getSecond } from '@/utils/date-util'
import { get } from '@/utils/http'
import { api } from '@/utils/api'
import _ from 'lodash'
import * as echarts from 'echarts'
import {linkTrafficLineChartOption} from '@/views/charts2/charts/options/echartOption'
import {stackedLineTooltipFormatter} from '@/views/charts/charts/tools'
import { linkTrafficLineChartOption } from '@/views/charts2/charts/options/echartOption'
import { stackedLineTooltipFormatter } from '@/views/charts/charts/tools'
export default {
name: 'LinkTrafficLine',
@@ -126,7 +126,9 @@ export default {
sizes: [3, 4, 6, 8, 9, 10],
dynamicVariable: '',
showMarkLine: true,
loading: false
loading: false,
showError: false,
errorMsg: ''
}
},
watch: {
@@ -148,7 +150,7 @@ export default {
overwriteUrl(newUrl)
},
timeFilter: {
handler (n) {
handler () {
if (this.lineTab) {
this.init(this.lineMetric, this.showMarkLine, 'active')
} else {
@@ -176,8 +178,17 @@ export default {
this.loading = true
get(api.linkMonitor.totalTrafficAnalysis, params).then((res) => {
if (res.code === 200) {
this.showError = false
this.isNoData = res.data.result.length === 0
res.data.result.forEach((t, i) => {
if (this.isNoData) {
this.lineTab = ''
this.mpackets = [
{ analysis: {}, name: 'network.total', class: 'total', show: true, invertTab: true, positioning: 0, data: [], unitType: '' },
{ analysis: {}, name: 'linkMonitor.ingress', class: 'ingress', show: true, invertTab: true, positioning: 1, data: [], unitType: '' },
{ analysis: {}, name: 'linkMonitor.egress', class: 'egress', show: true, invertTab: true, positioning: 2, data: [], unitType: '' }
]
}
res.data.result.forEach((t) => {
if (t.type === 'bytes' && val === 'Bits/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalBitsRate.analysis
@@ -186,10 +197,12 @@ export default {
mpackets[0].data = t.totalBitsRate.values ? t.totalBitsRate.values : []
mpackets[1].data = t.ingressBitsRate.values ? t.ingressBitsRate.values : []
mpackets[2].data = t.egressBitsRate.values ? t.egressBitsRate.values : []
let num = 0
mpackets.forEach(e => {
e.unitType = 'bps'
if (e.name !== 'network.total' && e.analysis.avg == 0) {
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) === 0) {
e.show = false
num += 1
} else {
e.show = true
if (!active && !show) {
@@ -197,16 +210,27 @@ export default {
}
}
if (this.lineTab === e.class) {
if (e.analysis.avg < 1) {
if (parseFloat(e.analysis.avg) <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
}
}
})
this.mpackets = mpackets
this.$nextTick(() => {
this.echartsInit(this.mpackets)
})
if (num === 3) {
mpackets[0].invertTab = false
this.lineTab = 'total'
this.legendSelectChange(mpackets[0], 0)
this.$nextTick(() => {
this.echartsInit(this.mpackets)
})
} else {
this.$nextTick(() => {
this.echartsInit(this.mpackets)
if (!this.lineRefer) this.lineRefer = 'Average'
})
}
} else if (t.type === 'packets' && val === 'Packets/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalPacketsRate.analysis
@@ -215,10 +239,12 @@ export default {
mpackets[0].data = t.totalPacketsRate.values ? t.totalPacketsRate.values : []
mpackets[1].data = t.ingressPacketsRate.values ? t.ingressPacketsRate.values : []
mpackets[2].data = t.egressPacketsRate.values ? t.egressPacketsRate.values : []
let num = 0
mpackets.forEach(e => {
e.unitType = 'packets/s'
if (e.name !== 'network.total' && e.analysis.avg == 0) {
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) === 0) {
e.show = false
num += 1
} else {
e.show = true
if (!active && !show) {
@@ -226,22 +252,40 @@ export default {
}
}
if (this.lineTab === e.class) {
if (e.analysis.avg < 1) {
if (parseFloat(e.analysis.avg) <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
}
}
})
this.mpackets = mpackets
this.$nextTick(() => {
this.echartsInit(this.mpackets)
})
if (num === 3) {
mpackets[0].invertTab = false
this.lineTab = 'total'
this.legendSelectChange(mpackets[0], 0)
this.$nextTick(() => {
this.echartsInit(this.mpackets)
})
} else {
this.$nextTick(() => {
this.echartsInit(this.mpackets)
if (!this.lineRefer) this.lineRefer = 'Average'
})
}
}
})
} else {
this.showError = true
// todo 此时返回的是msg后期记得改
this.errorMsg = res.msg
// this.errorMsg = res.message
}
}).catch(e => {
console.error(e)
this.isNoData = true
this.showError = true
this.errorMsg = e.message
// this.isNoData = true
}).finally(() => {
this.loading = false
})
@@ -267,7 +311,7 @@ export default {
width: 1
},
stack: t.name !== 'network.total' ? 'network.total' : '',
symbolSize: function (value, params) {
symbolSize: function (value) {
return _this.symbolSizeSortChange(i, value[0])
},
itemStyle: {
@@ -291,26 +335,33 @@ export default {
}
])
},
data: t.data.map(v => [Number(v[0]) * 1000, Number(v[1]), 'number']),
data: t.data.map(v => [Number(v[0]) * 1000, Number(v[1]), 'number'])
}
})
this.chartOption.tooltip.formatter = (params) => {
params.forEach(t => {
t.seriesName = this.$t(t.seriesName)
this.mpackets.forEach(e => {
if (this.$t(e.name) === t.seriesName) {
t.borderColor = chartColor3[e.positioning]
}
})
})
const str = stackedLineTooltipFormatter(params)
return str
// const str = stackedLineTooltipFormatter(params)
return stackedLineTooltipFormatter(params)
}
this.showMarkLine = true
this.myChart.setOption(this.chartOption)
},
activeChange (item, index) {
if (this.isNoData) return
this.lineTab = item.class
this.legendSelectChange(item, index, 'active')
this.showMarkLine = !item.invertTab
this.init(this.lineMetric, this.showMarkLine, 'active')
},
mouseenter (item) {
if (this.isNoData) return
this.mousemoveCursor = item.class
this.handleActiveBar(item.class)
},
@@ -360,7 +411,7 @@ export default {
})
}
},
handleActiveBar (value) {
handleActiveBar () {
if (document.querySelector('.network .line-value-mpackets.is-active')) {
const { offsetLeft, clientWidth, clientLeft } = document.querySelector('.network .line-value-mpackets.is-active')
const activeBar = document.querySelector('.network .line-value-active')
@@ -375,7 +426,7 @@ export default {
this.lineTab = ''
this.handleActiveBar()
this.showMarkLine = !this.showMarkLine
this.mpackets.forEach((e, i) => {
this.mpackets.forEach((e) => {
if (!e.invertTab) {
e.invertTab = true
}

View File

@@ -2,21 +2,23 @@
<div class="link-traffic-sankey">
<el-tabs v-model="tab">
<el-tab-pane :label="$t('linkMonitor.ingress')" name="0">
<chart-error v-if="showError" :content="errorMsg"></chart-error>
<chart-no-data v-if="ingress"></chart-no-data>
<div v-if="tab == 0" class="chart-drawing" id="link-traffic-sankey-0"></div>
<div v-if="parseInt(tab) === 0 && !showError" class="chart-drawing" id="link-traffic-sankey-0"></div>
</el-tab-pane>
<el-tab-pane :label="$t('linkMonitor.egress')" name="1">
<chart-error v-if="showError" :content="errorMsg"></chart-error>
<chart-no-data v-if="egress"></chart-no-data>
<div v-if="tab == 1" class="chart-drawing" id="link-traffic-sankey-1"></div>
<div v-if="parseInt(tab) === 1 && !showError" class="chart-drawing" id="link-traffic-sankey-1"></div>
</el-tab-pane>
</el-tabs>
<template v-if="tab == 0 && !ingress">
<template v-if="parseInt(tab) === 0 && !ingress">
<div class="sankey__label" style="left: 5%;">External Locations</div>
<div class="sankey__label" style="left: 35%;">Next-Hop Internets</div>
<div class="sankey__label" style="left: 63%;">Links</div>
<div class="sankey__label" style="right: 9%; transform: translateX(50%)">Internal Locations</div>
</template>
<template v-else-if="tab == 1 && !egress">
<template v-else-if="parseInt(tab) === 1 && !egress">
<div class="sankey__label" style="left: 5%;">Internal Locations</div>
<div class="sankey__label" style="left: 33.2%;">Links</div>
<div class="sankey__label" style="left: 64.5%;">Next-Hop Internets</div>
@@ -38,11 +40,13 @@ import { useRoute } from 'vue-router'
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
import unitConvert from '@/utils/unit-convert'
import { storageKey, unitTypes } from '@/utils/constants'
import ChartError from '@/components/common/Error'
export default {
name: 'LinksTrafficSankey',
mixins: [chartMixin],
components: {
ChartError,
ChartNoData
},
setup () {
@@ -63,7 +67,9 @@ export default {
egress: false,
unitConvert,
unitTypes,
cnLinkInfo: JSON.parse(localStorage.getItem(storageKey.linkInfo))
cnLinkInfo: JSON.parse(localStorage.getItem(storageKey.linkInfo)),
showError: false,
errorMsg: ''
}
},
watch: {
@@ -78,13 +84,14 @@ export default {
overwriteUrl(newUrl)
},
timeFilter: {
handler (n) {
handler () {
this.linkTrafficSankeyDataRequest(this.tab)
}
}
},
methods: {
linkTrafficSankeyDataRequest (n) {
n = parseInt(n)
const params = {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime)
@@ -93,19 +100,19 @@ export default {
if (this.queryCondition) {
const condition = this.queryCondition.toLowerCase().split(' or ')
if (condition.length > 1) {
if (n == 0) {
if (n === 0) {
params.q = condition.find(c => c.indexOf('common_ingress_link_id') > -1 || c.indexOf('ingress_link_direction') > -1)
} else {
params.q = condition.find(c => c.indexOf('common_egress_link_id') > -1 || c.indexOf('egress_link_direction') > -1)
}
}
if (n == 0) {
if (n === 0) {
url = api.linkMonitor.drilldownQuadrupleIngressAnalysis // 入口
} else {
url = api.linkMonitor.drilldownQquadrupleEgressAnalysis // 出口
}
} else {
if (n == 0) {
if (n === 0) {
url = api.linkMonitor.quadrupleIngressAnalysis // 入口
} else {
url = api.linkMonitor.quadrupleEgressAnalysis // 出口
@@ -114,26 +121,32 @@ export default {
this.toggleLoading(true)
get(url, params).then(res => {
if (res.code === 200) {
if (n == 0) {
this.showError = false
if (n === 0) {
this.ingress = res.data.result.length === 0
} else {
this.egress = res.data.result.length === 0
}
this.dataProcessing(res.data.result, n)
this.dataProcessing(res.data.result, parseInt(n))
} else {
this.showError = true
this.errorMsg = res.message
}
}).catch(e => {
console.error(e)
this.egress = true
this.ingress = true
this.showError = true
this.errorMsg = e.message
}).finally(() => {
this.toggleLoading(false)
})
},
dataProcessing (result, tab) {
if (tab == 0) {
if (tab === 0) {
result.forEach(t => {
this.cnLinkInfo.forEach(e => {
if (t.commonIngressLinkId == e.originalLinkId) {
if (t.commonIngressLinkId === e.originalLinkId) {
t.linkId = e.linkId
t.linkDirection = e.nextHop
t.bandwidth = e.bandwidth
@@ -146,7 +159,7 @@ export default {
} else {
result.forEach(t => {
this.cnLinkInfo.forEach(e => {
if (t.commonEgressLinkId == e.originalLinkId) {
if (t.commonEgressLinkId === e.originalLinkId) {
t.linkId = e.linkId
t.bandwidth = e.bandwidth
t.linkDirection = e.nextHop
@@ -170,7 +183,7 @@ export default {
const links1 = []
const links2 = []
const linksAnalyze2 = []
if (tab == 1) {
if (tab === 1) {
result.forEach(r => {
// 第一列
if (!data0.some(d => d.name === r.client)) {
@@ -357,18 +370,16 @@ export default {
echartsInit (tab, data, links) {
const _this = this
let dom = ''
if (tab == 0) {
if (tab === 0) {
dom = document.getElementById('link-traffic-sankey-0')
if (this.myChart) {
this.myChart.dispose()
}
this.myChart = echarts.init(dom)
} else {
dom = document.getElementById('link-traffic-sankey-1')
if (this.myChart2) {
this.myChart2.dispose()
}
this.myChart2 = echarts.init(dom)
}
this.chartOption = this.$_.cloneDeep(linksTrafficSankeyOption)
this.chartOption.tooltip.formatter = function (param) {
@@ -400,14 +411,18 @@ export default {
}
this.chartOption.series[0].data = data
this.chartOption.series[0].links = links
if (tab == 0) {
this.myChart.setOption(this.chartOption)
} else {
this.myChart2.setOption(this.chartOption)
}
this.$nextTick(() => {
if (tab === 0) {
this.myChart = echarts.init(dom)
this.myChart.setOption(this.chartOption)
} else {
this.myChart2 = echarts.init(dom)
this.myChart2.setOption(this.chartOption)
}
})
},
resize () {
if (this.tab == 0) {
if (this.tab === 0) {
this.myChart.resize()
} else {
this.myChart2.resize()
@@ -415,6 +430,9 @@ export default {
}
},
mounted () {
this.myChart = null
this.myChart2 = null
this.chartOption = null
this.timer = setTimeout(() => {
this.linkTrafficSankeyDataRequest(this.tab)
}, 100)
@@ -423,6 +441,19 @@ export default {
beforeUnmount () {
clearTimeout(this.timer)
window.removeEventListener('resize', this.resize)
if (this.myChart) {
this.myChart.dispose()
// 避免不能生效
this.myChart = null
}
if (this.myChart2) {
this.myChart2.dispose()
this.myChart2 = null
}
this.chartOption = null
this.cnLinkInfo = null
this.unitConvert = null
}
}
</script>

View File

@@ -1,418 +0,0 @@
<template>
<div class="line network link-traffic">
<loading :loading="loading"></loading>
<div class="line-header">
<div class="line-header-left">
<div class="line-value-active" v-if="lineTab"></div>
<div class="line-value">
<div class="line-value-mpackets"
v-show="item.show"
:class=" {'is-active': lineTab === item.class, 'mousemove-cursor': mousemoveCursor === item.class}"
v-for="(item, index) in mpackets"
:key="index"
@mouseenter="mouseenter(item)"
@mouseleave="mouseleave(item)"
@click="activeChange(item, index)">
<div class="line-value-mpackets-name">
<div :class="item.class"></div>
<div class="mpackets-name">{{$t(item.name)}}</div>
</div>
<div class="line-value-unit">
<span class="line-value-unit-number">{{unitConvert(item.analysis.avg, unitTypes.number)[0]}}</span>
<span class="line-value-unit-number2">
<span>{{unitConvert(item.analysis.avg, unitTypes.number)[1]}}</span><span v-if="item.unitType">{{item.unitType}}</span>
</span>
</div>
</div>
</div>
</div>
<div class="line-select line-header-right">
<div class="line-select-metric">
<span>{{$t('network.metric')}}:</span>
<div class="line-select__operation">
<el-select
size="mini"
v-model="lineMetric"
popper-class="common-select"
:popper-append-to-body="false"
@change="metricSelectChange"
>
<el-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</div>
</div>
</div>
</div>
<div style="height: calc(100% - 74px); position: relative">
<chart-no-data v-if="isNoData"></chart-no-data>
<div class="chart-drawing" v-show="showMarkLine && !isNoData" id="linkTrafficLineChart"></div>
</div>
</div>
</template>
<script>
import * as echarts from 'echarts'
import { linkTrafficLineChartOption } from '@/views/charts2/charts/options/echartOption'
import unitConvert from '@/utils/unit-convert'
import { unitTypes, chartColor3, chartColor4 } from '@/utils/constants.js'
import { ref, shallowRef } from 'vue'
import { stackedLineTooltipFormatter } from '@/views/charts/charts/tools'
import _ from 'lodash'
import { get } from '@/utils/http'
import { api } from '@/utils/api'
import { getSecond } from '@/utils/date-util'
import ChartNoData from '@/views/charts/charts/ChartNoData'
import chartMixin from '@/views/charts2/chart-mixin'
import { useRoute } from 'vue-router'
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
import Loading from '@/components/common/Loading'
export default {
name: 'linkTrafficDrillDownLine',
components: {
ChartNoData,
Loading
},
setup () {
const { query } = useRoute()
const lineMetric = ref(query.lineMetric || 'Bits/s')
const lineTab = ref(query.lineTab || '')
const queryCondition = ref(query.queryCondition || '')
return {
lineMetric,
lineTab,
queryCondition,
myChart: shallowRef(null)
}
},
props: {
linkTrafficShow: Boolean,
linkTrafficData: Array
},
mixins: [chartMixin],
data () {
return {
options1: [
{
value: 'Bits/s',
label: 'Bits/s'
},
{
value: 'Packets/s',
label: 'Packets/s'
}
],
mpackets: [
{ analysis: {}, name: 'network.total', class: 'total', show: true, invertTab: true, positioning: 0, data: [], unitType: '' },
{ analysis: {}, name: 'linkMonitor.ingress', class: 'ingress', show: true, invertTab: true, positioning: 1, data: [], unitType: '' },
{ analysis: {}, name: 'linkMonitor.egress', class: 'egress', show: true, invertTab: true, positioning: 2, data: [], unitType: '' }
],
unitConvert,
unitTypes,
chartDateObject: [],
timer: null,
mousemoveCursor: '',
leftOffset: 0,
sizes: [3, 4, 6, 8, 9, 10],
dynamicVariable: '',
showMarkLine: true,
loading: false
}
},
watch: {
lineTab (n) {
this.$nextTick(() => {
this.handleActiveBar(n)
const { query } = this.$route
const newUrl = urlParamsHandler(window.location.href, query, {
lineTab: n
})
overwriteUrl(newUrl)
})
},
lineMetric (n) {
const { query } = this.$route
const newUrl = urlParamsHandler(window.location.href, query, {
lineMetric: n
})
overwriteUrl(newUrl)
},
timeFilter: {
handler (n) {
if (this.lineTab) {
this.init(this.lineMetric, this.showMarkLine, 'active')
} else {
this.init()
}
}
}
},
methods: {
init (val, show, active) {
if (!val) {
val = this.lineMetric
}
const params = {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime)
}
if (this.queryCondition) {
const condition = this.queryCondition.toLowerCase().split(' or ')
if (condition.length > 1) {
params.egressParam = condition.find(c => c.indexOf('common_egress_link_id') > -1 || c.indexOf('egress_link_direction') > -1)
params.ingressParam = condition.find(c => c.indexOf('common_ingress_link_id') > -1 || c.indexOf('ingress_link_direction') > -1)
}
}
this.loading = true
get(api.linkMonitor.totalTrafficAnalysis, params).then((res) => {
if (res.code === 200) {
this.isNoData = res.data.result.length === 0
res.data.result.forEach((t, i) => {
if (t.type === 'bytes' && val === 'Bits/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalBitsRate.analysis
mpackets[1].analysis = t.ingressBitsRate.analysis
mpackets[2].analysis = t.egressBitsRate.analysis
mpackets[0].data = t.totalBitsRate.values ? t.totalBitsRate.values : []
mpackets[1].data = t.ingressBitsRate.values ? t.ingressBitsRate.values : []
mpackets[2].data = t.egressBitsRate.values ? t.egressBitsRate.values : []
mpackets.forEach(e => {
e.unitType = 'bps'
if (e.name !== 'network.total' && e.analysis.avg == 0) {
e.show = false
} else {
e.show = true
if (!active && !show) {
this.legendSelectChange(e, 'index')
}
}
if (this.lineTab === e.class) {
if (e.analysis.avg < 0) {
this.lineTab = ''
this.init()
}
}
})
this.mpackets = mpackets
this.$nextTick(() => {
this.echartsInit(this.mpackets)
})
} else if (t.type === 'packets' && val === 'Packets/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalPacketsRate.analysis
mpackets[1].analysis = t.ingressPacketsRate.analysis
mpackets[2].analysis = t.egressPacketsRate.analysis
mpackets[0].data = t.totalPacketsRate.values ? t.totalPacketsRate.values : []
mpackets[1].data = t.ingressPacketsRate.values ? t.ingressPacketsRate.values : []
mpackets[2].data = t.egressPacketsRate.values ? t.egressPacketsRate.values : []
mpackets.forEach(e => {
e.unitType = 'packets/s'
if (e.name !== 'network.total' && e.analysis.avg == 0) {
e.show = false
} else {
e.show = true
if (!active && !show) {
this.legendSelectChange(e, 'index')
}
}
if (this.lineTab === e.class) {
if (e.analysis.avg < 0) {
this.lineTab = ''
this.init()
}
}
})
this.mpackets = mpackets
this.$nextTick(() => {
this.echartsInit(this.mpackets)
})
}
})
}
}).catch(e => {
console.error(e)
this.isNoData = true
}).finally(() => {
this.loading = false
})
},
echartsInit (echartsData) {
if (this.lineTab) {
this.handleActiveBar()
echartsData = echartsData.filter(t => t.show === true && t.invertTab === false)
} else {
echartsData = echartsData.filter(t => t.show === true)
}
const _this = this
const dom = document.getElementById('linkTrafficLineChart')
!this.myChart && (this.myChart = echarts.init(dom))
this.chartOption = linkTrafficLineChartOption
const chartOption = this.chartOption.series[0]
this.chartOption.series = echartsData.map((t, i) => {
return {
...chartOption,
name: t.name,
lineStyle: {
color: chartColor3[t.positioning],
width: 1
},
stack: t.name !== 'network.total' ? 'network.total' : '',
symbolSize: function (value, params) {
return _this.symbolSizeSortChange(i, value[0])
},
itemStyle: {
emphasis: {
borderColor: chartColor4[t.positioning],
borderWidth: 2,
shadowColor: chartColor4[t.positioning],
shadowBlur: this.sizes[t.positioning] + 2
}
},
areaStyle: {
opacity: 0.1,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: chartColor3[t.positioning]
},
{
offset: 1,
color: chartColor3[t.positioning]
}
])
},
data: t.data.map(v => [Number(v[0]) * 1000, Number(v[1]), 'number']),
}
})
this.chartOption.tooltip.formatter = (params) => {
params.forEach(t => {
t.seriesName = this.$t(t.seriesName)
})
const str = stackedLineTooltipFormatter(params)
return str
}
this.showMarkLine = true
this.myChart.setOption(this.chartOption)
},
activeChange (item, index) {
this.lineTab = item.class
this.legendSelectChange(item, index, 'active')
this.showMarkLine = !item.invertTab
this.init(this.lineMetric, this.showMarkLine, 'active')
},
mouseenter (item) {
this.mousemoveCursor = item.class
this.handleActiveBar(item.class)
},
mouseleave () {
this.mousemoveCursor = ''
},
dispatchLegendSelectAction (name) {
this.myChart && this.myChart.dispatchAction({
type: 'legendSelect',
name: name
})
},
dispatchLegendUnSelectAction (name) {
this.myChart && this.myChart.dispatchAction({
type: 'legendUnSelect',
name: name
})
},
legendSelectChange (item, index, val) {
if (index === 'index') {
this.dispatchLegendSelectAction(item.name)
} else if (this.mpackets[index] && this.mpackets[index].name === item.name) {
this.dispatchLegendSelectAction(item.name)
this.mpackets.forEach((t) => {
if (t.name !== item.name) {
this.dispatchLegendUnSelectAction(t.name)
}
})
}
if (val === 'active') {
this.mpackets.forEach(t => {
if (item.name === t.name) {
t.invertTab = !t.invertTab
} else {
t.invertTab = true
}
if (t.invertTab && item.name === t.name) {
if (this.lineTab) {
this.lineTab = ''
} else {
this.lineTab = t.class
}
this.mpackets.forEach((e) => {
this.dispatchLegendSelectAction(e.name)
})
}
})
}
},
handleActiveBar (value) {
if (document.querySelector('.network .line-value-mpackets.is-active')) {
const { offsetLeft, clientWidth, clientLeft } = document.querySelector('.network .line-value-mpackets.is-active')
const activeBar = document.querySelector('.network .line-value-active')
activeBar.style.cssText += `width: ${clientWidth}px; left: ${offsetLeft + this.leftOffset + clientLeft}px;`
}
},
resize () {
this.myChart.resize()
},
metricSelectChange (val) {
this.lineMetric = val
this.lineTab = ''
this.handleActiveBar()
this.showMarkLine = !this.showMarkLine
this.mpackets.forEach((e, i) => {
if (!e.invertTab) {
e.invertTab = true
}
})
this.init(val, this.showMarkLine)
},
symbolSizeSortChange (index, time) {
const dataIntegrationArray = []
if (linkTrafficLineChartOption.series[0]) {
const totalData = linkTrafficLineChartOption.series[0].data.find(t => t[0] === time) // [time, value]
if (totalData) {
dataIntegrationArray.push(totalData)
totalData[2] = 0
}
}
if (linkTrafficLineChartOption.series[1]) {
const ingressData = linkTrafficLineChartOption.series[1].data.find(t => t[0] === time)
if (ingressData) {
dataIntegrationArray.push(ingressData)
ingressData[2] = 1
}
}
if (linkTrafficLineChartOption.series[2]) {
const egressData = linkTrafficLineChartOption.series[2].data.find(t => t[0] === time)
if (egressData) {
dataIntegrationArray.push(egressData)
egressData[2] = 2
}
}
dataIntegrationArray.sort((a, b) => { return a[1] - b[1] })
const sortIndex = dataIntegrationArray.findIndex(a => a[2] === index)
return this.sizes[sortIndex]
}
},
mounted () {
this.timer = setTimeout(() => {
if (this.lineTab) {
const data = this.mpackets.find(t => t.class === this.lineTab)
this.activeChange(data, data.positioning)
} else {
this.init()
}
}, 200)
window.addEventListener('resize', this.resize)
},
beforeUnmount () {
clearTimeout(this.timer)
window.removeEventListener('resize', this.resize)
}
}
</script>

View File

@@ -1,38 +1,42 @@
<template>
<div class="link-traffic-list">
<loading :loading="loading"></loading>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('network.total')}}</div>
<div class="link-traffic-list-center-value">{{unitConvert(lineData[0].analysis.avg, unitTypes.bps).join('')}}</div>
</div>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('linkMonitor.bandwidthUsage')}}</div>
<div class="link-traffic-list-center-value" v-if="bandWidth">{{unitConvert(lineData[0].analysis.avg / bandWidth, unitTypes.percent).join('')}}</div>
<div class="link-traffic-list-center-value" v-else>-</div>
</div>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('linkMonitor.npmScore')}}</div>
<div class="link-traffic-list-center-value">{{linkTrafficListData.npmScore || '-'}}</div>
</div>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('networkAppPerformance.tcpConnectionEstablishLatency')}}</div>
<div class="link-traffic-list-center-value">{{unitConvert(Math.floor(linkTrafficListData.establishLatencyMs), unitTypes.time).join('')}}</div>
</div>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('networkAppPerformance.httpResponse')}}</div>
<div class="link-traffic-list-center-value">{{unitConvert(Math.floor(linkTrafficListData.httpResponseLatency), unitTypes.time).join('')}}</div>
</div>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('networkAppPerformance.sslResponseLatency')}}</div>
<div class="link-traffic-list-center-value">{{unitConvert(Math.floor(linkTrafficListData.sslConLatency), unitTypes.time).join('')}}</div>
</div>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('networkAppPerformance.packetLoss')}}</div>
<div class="link-traffic-list-center-value">{{unitConvert(linkTrafficListData.tcpLostlenPercent, unitTypes.percent).join('')}}</div>
</div>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('overall.packetRetrans')}}</div>
<div class="link-traffic-list-center-value">{{unitConvert(linkTrafficListData.pktRetransPercent, unitTypes.percent).join('')}}</div>
<chart-error v-if="showError" :content="errorMsg" />
<div v-else>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('network.total')}}</div>
<div class="link-traffic-list-center-value" v-if="lineData[0] && lineData[0].analysis">{{unitConvert(lineData[0].analysis.avg, unitTypes.bps).join('')}}</div>
</div>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('linkMonitor.bandwidthUsage')}}</div>
<div class="link-traffic-list-center-value" v-if="bandWidth && lineData[0] && lineData[0].analysis">{{unitConvert(lineData[0].analysis.avg / bandWidth, unitTypes.percent).join('')}}</div>
<div class="link-traffic-list-center-value" v-else>-</div>
</div>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('linkMonitor.npmScore')}}</div>
<div class="link-traffic-list-center-value">{{linkTrafficListData.npmScore || '-'}}</div>
</div>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('networkAppPerformance.tcpConnectionEstablishLatency')}}</div>
<div class="link-traffic-list-center-value">{{unitConvert(Math.floor(linkTrafficListData.establishLatencyMs), unitTypes.time).join('')}}</div>
</div>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('networkAppPerformance.httpResponse')}}</div>
<div class="link-traffic-list-center-value">{{unitConvert(Math.floor(linkTrafficListData.httpResponseLatency), unitTypes.time).join('')}}</div>
</div>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('networkAppPerformance.sslResponseLatency')}}</div>
<div class="link-traffic-list-center-value">{{unitConvert(Math.floor(linkTrafficListData.sslConLatency), unitTypes.time).join('')}}</div>
</div>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('networkAppPerformance.packetLoss')}}</div>
<div class="link-traffic-list-center-value">{{unitConvert(linkTrafficListData.tcpLostlenPercent, unitTypes.percent).join('')}}</div>
</div>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('overall.packetRetrans')}}</div>
<div class="link-traffic-list-center-value">{{unitConvert(linkTrafficListData.pktRetransPercent, unitTypes.percent).join('')}}</div>
</div>
</div>
</div>
</template>
@@ -48,6 +52,7 @@ import { useRoute } from 'vue-router'
import { getSecond } from '@/utils/date-util'
import { computeScore } from '@/utils/tools'
import Loading from '@/components/common/Loading'
import ChartError from '@/components/common/Error'
export default {
name: 'linkTrafficList',
mixins: [chartMixin],
@@ -62,6 +67,7 @@ export default {
}
},
components: {
ChartError,
Loading
},
data () {
@@ -72,7 +78,9 @@ export default {
linkTrafficListData: {},
cnLinkInfo: JSON.parse(localStorage.getItem(storageKey.linkInfo)),
bandWidth: 0,
loading: false
loading: false,
showError: false,
errorMsg: ''
}
},
watch: {
@@ -91,6 +99,7 @@ export default {
if (this.queryCondition) {
const condition = this.queryCondition.toLowerCase().split(' or ')
if (condition.length > 1) {
// params.egressParam = true
params.egressParam = condition.find(c => c.indexOf('common_egress_link_id') > -1 || c.indexOf('egress_link_direction') > -1)
params.ingressParam = condition.find(c => c.indexOf('common_ingress_link_id') > -1 || c.indexOf('ingress_link_direction') > -1)
let bandwidthAll = 0
@@ -109,10 +118,10 @@ export default {
}
if (egressLinkId && ingressLinkId) {
this.cnLinkInfo.forEach(e => {
if (ingressLinkId == e.originalLinkId) {
if (ingressLinkId === e.originalLinkId) {
bandwidthAll += e.bandwidth
}
if (egressLinkId == e.originalLinkId) {
if (egressLinkId === e.originalLinkId) {
bandwidthAll += e.bandwidth
}
})
@@ -129,22 +138,28 @@ export default {
this.loading = true
get(api.linkMonitor.networkAnalysis, params).then(res => {
if (res.code === 200) {
this.showError = false
this.isNoData = res.data.result.length === 0
const dataArr = [0, 1, 2, 3, 4]
let scoreAll = 0
dataArr.forEach(e => {
const score = computeScore(res.data.result[0], e)
scoreAll += score
})
this.linkTrafficListData = res.data.result[0]
this.linkTrafficListData.npmScore = Math.ceil(scoreAll * 6)
if (this.linkTrafficListData.npmScore > 6) {
this.linkTrafficListData.npmScore = 6
const data = {
establishLatencyMs: res.data.result[0].establishLatencyMs || null,
httpResponseLatency: res.data.result[0].httpResponseLatency || null,
sslConLatency: res.data.result[0].sslConLatency || null,
tcpLostlenPercent: res.data.result[0].tcpLostlenPercent || null,
pktRetransPercent: res.data.result[0].pktRetransPercent || null
}
this.linkTrafficListData = res.data.result[0]
this.linkTrafficListData.npmScore = computeScore(data)
} else {
this.showError = true
// todo 此时返回的是msg后期记得改
this.errorMsg = res.msg
// this.errorMsg = res.message
}
}).catch(e => {
console.error(e)
this.isNoData = true
this.showError = true
this.errorMsg = e.message
// this.isNoData = true
}).finally(() => {
this.loading = false
})

View File

@@ -1,30 +1,20 @@
<template>
<div class="network-overview-apps">
<div class="line-select-metric">
<span>{{$t('network.metric')}}:</span>
<div class="line-select__operation">
<el-select
size="mini"
v-model="metricFilter"
placeholder=""
popper-class="common-select"
:popper-append-to-body="false"
@change="metricChange"
>
<el-option v-for="item in metricOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</div>
<div class="network-overview-apps-header">
<div class="network-overview-apps-title">{{$t('networkOverview.appType.providerAndApp')}}</div>
<chart-error v-if="showError" tooltip :content="errorMsg" max-width="350" width="280" />
</div>
<div class="app-cards">
<div class="app-card" v-for="(app, index) in appData" :key="index">
<div class="app-card" @mouseenter="mouseenter(app)" @mouseleave="mouseleave(app)" v-for="(app, index) in appData" :key="app.type + app.name">
<div class="app-card-title">
<div class="app-card-title-name">
<i class="cn-icon" :class="app.type === 'provider' ? 'cn-icon-entity' : 'cn-icon-app2'"></i>
<span @click="drillDownData(app.type, app.name)">{{app.name}}</span>
</div>
<div class="app-card-title-more" v-ele-click-outside="clickOutSide">
<span><i class="cn-icon cn-icon-more-dark" @click="moreChange(app)"></i></span>
<span class="app-card-title-more-delete" @click="del(app, index)" v-show="app.moreOptions"><i class="cn-icon cn-icon-delete"></i>{{$t('overall.delete')}}</span>
<div class="app-card-title-more">
<span v-show="app.showMore"><i class="cn-icon cn-icon-more-dark" @mouseenter="mouseenterMore(app)"></i></span>
<span class="app-card-title-more-delete" @click="del(app, index)" v-show="app.moreOptions" @mouseleave="mouseleaveMore(app)"><i class="cn-icon cn-icon-delete"></i>{{$t('overall.delete')}}</span>
</div>
</div>
<div class="app-card__bodys">
@@ -44,12 +34,13 @@
</span>
<span v-else>>500.00%</span>
</div>
<div v-else-if="app.value === '-' || app.value === 0" class="app-card__body-content-percent">0</div>
<div v-else-if="app.value === '-' || app.value === 0" class="app-card__body-content-percent">+0.00%</div>
</div>
</div>
<div class="app-card__body-previous">
<div>Total</div>
<div>{{unitConvert(app.total, unitTypes.number).join(' ')}}</div>
<div v-if="metric === 'Bits/s'">{{unitConvert(app.total, unitTypes.byte).join(' ')}}</div>
<div v-else>{{unitConvert(app.total, unitTypes.number).join(' ')}}</div>
</div>
</div>
<div class="chart__drawing" v-show="!isNoData" :id="`chart-${app.name}-${app.type}`"></div>
@@ -77,7 +68,7 @@
</div>
<div class="add-app__body">
<el-tabs v-model="appTypeTab" @tab-click="appTypeTabChange">
<el-tab-pane :label="$t('networkOverview.appType.provider')" :name="0">
<el-tab-pane :label="$t('network.providers')" :name="0">
<div class="body__apps" :class="{'body__apps-no-grid': providerOptions.length === 0}">
<loading :loading="loadingBody"></loading>
<chart-no-data v-if="providerOptions.length === 0 && !loadingBody"></chart-no-data>
@@ -127,7 +118,7 @@ import unitConvert from '@/utils/unit-convert'
import { storageKey, unitTypes, networkTable, operationType, curTabState } from '@/utils/constants'
import * as echarts from 'echarts'
import { appListChartOption } from '@/views/charts2/charts/options/echartOption'
import { ref, shallowRef } from 'vue'
import { shallowRef } from 'vue'
import { get, put } from '@/utils/http'
import { api } from '@/utils/api'
import _ from 'lodash'
@@ -137,7 +128,6 @@ import loading from '@/components/common/Loading'
import ChartNoData from '@/views/charts/charts/ChartNoData'
import { appStackedLineTooltipFormatter } from '@/views/charts/charts/tools'
import chartMixin from '@/views/charts2/chart-mixin'
import { useRoute } from 'vue-router'
export default {
name: 'NetworkOverviewApps',
@@ -148,20 +138,7 @@ export default {
mixins: [chartMixin],
data () {
return {
metricOptions: [
{
value: 'Bits/s',
label: 'Bits/s'
},
{
value: 'Packets/s',
label: 'Packets/s'
},
{
value: 'Sessions/s',
label: 'Sessions/s'
}
],
testData: '测试值',
appData: [],
// 假数据
appTempData: [],
@@ -188,25 +165,23 @@ export default {
timerSearch: null,
loadingBody: false,
curTabState: curTabState,
urlChangeParams: {}
urlChangeParams: {},
showError: false,
errorMsg: ''
}
},
props: {
metric: {
type: String,
default: 'Bits/s'
}
},
setup () {
const { query } = useRoute()
const metricFilter = ref(query.appListMetric || 'Bits/s')
return {
metricFilter,
myChart: shallowRef([])
}
},
watch: {
metricFilter (n) {
const { query } = this.$route
const newUrl = urlParamsHandler(window.location.href, query, {
appListMetric: n
})
overwriteUrl(newUrl)
},
showAddApp: {
deep: true,
handler (n) {
@@ -218,10 +193,11 @@ export default {
}
}
},
timeFilter: {
handler (n) {
this.init()
}
timeFilter (n) {
this.init()
},
metric (n) {
this.init()
}
},
methods: {
@@ -249,7 +225,7 @@ export default {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
appLabels: appCards.map(item => {
return item.name
return `'${item.name}'`
}).join(',')
}
prevRequest = get(api.netWorkOverview.applicationCycleTrafficTotal, params)
@@ -261,7 +237,7 @@ export default {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
appCompanies: providerCards.map(item => {
return item.name
return `'${item.name}'`
}).join(',')
}
prevRequest = get(api.netWorkOverview.appCompanyCycleTrafficTotal, params)
@@ -273,13 +249,22 @@ export default {
this.toggleLoading(true)
Promise.all([prevRequest, request]).then(res => {
this.isNoData = (res[0].data.result.length && res[1].data.result.length) === 0
if (this.isNoData) {
this.appData = this.appData.map(t => {
return {
name: t.name,
type: t.type
}
})
}
if (res[0].code === 200 && res[1].code === 200) {
this.showError = false
const prevData = res[0].data.result
const data = res[1].data.result
let toCompareType = 'bytes'
if (this.metricFilter === 'Sessions/s') {
if (this.metric === 'Sessions/s') {
toCompareType = 'sessions'
} else if (this.metricFilter === 'Packets/s') {
} else if (this.metric === 'Packets/s') {
toCompareType = 'packets'
}
data.forEach(d => {
@@ -301,9 +286,13 @@ export default {
})
}
})
} else {
this.showError = true
this.errorMsg = res[0].message
}
}).catch(e => {
console.error(e)
this.showError = true
this.errorMsg = e.message
this.isNoData = true
}).finally(() => {
this.toggleLoading(false)
@@ -420,18 +409,18 @@ export default {
...chartOption.series[0],
data: obj.lineData.map(v => [Number(v[0]) * 1000, Number(v[1]), 'number']),
lineStyle: {
color: obj.trend === 'up' ? '#7FA054' : '#35ADDA'
color: '#35ADDA'
},
areaStyle: {
opacity: 0.1,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: obj.trend === 'up' ? '#7FA054' : '#35ADDA'
color: '#35ADDA'
},
{
offset: 1,
color: obj.trend === 'up' ? '#7FA054' : '#35ADDA'
color: '#35ADDA'
}
])
}
@@ -463,7 +452,6 @@ export default {
},
addApp (pageNo, val, show) {
this.showAddApp = true
const letter = 'abcdefghijklmnopqrstuvwxyz'
const params = {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
@@ -482,7 +470,7 @@ export default {
} else {
params.pageNo = 1
}
if (this.appTypeTab == 0) {
if (parseFloat(this.appTypeTab) === 0) {
params.type = 'overviewProvide'
get(api.dict, params).then(res => {
if (res.code === 200) {
@@ -507,7 +495,7 @@ export default {
this.loading = false
this.loadingBody = false
})
} else if (this.appTypeTab == 1) {
} else if (parseFloat(this.appTypeTab) === 1) {
params.type = 'overviewApp'
get(api.dict, params).then(res => {
res.data.list = res.data.list.filter(l => !this.appData.some(pd => pd.type === 'app' && pd.name === l.value))
@@ -547,7 +535,7 @@ export default {
cancelApp () {
this.showAddApp = false
},
appTypeTabChange (val) {
appTypeTabChange () {
this.pageObj.pageNo = 1
this.searcherApp = ''
this.addApp()
@@ -690,17 +678,46 @@ export default {
})
}
},
moreChange (app) {
this.appData.forEach(t => {
if (t.name === app.name && t.type === app.type) {
t.moreOptions = !t.moreOptions
}
})
},
// moreChange (app) {
// this.appData.forEach(t => {
// if (t.name === app.name && t.type === app.type) {
// t.moreOptions = !t.moreOptions
// }
// })
// },
resize () {
this.myChart.forEach(t => {
t.resize()
})
},
mouseenterMore (app) {
this.appData.forEach(t => {
if (t.name === app.name && t.type === app.type) {
t.moreOptions = true
}
})
},
mouseleaveMore (app) {
this.appData.forEach(t => {
if (t.name === app.name && t.type === app.type) {
t.moreOptions = false
}
})
},
mouseenter (app) {
this.appData.forEach(t => {
if (t.name === app.name && t.type === app.type) {
t.showMore = true
}
})
},
mouseleave (app) {
this.appData.forEach(t => {
if (t.name === app.name && t.type === app.type) {
t.showMore = false
t.moreOptions = false
}
})
}
},
mounted () {
@@ -720,6 +737,8 @@ export default {
window.removeEventListener('resize', this.resize)
clearTimeout(this.timerScroll)
clearTimeout(this.timerSearch)
this.myChart = null
this.unitConvert = null
}
}
</script>

View File

@@ -1,8 +1,13 @@
<template>
<div class="ddos-detection">
<chart-no-data v-if="isNoData"></chart-no-data>
<div class="ddos-detection-title"><i class="cn-icon cn-icon-a-DDosDetection"></i>{{$t('network.ddosDetection')}}</div>
<div class="ddos-detection-value" v-if="!isNoData">
<chart-error info v-if="showError" :content="errorMsg" />
<div class="ddos-detection-title">
<i class="cn-icon cn-icon-a-DDosDetection"></i>
{{$t('network.ddosDetection')}}
</div>
<div class="ddos-detection-value" v-if="!isNoData && !showError">
<div class="ddos-detection-type">
<div class="ddos-detection-type-value">
<div class="ddos-detection-type-value-name">{{$t('network.numberOfAttacks')}}</div>
@@ -28,21 +33,25 @@ import { get } from '@/utils/http'
import { getSecond } from '@/utils/date-util'
import ChartNoData from '@/views/charts/charts/ChartNoData'
import chartMixin from '@/views/charts2/chart-mixin'
import ChartError from '@/components/common/Error'
export default {
name: 'NetworkOverviewDdosDetection',
components: {
ChartError,
ChartNoData
},
mixins: [chartMixin],
data () {
return {
ddosData: {},
isNoData: false
isNoData: false,
showError: false,
errorMsg: ''
}
},
watch: {
timeFilter: {
handler (n) {
handler () {
this.ddosDetectDataRequests()
}
}
@@ -56,13 +65,22 @@ export default {
this.toggleLoading(true)
get(api.netWorkOverview.ddosEventAnalysis, params).then(res => {
if (res.code === 200) {
this.showError = false
if (res.data.result.length === 0) {
this.isNoData = true
} else {
this.ddosData = res.data.result[0]
this.isNoData = false
}
} else {
this.isNoData = false
this.showError = true
this.errorMsg = res.message
}
}).catch((e) => {
this.isNoData = false
this.showError = true
this.errorMsg = e.message
}).finally(() => {
this.toggleLoading(false)
})

View File

@@ -1,6 +1,7 @@
<template>
<div class="line network">
<div class="line-header">
<chart-error v-if="showError" :content="errorMsg" />
<div class="line-header" v-if="!showError">
<div class="line-header-left">
<div class="line-value-active" v-if="lineTab"></div>
<div class="line-value">
@@ -26,20 +27,6 @@
</div>
</div>
<div class="line-select line-header-right">
<div class="line-select-metric">
<span>{{$t('network.metric')}}:</span>
<div class="line-select__operation">
<el-select
size="mini"
v-model="lineMetric"
popper-class="common-select"
:popper-append-to-body="false"
@change="metricSelectChange"
>
<el-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</div>
</div>
<div class="line-select-reference-line">
<span>{{$t('network.referenceLine')}}:</span>
<div class="line-select__operation">
@@ -58,8 +45,12 @@
</div>
</div>
<div style="height: calc(100% - 74px); position: relative">
<chart-no-data v-if="isNoData"></chart-no-data>
<div class="chart-drawing" v-show="showMarkLine && !isNoData" id="overviewLineChart"></div>
<chart-no-data v-if="isNoData && !showError"></chart-no-data>
<div class="chart-drawing" v-show="showMarkLine && !isNoData && !showError" id="overviewLineChart"></div>
<!-- todo 后续改动此处为框选返回-->
<!-- <div id="brushBtn" style="position: absolute;left: 0;top: 0;" v-show="mouseDownFlag">-->
<!-- <el-button @click.stop="backBrushHistory">返回</el-button>-->
<!-- </div>-->
</div>
</div>
</template>
@@ -79,42 +70,38 @@ import ChartNoData from '@/views/charts/charts/ChartNoData'
import chartMixin from '@/views/charts2/chart-mixin'
import { useRoute } from 'vue-router'
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
import ChartError from '@/components/common/Error'
export default {
name: 'NetworkOverviewLine',
components: {
ChartError,
ChartNoData
},
props: {
metric: {
type: String,
default: 'Bits/s'
}
},
setup () {
const { query } = useRoute()
const lineMetric = ref(query.lineMetric || 'Bits/s')
const lineRefer = ref(query.lineRefer || 'Average')
const lineTab = ref(query.lineTab || '')
const queryCondition = ref(query.queryCondition || '')
const tabOperationType = ref(query.tabOperationType)
const networkOverviewBeforeTab = ref(query.networkOverviewBeforeTab)
return {
lineMetric,
lineRefer,
lineTab,
queryCondition,
tabOperationType,
networkOverviewBeforeTab,
myChart: shallowRef(null)
}
},
mixins: [chartMixin],
data () {
return {
options1: [
{
value: 'Bits/s',
label: 'Bits/s'
},
{
value: 'Packets/s',
label: 'Packets/s'
},
{
value: 'Sessions/s',
label: 'Sessions/s'
}
],
options2: [
{
value: 'Average',
@@ -145,7 +132,11 @@ export default {
leftOffset: 0,
sizes: [3, 4, 6, 8, 9, 10],
dynamicVariable: '',
showMarkLine: true
showMarkLine: true,
mouseDownFlag: false,
brushHistory: [],
showError: false,
errorMsg: ''
}
},
watch: {
@@ -159,13 +150,6 @@ export default {
overwriteUrl(newUrl)
})
},
lineMetric (n) {
const { query } = this.$route
const newUrl = urlParamsHandler(window.location.href, query, {
lineMetric: n
})
overwriteUrl(newUrl)
},
lineRefer (n) {
const { query } = this.$route
const newUrl = urlParamsHandler(window.location.href, query, {
@@ -174,34 +158,72 @@ export default {
overwriteUrl(newUrl)
},
timeFilter: {
handler (n) {
handler () {
if (this.lineTab) {
this.init(this.lineMetric, this.showMarkLine, 'active')
this.init(this.metric, this.showMarkLine, 'active')
} else {
this.init()
}
}
},
metric (n) {
this.handleActiveBar()
this.showMarkLine = !this.showMarkLine
this.mpackets.forEach((e) => {
if (!e.invertTab) {
e.invertTab = true
}
})
this.init(n, this.showMarkLine, '', n)
}
},
methods: {
init (val, show, active) {
init (val, show, active, n) {
if (!val) {
val = this.lineMetric
val = this.metric
}
const params = {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime)
}
// const condition = this.$store.getters.getQueryCondition
// const condition = this.$route.query.queryCondition ? this.$route.query.queryCondition : ''
if (this.queryCondition) {
let condition = ''
if (this.queryCondition && this.tabOperationType !== '3') {
params.q = this.queryCondition
} else if (this.tabOperationType == '3' && this.queryCondition) {
if (this.queryCondition.indexOf(' OR ') > -1) {
if (this.networkOverviewBeforeTab === 'isp') {
condition = this.queryCondition.split(/["|'= ](.*?)["|'= ]/)
params.q = `notEmpty(${condition[0]}) OR notEmpty(${condition[9]})`
} else {
condition = this.queryCondition.split(/["|'= ](.*?)["|'= ]/)
params.q = `notEmpty(${condition[0]}) OR notEmpty(${condition[5]})`
}
} else {
condition = this.queryCondition.split(/['=](.*?)['=]/)
params.q = `notEmpty(${condition[0]})`
}
}
this.toggleLoading(true)
get(api.netWorkOverview.totalTrafficAnalysis, params).then((res) => {
this.errorMsg = res.message
if (res.code === 200) {
this.isNoData = res.data.result.length === 0
res.data.result.forEach((t, i) => {
this.showError = false
if (this.isNoData) {
this.lineTab = ''
this.mpackets = [
{ analysis: {}, name: 'network.total', class: 'total', show: true, invertTab: true, positioning: 0, data: [], unitType: '' },
{ analysis: {}, name: 'network.inbound', class: 'inbound', show: true, invertTab: true, positioning: 1, data: [], unitType: '' },
{ analysis: {}, name: 'network.outbound', class: 'outbound', show: true, invertTab: true, positioning: 2, data: [], unitType: '' },
{ analysis: {}, name: 'network.internal', class: 'internal', show: true, invertTab: true, positioning: 3, data: [], unitType: '' },
{ analysis: {}, name: 'network.through', class: 'through', show: true, invertTab: true, positioning: 4, data: [], unitType: '' },
{ analysis: {}, name: 'network.other', class: 'other', show: true, invertTab: true, positioning: 5, data: [], unitType: '' }
]
}
res.data.result.forEach((t) => {
if (t.type === 'bytes' && val === 'Bits/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalBitsRate.analysis
@@ -216,10 +238,12 @@ export default {
mpackets[3].data = t.internalBitsRate.values ? t.internalBitsRate.values : []
mpackets[4].data = t.throughBitsRate.values ? t.throughBitsRate.values : []
mpackets[5].data = t.other.values ? t.other.values : []
let num = 0
mpackets.forEach(e => {
e.unitType = 'bps'
if (e.name !== 'network.total' && e.analysis.avg == 0) {
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) === 0) {
e.show = false
num += 1
} else {
e.show = true
if (!active && show !== this.lineRefer) {
@@ -227,16 +251,28 @@ export default {
}
}
if (this.lineTab === e.class) {
if (e.analysis.avg < 0) {
if (parseFloat(e.analysis.avg) <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
}
}
})
this.mpackets = mpackets
this.$nextTick(() => {
this.echartsInit(this.mpackets, show)
})
if (num === 5) {
mpackets[0].invertTab = false
this.lineTab = 'total'
this.legendSelectChange(mpackets[0], 0)
this.$nextTick(() => {
this.echartsInit(this.mpackets, true)
})
} else {
if (n) this.lineTab = ''
this.$nextTick(() => {
this.echartsInit(this.mpackets, show)
if (!this.lineRefer) this.lineRefer = 'Average'
})
}
} else if (t.type === 'packets' && val === 'Packets/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalPacketsRate.analysis
@@ -251,10 +287,12 @@ export default {
mpackets[3].data = t.internalPacketsRate.values ? t.internalPacketsRate.values : []
mpackets[4].data = t.throughPacketsRate.values ? t.throughPacketsRate.values : []
mpackets[5].data = t.other.values ? t.other.values : []
let num = 0
mpackets.forEach(e => {
e.unitType = 'packets/s'
if (e.name !== 'network.total' && e.analysis.avg == 0) {
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) === 0) {
e.show = false
num += 1
} else {
e.show = true
if (!active && show !== this.lineRefer) {
@@ -262,16 +300,28 @@ export default {
}
}
if (this.lineTab === e.class) {
if (e.analysis.avg < 0) {
if (parseFloat(e.analysis.avg) <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
}
}
})
this.mpackets = mpackets
this.$nextTick(() => {
this.echartsInit(this.mpackets, show)
})
if (num === 5) {
mpackets[0].invertTab = false
this.lineTab = 'total'
this.legendSelectChange(mpackets[0], 0)
this.$nextTick(() => {
this.echartsInit(this.mpackets, true)
})
} else {
if (n) this.lineTab = ''
this.$nextTick(() => {
this.echartsInit(this.mpackets, show)
if (!this.lineRefer) this.lineRefer = 'Average'
})
}
} else if (t.type === 'sessions' && val === 'Sessions/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalSessionsRate.analysis
@@ -281,24 +331,51 @@ export default {
e.show = false
}
e.unitType = 'sessions/s'
if (show !== this.lineRefer) {
this.legendSelectChange(e, 0)
}
e.invertTab = false
this.lineTab = 'total'
this.legendSelectChange(e, 0)
})
this.mpackets = mpackets
this.$nextTick(() => {
this.echartsInit(this.mpackets, show)
this.echartsInit(this.mpackets, true)
})
}
})
} else {
this.showError = true
this.errorMsg = res.message
}
}).catch(e => {
console.error(e)
this.isNoData = true
this.showError = true
this.errorMsg = e.message
this.isNoData = false
}).finally(() => {
this.toggleLoading(false)
})
},
/**
* 初始化echartsdom用于右键点击返回框选
*/
domInit () {
const self = this
// 去掉默认的contextmenu事件否则会和右键事件同时出现。
document.oncontextmenu = function (e) {
e.preventDefault()
}
document.getElementById('overviewLineChart').onmousedown = function (e) {
// e.button: 0左键1滚轮2右键
if (e.button === 2) {
self.myChart.dispatchAction({
type: 'brush',
areas: [] // 删除选框
})
self.mouseDownFlag = true
document.getElementById('brushBtn').style.left = e.layerX + 'px'
document.getElementById('brushBtn').style.top = e.layerY + 74 + 'px'
}
}
},
echartsInit (echartsData, show) {
if (this.lineTab) {
this.handleActiveBar()
@@ -307,8 +384,13 @@ export default {
echartsData = echartsData.filter(t => t.show === true)
}
const _this = this
const dom = document.getElementById('overviewLineChart')
!this.myChart && (this.myChart = echarts.init(dom))
// !this.myChart && (this.myChart = echarts.init(dom))
// 此处为验证是否因dom未销毁导致图表出错后续可能会改
let dom = null
dom = document.getElementById('overviewLineChart')
if (this.myChart) {
this.myChart.dispose()
}
this.chartOption = stackedLineChartOption
const chartOption = this.chartOption.series[0]
this.chartOption.series = echartsData.map((t, i) => {
@@ -320,7 +402,7 @@ export default {
width: 1
},
stack: t.name !== 'network.total' ? 'network.total' : '',
symbolSize: function (value, params) {
symbolSize: function (value) {
return _this.symbolSizeSortChange(i, value[0])
},
itemStyle: {
@@ -364,7 +446,7 @@ export default {
}
})
if (!show) {
this.chartOption.series.forEach((t, i) => {
this.chartOption.series.forEach((t) => {
t.markLine.label.show = false
t.markLine = []
})
@@ -396,20 +478,75 @@ export default {
this.chartOption.tooltip.formatter = (params) => {
params.forEach(t => {
t.seriesName = this.$t(t.seriesName)
this.mpackets.forEach(e => {
if (this.$t(e.name) === t.seriesName) {
t.borderColor = chartColor3[e.positioning]
}
})
})
const str = stackedLineTooltipFormatter(params)
return str
}
this.showMarkLine = true
this.myChart.setOption(this.chartOption)
this.$nextTick(() => {
this.myChart = echarts.init(dom)
this.myChart.setOption(this.chartOption)
// 设置参见官网https://echarts.apache.org/zh/api.html#action.brush.brush
this.myChart.dispatchAction({
// 刷选模式的开关。使用此 action 可将当前鼠标变为可刷选状态。事实上,点击 toolbox 中的 brush 按钮时,就是通过这个 action将当前普通鼠标变为刷选器的。
type: 'takeGlobalCursor',
// 如果想变为“可刷选状态”,必须设置。不设置则会关闭“可刷选状态”。
key: 'brush',
brushOption: {
// 参见 brush 组件的 brushType。如果设置为 false 则关闭“可刷选状态”。
brushType: 'lineX',
xAxisIndex: 'all',
// 单击清除选框
brushMode: 'single',
// 选择完毕再返回所选数据
throttleType: 'debounce'
}
})
const self = this
this.myChart.on('brushEnd', function (params) {
self.myChart.dispatchAction({
type: 'brush',
areas: [] // 删除选框
})
if (!self.mouseDownFlag) {
// 避免点击空白区域报错
if (params.areas !== undefined && params.areas.length > 0) {
self.brushHistory.unshift({
startTime: _.cloneDeep(self.timeFilter.startTime) * 1000,
endTime: _.cloneDeep(self.timeFilter.endTime) * 1000
})
const rangeObj = {
startTime: Math.ceil(params.areas[0].coordRange[0]),
endTime: Math.ceil(params.areas[0].coordRange[1])
}
// todo 目前暂定框选最小范围为5分钟后续可能会变动
if (rangeObj.endTime - rangeObj.startTime < 5 * 60 * 1000) {
rangeObj.startTime = rangeObj.endTime - 5 * 60 * 1000
}
_this.$store.commit('setRangeEchartsData', rangeObj)
}
}
})
})
},
activeChange (item, index) {
if (this.isNoData) return
this.lineTab = item.class
this.legendSelectChange(item, index, 'active')
this.showMarkLine = !item.invertTab
this.init(this.lineMetric, this.showMarkLine, 'active')
this.init(this.metric, this.showMarkLine, 'active')
},
mouseenter (item) {
if (this.isNoData) return
this.mousemoveCursor = item.class
this.handleActiveBar(item.class)
},
@@ -459,7 +596,7 @@ export default {
})
}
},
handleActiveBar (value) {
handleActiveBar () {
if (document.querySelector('.network .line-value-mpackets.is-active')) {
const { offsetLeft, clientWidth, clientLeft } = document.querySelector('.network .line-value-mpackets.is-active')
const activeBar = document.querySelector('.network .line-value-active')
@@ -469,18 +606,6 @@ export default {
resize () {
this.myChart.resize()
},
metricSelectChange (val) {
this.lineMetric = val
this.lineTab = ''
this.handleActiveBar()
this.showMarkLine = !this.showMarkLine
this.mpackets.forEach((e, i) => {
if (!e.invertTab) {
e.invertTab = true
}
})
this.init(val, this.showMarkLine)
},
referenceSelectChange (val) {
this.lineRefer = val
this.echartsInit(this.mpackets, this.showMarkLine)
@@ -532,13 +657,33 @@ export default {
dataIntegrationArray.sort((a, b) => { return a[1] - b[1] })
const sortIndex = dataIntegrationArray.findIndex(a => a[2] === index)
return this.sizes[sortIndex]
},
/**
* 鼠标右键返回框选的时间范围
*/
backBrushHistory () {
this.myChart.dispatchAction({
type: 'brush',
areas: [] // 删除选框
})
if (this.brushHistory.length > 0) {
this.$store.commit('setRangeEchartsData', _.cloneDeep(this.brushHistory[0]))
this.brushHistory.shift()
}
this.mouseDownFlag = false
}
},
mounted () {
// todo 初始化鼠标事件,开启右键返回
// this.domInit()
this.myChart = null
this.chartOption = null
this.timer = setTimeout(() => {
if (this.lineTab) {
const data = this.mpackets.find(t => t.class === this.lineTab)
this.activeChange(data, data.positioning)
if (data && data.positioning) {
this.activeChange(data, data.positioning)
}
} else {
this.init()
}
@@ -548,6 +693,15 @@ export default {
beforeUnmount () {
clearTimeout(this.timer)
window.removeEventListener('resize', this.resize)
let myChart = echarts.getInstanceByDom(document.getElementById('overviewLineChart'))
if (myChart) {
echarts.dispose(myChart)
}
this.myChart = null
// 检测时发现该方法占用较大内存,且未被释放
this.unitConvert = null
myChart = null
}
}
</script>

View File

@@ -1,18 +1,24 @@
<template>
<div class="performance-event">
<div class="performance-event-title"><i class="cn-icon cn-icon-a-NetworkPerformanceEvent"></i>{{$t('network.networkPerEvent')}}</div>
<div class="performance-event-title">
<i class="cn-icon cn-icon-a-NetworkPerformanceEvent"></i>{{$t('network.networkPerEvent')}}
</div>
<div class="performance-event-value">
<div class="performance-event-pie">
<chart-no-data v-if="isNoData"></chart-no-data>
<chart-error v-if="showError1" info :content="errorMsg1" />
<div class="chart-drawing" id="chart1" v-show="!isNoData"></div>
</div>
<div class="performance-event-pie-hr"></div>
<div class="performance-event-pie">
<chart-no-data v-if="isNoData2"></chart-no-data>
<chart-error v-if="showError1" info :content="errorMsg1" />
<div class="chart-drawing" id="chart2" v-show="!isNoData2"></div>
</div>
</div>
<el-button class="pie-button" size="small">{{$t('network.dashboards')}}<i class="cn-icon cn-icon-arrow-right"></i></el-button>
<el-button class="pie-button" size="small" @click="routerJump">
{{$t('network.dashboards')}}<i class="cn-icon cn-icon-arrow-right"></i>
</el-button>
</div>
</template>
@@ -25,6 +31,7 @@ import { api } from '@/utils/api'
import { getSecond } from '@/utils/date-util'
import ChartNoData from '@/views/charts/charts/ChartNoData'
import chartMixin from '@/views/charts2/chart-mixin'
import ChartError from '@/components/common/Error'
export default {
name: 'NetworkOverviewPerformanceEvent',
setup () {
@@ -35,6 +42,7 @@ export default {
},
mixins: [chartMixin],
components: {
ChartError,
ChartNoData
},
data () {
@@ -43,12 +51,17 @@ export default {
isNoData: false,
isNoData2: false,
loading1: false,
loading2: false
loading2: false,
showError1: false,
showError2: false,
errorMsg1: '',
errorMsg2: ''
}
},
methods: {
init () {
const params = {
// startTime: true,
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime)
}
@@ -60,6 +73,7 @@ export default {
this.loading1 = true
get(api.netWorkOverview.eventSeverity, params).then(res => {
if (res.code === 200) {
this.showError1 = false
if (res.data.result.length === 0) {
this.isNoData = true
return
@@ -88,8 +102,14 @@ export default {
this.chartOption.series[0].data = res.data.result.sort((a, b) => { return a.index - b.index })
this.myChart.setOption(this.chartOption)
} else {
this.isNoData = true
this.isNoData = false
this.showError1 = true
this.errorMsg1 = res.message
}
}).catch((e) => {
this.isNoData = false
this.showError1 = true
this.errorMsg1 = e.message
}).finally(() => {
this.loading1 = false
})
@@ -100,6 +120,8 @@ export default {
this.loading2 = true
get(api.netWorkOverview.eventType, params).then(res => {
if (res.code === 200) {
this.showError2 = false
if (res.data.result.length === 0) {
this.isNoData2 = true
return
@@ -119,12 +141,29 @@ export default {
}
this.chartOption2.series[0].data = res.data.result
this.myChart2.setOption(this.chartOption2)
} else {
this.isNoData2 = false
this.showError2 = true
this.errorMsg2 = res.message
}
}).catch((e) => {
this.isNoData2 = false
this.showError2 = true
this.errorMsg2 = e.message
}).finally(() => {
this.loading2 = false
})
}
},
routerJump () {
this.$router.push({
path: '/panel/networkAppPerformance',
query: {
tabIndex: 2,
t: +new Date()
}
})
},
resize () {
this.myChart.resize()
this.myChart2.resize()
@@ -154,6 +193,8 @@ export default {
beforeUnmount () {
clearTimeout(this.timer)
window.removeEventListener('resize', this.resize)
this.myChart = null
this.myChart2 = null
}
}
</script>

View File

@@ -1,6 +1,8 @@
<template>
<div class="npm-app">
<div class="npm-app-left">
<div class="npm-app" :class="showError?'npm-app-border':''">
<chart-error v-if="showError" :content="errorMsg" />
<div class="npm-app-left" v-if="!showError">
<div class="npm-app-letter" :class="{'npm-app-letter-no-data': isNoData}">
<div v-for="(letter, index) in colorPatchData" :key="index">
{{letter.letter}}
@@ -21,7 +23,7 @@
class="app-table"
height="100%"
empty-text=" "
>
v-if="!showError">
<template v-for="(item, index) in customTableTitles" :key="index">
<el-table-column class="data-column">
<template #header>
@@ -134,9 +136,16 @@ import unitConvert from '@/utils/unit-convert'
import { api } from '@/utils/api'
import { getSecond } from '@/utils/date-util'
import { get } from '@/utils/http'
import { getChainRatio, computeScore, changeCurTab, urlParamsHandler, overwriteUrl, getUserDrilldownTableConfig } from '@/utils/tools'
import {
getChainRatio,
computeScore,
urlParamsHandler,
overwriteUrl,
getUserDrilldownTableConfig
} from '@/utils/tools'
import chartMixin from '@/views/charts2/chart-mixin'
import ChartNoData from '@/views/charts/charts/ChartNoData'
import ChartError from '@/components/common/Error'
export default {
name: 'NpmAppCategoryScore',
data () {
@@ -162,16 +171,19 @@ export default {
],
isNoData: false,
curTabState: curTabState,
urlChangeParams: {}
urlChangeParams: {},
showError: false,
errorMsg: ''
}
},
components: {
ChartError,
ChartNoData
},
mixins: [chartMixin],
watch: {
timeFilter: {
handler (n) {
handler () {
this.init()
}
}
@@ -187,70 +199,98 @@ export default {
const lastCycleTrafficRequest = get(api.npm.overview.appTrafficAnalysis, { ...params, cycle: 1 })
this.toggleLoading(true)
Promise.all([currentTrafficRequest, lastCycleTrafficRequest]).then(res => {
const prevData = res[1].data.result
const data = res[0].data.result
if (data && data.length > 0) {
this.isNoData = false
const tableData = data.map(d => {
const mapping = npmCategoryInfoMapping.find(mapping => mapping.appSubcategory === d.appSubcategory)
const result = {
...mapping,
...d,
bytesRateChainRatio: '-',
inboundBytesRateChainRatio: '-',
outboundBytesRateChainRatio: '-'
}
if (res[0].code === 200 && res[1].code === 200) {
this.showError = false
this.errorMsg = ''
const prevData = res[1].data.result
const data = res[0].data.result
if (data && data.length > 0) {
this.isNoData = false
const tableData = data.map(d => {
const mapping = npmCategoryInfoMapping.find(mapping => mapping.appSubcategory === d.appSubcategory)
const result = {
...mapping,
...d,
bytesRateChainRatio: '-',
inboundBytesRateChainRatio: '-',
outboundBytesRateChainRatio: '-'
}
const prev = prevData.find(p => p.appSubcategory === d.appSubcategory)
if (prev) {
result.bytesRateChainRatio = getChainRatio(d.totalBitsRate, prev.totalBitsRate)
result.inboundBytesRateChainRatio = getChainRatio(d.inboundBitsRate, prev.inboundBitsRate)
result.outboundBytesRateChainRatio = getChainRatio(d.outboundBitsRate, prev.outboundBitsRate)
}
return result
})
// 计算分数
const tcpRequest = get(api.npm.overview.appTcpSessionDelay, params)
const httpRequest = get(api.npm.overview.appHttpResponseDelay, params)
const sslRequest = get(api.npm.overview.appSslConDelay, params)
const tcpLostRequest = get(api.npm.overview.appTcpLostlenPercent, params)
const packetRetransRequest = get(api.npm.overview.appPacketRetransPercent, params)
Promise.all([tcpRequest, httpRequest, sslRequest, tcpLostRequest, packetRetransRequest]).then(res => {
const keyPre = ['tcp', 'http', 'ssl', 'tcpLost', 'packetRetrans']
res.forEach((r, i) => {
if (r.code === 200) {
tableData.forEach(t => {
let score = 0
const find = r.data.result.find(d => d.appSubcategory === t.appSubcategory)
if (find) {
score = computeScore(find, i)
const prev = prevData.find(p => p.appSubcategory === d.appSubcategory)
if (prev) {
result.bytesRateChainRatio = getChainRatio(d.totalBitsRate, prev.totalBitsRate)
result.inboundBytesRateChainRatio = getChainRatio(d.inboundBitsRate, prev.inboundBitsRate)
result.outboundBytesRateChainRatio = getChainRatio(d.outboundBitsRate, prev.outboundBitsRate)
}
return result
})
// 计算分数
const tcpRequest = get(api.npm.overview.appTcpSessionDelay, params)
const httpRequest = get(api.npm.overview.appHttpResponseDelay, params)
const sslRequest = get(api.npm.overview.appSslConDelay, params)
const tcpLostRequest = get(api.npm.overview.appTcpLostlenPercent, params)
const packetRetransRequest = get(api.npm.overview.appPacketRetransPercent, params)
Promise.all([tcpRequest, httpRequest, sslRequest, tcpLostRequest, packetRetransRequest]).then(res => {
const keyPre = ['tcp', 'http', 'ssl', 'tcpLost', 'packetRetrans']
let msg = ''
res.forEach((r, i) => {
if (r.code === 200) {
tableData.forEach(t => {
const find = r.data.result.find(d => d.appSubcategory === t.appSubcategory)
t[keyPre[i] + 'Score'] = find
})
} else {
this.showError = true
// todo 此处目前返回字段为msg后续字段会修改为message
msg = msg + ',' + r.message
if (msg.indexOf(',') === 0) {
msg = msg.substring(1, msg.length)
}
t[keyPre[i] + 'Score'] = score
})
} else {
tableData.forEach(t => {
t[keyPre[i] + 'Score'] = 0
})
}
if (msg.lastIndexOf(',') === msg.length - 1) {
msg = msg.substring(0, msg.length - 1)
}
this.errorMsg = msg
}
})
tableData.forEach(t => {
const data = {
establishLatencyMs: t.tcpScore ? t.tcpScore.establishLatencyMs : null,
httpResponseLatency: t.httpScore ? t.httpScore.httpResponseLatency : null,
sslConLatency: t.sslScore ? t.sslScore.sslConLatency : null,
tcpLostlenPercent: t.tcpLostScore ? t.tcpLostScore.tcpLostlenPercent : null,
pktRetransPercent: t.packetRetransScore ? t.packetRetransScore.pktRetransPercent : null
}
t.score = computeScore(data)
})
this.tableData = tableData
}).finally(() => {
this.toggleLoading(false)
})
tableData.forEach(t => {
t.score = Math.ceil((t.tcpScore + t.httpScore + t.sslScore + t.tcpLostScore + t.packetRetransScore) * 6)
if (t.score > 6) {
t.score = 6
}
})
this.tableData = tableData
}).finally(() => {
} else {
this.tableData = []
this.isNoData = true
this.toggleLoading(false)
})
}
} else {
this.tableData = []
this.isNoData = true
this.toggleLoading(false)
this.showError = true
this.errorMsg = ''
let msg = res[0].message + ', ' + res[1].message
if (msg.indexOf(',') === 0) {
msg = msg.substring(1, msg.length)
}
if (msg.lastIndexOf(',') === msg.length - 1) {
msg = msg.substring(0, msg.length - 1)
}
this.errorMsg = msg
}
}).catch(e => {
console.error(e)
this.toggleLoading(false)
this.showError = true
this.errorMsg = ''
this.errorMsg = e.message
})
},
getUrlParam (param, defaultValue, isNumber) {

View File

@@ -1,40 +1,41 @@
<template>
<div class="npm-app-event">
<div class="metric-select" >
<el-select v-model="metric"
class="option__select select-column"
popper-class="option-popper common-select"
:popper-append-to-body="false"
key="tabMetric"
@change="changeMetric"
size="mini"
width="100">
<div class="metric-select">
<el-select
v-model="metric"
class="option__select select-column"
popper-class="option-popper common-select"
:popper-append-to-body="false"
key="tabMetric"
@change="changeMetric"
size="mini"
width="100">
<el-option
v-for="item in options"
:key="item.label"
:label="item.label"
:value="item.value"
v-for="item in options"
:key="item.label"
:label="item.label"
:value="item.value"
/>
</el-select>
<span>{{$t('network.metric')}}</span>
<span>{{ $t('network.metric') }}</span>
</div>
<el-table
:id="`tabTable_${index}`"
:ref="`dataTable_${index}`"
:data="tableData"
class="npm-app-event-table"
height="100%"
empty-text=""
:id="`tabTable_${index}`"
:ref="`dataTable_${index}`"
:data="tableData"
class="npm-app-event-table"
height="100%"
empty-text=""
>
<template v-for="(item, index) in customTableTitles" :key="index">
<el-table-column class="data-column" :min-width="columnWidth(index)">
<template #header>
<span class="data-column__span">{{$t(item.label)}}</span>
<span class="data-column__span">{{ $t(item.label) }}</span>
</template>
<template #default="scope" :column="item">
<template #default="scope" :column="item">
<div class="data-app-event-table">
<template v-if="item.prop === 'domain' ||item.prop === 'appName' ||item.prop === 'serverIp' ">
<span class="data-applications">{{$t(scope.row[item.prop])}}</span>
<span class="data-applications">{{ $t(scope.row[item.prop]) }}</span>
</template>
<template v-else-if="item.prop === 'eventSeverity'">
<template v-if="scope.row[item.prop]==='critical'">
@@ -56,14 +57,14 @@
<div v-for="item in 1" class="red-dot"></div>
<div v-for="item in 4" class="grey-dot"></div>
</template>
<span class="data-severity" >{{$t(scope.row[item.prop])}}</span>
<span class="data-severity">{{ $t(scope.row[item.prop]) }}</span>
</template>
<template v-else-if="item.prop === 'eventType'">
<!-- <span class="data-eventType" v-for="type in scope.row[item.prop]">{{type}}</span>-->
<span class="data-eventType" >{{$t(scope.row[item.prop])}}</span>
<!-- <span class="data-eventType" v-for="type in scope.row[item.prop]">{{type}}</span>-->
<span class="data-eventType">{{ $t(scope.row[item.prop]) }}</span>
</template>
<template v-else-if="item.prop === 'count'">
<span class="data-eventCount">{{scope.row[item.prop]}}</span>
<span class="data-eventCount">{{ scope.row[item.prop] }}</span>
</template>
<span v-else>-</span>
</div>
@@ -76,20 +77,23 @@
</div>
</template>
</el-table>
<div class="table-error">
<chart-error v-if="showError" :content="errorMsg"></chart-error>
</div>
</div>
</template>
<script>
import { unitTypes, npmCategoryInfoMapping } from '@/utils/constants'
import unitConvert from '@/utils/unit-convert'
import { api } from '@/utils/api'
import { getSecond } from '@/utils/date-util'
import { get } from '@/utils/http'
import { getChainRatio, computeScore } from '@/utils/tools'
import chartMixin from '@/views/charts2/chart-mixin'
import ChartError from '@/components/common/Error'
export default {
name: 'NpmAppEventTable',
components: { ChartError },
data () {
return {
metric: 'appLabel',
@@ -115,18 +119,32 @@ export default {
dotList: ['grey-dot', 'grey-dot', 'grey-dot', 'grey-dot', 'grey-dot'],
tableData: [],
customTableTitles: [
{ label: 'network.applications', prop: 'serverIp' },
{ label: 'network.severity', prop: 'eventSeverity' },
{ label: 'network.eventType', prop: 'eventType' },
{ label: 'network.eventCount', prop: 'count' }
{
label: 'network.applications',
prop: 'serverIp'
},
{
label: 'network.severity',
prop: 'eventSeverity'
},
{
label: 'network.eventType',
prop: 'eventType'
},
{
label: 'network.eventCount',
prop: 'count'
}
],
isNoData: false
isNoData: false,
showError: false,
errorMsg: ''
}
},
mixins: [chartMixin],
watch: {
timeFilter: {
handler (n) {
handler () {
this.init()
}
}
@@ -149,13 +167,20 @@ export default {
}
get(api.npm.events.dimensionEvents, params).then(res => {
if (res.code === 200) {
this.showError = false
if (!res.data.result || res.data.result.length === 0) {
this.isNoData = true
}
this.tableData = res.data.result
} else {
this.isNoData = true
this.isNoData = false
this.showError = true
this.errorMsg = res.message
}
}).catch((e) => {
this.isNoData = false
this.showError = true
this.errorMsg = e.message
}).finally(() => {
this.toggleLoading(false)
})
@@ -172,9 +197,7 @@ export default {
return '15%'
}
}
},
computed: {
}
computed: {}
}
</script>

View File

@@ -1,6 +1,9 @@
<template>
<div class="npm-event">
<div class="npm-event-title">{{$t('network.eventByType')}}</div>
<div class="npm-event-title">
{{$t('network.eventByType')}}
<chart-error tooltip v-if="showError" :content="errorMsg"></chart-error>
</div>
<div class="npm-event-pie">
<chart-no-data v-if="isNoData"></chart-no-data>
<div class="npm-event-pies" v-else>
@@ -35,6 +38,7 @@ import { pieChartOption3 } from '@/views/charts2/charts/options/echartOption'
import { getSecond } from '@/utils/date-util'
import ChartNoData from '@/views/charts/charts/ChartNoData'
import chartMixin from '@/views/charts2/chart-mixin'
import ChartError from '@/components/common/Error'
export default {
name: 'NpmEventsByType',
@@ -42,6 +46,7 @@ export default {
type: String
},
components: {
ChartError,
ChartNoData
},
mixins: [chartMixin],
@@ -54,7 +59,9 @@ export default {
return {
chartData: [],
timer: null,
isNoData: false
isNoData: false,
showError: false,
errorMsg: ''
}
},
watch: {
@@ -104,6 +111,7 @@ export default {
this.toggleLoading(true)
get(api.npm.events.recentEvents, params).then(res => {
if (res.code === 200) {
this.showError = false
this.isNoData = res.data.result.length === 0
const arrData = []
res.data.result.forEach(t => {
@@ -121,8 +129,14 @@ export default {
this.init()
})
} else {
this.isNoData = true
this.isNoData = false
this.showError = true
this.errorMsg = res.message
}
}).catch((e) => {
this.isNoData = false
this.showError = true
this.errorMsg = e.message
}).finally(() => {
this.toggleLoading(false)
})
@@ -140,6 +154,8 @@ export default {
beforeUnmount () {
clearTimeout(this.timer)
window.removeEventListener('resize', this.resize)
this.myChart = null
this.chartOption = null
}
}
</script>

View File

@@ -5,7 +5,8 @@
<div class="npm-header-body-severity-icon" :class="item.eventSeverity"></div>
<div class="npm-header-body-severity-value">{{item.eventSeverity}}</div>
</div>
<div class="npm-header-body-total">{{item.count}}</div>
<chart-error v-if="showError" tooltip :content="errorMsg" />
<div v-else class="npm-header-body-total">{{item.count}}</div>
</div>
</div>
</template>
@@ -15,8 +16,10 @@ import { getSecond } from '@/utils/date-util'
import { get } from '@/utils/http'
import { api } from '@/utils/api'
import chartMixin from '@/views/charts2/chart-mixin'
import ChartError from '@/components/common/Error'
export default {
name: 'NpmEventsHeader',
components: { ChartError },
mixins: [chartMixin],
data () {
return {
@@ -47,12 +50,14 @@ export default {
index: 4
}
],
type: 'severity'
type: 'severity',
showError: false,
errorMsg: ''
}
},
watch: {
timeFilter: {
handler (n) {
handler () {
this.recentEventsListData()
}
}
@@ -67,6 +72,7 @@ export default {
this.toggleLoading(true)
get(api.npm.events.list, params).then(res => {
if (res.code === 200) {
this.showError = false
res.data.result.forEach(t => {
this.chartData.forEach(d => {
if (d.eventSeverity === t.eventSeverity) {
@@ -74,7 +80,13 @@ export default {
}
})
})
} else {
this.showError = true
this.errorMsg = res.message
}
}).catch(error => {
this.showError = true
this.errorMsg = error.message
}).finally(() => {
this.toggleLoading(false)
})

View File

@@ -1,6 +1,9 @@
<template>
<div class="cn-chart__map-title" v-if="tabIndex == 1">{{$t('npm.clientLocation')}}</div>
<div class="cn-chart__map" :class="{'cn-chart__map-drilldown': tabIndex == 1}">
<div class="cn-chart__map-title" v-if="queryCondition">
{{$t('npm.clientLocation')}}
<chart-error v-if="showError" width="300" tooltip :content="errorMsg" />
</div>
<div class="cn-chart__map" :class="{'cn-chart__map-drilldown': queryCondition}">
<div class="map-canvas" id="npmDrillDownMap"></div>
</div>
</template>
@@ -10,20 +13,24 @@ import { ref, shallowRef } from 'vue'
import * as am4Core from '@amcharts/amcharts4/core'
import * as am4Maps from '@amcharts/amcharts4/maps'
import { computeScore, getGeoData } from '@/utils/tools'
import { storageKey, unitTypes, countryNameIdMapping, curTabState } from '@/utils/constants'
import { storageKey, unitTypes, curTabState } from '@/utils/constants'
import { valueToRangeValue } from '@/utils/unit-convert'
import { getSecond } from '@/utils/date-util'
import { api, getData } from '@/utils/api'
import { get } from '@/utils/http'
import chartMixin from '@/views/charts2/chart-mixin'
import { useRoute } from 'vue-router'
import ChartError from '@/components/common/Error'
export default {
name: 'NpmIpMap',
components: { ChartError },
setup () {
const { query } = useRoute()
const tabIndex = ref(query.tabIndex || '')
const queryCondition = ref(query.queryCondition || '')
return {
tabIndex
tabIndex,
queryCondition
}
},
data () {
@@ -35,7 +42,9 @@ export default {
countryImageSeries: null,
// Server | Client
trafficDirection: 'Server',
curTabState: curTabState
curTabState: curTabState,
showError: false,
errorMsg: ''
}
},
mixins: [chartMixin],
@@ -88,52 +97,64 @@ export default {
// typeVal: this.$store.getters.getBreadcrumbColumnValue
typeVal: this.getUrlParam(this.curTabState.fourthMenu, '')
}
if (params.type === 'serverIp' || params.type === 'clientIp') params.type = 'ip'
getData(api.npm.overview.map, params).then(res => {
const subParams = {
...params,
params: res.map(r => r.country).join(',')
this.showError = false
if (res && res.length > 0) {
const subParams = {
...params,
params: res.map(r => `'${r.country}'`).join(',')
}
// 计算分数
const tcpRequest = get(api.npm.overview.mapTcp, subParams)
const httpRequest = get(api.npm.overview.mapHttp, subParams)
const sslRequest = get(api.npm.overview.mapSsl, subParams)
const tcpLostRequest = get(api.npm.overview.mapPacketLoss, subParams)
const packetRetransRequest = get(api.npm.overview.mapPacketRetrans, subParams)
Promise.all([tcpRequest, httpRequest, sslRequest, tcpLostRequest, packetRetransRequest]).then(res2 => {
const keyPre = ['tcp', 'http', 'ssl', 'tcpLost', 'packetRetrans']
const mapData = res
res2.forEach((r, i) => {
if (r.code === 200) {
mapData.forEach(t => {
const find = r.data.result.find(d => d.country === t.country)
t[keyPre[i] + 'Score'] = find
})
} else {
this.showError = true
this.errorMsg = r.message
}
})
mapData.forEach(t => {
const data = {
establishLatencyMs: t.tcpScore ? t.tcpScore.establishLatencyMs : null,
httpResponseLatency: t.httpScore ? t.httpScore.httpResponseLatency : null,
sslConLatency: t.sslScore ? t.sslScore.sslConLatency : null,
tcpLostlenPercent: t.tcpLostScore ? t.tcpLostScore.tcpLostlenPercent : null,
pktRetransPercent: t.packetRetransScore ? t.packetRetransScore.pktRetransPercent : null
}
t.score = computeScore(data)
if (t.score === '-') {
t.score = ''
}
})
this.loadMarkerData(imageSeries, mapData)
})
}
// 计算分数
const tcpRequest = get(api.npm.overview.mapTcp, subParams)
const httpRequest = get(api.npm.overview.mapHttp, subParams)
const sslRequest = get(api.npm.overview.mapSsl, subParams)
const tcpLostRequest = get(api.npm.overview.mapPacketLoss, subParams)
const packetRetransRequest = get(api.npm.overview.mapPacketRetrans, subParams)
Promise.all([tcpRequest, httpRequest, sslRequest, tcpLostRequest, packetRetransRequest]).then(res2 => {
const keyPre = ['tcp', 'http', 'ssl', 'tcpLost', 'packetRetrans']
const mapData = res
res2.forEach((r, i) => {
if (r.code === 200) {
mapData.forEach(t => {
let score = 0
const find = r.data.result.find(d => d.country === t.country)
if (find) {
score = computeScore(find, i)
}
t[keyPre[i] + 'Score'] = score
})
} else {
mapData.forEach(t => {
t[keyPre[i] + 'Score'] = 0
})
}
})
mapData.forEach(t => {
t.score = Math.ceil((t.tcpScore + t.httpScore + t.sslScore + t.tcpLostScore + t.packetRetransScore) * 6)
if (t.score > 6) {
t.score = 6
}
})
this.loadMarkerData(imageSeries, mapData)
})
}).catch(e => {
this.showError = true
this.errorMsg = e.message
}).finally(() => {
this.toggleLoading(false)
})
} catch (e) {
console.error(e)
this.showError = true
this.errorMsg = e.message
}
},
loadMarkerData (imageSeries, data) {
data = data.filter(d => d.score || d.score === 0)
imageSeries.data = data.map(r => ({
score: r.score,
name: r.province || r.country,

View File

@@ -3,7 +3,10 @@
<chart-no-data v-if="isNoData"></chart-no-data>
<template v-if="chartData.id === 11">
<div class="npm-line-header">
<div class="npm-line-header-title">{{$t(chartData.i18n) || chartData.name}}</div>
<div class="npm-line-header-title">
{{$t(chartData.i18n) || chartData.name}}
<chart-error v-if="showError" tooltip :content="errorMsg"></chart-error>
</div>
<div class="npm-line-header-rights" v-if="chartData.params && chartData.params.showLegend && !isNoData">
<div class="npm-line-header-right" :class="{'active': item.show}" v-for="(item, index) in chartOptionLineData" :key="index" @click="highlightEvent(item)">
<div class="npm-line-header-icon" :class="'icon' + index"></div>
@@ -14,23 +17,38 @@
<div v-show="!isNoData" class="chart-drawing" :id="`chart${chartData.name}`"></div>
</template>
<template v-else-if="chartData.id === 12">
<div class="npm-line-title">{{$t(chartData.i18n) || chartData.name}}</div>
<div class="npm-line-title">
{{$t(chartData.i18n) || chartData.name}}(ms)
<chart-error v-if="showError" tooltip :content="errorMsg"></chart-error>
</div>
<div v-show="!isNoData" class="chart-drawing" :id="`chart${chartData.name}`"></div>
</template>
<template v-else-if="chartData.id === 13">
<div class="npm-line-title">{{$t(chartData.i18n) || chartData.name}}</div>
<div class="npm-line-title">
{{$t(chartData.i18n) || chartData.name}}(ms)
<chart-error v-if="showError" tooltip :content="errorMsg"></chart-error>
</div>
<div v-show="!isNoData" class="chart-drawing" :id="`chart${chartData.name}`"></div>
</template>
<template v-else-if="chartData.id === 14">
<div class="npm-line-title">{{$t(chartData.i18n) || chartData.name}}</div>
<div class="npm-line-title">
{{$t(chartData.i18n) || chartData.name}}(ms)
<chart-error v-if="showError" tooltip :content="errorMsg"></chart-error>
</div>
<div v-show="!isNoData" class="chart-drawing" :id="`chart${chartData.name}`"></div>
</template>
<template v-else-if="chartData.id === 15">
<div class="npm-line-title">{{$t(chartData.i18n) || chartData.name}}</div>
<div class="npm-line-title">
{{$t(chartData.i18n) || chartData.name}}(%)
<chart-error v-if="showError" tooltip :content="errorMsg"></chart-error>
</div>
<div v-show="!isNoData" class="chart-drawing" :id="`chart${chartData.name}`"></div>
</template>
<template v-else-if="chartData.id === 16">
<div class="npm-line-title">{{$t(chartData.i18n) || chartData.name}}</div>
<div class="npm-line-title">
{{$t(chartData.i18n) || chartData.name}}(%)
<chart-error v-if="showError" tooltip :content="errorMsg"></chart-error>
</div>
<div v-show="!isNoData" class="chart-drawing" :id="`chart${chartData.name}`"></div>
</template>
</div>
@@ -47,10 +65,13 @@ import { get } from '@/utils/http'
import { api } from '@/utils/api'
import ChartNoData from '@/views/charts/charts/ChartNoData'
import chartMixin from '@/views/charts2/chart-mixin'
import unitConvert from '@/utils/unit-convert'
import ChartError from '@/components/common/Error'
export default {
name: 'NpmLine',
components: {
ChartError,
ChartNoData
},
mixins: [chartMixin],
@@ -75,8 +96,10 @@ export default {
timer: null,
myChartArray: [],
side: this.$store.state.panel.npmLocationSide,
country: this.$store.state.panel.npmLocationCountry
country: this.$store.state.panel.npmLocationCountry,
// province: '',
showError: false,
errorMsg: ''
}
},
watch: {
@@ -91,24 +114,29 @@ export default {
deep: true,
handler (n) {
this.country = n
this.init()
this.init(n)
}
},
timeFilter: {
handler (n) {
handler () {
this.init()
}
}
},
methods: {
init () {
init (n) {
const params = {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
side: this.side,
country: this.country
side: this.side
// country: this.country
// province: this.province
}
if (n) {
params.country = n
} else {
params.country = ''
}
this.toggleLoading(true)
let url
if (this.chart.params) {
@@ -128,23 +156,34 @@ export default {
if (url) {
get(url, params).then(res => {
if (res.code === 200) {
this.showError = false
this.isNoData = res.data.result.length === 0
if (this.chart.params.index === 0) {
res.data.result.forEach((t, i) => {
if (t.type === 'totalBytesRate') {
this.chartOptionLineData[i].values = t.values
} else if (t.type === 'inboundBytesRate') {
this.chartOptionLineData[i].values = t.values
} else if (t.type === 'outboundBytesRate') {
this.chartOptionLineData[i].values = t.values
}
})
const result = this.chartOptionLineData.filter(t => this.chartData.params.color.indexOf(t.color) > -1)
this.echartsInit(result, this.chartData, this.chartData.params.unitType)
} else {
this.echartsInit(res.data.result, this.chartData, this.chartData.params.unitType)
if (!this.isNoData) {
if (this.chart.params.index === 0) {
res.data.result.forEach((t, i) => {
if (t.type === 'totalBitsRate') {
this.chartOptionLineData[i].values = t.values
} else if (t.type === 'inboundBitsRate') {
this.chartOptionLineData[i].values = t.values
} else if (t.type === 'outboundBitsRate') {
this.chartOptionLineData[i].values = t.values
}
})
const result = this.chartOptionLineData.filter(t => this.chartData.params.color.indexOf(t.color) > -1)
this.echartsInit(result, this.chartData, this.chartData.params.unitType)
} else {
this.echartsInit(res.data.result, this.chartData, this.chartData.params.unitType)
}
}
} else {
this.isNoData = false
this.showError = true
this.errorMsg = res.message
}
}).catch((e) => {
this.isNoData = false
this.showError = true
this.errorMsg = e.message
}).finally(() => {
this.toggleLoading(false)
})
@@ -161,11 +200,16 @@ export default {
this.myChart = echarts.init(dom)
}
this.chartOption = npmLineChartOption
const seriesTemplate = this.chartOption.series[0]
this.chartOption.color = this.chartData.params.color
this.chartOption.series = data.map((t, i) => {
return {
...seriesTemplate,
type: 'line',
symbol: 'circle',
smooth: true,
showSymbol: false,
emphasis: {
focus: 'series'
},
name: t.legend ? t.legend : this.$t(chartData.i18n) || chartData.name,
stack: this.chartData.params.isStack ? 'network.total' : '',
lineStyle: {
@@ -177,9 +221,24 @@ export default {
data: t.values.map((v) => [Number(v[0]) * 1000, Number(v[1]), type])
}
})
this.chartOption.yAxis[0].axisLabel.formatter = (value) => {
if (type === 'percent') {
return unitConvert(value, type)[0]
} else {
return unitConvert(value, 'number').join('')
}
}
this.chartOption.tooltip.formatter = (params) => {
params.forEach(t => {
t.seriesName = this.$t(t.seriesName)
this.chartOptionLineData.forEach(e => {
if (this.$t(e.legend) === t.seriesName) {
t.borderColor = e.color
}
if (this.$t(chartData.i18n) === t.seriesName) {
t.borderColor = t.color
}
})
})
return stackedLineTooltipFormatter(params)
}
@@ -272,6 +331,7 @@ export default {
beforeUnmount () {
clearTimeout(this.timer)
window.removeEventListener('resize', this.resize)
this.myChart = null
}
}
</script>

View File

@@ -1,6 +1,8 @@
<template>
<div class="cn-chart__map">
<div class="map-canvas" id="npmMap"></div>
<chart-error v-if="showError" max-width="900" :content="errorMsg"></chart-error>
<div class="map-filter">
<el-select
size="mini"
@@ -55,9 +57,11 @@ import { getSecond } from '@/utils/date-util'
import { api, getData } from '@/utils/api'
import { get } from '@/utils/http'
import chartMixin from '@/views/charts2/chart-mixin'
import { Rectangle3D } from '@amcharts/amcharts4/.internal/core/elements/3d/Rectangle3D'
// import { Rectangle3D } from '@amcharts/amcharts4/.internal/core/elements/3d/Rectangle3D'
import ChartError from '@/components/common/Error'
export default {
name: 'NpmMap',
components: { ChartError },
data () {
return {
locationOptions,
@@ -68,7 +72,9 @@ export default {
countryImageSeries: null,
// Server | Client
trafficDirection: 'Server',
location: ''
location: '',
showError: false,
errorMsg: ''
}
},
mixins: [chartMixin],
@@ -118,6 +124,7 @@ export default {
getData(api.npm.location.map, params).then(res => {
if (res.length > 0) {
// 计算分数
params.country = params.country ? `'${params.country}'` : ''
const tcpRequest = get(api.npm.location.mapTcp, params)
const httpRequest = get(api.npm.location.mapHttp, params)
const sslRequest = get(api.npm.location.mapSsl, params)
@@ -126,43 +133,63 @@ export default {
Promise.all([tcpRequest, httpRequest, sslRequest, tcpLostRequest, packetRetransRequest]).then(res2 => {
const keyPre = ['tcp', 'http', 'ssl', 'tcpLost', 'packetRetrans']
const mapData = res
let msg = ''
res2.forEach((r, i) => {
if (r.code === 200) {
mapData.forEach(t => {
let score = 0
const find = r.data.result.find(d => d.country === t.country)
if (find) {
score = computeScore(find, i)
}
t[keyPre[i] + 'Score'] = score
t[keyPre[i] + 'Score'] = find
})
} else {
mapData.forEach(t => {
t[keyPre[i] + 'Score'] = 0
})
this.showError = true
// todo 此处目前返回字段为msg后续字段会修改为message
msg = msg + ',' + r.message
if (msg.indexOf(',') === 0) {
msg = msg.substring(1, msg.length)
}
if (msg.lastIndexOf(',') === msg.length - 1) {
msg = msg.substring(0, msg.length - 1)
}
this.errorMsg = msg
}
})
mapData.forEach(t => {
t.score = Math.ceil((t.tcpScore + t.httpScore + t.sslScore + t.tcpLostScore + t.packetRetransScore) * 6)
if (t.score > 6) {
t.score = 6
const data = {
establishLatencyMs: t.tcpScore ? t.tcpScore.establishLatencyMs : null,
httpResponseLatency: t.httpScore ? t.httpScore.httpResponseLatency : null,
sslConLatency: t.sslScore ? t.sslScore.sslConLatency : null,
tcpLostlenPercent: t.tcpLostScore ? t.tcpLostScore.tcpLostlenPercent : null,
pktRetransPercent: t.packetRetransScore ? t.packetRetransScore.pktRetransPercent : null
}
t.score = computeScore(data)
if (t.score === '-') {
t.score = ''
}
})
this.loadMarkerData(imageSeries, mapData)
}).catch((e) => {
this.showError = true
this.errorMsg = e.message
})
} else {
imageSeries.data = [{}]
}
}).catch((e) => {
this.showError = true
this.errorMsg = e.message
}).finally(() => {
this.toggleLoading(false)
})
} catch (e) {
this.showError = true
// todo 此处错误信息有待考证,后续可能会改动
this.errorMsg = e
console.error(e)
}
},
loadMarkerData (imageSeries, data) {
imageSeries.data = data.map(r => ({
score: r.score,
score: r.score || '&ndash;',
name: r.province || r.country,
throughput: valueToRangeValue(r.throughBitsRate, unitTypes.bps).join(' '),
id: r.serverId,
@@ -304,7 +331,7 @@ export default {
}
},
timeFilter: {
handler (n) {
handler () {
if (this.location) {
this.loadAm4ChartMap(this.countrySeries, this.countryImageSeries)
} else {

View File

@@ -1,6 +1,7 @@
<template>
<div class="npm-network-quantity">
<single-value
v-if="npmNetworkData.length>0"
:npm-network-name="npmNetworkName"
:npm-network-data="npmNetworkData"
></single-value>
@@ -14,7 +15,7 @@ import { getSecond } from '@/utils/date-util'
import { api } from '@/utils/api'
import chartMixin from '@/views/charts2/chart-mixin'
import _ from 'lodash'
import { computeScore, getChainRatio } from '@/utils/tools'
import { getChainRatio } from '@/utils/tools'
import { useRoute } from 'vue-router'
import { ref } from 'vue'
export default {
@@ -25,9 +26,15 @@ export default {
const { query } = useRoute()
const queryCondition = ref(query.queryCondition || '')
const dimensionType = ref(query.dimensionType || '')
const tabIndex = ref(query.tabIndex || 0)
const tabOperationType = ref(query.tabOperationType)
const networkOverviewBeforeTab = ref(query.networkOverviewBeforeTab || '')
return {
queryCondition,
dimensionType
dimensionType,
tabIndex,
tabOperationType,
networkOverviewBeforeTab
}
},
data () {
@@ -43,7 +50,9 @@ export default {
npmNetworkLastCycleData: [],
npmNetworkData: [],
side: '',
chartData: {}
chartData: {},
timer1: null,
timer2: null
}
},
watch: {
@@ -57,28 +66,36 @@ export default {
},
methods: {
npmNetworkCycleQuery () {
// const conditionStr = this.$route.query.queryCondition ? this.$route.query.queryCondition : ''
let condition = ''
let url = ''
if (this.queryCondition.indexOf(' OR ') > -1) {
condition = this.queryCondition.split(/["|'](.*?)["|']/)
} else {
condition = this.queryCondition
}
// const type = this.$store.getters.getDimensionType
// const type = this.$route.query.dimensionType ? this.$route.query.dimensionType : ''
const type = this.dimensionType
const type = this.dimensionType || this.networkOverviewBeforeTab
const params = {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
cycle: 0
}
if (this.chartData.id === 23) {
if (this.tabIndex == 0) {
this.side = 'client'
} else if (this.chartData.id === 26) {
} else if (this.tabIndex == 1) {
this.side = 'server'
}
if (condition && (typeof condition !== 'object') && type) {
params.q = condition
if (type === 'clientIp') {
params.q = `ip='${condition.split(/'(.*?)'/)[1]}' and side='client'`
} else if (type === 'serverIp') {
params.q = `ip='${condition.split(/'(.*?)'/)[1]}' and side='server'`
} else if (type === 'clientCity') {
params.q = `client_city='${condition.split(/'(.*?)'/)[1]}'`
} else if (type === 'serverCity') {
params.q = `server_city='${condition.split(/'(.*?)'/)[1]}'`
} else {
params.q = condition
}
params.type = type
} else if (condition.length > 1 && type && type === 'ip') {
params.q = `${type}='${condition[1]}' and side='${this.side}'`
@@ -95,46 +112,19 @@ export default {
params.type = type
}
}
if (type && condition) {
if (parseFloat(this.tabOperationType) === 3) {
url = api.npm.overview.allNetworkAnalysis
} else {
url = api.npm.overview.networkAnalysis
}
if ((type && condition) || type) {
params.type = params.type || type
this.toggleLoading(true)
get(api.npm.overview.networkAnalysis, params).then(res => {
const keyPre = ['tcp', 'http', 'ssl', 'tcpLost', 'packetRetrans']
const scoreInfo = {}
let index = 0
get(url, params).then(res => {
if (res.code === 200) {
if (res.data.result.establishLatencyMsAvg || res.data.result.establishLatencyMsAvg === 0) {
res.data.result.establishLatencyMs = res.data.result.establishLatencyMsAvg
index = 0
scoreInfo[keyPre[index] + 'Score'] = computeScore(res.data.result, index)
}
if (res.data.result.httpResponseLatencyAvg || res.data.result.httpResponseLatencyAvg === 0) {
res.data.result.httpResponseLatency = res.data.result.httpResponseLatencyAvg
index = 1
scoreInfo[keyPre[index] + 'Score'] = computeScore(res.data.result, index)
}
if (res.data.result.tcpLostlenPercentAvg || res.data.result.tcpLostlenPercentAvg === 0) {
res.data.result.tcpLostlenPercent = res.data.result.tcpLostlenPercentAvg
index = 3
scoreInfo[keyPre[index] + 'Score'] = computeScore(res.data.result, index)
}
if (res.data.result.pktRetransPercentAvg || res.data.result.pktRetransPercentAvg === 0) {
res.data.result.pktRetransPercent = res.data.result.pktRetransPercentAvg
index = 4
scoreInfo[keyPre[index] + 'Score'] = computeScore(res.data.result, index)
}
if (res.data.result.sslConLatencyAvg || res.data.result.sslConLatencyAvg === 0) {
res.data.result.sslConLatency = res.data.result.sslConLatencyAvg
index = 2
scoreInfo[keyPre[index] + 'Score'] = computeScore(res.data.result, index)
}
this.npmNetworkCycleData = res.data.result
this.npmNetworkLastCycleQuery()
}
scoreInfo.score = Math.ceil((scoreInfo.tcpScore + scoreInfo.httpScore + scoreInfo.sslScore + scoreInfo.tcpLostScore + scoreInfo.packetRetransScore) * 6)
if (scoreInfo.score > 6) {
scoreInfo.score = 6
}
this.$store.commit('setNpmThirdLevelMenuScore', scoreInfo.score)
this.npmNetworkLastCycleQuery(url, params)
}).catch(e => {
this.toggleLoading(false)
})
@@ -147,96 +137,62 @@ export default {
this.toggleLoading(true)
Promise.all([tcp, http, ssl, tcpPercent, packetPercent]).then(res => {
this.npmNetworkCycleData = []
const keyPre = ['tcp', 'http', 'ssl', 'tcpLost', 'packetRetrans']
const scoreInfo = {}
let index = 0
res.forEach(t => {
if (t.code === 200) {
if (t.data.result.establishLatencyMsAvg || t.data.result.establishLatencyMsAvg === 0) {
t.data.result.establishLatencyMs = t.data.result.establishLatencyMsAvg
index = 0
}
if (t.data.result.httpResponseLatencyAvg || t.data.result.httpResponseLatencyAvg === 0) {
t.data.result.httpResponseLatency = t.data.result.httpResponseLatencyAvg
index = 1
}
if (t.data.result.tcpLostlenPercentAvg || t.data.result.tcpLostlenPercentAvg === 0) {
t.data.result.tcpLostlenPercent = t.data.result.tcpLostlenPercentAvg
index = 3
}
if (t.data.result.pktRetransPercentAvg || t.data.result.pktRetransPercentAvg === 0) {
t.data.result.pktRetransPercent = t.data.result.pktRetransPercentAvg
index = 4
}
if (t.data.result.sslConLatencyAvg || t.data.result.sslConLatencyAvg === 0) {
t.data.result.sslConLatency = t.data.result.sslConLatencyAvg
index = 2
}
scoreInfo[keyPre[index] + 'Score'] = computeScore(t.data.result, index)
this.npmNetworkCycleData.push(t.data.result)
} else {
this.npmNetworkCycleData.push(t)
}
})
scoreInfo.score = Math.ceil((scoreInfo.tcpScore + scoreInfo.httpScore + scoreInfo.sslScore + scoreInfo.tcpLostScore + scoreInfo.packetRetransScore) * 6)
if (scoreInfo.score > 6) {
scoreInfo.score = 6
}
this.$store.commit('setNpmThirdLevelMenuScore', scoreInfo.score)
this.npmNetworkLastCycleQuery()
}).catch(e => {
this.toggleLoading(false)
// 此时e为数组
if (e instanceof Array) {
this.npmNetworkCycleData = []
e.forEach(t => {
this.npmNetworkCycleData.push(t)
})
this.npmNetworkLastCycleQuery()
}
})
}
},
npmNetworkLastCycleQuery () {
let condition = ''
if (this.queryCondition.indexOf(' OR ') > -1) {
condition = this.queryCondition.split(/["|'](.*?)["|']/)
} else {
condition = this.queryCondition
}
// const type = this.$store.getters.getDimensionType
const type = this.dimensionType
npmNetworkLastCycleQuery (url, param) {
const params = {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
cycle: 1
}
if (this.chartData.id === 23) {
this.side = 'client'
} else if (this.chartData.id === 26) {
this.side = 'server'
if (param && param.type && param.q) {
params.type = param.type
params.q = param.q
}
if (condition && (typeof condition !== 'object') && type) {
params.q = condition
params.type = type
} else if (condition.length > 1 && type && type === 'ip') {
params.q = `${type}='${condition[1]}' and side='${this.side}'`
params.type = type
} else if (condition.length > 1 && type && type !== 'ip') {
if (type === 'country' || type === 'asn' || type === 'province' || type === 'city' || type === 'isp') {
params.q = `${type}='${condition[1]}'`
params.type = type
} else if (type === 'idcRenter') {
params.q = `idc_renter='${condition[1]}'`
params.type = type
} else {
params.q = `${condition[0]}'${condition[1]}'`
params.type = type
}
}
if (type && condition) {
if ((params.type && params.q) || (param && param.type)) {
params.type = params.type || param.type
this.toggleLoading(true)
get(api.npm.overview.networkAnalysis, params).then(res => {
get(url, params).then(res => {
if (res.code === 200) {
this.npmNetworkLastCycleData = res.data.result
let timer = null
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
this.npmNetworkQuantity(this.npmNetworkCycleData, this.npmNetworkLastCycleData, 0)
}, 300)
} else {
this.npmNetworkLastCycleData = [res]
}
let timer = null
if (timer) {
clearTimeout(timer)
}
this.timer1 = setTimeout(() => {
this.npmNetworkQuantity(this.npmNetworkCycleData, this.npmNetworkLastCycleData, 0)
}, 300)
}).catch((e) => {
let timer = null
if (timer) {
clearTimeout(timer)
}
this.npmNetworkLastCycleData = [e]
this.timer2 = setTimeout(() => {
this.npmNetworkQuantity(this.npmNetworkCycleData, this.npmNetworkLastCycleData, 0)
}, 300)
}).finally(() => {
this.toggleLoading(false)
})
@@ -251,9 +207,19 @@ export default {
res.forEach((t, i) => {
if (t.code === 200) {
this.npmNetworkLastCycleData.push(t.data.result)
this.npmNetworkQuantity(this.npmNetworkCycleData, this.npmNetworkLastCycleData, 1)
} else {
this.npmNetworkLastCycleData.push(t)
}
this.npmNetworkQuantity(this.npmNetworkCycleData, this.npmNetworkLastCycleData, 1)
})
}).catch((e) => {
// todo 此处的e可能为数组
if (e instanceof Array) {
e.forEach((t, i) => {
this.npmNetworkLastCycleData.push(t)
this.npmNetworkQuantity(this.npmNetworkCycleData, this.npmNetworkLastCycleData, 1)
})
}
}).finally(() => {
this.toggleLoading(false)
})
@@ -312,6 +278,10 @@ export default {
this.chartData = _.cloneDeep(this.chart)
}
this.npmNetworkCycleQuery()
},
beforeUnmount () {
clearTimeout(this.timer1)
clearTimeout(this.timer2)
}
}
</script>

View File

@@ -1,6 +1,9 @@
<template>
<div class="npm-recent">
<div class="npm-recent-title">{{ $t('network.recentEvents') }}</div>
<div class="npm-recent-title">
{{ $t('network.recentEvents') }}
<chart-error v-if="showError" tooltip :content="errorMsg" />
</div>
<el-table
:id="`tabTable_${index}`"
:ref="`dataTable_${index}`"
@@ -51,9 +54,11 @@ import { getSecond, dateFormatByAppearance } from '@/utils/date-util'
import chartMixin from '@/views/charts2/chart-mixin'
import { useRoute } from 'vue-router'
import { ref } from 'vue'
import ChartError from '@/components/common/Error'
export default {
name: 'NpmRecentEvents',
components: { ChartError },
mixins: [chartMixin],
setup () {
const { query } = useRoute()
@@ -71,7 +76,9 @@ export default {
{ label: 'network.severity', prop: 'eventSeverity' },
{ label: 'network.entity', prop: 'eventKey' },
{ label: 'detections.eventType', prop: 'eventType' }
]
],
showError: false,
errorMsg: ''
}
},
watch: {
@@ -83,11 +90,7 @@ export default {
},
methods: {
recentEventsListData () {
// const condition = this.$store.getters.getQueryCondition.split(/["|'](.*?)["|']/)
// const conditionStr = this.$route.query.queryCondition ? this.$route.query.queryCondition : ''
const condition = this.queryCondition.split(/["|'](.*?)["|']/)
// const type = this.$store.getters.getDimensionType
// const type = this.$route.query.dimensionType ? this.$route.query.dimensionType : ''
let url = ''
const params = {
startTime: getSecond(this.timeFilter.startTime),
@@ -97,6 +100,7 @@ export default {
if (condition.length > 1 && this.dimensionType) {
params.param = condition[1]
params.type = this.dimensionType
if (params.type === 'serverIp' || params.type === 'clientIp') params.type = 'ip'
params.limit = 10
url = api.npm.events.recentEventsD
this.customTableTitles = [
@@ -110,6 +114,7 @@ export default {
this.toggleLoading(true)
get(url, params).then(res => {
if (res.code === 200) {
this.showError = false
this.isNoData = res.data.result.length === 0
res.data.result.forEach(e => {
if (e.startTime) {
@@ -118,8 +123,13 @@ export default {
})
this.tableData = res.data.result
} else {
this.isNoData = true
// this.isNoData = true
this.showError = true
this.errorMsg = res.message
}
}).catch(error => {
this.showError = true
this.errorMsg = error.message
}).finally(() => {
this.toggleLoading(false)
})

View File

@@ -1,7 +1,8 @@
<template>
<div class="npm-tabs">
<div class="npm-tabs__active-bar"></div>
<el-tabs v-model="currentTab" ref="elTabs" type="border-card">
<el-tabs v-model="currentTab" ref="elTabs" type="border-card" v-show="isCurTabReady"
@tab-click="handleClick">
<el-tab-pane v-for="(tab,index) in tabs" :key="tab.i18n" :name="index" :disabled="tab.disable" >
<template #label>
<div class="npm-tab__label">
@@ -27,7 +28,9 @@ export default {
name: 'NpmTabs',
data () {
return {
leftOffset: 27
leftOffset: 27,
currentTab: ref(0),
isCurTabReady:false
}
},
mixins: [chartMixin],
@@ -39,11 +42,7 @@ export default {
item.disable = false
})
}
const { query } = useRoute()
const tabIndexParam = query.tabIndex
const currentTab = ref(tabIndexParam ? parseInt(tabIndexParam) : 0)
return {
currentTab,
tabs
}
},
@@ -64,6 +63,13 @@ export default {
}
},
methods: {
handleClick(tab){
const { query } = this.$route
const newUrl = urlParamsHandler(window.location.href, query, {
tabIndex: tab.index
})
overwriteUrl(newUrl)
},
handleActiveBar (index) {
const tabDom = document.getElementById('tab-' + index)
if (tabDom) {
@@ -73,9 +79,17 @@ export default {
const activeBar = document.querySelector('.npm-tabs .npm-tabs__active-bar')
activeBar.style.cssText += `width: ${clientWidth + 2}px; left: ${offsetLeft + this.leftOffset + clientLeft - 1}px;`
}
},
disableTab(n){
this.tabs[n].disable = true
const tabEle = document.getElementById('tab-'+n)
tabEle.style.cssText = 'cursor: not-allowed;'
}
},
mounted () {
const { query } = useRoute()
const tabIndexParam = query.tabIndex
let curTabIndexInUrl = tabIndexParam ? parseInt(tabIndexParam) : null
if (this.chart.panelId === drillDownPanelTypeMapping.npmOverviewIp) {
const self = this
// 当client或server的session数为0时对应tab置灰不可选默认高亮另一个不为0的tab
@@ -93,34 +107,53 @@ export default {
self.serverSessions = self.sessionData.serverSessions / (self.sessionData.clientSessions * 1 + self.sessionData.serverSessions * 1)
}
}).finally(() => {
if (self.clientSessions === 0) {
self.currentTab = 1
self.tabs[0].disable = true
self.tabs[1].disable = false
const tabEle = document.getElementById('tab-0')
tabEle.style.cssText = 'cursor: not-allowed;'
setTimeout(() => {
self.handleActiveBar(1)
}, 400)
let thirdMenu = this.$route.query['thirdMenu']
self.tabs[0].disable = false
self.tabs[1].disable = false
let curTabIndex = 0
if(thirdMenu === 'network.clientIps'){
curTabIndex = 0
if (self.serverSessions === 0) {
self.disableTab(1)
}else if(curTabIndexInUrl !== null){
curTabIndex = curTabIndexInUrl
}
}else if(thirdMenu === 'network.serverIps'){
curTabIndex = 1
if (self.clientSessions === 0) {
self.disableTab(0)
}else if(curTabIndexInUrl !== null){
curTabIndex = curTabIndexInUrl
}
}else if (self.clientSessions === 0) {
curTabIndex = 1
self.disableTab(0)
} else if (self.serverSessions === 0) {
self.currentTab = 0
self.tabs[0].disable = false
self.tabs[1].disable = true
setTimeout(() => {
const tabEle = document.getElementById('tab-1')
tabEle.style.cssText = 'cursor: not-allowed;'
self.handleActiveBar(0)
}, 400)
} else {
self.currentTab = 0
self.tabs[0].disable = false
self.tabs[1].disable = false
setTimeout(() => {
self.handleActiveBar(0)
}, 400)
curTabIndex = 0
self.disableTab(1)
} else if(curTabIndexInUrl !== null){
curTabIndex = curTabIndexInUrl
}
this.$nextTick(() => {
self.currentTab = curTabIndex
self.isCurTabReady = true
//URL中tabIndex的设置client初始化时查询条件需要side条件
const { query } = this.$route
const newUrl = urlParamsHandler(window.location.href, query, {
tabIndex: self.currentTab
})
overwriteUrl(newUrl)
setTimeout(() => {
self.handleActiveBar(self.currentTab)
}, 400)
setTimeout(() => {
this.$emit('tabChange', self.currentTab)
}, 400)
})
})
} else {
this.currentTab = curTabIndexInUrl ? curTabIndexInUrl : 0
this.isCurTabReady = true
setTimeout(() => {
this.handleActiveBar(this.currentTab)
}, 400)

View File

@@ -1,7 +1,7 @@
<template>
<div class="npm-traffic-line">
<div class="npm-traffic-line-header">
<div class="npm-traffic-line-title">{{$t('overall.traffic')}}</div>
<div class="npm-traffic-line-title"></div>
<div class="line-select-metric">
<span>{{$t('network.metric')}}:</span>
<div class="line-select__operation">
@@ -19,8 +19,9 @@
</div>
</div>
<div class="npm-traffic-line-body">
<chart-no-data v-if="isNoData"></chart-no-data>
<div v-show="!isNoData" class="chart-drawing" id="chart"></div>
<chart-error v-if="showError" :content="errorMsg" />
<chart-no-data v-if="isNoData && !showError"></chart-no-data>
<div v-show="!isNoData && !showError" class="chart-drawing" id="chart"></div>
</div>
</div>
</template>
@@ -40,10 +41,12 @@ import _ from 'lodash'
import chartMixin from '@/views/charts2/chart-mixin'
import { useRoute } from 'vue-router'
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
import ChartError from '@/components/common/Error'
export default {
name: 'NpmTrafficLine',
mixins: [chartMixin],
components: {
ChartError,
ChartNoData
},
setup () {
@@ -51,10 +54,12 @@ export default {
const metricFilter = ref(query.lineMetric || 'Bits/s')
const queryCondition = ref(query.queryCondition || '')
const dimensionType = ref(query.dimensionType || '')
const tabIndex = ref(query.tabIndex || 0)
return {
metricFilter,
queryCondition,
dimensionType,
tabIndex,
myChart: shallowRef(null)
}
},
@@ -64,19 +69,19 @@ export default {
unitTypes,
side: '',
mpackets: [
{ name: 'network.total', show: true, positioning: 0, data: [], unitType: '' },
{ name: 'network.inbound', show: true, positioning: 1, data: [], unitType: '' },
{ name: 'network.outbound', show: true, positioning: 2, data: [], unitType: '' },
{ name: 'network.internal', show: true, positioning: 3, data: [], unitType: '' },
{ name: 'network.through', show: true, positioning: 4, data: [], unitType: '' },
{ name: 'network.other', show: true, positioning: 5, data: [], unitType: '' }
{ name: 'network.total', show: true, positioning: 0, data: [], unitType: 'number' },
{ name: 'network.inbound', show: true, positioning: 1, data: [], unitType: 'number' },
{ name: 'network.outbound', show: true, positioning: 2, data: [], unitType: 'number' },
{ name: 'network.internal', show: true, positioning: 3, data: [], unitType: 'number' },
{ name: 'network.through', show: true, positioning: 4, data: [], unitType: 'number' },
{ name: 'network.other', show: true, positioning: 5, data: [], unitType: 'number' }
],
npmQuantity: [
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency', show: true, positioning: 0, data: [], unitType: '' },
{ name: 'networkAppPerformance.httpResponse', show: true, positioning: 0, data: [], unitType: '' },
{ name: 'networkAppPerformance.sslResponseLatency', show: true, positioning: 0, data: [], unitType: '' },
{ name: 'networkAppPerformance.packetLoss', show: true, positioning: 0, data: [], unitType: '' },
{ name: 'overall.packetRetrans', show: true, positioning: 0, data: [], unitType: '' }
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.httpResponse', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.sslResponseLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.packetLoss', show: true, positioning: 0, data: [], unitType: unitTypes.percent },
{ name: 'overall.packetRetrans', show: true, positioning: 0, data: [], unitType: unitTypes.percent }
],
chartData: {},
metricOptions: [
@@ -112,7 +117,9 @@ export default {
value: 'pktRetransPercent',
label: this.$t('overall.packetRetrans')
}
]
],
showError: false,
errorMsg: ''
}
},
watch: {
@@ -142,19 +149,30 @@ export default {
} else {
condition = this.queryCondition
}
// const type = this.$store.getters.getDimensionType
if (this.chartData.id === 24) {
if (this.tabIndex == 0) {
this.side = 'client'
} else if (this.chartData.id === 29) {
} else if (this.tabIndex == 1) {
this.side = 'server'
}
const params = {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
type: type
endTime: getSecond(this.timeFilter.endTime)
}
if (type) {
params.type = type
}
if (condition && (typeof condition !== 'object') && type) {
params.q = condition
if (type === 'clientIp') {
params.q = `ip='${condition.split(/'(.*?)'/)[1]}' and side='client'`
} else if (type === 'serverIp') {
params.q = `ip='${condition.split(/'(.*?)'/)[1]}' and side='server'`
} else if (type === 'clientCity') {
params.q = `client_city='${condition.split(/'(.*?)'/)[1]}'`
} else if (type === 'serverCity') {
params.q = `server_city='${condition.split(/'(.*?)'/)[1]}'`
} else {
params.q = condition
}
} else if (condition.length > 1 && type && type === 'ip') {
params.q = `${type}='${condition[1]}' and side='${this.side}'`
} else if (condition.length > 1 && type && type !== 'ip') {
@@ -167,129 +185,379 @@ export default {
}
}
this.toggleLoading(true)
get(api.npm.overview.trafficGraph, params).then((res) => {
if (res.code === 200) {
this.isNoData = res.data.result.length === 0
res.data.result.forEach((t, i) => {
if (t.type === 'bytes' && val === 'Bits/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].data = t.totalBitsRate.values ? t.totalBitsRate.values : []
mpackets[1].data = t.inboundBitsRate.values ? t.inboundBitsRate.values : []
mpackets[2].data = t.outboundBitsRate.values ? t.outboundBitsRate.values : []
mpackets[3].data = t.internalBitsRate.values ? t.internalBitsRate.values : []
mpackets[4].data = t.throughBitsRate.values ? t.throughBitsRate.values : []
mpackets[5].data = t.other.values ? t.other.values : []
mpackets.forEach((e, i) => {
e.show = true
})
this.mpackets = mpackets
this.echartsInit(this.mpackets)
} else if (t.type === 'packets' && val === 'Packets/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].data = t.totalPacketsRate.values ? t.totalPacketsRate.values : []
mpackets[1].data = t.inboundPacketsRate.values ? t.inboundPacketsRate.values : []
mpackets[2].data = t.outboundPacketsRate.values ? t.outboundPacketsRate.values : []
mpackets[3].data = t.internalPacketsRate.values ? t.internalPacketsRate.values : []
mpackets[4].data = t.throughPacketsRate.values ? t.throughPacketsRate.values : []
mpackets[5].data = t.other.values ? t.other.values : []
mpackets.forEach((e, i) => {
e.show = true
})
this.mpackets = mpackets
this.echartsInit(this.mpackets)
} else if (t.type === 'sessions' && val === 'Sessions/s') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[0].data = t.sessionsRate.values ? t.sessionsRate.values : []
npmQuantity.forEach((e, i) => {
if (i !== 0) {
e.show = false
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity)
} else if (t.type === 'establishLatencyMs' && val === 'establishLatencyMs') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[0].data = t.establishLatencyMsAvg.values ? t.establishLatencyMsAvg.values : []
npmQuantity.forEach((e, i) => {
if (i !== 0) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity)
} else if (t.type === 'httpResponseLatency' && val === 'httpResponseLatency') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[1].data = t.httpResponseLatencyAvg.values ? t.httpResponseLatencyAvg.values : []
npmQuantity.forEach((e, i) => {
console.log(e)
if (i !== 1) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity)
} else if (t.type === 'sslConLatency' && val === 'sslConLatency') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[2].data = t.sslConLatencyAvg.values ? t.sslConLatencyAvg.values : []
npmQuantity.forEach((e, i) => {
if (i !== 2) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity)
} else if (t.type === 'tcpLostlenPercent' && val === 'tcpLostlenPercent') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[3].data = t.tcpLostlenPercentAvg.values ? t.tcpLostlenPercentAvg.values : []
npmQuantity.forEach((e, i) => {
if (i !== 3) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity)
} else if (t.type === 'pktRetransPercent' && val === 'pktRetransPercent') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[4].data = t.pktRetransPercentAvg.values ? t.pktRetransPercentAvg.values : []
npmQuantity.forEach((e, i) => {
if (i !== 4) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity)
if (params.type && params.q) {
get(api.npm.overview.trafficGraph, params).then((res) => {
if (res.code === 200) {
this.showError = false
this.isNoData = res.data.result.length === 0
if (this.isNoData) {
this.mpackets = [
{ name: 'network.total', show: true, positioning: 0, data: [], unitType: 'number' },
{ name: 'network.inbound', show: true, positioning: 1, data: [], unitType: 'number' },
{ name: 'network.outbound', show: true, positioning: 2, data: [], unitType: 'number' },
{ name: 'network.internal', show: true, positioning: 3, data: [], unitType: 'number' },
{ name: 'network.through', show: true, positioning: 4, data: [], unitType: 'number' },
{ name: 'network.other', show: true, positioning: 5, data: [], unitType: 'number' }
]
this.npmQuantity = [
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.httpResponse', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.sslResponseLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.packetLoss', show: true, positioning: 0, data: [], unitType: unitTypes.percent },
{ name: 'overall.packetRetrans', show: true, positioning: 0, data: [], unitType: unitTypes.percent }
]
}
res.data.result.forEach((t, i) => {
if (t.type === 'bytes' && val === 'Bits/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].data = t.totalBitsRate.values ? t.totalBitsRate.values : []
mpackets[1].data = t.inboundBitsRate.values ? t.inboundBitsRate.values : []
mpackets[2].data = t.outboundBitsRate.values ? t.outboundBitsRate.values : []
mpackets[3].data = t.internalBitsRate.values ? t.internalBitsRate.values : []
mpackets[4].data = t.throughBitsRate.values ? t.throughBitsRate.values : []
mpackets[5].data = t.other.values ? t.other.values : []
mpackets.forEach((e, i) => {
e.show = true
})
this.mpackets = mpackets
this.echartsInit(this.mpackets)
} else if (t.type === 'packets' && val === 'Packets/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].data = t.totalPacketsRate.values ? t.totalPacketsRate.values : []
mpackets[1].data = t.inboundPacketsRate.values ? t.inboundPacketsRate.values : []
mpackets[2].data = t.outboundPacketsRate.values ? t.outboundPacketsRate.values : []
mpackets[3].data = t.internalPacketsRate.values ? t.internalPacketsRate.values : []
mpackets[4].data = t.throughPacketsRate.values ? t.throughPacketsRate.values : []
mpackets[5].data = t.other.values ? t.other.values : []
mpackets.forEach((e, i) => {
e.show = true
})
this.mpackets = mpackets
this.echartsInit(this.mpackets)
} else if (t.type === 'sessions' && val === 'Sessions/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].data = t.totalSessionsRate.values ? t.totalSessionsRate.values : []
mpackets.forEach((e, i) => {
if (i !== 0) {
e.show = false
}
})
this.mpackets = mpackets
this.echartsInit(this.mpackets)
} else if (t.type === 'establishLatencyMs' && val === 'establishLatencyMs') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[0].data = t.establishLatencyMsAvg.values ? t.establishLatencyMsAvg.values : []
npmQuantity.forEach((e, i) => {
if (i !== 0) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(ms)')
} else if (t.type === 'httpResponseLatency' && val === 'httpResponseLatency') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[1].data = t.httpResponseLatencyAvg.values ? t.httpResponseLatencyAvg.values : []
npmQuantity.forEach((e, i) => {
if (i !== 1) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(ms)')
} else if (t.type === 'sslConLatency' && val === 'sslConLatency') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[2].data = t.sslConLatencyAvg.values ? t.sslConLatencyAvg.values : []
npmQuantity.forEach((e, i) => {
if (i !== 2) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(ms)')
} else if (t.type === 'tcpLostlenPercent' && val === 'tcpLostlenPercent') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[3].data = t.tcpLostlenPercentAvg.values ? t.tcpLostlenPercentAvg.values : []
npmQuantity.forEach((e, i) => {
if (i !== 3) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(%)')
} else if (t.type === 'pktRetransPercent' && val === 'pktRetransPercent') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[4].data = t.pktRetransPercentAvg.values ? t.pktRetransPercentAvg.values : []
npmQuantity.forEach((e, i) => {
if (i !== 4) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(%)')
}
})
} else {
this.isNoData = false
this.showError = true
this.errorMsg = res.message
}
}).catch(e => {
this.isNoData = false
this.showError = true
this.errorMsg = e.message
}).finally(() => {
this.toggleLoading(false)
})
} else {
if (val === 'Bits/s' || val === 'Packets/s' || val === 'Sessions/s') {
this.toggleLoading(true)
get(api.npm.overview.totalTrafficAnalysis, params).then(res => {
if (res.code === 200) {
this.showError = false
this.isNoData = res.data.result.length === 0
if (this.isNoData) {
this.mpackets = [
{ name: 'network.total', show: true, positioning: 0, data: [], unitType: 'number' },
{ name: 'network.inbound', show: true, positioning: 1, data: [], unitType: 'number' },
{ name: 'network.outbound', show: true, positioning: 2, data: [], unitType: 'number' },
{ name: 'network.internal', show: true, positioning: 3, data: [], unitType: 'number' },
{ name: 'network.through', show: true, positioning: 4, data: [], unitType: 'number' },
{ name: 'network.other', show: true, positioning: 5, data: [], unitType: 'number' }
]
}
res.data.result.forEach((t, i) => {
if (t.type === 'bytes' && val === 'Bits/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].data = t.totalBitsRate.values ? t.totalBitsRate.values : []
mpackets[1].data = t.inboundBitsRate.values ? t.inboundBitsRate.values : []
mpackets[2].data = t.outboundBitsRate.values ? t.outboundBitsRate.values : []
mpackets[3].data = t.internalBitsRate.values ? t.internalBitsRate.values : []
mpackets[4].data = t.throughBitsRate.values ? t.throughBitsRate.values : []
mpackets[5].data = t.other.values ? t.other.values : []
mpackets.forEach((e, i) => {
e.show = true
})
this.mpackets = mpackets
this.echartsInit(this.mpackets)
} else if (t.type === 'packets' && val === 'Packets/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].data = t.totalPacketsRate.values ? t.totalPacketsRate.values : []
mpackets[1].data = t.inboundPacketsRate.values ? t.inboundPacketsRate.values : []
mpackets[2].data = t.outboundPacketsRate.values ? t.outboundPacketsRate.values : []
mpackets[3].data = t.internalPacketsRate.values ? t.internalPacketsRate.values : []
mpackets[4].data = t.throughPacketsRate.values ? t.throughPacketsRate.values : []
mpackets[5].data = t.other.values ? t.other.values : []
mpackets.forEach((e, i) => {
e.show = true
})
this.mpackets = mpackets
this.echartsInit(this.mpackets)
} else if (t.type === 'sessions' && val === 'Sessions/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].data = t.totalSessionsRate.values ? t.totalSessionsRate.values : []
mpackets.forEach((e, i) => {
if (i !== 0) {
e.show = false
}
})
this.mpackets = mpackets
this.echartsInit(this.mpackets)
}
})
} else {
this.isNoData = false
this.showError = true
this.errorMsg = res.message
}
}).catch(e => {
this.isNoData = false
this.showError = true
this.errorMsg = e.message
}).finally(() => {
this.toggleLoading(false)
})
} else if (val === 'establishLatencyMs' || val === 'tcpLostlenPercent' || val === 'pktRetransPercent') {
this.toggleLoading(true)
get(api.npm.overview.totalNetworkAnalysis, params).then(res => {
if (res.code === 200) {
this.showError = false
this.isNoData = res.data.result.length === 0
if (this.isNoData) {
this.npmQuantity = [
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.httpResponse', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.sslResponseLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.packetLoss', show: true, positioning: 0, data: [], unitType: unitTypes.percent },
{ name: 'overall.packetRetrans', show: true, positioning: 0, data: [], unitType: unitTypes.percent }
]
}
res.data.result.forEach((t, i) => {
if (t.type === 'establishLatencyMs' && val === 'establishLatencyMs') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[0].data = t.establishLatencyMs.values ? t.establishLatencyMs.values : []
npmQuantity.forEach((e, i) => {
if (i !== 0) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(ms)')
} else if (t.type === 'tcpLostlenPercent' && val === 'tcpLostlenPercent') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[3].data = t.tcpLostlenPercent.values ? t.tcpLostlenPercent.values : []
npmQuantity.forEach((e, i) => {
if (i !== 3) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(%)')
} else if (t.type === 'pktRetransPercent' && val === 'pktRetransPercent') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[4].data = t.pktRetransPercent.values ? t.pktRetransPercent.values : []
npmQuantity.forEach((e, i) => {
if (i !== 4) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(%)')
}
})
} else {
this.isNoData = false
this.showError = true
this.errorMsg = res.message
}
}).catch(e => {
this.isNoData = false
this.showError = true
this.errorMsg = e.message
}).finally(() => {
this.toggleLoading(false)
})
} else if (val === 'httpResponseLatency') {
this.toggleLoading(true)
get(api.npm.overview.totalHttpResponseDelay, params).then(res => {
if (res.code === 200) {
this.showError = false
this.isNoData = res.data.result.length === 0
if (this.isNoData) {
this.npmQuantity = [
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.httpResponse', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.sslResponseLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.packetLoss', show: true, positioning: 0, data: [], unitType: unitTypes.percent },
{ name: 'overall.packetRetrans', show: true, positioning: 0, data: [], unitType: unitTypes.percent }
]
}
res.data.result.forEach(t => {
if (t.type === 'httpResponseLatency' && val === 'httpResponseLatency') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[1].data = t.httpResponseLatency.values ? t.httpResponseLatency.values : []
npmQuantity.forEach((e, i) => {
if (i !== 1) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(ms)')
}
})
} else {
this.isNoData = false
this.showError = true
this.errorMsg = res.message
}
}).catch(e => {
this.isNoData = false
this.showError = true
this.errorMsg = e.message
}).finally(() => {
this.toggleLoading(false)
})
} else if (val === 'sslConLatency') {
this.toggleLoading(true)
get(api.npm.overview.totalSslConDelay, params).then(res => {
if (res.code === 200) {
this.showError = false
this.isNoData = res.data.result.length === 0
if (this.isNoData) {
this.npmQuantity = [
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.httpResponse', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.sslResponseLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.packetLoss', show: true, positioning: 0, data: [], unitType: unitTypes.percent },
{ name: 'overall.packetRetrans', show: true, positioning: 0, data: [], unitType: unitTypes.percent }
]
}
res.data.result.forEach(t => {
if (t.type === 'sslConLatency' && val === 'sslConLatency') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[2].data = t.sslConLatency.values ? t.sslConLatency.values : []
npmQuantity.forEach((e, i) => {
if (i !== 2) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(ms)')
}
})
} else {
this.isNoData = false
this.showError = true
this.errorMsg = res.message
}
}).catch(e => {
this.isNoData = false
this.showError = true
this.errorMsg = e.message
}).finally(() => {
this.toggleLoading(false)
})
} else {
this.isNoData = true
}
}).catch(e => {
console.error(e)
this.isNoData = true
}).finally(() => {
this.toggleLoading(false)
})
}
},
echartsInit (echartsData) {
echartsInit (echartsData, legendUnit) {
echartsData = echartsData.filter(t => t.show === true)
const dom = document.getElementById('chart')
!this.myChart && (this.myChart = echarts.init(dom))
this.chartOption = trafficLineChartOption
const chartOption = this.chartOption.series[0]
this.chartOption.series = echartsData.map((t, i) => {
this.chartOption.yAxis[0].axisLabel.formatter = (value) => {
if (t.unitType === 'percent') {
return unitConvert(value, t.unitType)[0]
} else if (t.unitType === 'time') {
return unitConvert(value, 'number').join('')
} else {
return unitConvert(value, t.unitType).join('')
}
}
return {
...chartOption,
name: this.$t(t.name),
name: this.$t(t.name) + (legendUnit || ''),
lineStyle: {
color: chartColor3[t.positioning],
width: 1
@@ -308,12 +576,26 @@ export default {
}
])
},
data: t.data.map(v => [Number(v[0]) * 1000, Number(v[1]), 'number'])
data: t.data.map(v => [Number(v[0]) * 1000, Number(v[1]), t.unitType])
}
})
this.chartOption.tooltip.formatter = (params) => {
params.forEach(t => {
t.seriesName = this.$t(t.seriesName)
this.mpackets.forEach(e => {
if (this.$t(e.name) === t.seriesName) {
t.borderColor = chartColor3[e.positioning]
}
})
this.npmQuantity.forEach(d => {
const nameMs = this.$t(d.name) + '(ms)'
const namePrent = this.$t(d.name) + '(%)'
if (nameMs === t.seriesName) {
t.borderColor = chartColor3[d.positioning]
} else if (namePrent === t.seriesName) {
t.borderColor = chartColor3[d.positioning]
}
})
})
const str = stackedLineTooltipFormatter(params)
return str
@@ -384,6 +666,7 @@ export default {
beforeUnmount () {
clearTimeout(this.timer)
window.removeEventListener('resize', this.resize)
this.myChart = null
}
}
</script>

View File

@@ -1,9 +1,13 @@
<template>
<div class="npm-sessions">
<div class="npm-sessions-title">{{$t('npm.relatedSessions')}}</div>
<div class="npm-sessions-title">
{{$t('npm.relatedSessions')}}
<chart-error v-if="showError" tooltip :content="errorMsg" />
</div>
<div class="npm-sessions-div">
<div class="npm-sessions-div-green" id="green" v-show="clientSessions > 0"></div>
<div class="npm-sessions-div-red" id="red" v-show="serverSessions > 0"></div>
<div class="npm-sessions-div-gray" id="gray" v-show="showError || isNoData"></div>
</div>
<div class="npm-sessions-body">
<div class="npm-sessions-body-left">
@@ -36,9 +40,11 @@ import { getSecond } from '@/utils/date-util'
import unitConvert from '@/utils/unit-convert'
import { unitTypes } from '@/utils/constants'
import chartMixin from '@/views/charts2/chart-mixin'
import ChartError from '@/components/common/Error'
export default {
name: 'RelatedSessions',
components: { ChartError },
mixins: [chartMixin],
data () {
return {
@@ -46,12 +52,16 @@ export default {
unitConvert,
unitTypes,
clientSessions: 0,
serverSessions: 0
serverSessions: 0,
showError: false,
errorMsg: '',
noData: false,
isNoData: false
}
},
watch: {
timeFilter: {
handler (n) {
handler () {
this.relatedSessionsData()
}
}
@@ -66,25 +76,63 @@ export default {
ip: condition[1]
}
const divGreen = document.getElementById('green')
const divred = document.getElementById('red')
const divRed = document.getElementById('red')
const divGray = document.getElementById('gray')
get(api.npm.overview.relatedSessions, params).then(res => {
if (res.code === 200) {
this.showError = false
this.isNoData = false
this.sessionData = res.data.result
this.clientSessions = this.sessionData.clientSessions / (this.sessionData.clientSessions * 1 + this.sessionData.serverSessions * 1)
this.serverSessions = this.sessionData.serverSessions / (this.sessionData.clientSessions * 1 + this.sessionData.serverSessions * 1)
this.sessionData.clientSessions = unitConvert(this.clientSessions, unitTypes.percent).join('')
this.sessionData.serverSessions = unitConvert(this.serverSessions, unitTypes.percent).join('')
if (this.clientSessions === 1) {
divGreen.style.borderRadius = 4 + 'px'
} else if (this.serverSessions === 1) {
divred.style.borderRadius = 4 + 'px'
const client = this.sessionData.clientSessions
const server = this.sessionData.serverSessions
// 如果返回数据为-,则不必计算比例
if (!isNaN(client) && !isNaN(server)) {
this.clientSessions = client / (client * 1 + server * 1)
this.serverSessions = server / (client * 1 + server * 1)
this.sessionData.clientSessions = unitConvert(this.clientSessions, unitTypes.percent).join('')
this.sessionData.serverSessions = unitConvert(this.serverSessions, unitTypes.percent).join('')
if (this.clientSessions === 1) {
divGreen.style.borderRadius = 4 + 'px'
} else if (this.serverSessions === 1) {
divRed.style.borderRadius = 4 + 'px'
} else if (this.clientSessions === 0 && this.serverSessions === 0) {
this.isNoData = true
divGray.style.borderRadius = 4 + 'px'
divGray.style.width = '100%'
}
divGreen.style.width = this.sessionData.clientSessions
divRed.style.width = this.sessionData.serverSessions
} else {
this.isNoData = true
this.changeByErrorOrNodata()
}
divGreen.style.width = this.sessionData.clientSessions
divred.style.width = this.sessionData.serverSessions
} else {
this.showError = true
this.errorMsg = res.message
this.changeByErrorOrNodata()
}
}).catch(error => {
this.showError = true
this.errorMsg = error.message
this.changeByErrorOrNodata()
}).finally(() => {
this.toggleLoading(false)
})
},
/**
* 当无数据或者报错时改变界面样式,出现灰条
*/
changeByErrorOrNodata () {
const divGray = document.getElementById('gray')
divGray.style.borderRadius = 4 + 'px'
divGray.style.width = '100%'
this.sessionData.clientSessions = '—'
this.sessionData.serverSessions = '—'
this.clientSessions = 0
this.serverSessions = 0
}
},
mounted () {

View File

@@ -1,153 +1,65 @@
<template v-if="npmNetworkData.length > 0">
<div class="single-value" v-for="(npm, index) in npmNetworkData" :key="index">
<template v-if="index === 0">
<div class="single-value__title">{{$t(npmNetworkName[index].name)}}</div>
<div class="single-value__content">
<div class="single-value__content-number">{{unitConvert(npm.establishLatencyMsAvg, unitTypes.time).join(' ')}}</div>
<div v-if="npm.value > 0" class="single-value__content-trend single-value__content-trend-red">
<i class="cn-icon-rise1 cn-icon"></i>&nbsp;
<span v-if="npm.value <= 5">
{{unitConvert(npm.value, unitTypes.percent).join('')}}
</span>
<span v-else>>500.00%</span>
</div>
<div v-else-if="npm.value < 0" class="single-value__content-trend single-value__content-trend-green">
<i class="cn-icon-decline cn-icon"></i>&nbsp;
<span v-if="npm.value >= -5">
{{unitConvert(npm.value, unitTypes.percent).join('').replaceAll('-', '')}}
</span>
<span v-else>>500.00%</span>
</div>
<div v-else-if="npm.value === 0" class="single-value__content-trend single-value__content-trend-black">
<i class="cn-icon-constant cn-icon"></i>
</div>
<div v-else></div>
<template>
<div class="single-value" v-for="(npm, index) in newNpmNetworkData" :key="index">
<div class="single-value__title" style="display: flex">
{{ $t(npmNetworkName[index].name) }}
<chart-error v-if="npm.message" tooltip :content="npm.message"></chart-error>
</div>
<div class="single-value__content">
<div class="single-value__content-number" v-if="index ===0 || index ===1 || index ===2">
{{ unitConvert(npm.Avg, unitTypes.time).join(' ') }}
</div>
<div class="single-value__circle">
<div class="single-value__circle-p95">P95: {{unitConvert(npm.establishLatencyMsP95, unitTypes.time).join(' ')}}</div>
<div class="single-value__circle-p99">P99: {{unitConvert(npm.establishLatencyMsP99, unitTypes.time).join(' ')}}</div>
<div class="single-value__content-number" v-else>
{{unitConvert(npm.Avg, unitTypes.percent).join(' ')}}
</div>
</template>
<template v-if="index === 1">
<div class="single-value__title">{{$t(npmNetworkName[index].name)}}</div>
<div class="single-value__content">
<div class="single-value__content-number">{{unitConvert(npm.httpResponseLatencyAvg, unitTypes.time).join(' ')}}</div>
<div v-if="npm.value > 0" class="single-value__content-trend single-value__content-trend-red">
<i class="cn-icon-rise1 cn-icon"></i>&nbsp;
<span v-if="npm.value <= 5">
{{unitConvert(npm.value, unitTypes.percent).join('')}}
</span>
<span v-else>>500.00%</span>
</div>
<div v-else-if="npm.value < 0" class="single-value__content-trend single-value__content-trend-green">
<i class="cn-icon-decline cn-icon"></i>&nbsp;
<span v-if="npm.value >= -5">
{{unitConvert(npm.value, unitTypes.percent).join('').replaceAll('-', '')}}
</span>
<span v-else>>500.00%</span>
</div>
<div v-else-if="npm.value === 0" class="single-value__content-trend single-value__content-trend-black">
<i class="cn-icon-constant cn-icon"></i>
</div>
<div v-else></div>
<div v-if="npm.value > 0" class="single-value__content-trend single-value__content-trend-red">
<i class="cn-icon-rise1 cn-icon"></i>&nbsp;
<span v-if="npm.value <= 5">
{{ unitConvert(npm.value, unitTypes.percent).join('') }}
</span>
<span v-else>>500.00%</span>
</div>
<div class="single-value__circle">
<div class="single-value__circle-p95">P95: {{unitConvert(npm.httpResponseLatencyP95, unitTypes.time).join(' ')}}</div>
<div class="single-value__circle-p99">P99: {{unitConvert(npm.httpResponseLatencyP99, unitTypes.time).join(' ')}}</div>
<div v-else-if="npm.value < 0" class="single-value__content-trend single-value__content-trend-green">
<i class="cn-icon-decline cn-icon"></i>&nbsp;
<span v-if="npm.value >= -5">
{{ unitConvert(npm.value, unitTypes.percent).join('').replaceAll('-', '') }}
</span>
<span v-else>>500.00%</span>
</div>
</template>
<template v-if="index === 2">
<div class="single-value__title">{{$t(npmNetworkName[index].name)}}</div>
<div class="single-value__content">
<div class="single-value__content-number">{{unitConvert(npm.sslConLatencyAvg, unitTypes.time).join(' ')}}</div>
<div v-if="npm.value > 0" class="single-value__content-trend single-value__content-trend-red">
<i class="cn-icon-rise1 cn-icon"></i>&nbsp;
<span v-if="npm.value <= 5">
{{unitConvert(npm.value, unitTypes.percent).join('')}}
</span>
<span v-else>>500.00%</span>
</div>
<div v-else-if="npm.value < 0" class="single-value__content-trend single-value__content-trend-green">
<i class="cn-icon-decline cn-icon"></i>&nbsp;
<span v-if="npm.value >= -5">
{{unitConvert(npm.value, unitTypes.percent).join('').replaceAll('-', '')}}
</span>
<span v-else>>500.00%</span>
</div>
<div v-else-if="npm.value === 0" class="single-value__content-trend single-value__content-trend-black">
<i class="cn-icon-constant cn-icon"></i>
</div>
<div v-else></div>
<div v-else-if="npm.value === 0" class="single-value__content-trend single-value__content-trend-black">
<i class="cn-icon-constant cn-icon"></i>
</div>
<div class="single-value__circle">
<div class="single-value__circle-p95">P95: {{unitConvert(npm.sslConLatencyP95, unitTypes.time).join(' ')}}</div>
<div class="single-value__circle-p99">P99: {{unitConvert(npm.sslConLatencyP99, unitTypes.time).join(' ')}}</div>
<div v-else></div>
</div>
<div class="single-value__circle">
<div class="single-value__circle-p95">
<span v-if="index ===0 || index ===1 || index ===2">
P95:{{ unitConvert(npm.P95, unitTypes.time).join(' ') }}</span>
<span v-else>
P95:{{ unitConvert(npm.P95, unitTypes.percent).join(' ') }}
</span>
</div>
</template>
<template v-if="index === 3">
<div class="single-value__title">{{$t(npmNetworkName[index].name)}}</div>
<div class="single-value__content">
<div class="single-value__content-number">{{unitConvert(npm.tcpLostlenPercentAvg, unitTypes.percent).join(' ')}}</div>
<div v-if="npm.value > 0" class="single-value__content-trend single-value__content-trend-red">
<i class="cn-icon-rise1 cn-icon"></i>&nbsp;
<span v-if="npm.value <= 5">
{{unitConvert(npm.value, unitTypes.percent).join('')}}
</span>
<span v-else>>500.00%</span>
</div>
<div v-else-if="npm.value < 0" class="single-value__content-trend single-value__content-trend-green">
<i class="cn-icon-decline cn-icon"></i>&nbsp;
<span v-if="npm.value >= -5">
{{unitConvert(npm.value, unitTypes.percent).join('').replaceAll('-', '')}}
</span>
<span v-else>>500.00%</span>
</div>
<div v-else-if="npm.value === 0" class="single-value__content-trend single-value__content-trend-black">
<i class="cn-icon-constant cn-icon"></i>
</div>
<div v-else></div>
<div class="single-value__circle-p99">
<span v-if="index ===0 || index ===1 || index ===2">
P99:{{ unitConvert(npm.P99, unitTypes.time).join(' ') }}
</span>
<span v-else>
P99:{{ unitConvert(npm.P99, unitTypes.percent).join(' ') }}
</span>
</div>
<div class="single-value__circle">
<div class="single-value__circle-p95">P95: {{unitConvert(npm.tcpLostlenPercentP95, unitTypes.percent).join(' ')}}</div>
<div class="single-value__circle-p99">P99: {{unitConvert(npm.tcpLostlenPercentP99, unitTypes.percent).join(' ')}}</div>
</div>
</template>
<template v-if="index === 4">
<div class="single-value__title">{{$t(npmNetworkName[index].name)}}</div>
<div class="single-value__content">
<div class="single-value__content-number">{{unitConvert(npm.pktRetransPercentAvg, unitTypes.percent).join(' ')}}</div>
<div v-if="npm.value > 0" class="single-value__content-trend single-value__content-trend-red">
<i class="cn-icon-rise1 cn-icon"></i>&nbsp;
<span v-if="npm.value <= 5">
{{unitConvert(npm.value, unitTypes.percent).join('')}}
</span>
<span v-else>>500.00%</span>
</div>
<div v-else-if="npm.value < 0" class="single-value__content-trend single-value__content-trend-green">
<i class="cn-icon-decline cn-icon"></i>&nbsp;
<span v-if="npm.value >= -5">
{{unitConvert(npm.value, unitTypes.percent).join('').replaceAll('-', '')}}
</span>
<span v-else>>500.00%</span>
</div>
<div v-else-if="npm.value === 0" class="single-value__content-trend single-value__content-trend-black">
<i class="cn-icon-constant cn-icon"></i>
</div>
<div v-else></div>
</div>
<div class="single-value__circle">
<div class="single-value__circle-p95">P95: {{unitConvert(npm.pktRetransPercentP95, unitTypes.percent).join(' ')}}</div>
<div class="single-value__circle-p99">P99: {{unitConvert(npm.pktRetransPercentP99, unitTypes.percent).join(' ')}}</div>
</div>
</template>
</div>
</div>
</template>
<script>
import { unitTypes } from '@/utils/constants'
import unitConvert from '@/utils/unit-convert'
import ChartError from '@/components/common/Error'
export default {
name: 'SingleValue',
components: { ChartError },
props: {
npmNetworkName: Array,
npmNetworkData: Array
@@ -155,7 +67,58 @@ export default {
data () {
return {
unitTypes,
unitConvert
unitConvert,
newNpmNetworkData: [] // 整合处理传过来的数据列表
}
},
watch: {
npmNetworkData: {
deep: true,
handler () {
this.initData()
}
}
},
mounted () {
this.initData()
},
methods: {
/**
* 初始化数据
*/
initData () {
// 传过来的数据
const npmNetworkData = this.npmNetworkData
// 处理数据后的数组
const dealList = []
if (npmNetworkData !== undefined && npmNetworkData.length > 0) {
npmNetworkData.forEach((item) => {
const tempObj = {}
for (const i in item) {
if (item.msg || item.message) {
// 为了兼容字段为msg的情况
tempObj.message = item.msg ? item.msg : item.message
} else {
// 将含有avg、p90等关键字使用avg、p90来代替形成统一属性
if (i.indexOf('Avg') > -1) {
tempObj.Avg = item[i]
} else if (i.indexOf('P50') > -1) {
tempObj.P50 = item[i]
} else if (i.indexOf('P90') > -1) {
tempObj.P90 = item[i]
} else if (i.indexOf('P95') > -1) {
tempObj.P95 = item[i]
} else if (i.indexOf('P99') > -1) {
tempObj.P99 = item[i]
}
tempObj.value = item.value
}
}
dealList.push(tempObj)
})
this.newNpmNetworkData = dealList
}
}
}
}

View File

@@ -44,7 +44,7 @@ export const pieChartOption1 = {
const data = pieChartOption1.series[0].data
let value
data.forEach(t => {
if (t.name == name) {
if (t.name === name) {
value = t.value
}
})
@@ -103,7 +103,7 @@ export const pieChartOption2 = {
const data = pieChartOption2.series[0].data
let value
data.forEach(t => {
if (t.name == name) {
if (t.name === name) {
value = t.value
}
})
@@ -164,6 +164,15 @@ export const stackedLineChartOption = {
trigger: 'axis',
className: 'echarts-tooltip echarts-tooltip-dark'
},
toolbox: {
show: false
},
brush: {
toolbox: ['lineX'],
xAxisIndex: 'all',
throttleType: 'debounce',
transformable: false
},
legend: {
show: false
},
@@ -177,7 +186,7 @@ export const stackedLineChartOption = {
xAxis: [
{
type: 'time',
splitNumber: 12
splitNumber: 8
// axisLabel: {
// formatter: function (value) {
// const data = new Date(value)
@@ -234,7 +243,7 @@ export const linkTrafficLineChartOption = {
xAxis: [
{
type: 'time',
splitNumber: 12
splitNumber: 8
// axisLabel: {
// formatter: function (value) {
// const data = new Date(value)
@@ -294,7 +303,7 @@ export const appListChartOption = {
bottom: 0
},
animation: false,
color: chartColor,
color: chartColor3[2],
axisLabel: {},
series: [
{
@@ -345,24 +354,13 @@ export const npmLineChartOption = {
show: false
},
axisLabel: {
formatter: function (value) {
return unitConvert(value, unitTypes.number).join('')
}
// formatter: function (value) {
// return unitConvert(value, unitTypes.number).join('')
// }
}
}
],
series: [
{
type: 'line',
symbol: 'circle',
smooth: true,
showSymbol: false,
emphasis: {
focus: 'series'
},
data: []
}
]
series: []
}
export const trafficLineChartOption = {
@@ -384,7 +382,6 @@ export const trafficLineChartOption = {
padding: [0, 0, 0, 2],
fontSize: 12,
color: '#717171',
fontWeight: 400,
fontFamily: 'NotoSansSChineseRegular'
}
},
@@ -398,7 +395,7 @@ export const trafficLineChartOption = {
xAxis: [
{
type: 'time',
splitNumber: 12
splitNumber: 8
// axisLabel: {
// formatter: function (value) {
// const data = new Date(value)
@@ -416,9 +413,9 @@ export const trafficLineChartOption = {
show: false
},
axisLabel: {
formatter: function (value) {
return unitConvert(value, unitTypes.number).join('')
}
// formatter: function (value) {
// return unitConvert(value, unitTypes.number).join('')
// }
}
}
],
@@ -488,7 +485,7 @@ export const stackedBarChartOption = {
xAxis: {
type: 'time',
boundaryGap: ['1%', '3%'],
splitNumber: 12,
splitNumber: 8,
axisLine: {
show: false
},

View File

@@ -1,11 +1,13 @@
<template>
<div class="detection-filter-case">
<div class="no-data" v-if="isNoData">No data</div>
<div class="new-detection-filter-title">{{$t('detections.filters')}}</div>
<template v-for="(filter, index) in filterData" :key="index">
<div class="detection-filter" v-show="filter.data.length > 0">
<div class="filter__header" @click="filter.collapse = !filter.collapse">
<i class="el-icon-arrow-right" :class="{ 'arrow-rotate': !filter.collapse }"></i>
<span>{{filter.title}}</span>
<span class="new-detection-filter-header-title">{{filter.title}}</span>
<i class="el-icon-arrow-right new-detection-filter-icon" :class="{ 'arrow-rotate': !filter.collapse }"></i>
</div>
<el-collapse-transition>
<div class="filter__body" v-show="!filter.collapse">

View File

@@ -4,8 +4,10 @@
<div class="detection-list__content">
<div class="detection-list--list">
<div class="no-data" v-if="noData">No data</div>
<div v-if="!isCollapse" @click="collapse" class="cn-detection__shadow"></div>
<div v-if="!isCollapse" @click="collapse" class="cn-detection__shadow new-cn-detection__shadow"></div>
<detection-row
style="margin-bottom: 10px"
class="detection-border"
v-for="(data, index) in listData"
:detection="data"
:page-type="pageType"

View File

@@ -1,13 +1,22 @@
<template>
<div class="cn-detection--list" :style="{zIndex: !isCollapse ? 1 : 'unset'}">
<div class="cn-detection--list" :style="{zIndex: !isCollapse ? 5 : 'unset'}">
<!-- 左侧下拉按钮 -->
<div class="cn-detection__collapse">
<span @click="switchCollapse" :class="{'reg-down': !isCollapse}"><i class="cn-icon cn-icon-arrow-right"></i></span>
<div class="cn-detection__collapse-block" @click="switchCollapse">
<span :class="{'reg-down': !isCollapse}">
<i class="cn-icon cn-icon-arrow-right"></i>
</span>
</div>
</div>
<div class="cn-detection__case">
<div class="cn-detection__icon" :style="`background-color: ${eventSeverityColor[detection.eventSecurity]}`"></div>
<div class="cn-detection__row">
<div class="cn-detection__header" v-if="pageType === detectionPageType.securityEvent">
<span
class="detection-event-severity-color-block"
:style="`background-color: ${eventSeverityColor[detection.eventSeverity]}`">
</span>
<span class="detection-event-severity-block">{{ detection.securityType || '-' }}</span>
<i class="cn-icon cn-icon-attacker" ></i>{{detection.offenderIp || '-'}}
<div v-if="detection.domain" class="domain">{{detection.domain}}</div>
<span class="line">-------</span>
@@ -31,11 +40,6 @@
<span>{{$t('detections.eventSeverity')}}&nbsp;:&nbsp;&nbsp;</span>
<span>{{detection.eventSeverity || '-'}}</span>
</div>
<div class="basic-info__item" v-if="detection.securityType">
<i class="cn-icon cn-icon-event-type"></i>
<span>{{$t('detection.list.securityType')}}&nbsp;:&nbsp;&nbsp;</span>
<span>{{detection.securityType || '-'}}</span>
</div>
<div class="basic-info__item" v-if="detection.eventType">
<i class="cn-icon cn-icon-event-type"></i>
<span>{{$t('detections.eventType')}}&nbsp;:&nbsp;&nbsp;</span>

View File

@@ -0,0 +1,94 @@
<template>
<div class="npm-tabs">
12345678
<div class="npm-tabs__active-bar"></div>
<el-tabs v-model="currentTab" ref="elTabs" type="border-card" @tab-click="jumpPage">
<el-tab-pane
v-for="(tab,index) in tabs"
:key="tab.i18n"
:name="index"
:disabled="tab.disable">
<template #label>
<div class="npm-tab__label">
<i :class="tab.icon"></i>
<span>{{ $t(tab.i18n) }}</span>
</div>
</template>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import chartMixin from '@/views/charts2/chart-mixin'
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
import { useRoute } from 'vue-router'
import { ref } from 'vue'
export default {
name: 'DetectionTabs',
data () {
return {
leftOffset: 27
}
},
mixins: [chartMixin],
setup (props) {
const tabs = ref([])
if (props.chart) {
tabs.value = [...props.chart]
tabs.value.forEach(item => {
item.disable = false
})
}
const { query } = useRoute()
const tabIndexParam = query.tabIndex
const currentTab = ref(tabIndexParam ? parseInt(tabIndexParam) : 0)
return {
currentTab,
tabs
}
},
watch: {
currentTab (n) {
const { query } = this.$route
const newUrl = urlParamsHandler(window.location.href, query, {
tabIndex: n
})
overwriteUrl(newUrl)
this.$nextTick(() => {
this.handleActiveBar(n)
})
}
},
methods: {
handleActiveBar (index) {
const tabDom = document.getElementById('tab-' + index)
if (tabDom) {
const offsetLeft = tabDom.offsetLeft
const clientWidth = tabDom.clientWidth
const clientLeft = tabDom.clientLeft
const activeBar = document.querySelector('.npm-tabs .npm-tabs__active-bar')
activeBar.style.cssText += `width: ${clientWidth + 2}px; left: ${offsetLeft + this.leftOffset + clientLeft - 1}px;`
}
},
jumpPage (item) {
this.$router.push({
path: this.tabs[item.index].path,
query: {
t: +new Date(),
tabIndex: this.currentTab
}
})
}
},
mounted () {
// setTimeout(() => {
this.$nextTick(() => {
this.handleActiveBar(this.currentTab)
})
// }, 120)
}
}
</script>

View File

@@ -1,37 +1,57 @@
<template>
<div
class="entity-explorer entity-explorer--show-list"
>
<div class="entity-explorer entity-explorer--show-list">
<!-- 顶部工具栏在列表页显示 -->
<div class="explorer-top-tools">
<DateTimeRange class="date-time-range" :start-time="timeFilter.startTime" :end-time="timeFilter.endTime" :date-range="timeFilter.dateRangeValue" ref="dateTimeRange" @change="reload"/>
<TimeRefresh class="date-time-range" @change="timeRefreshChange" :end-time="timeFilter.endTime"/>
<div class="explorer-top-tools explorer-detection-top-tools">
<div class="explorer-top-tools-title">{{$t('overall.detections')}}</div>
<div style="display: flex">
<div class="explorer-top-tools-block">
<i class="cn-icon cn-icon-setting detection-icon-setting"></i>
<span>Configure Policies</span>
</div>
<DateTimeRange
class="date-time-range"
:start-time="timeFilter.startTime"
:end-time="timeFilter.endTime"
:date-range="timeFilter.dateRangeValue"
ref="dateTimeRange"
@change="reload"/>
<TimeRefresh
class="date-time-range"
@change="timeRefreshChange"
:end-time="timeFilter.endTime"/>
</div>
</div>
<div style="width: 100%;padding-bottom: 26px;">
<detection-tabs :time-filter="timeFilter" :chart="tabsData" />
</div>
<!-- 搜索组件 -->
<detection-search
class="detection-border"
ref="search"
:page-type="pageType"
@search="search"
></detection-search>
<!-- 内容区 -->
<div class="explorer-container" style="height: calc(100% - 20px); flex-direction: column">
<div class="explorer-container" style="height: calc(100% - 20px);flex-direction: column">
<loading :loading="loading"></loading>
<template v-if="isEventSeverityNoData">
<div class="no-data detection__event-severity-bar" >No data</div>
</template>
<template v-if="!isEventSeverityNoData">
<div class="detection__event-severity-bar" :id="`eventSeverityTrendBar${pageType}`">
<div class="detection__event-severity-bar detection-border" :id="`eventSeverityTrendBar${pageType}`">
</div>
</template>
<div style="display: flex; flex-grow: 1; height: 100%;">
<detection-filter
class="detection-border"
:filter-data="filterData[pageType]"
:q="q"
:time-filter="timeFilter"
></detection-filter>
<div class="detection__list">
<div class="detection__list-statistics">
<div class="detection__list-statistics detection-border">
<div class="statistics__severity">
<div class="chart-header">
<div class="chart-header__title">{{$t('detection.severity')}}</div>
@@ -81,15 +101,14 @@
></detection-list>
<div class="entity__pagination" >
<Pagination
ref="pagination"
:page-obj="pageObj"
@pageNo='pageNo'
@pageSize='pageSize'
@size-change="pageSize"
@prev-click="prev"
@next-click="next"
>
</Pagination>
ref="pagination"
:page-obj="pageObj"
@pageNo='pageNo'
@pageSize='pageSize'
@size-change="pageSize"
@prev-click="prev"
@next-click="next"
></Pagination>
</div>
</div>
</div>
@@ -108,12 +127,13 @@ import { defaultPageSize, detectionPageType } from '@/utils/constants'
import { getNowTime, getSecond, rTime } from '@/utils/date-util'
import { ref, shallowRef } from 'vue'
import * as echarts from 'echarts'
import { multipleBarOption, pieForSeverity, activeAttackBar, getAttackColor, getSeverityColor, getSeriesIndex } from '@/views/detections/options/detectionOptions'
import { multipleBarOption, pieForSeverity, activeAttackBar, getAttackColor, getSeverityColor } from '@/views/detections/options/detectionOptions'
import { api, getData } from '@/utils/api'
import { reverseSortBy, sortBy, extensionEchartY } from '@/utils/tools'
import { reverseSortBy, extensionEchartY } from '@/utils/tools'
import { useRoute } from 'vue-router'
import DetectionNoData from '@/views/detections/DetectionNoData'
// import DetectionNoData from '@/views/detections/DetectionNoData'
import Loading from '@/components/common/Loading'
import DetectionTabs from '@/views/detections/DetectionTabs'
export default {
name: 'Index',
@@ -125,10 +145,31 @@ export default {
DetectionFilter,
DetectionList,
Pagination,
DetectionNoData
// DetectionNoData,
DetectionTabs
},
data () {
return {
tabsData: [
{
name: 'SecurityEvents',
i18n: 'entities.securityEvents',
path: '/detection/securityEvent',
icon: 'cn-icon cn-icon-a-SecurityEvent'
},
{
name: 'Regulatory Risk Event',
i18n: 'entities.regulatoryRiskEvents',
path: '/detection/securityEvent',
icon: 'cn-icon cn-icon-a-RegulatoryRiskEvent'
},
{
name: 'PerformanceEvents',
i18n: 'overall.performanceEvents',
path: '/detection/performanceEvent',
icon: 'cn-icon cn-icon-a-PerformanceEvent'
}
],
chartInit: [],
pageObj: {
pageNo: 1,
@@ -231,7 +272,6 @@ export default {
isStatisticsCategoryNoData: false,
isStatisticsActiveAttackNoData: false,
loading: false,
oldActiveEntitySearchValue: ''
}
},
@@ -258,7 +298,7 @@ export default {
const eventSeverityTrendOption = this.$_.cloneDeep(multipleBarOption)
const xData = []
dataMap.forEach(function (value, key) {
dataMap.forEach(function (value) {
// eventSeverityTrendOption.series[Number(getSeriesIndex(key))].data = value.map(v => Number(v[1]))
value.forEach(item => {
if (xData.indexOf(item[0]) < 0) {
@@ -270,8 +310,10 @@ export default {
const seriesData = []
xData.forEach(item => {
if (dataMap.has(serie.name)) {
// todo 下面这行注释可解决eslint报红线的问题暂不知道原因后续解决
// eslint-disable-next-line array-callback-return
const hasX = dataMap.get(serie.name).some(function (v) {
if (item == v[0]) {
if (item === v[0]) {
seriesData.push(Number(v[1]))
return true
}
@@ -296,7 +338,7 @@ export default {
// this.isEventSeverityNoData = true
}
}).catch(error => {
console.log(error)
}).finally(() => {
this.$nextTick(() => {
this.loading = false
@@ -329,7 +371,7 @@ export default {
})
}
}).catch(error => {
console.log(error)
})
},
initEventTypeData (params) {
@@ -357,7 +399,7 @@ export default {
})
}
}).catch(error => {
console.log(error)
})
},
initSecurityTypeData (params) {
@@ -385,7 +427,7 @@ export default {
})
}
}).catch(error => {
console.log(error)
})
},
initOffenderIpData (params) {
@@ -419,7 +461,7 @@ export default {
})
}
}).catch(error => {
console.log(error)
})
},
@@ -430,7 +472,7 @@ export default {
this.filterData[this.pageType][2].showMore = showMore
this.filterData[this.pageType][2].showIndex = showIndex
}).catch(error => {
console.log(error)
})
},
initVictimLocationData (params) {
@@ -440,7 +482,7 @@ export default {
this.filterData[this.pageType][3].showMore = showMore
this.filterData[this.pageType][3].showIndex = showIndex
}).catch(error => {
console.log(error)
})
},
initOffenderLocationData (params) {
@@ -450,7 +492,7 @@ export default {
this.filterData[this.pageType][5].showMore = showMore
this.filterData[this.pageType][5].showIndex = showIndex
}).catch(error => {
console.log(error)
})
},
initActiveEntity (params) {
@@ -510,6 +552,7 @@ export default {
})
}
}).catch(error => {
console.log(error)
})
},
triggerFilterDataValue (array, value) {
@@ -539,12 +582,12 @@ export default {
getData(api.detection[this.pageType].listBasic, params).then(data => {
this.listData = data
}).catch(error => {
console.log(error)
})
getData(api.detection[this.pageType].listCount, params).then(data => {
this.pageObj.total = data
}).catch(error => {
console.log(error)
})
},
timeRefreshChange () {
@@ -720,7 +763,7 @@ export default {
}
}
},
timeFilter (n) {
timeFilter () {
this.search(this.metaList, this.q)
},
'filterData.securityEvent.0.value': {

View File

@@ -46,7 +46,7 @@
<div class="overview__title">{{$t('detections.goToEntity')}}</div>
<div class="overview__row">
<div class="row__content">
<span>{{ $t('detections.viewDetailOf') }}</span> &nbsp;
<span class="row__content--span">{{ $t('detections.viewDetailOf') }}</span> &nbsp;
<span
class="row__content--link"
@click="goDetail('app', detection.appName)">{{detection.appName}}</span>

View File

@@ -49,7 +49,7 @@
<div class="overview__title">{{$t('detections.goToEntity')}}</div>
<div class="overview__row">
<div class="row__content">
<span>{{ $t('detections.viewDetailOf') }}</span> &nbsp;
<span class="row__content--span">{{ $t('detections.viewDetailOf') }}</span> &nbsp;
<span
class="row__content--link"
@click="goDetail('domain', computeSecondaryDomain(detection.domain))">{{detection.domain}}</span>

View File

@@ -40,7 +40,7 @@
<div class="overview__title">{{$t('detections.goToEntity')}}</div>
<div class="overview__row">
<div class="row__content">
<span>{{ $t('detections.viewDetailOf') }}</span> &nbsp;
<span class="row__content--span">{{ $t('detections.viewDetailOf') }}</span> &nbsp;
<span
class="row__content--link"
@click="goDetail('ip', detection.serverIp)">{{detection.serverIp}}</span>

View File

@@ -164,7 +164,7 @@
<div class="overview__title">{{ $t('detections.goToVictim') }}</div>
<div class="overview__row">
<div class="row__content">
<span>{{ $t('detections.viewDetailOf') }}</span> &nbsp;
<span class="row__content--span">{{ $t('detections.viewDetailOf') }}</span> &nbsp;
<span
class="row__content--link"
@click="goDetail('ip', basicInfo.victimIp)">{{ basicInfo.victimIp }}</span>
@@ -173,7 +173,7 @@
<div class="overview__title">{{ $t('detections.goToOffender') }}</div>
<div class="overview__row">
<div class="row__content">
<span>{{ $t('detections.viewDetailOf') }}</span> &nbsp;
<span class="row__content--span">{{ $t('detections.viewDetailOf') }}</span> &nbsp;
<span
class="row__content--link"
@click="goDetail('ip', basicInfo.offenderIp)"

View File

@@ -143,7 +143,6 @@ import { api } from '@/utils/api'
import { getNowTime, getSecond } from '@/utils/date-util'
import { ref } from 'vue'
import _ from 'lodash'
import Pagination from '@/components/common/Pagination'
import Loading from '@/components/common/Loading'
export default {
@@ -154,8 +153,7 @@ export default {
DateTimeRange,
TimeRefresh,
EntityFilter,
EntityList,
Pagination
EntityList
},
data () {
return {
@@ -345,7 +343,9 @@ export default {
loadingIpActive: false,
// 实体详情列表页面 左侧筛选条件
loadingLeft: false
loadingLeft: false,
initFlag: false, // 初始化标志避免初始化时pageSize和pageNo会调用搜索
timer: null // 初始化标志的延时器,需要销毁
}
},
methods: {
@@ -463,16 +463,36 @@ export default {
this.queryFilter({ entityType: 'dns', ...this.timeFilter })
this.queryList({ ...this.pageObj, ...this.timeFilter })
this.queryListTotal({ ...this.timeFilter })
// todo 当前页面选择其他值,重刷界面仍会被重置,后续记得添加上
// 延时一秒避免初始化时pageSize为20pageNo为1也会调用“搜索”的情况
if (!this.initFlag) {
this.timer = setTimeout(() => {
this.initFlag = true
}, 1000)
}
}
},
pageSize (val) {
this.pageObj.pageSize = val
this.search({ metaList: this.metaList, q: this.q })
if (this.initFlag) {
this.search({ metaList: this.metaList, q: this.q })
} else {
if (val !== 20) {
this.search({ metaList: this.metaList, q: this.q })
}
}
},
pageNo (val) {
this.pageObj.pageNo = val
this.pageObj.resetPageNo = false
this.search({ metaList: this.metaList, q: this.q })
if (this.initFlag) {
this.search({ metaList: this.metaList, q: this.q })
} else {
if (val !== 1) {
this.search({ metaList: this.metaList, q: this.q })
}
}
},
// 点击上一页箭头
prev () {
@@ -703,6 +723,9 @@ export default {
return {
timeFilter
}
},
beforeUnmount () {
clearTimeout(this.timer)
}
}
</script>