guoyu/Test/备份/_已清理文件备份_周六 22512/md/学习进度判断逻辑说明.md

376 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

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.

# 学习进度判断逻辑说明
## 📊 核心逻辑
**学习进度 = (累计学习时长 / 课程总时长) × 100%**
## 🔍 详细判断流程
### 1. 课件类型分类
系统将课件分为以下类型:
| 类型 | 说明 | 是否参与进度计算 | 计算方式 |
|------|------|----------------|---------|
| `video` | 视频课件 | ✅ **是** | 基于学习时长 |
| `document` | 文档课件PDF、Word、Excel等 | ✅ **是** | 基于完成状态 |
| `image` | 图片课件 | ✅ **是** | 基于完成状态 |
| `text` | 文本课件 | ❌ **否** | - |
### 2. 进度计算步骤(混合计算模式)
系统采用**混合计算模式**,不同类型课件使用不同的计算方式:
#### 步骤1查询课程的所有课件
```java
// 查询所有类型的课件
SELECT * FROM courseware WHERE course_id = ?
```
**课件分类**
- 视频课件(`type = 'video'`
- 图片课件(`type = 'image'`
- 文档课件(`type = 'document'`包括PDF
#### 步骤2分别计算各类型进度
**2.1 视频进度计算(基于时长)**
```java
// 计算视频总时长
videoTotalDuration = SUM(video.duration)
// 估算视频学习时长(从总学习时长中提取)
videoLearningDuration = totalDuration × 0.7 // 假设视频占70%
// 计算视频进度
videoProgress = (videoLearningDuration / videoTotalDuration) × 100
```
**关键点**
- 视频课件的 `duration` 字段必须设置(单位:秒)
- 如果所有视频的 `duration` 都未设置,视频进度 = 0%
**2.2 图片和PDF进度计算基于完成状态**
```java
// 统计图片和PDF总数
totalNonVideoCount = imageList.size() + documentList.size()
// 查询学习详情记录,估算已查看的课件数
viewedCount = min(学习详情记录数, totalNonVideoCount)
// 计算非视频进度
nonVideoProgress = (viewedCount / totalNonVideoCount) × 100
```
**关键点**
- 通过查询学习详情记录来判断学生是否查看过课件
- 每个图片/PDF查看一次默认算30秒学习时长
- 如果学生有学习记录,认为至少查看过部分课件
#### 步骤3计算权重并综合
```java
// 计算权重
videoWeight = (视频数量 / 总课件数量) × 100
nonVideoWeight = ((图片数量 + PDF数量) / 总课件数量) × 100
// 综合进度
courseProgress = (videoProgress × videoWeight + nonVideoProgress × nonVideoWeight) / 100
```
**计算公式**
```
综合进度 = (视频进度 × 视频权重 + 非视频进度 × 非视频权重) / 100
其中:
- 视频权重 = 视频课件数 / 总课件数 × 100%
- 非视频权重 = (图片数 + PDF数) / 总课件数 × 100%
```
#### 步骤4限制范围
```java
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
```
**方法**
```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正常情况
**课程配置**
- 视频112分钟720秒
- 视频210分钟600秒
- 课程总时长1320秒22分钟
**学生学习**
- 累计学习10分钟600秒
**进度计算**
```
进度 = (600 / 1320) × 100 = 45.45%
```
### 案例2视频时长未设置
**课程配置**
- 视频1duration = NULL
- 视频2duration = NULL
- 课程总时长0秒
**学生学习**
- 累计学习10分钟600秒
**进度计算**
```
进度 = (600 / 0) → 返回 0%避免除以0
```
### 案例3只有图片和PDF
**课程配置**
- 图片1xxx.jpg
- PDF1xxx.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
**课程配置**
- 视频112分钟720秒
- 图片1xxx.jpg
- PDF1xxx.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` 未设置
**解决方案**
1. 在管理端编辑视频课件,设置正确的时长(秒)
2. 执行SQL重新计算进度
```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**已参与**进度计算
- ✅ 采用基于完成状态的计算方式
- ✅ 通过查询学习详情记录来判断是否查看过
**计算逻辑**
1. 统计课程中的图片和PDF数量
2. 查询学生的学习详情记录
3. 根据学习记录数量估算已查看的课件数
4. 计算完成度:已查看数 / 总课件数 × 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 | 最后学习时间 |
## 🎯 总结
### 核心要点
1. **混合计算模式**
- ✅ 视频课件:基于学习时长计算
- ✅ 图片和PDF基于完成状态计算
- ❌ 文本课件:不参与进度计算
2. **视频时长必须设置**`duration` 字段必须大于0
3. **计算公式**
```
综合进度 = (视频进度 × 视频权重 + 非视频进度 × 非视频权重) / 100
```
4. **进度范围**:限制在 0-100% 之间
5. **图片和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
```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;
```