Merge branch 'dev-3.2' of https://git.mesalab.cn/nezha/nezha-fronted into dev-3.2

This commit is contained in:
@changcode
2021-12-08 14:54:00 +08:00
13 changed files with 299 additions and 27 deletions

View File

@@ -17,6 +17,13 @@
:chart-option="chartOption"
:is-fullscreen="isFullscreen"
></chart-pie>
<chart-bar
v-if="isChartBar(chartInfo.type)"
:chart-data="chartData"
:chart-info="chartInfo"
:chart-option="chartOption"
:is-fullscreen="isFullscreen"
></chart-bar>
<chartHexagon
:ref="'chart'+chartInfo.id"
v-if="isHexagonFigure(chartInfo.type)"
@@ -60,7 +67,7 @@ import chartTreemap from './chart/chartTreemap'
import chartUrl from './chart/chartUrl'
import chartValue from './chart/chartValue'
import chartHexagon from './chart/chartHexagon'
import { getOption, isTimeSeries, isHexagonFigure, isUrl, isText, isChartPie } from './chart/tools'
import { getOption, isTimeSeries, isHexagonFigure, isUrl, isText, isChartPie, isChartBar } from './chart/tools'
import lodash from 'lodash'
export default {
@@ -109,6 +116,7 @@ export default {
isTimeSeries,
isHexagonFigure,
isChartPie,
isChartBar,
isUrl,
isText,
resize () {

View File

@@ -1,10 +1,229 @@
<template>
<div
:class="legendPlacement"
ref="pie-chart-box"
class="nz-chart__component nz-chart__component--time-series" @mouseenter="mouseEnterChart"
@mouseleave="mouseLeaveChart"
>
<div :id="`chart-canvas-${chartId}`" class="chart__canvas"></div>
<chart-legend
v-if="hasLegend"
:chart-data="chartData"
:chart-info="chartInfo"
:legends="legends"
:is-fullscreen="isFullscreen"
></chart-legend>
</div>
</template>
<script>
import legend from '@/components/chart/chart/legend'
import chartMixin from '@/components/chart/chartMixin'
import { chartLegendPlacement } from '@/components/common/js/constants'
import * as echarts from 'echarts'
import { getChart, setChart } from '@/components/common/js/common'
import moment from 'moment-timezone'
import bus from '@/libs/bus'
import { formatScientificNotation, getMetricTypeValue } from '@/components/common/js/tools'
import chartDataFormat from '@/components/charts/chartDataFormat'
import { randomcolor } from '@/components/common/js/radomcolor/randomcolor'
import { initColor } from '@/components/chart/chart/tools'
import lodash from 'lodash'
export default {
name: 'chart-bar'
name: 'chart-bar',
components: {
chartLegend: legend
},
mixins: [chartMixin],
props: {
chartInfo: Object,
chartData: Array,
chartOption: Object,
isFullscreen: Boolean
},
computed: {
hasLegend () {
try {
return [chartLegendPlacement.bottom, chartLegendPlacement.left, chartLegendPlacement.right].indexOf(this.chartInfo.param.legend.placement) > -1
} catch (e) {
return false
}
},
legendPlacement () {
try {
switch (this.chartInfo.param.legend.placement) {
case 'left':
case 'right':
case 'bottom': {
return `nz-chart__component--${this.chartInfo.param.legend.placement}`
}
default: return ''
}
} catch (e) {
return ''
}
}
},
data () {
return {
colorList: [],
chartDot: 2,
isInit: true, // 是否是初始化初始化时为true图表初始化结束后设为false
legends: [], // { name, alias, color, statistics: [{type: min, value: xxx}, ...] }
toolboxIconColor: {
active: '#53a3cb',
inactive: '#7e7e7e'
},
chartId: ''
}
},
methods: {
initChart (chartOption) {
const self = this
this.legends = []
chartOption.series = this.initPieData(this.chartInfo, chartOption.series[0], this.chartData) // 生成series和legends
chartOption.xAxis.data = chartOption.series.data.map(item => item.name)
chartOption.axisLabel = {
margin: 8,
formatter (params) {
const dataLength = chartOption.series.data.length || 1
const chartWidth = (document.getElementById('chart-canvas-' + self.chartInfo.id).offsetWidth - 80) / dataLength// 容器宽 - padding - 空余
const length = Math.ceil((chartWidth) / 16)
let val = ''
if (params.length > length) {
val = params.substr(0, length) + '...'
return val
} else {
return params
}
}
}
chartOption.tooltip.formatter = this.formatterFunc
/* 使用setTimeout延迟渲染图表避免样式错乱 */
setTimeout(() => {
const myChart = this.isInit ? echarts.init(document.getElementById(`chart-canvas-${this.chartId}`)) : getChart(this.chartId)
myChart.setOption(chartOption)
this.isInit && setChart(this.chartId, myChart) // 缓存不使用vue的data是为避免整个chart被监听导致卡顿
this.isInit = false
}, 200)
},
getMinMaxFromData (originalDatas) {
let minTime = null
let maxTime = null
let minValue = null
let maxValue = null
// 将数据提为二维数组
let datas = []
originalDatas.forEach((originalData, expressionIndex) => {
originalData.forEach((data, dataIndex) => {
datas = [...datas, ...data.values]
})
})
const timeSorted = datas.sort((a, b) => {
return a[0] - b[0]
})
const valueSorted = datas.sort((a, b) => {
return a[1] - b[1]
})
minTime = timeSorted.length ? timeSorted[0][0] : ''
maxTime = timeSorted.length ? timeSorted[timeSorted.length - 1][0] : ''
minValue = valueSorted.length ? valueSorted[0][1] : ''
maxValue = valueSorted.length ? valueSorted[valueSorted.length - 1][1] : ''
return { minTime, maxTime, minValue, maxValue }
},
initPieData (chartInfo, seriesTemplate, originalDatas) {
let colorIndex = 0
const s = lodash.cloneDeep(seriesTemplate)
s.data = []
originalDatas.forEach((originalData, expressionIndex) => {
originalData.forEach((data, dataIndex) => {
if (s) {
const value = getMetricTypeValue(data.values, chartInfo.param.statistics)
const mapping = this.selectMapping(value, chartInfo.param.valueMapping)
// eslint-disable-next-line vue/no-mutating-props
mapping && (this.chartOption.color[colorIndex] = mapping.color.bac)
s.data.push({
value: chartDataFormat.getUnit(chartInfo.unit ? chartInfo.unit : 2).compute(value, null, -1, 2),
realValue: value,
name: this.handleLegend(chartInfo, data, expressionIndex, dataIndex, colorIndex),
labels: data.metric,
seriesIndex: expressionIndex,
dataIndex: dataIndex,
mapping: mapping,
label: {
...s.label,
formatter: this.pieFormatterLabel,
rich: {
color: {
color: mapping ? mapping.color.text : '#000000'
}
}
},
itemStyle: {
color: mapping ? mapping.color.bac : this.colorList[colorIndex]
}
})
colorIndex++
}
})
})
return s
},
pieFormatterLabel (params) {
let str = '{color|'
if (this.chartInfo.param.text === 'all') {
str += params.data.name
str += ' : '
str += params.data.mapping && params.data.mapping.display ? params.data.mapping.display : params.data.value
}
if (this.chartInfo.param.text === 'value') {
str += params.data.mapping && params.data.mapping.display ? params.data.mapping.display : params.data.value
}
if (this.chartInfo.param.text === 'legend') {
str += params.data.name
}
if (this.chartInfo.param.text === 'none') {
str += ''
}
str += '}'
return str
},
formatterFunc (params, ticket, callback) {
const chartInfo = this.chartData
return `
<div>
<div style="white-space:nowrap;overflow-x:hidden;text-overflow:ellipsis; min-width: 150px; max-width: 600px; line-height: 18px; font-size: 14px;">
<div style="max-width: 500px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-bottom: 5px">${params.data.name}</div>
<div style="font-size:12px;display:flex;justify-content: space-between;">
<div>value</div>
<div style="display: ${params.data.mapping && params.data.mapping.display ? 'none' : 'inline-block'}">${chartDataFormat.getUnit(chartInfo.unit ? chartInfo.unit : 2).compute(params.value, null, -1, 2)}</div>
<div style="display: ${params.data.mapping && params.data.mapping.display ? 'inline-block' : 'none'}">${params.data.mapping.display}</div>
</div>
</div>
</div>
`
}
},
watch: {
chartData: {
deep: true,
handler (n) {
if (!this.isInit) {
this.initChart(this.chartOption)
}
}
}
},
mounted () {
// eslint-disable-next-line vue/no-mutating-props
this.chartOption.color || (this.chartOption.color = initColor(20))
this.colorList = this.chartOption.color
try {
this.isStack = this.chartInfo.param.stack
} catch (e) {}
this.initChart(this.chartOption)
}
}
</script>

View File

@@ -193,9 +193,11 @@ export default {
chartData: {
deep: true,
handler (n) {
if (!this.isInit) {
this.initChart(this.chartOption)
}
}
}
},
mounted () {
// eslint-disable-next-line vue/no-mutating-props

View File

@@ -1,4 +1,32 @@
const chartBarOption = {
tooltip: {
trigger: 'item'
},
legend: {
show: false
},
xAxis: {
type: 'category'
},
yAxis: {
type: 'value'
},
series: [
{
type: 'bar',
data: [],
label: {
show: true,
color: '#333',
width: 100,
align: 'center',
overflow: 'break',
ellipsis: '...'
},
labelLine: {
show: true
}
}
]
}
export default chartBarOption

View File

@@ -15,7 +15,6 @@ const chartPieOption = {
show: true,
color: '#333',
position: 'inside',
rotate: true,
width: 200,
overflow: 'truncate',
ellipsis: '...'

View File

@@ -57,6 +57,9 @@ export function isHexagonFigure (type) {
export function isChartPie (type) {
return type === chartType.pie
}
export function isChartBar (type) {
return type === chartType.bar
}
export function isUrl (type) {
return type === chartType.url
}

View File

@@ -136,11 +136,11 @@ export default {
this.noData = !n || n.length < 1
this.copyDataList = n.map(item => {
let param = item.param
try {
param = JSON.parse(item.param)
} catch (e) {
console.info(e)
}
// try {
// param = JSON.parse(item.param)
// } catch (e) {
// console.info(e)
// }
param.showHeader = true
return {
...item,

View File

@@ -902,7 +902,7 @@ const chartData = {
height: 4,
updateBy: 1,
updateAt: '2021-11-10 07:06:09',
type: 'pie',
type: 'bar',
unit: 2,
weight: 0,
param: JSON.stringify(

View File

@@ -320,6 +320,12 @@ function randomcolor () {
return n()
}
export {
randomcolor
function ColorReverse (OldColorValue) {
const newValue = '0x' + OldColorValue.replace(/#/g, '')
const str = '000000' + (0xFFFFFF - newValue).toString(16)
return '#' + str.substring(str.length - 6, str.length)
}
export {
randomcolor,
ColorReverse
}

View File

@@ -513,6 +513,7 @@
size="small"
v-model.number="item.value"
placeholder="value"
@change="change"
></el-input>
</el-form-item>
<el-form-item
@@ -526,6 +527,7 @@
size="small"
v-model.number="item.from"
placeholder="from"
@change="change"
></el-input>
</el-form-item>
<el-form-item
@@ -538,6 +540,7 @@
:controls="false"
size="small"
v-model.number="item.to"
@change="change"
placeholder="to"
></el-input>
</el-form-item>
@@ -551,6 +554,7 @@
size="small"
v-model="item.regx"
placeholder="regx"
@change="change"
></el-input>
</el-form-item>
</el-row>
@@ -559,7 +563,7 @@
<div class='mapping-display'>Display</div>
</div>
<el-form-item :prop="'param.valueMapping.mapping.' + index + '.display'" :rules="{ required: true, message: $t('validate.required'), trigger: 'change'}" class="thresholds-from-item">
<el-input v-model="item.display" style="margin-right: 10px" :placeholder="$t('placeholder.chart.display')" size="small"/>
<el-input v-model="item.display" style="margin-right: 10px" :placeholder="$t('placeholder.chart.display')" size="small" @change="change"/>
</el-form-item>
<nezhaColor :color-val="item.color" :single="false" :value-arr="[{name:'bac',value:item.color.bac,key:'bac'},{name:'text',value:item.color.text,key:'text'}]" @colorChange="(val,key)=>{colorChange(val, key, index)}"/>
</el-row>
@@ -605,7 +609,7 @@
<div class='mapping-display'>Title</div>
</div>
<el-form-item :prop="'param.columns.' + index + '.title'" :rules="{ required: true, message: $t('validate.required'), trigger: 'change'}" class="thresholds-from-item" style="flex: 1">
<el-input size="small" v-model="item.title" placeholder="regx"></el-input>
<el-input size="small" v-model="item.title" placeholder="regx" @change="change"></el-input>
</el-form-item>
<div>
<div class='mapping-display'>Unit</div>
@@ -624,7 +628,7 @@
<div class='mapping-display'>Display</div>
</div>
<el-form-item :prop="'param.columns.' + index + '.display'" :rules="{ required: true, message: $t('validate.required'), trigger: 'change'}" class="thresholds-from-item">
<el-input v-model="item.display" style="margin-right: 10px" size="small"/>
<el-input v-model="item.display" style="margin-right: 10px" size="small" @change="change"/>
</el-form-item>
</el-row>
</transition-group>
@@ -645,7 +649,7 @@ import publicConfig from '@/components/common/rightBox/chart/publicConfig'
import chartTypeShow from '@/components/common/rightBox/chart/chartTypeShow'
import VueTagsInput from '@johmun/vue-tags-input'
import draggable from 'vuedraggable'
import { randomcolor } from '@/components/common/js/radomcolor/randomcolor'
import { randomcolor, ColorReverse } from '@/components/common/js/radomcolor/randomcolor'
export default {
name: 'chartConfig',
components: {

View File

@@ -1,6 +1,6 @@
import chartDataFormat from '@/components/charts/chartDataFormat'
import { getUUID, resetZIndex } from '@/components/common/js/common'
import { randomcolor } from '@/components/common/js/radomcolor/randomcolor'
import { randomcolor, ColorReverse } from '@/components/common/js/radomcolor/randomcolor'
const rz = {
methods: {
rz (e) {
@@ -304,8 +304,8 @@ export default {
value: undefined,
display: '',
color: {
bac: bacColor,
text: randomcolor()
bac: bacColor + 'FF',
text: ColorReverse(bacColor) + 'FF'
}
})
this.change()

View File

@@ -67,7 +67,7 @@
class="form-item--half-width"
prop="param.limit"
>
<el-input :controls="false" v-model.number="chartConfig.param.limit" :placeholder="$t('placeholder.system.limit')" size="small"/>
<el-input :controls="false" v-model.number="chartConfig.param.limit" :placeholder="$t('placeholder.system.limit')" size="small" @change="change"/>
</el-form-item>
</div>
</div>
@@ -258,6 +258,7 @@
size="small"
v-model.number="item.value"
placeholder="value"
@change="change"
></el-input>
</el-form-item>
<el-form-item
@@ -271,6 +272,7 @@
size="small"
v-model.number="item.from"
placeholder="from"
@change="change"
></el-input>
</el-form-item>
<el-form-item
@@ -284,6 +286,7 @@
size="small"
v-model.number="item.to"
placeholder="to"
@change="change"
></el-input>
</el-form-item>
<el-form-item
@@ -296,6 +299,7 @@
size="small"
v-model="item.regx"
placeholder="regx"
@change="change"
></el-input>
</el-form-item>
</el-row>
@@ -304,7 +308,7 @@
<div class='mapping-display'>Display</div>
</div>
<el-form-item :prop="'param.valueMapping.mapping.' + index + '.display'" :rules="{ required: true, message: $t('validate.required'), trigger: 'change'}" class="thresholds-from-item">
<el-input v-model="item.display" style="margin-right: 10px" size="small"/>
<el-input v-model="item.display" style="margin-right: 10px" size="small" @change="change"/>
</el-form-item>
<nezhaColor :color-val="item.color" :single="false" :value-arr="[{name:'bac',value:item.color.bac,key:'bac'},{name:'text',value:item.color.text,key:'text'}]" @colorChange="(val,key)=>{colorChange(val, key, index)}"/>
</el-row>
@@ -350,7 +354,7 @@
<div class='mapping-display'>Title</div>
</div>
<el-form-item :prop="'param.columns.' + index + 'title'" :rules="{ required: true, message: $t('validate.required'), trigger: 'change'}" class="thresholds-from-item" style="flex: 1">
<el-input size="small" v-model="item.title" placeholder="regx"></el-input>
<el-input size="small" v-model="item.title" placeholder="regx" @change="change"></el-input>
</el-form-item>
<div>
<div class='mapping-display'>Unit</div>
@@ -369,7 +373,7 @@
<div class='mapping-display'>Display</div>
</div>
<el-form-item :prop="'param.columns.' + index + 'display'" :rules="{ required: true, message: $t('validate.required'), trigger: 'change'}" class="thresholds-from-item">
<el-input v-model="item.display" style="margin-right: 10px" size="small"/>
<el-input v-model="item.display" style="margin-right: 10px" size="small" @change="change"/>
</el-form-item>
</el-row>
</transition-group>

View File

@@ -400,7 +400,6 @@ export default {
this.chart.panelId = this.showPanel.id
this.chart.panelName = this.showPanel.name
this.chart.param = JSON.parse(this.chart.param)
this.chart.datasource = 'metrics'
if (!this.chart.groupId || this.chart.groupId == -1) {
this.chart.groupId = ''
}
@@ -503,7 +502,7 @@ export default {
this.$get('visual/panel/chart?panelId=' + params.panelId + '&groupId=0' + '&pageSize=-1').then(response => {
if (response.code === 200) {
this.chartListLoading = false
this.dataList = chartData.data.list.map(item => {
this.dataList = response.data.list.map(item => {
return {
...item,
hide: item.name.indexOf(this.filter.searchName) === -1, // 搜索条件