weaver-e10-builder 1.6.8 → 1.6.10

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 (131) hide show
  1. package/dist/commands/form-attachment-setting.d.ts.map +1 -1
  2. package/dist/commands/form-attachment-setting.js +147 -50
  3. package/dist/commands/form-attachment-setting.js.map +1 -1
  4. package/dist/commands/form-code.d.ts.map +1 -1
  5. package/dist/commands/form-code.js +4 -1
  6. package/dist/commands/form-code.js.map +1 -1
  7. package/dist/commands/form-data.d.ts.map +1 -1
  8. package/dist/commands/form-data.js +4 -1
  9. package/dist/commands/form-data.js.map +1 -1
  10. package/dist/commands/form-field-linkage.d.ts +2 -0
  11. package/dist/commands/form-field-linkage.d.ts.map +1 -1
  12. package/dist/commands/form-field-linkage.js +97 -41
  13. package/dist/commands/form-field-linkage.js.map +1 -1
  14. package/dist/commands/form-layout-code-reviewed.d.ts.map +1 -1
  15. package/dist/commands/form-layout-code-reviewed.js +5 -2
  16. package/dist/commands/form-layout-code-reviewed.js.map +1 -1
  17. package/dist/commands/form-layout.js +1 -1
  18. package/dist/commands/form-layout.js.map +1 -1
  19. package/dist/commands/menu.d.ts.map +1 -1
  20. package/dist/commands/menu.js +90 -1
  21. package/dist/commands/menu.js.map +1 -1
  22. package/dist/commands/wf-form.d.ts.map +1 -1
  23. package/dist/commands/wf-form.js +111 -39
  24. package/dist/commands/wf-form.js.map +1 -1
  25. package/dist/services/action-detail.d.ts.map +1 -1
  26. package/dist/services/action-detail.js +1 -17
  27. package/dist/services/action-detail.js.map +1 -1
  28. package/dist/services/actionflow/components/action_eb_update_compiler.d.ts.map +1 -1
  29. package/dist/services/actionflow/components/action_eb_update_compiler.js +6 -2
  30. package/dist/services/actionflow/components/action_eb_update_compiler.js.map +1 -1
  31. package/dist/services/actionflow/components/custom_trigger.js +1 -1
  32. package/dist/services/actionflow/components/custom_trigger.js.map +1 -1
  33. package/dist/services/actionflow/components/dml_execute.js +1 -1
  34. package/dist/services/actionflow/components/dml_execute.js.map +1 -1
  35. package/dist/services/actionflow/components/document_actions.js +1 -2
  36. package/dist/services/actionflow/components/document_actions.js.map +1 -1
  37. package/dist/services/actionflow/components/eb_get_data_by_id.d.ts.map +1 -1
  38. package/dist/services/actionflow/components/eb_get_data_by_id.js +2 -2
  39. package/dist/services/actionflow/components/eb_get_data_by_id.js.map +1 -1
  40. package/dist/services/actionflow/components/form_data_builder.d.ts.map +1 -1
  41. package/dist/services/actionflow/components/form_data_builder.js +18 -10
  42. package/dist/services/actionflow/components/form_data_builder.js.map +1 -1
  43. package/dist/services/actionflow/components/hrm_actions.js +0 -1
  44. package/dist/services/actionflow/components/hrm_actions.js.map +1 -1
  45. package/dist/services/actionflow/components/webhook_trigger.js +3 -3
  46. package/dist/services/actionflow/components/webhook_trigger.js.map +1 -1
  47. package/dist/services/actionflow/components/workflow_actions.js +3 -2
  48. package/dist/services/actionflow/components/workflow_actions.js.map +1 -1
  49. package/dist/services/actionflow/filter_rules.d.ts.map +1 -1
  50. package/dist/services/actionflow/filter_rules.js +15 -13
  51. package/dist/services/actionflow/filter_rules.js.map +1 -1
  52. package/dist/services/actionflow/form_source.d.ts.map +1 -1
  53. package/dist/services/actionflow/form_source.js +59 -11
  54. package/dist/services/actionflow/form_source.js.map +1 -1
  55. package/dist/services/actionflow/formula_service.d.ts.map +1 -1
  56. package/dist/services/actionflow/formula_service.js +4 -1
  57. package/dist/services/actionflow/formula_service.js.map +1 -1
  58. package/dist/services/actionflow/option_field_types.d.ts +5 -0
  59. package/dist/services/actionflow/option_field_types.d.ts.map +1 -0
  60. package/dist/services/actionflow/option_field_types.js +20 -0
  61. package/dist/services/actionflow/option_field_types.js.map +1 -0
  62. package/dist/services/actionflow/param_group_dto.d.ts.map +1 -1
  63. package/dist/services/actionflow/param_group_dto.js +7 -3
  64. package/dist/services/actionflow/param_group_dto.js.map +1 -1
  65. package/dist/services/actionflow/preflight_service.d.ts.map +1 -1
  66. package/dist/services/actionflow/preflight_service.js +42 -18
  67. package/dist/services/actionflow/preflight_service.js.map +1 -1
  68. package/dist/services/actionflow/webhook_source.d.ts.map +1 -1
  69. package/dist/services/actionflow/webhook_source.js +9 -4
  70. package/dist/services/actionflow/webhook_source.js.map +1 -1
  71. package/dist/services/actionflow/workflow_compiler.d.ts.map +1 -1
  72. package/dist/services/actionflow/workflow_compiler.js +11 -8
  73. package/dist/services/actionflow/workflow_compiler.js.map +1 -1
  74. package/dist/services/form-attachment-settings.d.ts +47 -20
  75. package/dist/services/form-attachment-settings.d.ts.map +1 -1
  76. package/dist/services/form-attachment-settings.js +148 -68
  77. package/dist/services/form-attachment-settings.js.map +1 -1
  78. package/dist/services/form-code.d.ts +1 -1
  79. package/dist/services/form-code.d.ts.map +1 -1
  80. package/dist/services/form-code.js +2 -2
  81. package/dist/services/form-code.js.map +1 -1
  82. package/dist/services/form-layout-code-reviewed.d.ts +2 -0
  83. package/dist/services/form-layout-code-reviewed.d.ts.map +1 -1
  84. package/dist/services/form-layout-code-reviewed.js +4 -3
  85. package/dist/services/form-layout-code-reviewed.js.map +1 -1
  86. package/dist/services/menu-catalog.d.ts +45 -0
  87. package/dist/services/menu-catalog.d.ts.map +1 -1
  88. package/dist/services/menu-catalog.js +76 -0
  89. package/dist/services/menu-catalog.js.map +1 -1
  90. package/dist/services/workflow-layout-init-reviewed.d.ts +2 -0
  91. package/dist/services/workflow-layout-init-reviewed.d.ts.map +1 -1
  92. package/dist/services/workflow-layout-init-reviewed.js +30 -2
  93. package/dist/services/workflow-layout-init-reviewed.js.map +1 -1
  94. package/dist/services/workflow-layout-structure.d.ts +3 -0
  95. package/dist/services/workflow-layout-structure.d.ts.map +1 -0
  96. package/dist/services/workflow-layout-structure.js +44 -0
  97. package/dist/services/workflow-layout-structure.js.map +1 -0
  98. package/package.json +1 -1
  99. package/skill-docs/SKILL.md +4 -4
  100. package/skill-docs/_catalog.md +1 -1
  101. package/skill-docs/actionflows/SKILL.md +1 -0
  102. package/skill-docs/actionflows/references/components/ebuilder/EnquiryForm.md +2 -2
  103. package/skill-docs/actionflows/references/components/trigger/CustomTrigger.md +2 -0
  104. package/skill-docs/actionflows/references/components/trigger/WebHookTrigger.md +19 -1
  105. package/skill-docs/references/coding/guide-form-crud.md +2 -0
  106. package/skill-docs/references/coding/guide-page-code.md +13 -0
  107. package/skill-docs/references/common/capability-boundaries.md +6 -4
  108. package/skill-docs/references/common/ref-cli-commands.md +4 -3
  109. package/skill-docs/references/form/guide-field-linkage.md +9 -1
  110. package/skill-docs/references/form/guide-form-attachment-setting.md +31 -12
  111. package/skill-docs/references/form/guide-form-layout-planning.md +1 -1
  112. package/skill-docs/references/form/layout/code-block/code-block-guide.md +5 -5
  113. package/skill-docs/references/form/layout/code-block/layout-css.md +95 -15
  114. package/skill-docs/references/form/layout/template/advanced.md +2 -0
  115. package/skill-docs/references/form/layout/workflow-layout.md +10 -0
  116. package/skill-docs/references/menu/system-menus.md +21 -0
  117. package/skill-docs/references/code-block/guide-code-block.md +0 -141
  118. package/skill-docs/references/code-block/guide-layout-css.md +0 -107
  119. package/skill-docs/references/code-block/ref-controls.md +0 -60
  120. package/skill-docs/references/code-block/ref-coverage.md +0 -32
  121. package/skill-docs/references/code-block/ref-details.md +0 -57
  122. package/skill-docs/references/code-block/ref-events-validation.md +0 -42
  123. package/skill-docs/references/code-block/ref-foundations-fields.md +0 -56
  124. package/skill-docs/references/code-block/ref-recipes.md +0 -164
  125. package/skill-docs/references/code-block/ref-troubleshooting.md +0 -49
  126. package/skill-docs/references/code-block/ref-ui-global.md +0 -47
  127. package/skill-docs/references/form/form-template/style-templates-advanced-css-guide.md +0 -167
  128. package/skill-docs/references/form/form-template/style-templates-advanced.md +0 -315
  129. package/skill-docs/references/form/form-template/style-templates-easy.md +0 -55
  130. package/skill-docs/references/form/form-template/style-templates-flow.md +0 -27
  131. package/skill-docs/references/form/form-template/style-templates.md +0 -29
@@ -8,6 +8,9 @@ import { getRichType, resolveBrowserConfig, richIdUnits, BROWSER_TYPE_CATALOG }
8
8
  import { dropFieldComponents, prepareLayoutForSave } from '../services/form-field-drop.js';
9
9
  import { resolveBrowserByName } from '../services/browser.js';
10
10
  import { randomUUID } from 'node:crypto';
11
+ import { resolveStyleTemplateId } from '../services/form-style-template.js';
12
+ import { readTemplateEvidence, verifyAppliedTemplate } from '../services/form-layout-template-verification.js';
13
+ import { workflowExcelStructureIssues } from '../services/workflow-layout-structure.js';
11
14
  import { readFileSync } from 'node:fs';
12
15
  import { buildConditionDetail, resolveWorkflowEffect, readLinkageConfig } from '../services/form-linkage-condition.js';
13
16
  import { resolveSourceForm } from '../services/action-detail.js';
@@ -72,8 +75,34 @@ async function getLayoutMeta(client, baseUrl, formId, layoutMultiId) {
72
75
  return {
73
76
  layoutId: fl.id || '', layoutMultiId: flm.id || '', layoutName: flm.name || '',
74
77
  layoutType: flm.layoutType || 'FLOW', terminalType: flm.terminalType || 'PC',
78
+ formLayout: fl,
75
79
  };
76
80
  }
81
+ /** A rebuilding command must never silently replace a non-default template. */
82
+ async function templateForWorkflowRebuild(client, baseUrl, formId, meta, requested) {
83
+ if (requested)
84
+ return (await resolveStyleTemplateId(client, baseUrl, formId, meta.layoutType, requested)).id;
85
+ const defaultId = meta.layoutType === 'FLOW' ? '820000000000000001' : '700000000000000008';
86
+ if (!(meta.formLayout.pageLayouts || []).some((page) => page.comps?.length) || !meta.formLayout.formStyle?.styleConfig)
87
+ return defaultId;
88
+ const defaultStyle = await readTemplateEvidence(client, baseUrl, meta.layoutType, defaultId);
89
+ if (verifyAppliedTemplate(defaultStyle, meta.formLayout).length) {
90
+ throw new Error('当前布局不是系统默认模板效果;重建会覆盖现有样式。请显式传 --style-template <当前模板ID>,或使用布局局部编辑能力');
91
+ }
92
+ return defaultId;
93
+ }
94
+ async function verifyWorkflowRebuild(client, baseUrl, formId, templateId) {
95
+ const after = await getLayoutMeta(client, baseUrl, formId);
96
+ const issues = workflowExcelStructureIssues(after.formLayout);
97
+ const compCount = after.formLayout.pageLayouts?.[0]?.comps?.length || 0;
98
+ if (!compCount)
99
+ issues.push('回读布局没有组件');
100
+ const evidence = await readTemplateEvidence(client, baseUrl, after.layoutType, templateId);
101
+ issues.push(...verifyAppliedTemplate(evidence, after.formLayout));
102
+ if (issues.length)
103
+ throw new Error(`平台已接受布局,但独立回读校验失败:${issues.join(';')}`);
104
+ return compCount;
105
+ }
77
106
  async function readConfigs(client, baseUrl, formId) {
78
107
  const meta = await getLayoutMeta(client, baseUrl, formId);
79
108
  const cfg = await client.post(`${baseUrl}${ROUTE}/view/relate/getConfig`, {
@@ -188,6 +217,11 @@ function applyLoneSingleRows(configs) {
188
217
  const det = details.map((d) => ({ ...d, singleRow: true }));
189
218
  return [...others, ...biz, ...det];
190
219
  }
220
+ /** initLayout generates group containers from groupFieldIds; never submit existing Fold containers as input. */
221
+ function withoutCollapseContainers(configs) {
222
+ return configs.flatMap((c) => c.type === 'Collapse' || c.componentKey === 'Fold'
223
+ ? withoutCollapseContainers(c.children || []) : [c]);
224
+ }
191
225
  // 读表单现有字段分组 → refFieldIds(initLayout/getConfig 的 groupFieldIds)。
192
226
  // getFieldGroupPage 返回全部主表字段,字段 formField.group 带 groupId+groupName;
193
227
  // refFieldId = groupId - 1(平台先分配 layout config 再分配 formFieldGroup,顺序相连)。
@@ -205,7 +239,7 @@ async function fetchFormGroupEntries(client, baseUrl, formId) {
205
239
  for (const f of list) {
206
240
  const g = f?.formField?.group;
207
241
  if (g?.id)
208
- out.push(g);
242
+ out.push({ ...g, __fieldId: f?.formField?.id || f?.formField?.fieldId || f?.fieldId });
209
243
  }
210
244
  if (list.length < PAGE)
211
245
  break;
@@ -230,6 +264,9 @@ export async function initWorkflowFormLayout(client, baseUrl, formId, o = {}, ho
230
264
  throw new Error('无法获取 layoutId');
231
265
  // 保留字段分组:getConfig/initLayout 带 groupFieldIds,否则 Collapse 折叠被冲掉
232
266
  const groupIds = await fetchFormGroups(client, baseUrl, formId);
267
+ if (meta.layoutType === 'EXCEL' && o.generateCollapse === false && groupIds.length) {
268
+ throw new Error('表单已有字段分组;关闭 generateCollapse 会丢失分组子网格,已中止');
269
+ }
233
270
  // ⚠️ configs **一律从默认布局取**,哪怕这次要写的是另一套布局。
234
271
  // 实测:拿目标布局自己的 runtime id 去 getConfig 也能回一份 configs(字段数看着一样),
235
272
  // 但拿它 initLayout **写不进目标布局** —— 接口回 200、回读 `comps: 0`,静默失败。
@@ -271,7 +308,7 @@ export async function initWorkflowFormLayout(client, baseUrl, formId, o = {}, ho
271
308
  if (hooks.preLayout)
272
309
  hooks.preLayout(configs);
273
310
  // 落单/孤字段占满行(对齐 eb 表):奇数个最后一个 + 被 singleRow 挤落单的前一字段自动 singleRow
274
- const finalConfigs = applyLoneSingleRows(configs);
311
+ const finalConfigs = applyLoneSingleRows(meta.layoutType === 'EXCEL' ? withoutCollapseContainers(configs) : configs);
275
312
  const styleTemplateId = o.styleTemplate
276
313
  || (meta.layoutType === 'FLOW' ? '820000000000000001' : '700000000000000008');
277
314
  const initRes = await client.post(`${baseUrl}${ROUTE}/view/relate/initLayout`, {
@@ -287,6 +324,10 @@ export async function initWorkflowFormLayout(client, baseUrl, formId, o = {}, ho
287
324
  if (initRes?.code !== 200 || !initRes?.status)
288
325
  throw new Error(`initLayout 失败: ${initRes?.msg}`);
289
326
  const comps = initRes?.data?.pageLayouts?.[0]?.comps || initRes?.data?.formLayout?.pageLayouts?.[0]?.comps || [];
327
+ const returnedLayout = initRes?.data?.formLayout || { pageLayouts: initRes?.data?.pageLayouts };
328
+ const structureIssues = workflowExcelStructureIssues(returnedLayout);
329
+ if (structureIssues.length)
330
+ throw new Error(`平台已接受布局,但返回结构不完整:${structureIssues.join(';')}`);
290
331
  return { layoutType: meta.layoutType, styleTemplateId, comps: comps.length };
291
332
  }
292
333
  async function genIds(client, baseUrl, n) {
@@ -510,6 +551,7 @@ export function registerWorkflowFormCommands(program) {
510
551
  .option('--browser-form-source <src>', '--browser-type form 时的来源:business(默认) / ebuilder')
511
552
  .option('--browser-name <name>', '按名字指定浏览数据源(含自定义浏览框,如 "CLM-合同类型");优先于 --browser-type')
512
553
  .option('--no-init', '跳过末尾自动 layout init(默认加完自动重排布局,对齐 add-fields 批量)')
554
+ .option('--style-template <name|id>', '自动重排时应用的当前样式模板;已有自定义样式需指定')
513
555
  .action(async (formId, fieldName, fieldType, title, o) => {
514
556
  try {
515
557
  const opts = program.opts();
@@ -519,6 +561,9 @@ export function registerWorkflowFormCommands(program) {
519
561
  const client = new ApiClient(auth);
520
562
  const baseUrl = auth.getBaseUrl();
521
563
  const ebb = { ebbusinessid: formId };
564
+ const autoTemplate = o.init !== false
565
+ ? await templateForWorkflowRebuild(client, baseUrl, formId, await getLayoutMeta(client, baseUrl, formId), o.styleTemplate)
566
+ : undefined;
522
567
  const ck = canon(fieldType);
523
568
  const colName = toColumnName(fieldName);
524
569
  const [fieldId] = await genIds(client, baseUrl, 1);
@@ -634,7 +679,7 @@ export function registerWorkflowFormCommands(program) {
634
679
  // 走 initWorkflowFormLayout:强制业务字段可编辑(防 FLOW 锁死)+ 合并运行时 singleRow + applyLoneSingleRows(落单独占整行)。
635
680
  if (o.init !== false) {
636
681
  try {
637
- await initWorkflowFormLayout(client, baseUrl, formId, {}, o.singleRow ? {
682
+ await initWorkflowFormLayout(client, baseUrl, formId, { styleTemplate: autoTemplate }, o.singleRow ? {
638
683
  preLayout: (cfgs) => {
639
684
  // --single-row:field jsonObj 的 singleRow 平台不落到 layout comp(getConfig 不带),
640
685
  // 显式给新加字段 config.singleRow=true(递归找 fieldId,含明细 children)。
@@ -651,10 +696,12 @@ export function registerWorkflowFormCommands(program) {
651
696
  walkSet(cfgs);
652
697
  },
653
698
  } : undefined);
699
+ await verifyWorkflowRebuild(client, baseUrl, formId, autoTemplate);
654
700
  console.error(` 布局已 init`);
655
701
  }
656
702
  catch (e) {
657
- console.error(` 布局 init 失败: ${e?.message || e}(字段已加,手动跑 wf-form layout init)`);
703
+ console.error(` 布局 init 或回读失败: ${e?.message || e}(字段已加,布局未确认;请先检查当前布局)`);
704
+ process.exitCode = 1;
658
705
  }
659
706
  }
660
707
  // 开关:布局 init 可能把字段 options 冲回空,布局之后再补一次 开启=1 / 关闭=0。
@@ -1385,6 +1432,7 @@ export function registerWorkflowFormCommands(program) {
1385
1432
  .argument('<formId>', '流程表单 formId')
1386
1433
  .argument('<fieldsJson>', '字段定义 JSON / @文件路径')
1387
1434
  .option('--no-init', '跳过末尾自动 layout init(默认加完自动重排布局)')
1435
+ .option('--style-template <name|id>', '自动重排时应用的当前样式模板;已有自定义样式需指定')
1388
1436
  .action(async (formId, fieldsJson, cmdOpts) => {
1389
1437
  try {
1390
1438
  const opts = program.opts();
@@ -1410,6 +1458,9 @@ export function registerWorkflowFormCommands(program) {
1410
1458
  }
1411
1459
  if (!Array.isArray(defs) || !defs.length)
1412
1460
  throw new Error('fieldsJson 需为非空数组');
1461
+ const autoTemplate = cmdOpts.init !== false
1462
+ ? await templateForWorkflowRebuild(client, baseUrl, formId, await getLayoutMeta(client, baseUrl, formId), cmdOpts.styleTemplate)
1463
+ : undefined;
1413
1464
  const ids = await genIds(client, baseUrl, defs.length);
1414
1465
  let added = 0;
1415
1466
  for (let i = 0; i < defs.length; i++) {
@@ -1434,12 +1485,13 @@ export function registerWorkflowFormCommands(program) {
1434
1485
  let compCount = 0;
1435
1486
  if (cmdOpts.init !== false && added > 0) {
1436
1487
  try {
1437
- const r = await initWorkflowFormLayout(client, baseUrl, formId);
1438
- compCount = r.comps;
1488
+ const r = await initWorkflowFormLayout(client, baseUrl, formId, { styleTemplate: autoTemplate });
1489
+ compCount = await verifyWorkflowRebuild(client, baseUrl, formId, autoTemplate);
1439
1490
  console.error(` 布局已 init: 组件 ${compCount} 个`);
1440
1491
  }
1441
1492
  catch (e) {
1442
- console.error(` 布局 init 失败: ${e?.message || e}(字段已加,手动跑 wf-form layout init)`);
1493
+ console.error(` 布局 init 或回读失败: ${e?.message || e}(字段已加,布局未确认;请先检查当前布局)`);
1494
+ process.exitCode = 1;
1443
1495
  }
1444
1496
  }
1445
1497
  console.log(opts.json
@@ -1539,8 +1591,14 @@ export function registerWorkflowFormCommands(program) {
1539
1591
  // 读全字段
1540
1592
  const fData = await client.post(`${baseUrl}${ROUTE}/field/manage/getFormField`, { module: MODULE, formTableField: { formField: { id: fieldId, form: { id: formId } } } }, ebb);
1541
1593
  const jsonObj = fData?.data || {};
1542
- if (!jsonObj.fieldId)
1543
- throw new Error(`getFormField 未读到字段 fieldId=${fieldId}`);
1594
+ if (!jsonObj.fieldId) {
1595
+ const { configs } = await readConfigs(client, baseUrl, formId);
1596
+ const detail = configs.find((c) => String(c.id) === fieldId &&
1597
+ (c.componentKey === 'DataTable' || c.type === 'DetailTable'));
1598
+ throw new Error(detail
1599
+ ? `ID ${fieldId} 是明细表容器,不是普通字段;edit-field 不能修改其标题,当前 CLI 尚无已验证的明细表标题修改命令`
1600
+ : `getFormField 未读到普通字段 fieldId=${fieldId}`);
1601
+ }
1544
1602
  const changes = [];
1545
1603
  if (o.title !== undefined) {
1546
1604
  jsonObj.title = o.title;
@@ -1827,6 +1885,7 @@ export function registerWorkflowFormCommands(program) {
1827
1885
  .argument('[firstFieldName]', '首字段名(强烈建议传;空子表 getConfig 读不到)')
1828
1886
  .option('--data-key <k>', '子表物理表名/dataKey(默认 uf_拼音_随机)')
1829
1887
  .option('--init', '创建后跑 layout init 放入 DetailTable 组件')
1888
+ .option('--style-template <name|id>', '配合 --init 时应用的当前样式模板;已有自定义样式需指定')
1830
1889
  .option('--first-field-type <t>', '首字段类型(默认 Text)')
1831
1890
  .option('--first-field-data-key <k>', '首字段编码 dataKey(缺省取首字段名拼音首字母,与 add-field 一致)')
1832
1891
  .action(async (formId, name, firstFieldName, o) => {
@@ -1838,6 +1897,9 @@ export function registerWorkflowFormCommands(program) {
1838
1897
  const client = new ApiClient(auth);
1839
1898
  const baseUrl = auth.getBaseUrl();
1840
1899
  const ebb = { ebbusinessid: formId };
1900
+ const autoTemplate = o.init
1901
+ ? await templateForWorkflowRebuild(client, baseUrl, formId, await getLayoutMeta(client, baseUrl, formId), o.styleTemplate)
1902
+ : undefined;
1841
1903
  const [subFormId] = await genIds(client, baseUrl, 1);
1842
1904
  if (!subFormId)
1843
1905
  throw new Error('生成 subFormId 失败');
@@ -1874,7 +1936,7 @@ export function registerWorkflowFormCommands(program) {
1874
1936
  // 走 initWorkflowFormLayout:强制业务字段可编辑 + applyLoneSingleRows(落单独占整行)+ 保留分组;
1875
1937
  // DetailTable 由 normalizeDetailTableChildren 保留在 configs,applyLoneSingleRows 对明细恒 singleRow。
1876
1938
  try {
1877
- const r = await initWorkflowFormLayout(client, baseUrl, formId);
1939
+ const r = await initWorkflowFormLayout(client, baseUrl, formId, { styleTemplate: autoTemplate });
1878
1940
  compCount = r.comps;
1879
1941
  console.error(` 布局已 init: 组件 ${compCount} 个(含 DetailTable)`);
1880
1942
  }
@@ -1901,13 +1963,12 @@ export function registerWorkflowFormCommands(program) {
1901
1963
  // 流程表单字段分组(基本信息/系统设置等折叠容器)。三步接口(module=workflow,实测可用):
1902
1964
  // ① saveFieldGroup 建分组 → data.group.id(formFieldGroup记录id) + refFieldId(layout Collapse id)
1903
1965
  // ② updateFormFieldGroup 分配字段(fieldList)
1904
- // ③ initLayout 布局:configs 包 Collapse{id:refFieldId, componentKey:"Fold", type:"Collapse",
1905
- // dataKey:"f_"+refFieldId, children:[分组字段]} + 顶层 groupFieldIds:[refFieldId]
1906
- // (对齐 eb 表 form-create.ts FLOW 分组结构 / 记忆 field-group-saveFieldGroup-api)
1966
+ // ③ initLayout 平铺 configs + groupFieldIds,平台生成 Collapse 与子网格
1907
1967
  wfForm.command('group')
1908
1968
  .description('创建字段分组、分配字段并设置布局折叠')
1909
1969
  .argument('<formId>', '流程表单 formId')
1910
1970
  .requiredOption('--groups <json>', '分组定义 JSON:{"分组名":["字段名或ID",...]},可 @文件路径')
1971
+ .option('--style-template <name|id>', '重建时明确应用的当前样式模板;已有自定义样式必须指定')
1911
1972
  .action(async (formId, o) => {
1912
1973
  try {
1913
1974
  const opts = program.opts();
@@ -1935,6 +1996,8 @@ export function registerWorkflowFormCommands(program) {
1935
1996
  const entries = Object.entries(groups || {});
1936
1997
  if (entries.length === 0)
1937
1998
  throw new Error('--groups 为空');
1999
+ const initialMeta = await getLayoutMeta(client, baseUrl, formId);
2000
+ const styleTemplateId = await templateForWorkflowRebuild(client, baseUrl, formId, initialMeta, o.styleTemplate);
1938
2001
  // 名字 → 字段列表,无字段的分组也允许(空分组占位,后续 assign)
1939
2002
  // 解析字段(主表字段名→fieldId;含明细字段名但分组只建议主表)
1940
2003
  const { configs } = await readConfigs(client, baseUrl, formId);
@@ -2009,29 +2072,37 @@ export function registerWorkflowFormCommands(program) {
2009
2072
  }, ebb);
2010
2073
  if (cfgRes?.code !== 200 || !cfgRes?.status)
2011
2074
  throw new Error(`getConfig 失败: ${cfgRes?.msg}`);
2012
- const allConfigs = JSON.parse(JSON.stringify(cfgRes?.data?.configs || []));
2075
+ const rawConfigs = JSON.parse(JSON.stringify(cfgRes?.data?.configs || []));
2076
+ const allConfigs = meta.layoutType === 'EXCEL' ? withoutCollapseContainers(rawConfigs) : rawConfigs;
2013
2077
  // 合并运行时已保存的 singleRow(getConfig 不带,防 initLayout 冲掉独占一行)
2014
2078
  const allSrSet = await fetchRuntimeSingleRows(client, baseUrl, formId);
2015
2079
  mergeRuntimeSingleRow(allConfigs, allSrSet);
2016
- // 找出被分组的主表字段 config(顶层非系统非明细),从平铺抽出包 Collapse
2017
- const groupFieldIdSet = new Set(created.flatMap((g) => g.fieldIds));
2018
- const collapsedFields = allConfigs.filter((c) => !c.system && c.type !== 'DetailTable' && c.componentKey !== 'DataTable' && groupFieldIdSet.has(String(c.id)));
2019
- const rest = allConfigs.filter((c) => collapsedFields.indexOf(c) === -1);
2020
- const groupFieldIds = [];
2021
- const collapses = [];
2022
- for (const grp of created) {
2023
- const children = collapsedFields.filter((c) => grp.fieldIds.includes(String(c.id)));
2024
- groupFieldIds.push(grp.refFieldId);
2025
- collapses.push({
2026
- id: grp.refFieldId, name: grp.name, componentKey: 'Fold', display: true, show: true,
2080
+ const groupFieldIds = await fetchFormGroups(client, baseUrl, formId);
2081
+ // EXCEL 由平台生成容器与子网格;FLOW 需要显式 Fold 输入。
2082
+ let finalConfigs;
2083
+ if (meta.layoutType === 'EXCEL') {
2084
+ finalConfigs = applyLoneSingleRows(allConfigs);
2085
+ }
2086
+ else {
2087
+ const assigned = await fetchFormGroupEntries(client, baseUrl, formId);
2088
+ const byGroup = new Map();
2089
+ for (const row of assigned) {
2090
+ const id = String(row.id);
2091
+ const group = byGroup.get(id) || { name: String(row.groupName || ''), fieldIds: new Set() };
2092
+ if (row.__fieldId)
2093
+ group.fieldIds.add(String(row.__fieldId));
2094
+ byGroup.set(id, group);
2095
+ }
2096
+ const groupedIds = new Set([...byGroup.values()].flatMap(g => [...g.fieldIds]));
2097
+ const rest = allConfigs.filter((c) => !groupedIds.has(String(c.id)));
2098
+ const folds = [...byGroup].map(([groupId, grp]) => ({
2099
+ id: String(BigInt(groupId) - 1n), name: grp.name, componentKey: 'Fold', display: true, show: true,
2027
2100
  readOnly: true, required: false, disableEdit: false, singleRow: false, isDelete: false,
2028
- type: 'Collapse', typeDescribe: '分组', dataKey: `f_${grp.refFieldId}`,
2029
- children,
2030
- });
2101
+ type: 'Collapse', typeDescribe: '分组', dataKey: `f_${String(BigInt(groupId) - 1n)}`,
2102
+ children: allConfigs.filter((c) => grp.fieldIds.has(String(c.id))),
2103
+ }));
2104
+ finalConfigs = applyLoneSingleRows([...folds, ...rest]);
2031
2105
  }
2032
- // 落单/孤字段占满行(含分组内字段 singleRow 由平台 Collapse 自行排布,只对未分组字段算)
2033
- const finalConfigs = applyLoneSingleRows([...collapses, ...rest]);
2034
- const styleTemplateId = meta.layoutType === 'FLOW' ? '820000000000000001' : '700000000000000008';
2035
2106
  const initRes = await client.post(`${baseUrl}${ROUTE}/view/relate/initLayout`, {
2036
2107
  formId, module: MODULE, apiModule: 'workflow/form', layoutId: meta.layoutId,
2037
2108
  generateCollapse: true, styleTemplateId, styleTemplateType: 1,
@@ -2043,10 +2114,10 @@ export function registerWorkflowFormCommands(program) {
2043
2114
  }, ebb);
2044
2115
  if (initRes?.code !== 200 || !initRes?.status)
2045
2116
  throw new Error(`initLayout 失败: ${initRes?.msg}`);
2046
- const comps = initRes?.data?.pageLayouts?.[0]?.comps || initRes?.data?.formLayout?.pageLayouts?.[0]?.comps || [];
2117
+ const compCount = await verifyWorkflowRebuild(client, baseUrl, formId, styleTemplateId);
2047
2118
  console.log(opts.json
2048
- ? JSON.stringify({ success: true, formId, groups: created.map((g) => ({ name: g.name, groupId: g.groupId, refFieldId: g.refFieldId, fieldCount: g.fieldIds.length })), comps: comps.length }, null, 2)
2049
- : `字段分组完成: ${created.length} 个分组,布局 ${comps.length} 组件`);
2119
+ ? JSON.stringify({ success: true, formId, groups: created.map((g) => ({ name: g.name, groupId: g.groupId, refFieldId: g.refFieldId, fieldCount: g.fieldIds.length })), comps: compCount }, null, 2)
2120
+ : `字段分组完成: ${created.length} 个分组,布局 ${compCount} 组件`);
2050
2121
  }
2051
2122
  catch (e) {
2052
2123
  console.error(`字段分组失败: ${e.message}`);
@@ -2288,6 +2359,7 @@ export function registerWorkflowFormCommands(program) {
2288
2359
  .option('--readonly <fields...>', '设为只读(readOnly=true, disableEdit=true)')
2289
2360
  .option('--editable <fields...>', '设为可编辑(readOnly=false, disableEdit=false)')
2290
2361
  .option('--single-row <fields...>', '独占一行(singleRow=true)')
2362
+ .option('--style-template <name|id>', '重建时明确应用的当前样式模板;已有自定义样式必须指定')
2291
2363
  .action(async (formId, o) => {
2292
2364
  try {
2293
2365
  const opts = program.opts();
@@ -2300,6 +2372,7 @@ export function registerWorkflowFormCommands(program) {
2300
2372
  const meta = await getLayoutMeta(client, baseUrl, formId);
2301
2373
  if (!meta.layoutId)
2302
2374
  throw new Error('无法获取 layoutId');
2375
+ const styleTemplateId = await templateForWorkflowRebuild(client, baseUrl, formId, meta, o.styleTemplate);
2303
2376
  // 保留字段分组:getConfig/initLayout 带 groupFieldIds,否则 Collapse 折叠被冲掉
2304
2377
  const groupIds = await fetchFormGroups(client, baseUrl, formId);
2305
2378
  // 读当前布局 configs(含明细 children + Collapse 分组)
@@ -2349,8 +2422,7 @@ export function registerWorkflowFormCommands(program) {
2349
2422
  apply(o.editable, (c) => { c.readOnly = false; c.disableEdit = false; }, '可编辑');
2350
2423
  apply(o.singleRow, (c) => { c.singleRow = true; }, '独占一行');
2351
2424
  // 落单/孤字段占满行(对齐 eb 表):奇数个最后一个 + 被 singleRow 挤落单的前一字段自动 singleRow
2352
- const finalConfigs = applyLoneSingleRows(configs);
2353
- const styleTemplateId = meta.layoutType === 'FLOW' ? '820000000000000001' : '700000000000000008';
2425
+ const finalConfigs = applyLoneSingleRows(meta.layoutType === 'EXCEL' ? withoutCollapseContainers(configs) : configs);
2354
2426
  const initRes = await client.post(`${baseUrl}${ROUTE}/view/relate/initLayout`, {
2355
2427
  formId, module: MODULE, apiModule: 'workflow/form', layoutId: meta.layoutId,
2356
2428
  generateCollapse: true, styleTemplateId, styleTemplateType: 1,
@@ -2362,10 +2434,10 @@ export function registerWorkflowFormCommands(program) {
2362
2434
  }, ebb);
2363
2435
  if (initRes?.code !== 200 || !initRes?.status)
2364
2436
  throw new Error(`initLayout 失败: ${initRes?.msg}`);
2365
- const comps = initRes?.data?.pageLayouts?.[0]?.comps || initRes?.data?.formLayout?.pageLayouts?.[0]?.comps || [];
2437
+ const compCount = await verifyWorkflowRebuild(client, baseUrl, formId, styleTemplateId);
2366
2438
  console.log(opts.json
2367
- ? JSON.stringify({ success: true, formId, layoutType: meta.layoutType, comps: comps.length }, null, 2)
2368
- : `字段属性已保存: 布局 ${comps.length} 组件`);
2439
+ ? JSON.stringify({ success: true, formId, layoutType: meta.layoutType, comps: compCount }, null, 2)
2440
+ : `字段属性已保存: 布局 ${compCount} 组件`);
2369
2441
  }
2370
2442
  catch (e) {
2371
2443
  console.error(`设置字段属性失败: ${e.message}`);