xiangpei
2024-11-12 318d743292e40a939619cd9425066e10d67cf482
src/main/java/com/ycl/jxkg/service/impl/ExamServiceImpl.java
@@ -2,13 +2,17 @@
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.*;
@@ -29,6 +33,7 @@
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.*;
@@ -75,6 +80,7 @@
    private final UserMapper userMapper;
    private final ExamPaperScoreMapper examPaperScoreMapper;
    private final ExamPaperScoreService examPaperScoreService;
    private final QuestionAnswerRecordMapper questionAnswerRecordMapper;
    private final Producer producer;
@@ -89,10 +95,20 @@
        Exam entity = ExamForm.getEntityByForm(form, null);
        entity.setStatus(ExamStatusEnum.getStatusByTime(form.getStartTime(), form.getEndTime(), null));
        entity.setTeacherId(webContext.getCurrentUser().getId());
        // 设置乐观锁版本
        entity.setUpdateVersion(0);
        if (baseMapper.insert(entity) > 0) {
            this.sendMQ(entity, 0);
        // 查出考试试卷
        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("添加成功");
    }
@@ -113,12 +129,20 @@
            throw new RuntimeException("只能修改还未开始的考试");
        }
        BeanUtils.copyProperties(form, entity);
        entity.setStatus(ExamStatusEnum.getStatusByTime(form.getStartTime(), form.getEndTime(), null));
        // 如果修改成功发送mq消息
        if (baseMapper.updateById(entity) > 0) {
            this.sendMQ(entity, entity.getUpdateVersion() + 1);
        }
        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("修改成功");
    }
@@ -211,6 +235,7 @@
                item.setExamPaperId(null);
            }
        });
        //
        return Result.ok().data(page.getRecords()).total(page.getTotal());
    }
@@ -219,9 +244,103 @@
    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)
@@ -250,6 +369,10 @@
                .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());
@@ -292,6 +415,9 @@
                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());
@@ -336,7 +462,9 @@
                    childQuestionList.addAll(childQuestions);
                }
                paperFixQuestionVO.setQuestionList(childQuestionList);
                examData.add(paperFixQuestionVO);
                if (! CollectionUtils.isEmpty(childQuestionList)) {
                    examData.add(paperFixQuestionVO);
                }
            }
        }
        ExamSubmitTemp examSubmitTemp = new ExamSubmitTemp();
@@ -374,6 +502,23 @@
                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 -> {
@@ -384,24 +529,6 @@
                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())) {
@@ -432,10 +559,21 @@
     * @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);
    }
@@ -507,7 +645,6 @@
        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)) {
@@ -558,14 +695,21 @@
        for (StudentExamInfoVO studentExamInfoVO : studentExamList) {
            Integer userId = studentExamInfoVO.getUserId();
            Optional<ExamSubmitTemp> first = examSubmitTempList.stream().filter(examSubmitTemp -> examSubmitTemp.getUserId().equals(userId)).findFirst();
            if(first.isPresent()){
            if (first.isPresent()) {
                ExamSubmitTemp examSubmitTemp = first.get();
                studentExamInfoVO.setMarkPaperStatus(examSubmitTemp.getMarkPaperStatus());
                studentExamInfoVO.setStatus(examSubmitTemp.getStatus());
                studentExamInfoVO.setDoTime(examSubmitTemp.getDoTime());
            }else {
                studentExamInfoVO.setMarkPaperStatus(ExamSubmitTempStatusEnum.temp);
            } 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);
            }
        }
@@ -586,20 +730,22 @@
    @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);
@@ -618,28 +764,35 @@
        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;
@@ -817,16 +970,23 @@
    //封装阅卷返回数据
    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());
@@ -845,13 +1005,26 @@
        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 (!org.springframework.util.CollectionUtils.isEmpty(examPaperMark.getTitleItems())) {
            examPaperScore.setPaperContent(JSON.toJSONString(examPaperMark.getTitleItems()));
            // 保存答题记录
            this.saveQuestionAnswerRecord(examPaperMark.getUserId(), examPaperMark.getTitleItems());
        }
        if (!org.springframework.util.CollectionUtils.isEmpty(examPaperMark.getNavbar())) {
            examPaperScore.setNavbar(JSON.toJSONString(examPaperMark.getNavbar()));
        }
        long questionCorrect = 0;
        long questionCount = 0;
        if (!CollectionUtils.isEmpty(examPaperMark.getNavbar())) {
            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 + ""));
@@ -867,36 +1040,108 @@
                    .eq(ExamSubmitTemp::getExamId, examPaperMark.getExamId())
                    .eq(ExamSubmitTemp::getUserId, examPaperMark.getUserId())
                    .one();
            userExam.setMarkPaperStatus(ExamSubmitTempStatusEnum.finish);
            examSubmitTempMapper.updateById(userExam);
            if (userExam != null) {
                userExam.setMarkPaperStatus(ExamSubmitTempStatusEnum.finish);
                examSubmitTempMapper.updateById(userExam);
            }
        }
        return Result.ok();
    }
    /**
     * 保存答题记录
     *
     * @param titleItems
     */
    private void saveQuestionAnswerRecord(Integer studentUserId, List<PaperFixQuestionVO> titleItems) {
        for (PaperFixQuestionVO titleItem : titleItems) {
            for (DoQuestionVO question : titleItem.getQuestionList()) {
                QuestionAnswerRecord record = new QuestionAnswerRecord();
                record.setQuestionType(titleItem.getQuestionType());
                record.setUserId(studentUserId);
                record.setDoRight(question.getRight());
                record.setExamId(question.getExamId());
                record.setQuestionId(question.getId());
                record.setScore(question.getScore());
                record.setUserAnswer(StringUtils.hasText(question.getAnswer()) ? question.getAnswer() : question.getAnswerList().stream().collect(Collectors.joining("、")));
                questionAnswerRecordMapper.insert(record);
            }
        }
    }
    @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("考试记录已经恢复正常");
    }
}