Quellcode durchsuchen

Merge branch 'dev' into release

# Conflicts:
#	themis-business/src/main/java/com/qmth/themis/business/cache/ExamRecordCacheUtil.java
#	themis-business/src/main/java/com/qmth/themis/business/dto/response/TEExamActivityDto.java
#	themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamServiceImpl.java
wangliang vor 4 Jahren
Ursprung
Commit
0a549ad46d
17 geänderte Dateien mit 325 neuen und 566 gelöschten Zeilen
  1. 7 28
      themis-backend/src/main/java/com/qmth/themis/backend/api/TIeInvigilateController.java
  2. 10 292
      themis-business/src/main/java/com/qmth/themis/business/bean/backend/InvigilateListDetailBean.java
  3. 44 0
      themis-business/src/main/java/com/qmth/themis/business/bean/backend/InvigilateListPatrolBean.java
  4. 0 2
      themis-business/src/main/java/com/qmth/themis/business/bean/mobile/MobileAuthorizationBean.java
  5. 11 14
      themis-business/src/main/java/com/qmth/themis/business/cache/ExamRecordCacheUtil.java
  6. 1 1
      themis-business/src/main/java/com/qmth/themis/business/dto/response/TEExamActivityDto.java
  7. 11 0
      themis-business/src/main/java/com/qmth/themis/business/dto/response/TIeWarningNotifyDto.java
  8. 13 0
      themis-business/src/main/java/com/qmth/themis/business/entity/TOeLivenessVerifyHistory.java
  9. 1 1
      themis-business/src/main/java/com/qmth/themis/business/enums/VerifyExceptionEnum.java
  10. 147 187
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamServiceImpl.java
  11. 33 14
      themis-business/src/main/java/com/qmth/themis/business/service/impl/WarningServiceImpl.java
  12. 1 0
      themis-business/src/main/resources/db/init.sql
  13. 0 1
      themis-business/src/main/resources/mapper/TEExamActivityMapper.xml
  14. 2 1
      themis-business/src/main/resources/mapper/TIeInvigilateWarnInfoMapper.xml
  15. 8 5
      themis-business/src/main/resources/mapper/TOeExamRecordMapper.xml
  16. 30 18
      themis-business/src/main/resources/mapper/TOeFaceVerifyHistoryMapper.xml
  17. 6 2
      themis-mq/src/main/java/com/qmth/themis/mq/service/impl/MqLogicServiceImpl.java

+ 7 - 28
themis-backend/src/main/java/com/qmth/themis/backend/api/TIeInvigilateController.java

@@ -196,44 +196,30 @@ public class TIeInvigilateController {
         String courseNameCode = examStudentCacheBean.getCourseName() + "(" + examStudentCacheBean.getCourseCode() + ")";
         String roomCode = examStudentCacheBean.getRoomCode();
         String roomName = examStudentCacheBean.getRoomName();
-        Long studentId = examStudentCacheBean.getStudentId();
         ExamActivityCacheBean examActivityCacheBean = teExamActivityService.getExamActivityCacheBean(examActivityId);
         ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examId);
         InvigilateListDetailBean invigilateListDetailBean = new InvigilateListDetailBean(examCacheBean.getName(), examActivityCacheBean.getCode(), examId, examActivityId, examStudentId, examRecordId, identity, examStudentName, courseNameCode, status, roomCode, roomName, breachStatus);
 
         //考生轨迹
-
+        QueryWrapper<TEExamStudentLog> teExamStudentLogQueryWrapper = new QueryWrapper<>();
+        teExamStudentLogQueryWrapper.lambda().eq(TEExamStudentLog::getExamRecordId,examRecordId)
+                .eq(TEExamStudentLog::getExamStudentId,examStudentId);
+        List<TEExamStudentLog> teExamStudentLogList = teExamStudentLogService.list(teExamStudentLogQueryWrapper);
+        invigilateListDetailBean.setTeExamStudentLogList(teExamStudentLogList);
 
         //预警、异常、人脸
         //预警
         QueryWrapper<TIeInvigilateWarnInfo> tIeInvigilateWarnInfoQueryWrapper = new QueryWrapper<>();
         tIeInvigilateWarnInfoQueryWrapper.lambda().eq(TIeInvigilateWarnInfo::getExamRecordId, examRecordId);
-        List<TIeInvigilateWarnInfo> tIeInvigilateWarnInfoList = tIeInvigilateWarnInfoService.list(tIeInvigilateWarnInfoQueryWrapper);
-        Integer warningCount = 0;
-        if (Objects.nonNull(tIeInvigilateWarnInfoList) && tIeInvigilateWarnInfoList.size() > 0) {
-            warningCount = tIeInvigilateWarnInfoList.size();
-        }
+        int warningCount = tIeInvigilateWarnInfoService.count(tIeInvigilateWarnInfoQueryWrapper);
         invigilateListDetailBean.setWarningCount(warningCount);
 
-        Gson gson = new Gson();
-        List<InvigilateListDetailBean.InvigilateWarnInfoBean> invigilateWarnInfoBeanList = gson.fromJson(gson.toJson(tIeInvigilateWarnInfoList), new TypeToken<List<InvigilateListDetailBean.InvigilateWarnInfoBean>>() {
-        }.getType());
-//        invigilateListDetailBean.setWarningInfos(invigilateWarnInfoBeanList);
-
         //异常
         QueryWrapper<TIeInvigilateExceptionInfo> tIeInvigilateExceptionInfoQueryWrapper = new QueryWrapper<>();
         tIeInvigilateExceptionInfoQueryWrapper.lambda().eq(TIeInvigilateExceptionInfo::getExamRecordId, examRecordId);
-        List<TIeInvigilateExceptionInfo> tIeInvigilateExceptionInfoList = tIeInvigilateExceptionInfoService.list(tIeInvigilateExceptionInfoQueryWrapper);
-        Integer exceptionCount = 0;
-        if (Objects.nonNull(tIeInvigilateExceptionInfoList) && tIeInvigilateExceptionInfoList.size() > 0) {
-            exceptionCount = tIeInvigilateExceptionInfoList.size();
-        }
+        int exceptionCount = tIeInvigilateExceptionInfoService.count(tIeInvigilateExceptionInfoQueryWrapper);
         invigilateListDetailBean.setExceptionCount(exceptionCount);
 
-        List<InvigilateListDetailBean.InvigilateExceptionInfoBean> invigilateExceptionInfoBeanList = gson.fromJson(gson.toJson(tIeInvigilateExceptionInfoList), new TypeToken<List<InvigilateListDetailBean.InvigilateExceptionInfoBean>>() {
-        }.getType());
-//        invigilateListDetailBean.setExceptionInfos(invigilateExceptionInfoBeanList);
-
         //陌生人脸
         tIeInvigilateWarnInfoQueryWrapper = new QueryWrapper<>();
         tIeInvigilateWarnInfoQueryWrapper.lambda().eq(TIeInvigilateWarnInfo::getExamRecordId, examRecordId)
@@ -242,13 +228,6 @@ public class TIeInvigilateController {
         int multipleFaceCount = tIeInvigilateWarnInfoService.count(tIeInvigilateWarnInfoQueryWrapper);
         invigilateListDetailBean.setMultipleFaceCount(multipleFaceCount);
 
-        //考生轨迹
-//        QueryWrapper<TEExamStudentLog> teExamStudentLogQueryWrapper = new QueryWrapper<>();
-//        teExamStudentLogQueryWrapper.lambda().and(Wrapper -> Wrapper.eq(TEExamStudentLog::getExamRecordId, examRecordId).or().eq(TEExamStudentLog::getStudentId, studentId)).orderByAsc(TEExamStudentLog::getCreateTime);
-//        List<TEExamStudentLog> teExamStudentLogList = teExamStudentLogService.list(teExamStudentLogQueryWrapper);
-//        List<InvigilateListDetailBean.StudentLogBean> studentLogBeanList = gson.fromJson(gson.toJson(teExamStudentLogList), new TypeToken<List<InvigilateListDetailBean.StudentLogBean>>() {
-//        }.getType());
-//        invigilateListDetailBean.setStudentLogs(studentLogBeanList);
         return ResultUtil.ok(invigilateListDetailBean);
     }
 

+ 10 - 292
themis-business/src/main/java/com/qmth/themis/business/bean/backend/InvigilateListDetailBean.java

@@ -1,5 +1,6 @@
 package com.qmth.themis.business.bean.backend;
 
+import com.qmth.themis.business.entity.TEExamStudentLog;
 import com.qmth.themis.business.enums.ExamRecordStatusEnum;
 import com.qmth.themis.business.enums.ExamTypeEnum;
 import com.qmth.themis.business.enums.ExceptionEnum;
@@ -73,7 +74,15 @@ public class InvigilateListDetailBean implements Serializable {
     private Integer breachStatus;
 
     @ApiModelProperty(name = "考生轨迹")
-    private List<ExamStudentTrailBean> examStudentTrailBean;
+    private List<TEExamStudentLog> teExamStudentLogList;
+
+    public List<TEExamStudentLog> getTeExamStudentLogList() {
+        return teExamStudentLogList;
+    }
+
+    public void setTeExamStudentLogList(List<TEExamStudentLog> teExamStudentLogList) {
+        this.teExamStudentLogList = teExamStudentLogList;
+    }
 
     public InvigilateListDetailBean(String examName, String examActivityCode, Long examId, Long examActivityId, Long examStudentId, Long examRecordId, String identity, String examStudentName, String courseNameCode, ExamRecordStatusEnum statusCode, String roomCode, String roomName, Integer breachStatus) {
         this.examName = examName;
@@ -115,14 +124,6 @@ public class InvigilateListDetailBean implements Serializable {
         this.roomName = roomName;
     }
 
-    public List<ExamStudentTrailBean> getExamStudentTrailBean() {
-        return examStudentTrailBean;
-    }
-
-    public void setExamStudentTrailBean(List<ExamStudentTrailBean> examStudentTrailBean) {
-        this.examStudentTrailBean = examStudentTrailBean;
-    }
-
     public Integer getBreachStatus() {
         return breachStatus;
     }
@@ -237,287 +238,4 @@ public class InvigilateListDetailBean implements Serializable {
     public void setStatusCode(ExamRecordStatusEnum statusCode) {
         this.statusCode = statusCode;
     }
-
-    /**
-    * @Description: 考生轨迹bean
-    * @Param:
-    * @return:
-    * @Author: wangliang
-    * @Date: 2020/9/15
-    */
-    private class ExamStudentTrailBean implements Serializable{
-
-        @ApiModelProperty(value = "考生轨迹信息")
-        private StudentLogBean studentLogBean;
-
-        @ApiModelProperty(value = "异常信息")
-        private InvigilateExceptionInfoBean invigilateExceptionInfoBean;
-
-        @ApiModelProperty(value = "预警信息")
-        private List<InvigilateWarnInfoBean> invigilateWarnInfoBeanList;
-
-        @ApiModelProperty(value = "创建时间")
-        private Date createTime;
-    }
-
-    /**
-     * @Description: 预警bean
-     * @Param:
-     * @return:
-     * @Author: wangliang
-     * @Date: 2020/8/24
-     */
-    public class InvigilateWarnInfoBean implements Serializable {
-
-        @ApiModelProperty(value = "预警信息")
-        private String info;
-
-        @ApiModelProperty(value = "预警级别")
-        private String level;
-
-        @ApiModelProperty(value = "类别")
-        private VerifyExceptionEnum type;
-
-        @ApiModelProperty(value = "备注")
-        private String remark;
-
-        @ApiModelProperty(value = "审阅状态,0:未阅,1:已阅")
-        private Integer approveStatus;
-
-        @ApiModelProperty(value = "创建时间")
-        private Date createTime;
-
-        @ApiModelProperty(value = "图片url")
-        private String photoUrl;
-
-        @ApiModelProperty(value = "视频url")
-        private String videoUrl;
-
-        public String getPhotoUrl() {
-            return photoUrl;
-        }
-
-        public void setPhotoUrl(String photoUrl) {
-            this.photoUrl = photoUrl;
-        }
-
-        public String getVideoUrl() {
-            return videoUrl;
-        }
-
-        public void setVideoUrl(String videoUrl) {
-            this.videoUrl = videoUrl;
-        }
-
-        public String getInfo() {
-            return info;
-        }
-
-        public void setInfo(String info) {
-            this.info = info;
-        }
-
-        public String getLevel() {
-            return level;
-        }
-
-        public void setLevel(String level) {
-            this.level = level;
-        }
-
-        public VerifyExceptionEnum getType() {
-            return type;
-        }
-
-        public void setType(VerifyExceptionEnum type) {
-            this.type = type;
-        }
-
-        public String getRemark() {
-            return remark;
-        }
-
-        public void setRemark(String remark) {
-            this.remark = remark;
-        }
-
-        public Integer getApproveStatus() {
-            return approveStatus;
-        }
-
-        public void setApproveStatus(Integer approveStatus) {
-            this.approveStatus = approveStatus;
-        }
-
-        public Date getCreateTime() {
-            return createTime;
-        }
-
-        public void setCreateTime(Date createTime) {
-            this.createTime = createTime;
-        }
-    }
-
-    /**
-     * @Description: 异常bean
-     * @Param:
-     * @return:
-     * @Author: wangliang
-     * @Date: 2020/8/24
-     */
-    public class InvigilateExceptionInfoBean implements Serializable {
-
-        @ApiModelProperty(value = "异常信息")
-        private String info;
-
-        @ApiModelProperty(value = "类别")
-        private ExceptionEnum type;
-
-        @ApiModelProperty(value = "备注")
-        private String remark;
-
-        @ApiModelProperty(value = "创建时间")
-        private Date createTime;
-
-        @ApiModelProperty(value = "处理时差,单位秒")
-        private Integer difference;
-
-        @ApiModelProperty(value = "图片url")
-        private String photoUrl;
-
-        @ApiModelProperty(value = "视频url")
-        private String videoUrl;
-
-        public String getPhotoUrl() {
-            return photoUrl;
-        }
-
-        public void setPhotoUrl(String photoUrl) {
-            this.photoUrl = photoUrl;
-        }
-
-        public String getVideoUrl() {
-            return videoUrl;
-        }
-
-        public void setVideoUrl(String videoUrl) {
-            this.videoUrl = videoUrl;
-        }
-
-        public Integer getDifference() {
-            return difference;
-        }
-
-        public void setDifference(Integer difference) {
-            this.difference = difference;
-        }
-
-        public String getInfo() {
-            return info;
-        }
-
-        public void setInfo(String info) {
-            this.info = info;
-        }
-
-        public ExceptionEnum getType() {
-            return type;
-        }
-
-        public void setType(ExceptionEnum type) {
-            this.type = type;
-        }
-
-        public String getRemark() {
-            return remark;
-        }
-
-        public void setRemark(String remark) {
-            this.remark = remark;
-        }
-
-        public Date getCreateTime() {
-            return createTime;
-        }
-
-        public void setCreateTime(Date createTime) {
-            this.createTime = createTime;
-        }
-    }
-
-    /**
-     * @Description: 考生日志bean
-     * @Param:
-     * @return:
-     * @Author: wangliang
-     * @Date: 2020/8/24
-     */
-    public class StudentLogBean implements Serializable {
-
-        @ApiModelProperty(value = "信息")
-        private String info;
-
-        @ApiModelProperty(value = "类别")
-        private ExamTypeEnum type;
-
-        @ApiModelProperty(value = "备注")
-        private String remark;
-
-        @ApiModelProperty(value = "创建时间")
-        private Date createTime;
-
-        @ApiModelProperty(value = "图片url")
-        private String photoUrl;
-
-        @ApiModelProperty(value = "视频url")
-        private String videoUrl;
-
-        public String getPhotoUrl() {
-            return photoUrl;
-        }
-
-        public void setPhotoUrl(String photoUrl) {
-            this.photoUrl = photoUrl;
-        }
-
-        public String getVideoUrl() {
-            return videoUrl;
-        }
-
-        public void setVideoUrl(String videoUrl) {
-            this.videoUrl = videoUrl;
-        }
-
-        public String getInfo() {
-            return info;
-        }
-
-        public void setInfo(String info) {
-            this.info = info;
-        }
-
-        public ExamTypeEnum getType() {
-            return type;
-        }
-
-        public void setType(ExamTypeEnum type) {
-            this.type = type;
-        }
-
-        public String getRemark() {
-            return remark;
-        }
-
-        public void setRemark(String remark) {
-            this.remark = remark;
-        }
-
-        public Date getCreateTime() {
-            return createTime;
-        }
-
-        public void setCreateTime(Date createTime) {
-            this.createTime = createTime;
-        }
-    }
 }

+ 44 - 0
themis-business/src/main/java/com/qmth/themis/business/bean/backend/InvigilateListPatrolBean.java

@@ -71,6 +71,50 @@ public class InvigilateListPatrolBean implements Serializable {
     @ApiModelProperty(name = "虚拟考场名称")
     private String roomName;
 
+    @ApiModelProperty(name = "答题进度")
+    private Double progress;
+
+    @ApiModelProperty(name = "科目编码")
+    private String courseCode;
+
+    @ApiModelProperty(name = "科目名称")
+    private String courseName;
+
+    @ApiModelProperty(name = "剩余时间")
+    private String remainTime;
+
+    public Double getProgress() {
+        return progress;
+    }
+
+    public void setProgress(Double progress) {
+        this.progress = progress;
+    }
+
+    public String getCourseCode() {
+        return courseCode;
+    }
+
+    public void setCourseCode(String courseCode) {
+        this.courseCode = courseCode;
+    }
+
+    public String getCourseName() {
+        return courseName;
+    }
+
+    public void setCourseName(String courseName) {
+        this.courseName = courseName;
+    }
+
+    public String getRemainTime() {
+        return remainTime;
+    }
+
+    public void setRemainTime(String remainTime) {
+        this.remainTime = remainTime;
+    }
+
     public Integer getSeq() {
         return seq;
     }

+ 0 - 2
themis-business/src/main/java/com/qmth/themis/business/bean/mobile/MobileAuthorizationBean.java

@@ -8,7 +8,6 @@ import io.swagger.annotations.ApiModelProperty;
 @ApiModel("登录返回信息")
 public class MobileAuthorizationBean {
 
-	
 	@ApiModelProperty("功能模式")
 	private MobileModeEnum mode;
 	
@@ -21,7 +20,6 @@ public class MobileAuthorizationBean {
 	@ApiModelProperty("考试记录id")
 	private Long recordId;
 	
-	//TODO
 	private String accessToken;
 
 	public MobileModeEnum getMode() {

+ 11 - 14
themis-business/src/main/java/com/qmth/themis/business/cache/ExamRecordCacheUtil.java

@@ -1,20 +1,14 @@
 package com.qmth.themis.business.cache;
 
-import java.util.Date;
-import java.util.Objects;
-
 import com.qmth.themis.business.constant.SpringContextHolder;
 import com.qmth.themis.business.constant.SystemConstant;
-import com.qmth.themis.business.enums.ExamRecordStatusEnum;
-import com.qmth.themis.business.enums.FinishTypeEnum;
-import com.qmth.themis.business.enums.MonitorCallStatusSourceEnum;
-import com.qmth.themis.business.enums.MonitorStatusSourceEnum;
-import com.qmth.themis.business.enums.MonitorVideoSourceEnum;
-import com.qmth.themis.business.enums.VerifyExceptionEnum;
-import com.qmth.themis.business.enums.WebsocketStatusEnum;
+import com.qmth.themis.business.enums.*;
 import com.qmth.themis.business.service.TOeExamRecordService;
 import com.qmth.themis.business.util.RedisUtil;
 
+import java.util.Date;
+import java.util.Objects;
+
 /**
  * 考试记录缓存hash值操作
  *
@@ -206,7 +200,7 @@ public class ExamRecordCacheUtil {
     }
 
     public static void setMonitorCallStatus(Long recordId, String source, MonitorCallStatusSourceEnum callStatusSourceEnum) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), SystemConstant.MONITOR_CALL_STATUS_ + source, callStatusSourceEnum.name());
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), SystemConstant.MONITOR_CALL_STATUS_ + source, callStatusSourceEnum);
     }
 
     public static WebsocketStatusEnum getClientWebsocketStatus(Long recordId) {
@@ -264,24 +258,27 @@ public class ExamRecordCacheUtil {
     public static Date getLastStartTime(Long recordId) {
         return (Date) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "lastStartTime");
     }
-    
+
     public static Date getStartTime(Long recordId) {
         return (Date) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "startTime");
     }
-    
+
     public static Date getEndTime(Long recordId) {
         return (Date) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "endTime");
     }
-    
+
     public static Integer getOpeningSeconds(Long recordId) {
         return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "openingSeconds");
     }
+
     public static Integer getMinDurationSeconds(Long recordId) {
         return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "minDurationSeconds");
     }
+
     public static Integer getMaxDurationSeconds(Long recordId) {
         return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "maxDurationSeconds");
     }
+
     public static Integer getForceFinish(Long recordId) {
         return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "forceFinish");
     }

+ 1 - 1
themis-business/src/main/java/com/qmth/themis/business/dto/response/TEExamActivityDto.java

@@ -212,7 +212,7 @@ public class TEExamActivityDto implements Serializable {
         this.inProcessLivenessJudgePolicy = ec.getInProcessLivenessJudgePolicy().name();
         this.startTime = examActivityCacheBean.getStartTime();
         this.finishTime = examActivityCacheBean.getFinishTime();
-        this.leftExamCount = ec.getExamCount()-examStudentCacheBean.getAlreadyExamCount();
+        this.leftExamCount = ec.getExamCount() - examStudentCacheBean.getAlreadyExamCount();
         this.mobilePhotoUpload = ec.getMobilePhotoUpload();
         this.examId = ec.getId();
     }

+ 11 - 0
themis-business/src/main/java/com/qmth/themis/business/dto/response/TIeWarningNotifyDto.java

@@ -35,6 +35,17 @@ public class TIeWarningNotifyDto implements Serializable {
     @ApiModelProperty(name = "预警备注")
     private String remark;//预警备注
 
+    @ApiModelProperty(name = "考试记录id")
+    private Long examRecordId;//考试记录id
+
+    public Long getExamRecordId() {
+        return examRecordId;
+    }
+
+    public void setExamRecordId(Long examRecordId) {
+        this.examRecordId = examRecordId;
+    }
+
     public Long getExamId() {
         return examId;
     }

+ 13 - 0
themis-business/src/main/java/com/qmth/themis/business/entity/TOeLivenessVerifyHistory.java

@@ -3,6 +3,7 @@ package com.qmth.themis.business.entity;
 import java.io.Serializable;
 import java.util.Date;
 
+import com.baomidou.mybatisplus.annotation.FieldFill;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.qmth.themis.business.enums.LivenessTypeEnum;
@@ -54,6 +55,18 @@ public class TOeLivenessVerifyHistory implements Serializable {
     @TableField(value = "finish_time")
     private Date finishTime;
 
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "create_time", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
     public static long getSerialVersionUID() {
         return serialVersionUID;
     }

+ 1 - 1
themis-business/src/main/java/com/qmth/themis/business/enums/VerifyExceptionEnum.java

@@ -22,7 +22,7 @@ public enum VerifyExceptionEnum {
 
 	NONE("无异常", Arrays.asList("-1")),
 
-	REALNESS("真实性检测", Arrays.asList("D15"));
+	REALNESS("真实性检测异常", Arrays.asList("D15"));
 
 	private String code;
 

+ 147 - 187
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamServiceImpl.java

@@ -1,56 +1,11 @@
 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.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.UUID;
-
-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.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.*;
 import com.qmth.themis.business.config.SystemConfig;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.dao.TEExamMapper;
@@ -63,32 +18,32 @@ 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.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.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.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.enums.*;
+import com.qmth.themis.business.service.*;
 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.common.exception.BusinessException;
+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.*;
 
 /**
  * @Description: 考试批次 服务实现类
@@ -129,7 +84,7 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
 
     @Resource
     TencentYunUtil tencentYunUtil;
-    
+
     @Resource
     private TBTaskHistoryService tbTaskHistoryService;
 
@@ -163,10 +118,12 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
     public List<TEExamDto> getWaitingExam(Long studentId, Long examId, Long orgId) {
         List<TEExamDto> list = teExamMapper.getWaitingExam(studentId, examId, orgId);
         if (Objects.nonNull(list) && list.size() > 0) {
-        	ExamCacheBean examCache=getExamCacheBean(examId);
             list.forEach(s -> {
                 List<TEExamActivityDto> teExamActivityList = teExamActivityService.getWaitingExam(studentId, s.getId(), s.getExamActivityId(), s.getMode());
                 teExamActivityList.forEach(v -> {
+                    ExamCacheBean examCache = getExamCacheBean(v.getExamId());
+                    ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(v.getExamStudentId());
+                    v.setLeftExamCount(examCache.getExamCount() - examStudentCacheBean.getAlreadyExamCount());
                     if (Objects.nonNull(v.getInProcessLivenessFixedRangeStr())) {
                         String[] longs = v.getInProcessLivenessFixedRangeStr().trim().replaceAll(" ", "").split(",");
                         List inProcessLivenessFixedRange = new ArrayList();
@@ -203,8 +160,6 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
                     } else {
                         v.setMonitorVideoSource(null);
                     }
-                    ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(v.getExamStudentId());
-                    v.setLeftExamCount(examCache.getExamCount()-examStudentCacheBean.getAlreadyExamCount());
                 });
                 s.setActivities(teExamActivityList);
             });
@@ -227,32 +182,32 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
         if (!studentId.equals(es.getStudentId())) {
             throw new BusinessException("考生Id和当前登录用户不一致");
         }
-        ExamCacheBean examCache=getExamCacheBean(es.getExamId());
+        ExamCacheBean examCache = getExamCacheBean(es.getExamId());
         TEStudentCacheDto teStudentCacheDto = (TEStudentCacheDto) redisUtil.getStudent(es.getStudentId());
         if (teStudentCacheDto.getUnFinishedRecordId() != null) {
             Long recordId = teStudentCacheDto.getUnFinishedRecordId();
-            if(examStudentId.equals(ExamRecordCacheUtil.getExamStudentId(recordId))) {//当前考生已存在候考的考试记录
-	            ExamPaperCacheBean ep = teExamPaperService.getExamPaperCacheBean(ExamRecordCacheUtil.getPaperId(recordId));
-	            ExamCourseCacheBean ec = teExamCourseService.getExamCourseCacheBean(es.getExamId(), es.getCourseCode());
-	            ExamPrepareBean prepare = new ExamPrepareBean();
-	            prepare.setRecordId(recordId);
-	            prepare.setAudioPlayCount(ep.getAudioPlayCount());
-	            prepare.setHasAudio((ep.getHasAudio() == null || ep.getHasAudio().intValue() == 0 ? false : true));
-	            prepare.setObjectiveShuffle(
-	                    (ec.getObjectiveShuffle() == null || ec.getObjectiveShuffle().intValue() == 0 ? false : true));
-	            prepare.setOptionShuffle(
-	                    (ec.getOptionShuffle() == null || ec.getOptionShuffle().intValue() == 0 ? false : true));
-	            String paperurl = OssUtil.getUrlForPrivateBucket(systemConfig.getOssEnv(3), ep.getPaperPath());
-	            String structurl = OssUtil.getUrlForPrivateBucket(systemConfig.getOssEnv(3), ep.getStructPath());
-	            prepare.setPaperUrl(paperurl);
-	            prepare.setStructUrl(structurl);
-	            prepare.setMonitorKey(ExamRecordCacheUtil.getMonitorKey(recordId));
-	            prepare.setMonitorUserId("s_" + tbSession.getId());
-	            prepare.setMonitorUserSig(tencentYunUtil.getSign(prepare.getMonitorUserId(), SystemConstant.TENCENT_EXPIRE_TIME));
-	            return prepare;
+            if (examStudentId.equals(ExamRecordCacheUtil.getExamStudentId(recordId))) {//当前考生已存在候考的考试记录
+                ExamPaperCacheBean ep = teExamPaperService.getExamPaperCacheBean(ExamRecordCacheUtil.getPaperId(recordId));
+                ExamCourseCacheBean ec = teExamCourseService.getExamCourseCacheBean(es.getExamId(), es.getCourseCode());
+                ExamPrepareBean prepare = new ExamPrepareBean();
+                prepare.setRecordId(recordId);
+                prepare.setAudioPlayCount(ep.getAudioPlayCount());
+                prepare.setHasAudio((ep.getHasAudio() == null || ep.getHasAudio().intValue() == 0 ? false : true));
+                prepare.setObjectiveShuffle(
+                        (ec.getObjectiveShuffle() == null || ec.getObjectiveShuffle().intValue() == 0 ? false : true));
+                prepare.setOptionShuffle(
+                        (ec.getOptionShuffle() == null || ec.getOptionShuffle().intValue() == 0 ? false : true));
+                String paperurl = OssUtil.getUrlForPrivateBucket(systemConfig.getOssEnv(3), ep.getPaperPath());
+                String structurl = OssUtil.getUrlForPrivateBucket(systemConfig.getOssEnv(3), ep.getStructPath());
+                prepare.setPaperUrl(paperurl);
+                prepare.setStructUrl(structurl);
+                prepare.setMonitorKey(ExamRecordCacheUtil.getMonitorKey(recordId));
+                prepare.setMonitorUserId("s_" + tbSession.getId());
+                prepare.setMonitorUserSig(tencentYunUtil.getSign(prepare.getMonitorUserId(), SystemConstant.TENCENT_EXPIRE_TIME));
+                return prepare;
             }
         }
-        if (examCache.getExamCount().intValue()<=es.getAlreadyExamCount().intValue()) {
+        if (examCache.getExamCount().intValue() <= es.getAlreadyExamCount().intValue()) {
             throw new BusinessException("没有剩余考试次数");
         }
         ExamCacheBean exam = getExamCacheBean(es.getExamId());
@@ -262,16 +217,16 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
             throw new BusinessException("未找到场次");
         }
         Date now = new Date();
-        if(ExamModeEnum.ANYTIME.equals(exam.getMode())) {
-    		Long start = ac.getStartTime().getTime() - (ac.getPrepareSeconds() * 1000);
-    		Long end = ac.getFinishTime().getTime();
-    		if (now.getTime() < start) {
-    			throw new BusinessException("没有到允许开考的时间");
-    		}
-    		if (now.getTime() > end) {
-    			throw new BusinessException("允许开考的时间已结束");
-    		}
-        }else {
+        if (ExamModeEnum.ANYTIME.equals(exam.getMode())) {
+            Long start = ac.getStartTime().getTime() - (ac.getPrepareSeconds() * 1000);
+            Long end = ac.getFinishTime().getTime();
+            if (now.getTime() < start) {
+                throw new BusinessException("没有到允许开考的时间");
+            }
+            if (now.getTime() > end) {
+                throw new BusinessException("允许开考的时间已结束");
+            }
+        } else {
             Long start = ac.getStartTime().getTime() - (ac.getPrepareSeconds() * 1000);
             Long end = ac.getStartTime().getTime() + (ac.getOpeningSeconds() * 1000);
             if (now.getTime() < start) {
@@ -281,7 +236,7 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
                 throw new BusinessException("允许开考的时间已结束");
             }
         }
-        
+
         ExamCourseCacheBean ec = teExamCourseService.getExamCourseCacheBean(es.getExamId(), es.getCourseCode());
         if (ec == null) {
             throw new BusinessException("未找到考试科目");
@@ -303,7 +258,7 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
         }
 
         // 写入次数
-        Integer alreadyExamCount = es.getAlreadyExamCount()+1;
+        Integer alreadyExamCount = es.getAlreadyExamCount() + 1;
 
         Long recordId = toeExamRecordService.saveByPrepare(es.getExamId(), es.getExamActivityId(), examStudentId,
                 paperId, alreadyExamCount);
@@ -328,7 +283,6 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
         prepare.setMonitorUserId("s_" + tbSession.getId());
         prepare.setMonitorUserSig(tencentYunUtil.getSign(prepare.getMonitorUserId(), SystemConstant.TENCENT_EXPIRE_TIME));
 
-        
         // 更新考生缓存
         redisUtil.set(RedisKeyHelper.examStudentCacheKey(examStudentId), es);
         //更新场次-考试记录缓存
@@ -342,9 +296,9 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
         //mq发送消息end
         return prepare;
     }
-    
-    private void updateExamStudent(Long examStudentId,Integer alreadyExamCount,Long currentRecordId) {
-    	Map<String, Object> transMap = new HashMap<String, Object>();
+
+    private void updateExamStudent(Long examStudentId, Integer alreadyExamCount, Long currentRecordId) {
+        Map<String, Object> transMap = new HashMap<String, Object>();
         transMap.put("examStudentId", examStudentId);
         transMap.put("alreadyExamCount", alreadyExamCount);
         transMap.put("currentRecordId", currentRecordId);
@@ -395,24 +349,24 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
             throw new BusinessException("未找到场次");
         }
         Date now = new Date();
-        if(ExamModeEnum.ANYTIME.equals(exam.getMode())) {
-    		Long start = ac.getStartTime().getTime();
-    		Long end = ac.getFinishTime().getTime();
-    		if (now.getTime() < start) {
-    			throw new BusinessException("没有到允许开考的时间");
-    		}
-    		if (now.getTime() > end) {
-    			throw new BusinessException("允许开考的时间已结束");
-    		}
-        }else {
-	        Long start = ac.getStartTime().getTime();
-	        Long end = ac.getStartTime().getTime() + (ac.getOpeningSeconds() * 1000);
-	        if (now.getTime() < start) {
-	            throw new BusinessException("没有到允许开考的时间");
-	        }
-	        if (now.getTime() > end) {
-	            throw new BusinessException("允许开考的时间已结束");
-	        }
+        if (ExamModeEnum.ANYTIME.equals(exam.getMode())) {
+            Long start = ac.getStartTime().getTime();
+            Long end = ac.getFinishTime().getTime();
+            if (now.getTime() < start) {
+                throw new BusinessException("没有到允许开考的时间");
+            }
+            if (now.getTime() > end) {
+                throw new BusinessException("允许开考的时间已结束");
+            }
+        } else {
+            Long start = ac.getStartTime().getTime();
+            Long end = ac.getStartTime().getTime() + (ac.getOpeningSeconds() * 1000);
+            if (now.getTime() < start) {
+                throw new BusinessException("没有到允许开考的时间");
+            }
+            if (now.getTime() > end) {
+                throw new BusinessException("允许开考的时间已结束");
+            }
         }
         ExamRecordStatusEnum sta = ExamRecordCacheUtil.getStatus(recordId);
         if (ExamRecordStatusEnum.FINISHED.equals(sta) || ExamRecordStatusEnum.PERSISTED.equals(sta)) {
@@ -473,7 +427,8 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
      * 提交作答结果
      */
     @Override
-    public AnswerSubmitBean answerSubmit(Long studentId, Long recordId, Integer mainNumber, Integer subNumber, Integer subIndex,
+    public AnswerSubmitBean answerSubmit(Long studentId, Long recordId, Integer mainNumber, Integer
+            subNumber, Integer subIndex,
                                          String answer, Long version, Integer durationSeconds) {
 
         // 校验当前登录用户和参数一致性
@@ -541,7 +496,8 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
      * 更新音频剩余播放次数
      */
     @Override
-    public AudioLeftPlayCountSubmitBean audioLeftPlayCountSubmit(Long studentId, Long recordId, String key, Integer count) {
+    public AudioLeftPlayCountSubmitBean audioLeftPlayCountSubmit(Long studentId, Long recordId, String key, Integer
+            count) {
 
         // 校验当前登录用户和参数一致性
         if (ExamRecordCacheUtil.getId(recordId) == null) {
@@ -571,7 +527,8 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
      * 文件上传
      */
     @Override
-    public ExamFileUploadBean fileUpload(Long studentId, Long recordId, MultipartFile file, String suffix, String md5) {
+    public ExamFileUploadBean fileUpload(Long studentId, Long recordId, MultipartFile file, String suffix, String
+            md5) {
 
         // 校验当前登录用户和参数一致性
         if (ExamRecordCacheUtil.getId(recordId) == null) {
@@ -817,18 +774,18 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
         }
 
         Map<String, Object> transMap = new HashMap<String, Object>();
-		transMap.put("recordId", recordId);
-		String level = "10s";
-		Integer time = SystemConstant.mqDelayLevel.get(level);
-		LocalDateTime dt = LocalDateTime.now();
-		dt = dt.plusSeconds(Long.parseLong(level.replace("s", "")));
-		Map<String, Object> propMap = new HashMap<String, Object>();
-		propMap.put("timeOut", time);
-		propMap.put("mqExecTime", dt.toInstant(ZoneOffset.of("+8")).toEpochMilli());
-		MqDto mqDto = new MqDto(MqTopicEnum.themisTopic.getCode(), MqTagEnum.EXAM_RECORD_PERSISTED.name(),
-				transMap, MqTagEnum.EXAM_RECORD_PERSISTED, recordId.toString(), propMap, recordId.toString());
-
-		mqDtoService.assembleSendAsyncDelayMsg(mqDto);
+        transMap.put("recordId", recordId);
+        String level = "10s";
+        Integer time = SystemConstant.mqDelayLevel.get(level);
+        LocalDateTime dt = LocalDateTime.now();
+        dt = dt.plusSeconds(Long.parseLong(level.replace("s", "")));
+        Map<String, Object> propMap = new HashMap<String, Object>();
+        propMap.put("timeOut", time);
+        propMap.put("mqExecTime", dt.toInstant(ZoneOffset.of("+8")).toEpochMilli());
+        MqDto mqDto = new MqDto(MqTopicEnum.themisTopic.getCode(), MqTagEnum.EXAM_RECORD_PERSISTED.name(),
+                transMap, MqTagEnum.EXAM_RECORD_PERSISTED, recordId.toString(), propMap, recordId.toString());
+
+        mqDtoService.assembleSendAsyncDelayMsg(mqDto);
     }
 
     @Cacheable(value = "exam", key = "#examId", unless = "#result == null")
@@ -940,7 +897,8 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
      * @param mqDto
      */
     @Override
-    public void sendOeLogMessage(SystemOperationEnum systemOperationEnum, Long examStudentId, Long recordId, MqDto mqDto) {
+    public void sendOeLogMessage(SystemOperationEnum systemOperationEnum, Long examStudentId, Long recordId, MqDto
+            mqDto) {
         //mq发送消息start
         Map<String, Object> properties = new HashMap<>();
         properties.put("remark", systemOperationEnum.getCode());
@@ -985,62 +943,64 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
         }
         return ret;
     }
-    
-    /**重新算分
+
+    /**
+     * 重新算分
+     *
      * @param examId
      * @param taskId
      */
     @Override
-    public void calculateScore(Long examId,Long taskId) {
-    	int timeOutSecond=60*5;
-    	String lockKey = SystemConstant.REDIS_LOCK_CALCULATE_SCORE_PREFIX + examId;
+    public void calculateScore(Long examId, Long taskId) {
+        int timeOutSecond = 60 * 5;
+        String lockKey = SystemConstant.REDIS_LOCK_CALCULATE_SCORE_PREFIX + examId;
         Boolean lock = redisUtil.lock(lockKey, timeOutSecond);
         if (!lock) {
             return;
         }
-        TBTaskHistory task=null;
-        Long recordId=null;
+        TBTaskHistory task = null;
+        Long recordId = null;
         try {
-	    	task=tbTaskHistoryService.getById(taskId);
-	    	task.setStatus(TaskStatusEnum.RUNNING);
-	    	tbTaskHistoryService.saveOrUpdate(task);
-    		Long startId=0L;
-    		Long index=0L;
-    		Long total=toeExamRecordService.getCountByExamId(examId);
-    		if(total>0) {
-    			for(;;) {
-	    			List<TOeExamRecord> list=toeExamRecordService.getListByExamIdAndStartId(examId, startId);
-	    			if(list==null||list.size()==0) {
-	    				break;
-	    			}
-	    			startId=list.get(list.size()-1).getId();
-	    			for(TOeExamRecord rc:list) {
-	    				index++;
-	    				if(ExamRecordStatusEnum.PERSISTED.equals(rc.getStatus())) {
-	    					recordId=rc.getId();
-	    					toeExamRecordService.calculateScore(rc.getId());
-	    				}
-	    				redisUtil.expire(lockKey, timeOutSecond);
-	    			}
-	    			task.setProgress(getPercentage(index, total));
-	    			tbTaskHistoryService.saveOrUpdate(task);
-    			}
-    		}
-			task.setSummary("处理成功");
-			task.setProgress(100.0);
-			task.setStatus(TaskStatusEnum.FINISH);
-			task.setFinishTime(new Date());
-		} catch (Exception e) {
-			log.error("重新算分出错 recordId:"+(recordId==null?"":recordId), e);
-			task.setSummary("处理出错");
-			task.setStatus(TaskStatusEnum.FINISH);
-			task.setFinishTime(new Date());
-		} finally {
+            task = tbTaskHistoryService.getById(taskId);
+            task.setStatus(TaskStatusEnum.RUNNING);
+            tbTaskHistoryService.saveOrUpdate(task);
+            Long startId = 0L;
+            Long index = 0L;
+            Long total = toeExamRecordService.getCountByExamId(examId);
+            if (total > 0) {
+                for (; ; ) {
+                    List<TOeExamRecord> list = toeExamRecordService.getListByExamIdAndStartId(examId, startId);
+                    if (list == null || list.size() == 0) {
+                        break;
+                    }
+                    startId = list.get(list.size() - 1).getId();
+                    for (TOeExamRecord rc : list) {
+                        index++;
+                        if (ExamRecordStatusEnum.PERSISTED.equals(rc.getStatus())) {
+                            recordId = rc.getId();
+                            toeExamRecordService.calculateScore(rc.getId());
+                        }
+                        redisUtil.expire(lockKey, timeOutSecond);
+                    }
+                    task.setProgress(getPercentage(index, total));
+                    tbTaskHistoryService.saveOrUpdate(task);
+                }
+            }
+            task.setSummary("处理成功");
+            task.setProgress(100.0);
+            task.setStatus(TaskStatusEnum.FINISH);
+            task.setFinishTime(new Date());
+        } catch (Exception e) {
+            log.error("重新算分出错 recordId:" + (recordId == null ? "" : recordId), e);
+            task.setSummary("处理出错");
+            task.setStatus(TaskStatusEnum.FINISH);
+            task.setFinishTime(new Date());
+        } finally {
             redisUtil.releaseLock(lockKey);
         }
-    	tbTaskHistoryService.saveOrUpdate(task);
+        tbTaskHistoryService.saveOrUpdate(task);
     }
-    
+
     private Double getPercentage(Long a, Long b) {
         if (a == null) {
             a = 0L;

+ 33 - 14
themis-business/src/main/java/com/qmth/themis/business/service/impl/WarningServiceImpl.java

@@ -74,32 +74,22 @@ public class WarningServiceImpl implements WarningService {
                 Integer count = Integer.parseInt(String.valueOf(map.get("tmpCount")));
                 count = Objects.isNull(count) ? 0 : count;
                 if (count >= teConfig.getMultipleFaceCountError()) {
-                    List photoUrls = null;
-                    if (Objects.nonNull(map.get("photoUrls")) && !Objects.equals(map.get("photoUrls"), "")) {
-                        photoUrls = Arrays.asList(String.valueOf(map.get("photoUrls")).split(","));
-                    }
-                    if (Objects.isNull(photoUrls)) {
-                        photoUrls = new ArrayList();
-                    }
-                    photoUrls.add(photoUrl);
-                    JSONObject jsonObject = new JSONObject();
-                    jsonObject.put("PHOTOS", photoUrls);
                     TIeInvigilateWarnInfo tIeInvigilateWarnInfo = new TIeInvigilateWarnInfo(examId, examActivityId, recordId, examStudentId, warningEnum.getLevel().get(1), WarningLevelEnum.valueOf(warningEnum.getLevel().get(1)).getDesc(), warningEnum, photoUrl);
                     tIeInvigilateWarnInfoService.saveOrUpdate(tIeInvigilateWarnInfo);
-                    TEExamStudentLog teExamStudentLog = new TEExamStudentLog(tIeInvigilateWarnInfo.getType().name(), tIeInvigilateWarnInfo.getType().getCode(), jsonObject.toJSONString(), examStudentCacheBean.getStudentId(), examStudentCacheBean.getId(), recordId);
-                    teExamStudentLogService.saveOrUpdate(teExamStudentLog);
                     this.setWarningCount(recordId);
+                    this.setPhotoUrls(map, photoUrl, tIeInvigilateWarnInfo, examStudentCacheBean, recordId);
                 }
             }
         } else if (faceCount <= 0) {//未检测到人脸
             Map<String, Object> map = faceVerifyHistoryService.faceCountError(recordId, warningDto.getWarningEnum().name(), faceCount, false);
             if (Objects.nonNull(map) && map.size() > 0) {
-                Integer count = (Integer) map.get("tmpCount");
+                Integer count = Integer.parseInt(String.valueOf(map.get("tmpCount")));
                 count = Objects.isNull(count) ? 0 : count;
                 if (count >= teConfig.getNoFaceCountError()) {
                     TIeInvigilateWarnInfo tIeInvigilateWarnInfo = new TIeInvigilateWarnInfo(examId, examActivityId, recordId, examStudentId, warningEnum.getLevel().get(0), WarningLevelEnum.valueOf(warningEnum.getLevel().get(0)).getDesc(), warningEnum, photoUrl);
                     tIeInvigilateWarnInfoService.saveOrUpdate(tIeInvigilateWarnInfo);
                     this.setWarningCount(recordId);
+                    this.setPhotoUrls(map, photoUrl, tIeInvigilateWarnInfo, examStudentCacheBean, recordId);
                 }
             }
         }
@@ -120,19 +110,22 @@ public class WarningServiceImpl implements WarningService {
         Long examId = ExamRecordCacheUtil.getExamId(recordId);
         Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
         Long examActivityId = ExamRecordCacheUtil.getExamActivityId(recordId);
+        ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(examStudentId);
         Map<String, Object> map = faceVerifyHistoryService.faceCompareError(recordId, warningDto.getWarningEnum().name());
         if (Objects.nonNull(map) && map.size() > 0) {
-            Integer count = (Integer) map.get("tmpCount");
+            Integer count = Integer.parseInt(String.valueOf(map.get("tmpCount")));
             count = Objects.isNull(count) ? 0 : count;
             if (count >= teConfig.getMatchFaceCompareErrorCount()) {
                 TIeInvigilateWarnInfo tIeInvigilateWarnInfo = new TIeInvigilateWarnInfo(examId, examActivityId, recordId, examStudentId, warningEnum.getLevel().get(0), WarningLevelEnum.valueOf(warningEnum.getLevel().get(0)).getDesc(), warningEnum, photoUrl);
                 tIeInvigilateWarnInfoService.saveOrUpdate(tIeInvigilateWarnInfo);
                 this.setWarningCount(recordId);
+                this.setPhotoUrls(map, photoUrl, tIeInvigilateWarnInfo, examStudentCacheBean, recordId);
             }
             if (count >= teConfig.getTotalFaceCompareErrorCount()) {
                 TIeInvigilateWarnInfo tIeInvigilateWarnInfo = new TIeInvigilateWarnInfo(examId, examActivityId, recordId, examStudentId, warningEnum.getLevel().get(1), WarningLevelEnum.valueOf(warningEnum.getLevel().get(1)).getDesc(), warningEnum, photoUrl);
                 tIeInvigilateWarnInfoService.saveOrUpdate(tIeInvigilateWarnInfo);
                 this.setWarningCount(recordId);
+                this.setPhotoUrls(map, photoUrl, tIeInvigilateWarnInfo, examStudentCacheBean, recordId);
             }
         }
     }
@@ -173,11 +166,14 @@ public class WarningServiceImpl implements WarningService {
         Long examActivityId = ExamRecordCacheUtil.getExamActivityId(recordId);
         QueryWrapper<TOeFaceVerifyHistory> tOeFaceVerifyHistoryQueryWrapper = new QueryWrapper<>();
         tOeFaceVerifyHistoryQueryWrapper.lambda().eq(TOeFaceVerifyHistory::getExamRecordId, recordId).eq(TOeFaceVerifyHistory::getException, warningEnum.name());
+        ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(examStudentId);
         int count = faceVerifyHistoryService.count(tOeFaceVerifyHistoryQueryWrapper);
         if (count > teConfig.getRealnessCount()) {
             TIeInvigilateWarnInfo tIeInvigilateWarnInfo = new TIeInvigilateWarnInfo(examId, examActivityId, recordId, examStudentId, WarningLevelEnum.D15.name(), WarningLevelEnum.D15.getDesc(), warningEnum);
             tIeInvigilateWarnInfoService.saveOrUpdate(tIeInvigilateWarnInfo);
             this.setWarningCount(recordId);
+            TEExamStudentLog teExamStudentLog = new TEExamStudentLog(tIeInvigilateWarnInfo.getType().name(), tIeInvigilateWarnInfo.getType().getCode(), tIeInvigilateWarnInfo.getType().getCode(), examStudentCacheBean.getStudentId(), examStudentCacheBean.getId(), recordId);
+            teExamStudentLogService.saveOrUpdate(teExamStudentLog);
         }
     }
 
@@ -196,4 +192,27 @@ public class WarningServiceImpl implements WarningService {
             ExamRecordCacheUtil.setWarningCount(recordId, 1);
         }
     }
+
+    /**
+     * 设置图片集合
+     *
+     * @param map
+     * @param photoUrl
+     * @param tIeInvigilateWarnInfo
+     * @param examStudentCacheBean
+     * @param recordId
+     */
+    public void setPhotoUrls(Map<String, Object> map, String photoUrl, TIeInvigilateWarnInfo tIeInvigilateWarnInfo, ExamStudentCacheBean examStudentCacheBean, Long recordId) {
+        List<String> photoUrls = new ArrayList();
+        if (Objects.nonNull(map.get("photoUrls")) && !Objects.equals(map.get("photoUrls"), "")) {
+            String[] s = String.valueOf(map.get("photoUrls")).split(",");
+            Collections.addAll(photoUrls, s);
+        }
+        photoUrls.add(photoUrl);
+        JSONObject jsonObject = new JSONObject();
+        jsonObject.put("PHOTOS", photoUrls);
+        jsonObject.put("MIN_CREATE_TIME", (Date) map.get("createTime"));
+        TEExamStudentLog teExamStudentLog = new TEExamStudentLog(tIeInvigilateWarnInfo.getType().name(), tIeInvigilateWarnInfo.getType().getCode(), jsonObject.toJSONString(), examStudentCacheBean.getStudentId(), examStudentCacheBean.getId(), recordId);
+        teExamStudentLogService.saveOrUpdate(teExamStudentLog);
+    }
 }

+ 1 - 0
themis-business/src/main/resources/db/init.sql

@@ -1561,6 +1561,7 @@ CREATE TABLE `t_oe_liveness_verify_history` (
   `start_time` timestamp NULL COMMENT '开始时间',
   `finish_time` timestamp NULL COMMENT '完成时间',
   `exception` varchar(30) DEFAULT NULL COMMENT '异常类型',
+  `create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='活体验证记录';
 

+ 0 - 1
themis-business/src/main/resources/mapper/TEExamActivityMapper.xml

@@ -142,7 +142,6 @@
             tee.mobile_photo_upload as mobilePhotoUpload,
             teea.start_time as startTime,
             teea.finish_time as finishTime,
-            tees.left_exam_count as leftExamCount,
             tee.id as examId
         from
             t_e_exam_student tees

+ 2 - 1
themis-business/src/main/resources/mapper/TIeInvigilateWarnInfoMapper.xml

@@ -34,7 +34,8 @@
             tiiwi.`level`,
             tiiwi.id as warningId,
             tiiwi.remark,
-            tiiwi.exam_id as examId
+            tiiwi.exam_id as examId,
+            tiiwi.exam_record_id as examRecordId
         from
             t_ie_invigilate_warn_info tiiwi
         left join t_e_exam_student tees on

+ 8 - 5
themis-business/src/main/resources/mapper/TOeExamRecordMapper.xml

@@ -178,12 +178,12 @@
         <include refid="invigilatePageHead"/>
         ,(select count(1) from t_ie_invigilate_warn_info tiiwi where tiiwi.exam_record_id = t.id and
         tiiwi.approve_status = 0) as warningNew
+		,date_format(date_sub(date_add(teea.start_time, interval IFNULL(teea.max_duration_seconds,
+		tee.max_duration_seconds) second), interval teea.max_duration_seconds / 60 - t.duration_seconds
+		minute),'%H:%i:%s') as remainTime
         <include refid="invigilatePageMiddle"/>
 		<include refid="invigilatePageFoot"/>
-        <if test="paperDownload != null and paperDownload != ''">,
-            date_format(date_sub(date_add(teea.start_time, interval IFNULL(teea.max_duration_seconds,
-            tee.max_duration_seconds) second), interval teea.max_duration_seconds / 60 - t.duration_seconds
-            minute),'%H:%i:%s') as remainTime
+        <if test="paperDownload != null and paperDownload != ''">
             and t.paper_download = #{paperDownload}
         </if>
         ) t,
@@ -216,6 +216,9 @@
 		,(select count(1) from t_ie_invigilate_exception_info tiiei where tiiei.exam_record_id = t.id) as exceptionCount
 		,(select count(1) from t_ie_invigilate_warn_info tiiwi where tiiwi.exam_record_id = t.id and tiiwi.`type` =
 		'FACE_COUNT_ERROR' and tiiwi.`level` = 'D8') as multipleFaceCount
+		,date_format(date_sub(date_add(teea.start_time, interval IFNULL(teea.max_duration_seconds,
+		tee.max_duration_seconds) second), interval teea.max_duration_seconds / 60 - t.duration_seconds
+		minute),'%H:%i:%s') as remainTime
 		<include refid="invigilatePageMiddle" />
 		<include refid="invigilatePageFoot" />
 		) t
@@ -348,7 +351,7 @@
 		tees.name,
 		tees.course_code as courseCode,
 		tees.course_name as courseName,
-		tees.left_exam_count as leftExamCount,
+		(tee.exam_count - tees.already_exam_count) as leftExamCount,
 		if((select count(1) from t_oe_exam_record toer where toer.exam_student_id =
 		tees.id and (toer.status = 'FINISHED' or toer.status = 'PERSISTED') >
 		0),'已完成','未完成') as status

+ 30 - 18
themis-business/src/main/resources/mapper/TOeFaceVerifyHistoryMapper.xml

@@ -5,12 +5,14 @@
     <select id="faceCountError" resultType="java.util.Map">
         select
             sum(t.tmpCount) as tmpCount,
-            group_concat(t.photoUrl) as photoUrls
+            group_concat(t.photoUrl) as photoUrls,
+            min(t.createTime) as createTime
         from
             (
             select
                 count(1) as tmpCount,
-                group_concat(tofvh.photo_url) as photoUrl
+                group_concat(tofvh.photo_url) as photoUrl,
+                min(tofvh.create_time) as createTime
             from
                 t_oe_face_verify_history tofvh
             <where>
@@ -33,14 +35,15 @@
         union all
             select
                 count(1) as tmpCount,
-                group_concat(t.photoUrl)
+                group_concat(t.photoUrl),
+                min(t.create_time) as createTime
             from
                 (
                 select
                     CONVERT((tolvh.actions->>'$.faceCount')
                         USING utf8) as faceCount, tolvh.`exception`,
                     CONVERT((tolvh.actions->>'$.photoUrl')
-                        USING utf8) as photoUrl
+                        USING utf8) as photoUrl,tolvh.create_time
                 from
                     t_oe_liveness_verify_history tolvh
                 <where>
@@ -67,12 +70,14 @@
     <select id="faceCompareError" resultType="java.util.Map">
         select
             sum(t.tmpCount) as tmpCount,
-            group_concat(t.photoUrl) as photoUrls
+            group_concat(t.photoUrl) as photoUrls,
+            min(t.createTime) as createTime
         from
             (
             select
                 count(1) as tmpCount,
-                group_concat(tofvh.photo_url) as photoUrl
+                group_concat(tofvh.photo_url) as photoUrl,
+                min(tofvh.create_time) as createTime
             from
                 t_oe_face_verify_history tofvh
             <where>
@@ -85,20 +90,27 @@
             </where>
             group by tofvh.`exception`
         union all
-            select
+                select
                 count(1) as tmpCount,
+                group_concat(t.photoUrl),
+                min(t.create_time) as createTime
+                from
+                (
+                select
+                CONVERT((tolvh.actions->>'$.faceCount')
+                USING utf8) as faceCount, tolvh.`exception`,
                 CONVERT((tolvh.actions->>'$.photoUrl')
-                USING utf8) as photoUrl
-            from
+                USING utf8) as photoUrl,tolvh.create_time
+                from
                 t_oe_liveness_verify_history tolvh
-            <where>
-                <if test="recordId != null and recordId != ''">
-                    and tolvh.exam_record_id = #{recordId}
-                </if>
-                <if test="exception != null and exception != ''">
-                    and tolvh.`exception` = #{exception}
-                </if>
-            </where>
-            group by tolvh.`exception`) t
+                <where>
+                    <if test="recordId != null and recordId != ''">
+                        and tolvh.exam_record_id = #{recordId}
+                    </if>
+                    <if test="exception != null and exception != ''">
+                        and tolvh.`exception` = #{exception}
+                    </if>
+                </where> ) t
+            group by t.`exception`) t
     </select>
 </mapper>

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

@@ -494,10 +494,14 @@ public class MqLogicServiceImpl implements MqLogicService {
             //增加异常日志
             Long examId = ExamRecordCacheUtil.getExamId(recordId);
             Long examActivityId = ExamRecordCacheUtil.getExamActivityId(recordId);
-            TIeInvigilateExceptionInfo tIeInvigilateExceptionInfo = new TIeInvigilateExceptionInfo(examId, examActivityId, recordId, examStudentId, String.valueOf(jsonObject.getJSONObject("reason").get("reason")), exceptionEnum, diff);
+            String reason = String.valueOf(jsonObject.getJSONObject("reason").get("reason"));
+            TIeInvigilateExceptionInfo tIeInvigilateExceptionInfo = new TIeInvigilateExceptionInfo(examId, examActivityId, recordId, examStudentId, reason, exceptionEnum, diff);
             tIeInvigilateExceptionInfoService.saveOrUpdate(tIeInvigilateExceptionInfo);
-        } else if (tag.contains(MqTagEnum.WARNING_LOG.name())) {//考试预警日志
 
+            TEExamStudentLog teExamStudentLog = new TEExamStudentLog(exceptionEnum.name(), exceptionEnum.getCode(), reason, examStudentCacheBean.getStudentId(), examStudentCacheBean.getId(), recordId);
+            teExamStudentLogService.saveOrUpdate(teExamStudentLog);
+        } else if (tag.contains(MqTagEnum.WARNING_LOG.name())) {//考试预警日志
+            //todo 预警先预留
         }
         mqDto.setAck(SystemConstant.STANDARD_ACK_TYPE);
         TMRocketMessage tmRocketMessage = gson.fromJson(gson.toJson(mqDto), TMRocketMessage.class);