@gadmin2n/schematics 0.0.64 → 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/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,1088 @@
|
|
|
1
|
+
import { Alert, Card, Collapse, Divider, Table, Tabs, Typography } from "antd";
|
|
2
|
+
|
|
3
|
+
const { Title, Paragraph, Text } = Typography;
|
|
4
|
+
|
|
5
|
+
// ─── 核心概念 ────────────────────────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
const coreConceptColumns = [
|
|
8
|
+
{ title: "概念", dataIndex: "concept", key: "concept", width: 160 },
|
|
9
|
+
{ title: "数据库表", dataIndex: "table", key: "table", width: 140 },
|
|
10
|
+
{ title: "说明", dataIndex: "description", key: "description" },
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
const coreConceptData = [
|
|
14
|
+
{
|
|
15
|
+
key: "page",
|
|
16
|
+
concept: "Page(页面/菜单)",
|
|
17
|
+
table: "t_page",
|
|
18
|
+
description:
|
|
19
|
+
"定义系统中的所有菜单项,支持树形结构(parentId)。每个 Page 有唯一的 code,对应前端路由注册表中的 key。",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
key: "resource",
|
|
23
|
+
concept: "Resource(资源)",
|
|
24
|
+
table: "t_resource",
|
|
25
|
+
description:
|
|
26
|
+
"定义后端 API 资源,每个资源对应一组 CRUD 权限(readAny, createAny, updateAny, deleteAny)。",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
key: "role",
|
|
30
|
+
concept: "Role(角色)",
|
|
31
|
+
table: "t_role",
|
|
32
|
+
description:
|
|
33
|
+
"角色是权限分配的基本单位。一个用户拥有一个角色,角色决定了可见菜单和 API 权限。",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
key: "role_pages",
|
|
37
|
+
concept: "RolePages(角色-页面)",
|
|
38
|
+
table: "t_role_pages",
|
|
39
|
+
description: "角色与页面的关联表,决定角色可以看到哪些菜单项。",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
key: "role_resource",
|
|
43
|
+
concept: "RoleResource(角色-资源)",
|
|
44
|
+
table: "t_role_resource",
|
|
45
|
+
description:
|
|
46
|
+
"角色与资源的关联表,定义角色对每个资源的具体权限(读/写/改/删)。",
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
key: "page_resource",
|
|
50
|
+
concept: "PageResource(页面-资源)",
|
|
51
|
+
table: "t_page_resource",
|
|
52
|
+
description:
|
|
53
|
+
"页面与资源的关联表,记录每个页面需要哪些 API 资源。用于批量为角色分配权限。",
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
// ─── t_page 字段说明 ─────────────────────────────────────────────────────────
|
|
58
|
+
|
|
59
|
+
const pageFieldColumns = [
|
|
60
|
+
{ title: "字段", dataIndex: "field", key: "field", width: 180 },
|
|
61
|
+
{ title: "说明", dataIndex: "description", key: "description" },
|
|
62
|
+
{ title: "示例", dataIndex: "example", key: "example", width: 260 },
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
const pageFieldData = [
|
|
66
|
+
{
|
|
67
|
+
key: "code",
|
|
68
|
+
field: "code",
|
|
69
|
+
description:
|
|
70
|
+
"页面唯一标识,原生页面必须与 routeRegistry 的 key 一致",
|
|
71
|
+
example: "software_dashboard",
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
key: "zhName",
|
|
75
|
+
field: "zhName / enName",
|
|
76
|
+
description: "菜单显示的中英文名称",
|
|
77
|
+
example: "软件看板 / Software Dashboard",
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
key: "path",
|
|
81
|
+
field: "path",
|
|
82
|
+
description:
|
|
83
|
+
"URL 完整路径。原生页面会被 routeRegistry 覆盖,iframe/外部链接页面以此作为菜单跳转路径",
|
|
84
|
+
example: "/office/software-dashboard",
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
key: "parentId",
|
|
88
|
+
field: "parentId",
|
|
89
|
+
description: "父菜单 ID,用于构建树形菜单结构",
|
|
90
|
+
example: "office 页面的 ID",
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
key: "sortOrder",
|
|
94
|
+
field: "sortOrder",
|
|
95
|
+
description: "同级菜单的排序权重,数字越小越靠前",
|
|
96
|
+
example: "10",
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
key: "iframeUrl",
|
|
100
|
+
field: "iframeUrl",
|
|
101
|
+
description:
|
|
102
|
+
"iframe 嵌入地址。设置后页面以 iframe 方式渲染,支持 {{locale}} 模板变量",
|
|
103
|
+
example: "https://analytics.example.com?lang={{locale}}",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
key: "externalRedirectUrl",
|
|
107
|
+
field: "externalRedirectUrl",
|
|
108
|
+
description:
|
|
109
|
+
"外部跳转地址。设置后点击菜单在新窗口打开目标 URL,支持 {{locale}} 模板变量",
|
|
110
|
+
example: "https://wiki.example.com/page",
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
key: "isVirtual",
|
|
114
|
+
field: "isVirtual",
|
|
115
|
+
description: "虚拟页面标记,设为 true 时不在侧边栏显示菜单项",
|
|
116
|
+
example: "false",
|
|
117
|
+
},
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
// ─── 常见问题 ────────────────────────────────────────────────────────────────
|
|
121
|
+
|
|
122
|
+
const faqItems = [
|
|
123
|
+
{
|
|
124
|
+
key: "1",
|
|
125
|
+
label: "菜单不显示?",
|
|
126
|
+
children: (
|
|
127
|
+
<ol>
|
|
128
|
+
<li>
|
|
129
|
+
检查 <Text code>routeRegistry.tsx</Text> 中是否注册了路由,且 key 与
|
|
130
|
+
t_page 的 code 一致
|
|
131
|
+
</li>
|
|
132
|
+
<li>
|
|
133
|
+
检查 <Text code>t_page</Text>{" "}
|
|
134
|
+
表中是否创建了记录(进入 Page Management 查看)
|
|
135
|
+
</li>
|
|
136
|
+
<li>检查当前用户的角色是否分配了该页面(进入 Role Management 查看)</li>
|
|
137
|
+
<li>
|
|
138
|
+
检查 <Text code>parentId</Text>{" "}
|
|
139
|
+
是否正确——父级页面也需要分配给角色,否则整个子树不可见
|
|
140
|
+
</li>
|
|
141
|
+
</ol>
|
|
142
|
+
),
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
key: "2",
|
|
146
|
+
label: "页面显示空白?",
|
|
147
|
+
children: (
|
|
148
|
+
<ol>
|
|
149
|
+
<li>
|
|
150
|
+
检查 <Text code>routeRegistry.tsx</Text> 中的{" "}
|
|
151
|
+
<Text code>component</Text> 是否正确导入
|
|
152
|
+
</li>
|
|
153
|
+
<li>
|
|
154
|
+
确认页面组件文件已正确导出(export 名称是否与 import 一致)
|
|
155
|
+
</li>
|
|
156
|
+
<li>
|
|
157
|
+
打开浏览器 DevTools Console 查看是否有 JS 加载错误
|
|
158
|
+
</li>
|
|
159
|
+
</ol>
|
|
160
|
+
),
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
key: "3",
|
|
164
|
+
label: "API 返回 403?",
|
|
165
|
+
children: (
|
|
166
|
+
<Paragraph>
|
|
167
|
+
后端权限由 <Text code>t_role_resource</Text> 控制。进入 Role
|
|
168
|
+
Management,检查角色是否分配了对应资源的权限(readAny / createAny /
|
|
169
|
+
updateAny / deleteAny)。注意:前端菜单可见不代表有 API
|
|
170
|
+
权限,两者独立配置。
|
|
171
|
+
</Paragraph>
|
|
172
|
+
),
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
key: "4",
|
|
176
|
+
label: "iframe 页面加载失败?",
|
|
177
|
+
children: (
|
|
178
|
+
<ol>
|
|
179
|
+
<li>
|
|
180
|
+
检查目标网站是否允许被 iframe 嵌入(X-Frame-Options /
|
|
181
|
+
Content-Security-Policy 头)
|
|
182
|
+
</li>
|
|
183
|
+
<li>
|
|
184
|
+
确认 <Text code>iframeUrl</Text> 与{" "}
|
|
185
|
+
<Text code>externalRedirectUrl</Text> 未同时填写(两者互斥)
|
|
186
|
+
</li>
|
|
187
|
+
<li>
|
|
188
|
+
如果目标网站禁止 iframe 嵌入,改用 <Text code>externalRedirectUrl</Text>{" "}
|
|
189
|
+
以新窗口方式打开
|
|
190
|
+
</li>
|
|
191
|
+
</ol>
|
|
192
|
+
),
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
key: "5",
|
|
196
|
+
label: "如何添加子菜单?",
|
|
197
|
+
children: (
|
|
198
|
+
<Paragraph>
|
|
199
|
+
在 <Text code>t_page</Text> 中创建记录时将{" "}
|
|
200
|
+
<Text code>parentId</Text> 设为父菜单的 ID。如果是原生页面,在{" "}
|
|
201
|
+
<Text code>routeRegistry.tsx</Text> 中也需要将路由放入父路由的{" "}
|
|
202
|
+
<Text code>children</Text> 对象中。
|
|
203
|
+
</Paragraph>
|
|
204
|
+
),
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
key: "6",
|
|
208
|
+
label: "{{locale}} 模板变量怎么用?",
|
|
209
|
+
children: (
|
|
210
|
+
<Paragraph>
|
|
211
|
+
在 <Text code>iframeUrl</Text> 或{" "}
|
|
212
|
+
<Text code>externalRedirectUrl</Text> 中使用{" "}
|
|
213
|
+
<Text code>{"{{locale}}"}</Text>,系统会在运行时自动替换为当前语言(
|
|
214
|
+
<Text code>en</Text> 或 <Text code>zh</Text>)。例如:
|
|
215
|
+
<Text code>
|
|
216
|
+
https://example.com/docs?lang={"{{locale}}"}
|
|
217
|
+
</Text>
|
|
218
|
+
</Paragraph>
|
|
219
|
+
),
|
|
220
|
+
},
|
|
221
|
+
];
|
|
222
|
+
|
|
223
|
+
// ─── 原生页面注册步骤 ────────────────────────────────────────────────────────
|
|
224
|
+
|
|
225
|
+
const nativeStepColumns = [
|
|
226
|
+
{ title: "步骤", dataIndex: "step", key: "step", width: 80 },
|
|
227
|
+
{ title: "操作", dataIndex: "action", key: "action", width: 200 },
|
|
228
|
+
{ title: "说明", dataIndex: "detail", key: "detail" },
|
|
229
|
+
];
|
|
230
|
+
|
|
231
|
+
const nativeStepData = [
|
|
232
|
+
{
|
|
233
|
+
key: "1",
|
|
234
|
+
step: "1",
|
|
235
|
+
action: "创建页面组件",
|
|
236
|
+
detail:
|
|
237
|
+
"在 src/routes/ 下创建页面组件文件,如 src/routes/office/my-feature/index.tsx,导出页面组件。",
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
key: "2",
|
|
241
|
+
step: "2",
|
|
242
|
+
action: "在 routeRegistry 注册路由",
|
|
243
|
+
detail:
|
|
244
|
+
"在 src/config/routeRegistry.tsx 中添加路由条目。key 即为 page code,配置 path(相对路径)和 component(lazy import)。如有子路由放入 children。",
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
key: "3",
|
|
248
|
+
step: "3",
|
|
249
|
+
action: "在 Page Management 创建记录",
|
|
250
|
+
detail:
|
|
251
|
+
"进入 /admin/permission/page-list,新建页面。code 必须与 routeRegistry 中的 key 完全一致,设置 parentId 为父菜单 ID。",
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
key: "4",
|
|
255
|
+
step: "4",
|
|
256
|
+
action: "关联资源(可选)",
|
|
257
|
+
detail:
|
|
258
|
+
"如果页面需要 API 权限控制,在页面记录中关联对应的 Resource,用于后续批量分配权限。",
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
key: "5",
|
|
262
|
+
step: "5",
|
|
263
|
+
action: "为角色分配页面",
|
|
264
|
+
detail:
|
|
265
|
+
"进入 /admin/permission/role-list,编辑目标角色,勾选新添加的页面。",
|
|
266
|
+
},
|
|
267
|
+
];
|
|
268
|
+
|
|
269
|
+
// ─── 对比表 ──────────────────────────────────────────────────────────────────
|
|
270
|
+
|
|
271
|
+
const comparisonColumns = [
|
|
272
|
+
{ title: "", dataIndex: "item", key: "item", width: 160 },
|
|
273
|
+
{ title: "原生页面", dataIndex: "native", key: "native" },
|
|
274
|
+
{ title: "外部链接", dataIndex: "external", key: "external" },
|
|
275
|
+
{ title: "iframe 嵌入", dataIndex: "iframe", key: "iframe" },
|
|
276
|
+
{ title: "动态菜单", dataIndex: "dynamic", key: "dynamic" },
|
|
277
|
+
];
|
|
278
|
+
|
|
279
|
+
const comparisonData = [
|
|
280
|
+
{
|
|
281
|
+
key: "scene",
|
|
282
|
+
item: "适用场景",
|
|
283
|
+
native: "内部开发的完整功能页面",
|
|
284
|
+
external: "跳转到外部系统(Wiki、文档等)",
|
|
285
|
+
iframe: "在应用内嵌入外部页面(报表等)",
|
|
286
|
+
dynamic: "同一组件多实例(如工作室列表)",
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
key: "registry",
|
|
290
|
+
item: "需要修改前端页面",
|
|
291
|
+
native: "是(config/routeRegistry.tsx)",
|
|
292
|
+
external: "否",
|
|
293
|
+
iframe: "否",
|
|
294
|
+
dynamic: "是(config/dynamicMenus.ts 配置)",
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
key: "component",
|
|
298
|
+
item: "需要写页面组件",
|
|
299
|
+
native: "是",
|
|
300
|
+
external: "否",
|
|
301
|
+
iframe: "否",
|
|
302
|
+
dynamic: "是(共享组件)",
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
key: "tpage",
|
|
306
|
+
item: "需要 t_page 记录",
|
|
307
|
+
native: "是(code = routeRegistry key)",
|
|
308
|
+
external: "是(填 externalRedirectUrl)",
|
|
309
|
+
iframe: "是(填 iframeUrl)",
|
|
310
|
+
dynamic: "是(父级目录)",
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
key: "url",
|
|
314
|
+
item: "关键 t_page 字段",
|
|
315
|
+
native: "code, path, parentId",
|
|
316
|
+
external: "externalRedirectUrl",
|
|
317
|
+
iframe: "iframeUrl",
|
|
318
|
+
dynamic: "code(如 invested / native)",
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
key: "behavior",
|
|
322
|
+
item: "用户体验",
|
|
323
|
+
native: "应用内完整渲染",
|
|
324
|
+
external: "新窗口打开 + 自动返回",
|
|
325
|
+
iframe: "应用框架内嵌入",
|
|
326
|
+
dynamic: "应用内完整渲染",
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
key: "template",
|
|
330
|
+
item: "支持 {{locale}}",
|
|
331
|
+
native: "—",
|
|
332
|
+
external: "是",
|
|
333
|
+
iframe: "是",
|
|
334
|
+
dynamic: "—",
|
|
335
|
+
},
|
|
336
|
+
];
|
|
337
|
+
|
|
338
|
+
// ─── 组件 ────────────────────────────────────────────────────────────────────
|
|
339
|
+
|
|
340
|
+
export const PermissionReadmePage = () => {
|
|
341
|
+
return (
|
|
342
|
+
<div style={{ padding: "24px 0" }}>
|
|
343
|
+
<Typography>
|
|
344
|
+
<Title level={2}>菜单管理说明</Title>
|
|
345
|
+
<Paragraph>
|
|
346
|
+
本页面介绍系统的菜单、路由与权限管理机制,帮助管理员理解如何添加和配置不同类型的菜单项。
|
|
347
|
+
</Paragraph>
|
|
348
|
+
</Typography>
|
|
349
|
+
|
|
350
|
+
{/* ── 架构概览 ──────────────────────────────────────────────── */}
|
|
351
|
+
<Card title="菜单系统架构" style={{ marginBottom: 24 }}>
|
|
352
|
+
<Paragraph>
|
|
353
|
+
系统的菜单管理涉及<Text strong>前端路由注册</Text>和
|
|
354
|
+
<Text strong>数据库页面配置</Text>两个部分的协作。
|
|
355
|
+
未匹配到 routeRegistry 的路由会进入{" "}
|
|
356
|
+
<Text code>WildcardPage</Text> 通配组件,
|
|
357
|
+
由它根据 t_page 的配置决定渲染 iframe、打开外部链接或显示 404。
|
|
358
|
+
</Paragraph>
|
|
359
|
+
<Alert
|
|
360
|
+
type="info"
|
|
361
|
+
showIcon
|
|
362
|
+
message="数据流"
|
|
363
|
+
description={
|
|
364
|
+
<div>
|
|
365
|
+
<Text code>routeRegistry.tsx</Text>(前端路由定义:Route Path、React组件) +{" "}
|
|
366
|
+
<Text code>t_page</Text>(数据库菜单配置) →{" "}
|
|
367
|
+
<Text code>侧边栏菜单渲染</Text> + <Text code>路由匹配</Text>
|
|
368
|
+
<br />
|
|
369
|
+
<br />
|
|
370
|
+
路由匹配优先级:<Text code>routeRegistry</Text> 原生路由 >{" "}
|
|
371
|
+
<Text code>WildcardPage (/*)</Text> 通配路由
|
|
372
|
+
<br />
|
|
373
|
+
<br />
|
|
374
|
+
WildcardPage 处理:查询 t_page → 有{" "}
|
|
375
|
+
<Text code>iframeUrl</Text> → 渲染 iframe | 有{" "}
|
|
376
|
+
<Text code>externalRedirectUrl</Text> → 新窗口打开 | 否则 → 404
|
|
377
|
+
</div>
|
|
378
|
+
}
|
|
379
|
+
style={{ marginBottom: 16 }}
|
|
380
|
+
/>
|
|
381
|
+
</Card>
|
|
382
|
+
|
|
383
|
+
{/* ── 核心概念 ──────────────────────────────────────────────── */}
|
|
384
|
+
<Card title="核心概念" style={{ marginBottom: 24 }}>
|
|
385
|
+
<Table
|
|
386
|
+
columns={coreConceptColumns}
|
|
387
|
+
dataSource={coreConceptData}
|
|
388
|
+
pagination={false}
|
|
389
|
+
size="small"
|
|
390
|
+
bordered
|
|
391
|
+
/>
|
|
392
|
+
<Divider />
|
|
393
|
+
<Title level={5}>t_page 关键字段</Title>
|
|
394
|
+
<Table
|
|
395
|
+
columns={pageFieldColumns}
|
|
396
|
+
dataSource={pageFieldData}
|
|
397
|
+
pagination={false}
|
|
398
|
+
size="small"
|
|
399
|
+
bordered
|
|
400
|
+
/>
|
|
401
|
+
</Card>
|
|
402
|
+
|
|
403
|
+
{/* ── 四种注册方式 ──────────────────────────────────────────── */}
|
|
404
|
+
<Card title="菜单注册方式" style={{ marginBottom: 24 }}>
|
|
405
|
+
<Alert
|
|
406
|
+
type="info"
|
|
407
|
+
showIcon
|
|
408
|
+
message="四种方式对比"
|
|
409
|
+
style={{ marginBottom: 16 }}
|
|
410
|
+
description={
|
|
411
|
+
<Table
|
|
412
|
+
columns={comparisonColumns}
|
|
413
|
+
dataSource={comparisonData}
|
|
414
|
+
pagination={false}
|
|
415
|
+
size="small"
|
|
416
|
+
bordered
|
|
417
|
+
scroll={{ x: 800 }}
|
|
418
|
+
/>
|
|
419
|
+
}
|
|
420
|
+
/>
|
|
421
|
+
|
|
422
|
+
<Tabs
|
|
423
|
+
items={[
|
|
424
|
+
{
|
|
425
|
+
key: "native",
|
|
426
|
+
label: "原生页面",
|
|
427
|
+
children: (
|
|
428
|
+
<>
|
|
429
|
+
<Paragraph>
|
|
430
|
+
原生页面是最常见的方式——编写 React 组件,在{" "}
|
|
431
|
+
<Text code>routeRegistry.tsx</Text> 中注册路由,再在 t_page
|
|
432
|
+
中创建对应记录。
|
|
433
|
+
</Paragraph>
|
|
434
|
+
<Alert
|
|
435
|
+
type="warning"
|
|
436
|
+
showIcon
|
|
437
|
+
message="关键约束"
|
|
438
|
+
description={
|
|
439
|
+
<>
|
|
440
|
+
routeRegistry 中的 key(如{" "}
|
|
441
|
+
<Text code>software_dashboard</Text>)必须与 t_page 的{" "}
|
|
442
|
+
<Text code>code</Text>{" "}
|
|
443
|
+
字段完全一致,否则菜单无法正常显示。
|
|
444
|
+
</>
|
|
445
|
+
}
|
|
446
|
+
style={{ marginBottom: 16 }}
|
|
447
|
+
/>
|
|
448
|
+
<Title level={5}>注册步骤</Title>
|
|
449
|
+
<Table
|
|
450
|
+
columns={nativeStepColumns}
|
|
451
|
+
dataSource={nativeStepData}
|
|
452
|
+
pagination={false}
|
|
453
|
+
size="small"
|
|
454
|
+
bordered
|
|
455
|
+
/>
|
|
456
|
+
<Divider />
|
|
457
|
+
<Title level={5}>routeRegistry 示例</Title>
|
|
458
|
+
<pre
|
|
459
|
+
style={{
|
|
460
|
+
background: "#f5f5f5",
|
|
461
|
+
padding: 16,
|
|
462
|
+
borderRadius: 6,
|
|
463
|
+
overflow: "auto",
|
|
464
|
+
fontSize: 13,
|
|
465
|
+
lineHeight: 1.6,
|
|
466
|
+
}}
|
|
467
|
+
>{`// src/config/routeRegistry.tsx
|
|
468
|
+
office: {
|
|
469
|
+
path: "/office",
|
|
470
|
+
children: {
|
|
471
|
+
// key "my_feature" 即为 t_page 中的 code
|
|
472
|
+
my_feature: {
|
|
473
|
+
path: "my-feature-dashboard",
|
|
474
|
+
component: lazy(() => import("@/routes/office/my-feature")),
|
|
475
|
+
},
|
|
476
|
+
},
|
|
477
|
+
},`}</pre>
|
|
478
|
+
|
|
479
|
+
<Divider />
|
|
480
|
+
<Title level={5}>
|
|
481
|
+
下划线前缀(_ 开头)的子路由
|
|
482
|
+
</Title>
|
|
483
|
+
<Paragraph>
|
|
484
|
+
routeRegistry 中以 <Text code>_</Text>{" "}
|
|
485
|
+
开头的 key 是<Text strong>内部子路由</Text>,
|
|
486
|
+
<Text strong>无需在 t_page 中注册</Text>。
|
|
487
|
+
它们由父级页面的 code
|
|
488
|
+
统一管理权限,属于同一个页面模块的不同视图。
|
|
489
|
+
</Paragraph>
|
|
490
|
+
|
|
491
|
+
<Title level={5}>
|
|
492
|
+
CRUD 子路由
|
|
493
|
+
</Title>
|
|
494
|
+
<Paragraph>
|
|
495
|
+
最常见的 <Text code>_</Text> 前缀子路由,
|
|
496
|
+
用于同一模块的列表/新建/编辑/详情视图,不出现在侧边栏中:
|
|
497
|
+
</Paragraph>
|
|
498
|
+
<Table
|
|
499
|
+
columns={[
|
|
500
|
+
{ title: "Key", dataIndex: "key", key: "key", width: 100 },
|
|
501
|
+
{ title: "典型 path", dataIndex: "path", key: "path", width: 140 },
|
|
502
|
+
{ title: "用途", dataIndex: "usage", key: "usage" },
|
|
503
|
+
]}
|
|
504
|
+
dataSource={[
|
|
505
|
+
{
|
|
506
|
+
key: "_list",
|
|
507
|
+
path: '""(index: true)',
|
|
508
|
+
usage:
|
|
509
|
+
"列表页,作为父路由的默认子路由(index route),访问父路径时自动渲染",
|
|
510
|
+
},
|
|
511
|
+
{
|
|
512
|
+
key: "_create",
|
|
513
|
+
path: '"create"',
|
|
514
|
+
usage: "新建页,如 /admin/staff/create",
|
|
515
|
+
},
|
|
516
|
+
{
|
|
517
|
+
key: "_edit",
|
|
518
|
+
path: '"edit/:id"',
|
|
519
|
+
usage: "编辑页,如 /admin/staff/edit/123",
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
key: "_show",
|
|
523
|
+
path: '"show/:id"',
|
|
524
|
+
usage: "详情页,如 /admin/staff/show/123",
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
key: "_index",
|
|
528
|
+
path: '""(index: true)',
|
|
529
|
+
usage: "与 _list 类似,用于非 CRUD 场景的默认子路由",
|
|
530
|
+
},
|
|
531
|
+
]}
|
|
532
|
+
pagination={false}
|
|
533
|
+
size="small"
|
|
534
|
+
bordered
|
|
535
|
+
/>
|
|
536
|
+
|
|
537
|
+
<Divider />
|
|
538
|
+
<Title level={5}>
|
|
539
|
+
动态参数路由 + Sidebar-only 菜单条目
|
|
540
|
+
</Title>
|
|
541
|
+
<Paragraph>
|
|
542
|
+
当多个菜单项共享同一个页面组件、只通过 URL
|
|
543
|
+
参数区分内容时,使用{" "}
|
|
544
|
+
<Text strong>动态参数路由 + Sidebar-only 条目</Text>的组合模式:
|
|
545
|
+
</Paragraph>
|
|
546
|
+
<ul>
|
|
547
|
+
<li>
|
|
548
|
+
动态参数路由(如 <Text code>_tab</Text> / <Text code>_region</Text>) - 负责实际渲染,<Text strong>不注册 t_page</Text>
|
|
549
|
+
</li>
|
|
550
|
+
<li>
|
|
551
|
+
Sidebar-only 条目(如{" "}
|
|
552
|
+
<Text code>apac</Text>、<Text code>security_event</Text>
|
|
553
|
+
)— 只有 path、没有 component,
|
|
554
|
+
<Text strong>需要注册 t_page</Text>,
|
|
555
|
+
出现在侧边栏菜单中。用户点击后 URL
|
|
556
|
+
匹配到动态参数路由,由共享组件渲染。
|
|
557
|
+
</li>
|
|
558
|
+
</ul>
|
|
559
|
+
<pre
|
|
560
|
+
style={{
|
|
561
|
+
background: "#f5f5f5",
|
|
562
|
+
padding: 16,
|
|
563
|
+
borderRadius: 6,
|
|
564
|
+
overflow: "auto",
|
|
565
|
+
fontSize: 13,
|
|
566
|
+
lineHeight: 1.6,
|
|
567
|
+
}}
|
|
568
|
+
>{`// 示例:RTO 看板按区域分子菜单
|
|
569
|
+
// t_page 需注册:overview, apac, amer, emea
|
|
570
|
+
// _index 和 _region 无需注册
|
|
571
|
+
|
|
572
|
+
overview: {
|
|
573
|
+
path: "rto-dashboard",
|
|
574
|
+
children: {
|
|
575
|
+
_index: { // 默认视图,无需注册 t_page
|
|
576
|
+
path: "",
|
|
577
|
+
index: true,
|
|
578
|
+
component: lazy(() => import("@/routes/office/rto")),
|
|
579
|
+
},
|
|
580
|
+
_region: { // 动态参数路由,无需注册 t_page
|
|
581
|
+
path: ":region", // 匹配 /office/rto-dashboard/apac 等
|
|
582
|
+
component: lazy(() => import("@/routes/office/rto")),
|
|
583
|
+
},
|
|
584
|
+
// Sidebar-only 条目:需注册 t_page,出现在侧边栏菜单
|
|
585
|
+
apac: { path: "apac" }, // 无 component,点击后由 _region 渲染
|
|
586
|
+
amer: { path: "amer" },
|
|
587
|
+
emea: { path: "emea" },
|
|
588
|
+
},
|
|
589
|
+
},`}</pre>
|
|
590
|
+
|
|
591
|
+
<Alert
|
|
592
|
+
type="info"
|
|
593
|
+
showIcon
|
|
594
|
+
message="命名约定总结"
|
|
595
|
+
description={
|
|
596
|
+
<ul style={{ margin: 0, paddingLeft: 20 }}>
|
|
597
|
+
<li>
|
|
598
|
+
<Text strong>不以 _ 开头</Text>的 key →
|
|
599
|
+
页面 code,需在 t_page 中注册。有 component
|
|
600
|
+
的是原生页面,无 component 的是 sidebar-only 菜单条目
|
|
601
|
+
</li>
|
|
602
|
+
<li>
|
|
603
|
+
<Text strong>以 _ 开头</Text>的 key →
|
|
604
|
+
内部子路由,不注册 t_page,不出现在侧边栏,权限跟随父级页面
|
|
605
|
+
</li>
|
|
606
|
+
</ul>
|
|
607
|
+
}
|
|
608
|
+
style={{ marginTop: 16, marginBottom: 16 }}
|
|
609
|
+
/>
|
|
610
|
+
|
|
611
|
+
<Title level={5}>CRUD 模块完整示例</Title>
|
|
612
|
+
<pre
|
|
613
|
+
style={{
|
|
614
|
+
background: "#f5f5f5",
|
|
615
|
+
padding: 16,
|
|
616
|
+
borderRadius: 6,
|
|
617
|
+
overflow: "auto",
|
|
618
|
+
fontSize: 13,
|
|
619
|
+
lineHeight: 1.6,
|
|
620
|
+
}}
|
|
621
|
+
>{`// 只需在 t_page 中注册 "staff"(code="staff"),
|
|
622
|
+
// 下面 4 个 _ 开头的子路由无需注册,自动跟随 staff 的权限。
|
|
623
|
+
staff: {
|
|
624
|
+
path: "staff",
|
|
625
|
+
children: {
|
|
626
|
+
_list: {
|
|
627
|
+
path: "",
|
|
628
|
+
index: true, // 访问 /admin/staff 时渲染列表页
|
|
629
|
+
component: lazy(() => import("@/routes/administration/staff")
|
|
630
|
+
.then((m) => ({ default: m.StaffListPage }))),
|
|
631
|
+
},
|
|
632
|
+
_create: {
|
|
633
|
+
path: "create", // /admin/staff/create
|
|
634
|
+
component: lazy(() => import("@/routes/administration/staff")
|
|
635
|
+
.then((m) => ({ default: m.StaffCreatePage }))),
|
|
636
|
+
},
|
|
637
|
+
_edit: {
|
|
638
|
+
path: "edit/:id", // /admin/staff/edit/123
|
|
639
|
+
component: lazy(() => import("@/routes/administration/staff")
|
|
640
|
+
.then((m) => ({ default: m.StaffEditPage }))),
|
|
641
|
+
},
|
|
642
|
+
_show: {
|
|
643
|
+
path: "show/:id", // /admin/staff/show/123
|
|
644
|
+
component: lazy(() => import("@/routes/administration/staff")
|
|
645
|
+
.then((m) => ({ default: m.StaffShowPage }))),
|
|
646
|
+
},
|
|
647
|
+
},
|
|
648
|
+
},`}</pre>
|
|
649
|
+
</>
|
|
650
|
+
),
|
|
651
|
+
},
|
|
652
|
+
{
|
|
653
|
+
key: "external",
|
|
654
|
+
label: "外部链接",
|
|
655
|
+
children: (
|
|
656
|
+
<>
|
|
657
|
+
<Paragraph>
|
|
658
|
+
外部链接方式<Text strong>无需编写任何前端代码</Text>
|
|
659
|
+
,只需在 Page Management 中创建一条 t_page 记录,并填写{" "}
|
|
660
|
+
<Text code>externalRedirectUrl</Text> 字段即可。
|
|
661
|
+
点击菜单时系统会在新窗口打开目标 URL,并自动返回前一个页面。
|
|
662
|
+
</Paragraph>
|
|
663
|
+
<Title level={5}>注册步骤</Title>
|
|
664
|
+
<ol>
|
|
665
|
+
<li>
|
|
666
|
+
进入 <Text code>/admin/permission/page-list</Text>
|
|
667
|
+
,新建页面记录
|
|
668
|
+
</li>
|
|
669
|
+
<li>
|
|
670
|
+
填写 <Text code>code</Text>、
|
|
671
|
+
<Text code>zhName</Text>、<Text code>path</Text>(任意唯一路径即可)、
|
|
672
|
+
<Text code>parentId</Text>
|
|
673
|
+
</li>
|
|
674
|
+
<li>
|
|
675
|
+
在 <Text code>External Redirect URL</Text> 字段填入目标地址
|
|
676
|
+
</li>
|
|
677
|
+
<li>为角色分配该页面</li>
|
|
678
|
+
</ol>
|
|
679
|
+
<Alert
|
|
680
|
+
type="info"
|
|
681
|
+
showIcon
|
|
682
|
+
message="模板变量"
|
|
683
|
+
description={
|
|
684
|
+
<>
|
|
685
|
+
URL 中可使用{" "}
|
|
686
|
+
<Text code>{"{{locale}}"}</Text>{" "}
|
|
687
|
+
模板变量,运行时会替换为当前语言(en / zh)。例如:
|
|
688
|
+
<br />
|
|
689
|
+
<Text code>
|
|
690
|
+
https://wiki.example.com/page?lang={"{{locale}}"}
|
|
691
|
+
</Text>
|
|
692
|
+
</>
|
|
693
|
+
}
|
|
694
|
+
style={{ marginTop: 16 }}
|
|
695
|
+
/>
|
|
696
|
+
<Divider />
|
|
697
|
+
<Title level={5}>工作流程</Title>
|
|
698
|
+
<pre
|
|
699
|
+
style={{
|
|
700
|
+
background: "#f5f5f5",
|
|
701
|
+
padding: 16,
|
|
702
|
+
borderRadius: 6,
|
|
703
|
+
overflow: "auto",
|
|
704
|
+
fontSize: 13,
|
|
705
|
+
lineHeight: 1.6,
|
|
706
|
+
}}
|
|
707
|
+
>{`用户点击菜单
|
|
708
|
+
→ 前端路由跳转到 page.path
|
|
709
|
+
→ 未匹配到 routeRegistry,进入 WildcardPage
|
|
710
|
+
→ WildcardPage 查询 t_page,发现 externalRedirectUrl
|
|
711
|
+
→ window.open(url, "_blank") 新窗口打开
|
|
712
|
+
→ window.history.back() 自动返回`}</pre>
|
|
713
|
+
</>
|
|
714
|
+
),
|
|
715
|
+
},
|
|
716
|
+
{
|
|
717
|
+
key: "iframe",
|
|
718
|
+
label: "iframe 嵌入",
|
|
719
|
+
children: (
|
|
720
|
+
<>
|
|
721
|
+
<Paragraph>
|
|
722
|
+
iframe 方式同样<Text strong>无需编写前端代码</Text>
|
|
723
|
+
,在 Page Management 中填写{" "}
|
|
724
|
+
<Text code>iframeUrl</Text>{" "}
|
|
725
|
+
字段即可。页面会在应用框架(侧边栏、顶栏)内以
|
|
726
|
+
iframe 全屏嵌入目标网页。
|
|
727
|
+
</Paragraph>
|
|
728
|
+
<Title level={5}>注册步骤</Title>
|
|
729
|
+
<ol>
|
|
730
|
+
<li>
|
|
731
|
+
进入 <Text code>/admin/permission/page-list</Text>
|
|
732
|
+
,新建页面记录
|
|
733
|
+
</li>
|
|
734
|
+
<li>
|
|
735
|
+
填写 <Text code>code</Text>、
|
|
736
|
+
<Text code>zhName</Text>、<Text code>path</Text>(任意唯一路径即可)、
|
|
737
|
+
<Text code>parentId</Text>
|
|
738
|
+
</li>
|
|
739
|
+
<li>
|
|
740
|
+
在 <Text code>Iframe URL</Text> 字段填入目标地址
|
|
741
|
+
</li>
|
|
742
|
+
<li>为角色分配该页面</li>
|
|
743
|
+
</ol>
|
|
744
|
+
<Alert
|
|
745
|
+
type="warning"
|
|
746
|
+
showIcon
|
|
747
|
+
message="注意事项"
|
|
748
|
+
description={
|
|
749
|
+
<ul style={{ margin: 0, paddingLeft: 20 }}>
|
|
750
|
+
<li>
|
|
751
|
+
<Text code>iframeUrl</Text> 和{" "}
|
|
752
|
+
<Text code>externalRedirectUrl</Text>{" "}
|
|
753
|
+
不能同时填写,两者互斥
|
|
754
|
+
</li>
|
|
755
|
+
<li>
|
|
756
|
+
目标网站必须允许被 iframe 嵌入(未设置{" "}
|
|
757
|
+
<Text code>X-Frame-Options: DENY</Text> 或{" "}
|
|
758
|
+
<Text code>Content-Security-Policy: frame-ancestors 'none'</Text>
|
|
759
|
+
)
|
|
760
|
+
</li>
|
|
761
|
+
<li>
|
|
762
|
+
如果目标网站禁止 iframe,请改用外部链接方式
|
|
763
|
+
</li>
|
|
764
|
+
<li>
|
|
765
|
+
同样支持{" "}
|
|
766
|
+
<Text code>{"{{locale}}"}</Text> 模板变量
|
|
767
|
+
</li>
|
|
768
|
+
</ul>
|
|
769
|
+
}
|
|
770
|
+
style={{ marginTop: 16 }}
|
|
771
|
+
/>
|
|
772
|
+
</>
|
|
773
|
+
),
|
|
774
|
+
},
|
|
775
|
+
{
|
|
776
|
+
key: "dynamic",
|
|
777
|
+
label: "动态菜单",
|
|
778
|
+
children: (
|
|
779
|
+
<>
|
|
780
|
+
<Paragraph>
|
|
781
|
+
动态菜单适用于<Text strong>同一个页面组件需要生成多个菜单项</Text>
|
|
782
|
+
的场景。通过{" "}
|
|
783
|
+
<Text code>src/config/dynamicMenus.ts</Text>{" "}
|
|
784
|
+
的配置驱动方案,开发者只需添加一条配置即可新增动态菜单组。
|
|
785
|
+
</Paragraph>
|
|
786
|
+
|
|
787
|
+
<Title level={5}>配置方式</Title>
|
|
788
|
+
<Paragraph>
|
|
789
|
+
在{" "}
|
|
790
|
+
<Text code>src/config/dynamicMenus.ts</Text>{" "}
|
|
791
|
+
中的{" "}
|
|
792
|
+
<Text code>dynamicMenuGroups</Text>{" "}
|
|
793
|
+
数组中添加一条配置:
|
|
794
|
+
</Paragraph>
|
|
795
|
+
<pre
|
|
796
|
+
style={{
|
|
797
|
+
background: "#f5f5f5",
|
|
798
|
+
padding: 16,
|
|
799
|
+
borderRadius: 6,
|
|
800
|
+
overflow: "auto",
|
|
801
|
+
fontSize: 13,
|
|
802
|
+
lineHeight: 1.6,
|
|
803
|
+
}}
|
|
804
|
+
>{`// src/config/dynamicMenus.ts
|
|
805
|
+
interface DynamicMenuGroup {
|
|
806
|
+
parentCode: string; // 父级 page code(需在 t_page 注册)
|
|
807
|
+
routePrefix: string; // 路由前缀,如 "/rd/invested"
|
|
808
|
+
items: string[]; // 子项列表,每项生成一个菜单项和路由
|
|
809
|
+
component: LazyExoticComponent<ComponentType<any>>; // 共享组件
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// 示例:RD 工作室
|
|
813
|
+
{
|
|
814
|
+
parentCode: "invested",
|
|
815
|
+
routePrefix: "/rd/invested",
|
|
816
|
+
items: studioMap.investedStudios,
|
|
817
|
+
component: lazy(() => import("@/routes/rd/rdec")),
|
|
818
|
+
}`}</pre>
|
|
819
|
+
|
|
820
|
+
<Alert
|
|
821
|
+
type="info"
|
|
822
|
+
showIcon
|
|
823
|
+
message="权限控制"
|
|
824
|
+
description={
|
|
825
|
+
<>
|
|
826
|
+
动态菜单的权限以{" "}
|
|
827
|
+
<Text code>parentCode</Text>{" "}
|
|
828
|
+
为单位控制。例如为角色分配{" "}
|
|
829
|
+
<Text code>invested</Text>{" "}
|
|
830
|
+
页面后,该角色可以看到该组下所有子菜单项。无需为每个子项单独配置权限。
|
|
831
|
+
</>
|
|
832
|
+
}
|
|
833
|
+
style={{ marginTop: 16 }}
|
|
834
|
+
/>
|
|
835
|
+
|
|
836
|
+
<Divider />
|
|
837
|
+
<Title level={5}>添加新动态菜单组的步骤</Title>
|
|
838
|
+
<ol>
|
|
839
|
+
<li>
|
|
840
|
+
在 <Text code>t_page</Text> 中注册父级页面(设置{" "}
|
|
841
|
+
<Text code>code</Text>、<Text code>parentId</Text>)
|
|
842
|
+
</li>
|
|
843
|
+
<li>
|
|
844
|
+
在 <Text code>src/config/dynamicMenus.ts</Text> 的{" "}
|
|
845
|
+
<Text code>dynamicMenuGroups</Text> 数组中添加一条配置
|
|
846
|
+
</li>
|
|
847
|
+
<li>
|
|
848
|
+
路由和菜单项会自动生成,无需修改{" "}
|
|
849
|
+
<Text code>routeRegistry.tsx</Text>、
|
|
850
|
+
<Text code>App.tsx</Text> 或{" "}
|
|
851
|
+
<Text code>useDynamicResources.tsx</Text>
|
|
852
|
+
</li>
|
|
853
|
+
</ol>
|
|
854
|
+
|
|
855
|
+
<Divider />
|
|
856
|
+
<Title level={5}>现有示例:RD 工作室</Title>
|
|
857
|
+
<Paragraph>
|
|
858
|
+
当前系统中 RD 模块的 invested(投资工作室)和 native(自研工作室)使用动态菜单:
|
|
859
|
+
</Paragraph>
|
|
860
|
+
<ul>
|
|
861
|
+
<li>
|
|
862
|
+
工作室列表定义在{" "}
|
|
863
|
+
<Text code>src/config/studio.ts</Text> 的{" "}
|
|
864
|
+
<Text code>studioMap</Text> 中
|
|
865
|
+
</li>
|
|
866
|
+
<li>
|
|
867
|
+
所有工作室路由共享同一个{" "}
|
|
868
|
+
<Text code>RDEC</Text> 组件,组件内从 URL 提取工作室名称
|
|
869
|
+
</li>
|
|
870
|
+
<li>
|
|
871
|
+
添加新工作室只需在{" "}
|
|
872
|
+
<Text code>studio.ts</Text> 的{" "}
|
|
873
|
+
<Text code>StudioEnum</Text> 和{" "}
|
|
874
|
+
<Text code>studioMap</Text> 中添加条目即可
|
|
875
|
+
</li>
|
|
876
|
+
</ul>
|
|
877
|
+
</>
|
|
878
|
+
),
|
|
879
|
+
},
|
|
880
|
+
]}
|
|
881
|
+
/>
|
|
882
|
+
</Card>
|
|
883
|
+
|
|
884
|
+
{/* ── 权限层级关系 ────────────────────────────────────────────── */}
|
|
885
|
+
<Card title="权限层级关系" style={{ marginBottom: 24 }}>
|
|
886
|
+
<Title level={5}>实体关系总览</Title>
|
|
887
|
+
<pre
|
|
888
|
+
style={{
|
|
889
|
+
background: "#f5f5f5",
|
|
890
|
+
padding: 16,
|
|
891
|
+
borderRadius: 6,
|
|
892
|
+
overflow: "auto",
|
|
893
|
+
fontSize: 13,
|
|
894
|
+
lineHeight: 1.8,
|
|
895
|
+
}}
|
|
896
|
+
>{`User (t_admin_user_role)
|
|
897
|
+
└─ roles: ["PRODUCT", "SYSTEM_ADMIN"] ← 用户可拥有多个角色(JSON 数组)
|
|
898
|
+
│
|
|
899
|
+
▼
|
|
900
|
+
Role (t_role)
|
|
901
|
+
├─ RolePages (t_role_pages) ← 控制菜单可见性(前端)
|
|
902
|
+
│ └─ Page (t_page)
|
|
903
|
+
│ └─ PageResource (t_page_resource) ← 页面声明需要的资源权限
|
|
904
|
+
│
|
|
905
|
+
└─ RoleResource (t_role_resource) ← 控制 API 访问权限(后端)
|
|
906
|
+
└─ Resource (t_resource)
|
|
907
|
+
└─ actions: ["readAny", "createAny", "updateAny", "deleteAny"]`}</pre>
|
|
908
|
+
|
|
909
|
+
<Divider />
|
|
910
|
+
<Title level={5}>双层权限防御</Title>
|
|
911
|
+
<Paragraph>
|
|
912
|
+
系统在前端和后端分别进行权限检查,两层独立运作:
|
|
913
|
+
</Paragraph>
|
|
914
|
+
|
|
915
|
+
<Table
|
|
916
|
+
columns={[
|
|
917
|
+
{ title: "", dataIndex: "item", key: "item", width: 140 },
|
|
918
|
+
{ title: "前端:菜单可见性", dataIndex: "frontend", key: "frontend" },
|
|
919
|
+
{ title: "后端:API 访问权限", dataIndex: "backend", key: "backend" },
|
|
920
|
+
]}
|
|
921
|
+
dataSource={[
|
|
922
|
+
{
|
|
923
|
+
key: "table",
|
|
924
|
+
item: "关联表",
|
|
925
|
+
frontend: "t_role_pages(角色 → 页面)",
|
|
926
|
+
backend: "t_role_resource(角色 → 资源)",
|
|
927
|
+
},
|
|
928
|
+
{
|
|
929
|
+
key: "what",
|
|
930
|
+
item: "控制什么",
|
|
931
|
+
frontend: "侧边栏菜单项是否显示",
|
|
932
|
+
backend: "API 请求是否允许执行",
|
|
933
|
+
},
|
|
934
|
+
{
|
|
935
|
+
key: "fail",
|
|
936
|
+
item: "无权限表现",
|
|
937
|
+
frontend: "菜单不可见",
|
|
938
|
+
backend: "返回 HTTP 403",
|
|
939
|
+
},
|
|
940
|
+
{
|
|
941
|
+
key: "check",
|
|
942
|
+
item: "检查机制",
|
|
943
|
+
frontend: "useUserPageAccess() Hook 过滤菜单树",
|
|
944
|
+
backend: "AuthGuard → RolesGuard → @UseRoles() 装饰器",
|
|
945
|
+
},
|
|
946
|
+
]}
|
|
947
|
+
pagination={false}
|
|
948
|
+
size="small"
|
|
949
|
+
bordered
|
|
950
|
+
/>
|
|
951
|
+
|
|
952
|
+
<Divider />
|
|
953
|
+
<Title level={5}>权限检查完整流程</Title>
|
|
954
|
+
<pre
|
|
955
|
+
style={{
|
|
956
|
+
background: "#f5f5f5",
|
|
957
|
+
padding: 16,
|
|
958
|
+
borderRadius: 6,
|
|
959
|
+
overflow: "auto",
|
|
960
|
+
fontSize: 13,
|
|
961
|
+
lineHeight: 1.8,
|
|
962
|
+
}}
|
|
963
|
+
>{`┌─ 前端菜单加载 ─────────────────────────────────────────────────────┐
|
|
964
|
+
│ │
|
|
965
|
+
│ 1. GET /userinfo → 获取用户角色列表 (如 ["PRODUCT"]) │
|
|
966
|
+
│ 2. POST /role/findMany → 查询角色 ID │
|
|
967
|
+
│ 3. POST /rolePages/findMany → 查询角色关联的页面 ID │
|
|
968
|
+
│ 4. POST /page/findMany → 获取所有页面定义 │
|
|
969
|
+
│ 5. 构建可访问页面集合(包含分配页面 + 递归添加祖先页面) │
|
|
970
|
+
│ 6. 生成侧边栏菜单树 │
|
|
971
|
+
│ │
|
|
972
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
973
|
+
|
|
974
|
+
┌─ 后端 API 权限检查 ────────────────────────────────────────────────┐
|
|
975
|
+
│ │
|
|
976
|
+
│ 请求到达 → AuthGuard(验证身份,提取 userid) │
|
|
977
|
+
│ → RolesGuard(查询 t_admin_user_role,获取角色列表) │
|
|
978
|
+
│ → @UseRoles({ resource: "xxx", action: "read" }) │
|
|
979
|
+
│ → RolesBuilder 检查该角色对该资源是否有对应权限 │
|
|
980
|
+
│ → 通过 ✓ 执行 / 拒绝 ✗ 返回 403 │
|
|
981
|
+
│ │
|
|
982
|
+
└─────────────────────────────────────────────────────────────────────┘`}</pre>
|
|
983
|
+
|
|
984
|
+
<Divider />
|
|
985
|
+
<Title level={5}>PageResource 的作用</Title>
|
|
986
|
+
<Paragraph>
|
|
987
|
+
<Text code>t_page_resource</Text> 定义了每个页面需要哪些 API
|
|
988
|
+
资源及权限。当管理员在 Role Management
|
|
989
|
+
中为角色勾选页面时,系统会<Text strong>自动从 PageResource
|
|
990
|
+
中提取资源权限</Text>,同步写入{" "}
|
|
991
|
+
<Text code>t_role_resource</Text>。
|
|
992
|
+
</Paragraph>
|
|
993
|
+
<pre
|
|
994
|
+
style={{
|
|
995
|
+
background: "#f5f5f5",
|
|
996
|
+
padding: 16,
|
|
997
|
+
borderRadius: 6,
|
|
998
|
+
overflow: "auto",
|
|
999
|
+
fontSize: 13,
|
|
1000
|
+
lineHeight: 1.8,
|
|
1001
|
+
}}
|
|
1002
|
+
>{`管理员勾选页面 A(关联了 Resource X [readAny] 和 Resource Y [readAny, createAny])
|
|
1003
|
+
↓
|
|
1004
|
+
系统自动执行:
|
|
1005
|
+
1. 写入 t_role_pages:角色 → 页面 A
|
|
1006
|
+
2. 查询 t_page_resource:页面 A 需要 X(readAny)、Y(readAny, createAny)
|
|
1007
|
+
3. 合并写入 t_role_resource:角色 → X(readAny)、Y(readAny, createAny)
|
|
1008
|
+
|
|
1009
|
+
管理员取消勾选页面 A:
|
|
1010
|
+
1. 删除 t_role_pages 中的关联
|
|
1011
|
+
2. 如果 Resource X/Y 不被其他页面引用,同步删除 t_role_resource 中的关联`}</pre>
|
|
1012
|
+
|
|
1013
|
+
<Divider />
|
|
1014
|
+
<Title level={5}>API 权限类型</Title>
|
|
1015
|
+
<Table
|
|
1016
|
+
columns={[
|
|
1017
|
+
{ title: "权限", dataIndex: "action", key: "action", width: 140 },
|
|
1018
|
+
{ title: "含义", dataIndex: "meaning", key: "meaning" },
|
|
1019
|
+
{ title: "对应 HTTP 操作", dataIndex: "http", key: "http", width: 200 },
|
|
1020
|
+
]}
|
|
1021
|
+
dataSource={[
|
|
1022
|
+
{
|
|
1023
|
+
key: "read",
|
|
1024
|
+
action: "readAny",
|
|
1025
|
+
meaning: "读取任意记录",
|
|
1026
|
+
http: "GET / POST findMany",
|
|
1027
|
+
},
|
|
1028
|
+
{
|
|
1029
|
+
key: "create",
|
|
1030
|
+
action: "createAny",
|
|
1031
|
+
meaning: "创建新记录",
|
|
1032
|
+
http: "POST createOne",
|
|
1033
|
+
},
|
|
1034
|
+
{
|
|
1035
|
+
key: "update",
|
|
1036
|
+
action: "updateAny",
|
|
1037
|
+
meaning: "修改任意记录",
|
|
1038
|
+
http: "PATCH / PUT updateOne",
|
|
1039
|
+
},
|
|
1040
|
+
{
|
|
1041
|
+
key: "delete",
|
|
1042
|
+
action: "deleteAny",
|
|
1043
|
+
meaning: "删除任意记录",
|
|
1044
|
+
http: "DELETE deleteOne",
|
|
1045
|
+
},
|
|
1046
|
+
]}
|
|
1047
|
+
pagination={false}
|
|
1048
|
+
size="small"
|
|
1049
|
+
bordered
|
|
1050
|
+
/>
|
|
1051
|
+
|
|
1052
|
+
<Divider />
|
|
1053
|
+
<Title level={5}>通用资源(Common Resource)</Title>
|
|
1054
|
+
<Paragraph>
|
|
1055
|
+
<Text code>t_resource</Text> 中标记为{" "}
|
|
1056
|
+
<Text code>isCommonResource = true</Text>{" "}
|
|
1057
|
+
的资源会自动为所有角色授予{" "}
|
|
1058
|
+
<Text code>readAny</Text>{" "}
|
|
1059
|
+
权限,无需在页面或角色中单独配置。适用于全局公共数据(如枚举列表、配置项等)。
|
|
1060
|
+
</Paragraph>
|
|
1061
|
+
|
|
1062
|
+
<Divider />
|
|
1063
|
+
<Title level={5}>系统管理员</Title>
|
|
1064
|
+
<Alert
|
|
1065
|
+
type="info"
|
|
1066
|
+
showIcon
|
|
1067
|
+
message="硬编码管理员"
|
|
1068
|
+
description={
|
|
1069
|
+
<>
|
|
1070
|
+
以下用户在后端硬编码为 SYSTEM_ADMIN 角色,即使不在{" "}
|
|
1071
|
+
<Text code>t_admin_user_role</Text>{" "}
|
|
1072
|
+
表中也会自动获得管理员权限:
|
|
1073
|
+
<Text code>kavenma</Text>、<Text code>jasonlan</Text>、
|
|
1074
|
+
<Text code>gc_lvhenan</Text>。
|
|
1075
|
+
</>
|
|
1076
|
+
}
|
|
1077
|
+
/>
|
|
1078
|
+
</Card>
|
|
1079
|
+
|
|
1080
|
+
{/* ── 常见问题 ──────────────────────────────────────────────── */}
|
|
1081
|
+
<Card title="常见问题">
|
|
1082
|
+
<Collapse items={faqItems} />
|
|
1083
|
+
</Card>
|
|
1084
|
+
</div>
|
|
1085
|
+
);
|
|
1086
|
+
};
|
|
1087
|
+
|
|
1088
|
+
export default PermissionReadmePage;
|