diff --git a/src/utils/static-data.js b/src/utils/static-data.js new file mode 100644 index 00000000..2b1d33e4 --- /dev/null +++ b/src/utils/static-data.js @@ -0,0 +1,187 @@ +/** + * @name: 静态数据模板 + * @description: 用于存放引用到的静态数据,如表格列名称、echarts的legend名称等 + * 如有使用 this 的,js文件里不识别 this,需要引入对应方法,如this.$t引入i18n,this.$route 引入route + * @author: newhome + * @date: 2023-03-16 17:26:49 + */ +// 如有使用this的 +import i18n from '@/i18n' +import { unitTypes } from '@/utils/constants' +const _this = i18n.global +_this.$t = _this.t + +// NpmTrafficLine折线图数据 +export const dataForNpmTrafficLine = { + 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' + } + ], + 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 } + ], + metricOptions: [ + { value: 'Bits/s', label: 'Bits/s' }, + { value: 'Packets/s', label: 'Packets/s' }, + { value: 'Sessions/s', label: 'Sessions/s' }, + { value: 'establishLatencyMs', label: _this.$t('networkAppPerformance.tcpConnectionEstablishLatency') }, + { value: 'httpResponseLatency', label: _this.$t('networkAppPerformance.httpResponse') }, + { value: 'sslConLatency', label: _this.$t('networkAppPerformance.sslResponseLatency') }, + { value: 'tcpLostlenPercent', label: _this.$t('networkAppPerformance.packetLoss') }, + { value: 'pktRetransPercent', label: _this.$t('overall.packetRetrans') } + ] +} + +export const dataForNetworkOverviewLine = { + options2: [ + { + value: 'Average', + label: 'Average' + }, + { + value: '95th Percentile', + label: '95th Percentile' + }, + { + value: 'Maximum', + label: 'Maximum' + } + ], + 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: '' + }, + { + 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: '' + } + ] +} + +export const dataForLinkTrafficLine = { + options: [ + { + value: 'Bits/s', + label: 'Bits/s' + }, + { + value: 'Packets/s', + label: 'Packets/s' + } + ], + 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: '' } + ] +} + +export const dataForNpmLine = { + chartOptionLineData: [ + { legend: _this.$t('network.total'), index: 0, invertTab: true, show: false, color: '#749F4D' }, + { legend: _this.$t('network.inbound'), index: 1, invertTab: true, show: false, color: '#98709B' }, + { legend: _this.$t('network.outbound'), index: 2, invertTab: true, show: false, color: '#E5A219' } + ], + npmLineColor: [ + { legend: '', color: '#749F4D' }, + { legend: '', color: '#98709B' }, + { legend: '', color: '#E5A219' } + ] +} diff --git a/src/utils/tools.js b/src/utils/tools.js index a1efa9d6..c4cc1669 100644 --- a/src/utils/tools.js +++ b/src/utils/tools.js @@ -1163,3 +1163,37 @@ export function getLineIndexUnit2 (type) { return 0 } } +/** + 通过lineRefer切换来选择markLine对应的值 + */ +export function getMarkLineByLineRefer (data) { + switch (data) { + case 'Average': { + return 'avg' + } + case '95th Percentile': { + return 'p95' + } + case 'Maximum': { + return 'max' + } + } +} +/** + 通过 type 判断参数q的值 + */ +export function getQueryByType (type, condition) { + switch (type) { + case 'clientIp': + case 'serverIp': { + return `ip='${condition.split(/'(.*?)'/)[1]}'` + } + case 'clientCity': { + return `client_city='${condition.split(/'(.*?)'/)[1]}'` + } + case 'serverCity': { + return `server_city='${condition.split(/'(.*?)'/)[1]}'` + } + default: return condition + } +} diff --git a/src/views/charts2/charts/linkMonitor/LinkBlock.vue b/src/views/charts2/charts/linkMonitor/LinkBlock.vue index 945822b6..09d677f3 100644 --- a/src/views/charts2/charts/linkMonitor/LinkBlock.vue +++ b/src/views/charts2/charts/linkMonitor/LinkBlock.vue @@ -320,9 +320,8 @@ export default { this.nextHopNoData = false this.showError1 = true this.showError2 = true - // todo 此处数据还待验证 - this.errorMsg1 = e.message - this.errorMsg2 = e.message + this.errorMsg1 = this.errorMsgHandler(e) + this.errorMsg2 = this.errorMsgHandler(e) }).finally(() => { this.toggleLoading(false) }) diff --git a/src/views/charts2/charts/linkMonitor/LinkTrafficLine.vue b/src/views/charts2/charts/linkMonitor/LinkTrafficLine.vue index 1efdc5c4..ed3d0879 100644 --- a/src/views/charts2/charts/linkMonitor/LinkTrafficLine.vue +++ b/src/views/charts2/charts/linkMonitor/LinkTrafficLine.vue @@ -46,7 +46,7 @@ :popper-append-to-body="false" @change="metricSelectChange" > - + @@ -77,6 +77,7 @@ import * as echarts from 'echarts' import { linkTrafficLineChartOption } from '@/views/charts2/charts/options/echartOption' import { stackedLineTooltipFormatter } from '@/views/charts/charts/tools' import axios from 'axios' +import { dataForLinkTrafficLine } from '@/utils/static-data' export default { name: 'LinkTrafficLine', @@ -104,21 +105,8 @@ export default { }, data () { return { - options1: [ - { - value: 'Bits/s', - label: 'Bits/s' - }, - { - value: 'Packets/s', - label: 'Packets/s' - } - ], - 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: '' } - ], + options: dataForLinkTrafficLine.options, + tabs: dataForLinkTrafficLine.tabs, unitConvert, unitTypes, chartDateObject: [], @@ -137,19 +125,11 @@ export default { lineTab (n) { this.$nextTick(() => { this.handleActiveBar(n) - const { query } = this.$route - const newUrl = urlParamsHandler(window.location.href, query, { - lineTab: n - }) - overwriteUrl(newUrl) + this.reloadUrl({ lineTab: n }) }) }, lineMetric (n) { - const { query } = this.$route - const newUrl = urlParamsHandler(window.location.href, query, { - lineMetric: n - }) - overwriteUrl(newUrl) + this.reloadUrl({ lineMetric: n }) }, timeFilter: { handler () { @@ -162,6 +142,11 @@ export default { } }, methods: { + reloadUrl (newParam) { + const { query } = this.$route + const newUrl = urlParamsHandler(window.location.href, query, newParam) + overwriteUrl(newUrl) + }, init (val, show, active) { if (!val) { val = this.lineMetric @@ -185,22 +170,18 @@ export default { this.isNoData = res.data.result.length === 0 if (this.isNoData) { this.lineTab = '' - 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: '' } - ] + this.tabs = dataForLinkTrafficLine.tabs } else { this.initData(res.data.result, val, active, show) } } else { this.showError = true - this.errorMsg = res.message + this.errorMsg = this.errorMsgHandler(res.message) } }).catch(e => { console.error(e) this.showError = true - this.errorMsg = e.message + this.errorMsg = this.errorMsgHandler(e.message) this.isNoData = false }).finally(() => { this.loading = false @@ -214,11 +195,14 @@ export default { } 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, @@ -255,6 +239,7 @@ export default { data: t.data.map(v => [Number(v[0]) * 1000, Number(v[1]), 'number']) } }) + this.chartOption.tooltip.formatter = (params) => { params.forEach(t => { t.seriesName = this.$t(t.seriesName) @@ -264,9 +249,9 @@ export default { } }) }) - // const str = stackedLineTooltipFormatter(params) return stackedLineTooltipFormatter(params) } + this.showMarkLine = true this.myChart.setOption(this.chartOption) } @@ -286,44 +271,30 @@ export default { mouseleave () { this.mousemoveCursor = '' }, - dispatchLegendSelectAction (name) { + dispatchSelectAction (type, name) { this.myChart && this.myChart.dispatchAction({ - type: 'legendSelect', - name: name - }) - }, - dispatchLegendUnSelectAction (name) { - this.myChart && this.myChart.dispatchAction({ - type: 'legendUnSelect', + type: type, name: name }) }, legendSelectChange (item, index, val) { if (index === 'index') { - this.dispatchLegendSelectAction(item.name) + this.dispatchSelectAction('legendSelect', item.name) } else if (this.tabs[index] && this.tabs[index].name === item.name) { - this.dispatchLegendSelectAction(item.name) + this.dispatchSelectAction('legendSelect', item.name) this.tabs.forEach((t) => { if (t.name !== item.name) { - this.dispatchLegendUnSelectAction(t.name) + this.dispatchSelectAction('legendUnSelect', t.name) } }) } if (val === 'active') { this.tabs.forEach(t => { - if (item.name === t.name) { - t.invertTab = !t.invertTab - } else { - t.invertTab = true - } + t.invertTab = item.name === t.name ? !t.invertTab : true if (t.invertTab && item.name === t.name) { - if (this.lineTab) { - this.lineTab = '' - } else { - this.lineTab = t.class - } + this.lineTab = this.lineTab ? '' : t.class this.tabs.forEach((e) => { - this.dispatchLegendSelectAction(e.name) + this.dispatchSelectAction('legendSelect', e.name) }) } }) @@ -353,25 +324,13 @@ export default { }, symbolSizeSortChange (index, time) { const dataIntegrationArray = [] - if (linkTrafficLineChartOption.series[0]) { - const totalData = linkTrafficLineChartOption.series[0].data.find(t => t[0] === time) // [time, value] - if (totalData) { - dataIntegrationArray.push(totalData) - totalData[2] = 0 - } - } - if (linkTrafficLineChartOption.series[1]) { - const ingressData = linkTrafficLineChartOption.series[1].data.find(t => t[0] === time) - if (ingressData) { - dataIntegrationArray.push(ingressData) - ingressData[2] = 1 - } - } - if (linkTrafficLineChartOption.series[2]) { - const egressData = linkTrafficLineChartOption.series[2].data.find(t => t[0] === time) - if (egressData) { - dataIntegrationArray.push(egressData) - egressData[2] = 2 + for (let i = 0; i < 3; i++) { + if (linkTrafficLineChartOption.series[i]) { + const item = linkTrafficLineChartOption.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] }) diff --git a/src/views/charts2/charts/networkOverview/NetworkOverviewLine.vue b/src/views/charts2/charts/networkOverview/NetworkOverviewLine.vue index e06daf89..981249b3 100644 --- a/src/views/charts2/charts/networkOverview/NetworkOverviewLine.vue +++ b/src/views/charts2/charts/networkOverview/NetworkOverviewLine.vue @@ -51,10 +51,6 @@
- - - -
@@ -73,8 +69,9 @@ import { getSecond } from '@/utils/date-util' import ChartNoData from '@/views/charts/charts/ChartNoData' import chartMixin from '@/views/charts2/chart-mixin' import { useRoute } from 'vue-router' -import { getLineType, overwriteUrl, urlParamsHandler } from '@/utils/tools' +import { getLineType, getMarkLineByLineRefer, overwriteUrl, urlParamsHandler } from '@/utils/tools' import ChartError from '@/components/common/Error' +import { dataForNetworkOverviewLine } from '@/utils/static-data' export default { name: 'NetworkOverviewLine', @@ -107,82 +104,8 @@ export default { mixins: [chartMixin], data () { return { - options2: [ - { - value: 'Average', - label: 'Average' - }, - { - value: '95th Percentile', - label: '95th Percentile' - }, - { - value: 'Maximum', - label: 'Maximum' - } - ], - 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: '' - }, - { - 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: '' - } - ], + options2: dataForNetworkOverviewLine.options2, + tabsTemplate: dataForNetworkOverviewLine.tabsTemplate, tabs: [], unitConvert, unitTypes, @@ -203,19 +126,11 @@ export default { lineTab (n) { this.$nextTick(() => { this.handleActiveBar(n) - const { query } = this.$route - const newUrl = urlParamsHandler(window.location.href, query, { - lineTab: n - }) - overwriteUrl(newUrl) + this.reloadUrl({ lineTab: n }) }) }, lineRefer (n) { - const { query } = this.$route - const newUrl = urlParamsHandler(window.location.href, query, { - lineRefer: n - }) - overwriteUrl(newUrl) + this.reloadUrl({ lineRefer: n }) }, timeFilter: { handler () { @@ -238,22 +153,28 @@ export default { } }, methods: { + reloadUrl (newParam) { + const { query } = this.$route + const newUrl = urlParamsHandler(window.location.href, query, newParam) + overwriteUrl(newUrl) + }, init (val, show, active, n) { - if (!val) { - val = this.metric - } + 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 => { 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 @@ -261,43 +182,21 @@ export default { this.lineTab = '' this.tabs = _.cloneDeep(this.tabsTemplate) } else { - this.initData(res.data.result, val, active, show, n) + this.initData(res.data.result, newVal, active, show, n) } } else { this.showError = true - this.errorMsg = res.message + this.errorMsg = this.errorMsgHandler(res.message) } }).catch(e => { console.error(e) - this.showError = true - this.errorMsg = e.message this.isNoData = false + this.showError = true + this.errorMsg = this.errorMsgHandler(e.message) }).finally(() => { this.toggleLoading(false) }) }, - /** - * 初始化echartsdom,用于右键点击返回框选 - */ - // domInit () { - // const self = this - // // 去掉默认的contextmenu事件,否则会和右键事件同时出现。 - // document.oncontextmenu = function (e) { - // e.preventDefault() - // } - // document.getElementById('overviewLineChart').onmousedown = function (e) { - // // e.button: 0左键,1滚轮,2右键 - // if (e.button === 2) { - // self.myChart.dispatchAction({ - // type: 'brush', - // areas: [] // 删除选框 - // }) - // self.mouseDownFlag = true - // document.getElementById('brushBtn').style.left = e.layerX + 'px' - // document.getElementById('brushBtn').style.top = e.layerY + 74 + 'px' - // } - // } - // }, echartsInit (echartsData, show) { // echarts内容在单元测试时不执行 if (!this.isUnitTesting) { @@ -368,36 +267,24 @@ export default { } } }) - if (!show) { + if (!show && !this.lineTab) { this.chartOption.series.forEach((t) => { t.markLine.label.show = false t.markLine = [] }) } - if (this.lineRefer === 'Average' && show) { + + if (show) { this.chartOption.series.forEach((t, i) => { t.markLine.label.show = true t.markLine.data = [ { - yAxis: echartsData[i].analysis.avg + yAxis: echartsData[i].analysis[getMarkLineByLineRefer(this.lineRefer)] } ] }) - } 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) @@ -413,51 +300,23 @@ export default { 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' } }) + // 选中tab并刷新界面时,自动触发,避免markLine不显示的情况 + if (this.lineTab) { + this.referenceSelectChange(this.lineRefer) + } - 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) - } - } - }) + this.myChart.on('brushEnd', this.brushEcharts) }) } }, @@ -482,50 +341,36 @@ export default { mouseleave () { this.mousemoveCursor = '' }, - dispatchLegendSelectAction (name) { + dispatchSelectAction (type, name) { this.myChart && this.myChart.dispatchAction({ - type: 'legendSelect', - name: name - }) - }, - dispatchLegendUnSelectAction (name) { - this.myChart && this.myChart.dispatchAction({ - type: 'legendUnSelect', + type: type, name: name }) }, legendSelectChange (item, index, val, isActiveAll) { if (index === 'index') { - this.dispatchLegendSelectAction(item.name) + this.dispatchSelectAction('legendSelect', item.name) } else if (this.tabs[index] && this.tabs[index].name === item.name) { if (isActiveAll) { this.tabs.forEach((t) => { - this.dispatchLegendSelectAction(t.name) + this.dispatchSelectAction('legendSelect', t.name) }) } else { - this.dispatchLegendSelectAction(item.name) + this.dispatchSelectAction('legendSelect', item.name) this.tabs.forEach((t) => { if (t.name !== item.name) { - this.dispatchLegendUnSelectAction(t.name) + this.dispatchSelectAction('legendUnSelect', t.name) } }) } } if (val === 'active') { this.tabs.forEach(t => { - if (item.name === t.name) { - t.invertTab = !t.invertTab - } else { - t.invertTab = true - } + t.invertTab = item.name === t.name ? !t.invertTab : true if (t.invertTab && item.name === t.name) { - if (this.lineTab) { - this.lineTab = '' - } else { - this.lineTab = t.class - } + this.lineTab = this.lineTab ? '' : t.class this.tabs.forEach((e) => { - this.dispatchLegendSelectAction(e.name) + this.dispatchSelectAction('legendSelect', e.name) }) } }) @@ -581,48 +426,16 @@ export default { }, symbolSizeSortChange (index, time) { const dataIntegrationArray = [] - if (stackedLineChartOption.series[0]) { - const totalData = stackedLineChartOption.series[0].data.find(t => t[0] === time) // [time, value] - if (totalData) { - dataIntegrationArray.push(totalData) - totalData[2] = 0 - } - } - if (stackedLineChartOption.series[1]) { - const inboundData = stackedLineChartOption.series[1].data.find(t => t[0] === time) - if (inboundData) { - dataIntegrationArray.push(inboundData) - inboundData[2] = 1 - } - } - if (stackedLineChartOption.series[2]) { - const outboundData = stackedLineChartOption.series[2].data.find(t => t[0] === time) - if (outboundData) { - dataIntegrationArray.push(outboundData) - outboundData[2] = 2 - } - } - if (stackedLineChartOption.series[3]) { - const internalData = stackedLineChartOption.series[3].data.find(t => t[0] === time) - if (internalData) { - dataIntegrationArray.push(internalData) - internalData[2] = 3 - } - } - if (stackedLineChartOption.series[4]) { - const throughData = stackedLineChartOption.series[4].data.find(t => t[0] === time) - if (throughData) { - dataIntegrationArray.push(throughData) - throughData[2] = 4 - } - } - if (stackedLineChartOption.series[5]) { - const otherData = stackedLineChartOption.series[5].data.find(t => t[0] === time) - if (otherData) { - dataIntegrationArray.push(otherData) - otherData[2] = 5 + 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] }) @@ -710,25 +523,39 @@ export default { if (!this.lineRefer) this.lineRefer = 'Average' }) } - } + }, /** - * 鼠标右键返回框选的时间范围 + * echarts框选 + * @param params */ - // backBrushHistory () { - // this.myChart.dispatchAction({ - // type: 'brush', - // areas: [] // 删除选框 - // }) - // if (this.brushHistory.length > 0) { - // this.$store.commit('setRangeEchartsData', _.cloneDeep(this.brushHistory[0])) - // this.brushHistory.shift() - // } - // this.mouseDownFlag = false - // } + 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) + } + } + } }, mounted () { - // todo 初始化鼠标事件,开启右键返回 - // this.domInit() this.myChart = null this.chartOption = null const self = this diff --git a/src/views/charts2/charts/npm/NpmLine.vue b/src/views/charts2/charts/npm/NpmLine.vue index 607cd37e..481e2937 100644 --- a/src/views/charts2/charts/npm/NpmLine.vue +++ b/src/views/charts2/charts/npm/NpmLine.vue @@ -4,13 +4,14 @@ @@ -35,7 +35,6 @@ import unitConvert from '@/utils/unit-convert' import { chartColor3, unitTypes } from '@/utils/constants.js' import { ref, shallowRef } from 'vue' import { stackedLineTooltipFormatter } from '@/views/charts/charts/tools' -import { get } from '@/utils/http' import axios from 'axios' import { api } from '@/utils/api' import { getSecond } from '@/utils/date-util' @@ -43,8 +42,16 @@ import ChartNoData from '@/views/charts/charts/ChartNoData' import _ from 'lodash' import chartMixin from '@/views/charts2/chart-mixin' import { useRoute } from 'vue-router' -import { getLineType, getLineIndexUnit, getLineIndexUnit2, overwriteUrl, urlParamsHandler } from '@/utils/tools' +import { + getLineType, + getLineIndexUnit, + getLineIndexUnit2, + overwriteUrl, + urlParamsHandler, + getQueryByType +} from '@/utils/tools' import ChartError from '@/components/common/Error' +import { dataForNpmTrafficLine } from '@/utils/static-data' export default { name: 'NpmTrafficLine', @@ -72,56 +79,10 @@ export default { unitConvert, unitTypes, side: '', - 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' } - ], - 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 } - ], chartData: {}, - metricOptions: [ - { - value: 'Bits/s', - label: 'Bits/s' - }, - { - value: 'Packets/s', - label: 'Packets/s' - }, - { - value: 'Sessions/s', - label: 'Sessions/s' - }, - { - value: 'establishLatencyMs', - label: this.$t('networkAppPerformance.tcpConnectionEstablishLatency') - }, - { - value: 'httpResponseLatency', - label: this.$t('networkAppPerformance.httpResponse') - }, - { - value: 'sslConLatency', - label: this.$t('networkAppPerformance.sslResponseLatency') - }, - { - value: 'tcpLostlenPercent', - label: this.$t('networkAppPerformance.packetLoss') - }, - { - value: 'pktRetransPercent', - label: this.$t('overall.packetRetrans') - } - ], + tabs: dataForNpmTrafficLine.tabs, + npmQuantity: dataForNpmTrafficLine.npmQuantity, + metricOptions: dataForNpmTrafficLine.metricOptions, showError: false, errorMsg: '' } @@ -136,31 +97,40 @@ export default { }, timeFilter: { handler () { - this.init() + this.initData() } } }, methods: { - init (val) { + /** + * 根据过滤条件,请求接口获得折线图数据 + * @param val + */ + initData (val) { if (!val) { val = this.metricFilter } let condition = '' let type = this.dimensionType + if (this.queryCondition.indexOf(' OR ') > -1) { condition = this.queryCondition.split(/["|'](.*?)["|']/) } else { condition = this.queryCondition } + if (parseFloat(this.tabIndex) === 0) { this.side = 'client' } else if (parseFloat(this.tabIndex) === 1) { this.side = 'server' } + const params = { startTime: getSecond(this.timeFilter.startTime), endTime: getSecond(this.timeFilter.endTime) } + + // 此处过滤入参,再进行精简便降低可读性了,故暂时保留,若之后有更好处理方法则进行替换 if (type) { if (type === 'clientIp' || type === 'serverIp') { if (parseFloat(this.tabIndex) === 0) { @@ -172,20 +142,16 @@ export default { } params.type = type } + if (condition && (typeof condition !== 'object') && type) { - if (type === 'clientIp' || type === 'serverIp') { - params.q = `ip='${condition.split(/'(.*?)'/)[1]}'` - } else if (type === 'clientCity') { - params.q = `client_city='${condition.split(/'(.*?)'/)[1]}'` - } else if (type === 'serverCity') { - params.q = `server_city='${condition.split(/'(.*?)'/)[1]}'` - } else { - params.q = condition - } + params.q = getQueryByType(type, condition) } 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') { - if (type === 'country' || type === 'asn' || type === 'province' || type === 'city' || type === 'isp') { + const typeList = ['country', 'asn', 'province', 'city', 'isp'] + const typeFlag = typeList.find(t => type === t) + + if (typeFlag) { params.q = `${type}='${condition[1]}'` } else if (type === 'idcRenter') { params.q = `idc_renter='${condition[1]}'` @@ -193,6 +159,7 @@ export default { params.q = `${condition[0]}'${condition[1]}'` } } + this.toggleLoading(true) if (params.type && params.q) { axios.get(api.npm.overview.trafficGraph, { params: params }).then(res => { @@ -201,28 +168,15 @@ export default { this.showError = false this.isNoData = res.data.result.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 } - ] + this.tabs = dataForNpmTrafficLine.tabs + this.npmQuantity = dataForNpmTrafficLine.npmQuantity } else { - this.initData(res.data.result, val) + this.initLineData(res.data.result, val) } } else { this.isNoData = false this.showError = true - this.errorMsg = res.message + this.errorMsg = this.errorMsgHandler(res.message) } }).catch(e => { this.isNoData = false @@ -246,29 +200,16 @@ export default { } else { this.isNoData = false this.showError = true - this.errorMsg = res.message + this.errorMsg = this.errorMsgHandler(res.message) } }) this.showError = false this.isNoData = npmLineData.length === 0 if (this.isNoData) { - this.tabs = [ - { name: this.$t('network.total'), show: true, positioning: 0, data: [], unitType: 'number' }, - { name: this.$t('network.inbound'), show: true, positioning: 1, data: [], unitType: 'number' }, - { name: this.$t('network.outbound'), show: true, positioning: 2, data: [], unitType: 'number' }, - { name: this.$t('network.internal'), show: true, positioning: 3, data: [], unitType: 'number' }, - { name: this.$t('network.through'), show: true, positioning: 4, data: [], unitType: 'number' }, - { name: this.$t('network.other'), show: true, positioning: 5, data: [], unitType: 'number' } - ] - this.npmQuantity = [ - { name: this.$t('networkAppPerformance.tcpConnectionEstablishLatency'), show: true, positioning: 0, data: [], unitType: unitTypes.time, index: 0 }, - { name: this.$t('networkAppPerformance.httpResponse'), show: true, positioning: 0, data: [], unitType: unitTypes.time, index: 1 }, - { name: this.$t('networkAppPerformance.sslResponseLatency'), show: true, positioning: 0, data: [], unitType: unitTypes.time, index: 2 }, - { name: this.$t('networkAppPerformance.packetLoss'), show: true, positioning: 0, data: [], unitType: unitTypes.percent, index: 3 }, - { name: this.$t('overall.packetRetrans'), show: true, positioning: 0, data: [], unitType: unitTypes.percent, index: 4 } - ] + this.tabs = dataForNpmTrafficLine.tabs + this.npmQuantity = dataForNpmTrafficLine.npmQuantity } else { - this.initData(npmLineData, val) + this.initLineData(npmLineData, val) } }).catch(e => { this.isNoData = false @@ -279,15 +220,23 @@ export default { }) } }, - echartsInit (echartsData, legendUnit) { + /** + * 初始化echarts折线图配置信息 + * @param echartsData + * @param legendUnit + */ + initEchartsOption (echartsData, legendUnit) { echartsData = echartsData.filter(t => t.show === true) this.$nextTick(() => { if (echartsData.length > 0) { - const dom = document.getElementById('chart-line') + const dom = this.$refs['chart-line'] !this.myChart && (this.myChart = echarts.init(dom)) + this.chartOption = _.cloneDeep(trafficLineChartOption) const chartOption = this.chartOption.series[0] + this.chartOption.series = echartsData.map((t) => { + // 根据参数转换y轴单位 this.chartOption.yAxis[0].axisLabel.formatter = (value) => { if (t.unitType === 'percent') { return unitConvert(value, t.unitType)[0] @@ -297,6 +246,7 @@ export default { return unitConvert(value, t.unitType).join('') } } + return { ...chartOption, name: t.name + (legendUnit || ''), @@ -321,6 +271,7 @@ export default { data: t.data.map(v => [Number(v[0]) * 1000, Number(v[1]), t.unitType]) } }) + this.chartOption.tooltip.formatter = (params) => { params.forEach(t => { this.tabs.forEach(e => { @@ -340,12 +291,17 @@ export default { }) return stackedLineTooltipFormatter(params) } - this.myChart.on('legendselectchanged', this.handleLegendClick) + + this.myChart.on('legendselectchanged', this.selectLegend) this.myChart.setOption(this.chartOption, true) } }) }, - // 点击前,高亮legend个数 + /** + * 点击前legend,高亮legend个数 + * @param params + * @returns {number} + */ getSelectedNum (params) { let selectedNum = 0 const legendItem = params.selected @@ -362,13 +318,14 @@ export default { } return selectedNum }, - - // 自定义legend的点击事件:此方法只处理多条曲线的情况(单条曲线正常切换legend和曲线) - handleLegendClick (params) { + /** + * 自定义legend的点击事件:此方法只处理多条曲线的情况(单条曲线正常切换legend和曲线) + * @param params + */ + selectLegend (params) { // legend点击事件 const legendNum = Object.keys(params.selected).length const selectedNum = this.getSelectedNum(params) - const legendItem = params.selected if (selectedNum === legendNum) { // 点击前:全部曲线高亮 for (const name in legendItem) { @@ -386,18 +343,23 @@ export default { }) }, metricChange (value) { - this.init(value) + this.initData(value) }, resize () { this.myChart.resize() }, - initData (data, val) { + /** + * 初始化整理折线图数据 + * @param data + * @param val + */ + initLineData (data, val) { let lineData = [] if (data !== undefined && data.length > 0) { data.forEach(item => { item.type = getLineType(item.type) - if (['Bits/s', 'Packets/s', 'Sessions/s'].indexOf(val) > -1) { - if (item.type === val) { + if (item.type === val) { + if (['Bits/s', 'Packets/s', 'Sessions/s'].indexOf(val) > -1) { lineData = Object.keys((item)).map(t => { return { ...item[t], @@ -405,9 +367,7 @@ export default { key: t } }) - } - } else { - if (item.type === val) { + } else { lineData = Object.keys((item)).map(t => { return { ...item[t], @@ -421,7 +381,6 @@ export default { }) } lineData.splice(0, 1) - console.info(lineData) const tabs = _.cloneDeep(this.tabs) const npmQuantity = _.cloneDeep(this.npmQuantity) if (val === 'Sessions/s') { @@ -435,35 +394,42 @@ export default { } }) this.tabs = tabs - this.echartsInit(this.tabs) + this.initEchartsOption(this.tabs) } else if (val !== 'Bits/s' && val !== 'Packets/s') { - this.legendInit(lineData, npmQuantity, true) + this.initLegend(lineData, npmQuantity, true) } else { - this.legendInit(lineData, tabs, false) + this.initLegend(lineData, tabs, false) } }, - legendInit (data, npmData, show) { - data.forEach((d, i) => { + /** + * 初始化legend + * @param data + * @param npmData + * @param show + */ + initLegend (data, npmData, show) { + const newNpmData = _.clone(npmData) + data.forEach(d => { if (show) { - npmData[d.index].data = d.values - npmData[d.index].analysis = d.analysis + newNpmData[d.index].data = d.values + newNpmData[d.index].analysis = d.analysis } else { - npmData[d.index].data = d.values - npmData[d.index].analysis = d.analysis + newNpmData[d.index].data = d.values + newNpmData[d.index].analysis = d.analysis } }) if (show) { - npmData.forEach((e, i) => { + newNpmData.forEach((e, i) => { e.show = i === data[0].index }) - this.npmQuantity = npmData - this.echartsInit(this.npmQuantity, data[0].unit) + this.npmQuantity = newNpmData + this.initEchartsOption(this.npmQuantity, data[0].unit) } else { - npmData.forEach((e) => { + newNpmData.forEach((e) => { e.show = true }) - this.tabs = npmData - this.echartsInit(this.tabs) + this.tabs = newNpmData + this.initEchartsOption(this.tabs) } } }, @@ -472,7 +438,7 @@ export default { this.chartData = _.cloneDeep(this.chart) } this.timer = setTimeout(() => { - this.init() + this.initData() }, 200) window.addEventListener('resize', this.resize) }, diff --git a/src/views/charts2/charts/options/echartOption.js b/src/views/charts2/charts/options/echartOption.js index a7e6a44a..0306c687 100644 --- a/src/views/charts2/charts/options/echartOption.js +++ b/src/views/charts2/charts/options/echartOption.js @@ -239,7 +239,11 @@ export const linkTrafficLineChartOption = { xAxis: [ { type: 'time', - splitNumber: 8 + splitNumber: 8, + axisLabel: { + formatter: xAxisTimeFormatter, + rich: xAxisTimeRich + } // axisLabel: { // formatter: function (value) { // const data = new Date(value) @@ -286,7 +290,11 @@ export const appListChartOption = { }, xAxis: { show: false, - type: 'time' + type: 'time', + axisLabel: { + formatter: xAxisTimeFormatter, + rich: xAxisTimeRich + } }, yAxis: { show: false, @@ -331,7 +339,11 @@ export const npmLineChartOption = { xAxis: [ { type: 'time', - splitNumber: 8 + splitNumber: 8, + axisLabel: { + formatter: xAxisTimeFormatter, + rich: xAxisTimeRich + } // axisLabel: { // formatter: function (value) { // const data = new Date(value) @@ -391,7 +403,11 @@ export const trafficLineChartOption = { xAxis: [ { type: 'time', - splitNumber: 8 + splitNumber: 8, + axisLabel: { + formatter: xAxisTimeFormatter, + rich: xAxisTimeRich + } // axisLabel: { // formatter: function (value) { // const data = new Date(value) @@ -487,6 +503,10 @@ export const stackedBarChartOption = { }, axisTick: { show: false + }, + axisLabel: { + formatter: xAxisTimeFormatter, + rich: xAxisTimeRich } // axisLabel: { // margin: 12,