package com.ycl.jxkg.service.impl;
|
|
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.domain.query.ExamQuery;
|
import com.ycl.jxkg.domain.question.QuestionItemObject;
|
import com.ycl.jxkg.domain.question.QuestionObject;
|
import com.ycl.jxkg.domain.vo.*;
|
import com.ycl.jxkg.domain.vo.admin.exam.ExamPaperMarkNavbarVO;
|
import com.ycl.jxkg.domain.vo.admin.exam.ExamPaperMarkVO;
|
import com.ycl.jxkg.enums.DeductTypeEnum;
|
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;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.stereotype.Service;
|
import org.springframework.util.Assert;
|
import org.springframework.util.StringUtils;
|
|
import java.math.BigDecimal;
|
import java.math.RoundingMode;
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
/**
|
* 考试 服务实现类
|
*
|
* @author xp
|
* @since 2024-06-11
|
*/
|
@Service
|
@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 ExamSubmitTempMapper examSubmitTempMapper;
|
private final ClassesUserMapper classesUserMapper;
|
private final ExamPaperMapper examPaperMapper;
|
private final ExamPaperService examPaperService;
|
private final WebsocketServer websocketServer;
|
private final UserMapper userMapper;
|
private final ExamPaperScoreMapper examPaperScoreMapper;
|
private final ExamPaperScoreService examPaperScoreService;
|
private final QuestionAnswerRecordMapper questionAnswerRecordMapper;
|
|
private final Producer producer;
|
|
/**
|
* 添加
|
*
|
* @param form
|
* @return
|
*/
|
@Override
|
public Result add(ExamForm form) {
|
Exam entity = ExamForm.getEntityByForm(form, null);
|
entity.setStatus(ExamStatusEnum.getStatusByTime(form.getStartTime(), form.getEndTime(), null));
|
entity.setTeacherId(webContext.getCurrentUser().getId());
|
|
// 查出考试试卷
|
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("添加成功");
|
}
|
|
/**
|
* 修改
|
*
|
* @param form
|
* @return
|
*/
|
@Override
|
public Result update(ExamForm form) {
|
Exam entity = baseMapper.selectById(form.getId());
|
// 为空抛IllegalArgumentException,做全局异常处理
|
Assert.notNull(entity, "记录不存在");
|
// 判断考试状态
|
if (!ExamStatusEnum.NOT_START.equals(entity.getStatus())) {
|
throw new RuntimeException("只能修改还未开始的考试");
|
}
|
BeanUtils.copyProperties(form, 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;
|
}
|
}
|
|
/**
|
* 批量删除
|
*
|
* @param ids
|
* @return
|
*/
|
@Override
|
public Result remove(List<String> ids) {
|
baseMapper.deleteBatchIds(ids);
|
return Result.ok("删除成功");
|
}
|
|
/**
|
* id删除
|
*
|
* @param id
|
* @return
|
*/
|
@Override
|
public Result removeById(String id) {
|
baseMapper.deleteById(id);
|
return Result.ok("删除成功");
|
}
|
|
/**
|
* 分页查询
|
*
|
* @param query
|
* @return
|
*/
|
@Override
|
public Result page(ExamQuery query) {
|
IPage<ExamVO> page = PageUtil.getPage(query, ExamVO.class);
|
baseMapper.getPage(page, query, webContext.getCurrentUser().getId());
|
page.getRecords().stream().forEach(item -> {
|
if (!StringUtils.hasText(item.getClassName())) {
|
item.setClassName("班级不存在或被删除");
|
item.setClassesId(null);
|
}
|
if (!StringUtils.hasText(item.getExamPaperName())) {
|
item.setExamPaperName("试卷不存在或被删除");
|
item.setExamPaperId(null);
|
}
|
});
|
//
|
return Result.ok().data(page.getRecords()).total(page.getTotal());
|
}
|
|
|
@Override
|
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)
|
public Result start(Integer id) {
|
Exam exam = baseMapper.selectById(id);
|
if (Objects.isNull(exam)) {
|
throw new RuntimeException("该考试不存在");
|
}
|
if (Objects.isNull(exam.getExamPaperId())) {
|
throw new RuntimeException("考试未绑定试卷");
|
}
|
if (ExamStatusEnum.NOT_START.equals(exam.getStatus())) {
|
throw new RuntimeException("考试还未开始");
|
}
|
if (ExamStatusEnum.FINISHED.equals(exam.getStatus())) {
|
throw new RuntimeException("考试已经结束");
|
}
|
// 查出考试试卷
|
ExamPaper examPaper = examPaperMapper.selectById(exam.getExamPaperId());
|
if (Objects.isNull(examPaper)) {
|
throw new RuntimeException("试卷不存在");
|
}
|
// 如果已经参加过考试,直接返回数据
|
ExamSubmitTemp hasJoin = new LambdaQueryChainWrapper<>(examSubmitTempMapper)
|
.eq(ExamSubmitTemp::getExamId, id)
|
.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());
|
startExamVO.setTitleList(JSON.parseArray(hasJoin.getExamSubmit(), PaperFixQuestionVO.class));
|
startExamVO.setSuggestTime(examPaper.getSuggestTime());
|
startExamVO.setDoTime(hasJoin.getDoTime());
|
return Result.ok(startExamVO);
|
}
|
// 响应数据
|
StartExamVO startExamVO = new StartExamVO();
|
startExamVO.setExamName(exam.getExamName());
|
startExamVO.setId(exam.getId());
|
startExamVO.setSuggestTime(examPaper.getSuggestTime());
|
// 试卷内容
|
List<PaperFixQuestionVO> examData = new ArrayList<>();
|
// 拿到题目副本数据
|
List<QuestionAnswerCopyVO> questionAnswerCopyVOList = new ArrayList<>(32);
|
// 将题目转换为可临时保存的题目结构。固定试卷和随序试卷的题目是直接保存到content字段的
|
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);
|
}
|
}
|
}
|
ExamSubmitTemp examSubmitTemp = new ExamSubmitTemp();
|
examSubmitTemp.setExamId(id);
|
examSubmitTemp.setStatus(ExamSubmitTempStatusEnum.temp);
|
examSubmitTemp.setExamSubmit(JSON.toJSONString(examData));
|
examSubmitTemp.setCreateTime(new Date());
|
examSubmitTemp.setUserId(webContext.getCurrentUser().getId());
|
examSubmitTemp.setMarkPaperStatus(ExamSubmitTempStatusEnum.temp);
|
examSubmitTemp.setQuestionAnswerCopy(JSON.toJSONString(questionAnswerCopyVOList));
|
examSubmitTempMapper.insert(examSubmitTemp);
|
startExamVO.setTitleList(examData);
|
return Result.ok(startExamVO);
|
}
|
|
/**
|
* 将数据库存储的题目,转为可临时保存的题目结构
|
*
|
* @param examPaper 试卷
|
* @param questionAnswerCopyVOList 题目副本集合
|
* @return
|
*/
|
private List<PaperFixQuestionVO> coverTo(ExamPaper examPaper, List<QuestionAnswerCopyVO> questionAnswerCopyVOList) {
|
if (!StringUtils.hasText(examPaper.getContent())) {
|
throw new RuntimeException("试卷未配置题目,请联系老师");
|
}
|
List<PaperFixQuestionDTO> questionWarpList = JSON.parseArray(examPaper.getContent(), PaperFixQuestionDTO.class);
|
return questionWarpList.stream().map(item -> {
|
PaperFixQuestionVO vo = new PaperFixQuestionVO();
|
vo.setTitle(item.getTitle());
|
vo.setQuestionType(item.getQuestionType());
|
List<DoQuestionVO> doQuestionVOS = item.getQuestionList().stream().map(question -> {
|
DoQuestionVO doQuestionVO = new DoQuestionVO();
|
doQuestionVO.setTitle(question.getTitle());
|
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 -> {
|
option.setContent("");
|
});
|
}
|
doQuestionVO.setQuestionItemList(question.getItems());
|
doQuestionVO.setId(question.getId());
|
doQuestionVO.setOriginalFile(question.getOriginalFile());
|
doQuestionVO.setAudioFile(question.getAudioFile());
|
return doQuestionVO;
|
}).collect(Collectors.toList());
|
if (ExamPaperTypeEnum.RandomOrder.getCode().equals(examPaper.getPaperType())) {
|
// 随序试卷打乱顺序
|
Collections.shuffle(doQuestionVOS);
|
}
|
vo.setQuestionList(doQuestionVOS);
|
return vo;
|
}).collect(Collectors.toList());
|
}
|
|
/**
|
* 根据id查找
|
*
|
* @param id
|
* @return
|
*/
|
@Override
|
public Result detail(Integer id) {
|
ExamVO vo = baseMapper.getById(id);
|
Assert.notNull(vo, "记录不存在");
|
return Result.ok().data(vo);
|
}
|
|
/**
|
* 列表
|
*
|
* @return
|
*/
|
@Override
|
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 vo = new ExamVO();
|
vo = ExamVO.getVoByEntity(entity, vo);
|
vo.setStatus(entity.getStatus().getDesc());
|
return vo;
|
})
|
.collect(Collectors.toList());
|
return Result.ok().data(vos);
|
}
|
|
/**
|
* 主动提交试卷
|
*
|
* @param submitData 试卷做题提交数据
|
* @return
|
*/
|
@Override
|
public Result examSubmit(StartExamVO submitData) {
|
// 校验
|
Exam exam = examMapper.selectById(submitData.getId());
|
if (Objects.isNull(exam)) {
|
throw new RuntimeException("该考试不存在");
|
}
|
// // 判断单选、多选、判断题对错
|
// List<Integer> questionIds = new ArrayList<>(24);
|
// submitData.getPaperQuestionList().forEach(item -> {
|
// List<Integer> ids = item.getQuestionList().stream().map(DoQuestionVO::getId).collect(Collectors.toList());
|
// questionIds.addAll(ids);
|
// });
|
// List<Question> questionList = questionMapper.getAnswerInfo(questionIds);
|
// Map<Integer, Question> answerMap = questionList.stream().collect(Collectors.toMap(Question::getId, entity -> entity));
|
// submitData.getQuestionList().stream().forEach(item -> {
|
// Question question = answerMap.get(item.getId());
|
// if (Objects.nonNull(question)
|
// && (QuestionTypeEnum.SingleChoice.getCode().equals(question.getQuestionType())
|
// || QuestionTypeEnum.MultipleChoice.getCode().equals(question.getQuestionType())
|
// || QuestionTypeEnum.TrueFalse.getCode().equals(question.getQuestionType())
|
// )) {
|
// String correct = question.getCorrect();
|
// if (QuestionTypeEnum.MultipleChoice.getCode().equals(question.getQuestionType())) {
|
// // 如果是选择题,那么将答案转为list
|
// List<String> answerList = JSON.parseArray(correct, String.class);
|
// item.setRight(answerList.containsAll(item.getAnswerList()));
|
// } else {
|
// item.setRight(question.getCorrect().equals(item.getAnswer()));
|
// }
|
// }
|
// });
|
// 阅卷后才往exam_paper_answer保存考试成绩、以及保存到exam_paper_customer_answer
|
// 现在只需要保存到一张临时表
|
// 该接口是主动提交,所以状态都设置为完成,以便后续老师阅卷
|
saveTempExam(submitData, ExamSubmitTempStatusEnum.finish);
|
return Result.ok();
|
}
|
|
/**
|
* 临时保存试卷
|
*
|
* @param submitData
|
* @return
|
*/
|
@Override
|
public Result timingSubmit(StartExamVO submitData) {
|
saveTempExam(submitData, ExamSubmitTempStatusEnum.temp);
|
return Result.ok();
|
}
|
|
/**
|
* 保存试卷:如果接口是定时保存那么是临时试卷。如果接口是自主提交那么是完成试卷
|
*
|
* @param submitData 前端传递的试卷数据
|
* @param status 试卷的状态
|
*/
|
public void saveTempExam(StartExamVO submitData, ExamSubmitTempStatusEnum status) {
|
ExamSubmitTemp one = new LambdaQueryChainWrapper<>(examSubmitTempMapper)
|
.eq(ExamSubmitTemp::getExamId, submitData.getId())
|
.eq(ExamSubmitTemp::getUserId, webContext.getCurrentUser().getId())
|
.one();
|
|
if (Objects.nonNull(one)) {
|
if (ExamSubmitTempStatusEnum.finish.equals(one.getStatus())) {
|
return;
|
}
|
Date now = new Date();
|
one.setExamSubmit(JSON.toJSONString(submitData.getTitleList()));
|
one.setUpdateTime(now);
|
int doTimeInSeconds = (int) (now.getTime() - one.getCreateTime().getTime()) / 1000;
|
one.setDoTime(doTimeInSeconds);
|
one.setStatus(status);
|
examSubmitTempMapper.updateById(one);
|
} else {
|
ExamSubmitTemp examSubmitTemp = new ExamSubmitTemp();
|
examSubmitTemp.setExamId(submitData.getId());
|
examSubmitTemp.setDoTime(0);
|
examSubmitTemp.setStatus(status);
|
examSubmitTemp.setUserId(webContext.getCurrentUser().getId());
|
examSubmitTemp.setExamSubmit(JSON.toJSONString(submitData.getTitleList()));
|
examSubmitTemp.setMarkPaperStatus(ExamSubmitTempStatusEnum.temp);
|
examSubmitTempMapper.insert(examSubmitTemp);
|
}
|
}
|
|
@Override
|
public Result getMarkResultInfo(Integer id) {
|
Exam exam = baseMapper.selectById(id);
|
if (Objects.isNull(exam)) {
|
throw new RuntimeException("该考试不存在");
|
}
|
ExamPaper examPaper = examPaperMapper.selectById(exam.getExamPaperId());
|
if (Objects.isNull(examPaper)) {
|
throw new RuntimeException("考试试卷不存在");
|
}
|
List<ExamSubmitTemp> examSubmitTempList = new LambdaQueryChainWrapper<>(examSubmitTempMapper)
|
.eq(ExamSubmitTemp::getDeleted, 0)
|
.eq(ExamSubmitTemp::getExamId, id)
|
.list();
|
// 参考人数
|
Integer joinExamNum = examSubmitTempList.size();
|
// 参考但未完成提交人数
|
Integer joinButNotFinishedNum = Math.toIntExact(examSubmitTempList.stream().filter(item -> ExamSubmitTempStatusEnum.temp.equals(item.getStatus())).count());
|
|
List<StudentExamInfoVO> studentExamList = classesUserMapper.getClassesUserList(exam.getClassesId());
|
// 应考人数
|
Integer shouldUserNum = studentExamList.size();
|
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());
|
markPaperVO.setExamId(exam.getId());
|
markPaperVO.setJoinButNotFinishNum(joinButNotFinishedNum);
|
markPaperVO.setShouldJoinNum(shouldUserNum);
|
markPaperVO.setStudentExamInfoVOList(studentExamList);
|
markPaperVO.setMissJoinNum(shouldUserNum - joinExamNum);
|
markPaperVO.setJoinNum(joinExamNum);
|
markPaperVO.setExamPaperName(examPaper.getName());
|
markPaperVO.setSuggestTime(examPaper.getSuggestTime());
|
return Result.ok().data(markPaperVO);
|
}
|
|
|
@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)) {
|
//缺考,学生没有做题信息
|
ExamPaperMarkVO paperMarkVO = createVO(null, exam, student);
|
return Result.ok(paperMarkVO);
|
}
|
//封装阅卷基本数据
|
ExamPaperMarkVO paperMarkVO = createVO(userExam, exam, student);
|
List<QuestionAnswerCopyVO> answerList = JSONArray.parseArray(userExam.getQuestionAnswerCopy(), QuestionAnswerCopyVO.class);
|
//补充题目答案、解析
|
addAnswer(paperMarkVO, answerList);
|
//阅卷,客观题打分
|
Result InnerError = markPaper(paperMarkVO);
|
if (InnerError != null) return InnerError;
|
|
return Result.ok(paperMarkVO);
|
}
|
|
//补充题目答案、解析
|
private void addAnswer(ExamPaperMarkVO paperMarkVO, List<QuestionAnswerCopyVO> answerList) {
|
List<PaperFixQuestionVO> titleItems = paperMarkVO.getTitleItems();
|
for (PaperFixQuestionVO titleItem : titleItems) {
|
for (DoQuestionVO doQuestionVO : titleItem.getQuestionList()) {
|
Integer questionId = doQuestionVO.getId();
|
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, 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() + "");
|
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;
|
}
|
|
|
//阅卷
|
private Result markPaper(ExamPaperMarkVO paperMarkVO) {
|
List<PaperFixQuestionVO> titleItems = paperMarkVO.getTitleItems();
|
//初始化题目序号
|
Integer num = 1;
|
BigDecimal score = BigDecimal.ZERO;
|
//前端导航数组
|
List<ExamPaperMarkNavbarVO> navbar = new ArrayList<>();
|
//过滤掉题目为空的题目类型
|
titleItems = titleItems.stream().filter(paperFixQuestionVO -> !CollectionUtils.isEmpty(paperFixQuestionVO.getQuestionList())).collect(Collectors.toList());
|
|
for (PaperFixQuestionVO titleItem : titleItems) {
|
for (DoQuestionVO doQuestionVO : titleItem.getQuestionList()) {
|
//准备题目序号供前端跳转使用
|
ExamPaperMarkNavbarVO navbarVO = new ExamPaperMarkNavbarVO();
|
//获取试卷类型
|
Integer questionType = doQuestionVO.getQuestionType();
|
/* 如果是简答、计算、分析,不设置right只设置题目序号 */
|
if (QuestionTypeEnum.ShortAnswer.getCode().equals(questionType) || QuestionTypeEnum.Calculate.getCode().equals(questionType) || QuestionTypeEnum.Analysis.getCode().equals(questionType)) {
|
navbarVO.setItemOrder(num);
|
doQuestionVO.setItemOrder(num);
|
}
|
/* 如果是单选、语音、判断(判断答案是A、B) */
|
else if (QuestionTypeEnum.SingleChoice.getCode().equals(questionType) || QuestionTypeEnum.Audio.getCode().equals(questionType) || QuestionTypeEnum.TrueFalse.getCode().equals(questionType)) {
|
navbarVO.setItemOrder(num);
|
doQuestionVO.setItemOrder(num);
|
if (StringUtils.isEmpty(doQuestionVO.getQuestionAnswer())) {
|
return Result.fail(SystemCode.InnerError.getCode(), "题目id为:" + doQuestionVO.getId() + "的题目缺少答案,请先完善");
|
}
|
score = trueOrFalse(score, doQuestionVO, navbarVO, doQuestionVO.getQuestionAnswer().equals(doQuestionVO.getAnswer()));
|
}
|
/* 如果是多选 */
|
else if (QuestionTypeEnum.MultipleChoice.getCode().equals(questionType)) {
|
navbarVO.setItemOrder(num);
|
doQuestionVO.setItemOrder(num);
|
if (StringUtils.isEmpty(doQuestionVO.getQuestionAnswer())) {
|
return Result.fail(SystemCode.InnerError.getCode(), "题目id为:" + doQuestionVO.getId() + "的题目缺少答案,请先完善");
|
}
|
//学生答案
|
List<String> answerList = doQuestionVO.getAnswerList();
|
String questionAnswer = doQuestionVO.getQuestionAnswer();
|
//题目答案
|
List<String> questionAnswerList = Arrays.asList(questionAnswer.split(","));
|
//学生答案为空,判断为错
|
if (CollectionUtils.isEmpty(answerList)) {
|
score = trueOrFalse(score, doQuestionVO, navbarVO, false);
|
num++;
|
navbar.add(navbarVO);
|
continue;
|
}
|
//答案数量,不需要考虑顺序
|
int answerCount = answerList.size();
|
Set<String> set1 = new HashSet<>(answerList);
|
Set<String> set2 = new HashSet<>(questionAnswerList);
|
//答案完全一致,满分
|
if (set1.equals(set2)) {
|
score = trueOrFalse(score, doQuestionVO, navbarVO, true);
|
num++;
|
navbar.add(navbarVO);
|
continue;
|
}
|
if (paperMarkVO.getDeductType() == null) {
|
return Result.fail(SystemCode.InnerError.getCode(), "试卷没有配置多选得分类型,请联系管理员");
|
}
|
//如果多选得分类型为 答错不得分
|
if (Integer.valueOf(DeductTypeEnum.AllCorrect.getCode()).equals(paperMarkVO.getDeductType())) {
|
score = trueOrFalse(score, doQuestionVO, navbarVO, false);
|
}
|
//如果多选得分类型为 漏选得固定分值,包含错误选项不得分
|
else if (Integer.valueOf(DeductTypeEnum.PartCorrect.getCode()).equals(paperMarkVO.getDeductType())) {
|
//学生答案移除所有正确答案,如果还有元素说明包含错误选项
|
answerList.removeAll(questionAnswerList);
|
if (!CollectionUtils.isEmpty(answerList)) {
|
score = trueOrFalse(score, doQuestionVO, navbarVO, false);
|
} else {
|
navbarVO.setRight(false);
|
doQuestionVO.setRight(false);
|
//漏选得固定分
|
doQuestionVO.setScore(paperMarkVO.getDeductScore());
|
score = score.add(doQuestionVO.getScore());
|
}
|
}
|
//如果多选得分类型为 每对一题得相应分值,包含错误选项不得分
|
else if (Integer.valueOf(DeductTypeEnum.EachCorrect.getCode()).equals(paperMarkVO.getDeductType())) {
|
//学生答案移除所有正确答案,如果还有元素说明包含错误选项
|
answerList.removeAll(questionAnswerList);
|
if (!CollectionUtils.isEmpty(answerList)) {
|
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());
|
}
|
}
|
}
|
/* 如果是填空 */
|
else if (QuestionTypeEnum.GapFilling.getCode().equals(questionType)) {
|
navbarVO.setItemOrder(num);
|
doQuestionVO.setItemOrder(num);
|
if (StringUtils.isEmpty(doQuestionVO.getQuestionAnswer())) {
|
return Result.fail(SystemCode.InnerError.getCode(), "题目id为:" + doQuestionVO.getId() + "的题目缺少答案,请先完善");
|
}
|
//学生答案
|
List<String> answerList = doQuestionVO.getAnswerList();
|
String questionAnswer = doQuestionVO.getQuestionAnswer();
|
//题目答案
|
List<String> questionAnswerList = Arrays.asList(questionAnswer.split(","));
|
//学生答案为空,判断为错
|
if (CollectionUtils.isEmpty(answerList)) {
|
score = trueOrFalse(score, doQuestionVO, navbarVO, false);
|
num++;
|
navbar.add(navbarVO);
|
continue;
|
}
|
//总空的数量
|
int questionAnswerCount = questionAnswerList.size();
|
//答案完全一致,满分
|
if (answerList.equals(questionAnswerList)) {
|
score = trueOrFalse(score, doQuestionVO, navbarVO, true);
|
} else {
|
navbarVO.setRight(false);
|
doQuestionVO.setRight(false);
|
//做对的数量,需要按顺序比较
|
int count = 0;
|
for (int i = 0; i < answerList.size(); i++) {
|
if (answerList.get(i).equals(questionAnswerList.get(i))) {
|
count++;
|
}
|
}
|
//这个题的总分
|
BigDecimal questionScore = doQuestionVO.getQuestionScore();
|
//每个空的分数
|
BigDecimal scoreEach = questionScore.divide(new BigDecimal(questionAnswerCount), 1, RoundingMode.DOWN);
|
//填空得分
|
BigDecimal gapScore = scoreEach.multiply(new BigDecimal(count));
|
doQuestionVO.setScore(gapScore);
|
score = score.add(doQuestionVO.getScore());
|
}
|
|
}
|
num++;
|
navbar.add(navbarVO);
|
}
|
}
|
paperMarkVO.setTitleItems(titleItems);
|
paperMarkVO.setNavbar(navbar);
|
paperMarkVO.setScore(score + "");
|
return null;
|
}
|
|
//设置全对或全错
|
private BigDecimal trueOrFalse(BigDecimal score, DoQuestionVO doQuestionVO, ExamPaperMarkNavbarVO orderVO, Boolean isCorrect) {
|
if (isCorrect) {
|
//正确
|
orderVO.setRight(isCorrect);
|
doQuestionVO.setRight(isCorrect);
|
doQuestionVO.setScore(doQuestionVO.getQuestionScore());
|
score = score.add(doQuestionVO.getQuestionScore());
|
} else {
|
//错误
|
orderVO.setRight(isCorrect);
|
doQuestionVO.setRight(isCorrect);
|
doQuestionVO.setScore(BigDecimal.ZERO);
|
}
|
return score;
|
}
|
|
//封装阅卷返回数据
|
private ExamPaperMarkVO createVO(ExamSubmitTemp userExam, ExamVO exam, User student) {
|
ExamPaperMarkVO paperMarkVO = new ExamPaperMarkVO();
|
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.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());
|
return paperMarkVO;
|
}
|
|
//提交批改
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public Result submitMarkPaper(ExamPaperMarkVO examPaperMark) {
|
Integer userId = webContext.getCurrentUser().getId();
|
//插入exam_paper_answer(成绩表)
|
ExamPaperScore examPaperScore = new ExamPaperScore();
|
BeanUtils.copyProperties(examPaperMark, examPaperScore);
|
examPaperScore.setScore(new BigDecimal(examPaperMark.getScore()));
|
examPaperScore.setTotalScore(new BigDecimal(examPaperMark.getTotalScore()));
|
examPaperScore.setJudgeUser(userId);
|
examPaperScore.setJudgeTime(new Date());
|
if (!org.springframework.util.CollectionUtils.isEmpty(examPaperMark.getTitleItems())) {
|
examPaperScore.setPaperContent(JSON.toJSONString(examPaperMark.getTitleItems()));
|
// 保存答题记录
|
this.saveQuestionAnswerRecord(examPaperMark.getUserId(), examPaperMark.getTitleItems(), examPaperMark.getExamId(), examPaperMark.getPaperId());
|
}
|
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 + ""));
|
//找之前有无批改记录
|
ExamPaperScore score = examPaperScoreMapper.getByExamIdUserId(examPaperMark.getExamId(), examPaperMark.getUserId());
|
if (score != null) {
|
examPaperScore.setId(score.getId());
|
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();
|
}
|
|
/**
|
* 保存答题记录
|
*
|
* @param titleItems
|
*/
|
private void saveQuestionAnswerRecord(Integer studentUserId, List<PaperFixQuestionVO> titleItems, Integer examId, Integer paperId) {
|
// 删除原来的答题记录
|
new LambdaUpdateChainWrapper<>(questionAnswerRecordMapper)
|
.eq(QuestionAnswerRecord::getExamId, examId)
|
.eq(QuestionAnswerRecord::getUserId, studentUserId).remove();
|
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(examId);
|
record.setPaperId(paperId);
|
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);
|
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.getCommand());
|
BigDecimal sed = BigDecimal.valueOf(60).multiply(form.getAddTimeM());
|
form.setAddTimeM(sed);
|
websocket.setData(form);
|
// 发送websocket消息
|
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.getCommand());
|
websocket.setData(form);
|
// 发送websocket消息
|
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("考试记录已经恢复正常");
|
}
|
}
|