浏览代码

异步导出优化

xiatian 2 年之前
父节点
当前提交
72cdcf3a8f

+ 4 - 1
examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/enums/ExportTaskStatus.java

@@ -16,7 +16,10 @@ public enum ExportTaskStatus {
 
     SUCCESS("成功"),
 
-    ERROR("失败");
+    ERROR("失败"),
+    
+    TERMINATE("终止")
+    ;
 
     ExportTaskStatus(String desc) {
         this.desc = desc;

+ 1 - 1
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamAuditServiceImpl.java

@@ -261,7 +261,7 @@ public class ExamAuditServiceImpl implements ExamAuditService {
         Check.isNull(query.getExamId(), "请先选择考试批次!");
         List resultList = new ArrayList<ExamStudentEntity>();
         int pageNo = 1;
-        int pageSize = 200;
+        int pageSize = 5000;
         for (; ; ) {
             List tem = getExamAuditForAsyncPage(uds,query,pageNo, pageSize);
             if (tem == null || tem.size() == 0) {

+ 1 - 1
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamRecordServiceImpl.java

@@ -758,7 +758,7 @@ public class ExamRecordServiceImpl implements ExamRecordService {
 
         List<ExamRecordInfo> examRecordDataList = new ArrayList<ExamRecordInfo>();
         int pageNo = 1;
-        int pageSize = 200;
+        int pageSize = 5000;
         for (; ; ) {
             List<ExamRecordInfo> tem = getExamRecordDetailPageForExport(uds, query, pageNo, pageSize);
             if (tem == null || tem.size() == 0) {

+ 826 - 793
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamScoreServiceImpl.java

@@ -27,6 +27,7 @@ import cn.com.qmth.examcloud.core.oe.admin.service.bean.examscore.ExamScoreInfo;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examscore.ExamScoreQuery;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examscore.ObjectiveScoreInfo;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examstudent.ExamStudentInfo;
+import cn.com.qmth.examcloud.core.oe.admin.service.util.BatchGetDataUtil;
 import cn.com.qmth.examcloud.question.commons.core.question.QuestionType;
 import cn.com.qmth.examcloud.support.cache.CacheHelper;
 import cn.com.qmth.examcloud.support.cache.bean.*;
@@ -64,798 +65,830 @@ import java.util.stream.Collectors;
 @Service
 public class ExamScoreServiceImpl implements ExamScoreService {
 
-    private static final Logger log = LoggerFactory.getLogger(ExamScoreServiceImpl.class);
-
-    @Autowired
-    private ExamScoreRepo examScoreRepo;
-
-    @Autowired
-    private ExamRecordDataRepo examRecordDataRepo;
-
-    @Autowired
-    private ExamRecordQuestionsRepo examRecordQuestionsRepo;
-
-    @Autowired
-    private ExamRecordForMarkingRepo examRecordForMarkingRepo;
-
-    @Autowired
-    private ExamRecordQuestionsService examRecordQuestionsService;
-
-    @Autowired
-    private ExamStudentService examStudentService;
-
-    @Autowired
-    private ExamRecordService examRecordService;
-
-    @Autowired
-    private GainBaseDataService gainBaseDataService;
-
-    @Autowired
-    private JdbcTemplate jdbcTemplate;
-
-    @Autowired
-    private RedisClient redisClient;
-
-    @Autowired
-    private ExamStudentFinalScoreService examStudentFinalScoreService;
-
-    @Override
-    public Page<ExamScoreInfo> getExamScoreList(UserDataRules uds, ExamScoreQuery query) {
-        Check.isNull(query, "查询参数不能为空!");
-        Check.isNull(query.getExamId(), "请先选择考试批次!");
-        Pageable pageable = SpecUtils.buildPageable(query.getPageNo(), query.getPageSize());
-
-
-        //阅卷方式
-        String markingType = ExamCacheTransferHelper.
-                getDefaultCachedExamProperty(query.getExamId(), ExamProperties.MARKING_TYPE.name()).getValue();
-
-        //获取考生列表
-        Page<ExamStudentInfo> page = examStudentService.getExamStudentListPage(uds, ExamScoreEntityConvert.of(query));
-        List<ExamStudentInfo> examStudentList = page.getContent();
-        if (examStudentList == null || examStudentList.size() == 0) {
-            return new PageImpl<ExamScoreInfo>(Lists.newArrayList(), pageable, page.getTotalElements());
-        }
-
-        //封装成绩统计结果
-        List<ExamScoreInfo> examScoreList = new ArrayList<>();
-        examStudentList.forEach(examStudent -> {
-            //获取考试信息
-            ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(query.getExamId());
-            examScoreList.add(of(examStudent, examBean, markingType));
-        });
-        fillStage(examScoreList);
-        return new PageImpl<ExamScoreInfo>(examScoreList, pageable, page.getTotalElements());
-    }
-
-    private void fillStage(List<ExamScoreInfo> list) {
-        if (CollectionUtils.isEmpty(list)) {
-            return;
-        }
-        for (ExamScoreInfo info : list) {
-            if (info.getExamStageId() != null) {
-                ExamStageCacheBean stage = CacheHelper.getExamStage(info.getExamId(), info.getExamStageId());
-                info.setExamStageOrder(stage.getStageOrder());
-                info.setStageStartTime(stage.getStartTime());
-                info.setStageEndTime(stage.getEndTime());
-                info.setExamStage(stage.getStageOrder() + "("
-                        + DateUtil.format(stage.getStartTime(), DateUtil.DatePatterns.CHINA_DEFAULT) + "至"
-                        + DateUtil.format(stage.getEndTime(), DateUtil.DatePatterns.CHINA_DEFAULT) + ")");
-            }
-        }
-    }
-
-    /**
-     * 封装成绩统计结果
-     */
-    private ExamScoreInfo of(ExamStudentInfo examStudent, ExamSettingsCacheBean examBean, String markingType) {
-        ExamScoreInfo examScore = new ExamScoreInfo();
-        examScore.setExamId(examStudent.getExamId());
-        examScore.setExamName(examBean.getName());
-        examScore.setStudentId(examStudent.getStudentId());
-        examScore.setStudentCode(examStudent.getStudentCode());
-        examScore.setStudentName(examStudent.getStudentName());
-        examScore.setIdentityNumber(examStudent.getIdentityNumber());
-
-        examScore.setCourseId(examStudent.getCourseId());
-        examScore.setCourseCode(examStudent.getCourseCode());
-        examScore.setCourseName(examStudent.getCourseName());
-        examScore.setCourseNameAndCode(examStudent.getCourseName() + "(" + examStudent.getCourseCode() + ")");
-        examScore.setCourseLevel(CourseLevel.getCourseLevelTitle(examStudent.getCourseLevel()));
-
-        examScore.setOrgId(examStudent.getOrgId());
-        examScore.setOrgCode(examStudent.getOrgCode());
-        examScore.setOrgName(examStudent.getOrgName());
-        examScore.setInfoCollector(examStudent.getInfoCollector());
-        examScore.setSpecialtyName(examStudent.getSpecialtyName());
-        examScore.setGrade(examStudent.getGrade());
-        examScore.setExamStageId(examStudent.getExamStageId());
-        Long examTimes = examBean.getExamTimes();
-        if (examTimes != null) {
-            Integer extraExamNum = examStudent.getExtraNum() == null ? 0 : examStudent.getExtraNum();
-            Integer usedNum = examStudent.getUsedNum() == null ? 0 : examStudent.getUsedNum();
-            Long leftExamTimes = (examTimes + extraExamNum - usedNum) < 0 ? 0 : (examTimes + extraExamNum - usedNum);
-            examScore.setLeftExamTimes(leftExamTimes);
-        }
-        return setCommomScoreInfo(examScore, examStudent.getFinished(), examStudent.getExamStudentId(), examBean, markingType);
-    }
-
-    @Override
-    public List<ExamScoreInfo> exportExamScoreListForAsync(UserDataRules uds, ExamScoreQuery query) {
-        if (uds.getCourseRule().assertEmptyQueryResult() || uds.getOrgRule().assertEmptyQueryResult()) {
-            return Lists.newArrayList();
-        }
-        Check.isNull(query, "查询参数不能为空!");
-        Check.isNull(query.getExamId(), "请先选择考试批次!");
-
-        //阅卷方式
-        String markingType = ExamCacheTransferHelper.
-                getDefaultCachedExamProperty(query.getExamId(), ExamProperties.MARKING_TYPE.name()).getValue();
-        if (query.getStartLimit() != null && query.getEndLimit() != null) {
-            return getExamStudentInfoListOfScoreExport(uds, query, markingType);
-        } else {
-            List<ExamStudentEntity> examStudentList = new ArrayList<ExamStudentEntity>();
-            int pageNo = 1;
-            int pageSize = 200;
-            for (; ; ) {
-                List<ExamStudentEntity> tem = getExamStudentInfoListOfScoreExportByPage(uds, query, markingType, pageNo, pageSize);
-                if (tem == null || tem.size() == 0) {
-                    break;
-                } else {
-                    pageNo++;
-                    examStudentList.addAll(tem);
-                }
-            }
-
-            List<ExamScoreInfo> examScoreInfoList = new ArrayList<ExamScoreInfo>();
-            //缓存
-            for (ExamStudentEntity examStudent : examStudentList) {
-                long courseId = examStudent.getCourseId();
-                CourseCacheBean courseBean = ExamCacheTransferHelper.getCachedCourse(courseId);
-
-                long orgId = examStudent.getOrgId();
-                OrgCacheBean orgBean = gainBaseDataService.getOrgBean(orgId);
-
-                examScoreInfoList.add(convertToExamScoreInfo(examStudent, courseBean, orgBean, markingType));
-            }
-            fillStage(examScoreInfoList);
-            return examScoreInfoList;
-        }
-    }
-
-    private List<ExamStudentEntity> getExamStudentInfoListOfScoreExportByPage(UserDataRules uds, ExamScoreQuery query, String markingType, int pageNo, int pageSize) {
-        //查询条件
-        StringBuffer sql = new StringBuffer();
-        sql.append("select id,exam_student_id,exam_id,course_id,course_code,course_level,finished,student_id,student_code,student_name,identity_number"
-                + ",info_collector,root_org_id,org_id,paper_type,used_num,extra_num"
-                + ",specialty_code,specialty_name,grade,exam_stage_id from ec_oe_exam_student where 1=1 ");
-        if (query.getOrgId() != null) {
-            sql.append(" and org_id=" + query.getOrgId());
-        }
-        if (query.getExamId() != null) {
-            sql.append(" and exam_id=" + query.getExamId());
-        }
-        if (query.getExamStageId() != null) {
-            sql.append(" and exam_stage_id=" + query.getExamStageId());
-        }
-        if (StringUtils.isNotBlank(query.getStudentCode())) {
-            sql.append(" and student_code LIKE '" + query.getStudentCode() + "%'");
-        }
-        if (StringUtils.isNotBlank(query.getStudentName())) {
-            sql.append(" and student_name LIKE '" + query.getStudentName() + "%'");
-        }
-        if (StringUtils.isNotBlank(query.getIdentityNumber())) {
-            sql.append(" and identity_number LIKE '" + query.getIdentityNumber() + "%'");
-        }
-        if (query.getCourseId() != null) {
-            sql.append(" and course_id=" + query.getCourseId());
-        }
-        if (StringUtils.isNotBlank(query.getCourseLevel())) {
-            sql.append(" and course_level= '" + query.getCourseLevel() + "'");
-        }
-        if (query.getFinished() != null) {
-            sql.append(" and finished= " + query.getFinished());
-        }
-        if (uds.getOrgRule().assertNeedQueryRefIds()) {
-            sql.append(" and org_id in (" + StringUtils.join(uds.getOrgRule().getRefIds(), ",") + ") ");
-        }
-        if (uds.getCourseRule().assertNeedQueryRefIds()) {
-            sql.append(" and course_id in (" + StringUtils.join(uds.getCourseRule().getRefIds(), ",") + ") ");
-        }
-        int currentNum = (pageNo - 1) * pageSize;
-        sql.append(" order by id limit " + currentNum + "," + pageSize);
-
-        List<ExamStudentEntity> examStudentList = jdbcTemplate.query(sql.toString(), new RowMapper<ExamStudentEntity>() {
-            @Override
-            public ExamStudentEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
-                return getExamStudentEntityByResultSet(rs);
-            }
-        });
-
-        return examStudentList;
-    }
-
-    //    @Override
-    //    public List<ExamScoreInfo> exportExamScoreList(ExamScoreQuery query) {
-    //        Check.isNull(query, "查询参数不能为空!");
-    //        Check.isNull(query.getExamId(), "请先选择考试批次!");
-    //
-    //        //阅卷方式
-    //        String markingType = ExamCacheTransferHelper.
-    //                getDefaultCachedExamProperty(query.getExamId(), ExamProperties.MARKING_TYPE.name()).getValue();
-    //        return getExamStudentInfoListOfScoreExport(query, markingType);
-    //    }
-
-    @Override
-    public List<ExamScoreEntity> getAllExamScoreList(Long examId, String identityNumber, Long courseId) {
-        List<ExamRecordDataEntity> allExamRecordDataList =
-                examRecordDataRepo.findByExamIdAndIdentityNumberAndCourseId(examId, identityNumber, courseId);
-        if (allExamRecordDataList == null || allExamRecordDataList.isEmpty()) {
-            return null;
-        }
-
-        List<Long> examRecordDataIds = allExamRecordDataList.stream().map(p -> p.getId()).collect(Collectors.toList());
-        return examScoreRepo.findByExamRecordDataIdIn(examRecordDataIds);
-    }
-
-    private List<ExamScoreInfo> getExamStudentInfoListOfScoreExport(UserDataRules uds, ExamScoreQuery query, String markingType) {
-        Check.isNull(query, "查询参数不能为空!");
-        //查询条件
-        StringBuffer sql = new StringBuffer();
-        sql.append("select id,exam_student_id,exam_id,course_id,course_code,course_level,finished,student_id,student_code,student_name,identity_number"
-                + ",info_collector,root_org_id,org_id,paper_type,used_num,extra_num"
-                + ",specialty_code,specialty_name,grade,exam_stage_id from ec_oe_exam_student where 1=1 ");
-        if (query.getOrgId() != null) {
-            sql.append(" and org_id=" + query.getOrgId());
-        }
-        if (query.getExamId() != null) {
-            sql.append(" and exam_id=" + query.getExamId());
-        }
-        if (query.getExamStageId() != null) {
-            sql.append(" and exam_stage_id=" + query.getExamStageId());
-        }
-        if (StringUtils.isNotBlank(query.getStudentCode())) {
-            sql.append(" and student_code LIKE '" + query.getStudentCode() + "%'");
-        }
-        if (StringUtils.isNotBlank(query.getStudentName())) {
-            sql.append(" and student_name LIKE '" + query.getStudentName() + "%'");
-        }
-        if (StringUtils.isNotBlank(query.getIdentityNumber())) {
-            sql.append(" and identity_number LIKE '" + query.getIdentityNumber() + "%'");
-        }
-        if (query.getCourseId() != null) {
-            sql.append(" and course_id=" + query.getCourseId());
-        }
-        if (StringUtils.isNotBlank(query.getCourseLevel())) {
-            sql.append(" and course_level= '" + query.getCourseLevel() + "'");
-        }
-        if (query.getFinished() != null) {
-            sql.append(" and finished= " + query.getFinished());
-        }
-        if (uds.getOrgRule().assertNeedQueryRefIds()) {
-            sql.append(" and org_id in (" + StringUtils.join(uds.getOrgRule().getRefIds(), ",") + ") ");
-        }
-        if (uds.getCourseRule().assertNeedQueryRefIds()) {
-            sql.append(" and course_id in (" + StringUtils.join(uds.getCourseRule().getRefIds(), ",") + ") ");
-        }
-        sql.append(" order by id");
-
-        if (query.getStartLimit() != null && query.getEndLimit() != null) {
-            int offset = query.getEndLimit() - query.getStartLimit() + 1;
-            sql.append(" limit " + (query.getStartLimit() - 1) + "," + offset);
-        }
-        List<ExamStudentEntity> examStudentList = jdbcTemplate.query(sql.toString(), new RowMapper<ExamStudentEntity>() {
-            @Override
-            public ExamStudentEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
-                return getExamStudentEntityByResultSet(rs);
-            }
-        });
-
-        List<ExamScoreInfo> examScoreInfoList = new ArrayList<ExamScoreInfo>();
-        //缓存
-        for (ExamStudentEntity examStudent : examStudentList) {
-            long courseId = examStudent.getCourseId();
-            CourseCacheBean courseBean = ExamCacheTransferHelper.getCachedCourse(courseId);
-
-            long orgId = examStudent.getOrgId();
-            OrgCacheBean orgBean = gainBaseDataService.getOrgBean(orgId);
-
-            examScoreInfoList.add(convertToExamScoreInfo(examStudent, courseBean, orgBean, markingType));
-        }
-        fillStage(examScoreInfoList);
-        return examScoreInfoList;
-    }
-
-    private ExamScoreInfo convertToExamScoreInfo(ExamStudentEntity examStudent, CourseCacheBean courseBean, OrgCacheBean orgBean, String markingType) {
-        if (examStudent == null) {
-            return null;
-        }
-        //获取考试信息
-        ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getCachedExam(examStudent.getExamId(),
-                examStudent.getStudentId(), examStudent.getExamStageId());
-        ExamScoreInfo examScore = new ExamScoreInfo();
-        examScore.setExamStageId(examStudent.getExamStageId());
-        examScore.setExamId(examStudent.getExamId());
-        examScore.setExamName(examBean.getName());
-        examScore.setStudentId(examStudent.getStudentId());
-        examScore.setStudentCode(examStudent.getStudentCode());
-        examScore.setStudentName(examStudent.getStudentName());
-        examScore.setIdentityNumber(examStudent.getIdentityNumber());
-        examScore.setInfoCollector(examStudent.getInfoCollector());
-
-        examScore.setCourseId(examStudent.getCourseId());
-        examScore.setCourseCode(examStudent.getCourseCode());
-        examScore.setCourseName(courseBean.getName());
-        examScore.setCourseNameAndCode(courseBean.getName() + "(" + courseBean.getCode() + ")");
-        examScore.setCourseLevel(CourseLevel.getCourseLevelTitle(examStudent.getCourseLevel()));
-
-        examScore.setOrgId(examStudent.getOrgId());
-        examScore.setOrgCode(orgBean.getCode());
-        examScore.setOrgName(orgBean.getName());
-
-        examScore.setSpecialtyName(examStudent.getSpecialtyName());
-        examScore.setGrade(examStudent.getGrade());
-
-        //剩余考试次数=可考次数+可重考次数-已考次数
-        Long examTimes = examBean.getExamTimes();
-        if (examTimes != null) {
-            Integer extraExamNum = examStudent.getExtraNum() == null ? 0 : examStudent.getExtraNum();
-            Integer usedNum = examStudent.getUsedNum() == null ? 0 : examStudent.getUsedNum();
-            Long leftExamTimes = (examTimes + extraExamNum - usedNum) < 0 ? 0 : (examTimes + extraExamNum - usedNum);
-            examScore.setLeftExamTimes(leftExamTimes);
-        }
-
-        return setCommomScoreInfo(examScore, examStudent.getFinished(), examStudent.getExamStudentId(), examBean, markingType);
-    }
-
-    private ExamScoreInfo setCommomScoreInfo(ExamScoreInfo examScoreInfo, Boolean finished, long examStudentId, ExamSettingsCacheBean examBean, String markingType) {
-        //查询考试记录
-        if (finished != null && finished) {
-            //查询考试记录
-            List<ExamRecordDataEntity> examRecordList = examRecordService.getExamRecordListByExamStudentId(examStudentId);
-            examScoreInfo.setIsFinished("是");//是否完成考试
-            examScoreInfo.setIsAbsent("否");//是否缺考
-            //违纪次数
-            examScoreInfo.setDisciplineCount(disciplineCount(examRecordList));
-            //提交次数
-            examScoreInfo.setSubmitCount(submitCount(examRecordList));
-
-            //设置相关成绩(总分,主观分,客观分)
-            ExamStudentFinalScoreEntity finalExamScore = examStudentFinalScoreService.getFinalEffectiveExamScore(examStudentId);
-            setFinalExamScore(examScoreInfo, finalExamScore);
-
-            if (finalExamScore != null) {
-                // 违纪未审核 存在最终分为空情况
-                examScoreInfo.setExamRecordDataId(finalExamScore.getExamRecordDataId());
-
-                if (!CollectionUtils.isEmpty(examRecordList)) {
-                    for (ExamRecordDataEntity entity : examRecordList) {
-                        if (Objects.equals(entity.getId(), finalExamScore.getExamRecordDataId())) {
-                            examScoreInfo.setBasePaperId(entity.getBasePaperId());
-                        }
-                    }
-                }
-            }
-
-            //需求调整20200923:将开考时间,改为最终成绩的更新时间
-            examScoreInfo.setStartTime(getExamStudentFinalScoreUpdateTime(finalExamScore));
-        } else {
-            examScoreInfo.setIsFinished("否");//是否完成考试
-            examScoreInfo.setIsAbsent("是");//是否缺考
-            examScoreInfo.setDisciplineCount("--");//违纪次数
-            examScoreInfo.setSubmitCount("--"); //提交次数
-            examScoreInfo.setObjectiveScore("--");//主观分
-            examScoreInfo.setSubjectiveScore("--");//客观分
-            examScoreInfo.setFinalExamScore("--");//最终成绩
-            examScoreInfo.setStartTime("--");//考试开始时间
-        }
-
-        return examScoreInfo;
-    }
-
-
-    /**
-     * 给考生最终成绩赋值
-     *
-     * @param examScoreInfo 考试模型实体
-     * @param examScore     考试数据实体
-     */
-    private void setFinalExamScore(ExamScoreInfo examScoreInfo, final ExamStudentFinalScoreEntity examScore) {
-        if (examScore == null) {
-            examScoreInfo.setObjectiveScore("0");
-            examScoreInfo.setSubjectiveScore("0");
-            examScoreInfo.setFinalExamScore("0");
-        } else {
-            DecimalFormat decimalFormat = new DecimalFormat("#.##");
-            examScoreInfo.setObjectiveScore(decimalFormat.format(null == examScore.getObjectiveScore() ? 0 : examScore.getObjectiveScore()));
-            examScoreInfo.setSubjectiveScore(decimalFormat.format(null == examScore.getSubjectiveScore() ? 0 : examScore.getSubjectiveScore()));
-            examScoreInfo.setFinalExamScore(decimalFormat.format(null == examScore.getTotalScore() ? 0 : examScore.getTotalScore()));
-        }
-    }
-
-
-    /**
-     * 考试开始时间
-     */
-    private String getExamStudentFinalScoreUpdateTime(ExamStudentFinalScoreEntity examScore) {
-        if (examScore == null || examScore.getUpdateTime() == null) {
-            return "";
-        }
-
-        return CommonUtil.getDateStrWithSecond(examScore.getUpdateTime());
-    }
-
-    /**
-     * 违纪次数
-     */
-    private String disciplineCount(List<ExamRecordDataEntity> examRecordList) {
-        Integer disciplineCount = 0;
-        if (examRecordList == null) {
-            return disciplineCount.toString();
-        }
-        for (ExamRecordDataEntity e : examRecordList) {
-            if (e.getIsIllegality() != null && e.getIsIllegality()) {
-                disciplineCount++;
-            }
-        }
-        return disciplineCount.toString();
-    }
-
-    /**
-     * 正常交卷次数:无警告或者有警告,有审核,有正常提交时间
-     */
-    private String submitCount(List<ExamRecordDataEntity> examRecordList) {
-        Integer submitCount = 0;
-        for (ExamRecordDataEntity e : examRecordList) {
-            if (e.getIsWarn() == null) {
-                e.setIsWarn(false);
-            }
-            if (e.getIsAudit() == null) {
-                e.setIsAudit(false);
-            }
-            if (e.getIsWarn() && !e.getIsAudit()) {
-                //ignore
-            } else {
-                if (e.getEndTime() != null) {
-                    submitCount++;
-                }
-            }
-        }
-        return submitCount.toString();
-    }
-
-    private ExamStudentEntity getExamStudentEntityByResultSet(ResultSet rs) throws SQLException {
-        ExamStudentEntity examStudentEntity = new ExamStudentEntity();
-        examStudentEntity.setId(rs.getLong("id"));
-        examStudentEntity.setExamStudentId(rs.getLong("exam_student_id"));
-        examStudentEntity.setExamId(rs.getLong("exam_id"));
-        examStudentEntity.setCourseId(rs.getLong("course_id"));
-        examStudentEntity.setCourseCode(rs.getString("course_code"));
-        examStudentEntity.setCourseLevel(rs.getString("course_level"));
-        examStudentEntity.setFinished(rs.getBoolean("finished"));
-        examStudentEntity.setStudentId(rs.getLong("student_id"));
-        examStudentEntity.setStudentCode(rs.getString("student_code"));
-        examStudentEntity.setStudentName(rs.getString("student_name"));
-        examStudentEntity.setIdentityNumber(rs.getString("identity_number"));
-        examStudentEntity.setInfoCollector(rs.getString("info_collector"));
-        examStudentEntity.setRootOrgId(rs.getLong("root_org_id"));
-        examStudentEntity.setOrgId(rs.getLong("org_id"));
-        examStudentEntity.setPaperType(rs.getString("paper_type"));
-        examStudentEntity.setUsedNum(rs.getInt("used_num"));
-        examStudentEntity.setExtraNum(rs.getInt("extra_num"));
-        examStudentEntity.setSpecialtyCode(rs.getString("specialty_code"));
-        examStudentEntity.setSpecialtyName(rs.getString("specialty_name"));
-        examStudentEntity.setGrade(rs.getString("grade"));
-        if (rs.getString("exam_stage_id") != null) {
-            examStudentEntity.setExamStageId(rs.getLong("exam_stage_id"));
-        }
-        return examStudentEntity;
-    }
-
-    @Override
-    public void createExamScoreWithOffline(Long examRecordDataId) {
-        ExamScoreEntity examScoreEntity = new ExamScoreEntity();
-        examScoreEntity.setExamRecordDataId(examRecordDataId);
-        examScoreEntity.setObjectiveScore(0D);
-        examScoreEntity.setSubjectiveScore(0D);
-        examScoreEntity.setTotalScore(0D);
-        examScoreRepo.save(examScoreEntity);
-    }
-
-    @Override
-    public List<ObjectiveScoreInfo> queryObjectiveScoreList(Long examStudentId) {
-        Check.isNull(examStudentId, "examStudentId 不能为空");
-
-        List<ExamRecordDataEntity> examRecordDataList = examRecordDataRepo.findByExamStudentId(examStudentId);
-        //过滤已完成的考试记录(包括违纪的)
-        examRecordDataList = examRecordDataList.stream().filter((o -> {
-            return o.getExamRecordStatus() == ExamRecordStatus.EXAM_END ||
-                    o.getExamRecordStatus() == ExamRecordStatus.EXAM_OVERDUE ||
-                    o.getExamRecordStatus() == ExamRecordStatus.EXAM_HAND_IN ||
-                    o.getExamRecordStatus() == ExamRecordStatus.EXAM_AUTO_HAND_IN;
-        })).collect(Collectors.toList());
-
-        List<ObjectiveScoreInfo> objectiveScoreInfoList = new ArrayList<>();
-        for (ExamRecordDataEntity examRecordDataEntity : examRecordDataList) {
-            ObjectiveScoreInfo objectiveScoreInfo = new ObjectiveScoreInfo();
-            objectiveScoreInfo.setExamRecordDataId(examRecordDataEntity.getId());
-            objectiveScoreInfo.setExamOrder(examRecordDataEntity.getExamOrder());
-            objectiveScoreInfo.setStartTime(examRecordDataEntity.getStartTime());
-            objectiveScoreInfo.setEndTime(examRecordDataEntity.getEndTime());
-
-            //如果考试没有结束,则只能返回部分数据
-            if (!isExamRecordEnded(examRecordDataEntity)) {
-                objectiveScoreInfo.setIsExamEnded(false);
-                objectiveScoreInfoList.add(objectiveScoreInfo);
-                continue;
-            } else {
-                objectiveScoreInfo.setIsExamEnded(true);
-            }
-
-            if (examRecordDataEntity.getIsIllegality() == null || !examRecordDataEntity.getIsIllegality()) {
-                if (examRecordDataEntity.getIsWarn() && !examRecordDataEntity.getIsAudit()) {
-                    objectiveScoreInfo.setIsAuditing(true);
-                } else if (!examRecordDataEntity.getIsWarn() || (examRecordDataEntity.getIsWarn() && examRecordDataEntity.getIsAudit())) {
-                    ExamScoreEntity examScore = examScoreRepo.findByExamRecordDataId(examRecordDataEntity.getId());
-                    objectiveScoreInfo.setIsAuditing(false);
-                    objectiveScoreInfo.setObjectiveScore(examScore.getObjectiveScore());
-                }
-                objectiveScoreInfo.setIsIllegality(false);
-            } else {
-                objectiveScoreInfo.setIsIllegality(true);
-            }
-            objectiveScoreInfoList.add(objectiveScoreInfo);
-        }
-
-        processObjectiveScoreList(examStudentId, objectiveScoreInfoList);
-
-        return objectiveScoreInfoList;
-    }
-
-    private void processObjectiveScoreList(Long examStudentId, List<ObjectiveScoreInfo> resultList) {
-        //如果有未处理完成的考试记录,需要将未处理的考试记录数据添加到列表中
-        String examBossKey = RedisKeyHelper.getBuilder().examBossKey(examStudentId);
-        ExamBoss examBoss = redisClient.get(examBossKey, ExamBoss.class);
-        if (null != examBoss) {
-            //未完全同步的考试记录id
-            List<Long> unSyncedExamRecordDataIds = examBoss.getExamRecordDataIds();
-            if (null != unSyncedExamRecordDataIds && !unSyncedExamRecordDataIds.isEmpty()) {
-                //正序排列
-                unSyncedExamRecordDataIds.sort(Long::compareTo);
-
-                //已考次数
-                Integer examUsedNum = 0;
-
-                for (Long examRecordDataId : unSyncedExamRecordDataIds) {
-                    ExamRecordData examRecordData =
-                            redisClient.get(RedisKeyHelper.getBuilder().examRecordDataKey(examRecordDataId),
-                                    ExamRecordData.class);
-                    if (null == examRecordData) {
-                        throw new StatusException("100001", "考试记录的缓存数据有误");
-                    }
-
-                    //考试中的数据不展示
-                    if (cn.com.qmth.examcloud.support.enums.ExamRecordStatus.EXAM_ING == examRecordData.getExamRecordStatus()) {
-                        continue;
-                    }
-
-                    if (!resultList.isEmpty()) {
-                        examUsedNum = resultList.get(resultList.size() - 1).getExamOrder();
-                    }
-
-                    ObjectiveScoreInfo cachedObjectiveScoreInfo = getCachedObjectiveScoreInfo(examRecordData);
-                    cachedObjectiveScoreInfo.setExamOrder(
-                            getExamOrder(examRecordData.getExamId(), examRecordData.getStudentId(), examUsedNum));
-
-                    resultList.add(cachedObjectiveScoreInfo);
-                }
-            }
-        }
-    }
-
-    private ObjectiveScoreInfo getCachedObjectiveScoreInfo(final ExamRecordData examRecordData) {
-        ObjectiveScoreInfo objectiveScoreInfo = new ObjectiveScoreInfo();
-        objectiveScoreInfo.setExamRecordDataId(examRecordData.getId());
-        objectiveScoreInfo.setStartTime(examRecordData.getStartTime());
-        objectiveScoreInfo.setEndTime(examRecordData.getEndTime());
-
-        //如果考试没有结束,则只能返回部分数据
-        if (!isExamRecordEnded(examRecordData)) {
-            objectiveScoreInfo.setIsExamEnded(false);
-            return objectiveScoreInfo;
-        } else {
-            objectiveScoreInfo.setIsExamEnded(true);
-        }
-
-        if (examRecordData.getIsIllegality() == null || !examRecordData.getIsIllegality()) {
-            if ((null != examRecordData.getIsWarn() && !examRecordData.getIsWarn())
-                    || (null != examRecordData.getIsWarn() && examRecordData.getIsWarn()
-                    && null != examRecordData.getIsAudit() && examRecordData.getIsAudit())) {
-                objectiveScoreInfo.setIsAuditing(true);
-
-                //缓存中的分数是存储在临时考试记录表中的,所以需要从考试记录缓存中取
-                objectiveScoreInfo.setObjectiveScore(examRecordData.getObjectiveScore());
-            } else {
-                objectiveScoreInfo.setIsAuditing(false);
-            }
-
-            objectiveScoreInfo.setIsIllegality(false);
-        } else {
-            objectiveScoreInfo.setIsIllegality(true);
-        }
-
-        return objectiveScoreInfo;
-    }
-
-    /**
-     * 计算考试次数
-     *
-     * @param examId      考试id
-     * @param studentId   学生id
-     * @param usedExamNum 已考次数
-     * @return
-     */
-    private Integer getExamOrder(Long examId, Long studentId, Integer usedExamNum) {
-        ExamSettingsCacheBean cachedExam = ExamCacheTransferHelper.getDefaultCachedExam(examId);
-        Integer canExamTimes = cachedExam.getExamTimes() == null ? 0 : cachedExam.getExamTimes().intValue();//可考次数
-
-        //超过可考次数,始终为可考次数+1
-        if (usedExamNum > canExamTimes) {
-            return canExamTimes + 1;
-        }
-
-        return usedExamNum + 1;
-    }
-
-    private boolean isExamRecordEnded(ExamRecordData examRecordData) {
-        //如果考试记录状态为已处理,则直接返回true.
-        if (examRecordData.getExamRecordStatus() == cn.com.qmth.examcloud.support.enums.ExamRecordStatus.EXAM_END ||
-                examRecordData.getExamRecordStatus() == cn.com.qmth.examcloud.support.enums.ExamRecordStatus.EXAM_OVERDUE ||
-                examRecordData.getExamRecordStatus() == cn.com.qmth.examcloud.support.enums.ExamRecordStatus.EXAM_INVALID) {
-            return true;
-        }
-        return false;
-    }
-
-    private boolean isExamRecordEnded(ExamRecordDataEntity examRecordData) {
-        //如果考试记录状态为已处理,则直接返回true.
-        if (examRecordData.getExamRecordStatus() == ExamRecordStatus.EXAM_END ||
-                examRecordData.getExamRecordStatus() == ExamRecordStatus.EXAM_OVERDUE ||
-                examRecordData.getExamRecordStatus() == ExamRecordStatus.EXAM_INVALID) {
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public void updateCorrectAnswerAndReFixScore(Long examId, Long courseId, Long examStudentId) {
-        List<ExamRecordDataEntity> examRecordDataList = examRecordDataRepo.findByExamIdAndCourseIdAndExamStudentId(examId, courseId, examStudentId);
-        if (CollectionUtils.isEmpty(examRecordDataList)) {
-            log.warn("updateCorrectAnswerAndReFixScore examRecordDataList is empty, examStudentId = {}", examStudentId);
-            return;
-        }
-
-        // Map<试题ID, 正确答案列表>
-        Map<String, List<String>> questionAnswerMaps = new HashMap<>();
-        boolean needUpdateFinalScore = false;
-
-        for (ExamRecordDataEntity examRecordData : examRecordDataList) {
-            if (ExamType.OFFLINE == examRecordData.getExamType()) {
-                // 离线考试,examRecordQuestions实际为空
-                continue;
-            }
-
-            ExamRecordQuestionsEntity examRecordQuestion = examRecordQuestionsService.getExamRecordQuestionsAndFixExamRecordDataIfNecessary(examRecordData);
-            if (examRecordQuestion == null) {
-                log.warn("updateCorrectAnswerAndReFixScore examRecordQuestions is null, examRecordDataId = {}", examRecordData.getId());
-                continue;
-            }
-
-            // 所有客观题的试题ID列表
-            List<ExamQuestionEntity> examQuestions = examRecordQuestion.getExamQuestionEntities();
-            Set<String> objectiveQuestionIds = examQuestions.stream()
-                    .filter(e -> QuestionType.isObjective(e.getQuestionType()))
-                    .map(ExamQuestionEntity::getQuestionId)
-                    .collect(Collectors.toSet());
-
-            double objectiveScore = 0d; // 客观题得分
-            int totalObjective = 0; // 客观题总数
-            int totalRightObjective = 0; // 客观题作答正确数
-            boolean needUpdateExamRecordQuestions = false;
-
-            for (String curQuestionId : objectiveQuestionIds) {
-                // 按题号由小到大提取相同题ID的小题列表(注:套题的子题ID相同)
-                List<ExamQuestionEntity> questionUnits = examQuestions.stream().
-                        filter(e -> e.getQuestionId().equals(curQuestionId)).
-                        sorted(Comparator.comparingInt(ExamQuestionEntity::getOrder))
-                        .collect(Collectors.toList());
-
-                for (ExamQuestionEntity e : questionUnits) {
-                    if (QuestionType.isObjective(e.getQuestionType())) {
-                        totalObjective++;
-                    }
-                }
-
-                // 获取当前题的正确答案
-                List<String> rightAnswers;
-                if (questionAnswerMaps.containsKey(curQuestionId)) {
-                    rightAnswers = questionAnswerMaps.get(curQuestionId);
-                } else {
-                    QuestionAnswerCacheBean questionAnswer = CacheHelper.getQuestionAnswer(curQuestionId);
-                    rightAnswers = questionAnswer.getRightAnswers();
-                    questionAnswerMaps.put(curQuestionId, rightAnswers);
-                }
-
-                if (CollectionUtils.isEmpty(rightAnswers)) {
-                    log.warn("updateCorrectAnswerAndReFixScore rightAnswers is empty, questionId = {}", curQuestionId);
-                    continue;
-                }
-
-                if (questionUnits.size() != rightAnswers.size()) {
-                    log.warn("updateCorrectAnswerAndReFixScore rightAnswers incorrect, questionId = {}", curQuestionId);
-                    continue;
-                }
-
-                for (int i = 0; i < questionUnits.size(); i++) {
-                    ExamQuestionEntity curQuestion = questionUnits.get(i);
-                    if (!QuestionType.isObjective(curQuestion.getQuestionType())) {
-                        // 跳过套题内主观题
-                        continue;
-                    }
-
-                    // 答案不一致,则更新
-                    String rightAnswer = rightAnswers.get(i);
-                    if (rightAnswer != null && !rightAnswer.equals(curQuestion.getCorrectAnswer())) {
-                        curQuestion.setCorrectAnswer(rightAnswer);
-                        needUpdateExamRecordQuestions = true;
-                    }
-
-                    // 计算得分
-                    String correctAnswer = curQuestion.getCorrectAnswer();
-                    String studentAnswer = curQuestion.getStudentAnswer();
-                    // if (correctAnswer != null && QuestionOptionHelper.isEqualAnswer(correctAnswer, studentAnswer)) {
-                    if (correctAnswer != null && correctAnswer.equals(studentAnswer)) {
-                        objectiveScore += curQuestion.getQuestionScore();
-                        totalRightObjective++;
-                    }
-                }
-            }
-
-            if (needUpdateExamRecordQuestions) {
-                needUpdateFinalScore = true;
-
-                examRecordQuestionsRepo.save(examRecordQuestion);
-
-                ExamScoreEntity examScore = examScoreRepo.findByExamRecordDataId(examRecordData.getId());
-                if (examScore != null) {
-                    double subjectiveScore = examScore.getSubjectiveScore() != null ? examScore.getSubjectiveScore() : 0d;
-
-                    double objectiveAccuracy = 0d;// 客观题正确率
-                    if (totalObjective > 0) {
-                        objectiveAccuracy = totalRightObjective * 100d / totalObjective;
-                        objectiveAccuracy = Double.parseDouble(new DecimalFormat("#.00").format(objectiveAccuracy));
-                    }
-
-                    examScore.setObjectiveScore(objectiveScore);
-                    examScore.setObjectiveAccuracy(objectiveAccuracy);
-                    examScore.setTotalScore(objectiveScore + subjectiveScore);
-                    examScoreRepo.save(examScore);
-                }
-
-                ExamRecordForMarkingEntity examRecordForMarking = examRecordForMarkingRepo.findByExamRecordDataId(examRecordData.getId());
-                if (examRecordForMarking != null) {
-                    examRecordForMarking.setObjectiveScore(objectiveScore);
-                    examRecordForMarkingRepo.save(examRecordForMarking);
-                }
-
-                log.info("updateCorrectAnswerAndReFixScore examRecordQuestions examRecordDataId = {}", examRecordData.getId());
-            }
-        }
-
-        if (needUpdateFinalScore) {
-            examStudentFinalScoreService.calcAndSaveFinalScore(examStudentId);
-            log.info("updateCorrectAnswerAndReFixScore finalScore examStudentId = {}", examStudentId);
-        }
-    }
+	private static final Logger log = LoggerFactory.getLogger(ExamScoreServiceImpl.class);
+
+	@Autowired
+	private ExamScoreRepo examScoreRepo;
+
+	@Autowired
+	private ExamRecordDataRepo examRecordDataRepo;
+
+	@Autowired
+	private ExamRecordQuestionsRepo examRecordQuestionsRepo;
+
+	@Autowired
+	private ExamRecordForMarkingRepo examRecordForMarkingRepo;
+
+	@Autowired
+	private ExamRecordQuestionsService examRecordQuestionsService;
+
+	@Autowired
+	private ExamStudentService examStudentService;
+
+	@Autowired
+	private ExamRecordService examRecordService;
+
+	@Autowired
+	private GainBaseDataService gainBaseDataService;
+
+	@Autowired
+	private JdbcTemplate jdbcTemplate;
+
+	@Autowired
+	private RedisClient redisClient;
+
+	@Autowired
+	private ExamStudentFinalScoreService examStudentFinalScoreService;
+
+	@Override
+	public Page<ExamScoreInfo> getExamScoreList(UserDataRules uds, ExamScoreQuery query) {
+		Check.isNull(query, "查询参数不能为空!");
+		Check.isNull(query.getExamId(), "请先选择考试批次!");
+		Pageable pageable = SpecUtils.buildPageable(query.getPageNo(), query.getPageSize());
+
+		// 阅卷方式
+		String markingType = ExamCacheTransferHelper
+				.getDefaultCachedExamProperty(query.getExamId(), ExamProperties.MARKING_TYPE.name()).getValue();
+
+		// 获取考生列表
+		Page<ExamStudentInfo> page = examStudentService.getExamStudentListPage(uds, ExamScoreEntityConvert.of(query));
+		List<ExamStudentInfo> examStudentList = page.getContent();
+		if (examStudentList == null || examStudentList.size() == 0) {
+			return new PageImpl<ExamScoreInfo>(Lists.newArrayList(), pageable, page.getTotalElements());
+		}
+
+		// 封装成绩统计结果
+		List<ExamScoreInfo> examScoreList = new ArrayList<>();
+		examStudentList.forEach(examStudent -> {
+			// 获取考试信息
+			ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(query.getExamId());
+			examScoreList.add(of(examStudent, examBean, markingType));
+		});
+		fillStage(examScoreList);
+		return new PageImpl<ExamScoreInfo>(examScoreList, pageable, page.getTotalElements());
+	}
+
+	private void fillStage(List<ExamScoreInfo> list) {
+		if (CollectionUtils.isEmpty(list)) {
+			return;
+		}
+		for (ExamScoreInfo info : list) {
+			if (info.getExamStageId() != null) {
+				ExamStageCacheBean stage = CacheHelper.getExamStage(info.getExamId(), info.getExamStageId());
+				info.setExamStageOrder(stage.getStageOrder());
+				info.setStageStartTime(stage.getStartTime());
+				info.setStageEndTime(stage.getEndTime());
+				info.setExamStage(stage.getStageOrder() + "("
+						+ DateUtil.format(stage.getStartTime(), DateUtil.DatePatterns.CHINA_DEFAULT) + "至"
+						+ DateUtil.format(stage.getEndTime(), DateUtil.DatePatterns.CHINA_DEFAULT) + ")");
+			}
+		}
+	}
+
+	/**
+	 * 封装成绩统计结果
+	 */
+	private ExamScoreInfo of(ExamStudentInfo examStudent, ExamSettingsCacheBean examBean, String markingType) {
+		ExamScoreInfo examScore = new ExamScoreInfo();
+		examScore.setExamId(examStudent.getExamId());
+		examScore.setExamName(examBean.getName());
+		examScore.setStudentId(examStudent.getStudentId());
+		examScore.setStudentCode(examStudent.getStudentCode());
+		examScore.setStudentName(examStudent.getStudentName());
+		examScore.setIdentityNumber(examStudent.getIdentityNumber());
+
+		examScore.setCourseId(examStudent.getCourseId());
+		examScore.setCourseCode(examStudent.getCourseCode());
+		examScore.setCourseName(examStudent.getCourseName());
+		examScore.setCourseNameAndCode(examStudent.getCourseName() + "(" + examStudent.getCourseCode() + ")");
+		examScore.setCourseLevel(CourseLevel.getCourseLevelTitle(examStudent.getCourseLevel()));
+
+		examScore.setOrgId(examStudent.getOrgId());
+		examScore.setOrgCode(examStudent.getOrgCode());
+		examScore.setOrgName(examStudent.getOrgName());
+		examScore.setInfoCollector(examStudent.getInfoCollector());
+		examScore.setSpecialtyName(examStudent.getSpecialtyName());
+		examScore.setGrade(examStudent.getGrade());
+		examScore.setExamStageId(examStudent.getExamStageId());
+		Long examTimes = examBean.getExamTimes();
+		if (examTimes != null) {
+			Integer extraExamNum = examStudent.getExtraNum() == null ? 0 : examStudent.getExtraNum();
+			Integer usedNum = examStudent.getUsedNum() == null ? 0 : examStudent.getUsedNum();
+			Long leftExamTimes = (examTimes + extraExamNum - usedNum) < 0 ? 0 : (examTimes + extraExamNum - usedNum);
+			examScore.setLeftExamTimes(leftExamTimes);
+		}
+		return setCommomScoreInfo(examScore, examStudent.getFinished(), examStudent.getExamStudentId(), examBean,
+				markingType);
+	}
+
+	@Override
+	public List<ExamScoreInfo> exportExamScoreListForAsync(UserDataRules uds, ExamScoreQuery query) {
+		if (uds.getCourseRule().assertEmptyQueryResult() || uds.getOrgRule().assertEmptyQueryResult()) {
+			return Lists.newArrayList();
+		}
+		Check.isNull(query, "查询参数不能为空!");
+		Check.isNull(query.getExamId(), "请先选择考试批次!");
+
+		// 阅卷方式
+		String markingType = ExamCacheTransferHelper
+				.getDefaultCachedExamProperty(query.getExamId(), ExamProperties.MARKING_TYPE.name()).getValue();
+//        if (query.getStartLimit() != null && query.getEndLimit() != null) {
+//            return getExamStudentInfoListOfScoreExport(uds, query, markingType);
+//        } else {
+		List<ExamScoreInfo> examScoreInfoList = new ArrayList<ExamScoreInfo>();
+		List<Long> ids = getExamStudentInfoListOfScoreExportByPageOnlyId(uds, query, markingType);
+		if (CollectionUtils.isEmpty(ids)) {
+			return examScoreInfoList;
+		}
+		List<ExamStudentEntity> examStudentList=new BatchGetDataUtil<ExamStudentEntity, Long>() {
+
+			@Override
+			protected List<ExamStudentEntity> getData(List<Long> paramList) {
+				return getExamStudentInfoListOfScoreExportByPage(uds, query, markingType,paramList);
+			}
+		}.getDataForBatch(ids, 1000);
+       
+		if(CollectionUtils.isEmpty(examStudentList)) {
+        	return examScoreInfoList;
+        }
+
+		// 缓存
+		for (ExamStudentEntity examStudent : examStudentList) {
+			long courseId = examStudent.getCourseId();
+			CourseCacheBean courseBean = ExamCacheTransferHelper.getCachedCourse(courseId);
+
+			long orgId = examStudent.getOrgId();
+			OrgCacheBean orgBean = gainBaseDataService.getOrgBean(orgId);
+
+			examScoreInfoList.add(convertToExamScoreInfo(examStudent, courseBean, orgBean, markingType));
+		}
+		fillStage(examScoreInfoList);
+		return examScoreInfoList;
+//        }
+	}
+
+	private List<ExamStudentEntity> getExamStudentInfoListOfScoreExportByPage(UserDataRules uds, ExamScoreQuery query,
+			String markingType, List<Long> ids) {
+		// 查询条件
+		StringBuffer sql = new StringBuffer();
+		sql.append(
+				"select id,exam_student_id,exam_id,course_id,course_code,course_level,finished,student_id,student_code,student_name,identity_number"
+						+ ",info_collector,root_org_id,org_id,paper_type,used_num,extra_num"
+						+ ",specialty_code,specialty_name,grade,exam_stage_id from ec_oe_exam_student where id in ( ");
+		sql.append(StringUtils.join(ids, ","));
+		sql.append(" )");
+
+		List<ExamStudentEntity> examStudentList = jdbcTemplate.query(sql.toString(),
+				new RowMapper<ExamStudentEntity>() {
+					@Override
+					public ExamStudentEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
+						return getExamStudentEntityByResultSet(rs);
+					}
+				});
+
+		return examStudentList;
+	}
+
+	private List<Long> getExamStudentInfoListOfScoreExportByPageOnlyId(UserDataRules uds, ExamScoreQuery query,
+			String markingType) {
+		// 查询条件
+		StringBuffer sql = new StringBuffer();
+		sql.append("select id from ec_oe_exam_student where 1=1 ");
+		if (query.getOrgId() != null) {
+			sql.append(" and org_id=" + query.getOrgId());
+		}
+		if (query.getExamId() != null) {
+			sql.append(" and exam_id=" + query.getExamId());
+		}
+		if (query.getExamStageId() != null) {
+			sql.append(" and exam_stage_id=" + query.getExamStageId());
+		}
+		if (StringUtils.isNotBlank(query.getStudentCode())) {
+			sql.append(" and student_code LIKE '" + query.getStudentCode() + "%'");
+		}
+		if (StringUtils.isNotBlank(query.getStudentName())) {
+			sql.append(" and student_name LIKE '" + query.getStudentName() + "%'");
+		}
+		if (StringUtils.isNotBlank(query.getIdentityNumber())) {
+			sql.append(" and identity_number LIKE '" + query.getIdentityNumber() + "%'");
+		}
+		if (query.getCourseId() != null) {
+			sql.append(" and course_id=" + query.getCourseId());
+		}
+		if (StringUtils.isNotBlank(query.getCourseLevel())) {
+			sql.append(" and course_level= '" + query.getCourseLevel() + "'");
+		}
+		if (query.getFinished() != null) {
+			sql.append(" and finished= " + query.getFinished());
+		}
+		if (uds.getOrgRule().assertNeedQueryRefIds()) {
+			sql.append(" and org_id in (" + StringUtils.join(uds.getOrgRule().getRefIds(), ",") + ") ");
+		}
+		if (uds.getCourseRule().assertNeedQueryRefIds()) {
+			sql.append(" and course_id in (" + StringUtils.join(uds.getCourseRule().getRefIds(), ",") + ") ");
+		}
+
+		List<Long> examStudentList = jdbcTemplate.queryForList(sql.toString(), Long.class);
+
+		return examStudentList;
+	}
+
+	// @Override
+	// public List<ExamScoreInfo> exportExamScoreList(ExamScoreQuery query) {
+	// Check.isNull(query, "查询参数不能为空!");
+	// Check.isNull(query.getExamId(), "请先选择考试批次!");
+	//
+	// //阅卷方式
+	// String markingType = ExamCacheTransferHelper.
+	// getDefaultCachedExamProperty(query.getExamId(),
+	// ExamProperties.MARKING_TYPE.name()).getValue();
+	// return getExamStudentInfoListOfScoreExport(query, markingType);
+	// }
+
+	@Override
+	public List<ExamScoreEntity> getAllExamScoreList(Long examId, String identityNumber, Long courseId) {
+		List<ExamRecordDataEntity> allExamRecordDataList = examRecordDataRepo
+				.findByExamIdAndIdentityNumberAndCourseId(examId, identityNumber, courseId);
+		if (allExamRecordDataList == null || allExamRecordDataList.isEmpty()) {
+			return null;
+		}
+
+		List<Long> examRecordDataIds = allExamRecordDataList.stream().map(p -> p.getId()).collect(Collectors.toList());
+		return examScoreRepo.findByExamRecordDataIdIn(examRecordDataIds);
+	}
+
+//    private List<ExamScoreInfo> getExamStudentInfoListOfScoreExport(UserDataRules uds, ExamScoreQuery query, String markingType) {
+//        Check.isNull(query, "查询参数不能为空!");
+//        //查询条件
+//        StringBuffer sql = new StringBuffer();
+//        sql.append("select id,exam_student_id,exam_id,course_id,course_code,course_level,finished,student_id,student_code,student_name,identity_number"
+//                + ",info_collector,root_org_id,org_id,paper_type,used_num,extra_num"
+//                + ",specialty_code,specialty_name,grade,exam_stage_id from ec_oe_exam_student where 1=1 ");
+//        if (query.getOrgId() != null) {
+//            sql.append(" and org_id=" + query.getOrgId());
+//        }
+//        if (query.getExamId() != null) {
+//            sql.append(" and exam_id=" + query.getExamId());
+//        }
+//        if (query.getExamStageId() != null) {
+//            sql.append(" and exam_stage_id=" + query.getExamStageId());
+//        }
+//        if (StringUtils.isNotBlank(query.getStudentCode())) {
+//            sql.append(" and student_code LIKE '" + query.getStudentCode() + "%'");
+//        }
+//        if (StringUtils.isNotBlank(query.getStudentName())) {
+//            sql.append(" and student_name LIKE '" + query.getStudentName() + "%'");
+//        }
+//        if (StringUtils.isNotBlank(query.getIdentityNumber())) {
+//            sql.append(" and identity_number LIKE '" + query.getIdentityNumber() + "%'");
+//        }
+//        if (query.getCourseId() != null) {
+//            sql.append(" and course_id=" + query.getCourseId());
+//        }
+//        if (StringUtils.isNotBlank(query.getCourseLevel())) {
+//            sql.append(" and course_level= '" + query.getCourseLevel() + "'");
+//        }
+//        if (query.getFinished() != null) {
+//            sql.append(" and finished= " + query.getFinished());
+//        }
+//        if (uds.getOrgRule().assertNeedQueryRefIds()) {
+//            sql.append(" and org_id in (" + StringUtils.join(uds.getOrgRule().getRefIds(), ",") + ") ");
+//        }
+//        if (uds.getCourseRule().assertNeedQueryRefIds()) {
+//            sql.append(" and course_id in (" + StringUtils.join(uds.getCourseRule().getRefIds(), ",") + ") ");
+//        }
+//        sql.append(" order by id");
+//
+//        if (query.getStartLimit() != null && query.getEndLimit() != null) {
+//            int offset = query.getEndLimit() - query.getStartLimit() + 1;
+//            sql.append(" limit " + (query.getStartLimit() - 1) + "," + offset);
+//        }
+//        List<ExamStudentEntity> examStudentList = jdbcTemplate.query(sql.toString(), new RowMapper<ExamStudentEntity>() {
+//            @Override
+//            public ExamStudentEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
+//                return getExamStudentEntityByResultSet(rs);
+//            }
+//        });
+//
+//        List<ExamScoreInfo> examScoreInfoList = new ArrayList<ExamScoreInfo>();
+//        //缓存
+//        for (ExamStudentEntity examStudent : examStudentList) {
+//            long courseId = examStudent.getCourseId();
+//            CourseCacheBean courseBean = ExamCacheTransferHelper.getCachedCourse(courseId);
+//
+//            long orgId = examStudent.getOrgId();
+//            OrgCacheBean orgBean = gainBaseDataService.getOrgBean(orgId);
+//
+//            examScoreInfoList.add(convertToExamScoreInfo(examStudent, courseBean, orgBean, markingType));
+//        }
+//        fillStage(examScoreInfoList);
+//        return examScoreInfoList;
+//    }
+
+	private ExamScoreInfo convertToExamScoreInfo(ExamStudentEntity examStudent, CourseCacheBean courseBean,
+			OrgCacheBean orgBean, String markingType) {
+		if (examStudent == null) {
+			return null;
+		}
+		// 获取考试信息
+		ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getCachedExam(examStudent.getExamId(),
+				examStudent.getStudentId(), examStudent.getExamStageId());
+		ExamScoreInfo examScore = new ExamScoreInfo();
+		examScore.setExamStageId(examStudent.getExamStageId());
+		examScore.setExamId(examStudent.getExamId());
+		examScore.setExamName(examBean.getName());
+		examScore.setStudentId(examStudent.getStudentId());
+		examScore.setStudentCode(examStudent.getStudentCode());
+		examScore.setStudentName(examStudent.getStudentName());
+		examScore.setIdentityNumber(examStudent.getIdentityNumber());
+		examScore.setInfoCollector(examStudent.getInfoCollector());
+
+		examScore.setCourseId(examStudent.getCourseId());
+		examScore.setCourseCode(examStudent.getCourseCode());
+		examScore.setCourseName(courseBean.getName());
+		examScore.setCourseNameAndCode(courseBean.getName() + "(" + courseBean.getCode() + ")");
+		examScore.setCourseLevel(CourseLevel.getCourseLevelTitle(examStudent.getCourseLevel()));
+
+		examScore.setOrgId(examStudent.getOrgId());
+		examScore.setOrgCode(orgBean.getCode());
+		examScore.setOrgName(orgBean.getName());
+
+		examScore.setSpecialtyName(examStudent.getSpecialtyName());
+		examScore.setGrade(examStudent.getGrade());
+
+		// 剩余考试次数=可考次数+可重考次数-已考次数
+		Long examTimes = examBean.getExamTimes();
+		if (examTimes != null) {
+			Integer extraExamNum = examStudent.getExtraNum() == null ? 0 : examStudent.getExtraNum();
+			Integer usedNum = examStudent.getUsedNum() == null ? 0 : examStudent.getUsedNum();
+			Long leftExamTimes = (examTimes + extraExamNum - usedNum) < 0 ? 0 : (examTimes + extraExamNum - usedNum);
+			examScore.setLeftExamTimes(leftExamTimes);
+		}
+
+		return setCommomScoreInfo(examScore, examStudent.getFinished(), examStudent.getExamStudentId(), examBean,
+				markingType);
+	}
+
+	private ExamScoreInfo setCommomScoreInfo(ExamScoreInfo examScoreInfo, Boolean finished, long examStudentId,
+			ExamSettingsCacheBean examBean, String markingType) {
+		// 查询考试记录
+		if (finished != null && finished) {
+			// 查询考试记录
+			List<ExamRecordDataEntity> examRecordList = examRecordService
+					.getExamRecordListByExamStudentId(examStudentId);
+			examScoreInfo.setIsFinished("是");// 是否完成考试
+			examScoreInfo.setIsAbsent("否");// 是否缺考
+			// 违纪次数
+			examScoreInfo.setDisciplineCount(disciplineCount(examRecordList));
+			// 提交次数
+			examScoreInfo.setSubmitCount(submitCount(examRecordList));
+
+			// 设置相关成绩(总分,主观分,客观分)
+			ExamStudentFinalScoreEntity finalExamScore = examStudentFinalScoreService
+					.getFinalEffectiveExamScore(examStudentId);
+			setFinalExamScore(examScoreInfo, finalExamScore);
+
+			if (finalExamScore != null) {
+				// 违纪未审核 存在最终分为空情况
+				examScoreInfo.setExamRecordDataId(finalExamScore.getExamRecordDataId());
+
+				if (!CollectionUtils.isEmpty(examRecordList)) {
+					for (ExamRecordDataEntity entity : examRecordList) {
+						if (Objects.equals(entity.getId(), finalExamScore.getExamRecordDataId())) {
+							examScoreInfo.setBasePaperId(entity.getBasePaperId());
+						}
+					}
+				}
+			}
+
+			// 需求调整20200923:将开考时间,改为最终成绩的更新时间
+			examScoreInfo.setStartTime(getExamStudentFinalScoreUpdateTime(finalExamScore));
+		} else {
+			examScoreInfo.setIsFinished("否");// 是否完成考试
+			examScoreInfo.setIsAbsent("是");// 是否缺考
+			examScoreInfo.setDisciplineCount("--");// 违纪次数
+			examScoreInfo.setSubmitCount("--"); // 提交次数
+			examScoreInfo.setObjectiveScore("--");// 主观分
+			examScoreInfo.setSubjectiveScore("--");// 客观分
+			examScoreInfo.setFinalExamScore("--");// 最终成绩
+			examScoreInfo.setStartTime("--");// 考试开始时间
+		}
+
+		return examScoreInfo;
+	}
+
+	/**
+	 * 给考生最终成绩赋值
+	 *
+	 * @param examScoreInfo 考试模型实体
+	 * @param examScore     考试数据实体
+	 */
+	private void setFinalExamScore(ExamScoreInfo examScoreInfo, final ExamStudentFinalScoreEntity examScore) {
+		if (examScore == null) {
+			examScoreInfo.setObjectiveScore("0");
+			examScoreInfo.setSubjectiveScore("0");
+			examScoreInfo.setFinalExamScore("0");
+		} else {
+			DecimalFormat decimalFormat = new DecimalFormat("#.##");
+			examScoreInfo.setObjectiveScore(
+					decimalFormat.format(null == examScore.getObjectiveScore() ? 0 : examScore.getObjectiveScore()));
+			examScoreInfo.setSubjectiveScore(
+					decimalFormat.format(null == examScore.getSubjectiveScore() ? 0 : examScore.getSubjectiveScore()));
+			examScoreInfo.setFinalExamScore(
+					decimalFormat.format(null == examScore.getTotalScore() ? 0 : examScore.getTotalScore()));
+		}
+	}
+
+	/**
+	 * 考试开始时间
+	 */
+	private String getExamStudentFinalScoreUpdateTime(ExamStudentFinalScoreEntity examScore) {
+		if (examScore == null || examScore.getUpdateTime() == null) {
+			return "";
+		}
+
+		return CommonUtil.getDateStrWithSecond(examScore.getUpdateTime());
+	}
+
+	/**
+	 * 违纪次数
+	 */
+	private String disciplineCount(List<ExamRecordDataEntity> examRecordList) {
+		Integer disciplineCount = 0;
+		if (examRecordList == null) {
+			return disciplineCount.toString();
+		}
+		for (ExamRecordDataEntity e : examRecordList) {
+			if (e.getIsIllegality() != null && e.getIsIllegality()) {
+				disciplineCount++;
+			}
+		}
+		return disciplineCount.toString();
+	}
+
+	/**
+	 * 正常交卷次数:无警告或者有警告,有审核,有正常提交时间
+	 */
+	private String submitCount(List<ExamRecordDataEntity> examRecordList) {
+		Integer submitCount = 0;
+		for (ExamRecordDataEntity e : examRecordList) {
+			if (e.getIsWarn() == null) {
+				e.setIsWarn(false);
+			}
+			if (e.getIsAudit() == null) {
+				e.setIsAudit(false);
+			}
+			if (e.getIsWarn() && !e.getIsAudit()) {
+				// ignore
+			} else {
+				if (e.getEndTime() != null) {
+					submitCount++;
+				}
+			}
+		}
+		return submitCount.toString();
+	}
+
+	private ExamStudentEntity getExamStudentEntityByResultSet(ResultSet rs) throws SQLException {
+		ExamStudentEntity examStudentEntity = new ExamStudentEntity();
+		examStudentEntity.setId(rs.getLong("id"));
+		examStudentEntity.setExamStudentId(rs.getLong("exam_student_id"));
+		examStudentEntity.setExamId(rs.getLong("exam_id"));
+		examStudentEntity.setCourseId(rs.getLong("course_id"));
+		examStudentEntity.setCourseCode(rs.getString("course_code"));
+		examStudentEntity.setCourseLevel(rs.getString("course_level"));
+		examStudentEntity.setFinished(rs.getBoolean("finished"));
+		examStudentEntity.setStudentId(rs.getLong("student_id"));
+		examStudentEntity.setStudentCode(rs.getString("student_code"));
+		examStudentEntity.setStudentName(rs.getString("student_name"));
+		examStudentEntity.setIdentityNumber(rs.getString("identity_number"));
+		examStudentEntity.setInfoCollector(rs.getString("info_collector"));
+		examStudentEntity.setRootOrgId(rs.getLong("root_org_id"));
+		examStudentEntity.setOrgId(rs.getLong("org_id"));
+		examStudentEntity.setPaperType(rs.getString("paper_type"));
+		examStudentEntity.setUsedNum(rs.getInt("used_num"));
+		examStudentEntity.setExtraNum(rs.getInt("extra_num"));
+		examStudentEntity.setSpecialtyCode(rs.getString("specialty_code"));
+		examStudentEntity.setSpecialtyName(rs.getString("specialty_name"));
+		examStudentEntity.setGrade(rs.getString("grade"));
+		if (rs.getString("exam_stage_id") != null) {
+			examStudentEntity.setExamStageId(rs.getLong("exam_stage_id"));
+		}
+		return examStudentEntity;
+	}
+
+	@Override
+	public void createExamScoreWithOffline(Long examRecordDataId) {
+		ExamScoreEntity examScoreEntity = new ExamScoreEntity();
+		examScoreEntity.setExamRecordDataId(examRecordDataId);
+		examScoreEntity.setObjectiveScore(0D);
+		examScoreEntity.setSubjectiveScore(0D);
+		examScoreEntity.setTotalScore(0D);
+		examScoreRepo.save(examScoreEntity);
+	}
+
+	@Override
+	public List<ObjectiveScoreInfo> queryObjectiveScoreList(Long examStudentId) {
+		Check.isNull(examStudentId, "examStudentId 不能为空");
+
+		List<ExamRecordDataEntity> examRecordDataList = examRecordDataRepo.findByExamStudentId(examStudentId);
+		// 过滤已完成的考试记录(包括违纪的)
+		examRecordDataList = examRecordDataList.stream().filter((o -> {
+			return o.getExamRecordStatus() == ExamRecordStatus.EXAM_END
+					|| o.getExamRecordStatus() == ExamRecordStatus.EXAM_OVERDUE
+					|| o.getExamRecordStatus() == ExamRecordStatus.EXAM_HAND_IN
+					|| o.getExamRecordStatus() == ExamRecordStatus.EXAM_AUTO_HAND_IN;
+		})).collect(Collectors.toList());
+
+		List<ObjectiveScoreInfo> objectiveScoreInfoList = new ArrayList<>();
+		for (ExamRecordDataEntity examRecordDataEntity : examRecordDataList) {
+			ObjectiveScoreInfo objectiveScoreInfo = new ObjectiveScoreInfo();
+			objectiveScoreInfo.setExamRecordDataId(examRecordDataEntity.getId());
+			objectiveScoreInfo.setExamOrder(examRecordDataEntity.getExamOrder());
+			objectiveScoreInfo.setStartTime(examRecordDataEntity.getStartTime());
+			objectiveScoreInfo.setEndTime(examRecordDataEntity.getEndTime());
+
+			// 如果考试没有结束,则只能返回部分数据
+			if (!isExamRecordEnded(examRecordDataEntity)) {
+				objectiveScoreInfo.setIsExamEnded(false);
+				objectiveScoreInfoList.add(objectiveScoreInfo);
+				continue;
+			} else {
+				objectiveScoreInfo.setIsExamEnded(true);
+			}
+
+			if (examRecordDataEntity.getIsIllegality() == null || !examRecordDataEntity.getIsIllegality()) {
+				if (examRecordDataEntity.getIsWarn() && !examRecordDataEntity.getIsAudit()) {
+					objectiveScoreInfo.setIsAuditing(true);
+				} else if (!examRecordDataEntity.getIsWarn()
+						|| (examRecordDataEntity.getIsWarn() && examRecordDataEntity.getIsAudit())) {
+					ExamScoreEntity examScore = examScoreRepo.findByExamRecordDataId(examRecordDataEntity.getId());
+					objectiveScoreInfo.setIsAuditing(false);
+					objectiveScoreInfo.setObjectiveScore(examScore.getObjectiveScore());
+				}
+				objectiveScoreInfo.setIsIllegality(false);
+			} else {
+				objectiveScoreInfo.setIsIllegality(true);
+			}
+			objectiveScoreInfoList.add(objectiveScoreInfo);
+		}
+
+		processObjectiveScoreList(examStudentId, objectiveScoreInfoList);
+
+		return objectiveScoreInfoList;
+	}
+
+	private void processObjectiveScoreList(Long examStudentId, List<ObjectiveScoreInfo> resultList) {
+		// 如果有未处理完成的考试记录,需要将未处理的考试记录数据添加到列表中
+		String examBossKey = RedisKeyHelper.getBuilder().examBossKey(examStudentId);
+		ExamBoss examBoss = redisClient.get(examBossKey, ExamBoss.class);
+		if (null != examBoss) {
+			// 未完全同步的考试记录id
+			List<Long> unSyncedExamRecordDataIds = examBoss.getExamRecordDataIds();
+			if (null != unSyncedExamRecordDataIds && !unSyncedExamRecordDataIds.isEmpty()) {
+				// 正序排列
+				unSyncedExamRecordDataIds.sort(Long::compareTo);
+
+				// 已考次数
+				Integer examUsedNum = 0;
+
+				for (Long examRecordDataId : unSyncedExamRecordDataIds) {
+					ExamRecordData examRecordData = redisClient
+							.get(RedisKeyHelper.getBuilder().examRecordDataKey(examRecordDataId), ExamRecordData.class);
+					if (null == examRecordData) {
+						throw new StatusException("100001", "考试记录的缓存数据有误");
+					}
+
+					// 考试中的数据不展示
+					if (cn.com.qmth.examcloud.support.enums.ExamRecordStatus.EXAM_ING == examRecordData
+							.getExamRecordStatus()) {
+						continue;
+					}
+
+					if (!resultList.isEmpty()) {
+						examUsedNum = resultList.get(resultList.size() - 1).getExamOrder();
+					}
+
+					ObjectiveScoreInfo cachedObjectiveScoreInfo = getCachedObjectiveScoreInfo(examRecordData);
+					cachedObjectiveScoreInfo.setExamOrder(
+							getExamOrder(examRecordData.getExamId(), examRecordData.getStudentId(), examUsedNum));
+
+					resultList.add(cachedObjectiveScoreInfo);
+				}
+			}
+		}
+	}
+
+	private ObjectiveScoreInfo getCachedObjectiveScoreInfo(final ExamRecordData examRecordData) {
+		ObjectiveScoreInfo objectiveScoreInfo = new ObjectiveScoreInfo();
+		objectiveScoreInfo.setExamRecordDataId(examRecordData.getId());
+		objectiveScoreInfo.setStartTime(examRecordData.getStartTime());
+		objectiveScoreInfo.setEndTime(examRecordData.getEndTime());
+
+		// 如果考试没有结束,则只能返回部分数据
+		if (!isExamRecordEnded(examRecordData)) {
+			objectiveScoreInfo.setIsExamEnded(false);
+			return objectiveScoreInfo;
+		} else {
+			objectiveScoreInfo.setIsExamEnded(true);
+		}
+
+		if (examRecordData.getIsIllegality() == null || !examRecordData.getIsIllegality()) {
+			if ((null != examRecordData.getIsWarn() && !examRecordData.getIsWarn())
+					|| (null != examRecordData.getIsWarn() && examRecordData.getIsWarn()
+							&& null != examRecordData.getIsAudit() && examRecordData.getIsAudit())) {
+				objectiveScoreInfo.setIsAuditing(true);
+
+				// 缓存中的分数是存储在临时考试记录表中的,所以需要从考试记录缓存中取
+				objectiveScoreInfo.setObjectiveScore(examRecordData.getObjectiveScore());
+			} else {
+				objectiveScoreInfo.setIsAuditing(false);
+			}
+
+			objectiveScoreInfo.setIsIllegality(false);
+		} else {
+			objectiveScoreInfo.setIsIllegality(true);
+		}
+
+		return objectiveScoreInfo;
+	}
+
+	/**
+	 * 计算考试次数
+	 *
+	 * @param examId      考试id
+	 * @param studentId   学生id
+	 * @param usedExamNum 已考次数
+	 * @return
+	 */
+	private Integer getExamOrder(Long examId, Long studentId, Integer usedExamNum) {
+		ExamSettingsCacheBean cachedExam = ExamCacheTransferHelper.getDefaultCachedExam(examId);
+		Integer canExamTimes = cachedExam.getExamTimes() == null ? 0 : cachedExam.getExamTimes().intValue();// 可考次数
+
+		// 超过可考次数,始终为可考次数+1
+		if (usedExamNum > canExamTimes) {
+			return canExamTimes + 1;
+		}
+
+		return usedExamNum + 1;
+	}
+
+	private boolean isExamRecordEnded(ExamRecordData examRecordData) {
+		// 如果考试记录状态为已处理,则直接返回true.
+		if (examRecordData.getExamRecordStatus() == cn.com.qmth.examcloud.support.enums.ExamRecordStatus.EXAM_END
+				|| examRecordData
+						.getExamRecordStatus() == cn.com.qmth.examcloud.support.enums.ExamRecordStatus.EXAM_OVERDUE
+				|| examRecordData
+						.getExamRecordStatus() == cn.com.qmth.examcloud.support.enums.ExamRecordStatus.EXAM_INVALID) {
+			return true;
+		}
+		return false;
+	}
+
+	private boolean isExamRecordEnded(ExamRecordDataEntity examRecordData) {
+		// 如果考试记录状态为已处理,则直接返回true.
+		if (examRecordData.getExamRecordStatus() == ExamRecordStatus.EXAM_END
+				|| examRecordData.getExamRecordStatus() == ExamRecordStatus.EXAM_OVERDUE
+				|| examRecordData.getExamRecordStatus() == ExamRecordStatus.EXAM_INVALID) {
+			return true;
+		}
+		return false;
+	}
+
+	@Override
+	public void updateCorrectAnswerAndReFixScore(Long examId, Long courseId, Long examStudentId) {
+		List<ExamRecordDataEntity> examRecordDataList = examRecordDataRepo
+				.findByExamIdAndCourseIdAndExamStudentId(examId, courseId, examStudentId);
+		if (CollectionUtils.isEmpty(examRecordDataList)) {
+			log.warn("updateCorrectAnswerAndReFixScore examRecordDataList is empty, examStudentId = {}", examStudentId);
+			return;
+		}
+
+		// Map<试题ID, 正确答案列表>
+		Map<String, List<String>> questionAnswerMaps = new HashMap<>();
+		boolean needUpdateFinalScore = false;
+
+		for (ExamRecordDataEntity examRecordData : examRecordDataList) {
+			if (ExamType.OFFLINE == examRecordData.getExamType()) {
+				// 离线考试,examRecordQuestions实际为空
+				continue;
+			}
+
+			ExamRecordQuestionsEntity examRecordQuestion = examRecordQuestionsService
+					.getExamRecordQuestionsAndFixExamRecordDataIfNecessary(examRecordData);
+			if (examRecordQuestion == null) {
+				log.warn("updateCorrectAnswerAndReFixScore examRecordQuestions is null, examRecordDataId = {}",
+						examRecordData.getId());
+				continue;
+			}
+
+			// 所有客观题的试题ID列表
+			List<ExamQuestionEntity> examQuestions = examRecordQuestion.getExamQuestionEntities();
+			Set<String> objectiveQuestionIds = examQuestions.stream()
+					.filter(e -> QuestionType.isObjective(e.getQuestionType())).map(ExamQuestionEntity::getQuestionId)
+					.collect(Collectors.toSet());
+
+			double objectiveScore = 0d; // 客观题得分
+			int totalObjective = 0; // 客观题总数
+			int totalRightObjective = 0; // 客观题作答正确数
+			boolean needUpdateExamRecordQuestions = false;
+
+			for (String curQuestionId : objectiveQuestionIds) {
+				// 按题号由小到大提取相同题ID的小题列表(注:套题的子题ID相同)
+				List<ExamQuestionEntity> questionUnits = examQuestions.stream()
+						.filter(e -> e.getQuestionId().equals(curQuestionId))
+						.sorted(Comparator.comparingInt(ExamQuestionEntity::getOrder)).collect(Collectors.toList());
+
+				for (ExamQuestionEntity e : questionUnits) {
+					if (QuestionType.isObjective(e.getQuestionType())) {
+						totalObjective++;
+					}
+				}
+
+				// 获取当前题的正确答案
+				List<String> rightAnswers;
+				if (questionAnswerMaps.containsKey(curQuestionId)) {
+					rightAnswers = questionAnswerMaps.get(curQuestionId);
+				} else {
+					QuestionAnswerCacheBean questionAnswer = CacheHelper.getQuestionAnswer(curQuestionId);
+					rightAnswers = questionAnswer.getRightAnswers();
+					questionAnswerMaps.put(curQuestionId, rightAnswers);
+				}
+
+				if (CollectionUtils.isEmpty(rightAnswers)) {
+					log.warn("updateCorrectAnswerAndReFixScore rightAnswers is empty, questionId = {}", curQuestionId);
+					continue;
+				}
+
+				if (questionUnits.size() != rightAnswers.size()) {
+					log.warn("updateCorrectAnswerAndReFixScore rightAnswers incorrect, questionId = {}", curQuestionId);
+					continue;
+				}
+
+				for (int i = 0; i < questionUnits.size(); i++) {
+					ExamQuestionEntity curQuestion = questionUnits.get(i);
+					if (!QuestionType.isObjective(curQuestion.getQuestionType())) {
+						// 跳过套题内主观题
+						continue;
+					}
+
+					// 答案不一致,则更新
+					String rightAnswer = rightAnswers.get(i);
+					if (rightAnswer != null && !rightAnswer.equals(curQuestion.getCorrectAnswer())) {
+						curQuestion.setCorrectAnswer(rightAnswer);
+						needUpdateExamRecordQuestions = true;
+					}
+
+					// 计算得分
+					String correctAnswer = curQuestion.getCorrectAnswer();
+					String studentAnswer = curQuestion.getStudentAnswer();
+					// if (correctAnswer != null &&
+					// QuestionOptionHelper.isEqualAnswer(correctAnswer, studentAnswer)) {
+					if (correctAnswer != null && correctAnswer.equals(studentAnswer)) {
+						objectiveScore += curQuestion.getQuestionScore();
+						totalRightObjective++;
+					}
+				}
+			}
+
+			if (needUpdateExamRecordQuestions) {
+				needUpdateFinalScore = true;
+
+				examRecordQuestionsRepo.save(examRecordQuestion);
+
+				ExamScoreEntity examScore = examScoreRepo.findByExamRecordDataId(examRecordData.getId());
+				if (examScore != null) {
+					double subjectiveScore = examScore.getSubjectiveScore() != null ? examScore.getSubjectiveScore()
+							: 0d;
+
+					double objectiveAccuracy = 0d;// 客观题正确率
+					if (totalObjective > 0) {
+						objectiveAccuracy = totalRightObjective * 100d / totalObjective;
+						objectiveAccuracy = Double.parseDouble(new DecimalFormat("#.00").format(objectiveAccuracy));
+					}
+
+					examScore.setObjectiveScore(objectiveScore);
+					examScore.setObjectiveAccuracy(objectiveAccuracy);
+					examScore.setTotalScore(objectiveScore + subjectiveScore);
+					examScoreRepo.save(examScore);
+				}
+
+				ExamRecordForMarkingEntity examRecordForMarking = examRecordForMarkingRepo
+						.findByExamRecordDataId(examRecordData.getId());
+				if (examRecordForMarking != null) {
+					examRecordForMarking.setObjectiveScore(objectiveScore);
+					examRecordForMarkingRepo.save(examRecordForMarking);
+				}
+
+				log.info("updateCorrectAnswerAndReFixScore examRecordQuestions examRecordDataId = {}",
+						examRecordData.getId());
+			}
+		}
+
+		if (needUpdateFinalScore) {
+			examStudentFinalScoreService.calcAndSaveFinalScore(examStudentId);
+			log.info("updateCorrectAnswerAndReFixScore finalScore examStudentId = {}", examStudentId);
+		}
+	}
 
 }

+ 1347 - 1313
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamStudentServiceImpl.java

@@ -37,6 +37,7 @@ import cn.com.qmth.examcloud.core.oe.admin.service.bean.UserDataRules;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examrecord.ExamRecordFileAnswerInfo;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examstudent.*;
 import cn.com.qmth.examcloud.core.oe.admin.service.cache.ExamStudentCache;
+import cn.com.qmth.examcloud.core.oe.admin.service.util.BatchGetDataUtil;
 import cn.com.qmth.examcloud.examwork.api.ExamCloudService;
 import cn.com.qmth.examcloud.examwork.api.ExamStudentCloudService;
 import cn.com.qmth.examcloud.examwork.api.bean.ExamSpecialSettingsBean;
@@ -90,1318 +91,1351 @@ import static cn.com.qmth.examcloud.core.oe.admin.service.bean.examstudent.ExamS
 @Service
 public class ExamStudentServiceImpl implements ExamStudentService {
 
-    private static final Logger log = LoggerFactory.getLogger(ExamStudentServiceImpl.class);
-
-    @Autowired
-    private ExamStudentRepo examStudentRepo;
-
-    @Autowired
-    private ExamRecordDataRepo examRecordDataRepo;
-
-    @Autowired
-    private ExamRecordForMarkingRepo examRecordForMarkingRepo;
-
-    @Autowired
-    private ExamRecordService examRecordService;
-
-    @Autowired
-    private EntityManager entityManager;
-
-    @Autowired
-    private GainBaseDataService gainBaseDataService;
-
-    @Autowired
-    private JdbcTemplate jdbcTemplate;
-
-    @Autowired
-    private LocalCacheService localCacheService;
-
-    @Autowired
-    private ExamCloudService examCloudService;
-
-    @Autowired
-    private RedisClient redisClient;
-
-    @Autowired
-    private ExamStudentCache examStudentCache;
-
-    @Autowired
-    private ExamStudentFinalScoreService examStudentFinalScoreService;
-
-    @Autowired
-    ExamStudentCloudService examStudentCloudService;
-
-    @Autowired
-    private ExamRecordFileAnswerRepo examRecordFileAnswerRepo;
-
-    @Autowired
-    private StudentCloudService studentCloudService;
-
-    @Transactional
-    @Override
-    public List<Long> saveExamStudentList(List<ExamStudentInfo> examStudents) {
-        Check.isEmpty(examStudents, "考生信息不能为空!");
-        List<Long> examStudentIdList = Lists.newArrayList();
-        //封装并校验数据
-        for (ExamStudentInfo cur : examStudents) {
-            Check.isNull(cur.getRootOrgId(), "顶级机构ID不能为空!");
-            Check.isNull(cur.getOrgId(), "学习中心ID不能为空!");
-            Check.isEmpty(cur.getExamStudentId(), "考生ID不能为空!");
-            Check.isNull(cur.getExamId(), "考试ID不能为空!");
-            Check.isNull(cur.getCourseId(), "课程ID不能为空!");
-            Check.isNull(cur.getStudentId(), "学生ID不能为空!");
-            ExamStudentEntity entity = examStudentRepo.findByExamStudentId(cur.getExamStudentId());
-
-            if (entity == null) {
-                entity = new ExamStudentEntity();
-                entity.setFinished(false);
-                entity.setUsedNum(0);
-                entity.setExtraNum(0);
-                entity.setCreationTime(new Date());
-            }
-
-            entity.setExamStudentId(cur.getExamStudentId());
-            entity.setRootOrgId(cur.getRootOrgId());
-            entity.setOrgId(cur.getOrgId());
-            entity.setExamId(cur.getExamId());
-            entity.setStudentId(cur.getStudentId());
-            entity.setStudentName(cur.getStudentName());
-            entity.setStudentCode(cur.getStudentCode());
-            entity.setCourseId(cur.getCourseId());
-            entity.setCourseCode(cur.getCourseCode());
-            entity.setCourseLevel(cur.getCourseLevel());
-            entity.setIdentityNumber(cur.getIdentityNumber());
-            entity.setInfoCollector(cur.getInfoCollector());
-            entity.setSpecialtyCode(cur.getSpecialtyCode());
-            entity.setSpecialtyName(cur.getSpecialtyName());
-            entity.setPaperType(cur.getPaperType());
-            entity.setGrade(cur.getGrade());
-            entity.setUpdateTime(new Date());
-            entity.setEnable(cur.getEnable());
-            entity.setExamStageId(cur.getExamStageId());
-            entity.setExamStageOrder(cur.getExamStageOrder());
-
-            //保存考生
-            ExamStudentEntity examStudentEntity = examStudentRepo.save(entity);
-
-            examStudentIdList.add(examStudentEntity.getExamStudentId());
-            //已完成 考试,更新考试记录表
-            if (examStudentEntity.getFinished() != null && examStudentEntity.getFinished()) {
-                long examStudentId = examStudentEntity.getExamStudentId();
-                String studentName = examStudentEntity.getStudentName();
-                String studentCode = examStudentEntity.getStudentCode();
-                String infoCollector = examStudentEntity.getInfoCollector();
-                examRecordDataRepo.syncUpdateExamStudentInfo(examStudentId, studentName, studentCode, infoCollector);
-            }
-        }
-
-        return examStudentIdList;
-    }
-
-    @Override
-    public void syncExamStudentPartData(List<ExamStudentPartInfo> examStudents) {
-        Check.isEmpty(examStudents, "考生信息不能为空!");
-        for (ExamStudentPartInfo info : examStudents) {
-            Check.isNull(info.getStudentId(), "学生ID不能为空!");
-            Check.isNull(info.getStudentCode(), "学号不能为空!");
-            Check.isNull(info.getStudentName(), "学生姓名不能为空!");
-            List<ExamStudentEntity> entities = examStudentRepo.findByStudentId(info.getStudentId());
-            if (entities == null || entities.size() == 0) {
-                continue;
-            }
-            for (ExamStudentEntity entity : entities) {
-                //更新学号、姓名等信息
-                entity.setStudentCode(info.getStudentCode());
-                entity.setStudentName(info.getStudentName());
-            }
-            //批量更新
-            examStudentRepo.saveAll(entities);
-        }
-    }
-
-    @Override
-    @Transactional
-    public void syncRemoveExamStudentByExamId(Long examId) {
-        Check.isNull(examId, "考试ID不能为空!");
-        SqlWrapper wrapper = new SqlWrapper()
-                .delete().from("ec_oe_exam_student").where().eq("exam_id", examId);
-        int result = entityManager.createNativeQuery(wrapper.build()).executeUpdate();
-        log.debug(String.format("[syncRemoveExamStudentByExamId] examId = %s size = %s", examId, result));
-    }
-
-    @Override
-    public Page<ExamStudentInfo> getExamStudentListPage(UserDataRules uds, ExamStudentQuery query) {
-        if (uds.getCourseRule().assertEmptyQueryResult() || uds.getOrgRule().assertEmptyQueryResult()) {
-            return Page.empty();
-        }
-        Check.isNull(query, "查询参数不能为空!");
-
-        ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(query.getExamId());
-
-
-        StringBuffer sql = new StringBuffer();
-        sql.append("select id,exam_student_id,exam_id,course_id,course_code,course_level");
-        if ((ExamType.ONLINE.name().equals(examBean.getExamType()) || ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) && query.getFinished() == null) {
-            sql.append(",case when finished = 1 OR t1.exam_student_id in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id=" + query.getExamId() + "  ) then 1 else 0 end finished");
-        } else {
-            sql.append(",finished");
-        }
-
-        sql.append(",student_id,student_code,student_name,identity_number"
-                + ",info_collector,root_org_id,org_id,paper_type,used_num,extra_num"
-                + ",specialty_code,specialty_name,grade,t1.exam_stage_id from ec_oe_exam_student t1 where 1=1 ");
-        sql.append(selectExamStudentConfitionSql(uds, query, examBean.getExamType()));
-        sql.append(" order by id desc");
-        int currentNum = (query.getPageNo() - 1) * query.getPageSize();
-        sql.append(" limit " + currentNum + "," + query.getPageSize());
-        List<ExamStudentEntity> examStudentList = jdbcTemplate.query(sql.toString(), new RowMapper<ExamStudentEntity>() {
-            @Override
-            public ExamStudentEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
-                return getExamStudentEntityByResultSet(rs);
-            }
-        });
-
-        List<ExamStudentInfo> examStudentInfoList = new ArrayList<ExamStudentInfo>();
-        //缓存
-        Map<String, Object> cahcheMap = new HashMap<String, Object>();
-        for (ExamStudentEntity examStudentEntity : examStudentList) {
-            ExamStudentInfo examStudentInfo = buildExamStudentInfo(examStudentEntity, cahcheMap, examBean.getExamType());
-            examStudentInfoList.add(examStudentInfo);
-            if (ExamType.ONLINE.name().equals(examBean.getExamType()) || ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) {
-                if (query.getFinished() != null) {
-                    if (query.getFinished().intValue() == 1) {
-                        examStudentInfo.setFinished(true);
-                        examStudentInfo.setFinishedStatus(FinishStatus.已完成.name());
-                    }
-                    if (query.getFinished().intValue() == 0) {
-                        examStudentInfo.setFinished(false);
-                        examStudentInfo.setFinishedStatus(FinishStatus.未完成.name());
-                    }
-                }
-                countUseExamTimes(examStudentInfo, examBean.getExamType());
-            }
-        }
-        cahcheMap.clear();
-        Pageable pageable = SpecUtils.buildPageable(query.getPageNo(), query.getPageSize());
-        long totalSize = countExamStudent(uds, query, examBean.getExamType());
-        fillStage(examStudentInfoList);
-        return new PageImpl<>(examStudentInfoList, pageable, totalSize);
-    }
-
-    private void fillStage(List<ExamStudentInfo> list) {
-        if (CollectionUtils.isEmpty(list)) {
-            return;
-        }
-        for (ExamStudentInfo info : list) {
-            if (info.getExamStageId() != null) {
-                ExamStageCacheBean stage = CacheHelper.getExamStage(info.getExamId(), info.getExamStageId());
-                info.setExamStageOrder(stage.getStageOrder());
-                info.setStartTime(stage.getStartTime());
-                info.setEndTime(stage.getEndTime());
-            }
-        }
-    }
-
-    private long countExamStudent(UserDataRules uds, ExamStudentQuery query, String examType) {
-        //查询条件
-        StringBuffer sql = new StringBuffer();
-        sql.append("select count(t1.id) from ec_oe_exam_student t1 where 1=1 ");
-        sql.append(selectExamStudentConfitionSql(uds, query, examType));
-        return jdbcTemplate.queryForObject(sql.toString(), Long.class);
-    }
-
-    @Override
-    public List<ExamStudentInfo> getExamStudentInfoListForAsync(UserDataRules uds, ExamStudentQuery query) {
-        Check.isNull(query, "查询参数不能为空!");
-        ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(query.getExamId());
-
-        List<ExamStudentEntity> examStudentList = new ArrayList<ExamStudentEntity>();
-        int pageNo = 1;
-        int pageSize = 200;
-        for (; ; ) {
-            List<ExamStudentEntity> tem = getExamStudentInfoListByPage(uds, query, examBean, pageNo, pageSize);
-            if (tem == null || tem.size() == 0) {
-                break;
-            } else {
-                pageNo++;
-                examStudentList.addAll(tem);
-            }
-        }
-        List<ExamStudentInfo> examStudentInfoList = new ArrayList<ExamStudentInfo>();
-        if (examStudentList == null || examStudentList.size() == 0) {
-            return examStudentInfoList;
-        }
-        for (ExamStudentEntity examStudentEntity : examStudentList) {
-            ExamStudentInfo examStudentInfo = buildExamStudentInfoForExport(examStudentEntity, examBean.getExamType());
-            examStudentInfoList.add(examStudentInfo);
-            if (ExamType.ONLINE.name().equals(examBean.getExamType()) || ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) {
-                if (query.getFinished() != null) {
-                    if (query.getFinished().intValue() == 1) {
-                        examStudentInfo.setFinished(true);
-                        examStudentInfo.setFinishedStatus(FinishStatus.已完成.name());
-                    }
-                    if (query.getFinished().intValue() == 0) {
-                        examStudentInfo.setFinished(false);
-                        examStudentInfo.setFinishedStatus(FinishStatus.未完成.name());
-                    }
-                }
-                countUseExamTimes(examStudentInfo, examBean.getExamType());
-            }
-        }
-        setPhone(examStudentInfoList, query.getRootOrgId());
-        return examStudentInfoList;
-    }
-
-    @Override
-    public List<OnHandExamInfo> queryOnlineExamEndList(Long studentId, ExamType examType) {
-        //只查没有禁用的考生
-        List<ExamStudentEntity> examStudents =
-                examStudentRepo.findByStudentIdAndEnable(studentId, true);
-
-        List<OnHandExamInfo> examStudentDtoList = new ArrayList<>();
-        Date now = new Date();
-        for (ExamStudentEntity examStudent : examStudents) {
-            assemblingExamStudentDto(examStudent, now, examStudentDtoList, true);
-        }
-
-        for (OnHandExamInfo info : examStudentDtoList) {
-            ExamPropertyCacheBean examCycleEnabledCache = CacheHelper.getExamProperty(info.getExamId(), ExamProperties.EXAM_CYCLE_ENABLED.name());
-            if (examCycleEnabledCache != null && StringUtil.isTrue(examCycleEnabledCache.getValue())) {
-                info.setExamCycleEnabled(true);
-
-                ExamPropertyCacheBean examCycleWeekCache = CacheHelper.getExamProperty(info.getExamId(), ExamProperties.EXAM_CYCLE_WEEK.name());
-
-                info.setExamCycleWeek(JSONObject.parseArray(examCycleWeekCache.getValue()));
-                ExamPropertyCacheBean examCycleTimeRangeCache = CacheHelper.getExamProperty(info.getExamId(), ExamProperties.EXAM_CYCLE_TIME_RANGE.name());
-                info.setExamCycleTimeRange(JSONObject.parseArray(examCycleTimeRangeCache.getValue()));
-            } else {
-                info.setExamCycleEnabled(false);
-            }
-
-            info.setExamType(examType.name());
-        }
-
-        return examStudentDtoList;
-    }
-
-    private void setPhone(List<ExamStudentInfo> dataList, Long rootOrgId) {
-        GetStudentListByIdsReq req = new GetStudentListByIdsReq();
-        BatchSetDataUtil<ExamStudentInfo> tool = new BatchSetDataUtil<ExamStudentInfo>() {
-            @Override
-            public void setData(List<ExamStudentInfo> dataList) {
-                req.setRootOrgId(rootOrgId);
-                List<Long> ids = dataList.stream().map(dto -> dto.getStudentId()).distinct().collect(Collectors.toList());
-                req.setStudentIdList(ids);
-                GetStudentListByIdsResp resp = studentCloudService.getStudentListByIds(req);
-                if (resp.getStudentBeanList() != null && resp.getStudentBeanList().size() > 0) {
-                    Map<Long, String> map = resp.getStudentBeanList().stream()
-                            .collect(Collectors.toMap(StudentBean::getId, account -> (account.getPhoneNumber() == null ? "" : account.getPhoneNumber())));
-                    for (ExamStudentInfo erInfo : dataList) {
-                        erInfo.setPhone(map.get(erInfo.getStudentId()));
-                    }
-                }
-            }
-
-        };
-        tool.setDataForBatch(dataList, 100);
-    }
-
-    private List<ExamStudentEntity> getExamStudentInfoListByPage(UserDataRules uds, ExamStudentQuery query, ExamSettingsCacheBean examBean, int pageNo, int pageSize) {
-        //查询条件
-        StringBuffer sql = new StringBuffer();
-        sql.append("select id,exam_student_id,exam_id,course_id,course_code,course_level");
-        if ((ExamType.ONLINE.name().equals(examBean.getExamType()) || ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) && query.getFinished() == null) {
-            sql.append(",case when finished = 1 OR t1.exam_student_id in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id=" + query.getExamId() + "  ) then 1 else 0 end finished");
-        } else {
-            sql.append(",finished");
-        }
-
-        sql.append(",student_id,student_code,student_name,identity_number"
-                + ",info_collector,root_org_id,org_id,paper_type,used_num,extra_num"
-                + ",specialty_code,specialty_name,grade,exam_stage_id from ec_oe_exam_student t1 where 1=1 ");
-        sql.append(selectExamStudentConfitionSql(uds, query, examBean.getExamType()));
-        int currentNum = (pageNo - 1) * pageSize;
-        sql.append(" order by id limit " + currentNum + "," + pageSize);
-
-        List<ExamStudentEntity> examStudentList = jdbcTemplate.query(sql.toString(), new RowMapper<ExamStudentEntity>() {
-            @Override
-            public ExamStudentEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
-                return getExamStudentEntityByResultSet(rs);
-            }
-        });
-
-        return examStudentList;
-    }
-
-    @Override
-    public List<ExamStudentInfo> getExamStudentInfoList(UserDataRules uds, ExamStudentQuery query) {
-        if (uds.getCourseRule().assertEmptyQueryResult() || uds.getOrgRule().assertEmptyQueryResult()) {
-            return Lists.newArrayList();
-        }
-        Check.isNull(query, "查询参数不能为空!");
-        ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(query.getExamId());
-
-        //查询条件
-        StringBuffer sql = new StringBuffer();
-        sql.append("select id,exam_student_id,exam_id,course_id,course_code,course_level");
-        if ((ExamType.ONLINE.name().equals(examBean.getExamType()) || ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) && query.getFinished() == null) {
-            sql.append(",case when finished = 1 OR t1.exam_student_id in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id=" + query.getExamId() + "  ) then 1 else 0 end finished");
-        } else {
-            sql.append(",finished");
-        }
-
-        sql.append(",student_id,student_code,student_name,identity_number"
-                + ",info_collector,root_org_id,org_id,paper_type,used_num,extra_num"
-                + ",specialty_code,specialty_name,grade,t1.exam_stage_id from ec_oe_exam_student t1 where 1=1 ");
-        sql.append(selectExamStudentConfitionSql(uds, query, examBean.getExamType()));
-        sql.append(" order by id desc");
-
-        List<ExamStudentEntity> examStudentList = jdbcTemplate.query(sql.toString(), new RowMapper<ExamStudentEntity>() {
-            @Override
-            public ExamStudentEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
-                return getExamStudentEntityByResultSet(rs);
-            }
-        });
-        List<ExamStudentInfo> examStudentInfoList = new ArrayList<ExamStudentInfo>();
-        //缓存
-        Map<String, Object> cahcheMap = new HashMap<String, Object>();
-        for (ExamStudentEntity examStudentEntity : examStudentList) {
-            ExamStudentInfo examStudentInfo = buildExamStudentInfo(examStudentEntity, cahcheMap, examBean.getExamType());
-            examStudentInfoList.add(examStudentInfo);
-            if (ExamType.ONLINE.name().equals(examBean.getExamType()) || ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) {
-                if (query.getFinished() != null) {
-                    if (query.getFinished().intValue() == 1) {
-                        examStudentInfo.setFinished(true);
-                        examStudentInfo.setFinishedStatus(FinishStatus.已完成.name());
-                    }
-                    if (query.getFinished().intValue() == 0) {
-                        examStudentInfo.setFinished(false);
-                        examStudentInfo.setFinishedStatus(FinishStatus.未完成.name());
-                    }
-                }
-                countUseExamTimes(examStudentInfo, examBean.getExamType());
-            }
-        }
-        cahcheMap.clear();
-        fillStage(examStudentInfoList);
-        return examStudentInfoList;
-    }
-
-    private StringBuffer selectExamStudentConfitionSql(UserDataRules uds, ExamStudentQuery query, String examType) {
-        StringBuffer sql = new StringBuffer();
-        if (query.getOrgId() != null) {
-            sql.append(" and org_id=" + query.getOrgId());
-        }
-        if (query.getExamId() != null) {
-            sql.append(" and exam_id = " + query.getExamId());
-        }
-        if (query.getExamStageId() != null) {
-            sql.append(" and exam_stage_id = " + query.getExamStageId());
-        }
-        if (StringUtils.isNotBlank(query.getStudentCode())) {
-            sql.append(" and student_code LIKE '" + query.getStudentCode() + "%'");
-        }
-        if (StringUtils.isNotBlank(query.getStudentName())) {
-            sql.append(" and student_name LIKE '" + query.getStudentName() + "%'");
-        }
-        if (StringUtils.isNotBlank(query.getIdentityNumber())) {
-            sql.append(" and identity_number LIKE '" + query.getIdentityNumber() + "%'");
-        }
-        if (StringUtils.isNotBlank(query.getInfoCollector())) {
-            sql.append(" and info_collector LIKE '" + query.getInfoCollector() + "%'");
-        }
-        if (query.getCourseId() != null) {
-            sql.append(" and course_id=" + query.getCourseId());
-        }
-        if (StringUtils.isNotBlank(query.getCourseLevel())) {
-            sql.append(" and course_level= '" + query.getCourseLevel() + "'");
-        }
-        if (query.getFinished() != null) {
-            if (ExamType.ONLINE.name().equals(examType) || ExamType.ONLINE_HOMEWORK.name().equals(examType)) {
-                //                sql.append(" and finished = " + query.getFinished());
-                if (query.getFinished().intValue() == 1) {
-                    sql.append(" AND ( finished = 1 OR t1.exam_student_id in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id=" + query.getExamId() + "  )  )");
-                }
-                if (query.getFinished().intValue() == 0) {
-                    sql.append(" AND ( finished = 0 and t1.exam_student_id not in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id=" + query.getExamId() + "  )  )");
-                }
-            } else if (ExamType.OFFLINE.name().equals(examType)) {
-                //如果忽略是否上传答案时,只要是已抽题则认为已参加考试
-                if (query.getIgnoreUploadOfflineAnswer() != null && true == query.getIgnoreUploadOfflineAnswer()) {
-                    sql.append(" and finished = " + query.getFinished());
-                } else {
-                    if (query.getFinished() == 0) {                    //未抽题
-                        sql.append(" and finished = 0");
-                    } else if (query.getFinished() == 1) {                //已抽题未上传
-                        sql.append(" and finished = 1  and not exists (select id from ec_oe_exam_record_4_marking t2 where t1.exam_student_id = t2.exam_student_id)");
-                    } else if (query.getFinished() == 2) {                //已抽题已上传
-                        sql.append(" and finished = 1  and  exists (select id from ec_oe_exam_record_4_marking t2 where t1.exam_student_id = t2.exam_student_id)");
-                    }
-                }
-
-            }
-        }
-        if (uds.getOrgRule().assertNeedQueryRefIds()) {
-            sql.append(" and org_id in (" + StringUtils.join(uds.getOrgRule().getRefIds(), ",") + ") ");
-        }
-        if (uds.getCourseRule().assertNeedQueryRefIds()) {
-            sql.append(" and course_id in (" + StringUtils.join(uds.getCourseRule().getRefIds(), ",") + ") ");
-        }
-        return sql;
-    }
-
-    private ExamStudentInfo buildExamStudentInfoForExport(ExamStudentEntity examStudentEntity, String examType) {
-        ExamStudentInfo examStudentInfo = buildExamStudentInfoBase(examStudentEntity, examType);
-        return examStudentInfo;
-    }
-
-    private ExamStudentInfo buildExamStudentInfoBase(ExamStudentEntity examStudentEntity, String examType) {
-        ExamStudentInfo examStudentInfo = ExamStudentEntityConvert.of(examStudentEntity);
-        examStudentInfo.setExamType(examType);
-        CourseCacheBean courseBean = ExamCacheTransferHelper.getCachedCourse(examStudentInfo.getCourseId());
-        examStudentInfo.setCourseName(courseBean.getName());
-        examStudentInfo.setCourseCode(courseBean.getCode());
-        examStudentInfo.setCourseLevel(CourseLevel.getCourseLevel(courseBean.getLevel()).getTitle());
-
-        OrgCacheBean orgBean = gainBaseDataService.getOrgBean(examStudentInfo.getOrgId());
-        examStudentInfo.setOrgCode(orgBean.getCode());
-        examStudentInfo.setOrgName(orgBean.getName());
-
-        //        String photoNumber = localCacheService.getStudentPhotoNumber(cahcheMap, examStudentInfo.getStudentId());
-        //        examStudentInfo.setPhone(photoNumber);//电话号码
-
-        if (ExamType.ONLINE.name().equals(examType) || ExamType.ONLINE_HOMEWORK.name().equals(examType)) {
-            //完成状态
-            examStudentInfo.setFinishedStatus(examStudentEntity.getFinished() ? FinishStatus.已完成.name() : FinishStatus.未完成.name());
-        } else if (ExamType.OFFLINE.name().equals(examType)) {
-            //离线考试:当前机构是否允许上传附件
-            ExamPropertyCacheBean cachedExamProperty = ExamCacheTransferHelper.getCachedExamProperty(examStudentInfo.getExamId(),
-                    examStudentInfo.getStudentId(), ExamProperties.CAN_UPLOAD_ATTACHMENT.name());
-            if (StringUtils.isNotBlank(cachedExamProperty.getValue())) {
-                examStudentInfo.setCanUploadAttachment(Boolean.valueOf(cachedExamProperty.getValue()));
-            } else {
-                examStudentInfo.setCanUploadAttachment(false);
-            }
-            //完成状态
-            if (!examStudentEntity.getFinished()) {
-                examStudentInfo.setFinishedStatus(FinishStatus.未抽题.name());
-            } else {
-                examStudentInfo.setFinishedStatus(FinishStatus.已抽题.name());
-
-                ExamRecordForMarkingEntity examRecordForMarking = examRecordForMarkingRepo.findTopByExamStudentId(examStudentEntity.getExamStudentId());
-                if (examRecordForMarking != null) {
-                    List<ExamRecordFileAnswerEntity> fileAnswerList = examRecordFileAnswerRepo.findByExamRecordDataId(examRecordForMarking.getExamRecordDataId());
-                    if (null != fileAnswerList && !fileAnswerList.isEmpty()) {
-                        examStudentInfo.setFinishedStatus(FinishStatus.已上传.name());
-                        examStudentInfo.setOfflineFiles(getOfflineFilesFrom(fileAnswerList));
-                    }
-                }
-            }
-        }
-        return examStudentInfo;
-    }
-
-    private ExamStudentInfo buildExamStudentInfo(ExamStudentEntity examStudentEntity, Map<String, Object> cahcheMap, String examType) {
-        ExamStudentInfo examStudentInfo = buildExamStudentInfoBase(examStudentEntity, examType);
-        String photoNumber = localCacheService.getStudentPhotoNumber(cahcheMap, examStudentInfo.getStudentId());
-        examStudentInfo.setPhone(photoNumber);//电话号码
-        return examStudentInfo;
-    }
-
-    private List<ExamRecordFileAnswerInfo> getOfflineFilesFrom(List<ExamRecordFileAnswerEntity> fileAnswerList) {
-        List<ExamRecordFileAnswerInfo> resultList = new ArrayList<>();
-        for (ExamRecordFileAnswerEntity entity : fileAnswerList) {
-            ExamRecordFileAnswerInfo info = new ExamRecordFileAnswerInfo();
-            info.setId(entity.getId());
-            info.setExamRecordDataId(entity.getExamRecordDataId());
-            info.setOfflineFileUrl(FileStorageUtil.realPath(entity.getFileUrl()));
-            info.setOfflineFileName(entity.getFileName());
-            info.setOriginalFileName(entity.getOriginalFileName());
-            info.setFileType(entity.getFileType());
-            info.setSuffix(entity.getSuffix());
-            info.setProperties(entity.getProperties());
-            resultList.add(info);
-        }
-
-        return resultList;
-    }
-
-    private ExamStudentEntity getExamStudentEntityByResultSet(ResultSet rs) throws SQLException {
-        ExamStudentEntity examStudentEntity = new ExamStudentEntity();
-        examStudentEntity.setId(rs.getLong("id"));
-        examStudentEntity.setExamStudentId(rs.getLong("exam_student_id"));
-        examStudentEntity.setExamId(rs.getLong("exam_id"));
-        examStudentEntity.setCourseId(rs.getLong("course_id"));
-        examStudentEntity.setCourseCode(rs.getString("course_code"));
-        examStudentEntity.setCourseLevel(rs.getString("course_level"));
-        examStudentEntity.setFinished(rs.getBoolean("finished"));
-        examStudentEntity.setStudentId(rs.getLong("student_id"));
-        examStudentEntity.setStudentCode(rs.getString("student_code"));
-        examStudentEntity.setStudentName(rs.getString("student_name"));
-        examStudentEntity.setIdentityNumber(rs.getString("identity_number"));
-        examStudentEntity.setInfoCollector(rs.getString("info_collector"));
-        examStudentEntity.setRootOrgId(rs.getLong("root_org_id"));
-        examStudentEntity.setOrgId(rs.getLong("org_id"));
-        examStudentEntity.setPaperType(rs.getString("paper_type"));
-        examStudentEntity.setUsedNum(rs.getInt("used_num"));
-        examStudentEntity.setExtraNum(rs.getInt("extra_num"));
-        examStudentEntity.setSpecialtyCode(rs.getString("specialty_code"));
-        examStudentEntity.setSpecialtyName(rs.getString("specialty_name"));
-        examStudentEntity.setGrade(rs.getString("grade"));
-        if (rs.getString("exam_stage_id") != null) {
-            examStudentEntity.setExamStageId(rs.getLong("exam_stage_id"));
-        }
-
-        return examStudentEntity;
-    }
-
-    @Override
-    public Page<ExamStudentInfo> getReExamineStudentList(UserDataRules uds, ExamStudentQuery query) {
-        if (uds.getCourseRule().assertEmptyQueryResult() || uds.getOrgRule().assertEmptyQueryResult()) {
-            return Page.empty();
-        }
-        //获取考试的默认次数
-        ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(query.getExamId());
-
-        //封装查询条件
-        Pageable pageable = SpecUtils.buildPageable(query.getPageNo(), query.getPageSize());
-        StringBuffer sql = new StringBuffer();
-
-        sql.append("select t.id," +
-                "t.exam_student_id," +
-                "t.exam_id," +
-                "t.student_id," +
-                "t.student_code," +
-                "t.student_name," +
-                "t.identity_number," +
-                "t.course_id," +
-                "t.course_code," +
-                "t.course_level," +
-                "t.org_id," +
-                "t.root_org_id," +
-                "t.specialty_name," +
-                "t.finished," +
-                "t.used_num," +
-                "t.extra_num from ( ");
-        sql.append("SELECT * " +
-                " FROM ec_oe_exam_student student" +
-                " WHERE exam_id = " + examBean.getId() +
-                " AND used_num = extra_num+" + examBean.getExamTimes().longValue() +
-                " AND NOT EXISTS (" +
-                "	SELECT * FROM ec_oe_exam_record_data t1" +
-                "	WHERE" +
-                "		t1.exam_id = " + examBean.getId() + " and student.exam_student_id = t1.exam_student_id" +
-                "	AND t1.exam_record_status = 'EXAM_ING'" +
-                ") ");
-
-        sql.append(" order by student.id desc ");
-        sql.append(") t where 1=1 ");
-        if (query.getOrgId() != null) {
-            sql.append(" and t.org_id = " + query.getOrgId());
-        }
-
-        if (query.getExamStageId() != null) {
-            sql.append(" and t.exam_stage_id = " + query.getExamStageId());
-        }
-
-        if (StringUtils.isNotBlank(query.getStudentCode())) {
-            sql.append(" and t.student_code LIKE '" + query.getStudentCode() + "%'");
-        }
-        if (StringUtils.isNotBlank(query.getStudentName())) {
-            sql.append(" and t.student_name LIKE '" + query.getStudentName() + "%'");
-        }
-        if (StringUtils.isNotBlank(query.getIdentityNumber())) {
-            sql.append(" and t.identity_number LIKE '" + query.getIdentityNumber() + "%'");
-        }
-        if (query.getCourseId() != null && StringUtils.isNotBlank(query.getCourseId() + "")) {
-            sql.append(" and t.course_id=" + query.getCourseId());
-        }
-        if (StringUtils.isNotBlank(query.getCourseLevel())) {
-            sql.append(" and t.course_level= '" + query.getCourseLevel() + "'");
-        }
-        if (uds.getOrgRule().assertNeedQueryRefIds()) {
-            sql.append(" and t.org_id in (" + StringUtils.join(uds.getOrgRule().getRefIds(), ",") + ") ");
-        }
-        if (uds.getCourseRule().assertNeedQueryRefIds()) {
-            sql.append(" and t.course_id in (" + StringUtils.join(uds.getCourseRule().getRefIds(), ",") + ") ");
-        }
-        int currentNum = (query.getPageNo() - 1) * query.getPageSize();
-        sql.append(" limit " + currentNum + "," + query.getPageSize());
-
-        log.info("重考列表sql:" + sql.toString());
-        List<ExamStudentEntity> examStudentList = jdbcTemplate.query(sql.toString(), new RowMapper<ExamStudentEntity>() {
-            @Override
-            public ExamStudentEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
-                ExamStudentEntity examStudentEntity = new ExamStudentEntity();
-                examStudentEntity.setId(rs.getLong("id"));
-                examStudentEntity.setExamStudentId(rs.getLong("exam_student_id"));
-                examStudentEntity.setExamId(rs.getLong("exam_id"));
-                examStudentEntity.setStudentId(rs.getLong("student_id"));
-                examStudentEntity.setStudentCode(rs.getString("student_code"));
-                examStudentEntity.setStudentName(rs.getString("student_name"));
-                examStudentEntity.setIdentityNumber(rs.getString("identity_number"));
-                examStudentEntity.setCourseId(rs.getLong("course_id"));
-                examStudentEntity.setCourseCode(rs.getString("course_code"));
-                examStudentEntity.setCourseLevel(rs.getString("course_level"));
-                examStudentEntity.setOrgId(rs.getLong("org_id"));
-                examStudentEntity.setRootOrgId(rs.getLong("root_org_id"));
-                examStudentEntity.setSpecialtyName(rs.getString("specialty_name"));
-                examStudentEntity.setFinished(rs.getBoolean("finished"));
-                examStudentEntity.setUsedNum(rs.getInt("used_num"));
-                examStudentEntity.setExtraNum(rs.getInt("extra_num"));
-                return examStudentEntity;
-            }
-        });
-        long totalSize = countReExamine(uds, query, examBean);
-        List<ExamStudentInfo> list = new ArrayList<ExamStudentInfo>();
-        for (ExamStudentEntity examStudentEntity : examStudentList) {
-            ExamStudentInfo examStudentInfo = ExamStudentEntityConvert.of(examStudentEntity);
-            OrgCacheBean orgBean = gainBaseDataService.getOrgBean(examStudentInfo.getOrgId());
-            examStudentInfo.setOrgName(orgBean.getName());
-            examStudentInfo.setOrgCode(orgBean.getCode());
-            CourseCacheBean courseBean = ExamCacheTransferHelper.getCachedCourse(examStudentInfo.getCourseId());
-            examStudentInfo.setCourseName(courseBean.getName());
-            list.add(examStudentInfo);
-        }
-        return new PageImpl<>(list, pageable, totalSize);
-    }
-
-    private Long countReExamine(UserDataRules uds, ExamStudentQuery query, ExamSettingsCacheBean examBean) {
-        StringBuffer sql = new StringBuffer();
-        sql.append("SELECT count(*)" +
-                " FROM " +
-                "	ec_oe_exam_student student" +
-                " WHERE" +
-                "	exam_id = " + examBean.getId() +
-                " AND used_num = extra_num+" + examBean.getExamTimes().longValue() +
-                " AND NOT EXISTS (" +
-                "	SELECT * FROM ec_oe_exam_record_data t1" +
-                "	WHERE t1.exam_id = " + examBean.getId() +
-                "   AND student.exam_student_id = t1.exam_student_id" +
-                "	AND t1.exam_record_status = 'EXAM_ING'" +
-                ")");
-        if (query.getOrgId() != null) {
-            sql.append(" and student.org_id = " + query.getOrgId());
-        }
-        if (StringUtils.isNotBlank(query.getStudentCode())) {
-            sql.append(" and student.student_code LIKE '" + query.getStudentCode() + "%'");
-        }
-        if (StringUtils.isNotBlank(query.getStudentName())) {
-            sql.append(" and student.student_name LIKE '" + query.getStudentName() + "%'");
-        }
-        if (StringUtils.isNotBlank(query.getIdentityNumber())) {
-            sql.append(" and student.identity_number LIKE '" + query.getIdentityNumber() + "%'");
-        }
-        if (query.getCourseId() != null && StringUtils.isNotBlank(query.getCourseId() + "")) {
-            sql.append(" and student.course_id=" + query.getCourseId());
-        }
-        if (StringUtils.isNotBlank(query.getCourseLevel())) {
-            sql.append(" and student.course_level= '" + query.getCourseLevel() + "'");
-        }
-        if (uds.getOrgRule().assertNeedQueryRefIds()) {
-            sql.append(" and student.org_id in (" + StringUtils.join(uds.getOrgRule().getRefIds(), ",") + ") ");
-        }
-        if (uds.getCourseRule().assertNeedQueryRefIds()) {
-            sql.append(" and student.course_id in (" + StringUtils.join(uds.getCourseRule().getRefIds(), ",") + ") ");
-        }
-        return jdbcTemplate.queryForObject(sql.toString(), Long.class);
-    }
-
-    @SuppressWarnings({"deprecation", "unchecked", "rawtypes"})
-    @Override
-    public ExamStudentFinishedStatistic getExamStudentStatisticByFinished(Long examId, Long examStageId) {
-        ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(examId);
-        if (ExamType.ONLINE.name().equals(examBean.getExamType()) ||
-                ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) {
-            ExamStudentFinishedStatistic statistic = new ExamStudentFinishedStatistic();
-            StringBuffer totalsql = new StringBuffer();
-            totalsql.append("select count(t1.id) from ec_oe_exam_student t1 where 1=1 ");
-            totalsql.append(" and exam_id = " + examId);
-            if (null != examStageId) {
-                totalsql.append(" and exam_stage_id = " + examStageId);
-            }
-            Integer total = jdbcTemplate.queryForObject(totalsql.toString(), Integer.class);
-
-            StringBuffer finishsql = new StringBuffer();
-            finishsql.append("select count(t1.id) from ec_oe_exam_student t1 where 1=1 ");
-            finishsql.append(" and exam_id = " + examId);
-            if (null != examStageId) {
-                finishsql.append(" and exam_stage_id = " + examStageId);
-            }
-            finishsql.append(" AND ( finished = 1 OR t1.exam_student_id in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id=" + examId + "  )  )");
-            Integer finish = jdbcTemplate.queryForObject(finishsql.toString(), Integer.class);
-            statistic.setFinished(finish);
-            statistic.setUnFinished(total - finish);
-            return statistic;
-        } else {
-            SqlWrapper wrapper = new SqlWrapper()
-                    .select(statisticFinishedColumns())
-                    .from("ec_oe_exam_student").as("student")
-                    .where().eq("student.exam_id", examId);
-            if (null != examStageId) {
-                wrapper.and().eq("student.exam_stage_id", examStageId);
-            }
-
-            Query dataQuery = entityManager.createNativeQuery(wrapper.build());
-            dataQuery.unwrap(NativeQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
-            Map<String, BigDecimal> map = (HashMap) dataQuery.getSingleResult();
-            ExamStudentFinishedStatistic statistic = new ExamStudentFinishedStatistic();
-            if (map != null) {
-                if (map.get("finished") == null) {
-                    statistic.setFinished(0);
-                } else {
-                    statistic.setFinished(map.get("finished").intValue());
-                }
-                if (map.get("unFinished") == null) {
-                    statistic.setUnFinished(0);
-                } else {
-                    statistic.setUnFinished(map.get("unFinished").intValue());
-                }
-            }
-            return statistic;
-        }
-    }
-
-    @SuppressWarnings({"deprecation", "unchecked", "unused"})
-    @Override
-    public List<ExamStudentOrgStatistic> getExamStudentStatisticByOrg(UserDataRule ud, Long examId, Long examStageId, Long orgId) {
-        if (ud.assertEmptyQueryResult()) {
-            return Lists.newArrayList();
-        }
-        ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(examId);
-        if (ExamType.ONLINE.name().equals(examBean.getExamType()) ||
-                ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) {
-            StringBuffer totalsql = new StringBuffer();
-            totalsql.append("select t1.org_id orgId,count(t1.id) totalCount from ec_oe_exam_student t1 where 1=1 ");
-            totalsql.append(" and exam_id = " + examId);
-            if (null != examStageId) {
-                totalsql.append(" and exam_stage_id = " + examStageId);
-            }
-            if (orgId != null) {
-                totalsql.append(" and org_id = " + orgId);
-            }
-            totalsql.append(" group by t1.org_id ");
-            List<ExamStudentOrgStatistic> totalList = jdbcTemplate.query(totalsql.toString(), new BeanPropertyRowMapper<ExamStudentOrgStatistic>(ExamStudentOrgStatistic.class));
-
-            StringBuffer finishsql = new StringBuffer();
-            finishsql.append("select t1.org_id orgId,count(t1.id) finishedCount from ec_oe_exam_student t1 where 1=1 ");
-            finishsql.append(" and exam_id = " + examId);
-            if (null != examStageId) {
-                finishsql.append(" and exam_stage_id = " + examStageId);
-            }
-            if (orgId != null) {
-                finishsql.append(" and org_id = " + orgId);
-            }
-            finishsql.append(" AND ( finished = 1 OR t1.exam_student_id in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id=" + examId + "  ) )");
-            finishsql.append(" group by t1.org_id ");
-
-            List<ExamStudentOrgStatistic> finishList = jdbcTemplate.query(finishsql.toString(), new BeanPropertyRowMapper<ExamStudentOrgStatistic>(ExamStudentOrgStatistic.class));
-
-            Map<Long, ExamStudentOrgStatistic> finishMap = finishList.stream().collect(Collectors.toMap(ExamStudentOrgStatistic::getOrgId, account -> account));
-
-            for (ExamStudentOrgStatistic statistic : totalList) {
-                ExamStudentOrgStatistic finish = finishMap.get(statistic.getOrgId());
-                statistic.setFinishedCount(finish == null ? 0 : finish.getFinishedCount());
-                OrgCacheBean orgBean = gainBaseDataService.getOrgBean(statistic.getOrgId());
-                statistic.setOrgCode(orgBean.getCode());
-                statistic.setOrgName(orgBean.getName());
-                if (statistic.getTotalCount() == 0 || statistic.getFinishedCount() == 0) {
-                    statistic.setFinishedPercent("0");
-                } else {
-                    double percent = (double) statistic.getFinishedCount() / statistic.getTotalCount();
-                    statistic.setFinishedPercent(new DecimalFormat("#.00").format(percent * 100));
-                }
-            }
-            List<ExamStudentOrgStatistic> ret = Lists.newArrayList();
-            for (ExamStudentOrgStatistic statistic : totalList) {
-                if (!ud.assertNeedQueryRefIds() || ud.getRefIds().contains(statistic.getOrgId())) {
-                    ret.add(statistic);
-                }
-            }
-            return ret;
-        } else {
-            SqlWrapper wrapper = new SqlWrapper()
-                    .select(statisticOrgColumns())
-                    .from("ec_oe_exam_student").as("student")
-                    .where().eq("student.exam_id", examId);
-
-            if (null != examStageId) {
-                wrapper.and().eq("student.exam_stage_id", examStageId);
-            }
-            if (orgId != null) {
-                wrapper.and().eq("student.org_id", orgId);
-            }
-            wrapper.groupBy("student.org_id").orderBy("student.org_id", false);
-            Query dataQuery = entityManager.createNativeQuery(wrapper.build());
-            dataQuery.unwrap(NativeQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
-            List<ExamStudentOrgStatistic> examStudentOrgStatisticList = ExamStudentEntityConvert.ofList(dataQuery.getResultList());
-            Map<String, Object> cahcheMap = new HashMap<String, Object>();
-            for (ExamStudentOrgStatistic statistic : examStudentOrgStatisticList) {
-                OrgCacheBean orgBean = gainBaseDataService.getOrgBean(statistic.getOrgId());
-                statistic.setOrgCode(orgBean.getCode());
-                statistic.setOrgName(orgBean.getName());
-            }
-            List<ExamStudentOrgStatistic> ret = Lists.newArrayList();
-            for (ExamStudentOrgStatistic statistic : examStudentOrgStatisticList) {
-                if (!ud.assertNeedQueryRefIds() || ud.getRefIds().contains(statistic.getOrgId())) {
-                    ret.add(statistic);
-                }
-            }
-            return ret;
-        }
-    }
-
-    @Override
-    public ExamStudentInfo getExamStudentInfo(Long examStudentId) {
-        ExamStudentEntity entity = examStudentRepo.findByExamStudentId(examStudentId);
-        return ExamStudentEntityConvert.of(entity);
-    }
-
-    @Override
-    public boolean isEnableExamStudent(Long examStudentId) {
-        ExamStudentEntity entity = examStudentRepo.findByExamStudentId(examStudentId);
-        if (entity == null) {
-            log.warn("ExamStudent is not exist, id is " + examStudentId);
-            throw new StatusException("000500", "考生信息不存在!");
-        }
-
-        return entity.getEnable();
-    }
-
-    @Override
-    public List<Long> findCoursesFromExamStudent(Long examId, Long examStageId, Long orgId) {
-        String sql = "select course_id from ec_oe_exam_student where exam_id = " + examId;
-        if (null != examStageId) {
-            sql += " and exam_stage_id= " + examStageId;
-        }
-        if (orgId != null) {
-            sql += " and org_id = " + orgId;
-        }
-        sql += "  group by course_id";
-        return jdbcTemplate.queryForList(sql, Long.class);
-    }
-
-    @Override
-    @Transactional
-    public void setReexamine(Long examStudentId, String reexamineType, String reexamineDetail) {
-        List<ExamRecordDataEntity> examRecordDataList = examRecordService.getExamRecordListByExamStudentId(examStudentId);
-        //查询出上一次重考的记录
-        Optional<ExamRecordDataEntity> examRecordOptional = examRecordDataList.stream().filter(examRecordData ->
-                examRecordData.getExamRecordStatus() != ExamRecordStatus.EXAM_INVALID
-                        && examRecordData.getIsReexamine() != null
-                        && examRecordData.getIsReexamine()
-        ).findFirst();
-        ExamRecordDataEntity examRecordData = null;
-        if (examRecordOptional.isPresent()) {
-            examRecordData = examRecordOptional.get();
-        }
-        if (examRecordData != null) {
-            //将上一次重考的记录设置成无效
-            examRecordData.setExamRecordStatus(ExamRecordStatus.EXAM_INVALID);
-            examRecordDataRepo.save(examRecordData);
-            //删除生成的阅卷数据,避免传到阅卷
-            ExamRecordForMarkingEntity examRecordForMarking = examRecordForMarkingRepo.findByExamRecordDataId(examRecordData.getId());
-            if (examRecordForMarking != null) {
-                examRecordForMarkingRepo.delete(examRecordForMarking);
-            }
-
-            //重新计算考生的最终分数
-            examStudentFinalScoreService.calcAndSaveFinalScore(examRecordData.getExamStudentId());
-        }
-
-        //考生表重考次数+1
-        ExamStudentEntity examStudent = examStudentRepo.findByExamStudentId(examStudentId);
-        Integer extraExamNum = examStudent.getExtraNum() == null ? 0 : examStudent.getExtraNum();
-        examStudent.setExtraNum(extraExamNum + 1);
-        examStudent.setReexamineType(reexamineType);
-        examStudent.setReexamineDetail(reexamineDetail);
-        examStudentRepo.save(examStudent);
-
-        //刷新考生的缓存
-        examStudentCache.refresh(examStudentId);
-    }
-
-    @Override
-    public List<CourseProgressInfo> queryCourseProgressInfos(UserDataRule ud, Long examId, Long examStageId,
-                                                             Long courseId, String orderColumn) {
-        if (ud.assertEmptyQueryResult()) {
-            return Lists.newArrayList();
-        }
-        if (examId == null) {
-            return null;
-        }
-        ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(examId);
-        if (ExamType.ONLINE.name().equals(examBean.getExamType()) ||
-                ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) {
-            StringBuffer totalsql = new StringBuffer();
-            totalsql.append("select t1.course_id courseId,count(t1.id) allNum from ec_oe_exam_student t1 where 1=1 ");
-            totalsql.append(" and exam_id = " + examId);
-
-            if (null != examStageId) {
-                totalsql.append(" and exam_stage_id = " + examStageId);
-            }
-            if (courseId != null) {
-                totalsql.append(" and course_id = " + courseId);
-            }
-            totalsql.append(" group by t1.course_id ");
-            List<CourseProgressInfo> totalList = jdbcTemplate.query(totalsql.toString(), new BeanPropertyRowMapper<CourseProgressInfo>(CourseProgressInfo.class));
-
-            StringBuffer finishsql = new StringBuffer();
-            finishsql.append("select t1.course_id courseId,count(t1.id) completedNum from ec_oe_exam_student t1 where 1=1 ");
-            finishsql.append(" and exam_id = " + examId);
-
-            if (null != examStageId) {
-                finishsql.append(" and exam_stage_id = " + examStageId);
-            }
-            if (courseId != null) {
-                finishsql.append(" and course_id = " + courseId);
-            }
-            finishsql.append(" AND ( finished = 1 OR t1.exam_student_id in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id=" + examId + "  ))");
-            finishsql.append(" group by t1.course_id ");
-
-            List<CourseProgressInfo> finishList = jdbcTemplate.query(finishsql.toString(), new BeanPropertyRowMapper<CourseProgressInfo>(CourseProgressInfo.class));
-
-            Map<Long, CourseProgressInfo> finishMap = finishList.stream().collect(Collectors.toMap(CourseProgressInfo::getCourseId, account -> account));
-
-            for (CourseProgressInfo statistic : totalList) {
-                CourseProgressInfo finish = finishMap.get(statistic.getCourseId());
-                statistic.setCompletedNum(finish == null ? 0 : finish.getCompletedNum());
-                if (statistic.getAllNum() == 0 || statistic.getCompletedNum() == 0) {
-                    statistic.setCompletedProportion(0.0D);
-                    statistic.setNoCompletedNum(0);
-                } else {
-                    statistic.setNoCompletedNum(statistic.getAllNum() - statistic.getCompletedNum());
-                    double percent = (double) statistic.getCompletedNum() / statistic.getAllNum();
-                    statistic.setCompletedProportion(Double.valueOf(new DecimalFormat("#.00").format(percent * 100)));
-                }
-            }
-            List<CourseProgressInfo> ret = Lists.newArrayList();
-            for (CourseProgressInfo statistic : totalList) {
-                if (!ud.assertNeedQueryRefIds() || ud.getRefIds().contains(statistic.getCourseId())) {
-                    ret.add(statistic);
-                }
-            }
-            return ret;
-        } else {
-            if (StringUtils.isBlank(orderColumn)) {
-                orderColumn = "all_num";
-            }
-            String sql = "select *,ROUND(tb.completed_num/tb.all_num,2)*100 completed_proportion from ( " +
-                    " select " +
-                    " course_id, " +
-                    " sum(case when finished = 1 then 1 else 0 end) completed_num, " +
-                    " sum(case when finished = 0 then 1 else 0 end) no_completed_num, " +
-                    " count(course_id) all_num" +
-                    " from ec_oe_exam_student " +
-                    " where exam_id = " + examId;
-
-            if (null != examStageId) {
-                sql += " and exam_stage_id = " + examStageId;
-            }
-            if (courseId != null) {
-                sql += " and course_id = " + courseId;
-            }
-            sql += " group by course_id ) tb ORDER BY " + orderColumn + " desc";
-
-            List<CourseProgressInfo> totalList = jdbcTemplate.query(sql, new RowMapper<CourseProgressInfo>() {
-                @Override
-                public CourseProgressInfo mapRow(ResultSet rs, int rowNum) throws SQLException {
-                    CourseProgressInfo courseProgressInfo = new CourseProgressInfo();
-                    courseProgressInfo.setCourseId(rs.getLong("course_id"));
-                    courseProgressInfo.setCompletedNum(rs.getInt("completed_num"));
-                    courseProgressInfo.setNoCompletedNum(rs.getInt("no_completed_num"));
-                    courseProgressInfo.setAllNum(rs.getInt("all_num"));
-                    courseProgressInfo.setCompletedProportion(rs.getDouble("completed_proportion"));
-                    return courseProgressInfo;
-                }
-            });
-            List<CourseProgressInfo> ret = Lists.newArrayList();
-            for (CourseProgressInfo statistic : totalList) {
-                if (!ud.assertNeedQueryRefIds() || ud.getRefIds().contains(statistic.getCourseId())) {
-                    ret.add(statistic);
-                }
-            }
-            return ret;
-        }
-    }
-
-    @Override
-    public List<ExamStudentInfo> getLimitExamStudentList(Long examId, Long startId, Integer size) {
-        List<ExamStudentInfo> resultList = new ArrayList<>();
-        List<ExamStudentEntity> studentEntityList = examStudentRepo.getLimitExamStudentList(examId, startId, size);
-        for (ExamStudentEntity se : studentEntityList) {
-            ExamStudentInfo info = new ExamStudentInfo();
-            info.setId(se.getId());
-            info.setExamStudentId(se.getExamStudentId());
-            info.setExamId(se.getExamId());
-            info.setCourseId(se.getCourseId());
-            info.setCourseCode(se.getCourseCode());
-            info.setCourseLevel(se.getCourseLevel());
-            info.setFinished(se.getFinished());
-            info.setStudentId(se.getStudentId());
-            info.setStudentCode(se.getStudentCode());
-            info.setStudentName(se.getStudentName());
-            info.setIdentityNumber(se.getIdentityNumber());
-            info.setInfoCollector(se.getInfoCollector());
-            info.setRootOrgId(se.getRootOrgId());
-            info.setOrgId(se.getOrgId());
-            info.setPaperType(se.getPaperType());
-            info.setUsedNum(se.getUsedNum());
-            info.setExtraNum(se.getExtraNum());
-            info.setSpecialtyCode(se.getSpecialtyCode());
-            info.setSpecialtyName(se.getSpecialtyName());
-            info.setGrade(se.getGrade());
-            resultList.add(info);
-        }
-        return resultList;
-    }
-
-    /**
-     * 根据学生id获取考试列表
-     *
-     * @param studentId 学生id
-     */
-    @Override
-    public List<OnHandExamInfo> queryOnlineExamList(Long studentId, ExamType examType) {
-        StudentCacheBean studentBean = CacheHelper.getStudent(studentId);
-
-        //获取可以考的和即将考的考试Id
-        GetOngoingExamListReq getOngoingExamListReq = new GetOngoingExamListReq();
-        getOngoingExamListReq.setExamType(examType.name());
-        getOngoingExamListReq.setRootOrgId(studentBean.getRootOrgId());
-        getOngoingExamListReq.setOrgId(studentBean.getOrgId());
-        getOngoingExamListReq.setStudentId(studentId);
-        GetOngoingExamListResp getOngoingExamListResp = examCloudService.getOngoingExamList(getOngoingExamListReq);
-
-        //获取学生所在组织机构的所有考试列表集合
-        List<ExamSpecialSettingsBean> examSpecialSettingsBeanList = getOngoingExamListResp.getExamSpecialSettingsList();
-        if (examSpecialSettingsBeanList == null || examSpecialSettingsBeanList.size() == 0) {
-            log.warn("getOngoingExamList size is empty, studentId:{}", studentId);
-            return null;
-        }
-        List<Long> examIds = examSpecialSettingsBeanList.stream().map(ExamSpecialSettingsBean::getExamId).collect(Collectors.toList());
-
-        //只查没有禁用的考生
-        List<ExamStudentEntity> examStudents =
-                examStudentRepo.findByStudentIdAndEnableAndExamIdIn(studentId, true, examIds);
-
-        List<OnHandExamInfo> examStudentDtoList = new ArrayList<OnHandExamInfo>();
-        Date now = new Date();
-        for (ExamStudentEntity examStudent : examStudents) {
-            assemblingExamStudentDto(examStudent, now, examStudentDtoList, false);
-        }
-
-        for (OnHandExamInfo info : examStudentDtoList) {
-            ExamPropertyCacheBean examCycleEnabledCache = CacheHelper.getExamProperty(info.getExamId(), ExamProperties.EXAM_CYCLE_ENABLED.name());
-            if (examCycleEnabledCache != null && StringUtil.isTrue(examCycleEnabledCache.getValue())) {
-                info.setExamCycleEnabled(true);
-
-                ExamPropertyCacheBean examCycleWeekCache = CacheHelper.getExamProperty(info.getExamId(), ExamProperties.EXAM_CYCLE_WEEK.name());
-
-                info.setExamCycleWeek(JSONObject.parseArray(examCycleWeekCache.getValue()));
-                ExamPropertyCacheBean examCycleTimeRangeCache = CacheHelper.getExamProperty(info.getExamId(), ExamProperties.EXAM_CYCLE_TIME_RANGE.name());
-                info.setExamCycleTimeRange(JSONObject.parseArray(examCycleTimeRangeCache.getValue()));
-            } else {
-                info.setExamCycleEnabled(false);
-            }
-            ExamPropertyCacheBean showUndertaking = CacheHelper.getExamProperty(info.getExamId(), ExamProperties.SHOW_UNDERTAKING.name());
-            if (showUndertaking != null && StringUtil.isTrue(showUndertaking.getValue())) {
-                info.setShowUndertaking(true);
-                ExamPropertyCacheBean undertaking = CacheHelper.getExamProperty(info.getExamId(), ExamProperties.UNDERTAKING.name());
-                if (undertaking != null) {
-                    info.setUndertaking(undertaking.getValue());
-                }
-            } else {
-                info.setShowUndertaking(false);
-            }
-
-            info.setExamType(examType.name());
-        }
-
-        return examStudentDtoList;
-    }
-
-    private void assemblingExamStudentDto(ExamStudentEntity examStudent, Date now, final List<OnHandExamInfo> resultList, boolean end) {
-        Long examId = examStudent.getExamId();
-        Long studentId = examStudent.getStudentId();
-        Long examStageId = examStudent.getExamStageId();
-
-        ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getCachedExam(examId, studentId, examStageId);
-
-        if (end && !ExamType.ONLINE.name().equals(examBean.getExamType())) {
-            return;
-        }
-
-        if (examBean.getSpecialSettingsEnabled() && examStageId != null
-                && ExamSpecialSettingsType.STAGE_BASED == examBean.getSpecialSettingsType()) {
-            ExamStageCacheBean examStage = CacheHelper.getExamStage(examId, examStageId);
-
-            //场次如果禁用,该场次不允许考试
-            if (examStage.getHasValue() && !examStage.getEnable()) {
-                return;
-            }
-        }
-
-        if (end) {
-            Calendar calendar = Calendar.getInstance();
-            calendar.setTime(examBean.getEndTime());
-            calendar.add(Calendar.DATE, 30);
-            Date leftTime = calendar.getTime();
-            //已结束且结束时间30天以内的
-            if (now.after(leftTime) || now.before(examBean.getEndTime())) {
-                return;
-            }
-        } else {
-            if (now.after(examBean.getEndTime())) {
-                return;
-            }
-        }
-
-        OnHandExamInfo examStudentInfo = new OnHandExamInfo();
-
-
-        examStudentInfo.setExamStudentId(examStudent.getExamStudentId());
-        examStudentInfo.setStudentCode(examStudent.getStudentCode());
-        examStudentInfo.setStudentName(examStudent.getStudentName());
-        Long rootOrgId = examStudent.getRootOrgId();
-        examStudentInfo.setRootOrgId(rootOrgId);
-        examStudentInfo.setIdentityNumber(examStudent.getIdentityNumber());
-
-        CourseCacheBean courseBean = ExamCacheTransferHelper.getCachedCourse(examStudent.getCourseId());
-        examStudentInfo.setCourseName(courseBean.getName());
-        examStudentInfo.setCourseCode(courseBean.getCode());
-        examStudentInfo.setCourseLevel(CourseLevel.getCourseLevel(courseBean.getLevel()).getTitle());
-        examStudentInfo.setCourseId(examStudent.getCourseId());
-        examStudentInfo.setSpecialtyName(examStudent.getSpecialtyName());
-        Long orgId = examStudent.getOrgId();
-        examStudentInfo.setOrgId(orgId);
-
-        OrgCacheBean orgBean = gainBaseDataService.getOrgBean(orgId);
-
-        examStudentInfo.setOrgName(orgBean.getName());
-        examStudentInfo.setExamId(examId);
-        examStudentInfo.setExamName(examBean.getName());
-        examStudentInfo.setStartTime(examBean.getBeginTime());//考试开始时间设置
-        examStudentInfo.setEndTime(examBean.getEndTime());//考试结束时间设置
-        examStudentInfo.setAllowExamCount(countExamTimes(examStudent, examBean));
-        examStudentInfo.setPaperMins(examBean.getDuration());
-        //是否启用人脸识别
-        examStudentInfo.setFaceEnable(FaceBiopsyHelper.isFaceEnable(rootOrgId, examId, studentId));
-        //进入考试是否验证人脸识别(强制、非强制)
-        examStudentInfo.setFaceCheck(FaceBiopsyHelper.isFaceCheck(examId, studentId));
-
-        //是否显示客观分
-        String isObjScoreView = ExamCacheTransferHelper.getCachedExamProperty(examId,
-                studentId, ExamProperties.IS_OBJ_SCORE_VIEW.name()).getValue();
-        if (StringUtils.isBlank(isObjScoreView)) {
-            examStudentInfo.setIsObjScoreView(false);
-        } else {
-            examStudentInfo.setIsObjScoreView(Boolean.valueOf(isObjScoreView));
-        }
-        if (end && !examStudentInfo.getIsObjScoreView()) {
-            return;
-        }
-
-        //是否开放app考试
-        String appExamEnabled = ExamCacheTransferHelper.getCachedExamProperty(examId,
-                studentId, ExamProperties.APP_EXAM_ENABLED.name()).getValue();
-        if (StringUtils.isBlank(isObjScoreView)) {
-            examStudentInfo.setAppExamEnabled(false);
-        } else {
-            examStudentInfo.setAppExamEnabled(Boolean.valueOf(appExamEnabled));
-        }
-
-        resultList.add(examStudentInfo);
-
-    }
-
-    private Integer countExamTimes(ExamStudentEntity examStudentInfo, ExamSettingsCacheBean examBean) {
-        if (ExamType.OFFLINE.name().equals(examBean.getExamType())) {
-            return 1;
-        }
-        //考试批次中设置的考试次数
-        int canExamTimes = examBean.getExamTimes().intValue();
-        //可补考次数
-        int extraNum = (examStudentInfo.getExtraNum() == null ? 0 : examStudentInfo.getExtraNum());
-        //考生已考次数
-        int usedNum = (examStudentInfo.getUsedNum() == null ? 0 : examStudentInfo.getUsedNum());
-        //缓存中开考次数
-        int startCount = 0;
-        //缓存中考试完结次数
-        int endCount = 0;
-        String key = RedisKeyHelper.getBuilder().examBossKey(examStudentInfo.getExamStudentId());
-        ExamBoss eb = redisClient.get(key, ExamBoss.class);
-        if (eb != null) {
-            startCount = eb.getStartCount();
-            endCount = eb.getEndCount();
-        }
-        Integer ret = canExamTimes + extraNum - (usedNum + startCount - endCount);
-        if (ret < 0) {
-            ret = 0;
-        }
-        return ret;
-    }
-
-    private void countUseExamTimes(ExamStudentInfo examStudentInfo, String examType) {
-        if (!ExamType.ONLINE.name().equals(examType) && !ExamType.ONLINE_HOMEWORK.name().equals(examType)) {
-            return;
-        }
-        //考生已考次数
-        int usedNum = (examStudentInfo.getUsedNum() == null ? 0 : examStudentInfo.getUsedNum());
-        //缓存中开考次数
-        int startCount = 0;
-        //缓存中考试完结次数
-        int endCount = 0;
-        String key = RedisKeyHelper.getBuilder().examBossKey(examStudentInfo.getExamStudentId());
-        ExamBoss eb = redisClient.get(key, ExamBoss.class);
-        if (eb != null) {
-            startCount = eb.getStartCount();
-            endCount = eb.getEndCount();
-        }
-        Integer ret = usedNum + startCount - endCount;
-        if (ret < 0) {
-            ret = 0;
-        }
-        examStudentInfo.setUsedNum(ret);
-    }
-
-    @Override
-    public Page<ExamStudentEntity> getExamStudentSimpleList(ExamStudentQuery req) {
-        if (req.getPageNo() == null || req.getPageNo() < 1) {
-            req.setPageNo(1);
-        }
-
-        if (req.getPageSize() == null || req.getPageSize() < 1) {
-            req.setPageSize(10);
-        }
-
-        if (req.getExamId() == null) {
-            throw new StatusException("考试ID不能为空!");
-        }
-
-        Specification<ExamStudentEntity> spec = (root, query, cb) -> {
-            List<Predicate> predicates = new ArrayList<>();
-            predicates.add(cb.equal(root.get("examId"), req.getExamId()));
-
-            if (req.getCourseId() != null) {
-                predicates.add(cb.equal(root.get("courseId"), req.getCourseId()));
-            }
-
-            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
-        };
-
-        Sort sort = Sort.by(Sort.Order.desc("id"));
-        Pageable pageable = PageRequest.of(req.getPageNo() - 1, req.getPageSize(), sort);
-        return examStudentRepo.findAll(spec, pageable);
-    }
-
-    //    //获取考试的考生信息
-    //    private ExamStudentBean getRemoteExamStudent(Long rootOrgId, Long examStudentId) {
-    //        GetExamStudentReq req = new GetExamStudentReq();
-    //        req.setExamStudentId(examStudentId);
-    //        req.setRootOrgId(rootOrgId);
-    //        GetExamStudentResp resp = examStudentCloudService.getExamStudent(req);
-    //        return resp.getExamStudentBean();
-    //    }
+	private static final Logger log = LoggerFactory.getLogger(ExamStudentServiceImpl.class);
+
+	@Autowired
+	private ExamStudentRepo examStudentRepo;
+
+	@Autowired
+	private ExamRecordDataRepo examRecordDataRepo;
+
+	@Autowired
+	private ExamRecordForMarkingRepo examRecordForMarkingRepo;
+
+	@Autowired
+	private ExamRecordService examRecordService;
+
+	@Autowired
+	private EntityManager entityManager;
+
+	@Autowired
+	private GainBaseDataService gainBaseDataService;
+
+	@Autowired
+	private JdbcTemplate jdbcTemplate;
+
+	@Autowired
+	private LocalCacheService localCacheService;
+
+	@Autowired
+	private ExamCloudService examCloudService;
+
+	@Autowired
+	private RedisClient redisClient;
+
+	@Autowired
+	private ExamStudentCache examStudentCache;
+
+	@Autowired
+	private ExamStudentFinalScoreService examStudentFinalScoreService;
+
+	@Autowired
+	ExamStudentCloudService examStudentCloudService;
+
+	@Autowired
+	private ExamRecordFileAnswerRepo examRecordFileAnswerRepo;
+
+	@Autowired
+	private StudentCloudService studentCloudService;
+
+	@Transactional
+	@Override
+	public List<Long> saveExamStudentList(List<ExamStudentInfo> examStudents) {
+		Check.isEmpty(examStudents, "考生信息不能为空!");
+		List<Long> examStudentIdList = Lists.newArrayList();
+		// 封装并校验数据
+		for (ExamStudentInfo cur : examStudents) {
+			Check.isNull(cur.getRootOrgId(), "顶级机构ID不能为空!");
+			Check.isNull(cur.getOrgId(), "学习中心ID不能为空!");
+			Check.isEmpty(cur.getExamStudentId(), "考生ID不能为空!");
+			Check.isNull(cur.getExamId(), "考试ID不能为空!");
+			Check.isNull(cur.getCourseId(), "课程ID不能为空!");
+			Check.isNull(cur.getStudentId(), "学生ID不能为空!");
+			ExamStudentEntity entity = examStudentRepo.findByExamStudentId(cur.getExamStudentId());
+
+			if (entity == null) {
+				entity = new ExamStudentEntity();
+				entity.setFinished(false);
+				entity.setUsedNum(0);
+				entity.setExtraNum(0);
+				entity.setCreationTime(new Date());
+			}
+
+			entity.setExamStudentId(cur.getExamStudentId());
+			entity.setRootOrgId(cur.getRootOrgId());
+			entity.setOrgId(cur.getOrgId());
+			entity.setExamId(cur.getExamId());
+			entity.setStudentId(cur.getStudentId());
+			entity.setStudentName(cur.getStudentName());
+			entity.setStudentCode(cur.getStudentCode());
+			entity.setCourseId(cur.getCourseId());
+			entity.setCourseCode(cur.getCourseCode());
+			entity.setCourseLevel(cur.getCourseLevel());
+			entity.setIdentityNumber(cur.getIdentityNumber());
+			entity.setInfoCollector(cur.getInfoCollector());
+			entity.setSpecialtyCode(cur.getSpecialtyCode());
+			entity.setSpecialtyName(cur.getSpecialtyName());
+			entity.setPaperType(cur.getPaperType());
+			entity.setGrade(cur.getGrade());
+			entity.setUpdateTime(new Date());
+			entity.setEnable(cur.getEnable());
+			entity.setExamStageId(cur.getExamStageId());
+			entity.setExamStageOrder(cur.getExamStageOrder());
+
+			// 保存考生
+			ExamStudentEntity examStudentEntity = examStudentRepo.save(entity);
+
+			examStudentIdList.add(examStudentEntity.getExamStudentId());
+			// 已完成 考试,更新考试记录表
+			if (examStudentEntity.getFinished() != null && examStudentEntity.getFinished()) {
+				long examStudentId = examStudentEntity.getExamStudentId();
+				String studentName = examStudentEntity.getStudentName();
+				String studentCode = examStudentEntity.getStudentCode();
+				String infoCollector = examStudentEntity.getInfoCollector();
+				examRecordDataRepo.syncUpdateExamStudentInfo(examStudentId, studentName, studentCode, infoCollector);
+			}
+		}
+
+		return examStudentIdList;
+	}
+
+	@Override
+	public void syncExamStudentPartData(List<ExamStudentPartInfo> examStudents) {
+		Check.isEmpty(examStudents, "考生信息不能为空!");
+		for (ExamStudentPartInfo info : examStudents) {
+			Check.isNull(info.getStudentId(), "学生ID不能为空!");
+			Check.isNull(info.getStudentCode(), "学号不能为空!");
+			Check.isNull(info.getStudentName(), "学生姓名不能为空!");
+			List<ExamStudentEntity> entities = examStudentRepo.findByStudentId(info.getStudentId());
+			if (entities == null || entities.size() == 0) {
+				continue;
+			}
+			for (ExamStudentEntity entity : entities) {
+				// 更新学号、姓名等信息
+				entity.setStudentCode(info.getStudentCode());
+				entity.setStudentName(info.getStudentName());
+			}
+			// 批量更新
+			examStudentRepo.saveAll(entities);
+		}
+	}
+
+	@Override
+	@Transactional
+	public void syncRemoveExamStudentByExamId(Long examId) {
+		Check.isNull(examId, "考试ID不能为空!");
+		SqlWrapper wrapper = new SqlWrapper().delete().from("ec_oe_exam_student").where().eq("exam_id", examId);
+		int result = entityManager.createNativeQuery(wrapper.build()).executeUpdate();
+		log.debug(String.format("[syncRemoveExamStudentByExamId] examId = %s size = %s", examId, result));
+	}
+
+	@Override
+	public Page<ExamStudentInfo> getExamStudentListPage(UserDataRules uds, ExamStudentQuery query) {
+		if (uds.getCourseRule().assertEmptyQueryResult() || uds.getOrgRule().assertEmptyQueryResult()) {
+			return Page.empty();
+		}
+		Check.isNull(query, "查询参数不能为空!");
+
+		ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(query.getExamId());
+
+		StringBuffer sql = new StringBuffer();
+		sql.append("select id,exam_student_id,exam_id,course_id,course_code,course_level");
+		if ((ExamType.ONLINE.name().equals(examBean.getExamType())
+				|| ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) && query.getFinished() == null) {
+			sql.append(
+					",case when finished = 1 OR t1.exam_student_id in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id="
+							+ query.getExamId() + "  ) then 1 else 0 end finished");
+		} else {
+			sql.append(",finished");
+		}
+
+		sql.append(",student_id,student_code,student_name,identity_number"
+				+ ",info_collector,root_org_id,org_id,paper_type,used_num,extra_num"
+				+ ",specialty_code,specialty_name,grade,t1.exam_stage_id from ec_oe_exam_student t1 where 1=1 ");
+		sql.append(selectExamStudentConfitionSql(uds, query, examBean.getExamType()));
+		sql.append(" order by id desc");
+		int currentNum = (query.getPageNo() - 1) * query.getPageSize();
+		sql.append(" limit " + currentNum + "," + query.getPageSize());
+		List<ExamStudentEntity> examStudentList = jdbcTemplate.query(sql.toString(),
+				new RowMapper<ExamStudentEntity>() {
+					@Override
+					public ExamStudentEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
+						return getExamStudentEntityByResultSet(rs);
+					}
+				});
+
+		List<ExamStudentInfo> examStudentInfoList = new ArrayList<ExamStudentInfo>();
+		// 缓存
+		Map<String, Object> cahcheMap = new HashMap<String, Object>();
+		for (ExamStudentEntity examStudentEntity : examStudentList) {
+			ExamStudentInfo examStudentInfo = buildExamStudentInfo(examStudentEntity, cahcheMap,
+					examBean.getExamType());
+			examStudentInfoList.add(examStudentInfo);
+			if (ExamType.ONLINE.name().equals(examBean.getExamType())
+					|| ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) {
+				if (query.getFinished() != null) {
+					if (query.getFinished().intValue() == 1) {
+						examStudentInfo.setFinished(true);
+						examStudentInfo.setFinishedStatus(FinishStatus.已完成.name());
+					}
+					if (query.getFinished().intValue() == 0) {
+						examStudentInfo.setFinished(false);
+						examStudentInfo.setFinishedStatus(FinishStatus.未完成.name());
+					}
+				}
+				countUseExamTimes(examStudentInfo, examBean.getExamType());
+			}
+		}
+		cahcheMap.clear();
+		Pageable pageable = SpecUtils.buildPageable(query.getPageNo(), query.getPageSize());
+		long totalSize = countExamStudent(uds, query, examBean.getExamType());
+		fillStage(examStudentInfoList);
+		return new PageImpl<>(examStudentInfoList, pageable, totalSize);
+	}
+
+	private void fillStage(List<ExamStudentInfo> list) {
+		if (CollectionUtils.isEmpty(list)) {
+			return;
+		}
+		for (ExamStudentInfo info : list) {
+			if (info.getExamStageId() != null) {
+				ExamStageCacheBean stage = CacheHelper.getExamStage(info.getExamId(), info.getExamStageId());
+				info.setExamStageOrder(stage.getStageOrder());
+				info.setStartTime(stage.getStartTime());
+				info.setEndTime(stage.getEndTime());
+			}
+		}
+	}
+
+	private long countExamStudent(UserDataRules uds, ExamStudentQuery query, String examType) {
+		// 查询条件
+		StringBuffer sql = new StringBuffer();
+		sql.append("select count(t1.id) from ec_oe_exam_student t1 where 1=1 ");
+		sql.append(selectExamStudentConfitionSql(uds, query, examType));
+		return jdbcTemplate.queryForObject(sql.toString(), Long.class);
+	}
+
+	@Override
+	public List<ExamStudentInfo> getExamStudentInfoListForAsync(UserDataRules uds, ExamStudentQuery query) {
+		Check.isNull(query, "查询参数不能为空!");
+		ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(query.getExamId());
+		List<ExamStudentInfo> examStudentInfoList = new ArrayList<ExamStudentInfo>();
+		List<Long> ids = getExamStudentInfoListByPageOnlyId(uds, query, examBean);
+		if (CollectionUtils.isEmpty(ids)) {
+			return examStudentInfoList;
+		}
+		List<ExamStudentEntity> examStudentList = new BatchGetDataUtil<ExamStudentEntity, Long>() {
+
+			@Override
+			protected List<ExamStudentEntity> getData(List<Long> paramList) {
+				return getExamStudentInfoListByPage(uds, query, examBean, paramList);
+			}
+		}.getDataForBatch(ids, 1000);
+
+		if (CollectionUtils.isEmpty(examStudentList)) {
+			return examStudentInfoList;
+		}
+		for (ExamStudentEntity examStudentEntity : examStudentList) {
+			ExamStudentInfo examStudentInfo = buildExamStudentInfoForExport(examStudentEntity, examBean.getExamType());
+			examStudentInfoList.add(examStudentInfo);
+			if (ExamType.ONLINE.name().equals(examBean.getExamType())
+					|| ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) {
+				if (query.getFinished() != null) {
+					if (query.getFinished().intValue() == 1) {
+						examStudentInfo.setFinished(true);
+						examStudentInfo.setFinishedStatus(FinishStatus.已完成.name());
+					}
+					if (query.getFinished().intValue() == 0) {
+						examStudentInfo.setFinished(false);
+						examStudentInfo.setFinishedStatus(FinishStatus.未完成.name());
+					}
+				}
+				countUseExamTimes(examStudentInfo, examBean.getExamType());
+			}
+		}
+		setPhone(examStudentInfoList, query.getRootOrgId());
+		return examStudentInfoList;
+	}
+
+	@Override
+	public List<OnHandExamInfo> queryOnlineExamEndList(Long studentId, ExamType examType) {
+		// 只查没有禁用的考生
+		List<ExamStudentEntity> examStudents = examStudentRepo.findByStudentIdAndEnable(studentId, true);
+
+		List<OnHandExamInfo> examStudentDtoList = new ArrayList<>();
+		Date now = new Date();
+		for (ExamStudentEntity examStudent : examStudents) {
+			assemblingExamStudentDto(examStudent, now, examStudentDtoList, true);
+		}
+
+		for (OnHandExamInfo info : examStudentDtoList) {
+			ExamPropertyCacheBean examCycleEnabledCache = CacheHelper.getExamProperty(info.getExamId(),
+					ExamProperties.EXAM_CYCLE_ENABLED.name());
+			if (examCycleEnabledCache != null && StringUtil.isTrue(examCycleEnabledCache.getValue())) {
+				info.setExamCycleEnabled(true);
+
+				ExamPropertyCacheBean examCycleWeekCache = CacheHelper.getExamProperty(info.getExamId(),
+						ExamProperties.EXAM_CYCLE_WEEK.name());
+
+				info.setExamCycleWeek(JSONObject.parseArray(examCycleWeekCache.getValue()));
+				ExamPropertyCacheBean examCycleTimeRangeCache = CacheHelper.getExamProperty(info.getExamId(),
+						ExamProperties.EXAM_CYCLE_TIME_RANGE.name());
+				info.setExamCycleTimeRange(JSONObject.parseArray(examCycleTimeRangeCache.getValue()));
+			} else {
+				info.setExamCycleEnabled(false);
+			}
+
+			info.setExamType(examType.name());
+		}
+
+		return examStudentDtoList;
+	}
+
+	private void setPhone(List<ExamStudentInfo> dataList, Long rootOrgId) {
+		GetStudentListByIdsReq req = new GetStudentListByIdsReq();
+		BatchSetDataUtil<ExamStudentInfo> tool = new BatchSetDataUtil<ExamStudentInfo>() {
+			@Override
+			public void setData(List<ExamStudentInfo> dataList) {
+				req.setRootOrgId(rootOrgId);
+				List<Long> ids = dataList.stream().map(dto -> dto.getStudentId()).distinct()
+						.collect(Collectors.toList());
+				req.setStudentIdList(ids);
+				GetStudentListByIdsResp resp = studentCloudService.getStudentListByIds(req);
+				if (resp.getStudentBeanList() != null && resp.getStudentBeanList().size() > 0) {
+					Map<Long, String> map = resp.getStudentBeanList().stream()
+							.collect(Collectors.toMap(StudentBean::getId,
+									account -> (account.getPhoneNumber() == null ? "" : account.getPhoneNumber())));
+					for (ExamStudentInfo erInfo : dataList) {
+						erInfo.setPhone(map.get(erInfo.getStudentId()));
+					}
+				}
+			}
+
+		};
+		tool.setDataForBatch(dataList, 100);
+	}
+
+	private List<ExamStudentEntity> getExamStudentInfoListByPage(UserDataRules uds, ExamStudentQuery query,
+			ExamSettingsCacheBean examBean, List<Long> ids) {
+		// 查询条件
+		StringBuffer sql = new StringBuffer();
+		sql.append("select id,exam_student_id,exam_id,course_id,course_code,course_level");
+		if ((ExamType.ONLINE.name().equals(examBean.getExamType())
+				|| ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) && query.getFinished() == null) {
+			sql.append(
+					",case when finished = 1 OR t1.exam_student_id in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id="
+							+ query.getExamId() + "  ) then 1 else 0 end finished");
+		} else {
+			sql.append(",finished");
+		}
+
+		sql.append(",student_id,student_code,student_name,identity_number"
+				+ ",info_collector,root_org_id,org_id,paper_type,used_num,extra_num"
+				+ ",specialty_code,specialty_name,grade,exam_stage_id from ec_oe_exam_student t1 where id in (");
+		sql.append(StringUtils.join(ids, ","));
+		sql.append(" )");
+
+		List<ExamStudentEntity> examStudentList = jdbcTemplate.query(sql.toString(),
+				new RowMapper<ExamStudentEntity>() {
+					@Override
+					public ExamStudentEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
+						return getExamStudentEntityByResultSet(rs);
+					}
+				});
+
+		return examStudentList;
+	}
+
+	private List<Long> getExamStudentInfoListByPageOnlyId(UserDataRules uds, ExamStudentQuery query,
+			ExamSettingsCacheBean examBean) {
+		// 查询条件
+		StringBuffer sql = new StringBuffer();
+		sql.append("select id from ec_oe_exam_student t1 where 1=1 ");
+		sql.append(selectExamStudentConfitionSql(uds, query, examBean.getExamType()));
+		List<Long> examStudentList = jdbcTemplate.queryForList(sql.toString(), Long.class);
+
+		return examStudentList;
+	}
+
+	@Override
+	public List<ExamStudentInfo> getExamStudentInfoList(UserDataRules uds, ExamStudentQuery query) {
+		if (uds.getCourseRule().assertEmptyQueryResult() || uds.getOrgRule().assertEmptyQueryResult()) {
+			return Lists.newArrayList();
+		}
+		Check.isNull(query, "查询参数不能为空!");
+		ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(query.getExamId());
+
+		// 查询条件
+		StringBuffer sql = new StringBuffer();
+		sql.append("select id,exam_student_id,exam_id,course_id,course_code,course_level");
+		if ((ExamType.ONLINE.name().equals(examBean.getExamType())
+				|| ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) && query.getFinished() == null) {
+			sql.append(
+					",case when finished = 1 OR t1.exam_student_id in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id="
+							+ query.getExamId() + "  ) then 1 else 0 end finished");
+		} else {
+			sql.append(",finished");
+		}
+
+		sql.append(",student_id,student_code,student_name,identity_number"
+				+ ",info_collector,root_org_id,org_id,paper_type,used_num,extra_num"
+				+ ",specialty_code,specialty_name,grade,t1.exam_stage_id from ec_oe_exam_student t1 where 1=1 ");
+		sql.append(selectExamStudentConfitionSql(uds, query, examBean.getExamType()));
+		sql.append(" order by id desc");
+
+		List<ExamStudentEntity> examStudentList = jdbcTemplate.query(sql.toString(),
+				new RowMapper<ExamStudentEntity>() {
+					@Override
+					public ExamStudentEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
+						return getExamStudentEntityByResultSet(rs);
+					}
+				});
+		List<ExamStudentInfo> examStudentInfoList = new ArrayList<ExamStudentInfo>();
+		// 缓存
+		Map<String, Object> cahcheMap = new HashMap<String, Object>();
+		for (ExamStudentEntity examStudentEntity : examStudentList) {
+			ExamStudentInfo examStudentInfo = buildExamStudentInfo(examStudentEntity, cahcheMap,
+					examBean.getExamType());
+			examStudentInfoList.add(examStudentInfo);
+			if (ExamType.ONLINE.name().equals(examBean.getExamType())
+					|| ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) {
+				if (query.getFinished() != null) {
+					if (query.getFinished().intValue() == 1) {
+						examStudentInfo.setFinished(true);
+						examStudentInfo.setFinishedStatus(FinishStatus.已完成.name());
+					}
+					if (query.getFinished().intValue() == 0) {
+						examStudentInfo.setFinished(false);
+						examStudentInfo.setFinishedStatus(FinishStatus.未完成.name());
+					}
+				}
+				countUseExamTimes(examStudentInfo, examBean.getExamType());
+			}
+		}
+		cahcheMap.clear();
+		fillStage(examStudentInfoList);
+		return examStudentInfoList;
+	}
+
+	private StringBuffer selectExamStudentConfitionSql(UserDataRules uds, ExamStudentQuery query, String examType) {
+		StringBuffer sql = new StringBuffer();
+		if (query.getOrgId() != null) {
+			sql.append(" and org_id=" + query.getOrgId());
+		}
+		if (query.getExamId() != null) {
+			sql.append(" and exam_id = " + query.getExamId());
+		}
+		if (query.getExamStageId() != null) {
+			sql.append(" and exam_stage_id = " + query.getExamStageId());
+		}
+		if (StringUtils.isNotBlank(query.getStudentCode())) {
+			sql.append(" and student_code LIKE '" + query.getStudentCode() + "%'");
+		}
+		if (StringUtils.isNotBlank(query.getStudentName())) {
+			sql.append(" and student_name LIKE '" + query.getStudentName() + "%'");
+		}
+		if (StringUtils.isNotBlank(query.getIdentityNumber())) {
+			sql.append(" and identity_number LIKE '" + query.getIdentityNumber() + "%'");
+		}
+		if (StringUtils.isNotBlank(query.getInfoCollector())) {
+			sql.append(" and info_collector LIKE '" + query.getInfoCollector() + "%'");
+		}
+		if (query.getCourseId() != null) {
+			sql.append(" and course_id=" + query.getCourseId());
+		}
+		if (StringUtils.isNotBlank(query.getCourseLevel())) {
+			sql.append(" and course_level= '" + query.getCourseLevel() + "'");
+		}
+		if (query.getFinished() != null) {
+			if (ExamType.ONLINE.name().equals(examType) || ExamType.ONLINE_HOMEWORK.name().equals(examType)) {
+				// sql.append(" and finished = " + query.getFinished());
+				if (query.getFinished().intValue() == 1) {
+					sql.append(
+							" AND ( finished = 1 OR t1.exam_student_id in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id="
+									+ query.getExamId() + "  )  )");
+				}
+				if (query.getFinished().intValue() == 0) {
+					sql.append(
+							" AND ( finished = 0 and t1.exam_student_id not in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id="
+									+ query.getExamId() + "  )  )");
+				}
+			} else if (ExamType.OFFLINE.name().equals(examType)) {
+				// 如果忽略是否上传答案时,只要是已抽题则认为已参加考试
+				if (query.getIgnoreUploadOfflineAnswer() != null && true == query.getIgnoreUploadOfflineAnswer()) {
+					sql.append(" and finished = " + query.getFinished());
+				} else {
+					if (query.getFinished() == 0) { // 未抽题
+						sql.append(" and finished = 0");
+					} else if (query.getFinished() == 1) { // 已抽题未上传
+						sql.append(
+								" and finished = 1  and not exists (select id from ec_oe_exam_record_4_marking t2 where t1.exam_student_id = t2.exam_student_id)");
+					} else if (query.getFinished() == 2) { // 已抽题已上传
+						sql.append(
+								" and finished = 1  and  exists (select id from ec_oe_exam_record_4_marking t2 where t1.exam_student_id = t2.exam_student_id)");
+					}
+				}
+
+			}
+		}
+		if (uds.getOrgRule().assertNeedQueryRefIds()) {
+			sql.append(" and org_id in (" + StringUtils.join(uds.getOrgRule().getRefIds(), ",") + ") ");
+		}
+		if (uds.getCourseRule().assertNeedQueryRefIds()) {
+			sql.append(" and course_id in (" + StringUtils.join(uds.getCourseRule().getRefIds(), ",") + ") ");
+		}
+		return sql;
+	}
+
+	private ExamStudentInfo buildExamStudentInfoForExport(ExamStudentEntity examStudentEntity, String examType) {
+		ExamStudentInfo examStudentInfo = buildExamStudentInfoBase(examStudentEntity, examType);
+		return examStudentInfo;
+	}
+
+	private ExamStudentInfo buildExamStudentInfoBase(ExamStudentEntity examStudentEntity, String examType) {
+		ExamStudentInfo examStudentInfo = ExamStudentEntityConvert.of(examStudentEntity);
+		examStudentInfo.setExamType(examType);
+		CourseCacheBean courseBean = ExamCacheTransferHelper.getCachedCourse(examStudentInfo.getCourseId());
+		examStudentInfo.setCourseName(courseBean.getName());
+		examStudentInfo.setCourseCode(courseBean.getCode());
+		examStudentInfo.setCourseLevel(CourseLevel.getCourseLevel(courseBean.getLevel()).getTitle());
+
+		OrgCacheBean orgBean = gainBaseDataService.getOrgBean(examStudentInfo.getOrgId());
+		examStudentInfo.setOrgCode(orgBean.getCode());
+		examStudentInfo.setOrgName(orgBean.getName());
+
+		// String photoNumber = localCacheService.getStudentPhotoNumber(cahcheMap,
+		// examStudentInfo.getStudentId());
+		// examStudentInfo.setPhone(photoNumber);//电话号码
+
+		if (ExamType.ONLINE.name().equals(examType) || ExamType.ONLINE_HOMEWORK.name().equals(examType)) {
+			// 完成状态
+			examStudentInfo.setFinishedStatus(
+					examStudentEntity.getFinished() ? FinishStatus.已完成.name() : FinishStatus.未完成.name());
+		} else if (ExamType.OFFLINE.name().equals(examType)) {
+			// 离线考试:当前机构是否允许上传附件
+			ExamPropertyCacheBean cachedExamProperty = ExamCacheTransferHelper.getCachedExamProperty(
+					examStudentInfo.getExamId(), examStudentInfo.getStudentId(),
+					ExamProperties.CAN_UPLOAD_ATTACHMENT.name());
+			if (StringUtils.isNotBlank(cachedExamProperty.getValue())) {
+				examStudentInfo.setCanUploadAttachment(Boolean.valueOf(cachedExamProperty.getValue()));
+			} else {
+				examStudentInfo.setCanUploadAttachment(false);
+			}
+			// 完成状态
+			if (!examStudentEntity.getFinished()) {
+				examStudentInfo.setFinishedStatus(FinishStatus.未抽题.name());
+			} else {
+				examStudentInfo.setFinishedStatus(FinishStatus.已抽题.name());
+
+				ExamRecordForMarkingEntity examRecordForMarking = examRecordForMarkingRepo
+						.findTopByExamStudentId(examStudentEntity.getExamStudentId());
+				if (examRecordForMarking != null) {
+					List<ExamRecordFileAnswerEntity> fileAnswerList = examRecordFileAnswerRepo
+							.findByExamRecordDataId(examRecordForMarking.getExamRecordDataId());
+					if (null != fileAnswerList && !fileAnswerList.isEmpty()) {
+						examStudentInfo.setFinishedStatus(FinishStatus.已上传.name());
+						examStudentInfo.setOfflineFiles(getOfflineFilesFrom(fileAnswerList));
+					}
+				}
+			}
+		}
+		return examStudentInfo;
+	}
+
+	private ExamStudentInfo buildExamStudentInfo(ExamStudentEntity examStudentEntity, Map<String, Object> cahcheMap,
+			String examType) {
+		ExamStudentInfo examStudentInfo = buildExamStudentInfoBase(examStudentEntity, examType);
+		String photoNumber = localCacheService.getStudentPhotoNumber(cahcheMap, examStudentInfo.getStudentId());
+		examStudentInfo.setPhone(photoNumber);// 电话号码
+		return examStudentInfo;
+	}
+
+	private List<ExamRecordFileAnswerInfo> getOfflineFilesFrom(List<ExamRecordFileAnswerEntity> fileAnswerList) {
+		List<ExamRecordFileAnswerInfo> resultList = new ArrayList<>();
+		for (ExamRecordFileAnswerEntity entity : fileAnswerList) {
+			ExamRecordFileAnswerInfo info = new ExamRecordFileAnswerInfo();
+			info.setId(entity.getId());
+			info.setExamRecordDataId(entity.getExamRecordDataId());
+			info.setOfflineFileUrl(FileStorageUtil.realPath(entity.getFileUrl()));
+			info.setOfflineFileName(entity.getFileName());
+			info.setOriginalFileName(entity.getOriginalFileName());
+			info.setFileType(entity.getFileType());
+			info.setSuffix(entity.getSuffix());
+			info.setProperties(entity.getProperties());
+			resultList.add(info);
+		}
+
+		return resultList;
+	}
+
+	private ExamStudentEntity getExamStudentEntityByResultSet(ResultSet rs) throws SQLException {
+		ExamStudentEntity examStudentEntity = new ExamStudentEntity();
+		examStudentEntity.setId(rs.getLong("id"));
+		examStudentEntity.setExamStudentId(rs.getLong("exam_student_id"));
+		examStudentEntity.setExamId(rs.getLong("exam_id"));
+		examStudentEntity.setCourseId(rs.getLong("course_id"));
+		examStudentEntity.setCourseCode(rs.getString("course_code"));
+		examStudentEntity.setCourseLevel(rs.getString("course_level"));
+		examStudentEntity.setFinished(rs.getBoolean("finished"));
+		examStudentEntity.setStudentId(rs.getLong("student_id"));
+		examStudentEntity.setStudentCode(rs.getString("student_code"));
+		examStudentEntity.setStudentName(rs.getString("student_name"));
+		examStudentEntity.setIdentityNumber(rs.getString("identity_number"));
+		examStudentEntity.setInfoCollector(rs.getString("info_collector"));
+		examStudentEntity.setRootOrgId(rs.getLong("root_org_id"));
+		examStudentEntity.setOrgId(rs.getLong("org_id"));
+		examStudentEntity.setPaperType(rs.getString("paper_type"));
+		examStudentEntity.setUsedNum(rs.getInt("used_num"));
+		examStudentEntity.setExtraNum(rs.getInt("extra_num"));
+		examStudentEntity.setSpecialtyCode(rs.getString("specialty_code"));
+		examStudentEntity.setSpecialtyName(rs.getString("specialty_name"));
+		examStudentEntity.setGrade(rs.getString("grade"));
+		if (rs.getString("exam_stage_id") != null) {
+			examStudentEntity.setExamStageId(rs.getLong("exam_stage_id"));
+		}
+
+		return examStudentEntity;
+	}
+
+	@Override
+	public Page<ExamStudentInfo> getReExamineStudentList(UserDataRules uds, ExamStudentQuery query) {
+		if (uds.getCourseRule().assertEmptyQueryResult() || uds.getOrgRule().assertEmptyQueryResult()) {
+			return Page.empty();
+		}
+		// 获取考试的默认次数
+		ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(query.getExamId());
+
+		// 封装查询条件
+		Pageable pageable = SpecUtils.buildPageable(query.getPageNo(), query.getPageSize());
+		StringBuffer sql = new StringBuffer();
+
+		sql.append("select t.id," + "t.exam_student_id," + "t.exam_id," + "t.student_id," + "t.student_code,"
+				+ "t.student_name," + "t.identity_number," + "t.course_id," + "t.course_code," + "t.course_level,"
+				+ "t.org_id," + "t.root_org_id," + "t.specialty_name," + "t.finished," + "t.used_num,"
+				+ "t.extra_num from ( ");
+		sql.append("SELECT * " + " FROM ec_oe_exam_student student" + " WHERE exam_id = " + examBean.getId()
+				+ " AND used_num = extra_num+" + examBean.getExamTimes().longValue() + " AND NOT EXISTS ("
+				+ "	SELECT * FROM ec_oe_exam_record_data t1" + "	WHERE" + "		t1.exam_id = " + examBean.getId()
+				+ " and student.exam_student_id = t1.exam_student_id" + "	AND t1.exam_record_status = 'EXAM_ING'"
+				+ ") ");
+
+		sql.append(" order by student.id desc ");
+		sql.append(") t where 1=1 ");
+		if (query.getOrgId() != null) {
+			sql.append(" and t.org_id = " + query.getOrgId());
+		}
+
+		if (query.getExamStageId() != null) {
+			sql.append(" and t.exam_stage_id = " + query.getExamStageId());
+		}
+
+		if (StringUtils.isNotBlank(query.getStudentCode())) {
+			sql.append(" and t.student_code LIKE '" + query.getStudentCode() + "%'");
+		}
+		if (StringUtils.isNotBlank(query.getStudentName())) {
+			sql.append(" and t.student_name LIKE '" + query.getStudentName() + "%'");
+		}
+		if (StringUtils.isNotBlank(query.getIdentityNumber())) {
+			sql.append(" and t.identity_number LIKE '" + query.getIdentityNumber() + "%'");
+		}
+		if (query.getCourseId() != null && StringUtils.isNotBlank(query.getCourseId() + "")) {
+			sql.append(" and t.course_id=" + query.getCourseId());
+		}
+		if (StringUtils.isNotBlank(query.getCourseLevel())) {
+			sql.append(" and t.course_level= '" + query.getCourseLevel() + "'");
+		}
+		if (uds.getOrgRule().assertNeedQueryRefIds()) {
+			sql.append(" and t.org_id in (" + StringUtils.join(uds.getOrgRule().getRefIds(), ",") + ") ");
+		}
+		if (uds.getCourseRule().assertNeedQueryRefIds()) {
+			sql.append(" and t.course_id in (" + StringUtils.join(uds.getCourseRule().getRefIds(), ",") + ") ");
+		}
+		int currentNum = (query.getPageNo() - 1) * query.getPageSize();
+		sql.append(" limit " + currentNum + "," + query.getPageSize());
+
+		log.info("重考列表sql:" + sql.toString());
+		List<ExamStudentEntity> examStudentList = jdbcTemplate.query(sql.toString(),
+				new RowMapper<ExamStudentEntity>() {
+					@Override
+					public ExamStudentEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
+						ExamStudentEntity examStudentEntity = new ExamStudentEntity();
+						examStudentEntity.setId(rs.getLong("id"));
+						examStudentEntity.setExamStudentId(rs.getLong("exam_student_id"));
+						examStudentEntity.setExamId(rs.getLong("exam_id"));
+						examStudentEntity.setStudentId(rs.getLong("student_id"));
+						examStudentEntity.setStudentCode(rs.getString("student_code"));
+						examStudentEntity.setStudentName(rs.getString("student_name"));
+						examStudentEntity.setIdentityNumber(rs.getString("identity_number"));
+						examStudentEntity.setCourseId(rs.getLong("course_id"));
+						examStudentEntity.setCourseCode(rs.getString("course_code"));
+						examStudentEntity.setCourseLevel(rs.getString("course_level"));
+						examStudentEntity.setOrgId(rs.getLong("org_id"));
+						examStudentEntity.setRootOrgId(rs.getLong("root_org_id"));
+						examStudentEntity.setSpecialtyName(rs.getString("specialty_name"));
+						examStudentEntity.setFinished(rs.getBoolean("finished"));
+						examStudentEntity.setUsedNum(rs.getInt("used_num"));
+						examStudentEntity.setExtraNum(rs.getInt("extra_num"));
+						return examStudentEntity;
+					}
+				});
+		long totalSize = countReExamine(uds, query, examBean);
+		List<ExamStudentInfo> list = new ArrayList<ExamStudentInfo>();
+		for (ExamStudentEntity examStudentEntity : examStudentList) {
+			ExamStudentInfo examStudentInfo = ExamStudentEntityConvert.of(examStudentEntity);
+			OrgCacheBean orgBean = gainBaseDataService.getOrgBean(examStudentInfo.getOrgId());
+			examStudentInfo.setOrgName(orgBean.getName());
+			examStudentInfo.setOrgCode(orgBean.getCode());
+			CourseCacheBean courseBean = ExamCacheTransferHelper.getCachedCourse(examStudentInfo.getCourseId());
+			examStudentInfo.setCourseName(courseBean.getName());
+			list.add(examStudentInfo);
+		}
+		return new PageImpl<>(list, pageable, totalSize);
+	}
+
+	private Long countReExamine(UserDataRules uds, ExamStudentQuery query, ExamSettingsCacheBean examBean) {
+		StringBuffer sql = new StringBuffer();
+		sql.append("SELECT count(*)" + " FROM " + "	ec_oe_exam_student student" + " WHERE" + "	exam_id = "
+				+ examBean.getId() + " AND used_num = extra_num+" + examBean.getExamTimes().longValue()
+				+ " AND NOT EXISTS (" + "	SELECT * FROM ec_oe_exam_record_data t1" + "	WHERE t1.exam_id = "
+				+ examBean.getId() + "   AND student.exam_student_id = t1.exam_student_id"
+				+ "	AND t1.exam_record_status = 'EXAM_ING'" + ")");
+		if (query.getOrgId() != null) {
+			sql.append(" and student.org_id = " + query.getOrgId());
+		}
+		if (StringUtils.isNotBlank(query.getStudentCode())) {
+			sql.append(" and student.student_code LIKE '" + query.getStudentCode() + "%'");
+		}
+		if (StringUtils.isNotBlank(query.getStudentName())) {
+			sql.append(" and student.student_name LIKE '" + query.getStudentName() + "%'");
+		}
+		if (StringUtils.isNotBlank(query.getIdentityNumber())) {
+			sql.append(" and student.identity_number LIKE '" + query.getIdentityNumber() + "%'");
+		}
+		if (query.getCourseId() != null && StringUtils.isNotBlank(query.getCourseId() + "")) {
+			sql.append(" and student.course_id=" + query.getCourseId());
+		}
+		if (StringUtils.isNotBlank(query.getCourseLevel())) {
+			sql.append(" and student.course_level= '" + query.getCourseLevel() + "'");
+		}
+		if (uds.getOrgRule().assertNeedQueryRefIds()) {
+			sql.append(" and student.org_id in (" + StringUtils.join(uds.getOrgRule().getRefIds(), ",") + ") ");
+		}
+		if (uds.getCourseRule().assertNeedQueryRefIds()) {
+			sql.append(" and student.course_id in (" + StringUtils.join(uds.getCourseRule().getRefIds(), ",") + ") ");
+		}
+		return jdbcTemplate.queryForObject(sql.toString(), Long.class);
+	}
+
+	@SuppressWarnings({ "deprecation", "unchecked", "rawtypes" })
+	@Override
+	public ExamStudentFinishedStatistic getExamStudentStatisticByFinished(Long examId, Long examStageId) {
+		ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(examId);
+		if (ExamType.ONLINE.name().equals(examBean.getExamType())
+				|| ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) {
+			ExamStudentFinishedStatistic statistic = new ExamStudentFinishedStatistic();
+			StringBuffer totalsql = new StringBuffer();
+			totalsql.append("select count(t1.id) from ec_oe_exam_student t1 where 1=1 ");
+			totalsql.append(" and exam_id = " + examId);
+			if (null != examStageId) {
+				totalsql.append(" and exam_stage_id = " + examStageId);
+			}
+			Integer total = jdbcTemplate.queryForObject(totalsql.toString(), Integer.class);
+
+			StringBuffer finishsql = new StringBuffer();
+			finishsql.append("select count(t1.id) from ec_oe_exam_student t1 where 1=1 ");
+			finishsql.append(" and exam_id = " + examId);
+			if (null != examStageId) {
+				finishsql.append(" and exam_stage_id = " + examStageId);
+			}
+			finishsql.append(
+					" AND ( finished = 1 OR t1.exam_student_id in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id="
+							+ examId + "  )  )");
+			Integer finish = jdbcTemplate.queryForObject(finishsql.toString(), Integer.class);
+			statistic.setFinished(finish);
+			statistic.setUnFinished(total - finish);
+			return statistic;
+		} else {
+			SqlWrapper wrapper = new SqlWrapper().select(statisticFinishedColumns()).from("ec_oe_exam_student")
+					.as("student").where().eq("student.exam_id", examId);
+			if (null != examStageId) {
+				wrapper.and().eq("student.exam_stage_id", examStageId);
+			}
+
+			Query dataQuery = entityManager.createNativeQuery(wrapper.build());
+			dataQuery.unwrap(NativeQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
+			Map<String, BigDecimal> map = (HashMap) dataQuery.getSingleResult();
+			ExamStudentFinishedStatistic statistic = new ExamStudentFinishedStatistic();
+			if (map != null) {
+				if (map.get("finished") == null) {
+					statistic.setFinished(0);
+				} else {
+					statistic.setFinished(map.get("finished").intValue());
+				}
+				if (map.get("unFinished") == null) {
+					statistic.setUnFinished(0);
+				} else {
+					statistic.setUnFinished(map.get("unFinished").intValue());
+				}
+			}
+			return statistic;
+		}
+	}
+
+	@SuppressWarnings({ "deprecation", "unchecked", "unused" })
+	@Override
+	public List<ExamStudentOrgStatistic> getExamStudentStatisticByOrg(UserDataRule ud, Long examId, Long examStageId,
+			Long orgId) {
+		if (ud.assertEmptyQueryResult()) {
+			return Lists.newArrayList();
+		}
+		ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(examId);
+		if (ExamType.ONLINE.name().equals(examBean.getExamType())
+				|| ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) {
+			StringBuffer totalsql = new StringBuffer();
+			totalsql.append("select t1.org_id orgId,count(t1.id) totalCount from ec_oe_exam_student t1 where 1=1 ");
+			totalsql.append(" and exam_id = " + examId);
+			if (null != examStageId) {
+				totalsql.append(" and exam_stage_id = " + examStageId);
+			}
+			if (orgId != null) {
+				totalsql.append(" and org_id = " + orgId);
+			}
+			totalsql.append(" group by t1.org_id ");
+			List<ExamStudentOrgStatistic> totalList = jdbcTemplate.query(totalsql.toString(),
+					new BeanPropertyRowMapper<ExamStudentOrgStatistic>(ExamStudentOrgStatistic.class));
+
+			StringBuffer finishsql = new StringBuffer();
+			finishsql.append("select t1.org_id orgId,count(t1.id) finishedCount from ec_oe_exam_student t1 where 1=1 ");
+			finishsql.append(" and exam_id = " + examId);
+			if (null != examStageId) {
+				finishsql.append(" and exam_stage_id = " + examStageId);
+			}
+			if (orgId != null) {
+				finishsql.append(" and org_id = " + orgId);
+			}
+			finishsql.append(
+					" AND ( finished = 1 OR t1.exam_student_id in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id="
+							+ examId + "  ) )");
+			finishsql.append(" group by t1.org_id ");
+
+			List<ExamStudentOrgStatistic> finishList = jdbcTemplate.query(finishsql.toString(),
+					new BeanPropertyRowMapper<ExamStudentOrgStatistic>(ExamStudentOrgStatistic.class));
+
+			Map<Long, ExamStudentOrgStatistic> finishMap = finishList.stream()
+					.collect(Collectors.toMap(ExamStudentOrgStatistic::getOrgId, account -> account));
+
+			for (ExamStudentOrgStatistic statistic : totalList) {
+				ExamStudentOrgStatistic finish = finishMap.get(statistic.getOrgId());
+				statistic.setFinishedCount(finish == null ? 0 : finish.getFinishedCount());
+				OrgCacheBean orgBean = gainBaseDataService.getOrgBean(statistic.getOrgId());
+				statistic.setOrgCode(orgBean.getCode());
+				statistic.setOrgName(orgBean.getName());
+				if (statistic.getTotalCount() == 0 || statistic.getFinishedCount() == 0) {
+					statistic.setFinishedPercent("0");
+				} else {
+					double percent = (double) statistic.getFinishedCount() / statistic.getTotalCount();
+					statistic.setFinishedPercent(new DecimalFormat("#.00").format(percent * 100));
+				}
+			}
+			List<ExamStudentOrgStatistic> ret = Lists.newArrayList();
+			for (ExamStudentOrgStatistic statistic : totalList) {
+				if (!ud.assertNeedQueryRefIds() || ud.getRefIds().contains(statistic.getOrgId())) {
+					ret.add(statistic);
+				}
+			}
+			return ret;
+		} else {
+			SqlWrapper wrapper = new SqlWrapper().select(statisticOrgColumns()).from("ec_oe_exam_student").as("student")
+					.where().eq("student.exam_id", examId);
+
+			if (null != examStageId) {
+				wrapper.and().eq("student.exam_stage_id", examStageId);
+			}
+			if (orgId != null) {
+				wrapper.and().eq("student.org_id", orgId);
+			}
+			wrapper.groupBy("student.org_id").orderBy("student.org_id", false);
+			Query dataQuery = entityManager.createNativeQuery(wrapper.build());
+			dataQuery.unwrap(NativeQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
+			List<ExamStudentOrgStatistic> examStudentOrgStatisticList = ExamStudentEntityConvert
+					.ofList(dataQuery.getResultList());
+			Map<String, Object> cahcheMap = new HashMap<String, Object>();
+			for (ExamStudentOrgStatistic statistic : examStudentOrgStatisticList) {
+				OrgCacheBean orgBean = gainBaseDataService.getOrgBean(statistic.getOrgId());
+				statistic.setOrgCode(orgBean.getCode());
+				statistic.setOrgName(orgBean.getName());
+			}
+			List<ExamStudentOrgStatistic> ret = Lists.newArrayList();
+			for (ExamStudentOrgStatistic statistic : examStudentOrgStatisticList) {
+				if (!ud.assertNeedQueryRefIds() || ud.getRefIds().contains(statistic.getOrgId())) {
+					ret.add(statistic);
+				}
+			}
+			return ret;
+		}
+	}
+
+	@Override
+	public ExamStudentInfo getExamStudentInfo(Long examStudentId) {
+		ExamStudentEntity entity = examStudentRepo.findByExamStudentId(examStudentId);
+		return ExamStudentEntityConvert.of(entity);
+	}
+
+	@Override
+	public boolean isEnableExamStudent(Long examStudentId) {
+		ExamStudentEntity entity = examStudentRepo.findByExamStudentId(examStudentId);
+		if (entity == null) {
+			log.warn("ExamStudent is not exist, id is " + examStudentId);
+			throw new StatusException("000500", "考生信息不存在!");
+		}
+
+		return entity.getEnable();
+	}
+
+	@Override
+	public List<Long> findCoursesFromExamStudent(Long examId, Long examStageId, Long orgId) {
+		String sql = "select course_id from ec_oe_exam_student where exam_id = " + examId;
+		if (null != examStageId) {
+			sql += " and exam_stage_id= " + examStageId;
+		}
+		if (orgId != null) {
+			sql += " and org_id = " + orgId;
+		}
+		sql += "  group by course_id";
+		return jdbcTemplate.queryForList(sql, Long.class);
+	}
+
+	@Override
+	@Transactional
+	public void setReexamine(Long examStudentId, String reexamineType, String reexamineDetail) {
+		List<ExamRecordDataEntity> examRecordDataList = examRecordService
+				.getExamRecordListByExamStudentId(examStudentId);
+		// 查询出上一次重考的记录
+		Optional<ExamRecordDataEntity> examRecordOptional = examRecordDataList.stream()
+				.filter(examRecordData -> examRecordData.getExamRecordStatus() != ExamRecordStatus.EXAM_INVALID
+						&& examRecordData.getIsReexamine() != null && examRecordData.getIsReexamine())
+				.findFirst();
+		ExamRecordDataEntity examRecordData = null;
+		if (examRecordOptional.isPresent()) {
+			examRecordData = examRecordOptional.get();
+		}
+		if (examRecordData != null) {
+			// 将上一次重考的记录设置成无效
+			examRecordData.setExamRecordStatus(ExamRecordStatus.EXAM_INVALID);
+			examRecordDataRepo.save(examRecordData);
+			// 删除生成的阅卷数据,避免传到阅卷
+			ExamRecordForMarkingEntity examRecordForMarking = examRecordForMarkingRepo
+					.findByExamRecordDataId(examRecordData.getId());
+			if (examRecordForMarking != null) {
+				examRecordForMarkingRepo.delete(examRecordForMarking);
+			}
+
+			// 重新计算考生的最终分数
+			examStudentFinalScoreService.calcAndSaveFinalScore(examRecordData.getExamStudentId());
+		}
+
+		// 考生表重考次数+1
+		ExamStudentEntity examStudent = examStudentRepo.findByExamStudentId(examStudentId);
+		Integer extraExamNum = examStudent.getExtraNum() == null ? 0 : examStudent.getExtraNum();
+		examStudent.setExtraNum(extraExamNum + 1);
+		examStudent.setReexamineType(reexamineType);
+		examStudent.setReexamineDetail(reexamineDetail);
+		examStudentRepo.save(examStudent);
+
+		// 刷新考生的缓存
+		examStudentCache.refresh(examStudentId);
+	}
+
+	@Override
+	public List<CourseProgressInfo> queryCourseProgressInfos(UserDataRule ud, Long examId, Long examStageId,
+			Long courseId, String orderColumn) {
+		if (ud.assertEmptyQueryResult()) {
+			return Lists.newArrayList();
+		}
+		if (examId == null) {
+			return null;
+		}
+		ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(examId);
+		if (ExamType.ONLINE.name().equals(examBean.getExamType())
+				|| ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) {
+			StringBuffer totalsql = new StringBuffer();
+			totalsql.append("select t1.course_id courseId,count(t1.id) allNum from ec_oe_exam_student t1 where 1=1 ");
+			totalsql.append(" and exam_id = " + examId);
+
+			if (null != examStageId) {
+				totalsql.append(" and exam_stage_id = " + examStageId);
+			}
+			if (courseId != null) {
+				totalsql.append(" and course_id = " + courseId);
+			}
+			totalsql.append(" group by t1.course_id ");
+			List<CourseProgressInfo> totalList = jdbcTemplate.query(totalsql.toString(),
+					new BeanPropertyRowMapper<CourseProgressInfo>(CourseProgressInfo.class));
+
+			StringBuffer finishsql = new StringBuffer();
+			finishsql.append(
+					"select t1.course_id courseId,count(t1.id) completedNum from ec_oe_exam_student t1 where 1=1 ");
+			finishsql.append(" and exam_id = " + examId);
+
+			if (null != examStageId) {
+				finishsql.append(" and exam_stage_id = " + examStageId);
+			}
+			if (courseId != null) {
+				finishsql.append(" and course_id = " + courseId);
+			}
+			finishsql.append(
+					" AND ( finished = 1 OR t1.exam_student_id in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id="
+							+ examId + "  ))");
+			finishsql.append(" group by t1.course_id ");
+
+			List<CourseProgressInfo> finishList = jdbcTemplate.query(finishsql.toString(),
+					new BeanPropertyRowMapper<CourseProgressInfo>(CourseProgressInfo.class));
+
+			Map<Long, CourseProgressInfo> finishMap = finishList.stream()
+					.collect(Collectors.toMap(CourseProgressInfo::getCourseId, account -> account));
+
+			for (CourseProgressInfo statistic : totalList) {
+				CourseProgressInfo finish = finishMap.get(statistic.getCourseId());
+				statistic.setCompletedNum(finish == null ? 0 : finish.getCompletedNum());
+				if (statistic.getAllNum() == 0 || statistic.getCompletedNum() == 0) {
+					statistic.setCompletedProportion(0.0D);
+					statistic.setNoCompletedNum(0);
+				} else {
+					statistic.setNoCompletedNum(statistic.getAllNum() - statistic.getCompletedNum());
+					double percent = (double) statistic.getCompletedNum() / statistic.getAllNum();
+					statistic.setCompletedProportion(Double.valueOf(new DecimalFormat("#.00").format(percent * 100)));
+				}
+			}
+			List<CourseProgressInfo> ret = Lists.newArrayList();
+			for (CourseProgressInfo statistic : totalList) {
+				if (!ud.assertNeedQueryRefIds() || ud.getRefIds().contains(statistic.getCourseId())) {
+					ret.add(statistic);
+				}
+			}
+			return ret;
+		} else {
+			if (StringUtils.isBlank(orderColumn)) {
+				orderColumn = "all_num";
+			}
+			String sql = "select *,ROUND(tb.completed_num/tb.all_num,2)*100 completed_proportion from ( " + " select "
+					+ " course_id, " + " sum(case when finished = 1 then 1 else 0 end) completed_num, "
+					+ " sum(case when finished = 0 then 1 else 0 end) no_completed_num, " + " count(course_id) all_num"
+					+ " from ec_oe_exam_student " + " where exam_id = " + examId;
+
+			if (null != examStageId) {
+				sql += " and exam_stage_id = " + examStageId;
+			}
+			if (courseId != null) {
+				sql += " and course_id = " + courseId;
+			}
+			sql += " group by course_id ) tb ORDER BY " + orderColumn + " desc";
+
+			List<CourseProgressInfo> totalList = jdbcTemplate.query(sql, new RowMapper<CourseProgressInfo>() {
+				@Override
+				public CourseProgressInfo mapRow(ResultSet rs, int rowNum) throws SQLException {
+					CourseProgressInfo courseProgressInfo = new CourseProgressInfo();
+					courseProgressInfo.setCourseId(rs.getLong("course_id"));
+					courseProgressInfo.setCompletedNum(rs.getInt("completed_num"));
+					courseProgressInfo.setNoCompletedNum(rs.getInt("no_completed_num"));
+					courseProgressInfo.setAllNum(rs.getInt("all_num"));
+					courseProgressInfo.setCompletedProportion(rs.getDouble("completed_proportion"));
+					return courseProgressInfo;
+				}
+			});
+			List<CourseProgressInfo> ret = Lists.newArrayList();
+			for (CourseProgressInfo statistic : totalList) {
+				if (!ud.assertNeedQueryRefIds() || ud.getRefIds().contains(statistic.getCourseId())) {
+					ret.add(statistic);
+				}
+			}
+			return ret;
+		}
+	}
+
+	@Override
+	public List<ExamStudentInfo> getLimitExamStudentList(Long examId, Long startId, Integer size) {
+		List<ExamStudentInfo> resultList = new ArrayList<>();
+		List<ExamStudentEntity> studentEntityList = examStudentRepo.getLimitExamStudentList(examId, startId, size);
+		for (ExamStudentEntity se : studentEntityList) {
+			ExamStudentInfo info = new ExamStudentInfo();
+			info.setId(se.getId());
+			info.setExamStudentId(se.getExamStudentId());
+			info.setExamId(se.getExamId());
+			info.setCourseId(se.getCourseId());
+			info.setCourseCode(se.getCourseCode());
+			info.setCourseLevel(se.getCourseLevel());
+			info.setFinished(se.getFinished());
+			info.setStudentId(se.getStudentId());
+			info.setStudentCode(se.getStudentCode());
+			info.setStudentName(se.getStudentName());
+			info.setIdentityNumber(se.getIdentityNumber());
+			info.setInfoCollector(se.getInfoCollector());
+			info.setRootOrgId(se.getRootOrgId());
+			info.setOrgId(se.getOrgId());
+			info.setPaperType(se.getPaperType());
+			info.setUsedNum(se.getUsedNum());
+			info.setExtraNum(se.getExtraNum());
+			info.setSpecialtyCode(se.getSpecialtyCode());
+			info.setSpecialtyName(se.getSpecialtyName());
+			info.setGrade(se.getGrade());
+			resultList.add(info);
+		}
+		return resultList;
+	}
+
+	/**
+	 * 根据学生id获取考试列表
+	 *
+	 * @param studentId 学生id
+	 */
+	@Override
+	public List<OnHandExamInfo> queryOnlineExamList(Long studentId, ExamType examType) {
+		StudentCacheBean studentBean = CacheHelper.getStudent(studentId);
+
+		// 获取可以考的和即将考的考试Id
+		GetOngoingExamListReq getOngoingExamListReq = new GetOngoingExamListReq();
+		getOngoingExamListReq.setExamType(examType.name());
+		getOngoingExamListReq.setRootOrgId(studentBean.getRootOrgId());
+		getOngoingExamListReq.setOrgId(studentBean.getOrgId());
+		getOngoingExamListReq.setStudentId(studentId);
+		GetOngoingExamListResp getOngoingExamListResp = examCloudService.getOngoingExamList(getOngoingExamListReq);
+
+		// 获取学生所在组织机构的所有考试列表集合
+		List<ExamSpecialSettingsBean> examSpecialSettingsBeanList = getOngoingExamListResp.getExamSpecialSettingsList();
+		if (examSpecialSettingsBeanList == null || examSpecialSettingsBeanList.size() == 0) {
+			log.warn("getOngoingExamList size is empty, studentId:{}", studentId);
+			return null;
+		}
+		List<Long> examIds = examSpecialSettingsBeanList.stream().map(ExamSpecialSettingsBean::getExamId)
+				.collect(Collectors.toList());
+
+		// 只查没有禁用的考生
+		List<ExamStudentEntity> examStudents = examStudentRepo.findByStudentIdAndEnableAndExamIdIn(studentId, true,
+				examIds);
+
+		List<OnHandExamInfo> examStudentDtoList = new ArrayList<OnHandExamInfo>();
+		Date now = new Date();
+		for (ExamStudentEntity examStudent : examStudents) {
+			assemblingExamStudentDto(examStudent, now, examStudentDtoList, false);
+		}
+
+		for (OnHandExamInfo info : examStudentDtoList) {
+			ExamPropertyCacheBean examCycleEnabledCache = CacheHelper.getExamProperty(info.getExamId(),
+					ExamProperties.EXAM_CYCLE_ENABLED.name());
+			if (examCycleEnabledCache != null && StringUtil.isTrue(examCycleEnabledCache.getValue())) {
+				info.setExamCycleEnabled(true);
+
+				ExamPropertyCacheBean examCycleWeekCache = CacheHelper.getExamProperty(info.getExamId(),
+						ExamProperties.EXAM_CYCLE_WEEK.name());
+
+				info.setExamCycleWeek(JSONObject.parseArray(examCycleWeekCache.getValue()));
+				ExamPropertyCacheBean examCycleTimeRangeCache = CacheHelper.getExamProperty(info.getExamId(),
+						ExamProperties.EXAM_CYCLE_TIME_RANGE.name());
+				info.setExamCycleTimeRange(JSONObject.parseArray(examCycleTimeRangeCache.getValue()));
+			} else {
+				info.setExamCycleEnabled(false);
+			}
+			ExamPropertyCacheBean showUndertaking = CacheHelper.getExamProperty(info.getExamId(),
+					ExamProperties.SHOW_UNDERTAKING.name());
+			if (showUndertaking != null && StringUtil.isTrue(showUndertaking.getValue())) {
+				info.setShowUndertaking(true);
+				ExamPropertyCacheBean undertaking = CacheHelper.getExamProperty(info.getExamId(),
+						ExamProperties.UNDERTAKING.name());
+				if (undertaking != null) {
+					info.setUndertaking(undertaking.getValue());
+				}
+			} else {
+				info.setShowUndertaking(false);
+			}
+
+			info.setExamType(examType.name());
+		}
+
+		return examStudentDtoList;
+	}
+
+	private void assemblingExamStudentDto(ExamStudentEntity examStudent, Date now,
+			final List<OnHandExamInfo> resultList, boolean end) {
+		Long examId = examStudent.getExamId();
+		Long studentId = examStudent.getStudentId();
+		Long examStageId = examStudent.getExamStageId();
+
+		ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getCachedExam(examId, studentId, examStageId);
+
+		if (end && !ExamType.ONLINE.name().equals(examBean.getExamType())) {
+			return;
+		}
+
+		if (examBean.getSpecialSettingsEnabled() && examStageId != null
+				&& ExamSpecialSettingsType.STAGE_BASED == examBean.getSpecialSettingsType()) {
+			ExamStageCacheBean examStage = CacheHelper.getExamStage(examId, examStageId);
+
+			// 场次如果禁用,该场次不允许考试
+			if (examStage.getHasValue() && !examStage.getEnable()) {
+				return;
+			}
+		}
+
+		if (end) {
+			Calendar calendar = Calendar.getInstance();
+			calendar.setTime(examBean.getEndTime());
+			calendar.add(Calendar.DATE, 30);
+			Date leftTime = calendar.getTime();
+			// 已结束且结束时间30天以内的
+			if (now.after(leftTime) || now.before(examBean.getEndTime())) {
+				return;
+			}
+		} else {
+			if (now.after(examBean.getEndTime())) {
+				return;
+			}
+		}
+
+		OnHandExamInfo examStudentInfo = new OnHandExamInfo();
+
+		examStudentInfo.setExamStudentId(examStudent.getExamStudentId());
+		examStudentInfo.setStudentCode(examStudent.getStudentCode());
+		examStudentInfo.setStudentName(examStudent.getStudentName());
+		Long rootOrgId = examStudent.getRootOrgId();
+		examStudentInfo.setRootOrgId(rootOrgId);
+		examStudentInfo.setIdentityNumber(examStudent.getIdentityNumber());
+
+		CourseCacheBean courseBean = ExamCacheTransferHelper.getCachedCourse(examStudent.getCourseId());
+		examStudentInfo.setCourseName(courseBean.getName());
+		examStudentInfo.setCourseCode(courseBean.getCode());
+		examStudentInfo.setCourseLevel(CourseLevel.getCourseLevel(courseBean.getLevel()).getTitle());
+		examStudentInfo.setCourseId(examStudent.getCourseId());
+		examStudentInfo.setSpecialtyName(examStudent.getSpecialtyName());
+		Long orgId = examStudent.getOrgId();
+		examStudentInfo.setOrgId(orgId);
+
+		OrgCacheBean orgBean = gainBaseDataService.getOrgBean(orgId);
+
+		examStudentInfo.setOrgName(orgBean.getName());
+		examStudentInfo.setExamId(examId);
+		examStudentInfo.setExamName(examBean.getName());
+		examStudentInfo.setStartTime(examBean.getBeginTime());// 考试开始时间设置
+		examStudentInfo.setEndTime(examBean.getEndTime());// 考试结束时间设置
+		examStudentInfo.setAllowExamCount(countExamTimes(examStudent, examBean));
+		examStudentInfo.setPaperMins(examBean.getDuration());
+		// 是否启用人脸识别
+		examStudentInfo.setFaceEnable(FaceBiopsyHelper.isFaceEnable(rootOrgId, examId, studentId));
+		// 进入考试是否验证人脸识别(强制、非强制)
+		examStudentInfo.setFaceCheck(FaceBiopsyHelper.isFaceCheck(examId, studentId));
+
+		// 是否显示客观分
+		String isObjScoreView = ExamCacheTransferHelper
+				.getCachedExamProperty(examId, studentId, ExamProperties.IS_OBJ_SCORE_VIEW.name()).getValue();
+		if (StringUtils.isBlank(isObjScoreView)) {
+			examStudentInfo.setIsObjScoreView(false);
+		} else {
+			examStudentInfo.setIsObjScoreView(Boolean.valueOf(isObjScoreView));
+		}
+		if (end && !examStudentInfo.getIsObjScoreView()) {
+			return;
+		}
+
+		// 是否开放app考试
+		String appExamEnabled = ExamCacheTransferHelper
+				.getCachedExamProperty(examId, studentId, ExamProperties.APP_EXAM_ENABLED.name()).getValue();
+		if (StringUtils.isBlank(isObjScoreView)) {
+			examStudentInfo.setAppExamEnabled(false);
+		} else {
+			examStudentInfo.setAppExamEnabled(Boolean.valueOf(appExamEnabled));
+		}
+
+		resultList.add(examStudentInfo);
+
+	}
+
+	private Integer countExamTimes(ExamStudentEntity examStudentInfo, ExamSettingsCacheBean examBean) {
+		if (ExamType.OFFLINE.name().equals(examBean.getExamType())) {
+			return 1;
+		}
+		// 考试批次中设置的考试次数
+		int canExamTimes = examBean.getExamTimes().intValue();
+		// 可补考次数
+		int extraNum = (examStudentInfo.getExtraNum() == null ? 0 : examStudentInfo.getExtraNum());
+		// 考生已考次数
+		int usedNum = (examStudentInfo.getUsedNum() == null ? 0 : examStudentInfo.getUsedNum());
+		// 缓存中开考次数
+		int startCount = 0;
+		// 缓存中考试完结次数
+		int endCount = 0;
+		String key = RedisKeyHelper.getBuilder().examBossKey(examStudentInfo.getExamStudentId());
+		ExamBoss eb = redisClient.get(key, ExamBoss.class);
+		if (eb != null) {
+			startCount = eb.getStartCount();
+			endCount = eb.getEndCount();
+		}
+		Integer ret = canExamTimes + extraNum - (usedNum + startCount - endCount);
+		if (ret < 0) {
+			ret = 0;
+		}
+		return ret;
+	}
+
+	private void countUseExamTimes(ExamStudentInfo examStudentInfo, String examType) {
+		if (!ExamType.ONLINE.name().equals(examType) && !ExamType.ONLINE_HOMEWORK.name().equals(examType)) {
+			return;
+		}
+		// 考生已考次数
+		int usedNum = (examStudentInfo.getUsedNum() == null ? 0 : examStudentInfo.getUsedNum());
+		// 缓存中开考次数
+		int startCount = 0;
+		// 缓存中考试完结次数
+		int endCount = 0;
+		String key = RedisKeyHelper.getBuilder().examBossKey(examStudentInfo.getExamStudentId());
+		ExamBoss eb = redisClient.get(key, ExamBoss.class);
+		if (eb != null) {
+			startCount = eb.getStartCount();
+			endCount = eb.getEndCount();
+		}
+		Integer ret = usedNum + startCount - endCount;
+		if (ret < 0) {
+			ret = 0;
+		}
+		examStudentInfo.setUsedNum(ret);
+	}
+
+	@Override
+	public Page<ExamStudentEntity> getExamStudentSimpleList(ExamStudentQuery req) {
+		if (req.getPageNo() == null || req.getPageNo() < 1) {
+			req.setPageNo(1);
+		}
+
+		if (req.getPageSize() == null || req.getPageSize() < 1) {
+			req.setPageSize(10);
+		}
+
+		if (req.getExamId() == null) {
+			throw new StatusException("考试ID不能为空!");
+		}
+
+		Specification<ExamStudentEntity> spec = (root, query, cb) -> {
+			List<Predicate> predicates = new ArrayList<>();
+			predicates.add(cb.equal(root.get("examId"), req.getExamId()));
+
+			if (req.getCourseId() != null) {
+				predicates.add(cb.equal(root.get("courseId"), req.getCourseId()));
+			}
+
+			return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+		};
+
+		Sort sort = Sort.by(Sort.Order.desc("id"));
+		Pageable pageable = PageRequest.of(req.getPageNo() - 1, req.getPageSize(), sort);
+		return examStudentRepo.findAll(spec, pageable);
+	}
+
+	// //获取考试的考生信息
+	// private ExamStudentBean getRemoteExamStudent(Long rootOrgId, Long
+	// examStudentId) {
+	// GetExamStudentReq req = new GetExamStudentReq();
+	// req.setExamStudentId(examStudentId);
+	// req.setRootOrgId(rootOrgId);
+	// GetExamStudentResp resp = examStudentCloudService.getExamStudent(req);
+	// return resp.getExamStudentBean();
+	// }
 
 }

+ 53 - 0
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/util/BatchGetDataUtil.java

@@ -0,0 +1,53 @@
+package cn.com.qmth.examcloud.core.oe.admin.service.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.collections4.CollectionUtils;
+
+/**
+ *	多次批量获取数据
+ * @author xiatian
+ * @param <R> 结果类
+ * @param <P> 参数类
+ */
+public abstract  class BatchGetDataUtil<R,P> {
+	/**
+	 * @param resultList 全部结果集合
+	 * @param paramList 全部参数集合
+	 * @param batchSize 每批参数数量
+	 */
+	public final List<R> getDataForBatch(List<P> paramList,int batchSize) {
+		if(CollectionUtils.isEmpty(paramList)) {
+			return null;
+		}
+		List<R> resultList=new ArrayList<>();
+		if(paramList.size()<=batchSize) {
+			List<R> temlist = getData(paramList);
+			if(temlist!=null&&temlist.size()>0) {
+				resultList.addAll(temlist);
+			}
+		}else {
+			int size = paramList.size();
+			int len=batchSize;
+			int count = (size + len - 1) / len;
+
+			for (int i = 0; i < count; i++) {
+				List<P> subList = paramList.subList(i * len, ((i + 1) * len > size ? size : len * (i + 1)));
+				List<R> temlist = getData(subList);
+				if(temlist!=null&&temlist.size()>0) {
+					resultList.addAll(temlist);
+				}
+			}
+		}
+		return resultList;
+	}
+	/**
+	 * 	每批获取数据方法
+	 * @param <R>
+	 * @param <P>
+	 * @param paramList 获取每批数据时参数
+	 * @return
+	 */
+	protected abstract  List<R> getData(List<P> paramList);
+}