Ver código fonte

重新算分

xiatian 4 anos atrás
pai
commit
cdab17e82f

+ 39 - 0
themis-backend/src/main/java/com/qmth/themis/backend/api/TEExamController.java

@@ -67,6 +67,9 @@ public class TEExamController {
 
     @Resource
     RedisUtil redisUtil;
+    
+    @Resource
+    TBTaskHistoryService taskHistoryService;
 
     @ApiOperation(value = "考试批次修改/新增接口")
     @RequestMapping(value = "/save", method = RequestMethod.POST)
@@ -441,4 +444,40 @@ public class TEExamController {
         ExamPropCountDto examPropCountDto = new ExamPropCountDto(examId, allCount, prepareCount.get(), examCount.get(), clientWebsocketStatusCount.get(), monitorStatusSourceCount.get(), alreadyComplete.get(), notComplete, completionRate);
         return ResultUtil.ok(examPropCountDto);
     }
+    
+    @ApiOperation(value = "考试重新算分")
+    @RequestMapping(value = "/score/calculate", method = RequestMethod.POST)
+    @Transactional
+    @ApiResponses({@ApiResponse(code = 200, message = "{\"taskId\":0}", response = Result.class)})
+    public Result scoreCalculate(@ApiParam(value = "批次ID", required = true) @RequestParam Long examId) {
+    	//先查询考试相关信息
+        TEExam teExam = teExamService.getById(examId);
+        if (Objects.isNull(teExam)) {
+            throw new BusinessException(ExceptionResultEnum.EXAM_NO);
+        }
+        TBTaskHistory tbTaskHistory = null;
+        Map<String, Object> transMap = new HashMap<String, Object>();
+        try {
+            TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
+            //往任务表里插一条数据
+            tbTaskHistory = new TBTaskHistory(TaskTypeEnum.CALCULATE_EXAM_SCORE, TaskStatusEnum.INIT, "重新算分", 0d, tbUser.getId());
+            tbTaskHistory.setEntityId(examId);
+            taskHistoryService.save(tbTaskHistory);
+            transMap.put("examId", examId);
+            transMap.put(SystemConstant.TASK_ID, tbTaskHistory.getId());
+            //mq发送消息start
+            MqDto mqDto = new MqDto(MqTopicEnum.themisTopic.getCode(), MqTagEnum.EXAM_SCORE_CALCULATE.name(), transMap, MqTagEnum.EXAM_SCORE_CALCULATE, String.valueOf(tbTaskHistory.getId()), tbUser.getName());
+            mqDtoService.assembleSendOneWayMsg(mqDto);
+            //mq发送消息end
+        } catch (Exception e) {
+            if (e instanceof BusinessException) {
+                throw new BusinessException(e.getMessage());
+            } else {
+                throw new RuntimeException(e);
+            }
+        }
+        Map<String, Long> map = new HashMap<String, Long>();
+        map.put(SystemConstant.TASK_ID, tbTaskHistory.getId());
+        return ResultUtil.ok(map);
+    }
 }

+ 3 - 0
themis-backend/src/main/java/com/qmth/themis/backend/start/StartRunning.java

@@ -71,6 +71,9 @@ public class StartRunning implements CommandLineRunner {
         rocketMessageConsumer.setRocketMQConsumer(nameServer, MqGroupEnum.examRecordUpdateGroup.getCode(), MqTopicEnum.themisTopic.getCode(), MqTagEnum.EXAM_RECORD_UPDATE.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(ExamRecordUpdateConcurrentlyImpl.class));
         //考试记录数据初始化
         rocketMessageConsumer.setRocketMQConsumer(nameServer, MqGroupEnum.examRecordInitGroup.getCode(), MqTopicEnum.themisTopic.getCode(), MqTagEnum.EXAM_RECORD_INIT.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(ExamRecordInitConcurrentlyImpl.class));
+        
+        //考试重新算分
+        rocketMessageConsumer.setRocketMQConsumer(nameServer, MqGroupEnum.scoreCalculateGroup.getCode(), MqTopicEnum.themisTopic.getCode(), MqTagEnum.EXAM_SCORE_CALCULATE.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(CalculateScoreConcurrentlyImpl.class));
         SystemConstant.initTempFiles();
         log.info("服务器启动时执行 end");
     }

+ 4 - 0
themis-business/src/main/java/com/qmth/themis/business/dao/TOeExamRecordMapper.java

@@ -245,5 +245,9 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
 	
 	public List<Map<String,Object>> getDoneCountByDay(@Param("examId") Long examId, @Param("activityId") Long activityId,
 			@Param("roomCode") String roomCode,@Param("courseCode")  String courseCode);
+
+	public Long getCountByExamId(@Param("examId") Long examId);
+	
+	public List<TOeExamRecord> getListByExamIdAndStartId(@Param("examId")Long examId,@Param("startId") Long startId);
 	
 }

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

@@ -71,7 +71,12 @@ public enum MqGroupEnum {
     /**
      * 考试记录数据更新
      */
-    examRecordUpdateGroup("themis-group-exam-examRecordUpdate");
+    examRecordUpdateGroup("themis-group-exam-examRecordUpdate"),
+	
+	/**
+     * 考试重新算分
+     */
+    scoreCalculateGroup("themis-group-exam-scoreCalculate");
 
     private MqGroupEnum(String code) {
         this.code = code;

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

@@ -38,7 +38,8 @@ public enum MqTagEnum {
     EXAM_RECORD_INIT("考试记录数据初始化", "考试", "normal", 26),
     WARNING_LOG("预警标签", "预警", "normal", 27),
     EXCEPTION_LOG("异常标签", "异常", "normal", 28),
-    MONITOR_LOG("监考监控标签", "监考监控", "normal", 29);
+    MONITOR_LOG("监考监控标签", "监考监控", "normal", 29),
+    EXAM_SCORE_CALCULATE("重新算分", "考试", "normal", 30);
 
     private MqTagEnum(String desc, String code, String type, int id) {
         this.desc = desc;

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

@@ -187,4 +187,12 @@ public interface TEExamService extends IService<TEExam> {
      * @return
      */
     public List<TEExam> examPrivilegeQuery(Long userId);
+    
+	/**重新算分
+	 * @param examId
+	 * @param taskId
+	 */
+	void calculateScore(Long examId, Long taskId);
+	
+	
 }

+ 28 - 3
themis-business/src/main/java/com/qmth/themis/business/service/TOeExamRecordService.java

@@ -1,15 +1,21 @@
 package com.qmth.themis.business.service;
 
+import java.util.List;
+import java.util.Map;
+
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
-import com.qmth.themis.business.bean.backend.*;
+import com.qmth.themis.business.bean.backend.InvigilateListBean;
+import com.qmth.themis.business.bean.backend.InvigilateListHistoryBean;
+import com.qmth.themis.business.bean.backend.InvigilateListPatrolBean;
+import com.qmth.themis.business.bean.backend.InvigilateListProgressBean;
+import com.qmth.themis.business.bean.backend.InvigilateListVideoBean;
+import com.qmth.themis.business.bean.backend.InvigilateListWarningBean;
 import com.qmth.themis.business.entity.TOeExamRecord;
 import com.qmth.themis.business.enums.ExamTypeEnum;
 import com.qmth.themis.business.enums.LivenessTypeEnum;
 import com.qmth.themis.business.enums.VerifyExceptionEnum;
 
-import java.util.Map;
-
 /**
  * @Description: 考试记录 服务类
  * @Param:
@@ -292,4 +298,23 @@ public interface TOeExamRecordService extends IService<TOeExamRecord> {
                                                                       String clientWebsocketStatus,
                                                                       String monitorStatusSource,
                                                                       Long userId);
+
+
+	/**
+	 * 重新算分
+	 */
+	void calculateScore(Long recordId);
+
+	/**获取考试记录数
+	 * @param examId
+	 * @return
+	 */
+	Long getCountByExamId(Long examId);
+
+	/**批量获取考试记录
+	 * @param examId
+	 * @param startId
+	 * @return
+	 */
+	List<TOeExamRecord> getListByExamIdAndStartId(Long examId, Long startId);
 }

+ 129 - 19
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamServiceImpl.java

@@ -1,12 +1,53 @@
 package com.qmth.themis.business.service.impl;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+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.*;
+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.cache.ExamActivityRecordCacheUtil;
 import com.qmth.themis.business.cache.ExamRecordCacheUtil;
 import com.qmth.themis.business.cache.RedisKeyHelper;
-import com.qmth.themis.business.cache.bean.*;
+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.config.SystemConfig;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.dao.TEExamMapper;
@@ -16,30 +57,34 @@ import com.qmth.themis.business.dto.response.TEExamActivityDto;
 import com.qmth.themis.business.dto.response.TEExamDto;
 import com.qmth.themis.business.dto.response.TEExamQueryDto;
 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.*;
-import com.qmth.themis.business.service.*;
+import com.qmth.themis.business.enums.EntryAuthenticationPolicyEnum;
+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.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.IOException;
-import java.io.InputStream;
-import java.text.SimpleDateFormat;
-import java.util.*;
 
 /**
  * @Description: 考试批次 服务实现类
@@ -80,6 +125,9 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
 
     @Resource
     TencentYunUtil tencentYunUtil;
+    
+    @Resource
+    private TBTaskHistoryService tbTaskHistoryService;
 
     /**
      * 查询考试批次
@@ -901,4 +949,66 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
         }
         return ret;
     }
+    
+    /**重新算分
+     * @param examId
+     * @param taskId
+     */
+    @Override
+    public void calculateScore(Long examId,Long taskId) {
+    	TBTaskHistory task=tbTaskHistoryService.getById(taskId);
+    	task.setStatus(TaskStatusEnum.RUNNING);
+    	tbTaskHistoryService.saveOrUpdate(task);
+    	Long recordId=null;
+    	try {
+    		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())) {
+	    					toeExamRecordService.calculateScore(rc.getId());
+	    				}
+	    			}
+	    			task.setProgress(getPercentage(index, total));
+	    			tbTaskHistoryService.saveOrUpdate(task);
+    			}
+    		}
+			toeExamRecordService.calculateScore(recordId);
+			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());
+		}
+    	tbTaskHistoryService.saveOrUpdate(task);
+    }
+    
+    private Double getPercentage(Long a, Long b) {
+        if (a == null) {
+            a = 0L;
+        }
+        if (b == null) {
+            return null;
+        }
+        if (b == 0) {
+            return null;
+        }
+        Double da = Double.valueOf(a);
+        Double db = Double.valueOf(b);
+        BigDecimal bd = new BigDecimal(da / db);
+        Double tem = bd.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
+        return tem;
+    }
 }

+ 70 - 15
themis-business/src/main/java/com/qmth/themis/business/service/impl/TOeExamRecordServiceImpl.java

@@ -1,12 +1,39 @@
 package com.qmth.themis.business.service.impl;
 
+import java.io.File;
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
 import com.alibaba.fastjson.JSONArray;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.qmth.themis.business.bean.backend.*;
+import com.qmth.themis.business.bean.backend.InvigilateListBean;
+import com.qmth.themis.business.bean.backend.InvigilateListHistoryBean;
+import com.qmth.themis.business.bean.backend.InvigilateListPatrolBean;
+import com.qmth.themis.business.bean.backend.InvigilateListProgressBean;
+import com.qmth.themis.business.bean.backend.InvigilateListVideoBean;
+import com.qmth.themis.business.bean.backend.InvigilateListWarningBean;
 import com.qmth.themis.business.cache.ExamRecordCacheUtil;
 import com.qmth.themis.business.cache.RedisKeyHelper;
-import com.qmth.themis.business.cache.bean.*;
+import com.qmth.themis.business.cache.bean.ExamCacheBean;
+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.config.SystemConfig;
 import com.qmth.themis.business.constant.SpringContextHolder;
 import com.qmth.themis.business.constant.SystemConstant;
@@ -16,24 +43,24 @@ import com.qmth.themis.business.dto.response.TEExamUnFinishDto;
 import com.qmth.themis.business.entity.TEExamStudent;
 import com.qmth.themis.business.entity.TOeExamAnswer;
 import com.qmth.themis.business.entity.TOeExamRecord;
-import com.qmth.themis.business.enums.*;
-import com.qmth.themis.business.service.*;
+import com.qmth.themis.business.enums.ExamRecordStatusEnum;
+import com.qmth.themis.business.enums.ExamTypeEnum;
+import com.qmth.themis.business.enums.LivenessTypeEnum;
+import com.qmth.themis.business.enums.MqTagEnum;
+import com.qmth.themis.business.enums.MqTopicEnum;
+import com.qmth.themis.business.enums.ObjectiveScorePolicyEnum;
+import com.qmth.themis.business.enums.VerifyExceptionEnum;
+import com.qmth.themis.business.service.MqDtoService;
+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.TOeExamAnswerService;
+import com.qmth.themis.business.service.TOeExamRecordService;
 import com.qmth.themis.business.util.OssUtil;
 import com.qmth.themis.business.util.RedisUtil;
 import com.qmth.themis.common.contanst.Constants;
 import com.qmth.themis.common.util.FileUtil;
 import com.qmth.themis.common.util.SimpleBeanUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.BeanUtils;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import javax.annotation.Resource;
-import java.io.File;
-import java.math.BigDecimal;
-import java.text.SimpleDateFormat;
-import java.util.*;
 
 /**
  * @Description: 考试记录 服务实现类
@@ -562,4 +589,32 @@ public class TOeExamRecordServiceImpl extends ServiceImpl<TOeExamRecordMapper, T
     public IPage<InvigilateListHistoryBean> invigilatePageListHistory(IPage<Map> iPage, Long examId, Long examActivityId, String roomCode, String courseCode, String status, Integer breachStatus, String finishType, String name, String identity, Integer minMultipleFaceCount, Integer maxMultipleFaceCount, Integer minExceptionCount, Integer maxExceptionCount, Integer minWarningCount, Integer maxWarningCount, String clientWebsocketStatus, String monitorStatusSource, Long userId) {
         return tOeExamRecordMapper.invigilatePageListHistory(iPage, examId, examActivityId, roomCode, courseCode, status, breachStatus, finishType, name, identity, minMultipleFaceCount, maxMultipleFaceCount, minExceptionCount, maxExceptionCount, minWarningCount, maxWarningCount, clientWebsocketStatus, monitorStatusSource, userId);
     }
+    
+    /**
+     * 重新算分
+     */
+    @Transactional
+    @Override
+    public void calculateScore(Long recordId) {
+    	//TODO
+    }
+    
+    /**获取考试记录数
+     * @param examId
+     * @return
+     */
+    @Override
+    public Long getCountByExamId(Long examId) {
+    	return tOeExamRecordMapper.getCountByExamId(examId);
+    }
+    
+    /**批量获取考试记录
+     * @param examId
+     * @param startId
+     * @return
+     */
+    @Override
+    public List<TOeExamRecord> getListByExamIdAndStartId(Long examId,Long startId) {
+    	return tOeExamRecordMapper.getListByExamIdAndStartId(examId, startId);
+    }
 }

+ 427 - 382
themis-business/src/main/resources/mapper/TOeExamRecordMapper.xml

@@ -1,401 +1,446 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper
-        namespace="com.qmth.themis.business.dao.TOeExamRecordMapper">
+	namespace="com.qmth.themis.business.dao.TOeExamRecordMapper">
 
-    <select id="getUnFinishExam"
-            resultType="com.qmth.themis.business.dto.response.TEExamUnFinishDto">
-        select
-        tee.id,
-        teea.id as examActivityId,
-        toer.id as recordId,
-        tees.id as
-        examStudentId,
-        tee.name,
-        tee.mode,
-        tee.pre_notice as preNotice,
-        tee.pre_notice_stay_seconds as preNoticeStaySeconds,
-        tee.post_notice as
-        postNotice,
-        tee.code as examCode,
-        teea.code as examActivityCode,
-        tee.start_time as examStartTime,
-        tee.end_time as examEndTime,
-        teea.start_time as examActivityStartTime,
-        teea.finish_time as
-        examActivityFinishTime,
-        tees.course_code as courseCode,
-        teec.course_name as courseName,
-        tee.prepare_seconds as prepareSeconds,
-        tee.min_duration_seconds as minDurationSeconds,
-        tee.max_duration_seconds as maxDurationSeconds,
-        tee.exam_count as
-        examCount,
-        tee.force_finish as fouceFinish,
-        tee.entry_authentication_policy as entryAuthenticationPolicy,
-        tee.in_process_face_verify as inProcessFaceVerify,
-        tee.in_process_face_stranger_ignore as inProcessFaceStrangerIgnore,
-        tee.in_process_liveness_verify as inProcessLivenessVerify,
-        tee.in_process_liveness_fixed_range as inProcessLivenessFixedRange,
-        tee.in_process_liveness_judge_policy as inProcessLivenessJudgePolicy,
-        tee.camera_photo_upload as cameraPhotoUpload,
-        tee.mobile_photo_upload
-        as mobilePhotoUpload,
-        tee.break_expire_seconds as breakExpireSeconds,
-        tee.break_resume_count as breakResumeCount,
-        toer.duration_seconds as
-        durationSeconds,
-        toer.client_last_sync_time as clientLastSyncTime
-        from
-        t_oe_exam_record toer
-        left join t_e_exam_student tees on
-        tees.id =
-        toer.exam_student_id
-        left join t_e_exam_course teec on
-        teec.course_code
-        = tees.course_code
-        left join t_e_exam tee on
-        tee.id = tees.exam_id
-        left
-        join t_e_exam_activity teea on
-        teea.id = tees.exam_activity_id
-        <where>
-            <if test="studentId != null and studentId != ''">
-                and tees.student_id = #{studentId}
-            </if>
-            and tee.enable = 1
-            and teea.enable = 1
-            and tees.enable = 1
-            <if test="orgId != null and orgId != ''">
-                and tee.org_id = #{orgId}
-            </if>
-            <if test="examId != null and examId != ''">
-                and tee.id = #{examId}
-            </if>
-        </where>
-    </select>
+	<select id="getUnFinishExam"
+		resultType="com.qmth.themis.business.dto.response.TEExamUnFinishDto">
+		select
+		tee.id,
+		teea.id as examActivityId,
+		toer.id as recordId,
+		tees.id as
+		examStudentId,
+		tee.name,
+		tee.mode,
+		tee.pre_notice as preNotice,
+		tee.pre_notice_stay_seconds as preNoticeStaySeconds,
+		tee.post_notice as
+		postNotice,
+		tee.code as examCode,
+		teea.code as examActivityCode,
+		tee.start_time as examStartTime,
+		tee.end_time as examEndTime,
+		teea.start_time as examActivityStartTime,
+		teea.finish_time as
+		examActivityFinishTime,
+		tees.course_code as courseCode,
+		teec.course_name as courseName,
+		tee.prepare_seconds as prepareSeconds,
+		tee.min_duration_seconds as minDurationSeconds,
+		tee.max_duration_seconds as maxDurationSeconds,
+		tee.exam_count as
+		examCount,
+		tee.force_finish as fouceFinish,
+		tee.entry_authentication_policy as entryAuthenticationPolicy,
+		tee.in_process_face_verify as inProcessFaceVerify,
+		tee.in_process_face_stranger_ignore as inProcessFaceStrangerIgnore,
+		tee.in_process_liveness_verify as inProcessLivenessVerify,
+		tee.in_process_liveness_fixed_range as inProcessLivenessFixedRange,
+		tee.in_process_liveness_judge_policy as inProcessLivenessJudgePolicy,
+		tee.camera_photo_upload as cameraPhotoUpload,
+		tee.mobile_photo_upload
+		as mobilePhotoUpload,
+		tee.break_expire_seconds as breakExpireSeconds,
+		tee.break_resume_count as breakResumeCount,
+		toer.duration_seconds as
+		durationSeconds,
+		toer.client_last_sync_time as clientLastSyncTime
+		from
+		t_oe_exam_record toer
+		left join t_e_exam_student tees on
+		tees.id =
+		toer.exam_student_id
+		left join t_e_exam_course teec on
+		teec.course_code
+		= tees.course_code
+		left join t_e_exam tee on
+		tee.id = tees.exam_id
+		left
+		join t_e_exam_activity teea on
+		teea.id = tees.exam_activity_id
+		<where>
+			<if test="studentId != null and studentId != ''">
+				and tees.student_id = #{studentId}
+			</if>
+			and tee.enable = 1
+			and teea.enable = 1
+			and tees.enable = 1
+			<if test="orgId != null and orgId != ''">
+				and tee.org_id = #{orgId}
+			</if>
+			<if test="examId != null and examId != ''">
+				and tee.id = #{examId}
+			</if>
+		</where>
+	</select>
 
-    <update id="dataUpdate">
+	<update id="dataUpdate">
 		update t_oe_exam_record t set
 		t.${colName}=#{colValue} where t.id=#{recordId}
 	</update>
 
-    <sql id="invigilatePageHead">
-        select
-            t.exam_id examId,
-            tee.name as examName,
-            t.exam_activity_id examActivityId,
-            teea.code as examActivityCode,
-            t.exam_student_id examStudentId,
-            t.id examRecordId,
-            s.identity identity,
-            s.room_code roomCode,
-            s.room_name roomName,
-            s.name name,
-            s.course_name courseName,
-            s.course_code courseCode,
-            IFNULL(t.paper_download,1) paperDownload,
-            t.status statusCode,
-            t.answer_progress progress,
-            IFNULL(t.client_current_ip,'无') clientCurrentIp,
-            IFNULL(t.warning_count,0) as warningCount,
-            IFNULL(t.breach_status,1) as breachStatus,
-            IFNULL(t.client_websocket_status,'OFF_LINE') as clientWebsocketStatus,
-            IFNULL(t.monitor_status_source,'STOP') as monitorStatusSource,
-            t.client_last_sync_time as updateTime
-    </sql>
+	<sql id="invigilatePageHead">
+		select
+		t.exam_id examId,
+		tee.name as examName,
+		t.exam_activity_id examActivityId,
+		teea.code as examActivityCode,
+		t.exam_student_id examStudentId,
+		t.id examRecordId,
+		s.identity identity,
+		s.room_code roomCode,
+		s.room_name roomName,
+		s.name name,
+		s.course_name courseName,
+		s.course_code courseCode,
+		IFNULL(t.paper_download,1) paperDownload,
+		t.status statusCode,
+		t.answer_progress progress,
+		IFNULL(t.client_current_ip,'无') clientCurrentIp,
+		IFNULL(t.warning_count,0) as warningCount,
+		IFNULL(t.breach_status,1) as breachStatus,
+		IFNULL(t.client_websocket_status,'OFF_LINE') as clientWebsocketStatus,
+		IFNULL(t.monitor_status_source,'STOP') as monitorStatusSource,
+		t.client_last_sync_time as updateTime
+	</sql>
 
-    <sql id="invigilatePageMiddle">
-        from t_oe_exam_record t
-        left join t_e_exam_student s on t.exam_student_id = s.id
-        left join t_e_exam tee on tee.id = t.exam_id
-        left join t_e_exam_activity teea on teea.id = t.exam_activity_id
-        inner join (select toer.id from t_oe_exam_record toer where EXISTS(select tees.id from t_e_exam_student tees where EXISTS (select distinct tbeiu.room_code from t_b_exam_invigilate_user tbeiu
-        where
-        <if test="userId != null and userId != ''">
-            tbeiu.user_id = #{userId} and
-        </if>
-        tbeiu.room_code = tees.room_code and toer.exam_student_id = tees.id))) t1 on t1.id = t.id
-    </sql>
+	<sql id="invigilatePageMiddle">
+		from t_oe_exam_record t
+		left join t_e_exam_student s on t.exam_student_id = s.id
+		left join t_e_exam tee on tee.id = t.exam_id
+		left join t_e_exam_activity teea on teea.id = t.exam_activity_id
+		inner join (select toer.id from t_oe_exam_record toer where EXISTS(select
+		tees.id from t_e_exam_student tees where EXISTS (select distinct
+		tbeiu.room_code from t_b_exam_invigilate_user tbeiu
+		where
+		<if test="userId != null and userId != ''">
+			tbeiu.user_id = #{userId} and
+		</if>
+		tbeiu.room_code = tees.room_code and toer.exam_student_id = tees.id)))
+		t1 on t1.id = t.id
+	</sql>
 
-    <sql id="invigilatePageFoot">
-        <where>
-            <if test="examId != null and examId != ''">
-                and t.exam_id = #{examId}
-            </if>
-            <if test="examActivityId != null and examActivityId != ''">
-                and t.exam_activity_id = #{examActivityId}
-            </if>
-            <if test="roomCode != null and roomCode != ''">
-                and s.room_code = #{roomCode}
-            </if>
-            <if test="status != null and status != ''">
-                <choose>
-                    <when test="status == EXAMING">
-                        and (t.status = 'ANSWERING' or t.status = 'RESUME_PREPARE')
-                    </when>
-                    <otherwise>
-                        and t.status = #{status}
-                    </otherwise>
-                </choose>
-            </if>
-            <if test="name != null and name !=''">
-                and s.name like CONCAT('%', #{name},'%')
-            </if>
-            <if test="identity != null and identity !=''">
-                and s.identity like CONCAT('%', #{identity},'%')
-            </if>
-            <if test="maxWarningCount != null and maxWarningCount != ''">
-                and t.warning_count &lt;= #{maxWarningCount}
-            </if>
-            <if test="minWarningCount != null and minWarningCount != ''">
-                and t.warning_count &gt;= #{minWarningCount}
-            </if>
-            <if test="clientWebsocketStatus != null and clientWebsocketStatus != ''">
-                and t.client_websocket_status = #{clientWebsocketStatus}
-            </if>
-            <if test="monitorStatusSource != null and monitorStatusSource != ''">
-                and t.monitor_status_source = #{monitorStatusSource}
-            </if>
-                and s.enable = 1
-                and tee.enable = 1
-                and teea.enable = 1
-                and teea.finish_time > now()
-        </where>
-    </sql>
+	<sql id="invigilatePageFoot">
+		<where>
+			<if test="examId != null and examId != ''">
+				and t.exam_id = #{examId}
+			</if>
+			<if test="examActivityId != null and examActivityId != ''">
+				and t.exam_activity_id = #{examActivityId}
+			</if>
+			<if test="roomCode != null and roomCode != ''">
+				and s.room_code = #{roomCode}
+			</if>
+			<if test="status != null and status != ''">
+				<choose>
+					<when test="status == EXAMING">
+						and (t.status = 'ANSWERING' or t.status = 'RESUME_PREPARE')
+					</when>
+					<otherwise>
+						and t.status = #{status}
+					</otherwise>
+				</choose>
+			</if>
+			<if test="name != null and name !=''">
+				and s.name like CONCAT('%', #{name},'%')
+			</if>
+			<if test="identity != null and identity !=''">
+				and s.identity like CONCAT('%', #{identity},'%')
+			</if>
+			<if test="maxWarningCount != null and maxWarningCount != ''">
+				and t.warning_count &lt;= #{maxWarningCount}
+			</if>
+			<if test="minWarningCount != null and minWarningCount != ''">
+				and t.warning_count &gt;= #{minWarningCount}
+			</if>
+			<if
+				test="clientWebsocketStatus != null and clientWebsocketStatus != ''">
+				and t.client_websocket_status = #{clientWebsocketStatus}
+			</if>
+			<if
+				test="monitorStatusSource != null and monitorStatusSource != ''">
+				and t.monitor_status_source = #{monitorStatusSource}
+			</if>
+			and s.enable = 1
+			and tee.enable = 1
+			and teea.enable = 1
+			and teea.finish_time > now()
+		</where>
+	</sql>
 
-    <select id="invigilatePageList" resultType="com.qmth.themis.business.bean.backend.InvigilateListBean">
-        <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 != ''">
-            and t.paper_download = #{paperDownload}
-        </if>
-        order by s.room_code
-    </select>
+	<select id="invigilatePageList"
+		resultType="com.qmth.themis.business.bean.backend.InvigilateListBean">
+		<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 != ''">
+			and t.paper_download = #{paperDownload}
+		</if>
+		order by s.room_code
+	</select>
 
-    <select id="invigilatePageListVideo" resultType="com.qmth.themis.business.bean.backend.InvigilateListVideoBean">
-        <include refid="invigilatePageHead" />
-        ,t.monitor_live_url as monitorLiveUrl
-        <include refid="invigilatePageMiddle" />
-        <include refid="invigilatePageFoot" />
-        <if test="paperDownload != null and paperDownload != ''">
-            and t.paper_download = #{paperDownload}
-        </if>
-        order by s.room_code
-    </select>
+	<select id="invigilatePageListVideo"
+		resultType="com.qmth.themis.business.bean.backend.InvigilateListVideoBean">
+		<include refid="invigilatePageHead" />
+		,t.monitor_live_url as monitorLiveUrl
+		<include refid="invigilatePageMiddle" />
+		<include refid="invigilatePageFoot" />
+		<if test="paperDownload != null and paperDownload != ''">
+			and t.paper_download = #{paperDownload}
+		</if>
+		order by s.room_code
+	</select>
 
-    <select id="invigilatePagePatrolList" resultType="com.qmth.themis.business.bean.backend.InvigilateListPatrolBean">
-        select * from(<include refid="invigilatePageHead"/>
-        ,(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
-        <include refid="invigilatePageMiddle"/>
-        <include refid="invigilatePageFoot" />
-            ) t
-        <where>
-            <if test="minMultipleFaceCount != null and minMultipleFaceCount != ''">
-                and t.multipleFaceCount &lt;= #{minMultipleFaceCount}
-            </if>
-            <if test="maxMultipleFaceCount != null and maxMultipleFaceCount != ''">
-                and t.multipleFaceCount &gt;= #{maxMultipleFaceCount}
-            </if>
-            <if test="minExceptionCount != null and minExceptionCount != ''">
-                and t.exceptionCount &lt;= #{minExceptionCount}
-            </if>
-            <if test="maxExceptionCount != null and maxExceptionCount != ''">
-                and t.exceptionCount &gt;= #{maxExceptionCount}
-            </if>
-        </where>
-        order by t.roomCode
-    </select>
+	<select id="invigilatePagePatrolList"
+		resultType="com.qmth.themis.business.bean.backend.InvigilateListPatrolBean">
+		select * from(
+		<include refid="invigilatePageHead" />
+		,(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
+		<include refid="invigilatePageMiddle" />
+		<include refid="invigilatePageFoot" />
+		) t
+		<where>
+			<if
+				test="minMultipleFaceCount != null and minMultipleFaceCount != ''">
+				and t.multipleFaceCount &lt;= #{minMultipleFaceCount}
+			</if>
+			<if
+				test="maxMultipleFaceCount != null and maxMultipleFaceCount != ''">
+				and t.multipleFaceCount &gt;= #{maxMultipleFaceCount}
+			</if>
+			<if test="minExceptionCount != null and minExceptionCount != ''">
+				and t.exceptionCount &lt;= #{minExceptionCount}
+			</if>
+			<if test="maxExceptionCount != null and maxExceptionCount != ''">
+				and t.exceptionCount &gt;= #{maxExceptionCount}
+			</if>
+		</where>
+		order by t.roomCode
+	</select>
 
-    <select id="invigilatePageWarningList" resultType="com.qmth.themis.business.bean.backend.InvigilateListWarningBean">
-        select * from(select
-           tee.id as examId,
-           tee.name as examName,
-           teea.id as examActivityId,
-           tees.id as examStudentId,
-           teea.code as examActivityCode,
-           tees.room_code as roomCode,
-           tees.room_name as roomName,
-           toer.id as examRecordId,
-           tees.`identity`,
-           tees.name,
-           tees.course_code as courseCode,
-           tees.course_name as courseName,
-           toer.status as statusCode,
-           IFNULL(toer.warning_count,0) as warningCount,
-           IFNULL(toer.breach_status,1) as breachStatus,
-           toer.client_last_sync_time as updateTime,
-           tiiwi.approve_status as approveStatus
-           ,(select count(1) from t_ie_invigilate_warn_info tiiwi where tiiwi.exam_record_id = toer.id and tiiwi.`type` =
-            'FACE_COUNT_ERROR' and tiiwi.`level` = 'D8') as multipleFaceCount
-           ,(select count(1) from t_ie_invigilate_exception_info tiiei where tiiei.exam_record_id = toer.id) as exceptionCount
-         from t_ie_invigilate_warn_info tiiwi
-        left join t_e_exam tee on tee.id = tiiwi.exam_id
-        left join t_e_exam_activity teea on teea.id = tiiwi.exam_activity_id
-        inner join (select toer.id from t_oe_exam_record toer where EXISTS(select tees.id from t_e_exam_student tees where EXISTS (select distinct tbeiu.room_code from t_b_exam_invigilate_user tbeiu
-        where
-        <if test="userId != null and userId != ''">
-            tbeiu.user_id = #{userId} and
-        </if>
-        tbeiu.room_code = tees.room_code and toer.exam_student_id = tees.id))) t on t.id = tiiwi.exam_record_id
-        left join t_oe_exam_record toer on toer.id  = t.id
-        left join t_e_exam_student tees on tees.id = tiiwi.exam_student_id
-        <where>
-                <if test="examId != null and examId != ''">
-                    and tiiwi.exam_id = #{examId}
-                </if>
-                <if test="examActivityId != null and examActivityId != ''">
-                    and tiiwi.exam_activity_id = #{examActivityId}
-                </if>
-                <if test="roomCode != null and roomCode != ''">
-                    and tees.room_code = #{roomCode}
-                </if>
-                <if test="approveStatus != null and approveStatus != ''">
-                    and tiiwi.approve_status = #{approveStatus}
-                </if>
-                <if test="name != null and name !=''">
-                    and tees.name like CONCAT('%', #{name},'%')
-                </if>
-                <if test="identity != null and identity !=''">
-                    and tees.identity like CONCAT('%', #{identity},'%')
-                </if>
-                <if test="maxWarningCount != null and maxWarningCount != ''">
-                    and toer.warning_count &lt;= #{maxWarningCount}
-                </if>
-                <if test="minWarningCount != null and minWarningCount != ''">
-                    and toer.warning_count &gt;= #{minWarningCount}
-                </if>
-                <if test="clientWebsocketStatus != null and clientWebsocketStatus != ''">
-                    and toer.client_websocket_status = #{clientWebsocketStatus}
-                </if>
-                <if test="monitorStatusSource != null and monitorStatusSource != ''">
-                    and toer.monitor_status_source = #{monitorStatusSource}
-                </if>
-                    and tee.enable = 1
-                    and teea.enable = 1
-                    and tees.enable = 1
-            </where>
-        ) t
-        <where>
-            <if test="minMultipleFaceCount != null and minMultipleFaceCount != ''">
-                and t.multipleFaceCount &lt;= #{minMultipleFaceCount}
-            </if>
-            <if test="maxMultipleFaceCount != null and maxMultipleFaceCount != ''">
-                and t.multipleFaceCount &gt;= #{maxMultipleFaceCount}
-            </if>
-            <if test="minExceptionCount != null and minExceptionCount != ''">
-                and t.exceptionCount &lt;= #{minExceptionCount}
-            </if>
-            <if test="maxExceptionCount != null and maxExceptionCount != ''">
-                and t.exceptionCount &gt;= #{maxExceptionCount}
-            </if>
-        </where>
-        order by t.roomCode
-    </select>
+	<select id="invigilatePageWarningList"
+		resultType="com.qmth.themis.business.bean.backend.InvigilateListWarningBean">
+		select * from(select
+		tee.id as examId,
+		tee.name as examName,
+		teea.id as examActivityId,
+		tees.id as examStudentId,
+		teea.code as examActivityCode,
+		tees.room_code as roomCode,
+		tees.room_name as roomName,
+		toer.id as examRecordId,
+		tees.`identity`,
+		tees.name,
+		tees.course_code as courseCode,
+		tees.course_name as courseName,
+		toer.status as statusCode,
+		IFNULL(toer.warning_count,0) as warningCount,
+		IFNULL(toer.breach_status,1) as breachStatus,
+		toer.client_last_sync_time as updateTime,
+		tiiwi.approve_status as approveStatus
+		,(select count(1) from t_ie_invigilate_warn_info tiiwi where
+		tiiwi.exam_record_id = toer.id and tiiwi.`type` =
+		'FACE_COUNT_ERROR' and tiiwi.`level` = 'D8') as multipleFaceCount
+		,(select count(1) from t_ie_invigilate_exception_info tiiei where
+		tiiei.exam_record_id = toer.id) as exceptionCount
+		from t_ie_invigilate_warn_info tiiwi
+		left join t_e_exam tee on tee.id = tiiwi.exam_id
+		left join t_e_exam_activity teea on teea.id = tiiwi.exam_activity_id
+		inner join (select toer.id from t_oe_exam_record toer where EXISTS(select
+		tees.id from t_e_exam_student tees where EXISTS (select distinct
+		tbeiu.room_code from t_b_exam_invigilate_user tbeiu
+		where
+		<if test="userId != null and userId != ''">
+			tbeiu.user_id = #{userId} and
+		</if>
+		tbeiu.room_code = tees.room_code and toer.exam_student_id = tees.id)))
+		t on t.id = tiiwi.exam_record_id
+		left join t_oe_exam_record toer on toer.id = t.id
+		left join t_e_exam_student tees on tees.id = tiiwi.exam_student_id
+		<where>
+			<if test="examId != null and examId != ''">
+				and tiiwi.exam_id = #{examId}
+			</if>
+			<if test="examActivityId != null and examActivityId != ''">
+				and tiiwi.exam_activity_id = #{examActivityId}
+			</if>
+			<if test="roomCode != null and roomCode != ''">
+				and tees.room_code = #{roomCode}
+			</if>
+			<if test="approveStatus != null and approveStatus != ''">
+				and tiiwi.approve_status = #{approveStatus}
+			</if>
+			<if test="name != null and name !=''">
+				and tees.name like CONCAT('%', #{name},'%')
+			</if>
+			<if test="identity != null and identity !=''">
+				and tees.identity like CONCAT('%', #{identity},'%')
+			</if>
+			<if test="maxWarningCount != null and maxWarningCount != ''">
+				and toer.warning_count &lt;= #{maxWarningCount}
+			</if>
+			<if test="minWarningCount != null and minWarningCount != ''">
+				and toer.warning_count &gt;= #{minWarningCount}
+			</if>
+			<if
+				test="clientWebsocketStatus != null and clientWebsocketStatus != ''">
+				and toer.client_websocket_status = #{clientWebsocketStatus}
+			</if>
+			<if
+				test="monitorStatusSource != null and monitorStatusSource != ''">
+				and toer.monitor_status_source = #{monitorStatusSource}
+			</if>
+			and tee.enable = 1
+			and teea.enable = 1
+			and tees.enable = 1
+		</where>
+		) t
+		<where>
+			<if
+				test="minMultipleFaceCount != null and minMultipleFaceCount != ''">
+				and t.multipleFaceCount &lt;= #{minMultipleFaceCount}
+			</if>
+			<if
+				test="maxMultipleFaceCount != null and maxMultipleFaceCount != ''">
+				and t.multipleFaceCount &gt;= #{maxMultipleFaceCount}
+			</if>
+			<if test="minExceptionCount != null and minExceptionCount != ''">
+				and t.exceptionCount &lt;= #{minExceptionCount}
+			</if>
+			<if test="maxExceptionCount != null and maxExceptionCount != ''">
+				and t.exceptionCount &gt;= #{maxExceptionCount}
+			</if>
+		</where>
+		order by t.roomCode
+	</select>
 
-    <select id="invigilatePageProgressList" resultType="com.qmth.themis.business.bean.backend.InvigilateListProgressBean">
-        select
-            distinct tee.id as examId,
-            tee.name as examName,
-            teea.id as examActivityId,
-            teea.code as examActivityCode,
-            tees.room_code as roomCode,
-            tees.room_name as roomName,
-            tees.`identity`,
-            tees.name,
-            tees.course_code as courseCode,
-            tees.course_name as courseName,
-            tees.left_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
-        from
-            t_e_exam_student tees
-        left join t_e_exam tee on
-            tee.id = tees.exam_id
-        left join t_e_exam_activity teea on
-            teea.id = tees.exam_activity_id
-        inner join (select distinct tbeiu.room_code from t_b_exam_invigilate_user tbeiu
-        <if test="userId != null and userId != ''">
-            where tbeiu.user_id = #{userId}
-        </if>
-        ) t on t.room_code = tees.room_code
-        <where>
-            <if test="examId != null and examId != ''">
-                and tees.exam_id = #{examId}
-            </if>
-            <if test="examActivityId != null and examActivityId != ''">
-                and tees.exam_activity_id = #{examActivityId}
-            </if>
-            <if test="roomCode != null and roomCode != ''">
-                and tees.room_code = #{roomCode}
-            </if>
-            <if test="courseCode != null and courseCode != ''">
-                and tees.course_code like CONCAT('%', #{courseCode},'%')
-            </if>
-            <if test="name != null and name !=''">
-                and tees.name like CONCAT('%', #{name},'%')
-            </if>
-            <if test="identity != null and identity !=''">
-                and tees.identity like CONCAT('%', #{identity},'%')
-            </if>
-            and tee.enable = 1
-            and teea.enable = 1
-            and tees.enable = 1
-        </where>
-            order by tees.room_code
-    </select>
+	<select id="invigilatePageProgressList"
+		resultType="com.qmth.themis.business.bean.backend.InvigilateListProgressBean">
+		select
+		distinct tee.id as examId,
+		tee.name as examName,
+		teea.id as examActivityId,
+		teea.code as examActivityCode,
+		tees.room_code as roomCode,
+		tees.room_name as roomName,
+		tees.`identity`,
+		tees.name,
+		tees.course_code as courseCode,
+		tees.course_name as courseName,
+		tees.left_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
+		from
+		t_e_exam_student tees
+		left join t_e_exam tee on
+		tee.id = tees.exam_id
+		left join t_e_exam_activity teea on
+		teea.id = tees.exam_activity_id
+		inner join (select distinct tbeiu.room_code from t_b_exam_invigilate_user
+		tbeiu
+		<if test="userId != null and userId != ''">
+			where tbeiu.user_id = #{userId}
+		</if>
+		) t on t.room_code = tees.room_code
+		<where>
+			<if test="examId != null and examId != ''">
+				and tees.exam_id = #{examId}
+			</if>
+			<if test="examActivityId != null and examActivityId != ''">
+				and tees.exam_activity_id = #{examActivityId}
+			</if>
+			<if test="roomCode != null and roomCode != ''">
+				and tees.room_code = #{roomCode}
+			</if>
+			<if test="courseCode != null and courseCode != ''">
+				and tees.course_code like CONCAT('%', #{courseCode},'%')
+			</if>
+			<if test="name != null and name !=''">
+				and tees.name like CONCAT('%', #{name},'%')
+			</if>
+			<if test="identity != null and identity !=''">
+				and tees.identity like CONCAT('%', #{identity},'%')
+			</if>
+			and tee.enable = 1
+			and teea.enable = 1
+			and tees.enable = 1
+		</where>
+		order by tees.room_code
+	</select>
 
-    <select id="invigilatePageListHistory" resultType="com.qmth.themis.business.bean.backend.InvigilateListHistoryBean">
-        <include refid="invigilatePageHead" />
-        <include refid="invigilatePageMiddle" />
-        <include refid="invigilatePageFoot" />
-        <if test="breachStatus != null and breachStatus != '' or breachStatus == 0">
-            and t.breach_status = #{breachStatus}
-        </if>
-        <if test="finishType != null and finishType != ''">
-            and t.finish_type = #{finishType}
-        </if>
-        <if test="courseCode != null and courseCode != ''">
-            and tees.course_code like CONCAT('%', #{courseCode},'%')
-        </if>
-        order by s.room_code
-    </select>
-    
-    <select id="getDoneCount" resultType="java.util.Map">
-    	select f.exam_activity_id activityId,count(distinct(f.exam_student_id)) cc from t_oe_exam_record f
-    	left join t_e_exam_student t on f.exam_student_id=t.id
-    	where  f.exam_id = #{examId}
-            <if test="activityId != null and activityId != ''">
-                and f.exam_activity_id = #{activityId}
-            </if>
-            <if test="roomCode != null and roomCode != ''">
-                and t.room_code =#{roomCode}
-            </if>
-            <if test="courseCode != null and courseCode != ''">
-                and t.course_code = #{courseCode}
-            </if>
-            group by f.exam_activity_id
-    </select>
-    <select id="getDoneCountByDay" resultType="java.util.Map">
-    	select DATE_FORMAT(f.first_prepare_time, '%Y-%m-%d') AS day,
+	<select id="invigilatePageListHistory"
+		resultType="com.qmth.themis.business.bean.backend.InvigilateListHistoryBean">
+		<include refid="invigilatePageHead" />
+		<include refid="invigilatePageMiddle" />
+		<include refid="invigilatePageFoot" />
+		<if
+			test="breachStatus != null and breachStatus != '' or breachStatus == 0">
+			and t.breach_status = #{breachStatus}
+		</if>
+		<if test="finishType != null and finishType != ''">
+			and t.finish_type = #{finishType}
+		</if>
+		<if test="courseCode != null and courseCode != ''">
+			and tees.course_code like CONCAT('%', #{courseCode},'%')
+		</if>
+		order by s.room_code
+	</select>
+
+	<select id="getDoneCount" resultType="java.util.Map">
+		select f.exam_activity_id
+		activityId,count(distinct(f.exam_student_id)) cc from t_oe_exam_record
+		f
+		left join t_e_exam_student t on f.exam_student_id=t.id
+		where f.exam_id = #{examId}
+		<if test="activityId != null and activityId != ''">
+			and f.exam_activity_id = #{activityId}
+		</if>
+		<if test="roomCode != null and roomCode != ''">
+			and t.room_code =#{roomCode}
+		</if>
+		<if test="courseCode != null and courseCode != ''">
+			and t.course_code = #{courseCode}
+		</if>
+		group by f.exam_activity_id
+	</select>
+	<select id="getDoneCountByDay" resultType="java.util.Map">
+		select DATE_FORMAT(f.first_prepare_time, '%Y-%m-%d') AS day,
 		count(DISTINCT(f.exam_student_id)) count from t_oe_exam_record f
-    	left join t_e_exam_student t on f.exam_student_id=t.id
-    	where  f.exam_id = #{examId}
-            <if test="activityId != null and activityId != ''">
-                and f.exam_activity_id = #{activityId}
-            </if>
-            <if test="roomCode != null and roomCode != ''">
-                and t.room_code =#{roomCode}
-            </if>
-            <if test="courseCode != null and courseCode != ''">
-                and t.course_code = #{courseCode}
-            </if>
-            group by day
-            ORDER BY day
-    </select>
-    
+		left join t_e_exam_student t on f.exam_student_id=t.id
+		where f.exam_id = #{examId}
+		<if test="activityId != null and activityId != ''">
+			and f.exam_activity_id = #{activityId}
+		</if>
+		<if test="roomCode != null and roomCode != ''">
+			and t.room_code =#{roomCode}
+		</if>
+		<if test="courseCode != null and courseCode != ''">
+			and t.course_code = #{courseCode}
+		</if>
+		group by day
+		ORDER BY day
+	</select>
+
+	<select id="getCountByExamId" resultType="java.lang.Long">
+		select count(1) from t_oe_exam_record f
+		where f.exam_id = #{examId}
+	</select>
+	<select id="getListByExamIdAndStartId" resultType="com.qmth.themis.business.entity.TOeExamRecord">
+		select f.* from t_oe_exam_record f
+		where f.exam_id = #{examId} and f.id>#{startId}
+		order by f.id
+		limit 500
+	</select>
 </mapper>

+ 8 - 0
themis-mq/src/main/java/com/qmth/themis/mq/service/MqLogicService.java

@@ -106,4 +106,12 @@ public interface MqLogicService {
      * @param key
      */
     public void execMqLogLogic(MqDto mqDto, String key);
+
+	/**
+	 * 重新算分
+	 *
+	 * @param mqDto
+	 * @param key
+	 */
+	void execMqCalculateScoreLogic(MqDto mqDto, String key);
 }

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

@@ -258,8 +258,6 @@ public class MqLogicServiceImpl implements MqLogicService {
         Gson gson = new Gson();
         Map<String, Object> param = (Map<String, Object>) mqDto.getBody();
         examRecordService.calculateObjectiveScore(param);
-        Long recordId = (Long) param.get("recordId");
-        commonService.persisted(recordId);
         mqDto.setAck(SystemConstant.STANDARD_ACK_TYPE);
         TMRocketMessage tmRocketMessage = gson.fromJson(gson.toJson(mqDto), TMRocketMessage.class);
         tmRocketMessage.setBody(JacksonUtil.parseJson(tmRocketMessage.getBody()));
@@ -511,4 +509,25 @@ public class MqLogicServiceImpl implements MqLogicService {
         tmRocketMessageService.saveOrUpdate(tmRocketMessage);
         redisUtil.delete(key, mqDto.getId());
     }
+    
+    /**
+     * 重新算分
+     *
+     * @param mqDto
+     * @param key
+     */
+    @Override
+    @Transactional
+    public void execMqCalculateScoreLogic(MqDto mqDto, String key) {
+        Gson gson = new Gson();
+        Map<String, Object> param = (Map<String, Object>) mqDto.getBody();
+        Long examId = (Long) param.get("examId");
+        Long taskId = (Long) param.get("taskId");
+        teExamService.calculateScore(examId,taskId);
+        mqDto.setAck(SystemConstant.STANDARD_ACK_TYPE);
+        TMRocketMessage tmRocketMessage = gson.fromJson(gson.toJson(mqDto), TMRocketMessage.class);
+        tmRocketMessage.setBody(JacksonUtil.parseJson(tmRocketMessage.getBody()));
+        tmRocketMessageService.saveOrUpdate(tmRocketMessage);
+        redisUtil.delete(key, mqDto.getId());
+    }
 }

+ 74 - 0
themis-mq/src/main/java/com/qmth/themis/mq/templete/impl/CalculateScoreConcurrentlyImpl.java

@@ -0,0 +1,74 @@
+package com.qmth.themis.mq.templete.impl;
+
+import com.qmth.themis.business.constant.SpringContextHolder;
+import com.qmth.themis.business.constant.SystemConstant;
+import com.qmth.themis.business.dto.MqDto;
+import com.qmth.themis.business.util.JacksonUtil;
+import com.qmth.themis.business.util.RedisUtil;
+import com.qmth.themis.common.contanst.Constants;
+import com.qmth.themis.mq.service.MqLogicService;
+import com.qmth.themis.mq.templete.Concurrently;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * 重新算分
+ *
+ * @Description:
+ * @Author: xiatian
+ * @Date: 2020-07-30
+ */
+@Service
+public class CalculateScoreConcurrentlyImpl implements Concurrently {
+    private final static Logger log = LoggerFactory.getLogger(CalculateScoreConcurrentlyImpl.class);
+
+    @Override
+    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
+                                                    ConsumeConcurrentlyContext consumeConcurrentlyContext) {
+        RedisUtil redisUtil = SpringContextHolder.getBean(RedisUtil.class);
+        MqLogicService mqLogicService = SpringContextHolder.getBean(MqLogicService.class);
+        MqDto mqDto = null;
+        try {
+            long threadId = Thread.currentThread().getId();
+            String threadName = Thread.currentThread().getName();
+            for (MessageExt messageExt : msgs) {
+                log.debug(":{}-:{} CalculateObjectiveScore 重试次数:{}", threadId, threadName,
+                        messageExt.getReconsumeTimes());
+                mqDto = JacksonUtil.readJson(new String(messageExt.getBody(), Constants.CHARSET), MqDto.class);
+                log.debug(":{}-:{} CalculateObjectiveScore 接收到的消息:{}", threadId, threadName,
+                        JacksonUtil.parseJson(mqDto));
+                int reconsumeTime = messageExt.getReconsumeTimes();
+                if (reconsumeTime >= SystemConstant.MAXRECONSUMETIMES) {
+                    mqLogicService.execMqMaxReconsumeTime(mqDto, SystemConstant.MQ_TOPIC_BUFFER_LIST);
+                } else {
+                    if (Objects.nonNull(mqDto.getAck()) && mqDto.getAck().intValue() != SystemConstant.STANDARD_ACK_TYPE
+                            && Objects.nonNull(redisUtil.get(SystemConstant.MQ_TOPIC_BUFFER_LIST, mqDto.getId()))
+                            && redisUtil.lock(SystemConstant.REDIS_LOCK_MQ_PREFIX + mqDto.getId(),
+                            SystemConstant.REDIS_LOCK_MQ_TIME_OUT)) {
+                        log.debug(":{}-:{} 更新db", threadId, threadName);
+                        mqLogicService.execMqCalculateObjectiveScoreLogic(mqDto, SystemConstant.MQ_TOPIC_BUFFER_LIST);
+                        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
+                    } else {
+                        log.debug(":{}-:{} 消息ack未确认,重发", threadId, threadName);
+                        return ConsumeConcurrentlyStatus.RECONSUME_LATER;// 重试
+                    }
+                }
+            }
+        } catch (Exception e) {
+            log.error("mq 重新算分,消息消费出错", e);
+            return ConsumeConcurrentlyStatus.RECONSUME_LATER;//重试
+        } finally {
+            if (Objects.nonNull(mqDto)) {
+                redisUtil.releaseLock(SystemConstant.REDIS_LOCK_MQ_PREFIX + mqDto.getId());
+            }
+        }
+        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;// 成功
+    }
+}