|
@@ -1,58 +1,35 @@
|
|
|
package com.qmth.themis.business.service.impl;
|
|
|
|
|
|
-import java.io.IOException;
|
|
|
-import java.io.InputStream;
|
|
|
-import java.text.SimpleDateFormat;
|
|
|
-import java.util.ArrayList;
|
|
|
-import java.util.Collections;
|
|
|
-import java.util.Comparator;
|
|
|
-import java.util.Date;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Map;
|
|
|
-import java.util.Objects;
|
|
|
-import java.util.UUID;
|
|
|
-
|
|
|
-import javax.annotation.Resource;
|
|
|
-
|
|
|
-import org.apache.commons.codec.digest.DigestUtils;
|
|
|
-import org.apache.commons.lang3.StringUtils;
|
|
|
-import org.springframework.beans.BeanUtils;
|
|
|
-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.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
-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.*;
|
|
|
import com.qmth.themis.business.cache.ExamRecordCacheUtil;
|
|
|
import com.qmth.themis.business.cache.RedisKeyHelper;
|
|
|
-import com.qmth.themis.business.cache.bean.ExamActivityCacheBean;
|
|
|
-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.*;
|
|
|
import com.qmth.themis.business.config.SystemConfig;
|
|
|
import com.qmth.themis.business.dao.TEExamMapper;
|
|
|
+import com.qmth.themis.business.dto.response.TEExamActivityDto;
|
|
|
+import com.qmth.themis.business.dto.response.TEExamDto;
|
|
|
import com.qmth.themis.business.entity.TEExam;
|
|
|
import com.qmth.themis.business.enums.ExamRecordStatusEnum;
|
|
|
import com.qmth.themis.business.enums.FinishTypeEnum;
|
|
|
-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.service.*;
|
|
|
import com.qmth.themis.business.util.OssUtil;
|
|
|
import com.qmth.themis.business.util.RedisUtil;
|
|
|
import com.qmth.themis.common.exception.BusinessException;
|
|
|
+import org.apache.commons.codec.digest.DigestUtils;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.springframework.beans.BeanUtils;
|
|
|
+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.IOException;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.util.*;
|
|
|
|
|
|
/**
|
|
|
* @Description: 考试批次 服务实现类
|
|
@@ -63,528 +40,527 @@ import com.qmth.themis.common.exception.BusinessException;
|
|
|
*/
|
|
|
@Service
|
|
|
public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> implements TEExamService {
|
|
|
- private SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
|
|
|
- @Resource
|
|
|
- TEExamMapper teExamMapper;
|
|
|
-
|
|
|
- @Resource
|
|
|
- TEExamActivityService teExamActivityService;
|
|
|
-
|
|
|
- @Resource
|
|
|
- TEExamStudentService teExamStudentService;
|
|
|
-
|
|
|
- @Resource
|
|
|
- TEExamCourseService teExamCourseService;
|
|
|
-
|
|
|
- @Resource
|
|
|
- TEExamPaperService teExamPaperService;
|
|
|
-
|
|
|
- @Resource
|
|
|
- TOeExamRecordService toeExamRecordService;
|
|
|
-
|
|
|
- @Resource
|
|
|
- RedisUtil redisUtil;
|
|
|
-
|
|
|
- @Resource
|
|
|
- SystemConfig systemConfig;
|
|
|
-
|
|
|
- /**
|
|
|
- * 查询考试批次
|
|
|
- *
|
|
|
- * @param iPage
|
|
|
- * @param id
|
|
|
- * @param code
|
|
|
- * @param name
|
|
|
- * @param mode
|
|
|
- * @param enable
|
|
|
- * @return
|
|
|
- */
|
|
|
- @Override
|
|
|
- public IPage<TEExam> examQuery(IPage<Map> iPage, Long id, String code, String name, Integer mode, Integer enable) {
|
|
|
- return teExamMapper.examQuery(iPage, id, code, name, mode, enable);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 获取考试待考列表
|
|
|
- *
|
|
|
- * @param studentId
|
|
|
- * @param examId
|
|
|
- * @param orgId
|
|
|
- * @return
|
|
|
- */
|
|
|
- @Override
|
|
|
- public List<Map> getWaitingExam(Long studentId, Long examId, Long orgId) {
|
|
|
- List<Map> list = teExamMapper.getWaitingExam(studentId, examId, orgId);
|
|
|
- if (Objects.nonNull(list) && list.size() > 0) {
|
|
|
- for (int i = 0; i < list.size(); i++) {
|
|
|
- Map m = list.get(i);
|
|
|
- List<Map> teExamActivityList = teExamActivityService.getWaitingExam(studentId,
|
|
|
- Long.parseLong(String.valueOf(m.get("id"))),
|
|
|
- Long.parseLong(String.valueOf(m.get("examActivityId"))));
|
|
|
- m.put("activities", teExamActivityList);
|
|
|
- }
|
|
|
- }
|
|
|
- return list;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 获取考试待考列表
|
|
|
- *
|
|
|
- * @return
|
|
|
- */
|
|
|
- @Override
|
|
|
- public List<Map> getWaitingExamForJob() {
|
|
|
- return teExamMapper.getWaitingExamForJob();
|
|
|
- }
|
|
|
-
|
|
|
- @Transactional
|
|
|
- @Override
|
|
|
- public ExamPrepareBean prepare(Long studentId, Long examStudentId) {
|
|
|
- ExamPrepareBean ret = null;
|
|
|
- ExamStudentCacheBean es = null;
|
|
|
- es = (ExamStudentCacheBean) redisUtil.get(RedisKeyHelper.examStudentCacheKey(examStudentId));
|
|
|
- if (es == null) {
|
|
|
- es = teExamStudentService.getExamStudnetCacheBean(examStudentId);
|
|
|
- }
|
|
|
- if (es == null) {
|
|
|
- throw new BusinessException("未找到考试");
|
|
|
- }
|
|
|
-
|
|
|
- if (studentId.equals(es.getStudentId())) {
|
|
|
- throw new BusinessException("考生Id和当前登录用户不一致");
|
|
|
- }
|
|
|
- if (es.getLeftExamCount() == 0) {
|
|
|
- throw new BusinessException("没有剩余考试次数");
|
|
|
- }
|
|
|
- Long activityId = es.getExamActivityId();
|
|
|
- ExamActivityCacheBean ac = teExamActivityService.getExamActivityCacheBean(activityId);
|
|
|
- if (ac == null) {
|
|
|
- throw new BusinessException("未找到场次");
|
|
|
- }
|
|
|
- Date now = new Date();
|
|
|
- Long start = ac.getStartTime().getTime() - (ac.getPrepareSeconds() * 1000);
|
|
|
- Long end = ac.getStartTime().getTime() + (ac.getOpeningSeconds() * 1000);
|
|
|
- if (now.getTime() < start) {
|
|
|
- throw new BusinessException("没有到允许开考的时间");
|
|
|
- }
|
|
|
- if (now.getTime() > end) {
|
|
|
- throw new BusinessException("允许开考的时间已结束");
|
|
|
- }
|
|
|
- ExamCourseCacheBean ec = teExamCourseService.getExamCourseCacheBean(es.getExamId(), es.getCourseCode());
|
|
|
- if (ec == null) {
|
|
|
- throw new BusinessException("未找到考试科目");
|
|
|
- }
|
|
|
- if (ec.getPaperIds() == null) {
|
|
|
- throw new BusinessException("考试科目未绑定试卷");
|
|
|
- }
|
|
|
- if (ec.getHasAnswer() == null || ec.getHasAnswer().intValue() == 0) {
|
|
|
- throw new BusinessException("考试科目答案未补全");
|
|
|
- }
|
|
|
- // 根据权重选中试卷
|
|
|
- Long paperId = ec.getPaperIds().get(getPaperByWeight(ec.getPaperWeight()));
|
|
|
- ExamPaperCacheBean ep = teExamPaperService.getExamPaperCacheBean(paperId);
|
|
|
- if (ep == null) {
|
|
|
- throw new BusinessException("未找到试卷:" + paperId);
|
|
|
- }
|
|
|
- if (StringUtils.isBlank(ep.getAnswerPath())) {
|
|
|
- throw new BusinessException("试卷答案未上传:" + paperId);
|
|
|
- }
|
|
|
-
|
|
|
- // 写入次数
|
|
|
- Integer serialNumber = es.getCurrentSerialNumber();
|
|
|
- if (serialNumber == null) {
|
|
|
- serialNumber = 0;
|
|
|
- }
|
|
|
- es.setCurrentSerialNumber(serialNumber + 1);
|
|
|
-
|
|
|
- Long recordId = toeExamRecordService.saveByPrepare(es.getExamId(), es.getExamActivityId(), examStudentId,
|
|
|
- paperId, es.getCurrentSerialNumber());
|
|
|
-
|
|
|
- Integer leftExamCount = es.getLeftExamCount();
|
|
|
- es.setLeftExamCount(leftExamCount - 1);
|
|
|
-
|
|
|
- es.setCurrentRecordId(recordId);
|
|
|
-
|
|
|
- ExamPrepareBean prepare = new ExamPrepareBean();
|
|
|
- prepare.setRecordId(recordId);
|
|
|
- prepare.setAudioPlayCount(ep.getAudioPlayCount());
|
|
|
- prepare.setHasAudio((ep.getHasAudio() == null || ep.getHasAudio().intValue() == 0 ? false : true));
|
|
|
- prepare.setObjectiveShuffle(
|
|
|
- (ec.getObjectiveShuffle() == null || ec.getObjectiveShuffle().intValue() == 0 ? false : true));
|
|
|
- prepare.setOptionShuffle(
|
|
|
- (ec.getOptionShuffle() == null || ec.getOptionShuffle().intValue() == 0 ? false : true));
|
|
|
- String paperurl = OssUtil.getUrlForPrivateBucket(systemConfig.getOssEnv(3), ep.getPaperPath());
|
|
|
- String structurl = OssUtil.getUrlForPrivateBucket(systemConfig.getOssEnv(3), ep.getStructPath());
|
|
|
- prepare.setPaperUrl(paperurl);
|
|
|
- prepare.setStructUrl(structurl);
|
|
|
-
|
|
|
- // 更新考生缓存
|
|
|
- redisUtil.set(RedisKeyHelper.examStudentCacheKey(examStudentId), es);
|
|
|
-
|
|
|
- return ret;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 根据设定几率取出一套试卷
|
|
|
- */
|
|
|
- private int getPaperByWeight(List<Double> paperWeight) {
|
|
|
- // 从1开始
|
|
|
- double r = Math.random();
|
|
|
- for (int i = 0; i < paperWeight.size(); i++) {
|
|
|
- r -= paperWeight.get(i);
|
|
|
- if (r <= 0.0d) {
|
|
|
- return i;// 选中
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public ExamStartBean start(Long studentId, Long recordId) {
|
|
|
- ExamStartBean ret = null;
|
|
|
-
|
|
|
- // 校验当前登录用户和参数一致性
|
|
|
- if (ExamRecordCacheUtil.getId(recordId) == null) {
|
|
|
- throw new BusinessException("未找到考试记录");
|
|
|
- }
|
|
|
- Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
|
|
|
- ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
|
|
|
- .get(RedisKeyHelper.examStudentCacheKey(examStudentId));
|
|
|
- if (es == null) {
|
|
|
- throw new BusinessException("未找到考生");
|
|
|
- }
|
|
|
- if (studentId.equals(es.getStudentId())) {
|
|
|
- throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
|
|
|
- }
|
|
|
-
|
|
|
- Long activityId = es.getExamActivityId();
|
|
|
- ExamActivityCacheBean ac = teExamActivityService.getExamActivityCacheBean(activityId);
|
|
|
- if (ac == null) {
|
|
|
- throw new BusinessException("未找到场次");
|
|
|
- }
|
|
|
- Date now = new Date();
|
|
|
- Long start = ac.getStartTime().getTime();
|
|
|
- Long end = ac.getStartTime().getTime() + (ac.getOpeningSeconds() * 1000);
|
|
|
- if (now.getTime() < start) {
|
|
|
- throw new BusinessException("没有到允许开考的时间");
|
|
|
- }
|
|
|
- if (now.getTime() > end) {
|
|
|
- throw new BusinessException("允许开考的时间已结束");
|
|
|
- }
|
|
|
-
|
|
|
- Long paperId = ExamRecordCacheUtil.getPaperId(recordId);
|
|
|
- ExamPaperCacheBean ep = teExamPaperService.getExamPaperCacheBean(paperId);
|
|
|
- if (ep == null) {
|
|
|
- throw new BusinessException("未找到试卷");
|
|
|
- }
|
|
|
-
|
|
|
- ret = new ExamStartBean();
|
|
|
- ret.setPaperDecryptSecret(ep.getDecryptSecret());
|
|
|
- ret.setPaperDecryptVector(ep.getDecryptVector());
|
|
|
-
|
|
|
- // 更新考试记录缓存
|
|
|
- ExamRecordCacheUtil.setFirstStartTime(recordId, new Date());
|
|
|
- ExamRecordCacheUtil.setStatus(recordId, ExamRecordStatusEnum.FIRST_PREPARE);
|
|
|
-
|
|
|
- return ret;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Long studentPaperStruct(Long studentId, Long recordId, String content) {
|
|
|
-
|
|
|
- // 校验当前登录用户和参数一致性
|
|
|
- if (ExamRecordCacheUtil.getId(recordId) == null) {
|
|
|
- throw new BusinessException("未找到考试记录");
|
|
|
- }
|
|
|
- Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
|
|
|
- ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
|
|
|
- .get(RedisKeyHelper.examStudentCacheKey(examStudentId));
|
|
|
- if (es == null) {
|
|
|
- throw new BusinessException("未找到考生");
|
|
|
- }
|
|
|
- if (studentId.equals(es.getStudentId())) {
|
|
|
- throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
|
|
|
- }
|
|
|
-
|
|
|
- ExamStudentPaperStructCacheBean struct = new ExamStudentPaperStructCacheBean();
|
|
|
- struct.setContent(content);
|
|
|
- struct.setTime(new Date().getTime());
|
|
|
- // 更新考生试卷结构
|
|
|
- redisUtil.set(RedisKeyHelper.studentPaperStructKey(recordId), struct);
|
|
|
- return struct.getTime();
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Long answerSubmit(Long studentId, Long recordId, Integer mainNumber, Integer subNumber, Integer subIndex,
|
|
|
- String answer, Long version, Integer durationSeconds) {
|
|
|
-
|
|
|
- // 校验当前登录用户和参数一致性
|
|
|
- if (ExamRecordCacheUtil.getId(recordId) == null) {
|
|
|
- throw new BusinessException("未找到考试记录");
|
|
|
- }
|
|
|
- Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
|
|
|
- ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
|
|
|
- .get(RedisKeyHelper.examStudentCacheKey(examStudentId));
|
|
|
- if (es == null) {
|
|
|
- throw new BusinessException("未找到考生");
|
|
|
- }
|
|
|
- if (studentId.equals(es.getStudentId())) {
|
|
|
- throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
|
|
|
- }
|
|
|
-
|
|
|
- ExamStudentAnswerCacheBean answerCache = (ExamStudentAnswerCacheBean) redisUtil.get(
|
|
|
- RedisKeyHelper.examAnswerKey(recordId),
|
|
|
- RedisKeyHelper.examAnswerHashKey(mainNumber, subNumber, subIndex));
|
|
|
- if (answerCache == null) {
|
|
|
- answerCache = new ExamStudentAnswerCacheBean();
|
|
|
- answerCache.setMainNumber(mainNumber);
|
|
|
- answerCache.setSubNumber(subNumber);
|
|
|
- answerCache.setSubIndex(subIndex);
|
|
|
- answerCache.setContent(answer);
|
|
|
- answerCache.setVersion(version);
|
|
|
- answerCache.setDuration(durationSeconds);
|
|
|
- } else {
|
|
|
- if (version.longValue() < answerCache.getVersion().longValue()) {
|
|
|
- throw new BusinessException("版本时间戳过期");
|
|
|
- }
|
|
|
- answerCache.setContent(answer);
|
|
|
- answerCache.setVersion(version);
|
|
|
- answerCache.setDuration(durationSeconds);
|
|
|
- }
|
|
|
- // 每次提交,清空得分
|
|
|
- answerCache.setScore(null);
|
|
|
- // 更新考生作答
|
|
|
- redisUtil.set(RedisKeyHelper.examAnswerKey(recordId),
|
|
|
- RedisKeyHelper.examAnswerHashKey(mainNumber, subNumber, subIndex), answerCache);
|
|
|
- // 重置考试记录客观题得分
|
|
|
- ExamRecordCacheUtil.setObjectiveScore(recordId, null);
|
|
|
- return version;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Integer audioLeftPlayCountSubmit(Long studentId, Long recordId, String key, Integer count) {
|
|
|
-
|
|
|
- // 校验当前登录用户和参数一致性
|
|
|
- if (ExamRecordCacheUtil.getId(recordId) == null) {
|
|
|
- throw new BusinessException("未找到考试记录");
|
|
|
- }
|
|
|
- Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
|
|
|
- ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
|
|
|
- .get(RedisKeyHelper.examStudentCacheKey(examStudentId));
|
|
|
- if (es == null) {
|
|
|
- throw new BusinessException("未找到考生");
|
|
|
- }
|
|
|
- if (studentId.equals(es.getStudentId())) {
|
|
|
- throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
|
|
|
- }
|
|
|
-
|
|
|
- // 音频剩余播放次数缓存
|
|
|
- redisUtil.set(RedisKeyHelper.audioLeftPlayCountKey(recordId), key, count);
|
|
|
-
|
|
|
- return count;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public ExamFileUploadBean fileUpload(Long studentId, Long recordId, MultipartFile file, String suffix, String md5) {
|
|
|
-
|
|
|
- // 校验当前登录用户和参数一致性
|
|
|
- if (ExamRecordCacheUtil.getId(recordId) == null) {
|
|
|
- throw new BusinessException("未找到考试记录");
|
|
|
- }
|
|
|
- Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
|
|
|
- ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
|
|
|
- .get(RedisKeyHelper.examStudentCacheKey(examStudentId));
|
|
|
- if (es == null) {
|
|
|
- throw new BusinessException("未找到考生");
|
|
|
- }
|
|
|
- if (studentId.equals(es.getStudentId())) {
|
|
|
- throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
|
|
|
- }
|
|
|
-
|
|
|
- String filePath = "upload/" + sdf.format(new Date()) + "/" + uuid() + ".json";
|
|
|
- InputStream in = null;
|
|
|
- try {
|
|
|
- String fileMd5 = DigestUtils.md5Hex(file.getBytes());
|
|
|
- if (!md5.equals(fileMd5)) {
|
|
|
- throw new BusinessException("文件md5不一致");
|
|
|
- }
|
|
|
- in = file.getInputStream();
|
|
|
- OssUtil.ossUploadStream(systemConfig.getOssEnv(3), filePath, in);
|
|
|
- String url = systemConfig.getProperty("aliyun.oss.url") + "/" + filePath;
|
|
|
- ExamFileUploadBean ret = new ExamFileUploadBean();
|
|
|
- ret.setUrl(url);
|
|
|
- ret.setUploadTime(new Date().getTime());
|
|
|
- return ret;
|
|
|
- } catch (IOException e) {
|
|
|
- throw new BusinessException("文件读取出错");
|
|
|
- } finally {
|
|
|
- if (in != null) {
|
|
|
- try {
|
|
|
- in.close();
|
|
|
- } catch (IOException e) {
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private String uuid() {
|
|
|
- return UUID.randomUUID().toString().replaceAll("-", "");
|
|
|
- }
|
|
|
-
|
|
|
- @SuppressWarnings("unchecked")
|
|
|
- @Override
|
|
|
- public ExamResumeBean resume(Long studentId, Long recordId) {
|
|
|
-
|
|
|
- // 校验当前登录用户和参数一致性
|
|
|
- if (ExamRecordCacheUtil.getId(recordId) == null) {
|
|
|
- throw new BusinessException("未找到考试记录");
|
|
|
- }
|
|
|
- Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
|
|
|
- ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
|
|
|
- .get(RedisKeyHelper.examStudentCacheKey(examStudentId));
|
|
|
- if (es == null) {
|
|
|
- throw new BusinessException("未找到考生");
|
|
|
- }
|
|
|
- if (studentId.equals(es.getStudentId())) {
|
|
|
- throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
|
|
|
- }
|
|
|
-
|
|
|
- Long paperId = ExamRecordCacheUtil.getPaperId(recordId);
|
|
|
- ExamPaperCacheBean ep = teExamPaperService.getExamPaperCacheBean(paperId);
|
|
|
- if (ep == null) {
|
|
|
- throw new BusinessException("未找到试卷");
|
|
|
- }
|
|
|
-
|
|
|
- ExamResumeBean ret = new ExamResumeBean();
|
|
|
- ret.setDurationSeconds(ExamRecordCacheUtil.getDurationSeconds(recordId));
|
|
|
- ret.setPaperUrl(OssUtil.getUrlForPrivateBucket(systemConfig.getOssEnv(3), ep.getPaperPath()));
|
|
|
- ret.setStructUrl(OssUtil.getUrlForPrivateBucket(systemConfig.getOssEnv(3), ep.getStructPath()));
|
|
|
- ret.setHasAudio((ep.getHasAudio() != null && ep.getHasAudio().intValue() == 1 ? true : false));
|
|
|
- ret.setAudioPlayCount(ep.getAudioPlayCount());
|
|
|
- // TODO 9527
|
|
|
- ret.setMonitorKey(recordId.toString());
|
|
|
-
|
|
|
- ExamStudentPaperStructCacheBean struct = (ExamStudentPaperStructCacheBean) redisUtil
|
|
|
- .get(RedisKeyHelper.studentPaperStructKey(recordId));
|
|
|
- if (struct != null) {
|
|
|
- ret.setStudentPaperStruct(struct.getContent());
|
|
|
- }
|
|
|
- Map<String, ExamStudentAnswerCacheBean> answers = redisUtil
|
|
|
- .getHashEntries(RedisKeyHelper.examAnswerKey(recordId));
|
|
|
- if (answers != null && answers.size() > 0) {
|
|
|
- ret.setAnswerList(sortAnswers(answers));
|
|
|
- }
|
|
|
- Map<String, Integer> audioLeftPlayCounts = redisUtil
|
|
|
- .getHashEntries(RedisKeyHelper.audioLeftPlayCountKey(recordId));
|
|
|
- if (audioLeftPlayCounts != null && audioLeftPlayCounts.size() > 0) {
|
|
|
- ret.setAudioLeftPlayCount(audioLeftPlayCounts);
|
|
|
- }
|
|
|
- return ret;
|
|
|
- }
|
|
|
-
|
|
|
- // 作答排序
|
|
|
- private List<ExamStudentAnswerCacheBean> sortAnswers(Map<String, ExamStudentAnswerCacheBean> answers) {
|
|
|
- List<ExamStudentAnswerCacheBean> ret = new ArrayList<ExamStudentAnswerCacheBean>(answers.values());
|
|
|
- Collections.sort(ret, new Comparator<ExamStudentAnswerCacheBean>() {
|
|
|
-
|
|
|
- @Override
|
|
|
- public int compare(ExamStudentAnswerCacheBean o1, ExamStudentAnswerCacheBean o2) {
|
|
|
- if (o1.getMainNumber() > o2.getMainNumber()) {
|
|
|
- return 1;
|
|
|
- } else if (o1.getMainNumber() < o2.getMainNumber()) {
|
|
|
- return -1;
|
|
|
- } else {
|
|
|
- if (o1.getSubNumber() > o2.getSubNumber()) {
|
|
|
- return 1;
|
|
|
- } else if (o1.getSubNumber() < o2.getSubNumber()) {
|
|
|
- return -1;
|
|
|
- } else {
|
|
|
- if (o1.getSubIndex() == null || o2.getSubIndex() == null) {
|
|
|
- return 0;
|
|
|
- } else {
|
|
|
- if (o1.getSubIndex() > o2.getSubIndex()) {
|
|
|
- return 1;
|
|
|
- } else if (o1.getSubIndex() < o2.getSubIndex()) {
|
|
|
- return -1;
|
|
|
- } else {
|
|
|
- return 0;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- });
|
|
|
- return ret;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public ExamFinishBean finish(Long studentId, Long recordId, String type, Integer durationSeconds) {
|
|
|
-
|
|
|
- // 校验当前登录用户和参数一致性
|
|
|
- if (ExamRecordCacheUtil.getId(recordId) == null) {
|
|
|
- throw new BusinessException("未找到考试记录");
|
|
|
- }
|
|
|
- Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
|
|
|
- ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
|
|
|
- .get(RedisKeyHelper.examStudentCacheKey(examStudentId));
|
|
|
- if (es == null) {
|
|
|
- throw new BusinessException("未找到考生");
|
|
|
- }
|
|
|
- if (studentId.equals(es.getStudentId())) {
|
|
|
- throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
|
|
|
- }
|
|
|
-
|
|
|
- Date now = new Date();
|
|
|
- ExamFinishBean ret = new ExamFinishBean();
|
|
|
- ret.setFinishTime(now.getTime());
|
|
|
- ret.setObjectiveScore(ExamRecordCacheUtil.getObjectiveScore(recordId));
|
|
|
- // TODO
|
|
|
- ret.setReviewResult("");
|
|
|
- ExamRecordCacheUtil.setFinishTime(recordId, now);
|
|
|
- ExamRecordCacheUtil.setDurationSeconds(recordId, durationSeconds);
|
|
|
- ExamRecordCacheUtil.setFinishType(recordId, FinishTypeEnum.valueOf(type.toLowerCase()));
|
|
|
- ExamRecordCacheUtil.setStatus(recordId, ExamRecordStatusEnum.FINISHED);
|
|
|
- return ret;
|
|
|
- }
|
|
|
-
|
|
|
- @Cacheable(value = "exam", key = "#examId", unless = "#result == null")
|
|
|
- @Override
|
|
|
- public ExamCacheBean getExamCacheBean(Long examId) {
|
|
|
- ExamCacheBean ret = null;
|
|
|
- TEExam exam = getById(examId);
|
|
|
- if (exam == null) {
|
|
|
- return ret;
|
|
|
- }
|
|
|
- ret = new ExamCacheBean();
|
|
|
- BeanUtils.copyProperties(exam, ret);
|
|
|
- return ret;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public ExamResultBean result(Long studentId, Long recordId) {
|
|
|
- // 校验当前登录用户和参数一致性
|
|
|
- if (ExamRecordCacheUtil.getId(recordId) == null) {
|
|
|
- throw new BusinessException("未找到考试记录");
|
|
|
- }
|
|
|
- Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
|
|
|
- ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
|
|
|
- .get(RedisKeyHelper.examStudentCacheKey(examStudentId));
|
|
|
- if (es == null) {
|
|
|
- throw new BusinessException("未找到考生");
|
|
|
- }
|
|
|
- if (studentId.equals(es.getStudentId())) {
|
|
|
- throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
|
|
|
- }
|
|
|
-
|
|
|
- ExamResultBean ret=new ExamResultBean();
|
|
|
- ret.setDurationSeconds(ExamRecordCacheUtil.getDurationSeconds(recordId));
|
|
|
- ret.setFinishTime(ExamRecordCacheUtil.getFinishTime(recordId));
|
|
|
- ret.setFinishType(ExamRecordCacheUtil.getFinishType(recordId));
|
|
|
- ret.setObjectiveScore(ExamRecordCacheUtil.getObjectiveScore(recordId));
|
|
|
- //TODO
|
|
|
- ret.setReviewResult("");
|
|
|
- return ret;
|
|
|
- }
|
|
|
+ private SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
|
|
|
+ @Resource
|
|
|
+ TEExamMapper teExamMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ TEExamActivityService teExamActivityService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ TEExamStudentService teExamStudentService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ TEExamCourseService teExamCourseService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ TEExamPaperService teExamPaperService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ TOeExamRecordService toeExamRecordService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ RedisUtil redisUtil;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ SystemConfig systemConfig;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询考试批次
|
|
|
+ *
|
|
|
+ * @param iPage
|
|
|
+ * @param id
|
|
|
+ * @param code
|
|
|
+ * @param name
|
|
|
+ * @param mode
|
|
|
+ * @param enable
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public IPage<TEExam> examQuery(IPage<Map> iPage, Long id, String code, String name, Integer mode, Integer enable) {
|
|
|
+ return teExamMapper.examQuery(iPage, id, code, name, mode, enable);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取考试待考列表
|
|
|
+ *
|
|
|
+ * @param studentId
|
|
|
+ * @param examId
|
|
|
+ * @param orgId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public List<TEExamDto> getWaitingExam(Long studentId, Long examId, Long orgId) {
|
|
|
+ List<TEExamDto> list = teExamMapper.getWaitingExam(studentId, examId, orgId);
|
|
|
+ if (Objects.nonNull(list) && list.size() > 0) {
|
|
|
+ list.forEach(s -> {
|
|
|
+ List<TEExamActivityDto> teExamActivityList = teExamActivityService.getWaitingExam(studentId, s.getId(), s.getExamActivityId());
|
|
|
+ Map<String, Object> map = new HashMap();
|
|
|
+ map.put("activities", teExamActivityList);
|
|
|
+ s.setActivities(map);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取考试待考列表
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public List<Map> getWaitingExamForJob() {
|
|
|
+ return teExamMapper.getWaitingExamForJob();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional
|
|
|
+ @Override
|
|
|
+ public ExamPrepareBean prepare(Long studentId, Long examStudentId) {
|
|
|
+ ExamPrepareBean ret = null;
|
|
|
+ ExamStudentCacheBean es = null;
|
|
|
+ es = (ExamStudentCacheBean) redisUtil.get(RedisKeyHelper.examStudentCacheKey(examStudentId));
|
|
|
+ if (es == null) {
|
|
|
+ es = teExamStudentService.getExamStudnetCacheBean(examStudentId);
|
|
|
+ }
|
|
|
+ if (es == null) {
|
|
|
+ throw new BusinessException("未找到考试");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (studentId.equals(es.getStudentId())) {
|
|
|
+ throw new BusinessException("考生Id和当前登录用户不一致");
|
|
|
+ }
|
|
|
+ if (es.getLeftExamCount() == 0) {
|
|
|
+ throw new BusinessException("没有剩余考试次数");
|
|
|
+ }
|
|
|
+ Long activityId = es.getExamActivityId();
|
|
|
+ ExamActivityCacheBean ac = teExamActivityService.getExamActivityCacheBean(activityId);
|
|
|
+ if (ac == null) {
|
|
|
+ throw new BusinessException("未找到场次");
|
|
|
+ }
|
|
|
+ Date now = new Date();
|
|
|
+ Long start = ac.getStartTime().getTime() - (ac.getPrepareSeconds() * 1000);
|
|
|
+ Long end = ac.getStartTime().getTime() + (ac.getOpeningSeconds() * 1000);
|
|
|
+ if (now.getTime() < start) {
|
|
|
+ throw new BusinessException("没有到允许开考的时间");
|
|
|
+ }
|
|
|
+ if (now.getTime() > end) {
|
|
|
+ throw new BusinessException("允许开考的时间已结束");
|
|
|
+ }
|
|
|
+ ExamCourseCacheBean ec = teExamCourseService.getExamCourseCacheBean(es.getExamId(), es.getCourseCode());
|
|
|
+ if (ec == null) {
|
|
|
+ throw new BusinessException("未找到考试科目");
|
|
|
+ }
|
|
|
+ if (ec.getPaperIds() == null) {
|
|
|
+ throw new BusinessException("考试科目未绑定试卷");
|
|
|
+ }
|
|
|
+ if (ec.getHasAnswer() == null || ec.getHasAnswer().intValue() == 0) {
|
|
|
+ throw new BusinessException("考试科目答案未补全");
|
|
|
+ }
|
|
|
+ // 根据权重选中试卷
|
|
|
+ Long paperId = ec.getPaperIds().get(getPaperByWeight(ec.getPaperWeight()));
|
|
|
+ ExamPaperCacheBean ep = teExamPaperService.getExamPaperCacheBean(paperId);
|
|
|
+ if (ep == null) {
|
|
|
+ throw new BusinessException("未找到试卷:" + paperId);
|
|
|
+ }
|
|
|
+ if (StringUtils.isBlank(ep.getAnswerPath())) {
|
|
|
+ throw new BusinessException("试卷答案未上传:" + paperId);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 写入次数
|
|
|
+ Integer serialNumber = es.getCurrentSerialNumber();
|
|
|
+ if (serialNumber == null) {
|
|
|
+ serialNumber = 0;
|
|
|
+ }
|
|
|
+ es.setCurrentSerialNumber(serialNumber + 1);
|
|
|
+
|
|
|
+ Long recordId = toeExamRecordService.saveByPrepare(es.getExamId(), es.getExamActivityId(), examStudentId,
|
|
|
+ paperId, es.getCurrentSerialNumber());
|
|
|
+
|
|
|
+ Integer leftExamCount = es.getLeftExamCount();
|
|
|
+ es.setLeftExamCount(leftExamCount - 1);
|
|
|
+
|
|
|
+ es.setCurrentRecordId(recordId);
|
|
|
+
|
|
|
+ ExamPrepareBean prepare = new ExamPrepareBean();
|
|
|
+ prepare.setRecordId(recordId);
|
|
|
+ prepare.setAudioPlayCount(ep.getAudioPlayCount());
|
|
|
+ prepare.setHasAudio((ep.getHasAudio() == null || ep.getHasAudio().intValue() == 0 ? false : true));
|
|
|
+ prepare.setObjectiveShuffle(
|
|
|
+ (ec.getObjectiveShuffle() == null || ec.getObjectiveShuffle().intValue() == 0 ? false : true));
|
|
|
+ prepare.setOptionShuffle(
|
|
|
+ (ec.getOptionShuffle() == null || ec.getOptionShuffle().intValue() == 0 ? false : true));
|
|
|
+ String paperurl = OssUtil.getUrlForPrivateBucket(systemConfig.getOssEnv(3), ep.getPaperPath());
|
|
|
+ String structurl = OssUtil.getUrlForPrivateBucket(systemConfig.getOssEnv(3), ep.getStructPath());
|
|
|
+ prepare.setPaperUrl(paperurl);
|
|
|
+ prepare.setStructUrl(structurl);
|
|
|
+
|
|
|
+ // 更新考生缓存
|
|
|
+ redisUtil.set(RedisKeyHelper.examStudentCacheKey(examStudentId), es);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据设定几率取出一套试卷
|
|
|
+ */
|
|
|
+ private int getPaperByWeight(List<Double> paperWeight) {
|
|
|
+ // 从1开始
|
|
|
+ double r = Math.random();
|
|
|
+ for (int i = 0; i < paperWeight.size(); i++) {
|
|
|
+ r -= paperWeight.get(i);
|
|
|
+ if (r <= 0.0d) {
|
|
|
+ return i;// 选中
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ExamStartBean start(Long studentId, Long recordId) {
|
|
|
+ ExamStartBean ret = null;
|
|
|
+
|
|
|
+ // 校验当前登录用户和参数一致性
|
|
|
+ if (ExamRecordCacheUtil.getId(recordId) == null) {
|
|
|
+ throw new BusinessException("未找到考试记录");
|
|
|
+ }
|
|
|
+ Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
|
|
|
+ ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
|
|
|
+ .get(RedisKeyHelper.examStudentCacheKey(examStudentId));
|
|
|
+ if (es == null) {
|
|
|
+ throw new BusinessException("未找到考生");
|
|
|
+ }
|
|
|
+ if (studentId.equals(es.getStudentId())) {
|
|
|
+ throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
|
|
|
+ }
|
|
|
+
|
|
|
+ Long activityId = es.getExamActivityId();
|
|
|
+ ExamActivityCacheBean ac = teExamActivityService.getExamActivityCacheBean(activityId);
|
|
|
+ if (ac == null) {
|
|
|
+ throw new BusinessException("未找到场次");
|
|
|
+ }
|
|
|
+ Date now = new Date();
|
|
|
+ Long start = ac.getStartTime().getTime();
|
|
|
+ Long end = ac.getStartTime().getTime() + (ac.getOpeningSeconds() * 1000);
|
|
|
+ if (now.getTime() < start) {
|
|
|
+ throw new BusinessException("没有到允许开考的时间");
|
|
|
+ }
|
|
|
+ if (now.getTime() > end) {
|
|
|
+ throw new BusinessException("允许开考的时间已结束");
|
|
|
+ }
|
|
|
+
|
|
|
+ Long paperId = ExamRecordCacheUtil.getPaperId(recordId);
|
|
|
+ ExamPaperCacheBean ep = teExamPaperService.getExamPaperCacheBean(paperId);
|
|
|
+ if (ep == null) {
|
|
|
+ throw new BusinessException("未找到试卷");
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = new ExamStartBean();
|
|
|
+ ret.setPaperDecryptSecret(ep.getDecryptSecret());
|
|
|
+ ret.setPaperDecryptVector(ep.getDecryptVector());
|
|
|
+
|
|
|
+ // 更新考试记录缓存
|
|
|
+ ExamRecordCacheUtil.setFirstStartTime(recordId, new Date());
|
|
|
+ ExamRecordCacheUtil.setStatus(recordId, ExamRecordStatusEnum.FIRST_PREPARE);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Long studentPaperStruct(Long studentId, Long recordId, String content) {
|
|
|
+
|
|
|
+ // 校验当前登录用户和参数一致性
|
|
|
+ if (ExamRecordCacheUtil.getId(recordId) == null) {
|
|
|
+ throw new BusinessException("未找到考试记录");
|
|
|
+ }
|
|
|
+ Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
|
|
|
+ ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
|
|
|
+ .get(RedisKeyHelper.examStudentCacheKey(examStudentId));
|
|
|
+ if (es == null) {
|
|
|
+ throw new BusinessException("未找到考生");
|
|
|
+ }
|
|
|
+ if (studentId.equals(es.getStudentId())) {
|
|
|
+ throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
|
|
|
+ }
|
|
|
+
|
|
|
+ ExamStudentPaperStructCacheBean struct = new ExamStudentPaperStructCacheBean();
|
|
|
+ struct.setContent(content);
|
|
|
+ struct.setTime(System.currentTimeMillis());
|
|
|
+ // 更新考生试卷结构
|
|
|
+ redisUtil.set(RedisKeyHelper.studentPaperStructKey(recordId), struct);
|
|
|
+ return struct.getTime();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Long answerSubmit(Long studentId, Long recordId, Integer mainNumber, Integer subNumber, Integer subIndex,
|
|
|
+ String answer, Long version, Integer durationSeconds) {
|
|
|
+
|
|
|
+ // 校验当前登录用户和参数一致性
|
|
|
+ if (ExamRecordCacheUtil.getId(recordId) == null) {
|
|
|
+ throw new BusinessException("未找到考试记录");
|
|
|
+ }
|
|
|
+ Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
|
|
|
+ ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
|
|
|
+ .get(RedisKeyHelper.examStudentCacheKey(examStudentId));
|
|
|
+ if (es == null) {
|
|
|
+ throw new BusinessException("未找到考生");
|
|
|
+ }
|
|
|
+ if (studentId.equals(es.getStudentId())) {
|
|
|
+ throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
|
|
|
+ }
|
|
|
+
|
|
|
+ ExamStudentAnswerCacheBean answerCache = (ExamStudentAnswerCacheBean) redisUtil.get(
|
|
|
+ RedisKeyHelper.examAnswerKey(recordId),
|
|
|
+ RedisKeyHelper.examAnswerHashKey(mainNumber, subNumber, subIndex));
|
|
|
+ if (answerCache == null) {
|
|
|
+ answerCache = new ExamStudentAnswerCacheBean();
|
|
|
+ answerCache.setMainNumber(mainNumber);
|
|
|
+ answerCache.setSubNumber(subNumber);
|
|
|
+ answerCache.setSubIndex(subIndex);
|
|
|
+ answerCache.setContent(answer);
|
|
|
+ answerCache.setVersion(version);
|
|
|
+ answerCache.setDuration(durationSeconds);
|
|
|
+ } else {
|
|
|
+ if (version.longValue() < answerCache.getVersion().longValue()) {
|
|
|
+ throw new BusinessException("版本时间戳过期");
|
|
|
+ }
|
|
|
+ answerCache.setContent(answer);
|
|
|
+ answerCache.setVersion(version);
|
|
|
+ answerCache.setDuration(durationSeconds);
|
|
|
+ }
|
|
|
+ // 每次提交,清空得分
|
|
|
+ answerCache.setScore(null);
|
|
|
+ // 更新考生作答
|
|
|
+ redisUtil.set(RedisKeyHelper.examAnswerKey(recordId),
|
|
|
+ RedisKeyHelper.examAnswerHashKey(mainNumber, subNumber, subIndex), answerCache);
|
|
|
+ // 重置考试记录客观题得分
|
|
|
+ ExamRecordCacheUtil.setObjectiveScore(recordId, null);
|
|
|
+ return version;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Integer audioLeftPlayCountSubmit(Long studentId, Long recordId, String key, Integer count) {
|
|
|
+
|
|
|
+ // 校验当前登录用户和参数一致性
|
|
|
+ if (ExamRecordCacheUtil.getId(recordId) == null) {
|
|
|
+ throw new BusinessException("未找到考试记录");
|
|
|
+ }
|
|
|
+ Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
|
|
|
+ ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
|
|
|
+ .get(RedisKeyHelper.examStudentCacheKey(examStudentId));
|
|
|
+ if (es == null) {
|
|
|
+ throw new BusinessException("未找到考生");
|
|
|
+ }
|
|
|
+ if (studentId.equals(es.getStudentId())) {
|
|
|
+ throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 音频剩余播放次数缓存
|
|
|
+ redisUtil.set(RedisKeyHelper.audioLeftPlayCountKey(recordId), key, count);
|
|
|
+
|
|
|
+ return count;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ExamFileUploadBean fileUpload(Long studentId, Long recordId, MultipartFile file, String suffix, String md5) {
|
|
|
+
|
|
|
+ // 校验当前登录用户和参数一致性
|
|
|
+ if (ExamRecordCacheUtil.getId(recordId) == null) {
|
|
|
+ throw new BusinessException("未找到考试记录");
|
|
|
+ }
|
|
|
+ Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
|
|
|
+ ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
|
|
|
+ .get(RedisKeyHelper.examStudentCacheKey(examStudentId));
|
|
|
+ if (es == null) {
|
|
|
+ throw new BusinessException("未找到考生");
|
|
|
+ }
|
|
|
+ if (studentId.equals(es.getStudentId())) {
|
|
|
+ throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
|
|
|
+ }
|
|
|
+
|
|
|
+ String filePath = "upload/" + sdf.format(new Date()) + "/" + uuid() + ".json";
|
|
|
+ InputStream in = null;
|
|
|
+ try {
|
|
|
+ String fileMd5 = DigestUtils.md5Hex(file.getBytes());
|
|
|
+ if (!md5.equals(fileMd5)) {
|
|
|
+ throw new BusinessException("文件md5不一致");
|
|
|
+ }
|
|
|
+ in = file.getInputStream();
|
|
|
+ OssUtil.ossUploadStream(systemConfig.getOssEnv(3), filePath, in);
|
|
|
+ String url = systemConfig.getProperty("aliyun.oss.url") + "/" + filePath;
|
|
|
+ ExamFileUploadBean ret = new ExamFileUploadBean();
|
|
|
+ ret.setUrl(url);
|
|
|
+ ret.setUploadTime(System.currentTimeMillis());
|
|
|
+ return ret;
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new BusinessException("文件读取出错");
|
|
|
+ } finally {
|
|
|
+ if (in != null) {
|
|
|
+ try {
|
|
|
+ in.close();
|
|
|
+ } catch (IOException e) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private String uuid() {
|
|
|
+ return UUID.randomUUID().toString().replaceAll("-", "");
|
|
|
+ }
|
|
|
+
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ @Override
|
|
|
+ public ExamResumeBean resume(Long studentId, Long recordId) {
|
|
|
+
|
|
|
+ // 校验当前登录用户和参数一致性
|
|
|
+ if (ExamRecordCacheUtil.getId(recordId) == null) {
|
|
|
+ throw new BusinessException("未找到考试记录");
|
|
|
+ }
|
|
|
+ Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
|
|
|
+ ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
|
|
|
+ .get(RedisKeyHelper.examStudentCacheKey(examStudentId));
|
|
|
+ if (es == null) {
|
|
|
+ throw new BusinessException("未找到考生");
|
|
|
+ }
|
|
|
+ if (studentId.equals(es.getStudentId())) {
|
|
|
+ throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
|
|
|
+ }
|
|
|
+
|
|
|
+ Long paperId = ExamRecordCacheUtil.getPaperId(recordId);
|
|
|
+ ExamPaperCacheBean ep = teExamPaperService.getExamPaperCacheBean(paperId);
|
|
|
+ if (ep == null) {
|
|
|
+ throw new BusinessException("未找到试卷");
|
|
|
+ }
|
|
|
+
|
|
|
+ ExamResumeBean ret = new ExamResumeBean();
|
|
|
+ ret.setDurationSeconds(ExamRecordCacheUtil.getDurationSeconds(recordId));
|
|
|
+ ret.setPaperUrl(OssUtil.getUrlForPrivateBucket(systemConfig.getOssEnv(3), ep.getPaperPath()));
|
|
|
+ ret.setStructUrl(OssUtil.getUrlForPrivateBucket(systemConfig.getOssEnv(3), ep.getStructPath()));
|
|
|
+ ret.setHasAudio((ep.getHasAudio() != null && ep.getHasAudio().intValue() == 1 ? true : false));
|
|
|
+ ret.setAudioPlayCount(ep.getAudioPlayCount());
|
|
|
+ // TODO 9527
|
|
|
+ ret.setMonitorKey(recordId.toString());
|
|
|
+
|
|
|
+ ExamStudentPaperStructCacheBean struct = (ExamStudentPaperStructCacheBean) redisUtil
|
|
|
+ .get(RedisKeyHelper.studentPaperStructKey(recordId));
|
|
|
+ if (struct != null) {
|
|
|
+ ret.setStudentPaperStruct(struct.getContent());
|
|
|
+ }
|
|
|
+ Map<String, ExamStudentAnswerCacheBean> answers = redisUtil
|
|
|
+ .getHashEntries(RedisKeyHelper.examAnswerKey(recordId));
|
|
|
+ if (answers != null && answers.size() > 0) {
|
|
|
+ ret.setAnswerList(sortAnswers(answers));
|
|
|
+ }
|
|
|
+ Map<String, Integer> audioLeftPlayCounts = redisUtil
|
|
|
+ .getHashEntries(RedisKeyHelper.audioLeftPlayCountKey(recordId));
|
|
|
+ if (audioLeftPlayCounts != null && audioLeftPlayCounts.size() > 0) {
|
|
|
+ ret.setAudioLeftPlayCount(audioLeftPlayCounts);
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 作答排序
|
|
|
+ private List<ExamStudentAnswerCacheBean> sortAnswers(Map<String, ExamStudentAnswerCacheBean> answers) {
|
|
|
+ List<ExamStudentAnswerCacheBean> ret = new ArrayList<ExamStudentAnswerCacheBean>(answers.values());
|
|
|
+ Collections.sort(ret, new Comparator<ExamStudentAnswerCacheBean>() {
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int compare(ExamStudentAnswerCacheBean o1, ExamStudentAnswerCacheBean o2) {
|
|
|
+ if (o1.getMainNumber() > o2.getMainNumber()) {
|
|
|
+ return 1;
|
|
|
+ } else if (o1.getMainNumber() < o2.getMainNumber()) {
|
|
|
+ return -1;
|
|
|
+ } else {
|
|
|
+ if (o1.getSubNumber() > o2.getSubNumber()) {
|
|
|
+ return 1;
|
|
|
+ } else if (o1.getSubNumber() < o2.getSubNumber()) {
|
|
|
+ return -1;
|
|
|
+ } else {
|
|
|
+ if (o1.getSubIndex() == null || o2.getSubIndex() == null) {
|
|
|
+ return 0;
|
|
|
+ } else {
|
|
|
+ if (o1.getSubIndex() > o2.getSubIndex()) {
|
|
|
+ return 1;
|
|
|
+ } else if (o1.getSubIndex() < o2.getSubIndex()) {
|
|
|
+ return -1;
|
|
|
+ } else {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ });
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ExamFinishBean finish(Long studentId, Long recordId, String type, Integer durationSeconds) {
|
|
|
+
|
|
|
+ // 校验当前登录用户和参数一致性
|
|
|
+ if (ExamRecordCacheUtil.getId(recordId) == null) {
|
|
|
+ throw new BusinessException("未找到考试记录");
|
|
|
+ }
|
|
|
+ Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
|
|
|
+ ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
|
|
|
+ .get(RedisKeyHelper.examStudentCacheKey(examStudentId));
|
|
|
+ if (es == null) {
|
|
|
+ throw new BusinessException("未找到考生");
|
|
|
+ }
|
|
|
+ if (studentId.equals(es.getStudentId())) {
|
|
|
+ throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
|
|
|
+ }
|
|
|
+
|
|
|
+ Date now = new Date();
|
|
|
+ ExamFinishBean ret = new ExamFinishBean();
|
|
|
+ ret.setFinishTime(now.getTime());
|
|
|
+ ret.setObjectiveScore(ExamRecordCacheUtil.getObjectiveScore(recordId));
|
|
|
+ // TODO
|
|
|
+ ret.setReviewResult("");
|
|
|
+ ExamRecordCacheUtil.setFinishTime(recordId, now);
|
|
|
+ ExamRecordCacheUtil.setDurationSeconds(recordId, durationSeconds);
|
|
|
+ ExamRecordCacheUtil.setFinishType(recordId, FinishTypeEnum.valueOf(type.toLowerCase()));
|
|
|
+ ExamRecordCacheUtil.setStatus(recordId, ExamRecordStatusEnum.FINISHED);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Cacheable(value = "exam", key = "#examId", unless = "#result == null")
|
|
|
+ @Override
|
|
|
+ public ExamCacheBean getExamCacheBean(Long examId) {
|
|
|
+ ExamCacheBean ret = null;
|
|
|
+ TEExam exam = getById(examId);
|
|
|
+ if (exam == null) {
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ ret = new ExamCacheBean();
|
|
|
+ BeanUtils.copyProperties(exam, ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ExamResultBean result(Long studentId, Long recordId) {
|
|
|
+ // 校验当前登录用户和参数一致性
|
|
|
+ if (ExamRecordCacheUtil.getId(recordId) == null) {
|
|
|
+ throw new BusinessException("未找到考试记录");
|
|
|
+ }
|
|
|
+ Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
|
|
|
+ ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
|
|
|
+ .get(RedisKeyHelper.examStudentCacheKey(examStudentId));
|
|
|
+ if (es == null) {
|
|
|
+ throw new BusinessException("未找到考生");
|
|
|
+ }
|
|
|
+ if (studentId.equals(es.getStudentId())) {
|
|
|
+ throw new BusinessException("考试记录的学生Id和当前登录用户不一致");
|
|
|
+ }
|
|
|
+
|
|
|
+ ExamResultBean ret = new ExamResultBean();
|
|
|
+ ret.setDurationSeconds(ExamRecordCacheUtil.getDurationSeconds(recordId));
|
|
|
+ ret.setFinishTime(ExamRecordCacheUtil.getFinishTime(recordId));
|
|
|
+ ret.setFinishType(ExamRecordCacheUtil.getFinishType(recordId));
|
|
|
+ ret.setObjectiveScore(ExamRecordCacheUtil.getObjectiveScore(recordId));
|
|
|
+ //TODO
|
|
|
+ ret.setReviewResult("");
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
}
|