diff --git a/packages/s2-core/src/common/interface/basic.ts b/packages/s2-core/src/common/interface/basic.ts index 62d5c0a57f..71bf3d0032 100644 --- a/packages/s2-core/src/common/interface/basic.ts +++ b/packages/s2-core/src/common/interface/basic.ts @@ -106,6 +106,7 @@ export interface Fields { export interface ColumnNode { key: string; children?: Columns; + rowSpan?: number; } export interface TotalsStatus { diff --git a/packages/s2-core/src/facet/table-facet.ts b/packages/s2-core/src/facet/table-facet.ts index 19e57c7b76..099ce13004 100644 --- a/packages/s2-core/src/facet/table-facet.ts +++ b/packages/s2-core/src/facet/table-facet.ts @@ -4,8 +4,10 @@ import { isBoolean, isNil, isNumber, + isString, last, maxBy, + omit, set, values, } from 'lodash'; @@ -23,6 +25,7 @@ import { import { FrozenCellGroupMap } from '../common/constant/frozen'; import { DebuggerUtil } from '../common/debug'; import type { + Columns, FilterParam, LayoutResult, ResizeInteractionOptions, @@ -289,11 +292,68 @@ export class TableFacet extends BaseFacet { return cellCfg?.width; } + /** 扁平化树形 columns */ + private flattenTree(tree: Columns): Columns { + return tree.reduce((prev, curr) => { + if (isString(curr)) { + prev = prev.concat(curr); + } else { + prev = prev.concat(omit(curr, 'children')); + if (curr.children?.length) { + prev = prev.concat(this.flattenTree(curr.children)); + } + } + return prev; + }, []); + } + + /** 当前节点所在列是否配置了 rowSpan */ + private hasRowSpanInBranch(tree: Columns, field: string): boolean { + const columns = tree.map((item) => this.flattenTree([item])); + const branch = columns.find((items) => { + return items.some((item) => { + if (isString(item)) { + return item === field; + } + if (item.key === field) { + return true; + } + return false; + }); + }); + return branch?.some((item) => !isString(item) && Boolean(item?.rowSpan)); + } + + /** 当前节点的 rowSpan */ + private findRowSpanInCurrentNode( + columns: Columns, + field: string, + ): number | void { + const flattedColumns = this.flattenTree(columns); + const column = flattedColumns.find((item) => { + return !isString(item) && item.key === field; + }); + return !isString(column) && column.rowSpan; + } + + /** TIP: 获取列头 Node 高度 */ private getColNodeHeight(col: Node, totalHeight?: number) { - const { colCfg } = this.cfg; + const { colCfg, columns } = this.cfg; + // 明细表所有列节点高度保持一致 const userDragHeight = values(colCfg?.heightByField)[0]; + + const hasRowSpanInBranch = this.hasRowSpanInBranch(columns, col.field); + const currentRowSpan = this.findRowSpanInCurrentNode(columns, col.field); + + /** 用户拖拽高度 > 配置高度 */ const height = userDragHeight || colCfg?.height; + + // 如果当前列任意 leaf 设置了 rowSpan, 按照 rowSpan 划分列头单元格高度 + if (hasRowSpanInBranch) { + return height * (currentRowSpan || 1); + } + if (!totalHeight) { return height; } diff --git a/s2-site/docs/api/general/S2DataConfig.en.md b/s2-site/docs/api/general/S2DataConfig.en.md index f477162b0b..df8f4f8ff9 100644 --- a/s2-site/docs/api/general/S2DataConfig.en.md +++ b/s2-site/docs/api/general/S2DataConfig.en.md @@ -116,5 +116,6 @@ Function description: used to support custom data cell rendering of multiple ind | 属性名称 | 说明 | 类型 | 默认值 | 必选 | | ------- | ---------| -------| ------|------| -| name | 列字段 id 或分组 id | string | | ✓ | +| key | 列字段 id 或分组 id | string | | ✓ | +| rowSpan | 合并单元格行数,配置后则优先按照 rowSpan 规划列头单元格高度 | number | | | | children | 分组下面的子级 | Array\ | | | diff --git a/s2-site/docs/api/general/S2DataConfig.zh.md b/s2-site/docs/api/general/S2DataConfig.zh.md index f06b8effbe..8d6740f28e 100644 --- a/s2-site/docs/api/general/S2DataConfig.zh.md +++ b/s2-site/docs/api/general/S2DataConfig.zh.md @@ -115,4 +115,5 @@ object **必选**,_default:null_ | 属性名称 | 说明 | 类型 | 默认值 | 必选 | | ------- | ---------| -------| ------|------| | key | 列字段 id 或分组 id | string | | ✓ | +| rowSpan | 合并单元格行数,配置后则优先按照 rowSpan 规划列头单元格高度 | number | | | | children | 分组下面的子级 | `Array` | | |