guoyu/学习记录问题修复方案.md

278 lines
7.0 KiB
Markdown
Raw Normal View History

2025-12-11 23:28:07 +08:00
# 学习记录问题修复方案
## 📊 问题确认
### 数据库实际情况学生ID 452课程"妙解古诗文"
- **上报次数119次**
- **总时长1804秒约30分钟**
- **平均每次15秒**
- **视频最后位置3秒**
- **学习次数10次**
### 问题根源:
1. **前端上报频率过高**
- 当前每10秒上报一次
- 问题:视频很短(几秒)也会多次上报
2. **非视频课件重复统计**
- 每次打开图片/PDF都上报30秒
- 如果反复切换课件,会重复累加
3. **时长统计不准确**
- 前端计算的duration包含了所有操作时间
- 没有去重同一课件的重复学习
---
## 🔧 修复方案
### 方案1优化前端上报逻辑推荐
#### 1.1 延长上报间隔
**文件:** `fronted_uniapp/pages/course/detail.vue`
**修改:** 第172行
```javascript
// 修改前
reportInterval: 10000, // 每10秒上报一次
// 修改后
reportInterval: 30000, // 每30秒上报一次减少上报频率
```
#### 1.2 优化非视频课件上报
**修改:** 第1364-1370行
```javascript
// 修改前
duration: 30, // 非视频课件默认30秒
// 修改后
duration: 10, // 非视频课件默认10秒更合理
```
#### 1.3 添加课件去重逻辑
**在 `reportNonVideoProgress` 方法中添加去重检查:**
```javascript
// 在 reportNonVideoProgress 方法开始处添加
async reportNonVideoProgress() {
console.log('[课程学习] 📤 准备上报非视频课件进度')
if (!this.courseware || !this.courseware.id) {
console.warn('[课程学习] ⚠️ 课件信息不完整,跳过上报')
return
}
// ✅ 添加:检查是否已经上报过此课件(避免重复统计)
const storageKey = `courseware_viewed_${this.courseId}_${this.courseware.id}`
const hasViewed = uni.getStorageSync(storageKey)
if (hasViewed) {
console.log('[课程学习] 课件已查看过,跳过重复上报')
return
}
// 标记为已查看24小时后过期
uni.setStorageSync(storageKey, Date.now())
setTimeout(() => {
uni.removeStorageSync(storageKey)
}, 24 * 60 * 60 * 1000)
// ... 原有上报逻辑
}
```
---
### 方案2后端数据清洗立即执行
#### 2.1 清理异常数据
**问题:** 有些记录duration为0或非常小
**SQL**
```sql
-- 查看异常记录
SELECT
lr.student_id,
u.nick_name,
c.course_name,
lr.total_duration AS 总时长秒,
lr.learn_count AS 学习次数,
COUNT(ld.id) AS 上报次数,
AVG(ld.duration) AS 平均每次秒
FROM learning_record lr
INNER JOIN sys_user u ON lr.student_id = u.user_id
INNER JOIN course c ON lr.course_id = c.id
LEFT JOIN learning_detail ld ON lr.id = ld.learning_record_id
GROUP BY lr.id, lr.student_id, u.nick_name, c.course_name, lr.total_duration, lr.learn_count
HAVING 总时长秒 > 600 OR 上报次数 > 50
ORDER BY 总时长秒 DESC;
```
#### 2.2 重新计算总时长(基于课件实际观看)
**原理:** 每个课件只统计一次最大观看时长
**SQL**
```sql
-- 为每个学习记录重新计算总时长
UPDATE learning_record lr
INNER JOIN (
SELECT
ld.learning_record_id,
-- 对每个课件只取最大的video_end_position
-- 非视频课件courseware_id为NULL或video_end_position=0统计为10秒
SUM(
CASE
WHEN MAX(ld.video_end_position) > 0 THEN MAX(ld.video_end_position)
ELSE 10
END
) AS calculated_duration
FROM learning_detail ld
GROUP BY ld.learning_record_id, ld.courseware_id
) AS calc ON lr.id = calc.learning_record_id
SET lr.total_duration = calc.calculated_duration;
```
---
### 方案3添加数据验证逻辑后端
#### 3.1 限制单次上报的最大时长
**文件:** `StudyLearningRecordServiceImpl.java`
**在 `updateLearningProgress` 方法中添加验证:**
```java
// 第260行后添加
public int updateLearningProgress(Long studentId, Long courseId, Long coursewareId, Integer duration, Integer videoPosition, Integer videoTotalDuration)
{
// ✅ 添加验证duration合理性
if (duration != null) {
// 单次上报时长不应超过60秒上报间隔30秒 + 缓冲)
if (duration > 60) {
logger.warn("学生 {} 上报的时长异常:{} 秒限制为60秒", studentId, duration);
duration = 60;
}
// 时长不能为负数
if (duration < 0) {
logger.warn("学生 {} 上报的时长为负数:{} 秒,忽略", studentId, duration);
duration = 0;
}
}
// ... 原有逻辑
}
```
#### 3.2 优化学习次数统计
**当前问题:** 30分钟算一个会话太长
**修改:** 第291行
```java
// 修改前
long sessionTimeout = 30 * 60 * 1000L; // 30分钟
// 修改后
long sessionTimeout = 10 * 60 * 1000L; // 10分钟更合理
```
---
## 📋 立即执行步骤
### 步骤1备份数据
```bash
双击运行:导入前数据备份.bat
```
### 步骤2查看当前异常数据
```sql
-- 在MySQL中执行
USE study;
SELECT
lr.student_id,
u.nick_name AS 学生,
c.course_name AS 课程,
lr.total_duration AS 总时长秒,
ROUND(lr.total_duration / 60, 1) AS 总时长分钟,
lr.learn_count AS 学习次数,
lr.progress AS 进度百分比,
COUNT(ld.id) AS 上报次数
FROM learning_record lr
INNER JOIN sys_user u ON lr.student_id = u.user_id
INNER JOIN course c ON lr.course_id = c.id
LEFT JOIN learning_detail ld ON lr.id = ld.learning_record_id
GROUP BY lr.id
HAVING 总时长秒 > 600 OR 上报次数 > 50
ORDER BY 总时长秒 DESC
LIMIT 20;
```
### 步骤3清理测试数据可选
**如果需要重置学习记录:**
```sql
-- ⚠️ 谨慎操作!会清空所有学习记录
-- DELETE FROM learning_detail WHERE student_id = 452;
-- DELETE FROM learning_record WHERE student_id = 452;
```
### 步骤4修改前端代码
1. 打开 `fronted_uniapp/pages/course/detail.vue`
2. 修改第172行`reportInterval: 30000`
3. 修改第1368行`duration: 10`
4. 保存文件
### 步骤5重启服务
1. 后端在IDEA中重启
2. 前端在HBuilderX中重新运行
### 步骤6测试验证
1. 打开APP
2. 学习一门课程播放视频30秒
3. 查看数据库:
```sql
SELECT * FROM learning_detail
WHERE student_id = YOUR_ID
ORDER BY start_time DESC
LIMIT 5;
```
4. 验证duration应该合理约30秒左右
---
## 🎯 预期效果
修复后:
- ✅ 上报频率降低从每10秒改为每30秒
- ✅ 时长更准确非视频从30秒改为10秒
- ✅ 避免重复:同一课件不重复统计
- ✅ 数据验证单次上报不超过60秒
- ✅ 学习次数准确10分钟算一个会话
---
## 📞 如需帮助
如果修复后仍有问题,请提供:
1. 具体学生ID
2. 课程名称
3. 学习时长和实际播放时长
4. learning_detail表的最近10条记录
我会进一步协助分析。