浏览代码

同步开发环境代码

lideyin 4 年之前
父节点
当前提交
0ff96bb34a

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

@@ -442,6 +442,62 @@ public class ExamControlServiceImpl implements ExamControlService {
 
     }
 
+    /**
+     * 计算学生已作答的时间(秒)
+     *
+     * @param studentId
+     * @return
+     */
+    private long calcUsedExamSeconds(Long studentId) {
+        ExamingSession examSessionInfo = examingSessionService.getExamingSession(studentId);
+        if (examSessionInfo == null
+                || examSessionInfo.getExamingStatus().equals(ExamingStatus.INFORMAL)) {
+            return 0;
+        }
+
+        ExamRecordData examRecordDataCache =
+                examRecordDataService.getExamRecordDataCache(examSessionInfo.getExamRecordDataId());
+        //如果没有开始作答时间,则返回0
+        if (null == examRecordDataCache.getStartTime()) {
+            return 0;
+        }
+
+        boolean isContinued =
+                (examRecordDataCache.getIsContinued() != null && examRecordDataCache.getIsContinued()) ? true : false;
+
+        Date now = new Date();
+        long usedExamSeconds = 0;
+
+        //无断点续考,考试已用时间 = 当前时间 - 作答时间
+        if (!isContinued) {
+            usedExamSeconds = (now.getTime() - examRecordDataCache.getStartTime().getTime()) / 1000;
+        }
+
+        //如果有断点续考,考试已用时间 = 断点前考试已用时间 + (当前时间 - 最近一次的作答时间)
+        else {
+            //获取最新的一条断点记录
+            ExamContinuedRecordEntity latestExamContinuedRecord =
+                    examContinuedRecordRepo.findTopByExamRecordDataIdOrderByIdDesc(examSessionInfo.getExamRecordDataId());
+            if (null == latestExamContinuedRecord) {
+                throw new StatusException("101004", "找不到断点续考记录");
+            }
+
+            //断点前考试已用时间
+            long lastUsedMilliseconds = latestExamContinuedRecord.getUsedExamTime();
+
+            //断点续考后,未调用作答接口,则认为断点后未开始答题,直接返回断点前的考试已用时间
+            if (null == latestExamContinuedRecord.getStartTime()) {
+                return lastUsedMilliseconds / 1000;
+            }
+
+            //最新作答时间
+            long lastStartTime = latestExamContinuedRecord.getStartTime().getTime();
+            usedExamSeconds = (lastUsedMilliseconds + (now.getTime() - lastStartTime)) / 1000;
+        }
+
+        return usedExamSeconds;
+    }
+
     /**
      * 开考预处理
      *
@@ -477,7 +533,7 @@ public class ExamControlServiceImpl implements ExamControlService {
             throw new StatusException("008004", "已经有考试中的科目");
         }
 
-        Long examId=examStudent.getExamId();
+        Long examId = examStudent.getExamId();
         Long examStageId = examStudent.getExamStageId();
 
         ExamSettingsCacheBean examSettingsCacheBean = ExamCacheTransferHelper.getCachedExam(examStudent.getExamId(),
@@ -660,7 +716,7 @@ public class ExamControlServiceImpl implements ExamControlService {
                 }
             }
 
-            setAndSaveActiveTime(examRecordDataId, ip);
+
         } else if (handInExamType == HandInExamType.AUTO) {
             examRecordData.setExamRecordStatus(ExamRecordStatus.EXAM_AUTO_HAND_IN);
             examRecordData.setCleanTime(new Date());
@@ -671,6 +727,8 @@ public class ExamControlServiceImpl implements ExamControlService {
         //交卷时,落地最近的上次活动时间字段
         examRecordData.setLastActiveTime(new Date(getExamingActivityTime(examRecordDataId).getActiveTime()));
 
+        setAndSaveActiveTime(examRecordDataId, ip);
+
         //特殊处理:如果考试类型为 在线练习,则需要将部分数据提前入库,并更新相关状态
         if (ExamType.PRACTICE == examRecordData.getExamType()) {
 
@@ -1459,6 +1517,7 @@ public class ExamControlServiceImpl implements ExamControlService {
             //考试已用时间(秒)
             long usedTime = null == examingHeartbeat ? 0 : examingHeartbeat.getCost();
 
+            Long examRecordDataId = examingRecord.getId();
             if ((examingRecord.getIsExceed() == null || !examingRecord.getIsExceed())
                     && examingRecord.getContinuedCount().intValue() < maxInterruptNum.intValue()) {// 未达到最大断点次数,可继续断点一次
                 // 断点续考次数自增
@@ -1472,17 +1531,17 @@ public class ExamControlServiceImpl implements ExamControlService {
                 checkExamInProgressInfo.setIsExceed(false);
 
                 //添加断点记录
-                addExamContinuedRecord(examingRecord.getId(), usedTime * 1000, now);
+                addExamContinuedRecord(examRecordDataId, usedTime * 1000, now);
             } else {
                 examingRecord.setIsExceed(true);
                 checkExamInProgressInfo.setIsExceed(true);
             }
             examingRecord.setLastActiveTime(now);
             // 更新考试中的断点续考属性
-            examRecordDataService.saveExamRecordDataCache(examingRecord.getId(), examingRecord);
+            examRecordDataService.saveExamRecordDataCache(examRecordDataId, examingRecord);
 
 
-            checkExamInProgressInfo.setExamRecordDataId(examingRecord.getId());
+            checkExamInProgressInfo.setExamRecordDataId(examRecordDataId);
             checkExamInProgressInfo.setExamId(examSessionInfo.getExamId());
             checkExamInProgressInfo.setUsedTime(usedTime);
             checkExamInProgressInfo.setMaxInterruptNum(maxInterruptNum);
@@ -1495,7 +1554,7 @@ public class ExamControlServiceImpl implements ExamControlService {
 
             // 如果是新活体检测方案,则使用新的计算方案计算活检开始时间
             if (faceBiopsyScheme == FaceBiopsyScheme.NEW) {
-                faceVerifyMinute = faceBiopsyService.calculateFaceBiopsyStartMinute(examingRecord.getId());
+                faceVerifyMinute = faceBiopsyService.calculateFaceBiopsyStartMinute(examRecordDataId);
             } else {// 非新活检,默认使用旧的活检计算方式
                 faceVerifyMinute = examFaceLivenessVerifyService.getFaceLivenessVerifyMinute(
                         examSessionInfo.getRootOrgId(), examSessionInfo.getOrgId(), examSessionInfo.getExamId(),
@@ -1505,16 +1564,16 @@ public class ExamControlServiceImpl implements ExamControlService {
             checkExamInProgressInfo.setFaceVerifyMinute(faceVerifyMinute);
 
             //考试过程记录(断点)打点
-            ExamingActivityTime lastExamingActivityTime = getExamingActivityTime(examingRecord.getId());
+            ExamingActivityTime lastExamingActivityTime = getExamingActivityTime(examRecordDataId);
             ReportsUtil.report(
-                    new ExamProcessRecordReport(examingRecord.getId(),
+                    new ExamProcessRecordReport(examRecordDataId,
                             ExamProcess.BREAK_OFF,
                             lastExamingActivityTime.getActiveTime() == null ? new Date() : new Date(lastExamingActivityTime.getActiveTime()))
             );
             //考试过程记录(断点续考)打点
-            ReportsUtil.report(new ExamProcessRecordReport(examingRecord.getId(), ExamProcess.CONTINUE, new Date()));
+            ReportsUtil.report(new ExamProcessRecordReport(examRecordDataId, ExamProcess.CONTINUE, new Date()));
 
-            setAndSaveActiveTime(examingRecord.getId(), ip);
+            setAndSaveActiveTime(examRecordDataId, ip);
 
             return checkExamInProgressInfo;
         }
@@ -1653,25 +1712,11 @@ public class ExamControlServiceImpl implements ExamControlService {
             throw new StatusException("101003", "考试会话已过期,请重新开考");
         }
 
-        if (null == examingHeartbeat) {
-            examingHeartbeat = new ExamingHeartbeat();
-            examingHeartbeat.setExamRecordDataId(examSessionInfo.getExamRecordDataId());
-            examingHeartbeat.setCost(0L);
-        }
-
         boolean isContinued =
                 (examRecordDataCache.getIsContinued() != null && examRecordDataCache.getIsContinued()) ? true : false;
 
-        Date now = new Date();
-        long usedExamSeconds = examingHeartbeat.getCost();
-
-        //无断点续考,考试已用时间 = 当前时间 - 作答时间
-        if (!isContinued) {
-            usedExamSeconds = (now.getTime() - examRecordDataCache.getStartTime().getTime()) / 1000;
-        }
-
-        //如果有断点续考,考试已用时间 = 断点前考试已用时间 + (当前时间 - 最近一次的作答时间)
-        else {
+        //如果有断点续考,需要校验是否先调用作答接口
+        if (isContinued) {
             //获取最新的一条断点记录
             ExamContinuedRecordEntity latestExamContinuedRecord =
                     examContinuedRecordRepo.findTopByExamRecordDataIdOrderByIdDesc(examSessionInfo.getExamRecordDataId());
@@ -1682,15 +1727,14 @@ public class ExamControlServiceImpl implements ExamControlService {
             if (null == latestExamContinuedRecord.getStartTime()) {
                 throw new StatusException("101005", "请先执行作答");
             }
+        }
 
-            //断点前考试已用时间
-            long lastUsedMilliseconds = latestExamContinuedRecord.getUsedExamTime();
-            //最新作答时间
-            long lastStartTime = latestExamContinuedRecord.getStartTime().getTime();
-            usedExamSeconds = (lastUsedMilliseconds + (now.getTime() - lastStartTime)) / 1000;
+        if (null == examingHeartbeat) {
+            examingHeartbeat = new ExamingHeartbeat();
+            examingHeartbeat.setExamRecordDataId(examSessionInfo.getExamRecordDataId());
         }
 
-        examingHeartbeat.setCost(usedExamSeconds);
+        examingHeartbeat.setCost(calcUsedExamSeconds(studentId));
         redisClient.set(examingHeartbeatKey, examingHeartbeat);//更新心跳缓存
 
         setAndSaveActiveTime(examSessionInfo.getExamRecordDataId(), ip);
@@ -1707,16 +1751,16 @@ public class ExamControlServiceImpl implements ExamControlService {
     /**
      * 设置并保存活动时间
      *
-     * @param examRecrodDataId 考试记录id
+     * @param examRecordDataId 考试记录id
      */
-    private void setAndSaveActiveTime(Long examRecrodDataId, String ip) {
+    private void setAndSaveActiveTime(Long examRecordDataId, String ip) {
         String examingActiveTimeKey = RedisKeyHelper.getBuilder()
-                .examingActiveTimeKey(examRecrodDataId);
+                .examingActiveTimeKey(examRecordDataId);
         ExamingActivityTime examingActiveTime = redisClient.get(examingActiveTimeKey,
                 ExamingActivityTime.class);
         if (null == examingActiveTime) {
             examingActiveTime = new ExamingActivityTime();
-            examingActiveTime.setExamRecordDataId(examRecrodDataId);
+            examingActiveTime.setExamRecordDataId(examRecordDataId);
         }
 
         Long now = System.currentTimeMillis();
@@ -1725,7 +1769,7 @@ public class ExamControlServiceImpl implements ExamControlService {
         String lastIp = examingActiveTime.getRealIp();
         if (StringUtils.isNotEmpty(ip) && StringUtils.isNotEmpty(lastIp) && !ip.equals(lastIp)) {
             ReportsUtil.report(
-                    new ExamProcessRecordReport(examRecrodDataId, ExamProcess.IP_CHANGE, new Date(now))
+                    new ExamProcessRecordReport(examRecordDataId, ExamProcess.IP_CHANGE, new Date(now))
             );
         }
 
@@ -1738,16 +1782,16 @@ public class ExamControlServiceImpl implements ExamControlService {
     /**
      * 获取上次活动缓存
      *
-     * @param examRecrodDataId
+     * @param examRecordDataId
      * @return
      */
-    private ExamingActivityTime getExamingActivityTime(Long examRecrodDataId) {
+    private ExamingActivityTime getExamingActivityTime(Long examRecordDataId) {
         String examingActiveTimeKey = RedisKeyHelper.getBuilder()
-                .examingActiveTimeKey(examRecrodDataId);
+                .examingActiveTimeKey(examRecordDataId);
         ExamingActivityTime examingActiveTime = redisClient.get(examingActiveTimeKey, ExamingActivityTime.class);
         if (null == examingActiveTime) {
             examingActiveTime = new ExamingActivityTime();
-            examingActiveTime.setExamRecordDataId(examRecrodDataId);
+            examingActiveTime.setExamRecordDataId(examRecordDataId);
         }
 
         return examingActiveTime;
@@ -1767,15 +1811,9 @@ public class ExamControlServiceImpl implements ExamControlService {
             throw new StatusException("oestudent-100100", "考试会话已过期");
         }
 
-        String examingHeartbeatKey = RedisKeyHelper.getBuilder()
-                .examingHeartbeatKey(examingSession.getExamRecordDataId());
-        ExamingHeartbeat examingHeartbeat = redisClient.get(examingHeartbeatKey,
-                ExamingHeartbeat.class);
-
-        long cost = null == examingHeartbeat ? 0L : examingHeartbeat.getCost();
-
-        Long examUsedMilliSeconds = cost * 1000;
-
+        //交卷时重新计算考试已用时间
+        Long examUsedMilliSeconds = calcUsedExamSeconds(studentId) * 1000;
+        //考试总时长
         long examTotalMilliSeconds = calcExamTotalMilliSeconds(examingSession.getExamRecordDataId());
         //如果开启场次,并且设置了定点交卷,且考试时间已经用完,则不需要校验冻结时间,直接返回考试时长
         if (isTimingEnd(examingSession.getExamId(), studentId, examingSession.getExamStageId())