pom.xml
@@ -43,6 +43,14 @@ <dependencies> <!-- fastjson --> <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> <version>2.0.41</version> </dependency> <!-- swagger --> <dependency> <groupId>io.springfox</groupId> src/main/java/com/ycl/jxkg/controller/student/ExamController.java
New file @@ -0,0 +1,29 @@ package com.ycl.jxkg.controller.student; import com.ycl.jxkg.base.Result; import com.ycl.jxkg.domain.vo.ExamSubmitVO; import com.ycl.jxkg.service.ExamService; import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @author:xp * @date:2024/6/13 15:45 */ @RestController @RequiredArgsConstructor @RequestMapping(value = "/api/student/exampaper/answer") public class ExamController { private final ExamService examService; @PostMapping("/exam/submit") public Result examSubmit(@RequestBody @Validated ExamSubmitVO submitData) { return examService.examSubmit(submitData); } } src/main/java/com/ycl/jxkg/controller/student/ExamPaperAnswerController.java
@@ -7,6 +7,7 @@ import com.ycl.jxkg.domain.entity.Subject; import com.ycl.jxkg.domain.entity.User; import com.ycl.jxkg.domain.entity.UserEventLog; import com.ycl.jxkg.domain.vo.ExamSubmitVO; import com.ycl.jxkg.enums.ExamPaperAnswerStatusEnum; import com.ycl.jxkg.event.CalculateExamPaperAnswerCompleteEvent; import com.ycl.jxkg.event.UserEvent; @@ -25,6 +26,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.beans.BeanUtils; import org.springframework.context.ApplicationEventPublisher; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; @@ -80,7 +82,6 @@ eventPublisher.publishEvent(new UserEvent(userEventLog)); return Result.ok(scoreVm); } @RequestMapping(value = "/edit", method = RequestMethod.POST) public Result edit(@RequestBody @Valid ExamPaperSubmitVO examPaperSubmitVO) { src/main/java/com/ycl/jxkg/domain/entity/ExamSubmitTemp.java
New file @@ -0,0 +1,46 @@ package com.ycl.jxkg.domain.entity; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import java.io.Serializable; import java.util.Date; import com.ycl.jxkg.domain.base.AbsEntity; import com.ycl.jxkg.enums.general.ExamSubmitTempStatusEnum; import lombok.Data; /** * 提交试卷临时保存 * * @author xp * @since 2024-06-13 */ @Data @TableName("t_exam_submit_temp") public class ExamSubmitTemp extends AbsEntity { private static final long serialVersionUID = 1L; @TableField("exam_id") /** */ private Integer examId; @TableField("user_id") /** */ private Integer userId; @TableField("do_time") /** 做题耗时 秒 */ private Integer doTime; @TableField("exam_submit") /** 提交的试卷内容 */ private String examSubmit; @TableField("status") /** 状态:临时、保存 */ private ExamSubmitTempStatusEnum status; @TableField("create_time") private Date createTime; } src/main/java/com/ycl/jxkg/domain/query/ClassesUserQuery.java
@@ -18,5 +18,9 @@ @Data @ApiModel(value = "ClassesUser查询", description = "班级与用户关联表查询") public class ClassesUserQuery extends AbsQuery { /** 学员姓名 */ private String studentName; } src/main/java/com/ycl/jxkg/domain/vo/DoQuestionVO.java
New file @@ -0,0 +1,34 @@ package com.ycl.jxkg.domain.vo; import com.ycl.jxkg.domain.base.AbsVo; import lombok.Data; import java.util.List; /** * @author:xp * @date:2024/6/13 15:27 */ @Data public class DoQuestionVO extends AbsVo { /** 题目类型 */ private Integer questionType; /** 题干 */ private String titleContent; /** 学员答案 */ private String answer; /** 学员多选题答案 */ private List<String> answerList; /** 选项json,后端使用 */ private String content; /** 正确与否,后端判断后填充该值 */ private Boolean right; /** 题目选项 */ private List<QuestionItemVO> questionItemList; } src/main/java/com/ycl/jxkg/domain/vo/ExamSubmitTempVO.java
New file @@ -0,0 +1,48 @@ package com.ycl.jxkg.domain.vo; import com.ycl.jxkg.domain.base.AbsVo; import com.ycl.jxkg.domain.entity.ExamSubmitTemp; import java.util.List; import org.springframework.lang.NonNull; import org.springframework.beans.BeanUtils; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.util.Date; /** * 提交试卷临时保存展示 * * @author xp * @since 2024-06-13 */ @Data public class ExamSubmitTempVO extends AbsVo { /** */ private Integer examId; /** */ private Integer userId; /** 做题耗时 秒 */ private Integer doTime; /** 提交的试卷内容 */ private String examSubmit; /** */ private Date createTime; /** 状态:临时、保存 */ private String status; public static ExamSubmitTempVO getVoByEntity(@NonNull ExamSubmitTemp entity, ExamSubmitTempVO vo) { if(vo == null) { vo = new ExamSubmitTempVO(); } BeanUtils.copyProperties(entity, vo); return vo; } } src/main/java/com/ycl/jxkg/domain/vo/ExamSubmitVO.java
New file @@ -0,0 +1,23 @@ package com.ycl.jxkg.domain.vo; import lombok.Data; import java.util.List; /** * 提交试卷数据 * * @author:xp * @date:2024/6/13 15:19 */ @Data public class ExamSubmitVO { private Integer examId; /** 做题消耗时间 */ private Integer doTime; /** 题目 */ private List<DoQuestionVO> questionList; } src/main/java/com/ycl/jxkg/domain/vo/QuestionItemVO.java
New file @@ -0,0 +1,13 @@ package com.ycl.jxkg.domain.vo; import lombok.Data; /** * @author:xp * @date:2024/6/13 15:34 */ @Data public class QuestionItemVO { } src/main/java/com/ycl/jxkg/enums/QuestionTypeEnum.java
@@ -11,10 +11,11 @@ GapFilling(4, "填空题"), ShortAnswer(5, "简答题"), Calculation(6,"计算题"); int code; Integer code; String name; QuestionTypeEnum(int code, String name) { QuestionTypeEnum(Integer code, String name) { this.code = code; this.name = name; } @@ -43,21 +44,14 @@ } } public int getCode() { public Integer getCode() { return code; } public void setCode(int code) { this.code = code; } public String getName() { return name; } public void setName(String name) { this.name = name; } } src/main/java/com/ycl/jxkg/enums/general/ExamSubmitTempStatusEnum.java
New file @@ -0,0 +1,29 @@ package com.ycl.jxkg.enums.general; import com.baomidou.mybatisplus.annotation.EnumValue; import lombok.Getter; /** * 临时保存考试试卷 * * @author:xp * @date:2024/6/13 17:37 */ @Getter public enum ExamSubmitTempStatusEnum { TEMP("temp", "临时"), FINISH("finish", "完成"), ; @EnumValue private final String value; private final String desc; ExamSubmitTempStatusEnum(String value, String desc) { this.value = value; this.desc = desc; } } src/main/java/com/ycl/jxkg/mapper/ExamSubmitTempMapper.java
New file @@ -0,0 +1,25 @@ package com.ycl.jxkg.mapper; import com.ycl.jxkg.domain.entity.ExamSubmitTemp; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ycl.jxkg.domain.vo.ExamSubmitTempVO; import java.util.List; import org.apache.ibatis.annotations.Mapper; /** * 提交试卷临时保存 Mapper 接口 * * @author xp * @since 2024-06-13 */ @Mapper public interface ExamSubmitTempMapper extends BaseMapper<ExamSubmitTemp> { /** * id查找提交试卷临时保存 * @param id * @return */ ExamSubmitTempVO getById(Integer id); } src/main/java/com/ycl/jxkg/mapper/QuestionMapper.java
@@ -20,4 +20,12 @@ Integer selectAllCount(); List<KeyValue> selectCountByDate(@Param("startTime") Date startTime,@Param("endTime") Date endTime); /** * 获取题目:题型、答案 * * @param questionIds * @return */ List<Question> getAnswerInfo(@Param("questionIds") List<Integer> questionIds); } src/main/java/com/ycl/jxkg/service/ExamService.java
@@ -5,6 +5,8 @@ import com.ycl.jxkg.base.Result; import com.ycl.jxkg.domain.form.ExamForm; import com.ycl.jxkg.domain.query.ExamQuery; import com.ycl.jxkg.domain.vo.ExamSubmitVO; import java.util.List; /** @@ -62,4 +64,12 @@ * @return */ Result all(); /** * 考试提交 * * @param submitData * @return */ Result examSubmit(ExamSubmitVO submitData); } src/main/java/com/ycl/jxkg/service/impl/ExamServiceImpl.java
@@ -1,10 +1,20 @@ package com.ycl.jxkg.service.impl; import com.alibaba.fastjson2.JSON; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; import com.ycl.jxkg.context.WebContext; import com.ycl.jxkg.domain.entity.Exam; import com.ycl.jxkg.domain.entity.ExamSubmitTemp; import com.ycl.jxkg.domain.entity.Question; import com.ycl.jxkg.domain.vo.DoQuestionVO; import com.ycl.jxkg.domain.vo.ExamSubmitVO; import com.ycl.jxkg.enums.QuestionTypeEnum; import com.ycl.jxkg.enums.general.ExamStatusEnum; import com.ycl.jxkg.enums.general.ExamSubmitTempStatusEnum; import com.ycl.jxkg.mapper.ExamMapper; import com.ycl.jxkg.mapper.ExamSubmitTempMapper; import com.ycl.jxkg.mapper.QuestionMapper; import com.ycl.jxkg.service.ExamService; import com.ycl.jxkg.base.Result; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; @@ -17,7 +27,10 @@ import org.springframework.beans.BeanUtils; import org.springframework.util.Assert; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; /** @@ -32,9 +45,12 @@ private final ExamMapper examMapper; private final WebContext webContext; private final QuestionMapper questionMapper; private final ExamSubmitTempMapper examSubmitTempMapper; /** * 添加 * * @param form * @return */ @@ -49,6 +65,7 @@ /** * 修改 * * @param form * @return */ @@ -65,6 +82,7 @@ /** * 批量删除 * * @param ids * @return */ @@ -76,6 +94,7 @@ /** * id删除 * * @param id * @return */ @@ -87,6 +106,7 @@ /** * 分页查询 * * @param query * @return */ @@ -99,6 +119,7 @@ /** * 根据id查找 * * @param id * @return */ @@ -111,6 +132,7 @@ /** * 列表 * * @return */ @Override @@ -121,4 +143,55 @@ .collect(Collectors.toList()); return Result.ok().data(vos); } @Override public Result examSubmit(ExamSubmitVO submitData) { // 校验 Exam exam = examMapper.selectById(submitData.getExamId()); if (Objects.isNull(exam)) { throw new RuntimeException("该考试不存在"); } // 判断单选、多选、判断题对错 List<Integer> questionIds = submitData.getQuestionList().stream().map(DoQuestionVO::getId).collect(Collectors.toList()); 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 // 现在只需要保存到一张临时表 ExamSubmitTemp one = new LambdaQueryChainWrapper<>(examSubmitTempMapper) .eq(ExamSubmitTemp::getExamId, submitData.getExamId()) .eq(ExamSubmitTemp::getUserId, webContext.getCurrentUser().getId()) .one(); if (Objects.nonNull(one)) { one.setDoTime(submitData.getDoTime()); one.setExamSubmit(JSON.toJSONString(submitData.getQuestionList())); one.setCreateTime(new Date()); examSubmitTempMapper.updateById(one); } else { ExamSubmitTemp examSubmitTemp = new ExamSubmitTemp(); examSubmitTemp.setExamId(submitData.getExamId()); examSubmitTemp.setDoTime(submitData.getDoTime()); examSubmitTemp.setStatus(ExamSubmitTempStatusEnum.FINISH); examSubmitTemp.setUserId(webContext.getCurrentUser().getId()); examSubmitTemp.setExamSubmit(JSON.toJSONString(submitData.getQuestionList())); examSubmitTempMapper.insert(examSubmitTemp); } return Result.ok(); } } src/main/resources/mapper/ClassesUserMapper.xml
@@ -35,6 +35,7 @@ FROM t_classes_user TCU LEFT JOIN t_user TU ON TU.id = TCU.user_id WHERE TCU.deleted = 0 <if test="query.studentName != null and query.studentName != ''">AND TU.real_name like concat('%', #{query.studentName}, '%')</if> </select> </mapper> src/main/resources/mapper/ExamSubmitTempMapper.xml
New file @@ -0,0 +1,52 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.ycl.jxkg.mapper.ExamSubmitTempMapper"> <!-- 通用查询映射结果 --> <resultMap id="BaseResultMap" type="com.ycl.jxkg.domain.vo.ExamSubmitTempVO"> <result column="exam_id" property="examId" /> <result column="user_id" property="userId" /> <result column="do_time" property="doTime" /> <result column="exam_submit" property="examSubmit" /> <result column="create_time" property="createTime" /> <result column="status" property="status" /> </resultMap> <select id="getById" resultMap="BaseResultMap"> SELECT TEST.exam_id, TEST.user_id, TEST.do_time, TEST.exam_submit, TEST.create_time, TEST.status, TEST.id FROM t_exam_submit_temp TEST WHERE TEST.id = #{id} AND TEST.deleted = 0 </select> <select id="getPage" resultMap="BaseResultMap"> SELECT TEST.exam_id, TEST.user_id, TEST.do_time, TEST.exam_submit, TEST.create_time, TEST.status, TEST.id FROM t_exam_submit_temp TEST WHERE TEST.deleted = 0 </select> </mapper> src/main/resources/mapper/QuestionMapper.xml
@@ -15,13 +15,16 @@ <result column="deleted" jdbcType="BIT" property="deleted"/> </resultMap> <sql id="Base_Column_List"> id, question_type, subject_id, difficult, correct, content, create_user, status, create_time, deleted id , question_type, subject_id, difficult, correct, content, create_user, status, create_time, deleted </sql> <select id="page" resultType="com.ycl.jxkg.domain.vo.admin.question.QuestionResponseVO" parameterType="com.ycl.jxkg.domain.vo.admin.question.QuestionPageRequestVO"> <select id="page" resultType="com.ycl.jxkg.domain.vo.admin.question.QuestionResponseVO" parameterType="com.ycl.jxkg.domain.vo.admin.question.QuestionPageRequestVO"> SELECT tq.*, CASE WHEN tq.question_type = 1 THEN '单选题' WHEN tq.question_type = 2 THEN '多选题' WHEN tq.question_type = 3 THEN '判断题' WHEN tq.question_type = 4 THEN '填空题' WHEN tq.question_type = 5 THEN '简答题' END AS questionTypeName, CASE WHEN tq.question_type = 1 THEN '单选题' WHEN tq.question_type = 2 THEN '多选题' WHEN tq.question_type = 3 THEN '判断题' WHEN tq.question_type = 4 THEN '填空题' WHEN tq.question_type = 5 THEN '简答题' END AS questionTypeName, ts.name AS subjectName, tu.real_name AS createUserName FROM t_question tq @@ -36,10 +39,12 @@ and tq.status = #{status} </if> <if test="subjectId != null and subjectId.size() > 0"> and tq.subject_id in <foreach collection="subjectId" item="item" separator="," open="(" close=")"> #{item} </foreach> and tq.subject_id in <foreach collection="subjectId" item="item" separator="," open="(" close=")">#{item}</foreach> </if> <if test="questionType != null and questionType.size() > 0"> and tq.question_type in <foreach collection="questionType" item="item" separator="," open="(" close=")"> #{item} </foreach> and tq.question_type in <foreach collection="questionType" item="item" separator="," open="(" close=")">#{item}</foreach> </if> <if test="content != null and content != ''"> and instr(tq.content, #{content}) @@ -75,4 +80,9 @@ GROUP BY create_time </select> <select id="getAnswerInfo" resultType="com.ycl.jxkg.domain.entity.Question"> SELECT id, question_type, correct FROM t_question WHERE id in <foreach collection="questionIds" open="(" item="id" close=")" separator=",">#{id}</foreach> </select> </mapper>