kindergarten_java/docs/test-logs/school/2026-03-21-export-feature.md

304 lines
9.2 KiB
Markdown
Raw Permalink Normal View History

# 学校端数据导出功能测试记录
**测试日期**: 2026-03-21
**测试人员**: Claude
**功能模块**: 学校端数据概览 - 数据导出
---
## 实现内容
### 后端实现
#### 1. 添加依赖
- 添加 `EasyExcel 3.3.4` 依赖到 `pom.xml`
#### 2. 新建文件
- `dto/response/LessonExportVO.java` - 授课记录导出 VO
- `dto/response/TeacherPerformanceExportVO.java` - 教师绩效导出 VO
- `dto/response/StudentStatExportVO.java` - 学生统计导出 VO
- `service/SchoolExportService.java` - 导出服务接口
- `service/impl/SchoolExportServiceImpl.java` - 导出服务实现
#### 3. 修改文件
- `mapper/LessonMapper.java` - 添加三个导出查询方法
- `controller/school/SchoolExportController.java` - 实现导出接口
### 前端实现
#### 修改文件
- `src/api/school.ts` - 增强导出函数,处理空数据时返回的 JSON 响应
---
## 测试步骤
### 后端测试
#### 1. 启动后端服务(端口 8481
```bash
export JAVA_HOME="/f/Java/jdk-17"
export SERVER_PORT=8481
cd reading-platform-java
mvn spring-boot:run
```
#### 2. 使用 Swagger 测试接口
访问http://localhost:8481/doc.html
测试以下接口:
- `GET /api/v1/school/export/lessons` - 授课记录导出
- `GET /api/v1/school/export/teacher-stats` - 教师绩效导出
- `GET /api/v1/school/export/student-stats` - 学生统计导出
#### 3. 验证空数据响应
当没有数据时,应返回 JSON
```json
{
"code": 404,
"message": "指定时间范围内暂无授课记录",
"data": null
}
```
---
## 测试用例
### 用例 1导出授课记录
**请求参数**:
- startDate: 2026-03-01
- endDate: 2026-03-21
**预期结果**:
- 成功:下载 Excel 文件,包含授课日期、授课时间、班级名称、教师姓名、课程名称、课程类型、学生人数、平均参与度、评价反馈
- 无数据:返回 JSON 响应 `{code: 404, message: "指定时间范围内暂无授课记录"}`
### 用例 2导出教师绩效统计
**请求参数**:
- startDate: 2026-03-01
- endDate: 2026-03-21
**预期结果**:
- 成功:下载 Excel 文件,包含教师姓名、所属班级、授课次数、课程数量、活跃等级、最后活跃时间、平均参与度
- 无数据:返回 JSON 响应 `{code: 404, message: "指定时间范围内暂无教师绩效数据"}`
### 用例 3导出学生统计
**请求参数**:
- classId: 可选
**预期结果**:
- 成功:下载 Excel 文件,包含学生姓名、性别、班级、授课次数、平均参与度、平均专注度
- 无数据:返回 JSON 响应 `{code: 404, message: "暂无学生统计数据"}`
---
## 前端测试
### 1. 启动前端服务(端口 5174
```bash
export VITE_APP_PORT=5174
cd reading-platform-frontend
npm run dev
```
### 2. 访问学校端数据概览页面
访问http://localhost:5174/school/dashboard
### 3. 测试导出功能
1. 点击"授课记录"导出按钮
2. 点击"教师绩效"导出按钮
3. 点击"学生统计"导出按钮
**预期结果**:
- 有数据时:自动下载 Excel 文件,提示"导出成功"
- 无数据时:提示"暂无数据"或相应错误消息
---
## 导出字段设计
### 授课记录导出 (LessonExportVO)
| Excel 列名 | 字段 | 类型 | 数据来源 |
|-----------|------|------|----------|
| 授课日期 | lessonDate | LocalDate | lesson.lesson_date |
| 授课时间 | timeRange | String | lesson.start_time ~ end_time |
| 班级名称 | className | String | clazz.name |
| 教师姓名 | teacherName | String | teacher.name |
| 课程名称 | courseName | String | course_package.name |
| 课程类型 | lessonType | String | lesson.lesson_type |
| 学生人数 | studentCount | Integer | student_record count |
| 平均参与度 | avgParticipation | Double | avg(student_record.participation) |
| 评价反馈 | feedbackContent | String | lesson_feedback.content |
### 教师绩效导出 (TeacherPerformanceExportVO)
| Excel 列名 | 字段 | 类型 | 数据来源 |
|-----------|------|------|----------|
| 教师姓名 | teacherName | String | teacher.name |
| 所属班级 | classNames | String | GROUP_CONCAT(clazz.name) |
| 授课次数 | lessonCount | Integer | COUNT(lesson.id) |
| 课程数量 | courseCount | Integer | COUNT(DISTINCT course_id) |
| 活跃等级 | activityLevel | String | CASE WHEN |
| 最后活跃时间 | lastActiveAt | LocalDateTime | MAX(end_datetime) |
| 平均参与度 | avgParticipation | Double | AVG(participation) |
### 学生统计导出 (StudentStatExportVO)
| Excel 列名 | 字段 | 类型 | 数据来源 |
|-----------|------|------|----------|
| 学生姓名 | studentName | String | student.name |
| 性别 | gender | String | student.gender |
| 班级 | className | String | clazz.name |
| 授课次数 | lessonCount | Integer | COUNT(lesson.id) |
| 平均参与度 | avgParticipation | Double | AVG(participation) |
| 平均专注度 | avgFocus | Double | AVG(focus) |
---
## 注意事项
1. **日期范围处理**:前端传入日期字符串,后端解析为 LocalDate
2. **文件名编码**:中文文件名使用 URLEncoder 编码
3. **空数据处理**:没有数据时返回 JSON 响应,不生成 Excel 文件
4. **Content-Type 判断**:前端需要判断响应头,区分 Excel 和 JSON 响应
5. **权限验证**:通过 `@RequireRole(UserRole.SCHOOL)` 确保只导出当前租户数据
---
## 待办事项
- [ ] 后端服务启动验证
- [ ] Swagger 接口测试
- [ ] 前端页面功能测试
- [ ] 空数据场景测试
- [ ] 大数据量导出性能测试
---
## 测试结果
| 测试项 | 状态 | 备注 |
|--------|------|------|
| 编译通过 | ✅ | 后端编译成功 |
| 授课记录导出 | ✅ | HTTP 200生成 Excel 文件 (5.6KB, 39 条记录) |
| 教师绩效导出 | ✅ | HTTP 200生成 Excel 文件 (4.1KB, 10 条记录) |
| 学生统计导出 | ✅ | HTTP 200生成 Excel 文件 |
| 空数据处理 | ✅ | 返回 JSON `{code: 404, message: "指定时间范围内暂无授课记录"}` |
| 前端服务 | ✅ | 端口 5174 正常运行 |
---
## 问题修复
### 修复 1: 授课记录日期时间为空
**问题**: 授课日期和授课时间字段在 Excel 中显示为空
**原因**:
1. SQL 返回的 Map 使用下划线命名 (`lesson_date`),但 Java 代码获取驼峰命名 (`lessonDate`)
2. SQL 返回的是 `java.sql.Date``java.sql.Time` 类型,不能直接转换为 `LocalDate``LocalTime`
**解决**:
```java
// 日期转换
Object dateObj = row.get("lesson_date");
if (dateObj instanceof java.sql.Date) {
vo.setLessonDate(((java.sql.Date) dateObj).toLocalDate());
}
// 时间转换
Object startTimeObj = row.get("start_time");
if (startTimeObj instanceof java.sql.Time) {
vo.setTimeRange(((java.sql.Time) startTimeObj).toLocalTime().format(TIME_FORMATTER) + ...);
}
```
### 修复 2: 教师绩效活跃等级未翻译
**问题**: Excel 中活跃等级显示为 `HIGH`/`MEDIUM`/`LOW`/`INACTIVE` 英文代码
**解决**: 添加翻译方法 `translateActivityLevel()`:
```java
private String translateActivityLevel(String code) {
switch (code) {
case "HIGH": return "高";
case "MEDIUM": return "中";
case "LOW": return "低";
case "INACTIVE": return "未活跃";
default: return code;
}
}
```
---
## 测试详情
### 后端接口测试结果
**测试时间**: 2026-03-21
#### 1. 授课记录导出
- **接口**: `GET /api/v1/school/export/lessons?startDate=2026-03-01&endDate=2026-03-21`
- **状态**: ✅ 通过
- **响应**: HTTP 200Microsoft Excel 2007+ 文件格式
- **包含字段**: 授课日期、授课时间、班级名称、教师姓名、课程名称、状态、学生人数、平均参与度、备注
#### 2. 教师绩效导出
- **接口**: `GET /api/v1/school/export/teacher-stats?startDate=2026-03-01&endDate=2026-03-21`
- **状态**: ✅ 通过
- **响应**: HTTP 200Microsoft Excel 2007+ 文件格式
- **包含字段**: 教师姓名、所属班级、授课次数、课程数量、活跃等级、最后活跃时间、平均参与度
#### 3. 学生统计导出
- **接口**: `GET /api/v1/school/export/student-stats`
- **状态**: ✅ 通过
- **响应**: HTTP 200Microsoft Excel 2007+ 文件格式
- **包含字段**: 学生姓名、性别、年级、授课次数、平均参与度、平均专注度
#### 4. 空数据处理测试
- **接口**: `GET /api/v1/school/export/lessons?startDate=2020-01-01&endDate=2020-01-07`
- **状态**: ✅ 通过
- **响应**: `{"code":404,"message":"指定时间范围内暂无授课记录"}`
---
## 修复记录
1. **修复 lesson_type 字段不存在问题**
- 问题:`lesson` 表没有 `lesson_type` 字段
- 解决:移除 SQL 中的 `l.lesson_type`,改用 `l.status``l.notes`
2. **修复 student 表 class_id 字段不存在问题**
- 问题:`student` 表没有 `class_id` 字段
- 解决:改用 `s.grade` 作为 `className` 显示
---
## 前端测试
### 访问地址
- 前端http://localhost:5174
- 后端http://localhost:8481
- 登录账号school1 / 123456
### 测试步骤
1. 访问 http://localhost:5174/login 登录学校账号
2. 进入"数据概览"页面
3. 点击"授课记录"、"教师绩效"、"学生统计"导出按钮
### 预期结果
- 有数据时:自动下载 Excel 文件message 提示"导出成功"
- 无数据时message 提示"暂无数据"