import type { NavigationGuardNext, RouteLocationNormalized, Router } from 'vue-router'; import type { RouteKey, RoutePath } from '@elegant-router/types'; import { useAuthStore } from '@/store/modules/auth'; import { useRouteStore } from '@/store/modules/route'; import { localStg } from '@/utils/storage'; export function createPermissionGuard(router: Router) { router.beforeEach(async (to, from, next) => { const pass = await createAuthRouteGuard(to, from, next); if (!pass) return; // 1. route with href if (to.meta.href) { window.open(to.meta.href, '_blank'); next({ path: from.fullPath, replace: true, query: from.query, hash: to.hash }); } const authStore = useAuthStore(); const isLogin = Boolean(localStg.get('token')); const needLogin = !to.meta.constant; const routeRoles = to.meta.roles || []; const rootRoute: RouteKey = 'root'; const loginRoute: RouteKey = 'login'; const noPermissionRoute: RouteKey = '403'; // check whether the user has permission to access the route // 1. if the route's "roles" is empty, then it is allowed to access // 2. if the user is super admin, then it is allowed to access // 3. if the user's role is included in the route's "roles", then it is allowed to access const SUPER_ADMIN = 'R_SUPER'; const hasPermission = !routeRoles.length || authStore.userInfo.roles.includes(SUPER_ADMIN) || authStore.userInfo.roles.some(role => routeRoles.includes(role)); const strategicPatterns: Common.StrategicPattern[] = [ // 1. if it is login route when logged in, change to the root page { condition: isLogin && to.name === loginRoute, callback: () => { next({ name: rootRoute }); } }, // 2. if is is constant route, then it is allowed to access directly { condition: !needLogin, callback: () => { next(); } }, // 3. if the route need login but the user is not logged in, then switch to the login page { condition: !isLogin && needLogin, callback: () => { next({ name: loginRoute, query: { redirect: to.fullPath } }); } }, // 4. if the user is logged in and has permission, then it is allowed to access { condition: isLogin && needLogin && hasPermission, callback: () => { next(); } }, // 5. if the user is logged in but does not have permission, then switch to the 403 page { condition: isLogin && needLogin && !hasPermission, callback: () => { next({ name: noPermissionRoute }); } } ]; strategicPatterns.some(({ condition, callback }) => { if (condition) { callback(); } return condition; }); }); } async function createAuthRouteGuard( to: RouteLocationNormalized, _from: RouteLocationNormalized, next: NavigationGuardNext ) { const notFoundRoute: RouteKey = 'not-found'; const isNotFoundRoute = to.name === notFoundRoute; // 1. If the route is the constant route but is not the "not-found" route, then it is allowed to access. if (to.meta.constant && !isNotFoundRoute) { return true; } // 2. If the auth route is initialized but is not the "not-found" route, then it is allowed to access. const routeStore = useRouteStore(); if (routeStore.isInitAuthRoute && !isNotFoundRoute) { return true; } // 3. If the route is initialized, check whether the route exists. if (routeStore.isInitAuthRoute && isNotFoundRoute) { const exist = await routeStore.getIsAuthRouteExist(to.path as RoutePath); if (exist) { const noPermissionRoute: RouteKey = '403'; next({ name: noPermissionRoute }); return false; } return true; } // 4. If the user is not logged in, then redirect to the login page. const isLogin = Boolean(localStg.get('token')); if (!isLogin) { const loginRoute: RouteKey = 'login'; const redirect = to.fullPath; next({ name: loginRoute, query: { redirect } }); return false; } // 5. init auth route await routeStore.initAuthRoute(); // 6. the route is caught by the "not-found" route because the auto route is not initialized. after the auto route is initialized, redirect to the original route. if (isNotFoundRoute) { const rootRoute: RouteKey = 'root'; const path = to.redirectedFrom?.name === rootRoute ? '/' : to.fullPath; next({ path, replace: true, query: to.query, hash: to.hash }); return false; } return true; }