lu-lowcode-package-form 0.11.46 → 0.11.47

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.
@@ -65,6 +65,40 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
65
65
  }
66
66
  // 调用setFieldsValue时,进入锁定状态,阻止因字段值变化而触发级联处理
67
67
  const lockStatus = React.useRef(0);
68
+ // // 字段变更源跟踪,用于处理双向依赖问题
69
+ // const updateSourceRef = React.useRef(new Map());
70
+ // 更新周期依赖图,用于处理复杂循环依赖 (如 a→b→c→a)
71
+ const dependencyGraphRef = React.useRef({
72
+ // 当前更新周期ID
73
+ currentCycleId: 0,
74
+ // 当前更新周期的依赖路径
75
+ updatePath: [],
76
+ // 开始新的更新周期
77
+ startNewCycle: function() {
78
+ this.currentCycleId++;
79
+ this.updatePath = [];
80
+ return this.currentCycleId;
81
+ },
82
+ // 添加依赖路径
83
+ addToPath: function(fieldId) {
84
+ this.updatePath.push(fieldId);
85
+ },
86
+ // 检查是否形成循环
87
+ hasCircularDependency: function(targetFieldId) {
88
+ return this.updatePath.includes(targetFieldId);
89
+ },
90
+ // 获取当前依赖路径
91
+ getCurrentPath: function() {
92
+ return [...this.updatePath];
93
+ },
94
+ // 结束当前字段的处理
95
+ finishField: function() {
96
+ if (this.updatePath.length > 0) {
97
+ this.updatePath.pop();
98
+ }
99
+ }
100
+ });
101
+
68
102
  React.useImperativeHandle(ref, () => ({
69
103
  formRef: form,
70
104
  setFieldsValue: (values) => {
@@ -130,6 +164,7 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
130
164
  // return current;
131
165
  }
132
166
  const initializeDependencyMap = async () => {
167
+
133
168
  const fields = [];
134
169
  function traverse(currentNode, parentNode = null) {
135
170
  var componentName = currentNode.type?.displayName || currentNode.props?._componentName;
@@ -177,6 +212,8 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
177
212
  };
178
213
  const initializeFieldVisibilityImmediate = async (reloadFields = false) => {
179
214
  console.log("initializeFieldVisibility *************************************")
215
+
216
+
180
217
  const fieldValues = form.getFieldsValue();
181
218
 
182
219
  await Promise.all(Array.from(dependencyMap.current.keys()).map(async (key) => {
@@ -195,7 +232,7 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
195
232
 
196
233
 
197
234
  // 计算字段级联关系
198
- const handleFieldsWith = async (identifier, fieldValues, init = false) => {
235
+ const handleFieldsWith = async (identifier, fieldValues, init = false, fieldId = null) => {
199
236
  // console.log("handleFieldsWith identifier", identifier)
200
237
  let needRefresh = false;
201
238
  let parentIdentifier = [];
@@ -203,34 +240,53 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
203
240
  parentIdentifier = [...(identifier.slice(0, -1))]
204
241
  identifier = identifier.filter(item => typeof item == "string").join(".")
205
242
  }
206
- if (dependencyMap.current.has(identifier)) {
207
- const dependent = dependencyMap.current.get(identifier)
208
- const dependentChildren = dependent.children;
243
+
244
+ // 将标识符标准化为字符串,用于依赖图谱
245
+ const currentFieldId = fieldId || identifier;
246
+
247
+ // 检查是否在当前更新链路中已存在,避免循环依赖
248
+ if (!init && dependencyGraphRef.current.hasCircularDependency(currentFieldId)) {
249
+ const currentPath = dependencyGraphRef.current.getCurrentPath();
250
+ console.log(`检测到循环依赖链路: ${[...currentPath, currentFieldId].join(' -> ')}`);
251
+ return false;
252
+ }
253
+
254
+ // 将当前字段添加到依赖路径
255
+ dependencyGraphRef.current.addToPath(currentFieldId);
256
+
257
+ try {
258
+ if (dependencyMap.current.has(identifier)) {
259
+ const dependent = dependencyMap.current.get(identifier)
260
+ const dependentChildren = dependent.children;
209
261
 
210
262
 
211
- if (!init && dependent?.fillRules && Array.isArray(dependent?.fillRules) && dependent?.fillRules.length > 0) {
212
- handleFillRules(identifier, parentIdentifier, fieldValues, dependent?.fillRules)
213
- }
214
- for (let index = 0; index < dependentChildren.length; index++) {
215
- const child = dependentChildren[index];
216
- if (child.component.props.withVisibleFunc && typeof child.component.props.withVisibleFunc === 'function') {
217
- let needRefresh_ = handleFieldsVisibleFunc(fieldValues, child, parentIdentifier)
218
- needRefresh = needRefresh || needRefresh_
263
+ if (!init && dependent?.fillRules && Array.isArray(dependent?.fillRules) && dependent?.fillRules.length > 0) {
264
+ handleFillRules(identifier, parentIdentifier, fieldValues, dependent?.fillRules)
219
265
  }
266
+ for (let index = 0; index < dependentChildren.length; index++) {
267
+ const child = dependentChildren[index];
268
+ if (child.component.props.withVisibleFunc && typeof child.component.props.withVisibleFunc === 'function') {
269
+ let needRefresh_ = handleFieldsVisibleFunc(fieldValues, child, parentIdentifier)
270
+ needRefresh = needRefresh || needRefresh_
271
+ }
220
272
 
221
- if (child.component.props.withVisible) {
222
- let needRefresh_ = await handleFieldsVisible(fieldValues, child, parentIdentifier, dependent?.componentName)
223
- needRefresh = needRefresh || needRefresh_
224
- }
273
+ if (child.component.props.withVisible) {
274
+ let needRefresh_ = await handleFieldsVisible(fieldValues, child, parentIdentifier, dependent?.componentName)
275
+ needRefresh = needRefresh || needRefresh_
276
+ }
225
277
 
226
278
 
227
- if (!init && child.component.props.withFill)
228
- handleFieldsWithFill(fieldValues, child, parentIdentifier, dependent?.componentName)
279
+ if (!init && child.component.props.withFill)
280
+ await handleFieldsWithFill(fieldValues, child, parentIdentifier, dependent?.componentName, currentFieldId)
229
281
 
282
+ }
230
283
  }
284
+ } finally {
285
+ // 在处理完毕后,从依赖路径中移除当前字段
286
+ dependencyGraphRef.current.finishField();
231
287
  }
288
+
232
289
  return needRefresh;
233
-
234
290
  };
235
291
  const removeLastFieldsValues = (name, isTable = false) => {
236
292
  if (!lastFormValues.current) return
@@ -258,6 +314,7 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
258
314
  if (changedKeys.length > 0) {
259
315
  changedKeys.forEach(key => {
260
316
  recordFieldChange(key, changedFields[key])
317
+
261
318
  })
262
319
  if (handleChange) debounceHandleFieldsChange();
263
320
  }
@@ -269,12 +326,40 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
269
326
  let current_value = getParamValue("fieldsValue", current_identifier, fieldValues, null)
270
327
  let changedFields = {}
271
328
 
329
+ // 将标识符标准化为字符串
330
+ const sourceFieldId = Array.isArray(current_identifier)
331
+ ? current_identifier.filter(item => typeof item == "string").join(".")
332
+ : current_identifier;
333
+
272
334
  let idGroups = []
273
335
  for (let index = 0; index < fillRules.length; index++) {
274
336
  const rule = fillRules[index];
275
337
  let { source, target } = rule
276
338
  let source_value = current_value?.[source]
277
339
  let setValue = source_value
340
+
341
+ // 将sourceField格式化为字符串形式,用于依赖跟踪
342
+ const sourceField = Array.isArray(current_identifier)
343
+ ? current_identifier.filter(item => typeof item == "string").join(".")
344
+ : current_identifier;
345
+
346
+ // 格式化目标字段
347
+ const targetField = Array.isArray(target)
348
+ ? target.filter(item => typeof item == "string").join(".")
349
+ : target;
350
+
351
+ // // 检查循环依赖 - 使用更高级的依赖图检测
352
+ // if (dependencyGraphRef.current.hasCircularDependency(targetField)) {
353
+ // const currentPath = dependencyGraphRef.current.getCurrentPath();
354
+ // console.log(`检测到填充规则中的循环依赖链路: ${[...currentPath, targetField].join(' -> ')}`);
355
+ // continue; // 跳过这条规则
356
+ // }
357
+
358
+
359
+ //// 添加到依赖路径
360
+ // dependencyGraphRef.current.addToPath(targetField);
361
+
362
+
278
363
  // 子表
279
364
  if (rule?.type == 1) {
280
365
  if (dependencyMap.current.has(target)) {
@@ -324,15 +409,9 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
324
409
  form.setFieldValue(target, undefined);
325
410
  }
326
411
  form.setFieldValue(target, setValue)
327
- // handleFieldsWith(target, form.getFieldsValue())
328
- // setTimeout(() => {
329
- // form.setFieldValue(target, setValue)
330
- // handleFieldsWith(target, form.getFieldsValue())
331
- // if (idGroups.length > 0) handleTableAddRow(idGroups)
332
- // }, 0);
333
-
334
-
335
- // if (idGroups.length > 0) setTimeout(() => handleTableAddRow(idGroups), 0)
412
+
413
+ // 处理完当前字段后从依赖路径中移除
414
+ dependencyGraphRef.current.finishField();
336
415
  }
337
416
 
338
417
  setTimeout(() => {
@@ -340,7 +419,6 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
340
419
  // console.log("idGroups", idGroups)
341
420
  if (idGroups.length > 0) idGroups.forEach(ids => { if (Array.isArray(ids) && ids.length > 0) handleTableAddRow(ids) })
342
421
  }, 0)
343
-
344
422
  }
345
423
  // 处理级联显示隐藏 @return {boolean} 是否需要重新渲染表单的字段
346
424
  const handleFieldsVisibleFunc = (fieldValues, child, parentIdentifier) => {
@@ -458,7 +536,7 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
458
536
  }
459
537
  // 处理级联数据源
460
538
  // 处理级联填充
461
- const handleFieldsWithFill = async (fieldValues, child, parentIdentifier, componentName) => {
539
+ const handleFieldsWithFill = async (fieldValues, child, parentIdentifier, componentName, sourceFieldId) => {
462
540
  // console.log("handleFieldsWithFill child.identifier", child.identifier)
463
541
  // console.log("handleFieldsWithFill parentIdentifier", parentIdentifier)
464
542
  console.log("handleFieldsWithFill componentName", componentName)
@@ -480,89 +558,110 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
480
558
  let table_values = getParamValue("fieldsValue", childIdentifier[0], fieldValues, [])
481
559
  if (Array.isArray(table_values) && table_values.length > 0)
482
560
  for (let index = 0; index < table_values.length; index++) {
483
- await handleFieldsWithFill(fieldValues, child, [childIdentifier[0], index], componentName)
561
+ await handleFieldsWithFill(fieldValues, child, [childIdentifier[0], index], componentName, sourceFieldId)
484
562
  }
485
563
 
486
-
487
564
  return
488
-
489
565
  }
490
- let withDatas = [];
491
- // 先处理依赖数据
492
- if (withFill?.withData && withFill?.withData.length > 0 && withDataFetch && typeof withDataFetch === 'function') {
493
- for (let index = 0; index < withFill?.withData.length; index++) {
494
- const element = withFill?.withData[index];
495
- let params = {}
496
- params.tableName = element.withTable.table_name
497
- params.filter = {}
498
- for (let index = 0; index < element.withCondition.length; index++) {
499
- const { value: condition_value, column: condition_column } = element.withCondition[index];
500
- let filter_value = getParamValue(condition_value.group_key, condition_value.field_key, fieldValues, withDatas)
501
- if (Array.isArray(filter_value)) {
502
- if (Array.isArray(childIdentifier) && filter_value.length > withFillIndex) {
503
- filter_value = filter_value[withFillIndex]
566
+
567
+ // 将目标字段ID标准化为字符串
568
+ const targetFieldId = Array.isArray(childIdentifier)
569
+ ? childIdentifier.filter(item => typeof item == "string").join(".")
570
+ : childIdentifier;
571
+
572
+ // 检查是否在当前依赖链中已存在,避免循环依赖
573
+ if (dependencyGraphRef.current.hasCircularDependency(targetFieldId)) {
574
+ const currentPath = dependencyGraphRef.current.getCurrentPath();
575
+ console.log(`检测到公式计算中的循环依赖链路: ${[...currentPath, targetFieldId].join(' -> ')}`);
576
+ return;
577
+ }
578
+
579
+ // // 将当前字段添加到依赖路径
580
+ // dependencyGraphRef.current.addToPath(targetFieldId);
581
+
582
+ try {
583
+ let withDatas = [];
584
+ // 先处理依赖数据
585
+ if (withFill?.withData && withFill?.withData.length > 0 && withDataFetch && typeof withDataFetch === 'function') {
586
+ for (let index = 0; index < withFill?.withData.length; index++) {
587
+ const element = withFill?.withData[index];
588
+ let params = {}
589
+ params.tableName = element.withTable.table_name
590
+ params.filter = {}
591
+ for (let index = 0; index < element.withCondition.length; index++) {
592
+ const { value: condition_value, column: condition_column } = element.withCondition[index];
593
+ let filter_value = getParamValue(condition_value.group_key, condition_value.field_key, fieldValues, withDatas)
594
+ if (Array.isArray(filter_value)) {
595
+ if (Array.isArray(childIdentifier) && filter_value.length > withFillIndex) {
596
+ filter_value = filter_value[withFillIndex]
597
+ }
504
598
  }
505
- }
506
- if (filter_value && typeof filter_value === "string") {
507
- try {
508
- filter_value = JSON.parse(filter_value)
509
- } catch (error) {
599
+ if (filter_value && typeof filter_value === "string") {
600
+ try {
601
+ filter_value = JSON.parse(filter_value)
602
+ } catch (error) {
603
+ }
510
604
  }
605
+ if (filter_value?.value) filter_value = filter_value.value
606
+ // if (componentName == "Field.WithSingleSelect" && filter_value) {
607
+ // if (typeof filter_value === "string") {
608
+ // filter_value = JSON.parse(filter_value)
609
+ // }
610
+ // filter_value = filter_value?.value
611
+ // }
612
+ params.filter[condition_column.column_name] = filter_value
511
613
  }
512
- if (filter_value?.value) filter_value = filter_value.value
513
- // if (componentName == "Field.WithSingleSelect" && filter_value) {
514
- // if (typeof filter_value === "string") {
515
- // filter_value = JSON.parse(filter_value)
516
- // }
517
- // filter_value = filter_value?.value
518
- // }
519
- params.filter[condition_column.column_name] = filter_value
520
- }
521
614
 
522
- // 访问接口获取数据
523
- const response = await withDataFetch(params)
524
- if (response.code === 0 && response.data.list) {
525
- withDatas.push({
526
- id: element.id,
527
- data: response.data.list
528
- })
615
+ // 访问接口获取数据
616
+ const response = await withDataFetch(params)
617
+ if (response.code === 0 && response.data.list) {
618
+ withDatas.push({
619
+ id: element.id,
620
+ data: response.data.list
621
+ })
622
+ }
529
623
  }
530
624
  }
531
- }
532
625
 
533
- // 构造计算公式
534
- let formula;
535
- if (withFill.value && withFill.value.length > 0) {
536
- formula = withFill.value.map(item => {
537
- let result = "";
538
- const { insert, attributes } = item
539
- if (typeof insert !== "string") {
540
- if (insert?.span && attributes && attributes.tagKey && attributes.id) {
541
- result = getParamValue(attributes.tagKey, attributes.id, fieldValues, withDatas)
542
- if (Array.isArray(result)) {
543
- if (Array.isArray(childIdentifier) && result.length > withFillIndex) {
544
- result = result[withFillIndex]
626
+ // 构造计算公式
627
+ let formula;
628
+ if (withFill.value && withFill.value.length > 0) {
629
+ formula = withFill.value.map(item => {
630
+ let result = "";
631
+ const { insert, attributes } = item
632
+ if (typeof insert !== "string") {
633
+ if (insert?.span && attributes && attributes.tagKey && attributes.id) {
634
+ result = getParamValue(attributes.tagKey, attributes.id, fieldValues, withDatas)
635
+ if (Array.isArray(result)) {
636
+ if (Array.isArray(childIdentifier) && result.length > withFillIndex) {
637
+ result = result[withFillIndex]
638
+ }
639
+ if (typeof result === "object" && result !== null)
640
+ result = JSON.stringify(result)
545
641
  }
546
- if (typeof result === "object" && result !== null)
642
+ else if (typeof result === "object" && result !== null) {
547
643
  result = JSON.stringify(result)
644
+ }
645
+ else if (result.length > 0) result = `"${result}"`
548
646
  }
549
- else if (typeof result === "object" && result !== null) {
550
- result = JSON.stringify(result)
551
- }
552
- else if (result.length > 0) result = `"${result}"`
553
647
  }
554
- }
555
- else result = insert
556
- return result
557
- })
558
- }
648
+ else result = insert
649
+ return result
650
+ })
651
+ }
559
652
 
560
- if (formula && formula.length > 0) {
561
- const formulaResult = evalFormula(formula);
562
- console.log(`${childIdentifier} 计算公式:`, formula)
563
- console.log(`${childIdentifier} 计算结果:`, formulaResult)
564
- form.setFieldValue(childIdentifier, formulaResult)
565
- await handleFieldsWith(childIdentifier, form.getFieldsValue())
653
+ if (formula && formula.length > 0) {
654
+ const formulaResult = evalFormula(formula);
655
+ console.log(`${childIdentifier} 计算公式:`, formula)
656
+ console.log(`${childIdentifier} 计算结果:`, formulaResult)
657
+
658
+
659
+ form.setFieldValue(childIdentifier, formulaResult)
660
+ await handleFieldsWith(childIdentifier, form.getFieldsValue(), false, targetFieldId)
661
+ }
662
+ } finally {
663
+ // 处理完毕后,从依赖路径中删除当前字段
664
+ dependencyGraphRef.current.finishField();
566
665
  }
567
666
  }
568
667
 
@@ -606,6 +705,8 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
606
705
  const delay = lockStatus.current === 1 ? 500 : 100;
607
706
 
608
707
  timeoutRef.current = setTimeout(async () => {
708
+ // 开始新的更新周期
709
+ dependencyGraphRef.current.startNewCycle();
609
710
 
610
711
  const fieldValues = form.getFieldsValue();
611
712
  const lockStatus_ = lockStatus.current;
@@ -613,14 +714,25 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
613
714
  let needRefresh = false;
614
715
  if (!lastFormValues.current) lastFormValues.current = {}
615
716
 
717
+ // 创建已处理字段集合,用于避免多次处理同一字段
718
+ const processedFields = new Set();
719
+
616
720
  for (let key in changedFieldsState.current) {
617
721
  let field = changedFieldsState.current[key];
618
722
  if (!isEqual(field.value || "", getLastFieldValue(field.name) || "")) {
619
723
  if (lockStatus_ != 1) {
620
- // console.log("handleFieldsWith field.name", field.name)
621
- let needRefresh_ = await handleFieldsWith(field.name, fieldValues);
622
- needRefresh = needRefresh || needRefresh_
623
-
724
+ // 获取字段标识符(字符串形式)
725
+ const fieldId = Array.isArray(field.name)
726
+ ? field.name.filter(item => typeof item == "string").join(".")
727
+ : field.name;
728
+
729
+ // 跳过已处理的字段
730
+ if (processedFields.has(fieldId)) continue;
731
+ processedFields.add(fieldId);
732
+
733
+ // 处理字段依赖关系,传递字段ID和依赖图谱
734
+ let needRefresh_ = await handleFieldsWith(field.name, fieldValues, false, fieldId);
735
+ needRefresh = needRefresh || needRefresh_;
624
736
  }
625
737
  lastFormValues.current[field.name] = field.value;
626
738
  }
@@ -638,6 +750,8 @@ const FormContainer = forwardRef(({ cols = 1, children, mode = "view" }, ref) =>
638
750
  if (field.name && field.name.length > 0) {
639
751
  // const fieldKey = field.name.filter(item => typeof item == "string").join(".")
640
752
  changedFieldsState.current[field.name] = field;
753
+
754
+
641
755
  }
642
756
  })
643
757