openyida 2026.7.18 → 2026.7.21
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/README.md +37 -2
- package/bin/yida.js +113 -18
- package/docs/capabilities.md +202 -0
- package/lib/agent-center/agent-center.js +2 -3
- package/lib/app/app-list.js +3 -4
- package/lib/app/build-page.js +13 -6
- package/lib/app/check-page.js +16 -6
- package/lib/app/compile.js +17 -7
- package/lib/app/create-app.js +14 -2
- package/lib/app/create-form/api-path.js +25 -0
- package/lib/app/create-form/args.js +13 -0
- package/lib/app/create-form/commands.js +4 -0
- package/lib/app/create-form/definition-reader.js +23 -23
- package/lib/app/create-form/field-normalizers.js +26 -7
- package/lib/app/create-form/schema-patch.js +4 -1
- package/lib/app/create-form.js +155 -68
- package/lib/app/create-page.js +47 -10
- package/lib/app/generate-page.js +20 -1
- package/lib/app/get-form-config.js +2 -1
- package/lib/app/get-schema.js +67 -15
- package/lib/app/import-app.js +94 -42
- package/lib/app/list-forms.js +4 -8
- package/lib/app/page-ir.js +140 -0
- package/lib/app/publish.js +289 -556
- package/lib/app/schema-field-resolution.js +370 -0
- package/lib/app/services/app-reader.js +85 -0
- package/lib/app/services/app-service.js +235 -0
- package/lib/app/services/canvas-page-compiler.js +91 -0
- package/lib/app/services/canvas-page-schema-builder.js +149 -0
- package/lib/app/services/field-bindings.js +68 -0
- package/lib/app/services/form-compiler.js +1922 -0
- package/lib/app/services/form-mode-service.js +182 -0
- package/lib/app/services/form-schema-patcher.js +333 -0
- package/lib/app/services/form-schema-reader.js +59 -0
- package/lib/app/services/form-service.js +379 -0
- package/lib/app/services/form-validation.js +562 -0
- package/lib/app/services/native-page-compiler.js +92 -0
- package/lib/app/services/native-page-schema-builder.js +428 -0
- package/lib/app/services/page-resource-service.js +185 -0
- package/lib/app/update-app.js +22 -9
- package/lib/app/update-form-config.js +4 -2
- package/lib/asset/asset-cmd.js +19 -6
- package/lib/auth/oauth-loopback.js +376 -15
- package/lib/auth/token-auth.js +34 -3
- package/lib/auth/token-store.js +22 -4
- package/lib/basic-info/basic-info.js +2 -1
- package/lib/bridge/bridge.js +43 -18
- package/lib/core/agent-capabilities.js +5 -3
- package/lib/core/command-errors.js +38 -0
- package/lib/core/command-manifest.js +59 -1
- package/lib/core/copy.js +12 -0
- package/lib/core/doctor.js +15 -4
- package/lib/core/env-cmd.js +1 -1
- package/lib/core/env.js +7 -6
- package/lib/core/i18n.js +66 -8
- package/lib/core/legacy-schema-guard.js +408 -0
- package/lib/core/locales/en.js +38 -46
- package/lib/core/locales/zh.js +30 -46
- package/lib/core/sample.js +12 -2
- package/lib/core/utils.js +334 -66
- package/lib/core/yida-client.js +108 -5
- package/lib/corp-efficiency/corp-efficiency.js +2 -2
- package/lib/corp-manager/corp-manager.js +3 -3
- package/lib/formula/evaluate.js +11 -68
- package/lib/formula/field-refs.js +83 -0
- package/lib/i18n-management/i18n-management.js +2 -3
- package/lib/process/configure-process.js +44 -1992
- package/lib/process/create-process.js +54 -87
- package/lib/process/preview-process.js +20 -8
- package/lib/process/services/process-compiler.js +2056 -0
- package/lib/process/services/process-reader.js +232 -0
- package/lib/process/services/process-resource-service.js +571 -0
- package/lib/process/services/process-service.js +122 -0
- package/lib/process/services/process-stage-checkpoint.js +246 -0
- package/lib/report/append.js +7 -26
- package/lib/report/http.js +31 -5
- package/lib/report/index.js +10 -2
- package/lib/samples/yida-canvas-custom-page/business-list.canvas.jsx +63 -14
- package/lib/samples/yida-canvas-custom-page/dashboard-overview.canvas.jsx +176 -32
- package/lib/samples/yida-canvas-custom-page/dashboard-starter.canvas.jsx +5 -2
- package/lib/samples/yida-canvas-custom-page/data-management.canvas.jsx +228 -14
- package/lib/samples/yida-canvas-custom-page/portal-shell-home.canvas.jsx +2 -2
- package/lib/samples/yida-canvas-custom-page/split-pane-detail.canvas.jsx +206 -10
- package/lib/samples/yida-custom-page/data-management.oyd.jsx +14 -3
- package/lib/samples/yida-custom-page/design-tokens.js +2 -2
- package/lib/samples/yida-custom-page/detail-profile.oyd.jsx +1 -1
- package/lib/samples/yida-custom-page/portal-shell-home.oyd.jsx +7 -2
- package/lib/samples/yida-custom-page/split-pane-detail.oyd.jsx +2 -1
- package/lib/schema/adapters/app-adapter.js +210 -0
- package/lib/schema/adapters/form-adapter.js +1362 -0
- package/lib/schema/adapters/keys.js +19 -0
- package/lib/schema/adapters/page-adapter.js +566 -0
- package/lib/schema/adapters/process-adapter.js +519 -0
- package/lib/schema/applier.js +1878 -0
- package/lib/schema/apply-store.js +1083 -0
- package/lib/schema/command.js +645 -0
- package/lib/schema/dependency-graph.js +83 -0
- package/lib/schema/errors.js +481 -0
- package/lib/schema/hash.js +9 -0
- package/lib/schema/manifest-limits.js +177 -0
- package/lib/schema/manifest-loader.js +309 -0
- package/lib/schema/manifest-schema-v1.json +193 -0
- package/lib/schema/normalize-manifest.js +281 -0
- package/lib/schema/page-canvas-foundation.js +447 -0
- package/lib/schema/page-data-source-builder.js +561 -0
- package/lib/schema/page-foundation.js +556 -0
- package/lib/schema/page-source-loader.js +314 -0
- package/lib/schema/planner.js +691 -0
- package/lib/schema/remote-dispatch-boundary.js +39 -0
- package/lib/schema/remote-missing.js +21 -0
- package/lib/schema/remote-reader.js +189 -0
- package/lib/schema/resource-registry.js +157 -0
- package/lib/schema/server-revision.js +71 -0
- package/lib/schema/sort.js +28 -0
- package/lib/schema/state-store.js +589 -0
- package/package.json +10 -8
- package/scripts/check-release-risks.js +254 -0
- package/scripts/generate-command-docs.js +6 -1
- package/scripts/i18n-baseline.json +11 -11
- package/scripts/postinstall.js +8 -12
- package/scripts/validate-ci.sh +15 -11
- package/scripts/validate-i18n.js +30 -9
- package/scripts/validate-package-size.js +5 -2
- package/scripts/validate-skills.js +4 -0
- package/scripts/validate-structure.js +15 -0
- package/yida-skills/SKILL.md +117 -30
- package/yida-skills/references/schema-as-code-phase1.md +99 -0
- package/yida-skills/references/setup-and-env.md +59 -59
- package/yida-skills/references/task-retrospective.md +6 -6
- package/yida-skills/skills/yida-app/SKILL.md +78 -17
- package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +18 -7
- package/yida-skills/skills/yida-canvas-custom-page/references/data-bridge-guide.md +3 -3
- package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +15 -0
- package/yida-skills/skills/yida-create-app/SKILL.md +21 -3
- package/yida-skills/skills/yida-create-form-page/SKILL.md +19 -1
- package/yida-skills/skills/yida-create-page/SKILL.md +16 -3
- package/yida-skills/skills/yida-create-process/SKILL.md +100 -4
- package/yida-skills/skills/yida-custom-page/SKILL.md +19 -4
- package/yida-skills/skills/yida-dashboard/SKILL.md +1 -1
- package/yida-skills/skills/yida-dashboard/references/pitfalls.md +1 -1
- package/yida-skills/skills/yida-get-schema/SKILL.md +49 -5
- package/yida-skills/skills/yida-i18n/SKILL.md +1 -1
- package/yida-skills/skills/yida-integration/SKILL.md +7 -1
- package/yida-skills/skills/yida-login/SKILL.md +50 -99
- package/yida-skills/skills/yida-page-config/SKILL.md +7 -1
- package/yida-skills/skills/yida-page-uiux/references/app/blueprint.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/app/navigation-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/app/role-journey.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/app-blueprint.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/chart-contracts.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/component-contracts.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/layout-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/theme-recipes.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/detail/object-narrative.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/detail/section-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/detail/timeline-and-related.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/assets-workflow.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/industry-playbooks.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/research-levels.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/section-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/drawer-detail.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/empty-loading-error.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/filter-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/table-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/scenes/screen.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/workbench/entry-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/workbench/portal-layouts.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/workbench/task-feed.md +0 -1
- package/yida-skills/skills/yida-page-uiux/workflow/output-decision-block.md +1 -1
- package/yida-skills/skills/yida-process-rule/SKILL.md +35 -1
- package/yida-skills/skills/yida-publish-page/SKILL.md +46 -4
- package/yida-skills/skills/yida-report/SKILL.md +9 -235
- package/yida-skills/skills/yida-report/references/schema-builder-details.md +239 -0
- package/yida-skills/skills/yida-skill-evaluator/SKILL.md +170 -0
- package/yida-skills/skills-index.json +238 -54
- package/lib/core/locales/ar.js +0 -834
- package/lib/core/locales/de.js +0 -834
- package/lib/core/locales/es.js +0 -834
- package/lib/core/locales/fr.js +0 -834
- package/lib/core/locales/hi.js +0 -834
- package/lib/core/locales/ja.js +0 -1227
- package/lib/core/locales/ko.js +0 -836
- package/lib/core/locales/pt.js +0 -834
- package/lib/core/locales/vi.js +0 -834
- package/lib/core/locales/zh-HK.js +0 -1263
- package/project/pages/src/demo-birthday-game.oyd.jsx +0 -832
- package/project/pages/src/demo-chip-insight.oyd.jsx +0 -983
- package/project/pages/src/demo-compat-smoke.oyd.jsx +0 -58
- package/project/pages/src/demo-crm-batch-entry.oyd.jsx +0 -805
- package/project/pages/src/demo-crm-dashboard.oyd.jsx +0 -677
- package/project/pages/src/demo-future-vision-2026.oyd.jsx +0 -1102
- package/project/pages/src/demo-ppt.oyd.jsx +0 -1192
- package/project/pages/src/demo-salary-calculator.oyd.jsx +0 -904
- package/project/pages/src/openyida-knowledge-doc.oyd.jsx +0 -1714
- package/yida-skills/skills/large-file-write/SKILL.md +0 -93
- package/yida-skills/skills/large-file-write/references/write-patterns.md +0 -147
- package/yida-skills/skills/large-file-write/scripts/write.js +0 -157
- package/yida-skills/skills/sls-log-workbench/SKILL.md +0 -134
- package/yida-skills/skills/sls-log-workbench/references/workbench-reference.md +0 -130
- package/yida-skills/skills/sls-log-workbench/sls-query.js +0 -295
|
@@ -0,0 +1,2056 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* process-compiler.js - 共享宜搭流程定义编译器
|
|
3
|
+
*
|
|
4
|
+
* 同时服务于 legacy configure-process DSL 与 Schema-as-Code managed process IR。
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const { buildYidaI18n } = require('../../core/yida-i18n');
|
|
10
|
+
const { KEY_PATTERN } = require('../../schema/adapters/keys');
|
|
11
|
+
|
|
12
|
+
class ProcessCompilerError extends Error {
|
|
13
|
+
constructor(code, message, details) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = 'ProcessCompilerError';
|
|
16
|
+
this.code = code;
|
|
17
|
+
this.details = details;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// ── 操作符映射(基于浏览器捕获的真实数据)────────────
|
|
22
|
+
|
|
23
|
+
const OP_CODE_TO_DISPLAY = {
|
|
24
|
+
Equal: '等于',
|
|
25
|
+
NotEqual: '不等于',
|
|
26
|
+
Contains: '包含',
|
|
27
|
+
NotContain: '不包含',
|
|
28
|
+
IsEmpty: '为空',
|
|
29
|
+
IsNotEmpty: '不为空',
|
|
30
|
+
GreaterThan: '大于',
|
|
31
|
+
Bigger: '大于',
|
|
32
|
+
GreaterThanOrEqual: '大于等于',
|
|
33
|
+
LessThan: '小于',
|
|
34
|
+
LessThanOrEqual: '小于等于',
|
|
35
|
+
In: '属于',
|
|
36
|
+
NotIn: '不属于',
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const COMPONENT_TO_RULE_TYPE = {
|
|
40
|
+
TextField: 'rule_text',
|
|
41
|
+
TextareaField: 'rule_text',
|
|
42
|
+
NumberField: 'rule_number',
|
|
43
|
+
SelectField: 'rule_select',
|
|
44
|
+
RadioField: 'rule_radio',
|
|
45
|
+
DateField: 'rule_date',
|
|
46
|
+
EmployeeField: 'rule_employee',
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const NODE_TYPE_ALIASES = {
|
|
50
|
+
approval: 'approval',
|
|
51
|
+
approver: 'approval',
|
|
52
|
+
approvalnode: 'approval',
|
|
53
|
+
operator: 'operator',
|
|
54
|
+
executor: 'operator',
|
|
55
|
+
handler: 'operator',
|
|
56
|
+
fill: 'operator',
|
|
57
|
+
filler: 'operator',
|
|
58
|
+
formfill: 'operator',
|
|
59
|
+
operatornode: 'operator',
|
|
60
|
+
multiapproval: 'multiApproval',
|
|
61
|
+
multiapprover: 'multiApproval',
|
|
62
|
+
multiapprovalnode: 'multiApproval',
|
|
63
|
+
carbon: 'carbon',
|
|
64
|
+
cc: 'carbon',
|
|
65
|
+
copy: 'carbon',
|
|
66
|
+
copynode: 'carbon',
|
|
67
|
+
carbonnode: 'carbon',
|
|
68
|
+
route: 'route',
|
|
69
|
+
branch: 'route',
|
|
70
|
+
branchnode: 'route',
|
|
71
|
+
conditioncontainer: 'route',
|
|
72
|
+
conditionnode: 'route',
|
|
73
|
+
parallel: 'parallel',
|
|
74
|
+
parallelbranch: 'parallel',
|
|
75
|
+
connector: 'ConnectorNode',
|
|
76
|
+
connectornode: 'ConnectorNode',
|
|
77
|
+
groovy: 'GroovyNode',
|
|
78
|
+
groovynode: 'GroovyNode',
|
|
79
|
+
javascript: 'JavaScriptNode',
|
|
80
|
+
js: 'JavaScriptNode',
|
|
81
|
+
javascriptnode: 'JavaScriptNode',
|
|
82
|
+
initiateapproval: 'InitiateApprovalNode',
|
|
83
|
+
subprocess: 'InitiateApprovalNode',
|
|
84
|
+
initiateapprovalnode: 'InitiateApprovalNode',
|
|
85
|
+
sendmessage: 'SendMessageNode',
|
|
86
|
+
message: 'SendMessageNode',
|
|
87
|
+
sendmessagenode: 'SendMessageNode',
|
|
88
|
+
sendemail: 'SendEmailNode',
|
|
89
|
+
email: 'SendEmailNode',
|
|
90
|
+
sendemailnode: 'SendEmailNode',
|
|
91
|
+
getdata: 'GetSingleDataNode',
|
|
92
|
+
getsingledata: 'GetSingleDataNode',
|
|
93
|
+
getsingledatanode: 'GetSingleDataNode',
|
|
94
|
+
getbatchdata: 'GetBatchDataNode',
|
|
95
|
+
getbatchdatanode: 'GetBatchDataNode',
|
|
96
|
+
adddata: 'AddDataNode',
|
|
97
|
+
createdata: 'AddDataNode',
|
|
98
|
+
adddatanode: 'AddDataNode',
|
|
99
|
+
updatedata: 'UpdateDataNode',
|
|
100
|
+
updatedatanode: 'UpdateDataNode',
|
|
101
|
+
deletedata: 'DeleteDataNode',
|
|
102
|
+
deletedatanode: 'DeleteDataNode',
|
|
103
|
+
sendcard: 'SendCardNode',
|
|
104
|
+
sendcardnode: 'SendCardNode',
|
|
105
|
+
cardnode: 'CardNode',
|
|
106
|
+
updatecard: 'UpdateCardNode',
|
|
107
|
+
updatecardnode: 'UpdateCardNode',
|
|
108
|
+
cardupdate: 'CardUpdateNode',
|
|
109
|
+
cardupdatenode: 'CardUpdateNode',
|
|
110
|
+
cycle: 'CycleContainer',
|
|
111
|
+
foreach: 'CycleContainer',
|
|
112
|
+
cyclecontainer: 'CycleContainer',
|
|
113
|
+
ai: 'AINode',
|
|
114
|
+
ainode: 'AINode',
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const CONNECTOR_MODE_TO_PROCESS_TYPE = {
|
|
118
|
+
1: 'innerConnector',
|
|
119
|
+
3: 'thirdConnector',
|
|
120
|
+
5: 'httpConnector',
|
|
121
|
+
9: 'faasConnector',
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const GENERIC_NODE_CONFIGS = {
|
|
125
|
+
ConnectorNode: {
|
|
126
|
+
processType: 'innerConnector',
|
|
127
|
+
title: ['连接器', 'Connector', 'コネクタ'],
|
|
128
|
+
propKeys: ['connectorRules'],
|
|
129
|
+
},
|
|
130
|
+
GroovyNode: {
|
|
131
|
+
processType: 'CodeExecutor',
|
|
132
|
+
title: ['Groovy', 'Groovy', 'Groovy'],
|
|
133
|
+
propKeys: ['groovy'],
|
|
134
|
+
},
|
|
135
|
+
JavaScriptNode: {
|
|
136
|
+
processType: 'CodeExecutor',
|
|
137
|
+
title: ['JavaScript', 'JavaScript', 'JavaScript'],
|
|
138
|
+
propKeys: ['JavaScript'],
|
|
139
|
+
propAliases: { javascript: 'JavaScript' },
|
|
140
|
+
},
|
|
141
|
+
InitiateApprovalNode: {
|
|
142
|
+
processType: 'initiateApproval',
|
|
143
|
+
title: ['子流程', 'Sub process', 'サブプロセス'],
|
|
144
|
+
propKeys: ['initiateApprovalRules'],
|
|
145
|
+
},
|
|
146
|
+
SendMessageNode: {
|
|
147
|
+
processType: 'sendMessage',
|
|
148
|
+
title: ['消息通知', 'Message notification', 'メッセージ通知'],
|
|
149
|
+
propKeys: ['sendMessageRules'],
|
|
150
|
+
},
|
|
151
|
+
SendEmailNode: {
|
|
152
|
+
processType: 'sendEmail',
|
|
153
|
+
title: ['发送邮件', 'Send email', 'メール送信'],
|
|
154
|
+
propKeys: ['sendEmailRules'],
|
|
155
|
+
},
|
|
156
|
+
GetSingleDataNode: {
|
|
157
|
+
processType: 'dataRetrieve',
|
|
158
|
+
title: ['获取单条数据', 'Get single data', '単一データ取得'],
|
|
159
|
+
propKeys: ['getData'],
|
|
160
|
+
},
|
|
161
|
+
GetBatchDataNode: {
|
|
162
|
+
processType: 'dataRetrieve',
|
|
163
|
+
title: ['获取多条数据', 'Get batch data', '複数データ取得'],
|
|
164
|
+
propKeys: ['getData'],
|
|
165
|
+
},
|
|
166
|
+
AddDataNode: {
|
|
167
|
+
processType: 'dataCreate',
|
|
168
|
+
title: ['新增数据', 'Add data', 'データ追加'],
|
|
169
|
+
propKeys: ['addDataRules'],
|
|
170
|
+
},
|
|
171
|
+
UpdateDataNode: {
|
|
172
|
+
processType: 'dataUpdate',
|
|
173
|
+
title: ['更新数据', 'Update data', 'データ更新'],
|
|
174
|
+
propKeys: ['updateDataRules'],
|
|
175
|
+
},
|
|
176
|
+
DeleteDataNode: {
|
|
177
|
+
processType: 'dataDelete',
|
|
178
|
+
title: ['删除数据', 'Delete data', 'データ削除'],
|
|
179
|
+
propKeys: ['deleteData'],
|
|
180
|
+
},
|
|
181
|
+
SendCardNode: {
|
|
182
|
+
processType: 'sendCard',
|
|
183
|
+
title: ['发送卡片', 'Send card', 'カード送信'],
|
|
184
|
+
propKeys: ['sendCardRules', 'cardRules'],
|
|
185
|
+
},
|
|
186
|
+
CardNode: {
|
|
187
|
+
processType: 'sendCard',
|
|
188
|
+
title: ['发送卡片', 'Send card', 'カード送信'],
|
|
189
|
+
propKeys: ['sendCardRules', 'cardRules'],
|
|
190
|
+
},
|
|
191
|
+
UpdateCardNode: {
|
|
192
|
+
processType: 'updateCard',
|
|
193
|
+
title: ['更新卡片', 'Update card', 'カード更新'],
|
|
194
|
+
propKeys: ['updateCardRules', 'cardUpdateRules'],
|
|
195
|
+
},
|
|
196
|
+
CardUpdateNode: {
|
|
197
|
+
processType: 'updateCard',
|
|
198
|
+
title: ['更新卡片', 'Update card', 'カード更新'],
|
|
199
|
+
propKeys: ['updateCardRules', 'cardUpdateRules'],
|
|
200
|
+
},
|
|
201
|
+
CycleContainer: {
|
|
202
|
+
processType: 'foreach',
|
|
203
|
+
title: ['循环', 'Loop', 'ループ'],
|
|
204
|
+
propKeys: ['cycleContainerRules'],
|
|
205
|
+
propAliases: { cycleRules: 'cycleContainerRules', foreachRules: 'cycleContainerRules' },
|
|
206
|
+
},
|
|
207
|
+
AINode: {
|
|
208
|
+
processType: 'AIExecutor',
|
|
209
|
+
title: ['AI 工作流', 'AI workflow', 'AI ワークフロー'],
|
|
210
|
+
propKeys: ['workFlowRules'],
|
|
211
|
+
propAliases: { workflowRules: 'workFlowRules' },
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// ── 辅助函数 ─────────────────────────────────────────
|
|
216
|
+
|
|
217
|
+
function generateUuid() {
|
|
218
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
219
|
+
const r = (Math.random() * 16) | 0;
|
|
220
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
221
|
+
return v.toString(16);
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
let nodeIdCounter = 1;
|
|
226
|
+
function generateNodeId() {
|
|
227
|
+
return 'node_oc' + Date.now().toString(36) + (nodeIdCounter++).toString(36);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function i18n(zhText, enText, jaText) {
|
|
231
|
+
return buildYidaI18n(zhText, {
|
|
232
|
+
en_US: enText || zhText,
|
|
233
|
+
ja_JP: jaText || zhText,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function isPlainObject(value) {
|
|
238
|
+
return value && typeof value === 'object' && !Array.isArray(value);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function normalizeList(value) {
|
|
242
|
+
if (value === undefined || value === null || value === '') {
|
|
243
|
+
return [];
|
|
244
|
+
}
|
|
245
|
+
return Array.isArray(value) ? value : [value];
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function clonePlain(value) {
|
|
249
|
+
if (value === undefined) {
|
|
250
|
+
return undefined;
|
|
251
|
+
}
|
|
252
|
+
return JSON.parse(JSON.stringify(value));
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function normalizeNodeType(node) {
|
|
256
|
+
if (!node) {
|
|
257
|
+
return '';
|
|
258
|
+
}
|
|
259
|
+
if (node.componentName && GENERIC_NODE_CONFIGS[node.componentName]) {
|
|
260
|
+
return node.componentName;
|
|
261
|
+
}
|
|
262
|
+
const rawType = pickFirstDefined(node.type, node.kind, node.nodeType, node.componentName);
|
|
263
|
+
if (!rawType) {
|
|
264
|
+
return '';
|
|
265
|
+
}
|
|
266
|
+
const raw = String(rawType).trim();
|
|
267
|
+
const normalized = raw.toLowerCase().replace(/[-_\s]/g, '');
|
|
268
|
+
return NODE_TYPE_ALIASES[normalized] || raw;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function getNodeName(node, fallback) {
|
|
272
|
+
const value = pickFirstDefined(
|
|
273
|
+
node && node.name,
|
|
274
|
+
node && node.title,
|
|
275
|
+
node && node.props && node.props.name,
|
|
276
|
+
fallback
|
|
277
|
+
);
|
|
278
|
+
if (isPlainObject(value)) {
|
|
279
|
+
return pickFirstDefined(value.zh_CN, value.en_US, value.ja_JP, fallback) || fallback;
|
|
280
|
+
}
|
|
281
|
+
return String(value || fallback || '');
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function getNodeDescription(node) {
|
|
285
|
+
const value = pickFirstDefined(
|
|
286
|
+
node && node.description,
|
|
287
|
+
node && node.props && node.props.description,
|
|
288
|
+
''
|
|
289
|
+
);
|
|
290
|
+
if (isPlainObject(value)) {
|
|
291
|
+
return pickFirstDefined(value.zh_CN, value.en_US, value.ja_JP, '') || '';
|
|
292
|
+
}
|
|
293
|
+
return String(value || '');
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function pickFirstDefined() {
|
|
297
|
+
for (let i = 0; i < arguments.length; i++) {
|
|
298
|
+
if (arguments[i] !== undefined && arguments[i] !== null && arguments[i] !== '') {
|
|
299
|
+
return arguments[i];
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return undefined;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function getEntityId(item) {
|
|
306
|
+
if (typeof item === 'string' || typeof item === 'number') {
|
|
307
|
+
return String(item);
|
|
308
|
+
}
|
|
309
|
+
if (!isPlainObject(item)) {
|
|
310
|
+
return '';
|
|
311
|
+
}
|
|
312
|
+
return String(pickFirstDefined(item.id, item.userId, item.workNo, item.value, item.uuid, item.roleId, item.code) || '');
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function getEntityLabel(item, id) {
|
|
316
|
+
if (!isPlainObject(item)) {
|
|
317
|
+
return id;
|
|
318
|
+
}
|
|
319
|
+
return String(pickFirstDefined(item.label, item.name, item.nickName, item.userName, item.title, id) || id);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function normalizeApprovalMode(value) {
|
|
323
|
+
const mode = String(value || 'all');
|
|
324
|
+
const aliases = {
|
|
325
|
+
countersign: 'all',
|
|
326
|
+
counterSign: 'all',
|
|
327
|
+
and: 'all',
|
|
328
|
+
all: 'all',
|
|
329
|
+
or: 'or',
|
|
330
|
+
any: 'or',
|
|
331
|
+
one: 'or',
|
|
332
|
+
oneByOne: 'oneByOne',
|
|
333
|
+
serial: 'oneByOne',
|
|
334
|
+
sequence: 'oneByOne',
|
|
335
|
+
};
|
|
336
|
+
return aliases[mode] || mode;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function createBaseApproverRules(type, description, approver) {
|
|
340
|
+
return {
|
|
341
|
+
type: type,
|
|
342
|
+
mode: approver.mode || 'ApprovalNode_rules_only',
|
|
343
|
+
approverList: approver.approverList || [{ type: 'ext_target_approval' }],
|
|
344
|
+
multiApproverType: normalizeApprovalMode(approver.multiApproverType || approver.approvalMode || 'all'),
|
|
345
|
+
conditionalMode: approver.conditionalMode || 'conditional',
|
|
346
|
+
description: description,
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function getFriendlyApproverKind(approver) {
|
|
351
|
+
if (typeof approver === 'string') {
|
|
352
|
+
const text = approver.trim();
|
|
353
|
+
if (!text || text === 'originator' || text === 'self' || text === 'starter' || text === '发起人') {
|
|
354
|
+
return 'originator';
|
|
355
|
+
}
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
if (!isPlainObject(approver)) {
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
const rawKind = String(approver.kind || approver.approverType || approver.type || '').trim();
|
|
362
|
+
if (!rawKind || rawKind.indexOf('ext_target_') === 0) {
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
365
|
+
const normalized = rawKind.toLowerCase().replace(/[-_\s]/g, '');
|
|
366
|
+
const kindMap = {
|
|
367
|
+
originator: 'originator',
|
|
368
|
+
self: 'originator',
|
|
369
|
+
starter: 'originator',
|
|
370
|
+
user: 'user',
|
|
371
|
+
users: 'user',
|
|
372
|
+
member: 'user',
|
|
373
|
+
members: 'user',
|
|
374
|
+
person: 'user',
|
|
375
|
+
employee: 'user',
|
|
376
|
+
designee: 'user',
|
|
377
|
+
specifiedmember: 'user',
|
|
378
|
+
role: 'role',
|
|
379
|
+
roles: 'role',
|
|
380
|
+
deptleader: 'deptLeader',
|
|
381
|
+
departmentleader: 'deptLeader',
|
|
382
|
+
departmenthead: 'deptLeader',
|
|
383
|
+
supervisor: 'deptLeader',
|
|
384
|
+
manager: 'deptLeader',
|
|
385
|
+
directleader: 'directLeader',
|
|
386
|
+
directsupervisor: 'directLeader',
|
|
387
|
+
};
|
|
388
|
+
return kindMap[normalized] || null;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function normalizeUserApprovers(approver) {
|
|
392
|
+
const source = normalizeList(
|
|
393
|
+
pickFirstDefined(
|
|
394
|
+
approver.users,
|
|
395
|
+
approver.members,
|
|
396
|
+
approver.employees,
|
|
397
|
+
approver.userIds,
|
|
398
|
+
approver.ids,
|
|
399
|
+
approver.approvals,
|
|
400
|
+
approver.value
|
|
401
|
+
)
|
|
402
|
+
);
|
|
403
|
+
return source.map(function (item) {
|
|
404
|
+
const id = getEntityId(item);
|
|
405
|
+
if (!id) {
|
|
406
|
+
throw new Error('审批人 user 配置缺少 id/userId/value');
|
|
407
|
+
}
|
|
408
|
+
const user = {
|
|
409
|
+
id: id,
|
|
410
|
+
label: getEntityLabel(item, id),
|
|
411
|
+
type: isPlainObject(item) ? (item.type || 'employee') : 'employee',
|
|
412
|
+
roleType: isPlainObject(item) ? (item.roleType || 'DINGTALK') : 'DINGTALK',
|
|
413
|
+
};
|
|
414
|
+
if (isPlainObject(item) && item.avatar) {
|
|
415
|
+
user.avatar = item.avatar;
|
|
416
|
+
}
|
|
417
|
+
return user;
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function normalizeRoleApprovers(approver) {
|
|
422
|
+
const source = normalizeList(
|
|
423
|
+
pickFirstDefined(
|
|
424
|
+
approver.roles,
|
|
425
|
+
approver.roleIds,
|
|
426
|
+
approver.ids,
|
|
427
|
+
approver.approvals,
|
|
428
|
+
approver.value
|
|
429
|
+
)
|
|
430
|
+
);
|
|
431
|
+
return source.map(function (item) {
|
|
432
|
+
const id = getEntityId(item);
|
|
433
|
+
if (!id) {
|
|
434
|
+
throw new Error('审批人 role 配置缺少 id/uuid/roleId/value');
|
|
435
|
+
}
|
|
436
|
+
return {
|
|
437
|
+
id: id,
|
|
438
|
+
label: getEntityLabel(item, id),
|
|
439
|
+
type: isPlainObject(item) ? (item.type || 'role') : 'role',
|
|
440
|
+
roleType: isPlainObject(item)
|
|
441
|
+
? (item.roleType || approver.roleType || 'YIDA')
|
|
442
|
+
: (approver.roleType || 'YIDA'),
|
|
443
|
+
};
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function buildMultiRoles(roles) {
|
|
448
|
+
const grouped = {};
|
|
449
|
+
roles.forEach(function (role) {
|
|
450
|
+
const roleType = role.roleType || 'YIDA';
|
|
451
|
+
if (!grouped[roleType]) {
|
|
452
|
+
grouped[roleType] = [];
|
|
453
|
+
}
|
|
454
|
+
grouped[roleType].push(role.id);
|
|
455
|
+
});
|
|
456
|
+
return Object.keys(grouped).map(function (roleType) {
|
|
457
|
+
return {
|
|
458
|
+
roleId: grouped[roleType],
|
|
459
|
+
roleExtType: roleType,
|
|
460
|
+
};
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function getApproverSource(approver, direct) {
|
|
465
|
+
const value = pickFirstDefined(
|
|
466
|
+
approver.source,
|
|
467
|
+
approver.originator,
|
|
468
|
+
approver.userIdVar,
|
|
469
|
+
direct ? approver.directSupervisorSource : approver.supervisorSource,
|
|
470
|
+
'originator'
|
|
471
|
+
);
|
|
472
|
+
const label = pickFirstDefined(
|
|
473
|
+
approver.sourceLabel,
|
|
474
|
+
approver.originatorLabel,
|
|
475
|
+
value === 'originator' ? '发起人' : value
|
|
476
|
+
);
|
|
477
|
+
return {
|
|
478
|
+
value: String(value),
|
|
479
|
+
label: String(label),
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function formatLevelDescription(sourceLabel, level, direct) {
|
|
484
|
+
return sourceLabel + '的第' + level + '级' + (direct ? '直属主管' : '主管');
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function buildOriginatorApproverConfig(node, approver) {
|
|
488
|
+
const raw = isPlainObject(approver) ? approver : {};
|
|
489
|
+
return {
|
|
490
|
+
approvalType: 'ext_target_approval_originator',
|
|
491
|
+
approvals: [['originator']],
|
|
492
|
+
processProps: raw.processProps || raw.props || {},
|
|
493
|
+
approverRules: Object.assign(
|
|
494
|
+
createBaseApproverRules('ext_target_approval_originator', raw.description || '发起人本人', raw),
|
|
495
|
+
raw.approverRules || {}
|
|
496
|
+
),
|
|
497
|
+
description: raw.nodeDescription || node.description || '请选择审批人',
|
|
498
|
+
carbonReceiver: { type: 'VARIABLE', value: [['originator']] },
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
function buildUserApproverConfig(node, approver) {
|
|
503
|
+
const users = normalizeUserApprovers(approver);
|
|
504
|
+
if (users.length === 0) {
|
|
505
|
+
throw new Error('审批人 user 配置至少需要一个 users/userIds/approvals');
|
|
506
|
+
}
|
|
507
|
+
const userIds = users.map(function (user) { return user.id; });
|
|
508
|
+
const description = approver.description || users.map(function (user) { return user.label; }).join(', ');
|
|
509
|
+
const approvalMode = normalizeApprovalMode(approver.multiApproverType || approver.approvalMode || 'all');
|
|
510
|
+
const approverRules = Object.assign(
|
|
511
|
+
createBaseApproverRules('ext_target_approval', description, approver),
|
|
512
|
+
{
|
|
513
|
+
approvals: users,
|
|
514
|
+
approvalType_ext_target_approval: approvalMode,
|
|
515
|
+
},
|
|
516
|
+
approver.approverRules || {}
|
|
517
|
+
);
|
|
518
|
+
return {
|
|
519
|
+
approvalType: 'ext_target_approval',
|
|
520
|
+
approvals: userIds,
|
|
521
|
+
processProps: Object.assign({ multiApprove: approvalMode }, approver.processProps || approver.props || {}),
|
|
522
|
+
approverRules: approverRules,
|
|
523
|
+
description: approver.nodeDescription || node.description || '请选择审批人',
|
|
524
|
+
carbonReceiver: { type: 'NORMAL', value: userIds },
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function buildRoleApproverConfig(node, approver) {
|
|
529
|
+
const roles = normalizeRoleApprovers(approver);
|
|
530
|
+
if (roles.length === 0) {
|
|
531
|
+
throw new Error('审批人 role 配置至少需要一个 roles/roleIds/approvals');
|
|
532
|
+
}
|
|
533
|
+
const roleIds = roles.map(function (role) { return role.id; });
|
|
534
|
+
const description = approver.description || roles.map(function (role) { return role.label; }).join(', ');
|
|
535
|
+
const approvalMode = normalizeApprovalMode(approver.multiApproverType || approver.approvalMode || 'all');
|
|
536
|
+
const approverRules = Object.assign(
|
|
537
|
+
createBaseApproverRules('ext_target_approval_role', description, approver),
|
|
538
|
+
{
|
|
539
|
+
roles: roles,
|
|
540
|
+
approvalType_ext_target_approval_role: approvalMode,
|
|
541
|
+
},
|
|
542
|
+
approver.approverRules || {}
|
|
543
|
+
);
|
|
544
|
+
return {
|
|
545
|
+
approvalType: 'ext_target_approval_role',
|
|
546
|
+
processProps: Object.assign({
|
|
547
|
+
multiRoles: buildMultiRoles(roles),
|
|
548
|
+
multiApprove: approvalMode,
|
|
549
|
+
}, approver.processProps || approver.props || {}),
|
|
550
|
+
approverRules: approverRules,
|
|
551
|
+
description: approver.nodeDescription || node.description || '请选择审批人',
|
|
552
|
+
carbonReceiver: { type: 'ROLE', value: roleIds },
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
function buildDeptLeaderApproverConfig(node, approver) {
|
|
557
|
+
const source = getApproverSource(approver, false);
|
|
558
|
+
const level = String(pickFirstDefined(approver.level, approver.supervisorLevel, 1));
|
|
559
|
+
const approvalMode = normalizeApprovalMode(approver.multiApproverType || approver.approvalMode || 'all');
|
|
560
|
+
const needLeaderReplace = pickFirstDefined(approver.needLeaderReplace, true);
|
|
561
|
+
const ignoreNoLeaderDept = pickFirstDefined(approver.ignoreNoLeaderDept, false);
|
|
562
|
+
const description = approver.description || formatLevelDescription(source.label, level, false);
|
|
563
|
+
const approverRules = Object.assign(
|
|
564
|
+
createBaseApproverRules('ext_target_dept_leader', description, approver),
|
|
565
|
+
{
|
|
566
|
+
approvalType_ext_target_dept_leader: approvalMode,
|
|
567
|
+
supervisorType: source,
|
|
568
|
+
supervisorLevel: level,
|
|
569
|
+
ignoreNoLeaderDept: String(ignoreNoLeaderDept),
|
|
570
|
+
needLeaderReplace: Boolean(needLeaderReplace),
|
|
571
|
+
},
|
|
572
|
+
approver.approverRules || {}
|
|
573
|
+
);
|
|
574
|
+
return {
|
|
575
|
+
approvalType: 'ext_target_dept_leader',
|
|
576
|
+
processProps: Object.assign({
|
|
577
|
+
key: 'DeptLeaderApproverRule_1.0.0',
|
|
578
|
+
userIdVar: source.value,
|
|
579
|
+
reportLevel: Number(level),
|
|
580
|
+
ignoreNoLeaderDept: String(ignoreNoLeaderDept),
|
|
581
|
+
needLeaderReplace: String(Boolean(needLeaderReplace)),
|
|
582
|
+
multiApprove: approvalMode,
|
|
583
|
+
}, approver.processProps || approver.props || {}),
|
|
584
|
+
approverRules: approverRules,
|
|
585
|
+
description: approver.nodeDescription || node.description || '请选择审批人',
|
|
586
|
+
carbonReceiver: {
|
|
587
|
+
type: 'MANAGER',
|
|
588
|
+
value: {
|
|
589
|
+
originator: source.value,
|
|
590
|
+
level: Number(level),
|
|
591
|
+
},
|
|
592
|
+
},
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function buildDirectLeaderApproverConfig(node, approver) {
|
|
597
|
+
const source = getApproverSource(approver, true);
|
|
598
|
+
const level = String(pickFirstDefined(approver.level, approver.directSupervisorLevel, 1));
|
|
599
|
+
const approvalMode = normalizeApprovalMode(approver.multiApproverType || approver.approvalMode || 'all');
|
|
600
|
+
const needDeptLeaderReplace = pickFirstDefined(approver.needDeptLeaderReplace, true);
|
|
601
|
+
const description = approver.description || formatLevelDescription(source.label, level, true);
|
|
602
|
+
const approverRules = Object.assign(
|
|
603
|
+
createBaseApproverRules('ext_target_direct_leader', description, approver),
|
|
604
|
+
{
|
|
605
|
+
approvalType_ext_target_direct_leader: approvalMode,
|
|
606
|
+
directSupervisorType: source,
|
|
607
|
+
directSupervisorLevel: level,
|
|
608
|
+
needDeptLeaderReplace: Boolean(needDeptLeaderReplace),
|
|
609
|
+
},
|
|
610
|
+
approver.approverRules || {}
|
|
611
|
+
);
|
|
612
|
+
return {
|
|
613
|
+
approvalType: 'ext_target_direct_leader',
|
|
614
|
+
processProps: Object.assign({
|
|
615
|
+
key: 'DirectLeaderApproverRule_1.0.0',
|
|
616
|
+
userIdVar: source.value,
|
|
617
|
+
reportLevel: Number(level),
|
|
618
|
+
needDeptLeaderReplace: String(Boolean(needDeptLeaderReplace)),
|
|
619
|
+
multiApprove: approvalMode,
|
|
620
|
+
}, approver.processProps || approver.props || {}),
|
|
621
|
+
approverRules: approverRules,
|
|
622
|
+
description: approver.nodeDescription || node.description || '请选择审批人',
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
function buildFriendlyApproverConfig(node, approver) {
|
|
627
|
+
const kind = getFriendlyApproverKind(approver);
|
|
628
|
+
if (!kind) {
|
|
629
|
+
return null;
|
|
630
|
+
}
|
|
631
|
+
const raw = isPlainObject(approver) ? approver : {};
|
|
632
|
+
if (kind === 'originator') {
|
|
633
|
+
return buildOriginatorApproverConfig(node, raw);
|
|
634
|
+
}
|
|
635
|
+
if (kind === 'user') {
|
|
636
|
+
return buildUserApproverConfig(node, raw);
|
|
637
|
+
}
|
|
638
|
+
if (kind === 'role') {
|
|
639
|
+
return buildRoleApproverConfig(node, raw);
|
|
640
|
+
}
|
|
641
|
+
if (kind === 'deptLeader') {
|
|
642
|
+
return buildDeptLeaderApproverConfig(node, raw);
|
|
643
|
+
}
|
|
644
|
+
if (kind === 'directLeader') {
|
|
645
|
+
return buildDirectLeaderApproverConfig(node, raw);
|
|
646
|
+
}
|
|
647
|
+
return null;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
// ── 构建审批/抄送动作列表 ────────────────────────────
|
|
651
|
+
|
|
652
|
+
function buildActions() {
|
|
653
|
+
const actionDefs = [
|
|
654
|
+
{ action: 'agree', zh: '同意', en: 'Agree', ja: '同意', hidden: false },
|
|
655
|
+
{ action: 'disagree', zh: '拒绝', en: 'Disagree', ja: '拒否', hidden: false },
|
|
656
|
+
{ action: 'save', zh: '保存', en: 'Save', ja: '保存', hidden: true },
|
|
657
|
+
{ action: 'forward', zh: '转交', en: 'Forward', ja: '転送', hidden: true },
|
|
658
|
+
{ action: 'append', zh: '加签', en: 'Append', ja: '承認者を追加', hidden: true },
|
|
659
|
+
{ action: 'return', zh: '退回', en: 'Return', ja: '差し戻し', hidden: true },
|
|
660
|
+
];
|
|
661
|
+
|
|
662
|
+
return actionDefs.map(function (def) {
|
|
663
|
+
return {
|
|
664
|
+
hidden: def.hidden,
|
|
665
|
+
name: i18n(def.zh, def.en, def.ja),
|
|
666
|
+
action: def.action,
|
|
667
|
+
text: i18n(def.zh, def.en, def.ja),
|
|
668
|
+
alias: i18n(def.zh, def.en, def.ja),
|
|
669
|
+
};
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// ── 构建条件规则(严格匹配宜搭真实格式)─────────────
|
|
674
|
+
|
|
675
|
+
function buildConditionRules(rules, logic) {
|
|
676
|
+
const conditionCode = logic === 'OR' ? '||' : '&&';
|
|
677
|
+
const groupId = 'group-' + generateUuid();
|
|
678
|
+
|
|
679
|
+
const builtRules = rules.map(function (rule) {
|
|
680
|
+
const opDisplay = OP_CODE_TO_DISPLAY[rule.op] || rule.op;
|
|
681
|
+
const ruleType = COMPONENT_TO_RULE_TYPE[rule.componentType] || 'rule_text';
|
|
682
|
+
|
|
683
|
+
const ruleObj = {
|
|
684
|
+
id: rule.fieldId,
|
|
685
|
+
op: opDisplay,
|
|
686
|
+
operators: [],
|
|
687
|
+
value: rule.value,
|
|
688
|
+
componentType: rule.componentType || 'TextField',
|
|
689
|
+
ruleId: 'item-' + generateUuid(),
|
|
690
|
+
parentId: groupId,
|
|
691
|
+
extValue: 'value',
|
|
692
|
+
ruleValue: rule.value,
|
|
693
|
+
name: rule.fieldName || rule.fieldId,
|
|
694
|
+
valueType: 'literal',
|
|
695
|
+
ruleType: ruleType,
|
|
696
|
+
opCode: rule.op,
|
|
697
|
+
};
|
|
698
|
+
|
|
699
|
+
// NumberField 需要 formula 字段,宜搭服务端用它构建数字比较公式
|
|
700
|
+
if (rule.componentType === 'NumberField') {
|
|
701
|
+
const opSymbolMap = {
|
|
702
|
+
GreaterThan: '>',
|
|
703
|
+
Bigger: '>',
|
|
704
|
+
GreaterThanOrEqual: '>=',
|
|
705
|
+
LessThan: '<',
|
|
706
|
+
LessThanOrEqual: '<=',
|
|
707
|
+
Equal: '==',
|
|
708
|
+
NotEqual: '!=',
|
|
709
|
+
};
|
|
710
|
+
const opSymbol = opSymbolMap[rule.op] || '==';
|
|
711
|
+
ruleObj.formula = '${' + rule.fieldId + '}' + opSymbol + rule.value;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
return ruleObj;
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
return {
|
|
718
|
+
condition: logic === 'OR' ? 'OR' : 'AND',
|
|
719
|
+
rules: builtRules,
|
|
720
|
+
ruleId: groupId,
|
|
721
|
+
conditionCode: conditionCode,
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// ── 构建跳转规则(routeRule)──────────────────────────
|
|
726
|
+
|
|
727
|
+
function buildRouteRule(routeRuleDefs, currentNodeId, nodeNameToIdMap) {
|
|
728
|
+
if (!routeRuleDefs || routeRuleDefs.length === 0) {
|
|
729
|
+
return {
|
|
730
|
+
rules: [],
|
|
731
|
+
triggerRule: 'n',
|
|
732
|
+
ruleIfMiss: 'terminate',
|
|
733
|
+
defaultNextId: [],
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
const rules = routeRuleDefs.map(function (ruleDef, index) {
|
|
738
|
+
// 解析跳转目标
|
|
739
|
+
const targetNodeId = nodeNameToIdMap[ruleDef.jumpTo];
|
|
740
|
+
if (!targetNodeId) {
|
|
741
|
+
emitCompilerWarning(nodeNameToIdMap, ' ⚠️ routeRule 跳转目标 "' + ruleDef.jumpTo + '" 未找到对应节点');
|
|
742
|
+
return null;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// 构建条件规则
|
|
746
|
+
const conditionGroupId = 'group-' + generateUuid();
|
|
747
|
+
const conditionRules = [];
|
|
748
|
+
|
|
749
|
+
if (ruleDef.when === 'disagree' || ruleDef.when === 'agree') {
|
|
750
|
+
// 基于审批结果的跳转(内置虚拟字段 approvalResult)
|
|
751
|
+
conditionRules.push({
|
|
752
|
+
componentType: 'SelectField',
|
|
753
|
+
id: 'approvalResult',
|
|
754
|
+
extValue: 'value',
|
|
755
|
+
name: '审批结果',
|
|
756
|
+
op: '等于',
|
|
757
|
+
opCode: 'Equal',
|
|
758
|
+
parentId: conditionGroupId,
|
|
759
|
+
ruleId: 'item-' + generateUuid(),
|
|
760
|
+
ruleType: 'rule_text',
|
|
761
|
+
ruleValue: ruleDef.when,
|
|
762
|
+
value: ruleDef.when,
|
|
763
|
+
valueType: 'literal',
|
|
764
|
+
});
|
|
765
|
+
} else if (ruleDef.fieldRules && ruleDef.fieldRules.length > 0) {
|
|
766
|
+
// 基于表单字段的跳转条件
|
|
767
|
+
ruleDef.fieldRules.forEach(function (fieldRule) {
|
|
768
|
+
const opDisplay = OP_CODE_TO_DISPLAY[fieldRule.op] || fieldRule.op;
|
|
769
|
+
const ruleType = COMPONENT_TO_RULE_TYPE[fieldRule.componentType] || 'rule_text';
|
|
770
|
+
conditionRules.push({
|
|
771
|
+
componentType: fieldRule.componentType,
|
|
772
|
+
id: fieldRule.fieldId,
|
|
773
|
+
extValue: 'value',
|
|
774
|
+
name: fieldRule.fieldName,
|
|
775
|
+
op: opDisplay,
|
|
776
|
+
opCode: fieldRule.op,
|
|
777
|
+
parentId: conditionGroupId,
|
|
778
|
+
ruleId: 'item-' + generateUuid(),
|
|
779
|
+
ruleType: ruleType,
|
|
780
|
+
ruleValue: fieldRule.value,
|
|
781
|
+
value: fieldRule.value,
|
|
782
|
+
valueType: 'literal',
|
|
783
|
+
});
|
|
784
|
+
});
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
const conditionNodeId = generateNodeId();
|
|
788
|
+
return {
|
|
789
|
+
type: 'condition',
|
|
790
|
+
nodeId: conditionNodeId,
|
|
791
|
+
prevId: currentNodeId,
|
|
792
|
+
nextId: [targetNodeId],
|
|
793
|
+
props: {
|
|
794
|
+
calculate: 'condition',
|
|
795
|
+
isDefault: false,
|
|
796
|
+
conditions: {
|
|
797
|
+
condition: (ruleDef.logic || 'AND'),
|
|
798
|
+
conditionCode: (ruleDef.logic === 'OR' ? '||' : '&&'),
|
|
799
|
+
ruleId: conditionGroupId,
|
|
800
|
+
rules: conditionRules,
|
|
801
|
+
},
|
|
802
|
+
priority: index + 1,
|
|
803
|
+
},
|
|
804
|
+
};
|
|
805
|
+
}).filter(function (rule) { return rule !== null; });
|
|
806
|
+
|
|
807
|
+
return {
|
|
808
|
+
rules: rules,
|
|
809
|
+
triggerRule: rules.length > 0 ? 'y' : 'n',
|
|
810
|
+
ruleIfMiss: 'terminate',
|
|
811
|
+
defaultNextId: [],
|
|
812
|
+
};
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
// ── 递归分配 nodeId ──────────────────────────────────
|
|
816
|
+
|
|
817
|
+
function emitCompilerWarning(nodeNameToIdMap, message) {
|
|
818
|
+
const options = nodeNameToIdMap && nodeNameToIdMap.__compilerOptions;
|
|
819
|
+
if (options && typeof options.onWarning === 'function') {
|
|
820
|
+
options.onWarning(message);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
function componentNameForNodeType(nodeType) {
|
|
825
|
+
if (nodeType === 'approval') {return 'ApprovalNode';}
|
|
826
|
+
if (nodeType === 'operator') {return 'OperatorNode';}
|
|
827
|
+
if (nodeType === 'multiApproval') {return 'MultiApprovalNode';}
|
|
828
|
+
if (nodeType === 'carbon') {return 'CarbonNode';}
|
|
829
|
+
if (nodeType === 'route' || nodeType === 'parallel') {return 'ConditionContainer';}
|
|
830
|
+
return GENERIC_NODE_CONFIGS[nodeType] ? nodeType : null;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
function validateManagedNodeBindings(desiredNodes, nodeBindings) {
|
|
834
|
+
if (
|
|
835
|
+
!Array.isArray(desiredNodes) ||
|
|
836
|
+
!nodeBindings ||
|
|
837
|
+
typeof nodeBindings !== 'object' ||
|
|
838
|
+
Array.isArray(nodeBindings)
|
|
839
|
+
) {
|
|
840
|
+
return false;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
const expected = Object.create(null);
|
|
844
|
+
for (const node of desiredNodes) {
|
|
845
|
+
const key = node && typeof node.key === 'string' ? node.key : '';
|
|
846
|
+
const componentName = componentNameForNodeType(node && node.type);
|
|
847
|
+
if (!key || !componentName || Object.prototype.hasOwnProperty.call(expected, key)) {
|
|
848
|
+
return false;
|
|
849
|
+
}
|
|
850
|
+
expected[key] = componentName;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
const expectedKeys = Object.keys(expected).sort();
|
|
854
|
+
const bindingKeys = Object.keys(nodeBindings).sort();
|
|
855
|
+
if (
|
|
856
|
+
expectedKeys.length === 0 ||
|
|
857
|
+
expectedKeys.length !== bindingKeys.length ||
|
|
858
|
+
expectedKeys.some((key, index) => key !== bindingKeys[index])
|
|
859
|
+
) {
|
|
860
|
+
return false;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
const usedNodeIds = new Set();
|
|
864
|
+
for (const key of expectedKeys) {
|
|
865
|
+
const binding = nodeBindings[key];
|
|
866
|
+
if (!binding || typeof binding !== 'object' || Array.isArray(binding)) {
|
|
867
|
+
return false;
|
|
868
|
+
}
|
|
869
|
+
const properties = Object.keys(binding).sort();
|
|
870
|
+
if (
|
|
871
|
+
properties.length !== 2 ||
|
|
872
|
+
properties[0] !== 'componentName' ||
|
|
873
|
+
properties[1] !== 'nodeId' ||
|
|
874
|
+
typeof binding.nodeId !== 'string' ||
|
|
875
|
+
binding.nodeId.trim() === '' ||
|
|
876
|
+
binding.componentName !== expected[key] ||
|
|
877
|
+
usedNodeIds.has(binding.nodeId)
|
|
878
|
+
) {
|
|
879
|
+
return false;
|
|
880
|
+
}
|
|
881
|
+
usedNodeIds.add(binding.nodeId);
|
|
882
|
+
}
|
|
883
|
+
return true;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
function resolveExistingNodeId(existingBindings, semanticKey) {
|
|
887
|
+
if (!existingBindings || !Object.prototype.hasOwnProperty.call(existingBindings, semanticKey)) {
|
|
888
|
+
return null;
|
|
889
|
+
}
|
|
890
|
+
const binding = existingBindings[semanticKey];
|
|
891
|
+
if (typeof binding === 'string' && binding) {
|
|
892
|
+
return binding;
|
|
893
|
+
}
|
|
894
|
+
if (binding && typeof binding.nodeId === 'string' && binding.nodeId) {
|
|
895
|
+
return binding.nodeId;
|
|
896
|
+
}
|
|
897
|
+
return null;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
function assignNodeId(node, nodeType, nodeNameToIdMap) {
|
|
901
|
+
const options = nodeNameToIdMap.__compilerOptions || {};
|
|
902
|
+
if (!options.semanticBindings) {
|
|
903
|
+
return generateNodeId();
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
const semanticKey = typeof node.key === 'string' ? node.key.trim() : '';
|
|
907
|
+
if (!semanticKey) {
|
|
908
|
+
throw new ProcessCompilerError(
|
|
909
|
+
'PROCESS_COMPILE_NODE_KEY_REQUIRED',
|
|
910
|
+
'Managed process nodes require an explicit semantic key.'
|
|
911
|
+
);
|
|
912
|
+
}
|
|
913
|
+
if (!KEY_PATTERN.test(semanticKey) || semanticKey.includes('.')) {
|
|
914
|
+
throw new ProcessCompilerError(
|
|
915
|
+
'PROCESS_COMPILE_DEFINITION_INVALID',
|
|
916
|
+
'Managed process node semantic key is invalid.',
|
|
917
|
+
{ semanticPath: 'nodes' }
|
|
918
|
+
);
|
|
919
|
+
}
|
|
920
|
+
if (nodeNameToIdMap.__semanticKeys.has(semanticKey)) {
|
|
921
|
+
throw new ProcessCompilerError(
|
|
922
|
+
'PROCESS_COMPILE_NODE_KEY_DUPLICATE',
|
|
923
|
+
'Managed process node semantic keys must be unique.',
|
|
924
|
+
{ key: semanticKey }
|
|
925
|
+
);
|
|
926
|
+
}
|
|
927
|
+
nodeNameToIdMap.__semanticKeys.add(semanticKey);
|
|
928
|
+
|
|
929
|
+
const existingNodeId = resolveExistingNodeId(options.existingBindings, semanticKey);
|
|
930
|
+
let nodeId = existingNodeId;
|
|
931
|
+
if (nodeId && nodeNameToIdMap.__usedNodeIds.has(nodeId)) {
|
|
932
|
+
throw new ProcessCompilerError(
|
|
933
|
+
'PROCESS_COMPILE_NODE_BINDING_CONFLICT',
|
|
934
|
+
'Managed process node bindings contain a duplicate node identity.',
|
|
935
|
+
{ semanticPath: 'nodes.' + semanticKey }
|
|
936
|
+
);
|
|
937
|
+
}
|
|
938
|
+
if (!nodeId) {
|
|
939
|
+
do {
|
|
940
|
+
nodeId = generateNodeId();
|
|
941
|
+
} while (nodeNameToIdMap.__usedNodeIds.has(nodeId));
|
|
942
|
+
}
|
|
943
|
+
nodeNameToIdMap.__usedNodeIds.add(nodeId);
|
|
944
|
+
nodeNameToIdMap.__nodeBindings[semanticKey] = {
|
|
945
|
+
nodeId,
|
|
946
|
+
componentName: componentNameForNodeType(nodeType),
|
|
947
|
+
};
|
|
948
|
+
return nodeId;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
function assignNodeIdsRecursive(nodes, nameToIdMap) {
|
|
952
|
+
nodes.forEach(function (node) {
|
|
953
|
+
const nodeType = normalizeNodeType(node);
|
|
954
|
+
if (nodeType === 'route') {
|
|
955
|
+
node._nodeId = assignNodeId(node, nodeType, nameToIdMap);
|
|
956
|
+
const conditions = node.conditions || [];
|
|
957
|
+
conditions.forEach(function (cond) {
|
|
958
|
+
cond._nodeId = generateNodeId();
|
|
959
|
+
if (cond.childNodes && cond.childNodes.length > 0) {
|
|
960
|
+
assignNodeIdsRecursive(cond.childNodes, nameToIdMap);
|
|
961
|
+
}
|
|
962
|
+
});
|
|
963
|
+
} else if (nodeType === 'parallel') {
|
|
964
|
+
node._nodeId = assignNodeId(node, nodeType, nameToIdMap);
|
|
965
|
+
if (node.name) {
|
|
966
|
+
nameToIdMap[node.name] = node._nodeId;
|
|
967
|
+
}
|
|
968
|
+
const branches = getParallelBranches(node);
|
|
969
|
+
branches.forEach(function (branch) {
|
|
970
|
+
branch._nodeId = generateNodeId();
|
|
971
|
+
const childNodes = getBranchChildNodes(branch);
|
|
972
|
+
if (childNodes.length > 0) {
|
|
973
|
+
assignNodeIdsRecursive(childNodes, nameToIdMap);
|
|
974
|
+
}
|
|
975
|
+
});
|
|
976
|
+
} else if (GENERIC_NODE_CONFIGS[nodeType]) {
|
|
977
|
+
node._nodeId = assignNodeId(node, nodeType, nameToIdMap);
|
|
978
|
+
if (node.name) {
|
|
979
|
+
nameToIdMap[node.name] = node._nodeId;
|
|
980
|
+
}
|
|
981
|
+
const childNodes = getGenericChildNodes(node);
|
|
982
|
+
if (childNodes.length > 0) {
|
|
983
|
+
assignNodeIdsRecursive(childNodes, nameToIdMap);
|
|
984
|
+
}
|
|
985
|
+
} else {
|
|
986
|
+
node._nodeId = assignNodeId(node, nodeType, nameToIdMap);
|
|
987
|
+
if (node.name) {
|
|
988
|
+
nameToIdMap[node.name] = node._nodeId;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
// ── 递归构建节点 ─────────────────────────────────────
|
|
995
|
+
|
|
996
|
+
function buildNodeListRecursive(nodes, exitNodeId, nameToIdMap) {
|
|
997
|
+
const processNodes = [];
|
|
998
|
+
const viewNodes = [];
|
|
999
|
+
|
|
1000
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
1001
|
+
const node = nodes[i];
|
|
1002
|
+
const nextNodeId = i + 1 < nodes.length ? nodes[i + 1]._nodeId : exitNodeId;
|
|
1003
|
+
const nodeType = normalizeNodeType(node);
|
|
1004
|
+
|
|
1005
|
+
if (nodeType === 'route') {
|
|
1006
|
+
const routeResult = buildRouteNode(node, nextNodeId, nameToIdMap);
|
|
1007
|
+
processNodes.push(routeResult.processNode);
|
|
1008
|
+
viewNodes.push(routeResult.viewNode);
|
|
1009
|
+
} else if (nodeType === 'parallel') {
|
|
1010
|
+
const parallelResult = buildParallelNode(node, nextNodeId, nameToIdMap);
|
|
1011
|
+
processNodes.push(parallelResult.processNode);
|
|
1012
|
+
viewNodes.push(parallelResult.viewNode);
|
|
1013
|
+
} else if (nodeType === 'approval' || nodeType === 'operator' || nodeType === 'multiApproval') {
|
|
1014
|
+
const approvalResult = buildApprovalNode(node, nextNodeId, nameToIdMap, nodeType);
|
|
1015
|
+
processNodes.push(approvalResult.processNode);
|
|
1016
|
+
viewNodes.push(approvalResult.viewNode);
|
|
1017
|
+
} else if (nodeType === 'carbon') {
|
|
1018
|
+
const carbonResult = buildCarbonNode(node, nextNodeId);
|
|
1019
|
+
processNodes.push(carbonResult.processNode);
|
|
1020
|
+
viewNodes.push(carbonResult.viewNode);
|
|
1021
|
+
} else if (GENERIC_NODE_CONFIGS[nodeType]) {
|
|
1022
|
+
const genericResult = buildGenericNode(node, nextNodeId, nameToIdMap, nodeType);
|
|
1023
|
+
processNodes.push(genericResult.processNode);
|
|
1024
|
+
viewNodes.push(genericResult.viewNode);
|
|
1025
|
+
} else {
|
|
1026
|
+
throw new Error('不支持的流程节点类型: ' + (node.type || node.componentName || node.kind || JSON.stringify(node)));
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
return { processNodes, viewNodes };
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
function wireChildProcessNodes(childProcessNodes, parentNodeId) {
|
|
1034
|
+
if (childProcessNodes.length === 0) {
|
|
1035
|
+
return;
|
|
1036
|
+
}
|
|
1037
|
+
childProcessNodes[0].prevId = parentNodeId;
|
|
1038
|
+
for (let i = 1; i < childProcessNodes.length; i++) {
|
|
1039
|
+
childProcessNodes[i].prevId = childProcessNodes[i - 1].nodeId;
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
// ── 构建审批节点 ─────────────────────────────────────
|
|
1044
|
+
|
|
1045
|
+
function buildApproverConfig(node) {
|
|
1046
|
+
const approverInput = node.approverConfig
|
|
1047
|
+
|| node.approver
|
|
1048
|
+
|| node.executor
|
|
1049
|
+
|| node.operator
|
|
1050
|
+
|| node.receiver
|
|
1051
|
+
|| node.receivers;
|
|
1052
|
+
const friendlyApprover = buildFriendlyApproverConfig(node, approverInput);
|
|
1053
|
+
if (friendlyApprover) {
|
|
1054
|
+
return friendlyApprover;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
const rawApprover = node.approverConfig || (approverInput && typeof approverInput === 'object' ? approverInput : null);
|
|
1058
|
+
if (rawApprover) {
|
|
1059
|
+
return {
|
|
1060
|
+
approvalType: rawApprover.approvalType || rawApprover.type || 'ext_target_approval_originator',
|
|
1061
|
+
approvals: rawApprover.approvals || [['originator']],
|
|
1062
|
+
processProps: rawApprover.processProps || rawApprover.props || {},
|
|
1063
|
+
approverRules: rawApprover.approverRules || {
|
|
1064
|
+
type: rawApprover.approvalType || rawApprover.type || 'ext_target_approval_originator',
|
|
1065
|
+
mode: 'ApprovalNode_rules_only',
|
|
1066
|
+
approverList: rawApprover.approverList || [{ type: 'ext_target_approval' }],
|
|
1067
|
+
multiApproverType: rawApprover.multiApproverType || 'all',
|
|
1068
|
+
conditionalMode: rawApprover.conditionalMode || 'conditional',
|
|
1069
|
+
description: rawApprover.description || '自定义审批人',
|
|
1070
|
+
},
|
|
1071
|
+
description: rawApprover.description || node.description || '请选择审批人',
|
|
1072
|
+
carbonReceiver: rawApprover.carbonReceiver,
|
|
1073
|
+
};
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
if (node.approvalType || node.approvals || node.approverRules || node.processProps) {
|
|
1077
|
+
return {
|
|
1078
|
+
approvalType: node.approvalType || 'ext_target_approval_originator',
|
|
1079
|
+
approvals: node.approvals || [['originator']],
|
|
1080
|
+
processProps: node.processProps || {},
|
|
1081
|
+
approverRules: node.approverRules || {
|
|
1082
|
+
type: node.approvalType || 'ext_target_approval_originator',
|
|
1083
|
+
mode: 'ApprovalNode_rules_only',
|
|
1084
|
+
approverList: [{ type: 'ext_target_approval' }],
|
|
1085
|
+
multiApproverType: 'all',
|
|
1086
|
+
conditionalMode: 'conditional',
|
|
1087
|
+
description: node.description || '自定义审批人',
|
|
1088
|
+
},
|
|
1089
|
+
description: node.description || '请选择审批人',
|
|
1090
|
+
carbonReceiver: node.carbonReceiver,
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
return buildOriginatorApproverConfig(node, {});
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
function buildApprovalNode(node, nextNodeId, nameToIdMap, nodeType) {
|
|
1098
|
+
const nodeId = node._nodeId;
|
|
1099
|
+
const routeRule = buildRouteRule(node.routeRules || [], nodeId, nameToIdMap);
|
|
1100
|
+
const approverConfig = buildApproverConfig(node);
|
|
1101
|
+
const approvalNodeType = nodeType || normalizeNodeType(node);
|
|
1102
|
+
const componentName = approvalNodeType === 'operator'
|
|
1103
|
+
? 'OperatorNode'
|
|
1104
|
+
: (approvalNodeType === 'multiApproval' ? 'MultiApprovalNode' : 'ApprovalNode');
|
|
1105
|
+
const titleText = approvalNodeType === 'operator'
|
|
1106
|
+
? ['办理人', 'Executor', '実行者']
|
|
1107
|
+
: (approvalNodeType === 'multiApproval'
|
|
1108
|
+
? ['审批人', 'Approver', '承認者']
|
|
1109
|
+
: ['审批人', 'Approver', '承認者']);
|
|
1110
|
+
const defaultName = approvalNodeType === 'operator' ? '办理人' : '审批人';
|
|
1111
|
+
const displayName = getNodeName(node, defaultName);
|
|
1112
|
+
const nodeDescription = approverConfig.description || getNodeDescription(node) || '请选择审批人';
|
|
1113
|
+
|
|
1114
|
+
// 构建字段权限(formConfig.behaviorList)
|
|
1115
|
+
// 兼容两种输入格式:
|
|
1116
|
+
// 1. node.formConfig.behaviorList(推荐,与 SKILL.md 文档一致)
|
|
1117
|
+
// 2. node.fieldPermissions(旧格式,向后兼容)
|
|
1118
|
+
let formConfig = undefined;
|
|
1119
|
+
if (node.formConfig && node.formConfig.behaviorList && node.formConfig.behaviorList.length > 0) {
|
|
1120
|
+
const behaviorList = node.formConfig.behaviorList.map(function (fp) {
|
|
1121
|
+
return {
|
|
1122
|
+
fieldId: fp.fieldId,
|
|
1123
|
+
fieldBehavior: fp.fieldBehavior || fp.behavior || 'READONLY',
|
|
1124
|
+
};
|
|
1125
|
+
});
|
|
1126
|
+
formConfig = { behaviorList: behaviorList };
|
|
1127
|
+
} else if (node.fieldPermissions && node.fieldPermissions.length > 0) {
|
|
1128
|
+
const behaviorList = node.fieldPermissions.map(function (fp) {
|
|
1129
|
+
return {
|
|
1130
|
+
fieldId: fp.fieldId,
|
|
1131
|
+
fieldBehavior: fp.fieldBehavior || fp.behavior || 'READONLY',
|
|
1132
|
+
};
|
|
1133
|
+
});
|
|
1134
|
+
formConfig = { behaviorList: behaviorList };
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
const processNodeProps = {
|
|
1138
|
+
conditionalMode: 'conditional',
|
|
1139
|
+
actions: buildActions(),
|
|
1140
|
+
appendActions: buildActions(),
|
|
1141
|
+
openDigitalSign: false,
|
|
1142
|
+
noActionersType: 'stopProcess',
|
|
1143
|
+
routeRule: routeRule,
|
|
1144
|
+
};
|
|
1145
|
+
if (approverConfig.approvals !== undefined) {
|
|
1146
|
+
processNodeProps.approvals = approverConfig.approvals;
|
|
1147
|
+
}
|
|
1148
|
+
Object.assign(processNodeProps, approverConfig.processProps);
|
|
1149
|
+
if (formConfig) {
|
|
1150
|
+
processNodeProps.formConfig = formConfig;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
const processNode = {
|
|
1154
|
+
name: i18n(displayName, titleText[1], displayName),
|
|
1155
|
+
description: nodeDescription,
|
|
1156
|
+
type: 'approval',
|
|
1157
|
+
approvalType: approverConfig.approvalType,
|
|
1158
|
+
nodeId: nodeId,
|
|
1159
|
+
prevId: '',
|
|
1160
|
+
nextId: [nextNodeId],
|
|
1161
|
+
props: processNodeProps,
|
|
1162
|
+
childNodes: [],
|
|
1163
|
+
};
|
|
1164
|
+
|
|
1165
|
+
const viewNodeProps = {
|
|
1166
|
+
nodeName: componentName,
|
|
1167
|
+
name: i18n(displayName, titleText[1], displayName),
|
|
1168
|
+
description: nodeDescription,
|
|
1169
|
+
approverRules: approverConfig.approverRules,
|
|
1170
|
+
actions: {
|
|
1171
|
+
normalActions: buildActions(),
|
|
1172
|
+
appendActions: buildActions(),
|
|
1173
|
+
},
|
|
1174
|
+
routeRule: routeRule,
|
|
1175
|
+
};
|
|
1176
|
+
if (formConfig) {
|
|
1177
|
+
viewNodeProps.formConfig = formConfig;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
const viewNode = {
|
|
1181
|
+
componentName: componentName,
|
|
1182
|
+
id: nodeId,
|
|
1183
|
+
props: viewNodeProps,
|
|
1184
|
+
title: i18n(titleText[0], titleText[1], titleText[2]),
|
|
1185
|
+
};
|
|
1186
|
+
|
|
1187
|
+
return { processNode, viewNode };
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
// ── 构建抄送节点 ─────────────────────────────────────
|
|
1191
|
+
|
|
1192
|
+
function buildCarbonNode(node, nextNodeId) {
|
|
1193
|
+
const nodeId = node._nodeId;
|
|
1194
|
+
const approverConfig = buildApproverConfig(node);
|
|
1195
|
+
const carbonReceiver = approverConfig.carbonReceiver || { type: 'VARIABLE', value: approverConfig.approvals || [['originator']] };
|
|
1196
|
+
const displayName = getNodeName(node, '抄送人');
|
|
1197
|
+
const nodeDescription = getNodeDescription(node) || '请选择抄送人';
|
|
1198
|
+
|
|
1199
|
+
const processNode = {
|
|
1200
|
+
name: i18n(displayName, 'CC', displayName),
|
|
1201
|
+
description: '',
|
|
1202
|
+
type: 'carbon',
|
|
1203
|
+
approvalType: approverConfig.approvalType,
|
|
1204
|
+
nodeId: nodeId,
|
|
1205
|
+
prevId: '',
|
|
1206
|
+
nextId: [nextNodeId],
|
|
1207
|
+
props: {
|
|
1208
|
+
conditionalMode: 'conditional',
|
|
1209
|
+
params: [
|
|
1210
|
+
{ key: 'nodeId', value: nodeId },
|
|
1211
|
+
{ key: 'instId', value: '#procInstId' },
|
|
1212
|
+
{ key: 'userId', value: '#originator' },
|
|
1213
|
+
{ key: 'receiver', value: carbonReceiver },
|
|
1214
|
+
],
|
|
1215
|
+
...approverConfig.processProps,
|
|
1216
|
+
},
|
|
1217
|
+
childNodes: [],
|
|
1218
|
+
};
|
|
1219
|
+
|
|
1220
|
+
const viewNode = {
|
|
1221
|
+
componentName: 'CarbonNode',
|
|
1222
|
+
id: nodeId,
|
|
1223
|
+
props: {
|
|
1224
|
+
nodeName: 'CarbonNode',
|
|
1225
|
+
name: i18n(displayName, 'CC', displayName),
|
|
1226
|
+
description: nodeDescription,
|
|
1227
|
+
approverRules: approverConfig.approverRules,
|
|
1228
|
+
},
|
|
1229
|
+
title: i18n('抄送人', 'CC', '共有先'),
|
|
1230
|
+
};
|
|
1231
|
+
|
|
1232
|
+
return { processNode, viewNode };
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
// ── 构建真实组件节点(连接器、数据、消息、代码、子流程等)──
|
|
1236
|
+
|
|
1237
|
+
function getGenericChildNodes(node) {
|
|
1238
|
+
const childNodes = node.childNodes || node.children || node.nodes || [];
|
|
1239
|
+
return Array.isArray(childNodes) ? childNodes : [];
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
function buildGenericNodeProps(node, componentName) {
|
|
1243
|
+
const config = GENERIC_NODE_CONFIGS[componentName] || {};
|
|
1244
|
+
const props = Object.assign({}, node.props || {});
|
|
1245
|
+
const displayName = getNodeName(node, config.title ? config.title[0] : componentName);
|
|
1246
|
+
const description = getNodeDescription(node);
|
|
1247
|
+
|
|
1248
|
+
if (!props.name) {
|
|
1249
|
+
props.name = i18n(displayName, config.title ? config.title[1] : displayName, displayName);
|
|
1250
|
+
}
|
|
1251
|
+
if (!props.nodeName) {
|
|
1252
|
+
props.nodeName = componentName;
|
|
1253
|
+
}
|
|
1254
|
+
if (!props.description && description) {
|
|
1255
|
+
props.description = description;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
Object.keys(config.propAliases || {}).forEach(function (sourceKey) {
|
|
1259
|
+
const targetKey = config.propAliases[sourceKey];
|
|
1260
|
+
if (node[sourceKey] !== undefined && props[targetKey] === undefined) {
|
|
1261
|
+
props[targetKey] = clonePlain(node[sourceKey]);
|
|
1262
|
+
}
|
|
1263
|
+
});
|
|
1264
|
+
|
|
1265
|
+
(config.propKeys || []).forEach(function (key) {
|
|
1266
|
+
if (node[key] !== undefined && props[key] === undefined) {
|
|
1267
|
+
props[key] = clonePlain(node[key]);
|
|
1268
|
+
}
|
|
1269
|
+
});
|
|
1270
|
+
|
|
1271
|
+
if (node.viewProps && isPlainObject(node.viewProps)) {
|
|
1272
|
+
Object.assign(props, clonePlain(node.viewProps));
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
return props;
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
function getGenericProcessType(componentName, node, props) {
|
|
1279
|
+
if (node.processType || node.processNodeType) {
|
|
1280
|
+
return node.processType || node.processNodeType;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
if (componentName === 'ConnectorNode') {
|
|
1284
|
+
const connectorRules = props.connectorRules || {};
|
|
1285
|
+
const connector = connectorRules.connector || {};
|
|
1286
|
+
const mode = connector.mode || connectorRules.mode;
|
|
1287
|
+
return CONNECTOR_MODE_TO_PROCESS_TYPE[mode] || GENERIC_NODE_CONFIGS[componentName].processType;
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
return GENERIC_NODE_CONFIGS[componentName].processType;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
function pickRuleAssignments(ruleContainer) {
|
|
1294
|
+
if (!ruleContainer) {
|
|
1295
|
+
return [];
|
|
1296
|
+
}
|
|
1297
|
+
if (Array.isArray(ruleContainer.assignments)) {
|
|
1298
|
+
return clonePlain(ruleContainer.assignments);
|
|
1299
|
+
}
|
|
1300
|
+
if (ruleContainer.inputs && Array.isArray(ruleContainer.inputs.assignments)) {
|
|
1301
|
+
return clonePlain(ruleContainer.inputs.assignments);
|
|
1302
|
+
}
|
|
1303
|
+
if (Array.isArray(ruleContainer.rules)) {
|
|
1304
|
+
return ruleContainer.rules
|
|
1305
|
+
.map(function (rule) {
|
|
1306
|
+
if (Array.isArray(rule && rule.rules)) {
|
|
1307
|
+
return clonePlain(rule.rules);
|
|
1308
|
+
}
|
|
1309
|
+
return null;
|
|
1310
|
+
})
|
|
1311
|
+
.filter(Boolean)
|
|
1312
|
+
.reduce(function (all, rules) {
|
|
1313
|
+
return all.concat(rules);
|
|
1314
|
+
}, []);
|
|
1315
|
+
}
|
|
1316
|
+
return [];
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
function buildConnectorProcessProps(props) {
|
|
1320
|
+
const connectorRules = props.connectorRules || {};
|
|
1321
|
+
const inputs = Object.assign({}, clonePlain(connectorRules.inputs || {}), {
|
|
1322
|
+
url: connectorRules.url,
|
|
1323
|
+
method: connectorRules.method,
|
|
1324
|
+
body: connectorRules.body,
|
|
1325
|
+
connection: connectorRules.connectionId || connectorRules.connection,
|
|
1326
|
+
connectorId: connectorRules.connectorId,
|
|
1327
|
+
actionId: connectorRules.actionId,
|
|
1328
|
+
});
|
|
1329
|
+
const assignments = pickRuleAssignments(connectorRules);
|
|
1330
|
+
|
|
1331
|
+
if (assignments.length > 0) {
|
|
1332
|
+
inputs.assignments = assignments;
|
|
1333
|
+
}
|
|
1334
|
+
if (connectorRules.openDevSchemaType === 'integrationObject') {
|
|
1335
|
+
inputs.openDevSchemaType = 'integrationObject';
|
|
1336
|
+
inputs.connectorOrgId = connectorRules.connector && connectorRules.connector.orgId;
|
|
1337
|
+
inputs.integrationObject = connectorRules.integrationObject;
|
|
1338
|
+
inputs.integrationObjectPath = connectorRules.integrationObjectPath;
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
Object.keys(inputs).forEach(function (key) {
|
|
1342
|
+
if (inputs[key] === undefined) {
|
|
1343
|
+
delete inputs[key];
|
|
1344
|
+
}
|
|
1345
|
+
});
|
|
1346
|
+
|
|
1347
|
+
return { inputs };
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
function buildCodeExecutorProcessProps(props, componentName) {
|
|
1351
|
+
const codeConfig = componentName === 'GroovyNode' ? props.groovy : props.JavaScript;
|
|
1352
|
+
if (!codeConfig) {
|
|
1353
|
+
return {};
|
|
1354
|
+
}
|
|
1355
|
+
const outputs = Array.isArray(codeConfig.outputs)
|
|
1356
|
+
? codeConfig.outputs.map(function (output) {
|
|
1357
|
+
return {
|
|
1358
|
+
description: output.desc || output.description,
|
|
1359
|
+
name: output.name,
|
|
1360
|
+
type: output.type,
|
|
1361
|
+
valueType: output.valueType,
|
|
1362
|
+
};
|
|
1363
|
+
})
|
|
1364
|
+
: undefined;
|
|
1365
|
+
return {
|
|
1366
|
+
inputs: clonePlain(codeConfig.inputs),
|
|
1367
|
+
action: clonePlain(codeConfig.action),
|
|
1368
|
+
scriptType: codeConfig.scriptType,
|
|
1369
|
+
outputsSchema: outputs,
|
|
1370
|
+
};
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
function buildGetDataProcessProps(props) {
|
|
1374
|
+
const getData = props.getData || {};
|
|
1375
|
+
return {
|
|
1376
|
+
type: props.type,
|
|
1377
|
+
filterType: getData.filterType,
|
|
1378
|
+
sort: clonePlain(getData.sort),
|
|
1379
|
+
sourceId: getData.sourceId,
|
|
1380
|
+
appType: getData.appType,
|
|
1381
|
+
originalType: getData.originalType,
|
|
1382
|
+
subSourceId: getData.subSourceId,
|
|
1383
|
+
condition: clonePlain(getData.condition),
|
|
1384
|
+
quantity: getData.quantity === undefined ? undefined : String(getData.quantity),
|
|
1385
|
+
dataRules: clonePlain(getData.dataRules),
|
|
1386
|
+
assignments: clonePlain(getData.assignments),
|
|
1387
|
+
};
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
function buildAddDataProcessProps(props) {
|
|
1391
|
+
const addDataRules = props.addDataRules || {};
|
|
1392
|
+
return {
|
|
1393
|
+
formUuid: addDataRules.formUuid || '',
|
|
1394
|
+
appType: addDataRules.appType || '',
|
|
1395
|
+
subFormUuid: addDataRules.subFormUuid || '',
|
|
1396
|
+
insertType: addDataRules.insertType || '',
|
|
1397
|
+
type: addDataRules.type || '',
|
|
1398
|
+
sourceId: addDataRules.sourceId || '',
|
|
1399
|
+
assignments: pickRuleAssignments(addDataRules),
|
|
1400
|
+
};
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
function buildAIProcessProps(props) {
|
|
1404
|
+
const workFlowRules = props.workFlowRules || {};
|
|
1405
|
+
return {
|
|
1406
|
+
type: 'aiFlow',
|
|
1407
|
+
action: workFlowRules.flowId ? { flowId: workFlowRules.flowId } : undefined,
|
|
1408
|
+
outputs: clonePlain(workFlowRules.outputs),
|
|
1409
|
+
yidaFieldIdList: clonePlain(workFlowRules.yidaFieldIdList),
|
|
1410
|
+
};
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
function pruneUndefined(value) {
|
|
1414
|
+
if (!isPlainObject(value)) {
|
|
1415
|
+
return value;
|
|
1416
|
+
}
|
|
1417
|
+
Object.keys(value).forEach(function (key) {
|
|
1418
|
+
if (value[key] === undefined) {
|
|
1419
|
+
delete value[key];
|
|
1420
|
+
}
|
|
1421
|
+
});
|
|
1422
|
+
return value;
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
function buildGenericProcessProps(props, node, componentName) {
|
|
1426
|
+
let processProps;
|
|
1427
|
+
|
|
1428
|
+
if (componentName === 'ConnectorNode') {
|
|
1429
|
+
processProps = buildConnectorProcessProps(props);
|
|
1430
|
+
} else if (componentName === 'GroovyNode' || componentName === 'JavaScriptNode') {
|
|
1431
|
+
processProps = buildCodeExecutorProcessProps(props, componentName);
|
|
1432
|
+
} else if (componentName === 'InitiateApprovalNode') {
|
|
1433
|
+
processProps = clonePlain(props.initiateApprovalRules || {});
|
|
1434
|
+
} else if (componentName === 'SendMessageNode') {
|
|
1435
|
+
processProps = clonePlain(props.sendMessageRules || {});
|
|
1436
|
+
delete processProps.description;
|
|
1437
|
+
} else if (componentName === 'SendEmailNode') {
|
|
1438
|
+
processProps = clonePlain(props.sendEmailRules || {});
|
|
1439
|
+
} else if (componentName === 'GetSingleDataNode' || componentName === 'GetBatchDataNode') {
|
|
1440
|
+
processProps = buildGetDataProcessProps(props);
|
|
1441
|
+
} else if (componentName === 'AddDataNode') {
|
|
1442
|
+
processProps = buildAddDataProcessProps(props);
|
|
1443
|
+
} else if (componentName === 'UpdateDataNode') {
|
|
1444
|
+
processProps = clonePlain(props.updateDataRules || {});
|
|
1445
|
+
} else if (componentName === 'DeleteDataNode') {
|
|
1446
|
+
processProps = clonePlain(props.deleteData || {});
|
|
1447
|
+
} else if (componentName === 'SendCardNode') {
|
|
1448
|
+
processProps = clonePlain(props.sendCardRules || {});
|
|
1449
|
+
} else if (componentName === 'UpdateCardNode') {
|
|
1450
|
+
processProps = clonePlain(props.updateCardRules || {});
|
|
1451
|
+
} else if (componentName === 'CardNode') {
|
|
1452
|
+
processProps = clonePlain(props.cardRules || {});
|
|
1453
|
+
} else if (componentName === 'CardUpdateNode') {
|
|
1454
|
+
processProps = clonePlain(props.cardUpdateRules || {});
|
|
1455
|
+
} else if (componentName === 'CycleContainer') {
|
|
1456
|
+
processProps = clonePlain(props.cycleContainerRules || {});
|
|
1457
|
+
} else if (componentName === 'AINode') {
|
|
1458
|
+
processProps = buildAIProcessProps(props);
|
|
1459
|
+
} else {
|
|
1460
|
+
processProps = clonePlain(props);
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
delete processProps.name;
|
|
1464
|
+
delete processProps.nodeName;
|
|
1465
|
+
delete processProps.description;
|
|
1466
|
+
delete processProps.title;
|
|
1467
|
+
pruneUndefined(processProps);
|
|
1468
|
+
if (node.processProps && isPlainObject(node.processProps)) {
|
|
1469
|
+
Object.assign(processProps, clonePlain(node.processProps));
|
|
1470
|
+
}
|
|
1471
|
+
return processProps;
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
function buildGenericNode(node, nextNodeId, nameToIdMap, componentName) {
|
|
1475
|
+
const nodeId = node._nodeId;
|
|
1476
|
+
const config = GENERIC_NODE_CONFIGS[componentName];
|
|
1477
|
+
const props = buildGenericNodeProps(node, componentName);
|
|
1478
|
+
const displayName = getNodeName(node, config.title[0]);
|
|
1479
|
+
const description = getNodeDescription(node);
|
|
1480
|
+
const childNodes = getGenericChildNodes(node);
|
|
1481
|
+
let childProcessNodes = [];
|
|
1482
|
+
let childViewNodes = [];
|
|
1483
|
+
|
|
1484
|
+
if (childNodes.length > 0) {
|
|
1485
|
+
const childResult = buildNodeListRecursive(childNodes, nextNodeId, nameToIdMap);
|
|
1486
|
+
childProcessNodes = childResult.processNodes;
|
|
1487
|
+
childViewNodes = childResult.viewNodes;
|
|
1488
|
+
wireChildProcessNodes(childProcessNodes, nodeId);
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
const processNode = {
|
|
1492
|
+
name: i18n(displayName, config.title[1], displayName),
|
|
1493
|
+
description: description,
|
|
1494
|
+
type: getGenericProcessType(componentName, node, props),
|
|
1495
|
+
nodeId: nodeId,
|
|
1496
|
+
prevId: '',
|
|
1497
|
+
nextId: childProcessNodes.length > 0 ? [childProcessNodes[0].nodeId] : [nextNodeId],
|
|
1498
|
+
props: buildGenericProcessProps(props, node, componentName),
|
|
1499
|
+
childNodes: childProcessNodes.map(clonePlain),
|
|
1500
|
+
};
|
|
1501
|
+
|
|
1502
|
+
if (node.approvalType) {
|
|
1503
|
+
processNode.approvalType = node.approvalType;
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
const viewNode = {
|
|
1507
|
+
componentName: componentName,
|
|
1508
|
+
id: nodeId,
|
|
1509
|
+
props: props,
|
|
1510
|
+
title: i18n(config.title[0], config.title[1], config.title[2]),
|
|
1511
|
+
};
|
|
1512
|
+
|
|
1513
|
+
if (childViewNodes.length > 0) {
|
|
1514
|
+
viewNode.children = childViewNodes;
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
return { processNode, viewNode };
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
// ── 构建条件分支路由节点 ─────────────────────────────
|
|
1521
|
+
|
|
1522
|
+
function buildRouteNode(node, exitNodeId, nameToIdMap) {
|
|
1523
|
+
const routeNodeId = node._nodeId;
|
|
1524
|
+
const conditions = node.conditions || [];
|
|
1525
|
+
|
|
1526
|
+
const conditionNodeIds = [];
|
|
1527
|
+
const conditionProcessNodes = [];
|
|
1528
|
+
const conditionViewNodes = [];
|
|
1529
|
+
|
|
1530
|
+
// 构建每个条件分支
|
|
1531
|
+
conditions.forEach(function (cond, index) {
|
|
1532
|
+
const condNodeId = cond._nodeId;
|
|
1533
|
+
conditionNodeIds.push(condNodeId);
|
|
1534
|
+
|
|
1535
|
+
// 递归构建条件分支内的子节点
|
|
1536
|
+
let childProcessNodes = [];
|
|
1537
|
+
let childViewNodes = [];
|
|
1538
|
+
if (cond.childNodes && cond.childNodes.length > 0) {
|
|
1539
|
+
const childResult = buildNodeListRecursive(cond.childNodes, exitNodeId, nameToIdMap);
|
|
1540
|
+
childProcessNodes = childResult.processNodes;
|
|
1541
|
+
childViewNodes = childResult.viewNodes;
|
|
1542
|
+
wireChildProcessNodes(childProcessNodes, condNodeId);
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
// 构建条件规则
|
|
1546
|
+
const conditionProps = {
|
|
1547
|
+
priority: index + 1,
|
|
1548
|
+
isDefault: false,
|
|
1549
|
+
};
|
|
1550
|
+
|
|
1551
|
+
// 构建条件规则
|
|
1552
|
+
const condRules = buildConditionRules(cond.rules || [], cond.logic || 'AND');
|
|
1553
|
+
const condDescription = cond.name || '';
|
|
1554
|
+
|
|
1555
|
+
if (cond.rules && cond.rules.length > 0) {
|
|
1556
|
+
conditionProps.conditions = {
|
|
1557
|
+
condition: condRules.condition || 'AND',
|
|
1558
|
+
rules: condRules.rules || [],
|
|
1559
|
+
ruleId: condRules.ruleId || 'group-' + generateUuid(),
|
|
1560
|
+
conditionCode: condRules.conditionCode || '&&',
|
|
1561
|
+
};
|
|
1562
|
+
conditionProps.calculate = 'condition';
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
// 条件节点的 nextId:如果有子节点,指向第一个子节点;否则指向出口节点
|
|
1566
|
+
const condNextId = (childProcessNodes.length > 0)
|
|
1567
|
+
? [childProcessNodes[0].nodeId]
|
|
1568
|
+
: [exitNodeId];
|
|
1569
|
+
|
|
1570
|
+
const condProcessNode = {
|
|
1571
|
+
name: i18n(condDescription || '条件', 'Condition', condDescription || '条件'),
|
|
1572
|
+
description: '',
|
|
1573
|
+
type: 'condition',
|
|
1574
|
+
nodeId: condNodeId,
|
|
1575
|
+
prevId: routeNodeId,
|
|
1576
|
+
nextId: condNextId,
|
|
1577
|
+
props: conditionProps,
|
|
1578
|
+
childNodes: childProcessNodes.map(clonePlain),
|
|
1579
|
+
};
|
|
1580
|
+
|
|
1581
|
+
conditionProcessNodes.push(condProcessNode);
|
|
1582
|
+
|
|
1583
|
+
// 构建 condition viewNode(带嵌套 conditions 包装)
|
|
1584
|
+
const condViewNode = {
|
|
1585
|
+
componentName: 'ConditionNode',
|
|
1586
|
+
id: condNodeId,
|
|
1587
|
+
props: {
|
|
1588
|
+
name: i18n(condDescription || '条件', 'Condition', condDescription || '条件'),
|
|
1589
|
+
description: '',
|
|
1590
|
+
conditions: {
|
|
1591
|
+
calculate: 'condition',
|
|
1592
|
+
conditions: {
|
|
1593
|
+
condition: condRules.condition || 'AND',
|
|
1594
|
+
rules: condRules.rules || [],
|
|
1595
|
+
ruleId: condRules.ruleId || 'group-' + generateUuid(),
|
|
1596
|
+
conditionCode: condRules.conditionCode || '&&',
|
|
1597
|
+
},
|
|
1598
|
+
isDefault: false,
|
|
1599
|
+
priority: index + 1,
|
|
1600
|
+
description: condDescription,
|
|
1601
|
+
},
|
|
1602
|
+
},
|
|
1603
|
+
};
|
|
1604
|
+
|
|
1605
|
+
if (childViewNodes.length > 0) {
|
|
1606
|
+
condViewNode.children = childViewNodes;
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
conditionViewNodes.push(condViewNode);
|
|
1610
|
+
});
|
|
1611
|
+
|
|
1612
|
+
// 添加默认条件分支("其他情况")
|
|
1613
|
+
const defaultCondNodeId = generateNodeId();
|
|
1614
|
+
conditionNodeIds.push(defaultCondNodeId);
|
|
1615
|
+
|
|
1616
|
+
const defaultCondProcessNode = {
|
|
1617
|
+
name: i18n('其他情况', 'Other situations', 'その他の場合'),
|
|
1618
|
+
description: '',
|
|
1619
|
+
type: 'condition',
|
|
1620
|
+
nodeId: defaultCondNodeId,
|
|
1621
|
+
prevId: routeNodeId,
|
|
1622
|
+
nextId: [exitNodeId],
|
|
1623
|
+
props: {
|
|
1624
|
+
priority: 2147483647,
|
|
1625
|
+
isDefault: true,
|
|
1626
|
+
},
|
|
1627
|
+
childNodes: [],
|
|
1628
|
+
};
|
|
1629
|
+
|
|
1630
|
+
conditionProcessNodes.push(defaultCondProcessNode);
|
|
1631
|
+
|
|
1632
|
+
const defaultCondViewNode = {
|
|
1633
|
+
componentName: 'ConditionNode',
|
|
1634
|
+
id: defaultCondNodeId,
|
|
1635
|
+
props: {
|
|
1636
|
+
isDefault: true,
|
|
1637
|
+
buttons: [{ name: '关闭' }],
|
|
1638
|
+
name: i18n('其他情况', 'Other situations', 'その他の場合'),
|
|
1639
|
+
description: '',
|
|
1640
|
+
},
|
|
1641
|
+
};
|
|
1642
|
+
|
|
1643
|
+
conditionViewNodes.push(defaultCondViewNode);
|
|
1644
|
+
|
|
1645
|
+
// 构建 route processNode
|
|
1646
|
+
const routeProcessNode = {
|
|
1647
|
+
name: i18n('ConditionNode', 'ConditionNode', '条件ノード'),
|
|
1648
|
+
description: '',
|
|
1649
|
+
type: 'route',
|
|
1650
|
+
nodeId: routeNodeId,
|
|
1651
|
+
prevId: '',
|
|
1652
|
+
nextId: conditionNodeIds,
|
|
1653
|
+
props: { outgoingType: 'priority' },
|
|
1654
|
+
childNodes: conditionProcessNodes,
|
|
1655
|
+
};
|
|
1656
|
+
|
|
1657
|
+
// 构建 route viewNode(ConditionContainer)
|
|
1658
|
+
const routeViewNode = {
|
|
1659
|
+
componentName: 'ConditionContainer',
|
|
1660
|
+
id: routeNodeId,
|
|
1661
|
+
props: {},
|
|
1662
|
+
title: '条件分支',
|
|
1663
|
+
children: conditionViewNodes,
|
|
1664
|
+
};
|
|
1665
|
+
|
|
1666
|
+
return { processNode: routeProcessNode, viewNode: routeViewNode };
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
// ── 构建并行分支节点 ────────────────────────────────
|
|
1670
|
+
|
|
1671
|
+
function getParallelBranches(node) {
|
|
1672
|
+
const branches = node.branches || node.conditions || node.parallelBranches || [];
|
|
1673
|
+
return Array.isArray(branches) ? branches : [];
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
function getBranchChildNodes(branch) {
|
|
1677
|
+
const childNodes = branch.childNodes || branch.nodes || branch.children || [];
|
|
1678
|
+
return Array.isArray(childNodes) ? childNodes : [];
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
function buildAllDataConditionProps(branch, priority, isDefault) {
|
|
1682
|
+
return {
|
|
1683
|
+
calculate: 'all',
|
|
1684
|
+
conditions: {
|
|
1685
|
+
condition: 'AND',
|
|
1686
|
+
rules: [
|
|
1687
|
+
{
|
|
1688
|
+
id: 'originator',
|
|
1689
|
+
op: '等于',
|
|
1690
|
+
operators: [],
|
|
1691
|
+
componentType: 'EmployeeField',
|
|
1692
|
+
},
|
|
1693
|
+
],
|
|
1694
|
+
},
|
|
1695
|
+
isDefault: isDefault,
|
|
1696
|
+
priority: priority,
|
|
1697
|
+
description: branch.description || '所有数据均可进入',
|
|
1698
|
+
};
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
function buildParallelBranchConditionProps(branch, index) {
|
|
1702
|
+
const priority = Number(pickFirstDefined(branch.priority, index + 1));
|
|
1703
|
+
const isDefault = Boolean(branch.isDefault);
|
|
1704
|
+
const rawConditions = branch.conditionProps
|
|
1705
|
+
|| branch.condition
|
|
1706
|
+
|| (isPlainObject(branch.conditions) ? branch.conditions : null);
|
|
1707
|
+
|
|
1708
|
+
if (isPlainObject(rawConditions) && rawConditions.calculate) {
|
|
1709
|
+
const props = Object.assign({}, rawConditions, {
|
|
1710
|
+
isDefault: isDefault,
|
|
1711
|
+
priority: priority,
|
|
1712
|
+
});
|
|
1713
|
+
if (!props.description && branch.description) {
|
|
1714
|
+
props.description = branch.description;
|
|
1715
|
+
}
|
|
1716
|
+
return props;
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
if (isPlainObject(rawConditions) && (rawConditions.rules || rawConditions.condition)) {
|
|
1720
|
+
return {
|
|
1721
|
+
calculate: 'condition',
|
|
1722
|
+
conditions: rawConditions,
|
|
1723
|
+
isDefault: isDefault,
|
|
1724
|
+
priority: priority,
|
|
1725
|
+
description: branch.description || branch.name || '',
|
|
1726
|
+
};
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
if (branch.rules && branch.rules.length > 0) {
|
|
1730
|
+
const condRules = buildConditionRules(branch.rules, branch.logic || 'AND');
|
|
1731
|
+
return {
|
|
1732
|
+
calculate: 'condition',
|
|
1733
|
+
conditions: {
|
|
1734
|
+
condition: condRules.condition || 'AND',
|
|
1735
|
+
rules: condRules.rules || [],
|
|
1736
|
+
ruleId: condRules.ruleId || 'group-' + generateUuid(),
|
|
1737
|
+
conditionCode: condRules.conditionCode || '&&',
|
|
1738
|
+
},
|
|
1739
|
+
isDefault: isDefault,
|
|
1740
|
+
priority: priority,
|
|
1741
|
+
description: branch.description || branch.name || '',
|
|
1742
|
+
};
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
return buildAllDataConditionProps(branch, priority, isDefault);
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
function buildParallelBranchProcessProps(conditionProps) {
|
|
1749
|
+
const props = {};
|
|
1750
|
+
if (conditionProps.isDefault !== undefined) {
|
|
1751
|
+
props.isDefault = conditionProps.isDefault;
|
|
1752
|
+
}
|
|
1753
|
+
if (conditionProps.conditions !== undefined) {
|
|
1754
|
+
props.conditions = clonePlain(conditionProps.conditions);
|
|
1755
|
+
}
|
|
1756
|
+
if (conditionProps.calculate !== undefined) {
|
|
1757
|
+
props.calculate = conditionProps.calculate;
|
|
1758
|
+
}
|
|
1759
|
+
if (conditionProps.expression !== undefined) {
|
|
1760
|
+
props.expression = conditionProps.expression;
|
|
1761
|
+
}
|
|
1762
|
+
return props;
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
function buildParallelNode(node, exitNodeId, nameToIdMap) {
|
|
1766
|
+
const parallelNodeId = node._nodeId;
|
|
1767
|
+
const branches = getParallelBranches(node);
|
|
1768
|
+
|
|
1769
|
+
if (branches.length === 0) {
|
|
1770
|
+
throw new Error('parallel 节点至少需要一个 branches 分支');
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
const branchNodeIds = [];
|
|
1774
|
+
const branchProcessNodes = [];
|
|
1775
|
+
const branchViewNodes = [];
|
|
1776
|
+
|
|
1777
|
+
branches.forEach(function (branch, index) {
|
|
1778
|
+
const branchNodeId = branch._nodeId;
|
|
1779
|
+
const branchName = branch.name || ('条件' + (index + 1));
|
|
1780
|
+
const branchConditionProps = buildParallelBranchConditionProps(branch, index);
|
|
1781
|
+
const childNodes = getBranchChildNodes(branch);
|
|
1782
|
+
|
|
1783
|
+
branchNodeIds.push(branchNodeId);
|
|
1784
|
+
|
|
1785
|
+
let childProcessNodes = [];
|
|
1786
|
+
let childViewNodes = [];
|
|
1787
|
+
if (childNodes.length > 0) {
|
|
1788
|
+
const childResult = buildNodeListRecursive(childNodes, exitNodeId, nameToIdMap);
|
|
1789
|
+
childProcessNodes = childResult.processNodes;
|
|
1790
|
+
childViewNodes = childResult.viewNodes;
|
|
1791
|
+
wireChildProcessNodes(childProcessNodes, branchNodeId);
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
const branchNextId = childProcessNodes.length > 0
|
|
1795
|
+
? [childProcessNodes[0].nodeId]
|
|
1796
|
+
: [exitNodeId];
|
|
1797
|
+
|
|
1798
|
+
const branchProcessNode = {
|
|
1799
|
+
name: i18n(branchName, 'Parallel branch', branchName),
|
|
1800
|
+
description: '',
|
|
1801
|
+
type: 'condition',
|
|
1802
|
+
nodeId: branchNodeId,
|
|
1803
|
+
prevId: parallelNodeId,
|
|
1804
|
+
nextId: branchNextId,
|
|
1805
|
+
props: buildParallelBranchProcessProps(branchConditionProps),
|
|
1806
|
+
childNodes: childProcessNodes.map(clonePlain),
|
|
1807
|
+
};
|
|
1808
|
+
|
|
1809
|
+
branchProcessNodes.push(branchProcessNode);
|
|
1810
|
+
|
|
1811
|
+
const branchViewNode = {
|
|
1812
|
+
componentName: 'ParallelNode',
|
|
1813
|
+
id: branchNodeId,
|
|
1814
|
+
props: {
|
|
1815
|
+
name: branchConditionProps.isDefault
|
|
1816
|
+
? i18n(branchName, 'Other situations', branchName)
|
|
1817
|
+
: branchName,
|
|
1818
|
+
description: branch.description || '',
|
|
1819
|
+
conditions: clonePlain(branchConditionProps),
|
|
1820
|
+
},
|
|
1821
|
+
};
|
|
1822
|
+
|
|
1823
|
+
if (branchConditionProps.isDefault) {
|
|
1824
|
+
branchViewNode.props.buttons = branch.buttons || [{ name: '关闭' }];
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
if (childViewNodes.length > 0) {
|
|
1828
|
+
branchViewNode.children = childViewNodes;
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
branchViewNodes.push(branchViewNode);
|
|
1832
|
+
});
|
|
1833
|
+
|
|
1834
|
+
const parallelProcessNode = {
|
|
1835
|
+
name: i18n(node.name || 'ParallelNode', node.name || 'ParallelNode', node.name || 'ParallelNode'),
|
|
1836
|
+
description: '',
|
|
1837
|
+
type: 'route',
|
|
1838
|
+
nodeId: parallelNodeId,
|
|
1839
|
+
prevId: '',
|
|
1840
|
+
nextId: branchNodeIds,
|
|
1841
|
+
props: { outgoingType: 'multiple' },
|
|
1842
|
+
childNodes: branchProcessNodes,
|
|
1843
|
+
};
|
|
1844
|
+
|
|
1845
|
+
const parallelViewNode = {
|
|
1846
|
+
componentName: 'ConditionContainer',
|
|
1847
|
+
id: parallelNodeId,
|
|
1848
|
+
props: {
|
|
1849
|
+
name: i18n(node.name || '并行分支', node.name || 'ParallelNode', node.name || '並行分岐'),
|
|
1850
|
+
},
|
|
1851
|
+
title: node.title || '并行分支',
|
|
1852
|
+
type: 'parallel',
|
|
1853
|
+
children: branchViewNodes,
|
|
1854
|
+
};
|
|
1855
|
+
|
|
1856
|
+
return { processNode: parallelProcessNode, viewNode: parallelViewNode };
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
function appendOpenDetailParam(url, paramName) {
|
|
1860
|
+
if (!url) {
|
|
1861
|
+
return url;
|
|
1862
|
+
}
|
|
1863
|
+
if (new RegExp('([?&])' + paramName + '=').test(url)) {
|
|
1864
|
+
return url;
|
|
1865
|
+
}
|
|
1866
|
+
const separator = url.endsWith('?') || url.endsWith('&')
|
|
1867
|
+
? ''
|
|
1868
|
+
: (url.indexOf('?') === -1 ? '?' : '&');
|
|
1869
|
+
return url + separator + paramName + '=';
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
// ── 构建完整的 processJson 和 viewJson ──────────────
|
|
1873
|
+
|
|
1874
|
+
function buildProcessAndViewJson(definition, processCode, formUuid, baseUrl, appType, options) {
|
|
1875
|
+
const compilerOptions = options || {};
|
|
1876
|
+
const finishNodeId = generateNodeId();
|
|
1877
|
+
const nodes = definition.nodes || [];
|
|
1878
|
+
|
|
1879
|
+
// 第一遍:递归分配 nodeId 并收集名称映射
|
|
1880
|
+
const nodeNameToIdMap = {};
|
|
1881
|
+
Object.defineProperties(nodeNameToIdMap, {
|
|
1882
|
+
__compilerOptions: { value: compilerOptions },
|
|
1883
|
+
__nodeBindings: { value: Object.create(null) },
|
|
1884
|
+
__semanticKeys: { value: new Set() },
|
|
1885
|
+
__usedNodeIds: { value: new Set(['sid_instStart', finishNodeId]) },
|
|
1886
|
+
});
|
|
1887
|
+
assignNodeIdsRecursive(nodes, nodeNameToIdMap);
|
|
1888
|
+
|
|
1889
|
+
// 将结束节点加入映射
|
|
1890
|
+
nodeNameToIdMap['结束'] = finishNodeId;
|
|
1891
|
+
nodeNameToIdMap['finish'] = finishNodeId;
|
|
1892
|
+
nodeNameToIdMap['end'] = finishNodeId;
|
|
1893
|
+
|
|
1894
|
+
// 第二遍:递归构建所有节点
|
|
1895
|
+
const middleResult = buildNodeListRecursive(nodes, finishNodeId, nodeNameToIdMap);
|
|
1896
|
+
|
|
1897
|
+
// 设置顶层节点的 prevId
|
|
1898
|
+
if (middleResult.processNodes.length > 0) {
|
|
1899
|
+
middleResult.processNodes[0].prevId = 'sid_instStart';
|
|
1900
|
+
for (let mi = 1; mi < middleResult.processNodes.length; mi++) {
|
|
1901
|
+
middleResult.processNodes[mi].prevId = middleResult.processNodes[mi - 1].nodeId;
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1905
|
+
const firstMiddleNodeId = middleResult.processNodes.length > 0
|
|
1906
|
+
? middleResult.processNodes[0].nodeId
|
|
1907
|
+
: finishNodeId;
|
|
1908
|
+
|
|
1909
|
+
// 组装发起节点
|
|
1910
|
+
const applyProcessNode = {
|
|
1911
|
+
name: i18n('发起', 'start', '開始'),
|
|
1912
|
+
description: '',
|
|
1913
|
+
type: 'apply',
|
|
1914
|
+
nodeId: 'sid_instStart',
|
|
1915
|
+
prevId: '',
|
|
1916
|
+
nextId: [firstMiddleNodeId],
|
|
1917
|
+
props: {},
|
|
1918
|
+
childNodes: [],
|
|
1919
|
+
};
|
|
1920
|
+
|
|
1921
|
+
// 组装结束节点
|
|
1922
|
+
const finishProcessNode = {
|
|
1923
|
+
name: i18n('结束', 'end', '終了'),
|
|
1924
|
+
description: '',
|
|
1925
|
+
type: 'finish',
|
|
1926
|
+
nodeId: finishNodeId,
|
|
1927
|
+
prevId: '',
|
|
1928
|
+
nextId: [],
|
|
1929
|
+
props: {},
|
|
1930
|
+
childNodes: [],
|
|
1931
|
+
};
|
|
1932
|
+
|
|
1933
|
+
// 组装 processJson
|
|
1934
|
+
const processNodes = [applyProcessNode];
|
|
1935
|
+
middleResult.processNodes.forEach(function (node) {
|
|
1936
|
+
processNodes.push(node);
|
|
1937
|
+
});
|
|
1938
|
+
processNodes.push(finishProcessNode);
|
|
1939
|
+
|
|
1940
|
+
const defaultProcessDetailUrl = baseUrl + '/alibaba/web/' + appType + '/inst/taskDetail.htm';
|
|
1941
|
+
const defaultProcessMobileDetailUrl = baseUrl + '/alibaba/mobile/' + appType + '/inst/detail/taskDetail/';
|
|
1942
|
+
|
|
1943
|
+
const processJson = {
|
|
1944
|
+
props: {
|
|
1945
|
+
allowWithdraw: true,
|
|
1946
|
+
allowCollaboration: true,
|
|
1947
|
+
allowTemporaryStorage: true,
|
|
1948
|
+
processCode: processCode,
|
|
1949
|
+
processDetailUrl: definition.processDetailUrl
|
|
1950
|
+
|| (definition.detailUrls && (definition.detailUrls.web || definition.detailUrls.pc))
|
|
1951
|
+
|| definition.customDetailPageUrl
|
|
1952
|
+
|| defaultProcessDetailUrl,
|
|
1953
|
+
processInitUrl: baseUrl + '/alibaba/web/' + appType + '/inst/instStart.htm?processCode=' + processCode,
|
|
1954
|
+
processMobileDetailUrl: definition.processMobileDetailUrl
|
|
1955
|
+
|| (definition.detailUrls && definition.detailUrls.mobile)
|
|
1956
|
+
|| (definition.customDetailPageUrl ? appendOpenDetailParam(definition.customDetailPageUrl, 'formInstId') : null)
|
|
1957
|
+
|| defaultProcessMobileDetailUrl,
|
|
1958
|
+
bindingForm: formUuid,
|
|
1959
|
+
stopAssociationRulesIfFailed: false,
|
|
1960
|
+
noRecordRecall: false,
|
|
1961
|
+
untimedRule: [],
|
|
1962
|
+
},
|
|
1963
|
+
nodes: processNodes,
|
|
1964
|
+
flowConfig: {},
|
|
1965
|
+
formulaRules: [],
|
|
1966
|
+
approvalSummary: [],
|
|
1967
|
+
nodeI18nKeyMap: {},
|
|
1968
|
+
};
|
|
1969
|
+
|
|
1970
|
+
// 组装 viewJson
|
|
1971
|
+
const viewChildren = [];
|
|
1972
|
+
|
|
1973
|
+
viewChildren.push({
|
|
1974
|
+
componentName: 'ApplyNode',
|
|
1975
|
+
id: generateNodeId(),
|
|
1976
|
+
props: {
|
|
1977
|
+
nodeName: 'ApplyNode',
|
|
1978
|
+
name: i18n('发起', 'start', '開始'),
|
|
1979
|
+
},
|
|
1980
|
+
});
|
|
1981
|
+
|
|
1982
|
+
middleResult.viewNodes.forEach(function (node) {
|
|
1983
|
+
viewChildren.push(node);
|
|
1984
|
+
});
|
|
1985
|
+
|
|
1986
|
+
viewChildren.push({
|
|
1987
|
+
componentName: 'EndNode',
|
|
1988
|
+
id: finishNodeId,
|
|
1989
|
+
props: {
|
|
1990
|
+
name: i18n('结束', 'end', '終了'),
|
|
1991
|
+
},
|
|
1992
|
+
});
|
|
1993
|
+
|
|
1994
|
+
const viewJson = {
|
|
1995
|
+
schema: {
|
|
1996
|
+
componentName: 'CanvasEngine',
|
|
1997
|
+
id: generateNodeId(),
|
|
1998
|
+
props: {},
|
|
1999
|
+
children: viewChildren,
|
|
2000
|
+
},
|
|
2001
|
+
bindingForm: formUuid,
|
|
2002
|
+
formulaRules: [],
|
|
2003
|
+
globalSetting: {
|
|
2004
|
+
enableSignature: false,
|
|
2005
|
+
stopAssociationRulesIfFailed: false,
|
|
2006
|
+
nodeMerge: false,
|
|
2007
|
+
originatorMerge: false,
|
|
2008
|
+
allNodeMerge: false,
|
|
2009
|
+
behaviorList: [],
|
|
2010
|
+
needOpenDigitalSignNodes: [],
|
|
2011
|
+
approvalSummary: [],
|
|
2012
|
+
noRecordRecall: false,
|
|
2013
|
+
untimedRule: [],
|
|
2014
|
+
},
|
|
2015
|
+
};
|
|
2016
|
+
|
|
2017
|
+
const result = {
|
|
2018
|
+
processJson,
|
|
2019
|
+
viewJson,
|
|
2020
|
+
};
|
|
2021
|
+
if (compilerOptions.semanticBindings) {
|
|
2022
|
+
result.nodeBindings = nodeNameToIdMap.__nodeBindings;
|
|
2023
|
+
}
|
|
2024
|
+
return result;
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
function compileProcessDefinition(definition, options) {
|
|
2028
|
+
if (!definition || typeof definition !== 'object' || Array.isArray(definition)) {
|
|
2029
|
+
throw new ProcessCompilerError(
|
|
2030
|
+
'PROCESS_COMPILE_DEFINITION_INVALID',
|
|
2031
|
+
'Process definition must be an object.'
|
|
2032
|
+
);
|
|
2033
|
+
}
|
|
2034
|
+
const compileOptions = options || {};
|
|
2035
|
+
const clonedDefinition = clonePlain(definition);
|
|
2036
|
+
return buildProcessAndViewJson(
|
|
2037
|
+
clonedDefinition,
|
|
2038
|
+
compileOptions.processCode,
|
|
2039
|
+
compileOptions.formUuid,
|
|
2040
|
+
compileOptions.baseUrl,
|
|
2041
|
+
compileOptions.appType,
|
|
2042
|
+
{
|
|
2043
|
+
semanticBindings: true,
|
|
2044
|
+
existingBindings: compileOptions.existingBindings || {},
|
|
2045
|
+
onWarning: compileOptions.onWarning,
|
|
2046
|
+
}
|
|
2047
|
+
);
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
module.exports = {
|
|
2051
|
+
ProcessCompilerError,
|
|
2052
|
+
buildApproverConfig,
|
|
2053
|
+
buildProcessAndViewJson,
|
|
2054
|
+
compileProcessDefinition,
|
|
2055
|
+
validateManagedNodeBindings,
|
|
2056
|
+
};
|