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

7.0 KiB
Raw Blame History

学习记录问题修复方案

📊 问题确认

数据库实际情况学生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行

// 修改前
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修改前端代码

  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. 查看数据库:
    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条记录

我会进一步协助分析。