From b41598f7f86841ff7f51dd3b55e2e94254e53d86 Mon Sep 17 00:00:00 2001 From: Lqc Date: Wed, 3 Sep 2025 14:56:13 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E8=8E=B7=E5=8F=96=E8=80=83=E8=AF=95?= =?UTF-8?q?=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../aiol/controller/AiolExamController.java | 1582 +++++++++-------- .../modules/aiol/dto/ExaminationResult.java | 19 + 2 files changed, 869 insertions(+), 732 deletions(-) create mode 100644 jeecg-boot/jeecg-boot-module/jeecg-module-aiol/src/main/java/org/jeecg/modules/aiol/dto/ExaminationResult.java diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-aiol/src/main/java/org/jeecg/modules/aiol/controller/AiolExamController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-aiol/src/main/java/org/jeecg/modules/aiol/controller/AiolExamController.java index aaf96c2e..fad257b2 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-aiol/src/main/java/org/jeecg/modules/aiol/controller/AiolExamController.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-aiol/src/main/java/org/jeecg/modules/aiol/controller/AiolExamController.java @@ -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.*; @@ -58,132 +61,132 @@ public class AiolExamController extends JeecgController> queryPageList(AiolExam aiolExam, - @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, - @RequestParam(name="pageSize", defaultValue="10") Integer pageSize, - HttpServletRequest req) { - - - QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(aiolExam, req.getParameterMap()); - Page page = new Page(pageNo, pageSize); - IPage pageList = aiolExamService.page(page, queryWrapper); - return Result.OK(pageList); - } - - /** - * 添加 - * - * @param aiolExam - * @return - */ - @AutoLog(value = "考试-添加") - @Operation(summary="考试-添加") - @RequiresPermissions("aiol:aiol_exam:add") - @PostMapping(value = "/add") - public Result add(@RequestBody AiolExam aiolExam) { - aiolExamService.save(aiolExam); - - return Result.OK("添加成功!"); - } - - /** - * 编辑 - * - * @param aiolExam - * @return - */ - @AutoLog(value = "考试-编辑") - @Operation(summary="考试-编辑") - @RequiresPermissions("aiol:aiol_exam:edit") - @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) - public Result edit(@RequestBody AiolExam aiolExam) { - aiolExamService.updateById(aiolExam); - return Result.OK("编辑成功!"); - } - - /** - * 通过id删除 - * - * @param id - * @return - */ - @AutoLog(value = "考试-通过id删除") - @Operation(summary="考试-通过id删除") - @RequiresPermissions("aiol:aiol_exam:delete") - @DeleteMapping(value = "/delete") - public Result delete(@RequestParam(name="id",required=true) String id) { - aiolExamService.removeById(id); - return Result.OK("删除成功!"); - } - - /** - * 批量删除 - * - * @param ids - * @return - */ - @AutoLog(value = "考试-批量删除") - @Operation(summary="考试-批量删除") - @RequiresPermissions("aiol:aiol_exam:deleteBatch") - @DeleteMapping(value = "/deleteBatch") - public Result deleteBatch(@RequestParam(name="ids",required=true) String ids) { - this.aiolExamService.removeByIds(Arrays.asList(ids.split(","))); - return Result.OK("批量删除成功!"); - } - - /** - * 通过id查询 - * - * @param id - * @return - */ - //@AutoLog(value = "考试-通过id查询") - @Operation(summary="考试-通过id查询") - @GetMapping(value = "/queryById") - public Result queryById(@RequestParam(name="id",required=true) String id) { - AiolExam aiolExam = aiolExamService.getById(id); - if(aiolExam==null) { - return Result.error("未找到对应数据"); - } - return Result.OK(aiolExam); - } - - /** - * 导出excel - * - * @param request - * @param aiolExam - */ - @RequiresPermissions("aiol:aiol_exam:exportXls") - @RequestMapping(value = "/exportXls") - public ModelAndView exportXls(HttpServletRequest request, AiolExam aiolExam) { - return super.exportXls(request, aiolExam, AiolExam.class, "考试"); - } - - /** - * 通过excel导入数据 - * - * @param request - * @param response - * @return - */ - @RequiresPermissions("aiol:aiol_exam:importExcel") - @RequestMapping(value = "/importExcel", method = RequestMethod.POST) - public Result importExcel(HttpServletRequest request, HttpServletResponse response) { - return super.importExcel(request, response, AiolExam.class); - } +// /** +// * 分页列表查询 +// * +// * @param aiolExam +// * @param pageNo +// * @param pageSize +// * @param req +// * @return +// */ +// //@AutoLog(value = "考试-分页列表查询") +// @Operation(summary="考试-分页列表查询") +// @GetMapping(value = "/list") +// public Result> queryPageList(AiolExam aiolExam, +// @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, +// @RequestParam(name="pageSize", defaultValue="10") Integer pageSize, +// HttpServletRequest req) { +// +// +// QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(aiolExam, req.getParameterMap()); +// Page page = new Page(pageNo, pageSize); +// IPage pageList = aiolExamService.page(page, queryWrapper); +// return Result.OK(pageList); +// } +// +// /** +// * 添加 +// * +// * @param aiolExam +// * @return +// */ +// @AutoLog(value = "考试-添加") +// @Operation(summary="考试-添加") +// @RequiresPermissions("aiol:aiol_exam:add") +// @PostMapping(value = "/add") +// public Result add(@RequestBody AiolExam aiolExam) { +// aiolExamService.save(aiolExam); +// +// return Result.OK("添加成功!"); +// } +// +// /** +// * 编辑 +// * +// * @param aiolExam +// * @return +// */ +// @AutoLog(value = "考试-编辑") +// @Operation(summary="考试-编辑") +// @RequiresPermissions("aiol:aiol_exam:edit") +// @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) +// public Result edit(@RequestBody AiolExam aiolExam) { +// aiolExamService.updateById(aiolExam); +// return Result.OK("编辑成功!"); +// } +// +// /** +// * 通过id删除 +// * +// * @param id +// * @return +// */ +// @AutoLog(value = "考试-通过id删除") +// @Operation(summary="考试-通过id删除") +// @RequiresPermissions("aiol:aiol_exam:delete") +// @DeleteMapping(value = "/delete") +// public Result delete(@RequestParam(name="id",required=true) String id) { +// aiolExamService.removeById(id); +// return Result.OK("删除成功!"); +// } +// +// /** +// * 批量删除 +// * +// * @param ids +// * @return +// */ +// @AutoLog(value = "考试-批量删除") +// @Operation(summary="考试-批量删除") +// @RequiresPermissions("aiol:aiol_exam:deleteBatch") +// @DeleteMapping(value = "/deleteBatch") +// public Result deleteBatch(@RequestParam(name="ids",required=true) String ids) { +// this.aiolExamService.removeByIds(Arrays.asList(ids.split(","))); +// return Result.OK("批量删除成功!"); +// } +// +// /** +// * 通过id查询 +// * +// * @param id +// * @return +// */ +// //@AutoLog(value = "考试-通过id查询") +// @Operation(summary="考试-通过id查询") +// @GetMapping(value = "/queryById") +// public Result queryById(@RequestParam(name="id",required=true) String id) { +// AiolExam aiolExam = aiolExamService.getById(id); +// if(aiolExam==null) { +// return Result.error("未找到对应数据"); +// } +// return Result.OK(aiolExam); +// } +// +// /** +// * 导出excel +// * +// * @param request +// * @param aiolExam +// */ +// @RequiresPermissions("aiol:aiol_exam:exportXls") +// @RequestMapping(value = "/exportXls") +// public ModelAndView exportXls(HttpServletRequest request, AiolExam aiolExam) { +// return super.exportXls(request, aiolExam, AiolExam.class, "考试"); +// } +// +// /** +// * 通过excel导入数据 +// * +// * @param request +// * @param response +// * @return +// */ +// @RequiresPermissions("aiol:aiol_exam:importExcel") +// @RequestMapping(value = "/importExcel", method = RequestMethod.POST) +// public Result importExcel(HttpServletRequest request, HttpServletResponse response) { +// return super.importExcel(request, response, AiolExam.class); +// } @Autowired private IAiolPaperService paperService; @@ -204,303 +207,303 @@ public class AiolExamController extends JeecgController getExamQuestions(@PathVariable String examId, @RequestParam String studentId) { - AiolExam exam = examService.getById(examId); - if(exam.getPaperId().isEmpty()){ - return Result.error("考试未关联试卷"); - } - AiolPaper paper = paperService.getById(exam.getPaperId()); - //题目id集合 - List questionIds; - List paperQuestions = new ArrayList<>(); - //随机组卷 - if(paper.getGenerateMode()==1){ - List list = questionRepoService.list( - new LambdaQueryWrapper(). - eq(AiolQuestionRepo::getRepoId, paper.getRepoId()) - ); - //筛选试卷 - questionIds = random(list, paper.getRules()); - }else { - //固定组卷 - // 获取试卷中的试题关联信息 - paperQuestions = paperQuestionService.getQuestions(paper.getId()); - - // 如果没有试题关联信息,直接返回空列表 - if (CollectionUtils.isEmpty(paperQuestions)) { - return Result.OK("试卷中没有试题"); - } - // 提取所有试题ID - questionIds = paperQuestions.stream() - .map(AiolPaperQuestion::getQuestionId) - .collect(Collectors.toList()); - } - if (CollectionUtils.isEmpty(questionIds)) { - return Result.OK("试卷中没有试题"); - } - // 从题目表查询试题内容 - List questions = questionService.listByIds(questionIds); - - List sortedQuestions = questions; - // 将固定试题内容按试卷中的顺序排序 - if(paper.getGenerateMode()==0){ - Map questionMap = questions.stream() - .collect(Collectors.toMap(AiolQuestion::getId, question -> question)); - sortedQuestions = paperQuestions.stream() - .sorted(Comparator.comparing(AiolPaperQuestion::getOrderNo)) - .map(paperQuestion -> questionMap.get(paperQuestion.getQuestionId())) - .collect(Collectors.toList()); - } - //创建考试答题初始化记录 - List examAnswerList = new ArrayList<>(); - for (AiolQuestion resultQuestion : sortedQuestions) { - AiolExamAnswer examAnswer = new AiolExamAnswer(); - examAnswer.setExamId(examId); - examAnswer.setUserId(studentId); - if (resultQuestion != null && StringUtils.isNotEmpty(resultQuestion.getParentId())) { - examAnswer.setParentQuestionId(resultQuestion.getParentId()); - } - examAnswer.setQuestionId(resultQuestion.getId()); - examAnswerList.add(examAnswer); - } - examAnswerService.saveBatch(examAnswerList); - //创建考试记录 - AiolExamRecord examRecord = new AiolExamRecord(); - examRecord.setExamId(examId); - examRecord.setUserId(studentId); - examRecord.setStatus(0); - examRecordService.save(examRecord); - // 返回排序后的试题总列表 - return Result.OK(sortedQuestions); - } - - @PostMapping("/submitAnswer") - @Operation(summary = "提交答案") - public Result submitAnswer(@RequestBody AiolExamAnswer examAnswer) { - // 创建查询条件 - LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); - updateWrapper.eq(AiolExamAnswer::getExamId, examAnswer.getExamId()) - .eq(AiolExamAnswer::getUserId, examAnswer.getUserId()) - .eq(AiolExamAnswer::getQuestionId, examAnswer.getQuestionId()); - - // 更新答案 - if (examAnswer.getAnswer() != null) { - updateWrapper.set(AiolExamAnswer::getAnswer, examAnswer.getAnswer()); - } - // 执行更新 - return examAnswerService.update(updateWrapper) ? Result.OK() : Result.error("提交答案失败"); - } - - @PostMapping("/submitExam") - @Operation(summary = "提交考试") - @Transactional - public Result submitExam(@RequestBody AiolExamRecord examRecord, - HttpServletRequest req) { - examRecord.setIpAddress(getClientIp(req)); - examRecord.setDeviceInfo(getDeviceInfo(req)); - //修改状态 - examRecord.setStatus(1); - // 创建更新条件 - LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); - updateWrapper.eq(AiolExamRecord::getExamId, examRecord.getExamId()) - .eq(AiolExamRecord::getUserId, examRecord.getUserId()); - // 更新ip - if (examRecord.getIpAddress() != null) { - updateWrapper.set(AiolExamRecord::getIpAddress, examRecord.getIpAddress()); - } - // 更新设备信息 - if (examRecord.getDeviceInfo() != null) { - updateWrapper.set(AiolExamRecord::getDeviceInfo, examRecord.getDeviceInfo()); - } - // 阅卷 - List gradedAnswers = gradeExam(examRecord.getExamId(), examRecord.getUserId()); - examAnswerService.updateBatchById(gradedAnswers); - // 更新考试状态,提交时间 - updateWrapper. - set(AiolExamRecord::getStatus,1). - set(AiolExamRecord::getSubmittedAt, new Date()); - // 更新 - return examRecordService.update(updateWrapper) ? Result.OK() : Result.error("提交考试失败"); - } - - //获取名下考试信息 - @GetMapping("/getExamInfo") - @Operation(summary = "获取教师名下考试") - public Result getExamInfo(@RequestParam String userId) { - return Result.OK(examService.list(new LambdaQueryWrapper().eq(AiolExam::getCreateBy, userId))); - } - - //获取考试相关答卷 - @GetMapping("/getExamRecord") - @Operation(summary = "获取考试相关答卷记录") - public Result getExamRecord(@RequestParam String examId) { - return Result.OK(examRecordService. - list(new LambdaQueryWrapper(). - eq(AiolExamRecord::getExamId, examId))); - } - - //获取考试相关答卷 - @GetMapping("/getExamRecordByUser") - @Operation(summary = "获取考试相关答卷答案") - public Result getExamRecordByUser(@RequestParam String examId,@RequestParam String userId) { - List list = examAnswerService. - list(new LambdaQueryWrapper(). - eq(AiolExamAnswer::getExamId, examId). - eq(AiolExamAnswer::getUserId, userId)); - Map questionIdToAnswerMap = list.stream() - .collect(Collectors.toMap( - AiolExamAnswer::getQuestionId, - answer -> answer - )); - if(!list.isEmpty()){ - List questionIds = list.stream() - .map(AiolExamAnswer::getQuestionId) - .collect(Collectors.toList()); - List questions = questionService.listByIds(questionIds); - //取出简答题 - List type4Questions = questions.stream() - .filter(question -> question.getType() == 4) - .collect(Collectors.toList()); - Map questionIdToTitleMap = type4Questions.stream().collect(Collectors.toMap(AiolQuestion::getId, question -> question)); - if(!type4Questions.isEmpty()){ - List collect = type4Questions.stream().map(AiolQuestion::getId).collect(Collectors.toList()); - //查询题目答案 - List list1 = questionAnswerService.list(new LambdaQueryWrapper() - .in(AiolQuestionAnswer::getQuestionId, collect) - ); - // 查询题目分数 - AiolExam exam = examService.getById(examId); - AiolPaper paper = paperService.getById(exam.getPaperId()); - - // 根据试卷生成模式获取分数 - Map questionIdToScoreMap = Optional.ofNullable(paper) - .filter(p -> p.getGenerateMode() == 0) - .map(p -> paperQuestionService.list(new LambdaQueryWrapper() - .eq(AiolPaperQuestion::getPaperId, p.getId()) - .in(AiolPaperQuestion::getQuestionId, collect))) - .orElse(Collections.emptyList()) - .stream() - .collect(Collectors.toMap( - AiolPaperQuestion::getQuestionId, - AiolPaperQuestion::getScore - )); - - // 获取类型4的题目分数(仅在非固定模式下) - Double type4Score = Optional.ofNullable(paper) - .filter(p -> p.getGenerateMode() != 0) - .map(p -> JSON.parseObject(p.getRules()).getDouble("type4_score")) - .orElse(0.0); - - // 构建用户答案列表 - List questionAnswerUserList = list1.stream() - .map(questionAnswer -> { - QuestionAnswerUser questionAnswerUser = new QuestionAnswerUser(); - questionAnswerUser.setQuestion(questionIdToTitleMap.get(questionAnswer.getQuestionId())); - questionAnswerUser.setUserAnswer(questionIdToAnswerMap.get(questionAnswer.getQuestionId())); - questionAnswerUser.setAnswer(questionAnswer); - questionAnswerUser.setFullMark(questionIdToScoreMap.getOrDefault( - questionAnswer.getQuestionId(), - type4Score - )); - return questionAnswerUser; - }) - .collect(Collectors.toList()); - return Result.OK(questionAnswerUserList); - } - } - return Result.OK("没有需要批改的题目数据"); - } - - @PostMapping("/submitGrade") - @Operation(summary = "提交批改") - @Transactional - public Result submitGrade(@RequestBody List examAnswers) { - // 检查输入参数是否为空 - if (CollectionUtils.isEmpty(examAnswers)) { - return Result.error("批改数据不能为空"); - } - try { - String examId = examAnswers.get(0).getExamId(); - String userId = examAnswers.get(0).getUserId(); - List list = examAnswerService.list(new LambdaQueryWrapper() - .eq(AiolExamAnswer::getExamId, examId) - .eq(AiolExamAnswer::getUserId, userId)); - // 创建examAnswers的ID映射,方便查找 - Map examAnswerMap = examAnswers.stream() - .collect(Collectors.toMap(AiolExamAnswer::getId, answer -> answer)); - // 创建list的id映射 - Map listIdMap = list.stream() - .collect(Collectors.toMap(AiolExamAnswer::getQuestionId, answer -> answer)); - //计算总分 - Double totalScore = list.stream().mapToDouble(AiolExamAnswer::getScore).sum() + examAnswers.stream().mapToDouble(AiolExamAnswer::getScore).sum(); - - // 复合题对错得分 - List sonList = list.stream() - .filter(answer -> answer.getParentQuestionId() != null && !answer.getParentQuestionId().isEmpty()) - .collect(Collectors.toList()); - - if (!sonList.isEmpty()) { - // 按父ID分组 - Map> parentGroup = sonList.stream() - .collect(Collectors.groupingBy(AiolExamAnswer::getParentQuestionId)); - - // 遍历每个父题组 - for (Map.Entry> entry : parentGroup.entrySet()) { - String parentId = entry.getKey(); - List children = entry.getValue(); - - Double parentScore = 0.0; - boolean isCorrect = true; - - // 计算每个子题的分数和正确性 - for (AiolExamAnswer childAnswer : children) { - Double sonScore = 0.0; - if (examAnswerMap.get(childAnswer.getId()) != null) { - if (isCorrect && examAnswerMap.get(childAnswer.getId()).getIzCorrect() == 0) { - isCorrect = false; - } - sonScore = examAnswerMap.get(childAnswer.getId()).getScore(); - } else { - if (isCorrect && childAnswer.getIzCorrect() == 0) { - isCorrect = false; - } - sonScore = childAnswer.getScore(); - } - parentScore += sonScore; - } - - // 更新父题的分数和正确性 - AiolExamAnswer parentAnswer = listIdMap.get(parentId); - if (parentAnswer != null) { - parentAnswer.setIzCorrect(isCorrect ? 1 : 0); - parentAnswer.setScore(parentScore); - examAnswers.add(parentAnswer); - } - } - } - // 更新考试记录的状态为已批改 - examRecordService.update(new LambdaUpdateWrapper() - .set(AiolExamRecord::getStatus, 2) - .set(AiolExamRecord::getTotalScore, totalScore) - .eq(AiolExamRecord::getExamId, examId) - .eq(AiolExamRecord::getUserId, userId)); - // 批量更新答题分数 - boolean success = examAnswerService.updateBatchById(examAnswers); - if (!success) { - return Result.error("批改失败"); - } - // 可选:更新考试的总分和平均分(如果需要) - // 这里可以添加额外的业务逻辑 - return Result.OK("批改成功"); - } catch (Exception e) { - log.error("提交批改失败", e); - return Result.error("系统错误:" + e.getMessage()); - } - } +// //获取考试试题 +// @RequestMapping("/getExamQuestions/{examId}") +// @Operation(summary = "获取考试试题") +// @Transactional +// public Result getExamQuestions(@PathVariable String examId, @RequestParam String studentId) { +// AiolExam exam = examService.getById(examId); +// if(exam.getPaperId().isEmpty()){ +// return Result.error("考试未关联试卷"); +// } +// AiolPaper paper = paperService.getById(exam.getPaperId()); +// //题目id集合 +// List questionIds; +// List paperQuestions = new ArrayList<>(); +// //随机组卷 +// if(paper.getGenerateMode()==1){ +// List list = questionRepoService.list( +// new LambdaQueryWrapper(). +// eq(AiolQuestionRepo::getRepoId, paper.getRepoId()) +// ); +// //筛选试卷 +// questionIds = random(list, paper.getRules()); +// }else { +// //固定组卷 +// // 获取试卷中的试题关联信息 +// paperQuestions = paperQuestionService.getQuestions(paper.getId()); +// +// // 如果没有试题关联信息,直接返回空列表 +// if (CollectionUtils.isEmpty(paperQuestions)) { +// return Result.OK("试卷中没有试题"); +// } +// // 提取所有试题ID +// questionIds = paperQuestions.stream() +// .map(AiolPaperQuestion::getQuestionId) +// .collect(Collectors.toList()); +// } +// if (CollectionUtils.isEmpty(questionIds)) { +// return Result.OK("试卷中没有试题"); +// } +// // 从题目表查询试题内容 +// List questions = questionService.listByIds(questionIds); +// +// List sortedQuestions = questions; +// // 将固定试题内容按试卷中的顺序排序 +// if(paper.getGenerateMode()==0){ +// Map questionMap = questions.stream() +// .collect(Collectors.toMap(AiolQuestion::getId, question -> question)); +// sortedQuestions = paperQuestions.stream() +// .sorted(Comparator.comparing(AiolPaperQuestion::getOrderNo)) +// .map(paperQuestion -> questionMap.get(paperQuestion.getQuestionId())) +// .collect(Collectors.toList()); +// } +// //创建考试答题初始化记录 +// List examAnswerList = new ArrayList<>(); +// for (AiolQuestion resultQuestion : sortedQuestions) { +// AiolExamAnswer examAnswer = new AiolExamAnswer(); +// examAnswer.setExamId(examId); +// examAnswer.setUserId(studentId); +// if (resultQuestion != null && StringUtils.isNotEmpty(resultQuestion.getParentId())) { +// examAnswer.setParentQuestionId(resultQuestion.getParentId()); +// } +// examAnswer.setQuestionId(resultQuestion.getId()); +// examAnswerList.add(examAnswer); +// } +// examAnswerService.saveBatch(examAnswerList); +// //创建考试记录 +// AiolExamRecord examRecord = new AiolExamRecord(); +// examRecord.setExamId(examId); +// examRecord.setUserId(studentId); +// examRecord.setStatus(0); +// examRecordService.save(examRecord); +// // 返回排序后的试题总列表 +// return Result.OK(sortedQuestions); +// } +// +// @PostMapping("/submitAnswer") +// @Operation(summary = "提交答案") +// public Result submitAnswer(@RequestBody AiolExamAnswer examAnswer) { +// // 创建查询条件 +// LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); +// updateWrapper.eq(AiolExamAnswer::getExamId, examAnswer.getExamId()) +// .eq(AiolExamAnswer::getUserId, examAnswer.getUserId()) +// .eq(AiolExamAnswer::getQuestionId, examAnswer.getQuestionId()); +// +// // 更新答案 +// if (examAnswer.getAnswer() != null) { +// updateWrapper.set(AiolExamAnswer::getAnswer, examAnswer.getAnswer()); +// } +// // 执行更新 +// return examAnswerService.update(updateWrapper) ? Result.OK() : Result.error("提交答案失败"); +// } +// +// @PostMapping("/submitExam") +// @Operation(summary = "提交考试") +// @Transactional +// public Result submitExam(@RequestBody AiolExamRecord examRecord, +// HttpServletRequest req) { +// examRecord.setIpAddress(getClientIp(req)); +// examRecord.setDeviceInfo(getDeviceInfo(req)); +// //修改状态 +// examRecord.setStatus(1); +// // 创建更新条件 +// LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); +// updateWrapper.eq(AiolExamRecord::getExamId, examRecord.getExamId()) +// .eq(AiolExamRecord::getUserId, examRecord.getUserId()); +// // 更新ip +// if (examRecord.getIpAddress() != null) { +// updateWrapper.set(AiolExamRecord::getIpAddress, examRecord.getIpAddress()); +// } +// // 更新设备信息 +// if (examRecord.getDeviceInfo() != null) { +// updateWrapper.set(AiolExamRecord::getDeviceInfo, examRecord.getDeviceInfo()); +// } +// // 阅卷 +// List gradedAnswers = gradeExam(examRecord.getExamId(), examRecord.getUserId()); +// examAnswerService.updateBatchById(gradedAnswers); +// // 更新考试状态,提交时间 +// updateWrapper. +// set(AiolExamRecord::getStatus,1). +// set(AiolExamRecord::getSubmittedAt, new Date()); +// // 更新 +// return examRecordService.update(updateWrapper) ? Result.OK() : Result.error("提交考试失败"); +// } +// +// //获取名下考试信息 +// @GetMapping("/getExamInfo") +// @Operation(summary = "获取教师名下考试") +// public Result getExamInfo(@RequestParam String userId) { +// return Result.OK(examService.list(new LambdaQueryWrapper().eq(AiolExam::getCreateBy, userId))); +// } +// +// //获取考试相关答卷 +// @GetMapping("/getExamRecord") +// @Operation(summary = "获取考试相关答卷记录") +// public Result getExamRecord(@RequestParam String examId) { +// return Result.OK(examRecordService. +// list(new LambdaQueryWrapper(). +// eq(AiolExamRecord::getExamId, examId))); +// } +// +// //获取考试相关答卷 +// @GetMapping("/getExamRecordByUser") +// @Operation(summary = "获取考试相关答卷答案") +// public Result getExamRecordByUser(@RequestParam String examId,@RequestParam String userId) { +// List list = examAnswerService. +// list(new LambdaQueryWrapper(). +// eq(AiolExamAnswer::getExamId, examId). +// eq(AiolExamAnswer::getUserId, userId)); +// Map questionIdToAnswerMap = list.stream() +// .collect(Collectors.toMap( +// AiolExamAnswer::getQuestionId, +// answer -> answer +// )); +// if(!list.isEmpty()){ +// List questionIds = list.stream() +// .map(AiolExamAnswer::getQuestionId) +// .collect(Collectors.toList()); +// List questions = questionService.listByIds(questionIds); +// //取出简答题 +// List type4Questions = questions.stream() +// .filter(question -> question.getType() == 4) +// .collect(Collectors.toList()); +// Map questionIdToTitleMap = type4Questions.stream().collect(Collectors.toMap(AiolQuestion::getId, question -> question)); +// if(!type4Questions.isEmpty()){ +// List collect = type4Questions.stream().map(AiolQuestion::getId).collect(Collectors.toList()); +// //查询题目答案 +// List list1 = questionAnswerService.list(new LambdaQueryWrapper() +// .in(AiolQuestionAnswer::getQuestionId, collect) +// ); +// // 查询题目分数 +// AiolExam exam = examService.getById(examId); +// AiolPaper paper = paperService.getById(exam.getPaperId()); +// +// // 根据试卷生成模式获取分数 +// Map questionIdToScoreMap = Optional.ofNullable(paper) +// .filter(p -> p.getGenerateMode() == 0) +// .map(p -> paperQuestionService.list(new LambdaQueryWrapper() +// .eq(AiolPaperQuestion::getPaperId, p.getId()) +// .in(AiolPaperQuestion::getQuestionId, collect))) +// .orElse(Collections.emptyList()) +// .stream() +// .collect(Collectors.toMap( +// AiolPaperQuestion::getQuestionId, +// AiolPaperQuestion::getScore +// )); +// +// // 获取类型4的题目分数(仅在非固定模式下) +// Double type4Score = Optional.ofNullable(paper) +// .filter(p -> p.getGenerateMode() != 0) +// .map(p -> JSON.parseObject(p.getRules()).getDouble("type4_score")) +// .orElse(0.0); +// +// // 构建用户答案列表 +// List questionAnswerUserList = list1.stream() +// .map(questionAnswer -> { +// QuestionAnswerUser questionAnswerUser = new QuestionAnswerUser(); +// questionAnswerUser.setQuestion(questionIdToTitleMap.get(questionAnswer.getQuestionId())); +// questionAnswerUser.setUserAnswer(questionIdToAnswerMap.get(questionAnswer.getQuestionId())); +// questionAnswerUser.setAnswer(questionAnswer); +// questionAnswerUser.setFullMark(questionIdToScoreMap.getOrDefault( +// questionAnswer.getQuestionId(), +// type4Score +// )); +// return questionAnswerUser; +// }) +// .collect(Collectors.toList()); +// return Result.OK(questionAnswerUserList); +// } +// } +// return Result.OK("没有需要批改的题目数据"); +// } +// +// @PostMapping("/submitGrade") +// @Operation(summary = "提交批改") +// @Transactional +// public Result submitGrade(@RequestBody List examAnswers) { +// // 检查输入参数是否为空 +// if (CollectionUtils.isEmpty(examAnswers)) { +// return Result.error("批改数据不能为空"); +// } +// try { +// String examId = examAnswers.get(0).getExamId(); +// String userId = examAnswers.get(0).getUserId(); +// List list = examAnswerService.list(new LambdaQueryWrapper() +// .eq(AiolExamAnswer::getExamId, examId) +// .eq(AiolExamAnswer::getUserId, userId)); +// // 创建examAnswers的ID映射,方便查找 +// Map examAnswerMap = examAnswers.stream() +// .collect(Collectors.toMap(AiolExamAnswer::getId, answer -> answer)); +// // 创建list的id映射 +// Map listIdMap = list.stream() +// .collect(Collectors.toMap(AiolExamAnswer::getQuestionId, answer -> answer)); +// //计算总分 +// Double totalScore = list.stream().mapToDouble(AiolExamAnswer::getScore).sum() + examAnswers.stream().mapToDouble(AiolExamAnswer::getScore).sum(); +// +// // 复合题对错得分 +// List sonList = list.stream() +// .filter(answer -> answer.getParentQuestionId() != null && !answer.getParentQuestionId().isEmpty()) +// .collect(Collectors.toList()); +// +// if (!sonList.isEmpty()) { +// // 按父ID分组 +// Map> parentGroup = sonList.stream() +// .collect(Collectors.groupingBy(AiolExamAnswer::getParentQuestionId)); +// +// // 遍历每个父题组 +// for (Map.Entry> entry : parentGroup.entrySet()) { +// String parentId = entry.getKey(); +// List children = entry.getValue(); +// +// Double parentScore = 0.0; +// boolean isCorrect = true; +// +// // 计算每个子题的分数和正确性 +// for (AiolExamAnswer childAnswer : children) { +// Double sonScore = 0.0; +// if (examAnswerMap.get(childAnswer.getId()) != null) { +// if (isCorrect && examAnswerMap.get(childAnswer.getId()).getIzCorrect() == 0) { +// isCorrect = false; +// } +// sonScore = examAnswerMap.get(childAnswer.getId()).getScore(); +// } else { +// if (isCorrect && childAnswer.getIzCorrect() == 0) { +// isCorrect = false; +// } +// sonScore = childAnswer.getScore(); +// } +// parentScore += sonScore; +// } +// +// // 更新父题的分数和正确性 +// AiolExamAnswer parentAnswer = listIdMap.get(parentId); +// if (parentAnswer != null) { +// parentAnswer.setIzCorrect(isCorrect ? 1 : 0); +// parentAnswer.setScore(parentScore); +// examAnswers.add(parentAnswer); +// } +// } +// } +// // 更新考试记录的状态为已批改 +// examRecordService.update(new LambdaUpdateWrapper() +// .set(AiolExamRecord::getStatus, 2) +// .set(AiolExamRecord::getTotalScore, totalScore) +// .eq(AiolExamRecord::getExamId, examId) +// .eq(AiolExamRecord::getUserId, userId)); +// // 批量更新答题分数 +// boolean success = examAnswerService.updateBatchById(examAnswers); +// if (!success) { +// return Result.error("批改失败"); +// } +// // 可选:更新考试的总分和平均分(如果需要) +// // 这里可以添加额外的业务逻辑 +// return Result.OK("批改成功"); +// } catch (Exception e) { +// log.error("提交批改失败", e); +// return Result.error("系统错误:" + e.getMessage()); +// } +// } @@ -522,7 +525,15 @@ public class AiolExamController extends JeecgController(). @@ -531,116 +542,20 @@ public class AiolExamController extends JeecgController random(List list, String rules) { - JSONObject ruleJson = JSON.parseObject(rules); - - // 根据规则筛选和随机抽取题目 - Map> typeQuestions = new HashMap<>(); - - // 先按题目类型分组 - list.forEach(qr -> { - AiolQuestion question = questionService.getById(qr.getQuestionId()); - if (!typeQuestions.containsKey(question.getType())) { - typeQuestions.put(question.getType(), new ArrayList<>()); - } - typeQuestions.get(question.getType()).add(question.getId()); - }); - - // 根据规则随机抽取题目 - List questionIds = new ArrayList<>(); - List compositeQuestions = new ArrayList<>(); // 存储复合题ID - - for (Integer type : typeQuestions.keySet()) { - int count = ruleJson.getInteger("type" + type + "_count"); - List typeQuestionIds = typeQuestions.get(type); - - // 随机抽取指定数量的题目 - if (typeQuestionIds.size() <= count) { - if (type == 5) { // 复合题先不添加,等处理完其他题目后再添加 - compositeQuestions.addAll(typeQuestionIds); - } else { - questionIds.addAll(typeQuestionIds); - } - } else { - // 打乱顺序后取前count个 - Collections.shuffle(typeQuestionIds); - List selectedQuestions = typeQuestionIds.subList(0, count); - - if (type == 5) { // 复合题先不添加,等处理完其他题目后再添加 - compositeQuestions.addAll(selectedQuestions); - } else { - questionIds.addAll(selectedQuestions); - } - } + //查询考试结果 + @GetMapping("/queryExamResult") + @Operation(summary = "查询考试结果") + public Result queryExamResult(@RequestParam String examId, @RequestParam String userId) { + AiolExamRecord one = examRecordService.getOne( + new LambdaQueryWrapper() + .eq(AiolExamRecord::getExamId, examId) + .eq(AiolExamRecord::getUserId, userId) + ); + if(one == null){ + return Result.error("考试记录不存在"); } - - // 将复合题及其子题目添加到列表末尾 - for (String compositeId : compositeQuestions) { - questionIds.add(compositeId); - // 获取并添加子题目ID - questionService.list( - new LambdaQueryWrapper() - .eq(AiolQuestion::getParentId, compositeId) - ).stream() - .map(subQuestion -> subQuestion.getId().toString()) - .forEach(questionIds::add); - } - - return questionIds; - } - - //获取ip信息 - public String getClientIp(HttpServletRequest request) { - String ip = request.getHeader("X-Forwarded-For"); - - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("Proxy-Client-IP"); - } - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("WL-Proxy-Client-IP"); - } - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("HTTP_CLIENT_IP"); - } - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("HTTP_X_FORWARDED_FOR"); - } - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getRemoteAddr(); - } - // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 - if (ip != null && ip.contains(",")) { - ip = ip.split(",")[0].trim(); - } - return ip; - } - - /** - * 批量阅卷 - * @param examId 考试ID - * @param userId 用户ID - * @return 阅卷后的答题列表 - */ - private List gradeExam(String examId, String userId) { - //获取试卷信息 - AiolExam exam = examService.getById(examId); - //获取组卷信息 - AiolPaper paper = paperService.getOne(new LambdaQueryWrapper().eq(AiolPaper::getId, exam.getPaperId())); - if(paper == null){ - throw new RuntimeException("试卷不存在"); - } - Map questionScoreMap = new HashMap<>(); - JSONObject ruleJson = null; - if(paper.getGenerateMode()==0){ - List list = paperQuestionService.list(new LambdaQueryWrapper().eq(AiolPaperQuestion::getPaperId, paper.getId())); - questionScoreMap = list.stream() - .collect(Collectors.toMap( - AiolPaperQuestion::getQuestionId, - AiolPaperQuestion::getScore - )); - }else { - ruleJson = JSON.parseObject(paper.getRules()); + if(one.getStatus() != 2){ + return Result.error("考试未批改"); } // 获取学生的答题列表 List examAnswerList = examAnswerService.list( @@ -648,234 +563,437 @@ public class AiolExamController extends JeecgController examAnswerMap = examAnswerList.stream() + .collect(Collectors.toMap(AiolExamAnswer::getQuestionId, examAnswer -> examAnswer)); + // 提取所有题目ID List questionIds = examAnswerList.stream() .map(AiolExamAnswer::getQuestionId) .collect(Collectors.toList()); - - // 查询题目 + // 查询题目 List questions = questionService.list( new LambdaQueryWrapper() .in(AiolQuestion::getId, questionIds) - .lt(AiolQuestion::getType, 4) ); - - // 创建题目ID到题目的映射 - Map questionMap = questions.stream() - .collect(Collectors.toMap(AiolQuestion::getId, question -> question)); - - // 按题目类型分组 + // 按父题目id分类 + Map> questionsByParentId = questions.stream() + .collect(Collectors.groupingBy( + q -> q.getParentId() != null ? q.getParentId() : "NULL_PARENT" + )); + // 按题目类型分组 Map> questionsByType = questions.stream() .collect(Collectors.groupingBy(AiolQuestion::getType)); - - // 分离选择题(0、1、2)和填空题(3) + // 分离选择题(0、1、2) List choiceQuestions = questionsByType.entrySet().stream() .filter(entry -> entry.getKey() < 3) .flatMap(entry -> entry.getValue().stream()) .collect(Collectors.toList()); - - List fillQuestions = questionsByType.getOrDefault(3, new ArrayList<>()); - - // 查询题目的正确选项 + // 获取填空题和简答题(3、4) + List fillAndEssayQuestions = new ArrayList<>(); + if (questionsByType.containsKey(3)) { + fillAndEssayQuestions.addAll(questionsByType.get(3)); + } + if (questionsByType.containsKey(4)) { + fillAndEssayQuestions.addAll(questionsByType.get(4)); + } + // 查询题目的选项 List questionOptions = questionOptionService.list( new LambdaQueryWrapper() .in(AiolQuestionOption::getQuestionId, choiceQuestions.stream() .map(AiolQuestion::getId) .collect(Collectors.toList())) - .eq(AiolQuestionOption::getIzCorrent, 1) ); - - // 查询填空题的正确答案 + // 查询填空题简答题的答案 List questionAnswers = questionAnswerService.list( new LambdaQueryWrapper() .in(AiolQuestionAnswer::getQuestionId, - fillQuestions.stream() + fillAndEssayQuestions.stream() .map(AiolQuestion::getId) .collect(Collectors.toList())) ); + // 构建选择题选项映射:题目ID -> 选项列表 + Map> questionOptionMap = questionOptions.stream() + .collect(Collectors.groupingBy(AiolQuestionOption::getQuestionId)); - // 将选择题的正确选项转换为Map,结构为:题目ID -> 正确答案选项ID列表 - Map> correctAnswerMap = questionOptions.stream() - .collect(Collectors.groupingBy( - AiolQuestionOption::getQuestionId, - Collectors.mapping(AiolQuestionOption::getId, Collectors.toList()) - )); + // 构建填空题和简答题答案映射:题目ID -> 答案列表 + Map> questionAnswerMap = questionAnswers.stream() + .collect(Collectors.groupingBy(AiolQuestionAnswer::getQuestionId)); - // 将填空题的正确答案转换为Map,结构为:题目ID -> (空序号 -> 答案列表) - Map>> fillAnswerMap = questionAnswers.stream() - .collect(Collectors.groupingBy( - AiolQuestionAnswer::getQuestionId, - Collectors.groupingBy( - AiolQuestionAnswer::getOrderNo, - Collectors.mapping(AiolQuestionAnswer::getAnswerText, Collectors.toList()) - ) - )); - - // 遍历学生的答案,进行评分 - for (AiolExamAnswer examAnswer : examAnswerList) { - String studentAnswer = examAnswer.getAnswer(); - AiolQuestion question = questionMap.get(examAnswer.getQuestionId()); - - if (studentAnswer == null || question == null) { - examAnswer.setScore(0.0); - examAnswer.setIzCorrect(0); - continue; + // 合并到一个映射中 + Map> questionOrIdMap = new HashMap<>(); + questionOrIdMap.putAll(questionOptionMap); + questionOrIdMap.putAll(questionAnswerMap); + List 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 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); } - - List studentAnswers = Arrays.asList(studentAnswer.split(",")); - double score = 0.0; - - // 根据题目类型进行评分 - switch (question.getType()) { - case 0: // 单选题 - if (studentAnswers.get(0).equals(correctAnswerMap.get(question.getId()).get(0))) { - if (paper.getGenerateMode() == 0) { - score = questionScoreMap.get(question.getId()); - } else { - assert ruleJson != null; - score = ruleJson.getDouble("type" + question.getType() + "_score"); - } - } - break; - case 2: // 判断题 - if (studentAnswers.get(0).equals(correctAnswerMap.get(question.getId()).get(0))) { - if (paper.getGenerateMode() == 0) { - score = questionScoreMap.get(question.getId()); - } else { - assert ruleJson != null; - score = ruleJson.getDouble("type" + question.getType() + "_score"); - } - } - break; - - case 1: // 多选题 - List correctChoiceAnswers = correctAnswerMap.get(question.getId()); - if (correctChoiceAnswers != null && !correctChoiceAnswers.isEmpty()) { - // 检查学生答案是否包含错误选项 - boolean hasWrongAnswer = studentAnswers.stream() - .anyMatch(answer -> !correctChoiceAnswers.contains(answer)); - - // 如果有错选,直接得0分 - if (hasWrongAnswer) { - score = 0.0; - } - // 如果没有错选,检查是否全对 - else { - boolean allCorrect = new HashSet<>(studentAnswers).containsAll(correctChoiceAnswers); - boolean sameCount = studentAnswers.size() == correctChoiceAnswers.size(); - - if (allCorrect && sameCount) { - // 全对且数量正确,得满分 - if (paper.getGenerateMode() == 0) { - score = questionScoreMap.get(question.getId()); - } else { - assert ruleJson != null; - score = ruleJson.getDouble("type" + question.getType() + "_score"); - } - } else if (studentAnswers.size() < correctChoiceAnswers.size()) { - // 少选,得一半分数 - if (paper.getGenerateMode() == 0) { - score = questionScoreMap.get(question.getId()) * 0.5; - } else { - assert ruleJson != null; - score = ruleJson.getDouble("type" + question.getType() + "_score") * 0.5; - } - } - } - } - break; - - case 3: // 填空题 - Map> correctFillAnswers = fillAnswerMap.get(question.getId()); - if (correctFillAnswers != null && !correctFillAnswers.isEmpty()) { - int totalBlanks = correctFillAnswers.size(); - int correctBlanks = 0; - - // 检查每个空的答案 - for (int i = 0; i < studentAnswers.size() && i < totalBlanks; i++) { - int blankNumber = i + 1; - List correctBlankAnswers = correctFillAnswers.get(blankNumber); - if (correctBlankAnswers != null && correctBlankAnswers.contains(studentAnswers.get(i))) { - correctBlanks++; - } - } - - // 计算得分 - if (correctBlanks > 0) { - double fullScore; - if (paper.getGenerateMode() == 0) { - fullScore = questionScoreMap.get(question.getId()); - } else { - assert ruleJson != null; - fullScore = ruleJson.getDouble("type" + question.getType() + "_score"); - } - - // 按正确空的数量比例给分 - score = fullScore * ((double) correctBlanks / totalBlanks); - } - } - break; - } - examAnswer.setScore(score); - // 只有得了满分才算对 - examAnswer.setIzCorrect(score > 0 && score == (paper.getGenerateMode() == 0 ? - questionScoreMap.get(question.getId()) : - ruleJson.getDouble("type" + question.getType() + "_score")) ? 1 : 0); - } - - return examAnswerList; + examinationResultList.add(examinationResult); + }); + return Result.OK(examinationResultList); } - //获取设备信息 - public String getDeviceInfo(HttpServletRequest request) { - // 获取User-Agent - String userAgent = request.getHeader("User-Agent"); - // 解析设备信息 - String deviceInfo = parseDeviceInfo(userAgent); - return deviceInfo; - } - private String parseDeviceInfo(String userAgent) { - if (userAgent == null) { - return "Unknown"; - } - StringBuilder deviceInfo = new StringBuilder(); - // 判断操作系统 - if (userAgent.indexOf("Windows") > -1) { - deviceInfo.append("Windows"); - } else if (userAgent.indexOf("Mac") > -1) { - deviceInfo.append("Mac"); - } else if (userAgent.indexOf("X11") > -1) { - deviceInfo.append("Unix"); - } else if (userAgent.indexOf("Android") > -1) { - deviceInfo.append("Android"); - } else if (userAgent.indexOf("iPhone") > -1 || userAgent.indexOf("iPad") > -1) { - deviceInfo.append("iOS"); - } else { - deviceInfo.append("Unknown OS"); - } - deviceInfo.append(" | "); - // 判断浏览器 - if (userAgent.indexOf("MSIE") > -1) { - deviceInfo.append("MSIE"); - } else if (userAgent.indexOf("Firefox") > -1) { - deviceInfo.append("Firefox"); - } else if (userAgent.indexOf("Chrome") > -1) { - deviceInfo.append("Chrome"); - } else if (userAgent.indexOf("Safari") > -1) { - deviceInfo.append("Safari"); - } else if (userAgent.indexOf("Opera") > -1) { - deviceInfo.append("Opera"); - } else { - deviceInfo.append("Unknown Browser"); - } - // 可以添加更多设备信息的判断,如: - // 判断是否是移动设备 - boolean isMobile = userAgent.indexOf("Mobile") > -1 || - userAgent.indexOf("Android") > -1 || - userAgent.indexOf("iPhone") > -1; - deviceInfo.append(" | ").append(isMobile ? "Mobile" : "PC"); - return deviceInfo.toString(); - } +// //根据考试规则随机组卷 +// public List random(List list, String rules) { +// JSONObject ruleJson = JSON.parseObject(rules); +// +// // 根据规则筛选和随机抽取题目 +// Map> typeQuestions = new HashMap<>(); +// +// // 先按题目类型分组 +// list.forEach(qr -> { +// AiolQuestion question = questionService.getById(qr.getQuestionId()); +// if (!typeQuestions.containsKey(question.getType())) { +// typeQuestions.put(question.getType(), new ArrayList<>()); +// } +// typeQuestions.get(question.getType()).add(question.getId()); +// }); +// +// // 根据规则随机抽取题目 +// List questionIds = new ArrayList<>(); +// List compositeQuestions = new ArrayList<>(); // 存储复合题ID +// +// for (Integer type : typeQuestions.keySet()) { +// int count = ruleJson.getInteger("type" + type + "_count"); +// List typeQuestionIds = typeQuestions.get(type); +// +// // 随机抽取指定数量的题目 +// if (typeQuestionIds.size() <= count) { +// if (type == 5) { // 复合题先不添加,等处理完其他题目后再添加 +// compositeQuestions.addAll(typeQuestionIds); +// } else { +// questionIds.addAll(typeQuestionIds); +// } +// } else { +// // 打乱顺序后取前count个 +// Collections.shuffle(typeQuestionIds); +// List selectedQuestions = typeQuestionIds.subList(0, count); +// +// if (type == 5) { // 复合题先不添加,等处理完其他题目后再添加 +// compositeQuestions.addAll(selectedQuestions); +// } else { +// questionIds.addAll(selectedQuestions); +// } +// } +// } +// +// // 将复合题及其子题目添加到列表末尾 +// for (String compositeId : compositeQuestions) { +// questionIds.add(compositeId); +// // 获取并添加子题目ID +// questionService.list( +// new LambdaQueryWrapper() +// .eq(AiolQuestion::getParentId, compositeId) +// ).stream() +// .map(subQuestion -> subQuestion.getId().toString()) +// .forEach(questionIds::add); +// } +// +// return questionIds; +// } +// +// //获取ip信息 +// public String getClientIp(HttpServletRequest request) { +// String ip = request.getHeader("X-Forwarded-For"); +// +// if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { +// ip = request.getHeader("Proxy-Client-IP"); +// } +// if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { +// ip = request.getHeader("WL-Proxy-Client-IP"); +// } +// if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { +// ip = request.getHeader("HTTP_CLIENT_IP"); +// } +// if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { +// ip = request.getHeader("HTTP_X_FORWARDED_FOR"); +// } +// if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { +// ip = request.getRemoteAddr(); +// } +// // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 +// if (ip != null && ip.contains(",")) { +// ip = ip.split(",")[0].trim(); +// } +// return ip; +// } +// +// /** +// * 批量阅卷 +// * @param examId 考试ID +// * @param userId 用户ID +// * @return 阅卷后的答题列表 +// */ +// private List gradeExam(String examId, String userId) { +// //获取试卷信息 +// AiolExam exam = examService.getById(examId); +// //获取组卷信息 +// AiolPaper paper = paperService.getOne(new LambdaQueryWrapper().eq(AiolPaper::getId, exam.getPaperId())); +// if(paper == null){ +// throw new RuntimeException("试卷不存在"); +// } +// Map questionScoreMap = new HashMap<>(); +// JSONObject ruleJson = null; +// if(paper.getGenerateMode()==0){ +// List list = paperQuestionService.list(new LambdaQueryWrapper().eq(AiolPaperQuestion::getPaperId, paper.getId())); +// questionScoreMap = list.stream() +// .collect(Collectors.toMap( +// AiolPaperQuestion::getQuestionId, +// AiolPaperQuestion::getScore +// )); +// }else { +// ruleJson = JSON.parseObject(paper.getRules()); +// } +// // 获取学生的答题列表 +// List examAnswerList = examAnswerService.list( +// new LambdaQueryWrapper() +// .eq(AiolExamAnswer::getExamId, examId) +// .eq(AiolExamAnswer::getUserId, userId) +// ); +// +// // 提取所有题目ID +// List questionIds = examAnswerList.stream() +// .map(AiolExamAnswer::getQuestionId) +// .collect(Collectors.toList()); +// +// // 查询题目 +// List questions = questionService.list( +// new LambdaQueryWrapper() +// .in(AiolQuestion::getId, questionIds) +// .lt(AiolQuestion::getType, 4) +// ); +// +// // 创建题目ID到题目的映射 +// Map questionMap = questions.stream() +// .collect(Collectors.toMap(AiolQuestion::getId, question -> question)); +// +// // 按题目类型分组 +// Map> questionsByType = questions.stream() +// .collect(Collectors.groupingBy(AiolQuestion::getType)); +// +// // 分离选择题(0、1、2)和填空题(3) +// List choiceQuestions = questionsByType.entrySet().stream() +// .filter(entry -> entry.getKey() < 3) +// .flatMap(entry -> entry.getValue().stream()) +// .collect(Collectors.toList()); +// +// List fillQuestions = questionsByType.getOrDefault(3, new ArrayList<>()); +// +// // 查询题目的正确选项 +// List questionOptions = questionOptionService.list( +// new LambdaQueryWrapper() +// .in(AiolQuestionOption::getQuestionId, +// choiceQuestions.stream() +// .map(AiolQuestion::getId) +// .collect(Collectors.toList())) +// .eq(AiolQuestionOption::getIzCorrent, 1) +// ); +// +// // 查询填空题的正确答案 +// List questionAnswers = questionAnswerService.list( +// new LambdaQueryWrapper() +// .in(AiolQuestionAnswer::getQuestionId, +// fillQuestions.stream() +// .map(AiolQuestion::getId) +// .collect(Collectors.toList())) +// ); +// +// // 将选择题的正确选项转换为Map,结构为:题目ID -> 正确答案选项ID列表 +// Map> correctAnswerMap = questionOptions.stream() +// .collect(Collectors.groupingBy( +// AiolQuestionOption::getQuestionId, +// Collectors.mapping(AiolQuestionOption::getId, Collectors.toList()) +// )); +// +// // 将填空题的正确答案转换为Map,结构为:题目ID -> (空序号 -> 答案列表) +// Map>> fillAnswerMap = questionAnswers.stream() +// .collect(Collectors.groupingBy( +// AiolQuestionAnswer::getQuestionId, +// Collectors.groupingBy( +// AiolQuestionAnswer::getOrderNo, +// Collectors.mapping(AiolQuestionAnswer::getAnswerText, Collectors.toList()) +// ) +// )); +// +// // 遍历学生的答案,进行评分 +// for (AiolExamAnswer examAnswer : examAnswerList) { +// String studentAnswer = examAnswer.getAnswer(); +// AiolQuestion question = questionMap.get(examAnswer.getQuestionId()); +// +// if (studentAnswer == null || question == null) { +// examAnswer.setScore(0.0); +// examAnswer.setIzCorrect(0); +// continue; +// } +// +// List studentAnswers = Arrays.asList(studentAnswer.split(",")); +// double score = 0.0; +// +// // 根据题目类型进行评分 +// switch (question.getType()) { +// case 0: // 单选题 +// if (studentAnswers.get(0).equals(correctAnswerMap.get(question.getId()).get(0))) { +// if (paper.getGenerateMode() == 0) { +// score = questionScoreMap.get(question.getId()); +// } else { +// assert ruleJson != null; +// score = ruleJson.getDouble("type" + question.getType() + "_score"); +// } +// } +// break; +// case 2: // 判断题 +// if (studentAnswers.get(0).equals(correctAnswerMap.get(question.getId()).get(0))) { +// if (paper.getGenerateMode() == 0) { +// score = questionScoreMap.get(question.getId()); +// } else { +// assert ruleJson != null; +// score = ruleJson.getDouble("type" + question.getType() + "_score"); +// } +// } +// break; +// +// case 1: // 多选题 +// List correctChoiceAnswers = correctAnswerMap.get(question.getId()); +// if (correctChoiceAnswers != null && !correctChoiceAnswers.isEmpty()) { +// // 检查学生答案是否包含错误选项 +// boolean hasWrongAnswer = studentAnswers.stream() +// .anyMatch(answer -> !correctChoiceAnswers.contains(answer)); +// +// // 如果有错选,直接得0分 +// if (hasWrongAnswer) { +// score = 0.0; +// } +// // 如果没有错选,检查是否全对 +// else { +// boolean allCorrect = new HashSet<>(studentAnswers).containsAll(correctChoiceAnswers); +// boolean sameCount = studentAnswers.size() == correctChoiceAnswers.size(); +// +// if (allCorrect && sameCount) { +// // 全对且数量正确,得满分 +// if (paper.getGenerateMode() == 0) { +// score = questionScoreMap.get(question.getId()); +// } else { +// assert ruleJson != null; +// score = ruleJson.getDouble("type" + question.getType() + "_score"); +// } +// } else if (studentAnswers.size() < correctChoiceAnswers.size()) { +// // 少选,得一半分数 +// if (paper.getGenerateMode() == 0) { +// score = questionScoreMap.get(question.getId()) * 0.5; +// } else { +// assert ruleJson != null; +// score = ruleJson.getDouble("type" + question.getType() + "_score") * 0.5; +// } +// } +// } +// } +// break; +// +// case 3: // 填空题 +// Map> correctFillAnswers = fillAnswerMap.get(question.getId()); +// if (correctFillAnswers != null && !correctFillAnswers.isEmpty()) { +// int totalBlanks = correctFillAnswers.size(); +// int correctBlanks = 0; +// +// // 检查每个空的答案 +// for (int i = 0; i < studentAnswers.size() && i < totalBlanks; i++) { +// int blankNumber = i + 1; +// List correctBlankAnswers = correctFillAnswers.get(blankNumber); +// if (correctBlankAnswers != null && correctBlankAnswers.contains(studentAnswers.get(i))) { +// correctBlanks++; +// } +// } +// +// // 计算得分 +// if (correctBlanks > 0) { +// double fullScore; +// if (paper.getGenerateMode() == 0) { +// fullScore = questionScoreMap.get(question.getId()); +// } else { +// assert ruleJson != null; +// fullScore = ruleJson.getDouble("type" + question.getType() + "_score"); +// } +// +// // 按正确空的数量比例给分 +// score = fullScore * ((double) correctBlanks / totalBlanks); +// } +// } +// break; +// } +// examAnswer.setScore(score); +// // 只有得了满分才算对 +// examAnswer.setIzCorrect(score > 0 && score == (paper.getGenerateMode() == 0 ? +// questionScoreMap.get(question.getId()) : +// ruleJson.getDouble("type" + question.getType() + "_score")) ? 1 : 0); +// } +// +// return examAnswerList; +// } +// +// //获取设备信息 +// public String getDeviceInfo(HttpServletRequest request) { +// // 获取User-Agent +// String userAgent = request.getHeader("User-Agent"); +// // 解析设备信息 +// String deviceInfo = parseDeviceInfo(userAgent); +// return deviceInfo; +// } +// private String parseDeviceInfo(String userAgent) { +// if (userAgent == null) { +// return "Unknown"; +// } +// StringBuilder deviceInfo = new StringBuilder(); +// // 判断操作系统 +// if (userAgent.indexOf("Windows") > -1) { +// deviceInfo.append("Windows"); +// } else if (userAgent.indexOf("Mac") > -1) { +// deviceInfo.append("Mac"); +// } else if (userAgent.indexOf("X11") > -1) { +// deviceInfo.append("Unix"); +// } else if (userAgent.indexOf("Android") > -1) { +// deviceInfo.append("Android"); +// } else if (userAgent.indexOf("iPhone") > -1 || userAgent.indexOf("iPad") > -1) { +// deviceInfo.append("iOS"); +// } else { +// deviceInfo.append("Unknown OS"); +// } +// deviceInfo.append(" | "); +// // 判断浏览器 +// if (userAgent.indexOf("MSIE") > -1) { +// deviceInfo.append("MSIE"); +// } else if (userAgent.indexOf("Firefox") > -1) { +// deviceInfo.append("Firefox"); +// } else if (userAgent.indexOf("Chrome") > -1) { +// deviceInfo.append("Chrome"); +// } else if (userAgent.indexOf("Safari") > -1) { +// deviceInfo.append("Safari"); +// } else if (userAgent.indexOf("Opera") > -1) { +// deviceInfo.append("Opera"); +// } else { +// deviceInfo.append("Unknown Browser"); +// } +// // 可以添加更多设备信息的判断,如: +// // 判断是否是移动设备 +// boolean isMobile = userAgent.indexOf("Mobile") > -1 || +// userAgent.indexOf("Android") > -1 || +// userAgent.indexOf("iPhone") > -1; +// deviceInfo.append(" | ").append(isMobile ? "Mobile" : "PC"); +// return deviceInfo.toString(); +// } } diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-aiol/src/main/java/org/jeecg/modules/aiol/dto/ExaminationResult.java b/jeecg-boot/jeecg-boot-module/jeecg-module-aiol/src/main/java/org/jeecg/modules/aiol/dto/ExaminationResult.java new file mode 100644 index 00000000..763a53a8 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-aiol/src/main/java/org/jeecg/modules/aiol/dto/ExaminationResult.java @@ -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 children; +} From c4a6307b9ac2499862a6c4ccb0891bd598fa32e9 Mon Sep 17 00:00:00 2001 From: Lqc Date: Wed, 3 Sep 2025 15:27:40 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E5=BE=AE=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../aiol/controller/AiolExamController.java | 1540 ++++++++--------- 1 file changed, 770 insertions(+), 770 deletions(-) diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-aiol/src/main/java/org/jeecg/modules/aiol/controller/AiolExamController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-aiol/src/main/java/org/jeecg/modules/aiol/controller/AiolExamController.java index fad257b2..b5a340c6 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-aiol/src/main/java/org/jeecg/modules/aiol/controller/AiolExamController.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-aiol/src/main/java/org/jeecg/modules/aiol/controller/AiolExamController.java @@ -61,132 +61,132 @@ public class AiolExamController extends JeecgController> queryPageList(AiolExam aiolExam, -// @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, -// @RequestParam(name="pageSize", defaultValue="10") Integer pageSize, -// HttpServletRequest req) { -// -// -// QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(aiolExam, req.getParameterMap()); -// Page page = new Page(pageNo, pageSize); -// IPage pageList = aiolExamService.page(page, queryWrapper); -// return Result.OK(pageList); -// } -// -// /** -// * 添加 -// * -// * @param aiolExam -// * @return -// */ -// @AutoLog(value = "考试-添加") -// @Operation(summary="考试-添加") -// @RequiresPermissions("aiol:aiol_exam:add") -// @PostMapping(value = "/add") -// public Result add(@RequestBody AiolExam aiolExam) { -// aiolExamService.save(aiolExam); -// -// return Result.OK("添加成功!"); -// } -// -// /** -// * 编辑 -// * -// * @param aiolExam -// * @return -// */ -// @AutoLog(value = "考试-编辑") -// @Operation(summary="考试-编辑") -// @RequiresPermissions("aiol:aiol_exam:edit") -// @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) -// public Result edit(@RequestBody AiolExam aiolExam) { -// aiolExamService.updateById(aiolExam); -// return Result.OK("编辑成功!"); -// } -// -// /** -// * 通过id删除 -// * -// * @param id -// * @return -// */ -// @AutoLog(value = "考试-通过id删除") -// @Operation(summary="考试-通过id删除") -// @RequiresPermissions("aiol:aiol_exam:delete") -// @DeleteMapping(value = "/delete") -// public Result delete(@RequestParam(name="id",required=true) String id) { -// aiolExamService.removeById(id); -// return Result.OK("删除成功!"); -// } -// -// /** -// * 批量删除 -// * -// * @param ids -// * @return -// */ -// @AutoLog(value = "考试-批量删除") -// @Operation(summary="考试-批量删除") -// @RequiresPermissions("aiol:aiol_exam:deleteBatch") -// @DeleteMapping(value = "/deleteBatch") -// public Result deleteBatch(@RequestParam(name="ids",required=true) String ids) { -// this.aiolExamService.removeByIds(Arrays.asList(ids.split(","))); -// return Result.OK("批量删除成功!"); -// } -// -// /** -// * 通过id查询 -// * -// * @param id -// * @return -// */ -// //@AutoLog(value = "考试-通过id查询") -// @Operation(summary="考试-通过id查询") -// @GetMapping(value = "/queryById") -// public Result queryById(@RequestParam(name="id",required=true) String id) { -// AiolExam aiolExam = aiolExamService.getById(id); -// if(aiolExam==null) { -// return Result.error("未找到对应数据"); -// } -// return Result.OK(aiolExam); -// } -// -// /** -// * 导出excel -// * -// * @param request -// * @param aiolExam -// */ -// @RequiresPermissions("aiol:aiol_exam:exportXls") -// @RequestMapping(value = "/exportXls") -// public ModelAndView exportXls(HttpServletRequest request, AiolExam aiolExam) { -// return super.exportXls(request, aiolExam, AiolExam.class, "考试"); -// } -// -// /** -// * 通过excel导入数据 -// * -// * @param request -// * @param response -// * @return -// */ -// @RequiresPermissions("aiol:aiol_exam:importExcel") -// @RequestMapping(value = "/importExcel", method = RequestMethod.POST) -// public Result importExcel(HttpServletRequest request, HttpServletResponse response) { -// return super.importExcel(request, response, AiolExam.class); -// } + /** + * 分页列表查询 + * + * @param aiolExam + * @param pageNo + * @param pageSize + * @param req + * @return + */ + //@AutoLog(value = "考试-分页列表查询") + @Operation(summary="考试-分页列表查询") + @GetMapping(value = "/list") + public Result> queryPageList(AiolExam aiolExam, + @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, + @RequestParam(name="pageSize", defaultValue="10") Integer pageSize, + HttpServletRequest req) { + + + QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(aiolExam, req.getParameterMap()); + Page page = new Page(pageNo, pageSize); + IPage pageList = aiolExamService.page(page, queryWrapper); + return Result.OK(pageList); + } + + /** + * 添加 + * + * @param aiolExam + * @return + */ + @AutoLog(value = "考试-添加") + @Operation(summary="考试-添加") + @RequiresPermissions("aiol:aiol_exam:add") + @PostMapping(value = "/add") + public Result add(@RequestBody AiolExam aiolExam) { + aiolExamService.save(aiolExam); + + return Result.OK("添加成功!"); + } + + /** + * 编辑 + * + * @param aiolExam + * @return + */ + @AutoLog(value = "考试-编辑") + @Operation(summary="考试-编辑") + @RequiresPermissions("aiol:aiol_exam:edit") + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) + public Result edit(@RequestBody AiolExam aiolExam) { + aiolExamService.updateById(aiolExam); + return Result.OK("编辑成功!"); + } + + /** + * 通过id删除 + * + * @param id + * @return + */ + @AutoLog(value = "考试-通过id删除") + @Operation(summary="考试-通过id删除") + @RequiresPermissions("aiol:aiol_exam:delete") + @DeleteMapping(value = "/delete") + public Result delete(@RequestParam(name="id",required=true) String id) { + aiolExamService.removeById(id); + return Result.OK("删除成功!"); + } + + /** + * 批量删除 + * + * @param ids + * @return + */ + @AutoLog(value = "考试-批量删除") + @Operation(summary="考试-批量删除") + @RequiresPermissions("aiol:aiol_exam:deleteBatch") + @DeleteMapping(value = "/deleteBatch") + public Result deleteBatch(@RequestParam(name="ids",required=true) String ids) { + this.aiolExamService.removeByIds(Arrays.asList(ids.split(","))); + return Result.OK("批量删除成功!"); + } + + /** + * 通过id查询 + * + * @param id + * @return + */ + //@AutoLog(value = "考试-通过id查询") + @Operation(summary="考试-通过id查询") + @GetMapping(value = "/queryById") + public Result queryById(@RequestParam(name="id",required=true) String id) { + AiolExam aiolExam = aiolExamService.getById(id); + if(aiolExam==null) { + return Result.error("未找到对应数据"); + } + return Result.OK(aiolExam); + } + + /** + * 导出excel + * + * @param request + * @param aiolExam + */ + @RequiresPermissions("aiol:aiol_exam:exportXls") + @RequestMapping(value = "/exportXls") + public ModelAndView exportXls(HttpServletRequest request, AiolExam aiolExam) { + return super.exportXls(request, aiolExam, AiolExam.class, "考试"); + } + + /** + * 通过excel导入数据 + * + * @param request + * @param response + * @return + */ + @RequiresPermissions("aiol:aiol_exam:importExcel") + @RequestMapping(value = "/importExcel", method = RequestMethod.POST) + public Result importExcel(HttpServletRequest request, HttpServletResponse response) { + return super.importExcel(request, response, AiolExam.class); + } @Autowired private IAiolPaperService paperService; @@ -207,303 +207,303 @@ public class AiolExamController extends JeecgController getExamQuestions(@PathVariable String examId, @RequestParam String studentId) { -// AiolExam exam = examService.getById(examId); -// if(exam.getPaperId().isEmpty()){ -// return Result.error("考试未关联试卷"); -// } -// AiolPaper paper = paperService.getById(exam.getPaperId()); -// //题目id集合 -// List questionIds; -// List paperQuestions = new ArrayList<>(); -// //随机组卷 -// if(paper.getGenerateMode()==1){ -// List list = questionRepoService.list( -// new LambdaQueryWrapper(). -// eq(AiolQuestionRepo::getRepoId, paper.getRepoId()) -// ); -// //筛选试卷 -// questionIds = random(list, paper.getRules()); -// }else { -// //固定组卷 -// // 获取试卷中的试题关联信息 -// paperQuestions = paperQuestionService.getQuestions(paper.getId()); -// -// // 如果没有试题关联信息,直接返回空列表 -// if (CollectionUtils.isEmpty(paperQuestions)) { -// return Result.OK("试卷中没有试题"); -// } -// // 提取所有试题ID -// questionIds = paperQuestions.stream() -// .map(AiolPaperQuestion::getQuestionId) -// .collect(Collectors.toList()); -// } -// if (CollectionUtils.isEmpty(questionIds)) { -// return Result.OK("试卷中没有试题"); -// } -// // 从题目表查询试题内容 -// List questions = questionService.listByIds(questionIds); -// -// List sortedQuestions = questions; -// // 将固定试题内容按试卷中的顺序排序 -// if(paper.getGenerateMode()==0){ -// Map questionMap = questions.stream() -// .collect(Collectors.toMap(AiolQuestion::getId, question -> question)); -// sortedQuestions = paperQuestions.stream() -// .sorted(Comparator.comparing(AiolPaperQuestion::getOrderNo)) -// .map(paperQuestion -> questionMap.get(paperQuestion.getQuestionId())) -// .collect(Collectors.toList()); -// } -// //创建考试答题初始化记录 -// List examAnswerList = new ArrayList<>(); -// for (AiolQuestion resultQuestion : sortedQuestions) { -// AiolExamAnswer examAnswer = new AiolExamAnswer(); -// examAnswer.setExamId(examId); -// examAnswer.setUserId(studentId); -// if (resultQuestion != null && StringUtils.isNotEmpty(resultQuestion.getParentId())) { -// examAnswer.setParentQuestionId(resultQuestion.getParentId()); -// } -// examAnswer.setQuestionId(resultQuestion.getId()); -// examAnswerList.add(examAnswer); -// } -// examAnswerService.saveBatch(examAnswerList); -// //创建考试记录 -// AiolExamRecord examRecord = new AiolExamRecord(); -// examRecord.setExamId(examId); -// examRecord.setUserId(studentId); -// examRecord.setStatus(0); -// examRecordService.save(examRecord); -// // 返回排序后的试题总列表 -// return Result.OK(sortedQuestions); -// } -// -// @PostMapping("/submitAnswer") -// @Operation(summary = "提交答案") -// public Result submitAnswer(@RequestBody AiolExamAnswer examAnswer) { -// // 创建查询条件 -// LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); -// updateWrapper.eq(AiolExamAnswer::getExamId, examAnswer.getExamId()) -// .eq(AiolExamAnswer::getUserId, examAnswer.getUserId()) -// .eq(AiolExamAnswer::getQuestionId, examAnswer.getQuestionId()); -// -// // 更新答案 -// if (examAnswer.getAnswer() != null) { -// updateWrapper.set(AiolExamAnswer::getAnswer, examAnswer.getAnswer()); -// } -// // 执行更新 -// return examAnswerService.update(updateWrapper) ? Result.OK() : Result.error("提交答案失败"); -// } -// -// @PostMapping("/submitExam") -// @Operation(summary = "提交考试") -// @Transactional -// public Result submitExam(@RequestBody AiolExamRecord examRecord, -// HttpServletRequest req) { -// examRecord.setIpAddress(getClientIp(req)); -// examRecord.setDeviceInfo(getDeviceInfo(req)); -// //修改状态 -// examRecord.setStatus(1); -// // 创建更新条件 -// LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); -// updateWrapper.eq(AiolExamRecord::getExamId, examRecord.getExamId()) -// .eq(AiolExamRecord::getUserId, examRecord.getUserId()); -// // 更新ip -// if (examRecord.getIpAddress() != null) { -// updateWrapper.set(AiolExamRecord::getIpAddress, examRecord.getIpAddress()); -// } -// // 更新设备信息 -// if (examRecord.getDeviceInfo() != null) { -// updateWrapper.set(AiolExamRecord::getDeviceInfo, examRecord.getDeviceInfo()); -// } -// // 阅卷 -// List gradedAnswers = gradeExam(examRecord.getExamId(), examRecord.getUserId()); -// examAnswerService.updateBatchById(gradedAnswers); -// // 更新考试状态,提交时间 -// updateWrapper. -// set(AiolExamRecord::getStatus,1). -// set(AiolExamRecord::getSubmittedAt, new Date()); -// // 更新 -// return examRecordService.update(updateWrapper) ? Result.OK() : Result.error("提交考试失败"); -// } -// -// //获取名下考试信息 -// @GetMapping("/getExamInfo") -// @Operation(summary = "获取教师名下考试") -// public Result getExamInfo(@RequestParam String userId) { -// return Result.OK(examService.list(new LambdaQueryWrapper().eq(AiolExam::getCreateBy, userId))); -// } -// -// //获取考试相关答卷 -// @GetMapping("/getExamRecord") -// @Operation(summary = "获取考试相关答卷记录") -// public Result getExamRecord(@RequestParam String examId) { -// return Result.OK(examRecordService. -// list(new LambdaQueryWrapper(). -// eq(AiolExamRecord::getExamId, examId))); -// } -// -// //获取考试相关答卷 -// @GetMapping("/getExamRecordByUser") -// @Operation(summary = "获取考试相关答卷答案") -// public Result getExamRecordByUser(@RequestParam String examId,@RequestParam String userId) { -// List list = examAnswerService. -// list(new LambdaQueryWrapper(). -// eq(AiolExamAnswer::getExamId, examId). -// eq(AiolExamAnswer::getUserId, userId)); -// Map questionIdToAnswerMap = list.stream() -// .collect(Collectors.toMap( -// AiolExamAnswer::getQuestionId, -// answer -> answer -// )); -// if(!list.isEmpty()){ -// List questionIds = list.stream() -// .map(AiolExamAnswer::getQuestionId) -// .collect(Collectors.toList()); -// List questions = questionService.listByIds(questionIds); -// //取出简答题 -// List type4Questions = questions.stream() -// .filter(question -> question.getType() == 4) -// .collect(Collectors.toList()); -// Map questionIdToTitleMap = type4Questions.stream().collect(Collectors.toMap(AiolQuestion::getId, question -> question)); -// if(!type4Questions.isEmpty()){ -// List collect = type4Questions.stream().map(AiolQuestion::getId).collect(Collectors.toList()); -// //查询题目答案 -// List list1 = questionAnswerService.list(new LambdaQueryWrapper() -// .in(AiolQuestionAnswer::getQuestionId, collect) -// ); -// // 查询题目分数 -// AiolExam exam = examService.getById(examId); -// AiolPaper paper = paperService.getById(exam.getPaperId()); -// -// // 根据试卷生成模式获取分数 -// Map questionIdToScoreMap = Optional.ofNullable(paper) -// .filter(p -> p.getGenerateMode() == 0) -// .map(p -> paperQuestionService.list(new LambdaQueryWrapper() -// .eq(AiolPaperQuestion::getPaperId, p.getId()) -// .in(AiolPaperQuestion::getQuestionId, collect))) -// .orElse(Collections.emptyList()) -// .stream() -// .collect(Collectors.toMap( -// AiolPaperQuestion::getQuestionId, -// AiolPaperQuestion::getScore -// )); -// -// // 获取类型4的题目分数(仅在非固定模式下) -// Double type4Score = Optional.ofNullable(paper) -// .filter(p -> p.getGenerateMode() != 0) -// .map(p -> JSON.parseObject(p.getRules()).getDouble("type4_score")) -// .orElse(0.0); -// -// // 构建用户答案列表 -// List questionAnswerUserList = list1.stream() -// .map(questionAnswer -> { -// QuestionAnswerUser questionAnswerUser = new QuestionAnswerUser(); -// questionAnswerUser.setQuestion(questionIdToTitleMap.get(questionAnswer.getQuestionId())); -// questionAnswerUser.setUserAnswer(questionIdToAnswerMap.get(questionAnswer.getQuestionId())); -// questionAnswerUser.setAnswer(questionAnswer); -// questionAnswerUser.setFullMark(questionIdToScoreMap.getOrDefault( -// questionAnswer.getQuestionId(), -// type4Score -// )); -// return questionAnswerUser; -// }) -// .collect(Collectors.toList()); -// return Result.OK(questionAnswerUserList); -// } -// } -// return Result.OK("没有需要批改的题目数据"); -// } -// -// @PostMapping("/submitGrade") -// @Operation(summary = "提交批改") -// @Transactional -// public Result submitGrade(@RequestBody List examAnswers) { -// // 检查输入参数是否为空 -// if (CollectionUtils.isEmpty(examAnswers)) { -// return Result.error("批改数据不能为空"); -// } -// try { -// String examId = examAnswers.get(0).getExamId(); -// String userId = examAnswers.get(0).getUserId(); -// List list = examAnswerService.list(new LambdaQueryWrapper() -// .eq(AiolExamAnswer::getExamId, examId) -// .eq(AiolExamAnswer::getUserId, userId)); -// // 创建examAnswers的ID映射,方便查找 -// Map examAnswerMap = examAnswers.stream() -// .collect(Collectors.toMap(AiolExamAnswer::getId, answer -> answer)); -// // 创建list的id映射 -// Map listIdMap = list.stream() -// .collect(Collectors.toMap(AiolExamAnswer::getQuestionId, answer -> answer)); -// //计算总分 -// Double totalScore = list.stream().mapToDouble(AiolExamAnswer::getScore).sum() + examAnswers.stream().mapToDouble(AiolExamAnswer::getScore).sum(); -// -// // 复合题对错得分 -// List sonList = list.stream() -// .filter(answer -> answer.getParentQuestionId() != null && !answer.getParentQuestionId().isEmpty()) -// .collect(Collectors.toList()); -// -// if (!sonList.isEmpty()) { -// // 按父ID分组 -// Map> parentGroup = sonList.stream() -// .collect(Collectors.groupingBy(AiolExamAnswer::getParentQuestionId)); -// -// // 遍历每个父题组 -// for (Map.Entry> entry : parentGroup.entrySet()) { -// String parentId = entry.getKey(); -// List children = entry.getValue(); -// -// Double parentScore = 0.0; -// boolean isCorrect = true; -// -// // 计算每个子题的分数和正确性 -// for (AiolExamAnswer childAnswer : children) { -// Double sonScore = 0.0; -// if (examAnswerMap.get(childAnswer.getId()) != null) { -// if (isCorrect && examAnswerMap.get(childAnswer.getId()).getIzCorrect() == 0) { -// isCorrect = false; -// } -// sonScore = examAnswerMap.get(childAnswer.getId()).getScore(); -// } else { -// if (isCorrect && childAnswer.getIzCorrect() == 0) { -// isCorrect = false; -// } -// sonScore = childAnswer.getScore(); -// } -// parentScore += sonScore; -// } -// -// // 更新父题的分数和正确性 -// AiolExamAnswer parentAnswer = listIdMap.get(parentId); -// if (parentAnswer != null) { -// parentAnswer.setIzCorrect(isCorrect ? 1 : 0); -// parentAnswer.setScore(parentScore); -// examAnswers.add(parentAnswer); -// } -// } -// } -// // 更新考试记录的状态为已批改 -// examRecordService.update(new LambdaUpdateWrapper() -// .set(AiolExamRecord::getStatus, 2) -// .set(AiolExamRecord::getTotalScore, totalScore) -// .eq(AiolExamRecord::getExamId, examId) -// .eq(AiolExamRecord::getUserId, userId)); -// // 批量更新答题分数 -// boolean success = examAnswerService.updateBatchById(examAnswers); -// if (!success) { -// return Result.error("批改失败"); -// } -// // 可选:更新考试的总分和平均分(如果需要) -// // 这里可以添加额外的业务逻辑 -// return Result.OK("批改成功"); -// } catch (Exception e) { -// log.error("提交批改失败", e); -// return Result.error("系统错误:" + e.getMessage()); -// } -// } + //获取考试试题 + @RequestMapping("/getExamQuestions/{examId}") + @Operation(summary = "获取考试试题") + @Transactional + public Result getExamQuestions(@PathVariable String examId, @RequestParam String studentId) { + AiolExam exam = examService.getById(examId); + if(exam.getPaperId().isEmpty()){ + return Result.error("考试未关联试卷"); + } + AiolPaper paper = paperService.getById(exam.getPaperId()); + //题目id集合 + List questionIds; + List paperQuestions = new ArrayList<>(); + //随机组卷 + if(paper.getGenerateMode()==1){ + List list = questionRepoService.list( + new LambdaQueryWrapper(). + eq(AiolQuestionRepo::getRepoId, paper.getRepoId()) + ); + //筛选试卷 + questionIds = random(list, paper.getRules()); + }else { + //固定组卷 + // 获取试卷中的试题关联信息 + paperQuestions = paperQuestionService.getQuestions(paper.getId()); + + // 如果没有试题关联信息,直接返回空列表 + if (CollectionUtils.isEmpty(paperQuestions)) { + return Result.OK("试卷中没有试题"); + } + // 提取所有试题ID + questionIds = paperQuestions.stream() + .map(AiolPaperQuestion::getQuestionId) + .collect(Collectors.toList()); + } + if (CollectionUtils.isEmpty(questionIds)) { + return Result.OK("试卷中没有试题"); + } + // 从题目表查询试题内容 + List questions = questionService.listByIds(questionIds); + + List sortedQuestions = questions; + // 将固定试题内容按试卷中的顺序排序 + if(paper.getGenerateMode()==0){ + Map questionMap = questions.stream() + .collect(Collectors.toMap(AiolQuestion::getId, question -> question)); + sortedQuestions = paperQuestions.stream() + .sorted(Comparator.comparing(AiolPaperQuestion::getOrderNo)) + .map(paperQuestion -> questionMap.get(paperQuestion.getQuestionId())) + .collect(Collectors.toList()); + } + //创建考试答题初始化记录 + List examAnswerList = new ArrayList<>(); + for (AiolQuestion resultQuestion : sortedQuestions) { + AiolExamAnswer examAnswer = new AiolExamAnswer(); + examAnswer.setExamId(examId); + examAnswer.setUserId(studentId); + if (resultQuestion != null && StringUtils.isNotEmpty(resultQuestion.getParentId())) { + examAnswer.setParentQuestionId(resultQuestion.getParentId()); + } + examAnswer.setQuestionId(resultQuestion.getId()); + examAnswerList.add(examAnswer); + } + examAnswerService.saveBatch(examAnswerList); + //创建考试记录 + AiolExamRecord examRecord = new AiolExamRecord(); + examRecord.setExamId(examId); + examRecord.setUserId(studentId); + examRecord.setStatus(0); + examRecordService.save(examRecord); + // 返回排序后的试题总列表 + return Result.OK(sortedQuestions); + } + + @PostMapping("/submitAnswer") + @Operation(summary = "提交答案") + public Result submitAnswer(@RequestBody AiolExamAnswer examAnswer) { + // 创建查询条件 + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.eq(AiolExamAnswer::getExamId, examAnswer.getExamId()) + .eq(AiolExamAnswer::getUserId, examAnswer.getUserId()) + .eq(AiolExamAnswer::getQuestionId, examAnswer.getQuestionId()); + + // 更新答案 + if (examAnswer.getAnswer() != null) { + updateWrapper.set(AiolExamAnswer::getAnswer, examAnswer.getAnswer()); + } + // 执行更新 + return examAnswerService.update(updateWrapper) ? Result.OK() : Result.error("提交答案失败"); + } + + @PostMapping("/submitExam") + @Operation(summary = "提交考试") + @Transactional + public Result submitExam(@RequestBody AiolExamRecord examRecord, + HttpServletRequest req) { + examRecord.setIpAddress(getClientIp(req)); + examRecord.setDeviceInfo(getDeviceInfo(req)); + //修改状态 + examRecord.setStatus(1); + // 创建更新条件 + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.eq(AiolExamRecord::getExamId, examRecord.getExamId()) + .eq(AiolExamRecord::getUserId, examRecord.getUserId()); + // 更新ip + if (examRecord.getIpAddress() != null) { + updateWrapper.set(AiolExamRecord::getIpAddress, examRecord.getIpAddress()); + } + // 更新设备信息 + if (examRecord.getDeviceInfo() != null) { + updateWrapper.set(AiolExamRecord::getDeviceInfo, examRecord.getDeviceInfo()); + } + // 阅卷 + List gradedAnswers = gradeExam(examRecord.getExamId(), examRecord.getUserId()); + examAnswerService.updateBatchById(gradedAnswers); + // 更新考试状态,提交时间 + updateWrapper. + set(AiolExamRecord::getStatus,1). + set(AiolExamRecord::getSubmittedAt, new Date()); + // 更新 + return examRecordService.update(updateWrapper) ? Result.OK() : Result.error("提交考试失败"); + } + + //获取名下考试信息 + @GetMapping("/getExamInfo") + @Operation(summary = "获取教师名下考试") + public Result getExamInfo(@RequestParam String userId) { + return Result.OK(examService.list(new LambdaQueryWrapper().eq(AiolExam::getCreateBy, userId))); + } + + //获取考试相关答卷 + @GetMapping("/getExamRecord") + @Operation(summary = "获取考试相关答卷记录") + public Result getExamRecord(@RequestParam String examId) { + return Result.OK(examRecordService. + list(new LambdaQueryWrapper(). + eq(AiolExamRecord::getExamId, examId))); + } + + //获取考试相关答卷 + @GetMapping("/getExamRecordByUser") + @Operation(summary = "获取考试相关答卷答案") + public Result getExamRecordByUser(@RequestParam String examId,@RequestParam String userId) { + List list = examAnswerService. + list(new LambdaQueryWrapper(). + eq(AiolExamAnswer::getExamId, examId). + eq(AiolExamAnswer::getUserId, userId)); + Map questionIdToAnswerMap = list.stream() + .collect(Collectors.toMap( + AiolExamAnswer::getQuestionId, + answer -> answer + )); + if(!list.isEmpty()){ + List questionIds = list.stream() + .map(AiolExamAnswer::getQuestionId) + .collect(Collectors.toList()); + List questions = questionService.listByIds(questionIds); + //取出简答题 + List type4Questions = questions.stream() + .filter(question -> question.getType() == 4) + .collect(Collectors.toList()); + Map questionIdToTitleMap = type4Questions.stream().collect(Collectors.toMap(AiolQuestion::getId, question -> question)); + if(!type4Questions.isEmpty()){ + List collect = type4Questions.stream().map(AiolQuestion::getId).collect(Collectors.toList()); + //查询题目答案 + List list1 = questionAnswerService.list(new LambdaQueryWrapper() + .in(AiolQuestionAnswer::getQuestionId, collect) + ); + // 查询题目分数 + AiolExam exam = examService.getById(examId); + AiolPaper paper = paperService.getById(exam.getPaperId()); + + // 根据试卷生成模式获取分数 + Map questionIdToScoreMap = Optional.ofNullable(paper) + .filter(p -> p.getGenerateMode() == 0) + .map(p -> paperQuestionService.list(new LambdaQueryWrapper() + .eq(AiolPaperQuestion::getPaperId, p.getId()) + .in(AiolPaperQuestion::getQuestionId, collect))) + .orElse(Collections.emptyList()) + .stream() + .collect(Collectors.toMap( + AiolPaperQuestion::getQuestionId, + AiolPaperQuestion::getScore + )); + + // 获取类型4的题目分数(仅在非固定模式下) + Double type4Score = Optional.ofNullable(paper) + .filter(p -> p.getGenerateMode() != 0) + .map(p -> JSON.parseObject(p.getRules()).getDouble("type4_score")) + .orElse(0.0); + + // 构建用户答案列表 + List questionAnswerUserList = list1.stream() + .map(questionAnswer -> { + QuestionAnswerUser questionAnswerUser = new QuestionAnswerUser(); + questionAnswerUser.setQuestion(questionIdToTitleMap.get(questionAnswer.getQuestionId())); + questionAnswerUser.setUserAnswer(questionIdToAnswerMap.get(questionAnswer.getQuestionId())); + questionAnswerUser.setAnswer(questionAnswer); + questionAnswerUser.setFullMark(questionIdToScoreMap.getOrDefault( + questionAnswer.getQuestionId(), + type4Score + )); + return questionAnswerUser; + }) + .collect(Collectors.toList()); + return Result.OK(questionAnswerUserList); + } + } + return Result.OK("没有需要批改的题目数据"); + } + + @PostMapping("/submitGrade") + @Operation(summary = "提交批改") + @Transactional + public Result submitGrade(@RequestBody List examAnswers) { + // 检查输入参数是否为空 + if (CollectionUtils.isEmpty(examAnswers)) { + return Result.error("批改数据不能为空"); + } + try { + String examId = examAnswers.get(0).getExamId(); + String userId = examAnswers.get(0).getUserId(); + List list = examAnswerService.list(new LambdaQueryWrapper() + .eq(AiolExamAnswer::getExamId, examId) + .eq(AiolExamAnswer::getUserId, userId)); + // 创建examAnswers的ID映射,方便查找 + Map examAnswerMap = examAnswers.stream() + .collect(Collectors.toMap(AiolExamAnswer::getId, answer -> answer)); + // 创建list的id映射 + Map listIdMap = list.stream() + .collect(Collectors.toMap(AiolExamAnswer::getQuestionId, answer -> answer)); + //计算总分 + Double totalScore = list.stream().mapToDouble(AiolExamAnswer::getScore).sum() + examAnswers.stream().mapToDouble(AiolExamAnswer::getScore).sum(); + + // 复合题对错得分 + List sonList = list.stream() + .filter(answer -> answer.getParentQuestionId() != null && !answer.getParentQuestionId().isEmpty()) + .collect(Collectors.toList()); + + if (!sonList.isEmpty()) { + // 按父ID分组 + Map> parentGroup = sonList.stream() + .collect(Collectors.groupingBy(AiolExamAnswer::getParentQuestionId)); + + // 遍历每个父题组 + for (Map.Entry> entry : parentGroup.entrySet()) { + String parentId = entry.getKey(); + List children = entry.getValue(); + + Double parentScore = 0.0; + boolean isCorrect = true; + + // 计算每个子题的分数和正确性 + for (AiolExamAnswer childAnswer : children) { + Double sonScore = 0.0; + if (examAnswerMap.get(childAnswer.getId()) != null) { + if (isCorrect && examAnswerMap.get(childAnswer.getId()).getIzCorrect() == 0) { + isCorrect = false; + } + sonScore = examAnswerMap.get(childAnswer.getId()).getScore(); + } else { + if (isCorrect && childAnswer.getIzCorrect() == 0) { + isCorrect = false; + } + sonScore = childAnswer.getScore(); + } + parentScore += sonScore; + } + + // 更新父题的分数和正确性 + AiolExamAnswer parentAnswer = listIdMap.get(parentId); + if (parentAnswer != null) { + parentAnswer.setIzCorrect(isCorrect ? 1 : 0); + parentAnswer.setScore(parentScore); + examAnswers.add(parentAnswer); + } + } + } + // 更新考试记录的状态为已批改 + examRecordService.update(new LambdaUpdateWrapper() + .set(AiolExamRecord::getStatus, 2) + .set(AiolExamRecord::getTotalScore, totalScore) + .eq(AiolExamRecord::getExamId, examId) + .eq(AiolExamRecord::getUserId, userId)); + // 批量更新答题分数 + boolean success = examAnswerService.updateBatchById(examAnswers); + if (!success) { + return Result.error("批改失败"); + } + // 可选:更新考试的总分和平均分(如果需要) + // 这里可以添加额外的业务逻辑 + return Result.OK("批改成功"); + } catch (Exception e) { + log.error("提交批改失败", e); + return Result.error("系统错误:" + e.getMessage()); + } + } @@ -649,351 +649,351 @@ public class AiolExamController extends JeecgController random(List list, String rules) { -// JSONObject ruleJson = JSON.parseObject(rules); -// -// // 根据规则筛选和随机抽取题目 -// Map> typeQuestions = new HashMap<>(); -// -// // 先按题目类型分组 -// list.forEach(qr -> { -// AiolQuestion question = questionService.getById(qr.getQuestionId()); -// if (!typeQuestions.containsKey(question.getType())) { -// typeQuestions.put(question.getType(), new ArrayList<>()); -// } -// typeQuestions.get(question.getType()).add(question.getId()); -// }); -// -// // 根据规则随机抽取题目 -// List questionIds = new ArrayList<>(); -// List compositeQuestions = new ArrayList<>(); // 存储复合题ID -// -// for (Integer type : typeQuestions.keySet()) { -// int count = ruleJson.getInteger("type" + type + "_count"); -// List typeQuestionIds = typeQuestions.get(type); -// -// // 随机抽取指定数量的题目 -// if (typeQuestionIds.size() <= count) { -// if (type == 5) { // 复合题先不添加,等处理完其他题目后再添加 -// compositeQuestions.addAll(typeQuestionIds); -// } else { -// questionIds.addAll(typeQuestionIds); -// } -// } else { -// // 打乱顺序后取前count个 -// Collections.shuffle(typeQuestionIds); -// List selectedQuestions = typeQuestionIds.subList(0, count); -// -// if (type == 5) { // 复合题先不添加,等处理完其他题目后再添加 -// compositeQuestions.addAll(selectedQuestions); -// } else { -// questionIds.addAll(selectedQuestions); -// } -// } -// } -// -// // 将复合题及其子题目添加到列表末尾 -// for (String compositeId : compositeQuestions) { -// questionIds.add(compositeId); -// // 获取并添加子题目ID -// questionService.list( -// new LambdaQueryWrapper() -// .eq(AiolQuestion::getParentId, compositeId) -// ).stream() -// .map(subQuestion -> subQuestion.getId().toString()) -// .forEach(questionIds::add); -// } -// -// return questionIds; -// } -// -// //获取ip信息 -// public String getClientIp(HttpServletRequest request) { -// String ip = request.getHeader("X-Forwarded-For"); -// -// if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { -// ip = request.getHeader("Proxy-Client-IP"); -// } -// if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { -// ip = request.getHeader("WL-Proxy-Client-IP"); -// } -// if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { -// ip = request.getHeader("HTTP_CLIENT_IP"); -// } -// if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { -// ip = request.getHeader("HTTP_X_FORWARDED_FOR"); -// } -// if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { -// ip = request.getRemoteAddr(); -// } -// // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 -// if (ip != null && ip.contains(",")) { -// ip = ip.split(",")[0].trim(); -// } -// return ip; -// } -// -// /** -// * 批量阅卷 -// * @param examId 考试ID -// * @param userId 用户ID -// * @return 阅卷后的答题列表 -// */ -// private List gradeExam(String examId, String userId) { -// //获取试卷信息 -// AiolExam exam = examService.getById(examId); -// //获取组卷信息 -// AiolPaper paper = paperService.getOne(new LambdaQueryWrapper().eq(AiolPaper::getId, exam.getPaperId())); -// if(paper == null){ -// throw new RuntimeException("试卷不存在"); -// } -// Map questionScoreMap = new HashMap<>(); -// JSONObject ruleJson = null; -// if(paper.getGenerateMode()==0){ -// List list = paperQuestionService.list(new LambdaQueryWrapper().eq(AiolPaperQuestion::getPaperId, paper.getId())); -// questionScoreMap = list.stream() -// .collect(Collectors.toMap( -// AiolPaperQuestion::getQuestionId, -// AiolPaperQuestion::getScore -// )); -// }else { -// ruleJson = JSON.parseObject(paper.getRules()); -// } -// // 获取学生的答题列表 -// List examAnswerList = examAnswerService.list( -// new LambdaQueryWrapper() -// .eq(AiolExamAnswer::getExamId, examId) -// .eq(AiolExamAnswer::getUserId, userId) -// ); -// -// // 提取所有题目ID -// List questionIds = examAnswerList.stream() -// .map(AiolExamAnswer::getQuestionId) -// .collect(Collectors.toList()); -// -// // 查询题目 -// List questions = questionService.list( -// new LambdaQueryWrapper() -// .in(AiolQuestion::getId, questionIds) -// .lt(AiolQuestion::getType, 4) -// ); -// -// // 创建题目ID到题目的映射 -// Map questionMap = questions.stream() -// .collect(Collectors.toMap(AiolQuestion::getId, question -> question)); -// -// // 按题目类型分组 -// Map> questionsByType = questions.stream() -// .collect(Collectors.groupingBy(AiolQuestion::getType)); -// -// // 分离选择题(0、1、2)和填空题(3) -// List choiceQuestions = questionsByType.entrySet().stream() -// .filter(entry -> entry.getKey() < 3) -// .flatMap(entry -> entry.getValue().stream()) -// .collect(Collectors.toList()); -// -// List fillQuestions = questionsByType.getOrDefault(3, new ArrayList<>()); -// -// // 查询题目的正确选项 -// List questionOptions = questionOptionService.list( -// new LambdaQueryWrapper() -// .in(AiolQuestionOption::getQuestionId, -// choiceQuestions.stream() -// .map(AiolQuestion::getId) -// .collect(Collectors.toList())) -// .eq(AiolQuestionOption::getIzCorrent, 1) -// ); -// -// // 查询填空题的正确答案 -// List questionAnswers = questionAnswerService.list( -// new LambdaQueryWrapper() -// .in(AiolQuestionAnswer::getQuestionId, -// fillQuestions.stream() -// .map(AiolQuestion::getId) -// .collect(Collectors.toList())) -// ); -// -// // 将选择题的正确选项转换为Map,结构为:题目ID -> 正确答案选项ID列表 -// Map> correctAnswerMap = questionOptions.stream() -// .collect(Collectors.groupingBy( -// AiolQuestionOption::getQuestionId, -// Collectors.mapping(AiolQuestionOption::getId, Collectors.toList()) -// )); -// -// // 将填空题的正确答案转换为Map,结构为:题目ID -> (空序号 -> 答案列表) -// Map>> fillAnswerMap = questionAnswers.stream() -// .collect(Collectors.groupingBy( -// AiolQuestionAnswer::getQuestionId, -// Collectors.groupingBy( -// AiolQuestionAnswer::getOrderNo, -// Collectors.mapping(AiolQuestionAnswer::getAnswerText, Collectors.toList()) -// ) -// )); -// -// // 遍历学生的答案,进行评分 -// for (AiolExamAnswer examAnswer : examAnswerList) { -// String studentAnswer = examAnswer.getAnswer(); -// AiolQuestion question = questionMap.get(examAnswer.getQuestionId()); -// -// if (studentAnswer == null || question == null) { -// examAnswer.setScore(0.0); -// examAnswer.setIzCorrect(0); -// continue; -// } -// -// List studentAnswers = Arrays.asList(studentAnswer.split(",")); -// double score = 0.0; -// -// // 根据题目类型进行评分 -// switch (question.getType()) { -// case 0: // 单选题 -// if (studentAnswers.get(0).equals(correctAnswerMap.get(question.getId()).get(0))) { -// if (paper.getGenerateMode() == 0) { -// score = questionScoreMap.get(question.getId()); -// } else { -// assert ruleJson != null; -// score = ruleJson.getDouble("type" + question.getType() + "_score"); -// } -// } -// break; -// case 2: // 判断题 -// if (studentAnswers.get(0).equals(correctAnswerMap.get(question.getId()).get(0))) { -// if (paper.getGenerateMode() == 0) { -// score = questionScoreMap.get(question.getId()); -// } else { -// assert ruleJson != null; -// score = ruleJson.getDouble("type" + question.getType() + "_score"); -// } -// } -// break; -// -// case 1: // 多选题 -// List correctChoiceAnswers = correctAnswerMap.get(question.getId()); -// if (correctChoiceAnswers != null && !correctChoiceAnswers.isEmpty()) { -// // 检查学生答案是否包含错误选项 -// boolean hasWrongAnswer = studentAnswers.stream() -// .anyMatch(answer -> !correctChoiceAnswers.contains(answer)); -// -// // 如果有错选,直接得0分 -// if (hasWrongAnswer) { -// score = 0.0; -// } -// // 如果没有错选,检查是否全对 -// else { -// boolean allCorrect = new HashSet<>(studentAnswers).containsAll(correctChoiceAnswers); -// boolean sameCount = studentAnswers.size() == correctChoiceAnswers.size(); -// -// if (allCorrect && sameCount) { -// // 全对且数量正确,得满分 -// if (paper.getGenerateMode() == 0) { -// score = questionScoreMap.get(question.getId()); -// } else { -// assert ruleJson != null; -// score = ruleJson.getDouble("type" + question.getType() + "_score"); -// } -// } else if (studentAnswers.size() < correctChoiceAnswers.size()) { -// // 少选,得一半分数 -// if (paper.getGenerateMode() == 0) { -// score = questionScoreMap.get(question.getId()) * 0.5; -// } else { -// assert ruleJson != null; -// score = ruleJson.getDouble("type" + question.getType() + "_score") * 0.5; -// } -// } -// } -// } -// break; -// -// case 3: // 填空题 -// Map> correctFillAnswers = fillAnswerMap.get(question.getId()); -// if (correctFillAnswers != null && !correctFillAnswers.isEmpty()) { -// int totalBlanks = correctFillAnswers.size(); -// int correctBlanks = 0; -// -// // 检查每个空的答案 -// for (int i = 0; i < studentAnswers.size() && i < totalBlanks; i++) { -// int blankNumber = i + 1; -// List correctBlankAnswers = correctFillAnswers.get(blankNumber); -// if (correctBlankAnswers != null && correctBlankAnswers.contains(studentAnswers.get(i))) { -// correctBlanks++; -// } -// } -// -// // 计算得分 -// if (correctBlanks > 0) { -// double fullScore; -// if (paper.getGenerateMode() == 0) { -// fullScore = questionScoreMap.get(question.getId()); -// } else { -// assert ruleJson != null; -// fullScore = ruleJson.getDouble("type" + question.getType() + "_score"); -// } -// -// // 按正确空的数量比例给分 -// score = fullScore * ((double) correctBlanks / totalBlanks); -// } -// } -// break; -// } -// examAnswer.setScore(score); -// // 只有得了满分才算对 -// examAnswer.setIzCorrect(score > 0 && score == (paper.getGenerateMode() == 0 ? -// questionScoreMap.get(question.getId()) : -// ruleJson.getDouble("type" + question.getType() + "_score")) ? 1 : 0); -// } -// -// return examAnswerList; -// } -// -// //获取设备信息 -// public String getDeviceInfo(HttpServletRequest request) { -// // 获取User-Agent -// String userAgent = request.getHeader("User-Agent"); -// // 解析设备信息 -// String deviceInfo = parseDeviceInfo(userAgent); -// return deviceInfo; -// } -// private String parseDeviceInfo(String userAgent) { -// if (userAgent == null) { -// return "Unknown"; -// } -// StringBuilder deviceInfo = new StringBuilder(); -// // 判断操作系统 -// if (userAgent.indexOf("Windows") > -1) { -// deviceInfo.append("Windows"); -// } else if (userAgent.indexOf("Mac") > -1) { -// deviceInfo.append("Mac"); -// } else if (userAgent.indexOf("X11") > -1) { -// deviceInfo.append("Unix"); -// } else if (userAgent.indexOf("Android") > -1) { -// deviceInfo.append("Android"); -// } else if (userAgent.indexOf("iPhone") > -1 || userAgent.indexOf("iPad") > -1) { -// deviceInfo.append("iOS"); -// } else { -// deviceInfo.append("Unknown OS"); -// } -// deviceInfo.append(" | "); -// // 判断浏览器 -// if (userAgent.indexOf("MSIE") > -1) { -// deviceInfo.append("MSIE"); -// } else if (userAgent.indexOf("Firefox") > -1) { -// deviceInfo.append("Firefox"); -// } else if (userAgent.indexOf("Chrome") > -1) { -// deviceInfo.append("Chrome"); -// } else if (userAgent.indexOf("Safari") > -1) { -// deviceInfo.append("Safari"); -// } else if (userAgent.indexOf("Opera") > -1) { -// deviceInfo.append("Opera"); -// } else { -// deviceInfo.append("Unknown Browser"); -// } -// // 可以添加更多设备信息的判断,如: -// // 判断是否是移动设备 -// boolean isMobile = userAgent.indexOf("Mobile") > -1 || -// userAgent.indexOf("Android") > -1 || -// userAgent.indexOf("iPhone") > -1; -// deviceInfo.append(" | ").append(isMobile ? "Mobile" : "PC"); -// return deviceInfo.toString(); -// } + //根据考试规则随机组卷 + public List random(List list, String rules) { + JSONObject ruleJson = JSON.parseObject(rules); + + // 根据规则筛选和随机抽取题目 + Map> typeQuestions = new HashMap<>(); + + // 先按题目类型分组 + list.forEach(qr -> { + AiolQuestion question = questionService.getById(qr.getQuestionId()); + if (!typeQuestions.containsKey(question.getType())) { + typeQuestions.put(question.getType(), new ArrayList<>()); + } + typeQuestions.get(question.getType()).add(question.getId()); + }); + + // 根据规则随机抽取题目 + List questionIds = new ArrayList<>(); + List compositeQuestions = new ArrayList<>(); // 存储复合题ID + + for (Integer type : typeQuestions.keySet()) { + int count = ruleJson.getInteger("type" + type + "_count"); + List typeQuestionIds = typeQuestions.get(type); + + // 随机抽取指定数量的题目 + if (typeQuestionIds.size() <= count) { + if (type == 5) { // 复合题先不添加,等处理完其他题目后再添加 + compositeQuestions.addAll(typeQuestionIds); + } else { + questionIds.addAll(typeQuestionIds); + } + } else { + // 打乱顺序后取前count个 + Collections.shuffle(typeQuestionIds); + List selectedQuestions = typeQuestionIds.subList(0, count); + + if (type == 5) { // 复合题先不添加,等处理完其他题目后再添加 + compositeQuestions.addAll(selectedQuestions); + } else { + questionIds.addAll(selectedQuestions); + } + } + } + + // 将复合题及其子题目添加到列表末尾 + for (String compositeId : compositeQuestions) { + questionIds.add(compositeId); + // 获取并添加子题目ID + questionService.list( + new LambdaQueryWrapper() + .eq(AiolQuestion::getParentId, compositeId) + ).stream() + .map(subQuestion -> subQuestion.getId().toString()) + .forEach(questionIds::add); + } + + return questionIds; + } + + //获取ip信息 + public String getClientIp(HttpServletRequest request) { + String ip = request.getHeader("X-Forwarded-For"); + + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_CLIENT_IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 + if (ip != null && ip.contains(",")) { + ip = ip.split(",")[0].trim(); + } + return ip; + } + + /** + * 批量阅卷 + * @param examId 考试ID + * @param userId 用户ID + * @return 阅卷后的答题列表 + */ + private List gradeExam(String examId, String userId) { + //获取试卷信息 + AiolExam exam = examService.getById(examId); + //获取组卷信息 + AiolPaper paper = paperService.getOne(new LambdaQueryWrapper().eq(AiolPaper::getId, exam.getPaperId())); + if(paper == null){ + throw new RuntimeException("试卷不存在"); + } + Map questionScoreMap = new HashMap<>(); + JSONObject ruleJson = null; + if(paper.getGenerateMode()==0){ + List list = paperQuestionService.list(new LambdaQueryWrapper().eq(AiolPaperQuestion::getPaperId, paper.getId())); + questionScoreMap = list.stream() + .collect(Collectors.toMap( + AiolPaperQuestion::getQuestionId, + AiolPaperQuestion::getScore + )); + }else { + ruleJson = JSON.parseObject(paper.getRules()); + } + // 获取学生的答题列表 + List examAnswerList = examAnswerService.list( + new LambdaQueryWrapper() + .eq(AiolExamAnswer::getExamId, examId) + .eq(AiolExamAnswer::getUserId, userId) + ); + + // 提取所有题目ID + List questionIds = examAnswerList.stream() + .map(AiolExamAnswer::getQuestionId) + .collect(Collectors.toList()); + + // 查询题目 + List questions = questionService.list( + new LambdaQueryWrapper() + .in(AiolQuestion::getId, questionIds) + .lt(AiolQuestion::getType, 4) + ); + + // 创建题目ID到题目的映射 + Map questionMap = questions.stream() + .collect(Collectors.toMap(AiolQuestion::getId, question -> question)); + + // 按题目类型分组 + Map> questionsByType = questions.stream() + .collect(Collectors.groupingBy(AiolQuestion::getType)); + + // 分离选择题(0、1、2)和填空题(3) + List choiceQuestions = questionsByType.entrySet().stream() + .filter(entry -> entry.getKey() < 3) + .flatMap(entry -> entry.getValue().stream()) + .collect(Collectors.toList()); + + List fillQuestions = questionsByType.getOrDefault(3, new ArrayList<>()); + + // 查询题目的正确选项 + List questionOptions = questionOptionService.list( + new LambdaQueryWrapper() + .in(AiolQuestionOption::getQuestionId, + choiceQuestions.stream() + .map(AiolQuestion::getId) + .collect(Collectors.toList())) + .eq(AiolQuestionOption::getIzCorrent, 1) + ); + + // 查询填空题的正确答案 + List questionAnswers = questionAnswerService.list( + new LambdaQueryWrapper() + .in(AiolQuestionAnswer::getQuestionId, + fillQuestions.stream() + .map(AiolQuestion::getId) + .collect(Collectors.toList())) + ); + + // 将选择题的正确选项转换为Map,结构为:题目ID -> 正确答案选项ID列表 + Map> correctAnswerMap = questionOptions.stream() + .collect(Collectors.groupingBy( + AiolQuestionOption::getQuestionId, + Collectors.mapping(AiolQuestionOption::getId, Collectors.toList()) + )); + + // 将填空题的正确答案转换为Map,结构为:题目ID -> (空序号 -> 答案列表) + Map>> fillAnswerMap = questionAnswers.stream() + .collect(Collectors.groupingBy( + AiolQuestionAnswer::getQuestionId, + Collectors.groupingBy( + AiolQuestionAnswer::getOrderNo, + Collectors.mapping(AiolQuestionAnswer::getAnswerText, Collectors.toList()) + ) + )); + + // 遍历学生的答案,进行评分 + for (AiolExamAnswer examAnswer : examAnswerList) { + String studentAnswer = examAnswer.getAnswer(); + AiolQuestion question = questionMap.get(examAnswer.getQuestionId()); + + if (studentAnswer == null || question == null) { + examAnswer.setScore(0.0); + examAnswer.setIzCorrect(0); + continue; + } + + List studentAnswers = Arrays.asList(studentAnswer.split(",")); + double score = 0.0; + + // 根据题目类型进行评分 + switch (question.getType()) { + case 0: // 单选题 + if (studentAnswers.get(0).equals(correctAnswerMap.get(question.getId()).get(0))) { + if (paper.getGenerateMode() == 0) { + score = questionScoreMap.get(question.getId()); + } else { + assert ruleJson != null; + score = ruleJson.getDouble("type" + question.getType() + "_score"); + } + } + break; + case 2: // 判断题 + if (studentAnswers.get(0).equals(correctAnswerMap.get(question.getId()).get(0))) { + if (paper.getGenerateMode() == 0) { + score = questionScoreMap.get(question.getId()); + } else { + assert ruleJson != null; + score = ruleJson.getDouble("type" + question.getType() + "_score"); + } + } + break; + + case 1: // 多选题 + List correctChoiceAnswers = correctAnswerMap.get(question.getId()); + if (correctChoiceAnswers != null && !correctChoiceAnswers.isEmpty()) { + // 检查学生答案是否包含错误选项 + boolean hasWrongAnswer = studentAnswers.stream() + .anyMatch(answer -> !correctChoiceAnswers.contains(answer)); + + // 如果有错选,直接得0分 + if (hasWrongAnswer) { + score = 0.0; + } + // 如果没有错选,检查是否全对 + else { + boolean allCorrect = new HashSet<>(studentAnswers).containsAll(correctChoiceAnswers); + boolean sameCount = studentAnswers.size() == correctChoiceAnswers.size(); + + if (allCorrect && sameCount) { + // 全对且数量正确,得满分 + if (paper.getGenerateMode() == 0) { + score = questionScoreMap.get(question.getId()); + } else { + assert ruleJson != null; + score = ruleJson.getDouble("type" + question.getType() + "_score"); + } + } else if (studentAnswers.size() < correctChoiceAnswers.size()) { + // 少选,得一半分数 + if (paper.getGenerateMode() == 0) { + score = questionScoreMap.get(question.getId()) * 0.5; + } else { + assert ruleJson != null; + score = ruleJson.getDouble("type" + question.getType() + "_score") * 0.5; + } + } + } + } + break; + + case 3: // 填空题 + Map> correctFillAnswers = fillAnswerMap.get(question.getId()); + if (correctFillAnswers != null && !correctFillAnswers.isEmpty()) { + int totalBlanks = correctFillAnswers.size(); + int correctBlanks = 0; + + // 检查每个空的答案 + for (int i = 0; i < studentAnswers.size() && i < totalBlanks; i++) { + int blankNumber = i + 1; + List correctBlankAnswers = correctFillAnswers.get(blankNumber); + if (correctBlankAnswers != null && correctBlankAnswers.contains(studentAnswers.get(i))) { + correctBlanks++; + } + } + + // 计算得分 + if (correctBlanks > 0) { + double fullScore; + if (paper.getGenerateMode() == 0) { + fullScore = questionScoreMap.get(question.getId()); + } else { + assert ruleJson != null; + fullScore = ruleJson.getDouble("type" + question.getType() + "_score"); + } + + // 按正确空的数量比例给分 + score = fullScore * ((double) correctBlanks / totalBlanks); + } + } + break; + } + examAnswer.setScore(score); + // 只有得了满分才算对 + examAnswer.setIzCorrect(score > 0 && score == (paper.getGenerateMode() == 0 ? + questionScoreMap.get(question.getId()) : + ruleJson.getDouble("type" + question.getType() + "_score")) ? 1 : 0); + } + + return examAnswerList; + } + + //获取设备信息 + public String getDeviceInfo(HttpServletRequest request) { + // 获取User-Agent + String userAgent = request.getHeader("User-Agent"); + // 解析设备信息 + String deviceInfo = parseDeviceInfo(userAgent); + return deviceInfo; + } + private String parseDeviceInfo(String userAgent) { + if (userAgent == null) { + return "Unknown"; + } + StringBuilder deviceInfo = new StringBuilder(); + // 判断操作系统 + if (userAgent.indexOf("Windows") > -1) { + deviceInfo.append("Windows"); + } else if (userAgent.indexOf("Mac") > -1) { + deviceInfo.append("Mac"); + } else if (userAgent.indexOf("X11") > -1) { + deviceInfo.append("Unix"); + } else if (userAgent.indexOf("Android") > -1) { + deviceInfo.append("Android"); + } else if (userAgent.indexOf("iPhone") > -1 || userAgent.indexOf("iPad") > -1) { + deviceInfo.append("iOS"); + } else { + deviceInfo.append("Unknown OS"); + } + deviceInfo.append(" | "); + // 判断浏览器 + if (userAgent.indexOf("MSIE") > -1) { + deviceInfo.append("MSIE"); + } else if (userAgent.indexOf("Firefox") > -1) { + deviceInfo.append("Firefox"); + } else if (userAgent.indexOf("Chrome") > -1) { + deviceInfo.append("Chrome"); + } else if (userAgent.indexOf("Safari") > -1) { + deviceInfo.append("Safari"); + } else if (userAgent.indexOf("Opera") > -1) { + deviceInfo.append("Opera"); + } else { + deviceInfo.append("Unknown Browser"); + } + // 可以添加更多设备信息的判断,如: + // 判断是否是移动设备 + boolean isMobile = userAgent.indexOf("Mobile") > -1 || + userAgent.indexOf("Android") > -1 || + userAgent.indexOf("iPhone") > -1; + deviceInfo.append(" | ").append(isMobile ? "Mobile" : "PC"); + return deviceInfo.toString(); + } } From d294bfc60650615d1e8755df6068ab4ce7bbc745 Mon Sep 17 00:00:00 2001 From: Lqc Date: Wed, 3 Sep 2025 15:39:17 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E5=BE=AE=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/jeecg/modules/aiol/mapper/AiolRepoMapper.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-aiol/src/main/java/org/jeecg/modules/aiol/mapper/AiolRepoMapper.java b/jeecg-boot/jeecg-boot-module/jeecg-module-aiol/src/main/java/org/jeecg/modules/aiol/mapper/AiolRepoMapper.java index 1caf01ab..99788c63 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-aiol/src/main/java/org/jeecg/modules/aiol/mapper/AiolRepoMapper.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-aiol/src/main/java/org/jeecg/modules/aiol/mapper/AiolRepoMapper.java @@ -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 { } From 27dabcce7aa1604d89c97a86e900817ebe03fa6a Mon Sep 17 00:00:00 2001 From: Lqc Date: Wed, 3 Sep 2025 16:17:06 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E5=BE=AE=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../aiol/controller/AiolExamController.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-aiol/src/main/java/org/jeecg/modules/aiol/controller/AiolExamController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-aiol/src/main/java/org/jeecg/modules/aiol/controller/AiolExamController.java index b5a340c6..ff20414f 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-aiol/src/main/java/org/jeecg/modules/aiol/controller/AiolExamController.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-aiol/src/main/java/org/jeecg/modules/aiol/controller/AiolExamController.java @@ -320,11 +320,10 @@ public class AiolExamController extends JeecgController gradedAnswers = gradeExam(examRecord.getExamId(), examRecord.getUserId()); + List 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("提交考试失败"); @@ -738,9 +737,10 @@ public class AiolExamController extends JeecgController gradeExam(String examId, String userId) { + private List gradeExam(String examId, String userId , LambdaUpdateWrapper updateWrapper) { //获取试卷信息 AiolExam exam = examService.getById(examId); //获取组卷信息 @@ -832,6 +832,7 @@ public class AiolExamController extends JeecgController 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; }