diff options
25 files changed, 1427 insertions, 90 deletions
diff --git a/nezha-fronted/src/assets/css/common.scss b/nezha-fronted/src/assets/css/common.scss index 7856ea690..6cc276abf 100644 --- a/nezha-fronted/src/assets/css/common.scss +++ b/nezha-fronted/src/assets/css/common.scss @@ -440,7 +440,7 @@ td .nz-icon-gear:before { .chart-bar, .chart-gauge, .chart-sankey, -.chart-time-series, +.chart-time-series-tooltip, .chart-treemap, .chart-pie, .chart-bubble, @@ -456,7 +456,7 @@ td .nz-icon-gear:before { color: $--color-text-regular !important; box-shadow: none !important; } -.chart-time-series, +.chart-time-series-tooltip, .chart-pie, .chart-bar, .chart-treemap, @@ -464,7 +464,26 @@ td .nz-icon-gear:before { visibility: hidden; position: absolute; } - +.chart-time-series-tooltip { + position: absolute; + display: block; + border-style: solid; + white-space: nowrap; + box-shadow: rgba(0, 0, 0, 0.2) 1px 2px 10px; + transition: opacity 0.2s cubic-bezier(0.23, 1, 0.32, 1) 0s, visibility 0.2s cubic-bezier(0.23, 1, 0.32, 1) 0s, transform 0.4s cubic-bezier(0.23, 1, 0.32, 1) 0s; + background-color: rgb(255, 255, 255); + border-width: 1px; + border-radius: 4px; + color: rgb(102, 102, 102); + font: 14px / 21px "Microsoft YaHei"; + padding: 10px; + top: 0px; + left: 0px; + border-color: rgb(255, 255, 255); + z-index: 9998; + visibility: visible; + pointer-events: none; +} .yAxis-icon{ margin-right: 4px; background: transparent !important; @@ -543,7 +562,7 @@ i.nz-icon-override{ outline: none; } } -.chart-time-series.hide{ +.chart-time-series-tooltip.hide{ display: none !important; } .alert-rule-info-two{ diff --git a/nezha-fronted/src/assets/css/components/common/project/L5/CanvasProps.scss b/nezha-fronted/src/assets/css/components/common/project/L5/CanvasProps.scss index 01b1bd5f8..4457ad29d 100644 --- a/nezha-fronted/src/assets/css/components/common/project/L5/CanvasProps.scss +++ b/nezha-fronted/src/assets/css/components/common/project/L5/CanvasProps.scss @@ -376,6 +376,18 @@ margin-top: 10px; } +.ml10{ + margin-left: 10px; +} + +.mb10{ + margin-bottom: 10px; +} + +.mr10{ + margin-right: 10px; +} + .p10 { padding: 10px; } diff --git a/nezha-fronted/src/components/chart/chart.vue b/nezha-fronted/src/components/chart/chart.vue index 0e8be79b7..0ee25b98c 100644 --- a/nezha-fronted/src/components/chart/chart.vue +++ b/nezha-fronted/src/components/chart/chart.vue @@ -280,7 +280,8 @@ import chartRose from './chart/chartRose' import chartStat from './chart/chartStat' import chartTable from './chart/chartTable' import chartText from './chart/chartText' -import chartTimeSeries from './chart/chartTimeSeries' +// import chartTimeSeries from './chart/chartTimeSeries' +import chartTimeSeries from './chart/uplot/chartTimeSeries' import chartTreemap from './chart/chartTreemap' import chartUrl from './chart/chartUrl' import chartHexagonD3 from './chart/chartHexagonD3' diff --git a/nezha-fronted/src/components/chart/chart/chartTable.vue b/nezha-fronted/src/components/chart/chart/chartTable.vue index 1269e103e..3954dd08f 100644 --- a/nezha-fronted/src/components/chart/chart/chartTable.vue +++ b/nezha-fronted/src/components/chart/chart/chartTable.vue @@ -303,7 +303,6 @@ export default { oldValue: '' } const display = this.globalVariablesReplace(column.display) - console.log(column, display, /\{\{.+\}\}/.test(display), params) if (/\{\{.+\}\}/.test(display)) { const labelValue = display.replace(/(\{\{.+?\}\})/g, function (i) { const label = i.substr(i.indexOf('{{') + 2, i.indexOf('}}') - i.indexOf('{{') - 2) @@ -313,7 +312,6 @@ export default { if (label.indexOf('$value') !== -1) { value = chartDataFormat.getUnit(column.unit ? column.unit : 2).compute(value, null, -1, 2) } - console.log(value) if (!((typeof value) == 'string' && value.constructor == String) && isNaN(value)) { let legend = '' if (value.__name__) { @@ -363,7 +361,6 @@ export default { } return value || '' }) - console.log(labelValue) obj[column.title + 'display'] = { display: labelValue, oldValue: oldLabelValue diff --git a/nezha-fronted/src/components/chart/chart/chartTimeSeries.vue b/nezha-fronted/src/components/chart/chart/chartTimeSeries.vue index e26f64969..1feb8df55 100644 --- a/nezha-fronted/src/components/chart/chart/chartTimeSeries.vue +++ b/nezha-fronted/src/components/chart/chart/chartTimeSeries.vue @@ -166,6 +166,7 @@ export default { methods: { initChart (chartOptions = this.chartOption) { this.setDataLink() + console.log(JSON.stringify(this.chartData)) try { this.isStack = this.chartInfo.param.stack } catch (e) {} diff --git a/nezha-fronted/src/components/chart/chart/legend.vue b/nezha-fronted/src/components/chart/chart/legend.vue index 0157b04c6..35957f32c 100644 --- a/nezha-fronted/src/components/chart/chart/legend.vue +++ b/nezha-fronted/src/components/chart/chart/legend.vue @@ -157,51 +157,27 @@ export default { this.clickLegendD3(legendName, index, hasGrey, curIsGrey, currentIsTheOnlyOneHighlight) return } - if (echarts) { - // 判断timeSeries类型图表 先取消多表联动 - if (this.isTimeSeries && (this.isConnect && this.isConnect !== 'none')) { - chart.disconnect('timeSeriesGroup') - } if (!hasGrey) { // 1.除当前legend外全置灰 - echarts.dispatchAction({ - type: 'legendInverseSelect' - }) - echarts.dispatchAction({ - type: 'legendSelect', - name: legendName + echarts.series.forEach((seriesItem, sindex) => { + if (sindex > 0) { + echarts.setSeries(sindex, { show: false, focus: false }) + } }) + echarts.setSeries(index + 1, { show: true, focus: false }) this.isGrey = this.isGrey.map((g, i) => i !== index) } else if (currentIsTheOnlyOneHighlight) { // 2.全高亮 - echarts.dispatchAction({ - type: 'legendAllSelect' + echarts.series.forEach((seriesItem, sindex) => { + if (sindex > 0) { + echarts.setSeries(sindex, { show: true, focus: false }) + } }) this.isGrey = this.isGrey.map(() => false) } else { - const type = curIsGrey ? 'legendSelect' : 'legendUnSelect' - echarts.dispatchAction({ - type: type, - name: legendName - }) + echarts.setSeries(index + 1, { show: true, focus: false }) this.$set(this.isGrey, index, !this.isGrey[index]) } - if (this.isTimeSeries) { - this.$parent.legendChange(this.isGrey) - } - // 点击后 处理Y轴的刻度边的 - const chartInfo = this.chartInfo - const series = this.$lodash.cloneDeep(this.series) - const dataArg = series.filter((seriesItem, seriesIndex) => !this.isGrey[seriesIndex]) - const option = this.renderYAxis(dataArg, chartInfo, 'legend') - getChart(this.chartId) && getChart(this.chartId).setOption({ - yAxis: [ - ...option.yAxis - ] - }) - // 判断timeSeries类型图表 建立多表联动 - if (this.isTimeSeries && (this.isConnect && this.isConnect !== 'none')) { - chart.connect('timeSeriesGroup') - } + this.$emit('legendChange', this.isGrey) } }, clickLegendBar (legendName, index, hasGrey, curIsGrey, currentIsTheOnlyOneHighlight) { @@ -274,22 +250,12 @@ export default { if (this.chartInfo.type === 'pie' || this.chartInfo.type === 'doughnut' || this.chartInfo.type === 'rose') { this.$emit('hoverLegendD3', legendName, index, type) } else if (this.isTimeSeries) { - if (type == 'highlight' && getChart(this.chartId)) { - const option = getChart(this.chartId).getOption() - const series = this.$lodash.cloneDeep(option.series) - series[index].emphasis.focus = 'series' - getChart(this.chartId).setOption({ series }) - } else if (getChart(this.chartId)) { - const option = getChart(this.chartId).getOption() - const series = this.$lodash.cloneDeep(option.series) - series[index].emphasis.focus = 'none' - getChart(this.chartId).setOption({ series }) + const echarts = getChart(this.chartId) + if (type == 'highlight') { + echarts.setSeries(index + 1, { focus: true }) + } else { + echarts.setSeries(null, { focus: true }) } - getChart(this.chartId) && getChart(this.chartId).dispatchAction({ - type: type, - seriesIndex: index, - name: legendName - }) } else { getChart(this.chartId) && getChart(this.chartId).dispatchAction({ type: type, diff --git a/nezha-fronted/src/components/chart/chart/tools.js b/nezha-fronted/src/components/chart/chart/tools.js index 7771bd72e..c642dfece 100644 --- a/nezha-fronted/src/components/chart/chart/tools.js +++ b/nezha-fronted/src/components/chart/chart/tools.js @@ -203,3 +203,11 @@ export function initColor (colorNum = 20) { } return colorList } +export function initIncrs () { + const arr = [] + for (let i = 0; i < 53; i++) { + arr.push(Math.pow(2, i)) + } + return arr +} +export const Incrs = initIncrs() diff --git a/nezha-fronted/src/components/chart/chart/uplot/chartTimeSeries.vue b/nezha-fronted/src/components/chart/chart/uplot/chartTimeSeries.vue new file mode 100644 index 000000000..20efc68e7 --- /dev/null +++ b/nezha-fronted/src/components/chart/chart/uplot/chartTimeSeries.vue @@ -0,0 +1,614 @@ +<template> + <div + :class="legendPlacement" + ref="timeSeries-chart-box" + class="nz-chart__component nz-chart__component--time-series" @mouseenter="mouseEnterChart" + @mouseleave="mouseLeaveChart" + v-my-loading="chartLoading" + > + <div class="chart__canvas" style="position:relative" :class="{'chart-cursor-default':cursorDefault}"> + <div :id="`chart-canvas-${chartId}`"></div> + </div> + <chart-legend + ref="legend" + style="flex-shrink: 0" + v-if="hasLegend" + :chart-data="chartData" + :chart-info="chartInfo" + :legends="legends" + :series="series" + :is-fullscreen="isFullscreen" + @legendChange="legendChange" + ></chart-legend> + <!-- toolbox --> + <div :id="`chart-toolbox-${chartId}`" class="chart-canvas-tooltip no-style-class chart-toolbox" :style="{left:toolbox.x+'px',top:toolbox.y+'px'}" v-if="toolbox.show" v-clickoutside="clickout"> + <div v-html="toolbox.tooltipHtml"></div> + <!-- dataLink --> + <div class="chart-dataLink-list"> + <!-- 复制表达式 --> + <div class="chart-dataLink-item select-series" v-if="chartInfo.datasource==='metrics'||chartInfo.datasource==='logs'" @click="copyExpr"> + <i class="nz-icon nz-icon-override"></i> + <span v-if="chartInfo.datasource==='metrics'">{{$t('overall.copy')}} PromQL</span> + <span v-else>{{$t('overall.copy')}} LogQL</span> + </div> + <!-- 只有一条数据时显示 --> + <div class="chart-dataLink-item select-series" v-if="isGrey.filter(value => value === false).length==1" @click="showAllSeries"> + <i class="nz-icon nz-icon-a-Showallseries"></i> + <span>{{$t('dashboard.showAllSeries')}}</span> + </div> + <!-- 有多条数据时显示 --> + <div class="chart-dataLink-item select-series" v-else @click="showSelectedSeries"> + <i class="nz-icon nz-icon-a-Showseletedseries"></i> + <span>{{$t('dashboard.showSelectedSeries')}}</span> + </div> + <div class="chart-dataLink-item" v-for="(item,index) in dataLink" :title='item.title' :key="index" @click="linkClick(item)"> + <i class="nz-icon nz-icon-link"></i> + <span>{{item.title}}</span> + </div> + </div> + </div> + </div> +</template> + +<script> +import legend from '../legend' +import chartMixin from '@/components/chart/chartMixin' +import renderChart from '@/components/chart/renderChart' +import { chartLegendPlacement } from '@/components/common/js/constants' +import { getChart, setChart, chartCache } from '@/components/common/js/common' +import { initColor } from '@/components/chart/chart/tools' +import UPlot from 'uplot' +import chartTimeSeriesMixin from '@/components/chart/chart/uplot/chartTimeSeriesMixin' +import chartDataFormat from '@/components/chart/chartDataFormat' +import getStackedOpts from './stack' + +export default { + name: 'chartTimeSeries', + components: { + chartLegend: legend + }, + props: { + from: String, + multipleTime: {}, + minusTime: {} + }, + mixins: [chartMixin, renderChart, chartTimeSeriesMixin], + data () { + return { + stackTotalColor: null, + stackTotalColorRight: null, + isStack: false, + hasRightYAxis: false, + chartLoading: false, + cursorDefault: false, + toolbox: { + x: 0, + y: 0, + title: 0, + value: 0, + mapping: {}, + show: false, + metric: {}, + activeIndex: undefined, + clickIndex: undefined + }, + isGrey: [], + seriesData: [] + } + }, + computed: { + lineOption () { + return this.nzDefaultConfig.option + }, + hasLegend () { + try { + return [chartLegendPlacement.bottom, chartLegendPlacement.left, chartLegendPlacement.right].indexOf(this.chartInfo.param.legend.placement) > -1 && this.chartInfo.param.enable.legend + } 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 '' + } + }, + // timeSeries类型图表联动 + isConnect () { + return this.$store.state.panel.isConnect + } + }, + watch: { + // 监听当前鼠标所在的图表id变化 + '$store.state.panel.currentMousemove': { + handler (n) { + if (this.isConnect !== 'crosshair') { + return + } + // 判断是否是当前鼠标所在的图表 + if (n === this.chartId) { + let option = {} + for (const key in chartCache) { + if (!chartCache[key] || chartCache[key].group !== 'timeSeriesGroup') { + continue + } + if (chartCache[key] === getChart(this.chartId)) { + option = { + tooltip: { + className: 'chart-time-series' + } + } + } else { + option = { + tooltip: { + className: 'chart-time-series hide' + } + } + } + chartCache[key].setOption(option) + } + } + } + } + }, + methods: { + initChart (chartOptions = this.chartOption) { + this.setDataLink() + try { + this.isStack = !!this.chartInfo.param.stack + } catch (e) {} + const self = this + const leftUnit = this.chartInfo.unit + const leftUnitCompute = chartDataFormat.getUnit(leftUnit) + const rightUnit = this.$lodash.get(this.chartInfo, 'param.rightYAxis.unit', 2) + const rightUnitCompute = chartDataFormat.getUnit(rightUnit) + const incrs = leftUnitCompute.ascii == 1024 ? this.incrs : undefined + const rightIncrs = rightUnitCompute.ascii == 1024 ? this.incrs : undefined + const decimals = this.chartInfo.param.decimals || 2 + const cursLeft = -10 + const cursTop = -10 + const { seriesData, seriesAll } = this.initSeriesData(this.chartData) + this.isNoData = false + if (!seriesData.length || seriesData.length == 1) { + this.isNoData = true + this.$emit('chartIsNoData', this.isNoData) + } + if (this.isNoData) { + return + } + // .compute(minusVal, null, -1, decimals) + let opts = { + id: `chart-canvas-${this.chartId}-uplot`, + mode: 1, + width: 100, + height: 100, + cursor: { + focus: { + prox: 5 + }, + drag: { + x: true + }, + dataIdx: (self, seriesIdx, hoveredIdx, cursorXVal) => { + const seriesData = self.data[seriesIdx] + const hoverProximityPx = (self.valToPos(self.data[0][1], 'x') - self.valToPos(self.data[0][0], 'x')) / 2 + if (seriesData[hoveredIdx] == null) { + let nonNullLft = null + let nonNullRgt = null + let i + + i = hoveredIdx + while (nonNullLft == null && i-- > 0) { + if (seriesData[i] != null) { nonNullLft = i } + } + + i = hoveredIdx + while (nonNullRgt == null && i++ < seriesData.length) { + if (seriesData[i] != null) { nonNullRgt = i } + } + + const xVals = self.data[0] + + const curPos = self.valToPos(cursorXVal, 'x') + const rgtPos = nonNullRgt == null ? Infinity : self.valToPos(xVals[nonNullRgt], 'x') + const lftPos = nonNullLft == null ? -Infinity : self.valToPos(xVals[nonNullLft], 'x') + + const lftDelta = curPos - lftPos + const rgtDelta = rgtPos - curPos + + if (lftDelta <= rgtDelta) { + if (lftDelta <= hoverProximityPx) { hoveredIdx = nonNullLft } + } else { + if (rgtDelta <= hoverProximityPx) { hoveredIdx = nonNullRgt } + } + } + return hoveredIdx + }, + points: { + size: 10, + width: 5 + } + }, + plugins: [ + this.tooltipPlugin({ + onclick (u, seriesIdx, dataIdx) { + console.log(u, seriesIdx, dataIdx, 'nz-tooltipClick') + } + }) + ], + padding: [15, this.autoPadRight, 15, 15], + legend: { + show: false + }, + series: [ + { + scale: 'x' + } + ], + tzDate: ts => UPlot.tzDate(new Date(ts * 1e3), localStorage.getItem('nz-sys-timezone')), + fmtDate: () => { + return self.xAxisLabelFormatter(seriesData[0][0], seriesData[0][seriesData[0].length - 1]) + }, + axes: [ + { + scale: 'x', + gap: 5, + grid: { + show: true, + stroke: 'rgba(0, 10, 23, 0.09)', + width: 1 + } + }, + { + scale: 'left', + values: (u, vals, space) => vals.map(v => leftUnitCompute.compute(v, null, -1, decimals)), + incrs: incrs, + gap: 5, + grid: { + show: true, + stroke: 'rgba(0, 10, 23, 0.09)', + width: 1 + }, + // space: (self) => { + // console.log(self) + // return 50 + // }, + size (self, values, axisIdx, cycleNum) { + const axis = self.axes[axisIdx] + + // bail out, force convergence + if (cycleNum > 1) { return axis._size } + + let axisSize = axis.ticks.size + axis.gap + + // find longest value + const longestVal = (values ?? []).reduce((acc, val) => ( + val.length > acc.length ? val : acc + ), '') + + if (longestVal != '') { + self.ctx.font = axis.font[0] + axisSize += self.ctx.measureText(longestVal).width / devicePixelRatio + } + + return Math.ceil(axisSize) + } + }, + { + show: true, + side: 1, + grid: { + show: false, + stroke: 'rgba(0, 10, 23, 0.09)', + width: 1 + }, + scale: 'right', + gap: 5, + // space: (self) => { + // console.log(self) + // return 50 + // }, + values: (u, vals, space) => vals.map(v => rightUnitCompute.compute(v, null, -1, decimals)), + incrs: rightIncrs, + ticks: { + show: false // true + }, + size (self, values, axisIdx, cycleNum) { + const axis = self.axes[axisIdx] + + // bail out, force convergence + if (cycleNum > 1) { return axis._size } + + let axisSize = axis.ticks.size + axis.gap + + // find longest value + const longestVal = (values ?? []).reduce((acc, val) => ( + val.length > acc.length ? val : acc + ), '') + + if (longestVal != '') { + self.ctx.font = axis.font[0] + axisSize += self.ctx.measureText(longestVal).width / devicePixelRatio + } + + return Math.ceil(axisSize) + } + } + ], + scales: { + x: { + key: 'x', + auto: true, + ori: 0, + dir: 1, + time: true + }, + left: { + key: 'left', + time: false, + auto: true, + ori: 1, + dir: 1, + distr: 1 + }, + right: { + key: 'right', + time: false, + auto: true, + ori: 1, + dir: 1, + distr: 1 + } + } + } + if (this.isConnect !== 'none') { // 是否同步光标 + opts.cursor.sync = { + key: 'nz' + this.isFullscreen, + setSeries: true, + scales: [null, null] + } + } + let data = this.seriesData = seriesData + opts.series.push(...seriesAll) + if (this.isStack) { + const obj = getStackedOpts('', opts, data) + opts = obj.opts + data = obj.data + } + this.renderMinMax(opts) + if (getChart(this.chartId)) { + getChart(this.chartId).destroy() + } + setTimeout(() => { // 延迟加载 保证legend的高度正常 + const dom = document.getElementById(`chart-canvas-${this.chartId}`) + const width = dom.offsetWidth + const height = dom.offsetHeight + opts.width = width + opts.height = height + let chartUplot = '' + chartUplot = new UPlot(opts, data, document.getElementById(`chart-canvas-${this.chartId}`)) + setChart(this.chartId, chartUplot) + }, 100) + }, + renderMinMax (opts) { + let leftMin = this.$lodash.get(this.chartInfo, 'param.min', undefined) + let leftMax = this.$lodash.get(this.chartInfo, 'param.max', undefined) + if (leftMin || leftMax) { + if (leftMin > leftMax) { + const temp = leftMin + leftMin = leftMax + leftMax = temp + } + opts.scales.left.range = (self, initMin, initMax, scaleKey) => { + if (typeof (leftMin) === 'undefined') { + if (initMin > 0) { + leftMin = initMin / 2 + } else { + leftMin = initMin * 2 + } + } + if (typeof (leftMax) === 'undefined') { + if (initMax > 0) { + leftMax = initMax * 2 + } else { + leftMax = initMax / 2 + } + } + return [leftMin, leftMax] + } + } + const rightYAxisEnable = this.$lodash.get(this.chartInfo, 'param.enable.rightYAxis', false) + if (rightYAxisEnable) { + let rightMin = this.$lodash.get(this.chartInfo, 'param.rightYAxis.min', undefined) + let rightMax = this.$lodash.get(this.chartInfo, 'param.rightYAxis.max', undefined) + if (rightMin || rightMax) { + if (rightMin > leftMax) { + const temp = rightMin + rightMin = rightMax + rightMax = temp + } + opts.scales.right.range = (self, initMin, initMax, scaleKey) => { + if (typeof (rightMin) === 'undefined') { + if (initMin > 0) { + rightMin = initMin / 2 + } else { + rightMin = initMin * 2 + } + } + if (typeof (rightMax) === 'undefined') { + if (initMax > 0) { + rightMax = initMax * 2 + } else { + rightMax = initMax / 2 + } + } + return [rightMin, rightMax] + } + } + } + }, + size (self, values, axisIdx, cycleNum) { + const axis = self.axes[axisIdx] + + // bail out, force convergence + if (cycleNum > 1) { return axis._size } + + let axisSize = axis.ticks.size + axis.gap + + // find longest value + const longestVal = (values ?? []).reduce((acc, val) => ( + val.length > acc.length ? val : acc + ), '') + + if (longestVal != '') { + self.ctx.font = axis.font[0] + axisSize += self.ctx.measureText(longestVal).width / devicePixelRatio + } + + return Math.ceil(axisSize) + }, + autoPadRight (self, side, sidesWithAxes, cycleNum) { + const xAxis = self.axes[0] + + const xVals = xAxis._values + + if (xVals != null) { + // bail out, force convergence + if (cycleNum > 2) { return self._padding[1] } + + const xSplits = xAxis._splits + const rightSplit = xSplits[xSplits.length - 1] + const rightSplitCoord = self.valToPos(rightSplit, 'x') + const leftPlotEdge = (self.bbox.left / devicePixelRatio) + const rightPlotEdge = leftPlotEdge + (self.bbox.width / devicePixelRatio) + const rightChartEdge = rightPlotEdge + self._padding[1] + + const pxPerChar = 15 + const rightVal = xVals[xVals.length - 1] + '' + const valHalfWidth = pxPerChar * (rightVal.length / 2) + + const rightValEdge = leftPlotEdge + rightSplitCoord + valHalfWidth + + if (rightValEdge >= rightChartEdge) { + return rightValEdge - rightPlotEdge + } + } + + // default size + return 15 + }, + clickout () { + if (this.toolbox.show) { + this.toolbox.show = false + } + }, + showAllSeries () { + const echarts = getChart(this.chartId) + const arr = [] + if (echarts) { + echarts.series.forEach((seriesItem, sindex) => { + if (sindex > 0) { + echarts.setSeries(sindex, { show: true, focus: false }) + arr.push(false) + } + }) + this.isGrey = arr + if (this.$refs.legend) { + this.$refs.legend.isGrey = arr + } + if (this.$refs.legend) { + this.$refs.legend.isGrey = this.isGrey = arr + } + } + this.renderYaxis() + this.clickout() + }, + showSelectedSeries () { + const index = this.toolbox.clickIndex + const echarts = getChart(this.chartId) + const arr = [] + if (echarts) { + echarts.series.forEach((seriesItem, sindex) => { + if (sindex > 0) { + echarts.setSeries(sindex, { show: false, focus: false }) + arr.push(true) + } + }) + echarts.setSeries(index + 1, { show: true, focus: false }) + arr[index] = false + this.isGrey = arr + if (this.$refs.legend) { + this.$refs.legend.isGrey = arr + } + } + this.renderYaxis() + this.clickout() + }, + legendChange (isGrey) { + this.isGrey = isGrey + this.renderYaxis() + }, + resize () { + setTimeout(() => { + const dom = this.$refs['timeSeries-chart-box'] + const width = dom.offsetWidth + const legendHeight = this.$lodash.get(this.$refs, 'legend.$el.offsetHeight', 40) + const height = dom.offsetHeight - legendHeight + const u = getChart(this.chartId) + if (u) { + u.setSize({ width, height }) + } + }, 100) + }, + renderYaxis () { + const u = getChart(this.chartId) + let leftShow = false + let rightShow = false + u.series.forEach(item => { + if (item.show && item.scale == 'left') { + leftShow = true + } + if (item.show && item.scale == 'right') { + rightShow = true + } + }) + u.axes[1].show = leftShow + u.axes[2].show = rightShow + if (!leftShow) { + u.axes[2].grid.show = true + } else { + u.axes[2].grid.show = false + } + u.redraw(false, true) + } + }, + mounted () { + this.chartOption.color || (this.chartOption.color = initColor(20)) + this.colorList = this.chartOption.color + try { + this.isStack = !!this.chartInfo.param.stack + } catch (e) {} + this.chartInfo.loaded && this.initChart(this.chartOption) + }, + beforeDestroy () { + const chart = getChart(this.chartId) + if (chart) { + const over = chart.over + over.removeEventListener() + chart.destroy() + } + } +} +</script> + +<style scoped> + +</style> diff --git a/nezha-fronted/src/components/chart/chart/uplot/chartTimeSeriesMixin.js b/nezha-fronted/src/components/chart/chart/uplot/chartTimeSeriesMixin.js new file mode 100644 index 000000000..9b8a7f935 --- /dev/null +++ b/nezha-fronted/src/components/chart/chart/uplot/chartTimeSeriesMixin.js @@ -0,0 +1,665 @@ +import { initColor, Incrs } from '@/components/chart/chart/tools' +import { randomcolor } from '@/components/common/js/radomcolor/randomcolor' +import chartDataFormat from '@/components/chart/chartDataFormat' +import lodash from 'lodash' +import { formatScientificNotation, getMetricTypeValue } from '@/components/common/js/tools' +import bus from '@/libs/bus' +import moment from 'moment-timezone' +import { getChart } from '@/components/common/js/common' +import uplot from 'uplot' +export default { + data () { + return { + seriesColor: initColor(), + incrs: Incrs, + dataIdx: null, + seriesIdx: null, + mousePosition: { + top: 0, + left: 0 + } + } + }, + computed: { + // timeSeries类型图表联动 + isConnect () { + return this.$store.state.panel.isConnect + }, + // timeSeries类型图表联动 + currentMousemove () { + return this.$store.state.panel.currentMousemove + } + }, + methods: { + initSeriesData (chartData) { // 处理数据 以及 series + let time = [] + this.legends = [] + const nullValueMode = this.chartInfo.param.nullType + const seriesData = [] // 返回的数据 + const seriesAll = [ // 返回的 series + + ] + let chartIndex = 0 + chartData.forEach(series => { // 首先处理时间 对应点没有值(不包括null 则添加undefind) + series.forEach(item => { + time.push(...item.values.map(value => value[0])) + }) + }) + const timeSet = new Set(time) + time = [...timeSet] + time = this.$lodash.sortBy(time, function (o) { return o }) + const ObjTime = {} + time.forEach(item => { + ObjTime[item] = undefined + }) + chartData.forEach((series, expressionIndex) => { // 首先处理时间 对应点没有值(不包括null 则添加undefind) + series.forEach((item, seriesIndex) => { + if (chartIndex >= 20 && !this.showAllData) { + return + } + let seriesObjTime = {} + // 若需要统计,处理统计数据 + const statisticsTypes = this.chartInfo.param.legend ? this.chartInfo.param.legend.values : '' + let statistics = [] + if (!lodash.isEmpty(statisticsTypes)) { + statistics = statisticsTypes.map(type => { + return { type, value: getMetricTypeValue(item.values, type) } + }) + } + item.statistics = statistics + item.values.forEach(value => { + let itemValue = value[1] + if (typeof (itemValue) === 'string') { + itemValue = Number(itemValue) + } + if (itemValue === null && nullValueMode !== 'null') { + if (nullValueMode === 'zero') { + itemValue = 0 + } else { + itemValue = undefined + } + } + seriesObjTime[value[0]] = itemValue + }) + // 处理统计数据 statistics + seriesObjTime = { + ...ObjTime, + ...seriesObjTime + } + item.expressionIndex = expressionIndex + seriesData.push(Object.keys(seriesObjTime).map(time => seriesObjTime[time])) + seriesAll.push(this.renderSeries(item, expressionIndex, seriesIndex, chartIndex)) + chartIndex++ + }) + }) + seriesData.unshift(time) + this.series = seriesAll + return { + seriesData, + seriesAll + } + }, + renderSeries (series, expressionIndex, dataIndex, chartIndex) { + const leftUnit = this.chartInfo.unit + const leftUnitCompute = chartDataFormat.getUnit(leftUnit) + const decimals = this.chartInfo.param.decimals || 2 + if (chartIndex > 19) { + this.seriesColor.push(randomcolor()) + } + const legend = this.handleLegend(this.chartInfo, series, expressionIndex, dataIndex, chartIndex) + let isRight + if (this.chartInfo.param.enable.rightYAxis) { + const elementNames = this.$lodash.get(this.chartInfo, 'param.rightYAxis.elementNames', []) + isRight = elementNames.indexOf(series.elements.name) !== -1 ? 1 : 0 + } + const name = legend.name + const alias = legend.alias + const statistics = series.statistics + const chartType = this.chartInfo.type + + const obj = { + name: name, + label: alias, + scale: isRight ? 'right' : 'left', // right + yAxisIndex: isRight, // right + // values: (u, v) => series.elements.name + JSON.stringify(series.metric), + stroke: this.seriesColor[chartIndex], + width: 1 / devicePixelRatio, + expressionIndex: series.expressionIndex, + paths (taht, seriesIdx, idx0, idx1, filtIdxs) { + return uplot.paths.spline(taht)(taht, seriesIdx, idx0, idx1, filtIdxs) + }, + spanGaps: true + } + if (chartType === 'area') { + obj.fill = this.seriesColor[chartIndex] + '20' // 面积图使用 + } + if (chartType === 'point') { + obj.points = { + show: true, + size: 6, + width: 3, + fill: this.seriesColor[chartIndex], + stroke: this.seriesColor[chartIndex] + } + obj.width = 0 + } + this.legends.push({ name, alias, statistics, color: this.seriesColor[chartIndex] }) + return obj + }, + tooltipPlugin ({ onclick, shiftX = 10, shiftY = 10 }) { + let tooltipLeftOffset = 0 + let tooltipTopOffset = 0 + const self = this + const totoalStr = this.$t('dashboard.dashboard.chartTotal') + const tooltip = document.createElement('div') + tooltip.className = 'nz-uplot-tooltip chart-time-series-tooltip' + tooltip.style.display = 'none' + let over + let isRender = false + function setTooltip (u, e) { // 生成tooltip内容 + tooltip.style.display = 'none' + over.style.cursor = null + isRender = false + const { top } = u.cursor + const lft = u.valToPos(u.data[0][self.dataIdx], 'x') + const windowWidth = window.innerWidth// 窗口宽度 + const windowHeight = window.innerHeight// 窗口高度 + let x = 0 + let y = 0 + if (self.mousePosition.left < (windowWidth / 2)) { // 说明鼠标在左边放不下提示框 + tooltip.style.left = (tooltipLeftOffset + lft + shiftX) + 'px' + } else { + tooltip.style.left = (tooltipLeftOffset + lft - shiftX) + 'px' + x = '-100%' + } + if (self.mousePosition.top + 50 < windowHeight / 2) { // 说明鼠标上面放不下提示框 + tooltip.style.top = (tooltipTopOffset + top + shiftY) + 'px' + } else { + tooltip.style.top = (tooltipTopOffset + top - shiftY) + 'px' + y = '-100%' + } + tooltip.style.transform = `translate(${x},${y})` + if (!self.$lodash.get(self.chartInfo, 'param.enable.tooltip', false)) { + return + } + let params = [] + const tooltipModel = self.$lodash.get(self.chartInfo, 'param.tooltip.mode', 'single') + if (self.chartInfo.param && !(tooltipModel == 'single')) { + params = u.series.map((s, i) => { + if (i == 0) return '' + const value = self.seriesData[i][self.dataIdx] + return { + seriesIndex: i - 1, + yAxisIndex: s.yAxisIndex, + value: [u.data[0][self.dataIdx], value], + seriesName: s.label, + show: s.show + } + }) + params = params.filter(item => { + return item && item.show + }) + } else if (self.seriesIdx) { + let obj = self.series[self.seriesIdx - 1] + let value + if (!obj) { + obj = {} + } else { + value = self.seriesData[self.seriesIdx][self.dataIdx] + } + params = [{ + seriesIndex: self.seriesIdx - 1, + yAxisIndex: obj.yAxisIndex, + value: [u.data[0][self.dataIdx], value], + seriesName: obj.label || '' + }] + } + isRender = !!params.length + if (!isRender) { + tooltip.style.display = 'none' + return + } else { + tooltip.style.display = 'block' + } + if (self.isConnect == 'crosshair' && self.chartId != self.currentMousemove) { + tooltip.style.display = 'none' + return + } + if (tooltipModel == 'single' && self.isConnect !== 'none' && self.chartId != self.currentMousemove) { + tooltip.style.display = 'none' + return + } + if (self.seriesIdx) { + over.style.cursor = 'pointer' + } + let str = '<div class="nz-tooltip nz-chart__tooltip">' + const hasTotal = self.isStack + const decimals = self.chartInfo.param.decimals || 2 + // 区分左y轴右y轴 + params.forEach(item => { + if (self.series[item.seriesIndex]) { + item.yAxisIndex = self.series[item.seriesIndex].yAxisIndex + } + }) + // 排序先展示左y轴 + params.sort((a, b) => a.yAxisIndex - b.yAxisIndex) + // 分割 + const rightYAxisIndex = params.findIndex(item => item.yAxisIndex == 1) + let leftYAxis = [] + let rightYAxis = [] + if (rightYAxisIndex != -1) { + leftYAxis = params.slice(0, rightYAxisIndex) + rightYAxis = params.slice(rightYAxisIndex) + } else { + leftYAxis = params + } + handler(leftYAxis, 'left') + handler(rightYAxis, 'right') + function handler (arr, type) { + if (!arr.length) { + return + } + + // tooltip排序 + let sortBy + if (self.$lodash.get(self.chartInfo, 'param.enable.tooltip') && self.$lodash.get(self.chartInfo, 'param.tooltip.mode') !== 'single' && self.$lodash.get(self.chartInfo, 'param.tooltip.sort') !== 'none') { + sortBy = self.$lodash.get(self.chartInfo, 'param.tooltip.sort') + } + const previousIndex = arr.findIndex(item => item.seriesName.indexOf('Previous') !== -1) + if (previousIndex != -1) { // 对比状态 + const arrNow = arr.slice(0, previousIndex) + const arrPrevious = arr.slice(previousIndex) + if (sortBy === 'asc') { + arrNow.sort((a, b) => a.value[1] - b.value[1]) + arrPrevious.sort((a, b) => a.value[1] - b.value[1]) + } else if (sortBy === 'desc') { + arrNow.sort((a, b) => b.value[1] - a.value[1]) + arrPrevious.sort((a, b) => b.value[1] - a.value[1]) + } + arr = [...arrNow, ...arrPrevious] + } else { + if (sortBy === 'asc') { + arr.sort((a, b) => a.value[1] - b.value[1]) + } else if (sortBy === 'desc') { + arr.sort((a, b) => b.value[1] - a.value[1]) + } + } + + let sum = 0 + let flag = true + arr.forEach((item, i) => { + let unit = self.chartInfo.unit ? self.chartInfo.unit : 2 + if (type == 'right') { + unit = lodash.get(self, 'chartInfo.param.rightYAxis.unit', 2) + } + const nameArr = item.seriesName.split('-') + // if (nameArr.length > 1) { + // nameArr.splice(nameArr.length - 1, 1) + // } + const seriesName = nameArr.join('-') + if (i === 0 && item.seriesName.indexOf('Previous') === -1 && type == 'left') { + const value = bus.computeTimezone(item.value[0] * 1000) + const tData = new Date(value) + str += '<div class="tooltip-title" style="margin-bottom: 5px">' + str += bus.timeFormate(tData) + str += '</div>' + } + // 两条y轴数据分割线 + if (i == 0 && rightYAxisIndex != 0 && type == 'right') { + str += '<div style="border: 1px solid #EEEEEE;margin-top: 5px;margin-bottom: 5px"></div>' + } + if (item.seriesName.indexOf('Previous') === -1 && type == 'right') { + if (i == 0 && (rightYAxisIndex == 0 || (arr.some(item => item.seriesName.indexOf('Previous') !== -1)))) { + const value = bus.computeTimezone(item.value[0] * 1000) + const tData = new Date(value) + str += '<div class="tooltip-title" style="margin-bottom: 5px">' + str += bus.timeFormate(tData) + str += '</div>' + } + } + // Previous分割线 + if (i !== 0 && flag && item.seriesName.indexOf('Previous') !== -1) { + str += '<div style="border: 1px solid #EEEEEE;margin-top: 5px;margin-bottom: 5px"></div>' + } + if (flag && item.seriesName.indexOf('Previous') !== -1) { + flag = false + const value = bus.computeTimezone(item.value[0] * 1000 - self.minusTime) + const tData = new Date(value) + str += '<div class="tooltip-title" style="margin-bottom: 5px">' + str += bus.timeFormate(tData) + str += '</div>' + } + const color = self.colorList[item.seriesIndex] + const previousItem = arr.find((series) => ('Previous ' + item.seriesName) === series.seriesName) + let paramsDot = bus.countDecimals(item.value[1]) + if (paramsDot < decimals) { + paramsDot = decimals + } else if (paramsDot > 6) { + paramsDot = 6 + } + const val = typeof (item.value[1]) == 'undefined' ? 0 : formatScientificNotation(item.value[1], paramsDot) + const showVal = typeof (item.value[1]) == 'undefined' ? '' : chartDataFormat.getUnit(unit).compute(val, null, -1, decimals) + sum += isNaN(self.numberWithEConvent(val)) ? 0 : parseFloat(self.numberWithEConvent(val)) + let previousDom = '' + if (previousItem) { + const previousVal = typeof (previousItem.value[1]) == 'undefined' ? 0 : formatScientificNotation(previousItem.value[1], paramsDot) + let minusVal = 0 + let operator + if (previousVal <= val) { + minusVal = val - previousVal + operator = '+' + } else { + minusVal = previousVal - val + operator = '-' + } + previousDom = ` + <span>${operator}${chartDataFormat.getUnit(unit).compute(minusVal, null, -1, decimals)}</span> + ` + } + + // 根据左右轴设置图标 + let className = 'row__color-block' + if (item.yAxisIndex == 0) { + className = 'yAxis-icon nz-icon nz-icon-zuozongzhou' + } else if (item.yAxisIndex == 1) { + className = 'yAxis-icon nz-icon nz-icon-youzongzhou' + } + + // 鼠标悬浮 series data symbol 时,tooltip 中相应的legend 高亮显示 + str += ` + <div class="${(self.seriesIdx - 1 == item.seriesIndex) ? 'tooltip__row highlight' : 'tooltip__row'}" title="${seriesName}"> + <div class="row__label"> + <span class="${className}" style="background-color: ${color};color: ${color}"></span> + <span>${seriesName}</span> + </div> + <div class="row__value"> + <span>${showVal}</span> + ${previousDom} + </div> + </div> + ` + }) + // 显示total + if (hasTotal) { + sum = parseFloat(Number(sum).toFixed(2)) + let unit = self.chartInfo.unit ? self.chartInfo.unit : 2 + let className = 'row__color-block' + let color = '' + if (type == 'left') { + // 判断是否开启rightYAxis 否则显示普通图标 + if (self.series.some(item => item.yAxisIndex == 0)) { + className = 'yAxis-icon nz-icon nz-icon-zuozongzhou' + } + if (!self.stackTotalColor) { + self.stackTotalColor = randomcolor() + } + color = self.stackTotalColor + } else { + unit = lodash.get(self, 'chartInfo.param.rightYAxis.unit', 2) + className = 'yAxis-icon nz-icon nz-icon-youzongzhou' + if (!self.stackTotalColorRight) { + self.stackTotalColorRight = randomcolor() + } + color = self.stackTotalColorRight + } + str += ` + <div class="tooltip__row"> + <div class="row__label" title="${totoalStr}"> + <span class="${className}" style="background-color: ${color};color: ${color}"></span> + <span>${totoalStr}</span> + </div> + <div class="row__value"> + <span>${chartDataFormat.getUnit(unit).compute(sum, null, -1, decimals)}</span> + </div> + </div> + ` + } + } + str += '</div>' + tooltip.innerHTML = str + } + return { + hooks: { + ready: [ + u => { + over = u.over + tooltipLeftOffset = parseFloat(over.style.left) + tooltipTopOffset = parseFloat(over.style.top) + u.root.querySelector('.u-wrap').appendChild(tooltip) + over.addEventListener('mouseenter', self.uplotMouseenter) + // over.addEventListener('mouseleave', self.uplotMouseleave.bind(self, hideTooltip, over)) 放入mouseenter 减少绑定事件数量 + // over.addEventListener('mousemove', self.uplotMousemove) + // over.addEventListener('mousedown', self.uplotMousedown) + // over.addEventListener('mouseup', self.uplotMouseup.bind(self, nodeInfo)) + } + ], + setCursor: [ + u => { + const c = u.cursor + if (self.dataIdx != c.idx) { + self.dataIdx = c.idx + setTooltip(u) + } + } + ], + setSeries: [ + (u, sidx) => { + if (self.seriesIdx != sidx) { + this.seriesIdx = sidx + if (self.dataIdx != null) { setTooltip(u) } + } + } + ], + drawClear: [ + () => { + self.renderThresholds() + } + ] + } + } + }, + xAxisLabelFormatter (minTime, maxTime) { + const self = this + return function (val, index) { + const value = self.momentStrToTimestamp(self.momentTz(val)) + let offset = localStorage.getItem('nz-sys-timezone') + offset = moment.tz(offset).format('Z') + offset = Number.parseInt(offset) + const localOffset = new Date().getTimezoneOffset() * 60 * 1000 * -1 // 默认 一分钟显示时区偏移的结果 + // if (window.dataJson) { + // offset = new Date().getTimezoneOffset() * -1 / 60 + // } + const tData = new Date(value - localOffset + offset * 60 * 60 * 1000) + let hour = tData.getHours() + hour = hour > 9 ? hour : '0' + hour // 加0补充为两位数字 + let minute = tData.getMinutes() + minute = minute > 9 ? minute : '0' + minute // 如果分钟小于10,则在前面加0补充为两位数字 + if (minTime !== null && maxTime !== null) { + const diffSec = (maxTime - minTime) + const secOneDay = 12 * 60 * 60// 0.5天的秒数 + const secOneMonth = secOneDay * 30// 30天的秒数 + const dateFormatStr = self.timeFormatMain.split(' ')[0] + let str = '' + const month = tData.getMonth() + 1 + const day = tData.getDate() + if (dateFormatStr === 'DD/MM/YYYY') { + str += [day, month].join('/') + } else if (dateFormatStr === 'MM/DD/YYYY') { + str += [month, day].join('/') + } else { + str += [month, day].join('-') + } + if (diffSec <= secOneDay - 100) { // 同一天 + return [hour, minute].join(':') + } else if (diffSec < secOneMonth) { // 大于1天,小于30天 + return str + '\n' + [hour, minute].join(':') + } else { // 大于等于30天 + return str + } + } else { + return [tData.getFullYear(), tData.getMonth() + 1, tData.getDate()].join('/') + '\n' + [hour, minute].join(':') + } + } + }, + uplotMouseenter () { + const chart = getChart(this.chartId) + const over = chart.over + const root = chart.root.querySelector('.u-wrap') + let tooltip = root.getElementsByClassName('nz-uplot-tooltip') + if (tooltip.length) { + tooltip = tooltip[0] + tooltip.style.display = 'block' + } + over.addEventListener('mouseleave', this.uplotMouseleave) + over.addEventListener('mousemove', this.uplotMousemove) + over.addEventListener('mousedown', this.uplotMousedown) + over.addEventListener('mouseup', this.uplotMouseup) + this.$store.commit('setCurrentMousemove', this.chartId) + }, + uplotMouseleave () { + const chart = getChart(this.chartId) + const over = chart.over + const tooltip = document.getElementsByClassName('nz-uplot-tooltip') + if (tooltip.length) { + tooltip.forEach(item => { + item.style.display = 'none' + }) + } + over.removeEventListener('mouseleave', this.uplotMouseleave) + over.removeEventListener('mousemove', this.uplotMousemove) + over.removeEventListener('mousedown', this.uplotMousedown) + over.removeEventListener('mouseup', this.uplotMouseup) + }, + uplotMousemove (e) { + this.mousePosition = { + left: e.pageX, + top: e.pageY + } + }, + uplotMousedown (e) { + this.toolbox.x = e.clientX + this.toolbox.y = e.clientY + }, + uplotMouseup (e) { + if (e.clientX == this.toolbox.x && e.clientY == this.toolbox.y) { + if (this.seriesIdx) { + this.toolbox.show = true + this.datalinkClick(this.seriesIdx, this.dataIdx) + const windowWidth = window.innerWidth// 窗口宽度 + const windowHeight = window.innerHeight// 窗口高度 + this.$nextTick(() => { + const box = document.getElementById(`chart-toolbox-${this.chartId}`) + const left = e.pageX - this.$refs['timeSeries-chart-box'].getBoundingClientRect().left + const top = e.pageY - this.$refs['timeSeries-chart-box'].getBoundingClientRect().top + if (box) { + const boxWidth = box.offsetWidth + const boxHeight = box.offsetHeight + if (e.pageX < (windowWidth / 2)) { // 说明鼠标在左边放不下提示框 + this.toolbox.x = left + 15 + } else { + this.toolbox.x = left - boxWidth - 15 + } + if (e.pageY + 50 + boxHeight < windowHeight) { // 说明鼠标上面放不下提示框 + this.toolbox.y = top + 15 + } else { + this.toolbox.y = top - boxHeight - 10 + } + } + }) + } else { + this.toolbox.show = false + } + } + }, + datalinkClick (seriesIdx, dataIdx, e) { // 处理datalink数据 + const obj = this.series[seriesIdx - 1] + const chart = getChart(this.chartId) + const params = { + seriesIndex: seriesIdx - 1, + yAxisIndex: obj.yAxisIndex, + value: [chart.data[0][dataIdx], chart.data[seriesIdx][dataIdx]], + seriesName: obj.label + } + if (!params.seriesName) { + return + } + const nameArr = params.seriesName.split('-') + if (nameArr.length > 1) { + nameArr.splice(nameArr.length - 1, 1) + } + const seriesName = nameArr.join('-') + if (this.series[params.seriesIndex]) { + params.yAxisIndex = this.series[params.seriesIndex].yAxisIndex + } + const decimals = this.chartInfo.param.decimals || 2 + let unit = this.chartInfo.unit ? this.chartInfo.unit : 2 + if (params.yAxisIndex == 1) { + unit = lodash.get(this, 'chartInfo.param.rightYAxis.unit', 2) + } + // title + const value = bus.computeTimezone(params.value[0] * 1000) + const tData = new Date(value) + // value + let paramsDot = bus.countDecimals(params.value[1]) + if (paramsDot < this.chartDot) { + paramsDot = this.chartDot + } else if (paramsDot > 6) { + paramsDot = 6 + } + const val = formatScientificNotation(params.value[1], paramsDot) + // 根据左右轴设置图标 + let className = 'row__color-block' + if (params.yAxisIndex == 0) { + className = 'yAxis-icon nz-icon nz-icon-zuozongzhou' + } else if (params.yAxisIndex == 1) { + className = 'yAxis-icon nz-icon nz-icon-youzongzhou' + } + const color = this.colorList[params.seriesIndex] + this.toolbox.tooltipHtml = ` + <div class="nz-chart__tooltip"> + <div class="tooltip-title" style="margin-bottom: 5px">${bus.timeFormate(tData)}</div> + <div class="tooltip__row"> + <div class="row__label" :title=">${seriesName}"> + <span class="${className}" style="background-color: ${color};color: ${color}"></span> + <span>${seriesName}</span> + </div> + <div class="row__value"> + <span>${chartDataFormat.getUnit(unit).compute(val, null, -1, decimals)}</span> + </div> + </div> + </div> + ` + this.toolbox.show = true + this.toolbox.metric.labels = this.series[params.seriesIndex].labels + this.toolbox.metric.expressionIndex = this.series[params.seriesIndex].expressionIndex + this.toolbox.clickIndex = params.seriesIndex + }, + renderThresholds () { // 画阈值线 + const u = getChart(this.chartId) + const thresholdsEnable = this.$lodash.get(this.chartInfo, 'param.enable.thresholds', false) + if (!thresholdsEnable || !u) { + return + } + const thresholdsArr = this.$lodash.get(this.chartInfo, 'param.thresholds', []) + const ctx = u.ctx + ctx.save() + const xd = u.data[0] + const i0 = 0 + const i1 = xd.length - 1 + const x0 = u.valToPos(xd[i0], 'x', true) + const x1 = u.valToPos(xd[i1], 'x', true) + thresholdsArr.forEach(item => { + const y0 = u.valToPos(item.value, 'left', true) + const y1 = u.valToPos(item.value, 'left', true) + ctx.beginPath() + ctx.strokeStyle = item.color + ctx.setLineDash([5, 5]) + ctx.moveTo(x0, y0) + ctx.lineTo(x1, y1) + ctx.stroke() + }) + ctx.restore() + } + } +} diff --git a/nezha-fronted/src/components/chart/chart/uplot/stack.js b/nezha-fronted/src/components/chart/chart/uplot/stack.js new file mode 100644 index 000000000..7f97d1da9 --- /dev/null +++ b/nezha-fronted/src/components/chart/chart/uplot/stack.js @@ -0,0 +1,63 @@ +import uPlot from 'uplot' +function stack (data, omit) { + const data2 = [] + let bands = [] + const d0Len = data[0].length + const accum = Array(d0Len) + + for (let i = 0; i < d0Len; i++) { accum[i] = 0 } + + for (let i = 1; i < data.length; i++) { + data2.push(data[i].map((v, i) => { + if (typeof (v) === 'undefined') { + return accum[i] + } + return (accum[i] += +v) + })) + } + + for (let i = 1; i < data.length; i++) { + !omit(i) && bands.push({ + dir: -1, + series: [ + data.findIndex((s, j) => j > i && !omit(j)), + i + ] + }) + } + + bands = bands.filter(b => b.series[1] > -1) + bands = bands.filter(b => b.series[0] > -1) + bands = bands.reverse() + return { + data: [data[0]].concat(data2), + bands + } +} + +export default function getStackedOpts (title, opt, data, interp) { + const opts = opt + const interped = interp ? interp(data) : data + + const stacked = stack(interped, i => false) + opts.bands = stacked.bands + + opts.cursor = opts.cursor || {} + + opts.series.forEach(s => { + s.value = (u, v, si, i) => data[si][i] + }) + // restack on toggle + opts.hooks = { + setSeries: [ + (u, i) => { + const stacked = stack(data, i => !u.series[i].show) + u.delBand(null) + stacked.bands.forEach(b => u.addBand(b)) + u.setData(stacked.data) + } + ] + } + + return { opts, data: stacked.data } +} diff --git a/nezha-fronted/src/components/chart/chart/uplot/testData.js b/nezha-fronted/src/components/chart/chart/uplot/testData.js new file mode 100644 index 000000000..29012f87c --- /dev/null +++ b/nezha-fronted/src/components/chart/chart/uplot/testData.js @@ -0,0 +1,2 @@ +const data = [[{"metric":{"__name__":"process_resident_memory_bytes","agent_name":"nz-agent-3.9-1","application":"prometheus","datacenter":"JBXXG","instance":"192.168.44.22:3039","nz_agent_id":"44","type":"global"},"values":[[1698284160,"664502272"],[1698284240,"715702272"],[1698284320,"668807168"],[1698284400,"722210816"],[1698284480,"666652672"],[1698284560,"658755584"],[1698284640,"669261824"],[1698284720,"684421120"],[1698284800,"713576448"],[1698284880,"682487808"],[1698284960,"672030720"],[1698285040,"693309440"],[1698285120,"676003840"],[1698285200,"685109248"],[1698285280,"715018240"],[1698285360,"699088896"],[1698285440,"669544448"],[1698285520,"707051520"],[1698285600,"671023104"],[1698285680,"652013568"],[1698285760,"706666496"],[1698285840,"690761728"],[1698285920,"654004224"],[1698286000,"671494144"],[1698286080,"690024448"],[1698286160,"655577088"],[1698286240,"646959104"],[1698286320,"664928256"],[1698286400,"665780224"],[1698286480,"695353344"],[1698286560,"685662208"],[1698286640,"636469248"],[1698286720,"647122944"],[1698286800,"682663936"],[1698286880,"642875392"],[1698286960,"696758272"],[1698287040,"674689024"],[1698287120,"658259968"],[1698287200,"723881984"],[1698287280,"651169792"],[1698287360,"698503168"],[1698287440,"656830464"],[1698287520,"683626496"],[1698287600,"701636608"],[1698287680,"731688960"],[1698287760,"657887232"]],"elements":{"expression":"process_resident_memory_bytes{application=\"prometheus\"}","legend":"{{agent_name}}","name":"A","orderNum":0,"step":80,"state":1,"type":"expert","queryType":1}},{"metric":{"__name__":"process_resident_memory_bytes","agent_name":"nz-agent-3.9-2","application":"prometheus","datacenter":"JBXXG","instance":"192.168.44.23:3039","nz_agent_id":"45","type":"per_datacenter"},"values":[[1698284160,"880721920"],[1698284240,"885305344"],[1698284320,"885305344"],[1698284400,"885305344"],[1698284480,"892063744"],[1698284560,"892063744"],[1698284640,"892063744"],[1698284720,"892063744"],[1698284800,"892063744"],[1698284880,"892063744"],[1698284960,"892334080"],[1698285040,"892334080"],[1698285120,"892334080"],[1698285200,"892334080"],[1698285280,"892334080"],[1698285360,"872742912"],[1698285440,"879517696"],[1698285520,"879517696"],[1698285600,"886005760"],[1698285680,"892489728"],[1698285760,"892489728"],[1698285840,"892489728"],[1698285920,"1034932224"],[1698286000,"905584640"],[1698286080,"918441984"],[1698286160,"931688448"],[1698286240,"902414336"],[1698286320,"848613376"],[1698286400,"864821248"],[1698286480,"850259968"],[1698286560,"851611648"],[1698286640,"860532736"],[1698286720,"861609984"],[1698286800,"868364288"],[1698286880,"869986304"],[1698286960,"871337984"],[1698287040,"871878656"],[1698287120,"878637056"],[1698287200,"878637056"],[1698287280,"867917824"],[1698287360,"867917824"],[1698287440,"870076416"],[1698287520,"881156096"],[1698287600,"881696768"],[1698287680,"881696768"],[1698287760,"868925440"]],"elements":{"expression":"process_resident_memory_bytes{application=\"prometheus\"}","legend":"{{agent_name}}","name":"A","orderNum":0,"step":80,"state":1,"type":"expert","queryType":1}}],[{"metric":{"__name__":"process_resident_memory_bytes","agent_name":"nz-agent-3.9-1","application":"prometheus","datacenter":"JBXXG","instance":"192.168.44.22:3039","nz_agent_id":"44","type":"global"},"values":[[1698284160,"664502272"],[1698284175,"693637120"],[1698284190,"693637120"],[1698284205,"674811904"],[1698284220,"674811904"],[1698284235,"715702272"],[1698284250,"715702272"],[1698284265,"731127808"],[1698284280,"731127808"],[1698284295,"668807168"],[1698284310,"668807168"],[1698284325,"680472576"],[1698284340,"680472576"],[1698284355,"669126656"],[1698284370,"669126656"],[1698284385,"722210816"],[1698284400,"722210816"],[1698284415,"668172288"],[1698284430,"668172288"],[1698284445,"663568384"],[1698284460,"663568384"],[1698284475,"666652672"],[1698284490,"666652672"],[1698284505,"707928064"],[1698284520,"707928064"],[1698284535,"658755584"],[1698284550,"658755584"],[1698284565,"660320256"],[1698284580,"660320256"],[1698284595,"670625792"],[1698284610,"670625792"],[1698284625,"669261824"],[1698284640,"669261824"],[1698284655,"719749120"],[1698284670,"719749120"],[1698284685,"680538112"],[1698284700,"680538112"],[1698284715,"684421120"],[1698284730,"684421120"],[1698284745,"709795840"],[1698284760,"709795840"],[1698284775,"713576448"],[1698284790,"713576448"],[1698284805,"678215680"],[1698284820,"678215680"],[1698284835,"725278720"],[1698284850,"725278720"],[1698284865,"682487808"],[1698284880,"682487808"],[1698284895,"682954752"],[1698284910,"682954752"],[1698284925,"666243072"],[1698284940,"666243072"],[1698284955,"672030720"],[1698284970,"672030720"],[1698284985,"706322432"],[1698285000,"706322432"],[1698285015,"693309440"],[1698285030,"693309440"],[1698285045,"720531456"],[1698285060,"720531456"],[1698285075,"666591232"],[1698285090,"666591232"],[1698285105,"676003840"],[1698285120,"676003840"],[1698285135,"705163264"],[1698285150,"705163264"],[1698285165,"721276928"],[1698285180,"721276928"],[1698285195,"685109248"],[1698285210,"685109248"],[1698285225,"666677248"],[1698285240,"666677248"],[1698285255,"715018240"],[1698285270,"715018240"],[1698285285,"665255936"],[1698285300,"665255936"],[1698285315,"671453184"],[1698285330,"671453184"],[1698285345,"699088896"],[1698285360,"699088896"],[1698285375,"731766784"],[1698285390,"731766784"],[1698285405,"681107456"],[1698285420,"681107456"],[1698285435,"669544448"],[1698285450,"669544448"],[1698285465,"681975808"],[1698285480,"681975808"],[1698285495,"707051520"],[1698285510,"707051520"],[1698285525,"743505920"],[1698285540,"743505920"],[1698285555,"678473728"],[1698285570,"678473728"],[1698285585,"671023104"],[1698285600,"671023104"],[1698285615,"661622784"],[1698285630,"661622784"],[1698285645,"694079488"],[1698285660,"694079488"],[1698285675,"652013568"],[1698285690,"652013568"],[1698285705,"648028160"],[1698285720,"648028160"],[1698285735,"706666496"],[1698285750,"706666496"],[1698285765,"665985024"],[1698285780,"665985024"],[1698285795,"699326464"],[1698285810,"699326464"],[1698285825,"690761728"],[1698285840,"690761728"],[1698285855,"675127296"],[1698285870,"675127296"],[1698285885,"686600192"],[1698285900,"686600192"],[1698285915,"654004224"],[1698285930,"654004224"],[1698285945,"677564416"],[1698285960,"677564416"],[1698285975,"671494144"],[1698285990,"671494144"],[1698286005,"658026496"],[1698286020,"658026496"],[1698286035,"642789376"],[1698286050,"642789376"],[1698286065,"690024448"],[1698286080,"690024448"],[1698286095,"636588032"],[1698286110,"636588032"],[1698286125,"650903552"],[1698286140,"650903552"],[1698286155,"655577088"],[1698286170,"655577088"],[1698286185,"675180544"],[1698286200,"675180544"],[1698286215,"646959104"],[1698286230,"646959104"],[1698286245,"652636160"],[1698286260,"652636160"],[1698286275,"673689600"],[1698286290,"673689600"],[1698286305,"664928256"],[1698286320,"664928256"],[1698286335,"688869376"],[1698286350,"688869376"],[1698286365,"686288896"],[1698286380,"686288896"],[1698286395,"665780224"],[1698286410,"665780224"],[1698286425,"647020544"],[1698286440,"647020544"],[1698286455,"695353344"],[1698286470,"695353344"],[1698286485,"647864320"],[1698286500,"647864320"],[1698286515,"699715584"],[1698286530,"699715584"],[1698286545,"685662208"],[1698286560,"685662208"],[1698286575,"651571200"],[1698286590,"651571200"],[1698286605,"698564608"],[1698286620,"698564608"],[1698286635,"636469248"],[1698286650,"636469248"],[1698286665,"702648320"],[1698286680,"702648320"],[1698286695,"647122944"],[1698286710,"647122944"],[1698286725,"650334208"],[1698286740,"650334208"],[1698286755,"670662656"],[1698286770,"670662656"],[1698286785,"682663936"],[1698286800,"682663936"],[1698286815,"705875968"],[1698286830,"705875968"],[1698286845,"691957760"],[1698286860,"691957760"],[1698286875,"642875392"],[1698286890,"642875392"],[1698286905,"664678400"],[1698286920,"664678400"],[1698286935,"696758272"],[1698286950,"696758272"],[1698286965,"643043328"],[1698286980,"643043328"],[1698286995,"656474112"],[1698287010,"656474112"],[1698287025,"674689024"],[1698287040,"674689024"],[1698287055,"656105472"],[1698287070,"656105472"],[1698287085,"649641984"],[1698287100,"649641984"],[1698287115,"658259968"],[1698287130,"658259968"],[1698287145,"682287104"],[1698287160,"682287104"],[1698287175,"723881984"],[1698287190,"723881984"],[1698287205,"662056960"],[1698287220,"662056960"],[1698287235,"706244608"],[1698287250,"706244608"],[1698287265,"651169792"],[1698287280,"651169792"],[1698287295,"659550208"],[1698287310,"659550208"],[1698287325,"706445312"],[1698287340,"706445312"],[1698287355,"698503168"],[1698287370,"698503168"],[1698287385,"666472448"],[1698287400,"666472448"],[1698287415,"656830464"],[1698287430,"656830464"],[1698287445,"659017728"],[1698287460,"659017728"],[1698287475,"702779392"],[1698287490,"702779392"],[1698287505,"683626496"],[1698287520,"683626496"],[1698287535,"699219968"],[1698287550,"699219968"],[1698287565,"659644416"],[1698287580,"659644416"],[1698287595,"701636608"],[1698287610,"701636608"],[1698287625,"652582912"],[1698287640,"652582912"],[1698287655,"731688960"],[1698287670,"731688960"],[1698287685,"687755264"],[1698287700,"687755264"],[1698287715,"660193280"],[1698287730,"660193280"],[1698287745,"657887232"],[1698287760,"657887232"]],"elements":{"expression":"process_resident_memory_bytes{application=\"prometheus\"}","legend":"{{agent_name}}-B","name":"B","orderNum":1,"id":"","state":1,"type":"expert","queryType":1}},{"metric":{"__name__":"process_resident_memory_bytes","agent_name":"nz-agent-3.9-2","application":"prometheus","datacenter":"JBXXG","instance":"192.168.44.23:3039","nz_agent_id":"45","type":"per_datacenter"},"values":[[1698284160,"880721920"],[1698284175,"880721920"],[1698284190,"882880512"],[1698284205,"882880512"],[1698284220,"884494336"],[1698284235,"884494336"],[1698284250,"885305344"],[1698284265,"885305344"],[1698284280,"885305344"],[1698284295,"885305344"],[1698284310,"885305344"],[1698284325,"885305344"],[1698284340,"885305344"],[1698284355,"885305344"],[1698284370,"885305344"],[1698284385,"885305344"],[1698284400,"885305344"],[1698284415,"885305344"],[1698284430,"885305344"],[1698284445,"885305344"],[1698284460,"892063744"],[1698284475,"892063744"],[1698284490,"892063744"],[1698284505,"892063744"],[1698284520,"892063744"],[1698284535,"892063744"],[1698284550,"892063744"],[1698284565,"892063744"],[1698284580,"892063744"],[1698284595,"892063744"],[1698284610,"892063744"],[1698284625,"892063744"],[1698284640,"892063744"],[1698284655,"892063744"],[1698284670,"892063744"],[1698284685,"892063744"],[1698284700,"892063744"],[1698284715,"892063744"],[1698284730,"892063744"],[1698284745,"892063744"],[1698284760,"892063744"],[1698284775,"892063744"],[1698284790,"892063744"],[1698284805,"892063744"],[1698284820,"892063744"],[1698284835,"892063744"],[1698284850,"892063744"],[1698284865,"892063744"],[1698284880,"892063744"],[1698284895,"892063744"],[1698284910,"892063744"],[1698284925,"892063744"],[1698284940,"892334080"],[1698284955,"892334080"],[1698284970,"892334080"],[1698284985,"892334080"],[1698285000,"892334080"],[1698285015,"892334080"],[1698285030,"892334080"],[1698285045,"892334080"],[1698285060,"892334080"],[1698285075,"892334080"],[1698285090,"892334080"],[1698285105,"892334080"],[1698285120,"892334080"],[1698285135,"892334080"],[1698285150,"892334080"],[1698285165,"892334080"],[1698285180,"892334080"],[1698285195,"892334080"],[1698285210,"892334080"],[1698285225,"892334080"],[1698285240,"892334080"],[1698285255,"892334080"],[1698285270,"892334080"],[1698285285,"892334080"],[1698285300,"892334080"],[1698285315,"892334080"],[1698285330,"870850560"],[1698285345,"870850560"],[1698285360,"872742912"],[1698285375,"872742912"],[1698285390,"879230976"],[1698285405,"879230976"],[1698285420,"885706752"],[1698285435,"885706752"],[1698285450,"879517696"],[1698285465,"879517696"],[1698285480,"879517696"],[1698285495,"879517696"],[1698285510,"879517696"],[1698285525,"879517696"],[1698285540,"886005760"],[1698285555,"886005760"],[1698285570,"886005760"],[1698285585,"886005760"],[1698285600,"886005760"],[1698285615,"886005760"],[1698285630,"886005760"],[1698285645,"886005760"],[1698285660,"892489728"],[1698285675,"892489728"],[1698285690,"892489728"],[1698285705,"892489728"],[1698285720,"892489728"],[1698285735,"892489728"],[1698285750,"892489728"],[1698285765,"892489728"],[1698285780,"892489728"],[1698285795,"892489728"],[1698285810,"892489728"],[1698285825,"892489728"],[1698285840,"892489728"],[1698285855,"892489728"],[1698285870,"892489728"],[1698285885,"892489728"],[1698285900,"892489728"],[1698285915,"892489728"],[1698285930,"1034932224"],[1698285945,"1034932224"],[1698285960,"905314304"],[1698285975,"905314304"],[1698285990,"905584640"],[1698286005,"905584640"],[1698286020,"905584640"],[1698286035,"905584640"],[1698286050,"912343040"],[1698286065,"912343040"],[1698286080,"918441984"],[1698286095,"918441984"],[1698286110,"924930048"],[1698286125,"924930048"],[1698286140,"931688448"],[1698286155,"931688448"],[1698286170,"931688448"],[1698286185,"931688448"],[1698286200,"895926272"],[1698286215,"895926272"],[1698286230,"902414336"],[1698286245,"902414336"],[1698286260,"908902400"],[1698286275,"908902400"],[1698286290,"908902400"],[1698286305,"908902400"],[1698286320,"848613376"],[1698286335,"848613376"],[1698286350,"855097344"],[1698286365,"855097344"],[1698286380,"855097344"],[1698286395,"855097344"],[1698286410,"864821248"],[1698286425,"864821248"],[1698286440,"850259968"],[1698286455,"850259968"],[1698286470,"850259968"],[1698286485,"850259968"],[1698286500,"850530304"],[1698286515,"850530304"],[1698286530,"851611648"],[1698286545,"851611648"],[1698286560,"851611648"],[1698286575,"851611648"],[1698286590,"858099712"],[1698286605,"858099712"],[1698286620,"858099712"],[1698286635,"858099712"],[1698286650,"860532736"],[1698286665,"860532736"],[1698286680,"861343744"],[1698286695,"861343744"],[1698286710,"861609984"],[1698286725,"861609984"],[1698286740,"861609984"],[1698286755,"861609984"],[1698286770,"865390592"],[1698286785,"865390592"],[1698286800,"868364288"],[1698286815,"868364288"],[1698286830,"868364288"],[1698286845,"868364288"],[1698286860,"868634624"],[1698286875,"868634624"],[1698286890,"869986304"],[1698286905,"869986304"],[1698286920,"871337984"],[1698286935,"871337984"],[1698286950,"871337984"],[1698286965,"871337984"],[1698286980,"871337984"],[1698286995,"871337984"],[1698287010,"871878656"],[1698287025,"871878656"],[1698287040,"871878656"],[1698287055,"871878656"],[1698287070,"871878656"],[1698287085,"871878656"],[1698287100,"871878656"],[1698287115,"871878656"],[1698287130,"878637056"],[1698287145,"878637056"],[1698287160,"878637056"],[1698287175,"878637056"],[1698287190,"878637056"],[1698287205,"878637056"],[1698287220,"878637056"],[1698287235,"878637056"],[1698287250,"878637056"],[1698287265,"878637056"],[1698287280,"867917824"],[1698287295,"867917824"],[1698287310,"867917824"],[1698287325,"867917824"],[1698287340,"867917824"],[1698287355,"867917824"],[1698287370,"867917824"],[1698287385,"867917824"],[1698287400,"870076416"],[1698287415,"870076416"],[1698287430,"870076416"],[1698287445,"870076416"],[1698287460,"874397696"],[1698287475,"874397696"],[1698287490,"881156096"],[1698287505,"881156096"],[1698287520,"881156096"],[1698287535,"881156096"],[1698287550,"881156096"],[1698287565,"881156096"],[1698287580,"881156096"],[1698287595,"881156096"],[1698287610,"881696768"],[1698287625,"881696768"],[1698287640,"881696768"],[1698287655,"881696768"],[1698287670,"881696768"],[1698287685,"881696768"],[1698287700,"881696768"],[1698287715,"881696768"],[1698287730,"881967104"],[1698287745,"881967104"],[1698287760,"868925440"]],"elements":{"expression":"process_resident_memory_bytes{application=\"prometheus\"}","legend":"{{agent_name}}-B","name":"B","orderNum":1,"id":"","state":1,"type":"expert","queryType":1}}]] +export default data diff --git a/nezha-fronted/src/components/chart/chartMixin.js b/nezha-fronted/src/components/chart/chartMixin.js index ef546147f..28b5cdeeb 100644 --- a/nezha-fronted/src/components/chart/chartMixin.js +++ b/nezha-fronted/src/components/chart/chartMixin.js @@ -250,7 +250,7 @@ export default { const colorRandom = randomcolor() this.colorList.push(colorRandom) } - this.legends.push({ name, alias, statistics, color: this.colorList[colorIndex] }) + // this.legends.push({ name, alias, statistics, color: this.colorList[colorIndex] }) return { name, alias @@ -326,15 +326,6 @@ export default { }, mouseEnterChart () { const myChart = getChart(this.chartId) - if (myChart) { - setTimeout(() => { - myChart.setOption({ - toolbox: { - show: true - } - }) - }, 300) - } }, tooltipPosition (point, params, dom, rect, size) { if (this.isConnect === 'tooltip' && this.$store.state.panel.currentMousemove != this.chartId) { @@ -370,15 +361,6 @@ export default { }, mouseLeaveChart () { const myChart = getChart(this.chartId) - if (myChart) { - setTimeout(() => { - myChart.setOption({ - toolbox: { - show: false - } - }) - }, 300) - } }, getMaxValue (dataArg, chartInfo) { let maxValue = 0 @@ -445,7 +427,8 @@ export default { }, resize () { setTimeout(() => { - getChart(this.chartId) && getChart(this.chartId).resize() + console.log('chartMixin') + // getChart(this.chartId) && getChart(this.chartId).resize() }, 100) }, // 全局变量替换 diff --git a/nezha-fronted/src/components/common/bottomBox/tabs/alertMessageTabNew.vue b/nezha-fronted/src/components/common/bottomBox/tabs/alertMessageTabNew.vue index efbd9aefc..d2fc61184 100644 --- a/nezha-fronted/src/components/common/bottomBox/tabs/alertMessageTabNew.vue +++ b/nezha-fronted/src/components/common/bottomBox/tabs/alertMessageTabNew.vue @@ -583,7 +583,6 @@ export default { routePathParams.body.startAt = this.searchTimeHeader[0] ? this.momentStrToTimestamp(this.searchTimeHeader[0]) : '' routePathParams.body.endAt = this.searchTimeHeader[1] ? this.momentStrToTimestamp(this.searchTimeHeader[1]) : '' routePathParams.body.timeType = this.searchTimeHeader[2] - console.log(this.$route, this.$router) if (!this.searchTimeHeader[2]) { routePathParams.body.startAt = this.searchTimeHeader[0] ? this.momentStrToTimestamp(this.searchTimeHeader[0]) : '' routePathParams.body.endAt = this.searchTimeHeader[1] ? this.momentStrToTimestamp(this.searchTimeHeader[1]) : '' diff --git a/nezha-fronted/src/components/common/bottomBox/tabs/dashboardTab.vue b/nezha-fronted/src/components/common/bottomBox/tabs/dashboardTab.vue index f0a4b66f6..e8eda2217 100644 --- a/nezha-fronted/src/components/common/bottomBox/tabs/dashboardTab.vue +++ b/nezha-fronted/src/components/common/bottomBox/tabs/dashboardTab.vue @@ -324,11 +324,13 @@ export default { ], intervalList: [ { value: 0, label: this.$t('dashboard.dashboard.chartForm.lockList.off') }, + { value: 5, label: '5s' }, + { value: 10, label: '10s' }, { value: 30, label: '30s' }, { value: 60, label: '1m' }, { value: 300, label: '5m' }, { value: 900, label: '15m' }, - { value: 1800, label: '30m' } + { value: 1800, label: '30m' }, ] } }, diff --git a/nezha-fronted/src/components/common/mixin/mainMixinFun.js b/nezha-fronted/src/components/common/mixin/mainMixinFun.js index fe995bb3e..24356f389 100644 --- a/nezha-fronted/src/components/common/mixin/mainMixinFun.js +++ b/nezha-fronted/src/components/common/mixin/mainMixinFun.js @@ -223,7 +223,6 @@ export default { this.nowTimeType = nowType || this.$refs.pickTime.$refs.timePicker.nowTimeType const type = nowTimeType.type const val = nowTimeType.value - console.log(val) const oneDTimestamp = 24 * 60 * 60 * 1000 if (type === 'relative') { const now = new Date(bus.computeTimezone(new Date().getTime())) diff --git a/nezha-fronted/src/components/common/pickTime.vue b/nezha-fronted/src/components/common/pickTime.vue index 011ac35c8..66179b7f6 100644 --- a/nezha-fronted/src/components/common/pickTime.vue +++ b/nezha-fronted/src/components/common/pickTime.vue @@ -121,6 +121,9 @@ export default { this.getIntervalData(interval) } this.intervalTimer = setInterval(() => { + if (document.hidden) { + return + } this.getIntervalData(this.interval.value) }, val.value * 1000) } diff --git a/nezha-fronted/src/components/common/rightBox/panelBox.vue b/nezha-fronted/src/components/common/rightBox/panelBox.vue index 2ac703106..3fea53c30 100644 --- a/nezha-fronted/src/components/common/rightBox/panelBox.vue +++ b/nezha-fronted/src/components/common/rightBox/panelBox.vue @@ -514,11 +514,13 @@ export default { ], intervalList: [ { value: 0, label: this.$t('dashboard.dashboard.chartForm.lockList.off') }, + { value: 5, label: '5s' }, + { value: 10, label: '10s' }, { value: 30, label: '30s' }, { value: 60, label: '1m' }, { value: 300, label: '5m' }, { value: 900, label: '15m' }, - { value: 1800, label: '30m' } + { value: 1800, label: '30m' }, ] } }, diff --git a/nezha-fronted/src/components/common/timePicker.vue b/nezha-fronted/src/components/common/timePicker.vue index 041f5fb13..5888b59f4 100644 --- a/nezha-fronted/src/components/common/timePicker.vue +++ b/nezha-fronted/src/components/common/timePicker.vue @@ -246,7 +246,6 @@ export default { this.getUtcStr() this.getRangeHistoryArr() const timeTemp = this.$lodash.cloneDeep(this.searchTime) - console.log(this.searchTime) this.oldSearchTime[0] = timeTemp[0] || '' this.oldSearchTime[1] = timeTemp[1] || '' // 监听dateFormat变化 改变日期格式 diff --git a/nezha-fronted/src/components/page/alert/alertMessage.vue b/nezha-fronted/src/components/page/alert/alertMessage.vue index ec667455f..4183bcc2b 100644 --- a/nezha-fronted/src/components/page/alert/alertMessage.vue +++ b/nezha-fronted/src/components/page/alert/alertMessage.vue @@ -937,7 +937,6 @@ export default { const path = this.fromRoute.alertMessage const routePathParams = JSON.parse(JSON.stringify(param)) delete routePathParams.statistics - console.log(this.searchTime[2]) if (!this.searchTime[2]) { routePathParams.body.startAt = this.searchTime[0] ? this.momentStrToTimestamp(this.searchTime[0]) : '' routePathParams.body.endAt = this.searchTime[1] ? this.momentStrToTimestamp(this.searchTime[1]) : '' @@ -952,7 +951,6 @@ export default { ...this.searchLabel, body: encodeURIComponent(JSON.stringify(this.searchLabel.body)) } - console.log(this.searchLabel.body) this.$get('/alert/message/query', { ...queryParams }).then(response => { this.tools.loading = false if (response.code == 200) { diff --git a/nezha-fronted/src/components/page/dashboard/dashboard.vue b/nezha-fronted/src/components/page/dashboard/dashboard.vue index e72f6a9a0..0661e445a 100644 --- a/nezha-fronted/src/components/page/dashboard/dashboard.vue +++ b/nezha-fronted/src/components/page/dashboard/dashboard.vue @@ -354,11 +354,13 @@ export default { ], intervalList: [ { value: 0, label: this.$t('dashboard.dashboard.chartForm.lockList.off') }, + { value: 5, label: '5s' }, + { value: 10, label: '10s' }, { value: 30, label: '30s' }, { value: 60, label: '1m' }, { value: 300, label: '5m' }, { value: 900, label: '15m' }, - { value: 1800, label: '30m' } + { value: 1800, label: '30m' }, ], playListControls: false, // 显示隐藏轮播按钮 playlistObj: {} // 轮播仪表盘配置 diff --git a/nezha-fronted/src/components/page/dashboard/explore/exploreItem.vue b/nezha-fronted/src/components/page/dashboard/explore/exploreItem.vue index ecba8cb5d..f510986b6 100644 --- a/nezha-fronted/src/components/page/dashboard/explore/exploreItem.vue +++ b/nezha-fronted/src/components/page/dashboard/explore/exploreItem.vue @@ -3898,7 +3898,6 @@ export default { this.saveDisabled = false } axios.all(requestArr).then(res => { - console.log(res) this.chartLoading = false const errorRowIndex = [] res.forEach((r, i) => { @@ -4593,7 +4592,6 @@ export default { } }) postArr = postArr.filter(item => item.queryValue) - console.log(postArr) this.$post('/sys/user/queryHistory', postArr).then(res => { this.lastHistory = this.$lodash.cloneDeep(postArr) }) diff --git a/nezha-fronted/src/components/page/dashboard/explore/histoyrComponent/exploreHistory.vue b/nezha-fronted/src/components/page/dashboard/explore/histoyrComponent/exploreHistory.vue index 835c342a5..0e841a599 100644 --- a/nezha-fronted/src/components/page/dashboard/explore/histoyrComponent/exploreHistory.vue +++ b/nezha-fronted/src/components/page/dashboard/explore/histoyrComponent/exploreHistory.vue @@ -133,7 +133,7 @@ export default { }) }, deleteHistoryItem (item) { - this.$delete('/sys/user/queryHistory?ids=' + item.id).then(res => { + this.$delete('/sys/user/queryHistory?ids=' + item.id + '&queryHash=' + item.queryHash).then(res => { if (res.code === 200) { this.$message.success(this.$t('tip.deleteSuccess')) this.firstLoading = true diff --git a/nezha-fronted/src/components/page/dashboard/explore/queryPrompt/queryPrompt.vue b/nezha-fronted/src/components/page/dashboard/explore/queryPrompt/queryPrompt.vue index 720421f60..fb49dbfc2 100644 --- a/nezha-fronted/src/components/page/dashboard/explore/queryPrompt/queryPrompt.vue +++ b/nezha-fronted/src/components/page/dashboard/explore/queryPrompt/queryPrompt.vue @@ -301,7 +301,9 @@ export default { } str += ',' }) - str = str.slice(0, -1) + if (str.length !== 1) { + str = str.slice(0, -1) + } str += '}' this.logFinalStr = str }, diff --git a/nezha-fronted/src/entrance/app/main.js b/nezha-fronted/src/entrance/app/main.js index 1cdaa28cf..0d9f5d4f7 100644 --- a/nezha-fronted/src/entrance/app/main.js +++ b/nezha-fronted/src/entrance/app/main.js @@ -5,6 +5,7 @@ import '@/assets/css/main.scss' import '@/assets/css/animate.css' import '@/assets/css/font/iconfont.js' import 'intro.js/introjs.css' +import 'uplot/dist/uPlot.min.css' import Pace from 'pace-js' import ElementUI from 'element-ui' import i18n from '@/components/common/i18n' diff --git a/nezha-fronted/src/entrance/exportHtml/exportHtml.js b/nezha-fronted/src/entrance/exportHtml/exportHtml.js index ae6fe9615..050ff2881 100644 --- a/nezha-fronted/src/entrance/exportHtml/exportHtml.js +++ b/nezha-fronted/src/entrance/exportHtml/exportHtml.js @@ -5,6 +5,7 @@ import '@/assets/css/main.scss' import '@/assets/css/font/iconfont.js' import ElementUI from 'element-ui' import i18n from '@/components/common/i18n' +import 'uplot/dist/uPlot.min.css' import Vue from 'vue' import Vuex from 'vuex' |
