|
@@ -0,0 +1,335 @@
|
|
|
+package cn.com.qmth.examcloud.core.oe.admin.service.impl;
|
|
|
+
|
|
|
+import java.io.File;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+import javax.transaction.Transactional;
|
|
|
+
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import cn.com.qmth.examcloud.api.commons.enums.ExamSpecialSettingsType;
|
|
|
+import cn.com.qmth.examcloud.commons.exception.StatusException;
|
|
|
+import cn.com.qmth.examcloud.core.basic.api.bean.CourseBean;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.dao.ExamRecordDataRepo;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.dao.ExamRecordForMarkingRepo;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.dao.ExamStudentRepo;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordDataEntity;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordForMarkingEntity;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamStudentEntity;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamProperties;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamRecordStatus;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamType;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.service.ExamRecordDataService;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.service.ExamRecordForMarkingService;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.service.ExamScoreService;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.service.GainBaseDataService;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.service.OfflineExamService;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.service.bean.OfflineExamCourseInfo;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.service.bean.examrecord.ExamRecordDataBean;
|
|
|
+import cn.com.qmth.examcloud.core.oe.admin.service.others.ExamCacheTransferHelper;
|
|
|
+import cn.com.qmth.examcloud.core.questions.api.ExtractConfigCloudService;
|
|
|
+import cn.com.qmth.examcloud.core.questions.api.request.GetPaperReq;
|
|
|
+import cn.com.qmth.examcloud.core.questions.api.response.GetPaperResp;
|
|
|
+import cn.com.qmth.examcloud.examwork.api.bean.ExamBean;
|
|
|
+import cn.com.qmth.examcloud.support.cache.CacheHelper;
|
|
|
+import cn.com.qmth.examcloud.support.cache.bean.ExamOrgSettingsCacheBean;
|
|
|
+import cn.com.qmth.examcloud.support.cache.bean.ExamPropertyCacheBean;
|
|
|
+import cn.com.qmth.examcloud.support.cache.bean.ExamStudentSettingsCacheBean;
|
|
|
+import cn.com.qmth.examcloud.support.cache.bean.OrgCacheBean;
|
|
|
+import cn.com.qmth.examcloud.support.cache.bean.SysPropertyCacheBean;
|
|
|
+import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
|
|
|
+import main.java.com.UpYun;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @author chenken
|
|
|
+ * @date 2018年9月5日 下午3:24:44
|
|
|
+ * @company QMTH
|
|
|
+ * @description 离线考试服务实现
|
|
|
+ */
|
|
|
+@Service("offlineExamService")
|
|
|
+public class OfflineExamServiceImpl implements OfflineExamService {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ExamStudentRepo examStudentRepo;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ExamRecordDataRepo examRecordDataRepo;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private GainBaseDataService gainBaseDataService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ExtractConfigCloudService extractConfigCloudService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ExamRecordDataService examRecordDataService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ExamScoreService examScoreService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ExamRecordForMarkingService examRecordForMarkingService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ExamRecordForMarkingRepo examRecordForMarkingRepo;
|
|
|
+
|
|
|
+ @Value("${$upyun.site.1.bucketName}")
|
|
|
+ private String bucketName;
|
|
|
+
|
|
|
+ @Value("${$upyun.site.1.userName}")
|
|
|
+ private String userName;
|
|
|
+
|
|
|
+ @Value("${$upyun.site.1.password}")
|
|
|
+ private String password;
|
|
|
+
|
|
|
+ @Value("${app.upyun.uploadUrl}")
|
|
|
+ private String upyunUploadUrl;
|
|
|
+
|
|
|
+ @Value("${$upyun.site.1.domain}")
|
|
|
+ private String upyunFileUrl;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<OfflineExamCourseInfo> getOfflineCourse(Long studentId) {
|
|
|
+ List<ExamStudentEntity> examStudents = examStudentRepo.findByStudentId(studentId);
|
|
|
+ List<OfflineExamCourseInfo> offlineExamCourseInfoList = new ArrayList<OfflineExamCourseInfo>();
|
|
|
+ for (ExamStudentEntity examStudent : examStudents) {
|
|
|
+ ExamBean examBean = ExamCacheTransferHelper.getCachedExam(examStudent.getExamId(),studentId);
|
|
|
+ if (!ExamType.OFFLINE.name().equals(examBean.getExamType())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (!examBean.getEnable() || (examBean.getExamLimit() != null && examBean.getExamLimit())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (new Date().before(examBean.getBeginTime()) || examBean.getEndTime().before(new Date())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ offlineExamCourseInfoList.add(toOfflineExamCourse(examStudent, examBean));
|
|
|
+ }
|
|
|
+ return offlineExamCourseInfoList;
|
|
|
+ }
|
|
|
+
|
|
|
+ private OfflineExamCourseInfo toOfflineExamCourse(ExamStudentEntity examStudent, ExamBean examBean) {
|
|
|
+ OfflineExamCourseInfo offlineExamCourseInfo = new OfflineExamCourseInfo();
|
|
|
+
|
|
|
+ CourseBean courseBean = ExamCacheTransferHelper.getCachedCourse(examStudent.getCourseId());
|
|
|
+ offlineExamCourseInfo.setCourseCode(courseBean.getCode());
|
|
|
+ offlineExamCourseInfo.setCourseLevel(courseBean.getLevel());
|
|
|
+ offlineExamCourseInfo.setCourseName(courseBean.getName());
|
|
|
+ offlineExamCourseInfo.setExamId(examBean.getId());
|
|
|
+ offlineExamCourseInfo.setExamName(examBean.getName());
|
|
|
+ offlineExamCourseInfo.setSpecialtyName(examStudent.getSpecialtyName());
|
|
|
+ offlineExamCourseInfo.setExamStudentId(examStudent.getExamStudentId());
|
|
|
+ offlineExamCourseInfo.setStudentCode(examStudent.getStudentCode());
|
|
|
+ offlineExamCourseInfo.setStudentName(examStudent.getStudentName());
|
|
|
+ offlineExamCourseInfo.setStartTime(examBean.getBeginTime());
|
|
|
+ offlineExamCourseInfo.setEndTime(examBean.getEndTime());
|
|
|
+ Date nowDate = new Date();
|
|
|
+ if (nowDate.getTime() > offlineExamCourseInfo.getStartTime().getTime()
|
|
|
+ && nowDate.getTime() < offlineExamCourseInfo.getEndTime().getTime()) {
|
|
|
+ offlineExamCourseInfo.setIsvalid(true);
|
|
|
+ } else {
|
|
|
+ offlineExamCourseInfo.setIsvalid(false);
|
|
|
+ }
|
|
|
+
|
|
|
+ OrgCacheBean orgBean = gainBaseDataService.getOrgBean(examStudent.getOrgId());
|
|
|
+ offlineExamCourseInfo.setOrgName(orgBean.getName());
|
|
|
+
|
|
|
+ List<ExamRecordDataEntity> examRecords = examRecordDataRepo.findByExamStudentId(examStudent.getExamStudentId());
|
|
|
+ if (examRecords.size() > 0) {
|
|
|
+ ExamRecordDataEntity examRecordDataEntity = examRecords.get(0);
|
|
|
+ offlineExamCourseInfo.setExamRecordDataId(examRecordDataEntity.getId());
|
|
|
+ offlineExamCourseInfo.setStatus(examRecordDataEntity.getExamRecordStatus());
|
|
|
+ offlineExamCourseInfo.setPaperId(examRecordDataEntity.getBasePaperId());
|
|
|
+ if (examRecordDataEntity.getExamRecordStatus() == ExamRecordStatus.EXAM_END) {
|
|
|
+ ExamRecordForMarkingEntity examRecordForMarkingEntity = examRecordForMarkingRepo.findByExamRecordDataId(examRecordDataEntity.getId());
|
|
|
+ offlineExamCourseInfo.setOfflineFileUrl(examRecordForMarkingEntity.getOfflineFileUrl());
|
|
|
+ offlineExamCourseInfo.setFileName(examRecordForMarkingEntity.getOfflineFileName());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return offlineExamCourseInfo;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void startOfflineExam(Long examStudentId) {
|
|
|
+ SysPropertyCacheBean stuClientLoginLimit = CacheHelper.getSysProperty("STU_CLIENT_LOGIN_LIMIT");
|
|
|
+ Boolean stuClientLoginLimitBoolean = false;
|
|
|
+ if (stuClientLoginLimit.getHasValue()) {
|
|
|
+ stuClientLoginLimitBoolean = Boolean.valueOf(stuClientLoginLimit.getValue().toString());
|
|
|
+ }
|
|
|
+ if (stuClientLoginLimitBoolean) {
|
|
|
+ throw new StatusException("1001", "系统维护中... ...");
|
|
|
+ }
|
|
|
+ List<ExamRecordDataEntity> examRecordList = examRecordDataRepo.findByExamStudentId(examStudentId);
|
|
|
+ if (examRecordList != null && examRecordList.size() > 0) {
|
|
|
+ throw new StatusException("1002", "已经存在examStudentId=" + examStudentId + "的离线考试记录");
|
|
|
+ }
|
|
|
+ //获取考生信息
|
|
|
+ ExamStudentEntity examStudentEntity = examStudentRepo.findByExamStudentId(examStudentId);
|
|
|
+ //检查并获取课程信息
|
|
|
+ CourseBean courseBean = checkCourse(examStudentEntity);
|
|
|
+ //检查并获取考试信息
|
|
|
+ ExamBean examBean = checkExam(examStudentEntity);
|
|
|
+ //获取题库试卷结构(由于存在随机抽卷,所以不能缓存 )
|
|
|
+ GetPaperReq getPaperReq = new GetPaperReq();
|
|
|
+ getPaperReq.setExamId(examStudentEntity.getExamId());
|
|
|
+ getPaperReq.setCourseCode(courseBean.getCode());
|
|
|
+ getPaperReq.setGroupCode(examStudentEntity.getPaperType());
|
|
|
+ GetPaperResp getPaperResp = extractConfigCloudService.getPaper(getPaperReq);
|
|
|
+
|
|
|
+ //生成考试记录
|
|
|
+ ExamRecordDataEntity examRecordData = examRecordDataService.createOfflineExamRecordData(examStudentEntity,
|
|
|
+ examBean, courseBean, getPaperResp.getPaperId(),
|
|
|
+ null, getPaperResp.getDefaultPaper().getFullyObjective());
|
|
|
+ //生成分数
|
|
|
+ examScoreService.createExamScoreWithOffline(examRecordData.getId());
|
|
|
+ //更新考生
|
|
|
+ examStudentRepo.updateExamStudentFinished(examStudentId);
|
|
|
+ }
|
|
|
+
|
|
|
+ private CourseBean checkCourse(ExamStudentEntity examStudentEntity) {
|
|
|
+ CourseBean courseBean = ExamCacheTransferHelper.getCachedCourse(examStudentEntity.getCourseId());
|
|
|
+ if (!courseBean.getEnable()) {
|
|
|
+ throw new StatusException("2001", "该课程已被禁用");
|
|
|
+ }
|
|
|
+ return courseBean;
|
|
|
+ }
|
|
|
+
|
|
|
+ private ExamBean checkExam(ExamStudentEntity examStudentEntity) {
|
|
|
+ Long examId = examStudentEntity.getExamId();
|
|
|
+ Long studentId = examStudentEntity.getStudentId();
|
|
|
+ ExamBean examBean = ExamCacheTransferHelper.getCachedExam(examId, studentId);
|
|
|
+
|
|
|
+ //如果启用了了特殊设置,并且无特殊设置时结束考试 配置 设置为true..且实际未设置特殊设置则不允许考试
|
|
|
+ ExamPropertyCacheBean limitedIfNoSpecialSettings = ExamCacheTransferHelper.getDefaultCachedExamProperty(examId,
|
|
|
+ ExamProperties.LIMITED_IF_NO_SPECIAL_SETTINGS.toString());
|
|
|
+ if (examBean.getSpecialSettingsEnabled() &&
|
|
|
+ (limitedIfNoSpecialSettings.getHasValue() && Boolean.valueOf(limitedIfNoSpecialSettings.getValue()))) {
|
|
|
+
|
|
|
+ //学生特殊设置开启未配置,不允许考试
|
|
|
+ if (examBean.getSpecialSettingsType() == ExamSpecialSettingsType.STUDENT_BASED) {
|
|
|
+ ExamStudentSettingsCacheBean specialSettings = CacheHelper.getExamStudentSettings(examId, studentId);
|
|
|
+ if (!specialSettings.getHasValue()) {
|
|
|
+ throw new StatusException("3001", "考试配置未完成,不允许考试");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //机构特殊设置开启未配置,不允许考试
|
|
|
+ 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("3002", "考试配置未完成,不允许考试");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!examBean.getEnable() || (examBean.getExamLimit() != null && examBean.getExamLimit())) {
|
|
|
+ throw new StatusException("3003", "暂无考试资格,请与学校老师联系");
|
|
|
+ }
|
|
|
+ if (new Date().before(examBean.getBeginTime())) {
|
|
|
+ throw new StatusException("3004", "考试未开始");
|
|
|
+ }
|
|
|
+ if (examBean.getEndTime().before(new Date())) {
|
|
|
+ throw new StatusException("3005", "本次考试已结束");
|
|
|
+ }
|
|
|
+ return examBean;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional
|
|
|
+ public void submitPaper(Long examRecordDataId, File tempFile) throws Exception {
|
|
|
+ SysPropertyCacheBean stuClientLoginLimit = CacheHelper.getSysProperty("STU_CLIENT_LOGIN_LIMIT");
|
|
|
+ Boolean stuClientLoginLimitBoolean = false;
|
|
|
+ if (stuClientLoginLimit.getHasValue()) {
|
|
|
+ stuClientLoginLimitBoolean = Boolean.valueOf(stuClientLoginLimit.getValue().toString());
|
|
|
+ }
|
|
|
+ if (stuClientLoginLimitBoolean) {
|
|
|
+ throw new StatusException("4001", "系统维护中... ...");
|
|
|
+ }
|
|
|
+ ExamRecordDataEntity examRecordDataEntity = GlobalHelper.getEntity(examRecordDataRepo, examRecordDataId, ExamRecordDataEntity.class);
|
|
|
+ if (examRecordDataEntity == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ ExamRecordDataBean bean=of(examRecordDataEntity);
|
|
|
+ String fileName = tempFile.getName();
|
|
|
+ String fileSuffix = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()).toLowerCase();
|
|
|
+ //上传文件至又拍云
|
|
|
+ String fileNewName = createOfflineFileName(bean) + "." + fileSuffix;
|
|
|
+
|
|
|
+ ExamRecordDataEntity examRecordData = GlobalHelper.getEntity(examRecordDataRepo, examRecordDataId, ExamRecordDataEntity.class);
|
|
|
+ String upyunFilePath = upyunUploadUrl + examRecordData.getExamId() + "/" + fileNewName;
|
|
|
+ UpYun upyun = new UpYun(bucketName, userName, password);
|
|
|
+ upyun.writeFile(upyunFilePath, tempFile, true);
|
|
|
+ tempFile.delete();
|
|
|
+ //保存 文件信息
|
|
|
+ String fileUrl = upyunFileUrl + upyunFilePath;
|
|
|
+ examRecordForMarkingService.saveOffLineExamRecordForMarking(bean, fileNewName, fileUrl);
|
|
|
+ //更新考试记录状态
|
|
|
+ examRecordDataEntity.setExamRecordStatus(ExamRecordStatus.EXAM_END);
|
|
|
+ examRecordDataEntity.setEndTime(new Date());//交卷(上传)时间
|
|
|
+ examRecordDataRepo.save(examRecordDataEntity);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ private String createOfflineFileName(ExamRecordDataBean examRecordData) {
|
|
|
+ long currentTime = System.currentTimeMillis();
|
|
|
+
|
|
|
+ long orgId = examRecordData.getOrgId();
|
|
|
+ OrgCacheBean orgBean = gainBaseDataService.getOrgBean(orgId);
|
|
|
+ long courseId = examRecordData.getCourseId();
|
|
|
+ CourseBean courseBean = ExamCacheTransferHelper.getCachedCourse(courseId);
|
|
|
+ return orgBean.getCode() + "_" +
|
|
|
+ examRecordData.getStudentCode() + "_" +
|
|
|
+ examRecordData.getStudentName() + "_" +
|
|
|
+ courseBean.getCode() + "_" + currentTime;
|
|
|
+ }
|
|
|
+
|
|
|
+ private ExamRecordDataBean of(ExamRecordDataEntity record) {
|
|
|
+ ExamRecordDataBean info = new ExamRecordDataBean();
|
|
|
+ //封装基础数据
|
|
|
+ info.setId(record.getId());
|
|
|
+ info.setExamId(record.getExamId());
|
|
|
+ info.setExamType(record.getExamType());
|
|
|
+ info.setExamStudentId(record.getExamStudentId());
|
|
|
+ info.setStudentId(record.getStudentId());
|
|
|
+ info.setStudentCode(record.getStudentCode());
|
|
|
+ info.setStudentName(record.getStudentName());
|
|
|
+ info.setIdentityNumber(record.getIdentityNumber());
|
|
|
+ info.setCourseId(record.getCourseId());
|
|
|
+
|
|
|
+ info.setCourseLevel(record.getCourseLevel());
|
|
|
+ info.setOrgId(record.getOrgId());
|
|
|
+
|
|
|
+ info.setRootOrgId(record.getRootOrgId());
|
|
|
+ info.setBasePaperId(record.getBasePaperId());
|
|
|
+ info.setPaperStructId(record.getPaperStructId());
|
|
|
+ info.setInfoCollector(record.getInfoCollector());
|
|
|
+ info.setStartTime(record.getStartTime());
|
|
|
+ info.setEndTime(record.getEndTime());
|
|
|
+ info.setCleanTime(record.getCleanTime());
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ info.setExamRecordStatus(record.getExamRecordStatus());
|
|
|
+ info.setUsedExamTime(record.getUsedExamTime());
|
|
|
+ info.setExamOrder(record.getExamOrder());
|
|
|
+ info.setIsReexamine(record.getIsReexamine());
|
|
|
+ info.setIsContinued(record.getIsContinued());
|
|
|
+ info.setContinuedCount(record.getContinuedCount());
|
|
|
+ info.setFaceSuccessCount(record.getFaceSuccessCount());
|
|
|
+ info.setFaceFailedCount(record.getFaceFailedCount());
|
|
|
+ info.setFaceStrangerCount(record.getFaceStrangerCount());
|
|
|
+ info.setFaceTotalCount(record.getFaceTotalCount());
|
|
|
+ info.setFaceSuccessPercent(record.getFaceSuccessPercent());
|
|
|
+ info.setBaiduFaceLivenessSuccessPercent(record.getBaiduFaceLivenessSuccessPercent());
|
|
|
+ info.setFaceVerifyResult(record.getFaceVerifyResult());
|
|
|
+ info.setFaceLandmarkVal(record.getFaceLandmarkVal());
|
|
|
+ return info;
|
|
|
+ }
|
|
|
+}
|