weaver-e10-builder 1.5.2 → 1.5.3

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.
Files changed (187) hide show
  1. package/dist/commands/form-add-detail-table.js +3 -3
  2. package/dist/commands/form-add-detail-table.js.map +1 -1
  3. package/dist/commands/form-add-physical-field.d.ts.map +1 -1
  4. package/dist/commands/form-add-physical-field.js +3 -2
  5. package/dist/commands/form-add-physical-field.js.map +1 -1
  6. package/dist/commands/form-data.d.ts.map +1 -1
  7. package/dist/commands/form-data.js +125 -0
  8. package/dist/commands/form-data.js.map +1 -1
  9. package/dist/commands/form-ebuilder-columns.d.ts.map +1 -1
  10. package/dist/commands/form-ebuilder-columns.js +3 -3
  11. package/dist/commands/form-ebuilder-columns.js.map +1 -1
  12. package/dist/commands/form-ebuilder-scope.d.ts.map +1 -1
  13. package/dist/commands/form-ebuilder-scope.js +3 -4
  14. package/dist/commands/form-ebuilder-scope.js.map +1 -1
  15. package/dist/commands/form-field-lang.d.ts.map +1 -1
  16. package/dist/commands/form-field-lang.js +3 -4
  17. package/dist/commands/form-field-lang.js.map +1 -1
  18. package/dist/commands/form-field-linkage.d.ts.map +1 -1
  19. package/dist/commands/form-field-linkage.js +4 -3
  20. package/dist/commands/form-field-linkage.js.map +1 -1
  21. package/dist/commands/form-formula-linkage.d.ts.map +1 -1
  22. package/dist/commands/form-formula-linkage.js +4 -2
  23. package/dist/commands/form-formula-linkage.js.map +1 -1
  24. package/dist/commands/form-formula.d.ts.map +1 -1
  25. package/dist/commands/form-formula.js +5 -5
  26. package/dist/commands/form-formula.js.map +1 -1
  27. package/dist/commands/form-layout.d.ts.map +1 -1
  28. package/dist/commands/form-layout.js +6 -0
  29. package/dist/commands/form-layout.js.map +1 -1
  30. package/dist/commands/form-list-click.d.ts.map +1 -1
  31. package/dist/commands/form-list-click.js +3 -2
  32. package/dist/commands/form-list-click.js.map +1 -1
  33. package/dist/commands/form-physical-table.js +3 -3
  34. package/dist/commands/form-physical-table.js.map +1 -1
  35. package/dist/commands/form-relate.d.ts.map +1 -1
  36. package/dist/commands/form-relate.js +3 -2
  37. package/dist/commands/form-relate.js.map +1 -1
  38. package/dist/commands/form-validate.d.ts.map +1 -1
  39. package/dist/commands/form-validate.js +3 -3
  40. package/dist/commands/form-validate.js.map +1 -1
  41. package/dist/commands/form-view.d.ts.map +1 -1
  42. package/dist/commands/form-view.js +2 -0
  43. package/dist/commands/form-view.js.map +1 -1
  44. package/dist/commands/form.d.ts +9 -3
  45. package/dist/commands/form.d.ts.map +1 -1
  46. package/dist/commands/form.js +116 -160
  47. package/dist/commands/form.js.map +1 -1
  48. package/dist/commands/special.d.ts +24 -0
  49. package/dist/commands/special.d.ts.map +1 -0
  50. package/dist/commands/special.js +487 -0
  51. package/dist/commands/special.js.map +1 -0
  52. package/dist/commands/wf-form.d.ts.map +1 -1
  53. package/dist/commands/wf-form.js +4 -4
  54. package/dist/commands/wf-form.js.map +1 -1
  55. package/dist/commands/workflow-message.d.ts.map +1 -1
  56. package/dist/commands/workflow-message.js +1 -2
  57. package/dist/commands/workflow-message.js.map +1 -1
  58. package/dist/index.js +24 -0
  59. package/dist/index.js.map +1 -1
  60. package/dist/services/actionflow/components/action_eb_update_compiler.d.ts.map +1 -1
  61. package/dist/services/actionflow/components/action_eb_update_compiler.js +54 -12
  62. package/dist/services/actionflow/components/action_eb_update_compiler.js.map +1 -1
  63. package/dist/services/actionflow/components/index.d.ts.map +1 -1
  64. package/dist/services/actionflow/components/index.js +6 -0
  65. package/dist/services/actionflow/components/index.js.map +1 -1
  66. package/dist/services/actionflow/components/multiple_execution.d.ts.map +1 -1
  67. package/dist/services/actionflow/components/multiple_execution.js +73 -13
  68. package/dist/services/actionflow/components/multiple_execution.js.map +1 -1
  69. package/dist/services/actionflow/components/output.d.ts.map +1 -1
  70. package/dist/services/actionflow/components/output.js +144 -5
  71. package/dist/services/actionflow/components/output.js.map +1 -1
  72. package/dist/services/actionflow/components/send_message.d.ts.map +1 -1
  73. package/dist/services/actionflow/components/send_message.js +60 -32
  74. package/dist/services/actionflow/components/send_message.js.map +1 -1
  75. package/dist/services/actionflow/components/serverless_action.d.ts +5 -0
  76. package/dist/services/actionflow/components/serverless_action.d.ts.map +1 -0
  77. package/dist/services/actionflow/components/serverless_action.js +134 -0
  78. package/dist/services/actionflow/components/serverless_action.js.map +1 -0
  79. package/dist/services/actionflow/components/webhook_trigger.d.ts +5 -0
  80. package/dist/services/actionflow/components/webhook_trigger.d.ts.map +1 -0
  81. package/dist/services/actionflow/components/webhook_trigger.js +85 -0
  82. package/dist/services/actionflow/components/webhook_trigger.js.map +1 -0
  83. package/dist/services/actionflow/context_preflight.d.ts +6 -0
  84. package/dist/services/actionflow/context_preflight.d.ts.map +1 -1
  85. package/dist/services/actionflow/context_preflight.js +247 -7
  86. package/dist/services/actionflow/context_preflight.js.map +1 -1
  87. package/dist/services/actionflow/context_provider.d.ts.map +1 -1
  88. package/dist/services/actionflow/context_provider.js +67 -3
  89. package/dist/services/actionflow/context_provider.js.map +1 -1
  90. package/dist/services/actionflow/custom_trigger_context.d.ts.map +1 -1
  91. package/dist/services/actionflow/custom_trigger_context.js +9 -2
  92. package/dist/services/actionflow/custom_trigger_context.js.map +1 -1
  93. package/dist/services/actionflow/formula_service.d.ts +2 -0
  94. package/dist/services/actionflow/formula_service.d.ts.map +1 -1
  95. package/dist/services/actionflow/formula_service.js +381 -63
  96. package/dist/services/actionflow/formula_service.js.map +1 -1
  97. package/dist/services/actionflow/generation_service.d.ts.map +1 -1
  98. package/dist/services/actionflow/generation_service.js +9 -0
  99. package/dist/services/actionflow/generation_service.js.map +1 -1
  100. package/dist/services/actionflow/param_group_dto.d.ts +5 -0
  101. package/dist/services/actionflow/param_group_dto.d.ts.map +1 -0
  102. package/dist/services/actionflow/param_group_dto.js +181 -0
  103. package/dist/services/actionflow/param_group_dto.js.map +1 -0
  104. package/dist/services/actionflow/preflight_service.d.ts.map +1 -1
  105. package/dist/services/actionflow/preflight_service.js +53 -11
  106. package/dist/services/actionflow/preflight_service.js.map +1 -1
  107. package/dist/services/actionflow/readback_verifier.d.ts.map +1 -1
  108. package/dist/services/actionflow/readback_verifier.js +14 -1
  109. package/dist/services/actionflow/readback_verifier.js.map +1 -1
  110. package/dist/services/actionflow/update_service.d.ts.map +1 -1
  111. package/dist/services/actionflow/update_service.js +14 -8
  112. package/dist/services/actionflow/update_service.js.map +1 -1
  113. package/dist/services/actionflow/webhook_source.d.ts +4 -0
  114. package/dist/services/actionflow/webhook_source.d.ts.map +1 -0
  115. package/dist/services/actionflow/webhook_source.js +99 -0
  116. package/dist/services/actionflow/webhook_source.js.map +1 -0
  117. package/dist/services/actionflow/workflow_compiler.d.ts.map +1 -1
  118. package/dist/services/actionflow/workflow_compiler.js +1 -0
  119. package/dist/services/actionflow/workflow_compiler.js.map +1 -1
  120. package/dist/services/form-create.d.ts +45 -2
  121. package/dist/services/form-create.d.ts.map +1 -1
  122. package/dist/services/form-create.js +78 -8
  123. package/dist/services/form-create.js.map +1 -1
  124. package/dist/services/form-data-openapi.d.ts +142 -0
  125. package/dist/services/form-data-openapi.d.ts.map +1 -0
  126. package/dist/services/form-data-openapi.js +363 -0
  127. package/dist/services/form-data-openapi.js.map +1 -0
  128. package/dist/services/form-field-build.d.ts.map +1 -1
  129. package/dist/services/form-field-build.js +4 -4
  130. package/dist/services/form-field-build.js.map +1 -1
  131. package/dist/services/form-field-template.d.ts +71 -0
  132. package/dist/services/form-field-template.d.ts.map +1 -0
  133. package/dist/services/form-field-template.js +103 -0
  134. package/dist/services/form-field-template.js.map +1 -0
  135. package/dist/services/form-field-validate.d.ts +26 -0
  136. package/dist/services/form-field-validate.d.ts.map +1 -0
  137. package/dist/services/form-field-validate.js +121 -0
  138. package/dist/services/form-field-validate.js.map +1 -0
  139. package/dist/services/form-id.d.ts +50 -0
  140. package/dist/services/form-id.d.ts.map +1 -0
  141. package/dist/services/form-id.js +110 -0
  142. package/dist/services/form-id.js.map +1 -0
  143. package/dist/services/form-layout-grid.d.ts +123 -0
  144. package/dist/services/form-layout-grid.d.ts.map +1 -0
  145. package/dist/services/form-layout-grid.js +177 -0
  146. package/dist/services/form-layout-grid.js.map +1 -0
  147. package/dist/services/form-layout-insert.d.ts +24 -1
  148. package/dist/services/form-layout-insert.d.ts.map +1 -1
  149. package/dist/services/form-layout-insert.js +192 -27
  150. package/dist/services/form-layout-insert.js.map +1 -1
  151. package/dist/services/form-physical-table.d.ts +1 -1
  152. package/dist/services/form-physical-table.js +1 -1
  153. package/dist/services/form-table-view.d.ts.map +1 -1
  154. package/dist/services/form-table-view.js +2 -11
  155. package/dist/services/form-table-view.js.map +1 -1
  156. package/dist/services/form-view.d.ts +2 -0
  157. package/dist/services/form-view.d.ts.map +1 -1
  158. package/dist/services/form-view.js +57 -7
  159. package/dist/services/form-view.js.map +1 -1
  160. package/dist/services/form-virtual.d.ts.map +1 -1
  161. package/dist/services/form-virtual.js +6 -1
  162. package/dist/services/form-virtual.js.map +1 -1
  163. package/dist/services/special-page.d.ts +85 -0
  164. package/dist/services/special-page.d.ts.map +1 -0
  165. package/dist/services/special-page.js +129 -0
  166. package/dist/services/special-page.js.map +1 -0
  167. package/dist/services/special-route.d.ts +92 -0
  168. package/dist/services/special-route.d.ts.map +1 -0
  169. package/dist/services/special-route.js +93 -0
  170. package/dist/services/special-route.js.map +1 -0
  171. package/dist/services/workflow-node-layout.d.ts +13 -1
  172. package/dist/services/workflow-node-layout.d.ts.map +1 -1
  173. package/dist/services/workflow-node-layout.js +11 -3
  174. package/dist/services/workflow-node-layout.js.map +1 -1
  175. package/package.json +1 -1
  176. package/skill-docs/actionflows/SKILL.md +5 -4
  177. package/skill-docs/actionflows/references/components/logic/MultipleExecution.md +38 -38
  178. package/skill-docs/actionflows/references/components/logic/Output.md +9 -2
  179. package/skill-docs/actionflows/references/components/message/SendMessage.md +3 -3
  180. package/skill-docs/actionflows/references/components/serverless/ServerlessAction.md +42 -0
  181. package/skill-docs/actionflows/references/components/trigger/WebHookTrigger.md +89 -0
  182. package/skill-docs/actionflows/references/dynamic_capability_matrix.md +2 -2
  183. package/skill-docs/references/common/ref-cli-commands.md +3 -1
  184. package/skill-docs/references/form/guide-form-data.md +30 -0
  185. package/skill-docs/references/form/guide-form-layout-incremental.md +18 -3
  186. package/skill-docs/references/form/guide-form-physical-table.md +1 -1
  187. package/skill-docs/references/form/ref-form-fields.md +1 -1
@@ -27,6 +27,15 @@ const VALUE_TYPE_ALIASES = {
27
27
  date: 'Date', Date: 'Date', time: 'Time', Time: 'Time',
28
28
  datetime: 'DateTime', DateTime: 'DateTime',
29
29
  };
30
+ const WEBHOOK_CONTEXT_TABLES = new Set(['Params', 'Header', 'Body']);
31
+ const SERVERLESS_CONTEXT_TABLES = new Set(['Request', 'Response']);
32
+ function isParameterContext(componentType, paramKey, tableKey = '') {
33
+ if (componentType === 'WebHookTrigger' || componentType === 'ServerlessAction')
34
+ return true;
35
+ const head = String(paramKey).split('.')[0];
36
+ return WEBHOOK_CONTEXT_TABLES.has(String(tableKey)) || WEBHOOK_CONTEXT_TABLES.has(head)
37
+ || SERVERLESS_CONTEXT_TABLES.has(String(tableKey)) || SERVERLESS_CONTEXT_TABLES.has(head);
38
+ }
30
39
  /** 触发器上下文根节点。自定义触发的参数由 SelectParams 提供,不是普通表单数据。 */
31
40
  export function contextRootForComponent(componentType) {
32
41
  return String(componentType || '') === 'CustomTrigger'
@@ -167,6 +176,147 @@ export function resolveParamKey(workflowId, key) {
167
176
  return `${workflowId}.${fieldId}`;
168
177
  return keyStr;
169
178
  }
179
+ /**
180
+ * 对齐前端 AssignItem.getDetailDatas 的 parentName 读取规则。
181
+ *
182
+ * 前端会把 value 去掉上下文根节点后按 '.' 拆分,再用同一个下标读取
183
+ * config.parentName 的片段。因此 parentName 不能只写成“来源名称.字段名称”,
184
+ * 明细路径还必须包含主表/明细表/字段的对应层级,并在数组层保留 [] 标记。
185
+ */
186
+ function alignContextParentName(paramKey, parentName, fieldLabel, meta = null, options = {}) {
187
+ const componentType = String(options.componentType || meta?._context_component_type || meta?._upstream_component_type || '');
188
+ const rawKey = String(paramKey ?? '').replace(/^(?:FormData|ApprovalData|SelectParams)\./, '');
189
+ const pathParts = rawKey.split('.').filter(Boolean);
190
+ if (!pathParts.length)
191
+ return String(parentName || fieldLabel || rawKey);
192
+ const rootNames = new Set(['FormData', 'ApprovalData', 'SelectParams', '表单数据', '流程数据', '选择参数']);
193
+ let existing = String(parentName || '').split('.').filter(Boolean);
194
+ while (existing.length > pathParts.length && rootNames.has(existing[0]))
195
+ existing = existing.slice(1);
196
+ const isExactAlignment = existing.length === pathParts.length;
197
+ const customTables = componentType === 'CustomTrigger' && Array.isArray(meta?._custom_trigger_data?.tableList)
198
+ ? meta?._custom_trigger_data.tableList : [];
199
+ const hasCustomTables = customTables.length > 0;
200
+ if (isExactAlignment && !(componentType === 'CustomTrigger' && hasCustomTables)) {
201
+ return existing.map((name, index) => {
202
+ const isArray = /\[[^\]]*\]/.test(pathParts[index]) || pathParts[index].endsWith('[]');
203
+ return isArray && !name.endsWith('[]') ? `${name}[]` : name;
204
+ }).join('.');
205
+ }
206
+ const tokenOf = (value) => String(value ?? '').replace(/\[[^\]]*\]/g, '').replace(/\[\]/g, '');
207
+ const sameToken = (value, token) => {
208
+ const candidate = String(value ?? '').trim();
209
+ return Boolean(candidate) && candidate === token;
210
+ };
211
+ const tableLabel = (token) => {
212
+ const table = customTables.find((item) => item && (sameToken(item.id, token) || sameToken(item.formId, token) || sameToken(item.paramName, token)
213
+ || sameToken(item.paramKey, token) || sameToken(item.key, token)
214
+ || sameToken(item.showName, token) || sameToken(item.name, token)));
215
+ // CustomTrigger 的语义计划使用 mainTable/detailN 作为稳定的逻辑键,
216
+ // 但前端 parentName 要显示真实的主表/明细表名称。这里补齐 onClick
217
+ // 选中上下文时的“逻辑键 -> tableList 顺序”映射。
218
+ if (!table) {
219
+ if (/^(?:main|mainTable)$/i.test(token)) {
220
+ const mainTable = customTables.find((item) => item && (item.isMain === true || item.isMain === 1 || String(item.isMain) === '1'));
221
+ return String(mainTable?.showName || mainTable?.name || mainTable?.paramName || '');
222
+ }
223
+ const numberedDetail = String(token).match(/^detail(\d+)$/i);
224
+ if (numberedDetail) {
225
+ const detailIndex = Number(numberedDetail[1]) - 1;
226
+ const detailTables = customTables.filter((item) => item && !(item.isMain === true || item.isMain === 1 || String(item.isMain) === '1'))
227
+ .sort((left, right) => Number(left.orderNum ?? left.order ?? 0) - Number(right.orderNum ?? right.order ?? 0));
228
+ const detailTable = detailTables[detailIndex];
229
+ return String(detailTable?.showName || detailTable?.name || detailTable?.paramName || '');
230
+ }
231
+ }
232
+ return String(table?.showName || table?.name || table?.paramName || '');
233
+ };
234
+ const labels = [];
235
+ const workflowName = String(meta?._upstream_workflow_name || meta?._upstream_form_name || '');
236
+ const workflowId = tokenOf(pathParts[0]);
237
+ const detailId = pathParts.length > 2 ? tokenOf(pathParts[pathParts.length - 2]) : '';
238
+ const detailName = workflowId && detailId
239
+ ? String(getWorkflowDetailNames()[workflowId]?.[detailId] || '') : '';
240
+ for (let index = 0; index < pathParts.length; index += 1) {
241
+ const pathPart = pathParts[index];
242
+ const token = tokenOf(pathPart);
243
+ const isArray = /\[[^\]]*\]/.test(pathPart) || pathPart.endsWith('[]');
244
+ let label = '';
245
+ if (index === pathParts.length - 1) {
246
+ label = String(fieldLabel || existing[existing.length - 1] || token);
247
+ }
248
+ else if (componentType === 'CustomTrigger') {
249
+ const existingName = existing[index];
250
+ label = tableLabel(token) || (isExactAlignment && !rootNames.has(existingName) ? existingName : token);
251
+ }
252
+ else if (index === 0) {
253
+ label = workflowName || (isExactAlignment ? existing[0] : token);
254
+ }
255
+ else if (index === pathParts.length - 2) {
256
+ label = detailName || (isExactAlignment ? existing[index] : token);
257
+ }
258
+ else {
259
+ label = isExactAlignment ? existing[index] : token;
260
+ }
261
+ if (isArray && !label.endsWith('[]'))
262
+ label = `${label}[]`;
263
+ labels.push(label);
264
+ }
265
+ return labels.join('.');
266
+ }
267
+ /**
268
+ * 对齐 context/index.tsx onClick 的循环路径组装结果。
269
+ *
270
+ * 前端会根据当前循环是“当次”还是“历次”决定是否把 multKey/multName
271
+ * 拼到字段前面。后端没有浏览器 sessionStorage,因此只消费编译/预检阶段
272
+ * 已明确写入的 effectiveMultKey;没有该信息时保留接口返回的当前字段路径,
273
+ * 不凭空把一个当次循环改成历次循环。
274
+ */
275
+ function resolveFrontendMultPath(paramKey, parentName, meta = null) {
276
+ const baseParamKey = String(meta?._context_original_param_key || paramKey || '');
277
+ const selectedParamKey = String(meta?._context_selected_param_key || '');
278
+ const baseParentName = String(meta?._context_original_parent_name || parentName || '');
279
+ const multKey = String(meta?._context_mult_key || '');
280
+ const multName = String(meta?._context_mult_name || '');
281
+ const effectiveMultKey = String(meta?._context_effective_mult_key || '');
282
+ const effectiveMultName = String(meta?._context_effective_mult_name || '');
283
+ const currentParamKey = selectedParamKey
284
+ || (effectiveMultKey && !baseParamKey.startsWith(`${effectiveMultKey}.`)
285
+ ? `${effectiveMultKey}.${baseParamKey}` : baseParamKey);
286
+ const currentParentName = effectiveMultName && !baseParentName.startsWith(`${effectiveMultName}.`)
287
+ ? `${effectiveMultName}.${baseParentName}` : baseParentName;
288
+ const allParamKey = multKey && !baseParamKey.startsWith(`${multKey}.`)
289
+ ? `${multKey}.${baseParamKey}` : baseParamKey;
290
+ const allParentName = String(meta?._context_all_parent_name || '')
291
+ || (multName && !baseParentName.startsWith(`${multName}.`)
292
+ ? `${multName}.${baseParentName}` : baseParentName);
293
+ return {
294
+ paramKey: currentParamKey,
295
+ parentName: currentParentName,
296
+ allParamKey,
297
+ allParentName,
298
+ multKey,
299
+ multName,
300
+ };
301
+ }
302
+ function addContextTableKey(paramKey, meta = null) {
303
+ const tableKey = String(meta?._context_table_key || '').replace(/\.$/, '');
304
+ const rawKey = String(paramKey || '');
305
+ if (!tableKey || ['FormData', 'ApprovalData', 'SelectParams'].includes(tableKey))
306
+ return rawKey;
307
+ if (rawKey === tableKey || rawKey.startsWith(`${tableKey}.`))
308
+ return rawKey;
309
+ return `${tableKey}.${rawKey}`;
310
+ }
311
+ function resolveCustomTriggerFormulaFrontId(paramKey, resolved = {}, meta = null) {
312
+ const rawKey = String(paramKey || '');
313
+ const tableKey = String(resolved.tableKey || meta?._context_table_key || '');
314
+ const lookupKey = tableKey
315
+ && !rawKey.startsWith(`${tableKey}.`)
316
+ ? `${tableKey}.${rawKey}`
317
+ : rawKey;
318
+ return resolveCustomTriggerDtoId(lookupKey, meta?._custom_trigger_data, String(resolved.dimension || meta?._context_dimension || ''));
319
+ }
170
320
  // ── Formula 对象生成器 ───────────────────────────────────────
171
321
  function makeConfigStr(config) {
172
322
  return JSON.stringify(config);
@@ -208,6 +358,7 @@ export function formulaContext(sourceComponentId, fieldKey, opts = {}) {
208
358
  const fieldType = opts.fieldType || 'string';
209
359
  const contextRoot = contextRootForComponent(componentType);
210
360
  const tableName = contextTableNameForRoot(contextRoot);
361
+ const parentName = alignContextParentName(fieldKey, opts.parentName || fieldName, fieldName, opts.meta || null, { componentType });
211
362
  return {
212
363
  formulaType: ftNorm(fieldType),
213
364
  name: fieldName,
@@ -223,12 +374,12 @@ export function formulaContext(sourceComponentId, fieldKey, opts = {}) {
223
374
  config: makeConfigStr({
224
375
  paramKey: String(fieldKey),
225
376
  paramType: fieldType,
226
- parentName: fieldName,
227
- newParentName: fieldName,
377
+ parentName,
378
+ newParentName: parentName,
228
379
  multKey: '',
229
380
  multName: '',
230
381
  multTypeObj: {
231
- allName: fieldName, currentName: fieldName,
382
+ allName: parentName, currentName: parentName,
232
383
  currentParamKey: `${contextRoot}.${fieldKey}`, allParamKey: `${contextRoot}.${fieldKey}`,
233
384
  },
234
385
  comId: sourceId,
@@ -334,6 +485,32 @@ export function formulaContainerString(childFormulas, valuePlaceholder = '', app
334
485
  sortWeight: 0.0,
335
486
  };
336
487
  }
488
+ /**
489
+ * 动态赋值暂不生成 textarea(type=8) 模式。
490
+ *
491
+ * 函数参数通常只需要一个子 FormulaBean;遇到旧的单子项 textarea 容器时
492
+ * 直接展开,避免把 textarea 结构带进函数参数或普通动态赋值。多子项容器
493
+ * 无法在不改变语义的情况下展开,直接拒绝生成而不是继续输出该模式。
494
+ */
495
+ function unwrapDynamicTextarea(value, location = '动态赋值') {
496
+ if (Array.isArray(value))
497
+ return value.map((item) => unwrapDynamicTextarea(item, location));
498
+ if (!value || typeof value !== 'object')
499
+ return value;
500
+ const type = String(value.type || '');
501
+ if (type === '8') {
502
+ const children = Array.isArray(value.childs) ? value.childs : [];
503
+ if (children.length !== 1) {
504
+ throw new Error(`${location}暂不支持 textarea 模式(type=8 多子项容器)`);
505
+ }
506
+ const child = unwrapDynamicTextarea(children[0], location);
507
+ return child && typeof child === 'object' ? { ...child, parentId: 0 } : child;
508
+ }
509
+ if (Array.isArray(value.childs)) {
510
+ return { ...value, childs: value.childs.map((child) => unwrapDynamicTextarea(child, location)) };
511
+ }
512
+ return value;
513
+ }
337
514
  export function buildPersonObject(personId, personName) {
338
515
  const pid = String(personId);
339
516
  const pname = String(personName || pid);
@@ -654,11 +831,90 @@ function buildNamedFunctionBean(ref, fieldId, fieldType, meta, appId, defaultSou
654
831
  // ActionEbAdd 的“依据值下级”字段映射是两种不同的前端结构。
655
832
  const childs = args.map((arg, index) => {
656
833
  const resolved = resolveFunctionArgument(arg, entry.detail[index], entry.name, index);
657
- const child = resolved.value;
658
- return buildAssignBean(child && typeof child === 'object' ? { ...child, _formulaArgument: true } : child, fieldId, resolved.fieldType || formulaType, meta, appId, defaultSourceId);
834
+ const child = unwrapDynamicTextarea(resolved.value, `函数 '${entry.name}' 第 ${index + 1} 个参数`);
835
+ let normalizedChild = child;
836
+ // 预检阶段会把字段上下文挂到原始引用上;函数参数经过
837
+ // resolveFunctionArgument/unwrapDynamicTextarea 后仍需显式保留这份
838
+ // CustomTrigger 元数据,否则 buildAssignBean 只能看到字段名 d/e/f,
839
+ // 最终把字段名错误地写入 FormulaBean.frontId。
840
+ if (child && typeof child === 'object' && String(child.kind || child.assignmentKind || '') === 'context') {
841
+ const customData = meta?._custom_trigger_data;
842
+ const childKey = String(child.paramKey || child.key || '');
843
+ if (customData && childKey) {
844
+ const resolvedContext = child._resolvedContext && typeof child._resolvedContext === 'object'
845
+ ? child._resolvedContext : {};
846
+ const fieldId = String(resolvedContext.fieldId
847
+ || resolveCustomTriggerDtoId(childKey, customData, 'field')
848
+ || child.frontId
849
+ || '');
850
+ normalizedChild = {
851
+ ...child,
852
+ componentType: String(child.componentType || 'CustomTrigger'),
853
+ frontId: fieldId,
854
+ _resolvedContext: {
855
+ ...resolvedContext,
856
+ fieldId,
857
+ componentType: 'CustomTrigger',
858
+ paramKey: childKey,
859
+ parentName: String(resolvedContext.parentName || child.parentName || ''),
860
+ },
861
+ };
862
+ }
863
+ }
864
+ return buildAssignBean(normalizedChild && typeof normalizedChild === 'object' ? { ...normalizedChild, _formulaArgument: true } : normalizedChild, fieldId, resolved.fieldType || formulaType, meta, appId, defaultSourceId);
659
865
  });
660
866
  return formulaFunction(entry.id, entry.name, childs, formulaType, entry.excelFunc, entry.category || entry.resultType, entry.detail, appId, entry.paramSize);
661
867
  }
868
+ /**
869
+ * 把循环当前项的业务字段还原为上游列表的带索引上下文。
870
+ * CustomTrigger 的列表数据来自 SelectParams,不能复用 EnquiryForm 的
871
+ * query_result(FormData);其他来源也沿用各自的上下文根节点。
872
+ */
873
+ function buildIndexedSourceContextFormula(sourceParamKey, fieldLabel, sourceId, appId, fieldType, resolved, meta) {
874
+ const marker = sourceParamKey.indexOf('[]');
875
+ if (marker < 0)
876
+ throw new Error(`[context] 循环列表来源 paramKey 缺少 []: ${sourceParamKey}`);
877
+ const componentType = String(resolved.sourceComponentType || resolved.componentType || 'EventFormData');
878
+ const contextRoot = String(resolved.sourceTablePrimaryKey || contextRootForComponent(componentType));
879
+ const tableName = String(resolved.sourceTableName || contextTableNameForRoot(contextRoot));
880
+ const position = genSfId();
881
+ const indexedParamKey = `${sourceParamKey.slice(0, marker)}[${position}]${sourceParamKey.slice(marker + 2)}`;
882
+ const rawField = resolved.rawField && typeof resolved.rawField === 'object' ? resolved.rawField : {};
883
+ const label = String(resolved.label || fieldLabel || rawField.showName || rawField.paramName || sourceParamKey);
884
+ const parentName = alignContextParentName(sourceParamKey, resolved.parentName || `${tableName}.${label}`, label, meta, { componentType });
885
+ const frontIdCandidate = componentType === 'CustomTrigger'
886
+ ? resolveCustomTriggerFormulaFrontId(sourceParamKey, resolved, meta)
887
+ : (resolved.fieldId ?? rawField.id ?? rawField.paramId ?? '');
888
+ const frontId = normalizeNumericFrontId(frontIdCandidate, '循环当前项上下文 FormulaBean.frontId');
889
+ const child = formulaFixed('0', 'string');
890
+ child.name = '0';
891
+ child.position = position;
892
+ const flat = {
893
+ ...rawField,
894
+ formulaType: ftNorm(fieldType), name: label, parentName,
895
+ businessId: appId || '', id: genSfId(), source: String(sourceId || '0'), type: '3',
896
+ value: `${contextRoot}.${indexedParamKey}`, frontId,
897
+ paramKey: sourceParamKey, paramType: fieldType, fieldType: ftNorm(fieldType),
898
+ childs: [child], parentId: '0',
899
+ config: {
900
+ paramKey: sourceParamKey, isMultCom: false, comType: componentType,
901
+ switchType: 'assign', parentComId: 0, formulaVersion: 'V1',
902
+ fieldInfo: { paramKey: sourceParamKey, tablePrimaryKey: contextRoot },
903
+ tableName, paramType: ftNorm(fieldType), parentName,
904
+ multName: '', multKey: '',
905
+ multTypeObj: {
906
+ allName: parentName, currentName: parentName,
907
+ currentParamKey: `${contextRoot}.${indexedParamKey}`,
908
+ allParamKey: `${contextRoot}.${sourceParamKey}`,
909
+ },
910
+ comId: String(sourceId || '0'), newParentName: parentName,
911
+ },
912
+ };
913
+ child.parentId = flat.id;
914
+ child.position = position;
915
+ attachEsbAssign(flat, meta, String(sourceId || '0'));
916
+ return flat;
917
+ }
662
918
  export function buildAssignBean(raw, fieldId, fieldType, meta, appId, defaultSourceId = '') {
663
919
  if (!meta || typeof meta !== 'object')
664
920
  meta = {};
@@ -697,6 +953,11 @@ export function buildAssignBean(raw, fieldId, fieldType, meta, appId, defaultSou
697
953
  const sourceComponentId = String(resolved.sourceComponentId || '');
698
954
  const listMarker = sourceParamKey.indexOf('[]');
699
955
  if (sourceParamKey && sourceComponentId && listMarker >= 0) {
956
+ const sourceComponentType = String(resolved.sourceComponentType || resolved.sourceComponent || '');
957
+ if (sourceComponentType === 'CustomTrigger') {
958
+ const sourceBean = buildIndexedSourceContextFormula(sourceParamKey, String(resolved.label ?? label), sourceComponentId, appId, String(resolved.fieldType ?? src.fieldType ?? src.valueType ?? fieldType), resolved, meta);
959
+ return sourceBean;
960
+ }
700
961
  const formId = sourceParamKey.slice(0, listMarker);
701
962
  const sourceFieldKey = sourceParamKey.slice(listMarker + 2).replace(/^\./, '');
702
963
  if (formId && sourceFieldKey) {
@@ -714,10 +975,7 @@ export function buildAssignBean(raw, fieldId, fieldType, meta, appId, defaultSou
714
975
  rawField: resolved.rawField,
715
976
  },
716
977
  }, fieldId, fieldType, meta, appId, defaultSourceId);
717
- const container = formulaContainerString([queryBean], '', appId);
718
- delete container.configObject;
719
- container.config = { paramType: 'string', formulaVersion: 'V1' };
720
- return container;
978
+ return queryBean;
721
979
  }
722
980
  }
723
981
  return formulaCurrentLoopContext(String(sourceId), String(key), {
@@ -732,6 +990,7 @@ export function buildAssignBean(raw, fieldId, fieldType, meta, appId, defaultSou
732
990
  const wfId = String(meta._workflow_id || '');
733
991
  const resolvedKey = resolveParamKey(wfId, String(key));
734
992
  const sourceFieldType = resolveSourceFieldType(resolvedKey, meta) || String(src.fieldType || src.valueType || 'string');
993
+ const resolved = src && typeof src._resolvedContext === 'object' ? src._resolvedContext : {};
735
994
  // 批量新增的普通字段映射与函数参数使用不同的前端协议:前者是 type=10/sub,
736
995
  // 而函数里的明细字段必须是带索引子节点的 type=3 上下文引用。
737
996
  if (resolvedKey.includes('[].')) {
@@ -745,7 +1004,9 @@ export function buildAssignBean(raw, fieldId, fieldType, meta, appId, defaultSou
745
1004
  }
746
1005
  return formulaIndexedWorkflowDetailArgument(resolvedKey, String(label), String(sourceId), appId, String(sourceFieldType || fieldType || 'string'), detailLabel, sourceComponent === 'CustomTrigger'
747
1006
  ? { ...(meta || {}), _context_component_type: sourceComponent, _upstream_component_type: sourceComponent }
748
- : meta, src?._resolvedContext?.fieldId);
1007
+ : meta, sourceComponent === 'CustomTrigger'
1008
+ ? String(resolved.fieldId || resolveCustomTriggerFormulaFrontId(resolvedKey, resolved, meta))
1009
+ : src?._resolvedContext?.fieldId);
749
1010
  }
750
1011
  const child = assignFlatEsbChild(resolvedKey, String(label), String(sourceId), appId, String(sourceFieldType || fieldType || 'string'), undefined, detailLabel, workflowName, sourceComponent);
751
1012
  attachEsbAssign(child, meta, String(sourceId));
@@ -754,15 +1015,50 @@ export function buildAssignBean(raw, fieldId, fieldType, meta, appId, defaultSou
754
1015
  // 不能用 formulaContext 的默认 ApproveTrigger 壳:定时/表单/日期触发器的
755
1016
  // 动态文本会因此在设计器中只显示固定前缀。这里统一生成带真实来源组件、
756
1017
  // frontId 和 paramKey 的上下文 FormulaBean。
757
- const resolved = src && typeof src._resolvedContext === 'object' ? src._resolvedContext : {};
758
- const sourceMeta = resolved.componentType || src?.componentType
759
- ? { ...(meta || {}), _context_component_type: String(resolved.componentType || src?.componentType) }
760
- : meta;
1018
+ const sourceComponentType = String(resolved.componentType || src?.componentType || sourceComponent);
1019
+ const sourceMeta = {
1020
+ ...(meta || {}),
1021
+ ...(sourceComponentType ? { _context_component_type: sourceComponentType } : {}),
1022
+ ...(resolved.tablePrimaryKey ? { _context_table_primary_key: String(resolved.tablePrimaryKey) } : {}),
1023
+ ...(resolved.tableName ? { _context_table_name: String(resolved.tableName) } : {}),
1024
+ ...(resolved.tableKey ? { _context_table_key: String(resolved.tableKey) } : {}),
1025
+ ...(resolved.multKey ? { _context_mult_key: String(resolved.multKey) } : {}),
1026
+ ...(resolved.multName ? { _context_mult_name: String(resolved.multName) } : {}),
1027
+ ...(resolved.allParentName ? { _context_all_parent_name: String(resolved.allParentName) } : {}),
1028
+ ...(resolved.originalParentName ? { _context_original_parent_name: String(resolved.originalParentName) } : {}),
1029
+ ...(resolved.effectiveMultKey ? { _context_effective_mult_key: String(resolved.effectiveMultKey) } : {}),
1030
+ ...(resolved.effectiveMultName ? { _context_effective_mult_name: String(resolved.effectiveMultName) } : {}),
1031
+ ...(resolved.paramKey ? { _context_original_param_key: String(resolved.paramKey) } : {}),
1032
+ ...(resolved.dimension ? { _context_dimension: String(resolved.dimension) } : {}),
1033
+ ...(resolved.isMultCom !== undefined ? { _context_is_mult_com: Boolean(resolved.isMultCom) } : {}),
1034
+ ...(resolved.parentComId ? { _context_parent_com_id: String(resolved.parentComId) } : {}),
1035
+ _context_selected_param_key: String(key || resolvedKey),
1036
+ };
761
1037
  const sourceName = String(resolved.parentName || meta._upstream_workflow_name || meta._upstream_form_name || '');
762
1038
  const parentName = sourceName
763
1039
  ? (sourceName.endsWith(`.${String(label)}`) ? sourceName : `${sourceName}.${String(label)}`)
764
1040
  : `表单数据.${String(label)}`;
765
- const contextBean = assignFlatContextDirect(resolvedKey, String(label), String(sourceId), appId, sourceFieldType, parentName, sourceMeta, resolved.fieldId);
1041
+ const multPath = resolveFrontendMultPath(String(key || resolvedKey), parentName, sourceMeta);
1042
+ sourceMeta._context_original_param_key = String(resolved.paramKey || resolvedKey);
1043
+ const contextBean = assignFlatContextDirect(multPath.paramKey, String(label), String(sourceId), appId, sourceFieldType, multPath.parentName, sourceMeta, resolved.fieldId);
1044
+ if (contextBean.config && typeof contextBean.config === 'object') {
1045
+ contextBean.config.newParentName = multPath.allParentName;
1046
+ contextBean.config.multTypeObj = {
1047
+ ...(contextBean.config.multTypeObj || {}),
1048
+ currentName: multPath.parentName,
1049
+ allName: multPath.allParentName,
1050
+ currentParamKey: `${String(resolved.tablePrimaryKey || contextRootForComponent(sourceComponentType))}.${addContextTableKey(multPath.paramKey, sourceMeta)}`,
1051
+ allParamKey: `${String(resolved.tablePrimaryKey || contextRootForComponent(sourceComponentType))}.${addContextTableKey(multPath.allParamKey, sourceMeta)}`,
1052
+ };
1053
+ contextBean.config.multKey = multPath.multKey;
1054
+ contextBean.config.multName = multPath.multName;
1055
+ contextBean.config.isMultCom = Boolean(resolved.isMultCom);
1056
+ contextBean.config.parentComId = String(resolved.parentComId || contextBean.config.parentComId || '0');
1057
+ contextBean.config.fieldInfo = {
1058
+ ...(contextBean.config.fieldInfo || {}),
1059
+ paramKey: String(resolved.paramKey || resolvedKey),
1060
+ };
1061
+ }
766
1062
  attachEsbAssign(contextBean, meta, String(sourceId));
767
1063
  return contextBean;
768
1064
  }
@@ -970,24 +1266,24 @@ export function assignFlatContext(paramKey, fieldLabel, sourceId, appId, fieldTy
970
1266
  const componentType = String(meta?._context_component_type || meta?._upstream_component_type || '');
971
1267
  const contextRoot = contextRootForComponent(componentType);
972
1268
  const tableName = contextTableNameForRoot(contextRoot);
973
- const pname = String(parentName || fieldLabel);
974
1269
  const val = valueFull
975
1270
  ? String(valueFull).replace(/^(?:FormData|ApprovalData|SelectParams)\./, `${contextRoot}.`)
976
1271
  : (tableId ? `${contextRoot}.${tableId}.${paramKey}` : `${contextRoot}.${paramKey}`);
977
1272
  const pkey = paramKeyFull || (tableId ? `${tableId}.${paramKey}` : String(paramKey));
1273
+ const alignedParentName = alignContextParentName(pkey, parentName || fieldLabel, fieldLabel, meta, { componentType });
978
1274
  return {
979
1275
  id: fid, name: String(fieldLabel), value: val, type: '3', fieldType, formulaType: fieldType,
980
1276
  businessId: appId || '', applicationId: appId || '', source: src,
981
1277
  paramTypeString: 'STRING', dataTypeSting: 'ATTRIBUTE',
982
1278
  config: makeConfigStr({
983
1279
  switchType: 'assign', comId: src, paramKey: pkey, paramType: fieldType,
984
- parentName: pname, newParentName: pname, multName: '', multKey: '',
985
- multTypeObj: { currentName: pname, allName: pname, currentParamKey: val, allParamKey: val },
1280
+ parentName: alignedParentName, newParentName: alignedParentName, multName: '', multKey: '',
1281
+ multTypeObj: { currentName: alignedParentName, allName: alignedParentName, currentParamKey: val, allParamKey: val },
986
1282
  isMultCom: false, comType: componentType || 'ApproveTrigger', tableName,
987
1283
  fieldInfo: { tablePrimaryKey: contextRoot, paramKey: pkey },
988
1284
  tempFormulaId: tempFormulaId || '', formulaVersion: 'V1',
989
1285
  }),
990
- parentName: pname, tempFormulaId: tempFormulaId || '',
1286
+ parentName: alignedParentName, tempFormulaId: tempFormulaId || '',
991
1287
  };
992
1288
  }
993
1289
  function assignFlatHttpContext(paramKey, fieldLabel, sourceId, appId, fieldType = 'string', parentName = '', tablePrimaryKey = 'responseBody', meta = null) {
@@ -1040,25 +1336,43 @@ function assignFlatHttpContext(paramKey, fieldLabel, sourceId, appId, fieldType
1040
1336
  export function assignFlatContextDirect(paramKey, fieldLabel, sourceId, appId, fieldType = 'string', parentName = '', meta = null, resolvedFrontId = '') {
1041
1337
  const fid = genSfId();
1042
1338
  const src = String(sourceId) || '0';
1043
- const pkey = String(paramKey);
1044
- const httpMatch = pkey.match(/^(responseBody|responseHeader|responseCookie|URL)\.(.+)$/);
1339
+ const requestedPkey = String(paramKey);
1340
+ const httpMatch = requestedPkey.match(/^(responseBody|responseHeader|responseCookie|URL)\.(.+)$/);
1045
1341
  if (httpMatch) {
1046
1342
  return assignFlatHttpContext(httpMatch[2], fieldLabel, src, appId, fieldType, parentName, httpMatch[1], meta);
1047
1343
  }
1048
- const pname = String(parentName || `表单数据.${fieldLabel}`);
1344
+ const componentType = String(meta?._context_component_type || meta?._upstream_component_type || '');
1345
+ const contextRoot = String(meta?._context_table_primary_key || contextRootForComponent(componentType));
1346
+ const parameterContext = isParameterContext(componentType, requestedPkey, contextRoot);
1347
+ const parameterTable = WEBHOOK_CONTEXT_TABLES.has(contextRoot)
1348
+ ? contextRoot
1349
+ : WEBHOOK_CONTEXT_TABLES.has(requestedPkey.split('.')[0])
1350
+ ? requestedPkey.split('.')[0]
1351
+ : componentType === 'ServerlessAction' && SERVERLESS_CONTEXT_TABLES.has(contextRoot)
1352
+ ? contextRoot
1353
+ : SERVERLESS_CONTEXT_TABLES.has(requestedPkey.split('.')[0])
1354
+ ? requestedPkey.split('.')[0]
1355
+ : componentType === 'ServerlessAction' ? 'Response' : 'Body';
1356
+ const pkey = parameterContext
1357
+ ? ((WEBHOOK_CONTEXT_TABLES.has(requestedPkey.split('.')[0]) || SERVERLESS_CONTEXT_TABLES.has(requestedPkey.split('.')[0]))
1358
+ ? requestedPkey : `${parameterTable}.${requestedPkey}`)
1359
+ : requestedPkey.replace(/^(?:FormData|ApprovalData|SelectParams)\./, '');
1360
+ const multPath = resolveFrontendMultPath(pkey, parentName || `表单数据.${fieldLabel}`, meta);
1361
+ const currentPkey = multPath.paramKey;
1362
+ const pname = alignContextParentName(currentPkey, multPath.parentName, fieldLabel, meta, { componentType });
1049
1363
  const tail = pkey.includes('.') ? pkey.slice(pkey.lastIndexOf('.') + 1).replace(/\[\]$/, '') : pkey.replace(/\[\]$/, '');
1050
1364
  const plainApprovalShape = !/^\d+$/.test(tail) && !pkey.includes('[].') && !pkey.includes('[]. ');
1051
1365
  let frontId = '';
1052
1366
  let ctxComponentKey = '';
1053
1367
  const wfId = String(meta?._workflow_id || meta?._event_form_id || '');
1054
1368
  const ctxFields = wfId ? (getWorkflowContextFields()[wfId] || {}) : {};
1055
- const pkeyTail = pkey.includes('.') ? pkey.slice(pkey.lastIndexOf('.') + 1).replace(/\[\]$/, '') : pkey.replace(/\[\]$/, '');
1369
+ const pkeyTail = currentPkey.includes('.') ? currentPkey.slice(currentPkey.lastIndexOf('.') + 1).replace(/\[\]$/, '') : currentPkey.replace(/\[\]$/, '');
1056
1370
  for (const field of Object.values(ctxFields)) {
1057
1371
  if (!field || typeof field !== 'object')
1058
1372
  continue;
1059
1373
  const candidate = String(field.paramKey || '');
1060
1374
  const candTail = candidate.includes('.') ? candidate.slice(candidate.lastIndexOf('.') + 1).replace(/\[\]$/, '') : candidate.replace(/\[\]$/, '');
1061
- if (candidate !== pkey && candTail !== pkeyTail)
1375
+ if (candidate !== currentPkey && candTail !== pkeyTail)
1062
1376
  continue;
1063
1377
  if (String(field.id || ''))
1064
1378
  frontId = String(field.id);
@@ -1081,29 +1395,36 @@ export function assignFlatContextDirect(paramKey, fieldLabel, sourceId, appId, f
1081
1395
  // frontId 必须 = 字段 id(paramKey 尾段),设计器用它在字段浏览器里定位字段;
1082
1396
  // 清空会导致设计器「动态赋值」找不到字段标红(真机验证 2026-08-19,场景12)。
1083
1397
  const customFrontId = resolvedSourceComponent === 'CustomTrigger'
1084
- ? resolveCustomTriggerDtoId(paramKey, meta?._custom_trigger_data, '')
1398
+ ? resolveCustomTriggerDtoId(addContextTableKey(currentPkey, meta), meta?._custom_trigger_data, String(meta?._context_dimension || ''))
1085
1399
  : '';
1086
1400
  const frontIdCandidate = resolvedSourceComponent === 'CustomTrigger'
1087
- ? (customFrontId || resolvedFrontId)
1401
+ // CustomTrigger 的 frontId 只能来自触发器 customData.tableList。
1402
+ // 接口字段 id、paramKey 尾段和外部传入的临时 frontId 都不能兜底。
1403
+ ? customFrontId
1088
1404
  : (resolvedFrontId || frontId || pkeyTail);
1089
1405
  frontId = normalizeNumericFrontId(frontIdCandidate, '上下文 FormulaBean.frontId');
1090
- const prefix = isApproval ? 'ApprovalData' : contextRootForComponent(resolvedSourceComponent);
1091
- const tableName = contextTableNameForRoot(prefix);
1406
+ const prefix = isApproval ? 'ApprovalData' : (resolvedSourceComponent === 'CustomTrigger' ? 'SelectParams' : contextRoot);
1407
+ const valuePrefix = parameterContext ? '' : `${prefix}.`;
1408
+ const tableName = String(meta?._context_table_name || (parameterContext ? parameterTable : contextTableNameForRoot(prefix)));
1092
1409
  const sourceComponent = resolvedSourceComponent;
1410
+ const valueParamKey = parameterContext ? currentPkey : addContextTableKey(currentPkey, meta);
1411
+ const allValueParamKey = parameterContext ? multPath.allParamKey : addContextTableKey(multPath.allParamKey, meta);
1412
+ const fieldInfoParamKey = String(meta?._context_original_param_key || pkey);
1093
1413
  const result = {
1094
1414
  formulaType: fieldType, name: String(fieldLabel), businessId: appId || '', id: fid,
1095
- source: src, type: '3', value: `${prefix}.${pkey}`,
1096
- frontId, paramKey: pkey, parentName: pname, childs: [],
1415
+ source: src, type: '3', value: `${valuePrefix}${valueParamKey}`,
1416
+ frontId, paramKey: currentPkey, parentName: pname, childs: [],
1097
1417
  config: {
1098
- paramKey: pkey, isMultCom: false, comType: sourceComponent, switchType: 'assign', formulaVersion: 'V1',
1099
- fieldInfo: { paramKey: pkey, tablePrimaryKey: prefix },
1418
+ paramKey: currentPkey, isMultCom: Boolean(meta?._context_is_mult_com), comType: sourceComponent, switchType: 'assign', formulaVersion: 'V1',
1419
+ fieldInfo: { paramKey: fieldInfoParamKey, tablePrimaryKey: parameterContext ? parameterTable : prefix },
1100
1420
  tableName,
1101
- paramType: fieldType, parentName: pname, multName: '', multKey: '',
1421
+ paramType: fieldType, parentName: pname, multName: multPath.multName, multKey: multPath.multKey,
1102
1422
  multTypeObj: {
1103
- allName: pname, currentName: pname,
1104
- currentParamKey: `${prefix}.${pkey}`, allParamKey: `${prefix}.${pkey}`,
1423
+ allName: multPath.allParentName, currentName: pname,
1424
+ currentParamKey: `${valuePrefix}${valueParamKey}`, allParamKey: `${valuePrefix}${allValueParamKey}`,
1105
1425
  },
1106
- comId: src, newParentName: pname,
1426
+ comId: String(meta?._context_com_id || src), newParentName: multPath.allParentName,
1427
+ parentComId: String(meta?._context_parent_com_id || '0'),
1107
1428
  },
1108
1429
  parentId: '0',
1109
1430
  };
@@ -1111,6 +1432,20 @@ export function assignFlatContextDirect(paramKey, fieldLabel, sourceId, appId, f
1111
1432
  result.frontId = frontId;
1112
1433
  return result;
1113
1434
  }
1435
+ function directContextMeta(meta, sourceComponent, sourceRef) {
1436
+ if (sourceComponent !== 'CustomTrigger' && sourceComponent !== 'WebHookTrigger' && sourceComponent !== 'ServerlessAction')
1437
+ return meta;
1438
+ const resolved = sourceRef?._resolvedContext && typeof sourceRef._resolvedContext === 'object'
1439
+ ? sourceRef._resolvedContext : {};
1440
+ return {
1441
+ ...(meta || {}),
1442
+ _context_component_type: sourceComponent,
1443
+ ...(['WebHookTrigger', 'ServerlessAction'].includes(sourceComponent) ? {
1444
+ _context_table_primary_key: String(resolved.tablePrimaryKey || resolved.tableKey || ''),
1445
+ _context_table_name: String(resolved.tableName || ''),
1446
+ } : {}),
1447
+ };
1448
+ }
1114
1449
  function assignFlatEsbChild(paramKey, fieldLabel, sourceId, appId, fieldType = 'string', detailParamKey = '', detailLabel = '', workflowName = '', componentType = 'ApproveTrigger') {
1115
1450
  const fid = genSfId();
1116
1451
  const src = String(sourceId) || '0';
@@ -1160,12 +1495,12 @@ function formulaIndexedWorkflowDetailArgument(paramKey, fieldLabel, sourceId, ap
1160
1495
  const [, workflowId, detailId, detailFieldId] = match;
1161
1496
  const detailName = String(getWorkflowDetailNames()[workflowId]?.[detailId] || detailLabel || detailId);
1162
1497
  const workflowName = String(meta?._upstream_workflow_name || '');
1163
- const parentName = `${workflowName ? `${workflowName}.` : ''}${detailName}[].${fieldLabel}`;
1498
+ const sourceComponent = String(meta?._context_component_type || meta?._upstream_component_type || 'ApproveTrigger');
1499
+ const parentName = alignContextParentName(paramKey, `${workflowName ? `${workflowName}.` : ''}${detailName}[].${fieldLabel}`, fieldLabel, meta, { componentType: sourceComponent });
1164
1500
  const index = formulaFixed('0', 'string');
1165
1501
  index.name = '0';
1166
1502
  index.position = genSfId();
1167
1503
  index.parentId = fid;
1168
- const sourceComponent = String(meta?._context_component_type || meta?._upstream_component_type || 'ApproveTrigger');
1169
1504
  const contextRoot = contextRootForComponent(sourceComponent);
1170
1505
  const tableName = contextTableNameForRoot(contextRoot);
1171
1506
  const contextValue = `${contextRoot}.${workflowId}.${detailId}[${index.position}].${detailFieldId}`;
@@ -1361,9 +1696,7 @@ export function buildSettingEntry(fieldId, assignment, fieldType = 'Text', meta
1361
1696
  else if (assignmentMode === 'direct' && operate === 'OPERATE_EQUAL') {
1362
1697
  const workflowId = String(meta._workflow_id || '');
1363
1698
  const paramKeyFull = resolveParamKey(workflowId, String(key));
1364
- const directMeta = sourceComponent === 'CustomTrigger'
1365
- ? { ...(meta || {}), _context_component_type: sourceComponent }
1366
- : meta;
1699
+ const directMeta = directContextMeta(meta, sourceComponent, src);
1367
1700
  flat = assignFlatContextDirect(paramKeyFull, String(label || key), String(src), appId, 'string', String(meta._upstream_workflow_name || ''), directMeta, ref?._resolvedContext?.fieldId);
1368
1701
  switchT = 'assign';
1369
1702
  }
@@ -1410,29 +1743,16 @@ export function buildSettingEntry(fieldId, assignment, fieldType = 'Text', meta
1410
1743
  directParent = `${formName}.${label || pkey}`;
1411
1744
  else
1412
1745
  directParent = `表单数据.${label || key}`;
1413
- const directMeta = sourceComponent === 'CustomTrigger'
1414
- ? { ...(meta || {}), _context_component_type: sourceComponent }
1415
- : meta;
1746
+ const directMeta = directContextMeta(meta, sourceComponent, src);
1416
1747
  flat = assignFlatContextDirect(pkey, String(label || key), String(src), appId, ft, directParent, directMeta, ref?._resolvedContext?.fieldId);
1417
1748
  switchT = 'assign';
1418
1749
  }
1419
1750
  else {
1420
1751
  const child = assignFlatContext(String(key), String(label || key), String(src), appId, ft, parentName, '', tableId, 'Text', pkey, pval, meta);
1421
- const container = formulaContainerString([child], '', appId);
1422
- const childId = String(child.id || '');
1423
- if (childId && typeof child.config === 'string') {
1424
- const cfg = JSON.parse(child.config);
1425
- cfg.tempFormulaId = container.id;
1426
- child.config = JSON.stringify(cfg);
1427
- }
1428
- child.tempFormulaId = container.id;
1429
- const containerSwitch = detailMode && pval.includes('[].') ? 'sub' : 'assign';
1430
- flat = {
1431
- id: container.id, name: '', value: container.value, type: '8', fieldType: ft, formulaType: ft,
1432
- applicationId: appId || '', childs: container.childs,
1433
- config: { paramType: ft, switchType: containerSwitch, formulaVersion: 'V1' },
1434
- };
1435
- switchT = containerSwitch;
1752
+ // 动态赋值暂不生成 textarea(type=8) 容器,直接保留上下文 FormulaBean。
1753
+ flat = child;
1754
+ flat.applicationId ??= appId || '';
1755
+ switchT = pval.includes('[].') ? 'sub' : 'assign';
1436
1756
  }
1437
1757
  }
1438
1758
  }
@@ -1443,9 +1763,7 @@ export function buildSettingEntry(fieldId, assignment, fieldType = 'Text', meta
1443
1763
  if (!srcName)
1444
1764
  srcName = String(meta._upstream_form_name || '');
1445
1765
  const directParent = srcName ? `${srcName}.${label || key}` : `表单数据.${label || key}`;
1446
- const directMeta = sourceComponent === 'CustomTrigger'
1447
- ? { ...(meta || {}), _context_component_type: sourceComponent }
1448
- : meta;
1766
+ const directMeta = directContextMeta(meta, sourceComponent, src);
1449
1767
  flat = assignFlatContextDirect(pkey, String(label || key), String(src), appId, ft, directParent, directMeta, ref?._resolvedContext?.fieldId);
1450
1768
  switchT = 'assign';
1451
1769
  }
@@ -1491,7 +1809,7 @@ export function buildSettingEntry(fieldId, assignment, fieldType = 'Text', meta
1491
1809
  switchT = 'fixvalue';
1492
1810
  }
1493
1811
  else if (kind === 'constant' || kind === 'variable' || kind === 'transform' || kind === 'formula' || kind === 'function' || kind === 'query_result') {
1494
- const bean = buildAssignBean(assignment, fieldId, fieldType, meta, appId, defaultSourceId);
1812
+ const bean = unwrapDynamicTextarea(buildAssignBean(assignment, fieldId, fieldType, meta, appId, defaultSourceId), `字段 ${fieldId} 的动态赋值`);
1495
1813
  const flatId = bean.id || assignId;
1496
1814
  flat = Object.fromEntries(Object.entries(bean).filter(([k]) => !['configObject', 'childs', 'parentId', 'sortWeight', 'position'].includes(k)));
1497
1815
  if (bean.childs)