@gadmin2n/schematics 0.0.63 → 0.0.65
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.
- package/dist/lib/application/files/gadmin2-game-angle-demo/.dockerignore +2 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/Dockerfile +40 -26
- package/dist/lib/application/files/gadmin2-game-angle-demo/Jenkinsfile +30 -4
- package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/example.prisma +33 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/system.prisma +163 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/config/ui/Event.ts +70 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/config/ui/Game.ts +6 -6
- package/dist/lib/application/files/gadmin2-game-angle-demo/config/ui/ITActivityDay.ts +70 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/config/ui/Log.ts +2 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/config/ui/Role.ts +2 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/.env +20 -9
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/.env.local +1 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/.eslintrc.js +1 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/.prettierignore +1 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/README.md +2 -18
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/gadmin-cli.json +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/migrate-between-pg-schemas.js +1232 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/package.json +65 -38
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/prisma/.generator.prisma +4 -3
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/prisma.config.ts +16 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/games.ts +1 -71
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/index.ts +17 -21
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/permissions.ts +278 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/seedDataMngtPages.ts +258 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/users.ts +7 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/alias.config.ts +7 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/app.controller.ts +151 -11
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/app.module.ts +29 -13
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/app.service.ts +151 -12
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/lib/auth.guard.ts +87 -41
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/lib/http-cache.interceptor.ts +21 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/lib/logger.ts +19 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/lib/safe-log.util.ts +176 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/lib/{yufuid.ts → taihu.ts} +49 -34
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/lib/tracing.ts +174 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/lib/trim.pipe.ts +51 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/lib/utils.ts +91 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/lib/woaAuth.ts +25 -12
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/main.ts +22 -12
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/audit/audit.controller.spec.ts +20 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/audit/audit.controller.ts +190 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/audit/audit.module.ts +10 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/audit/audit.service.spec.ts +338 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/audit/audit.service.ts +83 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/game/game.controller.spec.ts +20 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/game/game.controller.ts +188 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/game/game.module.ts +10 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/game/game.service.spec.ts +18 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/game/game.service.ts +83 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/page/page.controller.spec.ts +20 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/page/page.controller.ts +250 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/page/page.module.ts +10 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/page/page.service.spec.ts +18 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/page/page.service.ts +1051 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/pageResource/pageResource.controller.spec.ts +20 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/pageResource/pageResource.controller.ts +196 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/pageResource/pageResource.module.ts +13 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/pageResource/pageResource.service.spec.ts +18 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/pageResource/pageResource.service.ts +219 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/resource/resource.controller.spec.ts +20 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/resource/resource.controller.ts +196 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/resource/resource.module.ts +10 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/resource/resource.service.spec.ts +18 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/resource/resource.service.ts +199 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/role.controller.spec.ts +20 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/role.controller.ts +210 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/role.module.ts +12 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/role.service.spec.ts +18 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/role.service.ts +849 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/roles-refresher.service.ts +133 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/rolePages/rolePages.controller.spec.ts +20 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/rolePages/rolePages.controller.ts +196 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/rolePages/rolePages.module.ts +10 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/rolePages/rolePages.service.spec.ts +18 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/rolePages/rolePages.service.ts +201 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/roleResource/roleResource.controller.spec.ts +20 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/roleResource/roleResource.controller.ts +196 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/roleResource/roleResource.module.ts +10 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/roleResource/roleResource.service.spec.ts +18 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/roleResource/roleResource.service.ts +216 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.controller.spec.ts +20 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.controller.ts +198 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.module.ts +10 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.service.spec.ts +18 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.service.ts +104 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/start-prod.sh +130 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/tsconfig.json +18 -3
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/index.html +19 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/package.json +34 -42
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/postcss.config.cjs +6 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/App.tsx +111 -185
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/auditLogProvider.ts +5 -5
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/contexts/color-mode/index.tsx +49 -51
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/custom-avatar.tsx +38 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/index.ts +4 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/layout/{header/index.tsx → header.tsx} +22 -31
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/layout/index.ts +3 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/layout/layout.tsx +32 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/layout/logo.tsx +19 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/layout/sider.tsx +331 -166
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/layout/title.tsx +61 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/pagination-total.tsx +21 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/tags/index.ts +1 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/tags/role-tag.tsx +44 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/text.tsx +74 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/config/routeRegistry.tsx +258 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/constants/layout.ts +16 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/enums/audit-log.enum.ts +13 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/enums/index.ts +1 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/helpers/form.tsx +2 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/helpers/login.ts +22 -4
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useDynamicResources.tsx +211 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useFetchData.ts +33 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useRoles.ts +30 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useUserPageAccess.ts +339 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/i18n.ts +8 -4
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/index.tsx +3 -11
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/{public → src}/locales/en/common.json +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/{public → src}/locales/zh_CN/common.json +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/audit/components/action-cell.css +3 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/audit/components/action-cell.tsx +134 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/audit/create.tsx +113 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/audit/edit.tsx +122 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/audit/index.ts +8 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/audit/index.tsx +6 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/audit/list.tsx +213 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/audit/show.tsx +61 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/Components/AssignRolesModal.tsx +168 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/Components/CreatePageModal.tsx +42 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/Components/EditPageModal.tsx +42 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/Components/PageDetailDrawer.tsx +101 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/Components/PageFormModal.tsx +731 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/create.tsx +113 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/edit.tsx +122 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/hooks/usePageManagement.ts +36 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/index.ts +8 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/index.tsx +6 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/list.tsx +1113 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/queries.ts +17 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/show.tsx +61 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/types.ts +44 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/pageResource/create.tsx +113 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/pageResource/edit.tsx +122 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/pageResource/index.tsx +6 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/pageResource/list.tsx +243 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/pageResource/show.tsx +61 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/permission-readme/index.tsx +1088 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/Components/CreateModal.tsx +25 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/Components/EditModal.tsx +28 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/Components/ResourceDetailDrawer.tsx +160 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/Components/modal.tsx +202 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/create.tsx +113 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/edit.tsx +122 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/index.ts +9 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/index.tsx +6 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/list.tsx +184 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/queries.ts +10 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/show.tsx +61 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/types.ts +9 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/Components/CreateModal.tsx +30 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/Components/EditModal.tsx +47 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/Components/RoleDetailDrawer.tsx +56 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/Components/modal.tsx +302 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/create.tsx +113 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/edit.tsx +122 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/hooks/useRolePage.ts +35 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/index.ts +8 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/index.tsx +6 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/list.tsx +382 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/queries.ts +8 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/show.tsx +61 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/types.ts +8 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/rolePages/create.tsx +113 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/rolePages/edit.tsx +122 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/rolePages/index.tsx +6 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/rolePages/list.tsx +243 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/rolePages/show.tsx +61 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/roleResource/create.tsx +113 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/roleResource/edit.tsx +122 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/roleResource/index.tsx +6 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/roleResource/list.tsx +243 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/roleResource/show.tsx +61 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/components/create-modal.tsx +17 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/components/edit-modal.tsx +19 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/components/form-modal.tsx +188 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/components/index.ts +5 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/components/role-tag.tsx +48 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/components/show-drawer.tsx +140 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/create.tsx +113 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/edit.tsx +122 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/index.ts +8 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/index.tsx +6 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/list.tsx +342 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/queries.ts +14 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/show.tsx +61 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/styles/antd.css +132 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/styles/fc.css +58 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/styles/index.css +128 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/styles/show-drawer.module.css +18 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/styles/show-page.module.css +21 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/types/audit-log.ts +1 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/types/index.ts +3 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/types/role.ts +7 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/types/user.ts +1 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/utilities/get-name-initials.ts +8 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/utilities/get-random-color.ts +27 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/utilities/index.ts +2 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/utilities/utils.tsx +5 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/vite-env.d.ts +1 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/tsconfig.json +3 -3
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/vite.config.ts +31 -0
- package/package.json +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/sample.prisma +0 -65
- package/dist/lib/application/files/gadmin2-game-angle-demo/config/ui/Source.ts +0 -76
- package/dist/lib/application/files/gadmin2-game-angle-demo/config/ui/Tasklog.ts +0 -76
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/roles.ts +0 -4
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/craco.config.js +0 -27
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/public/index.html +0 -53
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/layout/styles.ts +0 -10
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/react-app-env.d.ts +0 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/reportWebVitals.ts +0 -15
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/styles/antd.less +0 -79
- /package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/VanillaJSONEditor/{index.js → index.jsx} +0 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import { ConfigProvider, Typography } from "antd";
|
|
4
|
+
|
|
5
|
+
export type TextProps = {
|
|
6
|
+
size?:
|
|
7
|
+
| "xs"
|
|
8
|
+
| "sm"
|
|
9
|
+
| "md"
|
|
10
|
+
| "lg"
|
|
11
|
+
| "xl"
|
|
12
|
+
| "xxl"
|
|
13
|
+
| "xxxl"
|
|
14
|
+
| "huge"
|
|
15
|
+
| "xhuge"
|
|
16
|
+
| "xxhuge";
|
|
17
|
+
} & React.ComponentProps<typeof Typography.Text>;
|
|
18
|
+
|
|
19
|
+
const sizes = {
|
|
20
|
+
xs: {
|
|
21
|
+
fontSize: 12,
|
|
22
|
+
lineHeight: 20 / 12,
|
|
23
|
+
},
|
|
24
|
+
sm: {
|
|
25
|
+
fontSize: 14,
|
|
26
|
+
lineHeight: 22 / 14,
|
|
27
|
+
},
|
|
28
|
+
md: {
|
|
29
|
+
fontSize: 16,
|
|
30
|
+
lineHeight: 24 / 16,
|
|
31
|
+
},
|
|
32
|
+
lg: {
|
|
33
|
+
fontSize: 20,
|
|
34
|
+
lineHeight: 28 / 20,
|
|
35
|
+
},
|
|
36
|
+
xl: {
|
|
37
|
+
fontSize: 24,
|
|
38
|
+
lineHeight: 32 / 24,
|
|
39
|
+
},
|
|
40
|
+
xxl: {
|
|
41
|
+
fontSize: 30,
|
|
42
|
+
lineHeight: 38 / 30,
|
|
43
|
+
},
|
|
44
|
+
xxxl: {
|
|
45
|
+
fontSize: 38,
|
|
46
|
+
lineHeight: 46 / 38,
|
|
47
|
+
},
|
|
48
|
+
huge: {
|
|
49
|
+
fontSize: 46,
|
|
50
|
+
lineHeight: 54 / 46,
|
|
51
|
+
},
|
|
52
|
+
xhuge: {
|
|
53
|
+
fontSize: 56,
|
|
54
|
+
lineHeight: 64 / 56,
|
|
55
|
+
},
|
|
56
|
+
xxhuge: {
|
|
57
|
+
fontSize: 68,
|
|
58
|
+
lineHeight: 76 / 68,
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const Text: React.FC<TextProps> = ({ size = "sm", children, ...rest }) => {
|
|
63
|
+
return (
|
|
64
|
+
<ConfigProvider
|
|
65
|
+
theme={{
|
|
66
|
+
token: {
|
|
67
|
+
...sizes[size],
|
|
68
|
+
},
|
|
69
|
+
}}
|
|
70
|
+
>
|
|
71
|
+
<Typography.Text {...rest}>{children}</Typography.Text>
|
|
72
|
+
</ConfigProvider>
|
|
73
|
+
);
|
|
74
|
+
};
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import React, { lazy, Suspense } from "react";
|
|
2
|
+
import { Outlet, Route } from "react-router-dom";
|
|
3
|
+
import { Spin } from "antd";
|
|
4
|
+
import generatedResources from "generated/resources";
|
|
5
|
+
|
|
6
|
+
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
7
|
+
|
|
8
|
+
type LazyComp = React.LazyExoticComponent<React.ComponentType<any>>;
|
|
9
|
+
// Allow both lazy and eagerly-imported components (generated/resources uses the latter)
|
|
10
|
+
type AnyComp = React.ComponentType<any>;
|
|
11
|
+
|
|
12
|
+
interface RouteEntry {
|
|
13
|
+
path: string;
|
|
14
|
+
component?: LazyComp | AnyComp;
|
|
15
|
+
wrapper?: LazyComp | AnyComp;
|
|
16
|
+
index?: boolean;
|
|
17
|
+
children?: Record<string, RouteEntry>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ─── Data-Mngt dynamic route helpers ─────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Resource names already covered by the static registry entries below.
|
|
24
|
+
* These must NOT be auto-registered again under dataMngt.
|
|
25
|
+
*/
|
|
26
|
+
const SYSTEM_RESOURCE_NAMES = new Set([
|
|
27
|
+
"user", "role", "page", "resource", "audit",
|
|
28
|
+
"game", "roleResource", "pageResource", "rolePages",
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
/** camelCase → PascalCase (reverses toCamelCase in seedDataMngtPages) */
|
|
32
|
+
function toPascalCase(str: string): string {
|
|
33
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* PascalCase → kebab-case (same algorithm as seedDataMngtPages.ts so the
|
|
38
|
+
* generated route path always matches the page.path stored in the DB).
|
|
39
|
+
* "Event" → "event"
|
|
40
|
+
* "ITActivityDay" → "it-activity-day"
|
|
41
|
+
*/
|
|
42
|
+
function toKebabCase(str: string): string {
|
|
43
|
+
return str
|
|
44
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
|
|
45
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2")
|
|
46
|
+
.toLowerCase();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Build RouteEntry children for the dataMngt segment by scanning
|
|
51
|
+
* generated/resources.tsx (produced by gadmin2 on every `generate:dev`).
|
|
52
|
+
*
|
|
53
|
+
* Each business-model resource becomes:
|
|
54
|
+
* <Route path="<slug>">
|
|
55
|
+
* <Route index element={<List />} />
|
|
56
|
+
* <Route path="show/:id" element={<Show />} />
|
|
57
|
+
* <Route path="edit/:id" element={<Edit />} />
|
|
58
|
+
* <Route path="create" element={<Create />} />
|
|
59
|
+
* </Route>
|
|
60
|
+
*/
|
|
61
|
+
function buildDataMngtChildren(): Record<string, RouteEntry> {
|
|
62
|
+
const children: Record<string, RouteEntry> = {};
|
|
63
|
+
|
|
64
|
+
for (const res of generatedResources) {
|
|
65
|
+
if (SYSTEM_RESOURCE_NAMES.has(res.name)) continue;
|
|
66
|
+
|
|
67
|
+
// generated/resources stores components in meta.components
|
|
68
|
+
const { list: ListComp, show: ShowComp, edit: EditComp, create: CreateComp } =
|
|
69
|
+
(res.meta as any).components ?? {};
|
|
70
|
+
|
|
71
|
+
if (!ListComp) continue;
|
|
72
|
+
|
|
73
|
+
// Derive the URL slug from the PascalCase model name so it matches
|
|
74
|
+
// what seedDataMngtPages.ts writes into page.path.
|
|
75
|
+
const slug = toKebabCase(toPascalCase(res.name));
|
|
76
|
+
|
|
77
|
+
children[res.name] = {
|
|
78
|
+
path: slug,
|
|
79
|
+
// No component on the parent — React Router renders <Outlet /> so that
|
|
80
|
+
// the index / show / edit / create children can each occupy the full view.
|
|
81
|
+
children: {
|
|
82
|
+
list: { path: "", index: true, component: ListComp as AnyComp },
|
|
83
|
+
show: { path: "show/:id", component: ShowComp as AnyComp },
|
|
84
|
+
edit: { path: "edit/:id", component: EditComp as AnyComp },
|
|
85
|
+
create: { path: "create", component: CreateComp as AnyComp },
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return children;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ─── Suspense wrapper ────────────────────────────────────────────────────────
|
|
94
|
+
|
|
95
|
+
const S = ({ children }: { children: React.ReactNode }) => (
|
|
96
|
+
<Suspense fallback={<Spin size="large" />}>{children}</Suspense>
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
// ─── Route Registry ──────────────────────────────────────────────────────────
|
|
100
|
+
|
|
101
|
+
export const routeRegistry: Record<string, RouteEntry> = {
|
|
102
|
+
// ── Administration ─────────────────────────────────────────────────────────
|
|
103
|
+
admin: {
|
|
104
|
+
path: "/admin",
|
|
105
|
+
children: {
|
|
106
|
+
permission: {
|
|
107
|
+
path: "permission",
|
|
108
|
+
children: {
|
|
109
|
+
// 菜单指引 — sortOrder 1020, code: admin.permission.readme
|
|
110
|
+
permission_readme: {
|
|
111
|
+
path: "readme",
|
|
112
|
+
component: lazy(() =>
|
|
113
|
+
import("routes/permission-readme").then((m) => ({
|
|
114
|
+
default: m.PermissionReadmePage,
|
|
115
|
+
})),
|
|
116
|
+
),
|
|
117
|
+
},
|
|
118
|
+
// 用户管理 — sortOrder 1030, code: admin.permission.user
|
|
119
|
+
user: {
|
|
120
|
+
path: "user",
|
|
121
|
+
component: lazy(() =>
|
|
122
|
+
import("routes/user").then((m) => ({ default: m.UserListPage })),
|
|
123
|
+
),
|
|
124
|
+
},
|
|
125
|
+
// 角色管理 — sortOrder 1040, code: admin.permission.role
|
|
126
|
+
role: {
|
|
127
|
+
path: "role-list",
|
|
128
|
+
component: lazy(() =>
|
|
129
|
+
import("routes/role").then((m) => ({
|
|
130
|
+
default: m.RoleManagementListPage,
|
|
131
|
+
})),
|
|
132
|
+
),
|
|
133
|
+
},
|
|
134
|
+
// 页面管理 — sortOrder 1050, code: admin.permission.page
|
|
135
|
+
page: {
|
|
136
|
+
path: "page-list",
|
|
137
|
+
component: lazy(() =>
|
|
138
|
+
import("routes/page/list").then((m) => ({
|
|
139
|
+
default: m.PageManagementListPage,
|
|
140
|
+
})),
|
|
141
|
+
),
|
|
142
|
+
},
|
|
143
|
+
// 资源管理 — sortOrder 1060, code: admin.permission.resource
|
|
144
|
+
resource: {
|
|
145
|
+
path: "resource-list",
|
|
146
|
+
component: lazy(() =>
|
|
147
|
+
import("routes/resource").then((m) => ({
|
|
148
|
+
default: m.ResourceManagementListPage,
|
|
149
|
+
})),
|
|
150
|
+
),
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
dataMngt: {
|
|
155
|
+
path: "data-mngt",
|
|
156
|
+
children: buildDataMngtChildren(),
|
|
157
|
+
},
|
|
158
|
+
game: {
|
|
159
|
+
path: "game-list",
|
|
160
|
+
children: {
|
|
161
|
+
list: { path: "", index: true, component: lazy(() => import("routes/game").then((m) => ({ default: m.GameList }))) },
|
|
162
|
+
show: { path: "show/:id", component: lazy(() => import("routes/game").then((m) => ({ default: m.GameShow }))) },
|
|
163
|
+
edit: { path: "edit/:id", component: lazy(() => import("routes/game").then((m) => ({ default: m.GameEdit }))) },
|
|
164
|
+
create: { path: "create", component: lazy(() => import("routes/game").then((m) => ({ default: m.GameCreate }))) },
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
// 操作日志 — sortOrder 1070, code: admin.audit
|
|
168
|
+
audits: {
|
|
169
|
+
path: "audit-log-list",
|
|
170
|
+
component: lazy(() =>
|
|
171
|
+
import("routes/audit").then((m) => ({ default: m.AuditLogPage })),
|
|
172
|
+
),
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// ─── Path Index (getRoutePath) ────────────────────────────────────────────────
|
|
179
|
+
|
|
180
|
+
function buildPathIndex(
|
|
181
|
+
entries: Record<string, RouteEntry>,
|
|
182
|
+
parentPath = "",
|
|
183
|
+
): Record<string, string> {
|
|
184
|
+
const result: Record<string, string> = {};
|
|
185
|
+
for (const [key, entry] of Object.entries(entries)) {
|
|
186
|
+
const fullPath = entry.path.startsWith("/")
|
|
187
|
+
? entry.path
|
|
188
|
+
: entry.path === ""
|
|
189
|
+
? parentPath
|
|
190
|
+
: entry.path.startsWith("?")
|
|
191
|
+
? parentPath + entry.path
|
|
192
|
+
: parentPath + "/" + entry.path;
|
|
193
|
+
result[key] = fullPath;
|
|
194
|
+
if (entry.children) {
|
|
195
|
+
Object.assign(result, buildPathIndex(entry.children, fullPath.split("?")[0]));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return result;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const pathIndex = buildPathIndex(routeRegistry);
|
|
202
|
+
|
|
203
|
+
export function getRoutePath(pageCode: string): string | null {
|
|
204
|
+
return pathIndex[pageCode] ?? null;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// ─── renderRoutes() ──────────────────────────────────────────────────────────
|
|
208
|
+
|
|
209
|
+
function renderEntry(key: string, entry: RouteEntry): React.ReactElement | null {
|
|
210
|
+
let element: React.ReactNode | undefined;
|
|
211
|
+
if (entry.component) {
|
|
212
|
+
const Comp = entry.component;
|
|
213
|
+
element = (
|
|
214
|
+
<S>
|
|
215
|
+
<Comp />
|
|
216
|
+
</S>
|
|
217
|
+
);
|
|
218
|
+
} else if (entry.wrapper) {
|
|
219
|
+
const W = entry.wrapper;
|
|
220
|
+
element = (
|
|
221
|
+
<S>
|
|
222
|
+
<W>
|
|
223
|
+
<Outlet />
|
|
224
|
+
</W>
|
|
225
|
+
</S>
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (entry.index) {
|
|
230
|
+
return <Route key={key} index element={element ?? null} />;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const routePath = entry.path.split("?")[0];
|
|
234
|
+
|
|
235
|
+
const childRoutes = Object.entries(entry.children ?? {})
|
|
236
|
+
.map(([k, e]) => renderEntry(k, e))
|
|
237
|
+
.filter(Boolean);
|
|
238
|
+
|
|
239
|
+
// Sidebar-only: no element, no renderable children
|
|
240
|
+
if (!element && childRoutes.length === 0) return null;
|
|
241
|
+
|
|
242
|
+
return childRoutes.length > 0 ? (
|
|
243
|
+
<Route key={key} path={routePath} element={element ?? <Outlet />}>
|
|
244
|
+
{childRoutes}
|
|
245
|
+
</Route>
|
|
246
|
+
) : (
|
|
247
|
+
<Route key={key} path={routePath} element={element!} />
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Memoized at module level — registry is static, routes never change
|
|
252
|
+
const cachedRoutes: React.ReactElement[] = Object.entries(routeRegistry)
|
|
253
|
+
.map(([key, entry]) => renderEntry(key, entry))
|
|
254
|
+
.filter(Boolean) as React.ReactElement[];
|
|
255
|
+
|
|
256
|
+
export function renderRoutes(): React.ReactElement[] {
|
|
257
|
+
return cachedRoutes;
|
|
258
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** List / Create 页面顶层组件的内容区样式 */
|
|
2
|
+
export const LIST_CONTENT_PROPS = {
|
|
3
|
+
style: { marginTop: "1rem" },
|
|
4
|
+
} as const;
|
|
5
|
+
|
|
6
|
+
/** Show 页面顶层组件的内容区样式 */
|
|
7
|
+
export const SHOW_CONTENT_PROPS = {
|
|
8
|
+
style: {
|
|
9
|
+
backgroundColor: "#f5f5f5",
|
|
10
|
+
padding: 0,
|
|
11
|
+
marginTop: "1rem",
|
|
12
|
+
},
|
|
13
|
+
bodyStyle: {
|
|
14
|
+
padding: 0,
|
|
15
|
+
},
|
|
16
|
+
} as const;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export enum AuditLogActionEnum {
|
|
2
|
+
create = "create",
|
|
3
|
+
update = "update",
|
|
4
|
+
delete = "delete",
|
|
5
|
+
download = "download",
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const auditLogActionOptions = [
|
|
9
|
+
{ label: "Create", value: AuditLogActionEnum.create },
|
|
10
|
+
{ label: "Update", value: AuditLogActionEnum.update },
|
|
11
|
+
{ label: "Delete", value: AuditLogActionEnum.delete },
|
|
12
|
+
{ label: "Download", value: AuditLogActionEnum.download },
|
|
13
|
+
];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./audit-log.enum";
|
|
@@ -127,6 +127,7 @@ function getElement(
|
|
|
127
127
|
const hidden = !!fieldProps.hidden;
|
|
128
128
|
const readonly = !!fieldProps.readonly;
|
|
129
129
|
const showOptions = fieldProps.options;
|
|
130
|
+
const tooltip = field.uiType?.tooltip;
|
|
130
131
|
const itemProps = {
|
|
131
132
|
label: t(
|
|
132
133
|
`resources.${resourceName}.fields.${fieldName}`,
|
|
@@ -153,6 +154,7 @@ function getElement(
|
|
|
153
154
|
...(field.rules || []),
|
|
154
155
|
],
|
|
155
156
|
hidden,
|
|
157
|
+
...(tooltip && { tooltip }),
|
|
156
158
|
};
|
|
157
159
|
if (field.component) {
|
|
158
160
|
element = <Form.Item {...itemProps}>{field.component}</Form.Item>;
|
|
@@ -34,7 +34,7 @@ axiosInstance.interceptors.response.use(
|
|
|
34
34
|
console.log("login expired");
|
|
35
35
|
login();
|
|
36
36
|
// 返回pending状态的promise,以免后续代码出错
|
|
37
|
-
return new Promise(() => {});
|
|
37
|
+
return new Promise(() => { });
|
|
38
38
|
}
|
|
39
39
|
let message = error.response?.data?.message;
|
|
40
40
|
if (message) {
|
|
@@ -42,9 +42,8 @@ axiosInstance.interceptors.response.use(
|
|
|
42
42
|
message = message.join(" AND ");
|
|
43
43
|
} else if (typeof message === "string") {
|
|
44
44
|
if (message.includes("Unique constraint")) {
|
|
45
|
-
message = `Unique constraint ${
|
|
46
|
-
|
|
47
|
-
}`;
|
|
45
|
+
message = `Unique constraint ${message.split("Unique constraint")[1]
|
|
46
|
+
}`;
|
|
48
47
|
} else {
|
|
49
48
|
let strings = message.split(")");
|
|
50
49
|
message = strings[strings.length - 1];
|
|
@@ -122,3 +121,22 @@ export function requestHeaders() {
|
|
|
122
121
|
};
|
|
123
122
|
return headers;
|
|
124
123
|
}
|
|
124
|
+
|
|
125
|
+
type LowercaseMethod = 'get' | 'delete' | 'head' | 'options' | 'post' | 'put' | 'patch';
|
|
126
|
+
|
|
127
|
+
export async function customRequest<T>(
|
|
128
|
+
urlPath: string,
|
|
129
|
+
method: string,
|
|
130
|
+
params?: Record<string, any>
|
|
131
|
+
) {
|
|
132
|
+
const url = `${apiUrl}/${urlPath}`;
|
|
133
|
+
const headers = {
|
|
134
|
+
"Content-Type": "application/json",
|
|
135
|
+
...requestHeaders(),
|
|
136
|
+
};
|
|
137
|
+
const httpMethod = method.toLowerCase() as LowercaseMethod;
|
|
138
|
+
const axiosOptions = { headers };
|
|
139
|
+
const res = await axiosInstance[httpMethod](url, params, axiosOptions);
|
|
140
|
+
const { data } = res;
|
|
141
|
+
return data as T;
|
|
142
|
+
}
|
package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useDynamicResources.tsx
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { useMemo, useRef } from "react";
|
|
2
|
+
import type { IResourceItem, ResourceProps } from "@refinedev/core";
|
|
3
|
+
import {
|
|
4
|
+
DashboardOutlined,
|
|
5
|
+
SettingOutlined,
|
|
6
|
+
} from "@ant-design/icons";
|
|
7
|
+
import { getRoutePath } from "config/routeRegistry";
|
|
8
|
+
import { useUserPageAccess } from "./useUserPageAccess";
|
|
9
|
+
import generatedResources from "generated/resources";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Dynamic Resources Hook for erp-backend/web
|
|
13
|
+
*
|
|
14
|
+
* Features:
|
|
15
|
+
* 1. Get user accessible page resources from backend (via useUserPageAccess)
|
|
16
|
+
* 2. Convert backend data to Refine's IResourceItem[] format
|
|
17
|
+
* 3. Auto-generate show/edit/create paths for all pages
|
|
18
|
+
*
|
|
19
|
+
* Data Flow:
|
|
20
|
+
* useUserPageAccess → Accessible Pages → Resources → Sider Menu
|
|
21
|
+
*
|
|
22
|
+
* Performance:
|
|
23
|
+
* - Uses module-level cache - computed ONCE per page load
|
|
24
|
+
* - Returns same reference on every call after initial computation
|
|
25
|
+
* - Does NOT rebuild on route navigation or component re-renders
|
|
26
|
+
* - Permission changes require page refresh (handled by user)
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
// Module-level cache - computed once per page load
|
|
30
|
+
let cachedResources: IResourceItem[] | null = null;
|
|
31
|
+
let isComputing = false;
|
|
32
|
+
|
|
33
|
+
// 将 snake_case 转换为 camelCase
|
|
34
|
+
function snakeToCamel(str: string): string {
|
|
35
|
+
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Icon 映射:page.code 到 React Icon 组件
|
|
39
|
+
export const iconMapping: Record<string, React.ReactNode> = {
|
|
40
|
+
dashboard: <DashboardOutlined />,
|
|
41
|
+
administration: <SettingOutlined />,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Pages whose children are tabs (not separate menu items)
|
|
45
|
+
const PAGES_WITH_TABS: string[] = [];
|
|
46
|
+
|
|
47
|
+
export const useDynamicResources = (): IResourceItem[] => {
|
|
48
|
+
// Use shared page access data (single call, reused below)
|
|
49
|
+
const { accessiblePageIds, pagesData, pageMap, isLoading, roleNames } = useUserPageAccess();
|
|
50
|
+
|
|
51
|
+
// If we already have cached resources, return immediately
|
|
52
|
+
if (cachedResources !== null) {
|
|
53
|
+
return cachedResources;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Return empty array while loading (will retry on next render)
|
|
57
|
+
if (isLoading || !pagesData || isComputing) {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Mark as computing to prevent concurrent computation
|
|
62
|
+
isComputing = true;
|
|
63
|
+
|
|
64
|
+
if (import.meta.env.DEV) {
|
|
65
|
+
console.log('[useDynamicResources] 🔨 Computing resources (first time)');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Filter accessible pages and build hierarchical sorted list
|
|
69
|
+
const accessiblePages = pagesData.filter(page => accessiblePageIds.has(page.id));
|
|
70
|
+
|
|
71
|
+
// Group pages by parentId
|
|
72
|
+
const pagesByParent = new Map<number | null, typeof accessiblePages>();
|
|
73
|
+
accessiblePages.forEach(page => {
|
|
74
|
+
const parentId = page.parentId ?? null;
|
|
75
|
+
if (!pagesByParent.has(parentId)) {
|
|
76
|
+
pagesByParent.set(parentId, []);
|
|
77
|
+
}
|
|
78
|
+
pagesByParent.get(parentId)!.push(page);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Sort each group by sortOrder
|
|
82
|
+
pagesByParent.forEach(pages => {
|
|
83
|
+
pages.sort((a, b) => (a.sortOrder ?? Infinity) - (b.sortOrder ?? Infinity));
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Build sorted list using depth-first traversal
|
|
87
|
+
const sortedAccessiblePages: typeof accessiblePages = [];
|
|
88
|
+
const visited = new Set<number>();
|
|
89
|
+
|
|
90
|
+
const addPageWithChildren = (parentId: number | null) => {
|
|
91
|
+
const children = pagesByParent.get(parentId) || [];
|
|
92
|
+
children.forEach(page => {
|
|
93
|
+
if (visited.has(page.id)) return;
|
|
94
|
+
visited.add(page.id);
|
|
95
|
+
sortedAccessiblePages.push(page);
|
|
96
|
+
addPageWithChildren(page.id);
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// Start from root level (parentId = null)
|
|
101
|
+
addPageWithChildren(null);
|
|
102
|
+
|
|
103
|
+
// Add any orphaned pages
|
|
104
|
+
accessiblePages.forEach(page => {
|
|
105
|
+
if (!visited.has(page.id)) {
|
|
106
|
+
sortedAccessiblePages.push(page);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// 检测哪些父页面有"index 子页面"(子页面路径与父页面相同,即 path: "" 的 index 路由)
|
|
111
|
+
// 这类父页面应作为纯分组节点(不注册 list 路径),否则 Refine 会优先选中父节点
|
|
112
|
+
// 导致 "全部" 等 index 子菜单项无法高亮
|
|
113
|
+
const parentIdsWithIndexChild = new Set<number>();
|
|
114
|
+
accessiblePages.forEach(childPage => {
|
|
115
|
+
if (!childPage.parentId) return;
|
|
116
|
+
const childPath = getRoutePath(childPage.code);
|
|
117
|
+
if (!childPath) return;
|
|
118
|
+
const parentPage = pageMap.get(childPage.parentId);
|
|
119
|
+
if (!parentPage) return;
|
|
120
|
+
const parentPath = getRoutePath(parentPage.code);
|
|
121
|
+
if (childPath === parentPath) {
|
|
122
|
+
parentIdsWithIndexChild.add(childPage.parentId);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// Build resources
|
|
127
|
+
const resultResources: IResourceItem[] = [];
|
|
128
|
+
const addedResourceNames = new Set<string>();
|
|
129
|
+
|
|
130
|
+
sortedAccessiblePages.forEach(page => {
|
|
131
|
+
if (!page) return;
|
|
132
|
+
|
|
133
|
+
// Skip virtual pages
|
|
134
|
+
if (page.isVirtual) return;
|
|
135
|
+
|
|
136
|
+
// Skip children of pages that use tabs
|
|
137
|
+
if (page.parentId) {
|
|
138
|
+
const parentPage = pageMap.get(page.parentId);
|
|
139
|
+
if (parentPage && PAGES_WITH_TABS.includes(parentPage.code)) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const permissionRes = snakeToCamel(page.code);
|
|
145
|
+
|
|
146
|
+
// Avoid duplicates
|
|
147
|
+
if (addedResourceNames.has(permissionRes)) return;
|
|
148
|
+
|
|
149
|
+
let parentPermissionRes: string | undefined;
|
|
150
|
+
if (page.parentId) {
|
|
151
|
+
const parentPage = pageMap.get(page.parentId);
|
|
152
|
+
if (parentPage) {
|
|
153
|
+
parentPermissionRes = snakeToCamel(parentPage.code);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// 优先从 routeRegistry 获取路径
|
|
158
|
+
// fallback 到 page.path(用于 gadmin2 页面)
|
|
159
|
+
const registryPath = getRoutePath(page.code);
|
|
160
|
+
const dbPath = page.path
|
|
161
|
+
? page.path.startsWith("/") ? page.path : `/${page.path}`
|
|
162
|
+
: undefined;
|
|
163
|
+
const normalizedPath = registryPath ?? dbPath;
|
|
164
|
+
|
|
165
|
+
// 如果该页面是"有 index 子页面的父节点",则不注册 list/show/edit/create
|
|
166
|
+
// 使其成为纯分组节点(SubMenu),子页面(如"全部")的路径才负责 URL 匹配与菜单高亮
|
|
167
|
+
const isGroupParent = parentIdsWithIndexChild.has(page.id);
|
|
168
|
+
|
|
169
|
+
// Build resource item with auto-generated CRUD paths
|
|
170
|
+
// Store both zhLabel/enLabel in meta; Sider resolves at render time
|
|
171
|
+
const resource: IResourceItem = {
|
|
172
|
+
name: permissionRes,
|
|
173
|
+
...(!isGroupParent && normalizedPath && {
|
|
174
|
+
list: normalizedPath,
|
|
175
|
+
show: `${normalizedPath}/show/:id`,
|
|
176
|
+
edit: `${normalizedPath}/edit/:id`,
|
|
177
|
+
create: `${normalizedPath}/create`,
|
|
178
|
+
}),
|
|
179
|
+
meta: {
|
|
180
|
+
label: page.enName || page.code,
|
|
181
|
+
zhLabel: page.zhName || page.code,
|
|
182
|
+
enLabel: page.enName || page.code,
|
|
183
|
+
icon: iconMapping[page.code] || "",
|
|
184
|
+
parent: parentPermissionRes,
|
|
185
|
+
route: normalizedPath,
|
|
186
|
+
pageCode: page.code,
|
|
187
|
+
parentPageCode: page.parentId
|
|
188
|
+
? pageMap.get(page.parentId)?.code
|
|
189
|
+
: undefined,
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
resultResources.push(resource);
|
|
194
|
+
addedResourceNames.add(permissionRes);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Build final resources array with auto-crud if needed
|
|
198
|
+
const dynamicResources = resultResources;
|
|
199
|
+
const allResources = dynamicResources;
|
|
200
|
+
|
|
201
|
+
// Cache the result - will be used for all subsequent calls
|
|
202
|
+
cachedResources = allResources;
|
|
203
|
+
isComputing = false;
|
|
204
|
+
|
|
205
|
+
if (import.meta.env.DEV) {
|
|
206
|
+
console.log('[useDynamicResources] ✅ Resources cached. Count:', cachedResources.length);
|
|
207
|
+
console.log('[useDynamicResources] 📌 This reference will be reused for all future calls');
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return cachedResources;
|
|
211
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { customRequest } from "helpers/login";
|
|
4
|
+
|
|
5
|
+
export const useFetchData = (
|
|
6
|
+
url: string,
|
|
7
|
+
type: "post" | "get",
|
|
8
|
+
defaultQuery?: any,
|
|
9
|
+
disableReq?: any,
|
|
10
|
+
errorCallBack?: () => void
|
|
11
|
+
) => {
|
|
12
|
+
const [data, setData] = useState<any>();
|
|
13
|
+
const [reqQuery, setReqQuery] = useState<any>(defaultQuery);
|
|
14
|
+
const [loading, setLoading] = useState<boolean>(false);
|
|
15
|
+
const fetchData = async (query?: any) => {
|
|
16
|
+
if (!url) return;
|
|
17
|
+
setLoading(true);
|
|
18
|
+
try {
|
|
19
|
+
const res = await customRequest(url, type, query);
|
|
20
|
+
setData(res);
|
|
21
|
+
setReqQuery(query);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error(error);
|
|
24
|
+
errorCallBack && errorCallBack();
|
|
25
|
+
}
|
|
26
|
+
setLoading(false);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
!disableReq && url && fetchData(defaultQuery);
|
|
31
|
+
}, []);
|
|
32
|
+
return { data, loading, fetchData, reqQuery };
|
|
33
|
+
};
|