|
|
@ -0,0 +1,970 @@
|
|
|
|
|
|
|
|
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.LaborEducationService;
|
|
|
|
|
|
|
|
import cn.teammodel.model.dto.admin.common.GroupDto;
|
|
|
|
|
|
|
|
import cn.teammodel.model.dto.admin.common.RMember;
|
|
|
|
|
|
|
|
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.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.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 LaborEducationServiceImpl implements LaborEducationService {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@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;
|
|
|
|
|
|
|
|
private static Environment environment; // 静态字段
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
|
|
|
private Environment env; // 非静态字段
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@PostConstruct
|
|
|
|
|
|
|
|
public void init() {
|
|
|
|
|
|
|
|
LaborEducationServiceImpl.environment = env; // 在初始化时将非静态字段赋值给静态字段
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public Map<String, Object> getAnalysis(LaborDto laborDto, HttpServletRequest request) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//根据具体参数查询相关课列内容
|
|
|
|
|
|
|
|
List<LessonRecord> 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<ClassInfo> classes = classRepository.findClassBySchoolIdAndPeriodId(laborDto.getPeriodId(), String.format(PK.CLASS, schoolId));
|
|
|
|
|
|
|
|
if (classes.isEmpty()) {
|
|
|
|
|
|
|
|
throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "暂无班级");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
List<String> classIds = classes.stream().map(ClassInfo::getId).collect(Collectors.toList());
|
|
|
|
|
|
|
|
List<RecordVo> 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<String> recordIds = new ArrayList<>();
|
|
|
|
|
|
|
|
for (LessonRecord record : records) {
|
|
|
|
|
|
|
|
recordIds.add(record.getId());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//examIds.add("c26e5766-597f-45b3-91ad-19e76426323b");
|
|
|
|
|
|
|
|
//获取所有课程下的课中活动
|
|
|
|
|
|
|
|
List<Exam> exams = examRepository.findExamsByIds(String.format(PK.EXAM, laborDto.getTmdId()), recordIds);
|
|
|
|
|
|
|
|
Map<String, List<List<String>>> knowledgeMap = new HashMap<>();
|
|
|
|
|
|
|
|
Map<String, List<Double>> 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<String> examIds = new ArrayList<>();
|
|
|
|
|
|
|
|
for (Exam exam : exams) {
|
|
|
|
|
|
|
|
examIds.add(exam.getId());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
List<ExamClassResult> examResults = examClassResultRepository.findAll(String.format(PK.CLASS_RESULT, laborDto.getCode()),examIds);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Map<String, Object> resMap = new HashMap<>();
|
|
|
|
|
|
|
|
//处理德育知识块和知识点的关联关系
|
|
|
|
|
|
|
|
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<String, List<String>> knowledgeBlockToPointsMap = getKnowledgeBlockToPointsMap(appraise);
|
|
|
|
|
|
|
|
Map<String, Object> classScoreRate = new HashMap<>();
|
|
|
|
|
|
|
|
Map<String, Object> 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);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Map<String,Object> schoolScoreRate = calculateKnowledgeScoreForSchool(examResults, knowledgeMap,appraise, point,res);
|
|
|
|
|
|
|
|
resMap.put("gradeScoreRate", gradeScoreRate);
|
|
|
|
|
|
|
|
resMap.put("classScoreRate", classScoreRate);
|
|
|
|
|
|
|
|
resMap.put("schoolScoreRate", schoolScoreRate);
|
|
|
|
|
|
|
|
List<Map<String, Object>> scores = calculateScoresWithDetails(res, appraise);
|
|
|
|
|
|
|
|
List<Map<String, Object>> students = combineScoresWithExamResults(scores,examResults,knowledgeMap,point,knowledgeBlockToPointsMap);
|
|
|
|
|
|
|
|
resMap.put("scores", students);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//处理主观评价内容
|
|
|
|
|
|
|
|
return resMap;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public List<Map<String, Object>> combineScoresWithExamResults(
|
|
|
|
|
|
|
|
List<Map<String, Object>> scores,
|
|
|
|
|
|
|
|
List<ExamClassResult> examResults,
|
|
|
|
|
|
|
|
Map<String, List<List<String>>> knowledgeMap,
|
|
|
|
|
|
|
|
Map<String, List<Double>> points,
|
|
|
|
|
|
|
|
Map<String, List<String>> knowledgeBlockToPointsMap) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 计算每个学生的知识点得分
|
|
|
|
|
|
|
|
Map<String, Map<String, Double>> studentKnowledgePointScores = new HashMap<>();
|
|
|
|
|
|
|
|
for (Map<String, Object> studentResult : scores) {
|
|
|
|
|
|
|
|
String studentId = (String) studentResult.get("studentId");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化知识点总分
|
|
|
|
|
|
|
|
Map<String, Double> knowledgeTotalScore = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算当前学生的知识点得分
|
|
|
|
|
|
|
|
calculateStudentScoreRates(studentId, examResults, knowledgeMap, points, knowledgeTotalScore);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 将知识点得分存储到 studentKnowledgePointScores 中
|
|
|
|
|
|
|
|
studentKnowledgePointScores.put(studentId, knowledgeTotalScore);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 将知识点得分汇总到知识块级别
|
|
|
|
|
|
|
|
Map<String, Map<String, Double>> studentKnowledgeBlockScores = new HashMap<>();
|
|
|
|
|
|
|
|
for (Map.Entry<String, Map<String, Double>> entry : studentKnowledgePointScores.entrySet()) {
|
|
|
|
|
|
|
|
String studentId = entry.getKey();
|
|
|
|
|
|
|
|
Map<String, Double> pointScores = entry.getValue();
|
|
|
|
|
|
|
|
Map<String, Double> blockScores = studentKnowledgeBlockScores.computeIfAbsent(studentId, k -> new HashMap<>());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 遍历知识块和知识点的映射关系
|
|
|
|
|
|
|
|
for (Map.Entry<String, List<String>> blockEntry : knowledgeBlockToPointsMap.entrySet()) {
|
|
|
|
|
|
|
|
String knowledgeBlock = blockEntry.getKey();
|
|
|
|
|
|
|
|
List<String> 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<String, Object> studentResult : scores) {
|
|
|
|
|
|
|
|
String studentId = (String) studentResult.get("studentId");
|
|
|
|
|
|
|
|
Map<String, Integer> subjectiveScores = (Map<String, Integer>) studentResult.get("scores");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 查找该学生的知识块客观成绩
|
|
|
|
|
|
|
|
Map<String, Double> knowledgeBlockScores = studentKnowledgeBlockScores.get(studentId);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化主观总分和客观总分
|
|
|
|
|
|
|
|
double subjectiveTotal = 0.0;
|
|
|
|
|
|
|
|
double objectiveTotal = 0.0;
|
|
|
|
|
|
|
|
int knowledgeBlockCount = knowledgeBlockScores.size();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 更新主观成绩,计算主观总分和客观总分
|
|
|
|
|
|
|
|
Map<String, Object> combinedScores = new HashMap<>();
|
|
|
|
|
|
|
|
for (Map.Entry<String, Integer> entry : subjectiveScores.entrySet()) {
|
|
|
|
|
|
|
|
String knowledgeBlock = entry.getKey();
|
|
|
|
|
|
|
|
int count = entry.getValue(); // 次数
|
|
|
|
|
|
|
|
// 确保 count 不小于0
|
|
|
|
|
|
|
|
if (count < 0) {
|
|
|
|
|
|
|
|
count = 0; //次数永远不能为负数
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
double maxCount = 50.0; // 最大次数(可根据实际情况调整)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 将次数转换为 0-100 的分数
|
|
|
|
|
|
|
|
double convertedScore = (count / maxCount) * 100;
|
|
|
|
|
|
|
|
subjectiveTotal += convertedScore;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取对应知识块的客观成绩
|
|
|
|
|
|
|
|
double objectiveScore = knowledgeBlockScores.get(knowledgeBlock);
|
|
|
|
|
|
|
|
objectiveTotal += objectiveScore;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
形成 次数/客观分数 的格式
|
|
|
|
|
|
|
|
String combinedScore = count + "/" + objectiveScore;
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
int finalCount = count;
|
|
|
|
|
|
|
|
combinedScores.put(knowledgeBlock, new HashMap<String, Object>() {{
|
|
|
|
|
|
|
|
put("count", finalCount);
|
|
|
|
|
|
|
|
put("objectiveScore", objectiveScore);
|
|
|
|
|
|
|
|
}});
|
|
|
|
|
|
|
|
//combinedScores.put(knowledgeBlock, objectiveScore);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算客观平均分
|
|
|
|
|
|
|
|
double objectiveAverage = (knowledgeBlockCount > 0) ? objectiveTotal : 0.0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算综合得分(主观占 60%,客观占 40%)
|
|
|
|
|
|
|
|
double compositeScore = (subjectiveTotal * 0.6) + (objectiveAverage * 0.4);
|
|
|
|
|
|
|
|
compositeScore = Double.parseDouble(String.format("%.2f", compositeScore));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 更新返回数据
|
|
|
|
|
|
|
|
studentResult.put("scores", combinedScores);
|
|
|
|
|
|
|
|
studentResult.put("subjectiveTotal", subjectiveTotal);
|
|
|
|
|
|
|
|
studentResult.put("objectiveTotal", objectiveAverage);
|
|
|
|
|
|
|
|
studentResult.put("compositeScore", compositeScore);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return scores;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static List<Map<String, Object>> calculateScoresWithDetails(List<RecordVo> res, Appraise appraise) {
|
|
|
|
|
|
|
|
// 1. 构建知识点到知识块的映射 (一个知识块对应多个知识点)
|
|
|
|
|
|
|
|
Map<String, List<String>> knowledgeBlockToPointsMap = getKnowledgeBlockToPointsMap(appraise);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 构建所有二级知识块名称列表
|
|
|
|
|
|
|
|
Set<String> knowledgeBlocks = new HashSet<>();
|
|
|
|
|
|
|
|
for (AppraiseTreeNode node : appraise.getNodes()) {
|
|
|
|
|
|
|
|
if ("德育".equals(node.getName())) {
|
|
|
|
|
|
|
|
for (AppraiseTreeNode secondLevelNode : node.getChildren()) {
|
|
|
|
|
|
|
|
knowledgeBlocks.add(secondLevelNode.getName());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 构建知识点到知识块的映射 (一个知识点对应一个知识块)
|
|
|
|
|
|
|
|
Map<String, String> knowledgePointToBlockMap = new HashMap<>();
|
|
|
|
|
|
|
|
for (Map.Entry<String, List<String>> entry : knowledgeBlockToPointsMap.entrySet()) {
|
|
|
|
|
|
|
|
String knowledgeBlock = entry.getKey();
|
|
|
|
|
|
|
|
for (String knowledgePoint : entry.getValue()) {
|
|
|
|
|
|
|
|
knowledgePointToBlockMap.put(knowledgePoint, knowledgeBlock);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 遍历评价记录并统计得分
|
|
|
|
|
|
|
|
Map<String, Map<String, Integer>> studentScores = 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<String, Integer> studentScoreMap = studentScores.get(studentKey);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计分
|
|
|
|
|
|
|
|
// 计分
|
|
|
|
|
|
|
|
int score = isPraise ? 1 : -1;
|
|
|
|
|
|
|
|
int currentScore = studentScoreMap.getOrDefault(knowledgeBlock, 0) + score;
|
|
|
|
|
|
|
|
studentScoreMap.put(knowledgeBlock, Math.max(currentScore, 0));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 5. 初始化缺失的二级知识块分数
|
|
|
|
|
|
|
|
for (Map.Entry<String, Map<String, Integer>> entry : studentScores.entrySet()) {
|
|
|
|
|
|
|
|
Map<String, Integer> studentScoreMap = entry.getValue();
|
|
|
|
|
|
|
|
for (String block : knowledgeBlocks) {
|
|
|
|
|
|
|
|
studentScoreMap.putIfAbsent(block, 0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 6. 整理并返回结果
|
|
|
|
|
|
|
|
return getMaps(studentScores);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 整理并返回结果
|
|
|
|
|
|
|
|
private static List<Map<String, Object>> getMaps(Map<String, Map<String, Integer>> studentScores) {
|
|
|
|
|
|
|
|
List<Map<String, Object>> result = new ArrayList<>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (Map.Entry<String, Map<String, Integer>> entry : studentScores.entrySet()) {
|
|
|
|
|
|
|
|
String studentKey = entry.getKey();
|
|
|
|
|
|
|
|
Map<String, Integer> scoreMap = entry.getValue();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 解析学生唯一标识
|
|
|
|
|
|
|
|
String[] studentInfo = studentKey.split("\\|");
|
|
|
|
|
|
|
|
String studentId = studentInfo[0];
|
|
|
|
|
|
|
|
String studentName = studentInfo[1];
|
|
|
|
|
|
|
|
String className = studentInfo[2];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 构建返回结果
|
|
|
|
|
|
|
|
Map<String, Object> 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<String, List<String>> getKnowledgeBlockToPointsMap(Appraise appraise) {
|
|
|
|
|
|
|
|
Map<String, List<String>> knowledgeBlockToPointsMap = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (AppraiseTreeNode node : appraise.getNodes()) {
|
|
|
|
|
|
|
|
if ("德育".equals(node.getName())) {
|
|
|
|
|
|
|
|
for (AppraiseTreeNode secondLevelNode : node.getChildren()) {
|
|
|
|
|
|
|
|
String knowledgeBlock = secondLevelNode.getName();
|
|
|
|
|
|
|
|
List<String> 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<String, Double> calculateKnowledgeScoreRateForStudent(
|
|
|
|
|
|
|
|
String studentId, List<ExamClassResult> examResults,
|
|
|
|
|
|
|
|
Map<String, List<List<String>>> knowledgeMap, Appraise appraise, Map<String, List<Double>> points) {
|
|
|
|
|
|
|
|
Map<String, Double> knowledgeTotalScore = new HashMap<>();
|
|
|
|
|
|
|
|
// 计算学生的知识点得分率
|
|
|
|
|
|
|
|
List<KnowledgeScoreRate> studentScoreRates = calculateStudentScoreRates(studentId, examResults, knowledgeMap, points, knowledgeTotalScore);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 查找知识点对应的节点及其父节点
|
|
|
|
|
|
|
|
Map<String, Double> 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<String, Object> calculateKnowledgeScoreRateForClass(
|
|
|
|
|
|
|
|
String classId,
|
|
|
|
|
|
|
|
List<ExamClassResult> examResults,
|
|
|
|
|
|
|
|
Map<String, List<List<String>>> knowledgeMap,
|
|
|
|
|
|
|
|
Appraise appraise,
|
|
|
|
|
|
|
|
Map<String, List<Double>> points,
|
|
|
|
|
|
|
|
List<RecordVo> res
|
|
|
|
|
|
|
|
, HttpServletRequest request) { // 新增主观评价记录
|
|
|
|
|
|
|
|
// 将 classId 转换为 List<String>
|
|
|
|
|
|
|
|
List<String> classIds = Collections.singletonList(classId);
|
|
|
|
|
|
|
|
GroupDto groupDto = new GroupDto();
|
|
|
|
|
|
|
|
groupDto.setIds(classIds);
|
|
|
|
|
|
|
|
groupDto.setSchoolId(appraise.getSchoolId());
|
|
|
|
|
|
|
|
String url = environment.getProperty("ies.server-url-group");
|
|
|
|
|
|
|
|
Map<String, Object> groupId = GroupUtil.getGroupId(groupDto,new GroupUtil(environment), request,url);
|
|
|
|
|
|
|
|
List<RMember> rMembers = new ArrayList<>();
|
|
|
|
|
|
|
|
for (Map.Entry<String, Object> entry : groupId.entrySet()) {
|
|
|
|
|
|
|
|
String key = entry.getKey();
|
|
|
|
|
|
|
|
Object value = entry.getValue();
|
|
|
|
|
|
|
|
if (key.equals("members")) {
|
|
|
|
|
|
|
|
String jsonGroups = JSON.toJSONString(value);
|
|
|
|
|
|
|
|
rMembers = JSON.parseObject(jsonGroups, new TypeReference<List<RMember>>() {});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 获取班级所有学生的客观分数
|
|
|
|
|
|
|
|
Map<String, Map<String, Double>> studentScoreRates = new HashMap<>();
|
|
|
|
|
|
|
|
Map<String, Double> classScoreRates = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 遍历班级中的每个学生
|
|
|
|
|
|
|
|
for (ExamClassResult examResult : examResults) {
|
|
|
|
|
|
|
|
if (!examResult.getInfo().getId().equals(classId)) continue; // 过滤出该班级的考试
|
|
|
|
|
|
|
|
List<Integer> 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<String, Double> scoreRates = calculateKnowledgeScoreRateForStudent(
|
|
|
|
|
|
|
|
studentId, examResults, knowledgeMap, appraise, points
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
studentScoreRates.put(name, scoreRates);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 累加班级整体得分率
|
|
|
|
|
|
|
|
for (Map.Entry<String, Double> entry : scoreRates.entrySet()) {
|
|
|
|
|
|
|
|
classScoreRates.put(entry.getKey(), classScoreRates.getOrDefault(entry.getKey(), 0.0) + entry.getValue());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 获取班级所有学生的主观分数(次数)
|
|
|
|
|
|
|
|
List<Map<String, Object>> subjectiveScoresList = calculateScoresWithDetails(res, appraise);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 将主观次数转换为0-100分数
|
|
|
|
|
|
|
|
Map<String, Map<String, Double>> subjectiveScores = new HashMap<>();
|
|
|
|
|
|
|
|
for (Map<String, Object> studentScore : subjectiveScoresList) {
|
|
|
|
|
|
|
|
String studentId = (String) studentScore.get("studentId");
|
|
|
|
|
|
|
|
// 修改这里:假设 scores 是 Map<String, Integer>
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
|
|
|
|
Map<String, Integer> scores = (Map<String, Integer>) studentScore.get("scores");
|
|
|
|
|
|
|
|
Map<String, Double> convertedScores = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
|
|
|
|
|
|
|
|
String block = entry.getKey();
|
|
|
|
|
|
|
|
int count = entry.getValue();
|
|
|
|
|
|
|
|
double maxCount = 50.0;
|
|
|
|
|
|
|
|
double convertedScore = (count / maxCount) * 100;
|
|
|
|
|
|
|
|
convertedScores.put(block, convertedScore);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
subjectiveScores.put(studentId, convertedScores);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 融合主观和客观分数
|
|
|
|
|
|
|
|
Map<String, Map<String, Double>> compositeStudentScores = new HashMap<>();
|
|
|
|
|
|
|
|
for (Map.Entry<String, Map<String, Double>> entry : studentScoreRates.entrySet()) {
|
|
|
|
|
|
|
|
String studentId = entry.getKey();
|
|
|
|
|
|
|
|
Map<String, Double> objective = entry.getValue();
|
|
|
|
|
|
|
|
Map<String, Double> subjective = subjectiveScores.getOrDefault(studentId, new HashMap<>());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算综合得分
|
|
|
|
|
|
|
|
Map<String, Double> compositeScores = new HashMap<>();
|
|
|
|
|
|
|
|
for (Map.Entry<String, Double> 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<String, Double> compositeClassScoreRates = new HashMap<>();
|
|
|
|
|
|
|
|
for (Map<String, Double> studentScores : compositeStudentScores.values()) {
|
|
|
|
|
|
|
|
for (Map.Entry<String, Double> 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. 返回结果
|
|
|
|
|
|
|
|
Map<String, Object> result = new HashMap<>();
|
|
|
|
|
|
|
|
result.put("classScoreRates", compositeClassScoreRates); // 班级整体得分率
|
|
|
|
|
|
|
|
result.put("studentScoreRates", compositeStudentScores); // 每个学生的综合得分率
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static List<KnowledgeScoreRate> calculateStudentScoreRates(
|
|
|
|
|
|
|
|
String studentId,
|
|
|
|
|
|
|
|
List<ExamClassResult> examResults,
|
|
|
|
|
|
|
|
Map<String, List<List<String>>> knowledgeMap,
|
|
|
|
|
|
|
|
Map<String, List<Double>> points,
|
|
|
|
|
|
|
|
Map<String, Double> knowledgeTotalScore) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 记录每个知识点的考试次数
|
|
|
|
|
|
|
|
Map<String, Integer> 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<List<String>> knowledgeList = knowledgeMap.get(examResult.getExamId());
|
|
|
|
|
|
|
|
List<Double> point = points.get(examResult.getExamId());
|
|
|
|
|
|
|
|
if (knowledgeList == null) continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 检查 studentScores 是否为空或越界
|
|
|
|
|
|
|
|
List<List<Double>> studentScores = examResult.getStudentScores();
|
|
|
|
|
|
|
|
if (studentIndex >= studentScores.size() || studentScores.get(studentIndex) == null) {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取当前学生的成绩列表
|
|
|
|
|
|
|
|
List<Double> studentScoreList = studentScores.get(studentIndex);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 确保知识列表、分数列表和学生成绩列表的大小一致
|
|
|
|
|
|
|
|
if (knowledgeList.size() != point.size() || knowledgeList.size() != studentScoreList.size()) {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 遍历每道题的得分和知识点
|
|
|
|
|
|
|
|
for (int i = 0; i < studentScoreList.size(); i++) {
|
|
|
|
|
|
|
|
String knowledge = knowledgeList.get(i).get(0); // 每题的第一个知识点
|
|
|
|
|
|
|
|
double studentScore = studentScoreList.get(i); // 学生的得分
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 累加知识点总分
|
|
|
|
|
|
|
|
knowledgeTotalScore.put(knowledge, knowledgeTotalScore.getOrDefault(knowledge, 0.0) + studentScore);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 记录该知识点的考试次数
|
|
|
|
|
|
|
|
knowledgeExamCount.put(knowledge, knowledgeExamCount.getOrDefault(knowledge, 0) + 1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算每个知识点的平均分
|
|
|
|
|
|
|
|
Map<String, Double> knowledgeAverageScore = new HashMap<>();
|
|
|
|
|
|
|
|
for (Map.Entry<String, Double> entry : knowledgeTotalScore.entrySet()) {
|
|
|
|
|
|
|
|
String knowledge = entry.getKey();
|
|
|
|
|
|
|
|
double totalScore = entry.getValue();
|
|
|
|
|
|
|
|
int examCount = knowledgeExamCount.getOrDefault(knowledge, 1); // 避免除零
|
|
|
|
|
|
|
|
double averageScore = totalScore / examCount;
|
|
|
|
|
|
|
|
knowledgeAverageScore.put(knowledge, averageScore);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 返回知识点平均分
|
|
|
|
|
|
|
|
return knowledgeAverageScore.entrySet().stream()
|
|
|
|
|
|
|
|
.map(entry -> new KnowledgeScoreRate(entry.getKey(), entry.getValue()))
|
|
|
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static double calculateNodeScoreRate(AppraiseTreeNode node, Map<String, Double> 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<String, Object> calculateKnowledgeScoreForGrade(
|
|
|
|
|
|
|
|
String gradeId,
|
|
|
|
|
|
|
|
List<ExamClassResult> examResults,
|
|
|
|
|
|
|
|
Map<String, List<List<String>>> knowledgeMap,
|
|
|
|
|
|
|
|
Appraise appraise,
|
|
|
|
|
|
|
|
Map<String, List<Double>> points,
|
|
|
|
|
|
|
|
List<RecordVo> res) { // 新增主观评价记录
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 获取年级所有班级的客观分数
|
|
|
|
|
|
|
|
Map<String, Map<String, Double>> classScores = new HashMap<>();
|
|
|
|
|
|
|
|
Map<String, Double> gradeScores = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 过滤出该年级的考试结果
|
|
|
|
|
|
|
|
List<ExamClassResult> gradeExamResults = examResults.stream()
|
|
|
|
|
|
|
|
.filter(examResult -> examResult.getGradeId().equals(gradeId))
|
|
|
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 获取年级所有学生的主观分数(次数)
|
|
|
|
|
|
|
|
List<Map<String, Object>> subjectiveScoresList = calculateScoresWithDetails(res, appraise);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 将主观次数转换为0-100分数
|
|
|
|
|
|
|
|
Map<String, Map<String, Double>> subjectiveScores = new HashMap<>();
|
|
|
|
|
|
|
|
for (Map<String, Object> studentScore : subjectiveScoresList) {
|
|
|
|
|
|
|
|
String studentId = (String) studentScore.get("studentId");
|
|
|
|
|
|
|
|
// 修改这里:假设 scores 是 Map<String, Integer>
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
|
|
|
|
Map<String, Integer> scores = (Map<String, Integer>) studentScore.get("scores");
|
|
|
|
|
|
|
|
Map<String, Double> convertedScores = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
|
|
|
|
|
|
|
|
String block = entry.getKey();
|
|
|
|
|
|
|
|
int count = entry.getValue();
|
|
|
|
|
|
|
|
double maxCount = 50.0;
|
|
|
|
|
|
|
|
double convertedScore = (count / maxCount) * 100;
|
|
|
|
|
|
|
|
convertedScores.put(block, convertedScore);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
subjectiveScores.put(studentId, convertedScores);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 遍历年级下的所有班级
|
|
|
|
|
|
|
|
for (ExamClassResult examResult : gradeExamResults) {
|
|
|
|
|
|
|
|
String classId = examResult.getInfo().getId();
|
|
|
|
|
|
|
|
String className = examResult.getInfo().getName();
|
|
|
|
|
|
|
|
Map<String, Double> classScoreSum = new HashMap<>();
|
|
|
|
|
|
|
|
Map<String, Integer> classScoreCount = new HashMap<>();
|
|
|
|
|
|
|
|
Map<String, Double> classScoresInner = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取学生状态列表
|
|
|
|
|
|
|
|
List<Integer> 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<String, Double> studentObjectiveScores = calculateKnowledgeScoreRateForStudent(
|
|
|
|
|
|
|
|
studentId, examResults, knowledgeMap, appraise, points
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取学生的主观分数
|
|
|
|
|
|
|
|
Map<String, Double> studentSubjectiveScores = subjectiveScores.getOrDefault(studentId, new HashMap<>());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算综合得分(主观60%,客观40%)
|
|
|
|
|
|
|
|
Map<String, Double> studentCompositeScores = new HashMap<>();
|
|
|
|
|
|
|
|
for (Map.Entry<String, Double> 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<String, Double> 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<String, Double> 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 (node.getName().equals("德育")) {
|
|
|
|
|
|
|
|
for (AppraiseTreeNode child : node.getChildren()) {
|
|
|
|
|
|
|
|
if (!classScoresInner.containsKey(child.getName())) {
|
|
|
|
|
|
|
|
classScoresInner.put(child.getName(), 0.0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 存储班级的平均得分
|
|
|
|
|
|
|
|
classScores.put(className, classScoresInner);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 5. 计算年级的平均得分
|
|
|
|
|
|
|
|
Map<String, Double> gradeScoreSum = new HashMap<>();
|
|
|
|
|
|
|
|
Map<String, Integer> gradeScoreCount = new HashMap<>();
|
|
|
|
|
|
|
|
for (Map<String, Double> classScore : classScores.values()) {
|
|
|
|
|
|
|
|
for (Map.Entry<String, Double> 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<String, Double> 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 (node.getName().equals("德育")) {
|
|
|
|
|
|
|
|
for (AppraiseTreeNode child : node.getChildren()) {
|
|
|
|
|
|
|
|
if (!gradeScores.containsKey(child.getName())) {
|
|
|
|
|
|
|
|
gradeScores.put(child.getName(), 0.0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 6. 返回结果
|
|
|
|
|
|
|
|
Map<String, Object> result = new HashMap<>();
|
|
|
|
|
|
|
|
result.put("gradeScores", gradeScores); // 年级平均得分
|
|
|
|
|
|
|
|
result.put("classScores", classScores); // 每个班级的平均得分
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static Map<String, Object> calculateKnowledgeScoreForSchool(
|
|
|
|
|
|
|
|
List<ExamClassResult> examResults,
|
|
|
|
|
|
|
|
Map<String, List<List<String>>> knowledgeMap,
|
|
|
|
|
|
|
|
Appraise appraise,
|
|
|
|
|
|
|
|
Map<String, List<Double>> points,
|
|
|
|
|
|
|
|
List<RecordVo> res) { // 新增主观评价记录
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 获取全校所有年级的客观分数
|
|
|
|
|
|
|
|
Map<String, Map<String, Double>> gradeScores = new HashMap<>();
|
|
|
|
|
|
|
|
Map<String, Double> schoolScores = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取所有年级的 ID
|
|
|
|
|
|
|
|
Set<String> gradeIds = examResults.stream()
|
|
|
|
|
|
|
|
.map(ExamClassResult::getGradeId)
|
|
|
|
|
|
|
|
.collect(Collectors.toSet());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 获取全校所有学生的主观分数(次数)
|
|
|
|
|
|
|
|
List<Map<String, Object>> subjectiveScoresList = calculateScoresWithDetails(res, appraise);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 将主观次数转换为0-100分数
|
|
|
|
|
|
|
|
Map<String, Map<String, Double>> subjectiveScores = new HashMap<>();
|
|
|
|
|
|
|
|
for (Map<String, Object> studentScore : subjectiveScoresList) {
|
|
|
|
|
|
|
|
String studentId = (String) studentScore.get("studentId");
|
|
|
|
|
|
|
|
// 修改这里:假设 scores 是 Map<String, Integer>
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
|
|
|
|
Map<String, Integer> scores = (Map<String, Integer>) studentScore.get("scores");
|
|
|
|
|
|
|
|
Map<String, Double> convertedScores = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
|
|
|
|
|
|
|
|
String block = entry.getKey();
|
|
|
|
|
|
|
|
int count = entry.getValue();
|
|
|
|
|
|
|
|
double maxCount = 50.0;
|
|
|
|
|
|
|
|
double convertedScore = (count / maxCount) * 100;
|
|
|
|
|
|
|
|
convertedScores.put(block, convertedScore);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
subjectiveScores.put(studentId, convertedScores);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 遍历所有年级
|
|
|
|
|
|
|
|
for (String gradeId : gradeIds) {
|
|
|
|
|
|
|
|
// 计算该年级的平均得分(包含主观和客观分数)
|
|
|
|
|
|
|
|
Map<String, Object> gradeResult = calculateKnowledgeScoreForGrade(
|
|
|
|
|
|
|
|
gradeId, examResults, knowledgeMap, appraise, points, res
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取该年级的平均得分
|
|
|
|
|
|
|
|
Map<String, Double> gradeScoresInner = (Map<String, Double>) gradeResult.get("gradeScores");
|
|
|
|
|
|
|
|
gradeScores.put(gradeId, gradeScoresInner);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 累加全校的得分总和
|
|
|
|
|
|
|
|
Map<String, Map<String, Double>> classScores = (Map<String, Map<String, Double>>) gradeResult.get("classScores");
|
|
|
|
|
|
|
|
for (Map<String, Double> classScoresInner : classScores.values()) {
|
|
|
|
|
|
|
|
for (Map.Entry<String, Double> entry : classScoresInner.entrySet()) {
|
|
|
|
|
|
|
|
String nodeName = entry.getKey();
|
|
|
|
|
|
|
|
double score = entry.getValue();
|
|
|
|
|
|
|
|
schoolScores.put(nodeName, schoolScores.getOrDefault(nodeName, 0.0) + score);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 5. 计算全校的平均得分
|
|
|
|
|
|
|
|
if (gradeIds.size() == 1) {
|
|
|
|
|
|
|
|
schoolScores.putAll(gradeScores.get(gradeIds.iterator().next()));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// 计算全校的平均得分
|
|
|
|
|
|
|
|
for (Map.Entry<String, Double> 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. 返回结果
|
|
|
|
|
|
|
|
Map<String, Object> result = new HashMap<>();
|
|
|
|
|
|
|
|
result.put("schoolScores", schoolScores); // 全校平均得分
|
|
|
|
|
|
|
|
result.put("gradeScores", gradeScores); // 每个年级的平均得分
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 查找知识点对应的节点
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param nodes 节点列表
|
|
|
|
|
|
|
|
* @param knowledge 学生知识点得分率列表
|
|
|
|
|
|
|
|
* @return 知识点对应的节点
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private static AppraiseTreeNode findKnowledgeNode(List<AppraiseTreeNode> 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<AppraiseTreeNode> 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; // 未找到父节点
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|