| | |
| | | |
| | | import com.alibaba.fastjson2.JSON; |
| | | import com.alibaba.fastjson2.JSONArray; |
| | | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; |
| | | import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; |
| | |
| | | import com.ycl.jxkg.base.Result; |
| | | import com.ycl.jxkg.base.SystemCode; |
| | | import com.ycl.jxkg.context.WebContext; |
| | | import com.ycl.jxkg.domain.base.AbsVo; |
| | | import com.ycl.jxkg.domain.entity.*; |
| | | import com.ycl.jxkg.domain.exam.PaperFixQuestionDTO; |
| | | import com.ycl.jxkg.domain.exam.PaperQuestion; |
| | | import com.ycl.jxkg.domain.exam.PaperQuestionSettingDTO; |
| | | import com.ycl.jxkg.domain.exam.PaperSettingItem; |
| | | import com.ycl.jxkg.domain.form.AddTimeForm; |
| | | import com.ycl.jxkg.domain.form.ExamForm; |
| | | import com.ycl.jxkg.domain.form.ForceSubmitForm; |
| | |
| | | import com.ycl.jxkg.enums.general.ExamStatusEnum; |
| | | import com.ycl.jxkg.enums.general.ExamSubmitTempStatusEnum; |
| | | import com.ycl.jxkg.mapper.*; |
| | | import com.ycl.jxkg.rabbitmq.msg.ExamStatusMsg; |
| | | import com.ycl.jxkg.rabbitmq.product.Producer; |
| | | import com.ycl.jxkg.server.WebsocketServer; |
| | | import com.ycl.jxkg.service.ExamPaperScoreService; |
| | | import com.ycl.jxkg.service.ExamPaperService; |
| | | import com.ycl.jxkg.service.ExamService; |
| | | import com.ycl.jxkg.utils.DateTimeUtil; |
| | | import com.ycl.jxkg.utils.PageUtil; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.beans.BeanUtils; |
| | |
| | | @RequiredArgsConstructor |
| | | public class ExamServiceImpl extends ServiceImpl<ExamMapper, Exam> implements ExamService { |
| | | |
| | | private static final String ANSWER_SPLIT = ","; |
| | | |
| | | private final ExamMapper examMapper; |
| | | private final WebContext webContext; |
| | | private final QuestionMapper questionMapper; |
| | |
| | | private final UserMapper userMapper; |
| | | private final ExamPaperScoreMapper examPaperScoreMapper; |
| | | private final ExamPaperScoreService examPaperScoreService; |
| | | private static final String ANSWER_SPLIT = ","; |
| | | |
| | | private final Producer producer; |
| | | |
| | | /** |
| | | * 添加 |
| | |
| | | Exam entity = ExamForm.getEntityByForm(form, null); |
| | | entity.setStatus(ExamStatusEnum.getStatusByTime(form.getStartTime(), form.getEndTime(), null)); |
| | | entity.setTeacherId(webContext.getCurrentUser().getId()); |
| | | baseMapper.insert(entity); |
| | | // 设置乐观锁版本 |
| | | entity.setUpdateVersion(0); |
| | | if (baseMapper.insert(entity) > 0) { |
| | | this.sendMQ(entity, 0); |
| | | } |
| | | return Result.ok("添加成功"); |
| | | } |
| | | |
| | |
| | | } |
| | | BeanUtils.copyProperties(form, entity); |
| | | entity.setStatus(ExamStatusEnum.getStatusByTime(form.getStartTime(), form.getEndTime(), null)); |
| | | baseMapper.updateById(entity); |
| | | // 如果修改成功发送mq消息 |
| | | if (baseMapper.updateById(entity) > 0) { |
| | | this.sendMQ(entity, entity.getUpdateVersion() + 1); |
| | | } |
| | | |
| | | return Result.ok("修改成功"); |
| | | } |
| | | |
| | | /** |
| | | * 发送mq消息 |
| | | * |
| | | * @param entity 考试实体类 |
| | | * @param version 乐观锁版本 |
| | | */ |
| | | public void sendMQ(Exam entity, Integer version) { |
| | | // 如果当前状态为未开始,则发送两条mq消息,一条设置状态为进行中,一条设置状态为已结束 |
| | | if (ExamStatusEnum.NOT_START.equals(entity.getStatus())) { |
| | | // 进行状态消息 |
| | | ExamStatusMsg ingMsg = new ExamStatusMsg(); |
| | | ingMsg.setVersion(version); |
| | | ingMsg.setExamId(entity.getId()); |
| | | ingMsg.setTargetStatus(ExamStatusEnum.ING); |
| | | producer.examMsg(entity.getId(), JSON.toJSONString(ingMsg), DateTimeUtil.getTwoTimeDiffMS(entity.getStartTime(), new Date())); |
| | | // 结束状态消息 |
| | | ExamStatusMsg finishedMsg = new ExamStatusMsg(); |
| | | finishedMsg.setVersion(version); |
| | | finishedMsg.setExamId(entity.getId()); |
| | | finishedMsg.setTargetStatus(ExamStatusEnum.FINISHED); |
| | | producer.examMsg(entity.getId(), JSON.toJSONString(finishedMsg), DateTimeUtil.getTwoTimeDiffMS(entity.getEndTime(), new Date())); |
| | | } else if (ExamStatusEnum.ING.equals(entity.getStatus())) { // 当前是进行中状态则只需发送结束消息 |
| | | // 结束状态消息 |
| | | ExamStatusMsg finishedMsg = new ExamStatusMsg(); |
| | | finishedMsg.setVersion(0); |
| | | finishedMsg.setExamId(entity.getId()); |
| | | finishedMsg.setTargetStatus(ExamStatusEnum.FINISHED); |
| | | producer.examMsg(entity.getId(), JSON.toJSONString(finishedMsg), DateTimeUtil.getTwoTimeDiffMS(entity.getEndTime(), new Date())); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 根据考试的当前状态,得到下一个状态 |
| | | * |
| | | * @param currentStatus |
| | | * @return |
| | | */ |
| | | public ExamStatusEnum getNextStatus(ExamStatusEnum currentStatus) { |
| | | if (ExamStatusEnum.NOT_START.equals(currentStatus)) { |
| | | return ExamStatusEnum.ING; |
| | | } else { |
| | | return ExamStatusEnum.FINISHED; |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | PaperFixQuestionVO paperFixQuestionVO = new PaperFixQuestionVO(); |
| | | paperFixQuestionVO.setTitle(paperSetting.getTitle()); |
| | | paperFixQuestionVO.setQuestionType(paperSetting.getQuestionType()); |
| | | // 拿到课目下某类题型的x道随机题 |
| | | List<Question> questions = questionMapper.getRandomQuestion(examPaper.getSubjectId(), paperSetting.getQuestionType(), paperSetting.getNum()); |
| | | if (paperSetting.getNum() > questions.size()) { |
| | | throw new RuntimeException("配置的题目数不足以生成试卷"); |
| | | } |
| | | |
| | | // 拿到题目后组装为可临时保存的题目结构 |
| | | List<DoQuestionVO> childQuestions = questions.stream().map(item -> { |
| | | DoQuestionVO doQuestionVO = new DoQuestionVO(); |
| | | doQuestionVO.setTitle(item.getTitle()); |
| | | doQuestionVO.setQuestionType(item.getQuestionType()); |
| | | //从配置里拿题目分数 |
| | | doQuestionVO.setQuestionScore(paperSetting.getScore()); |
| | | if (StringUtils.hasText(item.getContent())) { |
| | | QuestionObject questionObject = JSON.parseObject(item.getContent(), QuestionObject.class); |
| | | doQuestionVO.setQuestionItemList(questionObject.getQuestionItemObjects()); |
| | | //一个类型的题目list |
| | | List<DoQuestionVO> childQuestionList = new ArrayList<>(); |
| | | List<PaperSettingItem> settingList = paperSetting.getSettingList(); |
| | | for (PaperSettingItem settingItem : settingList) { |
| | | Integer num = settingItem.getNum(); |
| | | Integer difficult = settingItem.getDifficult(); |
| | | //需要配置的题目数量为0则跳过 |
| | | if (num == null || num == 0) continue; |
| | | List<Question> questions = questionMapper.getRandomQuestion(settingItem.getSubjectId(), paperSetting.getQuestionType(), difficult, settingItem.getNum()); |
| | | if (org.springframework.util.CollectionUtils.isEmpty(questions) || settingItem.getNum() > questions.size()) { |
| | | throw new RuntimeException("配置的题目数不足以生成试卷"); |
| | | } |
| | | doQuestionVO.setId(item.getId()); |
| | | doQuestionVO.setOriginalFile(item.getOriginalFile()); |
| | | doQuestionVO.setAudioFile(item.getAudioFile()); |
| | | |
| | | // 题目副本 |
| | | QuestionAnswerCopyVO copy = new QuestionAnswerCopyVO(); |
| | | copy.setId(item.getId()); |
| | | copy.setDifficult(item.getDifficult()); |
| | | copy.setAnalyze(JSON.parseObject(item.getContent(), PaperQuestion.class).getAnalyze()); |
| | | //填空的答案在Json里 |
| | | if (QuestionTypeEnum.GapFilling.getCode().equals(item.getQuestionType())) { |
| | | List<String> gapAnswer = new ArrayList<>(); |
| | | for (QuestionItemObject questionItemObject : doQuestionVO.getQuestionItemList()) { |
| | | gapAnswer.add(questionItemObject.getContent()); |
| | | // 拿到题目后组装为可临时保存的题目结构 |
| | | List<DoQuestionVO> childQuestions = questions.stream().map(item -> { |
| | | DoQuestionVO doQuestionVO = new DoQuestionVO(); |
| | | doQuestionVO.setQuestionType(item.getQuestionType()); |
| | | //从配置里拿题目分数 |
| | | doQuestionVO.setQuestionScore(settingItem.getScore()); |
| | | if (StringUtils.hasText(item.getContent())) { |
| | | QuestionObject questionObject = JSON.parseObject(item.getContent(), QuestionObject.class); |
| | | doQuestionVO.setQuestionItemList(questionObject.getQuestionItemObjects()); |
| | | doQuestionVO.setTitle(questionObject.getTitleContent()); |
| | | } |
| | | copy.setCorrect(String.join(ANSWER_SPLIT, gapAnswer)); |
| | | } else { |
| | | copy.setCorrect(item.getCorrect()); |
| | | } |
| | | questionAnswerCopyVOList.add(copy); |
| | | doQuestionVO.setId(item.getId()); |
| | | doQuestionVO.setOriginalFile(item.getOriginalFile()); |
| | | doQuestionVO.setAudioFile(item.getAudioFile()); |
| | | |
| | | return doQuestionVO; |
| | | }).collect(Collectors.toList()); |
| | | paperFixQuestionVO.setQuestionList(childQuestions); |
| | | // 题目副本 |
| | | QuestionAnswerCopyVO copy = new QuestionAnswerCopyVO(); |
| | | copy.setId(item.getId()); |
| | | copy.setDifficult(item.getDifficult()); |
| | | copy.setAnalyze(JSON.parseObject(item.getContent(), PaperQuestion.class).getAnalyze()); |
| | | //填空的答案在Json里 |
| | | if (QuestionTypeEnum.GapFilling.getCode().equals(item.getQuestionType())) { |
| | | List<String> gapAnswer = new ArrayList<>(); |
| | | for (QuestionItemObject questionItemObject : doQuestionVO.getQuestionItemList()) { |
| | | gapAnswer.add(questionItemObject.getContent()); |
| | | } |
| | | copy.setCorrect(String.join(ANSWER_SPLIT, gapAnswer)); |
| | | } else { |
| | | copy.setCorrect(item.getCorrect()); |
| | | } |
| | | questionAnswerCopyVOList.add(copy); |
| | | |
| | | return doQuestionVO; |
| | | }).collect(Collectors.toList()); |
| | | //添加到这个类型的list中 |
| | | childQuestionList.addAll(childQuestions); |
| | | } |
| | | paperFixQuestionVO.setQuestionList(childQuestionList); |
| | | examData.add(paperFixQuestionVO); |
| | | } |
| | | return Result.ok(startExamVO); |
| | | } |
| | | ExamSubmitTemp examSubmitTemp = new ExamSubmitTemp(); |
| | | examSubmitTemp.setExamId(id); |
| | |
| | | // 阅卷后才往exam_paper_answer保存考试成绩、以及保存到exam_paper_customer_answer |
| | | // 现在只需要保存到一张临时表 |
| | | // 该接口是主动提交,所以状态都设置为完成,以便后续老师阅卷 |
| | | //TODO:暂时改为temp方便测试 |
| | | saveTempExam(submitData, ExamSubmitTempStatusEnum.temp); |
| | | saveTempExam(submitData, ExamSubmitTempStatusEnum.finish); |
| | | return Result.ok(); |
| | | } |
| | | |
| | |
| | | // 参考但未完成提交人数 |
| | | Integer joinButNotFinishedNum = Math.toIntExact(examSubmitTempList.stream().filter(item -> ExamSubmitTempStatusEnum.temp.equals(item.getStatus())).count()); |
| | | |
| | | List<StudentExamInfoVO> studentExamList = classesUserMapper.getClassesUserList(exam.getId(), exam.getClassesId()); |
| | | List<StudentExamInfoVO> studentExamList = classesUserMapper.getClassesUserList(exam.getClassesId()); |
| | | // 应考人数 |
| | | Integer shouldUserNum = studentExamList.size(); |
| | | |
| | | studentExamList.stream().forEach(item -> { |
| | | if (StringUtils.hasText(item.getExamSubmit())) { |
| | | item.setQuestionList(JSON.parseArray(item.getExamSubmit(), DoQuestionVO.class)); |
| | | for (StudentExamInfoVO studentExamInfoVO : studentExamList) { |
| | | Integer userId = studentExamInfoVO.getUserId(); |
| | | Optional<ExamSubmitTemp> first = examSubmitTempList.stream().filter(examSubmitTemp -> examSubmitTemp.getUserId().equals(userId)).findFirst(); |
| | | if(first.isPresent()){ |
| | | ExamSubmitTemp examSubmitTemp = first.get(); |
| | | studentExamInfoVO.setMarkPaperStatus(examSubmitTemp.getMarkPaperStatus()); |
| | | studentExamInfoVO.setStatus(examSubmitTemp.getStatus()); |
| | | studentExamInfoVO.setDoTime(examSubmitTemp.getDoTime()); |
| | | }else { |
| | | studentExamInfoVO.setMarkPaperStatus(ExamSubmitTempStatusEnum.temp); |
| | | studentExamInfoVO.setStatus(ExamSubmitTempStatusEnum.temp); |
| | | studentExamInfoVO.setDoTime(0); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | MarkPaperVO markPaperVO = new MarkPaperVO(); |
| | | markPaperVO.setExamName(exam.getExamName()); |
| | |
| | | long questionCorrect = 0; |
| | | long questionCount = 0; |
| | | if (!CollectionUtils.isEmpty(examPaperMark.getNavbar())) { |
| | | questionCorrect = examPaperMark.getNavbar().stream().filter(vo -> vo.getRight()!=null && vo.getRight()).count(); |
| | | questionCorrect = examPaperMark.getNavbar().stream().filter(vo -> vo.getRight() != null && vo.getRight()).count(); |
| | | questionCount = examPaperMark.getNavbar().size(); |
| | | } |
| | | examPaperScore.setQuestionCorrect(Integer.valueOf(questionCorrect + "")); |
| | |
| | | examPaperScoreMapper.updateById(examPaperScore); |
| | | } else { |
| | | examPaperScoreMapper.insert(examPaperScore); |
| | | //修改考试里试卷状态为已阅卷 |
| | | ExamSubmitTemp userExam = new LambdaQueryChainWrapper<>(examSubmitTempMapper) |
| | | .eq(ExamSubmitTemp::getExamId, examPaperMark.getExamId()) |
| | | .eq(ExamSubmitTemp::getUserId, examPaperMark.getUserId()) |
| | | .one(); |
| | | userExam.setMarkPaperStatus(ExamSubmitTempStatusEnum.finish); |
| | | examSubmitTempMapper.updateById(userExam); |
| | | } |
| | | return Result.ok(); |
| | | } |