7.0 KiB
7.0 KiB
学习记录问题修复方案
📊 问题确认
数据库实际情况(学生ID 452,课程"妙解古诗文"):
- 上报次数:119次
- 总时长:1804秒(约30分钟)
- 平均每次:15秒
- 视频最后位置:3秒
- 学习次数:10次
问题根源:
-
前端上报频率过高
- 当前:每10秒上报一次
- 问题:视频很短(几秒)也会多次上报
-
非视频课件重复统计
- 每次打开图片/PDF都上报30秒
- 如果反复切换课件,会重复累加
-
时长统计不准确
- 前端计算的duration包含了所有操作时间
- 没有去重同一课件的重复学习
🔧 修复方案
方案1:优化前端上报逻辑(推荐)
1.1 延长上报间隔
文件: fronted_uniapp/pages/course/detail.vue
修改: 第172行
// 修改前
reportInterval: 10000, // 每10秒上报一次
// 修改后
reportInterval: 30000, // 每30秒上报一次(减少上报频率)
1.2 优化非视频课件上报
修改: 第1364-1370行
// 修改前
duration: 30, // 非视频课件默认30秒
// 修改后
duration: 10, // 非视频课件默认10秒(更合理)
1.3 添加课件去重逻辑
在 reportNonVideoProgress 方法中添加去重检查:
// 在 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:
-- 查看异常记录
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:
-- 为每个学习记录重新计算总时长
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 方法中添加验证:
// 第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行
// 修改前
long sessionTimeout = 30 * 60 * 1000L; // 30分钟
// 修改后
long sessionTimeout = 10 * 60 * 1000L; // 10分钟(更合理)
📋 立即执行步骤
步骤1:备份数据
双击运行:导入前数据备份.bat
步骤2:查看当前异常数据
-- 在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:清理测试数据(可选)
如果需要重置学习记录:
-- ⚠️ 谨慎操作!会清空所有学习记录
-- DELETE FROM learning_detail WHERE student_id = 452;
-- DELETE FROM learning_record WHERE student_id = 452;
步骤4:修改前端代码
- 打开
fronted_uniapp/pages/course/detail.vue - 修改第172行:
reportInterval: 30000 - 修改第1368行:
duration: 10 - 保存文件
步骤5:重启服务
- 后端:在IDEA中重启
- 前端:在HBuilderX中重新运行
步骤6:测试验证
- 打开APP
- 学习一门课程(播放视频30秒)
- 查看数据库:
SELECT * FROM learning_detail WHERE student_id = YOUR_ID ORDER BY start_time DESC LIMIT 5; - 验证:duration应该合理(约30秒左右)
🎯 预期效果
修复后:
- ✅ 上报频率降低:从每10秒改为每30秒
- ✅ 时长更准确:非视频从30秒改为10秒
- ✅ 避免重复:同一课件不重复统计
- ✅ 数据验证:单次上报不超过60秒
- ✅ 学习次数准确:10分钟算一个会话
📞 如需帮助
如果修复后仍有问题,请提供:
- 具体学生ID
- 课程名称
- 学习时长和实际播放时长
- learning_detail表的最近10条记录
我会进一步协助分析。