feat(视图): 汇总表支持显示总计 #9589

This commit is contained in:
wisonic 2024-07-08 19:16:27 +08:00
parent 0e0def7309
commit 4bd3dbcd75
8 changed files with 138 additions and 17 deletions

View File

@ -733,6 +733,8 @@ export default {
table_show_col_tooltip: '开启列头提示',
table_show_cell_tooltip: '开启单元格提示',
table_show_header_tooltip: '开启表头提示',
table_show_summary: '显示总计',
table_summary_label: '总计标签',
stripe: '斑马纹',
start_angle: '起始角度',
end_angle: '结束角度',

View File

@ -256,6 +256,14 @@ declare interface ChartBasicStyle {
* 对称柱状图方向
*/
layout?: 'horizontal' | 'vertical'
/**
* 汇总表显示总计
*/
showSummary: boolean
/**
* 汇总表总计标签
*/
summaryLabel: string
}
/**
* 表头属性

View File

@ -2,8 +2,9 @@
import { SpreadSheet, Node } from '@antv/s2'
import { PropType } from 'vue'
import { useI18n } from '@/hooks/web/useI18n'
import { S2Event } from '@antv/s2'
import { S2Event, SortFuncParam } from '@antv/s2'
import { SortUp, SortDown, Sort } from '@element-plus/icons-vue'
import { cloneDeep } from 'lodash-es'
const { t } = useI18n()
const props = defineProps({
@ -12,15 +13,45 @@ const props = defineProps({
required: true
},
meta: {
type: Object as PropType<Node>
type: Object as PropType<Node>,
required: true
}
})
const sort = type => {
const sortFunc = (sortParams: SortFuncParam) => {
if (!sortParams.sortMethod) {
return sortParams.data
}
const data = cloneDeep(sortParams.data)
return data.sort((a, b) => {
//
if (a['SUMMARY']) {
return 1
}
const field = sortParams.sortFieldId
const aValue = a[field]
const bValue = b[field]
if (aValue === bValue) {
return 0
}
if (sortParams.sortMethod === 'asc') {
if (typeof aValue === 'number') {
return aValue - bValue
}
return aValue < bValue ? 1 : -1
}
if (typeof aValue === 'number') {
return bValue - aValue
}
return aValue > bValue ? 1 : -1
})
}
const sort = (type?) => {
props.table.updateSortMethodMap(props.meta.field, type, true)
props.table.emit(S2Event.RANGE_SORT, [
{
sortFieldId: props.meta.field,
sortMethod: type
sortMethod: type,
sortFunc
}
])
}

View File

@ -957,6 +957,33 @@ onMounted(() => {
<template #append>%</template>
</el-input>
</el-form-item>
<el-form-item
v-if="showProperty('showSummary')"
class="form-item"
:class="'form-item-' + themes"
>
<el-checkbox
size="small"
:effect="themes"
v-model="state.basicStyleForm.showSummary"
@change="changeBasicStyle('showSummary')"
>
{{ t('chart.table_show_summary') }}
</el-checkbox>
</el-form-item>
<el-form-item
v-if="showProperty('summaryLabel') && state.basicStyleForm.showSummary"
:label="$t('chart.table_summary_label')"
:class="'form-item-' + themes"
class="form-item"
>
<el-input
v-model="state.basicStyleForm.summaryLabel"
type="text"
:max-length="10"
@blur="changeBasicStyle('summaryLabel')"
/>
</el-form-item>
<!--table2 end-->
<!--gauge start-->
<el-form-item

View File

@ -1483,7 +1483,9 @@ export const DEFAULT_BASIC_STYLE: ChartBasicStyle = {
topN: 5,
topNLabel: '其他',
gaugeAxisLine: true,
gaugePercentLabel: true
gaugePercentLabel: true,
showSummary: false,
summaryLabel: '总计'
}
export const BASE_VIEW_CONFIG = {

View File

@ -1,15 +1,11 @@
import { S2ChartView, S2DrawOptions } from '@/views/chart/components/js/panel/types/impl/s2'
import { S2Event, S2Options, TableSheet, TableColCell, ViewMeta, TableDataCell } from '@antv/s2'
import { parseJson } from '@/views/chart/components/js/util'
import { formatterItem, valueFormatter } from '@/views/chart/components/js/formatter'
import {
copyContent,
getCurrentField,
SortTooltip
} from '@/views/chart/components/js/panel/common/common_table'
import { TABLE_EDITOR_PROPERTY, TABLE_EDITOR_PROPERTY_INNER } from './common'
import { useI18n } from '@/hooks/web/useI18n'
import { formatterItem, valueFormatter } from '@/views/chart/components/js/formatter'
import { copyContent, SortTooltip } from '@/views/chart/components/js/panel/common/common_table'
import { S2ChartView, S2DrawOptions } from '@/views/chart/components/js/panel/types/impl/s2'
import { parseJson } from '@/views/chart/components/js/util'
import { S2Event, S2Options, TableColCell, TableDataCell, TableSheet, ViewMeta } from '@antv/s2'
import { isNumber } from 'lodash-es'
import { TABLE_EDITOR_PROPERTY, TABLE_EDITOR_PROPERTY_INNER } from './common'
const { t } = useI18n()
/**
@ -17,12 +13,17 @@ const { t } = useI18n()
*/
export class TableNormal extends S2ChartView<TableSheet> {
properties = TABLE_EDITOR_PROPERTY
propertyInner = {
propertyInner: EditorPropertyInner = {
...TABLE_EDITOR_PROPERTY_INNER,
'table-header-selector': [
...TABLE_EDITOR_PROPERTY_INNER['table-header-selector'],
'tableHeaderSort',
'showTableHeader'
],
'basic-style-selector': [
...TABLE_EDITOR_PROPERTY_INNER['basic-style-selector'],
'showSummary',
'summaryLabel'
]
}
axis: AxisType[] = ['xAxis', 'yAxis', 'drill', 'filter']
@ -160,6 +161,43 @@ export class TableNormal extends S2ChartView<TableSheet> {
// header interaction
this.configHeaderInteraction(chart, s2Options)
}
// 总计
if (customAttr.basicStyle.showSummary) {
// 设置汇总行高度和表头一致
const heightByField = {}
heightByField[newData.length] = customAttr.tableHeader.tableTitleHeight
s2Options.style.rowCfg = { heightByField }
// 计算汇总加入到数据里冻结最后一行
s2Options.frozenTrailingRowCount = 1
const yAxis = chart.yAxis
const xAxis = chart.xAxis
const summaryObj = newData.reduce(
(p, n) => {
yAxis.forEach(axis => {
p[axis.dataeaseName] = (n[axis.dataeaseName] || 0) + (p[axis.dataeaseName] || 0)
})
return p
},
{ SUMMARY: true }
)
newData.push(summaryObj)
s2Options.dataCell = viewMeta => {
if (viewMeta.rowIndex !== newData.length - 1) {
return new TableDataCell(viewMeta, viewMeta.spreadsheet)
}
if (viewMeta.colIndex === 0) {
if (customAttr.tableHeader.showIndex) {
viewMeta.fieldValue = customAttr.basicStyle.summaryLabel ?? '总计'
} else {
if (xAxis.length) {
viewMeta.fieldValue = customAttr.basicStyle.summaryLabel ?? '总计'
}
}
}
return new SummaryCell(viewMeta, viewMeta.spreadsheet)
}
}
// 开始渲染
const newChart = new TableSheet(containerDom, s2DataConfig, s2Options)
@ -211,3 +249,13 @@ export class TableNormal extends S2ChartView<TableSheet> {
super('table-normal', [])
}
}
class SummaryCell extends TableDataCell {
getTextStyle() {
return this.theme.colCell.bolderText
}
getBackgroundColor() {
const { backgroundColor, backgroundColorOpacity } = this.theme.colCell.cell
return { backgroundColor, backgroundColorOpacity }
}
}

View File

@ -69,6 +69,10 @@ export abstract class S2ChartView<P extends SpreadSheet> extends AntVAbstractCha
let field
switch (cell.cellType) {
case 'dataCell':
if (meta.valueField === SERIES_NUMBER_FIELD) {
content = meta.fieldValue
break
}
field = find(metaConfig, item => item.field === meta.valueField)
if (meta.fieldValue === 0) {
content = '0'

View File

@ -116,7 +116,6 @@ const calcData = (view: Chart, callback, resetPageInfo = true) => {
} else {
delete view.chartExtRequest.pageSize
}
console.log(view)
if (view.tableId || view['dataFrom'] === 'template') {
isError.value = false
const v = JSON.parse(JSON.stringify(view))