guoyu/学习记录问题修复方案.md
2025-12-11 23:28:07 +08:00

278 lines
7.0 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

# 学习记录问题修复方案
## 📊 问题确认
### 数据库实际情况学生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条记录
我会进一步协助分析。