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.
- package/lib/core/locales/en.js +8 -3
- package/lib/core/locales/zh.js +8 -3
- package/lib/integration/integration-create.js +151 -4
- package/lib/integration/integration-diagnostics.js +12 -12
- package/lib/integration/integration-form-metadata.js +136 -0
- package/lib/integration/integration-process-builder.js +31 -4
- package/lib/integration/integration-spec-builder.js +570 -73
- package/lib/integration/integration-view-builder.js +240 -15
- package/package.json +1 -1
- package/yida-skills/SKILL.md +1 -0
- package/yida-skills/skills/yida-integration/SKILL.md +44 -5
- package/yida-skills/skills/yida-integration/references/integration-node-schemas.md +21 -0
package/lib/core/locales/en.js
CHANGED
|
@@ -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
|
|
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
|
|
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}',
|
package/lib/core/locales/zh.js
CHANGED
|
@@ -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
|
|
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>
|
|
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}
|
|
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
|
|
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
|
-
|
|
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: '
|
|
28
|
-
en: 'Use form instance
|
|
27
|
+
zh: '获取自身应使用来源表单的唯一实例字段精确匹配',
|
|
28
|
+
en: 'Use the source form unique instance field for get-self',
|
|
29
29
|
},
|
|
30
30
|
summary: {
|
|
31
|
-
zh: '
|
|
32
|
-
en: 'When reading the current trigger record, match the
|
|
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: '
|
|
36
|
-
en: 'Recommended setup: Get single data from the trigger form
|
|
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: '
|
|
53
|
-
en: 'Before using a serial number, add a get-self node
|
|
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: '
|
|
70
|
-
en: 'Check that the left-side field belongs to the queried form. For get-self, use query-side pid
|
|
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: '
|
|
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
|
|
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
|
|
417
|
-
|
|
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:
|
|
470
|
+
originalType: resolveDataOriginalType(dataSourceFormType),
|
|
444
471
|
subSourceId: '',
|
|
445
472
|
condition: conditions,
|
|
446
473
|
quantity: '1',
|