# DR02 — 导航与路由访问规则 > **版本:V1.1 | 左导航布局 | Vue3 + Element Plus + Vue Router** > **参考:pj006-zhilianyuan2 frontend-orgadmin 的路由守卫模式** > > **⚠️ 本文为 V1 导航基线。** > 当前正式导航与对象化工作台口径,请以 `SY22_Role_Skill_App_Unified_Task_Architecture.md` 为准: > `新建任务 / 项目 / 专员·技能·APP·连接器 / 长程APP / 知识库 / 后台管理 / 我的` > > 本文第 1 节菜单树、路由示例和权限说明,主要用于保留早期培训平台的导航与鉴权基线。 > 其中出现的“首页 / 公司介绍培训 / 产品知识 / 产品销售培训 / 考试 / 知识管理 / 系统管理”,都应理解为 V1 历史结构,而不是当前目标导航。 --- ## 1. 导航菜单可见性规则 | 菜单 | 可见角色 | 类型 | 说明 | |------|---------|------|------| | 首页 | employee + admin | 一级菜单 | 所有人可见 | | 公司介绍培训 | employee + admin | 一级菜单 | 所有人可见 | | 产品知识 | employee + admin | 一级菜单 | 所有人可见 | | 产品销售培训 | employee + admin | 一级菜单 | 所有人可见 | | 考试 | employee + admin | 一级展开 | 所有人可见 | | ├ 自测练习 | employee + admin | 子菜单 | — | | ├ 正式结业考试 | employee + admin | 子菜单 | — | | ├ 我的考试记录 | employee + admin | 子菜单 | — | | └ 题库管理 | **admin only** | 子菜单 | **管理员专属,员工不可见** | | 知识管理 | **admin only** | 一级展开 | **管理员专属,员工不可见** | | ├ 课件素材管理 | admin only | 子菜单 | — | | └ 素材审批列表 | admin only | 子菜单 | — | | 系统管理 | **admin only** | 一级展开 | **管理员专属,员工不可见** | | ├ 用户账号管理 | admin only | 子菜单 | — | | ├ 全部考试成绩 | admin only | 子菜单 | — | | └ 系统参数配置 | admin only | 子菜单 | — | ## 2. 路由守卫实现 ```javascript // router/index.js import { createRouter, createWebHistory } from 'vue-router' import { useAuthStore } from '@/store/auth' const routes = [ { path: '/login', component: () => import('@/views/Login.vue'), meta: { requiresAuth: false }, }, { path: '/', component: MainLayout, children: [ // 员工 + 管理员都能访问 { path: '', component: () => import('@/views/home/HomeView.vue') }, { path: 'company-train', component: () => import('@/views/companyTrain/CompanyTrainView.vue') }, { path: 'products', component: () => import('@/views/product/ProductList.vue') }, { path: 'products/:id', component: () => import('@/views/product/ProductDetail.vue') }, { path: 'courses', component: () => import('@/views/salesTrain/CourseList.vue') }, { path: 'courses/:id', component: () => import('@/views/salesTrain/CourseDetail.vue') }, { path: 'exam/self-test', component: () => import('@/views/exam/ExamSelfTest.vue') }, { path: 'exam/formal', component: () => import('@/views/exam/ExamFormal.vue') }, { path: 'exam/my-records', component: () => import('@/views/exam/ExamMyRecord.vue') }, // 管理员专属路由 { path: 'exam/questions', component: () => import('@/views/exam/ExamQuestionBank.vue'), meta: { requiresAdmin: true }, }, { path: 'knowledge/materials', component: () => import('@/views/knowledge/MaterialManage.vue'), meta: { requiresAdmin: true }, }, { path: 'knowledge/audit', component: () => import('@/views/knowledge/MaterialAuditList.vue'), meta: { requiresAdmin: true }, }, { path: 'system/users', component: () => import('@/views/system/UserManage.vue'), meta: { requiresAdmin: true }, }, { path: 'system/exam-records', component: () => import('@/views/system/ExamRecordManage.vue'), meta: { requiresAdmin: true }, }, { path: 'system/config', component: () => import('@/views/system/SystemConfig.vue'), meta: { requiresAdmin: true }, }, ], }, ] const router = createRouter({ history: createWebHistory(), routes }) // 路由守卫 router.beforeEach((to, from, next) => { if (to.path === '/login') { next() return } const authStore = useAuthStore() // 未登录 → 跳转登录页 if (!authStore.isLoggedIn) { next('/login') return } // 管理员路由校验(⚠️ 前端仅作 UX 隐藏,非安全边界) if (to.meta.requiresAdmin && authStore.user?.role !== 'admin') { next('/') return } next() }) export default router ``` ## 3. 后端鉴权对应规则 | 路由 | 后端校验 | 说明 | |------|---------|------| | `/api/auth/*` | 仅 login 无需认证 | — | | `/api/company-train/*` | 需有效 JWT | 员工/管理员均可 | | `/api/products/*` | 需有效 JWT | 员工/管理员均可 | | `/api/courses/*` | 需有效 JWT | 员工/管理员均可 | | `/api/exam/list\|cover\|start\|submit\|record` | 需有效 JWT | 学员端考试 | | `/api/exam/questions\|papers` | 需 admin 角色 | 题库/考试配置管理 | | `/api/media/upload\|preview\|status` | 需有效 JWT | 文件操作 | | `/api/media/audit*` | 需 admin 角色 | 素材审批 | | `/api/system/*` | 需 admin 角色 | 系统管理全部 | | `/api/ai-chat/*` | 需有效 JWT | 员工/管理员均可 | | `/api/health` | 无需认证 | 健康检查 | ## 4. 安全边界说明 > **前端路由守卫仅提供用户体验层面的菜单隐藏和路径拦截,不能作为安全边界。** > **所有权限校验必须在后端 API 层强制执行。** > > 即使员工通过直接输入 URL 访问 `/knowledge/materials`: > 1. 前端路由守卫会拦截并重定向 → UX 保护 > 2. 如果前端拦截被绕过,后端 API 返回 403 → 真正安全边界