src/main/java/com/ycl/jxkg/domain/entity/ExamPaper.java
@@ -23,12 +23,6 @@ private String name; /** * 学科 */ @TableField("subject_id") private Integer subjectId; /** * 试卷类型( 1固定试卷 2.随即试卷 3.随序试卷) */ @TableField("paper_type") src/main/java/com/ycl/jxkg/domain/exam/PaperQuestionSettingDTO.java
@@ -9,15 +9,8 @@ public class PaperQuestionSettingDTO { //标题(单选题(20分)...) private String title; //题目类别 private Integer questionType; //随机试卷题目数量 private Integer num; //随机试卷题目分数 private BigDecimal score; //题目难度 private Integer difficult; //学科id private Integer subjectId; //题目配置 List<PaperSettingItem> settingList; } src/main/java/com/ycl/jxkg/domain/exam/PaperSettingItem.java
File was renamed from src/main/java/com/ycl/jxkg/domain/exam/SettingDTO.java @@ -5,10 +5,10 @@ import java.math.BigDecimal; @Data public class SettingDTO { //随机试卷题目数量 public class PaperSettingItem { //题目数量 private Integer num; //随机试卷题目分数 //题目分数 private BigDecimal score; //题目难度 private Integer difficult; src/main/java/com/ycl/jxkg/domain/form/ExamPaperForm.java
@@ -31,12 +31,6 @@ private String name; /** * 学科 */ @NotNull(message = "学科不能为空", groups = {Add.class, Update.class}) private Integer subjectId; /** * 试卷类型( 1固定试卷 2.随即试卷 3.随序试卷) */ @NotNull (message = "试卷类型不能为空", groups = {Add.class, Update.class}) src/main/java/com/ycl/jxkg/domain/question/RandomQuestionDTO.java
@@ -5,5 +5,7 @@ @Data public class RandomQuestionDTO { private Integer questionId; private Integer subjectId; private Integer questionType; private Integer difficult; } src/main/java/com/ycl/jxkg/domain/vo/admin/exam/ExamPaperPageRequestVO.java
@@ -13,8 +13,6 @@ private String name; private Integer subjectId; private Integer paperType; private Integer suggestTime; src/main/java/com/ycl/jxkg/mapper/ClassesUserMapper.java
@@ -40,7 +40,7 @@ * @param classesId * @return */ List<StudentExamInfoVO> getClassesUserList(@Param("examId") Integer examId,@Param("classesId") Integer classesId); List<StudentExamInfoVO> getClassesUserList(@Param("classesId") Integer classesId); /** * 根据学生获取班级 src/main/java/com/ycl/jxkg/mapper/QuestionMapper.java
@@ -30,7 +30,7 @@ */ List<Question> getAnswerInfo(@Param("questionIds") List<Integer> questionIds); List<RandomQuestionDTO> selectBySubject(@Param("subjectId") Integer subjectId, @Param("types") List<Integer> types); Integer selectByDifAndSub(RandomQuestionDTO dto); /** * 获取随机题 @@ -40,5 +40,5 @@ * @param num 数量 * @return */ List<Question> getRandomQuestion(@Param("subjectId") Integer subjectId, @Param("questionType") Integer questionType, @Param("num") Integer num); List<Question> getRandomQuestion(@Param("subjectId") Integer subjectId, @Param("questionType") Integer questionType,@Param("difficult") Integer difficult, @Param("num") Integer num); } src/main/java/com/ycl/jxkg/service/impl/ExamPaperScoreServiceImpl.java
@@ -192,7 +192,7 @@ examPaperScoreDetail.setQuestionId(question.getId()); examPaperScoreDetail.setExamPaperId(examPaper.getId()); examPaperScoreDetail.setQuestionScore(null); examPaperScoreDetail.setSubjectId(examPaper.getSubjectId()); // examPaperScoreDetail.setSubjectId(examPaper.getSubjectId()); examPaperScoreDetail.setItemOrder(itemOrder); examPaperScoreDetail.setCreateTime(now); examPaperScoreDetail.setCreateUser(user.getId()); src/main/java/com/ycl/jxkg/service/impl/ExamPaperServiceImpl.java
@@ -16,6 +16,7 @@ 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.ExamPaperForm; import com.ycl.jxkg.domain.other.KeyValue; import com.ycl.jxkg.domain.question.QuestionItemObject; @@ -45,6 +46,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.math.BigDecimal; import java.util.*; @@ -71,18 +73,24 @@ if (ExamPaperTypeEnum.Random.getCode().equals(form.getPaperType())) { //校验题目数量 List<PaperQuestionSettingDTO> questionSetting = form.getQuestionSetting(); //题目配置里配的试卷类型 List<Integer> types = questionSetting.stream().map(PaperQuestionSettingDTO::getQuestionType).collect(Collectors.toList()); Map<Integer, List<Integer>> map = questionMapper.selectBySubject(form.getSubjectId(), types) .stream().collect(Collectors.groupingBy(RandomQuestionDTO::getQuestionType, Collectors.mapping(RandomQuestionDTO::getQuestionId, Collectors.toList()))); for (PaperQuestionSettingDTO settingDTO : questionSetting) { Integer num = settingDTO.getNum(); Integer questionType = settingDTO.getQuestionType(); //需要配置的题目数量为0则跳过 if(num ==null || num ==0 )continue; List<Integer> questions = map.get(questionType); if(CollectionUtils.isEmpty(questions) || num > questions.size())return Result.fail(SystemCode.InnerError.getCode(), QuestionTypeEnum.fromCode(questionType).getName()+"题目数量不足"); for (PaperSettingItem item : settingDTO.getSettingList()) { Integer num = item.getNum(); Integer difficult = item.getDifficult(); //需要配置的题目数量为0则跳过 if(num ==null || num ==0 )continue; //前端默认数据为0,转换为null if (0 == item.getDifficult()){ difficult= null; } RandomQuestionDTO randomQuestionDTO = new RandomQuestionDTO(); randomQuestionDTO.setQuestionType(questionType); randomQuestionDTO.setSubjectId(item.getSubjectId()); randomQuestionDTO.setDifficult(difficult); Integer numInData = questionMapper.selectByDifAndSub(randomQuestionDTO); if(num > numInData)return Result.fail(SystemCode.InnerError.getCode(), QuestionTypeEnum.fromCode(questionType).getName()+"难度为"+item.getDifficult()+"的题目数量不足"); } } examPaper.setContent(JSON.toJSONString(form.getQuestionSetting())); baseMapper.insert(examPaper); @@ -94,86 +102,61 @@ return Result.ok(); } else { //随序试卷 Integer subjectId = form.getSubjectId(); //题目配置 List<PaperQuestionSettingDTO> questionSetting = form.getQuestionSetting(); //题目配置里配的试卷类型 List<Integer> types = questionSetting.stream().map(PaperQuestionSettingDTO::getQuestionType).collect(Collectors.toList()); if (CollectionUtils.isEmpty(types)) { return Result.fail(SystemCode.InnerError.getCode(), "试卷题目类型不能为空"); } Map<Integer, List<Integer>> map = questionMapper.selectBySubject(subjectId, types) .stream().collect(Collectors.groupingBy(RandomQuestionDTO::getQuestionType, Collectors.mapping(RandomQuestionDTO::getQuestionId, Collectors.toList()))); List<PaperFixQuestionDTO> questionTitleList = new ArrayList<>(); // 遍历map for (Integer questionType : map.keySet()) { //数据库里的这个类型的题目 List<Integer> questionIdList = map.get(questionType); Result result = createQuestion(questionSetting, questionTitleList, questionType, questionIdList,QuestionTypeEnum.fromCode(questionType).getCode()); if (result != null) return result; for (PaperQuestionSettingDTO settingDTO : questionSetting) { List<PaperSettingItem> settingList = settingDTO.getSettingList(); List<PaperQuestion> questionList = new ArrayList<>(); for (PaperSettingItem item : settingList) { Integer num = item.getNum(); Integer difficult = item.getDifficult(); //需要配置的题目数量为0则跳过 if(num ==null || num ==0 )continue; //前端默认数据为0,转换为null if (0 == difficult){ difficult = null; } List<Question> questions = questionMapper.getRandomQuestion(item.getSubjectId(), settingDTO.getQuestionType(), difficult, item.getNum()); if (CollectionUtils.isEmpty(questions) || item.getNum() > questions.size()) { return Result.fail(SystemCode.InnerError.getCode(), QuestionTypeEnum.fromCode(settingDTO.getQuestionType()).getName()+"难度为:"+item.getDifficult()+"的题目数量不足"); } //转换数据 convert(questionList, item, questions); } PaperFixQuestionDTO dto = new PaperFixQuestionDTO(); dto.setTitle(settingDTO.getTitle()); dto.setQuestionType(settingDTO.getQuestionType()); dto.setQuestionList(questionList); questionTitleList.add(dto); } examPaper.setContent(JSON.toJSONString(questionTitleList)); baseMapper.insert(examPaper); return Result.ok(); } } //生成题目 private Result createQuestion(List<PaperQuestionSettingDTO> questionSetting, List<PaperFixQuestionDTO> questionTitleList, Integer questionType, List<Integer> questionIdList , Integer questionEnumCode) { if (questionType.equals(questionEnumCode)) { //循环找到对应题目 PaperQuestionSettingDTO settingDTO = new PaperQuestionSettingDTO(); for (PaperQuestionSettingDTO dto : questionSetting) { if (dto.getQuestionType().equals(questionType)) { settingDTO = dto; } }// 需要生成的题目数量 Integer num = settingDTO.getNum(); if(num ==null || num ==0 ){ //题目配置此类型数量为0,跳过,不生成题目。 return null; //转换数据 private void convert(List<PaperQuestion> questionList, PaperSettingItem item, List<Question> questions) { for (Question question : questions) { PaperQuestion paperQuestion = new PaperQuestion(); BeanUtils.copyProperties(question,paperQuestion); paperQuestion.setScore(item.getScore()); //转换 QuestionObject questionObject = JSONObject.parseObject(question.getContent(), QuestionObject.class); if(questionObject != null){ paperQuestion.setItems(questionObject.getQuestionItemObjects()); paperQuestion.setAnalyze(questionObject.getAnalyze()); paperQuestion.setTitle(questionObject.getTitleContent()); } if (CollectionUtils.isEmpty(questionIdList) || num > questionIdList.size()) { return Result.fail(SystemCode.InnerError.getCode(), QuestionTypeEnum.fromCode(questionType).getName()+"题目数量不足"); } // 使用Random类生成不重复的随机索引 Set<Integer> indexes = new HashSet<>(); Random random = new Random(); while (indexes.size() < num) { int index = random.nextInt(questionIdList.size()); indexes.add(index); } // 根据索引获取题目 List<Integer> questionIds = new ArrayList<>(); for (int index : indexes) { questionIds.add(questionIdList.get(index)); } QueryWrapper<Question> wrapper = new QueryWrapper<>(); wrapper.in("id",questionIds); List<Question> questions = questionMapper.selectList(wrapper); List<PaperQuestion> questionList = new ArrayList<>(); for (Question question : questions) { PaperQuestion paperQuestion = new PaperQuestion(); BeanUtils.copyProperties(question,paperQuestion); paperQuestion.setScore(settingDTO.getScore()); //转换 QuestionObject questionObject = JSONObject.parseObject(question.getContent(), QuestionObject.class); if(questionObject != null){ paperQuestion.setItems(questionObject.getQuestionItemObjects()); paperQuestion.setAnalyze(questionObject.getAnalyze()); paperQuestion.setTitle(questionObject.getTitleContent()); } questionList.add(paperQuestion); } PaperFixQuestionDTO dto = new PaperFixQuestionDTO(); dto.setTitle(settingDTO.getTitle()); dto.setQuestionType(questionType); dto.setQuestionList(questionList); questionTitleList.add(dto); questionList.add(paperQuestion); } return null; } @Override public Result updateExamPaper(ExamPaperForm form) { //TODO:验证是否是试卷创建人 src/main/java/com/ycl/jxkg/service/impl/ExamServiceImpl.java
@@ -14,6 +14,7 @@ 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; @@ -107,7 +108,7 @@ // 为空抛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); @@ -122,7 +123,7 @@ /** * 发送mq消息 * * @param entity 考试实体类 * @param entity 考试实体类 * @param version 乐观锁版本 */ public void sendMQ(Exam entity, Integer version) { @@ -283,50 +284,58 @@ PaperFixQuestionVO paperFixQuestionVO = new PaperFixQuestionVO(); paperFixQuestionVO.setTitle(paperSetting.getTitle()); paperFixQuestionVO.setQuestionType(paperSetting.getQuestionType()); // 拿到课目下某类题型的x道随机题 List<Question> questions = questionMapper.getRandomQuestion(examPaper.getSubjectId(), paperSetting.getQuestionType(), paperSetting.getNum()); if (paperSetting.getNum() > questions.size()) { throw new RuntimeException("配置的题目数不足以生成试卷"); } // 拿到题目后组装为可临时保存的题目结构 List<DoQuestionVO> childQuestions = questions.stream().map(item -> { DoQuestionVO doQuestionVO = new DoQuestionVO(); doQuestionVO.setTitle(item.getTitle()); doQuestionVO.setQuestionType(item.getQuestionType()); //从配置里拿题目分数 doQuestionVO.setQuestionScore(paperSetting.getScore()); if (StringUtils.hasText(item.getContent())) { QuestionObject questionObject = JSON.parseObject(item.getContent(), QuestionObject.class); doQuestionVO.setQuestionItemList(questionObject.getQuestionItemObjects()); //一个类型的题目list List<DoQuestionVO> childQuestionList = new ArrayList<>(); List<PaperSettingItem> settingList = paperSetting.getSettingList(); for (PaperSettingItem settingItem : settingList) { Integer num = settingItem.getNum(); Integer difficult = settingItem.getDifficult(); //需要配置的题目数量为0则跳过 if (num == null || num == 0) continue; List<Question> questions = questionMapper.getRandomQuestion(settingItem.getSubjectId(), paperSetting.getQuestionType(), difficult, settingItem.getNum()); if (org.springframework.util.CollectionUtils.isEmpty(questions) || settingItem.getNum() > questions.size()) { throw new RuntimeException("配置的题目数不足以生成试卷"); } doQuestionVO.setId(item.getId()); doQuestionVO.setOriginalFile(item.getOriginalFile()); doQuestionVO.setAudioFile(item.getAudioFile()); // 题目副本 QuestionAnswerCopyVO copy = new QuestionAnswerCopyVO(); copy.setId(item.getId()); copy.setDifficult(item.getDifficult()); copy.setAnalyze(JSON.parseObject(item.getContent(), PaperQuestion.class).getAnalyze()); //填空的答案在Json里 if (QuestionTypeEnum.GapFilling.getCode().equals(item.getQuestionType())) { List<String> gapAnswer = new ArrayList<>(); for (QuestionItemObject questionItemObject : doQuestionVO.getQuestionItemList()) { gapAnswer.add(questionItemObject.getContent()); // 拿到题目后组装为可临时保存的题目结构 List<DoQuestionVO> childQuestions = questions.stream().map(item -> { DoQuestionVO doQuestionVO = new DoQuestionVO(); doQuestionVO.setQuestionType(item.getQuestionType()); //从配置里拿题目分数 doQuestionVO.setQuestionScore(settingItem.getScore()); if (StringUtils.hasText(item.getContent())) { QuestionObject questionObject = JSON.parseObject(item.getContent(), QuestionObject.class); doQuestionVO.setQuestionItemList(questionObject.getQuestionItemObjects()); doQuestionVO.setTitle(questionObject.getTitleContent()); } copy.setCorrect(String.join(ANSWER_SPLIT, gapAnswer)); } else { copy.setCorrect(item.getCorrect()); } questionAnswerCopyVOList.add(copy); doQuestionVO.setId(item.getId()); doQuestionVO.setOriginalFile(item.getOriginalFile()); doQuestionVO.setAudioFile(item.getAudioFile()); return doQuestionVO; }).collect(Collectors.toList()); paperFixQuestionVO.setQuestionList(childQuestions); // 题目副本 QuestionAnswerCopyVO copy = new QuestionAnswerCopyVO(); copy.setId(item.getId()); copy.setDifficult(item.getDifficult()); copy.setAnalyze(JSON.parseObject(item.getContent(), PaperQuestion.class).getAnalyze()); //填空的答案在Json里 if (QuestionTypeEnum.GapFilling.getCode().equals(item.getQuestionType())) { List<String> gapAnswer = new ArrayList<>(); for (QuestionItemObject questionItemObject : doQuestionVO.getQuestionItemList()) { gapAnswer.add(questionItemObject.getContent()); } copy.setCorrect(String.join(ANSWER_SPLIT, gapAnswer)); } else { copy.setCorrect(item.getCorrect()); } questionAnswerCopyVOList.add(copy); return doQuestionVO; }).collect(Collectors.toList()); //添加到这个类型的list中 childQuestionList.addAll(childQuestions); } paperFixQuestionVO.setQuestionList(childQuestionList); examData.add(paperFixQuestionVO); } return Result.ok(startExamVO); } ExamSubmitTemp examSubmitTemp = new ExamSubmitTemp(); examSubmitTemp.setExamId(id); @@ -533,7 +542,7 @@ throw new RuntimeException("考试试卷不存在"); } List<ExamSubmitTemp> examSubmitTempList = new LambdaQueryChainWrapper<>(examSubmitTempMapper) .eq(ExamSubmitTemp::getDeleted,0) .eq(ExamSubmitTemp::getDeleted, 0) .eq(ExamSubmitTemp::getExamId, id) .list(); // 参考人数 @@ -541,15 +550,23 @@ // 参考但未完成提交人数 Integer joinButNotFinishedNum = Math.toIntExact(examSubmitTempList.stream().filter(item -> ExamSubmitTempStatusEnum.temp.equals(item.getStatus())).count()); List<StudentExamInfoVO> studentExamList = classesUserMapper.getClassesUserList(exam.getId(), exam.getClassesId()); List<StudentExamInfoVO> studentExamList = classesUserMapper.getClassesUserList(exam.getClassesId()); // 应考人数 Integer shouldUserNum = studentExamList.size(); studentExamList.stream().forEach(item -> { if (StringUtils.hasText(item.getExamSubmit())) { item.setQuestionList(JSON.parseArray(item.getExamSubmit(), DoQuestionVO.class)); for (StudentExamInfoVO studentExamInfoVO : studentExamList) { Integer userId = studentExamInfoVO.getUserId(); Optional<ExamSubmitTemp> first = examSubmitTempList.stream().filter(examSubmitTemp -> examSubmitTemp.getUserId().equals(userId)).findFirst(); if(first.isPresent()){ ExamSubmitTemp examSubmitTemp = first.get(); studentExamInfoVO.setMarkPaperStatus(examSubmitTemp.getMarkPaperStatus()); studentExamInfoVO.setStatus(examSubmitTemp.getStatus()); studentExamInfoVO.setDoTime(examSubmitTemp.getDoTime()); }else { studentExamInfoVO.setMarkPaperStatus(ExamSubmitTempStatusEnum.temp); studentExamInfoVO.setStatus(ExamSubmitTempStatusEnum.temp); studentExamInfoVO.setDoTime(0); } }); } MarkPaperVO markPaperVO = new MarkPaperVO(); markPaperVO.setExamName(exam.getExamName()); @@ -831,7 +848,7 @@ long questionCorrect = 0; long questionCount = 0; if (!CollectionUtils.isEmpty(examPaperMark.getNavbar())) { questionCorrect = examPaperMark.getNavbar().stream().filter(vo -> vo.getRight()!=null && vo.getRight()).count(); questionCorrect = examPaperMark.getNavbar().stream().filter(vo -> vo.getRight() != null && vo.getRight()).count(); questionCount = examPaperMark.getNavbar().size(); } examPaperScore.setQuestionCorrect(Integer.valueOf(questionCorrect + "")); src/main/resources/mapper/ClassesUserMapper.xml
@@ -57,17 +57,12 @@ SELECT TU.id, TU.real_name, TU.phone, EST.do_time, EST.status, EST.exam_submit, EST.mark_paper_status TU.phone FROM t_classes_user TCU INNER JOIN t_user TU ON TU.id = TCU.user_id AND TCU.classes_id = #{classesId} LEFT JOIN t_exam_submit_temp EST ON EST.user_id = TU.id WHERE TCU.deleted = 0 and EST.deleted = 0 and EST.exam_id = #{examId} TCU.deleted = 0 </select> <select id="getClassesByUserId" resultType="java.lang.Integer"> src/main/resources/mapper/ExamMapper.xml
@@ -19,12 +19,6 @@ <result column="isContinue" property="isContinue" /> </resultMap> <select id="getById" resultMap="BaseResultMap"> SELECT TE.exam_name, src/main/resources/mapper/ExamPaperMapper.xml
@@ -4,7 +4,6 @@ <resultMap id="BaseResultMap" type="com.ycl.jxkg.domain.entity.ExamPaper"> <id column="id" property="id"/> <result column="name" property="name"/> <result column="subject_id" property="subjectId"/> <result column="paper_type" property="paperType"/> <result column="score" property="score"/> <result column="question_count" property="questionCount"/> @@ -19,7 +18,7 @@ </resultMap> <sql id="Base_Column_List"> id, name, subject_id, paper_type, score, question_count, suggest_time,visibility id, name, paper_type, score, question_count, suggest_time,visibility ,deduct_type,deduct_type_score,create_user, create_time,deleted </sql> @@ -41,9 +40,6 @@ </if> <if test="name != null and name != ''"> and tep.name like concat('%',#{name},'%') </if> <if test="subjectId != null "> and tep.subject_id= #{subjectId} </if> <if test="paperType != null "> and tep.paper_type= #{paperType} @@ -68,9 +64,6 @@ FROM t_exam_paper <where> and deleted=0 <if test="subjectId != null "> and subject_id=#{subjectId} </if> <if test="levelId != null "> and grade_level=#{levelId} </if> src/main/resources/mapper/QuestionMapper.xml
@@ -92,18 +92,15 @@ <foreach collection="questionIds" open="(" item="id" close=")" separator=",">#{id}</foreach> </select> <select id="selectBySubject" resultType="com.ycl.jxkg.domain.question.RandomQuestionDTO"> SELECT id as questionId,question_type FROM t_question WHERE subject_id = #{subjectId} and question_type in <foreach collection="types" item="type" separator="," open="(" close=")"> #{type} </foreach> and deleted = 0 and status = 1 <select id="selectByDifAndSub" resultType="java.lang.Integer"> SELECT COUNT(*) FROM t_question <where> deleted = 0 and status = 1 <if test="subjectId!=null">and subject_id = #{subjectId}</if> <if test="difficult!=null">AND difficult = #{difficult}</if> <if test="questionType!=null">AND question_type = #{questionType}</if> </where> </select> <select id="getRandomQuestion" resultMap="BaseResultMap"> @@ -111,10 +108,14 @@ * FROM t_question tq WHERE tq.subject_id = #{subjectId} AND tq.question_type = #{questionType} AND tq.deleted = 0 <where> tq.deleted = 0 and tq.status = 1 <if test="subjectId!=null">and tq.subject_id = #{subjectId}</if> <if test="difficult!=null">AND tq.difficult = #{difficult}</if> <if test="questionType!=null">AND tq.question_type = #{questionType}</if> </where> ORDER BY RAND() RAND() LIMIT #{num} </select> </mapper>