@lovrabet/rabetbase-cli 2.5.3 → 2.5.4-beta.2

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 (389) hide show
  1. package/README.md +11 -0
  2. package/lib/api/api-doc.js +1 -1
  3. package/lib/api/api-group.js +1 -1
  4. package/lib/api/fetch-model-list.js +1 -1
  5. package/lib/api/generate-api-file.js +1 -1
  6. package/lib/api/generate-sdk-config-file.js +1 -1
  7. package/lib/api/legacy-api-file.js +1 -1
  8. package/lib/api/model-registry-file.js +1 -1
  9. package/lib/api/model-registry-scaffold.js +1 -1
  10. package/lib/api/model-source.js +1 -1
  11. package/lib/auth/auth-server-ui.js +1 -1
  12. package/lib/auth/auth-server.js +1 -1
  13. package/lib/auth/constant.js +1 -1
  14. package/lib/auth/get-cookie.js +1 -1
  15. package/lib/auth/get-session-user.js +1 -1
  16. package/lib/auth/is-session-valid.js +1 -1
  17. package/lib/auth/login-success-html.js +1 -1
  18. package/lib/auth/logout.js +1 -1
  19. package/lib/cli-flags.js +1 -1
  20. package/lib/cli.js +1 -1
  21. package/lib/commands/api/generate.js +1 -1
  22. package/lib/commands/api/index.js +1 -1
  23. package/lib/commands/api/list.js +1 -1
  24. package/lib/commands/api/pull.js +1 -1
  25. package/lib/commands/api/shared.js +1 -1
  26. package/lib/commands/app/index.js +1 -1
  27. package/lib/commands/app/list.js +1 -1
  28. package/lib/commands/app/members-list.js +1 -1
  29. package/lib/commands/app/remote-directory.js +1 -1
  30. package/lib/commands/app/shared.js +1 -1
  31. package/lib/commands/app-config/delete.js +1 -1
  32. package/lib/commands/app-config/get.js +1 -1
  33. package/lib/commands/app-config/index.js +1 -1
  34. package/lib/commands/app-config/list.js +1 -1
  35. package/lib/commands/app-config/set.js +1 -1
  36. package/lib/commands/app-config/shared.js +1 -1
  37. package/lib/commands/auth/index.js +1 -1
  38. package/lib/commands/bff/create.js +1 -1
  39. package/lib/commands/bff/delete.js +1 -1
  40. package/lib/commands/bff/detail.js +1 -1
  41. package/lib/commands/bff/index.js +1 -1
  42. package/lib/commands/bff/list.js +1 -1
  43. package/lib/commands/bff/logs.js +1 -1
  44. package/lib/commands/bff/pull.js +1 -1
  45. package/lib/commands/bff/push.js +1 -1
  46. package/lib/commands/bff/status.js +1 -1
  47. package/lib/commands/cli-skill/index.js +1 -1
  48. package/lib/commands/cli-update.js +1 -1
  49. package/lib/commands/codegen/index.js +1 -1
  50. package/lib/commands/codegen/sdk.js +1 -1
  51. package/lib/commands/codegen/sql.js +1 -1
  52. package/lib/commands/common/app-registry.js +1 -1
  53. package/lib/commands/common/app-selector.js +1 -1
  54. package/lib/commands/common/async-task.js +1 -1
  55. package/lib/commands/common/dry-run.js +1 -1
  56. package/lib/commands/common/flags.js +1 -1
  57. package/lib/commands/common/local-file.js +1 -1
  58. package/lib/commands/common/validate.js +1 -1
  59. package/lib/commands/config/delete.js +1 -1
  60. package/lib/commands/config/get.js +1 -1
  61. package/lib/commands/config/index.js +1 -1
  62. package/lib/commands/config/init.d.ts +1 -1
  63. package/lib/commands/config/init.js +1 -1
  64. package/lib/commands/config/list.js +1 -1
  65. package/lib/commands/config/set.js +1 -1
  66. package/lib/commands/config/shared.js +1 -1
  67. package/lib/commands/dataset/batch-design.js +1 -1
  68. package/lib/commands/dataset/business-group-update.js +1 -1
  69. package/lib/commands/dataset/business-groups.js +1 -1
  70. package/lib/commands/dataset/capability.js +1 -1
  71. package/lib/commands/dataset/cross-relation-create.js +1 -1
  72. package/lib/commands/dataset/cross-relation-delete.js +1 -1
  73. package/lib/commands/dataset/cross-relation-list.js +1 -1
  74. package/lib/commands/dataset/cross-relation-shared.js +1 -1
  75. package/lib/commands/dataset/cross-relation-update.js +1 -1
  76. package/lib/commands/dataset/delete.js +1 -1
  77. package/lib/commands/dataset/detail.js +1 -1
  78. package/lib/commands/dataset/extend-update.js +1 -1
  79. package/lib/commands/dataset/field-restore.js +1 -1
  80. package/lib/commands/dataset/field-update.js +1 -1
  81. package/lib/commands/dataset/generate.js +1 -1
  82. package/lib/commands/dataset/index.js +1 -1
  83. package/lib/commands/dataset/list.js +1 -1
  84. package/lib/commands/dataset/operations.js +1 -1
  85. package/lib/commands/dataset/relation-audit.js +1 -1
  86. package/lib/commands/dataset/relation-create.js +1 -1
  87. package/lib/commands/dataset/relation-delete.js +1 -1
  88. package/lib/commands/dataset/relation-shared.js +1 -1
  89. package/lib/commands/dataset/relation-update.js +1 -1
  90. package/lib/commands/dataset/relations.js +1 -1
  91. package/lib/commands/dataset/rename.js +1 -1
  92. package/lib/commands/dataset/restore.js +1 -1
  93. package/lib/commands/dataset/user-deleted-field-list.js +1 -1
  94. package/lib/commands/db/analysis-batching.js +1 -1
  95. package/lib/commands/db/analyze-batch-plan.js +1 -1
  96. package/lib/commands/db/analyze-cancel.js +1 -1
  97. package/lib/commands/db/analyze-start.js +1 -1
  98. package/lib/commands/db/analyze-status.js +1 -1
  99. package/lib/commands/db/create.js +1 -1
  100. package/lib/commands/db/delete.js +1 -1
  101. package/lib/commands/db/detail.js +1 -1
  102. package/lib/commands/db/diff-refresh-start.js +1 -1
  103. package/lib/commands/db/diff-refresh-status.js +1 -1
  104. package/lib/commands/db/diff.js +1 -1
  105. package/lib/commands/db/index.js +1 -1
  106. package/lib/commands/db/list.js +1 -1
  107. package/lib/commands/db/shared.js +1 -1
  108. package/lib/commands/db/table-diff-shared.js +1 -1
  109. package/lib/commands/db/tables.js +1 -1
  110. package/lib/commands/db/test.js +1 -1
  111. package/lib/commands/db/update.js +1 -1
  112. package/lib/commands/deployment/index.js +1 -1
  113. package/lib/commands/deployment/sync-all.js +1 -1
  114. package/lib/commands/deployment/sync-jobs.js +1 -1
  115. package/lib/commands/deployment/sync-status.js +1 -1
  116. package/lib/commands/doctor.js +1 -1
  117. package/lib/commands/file/index.js +1 -1
  118. package/lib/commands/flow/create.js +1 -1
  119. package/lib/commands/flow/detail.js +1 -1
  120. package/lib/commands/flow/index.js +1 -1
  121. package/lib/commands/flow/list.js +1 -1
  122. package/lib/commands/flow/publish.js +1 -1
  123. package/lib/commands/flow/runtime-resources-shared.js +1 -1
  124. package/lib/commands/flow/runtime-role-list.js +1 -1
  125. package/lib/commands/flow/runtime-role-user-list.js +1 -1
  126. package/lib/commands/flow/runtime-user-search.js +1 -1
  127. package/lib/commands/flow/shared.d.ts +2 -0
  128. package/lib/commands/flow/shared.js +1 -1
  129. package/lib/commands/flow/update.js +1 -1
  130. package/lib/commands/flow/validate.js +1 -1
  131. package/lib/commands/instant-api-policy/current.js +1 -1
  132. package/lib/commands/instant-api-policy/index.js +1 -1
  133. package/lib/commands/instant-api-policy/init.js +1 -1
  134. package/lib/commands/instant-api-policy/publish.js +1 -1
  135. package/lib/commands/instant-api-policy/pull.js +1 -1
  136. package/lib/commands/instant-api-policy/revision.js +1 -1
  137. package/lib/commands/instant-api-policy/revisions.js +1 -1
  138. package/lib/commands/instant-api-policy/rollback.js +1 -1
  139. package/lib/commands/instant-api-policy/shared.js +1 -1
  140. package/lib/commands/instant-api-policy/validate.js +1 -1
  141. package/lib/commands/issue/index.js +1 -1
  142. package/lib/commands/issue/nudge.js +1 -1
  143. package/lib/commands/issue/report.js +1 -1
  144. package/lib/commands/issue/shared.js +1 -1
  145. package/lib/commands/kb/create.js +1 -1
  146. package/lib/commands/kb/delete.js +1 -1
  147. package/lib/commands/kb/detail.js +1 -1
  148. package/lib/commands/kb/index.js +1 -1
  149. package/lib/commands/kb/list.js +1 -1
  150. package/lib/commands/kb/search.js +1 -1
  151. package/lib/commands/kb/shared.js +1 -1
  152. package/lib/commands/kb/update.js +1 -1
  153. package/lib/commands/logs/index.js +1 -1
  154. package/lib/commands/menu/asset-update.js +1 -1
  155. package/lib/commands/menu/delete.js +1 -1
  156. package/lib/commands/menu/external-link-create.js +1 -1
  157. package/lib/commands/menu/external-link-update.js +1 -1
  158. package/lib/commands/menu/group-create.js +1 -1
  159. package/lib/commands/menu/group-update.js +1 -1
  160. package/lib/commands/menu/index.js +1 -1
  161. package/lib/commands/menu/list.js +1 -1
  162. package/lib/commands/menu/move.js +1 -1
  163. package/lib/commands/menu/regroup-start.js +1 -1
  164. package/lib/commands/menu/rename.js +1 -1
  165. package/lib/commands/menu/shared/compare-table.js +1 -1
  166. package/lib/commands/menu/shared/delete-plan.js +1 -1
  167. package/lib/commands/menu/shared/facts.js +1 -1
  168. package/lib/commands/menu/shared/index.js +1 -1
  169. package/lib/commands/menu/shared/inquirer.js +1 -1
  170. package/lib/commands/menu/shared/local-pages.js +1 -1
  171. package/lib/commands/menu/shared/logic.js +1 -1
  172. package/lib/commands/menu/shared/mutations.js +1 -1
  173. package/lib/commands/menu/shared/service.js +1 -1
  174. package/lib/commands/menu/shared/sync-core.js +1 -1
  175. package/lib/commands/menu/shared/update-core.js +1 -1
  176. package/lib/commands/menu/shared/valid-url.js +1 -1
  177. package/lib/commands/menu/sync.js +1 -1
  178. package/lib/commands/menu/visibility-update.js +1 -1
  179. package/lib/commands/notification/config-create.js +1 -1
  180. package/lib/commands/notification/config-delete.js +1 -1
  181. package/lib/commands/notification/config-list.js +1 -1
  182. package/lib/commands/notification/config-update.js +1 -1
  183. package/lib/commands/notification/index.js +1 -1
  184. package/lib/commands/notification/shared.js +1 -1
  185. package/lib/commands/ocr/index.js +1 -1
  186. package/lib/commands/page/create.js +1 -1
  187. package/lib/commands/page/custom/detail.js +1 -1
  188. package/lib/commands/page/custom/list.js +1 -1
  189. package/lib/commands/page/custom/publish.js +1 -1
  190. package/lib/commands/page/custom/shared.js +1 -1
  191. package/lib/commands/page/custom/syntax.js +1 -1
  192. package/lib/commands/page/custom/update.js +1 -1
  193. package/lib/commands/page/data-list-status.js +1 -1
  194. package/lib/commands/page/generate-start.js +1 -1
  195. package/lib/commands/page/generate-status.js +1 -1
  196. package/lib/commands/page/index.js +1 -1
  197. package/lib/commands/page/pull.js +1 -1
  198. package/lib/commands/page/push.js +1 -1
  199. package/lib/commands/page/relation-audit.js +1 -1
  200. package/lib/commands/page/restore.js +1 -1
  201. package/lib/commands/page/shared.js +1 -1
  202. package/lib/commands/page/sync.js +1 -1
  203. package/lib/commands/project/api-architecture-upgrade.js +1 -1
  204. package/lib/commands/project/create/enhanced-guided-create.js +1 -1
  205. package/lib/commands/project/create/format-elapsed.js +1 -1
  206. package/lib/commands/project/create/main.js +1 -1
  207. package/lib/commands/project/create/materialize-project-template.js +1 -1
  208. package/lib/commands/project/create/project-name.js +1 -1
  209. package/lib/commands/project/create/project-template-archive.js +1 -1
  210. package/lib/commands/project/create/project-template-path.js +1 -1
  211. package/lib/commands/project/create/use-copy-project-template.js +1 -1
  212. package/lib/commands/project/create/use-format-code.js +1 -1
  213. package/lib/commands/project/create/use-install-dependencies.js +1 -1
  214. package/lib/commands/project/domain-routing-sync.js +1 -1
  215. package/lib/commands/project/index.js +1 -1
  216. package/lib/commands/project/upgrade.js +1 -1
  217. package/lib/commands/registry.js +1 -1
  218. package/lib/commands/role/delete.js +1 -1
  219. package/lib/commands/role/detail.js +1 -1
  220. package/lib/commands/role/index.js +1 -1
  221. package/lib/commands/role/list.js +1 -1
  222. package/lib/commands/role/shared.js +1 -1
  223. package/lib/commands/role/update.js +1 -1
  224. package/lib/commands/role/user-add.js +1 -1
  225. package/lib/commands/role/user-remove.js +1 -1
  226. package/lib/commands/role/user-resolve.js +1 -1
  227. package/lib/commands/rule/get.js +1 -1
  228. package/lib/commands/rule/index.js +1 -1
  229. package/lib/commands/rule/list.js +1 -1
  230. package/lib/commands/rule/set.js +1 -1
  231. package/lib/commands/rule/shared.js +1 -1
  232. package/lib/commands/run/index.js +1 -1
  233. package/lib/commands/schema.js +1 -1
  234. package/lib/commands/sql/create.js +1 -1
  235. package/lib/commands/sql/delete.js +1 -1
  236. package/lib/commands/sql/detail.js +1 -1
  237. package/lib/commands/sql/exec.js +1 -1
  238. package/lib/commands/sql/index.js +1 -1
  239. package/lib/commands/sql/list.js +1 -1
  240. package/lib/commands/sql/pull.js +1 -1
  241. package/lib/commands/sql/push.js +1 -1
  242. package/lib/commands/sql/shared.js +1 -1
  243. package/lib/commands/sql/status.js +1 -1
  244. package/lib/commands/sql/validate.js +1 -1
  245. package/lib/commands/task/index.js +1 -1
  246. package/lib/commands/task/status.js +1 -1
  247. package/lib/commands/tenant/index.js +1 -1
  248. package/lib/commands/tenant/members-list.js +1 -1
  249. package/lib/commands/tenant/shared.js +1 -1
  250. package/lib/commands/user-account/dingding-sandbox-bind.js +1 -1
  251. package/lib/commands/user-account/index.js +1 -1
  252. package/lib/commands/workspace/add.js +1 -1
  253. package/lib/commands/workspace/index.js +1 -1
  254. package/lib/commands/workspace/remove.js +1 -1
  255. package/lib/config/domain-config.d.ts +1 -1
  256. package/lib/config/domain-config.js +1 -1
  257. package/lib/config/project-domain-routing.js +1 -1
  258. package/lib/config/region-config.js +1 -1
  259. package/lib/config/schema.d.ts +1 -1
  260. package/lib/config/schema.js +1 -1
  261. package/lib/constant/cdn.js +1 -1
  262. package/lib/constant/cli.js +1 -1
  263. package/lib/constant/defaults.js +1 -1
  264. package/lib/constant/domain.d.ts +4 -0
  265. package/lib/constant/domain.js +1 -1
  266. package/lib/constant/env.js +1 -1
  267. package/lib/constant/output.js +1 -1
  268. package/lib/constant/paths.js +1 -1
  269. package/lib/constant/region.d.ts +1 -1
  270. package/lib/constant/region.js +1 -1
  271. package/lib/constant/risk.js +1 -1
  272. package/lib/constant/routing-profile.d.ts +14 -1
  273. package/lib/constant/routing-profile.js +1 -1
  274. package/lib/context/app-resolver.d.ts +1 -0
  275. package/lib/context/app-resolver.js +1 -1
  276. package/lib/context/auth-resolver.js +1 -1
  277. package/lib/context/config-loader.js +1 -1
  278. package/lib/context.js +1 -1
  279. package/lib/core/alias-resolver.js +1 -1
  280. package/lib/core/api-client.js +1 -1
  281. package/lib/core/bff/config.js +1 -1
  282. package/lib/core/bff/file-system.js +1 -1
  283. package/lib/core/bff/hash.js +1 -1
  284. package/lib/core/bff/hook-directory.js +1 -1
  285. package/lib/core/bff/lock.js +1 -1
  286. package/lib/core/bff/utils.js +1 -1
  287. package/lib/core/cross-db-relation.js +1 -1
  288. package/lib/core/db-resolver.js +1 -1
  289. package/lib/core/flow-config.d.ts +11 -10
  290. package/lib/core/flow-config.js +1 -1
  291. package/lib/core/instant-api-policy/config.js +1 -1
  292. package/lib/core/kb-search-client.d.ts +7 -1
  293. package/lib/core/kb-search-client.js +1 -1
  294. package/lib/core/page/file-system.js +1 -1
  295. package/lib/core/page/hash.js +1 -1
  296. package/lib/core/page/lock.js +1 -1
  297. package/lib/core/page/lr-smart-jsx.js +1 -1
  298. package/lib/core/sql-index-auditor.js +1 -1
  299. package/lib/core/sql-sync/config.js +1 -1
  300. package/lib/core/sql-sync/file-system.js +1 -1
  301. package/lib/core/sql-sync/hash.js +1 -1
  302. package/lib/core/sql-sync/lock.js +1 -1
  303. package/lib/core/sql-sync/utils.js +1 -1
  304. package/lib/core/sql-validator.d.ts +5 -2
  305. package/lib/core/sql-validator.js +1 -1
  306. package/lib/errors.js +1 -1
  307. package/lib/framework/build-all-flags.js +1 -1
  308. package/lib/framework/error-output.js +1 -1
  309. package/lib/framework/explicit-yes.js +1 -1
  310. package/lib/framework/flags.js +1 -1
  311. package/lib/framework/help.js +1 -1
  312. package/lib/framework/index.js +1 -1
  313. package/lib/framework/output.js +1 -1
  314. package/lib/framework/response.js +1 -1
  315. package/lib/framework/runner-alias.js +1 -1
  316. package/lib/framework/runner.js +1 -1
  317. package/lib/framework/schema-export.js +1 -1
  318. package/lib/framework/supported-flags.js +1 -1
  319. package/lib/framework/types.js +1 -1
  320. package/lib/generated/build-info.d.ts +4 -4
  321. package/lib/generated/build-info.js +1 -1
  322. package/lib/generated/official-routing.d.ts +15 -3
  323. package/lib/generated/official-routing.js +1 -1
  324. package/lib/generated/routing-contract.d.ts +2 -2
  325. package/lib/generated/routing-contract.js +1 -1
  326. package/lib/help.js +1 -1
  327. package/lib/postinstall.js +1 -1
  328. package/lib/runtime/confirmation.js +1 -1
  329. package/lib/runtime/event.js +1 -1
  330. package/lib/runtime/index.js +1 -1
  331. package/lib/runtime/queue.js +1 -1
  332. package/lib/runtime/resolve.js +1 -1
  333. package/lib/skills/builtin-skill.js +1 -1
  334. package/lib/skills/main.js +1 -1
  335. package/lib/skills/npx-skills-add.d.ts +5 -0
  336. package/lib/skills/npx-skills-add.js +1 -1
  337. package/lib/skills/skill-presence.js +1 -1
  338. package/lib/telemetry/cli-command-trace.js +1 -1
  339. package/lib/telemetry/cli-help-trace.js +1 -1
  340. package/lib/telemetry/ensure-cli-otel-config.js +1 -1
  341. package/lib/telemetry/register-otel-exit-shutdown.js +1 -1
  342. package/lib/telemetry/send-cli-trace-log.js +1 -1
  343. package/lib/telemetry/send-platform-issue-collect-log.js +1 -1
  344. package/lib/utils/ai_config.js +1 -1
  345. package/lib/utils/apply-jq-filter.js +1 -1
  346. package/lib/utils/cdn-config.js +1 -1
  347. package/lib/utils/check-sdk-version.js +1 -1
  348. package/lib/utils/cli-version-check.js +1 -1
  349. package/lib/utils/cli-version-policy.js +1 -1
  350. package/lib/utils/config.js +1 -1
  351. package/lib/utils/entity-with-id.js +1 -1
  352. package/lib/utils/file-utils.js +1 -1
  353. package/lib/utils/guides-cdn.js +1 -1
  354. package/lib/utils/http-client.js +1 -1
  355. package/lib/utils/is-non-interactive.js +1 -1
  356. package/lib/utils/logger.js +1 -1
  357. package/lib/utils/params.js +1 -1
  358. package/lib/utils/platform.js +1 -1
  359. package/lib/utils/sleep.js +1 -1
  360. package/lib/utils/template-replacer.js +1 -1
  361. package/lib/utils/update-notice.js +1 -1
  362. package/lib/utils/version.js +1 -1
  363. package/lib/utils/with-active-cookie.js +1 -1
  364. package/lib/utils/write-cli-side-channel.js +1 -1
  365. package/package.json +1 -1
  366. package/skills/rabetbase/SKILL.md +31 -17
  367. package/skills/rabetbase/guides/approval-flow-development-workflow.md +33 -11
  368. package/skills/rabetbase/guides/best-practices.md +1 -1
  369. package/skills/rabetbase/guides/conflict-detection.md +44 -92
  370. package/skills/rabetbase/guides/custom-page-flow-sdk.md +642 -0
  371. package/skills/rabetbase/guides/custom-page-flow-timeline-display.md +289 -0
  372. package/skills/rabetbase/guides/custom-page-workflow.md +12 -3
  373. package/skills/rabetbase/guides/sql-creation-workflow.md +44 -26
  374. package/skills/rabetbase/guides/sql-mybatis.md +18 -49
  375. package/skills/rabetbase/guides/typescript-sdk.md +18 -0
  376. package/skills/rabetbase/knowledge/approval-flow/config-json-schema.md +22 -6
  377. package/skills/rabetbase/knowledge/components.md +34 -28
  378. package/skills/rabetbase/knowledge/custom-page/generation-standards.md +2 -0
  379. package/skills/rabetbase/references/rabetbase-config.md +6 -4
  380. package/skills/rabetbase/references/rabetbase-flow-commands.md +8 -4
  381. package/skills/rabetbase/references/rabetbase-flow-resources.md +3 -3
  382. package/skills/rabetbase/references/rabetbase-flow-runtime-boundary.md +2 -0
  383. package/skills/rabetbase/references/rabetbase-init.md +7 -5
  384. package/skills/rabetbase/references/rabetbase-kb.md +14 -4
  385. package/skills/rabetbase/references/rabetbase-page-custom-detail.md +3 -1
  386. package/skills/rabetbase/references/rabetbase-page-custom-list.md +3 -0
  387. package/skills/rabetbase/references/rabetbase-sql-push.md +5 -0
  388. package/skills/rabetbase/references/rabetbase-sql-validate.md +12 -6
  389. package/skills/rabetbase.manifest.json +5 -3
@@ -0,0 +1,642 @@
1
+ # 自定义页面 Flow SDK
2
+
3
+ 本指南约束 rabetbase 生成或修改的自定义页面如何通过页面运行时注入的 `@lovrabet/sdk` client,发起、查询和办理独立自定义页面工作流。
4
+
5
+ ## 适用范围
6
+
7
+ - 流程定义必须是 `INDEPENDENT_FLOW + CUSTOM_PAGE`。
8
+ - 页面承担流程发起、当前用户待办/已办/已发起查询、详情、审批、驳回、办理、转交、撤回、重提、退回、作废或抄送交互。
9
+ - 不适用于 `FORM_FLOW`、`PLATFORM_FORM`,也不用于页面直接设计或发布 FlowConfig。
10
+
11
+ 流程定义和发布仍由 `rabetbase flow validate/create/update/publish` 完成。本指南只描述生成到页面中的运行时调用。
12
+
13
+ ## 身份、应用与权限边界
14
+
15
+ 自定义页面从页面上下文获得已经初始化的 SDK client:
16
+
17
+ ```jsx
18
+ import { useSdkClient } from "@/context/app-context";
19
+
20
+ const client = useSdkClient();
21
+ const flow = client.flow();
22
+ ```
23
+
24
+ 遵守以下约束:
25
+
26
+ 1. 页面使用当前 Runtime 登录用户的 Cookie 会话。
27
+ 2. `appCode` 来自页面注入的 client。页面业务方法不接收 `appCode`,不要把它放进 `variables` 或 `formData`。
28
+ 3. `client.flow()` 不传 `operatorUserId`。不要在页面中保存或传递 AccessKey、Cookie、OpenAPI Token 或时间戳。
29
+ 4. SDK 自动把 `appCode` 放到普通 Flow POST 和自定义页面 POST 的 JSON body;`getReturnTargets()`、`markCcRead()` 所需的 query 参数也由 SDK 处理。
30
+ 5. Runtime 最终校验当前用户、租户、应用边界、任务办理人、流程状态和应用管理员权限。页面不能通过自定义参数扩大权限。
31
+ 6. `canHandle`、`canCancel`、`canWithdraw`、`canResubmit`、`canVoid`、`canReturn` 只用于控制页面交互,不能代替服务端校验。
32
+
33
+ 如果项目安装的 `@lovrabet/sdk` 没有无参数 `client.flow()` 或相关类型,停止生成调用并说明需要升级 SDK;不要回退到旧的 `client.flow(operatorUserId)` 或 Flow OpenAPI 示例。
34
+
35
+ ## 开发前确认
36
+
37
+ 1. 使用 `rabetbase flow list` 找到目标流程,以 `flow detail` 确认 `flowType=INDEPENDENT_FLOW`、`pageMode=CUSTOM_PAGE`、流程编码和发布状态。
38
+ 2. 明确当前页面是发起页、办理页、详情页、终态页还是工作台;导航用的 `startPath` / `APPROVAL.path` / `END.path` 必须来自已发布页面的完整 `runtimePageUrl`,但不参与权限和流程状态计算。
39
+ 3. 建立业务变量契约:变量名、类型、初始来源、更新节点、消费节点和是否用于列表查询。
40
+ 4. 对动态表单确认 `formDataVersion` 的来源和刷新时机。
41
+ 5. 对应用范围列表确认当前用户确实需要且具备应用管理员权限。
42
+
43
+ 不要编造 `flowCode`、`taskId`、`processInstanceId`、节点 ID 或用户 ID。流程和页面资源从当前 CLI 查询结果取得,运行时 ID 从 SDK 返回值取得。
44
+
45
+ ## 数据位置
46
+
47
+ | 字段 | 用途 | 示例 |
48
+ | --- | --- | --- |
49
+ | `formData` | 发起时提交完整业务表单 | 采购主题、分类、数量、预算、供应商、原因 |
50
+ | `formPatch` | 办理或重提时按顶层字段合并修改 `formData` | 补充供应商、最终金额、附件 |
51
+ | `variables` | 流程分支、精确查询和业务状态同步 | `businessId`、`departmentCode`、`purchaseStatus` |
52
+ | `variableKeys` | 限制查询响应中的 `businessVariables` | `["businessId", "purchaseStatus"]` |
53
+
54
+ - 待办和已办变量查询只使用普通业务标量做等值条件。
55
+ - 对象和数组可以作为流程变量传递,但不作为待办/已办精确查询条件。
56
+ - 不写入、删除或依赖 `approval_sys_*`、`approved` 等系统变量。
57
+ - 当前任务完成后,下一任务可能属于其他用户。不要用当前用户的 `listTodo()` 推断下一办理人。
58
+
59
+ `approve()`、`reject()`、`complete()` 和 `resubmit()` 都可以通过 `formPatch` 修改普通非动态自定义页面的表单数据。合并只发生在 `formData` 根级:未传字段保持原值,传入字段替换原值,`null` 明确设为空值,嵌套对象和数组整字段替换,不做深合并。普通表单不要求动态 schema,也不强制传 `formDataVersion`;动态表单遵守已发布 schema 的字段权限和版本校验,办理请求只提交 Runtime 返回的最新 `formDataVersion`,不传 schema,也不用客户端自造的业务版本代替。
60
+
61
+ `approve()`、`reject()`、`complete()` 的兼容调用可以只通过 `variables.formData` 提交完整表单数据;新页面优先使用 `formPatch` 表达局部修改。这三个方法的同一次请求不能同时传 `formPatch` 和 `variables.formData`,Runtime 会拒绝这种无法确定覆盖顺序的请求。`resubmit()` 不兼容 `variables.formData`,重提表单只能使用 `formPatch`。顶层 `variables` 中除 `formData` 外的字段仍按业务变量处理。
62
+
63
+ ## 方法选择
64
+
65
+ ### 查询
66
+
67
+ | 页面意图 | SDK 方法 | 参数 | 返回值 |
68
+ | --- | --- | --- | --- |
69
+ | 当前用户待办 | `listTodo(query?)` | `FlowVariableQuery` | `FlowPage<FlowCustomPageTaskItem>` |
70
+ | 应用范围待办 | `listAppTodo(query?)` | `FlowVariableQuery` | `FlowPage<FlowCustomPageTaskItem>` |
71
+ | 当前用户已办 | `listDone(query?)` | `FlowVariableQuery` | `FlowPage<FlowCustomPageTaskItem>` |
72
+ | 应用范围已办 | `listAppDone(query?)` | `FlowVariableQuery` | `FlowPage<FlowCustomPageTaskItem>` |
73
+ | 当前用户已发起 | `listSubmitted(query?)` | `FlowSubmittedQuery` | `FlowPage<FlowCustomPageSubmittedProcess>` |
74
+ | 应用范围已发起 | `listAppSubmitted(query?)` | `FlowSubmittedQuery` | `FlowPage<FlowCustomPageSubmittedProcess>` |
75
+ | 可发起流程 | `listIndependentFlows(query?)` | `FlowDefinitionQuery` | `FlowPage<FlowCustomPageDefinition>` |
76
+ | 任务详情 | `getTaskDetail(taskId, variableKeys?)` | `string, string[]?` | `FlowCustomPageTaskDetail` |
77
+ | 流程/当前任务详情 | `getProcessDetail(processInstanceId, variableKeys?)` | `string, string[]?` | `FlowCustomPageTaskDetail` |
78
+ | 当前任务别名 | `getCurrentTask(processInstanceId, variableKeys?)` | `string, string[]?` | `FlowCustomPageTaskDetail` |
79
+ | 时间线 | `getTimeline(processInstanceId)` | `string` | `FlowCustomPageTimeline` |
80
+ | 审批记录 | `getRecords(processInstanceId)` | `string` | `FlowRecords` |
81
+ | 可退回节点 | `getReturnTargets(taskId)` | `string` | `FlowReturnTarget[]` |
82
+ | 抄送列表 | `listCc(query?)` | `FlowCcQuery` | `FlowPage<FlowCcRecord>` |
83
+ | 抄送详情 | `getCcDetail(ccRecordId)` | `number \| string` | `FlowCustomPageCcDetail` |
84
+
85
+ `listAppTodo()`、`listAppDone()`、`listAppSubmitted()` 只用于应用管理员工作台。普通用户页面使用非 `App` 方法。
86
+
87
+ 待办、已办和任务详情中的 `path` 是流程定义中当前 `APPROVAL` 节点配置的完整运行态页面地址,类型为 `string`;页面按该地址导航。不要再从这些自定义页面任务响应中读取节点 `pageId`。可发起流程定义中的 `startPath` 是发起页的完整运行态地址;`END.path` 是流程定义中的终态导航元数据,不是任务路径。设计态 Skill 只允许使用 `page custom-detail` 确认为 `FORMAL` 的页面所返回的 `runtimePageUrl`。
88
+
89
+ 任务、任务详情和已发起列表中的 `detailUrl` 由 Runtime 使用相应节点 `path` 与流程实例 ID 生成,查询参数名固定为 `processId`。当 `path` 不含 query 时追加 `?processId=...`,已有 `?` 时追加 `&processId=...`;流程运行中使用当前 `APPROVAL.path`,流程正常结束后使用实际到达的 `END.path`。`path` 或流程实例 ID 缺失时 `detailUrl` 为空。
90
+
91
+ ## 返回对象字段语义与页面展示
92
+
93
+ 本节是页面生成 Agent 必须使用的固定响应契约,字段来自 Runtime Java DTO、查询投影 Mapper 和状态枚举。不能只根据 TypeScript 字段名自行猜测含义,也不能把整个响应对象直接 `JSON.stringify` 后当成正式页面。
94
+
95
+ 通用规则:
96
+
97
+ - 所有 `*Time` 都是毫秒时间戳;为空表示事件尚未发生或没有可展示时间。页面格式化为本地日期时间,不直接展示原始数字。
98
+ - `taskId`、`processInstanceId`、`flowCode`、`nodeKey` 等 ID 用于查询、导航、React `key` 和提交动作;默认不作为面向业务用户的主标题。
99
+ - 名称字段优先展示;名称为空时可回退到对应 ID,但要使用弱化样式,不能编造名称。
100
+ - `path` 是节点配置的运行态页面基地址;`detailUrl` 是 Runtime 已追加 `processId` 的可导航详情地址。存在 `detailUrl` 时直接使用,不要再次拼接 query。
101
+ - `businessVariables` 只包含调用时通过 `variableKeys` 请求的业务变量;未请求、变量不存在或被系统字段过滤时返回空对象。空对象不表示流程没有业务变量。
102
+ - `formData` 是流程保存的业务表单数据,应按当前业务字段契约渲染;不要把未知对象直接展开成面向终端用户的原始 JSON。
103
+ - `can*` 字段是当前登录用户在当前服务端状态下的按钮权限事实。按钮显隐和禁用以它们为准,不能在前端根据用户 ID、角色或状态字符串重新推导权限。
104
+ - 列表、详情、时间线和记录可能因权限或历史数据缺少可选字段。页面必须对 `null`、空字符串、空对象和空数组提供稳定空态。
105
+
106
+ ### 通用分页 `FlowPage<T>`
107
+
108
+ | 字段 | 语义 | 页面使用 |
109
+ | --- | --- | --- |
110
+ | `records` | 当前页记录;没有数据时为空数组 | 表格或卡片列表的数据源 |
111
+ | `currentPage` | 当前页码,从 1 开始 | 分页器当前页 |
112
+ | `pageSize` | 当前每页条数 | 分页器 page size |
113
+ | `totalCount` | 满足条件的总记录数 | 分页器 total 和统计文案 |
114
+ | `totalPages` | 总页数,由 `totalCount / pageSize` 向上取整 | 判断是否还有下一页;不要用当前记录数代替 |
115
+
116
+ ### 可发起流程 `FlowCustomPageDefinition`
117
+
118
+ | 字段 | 语义 | 页面使用 |
119
+ | --- | --- | --- |
120
+ | `flowCode` | 服务端生成的稳定流程编码 | 调用 `start()` 的必填值,不把 `flowName` 当编码 |
121
+ | `flowName` | 流程展示名称 | 发起入口卡片标题、下拉选项 label |
122
+ | `flowDesc` | 流程说明 | 卡片说明;为空时不渲染占位段落 |
123
+ | `version` | 当前可发起的已发布流程版本 | 可作为辅助版本信息,不参与前端选路 |
124
+ | `pageMode` | 页面模式;本入口固定面向 `CUSTOM_PAGE` | 通常不展示,用于诊断契约是否匹配 |
125
+ | `startPath` | 已配置的完整发起页运行态地址 | “发起”按钮导航目标;为空时不能猜 URL,应使用当前页面内置发起表单或显示未配置 |
126
+
127
+ ### 发起结果 `FlowCustomPageStartResponse`
128
+
129
+ | 字段 | 语义 | 页面使用 |
130
+ | --- | --- | --- |
131
+ | `flowCode` | 实际发起的流程编码 | 成功结果核对或埋点 |
132
+ | `processInstanceId` | 新流程实例 ID;幂等重放时是原实例 ID | 后续详情、时间线、记录和流程级动作的主键 |
133
+ | `idempotentReplay` | 本次请求是否命中了相同 `idempotencyKey` 的既有结果 | `true` 表示复用了原实例,不是新建了第二个实例,也不是失败 |
134
+
135
+ 发起成功后用 `processInstanceId` 读取服务端详情。不要从 `idempotentReplay=false` 推导流程已经到达哪个节点。
136
+
137
+ ### 待办/已办列表项 `FlowCustomPageTaskItem`
138
+
139
+ | 字段 | 语义 | 页面使用 |
140
+ | --- | --- | --- |
141
+ | `taskId` | 当前或历史人工任务 ID | 打开任务详情、同意、拒绝、办理、转交和退回时使用 |
142
+ | `taskName` | 人工任务展示名称 | 列表主标题或“当前环节”列 |
143
+ | `taskDefinitionKey` | 流程定义中的节点 ID | 稳定定位节点;不代替 `taskName` 展示 |
144
+ | `taskMode` | `APPROVAL` 或 `HANDLE` | `APPROVAL` 显示同意/拒绝;`HANDLE` 显示办理完成,不混用动作 |
145
+ | `path` | 当前 `APPROVAL` 节点配置的完整运行态页面地址 | 仅作页面基地址;打开具体实例优先使用 `detailUrl` |
146
+ | `detailUrl` | Runtime 基于 `path` 和 `processInstanceId` 生成的详情地址 | 行点击或“查看详情”导航;为空时留在当前页面并按 ID 查询详情 |
147
+ | `assignee` | 实际办理人用户 ID;候选任务可能为空 | 动作参数和诊断用途,默认不直接展示 |
148
+ | `assigneeName` | 实际办理人名称;用户解析失败时可为空 | “办理人”列;为空可回退 `assignee` |
149
+ | `handleMode` | 当前用户办理授权来源:`ASSIGNEE`、`CANDIDATE` 或 `APP_ADMIN`;已办或不可办理时可为空 | 可作为管理员代办提示;不能代替服务端权限校验 |
150
+ | `transferCandidates` | 当前节点允许转交的候选用户 | 只在数组非空且任务可办理时展示转交入口 |
151
+ | `processInstanceId` | 所属流程实例 ID | 读取流程详情、时间线和记录 |
152
+ | `flowCode` | 所属流程编码 | 筛选、辅助信息和埋点 |
153
+ | `flowName` | 所属流程名称 | 列表中的流程名称 |
154
+ | `initiatorUserId` | 发起人用户 ID | 稳定标识或筛选,不优先直接展示 |
155
+ | `initiatorUsername` | 发起人展示名称 | “发起人”列;为空时回退 `initiatorUserId` |
156
+ | `taskStatus` | 当前任务生命周期状态 | 状态标签;不能与 `processStatus` 混为一个状态 |
157
+ | `processStatus` | 整个流程实例状态 | 流程状态标签;拒绝结论需结合时间线的 `approvalResult` 判断 |
158
+ | `createTime` | 任务创建时间 | 待办到达时间或已办开始时间 |
159
+ | `endTime` | 任务结束时间;待办通常为空 | 已办完成时间;为空不显示“已完成” |
160
+ | `processStartTime` | 流程发起时间 | 列表的“发起时间” |
161
+ | `businessVariables` | 按 `variableKeys` 投影出的业务变量 | 展示业务单号、金额、部门等稳定摘要字段 |
162
+
163
+ `transferCandidates` 的元素字段固定为:
164
+
165
+ | 字段 | 语义 | 页面使用 |
166
+ | --- | --- | --- |
167
+ | `userId` | 候选用户 ID | `transfer()` / `batchTransfer()` 的 `targetUserId` |
168
+ | `userName` | 候选用户名称;解析失败时为空 | 转交选择器 label;为空时回退 `userId` |
169
+
170
+ ### 已发起列表项 `FlowCustomPageSubmittedProcess`
171
+
172
+ | 字段 | 语义 | 页面使用 |
173
+ | --- | --- | --- |
174
+ | `processInstanceId` | 流程实例 ID | 详情、时间线、记录、撤回、重提、撤销和作废的主键 |
175
+ | `flowCode` | 流程编码 | 筛选或辅助信息 |
176
+ | `flowName` | 流程名称 | 列表主标题 |
177
+ | `startTime` | 流程发起时间 | “发起时间”列 |
178
+ | `endTime` | 流程结束时间;运行中为空 | “完成时间”列 |
179
+ | `status` | 流程实例状态,语义同 `processStatus` | 状态标签 |
180
+ | `cancelReason` | 已结束且被撤销时的删除/撤销原因;其他情况通常为空 | 仅在 `CANCELLED` 等终止态按需展示 |
181
+ | `detailUrl` | 当前审批节点或实际到达 `END` 节点的详情地址 | “查看详情”导航;为空时按 `processInstanceId` 在当前页面读取详情 |
182
+ | `currentNodeNames` | 当前运行节点名称的去重快捷列表 | 简洁“当前环节”文案;详细展示使用 `currentNodes` |
183
+ | `currentNodes` | 当前真实运行节点摘要 | 并行节点、当前审批人和节点类型展示 |
184
+ | `nextNodes` | 根据已发布流程配置推演的下一节点摘要 | 只能作为“预计下一步”;条件分支或运行变量变化时不保证最终一定到达 |
185
+ | `businessVariables` | 按 `variableKeys` 投影出的业务变量 | 列表业务摘要 |
186
+
187
+ `currentNodes` / `nextNodes` 的元素字段固定为:
188
+
189
+ | 字段 | 语义 | 页面使用 |
190
+ | --- | --- | --- |
191
+ | `nodeKey` | 流程节点 ID | React key、诊断和节点定位 |
192
+ | `nodeName` | 节点展示名称 | 环节名称 |
193
+ | `nodeType` | 节点类型,例如 `APPROVAL`、`SCRIPT`、`NOTIFICATION`、`END` | 图标或节点类别标签 |
194
+ | `status` | 当前节点固定为 `RUNNING`,预计下一节点固定为 `PENDING` | 节点状态标签 |
195
+ | `approvers` | 审批节点的实际或预计审批人;非审批节点为空数组 | 审批人头像/名称组;预计值不能表述为已分配事实 |
196
+
197
+ ### 任务/流程详情 `FlowCustomPageTaskDetail`
198
+
199
+ | 字段 | 语义 | 页面使用 |
200
+ | --- | --- | --- |
201
+ | `taskId` | 当前或历史任务 ID;已结束流程按实例查询时可能为空 | 任务级动作只在非空且 `canHandle=true` 时使用 |
202
+ | `taskName` | 当前或历史任务名称 | 详情页当前环节标题 |
203
+ | `taskDefinitionKey` | 当前任务对应的流程节点 ID | 节点定位,不代替展示名称 |
204
+ | `taskMode` | `APPROVAL` 或 `HANDLE` | 决定展示同意/拒绝还是办理完成 |
205
+ | `path` | 当前任务节点的完整运行态页面基地址 | 导航元数据;优先使用 `detailUrl` |
206
+ | `detailUrl` | 已带 `processId` 的完整详情地址 | 分享当前应用内导航或从工作台跳转,不重复拼接 |
207
+ | `assignee` | 当前或历史实际办理人 ID | 动作和诊断用途 |
208
+ | `assigneeName` | 当前或历史实际办理人名称 | 办理人展示 |
209
+ | `processInstanceId` | 流程实例 ID | 所有流程级查询和动作的主键 |
210
+ | `flowCode` | 流程编码 | 辅助信息 |
211
+ | `flowName` | 流程名称 | 页面标题 |
212
+ | `initiatorUserId` | 发起人 ID | 稳定标识 |
213
+ | `initiatorUsername` | 发起人名称 | 发起人展示 |
214
+ | `taskCreateTime` | 当前/历史任务创建时间 | 当前环节开始时间 |
215
+ | `taskEndTime` | 当前/历史任务结束时间;运行中为空 | 当前环节完成时间 |
216
+ | `processStartTime` | 流程开始时间 | 发起时间 |
217
+ | `processEndTime` | 流程结束时间;运行中为空 | 流程完成时间 |
218
+ | `taskStatus` | 任务状态 | 当前环节状态标签 |
219
+ | `processStatus` | 流程实例状态 | 页面总状态标签 |
220
+ | `returnReason` | 撤回或退回发起人的原因;其他状态为空 | 非空时按 `processStatus` 显示“撤回原因”或“退回原因”,不能用 `cancelReason` 代替 |
221
+ | `canHandle` | 当前用户是否可办理当前任务 | 所有任务动作的总开关 |
222
+ | `handleMode` | 当前用户以办理人、候选人或应用管理员身份办理 | 管理员代办提示;为空表示当前不可办理 |
223
+ | `canCancel` | 当前用户是否可撤销并结束运行中流程 | 控制“撤销”按钮;与“撤回”不同 |
224
+ | `canWithdraw` | 当前用户是否可撤回流程并保留后续重提能力 | 控制“撤回”按钮 |
225
+ | `canResubmit` | 当前用户是否可重新提交已撤回或退回的流程 | 控制“重新提交”按钮 |
226
+ | `canVoid` | 当前用户是否可作废流程 | 控制高风险“作废”按钮 |
227
+ | `canReturn` | 当前任务是否可退回历史审批节点 | 控制“退回”按钮,并且必须使用 `returnTargets` |
228
+ | `returnTargets` | 当前允许退回的历史节点 | 退回选择器;不能传列表外的节点 ID |
229
+ | `approvalRound` | 当前审批轮次,从 1 开始;撤回/退回后重提可能增加 | 可展示“第 N 轮”,不要当流程版本 |
230
+ | `transferCandidates` | 当前节点允许转交的人 | 转交选择器 |
231
+ | `formData` | 当前流程保存的完整业务表单数据 | 详情主体或办理表单初始值;按业务 schema 展示 |
232
+ | `businessVariables` | 按 `variableKeys` 投影出的业务变量 | 业务状态、单号和分支上下文摘要 |
233
+ | `timeline` | 与 `getTimeline()` 相同结构的流程轨迹 | 时间线或流程图区域;为空时显示独立空态 |
234
+
235
+ `returnTargets` 的元素只有 `nodeId` 和 `nodeName`:页面显示 `nodeName`,提交 `returnTask()` 时使用 `nodeId`。自定义页面详情当前不返回 `formDataVersion`;如果动态表单办理要求乐观锁版本,必须通过相应 Runtime/SDK 契约读取最新版本,不能把客户端业务版本、`approvalRound`、流程版本或时间戳冒充为 `formDataVersion`。流程挂起时 `canHandle=false`;`canResubmit` 和 `canVoid` 仍分别按当前用户及流程状态的服务端权限返回,页面不要因为 `canHandle=false` 自行覆盖这些流程级权限。
236
+
237
+ ### 时间线 `FlowCustomPageTimeline`
238
+
239
+ 生成时间线 UI 时,必须继续阅读 [时间线展示指南](custom-page-flow-timeline-display.md),按“节点 → 办理人状态 → 操作记录”的纵向结构生成页面。中文页面必须显示“提交人 / 处理人 / 处理结果 / 处理说明 / 处理时间”等字段标题,不能只把姓名、状态和时间串起来。下表解释字段,展示指南规定标签、排序、文案、颜色、转签、多次执行和展开方式。
240
+
241
+ | 字段 | 语义 | 页面使用 |
242
+ | --- | --- | --- |
243
+ | `processInstanceId` | 流程实例 ID | 时间线归属和后续刷新 |
244
+ | `flowCode` | 流程编码 | 辅助信息 |
245
+ | `flowName` | 流程名称 | 时间线标题 |
246
+ | `startUserId` | 发起人 ID | 稳定标识 |
247
+ | `startUserName` | 发起人名称;解析失败时可为空 | 发起节点展示 |
248
+ | `startTime` | 流程开始时间 | 发起节点时间 |
249
+ | `endTime` | 流程结束时间;运行中为空 | 终态时间 |
250
+ | `status` | 流程实例状态 | 总状态标签 |
251
+ | `cancelReason` | 撤销/终止原因;非撤销场景通常为空 | 终止说明 |
252
+ | `returnReason` | 撤回或退回发起人的原因;其他状态为空 | 非空时按 `status` 显示“撤回原因”或“退回原因”,不能用 `cancelReason` 代替 |
253
+ | `canCancel` | 当前用户是否可撤销流程 | 控制撤销按钮 |
254
+ | `canWithdraw` | 当前用户是否可撤回流程 | 控制撤回按钮 |
255
+ | `canResubmit` | 当前用户是否可重新提交 | 控制重提按钮 |
256
+ | `canVoid` | 当前用户是否可作废流程 | 控制作废按钮 |
257
+ | `approvalRound` | 当前审批轮次,从 1 开始 | 时间线轮次提示 |
258
+ | `steps` | 按流程顺序组织的节点轨迹 | 纵向时间线;同一节点重复执行时按 `occurrence` 区分 |
259
+ | `flowDiagram` | 发布版本流程图及本实例执行状态 | 可视化流程图;为空时回退到 `steps`,不要自行从时间线猜连线 |
260
+
261
+ `steps[]` 字段:
262
+
263
+ | 字段 | 语义 | 页面使用 |
264
+ | --- | --- | --- |
265
+ | `order` | 当前轨迹项顺序 | 排序;不要用数组原始位置替代持久语义 |
266
+ | `nodeKey` | BPMN/FlowConfig 节点 ID | 节点定位 |
267
+ | `nodeName` | 节点名称 | 时间线标题 |
268
+ | `occurrence` | 同一节点在本实例中的第几次执行,从 1 开始 | 区分重复执行;`nodeName` 已可能带“(第二次)”,直接使用原名,不重复追加次数;会签/或签的多个任务仍属于同一次执行 |
269
+ | `nodeType` | `START`、`APPROVAL`、`CONDITION`、`SCRIPT`、`NOTIFICATION`、虚拟 `RESUBMIT` 或 `END` | 选择图标和展示模板;`RESUBMIT` 不属于原 BPMN 图 |
270
+ | `approvalMode` | 审批模式,例如单人、或签、会签的服务端值;非审批节点可为空 | 审批节点辅助说明 |
271
+ | `sequential` | 多人审批是否串行;不适用时为空 | 会签/或签展示方式,不用于前端计算流程结果 |
272
+ | `startTime` | 节点最早开始时间;未执行为空 | 节点开始时间 |
273
+ | `endTime` | 节点完成时间;运行中或未执行为空 | 节点结束时间 |
274
+ | `status` | 节点执行状态 | 节点状态标签 |
275
+ | `approvalResult` | 节点业务结论;未得出结论时为空 | 审批/结束结论标签;判断拒绝结果应优先看实际到达 `END` 的该字段 |
276
+ | `tasks` | 此节点内的实际任务、历史任务或未来计划办理人 | 展开办理人和意见;非人工节点可为空数组 |
277
+
278
+ `steps[].tasks[]` 字段:
279
+
280
+ | 字段 | 语义 | 页面使用 |
281
+ | --- | --- | --- |
282
+ | `taskId` | Flowable 任务 ID;未来计划任务尚未创建时为空 | 仅真实当前任务可作为任务动作 ID;不能对计划任务提交动作 |
283
+ | `assignee` | 实际办理人 ID;未来节点可来自配置预解析 | 稳定标识 |
284
+ | `assigneeName` | 办理人名称;解析失败时为空 | 办理人展示 |
285
+ | `startTime` | 任务开始时间;计划任务为空 | 时间线时间 |
286
+ | `endTime` | 任务结束时间;运行中或计划任务为空 | 完成时间 |
287
+ | `status` | 任务状态 | 任务状态标签 |
288
+ | `approvalResult` | 任务结论;运行中、未创建或未得出结论时为空;自动跳过任务可继承节点结论 | 先判断任务 `status`,`SKIPPED + APPROVED` 仍显示“已跳过”,不能显示该人员已同意 |
289
+ | `cancelReason` | 流程撤销原因;仅撤销事件任务使用 | 撤销说明 |
290
+ | `comments` | 该任务的审批意见、系统动作和表单变更 | 意见列表,按 `time` 展示 |
291
+
292
+ `comments[]` 字段:
293
+
294
+ | 字段 | 语义 | 页面使用 |
295
+ | --- | --- | --- |
296
+ | `userId` | 操作人 ID | 稳定标识 |
297
+ | `name` | 操作人名称 | 操作人展示 |
298
+ | `type` | 固定动作码 | 图标/颜色映射和诊断;展示文案优先用 `typeName` |
299
+ | `typeName` | Runtime 给出的可展示动作名称 | 直接作为“通过”“转签”“重新提交”等动作标题 |
300
+ | `fullMessage` | 审批意见或系统动作说明 | 意见正文;为空时不渲染空气泡 |
301
+ | `time` | 动作时间 | 意见时间 |
302
+ | `fieldChanges` | `FORM_UPDATE` 对应的字段变更;其他动作通常为空 | 字段修改 diff,不替代 `fullMessage` |
303
+ | `nodeId` | 表单修改来源节点 ID | 审计定位,默认不作为正文 |
304
+ | `formRef` | 表单定义引用 | 审计/调试元数据 |
305
+ | `dataPath` | 表单数据命名空间 | 审计/调试元数据 |
306
+ | `formDataVersion` | 该次表单修改对应的数据版本 | 审计展示;不能作为当前办理请求的最新版本 |
307
+
308
+ `fieldChanges[]` 字段固定为 `fieldKey`、`fieldLabel`、`oldValue`、`newValue`。页面优先显示 `fieldLabel`,为空时回退 `fieldKey`;旧值和新值要按业务字段类型格式化,不能一律转成 `[object Object]`。
309
+
310
+ `flowDiagram` 字段:
311
+
312
+ | 字段 | 语义 | 页面使用 |
313
+ | --- | --- | --- |
314
+ | `schemaVersion` | 流程图配置结构版本 | 诊断信息,通常不展示 |
315
+ | `flowKey` | 流程图业务键 | 图实例标识 |
316
+ | `flowName` | 流程图名称 | 图标题 |
317
+ | `version` | 本实例绑定的历史发布版本 | 可展示版本;旧实例不能改用最新版本的图 |
318
+ | `nodes` | 全量流程节点及本实例状态 | 流程图节点数据源 |
319
+ | `edges` | 全量流程连线及是否实际经过 | 流程图边数据源 |
320
+
321
+ `flowDiagram.nodes[]` 包含 `id`、`name`、`type`、`result`、`status`、`approvalResult`、`startTime`、`endTime`、`x`、`y`。其中 `result` 是 `END` 节点配置的预期结果,`approvalResult` 是本实例实际轨迹结论;`x/y` 是设计态坐标,缺失时由页面布局算法兜底。
322
+
323
+ `flowDiagram.edges[]` 包含 `id`、`source`、`target`、`name`、`conditionType`、`expression`、`defaultFlow`、`executed`。`executed=true` 表示本实例已经走过该连线;条件表达式只作流程图辅助信息,页面不能在前端重新执行表达式决定流程状态。
324
+
325
+ ### 平铺审批记录 `FlowRecords`
326
+
327
+ | 字段 | 语义 | 页面使用 |
328
+ | --- | --- | --- |
329
+ | `processInstanceId` | 流程实例 ID | 记录归属 |
330
+ | `flowName` | 流程名称 | 记录区标题 |
331
+ | `status` | 流程实例状态 | 总状态标签 |
332
+ | `canCancel` | 当前用户是否可撤销流程 | 控制撤销按钮 |
333
+ | `records` | 按节点顺序展开的审批记录 | 审批记录表格;适合表格,不等同于完整流程图 |
334
+
335
+ `records[]` 字段:
336
+
337
+ | 字段 | 语义 | 页面使用 |
338
+ | --- | --- | --- |
339
+ | `nodeName` | 节点名称 | 表格“环节”列 |
340
+ | `occurrence` | 同一节点第几次执行,从 1 开始 | 重复流转轮次 |
341
+ | `taskId` | 任务 ID;提交、流程结束等系统记录可为空 | 当前运行任务动作定位 |
342
+ | `assignees` | 此记录关联的办理人列表 | 办理人名称组 |
343
+ | `status` | 记录状态;已发生动作为 `COMPLETED`,待办可为 `PENDING` / `RUNNING` | 状态标签 |
344
+ | `canHandle` | 当前登录用户是否可办理这条运行中任务 | 行级办理按钮总开关 |
345
+ | `transferCandidates` | 当前节点允许转交的人 | 行级转交选择器 |
346
+ | `userId` | 实际评论/操作人 ID | 稳定标识 |
347
+ | `name` | 实际评论/操作人名称 | 操作人展示 |
348
+ | `type` | 动作码;系统记录可为 `SUBMIT` / `PROCESS_END` | 图标或颜色映射 |
349
+ | `typeName` | 可展示动作名称 | 动作列文案 |
350
+ | `fullMessage` | 评论或系统记录正文 | 意见列 |
351
+ | `fieldChanges` | 表单字段变更 | 修改详情 |
352
+ | `time` | 操作时间 | 时间列 |
353
+
354
+ `assignees[]` 只有 `userId` 和 `userName`。运行中的会签/或签可能包含多个办理人,不要只取第一项。时间线适合展示节点全貌和未来节点,平铺记录适合展示已经发生的操作;同一详情页可以二选一,也可以分为“流程进度”和“审批记录”两个区域,不能把两者混成一条无层级数组。
355
+
356
+ ### 抄送 `FlowCcRecord` 与 `FlowCustomPageCcDetail`
357
+
358
+ `FlowCcRecord` 字段:
359
+
360
+ | 字段 | 语义 | 页面使用 |
361
+ | --- | --- | --- |
362
+ | `id` | 抄送记录 ID | `getCcDetail()` 和 `markCcRead()` 的参数 |
363
+ | `requestId` | 本次手动抄送请求的幂等标识 | 审计/诊断,默认不展示 |
364
+ | `appCode` | 所属应用编码 | 应用边界核对,通常不展示 |
365
+ | `flowType` | 流程类型;自定义页面入口固定为独立流程 | 诊断字段 |
366
+ | `flowCode` | 流程编码 | 辅助信息 |
367
+ | `flowName` | 流程名称 | 抄送列表主标题 |
368
+ | `flowVersion` | 抄送发生时的流程版本 | 审计辅助信息 |
369
+ | `processInstanceId` | 流程实例 ID | 详情与轨迹定位 |
370
+ | `sourceNodeId` | 产生抄送的来源节点 ID | “抄送于某环节”的节点定位 |
371
+ | `senderUserId` | 抄送发送人 ID | 稳定标识 |
372
+ | `senderUserName` | 抄送发送人名称 | “抄送人”展示 |
373
+ | `recipientUserId` | 接收人 ID | 当前记录归属,通常不重复展示 |
374
+ | `recipientUserName` | 接收人名称 | 管理或审计页面展示 |
375
+ | `comment` | 抄送备注 | 列表摘要或详情说明 |
376
+ | `readStatus` | `UNREAD` 或 `READ` | 未读点、筛选和状态标签 |
377
+ | `readTime` | 首次标记已读时间;未读时为空 | 已读时间 |
378
+ | `createTime` | 抄送产生时间 | 列表时间,列表默认按其倒序 |
379
+
380
+ `FlowCustomPageCcDetail` 固定包含:
381
+
382
+ | 字段 | 语义 | 页面使用 |
383
+ | --- | --- | --- |
384
+ | `ccRecord` | 当前抄送记录 | 抄送来源、发送人、备注和已读状态 |
385
+ | `processDetail` | 抄送发生时可见的流程详情与表单快照 | 只读详情;不是流程当前最新可编辑表单 |
386
+ | `approvalRecords` | 截止抄送发生时间可见的审批记录 | 只读历史;抄送发生后的记录不会出现在该快照中 |
387
+
388
+ 打开抄送详情后可调用 `markCcRead(id)`,成功后刷新列表或本地把该记录标记为 `READ`。抄送详情不能显示办理按钮,不能用快照 `formData` 覆盖当前业务数据。
389
+
390
+ ### 批量操作 `FlowBatchOperationResult`
391
+
392
+ | 字段 | 语义 | 页面使用 |
393
+ | --- | --- | --- |
394
+ | `totalCount` | 本次请求的任务总数 | 批量结果摘要 |
395
+ | `successCount` | 成功任务数 | 成功提示 |
396
+ | `failureCount` | 失败任务数 | 失败提示;大于 0 时不能提示“全部成功” |
397
+ | `results` | 每个任务的独立结果 | 逐条反馈和失败重试选择 |
398
+
399
+ `results[]` 包含 `taskId`、`success`、`errorCode`、`errorMsg`。部分成功是正常返回形态;只对失败项显示原始错误,并刷新整个列表确认最新状态,不能盲目重试已经成功的任务。
400
+
401
+ `approve()`、`reject()`、`complete()`、`transfer()`、`cancel()`、`withdraw()`、`resubmit()`、`returnTask()`、`voidProcess()`、`updateVariables()` 和 `markCcRead()` 成功时返回 `void`。无返回对象不等于没有变化;任务动作后以 `taskId` 回读任务详情,并以已有的 `processInstanceId` 回读流程详情和时间线;流程动作后回读流程详情和时间线,列表页面同时刷新相应列表。不要从请求参数推断最终任务、流程状态或下一办理人。
402
+
403
+ ### 状态和动作码展示映射
404
+
405
+ 流程实例状态:
406
+
407
+ | 值 | 建议文案 | 说明 |
408
+ | --- | --- | --- |
409
+ | `RUNNING` | 进行中 | 流程正在流转 |
410
+ | `SUSPENDED` | 已挂起 | 底层保留状态;出现时只读展示,不擅自提供恢复按钮 |
411
+ | `WITHDRAWN` | 已撤回 | 等待发起人重新提交 |
412
+ | `RETURNED` | 已退回发起人 | 等待修改后重新提交 |
413
+ | `COMPLETED` | 已完成 | 只表示实例正常结束,不等于一定审批通过 |
414
+ | `CANCELLED` | 已撤销 | 流程已结束 |
415
+ | `VOIDED` | 已作废 | 流程已结束且不可继续办理 |
416
+
417
+ 审批拒绝不能仅凭 `processStatus` / `status` 判断。正常走到拒绝 `END` 时流程实例仍可能是 `COMPLETED`;页面要从实际到达的 `END` 步骤或图节点的 `approvalResult=REJECTED` 展示“已拒绝”。
418
+
419
+ 撤回或退回发起人后,页面必须对原 `processInstanceId` 调用 `resubmit()`,不能再次调用 `start()`。重提在同一流程实例中开启新的 `approvalRound`,从 `START` 的后继节点重新流转;页面刷新详情和时间线后再展示新一轮状态。退回发起人目前只支持 `FORM_FLOW`,本指南范围内的 `INDEPENDENT_FLOW + CUSTOM_PAGE` 不提供该动作;`returnTask()` 只能选择 `getReturnTargets()` 返回的历史审批节点。
420
+
421
+ 任务/节点状态可出现 `PENDING`、`RUNNING`、`PARTIALLY_COMPLETED`、`COMPLETED`、`SKIPPED`、`RETURNED`、`RETURNED_TO_STARTER`、`WITHDRAWN`、`VOIDED`、`CANCELLED`。`PARTIALLY_COMPLETED` 表示非串行多人节点已有部分任务完成但节点仍在运行;`SKIPPED` 表示未执行或因多实例结果被系统跳过,不能展示成失败。
422
+
423
+ `approvalResult` 可出现 `APPROVED`、`REJECTED`、`RESUBMITTED`、`RETURNED`、`RETURNED_TO_STARTER`、`WITHDRAWN`、`VOIDED`、`CANCELLED`。状态表示生命周期,`approvalResult` 表示业务结论,两者要分别展示。
424
+
425
+ 评论动作 `type` 的固定展示语义:
426
+
427
+ | 值 | 默认文案 |
428
+ | --- | --- |
429
+ | `APPROVE` | 通过 |
430
+ | `AUTO_SKIP` | 自动跳过 |
431
+ | `REJECT` | 拒绝 |
432
+ | `TIMEOUT_APPROVE` | 超时自动同意 |
433
+ | `TIMEOUT_REJECT` | 超时自动拒绝 |
434
+ | `COMPLETE` | 办理 |
435
+ | `COMMENT` | 评论 |
436
+ | `FORM_UPDATE` | 修改表单 |
437
+ | `TRANSFER` | 转签 |
438
+ | `WITHDRAW` | 撤回 |
439
+ | `RESUBMIT` | 重新提交 |
440
+ | `RETURN` | 退回 |
441
+ | `RETURN_TO_STARTER` | 退回发起人 |
442
+ | `VOID` | 作废 |
443
+ | `CANCEL` | 撤销 |
444
+ | `SUBMIT` | 提交 |
445
+ | `PROCESS_END` | 流程结束 |
446
+
447
+ Runtime 已返回 `typeName` 时优先展示 `typeName`;上表用于图标、颜色和旧数据兜底,不覆盖服务端文案。
448
+
449
+ ### 页面组合建议
450
+
451
+ - 工作台:待办、已办、我发起的、抄送我的分别使用对应列表方法;列表业务摘要来自明确请求的 `businessVariables`,不能从 `formData` 猜列。
452
+ - 详情页头部:使用 `flowName`、`processStatus`、发起人、`processStartTime`;业务主体使用 `formData`;当前环节使用任务字段;进度使用 `timeline.steps` 或 `flowDiagram`;审计记录使用 `getRecords()`。
453
+ - 时间线默认按 [时间线展示指南](custom-page-flow-timeline-display.md) 生成纵向节点、办理人状态和操作记录三层视图;流程图作为独立查看入口,不能把转签操作人的记录误作当前办理人状态。
454
+ - 操作区:先检查 `canHandle`,再按 `taskMode` 决定动作;转交同时要求候选列表非空;退回只能从 `returnTargets` 选择;流程级按钮直接使用各 `can*` 字段。
455
+ - 终态页:不要假设 `COMPLETED` 等于通过;从实际 `END.approvalResult` 区分通过和拒绝,并展示 `processEndTime`。
456
+ - 抄送详情:使用只读快照,不展示任务办理按钮;标记已读后刷新 `readStatus`。
457
+
458
+ ### 写入和办理
459
+
460
+ | 页面意图 | SDK 方法 | 参数 | 返回值 |
461
+ | --- | --- | --- | --- |
462
+ | 发起 | `start(request)` | `FlowStartRequest` | `FlowCustomPageStartResponse` |
463
+ | 修改业务变量 | `updateVariables(request)` | `FlowUpdateVariablesRequest` | `void` |
464
+ | 同意 | `approve(request)` | `FlowTaskActionRequest` | `void` |
465
+ | 驳回 | `reject(request)` | `FlowTaskActionRequest` | `void` |
466
+ | 完成办理 | `complete(request)` | `FlowTaskActionRequest` | `void` |
467
+ | 批量同意/驳回 | `batchApprove` / `batchReject` | `FlowBatchTaskActionRequest` | `FlowBatchOperationResult` |
468
+ | 转交 | `transfer(request)` | `FlowTransferRequest` | `void` |
469
+ | 批量转交 | `batchTransfer(request)` | `FlowBatchTransferRequest` | `FlowBatchOperationResult` |
470
+ | 取消/撤回/作废 | `cancel` / `withdraw` / `voidProcess` | `FlowProcessReasonRequest` | `void` |
471
+ | 重新提交 | `resubmit(request)` | `FlowResubmitRequest` | `void` |
472
+ | 退回指定节点 | `returnTask(request)` | `FlowReturnRequest` | `void` |
473
+ | 手动抄送 | `ccProcess(request)` | `FlowCcRequest` | `FlowCcRecord[]` |
474
+ | 标记抄送已读 | `markCcRead(ccRecordId)` | `number \| string` | `void` |
475
+
476
+ ## 请求类型
477
+
478
+ ```typescript
479
+ interface FlowVariableQuery {
480
+ currentPage?: number; // 默认 1
481
+ pageSize?: number; // 默认 20
482
+ variables?: Record<string, any>;
483
+ variableKeys?: string[];
484
+ }
485
+
486
+ interface FlowSubmittedQuery {
487
+ currentPage?: number;
488
+ pageSize?: number;
489
+ variableKeys?: string[];
490
+ status?: string;
491
+ }
492
+
493
+ interface FlowDefinitionQuery {
494
+ currentPage?: number;
495
+ pageSize?: number;
496
+ flowName?: string;
497
+ }
498
+
499
+ interface FlowCcQuery {
500
+ currentPage?: number;
501
+ pageSize?: number;
502
+ readStatus?: string;
503
+ }
504
+
505
+ interface FlowStartRequest {
506
+ flowCode: string;
507
+ formData?: Record<string, any>;
508
+ variables?: Record<string, any>;
509
+ idempotencyKey?: string;
510
+ }
511
+
512
+ interface FlowUpdateVariablesRequest {
513
+ processInstanceId: string;
514
+ set?: Record<string, any>;
515
+ remove?: string[];
516
+ }
517
+
518
+ interface FlowTaskActionRequest {
519
+ taskId: string;
520
+ formPatch?: Record<string, any>;
521
+ formDataVersion?: number;
522
+ variables?: Record<string, any>;
523
+ comment?: string;
524
+ }
525
+
526
+ interface FlowBatchTaskActionRequest {
527
+ taskIds: string[];
528
+ comment?: string;
529
+ variables?: Record<string, any>;
530
+ }
531
+
532
+ interface FlowTransferRequest {
533
+ taskId: string;
534
+ targetUserId: string;
535
+ comment?: string;
536
+ }
537
+
538
+ interface FlowBatchTransferRequest {
539
+ taskIds: string[];
540
+ targetUserId: string;
541
+ comment?: string;
542
+ }
543
+
544
+ interface FlowProcessReasonRequest {
545
+ processInstanceId: string;
546
+ reason?: string;
547
+ }
548
+
549
+ interface FlowResubmitRequest {
550
+ processInstanceId: string;
551
+ formPatch?: Record<string, any>;
552
+ variables?: Record<string, any>;
553
+ formDataVersion?: number;
554
+ comment?: string;
555
+ }
556
+
557
+ interface FlowReturnRequest {
558
+ taskId: string;
559
+ targetNodeId: string;
560
+ reason?: string;
561
+ }
562
+
563
+ interface FlowCcRequest {
564
+ processInstanceId: string;
565
+ taskId?: string;
566
+ recipientUserIds: string[];
567
+ comment?: string;
568
+ requestId?: string;
569
+ }
570
+ ```
571
+
572
+ 必填字符串不能为空;`taskIds`、`recipientUserIds` 至少包含一个有效 ID。普通非动态自定义页面使用 `formPatch` 时不需要构造 schema 或 `formDataVersion`。动态表单要求版本时,办理和重提必须使用 Runtime 返回的最新 `formDataVersion`,不要提交 schema,也不要自行递增、缓存猜测或使用客户端业务版本。`approve()`、`reject()`、`complete()` 不能同时传 `formPatch` 与 `variables.formData`;`resubmit()` 始终不能传 `variables.formData`。
573
+
574
+ ## 采购申请示例
575
+
576
+ 页面不初始化 SDK,只使用 `useSdkClient()`:
577
+
578
+ ```jsx
579
+ import { useSdkClient } from "@/context/app-context";
580
+
581
+ const client = useSdkClient();
582
+ const flow = client.flow();
583
+
584
+ const started = await flow.start({
585
+ flowCode: "purchase_request",
586
+ formData: {
587
+ subject: "研发设备采购",
588
+ category: "信息技术设备",
589
+ quantity: 1,
590
+ budgetAmount: 12000,
591
+ supplier: "示例供应商",
592
+ reason: "项目开发使用",
593
+ },
594
+ variables: {
595
+ businessId: "PUR-20260916-001",
596
+ departmentCode: "RD",
597
+ budgetAmount: 12000,
598
+ },
599
+ idempotencyKey: "purchase-PUR-20260916-001",
600
+ });
601
+
602
+ const todoPage = await flow.listTodo({
603
+ variables: { businessId: "PUR-20260916-001" },
604
+ variableKeys: ["businessId", "departmentCode", "budgetAmount"],
605
+ });
606
+
607
+ const task = todoPage.records[0];
608
+ if (task) {
609
+ await flow.approve({
610
+ taskId: task.taskId,
611
+ comment: "预算和供应商信息已确认",
612
+ variables: { purchaseStatus: "APPROVED" },
613
+ });
614
+ }
615
+
616
+ console.log(started.processInstanceId);
617
+ ```
618
+
619
+ 发起时为同一业务单生成稳定的 `idempotencyKey`,网络重试复用该值。手动抄送同一次操作重试时复用 `requestId`。
620
+
621
+ ## 页面状态与错误处理
622
+
623
+ - 列表、详情和写入分别维护加载、空态、失败和成功状态。
624
+ - 提交按钮在请求进行中禁用,避免重复点击;幂等键仍必须稳定。
625
+ - 写入成功后重新读取相关列表或详情,不根据本地猜测下一任务或流程状态。
626
+ - 捕获 `LovrabetError`,使用 `status`、`code`、`message`、`description` 和 `response` 形成用户可理解的错误;不要记录 Cookie 或凭据。
627
+ - 遇到应用边界、办理人、流程状态或管理员权限错误时,保留 Runtime 原始语义;不要删除 `appCode`、伪造身份或改用低层 HTTP 绕过 SDK。
628
+
629
+ ## 页面自检
630
+
631
+ - [ ] 目标流程是已发布的 `INDEPENDENT_FLOW + CUSTOM_PAGE`。
632
+ - [ ] 页面使用 `useSdkClient()` 和无参数 `client.flow()`。
633
+ - [ ] 页面没有手动传 `appCode`、`operatorUserId`、Cookie、AccessKey 或 Token。
634
+ - [ ] `formData`、`formPatch`、`variables` 和 `variableKeys` 没有混用。
635
+ - [ ] 普通表单的 `formPatch` 按根级字段合并,嵌套对象和数组没有被误认为深合并。
636
+ - [ ] `approve()`、`reject()`、`complete()` 没有同时传 `formPatch` 和 `variables.formData`;`resubmit()` 没有传 `variables.formData`。
637
+ - [ ] 列表查询使用稳定业务变量;没有查询系统变量。
638
+ - [ ] 动态表单办理使用最新 `formDataVersion`。
639
+ - [ ] 退回目标来自 `getReturnTargets()`。
640
+ - [ ] 应用范围方法只出现在管理员页面。
641
+ - [ ] 写入有重复提交保护,成功后按服务端事实刷新。
642
+ - [ ] 页面完整处理 Runtime 权限、状态和业务错误。