From c8787b2d3387540464f49f151322d0410fb46c77 Mon Sep 17 00:00:00 2001 From: "hhb@hotmail.com" Date: Thu, 13 Mar 2025 10:22:37 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E5=8A=B3=E8=82=B2=E7=9C=8B=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/MoralEducationController.java | 37 + .../admin/service/MoralEducationService.java | 12 + .../impl/MoralEducationServiceImpl.java | 1243 +++++++++++++++++ 3 files changed, 1292 insertions(+) create mode 100644 src/main/java/cn/teammodel/controller/admin/controller/MoralEducationController.java create mode 100644 src/main/java/cn/teammodel/controller/admin/service/MoralEducationService.java create mode 100644 src/main/java/cn/teammodel/controller/admin/service/impl/MoralEducationServiceImpl.java diff --git a/src/main/java/cn/teammodel/controller/admin/controller/MoralEducationController.java b/src/main/java/cn/teammodel/controller/admin/controller/MoralEducationController.java new file mode 100644 index 0000000..da481ef --- /dev/null +++ b/src/main/java/cn/teammodel/controller/admin/controller/MoralEducationController.java @@ -0,0 +1,37 @@ +package cn.teammodel.controller.admin.controller; + +import cn.teammodel.common.R; +import cn.teammodel.controller.admin.service.MoralEducationService; +import cn.teammodel.model.dto.admin.labor.FindDto; +import cn.teammodel.model.dto.admin.labor.LaborDto; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.Map; + +@RestController +@RequestMapping("admin/moral") +@Api(tags = "管理员端-劳育分析") +public class MoralEducationController { + @Resource + private MoralEducationService moralEducationService; + @PostMapping("getMoralAnalysis") + @ApiOperation("获取劳育看板详细内容") + public R> getLaborAnalysis(@Valid @RequestBody LaborDto laborDto, HttpServletRequest request) { + Map res = moralEducationService.getAnalysis(laborDto,request); + return R.success(res); + } + @PostMapping("getDetails") + @ApiOperation("获取指定学生评测和评价数据") + public R> getDetails(@Valid @RequestBody FindDto findDto, HttpServletRequest request) { + Map res = moralEducationService.getDetails(findDto,request); + return R.success(res); + } +} diff --git a/src/main/java/cn/teammodel/controller/admin/service/MoralEducationService.java b/src/main/java/cn/teammodel/controller/admin/service/MoralEducationService.java new file mode 100644 index 0000000..955f2eb --- /dev/null +++ b/src/main/java/cn/teammodel/controller/admin/service/MoralEducationService.java @@ -0,0 +1,12 @@ +package cn.teammodel.controller.admin.service; + +import cn.teammodel.model.dto.admin.labor.FindDto; +import cn.teammodel.model.dto.admin.labor.LaborDto; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +public interface MoralEducationService { + Map getAnalysis(LaborDto laborDto, HttpServletRequest request); + Map getDetails(FindDto findDto, HttpServletRequest request); +} 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 new file mode 100644 index 0000000..32b19e0 --- /dev/null +++ b/src/main/java/cn/teammodel/controller/admin/service/impl/MoralEducationServiceImpl.java @@ -0,0 +1,1243 @@ +package cn.teammodel.controller.admin.service.impl; + +import cn.teammodel.common.ErrorCode; +import cn.teammodel.common.PK; +import cn.teammodel.config.exception.ServiceException; +import cn.teammodel.controller.admin.service.CommonService; +import cn.teammodel.controller.admin.service.MoralEducationService; +import cn.teammodel.model.dto.admin.common.GCDto; +import cn.teammodel.model.dto.admin.common.GroupDto; +import cn.teammodel.model.dto.admin.common.RGroupList; +import cn.teammodel.model.dto.admin.common.RMember; +import cn.teammodel.model.dto.admin.labor.FindDto; +import cn.teammodel.model.dto.admin.labor.LaborDto; +import cn.teammodel.model.entity.appraise.Appraise; +import cn.teammodel.model.entity.appraise.AppraiseTreeNode; +import cn.teammodel.model.entity.common.Exam; +import cn.teammodel.model.entity.common.ExamClassResult; +import cn.teammodel.model.entity.school.ClassInfo; +import cn.teammodel.model.entity.school.LessonRecord; +import cn.teammodel.model.entity.school.School; +import cn.teammodel.model.vo.admin.GradeAndClassVo; +import cn.teammodel.model.vo.appraise.RecordVo; +import cn.teammodel.repository.*; +import cn.teammodel.security.utils.SecurityUtil; +import cn.teammodel.service.impl.EvaluationServiceImpl; +import cn.teammodel.test.LessonRecordQueryService; +import cn.teammodel.utils.GroupUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import lombok.AllArgsConstructor; +import lombok.Data; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.*; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; + +@Service +public class MoralEducationServiceImpl implements MoralEducationService { + + @Resource + private LessonRecordRepository lessonRecordRepository; + @Resource + private ClassRepository classRepository; + @Resource + private AppraiseRecordRepository appraiseRecordRepository; + @Resource + private ExamRepository examRepository; + @Resource + private ExamClassResultRepository examClassResultRepository; + @Resource + private AppraiseRepository appraiseRepository; + @Resource + private EvaluationServiceImpl evaluationService; + @Resource + private SchoolRepository schoolRepository; + @Resource + private CommonService commonService; + + private static Environment environment; // 静态字段 + @Autowired + private Environment env; // 非静态字段 + + @PostConstruct + public void init() { + MoralEducationServiceImpl.environment = env; // 在初始化时将非静态字段赋值给静态字段 + } + @Override + public Map getAnalysis(LaborDto laborDto, HttpServletRequest request) { + + //根据具体参数查询相关课列内容 + List records; + LessonRecordQueryService queryService = new LessonRecordQueryService(lessonRecordRepository); + String schoolId = SecurityUtil.getLoginUser().getSchoolId(); + String lessonRecordKey = String.format(PK.PK_LESSON_RECORD, laborDto.getCode()); + Long startTime = laborDto.getStartTime(); + Long endTime = laborDto.getEndTime(); + String subjectId = laborDto.getSubjectId(); + String tmdId = laborDto.getTmdId(); + String grade = laborDto.getGrade(); + String periodId = laborDto.getPeriodId(); + String academicYearId = laborDto.getAcademicYearId(); + try { + + records = queryService.queryLessonsInParallel( + lessonRecordKey, startTime, endTime, subjectId, tmdId, grade, periodId + ); + // 获取当前月份的起始时间和结束时间 + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.DAY_OF_MONTH, 1); + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + long startOfMonth = calendar.getTimeInMillis(); + + calendar.add(Calendar.MONTH, 1); + calendar.add(Calendar.MILLISECOND, -1); + long endOfMonth = calendar.getTimeInMillis(); + + // 筛选出本月的数据量 + int currentRecordsCount = records.stream() + .filter(record -> record.getStartTime() >= startOfMonth && record.getStartTime() <= endOfMonth) + .mapToInt(record -> 1) + .sum(); + + } catch (InterruptedException | ExecutionException e) { + throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "数据查询异常"); + } finally { + queryService.shutdown(); + } + //总评价数 + List classes = classRepository.findClassBySchoolIdAndPeriodId(laborDto.getPeriodId(), String.format(PK.CLASS, schoolId)); + if (classes.isEmpty()) { + throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "暂无班级"); + } + List classIds = classes.stream().map(ClassInfo::getId).collect(Collectors.toList()); + List res = appraiseRecordRepository.latestRecords( + String.format(PK.PK_APPRAISE_RECORD, schoolId), + academicYearId, + startTime, + endTime, + classIds, + "劳育" + ); + //表扬的次数 + int rightCount = (int) res.stream().filter(RecordVo::isPraise).count(); + //批评的次数 + int wrongCount = (int) res.stream().filter(record -> !record.isPraise()).count(); + //已经评价的学生人数 + long uniqueTargetIdCount = res.stream() + .map(RecordVo::getTargetId) + .filter(Objects::nonNull) // 过滤掉 null 值 + .distinct() + .count(); + List targetId = res.stream() + .map(RecordVo::getTargetId) + .filter(Objects::nonNull) // 过滤掉 null 值 + .distinct() + .collect(Collectors.toList()); + + List recordIds = new ArrayList<>(); + for (LessonRecord record : records) { + recordIds.add(record.getId()); + } + //examIds.add("c26e5766-597f-45b3-91ad-19e76426323b"); + //获取所有课程下的课中活动 + List exams = new ArrayList<>(); + if (!recordIds.isEmpty()) { + exams = examRepository.findExamsByIds(String.format(PK.EXAM, laborDto.getTmdId()), recordIds); + } + Map>> knowledgeMap = new HashMap<>(); + Map> point = new HashMap<>(); + for (Exam exam : exams) { + if (exam.getPapers() != null) { + if (exam.getPapers().get(0).getKnowledge() != null) + { + knowledgeMap.put(exam.getId(), exam.getPapers().get(0).getKnowledge()); + point.put(exam.getId(), exam.getPapers().get(0).getPoint()); + } + } + } + List examIds = new ArrayList<>(); + for (Exam exam : exams) { + examIds.add(exam.getId()); + } + List examResults = new ArrayList<>(); + if (!examIds.isEmpty()) { + examResults = examClassResultRepository.findAll(String.format(PK.CLASS_RESULT, laborDto.getCode()),examIds); + } + //获取学校基础信息 + List period = schoolRepository.findPeriodById(schoolId,periodId); + + List gradeAndClassVos = commonService.getGradeAndClass(new GCDto(schoolId, periodId)); + Map resMap = new HashMap<>(); + //处理劳育知识块和知识点的关联关系 + resMap.put("exams",exams);//评测明细 + resMap.put("subjectiveCount", res.size()); //主观评价数 + resMap.put("examCount", exams.size());//评测数量 + resMap.put("lessonCount", records.size());//班会课数量 + resMap.put("rightCount", rightCount);//表扬评价数 + resMap.put("wrongCount", wrongCount);//待改进评价数 + resMap.put("uniqueTargetIdCount", uniqueTargetIdCount);//评价学生数 + Appraise appraise = appraiseRepository.findAppraiseBySchoolIdAndPeriodIdAndCode(schoolId, periodId, PK.PK_APPRAISE); + if (appraise != null) { + appraise = evaluationService.buildTree(appraise); + Map> knowledgeBlockToPointsMap = getKnowledgeBlockToPointsMap(appraise); + Map classScoreRate = new HashMap<>(); + Map gradeScoreRate = new HashMap<>(); + if (laborDto.getClassId() != null) { + classScoreRate = calculateKnowledgeScoreRateForClass(laborDto.getClassId(), examResults, knowledgeMap, appraise, point,res,request); + } + if (laborDto.getGrade() != null) { + gradeScoreRate = calculateKnowledgeScoreForGrade(laborDto.getGrade(), examResults, knowledgeMap,appraise, point,res,gradeAndClassVos); + } + Map schoolScoreRate = calculateKnowledgeScoreForSchool(examResults, knowledgeMap,appraise, point,res,period,gradeAndClassVos); + resMap.put("gradeScoreRate", gradeScoreRate); + resMap.put("classScoreRate", classScoreRate); + resMap.put("schoolScoreRate", schoolScoreRate); + List> scores = calculateScoresWithDetails(res, appraise); + List> students = combineScoresWithExamResults(scores,examResults,knowledgeMap,point,knowledgeBlockToPointsMap); + resMap.put("scores", students); + } + //处理主观评价内容 + return resMap; + + } + + @Override + public Map getDetails(FindDto findDto, HttpServletRequest request) { + Map resMap = new HashMap<>(); + List exams; + List res; + try { + exams = examRepository.findExamByClassId(String.format(PK.EXAM, findDto.getTmdId()), findDto.getClassId(), findDto.getPeriodId(), findDto.getSubjectId()); + res= appraiseRecordRepository.getRecords(String.format(PK.PK_APPRAISE_RECORD, findDto.getCode()),findDto.getAcademicYearId(), findDto.getClassId(), findDto.getStudentId()); + resMap.put("exams",exams); + resMap.put("res", res); + }catch (Exception e){ + throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "数据查询异常"); + } + return resMap; + } + + public List> combineScoresWithExamResults( + List> scores, + List examResults, + Map>> knowledgeMap, + Map> points, + Map> knowledgeBlockToPointsMap) { + + // 1. 计算每个学生的知识点得分 + Map> studentKnowledgePointScores = new HashMap<>(); + for (Map studentResult : scores) { + String studentId = (String) studentResult.get("studentId"); + + // 初始化知识点总分 + Map knowledgeTotalScore = new HashMap<>(); + + // 计算当前学生的知识点得分 + calculateStudentScoreRates(studentId, examResults, knowledgeMap, points, knowledgeTotalScore); + + // 将知识点得分存储到 studentKnowledgePointScores 中 + studentKnowledgePointScores.put(studentId, knowledgeTotalScore); + } + + // 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); + } + } + + // 3. 更新现有的 scores 返回数据 + for (Map studentResult : scores) { + String studentId = (String) studentResult.get("studentId"); + Map subjectiveScores = (Map) studentResult.get("scores"); + + // 查找该学生的知识块客观成绩 + Map knowledgeBlockScores = studentKnowledgeBlockScores.get(studentId); + + // 初始化主观总分和客观总分 + double subjectiveTotal = 0.0; + double objectiveTotal = 0.0; + int knowledgeBlockCount = knowledgeBlockScores.size(); + + // 更新主观成绩,计算主观总分和客观总分 + Map combinedScores = new HashMap<>(); + for (Map.Entry entry : subjectiveScores.entrySet()) { + double score = 0; + String knowledgeBlock = entry.getKey(); + int count = entry.getValue(); // 次数 + // 确保 count 不小于0 + if (count < 0) { + count = 0; //次数永远不能为负数 + } + double maxCount = 50.0; // 最大次数(可根据实际情况调整) + + // 将次数转换为 0-100 的分数 + double convertedScore; + if (count > maxCount) { + convertedScore = 100.0; // 如果次数超过最大次数,设置为满分 + } else { + convertedScore = (count / maxCount) * 100; + convertedScore = Double.parseDouble(String.format("%.2f", convertedScore)); + } + subjectiveTotal += convertedScore; + + // 获取对应知识块的客观成绩 + double objectiveScore = knowledgeBlockScores.get(knowledgeBlock); + objectiveTotal += objectiveScore; + score = convertedScore * 0.6 + objectiveScore * 0.4; + /* + 形成 次数/客观分数 的格式 + String combinedScore = count + "/" + objectiveScore; + */ + double finalCount = convertedScore; + 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); + + }}); + //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%) + double compositeScore = (subjectiveAverage * 0.6) + (objectiveAverage * 0.4); + compositeScore = Double.parseDouble(String.format("%.2f", compositeScore)); + + // 更新返回数据 + studentResult.put("scores", combinedScores); + studentResult.put("subjectiveTotal", subjectiveAverage); + studentResult.put("objectiveTotal", objectiveAverage); + studentResult.put("compositeScore", compositeScore); + } + + return scores; + } + + + public static List> calculateScoresWithDetails(List res, Appraise appraise) { + // 1. 构建知识点到知识块的映射 (一个知识块对应多个知识点) + Map> knowledgeBlockToPointsMap = getKnowledgeBlockToPointsMap(appraise); + + // 2. 构建所有二级知识块名称列表 + Set knowledgeBlocks = new HashSet<>(); + for (AppraiseTreeNode node : appraise.getNodes()) { + if ("劳育".equals(node.getName())) { + for (AppraiseTreeNode secondLevelNode : node.getChildren()) { + knowledgeBlocks.add(secondLevelNode.getName()); + } + } + } + + // 3. 构建知识点到知识块的映射 (一个知识点对应一个知识块) + Map knowledgePointToBlockMap = new HashMap<>(); + for (Map.Entry> entry : knowledgeBlockToPointsMap.entrySet()) { + String knowledgeBlock = entry.getKey(); + for (String knowledgePoint : entry.getValue()) { + knowledgePointToBlockMap.put(knowledgePoint, knowledgeBlock); + } + } + + // 4. 遍历评价记录并统计得分 + Map> studentScores = new HashMap<>(); + Map>> studentAppraises = new HashMap<>(); // 存储每个学生的评价记录 + + for (RecordVo record : res) { + String studentId = record.getTargetId(); // 学生 ID + String studentName = record.getTargetName(); // 学生名称 + String className = record.getClassName(); // 班级名称 + String appraiseName = record.getAppraiseName(); // 评价内容 + boolean isPraise = record.isPraise(); // 是否为优点 + + // 获取评价内容对应的第二级节点(知识块) + String knowledgeBlock = knowledgePointToBlockMap.get(appraiseName); + if (knowledgeBlock == null) { + continue; // 如果不在劳育知识块中,跳过 + } + + // 初始化学生得分记录 + String studentKey = studentId + "|" + studentName + "|" + className; // 组合学生唯一标识 + studentScores.putIfAbsent(studentKey, new HashMap<>()); + Map studentScoreMap = studentScores.get(studentKey); + + // 计分 + int score = isPraise ? 1 : -1; + int currentScore = studentScoreMap.getOrDefault(knowledgeBlock, 0) + score; + studentScoreMap.put(knowledgeBlock, currentScore); + + // 存储每个学生的评价记录 + studentAppraises.putIfAbsent(studentKey, new ArrayList<>()); + Map appraiseRecord = new HashMap<>(); + appraiseRecord.put("appraiseName", appraiseName); + appraiseRecord.put("isPraise", isPraise); + studentAppraises.get(studentKey).add(appraiseRecord); + } + + // 5. 初始化缺失的二级知识块分数 + for (Map.Entry> entry : studentScores.entrySet()) { + Map studentScoreMap = entry.getValue(); + for (String block : knowledgeBlocks) { + studentScoreMap.putIfAbsent(block, 0); + } + } + + // 6. 整理并返回结果 + return getMaps(studentScores, studentAppraises); + } + + // 整理并返回结果 + private static List> getMaps(Map> studentScores, Map>> studentAppraises) { + List> result = new ArrayList<>(); + + for (Map.Entry> entry : studentScores.entrySet()) { + String studentKey = entry.getKey(); + Map scoreMap = entry.getValue(); + List> appraiseList = studentAppraises.get(studentKey); // 获取学生的评价记录 + + // 解析学生唯一标识 + String[] studentInfo = studentKey.split("\\|"); + String studentId = studentInfo[0]; + String studentName = studentInfo[1]; + String className = studentInfo[2]; + + // 构建返回结果 + Map studentResult = new HashMap<>(); + studentResult.put("studentId", studentId); + studentResult.put("studentName", studentName); + studentResult.put("className", className); + studentResult.put("scores", scoreMap); + studentResult.put("appraises", appraiseList); // 添加评价记录 + + result.add(studentResult); + } + + return result; + } + + + // 整理并返回结果 + private static List> getMaps(Map> studentScores) { + List> result = new ArrayList<>(); + + for (Map.Entry> entry : studentScores.entrySet()) { + String studentKey = entry.getKey(); + Map scoreMap = entry.getValue(); + + // 解析学生唯一标识 + String[] studentInfo = studentKey.split("\\|"); + String studentId = studentInfo[0]; + String studentName = studentInfo[1]; + String className = studentInfo[2]; + + // 构建返回结果 + Map studentResult = new HashMap<>(); + studentResult.put("studentId", studentId); + studentResult.put("studentName", studentName); + studentResult.put("className", className); + studentResult.put("scores", scoreMap); + + result.add(studentResult); + } + + return result; + } + + // 构建知识块到知识点的映射 (一个知识块对应多个知识点) + private static Map> getKnowledgeBlockToPointsMap(Appraise appraise) { + Map> knowledgeBlockToPointsMap = new HashMap<>(); + + for (AppraiseTreeNode node : appraise.getNodes()) { + if ("劳育".equals(node.getName())) { + for (AppraiseTreeNode secondLevelNode : node.getChildren()) { + String knowledgeBlock = secondLevelNode.getName(); + List knowledgePoints = new ArrayList<>(); + + // 假设知识点的信息存储在 secondLevelNode.getChildren() 中 + for (AppraiseTreeNode pointNode : secondLevelNode.getChildren()) { + knowledgePoints.add(pointNode.getName()); + } + + knowledgeBlockToPointsMap.put(knowledgeBlock, knowledgePoints); + } + } + } + + return knowledgeBlockToPointsMap; + } + + + // 知识点得分率结果类 + @Data + @AllArgsConstructor + public static class KnowledgeScoreRate { + public String knowledge; // 知识点 + public double scoreRate; // 得分率 + } + + /** + * 计算某个学生在多次考试中的知识点得分率,并返回其所属节点的父节点得分率 + * + * @param studentId 学生 ID + * @param examResults 学生作答结果集 + * @param knowledgeMap 知识点映射(试卷 ID -> 知识点列表) + * @param appraise 评价对象 + * @return 父节点得分率 + */ + public static Map calculateKnowledgeScoreRateForStudent( + 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<>(); + 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); + } + } + } + + // 初始化所有同层的父节点 + 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); + } + } + } + } + + return parentNodeScoreRates; + } + + + /** + * 计算班级每个学生知识点得分率,并返回每个学生所属节点的父节点得分率 + * + * @param classId 班级 ID + * @param examResults 学生作答结果集 + * @param knowledgeMap 知识点映射(试卷 ID -> 知识点列表) + * @param appraise 评价对象 + * @return 学生 ID -> 父节点得分率映射 + */ + public static Map calculateKnowledgeScoreRateForClass( + String classId, + List examResults, + Map>> knowledgeMap, + Appraise appraise, + Map> points, + List res, + HttpServletRequest request) { + + // 将 classId 转换为 List + List classIds = Collections.singletonList(classId); + GroupDto groupDto = new GroupDto(); + groupDto.setIds(classIds); + groupDto.setSchoolId(appraise.getSchoolId()); + String url = environment.getProperty("ies.server-url-group"); + Map groupId = GroupUtil.getGroupId(groupDto, new GroupUtil(environment), request, url); + List rGroupList = new ArrayList<>(); + List rMembers = new ArrayList<>(); + for (Map.Entry entry : groupId.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if (key.equals("groups")) { + String jsonGroups = JSON.toJSONString(value); + rGroupList = JSON.parseObject(jsonGroups, new TypeReference>() {}); + } + if (key.equals("members")) { + String jsonGroups = JSON.toJSONString(value); + rMembers = JSON.parseObject(jsonGroups, new TypeReference>() {}); + } + } + String className = rGroupList.stream() + .filter(rGroupList1 -> rGroupList1.getId().equals(classId)) + .findFirst() + .map(RGroupList::getName) + .orElse("未知班级"); // 如果未找到则返回默认值 "未知班级" + + // 1. 获取班级所有学生的客观分数 + Map> studentScoreRates = new HashMap<>(); + Map classScoreRates = new HashMap<>(); + + // 遍历班级中的每个学生 + for (ExamClassResult examResult : examResults) { + if (!examResult.getInfo().getId().equals(classId)) continue; // 过滤出该班级的考试 + List statuses = examResult.getStatus(); + for (int i = 0; i < examResult.getStudentIds().size(); i++) { + String studentId = examResult.getStudentIds().get(i); + String name = rMembers.stream() + .filter(member -> member.getId().equals(studentId)) + .findFirst() + .map(RMember::getName) + .orElse("未知"); + int status = statuses.get(i); + if (status == 1) continue; // 跳过 status 为 1 的记录 + + // 计算父节点得分率(客观分数) + Map scoreRates = calculateKnowledgeScoreRateForStudent( + studentId, examResults, knowledgeMap, appraise, points + ); + studentScoreRates.put(name, scoreRates); + + // 累加班级整体得分率 + for (Map.Entry entry : scoreRates.entrySet()) { + classScoreRates.put(entry.getKey(), classScoreRates.getOrDefault(entry.getKey(), 0.0) + entry.getValue()); + } + } + } + + // 2. 获取班级所有学生的主观分数(次数) + List> subjectiveScoresList = calculateScoresWithDetails(res, appraise); + + // 3. 将主观次数转换为0-100分数 + Map> subjectiveScores = new HashMap<>(); + for (Map studentScore : subjectiveScoresList) { + String studentId = (String) studentScore.get("studentId"); + @SuppressWarnings("unchecked") + Map scores = (Map) studentScore.get("scores"); + Map convertedScores = new HashMap<>(); + + for (Map.Entry entry : scores.entrySet()) { + String block = entry.getKey(); + int count = entry.getValue(); + double maxCount = 50.0; + double convertedScore; + if (count > maxCount) { + convertedScore = 100.0; // 如果次数超过最大次数,设置为满分 + } else { + convertedScore = (count / maxCount) * 100; + convertedScore = Double.parseDouble(String.format("%.2f", convertedScore)); + } + convertedScores.put(block, convertedScore); + } + + subjectiveScores.put(studentId, convertedScores); + } + + // 4. 融合主观和客观分数 + Map> compositeStudentScores = new HashMap<>(); + for (Map.Entry> entry : studentScoreRates.entrySet()) { + String studentId = entry.getKey(); + Map objective = entry.getValue(); + Map subjective = subjectiveScores.getOrDefault(studentId, new HashMap<>()); + + // 计算综合得分 + Map compositeScores = new HashMap<>(); + for (Map.Entry objectiveEntry : objective.entrySet()) { + String block = objectiveEntry.getKey(); + double objectiveScore = objectiveEntry.getValue(); + double subjectiveScore = subjective.getOrDefault(block, 0.0); + + // 按6:4比例计算综合得分 + double compositeScore = (subjectiveScore * 0.6) + (objectiveScore * 0.4); + compositeScore = Double.parseDouble(String.format("%.2f", compositeScore)); + compositeScores.put(block, compositeScore); + } + + compositeStudentScores.put(studentId, compositeScores); + } + + // 5. 计算班级整体得分率 + int studentCount = compositeStudentScores.size(); + Map compositeClassScoreRates = new HashMap<>(); + for (Map studentScores : compositeStudentScores.values()) { + for (Map.Entry entry : studentScores.entrySet()) { + String block = entry.getKey(); + double score = entry.getValue(); + compositeClassScoreRates.put(block, compositeClassScoreRates.getOrDefault(block, 0.0) + score); + } + } + compositeClassScoreRates.replaceAll((k, v) -> Double.parseDouble(String.format("%.2f", v / studentCount))); // 保留小数点后两位 + + // 6. 初始化所有同层的父节点 + for (AppraiseTreeNode node : appraise.getNodes()) { + if (node.getName().equals("劳育")) { + for (AppraiseTreeNode child : node.getChildren()) { + if (!compositeClassScoreRates.containsKey(child.getName())) { + compositeClassScoreRates.put(child.getName(), 0.0); + } + } + } + } + + // 7. 转换 classScoreRates 和 studentScoreRates 为新的数据结构 + List> adjustedClassScoreRates = new ArrayList<>(); + Map classScore = new HashMap<>(); + classScore.put("className", className); // 设置班级名称 + + List> classBlocks = new ArrayList<>(); + for (Map.Entry entry : compositeClassScoreRates.entrySet()) { + Map block = new HashMap<>(); + block.put("name", entry.getKey()); + block.put("score", entry.getValue()); + classBlocks.add(block); + } + classScore.put("blocks", classBlocks); + adjustedClassScoreRates.add(classScore); + + List> adjustedStudentScoreRates = new ArrayList<>(); + for (Map.Entry> entry : compositeStudentScores.entrySet()) { + String studentId = entry.getKey(); + Map scores = entry.getValue(); + + Map studentScore = new HashMap<>(); + studentScore.put("studentName", studentId); // 设置学生名称 + + List> studentBlocks = new ArrayList<>(); + for (Map.Entry scoreEntry : scores.entrySet()) { + Map block = new HashMap<>(); + block.put("name", scoreEntry.getKey()); + block.put("score", scoreEntry.getValue()); + studentBlocks.add(block); + } + studentScore.put("blocks", studentBlocks); + adjustedStudentScoreRates.add(studentScore); + } + + // 8. 返回结果 + Map result = new HashMap<>(); + result.put("classScoreRates", adjustedClassScoreRates); // 班级整体得分率 + result.put("studentScoreRates", adjustedStudentScoreRates); // 每个学生的综合得分率 + return result; + } + + + + + private static List calculateStudentScoreRates( + String studentId, + List examResults, + Map>> knowledgeMap, + Map> points, + Map knowledgeTotalScore) { + + Map knowledgeTotalAverage = new HashMap<>(); + Map knowledgeExamCount = new HashMap<>(); + + for (ExamClassResult examResult : examResults) { + int studentIndex = examResult.getStudentIds().indexOf(studentId); + if (studentIndex == -1) continue; + int status = examResult.getStatus().get(studentIndex); + if (status == 1) continue; + + List> knowledgeList = knowledgeMap.get(examResult.getExamId()); + List pointList = points.get(examResult.getExamId()); + if (knowledgeList == null || pointList == null) continue; + + List> studentScores = examResult.getStudentScores(); + if (studentIndex >= studentScores.size() || studentScores.get(studentIndex) == null) continue; + List studentScoreList = studentScores.get(studentIndex); + + if (knowledgeList.size() != studentScoreList.size()) continue; + + Map currentExamKnowledgeTotal = new HashMap<>(); + Map currentExamKnowledgeCount = new HashMap<>(); + + // 遍历每道题 + for (int i = 0; i < studentScoreList.size(); i++) { + List knowledgePoints = knowledgeList.get(i); // 题目对应的知识点列表 + double score = studentScoreList.get(i); + + // 如果题目没有知识点或得分为空,跳过 + if (knowledgePoints.isEmpty() || score < 0) continue; + + // 将题目得分分摊到每个知识点 + double scorePerKnowledge = score / knowledgePoints.size(); + + // 遍历该题的所有知识点 + for (String knowledge : knowledgePoints) { + // 累加当前考试中该知识点的总得分和题目数量 + currentExamKnowledgeTotal.merge(knowledge, scorePerKnowledge, Double::sum); + currentExamKnowledgeCount.merge(knowledge, 1, Integer::sum); + } + } + + // 计算当前考试中每个知识点的平均分(总得分/题目数量) + for (String knowledge : currentExamKnowledgeTotal.keySet()) { + double total = currentExamKnowledgeTotal.get(knowledge); + int count = currentExamKnowledgeCount.get(knowledge); + double average = total / count; + + // 累加跨考试的总平均分和考试次数 + knowledgeTotalAverage.merge(knowledge, average, Double::sum); + knowledgeExamCount.merge(knowledge, 1, Integer::sum); + } + } + + // 计算最终平均分(所有考试平均分的平均) + 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)); + knowledgeTotalScore.put(knowledge, finalAverage); + } + + return knowledgeTotalScore.entrySet().stream() + .map(entry -> new KnowledgeScoreRate(entry.getKey(), entry.getValue())) + .collect(Collectors.toList()); + } + + + public static double calculateNodeScoreRate(AppraiseTreeNode node, Map knowledgeTotalScore) { + // 获取当前节点的得分 + double totalScore = knowledgeTotalScore.getOrDefault(node.getName(), 0.0); + + // 递归计算子节点的得分并累加 + for (AppraiseTreeNode child : node.getChildren()) { + totalScore += calculateNodeScoreRate(child, knowledgeTotalScore); + } + + return totalScore; + } + + /** + * 计算年级整体得分率,并返回其所属节点的父节点得分率 + * + * @param gradeId 年级 ID + * @param examResults 学生作答结果集 + * @param knowledgeMap 知识点映射(试卷 ID -> 知识点列表) + * @param appraise 评价对象 + * @param points 试卷配分 + * @return 年级所属节点的父节点得分率 + */ + public static Map calculateKnowledgeScoreForGrade( + String gradeId, + List examResults, + Map>> knowledgeMap, + Appraise appraise, + Map> points, + List res, + List gradeAndClassVos) { + + // 1. 获取年级所有班级的客观分数 + Map> classScores = new HashMap<>(); + Map gradeScores = new HashMap<>(); + + // 根据 gradeId 匹配并取出 classId 集合 + List classInfos = gradeAndClassVos.stream() + .filter(gradeAndClassVo -> String.valueOf(gradeAndClassVo.getGradeId()).equals(gradeId)) + .flatMap(gradeAndClassVo -> gradeAndClassVo.getClasses().stream()) + .collect(Collectors.toList()); + String gradeName = gradeAndClassVos.stream() + .filter(gradeAndClassVo -> String.valueOf(gradeAndClassVo.getGradeId()).equals(gradeId)) + .findFirst() + .map(GradeAndClassVo::getGradeName) + .orElse(""); + // 过滤出该年级的考试结果 + List gradeExamResults = examResults.stream() + .filter(examResult -> examResult.getGradeId().equals(gradeId)) + .collect(Collectors.toList()); + + // 2. 获取年级所有学生的主观分数(次数) + List> subjectiveScoresList = calculateScoresWithDetails(res, appraise); + + // 3. 将主观次数转换为0-100分数 + Map> subjectiveScores = new HashMap<>(); + for (Map studentScore : subjectiveScoresList) { + String studentId = (String) studentScore.get("studentId"); + @SuppressWarnings("unchecked") + Map scores = (Map) studentScore.get("scores"); + Map convertedScores = new HashMap<>(); + + for (Map.Entry entry : scores.entrySet()) { + String block = entry.getKey(); + int count = entry.getValue(); + double maxCount = 50.0; + double convertedScore; + if (count > maxCount) { + convertedScore = 100.0; // 如果次数超过最大次数,设置为满分 + } else { + convertedScore = (count / maxCount) * 100; + convertedScore = Double.parseDouble(String.format("%.2f", convertedScore)); + } + convertedScores.put(block, convertedScore); + } + + subjectiveScores.put(studentId, convertedScores); + } + + // 4. 遍历年级下的所有班级 + for (GradeAndClassVo.CI info : classInfos) { + String className = info.getClassName(); + Map classScoresInner = new HashMap<>(); + + for (ExamClassResult examResult : gradeExamResults) { + if (examResult.getInfo().getId().equals(info.getClassId())) { + Map classScoreSum = new HashMap<>(); + Map classScoreCount = new HashMap<>(); + + // 获取学生状态列表 + List statuses = examResult.getStatus(); + // 遍历班级中的每个学生 + for (int i = 0; i < examResult.getStudentIds().size(); i++) { + String studentId = examResult.getStudentIds().get(i); + if (statuses.get(i) == 1) { + continue; + } + + // 计算学生的知识点得分(客观分数) + Map studentObjectiveScores = calculateKnowledgeScoreRateForStudent( + studentId, examResults, knowledgeMap, appraise, points + ); + + // 获取学生的主观分数 + Map studentSubjectiveScores = subjectiveScores.getOrDefault(studentId, new HashMap<>()); + + // 计算综合得分(主观60%,客观40%) + Map studentCompositeScores = new HashMap<>(); + for (Map.Entry entry : studentObjectiveScores.entrySet()) { + String block = entry.getKey(); + double objectiveScore = entry.getValue(); + double subjectiveScore = studentSubjectiveScores.getOrDefault(block, 0.0); + double compositeScore = (subjectiveScore * 0.6) + (objectiveScore * 0.4); + studentCompositeScores.put(block, compositeScore); + } + + // 累加班级整体得分 + for (Map.Entry entry : studentCompositeScores.entrySet()) { + String nodeName = entry.getKey(); + double score = entry.getValue(); + classScoreSum.put(nodeName, classScoreSum.getOrDefault(nodeName, 0.0) + score); + classScoreCount.put(nodeName, classScoreCount.getOrDefault(nodeName, 0) + 1); + } + } + + // 计算班级平均得分 + for (Map.Entry entry : classScoreSum.entrySet()) { + String nodeName = entry.getKey(); + double totalScore = entry.getValue(); + int count = classScoreCount.get(nodeName); + classScoresInner.put(nodeName, Double.parseDouble(String.format("%.2f", totalScore / count))); // 保留小数点后两位 + } + } + } + + // 初始化所有同层的父节点 + for (AppraiseTreeNode node : appraise.getNodes()) { + if ("劳育".equals(node.getName())) { + for (AppraiseTreeNode child : node.getChildren()) { + classScoresInner.putIfAbsent(child.getName(), 0.0); + } + } + } + + // 存储班级的平均得分 + classScores.put(className, classScoresInner); + } + + // 5. 计算年级的平均得分 + Map gradeScoreSum = new HashMap<>(); + Map gradeScoreCount = new HashMap<>(); + for (Map classScore : classScores.values()) { + for (Map.Entry entry : classScore.entrySet()) { + String nodeName = entry.getKey(); + double score = entry.getValue(); + gradeScoreSum.put(nodeName, gradeScoreSum.getOrDefault(nodeName, 0.0) + score); + gradeScoreCount.put(nodeName, gradeScoreCount.getOrDefault(nodeName, 0) + 1); + } + } + for (Map.Entry entry : gradeScoreSum.entrySet()) { + String nodeName = entry.getKey(); + double totalScore = entry.getValue(); + int count = gradeScoreCount.get(nodeName); + gradeScores.put(nodeName, Double.parseDouble(String.format("%.2f", totalScore / count))); // 保留小数点后两位 + } + + // 初始化所有同层的父节点 + for (AppraiseTreeNode node : appraise.getNodes()) { + if ("劳育".equals(node.getName())) { + for (AppraiseTreeNode child : node.getChildren()) { + gradeScores.putIfAbsent(child.getName(), 0.0); + } + } + } + // 6. 转换 gradeScores 和 classScores 为新的数据结构 + return getStringObjectMap(gradeName, gradeScores, classScores); + } + + private static @NotNull Map getStringObjectMap(String gradeName, Map gradeScores, Map> classScores) { + List> adjustedGradeScores = new ArrayList<>(); + Map gradeScore = new HashMap<>(); + gradeScore.put("gradeName", gradeName); // 设置年级名称 + + List> gradeBlocks = new ArrayList<>(); + for (Map.Entry entry : gradeScores.entrySet()) { + Map block = new HashMap<>(); + block.put("name", entry.getKey()); + block.put("score", entry.getValue()); + gradeBlocks.add(block); + } + gradeScore.put("blocks", gradeBlocks); + adjustedGradeScores.add(gradeScore); + + List> adjustedClassScores = new ArrayList<>(); + for (Map.Entry> entry : classScores.entrySet()) { + String className = entry.getKey(); + Map scores = entry.getValue(); + + Map classScore = new HashMap<>(); + classScore.put("className", className); // 设置班级名称 + + List> classBlocks = new ArrayList<>(); + for (Map.Entry scoreEntry : scores.entrySet()) { + Map block = new HashMap<>(); + block.put("name", scoreEntry.getKey()); + block.put("score", scoreEntry.getValue()); + classBlocks.add(block); + } + classScore.put("blocks", classBlocks); + adjustedClassScores.add(classScore); + } + + // 7. 返回结果 + Map result = new HashMap<>(); + result.put("gradeScores", adjustedGradeScores); // 年级平均得分 + result.put("classScores", adjustedClassScores); // 每个班级的平均得分 + return result; + } + + + public static Map calculateKnowledgeScoreForSchool( + List examResults, + Map>> knowledgeMap, + Appraise appraise, + Map> points, + List res, + List period, + List gradeAndClassVos) { + + // 1. 获取全校所有年级的客观分数 + Map> gradeScores = new HashMap<>(); + Map schoolScores = new HashMap<>(); + + // 获取所有年级的 ID + List gradeIds = period.stream() + .flatMap(period1 -> period1.getGrades().stream()) + .collect(Collectors.toList()); + + // 2. 获取全校所有学生的主观分数(次数) + List> subjectiveScoresList = calculateScoresWithDetails(res, appraise); + + // 3. 将主观次数转换为0-100分数 + Map> subjectiveScores = new HashMap<>(); + for (Map studentScore : subjectiveScoresList) { + String studentId = (String) studentScore.get("studentId"); + @SuppressWarnings("unchecked") + Map scores = (Map) studentScore.get("scores"); + Map convertedScores = new HashMap<>(); + + for (Map.Entry entry : scores.entrySet()) { + String block = entry.getKey(); + int count = entry.getValue(); + double maxCount = 50.0; + double convertedScore; + if (count > maxCount) { + convertedScore = 100.0; // 如果次数超过最大次数,设置为满分 + } else { + convertedScore = (count / maxCount) * 100; + convertedScore = Double.parseDouble(String.format("%.2f", convertedScore)); + } + convertedScores.put(block, convertedScore); + } + + subjectiveScores.put(studentId, convertedScores); + } + + // 4. 遍历所有年级 + int index = 0; + for (String gradeId : gradeIds) { + // 调用改造后的方法,返回的 gradeResult 包含列表结构的 gradeScores 和 classScores + Map gradeResult = calculateKnowledgeScoreForGrade( + String.valueOf(index), examResults, knowledgeMap, appraise, points, res, gradeAndClassVos + ); + + // 1. 提取年级平均得分(gradeScores) + List> adjustedGradeScores = (List>) gradeResult.get("gradeScores"); + Map gradeScoresInner = new HashMap<>(); + + // 遍历年级得分列表(通常只有一个元素) + for (Map gradeScoreEntry : adjustedGradeScores) { + String gradeName = (String) gradeScoreEntry.get("gradeName"); + List> blocks = (List>) gradeScoreEntry.get("blocks"); + + // 将 blocks 转换为 Map + for (Map block : blocks) { + String nodeName = (String) block.get("name"); + Double score = (Double) block.get("score"); + gradeScoresInner.put(nodeName, score); + } + } + + // 保存年级得分 + gradeScores.put(gradeId, gradeScoresInner); + + // 2. 累加全校得分总和(从 classScores 中提取) + List> adjustedClassScores = (List>) gradeResult.get("classScores"); + + for (Map classScoreEntry : adjustedClassScores) { + List> classBlocks = (List>) classScoreEntry.get("blocks"); + + // 遍历班级的每个评分项 + for (Map block : classBlocks) { + String nodeName = (String) block.get("name"); + Double score = (Double) block.get("score"); + schoolScores.put(nodeName, schoolScores.getOrDefault(nodeName, 0.0) + score); + } + } + + index++; + } + + // 5. 计算全校的平均得分 + if (gradeIds.size() == 1) { + schoolScores.putAll(gradeScores.get(gradeIds.iterator().next())); + } else { + // 计算全校的平均得分 + for (Map.Entry entry : schoolScores.entrySet()) { + String nodeName = entry.getKey(); + double totalScore = entry.getValue(); + int totalCount = gradeIds.size(); // 每个年级视为一个单位 + schoolScores.put(nodeName, Double.parseDouble(String.format("%.2f", totalScore / totalCount))); // 保留小数点后两位 + } + } + + // 6. 初始化所有同层的父节点 + for (AppraiseTreeNode node : appraise.getNodes()) { + if (node.getName().equals("劳育")) { + for (AppraiseTreeNode child : node.getChildren()) { + if (!schoolScores.containsKey(child.getName())) { + schoolScores.put(child.getName(), 0.0); + } + } + } + } + + // 7. 转换 gradeScores 为新的数据结构 + List> adjustedGradeScores = new ArrayList<>(); + for (Map.Entry> entry : gradeScores.entrySet()) { + String gradeName = entry.getKey(); + Map scores = entry.getValue(); + + List> blocks = new ArrayList<>(); + for (Map.Entry scoreEntry : scores.entrySet()) { + Map block = new HashMap<>(); + block.put("name", scoreEntry.getKey()); + block.put("score", scoreEntry.getValue()); + blocks.add(block); + } + + Map gradeScore = new HashMap<>(); + gradeScore.put("gradeName", gradeName); + gradeScore.put("blocks", blocks); + adjustedGradeScores.add(gradeScore); + } + + // 8. 转换 schoolScores 为新的数据结构 + List> adjustedSchoolScores = new ArrayList<>(); + Map schoolScore = new HashMap<>(); + schoolScore.put("gradeName", "全校"); // 全校的 gradeName 设置为 "全校" + + List> schoolBlocks = new ArrayList<>(); + for (Map.Entry entry : schoolScores.entrySet()) { + Map block = new HashMap<>(); + block.put("name", entry.getKey()); + block.put("score", entry.getValue()); + schoolBlocks.add(block); + } + schoolScore.put("blocks", schoolBlocks); + adjustedSchoolScores.add(schoolScore); + + // 9. 返回结果 + Map result = new HashMap<>(); + result.put("schoolScores", adjustedSchoolScores); // 全校平均得分 + result.put("gradeScores", adjustedGradeScores); // 每个年级的平均得分 + return result; + } + + + /** + * 查找知识点对应的节点 + * + * @param nodes 节点列表 + * @param knowledge 学生知识点得分率列表 + * @return 知识点对应的节点 + */ + private static AppraiseTreeNode findKnowledgeNode(List nodes, String knowledge) { + for (AppraiseTreeNode node : nodes) { + if (node.getName().equals("劳育")) { + for (AppraiseTreeNode child : node.getChildren()) { + for (AppraiseTreeNode grandchild : child.getChildren()) { + if (grandchild.getName().equals(knowledge)) { + return grandchild; // 返回知识点对应的节点 + } + } + } + } + } + return null; // 未找到匹配的节点 + } + + private static AppraiseTreeNode findParentNode(List nodes, String nodeId) { + for (AppraiseTreeNode node : nodes) { + for (AppraiseTreeNode child : node.getChildren()) { + for (AppraiseTreeNode grandchild : child.getChildren()) { + if (grandchild.getId().equals(nodeId)) { + return child; // 返回父节点 + } + } + } + } + return null; // 未找到父节点 + } + +}