perf: No data提示、折线图优化

This commit is contained in:
chenjinsong
2021-08-15 15:49:29 +08:00
parent aa2d485f48
commit cad7c9a12b
5 changed files with 100 additions and 16 deletions

View File

@@ -8,7 +8,7 @@
<slot name="operations"></slot> <slot name="operations"></slot>
</div> </div>
</div> </div>
<div class="cn-chart__body" v-loading="loading"> <div class="cn-chart__body" v-loading="loading" v-no-data="noData">
<el-table <el-table
style="width: 100%" style="width: 100%"
tooltip-effect="light" tooltip-effect="light"
@@ -55,7 +55,8 @@ export default {
props: { props: {
tableColumns: Array, tableColumns: Array,
tableData: Array, tableData: Array,
loading: Boolean loading: Boolean,
noData: Boolean
}, },
setup () { setup () {
return { return {

View File

@@ -8,10 +8,10 @@
<slot name="operations"></slot> <slot name="operations"></slot>
</div> </div>
</div> </div>
<div class="cn-chart__body" :class="{'pie-with-table': isPieWithTable}" v-loading="loading"> <div class="cn-chart__body" :class="{'pie-with-table': isPieWithTable}" v-loading="loading" v-no-data="noData">
<slot></slot> <slot></slot>
</div> </div>
<div class="cn-chart__footer" v-if="layout.indexOf(layoutConstant.FOOTER) > -1" :class="{'pie-with-table': isPieWithTable}" v-loading="loading"> <div class="cn-chart__footer" v-if="layout.indexOf(layoutConstant.FOOTER) > -1 && !noData" :class="{'pie-with-table': isPieWithTable}" v-loading="loading">
<slot name="footer"></slot> <slot name="footer"></slot>
</div> </div>
</div> </div>
@@ -24,7 +24,8 @@ export default {
props: { props: {
layout: Array, layout: Array,
chartInfo: Object, chartInfo: Object,
loading: Boolean loading: Boolean,
noData: Boolean
}, },
setup (props) { setup (props) {
return { return {

View File

@@ -4,7 +4,7 @@ import store from '@/store'
import App from '@/App.vue' import App from '@/App.vue'
import { hasPermission } from '@/permission' import { hasPermission } from '@/permission'
import commonMixin from '@/mixins/common' import commonMixin from '@/mixins/common'
import { cancelWithChange, clickOutside } from '@/utils/tools' import { cancelWithChange, clickOutside, 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 '@/assets/css/main.scss' // 样式入口 import '@/assets/css/main.scss' // 样式入口
@@ -36,6 +36,7 @@ app.directive('has', hasPermission) // 注册指令
app.directive('click-outside', clickOutside) app.directive('click-outside', clickOutside)
app.directive('ele-click-outside', ClickOutside) app.directive('ele-click-outside', ClickOutside)
app.directive('cancel', cancelWithChange) app.directive('cancel', cancelWithChange)
app.directive('no-data', noData)
app.config.globalProperties.$_ = _ app.config.globalProperties.$_ = _
app.mixin(commonMixin) app.mixin(commonMixin)

View File

@@ -346,7 +346,15 @@ export const clickOutside = {
delete el.__vueClickOutside__ delete el.__vueClickOutside__
} }
} }
export const noData = {
updated (el, binding) {
if (el) {
if (binding.value) {
el.innerHTML = '<div style="display: flex; justify-content: center; align-items: center; height: 100%; color: #999;">No data</div>'
}
}
}
}
export function isEqual (o1, o2) { export function isEqual (o1, o2) {
const isEqualForInner = function (obj1, obj2) { const isEqualForInner = function (obj1, obj2) {
const o1 = obj1 instanceof Object const o1 = obj1 instanceof Object
@@ -447,3 +455,5 @@ function JSONParse (data) {
return firstParse return firstParse
} }
} }

View File

@@ -46,6 +46,7 @@
:style="computePosition" :style="computePosition"
:chartInfo="chartInfo" :chartInfo="chartInfo"
:loading="loading" :loading="loading"
:no-data="noData"
> >
<template #title v-if="layout.indexOf(layoutConstant.HEADER) > -1"> <template #title v-if="layout.indexOf(layoutConstant.HEADER) > -1">
{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}} {{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}
@@ -102,6 +103,7 @@
:table-data="table.currentPageData" :table-data="table.currentPageData"
:style="computePosition" :style="computePosition"
:loading="loading" :loading="loading"
:no-data="noData"
> >
<template #title>{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}</template> <template #title>{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}</template>
<template #operations> <template #operations>
@@ -230,6 +232,7 @@ export default {
allSelectPieChartName: [], allSelectPieChartName: [],
chartOption: null, chartOption: null,
loading: true, loading: true,
noData: false, // 查询结果为空
throttle: null // 节流器 throttle: null // 节流器
} }
}, },
@@ -324,17 +327,19 @@ export default {
getTitle (r) { getTitle (r) {
let title = '' let title = ''
if (r.establishLatency || r.httpResponseLatency || r.sslConLatency) { if (r.establishLatency || r.httpResponseLatency || r.sslConLatency) {
title = `${title}: ${unitConvert(r.establishLatency || r.httpResponseLatency || r.sslConLatency, unitTypes.time).join(' ')}` title = `: ${unitConvert(r.establishLatency || r.httpResponseLatency || r.sslConLatency, unitTypes.time).join(' ')}`
} }
if (r.sequenceGapLossPercent || r.pktRetransPercent) { if (r.sequenceGapLossPercent || r.pktRetransPercent) {
title = `${title}: ${unitConvert(r.sequenceGapLossPercent || r.pktRetransPercent, unitTypes.number).join(' ')} %` const d = unitConvert(r.sequenceGapLossPercent || r.pktRetransPercent, unitTypes.number)
title = d[0] === '0.00' ? ': 0' : `: ${d.join(' ')} %`
} }
if (r.sessions) { if (r.sessions) {
title = `${title}\nSessions: ${unitConvert(r.sessions, unitTypes.number).join(' ')}` title = `\nSessions: ${unitConvert(r.sessions, unitTypes.number).join(' ')}`
} }
if (r.bytes) { if (r.bytes) {
title = `${title}\nBytes: ${unitConvert(r.bytes, unitTypes.byte).join(' ')}` title = `\nBytes: ${unitConvert(r.bytes, unitTypes.byte).join(' ')}`
} }
title = title || ': 0'
return title return title
}, },
changeTab (tab) { changeTab (tab) {
@@ -445,21 +450,22 @@ export default {
max: am4Core.color('#D95D41') max: am4Core.color('#D95D41')
}) })
polygonSeries.data = response.data.result.map(r => { const seriesData = data.map(r => {
const value = r.establishLatency || r.httpResponseLatency || r.sslConLatency || r.sequenceGapLossPercent || r.pktRetransPercent || r.sessions
return { return {
id: r.serverId, id: r.serverId,
title: this.getTitle(r), title: this.getTitle(r),
value: r.establishLatency || r.httpResponseLatency || r.sslConLatency || r.sequenceGapLossPercent || r.pktRetransPercent || r.sessions value: value || 0
} }
}) })
const sorted = polygonSeries.data.sort((a, b) => b.value - a.value) polygonSeries.data = [...seriesData]
const sorted = seriesData.sort((a, b) => b.value - a.value)
const heatLegend = this.myChart.createChild(am4Maps.HeatLegend) const heatLegend = this.myChart.createChild(am4Maps.HeatLegend)
heatLegend.series = polygonSeries heatLegend.series = polygonSeries
heatLegend.align = 'center' heatLegend.align = 'center'
console.info(sorted)
if (!this.$_.isEmpty(sorted)) {
heatLegend.minValue = 0 heatLegend.minValue = 0
if (!this.$_.isEmpty(sorted)) {
heatLegend.maxValue = Number(sorted[0].value) heatLegend.maxValue = Number(sorted[0].value)
} }
heatLegend.markerContainer.height = 6 heatLegend.markerContainer.height = 6
@@ -514,11 +520,40 @@ export default {
this.initEchartsWithPieTable(chartParams) this.initEchartsWithPieTable(chartParams)
} }
}, },
timeLineIsAllZero (data) {
let allZero = true
try {
data.forEach(d => {
d.values.forEach(r => {
if (r[1] && r[1] !== '0' && r[1] !== 0) {
allZero = false
throw new Error('break')
}
})
})
} catch (e) {}
return allZero
},
initECharts (chartParams) { initECharts (chartParams) {
const queryParams = { startTime: parseInt(this.timeFilter.startTime / 1000), endTime: parseInt(this.timeFilter.endTime / 1000), ...this.entity } const queryParams = { startTime: parseInt(this.timeFilter.startTime / 1000), endTime: parseInt(this.timeFilter.endTime / 1000), ...this.entity }
get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => { get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => {
if (response.code === 200) { if (response.code === 200) {
if (this.$_.isEmpty(response.data.result)) {
this.noData = true
return
} else {
this.noData = false
}
const seriesTemplate = this.chartOption.series[0] const seriesTemplate = this.chartOption.series[0]
const allZero = this.timeLineIsAllZero(response.data.result)
if (allZero) {
this.chartOption.yAxis = {
...this.chartOption.yAxis,
min: 0,
max: 5,
interval: 1
}
}
this.chartOption.series = response.data.result.map(r => { this.chartOption.series = response.data.result.map(r => {
return { return {
...seriesTemplate, ...seriesTemplate,
@@ -545,6 +580,21 @@ export default {
const queryParams = { startTime: parseInt(this.timeFilter.startTime / 1000), endTime: parseInt(this.timeFilter.endTime / 1000), ...this.entity } const queryParams = { startTime: parseInt(this.timeFilter.startTime / 1000), endTime: parseInt(this.timeFilter.endTime / 1000), ...this.entity }
get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => { get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => {
if (response.code === 200) { if (response.code === 200) {
if (this.$_.isEmpty(response.data.result)) {
this.noData = true
return
} else {
this.noData = false
}
const allZero = this.timeLineIsAllZero(response.data.result)
if (allZero) {
this.chartOption.yAxis = {
...this.chartOption.yAxis,
min: 0,
max: 5,
interval: 1
}
}
this.statisticsData = response.data.result.map(d => { this.statisticsData = response.data.result.map(d => {
return { return {
...d, ...d,
@@ -580,6 +630,21 @@ export default {
tableQueryParams[chartParams.nameColumn] = [] // 处理两个图表不一样的地方 tableQueryParams[chartParams.nameColumn] = [] // 处理两个图表不一样的地方
get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => { get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => {
if (response.code === 200) { if (response.code === 200) {
if (this.$_.isEmpty(response.data.result)) {
this.noData = true
return
} else {
this.noData = false
}
const allZero = this.timeLineIsAllZero(response.data.result)
if (allZero) {
this.chartOption.yAxis = {
...this.chartOption.yAxis,
min: 0,
max: 5,
interval: 1
}
}
const data = response.data.result.map(d => { const data = response.data.result.map(d => {
tableQueryParams[chartParams.nameColumn].push(d[chartParams.nameColumn]) tableQueryParams[chartParams.nameColumn].push(d[chartParams.nameColumn])
return { return {
@@ -664,6 +729,12 @@ export default {
const queryParams = { startTime: parseInt(this.timeFilter.startTime / 1000), endTime: parseInt(this.timeFilter.endTime / 1000), limit: this.table.limit, order: this.table.orderBy, ...this.entity } const queryParams = { startTime: parseInt(this.timeFilter.startTime / 1000), endTime: parseInt(this.timeFilter.endTime / 1000), limit: this.table.limit, order: this.table.orderBy, ...this.entity }
get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => { get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => {
if (response.code === 200) { if (response.code === 200) {
if (this.$_.isEmpty(response.data.result)) {
this.noData = true
return
} else {
this.noData = false
}
this.table.tableData = response.data.result this.table.tableData = response.data.result
this.table.tableColumns = this.getTableTitle(response.data.result) this.table.tableColumns = this.getTableTitle(response.data.result)
this.table.currentPageData = this.getTargetPageData(1, this.table.pageSize, this.table.tableData) this.table.currentPageData = this.getTargetPageData(1, this.table.pageSize, this.table.tableData)