weaver-e10-builder 1.5.10 → 1.5.11

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 (211) hide show
  1. package/dist/commands/app.d.ts.map +1 -1
  2. package/dist/commands/app.js +159 -8
  3. package/dist/commands/app.js.map +1 -1
  4. package/dist/commands/designer-setters.d.ts.map +1 -1
  5. package/dist/commands/designer-setters.js +26 -4
  6. package/dist/commands/designer-setters.js.map +1 -1
  7. package/dist/commands/form-association-manage.d.ts.map +1 -1
  8. package/dist/commands/form-association-manage.js +3 -0
  9. package/dist/commands/form-association-manage.js.map +1 -1
  10. package/dist/commands/form-button-actions-cmd.d.ts +3 -0
  11. package/dist/commands/form-button-actions-cmd.d.ts.map +1 -0
  12. package/dist/commands/form-button-actions-cmd.js +309 -0
  13. package/dist/commands/form-button-actions-cmd.js.map +1 -0
  14. package/dist/commands/form-button-permission-cmd.d.ts +3 -0
  15. package/dist/commands/form-button-permission-cmd.d.ts.map +1 -0
  16. package/dist/commands/form-button-permission-cmd.js +132 -0
  17. package/dist/commands/form-button-permission-cmd.js.map +1 -0
  18. package/dist/commands/form-button-props-cmd.d.ts +3 -0
  19. package/dist/commands/form-button-props-cmd.d.ts.map +1 -0
  20. package/dist/commands/form-button-props-cmd.js +236 -0
  21. package/dist/commands/form-button-props-cmd.js.map +1 -0
  22. package/dist/commands/form-button.d.ts.map +1 -1
  23. package/dist/commands/form-button.js +82 -55
  24. package/dist/commands/form-button.js.map +1 -1
  25. package/dist/commands/form-formula-linkage.d.ts.map +1 -1
  26. package/dist/commands/form-formula-linkage.js +154 -63
  27. package/dist/commands/form-formula-linkage.js.map +1 -1
  28. package/dist/commands/form-list-permission.d.ts.map +1 -1
  29. package/dist/commands/form-list-permission.js +29 -3
  30. package/dist/commands/form-list-permission.js.map +1 -1
  31. package/dist/commands/form-list-search-group.d.ts.map +1 -1
  32. package/dist/commands/form-list-search-group.js +66 -3
  33. package/dist/commands/form-list-search-group.js.map +1 -1
  34. package/dist/commands/form-list-utils.d.ts +14 -0
  35. package/dist/commands/form-list-utils.d.ts.map +1 -1
  36. package/dist/commands/form-list-utils.js +65 -4
  37. package/dist/commands/form-list-utils.js.map +1 -1
  38. package/dist/commands/form-message.d.ts.map +1 -1
  39. package/dist/commands/form-message.js +16 -4
  40. package/dist/commands/form-message.js.map +1 -1
  41. package/dist/commands/form-permission.d.ts +20 -0
  42. package/dist/commands/form-permission.d.ts.map +1 -1
  43. package/dist/commands/form-permission.js +69 -11
  44. package/dist/commands/form-permission.js.map +1 -1
  45. package/dist/commands/menu-permission.d.ts.map +1 -1
  46. package/dist/commands/menu-permission.js +6 -7
  47. package/dist/commands/menu-permission.js.map +1 -1
  48. package/dist/commands/menu.d.ts.map +1 -1
  49. package/dist/commands/menu.js +63 -40
  50. package/dist/commands/menu.js.map +1 -1
  51. package/dist/commands/wf-form.d.ts.map +1 -1
  52. package/dist/commands/wf-form.js +56 -36
  53. package/dist/commands/wf-form.js.map +1 -1
  54. package/dist/commands/workflow-function-management.d.ts +5 -0
  55. package/dist/commands/workflow-function-management.d.ts.map +1 -0
  56. package/dist/commands/workflow-function-management.js +91 -0
  57. package/dist/commands/workflow-function-management.js.map +1 -0
  58. package/dist/commands/workflow-node-assign-flow.d.ts.map +1 -1
  59. package/dist/commands/workflow-node-assign-flow.js +1 -0
  60. package/dist/commands/workflow-node-assign-flow.js.map +1 -1
  61. package/dist/commands/workflow-node-sign.d.ts +0 -12
  62. package/dist/commands/workflow-node-sign.d.ts.map +1 -1
  63. package/dist/commands/workflow-node-sign.js +31 -102
  64. package/dist/commands/workflow-node-sign.js.map +1 -1
  65. package/dist/commands/workflow-opinion-settings.d.ts +5 -0
  66. package/dist/commands/workflow-opinion-settings.d.ts.map +1 -0
  67. package/dist/commands/workflow-opinion-settings.js +51 -0
  68. package/dist/commands/workflow-opinion-settings.js.map +1 -0
  69. package/dist/commands/workflow-subprocess.d.ts.map +1 -1
  70. package/dist/commands/workflow-subprocess.js +370 -20
  71. package/dist/commands/workflow-subprocess.js.map +1 -1
  72. package/dist/commands/workflow.d.ts.map +1 -1
  73. package/dist/commands/workflow.js +35 -61
  74. package/dist/commands/workflow.js.map +1 -1
  75. package/dist/index.js +4 -0
  76. package/dist/index.js.map +1 -1
  77. package/dist/services/actionflow/calendar_mapper.d.ts.map +1 -1
  78. package/dist/services/actionflow/calendar_mapper.js +30 -4
  79. package/dist/services/actionflow/calendar_mapper.js.map +1 -1
  80. package/dist/services/actionflow/component_registry.d.ts.map +1 -1
  81. package/dist/services/actionflow/component_registry.js +6 -0
  82. package/dist/services/actionflow/component_registry.js.map +1 -1
  83. package/dist/services/actionflow/components/meeting_create.d.ts.map +1 -1
  84. package/dist/services/actionflow/components/meeting_create.js +5 -1
  85. package/dist/services/actionflow/components/meeting_create.js.map +1 -1
  86. package/dist/services/actionflow/components/workflow_actions.d.ts.map +1 -1
  87. package/dist/services/actionflow/components/workflow_actions.js +15 -3
  88. package/dist/services/actionflow/components/workflow_actions.js.map +1 -1
  89. package/dist/services/actionflow/formula_service.d.ts +7 -0
  90. package/dist/services/actionflow/formula_service.d.ts.map +1 -1
  91. package/dist/services/actionflow/formula_service.js +25 -0
  92. package/dist/services/actionflow/formula_service.js.map +1 -1
  93. package/dist/services/app-publish.d.ts +25 -0
  94. package/dist/services/app-publish.d.ts.map +1 -1
  95. package/dist/services/app-publish.js +38 -0
  96. package/dist/services/app-publish.js.map +1 -1
  97. package/dist/services/app-range.d.ts +66 -0
  98. package/dist/services/app-range.d.ts.map +1 -0
  99. package/dist/services/app-range.js +137 -0
  100. package/dist/services/app-range.js.map +1 -0
  101. package/dist/services/form-association.d.ts +13 -0
  102. package/dist/services/form-association.d.ts.map +1 -1
  103. package/dist/services/form-association.js +42 -0
  104. package/dist/services/form-association.js.map +1 -1
  105. package/dist/services/form-button-action.d.ts +82 -0
  106. package/dist/services/form-button-action.d.ts.map +1 -1
  107. package/dist/services/form-button-action.js +194 -2
  108. package/dist/services/form-button-action.js.map +1 -1
  109. package/dist/services/form-button-condition.d.ts +45 -0
  110. package/dist/services/form-button-condition.d.ts.map +1 -0
  111. package/dist/services/form-button-condition.js +106 -0
  112. package/dist/services/form-button-condition.js.map +1 -0
  113. package/dist/services/form-button-context.d.ts +41 -0
  114. package/dist/services/form-button-context.d.ts.map +1 -0
  115. package/dist/services/form-button-context.js +54 -0
  116. package/dist/services/form-button-context.js.map +1 -0
  117. package/dist/services/form-button-logicflow.d.ts +30 -0
  118. package/dist/services/form-button-logicflow.d.ts.map +1 -0
  119. package/dist/services/form-button-logicflow.js +59 -0
  120. package/dist/services/form-button-logicflow.js.map +1 -0
  121. package/dist/services/form-button-org.d.ts +30 -0
  122. package/dist/services/form-button-org.d.ts.map +1 -0
  123. package/dist/services/form-button-org.js +80 -0
  124. package/dist/services/form-button-org.js.map +1 -0
  125. package/dist/services/form-button-permission.d.ts +65 -0
  126. package/dist/services/form-button-permission.d.ts.map +1 -0
  127. package/dist/services/form-button-permission.js +113 -0
  128. package/dist/services/form-button-permission.js.map +1 -0
  129. package/dist/services/form-button-position.d.ts +4 -18
  130. package/dist/services/form-button-position.d.ts.map +1 -1
  131. package/dist/services/form-button-position.js +4 -36
  132. package/dist/services/form-button-position.js.map +1 -1
  133. package/dist/services/form-button-props.d.ts +55 -0
  134. package/dist/services/form-button-props.d.ts.map +1 -0
  135. package/dist/services/form-button-props.js +90 -0
  136. package/dist/services/form-button-props.js.map +1 -0
  137. package/dist/services/form-button-save.d.ts +49 -0
  138. package/dist/services/form-button-save.d.ts.map +1 -0
  139. package/dist/services/form-button-save.js +54 -0
  140. package/dist/services/form-button-save.js.map +1 -0
  141. package/dist/services/form-formula-linkage.d.ts +116 -20
  142. package/dist/services/form-formula-linkage.d.ts.map +1 -1
  143. package/dist/services/form-formula-linkage.js +250 -38
  144. package/dist/services/form-formula-linkage.js.map +1 -1
  145. package/dist/services/form-list-search-group.d.ts +17 -2
  146. package/dist/services/form-list-search-group.d.ts.map +1 -1
  147. package/dist/services/form-list-search-group.js +29 -12
  148. package/dist/services/form-list-search-group.js.map +1 -1
  149. package/dist/services/form-list-search.d.ts.map +1 -1
  150. package/dist/services/form-list-search.js +4 -0
  151. package/dist/services/form-list-search.js.map +1 -1
  152. package/dist/services/form-list-stats.d.ts.map +1 -1
  153. package/dist/services/form-list-stats.js +9 -2
  154. package/dist/services/form-list-stats.js.map +1 -1
  155. package/dist/services/form-message.d.ts +26 -7
  156. package/dist/services/form-message.d.ts.map +1 -1
  157. package/dist/services/form-message.js +52 -5
  158. package/dist/services/form-message.js.map +1 -1
  159. package/dist/services/form-permission-archive.d.ts +9 -1
  160. package/dist/services/form-permission-archive.d.ts.map +1 -1
  161. package/dist/services/form-permission-archive.js +38 -22
  162. package/dist/services/form-permission-archive.js.map +1 -1
  163. package/dist/services/form-view-populate.d.ts.map +1 -1
  164. package/dist/services/form-view-populate.js +7 -0
  165. package/dist/services/form-view-populate.js.map +1 -1
  166. package/dist/services/icon-path.d.ts +70 -0
  167. package/dist/services/icon-path.d.ts.map +1 -0
  168. package/dist/services/icon-path.js +80 -0
  169. package/dist/services/icon-path.js.map +1 -0
  170. package/dist/services/matrix-condition.d.ts +161 -0
  171. package/dist/services/matrix-condition.d.ts.map +1 -0
  172. package/dist/services/matrix-condition.js +403 -0
  173. package/dist/services/matrix-condition.js.map +1 -0
  174. package/dist/services/menu-catalog.d.ts +33 -0
  175. package/dist/services/menu-catalog.d.ts.map +1 -1
  176. package/dist/services/menu-catalog.js +56 -0
  177. package/dist/services/menu-catalog.js.map +1 -1
  178. package/dist/services/permission-entity.d.ts +55 -0
  179. package/dist/services/permission-entity.d.ts.map +1 -0
  180. package/dist/services/permission-entity.js +79 -0
  181. package/dist/services/permission-entity.js.map +1 -0
  182. package/dist/services/workflow-assign-flow.d.ts.map +1 -1
  183. package/dist/services/workflow-assign-flow.js.map +1 -1
  184. package/dist/services/workflow-function-management.d.ts +123 -0
  185. package/dist/services/workflow-function-management.d.ts.map +1 -0
  186. package/dist/services/workflow-function-management.js +425 -0
  187. package/dist/services/workflow-function-management.js.map +1 -0
  188. package/dist/services/workflow-matrix-rule.d.ts +34 -0
  189. package/dist/services/workflow-matrix-rule.d.ts.map +1 -0
  190. package/dist/services/workflow-matrix-rule.js +94 -0
  191. package/dist/services/workflow-matrix-rule.js.map +1 -0
  192. package/dist/services/workflow-opinion-settings.d.ts +67 -0
  193. package/dist/services/workflow-opinion-settings.d.ts.map +1 -0
  194. package/dist/services/workflow-opinion-settings.js +328 -0
  195. package/dist/services/workflow-opinion-settings.js.map +1 -0
  196. package/package.json +1 -1
  197. package/skill-docs/SKILL.md +5 -5
  198. package/skill-docs/_catalog.md +3 -0
  199. package/skill-docs/actionflows/references/components/calendar/MeetingCreate.md +2 -0
  200. package/skill-docs/actionflows/references/components/workflow/ApproveDelete.md +1 -1
  201. package/skill-docs/references/common/ref-cli-commands.md +60 -22
  202. package/skill-docs/references/ebuilder-designer/guide-designer-components.md +9 -0
  203. package/skill-docs/references/form/guide-form-archive-permission.md +55 -2
  204. package/skill-docs/references/form/guide-form-association.md +13 -0
  205. package/skill-docs/references/form/guide-form-button.md +87 -0
  206. package/skill-docs/references/form/guide-form-message.md +19 -2
  207. package/skill-docs/references/form/guide-form-view.md +23 -3
  208. package/skill-docs/references/form/guide-formula-linkage.md +42 -11
  209. package/skill-docs/references/workflow/guide-function-management.md +154 -0
  210. package/skill-docs/references/workflow/guide-opinion-settings.md +126 -0
  211. package/skill-docs/references/workflow/guide-workflow.md +22 -6
@@ -26,24 +26,27 @@ import { buildConditionChildrens, saveWorkflowCondition } from '../services/cond
26
26
  */
27
27
  const BASE = '/api/bs/workflow/pathdef/subWf';
28
28
  const COND_BASE = '/api/workflow/pathdef/rule/condition';
29
- const TRI_TIME_LABELS = { LEAVE_NODE: '离开节点', ENTER_NODE: '进入节点' };
29
+ const TRI_TIME_LABELS = { LEAVE_NODE: '离开节点', ARRIVE_NODE: '到达节点' };
30
30
  const TRI_TYPE_LABELS = { AUTO: '自动触发', MANUAL: '手动触发' };
31
- const TRI_SOURCE_TYPE_LABELS = { MAIN: '主表', SUB: '明细' };
31
+ const TRI_SOURCE_TYPE_LABELS = { MAIN: '主表', DETAIL: '明细表' };
32
32
  const CREATOR_TYPE_LABELS = {
33
33
  MAIN_REQ_CREATOR: '主流程发起人',
34
34
  MAIN_NODE_OPERATOR: '主流程当前节点操作人',
35
35
  FIELD: '指定字段值',
36
36
  };
37
37
  /** 读节点全部子流程配置(getSetList.data.data) */
38
- async function fetchSetList(client, baseUrl, workflowId, nodeId) {
39
- const res = await client.get(`${baseUrl}${BASE}/getSetList?workflowId=${workflowId}&nodeId=${nodeId}`);
38
+ async function fetchSetList(client, baseUrl, workflowId, nodeId = '') {
39
+ const qs = new URLSearchParams({ workflowId });
40
+ if (nodeId)
41
+ qs.set('nodeId', nodeId);
42
+ const res = await client.get(`${baseUrl}${BASE}/getSetList?${qs}`);
40
43
  if (res?.code !== 200 || !res?.status)
41
44
  throw new Error(`读取子流程配置失败: ${res?.msg || '未知错误'}`);
42
45
  return res?.data?.data || [];
43
46
  }
44
47
  /** getSetList 记录里仅属于响应的字段(回写 saveSet 时剔除,避免后端误解析) */
45
48
  const RESP_ONLY_KEYS = new Set([
46
- 'detailSet', 'triNodeName', 'triTimeName', 'triTypeName', 'subWfName',
49
+ 'detailSet', 'triNodeName', 'triTimeName', 'triTypeName', 'triOperationName', 'subWfName',
47
50
  'creator', 'createTime', 'updateTime',
48
51
  ]);
49
52
  /** 新建 saveSet 的默认字段(对齐抓包 template) */
@@ -90,6 +93,67 @@ async function borrowTenantKey(client, baseUrl, workflowId, nodeId) {
90
93
  return '';
91
94
  }
92
95
  }
96
+ /** 不同子流程的详情接口返回浏览器对象;保存表格时应还原为 ID 字符串。 */
97
+ function browserIds(value) {
98
+ if (Array.isArray(value))
99
+ return value.map((v) => String(v?.id ?? v?.dataId ?? v ?? '')).filter(Boolean).join(',');
100
+ return value == null ? '' : String(value);
101
+ }
102
+ function normalizeDiffRoute(row) {
103
+ return { ...row, id: String(row.id || ''), diffFieldValue: browserIds(row.diffFieldValue), subWfId: browserIds(row.subWfId), isAdd: false };
104
+ }
105
+ function parseDiffValues(raw) {
106
+ const values = raw.split(',').map((v) => v.trim());
107
+ if (!values.length || values.some((v) => !/^\d+$/.test(v)) || new Set(values).size !== values.length) {
108
+ throw new Error('匹配值须为不重复的浏览器选项 ID,多个用逗号分隔');
109
+ }
110
+ return values.join(',');
111
+ }
112
+ async function fetchDiffConfig(client, baseUrl, workflowId, subSetId, detailSetId, subWfId = '') {
113
+ const qs = new URLSearchParams({ setId: subSetId, detailSetId, workflowId, subWfId });
114
+ const res = await client.get(`${baseUrl}${BASE}/getDetailSetInfo?${qs}`);
115
+ if (res?.code !== 200 || !res?.status)
116
+ throw new Error(`读取不同子流程设置失败: ${res?.msg || '未知错误'}`);
117
+ const body = res?.data?.data;
118
+ if (!body || typeof body !== 'object')
119
+ throw new Error('不同子流程详情缺少默认设置');
120
+ const rawRoutes = res?.data?.diffSubWfData?.data;
121
+ if (!Array.isArray(rawRoutes))
122
+ throw new Error('不同子流程详情缺少路由表,停止写入以免覆盖已有路由');
123
+ return {
124
+ defaultSet: body, routes: rawRoutes.map(normalizeDiffRoute),
125
+ sourceFieldId: String(res?.data?.ebuilderFieldProps?.config?.fieldId || ''),
126
+ };
127
+ }
128
+ async function fetchDiffRecord(client, baseUrl, workflowId, nodeId, subSetId) {
129
+ const list = await fetchSetList(client, baseUrl, workflowId, nodeId);
130
+ const rec = list.find((s) => String(s.id) === subSetId);
131
+ if (!rec)
132
+ throw new Error(`未找到子流程配置 ${subSetId}`);
133
+ if (!rec.diffWf)
134
+ throw new Error(`配置 ${subSetId} 未开启“触发不同子流程”`);
135
+ return rec;
136
+ }
137
+ async function saveDiffTable(client, baseUrl, workflowId, subSetId, defaultSet, routes, endpoint) {
138
+ const body = {
139
+ stopCreateNode: false, autoShow: 0, createForAnyone: false, delOldSubRequest: 1,
140
+ readMainNodeType: 'ALL', readSubNodeType: 'ALL', readParalleNodeType: 'ALL',
141
+ readMainCommentParam: [], readSubCommentParam: [], readParalleCommentParam: [],
142
+ initDefaultVal: false, splitField: false, splitUnit: false, dataSrc: 0,
143
+ deleteType: 0, readMain: false, readParalle: false, readSub: false,
144
+ readMainComment: false, readParalleComment: false, readSubComment: false,
145
+ createNodeCanDel: false,
146
+ ...defaultSet, workflowId, subSetId, moduleType: 'workflow', diffWf: true,
147
+ diffFieldValue: '-1', subWfId: browserIds(defaultSet.subWfId),
148
+ readMainNodes: browserIds(defaultSet.readMainNodes),
149
+ readSubNodes: browserIds(defaultSet.readSubNodes),
150
+ readParalleNodes: browserIds(defaultSet.readParalleNodes),
151
+ diffSubWfTableDatas: routes.map((row) => ({ ...normalizeDiffRoute(row), isAdd: Boolean(row.isAdd) })),
152
+ };
153
+ const res = await client.post(`${baseUrl}${BASE}/${endpoint}`, body);
154
+ if (res?.code !== 200 || !res?.status)
155
+ throw new Error(`保存不同子流程路由失败: ${res?.msg || '未知错误'}`);
156
+ }
93
157
  export function registerWorkflowSubProcessCommands(wf, program) {
94
158
  const subWf = wf.command('sub-process').description('子流程配置(在节点上调用另一流程:读 / 建 / 条件 / 映射 / 明细 / 删)');
95
159
  // ─── LIST ───────────────────────────────────────────
@@ -160,6 +224,9 @@ export function registerWorkflowSubProcessCommands(wf, program) {
160
224
  console.log(`子流程配置 [${rec.id}] ${rec.triName}`);
161
225
  console.log(` 子流程: ${rec.subWfName || rec.subWfId} (${rec.subWfId}) ${rec.enable ? '✅启用' : '⛔停用'}`);
162
226
  console.log(` 触发: ${TRI_TYPE_LABELS[rec.triType] || rec.triType} ${TRI_TIME_LABELS[rec.triTime] || rec.triTime} 源=${TRI_SOURCE_TYPE_LABELS[rec.triSourceType] || rec.triSourceType}(${rec.triSource}) 模式=${rec.triMode}`);
227
+ if (rec.triOperation || rec.triOperation2) {
228
+ console.log(` 节点操作: ${rec.triOperation || '(无)'} / ${rec.triOperation2 || '(无)'}`);
229
+ }
163
230
  console.log(` 延时: ${rec.timeDay || 0}天${rec.timeHour || 0}时${rec.timeMinute || 0}分 once=${rec.triOnce} splitDetail=${rec.splitDetail} groupSplit=${rec.groupSplit} diffWf=${rec.diffWf}`);
164
231
  console.log(` 触发条件: ${ruleId ? `ruleId=${ruleId}` : '(无)'}${rec.ruleName ? ` ${rec.ruleName}` : ''}`);
165
232
  if (condRecords.length) {
@@ -168,10 +235,12 @@ export function registerWorkflowSubProcessCommands(wf, program) {
168
235
  }
169
236
  const ds = rec.detailSet;
170
237
  if (ds) {
238
+ const detailRes = await client.get(`${baseUrl}${BASE}/getDetailSetInfo?${new URLSearchParams({ setId: subSetId, detailSetId: String(ds.id), workflowId, subWfId: String(rec.subWfId || '') })}`);
239
+ const detail = detailRes?.code === 200 && detailRes?.status ? detailRes?.data?.data || ds : ds;
171
240
  console.log(` 明细设置 (id=${ds.id}):`);
172
- console.log(` 创建人: ${CREATOR_TYPE_LABELS[ds.creatorType] || ds.creatorType}${ds.creatorValue ? ` (${ds.creatorValue})` : ''}`);
173
- console.log(` 读意见: 主=${ds.readMain} 并行=${ds.readParalle} 子=${ds.readSub} 读意见正文: 主=${ds.readMainComment} 并行=${ds.readParalleComment} 子=${ds.readSubComment}`);
174
- console.log(` delOldSubRequest=${ds.delOldSubRequest} autoShow=${ds.autoShow} initDefaultVal=${ds.initDefaultVal} dataRuleId=${ds.dataRuleId || '(无映射)'}`);
241
+ console.log(` 创建人: ${CREATOR_TYPE_LABELS[detail.creatorType] || detail.creatorType}${detail.creatorValue ? ` (${detail.creatorValue})` : ''}`);
242
+ console.log(` 读意见: 主=${detail.readMain} 并行=${detail.readParalle} 子=${detail.readSub} 读意见正文: 主=${detail.readMainComment} 并行=${detail.readParalleComment} 子=${detail.readSubComment}`);
243
+ console.log(` delOldSubRequest=${detail.delOldSubRequest} autoShow=${detail.autoShow} initDefaultVal=${detail.initDefaultVal} dataRuleId=${detail.dataRuleId || '(无映射)'}`);
175
244
  }
176
245
  }
177
246
  catch (e) {
@@ -184,20 +253,24 @@ export function registerWorkflowSubProcessCommands(wf, program) {
184
253
  .description('新建/更新子流程主配置(saveSet;新建无 --id,更新带 --id 读-改-写)')
185
254
  .argument('<workflowId>', '主流程 ID')
186
255
  .argument('<nodeId>', '节点 ID')
187
- .requiredOption('--sub-wf <id>', '子流程 ID(系统里已存在的普通流程)')
256
+ .option('--sub-wf <id>', '子流程 ID(普通模式必填;不同子流程模式在路由中指定)')
188
257
  .requiredOption('--name <n>', '配置名(triName)')
189
258
  .option('--id <subSetId>', '主配置 ID(更新时传;不传=新建)')
190
- .option('--tri-time <v>', '触发时间点: LEAVE_NODE(离开节点,默认;其它取值未验证)')
259
+ .option('--tri-time <v>', '触发时机: LEAVE_NODE(离开节点,默认) / ARRIVE_NODE(到达节点)')
260
+ .option('--tri-moment <v>', '触发时间: NOW(立即,默认) / DELAY(固定延迟)')
191
261
  .option('--tri-type <v>', '触发类型: AUTO(自动,默认;MANUAL 未验证)')
192
262
  .option('--tri-mode <v>', '触发模式 (默认 ALL;其它取值未验证)')
193
- .option('--tri-source-type <v>', '触发源类型: MAIN(主表,默认;SUB 未验证)')
194
- .option('--tri-source <objId>', '触发源(主表 objId)')
263
+ .option('--tri-source-type <v>', '触发源类型: MAIN(主表,默认) / DETAIL(明细表)')
264
+ .option('--tri-source <id>', '触发源:MAIN 传主表 objId;DETAIL 传明细表 subFormId')
265
+ .option('--tri-operation <v>', '上一节点操作: LAST_NODE_APPRIVE(批准) / LAST_NODE_REJECT(退回)')
266
+ .option('--tri-operation2 <v>', '操作结果: APPRIVE(批准) / REJECT(退回)')
195
267
  .option('--enable', '启用(默认停用)')
196
268
  .option('--disable', '停用')
197
269
  .option('--tri-once', '只触发一次')
198
- .option('--split-detail <v>', '拆分明细 (默认 TRI_DATA)')
270
+ .option('--split-detail <v>', '触发明细赋值: TRI_DATA(触发数据,默认) / ALL_DATA(全部数据)')
199
271
  .option('--group-split', '分组拆分')
200
272
  .option('--diff-wf', '不同流程')
273
+ .option('--diff-field-id <fieldId>', '触发不同子流程的可区分字段 ID(--diff-wf 时必填)')
201
274
  .option('--time-day <n>', '延时天')
202
275
  .option('--time-hour <n>', '延时时')
203
276
  .option('--time-minute <n>', '延时分')
@@ -209,10 +282,42 @@ export function registerWorkflowSubProcessCommands(wf, program) {
209
282
  throw new Error('无法加载认证');
210
283
  const client = new ApiClient(auth);
211
284
  const baseUrl = auth.getBaseUrl();
285
+ if (o.triSourceType && !['MAIN', 'DETAIL'].includes(o.triSourceType)) {
286
+ throw new Error('--tri-source-type 只支持 MAIN 或 DETAIL;明细表触发请使用 DETAIL');
287
+ }
288
+ if (o.enable && o.disable)
289
+ throw new Error('--enable 和 --disable 不能同时使用');
290
+ if (o.triOperation && !['LAST_NODE_APPRIVE', 'LAST_NODE_REJECT'].includes(o.triOperation)) {
291
+ throw new Error('--tri-operation 只支持 LAST_NODE_APPRIVE 或 LAST_NODE_REJECT');
292
+ }
293
+ if (o.triOperation2 && !['APPRIVE', 'REJECT'].includes(o.triOperation2)) {
294
+ throw new Error('--tri-operation2 只支持 APPRIVE 或 REJECT');
295
+ }
296
+ if (Boolean(o.triOperation) !== Boolean(o.triOperation2)) {
297
+ throw new Error('--tri-operation 与 --tri-operation2 应同时设置');
298
+ }
299
+ if (o.triOperation && ((o.triOperation === 'LAST_NODE_APPRIVE' && o.triOperation2 !== 'APPRIVE') ||
300
+ (o.triOperation === 'LAST_NODE_REJECT' && o.triOperation2 !== 'REJECT'))) {
301
+ throw new Error('节点触发操作取值不匹配:批准对应 APPRIVE,退回对应 REJECT');
302
+ }
303
+ if (o.splitDetail && !['TRI_DATA', 'ALL_DATA'].includes(o.splitDetail)) {
304
+ throw new Error('--split-detail 只支持 TRI_DATA 或 ALL_DATA');
305
+ }
306
+ if (o.triTime && !['LEAVE_NODE', 'ARRIVE_NODE'].includes(o.triTime)) {
307
+ throw new Error('--tri-time 只支持 LEAVE_NODE 或 ARRIVE_NODE');
308
+ }
309
+ if (o.triMoment && !['NOW', 'DELAY'].includes(o.triMoment)) {
310
+ throw new Error('--tri-moment 只支持 NOW 或 DELAY');
311
+ }
312
+ for (const [label, raw] of [['--time-day', o.timeDay], ['--time-hour', o.timeHour], ['--time-minute', o.timeMinute]]) {
313
+ if (raw != null && (!/^\d+$/.test(raw) || !Number.isSafeInteger(Number(raw)))) {
314
+ throw new Error(`${label} 必须是非负整数`);
315
+ }
316
+ }
212
317
  let body;
213
318
  if (o.id) {
214
319
  // 更新:读-改-写(保留原字段,剔除响应专用字段)
215
- const list = await fetchSetList(client, baseUrl, workflowId, nodeId);
320
+ const list = await fetchSetList(client, baseUrl, workflowId);
216
321
  const rec = list.find((s) => String(s.id) === String(o.id));
217
322
  if (!rec)
218
323
  throw new Error(`未找到子流程配置 ${o.id}`);
@@ -220,6 +325,12 @@ export function registerWorkflowSubProcessCommands(wf, program) {
220
325
  for (const k of Object.keys(body))
221
326
  if (RESP_ONLY_KEYS.has(k))
222
327
  delete body[k];
328
+ if (rec.diffWf && !o.diffFieldId) {
329
+ const info = await fetchDiffConfig(client, baseUrl, workflowId, String(rec.id), String(rec.detailSet?.id || ''), String(rec.subWfId || ''));
330
+ if (!info.sourceFieldId)
331
+ throw new Error('无法从详情接口还原可区分字段 ID,请显式传 --diff-field-id');
332
+ body.diffFieldId = info.sourceFieldId;
333
+ }
223
334
  }
224
335
  else {
225
336
  // 新建:默认 template + 借用 tenantKey(无则省略)
@@ -232,10 +343,13 @@ export function registerWorkflowSubProcessCommands(wf, program) {
232
343
  body.workflowId = workflowId;
233
344
  body.triNodeId = nodeId;
234
345
  body.multiTriNodeId = nodeId;
235
- body.subWfId = o.subWf;
346
+ if (o.subWf)
347
+ body.subWfId = o.subWf;
236
348
  body.triName = o.name;
237
349
  if (o.triTime)
238
350
  body.triTime = o.triTime;
351
+ if (o.triMoment)
352
+ body.triMoment = o.triMoment;
239
353
  if (o.triType)
240
354
  body.triType = o.triType;
241
355
  if (o.triMode)
@@ -244,6 +358,17 @@ export function registerWorkflowSubProcessCommands(wf, program) {
244
358
  body.triSourceType = o.triSourceType;
245
359
  if (o.triSource)
246
360
  body.triSource = o.triSource;
361
+ if (o.triOperation)
362
+ body.triOperation = o.triOperation;
363
+ if (o.triOperation2)
364
+ body.triOperation2 = o.triOperation2;
365
+ if (body.triSourceType === 'DETAIL' && !body.triSource) {
366
+ throw new Error('明细表触发需要 --tri-source <明细表 subFormId>');
367
+ }
368
+ if (body.triSourceType === 'DETAIL') {
369
+ body.triOperation ??= 'LAST_NODE_APPRIVE';
370
+ body.triOperation2 ??= 'APPRIVE';
371
+ }
247
372
  if (o.enable)
248
373
  body.enable = true;
249
374
  if (o.disable)
@@ -256,25 +381,216 @@ export function registerWorkflowSubProcessCommands(wf, program) {
256
381
  body.groupSplit = true;
257
382
  if (o.diffWf)
258
383
  body.diffWf = true;
384
+ if (o.diffFieldId)
385
+ body.diffFieldId = o.diffFieldId;
386
+ if (body.diffWf) {
387
+ if (!body.diffFieldId || !body.triSource)
388
+ throw new Error('触发不同子流程需要 --diff-field-id <字段ID> 和 --tri-source <表单/明细表ID>');
389
+ // 设计器同时提交以来源表 ID 为键的区分字段,保持与 saveSet 报文一致。
390
+ if (!o.id)
391
+ body[String(body.triSource)] = body.diffFieldId;
392
+ }
393
+ else if (!body.subWfId) {
394
+ throw new Error('普通子流程触发需要 --sub-wf <子流程ID>');
395
+ }
259
396
  if (o.timeDay != null)
260
397
  body.timeDay = Number(o.timeDay);
261
398
  if (o.timeHour != null)
262
399
  body.timeHour = Number(o.timeHour);
263
400
  if (o.timeMinute != null)
264
401
  body.timeMinute = Number(o.timeMinute);
402
+ if (!o.triMoment && (o.timeDay != null || o.timeHour != null || o.timeMinute != null)) {
403
+ body.triMoment = 'DELAY';
404
+ body.triTimeType = 'FINALVAL';
405
+ }
406
+ if (body.triMoment === 'DELAY' && !Number(body.timeDay || 0) && !Number(body.timeHour || 0) && !Number(body.timeMinute || 0)) {
407
+ throw new Error('固定延迟触发需要 --time-day、--time-hour 或 --time-minute 指定非零时长');
408
+ }
265
409
  const res = await client.post(`${baseUrl}${BASE}/saveSet`, body);
266
410
  if (res?.code !== 200 || !res?.status)
267
411
  throw new Error(`保存失败: ${res?.msg}`);
268
412
  const id = res?.data?.id || o.id || '';
413
+ if (!id)
414
+ throw new Error('保存接口未返回子流程配置 ID,无法回读校验');
415
+ const savedList = await fetchSetList(client, baseUrl, workflowId);
416
+ const saved = savedList.find((s) => String(s.id) === String(id));
417
+ if (!saved)
418
+ throw new Error(`保存后未能读回子流程配置 ${id}`);
419
+ if (String(saved.triNodeId || '') !== nodeId || String(saved.multiTriNodeId || '') !== nodeId) {
420
+ throw new Error(`触发节点未完整生效:期望 ${nodeId},读回 triNodeId=${saved.triNodeId || ''}、multiTriNodeId=${saved.multiTriNodeId || ''}`);
421
+ }
422
+ if (saved.triSourceType !== body.triSourceType ||
423
+ ((o.triSource || body.triSourceType === 'DETAIL') && String(saved.triSource || '') !== String(body.triSource || ''))) {
424
+ throw new Error(`触发来源未生效:请求 ${body.triSourceType}(${body.triSource || ''}),读回 ${saved.triSourceType}(${saved.triSource || ''})`);
425
+ }
426
+ if (body.triSourceType === 'DETAIL' && (saved.triOperation !== body.triOperation || saved.triOperation2 !== body.triOperation2)) {
427
+ throw new Error(`节点触发操作未生效:请求 ${body.triOperation}/${body.triOperation2},读回 ${saved.triOperation || ''}/${saved.triOperation2 || ''}`);
428
+ }
429
+ if (saved.triMoment !== body.triMoment || saved.splitDetail !== body.splitDetail) {
430
+ throw new Error('触发时间或明细赋值未按请求保存,请用 sub-process get 核对');
431
+ }
432
+ if (body.diffWf && (!saved.diffWf || !saved.diffFieldId)) {
433
+ throw new Error('“触发不同子流程”或区分字段未在保存后读回');
434
+ }
435
+ if (o.enable || o.disable) {
436
+ const enabled = Boolean(o.enable);
437
+ const statusRes = await client.post(`${baseUrl}${BASE}/updateStatus?id=${encodeURIComponent(String(id))}&enable=${enabled}&workflowId=${encodeURIComponent(workflowId)}`, {});
438
+ if (statusRes?.code !== 200 || !statusRes?.status)
439
+ throw new Error(`更新启停状态失败: ${statusRes?.msg}`);
440
+ const statusList = await fetchSetList(client, baseUrl, workflowId);
441
+ const status = statusList.find((s) => String(s.id) === String(id));
442
+ if (!status || Boolean(status.enable) !== enabled)
443
+ throw new Error(`启停状态未生效:期望 ${enabled ? '启用' : '停用'}`);
444
+ }
269
445
  console.log(opts.json
270
- ? JSON.stringify({ success: true, id, workflowId, nodeId, subWfId: o.subWf, name: o.name }, null, 2)
271
- : `子流程主配置已${o.id ? '更新' : '新建'}: id=${id} ${o.name} → ${o.subWf}`);
446
+ ? JSON.stringify({ success: true, id, workflowId, nodeId, subWfId: saved.subWfId, diffWf: saved.diffWf, name: o.name }, null, 2)
447
+ : `子流程主配置已${o.id ? '更新' : '新建'}: id=${id} ${o.name} → ${saved.diffWf ? '按字段路由' : saved.subWfId}`);
272
448
  }
273
449
  catch (e) {
274
450
  console.error(`保存子流程主配置失败: ${e.message}`);
275
451
  process.exitCode = 1;
276
452
  }
277
453
  });
454
+ // ─── DIFF-ROUTE(按区分字段触发不同子流程)────────────
455
+ const diffRoute = subWf.command('diff-route').description('按字段触发不同子流程:路由列表、新增、修改、删除及默认子流程');
456
+ async function diffContext(workflowId, nodeId, subSetId) {
457
+ const auth = await AuthSession.fromOptions(program.opts());
458
+ if (!auth)
459
+ throw new Error('无法加载认证');
460
+ const client = new ApiClient(auth);
461
+ const baseUrl = auth.getBaseUrl();
462
+ const rec = await fetchDiffRecord(client, baseUrl, workflowId, nodeId, subSetId);
463
+ const config = await fetchDiffConfig(client, baseUrl, workflowId, subSetId, String(rec.detailSet?.id || ''), String(rec.subWfId || ''));
464
+ return { client, baseUrl, rec, ...config };
465
+ }
466
+ diffRoute.command('list')
467
+ .description('查看默认子流程和字段值路由(同时输出路由 ID)')
468
+ .argument('<workflowId>').argument('<nodeId>').argument('<subSetId>')
469
+ .action(async (workflowId, nodeId, subSetId) => {
470
+ try {
471
+ const { rec, defaultSet, routes, sourceFieldId } = await diffContext(workflowId, nodeId, subSetId);
472
+ const result = { subSetId, diffFieldId: sourceFieldId || rec.diffFieldId, defaultSubWfId: browserIds(defaultSet.subWfId), routes: routes.map((r) => ({ id: r.id, values: r.diffFieldValue, subWfId: r.subWfId })) };
473
+ if (program.opts().json)
474
+ console.log(JSON.stringify(result, null, 2));
475
+ else {
476
+ console.log(`区分字段: ${result.diffFieldId} 默认子流程: ${result.defaultSubWfId || '(未设置)'}`);
477
+ for (const r of result.routes)
478
+ console.log(` [${r.id}] ${r.values} → ${r.subWfId}`);
479
+ }
480
+ }
481
+ catch (e) {
482
+ console.error(`读取不同子流程路由失败: ${e.message}`);
483
+ process.exitCode = 1;
484
+ }
485
+ });
486
+ diffRoute.command('default')
487
+ .description('设置未命中字段值时使用的默认子流程')
488
+ .argument('<workflowId>').argument('<nodeId>').argument('<subSetId>')
489
+ .requiredOption('--sub-wf <id>', '默认子流程 ID')
490
+ .action(async (workflowId, nodeId, subSetId, o) => {
491
+ try {
492
+ const { client, baseUrl, defaultSet, routes, rec } = await diffContext(workflowId, nodeId, subSetId);
493
+ if (!routes.length)
494
+ throw new Error('请先用 diff-route add --default-sub-wf 同时建立首条路由和默认子流程');
495
+ await saveDiffTable(client, baseUrl, workflowId, subSetId, { ...defaultSet, subWfId: o.subWf, id: defaultSet.id || rec.detailSet?.id }, routes, 'saveDefaultSubWfSet');
496
+ const updatedRec = await fetchDiffRecord(client, baseUrl, workflowId, nodeId, subSetId);
497
+ const fresh = await fetchDiffConfig(client, baseUrl, workflowId, subSetId, String(updatedRec.detailSet?.id || ''), o.subWf);
498
+ if (browserIds(fresh.defaultSet.subWfId) !== o.subWf)
499
+ throw new Error('默认子流程保存后读回不一致');
500
+ console.log(`默认子流程已设置: ${o.subWf}`);
501
+ }
502
+ catch (e) {
503
+ console.error(`设置默认子流程失败: ${e.message}`);
504
+ process.exitCode = 1;
505
+ }
506
+ });
507
+ diffRoute.command('add')
508
+ .description('新增一条字段值到子流程的路由;--values 传平台选项 ID')
509
+ .argument('<workflowId>').argument('<nodeId>').argument('<subSetId>')
510
+ .requiredOption('--values <ids>', '一个或多个匹配值 ID,逗号分隔')
511
+ .requiredOption('--sub-wf <id>', '目标子流程 ID')
512
+ .option('--default-sub-wf <id>', '首次建路由时同时指定默认子流程 ID')
513
+ .action(async (workflowId, nodeId, subSetId, o) => {
514
+ try {
515
+ const values = parseDiffValues(o.values);
516
+ const { client, baseUrl, defaultSet, routes, rec } = await diffContext(workflowId, nodeId, subSetId);
517
+ if (!browserIds(defaultSet.subWfId) && !o.defaultSubWf)
518
+ throw new Error('首条路由需要 --default-sub-wf <默认子流程ID>');
519
+ const used = new Set(routes.flatMap((r) => r.diffFieldValue.split(',')));
520
+ if (values.split(',').some((v) => used.has(v)))
521
+ throw new Error('匹配值已在其它路由中使用');
522
+ const idRes = await client.get(`${baseUrl}${BASE}/getDiffSubWfTableId`);
523
+ const routeId = String(idRes?.data || '');
524
+ if (idRes?.code !== 200 || !idRes?.status || !/^\d+$/.test(routeId))
525
+ throw new Error('无法取得新路由 ID');
526
+ await saveDiffTable(client, baseUrl, workflowId, subSetId, { ...defaultSet, subWfId: o.defaultSubWf || defaultSet.subWfId, id: defaultSet.id || rec.detailSet?.id }, [
527
+ ...routes, { id: routeId, diffFieldValue: values, subWfId: o.subWf, isAdd: true },
528
+ ], 'saveDefaultSubWfSet');
529
+ const updatedRec = await fetchDiffRecord(client, baseUrl, workflowId, nodeId, subSetId);
530
+ const fresh = await fetchDiffConfig(client, baseUrl, workflowId, subSetId, String(updatedRec.detailSet?.id || ''), String(updatedRec.subWfId || ''));
531
+ const saved = fresh.routes.find((r) => r.id === routeId);
532
+ if (!saved || saved.diffFieldValue !== values || saved.subWfId !== o.subWf)
533
+ throw new Error(`路由 ${routeId} 保存后读回不一致`);
534
+ if (o.defaultSubWf && browserIds(fresh.defaultSet.subWfId) !== o.defaultSubWf)
535
+ throw new Error('默认子流程保存后读回不一致');
536
+ console.log(`不同子流程路由已新增: [${routeId}] ${values} → ${o.subWf}`);
537
+ }
538
+ catch (e) {
539
+ console.error(`新增不同子流程路由失败: ${e.message}`);
540
+ process.exitCode = 1;
541
+ }
542
+ });
543
+ diffRoute.command('update')
544
+ .description('原位修改已有路由的匹配值或目标子流程,保留路由 ID')
545
+ .argument('<workflowId>').argument('<nodeId>').argument('<subSetId>').argument('<routeId>')
546
+ .option('--values <ids>', '新的匹配值 ID,逗号分隔')
547
+ .option('--sub-wf <id>', '新的目标子流程 ID')
548
+ .action(async (workflowId, nodeId, subSetId, routeId, o) => {
549
+ try {
550
+ if (!o.values && !o.subWf)
551
+ throw new Error('至少提供 --values 或 --sub-wf');
552
+ const { client, baseUrl, defaultSet, routes, rec } = await diffContext(workflowId, nodeId, subSetId);
553
+ const row = routes.find((r) => r.id === routeId);
554
+ if (!row)
555
+ throw new Error(`未找到路由 ${routeId}`);
556
+ const values = o.values ? parseDiffValues(o.values) : row.diffFieldValue;
557
+ const used = new Set(routes.filter((r) => r.id !== routeId).flatMap((r) => r.diffFieldValue.split(',')));
558
+ if (values.split(',').some((v) => used.has(v)))
559
+ throw new Error('匹配值已在其它路由中使用');
560
+ const subWfId = o.subWf || row.subWfId;
561
+ await saveDiffTable(client, baseUrl, workflowId, subSetId, { ...defaultSet, id: defaultSet.id || rec.detailSet?.id }, routes.map((r) => r.id === routeId ? { ...r, diffFieldValue: values, subWfId } : r), 'saveDetailSet');
562
+ const fresh = await fetchDiffConfig(client, baseUrl, workflowId, subSetId, String(rec.detailSet?.id || ''), String(rec.subWfId || ''));
563
+ const saved = fresh.routes.find((r) => r.id === routeId);
564
+ if (!saved || saved.diffFieldValue !== values || saved.subWfId !== subWfId)
565
+ throw new Error(`路由 ${routeId} 修改后读回不一致`);
566
+ console.log(`不同子流程路由已修改: [${routeId}] ${values} → ${subWfId}`);
567
+ }
568
+ catch (e) {
569
+ console.error(`修改不同子流程路由失败: ${e.message}`);
570
+ process.exitCode = 1;
571
+ }
572
+ });
573
+ diffRoute.command('delete')
574
+ .description('删除指定路由行(不删除子流程本身)')
575
+ .argument('<workflowId>').argument('<nodeId>').argument('<subSetId>').argument('<routeId>')
576
+ .action(async (workflowId, nodeId, subSetId, routeId) => {
577
+ try {
578
+ const { client, baseUrl, routes, rec } = await diffContext(workflowId, nodeId, subSetId);
579
+ if (!routes.some((r) => r.id === routeId))
580
+ throw new Error(`未找到路由 ${routeId}`);
581
+ const res = await client.post(`${baseUrl}${BASE}/deleteDiffSubWfSet`, { diffSubWfSetId: [routeId], workflowId });
582
+ if (res?.code !== 200 || !res?.status)
583
+ throw new Error(`删除路由失败: ${res?.msg || '未知错误'}`);
584
+ const fresh = await fetchDiffConfig(client, baseUrl, workflowId, subSetId, String(rec.detailSet?.id || ''), String(rec.subWfId || ''));
585
+ if (fresh.routes.some((r) => r.id === routeId))
586
+ throw new Error(`路由 ${routeId} 删除后仍可读到`);
587
+ console.log(`不同子流程路由已删除: ${routeId}`);
588
+ }
589
+ catch (e) {
590
+ console.error(`删除不同子流程路由失败: ${e.message}`);
591
+ process.exitCode = 1;
592
+ }
593
+ });
278
594
  // ─── SET-CONDITION(触发条件)────────────────────────
279
595
  subWf.command('set-condition')
280
596
  .description('设置子流程触发条件(复用 workflow 条件构建器,source=7)→ 回填 saveSet.ruleId')
@@ -359,7 +675,8 @@ export function registerWorkflowSubProcessCommands(wf, program) {
359
675
  .requiredOption('--sub-wf <id>', '子流程 ID')
360
676
  .requiredOption('--map <pairs...>', '映射 srcField:targetField[:name](可多个)')
361
677
  .option('--field-mapping-id <id>', '映射记录 ID(更新传;不传=新建)')
362
- .option('--tri-source <objId>', '主表 objId(写 dataSrc/triSource 联动用,可选)')
678
+ .option('--tri-source <objId>', '保留兼容参数:主表 objId')
679
+ .option('--detail-source <subFormId>', '明细逐行触发时的来源明细表 subFormId(写入映射上下文)')
363
680
  .action(async (workflowId, o) => {
364
681
  try {
365
682
  const opts = program.opts();
@@ -382,6 +699,10 @@ export function registerWorkflowSubProcessCommands(wf, program) {
382
699
  srcModuleType: 'WORKFLOW', otherParams: { showSysFieldDetailTableId: '' },
383
700
  targetWorkflowId: o.subWf, data, workflowId: o.subWf,
384
701
  };
702
+ if (o.detailSource) {
703
+ body.subRequestByDetailTrigger = o.detailSource;
704
+ body.otherParams.showSysFieldDetailTableId = o.detailSource;
705
+ }
385
706
  if (o.fieldMappingId)
386
707
  body.fieldMappingId = o.fieldMappingId;
387
708
  const res = await client.post(`${baseUrl}${BASE}/saveSubFieldMappingTable`, body);
@@ -427,10 +748,14 @@ export function registerWorkflowSubProcessCommands(wf, program) {
427
748
  const ds = rec.detailSet;
428
749
  if (!ds)
429
750
  throw new Error('该配置无内嵌 detailSet,无法更新');
751
+ // 不同子流程的默认路由使用独立详情接口,不能写普通 saveDetailSet。
752
+ const diffConfig = rec.diffWf
753
+ ? await fetchDiffConfig(client, baseUrl, workflowId, subSetId, String(ds.id), String(rec.subWfId || ''))
754
+ : null;
430
755
  const [ctype, cval] = o.creator.split(':');
431
756
  if (!ctype)
432
757
  throw new Error(`--creator 格式错误: ${o.creator}(应为 type:fieldId)`);
433
- const body = JSON.parse(JSON.stringify(ds));
758
+ const body = JSON.parse(JSON.stringify(diffConfig?.defaultSet || ds));
434
759
  // 联动:subSetId, subWfId, workflowId, moduleType 用主配置的值
435
760
  body.subSetId = String(rec.id);
436
761
  body.subWfId = rec.subWfId;
@@ -453,9 +778,34 @@ export function registerWorkflowSubProcessCommands(wf, program) {
453
778
  body.initDefaultVal = true;
454
779
  if (o.dataRuleId)
455
780
  body.dataRuleId = o.dataRuleId;
456
- const res = await client.post(`${baseUrl}${BASE}/saveDetailSet`, body);
781
+ if (rec.diffWf) {
782
+ body.diffWf = true;
783
+ body.diffFieldValue = '-1';
784
+ body.triSource = rec.triSource;
785
+ body.diffFieldId = diffConfig?.sourceFieldId || rec.diffFieldId;
786
+ }
787
+ const endpoint = rec.diffWf ? 'saveDiffSubWfDetailSet' : 'saveDetailSet';
788
+ // 设计器的不同子流程详情接口从 URL 查询参数取值;普通详情接口接收 JSON。
789
+ const saveUrl = rec.diffWf
790
+ ? `${baseUrl}${BASE}/${endpoint}?${new URLSearchParams(Object.entries(body).reduce((query, [key, value]) => {
791
+ if (value == null || typeof value === 'object')
792
+ return query;
793
+ query[key] = String(value);
794
+ return query;
795
+ }, {}))}`
796
+ : `${baseUrl}${BASE}/${endpoint}`;
797
+ const res = await client.post(saveUrl, rec.diffWf ? {} : body);
457
798
  if (res?.code !== 200 || !res?.status)
458
799
  throw new Error(`保存明细设置失败: ${res?.msg}`);
800
+ if (o.dataRuleId) {
801
+ const fresh = await client.get(`${baseUrl}${BASE}/getDetailSetInfo?${new URLSearchParams({ setId: subSetId, detailSetId: String(ds.id), workflowId, subWfId: String(rec.subWfId || '') })}`);
802
+ if (fresh?.code !== 200 || !fresh?.status)
803
+ throw new Error(`字段映射读回失败: ${fresh?.msg || '未知错误'}`);
804
+ const savedRuleId = String(fresh?.data?.data?.dataRuleId || '');
805
+ if (savedRuleId !== o.dataRuleId) {
806
+ throw new Error(`字段映射未生效:期望 dataRuleId=${o.dataRuleId},读回 ${savedRuleId || '(无)'}`);
807
+ }
808
+ }
459
809
  console.log(opts.json
460
810
  ? JSON.stringify({ success: true, subSetId, detailSetId: ds.id, creatorType: ctype, creatorValue: cval || '' }, null, 2)
461
811
  : `明细设置已保存: detailSetId=${ds.id} 创建人=${CREATOR_TYPE_LABELS[ctype] || ctype}${cval ? `(${cval})` : ''}`);