Bläddra i källkod

Merge remote-tracking branch 'origin/dev' into dev

# Conflicts:
#	themis-business/src/main/java/com/qmth/themis/business/cache/bean/ExamRecordCacheBean.java
#	themis-business/src/main/java/com/qmth/themis/business/enums/FinishExamTypeEnum.java
#	themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamServiceImpl.java
#	themis-task/src/main/java/com/qmth/themis/task/quartz/ExamActivityJob.java
wangliang 4 år sedan
förälder
incheckning
dcde44fcd2

+ 53 - 0
themis-business/src/main/java/com/qmth/themis/business/bean/exam/ExamFinishBean.java

@@ -0,0 +1,53 @@
+package com.qmth.themis.business.bean.exam;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel("结束考试返回信息")
+public class ExamFinishBean {
+
+	@ApiModelProperty("finishTime")
+	private Long finishTime;
+
+	@ApiModelProperty("交卷后状态")
+	private String status;
+
+	@ApiModelProperty("客观分")
+	private Double objectiveScore;
+
+	@ApiModelProperty("审核结果")
+	private String reviewResult;
+
+	public Long getFinishTime() {
+		return finishTime;
+	}
+
+	public void setFinishTime(Long finishTime) {
+		this.finishTime = finishTime;
+	}
+
+	public String getStatus() {
+		return status;
+	}
+
+	public void setStatus(String status) {
+		this.status = status;
+	}
+
+	public Double getObjectiveScore() {
+		return objectiveScore;
+	}
+
+	public void setObjectiveScore(Double objectiveScore) {
+		this.objectiveScore = objectiveScore;
+	}
+
+	public String getReviewResult() {
+		return reviewResult;
+	}
+
+	public void setReviewResult(String reviewResult) {
+		this.reviewResult = reviewResult;
+	}
+
+}

+ 45 - 0
themis-business/src/main/java/com/qmth/themis/business/cache/ExamRecordCacheUtil.java

@@ -0,0 +1,45 @@
+package com.qmth.themis.business.cache;
+
+import java.util.Date;
+
+import com.qmth.themis.business.constant.SpringContextHolder;
+import com.qmth.themis.business.enums.ExamRecordStatusEnum;
+import com.qmth.themis.business.util.RedisUtil;
+
+/**
+ * 考试记录缓存hash值操作
+ * 
+ * @Description:
+ * @Author: xiatian
+ * @Date: 2020-07-29
+ */
+public class ExamRecordCacheUtil {
+	private static RedisUtil redisUtil = SpringContextHolder.getBean(RedisUtil.class);
+
+	public static Long getId(Long recordId) {
+		return (Long) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "id");
+	}
+
+	public static Long getExamStudentId(Long recordId) {
+		return (Long) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "examStudentId");
+	}
+
+	public static Long getPaperId(Long recordId) {
+		return (Long) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "paperId");
+	}
+	public static void setFirstStartTime(Long recordId,Date date) {
+		redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "firstStartTime",date);
+	}
+	public static void setStatus(Long recordId,ExamRecordStatusEnum status) {
+		redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "status",status);
+	}
+	
+	public static Integer getDurationSeconds(Long recordId) {
+		return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "surationSeconds");
+	}
+	
+	public static Double getObjectiveScore(Long recordId) {
+		return (Double) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "objectiveScore");
+	}
+	
+}

+ 0 - 485
themis-business/src/main/java/com/qmth/themis/business/cache/bean/ExamRecordCacheBean.java

@@ -1,485 +0,0 @@
-package com.qmth.themis.business.cache.bean;
-
-import com.qmth.themis.business.enums.EntryAuthenticationPolicyEnum;
-import com.qmth.themis.business.enums.ExamRecordStatusEnum;
-import com.qmth.themis.business.enums.FinishTypeEnum;
-import com.qmth.themis.business.enums.ReviewResultEnum;
-
-import java.io.Serializable;
-import java.util.Date;
-
-public class ExamRecordCacheBean implements Serializable {
-
-	/**
-	 * 
-	 */
-	private static final long serialVersionUID = 4130111410312390960L;
-
-	//主键
-    private Long id;
-
-    //考试批次ID
-    private Long examId;
-
-    //考试场次ID
-    private Long examActivityId;
-
-    //考生ID
-    private Long examStudentId;
-
-    //实际使用的试卷ID
-    private Long paperId;
-
-    //全部作答保存地址
-    private String answerPath;
-
-    //当前状态
-    private ExamRecordStatusEnum status;
-
-    //首次进入候考时间
-    private Date firstPrepareTime;
-
-    //首次开考时间
-    private Date firstStartTime;
-
-    //最近断点时间
-    private Date lastBreakTime;
-
-    //最近恢复候考时间
-    private Date lastPrepareTime;
-
-    //最近恢复开考时间
-    private Date lastStartTime;
-
-    //剩余断点续考次数
-    private Integer leftBreakResumeCount;
-
-    //客户端当前IP地址
-    private String clientCurrentIp;
-
-    //客户端websocket状态
-    private Integer clientWebsocketStatus;
-
-    //客户端websocket连接标识
-    private String clientWebsocketId;
-
-    //客户端最近同步时间
-    private Date clientLastSyncTime;
-
-    //微信小程序websocket状态
-    private Integer wxappWebsocketStatus;
-
-    //微信小程序websocket连接标识
-    private String wxappWebsocketId;
-
-    //微信小程序最近同步时间
-    private Date wxappLastSyncTime;
-
-    //客户端推流状态
-    private Integer clientVideoPushStatus;
-
-    //客户端推流地址
-    private String clientVideoPushKey;
-
-    //微信小程序推流状态
-    private Integer wxappVideoPushStatus;
-
-    //微信小程序推流地址
-    private String wxappVideoPushKey;
-
-    //答题进度
-    private Double answerProgress;
-
-    //累计考试用时
-    private Integer durationSeconds;
-
-    //交卷时间
-    private Date finishTime;
-
-    //交卷原因
-    private FinishTypeEnum finishType;
-
-    //预警次数
-    private Integer warningCount;
-
-    //审核结果
-    private ReviewResultEnum reviewResult;
-
-    //客观题分数
-    private Double objectiveScore;
-
-    //试题下载,0:是,1:不是
-    private Integer paperDownload;
-
-    //是否违纪,0:是,1:不是
-    private Integer breachStatus;
-
-    //个人试卷结构
-    private String paperStruct;
-
-    //个人试卷结构是否已上传,0:未上传,1:已上传
-    private Integer paperStructUpload;
-
-    //第几次考试
-    private Integer serialNumber;
-
-    //最近断点记录ID
-    private Long lastBreakId;
-
-    //开考身份验证结果
-    private EntryAuthenticationPolicyEnum entryAuthenticationResult;
-
-    //开考身份验证记录ID
-    private Long entryAuthenticationId;
-
-    //当前过程人脸检测状态
-    private Integer inProcessFaceVerifyStatus;
-
-    //当前过程活体验证状态
-    private Integer inProcessLivenessVerifyStatus;
-
-    //已完成过程活体验证次数
-    private Integer inProcessLivenessVerifyCount;
-
-	public Long getId() {
-		return id;
-	}
-
-	public void setId(Long id) {
-		this.id = id;
-	}
-
-	public Long getExamId() {
-		return examId;
-	}
-
-	public void setExamId(Long examId) {
-		this.examId = examId;
-	}
-
-	public Long getExamActivityId() {
-		return examActivityId;
-	}
-
-	public void setExamActivityId(Long examActivityId) {
-		this.examActivityId = examActivityId;
-	}
-
-	public Long getExamStudentId() {
-		return examStudentId;
-	}
-
-	public void setExamStudentId(Long examStudentId) {
-		this.examStudentId = examStudentId;
-	}
-
-	public Long getPaperId() {
-		return paperId;
-	}
-
-	public void setPaperId(Long paperId) {
-		this.paperId = paperId;
-	}
-
-	public String getAnswerPath() {
-		return answerPath;
-	}
-
-	public void setAnswerPath(String answerPath) {
-		this.answerPath = answerPath;
-	}
-
-	public ExamRecordStatusEnum getStatus() {
-		return status;
-	}
-
-	public void setStatus(ExamRecordStatusEnum status) {
-		this.status = status;
-	}
-
-	public static long getSerialVersionUID() {
-		return serialVersionUID;
-	}
-
-	public Date getFirstPrepareTime() {
-		return firstPrepareTime;
-	}
-
-	public void setFirstPrepareTime(Date firstPrepareTime) {
-		this.firstPrepareTime = firstPrepareTime;
-	}
-
-	public Date getFirstStartTime() {
-		return firstStartTime;
-	}
-
-	public void setFirstStartTime(Date firstStartTime) {
-		this.firstStartTime = firstStartTime;
-	}
-
-	public Date getLastBreakTime() {
-		return lastBreakTime;
-	}
-
-	public void setLastBreakTime(Date lastBreakTime) {
-		this.lastBreakTime = lastBreakTime;
-	}
-
-	public Date getLastPrepareTime() {
-		return lastPrepareTime;
-	}
-
-	public void setLastPrepareTime(Date lastPrepareTime) {
-		this.lastPrepareTime = lastPrepareTime;
-	}
-
-	public Date getLastStartTime() {
-		return lastStartTime;
-	}
-
-	public void setLastStartTime(Date lastStartTime) {
-		this.lastStartTime = lastStartTime;
-	}
-
-	public Integer getLeftBreakResumeCount() {
-		return leftBreakResumeCount;
-	}
-
-	public void setLeftBreakResumeCount(Integer leftBreakResumeCount) {
-		this.leftBreakResumeCount = leftBreakResumeCount;
-	}
-
-	public String getClientCurrentIp() {
-		return clientCurrentIp;
-	}
-
-	public void setClientCurrentIp(String clientCurrentIp) {
-		this.clientCurrentIp = clientCurrentIp;
-	}
-
-	public Integer getClientWebsocketStatus() {
-		return clientWebsocketStatus;
-	}
-
-	public void setClientWebsocketStatus(Integer clientWebsocketStatus) {
-		this.clientWebsocketStatus = clientWebsocketStatus;
-	}
-
-	public String getClientWebsocketId() {
-		return clientWebsocketId;
-	}
-
-	public void setClientWebsocketId(String clientWebsocketId) {
-		this.clientWebsocketId = clientWebsocketId;
-	}
-
-	public Date getClientLastSyncTime() {
-		return clientLastSyncTime;
-	}
-
-	public void setClientLastSyncTime(Date clientLastSyncTime) {
-		this.clientLastSyncTime = clientLastSyncTime;
-	}
-
-	public Integer getWxappWebsocketStatus() {
-		return wxappWebsocketStatus;
-	}
-
-	public void setWxappWebsocketStatus(Integer wxappWebsocketStatus) {
-		this.wxappWebsocketStatus = wxappWebsocketStatus;
-	}
-
-	public String getWxappWebsocketId() {
-		return wxappWebsocketId;
-	}
-
-	public void setWxappWebsocketId(String wxappWebsocketId) {
-		this.wxappWebsocketId = wxappWebsocketId;
-	}
-
-	public Date getWxappLastSyncTime() {
-		return wxappLastSyncTime;
-	}
-
-	public void setWxappLastSyncTime(Date wxappLastSyncTime) {
-		this.wxappLastSyncTime = wxappLastSyncTime;
-	}
-
-	public Integer getClientVideoPushStatus() {
-		return clientVideoPushStatus;
-	}
-
-	public void setClientVideoPushStatus(Integer clientVideoPushStatus) {
-		this.clientVideoPushStatus = clientVideoPushStatus;
-	}
-
-	public String getClientVideoPushKey() {
-		return clientVideoPushKey;
-	}
-
-	public void setClientVideoPushKey(String clientVideoPushKey) {
-		this.clientVideoPushKey = clientVideoPushKey;
-	}
-
-	public Integer getWxappVideoPushStatus() {
-		return wxappVideoPushStatus;
-	}
-
-	public void setWxappVideoPushStatus(Integer wxappVideoPushStatus) {
-		this.wxappVideoPushStatus = wxappVideoPushStatus;
-	}
-
-	public String getWxappVideoPushKey() {
-		return wxappVideoPushKey;
-	}
-
-	public void setWxappVideoPushKey(String wxappVideoPushKey) {
-		this.wxappVideoPushKey = wxappVideoPushKey;
-	}
-
-	public Double getAnswerProgress() {
-		return answerProgress;
-	}
-
-	public void setAnswerProgress(Double answerProgress) {
-		this.answerProgress = answerProgress;
-	}
-
-	public Integer getDurationSeconds() {
-		return durationSeconds;
-	}
-
-	public void setDurationSeconds(Integer durationSeconds) {
-		this.durationSeconds = durationSeconds;
-	}
-
-	public Date getFinishTime() {
-		return finishTime;
-	}
-
-	public void setFinishTime(Date finishTime) {
-		this.finishTime = finishTime;
-	}
-
-	public FinishTypeEnum getFinishType() {
-		return finishType;
-	}
-
-	public void setFinishType(FinishTypeEnum finishType) {
-		this.finishType = finishType;
-	}
-
-	public Integer getWarningCount() {
-		return warningCount;
-	}
-
-	public void setWarningCount(Integer warningCount) {
-		this.warningCount = warningCount;
-	}
-
-	public ReviewResultEnum getReviewResult() {
-		return reviewResult;
-	}
-
-	public void setReviewResult(ReviewResultEnum reviewResult) {
-		this.reviewResult = reviewResult;
-	}
-
-	public Double getObjectiveScore() {
-		return objectiveScore;
-	}
-
-	public void setObjectiveScore(Double objectiveScore) {
-		this.objectiveScore = objectiveScore;
-	}
-
-	public Integer getPaperDownload() {
-		return paperDownload;
-	}
-
-	public void setPaperDownload(Integer paperDownload) {
-		this.paperDownload = paperDownload;
-	}
-
-	public Integer getBreachStatus() {
-		return breachStatus;
-	}
-
-	public void setBreachStatus(Integer breachStatus) {
-		this.breachStatus = breachStatus;
-	}
-
-	public String getPaperStruct() {
-		return paperStruct;
-	}
-
-	public void setPaperStruct(String paperStruct) {
-		this.paperStruct = paperStruct;
-	}
-
-	public Integer getPaperStructUpload() {
-		return paperStructUpload;
-	}
-
-	public void setPaperStructUpload(Integer paperStructUpload) {
-		this.paperStructUpload = paperStructUpload;
-	}
-
-	public Integer getSerialNumber() {
-		return serialNumber;
-	}
-
-	public void setSerialNumber(Integer serialNumber) {
-		this.serialNumber = serialNumber;
-	}
-
-	public Long getLastBreakId() {
-		return lastBreakId;
-	}
-
-	public void setLastBreakId(Long lastBreakId) {
-		this.lastBreakId = lastBreakId;
-	}
-
-	public EntryAuthenticationPolicyEnum getEntryAuthenticationResult() {
-		return entryAuthenticationResult;
-	}
-
-	public void setEntryAuthenticationResult(EntryAuthenticationPolicyEnum entryAuthenticationResult) {
-		this.entryAuthenticationResult = entryAuthenticationResult;
-	}
-
-	public Long getEntryAuthenticationId() {
-		return entryAuthenticationId;
-	}
-
-	public void setEntryAuthenticationId(Long entryAuthenticationId) {
-		this.entryAuthenticationId = entryAuthenticationId;
-	}
-
-	public Integer getInProcessFaceVerifyStatus() {
-		return inProcessFaceVerifyStatus;
-	}
-
-	public void setInProcessFaceVerifyStatus(Integer inProcessFaceVerifyStatus) {
-		this.inProcessFaceVerifyStatus = inProcessFaceVerifyStatus;
-	}
-
-	public Integer getInProcessLivenessVerifyStatus() {
-		return inProcessLivenessVerifyStatus;
-	}
-
-	public void setInProcessLivenessVerifyStatus(Integer inProcessLivenessVerifyStatus) {
-		this.inProcessLivenessVerifyStatus = inProcessLivenessVerifyStatus;
-	}
-
-	public Integer getInProcessLivenessVerifyCount() {
-		return inProcessLivenessVerifyCount;
-	}
-
-	public void setInProcessLivenessVerifyCount(Integer inProcessLivenessVerifyCount) {
-		this.inProcessLivenessVerifyCount = inProcessLivenessVerifyCount;
-	}
-
-    
-}

+ 35 - 0
themis-business/src/main/java/com/qmth/themis/business/enums/FinishExamResultEnum.java

@@ -0,0 +1,35 @@
+package com.qmth.themis.business.enums;
+
+/**结束考试后返回页面类型
+ * @Description: 
+ * @Author: xiatian
+ * @Date: 2020-07-29
+ */
+public enum FinishExamResultEnum {
+	/**
+	 * 分数计算中
+	 */
+	SCORE_CALCULATE("分数计算中"),
+	/**
+	 * 待审核
+	 */
+	AUDITING("待审核"),
+	/**
+	 * 分数显示
+	 */
+	SCORE_VIEW("分数显示"),
+	/**
+	 * 正常交卷
+	 */
+	NORMAL("正常交卷");
+
+	private String title;
+
+	private FinishExamResultEnum(String title) {
+		this.title = title;
+	}
+
+	public String getTitle() {
+		return title;
+	}
+}

+ 33 - 0
themis-business/src/main/java/com/qmth/themis/business/enums/FinishExamTypeEnum.java

@@ -0,0 +1,33 @@
+package com.qmth.themis.business.enums;
+
+/**
+ * @Description: 结束考试 enum
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2020/7/27
+ */
+public enum FinishExamTypeEnum {
+	/**
+	 * 手动
+	 */
+	MANUAL("手动"),
+	/**
+	 * 自动
+	 */
+	AUTO("自动"),
+	/**
+	 * 监考强制
+	 */
+	INTERRUPT("监考强制");
+
+	private String title;
+
+	private FinishExamTypeEnum(String title) {
+		this.title = title;
+	}
+
+	public String getTitle() {
+		return title;
+	}
+}

+ 10 - 0
themis-business/src/main/java/com/qmth/themis/business/service/TEExamService.java

@@ -8,6 +8,7 @@ import org.springframework.web.multipart.MultipartFile;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.qmth.themis.business.bean.exam.ExamFileUploadBean;
+import com.qmth.themis.business.bean.exam.ExamFinishBean;
 import com.qmth.themis.business.bean.exam.ExamPrepareBean;
 import com.qmth.themis.business.bean.exam.ExamResumeBean;
 import com.qmth.themis.business.bean.exam.ExamStartBean;
@@ -116,4 +117,13 @@ public interface TEExamService extends IService<TEExam> {
 	 * @return
 	 */
 	public ExamResumeBean resume(Long studentId, Long recordId);
+
+	/**结束考试
+	 * @param id
+	 * @param recordId
+	 * @param type
+	 * @param durationSeconds
+	 * @return
+	 */
+	public ExamFinishBean finish(Long studentId, Long recordId, String type, Integer durationSeconds);
 }

+ 101 - 53
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamServiceImpl.java

@@ -14,7 +14,6 @@ import java.util.UUID;
 
 import javax.annotation.Resource;
 
-import com.qmth.themis.business.enums.ExamRecordStatusEnum;
 import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
@@ -24,20 +23,22 @@ import org.springframework.web.multipart.MultipartFile;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qmth.themis.business.bean.exam.ExamFileUploadBean;
+import com.qmth.themis.business.bean.exam.ExamFinishBean;
 import com.qmth.themis.business.bean.exam.ExamPrepareBean;
 import com.qmth.themis.business.bean.exam.ExamResumeBean;
 import com.qmth.themis.business.bean.exam.ExamStartBean;
+import com.qmth.themis.business.cache.ExamRecordCacheUtil;
 import com.qmth.themis.business.cache.RedisKeyHelper;
 import com.qmth.themis.business.cache.bean.ExamActivityCacheBean;
 import com.qmth.themis.business.cache.bean.ExamCourseCacheBean;
 import com.qmth.themis.business.cache.bean.ExamPaperCacheBean;
-import com.qmth.themis.business.cache.bean.ExamRecordCacheBean;
 import com.qmth.themis.business.cache.bean.ExamStudentAnswerCacheBean;
 import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
 import com.qmth.themis.business.cache.bean.ExamStudentPaperStructCacheBean;
 import com.qmth.themis.business.config.SystemConfig;
 import com.qmth.themis.business.dao.TEExamMapper;
 import com.qmth.themis.business.entity.TEExam;
+import com.qmth.themis.business.enums.ExamRecordStatusEnum;
 import com.qmth.themis.business.service.TEExamActivityService;
 import com.qmth.themis.business.service.TEExamCourseService;
 import com.qmth.themis.business.service.TEExamPaperService;
@@ -234,22 +235,24 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
 		return -1;
 	}
 
-	@Transactional
 	@Override
 	public ExamStartBean start(Long studentId, Long recordId) {
 		ExamStartBean ret = null;
-		ExamRecordCacheBean er = (ExamRecordCacheBean) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId));
-		if (er == null) {
+
+		// 校验当前登录用户和参数一致性
+		if (ExamRecordCacheUtil.getId(recordId) == null) {
 			throw new BusinessException("未找到考试记录");
 		}
+		Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
 		ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
-				.get(RedisKeyHelper.examStudentCacheKey(er.getExamStudentId()));
+				.get(RedisKeyHelper.examStudentCacheKey(examStudentId));
 		if (es == null) {
 			throw new BusinessException("未找到考生");
 		}
 		if (studentId.equals(es.getStudentId())) {
 			throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
 		}
+
 		Long activityId = es.getExamActivityId();
 		ExamActivityCacheBean ac = teExamActivityService.getExamActivityCacheBean(activityId);
 		if (ac == null) {
@@ -265,11 +268,8 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
 			throw new BusinessException("允许开考的时间已结束");
 		}
 
-		// 修改考试记录数据
-		er.setFirstStartTime(new Date());
-		er.setStatus(ExamRecordStatusEnum.break_off);
-
-		ExamPaperCacheBean ep = teExamPaperService.getExamPaperCacheBean(er.getPaperId());
+		Long paperId = ExamRecordCacheUtil.getPaperId(recordId);
+		ExamPaperCacheBean ep = teExamPaperService.getExamPaperCacheBean(paperId);
 		if (ep == null) {
 			throw new BusinessException("未找到试卷");
 		}
@@ -279,50 +279,57 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
 		ret.setPaperDecryptVector(ep.getDecryptVector());
 
 		// 更新考试记录缓存
-		redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), er);
+		ExamRecordCacheUtil.setFirstStartTime(recordId, new Date());
+		ExamRecordCacheUtil.setStatus(recordId, ExamRecordStatusEnum.first_prepare);
 
 		return ret;
 	}
 
-	@Transactional
 	@Override
 	public Long studentPaperStruct(Long studentId, Long recordId, String content) {
-		ExamRecordCacheBean er = (ExamRecordCacheBean) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId));
-		if (er == null) {
+
+		// 校验当前登录用户和参数一致性
+		if (ExamRecordCacheUtil.getId(recordId) == null) {
 			throw new BusinessException("未找到考试记录");
 		}
+		Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
 		ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
-				.get(RedisKeyHelper.examStudentCacheKey(er.getExamStudentId()));
+				.get(RedisKeyHelper.examStudentCacheKey(examStudentId));
 		if (es == null) {
 			throw new BusinessException("未找到考生");
 		}
 		if (studentId.equals(es.getStudentId())) {
 			throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
 		}
+		
+
 		ExamStudentPaperStructCacheBean struct = new ExamStudentPaperStructCacheBean();
 		struct.setContent(content);
-		struct.setTime(System.currentTimeMillis());
+		struct.setTime(new Date().getTime());
 		// 更新考生试卷结构
 		redisUtil.set(RedisKeyHelper.studentPaperStructKey(recordId), struct);
 		return struct.getTime();
 	}
 
-	@Transactional
 	@Override
 	public Long answerSubmit(Long studentId, Long recordId, Integer mainNumber, Integer subNumber, Integer subIndex,
 			String answer, Long version, Integer durationSeconds) {
-		ExamRecordCacheBean er = (ExamRecordCacheBean) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId));
-		if (er == null) {
+
+		// 校验当前登录用户和参数一致性
+		if (ExamRecordCacheUtil.getId(recordId) == null) {
 			throw new BusinessException("未找到考试记录");
 		}
+		Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
 		ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
-				.get(RedisKeyHelper.examStudentCacheKey(er.getExamStudentId()));
+				.get(RedisKeyHelper.examStudentCacheKey(examStudentId));
 		if (es == null) {
 			throw new BusinessException("未找到考生");
 		}
 		if (studentId.equals(es.getStudentId())) {
 			throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
 		}
+		
+
 		ExamStudentAnswerCacheBean answerCache = (ExamStudentAnswerCacheBean) redisUtil.get(
 				RedisKeyHelper.examAnswerKey(recordId),
 				RedisKeyHelper.examAnswerHashKey(mainNumber, subNumber, subIndex));
@@ -348,21 +355,24 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
 		return version;
 	}
 
-	@Transactional
 	@Override
 	public Integer audioLeftPlayCountSubmit(Long studentId, Long recordId, String key, Integer count) {
-		ExamRecordCacheBean er = (ExamRecordCacheBean) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId));
-		if (er == null) {
+
+		// 校验当前登录用户和参数一致性
+		if (ExamRecordCacheUtil.getId(recordId) == null) {
 			throw new BusinessException("未找到考试记录");
 		}
+		Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
 		ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
-				.get(RedisKeyHelper.examStudentCacheKey(er.getExamStudentId()));
+				.get(RedisKeyHelper.examStudentCacheKey(examStudentId));
 		if (es == null) {
 			throw new BusinessException("未找到考生");
 		}
 		if (studentId.equals(es.getStudentId())) {
 			throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
 		}
+		
+
 		// 音频剩余播放次数缓存
 		redisUtil.set(RedisKeyHelper.audioLeftPlayCountKey(recordId), key, count);
 
@@ -371,31 +381,35 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
 
 	@Override
 	public ExamFileUploadBean fileUpload(Long studentId, Long recordId, MultipartFile file, String suffix, String md5) {
-		ExamRecordCacheBean er = (ExamRecordCacheBean) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId));
-		if (er == null) {
+
+		// 校验当前登录用户和参数一致性
+		if (ExamRecordCacheUtil.getId(recordId) == null) {
 			throw new BusinessException("未找到考试记录");
 		}
+		Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
 		ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
-				.get(RedisKeyHelper.examStudentCacheKey(er.getExamStudentId()));
+				.get(RedisKeyHelper.examStudentCacheKey(examStudentId));
 		if (es == null) {
 			throw new BusinessException("未找到考生");
 		}
 		if (studentId.equals(es.getStudentId())) {
 			throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
 		}
+		
+
 		String filePath = "upload/" + sdf.format(new Date()) + "/" + uuid() + ".json";
 		InputStream in = null;
 		try {
 			String fileMd5 = DigestUtils.md5Hex(file.getBytes());
-			if(!md5.equals(fileMd5)) {
+			if (!md5.equals(fileMd5)) {
 				throw new BusinessException("文件md5不一致");
 			}
 			in = file.getInputStream();
 			OssUtil.ossUploadStream(systemConfig.getOssEnv(3), filePath, in);
-			String url=systemConfig.getProperty("aliyun.oss.url")+"/"+filePath;
-			ExamFileUploadBean ret=new ExamFileUploadBean();
+			String url = systemConfig.getProperty("aliyun.oss.url") + "/" + filePath;
+			ExamFileUploadBean ret = new ExamFileUploadBean();
 			ret.setUrl(url);
-			ret.setUploadTime(System.currentTimeMillis());
+			ret.setUploadTime(new Date().getTime());
 			return ret;
 		} catch (IOException e) {
 			throw new BusinessException("文件读取出错");
@@ -416,49 +430,57 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
 	@SuppressWarnings("unchecked")
 	@Override
 	public ExamResumeBean resume(Long studentId, Long recordId) {
-		ExamRecordCacheBean er = (ExamRecordCacheBean) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId));
-		if (er == null) {
+
+		// 校验当前登录用户和参数一致性
+		if (ExamRecordCacheUtil.getId(recordId) == null) {
 			throw new BusinessException("未找到考试记录");
 		}
+		Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
 		ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
-				.get(RedisKeyHelper.examStudentCacheKey(er.getExamStudentId()));
+				.get(RedisKeyHelper.examStudentCacheKey(examStudentId));
 		if (es == null) {
 			throw new BusinessException("未找到考生");
 		}
 		if (studentId.equals(es.getStudentId())) {
 			throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
 		}
-		ExamPaperCacheBean ep = teExamPaperService.getExamPaperCacheBean(er.getPaperId());
+		
+
+		Long paperId = ExamRecordCacheUtil.getPaperId(recordId);
+		ExamPaperCacheBean ep = teExamPaperService.getExamPaperCacheBean(paperId);
 		if (ep == null) {
 			throw new BusinessException("未找到试卷");
 		}
-		
-		ExamResumeBean ret=new ExamResumeBean();
-		ret.setDurationSeconds(er.getDurationSeconds());
+
+		ExamResumeBean ret = new ExamResumeBean();
+		ret.setDurationSeconds(ExamRecordCacheUtil.getDurationSeconds(recordId));
 		ret.setPaperUrl(OssUtil.getUrlForPrivateBucket(systemConfig.getOssEnv(3), ep.getPaperPath()));
 		ret.setStructUrl(OssUtil.getUrlForPrivateBucket(systemConfig.getOssEnv(3), ep.getStructPath()));
-		ret.setHasAudio((ep.getHasAudio()!=null&&ep.getHasAudio().intValue()==1?true:false));
+		ret.setHasAudio((ep.getHasAudio() != null && ep.getHasAudio().intValue() == 1 ? true : false));
 		ret.setAudioPlayCount(ep.getAudioPlayCount());
-		//TODO 9527
+		// TODO 9527
 		ret.setMonitorKey(recordId.toString());
-		
-		ExamStudentPaperStructCacheBean struct=(ExamStudentPaperStructCacheBean)redisUtil.get(RedisKeyHelper.studentPaperStructKey(recordId));
-		if(struct!=null) {
+
+		ExamStudentPaperStructCacheBean struct = (ExamStudentPaperStructCacheBean) redisUtil
+				.get(RedisKeyHelper.studentPaperStructKey(recordId));
+		if (struct != null) {
 			ret.setStudentPaperStruct(struct.getContent());
 		}
-		Map<String,ExamStudentAnswerCacheBean> answers=redisUtil.getHashEntries(RedisKeyHelper.examAnswerKey(recordId));
-		if(answers!=null&&answers.size()>0) {
+		Map<String, ExamStudentAnswerCacheBean> answers = redisUtil
+				.getHashEntries(RedisKeyHelper.examAnswerKey(recordId));
+		if (answers != null && answers.size() > 0) {
 			ret.setAnswerList(sortAnswers(answers));
 		}
-		Map<String,Integer> audioLeftPlayCounts=redisUtil.getHashEntries(RedisKeyHelper.audioLeftPlayCountKey(recordId));
-		if(audioLeftPlayCounts!=null&&audioLeftPlayCounts.size()>0) {
+		Map<String, Integer> audioLeftPlayCounts = redisUtil
+				.getHashEntries(RedisKeyHelper.audioLeftPlayCountKey(recordId));
+		if (audioLeftPlayCounts != null && audioLeftPlayCounts.size() > 0) {
 			ret.setAudioLeftPlayCount(audioLeftPlayCounts);
 		}
 		return ret;
 	}
-	
-	//作答排序
-	private List<ExamStudentAnswerCacheBean> sortAnswers(Map<String,ExamStudentAnswerCacheBean> answers) {
+
+	// 作答排序
+	private List<ExamStudentAnswerCacheBean> sortAnswers(Map<String, ExamStudentAnswerCacheBean> answers) {
 		List<ExamStudentAnswerCacheBean> ret = new ArrayList<ExamStudentAnswerCacheBean>(answers.values());
 		Collections.sort(ret, new Comparator<ExamStudentAnswerCacheBean>() {
 
@@ -474,9 +496,9 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
 					} else if (o1.getSubNumber() < o2.getSubNumber()) {
 						return -1;
 					} else {
-						if (o1.getSubIndex()==null || o2.getSubIndex()==null) {
+						if (o1.getSubIndex() == null || o2.getSubIndex() == null) {
 							return 0;
-						}else {
+						} else {
 							if (o1.getSubIndex() > o2.getSubIndex()) {
 								return 1;
 							} else if (o1.getSubIndex() < o2.getSubIndex()) {
@@ -492,4 +514,30 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
 		});
 		return ret;
 	}
+
+	@Override
+	public ExamFinishBean finish(Long studentId, Long recordId, String type, Integer durationSeconds) {
+
+		// 校验当前登录用户和参数一致性
+		if (ExamRecordCacheUtil.getId(recordId) == null) {
+			throw new BusinessException("未找到考试记录");
+		}
+		Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
+		ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
+				.get(RedisKeyHelper.examStudentCacheKey(examStudentId));
+		if (es == null) {
+			throw new BusinessException("未找到考生");
+		}
+		if (studentId.equals(es.getStudentId())) {
+			throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
+		}
+		
+
+		ExamFinishBean ret = new ExamFinishBean();
+		ret.setFinishTime(new Date().getTime());
+		ret.setObjectiveScore(ExamRecordCacheUtil.getObjectiveScore(recordId));
+		// TODO
+		ret.setReviewResult("");
+		return null;
+	}
 }

+ 47 - 48
themis-business/src/main/java/com/qmth/themis/business/service/impl/TOeExamRecordServiceImpl.java

@@ -13,11 +13,11 @@ import org.springframework.transaction.annotation.Transactional;
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qmth.themis.business.cache.RedisKeyHelper;
-import com.qmth.themis.business.cache.bean.ExamRecordCacheBean;
 import com.qmth.themis.business.dao.TOeExamRecordMapper;
 import com.qmth.themis.business.entity.TOeExamRecord;
 import com.qmth.themis.business.service.TOeExamRecordService;
 import com.qmth.themis.business.util.RedisUtil;
+import com.qmth.themis.common.util.SimpleBeanUtil;
 
 /**
  * @Description: 考试记录 服务实现类
@@ -101,55 +101,54 @@ public class TOeExamRecordServiceImpl extends ServiceImpl<TOeExamRecordMapper, T
     	er.setFirstPrepareTime(new Date());
     	er.setStatus(ExamRecordStatusEnum.first_prepare);
     	saveOrUpdate(er);
-    	ExamRecordCacheBean erCache=new ExamRecordCacheBean();
-    	copy(erCache, er);
-    	redisUtil.set(RedisKeyHelper.examRecordCacheKey(er.getId()), erCache);
+    	redisUtil.set(RedisKeyHelper.examRecordCacheKey(er.getId()), SimpleBeanUtil.objectToMap(er));
     	return er.getId();
     }
+     
     
     
-    private void copy(ExamRecordCacheBean tb,TOeExamRecord sb) {
-    	tb.setId(sb.getId());
-    	tb.setExamId(sb.getExamId());
-    	tb.setExamActivityId(tb.getExamActivityId());
-    	tb.setPaperId(sb.getPaperId());
-    	tb.setAnswerPath(sb.getAnswerPath());
-    	tb.setStatus(sb.getStatus());
-    	tb.setFirstPrepareTime(sb.getFirstPrepareTime());
-    	tb.setFirstStartTime(sb.getFirstStartTime());
-    	tb.setLastPrepareTime(sb.getLastPrepareTime());
-    	tb.setLastBreakTime(sb.getLastBreakTime());
-    	tb.setLastStartTime(sb.getLastStartTime());
-    	tb.setLeftBreakResumeCount(sb.getLeftBreakResumeCount());
-    	tb.setClientCurrentIp(sb.getClientCurrentIp());
-    	tb.setClientLastSyncTime(sb.getClientLastSyncTime());
-    	tb.setClientVideoPushKey(sb.getClientVideoPushKey());
-    	tb.setClientVideoPushStatus(sb.getClientVideoPushStatus());
-    	tb.setClientWebsocketId(sb.getClientWebsocketId());
-    	tb.setClientWebsocketStatus(sb.getClientWebsocketStatus());
-    	tb.setWxappLastSyncTime(sb.getWxappLastSyncTime());
-    	tb.setWarningCount(sb.getWarningCount());
-    	tb.setWxappVideoPushKey(sb.getWxappVideoPushKey());
-    	tb.setWxappVideoPushStatus(sb.getWxappVideoPushStatus());
-    	tb.setWxappWebsocketId(sb.getWxappWebsocketId());
-    	tb.setWxappWebsocketStatus(sb.getWxappWebsocketStatus());
-    	tb.setAnswerProgress(sb.getAnswerProgress());
-    	tb.setDurationSeconds(sb.getDurationSeconds());
-    	tb.setFinishTime(sb.getFinishTime());
-    	tb.setFinishType(sb.getFinishType());
-    	tb.setWarningCount(sb.getWarningCount());
-    	tb.setReviewResult(sb.getReviewResult());
-    	tb.setObjectiveScore(sb.getObjectiveScore());
-    	tb.setPaperDownload(sb.getPaperDownload());
-    	tb.setBreachStatus(sb.getBreachStatus());
-    	tb.setPaperStruct(sb.getPaperStruct());
-    	tb.setPaperStructUpload(sb.getPaperStructUpload());
-    	tb.setSerialNumber(sb.getSerialNumber());
-    	tb.setLastBreakId(sb.getLastBreakId());
-    	tb.setEntryAuthenticationId(sb.getEntryAuthenticationId());
-    	tb.setEntryAuthenticationResult(sb.getEntryAuthenticationResult());
-    	tb.setInProcessFaceVerifyStatus(sb.getInProcessFaceVerifyStatus());
-    	tb.setInProcessLivenessVerifyCount(sb.getInProcessLivenessVerifyCount());
-    	tb.setInProcessLivenessVerifyStatus(sb.getInProcessLivenessVerifyStatus());
-    }
+//    private void copy(ExamRecordCacheBean tb,TOeExamRecord sb) {
+//    	tb.setId(sb.getId());
+//    	tb.setExamId(sb.getExamId());
+//    	tb.setExamActivityId(tb.getExamActivityId());
+//    	tb.setPaperId(sb.getPaperId());
+//    	tb.setAnswerPath(sb.getAnswerPath());
+//    	tb.setStatus(sb.getStatus());
+//    	tb.setFirstPrepareTime(sb.getFirstPrepareTime());
+//    	tb.setFirstStartTime(sb.getFirstStartTime());
+//    	tb.setLastPrepareTime(sb.getLastPrepareTime());
+//    	tb.setLastBreakTime(sb.getLastBreakTime());
+//    	tb.setLastStartTime(sb.getLastStartTime());
+//    	tb.setLeftBreakResumeCount(sb.getLeftBreakResumeCount());
+//    	tb.setClientCurrentIp(sb.getClientCurrentIp());
+//    	tb.setClientLastSyncTime(sb.getClientLastSyncTime());
+//    	tb.setClientVideoPushKey(sb.getClientVideoPushKey());
+//    	tb.setClientVideoPushStatus(sb.getClientVideoPushStatus());
+//    	tb.setClientWebsocketId(sb.getClientWebsocketId());
+//    	tb.setClientWebsocketStatus(sb.getClientWebsocketStatus());
+//    	tb.setWxappLastSyncTime(sb.getWxappLastSyncTime());
+//    	tb.setWarningCount(sb.getWarningCount());
+//    	tb.setWxappVideoPushKey(sb.getWxappVideoPushKey());
+//    	tb.setWxappVideoPushStatus(sb.getWxappVideoPushStatus());
+//    	tb.setWxappWebsocketId(sb.getWxappWebsocketId());
+//    	tb.setWxappWebsocketStatus(sb.getWxappWebsocketStatus());
+//    	tb.setAnswerProgress(sb.getAnswerProgress());
+//    	tb.setDurationSeconds(sb.getDurationSeconds());
+//    	tb.setFinishTime(sb.getFinishTime());
+//    	tb.setFinishType(sb.getFinishType());
+//    	tb.setWarningCount(sb.getWarningCount());
+//    	tb.setReviewResult(sb.getReviewResult());
+//    	tb.setObjectiveScore(sb.getObjectiveScore());
+//    	tb.setPaperDownload(sb.getPaperDownload());
+//    	tb.setBreachStatus(sb.getBreachStatus());
+//    	tb.setPaperStruct(sb.getPaperStruct());
+//    	tb.setPaperStructUpload(sb.getPaperStructUpload());
+//    	tb.setSerialNumber(sb.getSerialNumber());
+//    	tb.setLastBreakId(sb.getLastBreakId());
+//    	tb.setEntryAuthenticationId(sb.getEntryAuthenticationId());
+//    	tb.setEntryAuthenticationResult(sb.getEntryAuthenticationResult());
+//    	tb.setInProcessFaceVerifyStatus(sb.getInProcessFaceVerifyStatus());
+//    	tb.setInProcessLivenessVerifyCount(sb.getInProcessLivenessVerifyCount());
+//    	tb.setInProcessLivenessVerifyStatus(sb.getInProcessLivenessVerifyStatus());
+//    }
 }

+ 8 - 0
themis-business/src/main/java/com/qmth/themis/business/util/RedisUtil.java

@@ -277,4 +277,12 @@ public class RedisUtil {
     public void delete(String key) {
         redisTemplate.expire(key, 0, TimeUnit.SECONDS);
     }
+    
+    /**保存hash结构
+     * @param key
+     * @param map
+     */
+    public void setForHash(String key,Map<String,Object> map) {
+        redisTemplate.opsForHash().putAll(key, map);
+    }
 }

+ 47 - 0
themis-common/src/main/java/com/qmth/themis/common/util/SimpleBeanUtil.java

@@ -0,0 +1,47 @@
+package com.qmth.themis.common.util;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class SimpleBeanUtil {
+	public static Map<String, Object> objectToMap(Object obj) {
+		if (obj == null) {
+			throw new RuntimeException("Object is null");
+		}
+		// 获取关联的所有类,本类以及所有父类
+		boolean ret = true;
+		Class oo = obj.getClass();
+		List<Class> clazzs = new ArrayList<Class>();
+		while (ret) {
+			clazzs.add(oo);
+			oo = oo.getSuperclass();
+			if (oo == null || oo == Object.class)
+				break;
+		}
+
+		Map<String, Object> map = new HashMap<String, Object>();
+
+		for (int i = 0; i < clazzs.size(); i++) {
+			Field[] declaredFields = clazzs.get(i).getDeclaredFields();
+			for (Field field : declaredFields) {
+				int mod = field.getModifiers();
+				// 过滤 static 和 final 类型
+				if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
+					continue;
+				}
+				field.setAccessible(true);
+				try {
+					map.put(field.getName(), field.get(obj));
+				} catch (Exception e) {
+					throw new RuntimeException(e);
+				}
+			}
+		}
+
+		return map;
+	}
+}

+ 20 - 0
themis-exam/src/main/java/com/qmth/themis/exam/api/TEExamController.java

@@ -14,6 +14,7 @@ import org.springframework.web.multipart.MultipartFile;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.qmth.themis.business.bean.exam.ExamFileUploadBean;
+import com.qmth.themis.business.bean.exam.ExamFinishBean;
 import com.qmth.themis.business.bean.exam.ExamPrepareBean;
 import com.qmth.themis.business.bean.exam.ExamResumeBean;
 import com.qmth.themis.business.bean.exam.ExamStartBean;
@@ -194,4 +195,23 @@ public class TEExamController {
 			redisUtil.releaseLock(lockKey);
 		}
 	}
+	
+	@ApiOperation(value = "结束考试")
+	@RequestMapping(value = "/finish", method = RequestMethod.POST)
+	@ApiResponses({ @ApiResponse(code = 200, message = "试卷信息") })
+	public ExamFinishBean finish(@ApiParam(value = "考试记录ID", required = true) @RequestParam Long recordId,
+			@ApiParam(value = "结束类型", required = true) @RequestParam String type,
+			@ApiParam(value = "总用时秒数", required = true) @RequestParam Integer durationSeconds) {
+		TEStudent teStudent = (TEStudent) ServletUtil.getRequestStudentAccount();
+		String lockKey = SystemConstant.REDIS_LOCK_STUDENT_PREFIX + teStudent.getId();
+		Boolean lock = redisUtil.lock(lockKey, SystemConstant.REDIS_CACHE_TIME_OUT);
+		if (!lock) {
+			throw new BusinessException(ExceptionResultEnum.REQUEST_AWAIT);
+		}
+		try {
+			return teExamService.finish(teStudent.getId(), recordId,type,durationSeconds);
+		} finally {
+			redisUtil.releaseLock(lockKey);
+		}
+	}
 }

+ 3 - 3
themis-task/src/main/java/com/qmth/themis/task/quartz/ExamActivityJob.java

@@ -5,7 +5,7 @@ import com.qmth.themis.business.entity.TEExamActivity;
 import com.qmth.themis.business.entity.TEExamStudent;
 import com.qmth.themis.business.entity.TOeExamRecord;
 import com.qmth.themis.business.enums.ExamRecordStatusEnum;
-import com.qmth.themis.business.enums.FinishTypeEnum;
+import com.qmth.themis.business.enums.FinishExamTypeEnum;
 import com.qmth.themis.business.service.TEExamActivityService;
 import com.qmth.themis.business.service.TEExamStudentService;
 import com.qmth.themis.business.service.TOeExamRecordService;
@@ -62,9 +62,9 @@ public class ExamActivityJob extends QuartzJobBean {
                 List<TOeExamRecord> tOeExamRecordList = tOeExamRecordService.list(tOeExamRecordQueryWrapper);
                 List<Long> examStudentIdList = new ArrayList<>();
                 tOeExamRecordList.forEach(s -> {
-                    s.setStatus(ExamRecordStatusEnum.finished);
+                    s.setStatus(ExamRecordStatusEnum.finished.ordinal());
                     s.setFinishTime(new Date());
-                    s.setFinishType(FinishTypeEnum.auto);
+                    s.setFinishType(FinishExamTypeEnum.INTERRUPT.ordinal());
                     examStudentIdList.add(s.getExamStudentId());
                 });
                 tOeExamRecordService.updateBatchById(tOeExamRecordList);