From 774e278182ce03bf2c38448029c208d6c3627b0c Mon Sep 17 00:00:00 2001 From: wisonic-s Date: Tue, 16 Jan 2024 11:29:10 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E8=A7=86=E5=9B=BE-=E9=80=8F=E8=A7=86?= =?UTF-8?q?=E8=A1=A8):=20=E5=B0=8F=E8=AE=A1=E6=80=BB=E8=AE=A1=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=8C=89=E5=AD=97=E6=AE=B5=E9=85=8D=E7=BD=AE=E8=81=9A?= =?UTF-8?q?=E5=90=88=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/frontend/src/views/chart/chart/chart.js | 16 +- .../src/views/chart/chart/table/table-info.js | 57 ++++ .../chart/components/ChartComponentS2.vue | 3 + .../chart/components/shapeAttr/TotalCfg.vue | 289 ++++++++++++++---- 4 files changed, 306 insertions(+), 59 deletions(-) diff --git a/core/frontend/src/views/chart/chart/chart.js b/core/frontend/src/views/chart/chart/chart.js index d790f5510d..d991ad6dd7 100644 --- a/core/frontend/src/views/chart/chart/chart.js +++ b/core/frontend/src/views/chart/chart/chart.js @@ -227,10 +227,14 @@ export const DEFAULT_TOTAL = { subLabel: '小计', subTotalsDimensions: [], calcTotals: { - aggregation: 'SUM' + aggregation: 'SUM', + // { dataeaseName, aggregation } + cfg: [] }, calcSubTotals: { - aggregation: 'SUM' + aggregation: 'SUM', + // { dataeaseName, aggregation } + cfg: [] }, totalSort: 'none', // asc,desc totalSortField: '' @@ -244,10 +248,14 @@ export const DEFAULT_TOTAL = { subLabel: '小计', subTotalsDimensions: [], calcTotals: { - aggregation: 'SUM' + aggregation: 'SUM', + // { dataeaseName, aggregation } + cfg: [] }, calcSubTotals: { - aggregation: 'SUM' + aggregation: 'SUM', + // { dataeaseName, aggregation } + cfg: [] }, totalSort: 'none', // asc,desc totalSortField: '' diff --git a/core/frontend/src/views/chart/chart/table/table-info.js b/core/frontend/src/views/chart/chart/table/table-info.js index 49da1f9aa7..aa338ae9b7 100644 --- a/core/frontend/src/views/chart/chart/table/table-info.js +++ b/core/frontend/src/views/chart/chart/table/table-info.js @@ -3,6 +3,7 @@ import { getCustomTheme, getSize } from '@/views/chart/chart/common/common_table import { DEFAULT_COLOR_CASE, DEFAULT_TOTAL } from '@/views/chart/chart/chart' import { formatterItem, valueFormatter } from '@/views/chart/chart/formatter' import { handleTableEmptyStrategy, hexColorToRGBA } from '@/views/chart/chart/util' +import { maxBy, minBy } from 'lodash' class RowHoverInteraction extends BaseEvent { bindEvents() { @@ -500,6 +501,25 @@ export function baseTablePivot(s2, container, chart, action, headerAction, table } sortParams.push(sort) } + // 自定义总计小计 + const totals = [ + totalCfg.row.calcTotals, + totalCfg.row.calcSubTotals, + totalCfg.col.calcTotals, + totalCfg.col.calcSubTotals + ] + totals.forEach(total => { + if (total.cfg?.length) { + delete total.aggregation + const totalCfgMap = total.cfg.reduce((p, n) => { + p[n.dataeaseName] = n + return p + }, {}) + total.calcFunc = (query, data) => { + return customCalcFunc(query, data, totalCfgMap) + } + } + }) // 空值处理 const newData = handleTableEmptyStrategy(tableData, chart) // data config @@ -838,3 +858,40 @@ function getFieldValueMap(view) { } return fieldValueMap } + +function customCalcFunc(query, data, totalCfgMap) { + if (!data?.length) { + return 0 + } + const aggregation = totalCfgMap[query[EXTRA_FIELD]].aggregation + switch (aggregation) { + case 'SUM': { + return data.reduce((p, n) => { + return p + n[n[EXTRA_FIELD]] + }, 0) + } + case 'AVG': { + const sum = data.reduce((p, n) => { + return p + n[n[EXTRA_FIELD]] + }, 0) + return sum / data.length + } + case 'MIN': { + const result = minBy(data, n => { + return n[n[EXTRA_FIELD]] + }) + return result[result[EXTRA_FIELD]] + } + case 'MAX': { + const result = maxBy(data, n => { + return n[n[EXTRA_FIELD]] + }) + return result[result[EXTRA_FIELD]] + } + default: { + return data.reduce((p, n) => { + return p + n[n[EXTRA_FIELD]] + }, 0) + } + } +} diff --git a/core/frontend/src/views/chart/components/ChartComponentS2.vue b/core/frontend/src/views/chart/components/ChartComponentS2.vue index 4b4243c187..ba8599f4ac 100644 --- a/core/frontend/src/views/chart/components/ChartComponentS2.vue +++ b/core/frontend/src/views/chart/components/ChartComponentS2.vue @@ -393,6 +393,9 @@ export default { this.initData() this.initTitle() this.calcHeightRightNow((width, height) => { + if (!this.myChart) { + return + } const { width: chartWidth, height: chartHeight } = this.myChart.options if (width !== chartWidth || height !== chartHeight) { this.myChart?.changeSheetSize(width, height) diff --git a/core/frontend/src/views/chart/components/shapeAttr/TotalCfg.vue b/core/frontend/src/views/chart/components/shapeAttr/TotalCfg.vue index 3971f71d36..31d3bc7945 100644 --- a/core/frontend/src/views/chart/components/shapeAttr/TotalCfg.vue +++ b/core/frontend/src/views/chart/components/shapeAttr/TotalCfg.vue @@ -52,20 +52,39 @@ :label="$t('chart.aggregation')" class="form-item" > - + + + + + - - + + + + - + + + + + - - + + + + @@ -209,20 +248,39 @@ :label="$t('chart.aggregation')" class="form-item" > - + + + + + - - + + + + - + + + + + - - + + + + @@ -352,7 +430,23 @@ export default { { name: this.$t('chart.max'), value: 'MAX' }, { name: this.$t('chart.min'), value: 'MIN' } ], - totalSortFields: [] + totalSortFields: [], + rowSubTotalItem: { + dataeaseName: '', + aggregation: '' + }, + rowTotalItem: { + dataeaseName: '', + aggregation: '' + }, + colSubTotalItem: { + dataeaseName: '', + aggregation: '' + }, + colTotalItem: { + dataeaseName: '', + aggregation: '' + } } }, computed: { @@ -430,8 +524,67 @@ export default { this.totalForm.row.totalSortField = '' this.totalForm.col.totalSortField = '' } + let needCompatible = false + if (!this.totalForm.row.calcTotals.cfg) { + needCompatible = true + this.$set(this.totalForm.row.calcTotals, 'cfg', []) + this.$set(this.totalForm.row.calcSubTotals, 'cfg', []) + this.$set(this.totalForm.col.calcTotals, 'cfg', []) + this.$set(this.totalForm.col.calcSubTotals, 'cfg', []) + } + const totals = [ + { ...this.totalForm.row.calcTotals }, + { ...this.totalForm.row.calcSubTotals }, + { ...this.totalForm.col.calcTotals }, + { ...this.totalForm.col.calcSubTotals } + ] + totals.forEach(total => { + // 兼容原有的聚合方式 + const aggregation = needCompatible ? total.aggregation : 'SUM' + this.setupTotalCfg(total.cfg, this.totalSortFields, aggregation) + }) + const totalTupleArr = [ + [this.rowTotalItem, this.totalForm.row.calcTotals.cfg], + [this.rowSubTotalItem, this.totalForm.row.calcSubTotals.cfg], + [this.colTotalItem, this.totalForm.col.calcTotals.cfg], + [this.colSubTotalItem, this.totalForm.col.calcSubTotals.cfg] + ] + totalTupleArr.forEach(tuple => { + const [total, totalCfg] = tuple + if (!totalCfg.length) { + total.dataeaseName = '' + total.aggregation = '' + return + } + const totalIndex = totalCfg.findIndex(i => i.dataeaseName === total.dataeaseName) + if (totalIndex !== -1) { + total.aggregation = totalCfg[totalIndex].aggregation + } else { + total.dataeaseName = totalCfg[0].dataeaseName + total.aggregation = totalCfg[0].aggregation + } + }) } }, + changeTotal(totalItem, totals) { + for (let i = 0; i < totals.length; i++) { + const item = totals[i] + if (item.dataeaseName === totalItem.dataeaseName) { + totalItem.aggregation = item.aggregation + return + } + } + }, + changeTotalAggr(totalItem, totals, colOrNum) { + for (let i = 0; i < totals.length; i++) { + const item = totals[i] + if (item.dataeaseName === totalItem.dataeaseName) { + item.aggregation = totalItem.aggregation + break + } + } + this.changeTotalCfg(colOrNum) + }, changeTotalCfg(modifyName) { this.totalForm['modifyName'] = modifyName this.$emit('onTotalCfgChange', this.totalForm) @@ -448,6 +601,32 @@ export default { sortFieldList.push(ele.dataeaseName) }) return sortFieldList.indexOf(field) === -1 + }, + setupTotalCfg(totalCfg, axis, aggregation) { + if (!totalCfg.length) { + axis.forEach(i => { + totalCfg.push({ + dataeaseName: i.dataeaseName, + aggregation + }) + }) + return + } + if (!axis.length) { + totalCfg.splice(0, totalCfg.length) + return + } + const cfgMap = totalCfg.reduce((p, n) => { + p[n.dataeaseName] = n + return p + }, {}) + totalCfg.splice(0, totalCfg.length) + axis.forEach(i => { + totalCfg.push({ + dataeaseName: i.dataeaseName, + aggregation: cfgMap[i.dataeaseName] ? cfgMap[i.dataeaseName].aggregation : 'SUM' + }) + }) } } }