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