134 lines
3.7 KiB
TypeScript
134 lines
3.7 KiB
TypeScript
import { createRouter, createWebHistory } from 'vue-router'
|
||
import { useUserStore } from '@/stores/modules/user'
|
||
import Layout from '@/components/layout/Layout.vue'
|
||
import { setRouter, handleRouter } from './handleRouter'
|
||
import { getStorage, setStorage } from '@/utils/storage'
|
||
|
||
const routes = [
|
||
// user路由
|
||
{
|
||
path: '/user',
|
||
name: 'User',
|
||
component: () => import('@/views/user/index.vue'),
|
||
redirect: '/user/login',
|
||
children: [
|
||
{
|
||
path: 'login',
|
||
name: 'Login',
|
||
component: () => import('@/views/user/Login.vue'),
|
||
meta: { isAuthPage: true, title: '登录' },
|
||
},
|
||
{
|
||
path: 'register',
|
||
name: 'Register',
|
||
component: () => import('@/views/user/Register.vue'),
|
||
meta: { isAuthPage: true, title: '注册' },
|
||
},
|
||
{
|
||
path: 'forgot-password',
|
||
name: 'ForgotPassword',
|
||
component: () => import('@/views/user/ForgotPassword.vue'),
|
||
meta: { isAuthPage: true, title: '忘记密码' },
|
||
},
|
||
{
|
||
path: 'change-password',
|
||
name: 'ChangePassword',
|
||
component: () => import('@/views/user/ChangePassword.vue'),
|
||
meta: { requiresAuth: true, title: '修改密码' },
|
||
},
|
||
{
|
||
path: 'bind-email',
|
||
name: 'BindEmail',
|
||
component: () => import('@/views/user/bindEmail.vue'),
|
||
meta: { requiresAuth: true, title: '绑定邮箱' },
|
||
},
|
||
{
|
||
path: 'bind-phone',
|
||
name: 'BindPhone',
|
||
component: () => import('@/views/user/bindPhone.vue'),
|
||
meta: { requiresAuth: true, title: '绑定手机号' },
|
||
},
|
||
],
|
||
},
|
||
// 带侧边栏布局的核心业务页面
|
||
{
|
||
path: '/',
|
||
name: 'Layout',
|
||
component: Layout, // 全局布局(Sidebar + Header + MainContent)
|
||
redirect: '/dashboard',
|
||
meta: { requiresAuth: true }, // 需要登录
|
||
children: [
|
||
// 首页
|
||
{
|
||
path: '/dashboard',
|
||
name: 'Dashboard',
|
||
component: () => import('@/views/dashboard/index.vue'),
|
||
meta: {
|
||
title: '首页', // 左侧菜单显示的标题
|
||
},
|
||
},
|
||
],
|
||
},
|
||
{
|
||
path: '/:pathMatch(.*)*',
|
||
redirect: () => {
|
||
const token = getStorage('token')
|
||
return token ? '/dashboard' : '/user/login'
|
||
}, // 404 重定向到登录页,避免循环
|
||
},
|
||
]
|
||
|
||
const router = createRouter({
|
||
history: createWebHistory(),
|
||
routes,
|
||
})
|
||
|
||
// 标记:动态路由是否已初始化完成
|
||
let dynamicRoutesReady = false
|
||
|
||
router.beforeEach(async (to, _from) => {
|
||
const userStore = useUserStore()
|
||
const isLoggedIn = !!userStore.token
|
||
|
||
console.log('dynamicRoutesReady', dynamicRoutesReady)
|
||
console.log('isLoggedIn', isLoggedIn)
|
||
console.log('to.meta.requiresAuth', to.meta.requiresAuth)
|
||
console.log('to.meta.isAuthPage', to.meta.isAuthPage)
|
||
|
||
// 1. 未登录访问需要认证的页 → 登录页
|
||
if (!isLoggedIn && to.meta.requiresAuth) {
|
||
return '/user/login'
|
||
}
|
||
|
||
// 2. ✅ 动态路由恢复(只执行一次)
|
||
if (isLoggedIn && !dynamicRoutesReady) {
|
||
const menuList = getStorage('menusInfo')
|
||
if (menuList?.length > 0) {
|
||
const routeList = handleRouter(menuList).filter(
|
||
(item) => item.path && item.path !== '/dashboard',
|
||
)
|
||
routeList.forEach((route) => router.addRoute('Layout', route))
|
||
dynamicRoutesReady = true
|
||
// 返回目标路由以触发重新匹配
|
||
return to.redirectedFrom?.fullPath || true
|
||
}
|
||
}
|
||
|
||
// 3. 已登录访问登录/注册页 → 首页
|
||
if (isLoggedIn && to.meta.isAuthPage) {
|
||
return '/'
|
||
}
|
||
|
||
// 4. 其他情况正常放行
|
||
return true
|
||
})
|
||
|
||
// 可选:设置页面标题
|
||
router.afterEach((to) => {
|
||
if (to.meta.title) {
|
||
document.title = to.meta.title as string
|
||
}
|
||
})
|
||
|
||
export default router
|