@hzab/list-render 1.10.20-alpha.0 → 1.10.20

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,198 +0,0 @@
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,157 +0,0 @@
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
- };
@@ -1,71 +0,0 @@
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
- };
@@ -1,229 +0,0 @@
1
- import React, { useState, useCallback, useRef, useEffect } from "react";
2
- import { Card, Slider, Rate, Button } from "antd";
3
- import { createSchemaField } from "@formily/react";
4
- import { cloneDeep } from "lodash";
5
-
6
- import { antdComponents, customComponents } from "@hzab/form-render";
7
- import { getFormilyGlobalComponents } from "@hzab/utils/src/formily/global-components";
8
-
9
- import { Item, EditMode } from "./type";
10
-
11
- export const useEditTable = (props) => {
12
- const { rowFormMapRef, editingInofRef, topProps, idKey, columns, onEditSubmit } = props;
13
- const { editMode = "modal" } = topProps || {};
14
- const preIdRef = useRef("");
15
- const preIdxRef = useRef(null);
16
- const preRecordRef = useRef({});
17
-
18
- // 创建 formily 表单相关参数
19
- /** schema scope 解决父级无 schema Scope 导致 scope 对象刷新的问题 */
20
- const schemaScopeRef = useRef<{ _$tempData: Object }>();
21
- if (props.schemaScope && !schemaScopeRef.current) {
22
- schemaScopeRef.current = props.schemaScope;
23
- } else if (!schemaScopeRef.current) {
24
- schemaScopeRef.current = { _$tempData: {} };
25
- }
26
- if (!schemaScopeRef.current?._$tempData) {
27
- schemaScopeRef.current._$tempData = {};
28
- }
29
-
30
- const components = {
31
- // Upload,
32
- Card,
33
- Slider,
34
- Rate,
35
- ...antdComponents,
36
- ...customComponents,
37
- ...getFormilyGlobalComponents(),
38
- ...props.components,
39
- };
40
-
41
- const SchemaField = useCallback(
42
- createSchemaField({
43
- components,
44
- scope: {
45
- scenario: "tableRowForm",
46
- ...schemaScopeRef.current,
47
- },
48
- }),
49
- [],
50
- );
51
-
52
- // 是否可编辑状态逻辑处理
53
- const [editingId, setEditingId] = useState("");
54
- // 当前编辑的字段
55
- const [editingKey, setEditingKey] = useState("");
56
- /** 判断当前 行 是否处于编辑状态 */
57
- const isEditing = (record: Item) => record[idKey] === editingId;
58
- /** 判断当前 单元格 是否处于编辑状态 */
59
- const isEditingCell = (key) => key === editingKey;
60
- const editingFiledRef = useRef(null);
61
-
62
- // useEffect(() => {
63
- // if (editingId || editingKey) {
64
- // // HACK: try catch 解决 select 等表单项 focus 报错问题
65
- // try {
66
- // // HACK: setTimeout 解决执行先后顺序导致无法正常获取 dom 问题
67
- // setTimeout(() => {
68
- // editingFiledRef.current?.current?.focus?.();
69
- // }, 0);
70
- // } catch (error) {}
71
- // }
72
- // }, [editingId, editingKey]);
73
-
74
- /**
75
- * 点击编辑按钮
76
- * @param record
77
- */
78
- const onEdit = async (record: Partial<Item> & { key: React.Key }, key, opt = { fieldRef: null, index: null }) => {
79
- if (editMode == "modal") {
80
- return;
81
- }
82
- const { fieldRef } = opt || {};
83
- preRecordRef.current = record;
84
- const id = record[idKey];
85
- editingInofRef.current.editingRowId = id;
86
- editingInofRef.current.editingKey = key;
87
- const rowForm = rowFormMapRef.current.get(id);
88
- rowForm.readPretty = false;
89
- editingFiledRef.current = fieldRef;
90
- rowForm.values = record;
91
- rowForm?.setValues(record);
92
- preIdRef.current = id;
93
- preIdxRef.current = opt.index;
94
- setEditingId(id);
95
- setEditingKey(key);
96
- };
97
-
98
- /**
99
- * 点击编辑按钮
100
- * @param record
101
- */
102
- const onEditAFetch = async (record: Partial<Item> & { key: React.Key }, key, opt) => {
103
- if (editMode == "modal") {
104
- return;
105
- }
106
- const value = await (props.onEdit && props.onEdit(record));
107
- preRecordRef.current = value;
108
- preIdRef.current = record[idKey];
109
- preIdxRef.current = opt.index;
110
- onEdit.call(this, value, key, opt);
111
- };
112
-
113
- function onCancel() {
114
- onReset();
115
- setEditingId("");
116
- setEditingKey("");
117
- preRecordRef.current = {};
118
- preIdRef.current = "";
119
- editingFiledRef.current = null;
120
- }
121
-
122
- function onReset() {
123
- const preRowForm = rowFormMapRef.current.get(preIdRef.current);
124
- if (preRowForm) {
125
- // disabled 后设置会导致 readPretty 设置失效
126
- preRowForm.disabled = true;
127
- preRowForm.readPretty = true;
128
- // 取消数据重置为编辑前数据
129
- preRowForm.reset();
130
- preRowForm.values = preRecordRef.current;
131
- preRecordRef.current = {};
132
- editingInofRef.current.editingRowId = "";
133
- editingInofRef.current.editingKey = "";
134
- }
135
- }
136
-
137
- /**
138
- * 保存数据
139
- * field 当前编辑的项
140
- * 当前数据的 id
141
- */
142
- const onEditSave = async ({ field, id, dataIndex }) => {
143
- const rowForm = rowFormMapRef.current.get(id);
144
- try {
145
- // 点击保存,数据抛出
146
- (await rowForm?.validate()) as Item;
147
- onEditSubmit && (await onEditSubmit(rowForm.values, { field, id, dataIndex }));
148
- // 清除编辑目标
149
- setEditingId("");
150
- setEditingKey("");
151
- rowForm.disabled = true;
152
- rowForm.readPretty = true;
153
- onReset();
154
- } catch (errInfo) {
155
- console.error("Validate Failed:", errInfo);
156
- }
157
- };
158
-
159
- const mergedColumns = cloneDeep(columns)?.map((col) => {
160
- const isActions = col.key === "_$actions";
161
- if (!col.editable && !isActions) {
162
- return col;
163
- }
164
-
165
- const resCol = {
166
- ...col,
167
- onCell: (record: Item, ...args) => {
168
- let editing = false;
169
- if (editMode === "table-line-show") {
170
- editing = true;
171
- } else if (editMode === "cell") {
172
- editing = isEditing(record) && isEditingCell(col.dataIndex);
173
- } else {
174
- editing = isEditing(record);
175
- }
176
- return {
177
- ...(col.onCell ? col.onCell(record, ...args) : {}),
178
- record,
179
- components,
180
- SchemaField,
181
- // 函数获取解决 cloneDepp 报错问题
182
- getField: col.getField,
183
- dataIndex: col.dataIndex,
184
- title: col.title,
185
- editable: col.editable,
186
- editing,
187
- topProps: props.topProps,
188
- onEdit: onEditAFetch,
189
- onEditSave,
190
- onCancel,
191
- };
192
- },
193
- };
194
- // 操作列编辑态改成保存、取消按钮
195
- if (isActions) {
196
- resCol.render = (record, index) => {
197
- // 编辑态操作栏变成保存和取消按钮
198
- if (editMode === "line" && record[idKey] === editingId) {
199
- return (
200
- <div className="edit-table-actions">
201
- <Button
202
- type="link"
203
- onClick={() => {
204
- onEditSave({ field: undefined, dataIndex: undefined, id: record[idKey] });
205
- }}
206
- >
207
- 保存
208
- </Button>
209
- <Button type="text" onClick={onCancel}>
210
- 取消
211
- </Button>
212
- </div>
213
- );
214
- }
215
- return col.render(record, index);
216
- };
217
- }
218
- return resCol;
219
- });
220
-
221
- return {
222
- onEditAFetch,
223
- onEdit,
224
- onEditSave,
225
- onEditCancel: onCancel,
226
- SchemaField,
227
- mergedColumns,
228
- };
229
- };
@@ -1,6 +0,0 @@
1
- export interface Item {
2
- id: string;
3
- key: string;
4
- }
5
-
6
- export type EditMode = "modal" | "line" | "line-cell" | "cell" | "table-line-show";
@@ -1,17 +0,0 @@
1
- import { createContext, useContext } from "react";
2
-
3
- interface TableFormilyContextType {
4
- rowFormMapRef;
5
- editingInofRef;
6
- }
7
-
8
- // 创建行上下文
9
- export const TableFormilyContext = createContext<TableFormilyContextType | null>(null);
10
-
11
- export const useTableFormilyContext = () => {
12
- const context = useContext(TableFormilyContext);
13
- if (!context) {
14
- throw new Error("useTableFormilyContext must be used within TableFormilyContext.Provider");
15
- }
16
- return context;
17
- };