diff --git a/API文档.md b/API文档.md new file mode 100644 index 0000000..646be5d --- /dev/null +++ b/API文档.md @@ -0,0 +1,549 @@ +# 进度管理系统 API 文档 + +## 基础信息 + +- 基础 URL: `http://localhost:1218` +- 所有请求和响应均使用 JSON 格式 +- 所有需要认证的接口都需要在请求头中携带 `Authorization: Bearer {token}` + +## 通用响应格式 + +```json +{ + "code": 10000, // 响应码 + "message": "成功", // 响应消息 + "data": {} // 响应数据 +} +``` + +### 响应码说明 + +| 响应码 | 说明 | 消息 | +| ------ | ---------- | ---------- | +| 10000 | 成功 | 成功 | +| 10001 | 参数错误 | 参数无效 | +| 10002 | 邮箱重复 | 邮箱已存在 | +| 10003 | 用户不存在 | 用户不存在 | +| 10004 | 密码错误 | 密码错误 | +| 10005 | 邮箱已存在 | 邮箱已存在 | +| 10006 | 未授权 | 未授权 | +| 10007 | 令牌过期 | 令牌已过期 | +| 10008 | 令牌无效 | 无效的令牌 | +| 10009 | 系统错误 | 系统错误 | + +## 字段说明 + +### 用户相关字段 + +1. **角色 (roles)** + + - 1: 教师 + - 2: 普通管理员 + - 3: 沟通联络人 + - 4: 系统管理员 + +2. **岗位 (jobs)** + + - 1: 课程制作教师 + - 2: 课程购买方项目负责人 + - 3: 课程制作方沟通联络人 + - 4: 系统制作方项目负责人 + +3. **用户状态 (status)** + - 1: 正常 + - 0: 禁用 + +### 课程任务相关字段 + +1. **进度状态 (progressStatus)** + - 0: 脚本上传 + - 1: 脚本确认 + - 2: 视频拍摄 + - 3: 后期制作 + - 4: 任务完成 + +## 用户接口 + +### 1. 用户注册 + +- **接口**:`POST /api/users` +- **描述**:创建新用户 +- **认证**:不需要 +- **请求体**: + ```json + { + "username": "testuser", // 用户名,不可为空 + "email": "test@example.com", // 邮箱,不可为空且唯一 + "password": "password123", // 密码,不可为空 + "departmentId": 1, // 部门ID,不可为空,关联departments表 + "roles": 1, // 角色:1-教师,2-普通管理员,3-沟通联络人,4-系统管理员 + "jobs": 1, // 岗位:1-课程制作教师,2-课程购买方项目负责人,3-课程制作方沟通联络人,4-系统制作方项目负责人 + "avatar": "http://example.com/avatar.jpg", // 头像URL,可选 + "creatorId": 1 // 创建者ID,不可为空 + } + ``` +- **成功响应**: + ```json + { + "code": 10000, + "message": "成功", + "data": null + } + ``` +- **错误响应**: + ```json + { + "code": 10005, + "message": "邮箱已存在", + "data": null + } + ``` + +### 2. 用户登录 + +- **接口**:`POST /api/users/login` +- **描述**:用户登录获取 token +- **认证**:不需要 +- **请求体**: + ```json + { + "email": "test@example.com", // 邮箱 + "password": "password123", // 密码 + "remember": true // 是否记住登录(可选) + } + ``` +- **成功响应**: + ```json + { + "code": 10000, + "message": "成功", + "data": { + "token": "eyJhbGciOiJIUzM4NCJ9..." // JWT令牌 + } + } + ``` + +### 3. 用户登出 + +- **接口**:`POST /api/users/logout` +- **描述**:用户登出,使当前 token 失效 +- **认证**:需要 +- **成功响应**: + ```json + { + "code": 10000, + "message": "成功", + "data": "登出成功" + } + ``` + +### 4. 获取当前用户信息 + +- **接口**:`GET /api/users/current` +- **描述**:获取当前登录用户信息 +- **认证**:需要 +- **成功响应**: + ```json + { + "code": 10000, + "message": "成功", + "data": { + "id": 12, + "username": "testuser", + "email": "test@example.com", + "departmentId": 1, + "roles": 1, + "jobs": 1, + "avatar": null, + "creatorId": 1, + "status": 1, + "createdAt": 1734578081, + "updatedAt": 1734578081, + "enabled": true, + "authorities": [ + { + "authority": "ROLE_USER" + } + ] + } + } + ``` + +### 5. 获取用户列表 + +- **接口**:`GET /api/users/list` +- **描述**:分页获取用户列表 +- **认证**:需要 +- **查询参数**: + - `page`: 页码(从 1 开始) + - `limit`: 每页数量(默认 10) +- **成功响应**: + ```json + { + "code": 10000, + "message": "成功", + "data": { + "list": [ + { + "id": 1, + "username": "admin", + "email": "admin@example.com", + "departmentId": 1, + "roles": 4, + "jobs": 4, + "avatar": null, + "creatorId": 1, + "status": 1, + "createdAt": 1734578081, + "updatedAt": 1734578081 + } + ], + "total": 12, + "currentPage": 1, + "pageSize": 10 + } + } + ``` + +### 6. 禁用用户 + +- **接口**:`POST /api/users/disable/{userId}` +- **描述**:禁用指定用户 +- **认证**:需要 +- **路径参数**: + - `userId`: 用户 ID +- **成功响应**: + ```json + { + "code": 10000, + "message": "成功", + "data": "用户已禁用" + } + ``` + +### 7. 查询部门用户列表 + +- **接口**:`GET /api/users/department/{departmentId}` +- **描述**:获取指定部门下的所有正常状态用户列表 +- **认证**:需要 +- **路径参数**: + - `departmentId`: 部门 ID +- **成功响应**: + ```json + { + "code": 10000, + "message": "成功", + "data": [ + { + "id": 2, + "username": "普通管理员账号2", + "email": "user2@qq.com", + "password": null, + "departmentId": 1, + "roles": 2, + "jobs": 2, + "avatar": null, + "creatorId": 1, + "status": 1, + "createdAt": 1734504506, + "updatedAt": 1734504506, + "enabled": true, + "authorities": [ + { + "authority": "ROLE_USER" + } + ], + "accountNonExpired": true, + "accountNonLocked": true, + "credentialsNonExpired": true + } + ] + } + ``` +- **错误响应**: + ```json + { + "code": 50000, + "message": "获取部门用户列表失败", + "data": null + } + ``` + +## 课程任务接口 + +### 1. 获取课程任务列表 + +- **接口**:`GET /api/lesson-tasks` +- **描述**:分页获取课程任务列表 +- **认证**:需要 +- **查询参数**: + - `page`: 页码(从 1 开始) + - `size`: 每页数量(默认 10) + - `userId`: 用户 ID(可选) +- **成功响应**: + ```json + { + "code": 10000, + "message": "成功", + "data": { + "content": [ + { + "id": 6, + "courseName": "Test Course", + "microLessonName": "Test Lesson", + "userId": 12, + "progressStatus": 1, + "scriptUploadTime": 1734578081, + "scriptConfirmTime": 1734578081, + "videoCaptureTime": 1734578081, + "videoConfirmTime": 1734578081, + "finishTime": 1734578081, + "advise": "Test advice", + "createdAt": 1734578081, + "updatedAt": 1734578081 + } + ], + "totalElements": 4, + "totalPages": 1, + "size": 10, + "number": 0, + "first": true, + "last": true, + "empty": false + } + } + ``` + +### 2. 获取单个课程任务 + +- **接口**:`GET /api/lesson-tasks/{id}` +- **描述**:获取指定 ID 的课程任务 +- **认证**:需要 +- **路径参数**: + - `id`: 课程任务 ID +- **成功响应**: + ```json + { + "code": 10000, + "message": "成功", + "data": { + "id": 6, + "courseName": "Test Course", + "microLessonName": "Test Lesson", + "userId": 12, + "progressStatus": 1, + "scriptUploadTime": 1734578081, + "scriptConfirmTime": 1734578081, + "videoCaptureTime": 1734578081, + "videoConfirmTime": 1734578081, + "finishTime": 1734578081, + "advise": "Test advice", + "createdAt": 1734578081, + "updatedAt": 1734578081 + } + } + ``` + +### 3. 创建课程任务 + +- **接口**:`POST /api/lesson-tasks` +- **描述**:创建新的课程任务 +- **认证**:需要 +- **请求体**: + ```json + { + "courseName": "Java基础", // 课程名称,不可为空 + "microLessonName": "Java变量", // 微课名称,不可为空 + "userId": 1, // 负责人ID,不可为空,关联users表 + "advise": "请注意讲解速度" // 任务建议或备注,可选 + } + ``` +- **成功响应**: + ```json + { + "code": 10000, + "message": "成功", + "data": { + "id": 6, + "courseName": "Java基础", + "microLessonName": "Java变量", + "userId": 1, + "progressStatus": 1, + "scriptUploadTime": , + "scriptConfirmTime": , + "videoCaptureTime": , + "videoConfirmTime": , + "finishTime": , + "advise": "请注意讲解速度", + "createdAt": 1734578081, + "updatedAt": 1734578081 + } + } + ``` + +### 4. 更新课程任务 + +- **接口**:`PUT /api/lesson-tasks/{id}` +- **描述**:更新指定 ID 的课程任务 +- **认证**:需要 +- **路径参数**: + - `id`: 课程任务 ID +- **请求体**: + ```json + { + "courseName": "Updated Course", // 课程名称 + "microLessonName": "Updated Lesson", // 微课名称 + "userId": 12, // 用户ID + "progressStatus": 2, // 进度状态 + "scriptUploadTime": 1734578081, // 脚本上传时间 + "scriptConfirmTime": 1734578081, // 脚本确认时间 + "videoCaptureTime": 1734578081, // 视频录制时间 + "videoConfirmTime": 1734578081, // 视频确认时间 + "finishTime": 1734578081, // 完成时间 + "advise": "Updated advice" // 建议 + } + ``` +- **成功响应**: + ```json + { + "code": 10000, + "message": "成功", + "data": { + "id": 6, + "courseName": "Updated Course", + "microLessonName": "Updated Lesson", + "userId": 12, + "progressStatus": 2, + "scriptUploadTime": 1734578081, + "scriptConfirmTime": 1734578081, + "videoCaptureTime": 1734578081, + "videoConfirmTime": 1734578081, + "finishTime": 1734578081, + "advise": "Updated advice", + "createdAt": 1734578081, + "updatedAt": 1734578081 + } + } + ``` + +### 5. 删除课程任务 + +- **接口**:`DELETE /api/lesson-tasks/{id}` +- **描述**:删除指定 ID 的课程任务 +- **认证**:需要 +- **路径参数**: + - `id`: 课程任务 ID +- **成功响应**: + ```json + { + "code": 10000, + "message": "成功", + "data": null + } + ``` + +### 6. 按部门 ID 查询课程任务 + +- **接口**:`GET /api/lesson-tasks/department/{departmentId}` +- **描述**:获取指定部门下正常状态用户的课程任务列表(分页) +- **认证**:需要 +- **路径参数**: + - `departmentId`: 部门 ID +- **查询参数**: + - `page`: 页码(从 1 开始) + - `size`: 每页数量(默认 10) +- **成功响应**: + ```json + { + "code": 10000, + "message": "成功", + "data": { + "content": [ + { + "id": 1, + "courseName": "物理", + "microLessonName": "微课1-1", + "userId": 1, + "username": "教师账号1", // 新增:用户名字段 + "progressStatus": 4, + "scriptUploadTime": 1734498510, + "scriptConfirmTime": 1734498510, + "videoCaptureTime": 1734498510, + "videoConfirmTime": 1734498510, + "finishTime": 1734498510, + "advise": null, + "createdAt": 1734578081, + "updatedAt": 1734580393 + } + ], + "totalElements": 10, + "totalPages": 1, + "size": 10, + "number": 0, + "first": true, + "last": true, + "empty": false + } + } + ``` + +### 7. 更新课程任务进度 + +- **接口**:`PUT /api/lesson-tasks/{id}` +- **描述**:更新课程任务的进度状态和建议 +- **认证**:需要 +- **路径参数**: + - `id`: 课程任务 ID +- **请求体**: + ```json + { + "progressStatus": 2, // 进度状态(可选) + "advise": "{\"method\":\"wechat\",\"uploaded\":true}" // 建议(可选) + } + ``` +- **说明**: + - 更新进度状态时会自动更新对应的时间戳: + - 状态 1:更新 scriptUploadTime + - 状态 2:更新 scriptConfirmTime + - 状态 3:更新 videoCaptureTime + - 状态 4:更新 videoConfirmTime + - 状态 5:更新 finishTime + - 只会更新请求体中包含的字段,未提供的字段保持不变 +- **成功响应**: + ```json + { + "code": 10000, + "message": "成功", + "data": { + "id": 10, + "courseName": "测试课程", + "microLessonName": "测试微课", + "userId": 1, + "progressStatus": 2, + "scriptUploadTime": null, + "scriptConfirmTime": 1734663755, + "videoCaptureTime": null, + "videoConfirmTime": null, + "finishTime": null, + "advise": "{\"method\":\"wechat\",\"uploaded\":true}", + "createdAt": 1734602440, + "updatedAt": 1734663755 + } + } + ``` + +## 注意事项 + +1. 所有需要认证的接口必须在请求头中携带有效的 JWT 令牌 +2. 所有时间戳字段均为秒级时间戳 +3. 分页接口的页码从 1 开始 +4. 用户密码在传输和存储时都会进行加密处理 +5. 课程任务的 progressStatus 字段状态码说明: + - 0: 脚本上传 + - 1: 脚本确认 + - 2: 视频拍摄 + - 3: 后期制作 + - 4: 任务完成 +6. 用户状态说明: + - 1: 正常 + - 0: 禁用 diff --git a/components.d.ts b/components.d.ts index ea1cd36..6e75820 100644 --- a/components.d.ts +++ b/components.d.ts @@ -12,6 +12,7 @@ declare module 'vue' { WdButton: typeof import('wot-design-uni/components/wd-button/wd-button.vue')['default'] WdCell: typeof import('wot-design-uni/components/wd-cell/wd-cell.vue')['default'] WdCellGroup: typeof import('wot-design-uni/components/wd-cell-group/wd-cell-group.vue')['default'] + WdCheckbox: typeof import('wot-design-uni/components/wd-checkbox/wd-checkbox.vue')['default'] WdCollapse: typeof import('wot-design-uni/components/wd-collapse/wd-collapse.vue')['default'] WdCollapseItem: typeof import('wot-design-uni/components/wd-collapse-item/wd-collapse-item.vue')['default'] WdDropMenu: typeof import('wot-design-uni/components/wd-drop-menu/wd-drop-menu.vue')['default'] diff --git a/src/api/BussApi.ts b/src/api/BussApi.ts index 160b936..507f5fb 100644 --- a/src/api/BussApi.ts +++ b/src/api/BussApi.ts @@ -1,59 +1,137 @@ import http from "@/http/HttpClient"; import { useUser } from "@/stores/useUser"; import type { PagedData } from "@/types/api/common"; -import type { Lesson } from "@/types/api/lesson"; -import type { User } from "@/types/api/user"; - -export interface LoginRequest extends Record { - email: string; - password: string; - remember: string; -} +import type { CreateLessonTaskRequest, LessonTask, UpdateLessonTaskRequest } from "@/types/api/lesson"; +import type { LoginRequest } from "@/types/api/auth"; +import type { CreateUserRequest, User } from "@/types/api/user"; +/** + * 业务API类 + */ export default class BussApi { + /** + * 用户登录 + * @param params - 登录请求参数 + * @param params.email - 用户邮箱 + * @param params.password - 用户密码 + * @param params.remember - 是否记住登录状态 + * @returns Promise<{token: string}> 返回包含token的对象 + */ static login(params: LoginRequest): Promise<{ token: string }> { return http .server() - .post("/login", params) - .then((res) => res.data); + .post("users/login", params) + .then((res) => res.data.data); } + /** + * 获取当前用户信息 + * @param token - 用户认证token + * @returns Promise 返回用户信息 + */ static profile(token: string): Promise { return http .server() - .get("/user/online", { + .get("users/current", { headers: { Authorization: `Bearer ${token}`, }, }) - .then((res) => res.data); + .then((res) => res.data.data); } - static lessons(page: number = 1, limit: number = 20) { + /** + * 用户登出 + * @returns Promise 返回登出结果 + */ + static logout(): Promise { const user = useUser(); return http .server() - .get>("/lesson/task", { + .post("users/logout", null, { headers: { Authorization: `Bearer ${user.token}`, }, - params: { page, limit }, }) - .then((res) => { - if (user.hasJobTag("A")) { - res.data.data = res.data.data.filter( - (lesson) => lesson.user_id === user.userinfo?.id - ); - } - return res.data; - }); + .then((res) => res.data.data); } - static course(id: number): Promise { + /** + * 获取课程任务列表 + * @param page - 页码,默认为1 + * @param size - 每页数量,默认为10 + * @param userId - 可选的用户ID,用于筛选特定用户的课程任务 + * @returns Promise<{ + code: number; + message: string; + data: { + content: LessonTask[]; + pageable: { + pageNumber: number; + pageSize: number; + sort: { + empty: boolean; + unsorted: boolean; + sorted: boolean; + }; + offset: number; + paged: boolean; + unpaged: boolean; + }; + totalElements: number; + totalPages: number; + last: boolean; + first: boolean; + empty: boolean; + number: number; + size: number; + numberOfElements: number; + }; + }> 返回分页的课程任务数据 + */ + static getLessonTasks( + page: number = 1, + size: number = 20, + userId?: number + ): Promise<{ + code: number; + message: string; + data: { + content: LessonTask[]; + pageable: { + pageNumber: number; + pageSize: number; + sort: { + empty: boolean; + unsorted: boolean; + sorted: boolean; + }; + offset: number; + paged: boolean; + unpaged: boolean; + }; + totalElements: number; + totalPages: number; + last: boolean; + first: boolean; + empty: boolean; + number: number; + size: number; + numberOfElements: number; + }; + }> { const user = useUser(); + const params: any = { + page, + size, + }; + if (userId) { + params.userId = userId; + } return http .server() - .get(`/lesson/task/${id}`, { + .get("lesson-tasks", { + params, headers: { Authorization: `Bearer ${user.token}`, }, @@ -61,11 +139,209 @@ export default class BussApi { .then((res) => res.data); } - static editCourse(id: number, params: Partial): Promise { + /** + * 获取单个课程任务详情 + * @param id - 课程任务ID + * @returns Promise 返回课程任务详情 + */ + static getLessonTask(id: number): Promise { const user = useUser(); return http .server() - .put(`/lesson/task/${id}`, params, { + .get(`lesson-tasks/${id}`, { + headers: { + Authorization: `Bearer ${user.token}`, + }, + }) + .then((res) => res.data.data); + } + + /** + * 获取课程详情 + * @param lessonId - 课程ID + * @returns Promise 返回课程详情 + */ + static getLessonDetail(lessonId: number): Promise { + const user = useUser(); + return http + .server() + .get(`lesson/${lessonId}`, { + headers: { + Authorization: `Bearer ${user.token}`, + }, + }) + .then((res) => res.data.data); + } + + /** + * 更新课程进度 + * @param lessonId - 课程ID + * @returns Promise + */ + static updateLessonProgress(lessonId: number): Promise { + const user = useUser(); + return http + .server() + .post(`lesson/${lessonId}/progress`, null, { + headers: { + Authorization: `Bearer ${user.token}`, + }, + }) + .then((res) => res.data.data); + } + + /** + * 更新课程任务 + * @param id - 课程任务ID + * @param params - 更新参数,所有字段都是可选的 + * @returns Promise 返回更新后的课程任务 + */ + static updateLessonTask(id: number, params: UpdateLessonTaskRequest): Promise { + const user = useUser(); + return http + .server() + .put(`lesson-tasks/${id}`, params, { + headers: { + Authorization: `Bearer ${user.token}`, + }, + }) + .then((res) => res.data.data); + } + + /** + * 删除课程任务 + * @param id - 课程任务ID + * @returns Promise + */ + static deleteLessonTask(id: number): Promise { + const user = useUser(); + return http + .server() + .delete(`lesson-tasks/${id}`, { + headers: { + Authorization: `Bearer ${user.token}`, + }, + }) + .then((res) => res.data.data); + } + + /** + * 获取部门课程任务列表 + * @param departmentId - 部门ID + * @param page - 页码,默认为1 + * @param size - 每页数量,默认为20 + * @returns Promise<{ + * code: number; // 响应状态码 + * message: string; // 响应消息 + * data: { + * list: Array<{ + * id: number; // 用户ID + * username: string; // 用户名 + * email: string; // 邮箱 + * departmentId: number; // 部门ID + * roles: number; // 角色 + * jobs: number; // 岗位 + * avatar: string; // 头像 + * creatorId: number; // 创建者ID + * status: number; // 状态 + * createdAt: number; // 创建时间 + * updatedAt: number; // 更新时间 + * }>; + * total: number; // 总数 + * currentPage: number; // 当前页 + * pageSize: number; // 每页数量 + * }; + * }> 返回分页的课程任务数据 + */ + static getDepartmentLessonTasks( + departmentId: number, + page: number = 1, + size: number = 20 + ): Promise<{ + code: number; + message: string; + data: { + content: LessonTask[]; // 课程任务列表 + pageable: { + pageNumber: number; // 当前页码 + pageSize: number; // 每页大小 + sort: { + empty: boolean; // 是否无排序 + unsorted: boolean; // 是否未排序 + sorted: boolean; // 是否已排序 + }; + offset: number; // 偏移量 + paged: boolean; // 是否分页 + unpaged: boolean; // 是否不分页 + }; + totalElements: number; // 总记录数 + totalPages: number; // 总页数 + last: boolean; // 是否最后一页 + first: boolean; // 是否第一页 + empty: boolean; // 是否为空 + number: number; // 当前页码 + size: number; // 每页大小 + numberOfElements: number; // 当前页记录数 + }; + }> { + const user = useUser(); + const params: any = { + page, + size, + departmentId + }; + return http + .server() + .get("lesson-tasks/department", { + params, + headers: { + Authorization: `Bearer ${user.token}`, + }, + }) + .then((res) => res.data); + } + + /** + * 获取部门下的所有教师 + * @param departmentId - 部门ID + * @returns Promise<{ + * code: number; // 响应状态码 + * message: string; // 响应消息 + * data: { + * list: Array<{ + * id: number; // 用户ID + * username: string; // 用户名 + * email: string; // 邮箱 + * departmentId: number; // 部门ID + * roles: number; // 角色 + * jobs: number; // 岗位 + * status: number; // 状态 + * createdAt: number; // 创建时间 + * updatedAt: number; // 更新时间 + * }>; + * total: number; // 总数 + * }; + * }> + */ + static getDepartmentTeachers(departmentId: number): Promise<{ + code: number; + message: string; + data: Array<{ + id: number; + username: string; + email: string; + departmentId: number; + roles: number; + jobs: number; + status: number; + createdAt: number; + updatedAt: number; + }>; + }> { + const user = useUser(); + return http + .server() + .get(`users/department/${departmentId}`, { headers: { Authorization: `Bearer ${user.token}`, }, diff --git a/src/components/TabBar.vue b/src/components/TabBar.vue index fe906dc..f6b54b3 100644 --- a/src/components/TabBar.vue +++ b/src/components/TabBar.vue @@ -3,6 +3,7 @@ import { nextTick, ref } from 'vue'; import { useRouter, useRoute } from 'uni-mini-router' import { onMounted, computed, watch } from 'vue'; import { useTabbar } from '@/stores/useTabbar'; +import { useUser } from '@/stores/useUser'; // Import the useUser store const props = defineProps({ currentName: { @@ -13,6 +14,7 @@ const props = defineProps({ const router = useRouter() const tab = useTabbar() +const user = useUser() // Get the user store instance // const isFirstTime = ref(true) @@ -28,25 +30,37 @@ const tabWhitelist = ['home', 'progress', 'my'] const nameLabelIconMap = { home: { title: '进度查看', - icon: 'dashboard' + icon: 'dashboard', + roles: ['teacher', 'admin', 'liaison', 'sysadmin'] as const // 使用 as const 来确保类型正确 }, progress: { title: '进度管理', - icon: 'transfer' + icon: 'transfer', + roles: ['teacher', 'admin', 'sysadmin'] as const }, my: { title: '我的', - icon: 'user' + icon: 'user', + roles: ['teacher', 'admin', 'liaison', 'sysadmin'] as const } } -const tabList = computed(() => router.routes.filter((r: { name: string }) => tabWhitelist.includes(r.name)).map((route: { name: keyof typeof nameLabelIconMap }) => { - return { - name: route.name, - title: nameLabelIconMap[route.name]?.title, - icon: nameLabelIconMap[route.name]?.icon - } -})) +const tabList = computed(() => { + // 过滤出当前用户有权限看到的导航项 + return router.routes + .filter((r: { name: string }) => { + const config = nameLabelIconMap[r.name as keyof typeof nameLabelIconMap] + // 检查该路由是否在配置中,且用户是否有权限访问 + return config && config.roles.some(role => user.hasRole(role as "teacher" | "admin" | "liaison" | "sysadmin")) + }) + .map((route: { name: keyof typeof nameLabelIconMap }) => { + return { + name: route.name, + title: nameLabelIconMap[route.name]?.title, + icon: nameLabelIconMap[route.name]?.icon + } + }) +})