10 KiB
10 KiB
学习进度判断逻辑说明
📊 核心逻辑
学习进度 = (累计学习时长 / 课程总时长) × 100%
🔍 详细判断流程
1. 课件类型分类
系统将课件分为以下类型:
| 类型 | 说明 | 是否参与进度计算 | 计算方式 |
|---|---|---|---|
video |
视频课件 | ✅ 是 | 基于学习时长 |
document |
文档课件(PDF、Word、Excel等) | ✅ 是 | 基于完成状态 |
image |
图片课件 | ✅ 是 | 基于完成状态 |
text |
文本课件 | ❌ 否 | - |
2. 进度计算步骤(混合计算模式)
系统采用混合计算模式,不同类型课件使用不同的计算方式:
步骤1:查询课程的所有课件
// 查询所有类型的课件
SELECT * FROM courseware WHERE course_id = ?
课件分类:
- 视频课件(
type = 'video') - 图片课件(
type = 'image') - 文档课件(
type = 'document',包括PDF)
步骤2:分别计算各类型进度
2.1 视频进度计算(基于时长)
// 计算视频总时长
videoTotalDuration = SUM(video.duration)
// 估算视频学习时长(从总学习时长中提取)
videoLearningDuration = totalDuration × 0.7 // 假设视频占70%
// 计算视频进度
videoProgress = (videoLearningDuration / videoTotalDuration) × 100
关键点:
- 视频课件的
duration字段必须设置(单位:秒) - 如果所有视频的
duration都未设置,视频进度 = 0%
2.2 图片和PDF进度计算(基于完成状态)
// 统计图片和PDF总数
totalNonVideoCount = imageList.size() + documentList.size()
// 查询学习详情记录,估算已查看的课件数
viewedCount = min(学习详情记录数, totalNonVideoCount)
// 计算非视频进度
nonVideoProgress = (viewedCount / totalNonVideoCount) × 100
关键点:
- 通过查询学习详情记录来判断学生是否查看过课件
- 每个图片/PDF查看一次默认算30秒学习时长
- 如果学生有学习记录,认为至少查看过部分课件
步骤3:计算权重并综合
// 计算权重
videoWeight = (视频数量 / 总课件数量) × 100
nonVideoWeight = ((图片数量 + PDF数量) / 总课件数量) × 100
// 综合进度
courseProgress = (videoProgress × videoWeight + nonVideoProgress × nonVideoWeight) / 100
计算公式:
综合进度 = (视频进度 × 视频权重 + 非视频进度 × 非视频权重) / 100
其中:
- 视频权重 = 视频课件数 / 总课件数 × 100%
- 非视频权重 = (图片数 + PDF数) / 总课件数 × 100%
步骤4:限制范围
if (progress > 100) progress = 100
if (progress < 0) progress = 0
进度限制在 0-100% 之间。
📝 代码位置
文件:
Study-Vue-redis/ry-study-system/src/main/java/com/ddnai/system/service/impl/study/StudyLearningRecordServiceImpl.java
方法:
private BigDecimal calculateCourseProgress(Long studentId, Long courseId, ...)
⚠️ 重要限制
1. 只计算视频课件
当前逻辑:
- ✅ 只有
type = 'video'的课件参与进度计算 - ❌ 图片、PDF、文档等不参与进度计算
影响:
- 如果课程只有图片或PDF,没有视频,进度会显示 0%
- 即使学生学习了图片或PDF,也不会增加进度
2. 视频时长必须设置
要求:
- 每个视频课件的
duration字段必须设置(单位:秒) - 如果
duration为 NULL 或 0,该视频不计入课程总时长
影响:
- 如果所有视频的
duration都未设置,课程总时长 = 0 → 进度 = 0% - 即使学生学习了很长时间,进度也会显示 0%
3. 学习时长统计
统计方式:
- 学生观看视频时,系统会记录学习时长
- 每次学习都会累加到
total_duration字段 - 图片、PDF 等非视频课件的学习不统计学习时长
📊 实际案例
案例1:正常情况
课程配置:
- 视频1:12分钟(720秒)
- 视频2:10分钟(600秒)
- 课程总时长:1320秒(22分钟)
学生学习:
- 累计学习:10分钟(600秒)
进度计算:
进度 = (600 / 1320) × 100 = 45.45%
案例2:视频时长未设置
课程配置:
- 视频1:duration = NULL
- 视频2:duration = NULL
- 课程总时长:0秒
学生学习:
- 累计学习:10分钟(600秒)
进度计算:
进度 = (600 / 0) → 返回 0%(避免除以0)
案例3:只有图片和PDF
课程配置:
- 图片1:xxx.jpg
- PDF1:xxx.pdf
- 视频:无
- 总课件数:2个
学生学习:
- 查看了图片和PDF
- 学习详情记录:2条(每个课件查看一次)
- 累计学习:60秒(2个课件 × 30秒/个)
进度计算:
视频进度 = 0%(没有视频)
非视频进度 = (2个已查看 / 2个总数) × 100 = 100%
视频权重 = 0 / 2 × 100 = 0%
非视频权重 = 2 / 2 × 100 = 100%
综合进度 = (0 × 0% + 100% × 100%) / 100 = 100%
案例4:混合类型(视频+图片+PDF)
课程配置:
- 视频1:12分钟(720秒)
- 图片1:xxx.jpg
- PDF1:xxx.pdf
- 总课件数:3个
学生学习:
- 视频学习:6分钟(360秒)
- 查看了图片和PDF
- 累计学习:420秒(360秒视频 + 60秒图片PDF)
进度计算:
视频进度 = (360 / 720) × 100 = 50%
非视频进度 = (2个已查看 / 2个总数) × 100 = 100%
视频权重 = 1 / 3 × 100 = 33.33%
非视频权重 = 2 / 3 × 100 = 66.67%
综合进度 = (50% × 33.33% + 100% × 66.67%) / 100 = 83.33%
🔧 如何修复进度问题
问题1:进度显示0%,但学生已学习
原因:视频课件的 duration 未设置
解决方案:
- 在管理端编辑视频课件,设置正确的时长(秒)
- 执行SQL重新计算进度:
UPDATE learning_record lr
SET progress = (
SELECT
CASE
WHEN SUM(cw.duration) IS NULL OR SUM(cw.duration) = 0 THEN 0
ELSE LEAST(100, ROUND(lr.total_duration * 100.0 / SUM(cw.duration), 2))
END
FROM courseware cw
WHERE cw.course_id = lr.course_id AND cw.type = 'video'
)
WHERE lr.total_duration > 0;
问题2:图片和PDF进度计算(已解决)
当前实现:
- ✅ 图片和PDF已参与进度计算
- ✅ 采用基于完成状态的计算方式
- ✅ 通过查询学习详情记录来判断是否查看过
计算逻辑:
- 统计课程中的图片和PDF数量
- 查询学生的学习详情记录
- 根据学习记录数量估算已查看的课件数
- 计算完成度:已查看数 / 总课件数 × 100%
注意事项:
- 前端需要在学生查看图片/PDF时记录学习详情
- 每个图片/PDF查看一次默认算30秒学习时长
- 如果课程只有图片和PDF,没有视频,进度会基于学习时长计算
📋 数据库字段说明
courseware 表(课件表)
| 字段 | 类型 | 说明 | 是否必需 |
|---|---|---|---|
id |
BIGINT | 课件ID | ✅ |
course_id |
BIGINT | 课程ID | ✅ |
type |
VARCHAR | 课件类型(video/document/image/text) | ✅ |
duration |
INT | 视频时长(秒,仅视频类型) | ⚠️ 视频必需 |
title |
VARCHAR | 课件标题 | ✅ |
file_path |
VARCHAR | 文件路径 | ✅ |
learning_record 表(学习记录表)
| 字段 | 类型 | 说明 |
|---|---|---|
id |
BIGINT | 记录ID |
student_id |
BIGINT | 学生ID |
course_id |
BIGINT | 课程ID |
total_duration |
INT | 累计学习时长(秒) |
progress |
DECIMAL | 学习进度(0-100) |
learn_count |
INT | 学习次数 |
last_learn_time |
DATETIME | 最后学习时间 |
🎯 总结
核心要点
-
混合计算模式:
- ✅ 视频课件:基于学习时长计算
- ✅ 图片和PDF:基于完成状态计算
- ❌ 文本课件:不参与进度计算
-
视频时长必须设置:
duration字段必须大于0 -
计算公式:
综合进度 = (视频进度 × 视频权重 + 非视频进度 × 非视频权重) / 100 -
进度范围:限制在 0-100% 之间
-
图片和PDF完成判断:
- 通过查询学习详情记录来判断
- 每个图片/PDF查看一次默认算30秒学习时长
- 如果学生有学习记录,认为至少查看过部分课件
判断流程图
开始
↓
查询课程的所有课件
↓
分类统计:视频、图片、PDF
↓
┌─────────────────┬─────────────────┐
│ 视频进度计算 │ 非视频进度计算 │
│ (基于时长) │ (基于完成状态) │
├─────────────────┼─────────────────┤
│ 1. 计算视频总时长│ 1. 统计图片/PDF数│
│ 2. 估算视频学习 │ 2. 查询学习记录 │
│ 时长 │ 3. 估算已查看数 │
│ 3. 计算视频进度 │ 4. 计算完成度 │
└─────────────────┴─────────────────┘
↓
计算权重:
- 视频权重 = 视频数 / 总课件数
- 非视频权重 = (图片+PDF)数 / 总课件数
↓
综合进度 = (视频进度 × 视频权重 + 非视频进度 × 非视频权重) / 100
↓
限制在 0-100% 之间
↓
返回进度
📚 相关文件
- 后端代码:
StudyLearningRecordServiceImpl.java - 诊断SQL:
database_check_learning_progress.sql - 修复SQL:
database_fix_video_duration_and_progress.sql - 说明文档:
学习进度问题修复说明.md
🔍 调试方法
查看后端日志
后端已添加详细日志,重启服务后可以看到:
INFO - 开始计算学习进度 - 学生ID: 109, 课程ID: 3
INFO - 课程 3 包含 2 个视频课件
WARN - 视频课件 8 (亡羊补牢) 的时长未设置或为0
INFO - 课程 3 总时长: 1440秒 (24分钟), 2个视频有时长, 0个视频无时长
INFO - 学生 109 对课程 3 的累计学习时长: 3秒 (0分钟)
INFO - 计算进度: 3 / 1440 * 100 = 0.21%
INFO - 最终进度: 0.21%
执行诊断SQL
-- 查看学习记录和进度
SELECT
lr.id,
lr.course_id,
c.course_name,
lr.total_duration as '累计时长(秒)',
lr.progress as '进度(%)',
(SELECT SUM(duration) FROM courseware WHERE course_id = lr.course_id AND type = 'video') as '课程总时长(秒)'
FROM learning_record lr
LEFT JOIN course c ON lr.course_id = c.id;