|
@@ -95,6 +95,8 @@ import cn.com.qmth.examcloud.support.enums.FaceBiopsyScheme;
|
|
|
import cn.com.qmth.examcloud.support.enums.HandInExamType;
|
|
|
import cn.com.qmth.examcloud.support.examing.ExamBoss;
|
|
|
import cn.com.qmth.examcloud.support.examing.ExamRecordData;
|
|
|
+import cn.com.qmth.examcloud.support.examing.ExamingActivityTime;
|
|
|
+import cn.com.qmth.examcloud.support.examing.ExamingHeartbeat;
|
|
|
import cn.com.qmth.examcloud.support.examing.ExamingSession;
|
|
|
import cn.com.qmth.examcloud.support.examing.ExamingStatus;
|
|
|
import cn.com.qmth.examcloud.support.helper.ExamCacheTransferHelper;
|
|
@@ -169,7 +171,7 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
|
|
|
|
// 又拍云签名有效时间(秒)
|
|
|
private static final Integer SIGN_TIMEOUT = 60;
|
|
|
-
|
|
|
+
|
|
|
@Transactional
|
|
|
@Override
|
|
|
public StartExamInfo startExam(Long examStudentId, User user) {
|
|
@@ -419,8 +421,6 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
|
}
|
|
|
|
|
|
examingSession = new ExamingSession();
|
|
|
- examingSession.setActiveTime(0L);
|
|
|
- examingSession.setCost(0L);
|
|
|
examingSession.setCourseCode(courseCacheBean.getCode());
|
|
|
examingSession.setCourseId(courseCacheBean.getId());
|
|
|
examingSession.setCreationTime(new Date());
|
|
@@ -1191,10 +1191,17 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
|
}
|
|
|
// 更新考试中的断点续考属性
|
|
|
examRecordDataService.saveExamRecordDataCache(examingRecord.getId(), examingRecord);
|
|
|
+
|
|
|
+ String examingHeartbeatKey = RedisKeyHelper.getBuilder()
|
|
|
+ .examingHeartbeatKey(examSessionInfo.getExamRecordDataId());
|
|
|
+ ExamingHeartbeat examingHeartbeat = redisClient.get(examingHeartbeatKey,
|
|
|
+ ExamingHeartbeat.class);
|
|
|
+
|
|
|
+ long UsedTime = null == examingHeartbeat ? 0 : examingHeartbeat.getCost();
|
|
|
|
|
|
checkExamInProgressInfo.setExamRecordDataId(examingRecord.getId());
|
|
|
checkExamInProgressInfo.setExamId(examSessionInfo.getExamId());
|
|
|
- checkExamInProgressInfo.setUsedTime(examSessionInfo.getCost());
|
|
|
+ checkExamInProgressInfo.setUsedTime(UsedTime);
|
|
|
checkExamInProgressInfo.setMaxInterruptNum(maxInterruptNum);
|
|
|
checkExamInProgressInfo.setInterruptNum(examingRecord.getContinuedCount());
|
|
|
|
|
@@ -1208,7 +1215,7 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
|
} else {// 非新活检,默认使用旧的活检计算方式
|
|
|
faceVerifyMinute = examFaceLivenessVerifyService.getFaceLivenessVerifyMinute(
|
|
|
examSessionInfo.getRootOrgId(), examSessionInfo.getOrgId(), examSessionInfo.getExamId(),
|
|
|
- studentId, examSessionInfo.getExamRecordDataId(), examSessionInfo.getCost().intValue() / 60);
|
|
|
+ studentId, examSessionInfo.getExamRecordDataId(), (int) UsedTime / 60);
|
|
|
}
|
|
|
|
|
|
checkExamInProgressInfo.setFaceVerifyMinute(faceVerifyMinute);
|
|
@@ -1222,19 +1229,35 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
|
if (examingRecord == null) {
|
|
|
return null;
|
|
|
}
|
|
|
+
|
|
|
+ String examingHeartbeatKey = RedisKeyHelper.getBuilder()
|
|
|
+ .examingHeartbeatKey(examSessionInfo.getExamRecordDataId());
|
|
|
+ ExamingHeartbeat examingHeartbeat = redisClient.get(examingHeartbeatKey,
|
|
|
+ ExamingHeartbeat.class);
|
|
|
|
|
|
- // 如果考试时间结束,自动交卷
|
|
|
- if (examSessionInfo.getExamDuration() <= examSessionInfo.getCost() * 1000) {
|
|
|
- delayHandInExamIfLocked(examingRecord.getId());
|
|
|
- return null;
|
|
|
- }
|
|
|
+ long UsedTime = null == examingHeartbeat ? 0 : examingHeartbeat.getCost();
|
|
|
|
|
|
- // 如果已经过了断点续考时间,自动交卷
|
|
|
- long now = System.currentTimeMillis();
|
|
|
- if (now - examSessionInfo.getActiveTime() >= examSessionInfo.getExamReconnectTime().intValue() * 60 * 1000) {
|
|
|
+ // 如果考试时间结束,自动交卷
|
|
|
+ if (examSessionInfo.getExamDuration() <= UsedTime * 1000) {
|
|
|
delayHandInExamIfLocked(examingRecord.getId());
|
|
|
return null;
|
|
|
}
|
|
|
+
|
|
|
+ String examingActiveTimeKey = RedisKeyHelper.getBuilder()
|
|
|
+ .examingActiveTimeKey(examSessionInfo.getExamRecordDataId());
|
|
|
+ ExamingActivityTime examingActiveTime = redisClient.get(examingActiveTimeKey,
|
|
|
+ ExamingActivityTime.class);
|
|
|
+
|
|
|
+ long activeTime = null == examingActiveTime
|
|
|
+ ? System.currentTimeMillis()
|
|
|
+ : examingActiveTime.getActiveTime();
|
|
|
+
|
|
|
+ // 如果已经过了断点续考时间,自动交卷
|
|
|
+ long now = System.currentTimeMillis();
|
|
|
+ if (now - activeTime >= examSessionInfo.getExamReconnectTime().intValue() * 60 * 1000) {
|
|
|
+ delayHandInExamIfLocked(examingRecord.getId());
|
|
|
+ return null;
|
|
|
+ }
|
|
|
return examingRecord;
|
|
|
}
|
|
|
|
|
@@ -1295,24 +1318,56 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
|
public long examHeartbeat(User user) {
|
|
|
Long studentId = user.getUserId();
|
|
|
ExamingSession examSessionInfo = examingSessionService.getExamingSession(studentId);
|
|
|
- if (examSessionInfo == null || examSessionInfo.getExamingStatus().equals(ExamingStatus.INFORMAL)
|
|
|
- || examSessionInfo.getCost() >= examSessionInfo.getExamDuration()) {
|
|
|
- throw new StatusException("8001", "无效的会话,请离开考试");
|
|
|
- }
|
|
|
- // 考试耗时加60秒
|
|
|
- examSessionInfo.setCost(examSessionInfo.getCost() + 60);
|
|
|
+ if (examSessionInfo == null
|
|
|
+ || examSessionInfo.getExamingStatus().equals(ExamingStatus.INFORMAL)) {
|
|
|
+ throw new StatusException("8001", "无效的会话,请离开考试");
|
|
|
+ }
|
|
|
+
|
|
|
+ String examingHeartbeatKey = RedisKeyHelper.getBuilder().examingHeartbeatKey(examSessionInfo.getExamRecordDataId());
|
|
|
+ ExamingHeartbeat examingHeartbeat = redisClient.get(examingHeartbeatKey,ExamingHeartbeat.class);
|
|
|
+
|
|
|
+ if (null != examingHeartbeat
|
|
|
+ && examingHeartbeat.getCost() >= examSessionInfo.getExamDuration()) {
|
|
|
+ throw new StatusException("8002", "考试会话已过期,请重新开考");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (null==examingHeartbeat) {
|
|
|
+ examingHeartbeat=new ExamingHeartbeat();
|
|
|
+ examingHeartbeat.setCost(0L);
|
|
|
+ examingHeartbeat.setTimes(0L);
|
|
|
+ examingHeartbeat.setExamRecordDataId(examSessionInfo.getExamRecordDataId());
|
|
|
+ }
|
|
|
+
|
|
|
+ examingHeartbeat.setTimes(examingHeartbeat.getTimes()+1);
|
|
|
+ examingHeartbeat.setCost(examingHeartbeat.getCost() + 60);
|
|
|
+
|
|
|
+ redisClient.set(examingHeartbeatKey, examingHeartbeat);
|
|
|
+
|
|
|
+ String examingActiveTimeKey = RedisKeyHelper.getBuilder()
|
|
|
+ .examingActiveTimeKey(examSessionInfo.getExamRecordDataId());
|
|
|
+ ExamingActivityTime examingActiveTime = redisClient.get(examingActiveTimeKey,
|
|
|
+ ExamingActivityTime.class);
|
|
|
+ if (null==examingActiveTime) {
|
|
|
+ examingActiveTime=new ExamingActivityTime();
|
|
|
+ examingActiveTime.setActiveTime(System.currentTimeMillis());
|
|
|
+ examingActiveTime.setExamRecordDataId(examSessionInfo.getExamRecordDataId());
|
|
|
+ }
|
|
|
+
|
|
|
+ redisClient.set(examingActiveTimeKey, examingActiveTime);
|
|
|
+
|
|
|
+ long activeTime = examingActiveTime.getActiveTime();
|
|
|
+
|
|
|
long now = System.currentTimeMillis();
|
|
|
- if (now - examSessionInfo.getActiveTime() >= examSessionInfo.getExamReconnectTime().intValue() * 60 * 1000) {
|
|
|
+ if (now - activeTime>= examSessionInfo.getExamReconnectTime().intValue() * 60 * 1000) {
|
|
|
delayHandInExamIfLocked(examSessionInfo.getExamRecordDataId());
|
|
|
return 0L;
|
|
|
}
|
|
|
- // 更新考试会话过期时间
|
|
|
- examingSessionService.saveExamingSession(examSessionInfo.getStudentId(), examSessionInfo);
|
|
|
+
|
|
|
// 在线考生心跳打点
|
|
|
ReportsUtil.report(new OnlineExamStudentReport(user.getRootOrgId(), user.getUserId(),
|
|
|
examSessionInfo.getExamId(), examSessionInfo.getExamStudentId()));
|
|
|
// 返回考试剩余时间
|
|
|
- return examSessionInfo.getExamDuration() - (examSessionInfo.getCost() * 1000);
|
|
|
+ return examSessionInfo.getExamDuration() - (examingHeartbeat.getCost() * 1000);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1329,7 +1384,15 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
|
if (examingSession == null) {
|
|
|
throw new StatusException("oestudent-100100", "考试会话已过期");
|
|
|
}
|
|
|
- Long examUsedMilliSeconds = examingSession.getCost() * 1000;
|
|
|
+
|
|
|
+ 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;
|
|
|
// 如果没有超过冻结时间,抛出异常
|
|
|
if (examingSession.getExamType().equals(ExamType.ONLINE.name())) {
|
|
|
ExamRecordData examRecordData = examRecordDataService
|