package com.ruoyi.web.service; import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.util.DateUtils; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.enums.ExamineeStatus; import com.ruoyi.enums.PaperStatus; import com.ruoyi.enums.PaperType; import com.ruoyi.ie.domain.AMarjorPlan; import com.ruoyi.ie.service.IAMarjorPlanService; import com.ruoyi.learn.domain.*; import com.ruoyi.learn.mapper.*; import com.ruoyi.learn.service.ILearnPaperService; import com.ruoyi.system.service.ISysUserService; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.validation.ValidationException; import java.util.*; import java.util.stream.Collectors; /** * 考试服务 */ @Service public class ExamService { private final LearnAnswerMapper learnAnswerMapper; private final LearnExamineeMapper learnExamineeMapper; private final LearnStudentMapper learnStudentMapper; private Set paperTypeSet = Sets.newHashSet(PaperType.Real, PaperType.Custom, PaperType.Test); private final LearnPaperMapper paperMapper; private final LearnKnowledgeTreeMapper knowledgeTreeMapper; private final LearnExamineeMapper examineeMapper; private final ILearnPaperService learnPaperService; private final PaperService paperService; private final IAMarjorPlanService marjorPlanService; private final ISysUserService sysUserService; public ExamService(LearnPaperMapper paperMapper, LearnKnowledgeTreeMapper knowledgeTreeMapper, LearnExamineeMapper examineeMapper, ILearnPaperService learnPaperService, PaperService paperService, IAMarjorPlanService marjorPlanService, LearnAnswerMapper learnAnswerMapper, LearnExamineeMapper learnExamineeMapper, ISysUserService sysUserService, LearnStudentMapper learnStudentMapper) { this.paperMapper = paperMapper; this.knowledgeTreeMapper = knowledgeTreeMapper; this.examineeMapper = examineeMapper; this.learnPaperService = learnPaperService; this.paperService = paperService; this.marjorPlanService = marjorPlanService; this.learnAnswerMapper = learnAnswerMapper; this.learnExamineeMapper = learnExamineeMapper; this.sysUserService = sysUserService; this.learnStudentMapper = learnStudentMapper; } /** * 开卷 (卷, 实时组卷) * @return */ @Transactional(rollbackFor = Exception.class) public AnswerSheet openExaminee(boolean directed, PaperType paperType, Long relatedId) { if(paperTypeSet.contains(paperType)) { return openExaminee(paperType, relatedId, SecurityUtils.getUserId()); } else if(PaperType.Practice.equals(paperType)) { return openExaminee(relatedId, SecurityUtils.getUserId(), getDirectedKey(directed)); } else if(PaperType.Simulated.equals(paperType)) { SysUser exist = sysUserService.selectUserById(SecurityUtils.getUserId()); return openExaminee(relatedId, exist); } throw new RuntimeException("错误类型: " + paperType); } private String getDirectedKey(boolean directed) { if(!directed) { return ""; } LearnStudent ls = learnStudentMapper.selectLearnStudentByStudentId(SecurityUtils.getUserId()); return StringUtils.trimToEmpty(ls.getDirectKey()); } public AnswerSheet loadExaminee(Long examineeId, Boolean examContinue) { LearnExaminee examinee = examineeMapper.selectLearnExamineeByExamineeId(examineeId); if(examContinue) { if(ExamineeStatus.Sign.getVal().equals(examinee.getState())) { LearnExaminee upExaminee = new LearnExaminee(); upExaminee.setExamineeId(examineeId); upExaminee.setBeginTime(new Date()); upExaminee.setState(ExamineeStatus.Exam.getVal()); examineeMapper.updateLearnExaminee(upExaminee); } else if(!ExamineeStatus.Exam.getVal().equals(examinee.getState())) { throw new RuntimeException("已考完的卷不能继续做"); } } else if(ExamineeStatus.Exam.getVal().equals(examinee.getState())) { throw new RuntimeException("考试中,不能提取答案"); } LearnAnswer aCond = new LearnAnswer(); aCond.setExamineeId(examineeId); Map answerMap = learnAnswerMapper.selectLearnAnswerList(aCond).stream().collect(Collectors.toMap(LearnAnswer::getQuestionId, t -> t)); LearnPaper learnPaper = learnPaperService.selectLearnPaperById(examinee.getPaperId()); List questionList = paperService.loadPaperQuestionAnswers(examinee.getPaperId(), answerMap, !examContinue); AnswerSheet answerSheet = buildAnswerSheet(learnPaper, examinee); answerSheet.setTotalCount(questionList.size()); answerSheet.setWrongCount(examinee.getWrongCount()); answerSheet.setQuestions(questionList); return answerSheet; } /** * 交卷 * @param answerSheet */ @Transactional(rollbackFor = Exception.class) public void commitAnswerSheet(AnswerSheet answerSheet) { LearnExaminee exitExaminee = learnExamineeMapper.selectLearnExamineeByExamineeId(answerSheet.getExamineeId()); if(null == exitExaminee) { throw new RuntimeException("无此答卷" + answerSheet.getExamineeId()); } LearnAnswer aCond = new LearnAnswer(); aCond.setExamineeId(answerSheet.getExamineeId()); Map answerMap = learnAnswerMapper.selectLearnAnswerList(aCond).stream().collect(Collectors.toMap(LearnAnswer::getQuestionId, t -> t)); Map questionMap = paperService.loadPaperQuestionAnswers(answerSheet.getPaperId(), answerMap, true).stream().collect(Collectors.toMap(PaperVO.QuestionAnswer::getId, t -> t)); List addList = Lists.newArrayList(); List updateList = Lists.newArrayList(); Integer wrongCount = 0; for(PaperVO.QuestionAnswer question : answerSheet.getQuestions()) { if(CollectionUtils.isNotEmpty(question.getSubQuestions())) { for(PaperVO.QuestionAnswer sq : question.getSubQuestions()) { LearnAnswer answer = buildAnswer(answerSheet, questionMap, sq, addList, updateList); if(answerSheet.getIsDone() && !answer.getState().equals(1L)) { wrongCount++; } } } else { LearnAnswer answer = buildAnswer(answerSheet, questionMap, question, addList, updateList); if(answerSheet.getIsDone() && !answer.getState().equals(1L)) { wrongCount++; } } } if(addList.size() > 0) { addList.stream().forEach(t -> { learnAnswerMapper.insertLearnAnswer(t); }); } if(updateList.size() > 0) { updateList.stream().forEach(t -> { learnAnswerMapper.updateLearnAnswer(t); }); } LearnExaminee upExaminee = new LearnExaminee(); upExaminee.setExamineeId(answerSheet.getExamineeId()); upExaminee.setDuration(answerSheet.getDuration()); if(answerSheet.getIsDone()) { upExaminee.setEndTime(new Date()); upExaminee.setState(ExamineeStatus.Commit.getVal()); upExaminee.setWrongCount(wrongCount); } learnExamineeMapper.updateLearnExaminee(upExaminee); if(answerSheet.getIsDone()) { // 关闭试卷 LearnPaper up = new LearnPaper(); up.setId(answerSheet.getPaperId()); up.setStatus(PaperStatus.Valid.getVal()); paperMapper.updateLearnPaper(up); } } private LearnAnswer buildAnswer(AnswerSheet answerSheet, Map questionMap, PaperVO.QuestionAnswer question, List addList, List updateList) { LearnAnswer answer = new LearnAnswer(); PaperVO.QuestionAnswer exist = questionMap.remove(question.getId()); if(null == exist) { answer.setExamineeId(answerSheet.getExamineeId()); answer.setStudentId(SecurityUtils.getUserId()); answer.setQuestionId(question.getId()); answer.setSeq(question.getSeq()); answer.setKnowledgeId(answerSheet.getKnowledgeId()); addList.add(answer); } else { answer.setAnswerId(exist.getAnswerId()); updateList.add(answer); } answer.setAnswer(StringUtils.join(question.getAnswers(), ",")); answer.setState(question.calcState(answerSheet.getIsDone())); return answer; } private AnswerSheet openExaminee(PaperType paperType, Long paperId, Long studentId) { LearnPaper paper = paperMapper.selectLearnPaperById(paperId); LearnExaminee learnExaminee = new LearnExaminee(); learnExaminee.setStudentId(studentId); learnExaminee.setPaperId(paperId); learnExaminee.setPaperType(paperType.getVal()); learnExaminee.setState(ExamineeStatus.Exam.getVal()); List examineeList = examineeMapper.selectLearnExamineeList(learnExaminee); if (CollectionUtils.isNotEmpty(examineeList)) { learnExaminee = examineeList.get(0); } else { learnExaminee.setState(ExamineeStatus.Exam.getVal()); learnExaminee.setBeginTime(new Date()); learnExaminee.setDuration(0L); examineeMapper.insertLearnExaminee(learnExaminee); } return buildAnswerSheet(paper, learnExaminee); } private AnswerSheet openExaminee(Long planId, SysUser sysUser) { AMarjorPlan plan = marjorPlanService.selectAMarjorPlanById(planId); if(null == plan) { throw new ValidationException("专业id无效"); } LearnExaminee examinee = new LearnExaminee(); examinee.setStudentId(SecurityUtils.getLoginUser().getUser().getUserId()); examinee.setPaperType(PaperType.Simulated.getVal()); List examineeList = examineeMapper.selectLearnExamineeList(examinee); Set existPaperIdSet = Sets.newHashSet(); for(LearnExaminee e : examineeList) { if((ExamineeStatus.Exam.getVal().equals(e.getState()) || ExamineeStatus.Sign.getVal().equals(e.getState())) && e.getPaperKey().equals(planId.toString())) { return buildAnswerSheet(learnPaperService.selectLearnPaperById(e.getPaperId()), e); } existPaperIdSet.add(e.getPaperId()); } if(existPaperIdSet.size() >= sysUser.getEvalCount()) { throw new ValidationException("超过最大次数限制" + sysUser.getEvalCount() ); } SysUser upUser = new SysUser(); upUser.setUserId(sysUser.getUserId()); upUser.setEvalCount(sysUser.getEvalCount() - 1); sysUserService.updateUserProfile(upUser); LearnPaper paper = getBestPaper(plan, existPaperIdSet); examinee.setPaperKey(paper.getId().toString()); examinee.setState(ExamineeStatus.Sign.getVal()); examinee.setDuration(0L); examineeMapper.insertLearnExaminee(examinee); return buildAnswerSheet(paper, examinee); } /** * 根据知识点生成一次性练习卷并开始做题 * @return */ private AnswerSheet openExaminee(Long knowledgeId, Long studentId, String directKey) { LearnKnowledgeTree knowledgeTree = knowledgeTreeMapper.selectLearnKnowledgeTreeById(knowledgeId); LearnPaper paper = new LearnPaper(); paper.setPaperType(PaperType.Practice.name()); paper.setRelateId(knowledgeId); paper.setYear(Calendar.getInstance().get(Calendar.YEAR)); paper.setStatus(PaperStatus.TmpValid.getVal()); paper.setDirectKey(studentId + "_" + StringUtils.trimToEmpty(directKey)); List paperList = paperMapper.selectLearnPaperList(paper); if (CollectionUtils.isNotEmpty(paperList)) { // 有未做完的 LearnPaper existPaper = paperList.get(0); LearnExaminee learnExaminee = new LearnExaminee(); learnExaminee.setStudentId(studentId); learnExaminee.setPaperId(existPaper.getId()); learnExaminee.setPaperType(PaperType.Practice.getVal()); learnExaminee.setState(ExamineeStatus.Exam.getVal()); List examineeList = examineeMapper.selectLearnExamineeList(learnExaminee); if (CollectionUtils.isNotEmpty(examineeList)) { LearnExaminee examinee = examineeList.get(0); LearnAnswer aCond = new LearnAnswer(); aCond.setExamineeId(examinee.getExamineeId()); Map answerMap = learnAnswerMapper.selectLearnAnswerList(aCond).stream().collect(Collectors.toMap(LearnAnswer::getQuestionId, t -> t)); List questionList = paperService.loadPaperQuestionAnswers(examinee.getPaperId(), answerMap, false); AnswerSheet answerSheet = buildAnswerSheet(existPaper, examinee); answerSheet.setQuestions(questionList); answerSheet.setKnowledgeId(existPaper.getRelateId()); return answerSheet; } // 关闭试卷 LearnPaper up = new LearnPaper(); up.setId(learnExaminee.getPaperId()); up.setStatus(PaperStatus.Valid.getVal()); paperMapper.updateLearnPaper(up); } TestPaperVO.PaperDef paperDef = new TestPaperVO.PaperDef(); paperDef.setTotal(15L); paperDef.setFillExclude(true); paperDef.setKnowIds(Lists.newArrayList(knowledgeId)); List typeDefList= Lists.newArrayList(); typeDefList.add(new TestPaperVO.TypeDef("单选题", "单选题", 10, 1)); typeDefList.add(new TestPaperVO.TypeDef("判断题", "判断题", 5, 2)); paperDef.setTypes(typeDefList); List pqList = paperService.getQuestions(studentId, paperDef); paper.setPaperSource(0); paper.setSubjectId(knowledgeTree.getSubjectId()); paper.setPaperName(studentId + "-" + knowledgeTree.getName() + "-" + DateUtils.format(new Date(), "yyyyMMddHHmmss")); paper.setRelateId(knowledgeId); paperService.savePaper(paper, pqList); LearnExaminee learnExaminee = new LearnExaminee(); learnExaminee.setStudentId(studentId); learnExaminee.setPaperType(PaperType.Practice.getVal()); learnExaminee.setPaperId(paper.getId()); learnExaminee.setPaperKey(String.valueOf(knowledgeId)); learnExaminee.setState(ExamineeStatus.Exam.getVal()); learnExaminee.setBeginTime(new Date()); learnExaminee.setDuration(0L); examineeMapper.insertLearnExaminee(learnExaminee); AnswerSheet answerSheet = buildAnswerSheet(paper, learnExaminee); answerSheet.setKnowledgeId(paper.getRelateId()); return answerSheet; } private LearnPaper getBestPaper(AMarjorPlan plan, Set existPaperIdSet) { String groupName = StringUtils.trimToEmpty(plan.getMajorGroup()); LearnPaper paperCond = new LearnPaper(); paperCond.setPaperType(PaperType.Simulated.name()); for(int i = 3; i>0; i--) { if(i == 3) { paperCond.setDirectKey(plan.getUniversityId() + "_" + groupName + "_" + plan.getMajorName()); } else if(i == 2) { paperCond.setDirectKey(plan.getUniversityId() + "_" + groupName); } else if(StringUtils.isBlank(groupName)) { break; } List paperList = learnPaperService.selectLearnPaperList(paperCond); for(LearnPaper paper : paperList) { if(existPaperIdSet.add(paper.getId())) { return paper; } } } throw new ValidationException("未初始化院校定向模拟题库: " + plan.getId()); } private AnswerSheet buildAnswerSheet(LearnPaper paper, LearnExaminee examinee) { AnswerSheet answerSheet = new AnswerSheet(); answerSheet.setExamineeId(examinee.getExamineeId()); answerSheet.setPaperId(examinee.getPaperId()); answerSheet.setName(paper.getPaperName()); answerSheet.setBeginTime(examinee.getBeginTime()); if(StringUtils.isNotBlank(paper.getConditions())) { answerSheet.setConditions(JSONObject.parseObject(paper.getConditions(), AnswerSheet.PaperCond.class)); } answerSheet.setScoringType("1"); answerSheet.setMode(0L); answerSheet.setState(examinee.getState()); answerSheet.setAllowAnswer(true); answerSheet.setAllowScore(false); return answerSheet; } }