xiangpei
2024-06-13 b55933dc08b27a1e051115f8c58ce46291637f8c
手动、临时提交考试
9个文件已修改
9个文件已添加
440 ■■■■■ 已修改文件
pom.xml 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ycl/jxkg/controller/student/ExamController.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ycl/jxkg/controller/student/ExamPaperAnswerController.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ycl/jxkg/domain/entity/ExamSubmitTemp.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ycl/jxkg/domain/query/ClassesUserQuery.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ycl/jxkg/domain/vo/DoQuestionVO.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ycl/jxkg/domain/vo/ExamSubmitTempVO.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ycl/jxkg/domain/vo/ExamSubmitVO.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ycl/jxkg/domain/vo/QuestionItemVO.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ycl/jxkg/enums/QuestionTypeEnum.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ycl/jxkg/enums/general/ExamSubmitTempStatusEnum.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ycl/jxkg/mapper/ExamSubmitTempMapper.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ycl/jxkg/mapper/QuestionMapper.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ycl/jxkg/service/ExamService.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ycl/jxkg/service/impl/ExamServiceImpl.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/ClassesUserMapper.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/ExamSubmitTempMapper.xml 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/QuestionMapper.xml 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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>