Prechádzať zdrojové kódy

Merge branch 'dev' into release

# Conflicts:
#	themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamServiceImpl.java
wangliang 4 rokov pred
rodič
commit
b8a1487d63

+ 31 - 25
themis-backend/src/main/java/com/qmth/themis/backend/api/TEExamController.java

@@ -6,6 +6,7 @@ import com.qmth.themis.business.annotation.ApiJsonObject;
 import com.qmth.themis.business.annotation.ApiJsonProperty;
 import com.qmth.themis.business.cache.ExamRecordCacheUtil;
 import com.qmth.themis.business.cache.RedisKeyHelper;
+import com.qmth.themis.business.cache.bean.ExamActivityRecordCache;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.dto.AuthDto;
 import com.qmth.themis.business.dto.ExamPropCountDto;
@@ -378,7 +379,6 @@ public class TEExamController {
             AtomicReference<Integer> examCount = new AtomicReference<>(0);
             AtomicReference<Integer> clientWebsocketStatusCount = new AtomicReference<>(0);
             AtomicReference<Integer> monitorStatusSourceCount = new AtomicReference<>(0);
-            AtomicReference<Integer> alreadyComplete = new AtomicReference<>(0);
             Integer notComplete = 0;
             if (Objects.nonNull(teExamStudentList) && teExamStudentList.size() > 0) {
                 studentSet = new HashSet<>();
@@ -392,34 +392,40 @@ public class TEExamController {
                 allCount = studentSet.size();
             }
 
+            Set<Long> alreadyComplete = null;
             if (Objects.nonNull(examActivityIdSet)) {
+                alreadyComplete = new HashSet<>();
                 //获取已待考、考试中、已完成学生
+                Set<Long> finalAlreadyComplete = alreadyComplete;
                 examActivityIdSet.forEach(s -> {
                     Map<String, Object> objectMap = redisUtil.getHashEntries(RedisKeyHelper.examActivityRecordCacheKey(s));
                     if (Objects.nonNull(objectMap) && objectMap.size() > 0) {
                         objectMap.forEach((k, v) -> {
                             Long recordId = Long.parseLong(k);
-                            //客户端通讯状态
-                            WebsocketStatusEnum clientStatus = Objects.isNull(ExamRecordCacheUtil.getClientWebsocketStatus(recordId)) ? null : ExamRecordCacheUtil.getClientWebsocketStatus(recordId);
-                            if (Objects.nonNull(clientStatus) && Objects.equals(clientStatus, WebsocketStatusEnum.OFF_LINE)) {
-                                clientWebsocketStatusCount.getAndSet(clientWebsocketStatusCount.get() + 1);
+                            ExamActivityRecordCache examActivityRecordCache = (ExamActivityRecordCache) v;
+                            ExamRecordStatusEnum examRecordStatusEnum = examActivityRecordCache.getStatus();
+                            if (Objects.nonNull(examRecordStatusEnum) && !Objects.equals(examRecordStatusEnum, ExamRecordStatusEnum.PERSISTED) && !Objects.equals(examRecordStatusEnum, ExamRecordStatusEnum.FINISHED)) {
+                                //客户端通讯状态
+                                WebsocketStatusEnum clientStatus = Objects.isNull(ExamRecordCacheUtil.getClientWebsocketStatus(recordId)) ? null : ExamRecordCacheUtil.getClientWebsocketStatus(recordId);
+                                if (Objects.nonNull(clientStatus) && Objects.equals(clientStatus, WebsocketStatusEnum.OFF_LINE)) {
+                                    clientWebsocketStatusCount.getAndSet(clientWebsocketStatusCount.get() + 1);
+                                }
+                                //监控端通讯状态
+                                MonitorVideoSourceEnum source = null;
+                                if (Objects.nonNull(ExamRecordCacheUtil.getMonitorLiveUrlClientCamera(recordId))) {
+                                    source = MonitorVideoSourceEnum.CLIENT_CAMERA;
+                                } else if (Objects.nonNull(ExamRecordCacheUtil.getMonitorLiveUrlClientScreen(recordId))) {
+                                    source = MonitorVideoSourceEnum.CLIENT_SCREEN;
+                                } else if (Objects.nonNull(ExamRecordCacheUtil.getMonitorLiveUrlMobileFirst(recordId))) {
+                                    source = MonitorVideoSourceEnum.MOBILE_FIRST;
+                                } else if (Objects.nonNull(ExamRecordCacheUtil.getMonitorLiveUrlMobileSecond(recordId))) {
+                                    source = MonitorVideoSourceEnum.MOBILE_SECOND;
+                                }
+                                MonitorStatusSourceEnum status = Objects.isNull(source) ? null : ExamRecordCacheUtil.getMonitorStatus(recordId, source.name());
+                                if (Objects.nonNull(status) && Objects.equals(status, MonitorStatusSourceEnum.STOP)) {
+                                    monitorStatusSourceCount.getAndSet(monitorStatusSourceCount.get() + 1);
+                                }
                             }
-                            //监控端通讯状态
-                            MonitorVideoSourceEnum source = null;
-                            if (Objects.nonNull(ExamRecordCacheUtil.getMonitorLiveUrlClientCamera(recordId))) {
-                                source = MonitorVideoSourceEnum.CLIENT_CAMERA;
-                            } else if (Objects.nonNull(ExamRecordCacheUtil.getMonitorLiveUrlClientScreen(recordId))) {
-                                source = MonitorVideoSourceEnum.CLIENT_SCREEN;
-                            } else if (Objects.nonNull(ExamRecordCacheUtil.getMonitorLiveUrlMobileFirst(recordId))) {
-                                source = MonitorVideoSourceEnum.MOBILE_FIRST;
-                            } else if (Objects.nonNull(ExamRecordCacheUtil.getMonitorLiveUrlMobileSecond(recordId))) {
-                                source = MonitorVideoSourceEnum.MOBILE_SECOND;
-                            }
-                            MonitorStatusSourceEnum status = Objects.isNull(source) ? null : ExamRecordCacheUtil.getMonitorStatus(recordId, source.name());
-                            if (Objects.nonNull(status) && Objects.equals(status, MonitorStatusSourceEnum.STOP)) {
-                                monitorStatusSourceCount.getAndSet(monitorStatusSourceCount.get() + 1);
-                            }
-                            ExamRecordStatusEnum examRecordStatusEnum = (ExamRecordStatusEnum) v;
                             //已待考
                             if (Objects.equals(examRecordStatusEnum, ExamRecordStatusEnum.FIRST_PREPARE)) {
                                 prepareCount.getAndSet(prepareCount.get() + 1);
@@ -430,15 +436,15 @@ public class TEExamController {
                             }
                             //已完成
                             else if (Objects.equals(examRecordStatusEnum, ExamRecordStatusEnum.FINISHED) || Objects.equals(examRecordStatusEnum, ExamRecordStatusEnum.PERSISTED)) {
-                                alreadyComplete.getAndSet(alreadyComplete.get() + 1);
+                                finalAlreadyComplete.add(examActivityRecordCache.getExamStudentId());
                             }
                         });
                     }
                 });
             }
-            notComplete = allCount - alreadyComplete.get();
-            BigDecimal completionRate = new BigDecimal(alreadyComplete.get()).divide(new BigDecimal(allCount)).setScale(2, BigDecimal.ROUND_HALF_UP);
-            examPropCountDto = new ExamPropCountDto(examId, allCount, prepareCount.get(), examCount.get(), clientWebsocketStatusCount.get(), monitorStatusSourceCount.get(), alreadyComplete.get(), notComplete, completionRate);
+            notComplete = allCount - alreadyComplete.size();
+            BigDecimal completionRate = new BigDecimal(alreadyComplete.size()).divide(new BigDecimal(allCount)).setScale(2, BigDecimal.ROUND_HALF_UP);
+            examPropCountDto = new ExamPropCountDto(examId, allCount, prepareCount.get(), examCount.get(), clientWebsocketStatusCount.get(), monitorStatusSourceCount.get(), alreadyComplete.size(), notComplete, completionRate);
         } else {
             examPropCountDto = new ExamPropCountDto(examId, 0, 0, 0, 0, 0, 0, 0, new BigDecimal(0));
         }

+ 3 - 1
themis-backend/src/main/java/com/qmth/themis/backend/api/TIeInvigilateController.java

@@ -8,6 +8,7 @@ import com.qmth.themis.business.bean.backend.*;
 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.ExamActivityRecordCache;
 import com.qmth.themis.business.cache.bean.ExamCacheBean;
 import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
 import com.qmth.themis.business.config.SystemConfig;
@@ -543,7 +544,8 @@ public class TIeInvigilateController {
                 Map<String, Object> objectMap = redisUtil.getHashEntries(RedisKeyHelper.examActivityRecordCacheKey(s));
                 if (Objects.nonNull(objectMap) && objectMap.size() > 0) {
                     objectMap.forEach((k, v) -> {
-                        ExamRecordStatusEnum examRecordStatusEnum = (ExamRecordStatusEnum) v;
+                        ExamActivityRecordCache examActivityRecordCache = (ExamActivityRecordCache) v;
+                        ExamRecordStatusEnum examRecordStatusEnum = examActivityRecordCache.getStatus();
                         //已待考
                         if (Objects.equals(examRecordStatusEnum, ExamRecordStatusEnum.FIRST_PREPARE)) {
                             prepareCount.getAndSet(prepareCount.get() + 1);

+ 13 - 13
themis-business/src/main/java/com/qmth/themis/business/cache/ExamActivityRecordCacheUtil.java

@@ -1,29 +1,29 @@
 package com.qmth.themis.business.cache;
 
+import com.qmth.themis.business.cache.bean.ExamActivityRecordCache;
 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 ExamActivityRecordCacheUtil {
-	private static RedisUtil redisUtil = SpringContextHolder.getBean(RedisUtil.class);
+    private static RedisUtil redisUtil = SpringContextHolder.getBean(RedisUtil.class);
 
-	public static void removeActivityRecordCache(Long activityId, Long examRecordId) {
-		redisUtil.delete(RedisKeyHelper.examActivityRecordCacheKey(activityId), examRecordId.toString());
-	}
-	public static void setExamRecordStatus(Long activityId, Long examRecordId, ExamRecordStatusEnum status) {
-		redisUtil.set(RedisKeyHelper.examActivityRecordCacheKey(activityId), examRecordId.toString(), status);
-	}
+    public static void removeActivityRecordCache(Long activityId, Long examRecordId) {
+        redisUtil.delete(RedisKeyHelper.examActivityRecordCacheKey(activityId), examRecordId.toString());
+    }
 
-	public static ExamRecordStatusEnum getExamRecordStatus(Long activityId, Long examRecordId) {
-		return (ExamRecordStatusEnum) redisUtil.get(RedisKeyHelper.examActivityRecordCacheKey(activityId),
-				examRecordId.toString());
-	}
+    public static void setExamRecordStatus(Long activityId, Long examRecordId, ExamActivityRecordCache examActivityRecordCache) {
+        redisUtil.set(RedisKeyHelper.examActivityRecordCacheKey(activityId), examRecordId.toString(), examActivityRecordCache);
+    }
 
+    public static ExamActivityRecordCache getExamRecordStatus(Long activityId, Long examRecordId) {
+        return (ExamActivityRecordCache) redisUtil.get(RedisKeyHelper.examActivityRecordCacheKey(activityId),
+                examRecordId.toString());
+    }
 }

+ 44 - 0
themis-business/src/main/java/com/qmth/themis/business/cache/bean/ExamActivityRecordCache.java

@@ -0,0 +1,44 @@
+package com.qmth.themis.business.cache.bean;
+
+import com.qmth.themis.business.enums.ExamRecordStatusEnum;
+
+import java.io.Serializable;
+
+/**
+ * @Description: examActivity record cache
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2020/9/27
+ */
+public class ExamActivityRecordCache implements Serializable {
+
+    private ExamRecordStatusEnum status;
+
+    private Long examStudentId;
+
+    public ExamActivityRecordCache() {
+
+    }
+
+    public ExamActivityRecordCache(Long examStudentId, ExamRecordStatusEnum status) {
+        this.examStudentId = examStudentId;
+        this.status = status;
+    }
+
+    public ExamRecordStatusEnum getStatus() {
+        return status;
+    }
+
+    public void setStatus(ExamRecordStatusEnum status) {
+        this.status = status;
+    }
+
+    public Long getExamStudentId() {
+        return examStudentId;
+    }
+
+    public void setExamStudentId(Long examStudentId) {
+        this.examStudentId = examStudentId;
+    }
+}

+ 55 - 110
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamServiceImpl.java

@@ -1,64 +1,13 @@
 package com.qmth.themis.business.service.impl;
 
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.math.BigDecimal;
-import java.text.SimpleDateFormat;
-import java.time.LocalDateTime;
-import java.time.ZoneOffset;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.UUID;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-import javax.annotation.Resource;
-
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.BeanUtils;
-import org.springframework.cache.annotation.CacheEvict;
-import org.springframework.cache.annotation.CachePut;
-import org.springframework.cache.annotation.Cacheable;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-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.AnswerSubmitBean;
-import com.qmth.themis.business.bean.exam.AudioLeftPlayCountSubmitBean;
-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.ExamResultBean;
-import com.qmth.themis.business.bean.exam.ExamResumeBean;
-import com.qmth.themis.business.bean.exam.ExamStartBean;
-import com.qmth.themis.business.bean.exam.StudentPaperStructBean;
+import com.qmth.themis.business.bean.exam.*;
 import com.qmth.themis.business.cache.ExamActivityRecordCacheUtil;
 import com.qmth.themis.business.cache.ExamRecordCacheUtil;
 import com.qmth.themis.business.cache.ExamingDataCacheUtil;
 import com.qmth.themis.business.cache.RedisKeyHelper;
-import com.qmth.themis.business.cache.bean.ExamActivityCacheBean;
-import com.qmth.themis.business.cache.bean.ExamCacheBean;
-import com.qmth.themis.business.cache.bean.ExamCourseCacheBean;
-import com.qmth.themis.business.cache.bean.ExamPaperCacheBean;
-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.cache.bean.ObjectiveAnswerCacheBean;
+import com.qmth.themis.business.cache.bean.*;
 import com.qmth.themis.business.config.SystemConfig;
 import com.qmth.themis.business.constant.SpringContextHolder;
 import com.qmth.themis.business.constant.SystemConstant;
@@ -72,37 +21,33 @@ import com.qmth.themis.business.entity.TBSession;
 import com.qmth.themis.business.entity.TBTaskHistory;
 import com.qmth.themis.business.entity.TEExam;
 import com.qmth.themis.business.entity.TOeExamRecord;
-import com.qmth.themis.business.enums.EntryAuthenticationPolicyEnum;
-import com.qmth.themis.business.enums.ExamModeEnum;
-import com.qmth.themis.business.enums.ExamRecordFieldEnum;
-import com.qmth.themis.business.enums.ExamRecordStatusEnum;
-import com.qmth.themis.business.enums.FinishExamResultEnum;
-import com.qmth.themis.business.enums.FinishTypeEnum;
-import com.qmth.themis.business.enums.HardwareTestEnum;
-import com.qmth.themis.business.enums.InvigilateVerifyEnum;
-import com.qmth.themis.business.enums.MonitorStatusSourceEnum;
-import com.qmth.themis.business.enums.MonitorVideoSourceEnum;
-import com.qmth.themis.business.enums.MqTagEnum;
-import com.qmth.themis.business.enums.MqTopicEnum;
-import com.qmth.themis.business.enums.ReviewResultEnum;
-import com.qmth.themis.business.enums.SystemOperationEnum;
-import com.qmth.themis.business.enums.TaskStatusEnum;
-import com.qmth.themis.business.enums.WebsocketStatusEnum;
-import com.qmth.themis.business.service.MqDtoService;
-import com.qmth.themis.business.service.TBTaskHistoryService;
-import com.qmth.themis.business.service.TEExamActivityService;
-import com.qmth.themis.business.service.TEExamCourseService;
-import com.qmth.themis.business.service.TEExamPaperService;
-import com.qmth.themis.business.service.TEExamService;
-import com.qmth.themis.business.service.TEExamStudentService;
-import com.qmth.themis.business.service.TOeExamRecordService;
-import com.qmth.themis.business.util.JacksonUtil;
-import com.qmth.themis.business.util.OssUtil;
-import com.qmth.themis.business.util.RedisUtil;
-import com.qmth.themis.business.util.ServletUtil;
-import com.qmth.themis.business.util.TencentYunUtil;
+import com.qmth.themis.business.enums.*;
+import com.qmth.themis.business.service.*;
+import com.qmth.themis.business.util.*;
 import com.qmth.themis.common.exception.BusinessException;
 import com.qmth.themis.common.util.IpUtil;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 /**
  * @Description: 考试批次 服务实现类
@@ -246,7 +191,7 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
     @Transactional
     @Override
     public ExamPrepareBean prepare(Long studentId, Long examStudentId) {
-    	
+
         TBSession tbSession = (TBSession) ServletUtil.getRequestSession();
         ExamStudentCacheBean es = teExamStudentService.getExamStudentCacheBean(examStudentId);
         if (es == null) {
@@ -257,26 +202,26 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
             throw new BusinessException("考生Id和当前登录用户不一致");
         }
         ExamCacheBean examCache = getExamCacheBeanNative(es.getExamId());
-        
-        if(examCache.getEnableIpLimit()!=null&&examCache.getEnableIpLimit().intValue()==1) {
-        	String ipAllows=examCache.getIpAllow();
-	        //ip限制判断
-	    	String ip=IpUtil.getRemoteIp(ServletUtil.getRequest());
-	    	boolean allow=false;
-	    	for(String ipAllow:ipAllows.split(",")) {
-	    		String reg="^"+ipAllow.replaceAll("\\*", "[0-9]{1,3}").replaceAll("\\.", "\\\\.")+"$";
-	        	Pattern p = Pattern.compile(reg);
-	            Matcher matcher = p.matcher(ip);
-	            if(matcher.matches()) {
-	            	allow=true;
-	            	break;
-	            }
-	    	}
-	    	if(!allow) {
-	    		throw new BusinessException("考生IP不被允许");
-	    	}
-        }
-        
+
+        if (examCache.getEnableIpLimit() != null && examCache.getEnableIpLimit().intValue() == 1) {
+            String ipAllows = examCache.getIpAllow();
+            //ip限制判断
+            String ip = IpUtil.getRemoteIp(ServletUtil.getRequest());
+            boolean allow = false;
+            for (String ipAllow : ipAllows.split(",")) {
+                String reg = "^" + ipAllow.replaceAll("\\*", "[0-9]{1,3}").replaceAll("\\.", "\\\\.") + "$";
+                Pattern p = Pattern.compile(reg);
+                Matcher matcher = p.matcher(ip);
+                if (matcher.matches()) {
+                    allow = true;
+                    break;
+                }
+            }
+            if (!allow) {
+                throw new BusinessException("考生IP不被允许");
+            }
+        }
+
         Long unFinishedRecordId = ExamingDataCacheUtil.getUnFinishedRecordId(studentId);
         if (unFinishedRecordId != null) {
             Long recordId = unFinishedRecordId;
@@ -379,7 +324,7 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
         // 更新考生缓存
         redisUtil.set(RedisKeyHelper.examStudentCacheKey(examStudentId), es);
         //更新场次-考试记录缓存
-        ExamActivityRecordCacheUtil.setExamRecordStatus(activityId, recordId, ExamRecordCacheUtil.getStatus(recordId));
+        ExamActivityRecordCacheUtil.setExamRecordStatus(activityId, recordId, new ExamActivityRecordCache(ExamRecordCacheUtil.getExamStudentId(recordId), ExamRecordCacheUtil.getStatus(recordId)));
         ExamingDataCacheUtil.setUnFinishedRecordId(studentId, recordId);
         //mq发送消息start
         TEStudentCacheDto teStudentCacheDto = (TEStudentCacheDto) redisUtil.getStudent(studentId);
@@ -527,7 +472,7 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
         Object[] values = new Object[]{firstStartTime, ExamRecordStatusEnum.ANSWERING, lastStartTime};
         toeExamRecordService.dataUpdatesMq(recordId, columns, values);
         //更新场次-考试记录缓存
-        ExamActivityRecordCacheUtil.setExamRecordStatus(activityId, recordId, ExamRecordCacheUtil.getStatus(recordId));
+        ExamActivityRecordCacheUtil.setExamRecordStatus(activityId, recordId, new ExamActivityRecordCache(ExamRecordCacheUtil.getExamStudentId(recordId), ExamRecordCacheUtil.getStatus(recordId)));
 
         //非强制交卷,换算最终交卷时间并生成一次性延时任务
         if (Objects.nonNull(exam.getForceFinish()) && exam.getForceFinish().intValue() == 0) {
@@ -847,7 +792,7 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
         Object[] values = new Object[]{lastPrepareTime, ExamRecordStatusEnum.RESUME_PREPARE};
         toeExamRecordService.dataUpdatesMq(recordId, columns, values);
         //更新场次-考试记录缓存
-        ExamActivityRecordCacheUtil.setExamRecordStatus(es.getExamActivityId(), recordId, ExamRecordCacheUtil.getStatus(recordId));
+        ExamActivityRecordCacheUtil.setExamRecordStatus(es.getExamActivityId(), recordId, new ExamActivityRecordCache(ExamRecordCacheUtil.getExamStudentId(recordId), ExamRecordCacheUtil.getStatus(recordId)));
         return ret;
     }
 
@@ -966,7 +911,7 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
         Object[] values = new Object[]{finishTime, durationSeconds, FinishTypeEnum.valueOf(type), ExamRecordStatusEnum.FINISHED};
         toeExamRecordService.dataUpdatesMq(recordId, columns, values);
         //更新场次-考试记录缓存
-        ExamActivityRecordCacheUtil.setExamRecordStatus(es.getExamActivityId(), recordId, ExamRecordCacheUtil.getStatus(recordId));
+        ExamActivityRecordCacheUtil.setExamRecordStatus(es.getExamActivityId(), recordId, new ExamActivityRecordCache(ExamRecordCacheUtil.getExamStudentId(recordId), ExamRecordCacheUtil.getStatus(recordId)));
         //更新未完成考试记录id
         TEStudentCacheDto teStudentCacheDto = (TEStudentCacheDto) redisUtil.getStudent(es.getStudentId());
         ExamingDataCacheUtil.deleteUnFinishedRecordId(studentId);
@@ -1011,10 +956,10 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
     public ExamCacheBean getExamCacheBean(Long examId) {
         return cacheOperation(examId);
     }
-    
+
     private ExamCacheBean getExamCacheBeanNative(Long examId) {
-    	TEExamService examService = SpringContextHolder.getBean(TEExamService.class);
-    	return examService.getExamCacheBean(examId);
+        TEExamService examService = SpringContextHolder.getBean(TEExamService.class);
+        return examService.getExamCacheBean(examId);
     }
 
     /**

+ 11 - 2
themis-business/src/main/resources/mapper/TOeExamRecordMapper.xml

@@ -134,7 +134,7 @@
 			</if>
 			<if test="status != null and status != ''">
 				<choose>
-					<when test="status == EXAMING">
+					<when test="status == 'EXAMING'">
 						and (t.status = 'ANSWERING' or t.status = 'RESUME_PREPARE')
 					</when>
 					<otherwise>
@@ -184,6 +184,9 @@
         <if test="paperDownload != null and paperDownload != ''">
             and t.paper_download = #{paperDownload}
         </if>
+		<if test="status == null or status == ''">
+			and t.status = 'FIRST_PREPARE' or t.status = 'ANSWERING' or t.status = 'BREAK_OFF' or t.status = 'RESUME_PREPARE'
+		</if>
         ) t,
         (SELECT @i := 0) as i
 		order by t.roomCode
@@ -204,6 +207,9 @@
 		<if test="paperDownload != null and paperDownload != ''">
 			and t.paper_download = #{paperDownload}
 		</if>
+		<if test="status == null or status == ''">
+			and t.status = 'FIRST_PREPARE' or t.status = 'ANSWERING' or t.status = 'BREAK_OFF' or t.status = 'RESUME_PREPARE'
+		</if>
 		) t,
 		(SELECT @i := 0) as i
 		order by t.roomCode
@@ -218,6 +224,9 @@
 		<if test="examId != null and examId != ''">
 			and t.exam_id = #{examId}
 		</if>
+		<if test="status == null or status == ''">
+			and t.status = 'FIRST_PREPARE' or t.status = 'ANSWERING' or t.status = 'BREAK_OFF' or t.status = 'RESUME_PREPARE'
+		</if>
 		ORDER BY RAND() LIMIT #{randomNum}
 	</select>
 
@@ -477,7 +486,7 @@
 			and t.finish_type = #{finishType}
 		</if>
 		<if test="courseCode != null and courseCode != ''">
-			and tees.course_code like CONCAT('%', #{courseCode},'%')
+			and s.course_code like CONCAT('%', #{courseCode},'%')
 		</if>
 		) t,
 		(SELECT @i := 0) as i

+ 2 - 5
themis-exam/src/main/java/com/qmth/themis/exam/api/TEStudentController.java

@@ -9,10 +9,7 @@ import com.qmth.themis.business.bean.exam.ExamUnFinishBean;
 import com.qmth.themis.business.cache.ExamActivityRecordCacheUtil;
 import com.qmth.themis.business.cache.ExamRecordCacheUtil;
 import com.qmth.themis.business.cache.ExamingDataCacheUtil;
-import com.qmth.themis.business.cache.bean.ExamActivityCacheBean;
-import com.qmth.themis.business.cache.bean.ExamCacheBean;
-import com.qmth.themis.business.cache.bean.ExamCourseCacheBean;
-import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
+import com.qmth.themis.business.cache.bean.*;
 import com.qmth.themis.business.config.SystemConfig;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.dto.AuthDto;
@@ -265,7 +262,7 @@ public class TEStudentController {
                             mqDtoService.assembleSendOneWayMsg(mqDtoBreak);
                             //考试断点异常原因 发送mq end
                             //更新场次-考试记录缓存
-                            ExamActivityRecordCacheUtil.setExamRecordStatus(examActivityId, recordId, ExamRecordCacheUtil.getStatus(recordId));
+                            ExamActivityRecordCacheUtil.setExamRecordStatus(examActivityId, recordId, new ExamActivityRecordCache(ExamRecordCacheUtil.getExamStudentId(recordId), ExamRecordCacheUtil.getStatus(recordId)));
                         }
                         ExamUnFinishBean examUnFinishBean = this.unFinishCommon(recordId, ec, examStudentCacheBean, examActivityCacheBean, examStudentId);
                         map.put("unFinished", examUnFinishBean);

+ 2 - 1
themis-exam/src/main/java/com/qmth/themis/exam/config/ExamConstant.java

@@ -2,6 +2,7 @@ package com.qmth.themis.exam.config;
 
 import com.qmth.themis.business.cache.ExamActivityRecordCacheUtil;
 import com.qmth.themis.business.cache.ExamRecordCacheUtil;
+import com.qmth.themis.business.cache.bean.ExamActivityRecordCache;
 import com.qmth.themis.business.cache.bean.ExamCacheBean;
 import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
 import com.qmth.themis.business.constant.SpringContextHolder;
@@ -132,7 +133,7 @@ public class ExamConstant {
             mqDtoService.assembleSendOneWayMsg(mqDtoBreak);
             //考试断点异常原因 发送mq end
             //更新场次-考试记录缓存
-            ExamActivityRecordCacheUtil.setExamRecordStatus(examStudentCacheBean.getExamActivityId(), recordId, ExamRecordCacheUtil.getStatus(recordId));
+            ExamActivityRecordCacheUtil.setExamRecordStatus(examStudentCacheBean.getExamActivityId(), recordId, new ExamActivityRecordCache(ExamRecordCacheUtil.getExamStudentId(recordId), ExamRecordCacheUtil.getStatus(recordId)));
         }
     }
 }

+ 2 - 1
themis-mq/src/main/java/com/qmth/themis/mq/service/impl/MqLogicServiceImpl.java

@@ -7,6 +7,7 @@ import com.google.gson.Gson;
 import com.qmth.themis.business.cache.ExamActivityRecordCacheUtil;
 import com.qmth.themis.business.cache.ExamRecordCacheUtil;
 import com.qmth.themis.business.cache.RedisKeyHelper;
+import com.qmth.themis.business.cache.bean.ExamActivityRecordCache;
 import com.qmth.themis.business.cache.bean.ExamCacheBean;
 import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
 import com.qmth.themis.business.constant.SpringContextHolder;
@@ -266,7 +267,7 @@ public class MqLogicServiceImpl implements MqLogicService {
                 mqDtoService.assembleSendOneWayMsg(mqDtoBreak);
                 //考试断点异常原因 发送mq end
                 //更新场次-考试记录缓存
-                ExamActivityRecordCacheUtil.setExamRecordStatus(examActivityId, recordId, ExamRecordCacheUtil.getStatus(recordId));
+                ExamActivityRecordCacheUtil.setExamRecordStatus(examActivityId, recordId, new ExamActivityRecordCache(ExamRecordCacheUtil.getExamStudentId(recordId), ExamRecordCacheUtil.getStatus(recordId)));
             }
             //发送移动端监考退出考试mq消息 start
             MqDto mqDtoExamStop = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.EXAM_STOP.name(), recordId, MqTagEnum.EXAM_STOP, String.valueOf(recordId), String.valueOf(recordId));

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

@@ -3,6 +3,7 @@ package com.qmth.themis.task.quartz;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.qmth.themis.business.cache.ExamRecordCacheUtil;
 import com.qmth.themis.business.cache.RedisKeyHelper;
+import com.qmth.themis.business.cache.bean.ExamActivityRecordCache;
 import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
 import com.qmth.themis.business.entity.TEExam;
 import com.qmth.themis.business.entity.TEExamActivity;
@@ -62,7 +63,8 @@ public class MqActivityJob extends QuartzJobBean {
                         Map<String, Object> objectMap = redisUtil.getHashEntries(RedisKeyHelper.examActivityRecordCacheKey(teExamActivity.getId()));
                         if (Objects.nonNull(objectMap) && objectMap.size() > 0) {
                             objectMap.forEach((k, v) -> {
-                                ExamRecordStatusEnum examRecordStatusEnum = (ExamRecordStatusEnum) v;
+                                ExamActivityRecordCache examActivityRecordCache = (ExamActivityRecordCache) v;
+                                ExamRecordStatusEnum examRecordStatusEnum = examActivityRecordCache.getStatus();
                                 //获取该考试批次下所有未交卷的考生的考试记录
                                 if (Objects.nonNull(examRecordStatusEnum) && !Objects.equals(ExamRecordStatusEnum.FINISHED, examRecordStatusEnum) && !Objects.equals(ExamRecordStatusEnum.PERSISTED, examRecordStatusEnum) && !Objects.equals(ExamRecordStatusEnum.ANSWERING, examRecordStatusEnum)) {
                                     Long recordId = Long.parseLong(k);

+ 5 - 2
themis-task/src/main/java/com/qmth/themis/task/quartz/service/impl/QuartzLogicServiceImpl.java

@@ -4,6 +4,7 @@ import com.qmth.themis.business.cache.ExamActivityRecordCacheUtil;
 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.ExamActivityRecordCache;
 import com.qmth.themis.business.cache.bean.ExamCacheBean;
 import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
 import com.qmth.themis.business.enums.ExamRecordStatusEnum;
@@ -63,7 +64,8 @@ public class QuartzLogicServiceImpl implements QuartzLogicService {
             if (Objects.nonNull(forceFinish) && forceFinish.intValue() == 1) {//强制收卷
                 if (Objects.nonNull(objectMap) && objectMap.size() > 0) {
                     objectMap.forEach((k, v) -> {
-                        ExamRecordStatusEnum examRecordStatusEnum = (ExamRecordStatusEnum) v;
+                        ExamActivityRecordCache examActivityRecordCache = (ExamActivityRecordCache) v;
+                        ExamRecordStatusEnum examRecordStatusEnum = examActivityRecordCache.getStatus();
                         //获取该考试批次下所有未交卷的考生的考试记录
                         if (Objects.nonNull(examRecordStatusEnum) && !Objects.equals(ExamRecordStatusEnum.FINISHED, examRecordStatusEnum) && !Objects.equals(ExamRecordStatusEnum.PERSISTED, examRecordStatusEnum)) {
                             Long recordId = Long.parseLong(k);
@@ -83,7 +85,8 @@ public class QuartzLogicServiceImpl implements QuartzLogicService {
             } else {
                 if (Objects.nonNull(objectMap) && objectMap.size() > 0) {
                     objectMap.forEach((k, v) -> {
-                        ExamRecordStatusEnum examRecordStatusEnum = (ExamRecordStatusEnum) v;
+                        ExamActivityRecordCache examActivityRecordCache = (ExamActivityRecordCache) v;
+                        ExamRecordStatusEnum examRecordStatusEnum = examActivityRecordCache.getStatus();
                         //获取该考试批次下所有未交卷的考生的考试记录
                         if (Objects.nonNull(examRecordStatusEnum) && !Objects.equals(ExamRecordStatusEnum.FINISHED, examRecordStatusEnum) && !Objects.equals(ExamRecordStatusEnum.PERSISTED, examRecordStatusEnum) && !Objects.equals(ExamRecordStatusEnum.ANSWERING, examRecordStatusEnum)) {
                             Long recordId = Long.parseLong(k);