feat(图表): 明细表支持合并单元格 #8830

This commit is contained in:
wisonic 2024-10-31 21:44:49 +08:00
parent 6f54389797
commit 79932bfa9b
8 changed files with 91 additions and 6 deletions

View File

@ -1880,7 +1880,8 @@ export default {
zoom_level: '縮放等級', zoom_level: '縮放等級',
central_point: '中心點', central_point: '中心點',
full_display: '全量顯示', full_display: '全量顯示',
show_hover_style: '顯示鼠標懸浮樣式' show_hover_style: '顯示鼠標懸浮樣式',
merge_cells: '合並單元格'
}, },
dataset: { dataset: {
scope_edit: '僅編輯時生效', scope_edit: '僅編輯時生效',

View File

@ -1880,7 +1880,8 @@ export default {
zoom_level: '缩放等级', zoom_level: '缩放等级',
central_point: '中心点', central_point: '中心点',
full_display: '全量显示', full_display: '全量显示',
show_hover_style: '显示鼠标悬浮样式' show_hover_style: '显示鼠标悬浮样式',
merge_cells: '合并单元格'
}, },
dataset: { dataset: {
scope_edit: '仅编辑时生效', scope_edit: '仅编辑时生效',

View File

@ -459,6 +459,10 @@ declare interface ChartTableCellAttr {
* 冻结行 * 冻结行
*/ */
tableRowFreezeHead: number tableRowFreezeHead: number
/**
* 合并单元格
*/
mergeCells: boolean
} }
/** /**

View File

@ -65,6 +65,7 @@ const changeTableCell = prop => {
const init = () => { const init = () => {
const tableCell = props.chart?.customAttr?.tableCell const tableCell = props.chart?.customAttr?.tableCell
if (tableCell) { if (tableCell) {
tableCell.mergeCells = tableCell.mergeCells === undefined ? false : tableCell.mergeCells
state.tableCellForm = defaultsDeep(cloneDeep(tableCell), cloneDeep(DEFAULT_TABLE_CELL)) state.tableCellForm = defaultsDeep(cloneDeep(tableCell), cloneDeep(DEFAULT_TABLE_CELL))
const alpha = props.chart.customAttr.basicStyle.alpha const alpha = props.chart.customAttr.basicStyle.alpha
if (!isAlphaColor(state.tableCellForm.tableItemBgColor)) { if (!isAlphaColor(state.tableCellForm.tableItemBgColor)) {
@ -364,6 +365,20 @@ onMounted(() => {
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-form-item
class="form-item"
:class="'form-item-' + themes"
v-if="showProperty('mergeCells')"
>
<el-checkbox
size="small"
:effect="themes"
v-model="state.tableCellForm.mergeCells"
@change="changeTableCell('mergeCells')"
>
{{ t('chart.merge_cells') }}
</el-checkbox>
</el-form-item>
<el-form-item <el-form-item
class="form-item" class="form-item"
:class="'form-item-' + themes" :class="'form-item-' + themes"

View File

@ -432,7 +432,8 @@ export const DEFAULT_TABLE_CELL: ChartTableCellAttr = {
isBolder: false, isBolder: false,
tableFreeze: false, tableFreeze: false,
tableColumnFreezeHead: 0, tableColumnFreezeHead: 0,
tableRowFreezeHead: 0 tableRowFreezeHead: 0,
mergeCells: true
} }
export const DEFAULT_TITLE_STYLE: ChartTextStyle = { export const DEFAULT_TITLE_STYLE: ChartTextStyle = {
show: true, show: true,

View File

@ -66,7 +66,8 @@ export class TableInfo extends S2ChartView<TableSheet> {
...TABLE_EDITOR_PROPERTY_INNER['table-cell-selector'], ...TABLE_EDITOR_PROPERTY_INNER['table-cell-selector'],
'tableFreeze', 'tableFreeze',
'tableColumnFreezeHead', 'tableColumnFreezeHead',
'tableRowFreezeHead' 'tableRowFreezeHead',
'mergeCells'
] ]
} }
axis: AxisType[] = ['xAxis', 'filter', 'drill'] axis: AxisType[] = ['xAxis', 'filter', 'drill']
@ -197,6 +198,8 @@ export class TableInfo extends S2ChartView<TableSheet> {
} }
// tooltip // tooltip
this.configTooltip(chart, s2Options) this.configTooltip(chart, s2Options)
// 合并单元格
this.configMergeCells(chart, s2Options)
// 隐藏表头保留顶部的分割线, 禁用表头横向 resize // 隐藏表头保留顶部的分割线, 禁用表头横向 resize
if (tableHeader.showTableHeader === false) { if (tableHeader.showTableHeader === false) {
s2Options.style.colCfg.height = 1 s2Options.style.colCfg.height = 1
@ -312,7 +315,6 @@ export class TableInfo extends S2ChartView<TableSheet> {
// theme // theme
const customTheme = this.configTheme(chart) const customTheme = this.configTheme(chart)
newChart.setThemeCfg({ theme: customTheme }) newChart.setThemeCfg({ theme: customTheme })
return newChart return newChart
} }

View File

@ -1,3 +1,4 @@
/* eslint-disable prettier/prettier */
import { import {
copyString, copyString,
hexColorToRGBA, hexColorToRGBA,
@ -36,7 +37,6 @@ import TableTooltip from '@/views/chart/components/editor/common/TableTooltip.vu
import Exceljs from 'exceljs' import Exceljs from 'exceljs'
import { saveAs } from 'file-saver' import { saveAs } from 'file-saver'
import { ElMessage } from 'element-plus-secondary' import { ElMessage } from 'element-plus-secondary'
import { matrix } from 'mathjs'
export function getCustomTheme(chart: Chart): S2Theme { export function getCustomTheme(chart: Chart): S2Theme {
const headerColor = hexColorToRGBA( const headerColor = hexColorToRGBA(
@ -1408,3 +1408,59 @@ export async function exportPivotExcel(instance: PivotSheet, chart: ChartObj) {
exportTreePivot(instance, chart) exportTreePivot(instance, chart)
} }
} }
export function configMergeCells(chart: Chart, options: S2Options) {
const { mergeCells } = parseJson(chart.customAttr).tableCell
const { showIndex } = parseJson(chart.customAttr).tableHeader
if (mergeCells) {
const xAxis = chart.xAxis
const quotaIndex = xAxis.findIndex(axis => axis.groupType === 'q')
const data = chart.data?.tableRow
if (quotaIndex <= 0 || !data?.length) {
return
}
const mergedColInfo: number[][][] = [[[0, data.length - 1]]]
const mergedCellsInfo = []
const axisToMerge = xAxis.filter((a, i) => a.hide !== true && i < quotaIndex)
axisToMerge.forEach((a, i) => {
const preMergedColInfo = mergedColInfo[i]
const curMergedColInfo = []
mergedColInfo.push(curMergedColInfo)
preMergedColInfo.forEach(range => {
const [start, end] = range
let lastVal = data[start][a.dataeaseName]
let lastIndex = start
for (let index = start; index <= end; index++) {
const curVal = data[index][a.dataeaseName]
if (curVal !== lastVal || index === end) {
const curRange = index - lastIndex
if (curRange > 1 ||
(index === end && curRange === 1 && lastVal === curVal)) {
const tmpMergeCells = []
const textIndex = curRange % 2 === 1 ? (curRange - 1) / 2 : curRange / 2 - 1
for (let j = 0; j < curRange; j++) {
tmpMergeCells.push({
colIndex: showIndex ? i + 1 : i,
rowIndex: lastIndex + j,
showText: j === textIndex
})
}
if (index === end) {
tmpMergeCells.push({
colIndex: showIndex ? i + 1 : i,
rowIndex: index,
showText: false
})
}
mergedCellsInfo.push(tmpMergeCells)
curMergedColInfo.push([lastIndex, index === end ? index : index - 1])
}
lastVal = curVal
lastIndex = index
}
}
})
})
options.mergedCellsInfo = mergedCellsInfo
}
}

View File

@ -15,6 +15,7 @@ import {
} from '@antv/s2' } from '@antv/s2'
import { import {
configHeaderInteraction, configHeaderInteraction,
configMergeCells,
configTooltip, configTooltip,
getConditions, getConditions,
getCustomTheme, getCustomTheme,
@ -63,6 +64,10 @@ export abstract class S2ChartView<P extends SpreadSheet> extends AntVAbstractCha
return getConditions(chart) return getConditions(chart)
} }
protected configMergeCells(chart: Chart, option: S2Options) {
configMergeCells(chart, option)
}
protected showTooltip(s2Instance: P, event, metaConfig: Meta[]) { protected showTooltip(s2Instance: P, event, metaConfig: Meta[]) {
const cell = s2Instance.getCell(event.target) const cell = s2Instance.getCell(event.target)
const meta = cell.getMeta() const meta = cell.getMeta()