| | |
| | | |
| | | import com.alibaba.fastjson2.JSON; |
| | | import com.alibaba.fastjson2.JSONArray; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; |
| | | import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; |
| | | import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.ycl.jxkg.base.Result; |
| | | import com.ycl.jxkg.base.SystemCode; |
| | | import com.ycl.jxkg.constants.ExamScoreConstant; |
| | | 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.ExamPaperTypeEnum; |
| | | import com.ycl.jxkg.enums.QuestionTypeEnum; |
| | | import com.ycl.jxkg.enums.WebsocketCommendEnum; |
| | | import com.ycl.jxkg.enums.general.ClassesStatusEnum; |
| | | 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); |
| | | |
| | | // 查出考试试卷 |
| | | ExamPaper examPaper = examPaperMapper.selectById(entity.getExamPaperId()); |
| | | // 校验能否生成一张试卷 |
| | | try { |
| | | this.checkGenExam(examPaper); |
| | | // 设置乐观锁版本 |
| | | entity.setUpdateVersion(0); |
| | | if (baseMapper.insert(entity) > 0) { |
| | | this.sendMQ(entity, 0); |
| | | } |
| | | } catch (RuntimeException e) { |
| | | e.printStackTrace(); |
| | | return Result.fail(500, e.getMessage()); |
| | | } |
| | | return Result.ok("添加成功"); |
| | | } |
| | | |
| | |
| | | // 为空抛IllegalArgumentException,做全局异常处理 |
| | | Assert.notNull(entity, "记录不存在"); |
| | | // 判断考试状态 |
| | | if (! ExamStatusEnum.NOT_START.equals(entity.getStatus())) { |
| | | if (!ExamStatusEnum.NOT_START.equals(entity.getStatus())) { |
| | | throw new RuntimeException("只能修改还未开始的考试"); |
| | | } |
| | | BeanUtils.copyProperties(form, entity); |
| | | entity.setStatus(ExamStatusEnum.getStatusByTime(form.getStartTime(), form.getEndTime(), null)); |
| | | baseMapper.updateById(entity); |
| | | entity.setStatus(ExamStatusEnum.getStatusByTime(form.getStartTime(), form.getEndTime(), new Date())); |
| | | |
| | | // 查出考试试卷 |
| | | ExamPaper examPaper = examPaperMapper.selectById(entity.getExamPaperId()); |
| | | try { |
| | | this.checkGenExam(examPaper); |
| | | // 如果修改成功发送mq消息 |
| | | if (baseMapper.updateById(entity) > 0) { |
| | | this.sendMQ(entity, entity.getUpdateVersion()); |
| | | } |
| | | } catch (RuntimeException e) { |
| | | e.printStackTrace(); |
| | | return Result.fail(500, e.getMessage()); |
| | | } |
| | | 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; |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | item.setExamPaperId(null); |
| | | } |
| | | }); |
| | | // |
| | | return Result.ok().data(page.getRecords()).total(page.getTotal()); |
| | | } |
| | | |
| | |
| | | public Result studentPage(ExamQuery query) { |
| | | IPage<ExamVO> page = PageUtil.getPage(query, ExamVO.class); |
| | | baseMapper.studentPage(page, query, webContext.getCurrentUser().getId()); |
| | | for (ExamVO record : page.getRecords()) { |
| | | ExamSubmitTemp one = new LambdaQueryChainWrapper<>(examSubmitTempMapper) |
| | | .eq(ExamSubmitTemp::getExamId, record.getId()) |
| | | .eq(ExamSubmitTemp::getUserId, webContext.getCurrentUser().getId()) |
| | | .one(); |
| | | record.setIsContinue(Objects.isNull(one) || ExamSubmitTempStatusEnum.temp.equals(one.getExamSubmit())); |
| | | } |
| | | return Result.ok().data(page.getRecords()).total(page.getTotal()); |
| | | } |
| | | |
| | | /** |
| | | * 测试试卷配置能否生成试卷 |
| | | * |
| | | * @param examPaper |
| | | */ |
| | | public void checkGenExam(ExamPaper examPaper) throws RuntimeException { |
| | | // 试卷内容 |
| | | List<PaperFixQuestionVO> examData = new ArrayList<>(); |
| | | // 拿到题目副本数据 |
| | | List<QuestionAnswerCopyVO> questionAnswerCopyVOList = new ArrayList<>(32); |
| | | if (ExamPaperTypeEnum.Fixed.getCode().equals(examPaper.getPaperType()) |
| | | || ExamPaperTypeEnum.RandomOrder.getCode().equals(examPaper.getPaperType())) { |
| | | if (!StringUtils.hasText(examPaper.getContent())) { |
| | | throw new RuntimeException("试卷题目为空"); |
| | | } |
| | | // 转换 |
| | | examData = this.coverTo(examPaper, questionAnswerCopyVOList); |
| | | } else if (ExamPaperTypeEnum.Random.getCode().equals(examPaper.getPaperType())) { |
| | | // 根据随机试卷的配置,随机生成对应题目 |
| | | if (!StringUtils.hasText(examPaper.getContent())) { |
| | | throw new RuntimeException("试卷配置异常,请联系老师"); |
| | | } |
| | | List<PaperQuestionSettingDTO> paperSettingList = JSON.parseArray(examPaper.getContent(), PaperQuestionSettingDTO.class); |
| | | examData = new ArrayList<>(8); |
| | | for (PaperQuestionSettingDTO paperSetting : paperSettingList) { |
| | | PaperFixQuestionVO paperFixQuestionVO = new PaperFixQuestionVO(); |
| | | paperFixQuestionVO.setTitle(paperSetting.getTitle()); |
| | | paperFixQuestionVO.setQuestionType(paperSetting.getQuestionType()); |
| | | //一个类型的题目list |
| | | List<DoQuestionVO> childQuestionList = new ArrayList<>(); |
| | | List<PaperSettingItem> settingList = paperSetting.getSettingList(); |
| | | for (PaperSettingItem settingItem : settingList) { |
| | | Integer num = settingItem.getNum(); |
| | | Integer difficult = settingItem.getDifficult(); |
| | | if(0 == difficult) { |
| | | difficult = null; |
| | | } |
| | | //需要配置的题目数量为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("试卷配置的题目数不足以生成试卷"); |
| | | } |
| | | // 拿到题目后组装为可临时保存的题目结构 |
| | | 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()); |
| | | } |
| | | 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()); |
| | | } |
| | | 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); |
| | | if (! CollectionUtils.isEmpty(childQuestionList)) { |
| | | examData.add(paperFixQuestionVO); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | |
| | | .eq(ExamSubmitTemp::getUserId, webContext.getCurrentUser().getId()) |
| | | .one(); |
| | | if (Objects.nonNull(hasJoin)) { |
| | | // 允许提交后继续作答 |
| | | if(ExamSubmitTempStatusEnum.finish.equals(hasJoin.getStatus())){ |
| | | throw new RuntimeException("您已提交试卷,请勿重复作答"); |
| | | } |
| | | StartExamVO startExamVO = new StartExamVO(); |
| | | startExamVO.setExamName(exam.getExamName()); |
| | | startExamVO.setId(hasJoin.getExamId()); |
| | |
| | | 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(); |
| | | if(0 == difficult){ |
| | | difficult = null; |
| | | } |
| | | 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()); |
| | | //需要配置的题目数量为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("配置的题目数不足以生成试卷"); |
| | | } |
| | | // 拿到题目后组装为可临时保存的题目结构 |
| | | 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); |
| | | examData.add(paperFixQuestionVO); |
| | | // 题目副本 |
| | | 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); |
| | | if (! CollectionUtils.isEmpty(childQuestionList)) { |
| | | examData.add(paperFixQuestionVO); |
| | | } |
| | | } |
| | | return Result.ok(startExamVO); |
| | | } |
| | | ExamSubmitTemp examSubmitTemp = new ExamSubmitTemp(); |
| | | examSubmitTemp.setExamId(id); |
| | |
| | | doQuestionVO.setQuestionType(item.getQuestionType()); |
| | | //增加题目分数 |
| | | doQuestionVO.setQuestionScore(question.getScore()); |
| | | // 题目副本 |
| | | QuestionAnswerCopyVO copy = new QuestionAnswerCopyVO(); |
| | | copy.setId(question.getId()); |
| | | copy.setAnalyze(question.getAnalyze()); |
| | | copy.setDifficult(question.getDifficult()); |
| | | //填空的答案在Json里 |
| | | if (QuestionTypeEnum.GapFilling.getCode().equals(item.getQuestionType())) { |
| | | List<String> gapAnswer = new ArrayList<>(); |
| | | for (QuestionItemObject questionItemObject : question.getItems()) { |
| | | gapAnswer.add(questionItemObject.getContent()); |
| | | } |
| | | copy.setCorrect(String.join(ANSWER_SPLIT, gapAnswer)); |
| | | } else { |
| | | copy.setCorrect(question.getCorrect()); |
| | | } |
| | | questionAnswerCopyVOList.add(copy); |
| | | |
| | | // 填空题需要抹除content(因为是答案) |
| | | if (QuestionTypeEnum.GapFilling.getCode().equals(doQuestionVO.getQuestionType())) { |
| | | question.getItems().stream().forEach(option -> { |
| | |
| | | doQuestionVO.setId(question.getId()); |
| | | doQuestionVO.setOriginalFile(question.getOriginalFile()); |
| | | doQuestionVO.setAudioFile(question.getAudioFile()); |
| | | |
| | | // 题目副本 |
| | | QuestionAnswerCopyVO copy = new QuestionAnswerCopyVO(); |
| | | copy.setId(question.getId()); |
| | | copy.setAnalyze(question.getAnalyze()); |
| | | copy.setDifficult(question.getDifficult()); |
| | | //填空的答案在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(question.getCorrect()); |
| | | } |
| | | questionAnswerCopyVOList.add(copy); |
| | | |
| | | return doQuestionVO; |
| | | }).collect(Collectors.toList()); |
| | | if (ExamPaperTypeEnum.RandomOrder.getCode().equals(examPaper.getPaperType())) { |
| | |
| | | * @return |
| | | */ |
| | | @Override |
| | | public Result all() { |
| | | List<Exam> entities = baseMapper.selectList(null); |
| | | public Result all(ExamQuery query) { |
| | | List<Exam> entities; |
| | | // 判断如果examName为空或空字符串,则查询所有 |
| | | if (query.getExamName() == null || query.getExamName().isEmpty()) { |
| | | entities = baseMapper.selectList(null); |
| | | }else { |
| | | entities = baseMapper.selectList(new LambdaQueryWrapper<>(Exam.class).like(Exam::getExamName,query.getExamName())); |
| | | } |
| | | List<ExamVO> vos = entities.stream() |
| | | .map(entity -> ExamVO.getVoByEntity(entity, null)) |
| | | .map(entity -> { |
| | | ExamVO vo = new ExamVO(); |
| | | vo = ExamVO.getVoByEntity(entity, vo); |
| | | vo.setStatus(entity.getStatus().getDesc()); |
| | | return vo; |
| | | }) |
| | | .collect(Collectors.toList()); |
| | | return Result.ok().data(vos); |
| | | } |
| | |
| | | // 现在只需要保存到一张临时表 |
| | | // 该接口是主动提交,所以状态都设置为完成,以便后续老师阅卷 |
| | | saveTempExam(submitData, ExamSubmitTempStatusEnum.finish); |
| | | |
| | | //TODO:考试状态设定为结束 |
| | | |
| | | return Result.ok(); |
| | | } |
| | | |
| | |
| | | ExamSubmitTemp one = new LambdaQueryChainWrapper<>(examSubmitTempMapper) |
| | | .eq(ExamSubmitTemp::getExamId, submitData.getId()) |
| | | .eq(ExamSubmitTemp::getUserId, webContext.getCurrentUser().getId()) |
| | | .eq(ExamSubmitTemp::getDeleted, 0) |
| | | .one(); |
| | | |
| | | if (Objects.nonNull(one)) { |
| | |
| | | Date now = new Date(); |
| | | one.setExamSubmit(JSON.toJSONString(submitData.getTitleList())); |
| | | one.setUpdateTime(now); |
| | | long doTimeL = now.getTime() - one.getCreateTime().getTime(); |
| | | Integer doTime = (int) doTimeL; |
| | | one.setDoTime(doTime); |
| | | int doTimeInSeconds = (int) (now.getTime() - one.getCreateTime().getTime()) / 1000; |
| | | one.setDoTime(doTimeInSeconds); |
| | | one.setStatus(status); |
| | | examSubmitTempMapper.updateById(one); |
| | | } else { |
| | |
| | | throw new RuntimeException("考试试卷不存在"); |
| | | } |
| | | List<ExamSubmitTemp> examSubmitTempList = new LambdaQueryChainWrapper<>(examSubmitTempMapper) |
| | | .eq(ExamSubmitTemp::getDeleted,0) |
| | | .eq(ExamSubmitTemp::getDeleted, 0) |
| | | .eq(ExamSubmitTemp::getExamId, id) |
| | | .list(); |
| | | // 参考人数 |
| | |
| | | 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.setStatus(ExamSubmitTempStatusEnum.temp); |
| | | //根据Score表判断 |
| | | ExamPaperScore paperScore = examPaperScoreMapper.getByExamIdUserId(exam.getId(), userId); |
| | | if(paperScore==null) { |
| | | studentExamInfoVO.setMarkPaperStatus(ExamSubmitTempStatusEnum.temp); |
| | | }else { |
| | | studentExamInfoVO.setMarkPaperStatus(ExamSubmitTempStatusEnum.finish); |
| | | } |
| | | studentExamInfoVO.setDoTime(0); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | MarkPaperVO markPaperVO = new MarkPaperVO(); |
| | | markPaperVO.setExamName(exam.getExamName()); |
| | |
| | | |
| | | @Override |
| | | public Result getMarkPaperInfo(Integer examId, Integer userId) { |
| | | User student = userMapper.getUserById(userId); |
| | | //如果已经阅过卷了,查成绩表 |
| | | Result<ExamPaperMarkVO> paperMarkVO1 = checkHasJudge(examId, student); |
| | | if (paperMarkVO1 != null) return paperMarkVO1; |
| | | |
| | | ExamVO exam = examMapper.getById(examId); |
| | | //学生答题表 |
| | | ExamSubmitTemp userExam = new LambdaQueryChainWrapper<>(examSubmitTempMapper) |
| | | .eq(ExamSubmitTemp::getExamId, examId) |
| | | .eq(ExamSubmitTemp::getUserId, userId) |
| | | .one(); |
| | | if (Objects.isNull(userExam)) { |
| | | throw new RuntimeException("该学员考试记录不存在"); |
| | | //缺考,学生没有做题信息 |
| | | ExamPaperMarkVO paperMarkVO = createVO(null, exam, student); |
| | | return Result.ok(paperMarkVO); |
| | | } |
| | | //如果已经阅过卷了,查成绩表 |
| | | Result<ExamPaperMarkVO> paperMarkVO1 = checkHasJudge(examId, userId, userExam); |
| | | if (paperMarkVO1 != null) return paperMarkVO1; |
| | | |
| | | User student = userMapper.getUserById(userId); |
| | | ExamVO exam = examMapper.getById(examId); |
| | | //封装阅卷基本数据 |
| | | ExamPaperMarkVO paperMarkVO = createVO(userExam, exam, student); |
| | | List<QuestionAnswerCopyVO> answerList = JSONArray.parseArray(userExam.getQuestionAnswerCopy(), QuestionAnswerCopyVO.class); |
| | |
| | | for (PaperFixQuestionVO titleItem : titleItems) { |
| | | for (DoQuestionVO doQuestionVO : titleItem.getQuestionList()) { |
| | | Integer questionId = doQuestionVO.getId(); |
| | | Optional<QuestionAnswerCopyVO> first = answerList.stream().filter(answer -> questionId.equals(answer.getId())).findFirst(); |
| | | if (first.isPresent()) { |
| | | QuestionAnswerCopyVO answerCopyVO = first.get(); |
| | | doQuestionVO.setQuestionAnswer(answerCopyVO.getCorrect()); |
| | | doQuestionVO.setAnalyze(answerCopyVO.getAnalyze()); |
| | | doQuestionVO.setDifficult(answerCopyVO.getDifficult()); |
| | | if(questionId!=null) { |
| | | Optional<QuestionAnswerCopyVO> first = answerList.stream().filter(answer -> questionId.equals(answer.getId())).findFirst(); |
| | | if (first.isPresent()) { |
| | | QuestionAnswerCopyVO answerCopyVO = first.get(); |
| | | doQuestionVO.setQuestionAnswer(answerCopyVO.getCorrect()); |
| | | doQuestionVO.setAnalyze(answerCopyVO.getAnalyze()); |
| | | doQuestionVO.setDifficult(answerCopyVO.getDifficult()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | //检查是否阅卷 |
| | | private Result<ExamPaperMarkVO> checkHasJudge(Integer examId, Integer userId, ExamSubmitTemp userExam) { |
| | | if (ExamSubmitTempStatusEnum.finish.equals(userExam.getMarkPaperStatus())) { |
| | | ExamPaperScore examPaperScore = examPaperScoreMapper.getByExamIdUserId(examId, userId); |
| | | private Result<ExamPaperMarkVO> checkHasJudge(Integer examId, User student) { |
| | | ExamPaperScore examPaperScore = examPaperScoreMapper.getByExamIdUserId(examId, student.getId()); |
| | | if (examPaperScore != null) { |
| | | ExamPaperMarkVO paperMarkVO = new ExamPaperMarkVO(); |
| | | BeanUtils.copyProperties(examPaperScore, paperMarkVO); |
| | | paperMarkVO.setUserName(student.getRealName()); |
| | | paperMarkVO.setTotalScore(examPaperScore.getTotalScore() + ""); |
| | | paperMarkVO.setScore(examPaperScore.getScore() + ""); |
| | | List<PaperFixQuestionVO> paperFixQuestionVOS = JSONArray.parseArray(examPaperScore.getPaperContent(), PaperFixQuestionVO.class); |
| | | paperMarkVO.setTitleItems(paperFixQuestionVOS); |
| | | paperMarkVO.setNavbar(JSONArray.parseArray(examPaperScore.getNavbar(), ExamPaperMarkNavbarVO.class)); |
| | | if (!StringUtils.isEmpty(examPaperScore.getPaperContent())) { |
| | | List<PaperFixQuestionVO> paperFixQuestionVOS = JSONArray.parseArray(examPaperScore.getPaperContent(), PaperFixQuestionVO.class); |
| | | paperMarkVO.setTitleItems(paperFixQuestionVOS); |
| | | } |
| | | if (!StringUtils.isEmpty(examPaperScore.getNavbar())) { |
| | | paperMarkVO.setNavbar(JSONArray.parseArray(examPaperScore.getNavbar(), ExamPaperMarkNavbarVO.class)); |
| | | } |
| | | return Result.ok(paperMarkVO); |
| | | } |
| | | return null; |
| | |
| | | if (StringUtils.isEmpty(doQuestionVO.getQuestionAnswer())) { |
| | | return Result.fail(SystemCode.InnerError.getCode(), "题目id为:" + doQuestionVO.getId() + "的题目缺少答案,请先完善"); |
| | | } |
| | | trueOrFalse(score,doQuestionVO, navbarVO, doQuestionVO.getQuestionAnswer().equals(doQuestionVO.getAnswer())); |
| | | score = trueOrFalse(score, doQuestionVO, navbarVO, doQuestionVO.getQuestionAnswer().equals(doQuestionVO.getAnswer())); |
| | | } |
| | | /* 如果是多选 */ |
| | | else if (QuestionTypeEnum.MultipleChoice.getCode().equals(questionType)) { |
| | |
| | | List<String> questionAnswerList = Arrays.asList(questionAnswer.split(",")); |
| | | //学生答案为空,判断为错 |
| | | if (CollectionUtils.isEmpty(answerList)) { |
| | | trueOrFalse(score,doQuestionVO, navbarVO, false); |
| | | score = trueOrFalse(score, doQuestionVO, navbarVO, false); |
| | | num++; |
| | | navbar.add(navbarVO); |
| | | continue; |
| | |
| | | Set<String> set2 = new HashSet<>(questionAnswerList); |
| | | //答案完全一致,满分 |
| | | if (set1.equals(set2)) { |
| | | trueOrFalse(score,doQuestionVO, navbarVO, true); |
| | | score = trueOrFalse(score, doQuestionVO, navbarVO, true); |
| | | num++; |
| | | navbar.add(navbarVO); |
| | | continue; |
| | |
| | | } |
| | | //如果多选得分类型为 答错不得分 |
| | | if (Integer.valueOf(DeductTypeEnum.AllCorrect.getCode()).equals(paperMarkVO.getDeductType())) { |
| | | trueOrFalse(score,doQuestionVO, navbarVO, false); |
| | | score = trueOrFalse(score, doQuestionVO, navbarVO, false); |
| | | } |
| | | //如果多选得分类型为 漏选得固定分值,包含错误选项不得分 |
| | | else if (Integer.valueOf(DeductTypeEnum.PartCorrect.getCode()).equals(paperMarkVO.getDeductType())) { |
| | | //学生答案移除所有正确答案,如果还有元素说明包含错误选项 |
| | | answerList.removeAll(questionAnswerList); |
| | | if (!CollectionUtils.isEmpty(answerList)) { |
| | | trueOrFalse(score,doQuestionVO, navbarVO, false); |
| | | score = trueOrFalse(score, doQuestionVO, navbarVO, false); |
| | | } else { |
| | | navbarVO.setRight(false); |
| | | doQuestionVO.setRight(false); |
| | | //漏选得固定分 |
| | | score = score.add(paperMarkVO.getDeductScore()); |
| | | doQuestionVO.setScore(paperMarkVO.getDeductScore()); |
| | | score = score.add(doQuestionVO.getScore()); |
| | | } |
| | | } |
| | | //如果多选得分类型为 每对一题得相应分值,包含错误选项不得分 |
| | |
| | | //学生答案移除所有正确答案,如果还有元素说明包含错误选项 |
| | | answerList.removeAll(questionAnswerList); |
| | | if (!CollectionUtils.isEmpty(answerList)) { |
| | | trueOrFalse(score,doQuestionVO, navbarVO, false); |
| | | score = trueOrFalse(score, doQuestionVO, navbarVO, false); |
| | | } else { |
| | | navbarVO.setRight(false); |
| | | doQuestionVO.setRight(false); |
| | | //漏选得分 |
| | | doQuestionVO.setScore(paperMarkVO.getDeductScore().multiply(new BigDecimal(answerCount))); |
| | | score = score.add(doQuestionVO.getScore()); |
| | | } |
| | | } |
| | | } |
| | |
| | | List<String> questionAnswerList = Arrays.asList(questionAnswer.split(",")); |
| | | //学生答案为空,判断为错 |
| | | if (CollectionUtils.isEmpty(answerList)) { |
| | | trueOrFalse(score,doQuestionVO, navbarVO, false); |
| | | score = trueOrFalse(score, doQuestionVO, navbarVO, false); |
| | | num++; |
| | | navbar.add(navbarVO); |
| | | continue; |
| | |
| | | int questionAnswerCount = questionAnswerList.size(); |
| | | //答案完全一致,满分 |
| | | if (answerList.equals(questionAnswerList)) { |
| | | trueOrFalse(score,doQuestionVO, navbarVO, true); |
| | | score = trueOrFalse(score, doQuestionVO, navbarVO, true); |
| | | } else { |
| | | navbarVO.setRight(false); |
| | | doQuestionVO.setRight(false); |
| | |
| | | //填空得分 |
| | | BigDecimal gapScore = scoreEach.multiply(new BigDecimal(count)); |
| | | doQuestionVO.setScore(gapScore); |
| | | score = score.add(doQuestionVO.getScore()); |
| | | } |
| | | |
| | | } |
| | |
| | | } |
| | | paperMarkVO.setTitleItems(titleItems); |
| | | paperMarkVO.setNavbar(navbar); |
| | | paperMarkVO.setScore(score + ""); |
| | | return null; |
| | | } |
| | | |
| | | //设置全对或全错 |
| | | private void trueOrFalse(BigDecimal score,DoQuestionVO doQuestionVO, ExamPaperMarkNavbarVO orderVO, Boolean isCorrect) { |
| | | private BigDecimal trueOrFalse(BigDecimal score, DoQuestionVO doQuestionVO, ExamPaperMarkNavbarVO orderVO, Boolean isCorrect) { |
| | | if (isCorrect) { |
| | | //正确 |
| | | orderVO.setRight(isCorrect); |
| | |
| | | doQuestionVO.setRight(isCorrect); |
| | | doQuestionVO.setScore(BigDecimal.ZERO); |
| | | } |
| | | return score; |
| | | } |
| | | |
| | | //封装阅卷返回数据 |
| | | private ExamPaperMarkVO createVO(ExamSubmitTemp userExam, ExamVO exam, User student) { |
| | | Integer paperId = exam.getExamPaperId(); |
| | | ExamPaper examPaper = examPaperMapper.selectById(paperId); |
| | | ExamPaperMarkVO paperMarkVO = new ExamPaperMarkVO(); |
| | | BeanUtils.copyProperties(userExam, paperMarkVO); |
| | | paperMarkVO.setPaperId(exam.getExamPaperId()); |
| | | paperMarkVO.setExamName(exam.getExamName()); |
| | | paperMarkVO.setPaperType(exam.getExamPaperType()); |
| | | paperMarkVO.setSubmitTime(userExam.getUpdateTime()); |
| | | if (userExam != null) { |
| | | BeanUtils.copyProperties(userExam, paperMarkVO); |
| | | paperMarkVO.setSubmitTime(userExam.getUpdateTime()); |
| | | paperMarkVO.setTitleItems(JSON.parseArray(userExam.getExamSubmit(), PaperFixQuestionVO.class)); |
| | | } else { |
| | | //缺考,学生没有做题信息 |
| | | paperMarkVO.setExamId(exam.getId()); |
| | | paperMarkVO.setUserId(student.getId()); |
| | | paperMarkVO.setScore(BigDecimal.ZERO + ""); |
| | | paperMarkVO.setDoTime(0); |
| | | } |
| | | paperMarkVO.setUserName(student.getRealName()); |
| | | paperMarkVO.setTitleItems(JSON.parseArray(userExam.getExamSubmit(), PaperFixQuestionVO.class)); |
| | | paperMarkVO.setExamName(exam.getExamName()); |
| | | paperMarkVO.setPaperId(exam.getExamPaperId()); |
| | | paperMarkVO.setPaperType(exam.getExamPaperType()); |
| | | ExamPaper examPaper = examPaperMapper.selectById(exam.getExamPaperId()); |
| | | paperMarkVO.setTotalScore(examPaper.getScore() + ""); |
| | | paperMarkVO.setDeductType(examPaper.getDeductType()); |
| | | paperMarkVO.setDeductScore(examPaper.getDeductTypeScore()); |
| | |
| | | examPaperScore.setTotalScore(new BigDecimal(examPaperMark.getTotalScore())); |
| | | examPaperScore.setJudgeUser(userId); |
| | | examPaperScore.setJudgeTime(new Date()); |
| | | examPaperScore.setPaperContent(JSON.toJSONString(examPaperMark.getTitleItems())); |
| | | examPaperScore.setNavbar(JSON.toJSONString(examPaperMark.getNavbar())); |
| | | if (!StringUtils.isEmpty(examPaperMark.getTitleItems())) { |
| | | examPaperScore.setPaperContent(JSON.toJSONString(examPaperMark.getTitleItems())); |
| | | } |
| | | if (!StringUtils.isEmpty(examPaperMark.getNavbar())) { |
| | | examPaperScore.setNavbar(JSON.toJSONString(examPaperMark.getNavbar())); |
| | | } |
| | | long questionCorrect = 0; |
| | | long questionCount = 0; |
| | | if (!CollectionUtils.isEmpty(examPaperMark.getNavbar())) { |
| | | questionCorrect = examPaperMark.getNavbar().stream().filter(ExamPaperMarkNavbarVO::getRight).count(); |
| | | examPaperScore.setStatus(ExamScoreConstant.PRESENT); |
| | | questionCorrect = examPaperMark.getNavbar().stream().filter(vo -> vo.getRight() != null && vo.getRight()).count(); |
| | | questionCount = examPaperMark.getNavbar().size(); |
| | | } else { |
| | | //缺考查试卷配置 |
| | | Integer paperId = examPaperMark.getPaperId(); |
| | | ExamPaper examPaper = examPaperMapper.selectById(paperId); |
| | | questionCount = examPaper.getNum(); |
| | | examPaperScore.setStatus(ExamScoreConstant.ABSENT); |
| | | } |
| | | examPaperScore.setQuestionCorrect(Integer.valueOf(questionCorrect + "")); |
| | | examPaperScore.setQuestionCount(Integer.valueOf(questionCount + "")); |
| | |
| | | examPaperScoreMapper.updateById(examPaperScore); |
| | | } else { |
| | | examPaperScoreMapper.insert(examPaperScore); |
| | | //修改考试里试卷状态为已阅卷 |
| | | ExamSubmitTemp userExam = new LambdaQueryChainWrapper<>(examSubmitTempMapper) |
| | | .eq(ExamSubmitTemp::getExamId, examPaperMark.getExamId()) |
| | | .eq(ExamSubmitTemp::getUserId, examPaperMark.getUserId()) |
| | | .one(); |
| | | if (userExam != null) { |
| | | userExam.setMarkPaperStatus(ExamSubmitTempStatusEnum.finish); |
| | | examSubmitTempMapper.updateById(userExam); |
| | | } |
| | | } |
| | | return Result.ok(); |
| | | } |
| | |
| | | @Override |
| | | public Result monitorList(ExamQuery query) { |
| | | IPage<ExamSubmitTempVO> page = PageUtil.getPage(query, ExamSubmitTempVO.class); |
| | | return Result.ok((examSubmitTempMapper.monitorList(page, query))); |
| | | IPage<ExamSubmitTempVO> vo = examSubmitTempMapper.monitorList(page, query); |
| | | |
| | | return Result.ok(vo); |
| | | } |
| | | |
| | | @Override |
| | | public Result addTime(AddTimeForm form) { |
| | | if (!websocketServer.checkUserOnline(form.getUserId())) { |
| | | throw new RuntimeException("该学员不在线,无法执行该操作"); |
| | | } |
| | | WebsocketDataVO websocket = new WebsocketDataVO(); |
| | | websocket.setCommend(WebsocketCommendEnum.DELAYED.getCommend()); |
| | | websocket.setCommend(WebsocketCommendEnum.DELAYED.getCommand()); |
| | | BigDecimal sed = BigDecimal.valueOf(60).multiply(form.getAddTimeM()); |
| | | form.setAddTimeM(sed); |
| | | websocket.setData(form); |
| | | // 发送websocket消息 |
| | | websocketServer.sendOneMessage(form.getUserId(), JSON.toJSONString(form)); |
| | | websocketServer.sendOneMessage(form.getUserId(), JSON.toJSONString(websocket)); |
| | | return Result.ok("操作成功"); |
| | | } |
| | | |
| | | @Override |
| | | public Result forceSubmit(ForceSubmitForm form) { |
| | | if (!websocketServer.checkUserOnline(form.getUserId())) { |
| | | throw new RuntimeException("该学员不在线,无法执行该操作"); |
| | | } |
| | | WebsocketDataVO websocket = new WebsocketDataVO(); |
| | | websocket.setCommend(WebsocketCommendEnum.FORCE_SUBMIT.getCommend()); |
| | | websocket.setCommend(WebsocketCommendEnum.FORCE_SUBMIT.getCommand()); |
| | | websocket.setData(form); |
| | | // 发送websocket消息 |
| | | websocketServer.sendOneMessage(form.getUserId(), JSON.toJSONString(form)); |
| | | websocketServer.sendOneMessage(form.getUserId(), JSON.toJSONString(websocket)); |
| | | return Result.ok("操作成功"); |
| | | } |
| | | |
| | | /** |
| | | * 作废 |
| | | * |
| | | * @param id |
| | | * @return {@link Result } |
| | | * @author |
| | | */ |
| | | @Override |
| | | public Result cancel(Integer id) { |
| | | new LambdaUpdateChainWrapper<>(examMapper) |
| | | .eq(Exam::getId, id) |
| | | .set(Exam::getStatus, ExamStatusEnum.CANCEL) |
| | | .update(); |
| | | return Result.ok("作废成功"); |
| | | } |
| | | |
| | | @Override |
| | | public Result recover(Integer id) { |
| | | // 先查询当前考试记录的详细信息 |
| | | Exam examInfo = new LambdaQueryChainWrapper<>(examMapper) |
| | | .eq(Exam::getId, id) |
| | | .one(); |
| | | // 确定恢复后当前考试记录的状态 |
| | | Date currentTime = new Date(); |
| | | Date startTime = examInfo.getStartTime(); |
| | | Date endTime = examInfo.getEndTime(); |
| | | ExamStatusEnum statusByTime = ExamStatusEnum.getStatusByTime(startTime, endTime, currentTime); |
| | | examInfo.setStatus(statusByTime); |
| | | // 修改当前的考试状态 |
| | | new LambdaUpdateChainWrapper<>(examMapper) |
| | | .eq(Exam::getId, id) |
| | | .set(Exam::getStatus, examInfo.getStatus()) |
| | | .update(); |
| | | // 还原班级的考试信息 |
| | | return Result.ok("考试记录已经恢复正常"); |
| | | } |
| | | } |