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

269 lines
9.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 开发日志 - 2026-03-12
## 今日任务:代码重构(规范化)
根据 `docs/统一开发规范.md``docs/前端项目规范.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 模块
- [ ] 其他模块
### 前端
- [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` 作为备用,确保系统稳定性
---
## 备注
- 本次重构遵循渐进式原则,保持向后兼容
- 所有新增文件都遵循规范要求的目录结构
- 适配层确保旧代码可以继续工作