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