@hzab/edit-table 0.1.9 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.tsx CHANGED
@@ -1,464 +1,489 @@
1
- import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
2
- import { Checkbox, Empty, Spin } from "antd";
3
- import { ReactGrid } from "@silevis/reactgrid";
4
- import TextTemplate from "./Template/TextCellTemplate";
5
- import { antdComponents, customComponents } from "@hzab/form-render";
6
- import { WidthWrapHoc } from "./common/WidthWrapHoc";
7
- import NumberTemplate from "./Template/NumberCellTemplate";
8
- import { ExpandListTemplate } from "./Template/ExpandListTemplate";
9
- import { convertColumnsToRows, flattenColumns, isReactElement } from "./common/utils";
10
- import { childAntdComponent } from "./common/childAntdComponent";
11
- import { GetBaseTemplate } from "./Template/GetBaseTemplate";
12
- import "./index.less";
13
- import "@silevis/reactgrid/styles.css";
14
-
15
- interface CellEditTableProps {
16
- columns: any[];
17
- dataSource: any[];
18
- formulaConfig?: any;
19
- onChange?: (v: any) => void;
20
- reactGridProps?: any;
21
- onEditSubmit?: (v: any) => void;
22
- headerRowHeight?: number;
23
- rowHeight?: number;
24
- reactGridStyle?: any;
25
- className?: string;
26
- Slots?: any;
27
- rowSelection?: any;
28
- rowKey?: string;
29
- query?: any;
30
- loading?: boolean;
31
- isExpand?: boolean;
32
- getList?: () => void;
33
- onRow?: (v: any, ri: number, ci: number) => void;
34
- }
35
-
36
- function CellEditTable(props: CellEditTableProps, ref: any) {
37
- const {
38
- columns,
39
- dataSource,
40
- formulaConfig,
41
- onChange,
42
- reactGridProps = {},
43
- onEditSubmit,
44
- headerRowHeight = 44,
45
- rowHeight = 44,
46
- reactGridStyle,
47
- className,
48
- Slots,
49
- rowSelection,
50
- rowKey = "id",
51
- query,
52
- loading,
53
- isExpand = false,
54
- getList,
55
- onRow,
56
- } = props;
57
-
58
- const [headerList, setHeaderList] = useState<any>([]);
59
- const [rows, setRows] = useState<any>([]);
60
- const initRowsRef = useRef<any>([]);
61
- /** 初始行数据 */
62
- const [tableColumns, setTableColumns] = useState<any>([]);
63
- const [selectedRowKeys, setSelectedRowKeys] = useState<any>([]);
64
- const [newDataSource, setNewDataSource] = useState<any>([]);
65
- const [expandKeys, setExpandKeys] = useState<any>([]);
66
- const [headerCustomTemplate, setHeaderCustomTemplate] = useState<any>([]);
67
- const [highlights, setHighlights] = useState([]);
68
- const highlightsRowIdRef = useRef();
69
-
70
- const gridRef = useRef<any>();
71
- const currentCell = useRef<any>();
72
-
73
- useImperativeHandle(ref, () => {
74
- return {
75
- rows,
76
- };
77
- });
78
- /** 递归处理子节点数据 */
79
- const handleDataSource = (arr, level = 0) => {
80
- arr?.forEach((el) => {
81
- el.level = level + 1;
82
- if (el?.children) {
83
- handleDataSource(el?.children, el.level);
84
- }
85
- });
86
- };
87
- /** 洗数据 */
88
- useEffect(() => {
89
- handleDataSource(dataSource);
90
- setNewDataSource(dataSource);
91
- }, [dataSource]);
92
-
93
- /** 判断当前选中行是否还存在 */
94
- useEffect(() => {
95
- const validRowIds = rows.map((r) => r.rowId);
96
- if (!validRowIds?.includes(highlightsRowIdRef.current)) {
97
- setHighlights([]);
98
- }
99
- }, [rows]);
100
-
101
- /**将数组转为对象 */
102
- const handleArrayToObj = (item) => {
103
- const record = item?.cells?.[0]?.record;
104
- const fieldList = ["_$actions", "rowSelection"];
105
- const obj: any = {
106
- id: item?.rowId,
107
- };
108
- item?.cells?.forEach((el) => {
109
- if (el?.columnId && !fieldList?.includes(el?.columnId)) {
110
- obj[el?.columnId] = el?.text || el?.value || el?.selectedValue || "";
111
- if (el?.type == "Number") {
112
- obj[el?.columnId] = el?.value;
113
- }
114
- }
115
- });
116
-
117
- return {
118
- ...record,
119
- ...obj,
120
- };
121
- };
122
- /** 表头 */
123
- useEffect(() => {
124
- if (Array.isArray(columns) && columns?.length > 0) {
125
- if (isExpand) {
126
- columns.unshift({
127
- type: "ExpandListTemplate",
128
- width: 14,
129
- key: "ExpandListTemplate",
130
- nonEditable: true,
131
- style: rowSelection?.style || {
132
- background: "rgba(128, 128, 128, 0.1)",
133
- },
134
- });
135
- }
136
- if (rowSelection) {
137
- columns.unshift({
138
- type: "rowSelection",
139
- nonEditable: true,
140
- width: rowSelection?.width || 30,
141
- key: "rowSelection",
142
- style: rowSelection?.style || {
143
- background: "rgba(128, 128, 128, 0.1)",
144
- display: "flex",
145
- justifyContent: "center",
146
- },
147
- });
148
- }
149
-
150
- setHeaderList(convertColumnsToRows(columns, headerRowHeight));
151
- const newColumns = flattenColumns(columns);
152
-
153
- setTableColumns(
154
- newColumns?.map((item, index) => ({
155
- ...item,
156
- columnId: item?.dataIndex || item?.key || item?.name || "",
157
- })),
158
- );
159
- }
160
- }, [columns, rowSelection]);
161
-
162
- /** 自定义表头 */
163
- const headTemplate: any = {};
164
- const handleHeader = (arr) => {
165
- arr?.forEach((item) => {
166
- if (isReactElement(typeof item?.title == "function" ? item?.title() : null)) {
167
- const Com = item?.title;
168
- headTemplate[item?.dataIndex] = WidthWrapHoc(Com);
169
- }
170
- if (item?.children) {
171
- handleHeader(item?.children);
172
- }
173
- });
174
- };
175
- useEffect(() => {
176
- handleHeader(columns);
177
- setHeaderCustomTemplate(headTemplate);
178
- }, [columns]);
179
-
180
- /** 数据行 */
181
- useEffect(() => {
182
- const columnsIds = tableColumns?.map((el) => el?.columnId);
183
-
184
- const tempDataSource = newDataSource?.map((item, index) => {
185
- return {
186
- rowId: item[rowKey],
187
- height: rowHeight,
188
- cells: columnsIds?.map((el, ind) => {
189
- let newCell = {};
190
- const columnsItem = tableColumns[ind];
191
- const cellItem = item[el];
192
- const type: any = columnsItem?.type ?? "text";
193
- //设置单元格颜色及回显
194
- if (formulaConfig) {
195
- for (const key in formulaConfig) {
196
- if (key == el) {
197
- const it = formulaConfig[key];
198
- newCell = {
199
- text: it?.setCellData && it?.setCellData(item),
200
- value: it?.setCellData && it?.setCellData(item),
201
- style: it?.setCellStyle && it?.setCellStyle((it?.setCellData && it?.setCellData(item)) || item),
202
- };
203
- }
204
- }
205
- }
206
-
207
- return {
208
- ...columnsItem,
209
- record: item,
210
- rowId: item[rowKey] || columnsItem?.type,
211
- type: type,
212
- nonEditable: columnsItem?.nonEditable,
213
- text: String(cellItem || ""),
214
- value: cellItem,
215
- selectedValue: cellItem || "",
216
- style: columnsItem?.type == "rowSelection" ? { display: "flex", justifyContent: "center" } : {},
217
- ...(((onRow && onRow(item, index, ind)) as any) || {}),
218
- ...((columnsItem?.onCell && columnsItem?.onCell(item, index, ind)) || {}),
219
- ...(columnsItem?.cellProps || {}),
220
- setNewDataSource,
221
- setExpandKeys,
222
- rowKey,
223
- expandKeys,
224
- Slots,
225
- ...newCell,
226
- };
227
- }),
228
- };
229
- });
230
- const mergerList = [...headerList, ...tempDataSource];
231
- setRows(mergerList);
232
- }, [newDataSource, tableColumns, headerList]);
233
- useEffect(() => {
234
- if (loading) {
235
- const item = rows?.find((el) => el?.rowId == currentCell.current?.rowId);
236
- let newItem = item?.cells?.find((it) => it?.columnId == currentCell.current?.columnId);
237
- newItem = { ...currentCell.current };
238
- initRowsRef.current = rows;
239
- }
240
- }, [loading, rows]);
241
- // 单元格编辑回调
242
- const handleCellsChanged = async (changes) => {
243
- const batchQuery: any = [];
244
- if (!Array.isArray(changes) || changes.length === 0) return;
245
- /** 批量提交 */
246
- let isBatchSubmit = false;
247
- if (changes?.length > 1) {
248
- isBatchSubmit = true;
249
- }
250
-
251
- setRows((prevRows) => {
252
- changes.forEach(async (change) => {
253
- const changeRowIdx = prevRows.findIndex((el) => el.rowId == change.rowId);
254
- const changeColumnIdx = tableColumns.findIndex((el) => el.columnId == change.columnId);
255
- prevRows[changeRowIdx].cells[changeColumnIdx] = { ...change.newCell };
256
- currentCell.current = { ...change.newCell };
257
- batchQuery.push(handleArrayToObj(prevRows[changeRowIdx]));
258
- if (formulaConfig) {
259
- for (const key in formulaConfig) {
260
- const item = formulaConfig[key];
261
- const resultColumnIdx = tableColumns.findIndex((el) => el.columnId == key);
262
- const newCell = {
263
- ...prevRows[changeRowIdx].cells[resultColumnIdx],
264
- text: item?.setCellData && item?.setCellData(prevRows[changeRowIdx]),
265
- value: item?.setCellData && item?.setCellData(prevRows[changeRowIdx]),
266
- style:
267
- item?.setCellStyle &&
268
- item?.setCellStyle(
269
- (item?.setCellData && item?.setCellData(prevRows[changeRowIdx])) || prevRows[changeRowIdx],
270
- ),
271
- };
272
- prevRows[changeRowIdx].cells[resultColumnIdx] = newCell;
273
- }
274
- }
275
- if (onEditSubmit && !isBatchSubmit) {
276
- try {
277
- await onEditSubmit(batchQuery);
278
- } catch (err) {
279
- getList && getList();
280
- }
281
- }
282
- onChange && onChange(prevRows[changeRowIdx]);
283
- });
284
- return [...prevRows];
285
- });
286
-
287
- if (isBatchSubmit) {
288
- try {
289
- onEditSubmit && (await onEditSubmit(batchQuery));
290
- } catch (err) {
291
- getList && getList();
292
- }
293
- }
294
- };
295
-
296
- /** 自定义组件注册 */
297
- const baseTemplate = useMemo(() => {
298
- const mergeTemplate: any = { ...(antdComponents || {}), ...(customComponents || {}), ...childAntdComponent };
299
- const newMergeTemplate: any = {};
300
- for (const key in mergeTemplate) {
301
- const NewCom = (newComProps) => {
302
- return <GetBaseTemplate {...newComProps} {...props} Com={mergeTemplate[key]} />;
303
- };
304
- newMergeTemplate[key] = WidthWrapHoc(NewCom);
305
- }
306
- return newMergeTemplate;
307
- }, [antdComponents, customComponents]);
308
-
309
- const ActionDom = (props) => {
310
- const rowData = rows?.find((el) => el?.rowId == props?.cell?.rowId);
311
- return (
312
- <div onPointerDown={(e) => e.stopPropagation()}>
313
- {Slots?.tableActionsSlot && <Slots.tableActionsSlot {...props?.cell} rowData={rowData} />}
314
- {Slots?.actionPrefixSlot && <Slots.actionPrefixSlot {...props?.cell} rowData={rowData} />}
315
- {Slots?.actionCenterSlot && <Slots.actionCenterSlot {...props?.cell} rowData={rowData} />}
316
- {Slots?.actionSuffixSlot && <Slots.actionSuffixSlot {...props?.cell} rowData={rowData} />}
317
- </div>
318
- );
319
- };
320
- function flattenDataSource(arr: any) {
321
- const result: any = [];
322
- function loop(list: any) {
323
- for (const item of list) {
324
- result.push(item);
325
- if (item.children && item.children.length) {
326
- loop(item.children);
327
- }
328
- }
329
- }
330
- loop(arr);
331
- return result;
332
- }
333
- const CheckBoxDom = (props) => {
334
- const { record, rowId } = props?.cell;
335
- const newDataSource = flattenDataSource(dataSource);
336
- return (
337
- <Checkbox
338
- {...props?.componentProps}
339
- checked={
340
- rowSelection?.selectedRowKeys?.includes((record && record[rowKey]) || "") ||
341
- (rowSelection?.selectedRowKeys?.length == newDataSource?.length && newDataSource?.length > 0)
342
- }
343
- indeterminate={
344
- !rowId &&
345
- rowSelection?.selectedRowKeys?.length > 0 &&
346
- rowSelection?.selectedRowKeys?.length < newDataSource?.length
347
- }
348
- onChange={(e) => {
349
- if (e.target.checked && rowId) {
350
- const newSelectedRowKeys = [...rowSelection?.selectedRowKeys, record[rowKey]];
351
- const rows = newDataSource?.filter((el) => newSelectedRowKeys?.includes(el[rowKey]));
352
-
353
- rowSelection?.onChange(newSelectedRowKeys, rows);
354
- } else if (!e.target.checked && rowId) {
355
- const newSelectedRowKeys = rowSelection?.selectedRowKeys?.filter((el) => el != record[rowKey]);
356
- const rows = newDataSource?.filter((el) => newSelectedRowKeys?.includes(el[rowKey]));
357
-
358
- rowSelection?.onChange(
359
- rowSelection?.selectedRowKeys?.filter((el) => el != record[rowKey]),
360
- rows,
361
- );
362
- } else if (e.target.checked && !rowId) {
363
- const newSelectedRowKeys = newDataSource?.map((el) => el[rowKey]);
364
- const rows = newDataSource?.filter((el) => newSelectedRowKeys?.includes(el[rowKey]));
365
-
366
- rowSelection?.onChange(
367
- newDataSource?.map((el) => el[rowKey]),
368
- rows,
369
- );
370
- } else if (!e.target.checked && !rowId) {
371
- rowSelection?.onChange([], []);
372
- }
373
- }}
374
- ></Checkbox>
375
- );
376
- };
377
- useEffect(() => {
378
- if (rowSelection) {
379
- const newDataSource = flattenDataSource(dataSource);
380
- const rows = newDataSource?.filter((el) => selectedRowKeys?.includes(el[rowKey]));
381
- rowSelection?.onChange(selectedRowKeys, rows);
382
- }
383
- }, [selectedRowKeys, dataSource]);
384
- useEffect(() => {
385
- setSelectedRowKeys([]);
386
- }, [query?.pageNum]);
387
-
388
- const customCellTemplates = useMemo(() => {
389
- const templatesObj: any = {};
390
- for (const key in reactGridProps?.customCellTemplates) {
391
- const item = reactGridProps?.customCellTemplates[key];
392
- templatesObj[key] = WidthWrapHoc(item);
393
- }
394
- return templatesObj;
395
- }, [reactGridProps?.customCellTemplates]);
396
-
397
- /** 选中高亮整行 */
398
- const onHightsRow = (cell: any, rows: any) => {
399
- const list = rows
400
- ?.find((el) => el?.rowId == cell?.rowId)
401
- ?.cells?.map((item) => ({
402
- columnId: item?.columnId,
403
- rowId: cell?.rowId,
404
- className: "custom-highlights-row",
405
- borderColor: "transparent",
406
- }));
407
- highlightsRowIdRef.current = cell?.rowId;
408
- setHighlights(list);
409
- };
410
-
411
- return (
412
- <Spin spinning={loading}>
413
- <div className={`grid-container ${className}`} style={reactGridStyle}>
414
- <ReactGrid
415
- ref={gridRef}
416
- rows={loading ? initRowsRef.current : rows}
417
- key={dataSource?.length == 0 ? 0 : 1}
418
- columns={tableColumns}
419
- onCellsChanged={handleCellsChanged}
420
- enableFillHandle={true}
421
- enableRangeSelection={true}
422
- horizontalStickyBreakpoint={120}
423
- {...reactGridProps}
424
- highlights={reactGridProps?.highlights ?? highlights}
425
- onFocusLocationChanging={(cell: any) => {
426
- const datatypeId = cell?.columnId + cell?.rowId;
427
- (window as any).gridEditId = datatypeId;
428
- if (typeof cell?.rowId == "string" && cell?.rowId?.indexOf("header-") > -1) {
429
- return false;
430
- }
431
- if (reactGridProps?.isRowHighlights && cell?.columnId) {
432
- onHightsRow(cell, rows);
433
- }
434
- if (["_$actions", "rowSelection", "ExpandListTemplate"]?.includes(cell?.columnId)) {
435
- return false;
436
- }
437
- if (reactGridProps?.onFocusLocationChanging) {
438
- return reactGridProps?.onFocusLocationChanging(cell, rows);
439
- }
440
-
441
- return cell;
442
- }}
443
- customCellTemplates={{
444
- ExpandListTemplate: WidthWrapHoc(ExpandListTemplate),
445
- ...baseTemplate,
446
- ...customCellTemplates,
447
- ...headerCustomTemplate,
448
- _$actions: WidthWrapHoc(ActionDom),
449
- rowSelection: WidthWrapHoc(CheckBoxDom),
450
- // Input: WidthWrapHoc(TextTemplate,props),
451
- Number: WidthWrapHoc(NumberTemplate, props),
452
- }}
453
- />
454
- {dataSource?.length <= 0 && (
455
- <div className="grid-container-empty">
456
- <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
457
- </div>
458
- )}
459
- </div>
460
- </Spin>
461
- );
462
- }
463
-
464
- export default forwardRef(CellEditTable);
1
+ import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
2
+ import { Checkbox, Empty, Spin } from "antd";
3
+ import { ReactGrid } from "@silevis/reactgrid";
4
+ import TextTemplate from "./Template/TextCellTemplate";
5
+ import { antdComponents, customComponents } from "@hzab/form-render";
6
+ import { WidthWrapHoc } from "./common/WidthWrapHoc";
7
+ import NumberTemplate from "./Template/NumberCellTemplate";
8
+ import { ExpandListTemplate } from "./Template/ExpandListTemplate";
9
+ import { convertColumnsToRows, flattenColumns, isReactElement } from "./common/utils";
10
+ import { childAntdComponent } from "./common/childAntdComponent";
11
+ import { GetBaseTemplate } from "./Template/GetBaseTemplate";
12
+ import "./index.less";
13
+ import "@silevis/reactgrid/styles.css";
14
+
15
+ interface CellEditTableProps {
16
+ columns: any[];
17
+ dataSource: any[];
18
+ formulaConfig?: any;
19
+ onChange?: (v: any) => void;
20
+ reactGridProps?: any;
21
+ onEditSubmit?: (v: any) => void;
22
+ headerRowHeight?: number;
23
+ rowHeight?: number;
24
+ reactGridStyle?: any;
25
+ className?: string;
26
+ Slots?: any;
27
+ rowSelection?: any;
28
+ rowKey?: string;
29
+ query?: any;
30
+ loading?: boolean;
31
+ isExpand?: boolean;
32
+ getList?: () => void;
33
+ onRow?: (v: any, ri: number, ci: number) => void;
34
+ }
35
+
36
+ function CellEditTable(props: CellEditTableProps, ref: any) {
37
+ const {
38
+ columns,
39
+ dataSource,
40
+ formulaConfig,
41
+ onChange,
42
+ reactGridProps = {},
43
+ onEditSubmit,
44
+ headerRowHeight = 44,
45
+ rowHeight = 44,
46
+ reactGridStyle,
47
+ className,
48
+ Slots,
49
+ rowSelection,
50
+ rowKey = "id",
51
+ query,
52
+ loading,
53
+ isExpand = false,
54
+ getList,
55
+ onRow,
56
+ } = props;
57
+
58
+ const [headerList, setHeaderList] = useState<any>([]);
59
+ const [rows, setRows] = useState<any>([]);
60
+ const initRowsRef = useRef<any>([]);
61
+ /** 初始行数据 */
62
+ const [tableColumns, setTableColumns] = useState<any>([]);
63
+ const [selectedRowKeys, setSelectedRowKeys] = useState<any>([]);
64
+ const [newDataSource, setNewDataSource] = useState<any>([]);
65
+ const [expandKeys, setExpandKeys] = useState<any>([]);
66
+ const [headerCustomTemplate, setHeaderCustomTemplate] = useState<any>([]);
67
+ const [highlights, setHighlights] = useState([]);
68
+ const highlightsRowIdRef = useRef();
69
+
70
+ const gridRef = useRef<any>();
71
+ const currentCell = useRef<any>();
72
+
73
+ useImperativeHandle(ref, () => {
74
+ return {
75
+ rows,
76
+ };
77
+ });
78
+ /** 递归处理子节点数据 */
79
+ const handleDataSource = (arr, level = 0) => {
80
+ arr?.forEach((el) => {
81
+ el.level = level + 1;
82
+ if (el?.children) {
83
+ handleDataSource(el?.children, el.level);
84
+ }
85
+ });
86
+ };
87
+ /** 洗数据 */
88
+ useEffect(() => {
89
+ handleDataSource(dataSource);
90
+ setNewDataSource(dataSource);
91
+ }, [dataSource]);
92
+
93
+ /** 判断当前选中行是否还存在 */
94
+ useEffect(() => {
95
+ const validRowIds = rows.map((r) => r.rowId);
96
+ if (!validRowIds?.includes(highlightsRowIdRef.current)) {
97
+ setHighlights([]);
98
+ }
99
+ }, [rows]);
100
+
101
+ /**将数组转为对象 */
102
+ const handleArrayToObj = (item) => {
103
+ const record = item?.cells?.[0]?.record;
104
+ const fieldList = ["_$actions", "rowSelection"];
105
+ const obj: any = {
106
+ id: item?.rowId,
107
+ };
108
+ item?.cells?.forEach((el) => {
109
+ if (el?.columnId && !fieldList?.includes(el?.columnId)) {
110
+ obj[el?.columnId] = el?.text || el?.value || el?.selectedValue || "";
111
+ if (el?.type == "Number") {
112
+ obj[el?.columnId] = el?.value;
113
+ }
114
+ }
115
+ });
116
+
117
+ return {
118
+ ...record,
119
+ ...obj,
120
+ };
121
+ };
122
+ /** 表头 */
123
+ useEffect(() => {
124
+ if (Array.isArray(columns) && columns?.length > 0) {
125
+ if (isExpand) {
126
+ columns.unshift({
127
+ type: "ExpandListTemplate",
128
+ width: 14,
129
+ key: "ExpandListTemplate",
130
+ nonEditable: true,
131
+ style: rowSelection?.style || {
132
+ background: "rgba(128, 128, 128, 0.1)",
133
+ },
134
+ });
135
+ }
136
+ if (rowSelection) {
137
+ columns.unshift({
138
+ type: "rowSelection",
139
+ nonEditable: true,
140
+ width: rowSelection?.width || 30,
141
+ key: "rowSelection",
142
+ style: rowSelection?.style || {
143
+ background: "rgba(128, 128, 128, 0.1)",
144
+ display: "flex",
145
+ justifyContent: "center",
146
+ },
147
+ });
148
+ }
149
+
150
+ setHeaderList(convertColumnsToRows(columns, headerRowHeight));
151
+ const newColumns = flattenColumns(columns);
152
+
153
+ setTableColumns(
154
+ newColumns?.map((item, index) => ({
155
+ ...item,
156
+ columnId: item?.dataIndex || item?.key || item?.name || "",
157
+ })),
158
+ );
159
+ }
160
+ }, [columns, rowSelection]);
161
+
162
+ /** 自定义表头 */
163
+ const headTemplate: any = {};
164
+ const handleHeader = (arr) => {
165
+ arr?.forEach((item) => {
166
+ if (isReactElement(typeof item?.title == "function" ? item?.title() : null)) {
167
+ const Com = item?.title;
168
+ headTemplate[item?.dataIndex] = WidthWrapHoc(Com);
169
+ }
170
+ if (item?.children) {
171
+ handleHeader(item?.children);
172
+ }
173
+ });
174
+ };
175
+ useEffect(() => {
176
+ handleHeader(columns);
177
+ setHeaderCustomTemplate(headTemplate);
178
+ }, [columns]);
179
+
180
+ /** 数据行 */
181
+ useEffect(() => {
182
+ const columnsIds = tableColumns?.map((el) => el?.columnId);
183
+
184
+ const tempDataSource = newDataSource?.map((item, index) => {
185
+ return {
186
+ rowId: item[rowKey],
187
+ height: rowHeight,
188
+ cells: columnsIds?.map((el, ind) => {
189
+ let newCell = {};
190
+ const columnsItem = tableColumns[ind];
191
+ const cellItem = item[el];
192
+ const type: any = columnsItem?.type ?? "text";
193
+ //设置单元格颜色及回显
194
+ if (formulaConfig) {
195
+ for (const key in formulaConfig) {
196
+ if (key == el) {
197
+ const it = formulaConfig[key];
198
+ newCell = {
199
+ text: it?.setCellData && it?.setCellData(item),
200
+ value: it?.setCellData && it?.setCellData(item),
201
+ style:
202
+ it?.setCellStyle &&
203
+ it?.setCellStyle((it?.setCellData && it?.setCellData(item)) || item),
204
+ };
205
+ }
206
+ }
207
+ }
208
+
209
+ return {
210
+ ...columnsItem,
211
+ record: item,
212
+ rowId: item[rowKey] || columnsItem?.type,
213
+ type: type,
214
+ nonEditable: columnsItem?.pattern == "readPretty" ? true : columnsItem?.nonEditable,
215
+ text: String(cellItem || ""),
216
+ value: cellItem,
217
+ selectedValue: cellItem || "",
218
+ style:
219
+ columnsItem?.type == "rowSelection"
220
+ ? { display: "flex", justifyContent: "center" }
221
+ : {},
222
+ ...(((onRow && onRow(item, index, ind)) as any) || {}),
223
+ ...((columnsItem?.onCell && columnsItem?.onCell(item, index, ind)) || {}),
224
+ ...(columnsItem?.cellProps || {}),
225
+ setNewDataSource,
226
+ setExpandKeys,
227
+ rowKey,
228
+ expandKeys,
229
+ Slots,
230
+ ...newCell,
231
+ };
232
+ }),
233
+ };
234
+ });
235
+ const mergerList = [...headerList, ...tempDataSource];
236
+ setRows(mergerList);
237
+ }, [newDataSource, tableColumns, headerList]);
238
+ useEffect(() => {
239
+ if (loading) {
240
+ const item = rows?.find((el) => el?.rowId == currentCell.current?.rowId);
241
+ let newItem = item?.cells?.find((it) => it?.columnId == currentCell.current?.columnId);
242
+ newItem = { ...currentCell.current };
243
+ initRowsRef.current = rows;
244
+ }
245
+ }, [loading, rows]);
246
+ // 单元格编辑回调
247
+ const handleCellsChanged = async (changes) => {
248
+ const batchQuery: any = [];
249
+ if (!Array.isArray(changes) || changes.length === 0) return;
250
+ /** 批量提交 */
251
+ let isBatchSubmit = false;
252
+ if (changes?.length > 1) {
253
+ isBatchSubmit = true;
254
+ }
255
+
256
+ setRows((prevRows) => {
257
+ changes.forEach(async (change) => {
258
+ const changeRowIdx = prevRows.findIndex((el) => el.rowId == change.rowId);
259
+ const changeColumnIdx = tableColumns.findIndex((el) => el.columnId == change.columnId);
260
+ prevRows[changeRowIdx].cells[changeColumnIdx] = { ...change.newCell };
261
+ currentCell.current = { ...change.newCell };
262
+ batchQuery.push(handleArrayToObj(prevRows[changeRowIdx]));
263
+ if (formulaConfig) {
264
+ for (const key in formulaConfig) {
265
+ const item = formulaConfig[key];
266
+ const resultColumnIdx = tableColumns.findIndex((el) => el.columnId == key);
267
+ const newCell = {
268
+ ...prevRows[changeRowIdx].cells[resultColumnIdx],
269
+ text: item?.setCellData && item?.setCellData(prevRows[changeRowIdx]),
270
+ value: item?.setCellData && item?.setCellData(prevRows[changeRowIdx]),
271
+ style:
272
+ item?.setCellStyle &&
273
+ item?.setCellStyle(
274
+ (item?.setCellData && item?.setCellData(prevRows[changeRowIdx])) ||
275
+ prevRows[changeRowIdx],
276
+ ),
277
+ };
278
+ prevRows[changeRowIdx].cells[resultColumnIdx] = newCell;
279
+ }
280
+ }
281
+ if (onEditSubmit && !isBatchSubmit) {
282
+ try {
283
+ await onEditSubmit(batchQuery);
284
+ } catch (err) {
285
+ getList && getList();
286
+ }
287
+ }
288
+ onChange && onChange(prevRows[changeRowIdx]);
289
+ });
290
+ return [...prevRows];
291
+ });
292
+
293
+ if (isBatchSubmit) {
294
+ try {
295
+ onEditSubmit && (await onEditSubmit(batchQuery));
296
+ } catch (err) {
297
+ getList && getList();
298
+ }
299
+ }
300
+ };
301
+
302
+ /** 自定义组件注册 */
303
+ const baseTemplate = useMemo(() => {
304
+ const mergeTemplate: any = {
305
+ ...(antdComponents || {}),
306
+ ...(customComponents || {}),
307
+ ...childAntdComponent,
308
+ };
309
+ const newMergeTemplate: any = {};
310
+ for (const key in mergeTemplate) {
311
+ const NewCom = (newComProps) => {
312
+ return <GetBaseTemplate {...newComProps} {...props} Com={mergeTemplate[key]} />;
313
+ };
314
+ newMergeTemplate[key] = WidthWrapHoc(NewCom);
315
+ }
316
+ return newMergeTemplate;
317
+ }, [antdComponents, customComponents]);
318
+
319
+ const ActionDom = (props) => {
320
+ const rowData = rows?.find((el) => el?.rowId == props?.cell?.rowId);
321
+ return (
322
+ <div onPointerDown={(e) => e.stopPropagation()}>
323
+ {Slots?.tableActionsSlot && <Slots.tableActionsSlot {...props?.cell} rowData={rowData} />}
324
+ {Slots?.actionPrefixSlot && <Slots.actionPrefixSlot {...props?.cell} rowData={rowData} />}
325
+ {Slots?.actionCenterSlot && <Slots.actionCenterSlot {...props?.cell} rowData={rowData} />}
326
+ {Slots?.actionSuffixSlot && <Slots.actionSuffixSlot {...props?.cell} rowData={rowData} />}
327
+ </div>
328
+ );
329
+ };
330
+ function flattenDataSource(arr: any) {
331
+ const result: any = [];
332
+ function loop(list: any) {
333
+ for (const item of list) {
334
+ result.push(item);
335
+ if (item.children && item.children.length) {
336
+ loop(item.children);
337
+ }
338
+ }
339
+ }
340
+ loop(arr);
341
+ return result;
342
+ }
343
+ const CheckBoxDom = (props) => {
344
+ const { record, rowId } = props?.cell;
345
+
346
+ const newDataSource = flattenDataSource(dataSource)?.filter(
347
+ (item) => !rowSelection?.getCheckboxProps?.(item)?.disabled,
348
+ );
349
+
350
+ const checkboxProps =
351
+ typeof rowSelection?.getCheckboxProps === "function"
352
+ ? rowSelection?.getCheckboxProps?.(record)
353
+ : {};
354
+ return (
355
+ <Checkbox
356
+ {...props?.componentProps}
357
+ checked={
358
+ rowSelection?.selectedRowKeys?.includes((record && record[rowKey]) || "") ||
359
+ (!rowId &&
360
+ rowSelection?.selectedRowKeys?.length == newDataSource?.length &&
361
+ newDataSource?.length > 0)
362
+ }
363
+ indeterminate={
364
+ !rowId &&
365
+ rowSelection?.selectedRowKeys?.length > 0 &&
366
+ rowSelection?.selectedRowKeys?.length < newDataSource?.length
367
+ }
368
+ onChange={(e) => {
369
+ if (e.target.checked && rowId) {
370
+ const newSelectedRowKeys = [...rowSelection?.selectedRowKeys, record[rowKey]];
371
+ const rows = newDataSource?.filter((el) => newSelectedRowKeys?.includes(el[rowKey]));
372
+
373
+ rowSelection?.onChange(newSelectedRowKeys, rows);
374
+ } else if (!e.target.checked && rowId) {
375
+ const newSelectedRowKeys = rowSelection?.selectedRowKeys?.filter(
376
+ (el) => el != record[rowKey],
377
+ );
378
+ const rows = newDataSource?.filter((el) => newSelectedRowKeys?.includes(el[rowKey]));
379
+
380
+ rowSelection?.onChange(
381
+ rowSelection?.selectedRowKeys?.filter((el) => el != record[rowKey]),
382
+ rows,
383
+ );
384
+ } else if (e.target.checked && !rowId) {
385
+ const newSelectedRowKeys = newDataSource?.map((el) => el[rowKey]);
386
+ const rows = newDataSource?.filter((el) => newSelectedRowKeys?.includes(el[rowKey]));
387
+
388
+ rowSelection?.onChange(
389
+ newDataSource?.map((el) => el[rowKey]),
390
+ rows,
391
+ );
392
+ } else if (!e.target.checked && !rowId) {
393
+ rowSelection?.onChange([], []);
394
+ }
395
+ }}
396
+ {...checkboxProps}
397
+ ></Checkbox>
398
+ );
399
+ };
400
+ useEffect(() => {
401
+ if (rowSelection) {
402
+ const newDataSource = flattenDataSource(dataSource)?.filter(
403
+ (item) => !rowSelection?.getCheckboxProps?.(item)?.disabled,
404
+ );
405
+ const rows = newDataSource?.filter((el) => selectedRowKeys?.includes(el[rowKey]));
406
+ rowSelection?.onChange(selectedRowKeys, rows);
407
+ }
408
+ }, [selectedRowKeys, dataSource]);
409
+ useEffect(() => {
410
+ setSelectedRowKeys([]);
411
+ }, [query?.pageNum]);
412
+
413
+ const customCellTemplates = useMemo(() => {
414
+ const templatesObj: any = {};
415
+ for (const key in reactGridProps?.customCellTemplates) {
416
+ const item = reactGridProps?.customCellTemplates[key];
417
+ templatesObj[key] = WidthWrapHoc(item);
418
+ }
419
+ return templatesObj;
420
+ }, [reactGridProps?.customCellTemplates]);
421
+
422
+ /** 选中高亮整行 */
423
+ const onHightsRow = (cell: any, rows: any) => {
424
+ const list = rows
425
+ ?.find((el) => el?.rowId == cell?.rowId)
426
+ ?.cells?.map((item) => ({
427
+ columnId: item?.columnId,
428
+ rowId: cell?.rowId,
429
+ className: "custom-highlights-row",
430
+ borderColor: "transparent",
431
+ }));
432
+ highlightsRowIdRef.current = cell?.rowId;
433
+ setHighlights(list);
434
+ };
435
+
436
+ return (
437
+ <Spin spinning={loading}>
438
+ <div className={`grid-container ${className}`} style={reactGridStyle}>
439
+ <ReactGrid
440
+ ref={gridRef}
441
+ rows={loading ? initRowsRef.current : rows}
442
+ key={dataSource?.length == 0 ? 0 : 1}
443
+ columns={tableColumns}
444
+ onCellsChanged={handleCellsChanged}
445
+ enableFillHandle={true}
446
+ enableRangeSelection={true}
447
+ horizontalStickyBreakpoint={120}
448
+ {...reactGridProps}
449
+ highlights={reactGridProps?.highlights ?? highlights}
450
+ onFocusLocationChanging={(cell: any) => {
451
+ const datatypeId = cell?.columnId + cell?.rowId;
452
+ (window as any).gridEditId = datatypeId;
453
+ if (typeof cell?.rowId == "string" && cell?.rowId?.indexOf("header-") > -1) {
454
+ return false;
455
+ }
456
+ if (reactGridProps?.isRowHighlights && cell?.columnId) {
457
+ onHightsRow(cell, rows);
458
+ }
459
+ if (["_$actions", "rowSelection", "ExpandListTemplate"]?.includes(cell?.columnId)) {
460
+ return false;
461
+ }
462
+ if (reactGridProps?.onFocusLocationChanging) {
463
+ return reactGridProps?.onFocusLocationChanging(cell, rows);
464
+ }
465
+
466
+ return cell;
467
+ }}
468
+ customCellTemplates={{
469
+ ExpandListTemplate: WidthWrapHoc(ExpandListTemplate),
470
+ ...baseTemplate,
471
+ ...customCellTemplates,
472
+ ...headerCustomTemplate,
473
+ _$actions: WidthWrapHoc(ActionDom),
474
+ rowSelection: WidthWrapHoc(CheckBoxDom),
475
+ // Input: WidthWrapHoc(TextTemplate,props),
476
+ Number: WidthWrapHoc(NumberTemplate, props),
477
+ }}
478
+ />
479
+ {dataSource?.length <= 0 && (
480
+ <div className="grid-container-empty">
481
+ <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
482
+ </div>
483
+ )}
484
+ </div>
485
+ </Spin>
486
+ );
487
+ }
488
+
489
+ export default forwardRef(CellEditTable);