Compare commits

..

75 Commits

Author SHA1 Message Date
陈劲松
83a9b3fa57 Merge branch 'cherry-pick-16a255be' into 'dev-22.10'
CN-811 feat: networkoverview下钻第三级菜单折线图请求参数调整

See merge request cyber-narrator/cn-ui!6
2022-11-28 09:28:22 +00:00
changcode
cc3157c578 CN-811 feat: networkoverview下钻第三级菜单折线图请求参数调整
(cherry picked from commit 16a255be50)
2022-11-28 17:28:11 +08:00
陈劲松
d7b78da80f Merge branch 'cherry-pick-35fcbab8' into 'dev-22.10'
fix: 修复apps tab切换判断导致的loading一直存在,apps列表删除问题

See merge request cyber-narrator/cn-ui!5
2022-11-28 08:51:21 +00:00
@changcode
5f68b966ba fix: 修复apps tab切换判断导致的loading一直存在,apps列表删除问题
(cherry picked from commit 35fcbab852)
2022-11-28 16:51:06 +08:00
陈劲松
d175d834d1 Merge branch 'cherry-pick-9f6a9877' into 'dev-22.10'
CN-798 下钻table新增一系列维度后的问题:npm在customize里勾选client ip、client...

See merge request cyber-narrator/cn-ui!3
2022-11-15 07:36:32 +00:00
hyx
bb188483a7 CN-798 下钻table新增一系列维度后的问题:npm在customize里勾选client ip、client country等新增的维度后,没有被缓存;新增client asn和server asn维度;
(cherry picked from commit 9f6a98779b)
2022-11-15 15:35:54 +08:00
@changcode
32a2359e0d fix: 修复npm 折线图和下钻折线图,因名称判断错误导致的移入弹窗样式问题 2022-11-07 10:17:24 +08:00
chenjinsong
c425d87b00 fix: 临时性调整npm line和npm traffic line的legend名字 2022-11-04 12:52:12 +08:00
hyx
34e16fc890 CN-762 DNS service insights 显示建议:修改由dns的qtype及rcode维度转换对应名称的问题所影响的部分(panel名称,顶部四级菜单显示及下拉显示等) 2022-11-04 12:18:26 +08:00
chenjinsong
c0487a708a fix: 修复地图报错 2022-11-04 11:32:49 +08:00
chenjinsong
68596189b4 fix: 删除npm流量曲线标题 2022-11-04 11:26:46 +08:00
@changcode
29d89ee6e4 fix: 去除无用组件,修复部分折线图Reference line闪动问题 2022-11-04 10:31:10 +08:00
@changcode
14c53bd5ad fix: 修复折线图判断逻辑当字段不存在导致的折线图展示错误问题 2022-11-04 10:24:22 +08:00
@changcode
f39c4d8fc4 CN-790 fix: 修复NPM overview折线图metric、legend、内容 对应不上 2022-11-04 10:22:32 +08:00
hyx
6827d4f031 CN-762 DNS service insights 显示建议(dns qtype和rcode维度数据映射及自定义metric名称修改) 2022-11-03 17:51:53 +08:00
@changcode
1cb4c43b9e fix: 修复NetWork OVerview Providers and Applications 时间范围变化后,之前时间范围数据为清除问题 2022-11-03 16:01:32 +08:00
@changcode
e1bf796f0c fix: 修复 Network Overview 指标下拉为sessions/s时,切换其他选项lineTab一直为total问题 2022-11-03 15:36:36 +08:00
chenjinsong
94c15e0933 CN-775 fix: 修改图表标题 2022-11-03 14:49:55 +08:00
@changcode
043b785547 Merge branch 'dev' of https://git.mesalab.cn/cyber-narrator/cn-ui into dev 2022-11-03 11:21:53 +08:00
@changcode
b0b8de2712 fix: 修复折线图表tab反选错误 2022-11-03 11:21:39 +08:00
chenjinsong
93933502e4 CN-775 fix: 修改图表标题 2022-11-03 11:00:41 +08:00
@changcode
e5b636905f fix: 修复link下钻列表分数计算逻辑 2022-11-03 10:56:06 +08:00
@changcode
078ec2f69f CN-787 feat: Dashboard - npm - overview增加一个曲线图 2022-11-02 19:28:11 +08:00
@changcode
7c77c3c79a fix: 修复link下钻折线图左侧列表错误问题 2022-11-02 18:52:33 +08:00
hyx
0d89b3c23b CN-788 下钻table的分数样式、内容展示等调整 2022-11-02 16:26:31 +08:00
@changcode
a6ea1fa4e6 CN-771 feat: network overview metric统一顶部触发 2022-11-02 11:28:25 +08:00
@changcode
70c38fe2de fix: 修复npm下钻网络性能统计数据展示错误问题 2022-11-02 10:59:21 +08:00
@changcode
12b7290ecd fix: 修复折线图数据为空后,保留之前数据的问题 2022-11-01 19:23:17 +08:00
chenjinsong
60cbebe1cc CN-771 fix: metric下拉框背景色调整 2022-11-01 18:05:45 +08:00
chenjinsong
096517e34f fix: 更改app列表环比0的描述 2022-11-01 17:11:55 +08:00
chenjinsong
2020423c0a fix: metric下拉限定在networkoverview 2022-11-01 16:47:42 +08:00
chenjinsong
da03a3658c fix: networkoverview的metric提至顶部 2022-11-01 16:46:11 +08:00
@changcode
45de9c8107 fix: 分数计算方法逻辑错误修复 2022-11-01 14:31:28 +08:00
@changcode
14f661b78f Merge branch 'dev' of https://git.mesalab.cn/cyber-narrator/cn-ui into dev 2022-11-01 14:13:55 +08:00
@changcode
b5718a039f fix: 分数计算逻辑调整 2022-11-01 14:13:47 +08:00
@changcode
6845bb4ea4 fix: 修复network apps 移入效果错误 2022-11-01 14:13:03 +08:00
hyx
5f448c0ccb CN-778 下钻table取值变更: npm、dns、link的throughput列取值改为totalBytes,单位改为byte
CN-776 NPM Dashboard维度表中分数添加颜色标识
2022-11-01 10:33:23 +08:00
hyx
d568c748db CN-748 下钻table缓存功能优化(包括metric和tab结构的变化)
CN-778 总流量、总包、比特速率字段名前端统一
2022-11-01 09:12:14 +08:00
chenjinsong
07e137d5e0 fix: 调整networkoverview provider改为providers 2022-10-31 17:18:00 +08:00
@changcode
3093c3e3a8 fix: network app 更多点击事件切换为鼠标悬浮触发 2022-10-28 15:30:16 +08:00
刘洪洪
db105804b3 fix: 隐藏timeRange时间弹窗的方向标识 2022-10-28 14:46:04 +08:00
刘洪洪
49eb4d42ce fix:解决timeRange刷新后下钻返回时间被重置 2022-10-28 10:28:12 +08:00
刘洪洪
e019f8a02e fix: timeRange添加注释 2022-10-27 16:32:16 +08:00
刘洪洪
e7cf758ffd fix: 解决timeRange下钻后返回时间被重置的问题 2022-10-27 15:47:38 +08:00
@changcode
64610304c1 fix: 修复npm location 折线图,因字段改变导致的报错 2022-10-27 10:47:38 +08:00
刘洪洪
2da2172f03 fix: $dayJs改为全局引用,去除不必要组件引入 2022-10-27 09:48:31 +08:00
刘洪洪
c2c3898d5b CN-746: 更换时间选择器实现方案 2022-10-26 18:59:53 +08:00
@changcode
04e4371ac1 fix: 折线图多个 tab 无数据时,只保留total时默认选中 2022-10-26 18:20:31 +08:00
@changcode
06c86b8172 CN-768 fix: 1.app卡片Bit/s时底下的流量总数的单位需要使用byte2.折线图单个情况默认选中3.network overview 的右上角图表的按钮点击跳转到npm的events 2022-10-25 19:42:48 +08:00
chenjinsong
ced28fd3e7 fix: 调整networkoverview的图表位置,增加app-card图的resize逻辑 2022-10-25 18:41:27 +08:00
@changcode
943d64918d fix: 优化报告列表下拉 loading 位置 2022-10-25 10:31:47 +08:00
@changcode
de5040d9f4 fix: 注释页面中的打印 2022-10-24 18:40:57 +08:00
刘洪洪
64e41c3170 fix: 解决实体界面初始化时,接口会被调用三次的问题 2022-10-24 18:37:10 +08:00
hyx
8bee5301bc CN-760 score跳动问题 2022-10-24 16:51:41 +08:00
hyx
b75e975421 CN-754 下钻table的一些bug:NPM、DNS、Link的throughput列有值,但是显示横杠(我刚更新配置,这个字段的prop改为totalBitsRate,需清一下indexdb缓存) 2022-10-24 14:08:24 +08:00
@changcode
21c3ead654 fix: 修复折线图百分比数据与坐标对不上问题 2022-10-23 10:17:26 +08:00
hyx
74cbcf0d46 CN-754 下钻table的一些bug:城市单引号问题 2022-10-21 21:26:39 +08:00
chenjinsong
2e27cd5add fix: 关闭mock,解决下载pdf空白的问题 2022-10-21 18:10:12 +08:00
@changcode
e2b03c5d7f fix:修复domain 和 app, npm 下钻地图标题问题 2022-10-21 11:52:46 +08:00
hyx
a87b096c1c CN-754 下钻table的一些bug 2022-10-21 10:08:49 +08:00
@changcode
2a6958f61b fix: npm 地理位置折线图 弹框颜色错误问题 2022-10-20 20:13:09 +08:00
刘洪洪
ae8918f7f7 fix: Provider和Applications快捷图表添加标题,以及修改增加提示框名称问题 2022-10-20 16:13:05 +08:00
chenjinsong
f9e6250e2a fix: 下钻表格首列标题为单数 2022-10-20 14:53:50 +08:00
@changcode
bb81059529 CN-758 fix: 修复NPM下钻折线图bug 2022-10-20 14:41:48 +08:00
@changcode
c38b5ef000 fix: npm 下钻折线图切换数据展示错误问题 2022-10-20 13:56:39 +08:00
@changcode
75dd68f403 fix: npm 折线图移入弹框颜色补充 2022-10-20 11:23:32 +08:00
@changcode
e39e24258b fix; 修复折线图因数据问题导致移入弹框颜色错误问题 2022-10-20 11:19:58 +08:00
@changcode
5767fe896b fix: 修复报告Box侧滑Time limit 为 customize,时间限制错误问题 2022-10-19 17:19:39 +08:00
chenjinsong
53fc6475e2 feat: 更改评分规则 2022-10-19 15:55:23 +08:00
hyx
59ae26e078 CN-752 dns下钻后q查询条件有些与文档不符 2022-10-19 15:45:31 +08:00
刘洪洪
15cfd48770 CN-747: http请求支持取消 2022-10-19 15:27:26 +08:00
@changcode
111f731712 fix: 报告Box Time limit 时间限制逻辑调整 2022-10-19 11:16:38 +08:00
@changcode
c5a78887cb fix: 报告box Time limit 为 customize的时候,时间选择器增加限制 2022-10-19 09:57:51 +08:00
chenjinsong
add13f463d fix: 修正dns下钻后折线图的url 2022-10-18 19:14:08 +08:00
@changcode
c1dd39fb66 fix: 报告box time limit 为 customize 时增加时间范围限制 2022-10-18 17:38:37 +08:00
44 changed files with 2008 additions and 1575 deletions

View File

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

View File

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

View File

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

View File

@@ -115,6 +115,29 @@
.el-table thead {
color: $grey;
}
.score-cell {
display: flex !important;
justify-content: center;
.data-score {
border-radius: 10px;
font-size: 12px;
color: #FFFFFF;
font-weight: 500;
height: 20px;
width: 34px;
line-height: 20px;
text-align: center;
}
.data-score-red {
background: #E26154;
}
.data-score-yellow {
background: #E5A219;
}
.data-score-green {
background: #749F4D;
}
}
}
.el-tabs__header {
margin-bottom: 10px;

View File

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

View File

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

View File

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

View File

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

View File

@@ -53,7 +53,17 @@
trigger="click">
<template #reference>
<div class="breadcrumb-button" id="breadcrumbButton" :class="showBackground?'breadcrumb-button__active':''" >
<span id="breadcrumbValue"> {{item}}</span><i class="cn-icon-xiala cn-icon"></i>
<span id="breadcrumbValue">
<template v-if="curTabProp === 'qtype'">
<span>{{dnsQtypeMapData.get(item) ? dnsQtypeMapData.get(item):item}}</span>
</template>
<template v-else-if="curTabProp === 'rcode'">
<span>{{dnsRcodeMapData.get(item) ? dnsRcodeMapData.get(item):item}}</span>
</template>
<template v-else>
<span>{{item}}</span>
</template>
</span><i class="cn-icon-xiala cn-icon"></i>
</div>
</template>
<el-row type="flex" justify="center" style="width: fit-content;flex-direction: column;">
@@ -65,7 +75,15 @@
</div>
<ul class="select-dropdown" id="breadcrumbSelectDropdown" @scroll="scrollList()">
<li v-for="item in breadcrumbColumnValueListShow" title='' :key="item" :id="item" class="select-dropdown__item" @click="changeValue(item)" :class="selected?'':''">
<span>{{item}}</span>
<template v-if="curTabProp === 'qtype'">
<span>{{dnsQtypeMapData.get(item) ? dnsQtypeMapData.get(item):item}}</span>
</template>
<template v-else-if="curTabProp === 'rcode'">
<span>{{dnsRcodeMapData.get(item) ? dnsRcodeMapData.get(item):item}}</span>
</template>
<template v-else>
<span>{{item}}</span>
</template>
</li>
</ul>
</el-row>
@@ -190,11 +208,12 @@ import {
networkTable,
operationType,
storageKey,
wholeScreenRouterMapping
wholeScreenRouterMapping,
fromRoute
} from '@/utils/constants'
import { api } from '@/utils/api'
import { ref } from 'vue'
import { combineTabList, getDefaultCurTab, getTabList, overwriteUrl, urlParamsHandler } from '@/utils/tools'
import { combineTabList, getDefaultCurTab, getTabList, overwriteUrl, urlParamsHandler, combinDrilldownTableWithUserConfig,getDnsMapData } from '@/utils/tools'
import { getNowTime, getSecond } from '@/utils/date-util'
import { db } from '@/indexedDB'
@@ -226,10 +245,15 @@ export default {
showMenu: false,
dropDownValue: '',
breadcrumbColumnValueListShow: [],
curTabProp:'',
dnsRcodeMapData:[],
dnsQtypeMapData:[],
isDnsMapType:false,
valueMeta: [],
showBackground: false,
selected: false,
valueMenuId: '',
fromRoute: fromRoute,
detectionMenuList: [
{
name: 'securityEvents',
@@ -270,6 +294,7 @@ export default {
},
breadcrumb () {
const breadcrumbMap = []
this.curTabProp = this.$route.query.dimensionType ? this.$route.query.dimensionType : null
this.$store.getters.menuList.forEach(menu => {
if (this.$_.isEmpty(menu.children) && menu.route) {
breadcrumbMap.push({ name: this.$t(menu.i18n), path: menu.route, columnName: menu.columnName, columnValue: menu.columnValue })
@@ -312,8 +337,10 @@ export default {
}
}
},
mounted () {
async mounted () {
this.from = Object.keys(this.entityType)[0]
this.dnsQtypeMapData = await getDnsMapData('dnsQtype')
this.dnsRcodeMapData = await getDnsMapData('dnsRcode')
this.initDropdownList()
},
setup () {
@@ -350,14 +377,25 @@ export default {
window.location.reload()
})
},
initDropdownList () {
const currentValue = document.getElementById('breadcrumbValue') ? document.getElementById('breadcrumbValue').innerText : ''
const columnName = this.getUrlParam(this.curTabState.thirdMenu, '')
let type = 'ip'
const tableType = this.$route.params ? this.$route.params.typeName : 'networkOverview'
const curTableInCode = networkTable[tableType] ? networkTable[tableType] : networkTable.networkOverview
getCurTabByLabel(label){
let curTab = null
let tableType = this.$route.params ? this.$route.params.typeName : 'networkOverview'
let curTableInCode = networkTable[tableType] ? networkTable[tableType] : networkTable.networkOverview
if (curTableInCode && curTableInCode.tabList) {
const curTab = curTableInCode.tabList.find(item => item.label == columnName)
curTab = curTableInCode.tabList.find(item => item.label == label)
}
return curTab
},
async initDropdownList () {
//是否需要dns的qtype和rcode的数据字典
this.curTabProp = this.$route.query.dimensionType ? this.$route.query.dimensionType : null
let currentValue = document.getElementById('breadcrumbValue') ? document.getElementById('breadcrumbValue').innerText : ''
let 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
if (curTableInCode && curTableInCode.tabList) {
let curTab = curTableInCode.tabList.find(item => item.label == columnName)
if (curTab) {
type = curTab.prop
}
@@ -369,14 +407,22 @@ export default {
type: type,
name: this.dropDownValue ? this.dropDownValue : ''
}
get(curTableInCode.url.drilldownList, params).then(response => {
get(curTableInCode.url.drilldownList, params).then(async response => {
if (response.code === 200) {
this.breadcrumbColumnValueListShow = response.data.result
this.dnsQtypeMapData = await getDnsMapData('dnsQtype')
this.dnsRcodeMapData = await getDnsMapData('dnsRcode')
this.$nextTick(() => {
this.breadcrumbColumnValueListShow.forEach(item => {
const selectedDom = document.getElementById(item)
if (selectedDom) {
if (item === currentValue) {
let itemName = item
if(this.curTabProp === 'qtype'){
itemName = this.dnsQtypeMapData.get(item)
}else if(this.curTabProp === 'rcode'){
itemName = this.dnsRcodeMapData.get(item)
}
if (itemName === currentValue) {
selectedDom.style.cssText = 'color:#0091ff;font-weight: bold;'
} else {
selectedDom.style.cssText = ''
@@ -407,32 +453,37 @@ export default {
},
changeValue (value) {
// 设置面包屑显示的内容及hover时的title
let valName = value
if(this.tab === 'qtype'){
valName =this.dnsQtypeMapData.get(value)
}else if(this.tab === 'rcode'){
valName =this.dnsRcodeMapData.get(value)
}
this.curTabProp = this.$route.query.dimensionType ? this.$route.query.dimensionType : null
document.getElementById('breadcrumbValue').innerText = value
document.getElementById('breadcrumbButton').setAttribute('title', value)
document.getElementById(this.valueMenuId).setAttribute('title', value)
//document.getElementById('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)
if (tabObjGroup && tabObjGroup.length > 0) {
const curTab = tabObjGroup[0]
if (curTab) {
const queryCondition = []
const searchProps = curTab.dillDownProp
if (curTab.prop === 'protocolPort') {
const valueGroup = value.split(':')
if (valueGroup) {
queryCondition.push("common_l7_protocol='" + valueGroup[0] + "'")
queryCondition.push('common_server_port=' + valueGroup[1])
}
console.log(queryCondition.join(' AND '))
this.urlChangeParams[this.curTabState.queryCondition] = queryCondition.join(' AND ')
} else {
searchProps.forEach(item => {
queryCondition.push(item + "='" + value + "'")
})
this.urlChangeParams[this.curTabState.queryCondition] = queryCondition.join(' OR ')
//const tabObjGroup = networkOverviewTabList.filter(item => item.label == columnName)
let curTab = this.getCurTabByLabel()
if (curTab) {
const queryCondition = []
const searchProps = curTab.dillDownProp
if (curTab.prop === 'protocolPort') {
const valueGroup = value.split(':')
if (valueGroup) {
queryCondition.push("common_l7_protocol='" + valueGroup[0] + "'")
queryCondition.push('common_server_port=' + valueGroup[1])
}
console.log(queryCondition.join(' AND '))
this.urlChangeParams[this.curTabState.queryCondition] = queryCondition.join(' AND ')
} else {
searchProps.forEach(item => {
queryCondition.push(item + "='" + value.replaceAll("'", "\\\\'") + "'")
})
this.urlChangeParams[this.curTabState.queryCondition] = queryCondition.join(' OR ')
}
}
this.changeUrlTabState()
@@ -468,19 +519,7 @@ export default {
async handleCurDrilldownTableConfig (thirdMenu, fourthMenu) {
const userId = localStorage.getItem(storageKey.userId)
const tableType = this.$route.params ? this.$route.params.typeName : 'networkOverview'
// 先从localStorage中获取用户定制的自定义配置如果没有则使用默认的自定义配置
const userLocalConfig = await db[dbDrilldownTableConfig].get({ id: userId })
let drillDownTableConfigs = []
if (userLocalConfig) {
drillDownTableConfigs = userLocalConfig.config
}
if (!drillDownTableConfigs || drillDownTableConfigs.length === 0) { // 未找到当前用户的配置,使用默认配置
const defaultConfig = await db[dbDrilldownTableConfig].get({ id: 'default' })
if (defaultConfig) {
drillDownTableConfigs = defaultConfig.config
}
}
const drillDownTableConfigs = await combinDrilldownTableWithUserConfig()
const currentTableConfig = drillDownTableConfigs.find(config => config.route === tableType)
const tables = currentTableConfig ? currentTableConfig.tables : []
const commonTabList = currentTableConfig ? currentTableConfig.tabs : []
@@ -499,10 +538,6 @@ export default {
}
}
}
await db[dbDrilldownTableConfig].put({
id: userId,
config: this.$_.cloneDeep(drillDownTableConfigs)
})
},
jump (route, columnName, columnValue, opeType) {
this.showMenu = false
@@ -511,7 +546,9 @@ export default {
this.urlChangeParams[this.curTabState.tabOperationBeforeType] = this.getUrlParam(this.curTabState.tabOperationType, '', true)
this.urlChangeParams[this.curTabState.tabOperationType] = opeType
if (opeType === 3) {
this.urlChangeParams.queryCondition = ''
if (route !== '/panel/networkOverview') {
this.urlChangeParams.queryCondition = ''
}
}
} else {
this.urlChangeParams[this.curTabState.tabOperationType] = operationType.mainMenu
@@ -519,7 +556,6 @@ export default {
if (!columnName) { // 点击第二级菜单
this.$store.commit('setNetworkOverviewTabList', [])
}
// 清空网络概况的特殊面包屑
this.$store.getters.menuList.forEach(menu => {
if (!this.$_.isEmpty(menu.children)) {
@@ -530,16 +566,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)
const type = tabObjGroup && tabObjGroup[0] ? tabObjGroup[0].prop : ''
this.urlChangeParams[this.curTabState.dimensionType] = type
//const tabObjGroup = networkOverviewTabList.filter(item => item.label == columnName)
//let curTab = this.getCurTabByLabel()
//const type = curTab ? curTab.prop : ''
//this.curTabProp = this.$route.query.dimensionType ? this.$route.query.dimensionType : null
//this.urlChangeParams[this.curTabState.dimensionType] = type
this.urlChangeParams[this.curTabState.panelName] = columnValue
} else if (columnName) { // 点击的为列名
child.columnValue = ''
child.columnName = columnName
this.urlChangeParams[this.curTabState.thirdMenu] = columnName
this.urlChangeParams[this.curTabState.fourthMenu] = ''
this.urlChangeParams[this.curTabState.panelName] = columnName
this.urlChangeParams[this.curTabState.panelName] = columnValue
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)

View File

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

View File

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

View File

@@ -9,7 +9,7 @@ import commonMixin from '@/mixins/common'
import { cancelWithChange, noData } from '@/utils/tools'
import { ClickOutside } from 'element-plus/lib/directives'
import i18n from '@/i18n'
import '@/mock/index.js'
// import '@/mock/index.js'
import hljsVuePlugin from '@highlightjs/vue-plugin'
import 'highlight.js/styles/color-brewer.css'
import '@/assets/css/main.scss' // 样式入口
@@ -26,12 +26,6 @@ const emitter = new bus()
const _ = require('lodash') // lodash工具
/* dayjs.extend(utc)
dayjs.extend(timezone)
dayjs.extend(advancedFormat)
dayjs.extend(weekday)
window.$dayJs = dayjs */
const app = createApp(App)
app.use(router)

View File

@@ -51,7 +51,11 @@ const panel = {
npmLocationCountry: '', // npm location的查询条件--国家
npmLocationSide: 'server', // npm location的查询条件--方向
refreshTime: null, // 自动刷新时间的秒数
refreshFlag: true // 关闭自动刷新标志true为offfalse即开启自动刷新
refreshFlag: true, // 关闭自动刷新标志true为offfalse即开启自动刷新
timeRangeArray: [], // 时间范围列表:开始/结束时间
timeRangeFlag: null, // 时间范围标志默认60即一小时-1为手动选择的时间范围
routerPath: '', // 当前路由路径
httpCancel: null // 终止http请求
},
mutations: {
setShowRightBox (state, flag) {
@@ -146,6 +150,18 @@ const panel = {
},
setRefreshFlag (state, flag) {
state.refreshFlag = flag
},
setTimeRangeArray (state, array) {
state.timeRangeArray = array
},
setTimeRangeFlag (state, flag) {
state.timeRangeFlag = flag
},
setRouterPath (state, path) {
state.routerPath = path
},
setHttpCancel (state, cancel) {
state.httpCancel = cancel
}
},
getters: {
@@ -229,6 +245,15 @@ const panel = {
},
getNpmThirdLevelMenuScore (state) {
return state.npmThirdLevelMenuScore
},
getTimeRangeArray (state) {
return state.timeRangeArray
},
getTimeRangeFlag (state) {
return state.timeRangeFlag
},
getRouterPath (state) {
return state.routerPath
}
},
actions: {

View File

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

View File

@@ -161,6 +161,11 @@ export const api = {
appSslConDelay: '/interface/application/performance/overview/appSslConDelay',
appTcpLostlenPercent: '/interface/application/performance/overview/appTcpLostlenPercent',
appPacketRetransPercent: '/interface/application/performance/overview/appPacketRetransPercent',
// 整体流量折线图
totalTrafficAnalysis: '/interface/application/performance/overview/totalTrafficAnalysis',
totalNetworkAnalysis: '/interface/application/performance/overview/totalNetworkAnalysis',
totalHttpResponseDelay: '/interface/application/performance/overview/totalHttpResponseDelay',
totalSslConDelay: '/interface/application/performance/overview/totalSslConDelay',
// 各维度下钻会话统计
relatedSessions: '/interface/application/performance/relatedSessions',
// 各维度下钻流量曲线图
@@ -220,7 +225,8 @@ export const api = {
recentEvents: '/interface/dnsInsight/recentEvents',
activeMaliciousDomain: '/interface/dnsInsight/activeMaliciousDomain',
totalTrafficAnalysis: '/interface/dns/overview/totalTrafficAnalysis',
eventChart: '/interface/dnsInsight/eventChart'
eventChart: '/interface/dnsInsight/eventChart',
drilldownTrafficAnalysis: '/interface/dns/overview/drilldown/trafficAnalysis'
}
}

View File

@@ -31,7 +31,7 @@ export const storageKey = {
echartLegendFontSize: 'echartLegendFontSize',
echartLabelFontSize: 'echartLabelFontSize',
tokenExpireCurrentPath: 'token-expire-current-path',
drillDownTableConfig: 'cn-drill-down-table-config',
drillDownTableConfig: 'drilldownTableConfig',
userCustomizationConfig: 'userCustomizationConfig',
linkInfo: 'cn-link-info',
history: 'cn-history'
@@ -186,6 +186,21 @@ export const networkOverviewTabs = [
'network.protocolPorts'
] */
export const metricOptions = [
{
value: 'Bits/s',
label: 'Bits/s'
},
{
value: 'Packets/s',
label: 'Packets/s'
},
{
value: 'Sessions/s',
label: 'Sessions/s'
}
]
export const operationType = {
mainMenu: 0, // 菜单
secondMenu: 2, // 二级菜单
@@ -287,11 +302,11 @@ export const scoreUrl = [
// AppPerformance类型表格的列有属性cycleDataUrl的代表此数据的来源为对应接口返回的数据无cycleDataUrl的属性代表数据来源于主urlnpmSearchUrl.curUrl、npmSearchUrl.cycleUrl、npmSearchUrl.drilldownCurUrl、npmSearchUrl.drilldownCycleUrl
export const customTableTitlesForAppPerformance = [
{ label: 'network.ips', prop: 'tab', checked: true, tabColumn: true, columnType: tableColumnType.dillDown },
{ label: 'IP', prop: 'tab', checked: true, tabColumn: true, columnType: tableColumnType.dillDown },
{ label: 'network.score', prop: 'score', checked: true, tabColumn: false, columnType: tableColumnType.normal },
{
label: 'networkAppPerformance.throughput',
prop: 'through',
prop: 'totalBytes',
checked: true,
tabColumn: false,
columnType: tableColumnType.chainRatio,
@@ -375,11 +390,11 @@ export const customTableTitlesForAppPerformance = [
}
]
export const customTableTitlesForLinkMonitor = [
{ label: 'network.ips', prop: 'tab', checked: true, tabColumn: true, columnType: tableColumnType.dillDown },
{ label: 'IP', prop: 'tab', checked: true, tabColumn: true, columnType: tableColumnType.dillDown },
{ label: 'network.score', prop: 'score', checked: true, tabColumn: false, columnType: tableColumnType.normal },
{
label: 'networkAppPerformance.throughput',
prop: 'through',
prop: 'totalBytes',
checked: true,
tabColumn: false,
columnType: tableColumnType.chainRatio,
@@ -479,7 +494,7 @@ export const customTableTitlesForDns = [
]
// NetworkOverview类型表格的列:prop 为接口响应数据中的属性名
export const customTableTitlesForNetworkOverview = [
{ label: 'network.ips', prop: 'tab', checked: true, tabColumn: true, columnType: tableColumnType.dillDown },
{ label: 'IP', prop: 'tab', checked: true, tabColumn: true, columnType: tableColumnType.dillDown },
{
label: 'network.total',
prop: 'total',
@@ -953,6 +968,7 @@ export const dnsServiceInsightsTabList = [
prop: 'dnsServerRole',
queryCycleTotalProp: 'roles',
dillDownProp: ['dns_server_role'],
queryCondition: ['has(dns_server_role,\'$param\')'],
checked: true,
disabled: false,
panelId: drillDownPanelTypeMapping.dnsFourthMenu
@@ -971,6 +987,7 @@ export const dnsServiceInsightsTabList = [
prop: 'sld',
queryCycleTotalProp: 'slds',
dillDownProp: ['dns_qname'],
queryCondition: ['cutToFirstSignificantSubdomain(dns_qname) = \'$param\''],
checked: true,
disabled: false,
panelId: drillDownPanelTypeMapping.dnsFourthMenu
@@ -980,6 +997,7 @@ export const dnsServiceInsightsTabList = [
prop: 'tld',
queryCycleTotalProp: 'tlds',
dillDownProp: ['dns_qname'],
queryCondition: [' topLevelDomain(dns_qname) = \'$param\''],
checked: true,
disabled: false,
panelId: drillDownPanelTypeMapping.dnsFourthMenu
@@ -989,6 +1007,7 @@ export const dnsServiceInsightsTabList = [
prop: 'qtype',
queryCycleTotalProp: 'qtypes',
dillDownProp: ['dns_qtype'],
queryCondition: ['dns_qtype = $param'],
checked: true,
disabled: false,
panelId: drillDownPanelTypeMapping.dnsFourthMenu
@@ -998,6 +1017,7 @@ export const dnsServiceInsightsTabList = [
prop: 'rcode',
queryCycleTotalProp: 'rcodes',
dillDownProp: ['dns_rcode'],
queryCondition: ['dns_rcode = $param'],
checked: true,
disabled: false,
panelId: drillDownPanelTypeMapping.dnsFourthMenu
@@ -1007,6 +1027,7 @@ export const dnsServiceInsightsTabList = [
prop: 'a',
queryCycleTotalProp: 'a',
dillDownProp: ['rr_a'],
queryCondition: ['notEmpty(dns_rr) AND has(JSONExtractArrayRaw(JSON_QUERY(\'$.rr[*].type\', dns_rr) ), \'1\') AND arrayJoin(tupleElement(tupleElement(JSONExtract(dns_rr,\'Tuple(rr Nested(name String, type UInt32, a String))\'), \'rr\'), \'a\')) = \'$param\''],
checked: true,
disabled: false,
panelId: drillDownPanelTypeMapping.dnsFourthMenu
@@ -1016,6 +1037,7 @@ export const dnsServiceInsightsTabList = [
prop: 'aaaa',
queryCycleTotalProp: 'aaaa',
dillDownProp: ['rr_aaaa'],
queryCondition: ['notEmpty(dns_rr) and has(JSONExtractArrayRaw(JSON_QUERY(\'$.rr[*].type\', dns_rr) ), \'28\') AND arrayJoin(tupleElement(tupleElement(JSONExtract(dns_rr,\'Tuple(rr Nested(name String, type UInt32, aaaa String))\'), \'rr\'), \'aaaa\')) = \'$param\''],
checked: true,
disabled: false,
panelId: drillDownPanelTypeMapping.dnsFourthMenu
@@ -1025,6 +1047,7 @@ export const dnsServiceInsightsTabList = [
prop: 'cname',
queryCycleTotalProp: 'cnames',
dillDownProp: ['rr_cname'],
queryCondition: ['notEmpty(dns_rr) and has(JSONExtractArrayRaw(JSON_QUERY(\'$.rr[*].type\', dns_rr) ), \'5\') AND arrayJoin(tupleElement(tupleElement(JSONExtract(dns_rr,\'Tuple(rr Nested(name String, type UInt32, cname String))\'), \'rr\'), \'cname\')) = \'$param\''],
checked: true,
disabled: false,
panelId: drillDownPanelTypeMapping.dnsFourthMenu
@@ -1033,7 +1056,7 @@ export const dnsServiceInsightsTabList = [
// 用于组织数据时的名称,对应的属性名称
export const bytesColumnNameGroupForNpm = {
through: 'throughBitsRate',
totalBytes: 'totalBytes',
tcpConEstLatency: 'establishLatencyMs',
packetLoss: 'tcpLostlenPercent',
packetRetrans: 'pktRetransPercent',
@@ -1041,8 +1064,8 @@ export const bytesColumnNameGroupForNpm = {
httpResponseLatency: 'httpResponseLatency'
}
export const bytesCycleColumnNameGroupForNmp = {
through: 'throughBitsRate'
export const bytesCycleColumnNameGroupForNpm = {
totalBytes: 'totalBytes'
}
// 用于组织数据时的名称,对应的属性名称
@@ -1059,14 +1082,14 @@ export const bytesCycleColumnNameGroupForDns = {
// networkOverview 当前周期返回数据对应的属性名称(与上一周期中的属性名称不一致,total,之所以写在这里是因为有bytepacketssessions3种如果只有一种可以直接写在customTableTitlesForAppPerformance
export const bytesColumnNameGroup = {
total: 'bytesTotalRate',
total: 'totalBitsRate',
inbound: 'inboundBitsRate',
outbound: 'outboundBitsRate',
internal: 'internalBitsRate',
through: 'throughBitsRate'
}
export const packetsColumnNameGroup = {
total: 'packetsTotalRate',
total: 'totalPacketsRate',
inbound: 'inboundPacketsRate',
outbound: 'outboundPacketsRate',
internal: 'internalPacketsRate',
@@ -1077,7 +1100,7 @@ export const sessionsColumnNameGroup = {
}
export const bytesCycleColumnNameGroup = {
total: 'bytesRate'
total: 'bitsRate'
}
export const packetsCycleColumnNameGroup = {
total: 'packetsRate'
@@ -1110,7 +1133,7 @@ export const networkTable = {
bytesColumnNameGroup: bytesColumnNameGroupForNpm,
packetsColumnNameGroup: {}, // 无metric下拉列表条件用不到此属性
sessionsColumnNameGroup: {}, // 无metric下拉列表条件用不到此属性
bytesCycleColumnNameGroup: bytesCycleColumnNameGroupForNmp,
bytesCycleColumnNameGroup: bytesCycleColumnNameGroupForNpm,
packetsCycleColumnNameGroup: {},
sessionsCycleColumnNameGroup: {}
},
@@ -1131,7 +1154,7 @@ export const networkTable = {
hasMetricSearch: false, // 是否有metric下拉列表
panelIdOfThirdMenu: drillDownPanelTypeMapping.linkMonitor,
bytesColumnNameGroup: bytesColumnNameGroupForNpm,
bytesCycleColumnNameGroup: bytesCycleColumnNameGroupForNmp
bytesCycleColumnNameGroup: bytesCycleColumnNameGroupForNpm
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -9,25 +9,42 @@
Score:{{score}}
</div>
</div>
<div class="panel__time">
<date-time-range
class="date-time-range"
:start-time="timeFilter.startTime"
:end-time="timeFilter.endTime"
:date-range="timeFilter.dateRangeValue"
ref="dateTimeRange"
@change="reload"
/>
<time-refresh
class="date-time-range"
@change="timeRefreshChange"
:end-time="timeFilter.endTime"
/>
<div class="panel__tools">
<el-select
size="mini"
v-model="metric"
placeholder=""
popper-class="common-select"
v-if="panelType === panelTypeAndRouteMapping.networkOverview"
:popper-append-to-body="false"
@change="metricChange"
>
<template #prefix>
<span class="select-prefix">Metric:</span>
</template>
<el-option v-for="item in metricOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
<div class="panel__time">
<date-time-range
class="date-time-range"
:start-time="timeFilter.startTime"
:end-time="timeFilter.endTime"
:date-range="timeFilter.dateRangeValue"
ref="dateTimeRange"
@change="reload"
/>
<time-refresh
class="date-time-range"
@change="timeRefreshChange"
:end-time="timeFilter.endTime"
/>
</div>
</div>
</div>
<chart-list
ref="chartList"
:time-filter="timeFilter"
:metric="metric"
:chart-list="chartList"
:panel-type="panelType"
:panel-lock="panelLock"
@@ -42,19 +59,16 @@ import { useRoute } from 'vue-router'
import { ref } from 'vue'
import {
panelTypeAndRouteMapping,
bytesColumnNameGroupForNpm,
scoreUrl,
customTableTitlesForAppPerformance,
operationType,
curTabState,
drillDownPanelTypeMapping
drillDownPanelTypeMapping,
metricOptions
} from '@/utils/constants'
import { getPanelList, getChartList } from '@/utils/api'
import { getNowTime, getSecond } from '@/utils/date-util'
import { getTypeCategory } from '@/views/charts/charts/tools'
import { computeScore, urlParamsHandler, overwriteUrl } from '@/utils/tools'
import { urlParamsHandler, overwriteUrl,getDnsMapData } from '@/utils/tools'
import ChartList from '@/views/charts2/ChartList'
import { get } from '@/utils/http'
import { useStore } from 'vuex'
export default {
name: 'Panel',
@@ -67,10 +81,14 @@ export default {
},
data () {
return {
panelTypeAndRouteMapping,
metricOptions,
chartList: [], // 普通panel的chart
panelLock: true,
extraParams: {},
panelName: '',
dnsRcodeMapData: [],
dnsQtypeMapData: [],
score: null,
curTabState: curTabState
}
@@ -91,7 +109,18 @@ export default {
},
async mounted () {
// this.panelName = this.$store.getters.getPanelName
this.panelName = this.$route.query.panelName ? this.$t(this.$route.query.panelName) : ''
let pName = this.$route.query.panelName ? this.$t(this.$route.query.panelName) : ''
let curTabProp = this.$route.query.dimensionType ? this.$route.query.dimensionType : null
this.dnsQtypeMapData = await getDnsMapData('dnsQtype')
this.dnsRcodeMapData = await getDnsMapData('dnsRcode')
if(curTabProp === 'qtype'){
this.panelName = this.dnsQtypeMapData.get(pName)
}else if(curTabProp === 'rcode'){
this.panelName = this.dnsRcodeMapData.get(pName)
}else {
this.panelName = pName
}
// const curOperationType = this.$store.getters.getTabOperationType
/* const curOperationType = this.getUrlParam(this.curTabState.tabOperationType, '', true)
if (this.panelName && this.$route.path === '/panel/networkAppPerformance' && curOperationType !== operationType.thirdMenu) {
@@ -156,9 +185,34 @@ export default {
})
},
setup (props, ctx) {
// 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()
delete cancelList[index]
})
}
const panel = ref({})
let panelType = 1 // 取得panel的type
const { params, query } = useRoute()
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
})
overwriteUrl(newUrl)
} else {
store.commit('setTimeRangeArray', [])
store.commit('setTimeRangeFlag', null)
}
const thirdPanel = query.thirdPanel
const fourthPanel = query.fourthPanel
if (fourthPanel) {
@@ -187,15 +241,19 @@ 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')
return {
panelType,
panel,
timeFilter,
showScore
showScore,
metric
}
},
methods: {
@@ -233,6 +291,9 @@ export default {
reload (startTime, endTime, dateRangeValue) {
this.timeFilter = { startTime: getSecond(startTime), endTime: getSecond(endTime), dateRangeValue: dateRangeValue }
const { query } = this.$route
this.$store.commit('setTimeRangeArray', [this.timeFilter.startTime, this.timeFilter.endTime])
this.$store.commit('setTimeRangeFlag', dateRangeValue.value)
const newUrl = urlParamsHandler(window.location.href, query, {
startTime: this.timeFilter.startTime,
endTime: this.timeFilter.endTime,
@@ -255,6 +316,13 @@ export default {
} else {
return this.$route.query[param] ? this.$route.query[param] : defaultValue
}
},
metricChange (value) {
const { query } = this.$route
const newUrl = urlParamsHandler(window.location.href, query, {
metric: value
})
overwriteUrl(newUrl)
}
}
}

View File

@@ -189,9 +189,20 @@ export default {
params.q = this.queryCondition
}
this.toggleLoading(true)
get(api.dnsInsight.totalTrafficAnalysis, params).then((res) => {
let url = api.dnsInsight.totalTrafficAnalysis
if (this.queryCondition) {
url = api.dnsInsight.drilldownTrafficAnalysis
}
get(url, params).then((res) => {
if (res.code === 200) {
this.isNoData = res.data.result.length === 0
if (this.isNoData) {
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) => {
if (t.type === 'bytes' && val === 'Bits/s') {
const mpackets = _.cloneDeep(this.mpackets)
@@ -201,10 +212,12 @@ export default {
mpackets[0].data = t.totalBitsRate.values ? t.totalBitsRate.values : []
mpackets[1].data = t.inboundBitsRate.values ? t.inboundBitsRate.values : []
mpackets[2].data = t.outboundBitsRate.values ? t.outboundBitsRate.values : []
let num = 0
mpackets.forEach(e => {
e.unitType = 'bps'
if (e.name !== 'network.total' && e.analysis.avg == 0) {
e.show = false
num += 1
} else {
e.show = true
if (!active && show !== this.lineRefer) {
@@ -212,16 +225,26 @@ export default {
}
}
if (this.lineTab === e.class) {
if (e.analysis.avg < 0) {
if (e.analysis.avg <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
}
}
})
this.mpackets = mpackets
this.$nextTick(() => {
this.echartsInit(this.mpackets, show)
})
if (num === 3) {
mpackets[0].invertTab = false
this.lineTab = 'total'
this.legendSelectChange(mpackets[0], 0)
this.$nextTick(() => {
this.echartsInit(this.mpackets)
})
} else {
this.$nextTick(() => {
this.echartsInit(this.mpackets, show)
})
}
} else if (t.type === 'queries' && val === 'Queries/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalQueryRate.analysis
@@ -231,13 +254,13 @@ export default {
e.show = false
}
e.unitType = 'queries/s'
if (show !== this.lineRefer) {
this.legendSelectChange(e, 0)
}
e.invertTab = false
this.lineTab = 'total'
this.legendSelectChange(e, 0)
})
this.mpackets = mpackets
this.$nextTick(() => {
this.echartsInit(this.mpackets, show)
this.echartsInit(this.mpackets, true)
})
}
})
@@ -346,6 +369,11 @@ export default {
this.chartOption.tooltip.formatter = (params) => {
params.forEach(t => {
t.seriesName = this.$t(t.seriesName)
this.mpackets.forEach(e => {
if (this.$t(e.name) === t.seriesName) {
t.borderColor = chartColor3[e.positioning]
}
})
})
const str = stackedLineTooltipFormatter(params)
return str

View File

@@ -223,7 +223,6 @@ export default {
})
this.linkData = sorted
// todo 此处去重不优美,后续再处理
let directionArr = []
nextHopData.forEach((item) => {
if (item.egressLinkDirection !== '' && item.ingressLinkDirection !== '') {

View File

@@ -236,17 +236,16 @@ export default {
* 本地计算npm分数
*/
localComputeScore (data, bandwidth) {
const keyPre = ['tcp', 'http', 'ssl', 'tcpLost', 'packetRetrans']
let score = 0
keyPre.forEach((item, index) => {
score = computeScore(data, index)
data[keyPre[index] + 'Score'] = score
})
let npmScore = Math.ceil((data.tcpScore + data.httpScore + data.sslScore + data.tcpLostScore + data.packetRetransScore) * 6)
if (npmScore > 6) {
npmScore = 6
const dataScore = {
establishLatencyMs: data.establishLatencyMs || null,
httpResponseLatency: data.httpResponseLatency || null,
sslConLatency: data.sslConLatency || null,
tcpLostlenPercent: data.tcpLostlenPercent || null,
pktRetransPercent: data.pktRetransPercent || null
}
return npmScore
score = computeScore(dataScore)
return score
},
/**
* 计算popover弹窗和右侧数据模块的宽度

View File

@@ -177,6 +177,13 @@ export default {
get(api.linkMonitor.totalTrafficAnalysis, params).then((res) => {
if (res.code === 200) {
this.isNoData = res.data.result.length === 0
if (this.isNoData) {
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) => {
if (t.type === 'bytes' && val === 'Bits/s') {
const mpackets = _.cloneDeep(this.mpackets)
@@ -186,10 +193,12 @@ export default {
mpackets[0].data = t.totalBitsRate.values ? t.totalBitsRate.values : []
mpackets[1].data = t.ingressBitsRate.values ? t.ingressBitsRate.values : []
mpackets[2].data = t.egressBitsRate.values ? t.egressBitsRate.values : []
let num = 0
mpackets.forEach(e => {
e.unitType = 'bps'
if (e.name !== 'network.total' && e.analysis.avg == 0) {
e.show = false
num += 1
} else {
e.show = true
if (!active && !show) {
@@ -197,16 +206,26 @@ export default {
}
}
if (this.lineTab === e.class) {
if (e.analysis.avg < 1) {
if (e.analysis.avg <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
}
}
})
this.mpackets = mpackets
this.$nextTick(() => {
this.echartsInit(this.mpackets)
})
if (num === 3) {
mpackets[0].invertTab = false
this.lineTab = 'total'
this.legendSelectChange(mpackets[0], 0)
this.$nextTick(() => {
this.echartsInit(this.mpackets)
})
} else {
this.$nextTick(() => {
this.echartsInit(this.mpackets)
})
}
} else if (t.type === 'packets' && val === 'Packets/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalPacketsRate.analysis
@@ -215,10 +234,12 @@ export default {
mpackets[0].data = t.totalPacketsRate.values ? t.totalPacketsRate.values : []
mpackets[1].data = t.ingressPacketsRate.values ? t.ingressPacketsRate.values : []
mpackets[2].data = t.egressPacketsRate.values ? t.egressPacketsRate.values : []
let num = 0
mpackets.forEach(e => {
e.unitType = 'packets/s'
if (e.name !== 'network.total' && e.analysis.avg == 0) {
e.show = false
num += 1
} else {
e.show = true
if (!active && !show) {
@@ -226,16 +247,26 @@ export default {
}
}
if (this.lineTab === e.class) {
if (e.analysis.avg < 1) {
if (e.analysis.avg <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
}
}
})
this.mpackets = mpackets
this.$nextTick(() => {
this.echartsInit(this.mpackets)
})
if (num === 3) {
mpackets[0].invertTab = false
this.lineTab = 'total'
this.legendSelectChange(mpackets[0], 0)
this.$nextTick(() => {
this.echartsInit(this.mpackets)
})
} else {
this.$nextTick(() => {
this.echartsInit(this.mpackets)
})
}
}
})
}
@@ -291,12 +322,17 @@ export default {
}
])
},
data: t.data.map(v => [Number(v[0]) * 1000, Number(v[1]), 'number']),
data: t.data.map(v => [Number(v[0]) * 1000, Number(v[1]), 'number'])
}
})
this.chartOption.tooltip.formatter = (params) => {
params.forEach(t => {
t.seriesName = this.$t(t.seriesName)
this.mpackets.forEach(e => {
if (this.$t(e.name) === t.seriesName) {
t.borderColor = chartColor3[e.positioning]
}
})
})
const str = stackedLineTooltipFormatter(params)
return str

View File

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

View File

@@ -3,11 +3,11 @@
<loading :loading="loading"></loading>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('network.total')}}</div>
<div class="link-traffic-list-center-value">{{unitConvert(lineData[0].analysis.avg, unitTypes.bps).join('')}}</div>
<div class="link-traffic-list-center-value" v-if="lineData[0] && lineData[0].analysis">{{unitConvert(lineData[0].analysis.avg, unitTypes.bps).join('')}}</div>
</div>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('linkMonitor.bandwidthUsage')}}</div>
<div class="link-traffic-list-center-value" v-if="bandWidth">{{unitConvert(lineData[0].analysis.avg / bandWidth, unitTypes.percent).join('')}}</div>
<div class="link-traffic-list-center-value" v-if="bandWidth && lineData[0] && lineData[0].analysis">{{unitConvert(lineData[0].analysis.avg / bandWidth, unitTypes.percent).join('')}}</div>
<div class="link-traffic-list-center-value" v-else>-</div>
</div>
<div class="link-traffic-list-center">
@@ -130,17 +130,15 @@ export default {
get(api.linkMonitor.networkAnalysis, params).then(res => {
if (res.code === 200) {
this.isNoData = res.data.result.length === 0
const dataArr = [0, 1, 2, 3, 4]
let scoreAll = 0
dataArr.forEach(e => {
const score = computeScore(res.data.result[0], e)
scoreAll += score
})
this.linkTrafficListData = res.data.result[0]
this.linkTrafficListData.npmScore = Math.ceil(scoreAll * 6)
if (this.linkTrafficListData.npmScore > 6) {
this.linkTrafficListData.npmScore = 6
const data = {
establishLatencyMs: res.data.result[0].establishLatencyMs || null,
httpResponseLatency: res.data.result[0].httpResponseLatency || null,
sslConLatency: res.data.result[0].sslConLatency || null,
tcpLostlenPercent: res.data.result[0].tcpLostlenPercent || null,
pktRetransPercent: res.data.result[0].pktRetransPercent || null
}
this.linkTrafficListData = res.data.result[0]
this.linkTrafficListData.npmScore = computeScore(data)
}
}).catch(e => {
console.error(e)

View File

@@ -1,30 +1,19 @@
<template>
<div class="network-overview-apps">
<div class="line-select-metric">
<span>{{$t('network.metric')}}:</span>
<div class="line-select__operation">
<el-select
size="mini"
v-model="metricFilter"
placeholder=""
popper-class="common-select"
:popper-append-to-body="false"
@change="metricChange"
>
<el-option v-for="item in metricOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</div>
<div class="network-overview-apps-header">
<div class="network-overview-apps-title">{{$t('networkOverview.appType.providerAndApp')}}</div>
</div>
<div class="app-cards">
<div class="app-card" v-for="(app, index) in appData" :key="index">
<div class="app-card" @mouseenter="mouseenter(app)" @mouseleave="mouseleave(app)" v-for="(app, index) in appData" :key="app.type + app.name">
<div class="app-card-title">
<div class="app-card-title-name">
<i class="cn-icon" :class="app.type === 'provider' ? 'cn-icon-entity' : 'cn-icon-app2'"></i>
<span @click="drillDownData(app.type, app.name)">{{app.name}}</span>
</div>
<div class="app-card-title-more" v-ele-click-outside="clickOutSide">
<span><i class="cn-icon cn-icon-more-dark" @click="moreChange(app)"></i></span>
<span class="app-card-title-more-delete" @click="del(app, index)" v-show="app.moreOptions"><i class="cn-icon cn-icon-delete"></i>{{$t('overall.delete')}}</span>
<div class="app-card-title-more">
<span v-show="app.showMore"><i class="cn-icon cn-icon-more-dark" @mouseenter="mouseenterMore(app)"></i></span>
<span class="app-card-title-more-delete" @click="del(app, index)" v-show="app.moreOptions" @mouseleave="mouseleaveMore(app)"><i class="cn-icon cn-icon-delete"></i>{{$t('overall.delete')}}</span>
</div>
</div>
<div class="app-card__bodys">
@@ -44,12 +33,13 @@
</span>
<span v-else>>500.00%</span>
</div>
<div v-else-if="app.value === '-' || app.value === 0" class="app-card__body-content-percent">0</div>
<div v-else-if="app.value === '-' || app.value === 0" class="app-card__body-content-percent">+0.00%</div>
</div>
</div>
<div class="app-card__body-previous">
<div>Total</div>
<div>{{unitConvert(app.total, unitTypes.number).join(' ')}}</div>
<div v-if="metric === 'Bits/s'">{{unitConvert(app.total, unitTypes.byte).join(' ')}}</div>
<div v-else>{{unitConvert(app.total, unitTypes.number).join(' ')}}</div>
</div>
</div>
<div class="chart__drawing" v-show="!isNoData" :id="`chart-${app.name}-${app.type}`"></div>
@@ -77,7 +67,7 @@
</div>
<div class="add-app__body">
<el-tabs v-model="appTypeTab" @tab-click="appTypeTabChange">
<el-tab-pane :label="$t('networkOverview.appType.provider')" :name="0">
<el-tab-pane :label="$t('network.providers')" :name="0">
<div class="body__apps" :class="{'body__apps-no-grid': providerOptions.length === 0}">
<loading :loading="loadingBody"></loading>
<chart-no-data v-if="providerOptions.length === 0 && !loadingBody"></chart-no-data>
@@ -127,7 +117,7 @@ import unitConvert from '@/utils/unit-convert'
import { storageKey, unitTypes, networkTable, operationType, curTabState } from '@/utils/constants'
import * as echarts from 'echarts'
import { appListChartOption } from '@/views/charts2/charts/options/echartOption'
import { ref, shallowRef } from 'vue'
import { shallowRef } from 'vue'
import { get, put } from '@/utils/http'
import { api } from '@/utils/api'
import _ from 'lodash'
@@ -137,7 +127,6 @@ import loading from '@/components/common/Loading'
import ChartNoData from '@/views/charts/charts/ChartNoData'
import { appStackedLineTooltipFormatter } from '@/views/charts/charts/tools'
import chartMixin from '@/views/charts2/chart-mixin'
import { useRoute } from 'vue-router'
export default {
name: 'NetworkOverviewApps',
@@ -148,20 +137,6 @@ export default {
mixins: [chartMixin],
data () {
return {
metricOptions: [
{
value: 'Bits/s',
label: 'Bits/s'
},
{
value: 'Packets/s',
label: 'Packets/s'
},
{
value: 'Sessions/s',
label: 'Sessions/s'
}
],
appData: [],
// 假数据
appTempData: [],
@@ -191,22 +166,18 @@ export default {
urlChangeParams: {}
}
},
props: {
metric: {
type: String,
default: 'Bits/s'
}
},
setup () {
const { query } = useRoute()
const metricFilter = ref(query.appListMetric || 'Bits/s')
return {
metricFilter,
myChart: shallowRef([])
}
},
watch: {
metricFilter (n) {
const { query } = this.$route
const newUrl = urlParamsHandler(window.location.href, query, {
appListMetric: n
})
overwriteUrl(newUrl)
},
showAddApp: {
deep: true,
handler (n) {
@@ -218,10 +189,11 @@ export default {
}
}
},
timeFilter: {
handler (n) {
this.init()
}
timeFilter (n) {
this.init()
},
metric (n) {
this.init()
}
},
methods: {
@@ -273,13 +245,21 @@ export default {
this.toggleLoading(true)
Promise.all([prevRequest, request]).then(res => {
this.isNoData = (res[0].data.result.length && res[1].data.result.length) === 0
if (this.isNoData) {
this.appData = this.appData.map(t => {
return {
name: t.name,
type: t.type
}
})
}
if (res[0].code === 200 && res[1].code === 200) {
const prevData = res[0].data.result
const data = res[1].data.result
let toCompareType = 'bytes'
if (this.metricFilter === 'Sessions/s') {
if (this.metric === 'Sessions/s') {
toCompareType = 'sessions'
} else if (this.metricFilter === 'Packets/s') {
} else if (this.metric === 'Packets/s') {
toCompareType = 'packets'
}
data.forEach(d => {
@@ -463,7 +443,6 @@ export default {
},
addApp (pageNo, val, show) {
this.showAddApp = true
const letter = 'abcdefghijklmnopqrstuvwxyz'
const params = {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
@@ -482,7 +461,7 @@ export default {
} else {
params.pageNo = 1
}
if (this.appTypeTab == 0) {
if (parseFloat(this.appTypeTab) === 0) {
params.type = 'overviewProvide'
get(api.dict, params).then(res => {
if (res.code === 200) {
@@ -507,7 +486,7 @@ export default {
this.loading = false
this.loadingBody = false
})
} else if (this.appTypeTab == 1) {
} else if (parseFloat(this.appTypeTab) === 1) {
params.type = 'overviewApp'
get(api.dict, params).then(res => {
res.data.list = res.data.list.filter(l => !this.appData.some(pd => pd.type === 'app' && pd.name === l.value))
@@ -547,7 +526,7 @@ export default {
cancelApp () {
this.showAddApp = false
},
appTypeTabChange (val) {
appTypeTabChange () {
this.pageObj.pageNo = 1
this.searcherApp = ''
this.addApp()
@@ -690,17 +669,46 @@ export default {
})
}
},
moreChange (app) {
this.appData.forEach(t => {
if (t.name === app.name && t.type === app.type) {
t.moreOptions = !t.moreOptions
}
})
},
// moreChange (app) {
// this.appData.forEach(t => {
// if (t.name === app.name && t.type === app.type) {
// t.moreOptions = !t.moreOptions
// }
// })
// },
resize () {
this.myChart.forEach(t => {
t.resize()
})
},
mouseenterMore (app) {
this.appData.forEach(t => {
if (t.name === app.name && t.type === app.type) {
t.moreOptions = true
}
})
},
mouseleaveMore (app) {
this.appData.forEach(t => {
if (t.name === app.name && t.type === app.type) {
t.moreOptions = false
}
})
},
mouseenter (app) {
this.appData.forEach(t => {
if (t.name === app.name && t.type === app.type) {
t.showMore = true
}
})
},
mouseleave (app) {
this.appData.forEach(t => {
if (t.name === app.name && t.type === app.type) {
t.showMore = false
t.moreOptions = false
}
})
}
},
mounted () {

View File

@@ -26,20 +26,6 @@
</div>
</div>
<div class="line-select line-header-right">
<div class="line-select-metric">
<span>{{$t('network.metric')}}:</span>
<div class="line-select__operation">
<el-select
size="mini"
v-model="lineMetric"
popper-class="common-select"
:popper-append-to-body="false"
@change="metricSelectChange"
>
<el-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</div>
</div>
<div class="line-select-reference-line">
<span>{{$t('network.referenceLine')}}:</span>
<div class="line-select__operation">
@@ -84,37 +70,31 @@ export default {
components: {
ChartNoData
},
props: {
metric: {
type: String,
default: 'Bits/s'
}
},
setup () {
const { query } = useRoute()
const lineMetric = ref(query.lineMetric || 'Bits/s')
const lineRefer = ref(query.lineRefer || 'Average')
const lineTab = ref(query.lineTab || '')
const queryCondition = ref(query.queryCondition || '')
const tabOperationType = ref(query.tabOperationType)
const networkOverviewBeforeTab = ref(query.networkOverviewBeforeTab)
return {
lineMetric,
lineRefer,
lineTab,
queryCondition,
tabOperationType,
networkOverviewBeforeTab,
myChart: shallowRef(null)
}
},
mixins: [chartMixin],
data () {
return {
options1: [
{
value: 'Bits/s',
label: 'Bits/s'
},
{
value: 'Packets/s',
label: 'Packets/s'
},
{
value: 'Sessions/s',
label: 'Sessions/s'
}
],
options2: [
{
value: 'Average',
@@ -159,13 +139,6 @@ export default {
overwriteUrl(newUrl)
})
},
lineMetric (n) {
const { query } = this.$route
const newUrl = urlParamsHandler(window.location.href, query, {
lineMetric: n
})
overwriteUrl(newUrl)
},
lineRefer (n) {
const { query } = this.$route
const newUrl = urlParamsHandler(window.location.href, query, {
@@ -176,31 +149,63 @@ export default {
timeFilter: {
handler (n) {
if (this.lineTab) {
this.init(this.lineMetric, this.showMarkLine, 'active')
this.init(this.metric, this.showMarkLine, 'active')
} else {
this.init()
}
}
},
metric (n) {
this.handleActiveBar()
this.showMarkLine = !this.showMarkLine
this.mpackets.forEach((e, i) => {
if (!e.invertTab) {
e.invertTab = true
}
})
this.init(n, this.showMarkLine, '', n)
}
},
methods: {
init (val, show, active) {
init (val, show, active, n) {
if (!val) {
val = this.lineMetric
val = this.metric
}
const params = {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime)
}
// const condition = this.$store.getters.getQueryCondition
// const condition = this.$route.query.queryCondition ? this.$route.query.queryCondition : ''
if (this.queryCondition) {
let condition = ''
if (this.queryCondition && this.tabOperationType !== '3') {
params.q = this.queryCondition
} else if (this.tabOperationType == '3' && this.queryCondition) {
if (this.queryCondition.indexOf(' OR ') > -1) {
if (this.networkOverviewBeforeTab === 'isp') {
condition = this.queryCondition.split(/["|'= ](.*?)["|'= ]/)
params.q = `notEmpty(${condition[0]}) OR notEmpty(${condition[9]})`
} else {
condition = this.queryCondition.split(/["|'= ](.*?)["|'= ]/)
params.q = `notEmpty(${condition[0]}) OR notEmpty(${condition[5]})`
}
} else {
condition = this.queryCondition.split(/['=](.*?)['=]/)
params.q = `notEmpty(${condition[0]})`
}
}
this.toggleLoading(true)
get(api.netWorkOverview.totalTrafficAnalysis, params).then((res) => {
if (res.code === 200) {
this.isNoData = res.data.result.length === 0
if (this.isNoData) {
this.mpackets = [
{ analysis: {}, name: 'network.total', class: 'total', show: true, invertTab: true, positioning: 0, data: [], unitType: '' },
{ analysis: {}, name: 'network.inbound', class: 'inbound', show: true, invertTab: true, positioning: 1, data: [], unitType: '' },
{ analysis: {}, name: 'network.outbound', class: 'outbound', show: true, invertTab: true, positioning: 2, data: [], unitType: '' },
{ analysis: {}, name: 'network.internal', class: 'internal', show: true, invertTab: true, positioning: 3, data: [], unitType: '' },
{ analysis: {}, name: 'network.through', class: 'through', show: true, invertTab: true, positioning: 4, data: [], unitType: '' },
{ analysis: {}, name: 'network.other', class: 'other', show: true, invertTab: true, positioning: 5, data: [], unitType: '' }
]
}
res.data.result.forEach((t, i) => {
if (t.type === 'bytes' && val === 'Bits/s') {
const mpackets = _.cloneDeep(this.mpackets)
@@ -216,10 +221,12 @@ export default {
mpackets[3].data = t.internalBitsRate.values ? t.internalBitsRate.values : []
mpackets[4].data = t.throughBitsRate.values ? t.throughBitsRate.values : []
mpackets[5].data = t.other.values ? t.other.values : []
let num = 0
mpackets.forEach(e => {
e.unitType = 'bps'
if (e.name !== 'network.total' && e.analysis.avg == 0) {
e.show = false
num += 1
} else {
e.show = true
if (!active && show !== this.lineRefer) {
@@ -227,16 +234,27 @@ export default {
}
}
if (this.lineTab === e.class) {
if (e.analysis.avg < 0) {
if (e.analysis.avg <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
}
}
})
this.mpackets = mpackets
this.$nextTick(() => {
this.echartsInit(this.mpackets, show)
})
if (num === 5) {
mpackets[0].invertTab = false
this.lineTab = 'total'
this.legendSelectChange(mpackets[0], 0)
this.$nextTick(() => {
this.echartsInit(this.mpackets, true)
})
} else {
if (n) this.lineTab = ''
this.$nextTick(() => {
this.echartsInit(this.mpackets, show)
})
}
} else if (t.type === 'packets' && val === 'Packets/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalPacketsRate.analysis
@@ -251,10 +269,12 @@ export default {
mpackets[3].data = t.internalPacketsRate.values ? t.internalPacketsRate.values : []
mpackets[4].data = t.throughPacketsRate.values ? t.throughPacketsRate.values : []
mpackets[5].data = t.other.values ? t.other.values : []
let num = 0
mpackets.forEach(e => {
e.unitType = 'packets/s'
if (e.name !== 'network.total' && e.analysis.avg == 0) {
e.show = false
num += 1
} else {
e.show = true
if (!active && show !== this.lineRefer) {
@@ -262,16 +282,27 @@ export default {
}
}
if (this.lineTab === e.class) {
if (e.analysis.avg < 0) {
if (e.analysis.avg <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
}
}
})
this.mpackets = mpackets
this.$nextTick(() => {
this.echartsInit(this.mpackets, show)
})
if (num === 5) {
mpackets[0].invertTab = false
this.lineTab = 'total'
this.legendSelectChange(mpackets[0], 0)
this.$nextTick(() => {
this.echartsInit(this.mpackets, true)
})
} else {
if (n) this.lineTab = ''
this.$nextTick(() => {
this.echartsInit(this.mpackets, show)
})
}
} else if (t.type === 'sessions' && val === 'Sessions/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalSessionsRate.analysis
@@ -281,13 +312,13 @@ export default {
e.show = false
}
e.unitType = 'sessions/s'
if (show !== this.lineRefer) {
this.legendSelectChange(e, 0)
}
e.invertTab = false
this.lineTab = 'total'
this.legendSelectChange(e, 0)
})
this.mpackets = mpackets
this.$nextTick(() => {
this.echartsInit(this.mpackets, show)
this.echartsInit(this.mpackets, true)
})
}
})
@@ -396,6 +427,11 @@ export default {
this.chartOption.tooltip.formatter = (params) => {
params.forEach(t => {
t.seriesName = this.$t(t.seriesName)
this.mpackets.forEach(e => {
if (this.$t(e.name) === t.seriesName) {
t.borderColor = chartColor3[e.positioning]
}
})
})
const str = stackedLineTooltipFormatter(params)
return str
@@ -407,7 +443,7 @@ export default {
this.lineTab = item.class
this.legendSelectChange(item, index, 'active')
this.showMarkLine = !item.invertTab
this.init(this.lineMetric, this.showMarkLine, 'active')
this.init(this.metric, this.showMarkLine, 'active')
},
mouseenter (item) {
this.mousemoveCursor = item.class
@@ -469,18 +505,6 @@ export default {
resize () {
this.myChart.resize()
},
metricSelectChange (val) {
this.lineMetric = val
this.lineTab = ''
this.handleActiveBar()
this.showMarkLine = !this.showMarkLine
this.mpackets.forEach((e, i) => {
if (!e.invertTab) {
e.invertTab = true
}
})
this.init(val, this.showMarkLine)
},
referenceSelectChange (val) {
this.lineRefer = val
this.echartsInit(this.mpackets, this.showMarkLine)
@@ -538,7 +562,9 @@ export default {
this.timer = setTimeout(() => {
if (this.lineTab) {
const data = this.mpackets.find(t => t.class === this.lineTab)
this.activeChange(data, data.positioning)
if (data && data.positioning) {
this.activeChange(data, data.positioning)
}
} else {
this.init()
}

View File

@@ -12,7 +12,7 @@
<div class="chart-drawing" id="chart2" v-show="!isNoData2"></div>
</div>
</div>
<el-button class="pie-button" size="small">{{$t('network.dashboards')}}<i class="cn-icon cn-icon-arrow-right"></i></el-button>
<el-button class="pie-button" size="small" @click="routerJump">{{$t('network.dashboards')}}<i class="cn-icon cn-icon-arrow-right"></i></el-button>
</div>
</template>
@@ -125,6 +125,15 @@ export default {
})
}
},
routerJump () {
this.$router.push({
path: '/panel/networkAppPerformance',
query: {
tabIndex: 2,
t: +new Date()
}
})
},
resize () {
this.myChart.resize()
this.myChart2.resize()

View File

@@ -134,7 +134,14 @@ import unitConvert from '@/utils/unit-convert'
import { api } from '@/utils/api'
import { getSecond } from '@/utils/date-util'
import { get } from '@/utils/http'
import { getChainRatio, computeScore, changeCurTab, urlParamsHandler, overwriteUrl, getUserDrilldownTableConfig } from '@/utils/tools'
import {
getChainRatio,
computeScore,
changeCurTab,
urlParamsHandler,
overwriteUrl,
getUserDrilldownTableConfig
} from '@/utils/tools'
import chartMixin from '@/views/charts2/chart-mixin'
import ChartNoData from '@/views/charts/charts/ChartNoData'
export default {
@@ -220,24 +227,20 @@ export default {
res.forEach((r, i) => {
if (r.code === 200) {
tableData.forEach(t => {
let score = 0
const find = r.data.result.find(d => d.appSubcategory === t.appSubcategory)
if (find) {
score = computeScore(find, i)
}
t[keyPre[i] + 'Score'] = score
})
} else {
tableData.forEach(t => {
t[keyPre[i] + 'Score'] = 0
t[keyPre[i] + 'Score'] = find
})
}
})
tableData.forEach(t => {
t.score = Math.ceil((t.tcpScore + t.httpScore + t.sslScore + t.tcpLostScore + t.packetRetransScore) * 6)
if (t.score > 6) {
t.score = 6
const data = {
establishLatencyMs: t.tcpScore ? t.tcpScore.establishLatencyMs : null,
httpResponseLatency: t.httpScore ? t.httpScore.httpResponseLatency : null,
sslConLatency: t.sslScore ? t.sslScore.sslConLatency : null,
tcpLostlenPercent: t.tcpLostScore ? t.tcpLostScore.tcpLostlenPercent : null,
pktRetransPercent: t.packetRetransScore ? t.packetRetransScore.pktRetransPercent : null
}
t.score = computeScore(data)
})
this.tableData = tableData
}).finally(() => {

View File

@@ -1,6 +1,6 @@
<template>
<div class="cn-chart__map-title" v-if="tabIndex == 1">{{$t('npm.clientLocation')}}</div>
<div class="cn-chart__map" :class="{'cn-chart__map-drilldown': tabIndex == 1}">
<div class="cn-chart__map-title" v-if="queryCondition">{{$t('npm.clientLocation')}}</div>
<div class="cn-chart__map" :class="{'cn-chart__map-drilldown': queryCondition}">
<div class="map-canvas" id="npmDrillDownMap"></div>
</div>
</template>
@@ -22,8 +22,10 @@ export default {
setup () {
const { query } = useRoute()
const tabIndex = ref(query.tabIndex || '')
const queryCondition = ref(query.queryCondition || '')
return {
tabIndex
tabIndex,
queryCondition
}
},
data () {
@@ -105,24 +107,20 @@ export default {
res2.forEach((r, i) => {
if (r.code === 200) {
mapData.forEach(t => {
let score = 0
const find = r.data.result.find(d => d.country === t.country)
if (find) {
score = computeScore(find, i)
}
t[keyPre[i] + 'Score'] = score
})
} else {
mapData.forEach(t => {
t[keyPre[i] + 'Score'] = 0
t[keyPre[i] + 'Score'] = find
})
}
})
mapData.forEach(t => {
t.score = Math.ceil((t.tcpScore + t.httpScore + t.sslScore + t.tcpLostScore + t.packetRetransScore) * 6)
if (t.score > 6) {
t.score = 6
const data = {
establishLatencyMs: t.tcpScore ? t.tcpScore.establishLatencyMs : null,
httpResponseLatency: t.httpScore ? t.httpScore.httpResponseLatency : null,
sslConLatency: t.sslScore ? t.sslScore.sslConLatency : null,
tcpLostlenPercent: t.tcpLostScore ? t.tcpLostScore.tcpLostlenPercent : null,
pktRetransPercent: t.packetRetransScore ? t.packetRetransScore.pktRetransPercent : null
}
t.score = computeScore(data)
})
this.loadMarkerData(imageSeries, mapData)
})

View File

@@ -14,23 +14,23 @@
<div v-show="!isNoData" class="chart-drawing" :id="`chart${chartData.name}`"></div>
</template>
<template v-else-if="chartData.id === 12">
<div class="npm-line-title">{{$t(chartData.i18n) || chartData.name}}</div>
<div class="npm-line-title">{{$t(chartData.i18n) || chartData.name}}(ms)</div>
<div v-show="!isNoData" class="chart-drawing" :id="`chart${chartData.name}`"></div>
</template>
<template v-else-if="chartData.id === 13">
<div class="npm-line-title">{{$t(chartData.i18n) || chartData.name}}</div>
<div class="npm-line-title">{{$t(chartData.i18n) || chartData.name}}(ms)</div>
<div v-show="!isNoData" class="chart-drawing" :id="`chart${chartData.name}`"></div>
</template>
<template v-else-if="chartData.id === 14">
<div class="npm-line-title">{{$t(chartData.i18n) || chartData.name}}</div>
<div class="npm-line-title">{{$t(chartData.i18n) || chartData.name}}(ms)</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}}(%)</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}}(%)</div>
<div v-show="!isNoData" class="chart-drawing" :id="`chart${chartData.name}`"></div>
</template>
</div>
@@ -47,6 +47,7 @@ import { get } from '@/utils/http'
import { api } from '@/utils/api'
import ChartNoData from '@/views/charts/charts/ChartNoData'
import chartMixin from '@/views/charts2/chart-mixin'
import unitConvert from '@/utils/unit-convert'
export default {
name: 'NpmLine',
@@ -131,11 +132,11 @@ export default {
this.isNoData = res.data.result.length === 0
if (this.chart.params.index === 0) {
res.data.result.forEach((t, i) => {
if (t.type === 'totalBytesRate') {
if (t.type === 'totalBitsRate') {
this.chartOptionLineData[i].values = t.values
} else if (t.type === 'inboundBytesRate') {
} else if (t.type === 'inboundBitsRate') {
this.chartOptionLineData[i].values = t.values
} else if (t.type === 'outboundBytesRate') {
} else if (t.type === 'outboundBitsRate') {
this.chartOptionLineData[i].values = t.values
}
})
@@ -177,9 +178,24 @@ export default {
data: t.values.map((v) => [Number(v[0]) * 1000, Number(v[1]), type])
}
})
this.chartOption.yAxis[0].axisLabel.formatter = (value) => {
if (type === 'percent') {
return unitConvert(value, type)[0]
} else {
return unitConvert(value, 'number').join('')
}
}
this.chartOption.tooltip.formatter = (params) => {
params.forEach(t => {
t.seriesName = this.$t(t.seriesName)
this.chartOptionLineData.forEach(e => {
if (this.$t(e.legend) === t.seriesName) {
t.borderColor = e.color
}
if (this.$t(chartData.i18n) === t.seriesName) {
t.borderColor = t.color
}
})
})
return stackedLineTooltipFormatter(params)
}

View File

@@ -129,23 +129,22 @@ export default {
res2.forEach((r, i) => {
if (r.code === 200) {
mapData.forEach(t => {
let score = 0
const find = r.data.result.find(d => d.country === t.country)
if (find) {
score = computeScore(find, i)
}
t[keyPre[i] + 'Score'] = score
})
} else {
mapData.forEach(t => {
t[keyPre[i] + 'Score'] = 0
t[keyPre[i] + 'Score'] = find
})
}
})
mapData.forEach(t => {
t.score = Math.ceil((t.tcpScore + t.httpScore + t.sslScore + t.tcpLostScore + t.packetRetransScore) * 6)
if (t.score > 6) {
t.score = 6
const data = {
establishLatencyMs: t.tcpScore ? t.tcpScore.establishLatencyMs : null,
httpResponseLatency: t.httpScore ? t.httpScore.httpResponseLatency : null,
sslConLatency: t.sslScore ? t.sslScore.sslConLatency : null,
tcpLostlenPercent: t.tcpLostScore ? t.tcpLostScore.tcpLostlenPercent : null,
pktRetransPercent: t.packetRetransScore ? t.packetRetransScore.pktRetransPercent : null
}
t.score = computeScore(data)
if (t.score === '-') {
t.score = ''
}
})
this.loadMarkerData(imageSeries, mapData)

View File

@@ -98,43 +98,20 @@ export default {
if (type && condition) {
this.toggleLoading(true)
get(api.npm.overview.networkAnalysis, params).then(res => {
const keyPre = ['tcp', 'http', 'ssl', 'tcpLost', 'packetRetrans']
const scoreInfo = {}
let index = 0
let score = 0
if (res.code === 200) {
if (res.data.result.establishLatencyMsAvg || res.data.result.establishLatencyMsAvg === 0) {
res.data.result.establishLatencyMs = res.data.result.establishLatencyMsAvg
index = 0
scoreInfo[keyPre[index] + 'Score'] = computeScore(res.data.result, index)
}
if (res.data.result.httpResponseLatencyAvg || res.data.result.httpResponseLatencyAvg === 0) {
res.data.result.httpResponseLatency = res.data.result.httpResponseLatencyAvg
index = 1
scoreInfo[keyPre[index] + 'Score'] = computeScore(res.data.result, index)
}
if (res.data.result.tcpLostlenPercentAvg || res.data.result.tcpLostlenPercentAvg === 0) {
res.data.result.tcpLostlenPercent = res.data.result.tcpLostlenPercentAvg
index = 3
scoreInfo[keyPre[index] + 'Score'] = computeScore(res.data.result, index)
}
if (res.data.result.pktRetransPercentAvg || res.data.result.pktRetransPercentAvg === 0) {
res.data.result.pktRetransPercent = res.data.result.pktRetransPercentAvg
index = 4
scoreInfo[keyPre[index] + 'Score'] = computeScore(res.data.result, index)
}
if (res.data.result.sslConLatencyAvg || res.data.result.sslConLatencyAvg === 0) {
res.data.result.sslConLatency = res.data.result.sslConLatencyAvg
index = 2
scoreInfo[keyPre[index] + 'Score'] = computeScore(res.data.result, index)
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()
}
scoreInfo.score = Math.ceil((scoreInfo.tcpScore + scoreInfo.httpScore + scoreInfo.sslScore + scoreInfo.tcpLostScore + scoreInfo.packetRetransScore) * 6)
if (scoreInfo.score > 6) {
scoreInfo.score = 6
}
this.$store.commit('setNpmThirdLevelMenuScore', scoreInfo.score)
this.$store.commit('setNpmThirdLevelMenuScore', score)
}).catch(e => {
this.toggleLoading(false)
})
@@ -147,40 +124,21 @@ export default {
this.toggleLoading(true)
Promise.all([tcp, http, ssl, tcpPercent, packetPercent]).then(res => {
this.npmNetworkCycleData = []
const keyPre = ['tcp', 'http', 'ssl', 'tcpLost', 'packetRetrans']
const scoreInfo = {}
let index = 0
let score = 0
res.forEach(t => {
if (t.code === 200) {
if (t.data.result.establishLatencyMsAvg || t.data.result.establishLatencyMsAvg === 0) {
t.data.result.establishLatencyMs = t.data.result.establishLatencyMsAvg
index = 0
}
if (t.data.result.httpResponseLatencyAvg || t.data.result.httpResponseLatencyAvg === 0) {
t.data.result.httpResponseLatency = t.data.result.httpResponseLatencyAvg
index = 1
}
if (t.data.result.tcpLostlenPercentAvg || t.data.result.tcpLostlenPercentAvg === 0) {
t.data.result.tcpLostlenPercent = t.data.result.tcpLostlenPercentAvg
index = 3
}
if (t.data.result.pktRetransPercentAvg || t.data.result.pktRetransPercentAvg === 0) {
t.data.result.pktRetransPercent = t.data.result.pktRetransPercentAvg
index = 4
}
if (t.data.result.sslConLatencyAvg || t.data.result.sslConLatencyAvg === 0) {
t.data.result.sslConLatency = t.data.result.sslConLatencyAvg
index = 2
}
scoreInfo[keyPre[index] + 'Score'] = computeScore(t.data.result, index)
this.npmNetworkCycleData.push(t.data.result)
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)
}
})
scoreInfo.score = Math.ceil((scoreInfo.tcpScore + scoreInfo.httpScore + scoreInfo.sslScore + scoreInfo.tcpLostScore + scoreInfo.packetRetransScore) * 6)
if (scoreInfo.score > 6) {
scoreInfo.score = 6
}
this.$store.commit('setNpmThirdLevelMenuScore', scoreInfo.score)
this.$store.commit('setNpmThirdLevelMenuScore', score)
this.npmNetworkLastCycleQuery()
}).catch(e => {
this.toggleLoading(false)

View File

@@ -1,7 +1,7 @@
<template>
<div class="npm-traffic-line">
<div class="npm-traffic-line-header">
<div class="npm-traffic-line-title">{{$t('overall.traffic')}}</div>
<div class="npm-traffic-line-title"></div>
<div class="line-select-metric">
<span>{{$t('network.metric')}}:</span>
<div class="line-select__operation">
@@ -64,19 +64,19 @@ export default {
unitTypes,
side: '',
mpackets: [
{ name: 'network.total', show: true, positioning: 0, data: [], unitType: '' },
{ name: 'network.inbound', show: true, positioning: 1, data: [], unitType: '' },
{ name: 'network.outbound', show: true, positioning: 2, data: [], unitType: '' },
{ name: 'network.internal', show: true, positioning: 3, data: [], unitType: '' },
{ name: 'network.through', show: true, positioning: 4, data: [], unitType: '' },
{ name: 'network.other', show: true, positioning: 5, data: [], unitType: '' }
{ name: 'network.total', show: true, positioning: 0, data: [], unitType: 'number' },
{ name: 'network.inbound', show: true, positioning: 1, data: [], unitType: 'number' },
{ name: 'network.outbound', show: true, positioning: 2, data: [], unitType: 'number' },
{ name: 'network.internal', show: true, positioning: 3, data: [], unitType: 'number' },
{ name: 'network.through', show: true, positioning: 4, data: [], unitType: 'number' },
{ name: 'network.other', show: true, positioning: 5, data: [], unitType: 'number' }
],
npmQuantity: [
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency', show: true, positioning: 0, data: [], unitType: '' },
{ name: 'networkAppPerformance.httpResponse', show: true, positioning: 0, data: [], unitType: '' },
{ name: 'networkAppPerformance.sslResponseLatency', show: true, positioning: 0, data: [], unitType: '' },
{ name: 'networkAppPerformance.packetLoss', show: true, positioning: 0, data: [], unitType: '' },
{ name: 'overall.packetRetrans', show: true, positioning: 0, data: [], unitType: '' }
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.httpResponse', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.sslResponseLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.packetLoss', show: true, positioning: 0, data: [], unitType: unitTypes.percent },
{ name: 'overall.packetRetrans', show: true, positioning: 0, data: [], unitType: unitTypes.percent }
],
chartData: {},
metricOptions: [
@@ -150,8 +150,10 @@ export default {
}
const params = {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
type: type
endTime: getSecond(this.timeFilter.endTime)
}
if (type) {
params.type = type
}
if (condition && (typeof condition !== 'object') && type) {
params.q = condition
@@ -167,129 +169,346 @@ export default {
}
}
this.toggleLoading(true)
get(api.npm.overview.trafficGraph, params).then((res) => {
if (res.code === 200) {
this.isNoData = res.data.result.length === 0
res.data.result.forEach((t, i) => {
if (t.type === 'bytes' && val === 'Bits/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].data = t.totalBitsRate.values ? t.totalBitsRate.values : []
mpackets[1].data = t.inboundBitsRate.values ? t.inboundBitsRate.values : []
mpackets[2].data = t.outboundBitsRate.values ? t.outboundBitsRate.values : []
mpackets[3].data = t.internalBitsRate.values ? t.internalBitsRate.values : []
mpackets[4].data = t.throughBitsRate.values ? t.throughBitsRate.values : []
mpackets[5].data = t.other.values ? t.other.values : []
mpackets.forEach((e, i) => {
e.show = true
})
this.mpackets = mpackets
this.echartsInit(this.mpackets)
} else if (t.type === 'packets' && val === 'Packets/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].data = t.totalPacketsRate.values ? t.totalPacketsRate.values : []
mpackets[1].data = t.inboundPacketsRate.values ? t.inboundPacketsRate.values : []
mpackets[2].data = t.outboundPacketsRate.values ? t.outboundPacketsRate.values : []
mpackets[3].data = t.internalPacketsRate.values ? t.internalPacketsRate.values : []
mpackets[4].data = t.throughPacketsRate.values ? t.throughPacketsRate.values : []
mpackets[5].data = t.other.values ? t.other.values : []
mpackets.forEach((e, i) => {
e.show = true
})
this.mpackets = mpackets
this.echartsInit(this.mpackets)
} else if (t.type === 'sessions' && val === 'Sessions/s') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[0].data = t.sessionsRate.values ? t.sessionsRate.values : []
npmQuantity.forEach((e, i) => {
if (i !== 0) {
e.show = false
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity)
} else if (t.type === 'establishLatencyMs' && val === 'establishLatencyMs') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[0].data = t.establishLatencyMsAvg.values ? t.establishLatencyMsAvg.values : []
npmQuantity.forEach((e, i) => {
if (i !== 0) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity)
} else if (t.type === 'httpResponseLatency' && val === 'httpResponseLatency') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[1].data = t.httpResponseLatencyAvg.values ? t.httpResponseLatencyAvg.values : []
npmQuantity.forEach((e, i) => {
console.log(e)
if (i !== 1) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity)
} else if (t.type === 'sslConLatency' && val === 'sslConLatency') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[2].data = t.sslConLatencyAvg.values ? t.sslConLatencyAvg.values : []
npmQuantity.forEach((e, i) => {
if (i !== 2) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity)
} else if (t.type === 'tcpLostlenPercent' && val === 'tcpLostlenPercent') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[3].data = t.tcpLostlenPercentAvg.values ? t.tcpLostlenPercentAvg.values : []
npmQuantity.forEach((e, i) => {
if (i !== 3) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity)
} else if (t.type === 'pktRetransPercent' && val === 'pktRetransPercent') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[4].data = t.pktRetransPercentAvg.values ? t.pktRetransPercentAvg.values : []
npmQuantity.forEach((e, i) => {
if (i !== 4) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity)
if (params.type && params.q) {
get(api.npm.overview.trafficGraph, params).then((res) => {
if (res.code === 200) {
this.isNoData = res.data.result.length === 0
if (this.isNoData) {
this.mpackets = [
{ name: 'network.total', show: true, positioning: 0, data: [], unitType: 'number' },
{ name: 'network.inbound', show: true, positioning: 1, data: [], unitType: 'number' },
{ name: 'network.outbound', show: true, positioning: 2, data: [], unitType: 'number' },
{ name: 'network.internal', show: true, positioning: 3, data: [], unitType: 'number' },
{ name: 'network.through', show: true, positioning: 4, data: [], unitType: 'number' },
{ name: 'network.other', show: true, positioning: 5, data: [], unitType: 'number' }
]
this.npmQuantity = [
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.httpResponse', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.sslResponseLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.packetLoss', show: true, positioning: 0, data: [], unitType: unitTypes.percent },
{ name: 'overall.packetRetrans', show: true, positioning: 0, data: [], unitType: unitTypes.percent }
]
}
})
} else {
res.data.result.forEach((t, i) => {
if (t.type === 'bytes' && val === 'Bits/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].data = t.totalBitsRate.values ? t.totalBitsRate.values : []
mpackets[1].data = t.inboundBitsRate.values ? t.inboundBitsRate.values : []
mpackets[2].data = t.outboundBitsRate.values ? t.outboundBitsRate.values : []
mpackets[3].data = t.internalBitsRate.values ? t.internalBitsRate.values : []
mpackets[4].data = t.throughBitsRate.values ? t.throughBitsRate.values : []
mpackets[5].data = t.other.values ? t.other.values : []
mpackets.forEach((e, i) => {
e.show = true
})
this.mpackets = mpackets
this.echartsInit(this.mpackets)
} else if (t.type === 'packets' && val === 'Packets/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].data = t.totalPacketsRate.values ? t.totalPacketsRate.values : []
mpackets[1].data = t.inboundPacketsRate.values ? t.inboundPacketsRate.values : []
mpackets[2].data = t.outboundPacketsRate.values ? t.outboundPacketsRate.values : []
mpackets[3].data = t.internalPacketsRate.values ? t.internalPacketsRate.values : []
mpackets[4].data = t.throughPacketsRate.values ? t.throughPacketsRate.values : []
mpackets[5].data = t.other.values ? t.other.values : []
mpackets.forEach((e, i) => {
e.show = true
})
this.mpackets = mpackets
this.echartsInit(this.mpackets)
} else if (t.type === 'sessions' && val === 'Sessions/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].data = t.totalSessionsRate.values ? t.totalSessionsRate.values : []
mpackets.forEach((e, i) => {
if (i !== 0) {
e.show = false
}
})
this.mpackets = mpackets
this.echartsInit(this.mpackets)
} else if (t.type === 'establishLatencyMs' && val === 'establishLatencyMs') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[0].data = t.establishLatencyMsAvg.values ? t.establishLatencyMsAvg.values : []
npmQuantity.forEach((e, i) => {
if (i !== 0) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(ms)')
} else if (t.type === 'httpResponseLatency' && val === 'httpResponseLatency') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[1].data = t.httpResponseLatencyAvg.values ? t.httpResponseLatencyAvg.values : []
npmQuantity.forEach((e, i) => {
if (i !== 1) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(ms)')
} else if (t.type === 'sslConLatency' && val === 'sslConLatency') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[2].data = t.sslConLatencyAvg.values ? t.sslConLatencyAvg.values : []
npmQuantity.forEach((e, i) => {
if (i !== 2) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(ms)')
} else if (t.type === 'tcpLostlenPercent' && val === 'tcpLostlenPercent') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[3].data = t.tcpLostlenPercentAvg.values ? t.tcpLostlenPercentAvg.values : []
npmQuantity.forEach((e, i) => {
if (i !== 3) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(%)')
} else if (t.type === 'pktRetransPercent' && val === 'pktRetransPercent') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[4].data = t.pktRetransPercentAvg.values ? t.pktRetransPercentAvg.values : []
npmQuantity.forEach((e, i) => {
if (i !== 4) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(%)')
}
})
} else {
this.isNoData = true
}
}).catch(e => {
this.isNoData = true
}).finally(() => {
this.toggleLoading(false)
})
} else {
if (val === 'Bits/s' || val === 'Packets/s' || val === 'Sessions/s') {
this.toggleLoading(true)
get(api.npm.overview.totalTrafficAnalysis, params).then(res => {
if (res.code === 200) {
this.isNoData = res.data.result.length === 0
if (this.isNoData) {
this.mpackets = [
{ name: 'network.total', show: true, positioning: 0, data: [], unitType: 'number' },
{ name: 'network.inbound', show: true, positioning: 1, data: [], unitType: 'number' },
{ name: 'network.outbound', show: true, positioning: 2, data: [], unitType: 'number' },
{ name: 'network.internal', show: true, positioning: 3, data: [], unitType: 'number' },
{ name: 'network.through', show: true, positioning: 4, data: [], unitType: 'number' },
{ name: 'network.other', show: true, positioning: 5, data: [], unitType: 'number' }
]
}
res.data.result.forEach((t, i) => {
if (t.type === 'bytes' && val === 'Bits/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].data = t.totalBitsRate.values ? t.totalBitsRate.values : []
mpackets[1].data = t.inboundBitsRate.values ? t.inboundBitsRate.values : []
mpackets[2].data = t.outboundBitsRate.values ? t.outboundBitsRate.values : []
mpackets[3].data = t.internalBitsRate.values ? t.internalBitsRate.values : []
mpackets[4].data = t.throughBitsRate.values ? t.throughBitsRate.values : []
mpackets[5].data = t.other.values ? t.other.values : []
mpackets.forEach((e, i) => {
e.show = true
})
this.mpackets = mpackets
this.echartsInit(this.mpackets)
} else if (t.type === 'packets' && val === 'Packets/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].data = t.totalPacketsRate.values ? t.totalPacketsRate.values : []
mpackets[1].data = t.inboundPacketsRate.values ? t.inboundPacketsRate.values : []
mpackets[2].data = t.outboundPacketsRate.values ? t.outboundPacketsRate.values : []
mpackets[3].data = t.internalPacketsRate.values ? t.internalPacketsRate.values : []
mpackets[4].data = t.throughPacketsRate.values ? t.throughPacketsRate.values : []
mpackets[5].data = t.other.values ? t.other.values : []
mpackets.forEach((e, i) => {
e.show = true
})
this.mpackets = mpackets
this.echartsInit(this.mpackets)
} else if (t.type === 'sessions' && val === 'Sessions/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].data = t.totalSessionsRate.values ? t.totalSessionsRate.values : []
mpackets.forEach((e, i) => {
if (i !== 0) {
e.show = false
}
})
this.mpackets = mpackets
this.echartsInit(this.mpackets)
}
})
}
}).catch(e => {
this.isNoData = true
}).finally(() => {
this.toggleLoading(false)
})
} else if (val === 'establishLatencyMs' || val === 'tcpLostlenPercent' || val === 'pktRetransPercent') {
this.toggleLoading(true)
get(api.npm.overview.totalNetworkAnalysis, params).then(res => {
if (res.code === 200) {
this.isNoData = res.data.result.length === 0
if (this.isNoData) {
this.npmQuantity = [
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.httpResponse', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.sslResponseLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.packetLoss', show: true, positioning: 0, data: [], unitType: unitTypes.percent },
{ name: 'overall.packetRetrans', show: true, positioning: 0, data: [], unitType: unitTypes.percent }
]
}
res.data.result.forEach((t, i) => {
if (t.type === 'establishLatencyMs' && val === 'establishLatencyMs') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[0].data = t.establishLatencyMs.values ? t.establishLatencyMs.values : []
npmQuantity.forEach((e, i) => {
if (i !== 0) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(ms)')
} else if (t.type === 'tcpLostlenPercent' && val === 'tcpLostlenPercent') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[3].data = t.tcpLostlenPercent.values ? t.tcpLostlenPercent.values : []
npmQuantity.forEach((e, i) => {
if (i !== 3) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(%)')
} else if (t.type === 'pktRetransPercent' && val === 'pktRetransPercent') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[4].data = t.pktRetransPercent.values ? t.pktRetransPercent.values : []
npmQuantity.forEach((e, i) => {
if (i !== 4) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(%)')
}
})
}
}).catch(e => {
this.isNoData = true
}).finally(() => {
this.toggleLoading(false)
})
} else if (val === 'httpResponseLatency') {
this.toggleLoading(true)
get(api.npm.overview.totalHttpResponseDelay, params).then(res => {
if (res.code === 200) {
this.isNoData = res.data.result.length === 0
if (this.isNoData) {
this.npmQuantity = [
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.httpResponse', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.sslResponseLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.packetLoss', show: true, positioning: 0, data: [], unitType: unitTypes.percent },
{ name: 'overall.packetRetrans', show: true, positioning: 0, data: [], unitType: unitTypes.percent }
]
}
res.data.result.forEach(t => {
if (t.type === 'httpResponseLatency' && val === 'httpResponseLatency') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[1].data = t.httpResponseLatency.values ? t.httpResponseLatency.values : []
npmQuantity.forEach((e, i) => {
if (i !== 1) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(ms)')
}
})
}
}).catch(e => {
this.isNoData = true
}).finally(() => {
this.toggleLoading(false)
})
} else if (val === 'sslConLatency') {
this.toggleLoading(true)
get(api.npm.overview.totalSslConDelay, params).then(res => {
if (res.code === 200) {
this.isNoData = res.data.result.length === 0
if (this.isNoData) {
this.npmQuantity = [
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.httpResponse', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.sslResponseLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.packetLoss', show: true, positioning: 0, data: [], unitType: unitTypes.percent },
{ name: 'overall.packetRetrans', show: true, positioning: 0, data: [], unitType: unitTypes.percent }
]
}
res.data.result.forEach(t => {
if (t.type === 'sslConLatency' && val === 'sslConLatency') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[2].data = t.sslConLatency.values ? t.sslConLatency.values : []
npmQuantity.forEach((e, i) => {
if (i !== 2) {
e.show = false
} else {
e.show = true
}
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(ms)')
}
})
}
}).catch(e => {
this.isNoData = true
}).finally(() => {
this.toggleLoading(false)
})
}
}).catch(e => {
console.error(e)
this.isNoData = true
}).finally(() => {
this.toggleLoading(false)
})
}
},
echartsInit (echartsData) {
echartsInit (echartsData, legendUnit) {
echartsData = echartsData.filter(t => t.show === true)
const dom = document.getElementById('chart')
!this.myChart && (this.myChart = echarts.init(dom))
this.chartOption = trafficLineChartOption
const chartOption = this.chartOption.series[0]
this.chartOption.series = echartsData.map((t, i) => {
this.chartOption.yAxis[0].axisLabel.formatter = (value) => {
if (t.unitType === 'percent') {
return unitConvert(value, t.unitType)[0]
} else if (t.unitType === 'time') {
return unitConvert(value, 'number').join('')
} else {
return unitConvert(value, t.unitType).join('')
}
}
return {
...chartOption,
name: this.$t(t.name),
name: this.$t(t.name) + (legendUnit || ''),
lineStyle: {
color: chartColor3[t.positioning],
width: 1
@@ -308,12 +527,26 @@ export default {
}
])
},
data: t.data.map(v => [Number(v[0]) * 1000, Number(v[1]), 'number'])
data: t.data.map(v => [Number(v[0]) * 1000, Number(v[1]), t.unitType])
}
})
this.chartOption.tooltip.formatter = (params) => {
params.forEach(t => {
t.seriesName = this.$t(t.seriesName)
this.mpackets.forEach(e => {
if (this.$t(e.name) === t.seriesName) {
t.borderColor = chartColor3[e.positioning]
}
})
this.npmQuantity.forEach(d => {
const nameMs = this.$t(d.name) + '(ms)'
const namePrent = this.$t(d.name) + '(%)'
if (nameMs === t.seriesName) {
t.borderColor = chartColor3[d.positioning]
} else if (namePrent === t.seriesName) {
t.borderColor = chartColor3[d.positioning]
}
})
})
const str = stackedLineTooltipFormatter(params)
return str

View File

@@ -345,9 +345,9 @@ export const npmLineChartOption = {
show: false
},
axisLabel: {
formatter: function (value) {
return unitConvert(value, unitTypes.number).join('')
}
// formatter: function (value) {
// return unitConvert(value, unitTypes.number).join('')
// }
}
}
],
@@ -384,7 +384,6 @@ export const trafficLineChartOption = {
padding: [0, 0, 0, 2],
fontSize: 12,
color: '#717171',
fontWeight: 400,
fontFamily: 'NotoSansSChineseRegular'
}
},
@@ -416,9 +415,9 @@ export const trafficLineChartOption = {
show: false
},
axisLabel: {
formatter: function (value) {
return unitConvert(value, unitTypes.number).join('')
}
// formatter: function (value) {
// return unitConvert(value, unitTypes.number).join('')
// }
}
}
],

View File

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