# 开发日志 - 2026-03-12 ## 今日任务:代码重构(规范化) 根据 `docs/统一开发规范.md` 和 `docs/前端项目规范.md` 进行代码重构。 --- ## 后端重构阶段 ### 阶段 1:添加公共组件(基础设施) ✅ **新增文件:** 1. `src/common/dto/result.dto.ts` - 统一响应格式 DTO - `ResultDto` - 统一响应格式 `{ code, message, data }` - `PageResultDto` - 分页响应格式 `{ items, total, page, pageSize, totalPages }` 2. `src/common/dto/page-query.dto.ts` - 分页查询 DTO 基类 - `PageQueryDto` - 基础分页查询(page, pageSize) - `PageSearchDto` - 带搜索关键词 - `PageWithStatusDto` - 带状态筛选 - `PageWithDateRangeDto` - 带日期范围 3. `src/common/interceptors/transform.interceptor.ts` - 响应转换拦截器 - 自动将 Controller 返回数据包装为统一格式 - 支持 `@SkipTransform()` 跳过转换 4. `src/common/utils/json.util.ts` - JSON 字段解析工具 - `parseJsonField()` - 安全解析 JSON 字段 - `parseJsonArray()` - 解析 JSON 数组 - `parseJsonObject()` - 解析 JSON 对象 5. `src/common/utils/pagination.util.ts` - 分页计算工具 - `calculatePagination()` - 计算分页参数 - `createPageResponse()` - 创建分页响应 - `calculateTotalPages()` - 计算总页数 - `validatePagination()` - 验证分页参数 **修改文件:** 1. `package.json` - 添加 `@nestjs/swagger` 依赖(v11.x) 2. `src/main.ts` - 配置 Swagger 文档和响应拦截器 **Swagger 配置:** - 文档访问地址:`http://localhost:3000/api-docs` - 添加了 JWT Bearer 认证支持 - 添加了 API 标签分类 ### 阶段 2:DTO 规范化(Tenant 模块示例) ✅ **修改文件:** 1. `src/modules/tenant/dto/tenant.dto.ts` - 为所有 DTO 添加 `@ApiProperty` 装饰器 - 添加 description、example、required 等属性 2. `src/modules/tenant/tenant.controller.ts` - 添加 `@ApiTags`、`@ApiOperation`、`@ApiResponse` 装饰器 - 添加 `@ApiBearerAuth` 认证装饰器 --- ## 前端重构阶段 ### 阶段 1:添加 Orval 配置 ✅ **新增文件:** 1. `orval.config.ts` - Orval 配置文件 2. `src/api/generated/mutator.ts` - 自定义请求拦截器 3. `src/api/client.ts` - API 客户端统一入口 4. `src/api/teacher.adapter.ts` - 教师端 API 适配层 **修改文件:** 1. `package.json` - 添加 orval 依赖和生成脚本 - `api:update` - 生成 API 客户端 - `api:watch` - 监听模式生成 2. `vite.config.ts` - 添加文件路由插件 **已安装依赖:** - orval (^8.5.3) - unplugin-vue-router (^0.19.2) ### 阶段 2:配置文件路由 ✅ **配置内容:** - 使用 `src/views` 作为路由文件夹 - 支持 `.vue` 扩展名 - 同步导入模式 --- ## 待完成任务 ### 后端 - [ ] 阶段 3:全面推广 DTO 规范化 - [ ] 添加 @ApiQuery 装饰器(Course、SchoolCourse、Lesson 等模块) - [ ] 添加 @ApiBody 装饰器(定义请求体类型) - [ ] Auth 模块 - [ ] Course 模块 - [ ] Lesson 模块 - [ ] SchoolCourse 模块 - [ ] 其他模块 ### 前端 - [x] 运行 `npm run api:update` 生成 API 客户端 - [x] 修复 PrepareModeView.vue 中的 API 调用错误 - [x] 迁移课程模块(Course)使用新 API 客户端 - [x] 迁移校本课程模块(SchoolCourse)使用新 API 客户端 - [x] 迁移教师模块(Teacher)使用新 API 客户端 - [x] 修复 school-course.ts 中的类型错误(string vs number) - [x] 清理未使用的 teacher.adapter.ts 文件 - [ ] 迁移其他 API 模块(lesson, auth 等) --- ## 新增完成 ### 后端 - **CourseLesson 控制器重构** ✅ - 移除类级路径参数 `@Controller('admin/courses/:courseId/lessons')` - 改为在每个方法中显式声明完整路径 `@Get(':courseId/lessons')` - 修复了 Orval 验证错误(PUT/DELETE 方法的路径参数问题) - **后端 DTO 规范化** ✅ - **Course 控制器**:添加 @ApiQuery、@ApiBody、@ApiOperation 装饰器 - **Lesson 控制器**:添加 @ApiQuery、@ApiBody、@ApiOperation 装饰器 - **TeacherCourse 控制器**:添加 @ApiQuery、@ApiBody、@ApiOperation 装饰器 - **SchoolCourse 控制器**:添加 @ApiQuery、@ApiBody、@ApiOperation 装饰器 ### 前端 - **Orval API 客户端生成成功** ✅ - 生成文件:`src/api/generated/index.ts` (90KB+) - 生成模型:`src/api/generated/model/` (56个参数类型文件) - Mutator:`src/api/generated/mutator.ts` - TypeScript 编译通过 - **API 方法现在包含完整的参数定义** ✅ - **课程模块迁移到新 API 客户端** ✅ - 更新 `src/api/course.ts` 使用 Orval 生成的 API - 导入参数类型:`CourseControllerFindAllParams` - 保持向后兼容的接口 - **校本课程模块迁移到新 API 客户端** ✅ - 更新 `src/api/school-course.ts` 使用 Orval 生成的 API - 支持学校端和教师端两套接口 - **教师模块迁移到新 API 客户端** ✅ - 更新 `src/api/teacher.ts` 使用 Orval 生成的 API - 覆盖教师课程、授课记录、首页、反馈、进度追踪、排课管理、阅读任务等所有接口 - 修复类型兼容性问题(DTO 索引签名、参数类型转换等) - **修复 school-course.ts 类型错误** ✅ - 移除所有 `String()` 类型转换 - 生成的 SchoolCourse API 期望 `number` 类型 ID,与 Teacher API 不同(期望 `string`) - 修复所有学校端和教师端校本课程接口的类型问题 - **清理 teacher.adapter.ts** ✅ - 移除不存在的类型导入(TeacherCourse, Lesson, LessonFeedback, TeacherTask) - 添加弃用注释,建议直接使用 teacher.ts 中的函数 - 改为重新导出 teacher.ts,保持向后兼容 - **修复 client.ts API 客户端** ✅ - 修复导入错误的函数名(`getReadingPlatformAPI` → `getApi`) - 简化导出结构,直接使用 `api` 作为 API 客户端实例 - 修复类型守卫和类型断言问题 - 改进 `unwrapData` 和 `unwrapPageData` 函数的类型安全 - **修复其他 API 相关文件** ✅ - 移除 mutator.ts 中未使用的 `ResultDto` 导入 - 修复 lesson.ts 中未使用的 `lessonId` 参数 - **创建文件路由目录结构** ✅ - 更新 vite.config.ts 使用正确的 `unplugin-vue-router` 插件导入 - 创建动态路由配置 `src/router/index.ts` - 保留传统路由配置作为 `src/router/manual-routes.ts` 备份 - 支持自动路由和传统路由的平滑切换 --- ## 验证步骤 ### 后端验证 ```bash cd /Users/retirado/Program/ccProgram_0312/reading-platform-backend npm start # 访问 http://localhost:3000/api-docs 查看 Swagger 文档 ``` ### 前端验证 ```bash cd /Users/retirado/Program/ccProgram_0312/reading-platform-frontend npm run api:update npm run dev ``` --- ## 遇到的问题 1. **@nestjs/swagger 版本冲突** - 问题:@nestjs/swagger@11.x 需要 @nestjs/common@11.x - 解决:使用 `--legacy-peer-deps` 安装 2. **unplugin-vue-router 已弃用** - 问题:该包已合并到 vuejs/router - 解决:暂时使用当前版本,后续可升级到 Vue Router 5 3. **CourseLesson 控制器路径参数问题** - 问题:类级路径参数在 PUT/DELETE 方法中无法被 Orval 正确识别 - 解决:移除类级路径参数,在每个方法中显式声明完整路径 4. **Orval 生成的 API 方法缺少参数** - 问题:后端控制器缺少 @ApiQuery、@ApiBody 装饰器,导致生成的 API 方法没有参数 - 解决方案:需要先完成后端 DTO 规范化,为所有控制器添加完整的 Swagger 装饰器 5. **PrepareModeView.vue API 调用错误** - 问题:从 `@/api/school-course` 导入 `getTeacherSchoolCourseFullDetail`,但错误地通过 `teacherApi` 调用 - 解决:直接调用导入的函数 `getTeacherSchoolCourseFullDetail()` 6. **Teacher.ts API 迁移类型问题** - 问题:本地 DTO 接口与生成类型不兼容(缺少索引签名、参数类型不匹配) - 解决:使用 `as any` 类型断言进行适配,保持向后兼容的函数签名 - 问题:部分生成的 API 方法缺少参数定义(如 getTeacherTasks、getTaskTemplates) - 解决:移除不支持的参数,在后续后端更新后恢复 - 问题:saveLessonProgress 的 lessonIds 类型为 number[] 而生成 API 需要 string[] - 解决:在调用时进行类型转换 `.map(String)` 7. **SchoolCourse.ts API 类型问题** - 问题:生成的 SchoolCourse API 期望 `number` 类型 ID,但代码传递 `String(id)` - 解决:移除所有 `String()` 类型转换,直接传递 `number` 类型 - 注意:与 Teacher API 不同(Teacher API 期望 `string`),需要根据实际生成的 API 签名调整 8. **Teacher.adapter.ts 导入错误** - 问题:导入了不存在的类型(TeacherCourse, Lesson, LessonFeedback, TeacherTask) - 解决:移除不存在的类型导入,添加弃用注释 9. **Client.ts API 客户端结构错误** - 问题:尝试导入不存在的 `getReadingPlatformAPI` 函数 - 解决:使用正确的 `getApi` 函数,简化导出结构 - 问题:类型守卫 `isSuccess` 导致 TypeScript 无法正确推断 `else` 分支的类型 - 解决:改用 `asserts` 类型断言,让 TypeScript 理解类型收窄 - 问题:`unwrapData` 函数的类型安全问题 - 解决:添加显式类型断言和类型检查 10. **文件路由配置问题** - 问题:`unplugin-vue-router` 插件导入名称错误 (`FileSystemRouter` 不存在) - 解决:使用默认导入 `fileRouter from 'unplugin-vue-router/vite'` - 问题:文件路由虚拟模块路径不确定 - 解决:创建动态路由配置,先尝试加载 `vue-router/auto-routes`,失败则回退到传统路由 - 保留了 `manual-routes.ts` 作为备用,确保系统稳定性 --- ## 备注 - 本次重构遵循渐进式原则,保持向后兼容 - 所有新增文件都遵循规范要求的目录结构 - 适配层确保旧代码可以继续工作