Browse Source

ignore...

deason 1 year ago
parent
commit
9c4aa00442

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

@@ -91,1355 +91,1357 @@ 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);
+    private static final Logger log = LoggerFactory.getLogger(ExamStudentServiceImpl.class);
+
     @Autowired
     private ExportTaskService exportTaskService;
-	@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) {
-				exportTaskService.checkStopExportTaskById(query.getTaskId());
-				return getExamStudentInfoListByPage(uds, query, examBean, paramList);
-			}
-		}.getDataForBatch(ids, 1000);
-
-		if (CollectionUtils.isEmpty(examStudentList)) {
-			return examStudentInfoList;
-		}
-		for (ExamStudentEntity examStudentEntity : examStudentList) {
-			exportTaskService.checkStopExportTaskById(query.getTaskId());
-			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(),query.getTaskId());
-		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,Long taskId) {
-		GetStudentListByIdsReq req = new GetStudentListByIdsReq();
-		BatchSetDataUtil<ExamStudentInfo> tool = new BatchSetDataUtil<ExamStudentInfo>() {
-			@Override
-			public void setData(List<ExamStudentInfo> dataList) {
-				exportTaskService.checkStopExportTaskById(taskId);
-				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();
-	// }
+
+    @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) {
+                exportTaskService.checkStopExportTaskById(query.getTaskId());
+                return getExamStudentInfoListByPage(uds, query, examBean, paramList);
+            }
+        }.getDataForBatch(ids, 1000);
+
+        if (CollectionUtils.isEmpty(examStudentList)) {
+            return examStudentInfoList;
+        }
+        for (ExamStudentEntity examStudentEntity : examStudentList) {
+            exportTaskService.checkStopExportTaskById(query.getTaskId());
+            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(), query.getTaskId());
+        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, Long taskId) {
+        GetStudentListByIdsReq req = new GetStudentListByIdsReq();
+        BatchSetDataUtil<ExamStudentInfo> tool = new BatchSetDataUtil<ExamStudentInfo>() {
+            @Override
+            public void setData(List<ExamStudentInfo> dataList) {
+                exportTaskService.checkStopExportTaskById(taskId);
+                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();
+    // }
 
 }