kindergarten_java/docs/dev-logs/2026-03-20-teacher-course-usage-stats.md

205 lines
5.7 KiB
Markdown
Raw Normal View History

# 开发日志 - 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 中,提高查询性能