|
@@ -1,67 +1,16 @@
|
|
|
package com.qmth.themis.business.service.impl;
|
|
|
|
|
|
-import java.io.File;
|
|
|
-import java.io.IOException;
|
|
|
-import java.io.InputStream;
|
|
|
-import java.math.BigDecimal;
|
|
|
-import java.text.SimpleDateFormat;
|
|
|
-import java.time.LocalDateTime;
|
|
|
-import java.time.ZoneOffset;
|
|
|
-import java.util.ArrayList;
|
|
|
-import java.util.Arrays;
|
|
|
-import java.util.Calendar;
|
|
|
-import java.util.Collections;
|
|
|
-import java.util.Comparator;
|
|
|
-import java.util.Date;
|
|
|
-import java.util.HashMap;
|
|
|
-import java.util.HashSet;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Map;
|
|
|
-import java.util.Objects;
|
|
|
-import java.util.Set;
|
|
|
-import java.util.UUID;
|
|
|
-import java.util.regex.Matcher;
|
|
|
-import java.util.regex.Pattern;
|
|
|
-import java.util.stream.Collectors;
|
|
|
-
|
|
|
-import javax.annotation.Resource;
|
|
|
-
|
|
|
-import org.apache.commons.codec.digest.DigestUtils;
|
|
|
-import org.springframework.beans.BeanUtils;
|
|
|
-import org.springframework.cache.annotation.CacheEvict;
|
|
|
-import org.springframework.cache.annotation.CachePut;
|
|
|
-import org.springframework.cache.annotation.Cacheable;
|
|
|
-import org.springframework.stereotype.Service;
|
|
|
-import org.springframework.transaction.annotation.Transactional;
|
|
|
-import org.springframework.web.multipart.MultipartFile;
|
|
|
-
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
import com.qmth.themis.business.bean.backend.OpenExamBean;
|
|
|
-import com.qmth.themis.business.bean.exam.AnswerSubmitBean;
|
|
|
-import com.qmth.themis.business.bean.exam.AudioLeftPlayCountSubmitBean;
|
|
|
-import com.qmth.themis.business.bean.exam.ExamFileUploadBean;
|
|
|
-import com.qmth.themis.business.bean.exam.ExamFinishBean;
|
|
|
-import com.qmth.themis.business.bean.exam.ExamPrepareBean;
|
|
|
-import com.qmth.themis.business.bean.exam.ExamResultBean;
|
|
|
-import com.qmth.themis.business.bean.exam.ExamResumeBean;
|
|
|
-import com.qmth.themis.business.bean.exam.ExamStartBean;
|
|
|
-import com.qmth.themis.business.bean.exam.StudentPaperStructBean;
|
|
|
+import com.qmth.themis.business.bean.exam.*;
|
|
|
import com.qmth.themis.business.cache.ExamActivityRecordCacheUtil;
|
|
|
import com.qmth.themis.business.cache.ExamRecordCacheUtil;
|
|
|
import com.qmth.themis.business.cache.ExamingDataCacheUtil;
|
|
|
import com.qmth.themis.business.cache.RedisKeyHelper;
|
|
|
-import com.qmth.themis.business.cache.bean.ExamActivityCacheBean;
|
|
|
-import com.qmth.themis.business.cache.bean.ExamActivityRecordCacheBean;
|
|
|
-import com.qmth.themis.business.cache.bean.ExamCacheBean;
|
|
|
-import com.qmth.themis.business.cache.bean.ExamCourseCacheBean;
|
|
|
-import com.qmth.themis.business.cache.bean.ExamPaperCacheBean;
|
|
|
-import com.qmth.themis.business.cache.bean.ExamStudentAnswerCacheBean;
|
|
|
-import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
|
|
|
-import com.qmth.themis.business.cache.bean.ExamStudentPaperStructCacheBean;
|
|
|
-import com.qmth.themis.business.cache.bean.ObjectiveAnswerCacheBean;
|
|
|
+import com.qmth.themis.business.cache.bean.*;
|
|
|
import com.qmth.themis.business.config.SystemConfig;
|
|
|
import com.qmth.themis.business.constant.SpringContextHolder;
|
|
|
import com.qmth.themis.business.constant.SystemConstant;
|
|
@@ -75,40 +24,33 @@ import com.qmth.themis.business.entity.TBSession;
|
|
|
import com.qmth.themis.business.entity.TBTaskHistory;
|
|
|
import com.qmth.themis.business.entity.TEExam;
|
|
|
import com.qmth.themis.business.entity.TOeExamRecord;
|
|
|
-import com.qmth.themis.business.enums.EntryAuthenticationPolicyEnum;
|
|
|
-import com.qmth.themis.business.enums.ExamModeEnum;
|
|
|
-import com.qmth.themis.business.enums.ExamRecordFieldEnum;
|
|
|
-import com.qmth.themis.business.enums.ExamRecordStatusEnum;
|
|
|
-import com.qmth.themis.business.enums.FinishExamResultEnum;
|
|
|
-import com.qmth.themis.business.enums.FinishTypeEnum;
|
|
|
-import com.qmth.themis.business.enums.HardwareTestEnum;
|
|
|
-import com.qmth.themis.business.enums.InvigilateMonitorStatusEnum;
|
|
|
-import com.qmth.themis.business.enums.InvigilateVerifyEnum;
|
|
|
-import com.qmth.themis.business.enums.MonitorStatusSourceEnum;
|
|
|
-import com.qmth.themis.business.enums.MonitorVideoSourceEnum;
|
|
|
-import com.qmth.themis.business.enums.MqTagEnum;
|
|
|
-import com.qmth.themis.business.enums.MqTopicEnum;
|
|
|
-import com.qmth.themis.business.enums.ReviewResultEnum;
|
|
|
-import com.qmth.themis.business.enums.ScoreStatusEnum;
|
|
|
-import com.qmth.themis.business.enums.SystemOperationEnum;
|
|
|
-import com.qmth.themis.business.enums.TaskStatusEnum;
|
|
|
-import com.qmth.themis.business.enums.WebsocketStatusEnum;
|
|
|
-import com.qmth.themis.business.service.MqDtoService;
|
|
|
-import com.qmth.themis.business.service.TBTaskHistoryService;
|
|
|
-import com.qmth.themis.business.service.TEExamActivityService;
|
|
|
-import com.qmth.themis.business.service.TEExamCourseService;
|
|
|
-import com.qmth.themis.business.service.TEExamPaperService;
|
|
|
-import com.qmth.themis.business.service.TEExamService;
|
|
|
-import com.qmth.themis.business.service.TEExamStudentService;
|
|
|
-import com.qmth.themis.business.service.TOeExamRecordService;
|
|
|
-import com.qmth.themis.business.util.JacksonUtil;
|
|
|
-import com.qmth.themis.business.util.OssUtil;
|
|
|
-import com.qmth.themis.business.util.RedisUtil;
|
|
|
-import com.qmth.themis.business.util.ServletUtil;
|
|
|
-import com.qmth.themis.business.util.TencentYunUtil;
|
|
|
+import com.qmth.themis.business.enums.*;
|
|
|
+import com.qmth.themis.business.service.*;
|
|
|
+import com.qmth.themis.business.util.*;
|
|
|
import com.qmth.themis.common.enums.ExceptionResultEnum;
|
|
|
import com.qmth.themis.common.exception.BusinessException;
|
|
|
import com.qmth.themis.common.util.IpUtil;
|
|
|
+import org.apache.commons.codec.digest.DigestUtils;
|
|
|
+import org.springframework.beans.BeanUtils;
|
|
|
+import org.springframework.cache.annotation.CacheEvict;
|
|
|
+import org.springframework.cache.annotation.CachePut;
|
|
|
+import org.springframework.cache.annotation.Cacheable;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+import org.springframework.web.multipart.MultipartFile;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import java.io.File;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.ZoneOffset;
|
|
|
+import java.util.*;
|
|
|
+import java.util.regex.Matcher;
|
|
|
+import java.util.regex.Pattern;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
|
* @Description: 考试批次 服务实现类
|
|
@@ -217,10 +159,7 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
|
|
|
}
|
|
|
if (Objects.nonNull(v.getMonitorVideoSourceStr()) && !Objects.equals(v.getMonitorVideoSourceStr().toString().trim().replaceAll(" ", ""), "")) {
|
|
|
v.setMonitorVideoSource(Arrays.asList(v.getMonitorVideoSourceStr().trim().toUpperCase().replaceAll(" ", "").split(",")));
|
|
|
- //加入monitorAudioEnable逻辑
|
|
|
- if (v.getMonitorVideoSource().size() == 4 || (v.getMonitorVideoSourceStr().toUpperCase().contains(MonitorVideoSourceEnum.CLIENT_SCREEN.name()) || v.getMonitorVideoSourceStr().toUpperCase().contains(MonitorVideoSourceEnum.CLIENT_CAMERA.name()))) {
|
|
|
- v.setMonitorAudioEnable(true);
|
|
|
- }
|
|
|
+ v.setMonitorAudioEnable(examCache.getMonitorAudioEnable());
|
|
|
//加入hardwareTest逻辑
|
|
|
if (v.getMonitorVideoSourceStr().toUpperCase().contains(MonitorVideoSourceEnum.CLIENT_CAMERA.name()) || (Objects.nonNull(v.getEntryAuthenticationPolicy()) && (Objects.equals(v.getEntryAuthenticationPolicy(), EntryAuthenticationPolicyEnum.LIVENESS_VERIFY.name()) || Objects.equals(v.getEntryAuthenticationPolicy(), EntryAuthenticationPolicyEnum.FACE_VERIFY_FORCE.name()))) || (Objects.nonNull(v.getCameraPhotoUpload()) && v.getCameraPhotoUpload() == 1)) {
|
|
|
List<String> hardwareTest = v.getHardwareTest();
|
|
@@ -365,7 +304,7 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
|
|
|
// }
|
|
|
|
|
|
Long recordId = toeExamRecordService.saveByPrepare(es.getExamId(), es.getExamActivityId(), examStudentId,
|
|
|
- paperId, es.getAlreadyExamCount()+1);
|
|
|
+ paperId, es.getAlreadyExamCount() + 1);
|
|
|
|
|
|
es.setCurrentRecordId(recordId);
|
|
|
|
|
@@ -490,7 +429,6 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
Long paperId = ExamRecordCacheUtil.getPaperId(recordId);
|
|
|
ExamPaperCacheBean ep = teExamPaperService.getExamPaperCacheBean(paperId);
|
|
|
if (ep == null) {
|
|
@@ -501,21 +439,24 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
|
|
|
if (Objects.nonNull(websocketStatusEnum) && Objects.equals(WebsocketStatusEnum.OFF_LINE, websocketStatusEnum)) {
|
|
|
throw new BusinessException(ExceptionResultEnum.CLIENT_NET_OFFLINE);
|
|
|
}
|
|
|
- MonitorStatusSourceEnum clientCameraStatus = ExamRecordCacheUtil.getMonitorStatus(recordId, MonitorVideoSourceEnum.CLIENT_CAMERA);
|
|
|
- if (Objects.nonNull(clientCameraStatus) && Objects.equals(MonitorStatusSourceEnum.STOP, clientCameraStatus)) {
|
|
|
- throw new BusinessException(ExceptionResultEnum.CLIENT_CAMERA_OFFLINE);
|
|
|
- }
|
|
|
- MonitorStatusSourceEnum clientScreenStatus = ExamRecordCacheUtil.getMonitorStatus(recordId, MonitorVideoSourceEnum.CLIENT_SCREEN);
|
|
|
- if (Objects.nonNull(clientScreenStatus) && Objects.equals(MonitorStatusSourceEnum.STOP, clientScreenStatus)) {
|
|
|
- throw new BusinessException(ExceptionResultEnum.CLIENT_SCREEN_OFFLINE);
|
|
|
- }
|
|
|
- MonitorStatusSourceEnum mobileFirstStatus = ExamRecordCacheUtil.getMonitorStatus(recordId, MonitorVideoSourceEnum.MOBILE_FIRST);
|
|
|
- if (Objects.nonNull(mobileFirstStatus) && Objects.equals(MonitorStatusSourceEnum.STOP, mobileFirstStatus)) {
|
|
|
- throw new BusinessException(ExceptionResultEnum.MOBILE_FIRST_OFFLINE);
|
|
|
- }
|
|
|
- MonitorStatusSourceEnum mobileSecondStatus = ExamRecordCacheUtil.getMonitorStatus(recordId, MonitorVideoSourceEnum.MOBILE_SECOND);
|
|
|
- if (Objects.nonNull(mobileSecondStatus) && Objects.equals(MonitorStatusSourceEnum.STOP, mobileSecondStatus)) {
|
|
|
- throw new BusinessException(ExceptionResultEnum.MOBILE_SECOND_OFFLINE);
|
|
|
+
|
|
|
+ if (Objects.nonNull(exam.getMonitorVideoSource())) {
|
|
|
+ String[] strs = exam.getMonitorVideoSource().split(",");
|
|
|
+ for (int i = 0; i < strs.length; i++) {
|
|
|
+ MonitorStatusSourceEnum clientCameraStatus = ExamRecordCacheUtil.getMonitorStatus(recordId, MonitorVideoSourceEnum.valueOf(strs[i]));
|
|
|
+ if (Objects.isNull(clientCameraStatus) || Objects.equals(MonitorStatusSourceEnum.STOP, clientCameraStatus)) {
|
|
|
+ switch (strs[i]) {
|
|
|
+ case "CLIENT_CAMERA":
|
|
|
+ throw new BusinessException(ExceptionResultEnum.CLIENT_CAMERA_OFFLINE);
|
|
|
+ case "CLIENT_SCREEN":
|
|
|
+ throw new BusinessException(ExceptionResultEnum.CLIENT_SCREEN_OFFLINE);
|
|
|
+ case "MOBILE_FIRST":
|
|
|
+ throw new BusinessException(ExceptionResultEnum.MOBILE_FIRST_OFFLINE);
|
|
|
+ default:
|
|
|
+ throw new BusinessException(ExceptionResultEnum.MOBILE_SECOND_OFFLINE);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(examStudentId);
|
|
@@ -541,11 +482,11 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
|
|
|
ret.setPaperDecryptVector(ep.getDecryptVector());
|
|
|
|
|
|
if (!ExamRecordStatusEnum.RESUME_PREPARE.equals(sta)) {//非断点进入的
|
|
|
- // 写入次数
|
|
|
- es.setAlreadyExamCount(es.getAlreadyExamCount()+1);
|
|
|
- // 更新考生缓存
|
|
|
- redisUtil.set(RedisKeyHelper.examStudentCacheKey(examStudentId), es);
|
|
|
- updateExamStudent(examStudentId, es.getAlreadyExamCount(), recordId);
|
|
|
+ // 写入次数
|
|
|
+ es.setAlreadyExamCount(es.getAlreadyExamCount() + 1);
|
|
|
+ // 更新考生缓存
|
|
|
+ redisUtil.set(RedisKeyHelper.examStudentCacheKey(examStudentId), es);
|
|
|
+ updateExamStudent(examStudentId, es.getAlreadyExamCount(), recordId);
|
|
|
}
|
|
|
// 更新考试记录缓存
|
|
|
Long firstStartTime = System.currentTimeMillis();
|
|
@@ -558,7 +499,7 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
|
|
|
toeExamRecordService.dataUpdatesMq(recordId, columns, values);
|
|
|
//更新场次-考试记录缓存
|
|
|
ExamActivityRecordCacheUtil.setExamRecordStatus(activityId, recordId, new ExamActivityRecordCacheBean(ExamRecordCacheUtil.getExamStudentId(recordId), ExamRecordCacheUtil.getStatus(recordId)));
|
|
|
-
|
|
|
+
|
|
|
//非强制交卷,换算最终交卷时间并生成一次性延时任务
|
|
|
if (Objects.nonNull(exam.getForceFinish()) && exam.getForceFinish().intValue() == 0) {
|
|
|
Long date = ExamRecordCacheUtil.getExamFinalFinishTime(recordId);
|
|
@@ -750,7 +691,6 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
|
|
|
@Override
|
|
|
public ExamFileUploadBean fileUpload(Long studentId, Long recordId, MultipartFile file, String suffix, String
|
|
|
md5) {
|
|
|
-
|
|
|
// 校验当前登录用户和参数一致性
|
|
|
if (ExamRecordCacheUtil.getId(recordId) == null) {
|
|
|
throw new BusinessException(ExceptionResultEnum.NOT_FOUND_EXAM_RECORD);
|
|
@@ -778,7 +718,7 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
|
|
|
}
|
|
|
in = file.getInputStream();
|
|
|
OssUtil.ossUploadStream(systemConfig.getOssEnv(3), filePath, in);
|
|
|
- String url = systemConfig.getProperty("aliyun.oss.url") + File.separator + filePath;
|
|
|
+ String url = systemConfig.getProperty("aliyun.oss.privateUrl") + File.separator + filePath;
|
|
|
ExamFileUploadBean ret = new ExamFileUploadBean();
|
|
|
ret.setUrl(url);
|
|
|
ret.setUploadTime(System.currentTimeMillis());
|
|
@@ -1252,24 +1192,24 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
|
|
|
int timeOutSecond = 60 * 60 * 5;
|
|
|
String lockKey = SystemConstant.REDIS_LOCK_CALCULATE_SCORE_PREFIX + examId;
|
|
|
String multLockKey = SystemConstant.REDIS_LOCK_CALCULATE_SCORE_PAPER_IMPORT_PREFIX + examId;
|
|
|
-
|
|
|
+
|
|
|
TBTaskHistory task = null;
|
|
|
Long recordId = null;
|
|
|
try {
|
|
|
- Boolean lock = redisUtil.lock(lockKey, timeOutSecond);
|
|
|
+ Boolean lock = redisUtil.lock(lockKey, timeOutSecond);
|
|
|
if (!lock) {
|
|
|
- throw new BusinessException("该考试批次有正在进行的重新算分");
|
|
|
+ throw new BusinessException("该考试批次有正在进行的重新算分");
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
//重新算分和试卷导入互斥锁
|
|
|
- Boolean multLock = redisUtil.lock(multLockKey, timeOutSecond);
|
|
|
- if (!multLock) {
|
|
|
- throw new BusinessException("该考试批次有正在进行的试卷导入");
|
|
|
- }
|
|
|
-
|
|
|
- TEExamService examService = SpringContextHolder.getBean(TEExamService.class);
|
|
|
- teExamMapper.updateScoreStatus(ScoreStatusEnum.CALCULATING, examId);
|
|
|
- examService.updateExamCacheBean(examId);
|
|
|
+ Boolean multLock = redisUtil.lock(multLockKey, timeOutSecond);
|
|
|
+ if (!multLock) {
|
|
|
+ throw new BusinessException("该考试批次有正在进行的试卷导入");
|
|
|
+ }
|
|
|
+
|
|
|
+ TEExamService examService = SpringContextHolder.getBean(TEExamService.class);
|
|
|
+ teExamMapper.updateScoreStatus(ScoreStatusEnum.CALCULATING, examId);
|
|
|
+ examService.updateExamCacheBean(examId);
|
|
|
task = tbTaskHistoryService.getById(taskId);
|
|
|
task.setStatus(TaskStatusEnum.RUNNING);
|
|
|
tbTaskHistoryService.saveOrUpdate(task);
|
|
@@ -1306,7 +1246,7 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
|
|
|
task.setStatus(TaskStatusEnum.FINISH);
|
|
|
task.setFinishTime(System.currentTimeMillis());
|
|
|
JSONObject json = new JSONObject();
|
|
|
- String reportFilePath="file/"+sdf.format(new Date()) + "/" + uuid() + SystemConstant.TXT_PREFIX;
|
|
|
+ String reportFilePath = "file/" + sdf.format(new Date()) + "/" + uuid() + SystemConstant.TXT_PREFIX;
|
|
|
json.put("path", reportFilePath);
|
|
|
json.put("type", SystemConstant.OSS);
|
|
|
OssUtil.ossUploadContent(systemConfig.getOssEnv(3), reportFilePath, e.getMessage());
|
|
@@ -1340,15 +1280,15 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
|
|
|
public void updateInvigilateMonitorStatus(InvigilateMonitorStatusEnum monitorStatus, Long examId) {
|
|
|
teExamMapper.updateInvigilateMonitorStatus(monitorStatus, examId);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
@Transactional
|
|
|
@Override
|
|
|
public void updateScoreStatus(ScoreStatusEnum scoreStatus, Long examId) {
|
|
|
teExamMapper.updateScoreStatus(scoreStatus, examId);
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public IPage<OpenExamBean> examQueryForOpen(Page<OpenExamBean> ipage, Long examId, String examCode) {
|
|
|
- return teExamMapper.examQueryForOpen(ipage, examId, examCode);
|
|
|
- }
|
|
|
+ @Override
|
|
|
+ public IPage<OpenExamBean> examQueryForOpen(Page<OpenExamBean> ipage, Long examId, String examCode) {
|
|
|
+ return teExamMapper.examQueryForOpen(ipage, examId, examCode);
|
|
|
+ }
|
|
|
}
|