@hzab/list-render 1.10.10 → 1.10.12-beta

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 CHANGED
@@ -1,3 +1,13 @@
1
+ # @hzab/list-render@1.10.12
2
+
3
+ fix: table 响应数据 去除 inTable == false 的字段
4
+ feat: schema title 支持传入 ReactNode
5
+ feat: schema clone 函数
6
+
7
+ # @hzab/list-render@1.10.11
8
+
9
+ fix: 行内编辑统一 onEdit 获取数据,单元格编辑支持传入其他参数
10
+
1
11
  # @hzab/list-render@1.10.10
2
12
 
3
13
  fix: 解决 FormModal 与 DetailModal 相互影响的问题
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hzab/list-render",
3
- "version": "1.10.10",
3
+ "version": "1.10.12-beta",
4
4
  "description": "",
5
5
  "main": "src",
6
6
  "scripts": {
@@ -27,15 +27,16 @@
27
27
  "@hzab/permissions": "^1.0.0",
28
28
  "@hzab/schema-descriptions": "^1.3.0",
29
29
  "@hzab/webpack-config": "^0.7.2",
30
+ "@hzab/utils": "^1.0.7",
30
31
  "@types/react": "^17.0.62",
31
32
  "@types/react-dom": "^17.0.20",
32
33
  "antd": "^4.24.12",
33
34
  "axios": "^1.4.0",
34
35
  "eslint": "^8.30.0",
35
- "mobx": "^6.7.0",
36
- "mobx-react": "^7.6.0",
37
36
  "less": "^4.1.3",
38
37
  "lodash": "^4.17.21",
38
+ "mobx": "^6.7.0",
39
+ "mobx-react": "^7.6.0",
39
40
  "react": "^17.0.2",
40
41
  "react-dom": "^17.0.2",
41
42
  "react-router-dom": "^6.8.1",
@@ -49,6 +50,7 @@
49
50
  "@hzab/form-render": ">=1.0.0",
50
51
  "@hzab/formily-result-utils": ">=1.2.0",
51
52
  "@hzab/schema-descriptions": ">=1.0.0",
53
+ "@hzab/utils": ">=1.0.7",
52
54
  "antd": "4.x",
53
55
  "axios": ">=1.4.0",
54
56
  "c-formily-antd": "2.3.1",
@@ -0,0 +1,63 @@
1
+ import React from "react";
2
+
3
+ /**
4
+ * 检测是否为原生 HTML DOM 节点
5
+ * @param {any} node 待检测对象
6
+ * @returns {boolean} 是否为原生 DOM 节点
7
+ */
8
+ function isHtmlDomNode(node) {
9
+ // 先判断浏览器环境,避免 SSR 报错;兼容 Node/HTMLElement 类型
10
+ return !!(typeof window !== "undefined" && node && (node instanceof HTMLElement || node instanceof Node));
11
+ }
12
+
13
+ /**
14
+ * 增强版 Formily Schema 克隆函数
15
+ * 解决 lodash cloneDeep 丢失 React DOM/原生 DOM 的问题,兼容多种特殊类型
16
+ * @param {object} schema 待克隆的 Formily Schema
17
+ * @returns {object} 克隆后的 Schema
18
+ */
19
+ export function cloneSchema(schema) {
20
+ // 1. 基础类型(null/undefined/字符串/数字/布尔)直接返回
21
+ if (schema === null || typeof schema !== "object") {
22
+ return schema;
23
+ }
24
+
25
+ // 2. React 虚拟DOM:直接保留原引用,不拷贝
26
+ if (React.isValidElement(schema)) {
27
+ return schema;
28
+ }
29
+
30
+ // 3. 原生 HTML DOM 节点:直接保留原引用
31
+ if (isHtmlDomNode(schema)) {
32
+ return schema;
33
+ }
34
+
35
+ // 4. 函数:Formily Schema 中的校验/格式化函数等,保留原引用
36
+ if (typeof schema === "function") {
37
+ return schema;
38
+ }
39
+
40
+ // 5. 日期对象:创建新的 Date 实例,保证值相同但引用不同
41
+ if (schema instanceof Date) {
42
+ return new Date(schema.getTime());
43
+ }
44
+
45
+ // 6. 正则对象:创建新的 RegExp 实例,保留源和标志
46
+ if (schema instanceof RegExp) {
47
+ return new RegExp(schema.source, schema.flags);
48
+ }
49
+
50
+ // 7. 数组:递归克隆每一项
51
+ if (Array.isArray(schema)) {
52
+ return schema.map((item) => cloneSchema(item));
53
+ }
54
+
55
+ // 8. 普通对象:递归克隆自有属性
56
+ const clonedObj = {};
57
+ for (const key in schema) {
58
+ if (Object.prototype.hasOwnProperty.call(schema, key)) {
59
+ clonedObj[key] = cloneSchema(schema[key]);
60
+ }
61
+ }
62
+ return clonedObj;
63
+ }
@@ -1,12 +1,13 @@
1
1
  import _ from "lodash";
2
- import { getFieldMap } from "./utils";
3
2
  import {
4
3
  isRunStr,
5
4
  handleSchemaStrVal,
6
5
  isScopeKey as formIsScopeKey,
7
6
  getScopeKeyVal,
8
7
  } from "@hzab/form-render/src/common/schema-handler";
8
+ import { cloneSchema } from "@hzab/utils/src/formily/cloneSchema";
9
9
  import { URL_PARAM_NAME } from "./constant";
10
+ import { getFieldMap } from "./utils";
10
11
 
11
12
  // ===================== 类型定义 =====================
12
13
 
@@ -72,7 +73,7 @@ export const handleQuerySchema = (opt) => {
72
73
  index += 1;
73
74
  }
74
75
 
75
- const fieldMap = getFieldMap(_.cloneDeep(schema));
76
+ const fieldMap = getFieldMap(cloneSchema(schema));
76
77
  filters?.forEach((key) => {
77
78
  const item = fieldMap[key];
78
79
  if (item) {
@@ -1,5 +1,6 @@
1
- import { cloneDeep } from "lodash";
2
1
  import { autorun, observable } from "@formily/reactive";
2
+
3
+ import { cloneSchema } from "@hzab/utils/src/formily/cloneSchema";
3
4
  import { getStateFunc } from "./formily-utils";
4
5
 
5
6
  /**
@@ -14,7 +15,7 @@ export function handleReactions(fieldList, opt = {}) {
14
15
  return fieldList;
15
16
  }
16
17
  const resList = [];
17
- cloneDeep(fieldList).forEach((item) => {
18
+ cloneSchema(fieldList).forEach((item) => {
18
19
  handleReaction(item, opt);
19
20
  resList.push(item);
20
21
  });
@@ -1,279 +1,281 @@
1
- import { Schema } from "@formily/json-schema";
2
- import _ from "lodash";
3
- import dayjs from "dayjs";
4
- import advancedFormat from "dayjs/plugin/advancedFormat";
5
- import weekOfYear from "dayjs/plugin/weekOfYear";
6
-
7
- dayjs.extend(advancedFormat);
8
- dayjs.extend(weekOfYear);
9
-
10
- const dateFormatEnum = {
11
- time: "YYYY-MM-DD HH:mm:ss",
12
- date: "YYYY-MM-DD",
13
- week: "YYYY w周",
14
- quarter: "YYYY年 Q季度",
15
- month: "YYYY-MM",
16
- year: "YYYY",
17
- };
18
-
19
- /**
20
- * 获取 field 对应的值
21
- * @param {Object} field schema 项
22
- * @param {Object} data 数据
23
- * @param {Object} opt 配置项
24
- * @returns
25
- */
26
- export function getVal(field = {}, data = {}, opt = {}) {
27
- const {} = opt;
28
- let val = _.get(data, field.name);
29
- const {} = field || {};
30
- const xComponent = field["x-component"];
31
- const xComponentProps = field["x-component-props"] || {};
32
-
33
- if (val && (xComponent === "DatePicker" || xComponent === "DatePicker.RangePicker")) {
34
- const { picker, showTime } = xComponentProps || {};
35
- const mode = showTime === true ? "time" : picker || "date";
36
- const _formatEnum = opt.dateFormatEnum || dateFormatEnum;
37
- const format = xComponentProps?.format || _formatEnum[mode];
38
-
39
- if (Array.isArray(val)) {
40
- return val.map((it) => getDateVal(it, format)).join(" ~ ");
41
- }
42
- return getDateVal(val, format);
43
- }
44
-
45
- if (val && (xComponent === "TimePicker" || xComponent === "TimePicker.RangePicker")) {
46
- const format = xComponentProps?.format || "HH:mm:ss";
47
- if (Array.isArray(val)) {
48
- return val.map((it) => dayjs(it).format(format)).join(" ~ ");
49
- }
50
- return dayjs(val).format(format);
51
- }
52
-
53
- if (xComponent === "Switch") {
54
- if (val === undefined || val === false || val === field.inactiveValue) {
55
- return field.inactiveText || "";
56
- }
57
- if (val === true || val === field.activeValue) {
58
- return field.activeText || "是";
59
- }
60
- return val;
61
- }
62
- if (typeof field.relation === "object") {
63
- const { key, name, label } = field.relation;
64
- return data[key]?.[name];
65
- }
66
-
67
- const dataSource = field?.dataSource || field.enum;
68
- if (
69
- (xComponent === "Select" || xComponent === "Radio.Group" || xComponent === "Checkbox.Group") &&
70
- Array.isArray(dataSource)
71
- ) {
72
- if (!Array.isArray(val)) {
73
- return getFieldOptItByVal(val, field, opt)?.label || val;
74
- } else if (Array.isArray(val)) {
75
- let _val = [];
76
- val.forEach((valIt) => {
77
- _val.push(getFieldOptItByVal(val, field, opt)?.label || valIt);
78
- });
79
- val = _val;
80
- }
81
- }
82
-
83
- if (Array.isArray(val)) {
84
- return val.join("、");
85
- }
86
-
87
- return val;
88
- }
89
-
90
- export function getDateVal(val, format) {
91
- return dayjs(val).format(format);
92
- }
93
-
94
- export function getFieldList(_schema, fieldList = [], opt = {}, isTableSortXIdex = false) {
95
- const schema = _schema?.schema || _schema;
96
-
97
- // 解决 schema 字符串可执行代码、变量等
98
- const properties = Schema.getOrderProperties(schema);
99
- const { boxList = [] } = opt || {};
100
- let _boxList = ["FormGrid", "FormGrid.GridColumn"];
101
- if (Array.isArray(boxList)) {
102
- _boxList = [..._boxList, ...boxList];
103
- } else if (boxList === false) {
104
- _boxList = [];
105
- }
106
-
107
- schema?.properties &&
108
- properties.forEach((item) => {
109
- const field = item.schema;
110
- if (!field.name) {
111
- field.name = item.key;
112
- }
113
- const componentName = field["x-component"];
114
- if (_boxList.includes(componentName)) {
115
- getFieldList(field, fieldList, opt);
116
- } else {
117
- fieldList.push(field);
118
- }
119
- });
120
- isTableSortXIdex && fieldList.sort((a, b) => a["x-index"] - b["x-index"]);
121
- return fieldList;
122
- }
123
-
124
- export function getFieldMap(_schema, fieldMap = {}) {
125
- // const fieldMap = _.keyBy(getFieldList(_schema), "name");
126
- const schema = _schema?.schema || _schema;
127
- schema?.properties &&
128
- Object.keys(schema?.properties).forEach((key) => {
129
- const field = schema?.properties[key];
130
- if (field["x-component"] === "FormGrid") {
131
- getFieldMap(field, fieldMap);
132
- } else if (field["x-component"] === "FormGrid.GridColumn") {
133
- getFieldMap(field, fieldMap);
134
- } else {
135
- fieldMap[key] = field;
136
- }
137
- });
138
-
139
- return fieldMap;
140
- }
141
-
142
- export function objToFormData(data) {
143
- const formData = new FormData();
144
- Object.keys(data)?.forEach((key) => {
145
- formData.set(key, data[key]);
146
- });
147
- return formData;
148
- }
149
-
150
- /**
151
- * 根据 val 获取对应的 options 项数据
152
- * @param {string|number|boolean} val
153
- * @param {Object} field
154
- */
155
- export const getFieldOptItByVal = function (val, field, opt) {
156
- if (!field) {
157
- return {};
158
- }
159
- const options = Array.isArray(field.enum)
160
- ? field.enum
161
- : Array.isArray(field.options)
162
- ? field.options
163
- : field.dataSource || [];
164
- return getOptItByVal(val, options, {
165
- fieldNames: field.fieldNames || field["x-component-props"]?.fieldNames,
166
- ...opt,
167
- });
168
- };
169
-
170
- /**
171
- * 根据 val 获取对应的 options 项数据,并进行数据归一化处理
172
- * value, label, children
173
- * @param {string|number|boolean} val
174
- * @param {Object} field
175
- */
176
- export const getOptItByVal = function (val, options, opt) {
177
- const { fieldNames } = opt || {};
178
- const { value = "value", label = "label", children = "children" } = fieldNames || {};
179
- for (let i = 0; i < options.length; i++) {
180
- const it = options[i];
181
- if (it?.[value] === val) {
182
- return {
183
- ...it,
184
- value: it?.[value],
185
- label: it?.[label],
186
- children: it?.[children],
187
- };
188
- }
189
- // 递归处理
190
- const _children = it?.[children];
191
- if (Array.isArray(_children) && _children.length > 0) {
192
- const child = getOptItByVal(val, _children, opt);
193
- return {
194
- ...child,
195
- value: child?.[value],
196
- label: child?.[label],
197
- children: child?.[children],
198
- };
199
- }
200
- }
201
- };
202
-
203
- /**
204
- * 移除 schema.properties 中包含 "inTable": false 的字段
205
- * @param {Object} data - 原始数据对象
206
- * @returns {Object} - 处理后的新对象
207
- */
208
-
209
- /**
210
- * 移除表格中标记为inTable:false的字段
211
- * @param {Object} data - 原始数据
212
- * @param {Object} [opt={}] - 配置选项
213
- * @param {Array} [opt.boxList=[]] - 需要递归处理的组件类型列表
214
- * @returns {Object} 处理后的数据
215
- */
216
-
217
- export function removeInTableFalseFields(_schema, opt = {}) {
218
- // 1. 深拷贝原始数据
219
- const result = _.cloneDeep(_schema);
220
-
221
- // 2. 获取schema对象(支持直接传入schema或包含schema的对象)
222
- const schema = result?.schema || result;
223
-
224
- // 3. 处理容器组件配置
225
- const { boxList = [] } = opt;
226
- const _boxList =
227
- boxList === false
228
- ? []
229
- : [
230
- "Card",
231
- "FormGrid",
232
- "ArrayCards",
233
- "Collapse",
234
- "Tabs",
235
- "FormGrid.GridColumn",
236
- ...(Array.isArray(boxList) ? boxList : []),
237
- ];
238
-
239
- // 4. 递归删除inTable:false的字段
240
- const processProperties = (properties) => {
241
- if (!properties || typeof properties !== "object") return;
242
-
243
- Object.keys(properties).forEach((key) => {
244
- const item = properties[key];
245
-
246
- // 处理容器组件递归
247
- if (item["x-component"] && _boxList.includes(item["x-component"])) {
248
- if (item.properties) {
249
- processProperties(item.properties);
250
- }
251
- }
252
- // 处理数组类型的子项
253
- else if (item.items?.properties) {
254
- processProperties(item.items.properties);
255
- }
256
- // 处理普通字段
257
- else if (item.inTable === false) {
258
- delete properties[key];
259
- }
260
- // 移除x-display
261
- else if (item["x-display"]) {
262
- delete item["x-display"];
263
- }
264
- });
265
- };
266
-
267
- // 5. 处理主properties
268
- if (schema.properties) {
269
- processProperties(schema.properties);
270
- }
271
-
272
- // 6. 移除form的布局属性
273
- if (result.form) {
274
- delete result.form.labelCol;
275
- delete result.form.wrapperCol;
276
- }
277
-
278
- return result;
279
- }
1
+ import { Schema } from "@formily/json-schema";
2
+ import _ from "lodash";
3
+ import dayjs from "dayjs";
4
+ import advancedFormat from "dayjs/plugin/advancedFormat";
5
+ import weekOfYear from "dayjs/plugin/weekOfYear";
6
+
7
+ import { cloneSchema } from "@hzab/utils/src/formily/cloneSchema";
8
+
9
+ dayjs.extend(advancedFormat);
10
+ dayjs.extend(weekOfYear);
11
+
12
+ const dateFormatEnum = {
13
+ time: "YYYY-MM-DD HH:mm:ss",
14
+ date: "YYYY-MM-DD",
15
+ week: "YYYY年 w周",
16
+ quarter: "YYYY年 Q季度",
17
+ month: "YYYY-MM",
18
+ year: "YYYY",
19
+ };
20
+
21
+ /**
22
+ * 获取 field 对应的值
23
+ * @param {Object} field schema 项
24
+ * @param {Object} data 数据
25
+ * @param {Object} opt 配置项
26
+ * @returns
27
+ */
28
+ export function getVal(field = {}, data = {}, opt = {}) {
29
+ const {} = opt;
30
+ let val = _.get(data, field.name);
31
+ const {} = field || {};
32
+ const xComponent = field["x-component"];
33
+ const xComponentProps = field["x-component-props"] || {};
34
+
35
+ if (val && (xComponent === "DatePicker" || xComponent === "DatePicker.RangePicker")) {
36
+ const { picker, showTime } = xComponentProps || {};
37
+ const mode = showTime === true ? "time" : picker || "date";
38
+ const _formatEnum = opt.dateFormatEnum || dateFormatEnum;
39
+ const format = xComponentProps?.format || _formatEnum[mode];
40
+
41
+ if (Array.isArray(val)) {
42
+ return val.map((it) => getDateVal(it, format)).join(" ~ ");
43
+ }
44
+ return getDateVal(val, format);
45
+ }
46
+
47
+ if (val && (xComponent === "TimePicker" || xComponent === "TimePicker.RangePicker")) {
48
+ const format = xComponentProps?.format || "HH:mm:ss";
49
+ if (Array.isArray(val)) {
50
+ return val.map((it) => dayjs(it).format(format)).join(" ~ ");
51
+ }
52
+ return dayjs(val).format(format);
53
+ }
54
+
55
+ if (xComponent === "Switch") {
56
+ if (val === undefined || val === false || val === field.inactiveValue) {
57
+ return field.inactiveText || "否";
58
+ }
59
+ if (val === true || val === field.activeValue) {
60
+ return field.activeText || "是";
61
+ }
62
+ return val;
63
+ }
64
+ if (typeof field.relation === "object") {
65
+ const { key, name, label } = field.relation;
66
+ return data[key]?.[name];
67
+ }
68
+
69
+ const dataSource = field?.dataSource || field.enum;
70
+ if (
71
+ (xComponent === "Select" || xComponent === "Radio.Group" || xComponent === "Checkbox.Group") &&
72
+ Array.isArray(dataSource)
73
+ ) {
74
+ if (!Array.isArray(val)) {
75
+ return getFieldOptItByVal(val, field, opt)?.label || val;
76
+ } else if (Array.isArray(val)) {
77
+ let _val = [];
78
+ val.forEach((valIt) => {
79
+ _val.push(getFieldOptItByVal(val, field, opt)?.label || valIt);
80
+ });
81
+ val = _val;
82
+ }
83
+ }
84
+
85
+ if (Array.isArray(val)) {
86
+ return val.join("、");
87
+ }
88
+
89
+ return val;
90
+ }
91
+
92
+ export function getDateVal(val, format) {
93
+ return dayjs(val).format(format);
94
+ }
95
+
96
+ export function getFieldList(_schema, fieldList = [], opt = {}, isTableSortXIdex = false) {
97
+ const schema = _schema?.schema || _schema;
98
+
99
+ // 解决 schema 字符串可执行代码、变量等
100
+ const properties = Schema.getOrderProperties(schema);
101
+ const { boxList = [] } = opt || {};
102
+ let _boxList = ["FormGrid", "FormGrid.GridColumn"];
103
+ if (Array.isArray(boxList)) {
104
+ _boxList = [..._boxList, ...boxList];
105
+ } else if (boxList === false) {
106
+ _boxList = [];
107
+ }
108
+
109
+ schema?.properties &&
110
+ properties.forEach((item) => {
111
+ const field = item.schema;
112
+ if (!field.name) {
113
+ field.name = item.key;
114
+ }
115
+ const componentName = field["x-component"];
116
+ if (_boxList.includes(componentName)) {
117
+ getFieldList(field, fieldList, opt);
118
+ } else {
119
+ fieldList.push(field);
120
+ }
121
+ });
122
+ isTableSortXIdex && fieldList.sort((a, b) => a["x-index"] - b["x-index"]);
123
+ return fieldList;
124
+ }
125
+
126
+ export function getFieldMap(_schema, fieldMap = {}) {
127
+ // const fieldMap = _.keyBy(getFieldList(_schema), "name");
128
+ const schema = _schema?.schema || _schema;
129
+ schema?.properties &&
130
+ Object.keys(schema?.properties).forEach((key) => {
131
+ const field = schema?.properties[key];
132
+ if (field["x-component"] === "FormGrid") {
133
+ getFieldMap(field, fieldMap);
134
+ } else if (field["x-component"] === "FormGrid.GridColumn") {
135
+ getFieldMap(field, fieldMap);
136
+ } else {
137
+ fieldMap[key] = field;
138
+ }
139
+ });
140
+
141
+ return fieldMap;
142
+ }
143
+
144
+ export function objToFormData(data) {
145
+ const formData = new FormData();
146
+ Object.keys(data)?.forEach((key) => {
147
+ formData.set(key, data[key]);
148
+ });
149
+ return formData;
150
+ }
151
+
152
+ /**
153
+ * 根据 val 获取对应的 options 项数据
154
+ * @param {string|number|boolean} val
155
+ * @param {Object} field
156
+ */
157
+ export const getFieldOptItByVal = function (val, field, opt) {
158
+ if (!field) {
159
+ return {};
160
+ }
161
+ const options = Array.isArray(field.enum)
162
+ ? field.enum
163
+ : Array.isArray(field.options)
164
+ ? field.options
165
+ : field.dataSource || [];
166
+ return getOptItByVal(val, options, {
167
+ fieldNames: field.fieldNames || field["x-component-props"]?.fieldNames,
168
+ ...opt,
169
+ });
170
+ };
171
+
172
+ /**
173
+ * 根据 val 获取对应的 options 项数据,并进行数据归一化处理
174
+ * value, label, children
175
+ * @param {string|number|boolean} val
176
+ * @param {Object} field
177
+ */
178
+ export const getOptItByVal = function (val, options, opt) {
179
+ const { fieldNames } = opt || {};
180
+ const { value = "value", label = "label", children = "children" } = fieldNames || {};
181
+ for (let i = 0; i < options.length; i++) {
182
+ const it = options[i];
183
+ if (it?.[value] === val) {
184
+ return {
185
+ ...it,
186
+ value: it?.[value],
187
+ label: it?.[label],
188
+ children: it?.[children],
189
+ };
190
+ }
191
+ // 递归处理
192
+ const _children = it?.[children];
193
+ if (Array.isArray(_children) && _children.length > 0) {
194
+ const child = getOptItByVal(val, _children, opt);
195
+ return {
196
+ ...child,
197
+ value: child?.[value],
198
+ label: child?.[label],
199
+ children: child?.[children],
200
+ };
201
+ }
202
+ }
203
+ };
204
+
205
+ /**
206
+ * 移除 schema.properties 中包含 "inTable": false 的字段
207
+ * @param {Object} data - 原始数据对象
208
+ * @returns {Object} - 处理后的新对象
209
+ */
210
+
211
+ /**
212
+ * 移除表格中标记为inTable:false的字段
213
+ * @param {Object} data - 原始数据
214
+ * @param {Object} [opt={}] - 配置选项
215
+ * @param {Array} [opt.boxList=[]] - 需要递归处理的组件类型列表
216
+ * @returns {Object} 处理后的数据
217
+ */
218
+
219
+ export function removeInTableFalseFields(_schema, opt = {}) {
220
+ // 1. 深拷贝原始数据
221
+ const result = cloneSchema(_schema);
222
+
223
+ // 2. 获取schema对象(支持直接传入schema或包含schema的对象)
224
+ const schema = result?.schema || result;
225
+
226
+ // 3. 处理容器组件配置
227
+ const { boxList = [] } = opt;
228
+ const _boxList =
229
+ boxList === false
230
+ ? []
231
+ : [
232
+ "Card",
233
+ "FormGrid",
234
+ "ArrayCards",
235
+ "Collapse",
236
+ "Tabs",
237
+ "FormGrid.GridColumn",
238
+ ...(Array.isArray(boxList) ? boxList : []),
239
+ ];
240
+
241
+ // 4. 递归删除inTable:false的字段
242
+ const processProperties = (properties) => {
243
+ if (!properties || typeof properties !== "object") return;
244
+
245
+ Object.keys(properties).forEach((key) => {
246
+ const item = properties[key];
247
+
248
+ // 处理容器组件递归
249
+ if (item["x-component"] && _boxList.includes(item["x-component"])) {
250
+ if (item.properties) {
251
+ processProperties(item.properties);
252
+ }
253
+ }
254
+ // 处理数组类型的子项
255
+ else if (item.items?.properties) {
256
+ processProperties(item.items.properties);
257
+ }
258
+ // 处理普通字段
259
+ else if (item.inTable === false) {
260
+ delete properties[key];
261
+ }
262
+ // 移除x-display
263
+ else if (item["x-display"]) {
264
+ delete item["x-display"];
265
+ }
266
+ });
267
+ };
268
+
269
+ // 5. 处理主properties
270
+ if (schema.properties) {
271
+ processProperties(schema.properties);
272
+ }
273
+
274
+ // 6. 移除form的布局属性
275
+ if (result.form) {
276
+ delete result.form.labelCol;
277
+ delete result.form.wrapperCol;
278
+ }
279
+
280
+ return result;
281
+ }
@@ -27,7 +27,7 @@ export interface EditableCellProps extends React.HTMLAttributes<HTMLElement> {
27
27
  index: number;
28
28
  editable: boolean;
29
29
  onEdit: (record: Partial<Item> & { key: React.Key }, dataIndex: string, opt: Object) => void;
30
- onSave: () => void;
30
+ onSave: (field: { type: string; name: string }) => void;
31
31
  onCancel: () => void;
32
32
  topProps: {
33
33
  config: { hasEdit: boolean | Function };
@@ -100,7 +100,7 @@ export const EditableCell: React.FC<EditableCellProps> = ({
100
100
  />
101
101
  {editMode !== "line" ? (
102
102
  <div className="cell-editing-actions">
103
- <CheckOutlined className="table-cell-confirm-icon" onClick={onSave} />
103
+ <CheckOutlined className="table-cell-confirm-icon" onClick={() => onSave(field)} />
104
104
  <CloseOutlined className="table-cell-cancel-icon" onClick={onCancel} />
105
105
  </div>
106
106
  ) : null}
@@ -195,13 +195,20 @@ export const useEditTable = (props) => {
195
195
  const onEdit = async (record: Partial<Item> & { key: React.Key }, key, opt = { fieldRef: null }) => {
196
196
  const { fieldRef } = opt || {};
197
197
  editingFiledRef.current = fieldRef;
198
-
199
- // const value = await (props.onEdit && props.onEdit(record));
200
198
  formRender?.setValues(record);
201
199
  setEditingId(record[idKey]);
202
200
  setEditingKey(key);
203
201
  };
204
202
 
203
+ /**
204
+ * 点击编辑按钮
205
+ * @param record
206
+ */
207
+ const onEditAFetch = async (record: Partial<Item> & { key: React.Key }, ...args) => {
208
+ const value = await (props.onEdit && props.onEdit(record));
209
+ onEdit.call(this, value, ...args);
210
+ };
211
+
205
212
  const onCancel = () => {
206
213
  setEditingId("");
207
214
  setEditingKey("");
@@ -211,11 +218,11 @@ export const useEditTable = (props) => {
211
218
  /**
212
219
  * 保存数据
213
220
  */
214
- const onSave = async () => {
221
+ const onSave = async (field) => {
215
222
  try {
216
223
  // 点击保存,数据抛出
217
224
  (await formRender?.validate()) as Item;
218
- onEditSubmit && (await onEditSubmit(formRender.values));
225
+ onEditSubmit && (await onEditSubmit(formRender.values, { field } ));
219
226
  // 清除编辑目标
220
227
  setEditingId("");
221
228
  setEditingKey("");
@@ -246,7 +253,7 @@ export const useEditTable = (props) => {
246
253
  ? isEditing(record) && isEditingCell(col.dataIndex)
247
254
  : isEditing(record),
248
255
  topProps: props.topProps,
249
- onEdit,
256
+ onEdit: onEditAFetch,
250
257
  onSave,
251
258
  onCancel,
252
259
  }),
@@ -274,6 +281,7 @@ export const useEditTable = (props) => {
274
281
  });
275
282
 
276
283
  return {
284
+ onEditAFetch,
277
285
  onEdit,
278
286
  SchemaField,
279
287
  mergedColumns,
@@ -1,10 +1,11 @@
1
- import { memo, useEffect, useState, useMemo, useCallback, useRef } from "react";
1
+ import { memo, useMemo, useCallback } from "react";
2
2
  import { createForm } from "@formily/core";
3
- import { createSchemaField, useField, useFieldSchema, observer, FormProvider, Schema } from "@formily/react";
3
+ import { antdComponents, customComponents } from "@hzab/form-render";
4
+ import { createSchemaField, useField, useFieldSchema, Schema } from "@formily/react";
4
5
  import { Form } from "c-formily-antd";
5
- import { handleReaction } from "../../common/handleReactions";
6
+ import { cloneSchema } from "@hzab/utils/src/formily/cloneSchema";
6
7
 
7
- import { antdComponents, customComponents } from "@hzab/form-render";
8
+ import { handleReaction } from "../../common/handleReactions";
8
9
 
9
10
  type formilyFieldPropsT = {
10
11
  schema: Schema;
@@ -19,6 +20,16 @@ type formilyFieldPropsT = {
19
20
  export const FormilyField = memo(function (props: formilyFieldPropsT) {
20
21
  const { schema, formilyRef, schemaScope, components, reactionOpts } = props;
21
22
  const { fields, fieldSchemas } = formilyRef.current || {};
23
+ const _schema = useMemo(() => {
24
+ const schemaRmInTable = cloneSchema(schema);
25
+ // 去除 inTable = false 的字段
26
+ Object.keys(schemaRmInTable?.schema?.properties)?.forEach((key) => {
27
+ if (schemaRmInTable?.schema?.properties?.[key]?.inTable === false) {
28
+ delete schemaRmInTable?.schema?.properties?.[key];
29
+ }
30
+ });
31
+ return schemaRmInTable;
32
+ }, [schema]);
22
33
  const SchemaField = useCallback(
23
34
  createSchemaField({
24
35
  // @ts-ignore
@@ -60,7 +71,7 @@ export const FormilyField = memo(function (props: formilyFieldPropsT) {
60
71
  style={{ display: "none", width: 0, height: 0, overflow: "hidden" }}
61
72
  form={formRender}
62
73
  >
63
- <SchemaField schema={schema}></SchemaField>
74
+ <SchemaField schema={_schema}></SchemaField>
64
75
  </Form>
65
76
  );
66
77
  });
@@ -70,7 +70,6 @@ const ListRender = forwardRef(function (props, parentRef) {
70
70
  const [total, setTotal] = useState(0);
71
71
  const [list, setList] = useState([]);
72
72
  const [formState, setFormState] = useState("");
73
- const [rowId, setRowId] = useState(0);
74
73
  const [listLoading, setListLoading] = useState(false);
75
74
  const formModalRef = useRef();
76
75
  const detailModalRef = useRef();
@@ -329,14 +328,11 @@ const ListRender = forwardRef(function (props, parentRef) {
329
328
  }
330
329
 
331
330
  function handleDetail(data, id) {
332
- setRowId(id);
333
331
  let title = data[modalConf?.title?.detailKey] || modalConf?.title?.detailText || "详情";
334
332
  detailModalRef.current.show(data, title);
335
333
  }
336
334
 
337
335
  function onEdit(row, idx) {
338
- //编辑的时候提前存id和状态
339
- setRowId(row[idKey]);
340
336
  setFormState("edit");
341
337
 
342
338
  if (props.fetchOnEdit !== false) {
@@ -367,24 +363,27 @@ const ListRender = forwardRef(function (props, parentRef) {
367
363
 
368
364
  function handleEdit(data, id) {
369
365
  const { editMode = "modal" } = props;
370
- const isEditTable = editMode !== "modal";
371
- if (isEditTable) {
366
+ // 整行编辑的模式下列表数据回填
367
+ if (editMode == "line") {
372
368
  return tableRef.current.onEditByTable(data, id);
373
369
  }
374
- let title = data[modalConf?.title?.editKey] || modalConf?.title?.editText || "编辑";
375
- formModalRef.current.show(data, title, "edit");
370
+ if (editMode === "modal") {
371
+ let title = data[modalConf?.title?.editKey] || modalConf?.title?.editText || "编辑";
372
+ formModalRef.current.show(data, title, "edit");
373
+ }
376
374
  }
377
375
 
378
- async function onEditSubmit(data) {
376
+ async function onEditSubmit(data, opt) {
379
377
  let _data = data;
380
378
  if (isPatchUpdate) {
381
379
  if (model?.patchMap === "function") {
382
- _data = model.patchMap(data);
380
+ _data = model.patchMap(data, opt);
383
381
  }
384
382
  } else if (typeof model?.updateMap === "function") {
385
- _data = model.updateMap(data);
383
+ _data = model.updateMap(data, opt);
386
384
  }
387
385
 
386
+ // 行内编辑确认前的校验
388
387
  if (props.onEditReqVerify) {
389
388
  await props.onEditReqVerify(_data);
390
389
  }
@@ -394,7 +393,7 @@ const ListRender = forwardRef(function (props, parentRef) {
394
393
  }
395
394
  const request = isPatchUpdate ? model?.patch : model?.update;
396
395
  return request
397
- .bind(model)(_data, { id: rowId })
396
+ .bind(model)(_data, { id: data[idKey] })
398
397
  .then((res) => {
399
398
  getList();
400
399
  message.success(res?._message || "编辑成功");
@@ -4,10 +4,10 @@ import dayjs from "dayjs";
4
4
  import _ from "lodash";
5
5
 
6
6
  import FormRender from "@hzab/form-render";
7
+ import { cloneSchema } from "@hzab/utils/src/formily/cloneSchema";
7
8
  import { handleQuerySchema } from "../common/handleQuerySchema";
8
9
 
9
10
  import "./index.less";
10
- import { onFieldValueChange } from "@formily/core";
11
11
 
12
12
  function QueryRender(props, parentRef) {
13
13
  const [schema, setSchema] = useState({});
@@ -20,7 +20,7 @@ function QueryRender(props, parentRef) {
20
20
  handleQuerySchema({
21
21
  ...props?.config,
22
22
  schemaScope: { ...props.schemaScope, scenario: "query" },
23
- schema: _.cloneDeep(props.schema),
23
+ schema: cloneSchema(props.schema),
24
24
  search: props.search,
25
25
  filters: _.cloneDeep(props.filters),
26
26
  onSearch,
@@ -218,12 +218,12 @@ const TableRender = forwardRef(function (props, tableRef) {
218
218
  }
219
219
 
220
220
  columns.push({
221
- field,
221
+ // field, // title 传入 ReactNode,内部深克隆导致页面报错白屏
222
222
  editable: true,
223
223
  ..._colConf,
224
224
  onCell: (record, rowIndex) =>
225
225
  _colConf?.onCell?.({ ...record, _field: { ...field, ...(fieldSchemas?.[name] || {}) } }, rowIndex) || {},
226
- title: isFunction(_colConf?.title) ? _colConf?.title() : _title,
226
+ title: () => (isFunction(_colConf?.title) ? _colConf?.title() : _title),
227
227
  key: name,
228
228
  dataIndex: name,
229
229
  render: getColRender(colRender),
@@ -283,10 +283,6 @@ const TableRender = forwardRef(function (props, tableRef) {
283
283
  <Button
284
284
  type="link"
285
285
  onClick={() => {
286
- // // 可编辑表格使用对应回调
287
- // if (isEditTable) {
288
- // return onEditByTable && onEditByTable(record, index);
289
- // }
290
286
  props.onEdit && props.onEdit(record, index);
291
287
  }}
292
288
  >
@@ -430,7 +426,7 @@ const TableRender = forwardRef(function (props, tableRef) {
430
426
  <Table {...tableProps} />
431
427
  )}
432
428
  <FormilyField
433
- schema={props.schema}
429
+ schema={topProps.schema}
434
430
  formilyRef={formilyRef}
435
431
  components={props.components}
436
432
  schemaScope={{