Files
cn-rdms-web/src/router/guard/route.ts
hongawen 4122dfa50d feat(product): 新增产品管理模块与字典组件功能
- 新增产品管理相关路由和页面(dashboard、list、requirement、setting)
- 实现产品基础信息编辑弹窗组件(base-info-dialog.vue)
- 添加运行时字典功能(dict-select、dict-text、dict-tag组件)
- 集成字典管理store和API调用
- 规范ID类型定义为string避免精度丢失问题
- 完善国际化资源文件支持中英文对照
- 新增对象上下文业务域入口页导航实现说明
- 添加Vue DevTools浮动入口注释说明
- 统一权限控制支持全局和对象作用域区分
- 规范分页查询参数类型定义与使用方式
2026-04-23 09:05:55 +08:00

216 lines
5.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type {
LocationQueryRaw,
NavigationGuardNext,
RouteLocationNormalized,
RouteLocationRaw,
Router
} from 'vue-router';
import type { RouteKey, RoutePath } from '@elegant-router/types';
import { useAuthStore } from '@/store/modules/auth';
import { useObjectContextStore } from '@/store/modules/object-context';
import { useRouteStore } from '@/store/modules/route';
import { localStg } from '@/utils/storage';
import { getRouteName } from '@/router/elegant/transform';
/**
* 创建全局路由守卫
*
* @param router 路由实例
*/
export function createRouteGuard(router: Router) {
router.beforeEach(async (to, from, next) => {
const location = await initRoute(to);
if (location) {
next(location);
return;
}
const authStore = useAuthStore();
const rootRoute: RouteKey = 'root';
const loginRoute: RouteKey = 'login';
const noAuthorizationRoute: RouteKey = '403';
const isLogin = Boolean(localStg.get('token'));
const needLogin = !to.meta.constant;
const routeRoles = to.meta.roles || [];
const hasRole = authStore.userInfo.roles.some(role => routeRoles.includes(role));
const hasAuth = authStore.isStaticSuper || !routeRoles.length || hasRole;
// 已登录状态下访问登录页时,直接跳到首页
if (to.name === loginRoute && isLogin) {
const redirect = to.query?.redirect as string;
if (redirect) {
next({ path: redirect });
} else {
next({ name: rootRoute });
}
return;
}
// 不需要登录的路由允许直接访问
if (!needLogin) {
const objectContextLocation = await handleObjectContextSwitch(to);
if (objectContextLocation) {
next(objectContextLocation);
return;
}
handleRouteSwitch(to, from, next);
return;
}
// 需要登录但当前未登录时,跳转到登录页
if (!isLogin) {
next({ name: loginRoute, query: { redirect: to.fullPath } });
return;
}
// 已登录但没有权限时,跳转到 403 页面
if (!hasAuth) {
next({ name: noAuthorizationRoute });
return;
}
// 正常放行
const objectContextLocation = await handleObjectContextSwitch(to);
if (objectContextLocation) {
next(objectContextLocation);
return;
}
handleRouteSwitch(to, from, next);
});
}
/**
* 初始化路由
*
* @param to 目标路由
*/
async function initRoute(to: RouteLocationNormalized): Promise<RouteLocationRaw | null> {
const routeStore = useRouteStore();
const notFoundRoute: RouteKey = 'not-found';
const isNotFoundRoute = to.name === notFoundRoute;
// 常量路由还没初始化时,先初始化常量路由
if (!routeStore.isInitConstantRoute) {
await routeStore.initConstantRoute();
// 初始化前可能先被 not-found 捕获,初始化完成后重新回到原目标路由
const path = to.fullPath;
const location: RouteLocationRaw = {
path,
replace: true,
query: to.query,
hash: to.hash
};
return location;
}
const isLogin = Boolean(localStg.get('token'));
if (!isLogin) {
// 未登录时,如果访问的是常量路由且不是 not-found则允许访问
if (to.meta.constant && !isNotFoundRoute) {
routeStore.onRouteSwitchWhenNotLoggedIn();
return null;
}
// 未登录时跳到登录页
const loginRoute: RouteKey = 'login';
const query = getRouteQueryOfLoginRoute(to, routeStore.routeHome);
const location: RouteLocationRaw = {
name: loginRoute,
query
};
return location;
}
if (!routeStore.isInitAuthRoute) {
// 初始化权限路由
await routeStore.initAuthRoute();
// 初始化前可能先被 not-found 捕获,初始化完成后重新回到原目标路由
if (isNotFoundRoute) {
const rootRoute: RouteKey = 'root';
const path = to.redirectedFrom?.name === rootRoute ? '/' : to.fullPath;
const location: RouteLocationRaw = {
path,
replace: true,
query: to.query,
hash: to.hash
};
return location;
}
}
routeStore.onRouteSwitchWhenLoggedIn();
// 权限路由已初始化,且当前不是 not-found直接放行
if (!isNotFoundRoute) {
return null;
}
// 如果被 not-found 捕获,再判断是否其实是“存在但无权限”的路由
const exist = await routeStore.getIsAuthRouteExist(to.path as RoutePath);
const noPermissionRoute: RouteKey = '403';
if (exist) {
const location: RouteLocationRaw = {
name: noPermissionRoute
};
return location;
}
return null;
}
function handleRouteSwitch(to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) {
// 带 href 的路由直接新开窗口
if (to.meta.href) {
window.open(to.meta.href, '_blank');
next({ path: from.fullPath, replace: true, query: from.query, hash: from.hash });
return;
}
next();
}
async function handleObjectContextSwitch(to: RouteLocationNormalized) {
const objectContextStore = useObjectContextStore();
return objectContextStore.ensureContextByRoute(to);
}
function getRouteQueryOfLoginRoute(to: RouteLocationNormalized, routeHome: RouteKey) {
const loginRoute: RouteKey = 'login';
const redirect = to.fullPath;
const [redirectPath, redirectQuery] = redirect.split('?');
const redirectName = getRouteName(redirectPath as RoutePath);
const isRedirectHome = routeHome === redirectName;
const query: LocationQueryRaw = to.name !== loginRoute && !isRedirectHome ? { redirect } : {};
if (isRedirectHome && redirectQuery) {
query.redirect = `/?${redirectQuery}`;
}
return query;
}