diff --git a/src/assets/icons/403.svg b/src/assets/icons/403.svg new file mode 100644 index 00000000..0660eff5 --- /dev/null +++ b/src/assets/icons/403.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/router/index.ts b/src/router/index.ts index 441e620e..3533de37 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -90,6 +90,11 @@ router.beforeEach(async (to, from, next) => { removeRoutes.push(router.addRoute(route as RouteRecordRaw)) }) } + routeStore.flatRoutesUnallowed.forEach((route) => { + if (!/^(https?:|mailto:|tel:)/.test(route.path)) { + removeRoutes.push(router.addRoute(route as RouteRecordRaw)) + } + }) routeStore.setCurrentRemoveRoutes(removeRoutes) // 动态路由生成并注册后,重新进入当前路由 next({ diff --git a/src/store/modules/route.ts b/src/store/modules/route.ts index 23d282fd..54bce584 100644 --- a/src/store/modules/route.ts +++ b/src/store/modules/route.ts @@ -16,6 +16,7 @@ const useRouteStore = defineStore( const isGenerate = ref(false) const routes = ref([]) + const routesUnallowed = ref([]) const fileSystemRoutes = ref([]) const currentRemoveRoutes = ref([]) @@ -100,6 +101,32 @@ const useRouteStore = defineStore( } return returnRoutes }) + const flatRoutesUnallowed = computed(() => { + const twoLevelRoutes: RouteRecordRaw[] = [] + if (settingsStore.settings.app.routeBaseOn !== 'filesystem') { + if (routesUnallowed.value) { + routesUnallowed.value.forEach((item) => { + twoLevelRoutes.push(...cloneDeep(item.children) as RouteRecordRaw[]) + }) + twoLevelRoutes.forEach(item => flatAsyncRoutes(item)) + } + } + else { + twoLevelRoutes.push(...cloneDeep(routesUnallowed.value) as RouteRecordRaw[]) + } + const returnRoutes: RouteRecordRaw[] = [] + twoLevelRoutes.forEach((item) => { + if (item.children) { + item.children.forEach((child) => { + const tmpChild = cloneDeep(child) + tmpChild.path = resolveRoutePath(item.path, tmpChild.path) + tmpChild.component = () => import('@/views/403.vue') + returnRoutes.push(tmpChild) + }) + } + }) + return returnRoutes + }) const flatSystemRoutes = computed(() => { const routes = [...systemRoutes] routes.forEach(item => flatAsyncRoutes(item)) @@ -144,20 +171,40 @@ const useRouteStore = defineStore( }) return res } + // 根据权限过滤路由(过滤出没有权限的路由) + function filterAsyncRoutesNoAuth(routes: T, permissions: string[]): T { + const res: any = [] + routes.forEach((route) => { + const tmpRoute = cloneDeep(route) + if (tmpRoute.children) { + tmpRoute.children = filterAsyncRoutesNoAuth(tmpRoute.children, permissions) + tmpRoute.children.length && res.push(tmpRoute) + } + else { + if (!hasPermission(permissions, route)) { + res.push(tmpRoute) + } + } + }) + return res + } // 根据权限动态生成路由(前端生成) async function generateRoutesAtFront(asyncRoutes: Route.recordMainRaw[]) { - let accessedRoutes + let allowedRoutes + let unallowedRoutes: Route.recordMainRaw[] = [] // 如果权限功能开启,则需要对路由数据进行筛选过滤 if (settingsStore.settings.app.enablePermission) { const permissions = await userStore.getPermissions() - accessedRoutes = filterAsyncRoutes(asyncRoutes, permissions) + allowedRoutes = filterAsyncRoutes(asyncRoutes, permissions) + unallowedRoutes = filterAsyncRoutesNoAuth(asyncRoutes, permissions) } else { - accessedRoutes = cloneDeep(asyncRoutes) + allowedRoutes = cloneDeep(asyncRoutes) } // 设置 routes 数据 isGenerate.value = true - routes.value = accessedRoutes.filter(item => item.children?.length !== 0) as any + routes.value = allowedRoutes.filter(item => item.children?.length !== 0) as any + routesUnallowed.value = unallowedRoutes as any } // 格式化后端路由数据 function formatBackRoutes(routes: any, views = import.meta.glob('../../views/**/*.vue')): Route.recordMainRaw[] { @@ -183,34 +230,40 @@ const useRouteStore = defineStore( baseURL: '/mock/', }).then(async (res) => { const asyncRoutes = formatBackRoutes(res.data) - let accessedRoutes + let allowedRoutes + let unallowedRoutes: Route.recordMainRaw[] = [] // 如果权限功能开启,则需要对路由数据进行筛选过滤 if (settingsStore.settings.app.enablePermission) { const permissions = await userStore.getPermissions() - accessedRoutes = filterAsyncRoutes(asyncRoutes, permissions) + allowedRoutes = filterAsyncRoutes(asyncRoutes, permissions) + unallowedRoutes = filterAsyncRoutesNoAuth(asyncRoutes, permissions) } else { - accessedRoutes = cloneDeep(asyncRoutes) + allowedRoutes = cloneDeep(asyncRoutes) } // 设置 routes 数据 isGenerate.value = true - routes.value = accessedRoutes.filter(item => item.children.length !== 0) as any + routes.value = allowedRoutes.filter(item => item.children.length !== 0) as any + routesUnallowed.value = unallowedRoutes as any }).catch(() => {}) } // 根据权限动态生成路由(文件系统生成) async function generateRoutesAtFilesystem(asyncRoutes: RouteRecordRaw[]) { - let accessedRoutes + let allowedRoutes + let unallowedRoutes: RouteRecordRaw[] = [] // 如果权限功能开启,则需要对路由数据进行筛选过滤 if (settingsStore.settings.app.enablePermission) { const permissions = await userStore.getPermissions() - accessedRoutes = filterAsyncRoutes(asyncRoutes, permissions) + allowedRoutes = filterAsyncRoutes(asyncRoutes, permissions) + unallowedRoutes = filterAsyncRoutesNoAuth(asyncRoutes, permissions) } else { - accessedRoutes = cloneDeep(asyncRoutes) + allowedRoutes = cloneDeep(asyncRoutes) } // 设置 routes 数据 isGenerate.value = true - fileSystemRoutes.value = accessedRoutes.filter(item => item.children?.length !== 0) as any + fileSystemRoutes.value = allowedRoutes.filter(item => item.children?.length !== 0) as any + routesUnallowed.value = unallowedRoutes as any } // 记录 accessRoutes 路由,用于登出时删除路由 function setCurrentRemoveRoutes(routes: Function[]) { @@ -231,6 +284,7 @@ const useRouteStore = defineStore( routes, fileSystemRoutes, flatRoutes, + flatRoutesUnallowed, flatSystemRoutes, generateRoutesAtFront, generateRoutesAtBack, diff --git a/src/views/403.vue b/src/views/403.vue new file mode 100644 index 00000000..1652375c --- /dev/null +++ b/src/views/403.vue @@ -0,0 +1,76 @@ + +meta: + enabled: false + + + + + + +