lu-lowcode-package-form 0.9.76 → 0.9.78

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lu-lowcode-package-form",
3
- "version": "0.9.76",
3
+ "version": "0.9.78",
4
4
  "dependencies": {
5
5
  "@ant-design/icons": "^4.8.1",
6
6
  "@testing-library/jest-dom": "^5.17.0",
@@ -13,6 +13,7 @@
13
13
  "@wangeditor/editor-for-react": "^1.0.6",
14
14
  "antd": "^5.13.2",
15
15
  "dayjs": "^1.11.11",
16
+ "nanoid": "^5.0.7",
16
17
  "postcss-modules": "^6.0.0",
17
18
  "quill": "^2.0.2",
18
19
  "react-draggable": "^4.4.6",
package/src/App.jsx CHANGED
@@ -100,7 +100,7 @@ function App() {
100
100
  }
101
101
  const setFormFields = () => {
102
102
  formRef?.current?.formRef?.setFieldsValue({ datetime: "2024-08-25",datetime2: "2024-08-25",datetime3: "",
103
- "remark11": { "label": "选项2", "value": "2" },
103
+ "remark11": { "label": "选项2", value: '1'},
104
104
  "remark12": [{ "label": "选项1", "value": "1" }, { "label": "选项2", "value": "2" }],
105
105
  "userselect": "1213131", "DeptSelect": ["leaf11"],
106
106
  "searchuser": [{ "id": 2, "name": "2222", "label": "2222", "value": 2 }, { "id": 4, "name": "4444", "label": "4444", "value": 4 }],
@@ -180,7 +180,31 @@ function App() {
180
180
  ]} label="测试关联单选" options={[{ label: '选项1', value: '1', name: "1111", table: "[{\"price\":1,\"num\":2},{\"price\":2,\"num\":2},{\"price\":3,\"num\":3},{\"price\":3,\"num\":3}]" }, { label: '选项2', value: '2' }]} __id="remark11" />
181
181
  <Layout.FormRow layout={'1'}>
182
182
  <Field.Table label="子表格" __id="table" >
183
+ <Field.Number label="税率(%)" __id="shuilv_table" withIds={[
184
+ "shuilv"
185
+ ]}
186
+ withFill={{
187
+ "value": [
188
+ {
189
+ "insert": {
190
+ "span": true
191
+ },
192
+ "attributes": {
193
+ "id": "shuilv",
194
+ "color": "blue",
195
+ "tagKey": "fieldsValue",
196
+ "content": "当前表单.税率(%)"
197
+ }
198
+ },
199
+
200
+ ],
201
+ "version": 1723016911807,
202
+ "withData": [
203
+
204
+ ]
205
+ }}/>
183
206
  <Field.DatePicker defaultNow={true} label="日期时间" prompt="" datetype="date" __id="datetime2" />
207
+
184
208
  <Field.WithSingleSelect ref={testRef} fillRules={[
185
209
  {
186
210
  "id": "636d3924-0298-4e9b-809a-26d4a10d7b89",
@@ -191,15 +215,6 @@ function App() {
191
215
 
192
216
  ]
193
217
  },
194
- {
195
- "id": "636d3924-0298-4e9b-809a-26d4a10d7b89",
196
- "type": 0,
197
- "source": "product_price12",
198
- "target": "product_price12",
199
- "subRules": [
200
-
201
- ]
202
- },
203
218
  {
204
219
  "id": "636d3924-0298-4e9b-809a-26d4a10d7b89",
205
220
  "type": 0,
@@ -210,7 +225,7 @@ function App() {
210
225
  ]
211
226
  },
212
227
 
213
- ]} label="测试关联单选" options={[{ label: '选项1', value: '1', product_price11: "1111", product_price12: "2222", product_price1: 111 }, { label: '选项2', value: '2' }, { label: '选项2', value: '2' }]} __id="remark11" />
228
+ ]} label="测试关联单选" options={[{ label: '选项1', value: '1', product_price11: "1111", product_price12: "2222", product_price1: 111 }, { label: '选项2', value: '2' }, { label: '选项3', value: '3' }]} __id="remark11" />
214
229
 
215
230
  <Field.Switch label="开关" __id="switch_table"></Field.Switch>
216
231
  <Field.Input defaultValue={3} isRequired={true} label="含税单价" __id="product_price11" />
package/src/App.test.js CHANGED
@@ -6,3 +6,4 @@ test('renders learn react link', () => {
6
6
  const linkElement = screen.getByText(/learn react/i);
7
7
  expect(linkElement).toBeInTheDocument();
8
8
  });
9
+
@@ -33,7 +33,7 @@ export const BaseWrapper = ({
33
33
  }) => {
34
34
  useEffect(()=>{
35
35
  if (defaultValue && typeof onChange === "function" && !value) {
36
- console.log("defaultValue changed", defaultValue)
36
+ // console.log("defaultValue changed", defaultValue)
37
37
  onChange(defaultValue)
38
38
  }
39
39
  },[])
@@ -41,7 +41,7 @@ export const BaseWrapper = ({
41
41
  // 不接管只读属性的组件
42
42
  const ignoreReadonly = ["UploadImage", "UploadFile", "Table", "WithMultipleSelect", "WithSingleSelect"]
43
43
  if (readonly) {
44
- console.log("children?.type?.displayName", children?.type?.displayName)
44
+ // console.log("children?.type?.displayName", children?.type?.displayName)
45
45
  }
46
46
  if (ignoreReadonly.includes(children?.type?.displayName) && readonly) readonly = false
47
47
  const formWarpper = (
@@ -3,7 +3,7 @@
3
3
  import { Input, Select as OriginalSelect, Spin } from 'antd';
4
4
  import React, { useEffect, useState } from 'react';
5
5
  import { BaseWrapper } from "../base"
6
- import { debounce } from 'lodash';
6
+ import { debounce, isEqual } from 'lodash';
7
7
 
8
8
 
9
9
  const SearchSelect = ({ addWrapper = true, value, type, defaultValue, onChange, option_label, option_value, option_search, options, request, requestParams, callError, subRequest, sub_option_label = "label", mode = "single", sub_option_value = "id", rightIcon, rightIconClick, ...props }) => {
@@ -18,8 +18,11 @@ const SearchSelect = ({ addWrapper = true, value, type, defaultValue, onChange,
18
18
 
19
19
  if (request && typeof request === 'function') {
20
20
  const list = await fetchOptions(params)
21
- if (list && Array.isArray(list))
21
+ if (list && Array.isArray(list)) {
22
22
  item = value ? list.find(item => item.value == value) : null
23
+ console.log("SearchSelect value", value)
24
+ console.log("SearchSelect item", item)
25
+ }
23
26
  }
24
27
 
25
28
  if (options && options.length > 0) {
@@ -33,6 +36,27 @@ const SearchSelect = ({ addWrapper = true, value, type, defaultValue, onChange,
33
36
 
34
37
  }
35
38
 
39
+ useEffect(() => {
40
+ console.log("useEffect SearchSelect value", value)
41
+ if (value && nOptions.length > 0) {
42
+ let item = value
43
+ if (Array.isArray(value)) {
44
+ item = nOptions.filter(item => {
45
+ return value.filter(v => item.value == v?.value || item.value == v).length > 0
46
+ })
47
+ }
48
+ else {
49
+ item = nOptions.find(item => item.value == value?.value || item.value == value)
50
+ }
51
+
52
+ if (item && !isEqual(item, value)) {
53
+ onChange(item)
54
+ console.log("SearchSelect onChange value", item)
55
+ }
56
+
57
+ }
58
+ }, [value, nOptions])
59
+
36
60
  const handleSearch = debounce(async (value) => {
37
61
  const params = { ...requestParams }
38
62
  params[option_search] = value
@@ -88,24 +112,8 @@ const SearchSelect = ({ addWrapper = true, value, type, defaultValue, onChange,
88
112
 
89
113
  return addWrapper ? (
90
114
  <BaseWrapper {...props}>
91
- <OriginalSelect
92
-
93
- notFoundContent={fetching ? <Spin size="small" /> : null}
94
- value={value}
95
- {...props}
96
- filterOption={false}
97
- showSearch={request && option_search ? true : false}
98
- onSearch={request && option_search ? handleSearch : null}
99
- onChange={handleChange}
100
- style={{ width: '100%', flex: 1 }}
101
- options={nOptions}
102
- mode={mode} >
103
-
104
- </OriginalSelect>
105
- {!props?.disabled && rightIcon}
106
- </BaseWrapper>
107
- ) : (<>
108
115
  <OriginalSelect
116
+
109
117
  notFoundContent={fetching ? <Spin size="small" /> : null}
110
118
  value={value}
111
119
  {...props}
@@ -113,12 +121,28 @@ const SearchSelect = ({ addWrapper = true, value, type, defaultValue, onChange,
113
121
  showSearch={request && option_search ? true : false}
114
122
  onSearch={request && option_search ? handleSearch : null}
115
123
  onChange={handleChange}
116
- style={{ width: '100%' }}
124
+ style={{ width: '100%', flex: 1 }}
117
125
  options={nOptions}
118
- mode={mode} >
126
+ mode={mode} >
119
127
 
120
128
  </OriginalSelect>
121
- {!props?.disabled && rightIcon}</>
129
+ {!props?.disabled && rightIcon}
130
+ </BaseWrapper>
131
+ ) : (<>
132
+ <OriginalSelect
133
+ notFoundContent={fetching ? <Spin size="small" /> : null}
134
+ value={value}
135
+ {...props}
136
+ filterOption={false}
137
+ showSearch={request && option_search ? true : false}
138
+ onSearch={request && option_search ? handleSearch : null}
139
+ onChange={handleChange}
140
+ style={{ width: '100%' }}
141
+ options={nOptions}
142
+ mode={mode} >
143
+
144
+ </OriginalSelect>
145
+ {!props?.disabled && rightIcon}</>
122
146
  )
123
147
 
124
148
  }
@@ -2,6 +2,8 @@ import React, { useEffect, useState } from "react";
2
2
  import { Button, Form, Input } from "antd";
3
3
  import { DeleteOutlined } from "@ant-design/icons";
4
4
  import { BaseWrapper } from "../base.jsx"
5
+ import { type } from "@testing-library/user-event/dist/type/index.js";
6
+ import { nanoid } from "nanoid";
5
7
 
6
8
  const TableAction = ({ label, subTableIndex, children, subTableHead = false, ...props }) => {
7
9
  //fsticky fright-0
@@ -26,14 +28,16 @@ const TableCol = ({ children, width, ...props }) => {
26
28
  </div>
27
29
  }
28
30
 
29
- const Table = ({ children, ...props }) => {
31
+ const Table = ({ children, onTableAddRow,onTableRemoveRow, ...props }) => {
30
32
  const [init, setInit] = useState(false);
31
33
  const name = props.componentId || props.__id
34
+ const childrenIds = React.Children.map(children, (child) => `${name}.${child.props.componentId || child.props.__id}`)
32
35
  const rules = []
33
- const handleAdd = (add)=>{
36
+ const handleAdd = (add) => {
34
37
  if (!init) setInit(true);
35
38
  typeof add === "function" && add();
36
39
  }
40
+
37
41
  if (props.isRequired)
38
42
  rules.push({ required: true, message: `子表[${props.label}]必须填写` });
39
43
  return <Form.List name={name} rules={rules}>
@@ -41,7 +45,7 @@ const Table = ({ children, ...props }) => {
41
45
  if (fields.length === 0 && !init) handleAdd(add);
42
46
  return <div className="fw-full ">
43
47
  <div className="fw-full frelative fmin-h-20 foverflow-x-auto">
44
- {fields.length === 0 && <div key={`tableHead`} className="fborder-b fflex flex-nowrap fmin-w-full ">
48
+ {fields.length === 0 && <div key={`tableHead`} className="fborder-b fflex flex-nowrap fmin-w-full ">
45
49
  {React.Children.map(children, (child, childIndex) => {
46
50
  return <TableCol width={150} key={`row_${0}_col_${childIndex}`}>
47
51
  {React.cloneElement(child, {
@@ -52,16 +56,16 @@ const Table = ({ children, ...props }) => {
52
56
  })}
53
57
  </TableCol>
54
58
  })}
55
- {!props?.readonly && <TableAction subTableHead={true} key={`row_${0}_action`} subTable={true} subTableIndex={0} label={"操作"}>
56
- </TableAction>}
59
+ {!props?.readonly && <TableAction subTableHead={true} key={`row_${0}_action`} subTable={true} subTableIndex={0} label={"操作"}>
60
+ </TableAction>}
57
61
  </div>}
58
62
  {fields.map((field, index) => (
59
63
  <div key={field.key} className="fborder-b fflex flex-nowrap fmin-w-full ">
60
-
64
+ {/* {console.log("field",field)} */}
61
65
  {React.Children.map(children, (child, childIndex) => {
62
66
  let { props } = child;
63
67
  const col_id = child?.props?.componentId || child?.props?.__id || childIndex;
64
- if (field?.[col_id] === undefined) field[col_id] = "";
68
+ // if (field?.[col_id] === undefined) field[col_id] = "";
65
69
  const rules = []
66
70
  if (props.isRequired)
67
71
  rules.push({ required: true, message: `${props.label}必须填写` });
@@ -74,15 +78,16 @@ const Table = ({ children, ...props }) => {
74
78
  rules.push({ pattern: new RegExp(props.rules), message: props.rulesFailMessage ? props.rulesFailMessage : `${props.label}格式错误` })
75
79
  }
76
80
 
77
- return <TableCol width={150} key={`row_${index}_col_${childIndex}`}>
81
+ return <TableCol width={150} key={`row_${field.key}_col_${childIndex}`}>
78
82
  <Form.Item
79
83
  style={{ marginBottom: 0 }}
80
84
  label=""
81
85
  name={[field.name, col_id]}
82
86
  rules={rules}
87
+
83
88
  >
84
89
  {React.cloneElement(child, {
85
- key: `row_${index}_child_${childIndex}`,
90
+ key: `row_${field.key}_child_${childIndex}`,
86
91
  subTable: true,
87
92
  subTableIndex: index,
88
93
  subTableHead: index == 0,
@@ -90,13 +95,19 @@ const Table = ({ children, ...props }) => {
90
95
  </Form.Item>
91
96
  </TableCol>
92
97
  })}
93
- {!props?.readonly && <TableAction subTableHead={index ==0} key={`row_${index}_action`} subTable={true} subTableIndex={index} label={"操作"}>
94
- <DeleteOutlined className="fcursor-pointer" onClick={() => remove(index)} />
98
+ {!props?.readonly && <TableAction subTableHead={index == 0} key={`row_${index}_action`} subTable={true} subTableIndex={index} label={"操作"}>
99
+ <DeleteOutlined className="fcursor-pointer" onClick={() =>{
100
+ remove(index)
101
+ typeof onTableRemoveRow === "function" && onTableRemoveRow(childrenIds);
102
+ }} />
95
103
  </TableAction>}
96
104
  </div>
97
105
  ))}
98
106
  </div>
99
- <Button onClick={() => add()} className="fmy-2">新增一行</Button>
107
+ <Button onClick={() => {
108
+ add({ key: nanoid() })
109
+ typeof onTableAddRow === "function" && onTableAddRow(childrenIds);
110
+ }} className="fmy-2">新增一行</Button>
100
111
  </div>
101
112
  }}
102
113
  </Form.List>
@@ -110,5 +121,6 @@ const TableWrapper = (props) => {
110
121
  </BaseWrapper>
111
122
  );
112
123
  }
124
+ TableWrapper.displayName = "Table"
113
125
  export default TableWrapper;
114
126
  export { TableCol, TableAction };
@@ -3,6 +3,7 @@ import { Form, Row, Col, message } from "antd";
3
3
 
4
4
  import { debounce, isEqual } from 'lodash';
5
5
  import { evalFormula } from '../../utils/formula'
6
+ import { nanoid } from 'nanoid';
6
7
 
7
8
 
8
9
  function batchElements(elements, groupSize) {
@@ -45,7 +46,7 @@ function batchElements(elements, groupSize) {
45
46
  const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) => {
46
47
  const [form] = Form.useForm();
47
48
  const [formContent, setFormContent] = React.useState(null);
48
-
49
+
49
50
  const dependencyMap = React.useRef(null);
50
51
 
51
52
  React.useImperativeHandle(ref, () => ({
@@ -60,15 +61,16 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
60
61
 
61
62
 
62
63
  const lastFormValues = React.useRef(null);
63
- const getLastFieldValue = (path) => {
64
- let current = lastFormValues.current;
65
- for (let i = 0; i < path.length; i++) {
66
- if (current == null) {
67
- return undefined;
68
- }
69
- current = current[path[i]];
70
- }
71
- return current;
64
+ const getLastFieldValue = (path) => {
65
+ return lastFormValues.current?.[path]
66
+ // let current = lastFormValues.current;
67
+ // for (let i = 0; i < path.length; i++) {
68
+ // if (current == null) {
69
+ // return undefined;
70
+ // }
71
+ // current = current[path[i]];
72
+ // }
73
+ // return current;
72
74
  }
73
75
  const initializeDependencyMap = () => {
74
76
  const fields = [];
@@ -95,6 +97,7 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
95
97
  }
96
98
  }
97
99
  dependencyMap.current = new Map();
100
+
98
101
  const childrenArray = React.Children.toArray(children);
99
102
  for (let index = 0; index < childrenArray.length; index++) {
100
103
  const element = childrenArray[index];
@@ -111,7 +114,7 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
111
114
  ...field
112
115
  });
113
116
  });
114
- // console.log("dependencyMap", dependencyMap.current)
117
+
115
118
  initializeFieldVisibility();
116
119
  };
117
120
 
@@ -127,6 +130,7 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
127
130
  // 计算字段级联关系
128
131
  const handleFieldsWith = (identifier, fieldValues, init = false) => {
129
132
  let needRefresh = false;
133
+
130
134
  let parentIdentifier = [];
131
135
  if (Array.isArray(identifier)) {
132
136
  parentIdentifier = [...(identifier.slice(0, -1))]
@@ -135,8 +139,8 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
135
139
  if (dependencyMap.current.has(identifier)) {
136
140
  const dependent = dependencyMap.current.get(identifier)
137
141
  const dependentChildren = dependent.children;
138
- // console.log("identifier", identifier)
139
- // console.log("dependentChildren", dependentChildren)
142
+
143
+
140
144
  if (!init && dependent?.fillRules && Array.isArray(dependent?.fillRules) && dependent?.fillRules.length > 0) {
141
145
  handleFillRules(identifier, parentIdentifier, fieldValues, dependent?.fillRules)
142
146
  }
@@ -151,12 +155,16 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
151
155
  });
152
156
  }
153
157
  return needRefresh;
158
+
154
159
  };
155
160
 
156
161
  // 处理填充规则
157
162
  const handleFillRules = (current_identifier, parentIdentifier, fieldValues, fillRules) => {
158
163
  // 获取当前变更的字段数据
159
164
  let current_value = getParamValue("fieldsValue", current_identifier, fieldValues, null)
165
+ let changedFields = {}
166
+
167
+ let ids = []
160
168
  for (let index = 0; index < fillRules.length; index++) {
161
169
  const rule = fillRules[index];
162
170
  let { source, target } = rule
@@ -164,21 +172,28 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
164
172
  let setValue = source_value
165
173
  // 子表
166
174
  if (rule?.type == 1) {
175
+ if (dependencyMap.current.has(target)) {
176
+ let tableChildren = dependencyMap.current.get(target)?.component?.props?.children
177
+ if (Array.isArray(tableChildren) && tableChildren.length > 0) ids = tableChildren.map(item => `${source}.${item?.props?.componentId || item?.props?.__id}`)
178
+
179
+ }
167
180
  if (source_value && typeof source_value == "string") {
168
181
  try {
169
182
  source_value = JSON.parse(source_value)
170
183
  } catch (error) {
171
- console.log("error end", error)
184
+ console.error("error end", error)
172
185
  }
173
186
  }
174
187
 
175
188
  if (!Array.isArray(source_value)) return
176
- let target_value = source_value.map(item => {
189
+ let target_value = source_value.map((item, value_index) => {
177
190
  let target_item_value = {}
178
191
  if (rule?.subRules && Array.isArray(rule?.subRules) && rule?.subRules.length > 0)
179
192
  for (let index = 0; index < rule?.subRules.length; index++) {
180
193
  const { source: subSource, target: subTarget } = rule?.subRules[index];
181
194
  target_item_value[subTarget] = item?.[subSource]
195
+ let changedField = { name: [target, value_index, subTarget], value: item?.[subSource] }
196
+ changedFields[changedField.name] = changedField;
182
197
  }
183
198
  return target_item_value
184
199
  })
@@ -197,10 +212,31 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
197
212
  }
198
213
  }
199
214
  }
200
- form.setFieldValue(target, setValue)
201
- handleFieldsWith(target, form.getFieldsValue())
215
+ if (rule?.type == 1) {
216
+ form.setFieldValue(target, undefined);
217
+ }
218
+
219
+ setTimeout(() => {
220
+ form.setFieldValue(target, setValue)
221
+ handleFieldsWith(target, form.getFieldsValue())
222
+ // if (ids.length > 0) handleTableAddRow(ids)
223
+ }, 0);
224
+
202
225
  }
203
- // console.log("current value", current_value)
226
+
227
+ setTimeout(() => {
228
+ var changedKeys = Object.keys(changedFields)
229
+ if (changedKeys.length > 0) {
230
+ changedKeys.forEach(key => {
231
+ changedFieldsState.current[key] = changedFields[key];
232
+ })
233
+ debounceHandleFieldsChange();
234
+ }
235
+
236
+
237
+ if (ids.length > 0) handleTableAddRow(ids)
238
+ }, 100)
239
+
204
240
  }
205
241
  // 处理级联显示隐藏 @return {boolean} 是否需要重新渲染表单的字段
206
242
  const handleFieldsVisible = (fieldValues, child, parentIdentifier) => {
@@ -220,10 +256,10 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
220
256
  // 处理级联数据源
221
257
  // 处理级联填充
222
258
  const handleFieldsWithFill = async (fieldValues, child, parentIdentifier, componentName) => {
223
- // console.log("handleFieldsWithFill fieldValues", fieldValues)
224
- // console.log("handleFieldsWithFill child", child)
225
- // console.log("handleFieldsWithFill parentIdentifier", parentIdentifier)
226
- // console.log("handleFieldsWithFill componentName", componentName)
259
+
260
+
261
+
262
+
227
263
  const withFill = child?.component?.props.withFill;
228
264
  const withDataFetch = child?.component?.props.withDataFetch;
229
265
  let withFillIndex = 0
@@ -240,7 +276,6 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
240
276
  else if (childIdentifier.indexOf(".") >= 0) {
241
277
  childIdentifier = childIdentifier.split(".")
242
278
  let table_values = getParamValue("fieldsValue", childIdentifier[0], fieldValues, [])
243
- // console.log("table_values", table_values)
244
279
  if (Array.isArray(table_values) && table_values.length > 0)
245
280
  for (let index = 0; index < table_values.length; index++) {
246
281
  await handleFieldsWithFill(fieldValues, child, [childIdentifier[0], index], componentName)
@@ -294,18 +329,18 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
294
329
  }
295
330
  else result = JSON.stringify(result)
296
331
  }
297
- else if (result) result = `"${result}"`
332
+ else if (result.length > 0) result = `"${result}"`
298
333
  }
299
334
  }
300
335
  else result = insert
301
336
  return result
302
337
  })
303
338
  }
304
- // console.log("formula", formula)
339
+
305
340
  if (formula && formula.length > 0) {
306
341
  const formulaResult = evalFormula(formula);
307
- // console.log("formulaResult", formulaResult)
308
- // console.log("setFieldValue setFieldValue", childIdentifier)
342
+
343
+
309
344
  form.setFieldValue(childIdentifier, formulaResult)
310
345
  handleFieldsWith(childIdentifier, form.getFieldsValue())
311
346
  }
@@ -320,38 +355,80 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
320
355
  const parentValue = fieldValues?.[parentKey] || [];
321
356
  if (Array.isArray(parentValue))
322
357
  result = parentValue.map(item => {
323
- return item?.[childKey] || ""
358
+ return item?.[childKey] ?? ""
324
359
  })
325
- else result = parentValue?.[childKey] || ""
360
+ else result = parentValue?.[childKey] ?? ""
326
361
  }
327
- else result = fieldValues?.[id] || ""
362
+ else result = fieldValues?.[id] ?? ""
328
363
  }
329
364
  // 从依赖数据取值
330
365
  else {
331
366
  let withData = withDatas.find(item => item.id === tagKey)
332
367
  if (withData && withData.data && withData.data.length > 0) {
333
368
  // 暂时只取一条数据,后续再想 sum 函数等问题
334
- result = withData.data[0]?.[id] || ""
369
+ result = withData.data[0]?.[id] ?? ""
335
370
  }
336
371
  }
337
372
  return result
338
373
  }
339
374
 
340
- const handleFieldsChange = debounce((changedFields, allFields) => {
375
+ const changedFieldsState = React.useRef({});
376
+ const debounceHandleFieldsChange = debounce(() => {
341
377
  const fieldValues = form.getFieldsValue();
342
378
  let needRefresh = false;
343
- changedFields.forEach(field => {
344
- if (field.name && field.name.length > 0 && !isEqual(field.value, getLastFieldValue(field.name))) {
379
+ if (!lastFormValues.current) lastFormValues.current = {}
380
+ for (let key in changedFieldsState.current) {
381
+ let field = changedFieldsState.current[key];
382
+ if (!isEqual(field.value, getLastFieldValue(field.name))) {
345
383
  needRefresh = handleFieldsWith(field.name, fieldValues);
384
+ lastFormValues.current[field.name] = field.value;
346
385
  }
347
- });
348
-
386
+ }
349
387
  if (needRefresh) {
350
388
  setFormContent(renderChildren());
351
389
  }
352
- lastFormValues.current = form.getFieldsValue();
390
+ // lastFormValues.current = form.getFieldsValue();
391
+ changedFieldsState.current = {};
353
392
  }, 200);
354
393
 
394
+ const handleFieldsChange = (changedFields) => {
395
+ changedFields.filter(field => {
396
+ if (field.name && field.name.length > 0) {
397
+ // const fieldKey = field.name.filter(item => typeof item == "string").join(".")
398
+ changedFieldsState.current[field.name] = field;
399
+ }
400
+ })
401
+
402
+ debounceHandleFieldsChange();
403
+ }
404
+ const handleTableAddRow = (ids) => {
405
+ let withAllIds = []
406
+ ids.forEach(id => {
407
+ if (!dependencyMap.current.has(id)) return
408
+ let component = dependencyMap.current.get(id)
409
+ if (component.withIds.length <= 0) return
410
+ withAllIds.push(...(component.withIds.filter(withid => !withAllIds.includes(withid))))
411
+ })
412
+ withAllIds = withAllIds.filter(item => {
413
+ var withValue = form.getFieldValue(item)
414
+ if (typeof withValue != "number" && !withValue) return false
415
+ return true
416
+ })
417
+ const fieldValues = form.getFieldsValue();
418
+ setTimeout(() => {
419
+ withAllIds.forEach(withid => {
420
+ handleFieldsWith(withid, fieldValues);
421
+ })
422
+ }, 0);
423
+ }
424
+ const handleTableRemoveRow = (ids) => {
425
+ const fieldValues = form.getFieldsValue();
426
+ setTimeout(() => {
427
+ ids.forEach(id => {
428
+ handleFieldsWith(id, fieldValues);
429
+ })
430
+ }, 0);
431
+ }
355
432
  const renderChildren = () => {
356
433
  const childrenArray = React.Children.toArray(children);
357
434
  const groupedChildren = batchElements(
@@ -381,15 +458,19 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
381
458
  else {
382
459
  rules.push({ pattern: new RegExp(props.rules), message: props.rulesFailMessage ? props.rulesFailMessage : `${props.label}格式错误` })
383
460
  }
461
+ let childComponent = child;
462
+ if (isTable || isLayoutComponent) {
463
+ childComponent = React.cloneElement(child, { onTableAddRow: handleTableAddRow ,onTableRemoveRow: handleTableRemoveRow })
464
+ }
384
465
  return (
385
466
  <Col key={identifier || `col-${index}`} span={isLayoutComponent ? 24 : 24 / group.length} style={{ marginBottom: 0 }}>
386
- {(isLayoutComponent || isTable) ? child : <Form.Item
467
+ {(isLayoutComponent || isTable) ? childComponent : <Form.Item
387
468
  style={{ marginBottom: 0 }}
388
469
  label=""
389
470
  name={identifier}
390
471
  rules={rules}
391
472
  >
392
- {child}
473
+ {childComponent}
393
474
  </Form.Item>}
394
475
  </Col>
395
476
  );