Compare commits

...

88 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
70 changed files with 2922 additions and 1135 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

@@ -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

@@ -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

@@ -3,7 +3,7 @@
.network-overview-apps-header {
display: flex;
justify-content: space-between;
//justify-content: space-between;
.network-overview-apps-title {
font-size: 14px;

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,18 @@
.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;

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

@@ -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,7 +62,10 @@
.row__content {
display: flex;
color: #3976CB;
//color: #3976CB;
color: #046ECA;
font-weight: 500;
font-size: 14px;
&.row__content--link {
font-style: italic;
@@ -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;z-index: 99" 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">
@@ -76,7 +76,7 @@
</template>
<script>
import { ref, computed } from 'vue'
import { ref, computed, watch, reactive } from 'vue'
import { storageKey } from '@/utils/constants'
import { getMillisecond, timestampToList } from '@/utils/date-util'
import { useStore } from 'vuex'
@@ -157,6 +157,21 @@ export default {
// refs
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
/**
* 打开/关闭时间面板
@@ -256,6 +271,7 @@ export default {
myEndTime,
dropdownFlag,
utcStr,
rangeEchartsData,
address,
dateRangeArr,
dateRangeValue,

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,16 +58,17 @@
@hide="hideBreadcrumbPopover()"
trigger="click">
<template #reference>
<div class="breadcrumb-button" id="breadcrumbButton" :class="showBackground?'breadcrumb-button__active':''" >
<div class="breadcrumb-button" id="breadcrumbButton"
:class="showBackground?'breadcrumb-button__active':''">
<span id="breadcrumbValue">
<template v-if="curTabProp === 'qtype'">
<span>{{dnsQtypeMapData.get(item) ? dnsQtypeMapData.get(item):item}}</span>
<span>{{ dnsQtypeMapData.get(item)}}</span>
</template>
<template v-else-if="curTabProp === 'rcode'">
<span>{{dnsRcodeMapData.get(item) ? dnsRcodeMapData.get(item):item}}</span>
<span>{{ dnsRcodeMapData.get(item)}}</span>
</template>
<template v-else>
<span>{{item}}</span>
<span>{{ item }}</span>
</template>
</span><i class="cn-icon-xiala cn-icon"></i>
</div>
@@ -74,15 +81,16 @@
@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?'':''">
<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) ? dnsQtypeMapData.get(item):item}}</span>
<span>{{ dnsQtypeMapData.get(item) }}</span>
</template>
<template v-else-if="curTabProp === 'rcode'">
<span>{{dnsRcodeMapData.get(item) ? dnsRcodeMapData.get(item):item}}</span>
<span>{{ dnsRcodeMapData.get(item) }}</span>
</template>
<template v-else>
<span>{{item}}</span>
<span>{{ item }}</span>
</template>
</li>
</ul>
@@ -91,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>
@@ -140,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>
@@ -188,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>
@@ -197,14 +210,10 @@
</template>
<script>
import { useRoute } from 'vue-router'
import { get, put } from '@/utils/http'
import {
curTabState,
dbDrilldownTableConfig,
entityType,
networkOverviewSearchUrl,
networkOverviewTabList,
networkTable,
operationType,
storageKey,
@@ -213,9 +222,17 @@ import {
} from '@/utils/constants'
import { api } from '@/utils/api'
import { ref } from 'vue'
import { combineTabList, getDefaultCurTab, getTabList, overwriteUrl, urlParamsHandler, combinDrilldownTableWithUserConfig,getDnsMapData } 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',
@@ -238,17 +255,32 @@ 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:[],
dnsQtypeMapData:[],
isDnsMapType:false,
curTabProp: '',
dnsRcodeMapData: new Map(),
dnsQtypeMapData: new Map(),
isDnsMapType: false,
valueMeta: [],
showBackground: false,
selected: false,
@@ -297,10 +329,21 @@ export default {
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
})
})
}
})
@@ -339,14 +382,24 @@ export default {
},
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下拉框选择
@@ -377,25 +430,25 @@ export default {
window.location.reload()
})
},
getCurTabByLabel(label){
getCurTabByLabel (label) {
let curTab = null
let tableType = this.$route.params ? this.$route.params.typeName : 'networkOverview'
let curTableInCode = networkTable[tableType] ? networkTable[tableType] : networkTable.networkOverview
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的数据字典
// 是否需要dns的qtype和rcode的数据字典
this.curTabProp = this.$route.query.dimensionType ? this.$route.query.dimensionType : null
let currentValue = document.getElementById('breadcrumbValue') ? document.getElementById('breadcrumbValue').innerText : ''
let columnName = this.getUrlParam(this.curTabState.thirdMenu, '')
const currentValue = document.getElementById('breadcrumbValue') ? document.getElementById('breadcrumbValue').innerText : ''
const columnName = this.getUrlParam(this.curTabState.thirdMenu, '')
let type = 'ip'
let tableType = this.$route.params ? this.$route.params.typeName : 'networkOverview'
let curTableInCode = networkTable[tableType] ? networkTable[tableType] : networkTable.networkOverview
const tableType = this.$route.params ? this.$route.params.typeName : 'networkOverview'
const curTableInCode = networkTable[tableType] ? networkTable[tableType] : networkTable.networkOverview
if (curTableInCode && curTableInCode.tabList) {
let curTab = curTableInCode.tabList.find(item => item.label == columnName)
const curTab = curTableInCode.tabList.find(item => item.label == columnName)
if (curTab) {
type = curTab.prop
}
@@ -410,16 +463,18 @@ export default {
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) {
let itemName = item
if(this.curTabProp === 'qtype'){
if (this.curTabProp === 'qtype') {
itemName = this.dnsQtypeMapData.get(item)
}else if(this.curTabProp === 'rcode'){
} else if (this.curTabProp === 'rcode') {
itemName = this.dnsRcodeMapData.get(item)
}
if (itemName === currentValue) {
@@ -454,34 +509,31 @@ 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)
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', valName)
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)
let curTab = this.getCurTabByLabel()
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_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.replaceAll("'", "\\\\'") + "'")
queryCondition.push(item + '=\'' + handleSpecialValue(value) + '\'')
})
this.urlChangeParams[this.curTabState.queryCondition] = queryCondition.join(' OR ')
}
@@ -495,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
@@ -517,7 +572,7 @@ 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'
const drillDownTableConfigs = await combinDrilldownTableWithUserConfig()
const currentTableConfig = drillDownTableConfigs.find(config => config.route === tableType)
@@ -546,8 +601,10 @@ export default {
this.urlChangeParams[this.curTabState.tabOperationBeforeType] = this.getUrlParam(this.curTabState.tabOperationType, '', true)
this.urlChangeParams[this.curTabState.tabOperationType] = opeType
if (opeType === 3) {
if (route !== '/panel/networkOverview') {
this.urlChangeParams.queryCondition = ''
}
}
} else {
this.urlChangeParams[this.curTabState.tabOperationType] = operationType.mainMenu
}
@@ -564,18 +621,18 @@ 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)
//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
// 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 = ''
child.columnName = columnName
this.urlChangeParams[this.curTabState.thirdMenu] = columnName
this.urlChangeParams[this.curTabState.fourthMenu] = ''
this.urlChangeParams[this.curTabState.panelName] = columnValue
this.urlChangeParams[this.curTabState.panelName] = columnName
const tableType = this.$route.params ? this.$route.params.typeName : 'networkOverview'
const metric = this.getUrlParam(this.curTabState.tableMetric, 'Bits/s')
const curTab = getDefaultCurTab(tableType, metric, columnName)
@@ -605,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

@@ -20,6 +20,7 @@ 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()
@@ -46,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

@@ -55,7 +55,11 @@ const panel = {
timeRangeArray: [], // 时间范围列表:开始/结束时间
timeRangeFlag: null, // 时间范围标志默认60即一小时-1为手动选择的时间范围
routerPath: '', // 当前路由路径
httpCancel: null // 终止http请求
httpCancel: null, // 终止http请求
rangeEchartsData: {}, // 框选echarts图表
routerHistoryList: [], // 路由跳转记录列表
dnsQtypeMapData:[],
dnsRcodeMapData:[]
},
mutations: {
setShowRightBox (state, flag) {
@@ -106,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
},
@@ -162,6 +145,12 @@ const panel = {
},
setHttpCancel (state, cancel) {
state.httpCancel = cancel
},
setRangeEchartsData (state, data) {
state.rangeEchartsData = data
},
setRouterHistoryList (state, list) {
state.routerHistoryList = list
}
},
getters: {
@@ -207,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
},
@@ -254,6 +222,9 @@ const panel = {
},
getRouterPath (state) {
return state.routerPath
},
getRouterHistoryList (state) {
return state.routerHistoryList
}
},
actions: {

View File

@@ -3,7 +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 { readDrilldownTableConfigByUser } from '@/utils/tools'
import { getConfigVersion } from '@/utils/tools'
import { api } from '@/utils/api'
import { db } from '@/indexedDB'
@@ -94,8 +94,14 @@ const user = {
const defaultConfigs = JSON.parse(res.page.list[0].cvalue)
await db[dbDrilldownTableConfig].put({
id: 'default',
config: defaultConfigs
version: defaultConfigs.version,
config: defaultConfigs.config
})
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

@@ -172,6 +172,8 @@ export const api = {
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',

View File

@@ -291,7 +291,8 @@ export const curTabState = {
fourthPanel: 'fourthPanel',
networkOverviewBeforeTab: 'networkOverviewBeforeTab',
tabOperationType: 'tabOperationType',
tabOperationBeforeType: 'tabOperationBeforeType'
tabOperationBeforeType: 'tabOperationBeforeType',
tabIndex: 'tabIndex'
}
export const scoreUrl = [
@@ -652,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
}
]
@@ -784,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 = [
@@ -915,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 = [

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,getDictList } from '@/utils/api'
import { getIso36112JsonData, getDictList } from '@/utils/api'
import { format } from 'echarts'
import router from '@/router'
import { db } from '@/indexedDB'
@@ -840,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 : []
@@ -855,29 +854,35 @@ export function getTabList (curTable, curMetric) {
}
return tabs
}
export async function getDnsMapData(type){
let codeValueMap = new Map()
const dnsData = await getDictList({ type:type,pageSize: -1 })
if(dnsData && dnsData.length>0) {
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 => {
let code = mapData.code
if(code.indexOf('-')>-1){
let range = mapData.code.split('-')
if(range && range.length >= 2){
let start = range[0].trim()
let eEnd = range[1].trim()
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)
codeValueMap.set(i, mapData.value)
}
}
}else {
codeValueMap.set(code,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 : []
@@ -927,7 +932,7 @@ export async function getDefaultCurTab (tableType, metric, columnName) {
return curTab
}
export async function readDrilldownTableConfigByUser (tableType, curMetric) {
export async function readDrilldownTableConfigByUser () {
// 获取用户定制的自定义配置
const userId = localStorage.getItem(storageKey.userId)
const userLocalCongfig = await db[dbDrilldownTableConfig].get({ id: userId })
@@ -938,6 +943,17 @@ export async function readDrilldownTableConfigByUser (tableType, curMetric) {
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' })
}
return version
}
export async function combinDrilldownTableWithUserConfig () {
const defaultCongfigInDb = await db[dbDrilldownTableConfig].get({ id: 'default' })
const defaultConfigs = defaultCongfigInDb ? defaultCongfigInDb.config : []
@@ -951,8 +967,10 @@ export async function combinDrilldownTableWithUserConfig () {
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
}
})
}
})
@@ -960,40 +978,6 @@ export async function combinDrilldownTableWithUserConfig () {
return defaultConfigs
}
/*
export async function readDrilldownTableConfigByUser2 (tableType, curMetric) {
let list = []
// 获取用户定制的自定义配置,如果没有,则使用默认的自定义配置
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){
const currentTableConfig = defaultDrillDownTableConfigs.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 : []
}
//combineTabList(tableType, list, commonTabList)
}
}
}
}
return list
}
*/
export async function getUserDrilldownTableConfig (tableType, curMetric) {
let list = []
// 获取用户定制的自定义配置,如果没有,则使用默认的自定义配置

View File

@@ -3,7 +3,7 @@
<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}}
@@ -61,14 +61,16 @@ import {
panelTypeAndRouteMapping,
curTabState,
drillDownPanelTypeMapping,
metricOptions
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 { urlParamsHandler, overwriteUrl,getDnsMapData } 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 {
name: 'Panel',
@@ -94,30 +96,41 @@ export default {
}
},
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
let pName = this.$route.query.panelName ? this.$t(this.$route.query.panelName) : ''
let curTabProp = this.$route.query.dimensionType ? this.$route.query.dimensionType : null
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')
if(curTabProp === 'qtype'){
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'){
} else if (curTabProp === 'rcode') {
this.panelName = this.dnsRcodeMapData.get(pName)
}else {
} else {
this.panelName = pName
}
@@ -183,14 +196,16 @@ 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
// 进入页面时,发现有未结束的请求,终止请求
// console.log('panel.vue------setup------查看http终止情况', cancelList, cancelList.length)
if (cancelList.length > 0) {
cancelList.forEach((cancel, index) => {
cancel()
@@ -200,19 +215,20 @@ export default {
const panel = ref({})
let panelType = 1 // 取得panel的type
const { params, query, path } = useRoute()
// 只要当前路由和vuex里的路由一致且vuex存储的range有值即代表已经下钻后返回此时直接使用vuex里存储的时间范围
if (path === store.getters.getRouterPath && store.getters.getTimeRangeFlag !== null) {
const newUrl = urlParamsHandler(window.location.href, query, {
startTime: store.getters.getTimeRangeArray[0],
endTime: store.getters.getTimeRangeArray[1],
range: store.getters.getTimeRangeFlag
})
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)
} else {
store.commit('setTimeRangeArray', [])
store.commit('setTimeRangeFlag', null)
}
const thirdPanel = query.thirdPanel
const fourthPanel = query.fourthPanel
if (fourthPanel) {
@@ -231,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) {
@@ -241,19 +258,29 @@ export default {
timeFilter.value.startTime = parseInt(startTimeParam)
timeFilter.value.endTime = parseInt(endTimeParam)
}
store.commit('setRouterPath', path)
// 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,
metric
metric,
path,
queryCondition,
dimensionType,
tabOperationType,
networkOverviewBeforeTab
}
},
methods: {
@@ -323,7 +350,88 @@ export default {
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 {
@@ -195,15 +198,17 @@ export default {
}
get(url, params).then((res) => {
if (res.code === 200) {
this.showError = false
this.isNoData = res.data.result.length === 0
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, i) => {
res.data.result.forEach((t) => {
if (t.type === 'bytes' && val === 'Bits/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalBitsRate.analysis
@@ -215,7 +220,7 @@ export default {
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 {
@@ -225,7 +230,7 @@ export default {
}
}
if (this.lineTab === e.class) {
if (e.analysis.avg <= 0) {
if (parseFloat(e.analysis.avg) <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
@@ -243,6 +248,7 @@ export default {
} else {
this.$nextTick(() => {
this.echartsInit(this.mpackets, show)
if (!this.lineRefer) this.lineRefer = 'Average'
})
}
} else if (t.type === 'queries' && val === 'Queries/s') {
@@ -264,10 +270,16 @@ export default {
})
}
})
} 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)
})
@@ -293,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: {
@@ -337,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 = []
})
@@ -375,19 +387,20 @@ export default {
}
})
})
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)
},
@@ -437,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')
@@ -452,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
@@ -230,7 +242,7 @@ export default {
directionArr.push(item.ingressLinkDirection)
}
})
directionArr = [...new Set(directionArr)]
directionArr = Array.from(new Set(directionArr))
const newNextHopData = []
@@ -274,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)
})
@@ -365,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,47 +74,28 @@ export default {
return a.egressLinkId - b.egressLinkId
})
// 链路下一跳信息
const nextLinkData = res[1].data.result
// 接口数据乱序,根据出方向排序,再根据同个出方向下的入进行排序
nextLinkData.sort((a, b) => {
if (a.ingressLinkDirection !== b.ingressLinkDirection) {
return a.ingressLinkDirection.localeCompare(b.ingressLinkDirection)
}
return a.egressLinkDirection.localeCompare(b.egressLinkDirection)
})
this.isNoData = linkData.length === 0 && nextLinkData.length === 0
if (this.isNoData) {
return
}
this.isLinkNoData = linkData.length === 0
if (!this.isLinkNoData) {
// 链路流量数据
const gridData = []
// 链路下一跳数据
const gridData2 = []
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 = gridData.find(g => g.linkId === ingressLink.linkId)
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 = false
if (egressUsage >= 0.9 || ingressUsage >= 0.9) {
d.usageMore90 = true
}
d.usageMore90 = egressUsage >= 0.9 || ingressUsage >= 0.9
// 计算npm分数
// 分数低于3分赋红点
d.score = this.localComputeScore(d)
d.scoreLow3 = false
if (d.score < 3) {
d.scoreLow3 = true
}
d.scoreLow3 = d.score < 3
if (data) {
const existedEgressLink = data.egress.find(e => e.linkId === egressLink.linkId)
@@ -125,7 +111,7 @@ export default {
})
}
} else {
gridData.push({
linkGridData.push({
linkId: ingressLink.linkId,
egress: [{
linkId: egressLink.linkId,
@@ -141,14 +127,38 @@ export default {
}
})
this.gridData = gridData
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
// 接口数据乱序,根据出方向排序,再根据同个出方向下的入进行排序
nextLinkData.sort((a, b) => {
if (a.ingressLinkDirection !== b.ingressLinkDirection) {
return a.ingressLinkDirection.localeCompare(b.ingressLinkDirection)
}
return a.egressLinkDirection.localeCompare(b.egressLinkDirection)
})
this.isNextNoData = nextLinkData.length === 0
if (!this.isNextNoData) {
// 链路下一跳数据
const nextGridData = []
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')
if (ingressLink && egressLink) {
const data = gridData2.find(g => g.linkId === ingressLink.linkId)
const data = nextGridData.find(g => g.linkId === ingressLink.linkId)
let egressBanwidth = 0
let ingressBanwidth = 0
@@ -166,17 +176,13 @@ export default {
// 下行使用情况计算
const ingressUsage = this.computeUsage(d.ingressBitsRate, ingressBanwidth)
// 宽带使用超过90%,赋红点
d.usageMore90 = false
if (egressUsage >= 0.9 || ingressUsage >= 0.9) {
d.usageMore90 = true
}
d.usageMore90 = egressUsage >= 0.9 || ingressUsage >= 0.9
// 计算npm分数
// 分数低于3分赋红点
d.score = this.localComputeScore(d)
d.scoreLow3 = false
if (d.score < 3) {
d.scoreLow3 = true
}
d.scoreLow3 = d.score < 3
if (data) {
const existedEgressLink = data.egress.find(e => e.linkId === egressLink.linkId)
@@ -193,7 +199,7 @@ export default {
})
}
} else {
gridData2.push({
nextGridData.push({
linkId: ingressLink.linkId,
nextHop: ingressLink.nextHop,
egress: [{
@@ -211,13 +217,23 @@ export default {
}
})
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,7 +251,7 @@ export default {
/**
* 本地计算npm分数
*/
localComputeScore (data, bandwidth) {
localComputeScore (data) {
let score = 0
const dataScore = {
establishLatencyMs: data.establishLatencyMs || null,

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,15 +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
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, i) => {
res.data.result.forEach((t) => {
if (t.type === 'bytes' && val === 'Bits/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalBitsRate.analysis
@@ -196,7 +200,7 @@ export default {
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 {
@@ -206,7 +210,7 @@ export default {
}
}
if (this.lineTab === e.class) {
if (e.analysis.avg <= 0) {
if (parseFloat(e.analysis.avg) <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
@@ -224,6 +228,7 @@ export default {
} else {
this.$nextTick(() => {
this.echartsInit(this.mpackets)
if (!this.lineRefer) this.lineRefer = 'Average'
})
}
} else if (t.type === 'packets' && val === 'Packets/s') {
@@ -237,7 +242,7 @@ export default {
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 {
@@ -247,7 +252,7 @@ export default {
}
}
if (this.lineTab === e.class) {
if (e.analysis.avg <= 0) {
if (parseFloat(e.analysis.avg) <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
@@ -265,14 +270,22 @@ export default {
} 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
})
@@ -298,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: {
@@ -334,19 +347,21 @@ export default {
}
})
})
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)
},
@@ -396,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')
@@ -411,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.$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,6 +1,9 @@
<template>
<div class="link-traffic-list">
<loading :loading="loading"></loading>
<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>
@@ -35,6 +38,7 @@
<div class="link-traffic-list-center-value">{{unitConvert(linkTrafficListData.pktRetransPercent, unitTypes.percent).join('')}}</div>
</div>
</div>
</div>
</template>
<script>
@@ -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,6 +138,7 @@ 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 data = {
establishLatencyMs: res.data.result[0].establishLatencyMs || null,
@@ -139,10 +149,17 @@ export default {
}
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

@@ -2,10 +2,11 @@
<div class="network-overview-apps">
<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" @mouseenter="mouseenter(app)" @mouseleave="mouseleave(app)" 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>
@@ -137,6 +138,7 @@ export default {
mixins: [chartMixin],
data () {
return {
testData: '测试值',
appData: [],
// 假数据
appTempData: [],
@@ -163,7 +165,9 @@ export default {
timerSearch: null,
loadingBody: false,
curTabState: curTabState,
urlChangeParams: {}
urlChangeParams: {},
showError: false,
errorMsg: ''
}
},
props: {
@@ -221,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)
@@ -233,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)
@@ -254,6 +258,7 @@ export default {
})
}
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'
@@ -281,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)
@@ -400,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'
}
])
}
@@ -461,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) {
@@ -486,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))
@@ -728,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">
@@ -44,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>
@@ -65,9 +70,11 @@ 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: {
@@ -81,10 +88,14 @@ export default {
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 {
lineRefer,
lineTab,
queryCondition,
tabOperationType,
networkOverviewBeforeTab,
myChart: shallowRef(null)
}
},
@@ -121,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: {
@@ -143,7 +158,7 @@ export default {
overwriteUrl(newUrl)
},
timeFilter: {
handler (n) {
handler () {
if (this.lineTab) {
this.init(this.metric, this.showMarkLine, 'active')
} else {
@@ -154,7 +169,7 @@ export default {
metric (n) {
this.handleActiveBar()
this.showMarkLine = !this.showMarkLine
this.mpackets.forEach((e, i) => {
this.mpackets.forEach((e) => {
if (!e.invertTab) {
e.invertTab = true
}
@@ -171,16 +186,34 @@ export default {
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
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: '' },
@@ -190,7 +223,7 @@ export default {
{ analysis: {}, name: 'network.other', class: 'other', show: true, invertTab: true, positioning: 5, data: [], unitType: '' }
]
}
res.data.result.forEach((t, i) => {
res.data.result.forEach((t) => {
if (t.type === 'bytes' && val === 'Bits/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalBitsRate.analysis
@@ -208,7 +241,7 @@ export default {
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 {
@@ -218,7 +251,7 @@ export default {
}
}
if (this.lineTab === e.class) {
if (e.analysis.avg <= 0) {
if (parseFloat(e.analysis.avg) <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
@@ -237,6 +270,7 @@ export default {
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') {
@@ -256,7 +290,7 @@ export default {
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 {
@@ -266,7 +300,7 @@ export default {
}
}
if (this.lineTab === e.class) {
if (e.analysis.avg <= 0) {
if (parseFloat(e.analysis.avg) <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
@@ -285,6 +319,7 @@ export default {
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') {
@@ -306,14 +341,41 @@ export default {
})
}
})
} 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()
@@ -322,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) => {
@@ -335,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: {
@@ -379,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 = []
})
@@ -421,15 +488,65 @@ export default {
return str
}
this.showMarkLine = true
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.metric, this.showMarkLine, 'active')
},
mouseenter (item) {
if (this.isNoData) return
this.mousemoveCursor = item.class
this.handleActiveBar(item.class)
},
@@ -479,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')
@@ -540,9 +657,27 @@ 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)
@@ -558,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" @click="routerJump">{{$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,7 +141,15 @@ 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
})
@@ -163,6 +193,8 @@ export default {
beforeUnmount () {
clearTimeout(this.timer)
window.removeEventListener('resize', this.resize)
this.myChart = null
this.myChart2 = null
}
}
</script>

View File

@@ -1,7 +1,7 @@
<template>
<div class="tabs" :style="showCustomizeTabs ? (tableData.length > 10 && showRecordNum === 10 ? 'height: calc(100% - 40px);'
<div class="tabs" :style="showCustomizeTabs ? (tableData.length > 10 && showRecordNum === 10 ? 'height: calc(100% - 36px);'
: 'height: calc(100% - 2px)')
: (tableData.length > 10 && showRecordNum === 10 ? 'height: calc(100% - 64px);'
: (tableData.length > 10 && showRecordNum === 10 ? 'height: calc(100% - 77px);'
: 'height: calc(100% - 26px);')">
<el-tabs v-model="activeTab"
:class="showCustomizeTabs?'cn-chart__tabs':'tab-hide cn-chart__tabs cn-chart__tabs-hide-tab'"
@@ -33,7 +33,7 @@
<template v-for="(item, index) in customTableTitles">
<el-table-column
v-if="item.checked"
:sortable="sortable(item)"
:sortable="item.showError ? false : sortable(item)"
align="center"
:prop="item.prop"
class="data-column"
@@ -42,6 +42,7 @@
>
<template #header >
<span class="data-column__span" >{{$t(item.label)}}</span>
<chart-error v-if="item.showError" tooltip :content="item.errorMsg" width="300" />
</template>
<template #default="scope" :column="item">
<template v-if="item.columnType === tableColumnType.chainRatio" >
@@ -82,7 +83,7 @@
</template>
</div>
<div v-else class="data-click" @click="handleTabValue(item.name,scope.row['tab'])">
<template v-if="isDnsMapType">
<template v-if="tableType === fromRoute.dnsServiceInsights && isDnsMapType">
{{dnsMapData.get(scope.row['tab'])}}
</template>
<template v-else>
@@ -123,8 +124,9 @@
</template>
</el-table-column>
</template>
<template v-slot:empty>
<div class="table-no-data" v-if="isNoData">
<template v-slot:empty >
<chart-error v-if="showError" :content="errorMsg" />
<div class="table-no-data" v-else-if="isNoData">
<div class="table-no-data__title">{{ $t('npm.noData') }}</div>
</div>
</template>
@@ -169,7 +171,7 @@
</li>
</transition-group>
</el-tab-pane>
<el-tab-pane :label="$t('network.direction')" name="metrics" width="50%" >
<el-tab-pane :label="tableType==='networkOverview'?$t('network.direction'):$t('network.metrics')" name="metrics" width="50%" >
<transition-group name="dragMetric" class="list" tag="ul" ref="metric">
<template v-for="(item, index) in customTableTitles" :key="item.label">
<li v-if="index>0"
@@ -196,15 +198,15 @@
</template>
<script>
import { ref } from 'vue'
import { operationType, unitTypes, networkTable, tableColumnType, networkDefaultLimit, curTabState, storageKey, dbDrilldownTableConfig,fromRoute } from '@/utils/constants'
import { operationType, unitTypes, networkTable, tableColumnType, networkDefaultLimit, curTabState, storageKey, dbDrilldownTableConfig, fromRoute } from '@/utils/constants'
import { get } from '@/utils/http'
import unitConvert from '@/utils/unit-convert'
import { getChainRatio, computeScore, urlParamsHandler, overwriteUrl, getUserDrilldownTableGeo, readDrilldownTableConfigByUser, combinDrilldownTableWithUserConfig,getDnsMapData } from '@/utils/tools'
import { getChainRatio, computeScore, urlParamsHandler, overwriteUrl, getUserDrilldownTableGeo, readDrilldownTableConfigByUser, combinDrilldownTableWithUserConfig, getDnsMapData,handleSpecialValue,getConfigVersion } from '@/utils/tools'
import { getSecond } from '@/utils/date-util'
import chartMixin from '@/views/charts2/chart-mixin'
import ChartNoData from '@/views/charts/charts/ChartNoData'
import { db } from '@/indexedDB'
import { api,getDictList } from '@/utils/api'
import { api, getDictList } from '@/utils/api'
export default {
name: 'NetworkOverviewTabs',
@@ -250,16 +252,18 @@ export default {
column: {},
index: 0,
chartData: [],
dnsMapData:[],
dnsQtypeMapData:[],
dnsRcodeMapData:[],
isDnsMapType:false,
dnsMapData: new Map(),
dnsQtypeMapData: new Map(),
dnsRcodeMapData: new Map(),
isDnsMapType: false,
tableSortColumn: '',
tableSortType: '',
tableSortTab: '',
urlChangeParams: {},
showUnit: false,
fromRoute: fromRoute,
showError: false,
errorMsg: ''
}
},
props: {
@@ -327,14 +331,20 @@ export default {
const requestUrl = this.getCurUrl()
get(requestUrl, queryParams).then(response => {
if (response.code === 200) {
this.showError = false
this.errorMsg = ''
this.chartData = response.data.result
this.initData()
} else {
this.showError = true
this.errorMsg = response.message || 'Unknown'
this.isNoData = true
this.toggleLoading(false)
}
}).catch(e => {
console.error(e)
this.showError = true
this.errorMsg = e.message || 'Unknown'
}).finally(() => {
this.changeUrlTabState()
this.toggleLoading(false)
@@ -613,8 +623,14 @@ export default {
endTime: getSecond(this.timeFilter.endTime)
}
if (tabList.length > 0) {
const conditionStr = tabList.filter(item => item != '')
queryParams.params = conditionStr.toString().replaceAll("'", "\\\\'")
let conditionGroup = tabList.filter(item => item != '')
let conditionHandleRlt = []
conditionGroup.forEach(condition => {
condition = handleSpecialValue(condition)//condition.replaceAll("'", "\\\\'")
condition = "'"+condition+ "'"
conditionHandleRlt.push(condition)
})
queryParams.params = conditionHandleRlt.join(",")
queryParams.type = curTab.prop
}
@@ -630,6 +646,8 @@ export default {
if (tableColumn.columnType === tableColumnType.chainRatio && tableColumn.isInMainUrl && tableDataTmp && tableDataTmp.length > 0) {
get(self.gerCycleUrl(), queryParams).then(response => {
if (response.code === 200) {
tableColumn.showError = false
tableColumn.errorMsg = ''
cycleTotalList = response.data.result
tableDataTmp.forEach(item => {
const cycle = cycleTotalList.find(i => i[curTab.prop] === item.tab)
@@ -674,9 +692,14 @@ export default {
}
item[tableColumn.prop] = [(item[tableColumn.prop] || item[tableColumn.prop] === 0) ? item[tableColumn.prop] : '', trend, trendPercent]
})
}else {
tableColumn.showError = true
tableColumn.errorMsg = response.message || 'Unknown'
}
}).catch(e => {
console.log(e)
tableColumn.showError = true
tableColumn.errorMsg = e.message || 'Unknown'
}).finally(e => {
this.tableData = tableDataTmp
this.tableDataBackup = tableDataTmp
@@ -689,6 +712,10 @@ export default {
if (tableColumn.columnType === tableColumnType.chainRatio && !tableColumn.isInMainUrl) {
get(self.gerColumnUrl(tableColumn), queryParams).then(response => {
if (response.code === 200) {
if (!tableColumn.showError) {
tableColumn.showError = false
tableColumn.errorMsg = ''
}
const columnList = response.data.result
self.tableData.forEach((item, i) => {
const data = columnList.find(i => i[curTab.prop] === item.tab)
@@ -703,11 +730,19 @@ export default {
}
if (Object.keys(item.scoreGroup).length >= 5) {
item.score = computeScore(item.scoreGroup)
if(!_.isNumber(item.score)){
item.score = 0
}
}
})
}else {
tableColumn.showError = true
tableColumn.errorMsg = response.message || 'Unknown'
}
}).catch(e => {
console.log(e)
tableColumn.showError = true
tableColumn.errorMsg = e.message || 'Unknown'
}).finally(e => {
// 查询需要单独查询的,且需要展示环比图标,列的前一周期的数据
if (tableColumn.cycle && self.tableData && self.tableData.length > 0) {
@@ -717,6 +752,10 @@ export default {
}
get(self.gerColumnUrl(tableColumn), queryCycleParams).then(response => {
if (response.code === 200) {
if(!tableColumn.showError){
tableColumn.showError = false
tableColumn.errorMsg = ''
}
cycleTotalList = response.data.result
self.tableData.forEach(item => {
const cycle = cycleTotalList.find(i => i[curTab.prop] === item.tab)
@@ -764,9 +803,14 @@ export default {
item[tableColumn.prop] = [(item[tableColumn.prop] || item[tableColumn.prop] === 0) ? item[tableColumn.prop] : '', trend, trendPercent]
}
})
}else {
tableColumn.showError = true
tableColumn.errorMsg = response.message || 'Unknown'
}
}).catch(e => {
console.log(e)
tableColumn.showError = true
tableColumn.errorMsg = e.message || 'Unknown'
})
}
})
@@ -824,7 +868,7 @@ export default {
this.index = index
this.column = column
const arr = []
this.tableData.slice(0, this.showRecordNum).forEach(val => {
this.tableData.forEach(val => {
arr.push(val)
})
if (column.order == 'descending') {
@@ -866,11 +910,7 @@ export default {
return res
}
})
if (this.tableData.length - 1 > this.showRecordNum) {
this.tableData = arr.concat(this.tableDataBackup.slice(this.showRecordNum))
} else {
this.tableData = arr
}
} else if (column.order == 'ascending') {
arr.sort((a, b) => {
const str1 = Array.isArray(a[column.prop]) ? a[column.prop][0] : a[column.prop]
@@ -910,11 +950,7 @@ export default {
return res
}
})
if (this.tableData.length - 1 > this.showRecordNum) {
this.tableData = arr.concat(this.tableDataBackup.slice(this.showRecordNum))
} else {
this.tableData = arr
}
} else if (!column.order) {
this.tableData = this.tableDataBackup
}
@@ -1075,7 +1111,7 @@ export default {
this.urlChangeParams[this.curTabState.networkOverviewBeforeTab] = tab.prop
},
setQueryCondition (tab, value) {
value = value.replaceAll("'", "\\\\'")
value = handleSpecialValue(value)//value.replaceAll("'", "\\\\'")
const queryCondition = []
if (tab.prop === 'protocolPort') {
const valueGroup = value.split(':')
@@ -1087,7 +1123,7 @@ export default {
} else {
if (tab.queryCondition) {
tab.queryCondition.forEach(item => {
queryCondition.push(item.replace('$param', value))
queryCondition.push(item.replaceAll('$param', value))
})
} else {
if (tab.dillDownProp) {
@@ -1115,8 +1151,10 @@ export default {
4.设置菜单第三级第四级名称并保存到store中
5.设置panel名称表格维度类型如ipdomain等(即查询参数中的type)
* */
handleTabValue (columnName, columnValue) {
async handleTabValue (columnName, columnValue) {
// console.log('NetworkOverview类------handleTabValue下钻')
// 下钻前保存当前路由状态
this.beforeRouterPush()
const clickTab = this.getTabByName(columnName)// 下钻后显示的下钻tab对应的drilldownTabs
const tabLable = clickTab.label
const tabName = clickTab.name
@@ -1155,14 +1193,13 @@ export default {
})
}
this.saveUserLocalConfig()
// console.log(this.drillDownTableConfigs)
await this.saveUserLocalConfig()
let forthMenuName = ''
if(clickTab.prop === 'qtype'){
if (clickTab.prop === 'qtype') {
forthMenuName = this.dnsQtypeMapData.get(columnValue)
}else if(clickTab.prop === 'rcode'){
} else if (clickTab.prop === 'rcode') {
forthMenuName = this.dnsRcodeMapData.get(columnValue)
}else {
} else {
forthMenuName = columnValue
}
this.$store.getters.menuList.forEach(menu => {
@@ -1188,6 +1225,14 @@ export default {
})
}
})
if (!this.getUrlParam(this.curTabState.tabIndex)) {
let thirdMenu = this.urlChangeParams[this.curTabState.thirdMenu]
if(thirdMenu === 'network.serverIps'){
this.urlChangeParams[this.curTabState.tabIndex] = 1
}else if(thirdMenu === 'network.clientIps' || thirdMenu === 'network.ips'){
this.urlChangeParams[this.curTabState.tabIndex] = 0
}
}
this.changeUrlTabState()
this.$router.push({
path: this.$route.path,
@@ -1199,8 +1244,38 @@ export default {
}
})
},
/**
* 在路由跳转前,即下钻前将路由数据保存起来,确保回退和前进保留当时状态
*/
beforeRouterPush () {
const currentRouter = this.$_.cloneDeep(this.$route.query)
const historyList = this.$_.cloneDeep(this.$store.getters.getRouterHistoryList)
const tempObj = {
t: currentRouter.t,
query: currentRouter,
path: this.$_.cloneDeep(this.$route.path),
params: this.$_.cloneDeep(this.$route.params)
}
if (historyList.length > 0) {
let flag = true
historyList.forEach((item, index) => {
if (item.t === currentRouter.t) {
historyList[index] = tempObj
flag = false
}
if (!flag) {
return true
}
})
if (flag) historyList.push(tempObj)
} else {
historyList.push(tempObj)
}
this.$store.commit('setRouterHistoryList', historyList)
},
handleSearchParams (columnValue) {
columnValue = columnValue.replaceAll("'", "\\\\'")
columnValue = handleSpecialValue(columnValue)//columnValue.replaceAll("'", "\\\\'")
const queryCondition = []
const curTab = this.getCurTab()
if (curTab.prop === 'protocolPort') {
@@ -1213,7 +1288,7 @@ export default {
} else {
if (curTab.queryCondition) {
curTab.queryCondition.forEach(item => {
queryCondition.push(item.replace('$param', columnValue))
queryCondition.push(item.replaceAll('$param', columnValue))
})
} else {
if (curTab.dillDownProp) {
@@ -1276,13 +1351,13 @@ export default {
item.order = ''
})
}
this.cancleSortArrow()
this.column = {}
this.index = 0
this.tableSortColumn = ''
this.tableSortType = ''
this.tableSortTab = ''
this.urlChangeParams = this.$_.omit(this.urlChangeParams, [this.curTabState.tableSortColumn, this.curTabState.tableSortType, this.curTabState.tableSortTab])
this.cancleSortArrow()
},
// 切换tab
handleClick (tab) {
@@ -1304,11 +1379,11 @@ export default {
this.saveUserLocalConfig()
this.tab = curTab.prop
this.isDnsMapType = false
if(this.tab === 'qtype'){
this.dnsMapData =this.dnsQtypeMapData
if (this.tab === 'qtype') {
this.dnsMapData = this.dnsQtypeMapData
this.isDnsMapType = true
}else if(this.tab === 'rcode'){
this.dnsMapData =this.dnsRcodeMapData
} else if (this.tab === 'rcode') {
this.dnsMapData = this.dnsRcodeMapData
this.isDnsMapType = true
}
let queryParams = {
@@ -1409,7 +1484,7 @@ export default {
this.activeCustomize = tab.paneName
},
tableCellStyle ({ row, column, rowIndex, columnIndex }) {
let style = 'border-right:0px;font-size:12px;padding:7px 0 !important;border-bottom: 1px solid #ECECEC;'
let style = 'border-right:0px;font-size:12px;padding:7px 0 !important;border-bottom: 1px solid #ECECEC;height:41px !important;'
if (rowIndex === this.tableData.length - 1) {
// style = style + 'border-bottom:0px !important;'
}
@@ -1588,15 +1663,6 @@ export default {
}
}
},
/*
async getUserLocalConfig () {
const userLocalCongfig = await db[dbDrilldownTableConfig].get({ id: this.userId })
if (userLocalCongfig) {
return userLocalCongfig.config
} else {
return null
}
}, */
isDrilldown () {
if (this.getUrlParam(this.curTabState.fourthMenu)) {
return true
@@ -1618,6 +1684,7 @@ export default {
let curUserConfigs = await readDrilldownTableConfigByUser()
const hiddenColumns = this.getHiddenColumnNameGroup()
this.curTable.hiddenColumns = hiddenColumns
let version = ''
if (curUserConfigs && curUserConfigs.length > 0) { // 当前用户存在缓存配置
const currentRouteConfig = curUserConfigs.find(config => config.route === this.tableType)
if (currentRouteConfig) { // 用户的缓存中存在当前路径对应的下钻表格对应的配置
@@ -1633,13 +1700,16 @@ export default {
} else { // 用户的缓存中不存在当前路径对应的下钻表格对应的配置
curUserConfigs.push(this.handleInitDrilldownTableConfig())
}
version = await getConfigVersion(this.userId)
} else { // 当前用户不存在缓存配置
curUserConfigs = []
curUserConfigs.push(this.handleInitDrilldownTableConfig())
version = await getConfigVersion('default')
}
// 更新缓存中的配置
await db[dbDrilldownTableConfig].put({
id: this.userId,
version: version,
config: this.$_.cloneDeep(curUserConfigs)
})
// 更新使用的配置
@@ -1742,9 +1812,28 @@ export default {
}
},
async mounted () {
console.log('mounted start...')
this.list = null
this.tabList = null
this.allList = null
this.drillDownTableConfigs = null
this.curTable = null
this.commonColumnList = null
this.userId = localStorage.getItem(storageKey.userId)
this.drillDownTableConfigs = await combinDrilldownTableWithUserConfig()
this.tableType = this.$route.params ? this.$route.params.typeName : 'networkOverview'
// 是否需要dns的qtype和rcode的数据字典
if(this.tableType === fromRoute.dnsServiceInsights) {
this.dnsQtypeMapData = this.$store.getters.getDnsQtypeMapData
this.dnsRcodeMapData = this.$store.getters.getDnsRcodeMapData
if(!this.dnsQtypeMapData || this.dnsQtypeMapData.size === 0){
this.dnsQtypeMapData = await getDnsMapData('dnsQtype')
this.dnsRcodeMapData = await getDnsMapData('dnsRcode')
this.$store.commit('setDnsQtypeMapData', this.dnsQtypeMapData)
this.$store.commit('setDnsRcodeMapData', this.dnsRcodeMapData)
}
}
this.curTableInCode = this.networkTable[this.tableType] ? this.networkTable[this.tableType] : this.networkTable.networkOverview
// 表格状态初始化(url)
this.showRecordNum = Number(this.getUrlParam(this.curTabState.tableShowMore, 10))
@@ -1760,6 +1849,7 @@ export default {
const curTableOldConfig = this.tables.find(table => table.id === this.tableType)
this.curTable = curTableOldConfig
if (this.curTable) {
let curTab = null
if (this.isDrilldown()) { // 下钻状态
const thirdMenu = this.getUrlParam(this.curTabState.thirdMenu, '')
const tabList = this.getAllTabList()
@@ -1770,7 +1860,7 @@ export default {
const drilldownTab = tabList.find(item => item.label === thirdMenu)
this.list = drilldownTab ? drilldownTab.drilldownTabs : []
this.allList = this.$_.cloneDeep(tabList)// 备份所有配置,下钻及返回时使用
const curTab = this.getCurTab()// 初始化完list才能正确执行
curTab = this.getCurTab()// 初始化完list才能正确执行
const curTabColumns = tabList.find(item => item.prop === curTab.prop)
this.combineColumnList(curTabColumns.name)
this.activeTab = ref(curTab.label)
@@ -1782,11 +1872,22 @@ export default {
}
this.allList = this.$_.cloneDeep(this.list)// 备份所有配置,下钻及返回时使用
if (this.list && this.list.length > 0) {
const curTab = this.getCurTab()// 初始化完list才能正确执行
curTab = this.getCurTab()// 初始化完list才能正确执行
this.combineColumnList(curTab.name)
this.activeTab = ref(curTab.label)
}
}
if (curTab && curTab.prop) {
const tabName = curTab.prop
this.isDnsMapType = false
if (tabName === 'qtype') {
this.dnsMapData = this.dnsQtypeMapData
this.isDnsMapType = true
} else if (tabName === 'rcode') {
this.dnsMapData = this.dnsRcodeMapData
this.isDnsMapType = true
}
}
this.activeCustomize = ref('tabs')
this.networkSearchUrl = this.curTable.url
// let metric = this.getUrlParam(this.curTabState.tableMetric, 'Bits/s')
@@ -1798,14 +1899,14 @@ export default {
}
}
}
//是否需要dns的qtype和rcode的数据字典
this.isDnsMapType = false
this.dnsQtypeMapData = await getDnsMapData('dnsQtype')
this.dnsRcodeMapData = await getDnsMapData('dnsRcode')
this.saveUserLocalConfig()
await this.saveUserLocalConfig()
this.getChartData()
},
setup (props) {
},
beforeUnmount () {
// 以下元素,检测到内存并未释放
},
unmounted () {
this.isNoData = false

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>
@@ -137,13 +139,13 @@ import { get } from '@/utils/http'
import {
getChainRatio,
computeScore,
changeCurTab,
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 () {
@@ -169,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()
}
}
@@ -194,6 +199,9 @@ export default {
const lastCycleTrafficRequest = get(api.npm.overview.appTrafficAnalysis, { ...params, cycle: 1 })
this.toggleLoading(true)
Promise.all([currentTrafficRequest, lastCycleTrafficRequest]).then(res => {
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) {
@@ -224,12 +232,25 @@ export default {
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)
}
if (msg.lastIndexOf(',') === msg.length - 1) {
msg = msg.substring(0, msg.length - 1)
}
this.errorMsg = msg
}
})
tableData.forEach(t => {
@@ -251,9 +272,25 @@ export default {
this.isNoData = true
this.toggleLoading(false)
}
} else {
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,7 +1,8 @@
<template>
<div class="npm-app-event">
<div class="metric-select" >
<el-select v-model="metric"
<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"
@@ -16,7 +17,7 @@
:value="item.value"
/>
</el-select>
<span>{{$t('network.metric')}}</span>
<span>{{ $t('network.metric') }}</span>
</div>
<el-table
:id="`tabTable_${index}`"
@@ -29,12 +30,12 @@
<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">
<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">{{ $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,5 +1,8 @@
<template>
<div class="cn-chart__map-title" v-if="queryCondition">{{$t('npm.clientLocation')}}</div>
<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>
@@ -10,15 +13,17 @@ 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 || '')
@@ -37,7 +42,9 @@ export default {
countryImageSeries: null,
// Server | Client
trafficDirection: 'Server',
curTabState: curTabState
curTabState: curTabState,
showError: false,
errorMsg: ''
}
},
mixins: [chartMixin],
@@ -90,10 +97,13 @@ 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 => {
this.showError = false
if (res && res.length > 0) {
const subParams = {
...params,
params: res.map(r => r.country).join(',')
params: res.map(r => `'${r.country}'`).join(',')
}
// 计算分数
const tcpRequest = get(api.npm.overview.mapTcp, subParams)
@@ -110,6 +120,9 @@ export default {
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 => {
@@ -121,17 +134,27 @@ export default {
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
}).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}}(ms)</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}}(ms)</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}}(ms)</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>
@@ -48,10 +66,12 @@ 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],
@@ -76,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: {
@@ -92,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) {
@@ -129,7 +156,9 @@ 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.isNoData) {
if (this.chart.params.index === 0) {
res.data.result.forEach((t, i) => {
if (t.type === 'totalBitsRate') {
@@ -146,6 +175,15 @@ export default {
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)
})
@@ -162,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: {
@@ -288,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,12 +133,24 @@ 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 => {
const find = r.data.result.find(d => d.country === t.country)
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)
}
if (msg.lastIndexOf(',') === msg.length - 1) {
msg = msg.substring(0, msg.length - 1)
}
this.errorMsg = msg
}
})
mapData.forEach(t => {
@@ -148,20 +167,29 @@ export default {
}
})
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,
@@ -303,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) {
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,23 +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 => {
let score = 0
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
}
score = computeScore(data)
this.npmNetworkCycleData = res.data.result
this.npmNetworkLastCycleQuery()
}
this.$store.commit('setNpmThirdLevelMenuScore', score)
this.npmNetworkLastCycleQuery(url, params)
}).catch(e => {
this.toggleLoading(false)
})
@@ -124,77 +137,62 @@ export default {
this.toggleLoading(true)
Promise.all([tcp, http, ssl, tcpPercent, packetPercent]).then(res => {
this.npmNetworkCycleData = []
let score = 0
res.forEach(t => {
if (t.code === 200) {
this.npmNetworkCycleData.push(t.data.result)
const data = {
establishLatencyMs: t.data.result.establishLatencyMsAvg,
httpResponseLatency: t.data.result.httpResponseLatencyAvg,
sslConLatency: t.data.result.sslConLatencyAvg,
tcpLostlenPercent: t.data.result.tcpLostlenPercentAvg,
pktRetransPercent: t.data.result.pktRetransPercentAvg
}
score = computeScore(data)
} else {
this.npmNetworkCycleData.push(t)
}
})
this.$store.commit('setNpmThirdLevelMenuScore', 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
} else {
this.npmNetworkLastCycleData = [res]
}
let timer = null
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
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)
})
@@ -209,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)
})
@@ -270,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)
} 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
let thirdMenu = this.$route.query['thirdMenu']
self.tabs[0].disable = false
self.tabs[1].disable = false
setTimeout(() => {
self.handleActiveBar(0)
}, 400)
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) {
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

@@ -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)
}
},
@@ -112,7 +117,9 @@ export default {
value: 'pktRetransPercent',
label: this.$t('overall.packetRetrans')
}
]
],
showError: false,
errorMsg: ''
}
},
watch: {
@@ -142,10 +149,9 @@ 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 = {
@@ -156,7 +162,17 @@ export default {
params.type = type
}
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
}
} 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') {
@@ -172,6 +188,7 @@ export default {
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 = [
@@ -290,10 +307,14 @@ export default {
}
})
} else {
this.isNoData = true
this.isNoData = false
this.showError = true
this.errorMsg = res.message
}
}).catch(e => {
this.isNoData = true
this.isNoData = false
this.showError = true
this.errorMsg = e.message
}).finally(() => {
this.toggleLoading(false)
})
@@ -302,6 +323,7 @@ export default {
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 = [
@@ -352,9 +374,15 @@ export default {
this.echartsInit(this.mpackets)
}
})
} else {
this.isNoData = false
this.showError = true
this.errorMsg = res.message
}
}).catch(e => {
this.isNoData = true
this.isNoData = false
this.showError = true
this.errorMsg = e.message
}).finally(() => {
this.toggleLoading(false)
})
@@ -362,6 +390,7 @@ export default {
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 = [
@@ -411,9 +440,15 @@ export default {
this.echartsInit(this.npmQuantity, '(%)')
}
})
} else {
this.isNoData = false
this.showError = true
this.errorMsg = res.message
}
}).catch(e => {
this.isNoData = true
this.isNoData = false
this.showError = true
this.errorMsg = e.message
}).finally(() => {
this.toggleLoading(false)
})
@@ -421,6 +456,7 @@ export default {
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 = [
@@ -446,9 +482,15 @@ export default {
this.echartsInit(this.npmQuantity, '(ms)')
}
})
} else {
this.isNoData = false
this.showError = true
this.errorMsg = res.message
}
}).catch(e => {
this.isNoData = true
this.isNoData = false
this.showError = true
this.errorMsg = e.message
}).finally(() => {
this.toggleLoading(false)
})
@@ -456,6 +498,7 @@ export default {
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 = [
@@ -481,9 +524,15 @@ export default {
this.echartsInit(this.npmQuantity, '(ms)')
}
})
} else {
this.isNoData = false
this.showError = true
this.errorMsg = res.message
}
}).catch(e => {
this.isNoData = true
this.isNoData = false
this.showError = true
this.errorMsg = e.message
}).finally(() => {
this.toggleLoading(false)
})
@@ -617,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)
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'
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
divRed.style.width = this.sessionData.serverSessions
} else {
this.isNoData = true
this.changeByErrorOrNodata()
}
} 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,20 +1,28 @@
<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>
<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">{{unitConvert(npm.establishLatencyMsAvg, unitTypes.time).join(' ')}}</div>
<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__content-number" v-else>
{{unitConvert(npm.Avg, 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('')}}
{{ 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('-', '')}}
{{ unitConvert(npm.value, unitTypes.percent).join('').replaceAll('-', '') }}
</span>
<span v-else>>500.00%</span>
</div>
@@ -23,131 +31,35 @@
</div>
<div v-else></div>
</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>
</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('')}}
<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>
<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('-', '')}}
<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>>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.httpResponseLatencyP95, unitTypes.time).join(' ')}}</div>
<div class="single-value__circle-p99">P99: {{unitConvert(npm.httpResponseLatencyP99, unitTypes.time).join(' ')}}</div>
</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 v-else>
P99:{{ unitConvert(npm.P99, 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.sslConLatencyP95, unitTypes.time).join(' ')}}</div>
<div class="single-value__circle-p99">P99: {{unitConvert(npm.sslConLatencyP99, unitTypes.time).join(' ')}}</div>
</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>
<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>
</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: [
{
@@ -351,18 +360,7 @@ export const npmLineChartOption = {
}
}
],
series: [
{
type: 'line',
symbol: 'circle',
smooth: true,
showSymbol: false,
emphasis: {
focus: 'series'
},
data: []
}
]
series: []
}
export const trafficLineChartOption = {
@@ -397,7 +395,7 @@ export const trafficLineChartOption = {
xAxis: [
{
type: 'time',
splitNumber: 12
splitNumber: 8
// axisLabel: {
// formatter: function (value) {
// const data = new Date(value)
@@ -487,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>
@@ -88,8 +108,7 @@
@size-change="pageSize"
@prev-click="prev"
@next-click="next"
>
</Pagination>
></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)"