import { createWebHistory, createRouter, type RouteRecordRaw, } from "vue-router"; import { useUserStore } from "@/store"; import { getRouteMenus } from "@/api"; import TokenManager from "@/utils/storage"; import Login from "@/pages/Login/index.vue"; import HomeView from "@/pages/Layout/index.vue"; const tokenManager = TokenManager.getInstance(); // 基础路由(不需要权限验证) const constantRoutes: RouteRecordRaw[] = [ { path: "/login", name: "Login", component: Login, meta: { title: "登录", requiresAuth: false, }, }, ]; // 动态路由(需要权限验证) const asyncRoutes: RouteRecordRaw[] = [ { path: "/", name: "Layout", component: HomeView, // redirect: '/home', meta: { requiresAuth: true, }, children: [] as RouteRecordRaw[], }, ]; const router = createRouter({ history: createWebHistory(), routes: [...constantRoutes, ...asyncRoutes], }); // 白名单路由(不需要登录即可访问) const whiteList = ["/login"]; // 1. 预先加载所有可能的页面组件 // 这里的路径模式要覆盖到你所有的业务组件 const modules = import.meta.glob("@/pages/**/*.vue"); const loadComponent = (componentPath: string) => { if (!componentPath) return null; // 统一路径格式处理 let fullPath = ""; if (componentPath.startsWith("@/")) { fullPath = componentPath; } else if (componentPath.includes("/")) { // 补全路径,确保以 @/pages 开头 fullPath = componentPath.startsWith("pages/") ? `@/${componentPath}` : `@/pages/${componentPath}/index.vue`; } else { // 补全 index.vue fullPath = `@/pages/${componentPath}/index.vue`; } // 重点:将 @/ 转换为 /src/,因为 glob 默认生成的 key 是相对于项目根目录的 const key = fullPath.replace("@/", "/src/"); // 从 modules 中查找对应的导入函数 if (modules[key]) { return modules[key]; } else { console.error(`未找到组件文件: ${key}. 请检查路径或大小写。`); return null; } }; // 将后端返回的路由数据转换为 Vue Router 路由 const transformRoutes = ( routes: any[], parentCode: string = "" ): RouteRecordRaw[] => { console.log("transformRoutes", routes); return routes.flatMap((route) => { const fullCode = parentCode ? `${parentCode}/${route.code}` : route.code; // 如果当前路由有子路由,说明它是一个路由前缀,不需要组件 if (route.children && route.children.length > 0) { const childRoutes = transformRoutes(route.children, fullCode); if (route.code) { // 创建一个父路由,将子路由作为其 children const parentRoute: RouteRecordRaw = { path: `/${fullCode}`, name: route.code, meta: { title: route.name, icon: route.icon, ...route.meta, }, children: childRoutes, }; return parentRoute; } else { return childRoutes; } } else { // 叶子节点才需要组件和路由配置 const component = fullCode ? loadComponent(fullCode) : undefined; const routeRecord: any = { path: route.code, name: route.code, meta: { title: route.name, icon: route.icon, ...route.meta, }, }; if (component) { routeRecord.component = component; } return routeRecord as RouteRecordRaw; } }); }; // 添加动态路由 const addDynamicRoutes = async () => { const userStore = useUserStore(); // 如果路由已加载,直接返回 if (userStore.isRoutesLoaded) { return; } try { // 从后端获取路由菜单数据 (这边需要区分 后台的菜单 和用户的菜单) let allRoutes:any[] = []; if (userStore.isBackendUser) { // const backendResponse = await getRouteMenus(); const backendResponse = [ { "name": "字典管理", "code": "dict", "icon": "OfficeBuilding", "metadata": null, "children": null }, { "name": "组织管理", "code": "origanization", "icon": "OfficeBuilding", "metadata": null, "children": null }, { "name": "人员管理", "code": "personnel", "icon": "OfficeBuilding", "metadata": null, "children": null }, { "name": "权限管理", "code": "permission", "icon": "OfficeBuilding", "metadata": null, "children": null }, { "name": "流程管理", "code": "flow", "icon": "OfficeBuilding", "metadata": null, "children": null } ]; allRoutes = [ { code: "stage", name: "管理中心", icon: "", meta:{ title:'管理中心' }, children: backendResponse, }, ]; } else { // TODO:获取用户端的数据信息 // response = await getUserMenus(); allRoutes = []; } if (allRoutes) { // 转换路由数据 const dynamicRoutes = transformRoutes( Array.isArray(allRoutes) ? allRoutes : [allRoutes] ); // 将动态路由添加到 Layout 的 children 中 const layoutRoute = router .getRoutes() .find((route) => route.name === "Layout"); if (layoutRoute) { dynamicRoutes.forEach((route) => { router.addRoute("Layout", route); }); } else { // 如果找不到 Layout 路由,直接添加到根路由 dynamicRoutes.forEach((route) => { router.addRoute(route); }); } // 保存路由数据到 store userStore.setRoutes(dynamicRoutes); // 标记路由已加载 userStore.isRoutesLoaded = true; } } catch (error) { // 如果获取路由失败,清除用户数据并跳转到登录页 userStore.clearUserData(); router.push("/login"); } }; // 路由导航守卫 router.beforeEach(async (to, _from, next) => { const userStore = useUserStore(); const accessToken = tokenManager.getToken("accessToken"); // 获取 token const token = accessToken || userStore.token; // 如果已登录,更新 store 中的 token if (token) { userStore.setToken(token); } // 判断是否在白名单中 if (whiteList.includes(to.path)) { // 如果在白名单中且已登录,重定向到首页 if (token) { next("/"); } else { next(); } return; } // 需要登录验证 if (!token) { // 未登录,重定向到登录页 next({ path: "/login", query: { redirect: to.fullPath }, // 保存当前路径,登录后可以跳转回来 }); return; } // 已登录,检查路由是否已加载 if (!userStore.isRoutesLoaded) { try { // 加载动态路由 await addDynamicRoutes(); // 路由加载完成后,重新导航到目标路由 next({ ...to, replace: true }); } catch (error) { console.error("Route loading error:", error); next("/login"); } } else { // 路由已加载,直接放行 next(); } }); export default router;