@hzab/list-render 1.11.0 → 1.12.1

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.
@@ -1,263 +0,0 @@
1
- import { useEffect, useMemo, useState } from "react";
2
-
3
- import {
4
- Cell,
5
- CellTemplate,
6
- Compatible,
7
- getCellProperty,
8
- getCharFromKey,
9
- isAlphaNumericKey,
10
- keyCodes,
11
- Uncertain,
12
- UncertainCompatible,
13
- } from "@silevis/reactgrid";
14
- import { getVal } from "../../../common/utils";
15
-
16
- export type OptionType = {
17
- label: string;
18
- value: string | number;
19
- isDisabled?: boolean;
20
- };
21
-
22
- export interface BaseCell extends Cell {
23
- selectedValue?: string;
24
- value: string | number;
25
- values: OptionType[];
26
- isDisabled?: boolean;
27
- isOpen?: boolean;
28
- inputValue?: string;
29
- }
30
- interface DIProps {
31
- onCellChanged: (...args: any[]) => void;
32
- cell: Record<string, any>;
33
- isInEditMode?: boolean;
34
- }
35
-
36
- export const WidthWrap = (opt: any, edit = false) => {
37
- const { WrapComponent, ReadWrapComponent } = opt;
38
-
39
- class createBaseCellTemplate implements CellTemplate<BaseCell> {
40
- getCompatibleCell(uncertainCell: Uncertain<BaseCell>): Compatible<BaseCell> {
41
- let selectedValue: string | undefined;
42
- try {
43
- selectedValue = getCellProperty(uncertainCell, "selectedValue", "number");
44
- } catch {
45
- selectedValue = undefined;
46
- }
47
- if (!selectedValue) {
48
- try {
49
- selectedValue = getCellProperty(uncertainCell, "selectedValue", "string");
50
- } catch {
51
- selectedValue = undefined;
52
- }
53
- }
54
-
55
- let values: any;
56
- try {
57
- values = getCellProperty(uncertainCell, "values", "object");
58
- } catch {
59
- values = [];
60
- }
61
-
62
- const value = selectedValue ? parseFloat(selectedValue) : NaN;
63
-
64
- let isDisabled = true;
65
- try {
66
- isDisabled = getCellProperty(uncertainCell, "isDisabled", "boolean");
67
- } catch {
68
- isDisabled = false;
69
- }
70
-
71
- let inputValue: string | undefined;
72
- try {
73
- inputValue = getCellProperty(uncertainCell, "inputValue", "string");
74
- } catch {
75
- inputValue = undefined;
76
- }
77
-
78
- const text = selectedValue || "";
79
-
80
- return { ...uncertainCell, selectedValue, text, value, values, isDisabled, inputValue };
81
- }
82
-
83
- update(cell: Compatible<BaseCell>, cellToMerge: UncertainCompatible<BaseCell>): Compatible<BaseCell> {
84
- const selectedValueFromText = cell.values.some((val: any) => val.value === cellToMerge.text)
85
- ? cellToMerge.text
86
- : undefined;
87
- return this.getCompatibleCell({
88
- ...cell,
89
- selectedValue: selectedValueFromText,
90
- isOpen: cellToMerge?.isOpen,
91
- inputValue: cellToMerge.inputValue,
92
- });
93
- }
94
-
95
- getClassName(cell: Compatible<BaseCell>, isInEditMode: boolean): string {
96
- const isOpen = cell.isOpen ? "open" : "closed";
97
- return `${cell.className ? cell.className : ""}${isOpen}`;
98
- }
99
-
100
- // handleKeyDown(
101
- // cell: Compatible<BaseCell>,
102
- // keyCode: number,
103
- // ctrl: boolean,
104
- // shift: boolean,
105
- // alt: boolean,
106
- // key: string,
107
- // capsLock: boolean,
108
- // ): { cell: Compatible<BaseCell>; enableEditMode: boolean } {
109
- // if ((keyCode === keyCodes.SPACE || keyCode === keyCodes.ENTER) && !shift) {
110
- // return {
111
- // cell: this.getCompatibleCell({
112
- // ...cell,
113
- // isOpen: !cell.isOpen,
114
- // }),
115
- // enableEditMode: false,
116
- // };
117
- // }
118
-
119
- // const char = getCharFromKey(key, shift, capsLock);
120
-
121
- // if (!ctrl && !alt && isAlphaNumericKey(keyCode) && !(shift && keyCode === keyCodes.SPACE))
122
- // return {
123
- // cell: this.getCompatibleCell({
124
- // ...cell,
125
- // inputValue: char,
126
- // isOpen: !cell.isOpen,
127
- // }),
128
- // enableEditMode: false,
129
- // };
130
-
131
- // return { cell, enableEditMode: false };
132
- // }
133
-
134
- handleCompositionEnd(
135
- cell: Compatible<BaseCell>,
136
- eventData: any,
137
- ): { cell: Compatible<BaseCell>; enableEditMode: boolean } {
138
- return {
139
- cell: {
140
- ...cell,
141
- inputValue: eventData,
142
- isOpen: !cell.isOpen,
143
- },
144
- enableEditMode: false,
145
- };
146
- }
147
-
148
- render(
149
- cell: Compatible<BaseCell>,
150
- isInEditMode: boolean,
151
- onCellChanged: (cell: Compatible<BaseCell>, commit: boolean) => void,
152
- ): React.ReactNode {
153
- if (edit) {
154
- return (
155
- <div
156
- onPointerDown={(e) => e.stopPropagation()}
157
- style={{ display: "flex", justifyContent: "center", alignItems: "center" }}
158
- >
159
- <WrapComponent record={cell?.record} rowId={cell?.rowId} item={cell}></WrapComponent>
160
- </div>
161
- );
162
- }
163
- return (
164
- <BaseTemplate
165
- onCellChanged={(cell) => onCellChanged(this.getCompatibleCell(cell), true)}
166
- cell={cell}
167
- isInEditMode={isInEditMode}
168
- />
169
- );
170
- }
171
- }
172
-
173
- const BaseTemplate: React.FC<DIProps> = ({ onCellChanged, cell, isInEditMode }) => {
174
- const [isOpen, setIsOpen] = useState<boolean>(false);
175
- const datatypeId = cell?.columnId + cell?.rowId;
176
- useEffect(() => {
177
- // 处理下拉选项弹层失焦逻辑
178
- function onClick() {
179
- if (window.gridEditId != datatypeId) {
180
- setIsOpen(false);
181
- }
182
- }
183
- document.addEventListener("click", onClick);
184
- return () => {
185
- document.removeEventListener("click", onClick);
186
- };
187
- }, []);
188
-
189
- const _value = useMemo(() => {
190
- let str = "selectedValue";
191
- if (cell?.type.includes("DatePicker")) {
192
- str = "inputValue";
193
- }
194
- return str;
195
- }, [cell]);
196
-
197
- const echoValue = useMemo(() => {
198
- if (!cell?.getField) {
199
- return;
200
- }
201
- return getVal(
202
- { ...(cell?.getField && cell?.getField()), enum: cell?.getField()?.enum || cell?.values },
203
- { [cell?.getField && cell?.getField().name]: cell[_value] },
204
- );
205
- }, [cell, _value]);
206
-
207
- return (
208
- <div
209
- style={{ width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center" }}
210
- onDoubleClick={(e) => {
211
- if (cell?.nonEditable) {
212
- return;
213
- }
214
- setIsOpen(true);
215
- }}
216
- >
217
- {isOpen ? (
218
- <div onPointerDown={(e) => e.stopPropagation()} style={{ width: "100%" }}>
219
- <WrapComponent
220
- key={cell?.id}
221
- ref={(input) => {
222
- if (input) {
223
- input?.focus();
224
- }
225
- }}
226
- open={isOpen}
227
- style={{ width: "100%", display: "flex", alignItems: "center", justifyContent: "center" }}
228
- value={cell[_value]}
229
- options={cell.values}
230
- onChange={(e) => {
231
- setIsOpen(false);
232
- if (cell?.type.includes("DatePicker")) {
233
- onCellChanged({ ...cell, inputValue: e?.target?.value || e });
234
- return;
235
- }
236
- onCellChanged({ ...cell, selectedValue: e?.target?.value || e });
237
- }}
238
- {...((cell?.getField && cell?.getField()["x-component-props"]) || {})}
239
- ></WrapComponent>
240
- </div>
241
- ) : (
242
- <div>
243
- {ReadWrapComponent ? (
244
- <ReadWrapComponent
245
- key={cell?.id}
246
- value={echoValue}
247
- record={cell?.record}
248
- rowId={cell?.rowId}
249
- item={cell}
250
- />
251
- ) : (
252
- <div style={{ height: "100%", display: "flex", alignItems: "center", justifyContent: "center" }}>
253
- {echoValue}
254
- </div>
255
- )}
256
- </div>
257
- )}
258
- </div>
259
- );
260
- };
261
-
262
- return new createBaseCellTemplate();
263
- };
@@ -1,11 +0,0 @@
1
- .grid-container {
2
- overflow: auto;
3
- position: relative;
4
- max-height: 80vh;
5
-
6
-
7
-
8
- .ant-select {
9
- width: 100% !important;
10
- }
11
- }
@@ -1,344 +0,0 @@
1
- import React, { memo, useEffect, useMemo, useState } from "react";
2
- import { ReactGrid, Column, Row, CellChange, Cell, CellTemplate } from "@silevis/reactgrid";
3
- import "@silevis/reactgrid/styles.css";
4
- import _ from "lodash";
5
- import "./index.less";
6
- import { TextTemplate } from "./Template/TextCellTemplate";
7
- import { antdComponents, customComponents } from "@hzab/form-render/src/index";
8
- import { WidthWrap } from "./Template/widthWrap";
9
- import { NumberTemplate } from "./Template/NumberCellTemplate";
10
- import { Checkbox, Spin } from "antd";
11
- import { ExpandListTemplate } from "./Template/ExpandListTemplate";
12
- import { convertColumnsToRows, flattenColumns } from "./Template/utils";
13
-
14
- export default memo(function CellEditTable(props: any) {
15
- const {
16
- columns,
17
- dataSource,
18
- formulaConfig,
19
- onChange,
20
- reactGridProps = {},
21
- onEditSubmit,
22
- headerRowHeight,
23
- rowHeight,
24
- reactGridStyle,
25
- className,
26
- Slots,
27
- rowSelection,
28
- rowKey,
29
- query,
30
- loading,
31
- } = props;
32
-
33
- const [headerList, setHeaderList] = useState<any>([]);
34
- const [rows, setRows] = useState<any>([]);
35
- const [tableColumns, setTableColumns] = useState<any>([]);
36
- const [selectedRowKeys, setSelectedRowKeys] = useState<any>([]);
37
- const [newDataSource, setNewDataSource] = useState<any>([]);
38
- const [expandKeys, setExpandKeys] = useState<any>([]);
39
- useEffect(() => {
40
- setNewDataSource(dataSource);
41
- }, [dataSource]);
42
- /**将数组转为对象 */
43
- const handleArrayToObj = (item) => {
44
- const record = item?.cells?.[0]?.record;
45
- const fieldList = ["_$actions", "rowSelection"];
46
- let obj: any = {
47
- id: item?.rowId,
48
- };
49
- item?.cells?.forEach((el) => {
50
- if (el?.columnId && !fieldList?.includes(el?.columnId)) {
51
- obj[el?.columnId] = el?.text || el?.value || el?.selectedValue || "";
52
- }
53
- });
54
-
55
- return {
56
- ...record,
57
- ...obj,
58
- };
59
- };
60
- /** 表头 */
61
- useEffect(() => {
62
- if (Array.isArray(columns) && columns?.length > 0) {
63
- if (rowSelection) {
64
- columns.unshift({
65
- type: "rowSelection",
66
- width: rowSelection?.width || 30,
67
- key: "rowSelection",
68
- style: rowSelection?.style || {
69
- background: "rgba(128, 128, 128, 0.1)",
70
- display: "flex",
71
- justifyContent: "center",
72
- },
73
- });
74
- }
75
- // const cells = columns?.map((item, index) => {
76
- // return {
77
- // type: item?.type == "rowSelection" ? "rowSelection" : "header",
78
- // text:
79
- // typeof item?.title == "function"
80
- // ? isReactElement(item?.title())
81
- // ? item?.title()?.props.children
82
- // : String(item?.title()) || ""
83
- // : String(item?.title) || "",
84
- // style: item?.type == "rowSelection" ? item?.style : {},
85
- // onCell: item?.onCell,
86
- // };
87
- // });
88
- setHeaderList(convertColumnsToRows(columns, headerRowHeight));
89
- const newColumns = flattenColumns(columns);
90
- setTableColumns(
91
- newColumns?.map((item, index) => ({
92
- ...item,
93
- columnId: item?.dataIndex || item?.key || "",
94
- })),
95
- );
96
- }
97
- }, [columns, rowSelection]);
98
-
99
- /** 数据行 */
100
- useEffect(() => {
101
- const columnsIds = tableColumns?.map((el) => el?.columnId);
102
- const tempDataSource = newDataSource?.map((item, index) => {
103
- return {
104
- rowId: item[rowKey],
105
- height: rowHeight,
106
- cells: columnsIds?.map((el, ind) => {
107
- let newCell = {};
108
- const columnsItem = tableColumns[ind];
109
- const cellItem = item[el];
110
- let type: any = columnsItem?.type ?? "text";
111
- if (!rowSelection && ind == 0) {
112
- type = "ExpandListTemplate";
113
- }
114
- if (rowSelection && ind == 1) {
115
- type = "ExpandListTemplate";
116
- }
117
-
118
- if (formulaConfig) {
119
- for (let key in formulaConfig) {
120
- if (key == el) {
121
- const it = formulaConfig[key];
122
- newCell = {
123
- text: it?.setCellData(item),
124
- value: it?.setCellData(item),
125
- style: it?.setCellStyle(it?.setCellData(item)),
126
- };
127
- }
128
- }
129
- }
130
-
131
- return {
132
- ...columnsItem,
133
- record: item,
134
- rowId: item[rowKey] || columnsItem?.type,
135
- type: type,
136
- nonEditable: columnsItem?.nonEditable,
137
- text: String(cellItem || ""),
138
- value: cellItem,
139
- selectedValue: cellItem || "",
140
- // rowspan: item?.extendedConfig?.name == el ? item?.extendedConfig?.rowspan || 0 : 0,
141
- // colspan: item?.extendedConfig?.name == el ? item?.extendedConfig?.colspan || 0 : 0,
142
- style: columnsItem?.type == "rowSelection" ? { display: "flex", justifyContent: "center" } : {},
143
- ...((columnsItem?.onCell && columnsItem?.onCell(item, index, ind)) || {}),
144
- ...(columnsItem?.cellProps || {}),
145
- setNewDataSource,
146
- setExpandKeys,
147
- rowKey,
148
- expandKeys,
149
- Slots,
150
- ...newCell,
151
-
152
- // style:item?.extendedConfig?.name==el?item?.extendedConfig?.style||{}:{}
153
- // ...handleType(item[el],tableColumns[ind]),
154
- };
155
- }),
156
- };
157
- });
158
- setRows(_.uniqBy([...headerList, ...tempDataSource], "rowId"));
159
- }, [newDataSource, tableColumns, rowSelection]);
160
-
161
- // 单元格编辑回调
162
- const handleCellsChanged = (changes) => {
163
- if (!Array.isArray(changes) || changes.length === 0) return;
164
- const hasDiff = changes.some((c) => JSON.stringify(c.previousCell) !== JSON.stringify(c.newCell));
165
- if (!hasDiff) return;
166
- setRows((prevRows) => {
167
- changes.forEach((change) => {
168
- const changeRowIdx = prevRows.findIndex((el) => el.rowId == change.rowId);
169
- const changeColumnIdx = tableColumns.findIndex((el) => el.columnId == change.columnId);
170
- prevRows[changeRowIdx].cells[changeColumnIdx] = change.newCell;
171
- if (formulaConfig) {
172
- for (let key in formulaConfig) {
173
- const item = formulaConfig[key];
174
- const resultColumnIdx = tableColumns.findIndex((el) => el.columnId == key);
175
- const newCell = {
176
- ...prevRows[changeRowIdx].cells[resultColumnIdx],
177
- text: item?.setCellData(prevRows[changeRowIdx]),
178
- value: item?.setCellData(prevRows[changeRowIdx]),
179
- style: item?.setCellStyle(item?.setCellData(prevRows[changeRowIdx])),
180
- };
181
- prevRows[changeRowIdx].cells[resultColumnIdx] = newCell;
182
- }
183
- }
184
- onEditSubmit && onEditSubmit(handleArrayToObj(prevRows[changeRowIdx]));
185
- onChange && onChange(prevRows[changeRowIdx]);
186
- });
187
- return [...prevRows];
188
- });
189
- };
190
-
191
- /**提取组件内部子组件 */
192
- function extractSubComponents(comp, compName): any {
193
- if (!comp || typeof comp !== "object") return {};
194
-
195
- return Object.entries(comp).reduce((result, [key, value]) => {
196
- // 匹配 antd 规范子组件命名:XXPicker / XX / 驼峰组件名
197
- // 排除普通函数、数字、布尔、内部私有属性(带下划线)、原型上的方法
198
- const isNativeFunc = ["render", "defaultProps", "propTypes", "displayName", "Group", "$$typeof"].includes(key);
199
- // 判定为子组件:值是函数(React组件本质是函数/类),且不是内部方法
200
- const isSubComponent = typeof comp == "object" && !isNativeFunc;
201
-
202
- if (isSubComponent) {
203
- result[`${compName}.${key}`] = value;
204
- }
205
- return result;
206
- }, {});
207
- }
208
- /** 自定义组件注册 */
209
- const baseTemplate = useMemo(() => {
210
- const mergeTemplate: any = { ...(antdComponents || {}), ...(customComponents || {}) };
211
- const newMergeTemplate: any = {};
212
- for (let key in mergeTemplate) {
213
- for (let it in extractSubComponents(mergeTemplate[key], key)) {
214
- newMergeTemplate[it] = WidthWrap({ WrapComponent: extractSubComponents(mergeTemplate[key], key)[it] });
215
- }
216
- newMergeTemplate[key] = WidthWrap({ WrapComponent: mergeTemplate[key] });
217
- }
218
- return newMergeTemplate;
219
- }, [antdComponents, customComponents]);
220
-
221
- const ActionDom = (props) => {
222
- return (
223
- <div onPointerDown={(e) => e.stopPropagation()}>
224
- {Slots?.tableActionsSlot && <Slots.tableActionsSlot {...props} />}
225
- {Slots?.actionPrefixSlot && <Slots.actionPrefixSlot {...props} />}
226
- {Slots?.actionCenterSlot && <Slots.actionCenterSlot {...props} />}
227
- {Slots?.actionSuffixSlot && <Slots.actionSuffixSlot {...props} />}
228
- </div>
229
- );
230
- };
231
-
232
- const CheckBoxDom = (props) => {
233
- return (
234
- <Checkbox
235
- {...props}
236
- checked={
237
- rowSelection?.selectedRowKeys?.includes((props?.record && props?.record[rowKey]) || "") ||
238
- (rowSelection?.selectedRowKeys?.length == dataSource?.length && dataSource?.length > 0)
239
- }
240
- indeterminate={
241
- !props?.rowId &&
242
- rowSelection?.selectedRowKeys?.length > 0 &&
243
- rowSelection?.selectedRowKeys?.length < dataSource?.length
244
- }
245
- onChange={(e) => {
246
- if (e.target.checked && props?.rowId) {
247
- const newSelectedRowKeys = [...rowSelection?.selectedRowKeys, props?.record[rowKey]];
248
- const rows = dataSource?.filter((el) => newSelectedRowKeys?.includes(el[rowKey]));
249
-
250
- rowSelection?.onChange(newSelectedRowKeys, rows);
251
- } else if (!e.target.checked && props?.rowId) {
252
- const newSelectedRowKeys = rowSelection?.selectedRowKeys?.filter((el) => el != props?.record[rowKey]);
253
- const rows = dataSource?.filter((el) => newSelectedRowKeys?.includes(el[rowKey]));
254
-
255
- rowSelection?.onChange(
256
- rowSelection?.selectedRowKeys?.filter((el) => el != props?.record[rowKey]),
257
- rows,
258
- );
259
- } else if (e.target.checked && !props?.rowId) {
260
- const newSelectedRowKeys = dataSource?.map((el) => el[rowKey]);
261
- const rows = dataSource?.filter((el) => newSelectedRowKeys?.includes(el[rowKey]));
262
-
263
- rowSelection?.onChange(
264
- dataSource?.map((el) => el[rowKey]),
265
- rows,
266
- );
267
- } else if (!e.target.checked && !props?.rowId) {
268
- rowSelection?.onChange([], []);
269
- }
270
- }}
271
- ></Checkbox>
272
- );
273
- };
274
- useEffect(() => {
275
- if (rowSelection) {
276
- const rows = dataSource?.filter((el) => selectedRowKeys?.includes(el[rowKey]));
277
- rowSelection?.onChange(selectedRowKeys, rows);
278
- }
279
- }, [selectedRowKeys, dataSource]);
280
- useEffect(() => {
281
- setSelectedRowKeys([]);
282
- }, [query?.pageNum]);
283
-
284
- return (
285
- <Spin spinning={loading}>
286
- <div className={`grid-container ${className}`} style={reactGridStyle}>
287
- <ReactGrid
288
- rows={rows}
289
- columns={tableColumns}
290
- onCellsChanged={handleCellsChanged}
291
- enableFillHandle={true}
292
- enableRangeSelection={true}
293
- horizontalStickyBreakpoint={120}
294
- // stickyLeftColumns={1}
295
- // onFocusLocationChanging={(location) => {
296
- // return false;
297
- // }}
298
- {...reactGridProps}
299
- onFocusLocationChanging={(cell: any) => {
300
- const datatypeId = cell?.columnId + cell?.rowId;
301
- window.gridEditId = datatypeId;
302
-
303
- if (["_$actions", "rowSelection"]?.includes(cell?.columnId)) {
304
- return false;
305
- }
306
-
307
- if (reactGridProps?.onFocusLocationChanging) {
308
- return reactGridProps?.onFocusLocationChanging(cell, rows);
309
- }
310
- return cell;
311
- }}
312
- customCellTemplates={{
313
- ...baseTemplate,
314
- ...reactGridProps?.customCellTemplates,
315
- _$actions: WidthWrap(
316
- {
317
- WrapComponent: ActionDom,
318
- },
319
- true,
320
- ),
321
- rowSelection: WidthWrap(
322
- {
323
- WrapComponent: CheckBoxDom,
324
- },
325
- true,
326
- ),
327
- Input: TextTemplate,
328
- Number: NumberTemplate,
329
- ExpandListTemplate: WidthWrap(
330
- {
331
- WrapComponent: ExpandListTemplate,
332
- },
333
- true,
334
- ),
335
- }}
336
-
337
- // onSelectionChanged={(newSelection) => {
338
- // console.log("选区发生变化", newSelection[0]);
339
- // }}
340
- />
341
- </div>
342
- </Spin>
343
- );
344
- });