Compare commits

..

8 Commits

Author SHA1 Message Date
chenjinsong
823c761adf fix: 修复npm折线图堆叠bug 2023-03-14 17:58:27 +08:00
chenjinsong
9e2f1a02d6 fix: 将entity-detail默认时间查询范围改为1小时 2023-03-11 20:40:35 +08:00
chenjinsong
44e7bbf87d fix: 将entity默认时间查询范围改为1小时 2023-03-11 15:10:27 +08:00
chenjinsong
c6e21a0967 fix: 将detection默认时间查询范围改为1小时 2023-03-11 11:15:41 +08:00
lijinyang
cc847102c4 Merge remote-tracking branch 'origin/dev-22.12' into dev-22.12 2023-02-14 16:35:14 +08:00
lijinyang
56f010e991 Update .gitlab-ci.yml 2023-02-14 16:35:05 +08:00
李金洋
4642003193 Update .gitlab-ci.yml file 2023-02-14 08:24:54 +00:00
lijinyang
89dcd7b253 Update .gitlab-ci.yml 2023-02-14 16:14:25 +08:00
79 changed files with 1620 additions and 3761 deletions

View File

@@ -1,8 +1,7 @@
module.exports = {
env: {
browser: true,
es2021: true,
jest: true
es2021: true
},
extends: [
'plugin:vue/vue3-essential',

View File

@@ -2,7 +2,6 @@
stages:
- gen_git-log
- build_project
- test
- build_image
cache:
@@ -30,7 +29,7 @@ generate_git-log:
- public/index.html
- public/git-log.html
only:
- dev-test
- dev-22.12
tags:
- galaxy
@@ -48,21 +47,11 @@ build_project:
paths:
- dist/
only:
- dev-test
- dev-22.12
- tags
tags:
- galaxy
test:
stage: test
script:
- cnpm run test
when: on_success
only:
- dev-test
tags:
- galaxy
build_image:
dependencies:
- build_project
@@ -76,7 +65,7 @@ build_image:
- sudo docker push 192.168.40.153:9080/cyber-narrator/cn-ui-$CI_COMMIT_REF_NAME:$CNUI_TAG
when: on_success
only:
- dev-test
- dev-22.12
tags:
- galaxy

View File

@@ -6,8 +6,6 @@ module.exports = {
'<rootDir>/test/**/__tests__/**/*.{vue,js,jsx,ts,tsx}',
'<rootDir>/test/**/*.{spec,test}.{vue,js,jsx,ts,tsx}'
],
setupFilesAfterEnv: ['<rootDir>/test/init.js'],
verbose: true,
testEnvironment: 'jsdom',
transform: {
'^.+\\.(vue)$': '<rootDir>/node_modules/vue-jest',

0
npm Normal file
View File

View File

@@ -63,7 +63,7 @@
"@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0",
"@vue/component-compiler-utils": "^3.2.0",
"@vue/test-utils": "^2.2.7",
"@vue/test-utils": "^2.0.0-rc.18",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.0.0",
"compression-webpack-plugin": "^8.0.1",

View File

@@ -1,120 +1,27 @@
<template>
<span test-id="count">{{count}}</span>
<span test-id="id">{{obj.id}}</span>
<span test-id="title">{{obj.title}}</span>
<button test-id="button" @click="click">click</button>
<span test-id="tab">{{lineTab}}</span>
<el-table
:data="tableData"
class="test-table"
height="100%"
empty-text=" "
>
<template v-for="(item, index) in tableTitles" :key="index">
<el-table-column>
<template #default="scope" :column="item">
<span :test-id="`${item.prop}${scope.$index}`">{{scope.row[item.prop]}}</span>
</template>
</el-table-column>
</template>
</el-table>
<span data-test="count">{{count}}</span>
<button data-test="button" @click="click">click</button>
</template>
<script>
/* vue-jest的测试示例 */
import { useRoute, useRouter } from 'vue-router'
import axios from 'axios'
import { ref } from 'vue'
import indexedDBUtils from '@/indexedDB'
import VueRouter from 'vue-router'
export default {
name: 'Test',
data () {
return {
count: 0,
obj: { id: 1, title: 'title' },
differentParamData0: null,
differentParamData1: null,
indexedDBValue: null,
tableData: [
{
name: 'a',
age: 10
},
{
name: 'b',
age: 11
}
],
tableTitles: [
{ label: 'Name', prop: 'name' },
{ label: 'Age', prop: 'age' }
],
mergeRequestData0: null,
mergeRequestData1: null,
mergeRequestChildData0: null,
mergeRequestChildData1: null
count: 0
}
},
methods: {
click () {
this.count++
},
async getObj () {
axios.get('/api/getObjId').then(response => {
this.obj.id = response.data
})
axios.get('/api/getObjTitle').then(response => {
this.obj.title = response.data
})
},
async getCount () {
axios.get('/api/getCount').then(response => {
this.count = response.data
})
},
async differentRequestParam () {
axios.get('/api/differentParam', { params: { name: 0 } }).then(response => {
this.differentParamData0 = response.data
})
axios.get('/api/differentParam', { params: { name: 1 } }).then(response => {
this.differentParamData1 = response.data
})
},
/**
* 同一url不同入参的axios请求内包含多个不同url请求的demo
* @returns {Promise<void>}
*/
async mergeRequest () {
axios.get('/api/differentParam', { params: { name: 0 } }).then(response => {
this.mergeRequestData0 = response.data
})
axios.get('/api/differentParam', { params: { name: 1 } }).then(response => {
this.mergeRequestData1 = response.data
axios.get('/api/getChildId').then(response1 => {
this.mergeRequestChildData0 = response1.data
})
axios.get('/api/getChildTitle').then(response2 => {
this.mergeRequestChildData1 = response2.data
})
})
},
async setIndexedDBValue () {
await indexedDBUtils.selectTable('test').put({ id: 1, name: 'test' })
},
async getIndexedDBValue () {
this.indexedDBValue = await indexedDBUtils.selectTable('test').get(1)
}
},
setup () {
const { query } = useRoute()
const { currentRoute } = useRouter()
const localstorageValue = localStorage.getItem('key')
const lineTab = ref(query.lineTab || '')
const path = currentRoute.value.path
created () {
const { currentRoute } = VueRouter.useRouter()
return {
lineTab,
path,
localstorageValue
currentRoute
}
}
}

View File

@@ -11,9 +11,7 @@
z-index: 999999;
box-shadow: 0 0 10px #CCC;
box-sizing: border-box;
.pop-title {
margin: 10px 0;
}
.el-button--mini{
padding: 5px 7px;
}
@@ -25,6 +23,7 @@
top: 33px;
}
.custom-labels {
margin-top: 12px;
width: 100%;
height: 300px;
}
@@ -42,7 +41,8 @@
font-size: 14px;
}
.custom-label:hover{
background-color: rgba(220, 223, 230, .5)
color: #cccccc;
background-color: #DCDFE6;
}
.custom-title{
padding: 2px 0 2px 2px;
@@ -57,14 +57,6 @@
display: flex;
justify-content: space-between;
align-items: center;
.custom-bottom-btns-right {
.el-button:nth-of-type(1) {
margin-right: 3px;
}
.el-button .top-tool-btn-save {
color: #fff;
}
}
}
.unshow {
display: none;

View File

@@ -98,11 +98,11 @@
//top: 0;
//left: 0;
display: flex;
.line-value-tabs.mousemove-cursor {
.line-value-mpackets.mousemove-cursor {
border-top: 4px solid #D3D0D8;
z-index: 0;
}
.line-value-tabs {
.line-value-mpackets {
cursor: pointer;
padding: 16px 0 0 20px;
border-top: 4px solid transparent;
@@ -122,10 +122,10 @@
}
}
}
.line-value-tabs-name {
.line-value-mpackets-name {
position: relative;
display: flex;
.tabs-name {
.mpackets-name {
flex: 1;
padding-left: 19px;
}

View File

@@ -87,7 +87,7 @@
padding-right: 20px;
&.row__label--width130 {
flex-basis: 140px;
flex-basis: 130px;
padding-right: unset;
}
&.row__label--width160 {

View File

@@ -45,7 +45,6 @@
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useStore } from 'vuex'
export default {
name: 'ChartTabs',
@@ -70,9 +69,8 @@ export default {
setup (props) {
const tabsData = ref([])
const router = useRouter()
const store = useStore()
const routerPath = router.currentRoute.value.path
const tabList = store.getters.getChartTabList
const tabList = window.currentChartTabList
let currentTab = '0'
if (props.data) {
@@ -96,7 +94,7 @@ export default {
return item.path === routerPath
})
currentTab = JSON.stringify(currentTab)
store.dispatch('dispatchChartTabList', [{ path: routerPath, index: currentTab }])
window.currentChartTabList = [{ path: routerPath, index: currentTab }]
} else {
// 此处为切换界面如果window里保存的路径和tabsData里的路径一致选择window数据并使用
// 两个不一致的话则默认选择tabsData里的第一条
@@ -110,15 +108,10 @@ export default {
if (obj0 && obj1) {
currentTab = tabList[1].index
// 场景从遮罩面板进入界面时重置状态默认选中第一个tab
if (routerPath === tabList[0].path) {
currentTab = tabList[0].index
store.dispatch('dispatchChartTabList', [{ path: tabsData.value[0].path, index: '0' }])
}
} else if (obj0) {
currentTab = tabList[0].index
} else {
store.dispatch('dispatchChartTabList', [{ path: tabsData.value[0].path, index: '0' }])
window.currentChartTabList = [{ path: tabsData.value[0].path, index: '0' }]
currentTab = '0'
}
}
@@ -163,10 +156,9 @@ export default {
}
}
})
const tabList = this.$store.getters.getChartTabList
if (tabList && this.router !== 'noRouter') {
tabList.forEach((item) => {
if (window.currentChartTabList && this.router !== 'noRouter') {
window.currentChartTabList.forEach((item) => {
this.$nextTick(() => {
this.handleActiveBar(parseFloat(item.index))
})
@@ -175,7 +167,7 @@ export default {
this.$nextTick(() => {
this.handleActiveBar(this.currentTab)
})
this.$store.dispatch('dispatchChartTabList', null)
window.currentChartTabList = null
}
},
handleActiveBar (index) {
@@ -194,7 +186,7 @@ export default {
} else {
// 数组长度为1即代表刚刷新界面获取active的dom添加样式避免原模式错位问题
// 可添加css样式也可添加class类名两个操作选一即可
if (this.$store.getters.getChartTabList.length === 1) {
if (window.currentChartTabList.length === 1) {
// 此处操作是因为初始化时给active加border导致tab下移故需要将整体往上移动对应高度
const topDom = document.getElementsByClassName('el-tabs__header is-top')
topDom[0].style.cssText += 'top: -3px'
@@ -209,7 +201,6 @@ export default {
},
handleClick (item) {
this.$emit('click', item)
const tabList = this.$store.getters.getChartTabList
if (this.router === 'noRouter') {
const { query } = this.$route
@@ -219,15 +210,14 @@ export default {
})
overwriteUrl(newUrl)
} else {
tabList.push({
window.currentChartTabList.push({
path: this.tabsData[item.index].path,
index: item.index
})
if (tabList.length > 2) {
tabList.splice(0, 1)
if (window.currentChartTabList.length > 2) {
window.currentChartTabList.splice(0, 1)
}
this.$store.dispatch('dispatchChartTabList', tabList)
this.$router.push({
path: this.tabsData[item.index].path,
@@ -240,19 +230,6 @@ export default {
},
beforeUnmount () {
clearTimeout(this.timer)
const path = this.$router.currentRoute.value.path
const list = this.$store.getters.getChartTabList
if (list && this.router !== 'noRouter') {
if (list[1]) {
// 去其他界面,清除状态
if (path !== list[0].path && path !== list[1].path) {
this.$store.dispatch('dispatchChartTabList', null)
}
} else if (path !== list[0].path) {
// 避免刷新页面之后又点击菜单栏进入该界面,还保留上次点击状态
this.$store.dispatch('dispatchChartTabList', null)
}
}
}
}
</script>

View File

@@ -141,6 +141,7 @@ export default {
hoverError (e) {
// const dom = document.getElementById('error-content')
// if (dom) {
// console.log('---', dom.clientHeight)
// }
}
}

View File

@@ -25,7 +25,6 @@
class="date_style"
style="position: absolute;top: -53px;left: -536px;"
:clearable="false"
:default-time="defaultTime"
type="datetimerange"
@change="timeArrChange"
/>
@@ -128,11 +127,6 @@ export default {
{ value: 2880, name: 'last 2 days' }
]
const dropdownFlag = ref(false)
// 默认日历选择时间即开始时间YYYY-MM-DD 00:00:00,结束时间YYYY-MM-DD 59:59:59
const defaultTime = ref([
new Date(2023, 1, 1, 0, 0, 0),
new Date(2023, 1, 2, 23, 59, 59)
])
// computed
const utcStr = computed(() => {
@@ -280,7 +274,6 @@ export default {
rangeEchartsData,
address,
dateRangeArr,
defaultTime,
dateRangeValue,
isCustom,
newDateValue,

View File

@@ -98,6 +98,7 @@ export default {
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()

View File

@@ -103,7 +103,32 @@
<span v-else class="route-menu" @click="jump(route,item,'',3)">{{ $t(item) }}</span>
</template>
<template v-else-if="index===1">
<span class="route-menu" @click="jump(route,'','',2)">{{ item }}</span>
<span class="route-menu" @click="jump(route,'','',2)"
v-if="route.indexOf('detection') === -1 && route.indexOf('administration') === -1">{{ item }}</span>
<!-- <div class="header__left-breadcrumb-item-select" v-if="route.indexOf('detection') > -1">-->
<!-- <el-popover placement="bottom-start"-->
<!-- v-if="route.indexOf('detection') > -1"-->
<!-- ref="breadcrumbPopover"-->
<!-- :show-arrow="false"-->
<!-- :append-to-body="false"-->
<!-- :hide-after="0"-->
<!-- :show-after="0"-->
<!-- popper-class="breadcrumb__popper"-->
<!-- trigger="click">-->
<!-- <template #reference>-->
<!-- <div class="breadcrumb-button" id="breadcrumbButton2" :class="showBackground?'breadcrumb-button__active':''" v-if="route.indexOf('detection') > -1">-->
<!-- <span id="breadcrumbValue2"> {{item}}</span><i class="cn-icon-xiala cn-icon"></i>-->
<!-- </div>-->
<!-- </template>-->
<!-- <el-row type="flex" justify="center" style="width: fit-content;flex-direction: column;">-->
<!-- <ul class="select-dropdown" id="breadcrumbSelectDropdown2">-->
<!-- <li v-for="item in detectionMenuList" title='' :key="item.name" :id="item.name" class="select-dropdown__item" @click="jump(item.path,'','',2)">-->
<!-- <span>{{$t(item.i18n)}}</span>-->
<!-- </li>-->
<!-- </ul>-->
<!-- </el-row>-->
<!-- </el-popover>-->
<!-- </div>-->
</template>
<template v-else>
<span>{{ item }}</span>
@@ -527,7 +552,7 @@ export default {
queryCondition.push('common_l7_protocol=\'' + valueGroup[0] + '\'')
queryCondition.push('common_server_port=' + valueGroup[1])
}
// console.log(queryCondition.join(' AND '))
console.log(queryCondition.join(' AND '))
this.urlChangeParams[this.curTabState.queryCondition] = queryCondition.join(' AND ')
} else {
searchProps.forEach(item => {
@@ -602,11 +627,10 @@ export default {
this.urlChangeParams[this.curTabState.tabOperationBeforeType] = this.getUrlParam(this.curTabState.tabOperationType, '', true)
this.urlChangeParams[this.curTabState.tabOperationType] = opeType
if (opeType === 3) {
/* if (route !== '/panel/networkOverview') {
this.urlChangeParams.queryCondition = ''
} */
if (route !== '/panel/networkOverview') {
this.urlChangeParams.queryCondition = ''
}
}
} else {
this.urlChangeParams[this.curTabState.tabOperationType] = operationType.mainMenu
}

View File

@@ -8,7 +8,7 @@
</div>
<div class="right-box__container">
<div class="container__form">
<el-form ref="reportForm" :model="editObject" :rules="rules" label-position="top" label-width="120px">
<el-form ref="userForm" :model="editObject" :rules="rules" label-position="top" label-width="120px">
<!--name-->
<el-form-item :label="$t('report.name')" prop="name">
<el-input id="account-input-name" v-model="editObject.name" maxlength="64" placeholder=" " show-word-limit size="small" type="text"></el-input>
@@ -19,6 +19,7 @@
v-model="editObject.config.timeConfig.type"
class="right-box__select"
collapse-tags
:disabled="!!editObject.id"
placeholder=" "
popper-class="right-box-select-dropdown right-box-select-report "
size="small"
@@ -30,6 +31,7 @@
</el-select>
<template v-if="editObject.config.timeConfig.type === 'this'">
<el-select id="reportBoxTimeUnitSelect"
:disabled="!!editObject.id"
v-model="editObject.config.timeConfig.unit"
class="right-box__select"
collapse-tags
@@ -43,7 +45,7 @@
</el-select>
</template>
<div v-else-if="editObject.config.timeConfig.type === 'last' || editObject.config.timeConfig.type === 'previous'" style="display: flex;">
<el-input v-model.number="editObject.config.timeConfig.offset" size="small" class="el-input-single" placeholder=" ">
<el-input v-model.number="editObject.config.timeConfig.offset" size="small" class="el-input-single" placeholder=" " :disabled="!!editObject.id">
<template #prepend><i @click="timeOffsetHandle('m')" class="cn-icon cn-icon-a-"></i></template>
<template #append><i @click="timeOffsetHandle('p')" class="cn-icon cn-icon-a-1"></i></template>
</el-input>
@@ -51,6 +53,7 @@
v-model="editObject.config.timeConfig.unit"
class="right-box__select right-box__select-single"
collapse-tags
:disabled="!!editObject.id"
placeholder=" "
popper-class="right-box-select-dropdown el-select-last"
size="small"
@@ -70,8 +73,10 @@
v-model="editObject.config.startTime"
size="small"
:format="dateFormat"
:disabled="!!editObject.id"
:disabled-date="startDisabledDate"
@change="startTimeChang"
@focus="startFocus"
prefix-icon="cn-icon cn-icon-shijian"
type="datetime"
placeholder=" "
@@ -88,8 +93,10 @@
v-model="editObject.config.endTime"
size="small"
:format="dateFormat"
:disabled="!!editObject.id"
:disabled-date="endDisabledDate"
@change="endTimeChange"
@focus="endFocus"
prefix-icon="cn-icon cn-icon-shijian"
type="datetime"
placeholder=" "
@@ -98,41 +105,41 @@
</div>
</el-form-item >
<el-form-item class="el-height">
<el-checkbox v-model="scheduleChecked" :disabled="editObject.config.timeConfig.type === 'customize'" :label="$t('report.enableTimeSchedule')" size="large" />
<el-checkbox v-model="scheduleChecked" :disabled="editObject.config.timeConfig.type === 'customize' || !!editObject.id" :label="$t('report.enableTimeSchedule')" size="large" />
</el-form-item>
<!--Enable time schedule-->
<el-form-item prop="enableTimeSchedule" v-if="scheduleChecked">
<div class="enable-tab">
<div class="enable-tabs" @click="scheduleTypeChange(type.value)" v-for="type in scheduleTypeList" :key="type.value" :class="{'active': scheduleType === type.value}">{{$t(type.name)}}</div>
<div class="enable-tabs" @click="editObject.id ? null : (scheduleType = type.value)" v-for="type in scheduleTypeList" :key="type.value" :class="{'active': scheduleType === type.value, 'disable': editObject.id}">{{$t(type.name)}}</div>
</div>
<div class="enable-tabs-daily" v-if="scheduleType === scheduleTypeList[0].value">
<div class="enable-tabs-custom">{{$t('report.customEvery')}}</div>
<el-input v-model.number="editObject.config.schedulerConfig.interval" size="small" placeholder=" " style="margin-top: 0.3125rem;">
<el-input v-model.number="editObject.config.schedulerConfig.interval" size="small" placeholder=" " style="margin-top: 0.3125rem;" :disabled="!!editObject.id">
<template #append>{{$t('report.day')}}</template>
</el-input>
</div>
<div class="enable-tabs-weekly" v-else-if="scheduleType === scheduleTypeList[1].value">
<div class="enable-tabs-weekly" v-else-if="scheduleType === scheduleTypeList[1].value" :disabled="!!editObject.id">
<!-- 每隔几周暂时隐藏 -->
<!-- <div class="enable-tabs-custom">{{$t('report.customEvery')}}</div>
<el-input v-model="editObject.config.schedulerConfig.interval" size="small" placeholder="Please input">
<template #append>{{$t('report.week')}}</template>
</el-input>-->
<el-checkbox-group v-model="editObject.config.schedulerConfig.weekDates" style="margin-top: 0.3125rem">
<el-checkbox-group v-model="editObject.config.schedulerConfig.weekDates" style="margin-top: 0.3125rem" :disabled="!!editObject.id">
<el-checkbox v-for="(item, index) in weekdayList" :key="index" :label="item.value">{{$t(item.name)}}</el-checkbox>
</el-checkbox-group>
</div>
<!-- -->
<div class="enable-tabs-per-month" v-else-if="scheduleType === scheduleTypeList[2].value">
<div class="enable-month-tab">
<div class="enable-month-tabs" @click="monthScheduleType = 'daily'" :class="{'active': monthScheduleType === 'daily'}">{{$t('report.date')}}</div>
<div class="enable-month-tabs" @click="monthScheduleType = 'weekly'" :class="{'active': monthScheduleType === 'weekly'}">{{$t('report.week')}}</div>
<el-checkbox v-model="monthIsCycle" :label="$t('report.cycle')" size="large"/>
<div class="enable-month-tabs" @click="editObject.id ? null : (monthScheduleType = 'daily')" :class="{'active': monthScheduleType === 'daily', 'disable': editObject.id}">{{$t('report.date')}}</div>
<div class="enable-month-tabs" @click="editObject.id ? null : (monthScheduleType = 'weekly')" :class="{'active': monthScheduleType === 'weekly', 'disable': editObject.id}">{{$t('report.week')}}</div>
<el-checkbox v-model="monthIsCycle" :label="$t('report.cycle')" size="large" :disabled="!!editObject.id"/>
</div>
<div class="enable-month-data-tab">
<!-- 自定义月循环 -->
<template v-if="monthIsCycle">
<div class="enable-tabs-custom">{{$t('report.customEvery')}}</div>
<el-input v-model="editObject.config.schedulerConfig.interval" size="small" placeholder=" " style="margin-top: 0.3125rem;">
<el-input v-model="editObject.config.schedulerConfig.interval" size="small" placeholder=" " style="margin-top: 0.3125rem;" :disabled="!!editObject.id">
<template #append>{{$t('report.month')}}</template>
</el-input>
</template>
@@ -140,8 +147,8 @@
<template v-else>
<div class="enable-month-moon-custom">{{$t('report.custom')}}</div>
<div class="enable-month-all">
<el-checkbox v-model="monthCheckedAll" class="enable-month-all-months" :indeterminate="monthIsIndeterminate" @change="monthCheckAllChange" :label="$t('report.allMonths')"/>
<el-checkbox-group v-model="editObject.config.schedulerConfig.months" @change="monthCheckChange">
<el-checkbox v-model="monthCheckedAll" class="enable-month-all-months" :indeterminate="monthIsIndeterminate" @change="monthCheckAllChange" :label="$t('report.allMonths')" :disabled="!!editObject.id"/>
<el-checkbox-group v-model="editObject.config.schedulerConfig.months" @change="monthCheckChange" :disabled="!!editObject.id">
<el-checkbox v-for="(item, index) in monthList" :key="index" :label="item.value">{{$t(item.name)}}</el-checkbox>
</el-checkbox-group>
</div>
@@ -149,8 +156,8 @@
<!-- 按日期 -->
<template v-if="monthScheduleType === 'daily'">
<div class="enable-month-data-tabs">
<el-checkbox v-model="dateCheckedAll" :indeterminate="dateIsIndeterminate" @change="dateCheckAllChange" :label="$t('report.all')" size="large"/>
<el-checkbox-group v-model="editObject.config.schedulerConfig.monthDates" @change="dateCheckChange">
<el-checkbox v-model="dateCheckedAll" :indeterminate="dateIsIndeterminate" @change="dateCheckAllChange" :label="$t('report.all')" size="large" :disabled="!!editObject.id"/>
<el-checkbox-group v-model="editObject.config.schedulerConfig.monthDates" @change="dateCheckChange" :disabled="!!editObject.id">
<el-checkbox v-for="item in dateList" :key="item" :label="item"/>
</el-checkbox-group>
</div>
@@ -163,6 +170,7 @@
class="right-box__select"
multiple
placeholder=" "
:disabled="!!editObject.id"
popper-class="right-box-select-dropdown right-box-select-report"
size="small"
@change="()=>{ this.$forceUpdate() }">
@@ -171,8 +179,8 @@
</template>
</el-select>
<div class="enable-month-week">
<el-checkbox v-model="monthWeekdayCheckedAll" class="enable-month-week-all" :label="$t('report.all')" :indeterminate="monthWeekdayIsIndeterminate" @change="monthWeekdayCheckAllChange" size="large"/>
<el-checkbox-group v-model="editObject.config.schedulerConfig.weekDates" @change="monthWeekdayCheckChange">
<el-checkbox v-model="monthWeekdayCheckedAll" class="enable-month-week-all" :label="$t('report.all')" :indeterminate="monthWeekdayIsIndeterminate" @change="monthWeekdayCheckAllChange" size="large" :disabled="!!editObject.id"/>
<el-checkbox-group v-model="editObject.config.schedulerConfig.weekDates" @change="monthWeekdayCheckChange" :disabled="!!editObject.id">
<el-checkbox v-for="(item, index) in weekdayList" :key="index" :label="item.value">{{$t(item.name)}}</el-checkbox>
</el-checkbox-group>
</div>
@@ -222,7 +230,7 @@
:disabled="!!editObject.id"
popper-class="right-box-select-dropdown right-box-select-report"
size="small"
>
@change="typeChange">
<template v-for="category in categoryList" :key="category.id">
<el-option :label="category.name" :value="category.id"></el-option>
</template>
@@ -275,44 +283,8 @@ import { api } from '@/utils/api'
import _ from 'lodash'
import { get, post, put } from '@/utils/http'
import { dateFormat, getMillisecond } from '@/utils/date-util'
import { ref, getCurrentInstance } from 'vue'
import i18n from '@/i18n'
export default {
name: 'ReportBox',
mixins: [rightBoxMixin],
props: {
categoryList: Array,
currentCategoryId: Number
},
setup () {
const { proxy } = getCurrentInstance()
const startTime = ref('')
const endTime = ref('')
function endTimeChange (val) {
endTime.value = val
}
function startTimeChang (val) {
startTime.value = val
}
const endDisabledDate = (time) => {
if (time.getTime() > new Date()) {
return true
}
if (startTime.value !== '' && startTime.value > time) {
return true
}
}
const startDisabledDate = (time) => {
if (time.getTime() > new Date()) {
return true
}
if (endTime.value !== '' && endTime.value < time) {
return true
}
}
const paramValidator = (rule, value, callback) => {
import { ref } from 'vue'
const paramValidator = (rule, value, callback) => {
let validate = true
if (value && value.length > 0) {
const hasEmpty = value.some(v => {
@@ -321,57 +293,75 @@ export default {
validate = !hasEmpty
}
return validate
}
const nameValidator = (rule, value, callback) => {
}
const nameValidator = (rule, value, callback) => {
let validate = true
const reg = /^[\u4e00-\u9fa5A-Za-z0-9\-\_]*$/
validate = reg.test(value)
return validate
}
const startTimeValidator = (rule, value, callback) => {
const form = proxy.$refs.reportForm
if (form.model.config.endTime) {
form.validateField('config.endTime', () => null)
}
callback()
}
const endTimeValidator = (rule, value, callback) => {
let validate = true
if (startTime.value !== '' && value <= startTime.value) {
if (reg.test(value)) {
validate = true
} else {
validate = false
}
return validate
}
export default {
name: 'ReportBox',
mixins: [rightBoxMixin],
props: {
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
}
const rules = { // 表单校验规则
name: [
{ required: true, message: i18n.global.t('validate.required'), trigger: 'blur' },
{ validator: nameValidator, message: i18n.global.t('validate.onlyAllowNumberLetterChinese-_'), trigger: 'blur' }
],
categoryId: [
{ required: true, message: i18n.global.t('validate.required'), trigger: 'change' }
],
schedulerStart: [
{ required: true, message: i18n.global.t('validate.required'), trigger: 'change' }
],
'config.startTime': [
{ required: true, message: i18n.global.t('validate.required'), trigger: 'change' },
{ validator: startTimeValidator, trigger: 'change' }
],
'config.endTime': [
{ required: true, message: i18n.global.t('validate.required'), trigger: 'change' },
{ validator: endTimeValidator, message: i18n.global.t('validate.endTimeGreaterThanStart'), trigger: 'change' }
],
categoryParams: [
{ required: true, message: i18n.global.t('validate.required'), trigger: 'blur' },
{ validator: paramValidator, message: i18n.global.t('validate.required'), trigger: 'blur' }
]
}
return {
endDisabledDate,
startDisabledDate,
startTimeChang,
endTimeChange,
rules
startFocus,
endFocus
}
},
data () {
@@ -401,20 +391,48 @@ export default {
monthWeekdayCheckedAll: false,
monthWeekdayIsIndeterminate: false,
rules: { // 表单校验规则
name: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' },
{ validator: nameValidator, message: this.$t('validate.onlyAllowNumberLetterChinese-_'), trigger: 'blur' }
],
categoryId: [
{ required: true, message: this.$t('validate.required'), trigger: 'change' }
],
schedulerStart: [
{ required: true, message: this.$t('validate.required'), trigger: 'change' }
],
'config.startTime': [
{ required: true, message: this.$t('validate.required'), trigger: 'change' }
],
'config.endTime': [
{ required: true, message: this.$t('validate.required'), trigger: 'change' }
],
categoryParams: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' },
{ validator: paramValidator, message: this.$t('validate.required'), trigger: 'blur' }
]
},
paramsOptions: []
}
},
watch: {
scheduleType (n, o) {
this.editObject.config.schedulerConfig.type = n
if (!this.editObject.id) {
this.cleanScheduleConfig()
}
},
scheduleChecked (n) {
this.editObject.config.isScheduler = n ? 1 : 0
if (!this.editObject.id) {
this.cleanScheduleConfig()
}
},
monthScheduleType (n) {
if (!this.editObject.id) {
this.cleanScheduleConfig()
}
},
monthIsCycle (n) {
if (!this.editObject.id) {
@@ -548,13 +566,15 @@ export default {
this.editObject.config.timeConfig.offset--
}
}
},
typeChange (id) {
},
cleanScheduleConfig () {
this.editObject.config.schedulerConfig.monthDates = []
this.editObject.config.schedulerConfig.weekDates = []
this.editObject.config.schedulerConfig.months = []
this.editObject.config.schedulerConfig.monthWeekDates = []
this.editObject.config.schedulerConfig.interval = 1
this.monthIsCycle = true
this.dateCheckedAll = false
this.dateIsIndeterminate = false
@@ -568,14 +588,11 @@ export default {
this.scheduleChecked = false
}
},
scheduleTypeChange (val) {
this.scheduleType = val
},
save () {
if (this.blockOperation.save) { return }
this.blockOperation.save = true
this.$refs.reportForm.validate((valid) => {
this.$refs.userForm.validate((valid) => {
if (valid) {
let startTime = ''
let endTime = ''

View File

@@ -25,12 +25,12 @@
<el-button size="mini" v-if="!isCancel" :id="tableId+'-element-set-all'" class="cn-btn cn-btn-size-small-new cn-btn-style-light-new" type="button" @click="batchHandler(true)">
<span class="top-tool-btn-txt">{{$t('overall.all')}}</span>
</el-button>
<div class="custom-bottom-btns-right">
<div>
<el-button size="mini" :id="tableId+'-element-set-esc'" class="cn-btn cn-btn-size-small-new cn-btn-style-light-new" type="button" @click="esc">
<span class="top-tool-btn-txt">{{$t('overall.cancel')}}</span>
</el-button>
<el-button size="mini" :id="tableId+'-element-set-save'" class="cn-btn cn-btn-size-small-new cn-btn-style-normal-new" type="button" @click="save" style="background-color: #0091ff;color:#DCDFE6">
<span class="top-tool-btn-txt top-tool-btn-save">{{$t('overall.save')}}</span>
<span class="top-tool-btn-txt">{{$t('overall.save')}}</span>
</el-button>
</div>
</div>

View File

@@ -1,19 +1,8 @@
import { dbName, dbGeoDataTableName, dbDrilldownTableConfig } from '@/utils/constants'
import Dexie from 'dexie'
/* https://dexie.org/ */
const db = new Dexie(dbName)
db.version(3).stores({
export const db = new Dexie(dbName)
db.version(2).stores({
[dbGeoDataTableName]: '++name, geo',
[dbDrilldownTableConfig]: '++id, config',
test: '++id, name'
[dbDrilldownTableConfig]: '++id, config'
})
function selectTable (tableName) {
return db[tableName]
}
const indexedDBUtils = {
db,
selectTable
}
export default indexedDBUtils

View File

@@ -1,5 +1,6 @@
import { hasButton } from '@/permission'
import { dateFormatByAppearance } from '@/utils/date-util'
import { storageKey } from '@/utils/constants'
export default {
data () {
return {
@@ -20,9 +21,7 @@ export default {
query: false
},
timeout: null,
debounceFunc: null,
// 是否正在单元测试
isUnitTesting: false
debounceFunc: null
}
},
methods: {

View File

@@ -59,8 +59,7 @@ const panel = {
rangeEchartsData: {}, // 框选echarts图表
routerHistoryList: [], // 路由跳转记录列表
dnsQtypeMapData: [],
dnsRcodeMapData: [],
chartTabList: null // chartTabs组件的tab状态点击列表初始化为null方便原有逻辑计算
dnsRcodeMapData: []
},
mutations: {
setShowRightBox (state, flag) {
@@ -152,9 +151,6 @@ const panel = {
},
setRouterHistoryList (state, list) {
state.routerHistoryList = list
},
setChartTabList (state, list) {
state.chartTabList = list
}
},
getters: {
@@ -229,9 +225,6 @@ const panel = {
},
getRouterHistoryList (state) {
return state.routerHistoryList
},
getChartTabList (state) {
return state.chartTabList
}
},
actions: {
@@ -260,9 +253,6 @@ const panel = {
},
clearPanel (store) {
store.commit('cleanPanel')
},
dispatchChartTabList (store, list) {
store.commit('setChartTabList', list)
}
}
}

View File

@@ -5,7 +5,7 @@ import { ElMessage } from 'element-plus' // dependent on utc plugin
import { storageKey, dbDrilldownTableConfig } from '@/utils/constants'
import { getConfigVersion } from '@/utils/tools'
import { api } from '@/utils/api'
import indexedDBUtils from '@/indexedDB'
import { db } from '@/indexedDB'
const user = {
state () {
@@ -92,7 +92,7 @@ const user = {
if (res.code === 200 && res.page.list && res.page.list.length > 0) {
// 从接口返回整体配置,再读取用户缓存,将对应条目覆盖,作为使用的配置
const defaultConfigs = JSON.parse(res.page.list[0].cvalue)
await indexedDBUtils.selectTable(dbDrilldownTableConfig).put({
await db[dbDrilldownTableConfig].put({
id: 'default',
version: defaultConfigs.version,
config: defaultConfigs.config
@@ -100,7 +100,7 @@ const user = {
const userId = localStorage.getItem(storageKey.userId)
const oldVersion = await getConfigVersion(userId)
if (oldVersion !== defaultConfigs.version) {
indexedDBUtils.selectTable(dbDrilldownTableConfig).delete(userId)
db[dbDrilldownTableConfig].delete(userId)
}
}
})

View File

@@ -318,12 +318,11 @@ export async function getI18n () {
/* 获得原始的3611-2 json字符串数据 */
export async function getIso36112JsonData (suffix) {
const url = `${window.location.protocol}//${window.location.host}/geojson/${suffix}.json`
const request = new Promise(resolve => {
axios({ url }).then(response => {
axios({
url: `${window.location.protocol}//${window.location.host}:${window.location.port}/geojson/${suffix}.json`
}).then(response => {
resolve(response.data || response || null)
}).catch(err => {
console.error(err)
})
})
return await request

View File

@@ -1,8 +1,6 @@
export const defaultPageSize = 20
// indexedDB库名
export const dbName = 'cn-db'
// indexedDB表名
export const dbGeoDataTableName = 'geodata'
export const dbDrilldownTableConfig = 'cn-drilldown-table-config'
export const storageKey = {

View File

@@ -5,7 +5,8 @@ import { storageKey, iso36112, topDomain, echartsFontSize, dbGeoDataTableName, n
import { getIso36112JsonData, getDictList } from '@/utils/api'
import { format } from 'echarts'
import router from '@/router'
import indexedDBUtils from '@/indexedDB'
import { db } from '@/indexedDB'
import { useRoute } from 'vue-router'
export const tableSort = {
// 是否需要排序
@@ -487,11 +488,11 @@ export function loadGeoData () {
keys.push(storageKey.iso36112Capital)
keys.push(storageKey.iso36112WorldLow)
keys.forEach(async k => {
const queryData = await indexedDBUtils.selectTable(dbGeoDataTableName).get({ name: k })
const queryData = await db[dbGeoDataTableName].get({ name: k })
if (!queryData) {
const data = await getIso36112JsonData(iso36112[k])
if (data) {
indexedDBUtils.selectTable(dbGeoDataTableName).add({
db[dbGeoDataTableName].add({
name: k,
geo: data
})
@@ -504,14 +505,14 @@ export function loadGeoData () {
* 使用indexedDB缓存地图数据
* */
export async function getGeoData (key) {
const data = await indexedDBUtils.selectTable(dbGeoDataTableName).get({ name: key })
const data = await db[dbGeoDataTableName].get({ name: key })
if (data) {
return data.geo
} else {
if (iso36112[key]) {
const d = await getIso36112JsonData(iso36112[key])
if (d) {
indexedDBUtils.selectTable(dbGeoDataTableName).add({
db[dbGeoDataTableName].add({
name: key,
geo: d
})
@@ -936,7 +937,7 @@ export async function getDefaultCurTab (tableType, metric, columnName) {
export async function readDrilldownTableConfigByUser () {
// 获取用户定制的自定义配置
const userId = localStorage.getItem(storageKey.userId)
const userLocalConfig = await indexedDBUtils.selectTable(dbDrilldownTableConfig).get({ id: userId })
const userLocalConfig = await db[dbDrilldownTableConfig].get({ id: userId })
let defaultDrillDownTableConfigs = []
if (userLocalConfig) {
defaultDrillDownTableConfigs = userLocalConfig.config
@@ -945,15 +946,15 @@ export async function readDrilldownTableConfigByUser () {
}
export async function getConfigVersion (id) {
let defaultConfigInDb = await indexedDBUtils.selectTable(dbDrilldownTableConfig).get({ id: id })
let defaultConfigInDb = await db[dbDrilldownTableConfig].get({ id: id })
if (!defaultConfigInDb) {
defaultConfigInDb = await indexedDBUtils.selectTable(dbDrilldownTableConfig).get({ id: 'default' })
defaultConfigInDb = await db[dbDrilldownTableConfig].get({ id: 'default' })
}
return defaultConfigInDb.version || ''
}
export async function combineDrilldownTableWithUserConfig () {
const defaultConfigInDb = await indexedDBUtils.selectTable(dbDrilldownTableConfig).get({ id: 'default' })
const defaultConfigInDb = await db[dbDrilldownTableConfig].get({ id: 'default' })
const defaultConfigGroup = defaultConfigInDb ? defaultConfigInDb.config : []
const currentUserConfigGroup = await readDrilldownTableConfigByUser()
if (defaultConfigGroup && currentUserConfigGroup && currentUserConfigGroup.length > 0) {
@@ -1085,64 +1086,3 @@ export function colorGradientCalculation (startColor, endColor, values) {
export function colorHexToRgbArr (hex) {
return [1, 3, 5].map((h) => parseInt(hex.substring(h, h + 2), 16))
}
/**
* 通过事件类型eventType转换对应名称
* @param type
* @returns {string}
*/
export function getNameByEventType (type) {
switch (type) {
case 'http error': {
return 'http error ratio'
}
case 'dns error': {
return 'dns error ratio'
}
case 'high dns response time': {
return 'dns response time'
}
}
}
/**
折线图通过事件类型 type 转换对应名称
*/
export function getLineType (type) {
switch (type) {
case 'bytes': {
return 'Bits/s'
}
case 'packets': {
return 'Packets/s'
}
case 'sessions': {
return 'Sessions/s'
}
case 'queries': {
return 'Queries/s'
}
default: return type
}
}
/**
npm折线图通过事件类型 type 转换对应 index 以及 unit
*/
export function getLineIndexUnit (type, show) {
switch (type) {
case 'establishLatencyMs': {
return show ? '(ms)' : 0
}
case 'tcpLostlenPercent': {
return show ? '(%)' : 3
}
case 'pktRetransPercent': {
return show ? '(%)' : 4
}
case 'httpResponseLatency': {
return show ? '(ms)' : 1
}
case 'sslConLatency': {
return show ? '(ms)' : 2
}
}
}

View File

@@ -43,6 +43,16 @@ export default {
i18n: 'I18n',
path: '/administration/i18n',
icon: 'cn-icon cn-icon-i18n'
},
{
i18n: 'galaxyProxy.galaxyProxy',
path: '/administration/galaxyProxy',
icon: 'cn-icon cn-icon-proxy'
},
{
i18n: 'overall.chart',
path: '/administration/chart',
icon: 'cn-icon cn-icon-chart'
}
]
}

View File

@@ -247,9 +247,8 @@ import {
chartActiveIpTableOrderOptions,
chartPieTableTopOptions,
eventSeverity,
chartTableColumnMapping, panelTypeAndRouteMapping
chartTableColumnMapping
} from '@/utils/constants'
import { useRouter } from 'vue-router'
export default {
name: 'ChartHeader',
@@ -370,17 +369,12 @@ export default {
}
},
setup (props) {
const { currentRoute } = useRouter()
function isEntityDetail (r) {
return r.indexOf('entityDetail') > -1
}
const dateRangeValue = isEntityDetail(currentRoute.value.path) ? 60 * 24 : 60
const dateRangeValue = 60
const { startTime, endTime } = getNowTime(dateRangeValue)
// entity详情内的chart时间工具不是公共的需要单独定义
const chartTimeFilter = ref({ startTime, endTime, dateRangeValue })
// 复制一份prop中需要被组件v-model的内容避免报错
const copyOrderPieTable = props.orderPieTable
const copyOrderPieTable = ref(props.orderPieTable)
return {
chartTimeFilter,
chartTableTopOptions,

View File

@@ -107,11 +107,8 @@ export default {
const { params } = useRoute()
panelType = props.entity ? props.entity.type : panelTypeAndRouteMapping[params.typeName]
function isEntityDetail (t) {
return [4, 5, 6].indexOf(t) > -1
}
// date
const dateRangeValue = isEntityDetail(panelType) ? 60 * 24 : 60
const dateRangeValue = 60
const { startTime, endTime } = getNowTime(dateRangeValue)
const timeFilter = ref({ startTime, endTime, dateRangeValue })
@@ -150,12 +147,14 @@ export default {
if (panels && panels.length > 0) {
this.panel = panels[0]
}
// 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)
const allCharts = (await getChartList({ panelId: this.panel.id, pageSize: -1 })).map(chart => {
chart.i = chart.id
this.recursionParamsConvert(chart)

View File

@@ -114,8 +114,8 @@ export default {
},
reload () {
this.copyDataList.forEach(item => {
if (this.$refs['chart' + item.id] && this.$refs['chart' + item.id][0]) {
this.$refs['chart' + item.id][0].reload()
if (this.$refs['chart' + item.id]) {
this.$refs['chart' + item.id].reload()
}
})
},

View File

@@ -32,8 +32,8 @@ export default {
methods: {
reload () {
this.dnsScreenDataList.forEach(item => {
if (this.$refs['chart' + item.id] && this.$refs['chart' + item.id][0]) {
this.$refs['chart' + item.id][0].getChartData()
if (this.$refs['chart' + item.id]) {
this.$refs['chart' + item.id].getChartData()
}
})
}

View File

@@ -238,20 +238,16 @@ export default {
} else {
panelType = props.entity ? props.entity.type : panelTypeAndRouteMapping[params.typeName]
}
function isEntityDetail (t) {
return [4, 5, 6].indexOf(t) > -1
}
// 获取url携带的range、startTime、endTime
const rangeParam = query.range
const startTimeParam = query.startTime
const endTimeParam = query.endTime
// 若url携带了使用携带的值否则使用默认值。
const dateRangeValue = rangeParam ? parseInt(query.range) : (isEntityDetail(panelType) ? 60 * 24 : 60)
const dateRangeValue = rangeParam ? parseInt(query.range) : 60
const timeFilter = ref({ dateRangeValue })
if (!startTimeParam || !endTimeParam) {
const { startTime, endTime } = getNowTime(isEntityDetail(panelType) ? 60 * 24 : 60)
const { startTime, endTime } = getNowTime(60)
timeFilter.value.startTime = startTime
timeFilter.value.endTime = endTime
} else {
@@ -334,8 +330,6 @@ export default {
if (!this.$refs.dateTimeRange.isCustom) {
const value = this.timeFilter.dateRangeValue
this.$refs.dateTimeRange.quickChange(value)
} else {
this.timeFilter = JSON.parse(JSON.stringify(this.timeFilter))
}
} else {
this.timeFilter = JSON.parse(JSON.stringify(this.timeFilter))

View File

@@ -123,8 +123,11 @@ export default {
this.toggleLoading(true)
get(api.dnsInsight.activeMaliciousDomain, params).then(res => {
if (res.code === 200) {
this.isNoData = res.data.result.length === 0
this.tableData = res.data.result
const data = res.data.result
if (!data || data.length === 0) {
this.isNoData = true
}
this.tableData = data
} else {
this.isNoData = true
}

View File

@@ -95,9 +95,6 @@ export default {
},
beforeUnmount () {
window.removeEventListener('resize', this.resize)
if (this.myChart) {
echarts.dispose(this.myChart)
}
}
}
</script>

View File

@@ -147,9 +147,6 @@ export default {
},
beforeUnmount () {
window.removeEventListener('resize', this.resize)
if (this.myChart) {
echarts.dispose(this.myChart)
}
}
}
</script>

View File

@@ -208,7 +208,9 @@ export default {
this.toggleLoading(true)
get(api.dnsInsight.recentEvents, params).then(res => {
if (res.code === 200) {
this.isNoData = res.data.result.length === 0
if (!res.data.result || res.data.result.length === 0) {
this.isNoData = true
}
this.tableData = res.data.result
this.tableData.forEach((t, index) => {
if (index > 5) {

View File

@@ -5,17 +5,17 @@
<div class="line-header-left">
<div class="line-value-active" v-if="lineTab"></div>
<div class="line-value">
<div class="line-value-tabs"
<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 tabs"
v-for="(item, index) in mpackets"
:key="index"
@mouseenter="mouseenter(item)"
@mouseleave="mouseleave(item)"
@click="activeChange(item, index)">
<div class="line-value-tabs-name">
<div class="line-value-mpackets-name">
<div :class="item.class"></div>
<div class="tabs-name">{{$t(item.name)}}</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>
@@ -79,7 +79,7 @@ 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 { getLineType, overwriteUrl, urlParamsHandler } from '@/utils/tools'
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
export default {
name: 'DnsTrafficLine',
components: {
@@ -126,7 +126,7 @@ export default {
label: 'Maximum'
}
],
tabs: [
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: '' }
@@ -202,14 +202,68 @@ export default {
this.isNoData = res.data.result.length === 0
if (this.isNoData) {
this.lineTab = ''
this.tabs = [
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: '' }
]
} else {
this.initData(res.data.result, val, active, show)
}
res.data.result.forEach((t) => {
if (t.type === 'bytes' && val === 'Bits/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalBitsRate.analysis
mpackets[1].analysis = t.inboundBitsRate.analysis
mpackets[2].analysis = t.outboundBitsRate.analysis
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' && parseFloat(e.analysis.avg) === 0) {
e.show = false
num += 1
} else {
e.show = true
if (!active && show !== this.lineRefer) {
this.legendSelectChange(e, 'index')
}
}
if (this.lineTab === e.class) {
if (parseFloat(e.analysis.avg) <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
}
}
})
this.mpackets = mpackets
if (num === 3) {
mpackets[0].invertTab = false
this.lineTab = 'total'
this.legendSelectChange(mpackets[0], 0)
this.echartsInit(this.mpackets)
} else {
this.echartsInit(this.mpackets, show)
if (!this.lineRefer) this.lineRefer = 'Average'
}
} else if (t.type === 'queries' && val === 'Queries/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalQueryRate.analysis
mpackets[0].data = t.totalQueryRate.values ? t.totalQueryRate.values : []
mpackets.forEach((e, i) => {
if (i !== 0) {
e.show = false
}
e.unitType = 'queries/s'
e.invertTab = false
this.lineTab = 'total'
this.legendSelectChange(e, 0)
})
this.mpackets = mpackets
this.echartsInit(this.mpackets, true)
}
})
} else {
this.isNoData = false
this.showError = true
@@ -323,7 +377,7 @@ export default {
this.chartOption.tooltip.formatter = (params) => {
params.forEach(t => {
t.seriesName = this.$t(t.seriesName)
this.tabs.forEach(e => {
this.mpackets.forEach(e => {
if (this.$t(e.name) === t.seriesName) {
t.borderColor = chartColor3[e.positioning]
}
@@ -366,16 +420,16 @@ export default {
legendSelectChange (item, index, val) {
if (index === 'index') {
this.dispatchLegendSelectAction(item.name)
} else if (this.tabs[index] && this.tabs[index].name === item.name) {
} else if (this.mpackets[index] && this.mpackets[index].name === item.name) {
this.dispatchLegendSelectAction(item.name)
this.tabs.forEach((t) => {
this.mpackets.forEach((t) => {
if (t.name !== item.name) {
this.dispatchLegendUnSelectAction(t.name)
}
})
}
if (val === 'active') {
this.tabs.forEach(t => {
this.mpackets.forEach(t => {
if (item.name === t.name) {
t.invertTab = !t.invertTab
} else {
@@ -387,7 +441,7 @@ export default {
} else {
this.lineTab = t.class
}
this.tabs.forEach((e) => {
this.mpackets.forEach((e) => {
this.dispatchLegendSelectAction(e.name)
})
}
@@ -395,8 +449,8 @@ export default {
}
},
handleActiveBar () {
if (document.querySelector('.network .line-value-tabs.is-active')) {
const { offsetLeft, clientWidth, clientLeft } = document.querySelector('.network .line-value-tabs.is-active')
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;`
}
@@ -409,7 +463,7 @@ export default {
this.lineTab = ''
this.handleActiveBar()
this.showMarkLine = !this.showMarkLine
this.tabs.forEach((e) => {
this.mpackets.forEach((e) => {
if (!e.invertTab) {
e.invertTab = true
}
@@ -421,9 +475,9 @@ export default {
let echartsData
const chartOption = this.myChart.getOption()
if (this.lineTab) {
echartsData = this.tabs.filter(t => t.show === true && t.invertTab === false)
echartsData = this.mpackets.filter(t => t.show === true && t.invertTab === false)
} else {
echartsData = this.tabs.filter(t => t.show === true)
echartsData = this.mpackets.filter(t => t.show === true)
}
if (this.lineRefer === 'Average' && this.showMarkLine) {
chartOption.series.forEach((t, i) => {
@@ -472,85 +526,12 @@ export default {
dataIntegrationArray.sort((a, b) => { return a[1] - b[1] })
const sortIndex = dataIntegrationArray.findIndex(a => a[2] === index)
return this.sizes[sortIndex]
},
initData (data, val, active, show) {
let lineData = []
if (data !== undefined && data.length > 0) {
data.forEach((item) => {
item.type = getLineType(item.type)
if (item.type === val) {
lineData = Object.keys(item).map(t => {
return {
...item[t]
}
})
}
})
}
lineData.splice(0, 1)
const tabs = _.cloneDeep(this.tabs)
if (val === 'Queries/s') {
lineData.forEach((d, i) => {
tabs[i].data = d.values
tabs[i].analysis = d.analysis
})
tabs.forEach((e, i) => {
if (i !== 0) {
e.show = false
}
e.unitType = 'queries/s'
e.invertTab = false
this.lineTab = 'total'
this.legendSelectChange(e, 0)
})
this.tabs = tabs
this.echartsInit(this.tabs, true)
} else {
const unit = 'bps'
this.legendInit(lineData, active, show, unit, tabs)
}
},
legendInit (data, active, show, type, dnsData) {
data.forEach((d, i) => {
dnsData[i].data = d.values
dnsData[i].analysis = d.analysis
})
let num = 0
dnsData.forEach(e => {
e.unitType = type
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) === 0) {
e.show = false
num += 1
} else {
e.show = true
if (!active && show !== this.lineRefer) {
this.legendSelectChange(e, 'index')
}
}
if (this.lineTab === e.class) {
if (parseFloat(e.analysis.avg) <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
}
}
})
this.tabs = dnsData
if (num === 3) {
dnsData[0].invertTab = false
this.lineTab = 'total'
this.legendSelectChange(dnsData[0], 0)
this.echartsInit(this.tabs)
} else {
this.echartsInit(this.tabs, show)
if (!this.lineRefer) this.lineRefer = 'Average'
}
}
},
mounted () {
this.timer = setTimeout(() => {
if (this.lineTab) {
const data = this.tabs.find(t => t.class === this.lineTab)
const data = this.mpackets.find(t => t.class === this.lineTab)
this.activeChange(data, data.positioning)
} else {
this.init()
@@ -561,9 +542,7 @@ export default {
beforeUnmount () {
clearTimeout(this.timer)
window.removeEventListener('resize', this.resize)
if (this.myChart) {
echarts.dispose(this.myChart)
}
this.myChart = null
this.chartOption = null
this.unitConvert = null
}

View File

@@ -29,20 +29,20 @@
<div class="popper-content__link-id">Link ID: {{ item.linkId }}</div>
<div class="popper-content__link-info">
<div class="info__label">{{ $t('linkMonitor.linkBlock.total') }}</div>
<div class="info__value" :test-id="`linkBlockTotal${index}`" style="margin-left: 8px">
<div class="info__value" style="margin-left: 8px">
{{ unitConvert(item.totalBitsRate, unitTypes.bps).join(' ') }}
</div>
</div>
<div class="popper-content__link-info">
<div class="info__label">{{ $t('linkMonitor.linkBlock.bandwidthUsage') }}</div>
<div class="info__value" style="display: flex">
<div :test-id="`linkBlockEgressUsage${index}`">
<div>
<svg class="icon item-popover-up" aria-hidden="true">
<use xlink:href="#cn-icon-egress"></use>
</svg>
{{ convertValue(item.egressUsage) }}
</div>
<div :test-id="`linkBlockIngressUsage${index}`">
<div>
<svg class="icon item-popover-down" aria-hidden="true">
<use xlink:href="#cn-icon-ingress"></use>
</svg>
@@ -84,7 +84,7 @@
<div class="popper-content__link-id">Next-Hop Internet: {{ item.linkDirection }}</div>
<div class="popper-content__link-info">
<div class="info__label">{{ $t('linkMonitor.linkBlock.total') }}</div>
<div class="info__value" :test-id="`nextHopTotal${index}`" style="margin-left: 8px">
<div class="info__value" style="margin-left: 8px">
{{ unitConvert(item.totalBitsRate, unitTypes.bps).join(' ') }}
</div>
</div>
@@ -118,13 +118,13 @@ import ChartNoData from '@/views/charts/charts/ChartNoData'
import chartMixin from '@/views/charts2/chart-mixin'
import { useRoute } from 'vue-router'
import { ref } from 'vue'
import { get } from '@/utils/http'
import { api } from '@/utils/api'
import { colorGradientCalculation } from '@/utils/tools'
import unitConvert from '@/utils/unit-convert'
import { drillDownPanelTypeMapping, storageKey, unitTypes } from '@/utils/constants'
import { getSecond } from '@/utils/date-util'
import ChartError from '@/components/common/Error'
import axios from 'axios'
export default {
name: 'LinkBlock',
@@ -175,13 +175,10 @@ export default {
endTime: getSecond(this.timeFilter.endTime)
}
const dataRequest = axios.get(api.linkMonitor.analysis, { params: params })
const nextHopRequest = axios.get(api.linkMonitor.nextHopAnalysis, { params: params })
const dataRequest = get(api.linkMonitor.analysis, params)
const nextHopRequest = get(api.linkMonitor.nextHopAnalysis, params)
Promise.all([dataRequest, nextHopRequest]).then(response => {
const res = []
res[0] = response[0].data
res[1] = response[1].data
Promise.all([dataRequest, nextHopRequest]).then(res => {
if (res[0].code === 200 && res[1].code === 200) {
this.showError = false

View File

@@ -12,10 +12,10 @@
import chartMixin from '@/views/charts2/chart-mixin'
import { getSecond } from '@/utils/date-util'
import { api } from '@/utils/api'
import { get } from '@/utils/http'
import { storageKey } from '@/utils/constants'
import PopoverContent from './LinkDirectionGrid/PopoverContent'
import { computeScore } from '@/utils/tools'
import axios from 'axios'
export default {
name: 'LinkDirectionGrid',
@@ -56,14 +56,11 @@ export default {
endTime: getSecond(this.timeFilter.endTime)
}
const dataRequest = axios.get(api.linkMonitor.bigramAnalysis, { params: params })
const nextHopRequest = axios.get(api.linkMonitor.bigramNextHopAnalysis, { params: params })
const dataRequest = get(api.linkMonitor.bigramAnalysis, params)
const nextHopRequest = get(api.linkMonitor.bigramNextHopAnalysis, params)
this.toggleLoading(true)
Promise.all([dataRequest, nextHopRequest]).then(response => {
const res = []
res[0] = response[0].data
res[1] = response[1].data
Promise.all([dataRequest, nextHopRequest]).then(res => {
if (res[0].code === 200) {
this.isLinkShowError = false
// 链路流量数据
@@ -98,7 +95,7 @@ export default {
// 分数低于3分赋红点
d.score = this.localComputeScore(d)
d.scoreLow3 = d.score < 3 || d.score === '-'
d.scoreLow3 = d.score < 3
if (data) {
const existedEgressLink = data.egress.find(e => e.linkId === egressLink.linkId)
@@ -146,9 +143,9 @@ export default {
// 接口数据乱序,根据出方向排序,再根据同个出方向下的入进行排序
nextLinkData.sort((a, b) => {
if (a.ingressLinkDirection !== b.ingressLinkDirection) {
return a.ingressLinkDirection.localeCompare(b.ingressLinkDirection, 'zh')
return a.ingressLinkDirection.localeCompare(b.ingressLinkDirection)
}
return a.egressLinkDirection.localeCompare(b.egressLinkDirection, 'zh')
return a.egressLinkDirection.localeCompare(b.egressLinkDirection)
})
this.isNextNoData = nextLinkData.length === 0
@@ -185,7 +182,7 @@ export default {
// 分数低于3分赋红点
d.score = this.localComputeScore(d)
d.scoreLow3 = d.score < 3 || d.score === '-'
d.scoreLow3 = d.score < 3
if (data) {
const existedEgressLink = data.egress.find(e => e.linkId === egressLink.linkId)
@@ -228,11 +225,13 @@ export default {
this.nextErrorMsg = res[1].message
}
}).catch(e => {
console.error(e)
this.isLinkShowError = true
this.linkErrorMsg = e.message
this.linkErrorMsg = e[0].message
this.isNextShowError = true
this.nextErrorMsg = e.message
this.nextErrorMsg = e[1].message
}).finally(() => {
this.toggleLoading(false)
})

View File

@@ -1,7 +1,7 @@
<template>
<div class="link-statistical-dimension" style="position: relative">
<div class="dimension-title" v-if="gridData.length>3">{{ $t('linkMonitor.egressLink') }}&nbsp;&&nbsp;{{ $t('linkMonitor.ingressLink') }}</div>
<div class="dimension-title" v-else>{{ $t('linkMonitor.nextHopInternetOfGrid') }}</div>
<div class="dimension-title">{{ $t('linkMonitor.egressLink') }}&nbsp;&&nbsp;{{ $t('linkMonitor.ingressLink') }}
</div>
<chart-no-data v-if="isNoData"></chart-no-data>
@@ -21,13 +21,13 @@
<span v-if="row.nextHop">{{ row.nextHop }}</span>
<span v-else>{{ row.linkId }}</span>
</div>
<div v-for="(item, index3) in row.egress" :key="index3">
<div v-for="(item, index2) in row.egress" :key="index2">
<el-popover :width="item.popoverWidth" placement="right" trigger="hover">
<template #reference>
<div class="data-item data-item__hover">
<div :test-id="`usagePoint${gridData.length}-${index2+1}-${index3+1}`" :class="item.usageMore90 ? 'data-item__point-red':'data-item__point'"></div>
<div :test-id="`scorePoint${gridData.length}-${index2+1}-${index3+1}`" :class="item.scoreLow3 ? 'data-item__point-red':'data-item__point'"></div>
<div :class="row.egress[index2].usageMore90 ? 'data-item__point-red':'data-item__point'"></div>
<div :class="row.egress[index2].scoreLow3 ? 'data-item__point-red':'data-item__point'"></div>
</div>
</template>
@@ -35,13 +35,13 @@
<template #default>
<div class="item-popover-header">
<!--兼容下一跳情况-->
<span v-if="row.nextHop" :test-id="`toNextHop${index2+1}`">{{ row.nextHop }}</span>
<span v-else :test-id="`fromLinkId${index2+1}`">{{ row.linkId }}</span>
<span v-if="row.nextHop">{{ row.nextHop }}</span>
<span v-else>{{ row.linkId }}</span>
<svg class="icon item-popover-header-icon" aria-hidden="true">
<use xlink:href="#cn-icon-arrow-right2"></use>
</svg>
<span v-if="row.nextHop" :test-id="`toNextHop${index3+1}`">{{ item.egressLinkDirection }}</span>
<span v-else :test-id="`toLinkId${index3+1}`">{{ item.linkId }}</span>
<span v-if="row.nextHop">{{ row.egress[index2].egressLinkDirection }}</span>
<span v-else>{{ row.egress[index2].linkId }}</span>
</div>
<div class="item-popover-block">
@@ -49,24 +49,24 @@
<div style="display: flex">
<div class="row-dot">
<div :class="item.usageMore90 ? 'red-dot':'green-dot'"></div>
<div :class="row.egress[index2].usageMore90 ? 'red-dot':'green-dot'"></div>
</div>
<div class="item-popover-block-content">
<div class="block-content-item">
<div class="block-content-item-name">{{ $t('linkMonitor.bandwidthUsage') }}</div>
<div class="block-content-item-value" :style="{width: item.valueWidth + 'px'}">
<div :test-id="`egressUsage${gridData.length}-${index2+1}-${index3+1}`" style="margin-left: -10px">
<div class="block-content-item-value" :style="{width: row.egress[index2].valueWidth + 'px'}">
<div style="margin-left: -10px">
<svg class="icon item-popover-up" aria-hidden="true">
<use xlink:href="#cn-icon-egress"></use>
</svg>
{{ convertValue(item.egressUsage) }}
{{ convertValue(row.egress[index2].egressUsage) }}
</div>
<div :test-id="`ingressUsage${gridData.length}-${index2+1}-${index3+1}`">
<div>
<svg class="icon item-popover-down" aria-hidden="true">
<use xlink:href="#cn-icon-ingress"></use>
</svg>
{{ convertValue(item.ingressUsage) }}
{{ convertValue(row.egress[index2].ingressUsage) }}
</div>
</div>
</div>
@@ -74,8 +74,8 @@
<div class="block-content-item">
<div class="block-content-item-name">{{ $t('linkMonitor.linkBlock.total') }}</div>
<div :test-id="`totalBitsRate${gridData.length}-${index2+1}-${index3+1}`" class="block-content-item-value" :style="{width: item.valueWidth + 'px'}">
{{ unitConvert(item.totalBitsRate, unitTypes.bps).join('') }}
<div class="block-content-item-value" :style="{width: row.egress[index2].valueWidth + 'px'}">
{{ unitConvert(row.egress[index2].totalBitsRate, unitTypes.bps).join('') }}
</div>
</div>
</div>
@@ -87,48 +87,48 @@
<div style="display: flex">
<div class="row-dot">
<div :class="item.scoreLow3 ? 'red-dot':'green-dot'"></div>
<div :class="row.egress[index2].scoreLow3 ? 'red-dot':'green-dot'"></div>
</div>
<div class="item-popover-block-content">
<div class="block-content-item">
<div class="block-content-item-name">{{ $t('linkMonitor.npmScore1') }}</div>
<div :test-id="`score${gridData.length}-${index2+1}-${index3+1}`" class="block-content-item-value" :style="{width: item.valueWidth + 'px'}">
{{ item.score }}
<div class="block-content-item-value" :style="{width: row.egress[index2].valueWidth + 'px'}">
{{ row.egress[index2].score }}
</div>
</div>
<div class="block-content-item">
<div class="block-content-item-name">{{ $t(npmNetworkName[0].name) }}</div>
<div :test-id="`tcp${gridData.length}-${index2+1}-${index3+1}`" class="block-content-item-value" :style="{width: item.valueWidth + 'px'}">
{{ unitConvert(item.establishLatencyMs, unitTypes.time).join('') }}
<div class="block-content-item-value" :style="{width: row.egress[index2].valueWidth + 'px'}">
{{ unitConvert(row.egress[index2].establishLatencyMs, unitTypes.time).join('') }}
</div>
</div>
<div class="block-content-item">
<div class="block-content-item-name">{{ $t(npmNetworkName[1].name) }}</div>
<div :test-id="`http${gridData.length}-${index2+1}-${index3+1}`" class="block-content-item-value" :style="{'width': item.valueWidth + 'px'}">
{{ unitConvert(item.httpResponseLatency, unitTypes.time).join('') }}
<div class="block-content-item-value" :style="{'width': row.egress[index2].valueWidth + 'px'}">
{{ unitConvert(row.egress[index2].httpResponseLatency, unitTypes.time).join('') }}
</div>
</div>
<div class="block-content-item">
<div class="block-content-item-name">{{ $t(npmNetworkName[2].name) }}</div>
<div :test-id="`ssl${gridData.length}-${index2+1}-${index3+1}`" class="block-content-item-value" :style="{width: item.valueWidth + 'px'}">
{{ unitConvert(item.sslConLatency, unitTypes.time).join('') }}
<div class="block-content-item-value" :style="{width: row.egress[index2].valueWidth + 'px'}">
{{ unitConvert(row.egress[index2].sslConLatency, unitTypes.time).join('') }}
</div>
</div>
<div class="block-content-item">
<div class="block-content-item-name">{{ $t(npmNetworkName[3].name) }}</div>
<div :test-id="`packetLoss${gridData.length}-${index2+1}-${index3+1}`" class="block-content-item-value" :style="{width: item.valueWidth + 'px'}">
{{ unitConvert(item.tcpLostlenPercent, unitTypes.percent).join('') }}
<div class="block-content-item-value" :style="{width: row.egress[index2].valueWidth + 'px'}">
{{ unitConvert(row.egress[index2].tcpLostlenPercent, unitTypes.percent).join('') }}
</div>
</div>
<div class="block-content-item">
<div class="block-content-item-name">{{ $t(npmNetworkName[4].name) }}</div>
<div :test-id="`packetRetrans${gridData.length}-${index2+1}-${index3+1}`" class="block-content-item-value" :style="{width: item.valueWidth + 'px'}">
{{ unitConvert(item.pktRetransPercent, unitTypes.percent).join('') }}
<div class="block-content-item-value" :style="{width: row.egress[index2].valueWidth + 'px'}">
{{ unitConvert(row.egress[index2].pktRetransPercent, unitTypes.percent).join('') }}
</div>
</div>
</div>

View File

@@ -2,7 +2,7 @@
<div class="link-traffic-line">
<link-traffic-drill-down-list
:chart="chart"
:line-data="tabs[0]"
:line-data="mpackets"
:time-filter="timeFilter">
</link-traffic-drill-down-list>
<div class="line network link-traffic">
@@ -12,24 +12,22 @@
<div class="line-header-left">
<div class="line-value-active" v-if="lineTab"></div>
<div class="line-value">
<div class="line-value-tabs"
<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 tabs"
v-for="(item, index) in mpackets"
:key="index"
@mouseenter="mouseenter(item)"
@mouseleave="mouseleave(item)"
@click="activeChange(item, index)"
:test-id="`tab-${index}`">
<div class="line-value-tabs-name">
@click="activeChange(item, index)">
<div class="line-value-mpackets-name">
<div :class="item.class"></div>
<div class="tabs-name">{{$t(item.name)}}</div>
<div class="mpackets-name">{{$t(item.name)}}</div>
</div>
<div class="line-value-unit" :test-id="`tabContent${index}`">
<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>{{unitConvert(item.analysis.avg, unitTypes.number)[1]}}</span><span v-if="item.unitType">{{item.unitType}}</span>
</span>
</div>
</div>
@@ -69,14 +67,14 @@ import { useRoute } from 'vue-router'
import { ref, shallowRef } from 'vue'
import unitConvert from '@/utils/unit-convert'
import { chartColor3, chartColor4, unitTypes } from '@/utils/constants'
import { getLineType, overwriteUrl, urlParamsHandler } from '@/utils/tools'
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
import { getSecond } from '@/utils/date-util'
import { get } from '@/utils/http'
import { api } from '@/utils/api'
import _ from 'lodash'
import * as echarts from 'echarts'
import { linkTrafficLineChartOption } from '@/views/charts2/charts/options/echartOption'
import { stackedLineTooltipFormatter } from '@/views/charts/charts/tools'
import axios from 'axios'
export default {
name: 'LinkTrafficLine',
@@ -114,7 +112,7 @@ export default {
label: 'Packets/s'
}
],
tabs: [
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: '' }
@@ -178,21 +176,105 @@ export default {
}
}
this.loading = true
axios.get(api.linkMonitor.totalTrafficAnalysis, { params: params }).then((res) => {
res = res.data
get(api.linkMonitor.totalTrafficAnalysis, params).then((res) => {
if (res.code === 200) {
this.showError = false
this.isNoData = res.data.result.length === 0
if (this.isNoData) {
this.lineTab = ''
this.tabs = [
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: '' }
]
} else {
this.initData(res.data.result, val, active, show)
}
res.data.result.forEach((t) => {
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 : []
let num = 0
mpackets.forEach(e => {
e.unitType = 'bps'
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) === 0) {
e.show = false
num += 1
} else {
e.show = true
if (!active && !show) {
this.legendSelectChange(e, 'index')
}
}
if (this.lineTab === e.class) {
if (parseFloat(e.analysis.avg) <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
}
}
})
this.mpackets = mpackets
if (num === 3) {
mpackets[0].invertTab = false
this.lineTab = 'total'
this.legendSelectChange(mpackets[0], 0)
this.$nextTick(() => {
this.echartsInit(this.mpackets)
})
} else {
this.$nextTick(() => {
this.echartsInit(this.mpackets)
if (!this.lineRefer) this.lineRefer = 'Average'
})
}
} else if (t.type === 'packets' && val === 'Packets/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalPacketsRate.analysis
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 : []
let num = 0
mpackets.forEach(e => {
e.unitType = 'packets/s'
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) === 0) {
e.show = false
num += 1
} else {
e.show = true
if (!active && !show) {
this.legendSelectChange(e, 'index')
}
}
if (this.lineTab === e.class) {
if (parseFloat(e.analysis.avg) <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
}
}
})
this.mpackets = mpackets
if (num === 3) {
mpackets[0].invertTab = false
this.lineTab = 'total'
this.legendSelectChange(mpackets[0], 0)
this.$nextTick(() => {
this.echartsInit(this.mpackets)
})
} else {
this.$nextTick(() => {
this.echartsInit(this.mpackets)
if (!this.lineRefer) this.lineRefer = 'Average'
})
}
}
})
} else {
this.showError = true
this.errorMsg = res.message
@@ -207,7 +289,6 @@ export default {
})
},
echartsInit (echartsData) {
if (!this.isUnitTesting) {
if (this.lineTab) {
this.handleActiveBar()
echartsData = echartsData.filter(t => t.show === true && t.invertTab === false)
@@ -258,7 +339,7 @@ export default {
this.chartOption.tooltip.formatter = (params) => {
params.forEach(t => {
t.seriesName = this.$t(t.seriesName)
this.tabs.forEach(e => {
this.mpackets.forEach(e => {
if (this.$t(e.name) === t.seriesName) {
t.borderColor = chartColor3[e.positioning]
}
@@ -269,7 +350,6 @@ export default {
}
this.showMarkLine = true
this.myChart.setOption(this.chartOption)
}
},
activeChange (item, index) {
if (this.isNoData) return
@@ -301,16 +381,16 @@ export default {
legendSelectChange (item, index, val) {
if (index === 'index') {
this.dispatchLegendSelectAction(item.name)
} else if (this.tabs[index] && this.tabs[index].name === item.name) {
} else if (this.mpackets[index] && this.mpackets[index].name === item.name) {
this.dispatchLegendSelectAction(item.name)
this.tabs.forEach((t) => {
this.mpackets.forEach((t) => {
if (t.name !== item.name) {
this.dispatchLegendUnSelectAction(t.name)
}
})
}
if (val === 'active') {
this.tabs.forEach(t => {
this.mpackets.forEach(t => {
if (item.name === t.name) {
t.invertTab = !t.invertTab
} else {
@@ -322,7 +402,7 @@ export default {
} else {
this.lineTab = t.class
}
this.tabs.forEach((e) => {
this.mpackets.forEach((e) => {
this.dispatchLegendSelectAction(e.name)
})
}
@@ -330,8 +410,8 @@ export default {
}
},
handleActiveBar () {
if (document.querySelector('.network .line-value-tabs.is-active')) {
const { offsetLeft, clientWidth, clientLeft } = document.querySelector('.network .line-value-tabs.is-active')
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;`
}
@@ -344,7 +424,7 @@ export default {
this.lineTab = ''
this.handleActiveBar()
this.showMarkLine = !this.showMarkLine
this.tabs.forEach((e) => {
this.mpackets.forEach((e) => {
if (!e.invertTab) {
e.invertTab = true
}
@@ -377,71 +457,12 @@ export default {
dataIntegrationArray.sort((a, b) => { return a[1] - b[1] })
const sortIndex = dataIntegrationArray.findIndex(a => a[2] === index)
return this.sizes[sortIndex]
},
initData (data, val, active, show) {
let lineData = []
if (data !== undefined && data.length > 0) {
data.forEach((item) => {
item.type = getLineType(item.type)
if (item.type === val) {
lineData = Object.keys(item).map(t => {
return {
...item[t]
}
})
}
})
}
lineData.splice(0, 1)
const tabs = _.cloneDeep(this.tabs)
const unit = val === 'Bits/s' ? 'bps' : 'packets/s'
this.legendInit(lineData, active, show, unit, tabs)
},
legendInit (data, active, show, type, linkData) {
data.forEach((d, i) => {
linkData[i].data = d.values
linkData[i].analysis = d.analysis
})
let num = 0
linkData.forEach(e => {
e.unitType = type
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) === 0) {
e.show = false
num += 1
} else {
e.show = true
if (!active && !show) {
this.legendSelectChange(e, 'index')
}
}
if (this.lineTab === e.class) {
if (parseFloat(e.analysis.avg) <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
}
}
})
this.tabs = linkData
if (num === 3) {
linkData[0].invertTab = false
this.lineTab = 'total'
this.legendSelectChange(linkData[0], 0)
this.$nextTick(() => {
this.echartsInit(this.tabs)
})
} else {
this.$nextTick(() => {
this.echartsInit(this.tabs)
if (!this.lineRefer) this.lineRefer = 'Average'
})
}
}
},
mounted () {
this.timer = setTimeout(() => {
if (this.lineTab) {
const data = this.tabs.find(t => t.class === this.lineTab)
const data = this.mpackets.find(t => t.class === this.lineTab)
this.activeChange(data, data.positioning)
} else {
this.init()
@@ -452,9 +473,7 @@ export default {
beforeUnmount () {
clearTimeout(this.timer)
window.removeEventListener('resize', this.resize)
if (this.myChart) {
echarts.dispose(this.myChart)
}
this.myChart = null
this.chartOption = null
this.unitConvert = null
}

View File

@@ -102,12 +102,15 @@ export default {
if (condition.length > 1) {
if (n === 0) {
params.q = condition.find(c => c.indexOf('common_ingress_link_id') > -1 || c.indexOf('ingress_link_direction') > -1)
url = api.linkMonitor.drilldownQuadrupleIngressAnalysis // 入口
} else {
params.q = condition.find(c => c.indexOf('common_egress_link_id') > -1 || c.indexOf('egress_link_direction') > -1)
url = api.linkMonitor.drilldownQquadrupleEgressAnalysis // 出口
}
}
if (n === 0) {
url = api.linkMonitor.drilldownQuadrupleIngressAnalysis // 入口
} else {
url = api.linkMonitor.drilldownQquadrupleEgressAnalysis // 出口
}
} else {
if (n === 0) {
url = api.linkMonitor.quadrupleIngressAnalysis // 入口

View File

@@ -6,42 +6,36 @@
<div v-else>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('network.total')}}</div>
<div class="link-traffic-list-center-value" v-if="lineData && lineData.analysis" test-id="line-tabContent">
<span>{{unitConvert(lineData.analysis.avg, unitTypes.number)[0]}}</span>
<span>
<span>{{unitConvert(lineData.analysis.avg, unitTypes.number)[1]}}</span>
<span v-if="lineData.unitType">{{lineData.unitType}}</span>
</span>
</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="lineData && lineData.analysis && bandWidth" test-id="line-percent">{{unitConvert(lineData.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">
<div class="link-traffic-list-center-label">{{$t('linkMonitor.npmScore')}}</div>
<div class="link-traffic-list-center-value" test-id="line-score">{{linkTrafficListData.npmScore || '-'}}</div>
<div class="link-traffic-list-center-value">{{linkTrafficListData.npmScore || '-'}}</div>
</div>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('networkAppPerformance.tcpConnectionEstablishLatency')}}</div>
<div class="link-traffic-list-center-value" test-id="line-tcp">{{unitConvert(Math.floor(linkTrafficListData.establishLatencyMs), unitTypes.time).join('')}}</div>
<div class="link-traffic-list-center-value">{{unitConvert(Math.floor(linkTrafficListData.establishLatencyMs), unitTypes.time).join('')}}</div>
</div>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('networkAppPerformance.httpResponse')}}</div>
<div class="link-traffic-list-center-value" test-id="line-http">{{unitConvert(Math.floor(linkTrafficListData.httpResponseLatency), unitTypes.time).join('')}}</div>
<div class="link-traffic-list-center-value">{{unitConvert(Math.floor(linkTrafficListData.httpResponseLatency), unitTypes.time).join('')}}</div>
</div>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('networkAppPerformance.sslResponseLatency')}}</div>
<div class="link-traffic-list-center-value" test-id="line-ssl">{{unitConvert(Math.floor(linkTrafficListData.sslConLatency), unitTypes.time).join('')}}</div>
<div class="link-traffic-list-center-value">{{unitConvert(Math.floor(linkTrafficListData.sslConLatency), unitTypes.time).join('')}}</div>
</div>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('networkAppPerformance.packetLoss')}}</div>
<div class="link-traffic-list-center-value" test-id="line-packetLoss">{{unitConvert(linkTrafficListData.tcpLostlenPercent, unitTypes.percent).join('')}}</div>
<div class="link-traffic-list-center-value">{{unitConvert(linkTrafficListData.tcpLostlenPercent, unitTypes.percent).join('')}}</div>
</div>
<div class="link-traffic-list-center">
<div class="link-traffic-list-center-label">{{$t('overall.packetRetrans')}}</div>
<div class="link-traffic-list-center-value" test-id="line-packetRetrans">{{unitConvert(linkTrafficListData.pktRetransPercent, unitTypes.percent).join('')}}</div>
<div class="link-traffic-list-center-value">{{unitConvert(linkTrafficListData.pktRetransPercent, unitTypes.percent).join('')}}</div>
</div>
</div>
</div>
@@ -51,6 +45,7 @@
import chartMixin from '@/views/charts2/chart-mixin'
import { storageKey, unitTypes } from '@/utils/constants'
import unitConvert from '@/utils/unit-convert'
import { get } from '@/utils/http'
import { api } from '@/utils/api'
import { ref } from 'vue'
import { useRoute } from 'vue-router'
@@ -58,7 +53,6 @@ import { getSecond } from '@/utils/date-util'
import { computeScore } from '@/utils/tools'
import Loading from '@/components/common/Loading'
import ChartError from '@/components/common/Error'
import axios from 'axios'
export default {
name: 'linkTrafficList',
mixins: [chartMixin],
@@ -142,8 +136,7 @@ export default {
}
}
this.loading = true
axios.get(api.linkMonitor.networkAnalysis, { params: params }).then(res => {
res = res.data
get(api.linkMonitor.networkAnalysis, params).then(res => {
if (res.code === 200) {
this.showError = false
this.isNoData = res.data.result.length === 0
@@ -172,9 +165,6 @@ export default {
},
mounted () {
this.linkTrafficData()
},
beforeUnmount () {
this.unitConvert = null
}
}
</script>

View File

@@ -6,31 +6,31 @@
</div>
<div class="app-cards">
<div class="app-card" @mouseenter="mouseenter(app)" @mouseleave="mouseleave(app)" v-for="(app, index) in appData" :key="app.type + app.name" test-id="app-data-card">
<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'" :test-id="`icon${index}`"></i>
<span @click="drillDownData(app.type, app.name)" :test-id="`name${index}`">{{app.name}}</span>
<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">
<span v-show="app.showMore"><i class="cn-icon cn-icon-more-dark" @mouseenter="mouseenterMore(app)" test-id="mouseenter-dark"></i></span>
<span class="app-card-title-more-delete" @click="del(app, index)" v-show="app.moreOptions" @mouseleave="mouseleaveMore(app)" test-id="mouseleave-more"><i class="cn-icon cn-icon-delete"></i>{{$t('overall.delete')}}</span>
<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">
<div class="app-card__body">
<div class="app-card__body-content">
<div class="app-card__body-content-value">
<div class="app-card__body-content-number" :test-id="`rate${index}`">{{unitConvert(app.rate, unitTypes.number).join(' ')}}</div>
<div class="app-card__body-content-percent red" v-if="app.value > 0" :test-id="`percent${index}`">
<div class="app-card__body-content-number">{{unitConvert(app.rate, unitTypes.number).join(' ')}}</div>
<div class="app-card__body-content-percent red" v-if="app.value > 0">
<span v-if="app.value <= 5">
+{{unitConvert(app.value, unitTypes.percent).join('')}}
</span>
<span v-else>>500.00%</span>
</div>
<div class="app-card__body-content-percent green" v-else-if="app.value < 0" :test-id="`percent${index}`">
<div class="app-card__body-content-percent green" v-else-if="app.value < 0">
<span v-if="app.value >= -5">
-{{unitConvert(app.value, unitTypes.percent).join('').replace(/-/g, '')}}
-{{unitConvert(app.value, unitTypes.percent).join('').replaceAll('-', '')}}
</span>
<span v-else>>500.00%</span>
</div>
@@ -39,8 +39,8 @@
</div>
<div class="app-card__body-previous">
<div>Total</div>
<div v-if="metric === 'Bits/s'" :test-id="`total${index}`">{{unitConvert(app.total, unitTypes.byte).join(' ')}}</div>
<div v-else :test-id="`total${index}`">{{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>
@@ -48,7 +48,7 @@
</div>
<div class="app-card app-card--create">
<i class="cn-icon cn-icon-add1" @click="addApp"></i>
<span @click="addApp" test-id="add">{{$t('overall.add')}}</span>
<span @click="addApp">{{$t('overall.add')}}</span>
</div>
</div>
<el-drawer
@@ -62,7 +62,7 @@
<div class="add-app__header">
<div class="header__title">{{$t('overall.add')}}</div>
<div class="header__operations">
<div class="header__operation header__operation--cancel" @click="cancelApp" test-id="cancel-app">{{$t('overall.cancel')}}</div>
<div class="header__operation header__operation--cancel" @click="cancelApp">{{$t('overall.cancel')}}</div>
<div class="header__operation header__operation--save" @click="save">{{$t('overall.save')}}</div>
</div>
</div>
@@ -72,15 +72,15 @@
<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>
<div class="body__app" v-else :class="{'provide-show': app.provideShow}" v-for="(app, index) in providerOptions" :key="index" @click="appCheckedChange(app, 0)" :test-id="`provide${index}`">
<div class="body__app" v-else :class="{'provide-show': app.provideShow}" v-for="(app, index) in providerOptions" :key="index" @click="appCheckedChange(app, 0)">
<div class="body__app-content">
<div class="body__app-left">
<span><i class="cn-icon" :class="app.icon" :test-id="`provide-icon${index}`"></i></span>
<span class="body__app-left-title" :test-id="`provide-title${index}`">{{app.value}}</span>
<span><i class="cn-icon" :class="app.icon"></i></span>
<span class="body__app-left-title">{{app.value}}</span>
</div>
<div class="body__app-content-right" v-if="app.provideShow"><span><i class="cn-icon cn-icon-a-allclear"></i></span></div>
</div>
<div class="body__app-value" v-if="app.remark" :title="app.remark" :test-id="`provide-remark${index}`">{{app.remark}}</div>
<div class="body__app-value" v-if="app.remark" :title="app.remark">{{app.remark}}</div>
<div v-else>-</div>
</div>
</div>
@@ -89,22 +89,22 @@
<div class="body__apps" :class="{'body__apps-no-grid': appOptions.length === 0}">
<loading :loading="loadingBody"></loading>
<chart-no-data v-if="appOptions.length === 0 && !loadingBody"></chart-no-data>
<div class="body__app" v-else :class="{'app-show': app.appShow}" v-for="(app, index) in appOptions" :key="index" @click="appCheckedChange(app, 1)" :test-id="`app${index}`">
<div class="body__app" v-else :class="{'app-show': app.appShow}" v-for="(app, index) in appOptions" :key="index" @click="appCheckedChange(app, 1)">
<div class="body__app-content">
<div class="body__app-left">
<span><i class="cn-icon" :class="app.icon" :test-id="`app-icon${index}`"></i></span>
<span class="body__app-left-title" :test-id="`app-title${index}`">{{app.value}}</span>
<span><i class="cn-icon" :class="app.icon"></i></span>
<span class="body__app-left-title">{{app.value}}</span>
</div>
<div class="body__app-content-right" v-if="app.appShow"><span><i class="cn-icon cn-icon-a-allclear"></i></span></div>
</div>
<div class="body__app-value" v-if="app.remark" :title="app.remark" :test-id="`app-remark${index}`">{{app.remark}}</div>
<div class="body__app-value" v-if="app.remark" :title="app.remark">{{app.remark}}</div>
<div v-else>-</div>
</div>
</div>
</el-tab-pane>
</el-tabs>
<div class="body__searcher">
<el-input v-model="searcherApp" @input="searcherAppChange" size="mini" :placeholder="$t('networkOverview.search')" prefix-icon="el-icon-search" test-id="search-input"></el-input>
<el-input v-model="searcherApp" @input="searcherAppChange" size="mini" :placeholder="$t('networkOverview.search')" prefix-icon="el-icon-search"></el-input>
</div>
<div class="body__loading"><loading :loading="loading"></loading></div>
</div>
@@ -119,7 +119,7 @@ import { storageKey, unitTypes, networkTable, operationType, curTabState } from
import * as echarts from 'echarts'
import { appListChartOption } from '@/views/charts2/charts/options/echartOption'
import { shallowRef } from 'vue'
import { put } from '@/utils/http'
import { get, put } from '@/utils/http'
import { api } from '@/utils/api'
import _ from 'lodash'
import { getSecond } from '@/utils/date-util'
@@ -128,7 +128,6 @@ import loading from '@/components/common/Loading'
import ChartNoData from '@/views/charts/charts/ChartNoData'
import { appStackedLineTooltipFormatter } from '@/views/charts/charts/tools'
import chartMixin from '@/views/charts2/chart-mixin'
import axios from 'axios'
export default {
name: 'NetworkOverviewApps',
@@ -153,6 +152,7 @@ export default {
searcherApp: '',
// 选中的app不区分app和provider
toSaveApp: [],
appShowType: 'bytes',
pageObj: { // 分页对象
pageNo: 1,
pageSize: 24,
@@ -228,8 +228,8 @@ export default {
return `'${item.name}'`
}).join(',')
}
prevRequest = axios.get(api.netWorkOverview.applicationCycleTrafficTotal, { params: params })
request = axios.get(api.netWorkOverview.applicationTrafficAnalysis, { params: params })
prevRequest = get(api.netWorkOverview.applicationCycleTrafficTotal, params)
request = get(api.netWorkOverview.applicationTrafficAnalysis, params)
this.handleData(prevRequest, request, 'app')
}
if (providerCards.length > 0) {
@@ -240,15 +240,15 @@ export default {
return `'${item.name}'`
}).join(',')
}
prevRequest = axios.get(api.netWorkOverview.appCompanyCycleTrafficTotal, { params: params })
request = axios.get(api.netWorkOverview.appCompanyTrafficAnalysis, { params: params })
prevRequest = get(api.netWorkOverview.appCompanyCycleTrafficTotal, params)
request = get(api.netWorkOverview.appCompanyTrafficAnalysis, params)
this.handleData(prevRequest, request, 'provider')
}
},
handleData (prevRequest, request, _t) {
this.toggleLoading(true)
Promise.all([prevRequest, request]).then(res => {
this.isNoData = (res[0].data.data.result.length && res[1].data.data.result.length) === 0
this.isNoData = (res[0].data.result.length && res[1].data.result.length) === 0
if (this.isNoData) {
this.appData = this.appData.map(t => {
return {
@@ -257,10 +257,10 @@ export default {
}
})
}
if (res[0].data.code === 200 && res[1].data.code === 200) {
if (res[0].code === 200 && res[1].code === 200) {
this.showError = false
const prevData = res[0].data.data.result
const data = res[1].data.data.result
const prevData = res[0].data.result
const data = res[1].data.result
let toCompareType = 'bytes'
if (this.metric === 'Sessions/s') {
toCompareType = 'sessions'
@@ -298,6 +298,16 @@ export default {
this.toggleLoading(false)
})
},
metricChange (value) {
if (value === 'Bits/s') {
this.appShowType = 'bytes'
} else if (value === 'Packets/s') {
this.appShowType = 'packets'
} else if (value === 'Sessions/s') {
this.appShowType = 'sessions'
}
this.init()
},
getUrlParam (param, defaultValue, isNumber) {
if (isNumber) {
return this.$route.query[param] ? Number(this.$route.query[param]) : defaultValue
@@ -391,7 +401,6 @@ export default {
this.urlChangeParams = {}
},
initChart (obj) {
if (!this.isUnitTesting) {
let chart = this.myChart.find(m => m.name === obj.name && m.type === obj.type)
if (!chart) {
chart = echarts.init(document.getElementById(`chart-${obj.name}-${obj.type}`))
@@ -425,7 +434,6 @@ export default {
chart.resize()
})
}
}
},
handleScroll (e) {
const clientHeight = e.target.clientHeight
@@ -461,8 +469,7 @@ export default {
}
if (parseFloat(this.appTypeTab) === 0) {
params.type = 'overviewProvide'
axios.get(api.dict, { params: params }).then(res => {
res = res.data
get(api.dict, params).then(res => {
if (res.code === 200) {
res.data.list = res.data.list.filter(l => !this.appData.some(pd => pd.type === 'provider' && pd.name === l.value))
this.pageObj.pages = res.data.pages
@@ -487,10 +494,9 @@ export default {
})
} else if (parseFloat(this.appTypeTab) === 1) {
params.type = 'overviewApp'
axios.get(api.dict, { params: params }).then(res => {
res = res.data
if (res.code === 200) {
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))
if (res.code === 200) {
this.pageObj.pages = res.data.pages
res.data.list.forEach(t => {
this.toSaveApp.forEach(e => {
@@ -669,6 +675,13 @@ export default {
})
}
},
// 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()
@@ -705,7 +718,7 @@ export default {
}
},
mounted () {
if (this.chart && this.chart.params && this.chart.params.app) {
if (this.chart.params && this.chart.params.app) {
const userId = parseInt(localStorage.getItem(storageKey.userId))
const apps = _.cloneDeep(this.chart.params.app)
let app = apps.find(p => p.user === userId)
@@ -721,9 +734,7 @@ export default {
window.removeEventListener('resize', this.resize)
clearTimeout(this.timerScroll)
clearTimeout(this.timerSearch)
if (this.myChart) {
echarts.dispose(this.myChart)
}
this.myChart = null
this.unitConvert = null
}
}

View File

@@ -11,15 +11,15 @@
<div class="ddos-detection-type">
<div class="ddos-detection-type-value">
<div class="ddos-detection-type-value-name">{{$t('network.numberOfAttacks')}}</div>
<div class="ddos-detection-type-value-number" test-id="attackerCount">{{unitConvert($_.get(ddosData, 'attackerCount'), unitTypes.number).join(' ')}}</div>
<div class="ddos-detection-type-value-number">{{$_.get(ddosData, 'attackerCount') || 0}}</div>
</div>
<div class="ddos-detection-type-value">
<div class="ddos-detection-type-value-name">{{$t('network.number0fVictims')}}</div>
<div class="ddos-detection-type-value-number" test-id="victimCount">{{unitConvert($_.get(ddosData, 'victimCount'), unitTypes.number).join(' ')}}</div>
<div class="ddos-detection-type-value-number">{{$_.get(ddosData, 'victimCount') || 0}}</div>
</div>
<div class="ddos-detection-type-value">
<div class="ddos-detection-type-value-name">{{$t('network.number0fDetectedAttackEvents')}}</div>
<div class="ddos-detection-type-value-number ddos-event" test-id="attackEventCount">{{unitConvert($_.get(ddosData, 'attackEventCount'), unitTypes.number).join(' ')}}</div>
<div class="ddos-detection-type-value-number ddos-event">{{$_.get(ddosData, 'attackEventCount') || 0}}</div>
</div>
</div>
<el-button size="small">{{$t('network.ddosDetection')}}<i class="cn-icon cn-icon-arrow-right"></i></el-button>
@@ -29,13 +29,11 @@
<script>
import { api } from '@/utils/api'
import { get } from '@/utils/http'
import { getSecond } from '@/utils/date-util'
import ChartNoData from '@/views/charts/charts/ChartNoData'
import chartMixin from '@/views/charts2/chart-mixin'
import ChartError from '@/components/common/Error'
import unitConvert from '@/utils/unit-convert'
import { unitTypes } from '@/utils/constants'
import axios from 'axios'
export default {
name: 'NetworkOverviewDdosDetection',
components: {
@@ -46,8 +44,6 @@ export default {
data () {
return {
ddosData: {},
unitConvert,
unitTypes,
isNoData: false,
showError: false,
errorMsg: ''
@@ -63,16 +59,19 @@ export default {
methods: {
ddosDetectDataRequests () {
const params = {
startTime: this.timeFilter && this.timeFilter.startTime ? getSecond(this.timeFilter.startTime) : '',
endTime: this.timeFilter && this.timeFilter.endTime ? getSecond(this.timeFilter.endTime) : ''
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime)
}
this.toggleLoading(true)
axios.get(api.netWorkOverview.ddosEventAnalysis, { params: params }).then(res => {
res = res.data
get(api.netWorkOverview.ddosEventAnalysis, params).then(res => {
if (res.code === 200) {
this.showError = false
this.isNoData = res.data.result.length === 0
if (res.data.result.length === 0) {
this.isNoData = true
} else {
this.ddosData = res.data.result[0]
this.isNoData = false
}
} else {
this.isNoData = false
this.showError = true
@@ -88,12 +87,7 @@ export default {
}
},
mounted () {
this.$nextTick(() => {
this.ddosDetectDataRequests()
})
},
beforeUnmount () {
this.unitConvert = null
}
}
</script>

View File

@@ -5,29 +5,25 @@
<div class="line-header-left">
<div class="line-value-active" v-if="lineTab"></div>
<div class="line-value">
<template v-for="(item, index) in tabs">
<div class="line-value-tabs"
<div class="line-value-mpackets"
v-show="item.show"
:class=" {'is-active': lineTab === item.class, 'mousemove-cursor': mousemoveCursor === item.class}"
v-if="item.show"
v-for="(item, index) in mpackets"
:key="index"
@mouseenter="mouseenter(item)"
@mouseleave="mouseleave(item)"
@click="activeChange(item, index)"
:test-id="`tab${index}`"
>
<div class="line-value-tabs-name">
@click="activeChange(item, index)">
<div class="line-value-mpackets-name">
<div :class="item.class"></div>
<div class="tabs-name" :test-id="`tabTitle${index}`">{{$t(item.name)}}</div>
<div class="mpackets-name">{{$t(item.name)}}</div>
</div>
<div class="line-value-unit" :test-id="`tabContent${index}`">
<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>{{unitConvert(item.analysis.avg, unitTypes.number)[1]}}</span><span v-if="item.unitType">{{item.unitType}}</span>
</span>
</div>
</div>
</template>
</div>
</div>
<div class="line-select line-header-right">
@@ -50,7 +46,7 @@
</div>
<div style="height: calc(100% - 74px); position: relative">
<chart-no-data v-if="isNoData && !showError"></chart-no-data>
<div class="chart-drawing" v-show="showMarkLine && !isNoData && !showError" ref="overviewLineChart"></div>
<div class="chart-drawing" v-show="showMarkLine && !isNoData && !showError" id="overviewLineChart"></div>
<!-- todo 后续改动此处为框选返回-->
<!-- <div id="brushBtn" style="position: absolute;left: 0;top: 0;" v-show="mouseDownFlag">-->
<!-- <el-button @click.stop="backBrushHistory">返回</el-button>-->
@@ -67,16 +63,14 @@ import { unitTypes, chartColor3, chartColor4 } from '@/utils/constants.js'
import { ref, shallowRef } from 'vue'
import { stackedLineTooltipFormatter } from '@/views/charts/charts/tools'
import _ from 'lodash'
import axios from 'axios'
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 { getLineType, overwriteUrl, urlParamsHandler } from '@/utils/tools'
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
import ChartError from '@/components/common/Error'
import mockData from '../../../../../test/views/charts2/charts/networkOverview/NetworkOverviewLineMockData'
export default {
name: 'NetworkOverviewLine',
components: {
@@ -122,7 +116,7 @@ export default {
label: 'Maximum'
}
],
tabsTemplate: [
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: '' },
@@ -130,7 +124,6 @@ export default {
{ 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: '' }
],
tabs: [],
unitConvert,
unitTypes,
chartDateObject: [],
@@ -176,7 +169,7 @@ export default {
metric (n) {
this.handleActiveBar()
this.showMarkLine = !this.showMarkLine
this.tabs.forEach((e) => {
this.mpackets.forEach((e) => {
if (!e.invertTab) {
e.invertTab = true
}
@@ -193,23 +186,161 @@ export default {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime)
}
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)
axios.get(api.netWorkOverview.totalTrafficAnalysis, { params: params }).then(response => {
const res = response.data
// const res = mockData.bytes.boundary.data
get(api.netWorkOverview.totalTrafficAnalysis, params).then((res) => {
this.errorMsg = res.message
if (res.code === 200) {
this.isNoData = res.data.result.length === 0
this.showError = false
if (this.isNoData) {
this.lineTab = ''
this.tabs = _.cloneDeep(this.tabsTemplate)
} else {
this.initData(res.data.result, val, active, show, n)
this.mpackets = [
{ analysis: {}, name: 'network.total', class: 'total', show: true, invertTab: true, positioning: 0, data: [], unitType: '' },
{ analysis: {}, name: 'network.inbound', class: 'inbound', show: true, invertTab: true, positioning: 1, data: [], unitType: '' },
{ analysis: {}, name: 'network.outbound', class: 'outbound', show: true, invertTab: true, positioning: 2, data: [], unitType: '' },
{ analysis: {}, name: 'network.internal', class: 'internal', show: true, invertTab: true, positioning: 3, data: [], unitType: '' },
{ analysis: {}, name: 'network.through', class: 'through', show: true, invertTab: true, positioning: 4, data: [], unitType: '' },
{ analysis: {}, name: 'network.other', class: 'other', show: true, invertTab: true, positioning: 5, data: [], unitType: '' }
]
}
res.data.result.forEach((t) => {
if (t.type === 'bytes' && val === 'Bits/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalBitsRate.analysis
mpackets[1].analysis = t.inboundBitsRate.analysis
mpackets[2].analysis = t.outboundBitsRate.analysis
mpackets[3].analysis = t.internalBitsRate.analysis
mpackets[4].analysis = t.throughBitsRate.analysis
mpackets[5].analysis = t.other.analysis
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 : []
let num = 0
mpackets.forEach(e => {
e.unitType = 'bps'
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) === 0) {
e.show = false
num += 1
} else {
e.show = true
if (!active && show !== this.lineRefer) {
this.legendSelectChange(e, 'index')
}
}
if (this.lineTab === e.class) {
if (parseFloat(e.analysis.avg) <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
}
}
})
this.mpackets = mpackets
if (num === 5) {
mpackets[0].invertTab = false
this.lineTab = 'total'
this.legendSelectChange(mpackets[0], 0)
this.$nextTick(() => {
this.echartsInit(this.mpackets, true)
})
} else {
if (n) this.lineTab = ''
this.$nextTick(() => {
this.echartsInit(this.mpackets, show)
if (!this.lineRefer) this.lineRefer = 'Average'
})
}
} else if (t.type === 'packets' && val === 'Packets/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalPacketsRate.analysis
mpackets[1].analysis = t.inboundPacketsRate.analysis
mpackets[2].analysis = t.outboundPacketsRate.analysis
mpackets[3].analysis = t.internalPacketsRate.analysis
mpackets[4].analysis = t.throughPacketsRate.analysis
mpackets[5].analysis = t.other.analysis
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 : []
let num = 0
mpackets.forEach(e => {
e.unitType = 'packets/s'
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) === 0) {
e.show = false
num += 1
} else {
e.show = true
if (!active && show !== this.lineRefer) {
this.legendSelectChange(e, 'index')
}
}
if (this.lineTab === e.class) {
if (parseFloat(e.analysis.avg) <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
}
}
})
this.mpackets = mpackets
if (num === 5) {
mpackets[0].invertTab = false
this.lineTab = 'total'
this.legendSelectChange(mpackets[0], 0)
this.$nextTick(() => {
this.echartsInit(this.mpackets, true)
})
} else {
if (n) this.lineTab = ''
this.$nextTick(() => {
this.echartsInit(this.mpackets, show)
if (!this.lineRefer) this.lineRefer = 'Average'
})
}
} else if (t.type === 'sessions' && val === 'Sessions/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].analysis = t.totalSessionsRate.analysis
mpackets[0].data = t.totalSessionsRate.values ? t.totalSessionsRate.values : []
mpackets.forEach((e, i) => {
if (i !== 0) {
e.show = false
}
e.unitType = 'sessions/s'
e.invertTab = false
this.lineTab = 'total'
this.legendSelectChange(e, 0)
})
this.mpackets = mpackets
this.$nextTick(() => {
this.echartsInit(this.mpackets, true)
})
}
})
} else {
this.showError = true
this.errorMsg = res.message
@@ -246,8 +377,6 @@ export default {
}
},
echartsInit (echartsData, show) {
// echarts内容在单元测试时不执行
if (!this.isUnitTesting) {
if (this.lineTab) {
this.handleActiveBar()
echartsData = echartsData.filter(t => t.show === true && t.invertTab === false)
@@ -257,6 +386,9 @@ export default {
const _this = this
// !this.myChart && (this.myChart = echarts.init(dom))
// 此处为验证是否因dom未销毁导致图表出错后续可能会改
let dom = null
dom = document.getElementById('overviewLineChart')
this.chartOption = stackedLineChartOption
const chartOption = this.chartOption.series[0]
this.chartOption.series = echartsData.map((t, i) => {
@@ -344,7 +476,7 @@ export default {
this.chartOption.tooltip.formatter = (params) => {
params.forEach(t => {
t.seriesName = this.$t(t.seriesName)
this.tabs.forEach(e => {
this.mpackets.forEach(e => {
if (this.$t(e.name) === t.seriesName) {
t.borderColor = chartColor3[e.positioning]
}
@@ -354,7 +486,7 @@ export default {
}
this.showMarkLine = true
this.$nextTick(() => {
this.myChart = echarts.init(this.$refs.overviewLineChart)
this.myChart = echarts.init(dom)
this.myChart.setOption(this.chartOption)
// 设置参见官网https://echarts.apache.org/zh/api.html#action.brush.brush
this.myChart.dispatchAction({
@@ -402,7 +534,6 @@ export default {
}
})
})
}
},
activeChange (item, index) {
if (this.isNoData) return
@@ -434,16 +565,16 @@ export default {
legendSelectChange (item, index, val) {
if (index === 'index') {
this.dispatchLegendSelectAction(item.name)
} else if (this.tabs[index] && this.tabs[index].name === item.name) {
} else if (this.mpackets[index] && this.mpackets[index].name === item.name) {
this.dispatchLegendSelectAction(item.name)
this.tabs.forEach((t) => {
this.mpackets.forEach((t) => {
if (t.name !== item.name) {
this.dispatchLegendUnSelectAction(t.name)
}
})
}
if (val === 'active') {
this.tabs.forEach(t => {
this.mpackets.forEach(t => {
if (item.name === t.name) {
t.invertTab = !t.invertTab
} else {
@@ -455,7 +586,7 @@ export default {
} else {
this.lineTab = t.class
}
this.tabs.forEach((e) => {
this.mpackets.forEach((e) => {
this.dispatchLegendSelectAction(e.name)
})
}
@@ -463,8 +594,8 @@ export default {
}
},
handleActiveBar () {
if (document.querySelector('.network .line-value-tabs.is-active')) {
const { offsetLeft, clientWidth, clientLeft } = document.querySelector('.network .line-value-tabs.is-active')
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;`
}
@@ -475,13 +606,12 @@ export default {
referenceSelectChange (val) {
this.lineRefer = val
let echartsData
if (this.lineTab) {
echartsData = this.tabs.filter(t => t.show === true && t.invertTab === false)
} else {
echartsData = this.tabs.filter(t => t.show === true)
}
if (!this.isUnitTesting) {
const chartOption = this.myChart.getOption()
if (this.lineTab) {
echartsData = this.mpackets.filter(t => t.show === true && t.invertTab === false)
} else {
echartsData = this.mpackets.filter(t => t.show === true)
}
if (this.lineRefer === 'Average' && this.showMarkLine) {
chartOption.series.forEach((t, i) => {
if (t.name === echartsData[0].name) {
@@ -502,7 +632,6 @@ export default {
})
}
this.myChart.setOption(chartOption)
}
},
symbolSizeSortChange (index, time) {
const dataIntegrationArray = []
@@ -552,87 +681,6 @@ export default {
const sortIndex = dataIntegrationArray.findIndex(a => a[2] === index)
return this.sizes[sortIndex]
},
initData (data, val, active, show, n) {
let lineData = []
if (data !== undefined && data.length > 0) {
data.forEach((item) => {
item.type = getLineType(item.type)
if (item.type === val) {
lineData = Object.keys(item).map(t => {
return {
...item[t]
}
})
}
})
}
lineData.splice(0, 1)
if (val === 'Sessions/s') {
const tabs = _.cloneDeep(this.tabsTemplate)
lineData.forEach((d, i) => {
tabs[i].data = d.values
tabs[i].analysis = d.analysis
})
tabs.forEach((e, i) => {
if (i !== 0) {
e.show = false
}
e.unitType = 'sessions/s'
e.invertTab = false
this.lineTab = 'total'
this.legendSelectChange(e, 0)
})
this.tabs = tabs
this.$nextTick(() => {
this.echartsInit(this.tabs, true)
})
} else {
const unit = val === 'Bits/s' ? 'bps' : 'packets/s'
this.legendInit(lineData, active, show, unit, n)
}
},
legendInit (data, active, show, type, n) {
const tabs = _.cloneDeep(this.tabsTemplate)
data.forEach((d, i) => {
tabs[i].data = d.values
tabs[i].analysis = d.analysis
})
let num = 0
tabs.forEach(e => {
e.unitType = type
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) == 0) {
e.show = false
num += 1
} else {
e.show = true
if (!active && show !== this.lineRefer) {
this.legendSelectChange(e, 'index')
}
}
if (this.lineTab === e.class) {
if (parseFloat(e.analysis.avg) <= 0) {
this.lineTab = ''
this.lineRefer = ''
this.init()
}
}
})
this.tabs = tabs
if (num === 5) {
tabs[0].invertTab = false
this.lineTab = 'total'
this.legendSelectChange(tabs[0], 0)
this.$nextTick(() => {
this.echartsInit(this.tabs, true)
})
} else {
if (n) this.lineTab = ''
this.$nextTick(() => {
this.echartsInit(this.tabs, show)
if (!this.lineRefer) this.lineRefer = 'Average'
})
}
},
/**
* 鼠标右键返回框选的时间范围
*/
@@ -654,9 +702,11 @@ export default {
this.myChart = null
this.chartOption = null
this.timer = setTimeout(() => {
if (this.lineTab && this.metric !== 'Sessions/s') {
const data = this.tabsTemplate.find(t => t.class === this.lineTab)
if (this.lineTab) {
const data = this.mpackets.find(t => t.class === this.lineTab)
if (data && data.positioning) {
this.activeChange(data, data.positioning)
}
} else {
this.init()
}
@@ -667,13 +717,11 @@ export default {
clearTimeout(this.timer)
window.removeEventListener('resize', this.resize)
let myChart = echarts.getInstanceByDom(this.$refs.overviewLineChart)
let myChart = echarts.getInstanceByDom(document.getElementById('overviewLineChart'))
if (myChart) {
echarts.dispose(myChart)
}
if (this.myChart) {
echarts.dispose(this.myChart)
}
this.myChart = null
// 检测时发现该方法占用较大内存,且未被释放
this.unitConvert = null
myChart = null

View File

@@ -61,6 +61,7 @@ export default {
methods: {
init () {
const params = {
// startTime: true,
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime)
}
@@ -192,14 +193,6 @@ export default {
beforeUnmount () {
clearTimeout(this.timer)
window.removeEventListener('resize', this.resize)
const dom = document.getElementById('chart1')
const dom2 = document.getElementById('chart2')
if (dom) {
echarts.dispose(dom)
}
if (dom2) {
echarts.dispose(dom2)
}
this.myChart = null
this.myChart2 = null
}

View File

@@ -215,8 +215,8 @@ import unitConvert from '@/utils/unit-convert'
import { getChainRatio, computeScore, urlParamsHandler, overwriteUrl, readDrilldownTableConfigByUser, combineDrilldownTableWithUserConfig, getDnsMapData, handleSpecialValue, getConfigVersion } from '@/utils/tools'
import { getSecond } from '@/utils/date-util'
import chartMixin from '@/views/charts2/chart-mixin'
import { db } from '@/indexedDB'
import _ from 'lodash'
import indexedDBUtils from '@/indexedDB'
export default {
name: 'NetworkOverviewTabs',
@@ -1729,7 +1729,7 @@ export default {
version = await getConfigVersion('default')
}
// 更新缓存中的配置
await indexedDBUtils.selectTable(dbDrilldownTableConfig).put({
await db[dbDrilldownTableConfig].put({
id: this.userId,
version: version,
config: this.$_.cloneDeep(curUserConfigGroup)

View File

@@ -11,8 +11,8 @@
<chart-no-data v-if="isNoData"></chart-no-data>
<div class="npm-app-body" v-else>
<div class="npm-app-body-patch" v-for="(data, index) in tableData" :key="index">
<div class="npm-app-body-icon"><span><i :class="data.icon" :test-id="`iconContent${index}`"></i></span></div>
<div class="npm-app-body-color" v-for="index2 in 6" :key="index2" :class="{'score-color': data.score >= index2}"></div>
<div class="npm-app-body-icon"><span><i :class="data.icon"></i></span></div>
<div class="npm-app-body-color" v-for="(item, index) in 6" :key="index" :class="{'score-color': data.score >= index + 1}"></div>
</div>
</div>
</div>
@@ -48,7 +48,7 @@
<div v-else-if="scope.row.bytesRateChainRatio < 0" class="data-total-trend data-total-trend-green">
<i class="cn-icon-decline cn-icon"></i>&nbsp;
<span v-if="scope.row.bytesRateChainRatio >= -5">
{{unitConvert(scope.row.bytesRateChainRatio, unitTypes.percent).join('').replace(/-/g, '')}}
{{unitConvert(scope.row.bytesRateChainRatio, unitTypes.percent).join('').replaceAll('-', '')}}
</span>
<span v-else>>500.00%</span>
</div>
@@ -71,7 +71,7 @@
<div v-else-if="scope.row.outboundBytesRateChainRatio < 0" class="data-total-trend data-total-trend-green">
<i class="cn-icon-decline cn-icon"></i>&nbsp;
<span v-if="scope.row.outboundBytesRateChainRatio >= -5">
{{unitConvert(scope.row.outboundBytesRateChainRatio, unitTypes.percent).join('').replace(/-/g, '')}}
{{unitConvert(scope.row.outboundBytesRateChainRatio, unitTypes.percent).join('').replaceAll('-', '')}}
</span>
<span v-else>>500.00%</span>
</div>
@@ -86,35 +86,35 @@
<div class="data-trend">
<div v-if="scope.row.inboundBytesRateChainRatio > 0" class="data-total-trend data-total-trend-red">
<i class="cn-icon-rise1 cn-icon"></i>&nbsp;
<span v-if="scope.row.inboundBytesRateChainRatio <= 5" :test-id="`inbound-${scope.row.appSubcategory}`">
<span v-if="scope.row.inboundBytesRateChainRatio <= 5">
{{unitConvert(scope.row.inboundBytesRateChainRatio, unitTypes.percent).join('')}}
</span>
<span v-else :test-id="`inbound-${scope.row.appSubcategory}`">>500.00%</span>
<span v-else>>500.00%</span>
</div>
<div v-else-if="scope.row.inboundBytesRateChainRatio < 0" class="data-total-trend data-total-trend-green">
<i class="cn-icon-decline cn-icon"></i>&nbsp;
<span v-if="scope.row.inboundBytesRateChainRatio >= -5" :test-id="`inbound-${scope.row.appSubcategory}`">
{{unitConvert(scope.row.inboundBytesRateChainRatio, unitTypes.percent).join('').replace(/-/g, '')}}
<span v-if="scope.row.inboundBytesRateChainRatio >= -5">
{{unitConvert(scope.row.inboundBytesRateChainRatio, unitTypes.percent).join('').replaceAll('-', '')}}
</span>
<span v-else :test-id="`inbound-${scope.row.appSubcategory}`">>500.00%</span>
<span v-else>>500.00%</span>
</div>
<div v-else-if="scope.row.inboundBytesRateChainRatio === 0" :test-id="`inbound-${scope.row.appSubcategory}`" class="data-total-trend data-total-trend-black">
<div v-else-if="scope.row.inboundBytesRateChainRatio === 0" class="data-total-trend data-total-trend-black">
<i class="cn-icon-constant cn-icon"></i>
</div>
<div v-else></div>
</div>
</template>
<template v-else-if="item.prop === 'score'">
<div v-if="scope.row.score <= 2" :test-id="`score-${scope.row.appSubcategory}`" class="data-score data-score-red">
<div v-if="scope.row.score <= 2" :class="{'data-score-red': scope.row.score <= 2}" class="data-score">
{{scope.row.score}}
</div>
<div v-else-if="scope.row.score <= 4" :test-id="`score-${scope.row.appSubcategory}`" class="data-score data-score-yellow">
<div v-else-if="scope.row.score <= 4" :class="{'data-score-yellow': scope.row.score <= 4}" class="data-score">
{{scope.row.score}}
</div>
<div v-else-if="scope.row.score <= 6" :test-id="`score-${scope.row.appSubcategory}`" class="data-score data-score-green">
<div v-else-if="scope.row.score <= 6" :class="{'data-score-green': scope.row.score <= 6}" class="data-score">
{{scope.row.score}}
</div>
<div v-else-if="scope.row.score === '-'" :test-id="`score-${scope.row.appSubcategory}`" class="data-score-no-data">
<div v-else-if="scope.row.score === '-'" class="data-score-no-data">
-
</div>
</template>
@@ -138,12 +138,17 @@ import { unitTypes, npmCategoryInfoMapping, networkTable, operationType, npmCate
import unitConvert from '@/utils/unit-convert'
import { api } from '@/utils/api'
import { getSecond } from '@/utils/date-util'
import { computeScore, getChainRatio, getUserDrilldownTableConfig, overwriteUrl, urlParamsHandler } from '@/utils/tools'
import { get } from '@/utils/http'
import {
getChainRatio,
computeScore,
urlParamsHandler,
overwriteUrl,
getUserDrilldownTableConfig
} from '@/utils/tools'
import chartMixin from '@/views/charts2/chart-mixin'
import ChartNoData from '@/views/charts/charts/ChartNoData'
import ChartError from '@/components/common/Error'
import axios from 'axios'
export default {
name: 'NpmAppCategoryScore',
data () {
@@ -193,15 +198,15 @@ export default {
endTime: getSecond(this.timeFilter.endTime)
}
// 获取table后三列内容
const currentTrafficRequest = axios.get(api.npm.overview.appTrafficAnalysis, { params: { ...params, cycle: 0 } })
const lastCycleTrafficRequest = axios.get(api.npm.overview.appTrafficAnalysis, { params: { ...params, cycle: 1 } })
const currentTrafficRequest = get(api.npm.overview.appTrafficAnalysis, { ...params, cycle: 0 })
const lastCycleTrafficRequest = get(api.npm.overview.appTrafficAnalysis, { ...params, cycle: 1 })
this.toggleLoading(true)
Promise.all([currentTrafficRequest, lastCycleTrafficRequest]).then(res => {
if (res[0].data.code === 200 && res[1].data.code === 200) {
if (res[0].code === 200 && res[1].code === 200) {
this.showError = false
this.errorMsg = ''
const prevData = res[1].data.data.result
const data = res[0].data.data.result
const prevData = res[1].data.result
const data = res[0].data.result
if (data && data.length > 0) {
this.isNoData = false
const tableData = data.map(d => {
@@ -223,23 +228,24 @@ export default {
return result
})
// 计算分数
const tcpRequest = axios.get(api.npm.overview.appTcpSessionDelay, { params: params })
const httpRequest = axios.get(api.npm.overview.appHttpResponseDelay, { params: params })
const sslRequest = axios.get(api.npm.overview.appSslConDelay, { params: params })
const tcpLostRequest = axios.get(api.npm.overview.appTcpLostlenPercent, { params: params })
const packetRetransRequest = axios.get(api.npm.overview.appPacketRetransPercent, { params: params })
const tcpRequest = get(api.npm.overview.appTcpSessionDelay, params)
const httpRequest = get(api.npm.overview.appHttpResponseDelay, params)
const sslRequest = get(api.npm.overview.appSslConDelay, params)
const tcpLostRequest = get(api.npm.overview.appTcpLostlenPercent, params)
const packetRetransRequest = get(api.npm.overview.appPacketRetransPercent, params)
Promise.all([tcpRequest, httpRequest, sslRequest, tcpLostRequest, packetRetransRequest]).then(res => {
const keyPre = ['tcp', 'http', 'ssl', 'tcpLost', 'packetRetrans']
let msg = ''
res.forEach((r, i) => {
if (r.data.code === 200) {
if (r.code === 200) {
tableData.forEach(t => {
t[keyPre[i] + 'Score'] = r.data.data.result.find(d => d.appSubcategory === t.appSubcategory)
const find = r.data.result.find(d => d.appSubcategory === t.appSubcategory)
t[keyPre[i] + 'Score'] = find
})
} else {
this.showError = true
msg = msg + ',' + r.data.data.message
msg = msg + ',' + r.message
if (msg.indexOf(',') === 0) {
msg = msg.substring(1, msg.length)
}
@@ -342,7 +348,7 @@ export default {
}
})
let toPanel = null
list.forEach(item => {
list.forEach((item, index) => {
if (item.label === tabType) {
item.checked = false
toPanel = item.panelId
@@ -354,7 +360,8 @@ export default {
this.$store.commit('setNetworkOverviewTabList', list)
const tabObjGroup = list.filter(item => item.checked)
if (tabObjGroup && tabObjGroup.length > 0) {
this.urlChangeParams[this.curTabState.curTab] = tabObjGroup[0]
const curTab = tabObjGroup[0]
this.urlChangeParams[this.curTabState.curTab] = curTab
}
this.changeUrlTabState()
this.$router.push({
@@ -377,9 +384,6 @@ export default {
},
mounted () {
this.init()
},
beforeUnmount () {
this.unitConvert = null
}
}
</script>

View File

@@ -1,11 +1,29 @@
<template>
<div class="npm-app-event">
<!-- <div class="metric-select">
<el-select
v-model="metric"
class="option__select select-column"
popper-class="option-popper common-select"
:popper-append-to-body="false"
key="tabMetric"
@change="changeMetric"
size="mini"
width="100">
<el-option
v-for="item in options"
:key="item.label"
:label="item.label"
:value="item.value"
/>
</el-select>
<span>{{ $t('network.metric') }}</span>
</div>-->
<el-table
id="tabTable"
ref="dataTable"
:data="tableData"
class="npm-app-event-table"
:row-class-name="rowClassName"
height="100%"
empty-text=""
>
@@ -15,33 +33,34 @@
<span class="data-column__span">{{ $t(item.label) }}</span>
</template>
<template #default="scope" :column="item">
<div class="data-app-event-table" :test-id="`${item.prop}${scope.row.index}`">
<div class="data-app-event-table">
<template v-if="item.prop === 'domain' ||item.prop === 'appName' ||item.prop === 'serverIp' ">
<span class="data-applications">{{ scope.row[item.prop] }}</span>
</template>
<template v-else-if="item.prop === 'eventSeverity'" >
<template v-else-if="item.prop === 'eventSeverity'">
<template v-if="scope.row[item.prop]==='critical'">
<div v-for="item in 5" class="red-dot" :key="item" :test-id="`eventSeverityValue${scope.row.index}${item}`"></div>
<div v-for="item in 5" class="red-dot" :key="item"></div>
</template>
<template v-else-if="scope.row[item.prop]==='high'">
<div v-for="item in 4" class="red-dot" :key="item" :test-id="`eventSeverityValue${scope.row.index}${item}`"></div>
<div v-for="item in 1" class="grey-dot" :key="item" :test-id="`eventSeverityValue${scope.row.index}${4+item}`"></div>
<div v-for="item in 4" class="red-dot" :key="item"></div>
<div class="grey-dot"></div>
</template>
<template v-else-if="scope.row[item.prop]==='medium'">
<div v-for="item in 3" class="red-dot" :key="item" :test-id="`eventSeverityValue${scope.row.index}${item}`"></div>
<div v-for="item in 2" class="grey-dot" :key="item" :test-id="`eventSeverityValue${scope.row.index}${3+item}`"></div>
<div v-for="item in 3" class="red-dot" :key="item"></div>
<div v-for="item in 2" class="grey-dot" :key="item"></div>
</template>
<template v-else-if="scope.row[item.prop]==='low'">
<div v-for="item in 2" class="red-dot" :key="item" :test-id="`eventSeverityValue${scope.row.index}${item}`"></div>
<div v-for="item in 3" class="grey-dot" :key="item" :test-id="`eventSeverityValue${scope.row.index}${2+item}`"></div>
<div v-for="item in 2" class="red-dot" :key="item"></div>
<div v-for="item in 3" class="grey-dot" :key="item"></div>
</template>
<template v-else-if="scope.row[item.prop]==='info'">
<div v-for="item in 1" class="red-dot" :key="item" :test-id="`eventSeverityValue${scope.row.index}${item}`"></div>
<div v-for="item in 4" class="grey-dot" :key="item" :test-id="`eventSeverityValue${scope.row.index}${1+item}`"></div>
<div v-for="item in 1" class="red-dot" :key="item"></div>
<div v-for="item in 4" class="grey-dot" :key="item"></div>
</template>
<span class="data-severity">{{ scope.row[item.prop] }}</span>
</template>
<template v-else-if="item.prop === 'eventType'">
<!-- <span class="data-eventType" v-for="type in scope.row[item.prop]">{{type}}</span>-->
<span class="data-eventType">{{ scope.row[item.prop] }}</span>
</template>
<template v-else-if="item.prop === 'count'">
@@ -134,10 +153,6 @@ export default {
this.init()
},
methods: {
rowClassName ({ row, rowIndex }) {
// 把每一行的索引放进row
row.index = rowIndex
},
init () {
this.toggleLoading(true)
this.isNoData = false

View File

@@ -13,14 +13,14 @@
<div class="npm-event-pie-legend-title" v-if="chartData.length > 0">{{ $t('overall.type') }}</div>
<template v-for="(legend, index) in chartData" :key="index">
<div class="npm-event-pie-legend-type">
<div class="npm-event-pie-legend-type-severity" :test-id="`testNode${index}`">{{legend.name}}</div>
<div class="npm-event-pie-legend-type-severity">{{legend.name}}</div>
</div>
</template>
</div>
<div class="npm-event-pie-legend">
<div class="npm-event-pie-legend-title" v-if="chartData.length > 0">{{ $t('network.total') }}</div>
<template v-for="(legend, index) in chartData" :key="index">
<div class="npm-event-pie-legend-total" :test-id="`total${index}`">{{legend.value}}</div>
<div class="npm-event-pie-legend-total">{{legend.value}}</div>
</template>
</div>
</div>
@@ -31,6 +31,7 @@
<script>
import { shallowRef } from 'vue'
import { get } from '@/utils/http'
import { api } from '@/utils/api'
import * as echarts from 'echarts'
import { pieChartOption3 } from '@/views/charts2/charts/options/echartOption'
@@ -38,7 +39,6 @@ import { getSecond } from '@/utils/date-util'
import ChartNoData from '@/views/charts/charts/ChartNoData'
import chartMixin from '@/views/charts2/chart-mixin'
import ChartError from '@/components/common/Error'
import axios from 'axios'
export default {
name: 'NpmEventsByType',
@@ -108,8 +108,7 @@ export default {
type: 'severity'
}
this.toggleLoading(true)
axios.get(api.npm.events.recentEvents, { params: params }).then(res => {
res = res.data
get(api.npm.events.recentEvents, params).then(res => {
if (res.code === 200) {
this.showError = false
this.isNoData = res.data.result.length === 0
@@ -127,10 +126,8 @@ export default {
this.chartData = arrData.sort((a, b) => { return b.value - a.value })
this.$nextTick(() => {
if (this.chartData.length > 0) {
if (!this.isUnitTesting) {
this.init()
}
}
})
} else {
this.isNoData = false
@@ -155,9 +152,7 @@ export default {
},
beforeUnmount () {
window.removeEventListener('resize', this.resize)
if (this.myChart) {
echarts.dispose(this.myChart)
}
this.myChart = null
this.chartOption = null
}
}

View File

@@ -2,21 +2,21 @@
<div class="npm-header">
<div class="npm-header-body" v-for="(item, index) in chartData" :key=index>
<div class="npm-header-body-severity">
<div class="npm-header-body-severity-icon" :class="item.eventSeverity" :test-id="`icon${index}`"></div>
<div class="npm-header-body-severity-value" :test-id="`severity${index}`">{{item.eventSeverity}}</div>
<div class="npm-header-body-severity-icon" :class="item.eventSeverity"></div>
<div class="npm-header-body-severity-value">{{item.eventSeverity}}</div>
</div>
<chart-error v-if="showError" tooltip :content="errorMsg" />
<div v-else class="npm-header-body-total" :test-id="`total${index}`">{{item.count}}</div>
<div v-else class="npm-header-body-total">{{item.count}}</div>
</div>
</div>
</template>
<script>
import { getSecond } from '@/utils/date-util'
import { get } from '@/utils/http'
import { api } from '@/utils/api'
import chartMixin from '@/views/charts2/chart-mixin'
import ChartError from '@/components/common/Error'
import axios from 'axios'
export default {
name: 'NpmEventsHeader',
components: { ChartError },
@@ -65,13 +65,12 @@ export default {
methods: {
recentEventsListData () {
const params = {
startTime: this.timeFilter && this.timeFilter.startTime ? getSecond(this.timeFilter.startTime) : '',
endTime: this.timeFilter && this.timeFilter.endTime ? getSecond(this.timeFilter.endTime) : '',
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
type: this.type
}
this.toggleLoading(true)
axios.get(api.npm.events.list, { params: params }).then(res => {
res = res.data
get(api.npm.events.list, params).then(res => {
if (res.code === 200) {
this.showError = false
if (res.data.result.length === 0) {
@@ -97,9 +96,7 @@ export default {
}
},
mounted () {
this.$nextTick(() => {
this.recentEventsListData()
})
}
}
</script>

View File

@@ -336,9 +336,7 @@ export default {
beforeUnmount () {
clearTimeout(this.timer)
window.removeEventListener('resize', this.resize)
if (this.myChart) {
echarts.dispose(this.myChart)
}
this.myChart = null
this.chartOption = null
}
}

View File

@@ -1,60 +1,16 @@
<template>
<div class="npm-network-quantity">
<div class="single-value" v-for="(npm, index) in newNpmNetworkData" :key="index">
<div class="single-value__title" style="display: flex">
{{ $t(npmNetworkName[index].name) }}
<chart-error v-if="npm.message" tooltip :content="npm.message"></chart-error>
</div>
<div class="single-value__content" >
<div class="single-value__content-number" v-if="index ===0 || index ===1 || index ===2" :test-id="`singleValueContent${index}`">
{{ unitConvert(npm.Avg, unitTypes.time).join(' ') }}
</div>
<div class="single-value__content-number" v-else :test-id="`singleValueContent${index}`">
{{unitConvert(npm.Avg, unitTypes.percent).join(' ')}}
</div>
<div v-if="npm.value > 0" class="single-value__content-trend single-value__content-trend-red" >
<i class="cn-icon-rise1 cn-icon" :test-id="`singleValueTrendIcon${index}`"></i>&nbsp;
<span v-if="npm.value <= 5" :test-id="`singleValueTrendValue${index}`">
{{ unitConvert(npm.value, unitTypes.percent).join('') }}
</span>
<span v-else :test-id="`singleValueTrendValue${index}`">>500.00%</span>
</div>
<div v-else-if="npm.value < 0" class="single-value__content-trend single-value__content-trend-green" >
<i class="cn-icon-decline cn-icon" :test-id="`singleValueTrendIcon${index}`"></i>&nbsp;
<span v-if="npm.value >= -5" :test-id="`singleValueTrendValue${index}`">
{{ unitConvert(npm.value, unitTypes.percent).join('') }}
</span>
<span v-else :test-id="`singleValueTrendValue${index}`">>500.00%</span>
</div>
<div v-else-if="npm.value === 0" class="single-value__content-trend single-value__content-trend-black">
<i class="cn-icon-constant cn-icon" :test-id="`singleValueTrendIcon${index}`"></i>
</div>
<div v-else></div>
</div>
<div class="single-value__circle">
<div class="single-value__circle-p95" :test-id="`singleValueP95${index}`">
<span v-if="index ===0 || index ===1 || index ===2">
P95:{{ unitConvert(npm.P95, unitTypes.time).join(' ') }}</span>
<span v-else>
P95:{{ unitConvert(npm.P95, unitTypes.percent).join(' ') }}
</span>
</div>
<div class="single-value__circle-p99" :test-id="`singleValueP99${index}`">
<span v-if="index ===0 || index ===1 || index ===2">
P99:{{ unitConvert(npm.P99, unitTypes.time).join(' ') }}
</span>
<span v-else>
P99:{{ unitConvert(npm.P99, unitTypes.percent).join(' ') }}
</span>
</div>
</div>
</div>
<single-value
v-if="npmNetworkData.length>0"
:npm-network-name="npmNetworkName"
:npm-network-data="npmNetworkData"
></single-value>
</div>
</template>
<script>
import SingleValue from '@/views/charts2/charts/npm/localComponents/SingleValue'
import { get } from '@/utils/http'
import { getSecond } from '@/utils/date-util'
import { api } from '@/utils/api'
import chartMixin from '@/views/charts2/chart-mixin'
@@ -62,11 +18,9 @@ import _ from 'lodash'
import { getChainRatio } from '@/utils/tools'
import { useRoute } from 'vue-router'
import { ref } from 'vue'
import { unitTypes } from '@/utils/constants'
import unitConvert from '@/utils/unit-convert'
import axios from 'axios'
export default {
name: 'NpmNetworkQuantity',
components: { SingleValue },
mixins: [chartMixin],
setup () {
const { query } = useRoute()
@@ -85,8 +39,6 @@ export default {
},
data () {
return {
unitTypes,
unitConvert,
npmNetworkName: [
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency' },
{ name: 'networkAppPerformance.httpResponse' },
@@ -96,7 +48,6 @@ export default {
],
npmNetworkCycleData: [],
npmNetworkLastCycleData: [],
newNpmNetworkData: [],
npmNetworkData: [],
side: '',
chartData: {},
@@ -117,7 +68,7 @@ export default {
npmNetworkCycleQuery () {
let condition = ''
let url = ''
if (this.queryCondition && this.queryCondition.indexOf(' OR ') > -1) {
if (this.queryCondition.indexOf(' OR ') > -1) {
condition = this.queryCondition.split(/["|'](.*?)["|']/)
} else {
condition = this.queryCondition
@@ -133,38 +84,37 @@ export default {
} else if (parseFloat(this.tabIndex) === 1) {
this.side = 'server'
}
if (condition && (typeof condition !== 'object') && type) { // 判断 condition 不为空并且不为对象 type 不为空
if (type === 'clientIp' || type === 'serverIp') { // type = clientIp || serverIp
if (parseFloat(this.tabIndex) === 0) { // npm 下钻 tabIndex 为 0
if (condition && (typeof condition !== 'object') && type) {
if (type === 'clientIp' || type === 'serverIp') {
if (parseFloat(this.tabIndex) === 0) {
type = 'clientIp'
} else if (parseFloat(this.tabIndex) === 1) { // npm 下钻 tabIndex 为 1
} else if (parseFloat(this.tabIndex) === 1) {
type = 'serverIp'
}
params.q = `ip='${condition.split(/'(.*?)'/)[1]}'` // 拼接字段作为参数
params.q = `ip='${condition.split(/'(.*?)'/)[1]}'`
} else if (type === 'clientCity') {
params.q = `client_city='${condition.split(/'(.*?)'/)[1]}'` // 拼接字段作为参数
params.q = `client_city='${condition.split(/'(.*?)'/)[1]}'`
} else if (type === 'serverCity') {
params.q = `server_city='${condition.split(/'(.*?)'/)[1]}'` // 拼接字段作为参数
params.q = `server_city='${condition.split(/'(.*?)'/)[1]}'`
} else {
params.q = condition // 默认参数
params.q = condition
}
params.type = type
} else if (condition.length > 1 && type && type === 'ip') { // condition 为数组时数组长度不为 0 | type 不为空 | type为ip
params.q = `${type}='${condition[1]}' and side='${this.side}'` // 拼接字段作为参数
} else if (condition.length > 1 && type && type === 'ip') {
params.q = `${type}='${condition[1]}' and side='${this.side}'`
params.type = type
} else if (condition.length > 1 && type && type !== 'ip') { // condition 为数组时数组长度不为 0 | type 不为空 | type不为ip
if (type === 'country' || type === 'asn' || type === 'province' || type === 'city' || type === 'isp') { // 根据接口所需,调整参数
params.q = `${type}='${condition[1]}'` // 拼接字段作为参数
} else if (condition.length > 1 && type && type !== 'ip') {
if (type === 'country' || type === 'asn' || type === 'province' || type === 'city' || type === 'isp') {
params.q = `${type}='${condition[1]}'`
params.type = type
} else if (type === 'idcRenter') {
params.q = `idc_renter='${condition[1]}'` // 拼接字段作为参数
params.q = `idc_renter='${condition[1]}'`
params.type = type
} else {
params.q = `${condition[0]}'${condition[1]}'` // 拼接字段作为参数
params.q = `${condition[0]}'${condition[1]}'`
params.type = type
}
}
// 区分 3 级菜单和 2 级菜单使用不同的 url
if (parseFloat(this.tabOperationType) === 3) {
url = api.npm.overview.allNetworkAnalysis
} else {
@@ -173,8 +123,7 @@ export default {
if ((type && condition) || type) {
params.type = params.type || type
this.toggleLoading(true)
axios.get(url, { params: params }).then(res => {
res = res.data
get(url, params).then(res => {
if (res.code === 200) {
this.npmNetworkCycleData = res.data.result
}
@@ -184,21 +133,21 @@ export default {
this.toggleLoading(false)
})
} else {
const tcp = axios.get(api.npm.overview.tcpSessionDelay, { params: params })
const http = axios.get(api.npm.overview.httpResponseDelay, { params: params })
const ssl = axios.get(api.npm.overview.sslConDelay, { params: params })
const tcpPercent = axios.get(api.npm.overview.tcpLostlenPercent, { params: params })
const packetPercent = axios.get(api.npm.overview.packetRetransPercent, { params: params })
const tcp = get(api.npm.overview.tcpSessionDelay, params)
const http = get(api.npm.overview.httpResponseDelay, params)
const ssl = get(api.npm.overview.sslConDelay, params)
const tcpPercent = get(api.npm.overview.tcpLostlenPercent, params)
const packetPercent = get(api.npm.overview.packetRetransPercent, params)
this.toggleLoading(true)
Promise.all([tcp, http, ssl, tcpPercent, packetPercent]).then(res => {
// 状态为200的赋值接口数据不为200的传入报错提示message
// 传给子组件SingleValue再进行error处理error处理不在此处处理
this.npmNetworkCycleData = []
res.forEach(t => {
if (t.data.code === 200) {
this.npmNetworkCycleData.push(t.data.data.result)
if (t.code === 200) {
this.npmNetworkCycleData.push(t.data.result)
} else {
this.npmNetworkCycleData.push(t.data)
this.npmNetworkCycleData.push(t)
}
})
this.npmNetworkLastCycleQuery()
@@ -228,8 +177,7 @@ export default {
if ((params.type && params.q) || (param && param.type)) {
params.type = params.type || param.type
this.toggleLoading(true)
axios.get(url, { params: params }).then(res => {
res = res.data
get(url, params).then(res => {
if (res.code === 200) {
this.npmNetworkLastCycleData = res.data.result
} else {
@@ -247,20 +195,20 @@ export default {
this.toggleLoading(false)
})
} else {
const tcp = axios.get(api.npm.overview.tcpSessionDelay, { params: params })
const http = axios.get(api.npm.overview.httpResponseDelay, { params: params })
const ssl = axios.get(api.npm.overview.sslConDelay, { params: params })
const tcpPercent = axios.get(api.npm.overview.tcpLostlenPercent, { params: params })
const packetPercent = axios.get(api.npm.overview.packetRetransPercent, { params: params })
const tcp = get(api.npm.overview.tcpSessionDelay, params)
const http = get(api.npm.overview.httpResponseDelay, params)
const ssl = get(api.npm.overview.sslConDelay, params)
const tcpPercent = get(api.npm.overview.tcpLostlenPercent, params)
const packetPercent = get(api.npm.overview.packetRetransPercent, params)
this.toggleLoading(true)
Promise.all([tcp, http, ssl, tcpPercent, packetPercent]).then(res => {
// 状态为200的赋值接口数据不为200的保留报错提示message
// 传给子组件SingleValue再进行error处理error处理不在此处处理
res.forEach(t => {
if (t.data.code === 200) {
this.npmNetworkLastCycleData.push(t.data.data.result)
if (t.code === 200) {
this.npmNetworkLastCycleData.push(t.data.result)
} else {
this.npmNetworkLastCycleData.push(t.data)
this.npmNetworkLastCycleData.push(t)
}
this.npmNetworkQuantity(this.npmNetworkCycleData, this.npmNetworkLastCycleData, 1)
})
@@ -323,39 +271,6 @@ export default {
})
this.npmNetworkData = cycle
}
this.initData(this.npmNetworkData)
},
initData (data) {
// 处理数据后的数组
const dealList = []
if (data !== undefined && data.length > 0) {
data.forEach((item) => {
const tempObj = {}
for (const i in item) {
if (item.msg || item.message) {
// 为了兼容字段为msg的情况
tempObj.message = item.msg ? item.msg : item.message
} else {
// 将含有avg、p90等关键字使用avg、p90来代替形成统一属性
if (i.indexOf('Avg') > -1) {
tempObj.Avg = item[i]
} else if (i.indexOf('P50') > -1) {
tempObj.P50 = item[i]
} else if (i.indexOf('P90') > -1) {
tempObj.P90 = item[i]
} else if (i.indexOf('P95') > -1) {
tempObj.P95 = item[i]
} else if (i.indexOf('P99') > -1) {
tempObj.P99 = item[i]
}
tempObj.value = item.value
}
}
dealList.push(tempObj)
})
this.newNpmNetworkData = dealList
}
}
},
mounted () {
@@ -367,7 +282,6 @@ export default {
beforeUnmount () {
clearTimeout(this.timer1)
clearTimeout(this.timer2)
this.unitConvert = null
}
}
</script>

View File

@@ -21,15 +21,15 @@
<template #default="scope" :column="item">
<div class="data-recent-table">
<template v-if="item.prop === 'eventSeverity'">
<span class="data-recent-table-severity" :class="scope.row[item.prop]" :test-id="`eventSeverity-${scope.row.eventSeverity}-${scope.$index}`">{{scope.row[item.prop]}}</span>
<span class="data-recent-table-severity" :class="scope.row[item.prop]">{{scope.row[item.prop]}}</span>
</template>
<template v-else-if="item.prop === 'eventKey'">
<span class="data-recent-table-entity click-active" @click="jumpPage(scope.row)" :test-id="`eventKey-${splitEventKey(scope.row.eventKey)}-${scope.$index}`">{{splitEventKey(scope.row[item.prop])}}</span>
<span class="data-recent-table-entity click-active" @click="jumpPage(scope.row)">{{splitEventKey(scope.row[item.prop])}}</span>
</template>
<template v-else-if="item.prop === 'eventType'">
<span class="data-recent-table-eventType" :test-id="`eventType-${scope.row.eventType}-${scope.$index}`">{{scope.row[item.prop]}}</span>
<span class="data-recent-table-eventType">{{scope.row[item.prop]}}</span>
</template>
<span v-else-if="scope.row[item.prop]" :test-id="`startTime-${scope.$index}`">{{scope.row[item.prop]}}</span>
<span v-else-if="scope.row[item.prop]">{{scope.row[item.prop]}}</span>
<span v-else>-</span>
</div>
</template>
@@ -48,13 +48,13 @@
</template>
<script>
import { get } from '@/utils/http'
import { api } from '@/utils/api'
import { getSecond, dateFormatByAppearance } from '@/utils/date-util'
import chartMixin from '@/views/charts2/chart-mixin'
import { useRoute } from 'vue-router'
import { ref } from 'vue'
import ChartError from '@/components/common/Error'
import axios from 'axios'
export default {
name: 'NpmRecentEvents',
@@ -99,7 +99,7 @@ export default {
endTime: getSecond(this.timeFilter.endTime),
limit: 8
}
if (condition && condition.length > 1 && this.dimensionType) {
if (condition.length > 1 && this.dimensionType) {
params.param = condition[1]
params.type = this.dimensionType
if (params.type === 'serverIp' || params.type === 'clientIp') params.type = 'ip'
@@ -114,8 +114,7 @@ export default {
url = api.npm.events.recentEvents
}
this.toggleLoading(true)
axios.get(url, { params: params }).then(res => {
res = res.data
get(url, params).then(res => {
if (res.code === 200) {
this.showError = false
this.isNoData = res.data.result.length === 0
@@ -152,7 +151,6 @@ export default {
return name
},
jumpPage (item) {
this.beforeRouterPush()
this.$router.push({
path: '/detection/performanceEvent',
query: {
@@ -160,36 +158,6 @@ export default {
eventId: item.eventId
}
})
},
/**
* 在路由跳转前,即下钻前将路由数据保存起来,确保回退和前进保留当时状态
*/
beforeRouterPush () {
const currentRouter = this.$_.cloneDeep(this.$route.query)
const historyList = this.$_.cloneDeep(this.$store.getters.getRouterHistoryList)
const tempObj = {
t: currentRouter.t,
query: currentRouter,
path: this.$_.cloneDeep(this.$route.path),
params: this.$_.cloneDeep(this.$route.params)
}
if (historyList.length > 0) {
let flag = true
historyList.forEach((item, index) => {
if (item.t === currentRouter.t) {
historyList[index] = tempObj
flag = false
}
if (!flag) {
return true
}
})
if (flag) historyList.push(tempObj)
} else {
historyList.push(tempObj)
}
this.$store.commit('setRouterHistoryList', historyList)
}
},
mounted () {

View File

@@ -22,6 +22,7 @@ import { get } from '@/utils/http'
import { api } from '@/utils/api'
import { drillDownPanelTypeMapping } from '@/utils/constants'
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
import { useRoute } from 'vue-router'
import { ref } from 'vue'
export default {
name: 'NpmTabs',

View File

@@ -42,7 +42,7 @@ import ChartNoData from '@/views/charts/charts/ChartNoData'
import _ from 'lodash'
import chartMixin from '@/views/charts2/chart-mixin'
import { useRoute } from 'vue-router'
import { getLineType, getLineIndexUnit, overwriteUrl, urlParamsHandler } from '@/utils/tools'
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
import ChartError from '@/components/common/Error'
export default {
@@ -71,7 +71,7 @@ export default {
unitConvert,
unitTypes,
side: '',
tabs: [
mpackets: [
{ name: this.$t('network.total'), show: true, positioning: 0, data: [], unitType: 'number' },
{ name: this.$t('network.inbound'), show: true, positioning: 1, data: [], unitType: 'number' },
{ name: this.$t('network.outbound'), show: true, positioning: 2, data: [], unitType: 'number' },
@@ -80,11 +80,11 @@ export default {
{ name: this.$t('network.other'), show: true, positioning: 5, data: [], unitType: 'number' }
],
npmQuantity: [
{ name: this.$t('networkAppPerformance.tcpConnectionEstablishLatency'), show: true, positioning: 0, data: [], unitType: unitTypes.time, index: 0 },
{ name: this.$t('networkAppPerformance.httpResponse'), show: true, positioning: 0, data: [], unitType: unitTypes.time, index: 1 },
{ name: this.$t('networkAppPerformance.sslResponseLatency'), show: true, positioning: 0, data: [], unitType: unitTypes.time, index: 2 },
{ name: this.$t('networkAppPerformance.packetLoss'), show: true, positioning: 0, data: [], unitType: unitTypes.percent, index: 3 },
{ name: this.$t('overall.packetRetrans'), show: true, positioning: 0, data: [], unitType: unitTypes.percent, index: 4 }
{ name: this.$t('networkAppPerformance.tcpConnectionEstablishLatency'), show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: this.$t('networkAppPerformance.httpResponse'), show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: this.$t('networkAppPerformance.sslResponseLatency'), show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: this.$t('networkAppPerformance.packetLoss'), show: true, positioning: 0, data: [], unitType: unitTypes.percent },
{ name: this.$t('overall.packetRetrans'), show: true, positioning: 0, data: [], unitType: unitTypes.percent }
],
chartData: {},
metricOptions: [
@@ -144,6 +144,7 @@ export default {
if (!val) {
val = this.metricFilter
}
// const conditionStr = this.$route.query.queryCondition ? this.$route.query.queryCondition : ''
let condition = ''
let type = this.dimensionType
if (this.queryCondition.indexOf(' OR ') > -1) {
@@ -199,7 +200,7 @@ export default {
this.showError = false
this.isNoData = res.data.result.length === 0
if (this.isNoData) {
this.tabs = [
this.mpackets = [
{ name: this.$t('network.total'), show: true, positioning: 0, data: [], unitType: 'number' },
{ name: this.$t('network.inbound'), show: true, positioning: 1, data: [], unitType: 'number' },
{ name: this.$t('network.outbound'), show: true, positioning: 2, data: [], unitType: 'number' },
@@ -208,15 +209,92 @@ export default {
{ name: this.$t('network.other'), show: true, positioning: 5, data: [], unitType: 'number' }
]
this.npmQuantity = [
{ name: this.$t('networkAppPerformance.tcpConnectionEstablishLatency'), show: true, positioning: 0, data: [], unitType: unitTypes.time, index: 0 },
{ name: this.$t('networkAppPerformance.httpResponse'), show: true, positioning: 0, data: [], unitType: unitTypes.time, index: 1 },
{ name: this.$t('networkAppPerformance.sslResponseLatency'), show: true, positioning: 0, data: [], unitType: unitTypes.time, index: 2 },
{ name: this.$t('networkAppPerformance.packetLoss'), show: true, positioning: 0, data: [], unitType: unitTypes.percent, index: 3 },
{ name: this.$t('overall.packetRetrans'), show: true, positioning: 0, data: [], unitType: unitTypes.percent, index: 4 }
{ name: this.$t('networkAppPerformance.tcpConnectionEstablishLatency'), show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: this.$t('networkAppPerformance.httpResponse'), show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: this.$t('networkAppPerformance.sslResponseLatency'), show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: this.$t('networkAppPerformance.packetLoss'), show: true, positioning: 0, data: [], unitType: unitTypes.percent },
{ name: this.$t('overall.packetRetrans'), show: true, positioning: 0, data: [], unitType: unitTypes.percent }
]
} else {
this.initData(res.data.result, val)
}
res.data.result.forEach((t) => {
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) => {
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) => {
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) => {
e.show = i === 0
})
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) => {
e.show = i === 1
})
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) => {
e.show = i === 2
})
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) => {
e.show = i === 3
})
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) => {
e.show = i === 4
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(%)')
}
})
} else {
this.isNoData = false
this.showError = true
@@ -230,43 +308,66 @@ export default {
this.toggleLoading(false)
})
} else {
if (val === 'Bits/s' || val === 'Packets/s' || val === 'Sessions/s') {
this.toggleLoading(true)
const totalTrafficAnalysis = get(api.npm.overview.totalTrafficAnalysis, params)
const totalNetworkAnalysis = get(api.npm.overview.totalNetworkAnalysis, params)
const totalHttpResponseDelay = get(api.npm.overview.totalHttpResponseDelay, params)
const totalSslConDelay = get(api.npm.overview.totalSslConDelay, params)
const npmLineData = []
Promise.all([totalNetworkAnalysis, totalTrafficAnalysis, totalHttpResponseDelay, totalSslConDelay]).then(res => {
res.forEach(item => {
if (item.code === 200) {
npmLineData.push(...item.data.result)
get(api.npm.overview.totalTrafficAnalysis, params).then(res => {
if (res.code === 200) {
this.showError = false
this.isNoData = res.data.result.length === 0
if (this.isNoData) {
this.mpackets = [
{ name: 'network.total', show: true, positioning: 0, data: [], unitType: 'number' },
{ name: 'network.inbound', show: true, positioning: 1, data: [], unitType: 'number' },
{ name: 'network.outbound', show: true, positioning: 2, data: [], unitType: 'number' },
{ name: 'network.internal', show: true, positioning: 3, data: [], unitType: 'number' },
{ name: 'network.through', show: true, positioning: 4, data: [], unitType: 'number' },
{ name: 'network.other', show: true, positioning: 5, data: [], unitType: 'number' }
]
}
res.data.result.forEach((t) => {
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) => {
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) => {
e.show = true
})
this.mpackets = mpackets
this.echartsInit(this.mpackets)
} else if (t.type === 'sessions' && val === 'Sessions/s') {
const mpackets = _.cloneDeep(this.mpackets)
mpackets[0].data = t.totalSessionsRate.values ? t.totalSessionsRate.values : []
mpackets.forEach((e, i) => {
if (i !== 0) {
e.show = false
}
})
this.mpackets = mpackets
this.echartsInit(this.mpackets)
}
})
} else {
this.isNoData = false
this.showError = true
this.errorMsg = res.message
}
})
this.showError = false
this.isNoData = npmLineData.length === 0
if (this.isNoData) {
this.tabs = [
{ name: this.$t('network.total'), show: true, positioning: 0, data: [], unitType: 'number' },
{ name: this.$t('network.inbound'), show: true, positioning: 1, data: [], unitType: 'number' },
{ name: this.$t('network.outbound'), show: true, positioning: 2, data: [], unitType: 'number' },
{ name: this.$t('network.internal'), show: true, positioning: 3, data: [], unitType: 'number' },
{ name: this.$t('network.through'), show: true, positioning: 4, data: [], unitType: 'number' },
{ name: this.$t('network.other'), show: true, positioning: 5, data: [], unitType: 'number' }
]
this.npmQuantity = [
{ name: this.$t('networkAppPerformance.tcpConnectionEstablishLatency'), show: true, positioning: 0, data: [], unitType: unitTypes.time, index: 0 },
{ name: this.$t('networkAppPerformance.httpResponse'), show: true, positioning: 0, data: [], unitType: unitTypes.time, index: 1 },
{ name: this.$t('networkAppPerformance.sslResponseLatency'), show: true, positioning: 0, data: [], unitType: unitTypes.time, index: 2 },
{ name: this.$t('networkAppPerformance.packetLoss'), show: true, positioning: 0, data: [], unitType: unitTypes.percent, index: 3 },
{ name: this.$t('overall.packetRetrans'), show: true, positioning: 0, data: [], unitType: unitTypes.percent, index: 4 }
]
} else {
this.initData(npmLineData, val)
}
}).catch(e => {
this.isNoData = false
this.showError = true
@@ -274,6 +375,137 @@ export default {
}).finally(() => {
this.toggleLoading(false)
})
} else if (val === 'establishLatencyMs' || val === 'tcpLostlenPercent' || val === 'pktRetransPercent') {
this.toggleLoading(true)
get(api.npm.overview.totalNetworkAnalysis, params).then(res => {
if (res.code === 200) {
this.showError = false
this.isNoData = res.data.result.length === 0
if (this.isNoData) {
this.npmQuantity = [
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.httpResponse', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.sslResponseLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.packetLoss', show: true, positioning: 0, data: [], unitType: unitTypes.percent },
{ name: 'overall.packetRetrans', show: true, positioning: 0, data: [], unitType: unitTypes.percent }
]
}
res.data.result.forEach((t) => {
if (t.type === 'establishLatencyMs' && val === 'establishLatencyMs') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[0].data = t.establishLatencyMs.values ? t.establishLatencyMs.values : []
npmQuantity.forEach((e, i) => {
e.show = i === 0
})
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) => {
e.show = i === 3
})
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) => {
e.show = i === 4
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(%)')
}
})
} else {
this.isNoData = false
this.showError = true
this.errorMsg = res.message
}
}).catch(e => {
this.isNoData = false
this.showError = true
this.errorMsg = e.message
}).finally(() => {
this.toggleLoading(false)
})
} else if (val === 'httpResponseLatency') {
this.toggleLoading(true)
get(api.npm.overview.totalHttpResponseDelay, params).then(res => {
if (res.code === 200) {
this.showError = false
this.isNoData = res.data.result.length === 0
if (this.isNoData) {
this.npmQuantity = [
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.httpResponse', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.sslResponseLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.packetLoss', show: true, positioning: 0, data: [], unitType: unitTypes.percent },
{ name: 'overall.packetRetrans', show: true, positioning: 0, data: [], unitType: unitTypes.percent }
]
}
res.data.result.forEach(t => {
if (t.type === 'httpResponseLatency' && val === 'httpResponseLatency') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[1].data = t.httpResponseLatency.values ? t.httpResponseLatency.values : []
npmQuantity.forEach((e, i) => {
e.show = i === 1
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(ms)')
}
})
} else {
this.isNoData = false
this.showError = true
this.errorMsg = res.message
}
}).catch(e => {
this.isNoData = false
this.showError = true
this.errorMsg = e.message
}).finally(() => {
this.toggleLoading(false)
})
} else if (val === 'sslConLatency') {
this.toggleLoading(true)
get(api.npm.overview.totalSslConDelay, params).then(res => {
if (res.code === 200) {
this.showError = false
this.isNoData = res.data.result.length === 0
if (this.isNoData) {
this.npmQuantity = [
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.httpResponse', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.sslResponseLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
{ name: 'networkAppPerformance.packetLoss', show: true, positioning: 0, data: [], unitType: unitTypes.percent },
{ name: 'overall.packetRetrans', show: true, positioning: 0, data: [], unitType: unitTypes.percent }
]
}
res.data.result.forEach(t => {
if (t.type === 'sslConLatency' && val === 'sslConLatency') {
const npmQuantity = _.cloneDeep(this.npmQuantity)
npmQuantity[2].data = t.sslConLatency.values ? t.sslConLatency.values : []
npmQuantity.forEach((e, i) => {
e.show = i === 2
})
this.npmQuantity = npmQuantity
this.echartsInit(this.npmQuantity, '(ms)')
}
})
} else {
this.isNoData = false
this.showError = true
this.errorMsg = res.message
}
}).catch(e => {
this.isNoData = false
this.showError = true
this.errorMsg = e.message
}).finally(() => {
this.toggleLoading(false)
})
}
}
},
echartsInit (echartsData, legendUnit) {
@@ -301,7 +533,7 @@ export default {
color: chartColor3[t.positioning],
width: 1
},
stack: t.name !== 'network.total' ? 'network.total' : '',
stack: t.name !== this.$t('network.total') ? this.$t('network.total') : '',
areaStyle: {
opacity: 0.1,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
@@ -320,7 +552,7 @@ export default {
})
this.chartOption.tooltip.formatter = (params) => {
params.forEach(t => {
this.tabs.forEach(e => {
this.mpackets.forEach(e => {
if (e.name === t.seriesName) {
t.borderColor = chartColor3[e.positioning]
}
@@ -387,67 +619,6 @@ export default {
},
resize () {
this.myChart.resize()
},
initData (data, val) {
let lineData = []
if (data !== undefined && data.length > 0) {
data.forEach(item => {
item.type = getLineType(item.type)
if (item.type === val) {
lineData = Object.keys((item)).map(t => {
return {
...item[t],
index: getLineIndexUnit(item.type, false),
unit: getLineIndexUnit(item.type, true)
}
})
}
})
}
lineData.splice(0, 1)
const tabs = _.cloneDeep(this.tabs)
const npmQuantity = _.cloneDeep(this.npmQuantity)
if (val === 'Sessions/s') {
lineData.forEach((d, i) => {
tabs[i].data = d.values
tabs[i].analysis = d.analysis
})
tabs.forEach((e, i) => {
if (i !== 0) {
e.show = false
}
})
this.tabs = tabs
this.echartsInit(this.tabs)
} else if (val !== 'Bits/s' && val !== 'Packets/s' && val !== 'Sessions/s') {
this.legendInit(lineData, npmQuantity, true)
} else {
this.legendInit(lineData, tabs, false)
}
},
legendInit (data, npmData, show) {
data.forEach((d, i) => {
if (show) {
npmData[d.index].data = d.values
npmData[d.index].analysis = d.analysis
} else {
npmData[i].data = d.values
npmData[i].analysis = d.analysis
}
})
if (show) {
npmData.forEach((e, i) => {
e.show = i === data[0].index
})
this.npmQuantity = npmData
this.echartsInit(this.npmQuantity, data[0].unit)
} else {
npmData.forEach((e) => {
e.show = true
})
this.tabs = npmData
this.echartsInit(this.tabs)
}
}
},
mounted () {
@@ -462,9 +633,8 @@ export default {
beforeUnmount () {
clearTimeout(this.timer)
window.removeEventListener('resize', this.resize)
if (this.myChart) {
echarts.dispose(this.myChart)
}
this.myChart = null
this.myChart = null
this.unitConvert = null
}
}

View File

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

View File

@@ -134,7 +134,15 @@ export default {
}
},
mounted () {
this.initExpendTab()
if (this.$route.query.eventId) {
if (parseFloat(this.$route.query.eventId) === this.detection.eventId) {
const container = document.getElementById('cnContainer')
container.scrollTop = 555 + this.index * 97
this.isCollapse = false
this.$emit('switchCollapse', this.isCollapse, this.index)
}
}
},
computed: {
iconClass () {
@@ -178,7 +186,7 @@ export default {
this.$emit('switchCollapse', this.isCollapse, this.index)
if (this.isCollapse) {
const newQuery = this.$route.query
const newQuery = this.$route.query // 深拷贝路由数据
delete newQuery.eventId
this.reloadUrl(newQuery, 'cleanOldParams')
} else {
@@ -199,33 +207,6 @@ export default {
newUrl = urlParamsHandler(window.location.href, query, newParam, clean)
}
overwriteUrl(newUrl)
},
/**
* 初始化从npm跳转过来的id并展开tab
*/
initExpendTab () {
if (this.$route.query.eventId) {
if (this.$route.query.eventId === this.detection.eventId) {
const container = document.getElementById('cnContainer')
const dom = document.getElementsByClassName('cn-detection__case')
// 未展开的item折叠块高度67+下边距10+底部线高度1兼容不同分辨率下的tab高度
let itemHeight = 78
if (dom && this.index > 0) {
itemHeight = dom[0].clientHeight + 11
}
let topHeight = 554 + this.index * itemHeight
// 经过测试对比第7个以后的tab会往上移动但是手动展开和自动展开tab的滚动条高度一致为解决该问题自动加上误差值
if (this.index > 6) {
topHeight = topHeight + 6
}
container.scrollTop = topHeight
this.isCollapse = false
this.$emit('switchCollapse', this.isCollapse, this.index)
}
}
}
}
}

View File

@@ -842,7 +842,7 @@ export default {
setup () {
const { params } = useRoute()
const pageType = params.typeName
const dateRangeValue = 60 * 24
const dateRangeValue = 60
const { startTime, endTime } = getNowTime(dateRangeValue)
const timeFilter = ref({ startTime, endTime, dateRangeValue })

View File

@@ -61,7 +61,7 @@
<div class="metric__column">
<div class="overview__title">{{$t('detections.metric')}}</div>
<div class="overview__row">
<div class="row__content--metric ">{{getNameByEventType(detection.eventType) || '-'}}</div>
<div class="row__content--metric ">{{detection.eventType || '-'}}</div>
</div>
</div>
<div class="metric__column">
@@ -95,7 +95,7 @@ import { get } from '@/utils/http'
import * as echarts from 'echarts'
import { markRaw } from 'vue'
import { metricOption } from '@/views/detections/options/detectionOptions'
import { sortBy, reverseSortBy, getNameByEventType } from '@/utils/tools'
import { sortBy, reverseSortBy } from '@/utils/tools'
import _ from 'lodash'
export default {
name: 'DetectionPerformanceEventAppOverview',
@@ -134,7 +134,6 @@ export default {
}
},
methods: {
getNameByEventType,
query () {
this.queryBasic().then(responses => {
responses && (this.basicInfo = responses)
@@ -181,10 +180,6 @@ export default {
this.chartOptionMetric.series[2].data = this.metricList.slice(endIndex - 1, this.metricList.length).map(v => [Number(v[0]) * 1000, Number(v[1]), unitTypes.number])
}
this.chartOptionMetric.series.forEach(item => {
item.name = this.getNameByEventType(this.detection.eventType)
})
this.chartOptionMetric && this.metricChart.setOption(this.chartOptionMetric)
},

View File

@@ -63,7 +63,7 @@
<div class="metric__column">
<div class="overview__title">{{$t('detections.metric')}}</div>
<div class="overview__row">
<div class="row__content--metric ">{{getNameByEventType(detection.eventType) || '-'}}</div>
<div class="row__content--metric ">{{detection.eventType || '-'}}</div>
</div>
</div>
<div class="metric__column">
@@ -98,7 +98,7 @@ import { get } from '@/utils/http'
import * as echarts from 'echarts'
import { markRaw } from 'vue'
import { metricOption } from '@/views/detections/options/detectionOptions'
import { sortBy, reverseSortBy, getNameByEventType } from '@/utils/tools'
import { sortBy, reverseSortBy } from '@/utils/tools'
import _ from 'lodash'
export default {
name: 'DetectionPerformanceEventDomainOverview',
@@ -165,7 +165,6 @@ export default {
}
},
methods: {
getNameByEventType,
query () {
this.queryBasic().then(responses => {
responses && (this.basicInfo = responses)
@@ -213,10 +212,6 @@ export default {
this.chartOptionMetric.series[2].data = this.metricList.slice(endIndex - 1, this.metricList.length).map(v => [Number(v[0]) * 1000, Number(v[1]), unitTypes.number])
}
this.chartOptionMetric.series.forEach(item => {
item.name = this.getNameByEventType(this.detection.eventType)
})
this.chartOptionMetric && this.metricChart.setOption(this.chartOptionMetric)
},

View File

@@ -54,7 +54,7 @@
<div class="metric__column">
<div class="overview__title">{{$t('detections.metric')}}</div>
<div class="overview__row">
<div class="row__content--metric ">{{getNameByEventType(detection.eventType) || '-'}}</div>
<div class="row__content--metric ">{{getNameByType(detection.eventType) || '-'}}</div>
</div>
</div>
<div class="metric__column">
@@ -88,7 +88,7 @@ import { get } from '@/utils/http'
import * as echarts from 'echarts'
import { markRaw } from 'vue'
import { metricOption } from '@/views/detections/options/detectionOptions'
import { sortBy, reverseSortBy, getNameByEventType } from '@/utils/tools'
import { sortBy, reverseSortBy } from '@/utils/tools'
import _ from 'lodash'
export default {
@@ -129,7 +129,6 @@ export default {
}
},
methods: {
getNameByEventType,
query () {
this.queryBasic().then(responses => {
responses && (this.basicInfo = responses)
@@ -174,11 +173,9 @@ export default {
this.chartOptionMetric.series[1].data = this.metricList.slice(startIndex - 1, endIndex).map(v => [Number(v[0]) * 1000, Number(v[1]), unitTypes.number])
this.chartOptionMetric.series[2].data = this.metricList.slice(endIndex - 1, this.metricList.length).map(v => [Number(v[0]) * 1000, Number(v[1]), unitTypes.number])
}
this.chartOptionMetric.series.forEach(item => {
item.name = this.getNameByEventType(this.detection.eventType)
item.name = this.getNameByType(this.detection.eventType)
})
this.chartOptionMetric && this.metricChart.setOption(this.chartOptionMetric)
},
queryMetric () {
@@ -239,6 +236,29 @@ export default {
}
})
window.open(href, '_blank')
},
/**
* 通过事件类型转换对应名称
* @param type
* @returns {string}
*/
getNameByType (type) {
switch (type) {
case 'http error': {
return 'http error ratio'
}
case 'dns error': {
return 'dns error ratio'
}
case 'high dns response time': {
return 'dns response time'
}
// 目前ui并未找到此类型添加以防不测
case 'high http resopnse time':
default: {
return 'http response time'
}
}
}
},
mounted () {

View File

@@ -324,8 +324,8 @@ export default {
getMillisecond,
query () {
Promise.all([this.queryBasic(), this.queryEvent()]).then((responses) => {
responses[0].malwareTechniques = responses[0].malwareTechniques.length > 2 ? responses[0].malwareTechniques.replace('[', '').replace(']', '').split(',', 5).join(', ') : ''
responses[0].malwareGroups = responses[0].malwareGroups.length > 2 ? responses[0].malwareGroups.replace('[', '').replace(']', '').split(',', 5).join(', ') : ''
responses[0].malwareTechniques = responses[0].malwareTechniques.length > 2 ? responses[0].malwareTechniques.replace('[', '').split(',', 5).join(', ') : ''
responses[0].malwareGroups = responses[0].malwareGroups.length > 2 ? responses[0].malwareGroups.replace('[', '').split(',', 5).join(', ') : ''
responses[0].malwarePlatforms = responses[0].malwarePlatforms.length > 1 ? responses[0].malwarePlatforms : ''
responses[0].malwareDescription = responses[0].malwareDescription.length > 1 ? responses[0].malwareDescription : ''
responses[0] && (this.basicInfo = responses[0])

View File

@@ -129,6 +129,16 @@ export default {
beforeUnmount () {
window.removeEventListener('resize', this.debounceFunc)
},
watch: {
top (n) {
const findIndex = this.anchorPoints.findLastIndex(a => a.top < n + 100)
if (findIndex > -1) {
this.anchorPoints.forEach((a, i) => {
a.isActive = i === findIndex
})
}
}
},
computed: {
iconClass () {
let className

View File

@@ -717,7 +717,7 @@ export default {
}
},
setup () {
const dateRangeValue = 60 * 24
const dateRangeValue = 60
const { startTime, endTime } = getNowTime(dateRangeValue)
const timeFilter = ref({ startTime, endTime, dateRangeValue })
return {

View File

@@ -22,14 +22,6 @@
<div class="row__label row__label--width130">{{$t('entities.org')}}</div>
<div class="row__content">{{entityData.domainWhoisOrg || '-'}}</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.icpCompanyName')}}</div>
<div class="row__content">{{entityData.domainIcpCompanyName || '-'}}</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.icpLicense')}}</div>
<div class="row__content">{{entityData.domainIcpSiteLicense || '-'}}</div>
</div>
<!-- <div class="overview__row">
<div class="row__label row__label&#45;&#45;width130">{{$t('overall.remark')}}</div>
<div class="row__content">{{entityData.domainDescription || '-'}}</div>
@@ -360,9 +352,7 @@ export default {
domainDescription: response.data.result.domainDescription,
domainReputationScore: response.data.result.domainReputationScore,
domainWhoisAddress: response.data.result.domainWhoisAddress,
domainWhoisOrg: response.data.result.domainWhoisOrg,
domainIcpCompanyName: response.data.result.domainIcpCompanyName,
domainIcpSiteLicense: response.data.result.domainIcpSiteLicense
domainWhoisOrg: response.data.result.domainWhoisOrg
}
}
})

View File

@@ -1,215 +1,34 @@
/**
* jest: https://jestjs.io/docs/getting-started
* vue-jest: https://test-utils.vuejs.org/guide/
* */
import Test from '../src/Test'
import { mount } from '@vue/test-utils'
import { getNameByEventType } from '@/utils/tools'
import axios from 'axios'
import indexedDBUtils from '@/indexedDB'
import ElementPlus from 'element-plus'
// 模拟的axios返回数据
const mockId = { data: 2 }
const mockTitle = { data: 'title2' }
const mockCount = { data: 999 }
const mockDifferentParam0 = { data: 0 }
const mockDifferentParam1 = { data: 1 }
const mergeRequestParam0 = { data: 0 }
const mergeRequestParam1 = { data: 1 }
const mergeRequestChildParam0 = { data: 0 }
const mergeRequestChildParam1 = { data: 1 }
describe('单元测试demo', () => {
test('Vue组件--点击按钮后count的值+1', async () => {
// 若组件中使用了vue-router需要细化模拟相关内容
require('vue-router').useRoute.mockReturnValue({ query: {} })
require('vue-router').useRouter.mockReturnValue({ currentRoute: { value: { path: '/' } } })
// 加载vue组件获得实例
const wrapper = mount(Test, {
global: {
plugins: [ElementPlus]
// 模拟vue-router库否则组件中引用vue-router的代码报错
jest.mock('vue-router', () => {
return {
useRouter: function () { return { currentRoute: '/' } }
}
})
})
test('点击按钮后count的值+1', async () => {
// 加载vue组件获得实例
const wrapper = mount(Test)
// 取到文本和按钮的dom
const textNode = await wrapper.get('[test-id="count"]')
const button = await wrapper.get('[test-id="button"]')
const textNode = await wrapper.get('[data-test="count"]')
const button = await wrapper.get('[data-test="button"]')
// 断言文本dom的内容是否是'0'
expect(textNode.text()).toBe('0')
expect(textNode.text()).toContain('0')
// 模拟按钮dom点击执行click()方法
await button.trigger('click')
// 断言点击按钮后文本dom的内容是否是'1'
expect(textNode.text()).toBe('1')
expect(textNode.text()).toContain('1')
// 再次点击
await button.trigger('click')
// 断言点击按钮后文本dom的内容是否是'2'
expect(textNode.text()).toBe('2')
/* 更多断言类型https://jestjs.io/docs/expect */
})
test('Vue组件--获取路由中的参数', async () => {
// query中带上lineTab参数
require('vue-router').useRoute.mockReturnValue({ query: { lineTab: 'total' } })
require('vue-router').useRouter.mockReturnValue({ currentRoute: { value: { path: '/' } } })
// 加载vue组件获得实例
const wrapper = mount(Test, {
global: {
plugins: [ElementPlus]
}
})
// 取到文本和按钮的dom
const textNode = await wrapper.get('[test-id="tab"]')
expect(textNode.text()).toBe('total')
})
test('Vue组件--模拟获取localstorage/sessionStorage的内容', async () => {
require('vue-router').useRoute.mockReturnValue({ query: {} })
require('vue-router').useRouter.mockReturnValue({ currentRoute: { value: { path: '/' } } })
// 模拟localStorage的getItem
jest.spyOn(localStorage.__proto__, 'getItem').mockImplementation(key => key)
// 加载vue组件获得实例
const wrapper = mount(Test, {
global: {
plugins: [ElementPlus]
}
})
expect(wrapper.vm.localstorageValue).toBe('key')
})
test('Vue组件--直接获取vue实例中的data和method', async () => {
require('vue-router').useRoute.mockReturnValue({ query: {} })
require('vue-router').useRouter.mockReturnValue({ currentRoute: { value: { path: '/' } } })
// 模拟axios返回数据
// 测试内容只有一个axios请求的时候
axios.get.mockResolvedValue(mockCount)
// 加载vue组件获得实例
const wrapper = mount(Test, {
global: {
mocks: {
$t: key => key
},
plugins: [ElementPlus]
}
})
const textNode = await wrapper.get('[test-id="count"]')
expect(textNode.text()).toContain('2')
// 通过wrapper.vm.xxx直接执行click方法、获取data的数据
expect(wrapper.vm.count).toBe(0)
expect(wrapper.vm.count).toEqual(2)
await wrapper.vm.click()
expect(wrapper.vm.count).toBe(1)
await wrapper.vm.getCount()
await wrapper.vm.$nextTick(() => {
expect(textNode.text()).toBe('999')
})
})
test('Vue组件--多个axios请求', async () => {
require('vue-router').useRoute.mockReturnValue({ query: {} })
require('vue-router').useRouter.mockReturnValue({ currentRoute: { value: { path: '/' } } })
// 模拟axios返回数据
// 测试内容有多个url不同的axios请求的话需分开写
axios.get.mockImplementation(url => {
switch (url) {
case '/api/getObjId':
return Promise.resolve(mockId)
case '/api/getObjTitle':
return Promise.resolve(mockTitle)
}
})
// 加载vue组件获得实例
const wrapper = mount(Test, {
global: {
plugins: [ElementPlus]
}
})
const textNode = await wrapper.get('[test-id="id"]')
const textNode2 = await wrapper.get('[test-id="title"]')
expect(textNode2.text()).toBe('title')
await wrapper.vm.getObj()
await wrapper.vm.$nextTick(() => {
expect(textNode.text()).toBe('2')
expect(textNode2.text()).toBe('title2')
// 匹配整个对象
expect(wrapper.vm.obj).toEqual({ id: 2, title: 'title2' })
})
})
test('Vue组件--多个同url不同参数的axios请求', async () => {
require('vue-router').useRoute.mockReturnValue({ query: {} })
require('vue-router').useRouter.mockReturnValue({ currentRoute: { value: { path: '/' } } })
// 模拟axios返回数据
axios.get.mockResolvedValueOnce(mockDifferentParam0)
axios.get.mockResolvedValueOnce(mockDifferentParam1)
// 加载vue组件获得实例
const wrapper = mount(Test, {
global: {
plugins: [ElementPlus]
}
})
await wrapper.vm.differentRequestParam()
expect(wrapper.vm.differentParamData0).toBe(0)
expect(wrapper.vm.differentParamData1).toBe(1)
})
test('Vue组件--axios请求内包含多个不同url的组合请求', async () => {
require('vue-router').useRoute.mockReturnValue({ query: {} })
require('vue-router').useRouter.mockReturnValue({ currentRoute: { value: { path: '/' } } })
// 模拟axios返回数据
axios.get.mockResolvedValueOnce(mergeRequestParam0)
axios.get.mockResolvedValueOnce(mergeRequestParam1)
expect(wrapper.vm.count).toEqual(3)
axios.get.mockImplementation(url => {
switch (url) {
case '/api/getChildId':
return Promise.resolve(mergeRequestChildParam0)
case '/api/getChildTitle':
return Promise.resolve(mergeRequestChildParam1)
}
})
// 加载vue组件获得实例
const wrapper = mount(Test, {
global: {
plugins: [ElementPlus]
}
})
await wrapper.vm.mergeRequest()
await wrapper.vm.$nextTick(() => {
expect(wrapper.vm.mergeRequestData0).toBe(0)
expect(wrapper.vm.mergeRequestData1).toBe(1)
expect(wrapper.vm.mergeRequestChildData0).toBe(0)
expect(wrapper.vm.mergeRequestChildData1).toBe(1)
})
})
test('Vue组件--模拟indexedDB操作', async () => {
require('vue-router').useRoute.mockReturnValue({ query: {} })
require('vue-router').useRouter.mockReturnValue({ currentRoute: { value: { path: '/' } } })
// 加载vue组件获得实例
const wrapper = mount(Test, {
global: {
plugins: [ElementPlus]
}
})
// 模拟indexedDB的内容
indexedDBUtils.selectTable.mockReturnValue({
put: jest.fn(),
get: jest.fn().mockResolvedValue({ a: 1 })
})
await wrapper.vm.setIndexedDBValue()
await wrapper.vm.getIndexedDBValue()
expect(wrapper.vm.indexedDBValue).toEqual({ a: 1 })
})
test('Vue组件--使用第三方组件的情况以el-table为例', async () => {
require('vue-router').useRoute.mockReturnValue({ query: {} })
require('vue-router').useRouter.mockReturnValue({ currentRoute: { value: { path: '/' } } })
// 加载vue组件获得实例
const wrapper = mount(Test, {
global: {
plugins: [ElementPlus]
}
})
// 执行nextTick等待el-table渲染完成
await wrapper.vm.$nextTick()
const textNode = await wrapper.get('[test-id="name0"]')
const textNode2 = await wrapper.get('[test-id="age1"]')
expect(textNode.text()).toBe('a')
expect(textNode2.text()).toBe('11')
})
test('js方法--getNameByEventType', async () => {
expect(getNameByEventType('http error')).toBe('http error ratio')
})
// 更多断言类型https://jestjs.io/zh-Hans/docs/expect
})

View File

@@ -1,41 +0,0 @@
import { config } from '@vue/test-utils'
/* 开启测试 */
config.global.mocks.isUnitTesting = true
/* 初始化dayjs */
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
// 引入 lodash 工具 模拟 lodash
const _ = require('lodash') // lodash工具
/* 模拟vue-router库否则组件中引用vue-router的代码报错 */
jest.mock('vue-router', () => {
return {
useRouter: jest.fn(),
useRoute: jest.fn(),
createWebHashHistory: jest.fn(),
createRouter: jest.fn().mockReturnValue({
beforeEach: jest.fn()
})
}
})
/* 模拟axios */
jest.mock('axios')
/* 模拟indexedDB工具 */
jest.mock('@/indexedDB')
/* 模拟$t */
config.global.mocks.$t = key => key
/* 模拟$route具体用例中需要不同值时重写覆盖即可 */
config.global.mocks.$route = { query: '' }
/* 模拟 lodash */
config.global.mocks.$_ = _
/* 消除warn */
jest.spyOn(console, 'warn').mockImplementation(() => {})

View File

@@ -1,130 +0,0 @@
import linkBlock from '@/views/charts2/charts/linkMonitor/LinkBlock'
import { mount } from '@vue/test-utils'
import axios from 'axios'
const mockGet1 = {
data: { status: 200, code: 200, queryKey: '549b4c3bcabf0feee193b834671879de', success: true, message: null, statistics: { elapsed: 3, rows_read: 11480, bytes_read: 459200, result_size: 1214, result_rows: 21 }, job: null, formatType: 'json', meta: [{ name: 'link_id', type: 'string', category: 'Dimension' }, { name: 'egress_bytes', type: 'long', category: 'Metric' }, { name: 'ingress_bytes', type: 'long', category: 'Metric' }], data: { resultType: 'table', result: [{ linkId: '257', egressBytes: '0', egressBitsRate: 0, ingressBytes: '493739879', ingressBitsRate: 1097199.76 }, { linkId: '256', egressBytes: '4147998874', egressBitsRate: 9217775.28, ingressBytes: '0', ingressBitsRate: 0 }, { linkId: '1024', egressBytes: '4229808296', egressBitsRate: 9399574, ingressBytes: '0', ingressBitsRate: 0 }, { linkId: '1793', egressBytes: '0', egressBitsRate: 0, ingressBytes: '604840505', ingressBitsRate: 1344090 }, { linkId: '2817', egressBytes: '0', egressBitsRate: 0, ingressBytes: '430811638', ingressBitsRate: 957359.2 }, { linkId: '0', egressBytes: '819878366014', egressBitsRate: 1821951924.48, ingressBytes: '140774357362', ingressBitsRate: 312831905.28 }, { linkId: '1281', egressBytes: '0', egressBitsRate: 0, ingressBytes: '544675122', ingressBitsRate: 1210389.12 }, { linkId: '2049', egressBytes: '0', egressBitsRate: 0, ingressBytes: '711346274', ingressBitsRate: 1580769.52 }, { linkId: '1536', egressBytes: '4195896971', egressBitsRate: 9324215.52, ingressBytes: '0', ingressBitsRate: 0 }, { linkId: '2305', egressBytes: '0', egressBitsRate: 0, ingressBytes: '524865003', ingressBitsRate: 1166366.64 }, { linkId: '1792', egressBytes: '4145790227', egressBitsRate: 9212867.2, ingressBytes: '0', ingressBitsRate: 0 }, { linkId: '1025', egressBytes: '0', egressBitsRate: 0, ingressBytes: '492227445', ingressBitsRate: 1093838.8 }, { linkId: '2816', egressBytes: '4000074817', egressBitsRate: 8889055.12, ingressBytes: '0', ingressBitsRate: 0 }, { linkId: '513', egressBytes: '0', egressBitsRate: 0, ingressBytes: '1444814826', ingressBitsRate: 3210699.6 }, { linkId: '768', egressBytes: '4370006099', egressBitsRate: 9711124.64, ingressBytes: '0', ingressBitsRate: 0 }, { linkId: '512', egressBytes: '3894190397', egressBitsRate: 8653756.4, ingressBytes: '0', ingressBitsRate: 0 }, { linkId: '769', egressBytes: '0', egressBitsRate: 0, ingressBytes: '1877580759', ingressBitsRate: 4172401.68 }, { linkId: '2304', egressBytes: '3767761711', egressBitsRate: 8372803.84, ingressBytes: '0', ingressBitsRate: 0 }, { linkId: '1537', egressBytes: '0', egressBitsRate: 0, ingressBytes: '367986916', ingressBitsRate: 817748.72 }, { linkId: '1280', egressBytes: '4040444894', egressBitsRate: 8978766.4, ingressBytes: '0', ingressBitsRate: 0 }, { linkId: '2048', egressBytes: '4682050724', egressBitsRate: 10404557.2, ingressBytes: '0', ingressBitsRate: 0 }] }, originalUrl: 'http://192.168.44.55:9999?query=SELECT%20arrayJoin%28splitByChar%28%27_%27%2C%20concat%28toString%28common_egress_link_id%29%2C%20%27_%27%2C%20toString%28common_ingress_link_id%29%29%29%29%20AS%20link_id%2CSUM%28IF%28toString%28common_egress_link_id%29%20%3D%20link_id%2C%20traffic_outbound_byte%2C%200%29%29%20AS%20egress_bytes%2CSUM%28IF%28toString%28common_ingress_link_id%29%20%3D%20link_id%2C%20traffic_inbound_byte%2C%200%29%29%20AS%20ingress_bytes%20FROM%20metric_link%20WHERE%20stat_time%20%3E%3D%201675303793%20AND%20stat_time%20%3C%201675307393%20GROUP%20BY%20link_id&format=json&option=real-time', msg: 'OK' }
}
const mockGet2 = {
data: { status: 200, code: 200, queryKey: 'ee2e820b1275748167cdee82b2b4ea40', success: true, message: null, statistics: { elapsed: 3, rows_read: 11480, bytes_read: 618564, result_size: 1053, result_rows: 10 }, job: null, formatType: 'json', meta: [{ name: 'egress_link_direction', type: 'string', category: 'Dimension' }, { name: 'ingress_link_direction', type: 'string', category: 'Dimension' }, { name: 'egress_bytes', type: 'long', category: 'Metric' }, { name: 'ingress_bytes', type: 'long', category: 'Metric' }], data: { resultType: 'table', result: [{ egressLinkDirection: '太原', ingressLinkDirection: '西宁', egressBytes: '2407509269', egressBitsRate: 5350020.56, ingressBytes: '193368911', ingressBitsRate: 429708.72 }, { egressLinkDirection: '西安', ingressLinkDirection: '西安', egressBytes: '3609358392', egressBitsRate: 8020796.4, ingressBytes: '345009143', ingressBitsRate: 766686.96 }, { egressLinkDirection: '西宁', ingressLinkDirection: '西安', egressBytes: '1273508499', egressBitsRate: 2830018.88, ingressBytes: '122646511', ingressBitsRate: 272547.84 }, { egressLinkDirection: '太原', ingressLinkDirection: '太原', egressBytes: '14840136119', egressBitsRate: 32978080.24, ingressBytes: '3386427658', ingressBitsRate: 7525394.8 }, { egressLinkDirection: '西安', ingressLinkDirection: '太原', egressBytes: '7070361369', egressBitsRate: 15711914.16, ingressBytes: '1853445429', ingressBitsRate: 4118767.6 }, { egressLinkDirection: '西宁', ingressLinkDirection: '太原', egressBytes: '2619231460', egressBitsRate: 5820514.32, ingressBytes: '291561196', ingressBitsRate: 647913.76 }, { egressLinkDirection: '', ingressLinkDirection: '', egressBytes: '409939183007', egressBitsRate: 910975962.24, ingressBytes: '70387178681', ingressBitsRate: 156415952.64 }, { egressLinkDirection: '太原', ingressLinkDirection: '西安', egressBytes: '7808050741', egressBitsRate: 17351223.84, ingressBytes: '1001570985', ingressBitsRate: 2225713.28 }, { egressLinkDirection: '西宁', ingressLinkDirection: '西宁', egressBytes: '337068337', egressBitsRate: 749040.72, ingressBytes: '165230290', ingressBitsRate: 367178.4 }, { egressLinkDirection: '西安', ingressLinkDirection: '西宁', egressBytes: '1508798824', egressBitsRate: 3352886.24, ingressBytes: '133628244', ingressBitsRate: 296951.68 }] }, originalUrl: 'http://192.168.44.55:9999?query=SELECT%20egress_link_direction%20AS%20egress_link_direction%2C%20ingress_link_direction%20AS%20ingress_link_direction%2C%20SUM%28traffic_outbound_byte%29%20AS%20egress_bytes%2C%20SUM%28traffic_inbound_byte%29%20AS%20ingress_bytes%20FROM%20metric_link%20WHERE%20stat_time%20%3E%3D%201675303793%20AND%20stat_time%20%3C%201675307393%20GROUP%20BY%20egress_link_direction%2C%20ingress_link_direction&format=json&option=real-time', msg: 'OK' }
}
const linkInfoData = [{ originalLinkId: '256', linkId: 'Hundredgige1', direction: 'egress', nextHop: '西安', bandwidth: 100000000000 }, { originalLinkId: '257', linkId: 'Hundredgige1', direction: 'ingress', nextHop: '西安', bandwidth: 100000000000 }, { originalLinkId: '512', linkId: 'Hundredgige2', direction: 'egress', nextHop: '太原', bandwidth: 100000000000 }, { originalLinkId: '513', linkId: 'Hundredgige2', direction: 'ingress', nextHop: '太原', bandwidth: 100000000000 }, { originalLinkId: '768', linkId: 'Hundredgige3', direction: 'egress', nextHop: '太原', bandwidth: 100000000000 }, { originalLinkId: '769', linkId: 'Hundredgige3', direction: 'ingress', nextHop: '太原', bandwidth: 100000000000 }, { originalLinkId: '1024', linkId: 'Hundredgige4', direction: 'egress', nextHop: '西宁', bandwidth: 100000000000 }, { originalLinkId: '1025', linkId: 'Hundredgige4', direction: 'ingress', nextHop: '西宁', bandwidth: 100000000000 }, { originalLinkId: '1280', linkId: 'Hundredgige5', direction: 'egress', nextHop: '西安', bandwidth: 100000000000 }, { originalLinkId: '1281', linkId: 'Hundredgige5', direction: 'ingress', nextHop: '西安', bandwidth: 100000000000 }, { originalLinkId: '1536', linkId: 'Hundredgige6', direction: 'egress', nextHop: '太原', bandwidth: 100000000000 }, { originalLinkId: '1537', linkId: 'Hundredgige6', direction: 'ingress', nextHop: '太原', bandwidth: 100000000000 }, { originalLinkId: '1792', linkId: 'Hundredgige7', direction: 'egress', nextHop: '太原', bandwidth: 100000000000 }, { originalLinkId: '1793', linkId: 'Hundredgige7', direction: 'ingress', nextHop: '太原', bandwidth: 100000000000 }, { originalLinkId: '2048', linkId: 'Hundredgige8', direction: 'egress', nextHop: '太原', bandwidth: 100000000000 }, { originalLinkId: '2049', linkId: 'Hundredgige8', direction: 'ingress', nextHop: '太原', bandwidth: 100000000000 }, { originalLinkId: '2304', linkId: 'Hundredgige9', direction: 'egress', nextHop: '太原', bandwidth: 100000000000 }, { originalLinkId: '2305', linkId: 'Hundredgige9', direction: 'ingress', nextHop: '太原', bandwidth: 100000000000 }, { originalLinkId: '2816', linkId: 'Hundredgige10', direction: 'egress', nextHop: '西安', bandwidth: 100000000000 }, { originalLinkId: '2817', linkId: 'Hundredgige10', direction: 'ingress', nextHop: '西安', bandwidth: 100000000000 }]
const linkInfo = JSON.stringify(linkInfoData)
const timeFilter = {
dateRangeValue: -1,
startTime: 1673244000000,
endTime: 1673247600000
}
var wrapper = null
/**
* 进行axios请求并挂载vue实例
* @param list
*/
function axiosPostAndMounted (list) {
require('vue-router').useRoute.mockReturnValue({ query: {} })
const data = list || mockGet1
// 模拟axios返回数据
axios.get.mockImplementation(url => {
switch (url) {
case '/interface/link/overview/analysis':
return Promise.resolve(data)
case '/interface/link/overview/nextHopAnalysis':
return Promise.resolve(mockGet2)
}
})
// 模拟localStorage获取数据
// eslint-disable-next-line no-proto
jest.spyOn(localStorage.__proto__, 'getItem').mockImplementation(key => linkInfo)
// 加载vue组件获得实例
wrapper = mount(linkBlock, {
propsData: {
timeFilter
}
})
}
describe('views/charts2/charts/linkMonitor/LinkBlock.vue测试', () => {
test('测试链路蜂窝图和下一跳蜂窝图从大到小排列', async () => {
axiosPostAndMounted()
// 延迟等待渲染。使用wrapper.vm.$nextTick有时不管用例如组件中使用了setTimeout的时候
await new Promise(resolve => setTimeout(() => {
const linkBlockTotal0 = wrapper.get('[test-id="linkBlockTotal0"]')
const linkBlockTotal1 = wrapper.get('[test-id="linkBlockTotal1"]')
const linkBlockTotal2 = wrapper.get('[test-id="linkBlockTotal2"]')
const linkBlockTotal3 = wrapper.get('[test-id="linkBlockTotal3"]')
const linkBlockTotal4 = wrapper.get('[test-id="linkBlockTotal4"]')
const linkBlockTotal5 = wrapper.get('[test-id="linkBlockTotal5"]')
const linkBlockTotal6 = wrapper.get('[test-id="linkBlockTotal6"]')
const linkBlockTotal7 = wrapper.get('[test-id="linkBlockTotal7"]')
const linkBlockTotal8 = wrapper.get('[test-id="linkBlockTotal8"]')
const linkBlockTotal9 = wrapper.get('[test-id="linkBlockTotal9"]')
expect(linkBlockTotal0.text()).toBe('13.88 Mbps')
expect(linkBlockTotal1.text()).toBe('11.99 Mbps')
expect(linkBlockTotal2.text()).toBe('11.86 Mbps')
expect(linkBlockTotal3.text()).toBe('10.56 Mbps')
expect(linkBlockTotal4.text()).toBe('10.49 Mbps')
expect(linkBlockTotal5.text()).toBe('10.31 Mbps')
expect(linkBlockTotal6.text()).toBe('10.19 Mbps')
expect(linkBlockTotal7.text()).toBe('10.14 Mbps')
expect(linkBlockTotal8.text()).toBe('9.85 Mbps')
expect(linkBlockTotal9.text()).toBe('9.54 Mbps')
const nextHopTotal0 = wrapper.get('[test-id="nextHopTotal0"]')
const nextHopTotal1 = wrapper.get('[test-id="nextHopTotal1"]')
const nextHopTotal2 = wrapper.get('[test-id="nextHopTotal2"]')
expect(nextHopTotal0.text()).toBe('67.97 Mbps')
expect(nextHopTotal1.text()).toBe('30.35 Mbps')
expect(nextHopTotal2.text()).toBe('10.49 Mbps')
resolve()
}, 200))
})
test('鼠标移动到链路蜂窝图第一个测试total显示', async () => {
// 以"Hundredgige3"为例对应出方向linkId为768对应出方向流量为9711124.64
// 对应入方向linkId为769对应入方向流量为4172401.68修改流量测试total
const list = JSON.parse(JSON.stringify(mockGet1))
list.data.data.result[14].egressBitsRate = 9000000.00
list.data.data.result[16].ingressBitsRate = 4000000.00
axiosPostAndMounted(list)
// 延迟等待渲染。使用wrapper.vm.$nextTick有时不管用例如组件中使用了setTimeout的时候
await new Promise(resolve => setTimeout(() => {
const linkBlockTotal0 = wrapper.get('[test-id="linkBlockTotal0"]')
const linkBlockEgressUsage0 = wrapper.get('[test-id="linkBlockEgressUsage0"]')
const linkBlockIngressUsage0 = wrapper.get('[test-id="linkBlockIngressUsage0"]')
expect(linkBlockTotal0.text()).toBe('13 Mbps')
expect(linkBlockEgressUsage0.text()).toBe('< 0.01%')
expect(linkBlockIngressUsage0.text()).toBe('< 0.01%')
resolve()
}, 200))
})
test('鼠标移动到链路蜂窝图第一个,测试出入流量占比', async () => {
// 以"Hundredgige3"为例修改其出入流量为100000000000测试上行流量占比为100%下行占比为0%的情况
const list = JSON.parse(JSON.stringify(mockGet1))
list.data.data.result[14].egressBitsRate = 100000000000.00
list.data.data.result[16].ingressBitsRate = 0
axiosPostAndMounted(list)
// 延迟等待渲染。使用wrapper.vm.$nextTick有时不管用例如组件中使用了setTimeout的时候
await new Promise(resolve => setTimeout(() => {
const linkBlockTotal0 = wrapper.get('[test-id="linkBlockTotal0"]')
const linkBlockEgressUsage0 = wrapper.get('[test-id="linkBlockEgressUsage0"]')
const linkBlockIngressUsage0 = wrapper.get('[test-id="linkBlockIngressUsage0"]')
expect(linkBlockTotal0.text()).toBe('100 Gbps')
expect(linkBlockEgressUsage0.text()).toBe('100.00%')
expect(linkBlockIngressUsage0.text()).toBe('0%')
resolve()
}, 200))
})
})

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,37 +0,0 @@
import NetworkOverviewDdosDetection from '@/views/charts2/charts/networkOverview/NetworkOverviewDdosDetection'
import { mount } from '@vue/test-utils'
import axios from 'axios'
const mockGet = {
data: { status: 200, code: 200, queryKey: 'dec6723e173e8fa2b00917dc597bfb27', success: true, message: null, statistics: { elapsed: 0, rows_read: 2, result_size: 58, result_rows: 1 }, job: null, formatType: 'json', meta: [{ name: 'attack_event_count', type: 'long', category: 'Metric' }, { name: 'attacker_count', type: 'long', category: 'Metric' }, { name: 'victim_count', type: 'long', category: 'Metric' }], data: { resultType: 'object', result: [{ attackEventCount: 1200000, attackerCount: 2687878, victimCount: 36676767 }] }, originalUrl: 'http://192.168.44.55:9999?query=SELECT%20COUNT%28*%29%20AS%20attack_event_count%2C%20COUNT%28DISTINCT%28offender_ip%29%29%20AS%20attacker_count%2C%20COUNT%28DISTINCT%28victim_ip%29%29%20AS%20victim_count%20FROM%20security_event%20WHERE%20start_time%20%3E%3D%201675043912%20AND%20start_time%20%3C%201675047512%20AND%20security_type%20%3D%20%27ddos%27&format=json&option=real-time', msg: 'OK' }
}
const timeFilter = {
dateRangeValue: -1,
startTime: 1675043912,
endTime: 1675047512
}
describe('views/charts2/charts/networkOverview/NetworkOverviewDdosDetection.vue测试', () => {
test('攻击、受害、攻击数事件ddos检测图', async () => {
require('vue-router').useRoute.mockReturnValue({ query: {} })
// 模拟 axios 返回数据
axios.get.mockResolvedValue(mockGet)
// 加载vue组件获得实例
const wrapper = mount(NetworkOverviewDdosDetection, {
propsData: {
timeFilter
}
})
const attackEventCount = wrapper.get('[test-id="attackEventCount"]')
const attackerCount = wrapper.get('[test-id="attackerCount"]')
const victimCount = wrapper.get('[test-id="victimCount"]')
await new Promise(resolve => setTimeout(() => {
expect(attackEventCount.text()).toEqual('1.20 M')
expect(attackerCount.text()).toEqual('2.69 M')
expect(victimCount.text()).toEqual('36.68 M')
resolve()
}, 200))
})
})

View File

@@ -1,141 +0,0 @@
import NetworkOverviewLine from '@/views/charts2/charts/networkOverview/NetworkOverviewLine'
import { mount } from '@vue/test-utils'
import axios from 'axios'
import mockData from './NetworkOverviewLineMockData'
const timeFilter = {
dateRangeValue: -1,
startTime: 1673244000000,
endTime: 1673247600000
}
const chart = {"id":1,"name":"network overview line","i18n":"","panelId":1,"pid":0,"type":102,"x":0,"y":0,"w":19,"h":6,"children":[],"panel":{"id":1,"name":"Network Overview"},"i":1,"category":"echarts","firstShow":false,"moved":false}
function init () {
require('vue-router').useRoute.mockReturnValue({ query: {} })
}
describe('views/charts2/charts/networkOverview/NetworkOverviewLine.vue测试', () => {
test('Metric=Bits/s无数据空数组', async () => {
init()
axios.get.mockResolvedValue(mockData.empty)
const wrapper = mount(NetworkOverviewLine, {
propsData: {
timeFilter,
chart
}
})
// 延迟等待渲染。使用wrapper.vm.$nextTick有时不管用例如组件中使用了setTimeout的时候
await new Promise(resolve => setTimeout(async () => {
const textNode0 = await wrapper.get('[test-id="tabContent0"]')
const textNode1 = await wrapper.get('[test-id="tabContent1"]')
const textNode2 = await wrapper.get('[test-id="tabContent2"]')
const textNode3 = await wrapper.get('[test-id="tabContent3"]')
const textNode4 = await wrapper.get('[test-id="tabContent4"]')
const textNode5 = await wrapper.get('[test-id="tabContent5"]')
expect(textNode0.text()).toEqual('-')
expect(textNode1.text()).toEqual('-')
expect(textNode2.text()).toEqual('-')
expect(textNode3.text()).toEqual('-')
expect(textNode4.text()).toEqual('-')
expect(textNode5.text()).toEqual('-')
resolve()
}, 200))
})
test('Metric=Bits/s0和大数值', async () => {
init()
axios.get.mockResolvedValue(mockData.bytes.boundary)
const wrapper = mount(NetworkOverviewLine, {
propsData: {
timeFilter,
chart
}
})
// 延迟等待渲染。使用wrapper.vm.$nextTick有时不管用例如组件中使用了setTimeout的时候
await new Promise(resolve => setTimeout(async () => {
// total页签固定显示数据是0也一样
const titleNode0 = await wrapper.get('[test-id="tabTitle0"]')
const titleNode1 = await wrapper.get('[test-id="tabTitle2"]')
const titleNode2 = await wrapper.get('[test-id="tabTitle5"]')
const textNode0 = await wrapper.get('[test-id="tabContent0"]')
const textNode1 = await wrapper.get('[test-id="tabContent2"]')
const textNode2 = await wrapper.get('[test-id="tabContent5"]')
expect(titleNode0.text()).toEqual('network.total')
expect(titleNode1.text()).toEqual('network.outbound')
expect(titleNode2.text()).toEqual('network.other')
expect(textNode0.text()).toEqual('0bps')
expect(textNode1.text()).toEqual('95.23Ebps')
expect(textNode2.text()).toEqual('0.01bps')
resolve()
}, 200))
})
test('Metric=Bits/s点击第三个tab', async () => {
init()
// 模拟axios返回数据
axios.get.mockResolvedValue(mockData.common)
// 加载vue组件获得实例
const wrapper = mount(NetworkOverviewLine, {
propsData: {
timeFilter,
chart
}
})
// 延迟等待渲染。使用wrapper.vm.$nextTick有时不管用例如组件中使用了setTimeout的时候
await new Promise(resolve => setTimeout(async () => {
const textNode0 = await wrapper.get('[test-id="tabContent0"]')
const textNode1 = await wrapper.get('[test-id="tabContent1"]')
const textNode2 = await wrapper.get('[test-id="tabContent2"]')
expect(textNode0.text()).toEqual('112.04Mbps')
expect(textNode1.text()).toEqual('18.59Mbps')
expect(textNode2.text()).toEqual('87.56Mbps')
resolve()
}, 200))
// 点击tab后是否切换高亮状态
const textNode3 = await wrapper.get('[test-id="tab2"]')
await textNode3.trigger('click')
expect(textNode3.classes()).toContain('is-active')
})
test('Metric=Packets/s', async () => {
init()
// 模拟axios返回数据
axios.get.mockResolvedValue(mockData.common)
// 加载vue组件获得实例
const wrapper = mount(NetworkOverviewLine, {
propsData: {
timeFilter,
chart,
metric: 'Packets/s'
}
})
await new Promise(resolve => setTimeout(async () => {
const textNode0 = await wrapper.get('[test-id="tabContent0"]')
const textNode1 = await wrapper.get('[test-id="tabContent1"]')
const textNode2 = await wrapper.get('[test-id="tabContent2"]')
expect(textNode0.text()).toEqual('14.06Kpackets/s')
expect(textNode1.text()).toEqual('4.24Kpackets/s')
expect(textNode2.text()).toEqual('9.17Kpackets/s')
resolve()
}, 200))
})
test('Metric=Sessions/s', async () => {
init()
// 模拟axios返回数据
axios.get.mockResolvedValue(mockData.common)
// 加载vue组件获得实例
const wrapper = mount(NetworkOverviewLine, {
propsData: {
timeFilter,
chart,
metric: 'Sessions/s'
}
})
await new Promise(resolve => setTimeout(async () => {
const textNode0 = await wrapper.get('[test-id="tabContent0"]')
expect(textNode0.text()).toEqual('29.89sessions/s')
resolve()
}, 200))
})
})

View File

@@ -1,73 +0,0 @@
const mockData = {
// 空
empty: {
data: {
"status": 200,
"code": 200,
"data": {
"resultType": "object",
"result" : []
}
}
},
bytes: {
// 边界
boundary: {
data: {
"status": 200,
"code": 200,
"data": {
"resultType": "object",
"result": [
{
"type": "bytes",
"totalBitsRate": {
"analysis": {
"avg": "0"
}
},
"inboundBitsRate": {
"analysis": {
"avg": "0"
}
},
"outboundBitsRate": {
"analysis": {
"avg": "95229000000000000000"
}
},
"internalBitsRate": {
"analysis": {
"avg": "0"
}
},
"throughBitsRate": {
"analysis": {
"avg": "0"
}
},
"other": {
"analysis": {
"avg": "0.01"
}
}
},
{
"type": "packets"
},
{
"type": "sessions"
}
]
},
"msg": "OK"
}
}
},
// 正常数据
common: {
data: {"status":200,"code":200,"data":{"resultType":"object","result":[{"type":"bytes","totalBitsRate":{"values":[[1673247564,"96801019.52"]],"analysis":{"avg":"112042808.24","max":"301842105.76","min":"52096324","p95":"168089003.35199997"}},"inboundBitsRate":{"values":[[1673247564,"11814508.48"]],"analysis":{"avg":"18587597.36","max":"137528138.88","min":"3181142.88","p95":"49561521.447999954"}},"outboundBitsRate":{"values":[[1673247564,"84282965.52"]],"analysis":{"avg":"87557861.44","max":"290402258","min":"45337684.48","p95":"121041718.81199999"}},"internalBitsRate":{"values":[[1673247564,"9125.12"]],"analysis":{"avg":"278114.32","max":"2215460.48","min":"0","p95":"923494.5719999998"}},"throughBitsRate":{"values":[[1673247564,"694420.48"]],"analysis":{"avg":"5619235.12","max":"42455480.24","min":"262607.76","p95":"13559588.195999999"}},"other":{"values":[[1673247564,"0.00"]],"analysis":{"avg":"0.01","max":"0.08","min":"0.00","p95":"0.08"}}},{"type":"packets","totalPacketsRate":{"values":[[1673247564,"12077.53"]],"analysis":{"avg":"14062.37","max":"32840.42","min":"6564.17","p95":"20923.167999999987"}},"inboundPacketsRate":{"values":[[1673247564,"3865.58"]],"analysis":{"avg":"4241.61","max":"15460.03","min":"1918.22","p95":"8549.799999999997"}},"outboundPacketsRate":{"values":[[1673247564,"8118.89"]],"analysis":{"avg":"9170.98","max":"27134.58","min":"4510.25","p95":"13690.540999999996"}},"internalPacketsRate":{"values":[[1673247564,"15.89"]],"analysis":{"avg":"35.95","max":"276.47","min":"0.00","p95":"122.49749999999999"}},"throughPacketsRate":{"values":[[1673247564,"77.17"]],"analysis":{"avg":"613.82","max":"3768.56","min":"42.92","p95":"1279.757499999999"}},"other":{"values":[[1673247564,"0.00"]],"analysis":{"avg":"0","max":"0.01","min":"0.00","p95":"0.01"}}},{"type":"sessions","totalSessionsRate":{"values":[[1673247564,"29.92"]],"analysis":{"avg":"29.89","max":"29.92","min":"29.67","p95":"29.92"}}}]},"msg":"OK"}
}
}
export default mockData

File diff suppressed because one or more lines are too long

View File

@@ -1,258 +0,0 @@
import NpmAppEventTable from '@/views/charts2/charts/npm/NpmAppEventTable'
import { mount } from '@vue/test-utils'
import axios from 'axios'
import ElementPlus from 'element-plus'
const timeFilter = {
dateRangeValue: -1,
startTime: 1675558657,
endTime: 1675731457
}
const mockGet = { data: { status: 200, code: 200, queryKey: '88eeb92e0ddb40c0327db494cfe5c74c', success: true, message: null, statistics: { elapsed: 0, rows_read: 2, result_size: 752, result_rows: 10 }, job: null, formatType: 'json', meta: [{ name: 'app_name', type: 'string', category: 'Dimension' }, { name: 'event_severity', type: 'string', category: 'Dimension' }, { name: 'event_type', type: 'string', category: 'Dimension' }, { name: 'count', type: 'long', category: 'Metric' }], data: { resultType: 'table', result: [{ appName: 'youku', eventSeverity: 'info', eventType: 'http error', count: 6 }, { appName: 'uplive', eventSeverity: 'critical', eventType: 'http error', count: 5 }, { appName: 'youku', eventSeverity: 'low', eventType: 'http error', count: 4 }, { appName: 'apple_hls', eventSeverity: 'info', eventType: 'http error', count: 3 }, { appName: 'apple_hls', eventSeverity: 'low', eventType: 'http error', count: 3 }, { appName: 'apple_hls', eventSeverity: 'medium', eventType: 'http error', count: 2 }, { appName: 'uplive', eventSeverity: 'high', eventType: 'http error', count: 2 }, { appName: 'windows_update', eventSeverity: 'medium', eventType: 'http error', count: 2 }, { appName: 'apple_hls', eventSeverity: 'critical', eventType: 'http error', count: 1 }, { appName: 'cloudflare', eventSeverity: 'info', eventType: 'http error', count: 1 }] }, originalUrl: 'http://192.168.44.55:9999?query=SELECT%20app_name%20AS%20app_name%2C%20event_severity%20AS%20event_severity%2C%20event_type%20AS%20event_type%2C%20COUNT%28*%29%20AS%20count%20FROM%20performance_event%20WHERE%20start_time%20%3E%3D%201675580110%20AND%20end_time%20%3C%201675752910%20AND%20entity_type%20%3D%20%27app%27%20GROUP%20BY%20app_name%2Cevent_severity%2Cevent_type%20ORDER%20BY%20count%20DESC%20%20LIMIT%2010%20&format=json&option=real-time', msg: 'OK' } }
describe('views/charts2/charts/npm/NpmAppEventTable.vue测试', () => {
test('Npm 事件APP事件信息表格 严重程度色块验证', async () => {
require('vue-router').useRoute.mockReturnValue({ query: {} })
// 模拟 axios 数据
axios.get.mockResolvedValue(mockGet)
// 加载vue组件获得实例
const wrapper = mount(NpmAppEventTable, {
global: {
plugins: [ElementPlus]
},
propsData: {
timeFilter
}
})
await new Promise(resolve => setTimeout(() => {
// critical
const criticalArray = [1, 8]
for (let index = 0; index < criticalArray.length; index++) {
const rowIndex = criticalArray[index]
for (let i = 1; i <= 5; i++) {
const eventSeverityRedValue = wrapper.find('[test-id="eventSeverityValue' + rowIndex + i + '"]')
expect(eventSeverityRedValue.classes()).toContain('red-dot')
}
}
// high
const highArray = [6]
for (let index = 0; index < highArray.length; index++) {
const rowIndex = highArray[index]
for (let i = 1; i <= 4; i++) {
const eventSeverityRedValue = wrapper.find('[test-id="eventSeverityValue' + rowIndex + i + '"]')
expect(eventSeverityRedValue.classes()).toContain('red-dot')
}
for (let i = 5; i <= 5; i++) {
const eventSeverityGreyValue = wrapper.find('[test-id="eventSeverityValue' + rowIndex + i + '"]')
expect(eventSeverityGreyValue.classes()).toContain('grey-dot')
}
}
// medium
const mediumArray = [5, 7]
for (let index = 0; index < mediumArray.length; index++) {
const rowIndex = mediumArray[index]
for (let i = 1; i <= 3; i++) {
const eventSeverityRedValue = wrapper.find('[test-id="eventSeverityValue' + rowIndex + i + '"]')
expect(eventSeverityRedValue.classes()).toContain('red-dot')
}
for (let i = 4; i <= 5; i++) {
const eventSeverityGreyValue = wrapper.find('[test-id="eventSeverityValue' + rowIndex + i + '"]')
expect(eventSeverityGreyValue.classes()).toContain('grey-dot')
}
}
// low
const lowArray = [2, 4]
for (let index = 0; index < lowArray.length; index++) {
const rowIndex = lowArray[index]
for (let i = 1; i <= 2; i++) {
const eventSeverityRedValue = wrapper.find('[test-id="eventSeverityValue' + rowIndex + i + '"]')
expect(eventSeverityRedValue.classes()).toContain('red-dot')
}
for (let i = 3; i <= 5; i++) {
const eventSeverityGreyValue = wrapper.find('[test-id="eventSeverityValue' + rowIndex + i + '"]')
expect(eventSeverityGreyValue.classes()).toContain('grey-dot')
}
}
// info
const infoArray = [0, 3, 9]
for (let index = 0; index < infoArray.length; index++) {
const rowIndex = infoArray[index]
for (let i = 1; i <= 1; i++) {
const eventSeverityRedValue = wrapper.find('[test-id="eventSeverityValue' + rowIndex + i + '"]')
expect(eventSeverityRedValue.classes()).toContain('red-dot')
}
for (let i = 2; i <= 5; i++) {
const eventSeverityGreyValue = wrapper.find('[test-id="eventSeverityValue' + rowIndex + i + '"]')
expect(eventSeverityGreyValue.classes()).toContain('grey-dot')
}
}
resolve()
}, 200))
})
test('Npm 事件APP事件信息表格 数据验证(应用数据列)', async () => {
require('vue-router').useRoute.mockReturnValue({ query: {} })
// 模拟 axios 数据
axios.get.mockResolvedValue(mockGet)
// 加载vue组件获得实例
const wrapper = mount(NpmAppEventTable, {
global: {
plugins: [ElementPlus]
},
propsData: {
timeFilter
}
})
await new Promise(resolve => setTimeout(() => {
const textNode0 = wrapper.find('[test-id="appName0"]')
const textNode1 = wrapper.find('[test-id="appName1"]')
const textNode2 = wrapper.find('[test-id="appName2"]')
const textNode3 = wrapper.find('[test-id="appName3"]')
const textNode4 = wrapper.find('[test-id="appName4"]')
const textNode5 = wrapper.find('[test-id="appName5"]')
const textNode6 = wrapper.find('[test-id="appName6"]')
const textNode7 = wrapper.find('[test-id="appName7"]')
const textNode8 = wrapper.find('[test-id="appName8"]')
const textNode9 = wrapper.find('[test-id="appName9"]')
expect(textNode0.text()).toEqual('youku')
expect(textNode1.text()).toEqual('uplive')
expect(textNode2.text()).toEqual('youku')
expect(textNode3.text()).toEqual('apple_hls')
expect(textNode4.text()).toEqual('apple_hls')
expect(textNode5.text()).toEqual('apple_hls')
expect(textNode6.text()).toEqual('uplive')
expect(textNode7.text()).toEqual('windows_update')
expect(textNode8.text()).toEqual('apple_hls')
expect(textNode9.text()).toEqual('cloudflare')
resolve()
}, 200))
})
test('Npm 事件APP事件信息表格 数据验证(严重程度数据列)', async () => {
require('vue-router').useRoute.mockReturnValue({ query: {} })
// 模拟 axios 数据
axios.get.mockResolvedValue(mockGet)
// 加载vue组件获得实例
const wrapper = mount(NpmAppEventTable, {
global: {
plugins: [ElementPlus]
},
propsData: {
timeFilter
}
})
await new Promise(resolve => setTimeout(() => {
const textNode0 = wrapper.find('[test-id="eventSeverity0"]')
const textNode1 = wrapper.find('[test-id="eventSeverity1"]')
const textNode2 = wrapper.find('[test-id="eventSeverity2"]')
const textNode3 = wrapper.find('[test-id="eventSeverity3"]')
const textNode4 = wrapper.find('[test-id="eventSeverity4"]')
const textNode5 = wrapper.find('[test-id="eventSeverity5"]')
const textNode6 = wrapper.find('[test-id="eventSeverity6"]')
const textNode7 = wrapper.find('[test-id="eventSeverity7"]')
const textNode8 = wrapper.find('[test-id="eventSeverity8"]')
const textNode9 = wrapper.find('[test-id="eventSeverity9"]')
expect(textNode0.text()).toEqual('info')
expect(textNode1.text()).toEqual('critical')
expect(textNode2.text()).toEqual('low')
expect(textNode3.text()).toEqual('info')
expect(textNode4.text()).toEqual('low')
expect(textNode5.text()).toEqual('medium')
expect(textNode6.text()).toEqual('high')
expect(textNode7.text()).toEqual('medium')
expect(textNode8.text()).toEqual('critical')
expect(textNode9.text()).toEqual('info')
resolve()
}, 200))
})
test('Npm 事件APP事件信息表格 数据验证(事件类型数据列)', async () => {
require('vue-router').useRoute.mockReturnValue({ query: {} })
// 模拟 axios 数据
axios.get.mockResolvedValue(mockGet)
// 加载vue组件获得实例
const wrapper = mount(NpmAppEventTable, {
global: {
plugins: [ElementPlus]
},
propsData: {
timeFilter
}
})
await new Promise(resolve => setTimeout(() => {
const textNode0 = wrapper.find('[test-id="eventType0"]')
const textNode1 = wrapper.find('[test-id="eventType1"]')
const textNode2 = wrapper.find('[test-id="eventType2"]')
const textNode3 = wrapper.find('[test-id="eventType3"]')
const textNode4 = wrapper.find('[test-id="eventType4"]')
const textNode5 = wrapper.find('[test-id="eventType5"]')
const textNode6 = wrapper.find('[test-id="eventType6"]')
const textNode7 = wrapper.find('[test-id="eventType7"]')
const textNode8 = wrapper.find('[test-id="eventType8"]')
const textNode9 = wrapper.find('[test-id="eventType9"]')
expect(textNode0.text()).toEqual('http error')
expect(textNode1.text()).toEqual('http error')
expect(textNode2.text()).toEqual('http error')
expect(textNode3.text()).toEqual('http error')
expect(textNode4.text()).toEqual('http error')
expect(textNode5.text()).toEqual('http error')
expect(textNode6.text()).toEqual('http error')
expect(textNode7.text()).toEqual('http error')
expect(textNode8.text()).toEqual('http error')
expect(textNode9.text()).toEqual('http error')
resolve()
}, 200))
})
test('Npm 事件APP事件信息表格 数据验证(事件数量数据列)', async () => {
require('vue-router').useRoute.mockReturnValue({ query: {} })
// 模拟 axios 数据
axios.get.mockResolvedValue(mockGet)
// 加载vue组件获得实例
const wrapper = mount(NpmAppEventTable, {
global: {
plugins: [ElementPlus]
},
propsData: {
timeFilter
}
})
await new Promise(resolve => setTimeout(() => {
const textNode0 = wrapper.find('[test-id="count0"]')
const textNode1 = wrapper.find('[test-id="count1"]')
const textNode2 = wrapper.find('[test-id="count2"]')
const textNode3 = wrapper.find('[test-id="count3"]')
const textNode4 = wrapper.find('[test-id="count4"]')
const textNode5 = wrapper.find('[test-id="count5"]')
const textNode6 = wrapper.find('[test-id="count6"]')
const textNode7 = wrapper.find('[test-id="count7"]')
const textNode8 = wrapper.find('[test-id="count8"]')
const textNode9 = wrapper.find('[test-id="count9"]')
expect(textNode0.text()).toEqual('6')
expect(textNode1.text()).toEqual('5')
expect(textNode2.text()).toEqual('4')
expect(textNode3.text()).toEqual('3')
expect(textNode4.text()).toEqual('3')
expect(textNode5.text()).toEqual('2')
expect(textNode6.text()).toEqual('2')
expect(textNode7.text()).toEqual('2')
expect(textNode8.text()).toEqual('1')
expect(textNode9.text()).toEqual('1')
resolve()
}, 200))
})
})

File diff suppressed because one or more lines are too long

View File

@@ -1,54 +0,0 @@
import NpmEventsHeader from '@/views/charts2/charts/npm/NpmEventsHeader'
import { mount } from '@vue/test-utils'
import axios from 'axios'
// 模拟数据
const chartData = {
data: { status: 200, code: 200, queryKey: '6480498979f7501d822572ebeb9e9665', success: true, message: null, statistics: { elapsed: 0, rows_read: 3, result_size: 167, result_rows: 5 }, job: null, formatType: 'json', meta: [{ name: 'event_severity', type: 'string', category: 'Dimension' }, { name: 'count', type: 'long', category: 'Metric' }], data: { resultType: 'table', result: [{ eventSeverity: 'critical', count: 322334 }, { eventSeverity: 'high', count: 1111 }, { eventSeverity: 'info', count: 122222 }, { eventSeverity: 'low', count: 14456678 }, { eventSeverity: 'medium', count: 2000000 }] }, originalUrl: 'http://192.168.44.55:9999?query=SELECT%20event_severity%20AS%20event_severity%2C%20COUNT%28*%29%20AS%20count%20FROM%20performance_event%20WHERE%20start_time%20%3E%3D%201675026686%20AND%20end_time%20%3C%201675048286%20GROUP%20BY%20event_severity&format=json&option=real-time', msg: 'OK' }
}
// type
const type = 'severity'
describe('views/charts2/charts/npm/NpmEventsHeader.vue测试', () => {
test('严重等级各等级个数npm event 严重等级单值', async () => {
require('vue-router').useRoute.mockReturnValue({ query: {} })
// 模拟 axios 返回数据
axios.get.mockResolvedValue(chartData)
// 加载vue组件获得实例
const wrapper = mount(NpmEventsHeader, {
propsData: {
type
}
})
// 严重等级
const severity0 = wrapper.get('[test-id="severity0"]')
const severity1 = wrapper.get('[test-id="severity1"]')
const severity2 = wrapper.get('[test-id="severity2"]')
const severity3 = wrapper.get('[test-id="severity3"]')
const severity4 = wrapper.get('[test-id="severity4"]')
// 各等级个数
const total0 = wrapper.get('[test-id="total0"]')
const total1 = wrapper.get('[test-id="total1"]')
const total2 = wrapper.get('[test-id="total2"]')
const total3 = wrapper.get('[test-id="total3"]')
const total4 = wrapper.get('[test-id="total4"]')
// type
expect(wrapper.vm.type).toEqual('severity')
expect(severity0.text()).toEqual('critical')
expect(severity1.text()).toEqual('high')
expect(severity2.text()).toEqual('medium')
expect(severity3.text()).toEqual('low')
expect(severity4.text()).toEqual('info')
await new Promise(resolve => setTimeout(() => {
expect(total0.text()).toEqual('322,334')
expect(total1.text()).toEqual('1,111')
expect(total2.text()).toEqual('2,000,000')
expect(total3.text()).toEqual('14,456,678')
expect(total4.text()).toEqual('122,222')
resolve()
}, 200))
})
})

File diff suppressed because one or more lines are too long

View File

@@ -1,162 +0,0 @@
import NpmRecentEvents from '@/views/charts2/charts/npm/NpmRecentEvents'
import { mount } from '@vue/test-utils'
import axios from 'axios'
import ElementPlus from 'element-plus'
// 未下钻
const mockGet = {
data: { status: 200, code: 200, queryKey: '68d8aa5867b08b926b5bd38c36add9e5', success: true, message: null, statistics: { elapsed: 0, rows_read: 2, result_size: 550, result_rows: 5 }, job: null, formatType: 'json', meta: [{ name: 'event_id', type: 'long', category: 'Metric' }, { name: 'event_severity', type: 'string', category: 'Metric' }, { name: 'event_key', type: 'string', category: 'Metric' }, { name: 'event_type', type: 'string', category: 'Metric' }], data: { resultType: 'table', result: [{ eventId: 1173511643475208200, eventSeverity: 'critical', eventKey: '114.114.114.114 dns error', eventType: 'dns error' }, { eventId: 1173504415263352800, eventSeverity: 'high', eventKey: '116.178.78.241 http error', eventType: 'http error' }, { eventId: 1173492761289025500, eventSeverity: 'medium', eventKey: '223.6.6.6 dns error', eventType: 'dns error' }, { eventId: 1173489002890651600, eventSeverity: 'low', eventKey: '114.114.114.114 dns error', eventType: 'dns error' }, { eventId: 1173482380537620500, eventSeverity: 'info', eventKey: '1.1.1.2 dns error', eventType: 'http error' }, { eventId: 1173482380537620500, eventSeverity: 'critical', eventKey: '1.1.1.2 dns error', eventType: 'dns error' }] }, originalUrl: 'http://192.168.44.55:9999?query=SELECT%20event_id%20AS%20event_id%2Cevent_severity%20AS%20event_severity%2C%20event_key%20AS%20event_key%2C%20event_type%20AS%20event_type%20FROM%20performance_event%20WHERE%20start_time%20%3E%3D%201675227528%20AND%20end_time%20%3C%201675231128%20ORDER%20BY%20start_time%20DESC%20%20LIMIT%208%20&format=json&option=real-time', msg: 'OK' }
}
// 下钻
const mockGet1 = {
data: { status: 200, code: 200, queryKey: 'fc0bd92bf3b48a37310d5c004d8b7a7b', success: true, message: null, statistics: { elapsed: 0, rows_read: 2, result_size: 689, result_rows: 7 }, job: null, formatType: 'json', meta: [{ name: 'event_id', type: 'long', category: 'Metric' }, { name: 'event_severity', type: 'string', category: 'Metric' }, { name: 'event_type', type: 'string', category: 'Metric' }, { name: 'start_time', type: 'long', category: 'Metric' }], data: { resultType: 'table', result: [{ eventId: 1132790825086844900, eventSeverity: 'critical', eventType: 'http error', startTime: 1672802700 }, { eventId: 1132132403379142700, eventSeverity: 'high', eventType: 'dns error', startTime: 1672763400 }, { eventId: 1131441760155689000, eventSeverity: 'low', eventType: 'dns error', startTime: 1672722300 }, { eventId: 1131411523384598500, eventSeverity: 'medium', eventType: 'http error', startTime: 1672720500 }, { eventId: 1131390214323789800, eventSeverity: 'info', eventType: 'dns error', startTime: 1672719300 }, { eventId: 1131306200132968400, eventSeverity: 'critical', eventType: 'http error', startTime: 1672714200 }] }, originalUrl: 'http://192.168.44.55:9999?query=SELECT%20event_id%20AS%20event_id%2Cevent_severity%20AS%20event_severity%2C%20event_type%20AS%20event_type%2C%20start_time%20AS%20start_time%20FROM%20performance_event%20WHERE%20start_time%20%3E%3D%201672675200%20AND%20start_time%20%3C%201677513600%20AND%20server_ip%20%3D%20%27116.178.236.216%27%20ORDER%20BY%20start_time%20DESC&format=json&option=real-time', msg: 'OK' }
}
const query = {
curTab: 'country',
dimensionType: 'ip',
fourthMenu: '116.178.214.84',
fourthPanel: '8',
networkOverviewBeforeTab: 'ip',
panelName: '116.178.214.84',
queryCondition: "common_client_ip='116.178.214.84' OR common_server_ip='116.178.214.84'",
t: '1675236779453',
tabIndex: '1',
tabOperationBeforeType: '',
tabOperationType: '4',
thirdMenu: 'network.ips',
thirdPanel: '12'
}
const timeFilter = {
dateRangeValue: -1,
startTime: 1675043912,
endTime: 1675047512
}
describe('views/charts2/charts/npm/NpmRecentEvents.vue测试', () => {
test('npm events 近期事件表格 未下钻', async () => {
require('vue-router').useRoute.mockReturnValue({ query: {} })
// 模拟 axios 返回数据
axios.get.mockResolvedValue(mockGet)
const wrapper = mount(NpmRecentEvents, {
propsData: {
timeFilter
},
global: {
plugins: [ElementPlus]
}
})
await new Promise(resolve => setTimeout(() => {
const severity0 = wrapper.get('[test-id="eventSeverity-critical-0"]')
const severity1 = wrapper.get('[test-id="eventSeverity-high-1"]')
const severity2 = wrapper.get('[test-id="eventSeverity-medium-2"]')
const severity3 = wrapper.get('[test-id="eventSeverity-low-3"]')
const severity4 = wrapper.get('[test-id="eventSeverity-info-4"]')
const severity5 = wrapper.get('[test-id="eventSeverity-critical-5"]')
expect(severity0.text()).toEqual('critical')
expect(severity1.text()).toEqual('high')
expect(severity2.text()).toEqual('medium')
expect(severity3.text()).toEqual('low')
expect(severity4.text()).toEqual('info')
expect(severity5.text()).toEqual('critical')
expect(severity0.classes()).toContain('critical')
expect(severity1.classes()).toContain('high')
expect(severity2.classes()).toContain('medium')
expect(severity3.classes()).toContain('low')
expect(severity4.classes()).toContain('info')
expect(severity5.classes()).toContain('critical')
const eventKey0 = wrapper.get('[test-id="eventKey-114.114.114.114-0"]')
const eventKey1 = wrapper.get('[test-id="eventKey-116.178.78.241-1"]')
const eventKey2 = wrapper.get('[test-id="eventKey-223.6.6.6-2"]')
const eventKey3 = wrapper.get('[test-id="eventKey-114.114.114.114-3"]')
const eventKey4 = wrapper.get('[test-id="eventKey-1.1.1.2-4"]')
expect(eventKey0.text()).toEqual('114.114.114.114')
expect(eventKey1.text()).toEqual('116.178.78.241')
expect(eventKey2.text()).toEqual('223.6.6.6')
expect(eventKey3.text()).toEqual('114.114.114.114')
expect(eventKey4.text()).toEqual('1.1.1.2')
const eventType0 = wrapper.get('[test-id="eventType-dns error-0"]')
const eventType1 = wrapper.get('[test-id="eventType-http error-1"]')
const eventType2 = wrapper.get('[test-id="eventType-dns error-2"]')
const eventType3 = wrapper.get('[test-id="eventType-dns error-3"]')
const eventType4 = wrapper.get('[test-id="eventType-http error-4"]')
expect(eventType0.text()).toEqual('dns error')
expect(eventType1.text()).toEqual('http error')
expect(eventType2.text()).toEqual('dns error')
expect(eventType3.text()).toEqual('dns error')
expect(eventType4.text()).toEqual('http error')
resolve()
}, 200))
})
test('npm events 近期事件表格 下钻', async () => {
require('vue-router').useRoute.mockReturnValue({ query: query })
// 模拟 axios 返回数据
axios.get.mockResolvedValue(mockGet1)
const wrapper = mount(NpmRecentEvents, {
propsData: {
timeFilter
},
global: {
plugins: [ElementPlus]
}
})
await new Promise(resolve => setTimeout(() => {
const severity0 = wrapper.get('[test-id="eventSeverity-critical-0"]')
const severity1 = wrapper.get('[test-id="eventSeverity-high-1"]')
const severity2 = wrapper.get('[test-id="eventSeverity-low-2"]')
const severity3 = wrapper.get('[test-id="eventSeverity-medium-3"]')
const severity4 = wrapper.get('[test-id="eventSeverity-info-4"]')
const severity5 = wrapper.get('[test-id="eventSeverity-critical-5"]')
expect(severity0.text()).toEqual('critical')
expect(severity1.text()).toEqual('high')
expect(severity2.text()).toEqual('low')
expect(severity3.text()).toEqual('medium')
expect(severity4.text()).toEqual('info')
expect(severity5.text()).toEqual('critical')
expect(severity0.classes()).toContain('critical')
expect(severity1.classes()).toContain('high')
expect(severity2.classes()).toContain('low')
expect(severity3.classes()).toContain('medium')
expect(severity4.classes()).toContain('info')
expect(severity5.classes()).toContain('critical')
const eventType0 = wrapper.get('[test-id="eventType-http error-0"]')
const eventType1 = wrapper.get('[test-id="eventType-dns error-1"]')
const eventType2 = wrapper.get('[test-id="eventType-dns error-2"]')
const eventType3 = wrapper.get('[test-id="eventType-http error-3"]')
const eventType4 = wrapper.get('[test-id="eventType-dns error-4"]')
expect(eventType0.text()).toEqual('http error')
expect(eventType1.text()).toEqual('dns error')
expect(eventType2.text()).toEqual('dns error')
expect(eventType3.text()).toEqual('http error')
expect(eventType4.text()).toEqual('dns error')
const startTime0 = wrapper.get('[test-id="startTime-0"]')
const startTime1 = wrapper.get('[test-id="startTime-1"]')
const startTime2 = wrapper.get('[test-id="startTime-2"]')
const startTime3 = wrapper.get('[test-id="startTime-3"]')
const startTime4 = wrapper.get('[test-id="startTime-4"]')
expect(startTime0.text()).toEqual('2023-01-04T11:25:00+08:00')
expect(startTime1.text()).toEqual('2023-01-04T00:30:00+08:00')
expect(startTime2.text()).toEqual('2023-01-03T13:05:00+08:00')
expect(startTime3.text()).toEqual('2023-01-03T12:35:00+08:00')
expect(startTime4.text()).toEqual('2023-01-03T12:15:00+08:00')
resolve()
}, 300))
})
})