first commit

This commit is contained in:
2026-06-03 10:09:03 +08:00
commit 81f5039458
6266 changed files with 188236 additions and 0 deletions
+52
View File
@@ -0,0 +1,52 @@
import { createRouter, createWebHistory } from 'vue-router';
import { constantRoute, registerDynamicRoutes } from './routes';
// 先创建路由,但不立即匹配
const router = createRouter({
history: createWebHistory(),
routes: constantRoute,
// 延迟路由匹配,等待动态路由注册完成
strict: false,
});
// 在应用启动时加载菜单并注册路由
let routesLoaded = false;
let routesLoadingPromise: Promise<void> | null = null;
export async function loadAndRegisterRoutes() {
// 如果已经加载过,直接返回
if (routesLoaded) {
return;
}
// 如果正在加载,等待加载完成
if (routesLoadingPromise) {
return routesLoadingPromise;
}
return routesLoadingPromise;
}
// 路由守卫:确保路由已加载
router.beforeEach(async (to, _from, next) => {
// 如果路由还未加载,先加载路由
if (!routesLoaded) {
// 等待路由加载完成
await routesLoadingPromise;
// 路由加载完成后,如果当前路径不匹配,尝试重新匹配
const matched = router.resolve(to.path).matched;
if (matched.length === 0 && to.path !== '/404') {
// 路由已加载但当前路径不匹配,可能是通配符路由
// 继续导航,让通配符路由处理
next();
return;
}
}
// 路由已加载,继续导航
next();
});
export default router;
+124
View File
@@ -0,0 +1,124 @@
import { createComponentLoader } from '@/utils/pathResolver'
// 对外暴漏配置路由,常量路由
export const constantRoute = [
{
path: '/',
component: () => import('@/views/theme/index.vue'),
name: '首页',
meta: {
title: '首页',
hidden: false,
},
},
{
path: '/404',
component: () => import('@/views/404/index.vue'),
name: '404',
meta: {
title: '404',
hidden: true,
icon: 'DocumentDelete',
},
},
]
// 动态路由注册函数
export function registerDynamicRoutes(router: any, menus: any[]) {
if (!menus || menus.length === 0) return
// 统一处理菜单路径大小写
const normalizeMenuPaths = (menus: any[]) => {
return menus.map(menu => {
const normalizedMenu = { ...menu }
// 将路径中的 /newscenter/ 替换为 /newsCenter/
if (normalizedMenu.path) {
normalizedMenu.path = normalizedMenu.path.replace(/\/newscenter\//g, '/newsCenter/')
}
// 递归处理子菜单
if (normalizedMenu.children && normalizedMenu.children.length > 0) {
normalizedMenu.children = normalizeMenuPaths(normalizedMenu.children)
}
return normalizedMenu
})
}
// 先规范化菜单路径
const normalizedMenus = normalizeMenuPaths(menus)
// 收集所有需要注册的路由
const routesToAdd: any[] = []
// 递归处理菜单,收集路由
const processMenu = (menu: any) => {
// type 2: 页面 - 根据 component_path 加载组件
if (menu.type === 2 && menu.path && menu.component_path) {
const path = menu.path
// 检查路由是否已存在
const existingRoute = router.getRoutes().find((r: any) => r.path === path)
if (!existingRoute) {
try {
// 使用 pathResolver 来解析 component_path
// component_path 可能的格式:
// 1. /views/newsCenter/companyNews/index.vue
// 2. views/newsCenter/companyNews/index.vue
// 3. newsCenter/companyNews/index.vue
const componentLoader = createComponentLoader(menu.component_path)
if (!componentLoader) {
console.error(`Failed to create component loader for: ${menu.component_path}`)
return
}
routesToAdd.push({
path: path,
name: `menu_${menu.id}`,
component: componentLoader,
meta: {
title: menu.title,
menuId: menu.id,
menuType: menu.type,
},
})
} catch (error) {
console.error(`Failed to prepare route for path ${path}, component_path: ${menu.component_path}`, error)
}
}
}
// type 4: 单页 - 使用通配符路由处理,不需要单独注册
// 递归处理子菜单
if (menu.children && menu.children.length > 0) {
menu.children.forEach((child: any) => processMenu(child))
}
}
// 处理所有菜单
normalizedMenus.forEach((menu) => processMenu(menu))
// 先移除通配符路由(如果存在),以便重新添加
const catchAllRoute = router.getRoutes().find((r: any) => r.path === '/:pathMatch(.*)*')
if (catchAllRoute) {
router.removeRoute('OnePage')
}
// 注册 type 2 的路由(必须在通配符路由之前)
routesToAdd.forEach((route) => {
router.addRoute(route)
})
// 最后添加通配符路由(用于单页和其他未匹配的路径)
const catchAllExists = router.getRoutes().find((r: any) => r.path === '/:pathMatch(.*)*')
if (!catchAllExists) {
router.addRoute({
path: '/:pathMatch(.*)*',
component: () => import('@/views/onepage/index.vue'),
name: 'OnePage',
meta: {
title: '单页',
hidden: true,
},
})
}
}