fix:完善相关页面
This commit is contained in:
@@ -1,16 +1,204 @@
|
||||
import { createWebHistory, createRouter } from 'vue-router'
|
||||
import { createWebHistory, createRouter, type RouteRecordRaw } from 'vue-router'
|
||||
import { useUserStore } from '@/store'
|
||||
import { getRouteMenus } from '@/api'
|
||||
import useTokenRefresh from '@/hooks/useTokenRefresh'
|
||||
|
||||
import Login from '@/pages/Login/index.vue';
|
||||
import HomeView from '@/pages/Layout/index.vue';
|
||||
const routes = [
|
||||
{ path: '/', component: HomeView },
|
||||
{ path: '/login', component: Login },
|
||||
|
||||
const baseUrl = import.meta.env.VITE_APP_BASE_API || '';
|
||||
|
||||
// 基础路由(不需要权限验证)
|
||||
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,
|
||||
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}`
|
||||
} 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[]): RouteRecordRaw[] => {
|
||||
return routes.map((route) => {
|
||||
const component = route.component ? loadComponent(route.component) : undefined
|
||||
// 构建基础路由对象
|
||||
const routeRecord: any = {
|
||||
path: route.path,
|
||||
name: route.name || route.path,
|
||||
meta: {
|
||||
title: route.meta?.title || route.title || route.name,
|
||||
icon: route.meta?.icon || route.icon,
|
||||
requiresAuth: route.meta?.requiresAuth !== false, // 默认需要权限
|
||||
roles: route.meta?.roles || route.roles,
|
||||
...route.meta,
|
||||
},
|
||||
}
|
||||
|
||||
// 如果有组件,添加组件属性
|
||||
if (component) {
|
||||
routeRecord.component = component
|
||||
}
|
||||
|
||||
// 处理子路由
|
||||
if (route.children && route.children.length > 0) {
|
||||
routeRecord.children = transformRoutes(route.children)
|
||||
}
|
||||
|
||||
return routeRecord as RouteRecordRaw
|
||||
})
|
||||
}
|
||||
|
||||
// 添加动态路由
|
||||
const addDynamicRoutes = async () => {
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 如果路由已加载,直接返回
|
||||
if (userStore.isRoutesLoaded) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// 从后端获取路由菜单数据
|
||||
const response = await getRouteMenus()
|
||||
if (response.code === 0 && response.data) {
|
||||
// 转换路由数据
|
||||
const dynamicRoutes = transformRoutes(Array.isArray(response.data) ? response.data : [response.data])
|
||||
// 将动态路由添加到 Layout 的 children 中
|
||||
const layoutRoute = router.getRoutes().find(route => route.name === 'Layout')
|
||||
|
||||
console.log('Layout route:', layoutRoute,dynamicRoutes)
|
||||
if (layoutRoute) {
|
||||
dynamicRoutes.forEach(route => {
|
||||
router.addRoute('Layout', route)
|
||||
})
|
||||
} else {
|
||||
// 如果找不到 Layout 路由,直接添加到根路由
|
||||
dynamicRoutes.forEach(route => {
|
||||
router.addRoute(route)
|
||||
})
|
||||
}
|
||||
|
||||
// 保存路由数据到 store
|
||||
userStore.setRoutes(response.data)
|
||||
|
||||
// 标记路由已加载
|
||||
userStore.isRoutesLoaded = true
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load routes:', error)
|
||||
// 如果获取路由失败,清除用户数据并跳转到登录页
|
||||
userStore.clearUserData()
|
||||
router.push('/login')
|
||||
}
|
||||
}
|
||||
|
||||
// 路由导航守卫
|
||||
router.beforeEach(async (to, _from, next) => {
|
||||
const userStore = useUserStore()
|
||||
const { getAccessToken } = useTokenRefresh(baseUrl)
|
||||
|
||||
// 获取 token
|
||||
const token = getAccessToken() || 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
|
||||
Reference in New Issue
Block a user