import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router' import { useAuthStore } from '@/stores/auth' import type { PermissionCode } from '@/types' const routes: RouteRecordRaw[] = [ { path: '/login', name: 'login', component: () => import('@/views/login/LoginView.vue'), meta: { title: '登录', public: true }, }, { path: '/guide', name: 'guide', component: () => import('@/views/guide/GuideView.vue'), meta: { title: '使用文档', skipPermission: true }, }, { path: '/', component: () => import('@/layouts/MainLayout.vue'), redirect: '/dashboard', children: [ // 服务看板 { path: 'dashboard', name: 'dashboard', component: () => import('@/views/dashboard/DashboardView.vue'), meta: { title: '服务看板' }, }, // 模型调优 { path: 'fine-tune', name: 'fine-tune', component: () => import('@/views/fine-tune/FineTuneListView.vue'), meta: { title: '模型训练', pageSurface: 'self' }, }, { path: 'fine-tune/create', name: 'fine-tune-create', component: () => import('@/views/fine-tune/FineTuneCreateView.vue'), meta: { title: '创建训练任务' }, }, // 模型评测 { path: 'model-eval', name: 'model-eval', component: () => import('@/views/eval/EvalView.vue'), meta: { title: '模型评测', pageSurface: 'self' }, }, { path: 'model-eval/create', name: 'model-eval-create', component: () => import('@/views/eval/EvalCreateView.vue'), meta: { title: '新建评测' }, }, { path: 'model-eval/:id', name: 'model-eval-detail', component: () => import('@/views/eval/EvalDetailView.vue'), meta: { title: '评测详情' }, }, { path: 'model-eval/dimension/create', name: 'dimension-create', redirect: '/model-eval/create', }, { path: 'model-eval/dimension/:id/edit', name: 'dimension-edit', component: () => import('@/views/eval/DimensionCreateView.vue'), meta: { title: '编辑评测维度' }, }, // 模型推理 { path: 'model-inference', name: 'model-inference', component: () => import('@/views/inference/InferenceListView.vue'), meta: { title: '模型推理', pageSurface: 'self' }, }, { path: 'model-inference/create', name: 'model-inference-create', component: () => import('@/views/inference/InferenceCreateView.vue'), meta: { title: '新建推理' }, }, { path: 'model-inference/chat/:id', name: 'inference-chat', component: () => import('@/views/inference/InferenceChatView.vue'), meta: { title: '模型对话', pageSurface: 'self' }, }, // 模型对比 { path: 'model-compare/chat/:id', name: 'compare-chat', component: () => import('@/views/compare/CompareChatView.vue'), meta: { title: '模型对比' }, }, { path: 'model-compare/result', name: 'compare-result', component: () => import('@/views/compare/CompareResultView.vue'), meta: { title: '对比结果' }, }, // 模型管理 { path: 'model-manage', name: 'model-manage', component: () => import('@/views/model/ModelManageView.vue'), meta: { title: '模型管理', pageSurface: 'self' }, }, { path: 'model-manage/create', name: 'model-manage-create', component: () => import('@/views/model/ModelCreateView.vue'), meta: { title: '添加模型' }, }, { path: 'model-manage/:id/edit', name: 'model-manage-edit', component: () => import('@/views/model/ModelCreateView.vue'), meta: { title: '编辑模型' }, }, { path: 'model-manage/merge', name: 'merge-weights', component: () => import('@/views/model/MergeWeightsView.vue'), meta: { title: '合并权重' }, }, // 数据处理 { path: 'data-process', name: 'data-process', component: () => import('@/views/data-process/DataProcessListView.vue'), meta: { title: '数据处理', pageSurface: 'self' }, }, { path: 'data-process/create', name: 'data-process-create', component: () => import('@/views/data-process/DataProcessCreateView.vue'), meta: { title: '新建数据处理任务', pageSurface: 'self' }, }, { path: 'data-process/:id/regenerate', name: 'data-process-regenerate', component: () => import('@/views/data-process/DataProcessCreateView.vue'), meta: { title: '重新生成数据处理任务', pageSurface: 'self' }, }, { path: 'data-process/:id', name: 'data-process-detail', component: () => import('@/views/data-process/DataProcessDetailView.vue'), meta: { title: '数据处理详情' }, }, // 数据集管理 { path: 'dataset', name: 'dataset', component: () => import('@/views/dataset/DatasetListView.vue'), meta: { title: '数据集管理', pageSurface: 'self' }, }, { path: 'dataset/create', name: 'dataset-create', component: () => import('@/views/dataset/DatasetCreateView.vue'), meta: { title: '上传数据集' }, }, { path: 'dataset/:id/edit', name: 'dataset-edit', component: () => import('@/views/dataset/DatasetCreateView.vue'), meta: { title: '编辑数据集' }, }, { path: 'dataset/:id/preview', name: 'dataset-preview', component: () => import('@/views/dataset/DatasetPreviewView.vue'), meta: { title: '数据集预览' }, }, // 其他工具 { path: 'tools', name: 'tools', component: () => import('@/views/tools/ToolsView.vue'), meta: { title: '其他工具' }, }, { path: 'tools/create', name: 'tools-create', component: () => import('@/views/tools/ToolCreateView.vue'), meta: { title: '添加自定义工具' }, }, { path: 'tools/:id/edit', name: 'tools-edit', component: () => import('@/views/tools/ToolCreateView.vue'), meta: { title: '编辑自定义工具' }, }, // 数据类型转换 { path: 'data-convert', name: 'data-convert', component: () => import('@/views/data-convert/DataConvertView.vue'), meta: { title: '数据类型转换' }, }, { path: 'compute', name: 'compute', component: () => import('@/views/compute/ComputeNodesView.vue'), meta: { title: '算力节点', pageSurface: 'self', permission: 'compute' }, }, { path: 'compute/gpus', redirect: '/compute?tab=gpus', }, { path: 'compute/queue', redirect: '/compute?tab=queue', }, { path: 'compute/nodes', redirect: '/compute?tab=nodes', }, // 系统设置 { path: 'permission-denied', name: 'permission-denied', component: () => import('@/views/system/PermissionDeniedView.vue'), meta: { title: '无权访问', skipPermission: true }, }, { path: 'hardware', name: 'hardware', component: () => import('@/views/system/HardwareView.vue'), meta: { title: '平台性能' }, }, { path: 'logs', name: 'logs', component: () => import('@/views/system/LogsView.vue'), meta: { title: '查看日志' }, }, { path: 'user-settings', name: 'user-settings', component: () => import('@/views/system/UserSettingsView.vue'), meta: { title: '用户设置', pageSurface: 'self', permission: 'user-settings' }, }, { path: 'user-settings/create', name: 'user-create', component: () => import('@/views/system/UserCreateView.vue'), meta: { title: '创建用户', permission: 'user-settings' }, }, { path: 'user-settings/:id/permission', name: 'user-permission', component: () => import('@/views/system/UserPermissionView.vue'), meta: { title: '权限设置', permission: 'user-settings' }, }, { path: 'training-log/:id', name: 'training-log', component: () => import('@/views/system/TrainingLogView.vue'), meta: { title: '训练日志' }, }, ], }, { path: '/:pathMatch(.*)*', redirect: '/dashboard', }, ] const router = createRouter({ history: createWebHistory(), routes, }) const permissionBySegment: Record = { dashboard: 'dashboard', 'fine-tune': 'fine-tune', 'training-log': 'fine-tune', 'model-eval': 'model-eval', 'model-inference': 'model-inference', 'model-compare': 'model-inference', 'model-manage': 'model-manage', dataset: 'dataset', 'data-process': 'data-process', 'data-convert': 'data-convert', compute: 'compute', tools: 'data-convert', hardware: 'hardware', logs: 'logs', 'user-settings': 'user-settings', } function requiredPermission(path: string, explicit?: unknown) { if (explicit) return explicit as PermissionCode const segment = path.split('/')[1] return permissionBySegment[segment] } // 全局守卫:登录校验 + 会话超时 router.beforeEach((to, _from, next) => { const auth = useAuthStore() auth.syncSession() document.title = to.meta.title ? `${to.meta.title} - 远光软件微调平台` : '远光软件微调平台' if (to.meta.public) { // 已登录访问登录页则跳转主页 if (to.name === 'login' && auth.isLoggedIn) { next('/dashboard') return } next() return } if (!auth.isLoggedIn) { next({ name: 'login' }) return } if (!to.meta.skipPermission) { const permission = requiredPermission(to.path, to.meta.permission) if (permission && !auth.hasPermission(permission)) { next({ name: 'permission-denied', replace: true }) return } } // 续期会话 auth.refresh() next() }) export default router