weaver-e10-builder 1.0.7-beta → 1.0.9-beta
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/dist/commands/actionflow.d.ts +7 -0
- package/dist/commands/actionflow.d.ts.map +1 -0
- package/dist/commands/actionflow.js +105 -0
- package/dist/commands/actionflow.js.map +1 -0
- package/dist/commands/auth.js +1 -1
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/form-list.d.ts.map +1 -1
- package/dist/commands/form-list.js +18 -9
- package/dist/commands/form-list.js.map +1 -1
- package/dist/commands/form-native.d.ts +0 -14
- package/dist/commands/form-native.d.ts.map +1 -1
- package/dist/commands/form-native.js +398 -72
- package/dist/commands/form-native.js.map +1 -1
- package/dist/commands/form.d.ts.map +1 -1
- package/dist/commands/form.js +5 -2
- package/dist/commands/form.js.map +1 -1
- package/dist/commands/wf-form.d.ts.map +1 -1
- package/dist/commands/wf-form.js +872 -42
- package/dist/commands/wf-form.js.map +1 -1
- package/dist/commands/workflow-action.d.ts +11 -0
- package/dist/commands/workflow-action.d.ts.map +1 -1
- package/dist/commands/workflow-action.js +13 -1586
- package/dist/commands/workflow-action.js.map +1 -1
- package/dist/commands/workflow-create-workflow.d.ts.map +1 -1
- package/dist/commands/workflow-create-workflow.js +111 -30
- package/dist/commands/workflow-create-workflow.js.map +1 -1
- package/dist/commands/workflow-node-robot.js +1 -1
- package/dist/commands/workflow-node-robot.js.map +1 -1
- package/dist/commands/workflow-node-validate.d.ts.map +1 -1
- package/dist/commands/workflow-node-validate.js +56 -45
- package/dist/commands/workflow-node-validate.js.map +1 -1
- package/dist/commands/workflow-numbering.d.ts.map +1 -1
- package/dist/commands/workflow-numbering.js +98 -2
- package/dist/commands/workflow-numbering.js.map +1 -1
- package/dist/commands/workflow-operator-sign.d.ts +3 -0
- package/dist/commands/workflow-operator-sign.d.ts.map +1 -0
- package/dist/commands/workflow-operator-sign.js +118 -0
- package/dist/commands/workflow-operator-sign.js.map +1 -0
- package/dist/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +83 -6
- package/dist/commands/workflow.js.map +1 -1
- package/dist/core/client.d.ts +2 -0
- package/dist/core/client.d.ts.map +1 -1
- package/dist/core/client.js +2 -0
- package/dist/core/client.js.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/services/actionflow/build_workflow_draft.d.ts +20 -0
- package/dist/services/actionflow/build_workflow_draft.d.ts.map +1 -0
- package/dist/services/actionflow/build_workflow_draft.js +222 -0
- package/dist/services/actionflow/build_workflow_draft.js.map +1 -0
- package/dist/services/actionflow/calendar_mapper.d.ts +3 -0
- package/dist/services/actionflow/calendar_mapper.d.ts.map +1 -0
- package/dist/services/actionflow/calendar_mapper.js +152 -0
- package/dist/services/actionflow/calendar_mapper.js.map +1 -0
- package/dist/services/actionflow/component_registry.d.ts +13 -0
- package/dist/services/actionflow/component_registry.d.ts.map +1 -0
- package/dist/services/actionflow/component_registry.js +213 -0
- package/dist/services/actionflow/component_registry.js.map +1 -0
- package/dist/services/actionflow/components/action_eb_add.d.ts +3 -0
- package/dist/services/actionflow/components/action_eb_add.d.ts.map +1 -0
- package/dist/services/actionflow/components/action_eb_add.js +127 -0
- package/dist/services/actionflow/components/action_eb_add.js.map +1 -0
- package/dist/services/actionflow/components/action_eb_add_compiler.d.ts +4 -0
- package/dist/services/actionflow/components/action_eb_add_compiler.d.ts.map +1 -0
- package/dist/services/actionflow/components/action_eb_add_compiler.js +13 -0
- package/dist/services/actionflow/components/action_eb_add_compiler.js.map +1 -0
- package/dist/services/actionflow/components/action_eb_delete.d.ts +3 -0
- package/dist/services/actionflow/components/action_eb_delete.d.ts.map +1 -0
- package/dist/services/actionflow/components/action_eb_delete.js +69 -0
- package/dist/services/actionflow/components/action_eb_delete.js.map +1 -0
- package/dist/services/actionflow/components/action_eb_delete_compiler.d.ts +4 -0
- package/dist/services/actionflow/components/action_eb_delete_compiler.d.ts.map +1 -0
- package/dist/services/actionflow/components/action_eb_delete_compiler.js +7 -0
- package/dist/services/actionflow/components/action_eb_delete_compiler.js.map +1 -0
- package/dist/services/actionflow/components/action_eb_recover.d.ts +3 -0
- package/dist/services/actionflow/components/action_eb_recover.d.ts.map +1 -0
- package/dist/services/actionflow/components/action_eb_recover.js +28 -0
- package/dist/services/actionflow/components/action_eb_recover.js.map +1 -0
- package/dist/services/actionflow/components/action_eb_recover_compiler.d.ts +3 -0
- package/dist/services/actionflow/components/action_eb_recover_compiler.d.ts.map +1 -0
- package/dist/services/actionflow/components/action_eb_recover_compiler.js +16 -0
- package/dist/services/actionflow/components/action_eb_recover_compiler.js.map +1 -0
- package/dist/services/actionflow/components/action_eb_save_version.d.ts +3 -0
- package/dist/services/actionflow/components/action_eb_save_version.d.ts.map +1 -0
- package/dist/services/actionflow/components/action_eb_save_version.js +30 -0
- package/dist/services/actionflow/components/action_eb_save_version.js.map +1 -0
- package/dist/services/actionflow/components/action_eb_save_version_compiler.d.ts +3 -0
- package/dist/services/actionflow/components/action_eb_save_version_compiler.d.ts.map +1 -0
- package/dist/services/actionflow/components/action_eb_save_version_compiler.js +15 -0
- package/dist/services/actionflow/components/action_eb_save_version_compiler.js.map +1 -0
- package/dist/services/actionflow/components/action_eb_update.d.ts +3 -0
- package/dist/services/actionflow/components/action_eb_update.d.ts.map +1 -0
- package/dist/services/actionflow/components/action_eb_update.js +154 -0
- package/dist/services/actionflow/components/action_eb_update.js.map +1 -0
- package/dist/services/actionflow/components/action_eb_update_compiler.d.ts +16 -0
- package/dist/services/actionflow/components/action_eb_update_compiler.d.ts.map +1 -0
- package/dist/services/actionflow/components/action_eb_update_compiler.js +94 -0
- package/dist/services/actionflow/components/action_eb_update_compiler.js.map +1 -0
- package/dist/services/actionflow/components/approve_create.d.ts +3 -0
- package/dist/services/actionflow/components/approve_create.d.ts.map +1 -0
- package/dist/services/actionflow/components/approve_create.js +44 -0
- package/dist/services/actionflow/components/approve_create.js.map +1 -0
- package/dist/services/actionflow/components/approve_trigger.d.ts +5 -0
- package/dist/services/actionflow/components/approve_trigger.d.ts.map +1 -0
- package/dist/services/actionflow/components/approve_trigger.js +184 -0
- package/dist/services/actionflow/components/approve_trigger.js.map +1 -0
- package/dist/services/actionflow/components/approve_trigger_compiler.d.ts +4 -0
- package/dist/services/actionflow/components/approve_trigger_compiler.d.ts.map +1 -0
- package/dist/services/actionflow/components/approve_trigger_compiler.js +20 -0
- package/dist/services/actionflow/components/approve_trigger_compiler.js.map +1 -0
- package/dist/services/actionflow/components/condition.d.ts +3 -0
- package/dist/services/actionflow/components/condition.d.ts.map +1 -0
- package/dist/services/actionflow/components/condition.js +23 -0
- package/dist/services/actionflow/components/condition.js.map +1 -0
- package/dist/services/actionflow/components/date_trigger.d.ts +5 -0
- package/dist/services/actionflow/components/date_trigger.d.ts.map +1 -0
- package/dist/services/actionflow/components/date_trigger.js +129 -0
- package/dist/services/actionflow/components/date_trigger.js.map +1 -0
- package/dist/services/actionflow/components/document_actions.d.ts +28 -0
- package/dist/services/actionflow/components/document_actions.d.ts.map +1 -0
- package/dist/services/actionflow/components/document_actions.js +266 -0
- package/dist/services/actionflow/components/document_actions.js.map +1 -0
- package/dist/services/actionflow/components/eb_get_data_by_id.d.ts +5 -0
- package/dist/services/actionflow/components/eb_get_data_by_id.d.ts.map +1 -0
- package/dist/services/actionflow/components/eb_get_data_by_id.js +44 -0
- package/dist/services/actionflow/components/eb_get_data_by_id.js.map +1 -0
- package/dist/services/actionflow/components/enquiry_form.d.ts +5 -0
- package/dist/services/actionflow/components/enquiry_form.d.ts.map +1 -0
- package/dist/services/actionflow/components/enquiry_form.js +100 -0
- package/dist/services/actionflow/components/enquiry_form.js.map +1 -0
- package/dist/services/actionflow/components/event_form_data.d.ts +3 -0
- package/dist/services/actionflow/components/event_form_data.d.ts.map +1 -0
- package/dist/services/actionflow/components/event_form_data.js +29 -0
- package/dist/services/actionflow/components/event_form_data.js.map +1 -0
- package/dist/services/actionflow/components/hrm_actions.d.ts +7 -0
- package/dist/services/actionflow/components/hrm_actions.d.ts.map +1 -0
- package/dist/services/actionflow/components/hrm_actions.js +138 -0
- package/dist/services/actionflow/components/hrm_actions.js.map +1 -0
- package/dist/services/actionflow/components/index.d.ts +32 -0
- package/dist/services/actionflow/components/index.d.ts.map +1 -0
- package/dist/services/actionflow/components/index.js +132 -0
- package/dist/services/actionflow/components/index.js.map +1 -0
- package/dist/services/actionflow/components/logic_flow_set.d.ts +10 -0
- package/dist/services/actionflow/components/logic_flow_set.d.ts.map +1 -0
- package/dist/services/actionflow/components/logic_flow_set.js +79 -0
- package/dist/services/actionflow/components/logic_flow_set.js.map +1 -0
- package/dist/services/actionflow/components/meeting_create.d.ts +5 -0
- package/dist/services/actionflow/components/meeting_create.d.ts.map +1 -0
- package/dist/services/actionflow/components/meeting_create.js +37 -0
- package/dist/services/actionflow/components/meeting_create.js.map +1 -0
- package/dist/services/actionflow/components/multiple_execution.d.ts +5 -0
- package/dist/services/actionflow/components/multiple_execution.d.ts.map +1 -0
- package/dist/services/actionflow/components/multiple_execution.js +136 -0
- package/dist/services/actionflow/components/multiple_execution.js.map +1 -0
- package/dist/services/actionflow/components/output.d.ts +9 -0
- package/dist/services/actionflow/components/output.d.ts.map +1 -0
- package/dist/services/actionflow/components/output.js +81 -0
- package/dist/services/actionflow/components/output.js.map +1 -0
- package/dist/services/actionflow/components/schedule_create.d.ts +5 -0
- package/dist/services/actionflow/components/schedule_create.d.ts.map +1 -0
- package/dist/services/actionflow/components/schedule_create.js +42 -0
- package/dist/services/actionflow/components/schedule_create.js.map +1 -0
- package/dist/services/actionflow/components/send_message.d.ts +7 -0
- package/dist/services/actionflow/components/send_message.d.ts.map +1 -0
- package/dist/services/actionflow/components/send_message.js +200 -0
- package/dist/services/actionflow/components/send_message.js.map +1 -0
- package/dist/services/actionflow/components/simple_scheduler.d.ts +5 -0
- package/dist/services/actionflow/components/simple_scheduler.d.ts.map +1 -0
- package/dist/services/actionflow/components/simple_scheduler.js +22 -0
- package/dist/services/actionflow/components/simple_scheduler.js.map +1 -0
- package/dist/services/actionflow/components/time_batch_trigger.d.ts +5 -0
- package/dist/services/actionflow/components/time_batch_trigger.d.ts.map +1 -0
- package/dist/services/actionflow/components/time_batch_trigger.js +92 -0
- package/dist/services/actionflow/components/time_batch_trigger.js.map +1 -0
- package/dist/services/actionflow/components/workflow_actions.d.ts +26 -0
- package/dist/services/actionflow/components/workflow_actions.d.ts.map +1 -0
- package/dist/services/actionflow/components/workflow_actions.js +403 -0
- package/dist/services/actionflow/components/workflow_actions.js.map +1 -0
- package/dist/services/actionflow/context_data_builder.d.ts +9 -0
- package/dist/services/actionflow/context_data_builder.d.ts.map +1 -0
- package/dist/services/actionflow/context_data_builder.js +31 -0
- package/dist/services/actionflow/context_data_builder.js.map +1 -0
- package/dist/services/actionflow/context_preflight.d.ts +6 -0
- package/dist/services/actionflow/context_preflight.d.ts.map +1 -0
- package/dist/services/actionflow/context_preflight.js +122 -0
- package/dist/services/actionflow/context_preflight.js.map +1 -0
- package/dist/services/actionflow/context_provider.d.ts +18 -0
- package/dist/services/actionflow/context_provider.d.ts.map +1 -0
- package/dist/services/actionflow/context_provider.js +102 -0
- package/dist/services/actionflow/context_provider.js.map +1 -0
- package/dist/services/actionflow/context_source.d.ts +7 -0
- package/dist/services/actionflow/context_source.d.ts.map +1 -0
- package/dist/services/actionflow/context_source.js +10 -0
- package/dist/services/actionflow/context_source.js.map +1 -0
- package/dist/services/actionflow/design_client.d.ts +48 -0
- package/dist/services/actionflow/design_client.d.ts.map +1 -0
- package/dist/services/actionflow/design_client.js +170 -0
- package/dist/services/actionflow/design_client.js.map +1 -0
- package/dist/services/actionflow/document_source.d.ts +5 -0
- package/dist/services/actionflow/document_source.d.ts.map +1 -0
- package/dist/services/actionflow/document_source.js +5 -0
- package/dist/services/actionflow/document_source.js.map +1 -0
- package/dist/services/actionflow/enrich_approve_trigger.d.ts +12 -0
- package/dist/services/actionflow/enrich_approve_trigger.d.ts.map +1 -0
- package/dist/services/actionflow/enrich_approve_trigger.js +107 -0
- package/dist/services/actionflow/enrich_approve_trigger.js.map +1 -0
- package/dist/services/actionflow/filter_rules.d.ts +14 -0
- package/dist/services/actionflow/filter_rules.d.ts.map +1 -0
- package/dist/services/actionflow/filter_rules.js +259 -0
- package/dist/services/actionflow/filter_rules.js.map +1 -0
- package/dist/services/actionflow/form_source.d.ts +17 -0
- package/dist/services/actionflow/form_source.d.ts.map +1 -0
- package/dist/services/actionflow/form_source.js +42 -0
- package/dist/services/actionflow/form_source.js.map +1 -0
- package/dist/services/actionflow/formula_service.d.ts +51 -0
- package/dist/services/actionflow/formula_service.d.ts.map +1 -0
- package/dist/services/actionflow/formula_service.js +999 -0
- package/dist/services/actionflow/formula_service.js.map +1 -0
- package/dist/services/actionflow/generation_service.d.ts +28 -0
- package/dist/services/actionflow/generation_service.d.ts.map +1 -0
- package/dist/services/actionflow/generation_service.js +283 -0
- package/dist/services/actionflow/generation_service.js.map +1 -0
- package/dist/services/actionflow/hrm_source.d.ts +4 -0
- package/dist/services/actionflow/hrm_source.d.ts.map +1 -0
- package/dist/services/actionflow/hrm_source.js +8 -0
- package/dist/services/actionflow/hrm_source.js.map +1 -0
- package/dist/services/actionflow/id_generator.d.ts +13 -0
- package/dist/services/actionflow/id_generator.d.ts.map +1 -0
- package/dist/services/actionflow/id_generator.js +33 -0
- package/dist/services/actionflow/id_generator.js.map +1 -0
- package/dist/services/actionflow/person_source.d.ts +7 -0
- package/dist/services/actionflow/person_source.d.ts.map +1 -0
- package/dist/services/actionflow/person_source.js +34 -0
- package/dist/services/actionflow/person_source.js.map +1 -0
- package/dist/services/actionflow/preflight_service.d.ts +42 -0
- package/dist/services/actionflow/preflight_service.d.ts.map +1 -0
- package/dist/services/actionflow/preflight_service.js +1247 -0
- package/dist/services/actionflow/preflight_service.js.map +1 -0
- package/dist/services/actionflow/query_field_defaults.d.ts +3 -0
- package/dist/services/actionflow/query_field_defaults.d.ts.map +1 -0
- package/dist/services/actionflow/query_field_defaults.js +46 -0
- package/dist/services/actionflow/query_field_defaults.js.map +1 -0
- package/dist/services/actionflow/readback_verifier.d.ts +11 -0
- package/dist/services/actionflow/readback_verifier.d.ts.map +1 -0
- package/dist/services/actionflow/readback_verifier.js +252 -0
- package/dist/services/actionflow/readback_verifier.js.map +1 -0
- package/dist/services/actionflow/request.d.ts +13 -0
- package/dist/services/actionflow/request.d.ts.map +1 -0
- package/dist/services/actionflow/request.js +15 -0
- package/dist/services/actionflow/request.js.map +1 -0
- package/dist/services/actionflow/runtime_metadata.d.ts +27 -0
- package/dist/services/actionflow/runtime_metadata.d.ts.map +1 -0
- package/dist/services/actionflow/runtime_metadata.js +142 -0
- package/dist/services/actionflow/runtime_metadata.js.map +1 -0
- package/dist/services/actionflow/save_workflow_draft.d.ts +34 -0
- package/dist/services/actionflow/save_workflow_draft.d.ts.map +1 -0
- package/dist/services/actionflow/save_workflow_draft.js +449 -0
- package/dist/services/actionflow/save_workflow_draft.js.map +1 -0
- package/dist/services/actionflow/system_params.d.ts +5 -0
- package/dist/services/actionflow/system_params.d.ts.map +1 -0
- package/dist/services/actionflow/system_params.js +55 -0
- package/dist/services/actionflow/system_params.js.map +1 -0
- package/dist/services/actionflow/trigger_common.d.ts +6 -0
- package/dist/services/actionflow/trigger_common.d.ts.map +1 -0
- package/dist/services/actionflow/trigger_common.js +41 -0
- package/dist/services/actionflow/trigger_common.js.map +1 -0
- package/dist/services/actionflow/workflow_compiler.d.ts +27 -0
- package/dist/services/actionflow/workflow_compiler.d.ts.map +1 -0
- package/dist/services/actionflow/workflow_compiler.js +1804 -0
- package/dist/services/actionflow/workflow_compiler.js.map +1 -0
- package/dist/services/actionflow/workflow_source.d.ts +14 -0
- package/dist/services/actionflow/workflow_source.d.ts.map +1 -0
- package/dist/services/actionflow/workflow_source.js +86 -0
- package/dist/services/actionflow/workflow_source.js.map +1 -0
- package/dist/services/workflow-initiator.d.ts +15 -0
- package/dist/services/workflow-initiator.d.ts.map +1 -0
- package/dist/services/workflow-initiator.js +77 -0
- package/dist/services/workflow-initiator.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,1247 @@
|
|
|
1
|
+
import * as formSource from './form_source.js';
|
|
2
|
+
import * as workflowSource from './workflow_source.js';
|
|
3
|
+
import * as personSource from './person_source.js';
|
|
4
|
+
import * as contextSource from './context_source.js';
|
|
5
|
+
import * as hrmSource from './hrm_source.js';
|
|
6
|
+
import { registerTargetFormFields, registerTargetDetailFields, registerWorkflowFieldIds, registerWorkflowContextFields, getWorkflowFieldIds, getWorkflowDetailFields, getWorkflowDetailNames, getTargetFormFields, } from './runtime_metadata.js';
|
|
7
|
+
// workflow_id → 目标表单 id(进程缓存)
|
|
8
|
+
const FORM_ID_CACHE = {};
|
|
9
|
+
import { ContextStore, PlatformContextProvider } from './context_provider.js';
|
|
10
|
+
import { queryNodeContext } from './context_preflight.js';
|
|
11
|
+
import { get as getComponent } from './components/index.js';
|
|
12
|
+
// 表单字段进程缓存
|
|
13
|
+
const FORM_FIELDS_CACHE = {};
|
|
14
|
+
/** 组件表单引用:兼容 params.dataSource/targetForm 与 event/step 顶层写法。 */
|
|
15
|
+
export function stepFormRef(step) {
|
|
16
|
+
const params = step.params || {};
|
|
17
|
+
let ref = params.targetForm || params.dataSource;
|
|
18
|
+
if (!ref || typeof ref !== 'object')
|
|
19
|
+
ref = step.dataSource || step.targetForm;
|
|
20
|
+
return ref && typeof ref === 'object' ? ref : null;
|
|
21
|
+
}
|
|
22
|
+
/** 查 form-fields 返回完整字段列表(id/showName/componentKey/paramType),进程缓存。 */
|
|
23
|
+
export async function getFormFieldsFull(formId, client, tf) {
|
|
24
|
+
if (formId in FORM_FIELDS_CACHE) {
|
|
25
|
+
registerTargetFormFields(formId, FORM_FIELDS_CACHE[formId]);
|
|
26
|
+
return FORM_FIELDS_CACHE[formId];
|
|
27
|
+
}
|
|
28
|
+
const fields = [];
|
|
29
|
+
try {
|
|
30
|
+
const appId = String((tf || {}).groupId || '');
|
|
31
|
+
const resp = await formSource.getEbField(client, formId, appId);
|
|
32
|
+
const raw = resp?.data ?? [];
|
|
33
|
+
let rows = [];
|
|
34
|
+
if (raw && typeof raw === 'object' && !Array.isArray(raw)) {
|
|
35
|
+
for (const dt of raw.detail || []) {
|
|
36
|
+
if (!dt || typeof dt !== 'object' || !dt.detailTableId)
|
|
37
|
+
continue;
|
|
38
|
+
registerTargetDetailFields(formId, String(dt.detailTableId), dt.fields || []);
|
|
39
|
+
}
|
|
40
|
+
rows.push(...(raw.main || []));
|
|
41
|
+
for (const dt of raw.detail || []) {
|
|
42
|
+
if (dt && typeof dt === 'object')
|
|
43
|
+
rows.push(...(dt.fields || []));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else if (Array.isArray(raw)) {
|
|
47
|
+
rows = raw;
|
|
48
|
+
}
|
|
49
|
+
for (const f of rows) {
|
|
50
|
+
if (!f || typeof f !== 'object' || !f.id)
|
|
51
|
+
continue;
|
|
52
|
+
fields.push({
|
|
53
|
+
...f,
|
|
54
|
+
id: String(f.id),
|
|
55
|
+
showName: String(f.showName || f.name || ''),
|
|
56
|
+
name: String(f.name || f.showName || ''),
|
|
57
|
+
componentKey: String(f.componentKey || ''),
|
|
58
|
+
paramType: String(f.paramType || f.type || '').toLowerCase(),
|
|
59
|
+
type: String(f.type || f.paramType || 'String'),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// 查询失败返回空,由调用方判定
|
|
65
|
+
}
|
|
66
|
+
FORM_FIELDS_CACHE[formId] = fields;
|
|
67
|
+
registerTargetFormFields(formId, fields);
|
|
68
|
+
return fields;
|
|
69
|
+
}
|
|
70
|
+
/** 在 plan 里查找 form_id 对应的 groupId(无则空串)。 */
|
|
71
|
+
function findTfGroup(plan, formId) {
|
|
72
|
+
const search = (steps) => {
|
|
73
|
+
for (const step of steps || []) {
|
|
74
|
+
if (!step || typeof step !== 'object')
|
|
75
|
+
continue;
|
|
76
|
+
const params = step.params || {};
|
|
77
|
+
if (params && typeof params === 'object') {
|
|
78
|
+
if (['ActionEbAdd', 'ActionEbUpdate', 'ActionEbDelete', 'ActionEbRecover', 'ActionEbSaveVersion', 'EbGetDataById'].includes(step.type)) {
|
|
79
|
+
const tf = params.targetForm;
|
|
80
|
+
if (tf && typeof tf === 'object' && String(tf.id || '') === String(formId))
|
|
81
|
+
return String(tf.groupId || '');
|
|
82
|
+
}
|
|
83
|
+
if (['EventFormData', 'TimeBatchTrigger', 'DateTrigger', 'EnquiryForm'].includes(step.type)) {
|
|
84
|
+
const ds = stepFormRef(step);
|
|
85
|
+
if (ds && String(ds.id || '') === String(formId))
|
|
86
|
+
return String(ds.groupId || '');
|
|
87
|
+
}
|
|
88
|
+
if (step.type === 'Condition') {
|
|
89
|
+
for (const branch of step.branches || []) {
|
|
90
|
+
if (branch && typeof branch === 'object') {
|
|
91
|
+
const g = search(branch.actions || []);
|
|
92
|
+
if (g)
|
|
93
|
+
return g;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return '';
|
|
100
|
+
};
|
|
101
|
+
return search(plan.actions || []);
|
|
102
|
+
}
|
|
103
|
+
/** 回填 plan 里 targetForm 缺失的 groupId/name/text/groupName。返回无法解析的表单 id 列表。 */
|
|
104
|
+
export async function resolveTargetForms(plan, client) {
|
|
105
|
+
const normalizeRef = (ref) => {
|
|
106
|
+
if (!ref || typeof ref !== 'object')
|
|
107
|
+
return;
|
|
108
|
+
if (!ref.id && ref.tableId)
|
|
109
|
+
ref.id = String(ref.tableId);
|
|
110
|
+
if (!ref.groupId && ref.appId)
|
|
111
|
+
ref.groupId = String(ref.appId);
|
|
112
|
+
};
|
|
113
|
+
const normalizeSteps = (steps) => {
|
|
114
|
+
for (const step of steps || []) {
|
|
115
|
+
if (!step || typeof step !== 'object')
|
|
116
|
+
continue;
|
|
117
|
+
const params = step.params || {};
|
|
118
|
+
if (params && typeof params === 'object') {
|
|
119
|
+
normalizeRef(params.targetForm);
|
|
120
|
+
normalizeRef(params.dataSource);
|
|
121
|
+
}
|
|
122
|
+
if (step.type === 'Condition') {
|
|
123
|
+
for (const branch of step.branches || []) {
|
|
124
|
+
if (branch && typeof branch === 'object')
|
|
125
|
+
normalizeSteps(branch.actions || []);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
const event = plan.event;
|
|
131
|
+
if (event && typeof event === 'object') {
|
|
132
|
+
const ep = event.params || {};
|
|
133
|
+
if (ep && typeof ep === 'object') {
|
|
134
|
+
normalizeRef(ep.targetForm);
|
|
135
|
+
normalizeRef(ep.dataSource);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
normalizeSteps(plan.actions || []);
|
|
139
|
+
const unresolved = [];
|
|
140
|
+
const collect = (steps) => {
|
|
141
|
+
for (const step of steps || []) {
|
|
142
|
+
if (!step || typeof step !== 'object')
|
|
143
|
+
continue;
|
|
144
|
+
if (['ActionEbAdd', 'ActionEbUpdate', 'ActionEbDelete', 'ActionEbRecover', 'ActionEbSaveVersion', 'EbGetDataById'].includes(step.type)) {
|
|
145
|
+
const tf = (step.params || {}).targetForm;
|
|
146
|
+
if (tf && typeof tf === 'object' && tf.id) {
|
|
147
|
+
if (!tf.groupId || !tf.name || !tf.text || !tf.groupName)
|
|
148
|
+
unresolved.push(String(tf.id));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (step.type === 'Condition') {
|
|
152
|
+
for (const branch of step.branches || []) {
|
|
153
|
+
if (branch && typeof branch === 'object')
|
|
154
|
+
collect(branch.actions || []);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (['EventFormData', 'TimeBatchTrigger', 'DateTrigger', 'EnquiryForm'].includes(step.type)) {
|
|
158
|
+
const ds = (step.params || {}).dataSource || (step.params || {}).targetForm;
|
|
159
|
+
if (ds && typeof ds === 'object' && ds.id) {
|
|
160
|
+
if (!ds.groupId || !ds.name || !ds.text || !ds.groupName)
|
|
161
|
+
unresolved.push(String(ds.id));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
if (event && typeof event === 'object') {
|
|
167
|
+
const ep = event.params || {};
|
|
168
|
+
if (ep && typeof ep === 'object') {
|
|
169
|
+
const es = ep.targetForm || ep.dataSource;
|
|
170
|
+
if (es && typeof es === 'object' && es.id) {
|
|
171
|
+
if (!es.groupId || !es.name || !es.text || !es.groupName)
|
|
172
|
+
unresolved.push(String(es.id));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
collect(plan.actions || []);
|
|
177
|
+
if (!unresolved.length)
|
|
178
|
+
return [];
|
|
179
|
+
let appNames = null;
|
|
180
|
+
const applicationName = async (groupId) => {
|
|
181
|
+
if (appNames === null) {
|
|
182
|
+
appNames = {};
|
|
183
|
+
try {
|
|
184
|
+
const apps = await formSource.dsGroup(client);
|
|
185
|
+
for (const app of apps?.data || []) {
|
|
186
|
+
if (app && typeof app === 'object' && app.id)
|
|
187
|
+
appNames[String(app.id)] = String(app.name || '');
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// 忽略
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return appNames[groupId] || '';
|
|
195
|
+
};
|
|
196
|
+
const groupForms = async (groupId) => {
|
|
197
|
+
const idx = {};
|
|
198
|
+
try {
|
|
199
|
+
const forms = await formSource.dsList(client, groupId);
|
|
200
|
+
for (const f of forms?.data || []) {
|
|
201
|
+
if (f && typeof f === 'object' && f.id) {
|
|
202
|
+
idx[String(f.id)] = { groupId, groupName: await applicationName(groupId), name: String(f.name || '') };
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
// 忽略
|
|
208
|
+
}
|
|
209
|
+
return idx;
|
|
210
|
+
};
|
|
211
|
+
const groupIds = new Set();
|
|
212
|
+
const collectGroups = (steps) => {
|
|
213
|
+
for (const step of steps || []) {
|
|
214
|
+
if (!step || typeof step !== 'object')
|
|
215
|
+
continue;
|
|
216
|
+
const params = step.params || {};
|
|
217
|
+
if (params && typeof params === 'object') {
|
|
218
|
+
if (['ActionEbAdd', 'ActionEbUpdate', 'ActionEbDelete', 'ActionEbRecover', 'ActionEbSaveVersion', 'EbGetDataById'].includes(step.type)) {
|
|
219
|
+
const tf = params.targetForm;
|
|
220
|
+
if (tf && typeof tf === 'object' && tf.groupId)
|
|
221
|
+
groupIds.add(String(tf.groupId));
|
|
222
|
+
}
|
|
223
|
+
if (['EventFormData', 'TimeBatchTrigger', 'DateTrigger', 'EnquiryForm'].includes(step.type)) {
|
|
224
|
+
const ds = params.dataSource || params.targetForm;
|
|
225
|
+
if (ds && typeof ds === 'object' && ds.groupId)
|
|
226
|
+
groupIds.add(String(ds.groupId));
|
|
227
|
+
}
|
|
228
|
+
if (step.type === 'Condition') {
|
|
229
|
+
for (const branch of step.branches || []) {
|
|
230
|
+
if (branch && typeof branch === 'object')
|
|
231
|
+
collectGroups(branch.actions || []);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
collectGroups(plan.actions || []);
|
|
238
|
+
if (event && typeof event === 'object') {
|
|
239
|
+
const ep = event.params || {};
|
|
240
|
+
if (ep && typeof ep === 'object') {
|
|
241
|
+
const es = ep.targetForm || ep.dataSource;
|
|
242
|
+
if (es && typeof es === 'object' && es.groupId)
|
|
243
|
+
groupIds.add(String(es.groupId));
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
const formIndex = {};
|
|
247
|
+
for (const gid of groupIds) {
|
|
248
|
+
Object.assign(formIndex, await groupForms(gid));
|
|
249
|
+
}
|
|
250
|
+
const stillMissing = [];
|
|
251
|
+
for (const fid of unresolved) {
|
|
252
|
+
let info = formIndex[fid];
|
|
253
|
+
if (!info) {
|
|
254
|
+
const gid = findTfGroup(plan, fid);
|
|
255
|
+
if (gid) {
|
|
256
|
+
Object.assign(formIndex, await groupForms(gid));
|
|
257
|
+
info = formIndex[fid];
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (!info) {
|
|
261
|
+
stillMissing.push(fid);
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
const patch = (steps) => {
|
|
265
|
+
for (const step of steps || []) {
|
|
266
|
+
if (!step || typeof step !== 'object')
|
|
267
|
+
continue;
|
|
268
|
+
if (['ActionEbAdd', 'ActionEbUpdate', 'ActionEbDelete', 'ActionEbRecover', 'ActionEbSaveVersion', 'EbGetDataById'].includes(step.type)) {
|
|
269
|
+
const tf = (step.params || {}).targetForm;
|
|
270
|
+
if (tf && typeof tf === 'object' && String(tf.id || '') === fid) {
|
|
271
|
+
tf.groupId = info.groupId;
|
|
272
|
+
if (!String(tf.name || '').trim())
|
|
273
|
+
tf.name = info.name;
|
|
274
|
+
if (!String(tf.text || '').trim())
|
|
275
|
+
tf.text = info.name;
|
|
276
|
+
if (!String(tf.groupName || '').trim())
|
|
277
|
+
tf.groupName = info.groupName;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if (['EventFormData', 'TimeBatchTrigger', 'DateTrigger', 'EnquiryForm'].includes(step.type)) {
|
|
281
|
+
const ds = (step.params || {}).dataSource || (step.params || {}).targetForm;
|
|
282
|
+
if (ds && typeof ds === 'object' && String(ds.id || '') === fid) {
|
|
283
|
+
ds.groupId = info.groupId;
|
|
284
|
+
if (!String(ds.name || '').trim())
|
|
285
|
+
ds.name = info.name;
|
|
286
|
+
if (!String(ds.text || '').trim())
|
|
287
|
+
ds.text = info.name;
|
|
288
|
+
if (!String(ds.groupName || '').trim())
|
|
289
|
+
ds.groupName = info.groupName;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if (step.type === 'Condition') {
|
|
293
|
+
for (const branch of step.branches || []) {
|
|
294
|
+
if (branch && typeof branch === 'object')
|
|
295
|
+
patch(branch.actions || []);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
patch(plan.actions || []);
|
|
301
|
+
if (event && typeof event === 'object') {
|
|
302
|
+
const ep = event.params || {};
|
|
303
|
+
if (ep && typeof ep === 'object') {
|
|
304
|
+
const es = ep.targetForm || ep.dataSource;
|
|
305
|
+
if (es && typeof es === 'object' && String(es.id || '') === fid) {
|
|
306
|
+
es.groupId = info.groupId;
|
|
307
|
+
if (!String(es.name || '').trim())
|
|
308
|
+
es.name = info.name;
|
|
309
|
+
if (!String(es.text || '').trim())
|
|
310
|
+
es.text = info.name;
|
|
311
|
+
if (!String(es.groupName || '').trim())
|
|
312
|
+
es.groupName = info.groupName;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return stillMissing;
|
|
318
|
+
}
|
|
319
|
+
/** 为必填的表单定时触发器补一个当前租户真实操作人。 */
|
|
320
|
+
export async function fillRequiredTriggerOperator(plan, client) {
|
|
321
|
+
const event = plan.event;
|
|
322
|
+
if (!event || typeof event !== 'object' || !['DateTrigger', 'TimeBatchTrigger'].includes(event.type))
|
|
323
|
+
return [];
|
|
324
|
+
const params = event.params ??= {};
|
|
325
|
+
if (typeof params !== 'object' || params.operator)
|
|
326
|
+
return [];
|
|
327
|
+
const response = await personSource.resourceData(client, '', 1, 30);
|
|
328
|
+
const rows = response?.data?.data || [];
|
|
329
|
+
const candidates = rows.filter((r) => r && typeof r === 'object' && r.id && String(r.statusCode || 'normal') === 'normal');
|
|
330
|
+
if (!candidates.length)
|
|
331
|
+
return [];
|
|
332
|
+
const chosen = candidates.sort((a, b) => String(a.id).localeCompare(String(b.id)))[0];
|
|
333
|
+
const value = { id: String(chosen.id), name: String(chosen.name || chosen.content || '') };
|
|
334
|
+
params.operator = value;
|
|
335
|
+
const record = { path: 'event.params.operator', resourceType: 'user_assignment', value, reason: '操作人必填但需求未指定;从当前租户人员浏览器选择真实可用人员' };
|
|
336
|
+
(plan._autoResources ??= []).push(record);
|
|
337
|
+
return [record];
|
|
338
|
+
}
|
|
339
|
+
function isBrowserPerson(value) {
|
|
340
|
+
return value && typeof value === 'object' && Boolean(value.id) && Boolean(value.originTargetType || value.mainId || value.userid);
|
|
341
|
+
}
|
|
342
|
+
function walkPlanSteps(value) {
|
|
343
|
+
const steps = [];
|
|
344
|
+
const walk = (v) => {
|
|
345
|
+
if (v && typeof v === 'object' && !Array.isArray(v)) {
|
|
346
|
+
if (typeof v.type === 'string' && typeof v.params === 'object')
|
|
347
|
+
steps.push(v);
|
|
348
|
+
for (const child of Object.values(v))
|
|
349
|
+
walk(child);
|
|
350
|
+
}
|
|
351
|
+
else if (Array.isArray(v)) {
|
|
352
|
+
for (const child of v)
|
|
353
|
+
walk(child);
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
walk(value);
|
|
357
|
+
return steps[Symbol.iterator]();
|
|
358
|
+
}
|
|
359
|
+
/** 把显式固定人员展开为当前租户 Browser 对象。 */
|
|
360
|
+
export async function resolveFixedPeople(plan, client) {
|
|
361
|
+
const records = [];
|
|
362
|
+
for (const step of walkPlanSteps(plan.actions || [])) {
|
|
363
|
+
const componentType = String(step.type || '');
|
|
364
|
+
const contract = getComponent(componentType);
|
|
365
|
+
const personKeys = Object.entries(contract?.params || {})
|
|
366
|
+
.filter(([, definition]) => String(definition?.referenceType || '').startsWith('user_assignment'))
|
|
367
|
+
.map(([key]) => key);
|
|
368
|
+
// 会议字段在 meetingFields 中承载,属于组件特有嵌套结构,无法从顶层 params 推导。
|
|
369
|
+
if (componentType === 'MeetingCreate')
|
|
370
|
+
personKeys.push('caller', 'contacter', 'hrmMembers');
|
|
371
|
+
if (!personKeys.length)
|
|
372
|
+
continue;
|
|
373
|
+
const params = step.params || {};
|
|
374
|
+
const fields = params.meetingFields;
|
|
375
|
+
const containers = [];
|
|
376
|
+
if (fields && typeof fields === 'object')
|
|
377
|
+
containers.push(['meetingFields', fields]);
|
|
378
|
+
containers.push(['params', params]);
|
|
379
|
+
for (const [containerName, container] of containers) {
|
|
380
|
+
for (const key of personKeys) {
|
|
381
|
+
const raw = container[key];
|
|
382
|
+
if (raw == null)
|
|
383
|
+
continue;
|
|
384
|
+
const values = Array.isArray(raw) ? raw : [raw];
|
|
385
|
+
if (values.length && values.every((item) => isBrowserPerson(item)))
|
|
386
|
+
continue;
|
|
387
|
+
if (!values.length || !values.every((item) => item && typeof item === 'object' && item.id))
|
|
388
|
+
continue;
|
|
389
|
+
const resolved = [];
|
|
390
|
+
for (const item of values) {
|
|
391
|
+
const query = String(item.name || item.id);
|
|
392
|
+
const response = await personSource.resourceData(client, query, 1, 30);
|
|
393
|
+
const rows = response?.data?.data || [];
|
|
394
|
+
const match = rows.find((r) => r && typeof r === 'object' && String(r.id) === String(item.id));
|
|
395
|
+
if (!match)
|
|
396
|
+
throw new Error(`${componentType}.${key} 的人员 id=${item.id} 不在当前租户人员浏览器中,无法生成可回显的 Browser 对象`);
|
|
397
|
+
resolved.push(match);
|
|
398
|
+
}
|
|
399
|
+
container[key] = Array.isArray(raw) ? resolved : resolved[0];
|
|
400
|
+
records.push({
|
|
401
|
+
path: `${componentType}.${containerName}.${key}`,
|
|
402
|
+
resourceType: 'user_browser',
|
|
403
|
+
value: resolved.map((item) => ({ id: String(item.id), name: String(item.name || item.content || '') })),
|
|
404
|
+
reason: '固定人员已从当前租户人员浏览器补全为真实对象,保留头像、部门等设计器展示字段',
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
if (records.length)
|
|
410
|
+
(plan._autoResources ??= []).push(...records);
|
|
411
|
+
return records;
|
|
412
|
+
}
|
|
413
|
+
/** 委托流程的两张设置表在每个租户都有独立字段 ID,生成前必须实时读取。 */
|
|
414
|
+
export async function resolveEntrustFields(plan, client, errors) {
|
|
415
|
+
for (const step of walkPlanSteps(plan.actions || [])) {
|
|
416
|
+
if (step.type !== 'ApproveEntrust')
|
|
417
|
+
continue;
|
|
418
|
+
const params = step.params || {};
|
|
419
|
+
try {
|
|
420
|
+
const response = await contextSource.getComponentContext(client, 'ApproveEntrust', {
|
|
421
|
+
type: 'ApproveEntrust', module: 'workflow', ebActionId: '-1',
|
|
422
|
+
});
|
|
423
|
+
const tables = Array.isArray(response?.data) ? response.data : [];
|
|
424
|
+
const fields = {};
|
|
425
|
+
for (const table of tables) {
|
|
426
|
+
for (const field of table?.tableData || []) {
|
|
427
|
+
const key = String(field?.paramKey || '');
|
|
428
|
+
if (!key.startsWith('entrysetting.') && !key.startsWith('entrysettingCommon.'))
|
|
429
|
+
continue;
|
|
430
|
+
const name = key.slice(key.lastIndexOf('.') + 1);
|
|
431
|
+
if (name && field?.id)
|
|
432
|
+
fields[name] = { id: String(field.id), componentKey: String(field.componentKey || 'Text') };
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
const required = ['entrustUserId', 'beAgentIdentities', 'consigneeId', 'entrustType'];
|
|
436
|
+
const missing = required.filter((key) => !fields[key]);
|
|
437
|
+
if (missing.length) {
|
|
438
|
+
errors.push(`ApproveEntrust: 当前租户未返回委托设置字段 ${missing.join(', ')},拒绝生成。`);
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
params._entrustFields = fields;
|
|
442
|
+
}
|
|
443
|
+
const entrustUserId = String(params.entrustUser?.id || '');
|
|
444
|
+
const identityId = String(params.identityId || '');
|
|
445
|
+
if (entrustUserId && identityId) {
|
|
446
|
+
const identities = await client.get(`${client.getBaseUrl()}/api/bs/esb/setting/component/getBeAgentIdentities?empId=${encodeURIComponent(entrustUserId)}`);
|
|
447
|
+
const rows = Array.isArray(identities?.data) ? identities.data : [];
|
|
448
|
+
const allowed = new Set(rows.map((item) => String(item.extraInfoId)).filter(Boolean));
|
|
449
|
+
if (rows.length)
|
|
450
|
+
allowed.add('all');
|
|
451
|
+
if (!allowed.has(identityId)) {
|
|
452
|
+
errors.push(`ApproveEntrust.identityId='${identityId}' 不属于委托人 ${entrustUserId} 的当前可用身份;不能伪造身份。`);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
catch (error) {
|
|
457
|
+
errors.push(`ApproveEntrust: 无法读取当前租户委托设置字段 (${error?.message || error})。`);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
/** ApproveCreate 新建流程:调 getWfField 拿目标流程真实表单字段。 */
|
|
462
|
+
export async function resolveBizCreateFields(step, plan, client, errors, path) {
|
|
463
|
+
const params = (step.params || {});
|
|
464
|
+
const wfPath = params.workflowPath || {};
|
|
465
|
+
const wfId = String(wfPath.id || wfPath.createFlowId || '');
|
|
466
|
+
if (!wfId) {
|
|
467
|
+
errors.push(`${path}.params.workflowPath.id 缺失 (新建流程必须指定目标流程)`);
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
try {
|
|
471
|
+
const resp = await workflowSource.getWfField(client, wfId);
|
|
472
|
+
let data = resp?.data ?? {};
|
|
473
|
+
if (resp?.code === 200) {
|
|
474
|
+
if (Array.isArray(data))
|
|
475
|
+
data = { main: data, detail: [] };
|
|
476
|
+
if (data && typeof data === 'object') {
|
|
477
|
+
let main = Array.isArray(data.main) ? data.main : [];
|
|
478
|
+
const bizFields = {
|
|
479
|
+
main: main.map((f) => ({
|
|
480
|
+
id: String(f.id || ''), showName: String(f.showName || ''),
|
|
481
|
+
componentKey: String(f.componentKey || ''), formId: String(f.formId || ''),
|
|
482
|
+
required: Boolean(f.required), custom: Boolean(f.custom), subFormId: String(f.subFormId || '-1'),
|
|
483
|
+
})),
|
|
484
|
+
detail: data.detail || [],
|
|
485
|
+
};
|
|
486
|
+
params._bizFields = bizFields;
|
|
487
|
+
let formIds = (wfPath.formIds ? (Array.isArray(wfPath.formIds) ? wfPath.formIds : [wfPath.formIds]) : []).map(String);
|
|
488
|
+
if (!formIds.length) {
|
|
489
|
+
formIds = [...new Set(main.map((f) => f && f.formId ? String(f.formId) : '').filter(Boolean))];
|
|
490
|
+
if (formIds.length)
|
|
491
|
+
wfPath.formIds = formIds;
|
|
492
|
+
}
|
|
493
|
+
if (!formIds.length) {
|
|
494
|
+
errors.push(`${path}.params.workflowPath.formIds 缺失: getWfField 未返回目标流程主表 formId,无法安全保存新建流程;请确认目标流程已绑定表单。`);
|
|
495
|
+
}
|
|
496
|
+
const allFieldIds = new Set(bizFields.main.map((f) => f.id));
|
|
497
|
+
for (const dt of bizFields.detail) {
|
|
498
|
+
if (dt && typeof dt === 'object') {
|
|
499
|
+
for (const df of dt.fields || []) {
|
|
500
|
+
if (df && typeof df === 'object' && df.id)
|
|
501
|
+
allFieldIds.add(String(df.id));
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
const mapping = params.mapping || {};
|
|
506
|
+
if (mapping && typeof mapping === 'object') {
|
|
507
|
+
for (const [srcKey, targetFid] of Object.entries(mapping)) {
|
|
508
|
+
const tid = targetFid && typeof targetFid === 'object' ? String(targetFid.target || targetFid.fieldId || '') : String(targetFid);
|
|
509
|
+
if (tid && !allFieldIds.has(tid))
|
|
510
|
+
errors.push(`${path}.params.mapping['${srcKey}'] 目标字段 '${targetFid}' 不存在于目标流程 '${wfId}' 的表单字段中`);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
const constants = params.constants || {};
|
|
514
|
+
if (constants && typeof constants === 'object') {
|
|
515
|
+
for (const targetFid of Object.keys(constants)) {
|
|
516
|
+
if (!allFieldIds.has(String(targetFid)))
|
|
517
|
+
errors.push(`${path}.params.constants['${targetFid}'] 目标字段不存在于目标流程 '${wfId}' 的表单字段中`);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
for (const [di, ditem] of (params.detail || []).entries()) {
|
|
521
|
+
if (!ditem || typeof ditem !== 'object')
|
|
522
|
+
continue;
|
|
523
|
+
const dm = ditem.mapping || {};
|
|
524
|
+
if (typeof dm !== 'object')
|
|
525
|
+
continue;
|
|
526
|
+
for (const [sk, tv] of Object.entries(dm)) {
|
|
527
|
+
const tid2 = tv && typeof tv === 'object' ? String(tv.target || tv.fieldId || '') : String(tv);
|
|
528
|
+
if (tid2 && !allFieldIds.has(tid2))
|
|
529
|
+
errors.push(`${path}.params.detail[${di}].mapping['${sk}'] 目标字段 '${tid2}' 不存在于目标流程 '${wfId}' 的表单字段中 (明细表子字段 id 必须实时查全量, 禁止推算)`);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
catch (e) {
|
|
536
|
+
errors.push(`${path}: getWfField 查询目标流程字段失败: ${e?.message || e}`);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
/** 硬性校验 mapping 源字段引用必须真实存在于 event 上下文中。 */
|
|
540
|
+
export function checkSourceReferences(plan, eventContextFields, errors) {
|
|
541
|
+
const realKeys = new Set();
|
|
542
|
+
for (const field of eventContextFields) {
|
|
543
|
+
if (!field || typeof field !== 'object')
|
|
544
|
+
continue;
|
|
545
|
+
const pk = String(field.paramKey || '');
|
|
546
|
+
if (pk) {
|
|
547
|
+
realKeys.add(pk);
|
|
548
|
+
realKeys.add(pk.replace(/\[\]$/, ''));
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
const skip = (s) => {
|
|
552
|
+
const t = s.trim();
|
|
553
|
+
if (!t || t.startsWith('{'))
|
|
554
|
+
return true;
|
|
555
|
+
if (!t.includes('.'))
|
|
556
|
+
return true;
|
|
557
|
+
return false;
|
|
558
|
+
};
|
|
559
|
+
const checkSourceKey = (sourceKey, where) => {
|
|
560
|
+
const s = sourceKey.trim();
|
|
561
|
+
if (skip(s))
|
|
562
|
+
return;
|
|
563
|
+
if (!realKeys.has(s.replace(/\[\]$/, ''))) {
|
|
564
|
+
const wfId = s.split('.', 1)[0];
|
|
565
|
+
errors.push(`${where}: 源字段 paramKey '${s}' 未在流程 ${wfId} 的真实上下文中找到。请用 workflow-context-fields 确认该流程和字段真实存在。`);
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
const checkMapping = (mapping, where) => {
|
|
569
|
+
if (!mapping || typeof mapping !== 'object')
|
|
570
|
+
return;
|
|
571
|
+
for (const srcKey of Object.keys(mapping))
|
|
572
|
+
checkSourceKey(String(srcKey), where);
|
|
573
|
+
};
|
|
574
|
+
const walk = (steps, prefix = 'actions') => {
|
|
575
|
+
for (const [idx, step] of (steps || []).entries()) {
|
|
576
|
+
if (!step || typeof step !== 'object')
|
|
577
|
+
continue;
|
|
578
|
+
const params = step.params || {};
|
|
579
|
+
const path = `${prefix}[${idx}]`;
|
|
580
|
+
if (['ActionEbAdd', 'ActionEbUpdate', 'ActionEbDelete', 'ActionEbRecover', 'ActionEbSaveVersion', 'EbGetDataById'].includes(step.type)) {
|
|
581
|
+
if (params && typeof params === 'object') {
|
|
582
|
+
checkMapping(params.mapping, `${path}.mapping`);
|
|
583
|
+
const bv = params.basisValue;
|
|
584
|
+
if (bv && typeof bv === 'object')
|
|
585
|
+
checkSourceKey(String(bv.paramKey || bv.key || ''), `${path}.basisValue`);
|
|
586
|
+
for (const [di, det] of (params.detail || []).entries()) {
|
|
587
|
+
if (det && typeof det === 'object')
|
|
588
|
+
checkMapping(det.mapping, `${path}.detail[${di}].mapping`);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
if (step.type === 'ApproveCreate') {
|
|
593
|
+
if (params && typeof params === 'object') {
|
|
594
|
+
checkMapping(params.mapping, `${path}.mapping`);
|
|
595
|
+
for (const [di, det] of (params.detail || []).entries()) {
|
|
596
|
+
if (det && typeof det === 'object')
|
|
597
|
+
checkMapping(det.mapping, `${path}.detail[${di}].mapping`);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
if (step.type === 'MultipleExecution') {
|
|
602
|
+
for (const fieldName of ['cycleTimes', 'detailData', 'batchDetailData']) {
|
|
603
|
+
const formula = params?.[fieldName];
|
|
604
|
+
if (formula && typeof formula === 'object' && ['context', 'reference'].includes(String(formula.kind ?? formula.assignmentKind ?? ''))) {
|
|
605
|
+
checkSourceKey(String(formula.paramKey || formula.key || formula.fieldKey || ''), `${path}.${fieldName}`);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
walk(step.actions || [], `${path}.actions`);
|
|
609
|
+
}
|
|
610
|
+
if (step.type === 'Condition') {
|
|
611
|
+
for (const [bi, branch] of (step.branches || []).entries()) {
|
|
612
|
+
if (branch && typeof branch === 'object')
|
|
613
|
+
walk(branch.actions || [], `${path}.branches[${bi}].actions`);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
walk(plan.actions || []);
|
|
619
|
+
}
|
|
620
|
+
function hydrateLoopCycleTimes(plan, eventContextFields) {
|
|
621
|
+
const byKey = new Map();
|
|
622
|
+
for (const field of eventContextFields) {
|
|
623
|
+
if (field && typeof field === 'object' && field.paramKey)
|
|
624
|
+
byKey.set(String(field.paramKey), field);
|
|
625
|
+
}
|
|
626
|
+
const walk = (steps) => {
|
|
627
|
+
for (const step of steps || []) {
|
|
628
|
+
if (!step || typeof step !== 'object')
|
|
629
|
+
continue;
|
|
630
|
+
if (step.type === 'MultipleExecution') {
|
|
631
|
+
for (const fieldName of ['cycleTimes', 'detailData', 'batchDetailData']) {
|
|
632
|
+
const formula = step.params?.[fieldName];
|
|
633
|
+
const kind = String(formula?.kind ?? formula?.assignmentKind ?? '');
|
|
634
|
+
if (!formula || typeof formula !== 'object' || !['context', 'reference'].includes(kind))
|
|
635
|
+
continue;
|
|
636
|
+
const paramKey = String(formula.paramKey ?? formula.key ?? formula.fieldKey ?? '');
|
|
637
|
+
const field = byKey.get(paramKey);
|
|
638
|
+
if (field) {
|
|
639
|
+
const label = String(field.showName || field.paramName || paramKey);
|
|
640
|
+
const workflowId = String(plan.event?.params?.workflowPath?.id || '');
|
|
641
|
+
formula.paramKey = String(field.paramKey);
|
|
642
|
+
formula.label = label;
|
|
643
|
+
formula.valueType = String(field.paramType || field.fieldType || 'string');
|
|
644
|
+
formula.fieldType = String(field.paramType || field.fieldType || 'string');
|
|
645
|
+
formula._resolvedContext = {
|
|
646
|
+
fieldId: String(field.id || field.paramId || ''),
|
|
647
|
+
fieldType: String(field.paramType || field.fieldType || 'string'),
|
|
648
|
+
label,
|
|
649
|
+
componentType: 'ApproveTrigger',
|
|
650
|
+
tablePrimaryKey: 'ApprovalData',
|
|
651
|
+
tableName: '流程数据',
|
|
652
|
+
parentName: workflowId ? `${workflowId}.${label}` : label,
|
|
653
|
+
rawField: { ...field },
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
walk(step.actions || []);
|
|
658
|
+
}
|
|
659
|
+
if (step.type === 'Condition')
|
|
660
|
+
for (const branch of step.branches || [])
|
|
661
|
+
walk(branch?.actions || []);
|
|
662
|
+
}
|
|
663
|
+
};
|
|
664
|
+
walk(plan.actions || []);
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* 循环体里的 scope=current_loop 引用必须使用循环节点 getComponentContext 返回的
|
|
668
|
+
* CycleParams 元数据。这里补 fieldId/类型/名称,供 FormulaBean 的 frontId 和
|
|
669
|
+
* 配置字段直接复用;不将它误识别成流程表单 FormData。
|
|
670
|
+
*/
|
|
671
|
+
function hydrateCurrentLoopReferences(steps, context) {
|
|
672
|
+
const walkValue = (value) => {
|
|
673
|
+
if (Array.isArray(value)) {
|
|
674
|
+
for (const item of value)
|
|
675
|
+
walkValue(item);
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
if (!value || typeof value !== 'object')
|
|
679
|
+
return;
|
|
680
|
+
if (String(value.scope ?? value.contextScope ?? '') === 'current_loop') {
|
|
681
|
+
const paramKey = String(value.paramKey ?? value.key ?? value.fieldKey ?? '');
|
|
682
|
+
const field = context[paramKey];
|
|
683
|
+
if (field && typeof field === 'object') {
|
|
684
|
+
const raw = field.raw && typeof field.raw === 'object' ? field.raw : {};
|
|
685
|
+
const label = String(field.label ?? raw.showName ?? raw.paramName ?? paramKey);
|
|
686
|
+
const fieldType = String(field.type ?? raw.paramType ?? 'int');
|
|
687
|
+
value.paramKey = paramKey;
|
|
688
|
+
value.label = label;
|
|
689
|
+
value.valueType = fieldType;
|
|
690
|
+
value.fieldType = fieldType;
|
|
691
|
+
value._resolvedContext = {
|
|
692
|
+
fieldId: String(raw.id ?? raw.paramId ?? value.frontId ?? paramKey),
|
|
693
|
+
fieldType,
|
|
694
|
+
label,
|
|
695
|
+
componentType: 'MultipleExecution',
|
|
696
|
+
tablePrimaryKey: 'CycleParams',
|
|
697
|
+
tableName: '循环参数',
|
|
698
|
+
parentName: `循环.${label}`,
|
|
699
|
+
rawField: raw,
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
for (const child of Object.values(value))
|
|
704
|
+
walkValue(child);
|
|
705
|
+
};
|
|
706
|
+
for (const step of steps || [])
|
|
707
|
+
walkValue(step?.params || {});
|
|
708
|
+
}
|
|
709
|
+
/** 显式 mapping 也必须带实时显示名(label)。 */
|
|
710
|
+
export function hydrateMappingLabels(plan, eventContextFields) {
|
|
711
|
+
const labelByParamKey = {};
|
|
712
|
+
for (const field of eventContextFields) {
|
|
713
|
+
if (field && typeof field === 'object' && field.paramKey) {
|
|
714
|
+
labelByParamKey[String(field.paramKey)] = String(field.showName || field.paramName || '');
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
const hydrate = (steps) => {
|
|
718
|
+
for (const step of steps || []) {
|
|
719
|
+
if (!step || typeof step !== 'object')
|
|
720
|
+
continue;
|
|
721
|
+
const params = step.params || {};
|
|
722
|
+
const mapping = params && typeof params === 'object' ? params.mapping : null;
|
|
723
|
+
if (mapping && typeof mapping === 'object') {
|
|
724
|
+
for (const [sourceKey, target] of Object.entries(mapping)) {
|
|
725
|
+
const label = labelByParamKey[String(sourceKey)] || '';
|
|
726
|
+
if (!label)
|
|
727
|
+
continue;
|
|
728
|
+
if (target && typeof target === 'object') {
|
|
729
|
+
target.paramKey ??= String(sourceKey);
|
|
730
|
+
target.label ??= label;
|
|
731
|
+
}
|
|
732
|
+
else {
|
|
733
|
+
mapping[sourceKey] = { target: String(target), paramKey: String(sourceKey), label };
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
if (params && typeof params === 'object') {
|
|
738
|
+
for (const detail of params.detail || []) {
|
|
739
|
+
if (!detail || typeof detail !== 'object' || typeof detail.mapping !== 'object')
|
|
740
|
+
continue;
|
|
741
|
+
for (const [sourceKey, target] of Object.entries(detail.mapping)) {
|
|
742
|
+
const sourceParamKey = target && typeof target === 'object' ? String(target.paramKey || sourceKey) : String(sourceKey);
|
|
743
|
+
const label = labelByParamKey[sourceParamKey] || '';
|
|
744
|
+
if (!label)
|
|
745
|
+
continue;
|
|
746
|
+
if (target && typeof target === 'object') {
|
|
747
|
+
target.paramKey ??= sourceParamKey;
|
|
748
|
+
target.label ??= label;
|
|
749
|
+
}
|
|
750
|
+
else {
|
|
751
|
+
detail.mapping[sourceKey] = { target: String(target), paramKey: sourceParamKey, label };
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
if (step.type === 'Condition') {
|
|
757
|
+
for (const branch of step.branches || []) {
|
|
758
|
+
if (branch && typeof branch === 'object')
|
|
759
|
+
hydrate(branch.actions || []);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
};
|
|
764
|
+
hydrate(plan.actions || []);
|
|
765
|
+
}
|
|
766
|
+
// ── sync 系列(preflight 注入 plan → 同步到 compile 产物 draft)──
|
|
767
|
+
export function syncAutoMappingsToDraft(draft, plan) {
|
|
768
|
+
const planActions = plan.actions || [];
|
|
769
|
+
const draftActions = draft.actions || [];
|
|
770
|
+
for (let i = 0; i < planActions.length && i < draftActions.length; i++) {
|
|
771
|
+
const pa = planActions[i], da = draftActions[i];
|
|
772
|
+
if (!pa || !da || typeof pa !== 'object' || typeof da !== 'object')
|
|
773
|
+
continue;
|
|
774
|
+
const pm = pa.params?.mapping, dm = da.params?.mapping;
|
|
775
|
+
if (pm)
|
|
776
|
+
da.params.mapping = pm;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
export function syncFormReferencesToDraft(draft, plan) {
|
|
780
|
+
const syncStep = (planStep, draftStep) => {
|
|
781
|
+
if (!planStep || !draftStep || typeof planStep !== 'object' || typeof draftStep !== 'object')
|
|
782
|
+
return;
|
|
783
|
+
const pp = planStep.params, dp = draftStep.params;
|
|
784
|
+
if (pp && typeof pp === 'object' && dp && typeof dp === 'object') {
|
|
785
|
+
for (const key of ['targetForm', 'dataSource']) {
|
|
786
|
+
const ref = pp[key];
|
|
787
|
+
if (ref && typeof ref === 'object' && ref.id)
|
|
788
|
+
dp[key] = { ...ref };
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
const pb = planStep.branches, db = draftStep.branches;
|
|
792
|
+
if (Array.isArray(pb) && Array.isArray(db)) {
|
|
793
|
+
for (let i = 0; i < pb.length && i < db.length; i++) {
|
|
794
|
+
const pa2 = pb[i]?.actions || [], da2 = db[i]?.actions || [];
|
|
795
|
+
for (let j = 0; j < pa2.length && j < da2.length; j++)
|
|
796
|
+
syncStep(pa2[j], da2[j]);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
syncStep(plan.event, draft.event);
|
|
801
|
+
const planActions = plan.actions || [];
|
|
802
|
+
const draftActions = draft.actions || [];
|
|
803
|
+
for (let i = 0; i < planActions.length && i < draftActions.length; i++)
|
|
804
|
+
syncStep(planActions[i], draftActions[i]);
|
|
805
|
+
}
|
|
806
|
+
export function syncEventResourcesToDraft(draft, plan) {
|
|
807
|
+
const pe = plan.event, de = draft.event;
|
|
808
|
+
if (!pe || !de || typeof pe !== 'object' || typeof de !== 'object')
|
|
809
|
+
return;
|
|
810
|
+
const pp = pe.params, dp = de.params;
|
|
811
|
+
if (!pp || !dp || typeof pp !== 'object' || typeof dp !== 'object')
|
|
812
|
+
return;
|
|
813
|
+
if (['DateTrigger', 'TimeBatchTrigger'].includes(pe.type) && pp.operator)
|
|
814
|
+
dp.operator = pp.operator;
|
|
815
|
+
}
|
|
816
|
+
export function syncFixedPeopleToDraft(draft, plan) {
|
|
817
|
+
const syncStep = (planStep, draftStep) => {
|
|
818
|
+
if (!planStep || !draftStep || typeof planStep !== 'object' || typeof draftStep !== 'object')
|
|
819
|
+
return;
|
|
820
|
+
const type = String(planStep.type || '');
|
|
821
|
+
const contract = getComponent(type);
|
|
822
|
+
const personKeys = Object.entries(contract?.params || {})
|
|
823
|
+
.filter(([, definition]) => String(definition?.referenceType || '').startsWith('user_assignment'))
|
|
824
|
+
.map(([key]) => key);
|
|
825
|
+
// 会议的召集人/联系人存在 meetingFields 中,是该组件特有的嵌套字段。
|
|
826
|
+
if (type === 'MeetingCreate')
|
|
827
|
+
personKeys.push('caller', 'contacter', 'hrmMembers');
|
|
828
|
+
const pp = planStep.params;
|
|
829
|
+
const dp = draftStep.params;
|
|
830
|
+
if (personKeys.length && pp && dp && typeof pp === 'object' && typeof dp === 'object') {
|
|
831
|
+
const containers = [[pp, dp]];
|
|
832
|
+
if (typeof pp.meetingFields === 'object' && typeof dp.meetingFields === 'object')
|
|
833
|
+
containers.push([pp.meetingFields, dp.meetingFields]);
|
|
834
|
+
for (const [planContainer, draftContainer] of containers) {
|
|
835
|
+
for (const key of personKeys) {
|
|
836
|
+
const value = planContainer[key];
|
|
837
|
+
if (value == null)
|
|
838
|
+
continue;
|
|
839
|
+
const values = Array.isArray(value) ? value : [value];
|
|
840
|
+
if (values.length && values.every((item) => isBrowserPerson(item)))
|
|
841
|
+
draftContainer[key] = value;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
const planBranches = planStep.branches || [];
|
|
846
|
+
const draftBranches = draftStep.branches || [];
|
|
847
|
+
for (let i = 0; i < planBranches.length && i < draftBranches.length; i++) {
|
|
848
|
+
const planActions = planBranches[i]?.actions || [];
|
|
849
|
+
const draftActions = draftBranches[i]?.actions || [];
|
|
850
|
+
for (let j = 0; j < planActions.length && j < draftActions.length; j++)
|
|
851
|
+
syncStep(planActions[j], draftActions[j]);
|
|
852
|
+
}
|
|
853
|
+
const planActions = planStep.actions || [];
|
|
854
|
+
const draftActions = draftStep.actions || [];
|
|
855
|
+
for (let i = 0; i < planActions.length && i < draftActions.length; i++)
|
|
856
|
+
syncStep(planActions[i], draftActions[i]);
|
|
857
|
+
};
|
|
858
|
+
const planActions = plan.actions || [];
|
|
859
|
+
const draftActions = draft.actions || [];
|
|
860
|
+
for (let i = 0; i < planActions.length && i < draftActions.length; i++)
|
|
861
|
+
syncStep(planActions[i], draftActions[i]);
|
|
862
|
+
}
|
|
863
|
+
export function syncBizFieldsToDraft(draft, plan) {
|
|
864
|
+
const planActions = plan.actions || [];
|
|
865
|
+
const draftActions = draft.actions || [];
|
|
866
|
+
for (let i = 0; i < planActions.length && i < draftActions.length; i++) {
|
|
867
|
+
const pa = planActions[i], da = draftActions[i];
|
|
868
|
+
if (!pa || !da || typeof pa !== 'object' || typeof da !== 'object')
|
|
869
|
+
continue;
|
|
870
|
+
if (pa.type !== 'ApproveCreate')
|
|
871
|
+
continue;
|
|
872
|
+
const pp = pa.params;
|
|
873
|
+
if (!pp || typeof pp !== 'object' || !pp._bizFields)
|
|
874
|
+
continue;
|
|
875
|
+
const dp = da.params ??= {};
|
|
876
|
+
if (typeof dp === 'object')
|
|
877
|
+
dp._bizFields = pp._bizFields;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
export function syncEntrustFieldsToDraft(draft, plan) {
|
|
881
|
+
const syncStep = (planStep, draftStep) => {
|
|
882
|
+
if (!planStep || !draftStep || typeof planStep !== 'object' || typeof draftStep !== 'object')
|
|
883
|
+
return;
|
|
884
|
+
if (planStep.type === 'ApproveEntrust' && planStep.params?._entrustFields && draftStep.params) {
|
|
885
|
+
draftStep.params._entrustFields = planStep.params._entrustFields;
|
|
886
|
+
}
|
|
887
|
+
const planBranches = planStep.branches || [];
|
|
888
|
+
const draftBranches = draftStep.branches || [];
|
|
889
|
+
for (let i = 0; i < planBranches.length && i < draftBranches.length; i++) {
|
|
890
|
+
const pa = planBranches[i]?.actions || [], da = draftBranches[i]?.actions || [];
|
|
891
|
+
for (let j = 0; j < pa.length && j < da.length; j++)
|
|
892
|
+
syncStep(pa[j], da[j]);
|
|
893
|
+
}
|
|
894
|
+
};
|
|
895
|
+
for (let i = 0; i < (plan.actions || []).length && i < (draft.actions || []).length; i++)
|
|
896
|
+
syncStep(plan.actions[i], draft.actions[i]);
|
|
897
|
+
}
|
|
898
|
+
/** 入职/更新人员的字段定义是租户实时数据;只把读取结果注入本次 draft,不落盘到 Skill。 */
|
|
899
|
+
export function syncHrmFieldSchemasToDraft(draft, plan) {
|
|
900
|
+
const syncNode = (planStep, draftStep) => {
|
|
901
|
+
if (!planStep || !draftStep || typeof planStep !== 'object' || typeof draftStep !== 'object')
|
|
902
|
+
return;
|
|
903
|
+
if (['PersonnelOnboarding', 'HrmEmployeeUpdate'].includes(String(planStep.type)) && planStep.params?._hrmFieldSchema && draftStep.params) {
|
|
904
|
+
draftStep.params._hrmFieldSchema = planStep.params._hrmFieldSchema;
|
|
905
|
+
}
|
|
906
|
+
const planBranches = planStep.branches || [], draftBranches = draftStep.branches || [];
|
|
907
|
+
for (let i = 0; i < planBranches.length && i < draftBranches.length; i++)
|
|
908
|
+
syncSteps(planBranches[i]?.actions || [], draftBranches[i]?.actions || []);
|
|
909
|
+
if (Array.isArray(planStep.actions) && Array.isArray(draftStep.actions))
|
|
910
|
+
syncSteps(planStep.actions, draftStep.actions);
|
|
911
|
+
};
|
|
912
|
+
const syncSteps = (planSteps, draftSteps) => {
|
|
913
|
+
for (let i = 0; i < planSteps.length && i < draftSteps.length; i++)
|
|
914
|
+
syncNode(planSteps[i], draftSteps[i]);
|
|
915
|
+
};
|
|
916
|
+
syncSteps(plan.actions || [], draft.actions || []);
|
|
917
|
+
}
|
|
918
|
+
async function resolveHrmFieldAssignments(plan, client, errors) {
|
|
919
|
+
let schema = null;
|
|
920
|
+
const fetchSchema = async () => {
|
|
921
|
+
if (schema)
|
|
922
|
+
return schema;
|
|
923
|
+
const response = await hrmSource.getHrmOnboardingFields(client);
|
|
924
|
+
schema = response?.data;
|
|
925
|
+
if (!schema || !Array.isArray(schema.main))
|
|
926
|
+
throw new Error('hrm-onboarding-fields 未返回有效字段定义');
|
|
927
|
+
return schema;
|
|
928
|
+
};
|
|
929
|
+
const validateFields = (values, fields, path) => {
|
|
930
|
+
if (!values || typeof values !== 'object' || Array.isArray(values) || !Object.keys(values).length) {
|
|
931
|
+
errors.push(`${path} 至少配置一个字段。`);
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
for (const key of Object.keys(values)) {
|
|
935
|
+
const hits = fields.filter((field) => String(field.id || '') === key || String(field.showName || field.name || '') === key);
|
|
936
|
+
if (!hits.length)
|
|
937
|
+
errors.push(`${path}: 字段 '${key}' 不在当前租户人员字段定义中。`);
|
|
938
|
+
else if (hits.length > 1)
|
|
939
|
+
errors.push(`${path}: 字段名 '${key}' 重名,请改传字段 ID。`);
|
|
940
|
+
}
|
|
941
|
+
};
|
|
942
|
+
const walk = async (steps, path) => {
|
|
943
|
+
for (let index = 0; index < (steps || []).length; index++) {
|
|
944
|
+
const step = steps[index];
|
|
945
|
+
if (!step || typeof step !== 'object')
|
|
946
|
+
continue;
|
|
947
|
+
const stepPath = `${path}[${index}]`;
|
|
948
|
+
if (['PersonnelOnboarding', 'HrmEmployeeUpdate'].includes(String(step.type))) {
|
|
949
|
+
const params = step.params || {};
|
|
950
|
+
if (!params.fieldAssignments) {
|
|
951
|
+
errors.push(`${stepPath}.params.fieldAssignments 为必填项;请使用语义化字段赋值,不要传 setting DTO。`);
|
|
952
|
+
continue;
|
|
953
|
+
}
|
|
954
|
+
try {
|
|
955
|
+
const current = await fetchSchema();
|
|
956
|
+
params._hrmFieldSchema = current;
|
|
957
|
+
validateFields(params.fieldAssignments.main, current.main || [], `${stepPath}.params.fieldAssignments.main`);
|
|
958
|
+
if (params.fieldAssignments.detail !== undefined) {
|
|
959
|
+
if (!Array.isArray(params.fieldAssignments.detail))
|
|
960
|
+
errors.push(`${stepPath}.params.fieldAssignments.detail 必须是数组。`);
|
|
961
|
+
else
|
|
962
|
+
for (const item of params.fieldAssignments.detail) {
|
|
963
|
+
const tableKey = String(item?.tableId ?? item?.table ?? item?.tableName ?? '');
|
|
964
|
+
const tables = (current.detail || []).filter((table) => String(table.detailTableId || '') === tableKey || String(table.tableName || '') === tableKey);
|
|
965
|
+
if (tables.length !== 1)
|
|
966
|
+
errors.push(`${stepPath}.params.fieldAssignments.detail: 表 '${tableKey}' ${tables.length ? '重名,请传 tableId' : '不在当前租户字段定义中'}。`);
|
|
967
|
+
else
|
|
968
|
+
validateFields(item?.fields ?? item?.assignments, tables[0].fields || [], `${stepPath}.params.fieldAssignments.detail[${tableKey}]`);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
catch (error) {
|
|
973
|
+
errors.push(`${stepPath}: 人员字段读取失败: ${String(error?.message || error)}`);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
for (const branch of step.branches || [])
|
|
977
|
+
await walk(branch?.actions || [], `${stepPath}.branches`);
|
|
978
|
+
if (Array.isArray(step.actions))
|
|
979
|
+
await walk(step.actions, `${stepPath}.actions`);
|
|
980
|
+
}
|
|
981
|
+
};
|
|
982
|
+
await walk(plan.actions || [], 'actions');
|
|
983
|
+
}
|
|
984
|
+
/** 按拓扑顺序查询真实上下文,禁止未解析引用进入保存阶段。 */
|
|
985
|
+
export async function preflightContext(plan, appId, client) {
|
|
986
|
+
const store = new ContextStore();
|
|
987
|
+
const provider = new PlatformContextProvider(client);
|
|
988
|
+
const errors = [];
|
|
989
|
+
const warnings = [];
|
|
990
|
+
const event = plan.event;
|
|
991
|
+
if (!event || typeof event !== 'object') {
|
|
992
|
+
return { valid: false, errors: ['event must be an object'], contextStore: {} };
|
|
993
|
+
}
|
|
994
|
+
await fillRequiredTriggerOperator(plan, client);
|
|
995
|
+
await resolveFixedPeople(plan, client);
|
|
996
|
+
await resolveEntrustFields(plan, client, errors);
|
|
997
|
+
await resolveHrmFieldAssignments(plan, client, errors);
|
|
998
|
+
// 回填 targetForm 缺失的 groupId/name
|
|
999
|
+
try {
|
|
1000
|
+
const unresolvedForms = await resolveTargetForms(plan, client);
|
|
1001
|
+
for (const fid of unresolvedForms) {
|
|
1002
|
+
errors.push(`targetForm.id='${fid}' 未在平台表单中找到, 无法确定所属应用(groupId). 请用 form-applications + form-list 确认表单真实存在.`);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
catch {
|
|
1006
|
+
// 忽略
|
|
1007
|
+
}
|
|
1008
|
+
// 查并登记所有目标表单字段元数据(转换前必须有 fieldType/componentKey)
|
|
1009
|
+
const hydrateFilterFields = async (steps) => {
|
|
1010
|
+
for (const step of steps || []) {
|
|
1011
|
+
if (!step || typeof step !== 'object')
|
|
1012
|
+
continue;
|
|
1013
|
+
if (['ActionEbAdd', 'ActionEbUpdate', 'ActionEbDelete', 'ActionEbRecover', 'ActionEbSaveVersion', 'EbGetDataById', 'EnquiryForm', 'TimeBatchTrigger', 'EventFormData', 'DateTrigger'].includes(step.type)) {
|
|
1014
|
+
const tf = stepFormRef(step);
|
|
1015
|
+
if (tf && tf.id)
|
|
1016
|
+
await getFormFieldsFull(String(tf.id), client, tf);
|
|
1017
|
+
}
|
|
1018
|
+
if (step.type === 'Condition') {
|
|
1019
|
+
for (const branch of step.branches || []) {
|
|
1020
|
+
if (branch && typeof branch === 'object')
|
|
1021
|
+
await hydrateFilterFields(branch.actions || []);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
};
|
|
1026
|
+
await hydrateFilterFields([event]);
|
|
1027
|
+
await hydrateFilterFields(plan.actions || []);
|
|
1028
|
+
// 更新动作若无法拿到目标表字段,平台 saveDesign 会直接 500,这里硬拦截。
|
|
1029
|
+
const validateUpdateFields = (steps, prefix = 'actions') => {
|
|
1030
|
+
for (const [index, step] of (steps || []).entries()) {
|
|
1031
|
+
if (!step || typeof step !== 'object')
|
|
1032
|
+
continue;
|
|
1033
|
+
const path = `${prefix}[${index}]`;
|
|
1034
|
+
if (step.type === 'ActionEbUpdate') {
|
|
1035
|
+
const target = stepFormRef(step) || {};
|
|
1036
|
+
const formId = String(target.id || '');
|
|
1037
|
+
const fields = formId ? (getTargetFormFields())[formId] || {} : {};
|
|
1038
|
+
if (!Object.keys(fields).length) {
|
|
1039
|
+
errors.push(`${path}.targetForm: 未取得目标表单字段,拒绝保存更新动作;请确认 form-fields 能返回该表单的字段定义。`);
|
|
1040
|
+
continue;
|
|
1041
|
+
}
|
|
1042
|
+
const params = step.params || {};
|
|
1043
|
+
for (const key of ['mapping', 'constants']) {
|
|
1044
|
+
const values = params[key] || {};
|
|
1045
|
+
const targets = key === 'mapping' && values && typeof values === 'object'
|
|
1046
|
+
? Object.values(values)
|
|
1047
|
+
: key === 'constants' && values && typeof values === 'object'
|
|
1048
|
+
? Object.keys(values)
|
|
1049
|
+
: [];
|
|
1050
|
+
for (const targetId of targets) {
|
|
1051
|
+
let normalized = String(targetId);
|
|
1052
|
+
if (['+', '-'].includes(normalized[0]))
|
|
1053
|
+
normalized = normalized.slice(1);
|
|
1054
|
+
if (targetId && typeof targetId === 'object') {
|
|
1055
|
+
normalized = String(targetId.target || targetId.fieldId || '');
|
|
1056
|
+
if (['+', '-'].includes(normalized[0]))
|
|
1057
|
+
normalized = normalized.slice(1);
|
|
1058
|
+
}
|
|
1059
|
+
if (normalized && !(normalized in fields)) {
|
|
1060
|
+
errors.push(`${path}.params.${key}: 目标字段 '${targetId}' 不属于表单 '${formId}'。`);
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
if (step.type === 'Condition') {
|
|
1066
|
+
for (const [bi, branch] of (step.branches || []).entries()) {
|
|
1067
|
+
if (branch && typeof branch === 'object')
|
|
1068
|
+
validateUpdateFields(branch.actions || [], `${path}.branches[${bi}].actions`);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
};
|
|
1073
|
+
validateUpdateFields(plan.actions || []);
|
|
1074
|
+
// 查 event 上下文
|
|
1075
|
+
let eventContext = {};
|
|
1076
|
+
try {
|
|
1077
|
+
const eventResult = await queryNodeContext(event, appId, 'event_1', store, provider, 'event');
|
|
1078
|
+
errors.push(...eventResult.errors);
|
|
1079
|
+
eventContext = eventResult.context;
|
|
1080
|
+
}
|
|
1081
|
+
catch (e) {
|
|
1082
|
+
errors.push(String(e?.message || e));
|
|
1083
|
+
}
|
|
1084
|
+
// 提取 event 上下文字段(event_source_fields 按显示名去重,event_context_fields 全量)
|
|
1085
|
+
const eventFieldTypes = {};
|
|
1086
|
+
const eventSourceFields = [];
|
|
1087
|
+
const eventContextFields = [];
|
|
1088
|
+
const seenPk = {};
|
|
1089
|
+
for (const [, v] of Object.entries(eventContext)) {
|
|
1090
|
+
if (v && typeof v === 'object' && v.type === 'context_group') {
|
|
1091
|
+
for (const f of v.fields || []) {
|
|
1092
|
+
if (!f || typeof f !== 'object')
|
|
1093
|
+
continue;
|
|
1094
|
+
if (f.showName && f.componentKey)
|
|
1095
|
+
eventFieldTypes[String(f.showName)] = String(f.componentKey);
|
|
1096
|
+
if (f.showName) {
|
|
1097
|
+
const pk = String(f.paramKey || '');
|
|
1098
|
+
eventContextFields.push({ ...f });
|
|
1099
|
+
const idx = seenPk[String(f.showName)];
|
|
1100
|
+
if (idx === undefined) {
|
|
1101
|
+
seenPk[String(f.showName)] = eventSourceFields.length;
|
|
1102
|
+
eventSourceFields.push({
|
|
1103
|
+
showName: String(f.showName || ''),
|
|
1104
|
+
componentKey: String(f.componentKey || ''),
|
|
1105
|
+
paramType: String(f.paramType || '').toLowerCase(),
|
|
1106
|
+
paramKey: pk,
|
|
1107
|
+
id: String(f.id || ''),
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1110
|
+
else if (pk.endsWith('[]') && !String(eventSourceFields[idx].paramKey).endsWith('[]')) {
|
|
1111
|
+
eventSourceFields[idx].paramKey = pk;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
// 注册字段名→id 映射(component-context paramKey 权威源)
|
|
1118
|
+
const WF_IDS = getWorkflowFieldIds();
|
|
1119
|
+
const byWf = {};
|
|
1120
|
+
for (const sf of eventSourceFields) {
|
|
1121
|
+
const pk = String(sf.paramKey || '');
|
|
1122
|
+
if (pk.includes('.') && sf.showName) {
|
|
1123
|
+
const idx = pk.lastIndexOf('.');
|
|
1124
|
+
const head = pk.slice(0, idx);
|
|
1125
|
+
const tail = pk.slice(idx + 1);
|
|
1126
|
+
(byWf[head] ??= {})[String(sf.showName)] = tail;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
for (const [wfId, wfMap] of Object.entries(byWf)) {
|
|
1130
|
+
if (wfId && wfMap)
|
|
1131
|
+
Object.assign((WF_IDS[wfId] ??= {}), wfMap);
|
|
1132
|
+
}
|
|
1133
|
+
// 提取流程明细表子字段 → WORKFLOW_DETAIL_FIELDS
|
|
1134
|
+
const evWfId = String(event.workflowId || event.params?.workflowPath?.id || '');
|
|
1135
|
+
const WF_DETAIL = getWorkflowDetailFields();
|
|
1136
|
+
for (const sf of eventSourceFields) {
|
|
1137
|
+
const pk = String(sf.paramKey || '');
|
|
1138
|
+
const nm = String(sf.showName || '');
|
|
1139
|
+
if (!nm || (!pk.includes('[]. ') && !pk.includes('[].')))
|
|
1140
|
+
continue;
|
|
1141
|
+
const subform = pk.split('[]')[0].split('.').pop() || '';
|
|
1142
|
+
if (subform) {
|
|
1143
|
+
((WF_DETAIL[evWfId] ??= {})[subform] ??= {})[nm] = pk;
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
// 登记流程明细表真实名称(只登记有子字段的明细表)
|
|
1147
|
+
const WF_DETAIL_NAMES = getWorkflowDetailNames();
|
|
1148
|
+
for (const sf of eventSourceFields) {
|
|
1149
|
+
const pk = String(sf.paramKey || '');
|
|
1150
|
+
const nm = String(sf.showName || '');
|
|
1151
|
+
if (!nm || !pk.endsWith('[]') || pk.includes('[]. ') || pk.includes('[].'))
|
|
1152
|
+
continue;
|
|
1153
|
+
const idx = pk.lastIndexOf('.');
|
|
1154
|
+
const head = pk.slice(0, idx);
|
|
1155
|
+
const subf = pk.slice(idx + 1).replace(/\[\]$/, '');
|
|
1156
|
+
if (head && subf && /^\d+$/.test(subf) && (WF_DETAIL[head] || {})[subf]) {
|
|
1157
|
+
(WF_DETAIL_NAMES[head] ??= {})[subf] = nm;
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
// 触发器上下文注册 + workflow-fields 补注册
|
|
1161
|
+
if (['ApproveTrigger', 'TimeBatchTrigger', 'EventFormData', 'DateTrigger'].includes(event.type)) {
|
|
1162
|
+
let workflowId = String(event.workflowId || event.params?.workflowPath?.id || '');
|
|
1163
|
+
if (!workflowId) {
|
|
1164
|
+
const ds = event.params?.dataSource || event.params?.targetForm || {};
|
|
1165
|
+
workflowId = String(ds.id || '');
|
|
1166
|
+
}
|
|
1167
|
+
if (workflowId) {
|
|
1168
|
+
registerWorkflowContextFields(workflowId, eventContextFields);
|
|
1169
|
+
let fid = FORM_ID_CACHE[workflowId] || '';
|
|
1170
|
+
if (!fid) {
|
|
1171
|
+
for (const s of plan.actions || []) {
|
|
1172
|
+
const tp = s?.params?.targetForm;
|
|
1173
|
+
if (tp && typeof tp === 'object' && tp.id) {
|
|
1174
|
+
fid = String(tp.id);
|
|
1175
|
+
break;
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
if (fid) {
|
|
1180
|
+
FORM_ID_CACHE[workflowId] = fid;
|
|
1181
|
+
try {
|
|
1182
|
+
const wfFields = await workflowSource.getWorkflowFields(client, workflowId, fid);
|
|
1183
|
+
if (wfFields && typeof wfFields === 'object' && Array.isArray(wfFields.data)) {
|
|
1184
|
+
registerWorkflowFieldIds(workflowId, wfFields.data);
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
catch {
|
|
1188
|
+
// 忽略
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
// 显式 mapping 补实时显示名
|
|
1194
|
+
hydrateMappingLabels(plan, eventContextFields);
|
|
1195
|
+
hydrateLoopCycleTimes(plan, eventContextFields);
|
|
1196
|
+
if (errors.length) {
|
|
1197
|
+
return { valid: false, errors, warnings, contextStore: store.asDict() };
|
|
1198
|
+
}
|
|
1199
|
+
// 逐节点查上下文 + ApproveCreate 目标字段
|
|
1200
|
+
const walk = async (steps, branchStore, prefix) => {
|
|
1201
|
+
for (const [index, step] of (steps || []).entries()) {
|
|
1202
|
+
const path = `${prefix}[${index}]`;
|
|
1203
|
+
let result;
|
|
1204
|
+
try {
|
|
1205
|
+
result = await queryNodeContext(step, appId, 'event_1', branchStore, provider, path);
|
|
1206
|
+
}
|
|
1207
|
+
catch (e) {
|
|
1208
|
+
errors.push(String(e?.message || e));
|
|
1209
|
+
return;
|
|
1210
|
+
}
|
|
1211
|
+
errors.push(...result.errors);
|
|
1212
|
+
if (result.errors.length)
|
|
1213
|
+
return;
|
|
1214
|
+
if (step.type === 'Condition') {
|
|
1215
|
+
for (const [bi, branch] of (step.branches || []).entries()) {
|
|
1216
|
+
if (branch && typeof branch === 'object') {
|
|
1217
|
+
await walk(branch.actions || [], new ContextStore(branchStore.asDict()), `${path}.branches[${bi}].actions`);
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
else if (step.type === 'MultipleExecution') {
|
|
1222
|
+
// 循环体可以引用该循环刚返回的 CycleParams(当次循环);先查询循环节点,
|
|
1223
|
+
// 再携带其上下文进入循环体,不能把循环体当作独立主链处理。
|
|
1224
|
+
hydrateCurrentLoopReferences(step.actions || [], branchStore.asDict());
|
|
1225
|
+
await walk(step.actions || [], new ContextStore(branchStore.asDict()), `${path}.actions`);
|
|
1226
|
+
}
|
|
1227
|
+
else if (step.type === 'ApproveCreate') {
|
|
1228
|
+
await resolveBizCreateFields(step, plan, client, errors, path);
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
};
|
|
1232
|
+
await walk(plan.actions || [], store, 'actions');
|
|
1233
|
+
// 源字段硬性校验
|
|
1234
|
+
checkSourceReferences(plan, eventContextFields, errors);
|
|
1235
|
+
if (errors.length) {
|
|
1236
|
+
return { valid: false, errors, warnings, contextStore: store.asDict() };
|
|
1237
|
+
}
|
|
1238
|
+
return {
|
|
1239
|
+
valid: true,
|
|
1240
|
+
errors,
|
|
1241
|
+
warnings,
|
|
1242
|
+
contextStore: store.asDict(),
|
|
1243
|
+
autoMappings: plan._autoMappings || [],
|
|
1244
|
+
autoResources: plan._autoResources || [],
|
|
1245
|
+
};
|
|
1246
|
+
}
|
|
1247
|
+
//# sourceMappingURL=preflight_service.js.map
|