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'
+ })
+ })
}
}
}