kindergarten_java/docs/dev-logs/2026-03-12.md
Claude Opus 4.6 2f5ad32820 refactor: 代码重构 - API规范化和文件路由配置
## 后端重构

### 新增基础设施
- src/common/dto/ - 统一响应格式和分页查询DTO基类
- src/common/interceptors/ - 响应转换拦截器
- src/common/utils/ - JSON解析和分页计算工具函数

### DTO规范化
- Course、Lesson、TeacherCourse、SchoolCourse、Tenant控制器添加Swagger装饰器
- 添加@ApiQuery、@ApiBody、@ApiOperation完善API文档
- 修复CourseLesson控制器路径参数问题

## 前端重构

### Orval API客户端生成
- 添加orval配置和生成脚本
- 生成完整的类型安全API客户端 (src/api/generated/)
- 导入56个参数类型文件

### API模块迁移
- src/api/course.ts - 迁移使用Orval生成API
- src/api/school-course.ts - 修复类型错误(number vs string)
- src/api/teacher.ts - 完整迁移教师端API
- src/api/client.ts - 重构API客户端统一入口
- src/api/lesson.ts - 修复未使用参数

### 文件路由配置
- 配置unplugin-vue-router插件
- 创建动态路由配置支持自动路由和传统路由切换
- 添加路由守卫保留原有权限逻辑

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 13:05:20 +08:00

9.9 KiB
Raw Blame History

开发日志 - 2026-03-12

今日任务:代码重构(规范化)

根据 docs/统一开发规范.mddocs/前端项目规范.md 进行代码重构。


后端重构阶段

阶段 1添加公共组件基础设施

新增文件:

  1. src/common/dto/result.dto.ts - 统一响应格式 DTO

    • ResultDto<T> - 统一响应格式 { code, message, data }
    • PageResultDto<T> - 分页响应格式 { 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 标签分类

阶段 2DTO 规范化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 模块
    • 其他模块

前端

  • 运行 npm run api:update 生成 API 客户端
  • 修复 PrepareModeView.vue 中的 API 调用错误
  • 迁移课程模块Course使用新 API 客户端
  • 迁移校本课程模块SchoolCourse使用新 API 客户端
  • 迁移教师模块Teacher使用新 API 客户端
  • 修复 school-course.ts 中的类型错误string vs number
  • 清理未使用的 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个参数类型文件)
    • Mutatorsrc/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 客户端

    • 修复导入错误的函数名(getReadingPlatformAPIgetApi
    • 简化导出结构,直接使用 api 作为 API 客户端实例
    • 修复类型守卫和类型断言问题
    • 改进 unwrapDataunwrapPageData 函数的类型安全
  • 修复其他 API 相关文件

    • 移除 mutator.ts 中未使用的 ResultDto 导入
    • 修复 lesson.ts 中未使用的 lessonId 参数
  • 创建文件路由目录结构

    • 更新 vite.config.ts 使用正确的 unplugin-vue-router 插件导入
    • 创建动态路由配置 src/router/index.ts
    • 保留传统路由配置作为 src/router/manual-routes.ts 备份
    • 支持自动路由和传统路由的平滑切换

验证步骤

后端验证

cd /Users/retirado/Program/ccProgram_0312/reading-platform-backend
npm start
# 访问 http://localhost:3000/api-docs 查看 Swagger 文档

前端验证

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 作为备用,确保系统稳定性

备注

  • 本次重构遵循渐进式原则,保持向后兼容
  • 所有新增文件都遵循规范要求的目录结构
  • 适配层确保旧代码可以继续工作