weaver-e10-builder 1.0.8-beta → 1.0.10-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 +420 -72
- package/dist/commands/form-native.js.map +1 -1
- package/dist/commands/form.d.ts.map +1 -1
- package/dist/commands/form.js +175 -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 +78 -8
- 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 -1592
- 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 +36 -5
- package/dist/commands/workflow-create-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 +2 -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/package.json +1 -1
|
@@ -0,0 +1,1804 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkflowDraft 到平台设计 JSON 的节点与拓扑编排。
|
|
3
|
+
* 对齐 Python 版 core/workflow_compiler.py(黄金参照)。
|
|
4
|
+
* 第 1 期聚焦:ApproveTrigger / ActionEbAdd / ActionEbUpdate / ActionEbDelete / Output 的编译主链。
|
|
5
|
+
*/
|
|
6
|
+
import { genSfId } from './id_generator.js';
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import { get, getCompiler, getNodePost } from './components/index.js';
|
|
9
|
+
import { findInMetadata, getTargetFormFields, getWorkflowDetailNames, getTargetDetailFields, getWorkflowDetailFields, getWorkflowFieldIds, workflowFieldId, getWorkflowContextFields, getWorkflowContextFieldsByKey } from './runtime_metadata.js';
|
|
10
|
+
import { buildPersonFormula, buildSettingEntry, attachEsbAssign, resolveEnumConstant, resolveParamKey, resolveSourceFieldLabel, resolveSourceFieldType, normalizeConstantAssignment, lookupTargetFieldMeta, formulaFixedForAssignSwitch, formulaSystemVar, formulaContext, assignFlatContext, assignFlatContextDirect, getFormulaFn, formulaFunction, } from './formula_service.js';
|
|
11
|
+
import { buildFormulaReference, buildUpdateFieldCondition } from './components/action_eb_update_compiler.js';
|
|
12
|
+
import { resolveSystemParameter, isDateSystemParameter } from './system_params.js';
|
|
13
|
+
import { conditionFieldFamily, filterFieldType, normalizeFilterOperator, conditionOperatorOverride, resolveFormCtx, buildFilterContextFormula, } from './filter_rules.js';
|
|
14
|
+
const ENUM_COMPONENT_KEYS = new Set(['Select', 'RadioBox', 'Checkbox', 'MultiSelect', 'Radio']);
|
|
15
|
+
function optionValues(field) {
|
|
16
|
+
if (!field || typeof field !== 'object')
|
|
17
|
+
return new Set();
|
|
18
|
+
const options = field.selectData || field.fieldConfig?.options || [];
|
|
19
|
+
if (!Array.isArray(options))
|
|
20
|
+
return new Set();
|
|
21
|
+
return new Set(options
|
|
22
|
+
.map((option) => String(option?.valueKey ?? option?.value ?? option?.id ?? ''))
|
|
23
|
+
.filter(Boolean));
|
|
24
|
+
}
|
|
25
|
+
function sourceFieldMeta(paramKey, meta) {
|
|
26
|
+
const workflowId = String(meta?._workflow_id || meta?._event_form_id || '');
|
|
27
|
+
const fields = workflowId ? getWorkflowContextFields()[workflowId] || {} : {};
|
|
28
|
+
const byKey = workflowId ? getWorkflowContextFieldsByKey()[workflowId] || {} : {};
|
|
29
|
+
const exact = byKey[paramKey];
|
|
30
|
+
if (exact && typeof exact === 'object')
|
|
31
|
+
return exact;
|
|
32
|
+
const tail = paramKey.split('.').at(-1)?.replace(/\[\]$/, '') || paramKey;
|
|
33
|
+
return Object.values(fields).find((field) => field && typeof field === 'object' && String(field.paramKey || '').split('.').at(-1)?.replace(/\[\]$/, '') === tail);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A context formula copies the source option value at runtime. Cross-form
|
|
37
|
+
* Select fields often use different option IDs even when their labels match;
|
|
38
|
+
* silently compiling that copy produces an empty designer selection. Refuse
|
|
39
|
+
* the unsafe plan and require a target-side fixed value or an explicit mapper.
|
|
40
|
+
*/
|
|
41
|
+
export function assertCompatibleEnumContextMapping(sourceKey, targetFieldId, result, meta) {
|
|
42
|
+
const target = lookupTargetFieldMeta(targetFieldId, result);
|
|
43
|
+
const source = sourceFieldMeta(sourceKey, meta);
|
|
44
|
+
const sourceKind = String(source?.componentKey || source?.type || '');
|
|
45
|
+
const targetKind = String(target?.componentKey || target?.type || '');
|
|
46
|
+
if (!ENUM_COMPONENT_KEYS.has(sourceKind) || !ENUM_COMPONENT_KEYS.has(targetKind))
|
|
47
|
+
return;
|
|
48
|
+
const sourceValues = optionValues(source);
|
|
49
|
+
const targetValues = optionValues(target);
|
|
50
|
+
if (!sourceValues.size || !targetValues.size)
|
|
51
|
+
return;
|
|
52
|
+
const isSameDomain = sourceValues.size === targetValues.size && [...sourceValues].every((value) => targetValues.has(value));
|
|
53
|
+
if (!isSameDomain) {
|
|
54
|
+
throw new Error(`枚举字段 '${source?.showName || source?.paramName || sourceKey}' 不能直接动态赋值到 '${target?.showName || targetFieldId}':两表选项 ID 不一致。请改用目标表 constants,或提供显式 enumMapping。`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// ── compile_component_data ──────────────────────────────────
|
|
58
|
+
export function compileComponentData(draftParams, componentType, ctx, skipCompiler = false) {
|
|
59
|
+
const compiler = skipCompiler ? undefined : getCompiler(componentType);
|
|
60
|
+
if (compiler) {
|
|
61
|
+
const compilerCtx = {
|
|
62
|
+
...ctx,
|
|
63
|
+
compileGeneric: (p, t, c) => compileComponentData(p, t, c, true),
|
|
64
|
+
buildFilterInput: ctx.buildFilterInput ?? buildFilterInput,
|
|
65
|
+
buildConditionDetail: ctx.buildConditionDetail ?? buildConditionDetail,
|
|
66
|
+
};
|
|
67
|
+
return compiler(draftParams, compilerCtx);
|
|
68
|
+
}
|
|
69
|
+
const comp = get(componentType) || {};
|
|
70
|
+
const meta = ctx.meta;
|
|
71
|
+
const appId = ctx.appId;
|
|
72
|
+
const actionIndex = ctx.actionIndex;
|
|
73
|
+
const eventNodeId = ctx.eventNodeId;
|
|
74
|
+
const eventName = ctx.eventName;
|
|
75
|
+
const lenient = ctx.lenient;
|
|
76
|
+
const params = { ...(draftParams || {}) };
|
|
77
|
+
for (const [legacyKey, currentKey] of Object.entries((comp.paramAliases || {}))) {
|
|
78
|
+
if (!(currentKey in params) && legacyKey in params)
|
|
79
|
+
params[currentKey] = params[legacyKey];
|
|
80
|
+
}
|
|
81
|
+
const mapping = comp.dataMapping || {};
|
|
82
|
+
const result = JSON.parse(JSON.stringify(comp.defaultData || {}));
|
|
83
|
+
for (const [draftKey, realKeysRaw] of Object.entries(mapping)) {
|
|
84
|
+
const val = params[draftKey];
|
|
85
|
+
if (val === null || val === undefined || val === '' || (Array.isArray(val) && val.length === 0) || (val && typeof val === 'object' && Object.keys(val).length === 0))
|
|
86
|
+
continue;
|
|
87
|
+
const targets = String(realKeysRaw).split(',').map((k) => k.trim());
|
|
88
|
+
for (const t of targets) {
|
|
89
|
+
if (t.startsWith('_')) {
|
|
90
|
+
try {
|
|
91
|
+
handleSpecial(draftKey, t, val, result, meta, appId, actionIndex, eventNodeId, componentType, eventName);
|
|
92
|
+
}
|
|
93
|
+
catch (e) {
|
|
94
|
+
if (!lenient)
|
|
95
|
+
throw e;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
result[t] = val;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (meta && !Object.values(mapping).includes('_targetForm')) {
|
|
104
|
+
autoTargetForm(result, params, meta, appId);
|
|
105
|
+
}
|
|
106
|
+
if (!('ebActionId' in result) && componentType.startsWith('ActionEb'))
|
|
107
|
+
result.ebActionId = '-1';
|
|
108
|
+
if (componentType.startsWith('ActionEb'))
|
|
109
|
+
result.type = componentType;
|
|
110
|
+
if (componentType === 'EventFormData')
|
|
111
|
+
normalizeEventFormDataTrigger(result, params, componentType);
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* EventFormData 触发时机归一化(真机验证 2026-08-19):
|
|
116
|
+
* 平台 triggerTimes 是字符串数组,枚举 only afterAdd/afterUpdate/afterDelete/fieldDataChange
|
|
117
|
+
* (前端 weapp-esb ActionEbFormData/index.tsx selectData,后端 EventFormDataDTO List<String>)。
|
|
118
|
+
* plan 允许的写法:['afterAdd'] | 'afterAdd' | {triggerEvent:'afterAdd'} | {triggerTimes:[...]},
|
|
119
|
+
* 并支持别名 afterCreate/afterSubmit→afterAdd、afterModify/afterUpdate→afterUpdate。
|
|
120
|
+
* 缺触发时机或值非法 → 显式抛错(不再静默丢弃导致设计器「触发时机」空白)。
|
|
121
|
+
*/
|
|
122
|
+
const EVENT_FORM_DATA_TRIGGER_ALIASES = {
|
|
123
|
+
afterAdd: 'afterAdd', afterCreate: 'afterAdd', afterSubmit: 'afterAdd', add: 'afterAdd',
|
|
124
|
+
afterUpdate: 'afterUpdate', afterModify: 'afterUpdate', update: 'afterUpdate', modify: 'afterUpdate',
|
|
125
|
+
afterDelete: 'afterDelete', delete: 'afterDelete', remove: 'afterDelete',
|
|
126
|
+
fieldDataChange: 'fieldDataChange', valueChange: 'fieldDataChange', change: 'fieldDataChange',
|
|
127
|
+
};
|
|
128
|
+
const EVENT_FORM_DATA_TRIGGER_OPTIONS = Object.values(EVENT_FORM_DATA_TRIGGER_ALIASES);
|
|
129
|
+
function normalizeEventFormDataTrigger(result, params, componentType) {
|
|
130
|
+
const raw = result.triggerTimes ?? params.triggerTimes ?? params.triggerEvent ?? params.triggerTime;
|
|
131
|
+
const errors = [];
|
|
132
|
+
let items = [];
|
|
133
|
+
if (raw === null || raw === undefined || raw === '') {
|
|
134
|
+
errors.push('EventFormData 缺少触发时机 triggerTimes(应为数组/字符串,如 ["afterAdd"])');
|
|
135
|
+
}
|
|
136
|
+
else if (Array.isArray(raw)) {
|
|
137
|
+
items = raw.map((v) => String(v));
|
|
138
|
+
}
|
|
139
|
+
else if (typeof raw === 'string') {
|
|
140
|
+
items = [raw];
|
|
141
|
+
}
|
|
142
|
+
else if (typeof raw === 'object') {
|
|
143
|
+
const ev = raw.triggerEvent ?? raw.event ?? raw.id ?? raw.type ?? '';
|
|
144
|
+
if (ev)
|
|
145
|
+
items = [String(ev)];
|
|
146
|
+
else if (Array.isArray(raw.triggerTimes))
|
|
147
|
+
items = raw.triggerTimes.map((v) => String(v));
|
|
148
|
+
else if (typeof raw.triggerTimes === 'string')
|
|
149
|
+
items = [String(raw.triggerTimes)];
|
|
150
|
+
else
|
|
151
|
+
errors.push(`EventFormData 触发时机对象无法解析: ${JSON.stringify(raw)}`);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
errors.push(`EventFormData 触发时机类型不支持: ${typeof raw}`);
|
|
155
|
+
}
|
|
156
|
+
const normalized = items
|
|
157
|
+
.map((it) => EVENT_FORM_DATA_TRIGGER_ALIASES[it] || '')
|
|
158
|
+
.filter((it) => it);
|
|
159
|
+
const unknown = items.filter((it) => !EVENT_FORM_DATA_TRIGGER_ALIASES[it]);
|
|
160
|
+
if (unknown.length)
|
|
161
|
+
errors.push(`EventFormData 触发时机含非法值 [${unknown.join(',')}],合法枚举: ${[...new Set(EVENT_FORM_DATA_TRIGGER_OPTIONS)].join('/')}`);
|
|
162
|
+
if (errors.length)
|
|
163
|
+
throw new Error(errors.join('; '));
|
|
164
|
+
result.triggerTimes = normalized;
|
|
165
|
+
if (!('triggerType' in result))
|
|
166
|
+
result.triggerType = 'sequence';
|
|
167
|
+
}
|
|
168
|
+
// ── _handle_special ─────────────────────────────────────────
|
|
169
|
+
function handleSpecial(draftKey, special, val, result, meta, appId, idx, eventId, componentType, eventName) {
|
|
170
|
+
if (special === '_person' && val && typeof val === 'object' && !Array.isArray(val)) {
|
|
171
|
+
const contract = get(componentType) || {};
|
|
172
|
+
const personTarget = contract.personTarget ?? 'person';
|
|
173
|
+
if (personTarget === null || personTarget === undefined)
|
|
174
|
+
return;
|
|
175
|
+
result[String(personTarget)] = buildPersonFormula(val, meta, appId, false, true);
|
|
176
|
+
}
|
|
177
|
+
else if (special === '_targetForm' && val && typeof val === 'object' && !Array.isArray(val)) {
|
|
178
|
+
fillTargetForm(result, val, meta, appId);
|
|
179
|
+
}
|
|
180
|
+
else if (special === '_updateId' || special === '_basisValueFormula') {
|
|
181
|
+
if (special === '_updateId') {
|
|
182
|
+
const wfId = String(meta?._workflow_id || '');
|
|
183
|
+
if (val && typeof val === 'object' && (val.kind === 'context' || val.key || val.paramKey)) {
|
|
184
|
+
const key = String(val.paramKey || val.key || val.fieldKey || '');
|
|
185
|
+
const resolved = resolveParamKey(wfId, key);
|
|
186
|
+
const label = String(val.label || val.name || key);
|
|
187
|
+
let wfName = String(meta?._upstream_workflow_name || '');
|
|
188
|
+
if (!wfName)
|
|
189
|
+
wfName = String(meta?._upstream_form_name || '');
|
|
190
|
+
const pn = wfName ? `${wfName}.${label}` : label;
|
|
191
|
+
result.updateId = assignFlatContextDirect(resolved, label, String(eventId || val.source || '0'), appId, 'string', pn, meta);
|
|
192
|
+
// esbAssign.wId 指向当前数据动作节点(设计器动态赋值定位用),与 filterInput 修复同源。
|
|
193
|
+
attachEsbAssign(result.updateId, meta, String(eventId || val.source || '0'));
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
result.updateId = buildFormulaReference(val, { meta, appId, eventId, componentType });
|
|
197
|
+
attachEsbAssign(result.updateId, meta, String(eventId || ''));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
result[special.slice(1)] = buildFormulaReference(val, { meta, appId, eventId, componentType });
|
|
202
|
+
attachEsbAssign(result[special.slice(1)], meta, String(eventId || ''));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
else if (special === '_updateFieldCondition') {
|
|
206
|
+
const condition = buildUpdateFieldCondition(val, { meta, appId, eventId, componentType });
|
|
207
|
+
result.updateFieldCondition = condition;
|
|
208
|
+
(result.setting ??= {}).updateFieldCondition = JSON.parse(JSON.stringify(condition));
|
|
209
|
+
result.updateCondition = (condition.updateField || []).filter((it) => it && typeof it === 'object' && it.fieldKey).map((it) => String(it.fieldKey));
|
|
210
|
+
}
|
|
211
|
+
else if (special === '_setting_main') {
|
|
212
|
+
fillSetting(result, val, undefined, undefined, undefined, meta, appId, eventId, eventName, componentType);
|
|
213
|
+
}
|
|
214
|
+
else if (special === '_setting_mapping') {
|
|
215
|
+
result._pending_mapping ??= {};
|
|
216
|
+
if (val && typeof val === 'object' && !Array.isArray(val))
|
|
217
|
+
Object.assign(result._pending_mapping, val);
|
|
218
|
+
else if (Array.isArray(val)) {
|
|
219
|
+
for (const item of val)
|
|
220
|
+
if (item && typeof item === 'object')
|
|
221
|
+
Object.assign(result._pending_mapping, item);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
else if (special === '_setting_constants' || special === '_setting_formula') {
|
|
225
|
+
const pendingKey = special === '_setting_constants' ? '_pending_constants' : '_pending_formula';
|
|
226
|
+
result[pendingKey] ??= {};
|
|
227
|
+
if (val && typeof val === 'object' && !Array.isArray(val))
|
|
228
|
+
Object.assign(result[pendingKey], val);
|
|
229
|
+
}
|
|
230
|
+
else if (special === '_basisValue') {
|
|
231
|
+
handleBasisValue(val, result, meta, appId, eventId);
|
|
232
|
+
}
|
|
233
|
+
else if (special === '_setting_detail') {
|
|
234
|
+
result._pending_detail ??= [];
|
|
235
|
+
if (Array.isArray(val)) {
|
|
236
|
+
for (const item of val) {
|
|
237
|
+
if (item && typeof item === 'object' && item.detailTableId)
|
|
238
|
+
result._pending_detail.push(item);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
else if (special === '_filterInput') {
|
|
243
|
+
result.filterInput = buildFilterInput(result, val, meta, appId, componentType);
|
|
244
|
+
}
|
|
245
|
+
else if (special === '_bizWorkflowPath' && val && typeof val === 'object') {
|
|
246
|
+
const wfId = String(val.id || '');
|
|
247
|
+
let formIds = val.formIds;
|
|
248
|
+
if (!Array.isArray(formIds))
|
|
249
|
+
formIds = val.formId || val.objId ? [String(val.formId || val.objId)] : [];
|
|
250
|
+
result.workflowPath = [{
|
|
251
|
+
bridgeService: 'ebuilder', relateFormTypes: ['WEA_EBUILDER'],
|
|
252
|
+
name: String(val.name || val.text || ''),
|
|
253
|
+
formIds: formIds.filter(Boolean).map(String),
|
|
254
|
+
id: wfId,
|
|
255
|
+
createFlowId: String(val.createFlowId || wfId),
|
|
256
|
+
workflowtype: String(val.workflowtype ?? val.workflowType ?? appId ?? ''),
|
|
257
|
+
}];
|
|
258
|
+
}
|
|
259
|
+
else if (special === '_bizRequestName') {
|
|
260
|
+
if (typeof val === 'string' && val.trim())
|
|
261
|
+
result.requestName = formulaFixedForAssignSwitch(val);
|
|
262
|
+
else if (val && typeof val === 'object') {
|
|
263
|
+
if (val.systemValue || String(val.kind || '') === 'system_variable') {
|
|
264
|
+
const rawSystem = val.systemValue || val.key;
|
|
265
|
+
result.requestName = formulaSystemVar(rawSystem);
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
const wfId = String(meta?._workflow_id || '');
|
|
269
|
+
const rqKey = resolveParamKey(wfId, String(val.key ?? val.value ?? ''));
|
|
270
|
+
result.requestName = formulaContext('', rqKey, { name: String(val.label || '') });
|
|
271
|
+
attachEsbAssign(result.requestName, meta, String(eventId || ''));
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
else if (special === '_bizOperateUser' && val && typeof val === 'object') {
|
|
276
|
+
result.operator = buildPersonFormula(val, meta, appId);
|
|
277
|
+
}
|
|
278
|
+
else if (special === '_meetingOperators' && val && typeof val === 'object') {
|
|
279
|
+
result.operators = buildPersonFormula(val, meta, appId);
|
|
280
|
+
}
|
|
281
|
+
else if (special === '_dateDataSource' && val && typeof val === 'object') {
|
|
282
|
+
const dsId = String(val.id || val.tableId || val.sourceId || '');
|
|
283
|
+
result.dataSource = {
|
|
284
|
+
isPhysical: true, physical: true,
|
|
285
|
+
groupId: String(val.groupId ?? val.appId ?? '-98'),
|
|
286
|
+
id: dsId, text: String(val.text || val.name || ''), type: String(val.type || 'FORM'),
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
function handleBasisValue(val, result, meta, appId, eventId) {
|
|
291
|
+
if (!val || typeof val !== 'object')
|
|
292
|
+
return;
|
|
293
|
+
let bvKey = String(val.paramKey || val.key || val.value || '').trim();
|
|
294
|
+
let bvLabel = String(val.label || val.name || '');
|
|
295
|
+
// 明细表依据值 paramKey 必须带 [](早期正确产物 FormData.{wfId}.{明细表id}[])。
|
|
296
|
+
// plan 允许省略 [],编译器检测上下文存在数组版本时自动补齐(真机验证 2026-08-19:漏 [] 前端定位不到明细表标红)。
|
|
297
|
+
if (bvKey && !bvKey.includes('[]')) {
|
|
298
|
+
const wfId = String(meta?._workflow_id || '');
|
|
299
|
+
const keyIndex = wfId ? getWorkflowContextFieldsByKey()[String(wfId)] || {} : {};
|
|
300
|
+
const arrKey = `${bvKey}[]`;
|
|
301
|
+
if (keyIndex[arrKey] && !keyIndex[bvKey])
|
|
302
|
+
bvKey = arrKey;
|
|
303
|
+
}
|
|
304
|
+
if (bvKey) {
|
|
305
|
+
const idx = bvKey.lastIndexOf('.');
|
|
306
|
+
const bkHead = idx >= 0 ? bvKey.slice(0, idx) : '';
|
|
307
|
+
const bkTail = idx >= 0 ? bvKey.slice(idx + 1) : bvKey;
|
|
308
|
+
const realName = getWorkflowDetailNames()[bkHead]?.[bkTail.replace(/\[\]$/, '')];
|
|
309
|
+
if (realName)
|
|
310
|
+
bvLabel = realName;
|
|
311
|
+
}
|
|
312
|
+
if (!bvLabel)
|
|
313
|
+
bvLabel = bvKey;
|
|
314
|
+
if (bvKey) {
|
|
315
|
+
const tail = bvKey.includes('.') ? bvKey.slice(bvKey.lastIndexOf('.') + 1).replace(/\[\]$/, '') : bvKey.replace(/\[\]$/, '');
|
|
316
|
+
const bvId = /^\d+$/.test(tail) ? tail : bvKey;
|
|
317
|
+
result.basisValue = bvId;
|
|
318
|
+
const fId = genSfId();
|
|
319
|
+
const fBiz = genSfId();
|
|
320
|
+
const srcId = eventId || String(meta?._upstream_node_id || '');
|
|
321
|
+
const wnBv = String(meta?._upstream_workflow_name || '');
|
|
322
|
+
const bvParent = wnBv ? `${wnBv}.${bvLabel}[]` : `${bvLabel}[]`;
|
|
323
|
+
const bvfType = resolveSourceFieldType(bvKey, meta);
|
|
324
|
+
const bvfConfig = {
|
|
325
|
+
paramKey: bvKey, isMultCom: false, comType: 'ApproveTrigger', switchType: 'assign', parentComId: 0, formulaVersion: 'V1',
|
|
326
|
+
fieldInfo: { paramKey: bvKey, tablePrimaryKey: 'FormData' },
|
|
327
|
+
tableName: '表单数据', paramType: bvfType, parentName: bvParent, multName: '', multKey: '',
|
|
328
|
+
multTypeObj: {
|
|
329
|
+
allName: bvParent, currentName: bvParent,
|
|
330
|
+
currentParamKey: `FormData.${bvKey}`, allParamKey: `FormData.${bvKey}`,
|
|
331
|
+
},
|
|
332
|
+
comId: srcId, newParentName: bvParent,
|
|
333
|
+
};
|
|
334
|
+
const bvf = {
|
|
335
|
+
frontId: bvId, formulaType: bvfType, name: bvLabel, businessId: fBiz, id: fId,
|
|
336
|
+
source: srcId, type: '3', value: `FormData.${bvKey}`, childs: [], config: bvfConfig, parentId: '0',
|
|
337
|
+
};
|
|
338
|
+
// 依据值公式同样需要 esbAssign.wId 指向当前数据动作节点(设计器动态赋值定位用)。
|
|
339
|
+
attachEsbAssign(bvf, meta, srcId);
|
|
340
|
+
result.basisValueFormula = bvf;
|
|
341
|
+
result._pending_basis = { bassisValueId: bvId, bassisValue: JSON.parse(JSON.stringify(bvf)) };
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
function autoTargetForm(result, params, meta, appId) {
|
|
345
|
+
const tf = params.targetForm;
|
|
346
|
+
if (!tf || typeof tf !== 'object' || Array.isArray(tf))
|
|
347
|
+
return;
|
|
348
|
+
fillTargetForm(result, tf, meta, appId);
|
|
349
|
+
}
|
|
350
|
+
function fillTargetForm(result, tf, meta, appId) {
|
|
351
|
+
const form = findInMetadata(meta, 'forms', tf);
|
|
352
|
+
const fid = form ? form.id : (tf.id ?? tf.tableId ?? '');
|
|
353
|
+
const formRef = form || tf;
|
|
354
|
+
const formText = formRef.text || formRef.name || '';
|
|
355
|
+
const formAppId = (form || tf).groupId ?? (form || tf).appId ?? '';
|
|
356
|
+
const resolvedAppId = formAppId || fid;
|
|
357
|
+
const groupName = formRef.groupName ?? formText;
|
|
358
|
+
result.targetForm = { groupName, groupId: resolvedAppId, id: fid, text: formText, type: 'FORM' };
|
|
359
|
+
result.tableType = [{ name: formText, id: fid }];
|
|
360
|
+
result.appType = [{ pcUrl: `/ebdapp/view/${resolvedAppId}`, name: groupName, id: resolvedAppId }];
|
|
361
|
+
result.dataSource = { groupId: resolvedAppId, id: fid, text: formText, type: 'FORM' };
|
|
362
|
+
result.appId = resolvedAppId;
|
|
363
|
+
result.objId = fid;
|
|
364
|
+
if (appId) {
|
|
365
|
+
result.currentApplication = appId;
|
|
366
|
+
result.applicationId = appId;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
// ── _fill_setting ───────────────────────────────────────────
|
|
370
|
+
export function fillSetting(result, updates, mapping, constants, formula, meta, appId, eventId, eventName, componentType) {
|
|
371
|
+
if (!meta || typeof meta !== 'object')
|
|
372
|
+
meta = {};
|
|
373
|
+
const main = {};
|
|
374
|
+
const assignmentMode = (get(componentType) || {}).assignmentContextMode || '';
|
|
375
|
+
if (Array.isArray(updates)) {
|
|
376
|
+
for (const u of updates) {
|
|
377
|
+
if (!u || typeof u !== 'object')
|
|
378
|
+
continue;
|
|
379
|
+
const field = u.field ?? u.formField ?? u.fieldId ?? genSfId();
|
|
380
|
+
let fid = field;
|
|
381
|
+
let fieldType = 'Text';
|
|
382
|
+
if (field && typeof field === 'object') {
|
|
383
|
+
fid = field.id ?? field.key ?? genSfId();
|
|
384
|
+
const sourceType = field.type ?? '';
|
|
385
|
+
fieldType = { String: 'Text', string: 'Text', Number: 'NumberComponent', number: 'NumberComponent' }[sourceType] ?? (sourceType || 'Text');
|
|
386
|
+
}
|
|
387
|
+
main[String(fid)] = buildSettingEntry(String(fid), u, fieldType, meta, appId, String(eventId), 'OPERATE_EQUAL', componentType, false, assignmentMode);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
if (mapping && typeof mapping === 'object' && !Array.isArray(mapping)) {
|
|
391
|
+
for (const [sourceKey, targetFieldIdRaw] of Object.entries(mapping)) {
|
|
392
|
+
const targetFieldId = targetFieldIdRaw;
|
|
393
|
+
let operate = 'OPERATE_EQUAL';
|
|
394
|
+
if (targetFieldId && typeof targetFieldId === 'object' && !Array.isArray(targetFieldId)) {
|
|
395
|
+
if (targetFieldId.systemValue) {
|
|
396
|
+
const svKey = String(targetFieldId.systemValue);
|
|
397
|
+
const tfid = String(targetFieldId.target || '');
|
|
398
|
+
if (!tfid)
|
|
399
|
+
throw new Error(`mapping 系统变量值缺少目标字段 id: 应传 {'target':'<目标字段id>', 'systemValue':'currentUser'}`);
|
|
400
|
+
main[tfid] = buildSettingEntry(tfid, { kind: 'system_variable', key: svKey }, 'Text', meta, appId, String(eventId), 'OPERATE_EQUAL', componentType, false, assignmentMode);
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
let raw = String(targetFieldId.target || targetFieldId.fieldId || '');
|
|
404
|
+
if (!raw)
|
|
405
|
+
throw new Error('ActionEbAdd.mapping 依据值下级值缺少目标字段 id');
|
|
406
|
+
if (raw.startsWith('+')) {
|
|
407
|
+
operate = 'OPERATE_PLUS';
|
|
408
|
+
raw = raw.slice(1);
|
|
409
|
+
}
|
|
410
|
+
else if (raw.startsWith('-')) {
|
|
411
|
+
operate = 'OPERATE_MINUS';
|
|
412
|
+
raw = raw.slice(1);
|
|
413
|
+
}
|
|
414
|
+
const refKey = String(targetFieldId.paramKey || sourceKey);
|
|
415
|
+
const refLabel = String(targetFieldId.label || resolveSourceFieldLabel(refKey, meta, String(sourceKey)));
|
|
416
|
+
const refDetail = String(targetFieldId.detailLabel || '');
|
|
417
|
+
const assignment = { kind: 'context', paramKey: refKey, label: refLabel };
|
|
418
|
+
if (refDetail)
|
|
419
|
+
assignment.detailLabel = refDetail;
|
|
420
|
+
assertCompatibleEnumContextMapping(refKey, raw, result, meta || {});
|
|
421
|
+
const srcParamKey = String(assignment.paramKey || sourceKey);
|
|
422
|
+
const srcFt = resolveSourceFieldType(srcParamKey, meta);
|
|
423
|
+
main[raw] = buildSettingEntry(raw, assignment, srcFt, meta, appId, String(eventId), operate, componentType, false, assignmentMode);
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
let raw = String(targetFieldId);
|
|
427
|
+
if (raw.startsWith('+')) {
|
|
428
|
+
operate = 'OPERATE_PLUS';
|
|
429
|
+
raw = raw.slice(1);
|
|
430
|
+
}
|
|
431
|
+
else if (raw.startsWith('-')) {
|
|
432
|
+
operate = 'OPERATE_MINUS';
|
|
433
|
+
raw = raw.slice(1);
|
|
434
|
+
}
|
|
435
|
+
const refKey = String(sourceKey);
|
|
436
|
+
const assignment = { kind: 'context', paramKey: refKey, label: resolveSourceFieldLabel(refKey, meta, refKey) };
|
|
437
|
+
assertCompatibleEnumContextMapping(refKey, raw, result, meta || {});
|
|
438
|
+
const srcFt = resolveSourceFieldType(refKey, meta);
|
|
439
|
+
main[raw] = buildSettingEntry(raw, assignment, srcFt, meta, appId, String(eventId), operate, componentType, false, assignmentMode);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
if (constants && typeof constants === 'object' && !Array.isArray(constants)) {
|
|
444
|
+
for (const [targetFieldId, value] of Object.entries(constants)) {
|
|
445
|
+
const tfid = String(targetFieldId);
|
|
446
|
+
let operateC = 'OPERATE_EQUAL';
|
|
447
|
+
let rawV = value;
|
|
448
|
+
if (typeof value === 'string' && value.length > 1 && (value[0] === '+' || value[0] === '-')) {
|
|
449
|
+
operateC = value[0] === '+' ? 'OPERATE_PLUS' : 'OPERATE_MINUS';
|
|
450
|
+
rawV = value.slice(1);
|
|
451
|
+
}
|
|
452
|
+
const fieldMeta = lookupTargetFieldMeta(tfid, result);
|
|
453
|
+
rawV = resolveEnumConstant(rawV, fieldMeta);
|
|
454
|
+
const [assignment, ft] = normalizeConstantAssignment(rawV, 'Text');
|
|
455
|
+
// 固定枚举值的外层 fieldType 必须是目标组件类型(例如 Select),
|
|
456
|
+
// 与手工保存 JSON 一致;使用默认 Text 会导致设计器下拉回显为空。
|
|
457
|
+
const targetFieldType = String(fieldMeta?.componentKey || fieldMeta?.type || ft);
|
|
458
|
+
main[tfid] = buildSettingEntry(tfid, assignment, targetFieldType, meta, appId, String(eventId), operateC, componentType, false, assignmentMode);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
if (formula && typeof formula === 'object' && !Array.isArray(formula)) {
|
|
462
|
+
for (const [targetFieldId, fspecRaw] of Object.entries(formula)) {
|
|
463
|
+
const fspec = fspecRaw;
|
|
464
|
+
if (!fspec || typeof fspec !== 'object')
|
|
465
|
+
continue;
|
|
466
|
+
const op = fspec.op || 'add';
|
|
467
|
+
const fields = fspec.fields || [];
|
|
468
|
+
if (!fields.length)
|
|
469
|
+
continue;
|
|
470
|
+
const fnInfo = getFormulaFn(op);
|
|
471
|
+
const childs = [];
|
|
472
|
+
for (const fld of fields) {
|
|
473
|
+
const child = assignFlatContext(String(fld), String(fld), String(eventId), appId, 'double');
|
|
474
|
+
child.position = genSfId();
|
|
475
|
+
child.paramType = 'double';
|
|
476
|
+
child.componentKey = 'Number';
|
|
477
|
+
child.fieldType = 'number';
|
|
478
|
+
childs.push(child);
|
|
479
|
+
}
|
|
480
|
+
const bean = formulaFunction(fnInfo.fnId, fnInfo.name, childs, 'double', op, fnInfo.functionType || 'operation', undefined, appId);
|
|
481
|
+
const flatId = bean.id || genSfId();
|
|
482
|
+
const assign = Object.fromEntries(Object.entries(bean).filter(([k]) => !['configObject', 'childs', 'parentId', 'sortWeight', 'position'].includes(k)));
|
|
483
|
+
if (bean.childs)
|
|
484
|
+
assign.childs = bean.childs;
|
|
485
|
+
assign.applicationId ??= String(appId);
|
|
486
|
+
assign.id ??= String(flatId);
|
|
487
|
+
main[String(targetFieldId)] = {
|
|
488
|
+
formFieldKey: '',
|
|
489
|
+
value: {
|
|
490
|
+
original: false, operate: 'OPERATE_EQUAL', switchType: 'assign', fieldKey: String(targetFieldId),
|
|
491
|
+
assignType: '', multiSelect: false, fieldType: 'NumberComponent', assign, assignId: String(flatId),
|
|
492
|
+
},
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
const contract = get(componentType) || {};
|
|
497
|
+
const settingBehavior = contract.settingBehavior || {};
|
|
498
|
+
const completeOps = settingBehavior.completeFieldsForOpTypes || [];
|
|
499
|
+
if (completeOps.includes(result.opType)) {
|
|
500
|
+
const tfId = String((result.targetForm || {}).id || '');
|
|
501
|
+
const tff = tfId ? (getTargetFormFields()[tfId] || {}) : {};
|
|
502
|
+
for (const [fid, fmeta] of Object.entries(tff)) {
|
|
503
|
+
const fidS = String(fid);
|
|
504
|
+
if (fidS in main)
|
|
505
|
+
continue;
|
|
506
|
+
const ftype = String(fmeta.fieldType || fmeta.type || 'Text');
|
|
507
|
+
main[fidS] = { formFieldKey: '', value: { original: false, operate: 'OPERATE_EQUAL', fieldKey: fidS, multiSelect: false } };
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
result.setting = {
|
|
511
|
+
opType: result.opType ?? 'insert',
|
|
512
|
+
updatePolicy: result.updatePolicy ?? 'ALL',
|
|
513
|
+
dataDrWithCalc: false,
|
|
514
|
+
main,
|
|
515
|
+
detail: [],
|
|
516
|
+
updateFieldCondition: { updateField: [] },
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
// ── filter 筛选条件树 ───────────────────────────────────────
|
|
520
|
+
function isFilterGroup(value) {
|
|
521
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
522
|
+
return false;
|
|
523
|
+
const children = value.conditions ?? value.datas;
|
|
524
|
+
if (!Array.isArray(children))
|
|
525
|
+
return false;
|
|
526
|
+
return !['left', 'right', 'field', 'operator', 'value', 'id', 'key', 'fieldName'].some((k) => k in value);
|
|
527
|
+
}
|
|
528
|
+
function filterGroupChildren(value) {
|
|
529
|
+
const children = value.conditions ?? value.datas ?? [];
|
|
530
|
+
if (!Array.isArray(children))
|
|
531
|
+
throw new Error('filterCondition 分组的 conditions 必须是数组');
|
|
532
|
+
if (!children.length)
|
|
533
|
+
throw new Error('filterCondition 分组至少需要一条条件');
|
|
534
|
+
return children;
|
|
535
|
+
}
|
|
536
|
+
function filterRelationship(value) {
|
|
537
|
+
const text = String(value ?? '1').trim().toLowerCase();
|
|
538
|
+
if (['1', 'and', '&&'].includes(text))
|
|
539
|
+
return '1';
|
|
540
|
+
if (['0', 'or', '||'].includes(text))
|
|
541
|
+
return '0';
|
|
542
|
+
throw new Error('filterCondition relationship 只支持 and/or(或 1/0)');
|
|
543
|
+
}
|
|
544
|
+
function containsFilterGroup(value) {
|
|
545
|
+
if (isFilterGroup(value))
|
|
546
|
+
return true;
|
|
547
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
548
|
+
const children = value.conditions ?? value.datas;
|
|
549
|
+
if (Array.isArray(children))
|
|
550
|
+
return children.some(containsFilterGroup);
|
|
551
|
+
return false;
|
|
552
|
+
}
|
|
553
|
+
if (Array.isArray(value))
|
|
554
|
+
return value.some(containsFilterGroup);
|
|
555
|
+
return false;
|
|
556
|
+
}
|
|
557
|
+
function rejectUnsupportedFilterModes(value) {
|
|
558
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
559
|
+
const mode = String(value.type ?? value.mode ?? '').trim().toLowerCase();
|
|
560
|
+
if (['sql', 'sql_where', 'http'].includes(mode))
|
|
561
|
+
throw new Error('filterCondition 不支持 SQL/HTTP 条件;请使用表单字段条件树');
|
|
562
|
+
for (const item of Object.values(value))
|
|
563
|
+
rejectUnsupportedFilterModes(item);
|
|
564
|
+
}
|
|
565
|
+
else if (Array.isArray(value)) {
|
|
566
|
+
for (const item of value)
|
|
567
|
+
rejectUnsupportedFilterModes(item);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
export function buildFilterInput(result, val, meta, appId, componentType = '', allowTree = true) {
|
|
571
|
+
componentType = String(componentType || '');
|
|
572
|
+
if (allowTree && containsFilterGroup(val)) {
|
|
573
|
+
return buildFilterTree(result, val, meta, appId, componentType);
|
|
574
|
+
}
|
|
575
|
+
const eventLocalFilter = (get(componentType) || {}).filterValueScope === 'local';
|
|
576
|
+
let conditions;
|
|
577
|
+
if (val && typeof val === 'object' && !Array.isArray(val)) {
|
|
578
|
+
if (val.condition && typeof val.condition === 'object')
|
|
579
|
+
conditions = [val.condition];
|
|
580
|
+
else if ('conditions' in val)
|
|
581
|
+
conditions = val.conditions;
|
|
582
|
+
else
|
|
583
|
+
conditions = [val];
|
|
584
|
+
}
|
|
585
|
+
else if (Array.isArray(val))
|
|
586
|
+
conditions = val;
|
|
587
|
+
else
|
|
588
|
+
conditions = [];
|
|
589
|
+
const formId = result.objId || (result.targetForm || {}).id || (result.dataSource || {}).id || (result.dataSource || {}).sourceId || '';
|
|
590
|
+
const fctx = resolveFormCtx(result, meta, formId);
|
|
591
|
+
const form = findInMetadata(meta, 'forms', { id: formId }) || {};
|
|
592
|
+
const fieldIndex = {};
|
|
593
|
+
for (const f of form.fields || [])
|
|
594
|
+
fieldIndex[String(f.id || '')] = f;
|
|
595
|
+
Object.assign(fieldIndex, getTargetFormFields()[String(formId)] || {});
|
|
596
|
+
const datas = [];
|
|
597
|
+
const timeStamp = String(Date.now());
|
|
598
|
+
conditions.forEach((c, idx) => {
|
|
599
|
+
if (!c || typeof c !== 'object')
|
|
600
|
+
return;
|
|
601
|
+
const left = c.left && typeof c.left === 'object' ? c.left : c;
|
|
602
|
+
let fieldId = '';
|
|
603
|
+
let label = '';
|
|
604
|
+
let right;
|
|
605
|
+
if (left.field && typeof left.field === 'object' && left.field.id) {
|
|
606
|
+
fieldId = String(left.field.id);
|
|
607
|
+
label = left.field.label || left.field.name || fieldId;
|
|
608
|
+
if (c.right && typeof c.right === 'object')
|
|
609
|
+
right = c.right;
|
|
610
|
+
else if (c.value && typeof c.value === 'object')
|
|
611
|
+
right = c.value;
|
|
612
|
+
else
|
|
613
|
+
right = { value: c.value ?? '' };
|
|
614
|
+
}
|
|
615
|
+
else if (left.key || left.id) {
|
|
616
|
+
fieldId = String(left.key ?? left.id ?? '');
|
|
617
|
+
label = left.label ?? left.name ?? '';
|
|
618
|
+
right = c.right ?? c.value ?? '';
|
|
619
|
+
}
|
|
620
|
+
else {
|
|
621
|
+
fieldId = '';
|
|
622
|
+
label = '';
|
|
623
|
+
right = '';
|
|
624
|
+
}
|
|
625
|
+
const fmeta = fieldIndex[fieldId] || {};
|
|
626
|
+
if (!fmeta || Object.keys(fmeta).length === 0) {
|
|
627
|
+
throw new Error(`filterCondition 左侧字段 id='${fieldId}' 不在目标表单 '${formId}' 的实时字段列表中`);
|
|
628
|
+
}
|
|
629
|
+
const schema = fmeta.schema && typeof fmeta.schema === 'object' ? fmeta.schema : {};
|
|
630
|
+
const rawFieldType = String(fmeta.type || fmeta.fieldType || schema.fieldType || 'String');
|
|
631
|
+
const compType = String(fmeta.componentKey || schema.componentKey || schema.compType || 'Text');
|
|
632
|
+
const family = conditionFieldFamily(compType, rawFieldType);
|
|
633
|
+
const fieldType = filterFieldType(rawFieldType, compType);
|
|
634
|
+
label = String(label || fmeta.showName || fmeta.name || fieldId);
|
|
635
|
+
let rawConfig = fmeta.config;
|
|
636
|
+
if (typeof rawConfig === 'string') {
|
|
637
|
+
try {
|
|
638
|
+
rawConfig = JSON.parse(rawConfig);
|
|
639
|
+
}
|
|
640
|
+
catch {
|
|
641
|
+
rawConfig = {};
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
let multiSelect = fmeta.multiSelect;
|
|
645
|
+
if (multiSelect === undefined && rawConfig && typeof rawConfig === 'object' && 'isSingle' in rawConfig)
|
|
646
|
+
multiSelect = !Boolean(rawConfig.isSingle);
|
|
647
|
+
const isMultiSelect = multiSelect === true || String(multiSelect).toLowerCase() === 'true';
|
|
648
|
+
if (right && typeof right === 'object' && right.kind === 'context' && !right.type) {
|
|
649
|
+
throw new Error("filterCondition 不支持 value.kind:'context';请使用 right:{type:'context',paramKey:'<真实paramKey>',label:'<显示名>'}");
|
|
650
|
+
}
|
|
651
|
+
let rightType = right && typeof right === 'object' ? String(right.type || 'fixed').trim().toLowerCase() : 'fixed';
|
|
652
|
+
if (right && typeof right === 'object' && right.paramKey && !right.type) {
|
|
653
|
+
throw new Error("filterCondition 动态右值缺少 type:'context';请使用 right:{type:'context',paramKey:'<真实paramKey>',label:'<显示名>'}");
|
|
654
|
+
}
|
|
655
|
+
if (['manual', 'constant', 'const'].includes(rightType))
|
|
656
|
+
rightType = 'fixed';
|
|
657
|
+
else if (['dynamic', 'assign', 'workflowfield', 'workflow_field'].includes(rightType))
|
|
658
|
+
rightType = 'context';
|
|
659
|
+
else if (['formfield', 'form_field'].includes(rightType))
|
|
660
|
+
rightType = 'formfield';
|
|
661
|
+
else if (['custom', 'custombyhandler'].includes(rightType))
|
|
662
|
+
rightType = 'custombyhander';
|
|
663
|
+
else if (['platform', 'condition'].includes(rightType))
|
|
664
|
+
rightType = 'native';
|
|
665
|
+
if (!['fixed', 'system', 'context', 'formfield', 'selectdata', 'custombyhander', 'native', 'varfield', 'filterval'].includes(rightType)) {
|
|
666
|
+
throw new Error(`filterCondition 右值 type='${rightType}' 不支持; 支持 fixed/manual/context/formField/selectData/customByHander/native/varField/filterVal`);
|
|
667
|
+
}
|
|
668
|
+
// 原生「当前时间/当前日期」改写为系统参数(真机验证 2026-08-18):平台 native type 列表不含 currentTime/currentDate
|
|
669
|
+
// 等具体 token,原样透传后 conditionData.value="" 触发设计器「右值未配置」判断(外面能显示摘要,点进去空)。
|
|
670
|
+
// 与 system_params 的 currentTime→{time}/currentDate→{date} 映射一致,落到 system 路径后走完整校验+value 非空。
|
|
671
|
+
if (rightType === 'native') {
|
|
672
|
+
const m = (right && typeof right === 'object' ? String(right.mode || right.conditionType || right.nativeType || '') : '').toLowerCase();
|
|
673
|
+
if (['currenttime', 'now', 'current_time'].includes(m)) {
|
|
674
|
+
rightType = 'system';
|
|
675
|
+
if (right && typeof right === 'object')
|
|
676
|
+
right.value = '{time}';
|
|
677
|
+
else
|
|
678
|
+
right = '{time}';
|
|
679
|
+
}
|
|
680
|
+
else if (['currentdate', 'today', 'current_date'].includes(m)) {
|
|
681
|
+
rightType = 'system';
|
|
682
|
+
if (right && typeof right === 'object')
|
|
683
|
+
right.value = '{date}';
|
|
684
|
+
else
|
|
685
|
+
right = '{date}';
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
if (rightType === 'fixed' && right && typeof right === 'object') {
|
|
689
|
+
try {
|
|
690
|
+
resolveSystemParameter(right.value ?? '');
|
|
691
|
+
rightType = 'system';
|
|
692
|
+
}
|
|
693
|
+
catch { /* not a system token */ }
|
|
694
|
+
}
|
|
695
|
+
if (rightType === 'system') {
|
|
696
|
+
const systemValue = right && typeof right === 'object' ? String(right.value ?? '') : String(right);
|
|
697
|
+
const resolvedSystemValue = resolveSystemParameter(systemValue);
|
|
698
|
+
if (family === 'date' && !isDateSystemParameter(resolvedSystemValue))
|
|
699
|
+
throw new Error('filterCondition 日期/日期时间字段只能使用日期类系统参数');
|
|
700
|
+
if (right && typeof right === 'object')
|
|
701
|
+
right.value = resolvedSystemValue;
|
|
702
|
+
}
|
|
703
|
+
if (eventLocalFilter && ['context', 'formfield', 'custombyhander'].includes(rightType)) {
|
|
704
|
+
throw new Error('EventFormData 的 ConditionSet 不支持上下文右值;前端未启用 supportEsbAssign,请改用固定值或无值操作符');
|
|
705
|
+
}
|
|
706
|
+
const isContext = ['context', 'formfield', 'custombyhander'].includes(rightType);
|
|
707
|
+
const isNative = ['native', 'varfield', 'filterval'].includes(rightType);
|
|
708
|
+
const filterValueType = String((right && typeof right === 'object' ? right.filterValueType : '') || c.filterValueType || '');
|
|
709
|
+
const allowedOverride = conditionOperatorOverride(fmeta, family, compType, fieldId, filterValueType);
|
|
710
|
+
let contextIsArray = false;
|
|
711
|
+
let value;
|
|
712
|
+
if (isContext) {
|
|
713
|
+
[value, contextIsArray] = buildFilterContextFormula(right, meta, appId, fieldType, compType);
|
|
714
|
+
}
|
|
715
|
+
else {
|
|
716
|
+
let rawValue = right && typeof right === 'object' ? (right.value ?? right.id ?? right.name ?? '') : right;
|
|
717
|
+
const preserveBrowserPayload = isNative || ['reference', 'file', 'doc_folder', 'app_tag'].includes(family);
|
|
718
|
+
if (rawValue && typeof rawValue === 'object' && !Array.isArray(rawValue) && !preserveBrowserPayload)
|
|
719
|
+
rawValue = rawValue.value ?? rawValue.id ?? rawValue.name ?? '';
|
|
720
|
+
else if (Array.isArray(rawValue) && !preserveBrowserPayload) {
|
|
721
|
+
rawValue = rawValue.map((v) => (v && typeof v === 'object' ? (v.value ?? v.id ?? v.name ?? '') : v));
|
|
722
|
+
}
|
|
723
|
+
value = rawValue;
|
|
724
|
+
}
|
|
725
|
+
const func = normalizeFilterOperator(c.operator ?? 'eq', family, { contextIsArray, multiSelect: isMultiSelect, allowedOverride });
|
|
726
|
+
const isNullary = ['empty', 'nempty'].includes(func);
|
|
727
|
+
if (isNullary)
|
|
728
|
+
value = '';
|
|
729
|
+
else if (func === 'range') {
|
|
730
|
+
if (isContext)
|
|
731
|
+
throw new Error('filterCondition range 动态右值必须提供两个原生端点,不能使用单个 context');
|
|
732
|
+
if (!Array.isArray(value) || value.length !== 2)
|
|
733
|
+
throw new Error('filterCondition range 右值必须是长度为 2 的数组 [起始值, 结束值]');
|
|
734
|
+
}
|
|
735
|
+
let valueText = '';
|
|
736
|
+
if (right && typeof right === 'object' && (right.label || right.name))
|
|
737
|
+
valueText = String(right.label || right.name);
|
|
738
|
+
else if (value && typeof value === 'object' && !Array.isArray(value))
|
|
739
|
+
valueText = String(value.name || value.value || '');
|
|
740
|
+
else if (Array.isArray(value))
|
|
741
|
+
valueText = value.map((v) => (v && typeof v === 'object' ? String(v.content || v.label || v.name || v.id || '') : String(v))).join(',');
|
|
742
|
+
else if (typeof value === 'string')
|
|
743
|
+
valueText = value;
|
|
744
|
+
const conditionData = { func, text: isNullary ? '' : valueText, value };
|
|
745
|
+
if (!isNullary) {
|
|
746
|
+
if (isContext) {
|
|
747
|
+
const valStr = value && typeof value === 'object' ? String(value.value || '') : '';
|
|
748
|
+
const valTail = valStr.includes('.') ? valStr.slice(valStr.lastIndexOf('.') + 1) : valStr;
|
|
749
|
+
const isApprovalField = typeof valStr === 'string' && valStr.startsWith('ApprovalData.') && !/^\d+$/.test(valTail);
|
|
750
|
+
if (isApprovalField || rightType === 'formfield' || (value && typeof value === 'object' && String(value.value || '').startsWith('FormData.')))
|
|
751
|
+
conditionData.type = 'formField';
|
|
752
|
+
else if (rightType === 'custombyhander' || family === 'reference')
|
|
753
|
+
conditionData.type = 'custombyhander';
|
|
754
|
+
}
|
|
755
|
+
else if (isNative) {
|
|
756
|
+
const nativeMode = String((right && typeof right === 'object' ? (right.mode || right.conditionType || right.nativeType) : '') || { varfield: 'varField', filterval: 'filterVal' }[rightType] || '');
|
|
757
|
+
if (!nativeMode)
|
|
758
|
+
throw new Error('filterCondition native 右值必须提供 mode/conditionType/nativeType');
|
|
759
|
+
conditionData.type = nativeMode;
|
|
760
|
+
}
|
|
761
|
+
else if (rightType === 'system') {
|
|
762
|
+
conditionData.type = '';
|
|
763
|
+
}
|
|
764
|
+
else if (family === 'reference' || rightType === 'selectdata') {
|
|
765
|
+
conditionData.type = 'selectData';
|
|
766
|
+
}
|
|
767
|
+
else if (family === 'select' || family === 'boolean') {
|
|
768
|
+
conditionData.type = '';
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
if (!isNullary && isContext) {
|
|
772
|
+
const renderType = conditionData.type;
|
|
773
|
+
// esbAssign.wId 必须指向「当前节点」(filterInput 所属节点),不是上游 event 节点。
|
|
774
|
+
// 设计器用它对 orginFlowDatas 定位当前组件;指向 event 会导致打开动态赋值时右侧「暂无数据」。
|
|
775
|
+
let esbWid = String(meta && typeof meta === 'object' ? (meta._upstream_node_id || '') : '');
|
|
776
|
+
if (!esbWid && value && typeof value === 'object')
|
|
777
|
+
esbWid = String(value.source || '');
|
|
778
|
+
if (!esbWid && meta && typeof meta === 'object')
|
|
779
|
+
esbWid = String(meta._upstream_w_id || '');
|
|
780
|
+
if (!esbWid)
|
|
781
|
+
esbWid = timeStamp.slice(0, 13);
|
|
782
|
+
conditionData.isEsb = true;
|
|
783
|
+
conditionData.esbAssign = { wId: esbWid, textarea: false, withoutDftNum: true };
|
|
784
|
+
void renderType;
|
|
785
|
+
}
|
|
786
|
+
else if (!isNullary) {
|
|
787
|
+
conditionData.isEsb = false;
|
|
788
|
+
}
|
|
789
|
+
if (right && typeof right === 'object') {
|
|
790
|
+
for (const nativeKey of ['customSelect', 'filterValueType', 'matchType', 'changeTrigger']) {
|
|
791
|
+
if (nativeKey in right)
|
|
792
|
+
conditionData[nativeKey] = right[nativeKey];
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
const originBrowserType = String(fmeta.originBrowserType || (rawConfig && typeof rawConfig === 'object' ? rawConfig.originBrowserType : '') || (['select', 'reference'].includes(family) ? 'browser' : ''));
|
|
796
|
+
const item = {
|
|
797
|
+
isParent: false, fieldName: fieldId, mainField: true, module: '', subTableId: '',
|
|
798
|
+
parentNode: timeStamp + String(idx), type: 'condition', optionType: '',
|
|
799
|
+
compType, objId: String(fctx.objId || formId), id: fieldId, text: label,
|
|
800
|
+
conditions: conditionData, originBrowserType, fieldType,
|
|
801
|
+
key: timeStamp + String(idx + 1), multiSelect: String(Boolean(multiSelect)).toLowerCase(),
|
|
802
|
+
};
|
|
803
|
+
if (rawFieldType)
|
|
804
|
+
item.dbFieldType = rawFieldType;
|
|
805
|
+
datas.push(item);
|
|
806
|
+
});
|
|
807
|
+
return { isNewFilter: true, isParent: true, datas, parentNode: '', relationship: '1', key: timeStamp };
|
|
808
|
+
}
|
|
809
|
+
function buildFilterTree(result, value, meta, appId, componentType) {
|
|
810
|
+
rejectUnsupportedFilterModes(value);
|
|
811
|
+
let rootSource;
|
|
812
|
+
if (isFilterGroup(value))
|
|
813
|
+
rootSource = value;
|
|
814
|
+
else if (Array.isArray(value))
|
|
815
|
+
rootSource = { relationship: 'and', conditions: value };
|
|
816
|
+
else if (value && typeof value === 'object' && Array.isArray(value.conditions))
|
|
817
|
+
rootSource = value;
|
|
818
|
+
else
|
|
819
|
+
rootSource = { relationship: 'and', conditions: [value] };
|
|
820
|
+
const build = (source) => {
|
|
821
|
+
if (isFilterGroup(source)) {
|
|
822
|
+
return {
|
|
823
|
+
isNewFilter: true, isParent: true,
|
|
824
|
+
datas: filterGroupChildren(source).map(build),
|
|
825
|
+
parentNode: '', relationship: filterRelationship(source.relationship), key: '',
|
|
826
|
+
};
|
|
827
|
+
}
|
|
828
|
+
const compiled = buildFilterInput(result, [JSON.parse(JSON.stringify(source))], meta, appId, componentType, false);
|
|
829
|
+
if (compiled.datas.length !== 1)
|
|
830
|
+
throw new Error('filterCondition 叶子必须是单个有效条件');
|
|
831
|
+
return compiled.datas[0];
|
|
832
|
+
};
|
|
833
|
+
const tree = build(rootSource);
|
|
834
|
+
const baseKey = String(Date.now());
|
|
835
|
+
let sequence = 0;
|
|
836
|
+
const assignTreeIds = (node, parentKey = '', isRoot = false) => {
|
|
837
|
+
let key;
|
|
838
|
+
if (isRoot)
|
|
839
|
+
key = baseKey;
|
|
840
|
+
else {
|
|
841
|
+
sequence += 1;
|
|
842
|
+
key = `${baseKey}${sequence}`;
|
|
843
|
+
}
|
|
844
|
+
node.key = key;
|
|
845
|
+
node.parentNode = parentKey;
|
|
846
|
+
node.isNewFilter = true;
|
|
847
|
+
if (node.isParent) {
|
|
848
|
+
node.relationship = filterRelationship(node.relationship);
|
|
849
|
+
for (const child of node.datas || [])
|
|
850
|
+
assignTreeIds(child, key);
|
|
851
|
+
}
|
|
852
|
+
};
|
|
853
|
+
assignTreeIds(tree, '', true);
|
|
854
|
+
return tree;
|
|
855
|
+
}
|
|
856
|
+
// ── Condition 条件分支 ──────────────────────────────────────
|
|
857
|
+
const CONDITION_OPT_CODE_MAP = {
|
|
858
|
+
// ESB WfpRuleDesign getCustomData 的实际枚举:1/2/3/4 是大小比较,5/6 是等于/不等于。
|
|
859
|
+
eq: 5, '==': 5, '=': 5, '等于': 5,
|
|
860
|
+
neq: 6, '!=': 6, '<>': 6, '不等于': 6, ne: 6,
|
|
861
|
+
gt: 1, '>': 1, '大于': 1, lt: 3, '<': 3, '小于': 3,
|
|
862
|
+
gte: 2, '>=': 2, '大于等于': 2, lte: 4, '<=': 4, '小于等于': 4,
|
|
863
|
+
contains: 9, contain: 9, '包含': 9, notcontains: 10, notcontain: 10, '不包含': 10,
|
|
864
|
+
in: 11, '属于': 11, notin: 12, not_in: 12, '不属于': 12,
|
|
865
|
+
empty: 13, isnull: 13, '为空': 13, nempty: 14, isnotnull: 14, '不为空': 14,
|
|
866
|
+
};
|
|
867
|
+
const CONDITION_OPT_LABEL_MAP = {
|
|
868
|
+
1: '大于', 2: '大于等于', 3: '小于', 4: '小于等于', 5: '等于', 6: '不等于',
|
|
869
|
+
9: '包含', 10: '不包含', 11: '属于', 12: '不属于', 13: '为空', 14: '不为空',
|
|
870
|
+
23: '是', 24: '否',
|
|
871
|
+
};
|
|
872
|
+
const CONDITION_OPERATOR_CODES_BY_FAMILY = {
|
|
873
|
+
string: new Set([5, 6, 9, 10, 13, 14]),
|
|
874
|
+
number: new Set([1, 2, 3, 4, 5, 6, 13, 14]),
|
|
875
|
+
date: new Set([1, 2, 3, 4, 5, 6, 13, 14]),
|
|
876
|
+
datetime: new Set([1, 2, 3, 4, 5, 6, 13, 14]),
|
|
877
|
+
time: new Set([1, 2, 3, 4, 5, 6, 13, 14]),
|
|
878
|
+
bool: new Set([23, 24]),
|
|
879
|
+
browser: new Set([5, 6, 9, 10, 11, 12, 13, 14]),
|
|
880
|
+
list: new Set([5, 6, 11, 12, 13, 14]),
|
|
881
|
+
};
|
|
882
|
+
function conditionFieldShape(workflowId, fieldKey, fieldLabel) {
|
|
883
|
+
const fields = getWorkflowContextFields()[workflowId] || {};
|
|
884
|
+
const raw = fields[fieldKey] || fields[fieldLabel] || Object.values(fields).find((item) => String(item?.id || item?.paramId || '') === fieldKey);
|
|
885
|
+
const type = String(raw?.paramType || raw?.paramTypeString || raw?.componentKey || '').toLowerCase();
|
|
886
|
+
if (['int', 'integer', 'number', 'double', 'float', 'money', 'numbercomponent'].includes(type))
|
|
887
|
+
return { family: 'number', prefix: 'Number', formulaType: 'double' };
|
|
888
|
+
if (['datetime', 'datetimepicker', 'datetimesecondcomponent'].includes(type))
|
|
889
|
+
return { family: 'datetime', prefix: 'DateTime', formulaType: 'datetime' };
|
|
890
|
+
if (['date', 'datepicker', 'datecomponent'].includes(type))
|
|
891
|
+
return { family: 'date', prefix: 'Date', formulaType: 'date' };
|
|
892
|
+
if (['time', 'timepicker', 'timecomponent'].includes(type))
|
|
893
|
+
return { family: 'time', prefix: 'Time', formulaType: 'time' };
|
|
894
|
+
if (['bool', 'boolean', 'switch', 'checkbox'].includes(type))
|
|
895
|
+
return { family: 'bool', prefix: 'Bool', formulaType: 'bool' };
|
|
896
|
+
if (['employee', 'department', 'role', 'position', 'browser', 'browserbutton', 'relatebrowser'].includes(type))
|
|
897
|
+
return { family: 'browser', prefix: 'Browser', formulaType: 'string' };
|
|
898
|
+
if (['select', 'multiselect', 'radio', 'radiobox', 'checkboxgroup'].includes(type))
|
|
899
|
+
return { family: 'list', prefix: 'List', formulaType: 'json' };
|
|
900
|
+
if (Boolean(raw?.arrs) || ['list', 'json', 'array'].includes(type))
|
|
901
|
+
return { family: 'list', prefix: 'List', formulaType: 'json' };
|
|
902
|
+
return { family: 'string', prefix: 'String', formulaType: 'string' };
|
|
903
|
+
}
|
|
904
|
+
function conditionRelationCode(value) {
|
|
905
|
+
const relation = String(value ?? 'and').trim().toLowerCase();
|
|
906
|
+
return ['2', 'or', '||', '或'].includes(relation) ? 2 : 1;
|
|
907
|
+
}
|
|
908
|
+
function conditionItems(condition) {
|
|
909
|
+
const items = condition.conditions ?? condition.childrens ?? condition.rules ?? [];
|
|
910
|
+
return Array.isArray(items) ? items.filter((item) => Boolean(item && typeof item === 'object')) : [];
|
|
911
|
+
}
|
|
912
|
+
function conditionFormulaType(right, shape, sourceId) {
|
|
913
|
+
if (right?.formula && typeof right.formula === 'object')
|
|
914
|
+
return JSON.parse(JSON.stringify(right.formula));
|
|
915
|
+
const kind = String(right?.type || right?.kind || 'fixed').trim().toLowerCase();
|
|
916
|
+
const raw = right && typeof right === 'object' ? (right.paramKey ?? right.key ?? right.value ?? '') : right;
|
|
917
|
+
if (kind === 'fixed' || kind === 'constant' || kind === 'manual') {
|
|
918
|
+
if (['browser', 'list'].includes(shape.family)) {
|
|
919
|
+
throw new Error(`Condition ${shape.family} 类型固定右值必须提供平台回读 formula,不能伪造为文本`);
|
|
920
|
+
}
|
|
921
|
+
// ConditionRule 的固定右值不是普通组件的 AssignWrapper;后者无法被规则编辑器回填。
|
|
922
|
+
return {
|
|
923
|
+
formulaType: shape.formulaType,
|
|
924
|
+
name: String(raw),
|
|
925
|
+
businessId: genSfId(),
|
|
926
|
+
selectType: '-1',
|
|
927
|
+
id: genSfId(),
|
|
928
|
+
type: '1',
|
|
929
|
+
value: String(raw),
|
|
930
|
+
fieldType: shape.formulaType,
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
if (kind === 'system' || kind === 'system_variable') {
|
|
934
|
+
const bean = formulaSystemVar(String(raw));
|
|
935
|
+
bean.formulaType = shape.formulaType;
|
|
936
|
+
bean.fieldType = shape.formulaType;
|
|
937
|
+
return bean;
|
|
938
|
+
}
|
|
939
|
+
if (['context', 'dynamic', 'formfield', 'form_field'].includes(kind)) {
|
|
940
|
+
const key = String(raw || '').replace(/^(FormData|ApprovalData)\./, '');
|
|
941
|
+
if (!key)
|
|
942
|
+
throw new Error('Condition 动态右值必须提供 paramKey/key/value 或完整 formula');
|
|
943
|
+
const bean = formulaContext(String(right?.source || right?.comId || sourceId), key, {
|
|
944
|
+
name: String(right?.label || right?.name || key),
|
|
945
|
+
fieldType: shape.formulaType,
|
|
946
|
+
componentType: String(right?.componentType || right?.comType || 'ApproveTrigger'),
|
|
947
|
+
});
|
|
948
|
+
bean.businessId = String(right?.businessId || bean.businessId || '0');
|
|
949
|
+
return bean;
|
|
950
|
+
}
|
|
951
|
+
throw new Error(`Condition 右值 type='${kind}' 不支持;请使用 fixed/system/context 或提供完整 formula`);
|
|
952
|
+
}
|
|
953
|
+
export function hasConditionExpression(condition) {
|
|
954
|
+
if (!condition || typeof condition !== 'object')
|
|
955
|
+
return false;
|
|
956
|
+
const data = condition;
|
|
957
|
+
return Boolean(data.left && typeof data.left === 'object') || conditionItems(data).length > 0;
|
|
958
|
+
}
|
|
959
|
+
function buildSingleConditionDetail(condition, sourceId, meta = null) {
|
|
960
|
+
if (!condition || typeof condition !== 'object')
|
|
961
|
+
return {};
|
|
962
|
+
const left = condition.left || {};
|
|
963
|
+
const requestedFieldKey = String(left.key || left.value || '').trim();
|
|
964
|
+
const requestedLabel = String(left.label || left.name || requestedFieldKey || '').trim();
|
|
965
|
+
const operator = String(condition.operator || '').trim().toLowerCase();
|
|
966
|
+
const workflowId = meta && typeof meta === 'object' ? String(meta._workflow_id || '') : '';
|
|
967
|
+
// 条件计划允许使用完整 paramKey、paramName、真实字段 id 或界面显示名;统一回到
|
|
968
|
+
// workflow-context-fields 的原始字段,避免把 label/内部字段名拼成不存在的路径。
|
|
969
|
+
const contextFields = workflowId ? Object.values(getWorkflowContextFields()[workflowId] || {}) : [];
|
|
970
|
+
const rawField = contextFields.find((field) => {
|
|
971
|
+
if (!field || typeof field !== 'object')
|
|
972
|
+
return false;
|
|
973
|
+
return [field.paramKey, field.paramName, field.showName, field.id, field.paramId]
|
|
974
|
+
.some((candidate) => String(candidate ?? '') === requestedFieldKey || String(candidate ?? '') === requestedLabel);
|
|
975
|
+
}) || null;
|
|
976
|
+
const fieldKey = String(rawField?.paramKey || requestedFieldKey);
|
|
977
|
+
const fieldLabel = String(rawField?.showName || rawField?.paramName || requestedLabel || fieldKey);
|
|
978
|
+
const isEnquiryCount = ['count', 'response.count', 'Response.response.count'].includes(requestedFieldKey);
|
|
979
|
+
if (requestedFieldKey && !isEnquiryCount && workflowId) {
|
|
980
|
+
const wfFields = getWorkflowFieldIds()[workflowId] || {};
|
|
981
|
+
if (!rawField && Object.keys(wfFields).length && !(requestedFieldKey in wfFields) && !(requestedLabel in wfFields)) {
|
|
982
|
+
throw new Error(`Condition.left.key='${requestedFieldKey}' 未在流程 '${workflowId}' 的实时上下文中找到。请传完整 paramKey、字段显示名或 getComponentContext 返回的字段对象。`);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
const shape = conditionFieldShape(workflowId, fieldKey, fieldLabel);
|
|
986
|
+
const opt = CONDITION_OPT_CODE_MAP[operator];
|
|
987
|
+
if (!opt)
|
|
988
|
+
throw new Error(`Condition 操作符 '${condition.operator}' 不支持`);
|
|
989
|
+
if (!CONDITION_OPERATOR_CODES_BY_FAMILY[shape.family]?.has(opt)) {
|
|
990
|
+
throw new Error(`Condition 字段 '${fieldLabel}' 类型=${shape.family} 不支持操作 '${condition.operator}'`);
|
|
991
|
+
}
|
|
992
|
+
const optLabel = CONDITION_OPT_LABEL_MAP[opt] ?? '等于';
|
|
993
|
+
const needRight = !(opt === 13 || opt === 14);
|
|
994
|
+
const right = condition.right || {};
|
|
995
|
+
const rightValue = right.value ?? '';
|
|
996
|
+
const rightLabel = String(right.label || rightValue || '').trim();
|
|
997
|
+
const conditionCn = needRight ? `(${fieldLabel} ${optLabel} ${rightLabel})` : `(${fieldLabel} ${optLabel})`;
|
|
998
|
+
const cid = genSfId(), exprId = genSfId(), mapBase = genSfId(), mapIdVal = genSfId();
|
|
999
|
+
const ebId = genSfId(), baseId = genSfId(), dvId = genSfId(), ev1 = genSfId(), ev2 = genSfId();
|
|
1000
|
+
const fieldId = rawField ? String(rawField.id || rawField.paramId || '') : (workflowId ? workflowFieldId(workflowId, requestedFieldKey) : '');
|
|
1001
|
+
let paramKeyId, valueId, comType;
|
|
1002
|
+
if (isEnquiryCount) {
|
|
1003
|
+
paramKeyId = 'response.count';
|
|
1004
|
+
valueId = 'response.count';
|
|
1005
|
+
comType = 'EnquiryForm';
|
|
1006
|
+
}
|
|
1007
|
+
else if (rawField) {
|
|
1008
|
+
paramKeyId = String(rawField.paramKey);
|
|
1009
|
+
valueId = `ApprovalData.${paramKeyId}`;
|
|
1010
|
+
comType = 'ApproveTrigger';
|
|
1011
|
+
}
|
|
1012
|
+
else if (fieldId && workflowId && fieldId !== fieldKey) {
|
|
1013
|
+
paramKeyId = `${workflowId}.${fieldId}`;
|
|
1014
|
+
valueId = `FormData.${workflowId}.${fieldId}`;
|
|
1015
|
+
comType = 'ApproveTrigger';
|
|
1016
|
+
}
|
|
1017
|
+
else {
|
|
1018
|
+
paramKeyId = fieldKey;
|
|
1019
|
+
valueId = fieldKey ? `FormData.${fieldKey}` : '';
|
|
1020
|
+
comType = 'EbGetDataById';
|
|
1021
|
+
}
|
|
1022
|
+
const upstreamWId = meta && typeof meta === 'object' ? String(meta._upstream_w_id || '') : '';
|
|
1023
|
+
const contextWId = isEnquiryCount ? String(sourceId) : (upstreamWId || String(sourceId));
|
|
1024
|
+
// customFieldType.id/businessId 是条件编辑器中“本次选择上下文”的 FormulaBean
|
|
1025
|
+
// 实例 ID,不是业务字段 ID。真实字段身份只由 config.paramKey 承载。若把两者
|
|
1026
|
+
// 写成字段 id(例如 17),saveCondition 会返回 haveData=false,仅保留空骨架,
|
|
1027
|
+
// 用户再次保存条件时就会清空。手工创建的回读也使用独立的分布式实例 ID。
|
|
1028
|
+
const customFieldId = genSfId();
|
|
1029
|
+
const customFieldBiz = genSfId();
|
|
1030
|
+
// 流程字段需保留“流程 ID.字段名”的上下文显示路径,规则编辑器才能定位来源。
|
|
1031
|
+
const contextDisplayName = rawField && workflowId ? `${workflowId}.${fieldLabel}` : fieldLabel;
|
|
1032
|
+
const leftOperand = {
|
|
1033
|
+
expressionBaseId: baseId, [`${shape.prefix}CompareOptionLeft`]: opt, dataValueId: dvId,
|
|
1034
|
+
elementValue2Id: ev2, elementValue1Id: ev1, selectType: 97,
|
|
1035
|
+
customFieldType: {
|
|
1036
|
+
paramType: shape.formulaType, formulaType: shape.formulaType, name: fieldLabel, businessId: customFieldBiz,
|
|
1037
|
+
selectType: '-1', id: customFieldId, source: contextWId, type: '3', value: valueId,
|
|
1038
|
+
config: {
|
|
1039
|
+
paramKey: paramKeyId, isMultCom: false, comType, parentComId: '0',
|
|
1040
|
+
fieldInfo: { paramKey: paramKeyId, tablePrimaryKey: rawField ? 'ApprovalData' : 'FormData' },
|
|
1041
|
+
tableName: rawField ? '流程数据' : '表单数据', paramType: shape.formulaType, parentName: contextDisplayName, multName: '', multKey: '',
|
|
1042
|
+
multTypeObj: { allName: contextDisplayName, currentName: contextDisplayName, currentParamKey: valueId, allParamKey: valueId },
|
|
1043
|
+
comId: contextWId, newParentName: contextDisplayName,
|
|
1044
|
+
},
|
|
1045
|
+
fieldType: shape.formulaType,
|
|
1046
|
+
},
|
|
1047
|
+
};
|
|
1048
|
+
if (needRight) {
|
|
1049
|
+
leftOperand[`${shape.prefix}TextValueLeft`] = conditionFormulaType(right, shape, contextWId);
|
|
1050
|
+
}
|
|
1051
|
+
const dataJson = JSON.stringify({
|
|
1052
|
+
sourceId: sourceId ? String(sourceId) : '-1',
|
|
1053
|
+
expressionId: exprId, mapBaseId: mapBase, conditionId: cid,
|
|
1054
|
+
// saveCondition 自身会为同一层的规则生成 AND/OR 表达式组。
|
|
1055
|
+
// 单条规则若先在这里包一层 group,会在服务端变成“根 → AND → AND → 叶子”,
|
|
1056
|
+
// 条件编辑器打开后显示为多余嵌套。直接提交叶子,与手工新建单条件一致。
|
|
1057
|
+
childrens: [leftOperand],
|
|
1058
|
+
mapId: mapIdVal, source: 8, relation: 1,
|
|
1059
|
+
});
|
|
1060
|
+
return {
|
|
1061
|
+
conditionId: cid, conditionCn, mapBaseId: mapBase, mapId: mapIdVal,
|
|
1062
|
+
sourceIds: sourceId ? [sourceId] : [],
|
|
1063
|
+
conditionDataJson: dataJson,
|
|
1064
|
+
};
|
|
1065
|
+
}
|
|
1066
|
+
function buildConditionExpressionNodes(condition, sourceId, meta) {
|
|
1067
|
+
const items = conditionItems(condition);
|
|
1068
|
+
if (items.length > 0) {
|
|
1069
|
+
const relation = conditionRelationCode(condition.relationship ?? condition.relation);
|
|
1070
|
+
const built = items.map((item) => buildConditionExpressionNodes(item, sourceId, meta));
|
|
1071
|
+
return {
|
|
1072
|
+
nodes: [{ expressionId: genSfId(), relation, childrens: built.flatMap((item) => item.nodes) }],
|
|
1073
|
+
text: `(${built.map((item) => item.text).join(relation === 2 ? ' 或 ' : ' 且 ')})`,
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
if (!condition.left || typeof condition.left !== 'object') {
|
|
1077
|
+
throw new Error('Condition 规则组中的每个叶子都必须包含 left 字段');
|
|
1078
|
+
}
|
|
1079
|
+
const detail = buildSingleConditionDetail(condition, sourceId, meta);
|
|
1080
|
+
const tree = JSON.parse(String(detail.conditionDataJson || '{}'));
|
|
1081
|
+
const nodes = Array.isArray(tree.childrens) ? tree.childrens : [];
|
|
1082
|
+
if (!nodes.length)
|
|
1083
|
+
throw new Error('Condition 叶子未生成 ExpressionBean');
|
|
1084
|
+
return { nodes, text: String(detail.conditionCn || '') };
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* 编译 ESB Condition 的 ExpressionBean。
|
|
1088
|
+
* 支持旧版单叶子 {left, operator, right},以及 {relationship, conditions:[...]} 规则组。
|
|
1089
|
+
*/
|
|
1090
|
+
export function buildConditionDetail(condition, sourceId, meta = null) {
|
|
1091
|
+
if (!condition || typeof condition !== 'object')
|
|
1092
|
+
return {};
|
|
1093
|
+
const built = buildConditionExpressionNodes(condition, sourceId, meta);
|
|
1094
|
+
const relation = conditionRelationCode(condition.relationship ?? condition.relation);
|
|
1095
|
+
const cid = genSfId(), exprId = genSfId(), mapBase = genSfId(), mapIdVal = genSfId();
|
|
1096
|
+
const dataJson = JSON.stringify({
|
|
1097
|
+
sourceId: sourceId ? String(sourceId) : '-1',
|
|
1098
|
+
expressionId: exprId, mapBaseId: mapBase, conditionId: cid,
|
|
1099
|
+
childrens: built.nodes,
|
|
1100
|
+
mapId: mapIdVal, source: 8, relation,
|
|
1101
|
+
});
|
|
1102
|
+
return {
|
|
1103
|
+
conditionId: cid, conditionCn: built.text, mapBaseId: mapBase, mapId: mapIdVal,
|
|
1104
|
+
sourceIds: sourceId ? [sourceId] : [], conditionDataJson: dataJson,
|
|
1105
|
+
};
|
|
1106
|
+
}
|
|
1107
|
+
// ── _build_setting_detail ───────────────────────────────────
|
|
1108
|
+
export function buildSettingDetail(nodeData, detailItems, meta, appId, eventId, nodeType) {
|
|
1109
|
+
if (!Array.isArray(detailItems))
|
|
1110
|
+
return;
|
|
1111
|
+
const detailOut = [];
|
|
1112
|
+
for (const item of detailItems) {
|
|
1113
|
+
if (!item || typeof item !== 'object' || !item.detailTableId)
|
|
1114
|
+
continue;
|
|
1115
|
+
const ele = { detailTableId: String(item.detailTableId) };
|
|
1116
|
+
if (item.updateFieldCondition && typeof item.updateFieldCondition === 'object') {
|
|
1117
|
+
ele.updateFieldCondition = buildUpdateFieldCondition(item.updateFieldCondition, { meta, appId, eventId: String(eventId), componentType: nodeType });
|
|
1118
|
+
}
|
|
1119
|
+
else {
|
|
1120
|
+
ele.updateFieldCondition = { updateField: [] };
|
|
1121
|
+
}
|
|
1122
|
+
const eleData = {};
|
|
1123
|
+
// 明细项依据值:引用整个明细表,source=event 节点 id, frontId=明细表 id。
|
|
1124
|
+
if (item.basisValue && typeof item.basisValue === 'object') {
|
|
1125
|
+
const bvVal = item.basisValue;
|
|
1126
|
+
const bvKey = String(bvVal.paramKey || bvVal.key || '').trim();
|
|
1127
|
+
const bvLabel = String(bvVal.label || bvVal.name || bvKey);
|
|
1128
|
+
if (bvKey) {
|
|
1129
|
+
const bvType = resolveSourceFieldType(bvKey, meta);
|
|
1130
|
+
let prefix = '';
|
|
1131
|
+
if (meta && typeof meta === 'object') {
|
|
1132
|
+
prefix = String(meta._upstream_workflow_name || '');
|
|
1133
|
+
if (!prefix)
|
|
1134
|
+
prefix = String(meta._upstream_form_name || '');
|
|
1135
|
+
}
|
|
1136
|
+
const parentName = prefix ? `${prefix}.${bvLabel}[]` : `${bvLabel}[]`;
|
|
1137
|
+
const bvSubformId = bvKey.includes('[]') ? bvKey.split('[]')[0].includes('.') ? bvKey.split('[]')[0].slice(bvKey.split('[]')[0].lastIndexOf('.') + 1) : bvKey : bvKey;
|
|
1138
|
+
ele.basisValue = {
|
|
1139
|
+
frontId: bvSubformId,
|
|
1140
|
+
formulaType: bvType,
|
|
1141
|
+
name: bvLabel,
|
|
1142
|
+
id: genSfId(),
|
|
1143
|
+
source: String(eventId),
|
|
1144
|
+
type: '3',
|
|
1145
|
+
value: `FormData.${bvKey}`,
|
|
1146
|
+
childs: [],
|
|
1147
|
+
config: {
|
|
1148
|
+
paramKey: bvKey,
|
|
1149
|
+
paramType: bvType,
|
|
1150
|
+
isMultCom: false,
|
|
1151
|
+
switchType: 'assign',
|
|
1152
|
+
parentName,
|
|
1153
|
+
multName: '',
|
|
1154
|
+
multKey: '',
|
|
1155
|
+
multTypeObj: {
|
|
1156
|
+
allName: parentName, currentName: parentName,
|
|
1157
|
+
currentParamKey: `FormData.${bvKey}`, allParamKey: `FormData.${bvKey}`,
|
|
1158
|
+
},
|
|
1159
|
+
comId: String(eventId),
|
|
1160
|
+
comType: 'ApproveTrigger',
|
|
1161
|
+
newParentName: parentName,
|
|
1162
|
+
fieldInfo: { paramKey: bvKey, tablePrimaryKey: 'FormData' },
|
|
1163
|
+
},
|
|
1164
|
+
parentId: '0',
|
|
1165
|
+
};
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
const mapping = item.mapping || {};
|
|
1169
|
+
const constants = item.constants || {};
|
|
1170
|
+
if (mapping && typeof mapping === 'object' && !Array.isArray(mapping)) {
|
|
1171
|
+
for (const [sourceKey, targetFieldIdRaw] of Object.entries(mapping)) {
|
|
1172
|
+
const targetFieldId = targetFieldIdRaw;
|
|
1173
|
+
let operate = 'OPERATE_EQUAL';
|
|
1174
|
+
let assignment;
|
|
1175
|
+
if (targetFieldId && typeof targetFieldId === 'object' && !Array.isArray(targetFieldId)) {
|
|
1176
|
+
let raw = String(targetFieldId.target || targetFieldId.fieldId || '');
|
|
1177
|
+
if (!raw)
|
|
1178
|
+
throw new Error('detail.mapping 依据值下级值缺少目标字段 id: 应传 {"target":"<目标明细字段id>", "paramKey":"<源paramKey>", ...}');
|
|
1179
|
+
if (raw.startsWith('+')) {
|
|
1180
|
+
operate = 'OPERATE_PLUS';
|
|
1181
|
+
raw = raw.slice(1);
|
|
1182
|
+
}
|
|
1183
|
+
else if (raw.startsWith('-')) {
|
|
1184
|
+
operate = 'OPERATE_MINUS';
|
|
1185
|
+
raw = raw.slice(1);
|
|
1186
|
+
}
|
|
1187
|
+
const refKey = String(targetFieldId.paramKey || sourceKey);
|
|
1188
|
+
const refLabel = String(targetFieldId.label || sourceKey);
|
|
1189
|
+
const refDetail = String(targetFieldId.detailLabel || '');
|
|
1190
|
+
assignment = { kind: 'context', paramKey: refKey, label: refLabel };
|
|
1191
|
+
if (refDetail)
|
|
1192
|
+
assignment.detailLabel = refDetail;
|
|
1193
|
+
eleData[raw] = buildSettingEntry(raw, assignment, 'Text', meta, appId, eventId, operate, nodeType, true, '');
|
|
1194
|
+
}
|
|
1195
|
+
else {
|
|
1196
|
+
let raw = String(targetFieldId);
|
|
1197
|
+
if (raw.startsWith('+')) {
|
|
1198
|
+
operate = 'OPERATE_PLUS';
|
|
1199
|
+
raw = raw.slice(1);
|
|
1200
|
+
}
|
|
1201
|
+
else if (raw.startsWith('-')) {
|
|
1202
|
+
operate = 'OPERATE_MINUS';
|
|
1203
|
+
raw = raw.slice(1);
|
|
1204
|
+
}
|
|
1205
|
+
assignment = { kind: 'context', paramKey: String(sourceKey), label: resolveSourceFieldLabel(String(sourceKey), meta, String(sourceKey)) };
|
|
1206
|
+
eleData[raw] = buildSettingEntry(raw, assignment, 'Text', meta, appId, eventId, operate, nodeType, true, '');
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
if (constants && typeof constants === 'object' && !Array.isArray(constants)) {
|
|
1211
|
+
for (const [targetFieldIdRaw, valueRaw] of Object.entries(constants)) {
|
|
1212
|
+
const targetFieldId = String(targetFieldIdRaw);
|
|
1213
|
+
const value = valueRaw;
|
|
1214
|
+
const [assignment, ft] = normalizeConstantAssignment(value, 'Text');
|
|
1215
|
+
eleData[targetFieldId] = buildSettingEntry(targetFieldId, assignment, ft, meta, appId, eventId, 'OPERATE_EQUAL', nodeType, true, '');
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
// detail 自动按名补全
|
|
1219
|
+
const targetFormId = String((nodeData.targetForm || {}).id || '');
|
|
1220
|
+
autoFillDetailMapping(eleData, item, targetFormId, meta, appId, eventId, nodeType);
|
|
1221
|
+
ele.data = eleData;
|
|
1222
|
+
if (item.deleteFields)
|
|
1223
|
+
ele.deleteFields = item.deleteFields;
|
|
1224
|
+
if (item.operateType)
|
|
1225
|
+
ele.operateType = item.operateType;
|
|
1226
|
+
else
|
|
1227
|
+
ele.operateType = 'insert';
|
|
1228
|
+
if (item.updateFieldCondition && typeof item.updateFieldCondition === 'object')
|
|
1229
|
+
ele.updateFieldCondition = item.updateFieldCondition;
|
|
1230
|
+
detailOut.push(ele);
|
|
1231
|
+
}
|
|
1232
|
+
if (detailOut.length)
|
|
1233
|
+
nodeData.setting.detail = detailOut;
|
|
1234
|
+
}
|
|
1235
|
+
export function autoFillDetailMapping(eleData, item, targetFormId, meta, appId, eventId, nodeType) {
|
|
1236
|
+
if (!item || typeof item !== 'object' || !item.detailTableId)
|
|
1237
|
+
return;
|
|
1238
|
+
const bvVal = item.basisValue;
|
|
1239
|
+
if (!bvVal || typeof bvVal !== 'object')
|
|
1240
|
+
return;
|
|
1241
|
+
const bvKey = String(bvVal.paramKey || bvVal.key || '').trim();
|
|
1242
|
+
const bvLabel = String(bvVal.label || bvVal.name || '');
|
|
1243
|
+
if (!bvKey || !bvKey.includes('[]'))
|
|
1244
|
+
return;
|
|
1245
|
+
const wfId = String(meta._workflow_id || '');
|
|
1246
|
+
const subformId = bvKey.split('[]')[0].includes('.') ? bvKey.split('[]')[0].slice(bvKey.split('[]')[0].lastIndexOf('.') + 1) : bvKey.split('[]')[0];
|
|
1247
|
+
const targetFields = targetFormId ? (getTargetDetailFields()[String(targetFormId)] || {})[String(item.detailTableId)] || {} : {};
|
|
1248
|
+
const sourceFields = getWorkflowDetailFields()[wfId]?.[subformId] || {};
|
|
1249
|
+
if (Object.keys(targetFields).length === 0 || Object.keys(sourceFields).length === 0)
|
|
1250
|
+
return;
|
|
1251
|
+
for (const [tid, tmetaRaw] of Object.entries(targetFields)) {
|
|
1252
|
+
const tmeta = tmetaRaw;
|
|
1253
|
+
const tidS = String(tid);
|
|
1254
|
+
if (tidS in eleData)
|
|
1255
|
+
continue;
|
|
1256
|
+
const tname = String(tmeta.name || tmeta.showName || '');
|
|
1257
|
+
if (!tname || !(tname in sourceFields))
|
|
1258
|
+
continue;
|
|
1259
|
+
const srcPk = sourceFields[tname];
|
|
1260
|
+
const assignment = { kind: 'context', paramKey: srcPk, label: tname };
|
|
1261
|
+
if (bvLabel)
|
|
1262
|
+
assignment.detailLabel = bvLabel;
|
|
1263
|
+
eleData[tidS] = buildSettingEntry(tidS, assignment, String(tmeta.componentKey || tmeta.type || 'Text'), meta, appId, eventId, 'OPERATE_EQUAL', nodeType, true, '');
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
// ── convert_node ────────────────────────────────────────────
|
|
1267
|
+
export function convertNode(draftAction, isEvent = false, meta = null, appId = '', actionIndex = 0, eventNodeId = '', eventName = '', previousNodeId = '0', lenient = false) {
|
|
1268
|
+
const nodeType = draftAction.type;
|
|
1269
|
+
const comp = get(nodeType) || {};
|
|
1270
|
+
const display = comp.display || {};
|
|
1271
|
+
const rawId = draftAction.id;
|
|
1272
|
+
let nid = genSfId();
|
|
1273
|
+
if (rawId !== undefined && rawId !== null) {
|
|
1274
|
+
const parsed = Number(rawId);
|
|
1275
|
+
if (Number.isFinite(parsed))
|
|
1276
|
+
nid = String(parsed);
|
|
1277
|
+
}
|
|
1278
|
+
const nidStr = String(nid);
|
|
1279
|
+
// 当前节点 id 供 filterInput 的 esbAssign.wId 使用(设计器用其定位当前组件)。
|
|
1280
|
+
if (meta && typeof meta === 'object')
|
|
1281
|
+
meta._upstream_node_id = nidStr;
|
|
1282
|
+
const ctx = { meta: meta || {}, appId, actionIndex, eventNodeId: eventNodeId || nidStr, eventName, lenient, compileGeneric: (p, t, c) => compileComponentData(p, t, c, true), buildFilterInput, buildConditionDetail };
|
|
1283
|
+
let node = {
|
|
1284
|
+
id: nidStr, wId: nidStr,
|
|
1285
|
+
name: draftAction.name ?? display.componentName ?? nodeType,
|
|
1286
|
+
type: nodeType,
|
|
1287
|
+
attr: { icon: display.icon ?? 'Icon-default' },
|
|
1288
|
+
data: compileComponentData(draftAction.params || {}, nodeType, ctx),
|
|
1289
|
+
parentId: '0',
|
|
1290
|
+
};
|
|
1291
|
+
const nodeData = node.data || {};
|
|
1292
|
+
const pendingMapping = nodeData._pending_mapping;
|
|
1293
|
+
delete nodeData._pending_mapping;
|
|
1294
|
+
const pendingConstants = nodeData._pending_constants;
|
|
1295
|
+
delete nodeData._pending_constants;
|
|
1296
|
+
const pendingFormula = nodeData._pending_formula;
|
|
1297
|
+
delete nodeData._pending_formula;
|
|
1298
|
+
let pendingDetail = nodeData._pending_detail;
|
|
1299
|
+
delete nodeData._pending_detail;
|
|
1300
|
+
const formDataPayload = comp.formDataPayload;
|
|
1301
|
+
if (formDataPayload && typeof formDataPayload === 'object' && (pendingMapping || pendingConstants || pendingFormula || pendingDetail)) {
|
|
1302
|
+
// ApproveCreate 新建流程:字段映射进 formData.main/detail(BPM 流程表单字段)。
|
|
1303
|
+
fillSetting(nodeData, undefined, pendingMapping, pendingConstants, pendingFormula, meta || {}, appId, eventNodeId || nidStr, eventName, nodeType);
|
|
1304
|
+
if (pendingDetail && typeof nodeData.setting === 'object') {
|
|
1305
|
+
buildSettingDetail(nodeData, pendingDetail, meta || {}, appId, eventNodeId || nidStr, nodeType);
|
|
1306
|
+
}
|
|
1307
|
+
const setting = nodeData.setting;
|
|
1308
|
+
delete nodeData.setting;
|
|
1309
|
+
const main = (setting || {}).main || {};
|
|
1310
|
+
const detailOut = (setting || {}).detail || [];
|
|
1311
|
+
nodeData.formData = { main, detail: detailOut, dataDrWithCalc: false };
|
|
1312
|
+
const fieldsMetaKey = String(formDataPayload.fieldsMetaKey || '_bizFields');
|
|
1313
|
+
let bizFields = meta && typeof meta === 'object' ? (meta[fieldsMetaKey] || {}) : {};
|
|
1314
|
+
if (!bizFields || Object.keys(bizFields).length === 0)
|
|
1315
|
+
bizFields = draftAction.params?.[fieldsMetaKey] || {};
|
|
1316
|
+
nodeData.fields = {
|
|
1317
|
+
main: bizFields && typeof bizFields === 'object' ? (bizFields.main || []) : [],
|
|
1318
|
+
detail: bizFields && typeof bizFields === 'object' ? (bizFields.detail || []) : [],
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1321
|
+
else if (pendingDetail && !(pendingMapping || pendingConstants || pendingFormula)) {
|
|
1322
|
+
// 只有明细表赋值(无主表 mapping/constants):先 _fill_setting 生成空 main + setting,再放回 detail。
|
|
1323
|
+
fillSetting(nodeData, undefined, undefined, undefined, undefined, meta || {}, appId, eventNodeId || nidStr, eventName, nodeType);
|
|
1324
|
+
nodeData._pending_detail = pendingDetail;
|
|
1325
|
+
nodeData.formDataId = genSfId();
|
|
1326
|
+
}
|
|
1327
|
+
else if (formDataPayload && typeof formDataPayload === 'object') {
|
|
1328
|
+
// 声明 formDataPayload 的组件即使没有字段映射,也显式携带表单数据容器。
|
|
1329
|
+
nodeData.formData ??= { main: {}, detail: [], dataDrWithCalc: false };
|
|
1330
|
+
nodeData.fields ??= { main: [], detail: [] };
|
|
1331
|
+
nodeData.formDataId ??= genSfId();
|
|
1332
|
+
}
|
|
1333
|
+
else if ((pendingMapping || pendingConstants || pendingFormula) && !('setting' in nodeData)) {
|
|
1334
|
+
let m = { ...(meta || {}) };
|
|
1335
|
+
const tf = nodeData.targetForm || {};
|
|
1336
|
+
if (tf.text || tf.name)
|
|
1337
|
+
m._upstream_form_name = tf.text || tf.name;
|
|
1338
|
+
if (tf.id)
|
|
1339
|
+
m._upstream_table_id = String(tf.id);
|
|
1340
|
+
if (eventName)
|
|
1341
|
+
m._upstream_name = eventName;
|
|
1342
|
+
if (nodeData.workflowId)
|
|
1343
|
+
m._workflow_id = String(nodeData.workflowId);
|
|
1344
|
+
if (pendingDetail)
|
|
1345
|
+
nodeData._pending_detail = pendingDetail;
|
|
1346
|
+
fillSetting(nodeData, undefined, pendingMapping, pendingConstants, pendingFormula, m, appId, eventNodeId || nidStr, eventName, nodeType);
|
|
1347
|
+
}
|
|
1348
|
+
const pendingBasis = nodeData._pending_basis;
|
|
1349
|
+
delete nodeData._pending_basis;
|
|
1350
|
+
if (pendingBasis && typeof nodeData.setting === 'object' && nodeData.setting) {
|
|
1351
|
+
Object.assign(nodeData.setting, pendingBasis);
|
|
1352
|
+
}
|
|
1353
|
+
// 若既有旧 updates(-setting_main)又有新 mapping/constants,合并到已有 main。
|
|
1354
|
+
// 对齐 Python 版 convert_node 的二次合并逻辑(该分支不传 field_type,会用默认 "Text" 覆盖)。
|
|
1355
|
+
const assignmentMode = comp.assignmentContextMode || '';
|
|
1356
|
+
if ((pendingMapping || pendingConstants) && typeof nodeData.setting === 'object' && nodeData.setting) {
|
|
1357
|
+
const main = nodeData.setting.main || {};
|
|
1358
|
+
if (pendingMapping && typeof pendingMapping === 'object') {
|
|
1359
|
+
for (const [sourceKey, targetFieldIdRaw] of Object.entries(pendingMapping)) {
|
|
1360
|
+
const targetFieldId = targetFieldIdRaw;
|
|
1361
|
+
if (targetFieldId && typeof targetFieldId === 'object')
|
|
1362
|
+
continue;
|
|
1363
|
+
let raw = String(targetFieldId);
|
|
1364
|
+
let operate = 'OPERATE_EQUAL';
|
|
1365
|
+
if (raw.startsWith('+')) {
|
|
1366
|
+
operate = 'OPERATE_PLUS';
|
|
1367
|
+
raw = raw.slice(1);
|
|
1368
|
+
}
|
|
1369
|
+
else if (raw.startsWith('-')) {
|
|
1370
|
+
operate = 'OPERATE_MINUS';
|
|
1371
|
+
raw = raw.slice(1);
|
|
1372
|
+
}
|
|
1373
|
+
main[raw] = buildSettingEntry(raw, { kind: 'context', paramKey: String(sourceKey), label: String(sourceKey) }, 'Text', meta || {}, appId, eventNodeId || nidStr, operate, nodeType, false, assignmentMode);
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
if (pendingConstants && typeof pendingConstants === 'object') {
|
|
1377
|
+
for (const [targetFieldIdRaw, valueRaw] of Object.entries(pendingConstants)) {
|
|
1378
|
+
const targetFieldId = String(targetFieldIdRaw);
|
|
1379
|
+
const value = valueRaw;
|
|
1380
|
+
let operateC = 'OPERATE_EQUAL';
|
|
1381
|
+
let rawV = value;
|
|
1382
|
+
if (typeof value === 'string' && value.length > 1 && (value[0] === '+' || value[0] === '-')) {
|
|
1383
|
+
operateC = value[0] === '+' ? 'OPERATE_PLUS' : 'OPERATE_MINUS';
|
|
1384
|
+
rawV = value.slice(1);
|
|
1385
|
+
}
|
|
1386
|
+
const targetFieldMeta = lookupTargetFieldMeta(targetFieldId, nodeData);
|
|
1387
|
+
rawV = resolveEnumConstant(rawV, targetFieldMeta);
|
|
1388
|
+
const [assignment, ft] = normalizeConstantAssignment(rawV, 'Text');
|
|
1389
|
+
const targetFieldType = String(targetFieldMeta?.componentKey || targetFieldMeta?.type || ft);
|
|
1390
|
+
main[targetFieldId] = buildSettingEntry(targetFieldId, assignment, targetFieldType, meta || {}, appId, eventNodeId || nidStr, operateC, nodeType, false, assignmentMode);
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
nodeData.setting.main = main;
|
|
1394
|
+
nodeData.setting.opType = nodeData.setting.opType ?? 'insert';
|
|
1395
|
+
}
|
|
1396
|
+
pendingDetail = nodeData._pending_detail;
|
|
1397
|
+
delete nodeData._pending_detail;
|
|
1398
|
+
if (pendingDetail && Array.isArray(pendingDetail) && pendingDetail.length && typeof nodeData.setting === 'object') {
|
|
1399
|
+
buildSettingDetail(nodeData, pendingDetail, meta || {}, appId, eventNodeId || nidStr, nodeType);
|
|
1400
|
+
}
|
|
1401
|
+
if (isEvent) {
|
|
1402
|
+
node.triggerType = comp.triggerType ?? 'WorkflowTrigger';
|
|
1403
|
+
node.triggerTypeName = comp.triggerTypeName ?? (nodeType === 'ApproveTrigger' ? '流程事件触发' : nodeType);
|
|
1404
|
+
node.costTime = 0;
|
|
1405
|
+
if (display.iconColor)
|
|
1406
|
+
node.attr.iconColor = display.iconColor;
|
|
1407
|
+
const nd = node.data || {};
|
|
1408
|
+
for (const [key, value] of Object.entries(comp.nodeDataDefaults || {})) {
|
|
1409
|
+
nd[key] ??= JSON.parse(JSON.stringify(value));
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
else {
|
|
1413
|
+
node.componentId = nidStr;
|
|
1414
|
+
// 首节点(previousNodeId=event)通常不写 sources,平台对 ActionEb 等数据/动作组件自动接 event;
|
|
1415
|
+
// 但 EnquiryForm 查询组件不适用该约定——漏 sources 会被平台判定为「起始执行组件」,
|
|
1416
|
+
// 报「有两个起始执行组件」(真机验证 2026-08-27,sjrdemo 环境)。
|
|
1417
|
+
const needsEventSource = nodeType === 'EnquiryForm' && ['', '0', String(eventNodeId)].includes(String(previousNodeId));
|
|
1418
|
+
if (!['', '0', String(eventNodeId)].includes(String(previousNodeId)) || needsEventSource) {
|
|
1419
|
+
node.sources = [{ wId: needsEventSource ? String(eventNodeId) : String(previousNodeId) }];
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
// 设计器通过“添加操作”创建节点时,除平台执行 DTO 外还会保留组件目录项。
|
|
1423
|
+
// 这套前端节点壳(尤其是 MultipleExecution 的 originId/options)决定容器
|
|
1424
|
+
// 内部编辑能否被前端 Store 正确回写;只发 componentId 的后端简化节点会
|
|
1425
|
+
// 造成循环内条件保存后显示为空。目录由运行时接口读取,避免租户硬编码。
|
|
1426
|
+
const catalogOption = !isEvent && meta && typeof meta === 'object'
|
|
1427
|
+
? (meta._componentOptions || {})[nodeType]
|
|
1428
|
+
: undefined;
|
|
1429
|
+
if (catalogOption && typeof catalogOption === 'object') {
|
|
1430
|
+
const option = JSON.parse(JSON.stringify(catalogOption));
|
|
1431
|
+
option.content ??= option.actionName || option.eventName || '';
|
|
1432
|
+
node.nodeType = nodeType === 'MultipleExecution' ? 'MultipleExecution' : 'Normal';
|
|
1433
|
+
node.comType = nodeType;
|
|
1434
|
+
node.previousId = String(previousNodeId || '0');
|
|
1435
|
+
node.isAdd = true;
|
|
1436
|
+
node.isLock = false;
|
|
1437
|
+
node.ignoreFlowCheck = true;
|
|
1438
|
+
node.originId = String(option.id || '');
|
|
1439
|
+
node.options = option;
|
|
1440
|
+
node.componentDesc = String(option.des || option.componentDesc || node.name || '');
|
|
1441
|
+
node.componentDescLabel = option.componentDescLabel;
|
|
1442
|
+
node.componentName = String(option.eventName || option.actionName || option.componentName || node.name || '');
|
|
1443
|
+
node.componentNameLabel = option.componentNameLabel;
|
|
1444
|
+
node.name = String(option.actionName || option.eventName || node.name || nodeType);
|
|
1445
|
+
node.nameMultilang = node.name;
|
|
1446
|
+
node.attr = { ...node.attr, ...(option.icon ? { icon: option.icon } : {}) };
|
|
1447
|
+
delete node.componentId;
|
|
1448
|
+
delete node.sources;
|
|
1449
|
+
}
|
|
1450
|
+
const defaultPerson = comp.defaultPerson;
|
|
1451
|
+
if (defaultPerson && typeof defaultPerson === 'object' && !isEvent) {
|
|
1452
|
+
const data = node.data || {};
|
|
1453
|
+
if (!('person' in data)) {
|
|
1454
|
+
data.person = buildPersonFormula(defaultPerson, meta || {}, appId, false, Boolean(defaultPerson.direct));
|
|
1455
|
+
node.data = data;
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
// 组件画布节点后处理(如 SendMessage 的 person/shareList)
|
|
1459
|
+
const postNode = getNodePost(nodeType);
|
|
1460
|
+
if (postNode) {
|
|
1461
|
+
node = postNode(node, { draftAction, meta: meta || {}, appId, eventNodeId, isEvent });
|
|
1462
|
+
}
|
|
1463
|
+
return node;
|
|
1464
|
+
}
|
|
1465
|
+
// ── convert_condition ───────────────────────────────────────
|
|
1466
|
+
export function convertCondition(draftAction, meta = null, appId = '', actionIndex = 0, eventId = '', previousNodeId = '0', lenient = false) {
|
|
1467
|
+
const node = convertNode(draftAction, false, meta, appId, actionIndex, eventId, '', previousNodeId, lenient);
|
|
1468
|
+
const src = draftAction.params && typeof draftAction.params === 'object' ? draftAction.params : {};
|
|
1469
|
+
const branches = draftAction.branches || src.branches || [];
|
|
1470
|
+
if (!branches || branches.length === 0) {
|
|
1471
|
+
node.data.trueBranchActions = [];
|
|
1472
|
+
node.data.falseBranchActions = [];
|
|
1473
|
+
node.data.otherConditionBranch = [];
|
|
1474
|
+
return node;
|
|
1475
|
+
}
|
|
1476
|
+
const conditionalBranches = [];
|
|
1477
|
+
let elseBranchActions = null;
|
|
1478
|
+
for (let i = 0; i < branches.length; i++) {
|
|
1479
|
+
const branch = branches[i];
|
|
1480
|
+
let cond = branch && typeof branch === 'object' ? branch.condition : null;
|
|
1481
|
+
if (!cond || typeof cond !== 'object')
|
|
1482
|
+
cond = {};
|
|
1483
|
+
const isElse = cond.type === 'else';
|
|
1484
|
+
const hasRealCond = !isElse && hasConditionExpression(cond);
|
|
1485
|
+
const bacts = [];
|
|
1486
|
+
let branchPreviousId = '0';
|
|
1487
|
+
for (const a of branch.actions || []) {
|
|
1488
|
+
if (a.type === 'Output')
|
|
1489
|
+
continue;
|
|
1490
|
+
const branchNode = convertNode(a, false, meta, appId, i, eventId, '', branchPreviousId, lenient);
|
|
1491
|
+
bacts.push(branchNode);
|
|
1492
|
+
branchPreviousId = branchNode.wId;
|
|
1493
|
+
}
|
|
1494
|
+
if (hasRealCond) {
|
|
1495
|
+
conditionalBranches.push([cond, bacts, String(branch.name || '满足条件')]);
|
|
1496
|
+
}
|
|
1497
|
+
else {
|
|
1498
|
+
if (elseBranchActions === null)
|
|
1499
|
+
elseBranchActions = bacts;
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
const trueBranchActions = conditionalBranches.length ? conditionalBranches[0][1] : [];
|
|
1503
|
+
const falseBranchActions = elseBranchActions || [];
|
|
1504
|
+
const otherBranchActions = [];
|
|
1505
|
+
for (let index = 0; index < conditionalBranches.length - 1; index++) {
|
|
1506
|
+
const [cond, actions, name] = conditionalBranches[index + 1];
|
|
1507
|
+
const branchId = genSfId();
|
|
1508
|
+
const detail = buildConditionDetail(cond, String(previousNodeId), meta);
|
|
1509
|
+
otherBranchActions.push({
|
|
1510
|
+
id: branchId, wId: branchId, branchName: name || `条件${index + 2}`,
|
|
1511
|
+
conditionId: detail.conditionId || '', conditionDetail: detail, branchActions: actions,
|
|
1512
|
+
});
|
|
1513
|
+
}
|
|
1514
|
+
node.data.trueBranchActions = trueBranchActions;
|
|
1515
|
+
node.data.falseBranchActions = falseBranchActions;
|
|
1516
|
+
node.data.otherConditionBranch = otherBranchActions;
|
|
1517
|
+
if (conditionalBranches.length) {
|
|
1518
|
+
const detail = buildConditionDetail(conditionalBranches[0][0], String(previousNodeId), meta);
|
|
1519
|
+
node.data.conditionDetail = detail;
|
|
1520
|
+
node.data.conditionId = detail.conditionId;
|
|
1521
|
+
}
|
|
1522
|
+
if (previousNodeId && !['0', String(eventId)].includes(String(previousNodeId))) {
|
|
1523
|
+
node.sources = [{ wId: String(previousNodeId) }];
|
|
1524
|
+
}
|
|
1525
|
+
return node;
|
|
1526
|
+
}
|
|
1527
|
+
/** 将简化计划中的循环体编译进 MultipleExecution.data.actions。 */
|
|
1528
|
+
export function convertMultipleExecution(draftAction, meta = null, appId = '', actionIndex = 0, eventId = '', eventName = '', previousNodeId = '0', lenient = false) {
|
|
1529
|
+
const node = convertNode(draftAction, false, meta, appId, actionIndex, eventId, eventName, previousNodeId, lenient);
|
|
1530
|
+
// 对齐前端 NodeConfig 的循环节点初始数据。data.id 不是画布 wId:它是循环组件
|
|
1531
|
+
// 的配置数据标识;缺失时循环可显示,却无法持久化其中手工新增的条件或赋值。
|
|
1532
|
+
node.data ??= {};
|
|
1533
|
+
node.data.id ??= genSfId();
|
|
1534
|
+
node.data.tempCycleMode ??= String(node.data.cycleMode ?? '1');
|
|
1535
|
+
node.data.type ??= 'MultipleExecution';
|
|
1536
|
+
node.data.applicationId ??= String(appId);
|
|
1537
|
+
node.data.sceneId ??= String(meta?._scene_id || '');
|
|
1538
|
+
node.data.multiParallelFlag ??= '0';
|
|
1539
|
+
// 前端递归展开循环体时使用这两个路径标识构造循环内上下文;根循环为空,
|
|
1540
|
+
// 循环体第一层以当前循环画布节点为 key。缺失会让手工编辑后的状态落回根链。
|
|
1541
|
+
node.multKey ??= '';
|
|
1542
|
+
node.multName ??= '';
|
|
1543
|
+
const body = Array.isArray(draftAction.actions) ? draftAction.actions : [];
|
|
1544
|
+
if (!body.length)
|
|
1545
|
+
throw new Error('MultipleExecution.actions 循环体不能为空');
|
|
1546
|
+
const actions = [];
|
|
1547
|
+
// 循环体首节点在画布中的 previousId 必须为 0;parentId 才是循环容器。
|
|
1548
|
+
// 若把 sources 指向循环节点,前端回读会找不到循环内起始节点并将其画到循环外。
|
|
1549
|
+
let bodyPreviousId = '0';
|
|
1550
|
+
for (let index = 0; index < body.length; index++) {
|
|
1551
|
+
const action = body[index];
|
|
1552
|
+
if (action?.type === 'Output')
|
|
1553
|
+
continue;
|
|
1554
|
+
if (action?.type === 'MultipleExecution')
|
|
1555
|
+
throw new Error('MultipleExecution 暂不支持嵌套循环');
|
|
1556
|
+
const bodyNode = action?.type === 'Condition'
|
|
1557
|
+
? convertCondition(action, meta, appId, index, eventId, bodyPreviousId, lenient)
|
|
1558
|
+
: convertNode(action, false, meta, appId, index, eventId, eventName, bodyPreviousId, lenient);
|
|
1559
|
+
// 前端 dealBackData 展开 data.actions 后,依赖 parentId 将节点挂进循环画布;
|
|
1560
|
+
// 缺失时会被当作主链节点,循环容器显示为空。
|
|
1561
|
+
bodyNode.parentId = node.wId;
|
|
1562
|
+
bodyNode.multKey = node.multKey ? `${node.multKey}.${node.wId}` : String(node.wId);
|
|
1563
|
+
bodyNode.multName = node.multName ? `${node.multName}.${node.name}` : String(node.name);
|
|
1564
|
+
bodyNode.ignoreFlowCheck = true;
|
|
1565
|
+
// 前端以 sources[0] ? sources[0].wId : 0 还原 previousId。
|
|
1566
|
+
// [{}] 会还原为 undefined,循环体找不到起始节点;首节点必须为空数组。
|
|
1567
|
+
if (index === 0)
|
|
1568
|
+
bodyNode.sources = [];
|
|
1569
|
+
actions.push(bodyNode);
|
|
1570
|
+
bodyPreviousId = bodyNode.wId;
|
|
1571
|
+
}
|
|
1572
|
+
if (!actions.length)
|
|
1573
|
+
throw new Error('MultipleExecution.actions 循环体必须包含至少一个非 Output 动作');
|
|
1574
|
+
node.data.actions = actions;
|
|
1575
|
+
return node;
|
|
1576
|
+
}
|
|
1577
|
+
// ── 辅助层 / 骨架 / 别名替换 ───────────────────────────────
|
|
1578
|
+
export function buildAssistLayer(event, actions) {
|
|
1579
|
+
const nodes = [{ id: event.id, type: event.type, layout: { x: 100, y: 100, width: 200, height: 80 } }];
|
|
1580
|
+
let y = 220;
|
|
1581
|
+
for (const a of actions) {
|
|
1582
|
+
nodes.push({ id: a.id, type: a.type, layout: { x: 100, y, width: 200, height: 80 } });
|
|
1583
|
+
y += 130;
|
|
1584
|
+
}
|
|
1585
|
+
return { nodes, edges: [], layout: { offsetX: 0, offsetY: 0, zoom: 1.0 } };
|
|
1586
|
+
}
|
|
1587
|
+
function registerRealNodeIds(draftNode, realNode, nodeIds) {
|
|
1588
|
+
const draftId = String(draftNode?.id ?? '');
|
|
1589
|
+
const realId = String(realNode?.id ?? '');
|
|
1590
|
+
if (draftId && realId)
|
|
1591
|
+
nodeIds[draftId] = realId;
|
|
1592
|
+
}
|
|
1593
|
+
function replaceFormulaSourceAliases(value, nodeIds) {
|
|
1594
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
1595
|
+
if (String(value.type) === '3' && 'formulaType' in value) {
|
|
1596
|
+
const source = value.source;
|
|
1597
|
+
if (typeof source === 'string' && source in nodeIds)
|
|
1598
|
+
value.source = nodeIds[source];
|
|
1599
|
+
}
|
|
1600
|
+
const cfg = value.config;
|
|
1601
|
+
if (typeof cfg === 'string') {
|
|
1602
|
+
try {
|
|
1603
|
+
const cfgObj = JSON.parse(cfg);
|
|
1604
|
+
if (cfgObj && typeof cfgObj === 'object' && typeof cfgObj.comId === 'string' && cfgObj.comId in nodeIds) {
|
|
1605
|
+
cfgObj.comId = nodeIds[cfgObj.comId];
|
|
1606
|
+
value.config = JSON.stringify(cfgObj);
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
catch { /* ignore */ }
|
|
1610
|
+
}
|
|
1611
|
+
else if (cfg && typeof cfg === 'object' && typeof cfg.comId === 'string' && cfg.comId in nodeIds) {
|
|
1612
|
+
cfg.comId = nodeIds[cfg.comId];
|
|
1613
|
+
}
|
|
1614
|
+
for (const child of Object.values(value))
|
|
1615
|
+
replaceFormulaSourceAliases(child, nodeIds);
|
|
1616
|
+
}
|
|
1617
|
+
else if (Array.isArray(value)) {
|
|
1618
|
+
for (const child of value)
|
|
1619
|
+
replaceFormulaSourceAliases(child, nodeIds);
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
function buildSkeletonNode(actionType, previousNodeId, actionIndex = 0) {
|
|
1623
|
+
const comp = get(actionType) || {};
|
|
1624
|
+
const disp = comp.display || {};
|
|
1625
|
+
const nodeId = genSfId();
|
|
1626
|
+
const node = {
|
|
1627
|
+
id: nodeId, wId: nodeId,
|
|
1628
|
+
name: disp.typeName || disp.componentName || actionType,
|
|
1629
|
+
nameMultilang: disp.typeName || disp.componentName || actionType,
|
|
1630
|
+
type: actionType, typeName: disp.typeName || actionType,
|
|
1631
|
+
attr: { icon: disp.icon ?? 'Icon-eb-mcolor' },
|
|
1632
|
+
sources: [{ id: String(previousNodeId), wId: String(previousNodeId), status: [] }],
|
|
1633
|
+
data: JSON.parse(JSON.stringify(comp.defaultData || {})),
|
|
1634
|
+
parentId: '0',
|
|
1635
|
+
};
|
|
1636
|
+
if (actionType.startsWith('ActionEb')) {
|
|
1637
|
+
node.data.ebActionId ??= '-1';
|
|
1638
|
+
node.data.type = actionType;
|
|
1639
|
+
}
|
|
1640
|
+
return node;
|
|
1641
|
+
}
|
|
1642
|
+
// ── convert(主入口)────────────────────────────────────────
|
|
1643
|
+
export function convert(draft, appId = '', sceneId = '', metadataPath = '', lenient = false) {
|
|
1644
|
+
let meta = {};
|
|
1645
|
+
if (metadataPath)
|
|
1646
|
+
meta = JSON.parse(fs.readFileSync(metadataPath, 'utf-8'));
|
|
1647
|
+
if (!meta || typeof meta !== 'object')
|
|
1648
|
+
meta = {};
|
|
1649
|
+
meta._scene_id = String(sceneId || '');
|
|
1650
|
+
meta._componentOptions = draft._componentOptions && typeof draft._componentOptions === 'object'
|
|
1651
|
+
? draft._componentOptions
|
|
1652
|
+
: {};
|
|
1653
|
+
let draftEvent = draft.event || {};
|
|
1654
|
+
let draftActions = draft.actions || [];
|
|
1655
|
+
const lenientWarnings = [];
|
|
1656
|
+
if ('resolvedPlan' in draft) {
|
|
1657
|
+
const rp = draft.resolvedPlan;
|
|
1658
|
+
draftEvent = rp.event || {};
|
|
1659
|
+
draftActions = rp.actions || [];
|
|
1660
|
+
}
|
|
1661
|
+
const eventNode = convertNode(draftEvent, true, meta, appId);
|
|
1662
|
+
const eventId = eventNode.id;
|
|
1663
|
+
const eventName = String(eventNode.attr?.componentName || eventNode.data?.typeName || eventNode.name || '流程触发');
|
|
1664
|
+
const eventData = eventNode.data || {};
|
|
1665
|
+
const workflowPath = eventData.workflowPath || [];
|
|
1666
|
+
let workflowId = '';
|
|
1667
|
+
if (Array.isArray(workflowPath) && workflowPath.length && workflowPath[0] && typeof workflowPath[0] === 'object') {
|
|
1668
|
+
workflowId = String(workflowPath[0].id ?? '');
|
|
1669
|
+
}
|
|
1670
|
+
if (!workflowId && draftEvent && typeof draftEvent === 'object') {
|
|
1671
|
+
const eventParams = draftEvent.params || {};
|
|
1672
|
+
const eventWorkflowPath = eventParams.workflowPath;
|
|
1673
|
+
if (eventWorkflowPath && typeof eventWorkflowPath === 'object' && !Array.isArray(eventWorkflowPath))
|
|
1674
|
+
workflowId = String(eventWorkflowPath.id ?? '');
|
|
1675
|
+
if (!workflowId)
|
|
1676
|
+
workflowId = String(draftEvent.workflowId ?? '');
|
|
1677
|
+
}
|
|
1678
|
+
if (!workflowId && eventData && typeof eventData === 'object') {
|
|
1679
|
+
const ds = eventData.dataSource || {};
|
|
1680
|
+
let dsId = String(ds.id || '');
|
|
1681
|
+
if (!dsId) {
|
|
1682
|
+
const tf = eventData.targetForm || {};
|
|
1683
|
+
dsId = String(tf.id || eventData.objId || '');
|
|
1684
|
+
}
|
|
1685
|
+
if (dsId)
|
|
1686
|
+
workflowId = dsId;
|
|
1687
|
+
}
|
|
1688
|
+
const workflowModule = String(eventData.module ?? 'workflow');
|
|
1689
|
+
if (workflowId) {
|
|
1690
|
+
meta._workflow_id = workflowId;
|
|
1691
|
+
let eventFormId = '';
|
|
1692
|
+
let wfFids = [];
|
|
1693
|
+
if (Array.isArray(workflowPath) && workflowPath.length && workflowPath[0] && typeof workflowPath[0] === 'object')
|
|
1694
|
+
wfFids = workflowPath[0].formIds || [];
|
|
1695
|
+
else if (workflowPath && typeof workflowPath === 'object' && !Array.isArray(workflowPath))
|
|
1696
|
+
wfFids = workflowPath.formIds || [];
|
|
1697
|
+
if (wfFids.length)
|
|
1698
|
+
eventFormId = String(wfFids[0]);
|
|
1699
|
+
else {
|
|
1700
|
+
const evType = String(draftEvent?.type || '');
|
|
1701
|
+
if (['TimeBatchTrigger', 'EventFormData', 'DateTrigger', 'EnquiryForm'].includes(evType))
|
|
1702
|
+
eventFormId = workflowId;
|
|
1703
|
+
}
|
|
1704
|
+
meta._event_form_id = eventFormId;
|
|
1705
|
+
meta._upstream_component_type = String(draftEvent?.type || 'ApproveTrigger');
|
|
1706
|
+
let wfName = '';
|
|
1707
|
+
if (Array.isArray(workflowPath) && workflowPath.length && workflowPath[0] && typeof workflowPath[0] === 'object')
|
|
1708
|
+
wfName = String(workflowPath[0].name || workflowPath[0].text || '');
|
|
1709
|
+
else if (workflowPath && typeof workflowPath === 'object' && !Array.isArray(workflowPath))
|
|
1710
|
+
wfName = String(workflowPath.name || workflowPath.text || '');
|
|
1711
|
+
if (!wfName && draft && typeof draft === 'object')
|
|
1712
|
+
wfName = String(draft.workflowName || '');
|
|
1713
|
+
if (!wfName && draft && typeof draft === 'object') {
|
|
1714
|
+
const evParams = (draft.event || {}).params || {};
|
|
1715
|
+
const an = evParams.approveNode;
|
|
1716
|
+
if (an && typeof an === 'object')
|
|
1717
|
+
wfName = String(an.workflowName || '');
|
|
1718
|
+
}
|
|
1719
|
+
meta._upstream_workflow_name = wfName;
|
|
1720
|
+
if (!meta._upstream_form_name && eventData && typeof eventData === 'object') {
|
|
1721
|
+
let srcName = '';
|
|
1722
|
+
const ds = eventData.dataSource || {};
|
|
1723
|
+
if (ds && typeof ds === 'object')
|
|
1724
|
+
srcName = String(ds.text || ds.name || '');
|
|
1725
|
+
if (!srcName) {
|
|
1726
|
+
const tf = eventData.targetForm || {};
|
|
1727
|
+
if (tf && typeof tf === 'object')
|
|
1728
|
+
srcName = String(tf.text || tf.name || '');
|
|
1729
|
+
}
|
|
1730
|
+
if (srcName)
|
|
1731
|
+
meta._upstream_form_name = srcName;
|
|
1732
|
+
}
|
|
1733
|
+
meta._upstream_w_id = String(eventNode.id || '');
|
|
1734
|
+
}
|
|
1735
|
+
const realActions = [];
|
|
1736
|
+
let previousNode = eventNode;
|
|
1737
|
+
for (let i = 0; i < draftActions.length; i++) {
|
|
1738
|
+
const a = draftActions[i];
|
|
1739
|
+
const prevId = previousNode.id;
|
|
1740
|
+
let node;
|
|
1741
|
+
try {
|
|
1742
|
+
if (a.type === 'Condition') {
|
|
1743
|
+
node = convertCondition(a, meta, appId, i, eventId, prevId, lenient);
|
|
1744
|
+
}
|
|
1745
|
+
else if (a.type === 'MultipleExecution') {
|
|
1746
|
+
node = convertMultipleExecution(a, meta, appId, i, eventId, eventName, prevId, lenient);
|
|
1747
|
+
}
|
|
1748
|
+
else {
|
|
1749
|
+
node = convertNode(a, false, meta, appId, i, eventId, eventName, prevId, lenient);
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
catch (e) {
|
|
1753
|
+
if (!lenient)
|
|
1754
|
+
throw e;
|
|
1755
|
+
node = buildSkeletonNode(String(a.type || ''), String(prevId), i);
|
|
1756
|
+
lenientWarnings.push(`actions[${i}](${a.type}) 转换失败已降级为骨架节点(字段未生成): ${e}`);
|
|
1757
|
+
}
|
|
1758
|
+
if (['ActionEbAdd', 'ActionEbUpdate'].includes(a.type) && workflowId) {
|
|
1759
|
+
const nodeData = node.data ?? (node.data = {});
|
|
1760
|
+
nodeData.workflowModule ??= workflowModule;
|
|
1761
|
+
nodeData.workflowId ??= workflowId;
|
|
1762
|
+
}
|
|
1763
|
+
realActions.push(node);
|
|
1764
|
+
if (workflowId)
|
|
1765
|
+
meta._workflow_id = workflowId;
|
|
1766
|
+
previousNode = node;
|
|
1767
|
+
}
|
|
1768
|
+
const sourceNodeIds = { event: String(eventNode.id), trigger: String(eventNode.id) };
|
|
1769
|
+
registerRealNodeIds(draftEvent, eventNode, sourceNodeIds);
|
|
1770
|
+
draftActions.forEach((draftAction, idx) => registerRealNodeIds(draftAction, realActions[idx], sourceNodeIds));
|
|
1771
|
+
replaceFormulaSourceAliases(realActions, sourceNodeIds);
|
|
1772
|
+
const assist = buildAssistLayer(eventNode, realActions);
|
|
1773
|
+
const design = {
|
|
1774
|
+
appId: appId ? String(appId) : genSfId(),
|
|
1775
|
+
sceneId: sceneId ? String(sceneId) : genSfId(),
|
|
1776
|
+
event: eventNode,
|
|
1777
|
+
actions: realActions,
|
|
1778
|
+
assistLayer: JSON.stringify(assist),
|
|
1779
|
+
reloadFormula: [],
|
|
1780
|
+
version: 1,
|
|
1781
|
+
};
|
|
1782
|
+
const coerced = coerceIdsToStr(design);
|
|
1783
|
+
if (lenient)
|
|
1784
|
+
coerced._lenient_warnings = lenientWarnings;
|
|
1785
|
+
return coerced;
|
|
1786
|
+
}
|
|
1787
|
+
// ── _coerce_ids_to_str ──────────────────────────────────────
|
|
1788
|
+
const ID_KEYS = new Set(['id', 'wId', 'componentId', 'parentId', 'parentNode', 'frontId']);
|
|
1789
|
+
export function coerceIdsToStr(obj) {
|
|
1790
|
+
if (obj && typeof obj === 'object' && !Array.isArray(obj)) {
|
|
1791
|
+
const out = {};
|
|
1792
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
1793
|
+
if (ID_KEYS.has(k) && (typeof v === 'number' || typeof v === 'bigint'))
|
|
1794
|
+
out[k] = String(v);
|
|
1795
|
+
else
|
|
1796
|
+
out[k] = coerceIdsToStr(v);
|
|
1797
|
+
}
|
|
1798
|
+
return out;
|
|
1799
|
+
}
|
|
1800
|
+
if (Array.isArray(obj))
|
|
1801
|
+
return obj.map(coerceIdsToStr);
|
|
1802
|
+
return obj;
|
|
1803
|
+
}
|
|
1804
|
+
//# sourceMappingURL=workflow_compiler.js.map
|