|
@@ -27,6 +27,10 @@ import cn.com.qmth.examcloud.core.oe.student.api.response.GetExamRecordQuestions
|
|
import cn.com.qmth.examcloud.core.oe.student.base.utils.CommonUtil;
|
|
import cn.com.qmth.examcloud.core.oe.student.base.utils.CommonUtil;
|
|
import cn.com.qmth.examcloud.core.oe.student.base.utils.QuestionTypeUtil;
|
|
import cn.com.qmth.examcloud.core.oe.student.base.utils.QuestionTypeUtil;
|
|
import cn.com.qmth.examcloud.core.oe.student.bean.*;
|
|
import cn.com.qmth.examcloud.core.oe.student.bean.*;
|
|
|
|
+import cn.com.qmth.examcloud.core.oe.student.dao.ExamContinuedRecordRepo;
|
|
|
|
+import cn.com.qmth.examcloud.core.oe.student.dao.ExamRecordDataRepo;
|
|
|
|
+import cn.com.qmth.examcloud.core.oe.student.dao.entity.ExamContinuedRecordEntity;
|
|
|
|
+import cn.com.qmth.examcloud.core.oe.student.dao.entity.ExamRecordDataEntity;
|
|
import cn.com.qmth.examcloud.core.oe.student.service.*;
|
|
import cn.com.qmth.examcloud.core.oe.student.service.*;
|
|
import cn.com.qmth.examcloud.core.oe.task.api.ExamCaptureCloudService;
|
|
import cn.com.qmth.examcloud.core.oe.task.api.ExamCaptureCloudService;
|
|
import cn.com.qmth.examcloud.core.oe.task.api.request.SaveExamCaptureSyncCompareResultReq;
|
|
import cn.com.qmth.examcloud.core.oe.task.api.request.SaveExamCaptureSyncCompareResultReq;
|
|
@@ -56,6 +60,7 @@ import cn.com.qmth.examcloud.support.helper.FaceBiopsyHelper;
|
|
import cn.com.qmth.examcloud.support.redis.RedisKeyHelper;
|
|
import cn.com.qmth.examcloud.support.redis.RedisKeyHelper;
|
|
import cn.com.qmth.examcloud.web.bootstrap.PropertyHolder;
|
|
import cn.com.qmth.examcloud.web.bootstrap.PropertyHolder;
|
|
import cn.com.qmth.examcloud.web.exception.SequenceLockException;
|
|
import cn.com.qmth.examcloud.web.exception.SequenceLockException;
|
|
|
|
+import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
|
|
import cn.com.qmth.examcloud.web.helpers.SequenceLockHelper;
|
|
import cn.com.qmth.examcloud.web.helpers.SequenceLockHelper;
|
|
import cn.com.qmth.examcloud.web.redis.RedisClient;
|
|
import cn.com.qmth.examcloud.web.redis.RedisClient;
|
|
import cn.com.qmth.examcloud.ws.api.WsCloudService;
|
|
import cn.com.qmth.examcloud.ws.api.WsCloudService;
|
|
@@ -136,6 +141,10 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
SyncExamDataCloudService syncExamDataCloudService;
|
|
SyncExamDataCloudService syncExamDataCloudService;
|
|
@Autowired
|
|
@Autowired
|
|
private ExamStageCloudService examStageCloudService;
|
|
private ExamStageCloudService examStageCloudService;
|
|
|
|
+ @Autowired
|
|
|
|
+ private ExamRecordDataRepo examRecordDataRepo;
|
|
|
|
+ @Autowired
|
|
|
|
+ private ExamContinuedRecordRepo examContinuedRecordRepo;
|
|
|
|
|
|
private static final String SEPARATOR = "/";
|
|
private static final String SEPARATOR = "/";
|
|
|
|
|
|
@@ -173,7 +182,8 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
|
|
|
|
// 检查并获取考试信息
|
|
// 检查并获取考试信息
|
|
startTime = System.currentTimeMillis();
|
|
startTime = System.currentTimeMillis();
|
|
- ExamSettingsCacheBean examBean = checkExam(examingSession.getExamId(), examingSession.getStudentId());
|
|
|
|
|
|
+ ExamSettingsCacheBean examBean = checkExam(examingSession.getExamId(),
|
|
|
|
+ examingSession.getStudentId(), examingSession.getExamStageId());
|
|
if (log.isDebugEnabled()) {
|
|
if (log.isDebugEnabled()) {
|
|
log.debug("2 检查并获取考试信息耗时:" + (System.currentTimeMillis() - startTime) + " ms");
|
|
log.debug("2 检查并获取考试信息耗时:" + (System.currentTimeMillis() - startTime) + " ms");
|
|
}
|
|
}
|
|
@@ -298,6 +308,43 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ @Override
|
|
|
|
+ public void startAnswer(Long examRecordDataId) {
|
|
|
|
+ Date now = new Date();
|
|
|
|
+
|
|
|
|
+ ExamRecordDataEntity examRecordDataEntity =
|
|
|
|
+ GlobalHelper.getEntity(examRecordDataRepo, examRecordDataId, ExamRecordDataEntity.class);
|
|
|
|
+ if (null == examRecordDataEntity) {
|
|
|
|
+ throw new StatusException("100001", "找不到相关考试记录");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //如果是断点续考,则需要更新断点续考表中开始答题时间
|
|
|
|
+ if (null != examRecordDataEntity.getIsContinued() && examRecordDataEntity.getIsContinued()) {
|
|
|
|
+ //获取最新的一条断点记录
|
|
|
|
+ ExamContinuedRecordEntity latestExamContinuedRecord =
|
|
|
|
+ examContinuedRecordRepo.findTopByExamRecordDataIdOrderByIdDesc(examRecordDataId);
|
|
|
|
+ if (null == latestExamContinuedRecord) {
|
|
|
|
+ throw new StatusException("100002", "找不到断点续考记录");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ latestExamContinuedRecord.setStartTime(now);
|
|
|
|
+ examContinuedRecordRepo.save(latestExamContinuedRecord);
|
|
|
|
+ }
|
|
|
|
+ //第一次开考,更新考试记录中的开始答题时间
|
|
|
|
+ else {
|
|
|
|
+ //更新考试记录临时表
|
|
|
|
+ examRecordDataEntity.setStartTime(now);
|
|
|
|
+ examRecordDataEntity.setLastActiveTime(now);
|
|
|
|
+ examRecordDataRepo.save(examRecordDataEntity);
|
|
|
|
+
|
|
|
|
+ //更新考试记录缓存
|
|
|
|
+ ExamRecordData examRecordData = examRecordDataService.getExamRecordDataCache(examRecordDataId);
|
|
|
|
+ examRecordData.setLastActiveTime(now);
|
|
|
|
+ examRecordData.setStartTime(now);
|
|
|
|
+ examRecordDataService.saveExamRecordDataCache(examRecordDataId, examRecordData);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* 开考预处理
|
|
* 开考预处理
|
|
*
|
|
*
|
|
@@ -305,11 +352,6 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
* @param user
|
|
* @param user
|
|
*/
|
|
*/
|
|
private void prepare4Exam(Long examStudentId, User user) {
|
|
private void prepare4Exam(Long examStudentId, User user) {
|
|
-
|
|
|
|
-// // 开始考试上锁,分布式锁,系统在请求结束后会,自动释放锁,无需手动解锁
|
|
|
|
-// String sequenceLockKey = Constants.EXAM_CONTROL_LOCK_PREFIX + user.getUserId();
|
|
|
|
-// SequenceLockHelper.getLock(sequenceLockKey);
|
|
|
|
-
|
|
|
|
SysPropertyCacheBean stuClientLoginLimit = CacheHelper.getSysProperty("STU_CLIENT_LOGIN_LIMIT");
|
|
SysPropertyCacheBean stuClientLoginLimit = CacheHelper.getSysProperty("STU_CLIENT_LOGIN_LIMIT");
|
|
Boolean stuClientLoginLimitBoolean = false;
|
|
Boolean stuClientLoginLimitBoolean = false;
|
|
if (stuClientLoginLimit.getHasValue()) {
|
|
if (stuClientLoginLimit.getHasValue()) {
|
|
@@ -338,7 +380,7 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
}
|
|
}
|
|
|
|
|
|
ExamSettingsCacheBean examSettingsCacheBean = ExamCacheTransferHelper.getCachedExam(examStudent.getExamId(),
|
|
ExamSettingsCacheBean examSettingsCacheBean = ExamCacheTransferHelper.getCachedExam(examStudent.getExamId(),
|
|
- examStudent.getStudentId());
|
|
|
|
|
|
+ examStudent.getStudentId(),examStudent.getExamStageId());
|
|
|
|
|
|
StudentCacheBean studentCacheBean = CacheHelper.getStudent(examStudent.getStudentId());
|
|
StudentCacheBean studentCacheBean = CacheHelper.getStudent(examStudent.getStudentId());
|
|
|
|
|
|
@@ -363,7 +405,7 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- // 机构特殊设置开启未配置,不允许考试
|
|
|
|
|
|
+ // 机构特殊设置开启但未配置,不允许考试
|
|
if (examSettingsCacheBean.getSpecialSettingsType() == ExamSpecialSettingsType.ORG_BASED) {
|
|
if (examSettingsCacheBean.getSpecialSettingsType() == ExamSpecialSettingsType.ORG_BASED) {
|
|
// 需求调整,所有的组织机构取学生表所关联的orgId
|
|
// 需求调整,所有的组织机构取学生表所关联的orgId
|
|
Long orgId = CacheHelper.getStudent(examStudent.getStudentId()).getOrgId();
|
|
Long orgId = CacheHelper.getStudent(examStudent.getStudentId()).getOrgId();
|
|
@@ -374,6 +416,15 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ //场次特殊设置开启但未配置,不允许考试
|
|
|
|
+ if (examSettingsCacheBean.getSpecialSettingsType() == ExamSpecialSettingsType.STAGE_BASED) {
|
|
|
|
+ if (null != examStudent.getExamStageId()) {
|
|
|
|
+ ExamStageCacheBean examStage = CacheHelper.getExamStage(examStudent.getExamId(), examStudent.getExamStageId());
|
|
|
|
+ if (!examStage.getHasValue()) {
|
|
|
|
+ throw new StatusException("100016", "场次配置未完成,不允许考试");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
if (!examSettingsCacheBean.getEnable()
|
|
if (!examSettingsCacheBean.getEnable()
|
|
@@ -947,36 +998,58 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
*
|
|
*
|
|
* @param examId
|
|
* @param examId
|
|
* @param studentId
|
|
* @param studentId
|
|
|
|
+ * @param examStageId
|
|
* @return
|
|
* @return
|
|
*/
|
|
*/
|
|
- private ExamSettingsCacheBean checkExam(Long examId, Long studentId) {
|
|
|
|
|
|
+ private ExamSettingsCacheBean checkExam(Long examId, Long studentId, Long examStageId) {
|
|
|
|
|
|
// 学习中心特殊考试配置(是否禁考,开考时间可以特殊设置)
|
|
// 学习中心特殊考试配置(是否禁考,开考时间可以特殊设置)
|
|
- ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getCachedExam(examId, studentId);
|
|
|
|
|
|
+ ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getCachedExam(examId, studentId,examStageId);
|
|
|
|
+
|
|
// 如果启用了了特殊设置,并且无特殊设置时结束考试 配置 设置为true..且实际未设置特殊设置则不允许考试
|
|
// 如果启用了了特殊设置,并且无特殊设置时结束考试 配置 设置为true..且实际未设置特殊设置则不允许考试
|
|
ExamPropertyCacheBean limitedIfNoSpecialSettings = ExamCacheTransferHelper.getDefaultCachedExamProperty(examId,
|
|
ExamPropertyCacheBean limitedIfNoSpecialSettings = ExamCacheTransferHelper.getDefaultCachedExamProperty(examId,
|
|
ExamProperties.LIMITED_IF_NO_SPECIAL_SETTINGS.toString());
|
|
ExamProperties.LIMITED_IF_NO_SPECIAL_SETTINGS.toString());
|
|
- if (examBean.getSpecialSettingsEnabled() && (limitedIfNoSpecialSettings.getHasValue()
|
|
|
|
- && Boolean.valueOf(limitedIfNoSpecialSettings.getValue()))) {
|
|
|
|
|
|
+ if (examBean.getSpecialSettingsEnabled()) {
|
|
|
|
+ if ((limitedIfNoSpecialSettings.getHasValue()
|
|
|
|
+ && Boolean.valueOf(limitedIfNoSpecialSettings.getValue()))) {
|
|
|
|
+ // 学生特殊设置开启未配置,不允许考试
|
|
|
|
+ if (examBean.getSpecialSettingsType() == ExamSpecialSettingsType.STUDENT_BASED) {
|
|
|
|
+ ExamStudentSettingsCacheBean specialSettings = CacheHelper.getExamStudentSettings(examId, studentId);
|
|
|
|
+ if (!specialSettings.getHasValue()) {
|
|
|
|
+ throw new StatusException("2001", "考试配置未完成,不允许考试");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
- // 学生特殊设置开启未配置,不允许考试
|
|
|
|
- if (examBean.getSpecialSettingsType() == ExamSpecialSettingsType.STUDENT_BASED) {
|
|
|
|
- ExamStudentSettingsCacheBean specialSettings = CacheHelper.getExamStudentSettings(examId, studentId);
|
|
|
|
- if (!specialSettings.getHasValue()) {
|
|
|
|
- throw new StatusException("2001", "考试配置未完成,不允许考试");
|
|
|
|
|
|
+ // 机构特殊设置开启未配置,不允许考试
|
|
|
|
+ if (examBean.getSpecialSettingsType() == ExamSpecialSettingsType.ORG_BASED) {
|
|
|
|
+ // 需求调整,所有的组织机构取学生表所关联的orgId
|
|
|
|
+ Long orgId = CacheHelper.getStudent(studentId).getOrgId();
|
|
|
|
+ ExamOrgSettingsCacheBean specialSettings = CacheHelper.getExamOrgSettings(examId, orgId);
|
|
|
|
+ if (!specialSettings.getHasValue()) {
|
|
|
|
+ throw new StatusException("2002", "考试配置未完成,不允许考试");
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
|
|
- // 机构特殊设置开启未配置,不允许考试
|
|
|
|
- if (examBean.getSpecialSettingsType() == ExamSpecialSettingsType.ORG_BASED) {
|
|
|
|
- // 需求调整,所有的组织机构取学生表所关联的orgId
|
|
|
|
- Long orgId = CacheHelper.getStudent(studentId).getOrgId();
|
|
|
|
- ExamOrgSettingsCacheBean specialSettings = CacheHelper.getExamOrgSettings(examId, orgId);
|
|
|
|
- if (!specialSettings.getHasValue()) {
|
|
|
|
- throw new StatusException("2002", "考试配置未完成,不允许考试");
|
|
|
|
|
|
+ //场次特殊设置开启但未配置,不允许考试
|
|
|
|
+ if (examBean.getSpecialSettingsType() == ExamSpecialSettingsType.STAGE_BASED) {
|
|
|
|
+ if (null != examStageId) {
|
|
|
|
+ ExamStageCacheBean examStage = CacheHelper.getExamStage(examId, examStageId);
|
|
|
|
+ if (!examStage.getHasValue()) {
|
|
|
|
+ throw new StatusException("2006", "场次配置未完成,不允许考试");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ //场次禁用,不允许考试 TODO 20200814 跟张莹确认一下,场次被禁用了是不能考试还是使用考试的设置???
|
|
|
|
+ if (examBean.getSpecialSettingsType() == ExamSpecialSettingsType.STAGE_BASED) {
|
|
|
|
+ if (null != examStageId) {
|
|
|
|
+ ExamStageCacheBean examStage = CacheHelper.getExamStage(examId, examStageId);
|
|
|
|
+ if (examStage.getHasValue() && !examStage.getEnable()) {
|
|
|
|
+ throw new StatusException("2007", "场次被禁用,不允许考试");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
if (!examBean.getEnable() || (examBean.getExamLimit() != null && examBean.getExamLimit())) {
|
|
if (!examBean.getEnable() || (examBean.getExamLimit() != null && examBean.getExamLimit())) {
|
|
@@ -1228,6 +1301,7 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
if (examingRecord == null) {
|
|
if (examingRecord == null) {
|
|
return null;
|
|
return null;
|
|
} else {
|
|
} else {
|
|
|
|
+ Date now = new Date();
|
|
Integer maxInterruptNum = getMaxInterruptNum(examSessionInfo.getExamId(), examSessionInfo.getRootOrgId(),
|
|
Integer maxInterruptNum = getMaxInterruptNum(examSessionInfo.getExamId(), examSessionInfo.getRootOrgId(),
|
|
examSessionInfo.getOrgId());
|
|
examSessionInfo.getOrgId());
|
|
CheckExamInProgressInfo checkExamInProgressInfo = new CheckExamInProgressInfo();
|
|
CheckExamInProgressInfo checkExamInProgressInfo = new CheckExamInProgressInfo();
|
|
@@ -1240,11 +1314,17 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
examingRecord.setContinuedCount(continutedCount + 1);
|
|
examingRecord.setContinuedCount(continutedCount + 1);
|
|
examingRecord.setIsContinued(true);
|
|
examingRecord.setIsContinued(true);
|
|
examingRecord.setIsExceed(false);
|
|
examingRecord.setIsExceed(false);
|
|
|
|
+ examingRecord.setLastActiveTime(now);
|
|
|
|
+ examingRecord.setContinuedTime(now);
|
|
checkExamInProgressInfo.setIsExceed(false);
|
|
checkExamInProgressInfo.setIsExceed(false);
|
|
|
|
+
|
|
|
|
+ //添加断点记录
|
|
|
|
+ addExamContinuedRecord(examingRecord.getId(), now);
|
|
} else {
|
|
} else {
|
|
examingRecord.setIsExceed(true);
|
|
examingRecord.setIsExceed(true);
|
|
checkExamInProgressInfo.setIsExceed(true);
|
|
checkExamInProgressInfo.setIsExceed(true);
|
|
}
|
|
}
|
|
|
|
+ examingRecord.setLastActiveTime(now);
|
|
// 更新考试中的断点续考属性
|
|
// 更新考试中的断点续考属性
|
|
examRecordDataService.saveExamRecordDataCache(examingRecord.getId(), examingRecord);
|
|
examRecordDataService.saveExamRecordDataCache(examingRecord.getId(), examingRecord);
|
|
|
|
|
|
@@ -1280,6 +1360,20 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * 添加断点续考记录
|
|
|
|
+ *
|
|
|
|
+ * @param examRecordDataId
|
|
|
|
+ * @param continuedTime
|
|
|
|
+ */
|
|
|
|
+ private void addExamContinuedRecord(Long examRecordDataId, Date continuedTime) {
|
|
|
|
+ ExamContinuedRecordEntity entity = new ExamContinuedRecordEntity();
|
|
|
|
+ entity.setExamRecordDataId(examRecordDataId);
|
|
|
|
+ entity.setContinuedTime(continuedTime);
|
|
|
|
+
|
|
|
|
+ examContinuedRecordRepo.save(entity);
|
|
|
|
+ }
|
|
|
|
+
|
|
private ExamRecordData checkExamSession(ExamingSession examSessionInfo, Long studentId) {
|
|
private ExamRecordData checkExamSession(ExamingSession examSessionInfo, Long studentId) {
|
|
ExamRecordData examingRecord = examRecordDataService
|
|
ExamRecordData examingRecord = examRecordDataService
|
|
.getExamRecordDataCache(examSessionInfo.getExamRecordDataId());
|
|
.getExamRecordDataCache(examSessionInfo.getExamRecordDataId());
|