import { Store } from '@/lib/store'; import { Column, GridProp, GroupColumn, IndexColumn, IndexColumnWithoutIndexStatus, SingleColumn, } from '@/lib/types'; import { omit, reduce, sortBy, values } from 'lodash'; import { calculateAllColumnLeftAndIndex } from '@/lib/calculate/column'; import { GROUP_NONE, ORDER_COLUMN_KEY, SELECTION_COLUMN_KEY } from '@/lib/constants/filler'; import { COLUMN_MAX_WIDTH, COLUMN_MIN_WIDTH, ORDER_COLUMN_WIDTH, SELECTION_COLUMN_WIDTH, } from '@/lib/constants/dom-fixed'; import { GroupPin } from '@/lib/types/group'; import { LayoutOperator } from '@/lib/operator/LayoutOperator'; import { RowSelectionOperator } from '@/lib/operator/RowSelectionOperator'; import { EditOperator } from '@/lib/operator/EditOperator'; import { RowDataCalculator } from '@/lib/operator/RowDataCalculator'; import { RowModifyInfo } from '@/lib/types/api'; import { getCurrentRowData } from '@/lib/calculate/data'; const FEATURE_FIELDS = [ORDER_COLUMN_KEY, SELECTION_COLUMN_KEY]; export class StructureCalculator { private readonly store: Store; private readonly layoutOperator: LayoutOperator; private readonly rowSelectionOperator: RowSelectionOperator; private readonly editOperator: EditOperator; private readonly rowDataCalculator: RowDataCalculator; constructor( store: Store, layoutOperator: LayoutOperator, rowSelectionOperator: RowSelectionOperator, editOperator: EditOperator, rowDataCalculator: RowDataCalculator, ) { this.store = store; this.layoutOperator = layoutOperator; this.rowSelectionOperator = rowSelectionOperator; this.editOperator = editOperator; this.rowDataCalculator = rowDataCalculator; } public getData() { const data2D = this.store.state.index.data2D; const rowIndex2Id = this.store.state.index.rowIndex2Id; const columnId2Field = this.store.state.index.columnId2Field; const pushNode = (result, rowId) => { const data = this.store.state.featureConfig.treeData.active ? omit(getCurrentRowData(data2D[rowId], columnId2Field), [ this.store.state.featureConfig.treeData.childrenKey, ]) : getCurrentRowData(data2D[rowId], columnId2Field); result.push(data); }; return reduce( rowIndex2Id, (result, rowId) => { pushNode(result, rowId); return result; }, [], ); } public modifyRows(changes: RowModifyInfo[]) { this.rowDataCalculator.modifyRows(changes); } public removeRows(rowIds: string[]) { this.rowDataCalculator.removeRows(rowIds); this.layoutOperator.flushBodyView(); } public resetColumnWidth(columnRecord: Record) { return (id: string, changeWidth: number) => { const targetWidth = columnRecord[id].width + changeWidth; if (targetWidth < COLUMN_MIN_WIDTH || targetWidth > COLUMN_MAX_WIDTH) { return null; } columnRecord[id].width = columnRecord[id].width + changeWidth; const sortedColumns = sortBy(values(columnRecord), 'index'); return calculateAllColumnLeftAndIndex(sortedColumns); }; } public getAllColumnsData = (columns: GridProp['columns'], defaultColumnWidth: number) => { const rowHeight = this.store.state.config.rowHeight; const { indexColumnRecord, groupLevel } = this.columns2BaseColumnRecord( columns, defaultColumnWidth, rowHeight, ); return { ...calculateAllColumnLeftAndIndex(values(indexColumnRecord)), groupLevel }; }; public initTableStore(props: Readonly) { const { columns, data, defaultColumnConfig, idKey, isTree, childrenKey, expandKey, defaultExpand, } = props; const { columnRecord, columnGroupRecord, columnId2Index, columnId2Field, groupLevel } = this.getAllColumnsData(columns, defaultColumnConfig.width); // 初始化 Column 相关的索引数据 this.store.mutation.setIndexColumnRecord(columnRecord, columnId2Index, columnId2Field); this.store.mutation.setIndexColumnGroup( columnGroupRecord.left, columnGroupRecord.right, columnGroupRecord.scroll, ); const { rowRecord, rowIndex2Id, data2D } = this.rowDataCalculator.flushPropData(data, { idKey, isTree, childrenKey, expandKey, defaultExpand, }); // 设置索引数据、设置热区数据 this.store.mutation.setIndexRow(rowRecord, rowIndex2Id); this.store.mutation.setViewRow(rowRecord, rowIndex2Id); // 设置表格数据 this.store.mutation.setIndexData(data2D); // 计算所有的数据,形成初始化的数据集,计算顺序 原始值填充 > 树结点收集 > calculator > rowSelection | total this.editOperator.flushCalculator(); this.editOperator.flushColumnTotal(); this.rowSelectionOperator.flushRowSelection(); this.layoutOperator.initComponentsSize(groupLevel); } private addOrderColumn = (columns: GridProp['columns']) => { columns.unshift({ title: '', field: ORDER_COLUMN_KEY, width: ORDER_COLUMN_WIDTH, pin: GroupPin.left, }); }; private addSelectionColumn = (columns: GridProp['columns']) => { columns.unshift({ title: '', field: SELECTION_COLUMN_KEY, width: SELECTION_COLUMN_WIDTH, pin: GroupPin.left, }); }; private addFeatureRow(columns: GridProp['columns']) { const { rowIndex, rowSelection } = this.store.state.featureConfig; if (rowIndex.active) { this.addOrderColumn(columns); } if (rowSelection.active) { this.addSelectionColumn(columns); } } private columns2BaseColumnRecord = ( columns: GridProp['columns'], defaultColumnWidth: number, rowHeight: number, ): { indexColumnRecord: Record; groupLevel: number; } => { let indexColumnRecord: Record = {}; let groupLevel = 1; this.addFeatureRow(columns); columns.forEach((itm, idx) => { const currentId = this.getColumnId(itm, idx); if (!(itm as GroupColumn).isGroup) { indexColumnRecord[currentId] = this.column2IndexColumn( itm as SingleColumn, currentId, defaultColumnWidth, rowHeight, 0, GROUP_NONE, '', ); } else { groupLevel = 2; const subCells = (itm as GroupColumn).children.reduce( (acc, subCell, subCellIdx) => { const currentSubCellId = `clm-${idx}_${subCellIdx}`; return { ...acc, [currentSubCellId]: this.column2IndexColumn( subCell as SingleColumn, currentSubCellId, defaultColumnWidth, rowHeight, rowHeight, (itm as GroupColumn).group, (itm as GroupColumn).title, ), }; }, {}, ); indexColumnRecord = { ...indexColumnRecord, ...subCells }; } }); return { indexColumnRecord, groupLevel }; }; private getColumnId = (column: Column, idx: number) => { if (FEATURE_FIELDS.includes((column as any)?.field)) { return (column as any)?.field; } else { return `clm-${idx}`; } }; private column2IndexColumn = ( column: SingleColumn, id: string, defaultWidth: number, height: number, top: number, group: string, groupTitle: string, ): IndexColumnWithoutIndexStatus => ({ ...column, title: column.title, field: column.field, pin: column.pin || GroupPin.scroll, editor: column.editor, width: column.width || defaultWidth, calculator: column.calculator, formatter: column.formatter, id: id, top: top, height: height, index: -1, left: 0, group, groupTitle, }); }