@oj-module/cli 0.2.64 → 0.2.67

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 (369) hide show
  1. package/bin/.oj-version +1 -0
  2. package/bin/oj +4 -0
  3. package/devkit/README.md +18 -4
  4. package/devkit/SKILL.md +35 -3
  5. package/devkit/framework-dev.md +22 -11
  6. package/devkit/manual.md +161 -68
  7. package/devkit/menu-rules.md +4 -1
  8. package/devkit/publish-walkthrough.md +110 -37
  9. package/devkit/wecom-internal-app.md +7 -2
  10. package/devkit/wecom-multi-corp-links.md +163 -0
  11. package/package.json +3 -2
  12. package/shell-dist/assets/ahooks.2l850ymmh0.js +18 -0
  13. package/shell-dist/assets/antd-es-locale-zh_CN.1gjjsvxbf0.js +1 -0
  14. package/shell-dist/assets/antd-img-crop.196rkty480.js +99 -0
  15. package/shell-dist/assets/antd-locale-en_US.561tozx860.js +1 -0
  16. package/shell-dist/assets/antd-locale-zh_CN.1cmpmgzh70.js +1 -0
  17. package/shell-dist/assets/antd.uw1coq15l0.js +348 -0
  18. package/shell-dist/assets/clsx.jotilrt2e0.js +1 -0
  19. package/shell-dist/assets/contract-errors.2o17vz9u50.js +1 -0
  20. package/shell-dist/assets/contract.3h327o3mj0.js +57 -0
  21. package/shell-dist/assets/cssinjs.atgmhan7m0.js +3 -0
  22. package/shell-dist/assets/dayjs-plugin-advancedFormat.3vsyd2eis0.js +1 -0
  23. package/shell-dist/assets/dayjs-plugin-customParseFormat.13xhghv1d0.js +1 -0
  24. package/shell-dist/assets/dayjs-plugin-isoWeek.1fn1tw82p0.js +1 -0
  25. package/shell-dist/assets/dayjs-plugin-localeData.2rwbjp9nk0.js +1 -0
  26. package/shell-dist/assets/dayjs-plugin-quarterOfYear.2oqo1lcx80.js +1 -0
  27. package/shell-dist/assets/dayjs-plugin-relativeTime.2pqs3et4y0.js +1 -0
  28. package/shell-dist/assets/dayjs-plugin-weekOfYear.gvn9iph080.js +1 -0
  29. package/shell-dist/assets/dayjs-plugin-weekYear.2u78l3ex10.js +1 -0
  30. package/shell-dist/assets/dayjs-plugin-weekday.2d56a4tml0.js +1 -0
  31. package/shell-dist/assets/dayjs.pa60l6wjo0.js +1 -0
  32. package/shell-dist/assets/dnd-kit-core.1xyreig6r0.js +5 -0
  33. package/shell-dist/assets/dnd-kit-sortable.s94qciuft0.js +1 -0
  34. package/shell-dist/assets/dnd-kit-utilities.1umw4xphb0.js +1 -0
  35. package/shell-dist/assets/i18next.33zqofapj0.js +1 -0
  36. package/shell-dist/assets/icons-es-components-Context.365qmflwg0.js +1 -0
  37. package/shell-dist/assets/icons.159wjwals0.js +57 -0
  38. package/shell-dist/assets/{index-xZhmujjM.js → index.6alqyx6ae0.js} +21 -1
  39. package/shell-dist/assets/jsx-dev-runtime.3uibuc82f0.js +14 -0
  40. package/shell-dist/assets/jsx-runtime.h40xu4o5b0.js +14 -0
  41. package/shell-dist/assets/keepalive-for-react.xenu5vam70.js +1 -0
  42. package/shell-dist/assets/kit.37kr8ui390.js +1 -0
  43. package/shell-dist/assets/ky.1cgch7gu60.js +6 -0
  44. package/shell-dist/assets/motion-react.pjsxytvjs0.js +12 -0
  45. package/shell-dist/assets/motion.21tciqutg0.js +4 -0
  46. package/shell-dist/assets/nprogress.2nz76n9ny0.js +7 -0
  47. package/shell-dist/assets/ojm-dayjs-locale-zh-cn.3vr3beiyp0.js +9 -0
  48. package/shell-dist/assets/pinyin-pro.3v0mnxczn0.js +1 -0
  49. package/shell-dist/assets/pro-components.2kyot1vcl0.js +83 -0
  50. package/shell-dist/assets/react-countup.2x8idnr8y0.js +10 -0
  51. package/shell-dist/assets/react-dom-client.ick0v05ob0.js +43 -0
  52. package/shell-dist/assets/react-dom.2so9uxg3f0.js +22 -0
  53. package/shell-dist/assets/react-error-boundary.2dncdfj3b0.js +1 -0
  54. package/shell-dist/assets/react-i18next.auhvjhqv00.js +1 -0
  55. package/shell-dist/assets/react-jss.1ei6dr9e00.js +29 -0
  56. package/shell-dist/assets/react-query.3rln45ow00.js +1 -0
  57. package/shell-dist/assets/react-router-dom.3c6zld8h40.js +44 -0
  58. package/shell-dist/assets/react-router.2h9rebcv50.js +56 -0
  59. package/shell-dist/assets/react.1ew63mwts0.js +14 -0
  60. package/shell-dist/assets/runtime.2dgstpjsu0.js +21702 -0
  61. package/shell-dist/assets/simplebar-react.2g739uvai0.js +1 -0
  62. package/shell-dist/assets/spin-delay.yjeyj6iwp0.js +9 -0
  63. package/shell-dist/assets/tailwind-merge.125ehiqjw0.js +1 -0
  64. package/shell-dist/assets/use-sync-external-store-shim.1nz1pi9bb0.js +22 -0
  65. package/shell-dist/assets/zustand-middleware.1xaxjueme0.js +6 -0
  66. package/shell-dist/assets/zustand-react-shallow.pybayv1hx0.js +1 -0
  67. package/shell-dist/assets/zustand-react.9fsl9brxy0.js +1 -0
  68. package/shell-dist/assets/zustand-shallow.6cz0yyv9x0.js +1 -0
  69. package/shell-dist/assets/zustand-vanilla-shallow.3424monv50.js +1 -0
  70. package/shell-dist/assets/zustand-vanilla.1mo3ka3g30.js +1 -0
  71. package/shell-dist/assets/zustand.3gjgzlnqo0.js +1 -0
  72. package/shell-dist/index.html +67 -118
  73. package/shell-dist/versions.json +3 -3
  74. package/src/__tests__/publish-keygen.test.ts +157 -0
  75. package/src/__tests__/templates-migration-schema-parity.test.ts +540 -0
  76. package/src/__tests__/templates-schema-columns.test.ts +15 -2
  77. package/src/__tests__/templates-tenant-scope.test.ts +6 -2
  78. package/src/bundle.ts +8 -3
  79. package/src/cli.ts +17 -5
  80. package/src/dev.ts +15 -10
  81. package/src/esm-exports.ts +152 -70
  82. package/src/install.ts +11 -4
  83. package/src/keygen.ts +54 -0
  84. package/src/lifecycle/__tests__/bundle.test.ts +21 -3
  85. package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/manifest.yaml +1 -1
  86. package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/migrations/0001__init.sql +2 -2
  87. package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/schema.yaml +5 -2
  88. package/src/lifecycle/__tests__/fixtures/fixture-valid/manifest.yaml +1 -1
  89. package/src/lifecycle/__tests__/manifest-contract.test.ts +75 -3
  90. package/src/lifecycle/__tests__/smoke.test.ts +2 -2
  91. package/src/manifest-contract.ts +91 -8
  92. package/src/market/bootstrap.ts +26 -2
  93. package/src/market/command.ts +1 -0
  94. package/src/market/publish.ts +5 -1
  95. package/src/market/walkthrough.ts +24 -8
  96. package/src/shared-deps.ts +69 -19
  97. package/src/site-base.ts +4 -0
  98. package/src/site.ts +2 -0
  99. package/src/usage.ts +8 -4
  100. package/src/vendor.ts +5 -1
  101. package/templates/config.yaml +4 -2
  102. package/templates/init.include.yaml +8 -3
  103. package/templates/openapi.json +460 -1
  104. package/templates/src/app/api/_platform/_lifecycle/compensate.ts +136 -0
  105. package/templates/src/app/api/_platform/_lifecycle/installer.ts +71 -22
  106. package/templates/src/app/api/_platform/_lifecycle/lock.ts +23 -0
  107. package/templates/src/app/api/_platform/_lifecycle/steps/deploy-web.ts +28 -0
  108. package/templates/src/app/api/_platform/_lifecycle/steps/preflight.ts +46 -0
  109. package/templates/src/app/api/_platform/_lifecycle/steps/reload.ts +100 -36
  110. package/templates/src/app/api/_platform/_lifecycle/steps/smoke.ts +7 -15
  111. package/templates/src/app/api/_platform/_lifecycle/text-edit.ts +71 -19
  112. package/templates/src/app/api/_platform/_lifecycle/types.ts +26 -2
  113. package/templates/src/app/api/_platform/_lifecycle/uninstall.ts +93 -14
  114. package/templates/src/app/api/_platform/_shared/service/domain/settings.ts +8 -4
  115. package/templates/src/app/api/_platform/manifest.yaml +1 -0
  116. package/templates/src/app/api/_platform/market/api.ts +235 -10
  117. package/templates/src/app/api/_platform/migrations/0001__baseline.mysql.sql +178 -0
  118. package/templates/src/app/api/_platform/migrations/0001__baseline.pg.sql +173 -0
  119. package/templates/src/app/api/_platform/migrations/0001__baseline.sql +188 -0
  120. package/templates/src/app/api/_platform/migrations/0002__market_release.mysql.sql +17 -0
  121. package/templates/src/app/api/_platform/migrations/0002__market_release.pg.sql +16 -0
  122. package/templates/src/app/api/_platform/migrations/0002__market_release.sql +33 -0
  123. package/templates/src/app/api/_platform/schema.yaml +18 -0
  124. package/templates/src/app/api/_platform/seed.mysql.sql +10 -0
  125. package/templates/src/app/api/_platform/seed.pg.sql +10 -0
  126. package/templates/src/app/api/auth/_shared/wecom/client.ts +24 -4
  127. package/templates/src/app/api/home/migrations/0001__create_home_tables.mysql.sql +14 -0
  128. package/templates/src/app/api/home/migrations/0001__create_home_tables.pg.sql +14 -0
  129. package/templates/src/app/api/home/migrations/0002__tenant.pg.sql +4 -0
  130. package/templates/src/app/api/home/seed.mysql.sql +71 -0
  131. package/templates/src/app/api/home/seed.pg.sql +71 -0
  132. package/templates/src/app/api/notification/_shared/notify.ts +6 -6
  133. package/templates/src/app/api/notification/migrations/0001__create_notifications.mysql.sql +11 -0
  134. package/templates/src/app/api/notification/migrations/0001__create_notifications.pg.sql +11 -0
  135. package/templates/src/app/api/notification/migrations/0002__notifications_user.mysql.sql +8 -0
  136. package/templates/src/app/api/notification/migrations/0003__notifications_broadcast.mysql.sql +21 -0
  137. package/templates/src/app/api/notification/migrations/0003__notifications_broadcast.pg.sql +22 -0
  138. package/templates/src/app/api/notification/migrations/0004__notifications_broadcast_hidden.mysql.sql +10 -0
  139. package/templates/src/app/api/notification/migrations/0004__notifications_broadcast_hidden.pg.sql +11 -0
  140. package/templates/src/app/api/notification/migrations/0005__tenant.pg.sql +6 -0
  141. package/templates/src/app/api/notification/seed.mysql.sql +8 -0
  142. package/templates/src/app/api/notification/seed.pg.sql +11 -0
  143. package/templates/src/app/api/publish/_shared/identity.ts +69 -0
  144. package/templates/src/app/api/publish/api.ts +349 -0
  145. package/templates/src/app/api/publish/manifest.yaml +8 -0
  146. package/templates/src/app/api/publish/migrations/0001__publish_credential.mysql.sql +23 -0
  147. package/templates/src/app/api/publish/migrations/0001__publish_credential.pg.sql +23 -0
  148. package/templates/src/app/api/publish/migrations/0001__publish_credential.sql +39 -0
  149. package/templates/src/app/api/publish/schema.yaml +33 -0
  150. package/templates/src/app/api/system/login-methods/api.ts +2 -1
  151. package/templates/src/app/web/_platform/__client/api.schemas.ts +15 -0
  152. package/templates/src/app/web/_platform/__client/index.ts +25 -1
  153. package/templates/src/app/web/entry.ts +9 -5
  154. package/templates/src/app/web/home/pages/components/bar-chart.tsx +5 -3
  155. package/templates/src/app/web/home/pages/components/echarts-setup.ts +30 -0
  156. package/templates/src/app/web/home/pages/components/line-chart.tsx +5 -3
  157. package/templates/src/app/web/home/pages/components/pie-chart.tsx +6 -3
  158. package/templates/src/app/web/home/pages/index.tsx +3 -2
  159. package/templates/src/app/web/home/routes.ts +8 -2
  160. package/templates/src/app/web/login/locales/en-US.json +7 -1
  161. package/templates/src/app/web/login/locales/zh-CN.json +7 -1
  162. package/templates/src/app/web/login/pages/login.tsx +79 -86
  163. package/templates/src/app/web/login/routes.ts +54 -1
  164. package/templates/src/app/web/personal-center/locales/en-US.json +1 -0
  165. package/templates/src/app/web/personal-center/locales/zh-CN.json +1 -0
  166. package/templates/src/app/web/personal-center/pages/my-profile/index.tsx +5 -0
  167. package/templates/src/app/web/system/__client/api.schemas.ts +2 -1
  168. package/templates/src/app/web/system/locales/en-US.json +1 -8
  169. package/templates/src/app/web/system/locales/zh-CN.json +1 -8
  170. package/templates/src/app/web/system/pages/settings/index.tsx +17 -4
  171. package/templates/src/app/web/system/routes.ts +0 -6
  172. package/templates/src/oj-market/web/__tests__/CardGrid.test.tsx +33 -0
  173. package/templates/src/oj-market/web/__tests__/DetailDrawer.test.tsx +69 -0
  174. package/templates/src/oj-market/web/__tests__/marketClient.fake.ts +7 -1
  175. package/templates/src/oj-market/web/api/client.ts +3 -0
  176. package/templates/src/oj-market/web/api/defaultClient.ts +5 -0
  177. package/templates/src/oj-market/web/components/CardItem.tsx +44 -1
  178. package/templates/src/oj-market/web/components/DetailDrawer.tsx +17 -1
  179. package/templates/src/oj-market/web/entry.ts +31 -2
  180. package/templates/src/oj-market/web/locales/en-US.json +5 -1
  181. package/templates/src/oj-market/web/locales/zh-CN.json +5 -1
  182. package/templates/src/oj-market/web/publish/__client/api.schemas.ts +61 -0
  183. package/templates/src/oj-market/web/publish/__client/index.ts +164 -0
  184. package/templates/src/oj-market/web/publish/locales/en-US.json +80 -0
  185. package/templates/src/oj-market/web/publish/locales/zh-CN.json +80 -0
  186. package/templates/src/oj-market/web/publish/pages/history.tsx +112 -0
  187. package/templates/src/oj-market/web/publish/pages/index.tsx +196 -0
  188. package/templates/src/oj-market/web/publish/pages/model.ts +52 -0
  189. package/templates/src/oj-market/web/publish/pages/token-modal.tsx +82 -0
  190. package/templates/src/oj-market/web/publish/routes.ts +41 -0
  191. package/templates/src/oj-market/web/types.ts +30 -0
  192. package/templates/tests/lifecycle/compensate.spec.ts +207 -0
  193. package/templates/tests/lifecycle/deploy-smoke.spec.ts +38 -14
  194. package/templates/tests/lifecycle/installer.spec.ts +28 -9
  195. package/templates/tests/lifecycle/market-api.spec.ts +164 -12
  196. package/templates/tests/lifecycle/preflight.spec.ts +68 -0
  197. package/templates/tests/lifecycle/role-title-translate.spec.ts +2 -32
  198. package/templates/tests/lifecycle/text-edit.spec.ts +45 -27
  199. package/templates/tests/lifecycle/uninstall.spec.ts +36 -0
  200. package/templates/tests/publish-credential.spec.ts +354 -0
  201. package/templates/tests/publish-identity.spec.ts +44 -0
  202. package/templates/tests/wecom-client-timeout.spec.ts +33 -3
  203. package/templates/tests/wecom-landing.spec.ts +63 -1
  204. package/templates/tsconfig.paths.json +1 -0
  205. package/templates/web.config.ts +6 -4
  206. package/vendor/host-versions.json +3 -3
  207. package/shell-dist/assets/ahooks.js +0 -6909
  208. package/shell-dist/assets/antd-es-locale-zh_CN.js +0 -257
  209. package/shell-dist/assets/antd-img-crop.js +0 -1495
  210. package/shell-dist/assets/antd-locale-en_US.js +0 -374
  211. package/shell-dist/assets/antd-locale-zh_CN.js +0 -379
  212. package/shell-dist/assets/antd.js +0 -106874
  213. package/shell-dist/assets/clsx.js +0 -33
  214. package/shell-dist/assets/contract-errors.js +0 -30
  215. package/shell-dist/assets/contract.js +0 -18900
  216. package/shell-dist/assets/cssinjs.js +0 -2595
  217. package/shell-dist/assets/dayjs-plugin-advancedFormat.js +0 -98
  218. package/shell-dist/assets/dayjs-plugin-customParseFormat.js +0 -173
  219. package/shell-dist/assets/dayjs-plugin-isoWeek.js +0 -77
  220. package/shell-dist/assets/dayjs-plugin-localeData.js +0 -126
  221. package/shell-dist/assets/dayjs-plugin-quarterOfYear.js +0 -77
  222. package/shell-dist/assets/dayjs-plugin-relativeTime.js +0 -92
  223. package/shell-dist/assets/dayjs-plugin-weekOfYear.js +0 -73
  224. package/shell-dist/assets/dayjs-plugin-weekYear.js +0 -63
  225. package/shell-dist/assets/dayjs-plugin-weekday.js +0 -63
  226. package/shell-dist/assets/dayjs.js +0 -326
  227. package/shell-dist/assets/dnd-kit-core.js +0 -3601
  228. package/shell-dist/assets/dnd-kit-sortable.js +0 -717
  229. package/shell-dist/assets/dnd-kit-utilities.js +0 -340
  230. package/shell-dist/assets/i18next.js +0 -2321
  231. package/shell-dist/assets/icons-es-components-Context.js +0 -20
  232. package/shell-dist/assets/icons.js +0 -34961
  233. package/shell-dist/assets/jsx-dev-runtime.js +0 -75
  234. package/shell-dist/assets/jsx-runtime.js +0 -97
  235. package/shell-dist/assets/keepalive-for-react.js +0 -283
  236. package/shell-dist/assets/kit.js +0 -151
  237. package/shell-dist/assets/ky.js +0 -1427
  238. package/shell-dist/assets/motion-react.js +0 -13589
  239. package/shell-dist/assets/motion.js +0 -9959
  240. package/shell-dist/assets/nprogress.js +0 -314
  241. package/shell-dist/assets/ojm--ant-design-icons-es-icons-BarsOutlined.js +0 -7
  242. package/shell-dist/assets/ojm--ant-design-icons-es-icons-CalendarOutlined.js +0 -7
  243. package/shell-dist/assets/ojm--ant-design-icons-es-icons-CaretDownFilled.js +0 -7
  244. package/shell-dist/assets/ojm--ant-design-icons-es-icons-CaretDownOutlined.js +0 -7
  245. package/shell-dist/assets/ojm--ant-design-icons-es-icons-CaretUpOutlined.js +0 -7
  246. package/shell-dist/assets/ojm--ant-design-icons-es-icons-CheckCircleFilled.js +0 -7
  247. package/shell-dist/assets/ojm--ant-design-icons-es-icons-CheckOutlined.js +0 -7
  248. package/shell-dist/assets/ojm--ant-design-icons-es-icons-ClockCircleOutlined.js +0 -7
  249. package/shell-dist/assets/ojm--ant-design-icons-es-icons-CloseCircleFilled.js +0 -7
  250. package/shell-dist/assets/ojm--ant-design-icons-es-icons-CloseOutlined.js +0 -7
  251. package/shell-dist/assets/ojm--ant-design-icons-es-icons-CopyOutlined.js +0 -7
  252. package/shell-dist/assets/ojm--ant-design-icons-es-icons-DeleteOutlined.js +0 -7
  253. package/shell-dist/assets/ojm--ant-design-icons-es-icons-DoubleLeftOutlined.js +0 -7
  254. package/shell-dist/assets/ojm--ant-design-icons-es-icons-DoubleRightOutlined.js +0 -7
  255. package/shell-dist/assets/ojm--ant-design-icons-es-icons-DownOutlined.js +0 -7
  256. package/shell-dist/assets/ojm--ant-design-icons-es-icons-DownloadOutlined.js +0 -7
  257. package/shell-dist/assets/ojm--ant-design-icons-es-icons-EditOutlined.js +0 -7
  258. package/shell-dist/assets/ojm--ant-design-icons-es-icons-EllipsisOutlined.js +0 -7
  259. package/shell-dist/assets/ojm--ant-design-icons-es-icons-EnterOutlined.js +0 -7
  260. package/shell-dist/assets/ojm--ant-design-icons-es-icons-ExclamationCircleFilled.js +0 -7
  261. package/shell-dist/assets/ojm--ant-design-icons-es-icons-EyeInvisibleOutlined.js +0 -7
  262. package/shell-dist/assets/ojm--ant-design-icons-es-icons-EyeOutlined.js +0 -7
  263. package/shell-dist/assets/ojm--ant-design-icons-es-icons-FileOutlined.js +0 -7
  264. package/shell-dist/assets/ojm--ant-design-icons-es-icons-FileTextOutlined.js +0 -7
  265. package/shell-dist/assets/ojm--ant-design-icons-es-icons-FilterFilled.js +0 -7
  266. package/shell-dist/assets/ojm--ant-design-icons-es-icons-FolderOpenOutlined.js +0 -7
  267. package/shell-dist/assets/ojm--ant-design-icons-es-icons-FolderOutlined.js +0 -7
  268. package/shell-dist/assets/ojm--ant-design-icons-es-icons-HolderOutlined.js +0 -7
  269. package/shell-dist/assets/ojm--ant-design-icons-es-icons-InfoCircleFilled.js +0 -7
  270. package/shell-dist/assets/ojm--ant-design-icons-es-icons-LeftOutlined.js +0 -7
  271. package/shell-dist/assets/ojm--ant-design-icons-es-icons-LoadingOutlined.js +0 -7
  272. package/shell-dist/assets/ojm--ant-design-icons-es-icons-MinusOutlined.js +0 -7
  273. package/shell-dist/assets/ojm--ant-design-icons-es-icons-MinusSquareOutlined.js +0 -7
  274. package/shell-dist/assets/ojm--ant-design-icons-es-icons-PaperClipOutlined.js +0 -7
  275. package/shell-dist/assets/ojm--ant-design-icons-es-icons-PictureOutlined.js +0 -7
  276. package/shell-dist/assets/ojm--ant-design-icons-es-icons-PlusOutlined.js +0 -7
  277. package/shell-dist/assets/ojm--ant-design-icons-es-icons-PlusSquareOutlined.js +0 -7
  278. package/shell-dist/assets/ojm--ant-design-icons-es-icons-QuestionCircleOutlined.js +0 -7
  279. package/shell-dist/assets/ojm--ant-design-icons-es-icons-ReloadOutlined.js +0 -7
  280. package/shell-dist/assets/ojm--ant-design-icons-es-icons-RightOutlined.js +0 -7
  281. package/shell-dist/assets/ojm--ant-design-icons-es-icons-RotateLeftOutlined.js +0 -7
  282. package/shell-dist/assets/ojm--ant-design-icons-es-icons-RotateRightOutlined.js +0 -7
  283. package/shell-dist/assets/ojm--ant-design-icons-es-icons-SearchOutlined.js +0 -7
  284. package/shell-dist/assets/ojm--ant-design-icons-es-icons-StarFilled.js +0 -7
  285. package/shell-dist/assets/ojm--ant-design-icons-es-icons-SwapOutlined.js +0 -7
  286. package/shell-dist/assets/ojm--ant-design-icons-es-icons-SwapRightOutlined.js +0 -7
  287. package/shell-dist/assets/ojm--ant-design-icons-es-icons-UpOutlined.js +0 -7
  288. package/shell-dist/assets/ojm--ant-design-icons-es-icons-VerticalAlignTopOutlined.js +0 -7
  289. package/shell-dist/assets/ojm--ant-design-icons-es-icons-WarningFilled.js +0 -7
  290. package/shell-dist/assets/ojm--ant-design-icons-es-icons-ZoomInOutlined.js +0 -7
  291. package/shell-dist/assets/ojm--ant-design-icons-es-icons-ZoomOutOutlined.js +0 -7
  292. package/shell-dist/assets/ojm-dayjs-locale-zh-cn.js +0 -81
  293. package/shell-dist/assets/pinyin-pro.js +0 -25175
  294. package/shell-dist/assets/pro-components.js +0 -44627
  295. package/shell-dist/assets/react-countup.js +0 -525
  296. package/shell-dist/assets/react-dom-client.js +0 -12134
  297. package/shell-dist/assets/react-dom.js +0 -266
  298. package/shell-dist/assets/react-error-boundary.js +0 -141
  299. package/shell-dist/assets/react-i18next.js +0 -1773
  300. package/shell-dist/assets/react-jss.js +0 -4089
  301. package/shell-dist/assets/react-query.js +0 -3072
  302. package/shell-dist/assets/react-router-dom.js +0 -9927
  303. package/shell-dist/assets/react-router.js +0 -14584
  304. package/shell-dist/assets/react.js +0 -590
  305. package/shell-dist/assets/runtime.js +0 -28311
  306. package/shell-dist/assets/simplebar-react.js +0 -1119
  307. package/shell-dist/assets/spin-delay.js +0 -111
  308. package/shell-dist/assets/tailwind-merge.js +0 -3364
  309. package/shell-dist/assets/use-sync-external-store-shim.js +0 -130
  310. package/shell-dist/assets/zustand-middleware.js +0 -513
  311. package/shell-dist/assets/zustand-react-shallow.js +0 -27
  312. package/shell-dist/assets/zustand-react.js +0 -39
  313. package/shell-dist/assets/zustand-shallow.js +0 -22
  314. package/shell-dist/assets/zustand-vanilla-shallow.js +0 -71
  315. package/shell-dist/assets/zustand-vanilla.js +0 -40
  316. package/shell-dist/assets/zustand.js +0 -32
  317. package/templates/seed.mysql.sql +0 -6
  318. package/templates/seed.pg.sql +0 -6
  319. package/templates/src/app/api/_platform/migrations/0001__create_users.mysql.sql +0 -9
  320. package/templates/src/app/api/_platform/migrations/0001__create_users.pg.sql +0 -9
  321. package/templates/src/app/api/_platform/migrations/0001__create_users.sql +0 -7
  322. package/templates/src/app/api/_platform/migrations/0002__add_users_avatar_base64.mysql.sql +0 -3
  323. package/templates/src/app/api/_platform/migrations/0002__add_users_avatar_base64.sql +0 -2
  324. package/templates/src/app/api/_platform/migrations/0003__users_source_display_name.mysql.sql +0 -5
  325. package/templates/src/app/api/_platform/migrations/0003__users_source_display_name.sql +0 -5
  326. package/templates/src/app/api/_platform/migrations/0004__sys_rbac.mysql.sql +0 -70
  327. package/templates/src/app/api/_platform/migrations/0004__sys_rbac.pg.sql +0 -67
  328. package/templates/src/app/api/_platform/migrations/0004__sys_rbac.sql +0 -67
  329. package/templates/src/app/api/_platform/migrations/0005__users_must_change.mysql.sql +0 -3
  330. package/templates/src/app/api/_platform/migrations/0005__users_must_change.sql +0 -2
  331. package/templates/src/app/api/_platform/migrations/0006__users_is_forbidden.mysql.sql +0 -3
  332. package/templates/src/app/api/_platform/migrations/0006__users_is_forbidden.sql +0 -3
  333. package/templates/src/app/api/_platform/migrations/0007__users_email.sql +0 -3
  334. package/templates/src/app/api/_platform/migrations/0008__sys_refresh_token.mysql.sql +0 -10
  335. package/templates/src/app/api/_platform/migrations/0008__sys_refresh_token.pg.sql +0 -10
  336. package/templates/src/app/api/_platform/migrations/0008__sys_refresh_token.sql +0 -11
  337. package/templates/src/app/api/_platform/migrations/0009__sys_throttle.mysql.sql +0 -12
  338. package/templates/src/app/api/_platform/migrations/0009__sys_throttle.pg.sql +0 -12
  339. package/templates/src/app/api/_platform/migrations/0009__sys_throttle.sql +0 -13
  340. package/templates/src/app/api/_platform/migrations/0010__sys_solution_route.mysql.sql +0 -17
  341. package/templates/src/app/api/_platform/migrations/0010__sys_solution_route.pg.sql +0 -16
  342. package/templates/src/app/api/_platform/migrations/0010__sys_solution_route.sql +0 -18
  343. package/templates/src/app/api/_platform/migrations/0011__sys_setting_group_label.mysql.sql +0 -2
  344. package/templates/src/app/api/_platform/migrations/0011__sys_setting_group_label.sql +0 -4
  345. package/templates/src/app/api/_platform/migrations/0012__market_history.mysql.sql +0 -13
  346. package/templates/src/app/api/_platform/migrations/0012__market_history.pg.sql +0 -12
  347. package/templates/src/app/api/_platform/migrations/0012__market_history.sql +0 -14
  348. package/templates/src/app/api/_platform/migrations/0013__users_profile.sql +0 -4
  349. package/templates/src/app/api/_platform/migrations/0014__reg_source_seq.mysql.sql +0 -9
  350. package/templates/src/app/api/_platform/migrations/0014__reg_source_seq.pg.sql +0 -7
  351. package/templates/src/app/api/_platform/migrations/0014__reg_source_seq.sql +0 -8
  352. package/templates/src/app/api/_platform/migrations/0015__tenant.mysql.sql +0 -12
  353. package/templates/src/app/api/_platform/migrations/0015__tenant.pg.sql +0 -11
  354. package/templates/src/app/api/_platform/migrations/0015__tenant.sql +0 -44
  355. package/templates/src/app/api/_platform/migrations/0016__org.mysql.sql +0 -41
  356. package/templates/src/app/api/_platform/migrations/0016__org.pg.sql +0 -40
  357. package/templates/src/app/api/_platform/migrations/0016__org.sql +0 -62
  358. package/templates/src/app/api/_platform/migrations/0017__users_employee_no.mysql.sql +0 -7
  359. package/templates/src/app/api/_platform/migrations/0017__users_employee_no.pg.sql +0 -4
  360. package/templates/src/app/api/_platform/migrations/0017__users_employee_no.sql +0 -8
  361. package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.mysql.sql +0 -3
  362. package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.pg.sql +0 -3
  363. package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.sql +0 -8
  364. package/templates/src/app/web/system/pages/login-methods/index.tsx +0 -30
  365. /package/shell-dist/assets/{nprogress-css.js → nprogress-css.1cq2pzkre0.js} +0 -0
  366. /package/shell-dist/assets/{ojm-antd-es-button.js → ojm-antd-es-button.2uriphio50.js} +0 -0
  367. /package/shell-dist/assets/{ojm-antd-es-modal.js → ojm-antd-es-modal.bf3tgdh8v0.js} +0 -0
  368. /package/shell-dist/assets/{ojm-antd-es-slider.js → ojm-antd-es-slider.xyvptuhid0.js} +0 -0
  369. /package/shell-dist/assets/{ojm-antd-es-upload.js → ojm-antd-es-upload.13gx45e0g0.js} +0 -0
@@ -0,0 +1,112 @@
1
+ import type { ReleaseRow } from "../../types";
2
+ import { useQuery } from "@tanstack/react-query";
3
+ import { Alert, Space, Table, Tag, Tooltip, Typography } from "antd";
4
+ import dayjs from "dayjs";
5
+ import { useState } from "react";
6
+ import { useTranslation } from "react-i18next";
7
+ import { useMarketClient } from "../../api/context";
8
+
9
+ const DEFAULT_PAGE_SIZE = 20;
10
+ const PAGE_SIZE_OPTIONS = [20, 50, 100];
11
+
12
+ /** 秒级 epoch(服务端统一存秒)→ 本地时间;缺值显示 - */
13
+ function formatSecs(secs: number | null | undefined): string {
14
+ return secs == null ? "-" : dayjs.unix(secs).format("YYYY-MM-DD HH:mm");
15
+ }
16
+
17
+ /**
18
+ * 发布历史页。
19
+ *
20
+ * 数据真相在服务端:每次打开都由后端先与签名索引对账(新版本补进来,已入库行不改时间),
21
+ * 前端只做分页展示——不在浏览器里重算「谁先谁后」,避免两处排序口径分叉。
22
+ *
23
+ * 发布时间优先取分发包落 CDN 的 Last-Modified;源不提供时回落索引生成时间,
24
+ * 这种情况标一个「索引时间」,让读者知道它不是精确落包时刻。
25
+ */
26
+ export default function ReleaseHistoryPage() {
27
+ const { t } = useTranslation();
28
+ const client = useMarketClient();
29
+ const [page, setPage] = useState(1);
30
+ const [size, setSize] = useState(DEFAULT_PAGE_SIZE);
31
+
32
+ const query = useQuery({
33
+ queryKey: ["market", "releases", page, size],
34
+ queryFn: () => client.releases({ page, limit: size }),
35
+ });
36
+
37
+ const rows = query.data?.list ?? [];
38
+
39
+ const columns = [
40
+ { title: t("publish:history.columns.product"), dataIndex: "product" },
41
+ { title: t("publish:history.columns.version"), dataIndex: "version" },
42
+ {
43
+ title: t("publish:history.columns.publisher"),
44
+ dataIndex: "key_id",
45
+ render: (value: string | null) => value ?? "-",
46
+ },
47
+ {
48
+ title: (
49
+ <Tooltip title={t("publish:history.publishedAtHint")}>
50
+ <span>{t("publish:history.columns.publishedAt")}</span>
51
+ </Tooltip>
52
+ ),
53
+ dataIndex: "published_at",
54
+ render: (value: number, row: ReleaseRow) => (
55
+ <Space size={4}>
56
+ <span>{formatSecs(value)}</span>
57
+ {row.published_at_source === "index" && <Tag color="default">{t("publish:history.indexTime")}</Tag>}
58
+ </Space>
59
+ ),
60
+ },
61
+ {
62
+ title: t("publish:history.columns.status"),
63
+ dataIndex: "yanked",
64
+ render: (value: number) => (
65
+ <Tag color={value === 1 ? "default" : "green"}>
66
+ {value === 1 ? t("publish:history.status.yanked") : t("publish:history.status.active")}
67
+ </Tag>
68
+ ),
69
+ },
70
+ ];
71
+
72
+ return (
73
+ <Space direction="vertical" style={{ width: "100%", paddingTop: 16 }} size="middle">
74
+ <Space direction="vertical" size={4}>
75
+ <Typography.Title level={4} style={{ margin: 0 }}>
76
+ {t("publish:history.title")}
77
+ </Typography.Title>
78
+ <Typography.Text type="secondary">{t("publish:history.subtitle")}</Typography.Text>
79
+ </Space>
80
+
81
+ {query.data?.syncError != null && (
82
+ <Alert
83
+ type="warning"
84
+ showIcon
85
+ message={t("publish:history.syncFailed")}
86
+ description={query.data.syncError}
87
+ />
88
+ )}
89
+
90
+ <Table<ReleaseRow>
91
+ rowKey="id"
92
+ size="middle"
93
+ columns={columns}
94
+ dataSource={rows}
95
+ loading={query.isLoading}
96
+ locale={{ emptyText: t("publish:history.empty") }}
97
+ pagination={{
98
+ current: page,
99
+ pageSize: size,
100
+ total: query.data?.total ?? 0,
101
+ showSizeChanger: true,
102
+ pageSizeOptions: PAGE_SIZE_OPTIONS,
103
+ showTotal: total => t("publish:history.total", { total }),
104
+ onChange: (nextPage, nextSize) => {
105
+ setPage(nextPage);
106
+ setSize(nextSize);
107
+ },
108
+ }}
109
+ />
110
+ </Space>
111
+ );
112
+ }
@@ -0,0 +1,196 @@
1
+ import type { PublishCredentialGetData } from "../__client";
2
+ import type { CredentialStatus } from "./model";
3
+ import type { IssuedCredential } from "./token-modal";
4
+ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
5
+ import { App, Button, Form, Input, Modal, Popconfirm, Space, Table, Tag, Tooltip, Typography } from "antd";
6
+
7
+ import dayjs from "dayjs";
8
+ import { useState } from "react";
9
+ import { useTranslation } from "react-i18next";
10
+ import { publishCredentialGet, publishCredentialPost, publishCredentialRevokePost } from "../__client";
11
+ import { canRevoke, errorText, statusColor } from "./model";
12
+ import { TokenModal } from "./token-modal";
13
+
14
+ type CredentialRow = PublishCredentialGetData["list"][number];
15
+
16
+ const DEFAULT_PAGE_SIZE = 20;
17
+ const PAGE_SIZE_OPTIONS = [20, 50, 100];
18
+
19
+ /** 秒级 epoch(后端统一存秒,不是毫秒——故用 dayjs.unix 而非 dayjs()) */
20
+ function formatSecs(secs: number | null | undefined): string {
21
+ return secs == null ? "-" : dayjs.unix(secs).format("YYYY-MM-DD HH:mm");
22
+ }
23
+
24
+ /**
25
+ * 发布管理页。
26
+ *
27
+ * 页面的职责只有三件事:列凭证、申请、撤销。所有推导都留在服务端
28
+ * (`key_id` 在申请时算好、`status` 由 used/revoked/expiry 三列统一判定),
29
+ * 前端不重复算——否则「页面显示已过期、后端仍可兑换」这类分叉迟早出现。
30
+ *
31
+ * 可见范围同样由服务端决定:普通用户只拿到自己的;超管拿到全部,响应里多一个
32
+ * `owner_tenant` 字段。前端据「数据里有没有这个字段」决定是否显示租户列与租户筛选,
33
+ * 不去单独查一次「我是谁」——少一个请求,也少一处会过期的判断。
34
+ */
35
+ export default function PublishPage() {
36
+ const { t } = useTranslation();
37
+ const { message } = App.useApp();
38
+ const queryClient = useQueryClient();
39
+ const [page, setPage] = useState(1);
40
+ const [size, setSize] = useState(DEFAULT_PAGE_SIZE);
41
+ const [tenant, setTenant] = useState("");
42
+ const [tenantInput, setTenantInput] = useState("");
43
+ const [applyOpen, setApplyOpen] = useState(false);
44
+ const [issued, setIssued] = useState<IssuedCredential | null>(null);
45
+ const [form] = Form.useForm<{ product: string }>();
46
+
47
+ const query = useQuery({
48
+ queryKey: ["publish", "credential", page, size, tenant],
49
+ queryFn: () => publishCredentialGet({ page, limit: size, tenant: tenant || undefined }),
50
+ });
51
+
52
+ const apply = useMutation({
53
+ mutationFn: (product: string) => publishCredentialPost({ product }),
54
+ onSuccess: (r) => {
55
+ setApplyOpen(false);
56
+ form.resetFields();
57
+ // 明文只在响应里:先落进弹窗,再刷新列表(刷新失败也不该丢掉用户手里这张凭证)
58
+ setIssued(r);
59
+ void queryClient.invalidateQueries({ queryKey: ["publish", "credential"] });
60
+ },
61
+ onError: e => message.error(errorText(e)),
62
+ });
63
+
64
+ const revoke = useMutation({
65
+ mutationFn: (id: number) => publishCredentialRevokePost({ id }),
66
+ onSuccess: () => {
67
+ message.success(t("publish:revoke.done"));
68
+ void queryClient.invalidateQueries({ queryKey: ["publish", "credential"] });
69
+ },
70
+ onError: e => message.error(errorText(e)),
71
+ });
72
+
73
+ const rows = query.data?.list ?? [];
74
+ // 超管专属字段出现即说明当前账号看得见全部租户;已在筛选时也保持入口可见(否则无法清空筛选)
75
+ const seesTenants = tenant !== "" || rows.some(row => row.owner_tenant != null);
76
+
77
+ const columns = [
78
+ { title: t("publish:columns.product"), dataIndex: "product" },
79
+ {
80
+ title: t("publish:columns.keyId"),
81
+ dataIndex: "key_id",
82
+ ellipsis: { showTitle: false },
83
+ render: (keyId: string) => <Tooltip title={keyId}>{keyId}</Tooltip>,
84
+ },
85
+ {
86
+ title: t("publish:columns.applicant"),
87
+ dataIndex: "username",
88
+ render: (username: string, row: CredentialRow) => (row.display_name ? `${row.display_name}(${username})` : username),
89
+ },
90
+ {
91
+ title: t("publish:columns.tokenHint"),
92
+ dataIndex: "token_hint",
93
+ render: (hint: string) => (
94
+ <Typography.Text code>
95
+ {hint}
96
+ …
97
+ </Typography.Text>
98
+ ),
99
+ },
100
+ {
101
+ title: t("publish:columns.status"),
102
+ dataIndex: "status",
103
+ render: (status: CredentialStatus) => <Tag color={statusColor(status)}>{t(`publish:status.${status}`)}</Tag>,
104
+ },
105
+ { title: t("publish:columns.createdAt"), dataIndex: "created_at", render: (v: number) => formatSecs(v) },
106
+ { title: t("publish:columns.usedAt"), dataIndex: "used_at", render: (v: number | null) => formatSecs(v) },
107
+ { title: t("publish:columns.expiresAt"), dataIndex: "expires_at", render: (v: number) => formatSecs(v) },
108
+ ...(seesTenants ? [{ title: t("publish:columns.tenant"), dataIndex: "owner_tenant" }] : []),
109
+ {
110
+ title: t("publish:columns.actions"),
111
+ dataIndex: "id",
112
+ render: (_: number, row: CredentialRow) => (canRevoke(row.status)
113
+ ? (
114
+ <Popconfirm title={t("publish:revoke.confirm")} okText={t("publish:revoke.ok")} onConfirm={() => revoke.mutate(row.id)}>
115
+ <Button type="link" danger size="small" loading={revoke.isPending}>{t("publish:revoke.action")}</Button>
116
+ </Popconfirm>
117
+ )
118
+ : <Typography.Text type="secondary">-</Typography.Text>),
119
+ },
120
+ ];
121
+
122
+ return (
123
+ <Space direction="vertical" style={{ width: "100%", paddingTop: 16 }}>
124
+ <Space style={{ width: "100%", justifyContent: "space-between" }} wrap>
125
+ <Typography.Text type="secondary">{t("publish:page.subtitle")}</Typography.Text>
126
+ <Space>
127
+ {seesTenants && (
128
+ <Input.Search
129
+ data-testid="publish-tenant-filter"
130
+ allowClear
131
+ placeholder={t("publish:filter.tenantPlaceholder")}
132
+ value={tenantInput}
133
+ onChange={e => setTenantInput(e.target.value)}
134
+ onSearch={(value) => {
135
+ setTenant(value.trim());
136
+ setPage(1);
137
+ }}
138
+ style={{ width: 240 }}
139
+ />
140
+ )}
141
+ <Button type="primary" data-testid="publish-apply" onClick={() => setApplyOpen(true)}>{t("publish:page.apply")}</Button>
142
+ </Space>
143
+ </Space>
144
+ <Table
145
+ rowKey="id"
146
+ loading={query.isLoading}
147
+ dataSource={rows}
148
+ columns={columns}
149
+ locale={{ emptyText: t("publish:page.empty") }}
150
+ pagination={{
151
+ current: page,
152
+ pageSize: size,
153
+ total: query.data?.total ?? 0,
154
+ showSizeChanger: true,
155
+ pageSizeOptions: PAGE_SIZE_OPTIONS,
156
+ showTotal: total => t("publish:page.total", { total }),
157
+ onChange: (nextPage, nextSize) => {
158
+ // 改每页条数后原页码可能越界:统一回第 1 页(与操作日志页同口径)
159
+ if (nextSize !== size) {
160
+ setSize(nextSize);
161
+ setPage(1);
162
+ return;
163
+ }
164
+ setPage(nextPage);
165
+ },
166
+ }}
167
+ />
168
+
169
+ <Modal
170
+ open={applyOpen}
171
+ title={t("publish:apply.title")}
172
+ confirmLoading={apply.isPending}
173
+ okText={t("publish:apply.ok")}
174
+ cancelText={t("publish:apply.cancel")}
175
+ onCancel={() => setApplyOpen(false)}
176
+ onOk={() => form.submit()}
177
+ >
178
+ <Form form={form} layout="vertical" onFinish={v => apply.mutate(v.product)}>
179
+ <Form.Item
180
+ name="product"
181
+ label={t("publish:apply.product")}
182
+ extra={t("publish:apply.productExtra")}
183
+ rules={[{ required: true, message: t("publish:apply.productRequired") }]}
184
+ >
185
+ <Input data-testid="publish-product" placeholder="demo-solution" autoFocus />
186
+ </Form.Item>
187
+ </Form>
188
+ </Modal>
189
+
190
+ <TokenModal
191
+ issued={issued}
192
+ onClose={() => setIssued(null)}
193
+ />
194
+ </Space>
195
+ );
196
+ }
@@ -0,0 +1,52 @@
1
+ // 「发布管理」页的纯逻辑(无 React、无 IO)——状态颜色、可撤销判定、给用户的命令行。
2
+ // 抽出来的唯一理由:这三件事是页面里最该被钉死的口径,且都必须能脱离 antd 断言。
3
+
4
+ export type CredentialStatus = "active" | "used" | "revoked" | "expired";
5
+
6
+ /** 状态 → antd Tag 颜色。Record 全量约束:新增状态时这里编译期就缺键。 */
7
+ const STATUS_COLOR: Record<CredentialStatus, string> = {
8
+ active: "processing",
9
+ used: "success",
10
+ revoked: "default",
11
+ expired: "warning",
12
+ };
13
+
14
+ export function statusColor(status: CredentialStatus): string {
15
+ return STATUS_COLOR[status];
16
+ }
17
+
18
+ /**
19
+ * 能否撤销:只有「待兑换」可以。
20
+ *
21
+ * 兑换只下发 key_id,公钥是发布方本机生成的——站点手里没有那把钥匙,也就没有「撤回」可言;
22
+ * 撤回一条已兑换的凭证只会制造「以为撤了其实没撤」的错觉(后端的 400 文案就是这个意思,
23
+ * 真要停用只能到宿主信任库移除对应公钥)。按钮仍要渲染(禁用态),不用隐藏:
24
+ * 隐藏会让用户以为页面没做完。
25
+ */
26
+ export function canRevoke(status: string): boolean {
27
+ return status === "active";
28
+ }
29
+
30
+ /**
31
+ * 复制给用户的一行命令。
32
+ *
33
+ * 只带凭证,不带 `--site`:站点地址由 CLI 从本机配置或上次发布记录里取,
34
+ * 页面拼一个 origin 反而在反代/多域名部署下更容易错。
35
+ */
36
+ export function buildKeygenCommand(token: string): string {
37
+ return `ojm keygen --credential ${token}`;
38
+ }
39
+
40
+ /**
41
+ * 统一信封错误 → 人话。后端 fail(status, message) 的文案本身就是给用户看的,
42
+ * 故优先取 `msg`(ContractApiError),其次 Error.message。
43
+ *
44
+ * 与 system/pages/errors.ts 的 errMsg 同构但不互相 import:那是系统管理根内部模块,
45
+ * 让「发布管理」依赖它会把两个根的加载顺序绑在一起(多根聚合下互不依赖是硬约定)。
46
+ */
47
+ export function errorText(e: unknown): string {
48
+ const msg = (e as { msg?: unknown } | null)?.msg;
49
+ if (typeof msg === "string" && msg !== "")
50
+ return msg;
51
+ return e instanceof Error ? e.message : String(e);
52
+ }
@@ -0,0 +1,82 @@
1
+ import { Alert, Button, Input, Modal, Space, Typography } from "antd";
2
+ import { useState } from "react";
3
+ import { useTranslation } from "react-i18next";
4
+
5
+ import { buildKeygenCommand } from "./model";
6
+
7
+ /** 申请成功的返回值:明文只在这一刻存在 */
8
+ export interface IssuedCredential {
9
+ token: string
10
+ key_id: string
11
+ product: string
12
+ token_hint?: string
13
+ expires_at: number
14
+ }
15
+
16
+ /** 复制到剪贴板:非 https / 无权限时静默失败(输入框里的文本本来就能手动选中) */
17
+ async function copy(text: string): Promise<void> {
18
+ try {
19
+ await navigator.clipboard.writeText(text);
20
+ }
21
+ catch {
22
+ // 不打断流程:用户可直接在只读输入框里选中复制
23
+ }
24
+ }
25
+
26
+ /**
27
+ * 一次性明文弹窗。
28
+ *
29
+ * 三条不可退让的约束:
30
+ * · 不渲染 = 没有。`issued` 为 null 时整个 Modal 不挂载,关闭后 DOM 里不再有明文
31
+ * (服务端只存 sha256,关掉就真的找不回来——所以文案必须先说清楚)。
32
+ * · 不可点遮罩/ESC 关闭:误触的代价是重新申请一张凭证。
33
+ * · 凭证与命令都是只读输入框 + 复制按钮:64 位 hex 手抄必错。
34
+ */
35
+ export function TokenModal({ issued, onClose }: { issued: IssuedCredential | null, onClose: () => void }) {
36
+ const { t } = useTranslation();
37
+ const [copied, setCopied] = useState<string | null>(null);
38
+ if (!issued)
39
+ return null;
40
+ const command = buildKeygenCommand(issued.token);
41
+ const copyRow = (testId: string, value: string) => (
42
+ <Space.Compact style={{ width: "100%", marginBottom: 16 }}>
43
+ <Input readOnly value={value} data-testid={testId} />
44
+ <Button
45
+ onClick={() => {
46
+ void copy(value);
47
+ setCopied(testId);
48
+ }}
49
+ >
50
+ {copied === testId ? t("publish:issued.copied") : t("publish:issued.copy")}
51
+ </Button>
52
+ </Space.Compact>
53
+ );
54
+
55
+ return (
56
+ <Modal
57
+ open
58
+ closable={false}
59
+ maskClosable={false}
60
+ keyboard={false}
61
+ title={t("publish:issued.title")}
62
+ footer={<Button type="primary" onClick={onClose}>{t("publish:issued.done")}</Button>}
63
+ >
64
+ <div data-testid="publish-issued">
65
+ <Alert type="warning" showIcon message={t("publish:issued.warning")} style={{ marginBottom: 16 }} />
66
+ <Typography.Paragraph>
67
+ <Typography.Text type="secondary">{t("publish:issued.identity")}</Typography.Text>
68
+ <br />
69
+ <Typography.Text copyable={{ text: issued.key_id }} code>{issued.key_id}</Typography.Text>
70
+ </Typography.Paragraph>
71
+ <Typography.Paragraph style={{ marginBottom: 4 }}>
72
+ <Typography.Text type="secondary">{t("publish:issued.token")}</Typography.Text>
73
+ </Typography.Paragraph>
74
+ {copyRow("publish-token", issued.token)}
75
+ <Typography.Paragraph style={{ marginBottom: 4 }}>
76
+ <Typography.Text type="secondary">{t("publish:issued.command")}</Typography.Text>
77
+ </Typography.Paragraph>
78
+ {copyRow("publish-command", command)}
79
+ </div>
80
+ </Modal>
81
+ );
82
+ }
@@ -0,0 +1,41 @@
1
+ import type { AppRouteRecordRaw, ModuleContext } from "@oj-module/runtime";
2
+
3
+ import { HistoryOutlined, KeyOutlined } from "@ant-design/icons";
4
+
5
+ import { createElement, lazy } from "react";
6
+
7
+ import { createPublishClient } from "./__client";
8
+
9
+ const PublishPage = lazy(() => import("./pages"));
10
+ const ReleaseHistoryPage = lazy(() => import("./pages/history"));
11
+
12
+ /**
13
+ * 「方案市场」下的两个子页(单模单根:菜单只有 `/oj-market` 一个根)。
14
+ *
15
+ * 路径是**相对父路由**声明的:`publish` → `/oj-market/publish`,`history` → `/oj-market/history`。
16
+ * 发布管理不挂 handle.roles:申请发布凭证是普通登录用户的能力,超管多出来的只是
17
+ * 「看到所有租户的凭证」,由后端按角色决定返回范围,前端不重复判权。
18
+ */
19
+ export const routes: AppRouteRecordRaw[] = [
20
+ {
21
+ path: "publish",
22
+ Component: PublishPage,
23
+ handle: {
24
+ title: "publish:menu.publish",
25
+ icon: createElement(KeyOutlined),
26
+ },
27
+ },
28
+ {
29
+ path: "history",
30
+ Component: ReleaseHistoryPage,
31
+ handle: {
32
+ title: "publish:menu.history",
33
+ icon: createElement(HistoryOutlined),
34
+ },
35
+ },
36
+ ];
37
+
38
+ /** 构造即接线:登记契约前缀 /publish + 绑定 scoped request,页面直接 import 的函数才有通道 */
39
+ export function onInit(ctx: ModuleContext): void {
40
+ createPublishClient(ctx);
41
+ }
@@ -61,6 +61,12 @@ export interface IndexRow {
61
61
  upgradable: boolean
62
62
  /** 最新版许可(SPDX 简化式,来自分片条目的 manifest.license;未声明 → null) */
63
63
  license?: string | null
64
+ /** 发布者(分片条目 archive.signature.key_id,经验签的签名身份;与后端 trust_state/key_id 同用 snake_case) */
65
+ publisher_key?: string | null
66
+ /** 方案简介(manifest.summary,C2-04 单行 1..200;索引未带该字段 → undefined/null) */
67
+ summary?: string | null
68
+ /** 方案详细描述(manifest.description,C2-05 ≤2000;索引未带该字段 → undefined/null) */
69
+ description?: string | null
64
70
  }
65
71
 
66
72
  /** 安装输入(POST /_platform/market/install) */
@@ -97,3 +103,27 @@ export interface UninstallImpact {
97
103
  affectedRoles: number
98
104
  affectedUsers: number
99
105
  }
106
+
107
+ /** 发布历史一行(`market_release`;来源是签名索引,追加式记录) */
108
+ export interface ReleaseRow {
109
+ id: number
110
+ product: string
111
+ version: string
112
+ key_id: string | null
113
+ sha256: string | null
114
+ size: number | null
115
+ published_at: number
116
+ /** file = 分发包 Last-Modified;index = 索引生成时间兜底 */
117
+ published_at_source: "file" | "index"
118
+ yanked: number
119
+ }
120
+
121
+ /** 发布历史分页结果 */
122
+ export interface ReleasePage {
123
+ list: ReleaseRow[]
124
+ total: number
125
+ page: number
126
+ size: number
127
+ /** 本次同步索引失败的人话(页面照常显示已入库历史) */
128
+ syncError: string | null
129
+ }