@ai-partner-x/aiko-boot-cli 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (389) hide show
  1. package/README.md +187 -0
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +30 -0
  4. package/dist/commands/add-api.d.ts +5 -0
  5. package/dist/commands/add-api.js +34 -0
  6. package/dist/commands/add-app.d.ts +5 -0
  7. package/dist/commands/add-app.js +34 -0
  8. package/dist/commands/add-feature.d.ts +5 -0
  9. package/dist/commands/add-feature.js +32 -0
  10. package/dist/commands/init.d.ts +7 -0
  11. package/dist/commands/init.js +42 -0
  12. package/dist/commands/list.d.ts +6 -0
  13. package/dist/commands/list.js +36 -0
  14. package/dist/core/framework-version.d.ts +8 -0
  15. package/dist/core/framework-version.js +40 -0
  16. package/dist/core/logger.d.ts +6 -0
  17. package/dist/core/logger.js +16 -0
  18. package/dist/core/project-config.d.ts +21 -0
  19. package/dist/core/project-config.js +17 -0
  20. package/dist/core/prompts.d.ts +5 -0
  21. package/dist/core/prompts.js +43 -0
  22. package/dist/core/template-utils.d.ts +1 -0
  23. package/dist/core/template-utils.js +42 -0
  24. package/dist/core/workspace.d.ts +10 -0
  25. package/dist/core/workspace.js +141 -0
  26. package/dist/index.d.ts +2 -0
  27. package/dist/index.js +2 -0
  28. package/dist/scaffold.d.ts +7 -0
  29. package/dist/scaffold.js +272 -0
  30. package/dist/usecases/add-api.usecase.d.ts +16 -0
  31. package/dist/usecases/add-api.usecase.js +87 -0
  32. package/dist/usecases/add-app.usecase.d.ts +16 -0
  33. package/dist/usecases/add-app.usecase.js +101 -0
  34. package/dist/usecases/add-feature.usecase.d.ts +15 -0
  35. package/dist/usecases/add-feature.usecase.js +566 -0
  36. package/dist/usecases/init-scaffold.usecase.d.ts +19 -0
  37. package/dist/usecases/init-scaffold.usecase.js +131 -0
  38. package/package.json +43 -0
  39. package/templates/api-base/app.config.ts +155 -0
  40. package/templates/api-base/package.json +55 -0
  41. package/templates/api-base/scripts/codegen.cjs +30 -0
  42. package/templates/api-base/scripts/codegen.ts +10 -0
  43. package/templates/api-base/src/controller/auth.controller.ts +160 -0
  44. package/templates/api-base/src/controller/menu.controller.ts +56 -0
  45. package/templates/api-base/src/controller/role.controller.ts +62 -0
  46. package/templates/api-base/src/controller/user.controller.ts +75 -0
  47. package/templates/api-base/src/dto/auth.dto.ts +31 -0
  48. package/templates/api-base/src/dto/menu.dto.ts +38 -0
  49. package/templates/api-base/src/dto/role.dto.ts +18 -0
  50. package/templates/api-base/src/dto/user.dto.ts +36 -0
  51. package/templates/api-base/src/entity/menu.entity.ts +35 -0
  52. package/templates/api-base/src/entity/role-menu.entity.ts +14 -0
  53. package/templates/api-base/src/entity/role.entity.ts +23 -0
  54. package/templates/api-base/src/entity/user-role.entity.ts +14 -0
  55. package/templates/api-base/src/entity/user.entity.ts +32 -0
  56. package/templates/api-base/src/mapper/menu.mapper.ts +7 -0
  57. package/templates/api-base/src/mapper/role-menu.mapper.ts +7 -0
  58. package/templates/api-base/src/mapper/role.mapper.ts +7 -0
  59. package/templates/api-base/src/mapper/user-role.mapper.ts +7 -0
  60. package/templates/api-base/src/mapper/user.mapper.ts +12 -0
  61. package/templates/api-base/src/scripts/init-db.ts +204 -0
  62. package/templates/api-base/src/server.ts +69 -0
  63. package/templates/api-base/src/service/auth.service.ts +144 -0
  64. package/templates/api-base/src/service/log.request.service.ts +72 -0
  65. package/templates/api-base/src/service/menu.service.ts +94 -0
  66. package/templates/api-base/src/service/role.service.ts +88 -0
  67. package/templates/api-base/src/service/user.service.ts +175 -0
  68. package/templates/api-base/src/utils/jwt.util.ts +39 -0
  69. package/templates/api-base/tsconfig.json +18 -0
  70. package/templates/feature-file/api/upload.controller.ts +97 -0
  71. package/templates/feature-log/api/docs/log-integration-guide.md +54 -0
  72. package/templates/feature-log/api/src/service/log.request.service.ts +112 -0
  73. package/templates/feature-log/api/src/service/log.service.ts +124 -0
  74. package/templates/feature-mq/api/src/controller/mq.controller.ts +35 -0
  75. package/templates/feature-mq/api/src/dto/mq.dto.ts +16 -0
  76. package/templates/feature-mq/api/src/service/mq.consumer.service.ts +26 -0
  77. package/templates/feature-redis/api/src/controller/cache.controller.ts +107 -0
  78. package/templates/feature-redis/api/src/dto/cache.dto.ts +24 -0
  79. package/templates/feature-redis/api/src/service/cache.service.ts +80 -0
  80. package/templates/scaffold-default/README.md +114 -0
  81. package/templates/scaffold-default/package.json +26 -0
  82. package/templates/scaffold-default/packages/admin/.env.dev +1 -0
  83. package/templates/scaffold-default/packages/admin/.env.prod +4 -0
  84. package/templates/scaffold-default/packages/admin/.env.stage +4 -0
  85. package/templates/scaffold-default/packages/admin/Dockerfile +37 -0
  86. package/templates/scaffold-default/packages/admin/README.MD +27 -0
  87. package/templates/scaffold-default/packages/admin/components.json +21 -0
  88. package/templates/scaffold-default/packages/admin/eslint.config.js +28 -0
  89. package/templates/scaffold-default/packages/admin/index.html +50 -0
  90. package/templates/scaffold-default/packages/admin/package.json +100 -0
  91. package/templates/scaffold-default/packages/admin/public/vite.svg +1 -0
  92. package/templates/scaffold-default/packages/admin/src/App.css +82 -0
  93. package/templates/scaffold-default/packages/admin/src/App.tsx +128 -0
  94. package/templates/scaffold-default/packages/admin/src/app.config.ts +3 -0
  95. package/templates/scaffold-default/packages/admin/src/components/admin-ui/data-table/data-table-pagination.tsx +148 -0
  96. package/templates/scaffold-default/packages/admin/src/components/admin-ui/data-table/data-table-sorter.tsx +50 -0
  97. package/templates/scaffold-default/packages/admin/src/components/admin-ui/data-table/index.tsx +266 -0
  98. package/templates/scaffold-default/packages/admin/src/components/admin-ui/editable-table.tsx +292 -0
  99. package/templates/scaffold-default/packages/admin/src/components/admin-ui/form/input-password.tsx +38 -0
  100. package/templates/scaffold-default/packages/admin/src/components/admin-ui/form/sign-in-form.tsx +118 -0
  101. package/templates/scaffold-default/packages/admin/src/components/admin-ui/layout/error-component.tsx +71 -0
  102. package/templates/scaffold-default/packages/admin/src/components/admin-ui/layout/header.tsx +162 -0
  103. package/templates/scaffold-default/packages/admin/src/components/admin-ui/layout/language-switcher.tsx +47 -0
  104. package/templates/scaffold-default/packages/admin/src/components/admin-ui/layout/layout.tsx +42 -0
  105. package/templates/scaffold-default/packages/admin/src/components/admin-ui/layout/loading-overlay.tsx +36 -0
  106. package/templates/scaffold-default/packages/admin/src/components/admin-ui/layout/shell-bar.tsx +232 -0
  107. package/templates/scaffold-default/packages/admin/src/components/admin-ui/layout/sidebar.tsx +193 -0
  108. package/templates/scaffold-default/packages/admin/src/components/admin-ui/layout/user-avatar.tsx +31 -0
  109. package/templates/scaffold-default/packages/admin/src/components/admin-ui/list-report.tsx +306 -0
  110. package/templates/scaffold-default/packages/admin/src/components/admin-ui/master-detail.tsx +382 -0
  111. package/templates/scaffold-default/packages/admin/src/components/admin-ui/notification/toaster.tsx +23 -0
  112. package/templates/scaffold-default/packages/admin/src/components/admin-ui/notification/undoable-notification.tsx +84 -0
  113. package/templates/scaffold-default/packages/admin/src/components/admin-ui/object-page.tsx +539 -0
  114. package/templates/scaffold-default/packages/admin/src/components/admin-ui/theme/theme-provider.tsx +160 -0
  115. package/templates/scaffold-default/packages/admin/src/components/admin-ui/theme/theme-select.tsx +129 -0
  116. package/templates/scaffold-default/packages/admin/src/components/admin-ui/theme/theme-toggle.tsx +90 -0
  117. package/templates/scaffold-default/packages/admin/src/components/ui/accordion.tsx +64 -0
  118. package/templates/scaffold-default/packages/admin/src/components/ui/alert-dialog.tsx +157 -0
  119. package/templates/scaffold-default/packages/admin/src/components/ui/alert.tsx +66 -0
  120. package/templates/scaffold-default/packages/admin/src/components/ui/aspect-ratio.tsx +9 -0
  121. package/templates/scaffold-default/packages/admin/src/components/ui/avatar.tsx +53 -0
  122. package/templates/scaffold-default/packages/admin/src/components/ui/badge.tsx +47 -0
  123. package/templates/scaffold-default/packages/admin/src/components/ui/breadcrumb.tsx +111 -0
  124. package/templates/scaffold-default/packages/admin/src/components/ui/button.tsx +59 -0
  125. package/templates/scaffold-default/packages/admin/src/components/ui/calendar.tsx +74 -0
  126. package/templates/scaffold-default/packages/admin/src/components/ui/card.tsx +92 -0
  127. package/templates/scaffold-default/packages/admin/src/components/ui/carousel.tsx +237 -0
  128. package/templates/scaffold-default/packages/admin/src/components/ui/chart.tsx +351 -0
  129. package/templates/scaffold-default/packages/admin/src/components/ui/checkbox.tsx +32 -0
  130. package/templates/scaffold-default/packages/admin/src/components/ui/collapsible.tsx +33 -0
  131. package/templates/scaffold-default/packages/admin/src/components/ui/command.tsx +182 -0
  132. package/templates/scaffold-default/packages/admin/src/components/ui/context-menu.tsx +252 -0
  133. package/templates/scaffold-default/packages/admin/src/components/ui/dialog.tsx +141 -0
  134. package/templates/scaffold-default/packages/admin/src/components/ui/drawer.tsx +130 -0
  135. package/templates/scaffold-default/packages/admin/src/components/ui/dropdown-menu.tsx +255 -0
  136. package/templates/scaffold-default/packages/admin/src/components/ui/form.tsx +166 -0
  137. package/templates/scaffold-default/packages/admin/src/components/ui/hover-card.tsx +42 -0
  138. package/templates/scaffold-default/packages/admin/src/components/ui/input-otp.tsx +77 -0
  139. package/templates/scaffold-default/packages/admin/src/components/ui/input.tsx +21 -0
  140. package/templates/scaffold-default/packages/admin/src/components/ui/label.tsx +22 -0
  141. package/templates/scaffold-default/packages/admin/src/components/ui/menubar.tsx +274 -0
  142. package/templates/scaffold-default/packages/admin/src/components/ui/navigation-menu.tsx +168 -0
  143. package/templates/scaffold-default/packages/admin/src/components/ui/pagination.tsx +127 -0
  144. package/templates/scaffold-default/packages/admin/src/components/ui/popover.tsx +48 -0
  145. package/templates/scaffold-default/packages/admin/src/components/ui/progress.tsx +29 -0
  146. package/templates/scaffold-default/packages/admin/src/components/ui/radio-group.tsx +45 -0
  147. package/templates/scaffold-default/packages/admin/src/components/ui/resizable.tsx +54 -0
  148. package/templates/scaffold-default/packages/admin/src/components/ui/scroll-area.tsx +58 -0
  149. package/templates/scaffold-default/packages/admin/src/components/ui/select.tsx +183 -0
  150. package/templates/scaffold-default/packages/admin/src/components/ui/separator.tsx +26 -0
  151. package/templates/scaffold-default/packages/admin/src/components/ui/sheet.tsx +139 -0
  152. package/templates/scaffold-default/packages/admin/src/components/ui/sidebar.tsx +740 -0
  153. package/templates/scaffold-default/packages/admin/src/components/ui/skeleton.tsx +13 -0
  154. package/templates/scaffold-default/packages/admin/src/components/ui/slider.tsx +63 -0
  155. package/templates/scaffold-default/packages/admin/src/components/ui/sonner.tsx +23 -0
  156. package/templates/scaffold-default/packages/admin/src/components/ui/switch.tsx +31 -0
  157. package/templates/scaffold-default/packages/admin/src/components/ui/table.tsx +114 -0
  158. package/templates/scaffold-default/packages/admin/src/components/ui/tabs.tsx +66 -0
  159. package/templates/scaffold-default/packages/admin/src/components/ui/textarea.tsx +18 -0
  160. package/templates/scaffold-default/packages/admin/src/components/ui/toggle-group.tsx +73 -0
  161. package/templates/scaffold-default/packages/admin/src/components/ui/toggle.tsx +45 -0
  162. package/templates/scaffold-default/packages/admin/src/components/ui/tooltip.tsx +59 -0
  163. package/templates/scaffold-default/packages/admin/src/hooks/use-mobile.ts +21 -0
  164. package/templates/scaffold-default/packages/admin/src/i18n.ts +20 -0
  165. package/templates/scaffold-default/packages/admin/src/index.tsx +19 -0
  166. package/templates/scaffold-default/packages/admin/src/layouts/menu-layout.tsx +211 -0
  167. package/templates/scaffold-default/packages/admin/src/layouts/tile-layout.tsx +355 -0
  168. package/templates/scaffold-default/packages/admin/src/lib/utils.ts +6 -0
  169. package/templates/scaffold-default/packages/admin/src/locales/en.json +68 -0
  170. package/templates/scaffold-default/packages/admin/src/locales/zh.json +68 -0
  171. package/templates/scaffold-default/packages/admin/src/pages/dashboard.tsx +12 -0
  172. package/templates/scaffold-default/packages/admin/src/pages/goods-receipt/CreatePage.tsx +302 -0
  173. package/templates/scaffold-default/packages/admin/src/pages/goods-receipt/EditPage.tsx +221 -0
  174. package/templates/scaffold-default/packages/admin/src/pages/goods-receipt/ListPage.tsx +283 -0
  175. package/templates/scaffold-default/packages/admin/src/pages/goods-receipt/ViewPage.tsx +280 -0
  176. package/templates/scaffold-default/packages/admin/src/pages/goods-receipt/index.ts +4 -0
  177. package/templates/scaffold-default/packages/admin/src/pages/home-page.tsx +244 -0
  178. package/templates/scaffold-default/packages/admin/src/pages/master-data/cost-centers/index.tsx +461 -0
  179. package/templates/scaffold-default/packages/admin/src/pages/master-data/currencies/index.tsx +255 -0
  180. package/templates/scaffold-default/packages/admin/src/pages/master-data/materials/ListPage.tsx +271 -0
  181. package/templates/scaffold-default/packages/admin/src/pages/master-data/materials/ViewPage.tsx +240 -0
  182. package/templates/scaffold-default/packages/admin/src/pages/master-data/materials/index.ts +2 -0
  183. package/templates/scaffold-default/packages/admin/src/pages/master-data/plants/ListPage.tsx +279 -0
  184. package/templates/scaffold-default/packages/admin/src/pages/master-data/plants/ViewPage.tsx +380 -0
  185. package/templates/scaffold-default/packages/admin/src/pages/master-data/plants/index.ts +2 -0
  186. package/templates/scaffold-default/packages/admin/src/pages/master-data/purchase-organizations/index.tsx +341 -0
  187. package/templates/scaffold-default/packages/admin/src/pages/master-data/units-of-measure/index.tsx +295 -0
  188. package/templates/scaffold-default/packages/admin/src/pages/master-data/vendors/ListPage.tsx +266 -0
  189. package/templates/scaffold-default/packages/admin/src/pages/master-data/vendors/ViewPage.tsx +274 -0
  190. package/templates/scaffold-default/packages/admin/src/pages/master-data/vendors/index.ts +2 -0
  191. package/templates/scaffold-default/packages/admin/src/pages/placeholder-page.tsx +13 -0
  192. package/templates/scaffold-default/packages/admin/src/pages/purchase-orders/ListPage.tsx +289 -0
  193. package/templates/scaffold-default/packages/admin/src/pages/purchase-orders/ViewPage.tsx +343 -0
  194. package/templates/scaffold-default/packages/admin/src/pages/purchase-orders/index.ts +2 -0
  195. package/templates/scaffold-default/packages/admin/src/pages/purchase-requisitions/CreatePage.tsx +398 -0
  196. package/templates/scaffold-default/packages/admin/src/pages/purchase-requisitions/EditPage.tsx +473 -0
  197. package/templates/scaffold-default/packages/admin/src/pages/purchase-requisitions/ListPage.tsx +307 -0
  198. package/templates/scaffold-default/packages/admin/src/pages/purchase-requisitions/ViewPage.tsx +304 -0
  199. package/templates/scaffold-default/packages/admin/src/pages/purchase-requisitions/constants.ts +51 -0
  200. package/templates/scaffold-default/packages/admin/src/pages/purchase-requisitions/index.ts +4 -0
  201. package/templates/scaffold-default/packages/admin/src/pages/reports/PurchaseOrderReport.tsx +312 -0
  202. package/templates/scaffold-default/packages/admin/src/pages/reports/PurchaseRequisitionReport.tsx +303 -0
  203. package/templates/scaffold-default/packages/admin/src/pages/reports/index.ts +2 -0
  204. package/templates/scaffold-default/packages/admin/src/pages/settings-page.tsx +335 -0
  205. package/templates/scaffold-default/packages/admin/src/providers/app-config.tsx +50 -0
  206. package/templates/scaffold-default/packages/admin/src/providers/auth-provider.ts +2 -0
  207. package/templates/scaffold-default/packages/admin/src/routes/auth.ts +9 -0
  208. package/templates/scaffold-default/packages/admin/src/routes/index.ts +85 -0
  209. package/templates/scaffold-default/packages/admin/src/routes/menu.ts +176 -0
  210. package/templates/scaffold-default/packages/admin/src/routes/modules/goods-receipt.ts +31 -0
  211. package/templates/scaffold-default/packages/admin/src/routes/modules/master-data.ts +41 -0
  212. package/templates/scaffold-default/packages/admin/src/routes/modules/purchase-orders.ts +27 -0
  213. package/templates/scaffold-default/packages/admin/src/routes/modules/purchase-requisitions.ts +39 -0
  214. package/templates/scaffold-default/packages/admin/src/routes/modules/reports.ts +33 -0
  215. package/templates/scaffold-default/packages/admin/src/routes/modules/settings.ts +19 -0
  216. package/templates/scaffold-default/packages/admin/src/routes/withSuspense.tsx +21 -0
  217. package/templates/scaffold-default/packages/admin/src/theme/amber.css +27 -0
  218. package/templates/scaffold-default/packages/admin/src/theme/blue.css +27 -0
  219. package/templates/scaffold-default/packages/admin/src/theme/default.css +75 -0
  220. package/templates/scaffold-default/packages/admin/src/theme/fiori.css +180 -0
  221. package/templates/scaffold-default/packages/admin/src/theme/green.css +27 -0
  222. package/templates/scaffold-default/packages/admin/src/theme/index.css +12 -0
  223. package/templates/scaffold-default/packages/admin/src/theme/rose.css +27 -0
  224. package/templates/scaffold-default/packages/admin/src/theme/violet.css +27 -0
  225. package/templates/scaffold-default/packages/admin/src/vite-env.d.ts +1 -0
  226. package/templates/scaffold-default/packages/admin/tsconfig.json +28 -0
  227. package/templates/scaffold-default/packages/admin/tsconfig.node.json +21 -0
  228. package/templates/scaffold-default/packages/admin/vite.config.ts +26 -0
  229. package/templates/scaffold-default/packages/api/.eslintrc.json +6 -0
  230. package/templates/scaffold-default/packages/api/.swcrc +17 -0
  231. package/templates/scaffold-default/packages/api/app.config.ts +163 -0
  232. package/templates/scaffold-default/packages/api/docs/api-document.md +497 -0
  233. package/templates/scaffold-default/packages/api/docs/final-completion-report.md +565 -0
  234. package/templates/scaffold-default/packages/api/docs/permission-integration-summary.md +432 -0
  235. package/templates/scaffold-default/packages/api/examples/security/README.md +664 -0
  236. package/templates/scaffold-default/packages/api/examples/security/complete/.env.example +26 -0
  237. package/templates/scaffold-default/packages/api/examples/security/complete/PROJECT_STRUCTURE.md +220 -0
  238. package/templates/scaffold-default/packages/api/examples/security/complete/README.md +847 -0
  239. package/templates/scaffold-default/packages/api/examples/security/complete/app.config.ts +69 -0
  240. package/templates/scaffold-default/packages/api/examples/security/complete/app.ts +63 -0
  241. package/templates/scaffold-default/packages/api/examples/security/complete/controller/auth.controller.ts +131 -0
  242. package/templates/scaffold-default/packages/api/examples/security/complete/controller/index.ts +4 -0
  243. package/templates/scaffold-default/packages/api/examples/security/complete/controller/permission.controller.ts +41 -0
  244. package/templates/scaffold-default/packages/api/examples/security/complete/controller/role.controller.ts +53 -0
  245. package/templates/scaffold-default/packages/api/examples/security/complete/controller/user.controller.ts +53 -0
  246. package/templates/scaffold-default/packages/api/examples/security/complete/dto/change-password.dto.ts +10 -0
  247. package/templates/scaffold-default/packages/api/examples/security/complete/dto/create-permission.dto.ts +14 -0
  248. package/templates/scaffold-default/packages/api/examples/security/complete/dto/create-role.dto.ts +11 -0
  249. package/templates/scaffold-default/packages/api/examples/security/complete/dto/create-user.dto.ts +15 -0
  250. package/templates/scaffold-default/packages/api/examples/security/complete/dto/index.ts +7 -0
  251. package/templates/scaffold-default/packages/api/examples/security/complete/dto/login.dto.ts +10 -0
  252. package/templates/scaffold-default/packages/api/examples/security/complete/dto/oauth-profile.dto.ts +7 -0
  253. package/templates/scaffold-default/packages/api/examples/security/complete/dto/register.dto.ts +17 -0
  254. package/templates/scaffold-default/packages/api/examples/security/complete/entity/index.ts +6 -0
  255. package/templates/scaffold-default/packages/api/examples/security/complete/entity/oauth-account.entity.ts +39 -0
  256. package/templates/scaffold-default/packages/api/examples/security/complete/entity/permission.entity.ts +31 -0
  257. package/templates/scaffold-default/packages/api/examples/security/complete/entity/role-permission.entity.ts +19 -0
  258. package/templates/scaffold-default/packages/api/examples/security/complete/entity/role.entity.ts +25 -0
  259. package/templates/scaffold-default/packages/api/examples/security/complete/entity/user-role.entity.ts +19 -0
  260. package/templates/scaffold-default/packages/api/examples/security/complete/entity/user.entity.ts +46 -0
  261. package/templates/scaffold-default/packages/api/examples/security/complete/init.sql +81 -0
  262. package/templates/scaffold-default/packages/api/examples/security/complete/middleware/auth.interceptor.ts +39 -0
  263. package/templates/scaffold-default/packages/api/examples/security/complete/middleware/index.ts +2 -0
  264. package/templates/scaffold-default/packages/api/examples/security/complete/middleware/permission.interceptor.ts +61 -0
  265. package/templates/scaffold-default/packages/api/examples/security/complete/package.json +54 -0
  266. package/templates/scaffold-default/packages/api/examples/security/complete/seed.sql +42 -0
  267. package/templates/scaffold-default/packages/api/examples/security/complete/service/auth.service.ts +41 -0
  268. package/templates/scaffold-default/packages/api/examples/security/complete/service/index.ts +5 -0
  269. package/templates/scaffold-default/packages/api/examples/security/complete/service/oauth.service.ts +82 -0
  270. package/templates/scaffold-default/packages/api/examples/security/complete/service/permission.service.ts +113 -0
  271. package/templates/scaffold-default/packages/api/examples/security/complete/service/role.service.ts +85 -0
  272. package/templates/scaffold-default/packages/api/examples/security/complete/service/user.service.ts +132 -0
  273. package/templates/scaffold-default/packages/api/examples/security/complete/tests/TEST_REPORT.md +318 -0
  274. package/templates/scaffold-default/packages/api/examples/security/complete/tests/generate-report.js +335 -0
  275. package/templates/scaffold-default/packages/api/examples/security/complete/tests/helpers/api-helpers.ts +116 -0
  276. package/templates/scaffold-default/packages/api/examples/security/complete/tests/helpers/index.ts +2 -0
  277. package/templates/scaffold-default/packages/api/examples/security/complete/tests/helpers/test-helpers.ts +129 -0
  278. package/templates/scaffold-default/packages/api/examples/security/complete/tests/integration/auth.api.test.ts +429 -0
  279. package/templates/scaffold-default/packages/api/examples/security/complete/tests/integration/role.api.test.ts +400 -0
  280. package/templates/scaffold-default/packages/api/examples/security/complete/tests/integration/user.api.test.ts +459 -0
  281. package/templates/scaffold-default/packages/api/examples/security/complete/tests/jest.config.js +40 -0
  282. package/templates/scaffold-default/packages/api/examples/security/complete/tests/run-all-tests.js +135 -0
  283. package/templates/scaffold-default/packages/api/examples/security/complete/tests/run-tests.js +109 -0
  284. package/templates/scaffold-default/packages/api/examples/security/complete/tests/setup.ts +19 -0
  285. package/templates/scaffold-default/packages/api/examples/security/complete/tests/unit/auth.service.test.ts +199 -0
  286. package/templates/scaffold-default/packages/api/examples/security/complete/tests/unit/permission.service.test.ts +377 -0
  287. package/templates/scaffold-default/packages/api/examples/security/complete/tests/unit/user.service.test.ts +288 -0
  288. package/templates/scaffold-default/packages/api/examples/security/complete/tsconfig.json +35 -0
  289. package/templates/scaffold-default/packages/api/examples/security/jwt/README.md +424 -0
  290. package/templates/scaffold-default/packages/api/examples/security/local/README.md +499 -0
  291. package/templates/scaffold-default/packages/api/examples/security/oauth2/README.md +637 -0
  292. package/templates/scaffold-default/packages/api/examples/security/permission/README.md +943 -0
  293. package/templates/scaffold-default/packages/api/examples/security/session/README.md +753 -0
  294. package/templates/scaffold-default/packages/api/package.json +63 -0
  295. package/templates/scaffold-default/packages/api/scripts/codegen.cjs +29 -0
  296. package/templates/scaffold-default/packages/api/scripts/codegen.ts +9 -0
  297. package/templates/scaffold-default/packages/api/src/config/security-auto-configuration.ts +75 -0
  298. package/templates/scaffold-default/packages/api/src/controller/auth.controller.ts +109 -0
  299. package/templates/scaffold-default/packages/api/src/controller/cache.controller.ts +106 -0
  300. package/templates/scaffold-default/packages/api/src/controller/menu.controller.ts +86 -0
  301. package/templates/scaffold-default/packages/api/src/controller/mq.controller.ts +35 -0
  302. package/templates/scaffold-default/packages/api/src/controller/role.controller.ts +100 -0
  303. package/templates/scaffold-default/packages/api/src/controller/upload.controller.ts +83 -0
  304. package/templates/scaffold-default/packages/api/src/controller/user.controller.ts +102 -0
  305. package/templates/scaffold-default/packages/api/src/dto/auth.dto.ts +30 -0
  306. package/templates/scaffold-default/packages/api/src/dto/cache.dto.ts +24 -0
  307. package/templates/scaffold-default/packages/api/src/dto/menu.dto.ts +37 -0
  308. package/templates/scaffold-default/packages/api/src/dto/mq.dto.ts +16 -0
  309. package/templates/scaffold-default/packages/api/src/dto/role.dto.ts +16 -0
  310. package/templates/scaffold-default/packages/api/src/dto/user.dto.ts +35 -0
  311. package/templates/scaffold-default/packages/api/src/entity/menu.entity.ts +34 -0
  312. package/templates/scaffold-default/packages/api/src/entity/role-menu.entity.ts +13 -0
  313. package/templates/scaffold-default/packages/api/src/entity/role.entity.ts +22 -0
  314. package/templates/scaffold-default/packages/api/src/entity/user-role.entity.ts +13 -0
  315. package/templates/scaffold-default/packages/api/src/entity/user.entity.ts +31 -0
  316. package/templates/scaffold-default/packages/api/src/mapper/menu.mapper.ts +6 -0
  317. package/templates/scaffold-default/packages/api/src/mapper/role-menu.mapper.ts +6 -0
  318. package/templates/scaffold-default/packages/api/src/mapper/role.mapper.ts +6 -0
  319. package/templates/scaffold-default/packages/api/src/mapper/user-role.mapper.ts +6 -0
  320. package/templates/scaffold-default/packages/api/src/mapper/user.mapper.ts +11 -0
  321. package/templates/scaffold-default/packages/api/src/scripts/assign-role.ts +41 -0
  322. package/templates/scaffold-default/packages/api/src/scripts/check-user-role.ts +28 -0
  323. package/templates/scaffold-default/packages/api/src/scripts/check-users.mjs +44 -0
  324. package/templates/scaffold-default/packages/api/src/scripts/demo-permissions.mjs +418 -0
  325. package/templates/scaffold-default/packages/api/src/scripts/init-db.ts +166 -0
  326. package/templates/scaffold-default/packages/api/src/scripts/reset-admin-password.mjs +70 -0
  327. package/templates/scaffold-default/packages/api/src/scripts/reset-password.ts +31 -0
  328. package/templates/scaffold-default/packages/api/src/scripts/simple-reset-admin.mjs +39 -0
  329. package/templates/scaffold-default/packages/api/src/scripts/test-db.ts +36 -0
  330. package/templates/scaffold-default/packages/api/src/scripts/test-di.ts +45 -0
  331. package/templates/scaffold-default/packages/api/src/scripts/test-permissions.mjs +551 -0
  332. package/templates/scaffold-default/packages/api/src/scripts/update-admin-password.mjs +56 -0
  333. package/templates/scaffold-default/packages/api/src/scripts/user-roles.ts +28 -0
  334. package/templates/scaffold-default/packages/api/src/server.ts +38 -0
  335. package/templates/scaffold-default/packages/api/src/service/auth.service.ts +165 -0
  336. package/templates/scaffold-default/packages/api/src/service/cache.service.ts +80 -0
  337. package/templates/scaffold-default/packages/api/src/service/log.request.service.ts +158 -0
  338. package/templates/scaffold-default/packages/api/src/service/log.service.ts +123 -0
  339. package/templates/scaffold-default/packages/api/src/service/menu.service.ts +94 -0
  340. package/templates/scaffold-default/packages/api/src/service/mq.consumer.service.ts +26 -0
  341. package/templates/scaffold-default/packages/api/src/service/role.service.ts +88 -0
  342. package/templates/scaffold-default/packages/api/src/service/user.service.ts +195 -0
  343. package/templates/scaffold-default/packages/api/src/types/sqljs.d.ts +18 -0
  344. package/templates/scaffold-default/packages/api/src/utils/auth.utils.js +0 -0
  345. package/templates/scaffold-default/packages/api/src/utils/jwt.util.ts +29 -0
  346. package/templates/scaffold-default/packages/api/tsconfig.json +17 -0
  347. package/templates/scaffold-default/packages/api/tsup.config.ts +14 -0
  348. package/templates/scaffold-default/packages/api/uploads/.gitkeep +0 -0
  349. package/templates/scaffold-default/packages/core/package.json +28 -0
  350. package/templates/scaffold-default/packages/core/src/auth/auth-client-middleware.ts +22 -0
  351. package/templates/scaffold-default/packages/core/src/auth/auth-constants.ts +6 -0
  352. package/templates/scaffold-default/packages/core/src/auth/auth-service.ts +65 -0
  353. package/templates/scaffold-default/packages/core/src/auth/backend-auth-provider.ts +149 -0
  354. package/templates/scaffold-default/packages/core/src/auth/default-auth-provider.ts +38 -0
  355. package/templates/scaffold-default/packages/core/src/auth/index.ts +12 -0
  356. package/templates/scaffold-default/packages/core/src/auth/types.ts +38 -0
  357. package/templates/scaffold-default/packages/core/src/authorization/authorization-client-middleware.ts +38 -0
  358. package/templates/scaffold-default/packages/core/src/authorization/authorization-config.ts +13 -0
  359. package/templates/scaffold-default/packages/core/src/authorization/authorization-provider.tsx +116 -0
  360. package/templates/scaffold-default/packages/core/src/authorization/default-authorization-provider.ts +26 -0
  361. package/templates/scaffold-default/packages/core/src/authorization/index.ts +15 -0
  362. package/templates/scaffold-default/packages/core/src/authorization/types.ts +42 -0
  363. package/templates/scaffold-default/packages/core/src/index.ts +3 -0
  364. package/templates/scaffold-default/packages/core/src/utils/promise-result-cache.ts +18 -0
  365. package/templates/scaffold-default/packages/core/tsconfig.json +19 -0
  366. package/templates/scaffold-default/packages/mobile/README.md +56 -0
  367. package/templates/scaffold-default/packages/mobile/index.html +13 -0
  368. package/templates/scaffold-default/packages/mobile/package.json +28 -0
  369. package/templates/scaffold-default/packages/mobile/postcss.config.mjs +7 -0
  370. package/templates/scaffold-default/packages/mobile/src/App.tsx +5 -0
  371. package/templates/scaffold-default/packages/mobile/src/app/globals.css +1 -0
  372. package/templates/scaffold-default/packages/mobile/src/components/LoginForm.tsx +83 -0
  373. package/templates/scaffold-default/packages/mobile/src/hooks/index.ts +5 -0
  374. package/templates/scaffold-default/packages/mobile/src/lib/utils.ts +7 -0
  375. package/templates/scaffold-default/packages/mobile/src/main.tsx +19 -0
  376. package/templates/scaffold-default/packages/mobile/src/pages/HomePage.tsx +41 -0
  377. package/templates/scaffold-default/packages/mobile/src/pages/LoginPage.tsx +24 -0
  378. package/templates/scaffold-default/packages/mobile/src/pages/index.ts +2 -0
  379. package/templates/scaffold-default/packages/mobile/src/routes/ProtectedRoute.tsx +35 -0
  380. package/templates/scaffold-default/packages/mobile/src/routes/index.tsx +24 -0
  381. package/templates/scaffold-default/packages/mobile/src/routes/routes.ts +11 -0
  382. package/templates/scaffold-default/packages/mobile/src/types/index.ts +5 -0
  383. package/templates/scaffold-default/packages/mobile/src/vite-env.d.ts +1 -0
  384. package/templates/scaffold-default/packages/mobile/tsconfig.json +23 -0
  385. package/templates/scaffold-default/packages/mobile/tsconfig.node.json +11 -0
  386. package/templates/scaffold-default/packages/mobile/vite.config.ts +20 -0
  387. package/templates/scaffold-default/pnpm-workspace.yaml +2 -0
  388. package/templates/scaffold-default/scripts/postinstall.cjs +42 -0
  389. package/templates/scaffold-default/scripts/rebuild-sqlite.cjs +23 -0
@@ -0,0 +1,335 @@
1
+ import { useState } from "react";
2
+ import { Settings, User, Bell, Palette, Globe, Shield, Check } from "lucide-react";
3
+ import { cn } from "@/lib/utils";
4
+ import { Input } from "@/components/ui/input";
5
+ import { Label } from "@/components/ui/label";
6
+ import { Button } from "@/components/ui/button";
7
+ import {
8
+ Select,
9
+ SelectContent,
10
+ SelectItem,
11
+ SelectTrigger,
12
+ SelectValue,
13
+ } from "@/components/ui/select";
14
+ import { Switch } from "@/components/ui/switch";
15
+ import { useTheme } from "@/components/admin-ui/theme/theme-provider";
16
+ import type { Appearance, Palette as ThemePalette } from "@/components/admin-ui/theme/theme-provider";
17
+
18
+ function SettingSection({
19
+ icon,
20
+ title,
21
+ description,
22
+ children,
23
+ iconBg,
24
+ }: {
25
+ icon: React.ReactNode;
26
+ title: string;
27
+ description?: string;
28
+ children: React.ReactNode;
29
+ iconBg: string;
30
+ }) {
31
+ return (
32
+ <div className="overflow-hidden rounded-xl border border-border bg-card shadow-sm">
33
+ <div className="flex items-center gap-3 border-b border-border px-5 py-4">
34
+ <div className={cn("flex size-9 items-center justify-center rounded-lg text-primary-foreground", iconBg)}>
35
+ {icon}
36
+ </div>
37
+ <div>
38
+ <h3 className="font-semibold">{title}</h3>
39
+ {description && <p className="mt-0.5 text-xs text-muted-foreground">{description}</p>}
40
+ </div>
41
+ </div>
42
+ <div className="p-5">{children}</div>
43
+ </div>
44
+ );
45
+ }
46
+
47
+ function ThemeOption({
48
+ value,
49
+ label,
50
+ active,
51
+ icon,
52
+ onClick,
53
+ }: {
54
+ value: string;
55
+ label: string;
56
+ active: boolean;
57
+ icon: React.ReactNode;
58
+ onClick: () => void;
59
+ }) {
60
+ return (
61
+ <button
62
+ type="button"
63
+ onClick={onClick}
64
+ className={cn(
65
+ "relative flex flex-1 flex-col items-center gap-2 rounded-xl border-2 px-3 py-4 transition-all",
66
+ active ? "border-primary bg-primary/10" : "border-border bg-card hover:border-muted-foreground"
67
+ )}
68
+ >
69
+ <div
70
+ className={cn(
71
+ "flex size-12 items-center justify-center rounded-xl",
72
+ value === "light" && "bg-muted",
73
+ value === "dark" && "bg-muted-foreground",
74
+ value === "system" && "bg-gradient-to-br from-muted to-muted-foreground"
75
+ )}
76
+ >
77
+ {icon}
78
+ </div>
79
+ <span className={cn("text-sm font-medium", active ? "text-primary" : "text-muted-foreground")}>
80
+ {label}
81
+ </span>
82
+ {active && (
83
+ <span className="absolute right-2 top-2 flex size-5 items-center justify-center rounded-full bg-primary text-primary-foreground">
84
+ <Check className="size-3" />
85
+ </span>
86
+ )}
87
+ </button>
88
+ );
89
+ }
90
+
91
+ export function SettingsPage() {
92
+ const { appearance, palette, setTheme: setAppTheme } = useTheme();
93
+ const [language, setLanguage] = useState("zh-CN");
94
+ const [notifications, setNotifications] = useState({
95
+ email: true,
96
+ push: true,
97
+ sms: false,
98
+ });
99
+
100
+ return (
101
+ <div className="flex flex-col overflow-hidden rounded-lg bg-muted/30 shadow-sm">
102
+ <div className="bg-primary px-6 py-5 text-primary-foreground">
103
+ <div className="flex items-center gap-3">
104
+ <div className="flex size-10 items-center justify-center rounded-xl bg-white/20">
105
+ <Settings className="size-5" />
106
+ </div>
107
+ <div>
108
+ <h1 className="text-xl font-semibold">系统设置</h1>
109
+ <p className="mt-0.5 text-sm text-primary-foreground/80">管理您的账户和系统偏好设置</p>
110
+ </div>
111
+ </div>
112
+ </div>
113
+
114
+ <div className="flex-1 overflow-y-auto p-4">
115
+ <div className="mx-auto max-w-3xl space-y-4">
116
+ <SettingSection
117
+ icon={<User className="size-5" />}
118
+ title="个人信息"
119
+ description="管理您的账户基本信息"
120
+ iconBg="bg-primary"
121
+ >
122
+ <div className="mb-5 flex items-center gap-4">
123
+ <div className="flex size-16 items-center justify-center rounded-2xl bg-primary text-xl font-bold text-primary-foreground">
124
+ A
125
+ </div>
126
+ <div className="flex-1">
127
+ <h4 className="text-lg font-semibold">Admin</h4>
128
+ <p className="text-sm text-muted-foreground">系统管理员</p>
129
+ </div>
130
+ <Button variant="secondary" size="sm">
131
+ 编辑资料
132
+ </Button>
133
+ </div>
134
+ <div className="grid grid-cols-2 gap-4">
135
+ <div className="space-y-2">
136
+ <Label className="text-xs text-muted-foreground">用户名</Label>
137
+ <Input value="admin" disabled className="bg-muted" />
138
+ </div>
139
+ <div className="space-y-2">
140
+ <Label className="text-xs text-muted-foreground">邮箱地址</Label>
141
+ <Input value="admin@example.com" disabled className="bg-muted" />
142
+ </div>
143
+ <div className="space-y-2">
144
+ <Label className="text-xs text-muted-foreground">手机号码</Label>
145
+ <Input value="+86 138****8888" disabled className="bg-muted" />
146
+ </div>
147
+ <div className="space-y-2">
148
+ <Label className="text-xs text-muted-foreground">部门</Label>
149
+ <Input value="信息技术部" disabled className="bg-muted" />
150
+ </div>
151
+ </div>
152
+ </SettingSection>
153
+
154
+ <SettingSection
155
+ icon={<Bell className="size-5" />}
156
+ title="通知设置"
157
+ description="配置消息通知方式"
158
+ iconBg="bg-amber-500"
159
+ >
160
+ <div className="space-y-4">
161
+ <div className="flex items-center justify-between py-2">
162
+ <div>
163
+ <Label className="font-medium">邮件通知</Label>
164
+ <p className="text-xs text-muted-foreground">接收重要事项的邮件提醒</p>
165
+ </div>
166
+ <Switch
167
+ checked={notifications.email}
168
+ onCheckedChange={(v) => setNotifications({ ...notifications, email: v })}
169
+ />
170
+ </div>
171
+ <div className="flex items-center justify-between border-t border-border py-2">
172
+ <div>
173
+ <Label className="font-medium">浏览器推送</Label>
174
+ <p className="text-xs text-muted-foreground">在浏览器中接收实时通知</p>
175
+ </div>
176
+ <Switch
177
+ checked={notifications.push}
178
+ onCheckedChange={(v) => setNotifications({ ...notifications, push: v })}
179
+ />
180
+ </div>
181
+ <div className="flex items-center justify-between border-t border-border py-2">
182
+ <div>
183
+ <Label className="font-medium">短信通知</Label>
184
+ <p className="text-xs text-muted-foreground">接收紧急事项的短信提醒</p>
185
+ </div>
186
+ <Switch
187
+ checked={notifications.sms}
188
+ onCheckedChange={(v) => setNotifications({ ...notifications, sms: v })}
189
+ />
190
+ </div>
191
+ </div>
192
+ </SettingSection>
193
+
194
+ <SettingSection
195
+ icon={<Palette className="size-5" />}
196
+ title="外观设置"
197
+ description="自定义界面外观主题"
198
+ iconBg="bg-purple-500"
199
+ >
200
+ <div className="flex gap-3">
201
+ <ThemeOption
202
+ value="light"
203
+ label="浅色模式"
204
+ active={appearance === "light"}
205
+ onClick={() => setAppTheme({ appearance: "light" as Appearance })}
206
+ icon={<div className="size-6 rounded-full border-2 border-muted-foreground" />}
207
+ />
208
+ <ThemeOption
209
+ value="dark"
210
+ label="深色模式"
211
+ active={appearance === "dark"}
212
+ onClick={() => setAppTheme({ appearance: "dark" as Appearance })}
213
+ icon={<div className="size-6 rounded-full bg-muted-foreground" />}
214
+ />
215
+ <ThemeOption
216
+ value="system"
217
+ label="跟随系统"
218
+ active={appearance === "system"}
219
+ onClick={() => setAppTheme({ appearance: "system" as Appearance })}
220
+ icon={<div className="size-6 rounded-full bg-gradient-to-br from-muted to-muted-foreground" />}
221
+ />
222
+ </div>
223
+
224
+ <div className="mt-5 grid grid-cols-2 gap-4">
225
+ <div className="space-y-2">
226
+ <Label className="text-xs text-muted-foreground">配色</Label>
227
+ <Select
228
+ value={palette}
229
+ onValueChange={(v) => setAppTheme({ palette: v as ThemePalette })}
230
+ >
231
+ <SelectTrigger><SelectValue /></SelectTrigger>
232
+ <SelectContent>
233
+ <SelectItem value="default">默认</SelectItem>
234
+ <SelectItem value="blue">蓝色</SelectItem>
235
+ <SelectItem value="green">绿色</SelectItem>
236
+ <SelectItem value="violet">紫色</SelectItem>
237
+ <SelectItem value="rose">玫红</SelectItem>
238
+ <SelectItem value="amber">琥珀</SelectItem>
239
+ <SelectItem value="fiori">Fiori</SelectItem>
240
+ </SelectContent>
241
+ </Select>
242
+ </div>
243
+ </div>
244
+ </SettingSection>
245
+
246
+ <SettingSection
247
+ icon={<Globe className="size-5" />}
248
+ title="语言和地区"
249
+ description="设置界面语言和区域格式"
250
+ iconBg="bg-emerald-500"
251
+ >
252
+ <div className="grid grid-cols-2 gap-4">
253
+ <div className="space-y-2">
254
+ <Label className="text-xs text-muted-foreground">界面语言</Label>
255
+ <Select value={language} onValueChange={setLanguage}>
256
+ <SelectTrigger><SelectValue /></SelectTrigger>
257
+ <SelectContent>
258
+ <SelectItem value="zh-CN">简体中文</SelectItem>
259
+ <SelectItem value="zh-TW">繁體中文</SelectItem>
260
+ <SelectItem value="en-US">English (US)</SelectItem>
261
+ <SelectItem value="ja-JP">日本語</SelectItem>
262
+ </SelectContent>
263
+ </Select>
264
+ </div>
265
+ <div className="space-y-2">
266
+ <Label className="text-xs text-muted-foreground">时区</Label>
267
+ <Select value="Asia/Shanghai" onValueChange={() => {}}>
268
+ <SelectTrigger><SelectValue /></SelectTrigger>
269
+ <SelectContent>
270
+ <SelectItem value="Asia/Shanghai">(UTC+8) 中国标准时间</SelectItem>
271
+ <SelectItem value="Asia/Tokyo">(UTC+9) 日本标准时间</SelectItem>
272
+ <SelectItem value="America/New_York">(UTC-5) 美国东部时间</SelectItem>
273
+ </SelectContent>
274
+ </Select>
275
+ </div>
276
+ <div className="space-y-2">
277
+ <Label className="text-xs text-muted-foreground">日期格式</Label>
278
+ <Select value="YYYY-MM-DD" onValueChange={() => {}}>
279
+ <SelectTrigger><SelectValue /></SelectTrigger>
280
+ <SelectContent>
281
+ <SelectItem value="YYYY-MM-DD">2024-12-31</SelectItem>
282
+ <SelectItem value="DD/MM/YYYY">31/12/2024</SelectItem>
283
+ <SelectItem value="MM/DD/YYYY">12/31/2024</SelectItem>
284
+ </SelectContent>
285
+ </Select>
286
+ </div>
287
+ <div className="space-y-2">
288
+ <Label className="text-xs text-muted-foreground">数字格式</Label>
289
+ <Select value="1,234.56" onValueChange={() => {}}>
290
+ <SelectTrigger><SelectValue /></SelectTrigger>
291
+ <SelectContent>
292
+ <SelectItem value="1,234.56">1,234.56</SelectItem>
293
+ <SelectItem value="1.234,56">1.234,56</SelectItem>
294
+ <SelectItem value="1 234.56">1 234.56</SelectItem>
295
+ </SelectContent>
296
+ </Select>
297
+ </div>
298
+ </div>
299
+ </SettingSection>
300
+
301
+ <SettingSection
302
+ icon={<Shield className="size-5" />}
303
+ title="安全设置"
304
+ description="管理账户安全选项"
305
+ iconBg="bg-destructive"
306
+ >
307
+ <div className="space-y-4">
308
+ <div className="flex items-center justify-between py-2">
309
+ <div>
310
+ <span className="text-sm font-medium">修改密码</span>
311
+ <p className="text-xs text-muted-foreground">上次修改:30 天前</p>
312
+ </div>
313
+ <Button variant="outline" size="sm">修改密码</Button>
314
+ </div>
315
+ <div className="flex items-center justify-between border-t border-border py-2">
316
+ <div>
317
+ <span className="text-sm font-medium">双因素认证</span>
318
+ <p className="text-xs text-muted-foreground">增强账户安全性</p>
319
+ </div>
320
+ <Button size="sm" variant="secondary" className="text-emerald-600">已启用</Button>
321
+ </div>
322
+ <div className="flex items-center justify-between border-t border-border py-2">
323
+ <div>
324
+ <span className="text-sm font-medium">登录记录</span>
325
+ <p className="text-xs text-muted-foreground">查看最近的登录活动</p>
326
+ </div>
327
+ <Button variant="outline" size="sm">查看记录</Button>
328
+ </div>
329
+ </div>
330
+ </SettingSection>
331
+ </div>
332
+ </div>
333
+ </div>
334
+ );
335
+ }
@@ -0,0 +1,50 @@
1
+ /* eslint-disable react-refresh/only-export-components */
2
+ "use client"
3
+
4
+ import { createContext, useContext, type ReactNode } from "react"
5
+
6
+ export type AppTitleConfig = {
7
+ icon: ReactNode
8
+ text: string
9
+ }
10
+
11
+ const defaultTitle: AppTitleConfig = {
12
+ icon: (
13
+ <svg
14
+ xmlns="http://www.w3.org/2000/svg"
15
+ width="24"
16
+ height="24"
17
+ viewBox="0 0 24 24"
18
+ fill="none"
19
+ stroke="currentColor"
20
+ strokeWidth="2"
21
+ strokeLinecap="round"
22
+ strokeLinejoin="round"
23
+ >
24
+ <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
25
+ </svg>
26
+ ),
27
+ text: "Admin",
28
+ }
29
+
30
+ const AppConfigContext = createContext<{ title: AppTitleConfig }>({
31
+ title: defaultTitle,
32
+ })
33
+
34
+ export function AppConfigProvider({
35
+ children,
36
+ title = defaultTitle,
37
+ }: {
38
+ children: ReactNode
39
+ title?: AppTitleConfig
40
+ }) {
41
+ return (
42
+ <AppConfigContext.Provider value={{ title }}>
43
+ {children}
44
+ </AppConfigContext.Provider>
45
+ )
46
+ }
47
+
48
+ export function useAppConfig() {
49
+ return useContext(AppConfigContext)
50
+ }
@@ -0,0 +1,2 @@
1
+ // Backward-compatible re-export: admin & mobile share the same backend auth provider from @scaffold/core.
2
+ export { createBackendAuthProvider } from "@scaffold/core"
@@ -0,0 +1,9 @@
1
+ import { LOGIN_URL, USE_GUARD } from "@/app.config"
2
+ import { createAuthClientMiddleware, createAuthorizationClientMiddleware } from "@scaffold/core"
3
+ import { redirect } from "react-router"
4
+
5
+ export const authorizationClientMiddleware = USE_GUARD ? createAuthorizationClientMiddleware() : (_args: unknown, next: () => Promise<unknown>) => { next() }
6
+
7
+ export const middleware = [createAuthClientMiddleware(() => {
8
+ redirect(LOGIN_URL)
9
+ }), authorizationClientMiddleware]
@@ -0,0 +1,85 @@
1
+ import { USE_GUARD } from "@/app.config"
2
+ import { createAuthClientMiddleware, createAuthorizationClientMiddleware } from "@scaffold/core"
3
+ import { ReactNode } from "react"
4
+ import { RouteObject } from "react-router"
5
+
6
+ type ModuleExport = {
7
+ routes?: RouteConfig[]
8
+ }
9
+
10
+ /** 中间件函数类型(与 react-router 约定一致) */
11
+ type MiddlewareFn = (
12
+ args: { request: Request; context: unknown },
13
+ next: () => Promise<unknown>
14
+ ) => Promise<unknown>
15
+
16
+ /**
17
+ * 路由配置,支持树状结构:子路由定义在 children 中;与菜单对齐可配 icon / label / group。
18
+ * - path 为相对父级路径;index 为 true 时 path 可省略
19
+ * - 有 children 时,父级可不写 element,渲染时用 <Outlet /> 占位
20
+ * - anonymous / useGuard 用于在 getModulesContext 中自动注入 middleware,无需在模块里配置
21
+ * - group 从路由读取,用于菜单分区;groupOrder 指定该分区在菜单中的顺序(越小越靠前)
22
+ */
23
+ export type RouteConfig = Omit<RouteObject, "children"> & {
24
+ label?: string
25
+ icon?: ReactNode
26
+ /** 是否允许匿名(不注入认证中间件) */
27
+ anonymous?: boolean
28
+ /** 是否注入授权中间件 */
29
+ useGuard?: boolean
30
+ /** 菜单分区(如 business / analytics / system),与 menu-layout 的 MenuItem.group 对应 */
31
+ group?: string
32
+ /** 同 groupName 的多条路由会合并为一个父菜单(如 MM-采购) */
33
+ groupName?: string
34
+ /** 分区在菜单中的顺序,数值越小越靠前;同分区取该分区内最小 groupOrder */
35
+ groupOrder?: number
36
+ /** 同级菜单顺序(同一 groupName 下多项时),数值越小越靠前 */
37
+ order?: number
38
+ children?: RouteConfig[]
39
+ }
40
+
41
+ const modules = import.meta.glob<ModuleExport>("./modules/*.ts", { eager: true })
42
+
43
+ /** 按 RouteConfig 的 anonymous / useGuard 递归注入 middleware */
44
+ function applyMiddlewareToRoutes(routes: RouteConfig[], middlewares: MiddlewareFn[]): RouteConfig[] {
45
+ return routes.map((route) => {
46
+ const { children, anonymous, useGuard, ...rest } = route
47
+ const middleware: MiddlewareFn[] = []
48
+
49
+ const requiresAuth = anonymous !== true
50
+
51
+ if (requiresAuth) {
52
+ middleware.push(middlewares[0] as MiddlewareFn)
53
+ if (useGuard !== false) {
54
+ middleware.push(middlewares[1] as MiddlewareFn)
55
+ }
56
+ }
57
+ const out: RouteConfig = { ...rest, anonymous, useGuard, middleware, children: undefined }
58
+ if (children?.length) {
59
+ out.children = applyMiddlewareToRoutes(children, middlewares)
60
+ }
61
+ return out
62
+ })
63
+ }
64
+
65
+ let _routes: RouteConfig[] = []
66
+
67
+ export function getModulesContext(): {
68
+ routes: RouteConfig[]
69
+ middlewares: MiddlewareFn[]
70
+ } {
71
+ const authClientMiddleware = createAuthClientMiddleware()
72
+ const authorizationClientMiddleware = USE_GUARD ? createAuthorizationClientMiddleware() : (_args: unknown, next: () => Promise<unknown>) => next()
73
+ if (_routes.length === 0) {
74
+ const routes: RouteConfig[] = []
75
+ for (const key of Object.keys(modules)) {
76
+ const mod = modules[key] as ModuleExport
77
+ if (mod?.routes?.length) routes.push(...mod.routes)
78
+ }
79
+ _routes = applyMiddlewareToRoutes(routes, [authClientMiddleware, authorizationClientMiddleware])
80
+ }
81
+ return {
82
+ routes: _routes,
83
+ middlewares: [authClientMiddleware, authorizationClientMiddleware]
84
+ }
85
+ }
@@ -0,0 +1,176 @@
1
+ import { useMemo } from "react"
2
+ import type { RouteConfig } from "./index"
3
+ import { getModulesContext } from "./index"
4
+
5
+ export interface MenuItem {
6
+ id: string
7
+ label: string
8
+ icon?: React.ReactNode
9
+ path?: string
10
+ children?: MenuItem[]
11
+ badge?: string | number
12
+ useGuard?: boolean
13
+ /** 菜单分区,从 route.group 读取,用于 menu-layout 分区展示与筛选 */
14
+ group?: string
15
+ }
16
+
17
+ const DEFAULT_GROUP_ORDER = 999
18
+
19
+ /**
20
+ * 从路由读取 group:优先 group,兼容旧字段 groupKey(如 master-data 映射为 business)
21
+ */
22
+ function getMenuGroup(r: RouteConfig): string {
23
+ const g = r.group
24
+ return g ?? "other"
25
+ }
26
+
27
+ /** 遍历路由树填充 path → RouteConfig,path 为完整路径(如 "/goods-receipt/create")。 */
28
+ function fillPathToRouteConfig(
29
+ routeList: RouteConfig[],
30
+ pathToRouteConfig: Map<string, RouteConfig>,
31
+ prefix = ""
32
+ ): void {
33
+ for (const r of routeList) {
34
+ const segment = r.path ?? ""
35
+ const fullPath = segment ? (prefix ? `${prefix}/${segment}` : `/${segment}`) : prefix || "/"
36
+ if (r.index) {
37
+ pathToRouteConfig.set(prefix || "/", r)
38
+ } else if (segment || fullPath === "/") {
39
+ pathToRouteConfig.set(fullPath, r)
40
+ }
41
+ if (r.children?.length) {
42
+ const nextPrefix = segment ? (prefix ? `${prefix}/${segment}` : `/${segment}`) : prefix
43
+ fillPathToRouteConfig(r.children, pathToRouteConfig, nextPrefix)
44
+ }
45
+ }
46
+ }
47
+
48
+ export type RoutesToMenuResult = {
49
+ menuItems: MenuItem[]
50
+ pathToRouteConfig: Map<string, RouteConfig>
51
+ }
52
+
53
+ /**
54
+ * 将路由配置转为菜单项,并生成 path→RouteConfig 映射(一次遍历出两个结果)。
55
+ * - group 从 route.group 读取;分区顺序由 route.groupOrder 决定
56
+ * - 同 groupName 的多个顶层路由合并为一个父菜单(如 MM-采购)
57
+ * @param routes 聚合后的 RouteConfig[]
58
+ * @param options.mainItem 首页项(path: "/", group: "main")
59
+ */
60
+ export function routesToMenu(
61
+ routeList: RouteConfig[],
62
+ options?: { mainItem?: MenuItem }
63
+ ): RoutesToMenuResult {
64
+ const pathToRouteConfig = new Map<string, RouteConfig>()
65
+ fillPathToRouteConfig(routeList, pathToRouteConfig)
66
+
67
+ const topLevel = routeList.filter((r) => r.path !== undefined && !r.index)
68
+ const byGroupKey = new Map<string, RouteConfig[]>()
69
+ for (const r of topLevel) {
70
+ const menuGroup = getMenuGroup(r)
71
+ const gn = r.groupName ?? r.path ?? ""
72
+ const key = `${menuGroup}|${gn}`
73
+ if (!byGroupKey.has(key)) byGroupKey.set(key, [])
74
+ byGroupKey.get(key)!.push(r)
75
+ }
76
+
77
+ const menuItems: MenuItem[] = []
78
+ if (options?.mainItem) menuItems.push(options.mainItem)
79
+
80
+ /** 每个分区内:(itemOrder, menuItem)[],分区内按 itemOrder 排序 */
81
+ const groupToItems = new Map<string, { order: number; item: MenuItem }[]>()
82
+ const groupOrderMin = new Map<string, number>()
83
+ for (const [key, configs] of byGroupKey) {
84
+ const [menuGroup, groupName] = key.split("|")
85
+ const itemOrder = Math.min(
86
+ ...configs.map((r) => r.groupOrder ?? DEFAULT_GROUP_ORDER)
87
+ )
88
+ if (!groupToItems.has(menuGroup)) {
89
+ groupToItems.set(menuGroup, [])
90
+ groupOrderMin.set(menuGroup, itemOrder)
91
+ }
92
+ groupOrderMin.set(
93
+ menuGroup,
94
+ Math.min(groupOrderMin.get(menuGroup)!, itemOrder)
95
+ )
96
+
97
+ if (configs.length > 1) {
98
+ const sorted = [...configs].sort(
99
+ (a, b) => (a.order ?? DEFAULT_GROUP_ORDER) - (b.order ?? DEFAULT_GROUP_ORDER)
100
+ )
101
+ const first = sorted[0]
102
+ const parent: MenuItem = {
103
+ id: slugify(groupName),
104
+ label: groupName,
105
+ icon: first.icon,
106
+ group: menuGroup,
107
+ children: sorted.map((r) => ({
108
+ id: r.path!.replace(/\//g, "-"),
109
+ label: r.label ?? r.path ?? "",
110
+ path: "/" + r.path,
111
+ })),
112
+ }
113
+ groupToItems.get(menuGroup)!.push({ order: itemOrder, item: parent })
114
+ } else {
115
+ const r = configs[0]
116
+ if (r.children?.length) {
117
+ const listChildren = r.children.filter(
118
+ (c) => c.path && !c.path.includes(":")
119
+ )
120
+ const parent: MenuItem = {
121
+ id: r.path ?? slugify(groupName),
122
+ label: r.groupName ?? r.label ?? r.path ?? "",
123
+ icon: r.icon,
124
+ group: menuGroup,
125
+ children: listChildren.map((c) => ({
126
+ id: (c.path ?? "").replace(/\//g, "-"),
127
+ label: c.label ?? c.path ?? "",
128
+ path: "/" + (r.path ? r.path + "/" : "") + c.path,
129
+ })),
130
+ }
131
+ groupToItems.get(menuGroup)!.push({ order: itemOrder, item: parent })
132
+ } else {
133
+ groupToItems.get(menuGroup)!.push({
134
+ order: itemOrder,
135
+ item: {
136
+ id: (r.path ?? "").replace(/\//g, "-"),
137
+ label: r.label ?? r.path ?? "",
138
+ icon: r.icon,
139
+ path: "/" + (r.path ?? ""),
140
+ group: menuGroup,
141
+ },
142
+ })
143
+ }
144
+ }
145
+ }
146
+
147
+ const sortedGroupKeys = [...groupToItems.keys()].sort(
148
+ (a, b) =>
149
+ (groupOrderMin.get(a) ?? DEFAULT_GROUP_ORDER) -
150
+ (groupOrderMin.get(b) ?? DEFAULT_GROUP_ORDER)
151
+ )
152
+ for (const g of sortedGroupKeys) {
153
+ const entries = groupToItems.get(g) ?? []
154
+ const items = entries
155
+ .sort((a, b) => a.order - b.order)
156
+ .map((e) => e.item)
157
+ menuItems.push(...items)
158
+ }
159
+
160
+ return { menuItems, pathToRouteConfig }
161
+ }
162
+
163
+ export type UseMenuItemsOptions = { mainItem?: MenuItem }
164
+
165
+ /**
166
+ * 根据当前路由配置生成菜单项与 path→RouteConfig 映射(声明式 hook)。
167
+ * 若 options 含动态值(如 i18n),请用 useMemo 包住 options 以保持引用稳定。
168
+ */
169
+ export function useMenuItems(options?: UseMenuItemsOptions): RoutesToMenuResult {
170
+ const { routes } = getModulesContext()
171
+ return useMemo(() => routesToMenu(routes, options), [routes, options])
172
+ }
173
+
174
+ function slugify(s: string): string {
175
+ return s.replace(/\s+/g, "-").replace(/[^\w\u4e00-\u9fa5-]/g, "") || "item"
176
+ }