From 0c18661b1199b22adcf61ff9cf733438f571d307 Mon Sep 17 00:00:00 2001 From: SharerMax Date: Tue, 30 Sep 2025 03:10:09 +0800 Subject: [PATCH 01/12] fix: vue devtools OOM when role not `all` --- src/store/modules/permission-fe.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/store/modules/permission-fe.ts b/src/store/modules/permission-fe.ts index aa089dd5..44e3ed37 100644 --- a/src/store/modules/permission-fe.ts +++ b/src/store/modules/permission-fe.ts @@ -42,14 +42,14 @@ export const usePermissionStore = defineStore('permission', { let removeRoutes: Array = []; // special token if (roles.includes('all')) { - accessedRouters = cloneDeep(allRoutes); + accessedRouters = allRoutes; } else { const res = filterPermissionsRouters(allRoutes, roles); accessedRouters = res.accessedRouters; removeRoutes = res.removeRoutes; } - this.routers = accessedRouters; + this.routers = cloneDeep(accessedRouters); this.removeRoutes = removeRoutes; removeRoutes.forEach((item: RouteRecordRaw) => { From 8e21ab259259a0d1df2d5302415becb7aeb1af24 Mon Sep 17 00:00:00 2001 From: SharerMax Date: Fri, 3 Oct 2025 00:26:21 +0800 Subject: [PATCH 02/12] fix: route path of `PAGE_NOT_FOUND_ROUTE` incorrect --- src/utils/route/constant.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/utils/route/constant.ts b/src/utils/route/constant.ts index a3ec01c6..ac5e7da5 100644 --- a/src/utils/route/constant.ts +++ b/src/utils/route/constant.ts @@ -1,3 +1,5 @@ +import type { RouteRecordRaw } from 'vue-router'; + export const LAYOUT = () => import('@/layouts/index.vue'); export const BLANK_LAYOUT = () => import('@/layouts/blank.vue'); export const IFRAME = () => import('@/layouts/components/FrameBlank.vue'); @@ -7,8 +9,8 @@ export const PARENT_LAYOUT = () => resolve({ name: 'ParentLayout' }); }); -export const PAGE_NOT_FOUND_ROUTE = { - path: '/:w+', +export const PAGE_NOT_FOUND_ROUTE: RouteRecordRaw = { + path: '/:pathMatch(.*)*', name: '404Page', redirect: '/result/404', }; From 548515953deb921dce0c0324f24a4ddffc4e1c0f Mon Sep 17 00:00:00 2001 From: SharerMax Date: Fri, 3 Oct 2025 01:45:21 +0800 Subject: [PATCH 03/12] fix: only init route in permission route guard --- src/store/modules/user.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts index f68b4edc..63b16adc 100644 --- a/src/store/modules/user.ts +++ b/src/store/modules/user.ts @@ -1,6 +1,5 @@ import { defineStore } from 'pinia'; -import { usePermissionStore } from '@/store'; import type { UserInfo } from '@/types/interface'; const InitUserInfo: UserInfo = { @@ -77,10 +76,6 @@ export const useUserStore = defineStore('user', { }, }, persist: { - afterRestore: () => { - const permissionStore = usePermissionStore(); - permissionStore.initRoutes(); - }, key: 'user', paths: ['token'], }, From 800a4bfc2e629151458ab53a1f5b2e055b6e039a Mon Sep 17 00:00:00 2001 From: SharerMax Date: Fri, 3 Oct 2025 02:01:33 +0800 Subject: [PATCH 04/12] feat: add `permission-fe` use sample --- src/permission.ts | 22 ++++++++++++++++++---- src/store/modules/permission-fe.ts | 1 - 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/permission.ts b/src/permission.ts index c771e906..6c6d1fbe 100644 --- a/src/permission.ts +++ b/src/permission.ts @@ -26,8 +26,8 @@ router.beforeEach(async (to, from, next) => { try { await userStore.getUserInfo(); + // 后端权限控制 const { asyncRoutes } = permissionStore; - if (asyncRoutes && asyncRoutes.length === 0) { const routeList = await permissionStore.buildAsyncRoutes(); routeList.forEach((item: RouteRecordRaw) => { @@ -43,10 +43,23 @@ router.beforeEach(async (to, from, next) => { return; } } + + // 前端权限控制 + // const permissionStore = getPermissionStore(); + // const { routers } = permissionStore; + // if (routers.length === 0) { + // await permissionStore.initRoutes(userStore.roles); + // } + if (router.hasRoute(to.name)) { next(); } else { - next(`/`); + // 动态添加404 page + // router.addRoute(PAGE_NOT_FOUND_ROUTE); + // next(to.fullPath); + + // 不添加404 page,重定向到首页 + next({ path: '/' }); } } catch (error) { MessagePlugin.error(error.message); @@ -73,10 +86,11 @@ router.beforeEach(async (to, from, next) => { router.afterEach((to) => { if (to.path === '/login') { const userStore = useUserStore(); - const permissionStore = getPermissionStore(); userStore.logout(); - permissionStore.restoreRoutes(); + // 后端权限控制 + // const permissionStore = getPermissionStore(); + // permissionStore.restoreRoutes(); } NProgress.done(); }); diff --git a/src/store/modules/permission-fe.ts b/src/store/modules/permission-fe.ts index 44e3ed37..b1155ef1 100644 --- a/src/store/modules/permission-fe.ts +++ b/src/store/modules/permission-fe.ts @@ -48,7 +48,6 @@ export const usePermissionStore = defineStore('permission', { accessedRouters = res.accessedRouters; removeRoutes = res.removeRoutes; } - this.routers = cloneDeep(accessedRouters); this.removeRoutes = removeRoutes; From 82282ffe9ac5ddf052a4eb7fb3d90cd0406022df Mon Sep 17 00:00:00 2001 From: SharerMax Date: Sun, 5 Oct 2025 03:03:14 +0800 Subject: [PATCH 05/12] fix: can restore route when use `permission-fe` ;only use `roleCode` to check permission --- src/layouts/components/MenuContent.vue | 4 +- src/permission.ts | 7 +- src/router/index.ts | 2 + src/router/modules/homepage.ts | 2 + src/router/modules/user.ts | 8 +- src/store/modules/permission-fe.ts | 107 ++++++++++++++++++------- src/store/modules/user.ts | 2 +- src/types/router.d.ts | 2 +- 8 files changed, 94 insertions(+), 40 deletions(-) diff --git a/src/layouts/components/MenuContent.vue b/src/layouts/components/MenuContent.vue index 2bb2a08b..a51430a8 100644 --- a/src/layouts/components/MenuContent.vue +++ b/src/layouts/components/MenuContent.vue @@ -37,7 +37,7 @@ type ListItemType = MenuRoute; const { navData } = defineProps({ navData: { type: Array as PropType, - default: () => [], + default: (): MenuRoute[] => [], }, }); @@ -80,7 +80,7 @@ const getMenuList = (list: MenuRoute[], basePath?: string): ListItemType[] => { redirect: item.redirect, }; }) - .filter((item) => item.meta && item.meta.hidden !== true); + .filter((item) => item.meta && item.meta.hidden !== true && item.meta.title); }; const getHref = (item: MenuRoute) => { diff --git a/src/permission.ts b/src/permission.ts index 6c6d1fbe..73018c73 100644 --- a/src/permission.ts +++ b/src/permission.ts @@ -86,11 +86,10 @@ router.beforeEach(async (to, from, next) => { router.afterEach((to) => { if (to.path === '/login') { const userStore = useUserStore(); - userStore.logout(); - // 后端权限控制 - // const permissionStore = getPermissionStore(); - // permissionStore.restoreRoutes(); + + const permissionStore = getPermissionStore(); + permissionStore.restoreRoutes(); } NProgress.done(); }); diff --git a/src/router/index.ts b/src/router/index.ts index aff51fa4..d8e914e0 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -16,11 +16,13 @@ const defaultRouterList: Array = [ { path: '/login', name: 'login', + meta: { roleCode: 'dev' }, component: () => import('@/pages/login/index.vue'), }, { path: '/', redirect: '/dashboard/base', + meta: { roleCode: 'dev' }, }, ]; // 存放固定路由 diff --git a/src/router/modules/homepage.ts b/src/router/modules/homepage.ts index f5557f83..24a42588 100644 --- a/src/router/modules/homepage.ts +++ b/src/router/modules/homepage.ts @@ -17,6 +17,7 @@ export default [ }, icon: shallowRef(DashboardIcon), orderNo: 0, + roleCode: 'dev', }, children: [ { @@ -28,6 +29,7 @@ export default [ zh_CN: '概览仪表盘', en_US: 'Overview', }, + roleCode: 'dev', }, }, { diff --git a/src/router/modules/user.ts b/src/router/modules/user.ts index fd08b9a5..f787c35e 100644 --- a/src/router/modules/user.ts +++ b/src/router/modules/user.ts @@ -10,13 +10,13 @@ export default [ name: 'user', component: Layout, redirect: '/user/index', - meta: { title: { zh_CN: '个人中心', en_US: 'User Center' }, icon: 'user-circle' }, + meta: { title: { zh_CN: '个人中心', en_US: 'User Center' }, icon: 'user-circle', roleCode: 'dev' }, children: [ { path: 'index', name: 'UserIndex', component: () => import('@/pages/user/index.vue'), - meta: { title: { zh_CN: '个人中心', en_US: 'User Center' } }, + meta: { title: { zh_CN: '个人中心', en_US: 'User Center' }, roleCode: 'dev' }, }, ], }, @@ -24,13 +24,13 @@ export default [ path: '/loginRedirect', name: 'loginRedirect', redirect: '/login', - meta: { title: { zh_CN: '登录页', en_US: 'Login' }, icon: shallowRef(LogoutIcon) }, + meta: { title: { zh_CN: '登录页', en_US: 'Login' }, icon: shallowRef(LogoutIcon), roleCode: 'dev' }, component: () => import('@/layouts/blank.vue'), children: [ { path: 'index', redirect: '/login', - meta: { title: { zh_CN: '登录页', en_US: 'Login' } }, + meta: { title: { zh_CN: '登录页', en_US: 'Login' }, roleCode: 'dev' }, }, ], }, diff --git a/src/store/modules/permission-fe.ts b/src/store/modules/permission-fe.ts index b1155ef1..c693e522 100644 --- a/src/store/modules/permission-fe.ts +++ b/src/store/modules/permission-fe.ts @@ -3,30 +3,46 @@ import cloneDeep from 'lodash/cloneDeep'; import { defineStore } from 'pinia'; -import type { RouteRecordRaw } from 'vue-router'; +import type { RouteRecordName, RouteRecordRaw } from 'vue-router'; import router, { allRoutes } from '@/router'; import { store } from '@/store'; -function filterPermissionsRouters(routes: Array, roles: Array) { - const res: Array = []; - const removeRoutes: Array = []; +function filterPermissionsRouters( + routes: Array, + roles: Array, +): { + accessedRouters: Array; + removedRoutes: Array; +} { + if (routes.length === 0) return { accessedRouters: [], removedRoutes: [] }; + const accessedRouters: Array = []; + const removedRoutes: Array = []; routes.forEach((route) => { - const children: Array = []; - route.children?.forEach((childRouter) => { - const roleCode = childRouter.meta?.roleCode || childRouter.name; - if (roles.includes(roleCode)) { - children.push(childRouter); + const roleCode = route.meta?.roleCode; + if (roles.includes(roleCode)) { + if (route.children) { + const { accessedRouters: accessedChildren, removedRoutes: removedChildren } = filterPermissionsRouters( + route.children, + roles, + ); + route.children = accessedChildren; + accessedRouters.push(route); + + if (removedChildren.length > 0) { + const removedRoute = cloneDeep(route); + removedRoute.children = removedChildren; + removedRoutes.push(removedRoute); + } } else { - removeRoutes.push(childRouter); + accessedRouters.push(route); } - }); - if (children.length > 0) { - route.children = children; - res.push(route); + } else { + const removedRoute = cloneDeep(route); + removedRoutes.push(removedRoute); } }); - return { accessedRouters: res, removeRoutes }; + return { accessedRouters, removedRoutes }; } export const usePermissionStore = defineStore('permission', { @@ -37,30 +53,65 @@ export const usePermissionStore = defineStore('permission', { }), actions: { async initRoutes(roles: Array) { - let accessedRouters = []; - - let removeRoutes: Array = []; + let accessedRouters: Array = []; + let removedRoutes: Array = []; // special token if (roles.includes('all')) { accessedRouters = allRoutes; } else { const res = filterPermissionsRouters(allRoutes, roles); accessedRouters = res.accessedRouters; - removeRoutes = res.removeRoutes; + removedRoutes = res.removedRoutes; } this.routers = cloneDeep(accessedRouters); - this.removeRoutes = removeRoutes; + this.removeRoutes = removedRoutes; - removeRoutes.forEach((item: RouteRecordRaw) => { - if (router.hasRoute(item.name)) { - router.removeRoute(item.name); + function checkNameInRoutes(name: RouteRecordName, routes: Array) { + if (routes.length === 0) return false; + for (const route of routes) { + if (route.name === name) { + return true; + } + if (route.children && route.children.length > 0) { + if (checkNameInRoutes(name, route.children)) { + return true; + } + } + } + return false; + } + function removeRoutes(routes: Array) { + for (const route of routes) { + if (route.children && route.children.length > 0) { + removeRoutes(route.children); + } + const canRemoveRoute = !checkNameInRoutes(route.name, accessedRouters); + if (canRemoveRoute && router.hasRoute(route.name)) { + router.removeRoute(route.name); + } } - }); + } + removeRoutes(removedRoutes); }, - async restore() { - this.removeRoutes.forEach((item: RouteRecordRaw) => { - router.addRoute(item); - }); + async restoreRoutes() { + function addRemovedRoutes(routes: Array, parentName?: RouteRecordName) { + for (const route of routes) { + console.log(parentName, route); + if (!router.hasRoute(route.name)) { + if (parentName) { + router.addRoute(parentName, route); + } else { + router.addRoute(route); + } + } + if (route.children && route.children.length > 0) { + addRemovedRoutes(route.children, route.name); + } + } + } + addRemovedRoutes(this.removeRoutes); + this.removeRoutes = []; + this.routers = []; }, }, }); diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts index 63b16adc..d098e7cf 100644 --- a/src/store/modules/user.ts +++ b/src/store/modules/user.ts @@ -63,7 +63,7 @@ export const useUserStore = defineStore('user', { } return { name: 'td_dev', - roles: ['UserIndex', 'DashboardBase', 'login'], // 前端权限模型使用 如果使用请配置modules/permission-fe.ts使用 + roles: ['dev'], // 前端权限模型使用 如果使用请配置modules/permission-fe.ts使用 }; }; const res = await mockRemoteUserInfo(this.token); diff --git a/src/types/router.d.ts b/src/types/router.d.ts index f995e9a9..ae88563c 100644 --- a/src/types/router.d.ts +++ b/src/types/router.d.ts @@ -15,6 +15,6 @@ declare module 'vue-router' { keepAlive?: boolean; frameSrc?: string; frameBlank?: boolean; - // roleCode?: string; // 前端 roles 控制菜单权限 + roleCode?: string; // 前端 roles 控制菜单权限 } } From 9ed5c93be24538570bcb139ed77062feb9170094 Mon Sep 17 00:00:00 2001 From: SharerMax Date: Mon, 6 Oct 2025 02:41:08 +0800 Subject: [PATCH 06/12] feat: add `CHECK_ROLE_STRICT` --- src/store/modules/permission-fe.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/store/modules/permission-fe.ts b/src/store/modules/permission-fe.ts index c693e522..8733bd82 100644 --- a/src/store/modules/permission-fe.ts +++ b/src/store/modules/permission-fe.ts @@ -8,6 +8,8 @@ import type { RouteRecordName, RouteRecordRaw } from 'vue-router'; import router, { allRoutes } from '@/router'; import { store } from '@/store'; +// 严格模式 默认所有路由不可访问 +const CHECK_ROLE_STRICT = false; function filterPermissionsRouters( routes: Array, roles: Array, @@ -20,7 +22,8 @@ function filterPermissionsRouters( const removedRoutes: Array = []; routes.forEach((route) => { const roleCode = route.meta?.roleCode; - if (roles.includes(roleCode)) { + const hasPermission = CHECK_ROLE_STRICT ? roles.includes(roleCode) : !roleCode || roles.includes(roleCode); + if (hasPermission) { if (route.children) { const { accessedRouters: accessedChildren, removedRoutes: removedChildren } = filterPermissionsRouters( route.children, From 99e04830ed8e2c9489d3f68eb5ddaa54786b0a36 Mon Sep 17 00:00:00 2001 From: SharerMax Date: Thu, 9 Oct 2025 02:22:13 +0800 Subject: [PATCH 07/12] feat: handle `whiteListRouters` --- src/store/modules/permission-fe.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/store/modules/permission-fe.ts b/src/store/modules/permission-fe.ts index 8733bd82..959464cc 100644 --- a/src/store/modules/permission-fe.ts +++ b/src/store/modules/permission-fe.ts @@ -13,6 +13,7 @@ const CHECK_ROLE_STRICT = false; function filterPermissionsRouters( routes: Array, roles: Array, + whiteListRouters: Array, ): { accessedRouters: Array; removedRoutes: Array; @@ -23,11 +24,14 @@ function filterPermissionsRouters( routes.forEach((route) => { const roleCode = route.meta?.roleCode; const hasPermission = CHECK_ROLE_STRICT ? roles.includes(roleCode) : !roleCode || roles.includes(roleCode); - if (hasPermission) { + const resolvedRoute = router.resolve(route); + const inWhiteList = whiteListRouters.includes(resolvedRoute.path); + if (hasPermission || inWhiteList) { if (route.children) { const { accessedRouters: accessedChildren, removedRoutes: removedChildren } = filterPermissionsRouters( route.children, roles, + whiteListRouters, ); route.children = accessedChildren; accessedRouters.push(route); @@ -62,7 +66,7 @@ export const usePermissionStore = defineStore('permission', { if (roles.includes('all')) { accessedRouters = allRoutes; } else { - const res = filterPermissionsRouters(allRoutes, roles); + const res = filterPermissionsRouters(allRoutes, roles, this.whiteListRouters); accessedRouters = res.accessedRouters; removedRoutes = res.removedRoutes; } From f0b8a595c5f8b61bde1f8a103172794e4e645328 Mon Sep 17 00:00:00 2001 From: SharerMax Date: Thu, 9 Oct 2025 16:07:35 +0800 Subject: [PATCH 08/12] refactor: refine `filterPermissionsRouters` --- src/store/modules/permission-fe.ts | 46 +++++++++++++++--------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/store/modules/permission-fe.ts b/src/store/modules/permission-fe.ts index 959464cc..16207d61 100644 --- a/src/store/modules/permission-fe.ts +++ b/src/store/modules/permission-fe.ts @@ -26,26 +26,26 @@ function filterPermissionsRouters( const hasPermission = CHECK_ROLE_STRICT ? roles.includes(roleCode) : !roleCode || roles.includes(roleCode); const resolvedRoute = router.resolve(route); const inWhiteList = whiteListRouters.includes(resolvedRoute.path); - if (hasPermission || inWhiteList) { - if (route.children) { - const { accessedRouters: accessedChildren, removedRoutes: removedChildren } = filterPermissionsRouters( - route.children, - roles, - whiteListRouters, - ); - route.children = accessedChildren; - accessedRouters.push(route); + if (!hasPermission && !inWhiteList) { + const removedRoute = cloneDeep(route); + removedRoutes.push(removedRoute); + return; + } + if (!route.children || route.children.length === 0) { + accessedRouters.push(route); + return; + } + const { accessedRouters: accessedChildren, removedRoutes: removedChildren } = filterPermissionsRouters( + route.children, + roles, + whiteListRouters, + ); + route.children = accessedChildren; + accessedRouters.push(route); - if (removedChildren.length > 0) { - const removedRoute = cloneDeep(route); - removedRoute.children = removedChildren; - removedRoutes.push(removedRoute); - } - } else { - accessedRouters.push(route); - } - } else { + if (removedChildren.length > 0) { const removedRoute = cloneDeep(route); + removedRoute.children = removedChildren; removedRoutes.push(removedRoute); } }); @@ -79,10 +79,11 @@ export const usePermissionStore = defineStore('permission', { if (route.name === name) { return true; } - if (route.children && route.children.length > 0) { - if (checkNameInRoutes(name, route.children)) { - return true; - } + if (!route.children || route.children.length === 0) { + return false; + } + if (checkNameInRoutes(name, route.children)) { + return true; } } return false; @@ -103,7 +104,6 @@ export const usePermissionStore = defineStore('permission', { async restoreRoutes() { function addRemovedRoutes(routes: Array, parentName?: RouteRecordName) { for (const route of routes) { - console.log(parentName, route); if (!router.hasRoute(route.name)) { if (parentName) { router.addRoute(parentName, route); From a497b92be5ab3ab4be1b14c2ff236222e53a18ad Mon Sep 17 00:00:00 2001 From: SharerMax Date: Fri, 10 Oct 2025 00:48:19 +0800 Subject: [PATCH 09/12] chore: clean code --- src/router/index.ts | 2 -- src/router/modules/homepage.ts | 2 -- src/router/modules/user.ts | 8 ++++---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/router/index.ts b/src/router/index.ts index d8e914e0..aff51fa4 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -16,13 +16,11 @@ const defaultRouterList: Array = [ { path: '/login', name: 'login', - meta: { roleCode: 'dev' }, component: () => import('@/pages/login/index.vue'), }, { path: '/', redirect: '/dashboard/base', - meta: { roleCode: 'dev' }, }, ]; // 存放固定路由 diff --git a/src/router/modules/homepage.ts b/src/router/modules/homepage.ts index 24a42588..f5557f83 100644 --- a/src/router/modules/homepage.ts +++ b/src/router/modules/homepage.ts @@ -17,7 +17,6 @@ export default [ }, icon: shallowRef(DashboardIcon), orderNo: 0, - roleCode: 'dev', }, children: [ { @@ -29,7 +28,6 @@ export default [ zh_CN: '概览仪表盘', en_US: 'Overview', }, - roleCode: 'dev', }, }, { diff --git a/src/router/modules/user.ts b/src/router/modules/user.ts index f787c35e..fd08b9a5 100644 --- a/src/router/modules/user.ts +++ b/src/router/modules/user.ts @@ -10,13 +10,13 @@ export default [ name: 'user', component: Layout, redirect: '/user/index', - meta: { title: { zh_CN: '个人中心', en_US: 'User Center' }, icon: 'user-circle', roleCode: 'dev' }, + meta: { title: { zh_CN: '个人中心', en_US: 'User Center' }, icon: 'user-circle' }, children: [ { path: 'index', name: 'UserIndex', component: () => import('@/pages/user/index.vue'), - meta: { title: { zh_CN: '个人中心', en_US: 'User Center' }, roleCode: 'dev' }, + meta: { title: { zh_CN: '个人中心', en_US: 'User Center' } }, }, ], }, @@ -24,13 +24,13 @@ export default [ path: '/loginRedirect', name: 'loginRedirect', redirect: '/login', - meta: { title: { zh_CN: '登录页', en_US: 'Login' }, icon: shallowRef(LogoutIcon), roleCode: 'dev' }, + meta: { title: { zh_CN: '登录页', en_US: 'Login' }, icon: shallowRef(LogoutIcon) }, component: () => import('@/layouts/blank.vue'), children: [ { path: 'index', redirect: '/login', - meta: { title: { zh_CN: '登录页', en_US: 'Login' }, roleCode: 'dev' }, + meta: { title: { zh_CN: '登录页', en_US: 'Login' } }, }, ], }, From cf9c31ad44126cd031f26a9b42fc17f4e2d43014 Mon Sep 17 00:00:00 2001 From: SharerMax Date: Tue, 14 Oct 2025 16:13:37 +0800 Subject: [PATCH 10/12] feat: refine 404 page define --- src/utils/route/constant.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/route/constant.ts b/src/utils/route/constant.ts index ac5e7da5..efcc07b6 100644 --- a/src/utils/route/constant.ts +++ b/src/utils/route/constant.ts @@ -4,6 +4,7 @@ export const LAYOUT = () => import('@/layouts/index.vue'); export const BLANK_LAYOUT = () => import('@/layouts/blank.vue'); export const IFRAME = () => import('@/layouts/components/FrameBlank.vue'); export const EXCEPTION_COMPONENT = () => import('@/pages/result/500/index.vue'); +export const PAGE_NOT_FOUND_COMPONENT = () => import('@/pages/result/404/index.vue'); export const PARENT_LAYOUT = () => new Promise((resolve) => { resolve({ name: 'ParentLayout' }); @@ -12,5 +13,5 @@ export const PARENT_LAYOUT = () => export const PAGE_NOT_FOUND_ROUTE: RouteRecordRaw = { path: '/:pathMatch(.*)*', name: '404Page', - redirect: '/result/404', + component: PAGE_NOT_FOUND_COMPONENT, }; From 9e40175ce4d7f5a04535ba6be82625de94efcdd5 Mon Sep 17 00:00:00 2001 From: SharerMax Date: Tue, 14 Oct 2025 16:22:52 +0800 Subject: [PATCH 11/12] refactor: refine restore routes --- src/permission.ts | 30 ++++---------- src/router/index.ts | 8 ++-- src/router/modules/homepage.ts | 4 ++ src/store/modules/permission-fe.ts | 64 ++++++------------------------ src/store/modules/permission.ts | 20 ++++++---- 5 files changed, 40 insertions(+), 86 deletions(-) diff --git a/src/permission.ts b/src/permission.ts index 73018c73..55a355ff 100644 --- a/src/permission.ts +++ b/src/permission.ts @@ -2,9 +2,9 @@ import 'nprogress/nprogress.css'; // progress bar style import NProgress from 'nprogress'; // progress bar import { MessagePlugin } from 'tdesign-vue-next'; -import type { RouteRecordRaw } from 'vue-router'; -import router from '@/router'; +// import type { RouteRecordRaw } from 'vue-router'; +import router, { whiteListRoutePath } from '@/router'; import { getPermissionStore, useUserStore } from '@/store'; import { PAGE_NOT_FOUND_ROUTE } from '@/utils/route/constant'; @@ -13,9 +13,6 @@ NProgress.configure({ showSpinner: false }); router.beforeEach(async (to, from, next) => { NProgress.start(); - const permissionStore = getPermissionStore(); - const { whiteListRouters } = permissionStore; - const userStore = useUserStore(); if (userStore.token) { @@ -25,14 +22,12 @@ router.beforeEach(async (to, from, next) => { } try { await userStore.getUserInfo(); + const permissionStore = getPermissionStore(); // 后端权限控制 const { asyncRoutes } = permissionStore; if (asyncRoutes && asyncRoutes.length === 0) { - const routeList = await permissionStore.buildAsyncRoutes(); - routeList.forEach((item: RouteRecordRaw) => { - router.addRoute(item); - }); + await permissionStore.buildAsyncRoutes(); if (to.name === PAGE_NOT_FOUND_ROUTE.name) { // 动态添加路由后,此处应当重定向到fullPath,否则会加载404页面内容 @@ -45,22 +40,14 @@ router.beforeEach(async (to, from, next) => { } // 前端权限控制 - // const permissionStore = getPermissionStore(); // const { routers } = permissionStore; // if (routers.length === 0) { // await permissionStore.initRoutes(userStore.roles); + // next({ ...to, replace: true }); + // return; // } - if (router.hasRoute(to.name)) { - next(); - } else { - // 动态添加404 page - // router.addRoute(PAGE_NOT_FOUND_ROUTE); - // next(to.fullPath); - - // 不添加404 page,重定向到首页 - next({ path: '/' }); - } + next(); } catch (error) { MessagePlugin.error(error.message); next({ @@ -70,8 +57,7 @@ router.beforeEach(async (to, from, next) => { NProgress.done(); } } else { - /* white list router */ - if (whiteListRouters.includes(to.path)) { + if (whiteListRoutePath.includes(to.path)) { next(); } else { next({ diff --git a/src/router/index.ts b/src/router/index.ts index aff51fa4..d64d4552 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -18,16 +18,14 @@ const defaultRouterList: Array = [ name: 'login', component: () => import('@/pages/login/index.vue'), }, - { - path: '/', - redirect: '/dashboard/base', - }, ]; + // 存放固定路由 export const homepageRouterList: Array = mapModuleRouterList(homepageModules); export const fixedRouterList: Array = mapModuleRouterList(fixedModules); export const allRoutes = [...homepageRouterList, ...fixedRouterList, ...defaultRouterList]; +export const whiteListRoutePath = uniq(defaultRouterList.map((item) => item.path)); // 固定路由模块转换为路由 export function mapModuleRouterList(modules: Record): Array { @@ -83,7 +81,7 @@ export const getActive = (maxLevel = 3): string => { const router = createRouter({ history: createWebHistory(env === 'site' ? '/starter/vue-next/' : import.meta.env.VITE_BASE_URL), - routes: allRoutes, + routes: defaultRouterList, scrollBehavior() { return { el: '#app', diff --git a/src/router/modules/homepage.ts b/src/router/modules/homepage.ts index f5557f83..12f71cf2 100644 --- a/src/router/modules/homepage.ts +++ b/src/router/modules/homepage.ts @@ -5,6 +5,10 @@ import type { RouteRecordRaw } from 'vue-router'; import Layout from '@/layouts/index.vue'; export default [ + { + path: '/', + redirect: '/dashboard/base', + }, { path: '/dashboard', component: Layout, diff --git a/src/store/modules/permission-fe.ts b/src/store/modules/permission-fe.ts index 16207d61..9c3e53ff 100644 --- a/src/store/modules/permission-fe.ts +++ b/src/store/modules/permission-fe.ts @@ -3,9 +3,9 @@ import cloneDeep from 'lodash/cloneDeep'; import { defineStore } from 'pinia'; -import type { RouteRecordName, RouteRecordRaw } from 'vue-router'; +import type { RouteRecordRaw } from 'vue-router'; -import router, { allRoutes } from '@/router'; +import router, { fixedRouterList, homepageRouterList } from '@/router'; import { store } from '@/store'; // 严格模式 默认所有路由不可访问 @@ -13,7 +13,6 @@ const CHECK_ROLE_STRICT = false; function filterPermissionsRouters( routes: Array, roles: Array, - whiteListRouters: Array, ): { accessedRouters: Array; removedRoutes: Array; @@ -24,9 +23,7 @@ function filterPermissionsRouters( routes.forEach((route) => { const roleCode = route.meta?.roleCode; const hasPermission = CHECK_ROLE_STRICT ? roles.includes(roleCode) : !roleCode || roles.includes(roleCode); - const resolvedRoute = router.resolve(route); - const inWhiteList = whiteListRouters.includes(resolvedRoute.path); - if (!hasPermission && !inWhiteList) { + if (!hasPermission) { const removedRoute = cloneDeep(route); removedRoutes.push(removedRoute); return; @@ -38,7 +35,6 @@ function filterPermissionsRouters( const { accessedRouters: accessedChildren, removedRoutes: removedChildren } = filterPermissionsRouters( route.children, roles, - whiteListRouters, ); route.children = accessedChildren; accessedRouters.push(route); @@ -52,9 +48,9 @@ function filterPermissionsRouters( return { accessedRouters, removedRoutes }; } +const remvoeRouteFnSet = new Set<() => void>(); export const usePermissionStore = defineStore('permission', { state: () => ({ - whiteListRouters: ['/login'], routers: [], removeRoutes: [], }), @@ -64,59 +60,23 @@ export const usePermissionStore = defineStore('permission', { let removedRoutes: Array = []; // special token if (roles.includes('all')) { - accessedRouters = allRoutes; + accessedRouters = [...homepageRouterList, ...fixedRouterList]; } else { - const res = filterPermissionsRouters(allRoutes, roles, this.whiteListRouters); + const res = filterPermissionsRouters([...homepageRouterList, ...fixedRouterList], roles); accessedRouters = res.accessedRouters; removedRoutes = res.removedRoutes; } + for (const route of accessedRouters) { + remvoeRouteFnSet.add(router.addRoute(route)); + } this.routers = cloneDeep(accessedRouters); this.removeRoutes = removedRoutes; - - function checkNameInRoutes(name: RouteRecordName, routes: Array) { - if (routes.length === 0) return false; - for (const route of routes) { - if (route.name === name) { - return true; - } - if (!route.children || route.children.length === 0) { - return false; - } - if (checkNameInRoutes(name, route.children)) { - return true; - } - } - return false; - } - function removeRoutes(routes: Array) { - for (const route of routes) { - if (route.children && route.children.length > 0) { - removeRoutes(route.children); - } - const canRemoveRoute = !checkNameInRoutes(route.name, accessedRouters); - if (canRemoveRoute && router.hasRoute(route.name)) { - router.removeRoute(route.name); - } - } - } - removeRoutes(removedRoutes); }, async restoreRoutes() { - function addRemovedRoutes(routes: Array, parentName?: RouteRecordName) { - for (const route of routes) { - if (!router.hasRoute(route.name)) { - if (parentName) { - router.addRoute(parentName, route); - } else { - router.addRoute(route); - } - } - if (route.children && route.children.length > 0) { - addRemovedRoutes(route.children, route.name); - } - } + for (const removeRoute of remvoeRouteFnSet) { + removeRoute(); } - addRemovedRoutes(this.removeRoutes); + remvoeRouteFnSet.clear(); this.removeRoutes = []; this.routers = []; }, diff --git a/src/store/modules/permission.ts b/src/store/modules/permission.ts index 5398030c..cf085c72 100644 --- a/src/store/modules/permission.ts +++ b/src/store/modules/permission.ts @@ -1,6 +1,5 @@ import cloneDeep from 'lodash/cloneDeep'; import { defineStore } from 'pinia'; -import type { RouteRecordRaw } from 'vue-router'; import type { RouteItem } from '@/api/model/permissionModel'; import { getMenuList } from '@/api/permission'; @@ -8,6 +7,8 @@ import router, { fixedRouterList, homepageRouterList } from '@/router'; import { store } from '@/store'; import { transformObjectToRoute } from '@/utils/route'; +const remvoeRouteFnSet = new Set<() => void>(); + export const usePermissionStore = defineStore('permission', { state: () => ({ whiteListRouters: ['/login'], @@ -19,8 +20,12 @@ export const usePermissionStore = defineStore('permission', { async initRoutes() { const accessedRouters = this.asyncRoutes; + const allRoutes = [...homepageRouterList, ...fixedRouterList, ...accessedRouters]; + for (const route of allRoutes) { + remvoeRouteFnSet.add(router.addRoute(route)); + } // 在菜单展示全部路由 - this.routers = cloneDeep([...homepageRouterList, ...accessedRouters, ...fixedRouterList]); + this.routers = cloneDeep(allRoutes); // 在菜单只展示动态路由和首页 // this.routers = [...homepageRouterList, ...accessedRouters]; // 在菜单只展示动态路由 @@ -39,11 +44,12 @@ export const usePermissionStore = defineStore('permission', { }, async restoreRoutes() { // 不需要在此额外调用initRoutes更新侧边导肮内容,在登录后asyncRoutes为空会调用 - this.asyncRoutes.forEach((item: RouteRecordRaw) => { - if (item.name) { - router.removeRoute(item.name); - } - }); + for (const removeRoute of remvoeRouteFnSet) { + removeRoute(); + } + remvoeRouteFnSet.clear(); + this.routers = []; + this.removeRoutes = []; this.asyncRoutes = []; }, }, From 998dcb0765ae3d219b40c5a2e33c8ef044e945af Mon Sep 17 00:00:00 2001 From: SharerMax Date: Tue, 14 Oct 2025 16:30:06 +0800 Subject: [PATCH 12/12] chore: typo --- src/store/modules/permission-fe.ts | 8 ++++---- src/store/modules/permission.ts | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/store/modules/permission-fe.ts b/src/store/modules/permission-fe.ts index 9c3e53ff..4f1fd202 100644 --- a/src/store/modules/permission-fe.ts +++ b/src/store/modules/permission-fe.ts @@ -48,7 +48,7 @@ function filterPermissionsRouters( return { accessedRouters, removedRoutes }; } -const remvoeRouteFnSet = new Set<() => void>(); +const removeRouteFnSet = new Set<() => void>(); export const usePermissionStore = defineStore('permission', { state: () => ({ routers: [], @@ -67,16 +67,16 @@ export const usePermissionStore = defineStore('permission', { removedRoutes = res.removedRoutes; } for (const route of accessedRouters) { - remvoeRouteFnSet.add(router.addRoute(route)); + removeRouteFnSet.add(router.addRoute(route)); } this.routers = cloneDeep(accessedRouters); this.removeRoutes = removedRoutes; }, async restoreRoutes() { - for (const removeRoute of remvoeRouteFnSet) { + for (const removeRoute of removeRouteFnSet) { removeRoute(); } - remvoeRouteFnSet.clear(); + removeRouteFnSet.clear(); this.removeRoutes = []; this.routers = []; }, diff --git a/src/store/modules/permission.ts b/src/store/modules/permission.ts index cf085c72..64520ea8 100644 --- a/src/store/modules/permission.ts +++ b/src/store/modules/permission.ts @@ -7,7 +7,7 @@ import router, { fixedRouterList, homepageRouterList } from '@/router'; import { store } from '@/store'; import { transformObjectToRoute } from '@/utils/route'; -const remvoeRouteFnSet = new Set<() => void>(); +const removeRouteFnSet = new Set<() => void>(); export const usePermissionStore = defineStore('permission', { state: () => ({ @@ -22,7 +22,7 @@ export const usePermissionStore = defineStore('permission', { const allRoutes = [...homepageRouterList, ...fixedRouterList, ...accessedRouters]; for (const route of allRoutes) { - remvoeRouteFnSet.add(router.addRoute(route)); + removeRouteFnSet.add(router.addRoute(route)); } // 在菜单展示全部路由 this.routers = cloneDeep(allRoutes); @@ -44,10 +44,10 @@ export const usePermissionStore = defineStore('permission', { }, async restoreRoutes() { // 不需要在此额外调用initRoutes更新侧边导肮内容,在登录后asyncRoutes为空会调用 - for (const removeRoute of remvoeRouteFnSet) { + for (const removeRoute of removeRouteFnSet) { removeRoute(); } - remvoeRouteFnSet.clear(); + removeRouteFnSet.clear(); this.routers = []; this.removeRoutes = []; this.asyncRoutes = [];