import React from "react"; import { TableAddon, TableColumn } from "../TableProps"; export interface TableHeaderGroup { /** * 分组头标识 */ key: string; /** * 分组头内容 */ title?: React.ReactNode; /** * 对齐规则,左中右 * @default "left" * @since 2.6.0 */ align?: TableColumn["align"]; /** * 子分组或 Column */ children?: string[]; } export interface GroupableOptions { /** * 分组表头配置 */ headerGroups: TableHeaderGroup[]; } export interface TableGroupableHeadItem extends TableHeaderGroup { order?: number; level?: number; colSpan?: number; rowSpan?: number; isLeaf?: boolean; } function getRows(groups: TableHeaderGroup[], columns: TableColumn[]) { const groupMap: Record = {}; const parentMap: Record = {}; const headIndexMap: Record = {}; groups.forEach(({ key, title, align, children }) => { groupMap[key] = { key, title, align, children }; children.forEach(child => { parentMap[child] = key; }); }); columns.forEach(({ key }, index) => { headIndexMap[key] = index; }); // 获取各分组 [层级,包含列数,排序] const traverse = (node: string): [number, number, number] => { if (groupMap[node] && groupMap[node].children) { let level = -1; let colSpan = 0; let minIndex = columns.length; groupMap[node].children.forEach(child => { const [childLevel, childColSpan, childIndex] = traverse(child); level = Math.max(childLevel, level); colSpan += childColSpan; minIndex = Math.min(minIndex, childIndex); }); return [level + 1, colSpan, minIndex]; } // 原始列 return [0, 1, headIndexMap[node]]; }; const rows: TableGroupableHeadItem[][] = []; // 分组头 groups.forEach(({ key }) => { const [level, colSpan, order] = traverse(key); groupMap[key] = { ...groupMap[key], order, level, colSpan, }; if (!rows[level]) { rows[level] = [groupMap[key]]; } else { rows[level].push(groupMap[key]); } }); const headRowSpanMap: Record = {}; // 原始头 columns.forEach(({ key }) => { const level = parentMap[key] ? groupMap[parentMap[key]].level - 1 : (rows.length || 1) - 1; const head = { key, isLeaf: true, order: headIndexMap[key], rowSpan: level + 1, }; if (!rows[level]) { rows[level] = [head]; } else { rows[level].push(head); } headRowSpanMap[key] = head.rowSpan; }); // 排序 return [ rows.map(row => row.sort((a, b) => a.order - b.order)).reverse(), headRowSpanMap, ]; } export function groupable({ headerGroups }: GroupableOptions): TableAddon { let rows; let headRowSpanMap; return { getInfo: () => ({ name: "groupable" }), onInjectProps: props => { [rows, headRowSpanMap] = getRows(headerGroups, props.columns); return { ...props, headerRows: rows }; }, onInjectColumn: previous => ( record, rowKey, recordIndex, column, columnIndex ) => { const { props, ...result } = previous( record, rowKey, recordIndex, column, columnIndex ); if (recordIndex === -1) { return { ...result, props: { ...props, rowSpan: headRowSpanMap ? headRowSpanMap[column.key] : undefined, }, }; } return { ...result, props }; }, }; }