feat(图表): 明细表支持总计 #12650

This commit is contained in:
jianneng-fit2cloud 2024-11-26 13:31:59 +08:00
parent 7a87a511ce
commit 804e6e93ae
3 changed files with 108 additions and 65 deletions

View File

@ -20,7 +20,9 @@ import {
CustomTableColCell,
getRowIndex,
calculateHeaderHeight,
SortTooltip
SortTooltip,
configSummaryRow,
summaryRowStyle
} from '@/views/chart/components/js/panel/common/common_table'
const { t } = useI18n()
@ -68,7 +70,9 @@ export class TableInfo extends S2ChartView<TableSheet> {
'alpha',
'tablePageMode',
'showHoverStyle',
'autoWrap'
'autoWrap',
'showSummary',
'summaryLabel'
],
'table-cell-selector': [
...TABLE_EDITOR_PROPERTY_INNER['table-cell-selector'],
@ -240,8 +244,12 @@ export class TableInfo extends S2ChartView<TableSheet> {
return new CustomTableColCell(node, sheet, config)
}
}
// 总计
configSummaryRow(chart, s2Options, newData, tableHeader, basicStyle, basicStyle.showSummary)
// 开始渲染
const newChart = new TableSheet(containerDom, s2DataConfig, s2Options)
// 总计紧贴在单元格后面
summaryRowStyle(newChart, newData, tableCell, tableHeader, basicStyle.showSummary)
// 开启自动换行
if (basicStyle.autoWrap) {
// 调整表头宽度时计算表头高度

View File

@ -1,9 +1,10 @@
import { useI18n } from '@/hooks/web/useI18n'
import { formatterItem, valueFormatter } from '@/views/chart/components/js/formatter'
import {
configSummaryRow,
copyContent,
CustomDataCell,
SortTooltip
SortTooltip,
summaryRowStyle
} 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'
@ -189,56 +190,11 @@ export class TableNormal extends S2ChartView<TableSheet> {
}
// 总计
if (basicStyle.showSummary) {
// 设置汇总行高度和表头一致
const heightByField = {}
heightByField[newData.length] = 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] =
(parseFloat(n[axis.dataeaseName]) || 0) + (parseFloat(p[axis.dataeaseName]) || 0)
})
return p
},
{ SUMMARY: true }
)
newData.push(summaryObj)
s2Options.dataCell = viewMeta => {
if (viewMeta.rowIndex !== newData.length - 1) {
return new CustomDataCell(viewMeta, viewMeta.spreadsheet)
}
if (viewMeta.colIndex === 0) {
if (tableHeader.showIndex) {
viewMeta.fieldValue = basicStyle.summaryLabel ?? '总计'
} else {
if (xAxis.length) {
viewMeta.fieldValue = basicStyle.summaryLabel ?? '总计'
}
}
}
return new SummaryCell(viewMeta, viewMeta.spreadsheet)
}
}
configSummaryRow(chart, s2Options, newData, tableHeader, basicStyle, basicStyle.showSummary)
// 开始渲染
const newChart = new TableSheet(containerDom, s2DataConfig, s2Options)
// 总计紧贴在单元格后面
if (basicStyle.showSummary) {
newChart.on(S2Event.LAYOUT_BEFORE_RENDER, () => {
const totalHeight =
tableHeader.tableTitleHeight * 2 + tableCell.tableItemHeight * (newData.length - 1)
if (totalHeight < newChart.options.height) {
// 6 是阴影高度
newChart.options.height =
totalHeight < newChart.options.height - 6 ? totalHeight + 6 : totalHeight
}
})
}
summaryRowStyle(newChart, newData, tableCell, tableHeader, basicStyle.showSummary)
// 自适应铺满
if (basicStyle.tableColumnMode === 'adapt') {
newChart.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, () => {
@ -334,15 +290,3 @@ export class TableNormal extends S2ChartView<TableSheet> {
super('table-normal', [])
}
}
class SummaryCell extends CustomDataCell {
getTextStyle() {
const textStyle = cloneDeep(this.theme.colCell.bolderText)
textStyle.textAlign = this.theme.dataCell.text.textAlign
return textStyle
}
getBackgroundColor() {
const { backgroundColor, backgroundColorOpacity } = this.theme.colCell.cell
return { backgroundColor, backgroundColorOpacity }
}
}

View File

@ -28,7 +28,7 @@ import {
type PivotSheet,
renderPolygon,
renderText,
S2DataConfig,
S2DataConfig, S2Event,
S2Options,
S2Theme,
SERIES_NUMBER_FIELD,
@ -40,13 +40,15 @@ import {
TableDataCell,
updateShapeAttr,
ViewMeta
} from '@antv/s2'
} from "@antv/s2";
import { cloneDeep, filter, find, intersection, keys, merge, repeat } from 'lodash-es'
import { createVNode, render } from 'vue'
import TableTooltip from '@/views/chart/components/editor/common/TableTooltip.vue'
import Exceljs from 'exceljs'
import { saveAs } from 'file-saver'
import { ElMessage } from 'element-plus-secondary'
import { useI18n } from '@/hooks/web/useI18n'
const { t } = useI18n()
export function getCustomTheme(chart: Chart): S2Theme {
const headerColor = hexColorToRGBA(
@ -1748,3 +1750,92 @@ const getWrapTextHeight = (wrapText, textStyle, spreadsheet, maxLines) => {
const lines = wrapText.split('\n').length
return Math.min(lines, maxLines) * maxHeight
}
/**
* 设置汇总行
* @param chart
* @param s2Options
* @param newData
* @param tableHeader
* @param basicStyle
* @param showSummary
*/
export const configSummaryRow = (chart, s2Options, newData, tableHeader, basicStyle, showSummary) =>{
if (!showSummary) return
// 设置汇总行高度和表头一致
const heightByField = {}
heightByField[newData.length] = tableHeader.tableTitleHeight
s2Options.style.rowCfg = { heightByField }
// 计算汇总加入到数据里冻结最后一行
s2Options.frozenTrailingRowCount = 1
const yAxis = chart.yAxis
const xAxis = chart.xAxis
const summaryObj = newData.reduce(
(p, n) => {
if (chart.type === 'table-info') {
xAxis
.filter(axis => [2, 3, 4].includes(axis.deType))
.forEach(axis => {
p[axis.dataeaseName] =
(parseFloat(n[axis.dataeaseName]) || 0) + (parseFloat(p[axis.dataeaseName]) || 0)
})
} else {
yAxis.forEach(axis => {
p[axis.dataeaseName] =
(parseFloat(n[axis.dataeaseName]) || 0) + (parseFloat(p[axis.dataeaseName]) || 0)
})
}
return p
},
{ SUMMARY: true }
)
newData.push(summaryObj)
s2Options.dataCell = viewMeta => {
if (viewMeta.rowIndex !== newData.length - 1) {
return new CustomDataCell(viewMeta, viewMeta.spreadsheet)
}
if (viewMeta.colIndex === 0) {
if (tableHeader.showIndex) {
viewMeta.fieldValue = basicStyle.summaryLabel ?? t('chart.total_show')
} else {
if (xAxis.length) {
viewMeta.fieldValue = basicStyle.summaryLabel ?? t('chart.total_show')
}
}
}
return new SummaryCell(viewMeta, viewMeta.spreadsheet)
}
}
/**
* 汇总行样式,紧贴在单元格后面
* @param newChart
* @param newData
* @param tableCell
* @param tableHeader
* @param showSummary
*/
export const summaryRowStyle = (newChart, newData, tableCell, tableHeader, showSummary) => {
if (!showSummary) return
newChart.on(S2Event.LAYOUT_BEFORE_RENDER, () => {
const totalHeight =
tableHeader.tableTitleHeight * 2 + tableCell.tableItemHeight * (newData.length - 1)
if (totalHeight < newChart.options.height) {
// 6 是阴影高度
newChart.options.height =
totalHeight < newChart.options.height - 6 ? totalHeight + 6 : totalHeight
}
})
}
export class SummaryCell extends CustomDataCell {
getTextStyle() {
const textStyle = cloneDeep(this.theme.colCell.bolderText)
textStyle.textAlign = this.theme.dataCell.text.textAlign
return textStyle
}
getBackgroundColor() {
const { backgroundColor, backgroundColorOpacity } = this.theme.colCell.cell
return { backgroundColor, backgroundColorOpacity }
}
}