264 lines
7.1 KiB
JavaScript
264 lines
7.1 KiB
JavaScript
import { createRouter, createWebHashHistory } from "vue-router";
|
|
import { convertMenusToRoutes } from "./dynamicRoutes";
|
|
|
|
// 静态子路由:需要在 Main 框架内显示的页面
|
|
const staticMainChildren = [
|
|
{
|
|
path: "/home",
|
|
name: "Home",
|
|
component: () => import("@/views/home/index.vue"),
|
|
meta: { requiresAuth: true, title: "首页" }
|
|
},
|
|
{
|
|
path: "/user/userProfile",
|
|
name: "userProfile",
|
|
component: () => import("@/views/user/userProfile.vue"),
|
|
meta: { requiresAuth: true, title: "用户中心" }
|
|
},
|
|
{
|
|
path: "/system/email",
|
|
name: "SystemEmail",
|
|
component: () => import("@/views/system/email/index.vue"),
|
|
meta: { requiresAuth: true, title: "邮箱管理" }
|
|
},
|
|
// 统一认证中心:接入应用(OIDC Client)注册管理
|
|
{
|
|
path: "/system/authClient",
|
|
name: "AuthClientManage",
|
|
component: () => import("@/views/system/authClient/index.vue"),
|
|
meta: { requiresAuth: true, title: "应用注册" }
|
|
},
|
|
// 统一认证中心:第三方登录配置(全局 / 租户自带)
|
|
{
|
|
path: "/system/authIdp",
|
|
name: "AuthIdpManage",
|
|
component: () => import("@/views/system/authIdp/index.vue"),
|
|
meta: { requiresAuth: true, title: "第三方登录" }
|
|
},
|
|
// 统一认证中心:租户登录策略(验证方式/会话时长/1号1机)
|
|
{
|
|
path: "/system/authConfig",
|
|
name: "AuthConfigManage",
|
|
component: () => import("@/views/system/authConfig/index.vue"),
|
|
meta: { requiresAuth: true, title: "登录策略" }
|
|
},
|
|
// 审批流配置(平台侧:域名申请等管控场景)
|
|
{
|
|
path: "/system/approval",
|
|
name: "PlatformApprovalFlow",
|
|
component: () => import("@/views/system/approval/index.vue"),
|
|
meta: { requiresAuth: true, title: "审批流配置" }
|
|
},
|
|
{
|
|
path: "/tools/passwordStore",
|
|
name: "PlatformPasswordStore",
|
|
component: () => import("@/views/tools/passwordStore/index.vue"),
|
|
meta: { requiresAuth: true, title: "密码存储" }
|
|
},
|
|
{
|
|
path: "/website/setting",
|
|
name: "PlatformWebsiteSetting",
|
|
component: () => import("@/views/website/site/setting/index.vue"),
|
|
meta: { requiresAuth: true, title: "站点设置" }
|
|
},
|
|
{
|
|
path: "/template/index",
|
|
name: "PlatformTemplateManage",
|
|
component: () => import("@/views/template/index.vue"),
|
|
meta: { requiresAuth: true, title: "官网模板管理" }
|
|
},
|
|
{
|
|
path: "/template/tags",
|
|
name: "PlatformTemplateTags",
|
|
component: () => import("@/views/template/tags.vue"),
|
|
meta: { requiresAuth: true, title: "标签调用说明" }
|
|
},
|
|
// 兼容拼写错误的路径重定向
|
|
{
|
|
path: "/apps/erp/dashborad",
|
|
redirect: "/apps/erp/dashboard"
|
|
}
|
|
];
|
|
|
|
// 静态路由:登录页独立、home 导航门户独立、404 页面独立
|
|
const staticRoutes = [
|
|
{
|
|
path: "/login",
|
|
name: "Login",
|
|
component: () => import("@/views/login/index.vue"),
|
|
meta: { requiresAuth: false }
|
|
},
|
|
{
|
|
path: "/register",
|
|
name: "Register",
|
|
component: () => import("@/views/login/register.vue"),
|
|
meta: { requiresAuth: false }
|
|
},
|
|
{
|
|
path: "/forget",
|
|
name: "ForgetPassword",
|
|
component: () => import("@/views/login/forget.vue"),
|
|
meta: { requiresAuth: false }
|
|
},
|
|
|
|
// 兼容路径拼写错误:dashborad -> dashboard
|
|
{
|
|
path: "/apps/erp/dashborad",
|
|
redirect: "/apps/erp/dashboard"
|
|
},
|
|
{
|
|
path: "/:pathMatch(.*)*",
|
|
name: "NotFound",
|
|
component: () => import("@/views/404/404.vue"),
|
|
meta: { requiresAuth: false }
|
|
}
|
|
];
|
|
|
|
const router = createRouter({
|
|
history: createWebHashHistory(),
|
|
routes: staticRoutes
|
|
});
|
|
|
|
let dynamicRoutesAdded = false;
|
|
let dynamicRoutesData = [];
|
|
let routesLoadingPromise = null;
|
|
|
|
export function resetDynamicRoutes() {
|
|
dynamicRoutesAdded = false;
|
|
routesLoadingPromise = null;
|
|
}
|
|
|
|
export async function loadAndAddDynamicRoutes() {
|
|
if (routesLoadingPromise) {
|
|
return routesLoadingPromise;
|
|
}
|
|
|
|
if (dynamicRoutesAdded) {
|
|
return Promise.resolve();
|
|
}
|
|
|
|
routesLoadingPromise = (async () => {
|
|
try {
|
|
const { useMenuStore } = await import("@/stores/menu");
|
|
const menuStore = useMenuStore();
|
|
const menuData = await menuStore.fetchMenus();
|
|
|
|
if (menuData && menuData.length > 0) {
|
|
addDynamicRoutes(menuData);
|
|
dynamicRoutesAdded = true;
|
|
routesLoadingPromise = null;
|
|
return Promise.resolve();
|
|
} else {
|
|
dynamicRoutesAdded = true;
|
|
routesLoadingPromise = null;
|
|
return Promise.resolve();
|
|
}
|
|
} catch (error) {
|
|
console.error('加载动态路由失败:', error);
|
|
dynamicRoutesAdded = true;
|
|
routesLoadingPromise = null;
|
|
throw error;
|
|
}
|
|
})();
|
|
|
|
return routesLoadingPromise;
|
|
}
|
|
|
|
// 核心修改:移除扁平化,直接使用嵌套菜单生成路由
|
|
function addDynamicRoutes(menus) {
|
|
if (!menus?.length) {
|
|
return;
|
|
}
|
|
|
|
// 直接转换嵌套菜单为嵌套路由(不再扁平化)
|
|
const dynamicRoutes = convertMenusToRoutes(menus);
|
|
|
|
if (router.hasRoute('Main')) {
|
|
router.removeRoute('Main');
|
|
}
|
|
|
|
// 重新添加主路由,合并静态子路由和动态路由
|
|
router.addRoute({
|
|
path: "/",
|
|
name: "Main",
|
|
component: () => import("@/views/Main.vue"),
|
|
redirect: "/home",
|
|
meta: { requiresAuth: true },
|
|
children: [...staticMainChildren, ...dynamicRoutes] // 合并静态和动态子路由
|
|
});
|
|
|
|
dynamicRoutesAdded = true;
|
|
}
|
|
|
|
function findRouteByName(routes, routeName) {
|
|
for (const route of routes) {
|
|
if (route.name === routeName) {
|
|
return route;
|
|
}
|
|
if (route.children) {
|
|
const found = findRouteByName(route.children, routeName);
|
|
if (found) {
|
|
return found;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function findFirstValidRoute(routes) {
|
|
for (const route of routes) {
|
|
if (route.component) {
|
|
return route;
|
|
}
|
|
if (route.children && route.children.length > 0) {
|
|
const childRoute = findFirstValidRoute(route.children);
|
|
if (childRoute) {
|
|
return childRoute;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
router.beforeEach(async (to, from, next) => {
|
|
const token = localStorage.getItem("token");
|
|
const publicPaths = ["/login", "/register", "/forget"];
|
|
|
|
if (publicPaths.includes(to.path)) {
|
|
if (token) {
|
|
if (!dynamicRoutesAdded) {
|
|
await loadAndAddDynamicRoutes();
|
|
}
|
|
next({ path: "/home" });
|
|
} else {
|
|
next();
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!token) {
|
|
next({ path: "/login", query: { redirect: to.path } });
|
|
return;
|
|
}
|
|
|
|
if (!dynamicRoutesAdded) {
|
|
try {
|
|
await loadAndAddDynamicRoutes();
|
|
} catch (error) {
|
|
console.error('动态路由加载失败:', error);
|
|
// token 无效时跳转登录
|
|
if (error?.message === 'token无效' || error?.response?.status === 401) {
|
|
next({ path: '/login' });
|
|
return;
|
|
}
|
|
}
|
|
// 路由加载后重新导航,确保路由匹配正确
|
|
next({ path: to.path, replace: true });
|
|
return;
|
|
}
|
|
|
|
next();
|
|
});
|
|
|
|
export default router;
|