浏览代码

Merge branch 'dev_v1.2.8' into dev_v1.2.9
merge

wangliang 1 年之前
父节点
当前提交
e658cba623

+ 120 - 81
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamActivityServiceImpl.java

@@ -50,7 +50,9 @@ import java.util.stream.Collectors;
  * @Date: 2020/6/25
  */
 @Service
-public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper, TEExamActivity> implements TEExamActivityService {
+public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper, TEExamActivity>
+        implements TEExamActivityService {
+
     private final static Logger log = LoggerFactory.getLogger(TEExamActivityServiceImpl.class);
 
     @Resource
@@ -152,7 +154,8 @@ public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper,
      * @return
      */
     @Override
-    public IPage<TEExamActivityQueryDto> examActivityQuery(IPage<Map> iPage, Long id, Long examId, String code, Long startDate, Long finishDate) {
+    public IPage<TEExamActivityQueryDto> examActivityQuery(IPage<Map> iPage, Long id, Long examId, String code,
+            Long startDate, Long finishDate) {
         return teExamActivityMapper.examActivityQuery(iPage, id, examId, code, startDate, finishDate);
     }
 
@@ -178,19 +181,18 @@ public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper,
      * @return
      */
     @Override
-    public TEExamActivityDto getWaitingExam(Long examActivityId, Long examStudentId, String courseCode, String prefix, Long recordId) {
+    public TEExamActivityDto getWaitingExam(Long examActivityId, Long examStudentId, String courseCode, String prefix,
+            Long recordId) {
         TEExamActivityDto teExamActivityDto = teExamActivityMapper.getWaitingExamByExamActivityId(examActivityId);
         ExamCacheBean examCache = teExamService.getExamCacheBean(teExamActivityDto.getExamId());
-        ExamStudentCacheBean examStudentCacheBean = teExamStudentService
-                .getExamStudentCacheBean(examStudentId);
+        ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(examStudentId);
         teExamActivityDto.setLeftExamCount(
-                (examCache.getExamCount().intValue() - (examStudentCacheBean.getAlreadyExamCount().intValue())
-                        < 0 ?
+                (examCache.getExamCount().intValue() - (examStudentCacheBean.getAlreadyExamCount().intValue()) < 0 ?
                         0 :
-                        examCache.getExamCount().intValue() - (examStudentCacheBean.getAlreadyExamCount()
-                                .intValue())));
+                        examCache.getExamCount().intValue() - (examStudentCacheBean.getAlreadyExamCount().intValue())));
         if (Objects.nonNull(teExamActivityDto.getInProcessLivenessFixedRangeStr())) {
-            String[] longs = teExamActivityDto.getInProcessLivenessFixedRangeStr().trim().replaceAll(" ", "").split(",");
+            String[] longs = teExamActivityDto.getInProcessLivenessFixedRangeStr().trim().replaceAll(" ", "")
+                    .split(",");
             List inProcessLivenessFixedRange = new ArrayList();
             for (int i = 0; i < longs.length; i++) {
                 Integer integer = Integer.valueOf(longs[i].trim());
@@ -203,63 +205,77 @@ public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper,
             }
         }
         //取course缓存
-        ExamCourseCacheBean examCourseCacheBean = teExamCourseService
-                .getExamCourseCacheBean(teExamActivityDto.getExamId(), courseCode);
+        ExamCourseCacheBean examCourseCacheBean = teExamCourseService.getExamCourseCacheBean(
+                teExamActivityDto.getExamId(), courseCode);
         if (Objects.nonNull(examCourseCacheBean) && Objects.nonNull(examCourseCacheBean.getMobilePhotoUpload())) {
             teExamActivityDto.setMobilePhotoUpload(examCourseCacheBean.getMobilePhotoUpload());
         }
-        if (Objects.nonNull(teExamActivityDto.getMonitorVideoSourceStr()) && !Objects
-                .equals(teExamActivityDto.getMonitorVideoSourceStr().toString().trim().replaceAll(" ", ""), "")) {
+        if (Objects.nonNull(teExamActivityDto.getMonitorVideoSourceStr()) && !Objects.equals(
+                teExamActivityDto.getMonitorVideoSourceStr().toString().trim().replaceAll(" ", ""), "")) {
             Map<String, String> monitorRecordMap = null;
-            if (Objects.nonNull(teExamActivityDto.getMonitorRecordStr()) && !Objects.equals(teExamActivityDto.getMonitorRecordStr().trim().replaceAll(" ", ""), "")) {
-                List<String> monitorRecordList = Arrays.asList(teExamActivityDto.getMonitorRecordStr().trim().toUpperCase().split(","));
-                monitorRecordMap = monitorRecordList.stream()
-                        .collect(Collectors.toMap(Function.identity(), s -> s));
+            if (Objects.nonNull(teExamActivityDto.getMonitorRecordStr()) && !Objects.equals(
+                    teExamActivityDto.getMonitorRecordStr().trim().replaceAll(" ", ""), "")) {
+                List<String> monitorRecordList = Arrays.asList(
+                        teExamActivityDto.getMonitorRecordStr().trim().toUpperCase().split(","));
+                monitorRecordMap = monitorRecordList.stream().collect(Collectors.toMap(Function.identity(), s -> s));
             }
-            List<String> videoSources = Arrays.asList(teExamActivityDto.getMonitorVideoSourceStr().trim().toUpperCase().replaceAll(" ", "").split(","));
+            List<String> videoSources = Arrays.asList(
+                    teExamActivityDto.getMonitorVideoSourceStr().trim().toUpperCase().replaceAll(" ", "").split(","));
             List<MonitorStreamDto> monitorStreamDtoList = new ArrayList<>();
             Map<String, String> finalMonitorRecordMap = monitorRecordMap;
             videoSources.forEach(s -> {
                 if (Objects.isNull(finalMonitorRecordMap) || finalMonitorRecordMap.size() == 0) {
-                    monitorStreamDtoList.add(new MonitorStreamDto(MonitorVideoSourceEnum.valueOf(s), SystemConstant.setStreamId(prefix, recordId, MonitorVideoSourceEnum.valueOf(s)), null));
+                    monitorStreamDtoList.add(new MonitorStreamDto(MonitorVideoSourceEnum.valueOf(s),
+                            SystemConstant.setStreamId(prefix, recordId, MonitorVideoSourceEnum.valueOf(s)), null));
                 } else {
                     String monitorRecordStr = finalMonitorRecordMap.get(s);
-                    monitorStreamDtoList.add(new MonitorStreamDto(MonitorVideoSourceEnum.valueOf(s), SystemConstant.setStreamId(prefix, recordId, MonitorVideoSourceEnum.valueOf(s)), Objects.nonNull(monitorRecordStr) ? SystemConstant.setStreamId(prefix, recordId, MonitorVideoSourceEnum.valueOf(s)) : null));
+                    monitorStreamDtoList.add(new MonitorStreamDto(MonitorVideoSourceEnum.valueOf(s),
+                            SystemConstant.setStreamId(prefix, recordId, MonitorVideoSourceEnum.valueOf(s)),
+                            Objects.nonNull(monitorRecordStr) ?
+                                    SystemConstant.setStreamId(prefix, recordId, MonitorVideoSourceEnum.valueOf(s)) :
+                                    null));
                 }
             });
             teExamActivityDto.setMonitorVideoSource(monitorStreamDtoList);
             teExamActivityDto.setMonitorAudioEnable(examCache.getMonitorAudioEnable());
 
             //加入hardwareTest逻辑
-            if (teExamActivityDto.getMonitorVideoSourceStr().toUpperCase().contains(MonitorVideoSourceEnum.CLIENT_CAMERA.name())
-                    || (Objects.nonNull(teExamActivityDto.getEntryAuthenticationPolicy()) && (
-                    Objects.equals(teExamActivityDto.getEntryAuthenticationPolicy(),
-                            EntryAuthenticationPolicyEnum.LIVENESS_VERIFY.name()) || Objects
-                            .equals(teExamActivityDto.getEntryAuthenticationPolicy(),
+            if (teExamActivityDto.getMonitorVideoSourceStr().toUpperCase()
+                    .contains(MonitorVideoSourceEnum.CLIENT_CAMERA.name()) || (
+                    Objects.nonNull(teExamActivityDto.getEntryAuthenticationPolicy()) && (
+                            Objects.equals(teExamActivityDto.getEntryAuthenticationPolicy(),
+                                    EntryAuthenticationPolicyEnum.LIVENESS_VERIFY.name()) || Objects.equals(
+                                    teExamActivityDto.getEntryAuthenticationPolicy(),
                                     EntryAuthenticationPolicyEnum.FACE_VERIFY_FORCE.name()))) || (
-                    Objects.nonNull(teExamActivityDto.getCameraPhotoUpload()) && teExamActivityDto.getCameraPhotoUpload() == 1)
-                    || Objects.nonNull(teExamActivityDto.getInProcessFaceVerify()) && teExamActivityDto.getInProcessFaceVerify() == 1
-                    || Objects.nonNull(teExamActivityDto.getInProcessLivenessVerify()) && teExamActivityDto.getInProcessLivenessVerify() == 1) {
+                    Objects.nonNull(teExamActivityDto.getCameraPhotoUpload())
+                            && teExamActivityDto.getCameraPhotoUpload() == 1)
+                    || Objects.nonNull(teExamActivityDto.getInProcessFaceVerify())
+                    && teExamActivityDto.getInProcessFaceVerify() == 1
+                    || Objects.nonNull(teExamActivityDto.getInProcessLivenessVerify())
+                    && teExamActivityDto.getInProcessLivenessVerify() == 1) {
                 List<String> hardwareTest = teExamActivityDto.getHardwareTest();
                 if (Objects.isNull(hardwareTest)) {
                     hardwareTest = new ArrayList<>();
                 }
                 hardwareTest.add(HardwareTestEnum.CAMERA.name());
                 if ((Objects.nonNull(examCourseCacheBean) && Objects.nonNull(examCourseCacheBean.getHasAudio())
-                        && examCourseCacheBean.getHasAudio() == 1)
-                        || teExamActivityDto.getMonitorVideoSourceStr().toUpperCase().contains(MonitorVideoSourceEnum.CLIENT_CAMERA.name())) {
+                        && examCourseCacheBean.getHasAudio() == 1) || teExamActivityDto.getMonitorVideoSourceStr()
+                        .toUpperCase().contains(MonitorVideoSourceEnum.CLIENT_CAMERA.name())) {
                     hardwareTest.add(HardwareTestEnum.AUDIOPLAY.name());
                 }
                 teExamActivityDto.setHardwareTest(hardwareTest);
             }
         } else if ((Objects.nonNull(teExamActivityDto.getEntryAuthenticationPolicy()) && (
                 Objects.equals(teExamActivityDto.getEntryAuthenticationPolicy(),
-                        EntryAuthenticationPolicyEnum.LIVENESS_VERIFY.name()) || Objects
-                        .equals(teExamActivityDto.getEntryAuthenticationPolicy(),
-                                EntryAuthenticationPolicyEnum.FACE_VERIFY_FORCE.name()))) || (
-                Objects.nonNull(teExamActivityDto.getCameraPhotoUpload()) && teExamActivityDto.getCameraPhotoUpload() == 1)
-                || Objects.nonNull(teExamActivityDto.getInProcessFaceVerify()) && teExamActivityDto.getInProcessFaceVerify() == 1
-                || Objects.nonNull(teExamActivityDto.getInProcessLivenessVerify()) && teExamActivityDto.getInProcessLivenessVerify() == 1) {
+                        EntryAuthenticationPolicyEnum.LIVENESS_VERIFY.name()) || Objects.equals(
+                        teExamActivityDto.getEntryAuthenticationPolicy(),
+                        EntryAuthenticationPolicyEnum.FACE_VERIFY_FORCE.name()))) || (
+                Objects.nonNull(teExamActivityDto.getCameraPhotoUpload())
+                        && teExamActivityDto.getCameraPhotoUpload() == 1)
+                || Objects.nonNull(teExamActivityDto.getInProcessFaceVerify())
+                && teExamActivityDto.getInProcessFaceVerify() == 1
+                || Objects.nonNull(teExamActivityDto.getInProcessLivenessVerify())
+                && teExamActivityDto.getInProcessLivenessVerify() == 1) {
             List<String> hardwareTest = teExamActivityDto.getHardwareTest();
             if (Objects.isNull(hardwareTest)) {
                 hardwareTest = new ArrayList<>();
@@ -313,9 +329,9 @@ public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper,
         if (ac == null) {
             return ret;
         }
-//        if (ac.getEnable() != null && ac.getEnable().intValue() == 0) {
-//            return ret;
-//        }
+        //        if (ac.getEnable() != null && ac.getEnable().intValue() == 0) {
+        //            return ret;
+        //        }
         ret = new ExamActivityCacheBean();
         ret.setId(ac.getId());
         ret.setCode(ac.getCode());
@@ -348,8 +364,8 @@ public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper,
             examId = teExamActivityList.get(0).getExamId();
             ExamCacheBean examCacheBean = teExamService.getExamCacheBean(teExamActivityList.get(0).getExamId());
             TEExam teExam = teExamService.cacheConvert(examCacheBean);
-            if (Objects.nonNull(teExam.getMonitorStatus()) && Objects
-                    .equals(teExam.getMonitorStatus(), InvigilateMonitorStatusEnum.FINISHED)) {
+            if (Objects.nonNull(teExam.getMonitorStatus()) && Objects.equals(teExam.getMonitorStatus(),
+                    InvigilateMonitorStatusEnum.FINISHED)) {
                 throw new BusinessException("监考结束的考试场次不可以修改");
             }
             List<TEAudio> teAudioList = new ArrayList<>();
@@ -362,7 +378,10 @@ public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper,
                             .eq(TEAudio::getAudioDefault, AudioDefaultEnum.SYS.name());
                     int count = teAudioService.count(teAudioQueryWrapper);
                     if (count == 0) {
-                        teAudioList.add(new TEAudio(tbUser.getOrgId(), s.getId(), SystemConstant.BEFORE_AUDIO_ATTACHMENT_ID, AudioTypeEnum.BEFORE.getTitle(), AudioTypeEnum.BEFORE, AudioDefaultEnum.SYS, tbUser.getId(), SystemConstant.BEFORE_AUDIO_SECOND, teExam, s));//开考前语音
+                        teAudioList.add(
+                                new TEAudio(tbUser.getOrgId(), s.getId(), SystemConstant.BEFORE_AUDIO_ATTACHMENT_ID,
+                                        AudioTypeEnum.BEFORE.getTitle(), AudioTypeEnum.BEFORE, AudioDefaultEnum.SYS,
+                                        tbUser.getId(), SystemConstant.BEFORE_AUDIO_SECOND, teExam, s));//开考前语音
                     }
 
                     teAudioQueryWrapper = new QueryWrapper<>();
@@ -371,10 +390,14 @@ public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper,
                             .eq(TEAudio::getAudioDefault, AudioDefaultEnum.SYS.name());
                     count = teAudioService.count(teAudioQueryWrapper);
                     if (count == 0) {
-                        teAudioList.add(new TEAudio(tbUser.getOrgId(), s.getId(), SystemConstant.AFTER_AUDIO_ATTACHMENT_ID, AudioTypeEnum.AFTER.getTitle(), AudioTypeEnum.AFTER, AudioDefaultEnum.SYS, tbUser.getId(), SystemConstant.AFTER_AUDIO_SECOND, teExam, s));//考试结束前语音
+                        teAudioList.add(
+                                new TEAudio(tbUser.getOrgId(), s.getId(), SystemConstant.AFTER_AUDIO_ATTACHMENT_ID,
+                                        AudioTypeEnum.AFTER.getTitle(), AudioTypeEnum.AFTER, AudioDefaultEnum.SYS,
+                                        tbUser.getId(), SystemConstant.AFTER_AUDIO_SECOND, teExam, s));//考试结束前语音
                     }
                     if (Objects.nonNull(s.getEnable()) && s.getEnable().intValue() == 0) {
-                        Integer examCount = tOeExamRecordService.findByExamIdOrExamActivityIdCount(teExam.getId(), s.getId());
+                        Integer examCount = tOeExamRecordService.findByExamIdOrExamActivityIdCount(teExam.getId(),
+                                s.getId());
                         if (Objects.nonNull(examCount) && examCount.intValue() > 0) {
                             throw new BusinessException("已有考试记录不能禁用");
                         }
@@ -387,7 +410,8 @@ public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper,
                                     throw new BusinessException("修改的场次结束时间只能大于当前时间");
                                 }
                                 if (Objects.nonNull(teExam.getForceFinish()) && teExam.getForceFinish().intValue() == 1
-                                        && s.getFinishTime().longValue() != teExamActivityDb.getFinishTime().longValue()) {
+                                        && s.getFinishTime().longValue() != teExamActivityDb.getFinishTime()
+                                        .longValue()) {
                                     //删除再新增quartz任务,发送mq消息start
                                     Map<String, Object> prop = new HashMap<>();
                                     prop.put(SystemConstant.OPER, SystemConstant.INSERT);
@@ -406,52 +430,66 @@ public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper,
                     s.setId(uidUtil.getId());
                     s.setCreateId(tbUser.getId());
                     s.setCode(String.valueOf(redisUtil.getRedisActivityCodeSequence(s.getExamId())));
-                    teAudioList.add(new TEAudio(tbUser.getOrgId(), s.getId(), SystemConstant.BEFORE_AUDIO_ATTACHMENT_ID, AudioTypeEnum.BEFORE.getTitle(), AudioTypeEnum.BEFORE, AudioDefaultEnum.SYS, tbUser.getId(), SystemConstant.BEFORE_AUDIO_SECOND, teExam, s));//开考前语音
-                    teAudioList.add(new TEAudio(tbUser.getOrgId(), s.getId(), SystemConstant.AFTER_AUDIO_ATTACHMENT_ID, AudioTypeEnum.AFTER.getTitle(), AudioTypeEnum.AFTER, AudioDefaultEnum.SYS, tbUser.getId(), SystemConstant.AFTER_AUDIO_SECOND, teExam, s));//考试结束前语音
+                    teAudioList.add(new TEAudio(tbUser.getOrgId(), s.getId(), SystemConstant.BEFORE_AUDIO_ATTACHMENT_ID,
+                            AudioTypeEnum.BEFORE.getTitle(), AudioTypeEnum.BEFORE, AudioDefaultEnum.SYS, tbUser.getId(),
+                            SystemConstant.BEFORE_AUDIO_SECOND, teExam, s));//开考前语音
+                    teAudioList.add(new TEAudio(tbUser.getOrgId(), s.getId(), SystemConstant.AFTER_AUDIO_ATTACHMENT_ID,
+                            AudioTypeEnum.AFTER.getTitle(), AudioTypeEnum.AFTER, AudioDefaultEnum.SYS, tbUser.getId(),
+                            SystemConstant.AFTER_AUDIO_SECOND, teExam, s));//考试结束前语音
                 }
             });
-            teExamActivityService.saveOrUpdateBatch(teExamActivityList);
-            for (TEExamActivity ac : teExamActivityList) {
-                teExamActivityService.updateExamActivityCacheBean(ac.getId());
-                //加入更新考试列表缓存方法
-                ExamActivityCacheBean examActivityCacheBean = this.getExamActivityCacheBean(ac.getId());
-                if (Objects.nonNull(examActivityCacheBean.getEnable()) && examActivityCacheBean.getEnable().intValue() == 1 && Objects.nonNull(teExam.getEnable()) && teExam.getEnable().intValue() == 1 && Objects.nonNull(teExam.getEndTime()) && teExam.getEndTime().longValue() > System.currentTimeMillis()) {
-                    themisCacheService.updateCurrentExamListCache(ac.getExamId().toString(), ac.getId());
-                    themisCacheService.updateOrgExamListCache(teExam.getOrgId().toString(), ac.getExamId().toString(), ac.getId());
-                } else {
-                    themisCacheService.removeCurrentExamListCache(ac.getExamId().toString(), ac.getId());
-                    themisCacheService.removeOrgExamListCache(teExam.getOrgId().toString(), ac.getExamId().toString(), ac.getId());
+            if (!CollectionUtils.isEmpty(teExamActivityList)) {
+                teExamActivityService.saveOrUpdateBatch(teExamActivityList);
+                for (TEExamActivity ac : teExamActivityList) {
+                    teExamActivityService.updateExamActivityCacheBean(ac.getId());
+                    //加入更新考试列表缓存方法
+                    ExamActivityCacheBean examActivityCacheBean = this.getExamActivityCacheBean(ac.getId());
+                    if (Objects.nonNull(examActivityCacheBean.getEnable())
+                            && examActivityCacheBean.getEnable().intValue() == 1 && Objects.nonNull(teExam.getEnable())
+                            && teExam.getEnable().intValue() == 1 && Objects.nonNull(teExam.getEndTime())
+                            && teExam.getEndTime().longValue() > System.currentTimeMillis()) {
+                        themisCacheService.updateCurrentExamListCache(ac.getExamId().toString(), ac.getId());
+                        themisCacheService.updateOrgExamListCache(teExam.getOrgId().toString(),
+                                ac.getExamId().toString(), ac.getId());
+                    } else {
+                        themisCacheService.removeCurrentExamListCache(ac.getExamId().toString(), ac.getId());
+                        themisCacheService.removeOrgExamListCache(teExam.getOrgId().toString(),
+                                ac.getExamId().toString(), ac.getId());
+                    }
                 }
-//                //最后开考时间发送定时任务
-//                //删除再新增quartz任务,发送mq消息start
-//                Map<String, Object> prop = new HashMap<>();
-//                prop.put(SystemConstant.OPER, SystemConstant.INSERT);
-//                prop.put(SystemConstant.EXAM, teExam);
-//                MqDto mqDto = new MqDto(mqUtil.getTopic(), MqTagEnum.EXAM_ACTIVITY_FINAL_PREPARE_TIME.name(), JacksonUtil.parseJson(ac), MqTagEnum.EXAM_ACTIVITY_FINAL_PREPARE_TIME, String.valueOf(teExam.getId()), prop, tbUser.getName());
-//                mqDtoService.assembleSendAsyncOrderMsg(mqDto);
-//                //删除再新增quartz任务,发送mq消息end
+                //最后开考时间发送定时任务
+                Map<String, Object> prop = new HashMap<>();
+                prop.put(SystemConstant.OPER, SystemConstant.INSERT);
+                prop.put(SystemConstant.EXAM, teExam);
+                MqDto mqDto = new MqDto(mqUtil.getTopic(), MqTagEnum.EXAM_ACTIVITY_FINAL_PREPARE_TIME.name(),
+                        JacksonUtil.parseJson(teExamActivityList), MqTagEnum.EXAM_ACTIVITY_FINAL_PREPARE_TIME,
+                        String.valueOf(teExam.getId()), prop, tbUser.getName());
+                mqDtoService.assembleSendAsyncOrderMsg(mqDto);
             }
 
             if (!CollectionUtils.isEmpty(teAudioList)) {
                 teAudioService.saveOrUpdateBatch(teAudioList);
-//                for (TEAudio t : teAudioList) {
-//                    teAudioService.sendAudioMessage(t);
-//                }
+                //                for (TEAudio t : teAudioList) {
+                //                    teAudioService.sendAudioMessage(t);
+                //                }
             }
             if (size.get() > 0 && (Objects.nonNull(teExam.getForceFinish()) && teExam.getForceFinish().intValue() == 1)) {
-                //新增quartz任务,发送mq消息start
-                Map<String, Object> prop = new HashMap<>();
-                prop.put(SystemConstant.OPER, SystemConstant.INSERT);
-                prop.put(SystemConstant.EXAM, teExam);
-                MqDto mqDto = new MqDto(mqUtil.getTopic(), MqTagEnum.EXAM_ACTIVITY.name(),
-                        JacksonUtil.parseJson(teExamActivityList), MqTagEnum.EXAM_ACTIVITY,
-                        String.valueOf(teExam.getId()), prop, tbUser.getName());
-                mqDtoService.assembleSendAsyncOrderMsg(mqDto);
-                //新增quartz任务,发送mq消息end
+                if (Objects.nonNull(teExam.getForceFinish()) && teExam.getForceFinish().intValue() == 1) {
+                    //新增quartz任务,发送mq消息start
+                    Map<String, Object> prop = new HashMap<>();
+                    prop.put(SystemConstant.OPER, SystemConstant.INSERT);
+                    prop.put(SystemConstant.EXAM, teExam);
+                    MqDto mqDto = new MqDto(mqUtil.getTopic(), MqTagEnum.EXAM_ACTIVITY.name(),
+                            JacksonUtil.parseJson(teExamActivityList), MqTagEnum.EXAM_ACTIVITY,
+                            String.valueOf(teExam.getId()), prop, tbUser.getName());
+                    mqDtoService.assembleSendAsyncOrderMsg(mqDto);
+                    //新增quartz任务,发送mq消息end
+                }
             }
         } catch (Exception e) {
             log.error(SystemConstant.LOG_ERROR, e);
-            if (Objects.nonNull(examId) && redisUtil.lock(SystemConstant.REDIS_LOCK_EXAM_ACTIVITY_CODE_PREFIX + examId, SystemConstant.REDIS_LOCK_EXAM_ACTIVITY_CODE_TIME_OUT)) {
+            if (Objects.nonNull(examId) && redisUtil.lock(SystemConstant.REDIS_LOCK_EXAM_ACTIVITY_CODE_PREFIX + examId,
+                    SystemConstant.REDIS_LOCK_EXAM_ACTIVITY_CODE_TIME_OUT)) {
                 try {
                     Integer value = redisUtil.getRedisActivityCodeSequenceValue(examId);
                     redisUtil.setRedisActivityCodeSequence(examId, value - size.get());
@@ -464,7 +502,8 @@ public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper,
                 String columnStr = errorColumn.substring(errorColumn.lastIndexOf("key") + 3, errorColumn.length())
                         .replaceAll("'", "");
                 throw new BusinessException(
-                        "机构id[" + teExamActivityList.get(0).getExamId() + "]下的" + FieldUniqueEnum.convertToCode(columnStr) + "数据不允许重复插入");
+                        "机构id[" + teExamActivityList.get(0).getExamId() + "]下的" + FieldUniqueEnum.convertToCode(
+                                columnStr) + "数据不允许重复插入");
             } else if (e instanceof BusinessException) {
                 throw new BusinessException(e.getMessage());
             } else {

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

@@ -408,14 +408,14 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
         this.sendOeLogMessage(SystemOperationEnum.FIRST_PREPARE, examStudentId, recordId, mqDto);
         //mq发送消息end
 
-        //最后开考时间发送定时任务
-        //删除再新增quartz任务,发送mq消息start
-        Map<String, Object> prop = new HashMap<>();
-        prop.put(SystemConstant.OPER, SystemConstant.INSERT);
-        prop.put(SystemConstant.EXAM, teExamService.getById(es.getExamId()));
-        MqDto mqDtoFinalPrepare = new MqDto(mqUtil.getTopic(), MqTagEnum.EXAM_ACTIVITY_FINAL_PREPARE_TIME.name(), JacksonUtil.parseJson(tOeExamRecord), MqTagEnum.EXAM_ACTIVITY_FINAL_PREPARE_TIME, String.valueOf(tOeExamRecord.getId()), prop, String.valueOf(tOeExamRecord.getId()));
-        mqDtoService.assembleSendAsyncOrderMsg(mqDtoFinalPrepare);
-        //删除再新增quartz任务,发送mq消息end
+//        //最后开考时间发送定时任务
+//        //删除再新增quartz任务,发送mq消息start
+//        Map<String, Object> prop = new HashMap<>();
+//        prop.put(SystemConstant.OPER, SystemConstant.INSERT);
+//        prop.put(SystemConstant.EXAM, teExamService.getById(es.getExamId()));
+//        MqDto mqDtoFinalPrepare = new MqDto(mqUtil.getTopic(), MqTagEnum.EXAM_ACTIVITY_FINAL_PREPARE_TIME.name(), JacksonUtil.parseJson(tOeExamRecord), MqTagEnum.EXAM_ACTIVITY_FINAL_PREPARE_TIME, String.valueOf(tOeExamRecord.getId()), prop, String.valueOf(tOeExamRecord.getId()));
+//        mqDtoService.assembleSendAsyncOrderMsg(mqDtoFinalPrepare);
+//        //删除再新增quartz任务,发送mq消息end
         return prepare;
     }
 

+ 2 - 1
themis-task/src/main/java/com/qmth/themis/task/listener/service/MqTaskLogicService.java

@@ -1,6 +1,7 @@
 package com.qmth.themis.task.listener.service;
 
 import com.qmth.themis.business.dto.MqDto;
+import org.quartz.SchedulerException;
 
 import java.lang.reflect.InvocationTargetException;
 
@@ -27,5 +28,5 @@ public interface MqTaskLogicService {
      * @param mqDto
      * @param key
      */
-    public void execMqQuartzLogic(MqDto mqDto, String key);
+    public void execMqQuartzLogic(MqDto mqDto, String key) throws SchedulerException;
 }

+ 62 - 36
themis-task/src/main/java/com/qmth/themis/task/listener/service/impl/MqTaskLogicServiceImpl.java

@@ -9,7 +9,6 @@ import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.dto.MqDto;
 import com.qmth.themis.business.entity.TEExam;
 import com.qmth.themis.business.entity.TEExamActivity;
-import com.qmth.themis.business.entity.TOeExamRecord;
 import com.qmth.themis.business.enums.MqTagEnum;
 import com.qmth.themis.business.service.TMRocketMessageService;
 import com.qmth.themis.business.util.JacksonUtil;
@@ -19,6 +18,7 @@ import com.qmth.themis.task.quartz.ExamActivityFinalPrepareTimeJob;
 import com.qmth.themis.task.quartz.ExamActivityJob;
 import com.qmth.themis.task.quartz.ExamStudentJob;
 import com.qmth.themis.task.service.QuartzService;
+import org.quartz.SchedulerException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
@@ -39,6 +39,7 @@ import java.util.Objects;
  */
 @Service
 public class MqTaskLogicServiceImpl implements MqTaskLogicService {
+
     private final static Logger log = LoggerFactory.getLogger(MqTaskLogicServiceImpl.class);
 
     @Resource
@@ -62,7 +63,7 @@ public class MqTaskLogicServiceImpl implements MqTaskLogicService {
 
     @Override
     @Transactional
-    public void execMqQuartzLogic(MqDto mqDto, String key) {
+    public void execMqQuartzLogic(MqDto mqDto, String key) throws SchedulerException {
         Map<String, Object> tranMap = mqDto.getProperties();
         String oper = String.valueOf(tranMap.get(SystemConstant.OPER));
         Object o = JacksonUtil.parseJson(tranMap.get(SystemConstant.EXAM));
@@ -72,12 +73,19 @@ public class MqTaskLogicServiceImpl implements MqTaskLogicService {
             JSONArray jsonArray = (JSONArray) JSONArray.parse(String.valueOf(mqDto.getBody()));
             for (int i = 0; i < jsonArray.size(); i++) {
                 TEExamActivity teExamActivity = JSONObject.toJavaObject((JSON) jsonArray.get(i), TEExamActivity.class);
-                if (Objects.equals(SystemConstant.DELETE, oper)) {
-                    quartzService.deleteJob(String.valueOf(teExamActivity.getId()), QuartzTaskEnum.EXAM_ACTIVITY_JOB_GROUP_NAME.name());
-                } else if (Objects.equals(SystemConstant.INSERT, oper)) {
-                    quartzService.deleteJob(String.valueOf(teExamActivity.getId()), QuartzTaskEnum.EXAM_ACTIVITY_JOB_GROUP_NAME.name());
-                    if (Objects.nonNull(teExam.getEnable()) && teExam.getEnable().intValue() == 1 && Objects.nonNull(teExamActivity.getEnable()) && teExamActivity.getEnable().intValue() == 1) {
-                        this.setCron(teExamActivity.getFinishTime(), String.valueOf(teExamActivity.getId()), ExamActivityJob.class, QuartzTaskEnum.EXAM_ACTIVITY_JOB_GROUP_NAME);
+                if (Objects.nonNull(teExamActivity.getFinishTime())
+                        && teExamActivity.getFinishTime().longValue() > System.currentTimeMillis()) {
+                    String jobName = teExamActivity.getId() + "-" + teExamActivity.getFinishTime();
+                    if (Objects.equals(SystemConstant.DELETE, oper)) {
+                        quartzService.deleteJob(jobName, QuartzTaskEnum.EXAM_ACTIVITY_JOB_GROUP_NAME.name());
+                    } else if (Objects.equals(SystemConstant.INSERT, oper)) {
+                        quartzService.deleteJob(jobName, QuartzTaskEnum.EXAM_ACTIVITY_JOB_GROUP_NAME.name());
+                        if (Objects.nonNull(teExam.getEnable()) && teExam.getEnable().intValue() == 1
+                                && Objects.nonNull(teExamActivity.getEnable())
+                                && teExamActivity.getEnable().intValue() == 1) {
+                            this.setCron(teExamActivity.getFinishTime(), jobName, ExamActivityJob.class,
+                                    QuartzTaskEnum.EXAM_ACTIVITY_JOB_GROUP_NAME);
+                        }
                     }
                 }
             }
@@ -85,40 +93,58 @@ public class MqTaskLogicServiceImpl implements MqTaskLogicService {
             JSONObject jsonObject = JSONObject.parseObject(String.valueOf(mqDto.getBody()));
             ExamStudentCacheBean examStudentCacheBean = JSONObject.toJavaObject(jsonObject, ExamStudentCacheBean.class);
             Long recordId = Long.parseLong(String.valueOf(mqDto.getObjId()));
+            String jobName = examStudentCacheBean.getId() + "-" + recordId;
             if (Objects.equals(SystemConstant.DELETE, oper)) {
-                quartzService.deleteJob(examStudentCacheBean.getId() + "-" + recordId, QuartzTaskEnum.EXAM_STUDENT_JOB_GROUP_NAME.name());
+                quartzService.deleteJob(jobName, QuartzTaskEnum.EXAM_STUDENT_JOB_GROUP_NAME.name());
             } else if (Objects.equals(SystemConstant.INSERT, oper)) {
-                quartzService.deleteJob(examStudentCacheBean.getId() + "-" + recordId, QuartzTaskEnum.EXAM_STUDENT_JOB_GROUP_NAME.name());
-                if (Objects.nonNull(examStudentCacheBean.getEnable()) && examStudentCacheBean.getEnable().intValue() == 1) {
-                    this.setCron(ExamRecordCacheUtil.getExamFinalFinishTime(recordId), examStudentCacheBean.getId() + "-" + recordId, ExamStudentJob.class, QuartzTaskEnum.EXAM_STUDENT_JOB_GROUP_NAME);
+                quartzService.deleteJob(jobName, QuartzTaskEnum.EXAM_STUDENT_JOB_GROUP_NAME.name());
+                if (Objects.nonNull(examStudentCacheBean.getEnable())
+                        && examStudentCacheBean.getEnable().intValue() == 1) {
+                    this.setCron(ExamRecordCacheUtil.getExamFinalFinishTime(recordId), jobName, ExamStudentJob.class,
+                            QuartzTaskEnum.EXAM_STUDENT_JOB_GROUP_NAME);
                 }
             }
         } else if (Objects.equals(tag, MqTagEnum.EXAM_ACTIVITY_FINAL_PREPARE_TIME.name())) {//考场最后开考时间任务
-            JSONObject jsonObject = JSONObject.parseObject(String.valueOf(mqDto.getBody()));
-            TOeExamRecord tOeExamRecord = JSONObject.toJavaObject(jsonObject, TOeExamRecord.class);
-            if (Objects.equals(SystemConstant.DELETE, oper)) {
-                quartzService.deleteJob(String.valueOf(tOeExamRecord.getId()), QuartzTaskEnum.EXAM_ACTIVITY_FINAL_PREPARE_TIME_JOB_GROUP_NAME.name());
-            } else if (Objects.equals(SystemConstant.INSERT, oper)) {
-                quartzService.deleteJob(String.valueOf(tOeExamRecord.getId()), QuartzTaskEnum.EXAM_ACTIVITY_FINAL_PREPARE_TIME_JOB_GROUP_NAME.name());
-                Integer openingSecondsTemp = tOeExamRecord.getOpeningSeconds();
-                openingSecondsTemp = Objects.nonNull(openingSecondsTemp) && openingSecondsTemp.intValue() == 0 ? SystemConstant.DEFAULT_OPENING_SECONDS : openingSecondsTemp;
-                Long finalPrepareTime = tOeExamRecord.getStartTime() + (openingSecondsTemp * 1000);
-                this.setCron(finalPrepareTime, String.valueOf(tOeExamRecord.getId()), ExamActivityFinalPrepareTimeJob.class, QuartzTaskEnum.EXAM_ACTIVITY_FINAL_PREPARE_TIME_JOB_GROUP_NAME);
+            JSONArray jsonArray = (JSONArray) JSONArray.parse(String.valueOf(mqDto.getBody()));
+            for (int i = 0; i < jsonArray.size(); i++) {
+                TEExamActivity teExamActivity = JSONObject.toJavaObject((JSON) jsonArray.get(i), TEExamActivity.class);
+                Integer openingSecondsTemp = teExamActivity.getOpeningSeconds();
+                openingSecondsTemp = Objects.nonNull(openingSecondsTemp) && openingSecondsTemp.intValue() == 0 ?
+                        SystemConstant.DEFAULT_OPENING_SECONDS :
+                        openingSecondsTemp;
+                Long finalPrepareTime = teExamActivity.getStartTime() + (openingSecondsTemp * 1000);
+                if (Objects.nonNull(finalPrepareTime) && finalPrepareTime.longValue() > System.currentTimeMillis()) {
+                    String jobName = teExamActivity.getId() + "-" + finalPrepareTime;
+                    //                    JobKey jobKey = new JobKey(teExamActivity.getId() + "-" + finalPrepareTime,
+                    //                            QuartzTaskEnum.EXAM_ACTIVITY_FINAL_PREPARE_TIME_JOB_GROUP_NAME.name());
+                    //                    List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
+                    if (Objects.equals(SystemConstant.DELETE, oper)) {
+                        quartzService.deleteJob(jobName,
+                                QuartzTaskEnum.EXAM_ACTIVITY_FINAL_PREPARE_TIME_JOB_GROUP_NAME.name());
+                    } else if (Objects.equals(SystemConstant.INSERT, oper)) {
+                        quartzService.deleteJob(jobName,
+                                QuartzTaskEnum.EXAM_ACTIVITY_FINAL_PREPARE_TIME_JOB_GROUP_NAME.name());
+                        if (Objects.nonNull(teExamActivity.getEnable()) && teExamActivity.getEnable().intValue() == 1) {
+                            this.setCron(finalPrepareTime, jobName, ExamActivityFinalPrepareTimeJob.class,
+                                    QuartzTaskEnum.EXAM_ACTIVITY_FINAL_PREPARE_TIME_JOB_GROUP_NAME);
+                        }
+                    }
+                }
             }
         }
-//        else if (Objects.equals(tag, MqTagEnum.EXAM_AUDIO.name())) {//考试语音
-//            JSONObject jsonObject = JSONObject.parseObject(String.valueOf(mqDto.getBody()));
-//            TEAudio teAudio = JSONObject.toJavaObject(jsonObject, TEAudio.class);
-//            Long examId = Long.parseLong(String.valueOf(mqDto.getObjId()));
-//            if (Objects.equals(SystemConstant.DELETE, oper)) {
-//                quartzService.deleteJob(teAudio.getId() + "-" + teAudio.getActivityId() + "-" + examId, QuartzTaskEnum.EXAM_AUDIO_JOB_GROUP_NAME.name());
-//            } else if (Objects.equals(SystemConstant.INSERT, oper)) {
-//                quartzService.deleteJob(teAudio.getId() + "-" + teAudio.getActivityId() + "-" + examId, QuartzTaskEnum.EXAM_AUDIO_JOB_GROUP_NAME.name());
-//                Long execTime = (Long) tranMap.get(SystemConstant.EXEC_TIME);
-//                Long realExecTime = (Long) tranMap.get(SystemConstant.REAL_EXEC_TIME);
-//                this.setCron(execTime, teAudio.getId() + "-" + teAudio.getActivityId() + "-" + examId + "-" + realExecTime, ExamAudioJob.class, QuartzTaskEnum.EXAM_AUDIO_JOB_GROUP_NAME);
-//            }
-//        }
+        //        else if (Objects.equals(tag, MqTagEnum.EXAM_AUDIO.name())) {//考试语音
+        //            JSONObject jsonObject = JSONObject.parseObject(String.valueOf(mqDto.getBody()));
+        //            TEAudio teAudio = JSONObject.toJavaObject(jsonObject, TEAudio.class);
+        //            Long examId = Long.parseLong(String.valueOf(mqDto.getObjId()));
+        //            if (Objects.equals(SystemConstant.DELETE, oper)) {
+        //                quartzService.deleteJob(teAudio.getId() + "-" + teAudio.getActivityId() + "-" + examId, QuartzTaskEnum.EXAM_AUDIO_JOB_GROUP_NAME.name());
+        //            } else if (Objects.equals(SystemConstant.INSERT, oper)) {
+        //                quartzService.deleteJob(teAudio.getId() + "-" + teAudio.getActivityId() + "-" + examId, QuartzTaskEnum.EXAM_AUDIO_JOB_GROUP_NAME.name());
+        //                Long execTime = (Long) tranMap.get(SystemConstant.EXEC_TIME);
+        //                Long realExecTime = (Long) tranMap.get(SystemConstant.REAL_EXEC_TIME);
+        //                this.setCron(execTime, teAudio.getId() + "-" + teAudio.getActivityId() + "-" + examId + "-" + realExecTime, ExamAudioJob.class, QuartzTaskEnum.EXAM_AUDIO_JOB_GROUP_NAME);
+        //            }
+        //        }
         tmRocketMessageService.saveMqMessageSuccess(mqDto, key);
     }
 
@@ -133,7 +159,7 @@ public class MqTaskLogicServiceImpl implements MqTaskLogicService {
     public void setCron(Long finishTime, String jobName, Class cls, QuartzTaskEnum quartzTaskEnum) {
         Calendar calendar = Calendar.getInstance();
         calendar.setTimeInMillis(finishTime);
-//                    calendar.add(Calendar.SECOND, 30);
+        //                    calendar.add(Calendar.SECOND, 30);
         if (calendar.getTime().getTime() > System.currentTimeMillis()) {
             int year = calendar.get(Calendar.YEAR);//获取年份
             int month = calendar.get(Calendar.MONTH) + 1;//获取月份

+ 125 - 88
themis-task/src/main/java/com/qmth/themis/task/quartz/service/impl/QuartzLogicServiceImpl.java

@@ -33,6 +33,7 @@ import java.util.*;
  */
 @Service
 public class QuartzLogicServiceImpl implements QuartzLogicService {
+
     private final static Logger log = LoggerFactory.getLogger(QuartzLogicServiceImpl.class);
 
     @Resource
@@ -66,9 +67,13 @@ public class QuartzLogicServiceImpl implements QuartzLogicService {
     public void execExamActivityJobLogic(String key) {
         log.info("execExamActivityJobLogic key:{}", key);
         String[] strings = key.split("\\.");
-        ExamActivityCacheBean examActivityCacheBean = teExamActivityService.getExamActivityCacheBean(Long.parseLong(strings[1]));
+        String[] keys = strings[1].split("-");
+        ExamActivityCacheBean examActivityCacheBean = teExamActivityService.getExamActivityCacheBean(
+                Long.parseLong(keys[0]));
+        Long finishTime = Long.parseLong(keys[1]);
         ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examActivityCacheBean.getExamId());
-        if (Objects.nonNull(examCacheBean) && examCacheBean.getEnable().intValue() == 1 && Objects.nonNull(examActivityCacheBean) && examActivityCacheBean.getEnable().intValue() == 1) {
+        if (Objects.nonNull(examCacheBean) && examCacheBean.getEnable().intValue() == 1 && Objects.nonNull(
+                examActivityCacheBean) && examActivityCacheBean.getEnable().intValue() == 1) {
             Integer forceFinish = examCacheBean.getForceFinish();
             QueryWrapper<TOeExamRecord> tOeExamRecordQueryWrapper = new QueryWrapper<>();
             tOeExamRecordQueryWrapper.lambda().eq(TOeExamRecord::getExamActivityId, examActivityCacheBean.getId());
@@ -79,28 +84,34 @@ public class QuartzLogicServiceImpl implements QuartzLogicService {
                     examRecordList.forEach(s -> {
                         ExamRecordStatusEnum examRecordStatusEnum = s.getStatus();
                         //获取该考试批次下所有未交卷的考生的考试记录
-                        if (Objects.nonNull(examRecordStatusEnum)
-                                && !Objects.equals(ExamRecordStatusEnum.FINISHED, examRecordStatusEnum)
-                                && !Objects.equals(ExamRecordStatusEnum.PERSISTED, examRecordStatusEnum)
-                                && !Objects.equals(ExamRecordStatusEnum.JUNK, examRecordStatusEnum)) {
+                        if (Objects.nonNull(examRecordStatusEnum) && !Objects.equals(ExamRecordStatusEnum.FINISHED,
+                                examRecordStatusEnum) && !Objects.equals(ExamRecordStatusEnum.PERSISTED,
+                                examRecordStatusEnum) && !Objects.equals(ExamRecordStatusEnum.JUNK,
+                                examRecordStatusEnum)) {
                             Integer durationSeconds = s.getDurationSeconds();
                             Long examStudentId = s.getExamStudentId();
-                            ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(examStudentId);
+                            ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(
+                                    examStudentId);
                             //候考阶段且没有进入考试则不交卷
                             try {
-                                if (examRecordStatusEnum == ExamRecordStatusEnum.FIRST_PREPARE && Objects.isNull(s.getFirstStartTime())) {
-                                    commonService.deleteExamStudentCache(s.getId(), examStudentCacheBean.getStudentId());
+                                if (examRecordStatusEnum == ExamRecordStatusEnum.FIRST_PREPARE && Objects.isNull(
+                                        s.getFirstStartTime())) {
+                                    commonService.deleteExamStudentCache(s.getId(),
+                                            examStudentCacheBean.getStudentId());
                                     s.setStatus(ExamRecordStatusEnum.JUNK);
                                     s.setUpdateTime(System.currentTimeMillis());
-                                    if (Objects.nonNull(s.getClientWebsocketStatus()) && s.getClientWebsocketStatus() == WebsocketStatusEnum.ON_LINE) {
+                                    if (Objects.nonNull(s.getClientWebsocketStatus())
+                                            && s.getClientWebsocketStatus() == WebsocketStatusEnum.ON_LINE) {
                                         s.setClientWebsocketStatus(WebsocketStatusEnum.OFF_LINE);
                                     }
                                     updateExamRecordList.add(s);
                                     commonService.dismissRoomByStrRoomId(s.getId());
                                 } else {//交卷
                                     Long recordEndTime = s.getEndTime();
-                                    if (Objects.nonNull(examActivityCacheBean.getFinishTime()) && Objects.nonNull(recordEndTime) && examActivityCacheBean.getFinishTime().longValue() == recordEndTime.longValue()) {
-                                        teExamService.finish(examStudentCacheBean.getStudentId(), s.getId(), FinishTypeEnum.AUTO.name(), durationSeconds);
+                                    if (Objects.nonNull(finishTime) && Objects.nonNull(recordEndTime)
+                                            && finishTime.longValue() == recordEndTime.longValue()) {
+                                        teExamService.finish(examStudentCacheBean.getStudentId(), s.getId(),
+                                                FinishTypeEnum.AUTO.name(), durationSeconds);
                                     }
                                 }
                             } catch (Exception e) {
@@ -118,29 +129,35 @@ public class QuartzLogicServiceImpl implements QuartzLogicService {
                     examRecordList.forEach(s -> {
                         ExamRecordStatusEnum examRecordStatusEnum = s.getStatus();
                         //获取该考试批次下所有未交卷的考生的考试记录
-                        if (Objects.nonNull(examRecordStatusEnum)
-                                && !Objects.equals(ExamRecordStatusEnum.FINISHED, examRecordStatusEnum)
-                                && !Objects.equals(ExamRecordStatusEnum.PERSISTED, examRecordStatusEnum)
-                                && !Objects.equals(ExamRecordStatusEnum.ANSWERING, examRecordStatusEnum)
-                                && !Objects.equals(ExamRecordStatusEnum.JUNK, examRecordStatusEnum)) {
+                        if (Objects.nonNull(examRecordStatusEnum) && !Objects.equals(ExamRecordStatusEnum.FINISHED,
+                                examRecordStatusEnum) && !Objects.equals(ExamRecordStatusEnum.PERSISTED,
+                                examRecordStatusEnum) && !Objects.equals(ExamRecordStatusEnum.ANSWERING,
+                                examRecordStatusEnum) && !Objects.equals(ExamRecordStatusEnum.JUNK,
+                                examRecordStatusEnum)) {
                             Long recordEndTime = s.getEndTime();
-                            if (Objects.nonNull(examActivityCacheBean.getFinishTime()) && Objects.nonNull(recordEndTime) && examActivityCacheBean.getFinishTime().longValue() == recordEndTime.longValue()) {
+                            if (Objects.nonNull(examActivityCacheBean.getFinishTime()) && Objects.nonNull(recordEndTime)
+                                    && examActivityCacheBean.getFinishTime().longValue() == recordEndTime.longValue()) {
                                 Integer durationSeconds = s.getDurationSeconds();
                                 Long examStudentId = s.getExamStudentId();
-                                ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(examStudentId);
+                                ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(
+                                        examStudentId);
                                 //候考阶段且没有进入考试则不交卷
                                 try {
-                                    if (examRecordStatusEnum == ExamRecordStatusEnum.FIRST_PREPARE && Objects.isNull(s.getFirstStartTime())) {
-                                        commonService.deleteExamStudentCache(s.getId(), examStudentCacheBean.getStudentId());
+                                    if (examRecordStatusEnum == ExamRecordStatusEnum.FIRST_PREPARE && Objects.isNull(
+                                            s.getFirstStartTime())) {
+                                        commonService.deleteExamStudentCache(s.getId(),
+                                                examStudentCacheBean.getStudentId());
                                         s.setStatus(ExamRecordStatusEnum.JUNK);
                                         s.setUpdateTime(System.currentTimeMillis());
-                                        if (Objects.nonNull(s.getClientWebsocketStatus()) && s.getClientWebsocketStatus() == WebsocketStatusEnum.ON_LINE) {
+                                        if (Objects.nonNull(s.getClientWebsocketStatus())
+                                                && s.getClientWebsocketStatus() == WebsocketStatusEnum.ON_LINE) {
                                             s.setClientWebsocketStatus(WebsocketStatusEnum.OFF_LINE);
                                         }
                                         updateExamRecordList.add(s);
                                         commonService.dismissRoomByStrRoomId(s.getId());
                                     } else {//交卷
-                                        teExamService.finish(examStudentCacheBean.getStudentId(), s.getId(), FinishTypeEnum.AUTO.name(), durationSeconds);
+                                        teExamService.finish(examStudentCacheBean.getStudentId(), s.getId(),
+                                                FinishTypeEnum.AUTO.name(), durationSeconds);
                                     }
                                 } catch (Exception e) {
                                     log.error(SystemConstant.LOG_ERROR, e);
@@ -165,17 +182,18 @@ public class QuartzLogicServiceImpl implements QuartzLogicService {
     public void execExamStudentJobLogic(String key) {
         log.info("execExamStudentJobLogic key:{}", key);
         String[] strings = key.split("\\.");
-        String[] exams = strings[1].split("-");
-        ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(Long.parseLong(exams[0]));
-        Long recordId = Long.parseLong(exams[1]);
+        String[] keys = strings[1].split("-");
+        ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(
+                Long.parseLong(keys[0]));
+        Long recordId = Long.parseLong(keys[1]);
         ExamRecordStatusEnum examRecordStatusEnum = ExamRecordCacheUtil.getStatus(recordId);
-        ExamActivityCacheBean examActivityCacheBean = teExamActivityService.getExamActivityCacheBean(examStudentCacheBean.getExamActivityId());
+        ExamActivityCacheBean examActivityCacheBean = teExamActivityService.getExamActivityCacheBean(
+                examStudentCacheBean.getExamActivityId());
         //获取该考试批次下所有未交卷的考生的考试记录
-        if (Objects.nonNull(examRecordStatusEnum)
-                && !Objects.equals(ExamRecordStatusEnum.FINISHED, examRecordStatusEnum)
-                && !Objects.equals(ExamRecordStatusEnum.PERSISTED, examRecordStatusEnum)
-                && !Objects.equals(ExamRecordStatusEnum.ANSWERING, examRecordStatusEnum)
-                && !Objects.equals(ExamRecordStatusEnum.JUNK, examRecordStatusEnum)) {
+        if (Objects.nonNull(examRecordStatusEnum) && !Objects.equals(ExamRecordStatusEnum.FINISHED,
+                examRecordStatusEnum) && !Objects.equals(ExamRecordStatusEnum.PERSISTED, examRecordStatusEnum)
+                && !Objects.equals(ExamRecordStatusEnum.ANSWERING, examRecordStatusEnum) && !Objects.equals(
+                ExamRecordStatusEnum.JUNK, examRecordStatusEnum)) {
             Long firstStartTime = ExamRecordCacheUtil.getFirstStartTime(recordId);
             if (Objects.isNull(firstStartTime)) {
                 TOeExamRecord tOeExamRecord = SystemConstant.getExamRecord(recordId);
@@ -189,7 +207,8 @@ public class QuartzLogicServiceImpl implements QuartzLogicService {
                     commonService.deleteExamStudentCache(recordId, examStudentCacheBean.getStudentId());
                     tOeExamRecord.setStatus(ExamRecordStatusEnum.JUNK);
                     tOeExamRecord.setUpdateTime(System.currentTimeMillis());
-                    if (Objects.nonNull(tOeExamRecord.getClientWebsocketStatus()) && tOeExamRecord.getClientWebsocketStatus() == WebsocketStatusEnum.ON_LINE) {
+                    if (Objects.nonNull(tOeExamRecord.getClientWebsocketStatus())
+                            && tOeExamRecord.getClientWebsocketStatus() == WebsocketStatusEnum.ON_LINE) {
                         tOeExamRecord.setClientWebsocketStatus(WebsocketStatusEnum.OFF_LINE);
                     }
                     commonService.dismissRoomByStrRoomId(recordId);
@@ -197,7 +216,8 @@ public class QuartzLogicServiceImpl implements QuartzLogicService {
                     Long recordEndTime = ExamRecordCacheUtil.getEndTime(recordId);
                     if (examActivityCacheBean.getFinishTime().longValue() == recordEndTime.longValue()) {
                         Integer durationSeconds = ExamRecordCacheUtil.getDurationSeconds(recordId);
-                        teExamService.finish(examStudentCacheBean.getStudentId(), recordId, FinishTypeEnum.AUTO.name(), durationSeconds);
+                        teExamService.finish(examStudentCacheBean.getStudentId(), recordId, FinishTypeEnum.AUTO.name(),
+                                durationSeconds);
                     }
                 }
             } catch (Exception e) {
@@ -217,61 +237,78 @@ public class QuartzLogicServiceImpl implements QuartzLogicService {
     @Override
     public void execExamActivityFinalPrepareTimeJobLogic(String key) {
         String[] strings = key.split("\\.");
-        String[] examRecordIds = strings[1].split("-");
-        TOeExamRecord tOeExamRecord = tOeExamRecordService.getById(Long.parseLong(examRecordIds[0]));
-        if (Objects.nonNull(tOeExamRecord)
-                && tOeExamRecord.getStatus() == ExamRecordStatusEnum.FIRST_PREPARE
-                && tOeExamRecord.getClientWebsocketStatus() == WebsocketStatusEnum.ON_LINE) {
-            Map<String, Object> properties = new HashMap<>();
-            properties.put(SystemConstant.RECORD_ID, tOeExamRecord.getId());
-            MqDto clientMqDto = new MqDto(mqUtil.getTopic(), MqTagEnum.EXAM_EXIT.name(), tOeExamRecord.getId(), MqTagEnum.EXAM_EXIT, String.valueOf(tOeExamRecord.getId()), properties, String.valueOf(tOeExamRecord.getId()));
-            mqDtoService.assembleSendAsyncOrderMsg(clientMqDto);
+        String[] keys = strings[1].split("-");
+        ExamActivityCacheBean examActivityCacheBean = teExamActivityService.getExamActivityCacheBean(
+                Long.parseLong(keys[0]));
+        Long finalPrepareTime = Long.parseLong(keys[1]);
+        ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examActivityCacheBean.getExamId());
+        List<TOeExamRecord> tOeExamRecordList = tOeExamRecordService.list(
+                new QueryWrapper<TOeExamRecord>().lambda().eq(TOeExamRecord::getExamId, examCacheBean.getId())
+                        .eq(TOeExamRecord::getExamActivityId, examActivityCacheBean.getId())
+                        .eq(TOeExamRecord::getStatus, ExamRecordStatusEnum.FIRST_PREPARE)
+                        .eq(TOeExamRecord::getClientWebsocketStatus, WebsocketStatusEnum.ON_LINE));
+        if (!CollectionUtils.isEmpty(tOeExamRecordList)) {
+            for (TOeExamRecord t : tOeExamRecordList) {
+                Integer openingSecondsTemp = t.getOpeningSeconds();
+                openingSecondsTemp = Objects.nonNull(openingSecondsTemp) && openingSecondsTemp.intValue() == 0 ?
+                        SystemConstant.DEFAULT_OPENING_SECONDS :
+                        openingSecondsTemp;
+                Long finalExamRecordPrepareTime = t.getStartTime() + (openingSecondsTemp * 1000);
+                if (Objects.nonNull(finalExamRecordPrepareTime) && Objects.nonNull(finalPrepareTime)
+                        && finalExamRecordPrepareTime.longValue() == finalPrepareTime.longValue()) {
+                    Map<String, Object> properties = new HashMap<>();
+                    properties.put(SystemConstant.RECORD_ID, t.getId());
+                    MqDto clientMqDto = new MqDto(mqUtil.getTopic(), MqTagEnum.EXAM_EXIT.name(), t.getId(),
+                            MqTagEnum.EXAM_EXIT, String.valueOf(t.getId()), properties, String.valueOf(t.getId()));
+                    mqDtoService.assembleSendAsyncOrderMsg(clientMqDto);
+                }
+            }
         }
     }
 
-//    /**
-//     * 考试语音quartz逻辑
-//     *
-//     * @param key
-//     */
-//    @Override
-//    public void execExamAudioJobLogic(String key) {
-//        log.info("execExamAudioJobLogic key:{}", key);
-//        String[] strings = key.split("\\.");
-//        String[] exams = strings[1].split("-");
-//        Long teAudioId = Long.parseLong(exams[0]);
-//        Long examActivityId = Long.parseLong(exams[1]);
-//        Long examId = Long.parseLong(exams[2]);
-//        Long execTime = Long.parseLong(exams[3]);
-//        if (Objects.nonNull(teAudioId)) {
-//            List<TOeExamRecord> tOeExamRecordList = tOeExamRecordService.findExamRecordByExamIdAndExamActivityId(examId, examActivityId);
-//            if (!CollectionUtils.isEmpty(tOeExamRecordList)) {
-//                for (TOeExamRecord t : tOeExamRecordList) {
-//                    ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examId);
-//                    ExamActivityCacheBean examActivityCacheBean = teExamActivityService.getExamActivityCacheBean(examActivityId);
-//                    TEAudio teAudio = cacheService.examAudioCache(teAudioId);
-//                    if (Objects.nonNull(examCacheBean) && Objects.nonNull(examActivityCacheBean) && Objects.nonNull(teAudio)
-//                            && Objects.nonNull(examCacheBean.getForceFinish()) && examCacheBean.getForceFinish().intValue() == 1
-//                            && Objects.nonNull(examCacheBean.getEnable()) && examCacheBean.getEnable() == 1
-//                            && Objects.nonNull(examActivityCacheBean.getEnable()) && examActivityCacheBean.getEnable() == 1
-//                            && Objects.nonNull(teAudio.getEnable()) && teAudio.getEnable()
-//                            && Objects.nonNull(t.getMonitorRecord())
-//                            && (t.getMonitorRecord().contains(MonitorVideoSourceEnum.MOBILE_FIRST.name())
-//                            || t.getMonitorRecord().contains(MonitorVideoSourceEnum.MOBILE_SECOND.name()))) {
-//                        Map<String, Object> mapParameter = new HashMap<>();
-//                        mapParameter.put(SystemConstant.RECORD_ID, t.getId());
-//                        mapParameter.put(SystemConstant.EXEC_TIME, execTime);
-//                        TBAttachment tbAttachment = cacheService.attachmentCache(teAudio.getAttachmentId());
-//                        if (Objects.nonNull(tbAttachment) && Objects.nonNull(tbAttachment.getRemark())) {
-//                            JSONObject jsonObject = JSONObject.parseObject(tbAttachment.getRemark());
-//                            mapParameter.put(SystemConstant.PATH, ossUtil.getAliYunOssPublicDomain().getPublicUrl() + File.separator + jsonObject.getString(SystemConstant.PATH));
-//                            mapParameter.put(SystemConstant.NAME, tbAttachment.getName() + tbAttachment.getType());
-//                        }
-//                        MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.EXAM_AUDIO_MOBILE.name(), t.getId(), MqTagEnum.EXAM_AUDIO_MOBILE, exams[2], mapParameter, exams[2]);
-//                        mqDtoService.assembleSendOneOrderMsg(mqDto);
-//                    }
-//                }
-//            }
-//        }
-//    }
+    //    /**
+    //     * 考试语音quartz逻辑
+    //     *
+    //     * @param key
+    //     */
+    //    @Override
+    //    public void execExamAudioJobLogic(String key) {
+    //        log.info("execExamAudioJobLogic key:{}", key);
+    //        String[] strings = key.split("\\.");
+    //        String[] exams = strings[1].split("-");
+    //        Long teAudioId = Long.parseLong(exams[0]);
+    //        Long examActivityId = Long.parseLong(exams[1]);
+    //        Long examId = Long.parseLong(exams[2]);
+    //        Long execTime = Long.parseLong(exams[3]);
+    //        if (Objects.nonNull(teAudioId)) {
+    //            List<TOeExamRecord> tOeExamRecordList = tOeExamRecordService.findExamRecordByExamIdAndExamActivityId(examId, examActivityId);
+    //            if (!CollectionUtils.isEmpty(tOeExamRecordList)) {
+    //                for (TOeExamRecord t : tOeExamRecordList) {
+    //                    ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examId);
+    //                    ExamActivityCacheBean examActivityCacheBean = teExamActivityService.getExamActivityCacheBean(examActivityId);
+    //                    TEAudio teAudio = cacheService.examAudioCache(teAudioId);
+    //                    if (Objects.nonNull(examCacheBean) && Objects.nonNull(examActivityCacheBean) && Objects.nonNull(teAudio)
+    //                            && Objects.nonNull(examCacheBean.getForceFinish()) && examCacheBean.getForceFinish().intValue() == 1
+    //                            && Objects.nonNull(examCacheBean.getEnable()) && examCacheBean.getEnable() == 1
+    //                            && Objects.nonNull(examActivityCacheBean.getEnable()) && examActivityCacheBean.getEnable() == 1
+    //                            && Objects.nonNull(teAudio.getEnable()) && teAudio.getEnable()
+    //                            && Objects.nonNull(t.getMonitorRecord())
+    //                            && (t.getMonitorRecord().contains(MonitorVideoSourceEnum.MOBILE_FIRST.name())
+    //                            || t.getMonitorRecord().contains(MonitorVideoSourceEnum.MOBILE_SECOND.name()))) {
+    //                        Map<String, Object> mapParameter = new HashMap<>();
+    //                        mapParameter.put(SystemConstant.RECORD_ID, t.getId());
+    //                        mapParameter.put(SystemConstant.EXEC_TIME, execTime);
+    //                        TBAttachment tbAttachment = cacheService.attachmentCache(teAudio.getAttachmentId());
+    //                        if (Objects.nonNull(tbAttachment) && Objects.nonNull(tbAttachment.getRemark())) {
+    //                            JSONObject jsonObject = JSONObject.parseObject(tbAttachment.getRemark());
+    //                            mapParameter.put(SystemConstant.PATH, ossUtil.getAliYunOssPublicDomain().getPublicUrl() + File.separator + jsonObject.getString(SystemConstant.PATH));
+    //                            mapParameter.put(SystemConstant.NAME, tbAttachment.getName() + tbAttachment.getType());
+    //                        }
+    //                        MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.EXAM_AUDIO_MOBILE.name(), t.getId(), MqTagEnum.EXAM_AUDIO_MOBILE, exams[2], mapParameter, exams[2]);
+    //                        mqDtoService.assembleSendOneOrderMsg(mqDto);
+    //                    }
+    //                }
+    //            }
+    //        }
+    //    }
 }