Explorar o código

新活检bug fix

lideyin %!s(int64=5) %!d(string=hai) anos
pai
achega
b65663c969

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

@@ -40,6 +40,15 @@ public class FaceBiopsyStepInfo implements JsonSerializable {
 	@ApiModelProperty(value = "指令是否超时")
 	private Boolean timeout;
 
+	@ApiModelProperty(value = "是否有陌生人脸即多张人脸")
+	private Boolean stranger;
+
+	@ApiModelProperty(value = "是否晃出摄像头")
+	private Boolean waggleOutCamera;
+
+	@ApiModelProperty(value = "是否检测到人脸")
+	private Boolean hasFace;
+
 	@ApiModelProperty(value = "指令执行结果json串")
 	private String resultJson;
 
@@ -117,4 +126,28 @@ public class FaceBiopsyStepInfo implements JsonSerializable {
 	public void setTimeout(Boolean timeout) {
 		this.timeout = timeout;
 	}
+
+	public Boolean getStranger() {
+		return stranger;
+	}
+
+	public void setStranger(Boolean stranger) {
+		this.stranger = stranger;
+	}
+
+	public Boolean getWaggleOutCamera() {
+		return waggleOutCamera;
+	}
+
+	public void setWaggleOutCamera(Boolean waggleOutCamera) {
+		this.waggleOutCamera = waggleOutCamera;
+	}
+
+	public Boolean getHasFace() {
+		return hasFace;
+	}
+
+	public void setHasFace(Boolean hasFace) {
+		this.hasFace = hasFace;
+	}
 }

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

@@ -88,6 +88,7 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
         //不存在未完成的活检的校验逻辑
         // 已活检次数
         int verifiedTimes = faceBiopsyEntity.getVerifiedTimes();
+
         if (verifiedTimes == 1) {
             FaceBiopsyItemEntity firstFaceBiopsyItem =
                     faceBiopsyItemRepo.findFirstByFaceBiopsyIdOrderByIdAsc(faceBiopsyEntity.getId());
@@ -103,6 +104,7 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
             //如果第一次活检失败,再次调用,按冻结时间内生成新的活检步骤
             return appendFaceBiopsy(faceBiopsyEntity.getId(), verifiedTimes, examRecordDataId, faceBiopsyType, true);
         }
+
         if (verifiedTimes == 2) {
             FaceBiopsyItemEntity secondFaceBiopsyItem =
                     faceBiopsyItemRepo.findFirstByFaceBiopsyIdOrderByIdDesc(faceBiopsyEntity.getId());
@@ -221,48 +223,123 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
      * @return
      */
     private SaveFaceBiopsyResultResp buildSaveFaceBiopsyResultResp(SaveFaceBiopsyResultReq req) {
-        Long examRecordDataId = req.getExamRecordDataId();
         List<FaceBiopsyStepInfo> verifySteps = req.getVerifySteps();
-        //本次检测的最终结果是否成功(检测步骤中只要有一项检测失败,则认为检测失败)
-        boolean finalIsSuccess = true;
-        String errorMsg = null;
-        /**
-         * 是否结束考试
-         * case1:人脸比对失败(即活检第1步,action==FACE_COMPARE,照片非本人或检测中多人脸)时,结束考试
-         * case2:冻结时间内,第2次人脸活检整体失败,结束考试
-         * case3:冻结时间外,人脸活检失败,结束考试
-         */
-        boolean isEndExam = false;
-        //检测次数
-        int verifyTimes = getVerifyTimes(examRecordDataId);
-
         // 检测结果至少有一条检测结果不允许为空
         if (!verifySteps.stream().anyMatch(p -> null != p.getResult())) {
             throw new StatusException("201005", "检测结果不允许为空");
         }
 
+        boolean finalIsSuccess = calculateIsSuccess(req.getVerifySteps());
+        Boolean isEndExam = calculateIsEndExam(verifySteps, req.getExamRecordDataId(), finalIsSuccess);
+
+        //构建业务实体
+        SaveFaceBiopsyResultResp resp = new SaveFaceBiopsyResultResp();
+        resp.setEndExam(isEndExam);
+        resp.setVerifyResult(finalIsSuccess);
+        resp.setNeedNextVerify(calculateNeedNextVerify(isEndExam, finalIsSuccess, req.getExamRecordDataId()));
+        resp.setErrorMessage(getErrorMsg(req.getVerifySteps()));
+        return resp;
+    }
+
+    /**
+     * 更新人脸活体检测结果至数据库
+     *
+     * @param examRecordDataId
+     * @param faceBiopsyItemId
+     * @param verifySteps
+     * @param finalIsSuccess
+     * @param errorMsg
+     */
+    public void updateFaceBiopsyResult(Long examRecordDataId, Long
+            faceBiopsyItemId, List<FaceBiopsyStepInfo> verifySteps,
+                                       boolean finalIsSuccess, String errorMsg) {
+        List<FaceBiopsyItemStepEntity> faceBiopsyItemStepEntityList =
+                faceBiopsyItemStepRepo.findByFaceBiopsyItemId(faceBiopsyItemId);
         for (FaceBiopsyStepInfo stepInfo : verifySteps) {
-            //如果检测结果为空,则直接跳过
-            if (stepInfo.getResult() == null) {
-                continue;
+            //循环更新新活体检测每步的执行结果
+            FaceBiopsyItemStepEntity faceBiopsyItemStepEntity = faceBiopsyItemStepEntityList.stream().
+                    filter(p -> p.getId().equals(stepInfo.getStepId())).findFirst().get();
+            faceBiopsyItemStepEntity.setErrorMsg(stepInfo.getErrorMsg());
+            faceBiopsyItemStepEntity.setResourceType(stepInfo.getResourceType());
+            faceBiopsyItemStepEntity.setResourceRelativePath(getRelativePath(stepInfo.getResourceUrl()));
+            faceBiopsyItemStepEntity.setExt1(stepInfo.getResultJson());//存储动作执行结果
+            faceBiopsyItemStepEntity.setResult(stepInfo.getResult());
+
+            if (null != stepInfo.getTimeout()) {
+                faceBiopsyItemStepEntity.setExt2(stepInfo.getTimeout().toString());//指令是否超时
             }
 
-            if (!stepInfo.getResult()) {
-                errorMsg = stepInfo.getErrorMsg();
+            if (null != stepInfo.getStranger()) {
+                faceBiopsyItemStepEntity.setExt3(stepInfo.getTimeout().toString());//是否有陌生人脸
+            }
+
+            if (null != stepInfo.getWaggleOutCamera()) {
+                faceBiopsyItemStepEntity.setExt3(stepInfo.getWaggleOutCamera().toString());//是否晃同摄像头
+            }
+
+            if (null != stepInfo.getHasFace()) {
+                faceBiopsyItemStepEntity.setExt4(stepInfo.getHasFace().toString());//是否有人脸
             }
 
+        }
+        //批量更新活检步骤执行结果
+        faceBiopsyItemStepRepo.saveAll(faceBiopsyItemStepEntityList);
+        //更新人脸活体检测最终结果
+        faceBiopsyItemRepo.updateFaceBiopsyItemResult(faceBiopsyItemId, finalIsSuccess, errorMsg, true);
+        faceBiopsyRepo.updateFaceBiopsyResult(examRecordDataId, finalIsSuccess, errorMsg);
+    }
+
+
+    /**
+     * 计算活检是否成功
+     *
+     * @param verifySteps
+     * @return
+     */
+    private boolean calculateIsSuccess(List<FaceBiopsyStepInfo> verifySteps) {
+        for (FaceBiopsyStepInfo stepInfo : verifySteps) {
+            //如果当前步骤为超时,则直接返回失败或者整个检测步骤中只要有一次失败,则认为整个活检失败
+            if ((null != stepInfo.getTimeout() && stepInfo.getTimeout()) ||
+                    (null != stepInfo.getResult() && !stepInfo.getResult())) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 获取错误信息
+     *
+     * @param verifySteps
+     * @return
+     */
+    private String getErrorMsg(List<FaceBiopsyStepInfo> verifySteps) {
+        for (FaceBiopsyStepInfo stepInfo : verifySteps) {
             //如果当前步骤为超时,则直接跳出循环
             if ((stepInfo.getTimeout() != null && stepInfo.getTimeout())) {
-                errorMsg = "超时未完成";
-                finalIsSuccess = false;
-                break;
+                return "超时未完成";
             }
 
-            //整个检测步骤中只要有一次失败或超时,则认为整个活检失败
+            //整个检测步骤中只要有一次失败,则认为整个活检失败
             if (!stepInfo.getResult()) {
-                finalIsSuccess = false;
+                return stepInfo.getErrorMsg();
             }
+        }
+        return null;
+    }
 
+    /**
+     * 计算是否结束考试
+     * @param verifySteps
+     * @param examRecordDataId
+     * @param finalIsSuccess
+     * @return
+     */
+    private boolean calculateIsEndExam(List<FaceBiopsyStepInfo> verifySteps, Long examRecordDataId, Boolean finalIsSuccess) {
+        /**
+         * 指定指令失败,(多人脸,人脸晃出摄像头,无人脸)直接结束考试
+         */
+        for (FaceBiopsyStepInfo stepInfo : verifySteps) {
             switch (stepInfo.getAction()) {
                 case FACE_COMPARE:
                     //如果第一步检测部分失败(照片非本人或检测中多人脸),需要结束考试
@@ -278,129 +355,78 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
                     Boolean existsSystemError = Boolean.valueOf(faceCompareResult.get("existsSystemError").toString());
                     //case1.1.有陌生人(即多人脸),不管是否比对成功,直接结束考试
                     if (isStranger) {
-                        isEndExam = true;
+                        return true;
                     }
-                    //case1.2.无陌生人且检测失败且不是系统错误(即照片非本人),也直接结束考试
+                    //case1.2.无陌生人且检测失败且不是系统错误(即照片非本人或无人脸),也直接结束考试
                     else {
                         if (!isPass && !existsSystemError) {
-                            isEndExam = true;
+                            return true;
                         }
                     }
                     break;
                 case HAPPY:
                 case SERIOUS:
                     //如果此前步骤已判断为需要结束考试则不作任何处理
-                    if (!isEndExam) {
-                        //本次检测步骤是否在冻结时间内生成
-                        FaceBiopsyItemEntity faceBiopsyItem = GlobalHelper.getEntity(faceBiopsyItemRepo,
-                                req.getFaceBiopsyItemId(), FaceBiopsyItemEntity.class);
-                        Boolean isCurStepInFreezeTime = faceBiopsyItem.getInFreezeTime();
-
-                        //如果本次活检步骤是在冻结时间内生成,则按冻结时间内的逻辑来处理
-                        if (null != isCurStepInFreezeTime && isCurStepInFreezeTime) {
-                            //如果冻结时间内第2次检测失败,则需要结束考试
-                            if (verifyTimes > 1 && !stepInfo.getResult()) {
-                                isEndExam = true;
-                            }
-                        } else {
-                            //冻结时间外检测失败,直接结束考试
-                            if (!stepInfo.getResult()) {
-                                isEndExam = true;
-                            }
-                        }
+                    //如果有陌生人脸或晃出摄像头或无人脸,直接结束考试
+                    if ((null != stepInfo.getStranger() && stepInfo.getStranger()) ||
+                            (null != stepInfo.getWaggleOutCamera() && stepInfo.getWaggleOutCamera()) ||
+                            (null != stepInfo.getHasFace() && !stepInfo.getHasFace())) {
+                        return true;
                     }
                     break;
             }
         }
 
-        //如果当前为第二次活检,且第一次活检已经失败,本次活检也失败,则直接结束考试
-        if (verifyTimes == 2) {
-            FaceBiopsyItemEntity firstFaceBiopsyItem =
-                    faceBiopsyItemRepo.findFirstByExamRecordDataIdOrderByIdAsc(req.getExamRecordDataId());
-            if (!firstFaceBiopsyItem.getResult() && !finalIsSuccess) {
-                isEndExam = true;
-            }
+        /**
+         * 根据活检情况结束考试
+         * 当前为第二次活检,且失败,且第一次活检也失败,则直接结束考试
+         * 当前为第二次活检,且失败,且第一次活检成功,则直接结束考试
+         * 当前为第三次活检,且失败,且第一次活检失败,第二次活检成功,则直接结束考试
+         */
+        //如果是第二次活检,且失败,则结束考试(无论第一次是否成功)
+        int verifyTimes = getVerifyTimes(examRecordDataId);
+        if (verifyTimes == 2 && !finalIsSuccess) {
+            return true;
         }
 
-        //构建业务实体
-        SaveFaceBiopsyResultResp resp = new SaveFaceBiopsyResultResp();
-        resp.setEndExam(isEndExam);
-        resp.setNeedNextVerify(calculateNeedNextVerify(
-                isEndExam, calculateIsInFreezeTime(examRecordDataId), finalIsSuccess, verifyTimes, examRecordDataId));
-        resp.setVerifyResult(finalIsSuccess);
-        resp.setErrorMessage(errorMsg);
-        return resp;
-    }
-
-    /**
-     * 更新人脸活体检测结果至数据库
-     *
-     * @param examRecordDataId
-     * @param faceBiopsyItemId
-     * @param verifySteps
-     * @param finalIsSuccess
-     * @param errorMsg
-     */
-    public void updateFaceBiopsyResult(Long examRecordDataId, Long faceBiopsyItemId, List<FaceBiopsyStepInfo> verifySteps,
-                                       boolean finalIsSuccess, String errorMsg) {
-        List<FaceBiopsyItemStepEntity> faceBiopsyItemStepEntityList =
-                faceBiopsyItemStepRepo.findByFaceBiopsyItemId(faceBiopsyItemId);
-        for (FaceBiopsyStepInfo stepInfo : verifySteps) {
-            //循环更新新活体检测每步的执行结果
-            FaceBiopsyItemStepEntity faceBiopsyItemStepEntity = faceBiopsyItemStepEntityList.stream().
-                    filter(p -> p.getId().equals(stepInfo.getStepId())).findFirst().get();
-            faceBiopsyItemStepEntity.setErrorMsg(stepInfo.getErrorMsg());
-            faceBiopsyItemStepEntity.setResourceType(stepInfo.getResourceType());
-            faceBiopsyItemStepEntity.setResourceRelativePath(getRelativePath(stepInfo.getResourceUrl()));
-            faceBiopsyItemStepEntity.setExt1(stepInfo.getResultJson());//存储动作执行结果
-            faceBiopsyItemStepEntity.setResult(stepInfo.getResult());
+        if (verifyTimes == 3 && !finalIsSuccess) {
+            return true;
         }
-        //批量更新活检步骤执行结果
-        faceBiopsyItemStepRepo.saveAll(faceBiopsyItemStepEntityList);
-        //更新人脸活体检测最终结果
-        faceBiopsyItemRepo.updateFaceBiopsyItemResult(faceBiopsyItemId, finalIsSuccess, errorMsg, true);
-        faceBiopsyRepo.updateFaceBiopsyResult(examRecordDataId, finalIsSuccess, errorMsg);
+
+        //其它情况不结束考试
+        return false;
     }
 
     /**
      * 计算是否需要下次活检
      *
      * @param isEndExam
-     * @param isInFreezeTime
      * @param finalIsSuccess
-     * @param verifyTimes
      * @return
      */
-    private boolean calculateNeedNextVerify(boolean isEndExam, boolean isInFreezeTime, boolean finalIsSuccess,
-                                            int verifyTimes, Long examRecordDataId) {
+    private boolean calculateNeedNextVerify(boolean isEndExam, boolean finalIsSuccess, Long examRecordDataId) {
         //考试已结束,不需要继续下次活检
         if (isEndExam) {
             return false;
         }
 
-        //如果考试未结束的情况
-        if (isInFreezeTime) {
-            if (verifyTimes == 1) {
-                //冻结时间内第一次活检失败,则需要下次活检
-                if (!finalIsSuccess) {
-                    return true;
-                }
-            } else {
-                //冻结时间内非第一次活检失败,则不需要下次活检
-                if (!finalIsSuccess) {
-                    return false;
-                }
-            }
+        int verifyTimes = getVerifyTimes(examRecordDataId);
+        //如果是第一次活检,且成功,且开启追加活检,则允许继续活检
+        if (verifyTimes == 1 && finalIsSuccess && isAddFaceVerifyOutFreezeTime(examRecordDataId)) {
+            return true;
+        }
 
-            //冻结时间内第一次或第二次活检成功,且开启冻结时间外增加一次活检,则需要下次活检,否则不需要
-            ExamRecordDataEntity examRecordData = GlobalHelper.getEntity(examRecordDataRepo, examRecordDataId,
-                    ExamRecordDataEntity.class);
-            return isAddFaceVerifyOutFreezeTime(examRecordData.getExamId(),
-                    examRecordData.getOrgId(), examRecordData.getStudentId());
-        } else {
-            //冻结时间外,无论活检成功或失败,均不可进行下次活检
-            return false;
+        //如果是第二次活检,且成功,且第一次活检失败,且开启追加活检,则允许继续活检
+        if (verifyTimes == 2 && finalIsSuccess) {
+            FaceBiopsyItemEntity firstFaceBiopsyItem =
+                    faceBiopsyItemRepo.findFirstByExamRecordDataIdOrderByIdAsc(examRecordDataId);
+            if (!firstFaceBiopsyItem.getResult() && isAddFaceVerifyOutFreezeTime(examRecordDataId)) {
+                return true;
+            }
         }
+
+        //其它情况均不允许继续活检
+        return false;
     }
 
     /**
@@ -498,7 +524,8 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
         return faceBiopsyInfo;
     }
 
-    private List<FaceBiopsyStepInfo> copyFaceBiopsyStepDomainListFrom(List<FaceBiopsyItemStepEntity> faceBiopsyItemStepEntityList) {
+    private List<FaceBiopsyStepInfo> copyFaceBiopsyStepDomainListFrom
+            (List<FaceBiopsyItemStepEntity> faceBiopsyItemStepEntityList) {
         List<FaceBiopsyStepInfo> resultList = new ArrayList<>();
         for (FaceBiopsyItemStepEntity entity : faceBiopsyItemStepEntityList) {
             FaceBiopsyStepInfo domain = new FaceBiopsyStepInfo();