From 48c03516281342035d1253abeaff66b5908b1742 Mon Sep 17 00:00:00 2001 From: "hhb@hotmail.com" Date: Tue, 18 Mar 2025 17:30:03 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E5=A4=84=E7=90=86=E4=B8=BB=E5=AE=A2?= =?UTF-8?q?=E8=A7=82=E7=AE=97=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/LaborEducationServiceImpl.java | 239 ++++++++++++----- .../impl/MoralEducationServiceImpl.java | 248 ++++++++++++------ .../frontend/AppraiseController.java | 5 +- .../model/dto/admin/labor/LaborDto.java | 1 + .../teammodel/repository/ExamRepository.java | 4 +- .../teammodel/service/EvaluationService.java | 3 +- .../service/impl/EvaluationServiceImpl.java | 8 +- 7 files changed, 353 insertions(+), 155 deletions(-) diff --git a/src/main/java/cn/teammodel/controller/admin/service/impl/LaborEducationServiceImpl.java b/src/main/java/cn/teammodel/controller/admin/service/impl/LaborEducationServiceImpl.java index a1c3bd0..c20a8ef 100644 --- a/src/main/java/cn/teammodel/controller/admin/service/impl/LaborEducationServiceImpl.java +++ b/src/main/java/cn/teammodel/controller/admin/service/impl/LaborEducationServiceImpl.java @@ -148,7 +148,10 @@ public class LaborEducationServiceImpl implements LaborEducationService { //获取所有课程下的课中活动 List exams = new ArrayList<>(); if (!recordIds.isEmpty()) { - exams = examRepository.findExamsByIds(String.format(PK.EXAM, laborDto.getTmdId()), recordIds); + exams = examRepository.findExamsByIds(laborDto.getSource(),recordIds); + exams = exams.stream() + .filter(exam -> !exam.getClasses().isEmpty()) + .collect(Collectors.toList()); } Map>> knowledgeMap = new HashMap<>(); Map> point = new HashMap<>(); @@ -246,27 +249,7 @@ public class LaborEducationServiceImpl implements LaborEducationService { } // 2. 将知识点得分汇总到知识块级别 - Map> studentKnowledgeBlockScores = new HashMap<>(); - for (Map.Entry> entry : studentKnowledgePointScores.entrySet()) { - String studentId = entry.getKey(); - Map pointScores = entry.getValue(); - Map blockScores = studentKnowledgeBlockScores.computeIfAbsent(studentId, k -> new HashMap<>()); - - // 遍历知识块和知识点的映射关系 - for (Map.Entry> blockEntry : knowledgeBlockToPointsMap.entrySet()) { - String knowledgeBlock = blockEntry.getKey(); - List knowledgePoints = blockEntry.getValue(); - - // 计算该知识块的总得分 - double totalScore = 0.0; - for (String knowledgePoint : knowledgePoints) { - if (pointScores.containsKey(knowledgePoint)) { - totalScore += pointScores.get(knowledgePoint); - } - } - blockScores.put(knowledgeBlock, totalScore); - } - } + Map> studentKnowledgeBlockScores = getStringMapMap(knowledgeBlockToPointsMap, studentKnowledgePointScores); // 3. 更新现有的 scores 返回数据 for (Map studentResult : scores) { @@ -293,46 +276,48 @@ public class LaborEducationServiceImpl implements LaborEducationService { } double maxCount = 50.0; // 最大次数(可根据实际情况调整) - // 将次数转换为 0-100 的分数 + // 将次数转换为 60-100 的分数(60分基础,额外加分不超过40分) double convertedScore; if (count > maxCount) { - convertedScore = 100.0; // 如果次数超过最大次数,设置为满分 + convertedScore = 100.0; // 超过最大次数,直接满分 } else { - convertedScore = (count / maxCount) * 100; + // 计算额外加分(占总40分的比例) + double additionalScore = (count / maxCount) * 40; + convertedScore = 60 + additionalScore; + // 保留两位小数 convertedScore = Double.parseDouble(String.format("%.2f", convertedScore)); } subjectiveTotal += convertedScore; - // 获取对应知识块的客观成绩 + // 获取对应知识块的客观成绩,并确保在60-100之间 double objectiveScore = knowledgeBlockScores.get(knowledgeBlock); + objectiveScore = Math.max(60.0, Math.min(100.0, objectiveScore)); // 确保60-100分 objectiveTotal += objectiveScore; + + // 计算综合得分(主观占60%,客观占40%) score = convertedScore * 0.6 + objectiveScore * 0.4; - /* - 形成 次数/客观分数 的格式 - String combinedScore = count + "/" + objectiveScore; - */ - double finalCount = convertedScore; + score = Double.parseDouble(String.format("%.2f", score)); + + // 存储结果 + double finalConvertedScore = convertedScore; + double finalObjectiveScore = objectiveScore; double finalScore = score; - finalScore = Double.parseDouble(String.format("%.2f", finalScore)); - double finalScore1 = finalScore; combinedScores.put(knowledgeBlock, new HashMap() {{ - put("count", finalCount); - put("objectiveScore", objectiveScore); - put("compositeScore", finalScore1); - + put("count", finalConvertedScore); + put("objectiveScore", finalObjectiveScore); + put("compositeScore", finalScore); }}); - //combinedScores.put(knowledgeBlock, objectiveScore); - } // 计算客观平均分 double objectiveAverage = (knowledgeBlockCount > 0) ? objectiveTotal / knowledgeBlockCount : 0.0; objectiveAverage = Double.parseDouble(String.format("%.2f", objectiveAverage)); - //计算主观平均分 + + // 计算主观平均分 double subjectiveAverage = (subjectiveTotal > 0) ? subjectiveTotal / knowledgeBlockCount : 0.0; subjectiveAverage = Double.parseDouble(String.format("%.2f", subjectiveAverage)); - // 计算综合得分(主观占 60%,客观占 40%) + // 计算综合得分(主观占60%,客观占40%) double compositeScore = (subjectiveAverage * 0.6) + (objectiveAverage * 0.4); compositeScore = Double.parseDouble(String.format("%.2f", compositeScore)); @@ -346,6 +331,37 @@ public class LaborEducationServiceImpl implements LaborEducationService { return scores; } + private static @NotNull Map> getStringMapMap(Map> knowledgeBlockToPointsMap, Map> studentKnowledgePointScores) { + Map> studentKnowledgeBlockScores = new HashMap<>(); + for (Map.Entry> entry : studentKnowledgePointScores.entrySet()) { + String studentId = entry.getKey(); + Map pointScores = entry.getValue(); + Map blockScores = studentKnowledgeBlockScores.computeIfAbsent(studentId, k -> new HashMap<>()); + + // 遍历知识块和知识点的映射关系 + for (Map.Entry> blockEntry : knowledgeBlockToPointsMap.entrySet()) { + String knowledgeBlock = blockEntry.getKey(); + List knowledgePoints = blockEntry.getValue(); + + // 计算该知识块的总得分和知识点数量 + double totalScore = 0.0; + int validPointCount = 0; // 有效知识点数量(有实际得分的知识点) + for (String knowledgePoint : knowledgePoints) { + if (pointScores.containsKey(knowledgePoint)) { + totalScore += pointScores.get(knowledgePoint); + validPointCount++; + } + } + + // 计算知识块的平均分 + double averageScore = (validPointCount > 0) ? totalScore / validPointCount : 60.0; // 无有效知识点时默认60分 + averageScore = Math.max(60.0, Math.min(100.0, averageScore)); // 确保得分在60-100之间 + blockScores.put(knowledgeBlock, averageScore); + } + } + return studentKnowledgeBlockScores; + } + public static List> calculateScoresWithDetails(List res, Appraise appraise) { // 1. 构建知识点到知识块的映射 (一个知识块对应多个知识点) @@ -392,7 +408,6 @@ public class LaborEducationServiceImpl implements LaborEducationService { studentScores.putIfAbsent(studentKey, new HashMap<>()); Map studentScoreMap = studentScores.get(studentKey); - // 计分 // 计分 int score = isPraise ? 1 : -1; int currentScore = studentScoreMap.getOrDefault(knowledgeBlock, 0) + score; @@ -495,32 +510,47 @@ public class LaborEducationServiceImpl implements LaborEducationService { String studentId, List examResults, Map>> knowledgeMap, Appraise appraise, Map> points) { Map knowledgeTotalScore = new HashMap<>(); + // 计算学生的知识点得分率 List studentScoreRates = calculateStudentScoreRates(studentId, examResults, knowledgeMap, points, knowledgeTotalScore); - // 查找知识点对应的节点及其父节点 Map parentNodeScoreRates = new HashMap<>(); + Map parentNodeScoreCount = new HashMap<>(); // 记录每个父节点的知识点数量 + for (KnowledgeScoreRate scoreRate : studentScoreRates) { AppraiseTreeNode node = findKnowledgeNode(appraise.getNodes(), scoreRate.getKnowledge()); if (node != null) { AppraiseTreeNode parentNode = findParentNode(appraise.getNodes(), node.getId()); if (parentNode != null) { - double parentNodeScoreRate = calculateNodeScoreRate(parentNode, knowledgeTotalScore); - parentNodeScoreRates.put(parentNode.getName(), parentNodeScoreRate); - }else { - // 如果没有找到父节点,初始化一个默认的得分率为0的父节点得分率 - parentNodeScoreRates.put(node.getName(), 0.0); + // 累加父节点的得分 + double currentScore = parentNodeScoreRates.getOrDefault(parentNode.getName(), 0.0); + parentNodeScoreRates.put(parentNode.getName(), currentScore + scoreRate.getScoreRate()); + + // 累加父节点的知识点数量 + int currentCount = parentNodeScoreCount.getOrDefault(parentNode.getName(), 0); + parentNodeScoreCount.put(parentNode.getName(), currentCount + 1); + } else { + // 如果没有找到父节点,直接使用当前知识点的得分 + parentNodeScoreRates.put(node.getName(), scoreRate.getScoreRate()); + parentNodeScoreCount.put(node.getName(), 1); } } } + // 计算父节点的平均得分 + parentNodeScoreRates.replaceAll((parentNodeName, totalScore) -> { + int count = parentNodeScoreCount.getOrDefault(parentNodeName, 1); + double averageScore = totalScore / count; + return Math.min(100.0, Math.max(60.0, averageScore)); // 确保得分在60-100之间 + }); + // 初始化所有同层的父节点 for (AppraiseTreeNode node : appraise.getNodes()) { if (node.getName().equals("德育")) { for (AppraiseTreeNode child : node.getChildren()) { if (!parentNodeScoreRates.containsKey(child.getName())) { - parentNodeScoreRates.put(child.getName(), 0.0); + parentNodeScoreRates.put(child.getName(), 60.0); // 默认60分 } } } @@ -617,6 +647,9 @@ public class LaborEducationServiceImpl implements LaborEducationService { Map scoreRates = calculateKnowledgeScoreRateForStudent( studentId, examResults, knowledgeMap, appraise, points ); + scoreRates.replaceAll((k, v) -> + Math.min(100.0, Math.max(60.0, v)) // 60分打底,最高100分 + ); studentScoreRates.put(name, scoreRates); // 累加班级整体得分率 @@ -625,21 +658,17 @@ public class LaborEducationServiceImpl implements LaborEducationService { } } } - }else { - // 无考试数据时,初始化所有学生的默认分数为0 + } else { + // 无考试数据时,初始化所有学生的默认分数为60 if (groupList != null) { for (RMember member : groupList.members) { String studentId = member.getId(); String studentName = studentIdToName.getOrDefault(studentId, "未知学生"); Map defaultScores = new HashMap<>(); for (String block : knowledgeBlocks) { - defaultScores.put(block, 0.0); + defaultScores.put(block, 60.0); // 初始化为60分 } studentScoreRates.put(studentName, defaultScores); - // 初始化班级得分率 - for (String block : knowledgeBlocks) { - classScoreRates.put(block, 0.0); - } } } } @@ -659,11 +688,15 @@ public class LaborEducationServiceImpl implements LaborEducationService { String block = entry.getKey(); int count = entry.getValue(); double maxCount = 50.0; + // 将次数转换为 60-100 的分数(60分基础,额外加分不超过40分) double convertedScore; if (count > maxCount) { - convertedScore = 100.0; // 如果次数超过最大次数,设置为满分 + convertedScore = 100.0; // 超过最大次数,直接满分 } else { - convertedScore = (count / maxCount) * 100; + // 计算额外加分(占总40分的比例) + double additionalScore = (count / maxCount) * 40; + convertedScore = 60 + additionalScore; + // 保留两位小数 convertedScore = Double.parseDouble(String.format("%.2f", convertedScore)); } convertedScores.put(block, convertedScore); @@ -676,15 +709,23 @@ public class LaborEducationServiceImpl implements LaborEducationService { Map> compositeStudentScores = new HashMap<>(); for (String studentId : studentIdToName.keySet()) { String studentName = studentIdToName.get(studentId); + // 获取客观分数(已确保60-100分) Map objective = studentScoreRates.getOrDefault(studentName, new HashMap<>()); + // 获取主观分数(确保60-100分) Map subjective = subjectiveScores.getOrDefault(studentId, new HashMap<>()); Map compositeScores = new HashMap<>(); for (String block : knowledgeBlocks) { - double objectiveScore = objective.getOrDefault(block, 0.0); - double subjectiveScore = subjective.getOrDefault(block, 0.0); + // 客观分数兜底逻辑(确保60分) + double objectiveScore = objective.getOrDefault(block, 60.0); + // 主观分数兜底逻辑(确保60分) + double subjectiveScore = subjective.getOrDefault(block, 60.0); + + // 计算综合得分(主观60% + 客观40%) double compositeScore = (subjectiveScore * 0.6) + (objectiveScore * 0.4); + compositeScore = Math.min(100.0, compositeScore); // 确保不超过100分 compositeScore = Double.parseDouble(String.format("%.2f", compositeScore)); + compositeScores.put(block, compositeScore); } compositeStudentScores.put(studentName, compositeScores); @@ -775,6 +816,20 @@ public class LaborEducationServiceImpl implements LaborEducationService { Map knowledgeTotalAverage = new HashMap<>(); Map knowledgeExamCount = new HashMap<>(); + // 如果没有考试数据,初始化所有知识点分数为60分 + if (examResults == null || examResults.isEmpty()) { + for (String knowledge : knowledgeMap.values().stream() + .flatMap(List::stream) + .flatMap(List::stream) + .collect(Collectors.toSet())) { + knowledgeTotalScore.put(knowledge, 60.0); // 默认60分 + } + return knowledgeTotalScore.entrySet().stream() + .map(entry -> new KnowledgeScoreRate(entry.getKey(), entry.getValue())) + .collect(Collectors.toList()); + } + + // 正常处理考试数据 for (ExamClassResult examResult : examResults) { int studentIndex = examResult.getStudentIds().indexOf(studentId); if (studentIndex == -1) continue; @@ -825,15 +880,29 @@ public class LaborEducationServiceImpl implements LaborEducationService { } } - // 计算最终平均分(所有考试平均分的平均) + // 计算最终平均分(所有考试平均分的平均),并限制在60-100分之间 for (String knowledge : knowledgeTotalAverage.keySet()) { double totalAverage = knowledgeTotalAverage.get(knowledge); int examCount = knowledgeExamCount.get(knowledge); double finalAverage = totalAverage / examCount; - finalAverage = Double.parseDouble(String.format("%.2f", finalAverage)); + + // 确保分数在60-100之间 + finalAverage = Math.max(60.0, Math.min(100.0, finalAverage)); // 60分打底,不超过100分 + finalAverage = Double.parseDouble(String.format("%.2f", finalAverage)); // 保留两位小数 + knowledgeTotalScore.put(knowledge, finalAverage); } + // 如果没有考试数据,确保所有知识点都有默认60分 + if (knowledgeTotalScore.isEmpty()) { + for (String knowledge : knowledgeMap.values().stream() + .flatMap(List::stream) + .flatMap(List::stream) + .collect(Collectors.toSet())) { + knowledgeTotalScore.put(knowledge, 60.0); // 默认60分 + } + } + return knowledgeTotalScore.entrySet().stream() .map(entry -> new KnowledgeScoreRate(entry.getKey(), entry.getValue())) .collect(Collectors.toList()); @@ -911,8 +980,17 @@ public class LaborEducationServiceImpl implements LaborEducationService { String block = entry.getKey(); int count = entry.getValue(); double maxCount = 50.0; - double convertedScore = (count > maxCount) ? 100.0 : (count / maxCount) * 100; - convertedScore = Double.parseDouble(String.format("%.2f", convertedScore)); + // 将次数转换为 60-100 的分数(60分基础,额外加分不超过40分) + double convertedScore; + if (count > maxCount) { + convertedScore = 100.0; // 超过最大次数,直接满分 + } else { + // 计算额外加分(占总40分的比例) + double additionalScore = (count / maxCount) * 40; + convertedScore = 60 + additionalScore; + // 保留两位小数 + convertedScore = Double.parseDouble(String.format("%.2f", convertedScore)); + } convertedScores.put(block, convertedScore); } subjectiveScores.put(studentId, convertedScores); @@ -950,6 +1028,14 @@ public class LaborEducationServiceImpl implements LaborEducationService { studentId, examResults, knowledgeMap, appraise, points ); + // 确保客观分数最低为60分 + for (Map.Entry entry : studentObjectiveScores.entrySet()) { + String block = entry.getKey(); + double score = entry.getValue(); + score = Math.max(60.0, Math.min(100.0, score)); // 确保60-100分 + studentObjectiveScores.put(block, score); + } + // 获取学生的主观分数 Map studentSubjectiveScores = subjectiveScores.getOrDefault(studentId, new HashMap<>()); @@ -960,9 +1046,10 @@ public class LaborEducationServiceImpl implements LaborEducationService { // 计算综合得分(主观60%,客观40%) for (String block : allBlocks) { - double objectiveScore = studentObjectiveScores.getOrDefault(block, 0.0); + double objectiveScore = studentObjectiveScores.getOrDefault(block, 60.0); // 默认60分 double subjectiveScore = studentSubjectiveScores.getOrDefault(block, 0.0); double compositeScore = (subjectiveScore * 0.6) + (objectiveScore * 0.4); + compositeScore = Math.max(60.0, Math.min(100.0, compositeScore)); // 确保60-100分 compositeScore = Double.parseDouble(String.format("%.2f", compositeScore)); // 累加班级得分 @@ -982,7 +1069,7 @@ public class LaborEducationServiceImpl implements LaborEducationService { for (AppraiseTreeNode node : appraise.getNodes()) { if ("德育".equals(node.getName())) { node.getChildren().forEach(child -> - classScoresInner.putIfAbsent(child.getName(), 0.0)); + classScoresInner.putIfAbsent(child.getName(), 60.0)); // 默认60分 } } @@ -1007,7 +1094,7 @@ public class LaborEducationServiceImpl implements LaborEducationService { for (AppraiseTreeNode node : appraise.getNodes()) { if ("德育".equals(node.getName())) { node.getChildren().forEach(child -> - gradeScores.putIfAbsent(child.getName(), 0.0)); + gradeScores.putIfAbsent(child.getName(), 60.0)); // 默认60分 } } @@ -1079,7 +1166,7 @@ public class LaborEducationServiceImpl implements LaborEducationService { List> subjectiveScoresList = calculateScoresWithDetails(res, appraise); // 3. 将主观次数转换为0-100分数 - Map> subjectiveScores = new HashMap<>(); + //Map> subjectiveScores = new HashMap<>(); for (Map studentScore : subjectiveScoresList) { String studentId = (String) studentScore.get("studentId"); @SuppressWarnings("unchecked") @@ -1090,17 +1177,21 @@ public class LaborEducationServiceImpl implements LaborEducationService { String block = entry.getKey(); int count = entry.getValue(); double maxCount = 50.0; + // 将次数转换为 60-100 的分数(60分基础,额外加分不超过40分) double convertedScore; if (count > maxCount) { - convertedScore = 100.0; // 如果次数超过最大次数,设置为满分 + convertedScore = 100.0; // 超过最大次数,直接满分 } else { - convertedScore = (count / maxCount) * 100; + // 计算额外加分(占总40分的比例) + double additionalScore = (count / maxCount) * 40; + convertedScore = 60 + additionalScore; + // 保留两位小数 convertedScore = Double.parseDouble(String.format("%.2f", convertedScore)); } convertedScores.put(block, convertedScore); } - subjectiveScores.put(studentId, convertedScores); + //subjectiveScores.put(studentId, convertedScores); } // 4. 遍历所有年级 @@ -1156,7 +1247,7 @@ public class LaborEducationServiceImpl implements LaborEducationService { for (Map.Entry entry : schoolScores.entrySet()) { String nodeName = entry.getKey(); double totalScore = entry.getValue(); - int totalCount = gradeIds.size(); // 每个年级视为一个单位 + int totalCount = schoolScores.size(); // 每个年级视为一个单位 schoolScores.put(nodeName, Double.parseDouble(String.format("%.2f", totalScore / totalCount))); // 保留小数点后两位 } } @@ -1173,6 +1264,10 @@ public class LaborEducationServiceImpl implements LaborEducationService { } // 7. 转换 gradeScores 为新的数据结构 + return getResult(gradeScores, schoolScores); + } + + private static @NotNull Map getResult(Map> gradeScores, Map schoolScores) { List> adjustedGradeScores = new ArrayList<>(); for (Map.Entry> entry : gradeScores.entrySet()) { String gradeName = entry.getKey(); diff --git a/src/main/java/cn/teammodel/controller/admin/service/impl/MoralEducationServiceImpl.java b/src/main/java/cn/teammodel/controller/admin/service/impl/MoralEducationServiceImpl.java index 7182317..cda9de5 100644 --- a/src/main/java/cn/teammodel/controller/admin/service/impl/MoralEducationServiceImpl.java +++ b/src/main/java/cn/teammodel/controller/admin/service/impl/MoralEducationServiceImpl.java @@ -148,7 +148,10 @@ public class MoralEducationServiceImpl implements MoralEducationService { //获取所有课程下的课中活动 List exams = new ArrayList<>(); if (!recordIds.isEmpty()) { - exams = examRepository.findExamsByIds(String.format(PK.EXAM, laborDto.getTmdId()), recordIds); + exams = examRepository.findExamsByIds(laborDto.getSource(),recordIds); + exams = exams.stream() + .filter(exam -> !exam.getClasses().isEmpty()) + .collect(Collectors.toList()); } Map>> knowledgeMap = new HashMap<>(); Map> point = new HashMap<>(); @@ -246,27 +249,7 @@ public class MoralEducationServiceImpl implements MoralEducationService { } // 2. 将知识点得分汇总到知识块级别 - Map> studentKnowledgeBlockScores = new HashMap<>(); - for (Map.Entry> entry : studentKnowledgePointScores.entrySet()) { - String studentId = entry.getKey(); - Map pointScores = entry.getValue(); - Map blockScores = studentKnowledgeBlockScores.computeIfAbsent(studentId, k -> new HashMap<>()); - - // 遍历知识块和知识点的映射关系 - for (Map.Entry> blockEntry : knowledgeBlockToPointsMap.entrySet()) { - String knowledgeBlock = blockEntry.getKey(); - List knowledgePoints = blockEntry.getValue(); - - // 计算该知识块的总得分 - double totalScore = 0.0; - for (String knowledgePoint : knowledgePoints) { - if (pointScores.containsKey(knowledgePoint)) { - totalScore += pointScores.get(knowledgePoint); - } - } - blockScores.put(knowledgeBlock, totalScore); - } - } + Map> studentKnowledgeBlockScores = getStringMapMap(knowledgeBlockToPointsMap, studentKnowledgePointScores); // 3. 更新现有的 scores 返回数据 for (Map studentResult : scores) { @@ -293,46 +276,48 @@ public class MoralEducationServiceImpl implements MoralEducationService { } double maxCount = 50.0; // 最大次数(可根据实际情况调整) - // 将次数转换为 0-100 的分数 + // 将次数转换为 60-100 的分数(60分基础,额外加分不超过40分) double convertedScore; if (count > maxCount) { - convertedScore = 100.0; // 如果次数超过最大次数,设置为满分 + convertedScore = 100.0; // 超过最大次数,直接满分 } else { - convertedScore = (count / maxCount) * 100; + // 计算额外加分(占总40分的比例) + double additionalScore = (count / maxCount) * 40; + convertedScore = 60 + additionalScore; + // 保留两位小数 convertedScore = Double.parseDouble(String.format("%.2f", convertedScore)); } subjectiveTotal += convertedScore; - // 获取对应知识块的客观成绩 + // 获取对应知识块的客观成绩,并确保在60-100之间 double objectiveScore = knowledgeBlockScores.get(knowledgeBlock); + objectiveScore = Math.max(60.0, Math.min(100.0, objectiveScore)); // 确保60-100分 objectiveTotal += objectiveScore; + + // 计算综合得分(主观占60%,客观占40%) score = convertedScore * 0.6 + objectiveScore * 0.4; - /* - 形成 次数/客观分数 的格式 - String combinedScore = count + "/" + objectiveScore; - */ - double finalCount = convertedScore; + score = Double.parseDouble(String.format("%.2f", score)); + + // 存储结果 + double finalConvertedScore = convertedScore; + double finalObjectiveScore = objectiveScore; double finalScore = score; - finalScore = Double.parseDouble(String.format("%.2f", finalScore)); - double finalScore1 = finalScore; combinedScores.put(knowledgeBlock, new HashMap() {{ - put("count", finalCount); - put("objectiveScore", objectiveScore); - put("compositeScore", finalScore1); - + put("count", finalConvertedScore); + put("objectiveScore", finalObjectiveScore); + put("compositeScore", finalScore); }}); - //combinedScores.put(knowledgeBlock, objectiveScore); - } // 计算客观平均分 double objectiveAverage = (knowledgeBlockCount > 0) ? objectiveTotal / knowledgeBlockCount : 0.0; objectiveAverage = Double.parseDouble(String.format("%.2f", objectiveAverage)); - //计算主观平均分 + + // 计算主观平均分 double subjectiveAverage = (subjectiveTotal > 0) ? subjectiveTotal / knowledgeBlockCount : 0.0; subjectiveAverage = Double.parseDouble(String.format("%.2f", subjectiveAverage)); - // 计算综合得分(主观占 60%,客观占 40%) + // 计算综合得分(主观占60%,客观占40%) double compositeScore = (subjectiveAverage * 0.6) + (objectiveAverage * 0.4); compositeScore = Double.parseDouble(String.format("%.2f", compositeScore)); @@ -346,6 +331,37 @@ public class MoralEducationServiceImpl implements MoralEducationService { return scores; } + private static @NotNull Map> getStringMapMap(Map> knowledgeBlockToPointsMap, Map> studentKnowledgePointScores) { + Map> studentKnowledgeBlockScores = new HashMap<>(); + for (Map.Entry> entry : studentKnowledgePointScores.entrySet()) { + String studentId = entry.getKey(); + Map pointScores = entry.getValue(); + Map blockScores = studentKnowledgeBlockScores.computeIfAbsent(studentId, k -> new HashMap<>()); + + // 遍历知识块和知识点的映射关系 + for (Map.Entry> blockEntry : knowledgeBlockToPointsMap.entrySet()) { + String knowledgeBlock = blockEntry.getKey(); + List knowledgePoints = blockEntry.getValue(); + + // 计算该知识块的总得分和知识点数量 + double totalScore = 0.0; + int validPointCount = 0; // 有效知识点数量(有实际得分的知识点) + for (String knowledgePoint : knowledgePoints) { + if (pointScores.containsKey(knowledgePoint)) { + totalScore += pointScores.get(knowledgePoint); + validPointCount++; + } + } + + // 计算知识块的平均分 + double averageScore = (validPointCount > 0) ? totalScore / validPointCount : 60.0; // 无有效知识点时默认60分 + averageScore = Math.max(60.0, Math.min(100.0, averageScore)); // 确保得分在60-100之间 + blockScores.put(knowledgeBlock, averageScore); + } + } + return studentKnowledgeBlockScores; + } + public static List> calculateScoresWithDetails(List res, Appraise appraise) { // 1. 构建知识点到知识块的映射 (一个知识块对应多个知识点) @@ -392,6 +408,7 @@ public class MoralEducationServiceImpl implements MoralEducationService { studentScores.putIfAbsent(studentKey, new HashMap<>()); Map studentScoreMap = studentScores.get(studentKey); + // 计分 // 计分 int score = isPraise ? 1 : -1; int currentScore = studentScoreMap.getOrDefault(knowledgeBlock, 0) + score; @@ -449,7 +466,6 @@ public class MoralEducationServiceImpl implements MoralEducationService { return result; } - // 构建知识块到知识点的映射 (一个知识块对应多个知识点) private static Map> getKnowledgeBlockToPointsMap(Appraise appraise) { Map> knowledgeBlockToPointsMap = new HashMap<>(); @@ -495,32 +511,47 @@ public class MoralEducationServiceImpl implements MoralEducationService { String studentId, List examResults, Map>> knowledgeMap, Appraise appraise, Map> points) { Map knowledgeTotalScore = new HashMap<>(); - // 计算学生的知识点得分率 - List studentScoreRates = calculateStudentScoreRates(studentId, examResults, knowledgeMap, points, knowledgeTotalScore); + // 计算学生的知识点得分率 + List studentScoreRates = calculateStudentScoreRates(studentId, examResults, knowledgeMap, points, knowledgeTotalScore); // 查找知识点对应的节点及其父节点 Map parentNodeScoreRates = new HashMap<>(); - for (KnowledgeScoreRate scoreRate : studentScoreRates) { + Map parentNodeScoreCount = new HashMap<>(); // 记录每个父节点的知识点数量 + + for (LaborEducationServiceImpl.KnowledgeScoreRate scoreRate : studentScoreRates) { AppraiseTreeNode node = findKnowledgeNode(appraise.getNodes(), scoreRate.getKnowledge()); if (node != null) { AppraiseTreeNode parentNode = findParentNode(appraise.getNodes(), node.getId()); if (parentNode != null) { - double parentNodeScoreRate = calculateNodeScoreRate(parentNode, knowledgeTotalScore); - parentNodeScoreRates.put(parentNode.getName(), parentNodeScoreRate); - }else { - // 如果没有找到父节点,初始化一个默认的得分率为0的父节点得分率 - parentNodeScoreRates.put(node.getName(), 0.0); + // 累加父节点的得分 + double currentScore = parentNodeScoreRates.getOrDefault(parentNode.getName(), 0.0); + parentNodeScoreRates.put(parentNode.getName(), currentScore + scoreRate.getScoreRate()); + + // 累加父节点的知识点数量 + int currentCount = parentNodeScoreCount.getOrDefault(parentNode.getName(), 0); + parentNodeScoreCount.put(parentNode.getName(), currentCount + 1); + } else { + // 如果没有找到父节点,直接使用当前知识点的得分 + parentNodeScoreRates.put(node.getName(), scoreRate.getScoreRate()); + parentNodeScoreCount.put(node.getName(), 1); } } } + // 计算父节点的平均得分 + parentNodeScoreRates.replaceAll((parentNodeName, totalScore) -> { + int count = parentNodeScoreCount.getOrDefault(parentNodeName, 1); + double averageScore = totalScore / count; + return Math.min(100.0, Math.max(60.0, averageScore)); // 确保得分在60-100之间 + }); + // 初始化所有同层的父节点 for (AppraiseTreeNode node : appraise.getNodes()) { if (node.getName().equals("劳育")) { for (AppraiseTreeNode child : node.getChildren()) { if (!parentNodeScoreRates.containsKey(child.getName())) { - parentNodeScoreRates.put(child.getName(), 0.0); + parentNodeScoreRates.put(child.getName(), 60.0); // 默认60分 } } } @@ -617,6 +648,9 @@ public class MoralEducationServiceImpl implements MoralEducationService { Map scoreRates = calculateKnowledgeScoreRateForStudent( studentId, examResults, knowledgeMap, appraise, points ); + scoreRates.replaceAll((k, v) -> + Math.min(100.0, Math.max(60.0, v)) // 60分打底,最高100分 + ); studentScoreRates.put(name, scoreRates); // 累加班级整体得分率 @@ -625,21 +659,17 @@ public class MoralEducationServiceImpl implements MoralEducationService { } } } - }else { - // 无考试数据时,初始化所有学生的默认分数为0 + } else { + // 无考试数据时,初始化所有学生的默认分数为60 if (groupList != null) { for (RMember member : groupList.members) { String studentId = member.getId(); String studentName = studentIdToName.getOrDefault(studentId, "未知学生"); Map defaultScores = new HashMap<>(); for (String block : knowledgeBlocks) { - defaultScores.put(block, 0.0); + defaultScores.put(block, 60.0); // 初始化为60分 } studentScoreRates.put(studentName, defaultScores); - // 初始化班级得分率 - for (String block : knowledgeBlocks) { - classScoreRates.put(block, 0.0); - } } } } @@ -659,11 +689,15 @@ public class MoralEducationServiceImpl implements MoralEducationService { String block = entry.getKey(); int count = entry.getValue(); double maxCount = 50.0; + // 将次数转换为 60-100 的分数(60分基础,额外加分不超过40分) double convertedScore; if (count > maxCount) { - convertedScore = 100.0; // 如果次数超过最大次数,设置为满分 + convertedScore = 100.0; // 超过最大次数,直接满分 } else { - convertedScore = (count / maxCount) * 100; + // 计算额外加分(占总40分的比例) + double additionalScore = (count / maxCount) * 40; + convertedScore = 60 + additionalScore; + // 保留两位小数 convertedScore = Double.parseDouble(String.format("%.2f", convertedScore)); } convertedScores.put(block, convertedScore); @@ -676,15 +710,23 @@ public class MoralEducationServiceImpl implements MoralEducationService { Map> compositeStudentScores = new HashMap<>(); for (String studentId : studentIdToName.keySet()) { String studentName = studentIdToName.get(studentId); + // 获取客观分数(已确保60-100分) Map objective = studentScoreRates.getOrDefault(studentName, new HashMap<>()); + // 获取主观分数(确保60-100分) Map subjective = subjectiveScores.getOrDefault(studentId, new HashMap<>()); Map compositeScores = new HashMap<>(); for (String block : knowledgeBlocks) { - double objectiveScore = objective.getOrDefault(block, 0.0); - double subjectiveScore = subjective.getOrDefault(block, 0.0); + // 客观分数兜底逻辑(确保60分) + double objectiveScore = objective.getOrDefault(block, 60.0); + // 主观分数兜底逻辑(确保60分) + double subjectiveScore = subjective.getOrDefault(block, 60.0); + + // 计算综合得分(主观60% + 客观40%) double compositeScore = (subjectiveScore * 0.6) + (objectiveScore * 0.4); + compositeScore = Math.min(100.0, compositeScore); // 确保不超过100分 compositeScore = Double.parseDouble(String.format("%.2f", compositeScore)); + compositeScores.put(block, compositeScore); } compositeStudentScores.put(studentName, compositeScores); @@ -765,7 +807,7 @@ public class MoralEducationServiceImpl implements MoralEducationService { } - private static List calculateStudentScoreRates( + private static List calculateStudentScoreRates( String studentId, List examResults, Map>> knowledgeMap, @@ -775,6 +817,20 @@ public class MoralEducationServiceImpl implements MoralEducationService { Map knowledgeTotalAverage = new HashMap<>(); Map knowledgeExamCount = new HashMap<>(); + // 如果没有考试数据,初始化所有知识点分数为60分 + if (examResults == null || examResults.isEmpty()) { + for (String knowledge : knowledgeMap.values().stream() + .flatMap(List::stream) + .flatMap(List::stream) + .collect(Collectors.toSet())) { + knowledgeTotalScore.put(knowledge, 60.0); // 默认60分 + } + return knowledgeTotalScore.entrySet().stream() + .map(entry -> new LaborEducationServiceImpl.KnowledgeScoreRate(entry.getKey(), entry.getValue())) + .collect(Collectors.toList()); + } + + // 正常处理考试数据 for (ExamClassResult examResult : examResults) { int studentIndex = examResult.getStudentIds().indexOf(studentId); if (studentIndex == -1) continue; @@ -825,17 +881,31 @@ public class MoralEducationServiceImpl implements MoralEducationService { } } - // 计算最终平均分(所有考试平均分的平均) + // 计算最终平均分(所有考试平均分的平均),并限制在60-100分之间 for (String knowledge : knowledgeTotalAverage.keySet()) { double totalAverage = knowledgeTotalAverage.get(knowledge); int examCount = knowledgeExamCount.get(knowledge); double finalAverage = totalAverage / examCount; - finalAverage = Double.parseDouble(String.format("%.2f", finalAverage)); + + // 确保分数在60-100之间 + finalAverage = Math.max(60.0, Math.min(100.0, finalAverage)); // 60分打底,不超过100分 + finalAverage = Double.parseDouble(String.format("%.2f", finalAverage)); // 保留两位小数 + knowledgeTotalScore.put(knowledge, finalAverage); } + // 如果没有考试数据,确保所有知识点都有默认60分 + if (knowledgeTotalScore.isEmpty()) { + for (String knowledge : knowledgeMap.values().stream() + .flatMap(List::stream) + .flatMap(List::stream) + .collect(Collectors.toSet())) { + knowledgeTotalScore.put(knowledge, 60.0); // 默认60分 + } + } + return knowledgeTotalScore.entrySet().stream() - .map(entry -> new KnowledgeScoreRate(entry.getKey(), entry.getValue())) + .map(entry -> new LaborEducationServiceImpl.KnowledgeScoreRate(entry.getKey(), entry.getValue())) .collect(Collectors.toList()); } @@ -911,8 +981,17 @@ public class MoralEducationServiceImpl implements MoralEducationService { String block = entry.getKey(); int count = entry.getValue(); double maxCount = 50.0; - double convertedScore = (count > maxCount) ? 100.0 : (count / maxCount) * 100; - convertedScore = Double.parseDouble(String.format("%.2f", convertedScore)); + // 将次数转换为 60-100 的分数(60分基础,额外加分不超过40分) + double convertedScore; + if (count > maxCount) { + convertedScore = 100.0; // 超过最大次数,直接满分 + } else { + // 计算额外加分(占总40分的比例) + double additionalScore = (count / maxCount) * 40; + convertedScore = 60 + additionalScore; + // 保留两位小数 + convertedScore = Double.parseDouble(String.format("%.2f", convertedScore)); + } convertedScores.put(block, convertedScore); } subjectiveScores.put(studentId, convertedScores); @@ -950,6 +1029,14 @@ public class MoralEducationServiceImpl implements MoralEducationService { studentId, examResults, knowledgeMap, appraise, points ); + // 确保客观分数最低为60分 + for (Map.Entry entry : studentObjectiveScores.entrySet()) { + String block = entry.getKey(); + double score = entry.getValue(); + score = Math.max(60.0, Math.min(100.0, score)); // 确保60-100分 + studentObjectiveScores.put(block, score); + } + // 获取学生的主观分数 Map studentSubjectiveScores = subjectiveScores.getOrDefault(studentId, new HashMap<>()); @@ -960,9 +1047,10 @@ public class MoralEducationServiceImpl implements MoralEducationService { // 计算综合得分(主观60%,客观40%) for (String block : allBlocks) { - double objectiveScore = studentObjectiveScores.getOrDefault(block, 0.0); + double objectiveScore = studentObjectiveScores.getOrDefault(block, 60.0); // 默认60分 double subjectiveScore = studentSubjectiveScores.getOrDefault(block, 0.0); double compositeScore = (subjectiveScore * 0.6) + (objectiveScore * 0.4); + compositeScore = Math.max(60.0, Math.min(100.0, compositeScore)); // 确保60-100分 compositeScore = Double.parseDouble(String.format("%.2f", compositeScore)); // 累加班级得分 @@ -982,7 +1070,7 @@ public class MoralEducationServiceImpl implements MoralEducationService { for (AppraiseTreeNode node : appraise.getNodes()) { if ("劳育".equals(node.getName())) { node.getChildren().forEach(child -> - classScoresInner.putIfAbsent(child.getName(), 0.0)); + classScoresInner.putIfAbsent(child.getName(), 60.0)); // 默认60分 } } @@ -1007,7 +1095,7 @@ public class MoralEducationServiceImpl implements MoralEducationService { for (AppraiseTreeNode node : appraise.getNodes()) { if ("劳育".equals(node.getName())) { node.getChildren().forEach(child -> - gradeScores.putIfAbsent(child.getName(), 0.0)); + gradeScores.putIfAbsent(child.getName(), 60.0)); // 默认60分 } } @@ -1079,7 +1167,7 @@ public class MoralEducationServiceImpl implements MoralEducationService { List> subjectiveScoresList = calculateScoresWithDetails(res, appraise); // 3. 将主观次数转换为0-100分数 - Map> subjectiveScores = new HashMap<>(); + //Map> subjectiveScores = new HashMap<>(); for (Map studentScore : subjectiveScoresList) { String studentId = (String) studentScore.get("studentId"); @SuppressWarnings("unchecked") @@ -1090,17 +1178,21 @@ public class MoralEducationServiceImpl implements MoralEducationService { String block = entry.getKey(); int count = entry.getValue(); double maxCount = 50.0; + // 将次数转换为 60-100 的分数(60分基础,额外加分不超过40分) double convertedScore; if (count > maxCount) { - convertedScore = 100.0; // 如果次数超过最大次数,设置为满分 + convertedScore = 100.0; // 超过最大次数,直接满分 } else { - convertedScore = (count / maxCount) * 100; + // 计算额外加分(占总40分的比例) + double additionalScore = (count / maxCount) * 40; + convertedScore = 60 + additionalScore; + // 保留两位小数 convertedScore = Double.parseDouble(String.format("%.2f", convertedScore)); } convertedScores.put(block, convertedScore); } - subjectiveScores.put(studentId, convertedScores); + //subjectiveScores.put(studentId, convertedScores); } // 4. 遍历所有年级 @@ -1156,7 +1248,7 @@ public class MoralEducationServiceImpl implements MoralEducationService { for (Map.Entry entry : schoolScores.entrySet()) { String nodeName = entry.getKey(); double totalScore = entry.getValue(); - int totalCount = gradeIds.size(); // 每个年级视为一个单位 + int totalCount = schoolScores.size(); // 每个年级视为一个单位 schoolScores.put(nodeName, Double.parseDouble(String.format("%.2f", totalScore / totalCount))); // 保留小数点后两位 } } @@ -1173,6 +1265,10 @@ public class MoralEducationServiceImpl implements MoralEducationService { } // 7. 转换 gradeScores 为新的数据结构 + return getResult(gradeScores, schoolScores); + } + + private static @NotNull Map getResult(Map> gradeScores, Map schoolScores) { List> adjustedGradeScores = new ArrayList<>(); for (Map.Entry> entry : gradeScores.entrySet()) { String gradeName = entry.getKey(); diff --git a/src/main/java/cn/teammodel/controller/frontend/AppraiseController.java b/src/main/java/cn/teammodel/controller/frontend/AppraiseController.java index 2cfc5ae..e8d3369 100644 --- a/src/main/java/cn/teammodel/controller/frontend/AppraiseController.java +++ b/src/main/java/cn/teammodel/controller/frontend/AppraiseController.java @@ -21,6 +21,7 @@ import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import java.io.IOException; import java.util.List; +import java.util.Map; /** * @author winter @@ -75,8 +76,8 @@ public class AppraiseController { @PostMapping("findVoteRecord") @ApiOperation(value = "多条件查询当前登录老师的学生评价(投票)") - public R> findMyVoteRecord(@Valid @RequestBody FindVoteRecordDto findVoteRecordDto, HttpServletRequest request) { - List res = evaluationService.findVoteRecord(findVoteRecordDto,request); + public R> findMyVoteRecord(@Valid @RequestBody FindVoteRecordDto findVoteRecordDto, HttpServletRequest request) { + Map res = evaluationService.findVoteRecord(findVoteRecordDto,request); return R.success(res); } diff --git a/src/main/java/cn/teammodel/model/dto/admin/labor/LaborDto.java b/src/main/java/cn/teammodel/model/dto/admin/labor/LaborDto.java index 754e398..ed1e205 100644 --- a/src/main/java/cn/teammodel/model/dto/admin/labor/LaborDto.java +++ b/src/main/java/cn/teammodel/model/dto/admin/labor/LaborDto.java @@ -24,4 +24,5 @@ public class LaborDto { public String semesterId; private String academicYearId; private String classId; + private String source = "1"; } diff --git a/src/main/java/cn/teammodel/repository/ExamRepository.java b/src/main/java/cn/teammodel/repository/ExamRepository.java index d31f6e6..b198155 100644 --- a/src/main/java/cn/teammodel/repository/ExamRepository.java +++ b/src/main/java/cn/teammodel/repository/ExamRepository.java @@ -16,6 +16,6 @@ public interface ExamRepository extends CosmosRepository { List findExamByClassId(String code,String classId,String periodId,String subjectId); @Query("select * from Exam as s where s.code = @code and s.id = @id") List findExamById(@Param("code")String code, @Param("id")String id); - @Query("select s.id,s.name,s.average,s.classes,s.stuCount,s.createTime,s.papers from Exam as s where s.code = @code and s.lessonRecordId in (@ids)") - List findExamsByIds(String code, Collection ids); + @Query("select s.id,s.name,s.average,s.classes,s.stuCount,s.createTime,s.papers from Exam as s where s.source = @source and s.lessonRecordId in (@ids)") + List findExamsByIds(String source, Collection ids); } diff --git a/src/main/java/cn/teammodel/service/EvaluationService.java b/src/main/java/cn/teammodel/service/EvaluationService.java index 956504c..49653d8 100644 --- a/src/main/java/cn/teammodel/service/EvaluationService.java +++ b/src/main/java/cn/teammodel/service/EvaluationService.java @@ -12,6 +12,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; +import java.util.Map; /** * @author winter @@ -55,7 +56,7 @@ public interface EvaluationService { */ void vote(AppraiseVoteDto appraiseVoteDto); - List findVoteRecord(FindVoteRecordDto findVoteRecordDto, HttpServletRequest request); + Map findVoteRecord(FindVoteRecordDto findVoteRecordDto, HttpServletRequest request); void recallVote(RecallVoteDto recallVoteDto); diff --git a/src/main/java/cn/teammodel/service/impl/EvaluationServiceImpl.java b/src/main/java/cn/teammodel/service/impl/EvaluationServiceImpl.java index 493de99..f0ae576 100644 --- a/src/main/java/cn/teammodel/service/impl/EvaluationServiceImpl.java +++ b/src/main/java/cn/teammodel/service/impl/EvaluationServiceImpl.java @@ -435,7 +435,7 @@ public class EvaluationServiceImpl implements EvaluationService { } @Override - public List findVoteRecord(FindVoteRecordDto findVoteRecordDto, HttpServletRequest request) { + public Map findVoteRecord(FindVoteRecordDto findVoteRecordDto, HttpServletRequest request) { String periodId = findVoteRecordDto.getPeriodId(); String targetId = StringUtils.isBlank(findVoteRecordDto.getTargetId()) ? null : findVoteRecordDto.getTargetId(); String targetType = StringUtils.isBlank(findVoteRecordDto.getTargetType()) ? null : findVoteRecordDto.getTargetType(); @@ -445,6 +445,7 @@ public class EvaluationServiceImpl implements EvaluationService { String teacherId = loginUser.getId(); String schoolId = loginUser.getSchoolId(); + Map params = new HashMap<>(); List semesters = schoolRepository.findSemestersById(schoolId, periodId); String academicYearId = SchoolDateUtil.calculateAcademicYearId(semesters, LocalDate.now()); // 分页 @@ -462,6 +463,7 @@ public class EvaluationServiceImpl implements EvaluationService { ); List content = appraiseRecordItemPage.getContent(); + long total = appraiseRecordItemPage.getTotalElements(); // 获取总数 //提取学生ID 查询学生个人信息 Set studentIds = content.stream().map(AppraiseRecordVo::getTargetId).collect(Collectors.toSet()); if (studentIds.isEmpty()) throw new ServiceException(ErrorCode.PARAM_ERROR.getCode(), "没有对应学生信息"); @@ -497,7 +499,9 @@ public class EvaluationServiceImpl implements EvaluationService { appraiseRecordVo.setClassName(classInfo.getName()); }); } - return content; + params.put("total", total); + params.put("content", content); + return params; } @Override