From 1dc28839223986e608b344d3f489ef0d98005a70 Mon Sep 17 00:00:00 2001 From: xiao12feng8 <120912171+xiao12feng8@users.noreply.github.com> Date: Sun, 7 Dec 2025 01:19:40 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B0=8Fbug=EF=BC=8C?= =?UTF-8?q?=E5=89=A9=E4=BD=99=E8=AF=AD=E9=9F=B3=E6=9C=AA=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/StudyScoreController.java | 28 ++++++---- .../domain/study/StudyLearningRecord.java | 26 +++++++++ .../study/StudyLearningRecordServiceImpl.java | 51 ++++++++++++++---- .../study/StudyLearningRecordMapper.xml | 27 +++++++--- .../src/views/study/learningRecord/index.vue | 30 +++++++---- fronted_uniapp/App.vue | 6 +-- fronted_uniapp/pages/exam/detail.vue | 14 ++++- fronted_uniapp/pages/speech/speech.vue | 5 +- fronted_uniapp/utils/speech-recorder.js | 53 +++++++++++++++++-- 9 files changed, 191 insertions(+), 49 deletions(-) diff --git a/Study-Vue-redis/ry-study-admin/src/main/java/com/ddnai/web/controller/study/StudyScoreController.java b/Study-Vue-redis/ry-study-admin/src/main/java/com/ddnai/web/controller/study/StudyScoreController.java index d780afa..6b234d0 100644 --- a/Study-Vue-redis/ry-study-admin/src/main/java/com/ddnai/web/controller/study/StudyScoreController.java +++ b/Study-Vue-redis/ry-study-admin/src/main/java/com/ddnai/web/controller/study/StudyScoreController.java @@ -505,23 +505,25 @@ public class StudyScoreController extends BaseController return "FALSE"; } + // ✅ 修复:去除所有空格,确保格式一致 + String noSpaces = trimmed.replaceAll("\\s+", ""); + // 处理选项前缀:去除"A. "、"B. "等前缀 // 支持格式: - // - "A. 选项内容" -> "A" 或 "选项内容" - // - "A.选项内容" -> "A" 或 "选项内容" + // - "A.选项内容" -> "A" 或 "选项内容"(已去除空格) // - "A" -> "A" - String normalized = trimmed; + String normalized = noSpaces; - // 如果以"字母. "或"字母."开头,提取字母部分 - if (trimmed.matches("^[A-F]\\.\\s*.*")) + // 如果以"字母."开头,提取字母部分 + if (noSpaces.matches("^[A-F]\\..*")) { - // 提取字母(如 "A. 选项内容" -> "A") - normalized = trimmed.substring(0, 1).toUpperCase(); + // 提取字母(如 "A.选项内容" -> "A") + normalized = noSpaces.substring(0, 1).toUpperCase(); } - else if (trimmed.length() == 1 && trimmed.matches("[A-Fa-f]")) + else if (noSpaces.length() == 1 && noSpaces.matches("[A-Fa-f]")) { // 单个字母(如 "A" -> "A") - normalized = trimmed.toUpperCase(); + normalized = noSpaces.toUpperCase(); } return normalized; @@ -540,9 +542,13 @@ public class StudyScoreController extends BaseController */ private boolean compareMultipleAnswers(String studentAnswer, String correctAnswer, String optionsJson) { + // ✅ 修复:去除所有空格,确保格式一致(与保存题目时的规范化逻辑一致) + String normalizedStudentAnswer = studentAnswer.replaceAll("\\s+", ""); + String normalizedCorrectAnswer = correctAnswer.replaceAll("\\s+", ""); + // 使用逗号分隔(不使用空格、分号等,避免选项内容中的这些字符导致问题) - String[] studentParts = studentAnswer.split(","); - String[] correctParts = correctAnswer.split(","); + String[] studentParts = normalizedStudentAnswer.split(","); + String[] correctParts = normalizedCorrectAnswer.split(","); java.util.Set studentSet = new java.util.HashSet<>(); java.util.Set correctSet = new java.util.HashSet<>(); diff --git a/Study-Vue-redis/ry-study-system/src/main/java/com/ddnai/system/domain/study/StudyLearningRecord.java b/Study-Vue-redis/ry-study-system/src/main/java/com/ddnai/system/domain/study/StudyLearningRecord.java index 5039c68..2ab2e0e 100644 --- a/Study-Vue-redis/ry-study-system/src/main/java/com/ddnai/system/domain/study/StudyLearningRecord.java +++ b/Study-Vue-redis/ry-study-system/src/main/java/com/ddnai/system/domain/study/StudyLearningRecord.java @@ -33,6 +33,12 @@ public class StudyLearningRecord extends BaseEntity /** 课程名称(不持久化,仅用于显示) */ private String courseName; + /** 学生姓名(不持久化,仅用于搜索和显示) */ + private String studentName; + + /** 学生学号/信息编号(不持久化,仅用于搜索和显示) */ + private String studentNo; + /** 学习进度(百分比,0-100) */ @Excel(name = "学习进度") private BigDecimal progress; @@ -172,6 +178,26 @@ public class StudyLearningRecord extends BaseEntity this.courseName = courseName; } + public String getStudentName() + { + return studentName; + } + + public void setStudentName(String studentName) + { + this.studentName = studentName; + } + + public String getStudentNo() + { + return studentNo; + } + + public void setStudentNo(String studentNo) + { + this.studentNo = studentNo; + } + @Override public String toString() { return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) diff --git a/Study-Vue-redis/ry-study-system/src/main/java/com/ddnai/system/service/impl/study/StudyLearningRecordServiceImpl.java b/Study-Vue-redis/ry-study-system/src/main/java/com/ddnai/system/service/impl/study/StudyLearningRecordServiceImpl.java index 64287ee..7ff37a0 100644 --- a/Study-Vue-redis/ry-study-system/src/main/java/com/ddnai/system/service/impl/study/StudyLearningRecordServiceImpl.java +++ b/Study-Vue-redis/ry-study-system/src/main/java/com/ddnai/system/service/impl/study/StudyLearningRecordServiceImpl.java @@ -51,6 +51,7 @@ public class StudyLearningRecordServiceImpl implements IStudyLearningRecordServi @Override public StudyLearningRecord selectLearningRecordById(Long id) { + // ✅ 直接返回数据库中的进度值,与APP端保持一致 return learningRecordMapper.selectLearningRecordById(id); } @@ -65,15 +66,9 @@ public class StudyLearningRecordServiceImpl implements IStudyLearningRecordServi { List records = learningRecordMapper.selectLearningRecordList(learningRecord); - // 实时计算每条记录的进度(与前端保持一致) - for (StudyLearningRecord record : records) - { - if (record.getStudentId() != null && record.getCourseId() != null) - { - BigDecimal realTimeProgress = calculateCourseProgressForDisplay(record.getStudentId(), record.getCourseId()); - record.setProgress(realTimeProgress); - } - } + // ✅ 直接返回数据库中的进度值,与APP端保持一致 + // APP端会在学习时计算进度并上报保存,后台直接显示保存的值即可 + logger.info("【管理端查询】查询到 {} 条学习记录,直接使用数据库中的进度值", records.size()); return records; } @@ -84,6 +79,8 @@ public class StudyLearningRecordServiceImpl implements IStudyLearningRecordServi */ private BigDecimal calculateCourseProgressForDisplay(Long studentId, Long courseId) { + logger.info("【进度计算】开始计算 - 学生ID={}, 课程ID={}", studentId, courseId); + // 查询课程包含的所有课件 StudyCourseware query = new StudyCourseware(); query.setCourseId(courseId); @@ -91,10 +88,12 @@ public class StudyLearningRecordServiceImpl implements IStudyLearningRecordServi if (allCoursewareList == null || allCoursewareList.isEmpty()) { + logger.warn("【进度计算】课程{}没有课件", courseId); return BigDecimal.ZERO; } int totalCoursewareCount = allCoursewareList.size(); + logger.info("【进度计算】课程共有{}个课件", totalCoursewareCount); // 查询该学员对该课程的所有学习详情记录 StudyLearningDetail detailQuery = new StudyLearningDetail(); @@ -136,6 +135,9 @@ public class StudyLearningRecordServiceImpl implements IStudyLearningRecordServi { StudyLearningDetail detail = coursewareDetailMap.get(cw.getId()); + logger.info("【课件检查】课件ID={}, 类型={}, 标题={}, 配置时长={}秒", + cw.getId(), cw.getType(), cw.getTitle(), cw.getDuration()); + if ("video".equals(cw.getType())) { // 视频:判断是否完成 @@ -145,6 +147,9 @@ public class StudyLearningRecordServiceImpl implements IStudyLearningRecordServi int maxPosition = maxPositionMap.getOrDefault(cw.getId(), videoPosition); int duration = (cw.getDuration() != null && cw.getDuration() > 0) ? cw.getDuration() : 0; + logger.info("【视频课件】课件ID={}, 播放位置={}秒, 最大位置={}秒, 配置时长={}秒", + cw.getId(), videoPosition, maxPosition, duration); + // 推断真实时长 int realDuration = duration > 0 ? duration : (maxPosition + 3); @@ -155,11 +160,19 @@ public class StudyLearningRecordServiceImpl implements IStudyLearningRecordServi if (videoPosition == maxPosition && videoPosition >= 3) { isCompleted = true; + logger.info("【完成判断】课件ID={} - 特殊判断通过(播放到最大位置{}秒)", cw.getId(), videoPosition); } // 常规判断:观看进度 >= 90% else if (realDuration > 0 && videoPosition >= realDuration * 0.9) { isCompleted = true; + logger.info("【完成判断】课件ID={} - 常规判断通过({}秒 >= {}秒的90%)", + cw.getId(), videoPosition, realDuration); + } + else + { + logger.info("【完成判断】课件ID={} - 未完成({}秒 < {}秒的90%)", + cw.getId(), videoPosition, realDuration); } if (isCompleted) @@ -167,6 +180,11 @@ public class StudyLearningRecordServiceImpl implements IStudyLearningRecordServi completedCount++; } } + else + { + logger.info("【视频课件】课件ID={} - 无学习记录或videoPosition为null, detail={}", + cw.getId(), detail); + } } else { @@ -174,6 +192,11 @@ public class StudyLearningRecordServiceImpl implements IStudyLearningRecordServi if (detail != null) { completedCount++; + logger.info("【非视频课件】课件ID={} - 已完成", cw.getId()); + } + else + { + logger.info("【非视频课件】课件ID={} - 无学习记录", cw.getId()); } } } @@ -183,9 +206,15 @@ public class StudyLearningRecordServiceImpl implements IStudyLearningRecordServi { double completionRate = (double) completedCount / totalCoursewareCount * 100; BigDecimal progress = new BigDecimal(completionRate).setScale(2, BigDecimal.ROUND_HALF_UP); - return progress.compareTo(new BigDecimal(100)) > 0 ? new BigDecimal(100) : progress; + BigDecimal finalProgress = progress.compareTo(new BigDecimal(100)) > 0 ? new BigDecimal(100) : progress; + + logger.info("【进度计算】完成 - 学生ID={}, 课程ID={}, 已完成{}/总共{} = {}%", + studentId, courseId, completedCount, totalCoursewareCount, finalProgress); + + return finalProgress; } + logger.warn("【进度计算】总课件数为0 - 学生ID={}, 课程ID={}", studentId, courseId); return BigDecimal.ZERO; } @@ -198,6 +227,7 @@ public class StudyLearningRecordServiceImpl implements IStudyLearningRecordServi @Override public List selectLearningRecordListByStudentId(Long studentId) { + // ✅ 直接返回数据库中的进度值,与APP端保持一致 return learningRecordMapper.selectLearningRecordListByStudentId(studentId); } @@ -210,6 +240,7 @@ public class StudyLearningRecordServiceImpl implements IStudyLearningRecordServi @Override public List selectLearningRecordListByCourseId(Long courseId) { + // ✅ 直接返回数据库中的进度值,与APP端保持一致 return learningRecordMapper.selectLearningRecordListByCourseId(courseId); } diff --git a/Study-Vue-redis/ry-study-system/src/main/resources/mapper/study/StudyLearningRecordMapper.xml b/Study-Vue-redis/ry-study-system/src/main/resources/mapper/study/StudyLearningRecordMapper.xml index 835c8f0..358ba78 100644 --- a/Study-Vue-redis/ry-study-system/src/main/resources/mapper/study/StudyLearningRecordMapper.xml +++ b/Study-Vue-redis/ry-study-system/src/main/resources/mapper/study/StudyLearningRecordMapper.xml @@ -9,6 +9,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + @@ -24,9 +26,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - select lr.id, lr.student_id, lr.course_id, c.course_name, lr.progress, lr.total_duration, lr.learn_count, lr.video_progress, lr.video_total_duration, lr.last_learn_time, lr.last_video_position, lr.create_by, lr.create_time, lr.update_by, lr.update_time, lr.remark + select lr.id, lr.student_id, lr.course_id, c.course_name, + u.nick_name as student_name, u.user_id as student_no, + lr.progress, lr.total_duration, lr.learn_count, lr.video_progress, + lr.video_total_duration, lr.last_learn_time, lr.last_video_position, + lr.create_by, lr.create_time, lr.update_by, lr.update_time, lr.remark from learning_record lr left join course c on lr.course_id = c.id + left join sys_user u on lr.student_id = u.user_id - where id = #{id} + where lr.id = #{id} diff --git a/Study-Vue-redis/ry-study-ui/src/views/study/learningRecord/index.vue b/Study-Vue-redis/ry-study-ui/src/views/study/learningRecord/index.vue index 28b22c5..9d62d4e 100644 --- a/Study-Vue-redis/ry-study-ui/src/views/study/learningRecord/index.vue +++ b/Study-Vue-redis/ry-study-ui/src/views/study/learningRecord/index.vue @@ -1,12 +1,21 @@