@yss123/cage-cli 0.2.0 → 0.3.0

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 (607) hide show
  1. package/README.md +47 -3
  2. package/bin/cage.js +5 -0
  3. package/bin/create-cage-app.js +5 -0
  4. package/dist/analyze.d.ts +16 -0
  5. package/dist/analyze.js +18 -2
  6. package/dist/analyze.js.map +1 -1
  7. package/dist/baseline.d.ts +8 -0
  8. package/dist/baseline.js +13 -0
  9. package/dist/baseline.js.map +1 -1
  10. package/dist/bootstrap.d.ts +20 -0
  11. package/dist/bootstrap.js +75 -0
  12. package/dist/bootstrap.js.map +1 -0
  13. package/dist/budget.d.ts +7 -0
  14. package/dist/budget.js +49 -5
  15. package/dist/budget.js.map +1 -1
  16. package/dist/capabilities.d.ts +38 -0
  17. package/dist/capabilities.js +133 -0
  18. package/dist/capabilities.js.map +1 -0
  19. package/dist/config.d.ts +31 -2
  20. package/dist/config.js +22 -0
  21. package/dist/config.js.map +1 -1
  22. package/dist/context.d.ts +14 -0
  23. package/dist/context.js +35 -2
  24. package/dist/context.js.map +1 -1
  25. package/dist/create-prompt.d.ts +7 -0
  26. package/dist/create-prompt.js +12 -0
  27. package/dist/create-prompt.js.map +1 -1
  28. package/dist/create.d.ts +21 -1
  29. package/dist/create.js +23 -1
  30. package/dist/create.js.map +1 -1
  31. package/dist/derive.d.ts +23 -0
  32. package/dist/derive.js +40 -0
  33. package/dist/derive.js.map +1 -1
  34. package/dist/dev.d.ts +6 -0
  35. package/dist/dev.js +11 -0
  36. package/dist/dev.js.map +1 -1
  37. package/dist/doctor.d.ts +98 -0
  38. package/dist/doctor.js +93 -0
  39. package/dist/doctor.js.map +1 -0
  40. package/dist/env.d.ts +6 -0
  41. package/dist/env.js +11 -0
  42. package/dist/env.js.map +1 -1
  43. package/dist/findings.d.ts +27 -0
  44. package/dist/findings.js +20 -0
  45. package/dist/findings.js.map +1 -1
  46. package/dist/gen/contracts.d.ts +28 -0
  47. package/dist/gen/contracts.js +52 -12
  48. package/dist/gen/contracts.js.map +1 -1
  49. package/dist/gen/index.d.ts +26 -0
  50. package/dist/gen/index.js +69 -1
  51. package/dist/gen/index.js.map +1 -1
  52. package/dist/gen/zod-code.d.ts +42 -0
  53. package/dist/gen/zod-code.js +178 -16
  54. package/dist/gen/zod-code.js.map +1 -1
  55. package/dist/graph-approvals.d.ts +60 -0
  56. package/dist/graph-approvals.js +80 -0
  57. package/dist/graph-approvals.js.map +1 -0
  58. package/dist/graph-business.d.ts +135 -0
  59. package/dist/graph-business.js +404 -0
  60. package/dist/graph-business.js.map +1 -0
  61. package/dist/graph-command.d.ts +17 -0
  62. package/dist/graph-command.js +21 -0
  63. package/dist/graph-command.js.map +1 -1
  64. package/dist/graph-model.d.ts +44 -0
  65. package/dist/graph-model.js +36 -3
  66. package/dist/graph-model.js.map +1 -1
  67. package/dist/graph-presentation.d.ts +16 -0
  68. package/dist/graph-presentation.js +10 -1
  69. package/dist/graph-presentation.js.map +1 -1
  70. package/dist/graph-query.d.ts +95 -0
  71. package/dist/graph-query.js +62 -0
  72. package/dist/graph-query.js.map +1 -1
  73. package/dist/graph-relations.d.ts +20 -0
  74. package/dist/graph-relations.js +34 -4
  75. package/dist/graph-relations.js.map +1 -1
  76. package/dist/graph-search.d.ts +35 -0
  77. package/dist/graph-search.js +36 -0
  78. package/dist/graph-search.js.map +1 -1
  79. package/dist/graph-snapshot.d.ts +26 -0
  80. package/dist/graph-snapshot.js +30 -1
  81. package/dist/graph-snapshot.js.map +1 -1
  82. package/dist/graph.d.ts +13 -2
  83. package/dist/graph.js +59 -4
  84. package/dist/graph.js.map +1 -1
  85. package/dist/impact.d.ts +50 -0
  86. package/dist/impact.js +62 -2
  87. package/dist/impact.js.map +1 -1
  88. package/dist/index.d.ts +10 -0
  89. package/dist/index.js +10 -0
  90. package/dist/index.js.map +1 -1
  91. package/dist/init.d.ts +12 -0
  92. package/dist/init.js +15 -0
  93. package/dist/init.js.map +1 -1
  94. package/dist/load.d.ts +10 -0
  95. package/dist/load.js +15 -0
  96. package/dist/load.js.map +1 -1
  97. package/dist/main.d.ts +6 -0
  98. package/dist/main.js +93 -5
  99. package/dist/main.js.map +1 -1
  100. package/dist/migrate.d.ts +12 -0
  101. package/dist/migrate.js +17 -0
  102. package/dist/migrate.js.map +1 -1
  103. package/dist/ontology.d.ts +67 -2
  104. package/dist/ontology.js +89 -2
  105. package/dist/ontology.js.map +1 -1
  106. package/dist/process-rules.d.ts +21 -0
  107. package/dist/process-rules.js +100 -0
  108. package/dist/process-rules.js.map +1 -0
  109. package/dist/process.d.ts +32 -0
  110. package/dist/process.js +32 -0
  111. package/dist/process.js.map +1 -1
  112. package/dist/project-structure.d.ts +5 -0
  113. package/dist/project-structure.js +10 -0
  114. package/dist/project-structure.js.map +1 -1
  115. package/dist/registration.d.ts +16 -0
  116. package/dist/registration.js +56 -0
  117. package/dist/registration.js.map +1 -0
  118. package/dist/rules.d.ts +52 -0
  119. package/dist/rules.js +58 -0
  120. package/dist/rules.js.map +1 -1
  121. package/dist/runtime-diagnostics.d.ts +27 -0
  122. package/dist/runtime-diagnostics.js +60 -0
  123. package/dist/runtime-diagnostics.js.map +1 -0
  124. package/dist/snapshots.d.ts +40 -0
  125. package/dist/snapshots.js +62 -0
  126. package/dist/snapshots.js.map +1 -0
  127. package/dist/static-check.d.ts +33 -0
  128. package/dist/static-check.js +37 -1
  129. package/dist/static-check.js.map +1 -1
  130. package/dist/sync.d.ts +11 -0
  131. package/dist/sync.js +65 -8
  132. package/dist/sync.js.map +1 -1
  133. package/dist/upgrade.d.ts +16 -0
  134. package/dist/upgrade.js +21 -0
  135. package/dist/upgrade.js.map +1 -1
  136. package/dist/verify.d.ts +14 -0
  137. package/dist/verify.js +19 -0
  138. package/dist/verify.js.map +1 -1
  139. package/dist/version.js +5 -0
  140. package/dist/version.js.map +1 -1
  141. package/graph-ui/app.js +321 -27
  142. package/graph-ui/approval-flow.js +165 -0
  143. package/graph-ui/business.css +985 -0
  144. package/graph-ui/business.js +549 -0
  145. package/graph-ui/flowchart-interaction.js +177 -0
  146. package/graph-ui/flowchart.js +1059 -0
  147. package/graph-ui/graph-approvals.js +79 -0
  148. package/graph-ui/graph-business.js +403 -0
  149. package/graph-ui/graph-model.js +36 -3
  150. package/graph-ui/graph-relations.js +34 -4
  151. package/graph-ui/graph-search.js +36 -0
  152. package/graph-ui/index.html +26 -12
  153. package/graph-ui/model.js +28 -0
  154. package/graph-ui/relations.js +4 -0
  155. package/graph-ui/structure.js +44 -0
  156. package/graph-ui/style.css +12 -0
  157. package/package.json +6 -4
  158. package/templates/app/.dockerignore +2 -0
  159. package/templates/app/.env.example +10 -0
  160. package/templates/app/AGENTS.md +49 -9
  161. package/templates/app/README.md +4 -1
  162. package/templates/app/_gitignore +1 -0
  163. package/templates/app/apps/api/package.json +2 -2
  164. package/templates/app/apps/api/src/main.ts +5 -1
  165. package/templates/app/apps/api/src/worker.ts +3 -0
  166. package/templates/app/apps/web/index.html +1 -0
  167. package/templates/app/apps/web/package.json +7 -3
  168. package/templates/app/apps/web/src/app/app.tsx +122 -12
  169. package/templates/app/apps/web/src/app/styles/global.css +88 -8
  170. package/templates/app/apps/web/src/app/use-session.ts +43 -0
  171. package/templates/app/apps/web/src/app/workspace-layout.tsx +58 -19
  172. package/templates/app/apps/web/src/main.tsx +5 -0
  173. package/templates/app/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +11 -0
  174. package/templates/app/apps/web/src/modules/approval/index.ts +4 -0
  175. package/templates/app/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +20 -1
  176. package/templates/app/apps/web/src/modules/auth/index.ts +4 -0
  177. package/templates/app/apps/web/src/modules/auth/pages/login-page.tsx +12 -0
  178. package/templates/app/apps/web/src/modules/inventory/index.ts +4 -0
  179. package/templates/app/apps/web/src/modules/inventory/pages/inventory-page.tsx +29 -1
  180. package/templates/app/apps/web/src/modules/purchase/components/approval-history.tsx +32 -0
  181. package/templates/app/apps/web/src/modules/purchase/components/order-attachments.tsx +29 -0
  182. package/templates/app/apps/web/src/modules/purchase/components/purchase-assistant-context.tsx +17 -0
  183. package/templates/app/apps/web/src/modules/purchase/components/purchase-order-form.css +6 -0
  184. package/templates/app/apps/web/src/modules/purchase/components/purchase-order-form.tsx +25 -3
  185. package/templates/app/apps/web/src/modules/purchase/index.ts +5 -0
  186. package/templates/app/apps/web/src/modules/purchase/lib/presentation.ts +20 -0
  187. package/templates/app/apps/web/src/modules/purchase/pages/purchase-intelligence.css +15 -0
  188. package/templates/app/apps/web/src/modules/purchase/pages/purchase-order-detail-page.tsx +154 -0
  189. package/templates/app/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +52 -22
  190. package/templates/app/apps/web/src/modules/workspace/index.ts +5 -0
  191. package/templates/app/apps/web/src/modules/workspace/pages/home-page.tsx +44 -0
  192. package/templates/app/apps/web/src/shared/hooks/use-command.ts +13 -0
  193. package/templates/app/apps/web/src/shared/lib/error-message.ts +9 -0
  194. package/templates/app/apps/web/src/shared/lib/navigation.ts +21 -0
  195. package/templates/app/apps/web/src/shared/ui/assistant-markdown.tsx +19 -0
  196. package/templates/app/apps/web/src/shared/ui/assistant-panel.css +134 -0
  197. package/templates/app/apps/web/src/shared/ui/assistant-panel.tsx +200 -0
  198. package/templates/app/apps/web/src/shared/ui/assistant-scope.tsx +72 -0
  199. package/templates/app/apps/web/src/shared/ui/attachment-upload.css +28 -0
  200. package/templates/app/apps/web/src/shared/ui/attachment-upload.tsx +163 -0
  201. package/templates/app/apps/web/src/shared/ui/notice.tsx +7 -0
  202. package/templates/app/apps/web/src/shared/ui/page-heading.tsx +7 -0
  203. package/templates/app/apps/web/src/shared/ui/page-state.css +47 -0
  204. package/templates/app/apps/web/src/shared/ui/page-state.tsx +76 -0
  205. package/templates/app/apps/web/src/shared/ui/require-capability.tsx +34 -0
  206. package/templates/app/apps/web/vite.config.ts +5 -0
  207. package/templates/app/cage.config.json +9 -0
  208. package/templates/app/db/migrations/0002_draft.sql +12 -0
  209. package/templates/app/db/migrations/0003_draft.sql +8 -0
  210. package/templates/app/deploy/nginx.conf +52 -0
  211. package/templates/app/docs/ai/README.md +21 -0
  212. package/templates/app/docs/ai/architecture.md +26 -0
  213. package/templates/app/docs/ai/commenting.md +203 -0
  214. package/templates/app/docs/ai/diagnostics.md +80 -0
  215. package/templates/app/docs/ai/files.md +93 -0
  216. package/templates/app/docs/ai/intelligence.md +348 -0
  217. package/templates/app/docs/ai/ontology-context.md +59 -4
  218. package/templates/app/docs/ai/primitives.md +33 -0
  219. package/templates/app/docs/ai/project-structure.md +8 -3
  220. package/templates/app/docs/ai/purchase-example.md +16 -2
  221. package/templates/app/docs/ai/recipes.md +9 -1
  222. package/templates/app/docs/ai/routing.md +86 -0
  223. package/templates/app/docs/ai/troubleshooting.md +5 -0
  224. package/templates/app/docs/ai/workflow.md +24 -11
  225. package/templates/app/docs/errors/CAGE-AI-001.md +61 -0
  226. package/templates/app/docs/errors/CAGE-APPR-001.md +7 -6
  227. package/templates/app/docs/errors/CAGE-APPR-002.md +2 -2
  228. package/templates/app/docs/errors/CAGE-APPR-003.md +1 -1
  229. package/templates/app/docs/errors/CAGE-APPR-004.md +4 -4
  230. package/templates/app/docs/errors/CAGE-APPR-005.md +1 -1
  231. package/templates/app/docs/errors/CAGE-APPR-006.md +12 -6
  232. package/templates/app/docs/errors/CAGE-APPR-007.md +3 -3
  233. package/templates/app/docs/errors/CAGE-APPR-010.md +5 -5
  234. package/templates/app/docs/errors/CAGE-AUDIT-001.md +53 -0
  235. package/templates/app/docs/errors/CAGE-AUTH-001.md +1 -1
  236. package/templates/app/docs/errors/CAGE-BIZ-001.md +51 -0
  237. package/templates/app/docs/errors/CAGE-BIZ-002.md +49 -0
  238. package/templates/app/docs/errors/CAGE-BUDGET-001.md +1 -1
  239. package/templates/app/docs/errors/CAGE-BUDGET-002.md +1 -1
  240. package/templates/app/docs/errors/CAGE-BUDGET-003.md +1 -1
  241. package/templates/app/docs/errors/CAGE-CMD-002.md +1 -1
  242. package/templates/app/docs/errors/CAGE-CMD-003.md +1 -1
  243. package/templates/app/docs/errors/CAGE-CONN-001.md +3 -3
  244. package/templates/app/docs/errors/CAGE-CONN-002.md +1 -1
  245. package/templates/app/docs/errors/CAGE-CONN-003.md +1 -1
  246. package/templates/app/docs/errors/CAGE-CONN-004.md +1 -1
  247. package/templates/app/docs/errors/CAGE-CONN-005.md +1 -1
  248. package/templates/app/docs/errors/CAGE-CONN-006.md +1 -1
  249. package/templates/app/docs/errors/CAGE-CONN-007.md +6 -6
  250. package/templates/app/docs/errors/CAGE-CONN-008.md +5 -5
  251. package/templates/app/docs/errors/CAGE-CONN-009.md +6 -6
  252. package/templates/app/docs/errors/CAGE-CONN-010.md +6 -6
  253. package/templates/app/docs/errors/CAGE-CONN-011.md +1 -1
  254. package/templates/app/docs/errors/CAGE-CONN-012.md +1 -1
  255. package/templates/app/docs/errors/CAGE-CONN-013.md +49 -0
  256. package/templates/app/docs/errors/CAGE-CONN-014.md +48 -0
  257. package/templates/app/docs/errors/CAGE-CONN-015.md +49 -0
  258. package/templates/app/docs/errors/CAGE-CREATE-001.md +10 -9
  259. package/templates/app/docs/errors/CAGE-DECL-001.md +2 -2
  260. package/templates/app/docs/errors/CAGE-DECL-002.md +7 -6
  261. package/templates/app/docs/errors/CAGE-DECL-003.md +1 -1
  262. package/templates/app/docs/errors/CAGE-DECL-004.md +1 -1
  263. package/templates/app/docs/errors/CAGE-DEP-001.md +2 -2
  264. package/templates/app/docs/errors/CAGE-DEP-002.md +1 -1
  265. package/templates/app/docs/errors/CAGE-DEP-003.md +2 -2
  266. package/templates/app/docs/errors/CAGE-DEP-004.md +1 -1
  267. package/templates/app/docs/errors/CAGE-DEP-005.md +1 -1
  268. package/templates/app/docs/errors/CAGE-DIAG-001.md +53 -0
  269. package/templates/app/docs/errors/CAGE-DLQ-001.md +2 -2
  270. package/templates/app/docs/errors/CAGE-ENV-001.md +4 -4
  271. package/templates/app/docs/errors/CAGE-ENV-002.md +51 -0
  272. package/templates/app/docs/errors/CAGE-ENV-003.md +48 -0
  273. package/templates/app/docs/errors/CAGE-EVENT-001.md +1 -1
  274. package/templates/app/docs/errors/CAGE-EVENT-002.md +7 -7
  275. package/templates/app/docs/errors/CAGE-FIELD-001.md +2 -2
  276. package/templates/app/docs/errors/CAGE-FIELD-002.md +1 -1
  277. package/templates/app/docs/errors/CAGE-FIELD-003.md +1 -1
  278. package/templates/app/docs/errors/CAGE-FIELD-004.md +1 -1
  279. package/templates/app/docs/errors/CAGE-FILE-001.md +56 -0
  280. package/templates/app/docs/errors/CAGE-GEN-001.md +2 -2
  281. package/templates/app/docs/errors/CAGE-GEN-002.md +1 -1
  282. package/templates/app/docs/errors/CAGE-GEN-003.md +53 -0
  283. package/templates/app/docs/errors/CAGE-GRANT-001.md +3 -3
  284. package/templates/app/docs/errors/CAGE-GRANT-002.md +2 -2
  285. package/templates/app/docs/errors/CAGE-GRANT-003.md +7 -6
  286. package/templates/app/docs/errors/CAGE-IMPACT-001.md +2 -2
  287. package/templates/app/docs/errors/CAGE-IMPACT-002.md +52 -0
  288. package/templates/app/docs/errors/CAGE-INIT-001.md +1 -1
  289. package/templates/app/docs/errors/CAGE-INIT-002.md +1 -1
  290. package/templates/app/docs/errors/CAGE-INIT-003.md +2 -2
  291. package/templates/app/docs/errors/CAGE-INIT-004.md +1 -1
  292. package/templates/app/docs/errors/CAGE-INIT-005.md +52 -0
  293. package/templates/app/docs/errors/CAGE-JOB-001.md +1 -1
  294. package/templates/app/docs/errors/CAGE-JOB-002.md +1 -1
  295. package/templates/app/docs/errors/CAGE-JOB-003.md +1 -1
  296. package/templates/app/docs/errors/CAGE-LINT-001.md +1 -1
  297. package/templates/app/docs/errors/CAGE-MIG-001.md +1 -1
  298. package/templates/app/docs/errors/CAGE-MIG-002.md +1 -1
  299. package/templates/app/docs/errors/CAGE-MIG-005.md +1 -1
  300. package/templates/app/docs/errors/CAGE-NAME-001.md +1 -1
  301. package/templates/app/docs/errors/CAGE-NAME-002.md +1 -1
  302. package/templates/app/docs/errors/CAGE-NAME-003.md +3 -3
  303. package/templates/app/docs/errors/CAGE-NAME-004.md +1 -1
  304. package/templates/app/docs/errors/CAGE-NAME-005.md +1 -1
  305. package/templates/app/docs/errors/CAGE-NAME-006.md +1 -1
  306. package/templates/app/docs/errors/CAGE-ORG-001.md +7 -6
  307. package/templates/app/docs/errors/CAGE-PAIR-002.md +6 -5
  308. package/templates/app/docs/errors/CAGE-QUERY-001.md +1 -1
  309. package/templates/app/docs/errors/CAGE-QUERY-002.md +2 -2
  310. package/templates/app/docs/errors/CAGE-QUERY-003.md +7 -6
  311. package/templates/app/docs/errors/CAGE-REACT-001.md +3 -3
  312. package/templates/app/docs/errors/CAGE-REACT-002.md +1 -1
  313. package/templates/app/docs/errors/CAGE-REACT-003.md +50 -0
  314. package/templates/app/docs/errors/CAGE-READS-001.md +9 -6
  315. package/templates/app/docs/errors/CAGE-REG-001.md +13 -12
  316. package/templates/app/docs/errors/CAGE-REG-002.md +2 -1
  317. package/templates/app/docs/errors/CAGE-REG-003.md +1 -1
  318. package/templates/app/docs/errors/CAGE-REL-001.md +14 -14
  319. package/templates/app/docs/errors/CAGE-ROUTE-001.md +7 -6
  320. package/templates/app/docs/errors/CAGE-SCOPE-001.md +1 -1
  321. package/templates/app/docs/errors/CAGE-SCOPE-002.md +2 -2
  322. package/templates/app/docs/errors/CAGE-SECRET-001.md +2 -2
  323. package/templates/app/docs/errors/CAGE-SECRET-002.md +1 -1
  324. package/templates/app/docs/errors/CAGE-SENS-001.md +5 -5
  325. package/templates/app/docs/errors/CAGE-SQL-001.md +1 -1
  326. package/templates/app/docs/errors/CAGE-SQL-002.md +1 -1
  327. package/templates/app/docs/errors/CAGE-STATE-001.md +3 -3
  328. package/templates/app/docs/errors/CAGE-STATE-002.md +1 -1
  329. package/templates/app/docs/errors/CAGE-STATE-003.md +1 -1
  330. package/templates/app/docs/errors/CAGE-STATE-004.md +1 -1
  331. package/templates/app/docs/errors/CAGE-STATE-005.md +3 -2
  332. package/templates/app/docs/errors/CAGE-STATE-010.md +5 -5
  333. package/templates/app/docs/errors/CAGE-STATE-011.md +5 -5
  334. package/templates/app/docs/errors/CAGE-STRUCT-001.md +1 -1
  335. package/templates/app/docs/errors/CAGE-STRUCT-002.md +1 -1
  336. package/templates/app/docs/errors/CAGE-SYNC-001.md +3 -2
  337. package/templates/app/docs/errors/CAGE-TEST-001.md +1 -1
  338. package/templates/app/docs/errors/CAGE-TEST-002.md +50 -0
  339. package/templates/app/docs/errors/CAGE-TEST-003.md +52 -0
  340. package/templates/app/docs/errors/CAGE-UNSAFE-001.md +3 -2
  341. package/templates/app/docs/errors/CAGE-UPGRADE-001.md +2 -2
  342. package/templates/app/docs/errors/CAGE-WORKER-001.md +48 -0
  343. package/templates/app/docs/errors/CAGE-WORKER-002.md +50 -0
  344. package/templates/app/docs/errors/CAGE-WORKER-003.md +48 -0
  345. package/templates/app/docs/errors/README.md +50 -0
  346. package/templates/app/package.json +3 -3
  347. package/templates/app/packages/contracts/package.json +1 -1
  348. package/templates/app/packages/contracts/src/aggregates/dept/index.ts +10 -10
  349. package/templates/app/packages/contracts/src/aggregates/inventory/index.ts +5 -5
  350. package/templates/app/packages/contracts/src/aggregates/inventory-lock/index.ts +4 -4
  351. package/templates/app/packages/contracts/src/aggregates/purchase-order/index.ts +26 -12
  352. package/templates/app/packages/contracts/src/aggregates/role/index.ts +15 -15
  353. package/templates/app/packages/contracts/src/aggregates/user/index.ts +16 -16
  354. package/templates/app/packages/contracts/src/index.ts +7 -1
  355. package/templates/app/packages/contracts/src/queries/index.ts +2 -2
  356. package/templates/app/packages/domain/package.json +5 -4
  357. package/templates/app/packages/domain/src/index.ts +4 -0
  358. package/templates/app/packages/domain/src/integrations/erp.ts +15 -0
  359. package/templates/app/packages/domain/src/integrations/intelligence.ts +20 -0
  360. package/templates/app/packages/domain/src/modules/inventory/index.ts +1 -0
  361. package/templates/app/packages/domain/src/modules/inventory/inventory.ts +12 -0
  362. package/templates/app/packages/domain/src/modules/purchase/approvals.ts +22 -1
  363. package/templates/app/packages/domain/src/modules/purchase/index.ts +1 -0
  364. package/templates/app/packages/domain/src/modules/purchase/intelligence.test.ts +62 -0
  365. package/templates/app/packages/domain/src/modules/purchase/jobs.ts +5 -0
  366. package/templates/app/packages/domain/src/modules/purchase/purchase-order.test.ts +9 -0
  367. package/templates/app/packages/domain/src/modules/purchase/purchase-order.ts +70 -0
  368. package/templates/app/packages/domain/src/modules/purchase/queries.ts +5 -0
  369. package/templates/app/packages/domain/src/workflows/purchase-inventory.ts +6 -0
  370. package/templates/app/packages/domain/src/workflows/purchase-process.ts +42 -0
  371. package/templates/blank/.dockerignore +2 -0
  372. package/templates/blank/.env.example +10 -0
  373. package/templates/blank/AGENTS.md +49 -9
  374. package/templates/blank/README.md +4 -1
  375. package/templates/blank/_gitignore +1 -0
  376. package/templates/blank/apps/api/package.json +1 -1
  377. package/templates/blank/apps/api/src/main.ts +4 -1
  378. package/templates/blank/apps/api/src/worker.ts +2 -0
  379. package/templates/blank/apps/web/index.html +1 -0
  380. package/templates/blank/apps/web/package.json +7 -3
  381. package/templates/blank/apps/web/src/app/app.tsx +80 -18
  382. package/templates/blank/apps/web/src/app/styles/global.css +90 -0
  383. package/templates/blank/apps/web/src/app/use-session.ts +43 -0
  384. package/templates/blank/apps/web/src/app/workspace-layout.tsx +30 -5
  385. package/templates/blank/apps/web/src/main.tsx +5 -0
  386. package/templates/blank/apps/web/src/modules/auth/index.ts +4 -0
  387. package/templates/blank/apps/web/src/modules/auth/pages/login-page.tsx +18 -1
  388. package/templates/blank/apps/web/src/modules/directory/index.ts +7 -0
  389. package/templates/blank/apps/web/src/modules/directory/pages/user-detail-page.tsx +78 -0
  390. package/templates/blank/apps/web/src/modules/directory/pages/users-page.tsx +93 -0
  391. package/templates/blank/apps/web/src/modules/workspace/index.ts +4 -0
  392. package/templates/blank/apps/web/src/modules/workspace/pages/home-page.tsx +17 -0
  393. package/templates/blank/apps/web/src/shared/lib/error-message.ts +11 -0
  394. package/templates/blank/apps/web/src/shared/lib/navigation.ts +21 -0
  395. package/templates/blank/apps/web/src/shared/ui/brand.tsx +10 -2
  396. package/templates/blank/apps/web/src/shared/ui/page-state.css +47 -0
  397. package/templates/blank/apps/web/src/shared/ui/page-state.tsx +76 -0
  398. package/templates/blank/apps/web/src/shared/ui/require-capability.tsx +34 -0
  399. package/templates/blank/apps/web/vite.config.ts +5 -0
  400. package/templates/blank/deploy/nginx.conf +52 -0
  401. package/templates/blank/docs/ai/README.md +21 -0
  402. package/templates/blank/docs/ai/architecture.md +26 -0
  403. package/templates/blank/docs/ai/commenting.md +203 -0
  404. package/templates/blank/docs/ai/diagnostics.md +80 -0
  405. package/templates/blank/docs/ai/files.md +93 -0
  406. package/templates/blank/docs/ai/intelligence.md +348 -0
  407. package/templates/blank/docs/ai/ontology-context.md +59 -4
  408. package/templates/blank/docs/ai/primitives.md +33 -0
  409. package/templates/blank/docs/ai/project-structure.md +8 -3
  410. package/templates/blank/docs/ai/purchase-example.md +16 -2
  411. package/templates/blank/docs/ai/recipes.md +9 -1
  412. package/templates/blank/docs/ai/routing.md +86 -0
  413. package/templates/blank/docs/ai/troubleshooting.md +5 -0
  414. package/templates/blank/docs/ai/workflow.md +24 -11
  415. package/templates/blank/docs/errors/CAGE-AI-001.md +61 -0
  416. package/templates/blank/docs/errors/CAGE-APPR-001.md +7 -6
  417. package/templates/blank/docs/errors/CAGE-APPR-002.md +2 -2
  418. package/templates/blank/docs/errors/CAGE-APPR-003.md +1 -1
  419. package/templates/blank/docs/errors/CAGE-APPR-004.md +4 -4
  420. package/templates/blank/docs/errors/CAGE-APPR-005.md +1 -1
  421. package/templates/blank/docs/errors/CAGE-APPR-006.md +12 -6
  422. package/templates/blank/docs/errors/CAGE-APPR-007.md +3 -3
  423. package/templates/blank/docs/errors/CAGE-APPR-010.md +5 -5
  424. package/templates/blank/docs/errors/CAGE-AUDIT-001.md +53 -0
  425. package/templates/blank/docs/errors/CAGE-AUTH-001.md +1 -1
  426. package/templates/blank/docs/errors/CAGE-BIZ-001.md +51 -0
  427. package/templates/blank/docs/errors/CAGE-BIZ-002.md +49 -0
  428. package/templates/blank/docs/errors/CAGE-BUDGET-001.md +1 -1
  429. package/templates/blank/docs/errors/CAGE-BUDGET-002.md +1 -1
  430. package/templates/blank/docs/errors/CAGE-BUDGET-003.md +1 -1
  431. package/templates/blank/docs/errors/CAGE-CMD-002.md +1 -1
  432. package/templates/blank/docs/errors/CAGE-CMD-003.md +1 -1
  433. package/templates/blank/docs/errors/CAGE-CONN-001.md +3 -3
  434. package/templates/blank/docs/errors/CAGE-CONN-002.md +1 -1
  435. package/templates/blank/docs/errors/CAGE-CONN-003.md +1 -1
  436. package/templates/blank/docs/errors/CAGE-CONN-004.md +1 -1
  437. package/templates/blank/docs/errors/CAGE-CONN-005.md +1 -1
  438. package/templates/blank/docs/errors/CAGE-CONN-006.md +1 -1
  439. package/templates/blank/docs/errors/CAGE-CONN-007.md +6 -6
  440. package/templates/blank/docs/errors/CAGE-CONN-008.md +5 -5
  441. package/templates/blank/docs/errors/CAGE-CONN-009.md +6 -6
  442. package/templates/blank/docs/errors/CAGE-CONN-010.md +6 -6
  443. package/templates/blank/docs/errors/CAGE-CONN-011.md +1 -1
  444. package/templates/blank/docs/errors/CAGE-CONN-012.md +1 -1
  445. package/templates/blank/docs/errors/CAGE-CONN-013.md +49 -0
  446. package/templates/blank/docs/errors/CAGE-CONN-014.md +48 -0
  447. package/templates/blank/docs/errors/CAGE-CONN-015.md +49 -0
  448. package/templates/blank/docs/errors/CAGE-CREATE-001.md +10 -9
  449. package/templates/blank/docs/errors/CAGE-DECL-001.md +2 -2
  450. package/templates/blank/docs/errors/CAGE-DECL-002.md +7 -6
  451. package/templates/blank/docs/errors/CAGE-DECL-003.md +1 -1
  452. package/templates/blank/docs/errors/CAGE-DECL-004.md +1 -1
  453. package/templates/blank/docs/errors/CAGE-DEP-001.md +2 -2
  454. package/templates/blank/docs/errors/CAGE-DEP-002.md +1 -1
  455. package/templates/blank/docs/errors/CAGE-DEP-003.md +2 -2
  456. package/templates/blank/docs/errors/CAGE-DEP-004.md +1 -1
  457. package/templates/blank/docs/errors/CAGE-DEP-005.md +1 -1
  458. package/templates/blank/docs/errors/CAGE-DIAG-001.md +53 -0
  459. package/templates/blank/docs/errors/CAGE-DLQ-001.md +2 -2
  460. package/templates/blank/docs/errors/CAGE-ENV-001.md +4 -4
  461. package/templates/blank/docs/errors/CAGE-ENV-002.md +51 -0
  462. package/templates/blank/docs/errors/CAGE-ENV-003.md +48 -0
  463. package/templates/blank/docs/errors/CAGE-EVENT-001.md +1 -1
  464. package/templates/blank/docs/errors/CAGE-EVENT-002.md +7 -7
  465. package/templates/blank/docs/errors/CAGE-FIELD-001.md +2 -2
  466. package/templates/blank/docs/errors/CAGE-FIELD-002.md +1 -1
  467. package/templates/blank/docs/errors/CAGE-FIELD-003.md +1 -1
  468. package/templates/blank/docs/errors/CAGE-FIELD-004.md +1 -1
  469. package/templates/blank/docs/errors/CAGE-FILE-001.md +56 -0
  470. package/templates/blank/docs/errors/CAGE-GEN-001.md +2 -2
  471. package/templates/blank/docs/errors/CAGE-GEN-002.md +1 -1
  472. package/templates/blank/docs/errors/CAGE-GEN-003.md +53 -0
  473. package/templates/blank/docs/errors/CAGE-GRANT-001.md +3 -3
  474. package/templates/blank/docs/errors/CAGE-GRANT-002.md +2 -2
  475. package/templates/blank/docs/errors/CAGE-GRANT-003.md +7 -6
  476. package/templates/blank/docs/errors/CAGE-IMPACT-001.md +2 -2
  477. package/templates/blank/docs/errors/CAGE-IMPACT-002.md +52 -0
  478. package/templates/blank/docs/errors/CAGE-INIT-001.md +1 -1
  479. package/templates/blank/docs/errors/CAGE-INIT-002.md +1 -1
  480. package/templates/blank/docs/errors/CAGE-INIT-003.md +2 -2
  481. package/templates/blank/docs/errors/CAGE-INIT-004.md +1 -1
  482. package/templates/blank/docs/errors/CAGE-INIT-005.md +52 -0
  483. package/templates/blank/docs/errors/CAGE-JOB-001.md +1 -1
  484. package/templates/blank/docs/errors/CAGE-JOB-002.md +1 -1
  485. package/templates/blank/docs/errors/CAGE-JOB-003.md +1 -1
  486. package/templates/blank/docs/errors/CAGE-LINT-001.md +1 -1
  487. package/templates/blank/docs/errors/CAGE-MIG-001.md +1 -1
  488. package/templates/blank/docs/errors/CAGE-MIG-002.md +1 -1
  489. package/templates/blank/docs/errors/CAGE-MIG-005.md +1 -1
  490. package/templates/blank/docs/errors/CAGE-NAME-001.md +1 -1
  491. package/templates/blank/docs/errors/CAGE-NAME-002.md +1 -1
  492. package/templates/blank/docs/errors/CAGE-NAME-003.md +3 -3
  493. package/templates/blank/docs/errors/CAGE-NAME-004.md +1 -1
  494. package/templates/blank/docs/errors/CAGE-NAME-005.md +1 -1
  495. package/templates/blank/docs/errors/CAGE-NAME-006.md +1 -1
  496. package/templates/blank/docs/errors/CAGE-ORG-001.md +7 -6
  497. package/templates/blank/docs/errors/CAGE-PAIR-002.md +6 -5
  498. package/templates/blank/docs/errors/CAGE-QUERY-001.md +1 -1
  499. package/templates/blank/docs/errors/CAGE-QUERY-002.md +2 -2
  500. package/templates/blank/docs/errors/CAGE-QUERY-003.md +7 -6
  501. package/templates/blank/docs/errors/CAGE-REACT-001.md +3 -3
  502. package/templates/blank/docs/errors/CAGE-REACT-002.md +1 -1
  503. package/templates/blank/docs/errors/CAGE-REACT-003.md +50 -0
  504. package/templates/blank/docs/errors/CAGE-READS-001.md +9 -6
  505. package/templates/blank/docs/errors/CAGE-REG-001.md +13 -12
  506. package/templates/blank/docs/errors/CAGE-REG-002.md +2 -1
  507. package/templates/blank/docs/errors/CAGE-REG-003.md +1 -1
  508. package/templates/blank/docs/errors/CAGE-REL-001.md +14 -14
  509. package/templates/blank/docs/errors/CAGE-ROUTE-001.md +7 -6
  510. package/templates/blank/docs/errors/CAGE-SCOPE-001.md +1 -1
  511. package/templates/blank/docs/errors/CAGE-SCOPE-002.md +2 -2
  512. package/templates/blank/docs/errors/CAGE-SECRET-001.md +2 -2
  513. package/templates/blank/docs/errors/CAGE-SECRET-002.md +1 -1
  514. package/templates/blank/docs/errors/CAGE-SENS-001.md +5 -5
  515. package/templates/blank/docs/errors/CAGE-SQL-001.md +1 -1
  516. package/templates/blank/docs/errors/CAGE-SQL-002.md +1 -1
  517. package/templates/blank/docs/errors/CAGE-STATE-001.md +3 -3
  518. package/templates/blank/docs/errors/CAGE-STATE-002.md +1 -1
  519. package/templates/blank/docs/errors/CAGE-STATE-003.md +1 -1
  520. package/templates/blank/docs/errors/CAGE-STATE-004.md +1 -1
  521. package/templates/blank/docs/errors/CAGE-STATE-005.md +3 -2
  522. package/templates/blank/docs/errors/CAGE-STATE-010.md +5 -5
  523. package/templates/blank/docs/errors/CAGE-STATE-011.md +5 -5
  524. package/templates/blank/docs/errors/CAGE-STRUCT-001.md +1 -1
  525. package/templates/blank/docs/errors/CAGE-STRUCT-002.md +1 -1
  526. package/templates/blank/docs/errors/CAGE-SYNC-001.md +3 -2
  527. package/templates/blank/docs/errors/CAGE-TEST-001.md +1 -1
  528. package/templates/blank/docs/errors/CAGE-TEST-002.md +50 -0
  529. package/templates/blank/docs/errors/CAGE-TEST-003.md +52 -0
  530. package/templates/blank/docs/errors/CAGE-UNSAFE-001.md +3 -2
  531. package/templates/blank/docs/errors/CAGE-UPGRADE-001.md +2 -2
  532. package/templates/blank/docs/errors/CAGE-WORKER-001.md +48 -0
  533. package/templates/blank/docs/errors/CAGE-WORKER-002.md +50 -0
  534. package/templates/blank/docs/errors/CAGE-WORKER-003.md +48 -0
  535. package/templates/blank/docs/errors/README.md +50 -0
  536. package/templates/blank/docs/examples/purchase-admin/apps/api/src/main.ts +5 -1
  537. package/templates/blank/docs/examples/purchase-admin/apps/api/src/worker.ts +3 -0
  538. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/app.tsx +122 -12
  539. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/styles/global.css +88 -8
  540. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/use-session.ts +43 -0
  541. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/workspace-layout.tsx +58 -19
  542. package/templates/blank/docs/examples/purchase-admin/apps/web/src/main.tsx +5 -0
  543. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +11 -0
  544. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/index.ts +4 -0
  545. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +20 -1
  546. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/index.ts +4 -0
  547. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/pages/login-page.tsx +12 -0
  548. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/index.ts +4 -0
  549. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/pages/inventory-page.tsx +29 -1
  550. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/approval-history.tsx +32 -0
  551. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/order-attachments.tsx +29 -0
  552. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-assistant-context.tsx +17 -0
  553. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-order-form.css +6 -0
  554. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-order-form.tsx +25 -3
  555. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/index.ts +5 -0
  556. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/lib/presentation.ts +20 -0
  557. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-intelligence.css +15 -0
  558. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-order-detail-page.tsx +154 -0
  559. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +52 -22
  560. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/workspace/index.ts +5 -0
  561. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/workspace/pages/home-page.tsx +44 -0
  562. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/hooks/use-command.ts +13 -0
  563. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/lib/error-message.ts +9 -0
  564. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/lib/navigation.ts +21 -0
  565. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-markdown.tsx +19 -0
  566. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-panel.css +134 -0
  567. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-panel.tsx +200 -0
  568. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-scope.tsx +72 -0
  569. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/attachment-upload.css +28 -0
  570. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/attachment-upload.tsx +163 -0
  571. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/notice.tsx +7 -0
  572. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-heading.tsx +7 -0
  573. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-state.css +47 -0
  574. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-state.tsx +76 -0
  575. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/require-capability.tsx +34 -0
  576. package/templates/blank/docs/examples/purchase-admin/cage.config.json +9 -0
  577. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/dept/index.ts +10 -10
  578. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/inventory/index.ts +5 -5
  579. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/inventory-lock/index.ts +4 -4
  580. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/purchase-order/index.ts +26 -12
  581. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/role/index.ts +15 -15
  582. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/user/index.ts +16 -16
  583. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/index.ts +7 -1
  584. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/queries/index.ts +2 -2
  585. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/index.ts +4 -0
  586. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/integrations/erp.ts +15 -0
  587. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/integrations/intelligence.ts +20 -0
  588. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/index.ts +1 -0
  589. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/inventory.ts +12 -0
  590. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/approvals.ts +22 -1
  591. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/index.ts +1 -0
  592. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/intelligence.test.ts +62 -0
  593. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/jobs.ts +5 -0
  594. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.test.ts +9 -0
  595. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.ts +70 -0
  596. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/queries.ts +5 -0
  597. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/workflows/purchase-inventory.ts +6 -0
  598. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/workflows/purchase-process.ts +42 -0
  599. package/templates/blank/package.json +3 -3
  600. package/templates/blank/packages/contracts/package.json +1 -1
  601. package/templates/blank/packages/contracts/src/aggregates/dept/index.ts +10 -10
  602. package/templates/blank/packages/contracts/src/aggregates/role/index.ts +15 -15
  603. package/templates/blank/packages/contracts/src/aggregates/user/index.ts +16 -16
  604. package/templates/blank/packages/contracts/src/index.ts +1 -1
  605. package/templates/blank/packages/contracts/src/queries/index.ts +1 -1
  606. package/templates/blank/packages/domain/package.json +5 -4
  607. package/templates/blank/packages/domain/src/index.ts +2 -1
@@ -1,3 +1,7 @@
1
+ /**
2
+ * 采购应用的全局视觉与布局基础,随浏览器入口加载;依次定义主题、工作台、业务表格、表单及登录页。
3
+ * 模块专用样式在模块附近维护。状态类只映射已有 UI 状态,不承担权限、审批或数据计算。
4
+ */
1
5
  /* 暖白纸面配墨绿导航;用边线、字重和留白建立信息层次,避免装饰压过业务数据。 */
2
6
  :root {
3
7
  font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
@@ -83,6 +87,9 @@ h3 {
83
87
  font-family: Consolas, 'Courier New', monospace;
84
88
  font-size: 12px;
85
89
  }
90
+ /**
91
+ * 固定侧栏与主内容区的桌面组合;窄屏规则在文件后部覆盖布局,保留导航可达性。
92
+ */
86
93
  .workspace {
87
94
  display: flex;
88
95
  min-height: 100vh;
@@ -124,7 +131,7 @@ nav {
124
131
  display: grid;
125
132
  gap: 7px;
126
133
  }
127
- nav button {
134
+ nav a {
128
135
  display: flex;
129
136
  align-items: center;
130
137
  gap: 16px;
@@ -134,22 +141,22 @@ nav button {
134
141
  text-align: left;
135
142
  padding: 14px 13px;
136
143
  }
137
- nav button span {
144
+ nav a span {
138
145
  font-size: 10px;
139
146
  opacity: 0.6;
140
147
  }
141
- nav button b {
148
+ nav a b {
142
149
  margin-left: auto;
143
150
  font-size: 11px;
144
151
  }
145
- nav button.selected {
152
+ nav a.selected {
146
153
  background: var(--accent);
147
154
  color: var(--green);
148
155
  }
149
- nav button:hover {
156
+ nav a:hover {
150
157
  background: #31594e;
151
158
  }
152
- nav button.selected:hover {
159
+ nav a.selected:hover {
153
160
  background: #d9efa9;
154
161
  }
155
162
  .aside-bottom {
@@ -301,6 +308,9 @@ header {
301
308
  .toolbar > button {
302
309
  font-size: 11px;
303
310
  }
311
+ /**
312
+ * 宽表格在容器中横向滚动,避免列内容把页面宽度撑出视口。
313
+ */
304
314
  .table-wrap {
305
315
  overflow: auto;
306
316
  }
@@ -470,6 +480,9 @@ input {
470
480
  input:focus {
471
481
  outline: 2px solid #b2cb8b;
472
482
  }
483
+ /**
484
+ * 创建弹窗的遮罩与居中层;具体采购弹窗高度及内部滚动由模块样式补充。
485
+ */
473
486
  .modal-backdrop {
474
487
  position: fixed;
475
488
  inset: 0;
@@ -560,6 +573,9 @@ input:focus {
560
573
  color: var(--muted);
561
574
  }
562
575
  /* 窄屏将导航转成横向工具栏,表格保留横向滚动,操作列不会挤成不可点击的小按钮。 */
576
+ /**
577
+ * 在九百像素及以下调整导航与表单布局,减少桌面侧栏对内容宽度的挤占。
578
+ */
563
579
  @media (max-width: 900px) {
564
580
  aside {
565
581
  position: static;
@@ -581,11 +597,11 @@ input:focus {
581
597
  display: flex;
582
598
  margin-top: 20px;
583
599
  }
584
- nav button {
600
+ nav a {
585
601
  flex: 1;
586
602
  padding: 10px;
587
603
  }
588
- nav button span {
604
+ nav a span {
589
605
  display: none;
590
606
  }
591
607
  .aside-bottom {
@@ -656,8 +672,72 @@ input:focus {
656
672
  padding: 10px;
657
673
  }
658
674
  }
675
+ /**
676
+ * 尊重系统减少动画偏好,避免将过渡效果作为理解操作反馈的唯一依据。
677
+ */
659
678
  @media (prefers-reduced-motion: reduce) {
660
679
  * {
661
680
  transition: none !important;
662
681
  }
663
682
  }
683
+
684
+ /* 链接保持原生导航语义,单据编号可复制地址或在新标签页打开。 */
685
+ .record-link {
686
+ color: var(--green);
687
+ font-weight: 600;
688
+ text-decoration: underline;
689
+ text-decoration-color: #c6d5b5;
690
+ text-underline-offset: 4px;
691
+ }
692
+ .record-link:hover {
693
+ text-decoration-color: var(--green);
694
+ }
695
+ .record-facts {
696
+ display: grid;
697
+ grid-template-columns: repeat(2, minmax(0, 1fr));
698
+ margin: 0;
699
+ padding: 8px 24px;
700
+ gap: 0 36px;
701
+ }
702
+ .record-facts > div {
703
+ padding: 22px 0;
704
+ border-bottom: 1px solid var(--line);
705
+ }
706
+ .record-facts dt {
707
+ color: var(--muted);
708
+ font-size: 11px;
709
+ margin-bottom: 11px;
710
+ }
711
+ .record-facts dd {
712
+ margin: 0;
713
+ font-size: 14px;
714
+ overflow-wrap: anywhere;
715
+ }
716
+ .entry-grid {
717
+ display: grid;
718
+ grid-template-columns: repeat(3, 1fr);
719
+ gap: 18px;
720
+ }
721
+ .entry-grid > a {
722
+ padding: 30px 25px;
723
+ background: #fff;
724
+ border: 1px solid var(--line);
725
+ border-radius: 6px;
726
+ }
727
+ .entry-grid > a:hover {
728
+ border-color: #99b47f;
729
+ background: #fafdf6;
730
+ }
731
+ .entry-grid small {
732
+ color: var(--muted);
733
+ font-size: 10px;
734
+ letter-spacing: 1px;
735
+ }
736
+ .entry-grid h2 {
737
+ margin: 24px 0 14px;
738
+ }
739
+ .entry-grid p {
740
+ font-size: 12px;
741
+ color: var(--muted);
742
+ line-height: 1.8;
743
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * 应用会话生命周期:首次加载 /me,并把 SDK 的账号退出或失效通知同步到路由状态。
3
+ * 与 URL 路由分离,网络故障不会被误判成未登录;查询缓存不能跨账号继续使用。
4
+ */
5
+ // 应用会话与 URL 导航分别管理:401 才进入登录,网络故障保留原地址并允许重试。
6
+ import { useCallback, useEffect, useState } from 'react';
7
+ import { useQueryClient } from '@tanstack/react-query';
8
+ import { client, loadMe } from '@app/contracts';
9
+
10
+ /**
11
+ * 在 QueryClientProvider 内使用。挂载时恢复用户,卸载时解除 SDK 订阅。
12
+ * 返回 session:loading 为恢复中,guest 为未认证,ready 为已加载身份,error 为其他恢复失败。
13
+ * restore 可重试恢复;onLogin/onLogout 由已完成认证动作的页面调用,只更新应用状态。
14
+ * 账号失效时发起取消查询并清空缓存;这里不负责服务端退出操作,也不保证取消已提交的业务命令。
15
+ */
16
+ export function useSession() {
17
+ const [session, setSession] = useState<'loading' | 'guest' | 'ready' | 'error'>('loading');
18
+ const cache = useQueryClient();
19
+ /**
20
+ * 每次恢复先显示 loading,再按 loadMe 的明确结果分类;只有 UNAUTHENTICATED 进入 guest。
21
+ */
22
+ const restore = useCallback(async () => {
23
+ setSession('loading');
24
+ const result = await loadMe();
25
+ setSession(result.ok ? 'ready' : result.code === 'UNAUTHENTICATED' ? 'guest' : 'error');
26
+ }, []);
27
+
28
+ useEffect(() => {
29
+ const unsubscribe = client.subscribe((_snapshot, reason) => {
30
+ if (reason === 'loaded') return;
31
+ // 先取消在途查询,再清除上一账号的缓存;路由守卫保留 URL 并决定登录回跳。
32
+ void cache.cancelQueries();
33
+ cache.clear();
34
+ setSession('guest');
35
+ });
36
+ void restore();
37
+ return () => {
38
+ unsubscribe();
39
+ };
40
+ }, [cache, restore]);
41
+
42
+ return { session, restore, onLogin: () => setSession('ready'), onLogout: () => setSession('guest') };
43
+ }
@@ -1,35 +1,65 @@
1
+ /**
2
+ * 已登录工作台的公共外壳:导航、当前账号、退出登录、Outlet 和唯一的业务助理。
3
+ * 业务页面经路由模块入口进入 Outlet;系统管理使用独立链接。
4
+ * 助理随页面更新语义快照,账号退出成功后清空查询缓存。
5
+ */
1
6
  // 应用壳组合模块公开入口,只持有导航和会话;表单、筛选、命令留在各业务模块。
2
7
  import { useState } from 'react';
8
+ import { Link, NavLink, Outlet, useLocation } from 'react-router-dom';
3
9
  import { useQueryClient } from '@tanstack/react-query';
4
10
  import { client, currentUser } from '@app/contracts';
5
- import { PurchaseOrdersPage } from '../modules/purchase';
6
- import { InventoryPage } from '../modules/inventory';
7
- import { ApprovalTasksPage, useApprovalTasks } from '../modules/approval';
11
+ import { useApprovalTasks } from '../modules/approval';
12
+ import { errorMessage } from '../shared/lib/error-message';
13
+ import { AssistantScope } from '../shared/ui/assistant-scope';
8
14
 
15
+ /**
16
+ * 渲染工作台公共区域并把子路由放入内容区。
17
+ * @param onLogout SDK 退出成功后通知 app 切换会话状态的回调。
18
+ * 本壳提供固定导航入口;目标路由和服务端分别处理页面访问与真实请求的权限。
19
+ * location.key 标识一次页面导航,用于防止新页面沿用上一张单据的助理上下文。
20
+ */
9
21
  export function WorkspaceLayout({ onLogout }: { onLogout: () => void }) {
10
- const [tab, setTab] = useState<'orders' | 'tasks' | 'stock'>('orders');
22
+ const [error, setError] = useState('');
23
+ const [busy, setBusy] = useState(false);
24
+ const location = useLocation();
25
+ const page = location.pathname.startsWith('/procurement/orders/')
26
+ ? '采购单详情'
27
+ : location.pathname === '/procurement/orders'
28
+ ? '采购单'
29
+ : location.pathname === '/approvals'
30
+ ? '审批待办'
31
+ : location.pathname === '/inventory'
32
+ ? '库存台账'
33
+ : location.pathname === '/workspace'
34
+ ? '工作台'
35
+ : '页面';
11
36
  const tasks = useApprovalTasks();
12
37
  const cache = useQueryClient();
13
38
  return (
39
+ <AssistantScope pageKey={location.key} fallback={{
40
+ context: { page: { id: 'workspace-page', title: page, kind: 'custom', route: location.pathname + location.search } },
41
+ suggestions: ['我在当前页面可以做什么?', '帮我查看待处理的审批'],
42
+ }}>
14
43
  <div className="workspace">
15
44
  <aside>
16
- <a className="brand" href="/">
45
+ <Link className="brand" to="/workspace">
17
46
  cage<span>采购工作台</span>
18
- </a>
47
+ </Link>
19
48
  <span className="nav-caption">工作空间</span>
20
49
  <nav>
21
50
  {(
22
51
  [
23
- ['orders', '01', '采购单'],
24
- ['tasks', '02', '审批待办'],
25
- ['stock', '03', '库存台账'],
52
+ ['/workspace', '00', '工作台'],
53
+ ['/procurement/orders', '01', '采购单'],
54
+ ['/approvals', '02', '审批待办'],
55
+ ['/inventory', '03', '库存台账'],
26
56
  ] as const
27
57
  ).map(([key, no, label]) => (
28
- <button key={key} className={tab === key ? 'selected' : ''} onClick={() => setTab(key)}>
58
+ <NavLink key={key} to={key} className={({ isActive }) => (isActive ? 'selected' : '')}>
29
59
  <span>{no}</span>
30
60
  {label}
31
- {key === 'tasks' && <b>{tasks.data?.length ?? 0}</b>}
32
- </button>
61
+ {key === '/approvals' && <b>{tasks.data?.length ?? 0}</b>}
62
+ </NavLink>
33
63
  ))}
34
64
  </nav>
35
65
  <div className="aside-bottom">
@@ -43,10 +73,15 @@ export function WorkspaceLayout({ onLogout }: { onLogout: () => void }) {
43
73
  </div>
44
74
  <button
45
75
  className="logout"
76
+ disabled={busy}
46
77
  onClick={async () => {
47
- await client.logout();
48
- cache.clear();
49
- onLogout();
78
+ setBusy(true);
79
+ const result = await client.logout();
80
+ setBusy(false);
81
+ if (result.ok) {
82
+ cache.clear();
83
+ onLogout();
84
+ } else setError(errorMessage(result));
50
85
  }}
51
86
  >
52
87
  退出登录
@@ -55,16 +90,20 @@ export function WorkspaceLayout({ onLogout }: { onLogout: () => void }) {
55
90
  </aside>
56
91
  <main className="content">
57
92
  <header>
58
- <span>采购管理 / {tab === 'orders' ? '采购单' : tab === 'tasks' ? '审批待办' : '库存台账'}</span>
93
+ <span>采购管理 / {page}</span>
59
94
  <span className="live-dot">团队工作空间</span>
60
95
  </header>
61
- {tab === 'orders' && <PurchaseOrdersPage pendingTasks={tasks.data?.length} />}
62
- {tab === 'tasks' && <ApprovalTasksPage />}
63
- {tab === 'stock' && <InventoryPage />}
96
+ {error && (
97
+ <p className="error" role="alert">
98
+ {error}
99
+ </p>
100
+ )}
101
+ <Outlet />
64
102
  <div className="page-footer">
65
103
  CAGE / PROCUREMENT WORKSPACE<span>业务操作均受权限与数据范围约束</span>
66
104
  </div>
67
105
  </main>
68
106
  </div>
107
+ </AssistantScope>
69
108
  );
70
109
  }
@@ -1,3 +1,8 @@
1
+ /**
2
+ * 采购 Web 的浏览器启动入口:创建共享查询缓存,将应用路由挂到 root DOM 节点。
3
+ * 契约客户端负责网络与会话协议,页面只在 Provider 内消费 hooks;这里不注册领域或启动后端。
4
+ * 全局样式在此加载,账号切换时的缓存清理由 useSession 和应用壳负责。
5
+ */
1
6
  // 唯一浏览器启动入口:挂载 React、全局 Provider 和样式;业务从 app 组合进入。
2
7
  import { createRoot } from 'react-dom/client';
3
8
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
@@ -1,13 +1,24 @@
1
+ /**
2
+ * 当前账号审批待办的共享查询入口,供审批页及 app 的数量组合复用同一缓存键。
3
+ * 任务分配与实际决策授权均来自服务端,不从角色名称在前端自行推导。
4
+ */
1
5
  import { useQuery } from '@tanstack/react-query';
2
6
  import { client } from '@app/contracts';
3
7
  import { errorMessage } from '../../../shared/lib/error-message';
4
8
 
9
+ /**
10
+ * 待办列表展示所需字段:id 是任务标识,businessKey 是业务记录键,title 为任务标题,createdAt 为创建时间字符串。
11
+ */
5
12
  type Task = { id: string; businessKey: string; title: string; createdAt: string };
6
13
 
7
14
  /**
8
15
  * 审批是框架通用接口,不属于某个聚合的生成方法,因此请求封装在审批模块内。
9
16
  * 待办页面和导航角标复用同一缓存键,调用方不需要了解接口地址或响应形状。
10
17
  */
18
+ /**
19
+ * 在 React Query 中读取审批待办,非 ok 结果转为查询错误。
20
+ * 返回查询状态及 refetch;空数组表示当前结果没有待办,未加载或失败不等同于零条。
21
+ */
11
22
  export function useApprovalTasks() {
12
23
  return useQuery({
13
24
  queryKey: ['tasks'],
@@ -1,2 +1,6 @@
1
+ /**
2
+ * approval 模块的公开入口,对 app 暴露审批待办页与共享待办查询。
3
+ * 外部组合通过本入口导入,页面、组件与内部 helper 的组织由模块自行维护。
4
+ */
1
5
  export { ApprovalTasksPage } from './pages/approval-tasks-page';
2
6
  export { useApprovalTasks } from './hooks/use-approval-tasks';
@@ -1,15 +1,29 @@
1
+ /**
2
+ * 个人审批待办页,展示服务端分配的任务并调用标准审批接口提交结论。
3
+ * 通过 app 注入业务详情链接,避免审批模块直接依赖采购页面文件。
4
+ */
1
5
  // 审批待办独立成页;结论调用框架审批接口,领域约束仍在后端执行。
2
6
  import { client } from '@app/contracts';
7
+ import { Link } from 'react-router-dom';
3
8
  import { useCommand } from '../../../shared/hooks/use-command';
4
9
  import { Notice } from '../../../shared/ui/notice';
5
10
  import { PageHeading } from '../../../shared/ui/page-heading';
6
11
  import { useApprovalTasks } from '../hooks/use-approval-tasks';
12
+ import { AssistantPage } from '../../../shared/ui/assistant-scope';
7
13
 
8
- export function ApprovalTasksPage() {
14
+ /**
15
+ * 查询待办并区分加载、失败与已清空状态;按钮使用 useCommand 共享忙碌及消息反馈。
16
+ * @param orderUrl 由 app 将 businessKey 转为采购详情 URL 的函数。
17
+ * 通过/驳回/退回对应不同后端流程,页面不直接更新单据状态;成功后刷新查询取得真实任务变化。
18
+ */
19
+ export function ApprovalTasksPage({ orderUrl }: { orderUrl: (id: string) => string }) {
9
20
  const tasks = useApprovalTasks();
10
21
  const { run, busy, message, clearMessage } = useCommand();
11
22
  return (
12
23
  <>
24
+ <AssistantPage context={{ page: { id: 'approval-inbox', title: '审批待办', kind: 'list', route: '/approvals' },
25
+ visibleContent: [{ id: 'pending-tasks', text: tasks.data ? `当前待处理审批 ${tasks.data.length} 项,以重新查询的待办为准。` : '审批待办正在读取或暂时不可用。' }],
26
+ }} suggestions={['查看当前待我处理的审批', '通过、驳回和退回修改有什么区别?']} />
13
27
  <PageHeading eyebrow="APPROVAL INBOX" title="审批待办" description="处理分配给你的审批任务。" />
14
28
  {message && <Notice onClose={clearMessage}>{message}</Notice>}
15
29
  <section className="panel">
@@ -26,12 +40,17 @@ export function ApprovalTasksPage() {
26
40
  <p className="mono muted">PO-{task.businessKey.slice(0, 8).toUpperCase()}</p>
27
41
  </div>
28
42
  <div className="actions">
43
+ {/* 单据的页面地址由 app 组合层提供,审批模块不依赖采购页面内部文件。 */}
44
+ <Link className="route-link" to={orderUrl(task.businessKey)}>
45
+ 查看采购单 ↗
46
+ </Link>
29
47
  <button
30
48
  disabled={busy}
31
49
  onClick={() => run(() => client.post(`/api/approval/tasks/${task.id}/reject`), '已驳回')}
32
50
  >
33
51
  驳回
34
52
  </button>
53
+ <button disabled={busy} onClick={() => run(() => client.post(`/api/approval/tasks/${task.id}/return`), '已退回修改')}>退回修改</button>
35
54
  <button
36
55
  disabled={busy}
37
56
  className="primary"
@@ -1 +1,5 @@
1
+ /**
2
+ * auth 模块的公开入口,对 app 暴露登录页。
3
+ * 外部组合通过本入口导入,页面、组件与内部 helper 的组织由模块自行维护。
4
+ */
1
5
  export { LoginPage } from './pages/login-page';
@@ -1,11 +1,23 @@
1
+ /**
2
+ * 采购应用认证页面,收集账号密码并调用契约客户端登录。
3
+ * 会话协议和当前能力同步由 SDK 负责;成功后的安全回跳交给 app 路由层。
4
+ */
1
5
  // 登录页属于认证模块;表单反馈留在模块内,会话切换由 app 处理。
2
6
  import { useState, type FormEvent } from 'react';
3
7
  import { client } from '@app/contracts';
4
8
  import { errorMessage } from '../../../shared/lib/error-message';
5
9
 
10
+ /**
11
+ * 维护提交中与失败提示,成功调用 onLogin 通知路由切换。
12
+ * 不在组件内持久化密码,不自行跳转未校验的 returnTo。
13
+ */
6
14
  export function LoginPage({ onLogin }: { onLogin: () => void }) {
7
15
  const [error, setError] = useState('');
8
16
  const [busy, setBusy] = useState(false);
17
+ /**
18
+ * 阻止浏览器原生表单跳转,读取本次输入并等待 client.login。
19
+ * 成功后由 app 进入已登录路由;错误通过统一映射显示,输入与凭证不写入日志。
20
+ */
9
21
  async function submit(event: FormEvent<HTMLFormElement>) {
10
22
  event.preventDefault();
11
23
  setBusy(true);
@@ -1 +1,5 @@
1
+ /**
2
+ * inventory 模块的公开入口,对 app 暴露库存页。
3
+ * 外部组合通过本入口导入,页面、组件与内部 helper 的组织由模块自行维护。
4
+ */
1
5
  export { InventoryPage } from './pages/inventory-page';
@@ -1,14 +1,43 @@
1
+ /**
2
+ * 库存示例页,读取库存安全列表并通过生成命令创建库存记录。
3
+ * 这只是采购范例中的库存展示与输入入口,资源占用和释放仍通过领域流程落实。
4
+ */
1
5
  // 库存模块只管理台账页面,登记物料通过生成的 Inventory.create 命令。
2
6
  import { can, inventory, useInventoryList } from '@app/contracts';
3
7
  import { useCommand } from '../../../shared/hooks/use-command';
4
8
  import { Notice } from '../../../shared/ui/notice';
5
9
  import { PageHeading } from '../../../shared/ui/page-heading';
10
+ import { QueryFailure } from '../../../shared/ui/page-state';
11
+ import { AssistantPage } from '../../../shared/ui/assistant-scope';
6
12
 
13
+ /**
14
+ * 读取最多前一百条库存并展示查询失败、加载和空结果;列表不代表系统全部库存。
15
+ * 创建成功后重置表单并刷新查询,失败保留输入。助理上下文只列当前可见记录 ID,服务端仍核验读取范围。
16
+ */
7
17
  export function InventoryPage() {
8
18
  const stock = useInventoryList({ pageSize: 100 });
9
19
  const { run, busy, message, clearMessage } = useCommand();
20
+ if (stock.isPending)
21
+ return (
22
+ <p className="empty" role="status">
23
+ 正在读取库存台账…
24
+ </p>
25
+ );
26
+ // 页面已打开后权限仍可能变化,必须处理安全接口的拒绝,不能把失败展示成空台账。
27
+ if (stock.isError)
28
+ return (
29
+ <QueryFailure
30
+ error={stock.error}
31
+ to="/workspace"
32
+ label="返回工作台"
33
+ retry={() => void stock.refetch()}
34
+ />
35
+ );
10
36
  return (
11
37
  <>
38
+ <AssistantPage context={{ page: { id: 'inventory', title: '库存台账', kind: 'list', route: '/inventory' },
39
+ view: { aggregate: 'Inventory', input: { pageSize: 100 }, visibleIds: stock.data.items.map(item => item.id) },
40
+ }} suggestions={['汇总当前可见的物料库存', '查询库存时有哪些权限限制?']} />
12
41
  <PageHeading eyebrow="INVENTORY" title="库存台账" description="查看物料与当前登记数量。" />
13
42
  {message && <Notice onClose={clearMessage}>{message}</Notice>}
14
43
  <section className="panel">
@@ -48,7 +77,6 @@ export function InventoryPage() {
48
77
  </button>
49
78
  </form>
50
79
  )}
51
- {stock.isError && <p className="error">{stock.error.message}</p>}
52
80
  <table>
53
81
  <thead>
54
82
  <tr>
@@ -0,0 +1,32 @@
1
+ /**
2
+ * 采购单审批轨迹展示,按单据与版本读取服务端整理后的轮次和步骤。
3
+ * AI 与人工状态使用同一记录来源;受限详情不显示理由,不能根据缺少细节推断未执行。
4
+ */
5
+ import { useQuery } from '@tanstack/react-query';
6
+ import { client } from '@yss123/cage-client';
7
+
8
+ /**
9
+ * 运行、步骤与人工待办状态的展示映射,未知状态仍由页面按实际值处理。
10
+ */
11
+ const status: Record<string, string> = { queued: '待执行', running: '处理中', passed: '已通过', approved: '已通过', returned: '已退回修改', rejected: '已拒绝', manual: '待人工接管', waiting_manual: '待人工接管', waiting: '待人工审批', cancelled: '已取消', failed: '执行失败', pending: '待处理', skipped: '未执行' };
12
+ /**
13
+ * id 为采购单标识,version 使业务变更后查询重新取数,pending 决定是否每 1500ms 刷新。
14
+ * 只显示历史,不执行审批;detailRestricted 分支尊重服务端裁剪,人工接管也不等于通过。
15
+ */
16
+ export function ApprovalHistory({ id, version, pending }: { id: string; version: number; pending: boolean }) {
17
+ const history = useQuery({ queryKey: ['approval-history', id, version], queryFn: async () => {
18
+ const result = await client.approvalHistory('PurchaseOrder', id);
19
+ if (!result.ok) throw new Error(`审批记录读取失败:${result.code}`);
20
+ return result.data;
21
+ }, refetchInterval: pending ? 1500 : false });
22
+ return <section className="panel approval-history"><div className="section-head"><h2>审批记录</h2><span className="muted">退回后重新提交,从第一步重新审核</span></div>
23
+ {history.isPending && <p className="muted">正在读取审核记录…</p>}
24
+ {history.isError && <p role="alert">{history.error.message}</p>}
25
+ {history.data?.length === 0 && <p className="muted">提交后先进入 AI 材料预审,再按流程交由人工审批。</p>}
26
+ {history.data?.map((round, index) => <div className="review-round" key={round.id}><h3>第 {history.data.length - index} 轮 · {status[round.status] ?? round.status}</h3>
27
+ {round.steps.map(step => <div className="review-step" key={step.index}><strong>{step.index + 1}. {step.kind === 'ai' ? 'AI 材料预审' : '人工审批'} · {status[step.status] ?? step.status}</strong>
28
+ {step.detailRestricted ? <p>当前权限无法查看审核解释。</p> : <>{step.decision && <p>{step.decision.reason}</p>}{step.decision?.suggestions.map((text, i) => <p className="review-suggestion" key={i}>{text}</p>)}</>}
29
+ </div>)}
30
+ </div>)}
31
+ </section>;
32
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * 采购详情的附件展示与草稿编辑区,将上传准备和领域关联保存明确分开。
3
+ * 读取到新版本后重新采用服务端附件列表并收起编辑,避免旧草稿覆盖已变化记录。
4
+ */
5
+ import { useEffect, useState } from 'react';
6
+ import { can, purchaseOrder, PurchaseOrderFileFields, type PurchaseOrder } from '@app/contracts';
7
+ import { AttachmentUpload, FileLink } from '../../../shared/ui/attachment-upload';
8
+ import { useCommand } from '../../../shared/hooks/use-command';
9
+
10
+ /**
11
+ * order 为已读取的采购记录,包含版本、状态和已绑定附件 ID。
12
+ * 仅草稿且具有 setAttachments 能力时显示编辑入口;保存传入 id 与 version,服务端重新校验。
13
+ * value 是临时选择列表,移除或上传不会自动修改单据;成功后的缓存刷新带回正式结果。
14
+ */
15
+ export function OrderAttachments({ order }: { order: PurchaseOrder }) {
16
+ const [editing, setEditing] = useState(false);
17
+ const [value, setValue] = useState(order.attachments);
18
+ const [uploading, setUploading] = useState(false);
19
+ const { run, busy, message } = useCommand();
20
+ useEffect(() => { setValue(order.attachments); setEditing(false); }, [order.version, order.attachments]);
21
+ return <section aria-label="采购附件">
22
+ <div className="section-head"><h2>采购附件</h2>{order.status === 'draft' && can('PurchaseOrder.setAttachments') && <button type="button" onClick={() => setEditing(!editing)}>{editing ? '收起编辑' : '编辑附件'}</button>}</div>
23
+ {editing ? <>
24
+ <AttachmentUpload command="PurchaseOrder.setAttachments" field="attachments" targetId={order.id} policy={PurchaseOrderFileFields.attachments} value={value} onChange={setValue} onBusyChange={setUploading} />
25
+ <button type="button" disabled={uploading || busy} onClick={() => run(() => purchaseOrder.setAttachments(order.id, { attachments: value }, order.version), '附件已保存')}>保存附件</button>
26
+ {message && <p role="status">{message}</p>}
27
+ </> : order.attachments.length ? <ul>{order.attachments.map(id => <li key={id}><FileLink id={id} /></li>)}</ul> : <p className="muted">暂无附件</p>}
28
+ </section>;
29
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * 采购模块与公共助理之间的语义适配层,提供采购字段、命令的中文展示名称。
3
+ * 页面通过 context 显式传入当前所见,不导入领域运行时或自行获取越权数据。
4
+ */
5
+ import type { PageContextInput } from '@yss123/cage-client';
6
+ import { AssistantPage } from '../../../shared/ui/assistant-scope';
7
+
8
+ // 页面只补充业务文案与上下文,工具发现、授权及命令执行全部使用框架 SDK。
9
+ /**
10
+ * 将页面快照与建议问题注册到最近的 AssistantScope,不再创建第二个面板。
11
+ * context 中的记录/草稿来源由页面负责;标签仅用于确认展示,工具与授权仍来自框架。
12
+ */
13
+ export function PurchaseAssistantContext({ context, suggestions }: { context: PageContextInput; suggestions: string[] }) {
14
+ return <AssistantPage context={context} suggestions={suggestions}
15
+ fieldLabels={{ reason: '采购用途', amount: '金额', items: '物料', key: '偏好名称', value: '偏好内容', comment: '审批意见', outcome: '审批结果' }}
16
+ commandLabels={{ 'PurchaseOrder.submit': '提交采购审批', 'PurchaseOrder.explainPurpose': '保存采购用途', 'PurchaseOrder.cancel': '取消采购单', 'PurchaseOrder.create': '新建采购单' }} />;
17
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 采购创建弹窗的高度与滚动约束。附件任务和恢复列表可能增高表单,使用动态视口高度保留边距。
3
+ * 滚动在弹窗内完成,限制滚动传播,确保保存按钮在窄屏仍可滚动到达。
4
+ */
5
+ /* 附件与恢复任务会增加表单高度;滚动留在弹窗内,保证窄屏仍可完成保存。 */
6
+ .purchase-order-dialog { max-height: calc(100dvh - 48px); overflow-y: auto; overscroll-behavior: contain; }