|
@@ -7,19 +7,67 @@
|
|
|
|
|
|
package cn.com.qmth.examcloud.core.oe.admin.service.impl;
|
|
|
|
|
|
+import java.math.BigInteger;
|
|
|
+import java.sql.ResultSet;
|
|
|
+import java.sql.SQLException;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Comparator;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.HashSet;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Set;
|
|
|
+import java.util.StringJoiner;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+import javax.persistence.EntityManager;
|
|
|
+import javax.persistence.Query;
|
|
|
+
|
|
|
+import cn.com.qmth.examcloud.support.enums.ExamProperties;
|
|
|
+import cn.com.qmth.examcloud.support.helper.FaceBiopsyHelper;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.json.JSONArray;
|
|
|
+import org.json.JSONException;
|
|
|
+import org.json.JSONObject;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.data.domain.Page;
|
|
|
+import org.springframework.data.domain.PageImpl;
|
|
|
+import org.springframework.data.domain.PageRequest;
|
|
|
+import org.springframework.data.domain.Pageable;
|
|
|
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
|
|
|
+import org.springframework.jdbc.core.JdbcTemplate;
|
|
|
+import org.springframework.jdbc.core.RowMapper;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.util.CollectionUtils;
|
|
|
+
|
|
|
+import com.google.common.collect.Lists;
|
|
|
+
|
|
|
+import cn.com.qmth.examcloud.api.commons.enums.ExamType;
|
|
|
import cn.com.qmth.examcloud.commons.exception.StatusException;
|
|
|
+import cn.com.qmth.examcloud.commons.logging.ExamCloudLog;
|
|
|
+import cn.com.qmth.examcloud.commons.logging.ExamCloudLogFactory;
|
|
|
+import cn.com.qmth.examcloud.core.basic.api.StudentCloudService;
|
|
|
+import cn.com.qmth.examcloud.core.basic.api.bean.StudentBean;
|
|
|
+import cn.com.qmth.examcloud.core.basic.api.request.GetStudentListByIdsReq;
|
|
|
+import cn.com.qmth.examcloud.core.basic.api.response.GetStudentListByIdsResp;
|
|
|
import cn.com.qmth.examcloud.core.oe.admin.base.jpa.SqlWrapper;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.base.utils.BatchSetDataUtil;
|
|
|
import cn.com.qmth.examcloud.core.oe.admin.base.utils.Check;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.base.utils.DateUtils;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.dao.ExamCaptureRepo;
|
|
|
import cn.com.qmth.examcloud.core.oe.admin.dao.ExamRecordDataRepo;
|
|
|
import cn.com.qmth.examcloud.core.oe.admin.dao.ExamRecordQuestionsRepo;
|
|
|
import cn.com.qmth.examcloud.core.oe.admin.dao.ExamScoreRepo;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamCaptureEntity;
|
|
|
import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamQuestionEntity;
|
|
|
import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordDataEntity;
|
|
|
import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordQuestionsEntity;
|
|
|
import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamScoreEntity;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.dao.enums.CourseLevel;
|
|
|
import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamRecordStatus;
|
|
|
import cn.com.qmth.examcloud.core.oe.admin.dao.enums.IsSuccess;
|
|
|
import cn.com.qmth.examcloud.core.oe.admin.dao.enums.MarkingType;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.dao.enums.TrueFalse;
|
|
|
import cn.com.qmth.examcloud.core.oe.admin.service.ExamRecordService;
|
|
|
import cn.com.qmth.examcloud.core.oe.admin.service.ExamStudentService;
|
|
|
import cn.com.qmth.examcloud.core.oe.admin.service.GainBaseDataService;
|
|
@@ -30,30 +78,12 @@ import cn.com.qmth.examcloud.core.oe.admin.service.bean.examrecord.ExamRecordInf
|
|
|
import cn.com.qmth.examcloud.core.oe.admin.service.bean.examrecord.ExamRecordQuery;
|
|
|
import cn.com.qmth.examcloud.core.oe.admin.service.bean.examrecord.ExamStudentQuestionScoreInfo;
|
|
|
import cn.com.qmth.examcloud.core.oe.admin.service.bean.examstudent.ExamStudentInfo;
|
|
|
-import cn.com.qmth.examcloud.examwork.api.bean.ExamBean;
|
|
|
import cn.com.qmth.examcloud.support.cache.CacheHelper;
|
|
|
+import cn.com.qmth.examcloud.support.cache.bean.CourseCacheBean;
|
|
|
import cn.com.qmth.examcloud.support.cache.bean.ExamSettingsCacheBean;
|
|
|
import cn.com.qmth.examcloud.support.cache.bean.OrgCacheBean;
|
|
|
import cn.com.qmth.examcloud.support.cache.bean.StudentCacheBean;
|
|
|
import cn.com.qmth.examcloud.support.helper.ExamCacheTransferHelper;
|
|
|
-import com.google.common.collect.Lists;
|
|
|
-import org.apache.commons.lang3.StringUtils;
|
|
|
-import org.springframework.beans.factory.annotation.Autowired;
|
|
|
-import org.springframework.data.domain.Page;
|
|
|
-import org.springframework.data.domain.PageImpl;
|
|
|
-import org.springframework.data.domain.PageRequest;
|
|
|
-import org.springframework.data.domain.Pageable;
|
|
|
-import org.springframework.jdbc.core.JdbcTemplate;
|
|
|
-import org.springframework.jdbc.core.RowMapper;
|
|
|
-import org.springframework.stereotype.Service;
|
|
|
-
|
|
|
-import javax.persistence.EntityManager;
|
|
|
-import javax.persistence.Query;
|
|
|
-import java.math.BigInteger;
|
|
|
-import java.sql.ResultSet;
|
|
|
-import java.sql.SQLException;
|
|
|
-import java.util.*;
|
|
|
-import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
|
* 考试记录接口
|
|
@@ -63,6 +93,8 @@ import java.util.stream.Collectors;
|
|
|
*/
|
|
|
@Service
|
|
|
public class ExamRecordServiceImpl implements ExamRecordService {
|
|
|
+ private static final ExamCloudLog LOG = ExamCloudLogFactory
|
|
|
+ .getLog(ExamRecordServiceImpl.class);
|
|
|
@Autowired
|
|
|
private ExamScoreRepo examScoreRepo;
|
|
|
@Autowired
|
|
@@ -79,6 +111,64 @@ public class ExamRecordServiceImpl implements ExamRecordService {
|
|
|
private ExamRecordEntityConvert examRecordEntityConvert;
|
|
|
@Autowired
|
|
|
private LocalCacheService localCacheService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private StudentCloudService studentCloudService;
|
|
|
+ @Autowired
|
|
|
+ private ExamCaptureRepo examCaptureRepo;
|
|
|
+
|
|
|
+
|
|
|
+ private static final String EXAM_RECORD_EXPORT_SQL = "select record_data.id," +
|
|
|
+ "record_data.exam_record_status examRecordStatusValue," +
|
|
|
+ "record_data.start_time startTime," +
|
|
|
+ "record_data.end_time endTime," +
|
|
|
+ "record_data.clean_time cleanTime," +
|
|
|
+ "record_data.used_exam_time usedExamTime," +
|
|
|
+ "record_data.exam_order examOrder," +
|
|
|
+ "record_data.is_warn isWarn," +
|
|
|
+ "record_data.is_audit isAudit," +
|
|
|
+ "record_data.is_illegality isIllegalityValue," +
|
|
|
+ "record_data.is_reexamine isReexamine," +
|
|
|
+ "record_data.is_continued isContinued," +
|
|
|
+ "record_data.is_all_objective_paper isAllObjectivePaper," +
|
|
|
+ "record_data.continued_count continuedCount," +
|
|
|
+ "record_data.face_success_count faceSuccessCount," +
|
|
|
+ "record_data.face_failed_count faceFailedCount," +
|
|
|
+ "record_data.face_stranger_count faceStrangerCount," +
|
|
|
+ "record_data.face_total_count faceTotalCount," +
|
|
|
+ "record_data.face_success_percent faceSuccessPercent," +
|
|
|
+ "record_data.face_verify_result faceVerifyResultValue," +
|
|
|
+ "record_data.baidu_face_liveness_success_percent baiduFaceLivenessSuccessPercent," +
|
|
|
+ "record_data.creation_time creationTime," +
|
|
|
+ "record_data.update_time updateTime," +
|
|
|
+ "record_data.exam_id examId," +
|
|
|
+ "record_data.exam_type examTypeValue," +
|
|
|
+ "record_data.exam_student_id examStudentId," +
|
|
|
+ "record_data.student_id studentId," +
|
|
|
+ "record_data.student_code studentCode," +
|
|
|
+ "record_data.student_name studentName," +
|
|
|
+ "record_data.identity_number identityNumber," +
|
|
|
+ "record_data.course_id courseId," +
|
|
|
+ "record_data.course_level courseLevel," +
|
|
|
+ "record_data.root_org_id rootOrgId," +
|
|
|
+ "record_data.org_id orgId," +
|
|
|
+ "record_data.base_paper_id basePaperId," +
|
|
|
+ "record_data.paper_type paperType," +
|
|
|
+ "record_data.paper_struct_id paperStructId," +
|
|
|
+ "record_data.info_collector infoCollector," +
|
|
|
+ "GROUP_CONCAT(DISTINCT process.source_ip) ip," +
|
|
|
+ "eoes.objective_score objectiveTotalScore," +
|
|
|
+ "eoes.subjective_score subjectiveTotalScore," +
|
|
|
+ "eoes.total_score paperTotalScore,"+
|
|
|
+ "eoest.grade ,"+
|
|
|
+ "eoest.specialty_name specialtyName"+
|
|
|
+
|
|
|
+ " from ec_oe_exam_record_data record_data " +
|
|
|
+ " LEFT JOIN ec_oe_exam_process_record AS process ON record_data.id = process.exam_record_data_id " +
|
|
|
+ " LEFT JOIN ec_oe_exam_score eoes ON record_data.id = eoes.exam_record_data_id "+
|
|
|
+ " LEFT JOIN ec_oe_exam_student eoest ON record_data.exam_student_id = eoest.exam_student_id "+
|
|
|
+ " where 1=1";
|
|
|
+
|
|
|
/**
|
|
|
* ec_oe_exam_record_data 查询sql
|
|
|
*/
|
|
@@ -119,9 +209,12 @@ public class ExamRecordServiceImpl implements ExamRecordService {
|
|
|
"record_data.base_paper_id base_paper_id," +
|
|
|
"record_data.paper_type paper_type," +
|
|
|
"record_data.paper_struct_id paper_struct_id," +
|
|
|
- "record_data.info_collector info_collector" +
|
|
|
+ "record_data.info_collector info_collector," +
|
|
|
+ "GROUP_CONCAT(DISTINCT process.source_ip) ip" +
|
|
|
" from ec_oe_exam_record_data record_data " +
|
|
|
+ " LEFT JOIN ec_oe_exam_process_record AS process ON record_data.id = process.exam_record_data_id " +
|
|
|
" where 1=1";
|
|
|
+
|
|
|
/**
|
|
|
* 考生作答成绩
|
|
|
*/
|
|
@@ -132,6 +225,7 @@ public class ExamRecordServiceImpl implements ExamRecordService {
|
|
|
"inner join ec_b_course co on erd.course_id=co.id " +
|
|
|
"inner join ec_e_exam ex on erd.exam_id=ex.id " +
|
|
|
"where 1=1 ";
|
|
|
+
|
|
|
@Autowired
|
|
|
private ExamRecordQuestionsRepo examRecordQuestionsRepo;
|
|
|
|
|
@@ -153,6 +247,48 @@ public class ExamRecordServiceImpl implements ExamRecordService {
|
|
|
return this.getExamRecordList(query);
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public Long getExamRecordWaitingAuditNextId(ExamRecordQuery query, Long examRecordDataId, String next) {
|
|
|
+ Check.isNull(query, "查询参数不能为空!");
|
|
|
+ //默认条件
|
|
|
+ query.setIsWarn(true);
|
|
|
+ query.setIsAudit(false);
|
|
|
+ query.addRecordStatus(ExamRecordStatus.EXAM_END.name());
|
|
|
+ query.addRecordStatus(ExamRecordStatus.EXAM_OVERDUE.name());
|
|
|
+ //查询条件
|
|
|
+ StringBuilder sqlBuilder = new StringBuilder();
|
|
|
+ //待审核(按原先的sql,多了一个ip字段)
|
|
|
+ sqlBuilder.append("select record_data.id from ec_oe_exam_record_data record_data where 1 = 1 ");
|
|
|
+ sqlBuilder.append(buildExamRecordCommonSelectCondition(query));
|
|
|
+ if (query.getIsWarn() != null) {
|
|
|
+ //只查有异常未审核
|
|
|
+ if (query.getIsWarn()) {
|
|
|
+ sqlBuilder.append(" and record_data.is_warn = 1 and record_data.is_audit = 0 ");
|
|
|
+ } else {
|
|
|
+ sqlBuilder.append(" and record_data.is_warn = 0 ");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ sqlBuilder.append(" and ((record_data.is_warn = 0) OR (record_data.is_warn = 1 and record_data.is_audit = 0))");
|
|
|
+ }
|
|
|
+ sqlBuilder.append(" and record_data.is_illegality = 0");
|
|
|
+ if (StringUtils.isBlank(next)){
|
|
|
+ sqlBuilder.append(" and record_data.id != ");
|
|
|
+ sqlBuilder.append(examRecordDataId);
|
|
|
+ sqlBuilder.append(" order by record_data.id desc");
|
|
|
+ } else if ("1".equals(next)){
|
|
|
+ sqlBuilder.append(" and record_data.id < ");
|
|
|
+ sqlBuilder.append(examRecordDataId);
|
|
|
+ sqlBuilder.append(" order by record_data.id desc");
|
|
|
+ } else if ("0".equals(next)){
|
|
|
+ sqlBuilder.append(" and record_data.id > ");
|
|
|
+ sqlBuilder.append(examRecordDataId);
|
|
|
+ sqlBuilder.append(" order by record_data.id asc");
|
|
|
+ }
|
|
|
+ sqlBuilder.append(" limit 1 ");
|
|
|
+ List<Long> ids = jdbcTemplate.query(sqlBuilder.toString(), (rs, rowNum) -> rs.getLong("id"));
|
|
|
+ return CollectionUtils.isEmpty(ids) ? null : ids.get(0);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 考试明细查询
|
|
|
*
|
|
@@ -166,6 +302,11 @@ public class ExamRecordServiceImpl implements ExamRecordService {
|
|
|
sqlBuilder.append(EXAM_RECORD_SQL);
|
|
|
sqlBuilder.append(buildExamRecordCommonSelectCondition(query));
|
|
|
sqlBuilder.append(" and ((record_data.is_warn = 0) OR (record_data.is_warn = 1 and record_data.is_audit = 1))");
|
|
|
+ sqlBuilder.append(" group by record_data.id ");
|
|
|
+ //根据ip查询
|
|
|
+ /*if (StringUtils.isNoneBlank(query.getIp())) {
|
|
|
+ sqlBuilder.append(" having ip like '%"+query.getIp()+"%' ");
|
|
|
+ }*/
|
|
|
sqlBuilder.append(" order by record_data.id desc");
|
|
|
//分页条件
|
|
|
int currentNum = (query.getPageNo() - 1) * query.getPageSize();
|
|
@@ -206,6 +347,7 @@ public class ExamRecordServiceImpl implements ExamRecordService {
|
|
|
examRecordData.setFaceSuccessPercent(rs.getDouble("face_success_percent"));
|
|
|
examRecordData.setFaceVerifyResult(IsSuccess.strToEnum(rs.getString("face_verify_result")));
|
|
|
examRecordData.setBaiduFaceLivenessSuccessPercent(rs.getDouble("baidu_face_liveness_success_percent"));
|
|
|
+ examRecordData.setIp(rs.getString("ip"));
|
|
|
|
|
|
return examRecordData;
|
|
|
}
|
|
@@ -260,6 +402,13 @@ public class ExamRecordServiceImpl implements ExamRecordService {
|
|
|
if (query.getExamRecordId() != null) {
|
|
|
sql.append(" and record_data.id = " + query.getExamRecordId());
|
|
|
}
|
|
|
+ if (query.getIsIllegality() != null) {
|
|
|
+ if(query.getIsIllegality()){
|
|
|
+ sql.append(" and record_data.is_illegality = 1");
|
|
|
+ } else {
|
|
|
+ sql.append(" and record_data.is_illegality = 0");
|
|
|
+ }
|
|
|
+ }
|
|
|
if (StringUtils.isNotBlank(query.getStartTime()) && StringUtils.isNotBlank(query.getEndTime())) {
|
|
|
sql.append(" and record_data.start_time >= str_to_date('" + query.getStartTime() + "','%Y/%m/%d %H:%i:%s')"
|
|
|
+ " and record_data.start_time <= str_to_date('" + query.getEndTime() + "','%Y/%m/%d %H:%i:%s')");
|
|
@@ -303,7 +452,9 @@ public class ExamRecordServiceImpl implements ExamRecordService {
|
|
|
if (query.getHasVirtual()) {
|
|
|
sql.append(" and record_data.id in (select t1.id from ec_oe_exam_record_data t1 left join ec_oe_exam_capture t2 on t1.id=t2.exam_record_data_id where t1.exam_id =" + query.getExamId()+" and t2.has_virtual_camera=1 )");
|
|
|
} else {
|
|
|
- sql.append(" and record_data.id in (select t1.id from ec_oe_exam_record_data t1 left join ec_oe_exam_capture t2 on t1.id=t2.exam_record_data_id where t1.exam_id =" + query.getExamId()+" and (t2.has_virtual_camera=0 or t2.has_virtual_camera is null) )");
|
|
|
+ //原先写法会跟有虚拟设备的出现重复情况,用有虚拟设备的not in
|
|
|
+ //sql.append(" and record_data.id in (select t1.id from ec_oe_exam_record_data t1 left join ec_oe_exam_capture t2 on t1.id=t2.exam_record_data_id where t1.exam_id =" + query.getExamId()+" and (t2.has_virtual_camera=0 or t2.has_virtual_camera is null) )");
|
|
|
+ sql.append(" and record_data.id not in (select t1.id from ec_oe_exam_record_data t1 left join ec_oe_exam_capture t2 on t1.id=t2.exam_record_data_id where t1.exam_id =" + query.getExamId()+" and t2.has_virtual_camera=1 )");
|
|
|
}
|
|
|
}
|
|
|
return sql;
|
|
@@ -318,10 +469,11 @@ public class ExamRecordServiceImpl implements ExamRecordService {
|
|
|
Check.isNull(query, "查询参数不能为空!");
|
|
|
//查询条件
|
|
|
StringBuilder sqlBuilder = new StringBuilder();
|
|
|
+ //待审核(按原先的sql,多了一个ip字段)
|
|
|
sqlBuilder.append(EXAM_RECORD_SQL);
|
|
|
sqlBuilder.append(buildExamRecordCommonSelectCondition(query));
|
|
|
- //只查有异常未审核
|
|
|
if (query.getIsWarn() != null) {
|
|
|
+ //只查有异常未审核
|
|
|
if (query.getIsWarn()) {
|
|
|
sqlBuilder.append(" and record_data.is_warn = 1 and record_data.is_audit = 0 ");
|
|
|
} else {
|
|
@@ -331,6 +483,12 @@ public class ExamRecordServiceImpl implements ExamRecordService {
|
|
|
sqlBuilder.append(" and ((record_data.is_warn = 0) OR (record_data.is_warn = 1 and record_data.is_audit = 0))");
|
|
|
}
|
|
|
sqlBuilder.append(" and record_data.is_illegality = 0");
|
|
|
+ //查询分页记录
|
|
|
+ sqlBuilder.append(" group by record_data.id ");
|
|
|
+ //根据ip查询
|
|
|
+ /*if (StringUtils.isNoneBlank(query.getIp())) {
|
|
|
+ sqlBuilder.append(" having ip like '%"+query.getIp()+"%' ");
|
|
|
+ }*/
|
|
|
sqlBuilder.append(" order by record_data.id desc");
|
|
|
//分页条件
|
|
|
int currentNum = (query.getPageNo() - 1) * query.getPageSize();
|
|
@@ -472,7 +630,231 @@ public class ExamRecordServiceImpl implements ExamRecordService {
|
|
|
sqlBuilder.append(" and record_data.is_warn = 1 and record_data.is_audit = 0");
|
|
|
return jdbcTemplate.queryForObject(sqlBuilder.toString(), Long.class);
|
|
|
}
|
|
|
+ @Override
|
|
|
+ public List<ExamRecordInfo> getExamRecordDetailListForAsync(ExamRecordQuery query) {
|
|
|
+ Check.isNull(query, "查询参数不能为空!");
|
|
|
+ query.addRecordStatus(ExamRecordStatus.EXAM_END.name());
|
|
|
+ query.addRecordStatus(ExamRecordStatus.EXAM_OVERDUE.name());
|
|
|
+
|
|
|
+ List<ExamRecordInfo> examRecordDataList=new ArrayList<ExamRecordInfo>();
|
|
|
+ Long startId=0L;
|
|
|
+ for(;;) {
|
|
|
+ List<ExamRecordInfo> tem=getExamRecordDetailPageForExport(query, startId);
|
|
|
+ if(tem==null||tem.size()==0) {
|
|
|
+ break;
|
|
|
+ }else {
|
|
|
+ startId=tem.get(tem.size()-1).getId();
|
|
|
+ examRecordDataList.addAll(tem);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(examRecordDataList==null||examRecordDataList.size()==0) {
|
|
|
+ return examRecordDataList;
|
|
|
+ }
|
|
|
+ for(ExamRecordInfo erInfo:examRecordDataList) {
|
|
|
+ setInfo(erInfo,query.getExamId());
|
|
|
+ }
|
|
|
+ setPhone(examRecordDataList,query.getRootOrgId());
|
|
|
+ String examType = examRecordDataList.get(0).getExamType();
|
|
|
+ if (ExamType.ONLINE.name().equals(examType) || ExamType.ONLINE_HOMEWORK.name().equals(examType)) {
|
|
|
+ setVirtualCameraNames(examRecordDataList);
|
|
|
+ }
|
|
|
+ return examRecordDataList;
|
|
|
+ }
|
|
|
|
|
|
+ @Override
|
|
|
+ public void refreshCaptureStatistic(Long examId) {
|
|
|
+ List<ExamRecordDataEntity> data = examRecordDataRepo.findDataByExamId(examId);
|
|
|
+
|
|
|
+ for (ExamRecordDataEntity entity : data) {
|
|
|
+ //如果开启了活检
|
|
|
+ if (FaceBiopsyHelper.isFaceEnable(entity.getRootOrgId(), examId, entity.getStudentId())) {
|
|
|
+ List<ExamCaptureEntity> captureEntities = examCaptureRepo.findByExamRecordDataId(entity.getId());
|
|
|
+
|
|
|
+ Double succPercent = entity.getFaceSuccessPercent();
|
|
|
+ Double livenessSuccessPercent = entity.getBaiduFaceLivenessSuccessPercent();
|
|
|
+
|
|
|
+ //人脸识别阀值
|
|
|
+ String warnThresholdStr = ExamCacheTransferHelper.getCachedExamProperty(examId,
|
|
|
+ entity.getStudentId(), ExamProperties.WARN_THRESHOLD.name()).getValue();
|
|
|
+ if (StringUtils.isBlank(warnThresholdStr)) {
|
|
|
+ throw new StatusException("400101", "人脸检测预警阈值未设置");
|
|
|
+ }
|
|
|
+
|
|
|
+ //人脸真实性(百度活体检测)通过阀值
|
|
|
+ String liveWarnThresholdStr = ExamCacheTransferHelper.getCachedExamProperty(examId,
|
|
|
+ entity.getStudentId(), ExamProperties.LIVING_WARN_THRESHOLD.name()).getValue();
|
|
|
+ if (StringUtils.isBlank(liveWarnThresholdStr)) {
|
|
|
+ throw new StatusException("400102", "人脸真实性阈值未设置");
|
|
|
+ }
|
|
|
+
|
|
|
+ Double warnThreshold = Double.parseDouble(warnThresholdStr);
|
|
|
+ Double livenessThreshold = Double.parseDouble(liveWarnThresholdStr);
|
|
|
+ boolean checkFailed = succPercent < warnThreshold || livenessSuccessPercent < livenessThreshold;
|
|
|
+
|
|
|
+ //虚拟摄像头进入待审核,且有虚拟摄像头的
|
|
|
+ String valueSql="SELECT value FROM ec_e_exam_prop WHERE exam_id ="+examId+" AND key_id=45";
|
|
|
+ List<Boolean> list = jdbcTemplate.query(valueSql, (rs, rowNum) -> rs.getBoolean("value"));
|
|
|
+ boolean hasVirtualCamera = !CollectionUtils.isEmpty(list) && list.get(0) &&
|
|
|
+ captureEntities.stream().anyMatch(e->e.getHasVirtualCamera()!=null&&e.getHasVirtualCamera());
|
|
|
+
|
|
|
+ entity.setIsWarn(hasVirtualCamera || checkFailed);
|
|
|
+
|
|
|
+ examRecordDataRepo.save(entity);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void setPhone(List<ExamRecordInfo> examRecordDataList,Long rootOrgId) {
|
|
|
+ GetStudentListByIdsReq req= new GetStudentListByIdsReq();
|
|
|
+ BatchSetDataUtil<ExamRecordInfo> tool = new BatchSetDataUtil<ExamRecordInfo>() {
|
|
|
+ @Override
|
|
|
+ public void setData(List<ExamRecordInfo> dataList) {
|
|
|
+ req.setRootOrgId(rootOrgId);
|
|
|
+ List<Long> ids = dataList.stream().map(dto -> dto.getStudentId()).distinct().collect(Collectors.toList());
|
|
|
+ req.setStudentIdList(ids);
|
|
|
+ GetStudentListByIdsResp resp=studentCloudService.getStudentListByIds(req);
|
|
|
+ if(resp.getStudentBeanList()!=null&&resp.getStudentBeanList().size()>0) {
|
|
|
+ Map<Long, String> map = resp.getStudentBeanList().stream()
|
|
|
+ .collect(Collectors.toMap(StudentBean::getId, account -> (account.getPhoneNumber()==null?"":account.getPhoneNumber())));
|
|
|
+ for(ExamRecordInfo erInfo:dataList) {
|
|
|
+ erInfo.setPhone(map.get(erInfo.getStudentId()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ };
|
|
|
+ tool.setDataForBatch(examRecordDataList, 100);
|
|
|
+ }
|
|
|
+ private void setVirtualCameraNames(List<ExamRecordInfo> examRecordDataList) {
|
|
|
+ BatchSetDataUtil<ExamRecordInfo> tool = new BatchSetDataUtil<ExamRecordInfo>() {
|
|
|
+ @Override
|
|
|
+ public void setData(List<ExamRecordInfo> dataList) {
|
|
|
+ List<Long> ids = dataList.stream().map(dto -> dto.getId()).distinct().collect(Collectors.toList());
|
|
|
+ Map<Long,Set<String>> map=new HashMap<>();
|
|
|
+ List<ExamCaptureEntity> examCaptureList = examCaptureRepo.findByExamRecordDataIdIn(ids);
|
|
|
+ if (examCaptureList != null && examCaptureList.size() > 0) {
|
|
|
+ for (ExamCaptureEntity examCapture : examCaptureList) {
|
|
|
+ Set<String> virtualCameraNames=map.get(examCapture.getExamRecordDataId());
|
|
|
+ if(virtualCameraNames==null) {
|
|
|
+ virtualCameraNames= new HashSet<String>();
|
|
|
+ map.put(examCapture.getExamRecordDataId(), virtualCameraNames);
|
|
|
+ }
|
|
|
+ String cameraInfos = examCapture.getCameraInfos();
|
|
|
+ if (StringUtils.isNotBlank(cameraInfos)) {
|
|
|
+ JSONArray jsonArray;
|
|
|
+ try {
|
|
|
+ jsonArray = new JSONArray(cameraInfos);
|
|
|
+ for (int i = 0; i < jsonArray.length(); i++) {
|
|
|
+ try {
|
|
|
+ JSONObject jsonObject = (JSONObject) jsonArray.get(i);
|
|
|
+ if (StringUtils.isBlank(jsonObject.getString("pid"))) {
|
|
|
+ virtualCameraNames.add(jsonObject.getString("name"));
|
|
|
+ }
|
|
|
+ } catch (JSONException e) {
|
|
|
+ //主要针对json数组最后的空对象处理,不影响业务
|
|
|
+ LOG.error("抓拍照片格式不正确", e);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (JSONException e) {
|
|
|
+ LOG.error("获取虚拟摄像头名称失败", e);
|
|
|
+ throw new StatusException("ExamCaptureService-001", "获取虚拟摄像头名称失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for(ExamRecordInfo erInfo:dataList) {
|
|
|
+ erInfo.setVirtualCameraNames(getStrFromSet(map.get(erInfo.getId())));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ };
|
|
|
+ tool.setDataForBatch(examRecordDataList, 100);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getStrFromSet(Set<String> set) {
|
|
|
+ if(set==null||set.size()==0) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ StringJoiner sj = new StringJoiner(";");
|
|
|
+ for (String cameraName : set) {
|
|
|
+ sj.add(cameraName);
|
|
|
+ }
|
|
|
+ return sj.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void setInfo(ExamRecordInfo info,Long examId) {
|
|
|
+ info.setDataId(info.getId());
|
|
|
+ if (info.getExamTypeValue() != null) {
|
|
|
+ info.setExamType(info.getExamTypeValue().name());
|
|
|
+ }
|
|
|
+ CourseCacheBean courseBean = ExamCacheTransferHelper.getCachedCourse(info.getCourseId());
|
|
|
+
|
|
|
+ info.setCourseCode(courseBean.getCode());
|
|
|
+ info.setCourseName(courseBean.getName());
|
|
|
+ info.setCourseNameAndCode(courseBean.getName() + "(" + courseBean.getCode() + ")");
|
|
|
+ info.setCourseLevel(CourseLevel.getCourseLevelTitle(courseBean.getLevel()));
|
|
|
+
|
|
|
+ OrgCacheBean orgBean = gainBaseDataService.getOrgBean(info.getOrgId());
|
|
|
+ info.setOrgName(orgBean.getName());
|
|
|
+ //封装详细数据
|
|
|
+ if (info.getStartTime() != null) {
|
|
|
+ info.setPaperStartTime(DateUtils.format(info.getStartTime()));
|
|
|
+ } else {
|
|
|
+ info.setPaperStartTime("");
|
|
|
+ }
|
|
|
+ if (info.getEndTime() != null) {
|
|
|
+ info.setPaperSubmitTime(DateUtils.format(info.getEndTime()));
|
|
|
+ info.setIsSubmit("是");
|
|
|
+ } else {
|
|
|
+ info.setPaperSubmitTime("");
|
|
|
+ info.setIsSubmit("否");
|
|
|
+ }
|
|
|
+
|
|
|
+ //每次考试持续时间
|
|
|
+ if (info.getStartTime() != null && info.getEndTime() != null) {
|
|
|
+ info.setExamTime(info.getUsedExamTime() > 0 ? DateUtils.diff(info.getUsedExamTime()) : "");
|
|
|
+ } else {
|
|
|
+ info.setExamTime("");
|
|
|
+ }
|
|
|
+
|
|
|
+ //违纪标志
|
|
|
+ info.setDisciplineSign(TrueFalse.of(info.getIsWarn()));
|
|
|
+ info.setIsIllegality(TrueFalse.of(info.getIsIllegalityValue()));
|
|
|
+
|
|
|
+ ExamRecordStatus status = info.getExamRecordStatusValue();
|
|
|
+ if (status != null) {
|
|
|
+ info.setExamRecordStatus(status.name());
|
|
|
+ }
|
|
|
+ IsSuccess result = info.getFaceVerifyResultValue();
|
|
|
+ if (result != null) {
|
|
|
+ info.setFaceVerifyResult(result.getDesc());
|
|
|
+ }
|
|
|
+
|
|
|
+ ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(examId);
|
|
|
+ info.setExamName(examBean.getName());
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<ExamRecordInfo> getExamRecordDetailPageForExport(ExamRecordQuery query,Long startId) {
|
|
|
+ StringBuilder sqlBuilder = new StringBuilder();
|
|
|
+ sqlBuilder.append(EXAM_RECORD_EXPORT_SQL);
|
|
|
+ sqlBuilder.append(buildExamRecordCommonSelectCondition(query));
|
|
|
+ sqlBuilder.append(" and ((record_data.is_warn = 0) OR (record_data.is_warn = 1 and record_data.is_audit = 1))");
|
|
|
+ sqlBuilder.append(" and record_data.id >"+startId);
|
|
|
+ sqlBuilder.append(" group by record_data.id ");
|
|
|
+ //根据ip查询
|
|
|
+ if (StringUtils.isNoneBlank(query.getIp())) {
|
|
|
+ sqlBuilder.append(" having ip like '%"+query.getIp()+"%' ");
|
|
|
+ }
|
|
|
+ sqlBuilder.append(" order by record_data.id limit 500");
|
|
|
+
|
|
|
+ RowMapper<ExamRecordInfo> rowMapper=new BeanPropertyRowMapper<ExamRecordInfo>(ExamRecordInfo.class);
|
|
|
+ List<ExamRecordInfo> ret = jdbcTemplate.query(sqlBuilder.toString(), rowMapper);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
@Override
|
|
|
public List<ExamRecordInfo> getExamRecordDetailList(ExamRecordQuery query) {
|
|
|
Check.isNull(query, "查询参数不能为空!");
|
|
@@ -483,6 +865,11 @@ public class ExamRecordServiceImpl implements ExamRecordService {
|
|
|
sqlBuilder.append(EXAM_RECORD_SQL);
|
|
|
sqlBuilder.append(buildExamRecordCommonSelectCondition(query));
|
|
|
sqlBuilder.append(" and ((record_data.is_warn = 0) OR (record_data.is_warn = 1 and record_data.is_audit = 1))");
|
|
|
+ sqlBuilder.append(" group by record_data.id ");
|
|
|
+ //根据ip查询
|
|
|
+ if (StringUtils.isNoneBlank(query.getIp())) {
|
|
|
+ sqlBuilder.append(" having ip like '%"+query.getIp()+"%' ");
|
|
|
+ }
|
|
|
sqlBuilder.append(" order by record_data.id desc");
|
|
|
|
|
|
List<ExamRecordDataEntity> examRecordDataList = jdbcTemplate.query(sqlBuilder.toString(), new RowMapper<ExamRecordDataEntity>() {
|