Compare commits
77 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12895e3589 | ||
|
|
c2f318391b | ||
|
|
5ccb91ac24 | ||
|
|
d4ce688a5f | ||
|
|
88836a1932 | ||
|
|
fec08141e5 | ||
|
|
28092cc9ab | ||
|
|
e009142e7d | ||
|
|
14a24b268a | ||
|
|
06de8e2bc9 | ||
|
|
d788657048 | ||
|
|
524be68781 | ||
|
|
0139a542da | ||
|
|
da607274d8 | ||
|
|
48426a3955 | ||
|
|
e95ca314a6 | ||
|
|
3d18a4b285 | ||
|
|
2b67cb4a0b | ||
|
|
eadb1e350d | ||
|
|
46a23d9464 | ||
|
|
a7e06c6ffa | ||
|
|
822e7bd9aa | ||
|
|
73952e6811 | ||
|
|
251e0a2018 | ||
|
|
d04bb5a87e | ||
|
|
f6a6ac82bd | ||
|
|
bca147a7db | ||
|
|
afab449f3a | ||
|
|
8bf7b85c2e | ||
|
|
ab146b5b15 | ||
|
|
230e897146 | ||
|
|
949a8e9d86 | ||
|
|
3604783570 | ||
|
|
f60a6bd778 | ||
|
|
5ece1b6c8e | ||
|
|
86c2c8364d | ||
|
|
1f130a6ac8 | ||
|
|
c8af5fd5a1 | ||
|
|
48b7493b2e | ||
|
|
98ba09b586 | ||
|
|
7d85d332df | ||
|
|
6ee5ea6f6e | ||
|
|
6756812c34 | ||
|
|
d2aa5c9b7a | ||
|
|
049d5f92b4 | ||
|
|
7ce190f3c7 | ||
|
|
e9edd9cf05 | ||
|
|
4655eed55f | ||
|
|
cf625c196e | ||
|
|
55fdd3f0e4 | ||
|
|
8aa96da577 | ||
|
|
22bf16a01d | ||
|
|
04e186e7d8 | ||
|
|
38006bd964 | ||
|
|
05677d5fb6 | ||
|
|
156979e79e | ||
|
|
0f2fcbe9e6 | ||
|
|
089887f05b | ||
|
|
c83f64706f | ||
|
|
c82d33fa39 | ||
|
|
eed1d398d8 | ||
|
|
a8643b8543 | ||
|
|
bd1eeec770 | ||
|
|
8cb3f00aa4 | ||
|
|
4fed5a9b8c | ||
|
|
d54054510b | ||
|
|
27bd8260d2 | ||
|
|
29916f8517 | ||
|
|
2bac72eb5d | ||
|
|
dfcc03f11a | ||
|
|
a608ac72f6 | ||
|
|
b5d897608c | ||
|
|
431821154e | ||
|
|
9f488adcb9 | ||
|
|
a31c408327 | ||
|
|
d84483c0dc | ||
|
|
4804748564 |
@@ -1,7 +1,8 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true
|
||||
es2021: true,
|
||||
jest: true
|
||||
},
|
||||
extends: [
|
||||
'plugin:vue/vue3-essential',
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
stages:
|
||||
- gen_git-log
|
||||
- build_project
|
||||
- test
|
||||
- build_image
|
||||
|
||||
cache:
|
||||
@@ -10,7 +11,7 @@ cache:
|
||||
- package.json
|
||||
paths:
|
||||
- node_modules
|
||||
- dist/
|
||||
# - dist/
|
||||
|
||||
before_script:
|
||||
- export CNUI_TAG=$(date +%Y%m%d%H%M%S)
|
||||
@@ -29,7 +30,7 @@ generate_git-log:
|
||||
- public/index.html
|
||||
- public/git-log.html
|
||||
only:
|
||||
- dev
|
||||
- dev-test
|
||||
tags:
|
||||
- galaxy
|
||||
|
||||
@@ -41,29 +42,48 @@ build_project:
|
||||
- cnpm install --save-dev --unsafe-perm
|
||||
- echo "npm run build"
|
||||
- cnpm run build
|
||||
artifacts:
|
||||
name: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME"
|
||||
when: on_success
|
||||
paths:
|
||||
- dist/
|
||||
only:
|
||||
- dev
|
||||
- dev-test
|
||||
- tags
|
||||
tags:
|
||||
- galaxy
|
||||
|
||||
test:
|
||||
stage: test
|
||||
script:
|
||||
- cnpm run test
|
||||
when: on_success
|
||||
only:
|
||||
- dev-test
|
||||
tags:
|
||||
- galaxy
|
||||
|
||||
build_image:
|
||||
dependencies:
|
||||
- build_project
|
||||
stage: build_image
|
||||
script:
|
||||
- echo "docker build"
|
||||
- sudo docker build --no-cache -t cn-ui:$CNUI_TAG .
|
||||
- sudo docker build --no-cache -t cn-ui-$CI_COMMIT_REF_NAME:$CNUI_TAG .
|
||||
- echo "docker tag"
|
||||
- sudo docker tag cn-ui:$CNUI_TAG 192.168.40.153:9080/cyber-narrator/cn-ui:$CNUI_TAG
|
||||
- sudo docker tag cn-ui-$CI_COMMIT_REF_NAME:$CNUI_TAG 192.168.40.153:9080/cyber-narrator/cn-ui-$CI_COMMIT_REF_NAME:$CNUI_TAG
|
||||
- echo "docker push"
|
||||
- sudo docker push 192.168.40.153:9080/cyber-narrator/cn-ui:$CNUI_TAG
|
||||
- sudo docker push 192.168.40.153:9080/cyber-narrator/cn-ui-$CI_COMMIT_REF_NAME:$CNUI_TAG
|
||||
when: on_success
|
||||
only:
|
||||
- dev
|
||||
- dev-test
|
||||
tags:
|
||||
- galaxy
|
||||
|
||||
|
||||
build_release_image:
|
||||
dependencies:
|
||||
- build_project
|
||||
stage: build_image
|
||||
script:
|
||||
- echo 'tag名称是'
|
||||
@@ -71,11 +91,11 @@ build_release_image:
|
||||
- echo '提交的版本是'
|
||||
- echo $CI_COMMIT_REF_NAME
|
||||
- echo "docker build"
|
||||
- sudo docker build --no-cache -t cn-ui:$CI_COMMIT_TAG .
|
||||
- sudo docker build --no-cache -t cn-ui-$CI_COMMIT_REF_NAME:$CI_COMMIT_TAG .
|
||||
- echo "docker tag"
|
||||
- sudo docker tag cn-ui:$CI_COMMIT_TAG 192.168.40.153:9080/cyber-narrator/cn-ui:$CI_COMMIT_TAG
|
||||
- sudo docker tag cn-ui-$CI_COMMIT_REF_NAME:$CI_COMMIT_TAG 192.168.40.153:9080/cyber-narrator/cn-ui-$CI_COMMIT_REF_NAME:$CI_COMMIT_TAG
|
||||
- echo "docker push"
|
||||
- sudo docker push 192.168.40.153:9080/cyber-narrator/cn-ui:$CI_COMMIT_TAG
|
||||
- sudo docker push 192.168.40.153:9080/cyber-narrator/cn-ui-$CI_COMMIT_REF_NAME:$CI_COMMIT_TAG
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
|
||||
@@ -6,6 +6,8 @@ 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',
|
||||
|
||||
@@ -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.0.0-rc.18",
|
||||
"@vue/test-utils": "^2.2.7",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-jest": "^26.0.0",
|
||||
"compression-webpack-plugin": "^8.0.1",
|
||||
|
||||
107
src/Test.vue
107
src/Test.vue
@@ -1,27 +1,120 @@
|
||||
<template>
|
||||
<span data-test="count">{{count}}</span>
|
||||
<button data-test="button" @click="click">click</button>
|
||||
<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>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* vue-jest的测试示例 */
|
||||
import VueRouter from 'vue-router'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import axios from 'axios'
|
||||
import { ref } from 'vue'
|
||||
import indexedDBUtils from '@/indexedDB'
|
||||
export default {
|
||||
name: 'Test',
|
||||
data () {
|
||||
return {
|
||||
count: 0
|
||||
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
|
||||
}
|
||||
},
|
||||
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)
|
||||
}
|
||||
},
|
||||
created () {
|
||||
const { currentRoute } = VueRouter.useRouter()
|
||||
setup () {
|
||||
const { query } = useRoute()
|
||||
const { currentRoute } = useRouter()
|
||||
const localstorageValue = localStorage.getItem('key')
|
||||
const lineTab = ref(query.lineTab || '')
|
||||
const path = currentRoute.value.path
|
||||
return {
|
||||
currentRoute
|
||||
lineTab,
|
||||
path,
|
||||
localstorageValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
z-index: 999999;
|
||||
box-shadow: 0 0 10px #CCC;
|
||||
box-sizing: border-box;
|
||||
|
||||
.pop-title {
|
||||
margin: 10px 0;
|
||||
}
|
||||
.el-button--mini{
|
||||
padding: 5px 7px;
|
||||
}
|
||||
@@ -23,7 +25,6 @@
|
||||
top: 33px;
|
||||
}
|
||||
.custom-labels {
|
||||
margin-top: 12px;
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
@@ -41,8 +42,7 @@
|
||||
font-size: 14px;
|
||||
}
|
||||
.custom-label:hover{
|
||||
color: #cccccc;
|
||||
background-color: #DCDFE6;
|
||||
background-color: rgba(220, 223, 230, .5)
|
||||
}
|
||||
.custom-title{
|
||||
padding: 2px 0 2px 2px;
|
||||
@@ -57,6 +57,14 @@
|
||||
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;
|
||||
|
||||
@@ -98,11 +98,11 @@
|
||||
//top: 0;
|
||||
//left: 0;
|
||||
display: flex;
|
||||
.line-value-mpackets.mousemove-cursor {
|
||||
.line-value-tabs.mousemove-cursor {
|
||||
border-top: 4px solid #D3D0D8;
|
||||
z-index: 0;
|
||||
}
|
||||
.line-value-mpackets {
|
||||
.line-value-tabs {
|
||||
cursor: pointer;
|
||||
padding: 16px 0 0 20px;
|
||||
border-top: 4px solid transparent;
|
||||
@@ -122,10 +122,10 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.line-value-mpackets-name {
|
||||
.line-value-tabs-name {
|
||||
position: relative;
|
||||
display: flex;
|
||||
.mpackets-name {
|
||||
.tabs-name {
|
||||
flex: 1;
|
||||
padding-left: 19px;
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
padding-right: 20px;
|
||||
|
||||
&.row__label--width130 {
|
||||
flex-basis: 130px;
|
||||
flex-basis: 140px;
|
||||
padding-right: unset;
|
||||
}
|
||||
&.row__label--width160 {
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
||||
import { ref } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useStore } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'ChartTabs',
|
||||
@@ -69,8 +70,9 @@ export default {
|
||||
setup (props) {
|
||||
const tabsData = ref([])
|
||||
const router = useRouter()
|
||||
const store = useStore()
|
||||
const routerPath = router.currentRoute.value.path
|
||||
const tabList = window.currentChartTabList
|
||||
const tabList = store.getters.getChartTabList
|
||||
let currentTab = '0'
|
||||
|
||||
if (props.data) {
|
||||
@@ -94,7 +96,7 @@ export default {
|
||||
return item.path === routerPath
|
||||
})
|
||||
currentTab = JSON.stringify(currentTab)
|
||||
window.currentChartTabList = [{ path: routerPath, index: currentTab }]
|
||||
store.dispatch('dispatchChartTabList', [{ path: routerPath, index: currentTab }])
|
||||
} else {
|
||||
// 此处为切换界面,如果window里保存的路径和tabsData里的路径一致,选择window数据并使用
|
||||
// 两个不一致的话,则默认选择tabsData里的第一条
|
||||
@@ -108,10 +110,15 @@ 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 {
|
||||
window.currentChartTabList = [{ path: tabsData.value[0].path, index: '0' }]
|
||||
store.dispatch('dispatchChartTabList', [{ path: tabsData.value[0].path, index: '0' }])
|
||||
currentTab = '0'
|
||||
}
|
||||
}
|
||||
@@ -156,9 +163,10 @@ export default {
|
||||
}
|
||||
}
|
||||
})
|
||||
const tabList = this.$store.getters.getChartTabList
|
||||
|
||||
if (window.currentChartTabList && this.router !== 'noRouter') {
|
||||
window.currentChartTabList.forEach((item) => {
|
||||
if (tabList && this.router !== 'noRouter') {
|
||||
tabList.forEach((item) => {
|
||||
this.$nextTick(() => {
|
||||
this.handleActiveBar(parseFloat(item.index))
|
||||
})
|
||||
@@ -167,7 +175,7 @@ export default {
|
||||
this.$nextTick(() => {
|
||||
this.handleActiveBar(this.currentTab)
|
||||
})
|
||||
window.currentChartTabList = null
|
||||
this.$store.dispatch('dispatchChartTabList', null)
|
||||
}
|
||||
},
|
||||
handleActiveBar (index) {
|
||||
@@ -186,7 +194,7 @@ export default {
|
||||
} else {
|
||||
// 数组长度为1,即代表刚刷新界面,获取active的dom添加样式,避免原模式错位问题
|
||||
// 可添加css样式,也可添加class类名,两个操作选一即可
|
||||
if (window.currentChartTabList.length === 1) {
|
||||
if (this.$store.getters.getChartTabList.length === 1) {
|
||||
// 此处操作是因为初始化时给active加border,导致tab下移,故需要将整体往上移动对应高度
|
||||
const topDom = document.getElementsByClassName('el-tabs__header is-top')
|
||||
topDom[0].style.cssText += 'top: -3px'
|
||||
@@ -201,6 +209,7 @@ export default {
|
||||
},
|
||||
handleClick (item) {
|
||||
this.$emit('click', item)
|
||||
const tabList = this.$store.getters.getChartTabList
|
||||
|
||||
if (this.router === 'noRouter') {
|
||||
const { query } = this.$route
|
||||
@@ -210,14 +219,15 @@ export default {
|
||||
})
|
||||
overwriteUrl(newUrl)
|
||||
} else {
|
||||
window.currentChartTabList.push({
|
||||
tabList.push({
|
||||
path: this.tabsData[item.index].path,
|
||||
index: item.index
|
||||
})
|
||||
|
||||
if (window.currentChartTabList.length > 2) {
|
||||
window.currentChartTabList.splice(0, 1)
|
||||
if (tabList.length > 2) {
|
||||
tabList.splice(0, 1)
|
||||
}
|
||||
this.$store.dispatch('dispatchChartTabList', tabList)
|
||||
|
||||
this.$router.push({
|
||||
path: this.tabsData[item.index].path,
|
||||
@@ -230,6 +240,19 @@ 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>
|
||||
|
||||
@@ -141,7 +141,6 @@ export default {
|
||||
hoverError (e) {
|
||||
// const dom = document.getElementById('error-content')
|
||||
// if (dom) {
|
||||
// console.log('---', dom.clientHeight)
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
class="date_style"
|
||||
style="position: absolute;top: -53px;left: -536px;"
|
||||
:clearable="false"
|
||||
:default-time="defaultTime"
|
||||
type="datetimerange"
|
||||
@change="timeArrChange"
|
||||
/>
|
||||
@@ -127,6 +128,11 @@ 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(() => {
|
||||
@@ -274,6 +280,7 @@ export default {
|
||||
rangeEchartsData,
|
||||
address,
|
||||
dateRangeArr,
|
||||
defaultTime,
|
||||
dateRangeValue,
|
||||
isCustom,
|
||||
newDateValue,
|
||||
|
||||
@@ -98,7 +98,6 @@ 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()
|
||||
|
||||
@@ -103,32 +103,7 @@
|
||||
<span v-else class="route-menu" @click="jump(route,item,'',3)">{{ $t(item) }}</span>
|
||||
</template>
|
||||
<template v-else-if="index===1">
|
||||
<span class="route-menu" @click="jump(route,'','',2)"
|
||||
v-if="route.indexOf('detection') === -1 && 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>-->
|
||||
<span class="route-menu" @click="jump(route,'','',2)">{{ item }}</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span>{{ item }}</span>
|
||||
@@ -552,7 +527,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 => {
|
||||
@@ -627,9 +602,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') {
|
||||
/* if (route !== '/panel/networkOverview') {
|
||||
this.urlChangeParams.queryCondition = ''
|
||||
}
|
||||
} */
|
||||
this.urlChangeParams.queryCondition = ''
|
||||
}
|
||||
} else {
|
||||
this.urlChangeParams[this.curTabState.tabOperationType] = operationType.mainMenu
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</div>
|
||||
<div class="right-box__container">
|
||||
<div class="container__form">
|
||||
<el-form ref="userForm" :model="editObject" :rules="rules" label-position="top" label-width="120px">
|
||||
<el-form ref="reportForm" :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,7 +19,6 @@
|
||||
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"
|
||||
@@ -31,7 +30,6 @@
|
||||
</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
|
||||
@@ -45,7 +43,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=" " :disabled="!!editObject.id">
|
||||
<el-input v-model.number="editObject.config.timeConfig.offset" size="small" class="el-input-single" placeholder=" ">
|
||||
<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>
|
||||
@@ -53,7 +51,6 @@
|
||||
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"
|
||||
@@ -73,10 +70,8 @@
|
||||
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=" "
|
||||
@@ -93,10 +88,8 @@
|
||||
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=" "
|
||||
@@ -105,41 +98,41 @@
|
||||
</div>
|
||||
</el-form-item >
|
||||
<el-form-item class="el-height">
|
||||
<el-checkbox v-model="scheduleChecked" :disabled="editObject.config.timeConfig.type === 'customize' || !!editObject.id" :label="$t('report.enableTimeSchedule')" size="large" />
|
||||
<el-checkbox v-model="scheduleChecked" :disabled="editObject.config.timeConfig.type === 'customize'" :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="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 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>
|
||||
<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;" :disabled="!!editObject.id">
|
||||
<el-input v-model.number="editObject.config.schedulerConfig.interval" size="small" placeholder=" " style="margin-top: 0.3125rem;">
|
||||
<template #append>{{$t('report.day')}}</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<div class="enable-tabs-weekly" v-else-if="scheduleType === scheduleTypeList[1].value" :disabled="!!editObject.id">
|
||||
<div class="enable-tabs-weekly" v-else-if="scheduleType === scheduleTypeList[1].value">
|
||||
<!-- 每隔几周暂时隐藏 -->
|
||||
<!-- <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" :disabled="!!editObject.id">
|
||||
<el-checkbox-group v-model="editObject.config.schedulerConfig.weekDates" style="margin-top: 0.3125rem">
|
||||
<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="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 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>
|
||||
<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;" :disabled="!!editObject.id">
|
||||
<el-input v-model="editObject.config.schedulerConfig.interval" size="small" placeholder=" " style="margin-top: 0.3125rem;">
|
||||
<template #append>{{$t('report.month')}}</template>
|
||||
</el-input>
|
||||
</template>
|
||||
@@ -147,8 +140,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')" :disabled="!!editObject.id"/>
|
||||
<el-checkbox-group v-model="editObject.config.schedulerConfig.months" @change="monthCheckChange" :disabled="!!editObject.id">
|
||||
<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-for="(item, index) in monthList" :key="index" :label="item.value">{{$t(item.name)}}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
@@ -156,8 +149,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" :disabled="!!editObject.id"/>
|
||||
<el-checkbox-group v-model="editObject.config.schedulerConfig.monthDates" @change="dateCheckChange" :disabled="!!editObject.id">
|
||||
<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-for="item in dateList" :key="item" :label="item"/>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
@@ -170,7 +163,6 @@
|
||||
class="right-box__select"
|
||||
multiple
|
||||
placeholder=" "
|
||||
:disabled="!!editObject.id"
|
||||
popper-class="right-box-select-dropdown right-box-select-report"
|
||||
size="small"
|
||||
@change="()=>{ this.$forceUpdate() }">
|
||||
@@ -179,8 +171,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" :disabled="!!editObject.id"/>
|
||||
<el-checkbox-group v-model="editObject.config.schedulerConfig.weekDates" @change="monthWeekdayCheckChange" :disabled="!!editObject.id">
|
||||
<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-for="(item, index) in weekdayList" :key="index" :label="item.value">{{$t(item.name)}}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
@@ -230,7 +222,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>
|
||||
@@ -283,28 +275,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 } from 'vue'
|
||||
const paramValidator = (rule, value, callback) => {
|
||||
let validate = true
|
||||
if (value && value.length > 0) {
|
||||
const hasEmpty = value.some(v => {
|
||||
return !v.value && v.value !== 0
|
||||
})
|
||||
validate = !hasEmpty
|
||||
}
|
||||
return validate
|
||||
}
|
||||
const nameValidator = (rule, value, callback) => {
|
||||
let validate = true
|
||||
const reg = /^[\u4e00-\u9fa5A-Za-z0-9\-\_]*$/
|
||||
if (reg.test(value)) {
|
||||
validate = true
|
||||
} else {
|
||||
validate = false
|
||||
}
|
||||
return validate
|
||||
}
|
||||
|
||||
import { ref, getCurrentInstance } from 'vue'
|
||||
import i18n from '@/i18n'
|
||||
export default {
|
||||
name: 'ReportBox',
|
||||
mixins: [rightBoxMixin],
|
||||
@@ -313,32 +285,21 @@ export default {
|
||||
currentCategoryId: Number
|
||||
},
|
||||
setup () {
|
||||
const { proxy } = getCurrentInstance()
|
||||
|
||||
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) {
|
||||
if (startTime.value !== '' && startTime.value > time) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -346,22 +307,71 @@ export default {
|
||||
if (time.getTime() > new Date()) {
|
||||
return true
|
||||
}
|
||||
if (focus.value != '' && startTime.value > time) {
|
||||
return false
|
||||
} else if (startTime.value != '' && startTime.value > time) {
|
||||
if (endTime.value !== '' && endTime.value < time) {
|
||||
return true
|
||||
}
|
||||
if (endTime.value != '' && endTime.value < time) {
|
||||
return true
|
||||
}
|
||||
|
||||
const paramValidator = (rule, value, callback) => {
|
||||
let validate = true
|
||||
if (value && value.length > 0) {
|
||||
const hasEmpty = value.some(v => {
|
||||
return !v.value && v.value !== 0
|
||||
})
|
||||
validate = !hasEmpty
|
||||
}
|
||||
return validate
|
||||
}
|
||||
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) {
|
||||
validate = false
|
||||
}
|
||||
return validate
|
||||
}
|
||||
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,
|
||||
startFocus,
|
||||
endFocus
|
||||
rules
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@@ -391,48 +401,20 @@ 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()
|
||||
}
|
||||
this.cleanScheduleConfig()
|
||||
},
|
||||
scheduleChecked (n) {
|
||||
this.editObject.config.isScheduler = n ? 1 : 0
|
||||
if (!this.editObject.id) {
|
||||
this.cleanScheduleConfig()
|
||||
}
|
||||
this.cleanScheduleConfig()
|
||||
},
|
||||
monthScheduleType (n) {
|
||||
if (!this.editObject.id) {
|
||||
this.cleanScheduleConfig()
|
||||
}
|
||||
this.cleanScheduleConfig()
|
||||
},
|
||||
monthIsCycle (n) {
|
||||
if (!this.editObject.id) {
|
||||
@@ -566,15 +548,13 @@ 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
|
||||
@@ -588,11 +568,14 @@ export default {
|
||||
this.scheduleChecked = false
|
||||
}
|
||||
},
|
||||
scheduleTypeChange (val) {
|
||||
this.scheduleType = val
|
||||
},
|
||||
save () {
|
||||
if (this.blockOperation.save) { return }
|
||||
this.blockOperation.save = true
|
||||
|
||||
this.$refs.userForm.validate((valid) => {
|
||||
this.$refs.reportForm.validate((valid) => {
|
||||
if (valid) {
|
||||
let startTime = ''
|
||||
let endTime = ''
|
||||
|
||||
@@ -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>
|
||||
<div class="custom-bottom-btns-right">
|
||||
<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">{{$t('overall.save')}}</span>
|
||||
<span class="top-tool-btn-txt top-tool-btn-save">{{$t('overall.save')}}</span>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,19 @@
|
||||
import { dbName, dbGeoDataTableName, dbDrilldownTableConfig } from '@/utils/constants'
|
||||
import Dexie from 'dexie'
|
||||
/* https://dexie.org/ */
|
||||
|
||||
export const db = new Dexie(dbName)
|
||||
db.version(2).stores({
|
||||
const db = new Dexie(dbName)
|
||||
db.version(3).stores({
|
||||
[dbGeoDataTableName]: '++name, geo',
|
||||
[dbDrilldownTableConfig]: '++id, config'
|
||||
[dbDrilldownTableConfig]: '++id, config',
|
||||
test: '++id, name'
|
||||
})
|
||||
function selectTable (tableName) {
|
||||
return db[tableName]
|
||||
}
|
||||
|
||||
const indexedDBUtils = {
|
||||
db,
|
||||
selectTable
|
||||
}
|
||||
export default indexedDBUtils
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { hasButton } from '@/permission'
|
||||
import { dateFormatByAppearance } from '@/utils/date-util'
|
||||
import { storageKey } from '@/utils/constants'
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
@@ -21,7 +20,9 @@ export default {
|
||||
query: false
|
||||
},
|
||||
timeout: null,
|
||||
debounceFunc: null
|
||||
debounceFunc: null,
|
||||
// 是否正在单元测试
|
||||
isUnitTesting: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -59,7 +59,8 @@ const panel = {
|
||||
rangeEchartsData: {}, // 框选echarts图表
|
||||
routerHistoryList: [], // 路由跳转记录列表
|
||||
dnsQtypeMapData: [],
|
||||
dnsRcodeMapData: []
|
||||
dnsRcodeMapData: [],
|
||||
chartTabList: null // chartTabs组件的tab状态点击列表,初始化为null方便原有逻辑计算
|
||||
},
|
||||
mutations: {
|
||||
setShowRightBox (state, flag) {
|
||||
@@ -151,6 +152,9 @@ const panel = {
|
||||
},
|
||||
setRouterHistoryList (state, list) {
|
||||
state.routerHistoryList = list
|
||||
},
|
||||
setChartTabList (state, list) {
|
||||
state.chartTabList = list
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
@@ -225,6 +229,9 @@ const panel = {
|
||||
},
|
||||
getRouterHistoryList (state) {
|
||||
return state.routerHistoryList
|
||||
},
|
||||
getChartTabList (state) {
|
||||
return state.chartTabList
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
@@ -253,6 +260,9 @@ const panel = {
|
||||
},
|
||||
clearPanel (store) {
|
||||
store.commit('cleanPanel')
|
||||
},
|
||||
dispatchChartTabList (store, list) {
|
||||
store.commit('setChartTabList', list)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 { db } from '@/indexedDB'
|
||||
import indexedDBUtils 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 db[dbDrilldownTableConfig].put({
|
||||
await indexedDBUtils.selectTable(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) {
|
||||
db[dbDrilldownTableConfig].delete(userId)
|
||||
indexedDBUtils.selectTable(dbDrilldownTableConfig).delete(userId)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -318,11 +318,12 @@ 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: `${window.location.protocol}//${window.location.host}:${window.location.port}/geojson/${suffix}.json`
|
||||
}).then(response => {
|
||||
axios({ url }).then(response => {
|
||||
resolve(response.data || response || null)
|
||||
}).catch(err => {
|
||||
console.error(err)
|
||||
})
|
||||
})
|
||||
return await request
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
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 = {
|
||||
|
||||
@@ -5,8 +5,7 @@ import { storageKey, iso36112, topDomain, echartsFontSize, dbGeoDataTableName, n
|
||||
import { getIso36112JsonData, getDictList } from '@/utils/api'
|
||||
import { format } from 'echarts'
|
||||
import router from '@/router'
|
||||
import { db } from '@/indexedDB'
|
||||
import { useRoute } from 'vue-router'
|
||||
import indexedDBUtils from '@/indexedDB'
|
||||
|
||||
export const tableSort = {
|
||||
// 是否需要排序
|
||||
@@ -488,11 +487,11 @@ export function loadGeoData () {
|
||||
keys.push(storageKey.iso36112Capital)
|
||||
keys.push(storageKey.iso36112WorldLow)
|
||||
keys.forEach(async k => {
|
||||
const queryData = await db[dbGeoDataTableName].get({ name: k })
|
||||
const queryData = await indexedDBUtils.selectTable(dbGeoDataTableName).get({ name: k })
|
||||
if (!queryData) {
|
||||
const data = await getIso36112JsonData(iso36112[k])
|
||||
if (data) {
|
||||
db[dbGeoDataTableName].add({
|
||||
indexedDBUtils.selectTable(dbGeoDataTableName).add({
|
||||
name: k,
|
||||
geo: data
|
||||
})
|
||||
@@ -505,14 +504,14 @@ export function loadGeoData () {
|
||||
* 使用indexedDB缓存地图数据
|
||||
* */
|
||||
export async function getGeoData (key) {
|
||||
const data = await db[dbGeoDataTableName].get({ name: key })
|
||||
const data = await indexedDBUtils.selectTable(dbGeoDataTableName).get({ name: key })
|
||||
if (data) {
|
||||
return data.geo
|
||||
} else {
|
||||
if (iso36112[key]) {
|
||||
const d = await getIso36112JsonData(iso36112[key])
|
||||
if (d) {
|
||||
db[dbGeoDataTableName].add({
|
||||
indexedDBUtils.selectTable(dbGeoDataTableName).add({
|
||||
name: key,
|
||||
geo: d
|
||||
})
|
||||
@@ -937,7 +936,7 @@ export async function getDefaultCurTab (tableType, metric, columnName) {
|
||||
export async function readDrilldownTableConfigByUser () {
|
||||
// 获取用户定制的自定义配置
|
||||
const userId = localStorage.getItem(storageKey.userId)
|
||||
const userLocalConfig = await db[dbDrilldownTableConfig].get({ id: userId })
|
||||
const userLocalConfig = await indexedDBUtils.selectTable(dbDrilldownTableConfig).get({ id: userId })
|
||||
let defaultDrillDownTableConfigs = []
|
||||
if (userLocalConfig) {
|
||||
defaultDrillDownTableConfigs = userLocalConfig.config
|
||||
@@ -946,15 +945,15 @@ export async function readDrilldownTableConfigByUser () {
|
||||
}
|
||||
|
||||
export async function getConfigVersion (id) {
|
||||
let defaultConfigInDb = await db[dbDrilldownTableConfig].get({ id: id })
|
||||
let defaultConfigInDb = await indexedDBUtils.selectTable(dbDrilldownTableConfig).get({ id: id })
|
||||
if (!defaultConfigInDb) {
|
||||
defaultConfigInDb = await db[dbDrilldownTableConfig].get({ id: 'default' })
|
||||
defaultConfigInDb = await indexedDBUtils.selectTable(dbDrilldownTableConfig).get({ id: 'default' })
|
||||
}
|
||||
return defaultConfigInDb.version || ''
|
||||
}
|
||||
|
||||
export async function combineDrilldownTableWithUserConfig () {
|
||||
const defaultConfigInDb = await db[dbDrilldownTableConfig].get({ id: 'default' })
|
||||
const defaultConfigInDb = await indexedDBUtils.selectTable(dbDrilldownTableConfig).get({ id: 'default' })
|
||||
const defaultConfigGroup = defaultConfigInDb ? defaultConfigInDb.config : []
|
||||
const currentUserConfigGroup = await readDrilldownTableConfigByUser()
|
||||
if (defaultConfigGroup && currentUserConfigGroup && currentUserConfigGroup.length > 0) {
|
||||
@@ -1086,3 +1085,64 @@ 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,16 +43,6 @@ 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'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -150,14 +150,12 @@ 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)
|
||||
|
||||
@@ -114,8 +114,8 @@ export default {
|
||||
},
|
||||
reload () {
|
||||
this.copyDataList.forEach(item => {
|
||||
if (this.$refs['chart' + item.id]) {
|
||||
this.$refs['chart' + item.id].reload()
|
||||
if (this.$refs['chart' + item.id] && this.$refs['chart' + item.id][0]) {
|
||||
this.$refs['chart' + item.id][0].reload()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -32,8 +32,8 @@ export default {
|
||||
methods: {
|
||||
reload () {
|
||||
this.dnsScreenDataList.forEach(item => {
|
||||
if (this.$refs['chart' + item.id]) {
|
||||
this.$refs['chart' + item.id].getChartData()
|
||||
if (this.$refs['chart' + item.id] && this.$refs['chart' + item.id][0]) {
|
||||
this.$refs['chart' + item.id][0].getChartData()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -334,6 +334,8 @@ 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))
|
||||
|
||||
@@ -123,11 +123,8 @@ export default {
|
||||
this.toggleLoading(true)
|
||||
get(api.dnsInsight.activeMaliciousDomain, params).then(res => {
|
||||
if (res.code === 200) {
|
||||
const data = res.data.result
|
||||
if (!data || data.length === 0) {
|
||||
this.isNoData = true
|
||||
}
|
||||
this.tableData = data
|
||||
this.isNoData = res.data.result.length === 0
|
||||
this.tableData = res.data.result
|
||||
} else {
|
||||
this.isNoData = true
|
||||
}
|
||||
|
||||
@@ -95,6 +95,9 @@ export default {
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('resize', this.resize)
|
||||
if (this.myChart) {
|
||||
echarts.dispose(this.myChart)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -147,6 +147,9 @@ export default {
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('resize', this.resize)
|
||||
if (this.myChart) {
|
||||
echarts.dispose(this.myChart)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -208,9 +208,7 @@ export default {
|
||||
this.toggleLoading(true)
|
||||
get(api.dnsInsight.recentEvents, params).then(res => {
|
||||
if (res.code === 200) {
|
||||
if (!res.data.result || res.data.result.length === 0) {
|
||||
this.isNoData = true
|
||||
}
|
||||
this.isNoData = res.data.result.length === 0
|
||||
this.tableData = res.data.result
|
||||
this.tableData.forEach((t, index) => {
|
||||
if (index > 5) {
|
||||
|
||||
@@ -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-mpackets"
|
||||
<div class="line-value-tabs"
|
||||
v-show="item.show"
|
||||
:class=" {'is-active': lineTab === item.class, 'mousemove-cursor': mousemoveCursor === item.class}"
|
||||
v-for="(item, index) in mpackets"
|
||||
v-for="(item, index) in tabs"
|
||||
:key="index"
|
||||
@mouseenter="mouseenter(item)"
|
||||
@mouseleave="mouseleave(item)"
|
||||
@click="activeChange(item, index)">
|
||||
<div class="line-value-mpackets-name">
|
||||
<div class="line-value-tabs-name">
|
||||
<div :class="item.class"></div>
|
||||
<div class="mpackets-name">{{$t(item.name)}}</div>
|
||||
<div class="tabs-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 { overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
||||
import { getLineType, overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
||||
export default {
|
||||
name: 'DnsTrafficLine',
|
||||
components: {
|
||||
@@ -126,7 +126,7 @@ export default {
|
||||
label: 'Maximum'
|
||||
}
|
||||
],
|
||||
mpackets: [
|
||||
tabs: [
|
||||
{ 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,68 +202,14 @@ export default {
|
||||
this.isNoData = res.data.result.length === 0
|
||||
if (this.isNoData) {
|
||||
this.lineTab = ''
|
||||
this.mpackets = [
|
||||
this.tabs = [
|
||||
{ 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
|
||||
@@ -377,7 +323,7 @@ export default {
|
||||
this.chartOption.tooltip.formatter = (params) => {
|
||||
params.forEach(t => {
|
||||
t.seriesName = this.$t(t.seriesName)
|
||||
this.mpackets.forEach(e => {
|
||||
this.tabs.forEach(e => {
|
||||
if (this.$t(e.name) === t.seriesName) {
|
||||
t.borderColor = chartColor3[e.positioning]
|
||||
}
|
||||
@@ -420,16 +366,16 @@ export default {
|
||||
legendSelectChange (item, index, val) {
|
||||
if (index === 'index') {
|
||||
this.dispatchLegendSelectAction(item.name)
|
||||
} else if (this.mpackets[index] && this.mpackets[index].name === item.name) {
|
||||
} else if (this.tabs[index] && this.tabs[index].name === item.name) {
|
||||
this.dispatchLegendSelectAction(item.name)
|
||||
this.mpackets.forEach((t) => {
|
||||
this.tabs.forEach((t) => {
|
||||
if (t.name !== item.name) {
|
||||
this.dispatchLegendUnSelectAction(t.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
if (val === 'active') {
|
||||
this.mpackets.forEach(t => {
|
||||
this.tabs.forEach(t => {
|
||||
if (item.name === t.name) {
|
||||
t.invertTab = !t.invertTab
|
||||
} else {
|
||||
@@ -441,7 +387,7 @@ export default {
|
||||
} else {
|
||||
this.lineTab = t.class
|
||||
}
|
||||
this.mpackets.forEach((e) => {
|
||||
this.tabs.forEach((e) => {
|
||||
this.dispatchLegendSelectAction(e.name)
|
||||
})
|
||||
}
|
||||
@@ -449,8 +395,8 @@ export default {
|
||||
}
|
||||
},
|
||||
handleActiveBar () {
|
||||
if (document.querySelector('.network .line-value-mpackets.is-active')) {
|
||||
const { offsetLeft, clientWidth, clientLeft } = document.querySelector('.network .line-value-mpackets.is-active')
|
||||
if (document.querySelector('.network .line-value-tabs.is-active')) {
|
||||
const { offsetLeft, clientWidth, clientLeft } = document.querySelector('.network .line-value-tabs.is-active')
|
||||
const activeBar = document.querySelector('.network .line-value-active')
|
||||
activeBar.style.cssText += `width: ${clientWidth}px; left: ${offsetLeft + this.leftOffset + clientLeft}px;`
|
||||
}
|
||||
@@ -463,7 +409,7 @@ export default {
|
||||
this.lineTab = ''
|
||||
this.handleActiveBar()
|
||||
this.showMarkLine = !this.showMarkLine
|
||||
this.mpackets.forEach((e) => {
|
||||
this.tabs.forEach((e) => {
|
||||
if (!e.invertTab) {
|
||||
e.invertTab = true
|
||||
}
|
||||
@@ -475,9 +421,9 @@ export default {
|
||||
let echartsData
|
||||
const chartOption = this.myChart.getOption()
|
||||
if (this.lineTab) {
|
||||
echartsData = this.mpackets.filter(t => t.show === true && t.invertTab === false)
|
||||
echartsData = this.tabs.filter(t => t.show === true && t.invertTab === false)
|
||||
} else {
|
||||
echartsData = this.mpackets.filter(t => t.show === true)
|
||||
echartsData = this.tabs.filter(t => t.show === true)
|
||||
}
|
||||
if (this.lineRefer === 'Average' && this.showMarkLine) {
|
||||
chartOption.series.forEach((t, i) => {
|
||||
@@ -526,12 +472,85 @@ 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.mpackets.find(t => t.class === this.lineTab)
|
||||
const data = this.tabs.find(t => t.class === this.lineTab)
|
||||
this.activeChange(data, data.positioning)
|
||||
} else {
|
||||
this.init()
|
||||
@@ -542,7 +561,9 @@ export default {
|
||||
beforeUnmount () {
|
||||
clearTimeout(this.timer)
|
||||
window.removeEventListener('resize', this.resize)
|
||||
this.myChart = null
|
||||
if (this.myChart) {
|
||||
echarts.dispose(this.myChart)
|
||||
}
|
||||
this.chartOption = null
|
||||
this.unitConvert = null
|
||||
}
|
||||
|
||||
@@ -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" style="margin-left: 8px">
|
||||
<div class="info__value" :test-id="`linkBlockTotal${index}`" 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>
|
||||
<div :test-id="`linkBlockEgressUsage${index}`">
|
||||
<svg class="icon item-popover-up" aria-hidden="true">
|
||||
<use xlink:href="#cn-icon-egress"></use>
|
||||
</svg>
|
||||
{{ convertValue(item.egressUsage) }}
|
||||
</div>
|
||||
<div>
|
||||
<div :test-id="`linkBlockIngressUsage${index}`">
|
||||
<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" style="margin-left: 8px">
|
||||
<div class="info__value" :test-id="`nextHopTotal${index}`" 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,10 +175,13 @@ export default {
|
||||
endTime: getSecond(this.timeFilter.endTime)
|
||||
}
|
||||
|
||||
const dataRequest = get(api.linkMonitor.analysis, params)
|
||||
const nextHopRequest = get(api.linkMonitor.nextHopAnalysis, params)
|
||||
const dataRequest = axios.get(api.linkMonitor.analysis, { params: params })
|
||||
const nextHopRequest = axios.get(api.linkMonitor.nextHopAnalysis, { params: params })
|
||||
|
||||
Promise.all([dataRequest, nextHopRequest]).then(res => {
|
||||
Promise.all([dataRequest, nextHopRequest]).then(response => {
|
||||
const res = []
|
||||
res[0] = response[0].data
|
||||
res[1] = response[1].data
|
||||
if (res[0].code === 200 && res[1].code === 200) {
|
||||
this.showError = false
|
||||
|
||||
|
||||
@@ -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,11 +56,14 @@ export default {
|
||||
endTime: getSecond(this.timeFilter.endTime)
|
||||
}
|
||||
|
||||
const dataRequest = get(api.linkMonitor.bigramAnalysis, params)
|
||||
const nextHopRequest = get(api.linkMonitor.bigramNextHopAnalysis, params)
|
||||
const dataRequest = axios.get(api.linkMonitor.bigramAnalysis, { params: params })
|
||||
const nextHopRequest = axios.get(api.linkMonitor.bigramNextHopAnalysis, { params: params })
|
||||
this.toggleLoading(true)
|
||||
|
||||
Promise.all([dataRequest, nextHopRequest]).then(res => {
|
||||
Promise.all([dataRequest, nextHopRequest]).then(response => {
|
||||
const res = []
|
||||
res[0] = response[0].data
|
||||
res[1] = response[1].data
|
||||
if (res[0].code === 200) {
|
||||
this.isLinkShowError = false
|
||||
// 链路流量数据
|
||||
@@ -95,7 +98,7 @@ export default {
|
||||
// 分数低于3分,赋红点
|
||||
d.score = this.localComputeScore(d)
|
||||
|
||||
d.scoreLow3 = d.score < 3
|
||||
d.scoreLow3 = d.score < 3 || d.score === '-'
|
||||
|
||||
if (data) {
|
||||
const existedEgressLink = data.egress.find(e => e.linkId === egressLink.linkId)
|
||||
@@ -143,9 +146,9 @@ export default {
|
||||
// 接口数据乱序,根据出方向排序,再根据同个出方向下的入进行排序
|
||||
nextLinkData.sort((a, b) => {
|
||||
if (a.ingressLinkDirection !== b.ingressLinkDirection) {
|
||||
return a.ingressLinkDirection.localeCompare(b.ingressLinkDirection)
|
||||
return a.ingressLinkDirection.localeCompare(b.ingressLinkDirection, 'zh')
|
||||
}
|
||||
return a.egressLinkDirection.localeCompare(b.egressLinkDirection)
|
||||
return a.egressLinkDirection.localeCompare(b.egressLinkDirection, 'zh')
|
||||
})
|
||||
|
||||
this.isNextNoData = nextLinkData.length === 0
|
||||
@@ -182,7 +185,7 @@ export default {
|
||||
// 分数低于3分,赋红点
|
||||
d.score = this.localComputeScore(d)
|
||||
|
||||
d.scoreLow3 = d.score < 3
|
||||
d.scoreLow3 = d.score < 3 || d.score === '-'
|
||||
|
||||
if (data) {
|
||||
const existedEgressLink = data.egress.find(e => e.linkId === egressLink.linkId)
|
||||
@@ -225,13 +228,11 @@ export default {
|
||||
this.nextErrorMsg = res[1].message
|
||||
}
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
|
||||
this.isLinkShowError = true
|
||||
this.linkErrorMsg = e[0].message
|
||||
this.linkErrorMsg = e.message
|
||||
|
||||
this.isNextShowError = true
|
||||
this.nextErrorMsg = e[1].message
|
||||
this.nextErrorMsg = e.message
|
||||
}).finally(() => {
|
||||
this.toggleLoading(false)
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="link-statistical-dimension" style="position: relative">
|
||||
<div class="dimension-title">{{ $t('linkMonitor.egressLink') }} & {{ $t('linkMonitor.ingressLink') }}
|
||||
</div>
|
||||
<div class="dimension-title" v-if="gridData.length>3">{{ $t('linkMonitor.egressLink') }} & {{ $t('linkMonitor.ingressLink') }}</div>
|
||||
<div class="dimension-title" v-else>{{ $t('linkMonitor.nextHopInternetOfGrid') }}</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, index2) in row.egress" :key="index2">
|
||||
<div v-for="(item, index3) in row.egress" :key="index3">
|
||||
|
||||
<el-popover :width="item.popoverWidth" placement="right" trigger="hover">
|
||||
<template #reference>
|
||||
<div class="data-item data-item__hover">
|
||||
<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 :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>
|
||||
</template>
|
||||
|
||||
@@ -35,13 +35,13 @@
|
||||
<template #default>
|
||||
<div class="item-popover-header">
|
||||
<!--兼容下一跳情况-->
|
||||
<span v-if="row.nextHop">{{ row.nextHop }}</span>
|
||||
<span v-else>{{ row.linkId }}</span>
|
||||
<span v-if="row.nextHop" :test-id="`toNextHop${index2+1}`">{{ row.nextHop }}</span>
|
||||
<span v-else :test-id="`fromLinkId${index2+1}`">{{ 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">{{ row.egress[index2].egressLinkDirection }}</span>
|
||||
<span v-else>{{ row.egress[index2].linkId }}</span>
|
||||
<span v-if="row.nextHop" :test-id="`toNextHop${index3+1}`">{{ item.egressLinkDirection }}</span>
|
||||
<span v-else :test-id="`toLinkId${index3+1}`">{{ item.linkId }}</span>
|
||||
</div>
|
||||
|
||||
<div class="item-popover-block">
|
||||
@@ -49,24 +49,24 @@
|
||||
|
||||
<div style="display: flex">
|
||||
<div class="row-dot">
|
||||
<div :class="row.egress[index2].usageMore90 ? 'red-dot':'green-dot'"></div>
|
||||
<div :class="item.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: row.egress[index2].valueWidth + 'px'}">
|
||||
<div style="margin-left: -10px">
|
||||
<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">
|
||||
<svg class="icon item-popover-up" aria-hidden="true">
|
||||
<use xlink:href="#cn-icon-egress"></use>
|
||||
</svg>
|
||||
{{ convertValue(row.egress[index2].egressUsage) }}
|
||||
{{ convertValue(item.egressUsage) }}
|
||||
</div>
|
||||
<div>
|
||||
<div :test-id="`ingressUsage${gridData.length}-${index2+1}-${index3+1}`">
|
||||
<svg class="icon item-popover-down" aria-hidden="true">
|
||||
<use xlink:href="#cn-icon-ingress"></use>
|
||||
</svg>
|
||||
{{ convertValue(row.egress[index2].ingressUsage) }}
|
||||
{{ convertValue(item.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 class="block-content-item-value" :style="{width: row.egress[index2].valueWidth + 'px'}">
|
||||
{{ unitConvert(row.egress[index2].totalBitsRate, unitTypes.bps).join('') }}
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
@@ -87,48 +87,48 @@
|
||||
|
||||
<div style="display: flex">
|
||||
<div class="row-dot">
|
||||
<div :class="row.egress[index2].scoreLow3 ? 'red-dot':'green-dot'"></div>
|
||||
<div :class="item.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 class="block-content-item-value" :style="{width: row.egress[index2].valueWidth + 'px'}">
|
||||
{{ row.egress[index2].score }}
|
||||
<div :test-id="`score${gridData.length}-${index2+1}-${index3+1}`" class="block-content-item-value" :style="{width: item.valueWidth + 'px'}">
|
||||
{{ item.score }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="block-content-item">
|
||||
<div class="block-content-item-name">{{ $t(npmNetworkName[0].name) }}</div>
|
||||
<div class="block-content-item-value" :style="{width: row.egress[index2].valueWidth + 'px'}">
|
||||
{{ unitConvert(row.egress[index2].establishLatencyMs, unitTypes.time).join('') }}
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div class="block-content-item">
|
||||
<div class="block-content-item-name">{{ $t(npmNetworkName[1].name) }}</div>
|
||||
<div class="block-content-item-value" :style="{'width': row.egress[index2].valueWidth + 'px'}">
|
||||
{{ unitConvert(row.egress[index2].httpResponseLatency, unitTypes.time).join('') }}
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div class="block-content-item">
|
||||
<div class="block-content-item-name">{{ $t(npmNetworkName[2].name) }}</div>
|
||||
<div class="block-content-item-value" :style="{width: row.egress[index2].valueWidth + 'px'}">
|
||||
{{ unitConvert(row.egress[index2].sslConLatency, unitTypes.time).join('') }}
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div class="block-content-item">
|
||||
<div class="block-content-item-name">{{ $t(npmNetworkName[3].name) }}</div>
|
||||
<div class="block-content-item-value" :style="{width: row.egress[index2].valueWidth + 'px'}">
|
||||
{{ unitConvert(row.egress[index2].tcpLostlenPercent, unitTypes.percent).join('') }}
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div class="block-content-item">
|
||||
<div class="block-content-item-name">{{ $t(npmNetworkName[4].name) }}</div>
|
||||
<div class="block-content-item-value" :style="{width: row.egress[index2].valueWidth + 'px'}">
|
||||
{{ unitConvert(row.egress[index2].pktRetransPercent, unitTypes.percent).join('') }}
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="link-traffic-line">
|
||||
<link-traffic-drill-down-list
|
||||
:chart="chart"
|
||||
:line-data="mpackets"
|
||||
:line-data="tabs[0]"
|
||||
:time-filter="timeFilter">
|
||||
</link-traffic-drill-down-list>
|
||||
<div class="line network link-traffic">
|
||||
@@ -12,23 +12,25 @@
|
||||
<div class="line-header-left">
|
||||
<div class="line-value-active" v-if="lineTab"></div>
|
||||
<div class="line-value">
|
||||
<div class="line-value-mpackets"
|
||||
<div class="line-value-tabs"
|
||||
v-show="item.show"
|
||||
:class=" {'is-active': lineTab === item.class, 'mousemove-cursor': mousemoveCursor === item.class}"
|
||||
v-for="(item, index) in mpackets"
|
||||
v-for="(item, index) in tabs"
|
||||
:key="index"
|
||||
@mouseenter="mouseenter(item)"
|
||||
@mouseleave="mouseleave(item)"
|
||||
@click="activeChange(item, index)">
|
||||
<div class="line-value-mpackets-name">
|
||||
@click="activeChange(item, index)"
|
||||
:test-id="`tab-${index}`">
|
||||
<div class="line-value-tabs-name">
|
||||
<div :class="item.class"></div>
|
||||
<div class="mpackets-name">{{$t(item.name)}}</div>
|
||||
<div class="tabs-name">{{$t(item.name)}}</div>
|
||||
</div>
|
||||
<div class="line-value-unit">
|
||||
<div class="line-value-unit" :test-id="`tabContent${index}`">
|
||||
<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>
|
||||
<span>{{unitConvert(item.analysis.avg, unitTypes.number)[1]}}</span>
|
||||
<span v-if="item.unitType">{{item.unitType}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -67,14 +69,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 { overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
||||
import { getLineType, 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',
|
||||
@@ -112,7 +114,7 @@ export default {
|
||||
label: 'Packets/s'
|
||||
}
|
||||
],
|
||||
mpackets: [
|
||||
tabs: [
|
||||
{ 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: '' }
|
||||
@@ -176,105 +178,21 @@ export default {
|
||||
}
|
||||
}
|
||||
this.loading = true
|
||||
get(api.linkMonitor.totalTrafficAnalysis, params).then((res) => {
|
||||
axios.get(api.linkMonitor.totalTrafficAnalysis, { params: params }).then((res) => {
|
||||
res = res.data
|
||||
if (res.code === 200) {
|
||||
this.showError = false
|
||||
this.isNoData = res.data.result.length === 0
|
||||
if (this.isNoData) {
|
||||
this.lineTab = ''
|
||||
this.mpackets = [
|
||||
this.tabs = [
|
||||
{ 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
|
||||
@@ -289,67 +207,69 @@ export default {
|
||||
})
|
||||
},
|
||||
echartsInit (echartsData) {
|
||||
if (this.lineTab) {
|
||||
this.handleActiveBar()
|
||||
echartsData = echartsData.filter(t => t.show === true && t.invertTab === false)
|
||||
} else {
|
||||
echartsData = echartsData.filter(t => t.show === true)
|
||||
}
|
||||
const _this = this
|
||||
const dom = document.getElementById('linkTrafficLineChart')
|
||||
!this.myChart && (this.myChart = echarts.init(dom))
|
||||
this.chartOption = linkTrafficLineChartOption
|
||||
const chartOption = this.chartOption.series[0]
|
||||
this.chartOption.series = echartsData.map((t, i) => {
|
||||
return {
|
||||
...chartOption,
|
||||
name: t.name,
|
||||
lineStyle: {
|
||||
color: chartColor3[t.positioning],
|
||||
width: 1
|
||||
},
|
||||
stack: t.name !== 'network.total' ? 'network.total' : '',
|
||||
symbolSize: function (value) {
|
||||
return _this.symbolSizeSortChange(i, value[0])
|
||||
},
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
borderColor: chartColor4[t.positioning],
|
||||
borderWidth: 2,
|
||||
shadowColor: chartColor4[t.positioning],
|
||||
shadowBlur: this.sizes[t.positioning] + 2
|
||||
}
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.1,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: chartColor3[t.positioning]
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: chartColor3[t.positioning]
|
||||
}
|
||||
])
|
||||
},
|
||||
data: t.data.map(v => [Number(v[0]) * 1000, Number(v[1]), 'number'])
|
||||
if (!this.isUnitTesting) {
|
||||
if (this.lineTab) {
|
||||
this.handleActiveBar()
|
||||
echartsData = echartsData.filter(t => t.show === true && t.invertTab === false)
|
||||
} else {
|
||||
echartsData = echartsData.filter(t => t.show === true)
|
||||
}
|
||||
})
|
||||
this.chartOption.tooltip.formatter = (params) => {
|
||||
params.forEach(t => {
|
||||
t.seriesName = this.$t(t.seriesName)
|
||||
this.mpackets.forEach(e => {
|
||||
if (this.$t(e.name) === t.seriesName) {
|
||||
t.borderColor = chartColor3[e.positioning]
|
||||
}
|
||||
})
|
||||
const _this = this
|
||||
const dom = document.getElementById('linkTrafficLineChart')
|
||||
!this.myChart && (this.myChart = echarts.init(dom))
|
||||
this.chartOption = linkTrafficLineChartOption
|
||||
const chartOption = this.chartOption.series[0]
|
||||
this.chartOption.series = echartsData.map((t, i) => {
|
||||
return {
|
||||
...chartOption,
|
||||
name: t.name,
|
||||
lineStyle: {
|
||||
color: chartColor3[t.positioning],
|
||||
width: 1
|
||||
},
|
||||
stack: t.name !== 'network.total' ? 'network.total' : '',
|
||||
symbolSize: function (value) {
|
||||
return _this.symbolSizeSortChange(i, value[0])
|
||||
},
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
borderColor: chartColor4[t.positioning],
|
||||
borderWidth: 2,
|
||||
shadowColor: chartColor4[t.positioning],
|
||||
shadowBlur: this.sizes[t.positioning] + 2
|
||||
}
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.1,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: chartColor3[t.positioning]
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: chartColor3[t.positioning]
|
||||
}
|
||||
])
|
||||
},
|
||||
data: t.data.map(v => [Number(v[0]) * 1000, Number(v[1]), 'number'])
|
||||
}
|
||||
})
|
||||
// const str = stackedLineTooltipFormatter(params)
|
||||
return stackedLineTooltipFormatter(params)
|
||||
this.chartOption.tooltip.formatter = (params) => {
|
||||
params.forEach(t => {
|
||||
t.seriesName = this.$t(t.seriesName)
|
||||
this.tabs.forEach(e => {
|
||||
if (this.$t(e.name) === t.seriesName) {
|
||||
t.borderColor = chartColor3[e.positioning]
|
||||
}
|
||||
})
|
||||
})
|
||||
// const str = stackedLineTooltipFormatter(params)
|
||||
return stackedLineTooltipFormatter(params)
|
||||
}
|
||||
this.showMarkLine = true
|
||||
this.myChart.setOption(this.chartOption)
|
||||
}
|
||||
this.showMarkLine = true
|
||||
this.myChart.setOption(this.chartOption)
|
||||
},
|
||||
activeChange (item, index) {
|
||||
if (this.isNoData) return
|
||||
@@ -381,16 +301,16 @@ export default {
|
||||
legendSelectChange (item, index, val) {
|
||||
if (index === 'index') {
|
||||
this.dispatchLegendSelectAction(item.name)
|
||||
} else if (this.mpackets[index] && this.mpackets[index].name === item.name) {
|
||||
} else if (this.tabs[index] && this.tabs[index].name === item.name) {
|
||||
this.dispatchLegendSelectAction(item.name)
|
||||
this.mpackets.forEach((t) => {
|
||||
this.tabs.forEach((t) => {
|
||||
if (t.name !== item.name) {
|
||||
this.dispatchLegendUnSelectAction(t.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
if (val === 'active') {
|
||||
this.mpackets.forEach(t => {
|
||||
this.tabs.forEach(t => {
|
||||
if (item.name === t.name) {
|
||||
t.invertTab = !t.invertTab
|
||||
} else {
|
||||
@@ -402,7 +322,7 @@ export default {
|
||||
} else {
|
||||
this.lineTab = t.class
|
||||
}
|
||||
this.mpackets.forEach((e) => {
|
||||
this.tabs.forEach((e) => {
|
||||
this.dispatchLegendSelectAction(e.name)
|
||||
})
|
||||
}
|
||||
@@ -410,8 +330,8 @@ export default {
|
||||
}
|
||||
},
|
||||
handleActiveBar () {
|
||||
if (document.querySelector('.network .line-value-mpackets.is-active')) {
|
||||
const { offsetLeft, clientWidth, clientLeft } = document.querySelector('.network .line-value-mpackets.is-active')
|
||||
if (document.querySelector('.network .line-value-tabs.is-active')) {
|
||||
const { offsetLeft, clientWidth, clientLeft } = document.querySelector('.network .line-value-tabs.is-active')
|
||||
const activeBar = document.querySelector('.network .line-value-active')
|
||||
activeBar.style.cssText += `width: ${clientWidth}px; left: ${offsetLeft + this.leftOffset + clientLeft}px;`
|
||||
}
|
||||
@@ -424,7 +344,7 @@ export default {
|
||||
this.lineTab = ''
|
||||
this.handleActiveBar()
|
||||
this.showMarkLine = !this.showMarkLine
|
||||
this.mpackets.forEach((e) => {
|
||||
this.tabs.forEach((e) => {
|
||||
if (!e.invertTab) {
|
||||
e.invertTab = true
|
||||
}
|
||||
@@ -457,12 +377,71 @@ 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.mpackets.find(t => t.class === this.lineTab)
|
||||
const data = this.tabs.find(t => t.class === this.lineTab)
|
||||
this.activeChange(data, data.positioning)
|
||||
} else {
|
||||
this.init()
|
||||
@@ -473,7 +452,9 @@ export default {
|
||||
beforeUnmount () {
|
||||
clearTimeout(this.timer)
|
||||
window.removeEventListener('resize', this.resize)
|
||||
this.myChart = null
|
||||
if (this.myChart) {
|
||||
echarts.dispose(this.myChart)
|
||||
}
|
||||
this.chartOption = null
|
||||
this.unitConvert = null
|
||||
}
|
||||
|
||||
@@ -102,15 +102,12 @@ 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 // 入口
|
||||
|
||||
@@ -6,36 +6,42 @@
|
||||
<div v-else>
|
||||
<div class="link-traffic-list-center">
|
||||
<div class="link-traffic-list-center-label">{{$t('network.total')}}</div>
|
||||
<div class="link-traffic-list-center-value" v-if="lineData[0] && lineData[0].analysis">{{unitConvert(lineData[0].analysis.avg, unitTypes.bps).join('')}}</div>
|
||||
<div 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>
|
||||
<div class="link-traffic-list-center">
|
||||
<div class="link-traffic-list-center-label">{{$t('linkMonitor.bandwidthUsage')}}</div>
|
||||
<div class="link-traffic-list-center-value" v-if="bandWidth && lineData[0] && lineData[0].analysis">{{unitConvert(lineData[0].analysis.avg / bandWidth, unitTypes.percent).join('')}}</div>
|
||||
<div class="link-traffic-list-center-value" v-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-else>-</div>
|
||||
</div>
|
||||
<div class="link-traffic-list-center">
|
||||
<div class="link-traffic-list-center-label">{{$t('linkMonitor.npmScore')}}</div>
|
||||
<div class="link-traffic-list-center-value">{{linkTrafficListData.npmScore || '-'}}</div>
|
||||
<div class="link-traffic-list-center-value" test-id="line-score">{{linkTrafficListData.npmScore || '-'}}</div>
|
||||
</div>
|
||||
<div class="link-traffic-list-center">
|
||||
<div class="link-traffic-list-center-label">{{$t('networkAppPerformance.tcpConnectionEstablishLatency')}}</div>
|
||||
<div class="link-traffic-list-center-value">{{unitConvert(Math.floor(linkTrafficListData.establishLatencyMs), unitTypes.time).join('')}}</div>
|
||||
<div class="link-traffic-list-center-value" test-id="line-tcp">{{unitConvert(Math.floor(linkTrafficListData.establishLatencyMs), unitTypes.time).join('')}}</div>
|
||||
</div>
|
||||
<div class="link-traffic-list-center">
|
||||
<div class="link-traffic-list-center-label">{{$t('networkAppPerformance.httpResponse')}}</div>
|
||||
<div class="link-traffic-list-center-value">{{unitConvert(Math.floor(linkTrafficListData.httpResponseLatency), unitTypes.time).join('')}}</div>
|
||||
<div class="link-traffic-list-center-value" test-id="line-http">{{unitConvert(Math.floor(linkTrafficListData.httpResponseLatency), unitTypes.time).join('')}}</div>
|
||||
</div>
|
||||
<div class="link-traffic-list-center">
|
||||
<div class="link-traffic-list-center-label">{{$t('networkAppPerformance.sslResponseLatency')}}</div>
|
||||
<div class="link-traffic-list-center-value">{{unitConvert(Math.floor(linkTrafficListData.sslConLatency), unitTypes.time).join('')}}</div>
|
||||
<div class="link-traffic-list-center-value" test-id="line-ssl">{{unitConvert(Math.floor(linkTrafficListData.sslConLatency), unitTypes.time).join('')}}</div>
|
||||
</div>
|
||||
<div class="link-traffic-list-center">
|
||||
<div class="link-traffic-list-center-label">{{$t('networkAppPerformance.packetLoss')}}</div>
|
||||
<div class="link-traffic-list-center-value">{{unitConvert(linkTrafficListData.tcpLostlenPercent, unitTypes.percent).join('')}}</div>
|
||||
<div class="link-traffic-list-center-value" test-id="line-packetLoss">{{unitConvert(linkTrafficListData.tcpLostlenPercent, unitTypes.percent).join('')}}</div>
|
||||
</div>
|
||||
<div class="link-traffic-list-center">
|
||||
<div class="link-traffic-list-center-label">{{$t('overall.packetRetrans')}}</div>
|
||||
<div class="link-traffic-list-center-value">{{unitConvert(linkTrafficListData.pktRetransPercent, unitTypes.percent).join('')}}</div>
|
||||
<div class="link-traffic-list-center-value" test-id="line-packetRetrans">{{unitConvert(linkTrafficListData.pktRetransPercent, unitTypes.percent).join('')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -45,7 +51,6 @@
|
||||
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'
|
||||
@@ -53,6 +58,7 @@ 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],
|
||||
@@ -136,7 +142,8 @@ export default {
|
||||
}
|
||||
}
|
||||
this.loading = true
|
||||
get(api.linkMonitor.networkAnalysis, params).then(res => {
|
||||
axios.get(api.linkMonitor.networkAnalysis, { params: params }).then(res => {
|
||||
res = res.data
|
||||
if (res.code === 200) {
|
||||
this.showError = false
|
||||
this.isNoData = res.data.result.length === 0
|
||||
@@ -165,6 +172,9 @@ export default {
|
||||
},
|
||||
mounted () {
|
||||
this.linkTrafficData()
|
||||
},
|
||||
beforeUnmount () {
|
||||
this.unitConvert = null
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -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">
|
||||
<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-title">
|
||||
<div class="app-card-title-name">
|
||||
<i class="cn-icon" :class="app.type === 'provider' ? 'cn-icon-entity' : 'cn-icon-app2'"></i>
|
||||
<span @click="drillDownData(app.type, app.name)">{{app.name}}</span>
|
||||
<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>
|
||||
</div>
|
||||
<div class="app-card-title-more">
|
||||
<span v-show="app.showMore"><i class="cn-icon cn-icon-more-dark" @mouseenter="mouseenterMore(app)"></i></span>
|
||||
<span class="app-card-title-more-delete" @click="del(app, index)" v-show="app.moreOptions" @mouseleave="mouseleaveMore(app)"><i class="cn-icon cn-icon-delete"></i>{{$t('overall.delete')}}</span>
|
||||
<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>
|
||||
</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">{{unitConvert(app.rate, unitTypes.number).join(' ')}}</div>
|
||||
<div class="app-card__body-content-percent red" v-if="app.value > 0">
|
||||
<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}`">
|
||||
<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">
|
||||
<div class="app-card__body-content-percent green" v-else-if="app.value < 0" :test-id="`percent${index}`">
|
||||
<span v-if="app.value >= -5">
|
||||
-{{unitConvert(app.value, unitTypes.percent).join('').replaceAll('-', '')}}
|
||||
-{{unitConvert(app.value, unitTypes.percent).join('').replace(/-/g, '')}}
|
||||
</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'">{{unitConvert(app.total, unitTypes.byte).join(' ')}}</div>
|
||||
<div v-else>{{unitConvert(app.total, unitTypes.number).join(' ')}}</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>
|
||||
</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">{{$t('overall.add')}}</span>
|
||||
<span @click="addApp" test-id="add">{{$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">{{$t('overall.cancel')}}</div>
|
||||
<div class="header__operation header__operation--cancel" @click="cancelApp" test-id="cancel-app">{{$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)">
|
||||
<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-content">
|
||||
<div class="body__app-left">
|
||||
<span><i class="cn-icon" :class="app.icon"></i></span>
|
||||
<span class="body__app-left-title">{{app.value}}</span>
|
||||
<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>
|
||||
</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">{{app.remark}}</div>
|
||||
<div class="body__app-value" v-if="app.remark" :title="app.remark" :test-id="`provide-remark${index}`">{{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)">
|
||||
<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-content">
|
||||
<div class="body__app-left">
|
||||
<span><i class="cn-icon" :class="app.icon"></i></span>
|
||||
<span class="body__app-left-title">{{app.value}}</span>
|
||||
<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>
|
||||
</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">{{app.remark}}</div>
|
||||
<div class="body__app-value" v-if="app.remark" :title="app.remark" :test-id="`app-remark${index}`">{{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"></el-input>
|
||||
<el-input v-model="searcherApp" @input="searcherAppChange" size="mini" :placeholder="$t('networkOverview.search')" prefix-icon="el-icon-search" test-id="search-input"></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 { get, put } from '@/utils/http'
|
||||
import { put } from '@/utils/http'
|
||||
import { api } from '@/utils/api'
|
||||
import _ from 'lodash'
|
||||
import { getSecond } from '@/utils/date-util'
|
||||
@@ -128,6 +128,7 @@ 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',
|
||||
@@ -152,7 +153,6 @@ 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 = get(api.netWorkOverview.applicationCycleTrafficTotal, params)
|
||||
request = get(api.netWorkOverview.applicationTrafficAnalysis, params)
|
||||
prevRequest = axios.get(api.netWorkOverview.applicationCycleTrafficTotal, { params: params })
|
||||
request = axios.get(api.netWorkOverview.applicationTrafficAnalysis, { params: params })
|
||||
this.handleData(prevRequest, request, 'app')
|
||||
}
|
||||
if (providerCards.length > 0) {
|
||||
@@ -240,15 +240,15 @@ export default {
|
||||
return `'${item.name}'`
|
||||
}).join(',')
|
||||
}
|
||||
prevRequest = get(api.netWorkOverview.appCompanyCycleTrafficTotal, params)
|
||||
request = get(api.netWorkOverview.appCompanyTrafficAnalysis, params)
|
||||
prevRequest = axios.get(api.netWorkOverview.appCompanyCycleTrafficTotal, { params: params })
|
||||
request = axios.get(api.netWorkOverview.appCompanyTrafficAnalysis, { params: params })
|
||||
this.handleData(prevRequest, request, 'provider')
|
||||
}
|
||||
},
|
||||
handleData (prevRequest, request, _t) {
|
||||
this.toggleLoading(true)
|
||||
Promise.all([prevRequest, request]).then(res => {
|
||||
this.isNoData = (res[0].data.result.length && res[1].data.result.length) === 0
|
||||
this.isNoData = (res[0].data.data.result.length && res[1].data.data.result.length) === 0
|
||||
if (this.isNoData) {
|
||||
this.appData = this.appData.map(t => {
|
||||
return {
|
||||
@@ -257,10 +257,10 @@ export default {
|
||||
}
|
||||
})
|
||||
}
|
||||
if (res[0].code === 200 && res[1].code === 200) {
|
||||
if (res[0].data.code === 200 && res[1].data.code === 200) {
|
||||
this.showError = false
|
||||
const prevData = res[0].data.result
|
||||
const data = res[1].data.result
|
||||
const prevData = res[0].data.data.result
|
||||
const data = res[1].data.data.result
|
||||
let toCompareType = 'bytes'
|
||||
if (this.metric === 'Sessions/s') {
|
||||
toCompareType = 'sessions'
|
||||
@@ -298,16 +298,6 @@ 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
|
||||
@@ -401,38 +391,40 @@ export default {
|
||||
this.urlChangeParams = {}
|
||||
},
|
||||
initChart (obj) {
|
||||
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}`))
|
||||
const chartOption = _.cloneDeep(appListChartOption)
|
||||
chartOption.series = [{
|
||||
...chartOption.series[0],
|
||||
data: obj.lineData.map(v => [Number(v[0]) * 1000, Number(v[1]), 'number']),
|
||||
lineStyle: {
|
||||
color: '#35ADDA'
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.1,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: '#35ADDA'
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: '#35ADDA'
|
||||
}
|
||||
])
|
||||
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}`))
|
||||
const chartOption = _.cloneDeep(appListChartOption)
|
||||
chartOption.series = [{
|
||||
...chartOption.series[0],
|
||||
data: obj.lineData.map(v => [Number(v[0]) * 1000, Number(v[1]), 'number']),
|
||||
lineStyle: {
|
||||
color: '#35ADDA'
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.1,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: '#35ADDA'
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: '#35ADDA'
|
||||
}
|
||||
])
|
||||
}
|
||||
}]
|
||||
chartOption.tooltip.formatter = (params) => {
|
||||
return appStackedLineTooltipFormatter(params)
|
||||
}
|
||||
}]
|
||||
chartOption.tooltip.formatter = (params) => {
|
||||
return appStackedLineTooltipFormatter(params)
|
||||
chart.setOption(chartOption)
|
||||
this.myChart.push(chart)
|
||||
this.$nextTick(() => {
|
||||
chart.resize()
|
||||
})
|
||||
}
|
||||
chart.setOption(chartOption)
|
||||
this.myChart.push(chart)
|
||||
this.$nextTick(() => {
|
||||
chart.resize()
|
||||
})
|
||||
}
|
||||
},
|
||||
handleScroll (e) {
|
||||
@@ -469,7 +461,8 @@ export default {
|
||||
}
|
||||
if (parseFloat(this.appTypeTab) === 0) {
|
||||
params.type = 'overviewProvide'
|
||||
get(api.dict, params).then(res => {
|
||||
axios.get(api.dict, { params: params }).then(res => {
|
||||
res = res.data
|
||||
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
|
||||
@@ -494,9 +487,10 @@ export default {
|
||||
})
|
||||
} else if (parseFloat(this.appTypeTab) === 1) {
|
||||
params.type = 'overviewApp'
|
||||
get(api.dict, params).then(res => {
|
||||
res.data.list = res.data.list.filter(l => !this.appData.some(pd => pd.type === 'app' && pd.name === l.value))
|
||||
axios.get(api.dict, { params: params }).then(res => {
|
||||
res = res.data
|
||||
if (res.code === 200) {
|
||||
res.data.list = res.data.list.filter(l => !this.appData.some(pd => pd.type === 'app' && pd.name === l.value))
|
||||
this.pageObj.pages = res.data.pages
|
||||
res.data.list.forEach(t => {
|
||||
this.toSaveApp.forEach(e => {
|
||||
@@ -675,13 +669,6 @@ 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()
|
||||
@@ -718,7 +705,7 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
if (this.chart.params && this.chart.params.app) {
|
||||
if (this.chart && 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)
|
||||
@@ -734,7 +721,9 @@ export default {
|
||||
window.removeEventListener('resize', this.resize)
|
||||
clearTimeout(this.timerScroll)
|
||||
clearTimeout(this.timerSearch)
|
||||
this.myChart = null
|
||||
if (this.myChart) {
|
||||
echarts.dispose(this.myChart)
|
||||
}
|
||||
this.unitConvert = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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">{{$_.get(ddosData, 'attackerCount') || 0}}</div>
|
||||
<div class="ddos-detection-type-value-number" test-id="attackerCount">{{unitConvert($_.get(ddosData, 'attackerCount'), unitTypes.number).join(' ')}}</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">{{$_.get(ddosData, 'victimCount') || 0}}</div>
|
||||
<div class="ddos-detection-type-value-number" test-id="victimCount">{{unitConvert($_.get(ddosData, 'victimCount'), unitTypes.number).join(' ')}}</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">{{$_.get(ddosData, 'attackEventCount') || 0}}</div>
|
||||
<div class="ddos-detection-type-value-number ddos-event" test-id="attackEventCount">{{unitConvert($_.get(ddosData, 'attackEventCount'), unitTypes.number).join(' ')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-button size="small">{{$t('network.ddosDetection')}}<i class="cn-icon cn-icon-arrow-right"></i></el-button>
|
||||
@@ -29,11 +29,13 @@
|
||||
|
||||
<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: {
|
||||
@@ -44,6 +46,8 @@ export default {
|
||||
data () {
|
||||
return {
|
||||
ddosData: {},
|
||||
unitConvert,
|
||||
unitTypes,
|
||||
isNoData: false,
|
||||
showError: false,
|
||||
errorMsg: ''
|
||||
@@ -59,19 +63,16 @@ export default {
|
||||
methods: {
|
||||
ddosDetectDataRequests () {
|
||||
const params = {
|
||||
startTime: getSecond(this.timeFilter.startTime),
|
||||
endTime: getSecond(this.timeFilter.endTime)
|
||||
startTime: this.timeFilter && this.timeFilter.startTime ? getSecond(this.timeFilter.startTime) : '',
|
||||
endTime: this.timeFilter && this.timeFilter.endTime ? getSecond(this.timeFilter.endTime) : ''
|
||||
}
|
||||
this.toggleLoading(true)
|
||||
get(api.netWorkOverview.ddosEventAnalysis, params).then(res => {
|
||||
axios.get(api.netWorkOverview.ddosEventAnalysis, { params: params }).then(res => {
|
||||
res = res.data
|
||||
if (res.code === 200) {
|
||||
this.showError = false
|
||||
if (res.data.result.length === 0) {
|
||||
this.isNoData = true
|
||||
} else {
|
||||
this.ddosData = res.data.result[0]
|
||||
this.isNoData = false
|
||||
}
|
||||
this.isNoData = res.data.result.length === 0
|
||||
this.ddosData = res.data.result[0]
|
||||
} else {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
@@ -87,7 +88,12 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.ddosDetectDataRequests()
|
||||
this.$nextTick(() => {
|
||||
this.ddosDetectDataRequests()
|
||||
})
|
||||
},
|
||||
beforeUnmount () {
|
||||
this.unitConvert = null
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -5,25 +5,29 @@
|
||||
<div class="line-header-left">
|
||||
<div class="line-value-active" v-if="lineTab"></div>
|
||||
<div class="line-value">
|
||||
<div class="line-value-mpackets"
|
||||
v-show="item.show"
|
||||
:class=" {'is-active': lineTab === item.class, 'mousemove-cursor': mousemoveCursor === item.class}"
|
||||
v-for="(item, index) in mpackets"
|
||||
:key="index"
|
||||
@mouseenter="mouseenter(item)"
|
||||
@mouseleave="mouseleave(item)"
|
||||
@click="activeChange(item, index)">
|
||||
<div class="line-value-mpackets-name">
|
||||
<div :class="item.class"></div>
|
||||
<div class="mpackets-name">{{$t(item.name)}}</div>
|
||||
</div>
|
||||
<div class="line-value-unit">
|
||||
<span class="line-value-unit-number">{{unitConvert(item.analysis.avg, unitTypes.number)[0]}}</span>
|
||||
<span class="line-value-unit-number2">
|
||||
<span>{{unitConvert(item.analysis.avg, unitTypes.number)[1]}}</span><span v-if="item.unitType">{{item.unitType}}</span>
|
||||
<template v-for="(item, index) in tabs">
|
||||
<div class="line-value-tabs"
|
||||
:class=" {'is-active': lineTab === item.class, 'mousemove-cursor': mousemoveCursor === item.class}"
|
||||
v-if="item.show"
|
||||
:key="index"
|
||||
@mouseenter="mouseenter(item)"
|
||||
@mouseleave="mouseleave(item)"
|
||||
@click="activeChange(item, index)"
|
||||
:test-id="`tab${index}`"
|
||||
>
|
||||
<div class="line-value-tabs-name">
|
||||
<div :class="item.class"></div>
|
||||
<div class="tabs-name" :test-id="`tabTitle${index}`">{{$t(item.name)}}</div>
|
||||
</div>
|
||||
<div class="line-value-unit" :test-id="`tabContent${index}`">
|
||||
<span class="line-value-unit-number">{{unitConvert(item.analysis.avg, unitTypes.number)[0]}}</span>
|
||||
<span class="line-value-unit-number2">
|
||||
<span>{{unitConvert(item.analysis.avg, unitTypes.number)[1]}}</span>
|
||||
<span v-if="item.unitType">{{item.unitType}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line-select line-header-right">
|
||||
@@ -46,7 +50,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" id="overviewLineChart"></div>
|
||||
<div class="chart-drawing" v-show="showMarkLine && !isNoData && !showError" ref="overviewLineChart"></div>
|
||||
<!-- todo 后续改动,此处为框选返回-->
|
||||
<!-- <div id="brushBtn" style="position: absolute;left: 0;top: 0;" v-show="mouseDownFlag">-->
|
||||
<!-- <el-button @click.stop="backBrushHistory">返回</el-button>-->
|
||||
@@ -63,14 +67,16 @@ import { unitTypes, chartColor3, chartColor4 } from '@/utils/constants.js'
|
||||
import { ref, shallowRef } from 'vue'
|
||||
import { stackedLineTooltipFormatter } from '@/views/charts/charts/tools'
|
||||
import _ from 'lodash'
|
||||
import { get } from '@/utils/http'
|
||||
import axios from 'axios'
|
||||
import { api } from '@/utils/api'
|
||||
import { getSecond } from '@/utils/date-util'
|
||||
import ChartNoData from '@/views/charts/charts/ChartNoData'
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
||||
import { getLineType, 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: {
|
||||
@@ -116,7 +122,7 @@ export default {
|
||||
label: 'Maximum'
|
||||
}
|
||||
],
|
||||
mpackets: [
|
||||
tabsTemplate: [
|
||||
{ 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: '' },
|
||||
@@ -124,6 +130,7 @@ 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: [],
|
||||
@@ -169,7 +176,7 @@ export default {
|
||||
metric (n) {
|
||||
this.handleActiveBar()
|
||||
this.showMarkLine = !this.showMarkLine
|
||||
this.mpackets.forEach((e) => {
|
||||
this.tabs.forEach((e) => {
|
||||
if (!e.invertTab) {
|
||||
e.invertTab = true
|
||||
}
|
||||
@@ -186,161 +193,23 @@ export default {
|
||||
startTime: getSecond(this.timeFilter.startTime),
|
||||
endTime: getSecond(this.timeFilter.endTime)
|
||||
}
|
||||
let condition = ''
|
||||
if (this.queryCondition && this.tabOperationType !== '3') {
|
||||
if (this.queryCondition) {
|
||||
params.q = this.queryCondition
|
||||
} else if (this.tabOperationType == '3' && this.queryCondition) {
|
||||
if (this.queryCondition.indexOf(' OR ') > -1) {
|
||||
if (this.networkOverviewBeforeTab === 'isp') {
|
||||
condition = this.queryCondition.split(/["|'= ](.*?)["|'= ]/)
|
||||
params.q = `notEmpty(${condition[0]}) OR notEmpty(${condition[9]})`
|
||||
} else {
|
||||
condition = this.queryCondition.split(/["|'= ](.*?)["|'= ]/)
|
||||
params.q = `notEmpty(${condition[0]}) OR notEmpty(${condition[5]})`
|
||||
}
|
||||
} else {
|
||||
condition = this.queryCondition.split(/['=](.*?)['=]/)
|
||||
params.q = `notEmpty(${condition[0]})`
|
||||
}
|
||||
}
|
||||
this.toggleLoading(true)
|
||||
|
||||
get(api.netWorkOverview.totalTrafficAnalysis, params).then((res) => {
|
||||
axios.get(api.netWorkOverview.totalTrafficAnalysis, { params: params }).then(response => {
|
||||
const res = response.data
|
||||
// const res = mockData.bytes.boundary.data
|
||||
this.errorMsg = res.message
|
||||
|
||||
if (res.code === 200) {
|
||||
this.isNoData = res.data.result.length === 0
|
||||
this.showError = false
|
||||
|
||||
if (this.isNoData) {
|
||||
this.lineTab = ''
|
||||
this.mpackets = [
|
||||
{ analysis: {}, name: 'network.total', class: 'total', show: true, invertTab: true, positioning: 0, data: [], unitType: '' },
|
||||
{ analysis: {}, name: 'network.inbound', class: 'inbound', show: true, invertTab: true, positioning: 1, data: [], unitType: '' },
|
||||
{ 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: '' }
|
||||
]
|
||||
this.tabs = _.cloneDeep(this.tabsTemplate)
|
||||
} else {
|
||||
this.initData(res.data.result, val, active, show, n)
|
||||
}
|
||||
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
|
||||
@@ -377,163 +246,163 @@ export default {
|
||||
}
|
||||
},
|
||||
echartsInit (echartsData, show) {
|
||||
if (this.lineTab) {
|
||||
this.handleActiveBar()
|
||||
echartsData = echartsData.filter(t => t.show === true && t.invertTab === false)
|
||||
} else {
|
||||
echartsData = echartsData.filter(t => t.show === true)
|
||||
}
|
||||
const _this = this
|
||||
// !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) => {
|
||||
return {
|
||||
...chartOption,
|
||||
name: t.name,
|
||||
lineStyle: {
|
||||
color: chartColor3[t.positioning],
|
||||
width: 1
|
||||
},
|
||||
stack: t.name !== 'network.total' ? 'network.total' : '',
|
||||
symbolSize: function (value) {
|
||||
return _this.symbolSizeSortChange(i, value[0])
|
||||
},
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
borderColor: chartColor4[t.positioning],
|
||||
borderWidth: 2,
|
||||
shadowColor: chartColor4[t.positioning],
|
||||
shadowBlur: this.sizes[t.positioning] + 2
|
||||
}
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.1,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: chartColor3[t.positioning]
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: chartColor3[t.positioning]
|
||||
}
|
||||
])
|
||||
},
|
||||
data: t.data.map(v => [Number(v[0]) * 1000, Number(v[1]), 'number']),
|
||||
markLine: {
|
||||
silent: true,
|
||||
lineStyle: {
|
||||
color: '#B4B1A8'
|
||||
},
|
||||
symbol: 'none',
|
||||
label: {
|
||||
formatter (params) {
|
||||
const arr = unitConvert(params.value, unitTypes.number).join('')
|
||||
return _this.lineRefer + '(' + arr + echartsData[0].unitType + ')'
|
||||
},
|
||||
position: 'insideStartTop',
|
||||
color: '#717171',
|
||||
fontFamily: 'NotoSansSChineseRegular'
|
||||
}
|
||||
}
|
||||
// echarts内容在单元测试时不执行
|
||||
if (!this.isUnitTesting) {
|
||||
if (this.lineTab) {
|
||||
this.handleActiveBar()
|
||||
echartsData = echartsData.filter(t => t.show === true && t.invertTab === false)
|
||||
} else {
|
||||
echartsData = echartsData.filter(t => t.show === true)
|
||||
}
|
||||
})
|
||||
if (!show) {
|
||||
this.chartOption.series.forEach((t) => {
|
||||
t.markLine.label.show = false
|
||||
t.markLine = []
|
||||
})
|
||||
}
|
||||
if (this.lineRefer === 'Average' && show) {
|
||||
this.chartOption.series.forEach((t, i) => {
|
||||
t.markLine.label.show = true
|
||||
t.markLine.data = [
|
||||
{
|
||||
yAxis: echartsData[i].analysis.avg
|
||||
}
|
||||
]
|
||||
})
|
||||
} else if (this.lineRefer === '95th Percentile' && show) {
|
||||
this.chartOption.series.forEach((t, i) => {
|
||||
t.markLine.label.show = true
|
||||
t.markLine.data = [
|
||||
{ yAxis: echartsData[i].analysis.p95 }
|
||||
]
|
||||
})
|
||||
} else if (this.lineRefer === 'Maximum' && show) {
|
||||
this.chartOption.series.forEach((t, i) => {
|
||||
t.markLine.label.show = true
|
||||
t.markLine.data = [
|
||||
{ yAxis: echartsData[i].analysis.max }
|
||||
]
|
||||
})
|
||||
}
|
||||
this.chartOption.tooltip.formatter = (params) => {
|
||||
params.forEach(t => {
|
||||
t.seriesName = this.$t(t.seriesName)
|
||||
this.mpackets.forEach(e => {
|
||||
if (this.$t(e.name) === t.seriesName) {
|
||||
t.borderColor = chartColor3[e.positioning]
|
||||
}
|
||||
})
|
||||
})
|
||||
return stackedLineTooltipFormatter(params)
|
||||
}
|
||||
this.showMarkLine = true
|
||||
this.$nextTick(() => {
|
||||
this.myChart = echarts.init(dom)
|
||||
this.myChart.setOption(this.chartOption)
|
||||
// 设置参见官网:https://echarts.apache.org/zh/api.html#action.brush.brush
|
||||
this.myChart.dispatchAction({
|
||||
// 刷选模式的开关。使用此 action 可将当前鼠标变为可刷选状态。事实上,点击 toolbox 中的 brush 按钮时,就是通过这个 action,将当前普通鼠标变为刷选器的。
|
||||
type: 'takeGlobalCursor',
|
||||
// 如果想变为“可刷选状态”,必须设置。不设置则会关闭“可刷选状态”。
|
||||
key: 'brush',
|
||||
brushOption: {
|
||||
// 参见 brush 组件的 brushType。如果设置为 false 则关闭“可刷选状态”。
|
||||
brushType: 'lineX',
|
||||
xAxisIndex: 'all',
|
||||
// 单击清除选框
|
||||
brushMode: 'single',
|
||||
// 选择完毕再返回所选数据
|
||||
throttleType: 'debounce'
|
||||
}
|
||||
})
|
||||
|
||||
const self = this
|
||||
|
||||
this.myChart.on('brushEnd', function (params) {
|
||||
self.myChart.dispatchAction({
|
||||
type: 'brush',
|
||||
areas: [] // 删除选框
|
||||
})
|
||||
if (!self.mouseDownFlag) {
|
||||
// 避免点击空白区域报错
|
||||
if (params.areas !== undefined && params.areas.length > 0) {
|
||||
self.brushHistory.unshift({
|
||||
startTime: _.cloneDeep(self.timeFilter.startTime) * 1000,
|
||||
endTime: _.cloneDeep(self.timeFilter.endTime) * 1000
|
||||
})
|
||||
|
||||
const rangeObj = {
|
||||
startTime: Math.ceil(params.areas[0].coordRange[0]),
|
||||
endTime: Math.ceil(params.areas[0].coordRange[1])
|
||||
const _this = this
|
||||
// !this.myChart && (this.myChart = echarts.init(dom))
|
||||
// 此处为验证是否因dom未销毁,导致图表出错,后续可能会改
|
||||
this.chartOption = stackedLineChartOption
|
||||
const chartOption = this.chartOption.series[0]
|
||||
this.chartOption.series = echartsData.map((t, i) => {
|
||||
return {
|
||||
...chartOption,
|
||||
name: t.name,
|
||||
lineStyle: {
|
||||
color: chartColor3[t.positioning],
|
||||
width: 1
|
||||
},
|
||||
stack: t.name !== 'network.total' ? 'network.total' : '',
|
||||
symbolSize: function (value) {
|
||||
return _this.symbolSizeSortChange(i, value[0])
|
||||
},
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
borderColor: chartColor4[t.positioning],
|
||||
borderWidth: 2,
|
||||
shadowColor: chartColor4[t.positioning],
|
||||
shadowBlur: this.sizes[t.positioning] + 2
|
||||
}
|
||||
|
||||
// todo 目前暂定框选最小范围为5分钟,后续可能会变动
|
||||
if (rangeObj.endTime - rangeObj.startTime < 5 * 60 * 1000) {
|
||||
rangeObj.startTime = rangeObj.endTime - 5 * 60 * 1000
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.1,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: chartColor3[t.positioning]
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: chartColor3[t.positioning]
|
||||
}
|
||||
])
|
||||
},
|
||||
data: t.data.map(v => [Number(v[0]) * 1000, Number(v[1]), 'number']),
|
||||
markLine: {
|
||||
silent: true,
|
||||
lineStyle: {
|
||||
color: '#B4B1A8'
|
||||
},
|
||||
symbol: 'none',
|
||||
label: {
|
||||
formatter (params) {
|
||||
const arr = unitConvert(params.value, unitTypes.number).join('')
|
||||
return _this.lineRefer + '(' + arr + echartsData[0].unitType + ')'
|
||||
},
|
||||
position: 'insideStartTop',
|
||||
color: '#717171',
|
||||
fontFamily: 'NotoSansSChineseRegular'
|
||||
}
|
||||
_this.$store.commit('setRangeEchartsData', rangeObj)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
if (!show) {
|
||||
this.chartOption.series.forEach((t) => {
|
||||
t.markLine.label.show = false
|
||||
t.markLine = []
|
||||
})
|
||||
}
|
||||
if (this.lineRefer === 'Average' && show) {
|
||||
this.chartOption.series.forEach((t, i) => {
|
||||
t.markLine.label.show = true
|
||||
t.markLine.data = [
|
||||
{
|
||||
yAxis: echartsData[i].analysis.avg
|
||||
}
|
||||
]
|
||||
})
|
||||
} else if (this.lineRefer === '95th Percentile' && show) {
|
||||
this.chartOption.series.forEach((t, i) => {
|
||||
t.markLine.label.show = true
|
||||
t.markLine.data = [
|
||||
{ yAxis: echartsData[i].analysis.p95 }
|
||||
]
|
||||
})
|
||||
} else if (this.lineRefer === 'Maximum' && show) {
|
||||
this.chartOption.series.forEach((t, i) => {
|
||||
t.markLine.label.show = true
|
||||
t.markLine.data = [
|
||||
{ yAxis: echartsData[i].analysis.max }
|
||||
]
|
||||
})
|
||||
}
|
||||
this.chartOption.tooltip.formatter = (params) => {
|
||||
params.forEach(t => {
|
||||
t.seriesName = this.$t(t.seriesName)
|
||||
this.tabs.forEach(e => {
|
||||
if (this.$t(e.name) === t.seriesName) {
|
||||
t.borderColor = chartColor3[e.positioning]
|
||||
}
|
||||
})
|
||||
})
|
||||
return stackedLineTooltipFormatter(params)
|
||||
}
|
||||
this.showMarkLine = true
|
||||
this.$nextTick(() => {
|
||||
this.myChart = echarts.init(this.$refs.overviewLineChart)
|
||||
this.myChart.setOption(this.chartOption)
|
||||
// 设置参见官网:https://echarts.apache.org/zh/api.html#action.brush.brush
|
||||
this.myChart.dispatchAction({
|
||||
// 刷选模式的开关。使用此 action 可将当前鼠标变为可刷选状态。事实上,点击 toolbox 中的 brush 按钮时,就是通过这个 action,将当前普通鼠标变为刷选器的。
|
||||
type: 'takeGlobalCursor',
|
||||
// 如果想变为“可刷选状态”,必须设置。不设置则会关闭“可刷选状态”。
|
||||
key: 'brush',
|
||||
brushOption: {
|
||||
// 参见 brush 组件的 brushType。如果设置为 false 则关闭“可刷选状态”。
|
||||
brushType: 'lineX',
|
||||
xAxisIndex: 'all',
|
||||
// 单击清除选框
|
||||
brushMode: 'single',
|
||||
// 选择完毕再返回所选数据
|
||||
throttleType: 'debounce'
|
||||
}
|
||||
})
|
||||
|
||||
const self = this
|
||||
|
||||
this.myChart.on('brushEnd', function (params) {
|
||||
self.myChart.dispatchAction({
|
||||
type: 'brush',
|
||||
areas: [] // 删除选框
|
||||
})
|
||||
if (!self.mouseDownFlag) {
|
||||
// 避免点击空白区域报错
|
||||
if (params.areas !== undefined && params.areas.length > 0) {
|
||||
self.brushHistory.unshift({
|
||||
startTime: _.cloneDeep(self.timeFilter.startTime) * 1000,
|
||||
endTime: _.cloneDeep(self.timeFilter.endTime) * 1000
|
||||
})
|
||||
|
||||
const rangeObj = {
|
||||
startTime: Math.ceil(params.areas[0].coordRange[0]),
|
||||
endTime: Math.ceil(params.areas[0].coordRange[1])
|
||||
}
|
||||
|
||||
// todo 目前暂定框选最小范围为5分钟,后续可能会变动
|
||||
if (rangeObj.endTime - rangeObj.startTime < 5 * 60 * 1000) {
|
||||
rangeObj.startTime = rangeObj.endTime - 5 * 60 * 1000
|
||||
}
|
||||
_this.$store.commit('setRangeEchartsData', rangeObj)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
activeChange (item, index) {
|
||||
if (this.isNoData) return
|
||||
@@ -565,16 +434,16 @@ export default {
|
||||
legendSelectChange (item, index, val) {
|
||||
if (index === 'index') {
|
||||
this.dispatchLegendSelectAction(item.name)
|
||||
} else if (this.mpackets[index] && this.mpackets[index].name === item.name) {
|
||||
} else if (this.tabs[index] && this.tabs[index].name === item.name) {
|
||||
this.dispatchLegendSelectAction(item.name)
|
||||
this.mpackets.forEach((t) => {
|
||||
this.tabs.forEach((t) => {
|
||||
if (t.name !== item.name) {
|
||||
this.dispatchLegendUnSelectAction(t.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
if (val === 'active') {
|
||||
this.mpackets.forEach(t => {
|
||||
this.tabs.forEach(t => {
|
||||
if (item.name === t.name) {
|
||||
t.invertTab = !t.invertTab
|
||||
} else {
|
||||
@@ -586,7 +455,7 @@ export default {
|
||||
} else {
|
||||
this.lineTab = t.class
|
||||
}
|
||||
this.mpackets.forEach((e) => {
|
||||
this.tabs.forEach((e) => {
|
||||
this.dispatchLegendSelectAction(e.name)
|
||||
})
|
||||
}
|
||||
@@ -594,8 +463,8 @@ export default {
|
||||
}
|
||||
},
|
||||
handleActiveBar () {
|
||||
if (document.querySelector('.network .line-value-mpackets.is-active')) {
|
||||
const { offsetLeft, clientWidth, clientLeft } = document.querySelector('.network .line-value-mpackets.is-active')
|
||||
if (document.querySelector('.network .line-value-tabs.is-active')) {
|
||||
const { offsetLeft, clientWidth, clientLeft } = document.querySelector('.network .line-value-tabs.is-active')
|
||||
const activeBar = document.querySelector('.network .line-value-active')
|
||||
activeBar.style.cssText += `width: ${clientWidth}px; left: ${offsetLeft + this.leftOffset + clientLeft}px;`
|
||||
}
|
||||
@@ -606,32 +475,34 @@ export default {
|
||||
referenceSelectChange (val) {
|
||||
this.lineRefer = val
|
||||
let echartsData
|
||||
const chartOption = this.myChart.getOption()
|
||||
if (this.lineTab) {
|
||||
echartsData = this.mpackets.filter(t => t.show === true && t.invertTab === false)
|
||||
echartsData = this.tabs.filter(t => t.show === true && t.invertTab === false)
|
||||
} else {
|
||||
echartsData = this.mpackets.filter(t => t.show === true)
|
||||
echartsData = this.tabs.filter(t => t.show === true)
|
||||
}
|
||||
if (this.lineRefer === 'Average' && this.showMarkLine) {
|
||||
chartOption.series.forEach((t, i) => {
|
||||
if (t.name === echartsData[0].name) {
|
||||
t.markLine.data = [{ yAxis: echartsData[0].analysis.avg }]
|
||||
}
|
||||
})
|
||||
} else if (this.lineRefer === '95th Percentile' && this.showMarkLine) {
|
||||
chartOption.series.forEach((t, i) => {
|
||||
if (t.name === echartsData[0].name) {
|
||||
t.markLine.data = [{ yAxis: echartsData[0].analysis.p95 }]
|
||||
}
|
||||
})
|
||||
} else if (this.lineRefer === 'Maximum' && this.showMarkLine) {
|
||||
chartOption.series.forEach((t, i) => {
|
||||
if (t.name === echartsData[0].name) {
|
||||
t.markLine.data = [{ yAxis: echartsData[0].analysis.max }]
|
||||
}
|
||||
})
|
||||
if (!this.isUnitTesting) {
|
||||
const chartOption = this.myChart.getOption()
|
||||
if (this.lineRefer === 'Average' && this.showMarkLine) {
|
||||
chartOption.series.forEach((t, i) => {
|
||||
if (t.name === echartsData[0].name) {
|
||||
t.markLine.data = [{ yAxis: echartsData[0].analysis.avg }]
|
||||
}
|
||||
})
|
||||
} else if (this.lineRefer === '95th Percentile' && this.showMarkLine) {
|
||||
chartOption.series.forEach((t, i) => {
|
||||
if (t.name === echartsData[0].name) {
|
||||
t.markLine.data = [{ yAxis: echartsData[0].analysis.p95 }]
|
||||
}
|
||||
})
|
||||
} else if (this.lineRefer === 'Maximum' && this.showMarkLine) {
|
||||
chartOption.series.forEach((t, i) => {
|
||||
if (t.name === echartsData[0].name) {
|
||||
t.markLine.data = [{ yAxis: echartsData[0].analysis.max }]
|
||||
}
|
||||
})
|
||||
}
|
||||
this.myChart.setOption(chartOption)
|
||||
}
|
||||
this.myChart.setOption(chartOption)
|
||||
},
|
||||
symbolSizeSortChange (index, time) {
|
||||
const dataIntegrationArray = []
|
||||
@@ -681,6 +552,87 @@ 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'
|
||||
})
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 鼠标右键返回框选的时间范围
|
||||
*/
|
||||
@@ -702,11 +654,9 @@ export default {
|
||||
this.myChart = null
|
||||
this.chartOption = null
|
||||
this.timer = setTimeout(() => {
|
||||
if (this.lineTab) {
|
||||
const data = this.mpackets.find(t => t.class === this.lineTab)
|
||||
if (data && data.positioning) {
|
||||
this.activeChange(data, data.positioning)
|
||||
}
|
||||
if (this.lineTab && this.metric !== 'Sessions/s') {
|
||||
const data = this.tabsTemplate.find(t => t.class === this.lineTab)
|
||||
this.activeChange(data, data.positioning)
|
||||
} else {
|
||||
this.init()
|
||||
}
|
||||
@@ -717,11 +667,13 @@ export default {
|
||||
clearTimeout(this.timer)
|
||||
window.removeEventListener('resize', this.resize)
|
||||
|
||||
let myChart = echarts.getInstanceByDom(document.getElementById('overviewLineChart'))
|
||||
let myChart = echarts.getInstanceByDom(this.$refs.overviewLineChart)
|
||||
if (myChart) {
|
||||
echarts.dispose(myChart)
|
||||
}
|
||||
this.myChart = null
|
||||
if (this.myChart) {
|
||||
echarts.dispose(this.myChart)
|
||||
}
|
||||
// 检测时发现该方法占用较大内存,且未被释放
|
||||
this.unitConvert = null
|
||||
myChart = null
|
||||
|
||||
@@ -61,7 +61,6 @@ export default {
|
||||
methods: {
|
||||
init () {
|
||||
const params = {
|
||||
// startTime: true,
|
||||
startTime: getSecond(this.timeFilter.startTime),
|
||||
endTime: getSecond(this.timeFilter.endTime)
|
||||
}
|
||||
@@ -193,6 +192,14 @@ 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
|
||||
}
|
||||
|
||||
@@ -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 db[dbDrilldownTableConfig].put({
|
||||
await indexedDBUtils.selectTable(dbDrilldownTableConfig).put({
|
||||
id: this.userId,
|
||||
version: version,
|
||||
config: this.$_.cloneDeep(curUserConfigGroup)
|
||||
|
||||
@@ -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"></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 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>
|
||||
</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>
|
||||
<span v-if="scope.row.bytesRateChainRatio >= -5">
|
||||
{{unitConvert(scope.row.bytesRateChainRatio, unitTypes.percent).join('').replaceAll('-', '')}}
|
||||
{{unitConvert(scope.row.bytesRateChainRatio, unitTypes.percent).join('').replace(/-/g, '')}}
|
||||
</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>
|
||||
<span v-if="scope.row.outboundBytesRateChainRatio >= -5">
|
||||
{{unitConvert(scope.row.outboundBytesRateChainRatio, unitTypes.percent).join('').replaceAll('-', '')}}
|
||||
{{unitConvert(scope.row.outboundBytesRateChainRatio, unitTypes.percent).join('').replace(/-/g, '')}}
|
||||
</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>
|
||||
<span v-if="scope.row.inboundBytesRateChainRatio <= 5">
|
||||
<span v-if="scope.row.inboundBytesRateChainRatio <= 5" :test-id="`inbound-${scope.row.appSubcategory}`">
|
||||
{{unitConvert(scope.row.inboundBytesRateChainRatio, unitTypes.percent).join('')}}
|
||||
</span>
|
||||
<span v-else>>500.00%</span>
|
||||
<span v-else :test-id="`inbound-${scope.row.appSubcategory}`">>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>
|
||||
<span v-if="scope.row.inboundBytesRateChainRatio >= -5">
|
||||
{{unitConvert(scope.row.inboundBytesRateChainRatio, unitTypes.percent).join('').replaceAll('-', '')}}
|
||||
<span v-if="scope.row.inboundBytesRateChainRatio >= -5" :test-id="`inbound-${scope.row.appSubcategory}`">
|
||||
{{unitConvert(scope.row.inboundBytesRateChainRatio, unitTypes.percent).join('').replace(/-/g, '')}}
|
||||
</span>
|
||||
<span v-else>>500.00%</span>
|
||||
<span v-else :test-id="`inbound-${scope.row.appSubcategory}`">>500.00%</span>
|
||||
</div>
|
||||
<div v-else-if="scope.row.inboundBytesRateChainRatio === 0" class="data-total-trend data-total-trend-black">
|
||||
<div v-else-if="scope.row.inboundBytesRateChainRatio === 0" :test-id="`inbound-${scope.row.appSubcategory}`" 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" :class="{'data-score-red': scope.row.score <= 2}" class="data-score">
|
||||
<div v-if="scope.row.score <= 2" :test-id="`score-${scope.row.appSubcategory}`" class="data-score data-score-red">
|
||||
{{scope.row.score}}
|
||||
</div>
|
||||
<div v-else-if="scope.row.score <= 4" :class="{'data-score-yellow': scope.row.score <= 4}" class="data-score">
|
||||
<div v-else-if="scope.row.score <= 4" :test-id="`score-${scope.row.appSubcategory}`" class="data-score data-score-yellow">
|
||||
{{scope.row.score}}
|
||||
</div>
|
||||
<div v-else-if="scope.row.score <= 6" :class="{'data-score-green': scope.row.score <= 6}" class="data-score">
|
||||
<div v-else-if="scope.row.score <= 6" :test-id="`score-${scope.row.appSubcategory}`" class="data-score data-score-green">
|
||||
{{scope.row.score}}
|
||||
</div>
|
||||
<div v-else-if="scope.row.score === '-'" class="data-score-no-data">
|
||||
<div v-else-if="scope.row.score === '-'" :test-id="`score-${scope.row.appSubcategory}`" class="data-score-no-data">
|
||||
-
|
||||
</div>
|
||||
</template>
|
||||
@@ -138,17 +138,12 @@ import { unitTypes, npmCategoryInfoMapping, networkTable, operationType, npmCate
|
||||
import unitConvert from '@/utils/unit-convert'
|
||||
import { api } from '@/utils/api'
|
||||
import { getSecond } from '@/utils/date-util'
|
||||
import { get } from '@/utils/http'
|
||||
import {
|
||||
getChainRatio,
|
||||
computeScore,
|
||||
urlParamsHandler,
|
||||
overwriteUrl,
|
||||
getUserDrilldownTableConfig
|
||||
} from '@/utils/tools'
|
||||
import { computeScore, getChainRatio, getUserDrilldownTableConfig, overwriteUrl, urlParamsHandler } 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 () {
|
||||
@@ -198,15 +193,15 @@ export default {
|
||||
endTime: getSecond(this.timeFilter.endTime)
|
||||
}
|
||||
// 获取table后三列内容
|
||||
const currentTrafficRequest = get(api.npm.overview.appTrafficAnalysis, { ...params, cycle: 0 })
|
||||
const lastCycleTrafficRequest = get(api.npm.overview.appTrafficAnalysis, { ...params, cycle: 1 })
|
||||
const currentTrafficRequest = axios.get(api.npm.overview.appTrafficAnalysis, { params: { ...params, cycle: 0 } })
|
||||
const lastCycleTrafficRequest = axios.get(api.npm.overview.appTrafficAnalysis, { params: { ...params, cycle: 1 } })
|
||||
this.toggleLoading(true)
|
||||
Promise.all([currentTrafficRequest, lastCycleTrafficRequest]).then(res => {
|
||||
if (res[0].code === 200 && res[1].code === 200) {
|
||||
if (res[0].data.code === 200 && res[1].data.code === 200) {
|
||||
this.showError = false
|
||||
this.errorMsg = ''
|
||||
const prevData = res[1].data.result
|
||||
const data = res[0].data.result
|
||||
const prevData = res[1].data.data.result
|
||||
const data = res[0].data.data.result
|
||||
if (data && data.length > 0) {
|
||||
this.isNoData = false
|
||||
const tableData = data.map(d => {
|
||||
@@ -228,24 +223,23 @@ export default {
|
||||
return result
|
||||
})
|
||||
// 计算分数
|
||||
const tcpRequest = get(api.npm.overview.appTcpSessionDelay, params)
|
||||
const httpRequest = get(api.npm.overview.appHttpResponseDelay, params)
|
||||
const sslRequest = get(api.npm.overview.appSslConDelay, params)
|
||||
const tcpLostRequest = get(api.npm.overview.appTcpLostlenPercent, params)
|
||||
const packetRetransRequest = get(api.npm.overview.appPacketRetransPercent, params)
|
||||
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 })
|
||||
Promise.all([tcpRequest, httpRequest, sslRequest, tcpLostRequest, packetRetransRequest]).then(res => {
|
||||
const keyPre = ['tcp', 'http', 'ssl', 'tcpLost', 'packetRetrans']
|
||||
let msg = ''
|
||||
|
||||
res.forEach((r, i) => {
|
||||
if (r.code === 200) {
|
||||
if (r.data.code === 200) {
|
||||
tableData.forEach(t => {
|
||||
const find = r.data.result.find(d => d.appSubcategory === t.appSubcategory)
|
||||
t[keyPre[i] + 'Score'] = find
|
||||
t[keyPre[i] + 'Score'] = r.data.data.result.find(d => d.appSubcategory === t.appSubcategory)
|
||||
})
|
||||
} else {
|
||||
this.showError = true
|
||||
msg = msg + ',' + r.message
|
||||
msg = msg + ',' + r.data.data.message
|
||||
if (msg.indexOf(',') === 0) {
|
||||
msg = msg.substring(1, msg.length)
|
||||
}
|
||||
@@ -348,7 +342,7 @@ export default {
|
||||
}
|
||||
})
|
||||
let toPanel = null
|
||||
list.forEach((item, index) => {
|
||||
list.forEach(item => {
|
||||
if (item.label === tabType) {
|
||||
item.checked = false
|
||||
toPanel = item.panelId
|
||||
@@ -360,8 +354,7 @@ export default {
|
||||
this.$store.commit('setNetworkOverviewTabList', list)
|
||||
const tabObjGroup = list.filter(item => item.checked)
|
||||
if (tabObjGroup && tabObjGroup.length > 0) {
|
||||
const curTab = tabObjGroup[0]
|
||||
this.urlChangeParams[this.curTabState.curTab] = curTab
|
||||
this.urlChangeParams[this.curTabState.curTab] = tabObjGroup[0]
|
||||
}
|
||||
this.changeUrlTabState()
|
||||
this.$router.push({
|
||||
@@ -384,6 +377,9 @@ export default {
|
||||
},
|
||||
mounted () {
|
||||
this.init()
|
||||
},
|
||||
beforeUnmount () {
|
||||
this.unitConvert = null
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,29 +1,11 @@
|
||||
<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=""
|
||||
>
|
||||
@@ -33,34 +15,33 @@
|
||||
<span class="data-column__span">{{ $t(item.label) }}</span>
|
||||
</template>
|
||||
<template #default="scope" :column="item">
|
||||
<div class="data-app-event-table">
|
||||
<div class="data-app-event-table" :test-id="`${item.prop}${scope.row.index}`">
|
||||
<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"></div>
|
||||
<div v-for="item in 5" class="red-dot" :key="item" :test-id="`eventSeverityValue${scope.row.index}${item}`"></div>
|
||||
</template>
|
||||
<template v-else-if="scope.row[item.prop]==='high'">
|
||||
<div v-for="item in 4" class="red-dot" :key="item"></div>
|
||||
<div class="grey-dot"></div>
|
||||
<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>
|
||||
</template>
|
||||
<template v-else-if="scope.row[item.prop]==='medium'">
|
||||
<div v-for="item in 3" class="red-dot" :key="item"></div>
|
||||
<div v-for="item in 2" class="grey-dot" :key="item"></div>
|
||||
<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>
|
||||
</template>
|
||||
<template v-else-if="scope.row[item.prop]==='low'">
|
||||
<div v-for="item in 2" class="red-dot" :key="item"></div>
|
||||
<div v-for="item in 3" class="grey-dot" :key="item"></div>
|
||||
<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>
|
||||
</template>
|
||||
<template v-else-if="scope.row[item.prop]==='info'">
|
||||
<div v-for="item in 1" class="red-dot" :key="item"></div>
|
||||
<div v-for="item in 4" class="grey-dot" :key="item"></div>
|
||||
<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>
|
||||
</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'">
|
||||
@@ -153,6 +134,10 @@ export default {
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
rowClassName ({ row, rowIndex }) {
|
||||
// 把每一行的索引放进row
|
||||
row.index = rowIndex
|
||||
},
|
||||
init () {
|
||||
this.toggleLoading(true)
|
||||
this.isNoData = false
|
||||
|
||||
@@ -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">{{legend.name}}</div>
|
||||
<div class="npm-event-pie-legend-type-severity" :test-id="`testNode${index}`">{{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">{{legend.value}}</div>
|
||||
<div class="npm-event-pie-legend-total" :test-id="`total${index}`">{{legend.value}}</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
@@ -31,7 +31,6 @@
|
||||
|
||||
<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'
|
||||
@@ -39,6 +38,7 @@ 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,7 +108,8 @@ export default {
|
||||
type: 'severity'
|
||||
}
|
||||
this.toggleLoading(true)
|
||||
get(api.npm.events.recentEvents, params).then(res => {
|
||||
axios.get(api.npm.events.recentEvents, { params: params }).then(res => {
|
||||
res = res.data
|
||||
if (res.code === 200) {
|
||||
this.showError = false
|
||||
this.isNoData = res.data.result.length === 0
|
||||
@@ -126,7 +127,9 @@ export default {
|
||||
this.chartData = arrData.sort((a, b) => { return b.value - a.value })
|
||||
this.$nextTick(() => {
|
||||
if (this.chartData.length > 0) {
|
||||
this.init()
|
||||
if (!this.isUnitTesting) {
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
@@ -152,7 +155,9 @@ export default {
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('resize', this.resize)
|
||||
this.myChart = null
|
||||
if (this.myChart) {
|
||||
echarts.dispose(this.myChart)
|
||||
}
|
||||
this.chartOption = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"></div>
|
||||
<div class="npm-header-body-severity-value">{{item.eventSeverity}}</div>
|
||||
<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>
|
||||
<chart-error v-if="showError" tooltip :content="errorMsg" />
|
||||
<div v-else class="npm-header-body-total">{{item.count}}</div>
|
||||
<div v-else class="npm-header-body-total" :test-id="`total${index}`">{{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,12 +65,13 @@ export default {
|
||||
methods: {
|
||||
recentEventsListData () {
|
||||
const params = {
|
||||
startTime: getSecond(this.timeFilter.startTime),
|
||||
endTime: getSecond(this.timeFilter.endTime),
|
||||
startTime: this.timeFilter && this.timeFilter.startTime ? getSecond(this.timeFilter.startTime) : '',
|
||||
endTime: this.timeFilter && this.timeFilter.endTime ? getSecond(this.timeFilter.endTime) : '',
|
||||
type: this.type
|
||||
}
|
||||
this.toggleLoading(true)
|
||||
get(api.npm.events.list, params).then(res => {
|
||||
axios.get(api.npm.events.list, { params: params }).then(res => {
|
||||
res = res.data
|
||||
if (res.code === 200) {
|
||||
this.showError = false
|
||||
if (res.data.result.length === 0) {
|
||||
@@ -96,7 +97,9 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.recentEventsListData()
|
||||
this.$nextTick(() => {
|
||||
this.recentEventsListData()
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -336,7 +336,9 @@ export default {
|
||||
beforeUnmount () {
|
||||
clearTimeout(this.timer)
|
||||
window.removeEventListener('resize', this.resize)
|
||||
this.myChart = null
|
||||
if (this.myChart) {
|
||||
echarts.dispose(this.myChart)
|
||||
}
|
||||
this.chartOption = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,60 @@
|
||||
<template>
|
||||
<div class="npm-network-quantity">
|
||||
<single-value
|
||||
v-if="npmNetworkData.length>0"
|
||||
:npm-network-name="npmNetworkName"
|
||||
:npm-network-data="npmNetworkData"
|
||||
></single-value>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
</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'
|
||||
@@ -18,9 +62,11 @@ 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()
|
||||
@@ -39,6 +85,8 @@ export default {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
unitTypes,
|
||||
unitConvert,
|
||||
npmNetworkName: [
|
||||
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency' },
|
||||
{ name: 'networkAppPerformance.httpResponse' },
|
||||
@@ -48,6 +96,7 @@ export default {
|
||||
],
|
||||
npmNetworkCycleData: [],
|
||||
npmNetworkLastCycleData: [],
|
||||
newNpmNetworkData: [],
|
||||
npmNetworkData: [],
|
||||
side: '',
|
||||
chartData: {},
|
||||
@@ -68,7 +117,7 @@ export default {
|
||||
npmNetworkCycleQuery () {
|
||||
let condition = ''
|
||||
let url = ''
|
||||
if (this.queryCondition.indexOf(' OR ') > -1) {
|
||||
if (this.queryCondition && this.queryCondition.indexOf(' OR ') > -1) {
|
||||
condition = this.queryCondition.split(/["|'](.*?)["|']/)
|
||||
} else {
|
||||
condition = this.queryCondition
|
||||
@@ -84,37 +133,38 @@ export default {
|
||||
} else if (parseFloat(this.tabIndex) === 1) {
|
||||
this.side = 'server'
|
||||
}
|
||||
if (condition && (typeof condition !== 'object') && type) {
|
||||
if (type === 'clientIp' || type === 'serverIp') {
|
||||
if (parseFloat(this.tabIndex) === 0) {
|
||||
if (condition && (typeof condition !== 'object') && type) { // 判断 condition 不为空并且不为对象 type 不为空
|
||||
if (type === 'clientIp' || type === 'serverIp') { // type = clientIp || serverIp
|
||||
if (parseFloat(this.tabIndex) === 0) { // npm 下钻 tabIndex 为 0
|
||||
type = 'clientIp'
|
||||
} else if (parseFloat(this.tabIndex) === 1) {
|
||||
} else if (parseFloat(this.tabIndex) === 1) { // npm 下钻 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') {
|
||||
params.q = `${type}='${condition[1]}' and side='${this.side}'`
|
||||
} else if (condition.length > 1 && type && type === 'ip') { // condition 为数组时数组长度不为 0 | type 不为空 | type为ip
|
||||
params.q = `${type}='${condition[1]}' and side='${this.side}'` // 拼接字段作为参数
|
||||
params.type = type
|
||||
} else if (condition.length > 1 && type && type !== 'ip') {
|
||||
if (type === 'country' || type === 'asn' || type === 'province' || type === 'city' || type === 'isp') {
|
||||
params.q = `${type}='${condition[1]}'`
|
||||
} 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]}'` // 拼接字段作为参数
|
||||
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 {
|
||||
@@ -123,7 +173,8 @@ export default {
|
||||
if ((type && condition) || type) {
|
||||
params.type = params.type || type
|
||||
this.toggleLoading(true)
|
||||
get(url, params).then(res => {
|
||||
axios.get(url, { params: params }).then(res => {
|
||||
res = res.data
|
||||
if (res.code === 200) {
|
||||
this.npmNetworkCycleData = res.data.result
|
||||
}
|
||||
@@ -133,21 +184,21 @@ export default {
|
||||
this.toggleLoading(false)
|
||||
})
|
||||
} else {
|
||||
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)
|
||||
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 })
|
||||
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.code === 200) {
|
||||
this.npmNetworkCycleData.push(t.data.result)
|
||||
if (t.data.code === 200) {
|
||||
this.npmNetworkCycleData.push(t.data.data.result)
|
||||
} else {
|
||||
this.npmNetworkCycleData.push(t)
|
||||
this.npmNetworkCycleData.push(t.data)
|
||||
}
|
||||
})
|
||||
this.npmNetworkLastCycleQuery()
|
||||
@@ -177,7 +228,8 @@ export default {
|
||||
if ((params.type && params.q) || (param && param.type)) {
|
||||
params.type = params.type || param.type
|
||||
this.toggleLoading(true)
|
||||
get(url, params).then(res => {
|
||||
axios.get(url, { params: params }).then(res => {
|
||||
res = res.data
|
||||
if (res.code === 200) {
|
||||
this.npmNetworkLastCycleData = res.data.result
|
||||
} else {
|
||||
@@ -195,20 +247,20 @@ export default {
|
||||
this.toggleLoading(false)
|
||||
})
|
||||
} else {
|
||||
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)
|
||||
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 })
|
||||
this.toggleLoading(true)
|
||||
Promise.all([tcp, http, ssl, tcpPercent, packetPercent]).then(res => {
|
||||
// 状态为200的,赋值接口数据,不为200的保留报错提示message,
|
||||
// 传给子组件SingleValue,再进行error处理,注:error处理不在此处处理
|
||||
res.forEach(t => {
|
||||
if (t.code === 200) {
|
||||
this.npmNetworkLastCycleData.push(t.data.result)
|
||||
if (t.data.code === 200) {
|
||||
this.npmNetworkLastCycleData.push(t.data.data.result)
|
||||
} else {
|
||||
this.npmNetworkLastCycleData.push(t)
|
||||
this.npmNetworkLastCycleData.push(t.data)
|
||||
}
|
||||
this.npmNetworkQuantity(this.npmNetworkCycleData, this.npmNetworkLastCycleData, 1)
|
||||
})
|
||||
@@ -271,6 +323,39 @@ 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 () {
|
||||
@@ -282,6 +367,7 @@ export default {
|
||||
beforeUnmount () {
|
||||
clearTimeout(this.timer1)
|
||||
clearTimeout(this.timer2)
|
||||
this.unitConvert = null
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -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]">{{scope.row[item.prop]}}</span>
|
||||
<span class="data-recent-table-severity" :class="scope.row[item.prop]" :test-id="`eventSeverity-${scope.row.eventSeverity}-${scope.$index}`">{{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)">{{splitEventKey(scope.row[item.prop])}}</span>
|
||||
<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>
|
||||
</template>
|
||||
<template v-else-if="item.prop === 'eventType'">
|
||||
<span class="data-recent-table-eventType">{{scope.row[item.prop]}}</span>
|
||||
<span class="data-recent-table-eventType" :test-id="`eventType-${scope.row.eventType}-${scope.$index}`">{{scope.row[item.prop]}}</span>
|
||||
</template>
|
||||
<span v-else-if="scope.row[item.prop]">{{scope.row[item.prop]}}</span>
|
||||
<span v-else-if="scope.row[item.prop]" :test-id="`startTime-${scope.$index}`">{{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.length > 1 && this.dimensionType) {
|
||||
if (condition && condition.length > 1 && this.dimensionType) {
|
||||
params.param = condition[1]
|
||||
params.type = this.dimensionType
|
||||
if (params.type === 'serverIp' || params.type === 'clientIp') params.type = 'ip'
|
||||
@@ -114,7 +114,8 @@ export default {
|
||||
url = api.npm.events.recentEvents
|
||||
}
|
||||
this.toggleLoading(true)
|
||||
get(url, params).then(res => {
|
||||
axios.get(url, { params: params }).then(res => {
|
||||
res = res.data
|
||||
if (res.code === 200) {
|
||||
this.showError = false
|
||||
this.isNoData = res.data.result.length === 0
|
||||
@@ -151,6 +152,7 @@ export default {
|
||||
return name
|
||||
},
|
||||
jumpPage (item) {
|
||||
this.beforeRouterPush()
|
||||
this.$router.push({
|
||||
path: '/detection/performanceEvent',
|
||||
query: {
|
||||
@@ -158,6 +160,36 @@ 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 () {
|
||||
|
||||
@@ -22,7 +22,6 @@ 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',
|
||||
|
||||
@@ -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 { overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
||||
import { getLineType, getLineIndexUnit, overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
||||
import ChartError from '@/components/common/Error'
|
||||
|
||||
export default {
|
||||
@@ -71,7 +71,7 @@ export default {
|
||||
unitConvert,
|
||||
unitTypes,
|
||||
side: '',
|
||||
mpackets: [
|
||||
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' },
|
||||
@@ -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 },
|
||||
{ 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 }
|
||||
{ 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 }
|
||||
],
|
||||
chartData: {},
|
||||
metricOptions: [
|
||||
@@ -144,7 +144,6 @@ 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) {
|
||||
@@ -200,7 +199,7 @@ export default {
|
||||
this.showError = false
|
||||
this.isNoData = res.data.result.length === 0
|
||||
if (this.isNoData) {
|
||||
this.mpackets = [
|
||||
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' },
|
||||
@@ -209,92 +208,15 @@ 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 },
|
||||
{ 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 }
|
||||
{ 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(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
|
||||
@@ -308,204 +230,50 @@ export default {
|
||||
this.toggleLoading(false)
|
||||
})
|
||||
} else {
|
||||
if (val === 'Bits/s' || val === 'Packets/s' || val === 'Sessions/s') {
|
||||
this.toggleLoading(true)
|
||||
get(api.npm.overview.totalTrafficAnalysis, params).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.showError = false
|
||||
this.isNoData = res.data.result.length === 0
|
||||
if (this.isNoData) {
|
||||
this.mpackets = [
|
||||
{ name: 'network.total', show: true, positioning: 0, data: [], unitType: 'number' },
|
||||
{ name: 'network.inbound', show: true, positioning: 1, data: [], unitType: 'number' },
|
||||
{ name: 'network.outbound', show: true, positioning: 2, data: [], unitType: 'number' },
|
||||
{ name: 'network.internal', show: true, positioning: 3, data: [], unitType: 'number' },
|
||||
{ name: 'network.through', show: true, positioning: 4, data: [], unitType: 'number' },
|
||||
{ name: 'network.other', show: true, positioning: 5, data: [], unitType: 'number' }
|
||||
]
|
||||
}
|
||||
res.data.result.forEach((t) => {
|
||||
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)
|
||||
}
|
||||
})
|
||||
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)
|
||||
} else {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.errorMsg = res.message
|
||||
}
|
||||
}).catch(e => {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.errorMsg = e.message
|
||||
}).finally(() => {
|
||||
this.toggleLoading(false)
|
||||
})
|
||||
} else if (val === 'establishLatencyMs' || val === 'tcpLostlenPercent' || val === 'pktRetransPercent') {
|
||||
this.toggleLoading(true)
|
||||
get(api.npm.overview.totalNetworkAnalysis, params).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.showError = false
|
||||
this.isNoData = res.data.result.length === 0
|
||||
if (this.isNoData) {
|
||||
this.npmQuantity = [
|
||||
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
|
||||
{ name: 'networkAppPerformance.httpResponse', show: true, positioning: 0, data: [], unitType: unitTypes.time },
|
||||
{ name: 'networkAppPerformance.sslResponseLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
|
||||
{ name: 'networkAppPerformance.packetLoss', show: true, positioning: 0, data: [], unitType: unitTypes.percent },
|
||||
{ name: 'overall.packetRetrans', show: true, positioning: 0, data: [], unitType: unitTypes.percent }
|
||||
]
|
||||
}
|
||||
res.data.result.forEach((t) => {
|
||||
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)
|
||||
})
|
||||
}
|
||||
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
|
||||
this.errorMsg = e.message
|
||||
}).finally(() => {
|
||||
this.toggleLoading(false)
|
||||
})
|
||||
}
|
||||
},
|
||||
echartsInit (echartsData, legendUnit) {
|
||||
@@ -552,7 +320,7 @@ export default {
|
||||
})
|
||||
this.chartOption.tooltip.formatter = (params) => {
|
||||
params.forEach(t => {
|
||||
this.mpackets.forEach(e => {
|
||||
this.tabs.forEach(e => {
|
||||
if (e.name === t.seriesName) {
|
||||
t.borderColor = chartColor3[e.positioning]
|
||||
}
|
||||
@@ -619,6 +387,67 @@ 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 () {
|
||||
@@ -633,8 +462,9 @@ export default {
|
||||
beforeUnmount () {
|
||||
clearTimeout(this.timer)
|
||||
window.removeEventListener('resize', this.resize)
|
||||
this.myChart = null
|
||||
this.myChart = null
|
||||
if (this.myChart) {
|
||||
echarts.dispose(this.myChart)
|
||||
}
|
||||
this.unitConvert = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
@@ -134,15 +134,7 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
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)
|
||||
}
|
||||
}
|
||||
this.initExpendTab()
|
||||
},
|
||||
computed: {
|
||||
iconClass () {
|
||||
@@ -186,7 +178,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 {
|
||||
@@ -207,6 +199,33 @@ 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 ">{{detection.eventType || '-'}}</div>
|
||||
<div class="row__content--metric ">{{getNameByEventType(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 } from '@/utils/tools'
|
||||
import { sortBy, reverseSortBy, getNameByEventType } from '@/utils/tools'
|
||||
import _ from 'lodash'
|
||||
export default {
|
||||
name: 'DetectionPerformanceEventAppOverview',
|
||||
@@ -134,6 +134,7 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getNameByEventType,
|
||||
query () {
|
||||
this.queryBasic().then(responses => {
|
||||
responses && (this.basicInfo = responses)
|
||||
@@ -180,6 +181,10 @@ 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)
|
||||
},
|
||||
|
||||
|
||||
@@ -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 ">{{detection.eventType || '-'}}</div>
|
||||
<div class="row__content--metric ">{{getNameByEventType(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 } from '@/utils/tools'
|
||||
import { sortBy, reverseSortBy, getNameByEventType } from '@/utils/tools'
|
||||
import _ from 'lodash'
|
||||
export default {
|
||||
name: 'DetectionPerformanceEventDomainOverview',
|
||||
@@ -165,6 +165,7 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getNameByEventType,
|
||||
query () {
|
||||
this.queryBasic().then(responses => {
|
||||
responses && (this.basicInfo = responses)
|
||||
@@ -212,6 +213,10 @@ 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)
|
||||
},
|
||||
|
||||
|
||||
@@ -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 ">{{getNameByType(detection.eventType) || '-'}}</div>
|
||||
<div class="row__content--metric ">{{getNameByEventType(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 } from '@/utils/tools'
|
||||
import { sortBy, reverseSortBy, getNameByEventType } from '@/utils/tools'
|
||||
import _ from 'lodash'
|
||||
|
||||
export default {
|
||||
@@ -129,6 +129,7 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getNameByEventType,
|
||||
query () {
|
||||
this.queryBasic().then(responses => {
|
||||
responses && (this.basicInfo = responses)
|
||||
@@ -173,9 +174,11 @@ 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.getNameByType(this.detection.eventType)
|
||||
item.name = this.getNameByEventType(this.detection.eventType)
|
||||
})
|
||||
|
||||
this.chartOptionMetric && this.metricChart.setOption(this.chartOptionMetric)
|
||||
},
|
||||
queryMetric () {
|
||||
@@ -236,29 +239,6 @@ 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 () {
|
||||
|
||||
@@ -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('[', '').split(',', 5).join(', ') : ''
|
||||
responses[0].malwareGroups = responses[0].malwareGroups.length > 2 ? responses[0].malwareGroups.replace('[', '').split(',', 5).join(', ') : ''
|
||||
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].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])
|
||||
|
||||
@@ -22,6 +22,14 @@
|
||||
<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--width130">{{$t('overall.remark')}}</div>
|
||||
<div class="row__content">{{entityData.domainDescription || '-'}}</div>
|
||||
@@ -352,7 +360,9 @@ export default {
|
||||
domainDescription: response.data.result.domainDescription,
|
||||
domainReputationScore: response.data.result.domainReputationScore,
|
||||
domainWhoisAddress: response.data.result.domainWhoisAddress,
|
||||
domainWhoisOrg: response.data.result.domainWhoisOrg
|
||||
domainWhoisOrg: response.data.result.domainWhoisOrg,
|
||||
domainIcpCompanyName: response.data.result.domainIcpCompanyName,
|
||||
domainIcpSiteLicense: response.data.result.domainIcpSiteLicense
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,34 +1,215 @@
|
||||
/**
|
||||
* 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'
|
||||
|
||||
// 模拟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('[data-test="count"]')
|
||||
const button = await wrapper.get('[data-test="button"]')
|
||||
// 断言文本dom的内容是否是'0'
|
||||
expect(textNode.text()).toContain('0')
|
||||
// 模拟按钮dom点击,执行click()方法
|
||||
await button.trigger('click')
|
||||
// 断言点击按钮后文本dom的内容是否是'1'
|
||||
expect(textNode.text()).toContain('1')
|
||||
// 再次点击
|
||||
await button.trigger('click')
|
||||
// 断言点击按钮后文本dom的内容是否是'2'
|
||||
expect(textNode.text()).toContain('2')
|
||||
|
||||
// 通过wrapper.vm.xxx直接执行click方法、获取data的数据
|
||||
expect(wrapper.vm.count).toEqual(2)
|
||||
await wrapper.vm.click()
|
||||
expect(wrapper.vm.count).toEqual(3)
|
||||
|
||||
// 更多断言类型:https://jestjs.io/zh-Hans/docs/expect
|
||||
// 模拟的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]
|
||||
}
|
||||
})
|
||||
// 取到文本和按钮的dom
|
||||
const textNode = await wrapper.get('[test-id="count"]')
|
||||
const button = await wrapper.get('[test-id="button"]')
|
||||
// 断言文本dom的内容是否是'0'
|
||||
expect(textNode.text()).toBe('0')
|
||||
// 模拟按钮dom点击,执行click()方法
|
||||
await button.trigger('click')
|
||||
// 断言点击按钮后文本dom的内容是否是'1'
|
||||
expect(textNode.text()).toBe('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"]')
|
||||
// 通过wrapper.vm.xxx直接执行click方法、获取data的数据
|
||||
expect(wrapper.vm.count).toBe(0)
|
||||
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)
|
||||
|
||||
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')
|
||||
})
|
||||
})
|
||||
|
||||
41
test/init.js
Normal file
41
test/init.js
Normal file
@@ -0,0 +1,41 @@
|
||||
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(() => {})
|
||||
130
test/views/charts2/charts/linkMonitor/LinkBlock.test.js
Normal file
130
test/views/charts2/charts/linkMonitor/LinkBlock.test.js
Normal file
@@ -0,0 +1,130 @@
|
||||
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))
|
||||
})
|
||||
})
|
||||
172
test/views/charts2/charts/linkMonitor/LinkDirectionGrid.test.js
Normal file
172
test/views/charts2/charts/linkMonitor/LinkDirectionGrid.test.js
Normal file
File diff suppressed because one or more lines are too long
109
test/views/charts2/charts/linkMonitor/LinkTrafficLine.test.js
Normal file
109
test/views/charts2/charts/linkMonitor/LinkTrafficLine.test.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,37 @@
|
||||
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))
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,141 @@
|
||||
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/s,0和大数值', 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))
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,73 @@
|
||||
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
|
||||
148
test/views/charts2/charts/npm/NpmAppCategoryScore.test.js
Normal file
148
test/views/charts2/charts/npm/NpmAppCategoryScore.test.js
Normal file
File diff suppressed because one or more lines are too long
258
test/views/charts2/charts/npm/NpmAppEventTable.test.js
Normal file
258
test/views/charts2/charts/npm/NpmAppEventTable.test.js
Normal file
@@ -0,0 +1,258 @@
|
||||
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))
|
||||
})
|
||||
})
|
||||
44
test/views/charts2/charts/npm/NpmEventsByType.test.js
Normal file
44
test/views/charts2/charts/npm/NpmEventsByType.test.js
Normal file
File diff suppressed because one or more lines are too long
54
test/views/charts2/charts/npm/NpmEventsHeader.test.js
Normal file
54
test/views/charts2/charts/npm/NpmEventsHeader.test.js
Normal file
@@ -0,0 +1,54 @@
|
||||
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))
|
||||
})
|
||||
})
|
||||
248
test/views/charts2/charts/npm/NpmNetworkQuantity.test.js
Normal file
248
test/views/charts2/charts/npm/NpmNetworkQuantity.test.js
Normal file
File diff suppressed because one or more lines are too long
162
test/views/charts2/charts/npm/NpmRecentEvents.test.js
Normal file
162
test/views/charts2/charts/npm/NpmRecentEvents.test.js
Normal file
@@ -0,0 +1,162 @@
|
||||
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))
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user