openyida 2026.9.7 → 2026.9.8

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.
@@ -414,9 +414,9 @@ Examples:
414
414
  create_opt_spec: ' --spec <file.json> Use a structured flow spec for complex automation nodes (dataUpdate/route, etc.)',
415
415
  create_opt_data_form_uuid: ' --data-form-uuid <uuid> Target form UUID for a get-single-data node',
416
416
  create_opt_data_condition: ' --data-condition <rule> Get-data condition: targetField:label:triggerField[:component[:opCode[:valueType]]]',
417
- create_opt_get_self: ' --get-self Insert a get-self node (pid equals trigger form instance ID)',
417
+ create_opt_get_self: ' --get-self Insert a get-self node (process runtime uses pid, designer uses proc_inst_id; ordinary forms use form_inst_id on both sides)',
418
418
  create_opt_get_self_field: ' --get-self-field <field> Override the trigger-side system field, default __masterdata_form_inst_id',
419
- create_opt_get_self_query_field: ' --get-self-query-field <f> Override the query-side system field, default pid',
419
+ create_opt_get_self_query_field: ' --get-self-query-field <f> Override the query-side system field (process: pid runtime / proc_inst_id designer; ordinary: form_inst_id)',
420
420
  create_opt_add_data_form_uuid: ' --add-data-form-uuid <uuid> Target form UUID for an add-data node',
421
421
  create_opt_add_data_assignment: ' --add-data-assignment <rule> Add-data assignment: targetField:valueType:value',
422
422
  create_opt_initiate_approval_form_uuid: ' --initiate-approval-form-uuid <uuid> Target process-form UUID for an initiate-approval node',
@@ -432,6 +432,11 @@ Examples:
432
432
  create_example2: ' openyida integration create APP_XXX FORM-XXX "Get self then notify" --get-self --publish',
433
433
  create_missing_args: 'Missing required arguments.',
434
434
  create_replace_required: 'Using --process-code fully replaces the existing flow. Pass --replace explicitly. Safe editing is not currently available; integration update only reports capability status.',
435
+ create_source_form_fetch_failed: 'Could not read the data-source form metadata; remote write stopped: {0}',
436
+ create_source_form_not_found: 'Could not find data-source form {0} in navigation; remote write stopped.',
437
+ create_source_form_type_unknown: 'Navigation did not return a verifiable data-source form type; remote write stopped.',
438
+ create_source_form_type_invalid: 'Navigation returned unsupported data-source form type "{0}"; remote write stopped.',
439
+ create_source_form_type_mismatch: 'Explicit formType={0} conflicts with navigation metadata {1}; remote write stopped.',
435
440
  create_flow_name_too_long: 'Logic-flow names cannot exceed {0} characters (received {1}).',
436
441
  create_invalid_events: 'No valid trigger event was recognized.',
437
442
  create_no_receivers: 'No notification receiver or user field specified; no message node will be generated.',
@@ -449,7 +454,7 @@ Examples:
449
454
  create_notify_content: 'Notification content: {0}',
450
455
  create_data_form: 'Get-data form: {0}',
451
456
  create_data_conditions: 'Get-data condition count: {0}',
452
- create_get_self_summary: 'Get-self guardrail: {0} equals field {1}',
457
+ create_get_self_summary: 'Get-self guardrail: runtime query field {0} equals field {1}; process-form designer maps it to proc_inst_id, while ordinary forms keep the same field',
453
458
  create_op_mode_publish: 'Mode: save and publish',
454
459
  create_op_mode_draft: 'Mode: save draft only',
455
460
  create_step: '[{0}/{1}] {2}',
@@ -410,9 +410,9 @@ openyida - 宜搭命令行工具
410
410
  create_opt_spec: ' --spec <file.json> 使用结构化编排文件创建复杂自动化(dataUpdate/route 等)',
411
411
  create_opt_data_form_uuid: ' --data-form-uuid <uuid> 插入获取单条数据节点的目标表单 UUID',
412
412
  create_opt_data_condition: ' --data-condition <rule> 获取数据过滤条件:目标字段:字段名:触发字段[:组件[:操作符[:值类型]]]',
413
- create_opt_get_self: ' --get-self 自动插入获取自身节点(pid 等于触发事件表单实例ID)',
413
+ create_opt_get_self: ' --get-self 自动插入获取自身节点(流程表单运行态使用 pid、设计器使用 proc_inst_id;普通表单两侧使用 form_inst_id)',
414
414
  create_opt_get_self_field: ' --get-self-field <field> 覆盖右侧触发事件系统字段,默认 __masterdata_form_inst_id',
415
- create_opt_get_self_query_field: ' --get-self-query-field <f> 覆盖左侧查询系统字段,默认 pid',
415
+ create_opt_get_self_query_field: ' --get-self-query-field <f> 覆盖左侧查询系统字段(流程表单默认 pid,普通表单默认 form_inst_id)',
416
416
  create_opt_add_data_form_uuid: ' --add-data-form-uuid <uuid> 插入新增数据节点的目标表单 UUID',
417
417
  create_opt_add_data_assignment: ' --add-data-assignment <rule> 新增数据赋值:目标字段:valueType:value',
418
418
  create_opt_initiate_approval_form_uuid: ' --initiate-approval-form-uuid <uuid> 发起审批节点的目标流程表单 UUID',
@@ -428,6 +428,11 @@ openyida - 宜搭命令行工具
428
428
  create_example2: ' openyida integration create APP_XXX FORM-XXX "获取自身后通知" --get-self --publish',
429
429
  create_missing_args: '缺少必要参数。',
430
430
  create_replace_required: '使用 --process-code 会整图替换已有逻辑流;必须显式传入 --replace。安全二次编辑当前不可用,integration update 仅报告 capability 状态。',
431
+ create_source_form_fetch_failed: '获取取数来源表单信息失败,已停止远端写入: {0}',
432
+ create_source_form_not_found: '获取取数来源表单信息失败,导航中未找到表单 {0},已停止远端写入',
433
+ create_source_form_type_unknown: '获取取数来源表单信息失败,导航未返回可确认的表单类型,已停止远端写入',
434
+ create_source_form_type_invalid: '获取取数来源表单信息失败,导航返回的表单类型“{0}”不是可取数表单,已停止远端写入',
435
+ create_source_form_type_mismatch: '获取取数来源表单信息失败,显式 formType={0} 与导航元数据 {1} 不一致,已停止远端写入',
431
436
  create_flow_name_too_long: '逻辑流名称不能超过 {0} 个字符(当前 {1} 个)。',
432
437
  create_invalid_events: '未识别到有效触发事件。',
433
438
  create_no_receivers: '未指定通知接收人或成员字段,将不会生成消息通知节点。',
@@ -445,7 +450,7 @@ openyida - 宜搭命令行工具
445
450
  create_notify_content: '通知内容: {0}',
446
451
  create_data_form: '获取数据表单: {0}',
447
452
  create_data_conditions: '获取数据条件数: {0}',
448
- create_get_self_summary: '获取自身闭坑: {0} 等于 字段 {1}',
453
+ create_get_self_summary: '获取自身闭坑: 运行态查询字段 {0} 等于字段 {1};流程表单设计器对应 proc_inst_id,普通表单设计器保持一致',
449
454
  create_op_mode_publish: '操作模式: 保存并发布',
450
455
  create_op_mode_draft: '操作模式: 仅保存草稿',
451
456
  create_step: '[{0}/{1}] {2}',
@@ -17,9 +17,16 @@ const {
17
17
  validateIntegrationSpec,
18
18
  buildSpecProcessAndViewJson,
19
19
  collectAddDataFormUuids,
20
+ collectDataSourceFormDescriptors,
20
21
  collectInitiateApprovalFormUuids,
21
22
  hasSpecNodeType,
22
23
  } = require('./integration-spec-builder');
24
+ const {
25
+ normalizeSourceFormType,
26
+ toRuntimeDataQueryField,
27
+ toDesignerDataQueryField,
28
+ normalizeDataQueryFieldName,
29
+ } = require('./integration-form-metadata');
23
30
  const { t } = require('../core/i18n');
24
31
  const { warn } = require('../core/chalk');
25
32
  const { CliError } = require('../core/cli-error');
@@ -415,7 +422,7 @@ async function run(args) {
415
422
  const getSelfTriggerField = parseFlag(subArgs, '--get-self-field')
416
423
  || parseFlag(subArgs, '--get-self-trigger-field')
417
424
  || '__masterdata_form_inst_id';
418
- const getSelfQueryField = parseFlag(subArgs, '--get-self-query-field') || 'pid';
425
+ const getSelfQueryFieldOverride = parseFlag(subArgs, '--get-self-query-field');
419
426
  const shouldPublish = hasFlag(subArgs, '--publish');
420
427
  let integrationSpec = null;
421
428
  if (specPath) {
@@ -439,6 +446,11 @@ async function run(args) {
439
446
  const formEventTypes = mapEventTypes(
440
447
  eventsRaw.split(',').map((event) => event.trim()).filter(Boolean)
441
448
  );
449
+ let getSelfQueryField = getSelfQueryFieldOverride || (
450
+ formEventTypes.includes('processFinish') || formEventTypes.includes('activityTask')
451
+ ? 'pid'
452
+ : 'form_inst_id'
453
+ );
442
454
  const approvalActions = normalizeApprovalActions(approvalActionsRaw
443
455
  ? approvalActionsRaw.split(',').map((item) => item.trim()).filter(Boolean)
444
456
  : []);
@@ -453,7 +465,7 @@ async function run(args) {
453
465
 
454
466
  if (integrationSpec) {
455
467
  try {
456
- validateIntegrationSpec(integrationSpec, formEventTypes);
468
+ validateIntegrationSpec(integrationSpec, formEventTypes, { formUuid });
457
469
  } catch (error) {
458
470
  throw new CliError(`读取 --spec 失败:${error.message}`, {
459
471
  code: 'INTEGRATION_SPEC_INVALID',
@@ -674,7 +686,13 @@ async function run(args) {
674
686
  totalSteps++;
675
687
  } // 获取目标表单 Schema
676
688
  const specAddDataFormUuids = integrationSpec
677
- ? collectAddDataFormUuids(integrationSpec).filter((uuid) => uuid !== addDataFormUuid)
689
+ ? collectAddDataFormUuids(integrationSpec, formUuid).filter((uuid) => uuid !== addDataFormUuid)
690
+ : [];
691
+ const specDirectAddDataFormUuids = integrationSpec
692
+ ? collectAddDataFormUuids(integrationSpec, formUuid, { kind: 'direct' })
693
+ : [];
694
+ const specSubTableParentFormUuids = integrationSpec
695
+ ? collectAddDataFormUuids(integrationSpec, formUuid, { kind: 'sub_table' })
678
696
  : [];
679
697
  const specInitiateApprovalFormUuids = integrationSpec
680
698
  ? collectInitiateApprovalFormUuids(integrationSpec).filter((uuid) => uuid !== initiateApprovalFormUuid)
@@ -756,6 +774,13 @@ async function run(args) {
756
774
  ...(addDataFormUuid ? [addDataFormUuid.toString()] : []),
757
775
  ...specAddDataFormUuids.map((uuid) => uuid.toString()),
758
776
  ]));
777
+ const directAddDataTargetUuidSet = new Set([
778
+ ...(addDataFormUuid ? [addDataFormUuid.toString()] : []),
779
+ ...specDirectAddDataFormUuids.map((uuid) => uuid.toString()),
780
+ ]);
781
+ const subTableParentFormUuidSet = new Set(
782
+ specSubTableParentFormUuids.map((uuid) => uuid.toString())
783
+ );
759
784
  const addDataTargetFormsByUuid = new Map();
760
785
  for (const targetFormUuid of addDataTargetUuids) {
761
786
  let targetForm;
@@ -765,7 +790,9 @@ async function run(args) {
765
790
  throw new Error(`获取目标表单信息失败,无法确认 ${targetFormUuid} 是否为普通表单: ${error.message}`);
766
791
  }
767
792
  const targetFormType = normalizeFormType(targetForm && targetForm.formType);
768
- if (targetFormType !== 'receipt') {
793
+ const isSubTableOnlyParent = subTableParentFormUuidSet.has(targetFormUuid)
794
+ && !directAddDataTargetUuidSet.has(targetFormUuid);
795
+ if (targetFormType !== 'receipt' && !(isSubTableOnlyParent && targetFormType === 'process')) {
769
796
  const errorMessage = targetFormType === 'process'
770
797
  ? buildProcessAddDataTargetError(targetForm, targetFormUuid)
771
798
  : `无法确认 ${targetFormUuid} 是普通表单,已停止创建“新增数据”节点。`;
@@ -788,6 +815,118 @@ async function run(args) {
788
815
  ? addDataTargetFormsByUuid.get(addDataFormUuid.toString())
789
816
  : null;
790
817
 
818
+ const sourceFormDescriptors = integrationSpec
819
+ ? collectDataSourceFormDescriptors(integrationSpec, formUuid)
820
+ : (dataFormUuid ? [{ formUuid: dataFormUuid.toString() }] : []);
821
+ const dataSourceFormsByUuid = new Map();
822
+ // Source metadata is part of the write preflight. Never silently downgrade an
823
+ // unverified source to a receipt; a spec may continue only with a validated
824
+ // explicit formType (and uses its declared name as the designer title).
825
+ for (const descriptor of sourceFormDescriptors) {
826
+ const explicitType = normalizeSourceFormType(descriptor.formType);
827
+ let dataSourceForm;
828
+ let navigationReadSuccessfully = false;
829
+ try {
830
+ dataSourceForm = await findFormNavigationItem(
831
+ authRef,
832
+ appType,
833
+ descriptor.formUuid,
834
+ getFormNavigationItems,
835
+ );
836
+ navigationReadSuccessfully = true;
837
+ } catch (error) {
838
+ if (!explicitType) {
839
+ throw new Error(t('integration.create_source_form_fetch_failed', error.message));
840
+ }
841
+ dataSourceForm = {
842
+ formUuid: descriptor.formUuid,
843
+ formName: descriptor.formName || descriptor.formUuid,
844
+ formType: explicitType,
845
+ };
846
+ }
847
+
848
+ if (navigationReadSuccessfully && !dataSourceForm) {
849
+ throw new Error(t('integration.create_source_form_not_found', descriptor.formUuid));
850
+ }
851
+
852
+ const rawRemoteFormType = dataSourceForm && dataSourceForm.formType !== undefined
853
+ && dataSourceForm.formType !== null
854
+ ? String(dataSourceForm.formType).trim()
855
+ : '';
856
+ const remoteFormType = normalizeSourceFormType(rawRemoteFormType);
857
+ if (navigationReadSuccessfully && (!rawRemoteFormType || !remoteFormType)) {
858
+ throw new Error(
859
+ dataSourceForm && rawRemoteFormType
860
+ ? t('integration.create_source_form_type_invalid', dataSourceForm.formType)
861
+ : t('integration.create_source_form_type_unknown')
862
+ );
863
+ }
864
+ if (explicitType && remoteFormType && explicitType !== remoteFormType) {
865
+ throw new Error(t(
866
+ 'integration.create_source_form_type_mismatch',
867
+ descriptor.formType,
868
+ dataSourceForm.formType,
869
+ ));
870
+ }
871
+ const sourceFormType = remoteFormType || explicitType;
872
+ if (!dataSourceForm || !sourceFormType) {
873
+ const reason = dataSourceForm
874
+ ? `表单类型“${dataSourceForm.formType || '未知'}”无法确认`
875
+ : `导航中未找到表单 ${descriptor.formUuid}`;
876
+ if (!explicitType) {
877
+ throw new Error(t('integration.create_source_form_fetch_failed', reason));
878
+ }
879
+ dataSourceForm = {
880
+ formUuid: descriptor.formUuid,
881
+ formName: descriptor.formName || descriptor.formUuid,
882
+ formType: explicitType,
883
+ };
884
+ }
885
+ dataSourceFormsByUuid.set(String(descriptor.formUuid), {
886
+ ...dataSourceForm,
887
+ formUuid: String(descriptor.formUuid),
888
+ formType: sourceFormType,
889
+ formName: dataSourceForm.formName || descriptor.formName || descriptor.formUuid,
890
+ });
891
+ }
892
+
893
+ const dataSourceForm = dataFormUuid
894
+ ? dataSourceFormsByUuid.get(String(dataFormUuid))
895
+ : null;
896
+ if (dataSourceForm && getSelf && !getSelfQueryFieldOverride) {
897
+ getSelfQueryField = normalizeSourceFormType(dataSourceForm.formType) === 'process'
898
+ ? 'pid'
899
+ : 'form_inst_id';
900
+ dataConditions[0].bFieldId = getSelfQueryField;
901
+ dataConditions[0].bFieldName = getSelfQueryField === 'pid' ? '流程实例ID' : '表单实例ID';
902
+ }
903
+ if (dataSourceForm) {
904
+ for (const condition of dataConditions) {
905
+ if (!condition) {
906
+ continue;
907
+ }
908
+ const runtimeFieldId = toRuntimeDataQueryField(condition.bFieldId, dataSourceForm.formType);
909
+ condition.bFieldId = runtimeFieldId;
910
+ condition.bFieldName = normalizeDataQueryFieldName(
911
+ runtimeFieldId,
912
+ dataSourceForm.formType,
913
+ condition.bFieldName,
914
+ );
915
+ }
916
+ }
917
+ const viewDataConditions = dataConditions.map((condition) => {
918
+ if (!condition) {
919
+ return condition;
920
+ }
921
+ const designerFieldId = toDesignerDataQueryField(
922
+ condition.bFieldId,
923
+ dataSourceForm && dataSourceForm.formType,
924
+ );
925
+ return designerFieldId === condition.bFieldId
926
+ ? condition
927
+ : { ...condition, bFieldId: designerFieldId };
928
+ });
929
+
791
930
  // Step 2(新建模式):调用 createLogicflow 接口新建绑定关系,获取真实 processCode
792
931
  const initiateApprovalTargetUuids = Array.from(new Set([
793
932
  ...(initiateApprovalFormUuid ? [initiateApprovalFormUuid.toString()] : []),
@@ -931,6 +1070,7 @@ async function run(args) {
931
1070
  toUsers,
932
1071
  userFields,
933
1072
  formSchemasByUuid,
1073
+ dataSourceFormsByUuid,
934
1074
  formNamesByUuid,
935
1075
  currentUserId: authRef.userId,
936
1076
  });
@@ -957,6 +1097,9 @@ async function run(args) {
957
1097
  initiateApprovalInitiator,
958
1098
  initiateApprovalAssignments,
959
1099
  dataFormUuid: dataFormUuid ?? undefined,
1100
+ dataFormType: dataSourceForm ? dataSourceForm.formType : undefined,
1101
+ dataFormName: dataSourceForm ? dataSourceForm.formName : undefined,
1102
+ dataSourceFormsByUuid,
960
1103
  dataConditions,
961
1104
  hasMessageNode,
962
1105
  approvalActions,
@@ -990,7 +1133,11 @@ async function run(args) {
990
1133
  initiateApprovalInitiator,
991
1134
  initiateApprovalAssignments,
992
1135
  dataFormUuid: dataFormUuid ?? undefined,
1136
+ dataFormType: dataSourceForm ? dataSourceForm.formType : undefined,
1137
+ dataFormName: dataSourceForm ? dataSourceForm.formName : undefined,
1138
+ dataSourceFormsByUuid,
993
1139
  dataConditions,
1140
+ viewDataConditions,
994
1141
  hasMessageNode,
995
1142
  approvalActions,
996
1143
  approvalNodeIds,
@@ -24,16 +24,16 @@ const PITFALL_RULES = [
24
24
  id: 'get-self-form-inst-id',
25
25
  severity: 'info',
26
26
  title: {
27
- zh: '获取自身应使用表单实例ID精确匹配',
28
- en: 'Use form instance ID for get-self',
27
+ zh: '获取自身应使用来源表单的唯一实例字段精确匹配',
28
+ en: 'Use the source form unique instance field for get-self',
29
29
  },
30
30
  summary: {
31
- zh: '获取当前触发记录时,推荐用同表的表单实例ID等于触发记录表单实例ID。',
32
- en: 'When reading the current trigger record, match the same form by form instance ID.',
31
+ zh: '获取当前触发记录时,按来源表单类型使用对应的唯一实例字段精确匹配。',
32
+ en: 'When reading the current trigger record, match the appropriate unique instance field for the source form type.',
33
33
  },
34
34
  recommendation: {
35
- zh: '标准配置:获取单条数据,来源表单为当前触发表,过滤条件用查询侧系统字段 pid 等于触发事件字段 __masterdata_form_inst_id。CLI 可使用 --get-self 生成该节点。',
36
- en: 'Recommended setup: Get single data from the trigger form with query-side system field pid equal to trigger field __masterdata_form_inst_id. The CLI can generate this via --get-self.',
35
+ zh: '标准配置:获取单条数据,来源表单为当前触发表;流程表单运行态使用查询侧系统字段 pid、设计器使用 proc_inst_id,普通表单两侧使用 form_inst_id,均等于触发事件字段 __masterdata_form_inst_id。CLI 可使用 --get-self 生成该节点。',
36
+ en: 'Recommended setup: Get single data from the trigger form. Process forms use query-side pid at runtime and proc_inst_id in the designer; ordinary forms use form_inst_id on both sides. All match the trigger field __masterdata_form_inst_id. The CLI can generate this via --get-self.',
37
37
  },
38
38
  patterns: [/获取自身/i, /表单实例ID/i, /formInstId/i, /__masterdata_form_inst_id/i, /form instance/i, /get.?self/i],
39
39
  },
@@ -49,8 +49,8 @@ const PITFALL_RULES = [
49
49
  en: 'Reading a serial number directly from trigger payload can return empty or stale values.',
50
50
  },
51
51
  recommendation: {
52
- zh: '需要消费流水号时,先用获取自身节点按表单实例ID重新获取最新记录,再引用该节点里的流水号字段。',
53
- en: 'Before using a serial number, add a get-self node by form instance ID and read the serial number from that node output.',
52
+ zh: '需要消费流水号时,先用获取自身节点按来源表单对应的唯一实例字段重新获取最新记录,再引用该节点里的流水号字段。',
53
+ en: 'Before using a serial number, add a get-self node using the source form type\'s unique instance field and read the serial number from that node output.',
54
54
  },
55
55
  patterns: [/流水号/i, /serialNumber/i, /SerialNumberField/i],
56
56
  },
@@ -66,8 +66,8 @@ const PITFALL_RULES = [
66
66
  en: 'A "field is null" log usually means the data retrieve filter uses a missing field ID, an event field on the query side, or an unsupported field type.',
67
67
  },
68
68
  recommendation: {
69
- zh: '检查获取数据节点左侧字段必须是被查询表单里的字段。获取自身时标准配置是查询侧 pid 等于触发事件字段 __masterdata_form_inst_id;不要把 __masterdata_form_inst_id 或 formInstId 放在查询侧。',
70
- en: 'Check that the left-side field belongs to the queried form. For get-self, use query-side pid equals trigger field __masterdata_form_inst_id; do not put __masterdata_form_inst_id or formInstId on the query side.',
69
+ zh: '检查获取数据节点左侧字段必须是被查询表单里的字段。获取自身时,流程表单运行态使用查询侧 pid、设计器使用 proc_inst_id,普通表单两侧使用 form_inst_id;均等于触发事件字段 __masterdata_form_inst_id。不要把 __masterdata_form_inst_id 或 formInstId 放在查询侧。',
70
+ en: 'Check that the left-side field belongs to the queried form. For get-self, process forms use query-side pid at runtime and proc_inst_id in the designer; ordinary forms use form_inst_id on both sides. Do not put __masterdata_form_inst_id or formInstId on the query side.',
71
71
  },
72
72
  patterns: [/field is null/i, /暂时不支持其他类型Field/i, /selectListException/i],
73
73
  },
@@ -306,7 +306,7 @@ function buildCheckHints(options = {}) {
306
306
  {
307
307
  id: 'get-self-standard',
308
308
  severity: 'info',
309
- message: '获取自身的标准配置是:查询侧系统字段 pid 等于触发事件字段 __masterdata_form_inst_id;创建时可使用 --get-self。',
309
+ message: '获取自身的标准配置是:流程表单运行态查询侧 pid、设计器 proc_inst_id,普通表单两侧 form_inst_id,均等于触发事件字段 __masterdata_form_inst_id;创建时可使用 --get-self。',
310
310
  },
311
311
  ];
312
312
  }
@@ -319,7 +319,7 @@ function buildCheckHints(options = {}) {
319
319
  {
320
320
  id: 'get-self-standard',
321
321
  severity: 'info',
322
- message: 'Recommended get-self setup: query-side system field pid equals trigger field __masterdata_form_inst_id; use --get-self when creating flows.',
322
+ message: 'Recommended get-self setup: process forms use query-side pid at runtime and proc_inst_id in the designer; ordinary forms use form_inst_id on both sides. Use --get-self when creating flows.',
323
323
  },
324
324
  ];
325
325
  }
@@ -0,0 +1,136 @@
1
+ 'use strict';
2
+
3
+ function normalizeSourceFormType(value) {
4
+ const normalized = String(value || '').trim().toLowerCase();
5
+ if (normalized === 'process' || normalized === 'process_form') {
6
+ return 'process';
7
+ }
8
+ if (normalized === 'form' || normalized === 'receipt' || normalized === 'normal' || normalized === 'normal_form') {
9
+ return 'receipt';
10
+ }
11
+ return '';
12
+ }
13
+
14
+ function isGetSelfNode(node = {}) {
15
+ return node.type === 'getSelf' || node.getSelf;
16
+ }
17
+
18
+ function resolveSourceFormUuid(node = {}, context = {}) {
19
+ return node.formUuid || node.sourceId || (isGetSelfNode(node) ? context.formUuid : '');
20
+ }
21
+
22
+ function resolveContextSourceForm(node = {}, context = {}) {
23
+ const formUuid = resolveSourceFormUuid(node, context);
24
+ if (!formUuid) {
25
+ return null;
26
+ }
27
+ const forms = context.dataSourceFormsByUuid;
28
+ if (forms instanceof Map) {
29
+ return forms.get(String(formUuid)) || forms.get(formUuid) || null;
30
+ }
31
+ if (forms && typeof forms === 'object') {
32
+ return forms[String(formUuid)] || null;
33
+ }
34
+ if (context.dataSourceForm && String(context.dataSourceForm.formUuid) === String(formUuid)) {
35
+ return context.dataSourceForm;
36
+ }
37
+ return null;
38
+ }
39
+
40
+ function resolveDataSourceFormType(node = {}, context = {}) {
41
+ const explicitType = normalizeSourceFormType(
42
+ node.formType || node.sourceFormType || node.originalType,
43
+ );
44
+ if (explicitType) {
45
+ return explicitType;
46
+ }
47
+
48
+ const sourceForm = resolveContextSourceForm(node, context);
49
+ const sourceType = normalizeSourceFormType(sourceForm && sourceForm.formType);
50
+ if (sourceType) {
51
+ return sourceType;
52
+ }
53
+
54
+ return normalizeSourceFormType(context.defaultFormType);
55
+ }
56
+
57
+ function resolveDataSourceFormName(node = {}, context = {}) {
58
+ const sourceForm = resolveContextSourceForm(node, context);
59
+ if (sourceForm && sourceForm.formName) {
60
+ return String(sourceForm.formName);
61
+ }
62
+ const explicitName = node.formName || node.sourceFormName || node.dataFormName;
63
+ if (explicitName) {
64
+ return String(explicitName);
65
+ }
66
+ return context.defaultFormName ? String(context.defaultFormName) : '';
67
+ }
68
+
69
+ function resolveDataOriginalType(sourceFormType) {
70
+ return normalizeSourceFormType(sourceFormType) === 'process' ? 'process_form' : 'form';
71
+ }
72
+
73
+ function resolveDataFormItemType(sourceFormType) {
74
+ return normalizeSourceFormType(sourceFormType) === 'process' ? 'process' : 'receipt';
75
+ }
76
+
77
+ function isSubTableOriginalType(value) {
78
+ return String(value || '').trim().toLowerCase() === 'sub_table';
79
+ }
80
+
81
+ function resolveDataQueryField(node = {}, sourceFormType) {
82
+ if (node.queryField) {
83
+ return toRuntimeDataQueryField(node.queryField, sourceFormType);
84
+ }
85
+ if (isGetSelfNode(node)) {
86
+ return normalizeSourceFormType(sourceFormType) === 'process' ? 'pid' : 'form_inst_id';
87
+ }
88
+ return '';
89
+ }
90
+
91
+ function toRuntimeDataQueryField(fieldId, sourceFormType) {
92
+ if (normalizeSourceFormType(sourceFormType) === 'process' && fieldId === 'proc_inst_id') {
93
+ return 'pid';
94
+ }
95
+ return fieldId;
96
+ }
97
+
98
+ function toDesignerDataQueryField(fieldId, sourceFormType) {
99
+ if (normalizeSourceFormType(sourceFormType) === 'process' && fieldId === 'pid') {
100
+ return 'proc_inst_id';
101
+ }
102
+ return fieldId;
103
+ }
104
+
105
+ function normalizeDataQueryFieldName(fieldId, sourceFormType, fieldName) {
106
+ const isProcessInstanceField = fieldId === 'pid' || fieldId === 'proc_inst_id';
107
+ if (normalizeSourceFormType(sourceFormType) === 'process' && isProcessInstanceField) {
108
+ return resolveDataQueryFieldName(sourceFormType);
109
+ }
110
+ return fieldName;
111
+ }
112
+
113
+ function resolveDesignerDataQueryField(node = {}, sourceFormType) {
114
+ return toDesignerDataQueryField(resolveDataQueryField(node, sourceFormType), sourceFormType);
115
+ }
116
+
117
+ function resolveDataQueryFieldName(sourceFormType) {
118
+ return normalizeSourceFormType(sourceFormType) === 'process' ? '流程实例ID' : '表单实例ID';
119
+ }
120
+
121
+ module.exports = {
122
+ normalizeSourceFormType,
123
+ isGetSelfNode,
124
+ resolveSourceFormUuid,
125
+ resolveDataSourceFormName,
126
+ resolveDataSourceFormType,
127
+ resolveDataOriginalType,
128
+ resolveDataFormItemType,
129
+ isSubTableOriginalType,
130
+ resolveDataQueryField,
131
+ toRuntimeDataQueryField,
132
+ toDesignerDataQueryField,
133
+ normalizeDataQueryFieldName,
134
+ resolveDesignerDataQueryField,
135
+ resolveDataQueryFieldName,
136
+ };
@@ -1,6 +1,12 @@
1
1
  'use strict';
2
2
 
3
3
  const { generateRuleGroupId, generateRuleItemId, generateDataRuleId, generateButtonUuid } = require('./integration-node-ids');
4
+ const {
5
+ resolveDataSourceFormType,
6
+ resolveDataOriginalType,
7
+ toRuntimeDataQueryField,
8
+ normalizeDataQueryFieldName,
9
+ } = require('./integration-form-metadata');
4
10
 
5
11
  const ALLOWED_ASSIGNMENT_VALUE_TYPES = new Set(['literal', 'processVar', 'column']);
6
12
  const ALLOWED_APPROVAL_ACTIONS = new Set(['agree', 'disagree', 'terminated']);
@@ -325,7 +331,7 @@ function buildProcessJson(options) {
325
331
  addDataFormUuid, addDataAssignments, addDataFormSchema,
326
332
  initiateApprovalFormUuid, initiateApprovalFormName,
327
333
  initiateApprovalInitiator, initiateApprovalAssignments,
328
- dataFormUuid, dataConditions, hasMessageNode, approvalActions,
334
+ dataFormUuid, dataFormType, dataConditions, hasMessageNode, approvalActions,
329
335
  approvalNodeIds, triggerRecursively, triggerConditions,
330
336
  // ConnectorCall 节点(可选):用于在集成自动化内调用任意连接器动作(如"钉钉待办/创建待办任务")
331
337
  connectorId, actionId, connectorAssignments, connectorDescription,
@@ -413,8 +419,29 @@ function buildProcessJson(options) {
413
419
 
414
420
  // 获取单条数据节点(可选)
415
421
  if (hasDataNode && dataNodeId) {
416
- const conditions = dataConditions && dataConditions.length > 0
417
- ? buildDataRetrieveCondition(dataConditions)
422
+ const dataSourceFormType = resolveDataSourceFormType(
423
+ { formUuid: dataFormUuid, formType: dataFormType },
424
+ { defaultFormType: dataFormType, formEventTypes },
425
+ );
426
+ const normalizedDataConditions = Array.isArray(dataConditions)
427
+ ? dataConditions.map((condition) => {
428
+ if (!condition) {
429
+ return condition;
430
+ }
431
+ const runtimeFieldId = toRuntimeDataQueryField(condition.bFieldId, dataSourceFormType);
432
+ return {
433
+ ...condition,
434
+ bFieldId: runtimeFieldId,
435
+ bFieldName: normalizeDataQueryFieldName(
436
+ runtimeFieldId,
437
+ dataSourceFormType,
438
+ condition.bFieldName,
439
+ ),
440
+ };
441
+ })
442
+ : dataConditions;
443
+ const conditions = normalizedDataConditions && normalizedDataConditions.length > 0
444
+ ? buildDataRetrieveCondition(normalizedDataConditions)
418
445
  : { condition: 'AND', rules: [], ruleId: generateRuleGroupId(), conditionCode: '&&' };
419
446
 
420
447
  const dataRetrieveNextId = hasAddDataNode
@@ -440,7 +467,7 @@ function buildProcessJson(options) {
440
467
  sort: { type: 'none', column: '' },
441
468
  sourceId: dataFormUuid,
442
469
  appType,
443
- originalType: 'form',
470
+ originalType: resolveDataOriginalType(dataSourceFormType),
444
471
  subSourceId: '',
445
472
  condition: conditions,
446
473
  quantity: '1',