Эх сурвалжийг харах

需求调整,新活检二次大重构。

lideyin 5 жил өмнө
parent
commit
5e0e5488e1

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

@@ -154,7 +154,7 @@ public class ExamControlController extends ControllerSupport {
     }
 
     /**
-     * 交卷后续处理
+     * 交卷后续处理,此处仅用于测试,无调用者
      */
     @ApiOperation(value = "交卷后续处理")
     @GetMapping("/processAfterEndExam")

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

@@ -91,15 +91,12 @@ public class FaceBiopsyController extends ControllerSupport {
             throw new StatusException("200105", "本场考试未开启人脸活体检测");
         }
 
-        FaceBiopsyBaseInfo faceBiopsyBaseInfo = new FaceBiopsyBaseInfo();
-
         FaceBiopsyScheme faceBiopsyScheme = FaceBiopsyHelper.getFaceBiopsyScheme(user.getRootOrgId());
-        faceBiopsyBaseInfo.setIdentificationOfLivingBodyScheme(faceBiopsyScheme.getCode());
 
         Integer faceVerifyMinute = null;
         // 如果是新活体检测方案,则使用新的计算方案计算活检开始时间
         if (faceBiopsyScheme == FaceBiopsyScheme.NEW) {
-            faceVerifyMinute = faceBiopsyService.getFaceBiopsyStartMinute(examRecordDataId);
+            faceVerifyMinute = faceBiopsyService.calculateFaceBiopsyStartMinute(examRecordDataId);
         }
         // 非新活检,默认使用旧的活检计算方式
         else {
@@ -107,6 +104,8 @@ public class FaceBiopsyController extends ControllerSupport {
                     orgId, examId, studentId, examRecordData.getId(), examSessionInfo.getHeartbeat());
         }
 
+        FaceBiopsyBaseInfo faceBiopsyBaseInfo = new FaceBiopsyBaseInfo();
+        faceBiopsyBaseInfo.setIdentificationOfLivingBodyScheme(faceBiopsyScheme.getCode());
         faceBiopsyBaseInfo.setFaceVerifyMinute(faceVerifyMinute);
         return faceBiopsyBaseInfo;
     }

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

@@ -12,7 +12,6 @@ public interface ExamSessionInfoService {
 
     /**
      * 保存
-     * @param key
      * @param examSessionInfo
      * @param timeout   秒
      */
@@ -20,14 +19,14 @@ public interface ExamSessionInfoService {
 
     /**
      * 获取
-     * @param key
+     * @param studentId
      * @return
      */
     public ExamSessionInfo getExamSessionInfo(Long studentId);
 
     /**
      * 删除
-     * @param key
+     * @param studentId
      */
     public void deleteExamSessionInfo(Long studentId);
 }

+ 10 - 0
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/ExamStudentFinalScoreService.java

@@ -0,0 +1,10 @@
+package cn.com.qmth.examcloud.core.oe.student.service;
+/**
+ * @Description 考生最终成绩接口
+ * @Author lideyin
+ * @Date 2019/11/7 18:19
+ * @Version 1.0
+ */
+public interface ExamStudentFinalScoreService {
+    void calculateFinalScore(Long examStudentId);
+}

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

@@ -35,5 +35,5 @@ public interface FaceBiopsyService {
      * @param examRecordDataId 考试记录id
      * @return Integer
      */
-    Integer getFaceBiopsyStartMinute(Long examRecordDataId);
+    Integer calculateFaceBiopsyStartMinute(Long examRecordDataId);
 }

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

@@ -832,20 +832,26 @@ public class ExamControlServiceImpl implements ExamControlService {
         // 保存阅卷相关数据
         examRecordForMarkingService.saveExamRecordForMarking(examRecordData, examScore.getObjectiveScore());
 
-        // 更新考试记录相关数据
+        // 更新考试记录相关数据,
+        // 手工交卷,更新考试状态
         if (handInExamType == HandInExamType.MANUAL) {
             examRecordData.setExamRecordStatus(ExamRecordStatus.EXAM_END);
-            // 产品确认,自动服务清理时,不再更新考试结束时间,以交卷时的时间为准。
+            // 产品确认,自动服务清理时,不再更新考试结束时间,以交卷时的时间为准。
             // examRecordData.setEndTime(new Date());
-        } else if (handInExamType == HandInExamType.AUTO) {
+        }
+        //自动交卷,更新考试状态和清理时间
+        else if (handInExamType == HandInExamType.AUTO) {
             examRecordData.setExamRecordStatus(ExamRecordStatus.EXAM_OVERDUE);
             examRecordData.setCleanTime(new Date());
         } else {
             throw new StatusException("201101", "暂不支持的交卷类型");
         }
+
         examRecordDataRepo.save(examRecordData);
+
         // 保存考试分数数据到推分队列
         examScorePushQueueService.saveScoreDataInfoToQueue(examRecordData, examScore.getId());
+
         // 保存考试分数数据到分数获取队列
         examScoreObtainQueueService.saveExamScoreObtainQueue(examRecordData);
 
@@ -940,7 +946,7 @@ public class ExamControlServiceImpl implements ExamControlService {
 
             // 如果是新活体检测方案,则使用新的计算方案计算活检开始时间
             if (faceBiopsyScheme == FaceBiopsyScheme.NEW) {
-                faceVerifyMinute = faceBiopsyService.getFaceBiopsyStartMinute(examingRecord.getExamRecordDataId());
+                faceVerifyMinute = faceBiopsyService.calculateFaceBiopsyStartMinute(examingRecord.getExamRecordDataId());
             }
             // 非新活检,默认使用旧的活检计算方式
             else {

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

@@ -304,7 +304,7 @@ public class ExamFaceLivenessVerifyServiceImpl implements ExamFaceLivenessVerify
                     int verifyTime = CommonUtil.calculationRandomNumber(heartbeat, faceVerifyEndMinute) - heartbeat;
                     return verifyTime < 1 ? 1 : verifyTime;
                 }
-                //case3如果考试已用时间>配置结束时间,则默认1分钟后开始人脸检测
+                //case3如果考试已用时间>配置结束时间,则默认random(1,4)分钟后开始人脸检测
                 else if (heartbeat >= faceVerifyEndMinute) {
                     return CommonUtil.calculationRandomNumber(1, secondFaceCheckMinute);
                 }

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

@@ -61,48 +61,12 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
     @Override
     @Transactional
     public FaceBiopsyInfo getFaceBiopsyInfo(Long rootOrgId, Long examRecordDataId, FaceBiopsyType faceBiopsyType) {
-        boolean isInFreezeTime = calculateIsInFreezeTime(examRecordDataId);
-        /**
-         * case1.冻结时间外的校验逻辑
-         * case1.1.未开启冻结时间外添加人脸活体检测的配置,则抛出异常
-         * case1.2.冻结时间外已完成过1次人脸活体检测,再次调用则抛出异常
-         * case1.3.冻结时间内已经存在2次失败的人脸活体检测记录,冻结时间外,再次调用抛出异常
-         */
-        if (!isInFreezeTime) {
-            //case1.1.未开启冻结时间外添加人脸活体检测的配置,则抛出异常
-            if (!isAddFaceVerifyOutFreezeTime(examRecordDataId)) {
-                throw new StatusException("201004", "非冻结时间内不允许人脸活体检测");
-            }
-        }
-
         //如果是第一次进行人脸活体检测,则初始化相关信息保存并返回
         FaceBiopsyEntity faceBiopsyEntity = faceBiopsyRepo.findByExamRecordDataId(examRecordDataId);
         if (faceBiopsyEntity == null) {
             return addFirstFaceBiopsy(rootOrgId, examRecordDataId, faceBiopsyType);
         }
 
-        //case1.2.冻结时间外已完成过1次人脸活体检测,再次调用则抛出异常
-        if (!isInFreezeTime) {
-            List<FaceBiopsyItemEntity> outFreezeTimeCompletedList =
-                    faceBiopsyItemRepo.findByExamRecordDataIdAndCompletedAndInFreezeTime(examRecordDataId,
-                            true, false);
-            if (outFreezeTimeCompletedList != null && outFreezeTimeCompletedList.size() > 0) {
-                throw new StatusException("201005", "冻结时间外不允许进行多次人脸活体检测");
-            }
-
-            //case1.3.冻结时间内已经存在2次失败的人脸活体检测记录,冻结时间外,再次调用抛出异常
-            if (faceBiopsyEntity.getVerifiedTimes() == 2) {
-                List<FaceBiopsyItemEntity> faceBiopsyItemList = faceBiopsyItemRepo.findByFaceBiopsyId(faceBiopsyEntity.getId());
-                FaceBiopsyItemEntity faceBiopsyItem1 = faceBiopsyItemList.get(0);
-                FaceBiopsyItemEntity faceBiopsyItem2 = faceBiopsyItemList.get(1);
-                if (faceBiopsyItem1.getCompleted() && faceBiopsyItem1.getResult() == false &&
-                        faceBiopsyItem2.getCompleted() && faceBiopsyItem2.getResult() == false) {
-                    throw new StatusException("201006", "非法调用,活体检测已结束");
-                }
-            }
-        }
-
-
         //如果不是第一次人脸活体检测,判断是否有未检测完的记录,
         FaceBiopsyInfo result = new FaceBiopsyInfo();
         // 未完成的活体检测列表
@@ -113,7 +77,7 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
         if (unCompletedFaceBiopsyItemList != null && !unCompletedFaceBiopsyItemList.isEmpty()) {
             FaceBiopsyItemEntity faceBiopsyItemEntity = unCompletedFaceBiopsyItemList.get(0);
             result.setFaceBiopsyItemId(faceBiopsyItemEntity.getId());
-            result.setFaceVerifyMinute(getFaceBiopsyStartMinute(examRecordDataId));
+            result.setFaceVerifyMinute(calculateFaceBiopsyStartMinute(examRecordDataId));
 
             List<FaceBiopsyItemStepEntity> faceBiopsyItemStepEntityList =
                     faceBiopsyItemStepRepo.findByFaceBiopsyItemId(faceBiopsyItemEntity.getId());
@@ -123,28 +87,39 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
 
         //已活检次数
         int verifiedTimes = faceBiopsyEntity.getVerifiedTimes();
-        /**
-         * case2.冻结时间内的校验逻辑
-         * case2.1.第一次校验成功,第二次调用则抛出异常(即只有第一次失败才能再调第二次)
-         * case1.2.冻结时间内活检次数不得超过2次(<=2)
-         */
-        if (isInFreezeTime) {
-            if (verifiedTimes == 1) {
-                List<FaceBiopsyItemEntity> faceBiopsyItemList = faceBiopsyItemRepo.findByFaceBiopsyId(faceBiopsyEntity.getId());
-                FaceBiopsyItemEntity faceBiopsyItemEntity = faceBiopsyItemList.get(0);
-                //case2.1.第一次校验成功,第二次调用则抛出异常(即只有第一次失败才能再调第二次)
-                if (faceBiopsyItemEntity.getInFreezeTime() && null != faceBiopsyItemEntity.getResult()
-                        && faceBiopsyItemEntity.getResult()) {
-                    throw new StatusException("201006", "非法请求,冻结时间内无需多次活体检测");
+        if (verifiedTimes == 1) {
+            FaceBiopsyItemEntity firstFaceBiopsyItem =
+                    faceBiopsyItemRepo.findFirstByFaceBiopsyIdOrderByIdAsc(faceBiopsyEntity.getId());
+            if (firstFaceBiopsyItem.getInFreezeTime() && null != firstFaceBiopsyItem.getResult()
+                    && firstFaceBiopsyItem.getResult()) {
+                //第一次活检成功,且未开启追加新活检,再次调用,则抛出异常
+                if (!isAddFaceVerifyOutFreezeTime(examRecordDataId)) {
+                    throw new StatusException("201006", "非法请求,无活体检测机会");
                 }
-            } else {
-                throw new StatusException("201006", "非法请求,冻结时间内最多只能两次活检");
+                //第一次活检成功,且开启追加新活检,再次调用,生成新的活检步骤
+                return appendFaceBiopsy(faceBiopsyEntity.getId(), verifiedTimes, examRecordDataId, faceBiopsyType, true);
             }
         }
+        if (verifiedTimes == 2) {
+            FaceBiopsyItemEntity secondFaceBiopsyItem =
+                    faceBiopsyItemRepo.findFirstByFaceBiopsyIdOrderByIdDesc(faceBiopsyEntity.getId());
 
-        //没有超过,则追加活检次数
-        verifiedTimes++;
-        return appendFaceBiopsy(faceBiopsyEntity.getId(), verifiedTimes, examRecordDataId, faceBiopsyType);
+            //如果是第二次活检为冻结时间外的活检记录,再次调用,则直接抛出异常
+            if (!secondFaceBiopsyItem.getInFreezeTime()) {
+                throw new StatusException("201007", "非法请求,无活体检测机会");
+            }
+
+            //如果第二次活检也失败,再次调用,则抛出异常
+            if (!secondFaceBiopsyItem.getResult()){
+                throw new StatusException("201008", "非法请求,无活体检测机会");
+            }
+
+            //否则追加冻结时间外的活检
+            return appendFaceBiopsy(faceBiopsyEntity.getId(), verifiedTimes, examRecordDataId, faceBiopsyType, false);
+        }
+
+        //三交活检已完成,则抛出异常
+        throw new StatusException("201009", "非法请求,无活体检测机会");
     }
 
     @Override
@@ -165,97 +140,75 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
     }
 
     /**
-     * 获取人脸活体检测开始分钟数
+     * 计算人脸活体检测开始分钟数
      *
      * @param examRecordDataId 考试记录id
      * @return Integer
      */
     @Override
-    public Integer getFaceBiopsyStartMinute(Long examRecordDataId) {
-        //case1.1.第一次调用,返回冻结时间内或冻结时间外下次活检时间
-        FaceBiopsyEntity faceBiopsyEntity = faceBiopsyRepo.findByExamRecordDataId(examRecordDataId);
-        //如果是一次活检都没有做过,则认为是第一次
-        if (faceBiopsyEntity == null) {
-            return calculateFaceBiopsyStartMinute(examRecordDataId);
+    public Integer calculateFaceBiopsyStartMinute(Long examRecordDataId) {
+        //如果未开启人脸活体检测,则返回null
+        if (!getIsFaceVerify(examRecordDataId)) {
+            return null;
         }
 
-        boolean isInFreezeTime = calculateIsInFreezeTime(examRecordDataId);
         /**
-         * case1.冻结时间内的逻辑
-         * case1.1.第一次调用,返回冻结时间内下次活检时间
-         * case1.2.第二次调用,
-         * case1.2.1.如果第一次活检失败,
-         * case1.2.1.1.如果第二次活检未完成,重新计算下次活检时间
-         * case1.2.1.2.如果第二次活检失败,返回null
-         * case1.2.1.3.如果第二次活检成功,返回冻结时间外活检开始的时间
-         * case1.2.2.如果第一次活检成功,
-         * case1.2.2.1.但未开启冻结时间外追加人脸活检的配置,返回null
-         * case1.2.2.2.且开启了冻结时间外追加人脸活检的配置,返回冻结时间外活检开始的时间
-         *
+         * case0.首次调用或超过3次调用的特殊处理
+         * case0.1.第一次调用,无冻结时间内还是冻结时间外,均按照冻结时间内的算法计算下次活检时间(相当于补偿措施)
+         * case0.2.超过3次调用,
+         * case0.2.1.如果第三次活检未完成,再次调用,则按活检外计算方式,返回下次活检时间
+         * case0.2.2.如果第三次活检已完成,则直接返回null
          */
-        if (isInFreezeTime) {
-            if (faceBiopsyEntity.getVerifiedTimes() <= 2) {
-                List<FaceBiopsyItemEntity> faceBiopsyItemList = faceBiopsyItemRepo.findByFaceBiopsyId(faceBiopsyEntity.getId());
-                FaceBiopsyItemEntity faceBiopsyItemEntity = faceBiopsyItemList.get(0);
-                //第一次活体检测成功,第二次调用时
-                if (faceBiopsyItemEntity.getInFreezeTime() && faceBiopsyItemEntity.getCompleted()
-                        && faceBiopsyItemEntity.getResult()) {
-                    //如果未开启冻结时间外人脸活体检测,则直接返回null
-                    if (!isAddFaceVerifyOutFreezeTime(examRecordDataId)) {
-                        return null;
-                    }
-
-                    //如果开启冻结时间外人脸活体检测,则直接返回冻结时间外的活检开始时间
-                    return calculateFaceBiopsyStartMinute(examRecordDataId, true,
-                            FreezeTimeBorder.OUT);
-                }
+        FaceBiopsyEntity faceBiopsy = faceBiopsyRepo.findByExamRecordDataId(examRecordDataId);
+        if (faceBiopsy == null) {
+            return generateInFreezeTimeFaceBiopsyStartMinute(examRecordDataId);
+        }
 
-                //如果进行了两次活检
-                if (faceBiopsyEntity.getVerifiedTimes() == 2) {
-                    faceBiopsyItemEntity = faceBiopsyItemList.get(1);
-                    //如果进行了两次活检,且第二次活检失败,冻结时间内再次调用,返回null
-                    if (faceBiopsyItemEntity.getInFreezeTime() && faceBiopsyItemEntity.getCompleted()
-                            && faceBiopsyItemEntity.getResult() == false) {
-                        return null;
-                    }
+        //超过三次的特殊处理
+        if (faceBiopsy.getVerifiedTimes() >= 3) {
+            FaceBiopsyItemEntity lastFaceBiopsyItem =
+                    faceBiopsyItemRepo.findFirstByFaceBiopsyIdOrderByIdDesc(faceBiopsy.getId());
 
-                    //如果进行了两次活检,且第二次活检成功,冻结时间内再次调用,返回冻结时间外的值
-                    if (faceBiopsyItemEntity.getInFreezeTime() && faceBiopsyItemEntity.getCompleted()
-                            && faceBiopsyItemEntity.getResult()) {
-                        return calculateFaceBiopsyStartMinute(examRecordDataId, true,
-                                FreezeTimeBorder.OUT);
-                    }
-                }
+            //如果第三次活检已完成,则直接返回null
+            if (lastFaceBiopsyItem.getCompleted()) {
+                return null;
             }
+
+            //如果第三次活检未完成,再次调用,则按活检外计算方式,返回下次活检时间
+            return generateOutFreezeTimeFaceBiopsyStartMinute(examRecordDataId);
         }
 
-        /**
-         * case2.冻结时间外的校验逻辑,
-         * case2.1.冻结时间外已完成过1次人脸活体检测,再次调用则返回null
-         * case2.2.冻结时间内两次活检均失败,冻结时间外再次调用则返回null
-         */
-        if (!isInFreezeTime) {
-            List<FaceBiopsyItemEntity> outFreezeTimeCompletedList =
-                    faceBiopsyItemRepo.findByExamRecordDataIdAndCompletedAndInFreezeTime(examRecordDataId,
-                            true, false);
-            //冻结时间外已完成过1次人脸活体检测,再次调用则返回null
-            if (outFreezeTimeCompletedList != null && outFreezeTimeCompletedList.size() > 0) {
+        //按id升序排列的活检集合
+        List<FaceBiopsyItemEntity> sortedFaceBiopsyItems =
+                faceBiopsyItemRepo.findByFaceBiopsyIdOrderByIdAsc(faceBiopsy.getId());
+
+        //第一次活检明细
+        FaceBiopsyItemEntity firstFaceBiopsyItem = sortedFaceBiopsyItems.get(0);
+
+        //第一次活检未完成,再次调用,继续按冻结时间内方式计算活检开始时间
+        if (!firstFaceBiopsyItem.getCompleted()) {
+            return generateInFreezeTimeFaceBiopsyStartMinute(examRecordDataId);
+        }
+
+        //第一次活体检测完成且成功,再次调用时根据是否开启追加活检判断相关逻辑
+        if (firstFaceBiopsyItem.getResult()) {
+            //如果未开启冻结时间外人脸活体检测,则无需求下次活检,故直接返回null
+            if (!isAddFaceVerifyOutFreezeTime(examRecordDataId)) {
                 return null;
             }
 
-            //冻结时间内两次活检均失败,冻结时间外再次调用则返回null
-            if (faceBiopsyEntity.getVerifiedTimes() == 2) {
-                List<FaceBiopsyItemEntity> faceBiopsyItemList = faceBiopsyItemRepo.findByFaceBiopsyId(faceBiopsyEntity.getId());
-                FaceBiopsyItemEntity faceBiopsyItem1 = faceBiopsyItemList.get(0);
-                FaceBiopsyItemEntity faceBiopsyItem2 = faceBiopsyItemList.get(1);
-                if (faceBiopsyItem1.getCompleted() && faceBiopsyItem1.getResult() == false &&
-                        faceBiopsyItem2.getCompleted() && faceBiopsyItem2.getResult() == false) {
-                    return null;
-                }
-            }
+            //如果开启冻结时间外人脸活体检测,则直接返回冻结时间外的活检开始时间
+            return generateOutFreezeTimeFaceBiopsyStartMinute(examRecordDataId);
         }
 
-        return calculateFaceBiopsyStartMinute(examRecordDataId);
+        //第一次活检完成且失败,那么第二次调用或者第N(N>=2)次调用且第二次活检未完成,采用活检内计算方式
+        if (faceBiopsy.getVerifiedTimes() == 1 ||
+                (faceBiopsy.getVerifiedTimes() == 2 && !sortedFaceBiopsyItems.get(1).getCompleted())) {
+            return generateInFreezeTimeFaceBiopsyStartMinute(examRecordDataId);
+        }
+
+        //其它情况,采用冻结时间外活检计算方式
+        return generateOutFreezeTimeFaceBiopsyStartMinute(examRecordDataId);
     }
 
     /**
@@ -479,7 +432,7 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
     public FaceBiopsyInfo addFirstFaceBiopsy(Long rootOrgId, Long examRecordDataId, FaceBiopsyType faceBiopsyType) {
         //保存人脸活体检测相关信息
         Long faceBiopsyId = addFaceBiopsyEntity(rootOrgId, examRecordDataId);
-        Long faceBiopsyItemId = addFaceBiopsyItemEntity(examRecordDataId, faceBiopsyType, faceBiopsyId);
+        Long faceBiopsyItemId = addFaceBiopsyItemEntity(examRecordDataId, faceBiopsyType, faceBiopsyId, true);
         List<FaceBiopsyItemStepEntity> faceBiopsyItemStepEntityList =
                 addFaceBiopsyItemStepList(examRecordDataId, faceBiopsyItemId);
 
@@ -498,13 +451,14 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
      */
     @Transactional
     public FaceBiopsyInfo appendFaceBiopsy(Long faceBiopsyId, Integer verifiedTimes, Long examRecordDataId,
-                                           FaceBiopsyType faceBiopsyType) {
+                                           FaceBiopsyType faceBiopsyType, boolean isInFreezeTime) {
+        verifiedTimes++;
         //更新人脸活体检测次数
         FaceBiopsyEntity faceBiopsyEntity = GlobalHelper.getEntity(faceBiopsyRepo, faceBiopsyId, FaceBiopsyEntity.class);
         faceBiopsyEntity.setVerifiedTimes(verifiedTimes);
         faceBiopsyRepo.save(faceBiopsyEntity);
         //添加人脸活体检测明细
-        Long faceBiopsyItemId = addFaceBiopsyItemEntity(examRecordDataId, faceBiopsyType, faceBiopsyId);
+        Long faceBiopsyItemId = addFaceBiopsyItemEntity(examRecordDataId, faceBiopsyType, faceBiopsyId, isInFreezeTime);
         //添加人脸活体检测步骤
         List<FaceBiopsyItemStepEntity> faceBiopsyItemStepEntityList =
                 addFaceBiopsyItemStepList(examRecordDataId, faceBiopsyItemId);
@@ -526,7 +480,7 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
         //构建业务实体
         FaceBiopsyInfo faceBiopsyInfo = new FaceBiopsyInfo();
         faceBiopsyInfo.setFaceBiopsyItemId(faceBiopsyItemId);
-        faceBiopsyInfo.setFaceVerifyMinute(getFaceBiopsyStartMinute(examRecordDataId));
+        faceBiopsyInfo.setFaceVerifyMinute(calculateFaceBiopsyStartMinute(examRecordDataId));
         faceBiopsyInfo.setVerifySteps(copyFaceBiopsyStepDomainListFrom(faceBiopsyItemStepEntityList));
         return faceBiopsyInfo;
     }
@@ -639,13 +593,13 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
      * @return Long 人脸活体检测明细id
      */
     private Long addFaceBiopsyItemEntity(Long examRecordDataId, FaceBiopsyType faceBiopsyType,
-                                         Long faceBiopsyId) {
+                                         Long faceBiopsyId, boolean isInFreezeTime) {
         FaceBiopsyItemEntity faceBiopsyItemEntity = new FaceBiopsyItemEntity();
         faceBiopsyItemEntity.setExamRecordDataId(examRecordDataId);
         faceBiopsyItemEntity.setFaceBiopsyId(faceBiopsyId);
         faceBiopsyItemEntity.setFaceBiopsyType(faceBiopsyType);
         faceBiopsyItemEntity.setCompleted(false);
-        faceBiopsyItemEntity.setInFreezeTime(calculateIsInFreezeTime(examRecordDataId));
+        faceBiopsyItemEntity.setInFreezeTime(isInFreezeTime);
         faceBiopsyItemRepo.save(faceBiopsyItemEntity);
         return faceBiopsyItemEntity.getId();
     }
@@ -667,35 +621,12 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
     }
 
     /**
-     * @param examRecordDataId 考试记录id
-     * @return
-     */
-    private Integer calculateFaceBiopsyStartMinute(Long examRecordDataId) {
-        return calculateFaceBiopsyStartMinute(examRecordDataId, false, null);
-    }
-
-    /**
-     * 计算人脸活体检测开始分钟数
+     * 获取心跳时间
      *
-     * @param examRecordDataId            考试记录id
-     * @param isSpecifiedFreezeTimeBorder 是否指定冻结时间
-     * @param freezeTimeBorder            冻结时间边界
+     * @param studentId
      * @return
      */
-    private Integer calculateFaceBiopsyStartMinute(Long examRecordDataId, Boolean isSpecifiedFreezeTimeBorder,
-                                                   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();
-
-        //如果未开启人脸活体检测,则返回null
-        if (!FaceBiopsyHelper.isFaceVerify(rootOrgId, examId, orgId, studentId)) {
-            return null;
-        }
-
+    private Integer getHeartbeat(Long studentId) {
         ExamSessionInfo examSessionInfo = examSessionInfoService.getExamSessionInfo(studentId);
         if (examSessionInfo == null) {
             throw new StatusException("201002", "考试会话已过期");
@@ -706,25 +637,24 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
         if (heartbeat < 0) {
             heartbeat = 0;
         }
-        Integer freezeTime = examSessionInfo.getFreezeTime();
 
-        //如果特殊指定了获取冻结时间外或冻结时间内的计算方法,则根据参数分别调用相关方法
-        if (isSpecifiedFreezeTimeBorder) {
-            if (freezeTimeBorder == FreezeTimeBorder.IN) {
-                return generateInFreezeTimeFaceBiopsyStartMinute(examRecordDataId, examId, orgId, studentId, heartbeat);
-            } else {
-                return generateOutFreezeTimeFaceBiopsyStartMinute(examId, orgId, studentId, heartbeat, freezeTime);
-            }
-        }
+        return heartbeat;
+    }
 
-        //未特殊指定则自动判断,如果冻结时间内,使用冻结时间内的计算方式
-        if (calculateIsInFreezeTime(examRecordDataId)) {
-            return generateInFreezeTimeFaceBiopsyStartMinute(examRecordDataId, examId, orgId, studentId, heartbeat);
-        }
-        //如果超过冻结时间则使用冻结时间外的计算方式
-        else {
-            return generateOutFreezeTimeFaceBiopsyStartMinute(examId, orgId, studentId, heartbeat, freezeTime);
+    /**
+     * 获取冻结时间
+     *
+     * @param studentId
+     * @return
+     */
+    private Integer getFreezeTime(Long studentId) {
+        ExamSessionInfo examSessionInfo = examSessionInfoService.getExamSessionInfo(studentId);
+        if (examSessionInfo == null) {
+            throw new StatusException("201002", "考试会话已过期");
         }
+
+        Integer freezeTime = examSessionInfo.getFreezeTime();
+        return freezeTime;
     }
 
     /**
@@ -744,23 +674,28 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
     /**
      * 冻结时间内生成人脸活体检测的开始时间
      *
-     * @param examId
-     * @param orgId
-     * @param heartbeat
+     * @param examRecordDataId
      * @return
      */
-    private Integer generateInFreezeTimeFaceBiopsyStartMinute(Long examRecordDataId, Long examId, Long orgId, Long studentId,
-                                                              Integer heartbeat) {
-        Integer verifyTimes = 0;
-        //第一次调用,返回冻结时间内或冻结时间外下次活检时间
+    private Integer generateInFreezeTimeFaceBiopsyStartMinute(Long examRecordDataId) {
+        ExamRecordDataEntity examRecordData = GlobalHelper.getEntity(examRecordDataRepo, examRecordDataId,
+                ExamRecordDataEntity.class);
+        Long examId = examRecordData.getExamId();
+        Long orgId = examRecordData.getOrgId();
+        Long studentId = examRecordData.getStudentId();
+
+        //如果一次接口都没调用过,则默认活检次数为1,否则从库中取出已活检次数
+        Integer verifyTimes = 1;
         FaceBiopsyEntity faceBiopsyEntity = faceBiopsyRepo.findByExamRecordDataId(examRecordDataId);
-        if (faceBiopsyEntity == null) {
-            verifyTimes = 1;
-        } else {
+        if (faceBiopsyEntity != null) {
             verifyTimes = faceBiopsyEntity.getVerifiedTimes();
         }
 
-        //如果没有进行过人脸检测(即第一次活体检测)
+        //默认二次活检
+        int minSecondFaceCheckMinute = PropertyHolder.getInt("oe.faceBiopsy.minSecondFaceCheckMinute", 1);
+        int maxSecondFaceCheckMinute = PropertyHolder.getInt("oe.faceBiopsy.maxSecondFaceCheckMinute", 4);
+
+        //如果是第一次活体检测
         if (verifyTimes == 1) {
             String faceVerifyStartMinuteStr = ExamCacheTransferHelper.getCachedExamProperty(examId, orgId,
                     studentId, ExamProperties.FACE_VERIFY_START_MINUTE.name()).getValue();
@@ -769,6 +704,9 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
             String faceVerifyEndMinuteStr = ExamCacheTransferHelper.getCachedExamProperty(examId, orgId,
                     studentId, ExamProperties.FACE_VERIFY_END_MINUTE.name()).getValue();
             Integer faceVerifyEndMinute = Integer.valueOf(faceVerifyEndMinuteStr);
+
+            Integer heartbeat = getHeartbeat(studentId);
+
             //	case1.如果考生已使用的考试时间(即心跳时间)还未达到系统设置的活体检测开始时间,
             //	则实际活体检测时间=random(配置结束时间,配置开始时间)-考试已用时间
             if (heartbeat < faceVerifyStartMinute) {
@@ -777,19 +715,17 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
             //	case2如果配置开始时间<考生已使用的考试时间<配置结束时间,
             //	则实际活体检测时间=random(配置结束时间,考试已用时间)-考试已用时间,如果结果小于1分钟则默认1分钟
             else if (heartbeat >= faceVerifyStartMinute && heartbeat < faceVerifyEndMinute) {
-                int verifyTime = CommonUtil.calculationRandomNumber(heartbeat, faceVerifyEndMinute) - heartbeat;
-                return verifyTime < 1 ? 1 : verifyTime;
+                int startMinute = CommonUtil.calculationRandomNumber(heartbeat, faceVerifyEndMinute) - heartbeat;
+                return startMinute < 1 ? 1 : startMinute;
             }
-            //case3如果考试已用时间>配置结束时间,则默认1分钟后开始人脸检测
+            //case3如果考试已用时间>配置结束时间,则默认random(1,4)分钟后开始人脸检测
             else {
-                return 1;
+                return CommonUtil.calculationRandomNumber(minSecondFaceCheckMinute, maxSecondFaceCheckMinute);
             }
         }
         //如果是第二次人脸
         else {
-            return CommonUtil.calculationRandomNumber(
-                    PropertyHolder.getInt("oe.faceBiopsy.minSecondFaceCheckMinute", 1),
-                    PropertyHolder.getInt("oe.faceBiopsy.maxSecondFaceCheckMinute", 4));
+            return CommonUtil.calculationRandomNumber(minSecondFaceCheckMinute, maxSecondFaceCheckMinute);
         }
     }
 
@@ -798,8 +734,13 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
      *
      * @return
      */
-    private Integer generateOutFreezeTimeFaceBiopsyStartMinute(Long examId, Long orgId,
-                                                               Long studentId, Integer heartbeat, Integer freezeTime) {
+    private Integer generateOutFreezeTimeFaceBiopsyStartMinute(Long examRecordDataId) {
+        ExamRecordDataEntity examRecordData = GlobalHelper.getEntity(examRecordDataRepo, examRecordDataId,
+                ExamRecordDataEntity.class);
+        Long examId = examRecordData.getExamId();
+        Long orgId = examRecordData.getOrgId();
+        Long studentId = examRecordData.getStudentId();
+
         //如果冻结时间外不添加活体检测,则直接返回null
         if (!isAddFaceVerifyOutFreezeTime(examId, orgId, studentId)) {
             return null;
@@ -814,7 +755,8 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
         Integer faceVerifyEndMinute = Integer.valueOf(strOutFreezeTimeFaceVerifyEndMinute);
 
         //活检开始时间 = (冻结时间 + random(配置开始时间,配置结束时间)) -  考试已用时间
-        int result = freezeTime + CommonUtil.calculationRandomNumber(faceVerifyStartMinute, faceVerifyEndMinute) - heartbeat;
+        int result = getFreezeTime(studentId) +
+                CommonUtil.calculationRandomNumber(faceVerifyStartMinute, faceVerifyEndMinute) - getHeartbeat(studentId);
         return result < 1 ? 1 : result;
     }
 
@@ -862,4 +804,20 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
 
         return usedMilliseconds < examSessionInfo.getFreezeTime() * 60 * 1000;
     }
+
+    /**
+     * 获取是否开启人脸活体检测
+     *
+     * @param examRecordDataId 考试记录id
+     * @return
+     */
+    private Boolean getIsFaceVerify(Long examRecordDataId) {
+        ExamRecordDataEntity examRecordData = GlobalHelper.getEntity(examRecordDataRepo, examRecordDataId,
+                ExamRecordDataEntity.class);
+        Long orgId = examRecordData.getOrgId();
+
+        //如果未开启人脸活体检测,则返回null
+        return FaceBiopsyHelper.isFaceVerify(examRecordData.getRootOrgId(),
+                examRecordData.getExamId(), orgId, examRecordData.getStudentId());
+    }
 }