283 lines
7.6 KiB
JavaScript
283 lines
7.6 KiB
JavaScript
import { createRouter, createWebHistory } from 'vue-router'
|
||
import NProgress from 'nprogress'
|
||
import 'nprogress/nprogress.css'
|
||
import { getToken } from '@/utils/auth'
|
||
import { useUserStore } from '@/store/modules/user'
|
||
|
||
NProgress.configure({ showSpinner: false })
|
||
|
||
// 静态路由
|
||
export const constantRoutes = [
|
||
{
|
||
path: '/',
|
||
component: () => import('@/layouts/BasicLayout.vue'),
|
||
redirect: '/dashboard',
|
||
meta: { title: '首页', icon: 'DashboardOutlined' },
|
||
children: [
|
||
{
|
||
path: 'dashboard',
|
||
name: 'Dashboard',
|
||
component: () => import('@/views/dashboard/index.vue'),
|
||
meta: { title: '控制台', icon: 'DashboardOutlined' }
|
||
}
|
||
]
|
||
},
|
||
{
|
||
path: '/login',
|
||
name: 'Login',
|
||
component: () => import('@/views/login/index.vue'),
|
||
meta: { title: '登录', hidden: true }
|
||
},
|
||
{
|
||
path: '/403',
|
||
name: '403',
|
||
component: () => import('@/views/error/403.vue'),
|
||
meta: { title: '无权限', hidden: true }
|
||
},
|
||
{
|
||
path: '/404',
|
||
name: '404',
|
||
component: () => import('@/views/error/404.vue'),
|
||
meta: { title: '页面不存在', hidden: true }
|
||
}
|
||
]
|
||
|
||
// 动态路由(根据权限加载)
|
||
export const asyncRoutes = [
|
||
{
|
||
path: '/user',
|
||
component: () => import('@/layouts/BasicLayout.vue'),
|
||
redirect: '/user/list',
|
||
meta: { title: '用户管理', icon: 'TeamOutlined' },
|
||
children: [
|
||
{
|
||
path: 'list',
|
||
name: 'UserList',
|
||
component: () => import('@/views/user/list.vue'),
|
||
meta: { title: '用户列表', icon: 'UnorderedListOutlined' }
|
||
}
|
||
]
|
||
},
|
||
{
|
||
path: '/order',
|
||
component: () => import('@/layouts/BasicLayout.vue'),
|
||
redirect: '/order/list',
|
||
meta: { title: '订单管理', icon: 'ShoppingOutlined' },
|
||
children: [
|
||
{
|
||
path: 'list',
|
||
name: 'OrderList',
|
||
component: () => import('@/views/order/list.vue'),
|
||
meta: { title: '订单列表', icon: 'UnorderedListOutlined' }
|
||
}
|
||
]
|
||
},
|
||
{
|
||
path: '/work',
|
||
component: () => import('@/layouts/BasicLayout.vue'),
|
||
redirect: '/work/list',
|
||
meta: { title: '作品管理', icon: 'PictureOutlined' },
|
||
children: [
|
||
{
|
||
path: 'list',
|
||
name: 'WorkList',
|
||
component: () => import('@/views/work/list.vue'),
|
||
meta: { title: '作品列表', icon: 'FileImageOutlined' }
|
||
},
|
||
{
|
||
path: 'audit',
|
||
name: 'WorkAudit',
|
||
component: () => import('@/views/work/audit.vue'),
|
||
meta: { title: '作品审核', icon: 'AuditOutlined' }
|
||
},
|
||
{
|
||
path: 'category',
|
||
name: 'WorkCategory',
|
||
component: () => import('@/views/work/category.vue'),
|
||
meta: { title: '分类管理', icon: 'AppstoreOutlined' }
|
||
}
|
||
]
|
||
},
|
||
{
|
||
path: '/ai',
|
||
component: () => import('@/layouts/BasicLayout.vue'),
|
||
redirect: '/ai/provider',
|
||
meta: { title: 'AI管理', icon: 'RobotOutlined' },
|
||
children: [
|
||
{
|
||
path: 'provider',
|
||
name: 'AiProvider',
|
||
component: () => import('@/views/ai/provider.vue'),
|
||
meta: { title: 'AI厂商', icon: 'CloudServerOutlined' }
|
||
},
|
||
{
|
||
path: 'model',
|
||
name: 'AiModel',
|
||
component: () => import('@/views/ai/model.vue'),
|
||
meta: { title: 'AI模型', icon: 'ApiOutlined' }
|
||
},
|
||
{
|
||
path: 'task',
|
||
name: 'AiTask',
|
||
component: () => import('@/views/ai/task.vue'),
|
||
meta: { title: 'AI任务', icon: 'ScheduleOutlined' }
|
||
},
|
||
{
|
||
path: 'debug',
|
||
name: 'AiDebug',
|
||
component: () => import('@/views/ai/debug.vue'),
|
||
meta: { title: 'AI调试', icon: 'BugOutlined' }
|
||
}
|
||
]
|
||
},
|
||
{
|
||
path: '/config',
|
||
component: () => import('@/layouts/BasicLayout.vue'),
|
||
redirect: '/config/reward',
|
||
meta: { title: '系统配置', icon: 'SettingOutlined' },
|
||
children: [
|
||
{
|
||
path: 'reward',
|
||
name: 'RewardConfig',
|
||
component: () => import('@/views/config/reward.vue'),
|
||
meta: { title: '奖励配置', icon: 'GiftOutlined' }
|
||
},
|
||
{
|
||
path: 'redeem',
|
||
name: 'RedeemConfig',
|
||
component: () => import('@/views/config/redeem.vue'),
|
||
meta: { title: '兑换码管理', icon: 'KeyOutlined' }
|
||
},
|
||
{
|
||
path: 'vip',
|
||
name: 'VipConfig',
|
||
component: () => import('@/views/config/vip.vue'),
|
||
meta: { title: 'VIP套餐', icon: 'CrownOutlined' }
|
||
},
|
||
{
|
||
path: 'points',
|
||
name: 'PointsConfig',
|
||
component: () => import('@/views/config/points.vue'),
|
||
meta: { title: '积分套餐', icon: 'StarOutlined' }
|
||
},
|
||
{
|
||
path: 'banner',
|
||
name: 'BannerConfig',
|
||
component: () => import('@/views/config/banner.vue'),
|
||
meta: { title: 'Banner管理', icon: 'FileImageOutlined' }
|
||
},
|
||
{
|
||
path: 'notice',
|
||
name: 'NoticeConfig',
|
||
component: () => import('@/views/config/notice.vue'),
|
||
meta: { title: '公告管理', icon: 'NotificationOutlined' }
|
||
}
|
||
]
|
||
},
|
||
{
|
||
path: '/system',
|
||
component: () => import('@/layouts/BasicLayout.vue'),
|
||
redirect: '/system/admin',
|
||
meta: { title: '系统管理', icon: 'ToolOutlined' },
|
||
children: [
|
||
{
|
||
path: 'admin',
|
||
name: 'AdminList',
|
||
component: () => import('@/views/system/admin.vue'),
|
||
meta: { title: '管理员管理', icon: 'UserOutlined' }
|
||
},
|
||
{
|
||
path: 'role',
|
||
name: 'RoleList',
|
||
component: () => import('@/views/system/role.vue'),
|
||
meta: { title: '角色管理', icon: 'SafetyOutlined' }
|
||
},
|
||
{
|
||
path: 'permission',
|
||
name: 'PermissionList',
|
||
component: () => import('@/views/system/permission.vue'),
|
||
meta: { title: '权限管理', icon: 'KeyOutlined' }
|
||
}
|
||
]
|
||
},
|
||
{ path: '/:pathMatch(.*)*', name: 'NotFound', redirect: '/404', meta: { hidden: true } }
|
||
]
|
||
|
||
const router = createRouter({
|
||
history: createWebHistory(),
|
||
routes: constantRoutes
|
||
})
|
||
|
||
// 白名单
|
||
const whiteList = ['/login', '/403', '/404']
|
||
|
||
// 标记是否已添加动态路由
|
||
let dynamicRoutesAdded = false
|
||
|
||
// 添加动态路由
|
||
function addDynamicRoutes() {
|
||
if (dynamicRoutesAdded) return
|
||
asyncRoutes.forEach(route => router.addRoute(route))
|
||
dynamicRoutesAdded = true
|
||
}
|
||
|
||
// 重置路由(登出时调用)
|
||
export function resetRouter() {
|
||
dynamicRoutesAdded = false
|
||
// 移除动态添加的路由
|
||
asyncRoutes.forEach(route => {
|
||
if (route.name && router.hasRoute(route.name)) {
|
||
router.removeRoute(route.name)
|
||
}
|
||
})
|
||
}
|
||
|
||
// 路由守卫
|
||
router.beforeEach(async (to, _from, next) => {
|
||
NProgress.start()
|
||
const token = getToken()
|
||
|
||
if (token) {
|
||
if (to.path === '/login') {
|
||
next({ path: '/' })
|
||
} else {
|
||
// 确保动态路由已添加
|
||
addDynamicRoutes()
|
||
|
||
const userStore = useUserStore()
|
||
// 确保用户信息已获取(包含权限和角色)
|
||
if (!userStore.userInfo || !userStore.roles.length) {
|
||
try {
|
||
await userStore.getUserInfo()
|
||
} catch (error) {
|
||
console.error('获取用户信息失败', error)
|
||
// Token可能已失效,跳转登录
|
||
userStore.resetState()
|
||
next(`/login?redirect=${to.path}`)
|
||
return
|
||
}
|
||
}
|
||
|
||
// 检查路由是否存在
|
||
if (router.hasRoute(to.name) || to.matched.length > 0) {
|
||
next()
|
||
} else {
|
||
// 路由刚添加,需要重新导航
|
||
next({ ...to, replace: true })
|
||
}
|
||
}
|
||
} else {
|
||
if (whiteList.includes(to.path)) {
|
||
next()
|
||
} else {
|
||
next(`/login?redirect=${to.path}`)
|
||
}
|
||
}
|
||
})
|
||
|
||
router.afterEach(() => {
|
||
NProgress.done()
|
||
})
|
||
|
||
export default router
|