lu-lowcode-package-form 0.11.50 → 0.11.53

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.11.50",
3
+ "version": "0.11.53",
4
4
  "dependencies": {
5
5
  "@ant-design/icons": "^4.8.1",
6
6
  "@dnd-kit/core": "^6.1.0",
package/src/App.jsx CHANGED
@@ -575,7 +575,7 @@ function App() {
575
575
  code: 0, data: {
576
576
  list:
577
577
  [
578
- { label: '选项1', value: '1', table_fill: [{ fill_shuilv:0.13, fill_tianchong1: { label: '选项1', value: '1' }, fill_tianchong2: { label: '选项2', value: '2' } }] },
578
+ { label: '选项1', value: '1', table_fill: [{ fill_shuilv:0.13, fill_tianchong1: { label: '选项1', value: '1' }, fill_tianchong2: { label: '选项2', value: '2' } },{ fill_shuilv:0.13, fill_tianchong1: { label: '选项1', value: '1' }, fill_tianchong2: { label: '选项2', value: '2' } }] },
579
579
  { label: '选项2', value: '2' },
580
580
  { label: '选项3', value: '3' }
581
581
  ]
@@ -79,18 +79,16 @@ const SearchSelect = forwardRef(({ addWrapper = true, form, fieldName, fieldsVal
79
79
  // console.log("callback loadValue", loadValue)
80
80
  // let item = selectOptions.find(item => item.value == loadValue?.value || item.value == loadValue);
81
81
  // if (item && !isEqual(item, loadValue)) {
82
- // console.log(`[${props?.label}]debounceFetchOptions new value /////`, item);
83
82
  // typeof onChange === 'function' && onChange(item);
84
83
  // }
85
84
  // }
86
85
  // });
87
86
  debounceFetchOptions({ ...requestParams, [option_value]: loadValue?.value }, null, (selectOptions) => {
88
87
  if (selectOptions && selectOptions.length > 0) {
89
- console.log(`[${props?.label}]callback selectOptions`, selectOptions)
90
- console.log(`[${props?.label}]callback loadValue`, loadValue)
88
+ // console.log(`[${props?.label}]callback selectOptions`, selectOptions)
89
+ // console.log(`[${props?.label}]callback loadValue`, loadValue)
91
90
  let item = selectOptions.find(item => item.value == loadValue?.value || item.value == loadValue);
92
91
  if (item && !isEqual(item, loadValue)) {
93
- console.log(`[${props?.label}]debounceFetchOptions new value /////`, item);
94
92
  typeof onChange === 'function' && onChange(item);
95
93
  }
96
94
  }
@@ -124,11 +122,8 @@ const SearchSelect = forwardRef(({ addWrapper = true, form, fieldName, fieldsVal
124
122
  if (debounceFetchOptionsRef.current) clearTimeout(debounceFetchOptionsRef.current);
125
123
  debounceFetchOptionsRef.current = setTimeout(() => {
126
124
  const callbacks = callbackQueue.current;
127
- console.log(`[${props?.label}]debounceFetchOptions callbackQueue`, JSON.parse(JSON.stringify(callbacks)));
128
125
  callbackQueue.current = [];
129
126
  fetchOptions(params, ruleParams, fieldName).then(result => {
130
- console.log(`[${props?.label}]debounceFetchOptions result`, result);
131
- console.log(`[${props?.label}]debounceFetchOptions callbacks`, callbacks);
132
127
  while (callbacks.length > 0) {
133
128
  const callback = callbacks.shift();
134
129
  if (typeof callback === 'function') {
@@ -8,7 +8,7 @@ import { nanoid } from 'nanoid';
8
8
  import { eventEmitter } from '../../utils/events'
9
9
 
10
10
 
11
- function batchElements(elements, groupSize,dmap) {
11
+ function batchElements(elements, groupSize, dmap) {
12
12
  const groupedElements = [];
13
13
  let tempArray = [];
14
14
 
@@ -61,7 +61,7 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
61
61
  if (!isEqual(formContentRef.current, newFormContent)) {
62
62
  formContentRef.current = newFormContent;
63
63
  setFormContent(newFormContent);
64
- }
64
+ }
65
65
  }
66
66
  // 调用setFieldsValue时,进入锁定状态,阻止因字段值变化而触发级联处理
67
67
  const lockStatus = React.useRef(0);
@@ -73,32 +73,42 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
73
73
  currentCycleId: 0,
74
74
  // 当前更新周期的依赖路径
75
75
  updatePath: [],
76
+ // 最大更新深度限制,避免过深的嵌套引起栈溢出
77
+ MAX_DEPTH: 30,
76
78
  // 开始新的更新周期
77
- startNewCycle: function() {
79
+ startNewCycle: function () {
78
80
  this.currentCycleId++;
79
81
  this.updatePath = [];
80
82
  return this.currentCycleId;
81
83
  },
82
84
  // 添加依赖路径
83
- addToPath: function(fieldId) {
84
- this.updatePath.push(fieldId);
85
+ addToPath: function (fieldId) {
86
+ // 限制依赖路径深度,防止栈溢出
87
+ if (this.updatePath.length >= this.MAX_DEPTH) {
88
+ console.warn(`依赖路径深度超过限制(${this.MAX_DEPTH}),可能存在过深嵌套`);
89
+ return;
90
+ }
91
+ if (fieldId) {
92
+ this.updatePath.push(fieldId);
93
+ }
85
94
  },
86
95
  // 检查是否形成循环
87
- hasCircularDependency: function(targetFieldId) {
96
+ hasCircularDependency: function (targetFieldId) {
97
+ if (!targetFieldId) return false;
88
98
  return this.updatePath.includes(targetFieldId);
89
99
  },
90
100
  // 获取当前依赖路径
91
- getCurrentPath: function() {
101
+ getCurrentPath: function () {
92
102
  return [...this.updatePath];
93
103
  },
94
104
  // 结束当前字段的处理
95
- finishField: function() {
105
+ finishField: function () {
96
106
  if (this.updatePath.length > 0) {
97
107
  this.updatePath.pop();
98
108
  }
99
109
  }
100
110
  });
101
-
111
+
102
112
  React.useImperativeHandle(ref, () => ({
103
113
  formRef: form,
104
114
  setFieldsValue: (values) => {
@@ -164,7 +174,7 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
164
174
  // return current;
165
175
  }
166
176
  const initializeDependencyMap = async () => {
167
-
177
+
168
178
  const fields = [];
169
179
  function traverse(currentNode, parentNode = null) {
170
180
  var componentName = currentNode.type?.displayName || currentNode.props?._componentName;
@@ -212,10 +222,10 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
212
222
  };
213
223
  const initializeFieldVisibilityImmediate = async (reloadFields = false) => {
214
224
  console.log("initializeFieldVisibility *************************************")
215
-
216
-
225
+
226
+
217
227
  const fieldValues = form.getFieldsValue();
218
-
228
+
219
229
  await Promise.all(Array.from(dependencyMap.current.keys()).map(async (key) => {
220
230
  await handleFieldsWith(key, fieldValues, true);
221
231
  }))
@@ -226,34 +236,37 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
226
236
  };
227
237
  // 初始化字段的级联关系
228
238
  const initializeFieldVisibility = debounce(async (reloadFields = false) => {
229
- console.log("initializeFieldVisibility begin",reloadFields)
230
239
  await initializeFieldVisibilityImmediate(reloadFields);
231
240
  }, 100);
232
241
 
233
242
 
234
243
  // 计算字段级联关系
235
244
  const handleFieldsWith = async (identifier, fieldValues, init = false, fieldId = null) => {
245
+ if (mode == "desgin") {
246
+ console.log("设计模式下不进行字段级联计算")
247
+ return false
248
+ }
236
249
  // console.log("handleFieldsWith identifier", identifier)
237
250
  let needRefresh = false;
238
251
  let parentIdentifier = [];
239
252
  if (Array.isArray(identifier)) {
240
253
  parentIdentifier = [...(identifier.slice(0, -1))]
241
254
  identifier = identifier.filter(item => typeof item == "string").join(".")
255
+
242
256
  }
243
-
257
+
244
258
  // 将标识符标准化为字符串,用于依赖图谱
245
259
  const currentFieldId = fieldId || identifier;
246
-
247
260
  // 检查是否在当前更新链路中已存在,避免循环依赖
248
261
  if (dependencyGraphRef.current.hasCircularDependency(currentFieldId)) {
249
262
  const currentPath = dependencyGraphRef.current.getCurrentPath();
250
263
  console.log(`检测到循环依赖链路: ${[...currentPath, currentFieldId].join(' -> ')}`);
251
264
  return false;
252
265
  }
253
-
266
+
254
267
  // 将当前字段添加到依赖路径
255
268
  dependencyGraphRef.current.addToPath(currentFieldId);
256
-
269
+
257
270
  try {
258
271
  if (dependencyMap.current.has(identifier)) {
259
272
  const dependent = dependencyMap.current.get(identifier)
@@ -285,7 +298,7 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
285
298
  // 在处理完毕后,从依赖路径中移除当前字段
286
299
  dependencyGraphRef.current.finishField();
287
300
  }
288
-
301
+
289
302
  return needRefresh;
290
303
  };
291
304
  const removeLastFieldsValues = (name, isTable = false) => {
@@ -309,12 +322,12 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
309
322
  changedFieldsState.current[fieldName] = fieldValue;
310
323
  }
311
324
  const recordFieldsChange = (changedFields, handleChange = false) => {
312
- console.log("recordFieldsChange", changedFields,handleChange)
325
+ console.log("recordFieldsChange", changedFields, handleChange)
313
326
  var changedKeys = Object.keys(changedFields)
314
327
  if (changedKeys.length > 0) {
315
328
  changedKeys.forEach(key => {
316
329
  recordFieldChange(key, changedFields[key])
317
-
330
+
318
331
  })
319
332
  if (handleChange) debounceHandleFieldsChange();
320
333
  }
@@ -327,7 +340,7 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
327
340
  let changedFields = {}
328
341
 
329
342
  // 将标识符标准化为字符串
330
- const sourceFieldId = Array.isArray(current_identifier)
343
+ const sourceFieldId = Array.isArray(current_identifier)
331
344
  ? current_identifier.filter(item => typeof item == "string").join(".")
332
345
  : current_identifier;
333
346
 
@@ -337,29 +350,29 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
337
350
  let { source, target } = rule
338
351
  let source_value = current_value?.[source]
339
352
  let setValue = source_value
340
-
353
+
341
354
  // 将sourceField格式化为字符串形式,用于依赖跟踪
342
- const sourceField = Array.isArray(current_identifier)
355
+ const sourceField = Array.isArray(current_identifier)
343
356
  ? current_identifier.filter(item => typeof item == "string").join(".")
344
357
  : current_identifier;
345
-
358
+
346
359
  // 格式化目标字段
347
- const targetField = Array.isArray(target)
360
+ const targetField = Array.isArray(target)
348
361
  ? target.filter(item => typeof item == "string").join(".")
349
362
  : target;
350
-
363
+
351
364
  // // 检查循环依赖 - 使用更高级的依赖图检测
352
365
  // if (dependencyGraphRef.current.hasCircularDependency(targetField)) {
353
366
  // const currentPath = dependencyGraphRef.current.getCurrentPath();
354
367
  // console.log(`检测到填充规则中的循环依赖链路: ${[...currentPath, targetField].join(' -> ')}`);
355
368
  // continue; // 跳过这条规则
356
369
  // }
357
-
358
-
370
+
371
+
359
372
  //// 添加到依赖路径
360
373
  // dependencyGraphRef.current.addToPath(targetField);
361
-
362
-
374
+
375
+
363
376
  // 子表
364
377
  if (rule?.type == 1) {
365
378
  if (dependencyMap.current.has(target)) {
@@ -409,7 +422,7 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
409
422
  form.setFieldValue(target, undefined);
410
423
  }
411
424
  form.setFieldValue(target, setValue)
412
-
425
+
413
426
  // 处理完当前字段后从依赖路径中移除
414
427
  // dependencyGraphRef.current.finishField();
415
428
  }
@@ -560,25 +573,25 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
560
573
  for (let index = 0; index < table_values.length; index++) {
561
574
  await handleFieldsWithFill(fieldValues, child, [childIdentifier[0], index], componentName, sourceFieldId)
562
575
  }
563
-
576
+
564
577
  return
565
578
  }
566
-
579
+
567
580
  // 将目标字段ID标准化为字符串
568
- const targetFieldId = Array.isArray(childIdentifier)
569
- ? childIdentifier.filter(item => typeof item == "string").join(".")
581
+ const targetFieldId = Array.isArray(childIdentifier)
582
+ ? childIdentifier.join(".")
570
583
  : childIdentifier;
571
-
584
+
572
585
  // 检查是否在当前依赖链中已存在,避免循环依赖
573
586
  if (dependencyGraphRef.current.hasCircularDependency(targetFieldId)) {
574
587
  const currentPath = dependencyGraphRef.current.getCurrentPath();
575
588
  console.log(`检测到公式计算中的循环依赖链路: ${[...currentPath, targetFieldId].join(' -> ')}`);
576
589
  return;
577
590
  }
578
-
591
+
579
592
  // // 将当前字段添加到依赖路径
580
593
  // dependencyGraphRef.current.addToPath(targetFieldId);
581
-
594
+
582
595
  try {
583
596
  let withDatas = [];
584
597
  // 先处理依赖数据
@@ -654,8 +667,8 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
654
667
  const formulaResult = evalFormula(formula);
655
668
  console.log(`${childIdentifier} 计算公式:`, formula)
656
669
  console.log(`${childIdentifier} 计算结果:`, formulaResult)
657
-
658
-
670
+
671
+
659
672
  form.setFieldValue(childIdentifier, formulaResult)
660
673
  await handleFieldsWith(childIdentifier, form.getFieldsValue(), false, targetFieldId)
661
674
  }
@@ -716,20 +729,19 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
716
729
 
717
730
  // 创建已处理字段集合,用于避免多次处理同一字段
718
731
  const processedFields = new Set();
719
-
720
732
  for (let key in changedFieldsState.current) {
721
733
  let field = changedFieldsState.current[key];
722
734
  if (!isEqual(field.value || "", getLastFieldValue(field.name) || "")) {
723
735
  if (lockStatus_ != 1) {
724
736
  // 获取字段标识符(字符串形式)
725
- const fieldId = Array.isArray(field.name)
726
- ? field.name.filter(item => typeof item == "string").join(".")
737
+ const fieldId = Array.isArray(field.name)
738
+ ? field.name.map(item => typeof item == "string" ? item : item.toString()).join(".")
727
739
  : field.name;
728
-
740
+
729
741
  // 跳过已处理的字段
730
742
  if (processedFields.has(fieldId)) continue;
731
743
  processedFields.add(fieldId);
732
-
744
+
733
745
  // 处理字段依赖关系,传递字段ID和依赖图谱
734
746
  let needRefresh_ = await handleFieldsWith(field.name, fieldValues, false, fieldId);
735
747
  needRefresh = needRefresh || needRefresh_;
@@ -746,16 +758,18 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
746
758
  }, []);
747
759
 
748
760
  const handleFieldsChange = React.useCallback((changedFields) => {
749
- changedFields.filter(field => {
750
- if (field.name && field.name.length > 0) {
751
- // const fieldKey = field.name.filter(item => typeof item == "string").join(".")
752
- changedFieldsState.current[field.name] = field;
753
-
754
-
755
- }
756
- })
761
+ setTimeout(() => {
762
+ changedFields.filter(field => {
763
+ if (field.name && field.name.length > 0) {
764
+ // const fieldKey = field.name.filter(item => typeof item == "string").join(".")
765
+ changedFieldsState.current[field.name] = field;
757
766
 
758
- debounceHandleFieldsChange();
767
+
768
+ }
769
+ })
770
+ console.log("handleFieldsChange", changedFieldsState.current)
771
+ debounceHandleFieldsChange();
772
+ }, 0);
759
773
  }, []);
760
774
 
761
775
  const getTableWithIds = (ids) => {
@@ -773,7 +787,7 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
773
787
  })
774
788
  return withAllIds
775
789
  }
776
- const handleTableAddRow = (ids) => {
790
+ const handleTableAddRow = (ids) => {
777
791
  let withAllIds = getTableWithIds(ids)
778
792
  const fieldValues = form.getFieldsValue();
779
793
  setTimeout(async () => {
@@ -807,7 +821,7 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
807
821
  return renderChildren();
808
822
  }
809
823
  return null;
810
- }
824
+ }
811
825
  const renderChildren = () => {
812
826
  console.log("renderChildren")
813
827
  const renderKey = nanoid()
@@ -824,7 +838,7 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
824
838
  );
825
839
 
826
840
 
827
-
841
+
828
842
 
829
843
 
830
844
 
@@ -860,7 +874,7 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
860
874
 
861
875
  let childComponent
862
876
  if (isTable || isLayoutComponent) {
863
- childComponent = React.cloneElement(child, { onTableAddRow: handleTableAddRow, getTableWithIds, onTableRemoveRow: handleTableRemoveRow, removeLastFieldsValues, form: form, fieldName: identifier, onCustomChange, initializeFormRender, mode, recordFieldsChange ,getDependencyMapItem,renderKey})
877
+ childComponent = React.cloneElement(child, { onTableAddRow: handleTableAddRow, getTableWithIds, onTableRemoveRow: handleTableRemoveRow, removeLastFieldsValues, form: form, fieldName: identifier, onCustomChange, initializeFormRender, mode, recordFieldsChange, getDependencyMapItem, renderKey })
864
878
  }
865
879
  else if (componentName === "Field.WithSingleSelect" || componentName === "Field.WithMultipleSelect" || componentName === "Show.WithTable") {
866
880
  childComponent = <Form.Item
@@ -925,7 +939,7 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
925
939
  style={{ marginBottom: 0 }}
926
940
  >
927
941
  {childComponent}
928
- </Col>
942
+ </Col>
929
943
  );
930
944
  })}
931
945
  </Row>
@@ -934,26 +948,26 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
934
948
 
935
949
  return (
936
950
  <ConfigProvider
937
- theme={{
938
- components: {
939
- Table: {
940
- rowHoverBg: '#ebebeb',
941
- // "fontSize": 14,
942
- // "cellPaddingBlock": 6
943
- },
944
- },
945
- token: {
946
- colorBgContainerDisabled: 'rgba(0, 0, 0, 0.02)', // 设置更浅的灰色背景
947
- colorTextDisabled: '#333',
948
- }
949
- }}
950
- >
951
- <Form form={form} className={"form-container fp-0 fw-full fh-full box-border fflex fflex-col " + (mode == "desgin" ? " fp-6" : "")} onFieldsChange={handleFieldsChange}>
952
- <Form.Item name="__id" hidden={true}>
953
- <input type="hidden" />
954
- </Form.Item>
955
- {formContent}
956
- </Form>
951
+ theme={{
952
+ components: {
953
+ Table: {
954
+ rowHoverBg: '#ebebeb',
955
+ // "fontSize": 14,
956
+ // "cellPaddingBlock": 6
957
+ },
958
+ },
959
+ token: {
960
+ colorBgContainerDisabled: 'rgba(0, 0, 0, 0.02)', // 设置更浅的灰色背景
961
+ colorTextDisabled: '#333',
962
+ }
963
+ }}
964
+ >
965
+ <Form form={form} className={"form-container fp-0 fw-full fh-full box-border fflex fflex-col " + (mode == "desgin" ? " fp-6" : "")} onFieldsChange={handleFieldsChange}>
966
+ <Form.Item name="__id" hidden={true}>
967
+ <input type="hidden" />
968
+ </Form.Item>
969
+ {formContent}
970
+ </Form>
957
971
  </ConfigProvider>
958
972
  );
959
973
  });