Эх сурвалжийг харах

推送云阅卷数据修改

wangliang 2 жил өмнө
parent
commit
df34c65ae0
30 өөрчлөгдсөн 1024 нэмэгдсэн , 247 устгасан
  1. 0 1
      themis-admin/src/main/java/com/qmth/themis/admin/api/TBUserController.java
  2. 1 5
      themis-admin/src/main/java/com/qmth/themis/admin/api/TEExamActivityController.java
  3. 110 164
      themis-admin/src/main/java/com/qmth/themis/admin/api/TEExamController.java
  4. 66 0
      themis-admin/src/main/java/com/qmth/themis/admin/api/TEExamStudentController.java
  5. 5 3
      themis-admin/src/main/resources/application-dev.properties
  6. 6 4
      themis-business/src/main/java/com/qmth/themis/business/bean/cloudmark/SaveExamParams.java
  7. 23 0
      themis-business/src/main/java/com/qmth/themis/business/cache/bean/ExamCacheBean.java
  8. 2 3
      themis-business/src/main/java/com/qmth/themis/business/constant/SystemConstant.java
  9. 10 0
      themis-business/src/main/java/com/qmth/themis/business/dao/TEExamStudentMapper.java
  10. 10 0
      themis-business/src/main/java/com/qmth/themis/business/dao/TOeExamRecordMapper.java
  11. 11 0
      themis-business/src/main/java/com/qmth/themis/business/entity/TBTaskHistory.java
  12. 10 12
      themis-business/src/main/java/com/qmth/themis/business/entity/TEAudio.java
  13. 1 0
      themis-business/src/main/java/com/qmth/themis/business/entity/TEExam.java
  14. 2 0
      themis-business/src/main/java/com/qmth/themis/business/enums/CloudMarkFileUploadTypeEnum.java
  15. 10 0
      themis-business/src/main/java/com/qmth/themis/business/service/TEExamStudentService.java
  16. 10 0
      themis-business/src/main/java/com/qmth/themis/business/service/TOeExamRecordService.java
  17. 1 1
      themis-business/src/main/java/com/qmth/themis/business/service/impl/AuthInfoServiceImpl.java
  18. 13 0
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamStudentServiceImpl.java
  19. 1 1
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEOpenServiceImpl.java
  20. 3 6
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEStudentServiceImpl.java
  21. 13 0
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TOeExamRecordServiceImpl.java
  22. 4 4
      themis-business/src/main/java/com/qmth/themis/business/templete/TaskSyncCommon.java
  23. 16 5
      themis-business/src/main/java/com/qmth/themis/business/templete/impl/TaskPushCloudMarkTemplete.java
  24. 1 1
      themis-business/src/main/java/com/qmth/themis/business/templete/impl/TaskSyncCloudMarkTemplete.java
  25. 595 34
      themis-business/src/main/java/com/qmth/themis/business/templete/service/impl/TempleteLogicServiceImpl.java
  26. 27 0
      themis-business/src/main/resources/mapper/TEExamStudentMapper.xml
  27. 70 0
      themis-business/src/main/resources/mapper/TOeExamRecordMapper.xml
  28. 1 1
      themis-exam/src/main/java/com/qmth/themis/exam/api/TEStudentController.java
  29. 1 1
      themis-task/src/main/java/com/qmth/themis/task/quartz/service/impl/QuartzLogicServiceImpl.java
  30. 1 1
      themis-task/src/main/resources/application-dev.properties

+ 0 - 1
themis-admin/src/main/java/com/qmth/themis/admin/api/TBUserController.java

@@ -168,7 +168,6 @@ public class TBUserController {
         if (Objects.isNull(user)) {
             throw new BusinessException(ExceptionResultEnum.USER_NO);
         }
-        //todo 加入验证码校验逻辑
         return userLoginCommon(user);
     }
 

+ 1 - 5
themis-admin/src/main/java/com/qmth/themis/admin/api/TEExamActivityController.java

@@ -162,8 +162,6 @@ public class TEExamActivityController {
                 }
                 teAudio.updateInfo(tbUser.getId());
             }
-            //TODO 测试默认为false
-            teAudio.setEnable(false);
             teAudioService.saveOrUpdate(teAudio);
 //        teAudioService.sendAudioMessage(teAudio);
         } catch (Exception e) {
@@ -213,9 +211,7 @@ public class TEExamActivityController {
                     throw new BusinessException("已有考试记录不能禁用");
                 }
             }
-            //TODO 测试默认为false
-            teAudio.setEnable(false);
-//            teAudio.setEnable(!enable ? null : enable);
+            teAudio.setEnable(!enable ? null : enable);
             teAudio.updateInfo(tbUser.getId());
             teAudioService.updateById(teAudio);
 //            cacheService.updateExamAudioCache(teAudio.getId());

+ 110 - 164
themis-admin/src/main/java/com/qmth/themis/admin/api/TEExamController.java

@@ -560,72 +560,6 @@ public class TEExamController {
         return ResultUtil.ok(Collections.singletonMap(SystemConstant.TASK_ID, tbTaskHistory.getId()));
     }
 
-    @ApiOperation(value = "云阅卷成绩同步")
-    @ApiResponses({@ApiResponse(code = 200, message = "成绩同步信息", response = Result.class)})
-    @RequestMapping(value = "/cloud_mark/score/sync", method = RequestMethod.POST)
-    public Result scoreSync(@ApiParam(value = "考试ID", required = true) @RequestParam String examId,
-                            @ApiParam(value = "云阅卷考试id", required = true) @RequestParam String cloudMarkExamId) {
-        TBTaskHistory tbTaskHistory = null;
-        try {
-            ExamCacheBean examCacheBean = teExamService.getExamCacheBean(Long.parseLong(examId));
-            Optional.ofNullable(examCacheBean).orElseThrow(() -> new BusinessException(ExceptionResultEnum.EXAM_NO));
-            InvigilateMonitorStatusEnum invigilateMonitorStatusEnum = examCacheBean.getMonitorStatus();//监考状态
-            if (Objects.nonNull(invigilateMonitorStatusEnum) && !Objects
-                    .equals(invigilateMonitorStatusEnum, InvigilateMonitorStatusEnum.FINISHED)) {
-                throw new BusinessException("当前批次监考未结束,请在结束后操作");
-            }
-            ScoreStatusEnum scoreStatusEnum = examCacheBean.getScoreStatus();//算分状态
-            if (Objects.nonNull(scoreStatusEnum) && (Objects.equals(scoreStatusEnum, ScoreStatusEnum.CALCULATING) || Objects
-                    .equals(scoreStatusEnum, ScoreStatusEnum.NEED_CALCULATE))) {
-                throw new BusinessException("当前批次算分未结束,请在结束后操作");
-            }
-            QueryWrapper<TEExamCourse> teExamCourseQueryWrapper = new QueryWrapper<>();
-            teExamCourseQueryWrapper.lambda().eq(TEExamCourse::getExamId, examId);
-            List<TEExamCourse> teExamCourseList = teExamCourseService.list(teExamCourseQueryWrapper);
-            Set answerList = null;
-            if (Objects.nonNull(teExamCourseList) && teExamCourseList.size() > 0) {
-                answerList = teExamCourseList.stream().filter(s -> {
-                    if (Objects.nonNull(s.getHasAnswer()) && s.getHasAnswer().intValue() == 0) {
-                        return true;
-                    } else {
-                        return false;
-                    }
-                }).collect(Collectors.toSet());
-            }
-            if (Objects.nonNull(answerList) && answerList.size() > 0) {
-                throw new BusinessException("当前批次标答未补齐,请补齐后操作");
-            }
-
-            Map transMap = new HashMap();
-            TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
-            //往任务表里插一条数据
-            tbTaskHistory = new TBTaskHistory(TaskTypeEnum.CLOUD_MARK_SCORE_SYNC, TaskStatusEnum.INIT,
-                    SystemConstant.SCORE_PUSH_INIT, 0d, tbUser.getId(), tbUser.getOrgId());
-            tbTaskHistory.setExamId(Long.parseLong(examId));
-            taskHistoryService.save(tbTaskHistory);
-
-            transMap.put("tbTaskHistory", tbTaskHistory);
-            transMap.put(SystemConstant.CREATE_ID, tbUser.getId());
-            transMap.put(SystemConstant.ORG_ID, tbUser.getOrgId());
-            transMap.put(SystemConstant.EXAM_ID, Long.parseLong(examId));
-            transMap.put(SystemConstant.CLOUD_MARK_EXAM_ID, Long.parseLong(cloudMarkExamId));
-            transMap.put(SystemConstant.EXAM_CODE, examCacheBean.getCode());
-            //mq发送消息start
-            MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.CLOUD_MARK_SCORE_SYNC.name(),
-                    transMap, MqTagEnum.CLOUD_MARK_SCORE_SYNC, String.valueOf(tbTaskHistory.getId()),
-                    tbUser.getName());
-            mqDtoService.assembleSendOneWayMsg(mqDto);
-        } catch (Exception e) {
-            log.error(SystemConstant.LOG_ERROR, e);
-            if (e instanceof BusinessException) {
-                throw new BusinessException(e.getMessage());
-            } else {
-                throw new RuntimeException(e);
-            }
-        }
-        return ResultUtil.ok(Collections.singletonMap(SystemConstant.TASK_ID, tbTaskHistory.getId()));
-    }
-
     @ApiOperation(value = "推送云阅卷数据")
     @ApiResponses({@ApiResponse(code = 200, message = "成绩同步信息", response = Result.class)})
     @RequestMapping(value = "/cloud_mark/push/data", method = RequestMethod.POST)
@@ -663,11 +597,23 @@ public class TEExamController {
 
             Map transMap = new HashMap();
             TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
-            //往任务表里插一条数据
-            tbTaskHistory = new TBTaskHistory(TaskTypeEnum.CLOUD_MARK_DATA_PUSH, TaskStatusEnum.INIT,
-                    SystemConstant.DATA_PUSH_INIT, 0d, tbUser.getId(), tbUser.getOrgId());
-            tbTaskHistory.setExamId(Long.parseLong(examId));
-            taskHistoryService.save(tbTaskHistory);
+
+            if (Objects.nonNull(examCacheBean.getThirdExamId())) {
+                QueryWrapper<TBTaskHistory> tbTaskHistoryQueryWrapper = new QueryWrapper<>();
+                tbTaskHistoryQueryWrapper.lambda().eq(TBTaskHistory::getExamId, examCacheBean.getId())
+                        .eq(TBTaskHistory::getType, TaskTypeEnum.CLOUD_MARK_DATA_PUSH)
+                        .eq(TBTaskHistory::getEntityId, examCacheBean.getThirdExamId());
+                tbTaskHistory = taskHistoryService.getOne(tbTaskHistoryQueryWrapper);
+            }
+            if (Objects.isNull(tbTaskHistory)) {
+                //往任务表里插一条数据
+                tbTaskHistory = new TBTaskHistory(TaskTypeEnum.CLOUD_MARK_DATA_PUSH, TaskStatusEnum.INIT,
+                        SystemConstant.DATA_PUSH_INIT, 0d, tbUser.getId(), tbUser.getOrgId());
+                tbTaskHistory.setExamId(examCacheBean.getId());
+                taskHistoryService.save(tbTaskHistory);
+            } else if (tbTaskHistory.getStatus() == TaskStatusEnum.FINISH && (Objects.nonNull(tbTaskHistory.getProgress()) && tbTaskHistory.getProgress().doubleValue() == 100D)) {
+                throw new BusinessException("当前推送任务已完成");
+            }
 
             transMap.put("tbTaskHistory", tbTaskHistory);
             transMap.put(SystemConstant.CREATE_ID, tbUser.getId());
@@ -690,100 +636,100 @@ public class TEExamController {
         return ResultUtil.ok(Collections.singletonMap(SystemConstant.TASK_ID, tbTaskHistory.getId()));
     }
 
-    @Resource
-    CloudMarkUtil cloudMarkUtil;
-
-    @Resource
-    TEExamPaperService teExamPaperService;
-
-    @Resource
-    TEExamStudentService teExamStudentService;
-
-    @ApiOperation(value = "http测试发送接口")
-    @RequestMapping(value = "/http/test/send", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "常规信息", response = Result.class)})
-    public Result httpTestSend() throws IOException {
-        Long orgId = 240069373300576256L, examId = 307119709605072896L, paperId = 307120792277622784L,
-                examStudentId = 1574244332533293057L, examRecordId = 307148263382851584L;
-        TBOrg tbOrg = cacheService.addOrgCache(orgId);
-        ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examId);
-
-//        //测试考试
-//        SaveExamParams saveExamParams = new SaveExamParams(orgId, examCacheBean.getId(), examCacheBean.getName(), DateUtil.format(new Date(examCacheBean.getStartTime()), Constants.DEFAULT_DATE_PATTERN));
-//        cloudMarkUtil.callExamSaveApi(saveExamParams);
+//    @Resource
+//    CloudMarkUtil cloudMarkUtil;
 //
-//        //测试科目试卷
-//        ExamPaperCacheBean examPaperCacheBean = teExamPaperService.getExamPaperCacheBean(paperId);
-//        SaveSubjectParams saveSubjectParams = new SaveSubjectParams(orgId, examCacheBean.getId(), examPaperCacheBean.getCode(), examPaperCacheBean.getName());
-//        cloudMarkUtil.callSubjectSaveApi(saveSubjectParams);
+//    @Resource
+//    TEExamPaperService teExamPaperService;
 //
-//        //测试考生
-        ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(examStudentId);
-//        SaveStudentParams saveStudentParams = new SaveStudentParams(orgId, examId, String.valueOf(examRecordId),
-//                examStudentCacheBean.getIdentity(),
-//                examStudentCacheBean.getName(),
-//                tbOrg.getName(),
-//                examStudentCacheBean.getClassNo(), "#",
-//                examStudentCacheBean.getCourseCode(),
-//                examStudentCacheBean.getCourseName());
-//        cloudMarkUtil.callStudentSaveApi(saveStudentParams);
-
-//        //测试上传文件json
-//        File fileJson = new File("/Users/king/Downloads/41a9c68b71c9486db62de90980bd7e9a");
-//        FileUploadParams fileUploadParamsJson = new FileUploadParams(orgId, examId, String.valueOf(examRecordId), fileJson);
-//        fileUploadParamsJson.setFormat(CloudMarkFileUploadTypeEnum.JSON.getCode());
-//        cloudMarkUtil.callFileUploadApi(fileUploadParamsJson);
+//    @Resource
+//    TEExamStudentService teExamStudentService;
 //
-        File filePaper = new File("/Users/king/Downloads/1");
-        FileUploadParams fileUploadParamsPaper = new FileUploadParams(orgId, examId, examStudentCacheBean.getIdentity(), CloudMarkFileUploadTypeEnum.PAPER, filePaper);
-        cloudMarkUtil.callFileUploadApi(fileUploadParamsPaper);
-        return ResultUtil.ok(true);
-    }
-
-    @ApiOperation(value = "http测试考试接口")
-    @RequestMapping(value = "/http/test/save", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "常规信息", response = Result.class)})
-    public Result httpTestApiExamSave(@ApiParam(value = "接收数据信息", required = true) @RequestBody String result) throws UnsupportedEncodingException {
-        Optional.ofNullable(result).orElseThrow(() -> new BusinessException("数据为空"));
-        String decodeJson = URLDecoder.decode(result, SystemConstant.CHARSET_NAME);
-        log.info("httpTestApiExamSave,result:{}", decodeJson);
-        return ResultUtil.ok(Collections.singletonMap("id", 1L));
-    }
-
-    @ApiOperation(value = "http测试科目接口")
-    @RequestMapping(value = "/http/test/subject/save", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "常规信息", response = Result.class)})
-    public Result httpTestApiSubjectSave(@ApiParam(value = "接收数据信息", required = true) @RequestBody String result) throws UnsupportedEncodingException {
-        Optional.ofNullable(result).orElseThrow(() -> new BusinessException("数据为空"));
-        String decodeJson = URLDecoder.decode(result, SystemConstant.CHARSET_NAME);
-        log.info("httpTestApiSubjectSave,result:{}", JacksonUtil.parseJson(decodeJson));
-        return ResultUtil.ok(Collections.singletonMap("updateTime", DateUtil.format(new Date(), Constants.DEFAULT_DATE_PATTERN)));
-    }
-
-    @ApiOperation(value = "http测试考生接口")
-    @RequestMapping(value = "/http/test/student/save", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "常规信息", response = Result.class)})
-    public Result httpTestApiStudentSave(@ApiParam(value = "接收数据信息", required = true) @RequestBody String result) throws UnsupportedEncodingException {
-        Optional.ofNullable(result).orElseThrow(() -> new BusinessException("数据为空"));
-        String decodeJson = URLDecoder.decode(result, SystemConstant.CHARSET_NAME);
-        log.info("httpTestApiStudentSave,result:{}", decodeJson);
-        return ResultUtil.ok(Collections.singletonMap("updateTime", DateUtil.format(new Date(), Constants.DEFAULT_DATE_PATTERN)));
-    }
-
-    @ApiOperation(value = "http测试文件接口")
-    @RequestMapping(value = "/http/test/file/{type}/upload", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "常规信息", response = Result.class)})
-    public Result httpTestFileUpload(@PathVariable("type") String type,
-                                     @ApiParam(value = "考试id", required = true) @RequestParam Long examId,
-                                     @ApiParam(value = "准考证号") @RequestParam(required = false) String examNumber,
-                                     @ApiParam(value = "科目编码") @RequestParam(required = false) String subjectCode,
-                                     @ApiParam(value = "格式") @RequestParam(required = false) String format,
-                                     @ApiParam(value = "文件", required = true) @RequestParam MultipartFile file,
-                                     @ApiParam(value = "文件md5", required = true) @RequestParam String md5) throws IOException {
-        if (Objects.nonNull(file)) {
-            File fileNew = new File("/Users/king/Downloads/41a9c68b71c9486db62de90980bd7e9a-new");
-            IOUtils.copy(file.getInputStream(), new FileOutputStream(fileNew));
-        }
-        return ResultUtil.ok(Collections.singletonMap("success", true));
-    }
+//    @ApiOperation(value = "http测试发送接口")
+//    @RequestMapping(value = "/http/test/send", method = RequestMethod.POST)
+//    @ApiResponses({@ApiResponse(code = 200, message = "常规信息", response = Result.class)})
+//    public Result httpTestSend() throws IOException {
+//        Long orgId = 240069373300576256L, examId = 307119709605072896L, paperId = 307120792277622784L,
+//                examStudentId = 1574244332533293057L, examRecordId = 307148263382851584L;
+//        TBOrg tbOrg = cacheService.addOrgCache(orgId);
+//        ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examId);
+//
+////        //测试考试
+////        SaveExamParams saveExamParams = new SaveExamParams(orgId, examCacheBean.getId(), examCacheBean.getName(), DateUtil.format(new Date(examCacheBean.getStartTime()), Constants.DEFAULT_DATE_PATTERN));
+////        cloudMarkUtil.callExamSaveApi(saveExamParams);
+////
+////        //测试科目试卷
+////        ExamPaperCacheBean examPaperCacheBean = teExamPaperService.getExamPaperCacheBean(paperId);
+////        SaveSubjectParams saveSubjectParams = new SaveSubjectParams(orgId, examCacheBean.getId(), examPaperCacheBean.getCode(), examPaperCacheBean.getName());
+////        cloudMarkUtil.callSubjectSaveApi(saveSubjectParams);
+////
+////        //测试考生
+//        ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(examStudentId);
+////        SaveStudentParams saveStudentParams = new SaveStudentParams(orgId, examId, String.valueOf(examRecordId),
+////                examStudentCacheBean.getIdentity(),
+////                examStudentCacheBean.getName(),
+////                tbOrg.getName(),
+////                examStudentCacheBean.getClassNo(), "#",
+////                examStudentCacheBean.getCourseCode(),
+////                examStudentCacheBean.getCourseName());
+////        cloudMarkUtil.callStudentSaveApi(saveStudentParams);
+//
+////        //测试上传文件json
+////        File fileJson = new File("/Users/king/Downloads/41a9c68b71c9486db62de90980bd7e9a");
+////        FileUploadParams fileUploadParamsJson = new FileUploadParams(orgId, examId, String.valueOf(examRecordId), fileJson);
+////        fileUploadParamsJson.setFormat(CloudMarkFileUploadTypeEnum.JSON.getCode());
+////        cloudMarkUtil.callFileUploadApi(fileUploadParamsJson);
+////
+//        File filePaper = new File("/Users/king/Downloads/1");
+//        FileUploadParams fileUploadParamsPaper = new FileUploadParams(orgId, examId, examStudentCacheBean.getIdentity(), CloudMarkFileUploadTypeEnum.PAPER, filePaper);
+//        cloudMarkUtil.callFileUploadApi(fileUploadParamsPaper);
+//        return ResultUtil.ok(true);
+//    }
+//
+//    @ApiOperation(value = "http测试考试接口")
+//    @RequestMapping(value = "/http/test/save", method = RequestMethod.POST)
+//    @ApiResponses({@ApiResponse(code = 200, message = "常规信息", response = Result.class)})
+//    public Result httpTestApiExamSave(@ApiParam(value = "接收数据信息", required = true) @RequestBody String result) throws UnsupportedEncodingException {
+//        Optional.ofNullable(result).orElseThrow(() -> new BusinessException("数据为空"));
+//        String decodeJson = URLDecoder.decode(result, SystemConstant.CHARSET_NAME);
+//        log.info("httpTestApiExamSave,result:{}", decodeJson);
+//        return ResultUtil.ok(Collections.singletonMap("id", 1L));
+//    }
+//
+//    @ApiOperation(value = "http测试科目接口")
+//    @RequestMapping(value = "/http/test/subject/save", method = RequestMethod.POST)
+//    @ApiResponses({@ApiResponse(code = 200, message = "常规信息", response = Result.class)})
+//    public Result httpTestApiSubjectSave(@ApiParam(value = "接收数据信息", required = true) @RequestBody String result) throws UnsupportedEncodingException {
+//        Optional.ofNullable(result).orElseThrow(() -> new BusinessException("数据为空"));
+//        String decodeJson = URLDecoder.decode(result, SystemConstant.CHARSET_NAME);
+//        log.info("httpTestApiSubjectSave,result:{}", JacksonUtil.parseJson(decodeJson));
+//        return ResultUtil.ok(Collections.singletonMap("updateTime", DateUtil.format(new Date(), Constants.DEFAULT_DATE_PATTERN)));
+//    }
+//
+//    @ApiOperation(value = "http测试考生接口")
+//    @RequestMapping(value = "/http/test/student/save", method = RequestMethod.POST)
+//    @ApiResponses({@ApiResponse(code = 200, message = "常规信息", response = Result.class)})
+//    public Result httpTestApiStudentSave(@ApiParam(value = "接收数据信息", required = true) @RequestBody String result) throws UnsupportedEncodingException {
+//        Optional.ofNullable(result).orElseThrow(() -> new BusinessException("数据为空"));
+//        String decodeJson = URLDecoder.decode(result, SystemConstant.CHARSET_NAME);
+//        log.info("httpTestApiStudentSave,result:{}", decodeJson);
+//        return ResultUtil.ok(Collections.singletonMap("updateTime", DateUtil.format(new Date(), Constants.DEFAULT_DATE_PATTERN)));
+//    }
+//
+//    @ApiOperation(value = "http测试文件接口")
+//    @RequestMapping(value = "/http/test/file/{type}/upload", method = RequestMethod.POST)
+//    @ApiResponses({@ApiResponse(code = 200, message = "常规信息", response = Result.class)})
+//    public Result httpTestFileUpload(@PathVariable("type") String type,
+//                                     @ApiParam(value = "考试id", required = true) @RequestParam Long examId,
+//                                     @ApiParam(value = "准考证号") @RequestParam(required = false) String examNumber,
+//                                     @ApiParam(value = "科目编码") @RequestParam(required = false) String subjectCode,
+//                                     @ApiParam(value = "格式") @RequestParam(required = false) String format,
+//                                     @ApiParam(value = "文件", required = true) @RequestParam MultipartFile file,
+//                                     @ApiParam(value = "文件md5", required = true) @RequestParam String md5) throws IOException {
+//        if (Objects.nonNull(file)) {
+//            File fileNew = new File("/Users/king/Downloads/41a9c68b71c9486db62de90980bd7e9a-new");
+//            IOUtils.copy(file.getInputStream(), new FileOutputStream(fileNew));
+//        }
+//        return ResultUtil.ok(Collections.singletonMap("success", true));
+//    }
 }

+ 66 - 0
themis-admin/src/main/java/com/qmth/themis/admin/api/TEExamStudentController.java

@@ -581,4 +581,70 @@ public class TEExamStudentController {
             throw new BusinessException("当前批次标答未补齐,请补齐后操作");
         }
     }
+
+    @ApiOperation(value = "云阅卷成绩同步")
+    @ApiResponses({@ApiResponse(code = 200, message = "成绩同步信息", response = Result.class)})
+    @RequestMapping(value = "/cloud_mark/score/sync", method = RequestMethod.POST)
+    public Result scoreSync(@ApiParam(value = "考试ID", required = true) @RequestParam String examId,
+                            @ApiParam(value = "云阅卷考试id", required = true) @RequestParam String cloudMarkExamId) {
+        TBTaskHistory tbTaskHistory = null;
+        try {
+            ExamCacheBean examCacheBean = teExamService.getExamCacheBean(Long.parseLong(examId));
+            Optional.ofNullable(examCacheBean).orElseThrow(() -> new BusinessException(ExceptionResultEnum.EXAM_NO));
+            InvigilateMonitorStatusEnum invigilateMonitorStatusEnum = examCacheBean.getMonitorStatus();//监考状态
+            if (Objects.nonNull(invigilateMonitorStatusEnum) && !Objects
+                    .equals(invigilateMonitorStatusEnum, InvigilateMonitorStatusEnum.FINISHED)) {
+                throw new BusinessException("当前批次监考未结束,请在结束后操作");
+            }
+            ScoreStatusEnum scoreStatusEnum = examCacheBean.getScoreStatus();//算分状态
+            if (Objects.nonNull(scoreStatusEnum) && (Objects.equals(scoreStatusEnum, ScoreStatusEnum.CALCULATING) || Objects
+                    .equals(scoreStatusEnum, ScoreStatusEnum.NEED_CALCULATE))) {
+                throw new BusinessException("当前批次算分未结束,请在结束后操作");
+            }
+            QueryWrapper<TEExamCourse> teExamCourseQueryWrapper = new QueryWrapper<>();
+            teExamCourseQueryWrapper.lambda().eq(TEExamCourse::getExamId, examId);
+            List<TEExamCourse> teExamCourseList = teExamCourseService.list(teExamCourseQueryWrapper);
+            Set answerList = null;
+            if (Objects.nonNull(teExamCourseList) && teExamCourseList.size() > 0) {
+                answerList = teExamCourseList.stream().filter(s -> {
+                    if (Objects.nonNull(s.getHasAnswer()) && s.getHasAnswer().intValue() == 0) {
+                        return true;
+                    } else {
+                        return false;
+                    }
+                }).collect(Collectors.toSet());
+            }
+            if (Objects.nonNull(answerList) && answerList.size() > 0) {
+                throw new BusinessException("当前批次标答未补齐,请补齐后操作");
+            }
+
+            Map transMap = new HashMap();
+            TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
+            //往任务表里插一条数据
+            tbTaskHistory = new TBTaskHistory(TaskTypeEnum.CLOUD_MARK_SCORE_SYNC, TaskStatusEnum.INIT,
+                    SystemConstant.SCORE_PUSH_INIT, 0d, tbUser.getId(), tbUser.getOrgId());
+            tbTaskHistory.setExamId(Long.parseLong(examId));
+            taskHistoryService.save(tbTaskHistory);
+
+            transMap.put("tbTaskHistory", tbTaskHistory);
+            transMap.put(SystemConstant.CREATE_ID, tbUser.getId());
+            transMap.put(SystemConstant.ORG_ID, tbUser.getOrgId());
+            transMap.put(SystemConstant.EXAM_ID, Long.parseLong(examId));
+            transMap.put(SystemConstant.CLOUD_MARK_EXAM_ID, Long.parseLong(cloudMarkExamId));
+            transMap.put(SystemConstant.EXAM_CODE, examCacheBean.getCode());
+            //mq发送消息start
+            MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.CLOUD_MARK_SCORE_SYNC.name(),
+                    transMap, MqTagEnum.CLOUD_MARK_SCORE_SYNC, String.valueOf(tbTaskHistory.getId()),
+                    tbUser.getName());
+            mqDtoService.assembleSendOneWayMsg(mqDto);
+        } catch (Exception e) {
+            log.error(SystemConstant.LOG_ERROR, e);
+            if (e instanceof BusinessException) {
+                throw new BusinessException(e.getMessage());
+            } else {
+                throw new RuntimeException(e);
+            }
+        }
+        return ResultUtil.ok(Collections.singletonMap(SystemConstant.TASK_ID, tbTaskHistory.getId()));
+    }
 }

+ 5 - 3
themis-admin/src/main/resources/application-dev.properties

@@ -21,7 +21,7 @@ spring.application.name=themis-admin
 #\u6570\u636E\u6E90\u914D\u7F6E
 db.host=localhost
 db.port=3306
-db.name=themis_v1.1
+db.name=themis_release
 db.username=root
 db.password=123456789
 #redis\u6570\u636E\u6E90\u914D\u7F6E
@@ -229,5 +229,7 @@ com.qmth.solar.access-key=8134f6aae0134770b8618913705d3667
 com.qmth.solar.access-secret=s1NENpvc8Jq5evcE0B7GfLmoQOvwmlCy
 
 #\u65E0\u9700\u9274\u6743\u7684url
-no.auth.urls=/webjars/**,/druid/**,/swagger-ui.html,/doc.html,/swagger-resources/**,/v2/api-docs,/webjars/springfox-swagger-ui/**,/api/admin/user/login/account,/api/admin/sys/org/queryByOrgCode,/file/**,/upload/**,/client/**,/base_photo/**,/frontend/**,/api/admin/client/save,/api/admin/client/upload,/api/admin/client/query,/api/admin/app/save,/api/admin/app/query,/api/notify/monitor/record/tencent,/api/notify/monitor/status/tencent,/api/admin/exam/http/test/send,/api/admin/exam/http/test/save,/api/admin/exam/http/test/student/score,/api/admin/exam/http/test/subject/save,/api/admin/exam/http/test/student/save,/api/admin/exam/http/test/file/{type}/upload
-common.system.urls=/api/admin/sys/getMenu,/api/admin/user/logout,/api/admin/sys/env,/api/admin/sys/file/upload,/api/admin/sys/file/download,/api/admin/sys/org/query,/api/admin/sys/role/query,/api/admin/sys/examActivity/query,/api/admin/sys/exam/query,/api/admin/sys/examRoom/query,/api/admin/sys/exam/privilegeQuery,/api/admin/student/photo/upload,/api/admin/sys/getPlayUrls,/api/admin/sys/exam/finish/query,/api/admin/sys/get_tencent_video
+#no.auth.urls=/webjars/**,/druid/**,/swagger-ui.html,/doc.html,/swagger-resources/**,/v2/api-docs,/webjars/springfox-swagger-ui/**,/api/admin/user/login/account,/api/admin/sys/org/queryByOrgCode,/file/**,/upload/**,/client/**,/base_photo/**,/frontend/**,/api/admin/client/save,/api/admin/client/upload,/api/admin/client/query,/api/admin/app/save,/api/admin/app/query,/api/notify/monitor/record/tencent,/api/notify/monitor/status/tencent,/api/admin/exam/http/test/send,/api/admin/exam/http/test/save,/api/admin/exam/http/test/student/score,/api/admin/exam/http/test/subject/save,/api/admin/exam/http/test/student/save,/api/admin/exam/http/test/file/{type}/upload
+#common.system.urls=/api/admin/sys/getMenu,/api/admin/user/logout,/api/admin/sys/env,/api/admin/sys/file/upload,/api/admin/sys/file/download,/api/admin/sys/org/query,/api/admin/sys/role/query,/api/admin/sys/examActivity/query,/api/admin/sys/exam/query,/api/admin/sys/examRoom/query,/api/admin/sys/exam/privilegeQuery,/api/admin/student/photo/upload,/api/admin/sys/getPlayUrls,/api/admin/sys/exam/finish/query,/api/admin/sys/get_tencent_video,/api/admin/exam/cloud_mark/push/data,/api/admin/examStudent/cloud_mark/score/sync
+no.auth.urls=/webjars/**,/druid/**,/swagger-ui.html,/doc.html,/swagger-resources/**,/v2/api-docs,/webjars/springfox-swagger-ui/**,/api/admin/user/login/account,/api/admin/sys/org/queryByOrgCode,/file/**,/upload/**,/client/**,/base_photo/**,/frontend/**,/api/admin/client/save,/api/admin/client/upload,/api/admin/client/query,/api/admin/app/save,/api/admin/app/query,/api/notify/monitor/record/tencent,/api/notify/monitor/status/tencent
+common.system.urls=/api/admin/sys/getMenu,/api/admin/user/logout,/api/admin/sys/env,/api/admin/sys/file/upload,/api/admin/sys/file/download,/api/admin/sys/org/query,/api/admin/sys/role/query,/api/admin/sys/examActivity/query,/api/admin/sys/exam/query,/api/admin/sys/examRoom/query,/api/admin/sys/exam/privilegeQuery,/api/admin/student/photo/upload,/api/admin/sys/getPlayUrls,/api/admin/sys/exam/finish/query,/api/admin/sys/get_tencent_video

+ 6 - 4
themis-business/src/main/java/com/qmth/themis/business/bean/cloudmark/SaveExamParams.java

@@ -45,15 +45,17 @@ public class SaveExamParams extends BaseParams implements Serializable {
         this.examTime = examTime;
     }
 
-
-    public SaveExamParams(Long orgId, Long id, String code) {
+    public SaveExamParams(Long orgId, Long id, String code, String name, String examTime) {
         super(orgId, null, null);
         this.id = id;
+        this.name = name;
         this.code = code;
+        this.examTime = examTime;
     }
 
-    public SaveExamParams(Long orgId, Long id, String code, String accessKey, String accessSecret) {
-        super(orgId, accessKey, accessSecret);
+
+    public SaveExamParams(Long orgId, Long id, String code) {
+        super(orgId, null, null);
         this.id = id;
         this.code = code;
     }

+ 23 - 0
themis-business/src/main/java/com/qmth/themis/business/cache/bean/ExamCacheBean.java

@@ -3,6 +3,7 @@ package com.qmth.themis.business.cache.bean;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
 import com.qmth.themis.business.enums.*;
+import io.swagger.annotations.ApiModelProperty;
 
 import java.io.Serializable;
 import java.util.Objects;
@@ -167,6 +168,28 @@ public class ExamCacheBean implements Serializable {
     //考试过程中是否启用真实性检测,0:不启用,1:启用
     private Integer inProcessRealnessVerify;
 
+    @ApiModelProperty(value = "扫描时间")
+    private Long scanTime;
+
+    @ApiModelProperty(value = "第三方考试id")
+    private String thirdExamId;
+
+    public Long getScanTime() {
+        return scanTime;
+    }
+
+    public void setScanTime(Long scanTime) {
+        this.scanTime = scanTime;
+    }
+
+    public String getThirdExamId() {
+        return thirdExamId;
+    }
+
+    public void setThirdExamId(String thirdExamId) {
+        this.thirdExamId = thirdExamId;
+    }
+
     public Integer getInProcessRealnessVerify() {
         return inProcessRealnessVerify;
     }

+ 2 - 3
themis-business/src/main/java/com/qmth/themis/business/constant/SystemConstant.java

@@ -65,9 +65,6 @@ public class SystemConstant {
     public static final String END_POINT = "endpoint";
 
     public static final String ACCESS_KEY_ID = "accessKeyId";
-    public static final String ACCESS_KEY = "accessKey";
-
-    public static final String ACCESS_SECRET = "accessSecret";
 
     public static final String ACCESS_KEY_SECRET = "accessKeySecret";
 
@@ -95,6 +92,8 @@ public class SystemConstant {
     /**
      * 系统相关
      */
+    public static final String JOINT_MARK = "_";
+    public static final String VALUE_OF_BLANK_REQUIRED_FIELD = "#";
     public static final String MULTI_MEDIA = "MULTI_MEDIA";
     public static final String FILE_UPLOAD_VARIABLE_URL = "\\{type\\}";
     public static final String CLOUD_MARK_EXAM_ID = "cloudMarkExamId";

+ 10 - 0
themis-business/src/main/java/com/qmth/themis/business/dao/TEExamStudentMapper.java

@@ -15,6 +15,7 @@ import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * @Description: 考生库 Mapper 接口
@@ -108,4 +109,13 @@ public interface TEExamStudentMapper extends CustomBaseMapper<TEExamStudent> {
 
     public List<TEExamStudentDto> findExamStudentNeedMark(@Param("examId") Long examId, @Param("courseCode") String courseCode,
                                                           @Param("idGt") Long idGt, @Param("count") Integer count);
+
+    /**
+     * 获取所有待阅卷的考生
+     *
+     * @param examId
+     * @param examPaperIdSet
+     * @return
+     */
+    public List<TEExamStudent> findExamStudentNeedMarkAll(@Param("examId") Long examId, @Param("examPaperIdSet") Set<Long> examPaperIdSet);
 }

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

@@ -530,4 +530,14 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @return
      */
     public Integer findByExamIdOrExamActivityIdCount(@Param("examId") Long examId, @Param("examActivityId") Long examActivityId);
+
+    /**
+     * 获取所有待阅卷的考试记录
+     *
+     * @param examId
+     * @param examPaperIdSet
+     * @param many
+     * @return
+     */
+    public List<TOeExamRecord> findExamRecordNeedMarkAll(@Param("examId") Long examId, @Param("examPaperIdSet") Set<Long> examPaperIdSet, @Param("many") Boolean many);
 }

+ 11 - 0
themis-business/src/main/java/com/qmth/themis/business/entity/TBTaskHistory.java

@@ -93,6 +93,9 @@ public class TBTaskHistory implements Serializable {
     @ApiModelProperty(value = "机构id")
     private Long orgId;
 
+    @ApiModelProperty(value = "备注")
+    private String remark;
+
     public TBTaskHistory() {
 
     }
@@ -124,6 +127,14 @@ public class TBTaskHistory implements Serializable {
         this.orgId = orgId;
     }
 
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
     public Long getOrgId() {
         return orgId;
     }

+ 10 - 12
themis-business/src/main/java/com/qmth/themis/business/entity/TEAudio.java

@@ -86,18 +86,16 @@ public class TEAudio extends BaseEntity implements Serializable {
         this.audioDefault = audioDefault;
         this.playTime = playTime;
         setCreateId(userId);
-//        if (Objects.nonNull(teExam.getForceFinish()) && teExam.getForceFinish().intValue() == 1
-//                && Objects.nonNull(teExam.getEnable()) && teExam.getEnable() == 1
-//                && Objects.nonNull(teExamActivity.getEnable()) && teExamActivity.getEnable() == 1
-//                && Objects.nonNull(teExam.getMonitorRecord())
-//                && (teExam.getMonitorRecord().contains(MonitorVideoSourceEnum.MOBILE_FIRST.name())
-//                || teExam.getMonitorRecord().contains(MonitorVideoSourceEnum.MOBILE_SECOND.name()))) {
-//            this.enable = true;
-//        } else {
-//            this.enable = false;
-//        }
-        //TODO 测试默认为false
-        this.enable = false;
+        if (Objects.nonNull(teExam.getForceFinish()) && teExam.getForceFinish().intValue() == 1
+                && Objects.nonNull(teExam.getEnable()) && teExam.getEnable() == 1
+                && Objects.nonNull(teExamActivity.getEnable()) && teExamActivity.getEnable() == 1
+                && Objects.nonNull(teExam.getMonitorRecord())
+                && (teExam.getMonitorRecord().contains(MonitorVideoSourceEnum.MOBILE_FIRST.name())
+                || teExam.getMonitorRecord().contains(MonitorVideoSourceEnum.MOBILE_SECOND.name()))) {
+            this.enable = true;
+        } else {
+            this.enable = false;
+        }
     }
 
     public void insertInfo(Long userId) {

+ 1 - 0
themis-business/src/main/java/com/qmth/themis/business/entity/TEExam.java

@@ -204,6 +204,7 @@ public class TEExam extends BaseEntity {
     private Long scanTime;
 
     @ApiModelProperty(value = "第三方考试id")
+    @TableField(value = "third_exam_id", updateStrategy = FieldStrategy.IGNORED)
     private String thirdExamId;
 
     public TEExam() {

+ 2 - 0
themis-business/src/main/java/com/qmth/themis/business/enums/CloudMarkFileUploadTypeEnum.java

@@ -15,6 +15,8 @@ public enum CloudMarkFileUploadTypeEnum {
 
     PAPER("paper"),
 
+    ANSWER("answer"),
+
     PDF("pdf");
 
     private String code;

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

@@ -11,6 +11,7 @@ import com.qmth.themis.business.entity.TEExamStudent;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * @Description: 考生库 服务类
@@ -92,4 +93,13 @@ public interface TEExamStudentService extends IService<TEExamStudent> {
     public IPage<MarkResultSimpleExportDto> markResultQueryExportIpage(IPage<Map> iPage, Long examId, Long examActivityId, String identity, String name, String courseCode);
 
     public List<TEExamStudentDto> findExamStudentNeedMark(Long examId, String courseCode, Long idGt, Integer count);
+
+    /**
+     * 获取所有待阅卷的考生
+     *
+     * @param examId
+     * @param examPaperIdSet
+     * @return
+     */
+    public List<TEExamStudent> findExamStudentNeedMarkAll(Long examId, Set<Long> examPaperIdSet);
 }

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

@@ -521,4 +521,14 @@ public interface TOeExamRecordService extends IService<TOeExamRecord> {
      * @return
      */
     public Integer findByExamIdOrExamActivityIdCount(Long examId, Long examActivityId);
+
+    /**
+     * 获取所有待阅卷的考试记录
+     *
+     * @param examId
+     * @param examPaperIdSet
+     * @param many
+     * @return
+     */
+    public List<TOeExamRecord> findExamRecordNeedMarkAll(Long examId, Set<Long> examPaperIdSet, Boolean many);
 }

+ 1 - 1
themis-business/src/main/java/com/qmth/themis/business/service/impl/AuthInfoServiceImpl.java

@@ -121,7 +121,7 @@ public class AuthInfoServiceImpl implements AuthInfoService {
         if (Objects.nonNull(code)) {
             AuthOrgInfoDto authOrgInfoDto = cacheService.authInfoCache(code);
             if (Objects.isNull(authOrgInfoDto) || (Objects.nonNull(authOrgInfoDto) && authOrgInfoDto.getControl().hasExpired())) {
-                throw new BusinessException(ExceptionResultEnum.AUTH_INFO_ERROR);
+//                throw new BusinessException(ExceptionResultEnum.AUTH_INFO_ERROR);
             }
         }
     }

+ 13 - 0
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamStudentServiceImpl.java

@@ -20,6 +20,7 @@ import org.springframework.transaction.annotation.Transactional;
 import javax.annotation.Resource;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * @Description: 考生库 服务实现类
@@ -183,4 +184,16 @@ public class TEExamStudentServiceImpl extends ServiceImpl<TEExamStudentMapper, T
     public List<TEExamStudentDto> findExamStudentNeedMark(Long examId, String courseCode, Long idGt, Integer count) {
         return teExamStudentMapper.findExamStudentNeedMark(examId, courseCode, idGt, count);
     }
+
+    /**
+     * 获取所有待阅卷的考生
+     *
+     * @param examId
+     * @param examPaperIdSet
+     * @return
+     */
+    @Override
+    public List<TEExamStudent> findExamStudentNeedMarkAll(Long examId, Set<Long> examPaperIdSet) {
+        return teExamStudentMapper.findExamStudentNeedMarkAll(examId, examPaperIdSet);
+    }
 }

+ 1 - 1
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEOpenServiceImpl.java

@@ -187,7 +187,7 @@ public class TEOpenServiceImpl implements TEOpenService {
         if (exam == null) {
             throw new BusinessException("未找到考试信息");
         }
-        if (exam.getEnable() == null || exam.getEnable() == 0) {
+        if (exam.getEnable() == null || exam.getEnable().intValue() == 0) {
             throw new BusinessException("考试批次已禁用");
         }
         if (!InvigilateMonitorStatusEnum.FINISHED.equals(exam.getMonitorStatus())) {

+ 3 - 6
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEStudentServiceImpl.java

@@ -165,14 +165,11 @@ public class TEStudentServiceImpl extends ServiceImpl<TEStudentMapper, TEStudent
     @Override
     public TEStudentExamRecordVideoDto examRecordVideoQuery(IPage<Map> iPage, Long examRecordId, MonitorVideoSourceEnum monitorRecord, Boolean log) {
         TOeExamRecord tOeExamRecord = SystemConstant.getExamRecord(examRecordId);
-        ExamCacheBean examCacheBean = null;
-        ExamStudentCacheBean examStudentCacheBean = null;
-
         List<TEExamStudentLog> teExamStudentLogList = null;
-        if (Objects.nonNull(log) && log) {
-            examCacheBean = teExamService.getExamCacheBean(tOeExamRecord.getExamId());
-            examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(tOeExamRecord.getExamStudentId());
+        ExamCacheBean examCacheBean = teExamService.getExamCacheBean(tOeExamRecord.getExamId());
+        ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(tOeExamRecord.getExamStudentId());
 
+        if (Objects.nonNull(log) && log) {
             QueryWrapper<TEExamStudentLog> teExamStudentLogQueryWrapper = new QueryWrapper<>();
             teExamStudentLogQueryWrapper.lambda().eq(TEExamStudentLog::getExamStudentId, examStudentCacheBean.getId())
                     .eq(TEExamStudentLog::getExamRecordId, examRecordId)

+ 13 - 0
themis-business/src/main/java/com/qmth/themis/business/service/impl/TOeExamRecordServiceImpl.java

@@ -1450,6 +1450,19 @@ public class TOeExamRecordServiceImpl extends ServiceImpl<TOeExamRecordMapper, T
         return tOeExamRecordMapper.findByExamIdOrExamActivityIdCount(examId, examActivityId);
     }
 
+    /**
+     * 获取所有待阅卷的考试记录
+     *
+     * @param examId
+     * @param examPaperIdSet
+     * @param many
+     * @return
+     */
+    @Override
+    public List<TOeExamRecord> findExamRecordNeedMarkAll(Long examId, Set<Long> examPaperIdSet, Boolean many) {
+        return tOeExamRecordMapper.findExamRecordNeedMarkAll(examId, examPaperIdSet, many);
+    }
+
     /**
      * 取最高分
      *

+ 4 - 4
themis-business/src/main/java/com/qmth/themis/business/templete/TaskSyncCommon.java

@@ -129,14 +129,14 @@ public class TaskSyncCommon {
      * 异常处理
      *
      * @param e
+     * @param message
      * @param txtList
      * @return
      */
-    public List<String> exception(Exception e, List<String> txtList) {
+    public List<String> exception(Exception e, String message, List<String> txtList) {
         this.exception = true;
-        String exceptionStr = "数据同步时发生异常,请联系系统管理员处理!";
-        txtList.add(DateUtil.format(new Date(), Constants.DEFAULT_DATE_PATTERN) + "->" + exceptionStr + "错误信息:[" + e.getMessage() + "]");
-        this.tbTaskHistory.setSummary(exceptionStr);
+        txtList.add(DateUtil.format(new Date(), Constants.DEFAULT_DATE_PATTERN) + "->" + message + "错误信息:[" + e.getMessage() + "]");
+        this.tbTaskHistory.setSummary(txtList.toString());
         this.tbTaskHistory.setStatus(TaskStatusEnum.FINISH);
         return txtList;
     }

+ 16 - 5
themis-business/src/main/java/com/qmth/themis/business/templete/impl/TaskPushCloudMarkTemplete.java

@@ -12,15 +12,13 @@ import com.qmth.themis.common.util.ResultUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
 
 import javax.annotation.Resource;
 import java.io.File;
 import java.io.IOException;
 import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.Map;
-import java.util.StringJoiner;
+import java.util.*;
 
 /**
  * @Description: 推送云阅卷数据
@@ -70,10 +68,23 @@ public class TaskPushCloudMarkTemplete implements TaskSyncTemplete {
             log.info("推送云阅卷数据结束,============耗时============:{}秒", (end - start) / 1000);
         } catch (Exception e) {
             log.error("推送云阅卷数据报错", e);
-            taskSyncCommon.exception(e, taskSyncCommon.getTxtList());
+            taskSyncCommon.exception(e, "推送数据时发生异常,请联系系统管理员处理!", taskSyncCommon.getTxtList());
         } finally {
             //这里写入txt文件
             taskSyncCommon.writeSyncResultTxt(stringJoiner.toString(), taskSyncCommon.getTxtList().toString());
+            List<File> paperJsonList = null, recordJsonList = null;
+            paperJsonList = (List<File>) map.get("paperJsonList");
+            if (!CollectionUtils.isEmpty(paperJsonList)) {
+                for (File f : paperJsonList) {
+                    f.delete();
+                }
+            }
+            recordJsonList = (List<File>) map.get("recordJsonList");
+            if (!CollectionUtils.isEmpty(recordJsonList)) {
+                for (File f : recordJsonList) {
+                    f.delete();
+                }
+            }
         }
         return ResultUtil.ok(true);
     }

+ 1 - 1
themis-business/src/main/java/com/qmth/themis/business/templete/impl/TaskSyncCloudMarkTemplete.java

@@ -110,7 +110,7 @@ public class TaskSyncCloudMarkTemplete implements TaskSyncTemplete {
             log.info("同步云阅卷成绩数据结束,============耗时============:{}秒", (end - start) / 1000);
         } catch (Exception e) {
             log.error("同步云阅卷成绩数据报错", e);
-            taskSyncCommon.exception(e, taskSyncCommon.getTxtList());
+            taskSyncCommon.exception(e, "数据同步时发生异常,请联系系统管理员处理!", taskSyncCommon.getTxtList());
         } finally {
             //这里写入txt文件
             taskSyncCommon.writeSyncResultTxt(stringJoiner.toString(), taskSyncCommon.getTxtList().toString());

+ 595 - 34
themis-business/src/main/java/com/qmth/themis/business/templete/service/impl/TempleteLogicServiceImpl.java

@@ -1,39 +1,56 @@
 package com.qmth.themis.business.templete.service.impl;
 
 import cn.hutool.core.date.DateUtil;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.google.common.reflect.TypeToken;
 import com.google.gson.Gson;
-import com.qmth.themis.business.bean.cloudmark.SaveExamParams;
-import com.qmth.themis.business.bean.cloudmark.SaveStudentParams;
-import com.qmth.themis.business.bean.cloudmark.SaveSubjectParams;
+import com.qmth.themis.business.bean.admin.OpenRecordAnswerBean;
+import com.qmth.themis.business.bean.admin.OpenRecordAnswerStructBean;
+import com.qmth.themis.business.bean.admin.OpenRecordAnswerTempBean;
+import com.qmth.themis.business.bean.admin.OpenRecordNeedMarkBean;
+import com.qmth.themis.business.bean.cloudmark.FileUploadParams;
+import com.qmth.themis.business.cache.RedisKeyHelper;
 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.constant.SystemConstant;
 import com.qmth.themis.business.dao.TEExamCourseMapper;
 import com.qmth.themis.business.dto.ExamStudentImportDto;
 import com.qmth.themis.business.dto.RoomCodeImportDto;
 import com.qmth.themis.business.entity.*;
+import com.qmth.themis.business.enums.CloudMarkFileUploadTypeEnum;
 import com.qmth.themis.business.enums.ExamModeEnum;
 import com.qmth.themis.business.enums.RoleEnum;
 import com.qmth.themis.business.enums.TaskStatusEnum;
 import com.qmth.themis.business.service.*;
 import com.qmth.themis.business.templete.service.TempleteLogicService;
 import com.qmth.themis.business.util.CloudMarkUtil;
+import com.qmth.themis.business.util.JacksonUtil;
+import com.qmth.themis.business.util.OssUtil;
 import com.qmth.themis.common.contanst.Constants;
 import com.qmth.themis.common.enums.ExceptionResultEnum;
 import com.qmth.themis.common.exception.BusinessException;
 import com.qmth.themis.common.util.Base64Util;
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.LinkedMultiValueMap;
 
 import javax.annotation.Resource;
+import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.math.BigDecimal;
+import java.nio.charset.StandardCharsets;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 /**
@@ -45,6 +62,7 @@ import java.util.stream.Collectors;
  */
 @Service
 public class TempleteLogicServiceImpl implements TempleteLogicService {
+    private final static Logger log = LoggerFactory.getLogger(TempleteLogicServiceImpl.class);
 
     @Resource
     TEExamStudentService teExamStudentService;
@@ -76,6 +94,24 @@ public class TempleteLogicServiceImpl implements TempleteLogicService {
     @Resource
     TEExamService teExamService;
 
+    @Resource
+    TEExamPaperService teExamPaperService;
+
+    @Resource
+    CacheService cacheService;
+
+    @Resource
+    TOeExamRecordService tOeExamRecordService;
+
+    @Resource
+    TBTaskHistoryService tbTaskHistoryService;
+
+    @Resource
+    OssUtil ossUtil;
+
+    @Resource
+    TOeExamAnswerService examAnswerService;
+
     /**
      * 考生导入逻辑
      *
@@ -370,61 +406,586 @@ public class TempleteLogicServiceImpl implements TempleteLogicService {
      * @return
      */
     @Override
-    @Transactional
     public Map<String, Object> execPushCloudMarkDataLogic(Map<String, Object> map) throws IOException {
+        checkData(map);
+        Long examId = (Long) map.get(SystemConstant.EXAM_ID);
+//        Long orgId = (Long) map.get(SystemConstant.ORG_ID);
+//        String examCode = (String) map.get(SystemConstant.EXAM_CODE);
+
+        //先推送考试
+        ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examId);
+        TBTaskHistory tbTaskHistory = (TBTaskHistory) map.get("tbTaskHistory");
+        JSONObject jsonObject = Objects.nonNull(tbTaskHistory.getRemark()) ? JSONObject.parseObject(tbTaskHistory.getRemark()) : null;
+        Integer totalTaskSize = 1, currentTaskSize = 1, jsTotalTaskSize = 0, jsCurrentTaskSize = 0;
+        Long cloudMarkExamId = null;
+
+        TEExam teExam = teExamService.cacheConvert(examCacheBean);
+        if (Objects.isNull(tbTaskHistory.getEntityId())) {
+//          cloudMarkExamId = cloudMarkUtil.callExamSaveApi(new SaveExamParams(orgId, examId, examCode, examCacheBean.getName(), DateUtil.format(new Date(examCacheBean.getStartTime()), Constants.DEFAULT_DATE_PATTERN)));
+            cloudMarkExamId = Long.parseLong((int) (Math.random() * 1000) + "");
+            teExam.setUpdateTime(System.currentTimeMillis());
+            teExam.setThirdExamId(String.valueOf(cloudMarkExamId));
+            teExamService.updateById(teExam);
+            teExamService.updateExamCacheBean(examId);
+        } else {
+            cloudMarkExamId = tbTaskHistory.getEntityId();
+        }
+        if (Objects.nonNull(cloudMarkExamId)) {
+            if (Objects.isNull(jsonObject)) {
+                jsonObject = new JSONObject();
+                jsonObject.put("examSize", 1);
+                jsonObject.put("totalTaskSize", totalTaskSize);
+                jsonObject.put("currentTaskSize", currentTaskSize);
+                tbTaskHistory.setEntityId(cloudMarkExamId);
+                tbTaskHistory.setRemark(jsonObject.toJSONString());
+            } else {
+                jsTotalTaskSize = jsonObject.getInteger("totalTaskSize");
+                jsCurrentTaskSize = jsonObject.getInteger("currentTaskSize");
+                tbTaskHistory.setStatus(TaskStatusEnum.RUNNING);
+            }
+            tbTaskHistoryService.updateById(tbTaskHistory);
+
+            //推送试卷科目
+            Set<Long> examPaperIdSet = pushExamPaperLogic(map, jsonObject, totalTaskSize, jsCurrentTaskSize, currentTaskSize, cloudMarkExamId);
+
+            //获取所有待阅卷的考生
+            List<TEExamStudent> teExamStudentList = getExamStudentNeedMarkAll(map, jsonObject, teExam, examPaperIdSet, jsTotalTaskSize, jsCurrentTaskSize);
+
+            //获取只有一次考试记录的考生
+            List<TOeExamRecord> tOeExamRecordList = getExamRecordOnce(map, jsonObject, examPaperIdSet);
+
+            //获取多次考试记录的考试
+            List<TOeExamRecord> tOeExamRecordManyList = tOeExamRecordService.findExamRecordNeedMarkAll(examId, examPaperIdSet, true);
+            if (!CollectionUtils.isEmpty(tOeExamRecordManyList)) {
+                Set<Long> manyExamStudentIdSet = tOeExamRecordManyList.stream().map(s -> s.getExamStudentId()).collect(Collectors.toSet());
+                jsonObject.put("examRecordManyListSize", manyExamStudentIdSet.size());
+                tbTaskHistory.setRemark(jsonObject.toJSONString());
+                tbTaskHistoryService.updateById(tbTaskHistory);
+                if (teExamStudentList.size() != tOeExamRecordList.size() + manyExamStudentIdSet.size()) {
+                    throw new BusinessException("待阅卷的考试记录和考生数不匹配");
+                }
+                List<TOeExamRecord> resultExamRecordList = filterManyExamRecord(tOeExamRecordManyList, teExam);
+                tOeExamRecordList.addAll(resultExamRecordList);
+                //推送多次考试记录的考生
+            } else {
+                if (teExamStudentList.size() != tOeExamRecordList.size()) {
+                    throw new BusinessException("待阅卷的考试记录和考生数不匹配");
+                }
+            }
+
+            //推送考试记录的考生开始
+            pushExamStudentLogic(map,
+                    jsonObject,
+                    teExamStudentList,
+                    tOeExamRecordList,
+                    jsCurrentTaskSize,
+                    cloudMarkExamId);
+        }
+        return pushDataSuccess(map, jsonObject);
+    }
+
+    /**
+     * 推送数据成功
+     *
+     * @param map
+     * @param jsonObject
+     * @return
+     */
+    private Map<String, Object> pushDataSuccess(Map<String, Object> map,
+                                                JSONObject jsonObject) {
+        TBTaskHistory tbTaskHistory = (TBTaskHistory) map.get("tbTaskHistory");
+        List<String> txtList = (List<String>) map.get("txtList");
+        StringJoiner stringJoiner = new StringJoiner("");
+        stringJoiner.add("推送数据成功:共推送了").add(String.valueOf(jsonObject.getInteger("examSize"))).add("个考试,")
+                .add(String.valueOf(jsonObject.getInteger("examPaperSize"))).add("个试卷科目,")
+                .add(String.valueOf(jsonObject.getInteger("examExamStudentSize"))).add("个考生");
+        txtList.add(DateUtil.format(new Date(), Constants.DEFAULT_DATE_PATTERN) + "->" + stringJoiner.toString());
+
+        tbTaskHistory.setSummary(txtList.toString());
+        tbTaskHistory.setStatus(TaskStatusEnum.FINISH);
+        tbTaskHistory.setFinishTime(System.currentTimeMillis());
+        tbTaskHistoryService.updateById(tbTaskHistory);
+        return map;
+    }
+
+    /**
+     * 获取只有一次考试记录的考生
+     *
+     * @param map
+     * @param jsonObject
+     * @param examPaperIdSet
+     * @return
+     */
+    private List<TOeExamRecord> getExamRecordOnce(Map<String, Object> map,
+                                                  JSONObject jsonObject,
+                                                  Set<Long> examPaperIdSet) {
+        Long examId = (Long) map.get(SystemConstant.EXAM_ID);
+        TBTaskHistory tbTaskHistory = (TBTaskHistory) map.get("tbTaskHistory");
+        List<TOeExamRecord> tOeExamRecordList = tOeExamRecordService.findExamRecordNeedMarkAll(examId, examPaperIdSet, false);
+        if (CollectionUtils.isEmpty(tOeExamRecordList)) {
+            throw new BusinessException("没有待阅卷的考试记录");
+        }
+        jsonObject.put("examRecordListSize", tOeExamRecordList.size());
+
+        Integer totalTaskSize = jsonObject.getInteger("totalTaskSize");
+        Integer currentTaskSize = jsonObject.getInteger("currentTaskSize");
+
+        BigDecimal progress = new BigDecimal(0);
+        BigDecimal b = new BigDecimal(100);
+        progress = new BigDecimal(currentTaskSize).divide(new BigDecimal(totalTaskSize), 2, BigDecimal.ROUND_HALF_UP).multiply(b);
+        if (Objects.isNull(tbTaskHistory.getProgress()) || (Objects.nonNull(tbTaskHistory.getProgress()) && tbTaskHistory.getProgress().doubleValue() < progress.doubleValue())) {
+            tbTaskHistory.setProgress(progress.doubleValue());
+            tbTaskHistoryService.updateById(tbTaskHistory);
+        }
+        tbTaskHistory.setRemark(jsonObject.toJSONString());
+        return tOeExamRecordList;
+    }
+
+    /**
+     * 获取所有待阅卷的考生
+     *
+     * @param map
+     * @param jsonObject
+     * @param teExam
+     * @param examPaperIdSet
+     * @param jsTotalTaskSize
+     * @param jsCurrentTaskSize
+     * @return
+     */
+    private List<TEExamStudent> getExamStudentNeedMarkAll(Map<String, Object> map,
+                                                          JSONObject jsonObject,
+                                                          TEExam teExam,
+                                                          Set<Long> examPaperIdSet,
+                                                          Integer jsTotalTaskSize,
+                                                          Integer jsCurrentTaskSize) {
+        Long examId = (Long) map.get(SystemConstant.EXAM_ID);
+        TBTaskHistory tbTaskHistory = (TBTaskHistory) map.get("tbTaskHistory");
+        List<TEExamStudent> teExamStudentList = teExamStudentService.findExamStudentNeedMarkAll(examId, examPaperIdSet);
+        if (CollectionUtils.isEmpty(teExamStudentList)) {
+            throw new BusinessException("没有待阅卷的考生");
+        }
+        Integer totalTaskSize = jsonObject.getInteger("totalTaskSize");
+        Integer currentTaskSize = jsonObject.getInteger("currentTaskSize");
+        totalTaskSize = totalTaskSize.intValue() + teExamStudentList.size();
+        if (jsCurrentTaskSize.intValue() > currentTaskSize.intValue() && jsTotalTaskSize.intValue() > 0 && jsTotalTaskSize.intValue() != totalTaskSize.intValue()) {
+            teExam.setUpdateTime(System.currentTimeMillis());
+            teExam.setThirdExamId(null);
+            teExamService.updateById(teExam);
+            teExamService.updateExamCacheBean(examId);
+            throw new BusinessException("数据已发生改变,需重新推送");
+        }
+        jsonObject.put("examExamStudentSize", teExamStudentList.size());
+        jsonObject.put("totalTaskSize", totalTaskSize);
+        tbTaskHistory.setRemark(jsonObject.toJSONString());
+        return teExamStudentList;
+    }
+
+    /**
+     * 推送考生和考试记录逻辑
+     *
+     * @param map
+     * @param jsonObject
+     * @param teExamStudentList
+     * @param tOeExamRecordList
+     * @param jsCurrentTaskSize
+     * @param cloudMarkExamId
+     */
+    private void pushExamStudentLogic(Map<String, Object> map,
+                                      JSONObject jsonObject,
+                                      List<TEExamStudent> teExamStudentList,
+                                      List<TOeExamRecord> tOeExamRecordList,
+                                      Integer jsCurrentTaskSize,
+                                      Long cloudMarkExamId) throws IOException {
+        Long orgId = (Long) map.get(SystemConstant.ORG_ID);
+        TBTaskHistory tbTaskHistory = (TBTaskHistory) map.get("tbTaskHistory");
+        BigDecimal progress = new BigDecimal(0);
+        BigDecimal b = new BigDecimal(100);
+        TBOrg tbOrg = cacheService.addOrgCache(orgId);
+
+        Integer totalTaskSize = jsonObject.getInteger("totalTaskSize");
+        Integer currentTaskSize = jsonObject.getInteger("currentTaskSize");
+
+        Map<Long, TOeExamRecord> tOeExamRecordMap = tOeExamRecordList.stream().collect(
+                Collectors.toMap(TOeExamRecord::getExamStudentId, Function.identity(), (dto1, dto2) -> dto1));
+
+        Map<Long, Map<String, Integer>> paperStructMap = new HashMap<>();
+        List<File> recordJsonList = new ArrayList<>(teExamStudentList.size());
+        map.put("recordJsonList", recordJsonList);
+        //推送考试记录的考生
+        int min = 0;
+        int max = SystemConstant.MAX_IMPORT_SIZE, size = teExamStudentList.size();
+        if (max >= size) {
+            max = size;
+        }
+        while (max <= size) {
+            List<TEExamStudent> subList = teExamStudentList.subList(min, max);
+            for (int y = 0; y < subList.size(); y++) {
+//                if (y == 300) {
+//                    int k = 1 / 0;
+//                }
+                TEExamStudent t = subList.get(y);
+                if (jsCurrentTaskSize.intValue() > 0 && currentTaskSize.intValue() < jsCurrentTaskSize.intValue()) {
+                    jsonObject.put("currentTaskSize", currentTaskSize);
+                    currentTaskSize++;
+                    tbTaskHistory.setRemark(jsonObject.toJSONString());
+                    continue;
+                } else {
+//                    cloudMarkUtil.callStudentSaveApi(new SaveStudentParams(orgId, cloudMarkExamId, SystemConstant.VALUE_OF_BLANK_REQUIRED_FIELD,
+//                            t.getIdentity(),
+//                            t.getName(),
+//                            tbOrg.getName(),
+//                            t.getClassNo(), SystemConstant.VALUE_OF_BLANK_REQUIRED_FIELD,
+//                            t.getCourseCode(),
+//                            t.getCourseName()));
+                    TOeExamRecord tOeExamRecord = tOeExamRecordMap.get(t.getId());
+//                    if (Objects.isNull(tOeExamRecord)) {
+//                        continue;
+//                    }
+                    Optional.ofNullable(tOeExamRecord).orElseThrow(() -> new BusinessException(ExceptionResultEnum.NOT_FOUND_EXAM_RECORD));
+
+                    Gson gson = new Gson();
+                    OpenRecordNeedMarkBean openRecordNeedMarkBean = gson.fromJson(gson.toJson(tOeExamRecord), OpenRecordNeedMarkBean.class);
+                    List<OpenRecordAnswerTempBean> answersTemp = examAnswerService.findByExamRecordId(tOeExamRecord.getId());
+                    List<OpenRecordAnswerBean> answers = new ArrayList<>(answersTemp.size());
+                    List<OpenRecordAnswerBean> finalAnswers = answers;
+                    answersTemp.forEach(s -> {
+                        OpenRecordAnswerBean openRecordAnswerBean = new OpenRecordAnswerBean(s.getMainNumber(), s.getSubNumber(), s.getSubIndex());
+                        try {
+                            openRecordAnswerBean.setAnswer(gson.fromJson(s.getAnswer(), new TypeToken<List<OpenRecordAnswerStructBean>>() {
+                            }.getType()));
+                        } catch (Exception e) {
+                            log.error("错误答案:{}", s.getAnswer(), e);
+                        }
+                        finalAnswers.add(openRecordAnswerBean);
+                    });
+                    openRecordNeedMarkBean.setAnswers(answers.stream().filter(answer -> {
+                        Map<String, Integer> struct = paperStructMap.get(tOeExamRecord.getPaperId());
+                        if (struct == null) {
+                            struct = teExamPaperService.getPaperStructCacheBean(tOeExamRecord.getPaperId());
+                            if (struct != null) {
+                                paperStructMap.put(tOeExamRecord.getPaperId(), struct);
+                            } else {
+                                log.error("找不到对应的试卷结构,paperId=" + tOeExamRecord.getPaperId());
+                                return false;
+                            }
+                        }
+                        Integer type = struct.get(RedisKeyHelper
+                                .examAnswerHashKey(answer.getMainNumber(), answer.getSubNumber(),
+                                        answer.getSubIndex()));
+                        //过滤单选、多选、判断题
+                        return type != null && type != 1 && type != 2 && type != 3;
+                    }).collect(Collectors.toList()));
+
+                    File fileAnswerJson = new File(SystemConstant.TEMP_FILES_DIR + File.separator + CloudMarkFileUploadTypeEnum.ANSWER.getCode() + File.separator + SystemConstant.getUuid() + ".json");
+                    if (!fileAnswerJson.exists()) {
+                        fileAnswerJson.getParentFile().mkdirs();
+                        fileAnswerJson.createNewFile();
+                    }
+                    IOUtils.write(JacksonUtil.parseJson(openRecordNeedMarkBean).getBytes(SystemConstant.CHARSET_NAME), new FileOutputStream(fileAnswerJson));
+                    recordJsonList.add(fileAnswerJson);
+                    FileUploadParams fileUploadParamsAnswerJson = new FileUploadParams(orgId, cloudMarkExamId, String.valueOf(tOeExamRecord.getId()), fileAnswerJson);
+//                    cloudMarkUtil.callFileUploadApi(fileUploadParamsAnswerJson);
+
+                    jsonObject.put("currentTaskSize", currentTaskSize);
+                    currentTaskSize++;
+                    tbTaskHistory.setRemark(jsonObject.toJSONString());
+                }
+            }
+            progress = new BigDecimal(currentTaskSize).divide(new BigDecimal(totalTaskSize), 2, BigDecimal.ROUND_HALF_UP).multiply(b);
+            if (Objects.isNull(tbTaskHistory.getProgress()) || (Objects.nonNull(tbTaskHistory.getProgress()) && tbTaskHistory.getProgress().doubleValue() < progress.doubleValue())) {
+                tbTaskHistory.setProgress(progress.doubleValue());
+                tbTaskHistoryService.updateById(tbTaskHistory);
+            }
+            if (max == size) {
+                break;
+            }
+            min = max;
+            max += SystemConstant.MAX_IMPORT_SIZE;
+            if (max >= size) {
+                max = size;
+            }
+        }
+        jsonObject.put("currentTaskSize", currentTaskSize);
+        tbTaskHistory.setRemark(jsonObject.toJSONString());
+    }
+
+    /**
+     * 过滤多条考试记录的考生
+     *
+     * @param tOeExamRecordManyList
+     * @param teExam
+     * @return
+     */
+    private List<TOeExamRecord> filterManyExamRecord(List<TOeExamRecord> tOeExamRecordManyList, TEExam teExam) {
+        List<TOeExamRecord> result = null;
+        LinkedMultiValueMap<Long, TOeExamRecord> tOeExamRecordLinkedMultiValueMap = new LinkedMultiValueMap<>();
+        for (TOeExamRecord bean : tOeExamRecordManyList) {
+            tOeExamRecordLinkedMultiValueMap.add(bean.getExamStudentId(), bean);
+        }
+        if (!CollectionUtils.isEmpty(tOeExamRecordLinkedMultiValueMap)) {
+            result = new ArrayList<>();
+            List<TOeExamRecord> finalResult = result;
+            tOeExamRecordLinkedMultiValueMap.forEach((k, v) -> {
+                double highestObjectiveScore = 0.0;
+                long maxFinishTime = 0L;
+                boolean subjective = false;
+                List<TOeExamRecord> tempResult = new ArrayList<>(v.size());
+                for (TOeExamRecord bean : v) {
+                    //获取对应的试卷信息
+                    ExamPaperCacheBean paper = teExamPaperService.getExamPaperCacheBean(bean.getPaperId());
+                    if (Objects.isNull(paper)) {
+                        log.error("找不到对应的试卷信息, paperId=" + bean.getPaperId());
+                        continue;
+                    }
+                    //根据试卷结构过滤没有主观题的情况
+                    if (paper.getTotalSubjectiveScore().doubleValue() == 0D) {
+                        subjective = true;
+                        maxFinishTime = Math.max(maxFinishTime, bean.getFinishTime());
+                        continue;
+                    }
+                    highestObjectiveScore = Math.max(highestObjectiveScore, bean.getObjectiveScore());
+                    maxFinishTime = Math.max(maxFinishTime, bean.getFinishTime());
+                    tempResult.add(bean);
+                }
+                if (tempResult.isEmpty()) {
+                    return;
+                }
+                switch (teExam.getRecordSelectStrategy()) {
+                    case HIGHEST_OBJECTIVE_SCORE:
+                        if (subjective) {
+                            final long time = maxFinishTime;
+                            finalResult.addAll(v.stream().filter(bean -> bean.getFinishTime() == time).collect(Collectors.toList()));
+                        } else {
+                            //客观分最高,客观分相同则全部提交阅卷
+                            final double score = highestObjectiveScore;
+                            finalResult.addAll(tempResult.stream().filter(bean -> bean.getObjectiveScore() == score).collect(Collectors.toList()));
+                        }
+                        break;
+                    case LATEST:
+                        //最后一次提交
+                        final long time = maxFinishTime;
+                        finalResult.addAll(tempResult.stream().filter(bean -> bean.getFinishTime() == time).collect(Collectors.toList()));
+                        break;
+                    default:
+                        //总分最高,全部提交阅卷
+                        finalResult.addAll(tempResult);
+                        break;
+                }
+            });
+        }
+        return result;
+    }
+
+    /**
+     * 推送试卷逻辑
+     *
+     * @param map
+     * @param jsonObject
+     * @param totalTaskSize
+     * @param jsCurrentTaskSize
+     * @param currentTaskSize
+     * @param cloudMarkExamId
+     * @return
+     * @throws IOException
+     */
+    private Set<Long> pushExamPaperLogic(Map<String, Object> map,
+                                         JSONObject jsonObject,
+                                         Integer totalTaskSize,
+                                         Integer jsCurrentTaskSize,
+                                         Integer currentTaskSize,
+                                         Long cloudMarkExamId) throws IOException {
+        Long examId = (Long) map.get(SystemConstant.EXAM_ID);
+        Long orgId = (Long) map.get(SystemConstant.ORG_ID);
+        TBTaskHistory tbTaskHistory = (TBTaskHistory) map.get("tbTaskHistory");
+        List<File> paperJsonList = null;
+
+        QueryWrapper<TEExamPaper> teExamPaperQueryWrapper = new QueryWrapper<>();
+        teExamPaperQueryWrapper.lambda().eq(TEExamPaper::getExamId, examId)
+                .gt(TEExamPaper::getTotalSubjectiveScore, 0).orderByAsc(TEExamPaper::getId);
+        List<TEExamPaper> teExamPaperList = teExamPaperService.list(teExamPaperQueryWrapper);
+        if (CollectionUtils.isEmpty(teExamPaperList)) {
+            throw new BusinessException("没有考试试卷");
+        }
+        totalTaskSize = totalTaskSize.intValue() + teExamPaperList.size();
+        jsonObject.put("totalTaskSize", totalTaskSize);
+        jsonObject.put("examPaperSize", teExamPaperList.size());
+        tbTaskHistory.setRemark(jsonObject.toJSONString());
+        Set<Long> examPaperIdSet = new HashSet<>(teExamPaperList.size());
+
+        if (!CollectionUtils.isEmpty(teExamPaperList)) {
+            paperJsonList = new ArrayList<>(teExamPaperList.size());
+            map.put("paperJsonList", paperJsonList);
+            for (int i = 0; i < teExamPaperList.size(); i++) {
+//                if (i == 10) {
+//                    int y = 1 / 0;
+//                }
+                TEExamPaper t = teExamPaperList.get(i);
+                examPaperIdSet.add(t.getId());
+                if (jsCurrentTaskSize.intValue() > 0 && currentTaskSize.intValue() < jsCurrentTaskSize.intValue()) {
+                    jsonObject.put("currentTaskSize", currentTaskSize);
+                    currentTaskSize++;
+                    tbTaskHistory.setRemark(jsonObject.toJSONString());
+                    continue;
+                } else {
+                    String courseCode = t.getCourseCode() + SystemConstant.JOINT_MARK + t.getId();
+//                    cloudMarkUtil.callSubjectSaveApi(new SaveSubjectParams(orgId, cloudMarkExamId, courseCode, t.getName()));
+                    //解析试卷JSON文件
+                    JSONObject paperResult = JSONObject.parseObject(new String(ossUtil.download(false, t.getPaperViewPath()), StandardCharsets.UTF_8));
+                    paperResult.put(SystemConstant.ID, t.getId());
+                    paperResult.put("code", t.getCode());
+                    paperResult.put(SystemConstant.NAME, t.getName());
+                    if (Objects.nonNull(t.getAnswerPath())) {
+                        JSONArray detailCollection = new JSONArray();
+                        JSONArray paperDetails = paperResult.getJSONArray("details");
+                        //解析答案JSON文件
+                        JSONObject answerJson = JSONObject.parseObject(new String(ossUtil.download(false, t.getAnswerPath()), StandardCharsets.UTF_8));
+                        JSONArray answerDetails = answerJson.getJSONArray("details");
+                        for (int j = 0; j < paperDetails.size(); j++) {
+                            //遍历所有大题
+                            JSONObject paperDetail = paperDetails.getJSONObject(j);
+                            JSONObject answerDetail = findJsonObject(answerDetails, paperDetail.getIntValue("number"));
+                            //按条件过滤需要的小题同时合并答案
+                            JSONArray questionCollection = filterQuestions(paperDetail.getJSONArray("questions"),
+                                    Objects.nonNull(answerDetail) ? answerDetail.getJSONArray("questions") : null, true,
+                                    true);
+                            //有小题的情况下,本大题才需要被包含
+                            if (questionCollection.size() > 0) {
+                                paperDetail.put("questions", questionCollection);
+                                detailCollection.add(paperDetail);
+                            }
+                        }
+                        paperResult.put("details", detailCollection);
+                    }
+
+                    File filePaperJson = new File(SystemConstant.TEMP_FILES_DIR + File.separator + CloudMarkFileUploadTypeEnum.PAPER.getCode() + File.separator + SystemConstant.getUuid() + ".json");
+                    if (!filePaperJson.exists()) {
+                        filePaperJson.getParentFile().mkdirs();
+                        filePaperJson.createNewFile();
+                    }
+                    IOUtils.write(paperResult.toJSONString().getBytes(SystemConstant.CHARSET_NAME), new FileOutputStream(filePaperJson));
+                    paperJsonList.add(filePaperJson);
+                    FileUploadParams fileUploadParamsPaperJson = new FileUploadParams(orgId, cloudMarkExamId, courseCode, CloudMarkFileUploadTypeEnum.PAPER, filePaperJson);
+                    fileUploadParamsPaperJson.setFormat(CloudMarkFileUploadTypeEnum.JSON.getCode());
+//                    cloudMarkUtil.callFileUploadApi(fileUploadParamsPaperJson);
+
+                    jsonObject.put("currentTaskSize", currentTaskSize);
+                    currentTaskSize++;
+                    tbTaskHistory.setRemark(jsonObject.toJSONString());
+                }
+            }
+            jsonObject.put("currentTaskSize", currentTaskSize);
+            tbTaskHistory.setRemark(jsonObject.toJSONString());
+            tbTaskHistoryService.updateById(tbTaskHistory);
+        }
+        return examPaperIdSet;
+    }
+
+    /**
+     * 数据检查
+     *
+     * @param map
+     */
+    private void checkData(Map<String, Object> map) {
         Long examId = (Long) map.get(SystemConstant.EXAM_ID);
         if (Objects.isNull(examId)) {
             throw new RuntimeException("考试id为空");
         }
         Long orgId = (Long) map.get(SystemConstant.ORG_ID);
         if (Objects.isNull(orgId)) {
-            throw new RuntimeException("机构id为空");
+            throw new BusinessException("机构id为空");
         }
         String examCode = (String) map.get(SystemConstant.EXAM_CODE);
         if (Objects.isNull(examCode)) {
             throw new RuntimeException("考试编码为空");
         }
-        Long createId = (Long) map.get(SystemConstant.CREATE_ID);
-        createId = Objects.isNull(createId) ? -1L : createId;
+        TBOrg tbOrg = cacheService.addOrgCache(orgId);
+        Optional.ofNullable(tbOrg).orElseThrow(() -> new BusinessException(ExceptionResultEnum.ORG_NO));
 
         //先推送考试
         ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examId);
         Optional.ofNullable(examCacheBean).orElseThrow(() -> new BusinessException(ExceptionResultEnum.EXAM_NO));
 
-        int line = 0;
-        SaveExamParams saveExamParams = new SaveExamParams(orgId, examId, examCode);
-        Long cloudMarkExamId = cloudMarkUtil.callExamSaveApi(saveExamParams);
-        if (Objects.nonNull(cloudMarkExamId)) {
-            line++;
-            TEExam teExam = teExamService.cacheConvert(examCacheBean);
-            teExam.setUpdateTime(System.currentTimeMillis());
-            teExam.setThirdExamId(String.valueOf(cloudMarkExamId));
-            teExamService.updateById(teExam);
+        if (Objects.isNull(examCacheBean.getEnable()) || examCacheBean.getEnable().intValue() == 0) {
+            throw new BusinessException("考试批次已禁用");
+        }
+    }
 
-            //推送科目
-            QueryWrapper<TEExamCourse> teExamCourseQueryWrapper = new QueryWrapper<>();
-            teExamCourseQueryWrapper.lambda().eq(TEExamCourse::getExamId, examId);
-            List<TEExamCourse> teExamCourseList = teExamCourseService.list(teExamCourseQueryWrapper);
-            if (!CollectionUtils.isEmpty(teExamCourseList)) {
-                for (TEExamCourse t : teExamCourseList) {
-                    line++;
-                    cloudMarkUtil.callSubjectSaveApi(new SaveSubjectParams(orgId, cloudMarkExamId, t.getCourseCode(), t.getCourseName()));
+    /**
+     * 过滤答案
+     *
+     * @param array
+     * @param number
+     * @return
+     */
+    private JSONObject findJsonObject(JSONArray array, int number) {
+        if (array != null) {
+            for (int i = 0; i < array.size(); i++) {
+                JSONObject item = array.getJSONObject(i);
+                if (item.getIntValue("number") == number) {
+                    return item;
                 }
             }
+        }
+        return null;
+    }
 
-            //推送考生
-            QueryWrapper<TEExamStudent> teExamStudentQueryWrapper = new QueryWrapper<>();
-            teExamStudentQueryWrapper.lambda().eq(TEExamStudent::getExamId, examId);
-            List<TEExamStudent> teExamStudentList = teExamStudentService.list(teExamStudentQueryWrapper);
-            if (!CollectionUtils.isEmpty(teExamStudentList)) {
-                for (TEExamStudent t : teExamStudentList) {
-                    line++;
-//                    cloudMarkUtil.callStudentSaveApi(new SaveStudentParams(orgId, cloudMarkExamId, t.getCourseCode(), t.getCourseName()));
+    /**
+     * 过滤题目
+     *
+     * @param questions
+     * @param answers
+     * @param acceptObjective
+     * @param acceptSubjective
+     * @return
+     */
+    private JSONArray filterQuestions(JSONArray questions, JSONArray answers, boolean acceptObjective,
+                                      boolean acceptSubjective) {
+        JSONArray collection = new JSONArray();
+        for (int i = 0; i < questions.size(); i++) {
+            JSONObject question = questions.getJSONObject(i);
+            //根据题号查找答案
+            JSONObject answer = findJsonObject(answers, question.getIntValue("number"));
+            boolean accept = true;
+            //判断结构类型
+            switch (question.getIntValue("structType")) {
+                case 1:
+                    //单选
+                case 2:
+                    //多选
+                case 3:
+                    //判断
+                    accept = acceptObjective;
+                    break;
+                case 4:
+                    //填空
+                case 5:
+                    //问答
+                    accept = acceptSubjective;
+                    break;
+                case 6:
+                    //套题
+                    //按条件过滤套题下所有子题
+                    JSONArray subAnswers = answer != null ? answer.getJSONArray("subQuestions") : null;
+                    JSONArray subCollection = filterQuestions(question.getJSONArray("subQuestions"), subAnswers,
+                            acceptObjective, acceptSubjective);
+                    //没有子题,则本题也被过滤掉
+                    if (subCollection.size() > 0) {
+                        question.put("subQuestions", subCollection);
+                    } else {
+                        accept = false;
+                    }
+                    break;
+                default:
+                    accept = false;
+            }
+            if (accept) {
+                if (answer != null) {
+                    question.put("answer", answer.get("answer"));
                 }
+                collection.add(question);
             }
         }
-        map.put("line", line);
-        return map;
+        return collection;
     }
 
     /**

+ 27 - 0
themis-business/src/main/resources/mapper/TEExamStudentMapper.xml

@@ -476,4 +476,31 @@
         order by tees.id
         limit #{count}
     </select>
+
+    <select id="findExamStudentNeedMarkAll" resultType="com.qmth.themis.business.entity.TEExamStudent">
+        select tees.* from t_e_exam_student tees
+            join t_oe_exam_record toer
+                on toer.exam_id = tees.exam_id
+                and toer.exam_activity_id = tees.exam_activity_id
+                and toer.exam_student_id = tees.id
+        <where>
+            <if test="examId != null and examId != ''">
+                and tees.exam_id = #{examId}
+            </if>
+          and tees.enable = 1
+          and tees.already_exam_count is not null
+          and tees.already_exam_count <![CDATA[ > ]]> 0
+            <if test="examPaperIdSet != null and examPaperIdSet != '' and examPaperIdSet.size > 0">
+                and toer.paper_id in
+                <foreach collection="examPaperIdSet" item="paperId" index="index" open="(" close=")" separator=",">
+                    #{paperId}
+                </foreach>
+            </if>
+          and (toer.status = 'FINISHED' or toer.status = 'PERSISTED')
+          and toer.first_start_time is not null
+          and toer.finish_time is not null
+          and (toer.breach_status is null or toer.breach_status = 1) order by tees.id
+            <!--limit 510-->
+        </where>
+    </select>
 </mapper>

+ 70 - 0
themis-business/src/main/resources/mapper/TOeExamRecordMapper.xml

@@ -1732,4 +1732,74 @@
                 or toer.status = 'RESUME_PREPARE')
         </where>
     </select>
+
+    <select id="findExamRecordNeedMarkAll" resultType="com.qmth.themis.business.entity.TOeExamRecord">
+        select
+            t1.*
+        from
+            (
+                select
+                    t.exam_student_id
+                from
+                    t_oe_exam_record t
+                where
+                    exists(
+                            select
+                                tees.id
+                            from
+                                t_e_exam_student tees
+                                    join t_oe_exam_record toer on
+                                            toer.exam_id = tees.exam_id
+                                        and toer.exam_activity_id = tees.exam_activity_id
+                                        and toer.exam_student_id = tees.id
+                              <where>
+                                  <if test="examId != null and examId != ''">
+                                      and tees.exam_id = #{examId}
+                                  </if>
+                              and tees.enable = 1
+                              and tees.already_exam_count is not null
+                              and tees.already_exam_count <![CDATA[ > ]]> 0
+                              <if test="examPaperIdSet != null and examPaperIdSet != '' and examPaperIdSet.size > 0">
+                                  and toer.paper_id in
+                                  <foreach collection="examPaperIdSet" item="paperId" index="index" open="(" close=")" separator=",">
+                                      #{paperId}
+                                  </foreach>
+                              </if>
+                              and (toer.status = 'FINISHED' or toer.status = 'PERSISTED')
+                              and toer.first_start_time is not null
+                              and toer.finish_time is not null
+                              and (toer.breach_status is null or toer.breach_status = 1)
+                              and t.exam_student_id = tees.id
+                        </where>)
+                group by
+                    t.exam_student_id
+                <if test="many != null and many != '' or many == 0">
+                    <choose>
+                        <when test="many == true">
+                            HAVING count(t.exam_student_id) <![CDATA[ > ]]> 1
+                        </when>
+                        <otherwise>
+                            HAVING count(t.exam_student_id) = 1
+                        </otherwise>
+                    </choose>
+                </if>
+                ) t
+                join t_oe_exam_record t1 on
+                t1.exam_student_id = t.exam_student_id
+                where (t1.status = 'FINISHED' or t1.status = 'PERSISTED')
+                and t1.first_start_time is not null
+                and t1.finish_time is not null
+                and (t1.breach_status is null or t1.breach_status = 1)
+                <!--<if test="many != null and many != '' or many == 0">
+                    <choose>
+                        <when test="many == true">
+                            order by t1.id limit 510
+                        </when>
+                        <otherwise>
+                            order by t1.id limit 500
+                        </otherwise>
+                    </choose>
+                </if>-->
+                order by t1.id
+    </select>
 </mapper>

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

@@ -199,7 +199,7 @@ public class TEStudentController {
      */
     private Result userLoginCommon(TEStudent teStudent, Long examId, Long orgId) throws NoSuchAlgorithmException {
         //停用
-        if (teStudent.getEnable() == 0) {
+        if (teStudent.getEnable().intValue() == 0) {
             throw new BusinessException(ExceptionResultEnum.STUDENT_ENABLE);
         }
         Platform platform = ServletUtil.getRequestPlatform();

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

@@ -82,7 +82,7 @@ public class QuartzLogicServiceImpl implements QuartzLogicService {
         String[] strings = key.split("\\.");
         ExamActivityCacheBean examActivityCacheBean = teExamActivityService.getExamActivityCacheBean(Long.parseLong(strings[1]));
         ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examActivityCacheBean.getExamId());
-        if (Objects.nonNull(examCacheBean) && examCacheBean.getEnable() == 1 && Objects.nonNull(examActivityCacheBean) && examActivityCacheBean.getEnable() == 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());

+ 1 - 1
themis-task/src/main/resources/application-dev.properties

@@ -13,7 +13,7 @@ spring.application.name=themis-task
 #\u6570\u636E\u6E90\u914D\u7F6E
 db.host=localhost
 db.port=3306
-db.name=themis_v1.1
+db.name=themis_release
 db.username=root
 db.password=123456789
 #redis\u6570\u636E\u6E90\u914D\u7F6E