CN-982: 实体详情--流量折线图开发
This commit is contained in:
@@ -79,3 +79,4 @@
|
|||||||
@import 'views/administration/Appearance.scss';
|
@import 'views/administration/Appearance.scss';
|
||||||
|
|
||||||
@import 'views/setting/knowledgeBase';
|
@import 'views/setting/knowledgeBase';
|
||||||
|
@import "views/charts2/EntityDetailLine";
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
.entity-detail-line {
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
.line-header-right {
|
||||||
|
.panel__tools {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
& > .el-select {
|
||||||
|
width: 162px;
|
||||||
|
margin-right: 10px;
|
||||||
|
|
||||||
|
.select-prefix {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #999;
|
||||||
|
padding: 0 6px 0 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input__inner {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #353636;
|
||||||
|
}
|
||||||
|
|
||||||
|
.common-select {
|
||||||
|
top: 32px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel__time {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-select-reference-line {
|
||||||
|
margin-left: 0 !important;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ import commonMixin from '@/mixins/common'
|
|||||||
import { cancelWithChange, noData } from '@/utils/tools'
|
import { cancelWithChange, noData } from '@/utils/tools'
|
||||||
import { ClickOutside } from 'element-plus/lib/directives'
|
import { ClickOutside } from 'element-plus/lib/directives'
|
||||||
import i18n from '@/i18n'
|
import i18n from '@/i18n'
|
||||||
// import '@/mock/index.js'
|
import '@/mock/index.js'
|
||||||
import hljsVuePlugin from '@highlightjs/vue-plugin'
|
import hljsVuePlugin from '@highlightjs/vue-plugin'
|
||||||
import 'highlight.js/styles/color-brewer.css'
|
import 'highlight.js/styles/color-brewer.css'
|
||||||
import '@/assets/css/main.scss' // 样式入口
|
import '@/assets/css/main.scss' // 样式入口
|
||||||
|
|||||||
81
src/mock/entity.js
Normal file
81
src/mock/entity.js
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import Mock from 'mockjs'
|
||||||
|
|
||||||
|
const openMock = true
|
||||||
|
if (openMock) {
|
||||||
|
Mock.mock(new RegExp(BASE_CONFIG.baseUrl + 'interface/entityDetail/totalTrafficAnalysis.*'), 'get', function (requestObj) {
|
||||||
|
const titleList = ['totalBitsRate', 'inboundBitsRate', 'outboundBitsRate', 'internalBitsRate', 'throughBitsRate', 'other']
|
||||||
|
const arr = [{ type: 'Bits/s' }, { type: 'Packets/s' }, { type: 'Sessions/s' }]
|
||||||
|
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
for (const j in titleList) {
|
||||||
|
// 目前模拟数据仅支持1小时的时间选择范围
|
||||||
|
let startTime = JSON.parse(getQuery(requestObj.url).startTime)
|
||||||
|
const values = []
|
||||||
|
let max = 2975
|
||||||
|
let min = 0
|
||||||
|
if (titleList[j] === 'totalBitsRate') {
|
||||||
|
max = 4462975
|
||||||
|
min = 1162975
|
||||||
|
}
|
||||||
|
for (let i = 0; i < 101; i++) {
|
||||||
|
const random = Math.floor(Math.random() * (max - min) + min)
|
||||||
|
values.push([startTime, random])
|
||||||
|
startTime += 36
|
||||||
|
}
|
||||||
|
|
||||||
|
const newValues = JSON.parse(JSON.stringify(values))
|
||||||
|
const sortArr = newValues.sort((a, b) => a[1] - b[1])
|
||||||
|
const maxAnalysis = Math.floor(sortArr[sortArr.length - 1][1])
|
||||||
|
let avg = 0
|
||||||
|
let sum = 0
|
||||||
|
newValues.forEach((item) => {
|
||||||
|
sum += item[1]
|
||||||
|
})
|
||||||
|
avg = JSON.parse(sum / newValues.length)
|
||||||
|
|
||||||
|
const analysis = {
|
||||||
|
avg: avg,
|
||||||
|
max: maxAnalysis,
|
||||||
|
min: Math.floor(sortArr[0][1]),
|
||||||
|
p95: maxAnalysis * 0.95 // 模拟值,p95并未最大值的95%
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metric为Packets/s时,没有other的tab选项
|
||||||
|
if (arr[i].type === 'Packets/s' && titleList[j] === 'other') {
|
||||||
|
analysis.avg = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arr[i].type === 'Sessions/s') {
|
||||||
|
// Metric为Sessions/s时,只有total选项,故total填充数据完毕终止循环,节省性能
|
||||||
|
arr[i].totalBitsRate = { values: values, analysis: analysis }
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
arr[i][titleList[j]] = { values: values, analysis: analysis }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
msg: 'success',
|
||||||
|
code: 200,
|
||||||
|
data: {
|
||||||
|
result: arr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const getQuery = (url) => {
|
||||||
|
// str为?之后的参数部分字符串
|
||||||
|
const str = url.substr(url.indexOf('?') + 1)
|
||||||
|
// arr每个元素都是完整的参数键值
|
||||||
|
const arr = str.split('&')
|
||||||
|
// result为存储参数键值的集合
|
||||||
|
const result = {}
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
// item的两个元素分别为参数名和参数值
|
||||||
|
const item = arr[i].split('=')
|
||||||
|
result[item[0]] = item[1]
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
import './npm'
|
import './npm'
|
||||||
import './linkMonitor'
|
import './linkMonitor'
|
||||||
import './dns'
|
import './dns'
|
||||||
|
import './entity'
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { createStore } from 'vuex'
|
import { createStore } from 'vuex'
|
||||||
import user from './modules/user'
|
import user from './modules/user'
|
||||||
import panel from './modules/panel'
|
import panel from './modules/panel'
|
||||||
import { storageKey } from '@/utils/constants'
|
|
||||||
|
|
||||||
const store = createStore({
|
const store = createStore({
|
||||||
modules: {
|
modules: {
|
||||||
|
|||||||
@@ -232,6 +232,9 @@ export const api = {
|
|||||||
totalTrafficAnalysis: '/interface/dns/overview/totalTrafficAnalysis',
|
totalTrafficAnalysis: '/interface/dns/overview/totalTrafficAnalysis',
|
||||||
eventChart: '/interface/dnsInsight/eventChart',
|
eventChart: '/interface/dnsInsight/eventChart',
|
||||||
drilldownTrafficAnalysis: '/interface/dns/overview/drilldown/trafficAnalysis'
|
drilldownTrafficAnalysis: '/interface/dns/overview/drilldown/trafficAnalysis'
|
||||||
|
},
|
||||||
|
entity: {
|
||||||
|
totalTrafficAnalysis: 'interface/entityDetail/totalTrafficAnalysis'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,669 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="border: 1px solid #ff5500; height: 100%;">{{entity}}</div>
|
<div class="entity-detail-line">
|
||||||
|
<div class="line network">
|
||||||
|
<chart-error v-if="showError" :content="errorMsg"/>
|
||||||
|
<div class="line-header" v-if="!showError">
|
||||||
|
<div class="line-header-left">
|
||||||
|
<div class="line-value-active" v-if="lineTab"></div>
|
||||||
|
<div class="line-value">
|
||||||
|
<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,true)"
|
||||||
|
: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">
|
||||||
|
{{ getTabUnit(item.analysis.avg) }}
|
||||||
|
</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>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="line-select line-header-right">
|
||||||
|
<div class="panel__tools">
|
||||||
|
<div class="panel__time">
|
||||||
|
<date-time-range
|
||||||
|
class="date-time-range"
|
||||||
|
:start-time="timeFilter.startTime"
|
||||||
|
:end-time="timeFilter.endTime"
|
||||||
|
:date-range="timeFilter.dateRangeValue"
|
||||||
|
ref="dateTimeRange"
|
||||||
|
@change="reload"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<el-select
|
||||||
|
size="mini"
|
||||||
|
v-model="metric"
|
||||||
|
placeholder=""
|
||||||
|
popper-class="common-select"
|
||||||
|
:popper-append-to-body="false"
|
||||||
|
@change="metricChange"
|
||||||
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<span class="select-prefix">Metric:</span>
|
||||||
|
</template>
|
||||||
|
<el-option v-for="item in metricOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="line-select-reference-line">
|
||||||
|
<span>{{ $t('network.referenceLine') }}:</span>
|
||||||
|
<div class="line-select__operation">
|
||||||
|
<el-select
|
||||||
|
size="mini"
|
||||||
|
v-model="lineRefer"
|
||||||
|
:disabled="!lineTab"
|
||||||
|
popper-class="common-select"
|
||||||
|
:popper-append-to-body="false"
|
||||||
|
@change="referenceSelectChange"
|
||||||
|
>
|
||||||
|
<el-option v-for="item in options2" :key="item.value" :label="item.label" :value="item.value"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="height: calc(100% - 74px); position: relative">
|
||||||
|
<chart-no-data v-if="isNoData && !showError"></chart-no-data>
|
||||||
|
<div class="chart-drawing" v-show="showMarkLine && !isNoData && !showError" ref="overviewLineChart"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import chartMixin from '@/views/charts2/chart-mixin'
|
import chartMixin from '@/views/charts2/chart-mixin'
|
||||||
|
import * as echarts from 'echarts'
|
||||||
|
import { stackedLineChartOption } from '@/views/charts2/charts/options/echartOption'
|
||||||
|
import unitConvert from '@/utils/unit-convert'
|
||||||
|
import { unitTypes, chartColor3, chartColor4 } from '@/utils/constants.js'
|
||||||
|
import { ref, shallowRef } from 'vue'
|
||||||
|
import { stackedLineTooltipFormatter } from '@/views/charts/charts/tools'
|
||||||
|
import _ from 'lodash'
|
||||||
|
import axios from 'axios'
|
||||||
|
import { api } from '@/utils/api'
|
||||||
|
import { getNowTime, getSecond } from '@/utils/date-util'
|
||||||
|
import ChartNoData from '@/views/charts/charts/ChartNoData'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import { getLineType, getMarkLineByLineRefer, overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
||||||
|
import ChartError from '@/components/common/Error'
|
||||||
|
import { dataForNetworkOverviewLine } from '@/utils/static-data'
|
||||||
|
import { metricOptions } from '@/utils/constants'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'EntityDetailLine',
|
name: 'EntityDetailLine',
|
||||||
mixins: [chartMixin],
|
mixins: [chartMixin],
|
||||||
mounted () {
|
components: {
|
||||||
|
ChartError,
|
||||||
|
ChartNoData
|
||||||
|
},
|
||||||
|
setup () {
|
||||||
|
const { query } = useRoute()
|
||||||
|
const lineRefer = ref(query.lineRefer || 'Average')
|
||||||
|
const lineTab = ref(query.lineTab || '')
|
||||||
|
const queryCondition = ref(query.queryCondition || '')
|
||||||
|
const tabOperationType = ref(query.tabOperationType)
|
||||||
|
const networkOverviewBeforeTab = ref(query.networkOverviewBeforeTab)
|
||||||
|
const metric = ref(query.metric || 'Bits/s')
|
||||||
|
|
||||||
|
// 获取url携带的range、startTime、endTime
|
||||||
|
const rangeParam = query.range
|
||||||
|
const startTimeParam = query.startTime
|
||||||
|
const endTimeParam = query.endTime
|
||||||
|
// 若url携带了,使用携带的值,否则使用默认值。
|
||||||
|
|
||||||
|
const dateRangeValue = rangeParam ? parseInt(query.range) : 60
|
||||||
|
const timeFilter = ref({ dateRangeValue })
|
||||||
|
if (!startTimeParam || !endTimeParam) {
|
||||||
|
const { startTime, endTime } = getNowTime(60)
|
||||||
|
timeFilter.value.startTime = startTime
|
||||||
|
timeFilter.value.endTime = endTime
|
||||||
|
} else {
|
||||||
|
timeFilter.value.startTime = parseInt(startTimeParam)
|
||||||
|
timeFilter.value.endTime = parseInt(endTimeParam)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
lineRefer,
|
||||||
|
lineTab,
|
||||||
|
queryCondition,
|
||||||
|
tabOperationType,
|
||||||
|
networkOverviewBeforeTab,
|
||||||
|
myChart: shallowRef(null),
|
||||||
|
metric,
|
||||||
|
timeFilter
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
options2: dataForNetworkOverviewLine.options2,
|
||||||
|
tabsTemplate: dataForNetworkOverviewLine.tabsTemplate,
|
||||||
|
tabs: [],
|
||||||
|
unitConvert,
|
||||||
|
unitTypes,
|
||||||
|
chartDateObject: [],
|
||||||
|
timer: null,
|
||||||
|
mousemoveCursor: '',
|
||||||
|
leftOffset: 0,
|
||||||
|
sizes: [3, 4, 6, 8, 9, 10],
|
||||||
|
dynamicVariable: '',
|
||||||
|
showMarkLine: true,
|
||||||
|
mouseDownFlag: false,
|
||||||
|
brushHistory: [],
|
||||||
|
showError: false,
|
||||||
|
errorMsg: '',
|
||||||
|
metricOptions
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
lineTab (n) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.handleActiveBar(n)
|
||||||
|
this.reloadUrl({ lineTab: n })
|
||||||
|
})
|
||||||
|
},
|
||||||
|
lineRefer (n) {
|
||||||
|
this.reloadUrl({ lineRefer: n })
|
||||||
|
},
|
||||||
|
timeFilter: {
|
||||||
|
handler () {
|
||||||
|
if (this.lineTab) {
|
||||||
|
this.init(this.metric, this.showMarkLine, 'active')
|
||||||
|
} else {
|
||||||
|
this.init()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
metric (n) {
|
||||||
|
this.handleActiveBar()
|
||||||
|
this.showMarkLine = !this.showMarkLine
|
||||||
|
this.tabs.forEach((e) => {
|
||||||
|
if (!e.invertTab) {
|
||||||
|
e.invertTab = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.init(n, this.showMarkLine, '', n)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
reloadUrl (newParam) {
|
||||||
|
const { query } = this.$route
|
||||||
|
const newUrl = urlParamsHandler(window.location.href, query, newParam)
|
||||||
|
overwriteUrl(newUrl)
|
||||||
|
},
|
||||||
|
init (val, show, active, n) {
|
||||||
|
const newVal = val ? _.clone(val) : this.metric
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
startTime: getSecond(this.timeFilter.startTime),
|
||||||
|
endTime: getSecond(this.timeFilter.endTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.queryCondition) {
|
||||||
|
params.q = this.queryCondition
|
||||||
|
}
|
||||||
|
|
||||||
|
this.toggleLoading(true)
|
||||||
|
// axios.get(api.netWorkOverview.totalTrafficAnalysis, { params: params }).then(response => {
|
||||||
|
axios.get(api.entity.totalTrafficAnalysis, { params: params }).then(response => {
|
||||||
|
const res = response.data
|
||||||
|
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.isNoData = res.data.result.length === 0
|
||||||
|
this.showError = false
|
||||||
|
if (this.isNoData) {
|
||||||
|
this.lineTab = ''
|
||||||
|
this.tabs = _.cloneDeep(this.tabsTemplate)
|
||||||
|
} else {
|
||||||
|
this.initData(res.data.result, newVal, active, show, n)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.httpError(res)
|
||||||
|
}
|
||||||
|
}).catch(e => {
|
||||||
|
console.error(e)
|
||||||
|
this.httpError(e)
|
||||||
|
}).finally(() => {
|
||||||
this.toggleLoading(false)
|
this.toggleLoading(false)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
echartsInit (echartsData, show) {
|
||||||
|
// echarts内容在单元测试时不执行
|
||||||
|
if (!this.isUnitTesting) {
|
||||||
|
if (this.lineTab) {
|
||||||
|
this.handleActiveBar()
|
||||||
|
echartsData = echartsData.filter(t => t.show === true && t.class === this.lineTab) // t.invertTab === false
|
||||||
|
} else {
|
||||||
|
echartsData = echartsData.filter(t => t.show === true)
|
||||||
|
}
|
||||||
|
const _this = this
|
||||||
|
this.chartOption = stackedLineChartOption
|
||||||
|
const chartOption = this.chartOption.series[0]
|
||||||
|
this.chartOption.series = echartsData.map((t, i) => {
|
||||||
|
return {
|
||||||
|
...chartOption,
|
||||||
|
name: t.name,
|
||||||
|
type: 'line',
|
||||||
|
showSymbol: false,
|
||||||
|
smooth: true,
|
||||||
|
symbol: 'circle',
|
||||||
|
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'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (!show && !this.lineTab) {
|
||||||
|
this.chartOption.series.forEach((t) => {
|
||||||
|
t.markLine.label.show = false
|
||||||
|
t.markLine = []
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show) {
|
||||||
|
this.chartOption.series.forEach((t, i) => {
|
||||||
|
t.markLine.label.show = true
|
||||||
|
t.markLine.data = [
|
||||||
|
{
|
||||||
|
yAxis: echartsData[i].analysis[getMarkLineByLineRefer(this.lineRefer)]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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(() => {
|
||||||
|
if (this.myChart) {
|
||||||
|
this.myChart.dispose()
|
||||||
|
}
|
||||||
|
this.myChart = echarts.init(this.$refs.overviewLineChart)
|
||||||
|
this.myChart.setOption(this.chartOption)
|
||||||
|
|
||||||
|
this.myChart.dispatchAction({
|
||||||
|
type: 'takeGlobalCursor',
|
||||||
|
key: 'brush',
|
||||||
|
brushOption: {
|
||||||
|
brushType: 'lineX',
|
||||||
|
xAxisIndex: 'all',
|
||||||
|
brushMode: 'single',
|
||||||
|
throttleType: 'debounce'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 选中tab并刷新界面时,自动触发,避免markLine不显示的情况
|
||||||
|
if (this.lineTab) {
|
||||||
|
this.referenceSelectChange(this.lineRefer)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.myChart.on('brushEnd', this.brushEcharts)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
activeChange (item, index, isClick) { // isClick:代表是通过点击操作来的
|
||||||
|
if (this.isNoData) return
|
||||||
|
if (isClick && this.lineTab === item.class) { // 点击高亮 tab 后取消高亮,恢复到全不高亮的状态
|
||||||
|
this.legendSelectChange(item, index, 'active', true)
|
||||||
|
this.lineTab = ''
|
||||||
|
this.showMarkLine = false
|
||||||
|
} else {
|
||||||
|
this.lineTab = item.class
|
||||||
|
this.legendSelectChange(item, index, 'active')
|
||||||
|
this.showMarkLine = !item.invertTab
|
||||||
|
}
|
||||||
|
this.init(this.metric, this.showMarkLine, 'active')
|
||||||
|
},
|
||||||
|
mouseenter (item) {
|
||||||
|
if (this.isNoData) return
|
||||||
|
this.mousemoveCursor = item.class
|
||||||
|
this.handleActiveBar(item.class)
|
||||||
|
},
|
||||||
|
mouseleave () {
|
||||||
|
this.mousemoveCursor = ''
|
||||||
|
},
|
||||||
|
dispatchSelectAction (type, name) {
|
||||||
|
this.myChart && this.myChart.dispatchAction({
|
||||||
|
type: type,
|
||||||
|
name: name
|
||||||
|
})
|
||||||
|
},
|
||||||
|
legendSelectChange (item, index, val, isActiveAll) {
|
||||||
|
if (index === 'index') {
|
||||||
|
this.dispatchSelectAction('legendSelect', item.name)
|
||||||
|
} else if (this.tabs[index] && this.tabs[index].name === item.name) {
|
||||||
|
if (isActiveAll) {
|
||||||
|
this.tabs.forEach((t) => {
|
||||||
|
this.dispatchSelectAction('legendSelect', t.name)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.dispatchSelectAction('legendSelect', item.name)
|
||||||
|
this.tabs.forEach((t) => {
|
||||||
|
if (t.name !== item.name) {
|
||||||
|
this.dispatchSelectAction('legendUnSelect', t.name)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (val === 'active') {
|
||||||
|
this.tabs.forEach(t => {
|
||||||
|
t.invertTab = item.name === t.name ? !t.invertTab : true
|
||||||
|
if (t.invertTab && item.name === t.name) {
|
||||||
|
this.lineTab = this.lineTab ? '' : t.class
|
||||||
|
this.tabs.forEach((e) => {
|
||||||
|
this.dispatchSelectAction('legendSelect', e.name)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleActiveBar () {
|
||||||
|
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;`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resize () {
|
||||||
|
if (this.myChart) {
|
||||||
|
this.myChart.resize()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
referenceSelectChange (val) {
|
||||||
|
this.lineRefer = val
|
||||||
|
let echartsData
|
||||||
|
if (this.lineTab) {
|
||||||
|
echartsData = this.tabs.filter(t => t.show === true && t.class === this.lineTab) // t.invertTab === false
|
||||||
|
} else {
|
||||||
|
echartsData = this.tabs.filter(t => t.show === true)
|
||||||
|
}
|
||||||
|
if (!this.isUnitTesting) {
|
||||||
|
const chartOption = this.myChart.getOption()
|
||||||
|
|
||||||
|
if (this.showMarkLine) {
|
||||||
|
chartOption.series.forEach(t => {
|
||||||
|
if (t.name === echartsData[0].name) {
|
||||||
|
t.markLine.data = [{ yAxis: echartsData[0].analysis[getMarkLineByLineRefer(this.lineRefer)] }]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.myChart.setOption(chartOption)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
symbolSizeSortChange (index, time) {
|
||||||
|
const dataIntegrationArray = []
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
if (stackedLineChartOption.series[i]) {
|
||||||
|
const item = stackedLineChartOption.series[i].data.find(t => t[0] === time)
|
||||||
|
if (item) {
|
||||||
|
dataIntegrationArray.push(item)
|
||||||
|
item[2] = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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, 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
|
||||||
|
const self = this
|
||||||
|
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 !== self.lineRefer) {
|
||||||
|
self.legendSelectChange(e, 'index')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (self.lineTab === e.class) {
|
||||||
|
if (parseFloat(e.analysis.avg) <= 0) {
|
||||||
|
self.lineTab = ''
|
||||||
|
self.lineRefer = ''
|
||||||
|
self.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'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* echarts框选
|
||||||
|
* @param params
|
||||||
|
*/
|
||||||
|
brushEcharts (params) {
|
||||||
|
this.myChart.dispatchAction({
|
||||||
|
type: 'brush',
|
||||||
|
areas: [] // 删除选框
|
||||||
|
})
|
||||||
|
if (!this.mouseDownFlag) {
|
||||||
|
// 避免点击空白区域报错
|
||||||
|
if (params.areas && params.areas.length > 0) {
|
||||||
|
this.brushHistory.unshift({
|
||||||
|
startTime: _.cloneDeep(this.timeFilter.startTime) * 1000,
|
||||||
|
endTime: _.cloneDeep(this.timeFilter.endTime) * 1000
|
||||||
|
})
|
||||||
|
|
||||||
|
const rangeObj = {
|
||||||
|
startTime: Math.ceil(params.areas[0].coordRange[0]),
|
||||||
|
endTime: Math.ceil(params.areas[0].coordRange[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暂定框选最小范围为5分钟,后续可能会变动
|
||||||
|
if (rangeObj.endTime - rangeObj.startTime < 5 * 60 * 1000) {
|
||||||
|
rangeObj.startTime = rangeObj.endTime - 5 * 60 * 1000
|
||||||
|
}
|
||||||
|
this.$store.commit('setRangeEchartsData', rangeObj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
httpError (e) {
|
||||||
|
this.isNoData = false
|
||||||
|
this.showError = true
|
||||||
|
this.errorMsg = this.errorMsgHandler(e)
|
||||||
|
},
|
||||||
|
metricChange (value) {
|
||||||
|
const { query } = this.$route
|
||||||
|
const newUrl = urlParamsHandler(window.location.href, query, {
|
||||||
|
metric: value
|
||||||
|
})
|
||||||
|
overwriteUrl(newUrl)
|
||||||
|
},
|
||||||
|
reload (startTime, endTime, dateRangeValue) {
|
||||||
|
this.timeFilter = { startTime: getSecond(startTime), endTime: getSecond(endTime) }
|
||||||
|
const { query } = this.$route
|
||||||
|
// 因为详情页是打开的新标签页,设置时间并不会影响到其他界面,所以store的名称不必改变
|
||||||
|
this.$store.commit('setTimeRangeArray', [this.timeFilter.startTime, this.timeFilter.endTime])
|
||||||
|
this.$store.commit('setTimeRangeFlag', dateRangeValue.value)
|
||||||
|
|
||||||
|
const newUrl = urlParamsHandler(window.location.href, query, {
|
||||||
|
startTime: this.timeFilter.startTime,
|
||||||
|
endTime: this.timeFilter.endTime,
|
||||||
|
range: dateRangeValue.value
|
||||||
|
})
|
||||||
|
overwriteUrl(newUrl)
|
||||||
|
},
|
||||||
|
timeRefreshChange () {
|
||||||
|
// 不是自选时间
|
||||||
|
if (this.$refs.dateTimeRange) {
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 对lineTab进行转换
|
||||||
|
getTabUnit (avg) {
|
||||||
|
let number = unitConvert(avg, unitTypes.number)[0]
|
||||||
|
if (number !== '-' && JSON.parse(number) > 0 && JSON.parse(number) < 1) {
|
||||||
|
number = '<1'
|
||||||
|
}
|
||||||
|
return number
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.myChart = null
|
||||||
|
this.chartOption = null
|
||||||
|
const self = this
|
||||||
|
self.timer = setTimeout(() => {
|
||||||
|
if (self.lineTab && self.metric !== 'Sessions/s') {
|
||||||
|
const data = self.tabsTemplate.find(t => t.class === self.lineTab)
|
||||||
|
self.activeChange(data, data.positioning)
|
||||||
|
} else {
|
||||||
|
self.init()
|
||||||
|
}
|
||||||
|
}, 200)
|
||||||
|
window.addEventListener('resize', this.resize)
|
||||||
|
},
|
||||||
|
beforeUnmount () {
|
||||||
|
clearTimeout(this.timer)
|
||||||
|
window.removeEventListener('resize', this.resize)
|
||||||
|
|
||||||
|
let myChart = echarts.getInstanceByDom(this.$refs.overviewLineChart)
|
||||||
|
if (myChart) {
|
||||||
|
echarts.dispose(myChart)
|
||||||
|
}
|
||||||
|
if (this.myChart) {
|
||||||
|
echarts.dispose(this.myChart)
|
||||||
|
}
|
||||||
|
// 检测时发现该方法占用较大内存,且未被释放
|
||||||
|
this.unitConvert = null
|
||||||
|
myChart = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
163
test/views/charts2/charts/entityDetail/EntityDetailLine.test.js
Normal file
163
test/views/charts2/charts/entityDetail/EntityDetailLine.test.js
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
import EntityDetailLine from '@/views/charts2/charts/entityDetail/EntityDetailLine'
|
||||||
|
import { mount } from '@vue/test-utils'
|
||||||
|
import axios from 'axios'
|
||||||
|
import mockData from './mockData/EntityDetailLine'
|
||||||
|
|
||||||
|
const timeFilter = {
|
||||||
|
dateRangeValue: -1,
|
||||||
|
startTime: 1673244000000,
|
||||||
|
endTime: 1673247600000
|
||||||
|
}
|
||||||
|
const chart = {
|
||||||
|
id: 2108,
|
||||||
|
name: 'APP流量图',
|
||||||
|
i18n: '',
|
||||||
|
panelId: 20,
|
||||||
|
pid: 0,
|
||||||
|
type: 107,
|
||||||
|
x: 0,
|
||||||
|
y: 6,
|
||||||
|
w: 30,
|
||||||
|
h: 6,
|
||||||
|
children: [],
|
||||||
|
panel: {
|
||||||
|
id: 20,
|
||||||
|
name: 'APP entity detail'
|
||||||
|
},
|
||||||
|
i: 2108,
|
||||||
|
category: 'echarts',
|
||||||
|
firstShow: false,
|
||||||
|
moved: false
|
||||||
|
}
|
||||||
|
|
||||||
|
function init (query) {
|
||||||
|
require('vue-router').useRoute.mockReturnValue({ query: query || {} })
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('views/charts2/charts/entityDetail/EntityDetailLine.vue测试', () => {
|
||||||
|
test('Metric=Bits/s,无数据(空数组)', async () => {
|
||||||
|
init()
|
||||||
|
axios.get.mockResolvedValue(mockData.empty)
|
||||||
|
const wrapper = mount(EntityDetailLine, {
|
||||||
|
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(EntityDetailLine, {
|
||||||
|
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('<1bps')
|
||||||
|
resolve()
|
||||||
|
}, 200))
|
||||||
|
})
|
||||||
|
test('Metric=Bits/s,点击第三个tab', async () => {
|
||||||
|
init()
|
||||||
|
// 模拟axios返回数据
|
||||||
|
axios.get.mockResolvedValue(mockData.common)
|
||||||
|
// 加载vue组件,获得实例
|
||||||
|
const wrapper = mount(EntityDetailLine, {
|
||||||
|
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 () => {
|
||||||
|
const query = { entityType: 'app', name: 'uplive', startTime: 1675388605, endTime: 1675410205, range: 60, metric: 'Packets/s' }
|
||||||
|
init(query)
|
||||||
|
// 模拟axios返回数据
|
||||||
|
axios.get.mockResolvedValue(mockData.common)
|
||||||
|
// 加载vue组件,获得实例
|
||||||
|
const wrapper = mount(EntityDetailLine, {
|
||||||
|
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 () => {
|
||||||
|
const query = { entityType: 'app', name: 'uplive', startTime: 1675388605, endTime: 1675410205, range: 60, metric: 'Sessions/s' }
|
||||||
|
init(query)
|
||||||
|
// 模拟axios返回数据
|
||||||
|
axios.get.mockResolvedValue(mockData.common)
|
||||||
|
// 加载vue组件,获得实例
|
||||||
|
const wrapper = mount(EntityDetailLine, {
|
||||||
|
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,207 @@
|
|||||||
|
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
|
||||||
Reference in New Issue
Block a user