@hzab/list-render 1.10.19 → 1.10.20-alpha.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.
@@ -0,0 +1,95 @@
1
+ import { Form, Table, Button, Popconfirm, Tooltip, Checkbox, Popover } from "antd";
2
+
3
+ /**
4
+ * 编辑按钮隐藏
5
+ */
6
+ export const editModeHideList = ["cell", "line-cell"];
7
+
8
+ export function TableActions(props) {
9
+ const {
10
+ text,
11
+ record,
12
+ index,
13
+ topProps,
14
+ tableConf,
15
+ colConf,
16
+ onEditByTable,
17
+ onDetail,
18
+ onEdit,
19
+ onDel,
20
+ onSearch,
21
+ getList,
22
+ } = props;
23
+ const { idKey = "id", i18n, Slots, editMode = "modal" } = topProps || {};
24
+ const { tableDel = "删除", tableEdit = "编辑", tableDelTip = "确认删除该项?", tableDetail = "详情" } = i18n || {};
25
+
26
+ const slotProps = { text, record, index, onEdit: onEdit, onDel: onDel, onSearch, getList };
27
+
28
+ if (Slots?.tableActionsSlot) {
29
+ return <Slots.tableActionsSlot {...slotProps} />;
30
+ }
31
+
32
+ const { hasEdit, hasDel, hasDelTips, hasDetail = false } = tableConf || {};
33
+
34
+ // 编辑按钮权限
35
+ const _hasEdit =
36
+ !editModeHideList.includes(editMode) &&
37
+ (hasEdit && typeof hasEdit === "function" ? hasEdit(record, index) : hasEdit !== false);
38
+
39
+ // 详情按钮权限
40
+ const _hasDetail = hasDetail && typeof hasDetail === "function" ? hasDetail(record, index) : hasDetail !== false;
41
+
42
+ // 删除按钮权限
43
+ const _hasDel = hasDel && typeof hasDel === "function" ? hasDel(record, index) : hasDel !== false;
44
+
45
+ // 删除按钮提示
46
+ const delTips =
47
+ hasDelTips && typeof hasDelTips === "function" ? hasDelTips(record, index) : hasDelTips || tableDelTip;
48
+
49
+ return (
50
+ <div style={{ width: colConf?.width, maxWidth: "100%" }}>
51
+ {Slots?.actionPrefixSlot && <Slots.actionPrefixSlot {...slotProps} />}
52
+ {_hasDetail ? (
53
+ <Button
54
+ type="link"
55
+ onClick={() => {
56
+ onDetail && onDetail(record, index);
57
+ }}
58
+ >
59
+ {tableDetail}
60
+ </Button>
61
+ ) : null}
62
+ {_hasEdit ? (
63
+ <Button
64
+ type="link"
65
+ onClick={() => {
66
+ onEdit && onEdit(record, index);
67
+ if (editMode == "line") {
68
+ // 整行编辑,编辑按钮在操作列的模式下表单数据回填
69
+ return onEditByTable(record, record[idKey]);
70
+ }
71
+ }}
72
+ >
73
+ {tableEdit}
74
+ </Button>
75
+ ) : null}
76
+ {Slots?.actionCenterSlot && <Slots.actionCenterSlot {...slotProps} />}
77
+ {_hasDel ? (
78
+ <Popconfirm
79
+ placement="topRight"
80
+ title={delTips}
81
+ onConfirm={() => {
82
+ onDel && onDel(record, index);
83
+ }}
84
+ >
85
+ <Button type="link" danger>
86
+ {tableDel}
87
+ </Button>
88
+ </Popconfirm>
89
+ ) : null}
90
+ {Slots?.actionSuffixSlot && <Slots.actionSuffixSlot {...slotProps} />}
91
+ </div>
92
+ );
93
+ }
94
+
95
+ export default TableActions;
@@ -1,13 +1,10 @@
1
- import { useEffect, useState, useMemo, useRef, forwardRef, useImperativeHandle } from "react";
1
+ import { useEffect, useState, useRef, forwardRef, useImperativeHandle, Fragment, useMemo } from "react";
2
2
  import { Form, Table, Button, Popconfirm, Tooltip, Checkbox, Popover } from "antd";
3
3
  import { QuestionCircleOutlined, FilterOutlined, SettingOutlined, MenuOutlined } from "@ant-design/icons";
4
4
  import { SortableContainer, SortableElement, SortableHandle } from "react-sortable-hoc";
5
5
  import { arrayMoveImmutable } from "array-move";
6
6
  import _, { isFunction } from "lodash";
7
7
 
8
- import { FormProvider, FormConsumer } from "@formily/react";
9
- import { createForm, onFormValuesChange, onFieldValueChange } from "@formily/core";
10
-
11
8
  import EnumRender from "@hzab/formily-result-utils/src/components/EnumRender";
12
9
  import { SHOW_MODE_TYPES } from "@hzab/formily-result-utils/src/common/constant";
13
10
  import { FormilyField } from "../components/Formily/FormilyField";
@@ -16,14 +13,19 @@ import { getColRender } from "../common/formily-utils";
16
13
  import { getVal, getFieldList } from "../common/utils";
17
14
  import { handleReactions } from "../common/handleReactions";
18
15
 
19
- import { useEditTable, EditableCell } from "../components/Formily/FormilyEditTable";
16
+ import { useEditTable } from "../components/Formily/FormilyEditTable";
17
+ import { EditTableRow } from "../components/Formily/FormilyEditTable/EditTableRow";
18
+ import { EditableCell } from "../components/Formily/FormilyEditTable/EditTableCell";
19
+ import { TableFormilyContext } from "../components/Formily/FormilyEditTable/useTableFormilyContext";
20
+ import TableActions from "./TableActions";
20
21
 
21
22
  import "./index.less";
22
23
 
23
24
  const scenario = "table-render";
24
25
 
25
26
  const TableRender = forwardRef(function (props, tableRef) {
26
- const { topProps, config = {}, query = {}, i18n, setList } = props;
27
+ const { topProps, config = {}, query = {}, i18n, setList, schema } = props;
28
+ const propsSchema = schema?.schema;
27
29
  const { tableDel = "删除", tableEdit = "编辑", tableDelTip = "确认删除该项?", tableDetail = "详情" } = i18n || {};
28
30
  const {
29
31
  dragColConf = {},
@@ -35,23 +37,36 @@ const TableRender = forwardRef(function (props, tableRef) {
35
37
  isShowTableFilter = false,
36
38
  isTableSortXIdex = false,
37
39
  } = config || {};
38
- const { editMode = "modal" } = topProps || {};
39
- const isEditTable = editMode !== "modal";
40
+ const [_list, _setList] = useState(props.list);
41
+ const antdTableRef = useRef();
42
+ const rowFormMapRef = useRef(new Map());
43
+ const editingInofRef = useRef({
44
+ editingRowId: "",
45
+ editingKey: "",
46
+ });
47
+
40
48
  useImperativeHandle(tableRef, () => ({
41
49
  onEditByTable,
42
50
  }));
43
51
 
52
+ useEffect(() => {
53
+ _setList(props.list);
54
+ // 数据清除问题,避免分页数据量持续累计过于庞大
55
+ rowFormMapRef.current.clear();
56
+ }, [props.list]);
57
+
44
58
  const [columns, setColumns] = useState([]);
45
59
  const [columnList, setColumnList] = useState([]);
46
60
  const DragHandle = SortableHandle(() => <MenuOutlined style={{ cursor: "grab", color: "#999" }} />);
47
61
 
48
- const SortableItem = SortableElement((props) => <tr {...props} />);
62
+ const SortableItem = SortableElement((props) => <Fragment children={props.children} />);
49
63
  const SortableBody = SortableContainer((props) => <tbody {...props} />);
50
64
 
51
65
  const onSortEnd = ({ oldIndex, newIndex }) => {
52
66
  if (oldIndex !== newIndex) {
53
67
  const newData = arrayMoveImmutable(props.list.slice(), oldIndex, newIndex).filter((el) => !!el);
54
68
  setList([...newData]);
69
+ _setList([...newData]);
55
70
  dargEndBack && dargEndBack(newData, query);
56
71
  }
57
72
  };
@@ -71,38 +86,27 @@ const TableRender = forwardRef(function (props, tableRef) {
71
86
  fieldSchemas: {},
72
87
  });
73
88
 
74
- const formRender = useMemo(
75
- () =>
76
- createForm({
77
- initialValues: props.initialValues,
78
- // 禁用状态(注意,自定义组件组件自行获取对应的状态)
79
- readOnly: props.readOnly,
80
- disabled: props.disabled,
81
- ...(props.formOptions || {}),
82
- effects(...args) {
83
- props.onFormValuesChange && onFormValuesChange(props.onFormValuesChange);
84
- props.onFieldValueChange && onFieldValueChange("*", props.onFieldValueChange);
85
- props.formOptions?.effects && props.formOptions?.effects(...args);
86
- },
87
- }),
88
- [],
89
- );
90
- const { onEdit: onEditByTable, mergedColumns } = useEditTable({
89
+ const {
90
+ onEditSave,
91
+ onEdit: onEditByTable,
92
+ mergedColumns,
93
+ } = useEditTable({
91
94
  idKey: props.idKey,
92
95
  columns,
93
96
  onEdit: props.onEdit,
94
97
  onEditSubmit: props.onEditSubmit,
95
- formRender,
96
98
  components: props.components,
97
99
  schemaScope: props.schemaScope,
98
100
  topProps: props.topProps,
101
+ rowFormMapRef,
102
+ editingInofRef,
99
103
  });
100
104
 
101
105
  useEffect(() => {
102
- if (!(props.schema && props.schema.properties)) {
106
+ if (!propsSchema.properties) {
103
107
  return;
104
108
  }
105
- const fieldList = getFieldList(props.schema, [], { ...props.getFieldListOpt, formilyRef }, isTableSortXIdex);
109
+ const fieldList = getFieldList(propsSchema, [], { ...props.getFieldListOpt, formilyRef }, isTableSortXIdex);
106
110
  const columns = [];
107
111
 
108
112
  // 序号列
@@ -125,16 +129,31 @@ const TableRender = forwardRef(function (props, tableRef) {
125
129
  }
126
130
 
127
131
  const { Slots = {} } = props;
128
- const _fieldList = handleReactions(fieldList, {
129
- scope: props.schemaScope,
130
- formilyRef,
131
- });
132
+ const _fieldList = fieldList;
132
133
  _fieldList.forEach((field, colIndex) => {
133
134
  const fieldSchemas = formilyRef.current?.fields;
135
+ if (!field["x-decorator-props"]) {
136
+ field["x-decorator-props"] = {};
137
+ }
138
+ // 存储原始的 pattern,用于行内编辑还原数据
139
+ field["x-decorator-props"]._sourcePattern = field["x-pattern"];
134
140
  if (field.inTable !== false) {
135
141
  const { name, title } = field;
136
142
  const comName = field["x-component"];
137
143
 
144
+ const decoratorProps = field["x-decorator-props"] || {};
145
+ let _title = title;
146
+ if (decoratorProps.tooltip) {
147
+ _title = (
148
+ <span className="col-title-tooltip-wrap inline-block-max-w">
149
+ {_title}
150
+ <Tooltip className="col-title-tooltip" title={decoratorProps.tooltip}>
151
+ <QuestionCircleOutlined className="col-title-tooltip-icon" />
152
+ </Tooltip>
153
+ </span>
154
+ );
155
+ }
156
+
138
157
  let _colConf = {};
139
158
 
140
159
  if (props.config?.colConf && props.config?.colConf[name]) {
@@ -204,22 +223,6 @@ const TableRender = forwardRef(function (props, tableRef) {
204
223
  };
205
224
  }
206
225
 
207
- let _title = isFunction(title) ? title() : title;
208
- if (_colConf?.title) {
209
- _title = isFunction(_colConf?.title) ? _colConf?.title() : _colConf?.title;
210
- }
211
- const decoratorProps = field["x-decorator-props"] || {};
212
- if (decoratorProps.tooltip) {
213
- _title = (
214
- <span className="col-title-tooltip-wrap inline-block-max-w">
215
- {_title}
216
- <Tooltip className="col-title-tooltip" title={decoratorProps.tooltip}>
217
- <QuestionCircleOutlined className="col-title-tooltip-icon" />
218
- </Tooltip>
219
- </span>
220
- );
221
- }
222
-
223
226
  columns.push({
224
227
  // field, // HACK: 直接传入 field 在 title 传入 ReactNode,内部深克隆导致页面报错白屏。使用函数获取解决
225
228
  getField: () => field,
@@ -227,8 +230,8 @@ const TableRender = forwardRef(function (props, tableRef) {
227
230
  ..._colConf,
228
231
  onCell: (record, rowIndex) =>
229
232
  _colConf?.onCell?.({ ...record, _field: { ...field, ...(fieldSchemas?.[name] || {}) } }, rowIndex) || {},
230
- // 函数式传入,解决 title ReactNode 传入报错问题(table 组件内部对 columns 进行 lodash.deepClone 导致 ReactNode 变成对象无法正常渲染) Uncaught TypeError: this.queryFeedbacks is not a function
231
- title: () => _title,
233
+ // 函数式传入,解决 title ReactNode 传入报错问题
234
+ title: () => (isFunction(_colConf?.title) ? _colConf?.title() : _title),
232
235
  key: name,
233
236
  dataIndex: name,
234
237
  render: getColRender(colRender),
@@ -246,71 +249,23 @@ const TableRender = forwardRef(function (props, tableRef) {
246
249
  title: "操作",
247
250
  key: "_$actions",
248
251
  render: getColRender(function (text, record, index) {
249
- const { onEdit, onDel, onSearch, getList } = props;
250
- const slotProps = { text, record, index, onEdit: onEdit, onDel: onDel, onSearch, getList };
251
-
252
- if (Slots?.tableActionsSlot) {
253
- return <Slots.tableActionsSlot {...slotProps} />;
254
- }
255
-
256
- const { editMode = "modal" } = props.topProps || {};
257
- // 编辑按钮权限
258
- const _hasEdit =
259
- editMode !== "cell" &&
260
- editMode !== "line-cell" &&
261
- (hasEdit && typeof hasEdit === "function" ? hasEdit(record, index) : hasEdit !== false);
262
-
263
- //详情按钮权限
264
- const _hasDetail =
265
- hasDetail && typeof hasDetail === "function" ? hasDetail(record, index) : hasDetail !== false;
266
-
267
- //删除按钮权限
268
- const _hasDel = hasDel && typeof hasDel === "function" ? hasDel(record, index) : hasDel !== false;
269
-
270
- //删除按钮提示
271
- const delTips =
272
- hasDelTips && typeof hasDelTips === "function" ? hasDelTips(record, index) : hasDelTips || tableDelTip;
273
-
274
- return (
275
- <div style={{ width: _colConf?.width, maxWidth: "100%" }}>
276
- {Slots?.actionPrefixSlot && <Slots.actionPrefixSlot {...slotProps} />}
277
- {_hasDetail ? (
278
- <Button
279
- type="link"
280
- onClick={() => {
281
- props.onDetail && props.onDetail(record, index);
282
- }}
283
- >
284
- {tableDetail}
285
- </Button>
286
- ) : null}
287
- {_hasEdit ? (
288
- <Button
289
- type="link"
290
- onClick={() => {
291
- props.onEdit && props.onEdit(record, index);
292
- }}
293
- >
294
- {tableEdit}
295
- </Button>
296
- ) : null}
297
- {Slots?.actionCenterSlot && <Slots.actionCenterSlot {...slotProps} />}
298
- {_hasDel ? (
299
- <Popconfirm
300
- placement="topRight"
301
- title={delTips}
302
- onConfirm={() => {
303
- props.onDel && props.onDel(record, index);
304
- }}
305
- >
306
- <Button type="link" danger>
307
- {tableDel}
308
- </Button>
309
- </Popconfirm>
310
- ) : null}
311
- {Slots?.actionSuffixSlot && <Slots.actionSuffixSlot {...slotProps} />}
312
- </div>
313
- );
252
+ const { onDetail, onEdit, onDel, onSearch, getList } = props;
253
+ const cProps = {
254
+ text,
255
+ record,
256
+ index,
257
+ Slots,
258
+ onEdit,
259
+ onDel,
260
+ onDetail,
261
+ onSearch,
262
+ onEditByTable,
263
+ getList,
264
+ tableConf: props.config,
265
+ colConf: _colConf,
266
+ topProps,
267
+ };
268
+ return <TableActions {...cProps} />;
314
269
  }),
315
270
  });
316
271
  }
@@ -327,12 +282,7 @@ const TableRender = forwardRef(function (props, tableRef) {
327
282
  }
328
283
  setColumns(columns);
329
284
  setColumnList(columns);
330
- }, [props.schema, props.config]);
331
-
332
- // 解决 FormilyField 中无相关参数报错的问题。自定义参数都从这里传入
333
- const reactionOpts = {
334
- scenario: scenario,
335
- };
285
+ }, [propsSchema, props.config]);
336
286
 
337
287
  const onChange = (e, col) => {
338
288
  if (e.target.checked) {
@@ -346,38 +296,67 @@ const TableRender = forwardRef(function (props, tableRef) {
346
296
  };
347
297
 
348
298
  const tableProps = {
299
+ ref: antdTableRef,
349
300
  className: "table-render",
350
301
  rowKey: props.idKey || "id",
351
302
  rowSelection: config?.rowSelection,
352
303
  columns: columns,
353
- dataSource: props.list,
304
+ dataSource: _list,
354
305
  pagination: false,
355
306
  scroll: config.scroll,
356
307
  expandable: config.expandable,
357
308
  loading: props.loading,
358
- onRow: config?.onRow,
359
- topProps: props.topProps,
360
309
  ...props.tableProps,
310
+ onRow: (record, index) => {
311
+ const _onRow = config?.onRow ?? props.tableProps?.onRow;
312
+ const _onRowRes = _onRow && _onRow(record, index);
313
+ return {
314
+ ..._onRowRes,
315
+ record,
316
+ id: record[props.idKey || "id"],
317
+ rowFormMapRef,
318
+ editingInofRef,
319
+ components: props.components,
320
+ topProps,
321
+ onEditSave,
322
+ };
323
+ },
324
+ topProps: props.topProps,
361
325
  };
362
326
 
363
- if (isDargTable) {
364
- tableProps.components = {
365
- body: {
366
- wrapper: DraggableContainer,
367
- row: DraggableBodyRow,
368
- },
369
- };
370
- }
327
+ tableProps.columns = mergedColumns;
371
328
 
372
- if (isEditTable) {
373
- tableProps.columns = mergedColumns;
374
- tableProps.components = {
329
+ // useMemo 解决 row 重复渲染问题
330
+ const tableComponents = useMemo(
331
+ () => ({
375
332
  body: {
376
333
  ...tableProps?.components?.body,
377
334
  cell: EditableCell,
335
+ row: isDargTable
336
+ ? ({ rowFormMapRef, components, topProps, ...props }) => {
337
+ // 拖拽
338
+ return (
339
+ <DraggableBodyRow {...props}>
340
+ <EditTableRow rowFormMapRef={rowFormMapRef} components={components} topProps={topProps} {...props} />
341
+ </DraggableBodyRow>
342
+ );
343
+ }
344
+ : EditTableRow,
345
+ ...(isDargTable
346
+ ? {
347
+ wrapper: DraggableContainer,
348
+ }
349
+ : {}),
378
350
  },
379
- };
380
- }
351
+ }),
352
+ [],
353
+ );
354
+ tableProps.components = tableComponents;
355
+
356
+ // 解决 FormilyField 中无相关参数报错的问题。自定义参数都从这里传入
357
+ const reactionOpts = {
358
+ scenario: scenario,
359
+ };
381
360
 
382
361
  return (
383
362
  <div className="table-render-wrap">
@@ -421,26 +400,24 @@ const TableRender = forwardRef(function (props, tableRef) {
421
400
  </Popover>
422
401
  </div>
423
402
  ) : null}
424
- {isEditTable ? (
425
- <FormProvider form={formRender}>
426
- <Form layout="vertical">
427
- <FormConsumer>{() => <Table {...tableProps} />}</FormConsumer>
428
- </Form>
429
- </FormProvider>
430
- ) : (
403
+ <TableFormilyContext.Provider
404
+ value={{
405
+ rowFormMapRef,
406
+ editingInofRef,
407
+ }}
408
+ >
431
409
  <Table {...tableProps} />
432
- )}
433
- <FormilyField
434
- schema={props.schema}
410
+ </TableFormilyContext.Provider>
411
+ {/* <FormilyField
412
+ schema={propsSchema}
435
413
  formilyRef={formilyRef}
436
414
  components={props.components}
437
- topProps={topProps}
438
415
  schemaScope={{
439
416
  ...reactionOpts,
440
417
  ...props.schemaScope,
441
418
  }}
442
419
  reactionOpts={reactionOpts}
443
- />
420
+ /> */}
444
421
  </div>
445
422
  );
446
423
  });