@hzab/list-render 1.10.18 → 1.10.20-alpha.0
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/CHANGELOG.md +5 -0
- package/README.md +15 -4
- package/package.json +3 -3
- package/src/EditArrayTable/index.less +11 -0
- package/src/EditArrayTable/index.tsx +198 -0
- package/src/components/Formily/{FormilyEditTable.tsx → --FormilyEditTable.tsx} +74 -3
- package/src/components/Formily/FormilyEditTable/EditTableCell.tsx +157 -0
- package/src/components/Formily/FormilyEditTable/EditTableRow.tsx +71 -0
- package/src/components/Formily/FormilyEditTable/index.tsx +229 -0
- package/src/components/Formily/FormilyEditTable/type.d.ts +6 -0
- package/src/components/Formily/FormilyEditTable/useTableFormilyContext.ts +17 -0
- package/src/components/Formily/SchemaToArrayTable.ts +266 -0
- package/src/list-render.jsx +18 -3
- package/src/pagination-render/index.jsx +53 -51
- package/src/table-render/index.jsx +117 -83
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -107,6 +107,16 @@ const listDM = useMemo(
|
|
|
107
107
|
| onEditReqVerify | Function | 否 | - | 编辑态保存时额外的规则校验函数,返回 Promise 的 resolve 或 reject 用于继续执行或停止执行 |
|
|
108
108
|
|
|
109
109
|
- fetchOnEdit 展示编辑弹框时,是否会调用一次详情接口进行回填(某些场景下,列表接口只返回部分部分字段,只有详情接口会返回全部字段);若为 false,则会使用表格列表接口返回的 row 数据进行回填
|
|
110
|
+
- editMode
|
|
111
|
+
- modal 弹窗/抽屉编辑;
|
|
112
|
+
- table-edit 整个 table 一起编辑;
|
|
113
|
+
- table-edit-show 整个 table 可 一起编辑,直接显示表单;
|
|
114
|
+
- line 编辑整行,编辑按钮在操作列;
|
|
115
|
+
- line-show 编辑整行,直接显示表单,编辑按钮在操作列;
|
|
116
|
+
- line-cell 编辑整行,操作按钮在单元格;
|
|
117
|
+
- line-cell-show 编辑整行,直接显示表单,操作按钮在单元格;
|
|
118
|
+
- cell 编辑指定单元格
|
|
119
|
+
- cell-show 编辑指定单元格,直接显示表单
|
|
110
120
|
|
|
111
121
|
#### tableConf
|
|
112
122
|
|
|
@@ -255,9 +265,11 @@ const Slots = {
|
|
|
255
265
|
|
|
256
266
|
- 默认参数参考 antd pagination 组件
|
|
257
267
|
|
|
258
|
-
| 属性名称 | 属性类型 | 必须 | 默认值 | 描述
|
|
259
|
-
| --------------- | -------- | ---- | ----------------- |
|
|
260
|
-
| pageSizeOptions | Array | 否 | [10, 20, 50, 100] | 可选 pageSize 数组
|
|
268
|
+
| 属性名称 | 属性类型 | 必须 | 默认值 | 描述 |
|
|
269
|
+
| --------------- | -------- | ---- | ----------------- | ------------------------------------------- |
|
|
270
|
+
| pageSizeOptions | Array | 否 | [10, 20, 50, 100] | 可选 pageSize 数组 |
|
|
271
|
+
| isAllSelect | boolean | 否 | false | 是否使用全部 |
|
|
272
|
+
| isAllSelectKey | string | 否 | "isAllSelect" | 选中全部时告知后端的字段名称,实际值为 true |
|
|
261
273
|
|
|
262
274
|
#### getFieldListOpt
|
|
263
275
|
|
|
@@ -566,7 +578,6 @@ async function test() {
|
|
|
566
578
|
## 命令
|
|
567
579
|
|
|
568
580
|
- Mac 执行该命令,设置 pre-commit 为可执行文件
|
|
569
|
-
|
|
570
581
|
- npm run mac-chmod
|
|
571
582
|
- chmod +x .husky && chmod +x .husky/pre-commit
|
|
572
583
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hzab/list-render",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.20-alpha.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "src",
|
|
6
6
|
"scripts": {
|
|
@@ -26,12 +26,12 @@
|
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@ant-design/icons": "^4.8.1",
|
|
28
28
|
"@hzab/data-model": "^1.7.4",
|
|
29
|
-
"@hzab/form-render": "^1.
|
|
29
|
+
"@hzab/form-render": "^1.7.12",
|
|
30
30
|
"@hzab/formily-result-utils": "^1.2.0",
|
|
31
31
|
"@hzab/permissions": "^1.0.0",
|
|
32
32
|
"@hzab/schema-descriptions": "^1.3.0",
|
|
33
|
+
"@hzab/utils": "^1.0.16",
|
|
33
34
|
"@hzab/webpack-config": "^0.7.2",
|
|
34
|
-
"@hzab/utils": "^1.0.7",
|
|
35
35
|
"@types/react": "^17.0.62",
|
|
36
36
|
"@types/react-dom": "^17.0.20",
|
|
37
37
|
"antd": "^4.24.12",
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { useEffect, useMemo, useRef, useState, forwardRef, useImperativeHandle } from "react";
|
|
2
|
+
import { Button } from "antd";
|
|
3
|
+
import { cloneDeep } from "lodash";
|
|
4
|
+
import { Schema } from "@formily/json-schema";
|
|
5
|
+
|
|
6
|
+
import FormRender from "@hzab/form-render";
|
|
7
|
+
import { useIndex } from "@hzab/form-render/src/components/ArrayBase";
|
|
8
|
+
import SchemaToArrayTable from "../components/Formily/SchemaToArrayTable";
|
|
9
|
+
|
|
10
|
+
import "./index.less";
|
|
11
|
+
|
|
12
|
+
export interface IEditArrayTableProps {
|
|
13
|
+
topProps: {
|
|
14
|
+
editMode?: string;
|
|
15
|
+
fetchOnEdit?: boolean;
|
|
16
|
+
hasAction?: boolean;
|
|
17
|
+
hideMessage?: boolean;
|
|
18
|
+
};
|
|
19
|
+
config?: {
|
|
20
|
+
isDargTable?: boolean;
|
|
21
|
+
orderColType?: string;
|
|
22
|
+
};
|
|
23
|
+
schema: Schema;
|
|
24
|
+
list: Object[];
|
|
25
|
+
components: Object[];
|
|
26
|
+
schemaScope: Object;
|
|
27
|
+
getList: () => Promise<{ list: any[] }>;
|
|
28
|
+
onEditSubmit: (val) => void;
|
|
29
|
+
handleMessage: (msg) => void;
|
|
30
|
+
query: {
|
|
31
|
+
pageNum: number;
|
|
32
|
+
pageSize: number;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// TODO: 插槽、权限、拖拽、序号、行选择、列显隐、操作列
|
|
37
|
+
export const EditArrayTable = forwardRef(function (props: IEditArrayTableProps, parentRef) {
|
|
38
|
+
const { topProps, schemaScope, getList, handleMessage, config, query } = props;
|
|
39
|
+
const { hasAction, editMode } = topProps || {};
|
|
40
|
+
const { orderColType = "page" } = config || {};
|
|
41
|
+
|
|
42
|
+
console.log("config", config, query);
|
|
43
|
+
|
|
44
|
+
const [editing, setEditing] = useState(false);
|
|
45
|
+
const [loading, setLoading] = useState(false);
|
|
46
|
+
const formRef = useRef(null);
|
|
47
|
+
const preValRef = useRef(null);
|
|
48
|
+
const queryRef = useRef(props.query);
|
|
49
|
+
|
|
50
|
+
queryRef.current = query;
|
|
51
|
+
|
|
52
|
+
const schema = useMemo(() => {
|
|
53
|
+
const schemaToArrayTable = new SchemaToArrayTable({
|
|
54
|
+
schema: props.schema,
|
|
55
|
+
option: { hasAction, ...config },
|
|
56
|
+
});
|
|
57
|
+
return schemaToArrayTable.handleSchema();
|
|
58
|
+
}, [props.schema]);
|
|
59
|
+
|
|
60
|
+
const components = useMemo(() => {
|
|
61
|
+
return {
|
|
62
|
+
TableActions() {
|
|
63
|
+
return <div>TableActions</div>;
|
|
64
|
+
},
|
|
65
|
+
TableIndex() {
|
|
66
|
+
const index = useIndex();
|
|
67
|
+
// 序号列
|
|
68
|
+
if (orderColType === "page") {
|
|
69
|
+
return index + 1;
|
|
70
|
+
} else if (orderColType == "all") {
|
|
71
|
+
const { pageSize = 10, pageNum = 1 } = queryRef.current || {};
|
|
72
|
+
// 当前页数减1乘以每一页页数再加当前页序号+1
|
|
73
|
+
return (pageNum - 1) * pageSize + (index + 1);
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
},
|
|
77
|
+
...props.components,
|
|
78
|
+
};
|
|
79
|
+
}, [props.components, props.query.pageNum, props.query.pageSize]);
|
|
80
|
+
|
|
81
|
+
useImperativeHandle(
|
|
82
|
+
parentRef,
|
|
83
|
+
() => ({
|
|
84
|
+
formRef,
|
|
85
|
+
}),
|
|
86
|
+
[],
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
if (formRef.current) {
|
|
91
|
+
setVal(props.list);
|
|
92
|
+
}
|
|
93
|
+
}, [props.list]);
|
|
94
|
+
|
|
95
|
+
function getVal() {
|
|
96
|
+
return cloneDeep(formRef.current.formRender.values.arrayTable);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function setVal(val) {
|
|
100
|
+
// formRef.current.formRender.reset();
|
|
101
|
+
formRef.current.formRender.setValues({
|
|
102
|
+
arrayTable: cloneDeep(val),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function onEdit() {
|
|
107
|
+
setLoading(true);
|
|
108
|
+
if (topProps.fetchOnEdit !== false) {
|
|
109
|
+
// 获取当前列表最新数据
|
|
110
|
+
return getList()
|
|
111
|
+
.then((res) => {
|
|
112
|
+
handleEdit(res?.list);
|
|
113
|
+
return res;
|
|
114
|
+
})
|
|
115
|
+
.catch((err) => {
|
|
116
|
+
console.error("err", err);
|
|
117
|
+
handleMessage(err._message);
|
|
118
|
+
return Promise.reject(err);
|
|
119
|
+
});
|
|
120
|
+
} else {
|
|
121
|
+
const value = getVal();
|
|
122
|
+
handleEdit(value);
|
|
123
|
+
return Promise.resolve(value);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function handleEdit(data) {
|
|
128
|
+
// cloneDeep 避免受影响
|
|
129
|
+
preValRef.current = cloneDeep(data);
|
|
130
|
+
setVal(data);
|
|
131
|
+
setEditing(true);
|
|
132
|
+
formRef.current.formRender.fields.arrayTable.readPretty = false;
|
|
133
|
+
setLoading(false);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function onSubmit() {
|
|
137
|
+
setLoading(true);
|
|
138
|
+
try {
|
|
139
|
+
// 表单校验
|
|
140
|
+
await formRef.current?.formRender?.validate();
|
|
141
|
+
try {
|
|
142
|
+
await (props.onEditSubmit && props.onEditSubmit(getVal()));
|
|
143
|
+
onClose();
|
|
144
|
+
} catch (error) {}
|
|
145
|
+
} catch (error) {
|
|
146
|
+
console.error("Error validate: ", error);
|
|
147
|
+
!topProps.hideMessage && handleMessage("输入有误!");
|
|
148
|
+
}
|
|
149
|
+
setLoading(false);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function onClose() {
|
|
153
|
+
formRef.current.formRender.fields.arrayTable.readPretty = true;
|
|
154
|
+
setEditing(false);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function onCancel() {
|
|
158
|
+
onClose();
|
|
159
|
+
// 未提交,取消恢复原始数据
|
|
160
|
+
setVal(preValRef.current);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<div className="edit-array-table">
|
|
165
|
+
<div className="edit-array-table-head">
|
|
166
|
+
<div></div>
|
|
167
|
+
<div className="edit-array-table-actions">
|
|
168
|
+
{editing ? (
|
|
169
|
+
<>
|
|
170
|
+
<Button className="edit-array-table-submit" type="primary" onClick={onSubmit} loading={loading}>
|
|
171
|
+
提交
|
|
172
|
+
</Button>
|
|
173
|
+
<Button className="edit-array-table-cancel" onClick={onCancel} loading={loading}>
|
|
174
|
+
取消
|
|
175
|
+
</Button>
|
|
176
|
+
</>
|
|
177
|
+
) : (
|
|
178
|
+
<Button className="edit-array-table-edit" type="primary" onClick={onEdit} loading={loading}>
|
|
179
|
+
编辑
|
|
180
|
+
</Button>
|
|
181
|
+
)}
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
<FormRender
|
|
185
|
+
ref={formRef}
|
|
186
|
+
className="edit-array-table-form"
|
|
187
|
+
schema={schema}
|
|
188
|
+
components={components}
|
|
189
|
+
schemaScope={schemaScope}
|
|
190
|
+
initialValues={{}}
|
|
191
|
+
emptyValue={" "}
|
|
192
|
+
formOptions={{ readPretty: editMode !== "table-edit-show" }}
|
|
193
|
+
/>
|
|
194
|
+
</div>
|
|
195
|
+
);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
export default EditArrayTable;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import React, { useState, useCallback, useRef, useEffect } from "react";
|
|
1
|
+
import React, { useState, useCallback, useRef, useEffect, useMemo } from "react";
|
|
2
2
|
import { Card, Slider, Rate, Form, Button } from "antd";
|
|
3
3
|
import { EditOutlined, CheckOutlined, CloseOutlined } from "@ant-design/icons";
|
|
4
|
+
import { createForm, onFormValuesChange, onFieldValueChange } from "@formily/core";
|
|
4
5
|
import { createSchemaField, FormProvider, FormConsumer } from "@formily/react";
|
|
6
|
+
|
|
5
7
|
import { cloneDeep } from "lodash";
|
|
6
8
|
|
|
7
9
|
import { antdComponents, customComponents } from "@hzab/form-render";
|
|
@@ -13,6 +15,74 @@ export interface Item {
|
|
|
13
15
|
address: string;
|
|
14
16
|
}
|
|
15
17
|
|
|
18
|
+
export interface EditableRowProps extends React.HTMLAttributes<HTMLElement> {
|
|
19
|
+
SchemaField: any;
|
|
20
|
+
getField: () => {
|
|
21
|
+
type: string;
|
|
22
|
+
name: string;
|
|
23
|
+
};
|
|
24
|
+
editing: boolean;
|
|
25
|
+
dataIndex: string;
|
|
26
|
+
title: any;
|
|
27
|
+
inputType: "number" | "text";
|
|
28
|
+
record: Item;
|
|
29
|
+
index: number;
|
|
30
|
+
editable: boolean;
|
|
31
|
+
onEdit: (record: Partial<Item> & { key: React.Key }, dataIndex: string, opt: Object) => void;
|
|
32
|
+
onSave: (field: { type: string; name: string }) => void;
|
|
33
|
+
onCancel: () => void;
|
|
34
|
+
topProps: {
|
|
35
|
+
config: { hasEdit: boolean | Function };
|
|
36
|
+
editMode: "modal" | "line" | "line-cell" | "cell";
|
|
37
|
+
formConf: any;
|
|
38
|
+
};
|
|
39
|
+
children: React.ReactNode;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const EditableRow: React.FC<EditableRowProps> = ({
|
|
43
|
+
SchemaField,
|
|
44
|
+
getField,
|
|
45
|
+
editing,
|
|
46
|
+
dataIndex,
|
|
47
|
+
title,
|
|
48
|
+
inputType,
|
|
49
|
+
record,
|
|
50
|
+
index,
|
|
51
|
+
onEdit,
|
|
52
|
+
onSave,
|
|
53
|
+
onCancel,
|
|
54
|
+
editable,
|
|
55
|
+
topProps,
|
|
56
|
+
children,
|
|
57
|
+
...restProps
|
|
58
|
+
}) => {
|
|
59
|
+
const { formConf = {} } = topProps || {};
|
|
60
|
+
const formRender = useMemo(
|
|
61
|
+
() =>
|
|
62
|
+
createForm({
|
|
63
|
+
initialValues: record,
|
|
64
|
+
// 禁用状态(注意,自定义组件组件自行获取对应的状态)
|
|
65
|
+
readOnly: formConf.readOnly,
|
|
66
|
+
disabled: formConf.disabled,
|
|
67
|
+
...(formConf.formOptions || {}),
|
|
68
|
+
effects(...args) {
|
|
69
|
+
formConf.onFormValuesChange && onFormValuesChange(formConf.onFormValuesChange);
|
|
70
|
+
formConf.onFieldValueChange && onFieldValueChange("*", formConf.onFieldValueChange);
|
|
71
|
+
formConf.formOptions?.effects && formConf.formOptions?.effects(...args);
|
|
72
|
+
},
|
|
73
|
+
}),
|
|
74
|
+
[],
|
|
75
|
+
);
|
|
76
|
+
// return <tr {...restProps}>{children}</tr>;
|
|
77
|
+
return (
|
|
78
|
+
<FormProvider form={formRender}>
|
|
79
|
+
<Form layout="vertical" component={false}>
|
|
80
|
+
<FormConsumer>{() => <tr {...restProps}>{children}</tr>}</FormConsumer>
|
|
81
|
+
</Form>
|
|
82
|
+
</FormProvider>
|
|
83
|
+
);
|
|
84
|
+
};
|
|
85
|
+
|
|
16
86
|
export interface EditableCellProps extends React.HTMLAttributes<HTMLElement> {
|
|
17
87
|
SchemaField: any;
|
|
18
88
|
getField: () => {
|
|
@@ -32,6 +102,7 @@ export interface EditableCellProps extends React.HTMLAttributes<HTMLElement> {
|
|
|
32
102
|
topProps: {
|
|
33
103
|
config: { hasEdit: boolean | Function };
|
|
34
104
|
editMode: "modal" | "line" | "line-cell" | "cell";
|
|
105
|
+
isEditCell: (record) => boolean;
|
|
35
106
|
};
|
|
36
107
|
children: React.ReactNode;
|
|
37
108
|
}
|
|
@@ -56,12 +127,12 @@ export const EditableCell: React.FC<EditableCellProps> = ({
|
|
|
56
127
|
const field = getField && getField();
|
|
57
128
|
const fPattern = field?.["x-pattern"];
|
|
58
129
|
const fDisplay = field?.["x-display"];
|
|
59
|
-
const { editMode = "modal" } = topProps || {};
|
|
130
|
+
const { editMode = "modal", isEditCell } = topProps || {};
|
|
60
131
|
const { hasEdit } = topProps?.config || {};
|
|
61
132
|
const fieldRef = useRef();
|
|
62
133
|
|
|
63
134
|
// 弹窗编辑模式
|
|
64
|
-
if (editMode === "modal") {
|
|
135
|
+
if (editMode === "modal" || (typeof isEditCell === "function" && !isEditCell(record))) {
|
|
65
136
|
return <td {...restProps}>{children}</td>;
|
|
66
137
|
}
|
|
67
138
|
// 无编辑权限或禁止编辑
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import React, { useRef } from "react";
|
|
2
|
+
import { EditOutlined, CheckOutlined, CloseOutlined } from "@ant-design/icons";
|
|
3
|
+
import { useForm } from "@formily/react";
|
|
4
|
+
|
|
5
|
+
import { Item, EditMode } from "./type";
|
|
6
|
+
|
|
7
|
+
const submitHideList = ["line"];
|
|
8
|
+
|
|
9
|
+
export interface EditableCellProps extends React.HTMLAttributes<HTMLElement> {
|
|
10
|
+
SchemaField: any;
|
|
11
|
+
getField: () => {
|
|
12
|
+
type: string;
|
|
13
|
+
name: string;
|
|
14
|
+
component: string;
|
|
15
|
+
};
|
|
16
|
+
editing: boolean;
|
|
17
|
+
dataIndex: string;
|
|
18
|
+
title: any;
|
|
19
|
+
inputType: "number" | "text";
|
|
20
|
+
record: Item;
|
|
21
|
+
index: number;
|
|
22
|
+
editable: boolean;
|
|
23
|
+
onEdit: (record: Partial<Item> & { key: React.Key }, dataIndex: string, opt: Object) => void;
|
|
24
|
+
onEditSave: ({ field, id, dataIndex }) => void;
|
|
25
|
+
onCancel: () => void;
|
|
26
|
+
topProps: {
|
|
27
|
+
hasEdit: boolean | Function;
|
|
28
|
+
tableConf: { canEdit: Function };
|
|
29
|
+
editMode: EditMode;
|
|
30
|
+
idKey: "string";
|
|
31
|
+
};
|
|
32
|
+
components: any;
|
|
33
|
+
children: React.ReactNode;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const EditableCell: React.FC<EditableCellProps> = ({
|
|
37
|
+
SchemaField,
|
|
38
|
+
getField,
|
|
39
|
+
editing,
|
|
40
|
+
dataIndex,
|
|
41
|
+
title,
|
|
42
|
+
inputType,
|
|
43
|
+
record,
|
|
44
|
+
index,
|
|
45
|
+
onEdit,
|
|
46
|
+
onEditSave,
|
|
47
|
+
onCancel,
|
|
48
|
+
editable,
|
|
49
|
+
topProps,
|
|
50
|
+
children,
|
|
51
|
+
components,
|
|
52
|
+
...restProps
|
|
53
|
+
}) => {
|
|
54
|
+
const field = getField && getField();
|
|
55
|
+
const { idKey = "id", hasEdit, editMode = "modal" } = topProps || {};
|
|
56
|
+
const { canEdit } = topProps?.tableConf || {};
|
|
57
|
+
|
|
58
|
+
// 弹窗编辑模式
|
|
59
|
+
if (!field || (typeof canEdit === "function" && canEdit(record, { index, field }))) {
|
|
60
|
+
return <td {...restProps}>{children}</td>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const name = field?.name;
|
|
64
|
+
const fieldRef = useRef();
|
|
65
|
+
const fPattern = field?.["x-pattern"];
|
|
66
|
+
const fDisplay = field?.["x-display"];
|
|
67
|
+
const display = field?.["x-display"];
|
|
68
|
+
const disabled = display === "none" || display === "hidden";
|
|
69
|
+
|
|
70
|
+
const id = record?.[idKey];
|
|
71
|
+
// 无编辑权限或禁止编辑
|
|
72
|
+
const _hasEdit = hasEdit && typeof hasEdit === "function" ? hasEdit(record, index) : hasEdit !== false;
|
|
73
|
+
let _editable =
|
|
74
|
+
!disabled && _hasEdit && editable && !(fPattern === "disabled" || fPattern === "readOnly" || fDisplay === "none");
|
|
75
|
+
// 行内单元格编辑按钮
|
|
76
|
+
const showEditIcon = !editing && _editable && (editMode === "line-cell" || editMode === "cell");
|
|
77
|
+
const showSubmitIcon = !disabled && editing && !submitHideList.includes(editMode);
|
|
78
|
+
|
|
79
|
+
const editOpt = { index, field, fieldRef };
|
|
80
|
+
|
|
81
|
+
const form = useForm();
|
|
82
|
+
if (form.fields[name]) {
|
|
83
|
+
form.fields[name].pattern = disabled || !editing ? "readPretty" : field?.["x-pattern"] ?? "editable";
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 使用 Schema 渲染模式
|
|
87
|
+
return (
|
|
88
|
+
<td {...restProps}>
|
|
89
|
+
<div
|
|
90
|
+
className="editable-table-cell table-cell"
|
|
91
|
+
onDoubleClick={(e) => {
|
|
92
|
+
if (editMode == "modal") {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (editing) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
e?.preventDefault();
|
|
99
|
+
e?.stopPropagation();
|
|
100
|
+
onEdit(record, dataIndex, editOpt);
|
|
101
|
+
}}
|
|
102
|
+
onKeyDown={(e) => {
|
|
103
|
+
if (e.key === "Enter") {
|
|
104
|
+
e.preventDefault(); // 防止意外的表单提交
|
|
105
|
+
onEditSave && onEditSave({ field, id, dataIndex });
|
|
106
|
+
}
|
|
107
|
+
}}
|
|
108
|
+
>
|
|
109
|
+
<SchemaField
|
|
110
|
+
schema={{
|
|
111
|
+
type: "object",
|
|
112
|
+
properties: {
|
|
113
|
+
[name]: {
|
|
114
|
+
...field,
|
|
115
|
+
title: "",
|
|
116
|
+
["x-component-props"]: {
|
|
117
|
+
...field["x-component-props"],
|
|
118
|
+
ref: (ref) => {
|
|
119
|
+
if (field["x-component-props"] && typeof field["x-component-props"].ref === "function") {
|
|
120
|
+
field["x-component-props"].ref(ref);
|
|
121
|
+
}
|
|
122
|
+
if (ref) {
|
|
123
|
+
fieldRef.current = ref;
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
// 外部配置的禁用状态
|
|
128
|
+
"x-pattern": disabled || !editing ? "readPretty" : field?.["x-pattern"] ?? "editable",
|
|
129
|
+
// 外部配置的表单显隐状态,强制为 显示
|
|
130
|
+
"x-display": "visible",
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
}}
|
|
134
|
+
/>
|
|
135
|
+
{showEditIcon ? (
|
|
136
|
+
<EditOutlined
|
|
137
|
+
className="table-cell-edit-icon"
|
|
138
|
+
onClick={(e) => {
|
|
139
|
+
e?.preventDefault();
|
|
140
|
+
e?.stopPropagation();
|
|
141
|
+
onEdit(record, dataIndex, editOpt);
|
|
142
|
+
}}
|
|
143
|
+
/>
|
|
144
|
+
) : null}
|
|
145
|
+
{showSubmitIcon ? (
|
|
146
|
+
<div className="cell-editing-actions">
|
|
147
|
+
<CheckOutlined
|
|
148
|
+
className="table-cell-confirm-icon"
|
|
149
|
+
onClick={() => onEditSave({ field, id: record[topProps.idKey || "id"], dataIndex })}
|
|
150
|
+
/>
|
|
151
|
+
<CloseOutlined className="table-cell-cancel-icon" onClick={onCancel} />
|
|
152
|
+
</div>
|
|
153
|
+
) : null}
|
|
154
|
+
</div>
|
|
155
|
+
</td>
|
|
156
|
+
);
|
|
157
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { memo, useMemo } from "react";
|
|
2
|
+
import { Form } from "antd";
|
|
3
|
+
import { createForm, onFormValuesChange, onFieldValueChange, Field } from "@formily/core";
|
|
4
|
+
import { FormProvider, FormConsumer } from "@formily/react";
|
|
5
|
+
import { PreviewText } from "c-formily-antd/lib/preview-text";
|
|
6
|
+
|
|
7
|
+
import { Item, EditMode } from "./type";
|
|
8
|
+
|
|
9
|
+
export interface EditableRowProps extends React.HTMLAttributes<HTMLElement> {
|
|
10
|
+
rowFormMapRef;
|
|
11
|
+
editingInofRef;
|
|
12
|
+
record: Item;
|
|
13
|
+
editable: boolean;
|
|
14
|
+
disabled: boolean;
|
|
15
|
+
onEditSave;
|
|
16
|
+
topProps: {
|
|
17
|
+
config: { hasEdit: boolean | Function };
|
|
18
|
+
editMode: EditMode;
|
|
19
|
+
idKey: "string";
|
|
20
|
+
onFormValuesChange: (form: any) => void;
|
|
21
|
+
onFieldValueChange: (field, form: any) => void;
|
|
22
|
+
formOptions: {
|
|
23
|
+
effects;
|
|
24
|
+
};
|
|
25
|
+
tableConf: {
|
|
26
|
+
tableEmptyValue;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
children: React.ReactNode;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const EditTableRow: React.FC<EditableRowProps> = (props: EditableRowProps) => {
|
|
33
|
+
const { record, rowFormMapRef, editingInofRef, topProps, onEditSave, ...resetProps } = props;
|
|
34
|
+
const { idKey = "id", editMode } = topProps || {};
|
|
35
|
+
const rowId = props["data-row-key"];
|
|
36
|
+
const rowForm = useMemo(() => {
|
|
37
|
+
if (rowFormMapRef?.current?.get && rowFormMapRef.current.get(rowId)) {
|
|
38
|
+
// @ts-ignore
|
|
39
|
+
rowFormMapRef.current.get(rowId).readPretty = true;
|
|
40
|
+
return rowFormMapRef.current?.get(rowId);
|
|
41
|
+
}
|
|
42
|
+
const form = createForm({
|
|
43
|
+
initialValues: record,
|
|
44
|
+
// 只读模式,非编辑态默认为只读模式
|
|
45
|
+
readPretty: editingInofRef?.current?.editingRowId !== rowId,
|
|
46
|
+
...(topProps?.formOptions || {}),
|
|
47
|
+
effects(...args) {
|
|
48
|
+
topProps?.onFormValuesChange && onFormValuesChange(topProps.onFormValuesChange);
|
|
49
|
+
onFieldValueChange("*", (field: Field, form) => {
|
|
50
|
+
topProps.onFieldValueChange && topProps.onFieldValueChange(field, form);
|
|
51
|
+
});
|
|
52
|
+
topProps?.formOptions?.effects && topProps.formOptions?.effects(...args);
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
if (rowFormMapRef) {
|
|
56
|
+
rowFormMapRef.current.set(rowId, form);
|
|
57
|
+
}
|
|
58
|
+
return form;
|
|
59
|
+
}, [record]);
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<FormProvider form={rowForm}>
|
|
63
|
+
{/* 传入空值展示的字符串 */}
|
|
64
|
+
<PreviewText.Placeholder value={topProps?.tableConf?.tableEmptyValue || " "}>
|
|
65
|
+
<Form layout="vertical" component={false}>
|
|
66
|
+
<FormConsumer>{() => <tr {...resetProps}>{props.children}</tr>}</FormConsumer>
|
|
67
|
+
</Form>
|
|
68
|
+
</PreviewText.Placeholder>
|
|
69
|
+
</FormProvider>
|
|
70
|
+
);
|
|
71
|
+
};
|