瀏覽代碼

重构活检和活检属性的相关代码

lideyin 5 年之前
父節點
當前提交
4118728cf1
共有 16 個文件被更改,包括 345 次插入275 次删除
  1. 1 2
      examcloud-core-oe-student-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/student/controller/ExamControlController.java
  2. 28 21
      examcloud-core-oe-student-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/student/controller/FaceBiopsyController.java
  3. 1 2
      examcloud-core-oe-student-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/student/controller/OfflineExamController.java
  4. 5 5
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/bean/FaceBiopsyStepInfo.java
  5. 4 3
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/ExamAuditService.java
  6. 72 58
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/ExamFaceLivenessVerifyService.java
  7. 1 1
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/ExamRecordDataService.java
  8. 1 1
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/FaceBiopsyService.java
  9. 110 80
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamAuditServiceImpl.java
  10. 26 24
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamControlServiceImpl.java
  11. 4 6
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamFaceLivenessVerifyServiceImpl.java
  12. 57 33
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamRecordDataServiceImpl.java
  13. 15 25
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamStudentServiceImpl.java
  14. 18 12
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/FaceBiopsyServiceImpl.java
  15. 1 1
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/OfflineExamServiceImpl.java
  16. 1 1
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/PracticeServiceImpl.java

+ 1 - 2
examcloud-core-oe-student-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/student/controller/ExamControlController.java

@@ -8,7 +8,7 @@ import cn.com.qmth.examcloud.core.basic.api.bean.StudentBean;
 import cn.com.qmth.examcloud.core.basic.api.request.GetStudentReq;
 import cn.com.qmth.examcloud.core.basic.api.response.GetStudentResp;
 import cn.com.qmth.examcloud.core.oe.common.base.Constants;
-import cn.com.qmth.examcloud.core.oe.common.base.helper.ExamCacheTransferHelper;
+import cn.com.qmth.examcloud.core.oe.common.helper.ExamCacheTransferHelper;
 import cn.com.qmth.examcloud.core.oe.common.base.utils.Check;
 import cn.com.qmth.examcloud.core.oe.common.entity.ExamFileAnswerTempEntity;
 import cn.com.qmth.examcloud.core.oe.common.entity.ExamRecordDataEntity;
@@ -28,7 +28,6 @@ import cn.com.qmth.examcloud.core.oe.student.service.ExamControlService;
 import cn.com.qmth.examcloud.core.oe.student.service.ExamRecordDataService;
 import cn.com.qmth.examcloud.core.oe.student.service.ExamSessionInfoService;
 import cn.com.qmth.examcloud.core.oe.student.service.ExamStudentService;
-import cn.com.qmth.examcloud.support.cache.CacheHelper;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import cn.com.qmth.examcloud.web.helpers.SequenceLockHelper;
 import cn.com.qmth.examcloud.web.redis.RedisClient;

+ 28 - 21
examcloud-core-oe-student-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/student/controller/FaceBiopsyController.java

@@ -3,22 +3,22 @@ package cn.com.qmth.examcloud.core.oe.student.controller;
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.core.oe.common.base.Constants;
-import cn.com.qmth.examcloud.core.oe.common.base.helper.ExamCacheTransferHelper;
 import cn.com.qmth.examcloud.core.oe.common.entity.ExamRecordDataEntity;
 import cn.com.qmth.examcloud.core.oe.common.entity.FaceBiopsyItemEntity;
 import cn.com.qmth.examcloud.core.oe.common.entity.FaceBiopsyItemStepEntity;
-import cn.com.qmth.examcloud.core.oe.common.enums.ExamProperties;
 import cn.com.qmth.examcloud.core.oe.common.enums.ExamRecordStatus;
+import cn.com.qmth.examcloud.core.oe.common.enums.FaceBiopsyScheme;
 import cn.com.qmth.examcloud.core.oe.common.enums.FaceBiopsyType;
+import cn.com.qmth.examcloud.core.oe.common.enums.HandInExamType;
+import cn.com.qmth.examcloud.core.oe.common.helper.FaceBiopsyHelper;
 import cn.com.qmth.examcloud.core.oe.common.repository.ExamRecordDataRepo;
 import cn.com.qmth.examcloud.core.oe.common.repository.FaceBiopsyItemRepo;
 import cn.com.qmth.examcloud.core.oe.common.repository.FaceBiopsyItemStepRepo;
 import cn.com.qmth.examcloud.core.oe.student.bean.*;
+import cn.com.qmth.examcloud.core.oe.student.service.ExamControlService;
 import cn.com.qmth.examcloud.core.oe.student.service.ExamFaceLivenessVerifyService;
 import cn.com.qmth.examcloud.core.oe.student.service.ExamSessionInfoService;
 import cn.com.qmth.examcloud.core.oe.student.service.FaceBiopsyService;
-import cn.com.qmth.examcloud.support.cache.CacheHelper;
-import cn.com.qmth.examcloud.support.cache.bean.OrgPropertyCacheBean;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import cn.com.qmth.examcloud.web.helpers.SequenceLockHelper;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
@@ -53,7 +53,8 @@ public class FaceBiopsyController extends ControllerSupport {
     @Autowired
     private ExamFaceLivenessVerifyService examFaceLivenessVerifyService;
 
-    private final String NEW_FACE_BIOPSY_SCHEME = "S2";
+    @Autowired
+    private ExamControlService examControlService;
 
     @ApiOperation(value = "获取活体检测基本信息")
     @GetMapping("/getFaceBiopsyBaseInfo")
@@ -82,28 +83,28 @@ public class FaceBiopsyController extends ControllerSupport {
         }
 
         //考试未开启人脸活体检测,不允许获取活检信息
-        String isFaceVerifyStr = ExamCacheTransferHelper.getCachedExamProperty(examRecordData.getExamId(),
-                examRecordData.getOrgId(), examRecordData.getStudentId(),
-                ExamProperties.IS_FACE_VERIFY.name()).getValue();
-        if (!Constants.isTrue.equals(isFaceVerifyStr)) {
+        Long rootOrgId = user.getRootOrgId();
+        Long examId = examRecordData.getExamId();
+        Long orgId = examRecordData.getOrgId();
+
+        if (!FaceBiopsyHelper.isFaceVerify(rootOrgId, examId, orgId, studentId)) {
             throw new StatusException("200105", "本场考试未开启人脸活体检测");
         }
 
         FaceBiopsyBaseInfo faceBiopsyBaseInfo = new FaceBiopsyBaseInfo();
-        OrgPropertyCacheBean orgProperty = CacheHelper.getOrgProperty(user.getRootOrgId(),
-                Constants.IDENTIFICATION_OF_LIVING_BODY_SCHEME_KEY);
-        faceBiopsyBaseInfo.setIdentificationOfLivingBodyScheme(orgProperty.getValue());
+
+        FaceBiopsyScheme faceBiopsyScheme = FaceBiopsyHelper.getFaceBiopsyScheme(user.getRootOrgId());
+        faceBiopsyBaseInfo.setIdentificationOfLivingBodyScheme(faceBiopsyScheme.getCode());
 
         Integer faceVerifyMinute = null;
         // 如果是新活体检测方案,则使用新的计算方案计算活检开始时间
-        if (NEW_FACE_BIOPSY_SCHEME.equals(orgProperty.getValue())) {
+        if (faceBiopsyScheme == FaceBiopsyScheme.NEW) {
             faceVerifyMinute = faceBiopsyService.getFaceBiopsyStartMinute(examRecordDataId);
         }
         // 非新活检,默认使用旧的活检计算方式
         else {
-            faceVerifyMinute = examFaceLivenessVerifyService.getFaceLivenessVerifyMinute(
-                    examRecordData.getOrgId(), examRecordData.getExamId(), studentId,
-                    examRecordData.getId(), examSessionInfo.getHeartbeat());
+            faceVerifyMinute = examFaceLivenessVerifyService.getFaceLivenessVerifyMinute(user.getRootOrgId(),
+                    orgId, examId, studentId, examRecordData.getId(), examSessionInfo.getHeartbeat());
         }
 
         faceBiopsyBaseInfo.setFaceVerifyMinute(faceVerifyMinute);
@@ -137,10 +138,10 @@ public class FaceBiopsyController extends ControllerSupport {
         }
 
         //考试未开启人脸活体检测,不允许获取活检信息
-        String isFaceVerifyStr = ExamCacheTransferHelper.getCachedExamProperty(examRecordData.getExamId(),
-                examRecordData.getOrgId(), examRecordData.getStudentId(),
-                ExamProperties.IS_FACE_VERIFY.name()).getValue();
-        if (!Constants.isTrue.equals(isFaceVerifyStr)) {
+        Long rootOrgId = user.getRootOrgId();
+        Long examId = examRecordData.getExamId();
+        Long orgId = examRecordData.getOrgId();
+        if (!FaceBiopsyHelper.isFaceVerify(rootOrgId, examId, orgId, studentId)) {
             throw new StatusException("200104", "本场考试未开启人脸活体检测");
         }
 
@@ -199,8 +200,14 @@ public class FaceBiopsyController extends ControllerSupport {
         if (!verifyStepsAllMatch(req.getFaceBiopsyItemId(), req.getExamRecordDataId(), req.getVerifySteps())) {
             throw new StatusException("200110", "活体检测步骤与原始定义不匹配");
         }
+        SaveFaceBiopsyResultResp resp = faceBiopsyService.saveFaceBiopsyResult(req, studentId);
 
-        return faceBiopsyService.saveFaceBiopsyResult(req);
+        //如果活检满足交卷条件,则系统自动交卷,自动交卷逻辑不应该影响活检保存结果,所以不能放一个事务中
+        if (resp.getEndExam()) {
+            examSessionInfoService.deleteExamSessionInfo(studentId);
+            examControlService.handInExam(req.getExamRecordDataId(), HandInExamType.AUTO);
+        }
+        return resp;
     }
 
     /**

+ 1 - 2
examcloud-core-oe-student-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/student/controller/OfflineExamController.java

@@ -2,7 +2,7 @@ package cn.com.qmth.examcloud.core.oe.student.controller;
 
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
-import cn.com.qmth.examcloud.core.oe.common.base.helper.ExamCacheTransferHelper;
+import cn.com.qmth.examcloud.core.oe.common.helper.ExamCacheTransferHelper;
 import cn.com.qmth.examcloud.core.oe.common.base.utils.Check;
 import cn.com.qmth.examcloud.core.oe.common.entity.ExamRecordDataEntity;
 import cn.com.qmth.examcloud.core.oe.common.enums.ExamProperties;
@@ -10,7 +10,6 @@ import cn.com.qmth.examcloud.core.oe.common.enums.ExamType;
 import cn.com.qmth.examcloud.core.oe.common.repository.ExamRecordDataRepo;
 import cn.com.qmth.examcloud.core.oe.student.bean.OfflineExamCourseInfo;
 import cn.com.qmth.examcloud.core.oe.student.service.OfflineExamService;
-import cn.com.qmth.examcloud.support.cache.CacheHelper;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
 import io.swagger.annotations.Api;

+ 5 - 5
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/bean/FaceBiopsyStepInfo.java

@@ -39,7 +39,7 @@ public class FaceBiopsyStepInfo implements JsonSerializable {
 	private Boolean result;
 
 	@ApiModelProperty(value = "指令是否超时")
-	private Boolean readTimeout;
+	private Boolean timeOut;
 
 	@ApiModelProperty(value = "指令执行结果json串")
 	private String resultJson;
@@ -111,11 +111,11 @@ public class FaceBiopsyStepInfo implements JsonSerializable {
 		this.errorMsg = errorMsg;
 	}
 
-	public Boolean getReadTimeout() {
-		return readTimeout;
+	public Boolean getTimeOut() {
+		return timeOut;
 	}
 
-	public void setReadTimeout(Boolean readTimeout) {
-		this.readTimeout = readTimeout;
+	public void setTimeOut(Boolean timeOut) {
+		this.timeOut = timeOut;
 	}
 }

+ 4 - 3
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/ExamAuditService.java

@@ -11,13 +11,14 @@ public interface ExamAuditService {
 
 	/**
 	 * 活体检测失败,系统审核
-	 * @param examRecordDataEntity
+	 * @param examRecordDataId
+	 * @param rootOrgId
 	 */
-	public void saveExamAuditByFaceVerifyFailed(Long examRecordDataId);
+	public void saveExamAuditByFaceVerifyFailed(Long examRecordDataId,Long rootOrgId);
 	
 	/**
 	 * 抓拍照片为0,系统审核
-	 * @param examRecordDataEntity
+	 * @param examRecordDataId
 	 */
 	public void saveExamAuditByNoPhoto(Long examRecordDataId);
 }

+ 72 - 58
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/ExamFaceLivenessVerifyService.java

@@ -8,66 +8,80 @@ import java.util.List;
 
 
 /**
- * @author  	chenken
- * @date    	2018年2月5日 上午8:44:19
- * @company 	QMTH
+ * @author chenken
+ * @date 2018年2月5日 上午8:44:19
+ * @company QMTH
  * @description 活体检测服务接口
  */
 public interface ExamFaceLivenessVerifyService {
-	
-	/**
-	 * 保存活体检测信息
-	 * @param examRecordDataId
-	 */
-	public ExamFaceLivenessVerifyEntity saveFaceVerify(Long examRecordDataId);
-	/**
-	 * 使用考试记录id查询人脸活体检测信息
-	 * @param examRecordDataId
-	 * @return
-	 */
-	public List<ExamFaceLivenessVerifyEntity> listFaceVerifyByExamRecordId(Long examRecordDataId);
-	/**
-	 * 人脸检测完成后回调处理
-	 * @param resultJson
-	 * @return
-	 */
-	public ExamFaceLivenessVerifyEntity faceIdNotify(String resultJson);
-	/**
-	 * 向faceId发起检测请求,返回token
-	 * @param examRecordDataId
-	 * @return
-	 */
-	public GetFaceVerifyTokenInfo getFaceVerifyToken(Long studentId,String bizNo);
-	
-	public ExamFaceLivenessVerifyEntity saveFaceVerifyByExamRecordDataId(Long examRecordDataId);
-	
-	/**
-	 * 根据ID查询
-	 * @param id
-	 * @return
-	 */
-	public ExamFaceLivenessVerifyEntity findFaceVerifyById(Long id);
-	
-	/**
-	 * 人脸检测超时处理
-	 * @param examRecordDataId
-	 */
-	public void faceTestTimeOut(Long examRecordDataId);
-	/**
-	 * 人脸活体检测结束处理
-	 * @param examRecordDataId
-	 * @param  studentId
-	 * @param result
-	 */
-	public void faceTestEndHandle(Long examRecordDataId,Long studentId, String result);
-	/**
-	 * 断点续考,获取活体检测开启时间
-	 * @param examId
-	 * @param examRecordDataId
-	 * @param heartbeat
-	 * @return
-	 */
-	public Integer getFaceLivenessVerifyMinute(Long orgId,Long examId,Long studentId,Long examRecordDataId, Integer heartbeat);
-	
+
+    /**
+     * 保存活体检测信息
+     *
+     * @param examRecordDataId
+     */
+    public ExamFaceLivenessVerifyEntity saveFaceVerify(Long examRecordDataId);
+
+    /**
+     * 使用考试记录id查询人脸活体检测信息
+     *
+     * @param examRecordDataId
+     * @return
+     */
+    public List<ExamFaceLivenessVerifyEntity> listFaceVerifyByExamRecordId(Long examRecordDataId);
+
+    /**
+     * 人脸检测完成后回调处理
+     *
+     * @param resultJson
+     * @return
+     */
+    public ExamFaceLivenessVerifyEntity faceIdNotify(String resultJson);
+
+    /**
+     * 向faceId发起检测请求,返回token
+     *
+     * @param examRecordDataId
+     * @return
+     */
+    public GetFaceVerifyTokenInfo getFaceVerifyToken(Long studentId, String bizNo);
+
+    public ExamFaceLivenessVerifyEntity saveFaceVerifyByExamRecordDataId(Long examRecordDataId);
+
+    /**
+     * 根据ID查询
+     *
+     * @param id
+     * @return
+     */
+    public ExamFaceLivenessVerifyEntity findFaceVerifyById(Long id);
+
+    /**
+     * 人脸检测超时处理
+     *
+     * @param examRecordDataId
+     */
+    public void faceTestTimeOut(Long examRecordDataId);
+
+    /**
+     * 人脸活体检测结束处理
+     *
+     * @param examRecordDataId
+     * @param studentId
+     * @param result
+     */
+    public void faceTestEndHandle(Long examRecordDataId, Long studentId, String result);
+
+    /**
+     * 断点续考,获取活体检测开启时间
+     *
+     * @param examId
+     * @param examRecordDataId
+     * @param heartbeat
+     * @return
+     */
+    public Integer getFaceLivenessVerifyMinute(Long rootOrgId, Long orgId, Long examId,
+                                               Long studentId, Long examRecordDataId, Integer heartbeat);
+
 }
 

+ 1 - 1
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/ExamRecordDataService.java

@@ -101,7 +101,7 @@ public interface ExamRecordDataService {
      *
      * @param examRecordDataEntity
      */
-    ExamRecordDataEntity calculateFaceLivenessVerifyResult(ExamRecordDataEntity examRecordDataEntity);
+    void calculateFaceLivenessVerifyResult(ExamRecordDataEntity examRecordDataEntity);
 
     /**
      * 创建离线考试记录

+ 1 - 1
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/FaceBiopsyService.java

@@ -28,7 +28,7 @@ public interface FaceBiopsyService {
      * @param req
      * @return
      */
-    SaveFaceBiopsyResultResp saveFaceBiopsyResult(SaveFaceBiopsyResultReq req);
+    SaveFaceBiopsyResultResp saveFaceBiopsyResult(SaveFaceBiopsyResultReq req,Long studentId);
 
     /**
      * 获取人脸活体检测开始分钟数

+ 110 - 80
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamAuditServiceImpl.java

@@ -1,99 +1,129 @@
 package cn.com.qmth.examcloud.core.oe.student.service.impl;
 
-import java.util.List;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
 import cn.com.qmth.examcloud.core.oe.common.base.utils.CommonUtil;
 import cn.com.qmth.examcloud.core.oe.common.entity.ExamAuditEntity;
 import cn.com.qmth.examcloud.core.oe.common.entity.ExamFaceLivenessVerifyEntity;
+import cn.com.qmth.examcloud.core.oe.common.entity.FaceBiopsyEntity;
 import cn.com.qmth.examcloud.core.oe.common.enums.AuditStatus;
 import cn.com.qmth.examcloud.core.oe.common.enums.DisciplineType;
+import cn.com.qmth.examcloud.core.oe.common.enums.FaceBiopsyScheme;
 import cn.com.qmth.examcloud.core.oe.common.enums.FaceVerifyResult;
+import cn.com.qmth.examcloud.core.oe.common.helper.FaceBiopsyHelper;
 import cn.com.qmth.examcloud.core.oe.common.repository.ExamAuditRepo;
 import cn.com.qmth.examcloud.core.oe.common.repository.ExamFaceLivenessVerifyRepo;
+import cn.com.qmth.examcloud.core.oe.common.repository.FaceBiopsyRepo;
 import cn.com.qmth.examcloud.core.oe.student.service.ExamAuditService;
+import com.mysql.cj.util.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
 
 /**
- * 
- * @author  	chenken
- * @date    	2018年9月5日 下午3:25:06
- * @company 	QMTH
+ * @author chenken
+ * @date 2018年9月5日 下午3:25:06
+ * @company QMTH
  * @description 学生端-考试记录审核服务实现
  */
 @Service("examAuditService")
 public class ExamAuditServiceImpl implements ExamAuditService {
 
-	//private static final Logger log = LoggerFactory.getLogger(ExamAuditServiceImpl.class);
-	
-	/**
-	 * 活体检测失败自动审核
-	 */
-	private static final String FACE_LIVENESS_VERIFY_AUTO_AUDIT = "FACE_LIVENESS_VERIFY_AUTO_AUDIT";
-	
-	/**
-	 * 无照片自动审核
-	 */
-	private static final String NOPHOTO_VERIFY_AUTO_AUDIT = "NOPHOTO_VERIFY_AUTO_AUDIT";
-	
-	/**
-	 * 系统审核
-	 */
-	private static final String AUDIT_USER_NAME = "SYSTEM";
-	
-	@Autowired
-	private ExamFaceLivenessVerifyRepo examFaceLivenessVerifyRepo;
-	
-	@Autowired
-	private ExamAuditRepo examAuditRepo;
-	
-	@Override
-	public void saveExamAuditByFaceVerifyFailed(Long examRecordDataId) {
-		ExamAuditEntity examAudit = examAuditRepo.findByExamRecordDataId(examRecordDataId);
-		if(examAudit != null){
-			return;
-		}
-		ExamAuditEntity examAuditEntity = new ExamAuditEntity();
-		examAuditEntity.setExamRecordDataId(examRecordDataId);
-		examAuditEntity.setDisciplineType(DisciplineType.ACTION_FAILURE);
-		examAuditEntity.setUserId(FACE_LIVENESS_VERIFY_AUTO_AUDIT);//活体检测自动审核
-		examAuditEntity.setAuditUserName(AUDIT_USER_NAME);
-		
-		List<ExamFaceLivenessVerifyEntity> faceVerifies = examFaceLivenessVerifyRepo.findByExamRecordDataIdOrderById(examRecordDataId);
-		if(faceVerifies == null || faceVerifies.size() == 0){
-			examAuditEntity.setDisciplineDetail("未进行人脸动作检测");
-		}else{
-			StringBuffer sbBuffer = new StringBuffer("");
-			for(ExamFaceLivenessVerifyEntity faceVerify:faceVerifies){
-				String startTime = CommonUtil.getDateStrWithSecond(faceVerify.getStartTime());
-				sbBuffer.append(startTime+":"+FaceVerifyResult.getDescByName(faceVerify.getVerifyResult()));
-				sbBuffer.append("&&");
-			}
-			String disciplineDetail = sbBuffer.toString();
-			if(disciplineDetail.length()>500){
-				disciplineDetail = disciplineDetail.substring(0,500);
-			}
-			examAuditEntity.setDisciplineDetail(disciplineDetail);
-		}
-		examAuditEntity.setStatus(AuditStatus.UN_PASS);
-		examAuditRepo.save(examAuditEntity);
-	}
-
-	@Override
-	public void saveExamAuditByNoPhoto(Long examRecordDataId) {
-		ExamAuditEntity examAudit = examAuditRepo.findByExamRecordDataId(examRecordDataId);
-		if(examAudit != null){
-			return;
-		}
-		ExamAuditEntity examAuditEntity = new ExamAuditEntity();
-		examAuditEntity.setExamRecordDataId(examRecordDataId);
-		examAuditEntity.setDisciplineType(DisciplineType.OTHER);
-		examAuditEntity.setDisciplineDetail("抓拍照片数量为0");
-		examAuditEntity.setUserId(NOPHOTO_VERIFY_AUTO_AUDIT);//抓拍照片为0自动审核
-		examAuditEntity.setAuditUserName(AUDIT_USER_NAME);
-		examAuditEntity.setStatus(AuditStatus.UN_PASS);
-		examAuditRepo.save(examAuditEntity);
-	}
-	
+    //private static final Logger log = LoggerFactory.getLogger(ExamAuditServiceImpl.class);
+
+    /**
+     * 活体检测失败自动审核
+     */
+    private static final String FACE_LIVENESS_VERIFY_AUTO_AUDIT = "FACE_LIVENESS_VERIFY_AUTO_AUDIT";
+
+    /**
+     * 无照片自动审核
+     */
+    private static final String NOPHOTO_VERIFY_AUTO_AUDIT = "NOPHOTO_VERIFY_AUTO_AUDIT";
+
+    /**
+     * 系统审核
+     */
+    private static final String AUDIT_USER_NAME = "SYSTEM";
+
+    @Autowired
+    private ExamFaceLivenessVerifyRepo examFaceLivenessVerifyRepo;
+
+    @Autowired
+    private ExamAuditRepo examAuditRepo;
+
+    @Autowired
+    private FaceBiopsyRepo faceBiopsyRepo;
+
+    @Override
+    public void saveExamAuditByFaceVerifyFailed(Long examRecordDataId, Long rootOrgId) {
+        ExamAuditEntity examAudit = examAuditRepo.findByExamRecordDataId(examRecordDataId);
+        if (examAudit != null) {
+            return;
+        }
+        ExamAuditEntity examAuditEntity = new ExamAuditEntity();
+        examAuditEntity.setExamRecordDataId(examRecordDataId);
+        examAuditEntity.setDisciplineType(DisciplineType.ACTION_FAILURE);
+        examAuditEntity.setUserId(FACE_LIVENESS_VERIFY_AUTO_AUDIT);//活体检测自动审核
+        examAuditEntity.setAuditUserName(AUDIT_USER_NAME);
+        examAuditEntity.setDisciplineDetail(getFaceVerifyDisciplineDetail(examRecordDataId, rootOrgId));//计算违纪描述
+        examAuditEntity.setStatus(AuditStatus.UN_PASS);
+        examAuditRepo.save(examAuditEntity);
+    }
+
+    //获取活检违纪详情
+    private String getFaceVerifyDisciplineDetail(Long examRecordDataId, Long rootOrgId) {
+        FaceBiopsyScheme faceBiopsyScheme = FaceBiopsyHelper.getFaceBiopsyScheme(rootOrgId);
+
+        //新活体检测方案从新表中取相关数据
+        if (faceBiopsyScheme == FaceBiopsyScheme.NEW) {
+            FaceBiopsyEntity faceBiopsy = faceBiopsyRepo.findByExamRecordDataId(examRecordDataId);
+            if (faceBiopsy == null) {
+                return "未进行人脸活体检测";
+            }
+
+            //如果有返回实际的活检错误
+            if (StringUtils.isNullOrEmpty(faceBiopsy.getErrorMsg())) {
+                return faceBiopsy.getErrorMsg();
+            }
+
+            return "活检失败";
+        }
+        //旧活体检测方案从旧表中取相关数据
+        else {
+            List<ExamFaceLivenessVerifyEntity> faceVerifies =
+                    examFaceLivenessVerifyRepo.findByExamRecordDataIdOrderById(examRecordDataId);
+            if (faceVerifies == null || faceVerifies.size() == 0) {
+                return "未进行人脸动作检测";
+            } else {
+                StringBuffer sbBuffer = new StringBuffer("");
+                for (ExamFaceLivenessVerifyEntity faceVerify : faceVerifies) {
+                    String startTime = CommonUtil.getDateStrWithSecond(faceVerify.getStartTime());
+                    sbBuffer.append(startTime + ":" + FaceVerifyResult.getDescByName(faceVerify.getVerifyResult()));
+                    sbBuffer.append("&&");
+                }
+                String disciplineDetail = sbBuffer.toString();
+                if (disciplineDetail.length() > 500) {
+                    disciplineDetail = disciplineDetail.substring(0, 500);
+                }
+                return disciplineDetail;
+            }
+        }
+    }
+
+    @Override
+    public void saveExamAuditByNoPhoto(Long examRecordDataId) {
+        ExamAuditEntity examAudit = examAuditRepo.findByExamRecordDataId(examRecordDataId);
+        if (examAudit != null) {
+            return;
+        }
+        ExamAuditEntity examAuditEntity = new ExamAuditEntity();
+        examAuditEntity.setExamRecordDataId(examRecordDataId);
+        examAuditEntity.setDisciplineType(DisciplineType.OTHER);
+        examAuditEntity.setDisciplineDetail("抓拍照片数量为0");
+        examAuditEntity.setUserId(NOPHOTO_VERIFY_AUTO_AUDIT);//抓拍照片为0自动审核
+        examAuditEntity.setAuditUserName(AUDIT_USER_NAME);
+        examAuditEntity.setStatus(AuditStatus.UN_PASS);
+        examAuditRepo.save(examAuditEntity);
+    }
+
 }

+ 26 - 24
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamControlServiceImpl.java

@@ -9,11 +9,12 @@ import cn.com.qmth.examcloud.commons.util.UrlUtil;
 import cn.com.qmth.examcloud.commons.util.Util;
 import cn.com.qmth.examcloud.core.basic.api.bean.CourseBean;
 import cn.com.qmth.examcloud.core.oe.common.base.Constants;
-import cn.com.qmth.examcloud.core.oe.common.base.helper.ExamCacheTransferHelper;
 import cn.com.qmth.examcloud.core.oe.common.base.utils.CommonUtil;
 import cn.com.qmth.examcloud.core.oe.common.base.utils.QuestionTypeUtil;
 import cn.com.qmth.examcloud.core.oe.common.entity.*;
 import cn.com.qmth.examcloud.core.oe.common.enums.*;
+import cn.com.qmth.examcloud.core.oe.common.helper.ExamCacheTransferHelper;
+import cn.com.qmth.examcloud.core.oe.common.helper.FaceBiopsyHelper;
 import cn.com.qmth.examcloud.core.oe.common.repository.*;
 import cn.com.qmth.examcloud.core.oe.common.service.ExamScoreObtainQueueService;
 import cn.com.qmth.examcloud.core.oe.common.service.ExamScorePushQueueService;
@@ -174,8 +175,6 @@ public class ExamControlServiceImpl implements ExamControlService {
     @Value("${$upyun.site.1.domain}")
     private String upyunFileUrl;
 
-    private final String NEW_FACE_BIOPSY_SCHEME = "S2";
-
     @Transactional
     @Override
     public StartExamInfo startExam(Long examStudentId, User user) {
@@ -277,13 +276,16 @@ public class ExamControlServiceImpl implements ExamControlService {
                 originalExamStudent.getIsReExamine(), extractConfigPaper.getDefaultPaper().getFullyObjective());
 
         // 生成进行中的考试记录
-        examRecordDataService.createExamingRecord(examRecordData.getId(), examRecordData.getStudentId(),
+        Long studentId = examRecordData.getStudentId();
+        examRecordDataService.createExamingRecord(examRecordData.getId(), studentId,
                 examRecordData.getExamType());
 
         // 如果开启人脸比对,将同步人脸比对结果存储到抓后结果表中
-        String isFaceEnable = ExamCacheTransferHelper.getCachedExamProperty(examRecordData.getExamId(), examRecordData.getOrgId(),
-                examRecordData.getStudentId(), ExamProperties.IS_FACE_ENABLE.name()).getValue();
-        if (isFaceEnable != null && Constants.isTrue.equals(isFaceEnable)) {
+        Long rootOrgId = examRecordData.getRootOrgId();
+        Long examId = examRecordData.getExamId();
+        Long orgId = examRecordData.getOrgId();
+
+        if (FaceBiopsyHelper.isFaceEnable(rootOrgId, examId, orgId, studentId)) {
             SaveExamCaptureSyncCompareResultReq req = new SaveExamCaptureSyncCompareResultReq();
             req.setExamRecordDataId(examRecordData.getId());
             req.setStudentId(user.getUserId());
@@ -395,7 +397,7 @@ public class ExamControlServiceImpl implements ExamControlService {
         startExamInfo.setCourseCode(examStudentEntity.getCourseCode());
         startExamInfo.setCourseName(courseBean.getName());
         startExamInfo.setDuration(examBean.getDuration());
-        startExamInfo.setFaceVerifyMinute(getFaceVerifyMinute(examBean.getId(), examStudentEntity.getOrgId(),
+        startExamInfo.setFaceVerifyMinute(getFaceVerifyMinute(examStudentEntity.getRootOrgId(), examBean.getId(), examStudentEntity.getOrgId(),
                 examStudentEntity.getStudentId()));
         return startExamInfo;
     }
@@ -406,11 +408,9 @@ public class ExamControlServiceImpl implements ExamControlService {
      * @param examId
      * @return
      */
-    private Integer getFaceVerifyMinute(Long examId, Long orgId, Long studentId) {
-        String isFaceVerifyStr = ExamCacheTransferHelper.getCachedExamProperty(examId, orgId,
-                studentId, ExamProperties.IS_FACE_VERIFY.name()).getValue();
+    private Integer getFaceVerifyMinute(Long rootOrgId, Long examId, Long orgId, Long studentId) {
         // 如果开启了活体检测
-        if (Constants.isTrue.equals(isFaceVerifyStr)) {
+        if (FaceBiopsyHelper.isFaceVerify(rootOrgId, examId, orgId, studentId)) {
             // 开始分钟数
             String startMinuteStr = ExamCacheTransferHelper
                     .getCachedExamProperty(examId, orgId, studentId, ExamProperties.FACE_VERIFY_START_MINUTE.name()).getValue();
@@ -720,20 +720,22 @@ public class ExamControlServiceImpl implements ExamControlService {
             log.debug("1  [HAND_IN_EXAM]获取考试记录耗时:" + (System.currentTimeMillis() - startTime) + " ms");
         }
 
+        Long studentId = examRecordData.getStudentId();
         if (handInExamType == HandInExamType.MANUAL) {
             startTime = System.currentTimeMillis();
 
             // 得到考试时长,校验是否达到冻结时间
-            long usedExamTime = checkAndComputeExamDuration(examRecordData.getStudentId());
+            long usedExamTime = checkAndComputeExamDuration(studentId);
             examRecordData.setUsedExamTime(usedExamTime);
             examRecordData.setExamRecordStatus(ExamRecordStatus.EXAM_HAND_IN);
             examRecordData.setEndTime(new Date());
 
             // 手工手卷时,如果开启人脸检测,则更新抓拍队列优先级
-            String isFaceEnable = ExamCacheTransferHelper.getCachedExamProperty(examRecordData.getExamId(),
-                    examRecordData.getOrgId(),
-                    examRecordData.getStudentId(), ExamProperties.IS_FACE_ENABLE.name()).getValue();
-            if (isFaceEnable != null && Constants.isTrue.equals(isFaceEnable)) {
+            Long rootOrgId = examRecordData.getRootOrgId();
+            Long examId = examRecordData.getExamId();
+            Long orgId = examRecordData.getOrgId();
+
+            if (FaceBiopsyHelper.isFaceEnable(rootOrgId, examId, rootOrgId, studentId)) {
                 // 更新照片抓拍队列优先级为高优先级
                 examCaptureQueueRepo.updateExamCaptureQueuePriority(Constants.PROCESS_CAPTURE_HIGH_PRIORITY,
                         examRecordData.getId());
@@ -772,7 +774,7 @@ public class ExamControlServiceImpl implements ExamControlService {
 
         startTime = System.currentTimeMillis();
         // 把进行中的考试记录放入交卷队列中
-        examRecordDataService.createHandInExamRecord(examRecordData.getId(), examRecordData.getStudentId());
+        examRecordDataService.createHandInExamRecord(examRecordData.getId(), studentId);
         if (log.isDebugEnabled()) {
             log.debug("4 [HAND_IN_EXAM]把进行中的考试记录放入交卷队列中耗时:" + (System.currentTimeMillis() - startTime) + " ms");
         }
@@ -786,7 +788,7 @@ public class ExamControlServiceImpl implements ExamControlService {
 
         startTime = System.currentTimeMillis();
         // 删除redis会话
-        examSessionInfoService.deleteExamSessionInfo(examRecordData.getStudentId());
+        examSessionInfoService.deleteExamSessionInfo(studentId);
         if (log.isDebugEnabled()) {
             log.debug("6 [HAND_IN_EXAM]删除redis会话:" + (System.currentTimeMillis() - startTime) + " ms");
         }
@@ -821,7 +823,7 @@ public class ExamControlServiceImpl implements ExamControlService {
                 .calculateFaceCheckResult(examRecordData);
         examRecordData = calculateFaceCheckResultInfo.getExamRecordData();
         // 计算活体检测结果(根据已检测出照片数据更新考试记录中的相关人脸检测的统计字段)
-        examRecordData = examRecordDataService.calculateFaceLivenessVerifyResult(examRecordData);
+        examRecordDataService.calculateFaceLivenessVerifyResult(examRecordData);
         // 违纪自动审核
         examRecordData = examRecordDataService
                 .examRecordAutoAudit(calculateFaceCheckResultInfo.getIsNoPhotoAndIllegality(), examRecordData);
@@ -934,17 +936,17 @@ public class ExamControlServiceImpl implements ExamControlService {
 
             // 断点续考时重新计算活体检测的分钟数
             Integer faceVerifyMinute = null;
-            OrgPropertyCacheBean orgProperty = CacheHelper.getOrgProperty(examStudentEntity.getRootOrgId(),
-                    Constants.IDENTIFICATION_OF_LIVING_BODY_SCHEME_KEY);
+            FaceBiopsyScheme faceBiopsyScheme = FaceBiopsyHelper.getFaceBiopsyScheme(examStudentEntity.getRootOrgId());
 
             // 如果是新活体检测方案,则使用新的计算方案计算活检开始时间
-            if (NEW_FACE_BIOPSY_SCHEME.equals(orgProperty.getValue())) {
+            if (faceBiopsyScheme == FaceBiopsyScheme.NEW) {
                 faceVerifyMinute = faceBiopsyService.getFaceBiopsyStartMinute(examingRecord.getExamRecordDataId());
             }
             // 非新活检,默认使用旧的活检计算方式
             else {
                 faceVerifyMinute = examFaceLivenessVerifyService.getFaceLivenessVerifyMinute(
-                        examStudentEntity.getOrgId(), examStudentEntity.getExamId(), studentId,
+                        examStudentEntity.getRootOrgId(), examStudentEntity.getOrgId(),
+                        examStudentEntity.getExamId(), studentId,
                         examingRecord.getExamRecordDataId(), examSessionInfo.getHeartbeat());
             }
 

+ 4 - 6
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamFaceLivenessVerifyServiceImpl.java

@@ -1,8 +1,6 @@
 package cn.com.qmth.examcloud.core.oe.student.service.impl;
 
 import cn.com.qmth.examcloud.commons.exception.StatusException;
-import cn.com.qmth.examcloud.core.oe.common.base.Constants;
-import cn.com.qmth.examcloud.core.oe.common.base.helper.ExamCacheTransferHelper;
 import cn.com.qmth.examcloud.core.oe.common.base.utils.CommonUtil;
 import cn.com.qmth.examcloud.core.oe.common.base.utils.FileDisposeUtil;
 import cn.com.qmth.examcloud.core.oe.common.base.utils.HttpPoolUtil;
@@ -12,6 +10,8 @@ import cn.com.qmth.examcloud.core.oe.common.enums.ExamProperties;
 import cn.com.qmth.examcloud.core.oe.common.enums.FaceVerifyResult;
 import cn.com.qmth.examcloud.core.oe.common.enums.HandInExamType;
 import cn.com.qmth.examcloud.core.oe.common.enums.IsSuccess;
+import cn.com.qmth.examcloud.core.oe.common.helper.ExamCacheTransferHelper;
+import cn.com.qmth.examcloud.core.oe.common.helper.FaceBiopsyHelper;
 import cn.com.qmth.examcloud.core.oe.common.repository.ExamFaceLivenessVerifyRepo;
 import cn.com.qmth.examcloud.core.oe.common.repository.ExamRecordDataRepo;
 import cn.com.qmth.examcloud.core.oe.common.service.GainBaseDataService;
@@ -279,12 +279,10 @@ public class ExamFaceLivenessVerifyServiceImpl implements ExamFaceLivenessVerify
     }
 
     @Override
-    public Integer getFaceLivenessVerifyMinute(Long orgId, Long examId, Long studentId,
+    public Integer getFaceLivenessVerifyMinute(Long rootOrgId, Long orgId, Long examId, Long studentId,
                                                Long examRecordDataId, Integer heartbeat) {
-        String isFaceVerifyStr = ExamCacheTransferHelper.getCachedExamProperty(examId, orgId,
-                studentId, ExamProperties.IS_FACE_VERIFY.name()).getValue();
         //开启了人脸检测
-        if (Constants.isTrue.equals(isFaceVerifyStr)) {
+        if (FaceBiopsyHelper.isFaceVerify(rootOrgId, examId, orgId, studentId)) {
 
             List<ExamFaceLivenessVerifyEntity> faceLivenessVerifys = listFaceVerifyByExamRecordId(examRecordDataId);
             //如果没有进行过人脸检测

+ 57 - 33
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamRecordDataServiceImpl.java

@@ -2,13 +2,13 @@ package cn.com.qmth.examcloud.core.oe.student.service.impl;
 
 import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.core.basic.api.bean.CourseBean;
-import cn.com.qmth.examcloud.core.oe.common.base.Constants;
-import cn.com.qmth.examcloud.core.oe.common.base.helper.ExamCacheTransferHelper;
 import cn.com.qmth.examcloud.core.oe.common.base.jpa.Searcher;
 import cn.com.qmth.examcloud.core.oe.common.base.jpa.SpecUtils;
 import cn.com.qmth.examcloud.core.oe.common.base.utils.CommonUtil;
 import cn.com.qmth.examcloud.core.oe.common.entity.*;
 import cn.com.qmth.examcloud.core.oe.common.enums.*;
+import cn.com.qmth.examcloud.core.oe.common.helper.ExamCacheTransferHelper;
+import cn.com.qmth.examcloud.core.oe.common.helper.FaceBiopsyHelper;
 import cn.com.qmth.examcloud.core.oe.common.repository.*;
 import cn.com.qmth.examcloud.core.oe.common.service.ExamScoreObtainQueueService;
 import cn.com.qmth.examcloud.core.oe.common.service.ExamScorePushQueueService;
@@ -17,7 +17,6 @@ import cn.com.qmth.examcloud.core.oe.student.bean.CalculateFaceCheckResultInfo;
 import cn.com.qmth.examcloud.core.oe.student.face.api.ExamCaptureQueueCloudService;
 import cn.com.qmth.examcloud.core.oe.student.service.*;
 import cn.com.qmth.examcloud.examwork.api.bean.ExamBean;
-import cn.com.qmth.examcloud.support.cache.CacheHelper;
 import cn.com.qmth.examcloud.web.bootstrap.PropertyHolder;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import org.apache.commons.lang3.StringUtils;
@@ -84,6 +83,9 @@ public class ExamRecordDataServiceImpl implements ExamRecordDataService {
     @Autowired
     private HandInExamRecordRepo handInExamRecordRepo;
 
+    @Autowired
+    FaceBiopsyRepo faceBiopsyRepo;
+
     private static final Logger log = LoggerFactory.getLogger(ExamRecordDataServiceImpl.class);
 
     @Override
@@ -191,46 +193,68 @@ public class ExamRecordDataServiceImpl implements ExamRecordDataService {
      * @return
      */
     @Override
-    public ExamRecordDataEntity calculateFaceLivenessVerifyResult(ExamRecordDataEntity examRecordDataEntity) {
-        if (examRecordDataEntity.getFaceVerifyResult() != null) {
-            if (examRecordDataEntity.getFaceVerifyResult() == IsSuccess.FAILED) {
-                List<ExamFaceLivenessVerifyEntity> faceVerifies = examFaceLivenessVerifyRepo.findByExamRecordDataIdOrderById(examRecordDataEntity.getId());
-                setExamRecordWithFaceLivenessVerifyFailed(examRecordDataEntity, faceVerifies);
+    public void calculateFaceLivenessVerifyResult(ExamRecordDataEntity examRecordDataEntity) {
+        //活体检测结果
+        IsSuccess faceVerifyResult = examRecordDataEntity.getFaceVerifyResult();
+
+        //如果活检结果不为空,且活检失败,需要更新考试记录的其它状态信息
+        if (faceVerifyResult != null) {
+            if (faceVerifyResult == IsSuccess.FAILED) {
+                setExamRecordByFaceVerifyResult(examRecordDataEntity, IsSuccess.FAILED);
             }
-        } else {
+            return;
+        }
+        //如果考试记录中的活检记录为空,需要再次计算一次,并更新到考试记录中
+        else {
             Long examId = examRecordDataEntity.getExamId();
-            String isFaceVerify = ExamCacheTransferHelper.getCachedExamProperty(examId,
-                    examRecordDataEntity.getOrgId(), examRecordDataEntity.getStudentId(),
-                    ExamProperties.IS_FACE_VERIFY.name()).getValue();
+            Long rootOrgId = examRecordDataEntity.getRootOrgId();
+            Long orgId = examRecordDataEntity.getOrgId();
+            Long studentId = examRecordDataEntity.getStudentId();
 
             //是否进行活体检测
-            if (isFaceVerify != null && Constants.isTrue.equals(isFaceVerify)) {
-                List<ExamFaceLivenessVerifyEntity> faceVerifies = examFaceLivenessVerifyRepo.findByExamRecordDataIdOrderById(examRecordDataEntity.getId());
-                if (faceVerifies != null && faceVerifies.size() > 0) {
-                    ExamFaceLivenessVerifyEntity latestFaceVerify = faceVerifies.get(faceVerifies.size() - 1);
-                    if (latestFaceVerify != null && latestFaceVerify.getVerifyResult() != null && latestFaceVerify.getVerifyResult() == FaceVerifyResult.VERIFY_SUCCESS) {
-                        examRecordDataEntity.setFaceVerifyResult(IsSuccess.SUCCESS);
-                    } else {
-                        setExamRecordWithFaceLivenessVerifyFailed(examRecordDataEntity, faceVerifies);
+            if (FaceBiopsyHelper.isFaceVerify(rootOrgId, examId, orgId, studentId)) {
+                FaceBiopsyScheme faceBiopsyScheme = FaceBiopsyHelper.getFaceBiopsyScheme(rootOrgId);
+                //新活体检测方案
+                if (faceBiopsyScheme == FaceBiopsyScheme.NEW) {
+                    FaceBiopsyEntity faceBiopsy = faceBiopsyRepo.findByExamRecordDataId(examRecordDataEntity.getId());
+
+                    //如果活检结果最终为true,则更新考试记录相关属性
+                    if (faceBiopsy != null && faceBiopsy.getResult()) {
+                        setExamRecordByFaceVerifyResult(examRecordDataEntity, IsSuccess.SUCCESS);
+                        return;
+                    }
+                }
+                //旧活体检测方案
+                else {
+                    List<ExamFaceLivenessVerifyEntity> faceVerifies =
+                            examFaceLivenessVerifyRepo.findByExamRecordDataIdOrderById(examRecordDataEntity.getId());
+                    if (faceVerifies != null && faceVerifies.size() > 0) {
+                        ExamFaceLivenessVerifyEntity latestFaceVerify = faceVerifies.get(faceVerifies.size() - 1);
+                        //最后一次活检成功,则认为成功,并更新考试记录相关属性
+                        if (latestFaceVerify != null && latestFaceVerify.getVerifyResult() != null &&
+                                latestFaceVerify.getVerifyResult() == FaceVerifyResult.VERIFY_SUCCESS) {
+                            setExamRecordByFaceVerifyResult(examRecordDataEntity, IsSuccess.SUCCESS);
+                            return;
+                        }
                     }
-                } else {
-                    setExamRecordWithFaceLivenessVerifyFailed(examRecordDataEntity, faceVerifies);
                 }
             }
+            //默认更新为失败
+            setExamRecordByFaceVerifyResult(examRecordDataEntity, IsSuccess.FAILED);
         }
-        return examRecordDataEntity;
     }
 
     /**
-     * 活体检测失败,设置考试记录属性
+     * 根据活体检测检测结果设置考试记录相关属性
      *
      * @param examRecordDataEntity
-     * @param faceVerifies
      */
-    private void setExamRecordWithFaceLivenessVerifyFailed(ExamRecordDataEntity examRecordDataEntity, List<ExamFaceLivenessVerifyEntity> faceVerifies) {
-        examRecordDataEntity.setIsIllegality(true);//判定为违纪
-        examRecordDataEntity.setIsWarn(true);    //有警告
-        examRecordDataEntity.setFaceVerifyResult(IsSuccess.FAILED);//活体检测失败
+    private void setExamRecordByFaceVerifyResult(ExamRecordDataEntity examRecordDataEntity, IsSuccess faceVerifyResult) {
+        examRecordDataEntity.setFaceVerifyResult(faceVerifyResult);
+        if (faceVerifyResult == IsSuccess.FAILED) {
+            examRecordDataEntity.setIsIllegality(true);//判定为违纪
+            examRecordDataEntity.setIsWarn(true);    //有警告
+        }
     }
 
     /**
@@ -252,13 +276,13 @@ public class ExamRecordDataServiceImpl implements ExamRecordDataService {
     @Override
     public CalculateFaceCheckResultInfo calculateFaceCheckResult(ExamRecordDataEntity examRecordData) {
         CalculateFaceCheckResultInfo calculateFaceCheckResultInfo = new CalculateFaceCheckResultInfo();
+        Long rootOrgId = examRecordData.getRootOrgId();
         Long examId = examRecordData.getExamId();
         Long orgId = examRecordData.getOrgId();
         Long studentId = examRecordData.getStudentId();
-        String isFaceEnable = ExamCacheTransferHelper.getCachedExamProperty(examId, orgId,
-                studentId, ExamProperties.IS_FACE_ENABLE.name()).getValue();
+
         //未开启人脸检测
-        if (!Constants.isTrue.equals(isFaceEnable)) {
+        if (!FaceBiopsyHelper.isFaceEnable(rootOrgId, examId, orgId, studentId)) {
             examRecordData.setIsWarn(false);
             calculateFaceCheckResultInfo.setExamRecordData(examRecordData);
             return calculateFaceCheckResultInfo;
@@ -452,7 +476,7 @@ public class ExamRecordDataServiceImpl implements ExamRecordDataService {
             if (examRecordData.getFaceVerifyResult() != null
                     && examRecordData.getFaceVerifyResult() == IsSuccess.FAILED
                     && examRecordData.getIsIllegality()) {
-                examAuditService.saveExamAuditByFaceVerifyFailed(examRecordData.getId());
+                examAuditService.saveExamAuditByFaceVerifyFailed(examRecordData.getId(), examRecordData.getRootOrgId());
                 examRecordData.setIsAudit(true);
             }
         }

+ 15 - 25
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamStudentServiceImpl.java

@@ -1,12 +1,13 @@
 package cn.com.qmth.examcloud.core.oe.student.service.impl;
 
 import cn.com.qmth.examcloud.core.basic.api.bean.CourseBean;
-import cn.com.qmth.examcloud.core.oe.common.base.helper.ExamCacheTransferHelper;
+import cn.com.qmth.examcloud.core.oe.common.helper.ExamCacheTransferHelper;
 import cn.com.qmth.examcloud.core.oe.common.base.utils.CommonUtil;
 import cn.com.qmth.examcloud.core.oe.common.entity.ExamStudentEntity;
 import cn.com.qmth.examcloud.core.oe.common.enums.CourseLevel;
 import cn.com.qmth.examcloud.core.oe.common.enums.ExamProperties;
 import cn.com.qmth.examcloud.core.oe.common.enums.ExamType;
+import cn.com.qmth.examcloud.core.oe.common.helper.FaceBiopsyHelper;
 import cn.com.qmth.examcloud.core.oe.common.repository.ExamStudentRepo;
 import cn.com.qmth.examcloud.core.oe.common.service.GainBaseDataService;
 import cn.com.qmth.examcloud.core.oe.student.bean.ExamStudentInfo;
@@ -93,7 +94,8 @@ public class ExamStudentServiceImpl implements ExamStudentService {
         examStudentInfo.setExamStudentId(examStudent.getExamStudentId());
         examStudentInfo.setStudentCode(examStudent.getStudentCode());
         examStudentInfo.setStudentName(examStudent.getStudentName());
-        examStudentInfo.setRootOrgId(examStudent.getRootOrgId());
+        Long rootOrgId = examStudent.getRootOrgId();
+        examStudentInfo.setRootOrgId(rootOrgId);
         examStudentInfo.setIdentityNumber(examStudent.getIdentityNumber());
 
         CourseBean courseBean = ExamCacheTransferHelper.getCachedCourse(examStudent.getCourseId());
@@ -102,41 +104,29 @@ public class ExamStudentServiceImpl implements ExamStudentService {
         examStudentInfo.setCourseLevel(CourseLevel.getCourseLevel(courseBean.getLevel()).getTitle());
         examStudentInfo.setCourseId(examStudent.getCourseId());
         examStudentInfo.setSpecialtyName(examStudent.getSpecialtyName());
-        examStudentInfo.setOrgId(examStudent.getOrgId());
+        Long orgId = examStudent.getOrgId();
+        examStudentInfo.setOrgId(orgId);
 
-        OrgCacheBean orgBean = gainBaseDataService.getOrgBean(examStudent.getOrgId());
+        OrgCacheBean orgBean = gainBaseDataService.getOrgBean(orgId);
+        Long studentId = examStudent.getStudentId();
         ExamBean examBean = ExamCacheTransferHelper.getCachedExam(examStudent.getExamId(),
-                examStudent.getOrgId(), examStudent.getStudentId());
+                orgId, studentId);
 
         examStudentInfo.setOrgName(orgBean.getName());
-        examStudentInfo.setExamId(examBean.getId());
+        Long examId = examBean.getId();
+        examStudentInfo.setExamId(examId);
         examStudentInfo.setExamName(examBean.getName());
         examStudentInfo.setStartTime(examSpecialSettingsBean.getBeginTime());//考试开始时间设置
         examStudentInfo.setEndTime(examSpecialSettingsBean.getEndTime());//考试结束时间设置
         examStudentInfo.setAllowExamCount(countExamTimes(examStudent, examBean));
         examStudentInfo.setPaperMins(examBean.getDuration());
-
         //是否启用人脸识别
-        String isFaceEnable = ExamCacheTransferHelper.getCachedExamProperty(examBean.getId(), examStudent.getOrgId(),
-                examStudent.getStudentId(), ExamProperties.IS_FACE_ENABLE.name()).getValue();
-        if (StringUtils.isBlank(isFaceEnable)) {
-            examStudentInfo.setFaceEnable(false);
-        } else {
-            examStudentInfo.setFaceEnable(Boolean.valueOf(isFaceEnable));
-            Class booleanClass = Boolean.class;
-        }
-
+        examStudentInfo.setFaceEnable(FaceBiopsyHelper.isFaceEnable(rootOrgId, examId, orgId, studentId));
         //进入考试是否验证人脸识别(强制、非强制)
-        String isFaceCheck = ExamCacheTransferHelper.getCachedExamProperty(examBean.getId(), examStudent.getOrgId(),
-                examStudent.getStudentId(), ExamProperties.IS_FACE_CHECK.name()).getValue();
-        if (StringUtils.isBlank(isFaceCheck)) {
-            examStudentInfo.setFaceCheck(false);
-        } else {
-            examStudentInfo.setFaceCheck(Boolean.valueOf(isFaceCheck));
-        }
+        examStudentInfo.setFaceCheck(FaceBiopsyHelper.isFaceCheck(examId, orgId, studentId));
         //是否显示客观分
-        String isObjScoreView = ExamCacheTransferHelper.getCachedExamProperty(examBean.getId(), examStudent.getOrgId(),
-                examStudent.getStudentId(), ExamProperties.IS_OBJ_SCORE_VIEW.name()).getValue();
+        String isObjScoreView = ExamCacheTransferHelper.getCachedExamProperty(examId, orgId,
+                studentId, ExamProperties.IS_OBJ_SCORE_VIEW.name()).getValue();
         if (StringUtils.isBlank(isObjScoreView)) {
             examStudentInfo.setIsObjScoreView(false);
         } else {

+ 18 - 12
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/FaceBiopsyServiceImpl.java

@@ -3,7 +3,7 @@ package cn.com.qmth.examcloud.core.oe.student.service.impl;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.commons.util.JsonUtil;
 import cn.com.qmth.examcloud.core.oe.common.base.Constants;
-import cn.com.qmth.examcloud.core.oe.common.base.helper.ExamCacheTransferHelper;
+import cn.com.qmth.examcloud.core.oe.common.helper.ExamCacheTransferHelper;
 import cn.com.qmth.examcloud.core.oe.common.base.utils.CommonUtil;
 import cn.com.qmth.examcloud.core.oe.common.entity.ExamRecordDataEntity;
 import cn.com.qmth.examcloud.core.oe.common.entity.FaceBiopsyEntity;
@@ -13,6 +13,7 @@ import cn.com.qmth.examcloud.core.oe.common.enums.ExamProperties;
 import cn.com.qmth.examcloud.core.oe.common.enums.FaceBiopsyAction;
 import cn.com.qmth.examcloud.core.oe.common.enums.FaceBiopsyType;
 import cn.com.qmth.examcloud.core.oe.common.enums.IsSuccess;
+import cn.com.qmth.examcloud.core.oe.common.helper.FaceBiopsyHelper;
 import cn.com.qmth.examcloud.core.oe.common.repository.ExamRecordDataRepo;
 import cn.com.qmth.examcloud.core.oe.common.repository.FaceBiopsyItemRepo;
 import cn.com.qmth.examcloud.core.oe.common.repository.FaceBiopsyItemStepRepo;
@@ -102,7 +103,6 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
         }
 
 
-
         //如果不是第一次人脸活体检测,判断是否有未检测完的记录,
         FaceBiopsyInfo result = new FaceBiopsyInfo();
         // 未完成的活体检测列表
@@ -149,7 +149,7 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
 
     @Override
     @Transactional
-    public SaveFaceBiopsyResultResp saveFaceBiopsyResult(SaveFaceBiopsyResultReq req) {
+    public SaveFaceBiopsyResultResp saveFaceBiopsyResult(SaveFaceBiopsyResultReq req, Long studentId) {
         //构建业务实体
         SaveFaceBiopsyResultResp resp = buildSaveFaceBiopsyResultResp(req.getExamRecordDataId(), req.getVerifySteps());
 
@@ -297,7 +297,7 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
             }
 
             //如果当前步骤为超时,则直接跳出循环
-            if ((stepInfo.getReadTimeout() != null && stepInfo.getReadTimeout())) {
+            if ((stepInfo.getTimeOut() != null && stepInfo.getTimeOut())) {
                 errorMsg = "未在指定时间内完成指令";
                 finalIsSuccess = false;
                 break;
@@ -312,7 +312,12 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
                 case FACE_COMPARE:
                     //如果第一步检测部分失败(照片非本人或检测中多人脸),需要结束考试
                     Map faceCompareResult = JsonUtil.fromJson(stepInfo.getResultJson(), Map.class);
-                    //TODO 取照片检测结果
+
+                    if (null == faceCompareResult.get("isStranger") || null == faceCompareResult.get("isPass") ||
+                            null == faceCompareResult.get("existsSystemError")) {
+                        throw new StatusException("201007", "活体检测第一步检测结果的json串格式不正确");
+                    }
+
                     Boolean isStranger = Boolean.valueOf(faceCompareResult.get("isStranger").toString());
                     Boolean isPass = Boolean.valueOf(faceCompareResult.get("isPass").toString());
                     Boolean existsSystemError = Boolean.valueOf(faceCompareResult.get("existsSystemError").toString());
@@ -677,16 +682,13 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
                                                    FreezeTimeBorder freezeTimeBorder) {
         ExamRecordDataEntity examRecordData = GlobalHelper.getEntity(examRecordDataRepo, examRecordDataId,
                 ExamRecordDataEntity.class);
+        Long rootOrgId = examRecordData.getRootOrgId();
         Long examId = examRecordData.getExamId();
         Long orgId = examRecordData.getOrgId();
         Long studentId = examRecordData.getStudentId();
 
-        //再次校验是否开启人脸活体校验
-        String isFaceVerifyStr = ExamCacheTransferHelper.getCachedExamProperty(examId, orgId,
-                studentId, ExamProperties.IS_FACE_VERIFY.name()).getValue();
-
         //如果未开启人脸活体检测,则返回null
-        if (!Constants.isTrue.equals(isFaceVerifyStr)) {
+        if (!FaceBiopsyHelper.isFaceVerify(rootOrgId, examId, orgId, studentId)) {
             return null;
         }
 
@@ -696,6 +698,10 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
         }
 
         Integer heartbeat = examSessionInfo.getHeartbeat();
+        //由于会话心跳的默认值为-1,所以这里需要特殊处理一下
+        if (heartbeat < 0) {
+            heartbeat = 0;
+        }
         Integer freezeTime = examSessionInfo.getFreezeTime();
 
         //如果特殊指定了获取冻结时间外或冻结时间内的计算方法,则根据参数分别调用相关方法
@@ -760,12 +766,12 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
                     studentId, ExamProperties.FACE_VERIFY_END_MINUTE.name()).getValue();
             Integer faceVerifyEndMinute = Integer.valueOf(faceVerifyEndMinuteStr);
             //	case1.如果考生已使用的考试时间(即心跳时间)还未达到系统设置的活体检测开始时间,
-            //	则实际活体检测时间=random(配置结束时间-配置开始时间)-考试已用时间
+            //	则实际活体检测时间=random(配置结束时间,配置开始时间)-考试已用时间
             if (heartbeat < faceVerifyStartMinute) {
                 return CommonUtil.calculationRandomNumber(faceVerifyStartMinute, faceVerifyEndMinute) - heartbeat;
             }
             //	case2如果配置开始时间<考生已使用的考试时间<配置结束时间,
-            //	则实际活体检测时间=random(配置结束时间-考试已用时间)-考试已用时间,如果结果小于1分钟则默认1分钟
+            //	则实际活体检测时间=random(配置结束时间,考试已用时间)-考试已用时间,如果结果小于1分钟则默认1分钟
             else if (heartbeat >= faceVerifyStartMinute && heartbeat < faceVerifyEndMinute) {
                 int verifyTime = CommonUtil.calculationRandomNumber(heartbeat, faceVerifyEndMinute) - heartbeat;
                 return verifyTime < 1 ? 1 : verifyTime;

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

@@ -3,7 +3,7 @@ package cn.com.qmth.examcloud.core.oe.student.service.impl;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.commons.util.HttpClientUtil;
 import cn.com.qmth.examcloud.core.basic.api.bean.CourseBean;
-import cn.com.qmth.examcloud.core.oe.common.base.helper.ExamCacheTransferHelper;
+import cn.com.qmth.examcloud.core.oe.common.helper.ExamCacheTransferHelper;
 import cn.com.qmth.examcloud.core.oe.common.entity.ExamRecordDataEntity;
 import cn.com.qmth.examcloud.core.oe.common.entity.ExamRecordForMarkingEntity;
 import cn.com.qmth.examcloud.core.oe.common.entity.ExamStudentEntity;

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

@@ -1,7 +1,7 @@
 package cn.com.qmth.examcloud.core.oe.student.service.impl;
 
 import cn.com.qmth.examcloud.core.basic.api.bean.CourseBean;
-import cn.com.qmth.examcloud.core.oe.common.base.helper.ExamCacheTransferHelper;
+import cn.com.qmth.examcloud.core.oe.common.helper.ExamCacheTransferHelper;
 import cn.com.qmth.examcloud.core.oe.common.base.utils.QuestionTypeUtil;
 import cn.com.qmth.examcloud.core.oe.common.entity.*;
 import cn.com.qmth.examcloud.core.oe.common.enums.ExamRecordStatus;