merge
This commit is contained in:
GoCo 2025-09-04 09:24:30 +08:00
commit a3a1ef430e
3 changed files with 153 additions and 5 deletions

View File

@ -1,5 +1,7 @@
package org.jeecg.modules.aiol.controller;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
import java.io.IOException;
@ -17,6 +19,7 @@ import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.query.QueryRuleEnum;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.aiol.dto.ExaminationResult;
import org.jeecg.modules.aiol.dto.QuestionAnswerDTO;
import org.jeecg.modules.aiol.dto.QuestionAnswerUser;
import org.jeecg.modules.aiol.entity.*;
@ -317,11 +320,10 @@ public class AiolExamController extends JeecgController<AiolExam, IAiolExamServi
updateWrapper.set(AiolExamRecord::getDeviceInfo, examRecord.getDeviceInfo());
}
// 阅卷
List<AiolExamAnswer> gradedAnswers = gradeExam(examRecord.getExamId(), examRecord.getUserId());
List<AiolExamAnswer> gradedAnswers = gradeExam(examRecord.getExamId(), examRecord.getUserId(), updateWrapper);
examAnswerService.updateBatchById(gradedAnswers);
// 更新考试状态提交时间
updateWrapper.
set(AiolExamRecord::getStatus,1).
set(AiolExamRecord::getSubmittedAt, new Date());
// 更新
return examRecordService.update(updateWrapper) ? Result.OK() : Result.error("提交考试失败");
@ -522,7 +524,15 @@ public class AiolExamController extends JeecgController<AiolExam, IAiolExamServi
.eq(AiolExamRecord::getUserId, userId)
);
if(one == null){
return Result.error("用户暂未考试,可获取考试题目");
return Result.ok("用户暂未考试,可获取考试题目");
}
LocalDateTime submittedAt = LocalDateTime.ofInstant(one.getSubmittedAt().toInstant(), ZoneId.systemDefault());
LocalDateTime examEndTime = submittedAt.plusMinutes(byId.getTotalTime());
if(examEndTime.isAfter(LocalDateTime.now(ZoneId.systemDefault()))){
return Result.ok("考试总时间已过");
}
if(one.getStatus() == 2){
return Result.OK("已批改",one);
}
return Result.OK(examAnswerService.
list(new LambdaQueryWrapper<AiolExamAnswer>().
@ -531,6 +541,113 @@ public class AiolExamController extends JeecgController<AiolExam, IAiolExamServi
);
}
//查询考试结果
@GetMapping("/queryExamResult")
@Operation(summary = "查询考试结果")
public Result<?> queryExamResult(@RequestParam String examId, @RequestParam String userId) {
AiolExamRecord one = examRecordService.getOne(
new LambdaQueryWrapper<AiolExamRecord>()
.eq(AiolExamRecord::getExamId, examId)
.eq(AiolExamRecord::getUserId, userId)
);
if(one == null){
return Result.error("考试记录不存在");
}
if(one.getStatus() != 2){
return Result.error("考试未批改");
}
// 获取学生的答题列表
List<AiolExamAnswer> examAnswerList = examAnswerService.list(
new LambdaQueryWrapper<AiolExamAnswer>()
.eq(AiolExamAnswer::getExamId, examId)
.eq(AiolExamAnswer::getUserId, userId)
);
//创建题目id到学生答案的映射
Map<String, AiolExamAnswer> examAnswerMap = examAnswerList.stream()
.collect(Collectors.toMap(AiolExamAnswer::getQuestionId, examAnswer -> examAnswer));
// 提取所有题目ID
List<String> questionIds = examAnswerList.stream()
.map(AiolExamAnswer::getQuestionId)
.collect(Collectors.toList());
// 查询题目
List<AiolQuestion> questions = questionService.list(
new LambdaQueryWrapper<AiolQuestion>()
.in(AiolQuestion::getId, questionIds)
);
// 按父题目id分类
Map<String, List<AiolQuestion>> questionsByParentId = questions.stream()
.collect(Collectors.groupingBy(
q -> q.getParentId() != null ? q.getParentId() : "NULL_PARENT"
));
// 按题目类型分组
Map<Integer, List<AiolQuestion>> questionsByType = questions.stream()
.collect(Collectors.groupingBy(AiolQuestion::getType));
// 分离选择题012
List<AiolQuestion> choiceQuestions = questionsByType.entrySet().stream()
.filter(entry -> entry.getKey() < 3)
.flatMap(entry -> entry.getValue().stream())
.collect(Collectors.toList());
// 获取填空题和简答题34
List<AiolQuestion> fillAndEssayQuestions = new ArrayList<>();
if (questionsByType.containsKey(3)) {
fillAndEssayQuestions.addAll(questionsByType.get(3));
}
if (questionsByType.containsKey(4)) {
fillAndEssayQuestions.addAll(questionsByType.get(4));
}
// 查询题目的选项
List<AiolQuestionOption> questionOptions = questionOptionService.list(
new LambdaQueryWrapper<AiolQuestionOption>()
.in(AiolQuestionOption::getQuestionId,
choiceQuestions.stream()
.map(AiolQuestion::getId)
.collect(Collectors.toList()))
);
// 查询填空题简答题的答案
List<AiolQuestionAnswer> questionAnswers = questionAnswerService.list(
new LambdaQueryWrapper<AiolQuestionAnswer>()
.in(AiolQuestionAnswer::getQuestionId,
fillAndEssayQuestions.stream()
.map(AiolQuestion::getId)
.collect(Collectors.toList()))
);
// 构建选择题选项映射题目ID -> 选项列表
Map<String, List<AiolQuestionOption>> questionOptionMap = questionOptions.stream()
.collect(Collectors.groupingBy(AiolQuestionOption::getQuestionId));
// 构建填空题和简答题答案映射题目ID -> 答案列表
Map<String, List<AiolQuestionAnswer>> questionAnswerMap = questionAnswers.stream()
.collect(Collectors.groupingBy(AiolQuestionAnswer::getQuestionId));
// 合并到一个映射中
Map<String, List<?>> questionOrIdMap = new HashMap<>();
questionOrIdMap.putAll(questionOptionMap);
questionOrIdMap.putAll(questionAnswerMap);
List<ExaminationResult> examinationResultList = new ArrayList<>();
// 遍历没有父题目的题目
questionsByParentId.get("NULL_PARENT").forEach(q -> {
ExaminationResult examinationResult = new ExaminationResult();
examinationResult.setQuestion(q);
examinationResult.setUserAnswer(examAnswerMap.get(q.getId()));
examinationResult.setAnswer(questionOrIdMap.get(q.getId()));
// 检查当前题目是否是复合题目
if (questionsByParentId.containsKey(q.getId())) {
// 如果是复合题目查找其子题目
List<ExaminationResult> childResults = new ArrayList<>();
questionsByParentId.get(q.getId()).forEach(childQ -> {
ExaminationResult childResult = new ExaminationResult();
childResult.setQuestion(childQ);
childResult.setUserAnswer(examAnswerMap.get(childQ.getId()));
childResult.setAnswer(questionOrIdMap.get(childQ.getId()));
childResults.add(childResult);
});
examinationResult.setChildren(childResults);
}
examinationResultList.add(examinationResult);
});
return Result.OK(examinationResultList);
}
//根据考试规则随机组卷
public List<String> random(List<AiolQuestionRepo> list, String rules) {
JSONObject ruleJson = JSON.parseObject(rules);
@ -620,9 +737,10 @@ public class AiolExamController extends JeecgController<AiolExam, IAiolExamServi
* 批量阅卷
* @param examId 考试ID
* @param userId 用户ID
*
* @return 阅卷后的答题列表
*/
private List<AiolExamAnswer> gradeExam(String examId, String userId) {
private List<AiolExamAnswer> gradeExam(String examId, String userId , LambdaUpdateWrapper<AiolExamRecord> updateWrapper) {
//获取试卷信息
AiolExam exam = examService.getById(examId);
//获取组卷信息
@ -714,6 +832,7 @@ public class AiolExamController extends JeecgController<AiolExam, IAiolExamServi
));
// 遍历学生的答案进行评分
Double totalPoint = 0.0;
for (AiolExamAnswer examAnswer : examAnswerList) {
String studentAnswer = examAnswer.getAnswer();
AiolQuestion question = questionMap.get(examAnswer.getQuestionId());
@ -818,13 +937,21 @@ public class AiolExamController extends JeecgController<AiolExam, IAiolExamServi
}
break;
}
totalPoint += score;
examAnswer.setScore(score);
// 只有得了满分才算对
examAnswer.setIzCorrect(score > 0 && score == (paper.getGenerateMode() == 0 ?
questionScoreMap.get(question.getId()) :
ruleJson.getDouble("type" + question.getType() + "_score")) ? 1 : 0);
}
if(paper.getRequireReview()==1){
updateWrapper
.set(AiolExamRecord::getStatus, 1);
}else {
updateWrapper
.set(AiolExamRecord::getStatus, 2)
.set(AiolExamRecord::getTotalScore, totalPoint);
}
return examAnswerList;
}

View File

@ -0,0 +1,19 @@
package org.jeecg.modules.aiol.dto;
import lombok.Data;
import org.jeecg.modules.aiol.entity.AiolExamAnswer;
import org.jeecg.modules.aiol.entity.AiolQuestion;
import java.util.List;
@Data
public class ExaminationResult {
//题目内容
private AiolQuestion question;
//选项答案
private List<?> answer;
//用户答案
private AiolExamAnswer userAnswer;
//子题目列表
private List<ExaminationResult> children;
}

View File

@ -2,6 +2,7 @@ package org.jeecg.modules.aiol.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.jeecg.modules.aiol.entity.AiolRepo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
@ -12,6 +13,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
* @Date: 2025-08-31
* @Version: V1.0
*/
@Mapper
public interface AiolRepoMapper extends BaseMapper<AiolRepo> {
}