# 开发日志 - 2026-03-20

## 教师端课程使用统计功能实现

### 实现内容

实现了教师端课程使用统计功能（增强版），支持按时间周期筛选和更多维度的统计。

### 后端改动

#### 1. 新增 DTO 类

**CourseUsageQuery.java** - 请求参数 DTO
- `periodType`: 统计周期类型（TODAY/WEEK/MONTH/CUSTOM）
- `startDate`: 自定义周期开始日期
- `endDate`: 自定义周期结束日期

**CourseUsageStatsVO.java** - 响应对象 DTO（增强版）
- `coursePackageId`: 课程包 ID
- `coursePackageName`: 课程包名称
- `usageCount`: 使用次数（基于实际授课记录统计）
- `studentCount`: 参与学生数（去重）
- `avgDuration`: 平均时长（分钟）
- `lastUsedAt`: 最后使用时间

#### 2. LessonMapper.java

新增 `getCourseUsageStats()` 方法：
- 使用自定义 SQL 统计课程包使用情况
- 基于 `lesson` 表实际授课记录
- 支持时间范围筛选
- 支持教师 ID 筛选
- 只统计 `COMPLETED` 状态的课程
- 返回 TOP 10 课程包

#### 3. TeacherStatsService.java

新增接口方法：
```java
List<CourseUsageStatsVO> getCourseUsageStats(Long tenantId, Long teacherId, CourseUsageQuery query);
```

#### 4. TeacherStatsServiceImpl.java

实现 `getCourseUsageStats()` 方法：
- 调用 `calculateTimeRange()` 计算时间范围
- 支持四种周期类型：TODAY、WEEK、MONTH、CUSTOM
- 调用 Mapper 获取统计数据

实现 `calculateTimeRange()` 辅助方法：
- TODAY: 当天 00:00:00 至今
- WEEK: 本周一至今
- MONTH: 本月 1 号至今
- CUSTOM: 自定义日期范围

#### 5. TeacherStatsController.java

新增接口：
- `GET /api/v1/teacher/course-usage-stats` - 增强版课程使用统计
- 支持参数：`periodType`、`startDate`、`endDate`
- 保留旧接口 `/api/v1/teacher/course-usage`（标记为 @Deprecated）

### 前端改动

#### 1. src/api/teacher.ts

新增类型定义：
- `CourseUsageQueryParams` - 查询参数类型
- `CourseUsageStatsItem` - 响应数据类型

新增 API 方法：
- `getTeacherCourseUsageStats()` - 获取增强版课程使用统计

保留旧 API（向后兼容）：
- `getTeacherCourseUsage()`

#### 2. src/views/teacher/DashboardView.vue

**新增响应式数据**：
- `usagePeriodType`: 当前选择的周期类型
- `courseUsageStatsData`: 增强版课程使用统计数据
- `periodOptions`: 周期选项（今日/本周/本月）

**UI 改动**：
- 在课程使用卡片添加周期选择器（a-segmented）
- 用户可通过点击切换统计周期

**图表增强**：
- `initUsageChart()` 支持新旧两种数据类型
- tooltip 显示更详细信息：
  - 使用次数
  - 参与学生数
  - 平均时长
  - 最后使用时间

**数据加载**：
- `loadUsageData()` 调用新 API `getTeacherCourseUsageStats()`
- 周期切换时自动重新加载数据

### 统计逻辑

1. **使用次数**：统计周期内 COMPLETED 状态的 lesson 数量
2. **参与学生数**：去重统计 student_record 中的 student_id
3. **平均时长**：计算 lesson 的 start_datetime 到 end_datetime 的分钟差平均值
4. **最后使用时间**：最近一次授课完成时间

### 数据流向

```
用户选择周期 → 前端调用 API → Controller 接收参数
→ Service 计算时间范围 → Mapper 执行 SQL 统计
→ 返回 CourseUsageStatsVO 列表 → 前端图表展示
```

### SQL 统计逻辑

```sql
SELECT
  cp.id AS coursePackageId,
  cp.name AS coursePackageName,
  COUNT(l.id) AS usageCount,
  COUNT(DISTINCT sr.student_id) AS studentCount,
  AVG(TIMESTAMPDIFF(MINUTE, l.start_datetime, l.end_datetime)) AS avgDuration,
  MAX(l.end_datetime) AS lastUsedAt
FROM lesson l
INNER JOIN course_package cp ON l.course_id = cp.id
LEFT JOIN student_record sr ON l.id = sr.lesson_id
WHERE l.tenant_id = #{tenantId}
  AND l.end_datetime >= #{startTime}
  AND l.end_datetime <= #{endTime}
  AND l.status = 'COMPLETED'
  AND l.teacher_id = #{teacherId}
GROUP BY cp.id, cp.name
ORDER BY usageCount DESC
LIMIT 10
```

### 测试验证

- [x] 后端编译通过 ✅
- [x] 启动后端服务测试 API ✅
- [x] API 返回数据正确 ✅
- [ ] 前端展示周期选择器
- [ ] 切换周期数据正确刷新
- [ ] tooltip 显示完整信息

### API 测试响应示例

**请求**: `GET /api/v1/teacher/course-usage-stats?periodType=MONTH`

**响应**:
```json
{
  "code": 200,
  "message": "操作成功",
  "data": [
    {
      "coursePackageId": "17",
      "coursePackageName": "课程简介课程简介课程简介课程简介课程简介课程简介课程简介",
      "usageCount": 15,
      "studentCount": 5,
      "avgDuration": 0,
      "lastUsedAt": "2026-03-16T00:00:00"
    },
    {
      "coursePackageId": "16",
      "coursePackageName": "T 色他",
      "usageCount": 1,
      "studentCount": 0,
      "avgDuration": 0,
      "lastUsedAt": "2026-03-16T00:00:00"
    }
  ]
}
```

### 技术难点解决

**问题**: MyBatis `@SelectProvider` 不支持 XML 格式的 `<if>` 动态标签

**解决方案**: 使用 SQL 条件 `AND (#{teacherId} IS NULL OR l.teacher_id = #{teacherId})` 替代动态 SQL，实现可选参数过滤。

### 文件清单

**后端新增**：
- `dto/request/CourseUsageQuery.java`
- `dto/response/CourseUsageStatsVO.java`

**后端修改**：
- `mapper/LessonMapper.java`
- `service/TeacherStatsService.java`
- `service/impl/TeacherStatsServiceImpl.java`
- `controller/teacher/TeacherStatsController.java`

**前端修改**：
- `src/api/teacher.ts`
- `src/views/teacher/DashboardView.vue`

### 后续优化建议

1. **前端展示优化**：可以考虑将饼图改为条形图，更适合展示 TOP 排行
2. **导出功能**：支持导出统计数据为 Excel
3. **更多维度**：增加课程类型分布、班级使用对比等
4. **缓存优化**：统计数据可以缓存在 Redis 中，提高查询性能
