weaver-e10-builder 1.5.10 → 1.5.12

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 (352) hide show
  1. package/README.md +212 -189
  2. package/assets/image-style-observation.schema.json +1355 -0
  3. package/assets/layout-spec.schema.json +52 -0
  4. package/dist/commands/app.d.ts.map +1 -1
  5. package/dist/commands/app.js +159 -8
  6. package/dist/commands/app.js.map +1 -1
  7. package/dist/commands/designer-setters.d.ts.map +1 -1
  8. package/dist/commands/designer-setters.js +26 -4
  9. package/dist/commands/designer-setters.js.map +1 -1
  10. package/dist/commands/form-association-manage.d.ts.map +1 -1
  11. package/dist/commands/form-association-manage.js +3 -0
  12. package/dist/commands/form-association-manage.js.map +1 -1
  13. package/dist/commands/form-button-actions-cmd.d.ts +3 -0
  14. package/dist/commands/form-button-actions-cmd.d.ts.map +1 -0
  15. package/dist/commands/form-button-actions-cmd.js +309 -0
  16. package/dist/commands/form-button-actions-cmd.js.map +1 -0
  17. package/dist/commands/form-button-permission-cmd.d.ts +3 -0
  18. package/dist/commands/form-button-permission-cmd.d.ts.map +1 -0
  19. package/dist/commands/form-button-permission-cmd.js +132 -0
  20. package/dist/commands/form-button-permission-cmd.js.map +1 -0
  21. package/dist/commands/form-button-props-cmd.d.ts +3 -0
  22. package/dist/commands/form-button-props-cmd.d.ts.map +1 -0
  23. package/dist/commands/form-button-props-cmd.js +236 -0
  24. package/dist/commands/form-button-props-cmd.js.map +1 -0
  25. package/dist/commands/form-button.d.ts.map +1 -1
  26. package/dist/commands/form-button.js +82 -55
  27. package/dist/commands/form-button.js.map +1 -1
  28. package/dist/commands/form-field-linkage.d.ts +55 -0
  29. package/dist/commands/form-field-linkage.d.ts.map +1 -1
  30. package/dist/commands/form-field-linkage.js +1026 -12
  31. package/dist/commands/form-field-linkage.js.map +1 -1
  32. package/dist/commands/form-formula-linkage.d.ts +36 -0
  33. package/dist/commands/form-formula-linkage.d.ts.map +1 -1
  34. package/dist/commands/form-formula-linkage.js +256 -65
  35. package/dist/commands/form-formula-linkage.js.map +1 -1
  36. package/dist/commands/form-layout-restore.d.ts +3 -0
  37. package/dist/commands/form-layout-restore.d.ts.map +1 -0
  38. package/dist/commands/form-layout-restore.js +217 -0
  39. package/dist/commands/form-layout-restore.js.map +1 -0
  40. package/dist/commands/form-layout.d.ts.map +1 -1
  41. package/dist/commands/form-layout.js +11 -1
  42. package/dist/commands/form-layout.js.map +1 -1
  43. package/dist/commands/form-list-permission.d.ts.map +1 -1
  44. package/dist/commands/form-list-permission.js +29 -3
  45. package/dist/commands/form-list-permission.js.map +1 -1
  46. package/dist/commands/form-list-search-group.d.ts.map +1 -1
  47. package/dist/commands/form-list-search-group.js +66 -3
  48. package/dist/commands/form-list-search-group.js.map +1 -1
  49. package/dist/commands/form-list-utils.d.ts +14 -0
  50. package/dist/commands/form-list-utils.d.ts.map +1 -1
  51. package/dist/commands/form-list-utils.js +65 -4
  52. package/dist/commands/form-list-utils.js.map +1 -1
  53. package/dist/commands/form-message.d.ts.map +1 -1
  54. package/dist/commands/form-message.js +16 -4
  55. package/dist/commands/form-message.js.map +1 -1
  56. package/dist/commands/form-obj-meta.d.ts +12 -0
  57. package/dist/commands/form-obj-meta.d.ts.map +1 -0
  58. package/dist/commands/form-obj-meta.js +116 -0
  59. package/dist/commands/form-obj-meta.js.map +1 -0
  60. package/dist/commands/form-permission.d.ts +20 -0
  61. package/dist/commands/form-permission.d.ts.map +1 -1
  62. package/dist/commands/form-permission.js +69 -11
  63. package/dist/commands/form-permission.js.map +1 -1
  64. package/dist/commands/form-validate.d.ts.map +1 -1
  65. package/dist/commands/form-validate.js +167 -35
  66. package/dist/commands/form-validate.js.map +1 -1
  67. package/dist/commands/form.d.ts.map +1 -1
  68. package/dist/commands/form.js +26 -2
  69. package/dist/commands/form.js.map +1 -1
  70. package/dist/commands/menu-permission.d.ts.map +1 -1
  71. package/dist/commands/menu-permission.js +6 -7
  72. package/dist/commands/menu-permission.js.map +1 -1
  73. package/dist/commands/menu.d.ts.map +1 -1
  74. package/dist/commands/menu.js +68 -43
  75. package/dist/commands/menu.js.map +1 -1
  76. package/dist/commands/wf-form.d.ts.map +1 -1
  77. package/dist/commands/wf-form.js +269 -47
  78. package/dist/commands/wf-form.js.map +1 -1
  79. package/dist/commands/workflow-function-management.d.ts +5 -0
  80. package/dist/commands/workflow-function-management.d.ts.map +1 -0
  81. package/dist/commands/workflow-function-management.js +91 -0
  82. package/dist/commands/workflow-function-management.js.map +1 -0
  83. package/dist/commands/workflow-node-assign-flow.d.ts.map +1 -1
  84. package/dist/commands/workflow-node-assign-flow.js +1 -0
  85. package/dist/commands/workflow-node-assign-flow.js.map +1 -1
  86. package/dist/commands/workflow-node-sign.d.ts +0 -12
  87. package/dist/commands/workflow-node-sign.d.ts.map +1 -1
  88. package/dist/commands/workflow-node-sign.js +31 -102
  89. package/dist/commands/workflow-node-sign.js.map +1 -1
  90. package/dist/commands/workflow-opinion-settings.d.ts +5 -0
  91. package/dist/commands/workflow-opinion-settings.d.ts.map +1 -0
  92. package/dist/commands/workflow-opinion-settings.js +51 -0
  93. package/dist/commands/workflow-opinion-settings.js.map +1 -0
  94. package/dist/commands/workflow-subprocess.d.ts.map +1 -1
  95. package/dist/commands/workflow-subprocess.js +370 -20
  96. package/dist/commands/workflow-subprocess.js.map +1 -1
  97. package/dist/commands/workflow.d.ts.map +1 -1
  98. package/dist/commands/workflow.js +35 -61
  99. package/dist/commands/workflow.js.map +1 -1
  100. package/dist/core/client.d.ts +2 -1
  101. package/dist/core/client.d.ts.map +1 -1
  102. package/dist/core/client.js +4 -2
  103. package/dist/core/client.js.map +1 -1
  104. package/dist/index.js +6 -0
  105. package/dist/index.js.map +1 -1
  106. package/dist/services/actionflow/calendar_mapper.d.ts.map +1 -1
  107. package/dist/services/actionflow/calendar_mapper.js +64 -18
  108. package/dist/services/actionflow/calendar_mapper.js.map +1 -1
  109. package/dist/services/actionflow/component_registry.d.ts.map +1 -1
  110. package/dist/services/actionflow/component_registry.js +6 -0
  111. package/dist/services/actionflow/component_registry.js.map +1 -1
  112. package/dist/services/actionflow/components/document_actions.d.ts.map +1 -1
  113. package/dist/services/actionflow/components/document_actions.js +113 -4
  114. package/dist/services/actionflow/components/document_actions.js.map +1 -1
  115. package/dist/services/actionflow/components/eb_get_data_by_id.d.ts.map +1 -1
  116. package/dist/services/actionflow/components/eb_get_data_by_id.js +18 -1
  117. package/dist/services/actionflow/components/eb_get_data_by_id.js.map +1 -1
  118. package/dist/services/actionflow/components/index.d.ts.map +1 -1
  119. package/dist/services/actionflow/components/index.js +2 -1
  120. package/dist/services/actionflow/components/index.js.map +1 -1
  121. package/dist/services/actionflow/components/meeting_create.d.ts.map +1 -1
  122. package/dist/services/actionflow/components/meeting_create.js +5 -1
  123. package/dist/services/actionflow/components/meeting_create.js.map +1 -1
  124. package/dist/services/actionflow/components/schedule_create.d.ts.map +1 -1
  125. package/dist/services/actionflow/components/schedule_create.js +22 -6
  126. package/dist/services/actionflow/components/schedule_create.js.map +1 -1
  127. package/dist/services/actionflow/components/workflow_actions.d.ts +1 -0
  128. package/dist/services/actionflow/components/workflow_actions.d.ts.map +1 -1
  129. package/dist/services/actionflow/components/workflow_actions.js +44 -7
  130. package/dist/services/actionflow/components/workflow_actions.js.map +1 -1
  131. package/dist/services/actionflow/document_source.d.ts +5 -0
  132. package/dist/services/actionflow/document_source.d.ts.map +1 -1
  133. package/dist/services/actionflow/document_source.js +16 -0
  134. package/dist/services/actionflow/document_source.js.map +1 -1
  135. package/dist/services/actionflow/formula_service.d.ts +7 -0
  136. package/dist/services/actionflow/formula_service.d.ts.map +1 -1
  137. package/dist/services/actionflow/formula_service.js +44 -8
  138. package/dist/services/actionflow/formula_service.js.map +1 -1
  139. package/dist/services/actionflow/preflight_service.d.ts +5 -0
  140. package/dist/services/actionflow/preflight_service.d.ts.map +1 -1
  141. package/dist/services/actionflow/preflight_service.js +127 -2
  142. package/dist/services/actionflow/preflight_service.js.map +1 -1
  143. package/dist/services/actionflow/save_workflow_draft.d.ts +7 -0
  144. package/dist/services/actionflow/save_workflow_draft.d.ts.map +1 -1
  145. package/dist/services/actionflow/save_workflow_draft.js +1 -1
  146. package/dist/services/actionflow/save_workflow_draft.js.map +1 -1
  147. package/dist/services/actionflow/workflow_compiler.d.ts.map +1 -1
  148. package/dist/services/actionflow/workflow_compiler.js +26 -0
  149. package/dist/services/actionflow/workflow_compiler.js.map +1 -1
  150. package/dist/services/app-publish.d.ts +25 -0
  151. package/dist/services/app-publish.d.ts.map +1 -1
  152. package/dist/services/app-publish.js +38 -0
  153. package/dist/services/app-publish.js.map +1 -1
  154. package/dist/services/app-range.d.ts +66 -0
  155. package/dist/services/app-range.d.ts.map +1 -0
  156. package/dist/services/app-range.js +137 -0
  157. package/dist/services/app-range.js.map +1 -0
  158. package/dist/services/form-association.d.ts +13 -0
  159. package/dist/services/form-association.d.ts.map +1 -1
  160. package/dist/services/form-association.js +42 -0
  161. package/dist/services/form-association.js.map +1 -1
  162. package/dist/services/form-button-action.d.ts +82 -0
  163. package/dist/services/form-button-action.d.ts.map +1 -1
  164. package/dist/services/form-button-action.js +194 -2
  165. package/dist/services/form-button-action.js.map +1 -1
  166. package/dist/services/form-button-condition.d.ts +45 -0
  167. package/dist/services/form-button-condition.d.ts.map +1 -0
  168. package/dist/services/form-button-condition.js +106 -0
  169. package/dist/services/form-button-condition.js.map +1 -0
  170. package/dist/services/form-button-context.d.ts +41 -0
  171. package/dist/services/form-button-context.d.ts.map +1 -0
  172. package/dist/services/form-button-context.js +54 -0
  173. package/dist/services/form-button-context.js.map +1 -0
  174. package/dist/services/form-button-logicflow.d.ts +30 -0
  175. package/dist/services/form-button-logicflow.d.ts.map +1 -0
  176. package/dist/services/form-button-logicflow.js +59 -0
  177. package/dist/services/form-button-logicflow.js.map +1 -0
  178. package/dist/services/form-button-org.d.ts +30 -0
  179. package/dist/services/form-button-org.d.ts.map +1 -0
  180. package/dist/services/form-button-org.js +80 -0
  181. package/dist/services/form-button-org.js.map +1 -0
  182. package/dist/services/form-button-permission.d.ts +65 -0
  183. package/dist/services/form-button-permission.d.ts.map +1 -0
  184. package/dist/services/form-button-permission.js +113 -0
  185. package/dist/services/form-button-permission.js.map +1 -0
  186. package/dist/services/form-button-position.d.ts +4 -18
  187. package/dist/services/form-button-position.d.ts.map +1 -1
  188. package/dist/services/form-button-position.js +4 -36
  189. package/dist/services/form-button-position.js.map +1 -1
  190. package/dist/services/form-button-props.d.ts +55 -0
  191. package/dist/services/form-button-props.d.ts.map +1 -0
  192. package/dist/services/form-button-props.js +90 -0
  193. package/dist/services/form-button-props.js.map +1 -0
  194. package/dist/services/form-button-save.d.ts +49 -0
  195. package/dist/services/form-button-save.d.ts.map +1 -0
  196. package/dist/services/form-button-save.js +54 -0
  197. package/dist/services/form-button-save.js.map +1 -0
  198. package/dist/services/form-formula-linkage.d.ts +120 -20
  199. package/dist/services/form-formula-linkage.d.ts.map +1 -1
  200. package/dist/services/form-formula-linkage.js +253 -39
  201. package/dist/services/form-formula-linkage.js.map +1 -1
  202. package/dist/services/form-layout-io.d.ts +18 -0
  203. package/dist/services/form-layout-io.d.ts.map +1 -0
  204. package/dist/services/form-layout-io.js +89 -0
  205. package/dist/services/form-layout-io.js.map +1 -0
  206. package/dist/services/form-layout-source/artifact.d.ts +8 -0
  207. package/dist/services/form-layout-source/artifact.d.ts.map +1 -0
  208. package/dist/services/form-layout-source/artifact.js +52 -0
  209. package/dist/services/form-layout-source/artifact.js.map +1 -0
  210. package/dist/services/form-layout-source/binding.d.ts +10 -0
  211. package/dist/services/form-layout-source/binding.d.ts.map +1 -0
  212. package/dist/services/form-layout-source/binding.js +43 -0
  213. package/dist/services/form-layout-source/binding.js.map +1 -0
  214. package/dist/services/form-layout-source/compile.d.ts +7 -0
  215. package/dist/services/form-layout-source/compile.d.ts.map +1 -0
  216. package/dist/services/form-layout-source/compile.js +262 -0
  217. package/dist/services/form-layout-source/compile.js.map +1 -0
  218. package/dist/services/form-layout-source/creation.d.ts +18 -0
  219. package/dist/services/form-layout-source/creation.d.ts.map +1 -0
  220. package/dist/services/form-layout-source/creation.js +42 -0
  221. package/dist/services/form-layout-source/creation.js.map +1 -0
  222. package/dist/services/form-layout-source/excel-extractor.d.ts +7 -0
  223. package/dist/services/form-layout-source/excel-extractor.d.ts.map +1 -0
  224. package/dist/services/form-layout-source/excel-extractor.js +342 -0
  225. package/dist/services/form-layout-source/excel-extractor.js.map +1 -0
  226. package/dist/services/form-layout-source/image-border.d.ts +9 -0
  227. package/dist/services/form-layout-source/image-border.d.ts.map +1 -0
  228. package/dist/services/form-layout-source/image-border.js +128 -0
  229. package/dist/services/form-layout-source/image-border.js.map +1 -0
  230. package/dist/services/form-layout-source/image-observation.d.ts +14 -0
  231. package/dist/services/form-layout-source/image-observation.d.ts.map +1 -0
  232. package/dist/services/form-layout-source/image-observation.js +90 -0
  233. package/dist/services/form-layout-source/image-observation.js.map +1 -0
  234. package/dist/services/form-layout-source/image-review.d.ts +32 -0
  235. package/dist/services/form-layout-source/image-review.d.ts.map +1 -0
  236. package/dist/services/form-layout-source/image-review.js +266 -0
  237. package/dist/services/form-layout-source/image-review.js.map +1 -0
  238. package/dist/services/form-layout-source/image-style.d.ts +16 -0
  239. package/dist/services/form-layout-source/image-style.d.ts.map +1 -0
  240. package/dist/services/form-layout-source/image-style.js +539 -0
  241. package/dist/services/form-layout-source/image-style.js.map +1 -0
  242. package/dist/services/form-layout-source/json.d.ts +3 -0
  243. package/dist/services/form-layout-source/json.d.ts.map +1 -0
  244. package/dist/services/form-layout-source/json.js +33 -0
  245. package/dist/services/form-layout-source/json.js.map +1 -0
  246. package/dist/services/form-layout-source/presentation.d.ts +23 -0
  247. package/dist/services/form-layout-source/presentation.d.ts.map +1 -0
  248. package/dist/services/form-layout-source/presentation.js +174 -0
  249. package/dist/services/form-layout-source/presentation.js.map +1 -0
  250. package/dist/services/form-layout-source/preview.d.ts +4 -0
  251. package/dist/services/form-layout-source/preview.d.ts.map +1 -0
  252. package/dist/services/form-layout-source/preview.js +49 -0
  253. package/dist/services/form-layout-source/preview.js.map +1 -0
  254. package/dist/services/form-layout-source/schema.d.ts +20 -0
  255. package/dist/services/form-layout-source/schema.d.ts.map +1 -0
  256. package/dist/services/form-layout-source/schema.js +149 -0
  257. package/dist/services/form-layout-source/schema.js.map +1 -0
  258. package/dist/services/form-layout-source/source-grid.d.ts +8 -0
  259. package/dist/services/form-layout-source/source-grid.d.ts.map +1 -0
  260. package/dist/services/form-layout-source/source-grid.js +61 -0
  261. package/dist/services/form-layout-source/source-grid.js.map +1 -0
  262. package/dist/services/form-layout-source/types.d.ts +242 -0
  263. package/dist/services/form-layout-source/types.d.ts.map +1 -0
  264. package/dist/services/form-layout-source/types.js +2 -0
  265. package/dist/services/form-layout-source/types.js.map +1 -0
  266. package/dist/services/form-layout-source/verify.d.ts +14 -0
  267. package/dist/services/form-layout-source/verify.d.ts.map +1 -0
  268. package/dist/services/form-layout-source/verify.js +226 -0
  269. package/dist/services/form-layout-source/verify.js.map +1 -0
  270. package/dist/services/form-list-search-group.d.ts +17 -2
  271. package/dist/services/form-list-search-group.d.ts.map +1 -1
  272. package/dist/services/form-list-search-group.js +29 -12
  273. package/dist/services/form-list-search-group.js.map +1 -1
  274. package/dist/services/form-list-search.d.ts.map +1 -1
  275. package/dist/services/form-list-search.js +4 -0
  276. package/dist/services/form-list-search.js.map +1 -1
  277. package/dist/services/form-list-stats.d.ts.map +1 -1
  278. package/dist/services/form-list-stats.js +9 -2
  279. package/dist/services/form-list-stats.js.map +1 -1
  280. package/dist/services/form-message.d.ts +26 -7
  281. package/dist/services/form-message.d.ts.map +1 -1
  282. package/dist/services/form-message.js +52 -5
  283. package/dist/services/form-message.js.map +1 -1
  284. package/dist/services/form-obj-meta.d.ts +72 -0
  285. package/dist/services/form-obj-meta.d.ts.map +1 -0
  286. package/dist/services/form-obj-meta.js +103 -0
  287. package/dist/services/form-obj-meta.js.map +1 -0
  288. package/dist/services/form-permission-archive.d.ts +9 -1
  289. package/dist/services/form-permission-archive.d.ts.map +1 -1
  290. package/dist/services/form-permission-archive.js +38 -22
  291. package/dist/services/form-permission-archive.js.map +1 -1
  292. package/dist/services/form-view-populate.d.ts.map +1 -1
  293. package/dist/services/form-view-populate.js +7 -0
  294. package/dist/services/form-view-populate.js.map +1 -1
  295. package/dist/services/icon-path.d.ts +70 -0
  296. package/dist/services/icon-path.d.ts.map +1 -0
  297. package/dist/services/icon-path.js +80 -0
  298. package/dist/services/icon-path.js.map +1 -0
  299. package/dist/services/matrix-condition.d.ts +161 -0
  300. package/dist/services/matrix-condition.d.ts.map +1 -0
  301. package/dist/services/matrix-condition.js +403 -0
  302. package/dist/services/matrix-condition.js.map +1 -0
  303. package/dist/services/menu-catalog.d.ts +33 -0
  304. package/dist/services/menu-catalog.d.ts.map +1 -1
  305. package/dist/services/menu-catalog.js +56 -0
  306. package/dist/services/menu-catalog.js.map +1 -1
  307. package/dist/services/permission-entity.d.ts +55 -0
  308. package/dist/services/permission-entity.d.ts.map +1 -0
  309. package/dist/services/permission-entity.js +79 -0
  310. package/dist/services/permission-entity.js.map +1 -0
  311. package/dist/services/validate-help.d.ts +25 -0
  312. package/dist/services/validate-help.d.ts.map +1 -0
  313. package/dist/services/validate-help.js +29 -0
  314. package/dist/services/validate-help.js.map +1 -0
  315. package/dist/services/workflow-assign-flow.d.ts.map +1 -1
  316. package/dist/services/workflow-assign-flow.js.map +1 -1
  317. package/dist/services/workflow-function-management.d.ts +123 -0
  318. package/dist/services/workflow-function-management.d.ts.map +1 -0
  319. package/dist/services/workflow-function-management.js +425 -0
  320. package/dist/services/workflow-function-management.js.map +1 -0
  321. package/dist/services/workflow-matrix-rule.d.ts +34 -0
  322. package/dist/services/workflow-matrix-rule.d.ts.map +1 -0
  323. package/dist/services/workflow-matrix-rule.js +94 -0
  324. package/dist/services/workflow-matrix-rule.js.map +1 -0
  325. package/dist/services/workflow-opinion-settings.d.ts +67 -0
  326. package/dist/services/workflow-opinion-settings.d.ts.map +1 -0
  327. package/dist/services/workflow-opinion-settings.js +328 -0
  328. package/dist/services/workflow-opinion-settings.js.map +1 -0
  329. package/package.json +3 -1
  330. package/skill-docs/SKILL.md +15 -6
  331. package/skill-docs/_catalog.md +4 -0
  332. package/skill-docs/actionflows/references/components/calendar/MeetingCreate.md +2 -0
  333. package/skill-docs/actionflows/references/components/document/DocumentSave.md +17 -17
  334. package/skill-docs/actionflows/references/components/workflow/ApproveCompletelyDelete.md +29 -0
  335. package/skill-docs/actionflows/references/components/workflow/ApproveDelete.md +2 -2
  336. package/skill-docs/assets/schemas/image-style-observation.schema.json +1355 -0
  337. package/skill-docs/references/common/guide-plan-template.md +3 -0
  338. package/skill-docs/references/common/ref-cli-commands.md +77 -26
  339. package/skill-docs/references/ebuilder-designer/guide-designer-components.md +9 -0
  340. package/skill-docs/references/form/guide-create-form.md +2 -0
  341. package/skill-docs/references/form/guide-field-linkage.md +140 -55
  342. package/skill-docs/references/form/guide-form-archive-permission.md +55 -2
  343. package/skill-docs/references/form/guide-form-association.md +13 -0
  344. package/skill-docs/references/form/guide-form-button.md +87 -0
  345. package/skill-docs/references/form/guide-form-layout-planning.md +6 -0
  346. package/skill-docs/references/form/guide-form-layout-source.md +366 -0
  347. package/skill-docs/references/form/guide-form-message.md +19 -2
  348. package/skill-docs/references/form/guide-form-view.md +24 -4
  349. package/skill-docs/references/form/guide-formula-linkage.md +86 -12
  350. package/skill-docs/references/workflow/guide-function-management.md +154 -0
  351. package/skill-docs/references/workflow/guide-opinion-settings.md +126 -0
  352. package/skill-docs/references/workflow/guide-workflow.md +22 -6
@@ -3,6 +3,13 @@ import { resolveFormRecord } from '../services/form-id.js';
3
3
  import { AuthSession } from '../core/auth.js';
4
4
  import { ApiClient } from '../core/client.js';
5
5
  import { genSfId, normalizeNumericFrontId } from '../services/actionflow/id_generator.js';
6
+ // 查询条件的算子与字段类型族:与动作流 EnquiryForm 共用同一套(filter_rules.ts)。
7
+ import { conditionFieldFamily, normalizeFilterOperator } from '../services/actionflow/filter_rules.js';
8
+ // 生效维度/触发时机与函数联动共用同一套解析,避免两处各写一份。
9
+ import { buildFdEffect, buildLinkageExt, extractEffect, isWorkflowDimension, buildTriggerSpecs, buildMonitorActions, mergeMonitorActions, specsFromStoredTriggers, storedTriggers, } from '../services/form-formula-linkage.js';
10
+ import { fetchDrivingEvents, fetchDrivingColumns, resolveEbEffect, isWorkflowEffectInput, } from './form-formula-linkage.js';
11
+ // 赋值前提走 ESB 条件服务(source=8),与动作流 Condition 节点同一套两步保存。
12
+ import { buildConditionDisplayTree, stripTemporaryConditionIds } from '../services/actionflow/save_workflow_draft.js';
6
13
  /**
7
14
  * form field-linkage — 字段联动(FormDataLinkage,跨表带出赋值)。
8
15
  *
@@ -19,15 +26,136 @@ const ESB_APP_API = '/api/bs/esb/setting/application';
19
26
  const ESB_DESIGN_API = '/api/bs/esb/setting/flow/design';
20
27
  const FIELD_LINKAGE_API = '/api/bs/esb/setting/fieldlinkage';
21
28
  const FIELD_LINKAGE_LIGHT_ID = '941997121054621697';
29
+ /** commander 可重复选项的收集器:`--assign a=b --assign c=d` → ['a=b','c=d'] */
30
+ function collect(value, previous) {
31
+ return [...(previous || []), value];
32
+ }
33
+ /** 生效维度解析失败直接退出(与函数联动同一套 `resolveEbEffect`)。 */
34
+ async function resolveEffectOrExit(client, baseUrl, formId, formName, o) {
35
+ try {
36
+ return await resolveEbEffect(client, baseUrl, formId, formName, o);
37
+ }
38
+ catch (error) {
39
+ console.error(` ❌ ${error?.message || error}`);
40
+ process.exit(1);
41
+ }
42
+ }
43
+ /** 「主表联动明细表时」→ `linkageExt.subFormLikeType`。 */
44
+ function resolveSubFormLikeType(input) {
45
+ if (!input)
46
+ return 'addSubForm';
47
+ const map = {
48
+ add: 'addSubForm', '添加明细': 'addSubForm', addSubForm: 'addSubForm',
49
+ cover: 'updSubForm', '覆盖明细': 'updSubForm', updSubForm: 'updSubForm',
50
+ update: 'rowUpdate', '更新明细': 'rowUpdate', rowUpdate: 'rowUpdate',
51
+ };
52
+ const hit = map[String(input).trim()] || map[String(input).trim().toLowerCase()];
53
+ if (!hit) {
54
+ console.error('--detail-mode 只接受 add(添加明细)/ cover(覆盖明细)/ update(更新明细)');
55
+ process.exit(1);
56
+ }
57
+ return hit;
58
+ }
59
+ /** 「明细表添加行时」→ `linkageExt.subFormAddType`。 */
60
+ function resolveSubFormAddType(input) {
61
+ if (!input)
62
+ return 'override';
63
+ const map = {
64
+ override: 'override', '删除再添加': 'override', '删除已联动出的明细再添加': 'override',
65
+ append: 'append', '累计添加': 'append', '累计添加明细': 'append',
66
+ };
67
+ const hit = map[String(input).trim()] || map[String(input).trim().toLowerCase()];
68
+ if (!hit) {
69
+ console.error('--detail-add 只接受 override(删除再添加)/ append(累计添加)');
70
+ process.exit(1);
71
+ }
72
+ return hit;
73
+ }
74
+ /** 「联动出的值继续触发联动」→ `linkageExt.fissionState`。 */
75
+ function parseFissionOrExit(input, fallback = 1) {
76
+ if (!input)
77
+ return fallback;
78
+ const v = String(input).toLowerCase();
79
+ if (v === 'on' || v === '1')
80
+ return 1;
81
+ if (v === 'off' || v === '0')
82
+ return 0;
83
+ console.error('--fission 只接受 on / off');
84
+ process.exit(1);
85
+ }
86
+ function parseStateOrExit(input, fallback = true) {
87
+ if (!input)
88
+ return fallback;
89
+ const v = String(input).toLowerCase();
90
+ if (v !== 'on' && v !== 'off') {
91
+ console.error('--state 只接受 on / off');
92
+ process.exit(1);
93
+ }
94
+ return v === 'on';
95
+ }
96
+ /** 触发动作:与函数联动同一套事件清单 + 字段解析(一个时机 × 一个字段 = 一条 action)。 */
97
+ async function resolveTriggerActionsOrExit(p) {
98
+ try {
99
+ const [events, columns] = await Promise.all([
100
+ fetchDrivingEvents(p.client, p.baseUrl, p.appId, p.formId, p.objId, { workflowWide: isWorkflowDimension(p.effect?.effectType) }),
101
+ fetchDrivingColumns(p.client, p.baseUrl, p.appId, p.formId, p.objId),
102
+ ]);
103
+ const built = buildTriggerSpecs(events, columns, p.event, p.trigger ? [p.trigger] : []);
104
+ for (const w of built.warnings)
105
+ console.error(` ⚠ ${w}`);
106
+ return buildMonitorActions(built.specs);
107
+ }
108
+ catch (error) {
109
+ console.error(` ❌ ${error?.message || error}`);
110
+ process.exit(1);
111
+ }
112
+ }
113
+ /** 改联动的报文:形状 = 新建报文 + `id`,`dataSources` 原样回传读回的那份。 */
114
+ export function buildFieldLinkageUpdatePayload(record, p) {
115
+ const ext = record?.linkageExt || {};
116
+ const extOverrides = {};
117
+ for (const key of ['subFormLikeType', 'subFormAddType', 'effectContent', 'fissionState']) {
118
+ if (ext[key] !== undefined && ext[key] !== null)
119
+ extOverrides[key] = ext[key];
120
+ }
121
+ for (const key of ['subFormLikeType', 'subFormAddType', 'fissionState']) {
122
+ const v = p.detailExt?.[key];
123
+ if (v !== undefined && v !== null)
124
+ extOverrides[key] = v;
125
+ }
126
+ return {
127
+ id: String(record?.id ?? ''),
128
+ formId: String(record?.formId ?? ''),
129
+ fdEffect: buildFdEffect(String(record?.formId ?? ''), p.effect),
130
+ linkageModule: 'ebuilderform',
131
+ linkageName: p.linkageName,
132
+ linkageState: p.linkageState,
133
+ linkageType: 'template',
134
+ linkageExt: buildLinkageExt({ subFormLikeType: 'addSubForm', subFormAddType: 'override', effectContent: '', fissionState: 1, ...extOverrides }),
135
+ monitorActions: p.monitorActions,
136
+ dataSources: record?.dataSources || [],
137
+ needSqlCompress: 1,
138
+ customParam: { appId: p.appId, objId: p.objId },
139
+ };
140
+ }
22
141
  async function getFormId(client, baseUrl, appId, objId) {
23
142
  const f = await resolveFormRecord(client, baseUrl, appId, objId);
24
143
  if (!f?.formId)
25
144
  throw new Error(`无法获取 formId,请确认 objId=${objId}`);
26
145
  return { formId: String(f.formId), formName: f.formName || f.objName || f.name || '' };
27
146
  }
28
- async function getFormFields(client, baseUrl, objId, userId, tenantKey) {
147
+ /** 主表字段 + 明细表(字段联动可以把值写到明细表,需要 subFormId)。 */
148
+ async function getFormMeta(client, baseUrl, objId, userId, tenantKey) {
29
149
  const res = await client.post(`${baseUrl}/api/ebuilder/form/dataset/v1/getFields`, { objId, userid: userId, tenantKey, isReturnDetail: 'y' });
30
- return res?.data?.mainFields || [];
150
+ const details = (res?.data?.detailFields || []).map((d) => ({
151
+ id: String(d.fields?.[0]?.subFormId || d.id || ''),
152
+ name: String(d.fields?.[0]?.subFormName || d.name || ''),
153
+ fields: d.fields || [],
154
+ })).filter((d) => /^\d+$/.test(d.id));
155
+ return { main: res?.data?.mainFields || [], details };
156
+ }
157
+ async function getFormFields(client, baseUrl, objId, userId, tenantKey) {
158
+ return (await getFormMeta(client, baseUrl, objId, userId, tenantKey)).main;
31
159
  }
32
160
  function findFieldId(fields, name) {
33
161
  const f = fields.find((x) => x.fieldName === name && /^\d+$/.test(String(x.fieldId)));
@@ -158,14 +286,200 @@ export function registerFormFieldLinkageCommands(form, program) {
158
286
  for (const f of fields)
159
287
  console.log(` ${f.id || f.fieldId} ${f.showName || f.fieldName} (${f.componentKey || f.fieldKey})`);
160
288
  });
161
- // ─── add(支持单跳和多跳链式)───
162
- fl.command('add').description('新增字段联动。--hops 多跳链式(objId:字段名,objId:字段名,...),或 --source-form/--query-field 单跳')
289
+ fl.command('events').description('列出可用的触发动作').argument('<appId>').argument('<objId>')
290
+ .option('--effect <dimension>', '按哪个生效维度列:form=当前表单 / formLayout=表单布局 / workFlow=当前工作流 / includeNode=选择节点')
291
+ .option('--workflow-id <id>', '流程 ID(与 add 写法保持一致,不影响清单)')
292
+ .action(async (appId, objId, cmdOpts) => {
293
+ const opts = program.opts();
294
+ const auth = await AuthSession.fromOptions(opts);
295
+ if (!auth)
296
+ process.exit(1);
297
+ const client = new ApiClient(auth);
298
+ const baseUrl = auth.getBaseUrl();
299
+ const { formId } = await getFormId(client, baseUrl, appId, objId);
300
+ const workflowWide = isWorkflowEffectInput(cmdOpts.effect);
301
+ const events = await fetchDrivingEvents(client, baseUrl, appId, formId, objId, { workflowWide });
302
+ if (opts.json) {
303
+ console.log(JSON.stringify(events, null, 2));
304
+ return;
305
+ }
306
+ console.log(`共 ${events.length} 个触发动作${workflowWide ? '(含流程级,需配合 --effect workFlow/includeNode 使用)' : ''}:`);
307
+ for (const e of events) {
308
+ console.log(` ${e.groupName ? `${e.groupName} / ` : ''}${e.name} ${e.type} ${e.selectColumn ? '(需触发字段)' : '(表单级/流程级,无需触发字段)'}`);
309
+ }
310
+ if (!workflowWide)
311
+ console.log(' (流程级事件加 --effect workFlow --workflow-id <流程id> 才列得出来)');
312
+ });
313
+ fl.command('update').description('改字段联动的名称/启停/触发动作/生效维度(不给 --event/--trigger 就原样沿用现有的触发动作)')
314
+ .argument('<appId>').argument('<objId>').argument('<linkageId>')
315
+ .option('--name <name>', '改联动名称')
316
+ .option('--state <onoff>', '启用或停用: on / off')
317
+ .option('--event <event...>', '改触发动作,可多个(写法同 add:事件名或 type,可带「类型:字段,字段」)。不给则沿用现有')
318
+ .option('--trigger <fields...>', '改触发字段(作用于记录里的字段级触发动作)。不给则沿用现有')
319
+ .option('--effect <dimension>', '改生效维度(默认沿用现有)')
320
+ .option('--detail-mode <mode>', '主表联动明细表时: add=添加明细 / cover=覆盖明细 / update=更新明细(不给沿用现有)')
321
+ .option('--detail-add <mode>', '明细表添加行时: override=删除再添加 / append=累计添加(不给沿用现有)')
322
+ .option('--fission <onoff>', '联动出的值继续触发联动: on / off(不给沿用现有)')
323
+ .option('--precondition <expr>', '设置/替换赋值前提(可重复,多个为「且」):源表字段:算子[:值];值写 @字段名 表示引用查询结果字段', collect, [])
324
+ .option('--clear-precondition', '关闭赋值前提')
325
+ .option('--workflow-id <id>', '流程 ID(workFlow / includeNode 必给;不给沿用记录里的)')
326
+ .option('--node <node>', 'includeNode 的节点(id 或节点名)')
327
+ .option('--layout-id <id>', 'formLayout 指定的布局 id')
328
+ .action(async (appId, objId, linkageId, cmdOpts) => {
329
+ const opts = program.opts();
330
+ const auth = await AuthSession.fromOptions(opts);
331
+ if (!auth)
332
+ process.exit(1);
333
+ const client = new ApiClient(auth);
334
+ const baseUrl = auth.getBaseUrl();
335
+ const { formId, formName } = await getFormId(client, baseUrl, appId, objId);
336
+ const rb = await client.post(`${baseUrl}${LINKAGE_API}/queryById?apid=${appId}`, { id: linkageId, formId, module: 'ebuilderform', customParam: { appId, objId } }, { ebbusinessid: formId });
337
+ if (rb?.code !== 200 || !rb?.status) {
338
+ console.error(`查询失败: ${rb?.msg || '未知错误'}`);
339
+ process.exit(1);
340
+ }
341
+ const record = rb?.data;
342
+ if (String(record?.linkageType) !== 'template') {
343
+ console.error(`这条的 linkageType 是 ${record?.linkageType},不是字段联动(跨表带出)—— 用 form formula-linkage 那套命令改`);
344
+ process.exit(1);
345
+ }
346
+ // 只改启停时走专用接口(设计器里点开关就是这一个请求),不重发整套联动报文
347
+ const onlyState = cmdOpts.state !== undefined
348
+ && !cmdOpts.name && !cmdOpts.event?.length && !cmdOpts.trigger?.length
349
+ && !cmdOpts.effect && cmdOpts.detailMode === undefined
350
+ && cmdOpts.detailAdd === undefined && cmdOpts.fission === undefined;
351
+ if (onlyState) {
352
+ const target = parseStateOrExit(cmdOpts.state);
353
+ const stateRes = await client.post(`${baseUrl}${LINKAGE_API}/updateFormDataLinkageState?apid=${appId}`, {
354
+ id: linkageId, formId, linkageModule: 'ebuilderform', linkageType: 'template',
355
+ linkageState: target, customParam: { appId, objId },
356
+ }, { ebbusinessid: formId });
357
+ if (stateRes?.code !== 200 || !stateRes?.status) {
358
+ console.error(`更新启用状态失败: ${stateRes?.msg || '未知错误'}`);
359
+ process.exit(1);
360
+ }
361
+ const rbState = await client.post(`${baseUrl}${LINKAGE_API}/queryById?apid=${appId}`, { id: linkageId, formId, module: 'ebuilderform', customParam: { appId, objId } }, { ebbusinessid: formId });
362
+ const afterState = rbState?.data || {};
363
+ const state = afterState.linkageState !== false;
364
+ if (state !== target) {
365
+ console.error(` ⚠ 回读的启用状态与提交的不一致,以平台为准(提交 ${target},回读 ${state})`);
366
+ }
367
+ console.log(opts.json
368
+ ? JSON.stringify({ success: true, linkageId, state })
369
+ : `已${state ? '启用' : '停用'}字段联动: [${linkageId}] ${afterState.linkageName || ''}`);
370
+ return;
371
+ }
372
+ let effect;
373
+ let specs = null;
374
+ try {
375
+ const curEffect = extractEffect(record);
376
+ const workflowId = cmdOpts.workflowId
377
+ || (isWorkflowDimension(curEffect?.effectType) ? String(curEffect?.effectValue || '') : '')
378
+ || String(record?.refId || '');
379
+ effect = cmdOpts.effect
380
+ ? await resolveEbEffect(client, baseUrl, formId, formName, { effect: cmdOpts.effect, workflowId, node: cmdOpts.node, layoutId: cmdOpts.layoutId })
381
+ : curEffect;
382
+ // 换维度时可用事件整个换了一套;不给 --event 会存出「事件与维度不匹配」的坏规则
383
+ if (isWorkflowDimension(curEffect?.effectType) !== isWorkflowDimension(effect?.effectType) && !cmdOpts.event?.length) {
384
+ throw new Error('生效维度在「当前表单/表单布局」与「当前工作流/选择节点」之间切换时,必须同时用 --event 指定新维度下可用的触发动作');
385
+ }
386
+ const wantEvents = !!cmdOpts.event?.length;
387
+ const wantTrigger = !!cmdOpts.trigger?.length;
388
+ if (wantEvents || wantTrigger) {
389
+ const [events, columns] = await Promise.all([
390
+ fetchDrivingEvents(client, baseUrl, appId, formId, objId, { workflowWide: isWorkflowDimension(effect?.effectType) }),
391
+ fetchDrivingColumns(client, baseUrl, appId, formId, objId),
392
+ ]);
393
+ if (wantEvents) {
394
+ const built = buildTriggerSpecs(events, columns, cmdOpts.event, cmdOpts.trigger || []);
395
+ specs = built.specs;
396
+ for (const w of built.warnings)
397
+ console.error(` ⚠ ${w}`);
398
+ }
399
+ else {
400
+ const built = specsFromStoredTriggers(storedTriggers(record), events, columns, cmdOpts.trigger || []);
401
+ specs = built.specs;
402
+ if (!built.overrideApplied)
403
+ console.error(' ⚠ 记录里没有字段级触发动作,--trigger 已忽略');
404
+ }
405
+ }
406
+ }
407
+ catch (error) {
408
+ console.error(` ❌ ${error?.message || error}`);
409
+ process.exit(1);
410
+ }
411
+ // 两个都没给就原样透传读回的 monitorActions,避免只改名称时把其余触发动作抹掉
412
+ const monitorActions = specs ? mergeMonitorActions(record?.monitorActions || [], specs) : (record?.monitorActions || []);
413
+ const linkageState = parseStateOrExit(cmdOpts.state, record?.linkageState !== false);
414
+ // 三个明细开关:不给就沿用读回值(buildFieldLinkageUpdatePayload 内部判断)
415
+ const detailExt = {
416
+ subFormLikeType: cmdOpts.detailMode !== undefined ? resolveSubFormLikeType(cmdOpts.detailMode) : undefined,
417
+ subFormAddType: cmdOpts.detailAdd !== undefined ? resolveSubFormAddType(cmdOpts.detailAdd) : undefined,
418
+ fissionState: cmdOpts.fission !== undefined ? parseFissionOrExit(cmdOpts.fission) : undefined,
419
+ };
420
+ const res = await client.post(`${baseUrl}${LINKAGE_API}/updateFormDataLinkage?apid=${appId}`, buildFieldLinkageUpdatePayload(record, {
421
+ appId, objId,
422
+ linkageName: cmdOpts.name || String(record?.linkageName || ''),
423
+ linkageState,
424
+ monitorActions,
425
+ effect,
426
+ detailExt,
427
+ }), { ebbusinessid: formId });
428
+ if (res?.code !== 200 || !res?.status) {
429
+ console.error(`更新失败: ${res?.msg || '未知错误'}`);
430
+ process.exit(1);
431
+ }
432
+ if (cmdOpts.precondition.length > 0 && cmdOpts.clearPrecondition) {
433
+ console.error('--precondition 与 --clear-precondition 只能二选一');
434
+ process.exit(1);
435
+ }
436
+ if (cmdOpts.precondition.length > 0 || cmdOpts.clearPrecondition) {
437
+ await updatePreconditionOrExit({
438
+ client, baseUrl, auth, record, objId,
439
+ precondition: cmdOpts.precondition,
440
+ disable: !!cmdOpts.clearPrecondition,
441
+ });
442
+ }
443
+ await client.post(`${baseUrl}${LINKAGE_API}/preCheck?apid=${appId}`, { module: 'ebuilderform', formId, linkageIds: [linkageId], customParam: { appId, objId } }, { ebbusinessid: formId });
444
+ const rb2 = await client.post(`${baseUrl}${LINKAGE_API}/queryById?apid=${appId}`, { id: linkageId, formId, module: 'ebuilderform', customParam: { appId, objId } }, { ebbusinessid: formId });
445
+ const after = rb2?.data || {};
446
+ const want = monitorActions.map((a) => String(a?.actionType || '')).filter(Boolean).join(',');
447
+ const got = storedTriggers(after).map(t => t.eventType).join(',');
448
+ if (want !== got) {
449
+ console.error(` ⚠ 回读的触发动作与提交的不一致,以平台为准\n 提交: ${want || '(空)'}\n 回读: ${got || '(空)'}`);
450
+ }
451
+ const summary = {
452
+ success: true, linkageId,
453
+ name: after.linkageName,
454
+ state: after.linkageState !== false,
455
+ triggers: storedTriggers(after).map(t => ({ type: t.eventType, name: t.eventName, fields: t.fieldNames })),
456
+ };
457
+ console.log(opts.json
458
+ ? JSON.stringify(summary)
459
+ : `已更新字段联动: [${linkageId}] ${summary.name}(${summary.state ? '启用' : '停用'})`);
460
+ });
461
+ // ─── add(快捷配置 / 单跳 / 多跳链式)───
462
+ fl.command('add').description('新增字段联动。快捷配置用 --condition/--query-fields/--assign;多跳链式用 --hops')
163
463
  .argument('<appId>').argument('<objId>')
164
- .requiredOption('--trigger <字段名>', '本表触发字段名')
165
- .requiredOption('--target <字段名>', '本表目标字段名(被赋值)')
464
+ .option('--trigger <字段名>', '本表触发字段名(默认触发事件「值改变时」的字段;旧单跳/多跳必给)')
465
+ .option('--event <event...>', '触发动作,可多个:事件名或 type,可带「类型:字段,字段」(默认 changeField 值改变时)', ['changeField'])
466
+ .option('--state <onoff>', '启用状态 on / off(默认 on)')
467
+ .option('--effect <dimension>', '生效维度: form=当前表单(默认)/ formLayout=表单布局 / workFlow=当前工作流 / includeNode=选择节点')
468
+ .option('--workflow-id <id>', '流程 ID(workFlow / includeNode 必给)')
469
+ .option('--node <node>', 'includeNode 的节点(id 或节点名)')
470
+ .option('--layout-id <id>', 'formLayout 指定的布局 id')
471
+ .option('--target <字段名>', '本表目标字段名(与 --query-field / --hops 配合)')
166
472
  .option('--hops <list>', '多跳链式:objId:字段名,objId:字段名,...(每跳查一张表带出一个字段,前一跳的输出喂下一跳的过滤)')
167
- .option('--source-form <objId>', '单跳:查询目标表单 objId(与 --query-field 配合)')
473
+ .option('--source-form <objId>', '查询目标表单 objId')
168
474
  .option('--query-field <字段名>', '单跳:目标表要带出的字段名')
475
+ .option('--condition <expr>', '查询条件:源表字段:算子:值;值写 @本表字段名 表示引用本表字段', collect, [])
476
+ .option('--query-fields <list>', '查询字段:源表字段名,逗号分隔(不给则从 --assign 的源字段推导)')
477
+ .option('--assign <expr>', '赋值:源表查询字段=本表目标字段(写「明细表名.字段名」则赋到明细表;可重复)', collect, [])
478
+ .option('--basis <expr>', '明细行依据:明细表名=源表字段名(可重复;不给则取该表第一个赋值的源字段)', collect, [])
479
+ .option('--detail-mode <mode>', '主表联动明细表时: add=添加明细(默认)/ cover=覆盖明细 / update=更新明细')
480
+ .option('--detail-add <mode>', '明细表添加行时: override=删除已联动出的明细再添加(默认)/ append=累计添加明细')
481
+ .option('--fission <onoff>', '联动出的值继续触发联动: on(默认)/ off')
482
+ .option('--precondition <expr>', '赋值前提(可重复,多个为「且」):源表字段:算子[:值];值写 @字段名 表示引用查询结果字段', collect, [])
169
483
  .option('--name <联动名>', '联动名称', '')
170
484
  .action(async (appId, objId, cmdOpts) => {
171
485
  const opts = program.opts();
@@ -175,7 +489,33 @@ export function registerFormFieldLinkageCommands(form, program) {
175
489
  const client = new ApiClient(auth);
176
490
  const baseUrl = auth.getBaseUrl();
177
491
  const { formId: selfFormId, formName: selfFormName } = await getFormId(client, baseUrl, appId, objId);
178
- const selfFields = await getFormFields(client, baseUrl, objId, auth.userId, auth.tenantKey);
492
+ const { main: selfFields, details: selfDetails } = await getFormMeta(client, baseUrl, objId, auth.userId, auth.tenantKey);
493
+ const effect = await resolveEffectOrExit(client, baseUrl, selfFormId, selfFormName, cmdOpts);
494
+ const linkageState = parseStateOrExit(cmdOpts.state);
495
+ const detailExt = {
496
+ subFormLikeType: resolveSubFormLikeType(cmdOpts.detailMode),
497
+ subFormAddType: resolveSubFormAddType(cmdOpts.detailAdd),
498
+ fissionState: parseFissionOrExit(cmdOpts.fission),
499
+ };
500
+ const monitorActions = await resolveTriggerActionsOrExit({
501
+ client, baseUrl, appId, formId: selfFormId, objId,
502
+ event: cmdOpts.event, trigger: cmdOpts.trigger, effect,
503
+ });
504
+ if (cmdOpts.assign.length > 0) {
505
+ await addQuickLinkage({
506
+ client, baseUrl, appId, objId, selfFormId, selfFormName, selfFields, selfDetails,
507
+ trigger: cmdOpts.trigger, monitorActions, effect, linkageState, detailExt, auth, opts, cmdOpts,
508
+ });
509
+ return;
510
+ }
511
+ if (!cmdOpts.trigger) {
512
+ console.error('旧单跳/多跳用法需要 --trigger');
513
+ process.exit(1);
514
+ }
515
+ if (!cmdOpts.target) {
516
+ console.error('需要 --target,或改用快捷配置的 --assign');
517
+ process.exit(1);
518
+ }
179
519
  const triggerField = findFieldId(selfFields, cmdOpts.trigger);
180
520
  const targetField = findFieldId(selfFields, cmdOpts.target);
181
521
  // 解析 hops(多跳)或单跳
@@ -231,10 +571,10 @@ export function registerFormFieldLinkageCommands(form, program) {
231
571
  // 3. saveFormDataLinkage
232
572
  const linkagePayload = {
233
573
  formId: selfFormId,
234
- fdEffect: { formId: selfFormId, effectModule: 'ebuilderform', effectType: 'form', effectName: '当前表单', optionList: [{ effectValue: selfFormId, effectName: '当前表单' }] },
235
- linkageModule: 'ebuilderform', linkageName, linkageState: true, linkageType: 'template',
236
- linkageExt: { subFormLikeType: 'addSubForm', subFormAddType: 'override', effectContent: '', fissionState: 1 },
237
- monitorActions: [{ actionType: 'changeField', actionName: '值改变时', monitorFields: [{ targetField: triggerField.fieldId, targetName: `主表.${cmdOpts.trigger}`, fieldObj: { dataKey: triggerField.fieldKey || '', groupName: '表单字段', address: '主表', addressType: 'form', groupId: 'formField', name: `主表.${cmdOpts.trigger}`, descType: triggerField.fieldKey || '', id: triggerField.fieldId, content: `主表.${cmdOpts.trigger}`, desc: '' } }] }],
574
+ fdEffect: buildFdEffect(selfFormId, effect),
575
+ linkageModule: 'ebuilderform', linkageName, linkageState, linkageType: 'template',
576
+ linkageExt: buildLinkageExt({ ...detailExt, effectContent: '' }),
577
+ monitorActions,
238
578
  dataSources: [{ menuKey: '1', sourceName: '联动设置1', linkageType: 'esb', dataMappings: [], sourceEsb: { configType: 'SIMPLE', parameters: [{ targetField: triggerField.fieldId, targetName: cmdOpts.trigger }] }, dataSourceId: esbAppId, dataSourceName: `${linkageName}-联动设置1` }],
239
579
  needSqlCompress: 1, customParam: { appId, objId },
240
580
  };
@@ -319,4 +659,678 @@ function buildSaveDesign(p) {
319
659
  addIds: [], deleteActions: [], version: 0, delCheckMsg: [], addCheckMsg: [], assistLayer: '{"nodes":[],"layout":{}}', versionConfig: '{}', saveNewVersion: false, lightId: p.lightId, initData: '', secretKey: '', operateType: '', appName: p.appName,
320
660
  };
321
661
  }
662
+ /**
663
+ * 快捷配置:源表任意字段条件 + 多查询字段 + 多赋值参数。
664
+ *
665
+ * 与旧 add(数据ID = 触发字段值)的区别只在 `filterInput`:
666
+ * 旧模型固定查系统字段「数据ID」,新模型查 `--condition` 指定的源表字段。
667
+ * 条件值可以写 `@本表字段名`,此时走 `isEsb:true` + `esbAssign` 动态引用(与旧模型同一形状)。
668
+ */
669
+ /** ESB 条件服务的算子码(与动作流 condition_rules 同一套)。 */
670
+ const CONDITION_OPT_CODE = {
671
+ eq: 5, neq: 6, gt: 1, gte: 2, lt: 3, lte: 4,
672
+ contains: 9, uncontains: 10, aggregate: 11, unaggregate: 12, empty: 13, nempty: 14,
673
+ };
674
+ /**
675
+ * 赋值前提:先调 ESB 条件服务(source=8)持久化条件,再返回 Output 节点要的
676
+ * `conditionEnable` / `conditionInfo`。
677
+ *
678
+ * 注意它**不在**联动记录(`linkageExt`)里 —— 开关赋值前提等价于重新 `saveDesign`。
679
+ */
680
+ /** 查询结果字段的上下文公式(条件左右两侧共用)。 */
681
+ function buildContextFormula(field, srcFormObjId, srcFormName, eqWId) {
682
+ const fid = String(field.fieldId);
683
+ const paramKey = `${srcFormObjId}[].field_${fid}`;
684
+ const valuePath = `FormData.${srcFormObjId}[].field_${fid}`;
685
+ const parentName = `${srcFormName}[].${field.fieldName}`;
686
+ return {
687
+ paramType: 'string', formulaType: 'string', name: String(field.fieldName),
688
+ businessId: genSfId(), selectType: '-1', id: genSfId(), source: eqWId, type: '3',
689
+ value: valuePath,
690
+ config: {
691
+ paramKey, isMultCom: false, comType: 'EnquiryForm', parentComId: '0',
692
+ fieldInfo: { paramKey, tablePrimaryKey: 'FormData' },
693
+ tableName: '表单数据', paramType: 'string', parentName, newParentName: parentName,
694
+ multName: '', multKey: '',
695
+ multTypeObj: { currentName: parentName, allName: parentName, currentParamKey: valuePath, allParamKey: valuePath },
696
+ comId: eqWId,
697
+ },
698
+ fieldType: 'browser',
699
+ };
700
+ }
701
+ /** 解析赋值前提:`源表字段:算子[:值]`;值写 `@字段名` 引用查询结果字段或本表字段。 */
702
+ function parsePreconditionListOrExit(inputs, srcFields, selfFields) {
703
+ return inputs.map(expr => {
704
+ const c = parseConditionExpr(expr, srcFields);
705
+ if (c.range) {
706
+ console.error('赋值前提暂不支持区间条件');
707
+ process.exit(1);
708
+ }
709
+ let refField;
710
+ let refSelf = false;
711
+ if (c.literal && c.literal.startsWith('@')) {
712
+ const name = c.literal.slice(1);
713
+ refField = srcFields.find((f) => f.fieldName === name);
714
+ if (!refField) {
715
+ refField = selfFields.find((f) => f.fieldName === name);
716
+ refSelf = true;
717
+ }
718
+ if (!refField) {
719
+ console.error(`赋值前提引用字段 "${name}" 既不在查询结果也不在本表字段里`);
720
+ process.exit(1);
721
+ }
722
+ }
723
+ return { field: c.field, func: c.func, literal: refField ? undefined : c.literal, refField, refSelf };
724
+ });
725
+ }
726
+ /** 本表字段的上下文化公式(赋值前提右值):source 指向 FieldLinkage 事件,而不是查询节点。 */
727
+ function buildSelfContextFormula(field, selfFormId, selfFormName, eventId, esbAppId) {
728
+ const fid = String(field.fieldId);
729
+ const paramKey = `${selfFormId}.${fid}`;
730
+ const valuePath = `FormData.${selfFormId}.${fid}`;
731
+ const parentName = `${selfFormName}.${field.fieldName}`;
732
+ return {
733
+ paramKey, paramName: fid, showName: String(field.fieldName),
734
+ paramType: 'string', dataType: 'node', arrs: false, required: false, description: fid,
735
+ paramTypeString: 'STRING', dataTypeSting: 'NODE', paramId: fid,
736
+ hideParamNameInSelect: false, hideParam: false, readonlyParam: false, sensitiveFlag: false, newdata: false,
737
+ parentName, name: String(field.fieldName),
738
+ source: eventId, value: valuePath, type: '3', formulaType: 'string', frontId: fid,
739
+ config: {
740
+ paramKey, paramType: 'string', parentName, newParentName: parentName,
741
+ multKey: '', multName: '',
742
+ multTypeObj: { currentName: parentName, allName: parentName, currentParamKey: valuePath, allParamKey: valuePath },
743
+ comId: eventId, isMultCom: false, tableName: '表单数据',
744
+ fieldInfo: { paramKey, tablePrimaryKey: 'FormData' },
745
+ comType: 'FieldLinkage', parentComId: '0',
746
+ },
747
+ id: genSfId(), applicationId: esbAppId, businessId: genSfId(),
748
+ selectType: '-1', needType: 'browser',
749
+ };
750
+ }
751
+ async function savePreconditionOrExit(p) {
752
+ const leaves = p.conds.map(c => {
753
+ const code = CONDITION_OPT_CODE[c.func];
754
+ if (code === undefined) {
755
+ console.error(`赋值前提不支持的算子 "${c.func}"`);
756
+ process.exit(1);
757
+ }
758
+ const leaf = {
759
+ expressionBaseId: genSfId(), dataValueId: genSfId(), elementValue2Id: genSfId(), elementValue1Id: genSfId(),
760
+ selectType: 97, BrowserCompareOptionLeft: code,
761
+ customFieldType: buildContextFormula(c.field, p.srcFormObjId, p.srcFormName, p.eqWId),
762
+ };
763
+ // 包含 / 不包含 额外带「任一值/全部」标记
764
+ if (code === 9 || code === 10)
765
+ leaf.containType = 1;
766
+ if (c.refField) {
767
+ leaf.BrowserTextValueLeft = c.refSelf
768
+ ? buildSelfContextFormula(c.refField, p.selfFormId, p.selfFormName, p.eventId, p.esbAppId)
769
+ : buildContextFormula(c.refField, p.srcFormObjId, p.srcFormName, p.eqWId);
770
+ }
771
+ else if (c.literal !== undefined && c.literal !== '') {
772
+ leaf.BrowserTextValueLeft = {
773
+ formulaType: 'string', name: String(c.literal), businessId: genSfId(),
774
+ selectType: '-1', id: genSfId(), type: '1', value: String(c.literal), fieldType: 'browser',
775
+ };
776
+ }
777
+ return leaf;
778
+ });
779
+ const tree = {
780
+ sourceId: '-1', source: 8, relation: 1,
781
+ expressionId: genSfId(), mapBaseId: genSfId(), conditionId: genSfId(), mapId: genSfId(),
782
+ // 根 AND 下直接放叶子;外面再套分组会让每个条件多一层括号
783
+ childrens: leaves,
784
+ };
785
+ try {
786
+ const mb = await p.client.get(`${p.baseUrl}/api/bs/esb/setting/condition/getConditionSet`);
787
+ const mapBaseId = typeof mb?.data === 'string'
788
+ ? mb.data
789
+ : String(mb?.data?.mapBaseId || mb?.data?.conditionKey || '');
790
+ if (!mapBaseId)
791
+ throw new Error('getConditionSet 未返回 mapBaseId');
792
+ tree.mapBaseId = mapBaseId;
793
+ stripTemporaryConditionIds(tree);
794
+ const resp = await p.client.post(`${p.baseUrl}/api/bs/esb/setting/condition/saveCondition`, tree);
795
+ const data = resp?.data || {};
796
+ if (resp?.code !== 200 || resp?.status === false || data?.result !== true || data?.haveData !== true
797
+ || !data.conditionKey || !data.conditionId || !data.mapId) {
798
+ throw new Error(`saveCondition 返回异常: ${resp?.msg || ''} code=${resp?.code}`);
799
+ }
800
+ const persisted = await p.client.get(`${p.baseUrl}/api/bs/esb/setting/condition/getExpressionBean?conditionId=${data.conditionId}`);
801
+ const storedTree = buildConditionDisplayTree(persisted?.data || {});
802
+ storedTree.sourceId = '-1';
803
+ storedTree.mapBaseId = String(data.conditionKey);
804
+ storedTree.conditionId = String(data.conditionId);
805
+ storedTree.mapId = String(data.mapId);
806
+ storedTree.source = 8;
807
+ storedTree.relation = Number(storedTree.relation) === 2 ? 2 : 1;
808
+ return {
809
+ conditionId: String(data.conditionId),
810
+ conditionDetail: {
811
+ conditionId: String(data.conditionId),
812
+ conditionCn: String(data.conditionCn || ''),
813
+ mapBaseId: String(data.conditionKey),
814
+ mapId: String(data.mapId),
815
+ sourceIds: Array.isArray(data.sourceIds) ? data.sourceIds.map(String) : [p.eqWId],
816
+ conditionDataJson: JSON.stringify({
817
+ code: 200, msg: resp?.msg || '接口返回成功', status: resp?.status !== false, fail: false, data: storedTree,
818
+ }),
819
+ },
820
+ };
821
+ }
822
+ catch (error) {
823
+ console.error(` ❌ 保存赋值前提失败: ${error?.message || error}`);
824
+ process.exit(1);
825
+ }
826
+ }
827
+ /**
828
+ * 改赋值前提:它只存在于 ESB 设计的 Output 节点,所以要读回设计 → 改 Output → 重新 saveDesign。
829
+ * `disable` 时清掉三个条件键;否则先保存新条件再回填。
830
+ */
831
+ async function updatePreconditionOrExit(p) {
832
+ const esbAppId = String(p.record?.dataSources?.[0]?.dataSourceId || '');
833
+ if (!esbAppId) {
834
+ console.error('这条联动没有关联的 ESB 应用,无法配置赋值前提');
835
+ process.exit(1);
836
+ }
837
+ const ver = await p.client.get(`${p.baseUrl}/api/bs/esb/setting/application/version/versionList/${esbAppId}`);
838
+ const list = Array.isArray(ver?.data) ? ver.data : [];
839
+ const sceneId = String(ver?.data?.activeVersion
840
+ || list.find((v) => v.active || v.status === 1 || v.isActive)?.id
841
+ || list[0]?.id || '');
842
+ if (!sceneId) {
843
+ console.error(`取不到 ESB 设计版本(appId=${esbAppId})`);
844
+ process.exit(1);
845
+ }
846
+ const dr = await p.client.get(`${p.baseUrl}/api/bs/esb/setting/flow/design/getDesignBySceneId/${sceneId}`);
847
+ if (dr?.code !== 200 || !dr?.data) {
848
+ console.error(`读取 ESB 设计失败: ${dr?.msg || '未知错误'}`);
849
+ process.exit(1);
850
+ }
851
+ const design = dr.data;
852
+ const output = (design.actions || []).find((a) => a.type === 'Output');
853
+ if (!output) {
854
+ console.error('ESB 设计里没有赋值节点');
855
+ process.exit(1);
856
+ }
857
+ if (p.disable) {
858
+ output.data.conditionEnable = false;
859
+ delete output.data.conditionId;
860
+ delete output.data.conditionDetail;
861
+ delete output.data.conditionInfo;
862
+ }
863
+ else {
864
+ const enquiry = (design.actions || []).find((a) => a.type === 'EnquiryForm');
865
+ const srcObjId = String(enquiry?.data?.dataSource?.id || '');
866
+ const srcFormName = String(enquiry?.data?.dataSource?.text || '');
867
+ if (!srcObjId || !enquiry?.wId) {
868
+ console.error('ESB 设计里找不到查询节点,无法定位前提字段');
869
+ process.exit(1);
870
+ }
871
+ const srcFields = await getFormFields(p.client, p.baseUrl, srcObjId, p.auth.userId, p.auth.tenantKey);
872
+ const selfFields = await getFormFields(p.client, p.baseUrl, p.objId, p.auth.userId, p.auth.tenantKey);
873
+ const conds = parsePreconditionListOrExit(p.precondition || [], srcFields, selfFields);
874
+ const info = await savePreconditionOrExit({
875
+ client: p.client, baseUrl: p.baseUrl, conds,
876
+ srcFormObjId: srcObjId, srcFormName, eqWId: String(enquiry.wId),
877
+ selfFormId: String(design.event?.data?.ownForm?.[0]?.id || p.record?.formId || ''),
878
+ selfFormName: String(design.event?.data?.ownForm?.[0]?.name || ''),
879
+ eventId: String(design.event?.wId || design.event?.id || ''),
880
+ esbAppId,
881
+ });
882
+ output.data.conditionEnable = true;
883
+ output.data.conditionInfo = info;
884
+ output.data.conditionId = info.conditionId;
885
+ output.data.conditionDetail = info.conditionDetail;
886
+ console.error(` 赋值前提: ${conds.map(c => `${c.field.fieldName} ${c.func} ${c.refField ? `@${c.refField.fieldName}` : c.literal ?? ''}`).join(' 且 ')}`);
887
+ }
888
+ const body = {
889
+ ...design,
890
+ ajaxUrl: '/api/bs/esb/setting/flow/design/saveDesign',
891
+ saveAndStart: true,
892
+ appId: esbAppId,
893
+ sceneId,
894
+ lightId: FIELD_LINKAGE_LIGHT_ID,
895
+ initData: '',
896
+ operateType: '',
897
+ reloadFormula: [],
898
+ };
899
+ const res = await p.client.post(`${p.baseUrl}${ESB_DESIGN_API}/saveDesign`, body, { ebbusinessid: esbAppId });
900
+ if (res?.code !== 200 || !res?.status) {
901
+ console.error(`保存 ESB 设计失败: ${res?.msg || '未知错误'}`);
902
+ process.exit(1);
903
+ }
904
+ }
905
+ async function addQuickLinkage(p) {
906
+ const { client, baseUrl, appId, objId, selfFormId, selfFormName, selfFields, selfDetails, trigger, monitorActions, effect, linkageState, detailExt, auth, opts, cmdOpts } = p;
907
+ if (!cmdOpts.sourceForm) {
908
+ console.error('快捷配置需要 --source-form <查询目标表 objId>');
909
+ process.exit(1);
910
+ }
911
+ if (cmdOpts.condition.length === 0) {
912
+ console.error('快捷配置需要至少一个 --condition');
913
+ process.exit(1);
914
+ }
915
+ const { formName: srcFormName } = await getFormId(client, baseUrl, appId, cmdOpts.sourceForm);
916
+ const srcFields = await getFormFields(client, baseUrl, cmdOpts.sourceForm, auth.userId, auth.tenantKey);
917
+ const condList = cmdOpts.condition.map(expr => {
918
+ const c = parseConditionExpr(expr, srcFields);
919
+ const refField = c.literal && c.literal.startsWith('@') ? findFieldId(selfFields, c.literal.slice(1)) : undefined;
920
+ return { field: c.field, func: c.func, literal: refField ? undefined : c.literal, range: c.range, refField };
921
+ });
922
+ const assigns = cmdOpts.assign.map(parseAssignExpr);
923
+ const assignPairs = assigns.map(a => {
924
+ const t = splitAssignTarget(a.target);
925
+ const srcField = findFieldId(srcFields, a.src);
926
+ if (!t.table)
927
+ return { srcField, targetField: findFieldId(selfFields, t.field) };
928
+ const detail = selfDetails.find(d => d.name === t.table);
929
+ if (!detail) {
930
+ console.error(`明细表 "${t.table}" 未找到。可用: ${selfDetails.map(d => d.name).join('、') || '(本表没有明细表)'}`);
931
+ process.exit(1);
932
+ }
933
+ return { srcField, targetField: findFieldId(detail.fields, t.field), subForm: detail };
934
+ });
935
+ // 明细行依据:用户指定,缺省取该表第一个赋值的源字段(设计器里「依据值本身」那种配置)
936
+ const basis = new Map();
937
+ for (const expr of cmdOpts.basis || []) {
938
+ const i = expr.indexOf('=');
939
+ if (i <= 0) {
940
+ console.error(`--basis 格式错误: ${expr}(应为 明细表名=源表字段名)`);
941
+ process.exit(1);
942
+ }
943
+ const tableName = expr.slice(0, i).trim();
944
+ const detail = selfDetails.find(d => d.name === tableName);
945
+ if (!detail) {
946
+ console.error(`明细表 "${tableName}" 未找到`);
947
+ process.exit(1);
948
+ }
949
+ basis.set(detail.id, findFieldId(srcFields, expr.slice(i + 1).trim()));
950
+ }
951
+ for (const a of assignPairs) {
952
+ if (a.subForm && !basis.has(a.subForm.id))
953
+ basis.set(a.subForm.id, a.srcField);
954
+ }
955
+ const queryNames = cmdOpts.queryFields
956
+ ? cmdOpts.queryFields.split(',').map(s => s.trim()).filter(Boolean)
957
+ : [];
958
+ const queryFieldList = [...new Set([
959
+ ...queryNames,
960
+ ...assigns.map(a => a.src),
961
+ ...[...basis.values()].map((f) => f.fieldName),
962
+ ])];
963
+ const queryFields = queryFieldList.map(n => findFieldId(srcFields, n));
964
+ if (queryFields.length === 0) {
965
+ console.error('需要 --query-fields 或 --assign 指定查询字段');
966
+ process.exit(1);
967
+ }
968
+ // orgId:ESB app 必须归属机构,否则 saveDesign 失败
969
+ const formRes = await client.post(`${baseUrl}/api/ebuilder/form/form/formmanage/getForm?apid=${appId}`, { module: 'ebuilderform', form: { id: selfFormId }, baseSettingPartType: 'basic', customParam: { appId, objId } }, { ebbusinessid: selfFormId });
970
+ const orgId = String(formRes?.data?.form?.orgId || '');
971
+ const condDesc = condList.map(c => `${c.field.fieldName} ${c.func} ${c.range ? c.range.join('~') : (c.refField ? `@${c.refField.fieldName}` : c.literal ?? '')}`).join(' 且 ');
972
+ const linkageName = cmdOpts.name || `${selfFormName}.${trigger || '联动'}→${srcFormName}.${condList[0].field.fieldName}`;
973
+ console.error(` 联动: ${trigger || '(表单级触发)'} → 查 ${srcFormName}: ${condDesc}`);
974
+ console.error(` 赋值: ${assignPairs.map(a => `${a.srcField.fieldName}→${a.targetField.fieldName}`).join(', ')}`);
975
+ // 1. ESB app
976
+ const appRes = await client.post(`${baseUrl}${ESB_APP_API}/save`, { id: genSfId(), name: linkageName, canDelete: false, lightId: FIELD_LINKAGE_LIGHT_ID, initData: '', orgId }, { ebbusinessid: appId });
977
+ if (appRes?.code !== 200 || !appRes?.status) {
978
+ console.error(`建 ESB app 失败: ${appRes?.msg}`);
979
+ process.exit(1);
980
+ }
981
+ const esbAppId = String(appRes?.data?.id || '');
982
+ const sceneId = String(appRes?.data?.activeVersion || '');
983
+ console.error(` ESB app: ${esbAppId} scene: ${sceneId}`);
984
+ // 2. saveDesign
985
+ const design = buildQuickSaveDesign({
986
+ esbAppId, sceneId, lightId: FIELD_LINKAGE_LIGHT_ID, appName: linkageName,
987
+ selfFormId, selfFormName, appId, selfFields,
988
+ srcFormObjId: cmdOpts.sourceForm, srcFormName,
989
+ conditions: condList,
990
+ queryFields, assigns: assignPairs,
991
+ details: selfDetails, basis,
992
+ });
993
+ if (cmdOpts.precondition.length > 0) {
994
+ const conds = parsePreconditionListOrExit(cmdOpts.precondition, srcFields, selfFields);
995
+ const info = await savePreconditionOrExit({
996
+ client, baseUrl, conds,
997
+ srcFormObjId: String(cmdOpts.sourceForm), srcFormName,
998
+ eqWId: String(design.actions[0].wId),
999
+ selfFormId, selfFormName, eventId: String(design.event.id), esbAppId,
1000
+ });
1001
+ design.actions[1].data.conditionEnable = true;
1002
+ design.actions[1].data.conditionInfo = info;
1003
+ // 设计器报文在 Output.data 上还平铺了这两个键,只发 conditionInfo 平台不会落库
1004
+ design.actions[1].data.conditionId = info.conditionId;
1005
+ design.actions[1].data.conditionDetail = info.conditionDetail;
1006
+ console.error(` 赋值前提: ${conds.map(c => `${c.field.fieldName} ${c.func} ${c.refField ? `@${c.refField.fieldName}` : c.literal ?? ''}`).join(' 且 ')}`);
1007
+ }
1008
+ const designRes = await client.post(`${baseUrl}${ESB_DESIGN_API}/saveDesign`, design, { ebbusinessid: esbAppId });
1009
+ if (designRes?.code !== 200 || !designRes?.status) {
1010
+ console.error(`saveDesign 失败: ${designRes?.msg}`);
1011
+ process.exit(1);
1012
+ }
1013
+ console.error(' ESB 设计已保存(1 查询 + 1 赋值)');
1014
+ // 3. saveFormDataLinkage
1015
+ const linkagePayload = {
1016
+ formId: selfFormId,
1017
+ fdEffect: buildFdEffect(selfFormId, effect),
1018
+ linkageModule: 'ebuilderform', linkageName, linkageState, linkageType: 'template',
1019
+ linkageExt: buildLinkageExt({ ...detailExt, effectContent: '' }),
1020
+ monitorActions,
1021
+ dataSources: [{
1022
+ menuKey: '1', sourceName: '联动设置1', linkageType: 'esb', dataMappings: [],
1023
+ sourceEsb: { configType: 'SIMPLE', parameters: assignPairs.map(a => ({ targetField: String(a.targetField.fieldId), targetName: `${a.subForm ? `${a.subForm.name}.` : ''}${a.targetField.fieldName}` })) },
1024
+ dataSourceId: esbAppId, dataSourceName: `${linkageName}-联动设置1`,
1025
+ }],
1026
+ needSqlCompress: 1, customParam: { appId, objId },
1027
+ };
1028
+ const linkRes = await client.post(`${baseUrl}${LINKAGE_API}/saveFormDataLinkage?apid=${appId}`, linkagePayload, { ebbusinessid: selfFormId });
1029
+ if (linkRes?.code !== 200 || !linkRes?.status) {
1030
+ console.error(`saveFormDataLinkage 失败: ${linkRes?.msg}`);
1031
+ process.exit(1);
1032
+ }
1033
+ const linkageId = String(linkRes?.data?.id || '');
1034
+ console.error(` 联动已绑定: ${linkageId}`);
1035
+ // 4. preCheck + 5. 回读
1036
+ await client.post(`${baseUrl}${LINKAGE_API}/preCheck?apid=${appId}`, { module: 'ebuilderform', formId: selfFormId, linkageIds: [linkageId], customParam: { appId, objId } }, { ebbusinessid: selfFormId });
1037
+ const rb = await client.post(`${baseUrl}${LINKAGE_API}/queryById?apid=${appId}`, { id: linkageId, formId: selfFormId, module: 'ebuilderform', customParam: { appId, objId } }, { ebbusinessid: selfFormId });
1038
+ const ds = (rb?.data?.dataSources || [])[0] || {};
1039
+ const inF = (ds.inFields || []).map((f) => f.id).join(',');
1040
+ const outF = (ds.outFields || []).map((f) => `${f.content}(${f.id})`).join(',');
1041
+ console.log(opts.json
1042
+ ? JSON.stringify({ success: true, linkageId, esbAppId, inFields: inF, outFields: outF })
1043
+ : `字段联动已创建: [${linkageId}] ${trigger || '(表单级触发)'}→${assignPairs.map(a => a.srcField.fieldName).join(',')} in:${inF} out:${outF}`);
1044
+ }
1045
+ /** `明细表名.字段名` → 明细表 + 字段;没有点号就是主表字段。 */
1046
+ function splitAssignTarget(target) {
1047
+ const i = target.indexOf('.');
1048
+ if (i <= 0)
1049
+ return { field: target };
1050
+ return { table: target.slice(0, i).trim(), field: target.slice(i + 1).trim() };
1051
+ }
1052
+ /**
1053
+ * 解析 `源表字段:算子:值`。
1054
+ *
1055
+ * 算子表直接复用动作流 filter_rules:中文/符号别名(等于、包含、区间、为空…)→ 平台 func 码,
1056
+ * 并按字段类型族做白名单校验;区间写成 `起始~结束`。
1057
+ */
1058
+ function parseConditionExpr(expr, srcFields) {
1059
+ const i = expr.indexOf(':');
1060
+ if (i <= 0) {
1061
+ console.error(`--condition 格式错误: ${expr}(应为 源表字段:算子:值)`);
1062
+ process.exit(1);
1063
+ }
1064
+ const fieldName = expr.slice(0, i).trim();
1065
+ const rest = expr.slice(i + 1);
1066
+ const j = rest.indexOf(':');
1067
+ const rawFunc = (j < 0 ? rest : rest.slice(0, j)).trim();
1068
+ let value = j < 0 ? '' : rest.slice(j + 1).trim();
1069
+ const field = findFieldId(srcFields, fieldName);
1070
+ const family = conditionFieldFamily(String(field.fieldKey || 'Text'), String(field.fieldType || field.type || ''));
1071
+ const multiSelect = field.multiSelect === true || String(field.multiSelect) === 'true';
1072
+ let func;
1073
+ try {
1074
+ func = normalizeFilterOperator(rawFunc, family, { multiSelect });
1075
+ }
1076
+ catch (error) {
1077
+ console.error(error.message);
1078
+ process.exit(1);
1079
+ }
1080
+ let range;
1081
+ if (func === 'range') {
1082
+ const parts = value.split('~').map(s => s.trim());
1083
+ if (parts.length !== 2) {
1084
+ console.error(`区间条件写法: ${fieldName}:区间:起始值~结束值`);
1085
+ process.exit(1);
1086
+ }
1087
+ range = parts;
1088
+ }
1089
+ if (func === 'empty' || func === 'nempty')
1090
+ value = '';
1091
+ else if (value === '') {
1092
+ console.error(`--condition 格式错误: ${expr}`);
1093
+ process.exit(1);
1094
+ }
1095
+ if (range && value.startsWith('@')) {
1096
+ console.error('区间条件不支持引用本表字段');
1097
+ process.exit(1);
1098
+ }
1099
+ return { field, func, literal: value, range };
1100
+ }
1101
+ function parseAssignExpr(expr) {
1102
+ const i = expr.indexOf('=');
1103
+ if (i <= 0 || i === expr.length - 1) {
1104
+ console.error(`--assign 格式错误: ${expr}(应为 源表查询字段=本表目标字段)`);
1105
+ process.exit(1);
1106
+ }
1107
+ return { src: expr.slice(0, i).trim(), target: expr.slice(i + 1).trim() };
1108
+ }
1109
+ function fieldTypeOf(componentKey) {
1110
+ const k = String(componentKey || '').toLowerCase();
1111
+ if (k.includes('date'))
1112
+ return 'Date';
1113
+ if (/number|int|decimal|float|money|percent/.test(k))
1114
+ return 'Number';
1115
+ return 'String';
1116
+ }
1117
+ function dbFieldTypeOf(componentKey) {
1118
+ const t = fieldTypeOf(componentKey);
1119
+ return t === 'Date' ? 'DATE' : t === 'Number' ? 'NUMBER' : 'STRING';
1120
+ }
1121
+ /** 选项/关联类字段回读时要带名称(与设计器一致);纯文本/数字/日期不带 */
1122
+ function parseMarkOf(componentKey) {
1123
+ return /select|radio|checkbox|browser|ebuilder|employee|department/i.test(String(componentKey || ''));
1124
+ }
1125
+ export function buildQuickSaveDesign(p) {
1126
+ const eventId = genSfId();
1127
+ const eqWId = genSfId();
1128
+ const filterKey = String(Date.now());
1129
+ const selfFormFields = p.selfFields.filter((f) => /^\d+$/.test(String(f.fieldId))).map((f) => ({
1130
+ id: f.fieldId, orderNum: 1, paramName: f.dataKey || f.fieldKey || '', showName: f.fieldName,
1131
+ paramType: 'string', multipleSelect: f.multiSelect === true || f.multiSelect === 'true', componentKey: f.fieldKey || '', required: false,
1132
+ }));
1133
+ // 多个条件在同一个 filterInput 下用 datas 数组表达,relationship=1 为「且」。
1134
+ const datas = p.conditions.map(c => {
1135
+ const cf = c.field;
1136
+ const cfId = String(cf.fieldId);
1137
+ const cComp = String(cf.fieldKey || 'Text');
1138
+ let conditions;
1139
+ if (c.refField) {
1140
+ const rf = c.refField;
1141
+ const rfId = String(rf.fieldId);
1142
+ const filterValue = {
1143
+ paramKey: `${p.selfFormId}.${rfId}`, paramName: rfId, showName: String(rf.fieldName),
1144
+ paramType: 'string', dataType: 'node', arrs: false, paramTypeString: 'STRING', dataTypeSting: 'NODE',
1145
+ paramId: rfId, name: String(rf.fieldName), source: eventId,
1146
+ value: `FormData.${p.selfFormId}.${rfId}`, type: '3', formulaType: 'string',
1147
+ frontId: normalizeNumericFrontId(rfId, '字段联动 FormulaBean.frontId'),
1148
+ config: {
1149
+ paramKey: `${p.selfFormId}.${rfId}`, paramType: 'string',
1150
+ parentName: `${p.selfFormName}.${rf.fieldName}`, newParentName: `${p.selfFormName}.${rf.fieldName}`,
1151
+ comId: eventId, isMultCom: false, tableName: '表单数据',
1152
+ fieldInfo: { tablePrimaryKey: 'FormData', paramKey: `${p.selfFormId}.${rfId}` },
1153
+ },
1154
+ applicationId: p.esbAppId, fieldType: 'string',
1155
+ };
1156
+ conditions = { func: c.func, value: filterValue, text: String(rf.fieldName), isEsb: true, esbAssign: { wId: eqWId, textarea: false, withoutDftNum: true } };
1157
+ }
1158
+ else {
1159
+ const nullary = c.func === 'empty' || c.func === 'nempty';
1160
+ conditions = {
1161
+ func: c.func,
1162
+ text: nullary ? '' : String(c.literal ?? ''),
1163
+ value: nullary ? '' : (c.range ?? c.literal),
1164
+ type: '',
1165
+ isEsb: false,
1166
+ };
1167
+ }
1168
+ return {
1169
+ isParent: false, parentNode: filterKey, id: cfId, fieldName: `field_${cfId}`,
1170
+ fieldType: fieldTypeOf(cComp), optionType: '', text: String(cf.fieldName), objId: p.srcFormObjId,
1171
+ compType: cComp, type: 'condition', conditions,
1172
+ multiSelect: cf.multiSelect === true || cf.multiSelect === 'true' ? 'true' : 'false',
1173
+ formInfo: { fieldId: cfId }, originBrowserType: '', module: 'ebuilderform', mainField: true, subTableId: '',
1174
+ formatType: '4', dbFieldType: dbFieldTypeOf(cComp), key: genSfId(), config: { fieldId: cfId },
1175
+ };
1176
+ });
1177
+ const FUNC_CN = {
1178
+ eq: '等于', neq: '不等于', gt: '大于', gte: '大于等于', lt: '小于', lte: '小于等于',
1179
+ contains: '包含', uncontains: '不包含', startWith: '开头包含', unStartWith: '开头不包含',
1180
+ endWith: '结尾包含', unEndWith: '结尾不包含', range: '区间', containedWith: '被包含于',
1181
+ aggregate: '属于', unaggregate: '不属于', empty: '为空', nempty: '不为空',
1182
+ };
1183
+ const describe = (c) => {
1184
+ const cn = FUNC_CN[c.func] || '等于';
1185
+ if (c.func === 'empty' || c.func === 'nempty')
1186
+ return `${c.field.fieldName} ${cn}`;
1187
+ if (c.range)
1188
+ return `${c.field.fieldName} ${cn} '${c.range[0]}' ~ '${c.range[1]}'`;
1189
+ return `${c.field.fieldName} ${cn} '${c.refField ? c.refField.fieldName : c.literal}'`;
1190
+ };
1191
+ const rootStr = `( ${p.conditions.map(describe).join(' 且 ')} )`;
1192
+ const enquiryAction = {
1193
+ id: eqWId, wId: eqWId, nodeType: 'Normal', comType: 'EnquiryForm', type: 'EnquiryForm',
1194
+ previousId: eventId, parentId: '0', name: '设置查询数据', isAdd: true, isOpen: false, attr: { icon: 'Icon-Data-preprocessing' },
1195
+ data: {
1196
+ currentApplication: p.esbAppId,
1197
+ person: { type: '8', name: '', value: `textarea#${genSfId()}#`, formulaType: 'string', applicationId: p.esbAppId, config: { paramType: 'string', switchType: 'assign' }, childs: [{ id: genSfId(), type: '9', name: '{userid}', value: '{userid}', fieldType: 'string', formulaType: 'string', config: { paramType: 'string' }, applicationId: p.esbAppId }] },
1198
+ conditionFormula: '',
1199
+ dataSource: { id: p.srcFormObjId, text: p.srcFormName, type: 'LOGIC', groupId: 'weaver-ebuilder-form-service', isPhysical: true, usage: 'all', detailTable: false, objType: 'physical', module: 'ebuilder', appId: p.appId, isFormModuleSelected: true, enquiryId: -1 },
1200
+ filterInput: { key: filterKey, relationship: '1', isParent: true, isNewFilter: true, parentNode: '', datas, version: 1, filterIsNull: false, rootStr },
1201
+ authorityFlag: '0', opType: 'list',
1202
+ queryFields: p.queryFields.map(f => ({
1203
+ id: `field_${f.fieldId}`, content: String(f.fieldName), parseMark: parseMarkOf(f.fieldKey),
1204
+ fieldGroup: { name: p.srcFormName, id: p.srcFormObjId }, formId: p.srcFormObjId,
1205
+ })),
1206
+ type: 'EventButton', applicationId: p.esbAppId,
1207
+ },
1208
+ branchs: [], multKey: '', multName: '', ignoreFlowCheck: true,
1209
+ };
1210
+ const outWId = genSfId();
1211
+ const mainTableId = genSfId();
1212
+ const baseFormulaValue = (sf) => {
1213
+ const sid = String(sf.fieldId);
1214
+ const paramKey = `${p.srcFormObjId}[].field_${sid}`;
1215
+ return {
1216
+ paramKey, paramName: `field_${sid}`, showName: String(sf.fieldName), paramType: 'string',
1217
+ dataType: 'attribute', arrs: false, paramTypeString: 'STRING', dataTypeSting: 'ATTRIBUTE',
1218
+ formulaId: '0', name: String(sf.fieldName), source: eqWId,
1219
+ value: `FormData.${p.srcFormObjId}[${genSfId()}].field_${sid}`, type: '3', formulaType: 'string',
1220
+ config: {
1221
+ paramKey, paramType: 'string',
1222
+ parentName: `${p.srcFormName}[].${sf.fieldName}`, newParentName: `${p.srcFormName}[].${sf.fieldName}`,
1223
+ comId: eqWId, isMultCom: false, tableName: '表单数据',
1224
+ fieldInfo: { tablePrimaryKey: 'FormData', paramKey }, switchType: 'assign',
1225
+ },
1226
+ switchType: 'assign',
1227
+ };
1228
+ };
1229
+ /** 明细字段被赋的源字段正好是「依据值」时,设计器存的是 esbAssignSelf。 */
1230
+ const buildAssignField = (a, tableId, basisField) => {
1231
+ const sf = a.srcField;
1232
+ const tf = a.targetField;
1233
+ const isBasisSelf = !!basisField && String(basisField.fieldId) === String(sf.fieldId);
1234
+ if (a.subForm && isBasisSelf) {
1235
+ const sid = String(sf.fieldId);
1236
+ const paramKey = `${p.srcFormObjId}[].field_${sid}`;
1237
+ return {
1238
+ id: genSfId(), paramName: '', showName: '', paramType: 'string', isRequired: false,
1239
+ fieldComments: '', skipNull: '1', assignFieldId: String(tf.fieldId),
1240
+ fieldPath: `${tableId}.${tf.fieldId}`, fieldType: String(tf.fieldKey || 'Text'), switchType: 'sub',
1241
+ formulaValue: {
1242
+ id: genSfId(), name: `${sf.fieldName}(依据值本身)`, value: 'esbAssignSelf', type: '10',
1243
+ fieldType: 'string', formulaType: 'string', applicationId: p.esbAppId, switchType: 'sub',
1244
+ config: {
1245
+ originValue: 'esbAssignSelf', switchType: 'sub', id: 'esbAssignSelf',
1246
+ content: `${sf.fieldName}(依据值本身)`, source: eqWId, frontId: genSfId(),
1247
+ value: `FormData.${p.srcFormObjId}[].field_${sid}`, paramKey,
1248
+ config: baseFormulaValue(sf).config, level: 0, basisType: 'formSetting',
1249
+ },
1250
+ },
1251
+ };
1252
+ }
1253
+ return {
1254
+ id: genSfId(), paramName: '', showName: '', paramType: 'string', isRequired: false,
1255
+ fieldComments: '', skipNull: a.subForm ? '1' : '0', assignFieldId: String(tf.fieldId),
1256
+ fieldPath: `${tableId}.${tf.fieldId}`, fieldType: String(tf.fieldKey || 'Text'),
1257
+ ...(a.subForm ? { switchType: 'sub' } : {}),
1258
+ formulaValue: baseFormulaValue(sf),
1259
+ };
1260
+ };
1261
+ const buildBasisValue = (field) => {
1262
+ const fid = String(field.fieldId);
1263
+ const paramKey = `${p.srcFormObjId}[].field_${fid}`;
1264
+ return {
1265
+ id: genSfId(), deleteType: 0, paramKey, paramName: `field_${fid}`, showName: String(field.fieldName),
1266
+ paramType: 'string', dataType: 'attribute', arrs: false, required: false, description: `field_${fid}`,
1267
+ paramTypeString: 'STRING', dataTypeSting: 'ATTRIBUTE', formulaId: '0',
1268
+ hideParamNameInSelect: false, hideParam: false, readonlyParam: false, sensitiveFlag: false, newdata: false,
1269
+ parentName: `${p.srcFormName}[].${field.fieldName}`, name: String(field.fieldName),
1270
+ source: eqWId, value: `FormData.${p.srcFormObjId}[].field_${fid}`, type: '3', formulaType: 'string',
1271
+ frontId: genSfId(),
1272
+ config: {
1273
+ paramKey, paramType: 'string',
1274
+ parentName: `${p.srcFormName}[].${field.fieldName}`, newParentName: `${p.srcFormName}[].${field.fieldName}`,
1275
+ comId: eqWId, isMultCom: false, tableName: '表单数据',
1276
+ fieldInfo: { tablePrimaryKey: 'FormData', paramKey }, comType: 'EnquiryForm', parentComId: '0', switchType: 'assign',
1277
+ },
1278
+ applicationId: p.esbAppId, businessId: genSfId(), fieldType: 'string',
1279
+ };
1280
+ };
1281
+ const tableList = [{
1282
+ id: mainTableId, formId: p.selfFormId, showName: p.selfFormName, orderNum: 0,
1283
+ fields: p.assigns.filter(a => !a.subForm).map(a => buildAssignField(a, mainTableId)),
1284
+ main: true, isMain: true,
1285
+ }];
1286
+ for (const det of p.details) {
1287
+ const detAssigns = p.assigns.filter(a => a.subForm?.id === det.id);
1288
+ if (!detAssigns.length)
1289
+ continue;
1290
+ const detTableId = genSfId();
1291
+ const basisField = p.basis.get(det.id);
1292
+ tableList.push({
1293
+ id: detTableId, formId: det.id, showName: det.name, orderNum: 1,
1294
+ fields: detAssigns.map(a => buildAssignField(a, detTableId, basisField)),
1295
+ main: false, isMain: false,
1296
+ ...(basisField ? { basisValue: buildBasisValue(basisField) } : {}),
1297
+ });
1298
+ }
1299
+ const detailFormFields = p.details
1300
+ .filter(det => p.assigns.some(a => a.subForm?.id === det.id))
1301
+ .map((det, idx) => ({
1302
+ id: det.id, formId: det.id, showName: det.name, orderNum: idx + 1, main: false,
1303
+ fields: [
1304
+ { id: '5', orderNum: 0, paramName: 'rowId', showName: 'rowId', paramType: 'string', componentKey: 'Text' },
1305
+ ...det.fields.filter((f) => /^\d+$/.test(String(f.fieldId))).map((f, i) => ({
1306
+ id: f.fieldId, orderNum: i + 1, paramName: f.dataKey || '', showName: f.fieldName,
1307
+ paramType: 'string', multipleSelect: f.multiSelect === true || String(f.multiSelect) === 'true',
1308
+ componentKey: f.fieldKey || '', required: false,
1309
+ })),
1310
+ ],
1311
+ }));
1312
+ const outputAction = {
1313
+ id: outWId, wId: outWId, nodeType: 'Normal', comType: 'Output', type: 'Output',
1314
+ previousId: eqWId, parentId: '0', name: '设置赋值字段', isAdd: true, isOpen: false,
1315
+ componentName: '终止', attr: { icon: 'Icon-termination-1' }, isControl: true,
1316
+ data: {
1317
+ outputStatus: '1', pageAction: '0', reminder: '0', fixedData: [], triggerFlag: false, nextAction: false,
1318
+ customOutputData: '', currentApplication: p.esbAppId,
1319
+ fieldLinkCustomParamSetting: {
1320
+ customId: '', formType: 'output', businessModule: '',
1321
+ tableList,
1322
+ deleteTableIds: [], appId: p.esbAppId,
1323
+ },
1324
+ applicationId: p.esbAppId,
1325
+ },
1326
+ canDelete: false, options: { type: 'Output', name: '设置赋值字段', canDelete: false },
1327
+ sources: [{ wId: eqWId }], ignoreFlowCheck: true,
1328
+ };
1329
+ return {
1330
+ ajaxUrl: '/api/bs/esb/setting/flow/design/saveDesign', saveAndStart: true, appId: p.esbAppId, sceneId: p.sceneId,
1331
+ event: { id: eventId, wId: eventId, nodeType: 'Normal', comType: 'FieldLinkage', type: 'FieldLinkage', previousId: '0', parentId: '0', isAdd: true, isOpen: true, attr: { icon: 'Icon-trigger03' }, isControl: true, name: '字段联动触发', canEdit: false, canDelete: false, triggerType: 'SystemTrigger', data: { ownForm: [{ id: p.selfFormId, name: p.selfFormName }], ownModule: 'ebuilderform', ownApplication: [{ id: p.appId, name: p.appId }], formFields: [{ id: genSfId(), formId: p.selfFormId, showName: p.selfFormName, orderNum: 0, fields: selfFormFields, main: true }, ...detailFormFields] } },
1332
+ actions: [enquiryAction, outputAction],
1333
+ addIds: [], deleteActions: [], version: 0, delCheckMsg: [], addCheckMsg: [], assistLayer: '{"nodes":[],"layout":{}}', versionConfig: '{}', saveNewVersion: false, lightId: p.lightId, initData: '', secretKey: '', operateType: '', appName: p.appName,
1334
+ };
1335
+ }
322
1336
  //# sourceMappingURL=form-field-linkage.js.map