diff options
| author | zhangyu <[email protected]> | 2021-04-08 17:49:07 +0800 |
|---|---|---|
| committer | zhangyu <[email protected]> | 2021-04-08 17:49:07 +0800 |
| commit | e035e371fe36df13bf5ef4e2af6637ee606bf2c9 (patch) | |
| tree | 3fce6c2e6b79df54e81189434a561860c6d6e9cd | |
| parent | ffbdcf7d958993df4af0d2c92eadd252d4b02344 (diff) | |
feat:chart group添加组 联调panel接口
14 files changed, 954 insertions, 82 deletions
diff --git a/nezha-fronted/src/components/charts/charLlist和chart-list-group的区别.md b/nezha-fronted/src/components/charts/charLlist和chart-list-group的区别.md new file mode 100644 index 000000000..a61c3b6af --- /dev/null +++ b/nezha-fronted/src/components/charts/charLlist和chart-list-group的区别.md @@ -0,0 +1,10 @@ + +``` bash +# list +向下传递 index + +# groupList +是 chart type=’group‘ 的子组件 +向下传递的是处理过后的 chartIndex +``` + diff --git a/nezha-fronted/src/components/charts/chart-bar-statistics.vue b/nezha-fronted/src/components/charts/chart-bar-statistics.vue new file mode 100644 index 000000000..38562a419 --- /dev/null +++ b/nezha-fronted/src/components/charts/chart-bar-statistics.vue @@ -0,0 +1,766 @@ +<style lang="scss"> + @import './chart.scss'; +</style> +<template> + <div class="nz-chart-resize"> + <div class="resize-shadow" ref="resizeShadow"></div> + <div class="resize-box resize-box-echarts" ref="resizeBox"> + <div class="chart-single-stat" :id="'chartPieChart'+chartIndex" @mouseenter="caretShow=true" @mouseleave="caretShow=false"> + <loading :ref="'localLoading'+chartIndex"></loading> + <div class="clearfix chartTitle" :class="{'dragTitle':dragTitleShow}" :id="'chartTitle'+chartIndex"> + <el-popover + v-if="isError" + :close-delay=10 + placement="top-start" + trigger="hover" + popper-class="chart-error-popper"> + <div >{{errorContent}}</div> + <span slot="reference" style="" class="panel-info-corner panel-info-corner--error"> + <i class="nz-icon nz-icon-warning fa"></i> + <span class="panel-info-corner-inner"></span> + </span> + </el-popover> + <el-dropdown trigger="click" class="nz-chart-top" :key="'chartDropdown'+chartIndex" v-clickoutside="clickos" :class="{'move-able':!isLock}"> + <el-dropdown-menu style="display: none"></el-dropdown-menu> + <span class="el-dropdown-link chart-title"> + <span class="chart-title-text">{{chartData.name}}</span> + <span class="chart-title-icon" :class="{'visible':caretShow,'hidden':!caretShow}"> + <span @click="refreshChart" class="" v-has="`${from}_chart_toEdit`" :title="$t('dashboard.refresh')"> + <i class="nz-icon nz-icon-replay"></i> + </span> + <span @click="showAllScreen" class="" :title="$t('dashboard.screen')"> + <i class="nz-icon nz-icon-maxview"></i> + </span> + <span><i class="el-icon-more" @click.stop="dropdownMenuShow=!dropdownMenuShow"></i></span> + </span> + </span> + <ul slot="dropdown" v-show="dropdownMenuShow" :id="'dropdownUl'+chartIndex" class="el-dropdown-menu nz-chart-dropdown" style="" > + <li @click="editChart" class="el-dropdown-menu__item"> + <i class="nz-icon nz-icon-edit" style="font-size: 16px;"></i><span>{{$t('dashboard.edit')}}</span></li> + <li @click="removeChart" class="el-dropdown-menu__item" v-has="`${from}_chart_delete`"> + <i class="nz-icon nz-icon-delete" style="font-size: 16px;"></i>{{$t('dashboard.delete')}}</li> + <li @click="duplicate" class="el-dropdown-menu__item" v-has="`${from}_chart_duplicate`"> + <i class="el-icon-copy-document" style="font-size: 16px;"></i>{{$t('dashboard.duplicate')}}</li> + </ul> + </el-dropdown> + </div> + <div :id="'pie-chart-local-'+chartIndex" ref="pieChartLocal" style="display: flex;justify-content: center"></div> + <div class="chart-no-data" v-show="noData">No Data</div> + <div class='legend-container' ref="legendArea" v-show="firstShow"> + <div v-for="(item, index) in legend" :title="item.alias?item.alias:item.name" @click="clickLegend(item.name,index)" class="legend-item" :class="{'ft-gr':isGrey[index]}" :key="'legend_' + item.name+'_'+index"> + <span class="legend-shape" :style="{background:(isGrey[index]?'#D3D3D3':item.color)}"></span>{{item.alias?item.alias:item.name}} + </div> + </div> + <!--全屏--> + <el-dialog class="nz-dialog table-chart-dialog" :title="$t('dashboard.panel.view')" @opened="initChart('screen')" + :visible.sync="screenModal" + width="96%" @close="screenModal = false" :modal-append-to-body="false"> + <div slot="title"> + <span class="nz-dialog-title">{{data.name}}</span> + <div class="float-right panel-calendar dialog-tool"> + <!-- <time-picker ref="calendarPanel" class="nz-dashboard-picker" style="margin-top: -12px;" @change="dateChange"></time-picker>--> + <pick-time :refresh-data-func="dateChange" v-model="searchTime" :use-chart-unit="false" ref="pickTime" style="height: 28px;" id="single-chart"></pick-time> + </div> + <!-- <span class="float-right dialog-tool" @click="screenRefreshChart" style="margin-right: 15px"><i class="global-active-color nz-icon nz-icon-refresh"/></span>--> + </div> + <div class="single-stat-screen-container" > + <div :id="'pie-chart-screen-'+chartIndex" ref="pieChartScreen" style="width: 100%;height: 100%;"></div> + <div :id="'screenLegendArea'+chartIndex" class="legend-container legend-container-screen"> + <div v-for="(item, index) in legendScreen" :title="item.alias?item.alias:item.name" @click="clickScreenLegend(item.name,index)" class="legend-item" :class="{'ft-gr':isGreyScreen[index]}" :key="'legend_' + item.name+'_'+index"> + <span class="legend-shape" :style="{background:(isGreyScreen[index]?'#D3D3D3':item.color)}"></span>{{item.alias?item.alias:item.name}} + <br/><!--bgColorList[index]--> + </div> + </div> + </div> + <loading :ref="'localLoadingScreen'+chartIndex"></loading> + </el-dialog> + </div> + <span class="vue-resizable-handle" @mousedown="startResize" v-if="!isLock"></span> + </div> + </div> +</template> + +<script> +import chartDataFormat from './chartDataFormat' +import loading from '../common/loading' +import * as echarts from 'echarts' +import { getChart, setChart, getMousePoint } from '../common/js/common' +import chartConfig from '../page/dashboard/overview/chartConfig' +import { randomcolor } from '../common/js/radomcolor/randomcolor' +export default { + name: 'pieChart', // 饼图 或者 柱状图的统计 + components: { + loading: loading + }, + props: { + tempDom: Object, + chartData: { + type: Object + }, + // 看板id + panelId: { + type: Number, + default: 0 + }, + editChartId: { + type: String, + default: 'editChartId' + }, + chartIndex: { + type: Number, + default: 0 + }, + from: { type: String }, + isLock: { type: Boolean, default: false } + }, + data () { + return { + data: {}, // 该图表信息,chartItem + noData: false, + unit: {}, + isError: false, + errorContent: '', + seriesItem: [], // 保存信息 + seriesItemScreen: [], // 全屏数据 + pieData: [], + mapping: '', // 满足valueMapping时 mapping的值 + images: '', + loading: Object, + items: { + metric_name: [], // 每条数据列名称 + xAxis: [], + theData: [] // series数据组 + }, + panelIdInner: '', // 看板id=panelId,原写作chart,由set_data获取 + firstLoad: false, // 是否第一次加载 + screenModal: false, + // 查询数据使用 + filter: { + start_time: '', + end_time: '' + }, + firstShow: false, // 默认不显示操作按钮, + caretShow: false, + dragTitleShow: false, + dropdownMenuShow: false, + divFirstShow: false, + searchTime: [new Date().setHours(new Date().getHours() - 1), new Date()], // 全屏显示的时间 + oldSearchTime: [], + legend: [], + legendScreen: [], + isGrey: [], + isGreyScreen: [], + echart: null, + echartScreen: null, + bgColorList: [], + stableFilter: {}, + option: { + title: { + show: false + }, + legend: { + show: false + }, + grid: { + left: 'center', + top: 'middle' + }, + tooltip: { + trigger: 'item', + backgroundColor: 'rgba(221,228,237,1)', + borderColor: 'rgba(255,255,255,0)', + textStyle: { + color: '#000' + }, + axisPointer: { + snap: false, + animation: false + }, + extraCssText: 'z-index:1000;' + }, + series: null + } + } + }, + created () { + }, + computed: {}, + watch: { + dropdownMenuShow (n) { + this.$emit('dropmenu-change', n) + } + }, + methods: { + startResize (e) { + const vm = this + this.$chartResizeTool.start(vm, this.data, e, this.chartIndex) + }, + startLoading (area) { + if (area === 'screen') { + this.$refs['localLoadingScreen' + this.chartIndex].startLoading() + } else { + // this.showLoading = true; + this.$refs['localLoading' + this.chartIndex].startLoading() + } + }, + endLoading (area) { + if (area === 'screen') { + // this.showLoadingScreen = false; + this.$refs['localLoadingScreen' + this.chartIndex].endLoading() + } else { + // this.showLoading = false; + this.$refs['localLoading' + this.chartIndex].endLoading() + } + }, + showLoad (chartItem) { + this.$nextTick(() => { + const chartBox = document.getElementById('chartPieChart' + this.chartIndex) + let height = Math.floor(chartItem.height / this.$chartResizeTool.stepHeight) * this.$chartResizeTool.stepHeight// 图表高度四舍五入 + if (height < this.$chartResizeTool.minHeight) { + height = this.$chartResizeTool.minHeight + } + chartBox.style.height = `${height - this.$chartResizeTool.chartBlankHeight}px` + }) + this.clearData() + this.firstShow = false + this.$refs['localLoading' + this.chartIndex].startLoading() + this.divFirstShow = true + }, + clearData () { + if (getChart(this.chartIndex)) { + getChart(this.chartIndex).clear() + // getChart(this.chartIndex).dispose();//关闭销毁实例 不再占用内存 + } + }, + screenRefreshChart () { + this.$refs.calendarPanel.timeChange(this.$refs.calendarPanel.nowTimeType, 'chart') + }, + // 重新请求数据 刷新操作-local + refreshChart () { + this.dropdownMenuShow = false + const id = this.data.id + this.clearChart() + this.$refs['localLoading' + this.chartIndex].startLoading() + this.firstShow = false + this.$emit('on-refresh-data', id) + }, + // 编辑图表 + editChart () { + this.dropdownMenuShow = false + this.$emit('on-edit-chart-block', this.data.id) + }, + // 删除该图表 + removeChart () { + this.dropdownMenuShow = false + this.$emit('on-remove-chart-block', this.data.id) + }, + // 全屏时间条件查询 + dateChange (time) { + this.seriesItemScreen = [] + this.seriePieChart = '' + this.startLoading('screen') + this.$emit('on-search-data', this.data.id, this.searchTime) + }, + clickos () { + this.dropdownMenuShow = false + }, + clearChart () { + this.data = {} + }, + duplicate () { + this.dropdownMenuShow = false + this.$emit('on-duplicate-chart-block', this.data.id) + }, + // 全屏查看 + showAllScreen () { + this.dropdownMenuShow = false + this.searchTime = [] + this.$set(this.searchTime, 0, this.oldSearchTime[0]) + this.$set(this.searchTime, 1, this.oldSearchTime[1]) + this.$refs.pickTime.$refs.timePicker.setCustomTime(this.stableFilter) + this.screenModal = true + }, + resize (chartItem) { + getChart(this.chartIndex).resize() + }, + // 设置数据, filter区分 + setData (chartItem, seriesItem, panelId, filter, legend, area, errorMsg) { + console.log(chartItem, seriesItem, this.option,this.chartIndex); + this.data = chartItem + if (chartItem.type === 'bar') { + this.option.xAxis = { + type: 'category', + } + const maxValueCopies = this.getMaxValue(seriesItem, chartItem) + console.log(maxValueCopies) + const dot = maxValueCopies.dot + const maxValue = maxValueCopies.dot + const copies = maxValueCopies.dot + const unit = maxValueCopies.unit + this.option.yAxis = { + type: 'value' + // maxInterval:{}, + // 去掉y轴--start + // minInterval: chartDataFormat.Interval(maxValue, copies, unit.type, 'min'), + // maxInterval: chartDataFormat.Interval(maxValue, copies, unit.type, 'max') * Math.ceil(seriesItem.length / 5), + // // 去掉y轴--end + // axisLabel: { + // show: true, + // fontSize: 10, + // formatter: function (val, index) { + // let value = val + // if (val !== 0) { + // value = parseFloat(Number(val).toFixed(2)) + // if (value === 0) { + // value = Number(val).toExponential(2) + // } + // } + // const flag = JSON.stringify(value).length > JSON.stringify(chartDataFormat.Interval(maxValue, copies, unit.type)).length + // if (chartDataFormat.Interval(maxValue, copies, unit.type, 'min') < 1 && dot < 2) { + // dot = 2 + // } + // if (flag || dot == 0) { + // dot = 1 + // } + // return unit.compute(value, index, -1, dot) + // } + // } + // boundaryGap:[0,0.2] + } + const nweSeriesItem = [] + console.log(legend) + seriesItem[0].data.forEach((item, index) => { + const obj = { ...seriesItem[0] } + const legendShow = legend[index].alias ? legend[index].alias : legend[index].name + obj.name = legend[index].name + obj.data = [[legendShow, item.value]] + obj.stack = true + nweSeriesItem.push(obj) + }) + console.log(nweSeriesItem) + seriesItem = nweSeriesItem + } + if (filter) { + this.stableFilter = filter + } + if (errorMsg && errorMsg !== '') { + this.isError = true + this.errorContent = errorMsg + } else { + this.isError = false + this.errorContent = '' + } + if (seriesItem || seriesItem.data.length < 1) { // 0 为false + this.noData = false + } else { + this.noData = true + } + this.legend = legend + this.legendScreen = legend + legend && this.setColor(legend.length) + legend && legend.forEach((t, i) => { t.color = this.bgColorList[i] }) + + this.$set(this.option, 'color', this.bgColorList) + this.pieData = seriesItem + if (area === 'showFullScreen') { // 全屏按时间查询 + this.data = chartItem + this.unit = chartDataFormat.getUnit(this.data.unit) + this.initChart('screen') + this.searchTime[0] = filter.start_time// 将列表的查询时间复制给全屏的查询时间 + this.searchTime[1] = filter.end_time + this.endLoading('screen') + } else { + this.divFirstShow = true + + this.firstShow = true // 展示操作按键 + + this.panelIdInner = panelId + this.data = chartItem + this.unit = chartDataFormat.getUnit(this.data.unit) + this.initChart('local') + if (filter) { // 保存数据,用于同步时间 + this.searchTime[0] = filter.start_time// 将列表的查询时间复制给全屏的查询时间 + this.searchTime[1] = filter.end_time + this.oldSearchTime[0] = this.searchTime[0] + this.oldSearchTime[1] = this.searchTime[1] + } + this.endLoading() + } + }, + formatLegend (chartWidth, name) { + if (!name) { + return '' + } + // 计算宽度 + const span = document.querySelector('.temp-dom') + span.textContent = name + const txtWidth = parseFloat(window.getComputedStyle(span).width) - this.tempDom.width + if (txtWidth < chartWidth) { + return name + } else { + const charNum = `${(chartWidth - 100) / (txtWidth / name.length)}` + return name.slice(0, charNum) + '...' + } + }, + initChart: function (type) { + this.option.series = this.pieData + if (type == 'local') { + this.initLocal() + } else { + this.initScreen() + } + }, + initLocal: function () { + const self = this + const dom = document.getElementById('pie-chart-local-' + this.chartIndex) + if (!this.echart) { + this.echart = echarts.init(dom) + setChart(this.chartIndex, this.echart) + } + if (this.legend) { + this.isGrey = [] + this.legend.map((item, i) => { + const legend = { + name: item.name, + alias: item.alias, + color: item.color, + showText: this.formatLegend(dom.clientWidth, item.name) + } + self.isGrey.push(false) + return legend + }) + } + + this.$nextTick(() => { + setTimeout(function () { + const divHeight = self.$refs.legendArea.offsetHeight + if (!self.chartData.height) { + getChart(self.chartIndex).resize({ height: (400 - divHeight - self.$chartResizeTool.titleHeight - self.$chartResizeTool.chartBlankHeight) }) + } else { + getChart(self.chartIndex).resize({ height: (self.chartData.height - divHeight - self.$chartResizeTool.titleHeight - self.$chartResizeTool.chartBlankHeight) }) + } + self.$set(self.option.tooltip, 'formatter', self.formatterFunc) + self.$set(self.option.tooltip, 'position', function (point, params, dom, rect, size) { + dom.style.transform = 'translateZ(0)' + const windowWidth = window.innerWidth// 窗口宽度 + const windowHeight = window.innerHeight// 窗口高度 + const windowMouse = getMousePoint() + // 提示框位置 + let x = 0 + let y = 0 + // 当前鼠标位置 + const pointX = point[0] + const pointY = point[1] + // 外层div大小 + const viewWidth = size.viewSize[0] + // const viewHeight = size.viewSize[1] + // 提示框大小 + const boxWidth = size.contentSize[0] + const boxHeight = size.contentSize[1] + if (!self.screenModal) { // 本地显示 + const chartDom = document.getElementById(self.chartData.name + '_' + self.chartData.id) + if (chartDom) { + // const parTop = document.getElementById(self.chartData.title + '_' + self.chartData.id).offsetTop + const parleft = document.getElementById(self.chartData.name + '_' + self.chartData.id).offsetLeft + + const parent = document.getElementById('tableList') + // const parClientHeight = parent.clientHeight// 可视高度 + const parClientWidth = parent.clientWidth// 可视宽度 + // const parScrollTop = parent.scrollTop + if ((parClientWidth - pointX - parleft - 20) >= boxWidth) { // 说明鼠标在左边放不下提示框 + x = pointX + 10 + } else { + x = pointX - boxWidth + } + if (windowMouse.y + 50 + boxHeight < windowHeight) { // 说明鼠标上面放不下提示框 + y = pointY + 15 + } else { + y = pointY - boxHeight - 10 + } + return [x, y] + } else { // preview page + if (windowMouse.x < (windowWidth / 2)) { // 说明鼠标在左边放不下提示框 + x = pointX + 15 + } else { + x = pointX - boxWidth - 15 + } + if (windowMouse.y + 50 + boxHeight < windowHeight) { // 说明鼠标上面放不下提示框 + y = pointY + 15 + } else { + y = pointY - boxHeight - 10 + } + return [x, y] + } + } else { + if (pointX < (viewWidth / 2)) { // 说明鼠标在左边放不下提示框 + x = pointX + 10 + } else { + x = pointX - boxWidth + } + if (windowMouse.y + 50 + boxHeight < windowHeight) { // 说明鼠标上面放不下提示框 + y = pointY + 15 + } else { + y = pointY - boxHeight - 10 + } + return [x, y] + } + }) + if (self.pieData[0].data.length > 0) { + getChart(self.chartIndex).clear() + getChart(self.chartIndex).setOption(self.option)// 创建图表 + self.noData = false + } else { + self.noData = true + self.option = chartConfig.getOption('noData') + getChart(self.chartIndex).clear() + getChart(self.chartIndex).setOption(self.option)// 创建图表 + } + + self.$refs['localLoading' + self.chartIndex].endLoading() + self.firstShow = true // 展示操作按键 + }, 100) + }) + }, + initScreen: function () { + const self = this + const dom = document.getElementById('pie-chart-screen-' + this.chartIndex) + if (!this.echartScreen) { + this.echartScreen = echarts.init(dom) + } + if (this.legendScreen) { + this.isGreyScreen = [] + this.legendScreen = this.legendScreen.map((item, i) => { + const legend = { + name: item.name, + alias: item.alias, + color: item.color, + showText: this.formatLegend(dom.clientWidth, item.name) + } + self.isGreyScreen.push(false) + return legend + }) + } + if (self.echartScreen) { + self.echartScreen.clear() + self.showLegend = true + self.$refs['localLoadingScreen' + self.chartIndex].endLoading() + } + this.$nextTick(() => { + const legendDiv = document.getElementById('screenLegendArea' + self.chartIndex) + const divHeight = legendDiv.offsetHeight + const screenHeight = document.documentElement.clientHeight || document.body.clientHeight + const sumHeight = Math.floor(screenHeight * 0.99 * 0.8)// margin-top:1vh; dailog:80% + self.$refs.pieChartScreen.style.height = `${sumHeight - divHeight - 58}px` + self.echartScreen.resize({ height: (sumHeight - divHeight - 58) })// 图表的高度 + setTimeout(function () { + if (self.pieData[0].data.length > 0) { + self.echartScreen.setOption(self.option)// 显示全屏界面 + self.noData = false + } else { + self.noData = true + self.option = chartConfig.getOption('noData') + self.echartScreen.setOption(self.option)// 显示全屏界面 + } + self.echartScreen.on('finished', function () { + const legendDiv = document.getElementById('screenLegendArea' + self.chartIndex) + const divHeight = legendDiv.offsetHeight + const screenHeight = document.documentElement.clientHeight || document.body.clientHeight + const sumHeight = Math.floor(screenHeight * 0.99 * 0.8)// margin-top:1vh; dailog:80% + self.$refs.pieChartScreen.style.height = `${sumHeight - divHeight - 58}px` + self.echartScreen.resize({ height: (sumHeight - divHeight - 58) })// 图表的高度 + self.echartScreen.off('finished') + }) + }, 100) + }) + }, + dealLegendAlias: function (legend, expression) { + if (/\{\{.+\}\}/.test(expression)) { + const labelValue = expression.replace(/(\{\{.+?\}\})/g, function (i) { + const label = i.substr(i.indexOf('{{') + 2, i.indexOf('}}') - i.indexOf('{{') - 2) + const reg = new RegExp(label + '=".+?"') + let value = null + if (reg.test(legend)) { + const find = legend.match(reg)[0] + value = find.substr(find.indexOf('"') + 1, find.lastIndexOf('"') - find.indexOf('"') - 1) + } + return value || label + }) + return labelValue + } else { + return expression + } + }, + clickLegend (legendName, index) { + /* 点击legend + * 1.当前如果是全高亮状态,则全部置灰,只留被点击的legend高亮 + * 2.如果点击的是唯一高亮的legend,则变为全高亮状态 + * 3.否则只改变被点击的legend状态 + * */ + let highlightNum = 0 // 高亮数量 + this.isGrey.forEach(g => { + if (!g) { + highlightNum++ + } + }) + const hasGrey = highlightNum < this.isGrey.length // 是否有置灰的 + const curIsGrey = this.isGrey[index] // 当前legend的状态 + const currentIsTheOnlyOneHighlight = !curIsGrey && highlightNum === 1 // 当前legend是否是目前唯一高亮的 + + const echart = getChart(this.chartIndex) + if (echart) { + if (!hasGrey) { // 1.除当前legend外全置灰 + echart.dispatchAction({ + type: 'legendInverseSelect' + }) + echart.dispatchAction({ + type: 'legendSelect', + name: legendName + }) + this.isGrey = this.isGrey.map((g, i) => i !== index) + } else if (currentIsTheOnlyOneHighlight) { // 2.全高亮 + echart.dispatchAction({ + type: 'legendAllSelect' + }) + this.isGrey = this.isGrey.map(() => false) + } else { + const type = curIsGrey ? 'legendSelect' : 'legendUnSelect' + echart.dispatchAction({ + type: type, + name: legendName + }) + this.$set(this.isGrey, index, !this.isGrey[index]) + } + } + }, + clickScreenLegend (legendName, index) { + /* 点击legend + * 1.当前如果是全高亮状态,则全部置灰,只留被点击的legend高亮 + * 2.如果点击的是唯一高亮的legend,则变为全高亮状态 + * 3.否则只改变被点击的legend状态 + * */ + let highlightNum = 0 // 高亮数量 + this.isGreyScreen.forEach(g => { + if (!g) { + highlightNum++ + } + }) + const hasGrey = highlightNum < this.isGreyScreen.length // 是否有置灰的 + const curIsGrey = this.isGreyScreen[index] // 当前legend的状态 + const currentIsTheOnlyOneHighlight = !curIsGrey && highlightNum === 1 // 当前legend是否是目前唯一高亮的 + + const echart = this.echartScreen + if (echart) { + if (!hasGrey) { // 1.除当前legend外全置灰 + echart.dispatchAction({ + type: 'legendInverseSelect' + }) + echart.dispatchAction({ + type: 'legendSelect', + name: legendName + }) + this.isGreyScreen = this.isGreyScreen.map((g, i) => i !== index) + } else if (currentIsTheOnlyOneHighlight) { // 2.全高亮 + echart.dispatchAction({ + type: 'legendAllSelect' + }) + this.isGreyScreen = this.isGreyScreen.map(() => false) + } else { + const type = curIsGrey ? 'legendSelect' : 'legendUnSelect' + echart.dispatchAction({ + type: type, + name: legendName + }) + this.$set(this.isGreyScreen, index, !this.isGreyScreen[index]) + } + } + }, + setColor (colorNum) { + this.bgColorList = [ + '#FF5200', '#3685FF', '#FF8D00', '#00DCA2', + '#954Eff', '#FFCB01', '#f65A96', '#00BFD0', + '#FF8BEA', '#4D7693', '#72577C', '#99D750', + '#DD8270', '#C475EE', '#7E83FB', '#7EB090', + '#FF9094', '#00CCF5', '#CF6684', '#4E55FF' + ] + for (let i = 0; i < colorNum - 19; i++) { + this.bgColorList.push(randomcolor()) + } + }, + formatterFunc: function (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-x:hidden;text-overflow:ellipsis;margin-bottom: 5px">${this.legend[params.dataIndex].alias}</div> + <div style="font-size:12px;display:flex;justify-content: space-between;"> + <div>value</div> + <div>${chartDataFormat.getUnit(chartInfo.unit ? chartInfo.unit : 2).compute(params.value, null, -1, 2)}</div> + </div> + <div style="font-size:12px;display:flex;justify-content: space-between;"> + <div>percent</div> + <div style="display: ${chartInfo.type === 'pie' ? 'block' : 'none'}">${params.percent}%</div> + </div> + </div> + </div> + ` + }, + getMaxValue (dataArg, chartInfo) { + let maxValue = 0 + let minValue = 0 + if (chartInfo.unit && dataArg.length > 0) { + maxValue = 0 + minValue = 0 + for (let j = 0; j < dataArg.length; j++) { + for (let i = 0; i < dataArg[j].data.length; i++) { + if (!isNaN(dataArg[j].data[i].value)) { + maxValue = (maxValue < Number(dataArg[j].data[i].value) ? Number(dataArg[j].data[i].value) : maxValue) + minValue = (minValue > Number(dataArg[j].data[i].value) ? Number(dataArg[j].data[i].value) : minValue) + } + } + } + } + const chartUnit = chartInfo.unit ? chartInfo.unit : 2 + const unit = chartDataFormat.getUnit(chartUnit) + minValue = minValue > 0 ? 0 : minValue + maxValue = maxValue - minValue + maxValue = chartDataFormat.formatDatas(maxValue, unit.type, 'ceil', unit.ascii) + let oldValue = maxValue + let dot = 0 + if (maxValue == 1) { + dot++ + } + if (oldValue > 10) { + while (oldValue > 10) { + oldValue = oldValue / 10 + } + } else if (oldValue < 1 && maxValue !== 0) { + while (oldValue < 1 && oldValue > 0) { + oldValue = oldValue * 10 + dot++ + } + maxValue = Math.floor(oldValue) / Math.pow(10, dot) + dot++ + } + const copies = chartDataFormat.copies(oldValue, unit.type) + let oldDot = 2 + if (maxValue <= 1) { + oldDot = dot > 6 ? 6 : dot + } + return { + maxValue, + dot, + copies, + minValue, + unit, + oldDot + } + } + }, + mounted () { + this.firstLoad = false + }, + beforeDestroy () { + this.clearChart() + } +} +</script> diff --git a/nezha-fronted/src/components/charts/chart-group.vue b/nezha-fronted/src/components/charts/chart-group.vue index 3ca56ed75..7d86a2e68 100644 --- a/nezha-fronted/src/components/charts/chart-group.vue +++ b/nezha-fronted/src/components/charts/chart-group.vue @@ -16,16 +16,16 @@ <i class="nz-icon nz-icon-arrow-down" :class="showList?'':'is-active'"/> </span> {{chartData.name}} - <span v-show="!showList">{{dataList.length}} panel collapse</span> + <span v-show="!showList" class="collapse-content">({{chartData.children.length}} charts)</span> </span> <span class="chart-title-icon" :class="{'visible':caretShow,'hidden':!caretShow}"> -<!-- <span @click="refreshChart" class="" v-has="`${from}_chart_toEdit`" :title="$t('dashboard.refresh')">--> -<!-- <i class="nz-icon nz-icon-replay"></i>--> -<!-- </span>--> + <span @click="addGroupItemChart" class="" v-has="`${from}_chart_toEdit`" :title="$t('dashboard.refresh')"> + <i class="nz-icon nz-icon-plus"></i> + </span> <!-- <span @click="showAllScreen" class="" :title="$t('dashboard.screen')">--> <!-- <i class="nz-icon nz-icon-maxview"></i>--> <!-- </span>--> -<!-- <span><i class="el-icon-more" @click.stop="dropdownMenuShow=!dropdownMenuShow"></i></span>--> + <span><i class="el-icon-more" @click.stop="dropdownMenuShow=!dropdownMenuShow"></i></span> </span> </span> @@ -214,9 +214,11 @@ export default { this.$emit('on-edit-chart-block', this.data.id) }, editGroupItem (chart) { + chart.isGroup = true this.$emit('on-edit-group-chart', chart) }, duplicateGroupItem (chart) { + chart.isGroup = true this.$emit('on-duplicate-group-chart', chart) }, // 删除该图表 @@ -224,10 +226,13 @@ export default { this.dropdownMenuShow = false this.$emit('on-remove-chart-block', this.data.id) }, - // 删除该图表 + // 删除group 下的该图表 removeChartGroup (chart) { this.$emit('on-remove-group-chart', chart) }, + addGroupItemChart () { + this.$emit('on-add-group-item-chart', this.data.id) + }, clickos () { this.dropdownMenuShow = false }, @@ -314,4 +319,8 @@ export default { -90deg ); } + .collapse-content{ + font-size: 12px; + color: #999999; + } </style> diff --git a/nezha-fronted/src/components/charts/chart-list-group.vue b/nezha-fronted/src/components/charts/chart-list-group.vue index 54cc1cc6b..a81965f7a 100644 --- a/nezha-fronted/src/components/charts/chart-list-group.vue +++ b/nezha-fronted/src/components/charts/chart-list-group.vue @@ -67,7 +67,7 @@ }" style="width: 100%;height: 100%"> <div :class="{'drag-disabled': !draggable,'chartBox':true}" :id="'chart-' + item.id" :key="item.id" :name="item.title" :ref="'chart' + item.id" :style="{marginBottom: extraMarginBottom}" v-for="(item, index) in dataList" v-show="!item.isHide"> - <line-chart-block v-if="item.type === 'line' || item.type === 'bar' ||item.type == 'stackArea' || item.type === 4" :key="'inner' + item.id" + <line-chart-block v-if="item.type === 'line' || (item.type === 'bar' && (!item.param.statistics || item.param.statistics === 'null')) ||item.type == 'stackArea' || item.type === 4" :key="'inner' + item.id" :from="from" :ref="'editChart'+item.id" :temp-dom="tempDom" @on-refresh-data="refreshChart" @on-remove-chart-block="removeChart" @@ -158,7 +158,18 @@ @on-edit-chart-block="editData" @dropmenu-change="(show) => {dropmenuChange(item.id, show)}" ></chart-alert-list> - + <chartBarStatis :from="from" :key="'inner' + item.id" :ref="'editChart'+item.id" v-if="(item.type === 'bar'&& item.param.statistics && item.param.statistics !== 'null')" :temp-dom="tempDom" + @on-refresh-data="refreshChart" + @on-search-data="searchData" + @on-remove-chart-block="removeChart" + @on-duplicate-chart-block="duplicateChart" + @on-drag-chart="editChartForDrag" + @on-edit-chart-block="editData" + :chart-data="item" + :is-lock="panelLock" + :panel-id="filter.panelId" + @dropmenu-change="(show) => {dropmenuChange(item.id, show)}" + :chart-index="item.chartIndex"></chartBarStatis> <chart-pie :from="from" :key="'inner' + item.id" :ref="'editChart'+item.id" v-if="item.type === 'pie'" :temp-dom="tempDom" @on-refresh-data="refreshChart" @on-search-data="searchData" @@ -191,6 +202,7 @@ import chartDataFormat from './chartDataFormat' import chartAlertList from './chart-alert-list' import textChart from './text-chart' import chartPie from './chart-pie' +import chartBarStatis from './chart-bar-statistics' // import visNetwork from './visNetwork' export default { name: 'chartList', @@ -203,7 +215,7 @@ export default { panelLock: { type: Boolean, default: false }, hasGroup: { type: Boolean, default: true }, groupList: {}, - filterParent: {}, + filterParent: {} }, components: { @@ -215,7 +227,8 @@ export default { chartSingleStat, draggable, textChart, - chartPie + chartPie, + chartBarStatis // visNetwork, }, watch: { @@ -225,10 +238,6 @@ export default { this.dataList = [...n] this.$nextTick(() => { this.dataList.forEach((item, index) => { - if (item.type === 'text') { - console.log(item) - } - console.log(item, index, this.filter) this.getChartData(item, index, this.filter) this.setChartSize(item, index) }) @@ -238,7 +247,6 @@ export default { filterParent: { immediate: true, handler (n) { - console.log(n) this.filter = { ...n } this.pagePanelId = this.filter.panelId } @@ -626,7 +634,6 @@ export default { this.dataTotalList = [...chartListTmp] this.dataList = [...this.dataTotalList] - console.log(this.dataList) this.dataList.push({ ...this.dataList[0], group: { @@ -886,6 +893,26 @@ export default { data: [] } } + if (chartInfo.type === 'bar' && chartInfo.param.statistics && chartInfo.param.statistics !== 'null') { + pieSeries = { + type: 'bar', + // roseType: 'radius', + itemStyle: { + borderRadius: 5, + borderColor: '#fff', + borderWidth: 1 + }, + label: { + show: false + }, + emphasis: { + label: { + show: false + } + }, + data: [] + } + } res.forEach((response, innerPos) => { if (response.status === 'success') { errorMsg = '' @@ -1011,6 +1038,8 @@ export default { }) if (chartInfo.type === 'pie') { pieSeries.data.push({ value: bus.getSingleStatRlt(chartInfo.param.statistics, seriesItem.theData.data), name: host + '-' + chartItem.elements[innerPos].id + '-' + resIndex }) + } else if (chartInfo.type === 'bar' && chartInfo.param.statistics && chartInfo.param.statistics !== 'null') { + pieSeries.data.push({ value: bus.getSingleStatRlt(chartInfo.param.statistics, seriesItem.theData.data), name: host + '-' + chartItem.elements[innerPos].id + '-' + resIndex }) } else { series.push(seriesItem.theData) seriesItem = null @@ -1048,6 +1077,9 @@ export default { if (chartInfo.type === 'pie') { series.push(pieSeries) } + if (chartInfo.type === 'bar' && chartInfo.param.statistics && chartInfo.param.statistics !== 'null') { + series.push(pieSeries) + } const chartData = { chartItem: chartItem, series: series, @@ -1475,7 +1507,6 @@ export default { if (this.additionalInfo) { this.$set(chartInfo, 'param', { endpointId: this.additionalInfo.id }) } - console.log(this.$refs['editChart' + chartInfo.id]) this.$refs['editChart' + chartInfo.id][0].getAlertList(filterType) }, getAlertRuleChartData (chartInfo) { diff --git a/nezha-fronted/src/components/charts/chart-list.vue b/nezha-fronted/src/components/charts/chart-list.vue index bb785e3f3..b8bc02b8d 100644 --- a/nezha-fronted/src/components/charts/chart-list.vue +++ b/nezha-fronted/src/components/charts/chart-list.vue @@ -67,7 +67,7 @@ handle: '.chart-title' }" > <div :class="{'drag-disabled': !draggable,'chartBox':true}" :id="'chart-' + item.id" :key="item.id" :name="item.title" :ref="'chart' + item.id" :style="{marginBottom: extraMarginBottom}" v-for="(item, index) in dataList" v-show="!item.isHide"> - <line-chart-block v-if="item.type === 'line' || item.type === 'bar' ||item.type == 'stackArea' || item.type === 4" :key="'inner' + item.id" + <line-chart-block v-if="item.type === 'line' || (item.type === 'bar' && (!item.param.statistics || item.param.statistics === 'null')) ||item.type == 'stackArea' || item.type === 4" :key="'inner' + item.id" :from="from" :ref="'editChart'+item.id" :temp-dom="tempDom" @on-refresh-data="refreshChart" @on-remove-chart-block="removeChart" @@ -170,6 +170,18 @@ :panel-id="filter.panelId" @dropmenu-change="(show) => {dropmenuChange(item.id, show)}" :chart-index="index"></chart-pie> + <chartBarStatis :from="from" :key="'inner' + item.id" :ref="'editChart'+item.id" v-if="(item.type === 'bar'&& item.param.statistics && item.param.statistics !== 'null')" :temp-dom="tempDom" + @on-refresh-data="refreshChart" + @on-search-data="searchData" + @on-remove-chart-block="removeChart" + @on-duplicate-chart-block="duplicateChart" + @on-drag-chart="editChartForDrag" + @on-edit-chart-block="editData" + :chart-data="item" + :is-lock="panelLock" + :panel-id="filter.panelId" + @dropmenu-change="(show) => {dropmenuChange(item.id, show)}" + :chart-index="index"></chartBarStatis> <chart-group :from="from" :key="'inner' + item.id" :ref="'editChart'+item.id" v-if="item.type === 'group'" @on-refresh-data="refreshChart" @on-search-data="searchData" @@ -183,6 +195,7 @@ @on-edit-group-chart="editDataGroup" @on-remove-group-chart="removeChartGroup" @on-duplicate-group-chart="duplicateChartGroup" + @on-add-group-item-chart="addGroupItem" @moveGroupItem="moveGroupItem" :panel-id="filter.panelId" :chart-data="item" @@ -209,6 +222,7 @@ import chartDataFormat from './chartDataFormat' import chartAlertList from './chart-alert-list' import textChart from './text-chart' import chartPie from './chart-pie' +import chartBarStatis from './chart-bar-statistics' import chartGroup from './chart-group' // import visNetwork from './visNetwork' export default { @@ -233,7 +247,8 @@ export default { draggable, textChart, chartPie, - chartGroup + chartGroup, + chartBarStatis // visNetwork, }, data () { @@ -629,14 +644,8 @@ export default { response.data.list.forEach((item, index) => { item.isLoaded = false }) - - response.data.list.forEach((item, index) => { // 把chart放入对应的group - if (item.type === 'group') { - item.children = response.data.list.filter(item1 => item1.groupId === item.id) - } - }) - response.data.list = response.data.list.filter((item) => item.groupId === -1 || !item.groupId) // 处理外层存在的groupItem - console.log(response.data.list) + // response.data.list = response.data.list.filter((item) => item.groupId === -1 || !item.groupId) // 处理外层存在的groupItem + // console.log(response.data.list) if (response.data.list) { this.dataTotalListBak = response.data.list } else { @@ -658,19 +667,6 @@ export default { this.dataTotalList = [...chartListTmp] this.dataList = [...this.dataTotalList] - console.log(this.dataList) - // this.dataList.push({ - // ...this.dataList[0], - // group: { - // id: 1, - // name: 'chart group' - // }, - // type: 'group', - // span: 12, - // height: 600, - // id: 999999, - // children: [...this.dataList] - // }) let addGroupIndex = 0 this.dataList.forEach((item) => { if (item.type === 'group') { @@ -932,6 +928,26 @@ export default { data: [] } } + if (chartInfo.type === 'bar' && chartInfo.param.statistics && chartInfo.param.statistics !== 'null') { + pieSeries = { + type: 'bar', + // roseType: 'radius', + itemStyle: { + borderRadius: 5, + borderColor: '#fff', + borderWidth: 1 + }, + label: { + show: false + }, + emphasis: { + label: { + show: false + } + }, + data: [] + } + } res.forEach((response, innerPos) => { if (response.status === 'success') { errorMsg = '' @@ -1022,7 +1038,6 @@ export default { host = chartItem.elements[innerPos].expression } // 处理legend别名 - console.log(chartItem.id) let alias = this.$refs['editChart' + chartItem.id][0].dealLegendAlias(host, chartItem.elements[innerPos].legend) if (!alias || alias === '') { alias = host @@ -1058,6 +1073,8 @@ export default { }) if (chartInfo.type === 'pie') { pieSeries.data.push({ value: bus.getSingleStatRlt(chartInfo.param.statistics, seriesItem.theData.data), name: host + '-' + chartItem.elements[innerPos].id + '-' + resIndex }) + } else if (chartInfo.type === 'bar' && chartInfo.param.statistics && chartInfo.param.statistics !== 'null') { + pieSeries.data.push({ value: bus.getSingleStatRlt(chartInfo.param.statistics, seriesItem.theData.data), name: host + '-' + chartItem.elements[innerPos].id + '-' + resIndex }) } else { series.push(seriesItem.theData) seriesItem = null @@ -1095,6 +1112,9 @@ export default { if (chartInfo.type === 'pie') { series.push(pieSeries) } + if (chartInfo.type === 'bar' && chartInfo.param.statistics && chartInfo.param.statistics !== 'null') { + series.push(pieSeries) + } const chartData = { chartItem: chartItem, series: series, @@ -1184,6 +1204,9 @@ export default { return Number('-' + (txtWidth + 5)) } }, + addGroupItem (id) { + this.$emit('on-add-group-item-chart', id) + }, modelStaticData (chartInfo, filterType) { const series = [] const legend = [] @@ -1596,6 +1619,7 @@ export default { // 删除图表 removeChart (chartId) { // from 区分从哪里点击的删除 1.从图表面板 2.从编辑框 const chart = this.dataList.find(item => item.id === chartId) + console.log(chart) if (chart) { this.$emit('on-remove-chart', chart) } diff --git a/nezha-fronted/src/components/charts/line-chart-block.vue b/nezha-fronted/src/components/charts/line-chart-block.vue index 045cbd7d5..8177fef82 100644 --- a/nezha-fronted/src/components/charts/line-chart-block.vue +++ b/nezha-fronted/src/components/charts/line-chart-block.vue @@ -762,10 +762,10 @@ export default { sum += self.numberWithEConvent(val) str += '<div style="white-space:nowrap;overflow-x:hidden;text-overflow:ellipsis;display: flex; justify-content: space-between; min-width: 150px; max-width: 600px; line-height: 18px; font-size: 12px;">' str += `<div style="max-width: 500px;white-space:nowrap;overflow-x:hidden;text-overflow:ellipsis;"><span style='display:inline-block;margin-right:5px;border-radius:10px;width:15px;height:5px;background-color: ${color};}'></span>${tip ? (tip.alias ? tip.alias : tip.name) : item.seriesName} </div>` - str += '<div style="padding-left: 10px;">' + str += '<div style="padding-left: 10px;min-width: 75px;text-align: right">' str += chartDataFormat.getUnit(chartInfo.unit ? chartInfo.unit : 2).compute(val, null, -1, oldDot) if (previousItem) { - str += '<span style="padding-left: 10px; display: inline-block;width: 100px;text-align: right">' + str += '<span style="padding-left: 10px; display: inline-block;width: 75px;text-align: right">' let previousval = parseFloat(Number(previousItem.data[1]).toFixed(2)) if (previousval === 0) { previousval = Number(item.data[1]).toExponential(2) @@ -782,7 +782,7 @@ export default { str += chartDataFormat.getUnit(chartInfo.unit ? chartInfo.unit : 2).compute(minusVal, null, 2) str += '</span>' } else if (tip.alias.indexOf('Previous ') !== -1) { - str += '<span style="padding-left: 10px; display: inline-block;width: 100px;text-align: right">' + str += '<span style="padding-left: 10px; display: inline-block;width: 75px;text-align: right">' str += '</span>' } str += '</div>' @@ -1200,10 +1200,10 @@ export default { sum += self.numberWithEConvent(val) str += '<div style="white-space:nowrap;overflow-x:hidden;text-overflow:ellipsis;display: flex; justify-content: space-between; min-width: 150px; max-width: 600px; line-height: 18px; font-size: 12px;">' str += `<div style="max-width: 500px;white-space:nowrap;overflow-x:hidden;text-overflow:ellipsis;"><span style='display:inline-block;margin-right:5px;border-radius:10px;width:15px;height:5px;background-color: ${color};}'></span>${tip ? (tip.alias ? tip.alias : tip.name) : item.seriesName} </div>` - str += '<div style="padding-left: 10px;">' + str += '<div style="padding-left: 10px;min-width: 75px;text-align: right">' str += chartDataFormat.getUnit(chartInfo.unit ? chartInfo.unit : 2).compute(val, null, 2) if (previousItem) { - str += '<span style="padding-left: 10px; display: inline-block;width: 100px;text-align: right">' + str += '<span style="padding-left: 10px; display: inline-block;width: 75px;text-align: right">' let previousval = parseFloat(Number(previousItem.data[1]).toFixed(2)) if (previousval === 0) { previousval = Number(item.data[1]).toExponential(2) @@ -1220,7 +1220,7 @@ export default { str += chartDataFormat.getUnit(chartInfo.unit ? chartInfo.unit : 2).compute(minusVal, null, 2) str += '</span>' } else if (tip.alias.indexOf('Previous ') !== -1) { - str += '<span style="padding-left: 10px; display: inline-block;width: 100px;text-align: right">' + str += '<span style="padding-left: 10px; display: inline-block;width: 75px;text-align: right">' str += '</span>' } str += '</div>' diff --git a/nezha-fronted/src/components/charts/text-chart.vue b/nezha-fronted/src/components/charts/text-chart.vue index beba1f239..e2c26daa5 100644 --- a/nezha-fronted/src/components/charts/text-chart.vue +++ b/nezha-fronted/src/components/charts/text-chart.vue @@ -188,7 +188,6 @@ export default { }, // 设置数据, filter区分 setData (chartItem, seriesItem, panelId, filter, area) { - console.log(chartItem); this.$nextTick(() => { this.resize(chartItem) }) diff --git a/nezha-fronted/src/components/common/js/tools.js b/nezha-fronted/src/components/common/js/tools.js index d73a1c1d7..5d2050944 100644 --- a/nezha-fronted/src/components/common/js/tools.js +++ b/nezha-fronted/src/components/common/js/tools.js @@ -335,7 +335,7 @@ export const chartResizeTool = { chartTableBlankHeight: 6, // 表格型图表额外空白占位高度 chartBlankWidth: 2, // 图表空白占位宽度 containerBlankWidth: 5, // 容器空白占位宽度(#listContainer的padding) - titleHeight: 28, // 标题dom高度 + titleHeight: 40, // 标题dom高度 stepHeight: 50, // 单元高度 timeouter: null, stepWidth (containerWidth) { // 单元宽度,参数为容器总宽度 diff --git a/nezha-fronted/src/components/common/language/cn.js b/nezha-fronted/src/components/common/language/cn.js index 8497a89ff..8d0293300 100644 --- a/nezha-fronted/src/components/common/language/cn.js +++ b/nezha-fronted/src/components/common/language/cn.js @@ -193,6 +193,8 @@ const cn = { last: 'Last', threshold: '阈值', thresholds: '阈值', + group: '组', + remark: '描述', typeVal: { line: { label: '曲线图' @@ -235,7 +237,7 @@ const cn = { last: 'Last', range: 'Range', different: 'Different', - null: 'Null' + null: 'None' }, width: '宽', high: '高', diff --git a/nezha-fronted/src/components/common/language/en.js b/nezha-fronted/src/components/common/language/en.js index 340f06ea5..27daa6cae 100644 --- a/nezha-fronted/src/components/common/language/en.js +++ b/nezha-fronted/src/components/common/language/en.js @@ -206,12 +206,14 @@ const en = { last: 'Last', threshold: 'Threshold', thresholds: 'Thresholds', + group: 'Group', + remark: 'Description', typeVal: { line: { label: 'Line Chart' // "曲线图" }, bar: { - label: 'Bar' // "柱状图" + label: 'Bar Chart' // "柱状图" }, table: { label: 'Table' // "表格" @@ -227,7 +229,7 @@ const en = { label: 'Single value' }, pie: { - label: 'Pie' + label: 'Pie Chart' }, alertList: { label: 'Alert list' @@ -248,7 +250,7 @@ const en = { last: 'Last', range: 'Range', different: 'Different', - null: 'Null' + null: 'None' }, width: 'Width', // "宽" high: 'High', // "高" diff --git a/nezha-fronted/src/components/common/popBox/selectPanel.vue b/nezha-fronted/src/components/common/popBox/selectPanel.vue index d183b1a6c..8c362dcf4 100644 --- a/nezha-fronted/src/components/common/popBox/selectPanel.vue +++ b/nezha-fronted/src/components/common/popBox/selectPanel.vue @@ -1,5 +1,5 @@ <template> - <el-popover :placement="placement" popper-class="nz-pop nz-pop-select-panel" ref="selectPanelPopBox" transition="slide" v-model="popBox.show" width="400"> + <el-popover :placement="placement" popper-class="nz-pop nz-pop-select-panel" ref="selectPanelPopBox" transition="slide" v-model="popBox.show" width="400" :disabled="disabled"> <div> <div class="pop-item-wider"> @@ -46,6 +46,7 @@ export default { panelData: { type: Array }, showPanel: { type: Object }, panelLock: { type: Boolean, default: true }, + disabled: { type: Boolean, default: false }, filterPanel: { type: String } }, mounted () { diff --git a/nezha-fronted/src/components/page/dashboard/chartBox.vue b/nezha-fronted/src/components/page/dashboard/chartBox.vue index e59cf7e1c..8ad760e14 100644 --- a/nezha-fronted/src/components/page/dashboard/chartBox.vue +++ b/nezha-fronted/src/components/page/dashboard/chartBox.vue @@ -156,7 +156,10 @@ <!-- begin--表单--> <div class="right-box-form-box" ref="scrollbar"> <el-form :model="editChart" :rules="rules" class="right-box-form right-box-form-left" label-position = "top" label-width="120px" ref="chartForm"> - <el-form-item :label="$t('dashboard.panel.title')" prop="panelName" v-if="showPanel.type != 'dashboard' && showPanel.type != 'project' && showPanel.type != 'asset' && showPanel.type != 'model'"> + <el-form-item :label='$t("dashboard.panel.chartForm.chartName")' prop="title"> + <el-input maxlength="64" show-word-limit size="small" v-model="editChart.name" id="chart-box-title"></el-input> + </el-form-item> + <el-form-item :label="$t('dashboard.panel.title')" prop="panelName" v-if="showPanel.type != 'project' && showPanel.type != 'asset' && showPanel.type != 'model'"> <!--<el-autocomplete :fetch-suggestions="panelSuggestion" @input="inputPanel" @@ -168,31 +171,22 @@ value-key="name" > </el-autocomplete>--> - <select-panel :filter-panel="filterPanel" :panel-lock="true" :panelData="panelData" :placement="'bottom-start'" @selectPanel="selectPanel" ref="selectPanel" - v-if="!editChart.id"> + <select-panel :filter-panel="filterPanel" :panel-lock="true" :disabled="showPanel.type==='dashboard'" :panelData="panelData" :placement="'bottom-start'" @selectPanel="selectPanel" ref="selectPanel"> <template v-slot:header> <div class="panel-select-header"> <el-input :placeholder="$t('overall.search')" clearable size="mini" style="width: 340px; margin-right: 5px;" v-model="filterPanel" id="chart-box-panelname"></el-input> </div> </template> <template v-slot:trigger> - <el-input placeholder="" readonly="readonly" size="small" v-model="panelName"></el-input> + <el-input placeholder="" readonly="readonly" size="small" v-model="panelName" :disabled="showPanel.type==='dashboard'"></el-input> </template> </select-panel> - <el-input :value="editChart.panelName" readonly="readonly" size="small" v-if="editChart.id"></el-input> </el-form-item> - <el-form-item :label='$t("dashboard.panel.chartForm.chartName")' prop="title"> - <el-input maxlength="64" show-word-limit size="small" v-model="editChart.name" id="chart-box-title"></el-input> - </el-form-item> - - <div class="right-box-sub-title">{{$t('dashboard.panel.chartForm.option')}}</div> - <div style="margin-bottom: 20px;width: 100%"></div> - - <!-- type unit start--> + <!-- type --> <el-form-item :label="$t('dashboard.panel.chartForm.type')" class="half-form-item" prop="type"> - <el-select @change="chartTypeChange" class="right-box-row-with-btn" placeholder="" popper-class="chart-box-dropdown-small" size="mini" v-model="editChart.type" value-key="chartType" id="chart-box-type"> - <el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in chartTypeList"> + <el-select @change="chartTypeChange" class="right-box-row-with-btn" placeholder="" popper-class="chart-box-dropdown-small" size="mini" v-model="editChart.type" value-key="chartType" id="chart-box-type" :disabled="editChart.type==='group'&&editChart.children&&editChart.children.length"> + <el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in chartTypeList" :disabled=" item.id==='group' && editChart.isGroup"> <span class="panel-dropdown-label-txt" >{{item.name}}</span> </el-option> </el-select> @@ -206,7 +200,9 @@ </el-option> </el-select> </el-form-item> - + <div class="right-box-sub-title">{{$t('dashboard.panel.chartForm.option')}}</div> + <div style="margin-bottom: 20px;width: 100%"></div> + <!-- unit --> <el-form-item :label="$t('dashboard.panel.chartForm.unit')" class="half-form-item" prop="unit" v-show="editChart.type !='text' && editChart.type !=='url'&& editChart.type !=='group'"> <el-cascader :options="unitOptions" :props="{ expandTrigger: 'hover',emitPath:false }" :show-all-levels="false" @change="unitSelected" filterable id="chart-box-unit" placeholder="" @@ -258,8 +254,8 @@ <el-input size="mini" type="input" v-model="editChart.param.threshold" id="chart-box-threshold"></el-input> </el-form-item> - <el-form-item :label="$t('dashboard.panel.chartForm.statistics')" class="half-form-item" prop="param.statistics" v-if="editChart.type == 'singleStat' || editChart.type == 'pie'|| editChart.type=='table' "> - <el-select placeholder="" popper-class="chart-box-dropdown-mini" size="mini" v-model="editChart.param.statistics" id="chart-box-panelname"> + <el-form-item :label="$t('dashboard.panel.chartForm.statistics')" class="half-form-item" prop="param.statistics" v-if="editChart.type == 'singleStat' || editChart.type == 'pie'|| editChart.type=='table' || editChart.type == 'bar'"> + <el-select placeholder="" popper-class="chart-box-dropdown-mini" size="mini" v-model="editChart.param.statistics" id="chart-box-statistics" @change="$forceUpdate"> <el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in statisticsList"> <span class="panel-dropdown-label-txt" >{{item.label}}</span> </el-option> @@ -867,13 +863,15 @@ export default { }); */ // panelPromise.then(()=>{ + console.log(this.editChart) if (this.panelId) { const chartParams = params || this.editChart chartParams.panelId = this.panelId if (!chartParams.groupId) { - chartParams.groupId = -1 + chartParams.groupId = 0 } delete chartParams.panel + delete chartParams.children this.$post('visual/panel/chart', chartParams).then(response => { if (response.code === 200) { this.$message({ duration: 1000, type: 'success', message: this.$t('tip.saveSuccess') }) @@ -901,6 +899,7 @@ export default { chartParams.groupId = -1 } delete chartParams.panel + delete chartParams.children this.$put('visual/panel/chart', chartParams).then(response2 => { if (response2.code === 200) { this.esc() @@ -935,7 +934,7 @@ export default { }, sync: this.editChart.sync } - if (this.editChart.type === 'singleStat' || this.editChart.type == 'pie') { + if (this.editChart.type === 'singleStat' || this.editChart.type === 'pie' || this.editChart.type === 'bar') { // params.param.statistics=this.statistics; } else { delete params.param.statistics @@ -1036,7 +1035,7 @@ export default { this.$refs.alertParamBox.saveParam() return } - if (this.editChart.type == 'singleStat' || this.editChart.type == 'pie' || this.editChart.type == 'table') { + if (this.editChart.type == 'singleStat' || this.editChart.type == 'pie' || this.editChart.type == 'table' || this.editChart.type == 'bar') { // this.$set(this.editChart.param, "statistics", this.statistics); } else { delete this.editChart.param.statistics @@ -1222,6 +1221,7 @@ export default { }, // 编辑chart时使用, set_tdata editData (data, panelId) { + console.log(data, this.editChart) if (!panelId) { this.panelId = 0 } else { @@ -1260,6 +1260,9 @@ export default { if ((this.editChart.type === 'line' || this.editChart.type === 'bar' || this.editChart.type === 'stackArea' || this.editChart.type === 'singleStat') && data.param) { this.editChart.param.threshold = data.param.threshold this.editChart.param.statistics = this.statistics = data.param.statistics + if (this.editChart.type === 'bar') { + this.statisticsList.push({ value: 'null', label: i18n.t('dashboard.panel.chartForm.statisticsVal.null') }) + } } else { this.editChart.param.threshold = '' } @@ -1299,7 +1302,7 @@ export default { this.editChart.height = 400 + '' this.editChart.unit = unit || 2 this.editChart.remark = '' - this.editChart.groupId = '' + this.editChart.groupId = this.editChart.groupId || '' const param = {} param.last = 0 param.url = '' @@ -1344,6 +1347,7 @@ export default { chartTypeChange () { const chartType = this.editChart.type this.editChart.param.url = '' + this.editChart.height = 400 if (chartType === 'url') { this.setIsUrl() /* if(this.$refs.chartTag){ @@ -1368,12 +1372,17 @@ export default { this.showPicker = [{ bac: false, text: false }] } else if (chartType === 'group') { this.editChart.span = 12 - this.editChart.height = -1 + this.editChart.height = '' this.setIsGroup() } else { this.setIsOtherChart() if (chartType === 'bar' || chartType === 'line' || chartType === 'stackArea') { this.editChart.param = { nullType: 'connected', threshold: '', legendValue: { min: 'off', max: 'off', avg: 'off', last: 'off', total: 'off' } } + if (chartType === 'bar') { + this.editChart.param = { statistics: 'last', nullType: 'connected', threshold: '', legendValue: { min: 'off', max: 'off', avg: 'off', last: 'off', total: 'off' } } + this.statisticsList = JSON.parse(JSON.stringify(this.$CONSTANTS.statisticsList)) + this.statisticsList.push({ value: 'null', label: i18n.t('dashboard.panel.chartForm.statisticsVal.null') }) + } } else if (chartType == 'table') { this.$set(this.editChart.param, 'last', 0) this.editChart.param = { @@ -1684,6 +1693,8 @@ export default { } this.editChart = JSON.parse(JSON.stringify(n)) + this.panelName = this.editChart.panelName + this.panelId = this.editChart.panelId this.editChart.name = this.editChart.name || '' if (!n.groupId || n.groupId == -1) { this.editChart.groupId = '' diff --git a/nezha-fronted/src/components/page/dashboard/explore/explore.vue b/nezha-fronted/src/components/page/dashboard/explore/explore.vue index 65c23e671..376111176 100644 --- a/nezha-fronted/src/components/page/dashboard/explore/explore.vue +++ b/nezha-fronted/src/components/page/dashboard/explore/explore.vue @@ -570,7 +570,7 @@ export default { }, saveChart () { const chart = { - title: '', + name: '', type: 'line', span: 12, height: '400', @@ -581,7 +581,9 @@ export default { }, elements: [], panel: '', - sync: 0 + sync: 0, + groupId: '', + remark: '', } this.expressions.forEach((exp) => { chart.elements.push({ expression: exp, legend: '', type: 'expert', id: '' }) @@ -606,7 +608,7 @@ export default { }) }, getPanelData () { // 获取panel数据 - this.$get('panel?pageNo=1&pageSize=-1').then(response => { + this.$get('visual/panel?pageNo=1&pageSize=-1').then(response => { if (response.code === 200) { this.panelData = response.data.list } diff --git a/nezha-fronted/src/components/page/dashboard/panel.vue b/nezha-fronted/src/components/page/dashboard/panel.vue index 66ff7773b..ac06f319f 100644 --- a/nezha-fronted/src/components/page/dashboard/panel.vue +++ b/nezha-fronted/src/components/page/dashboard/panel.vue @@ -100,7 +100,7 @@ <div class="table-list" id="tableList"> <div ref="dashboardScrollbar" style="height: 100%; overflow: auto;"> <div class="box-content"> - <chart-list :from="$CONSTANTS.fromRoute.panel" @on-edit-chart="editChart" @on-refresh-time="refreshTime" @on-remove-chart="delChart" ref="chartList" :panel-lock="panelLock" :class="{'show-top':showTopBtn}"></chart-list> + <chart-list :from="$CONSTANTS.fromRoute.panel" @on-edit-chart="editChart" @on-refresh-time="refreshTime" @on-remove-chart="delChart" ref="chartList" :panel-lock="panelLock" :class="{'show-top':showTopBtn}" @on-add-group-item-chart="addGroupItem"></chart-list> </div> </div> </div> @@ -140,7 +140,8 @@ export default { interval: 0, showPanel: { // panel下拉列表 id: '', - name: '' + name: '', + type: 'panel' }, panel: { // 新增panel id: '', @@ -221,6 +222,7 @@ export default { this.filter.searchName = '' // this.$refs.searchInput.select(); this.showPanel = val + this.showPanel.type = 'panel' this.filter.panelId = this.showPanel.id // let curTime = this.$refs.calendarPanel.getCurrentTime(); const curTime = this.searchTime @@ -284,9 +286,20 @@ export default { /* 图表相关操作--start */ addChart () { this.chart = this.newChart() + this.chart.panelId = this.showPanel.id + this.chart.panelName = this.showPanel.name this.rightBox.chart.show = true console.log(123123123) }, + addGroupItem (groupId) { + console.log(groupId) + this.chart = this.newChart() + this.chart.groupId = groupId + this.chart.panelId = this.showPanel.id + this.chart.panelName = this.showPanel.name + this.chart.isGroup = true + this.rightBox.chart.show = true + }, newChart () { return JSON.parse(JSON.stringify(this.blankChart)) }, @@ -296,6 +309,8 @@ export default { data.param = { url: '', threshold: '' } } this.chart = JSON.parse(JSON.stringify(data)) + this.chart.panelId = this.showPanel.id + this.chart.panelName = this.showPanel.name this.rightBox.chart.show = true }, closeChartBox (refresh) { |
