CN-65 feat: 流量曲线图、饼图、其他内容
This commit is contained in:
@@ -6,17 +6,17 @@ const { VueLoaderPlugin } = require('vue-loader')
|
|||||||
|
|
||||||
const libMode = process.env.LIBMODE
|
const libMode = process.env.LIBMODE
|
||||||
const isFullMode = libMode === 'full'
|
const isFullMode = libMode === 'full'
|
||||||
let externals = [
|
const externals = [
|
||||||
{
|
{
|
||||||
vue: {
|
vue: {
|
||||||
root: 'Vue',
|
root: 'Vue',
|
||||||
commonjs: 'vue',
|
commonjs: 'vue',
|
||||||
commonjs2: 'vue',
|
commonjs2: 'vue'
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
const plugins = [
|
const plugins = [
|
||||||
new VueLoaderPlugin(),
|
new VueLoaderPlugin()
|
||||||
// new BundleAnalyzerPlugin(),
|
// new BundleAnalyzerPlugin(),
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -50,20 +50,21 @@ const config = {
|
|||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.vue$/,
|
test: /\.vue$/,
|
||||||
use: 'vue-loader',
|
use: 'vue-loader'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(ts|js)x?$/,
|
test: /\.(ts|js)x?$/,
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
loader: 'babel-loader',
|
loader: 'babel-loader'
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.ts', '.tsx', '.js', '.json'],
|
extensions: ['.ts', '.tsx', '.js', '.json']
|
||||||
},
|
},
|
||||||
|
cache: true,
|
||||||
externals,
|
externals,
|
||||||
plugins,
|
plugins
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = config
|
module.exports = config
|
||||||
|
|||||||
@@ -60,3 +60,7 @@ th *:first-letter,
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-table__empty-block {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { shortFormatter } from '@/components/charts/chartFormatter'
|
import { shortFormatter } from '@/components/charts/chart-formatter'
|
||||||
export default {
|
export default {
|
||||||
name: 'ChartTable',
|
name: 'ChartTable',
|
||||||
props: {
|
props: {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { shortFormatter } from '@/components/charts/chartFormatter'
|
import { shortFormatter } from '@/components/charts/chart-formatter'
|
||||||
import { get } from '@/utils/http'
|
import { get } from '@/utils/http'
|
||||||
import { replaceUrlPlaceholder } from '@/utils/tools'
|
import { replaceUrlPlaceholder } from '@/utils/tools'
|
||||||
|
|
||||||
@@ -188,7 +188,8 @@ export default {
|
|||||||
startTime: parseInt(this.startTime / 1000),
|
startTime: parseInt(this.startTime / 1000),
|
||||||
endTime: parseInt(this.endTime / 1000),
|
endTime: parseInt(this.endTime / 1000),
|
||||||
order: this.order,
|
order: this.order,
|
||||||
domain: row.domain
|
domain: row.domain,
|
||||||
|
limit: 10
|
||||||
}
|
}
|
||||||
get(replaceUrlPlaceholder(url, queryParams)).then(response2 => {
|
get(replaceUrlPlaceholder(url, queryParams)).then(response2 => {
|
||||||
if (response2.code === 200) {
|
if (response2.code === 200) {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getChartColor } from '@/components/charts/chart-options'
|
import { getChartColor } from '@/components/charts/chart-options'
|
||||||
import { shortFormatter } from '@/components/charts/chartFormatter'
|
import { shortFormatter } from '@/components/charts/chart-formatter'
|
||||||
export default {
|
export default {
|
||||||
name: 'StatisticsLegend',
|
name: 'StatisticsLegend',
|
||||||
props: {
|
props: {
|
||||||
|
|||||||
55
src/components/charts/chart-formatter.js
Normal file
55
src/components/charts/chart-formatter.js
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
const shortList = [' ', 'K', 'M', 'G', 'T', 'Quadrillion', 'Quintillion']
|
||||||
|
function asciiCompute (num, ascii, units, dot = 2) {
|
||||||
|
if (!num && num !== 0 && num !== '0') {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
num = Number(num)
|
||||||
|
let carry = 0
|
||||||
|
if (num > 1) {
|
||||||
|
const log = Math.log(num) / Math.log(ascii)
|
||||||
|
carry = parseInt(log)
|
||||||
|
num = num / Math.pow(ascii, carry)
|
||||||
|
}
|
||||||
|
if (Number.isInteger(num)) {
|
||||||
|
return num + ' ' + units[carry]
|
||||||
|
} else {
|
||||||
|
return num.toFixed(dot) + ' ' + units[carry]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export function shortFormatter (value, index, dot = 2) {
|
||||||
|
return asciiCompute(value, 1000, shortList, dot)
|
||||||
|
}
|
||||||
|
/* 时间单位转换,例如将ms转为h */
|
||||||
|
const timeStep = [ // 步进倍数,以ms为基数
|
||||||
|
{ unit: 'ms', step: 1 },
|
||||||
|
{ unit: 's', step: 1000 },
|
||||||
|
{ unit: 'm', step: 60 },
|
||||||
|
{ unit: 'h', step: 60 },
|
||||||
|
{ unit: 'd', step: 24 }
|
||||||
|
]
|
||||||
|
export function timeUnitFormatter (time, sourceUnit = 'ms', targetUnit, dot = 2) {
|
||||||
|
let sourceIndex = -1
|
||||||
|
let targetIndex = -1
|
||||||
|
timeStep.forEach((t, i) => {
|
||||||
|
sourceUnit === t.unit && (sourceIndex = i)
|
||||||
|
targetUnit && targetUnit === t.unit && (targetIndex = i)
|
||||||
|
})
|
||||||
|
let multi = 1
|
||||||
|
let result = parseFloat(time)
|
||||||
|
if (targetIndex < 0) {
|
||||||
|
while (sourceIndex < timeStep.length - 1 && result > timeStep[sourceIndex + 1].step) {
|
||||||
|
sourceIndex++
|
||||||
|
multi = timeStep[sourceIndex].step
|
||||||
|
result /= multi
|
||||||
|
}
|
||||||
|
return [multi === 1 ? result : result.toFixed(dot), timeStep[sourceIndex].unit]
|
||||||
|
} else {
|
||||||
|
timeStep.forEach((s, i) => {
|
||||||
|
if (i <= targetIndex) {
|
||||||
|
multi *= s.step
|
||||||
|
}
|
||||||
|
})
|
||||||
|
result /= multi
|
||||||
|
return [result.toFixed(dot), targetUnit]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
* @description chart option和一些工具
|
* @description chart option和一些工具
|
||||||
*/
|
*/
|
||||||
import { format } from 'echarts'
|
import { format } from 'echarts'
|
||||||
import { shortFormatter, tooltipShortFormatter } from './chartFormatter'
|
import { shortFormatter, timeUnitFormatter } from './chart-formatter'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
export const chartColor = ['#5370C6', '#90CC74', '#FAC858', '#EE6666',
|
export const chartColor = ['#5370C6', '#90CC74', '#FAC858', '#EE6666',
|
||||||
'#73BFDE', '#3BA172', '#FC8452', '#9960B4',
|
'#73BFDE', '#3BA172', '#FC8452', '#9960B4',
|
||||||
@@ -179,9 +179,7 @@ const lineStack = {
|
|||||||
}
|
}
|
||||||
const pieWithTable = {
|
const pieWithTable = {
|
||||||
tooltip: {
|
tooltip: {
|
||||||
appendToBody: true,
|
appendToBody: true
|
||||||
trigger: 'item',
|
|
||||||
formatter: tooltipShortFormatter
|
|
||||||
},
|
},
|
||||||
color: chartColor,
|
color: chartColor,
|
||||||
animation: false,
|
animation: false,
|
||||||
@@ -194,10 +192,10 @@ const pieWithTable = {
|
|||||||
itemWidth: 10, // 设置宽度
|
itemWidth: 10, // 设置宽度
|
||||||
itemHeight: 10, // 设置高度
|
itemHeight: 10, // 设置高度
|
||||||
itemGap: 20,
|
itemGap: 20,
|
||||||
|
formatter: tooLongFormatter,
|
||||||
tooltip: {
|
tooltip: {
|
||||||
show: true
|
show: true
|
||||||
},
|
}
|
||||||
formatter: tooLongFormatter
|
|
||||||
},
|
},
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
@@ -209,6 +207,11 @@ const pieWithTable = {
|
|||||||
label: {
|
label: {
|
||||||
formatter: '{d}%'
|
formatter: '{d}%'
|
||||||
},
|
},
|
||||||
|
tooltip: {
|
||||||
|
formatter: function (param, index, callback) {
|
||||||
|
return `${param.name}: ${shortFormatter(param.value)}`
|
||||||
|
}
|
||||||
|
},
|
||||||
emphasis: {
|
emphasis: {
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
shadowBlur: 10,
|
shadowBlur: 10,
|
||||||
|
|||||||
@@ -74,8 +74,11 @@ export const allTableTitle = {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
export const legendMapping = {
|
export const legendMapping = {
|
||||||
bytes_received_rate: 'Bytes Received Rate',
|
bytes_received_rate: i18n.global.t('trafficSummary.throughputPerSecondC2s'),
|
||||||
bytes_sent_rate: 'Bytes Sent Rate',
|
bytes_sent_rate: i18n.global.t('trafficSummary.throughputPerSecondS2c'),
|
||||||
bytes_rate: 'Bytes Rate',
|
bytes_rate: i18n.global.t('trafficSummary.throughputPerSecond'),
|
||||||
session_rate: 'Session Rate'
|
session_rate: i18n.global.t('trafficSummary.sessionsPerSecond'),
|
||||||
|
packets_rate: i18n.global.t('trafficSummary.packetsPerSecond'),
|
||||||
|
packets_received_rate: i18n.global.t('trafficSummary.packetsPerSecondC2s'),
|
||||||
|
packets_sent_rate: i18n.global.t('trafficSummary.packetsPerSecondS2c')
|
||||||
}
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
const shortList = [' ', 'K', 'M', 'G', 'T', 'Quadrillion', 'Quintillion']
|
|
||||||
function asciiCompute (num, ascii, units, dot = 2) {
|
|
||||||
if (!num && num !== 0 && num !== '0') {
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
num = Number(num)
|
|
||||||
let carry = 0
|
|
||||||
if (num > 1) {
|
|
||||||
const log = Math.log(num) / Math.log(ascii)
|
|
||||||
carry = parseInt(log)
|
|
||||||
num = num / Math.pow(ascii, carry)
|
|
||||||
}
|
|
||||||
if (Number.isInteger(num)) {
|
|
||||||
return num + ' ' + units[carry]
|
|
||||||
} else {
|
|
||||||
return num.toFixed(dot) + ' ' + units[carry]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export function shortFormatter (value, index, dot = 2) {
|
|
||||||
return asciiCompute(value, 1000, shortList, dot)
|
|
||||||
}
|
|
||||||
export function tooltipShortFormatter (obj, index, callback, dot = 2) {
|
|
||||||
return asciiCompute(obj.value, 1000, shortList, dot)
|
|
||||||
}
|
|
||||||
@@ -17,7 +17,6 @@
|
|||||||
:expand-on-click-node="false"
|
:expand-on-click-node="false"
|
||||||
:lazy="i === 0"
|
:lazy="i === 0"
|
||||||
highlight-current
|
highlight-current
|
||||||
:show-checkbox="i === 1"
|
|
||||||
@node-click="nodeClick"
|
@node-click="nodeClick"
|
||||||
>
|
>
|
||||||
<template #default="{ node, data }">
|
<template #default="{ node, data }">
|
||||||
|
|||||||
@@ -83,8 +83,8 @@
|
|||||||
>
|
>
|
||||||
<template #title><span :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}</span></template>
|
<template #title><span :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}</span></template>
|
||||||
<template #data>
|
<template #data>
|
||||||
<span>{{handleSingleValue(singleValue.value)}}</span>
|
<span>{{handleSingleValue[0]}}</span>
|
||||||
<span v-if="chartInfo.params && chartInfo.params.unit" class="single-value__unit">{{chartInfo.params.unit}}</span>
|
<span v-if="chartInfo.params && chartInfo.params.unit" class="single-value__unit">{{handleSingleValue[1]}}</span>
|
||||||
</template>
|
</template>
|
||||||
</single-value>
|
</single-value>
|
||||||
<!-- 表格 -->
|
<!-- 表格 -->
|
||||||
@@ -149,7 +149,7 @@ import * as echarts from 'echarts'
|
|||||||
import * as am4Core from '@amcharts/amcharts4/core'
|
import * as am4Core from '@amcharts/amcharts4/core'
|
||||||
import * as am4Maps from '@amcharts/amcharts4/maps'
|
import * as am4Maps from '@amcharts/amcharts4/maps'
|
||||||
import { shallowRef } from 'vue'
|
import { shallowRef } from 'vue'
|
||||||
import { allTableTitle, legendMapping } from '@/components/charts/chartTableTitle'
|
import { allTableTitle, legendMapping } from '@/components/charts/chart-table-title'
|
||||||
import {
|
import {
|
||||||
isEcharts,
|
isEcharts,
|
||||||
isSingleValue,
|
isSingleValue,
|
||||||
@@ -174,7 +174,7 @@ import ChartMap from '@/components/charts/ChartMap'
|
|||||||
import PieTable from '@/components/charts/PieTable'
|
import PieTable from '@/components/charts/PieTable'
|
||||||
import StatisticsLegend from '@/components/charts/StatisticsLegend'
|
import StatisticsLegend from '@/components/charts/StatisticsLegend'
|
||||||
import ChartTablePagination from '@/components/charts/ChartTablePagination'
|
import ChartTablePagination from '@/components/charts/ChartTablePagination'
|
||||||
import { shortFormatter } from '@/components/charts/chartFormatter'
|
import { shortFormatter, timeUnitFormatter } from '@/components/charts/chart-formatter'
|
||||||
import { chartTableDefaultPageSize, chartTableTopOptions, storageKey, chartPieTableTopOptions } from '@/utils/constants'
|
import { chartTableDefaultPageSize, chartTableTopOptions, storageKey, chartPieTableTopOptions } from '@/utils/constants'
|
||||||
import { get } from '@/utils/http'
|
import { get } from '@/utils/http'
|
||||||
import { replaceUrlPlaceholder, getCapitalGeo, getGeoData, lineToSpace } from '@/utils/tools'
|
import { replaceUrlPlaceholder, getCapitalGeo, getGeoData, lineToSpace } from '@/utils/tools'
|
||||||
@@ -499,6 +499,7 @@ export default {
|
|||||||
seriesIndex: 0,
|
seriesIndex: 0,
|
||||||
dataIndex: i
|
dataIndex: i
|
||||||
})
|
})
|
||||||
|
self.selectPieChartName = ''
|
||||||
self.loadPieTableData()
|
self.loadPieTableData()
|
||||||
} else {
|
} else {
|
||||||
if (d.name === params.name) {
|
if (d.name === params.name) {
|
||||||
@@ -558,11 +559,15 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleSingleValue () {
|
handleSingleValue () {
|
||||||
return function (value) {
|
const value = this.singleValue.value
|
||||||
if (!Number(value) && Number(value) !== 0) {
|
const unit = this.chartInfo.params.unit
|
||||||
return '-'
|
if (!Number(value) && Number(value) !== 0) {
|
||||||
|
return '-'
|
||||||
|
} else {
|
||||||
|
if (unit && unit === 'ms') {
|
||||||
|
return Number(value) < 1 ? ['< 1', 'ms'] : timeUnitFormatter(value, null, 0)
|
||||||
} else {
|
} else {
|
||||||
return Number(value) < 0.01 ? '< 0.01' : shortFormatter(value)
|
return Number(value) < 0.01 ? ['< 0.01', ''] : [shortFormatter(value), '']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user