|
@@ -1,5 +1,6 @@
|
|
|
package com.qmth.teachcloud.mark.service.impl;
|
|
|
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
@@ -7,46 +8,64 @@ import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
|
|
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.boot.tools.io.ZipReader;
|
|
|
import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
|
|
|
import com.qmth.teachcloud.common.bean.dto.mark.MarkSettingDto;
|
|
|
import com.qmth.teachcloud.common.bean.params.mark.setting.MarkPaperSettingConfig;
|
|
|
import com.qmth.teachcloud.common.bean.params.mark.setting.MarkPaperSettingList;
|
|
|
import com.qmth.teachcloud.common.bean.params.mark.setting.MarkPaperSettingParam;
|
|
|
+import com.qmth.teachcloud.common.bean.vo.FilePathVo;
|
|
|
+import com.qmth.teachcloud.common.contant.SystemConstant;
|
|
|
import com.qmth.teachcloud.common.entity.BasicCourse;
|
|
|
import com.qmth.teachcloud.common.entity.BasicExam;
|
|
|
import com.qmth.teachcloud.common.entity.MarkQuestion;
|
|
|
import com.qmth.teachcloud.common.entity.SysUser;
|
|
|
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
|
|
|
+import com.qmth.teachcloud.common.enums.ObjectivePolicy;
|
|
|
+import com.qmth.teachcloud.common.enums.UploadFileEnum;
|
|
|
import com.qmth.teachcloud.common.enums.mark.MarkMode;
|
|
|
import com.qmth.teachcloud.common.enums.mark.MarkPaperStatus;
|
|
|
import com.qmth.teachcloud.common.enums.mark.SubjectiveStatus;
|
|
|
import com.qmth.teachcloud.common.service.BasicCourseService;
|
|
|
import com.qmth.teachcloud.common.service.BasicRoleDataPermissionService;
|
|
|
+import com.qmth.teachcloud.common.service.FileUploadService;
|
|
|
import com.qmth.teachcloud.common.service.TeachcloudCommonService;
|
|
|
+import com.qmth.teachcloud.common.util.FileUtil;
|
|
|
import com.qmth.teachcloud.common.util.ServletUtil;
|
|
|
import com.qmth.teachcloud.mark.bean.archivescore.ArchiveScoreQuery;
|
|
|
import com.qmth.teachcloud.mark.bean.archivescore.ArchiveScoreVo;
|
|
|
+import com.qmth.teachcloud.mark.bean.cardJson.CourseCard;
|
|
|
+import com.qmth.teachcloud.mark.bean.cardJson.Description;
|
|
|
+import com.qmth.teachcloud.mark.bean.cardJson.DescriptionCode;
|
|
|
import com.qmth.teachcloud.mark.bean.document.ArchivePaperQuery;
|
|
|
import com.qmth.teachcloud.mark.bean.document.ArchivePaperVo;
|
|
|
+import com.qmth.teachcloud.mark.bean.vo.parseCard.Struct;
|
|
|
import com.qmth.teachcloud.mark.dto.mark.score.CheckScoreListDto;
|
|
|
import com.qmth.teachcloud.mark.dto.mark.score.MarkPaperPackageDto;
|
|
|
import com.qmth.teachcloud.mark.dto.mark.score.SettingDto;
|
|
|
import com.qmth.teachcloud.mark.entity.MarkPaper;
|
|
|
import com.qmth.teachcloud.mark.entity.MarkStudent;
|
|
|
+import com.qmth.teachcloud.mark.entity.ScanAnswerCard;
|
|
|
import com.qmth.teachcloud.mark.entity.ScanPackage;
|
|
|
+import com.qmth.teachcloud.mark.enums.CardSource;
|
|
|
import com.qmth.teachcloud.mark.enums.OmrTaskStatus;
|
|
|
import com.qmth.teachcloud.mark.mapper.MarkPaperMapper;
|
|
|
import com.qmth.teachcloud.mark.service.*;
|
|
|
import com.qmth.teachcloud.mark.utils.Calculator;
|
|
|
+import com.qmth.teachcloud.mark.utils.CardParseUtils;
|
|
|
+import org.apache.commons.codec.digest.DigestUtils;
|
|
|
import org.apache.commons.collections4.CollectionUtils;
|
|
|
+import org.apache.commons.io.FileUtils;
|
|
|
+import org.apache.commons.io.FilenameUtils;
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
+import org.springframework.web.multipart.MultipartFile;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Objects;
|
|
|
-import java.util.StringJoiner;
|
|
|
+import java.io.File;
|
|
|
+import java.util.*;
|
|
|
+import java.util.function.Function;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
@@ -65,6 +84,8 @@ public class MarkPaperServiceImpl extends ServiceImpl<MarkPaperMapper, MarkPaper
|
|
|
@Resource
|
|
|
private ScanOmrTaskService scanOmrTaskService;
|
|
|
@Resource
|
|
|
+ private ScanAnswerCardService scanAnswerCardService;
|
|
|
+ @Resource
|
|
|
private TeachcloudCommonService teachcloudCommonService;
|
|
|
@Resource
|
|
|
private BasicRoleDataPermissionService basicRoleDataPermissionService;
|
|
@@ -78,6 +99,8 @@ public class MarkPaperServiceImpl extends ServiceImpl<MarkPaperMapper, MarkPaper
|
|
|
private MarkDocumentService markDocumentService;
|
|
|
@Resource
|
|
|
private BasicCourseService basicCourseService;
|
|
|
+ @Resource
|
|
|
+ private FileUploadService fileUploadService;
|
|
|
|
|
|
|
|
|
@Override
|
|
@@ -259,7 +282,7 @@ public class MarkPaperServiceImpl extends ServiceImpl<MarkPaperMapper, MarkPaper
|
|
|
this.update(updateWrapper);
|
|
|
}
|
|
|
|
|
|
- if(StringUtils.isNotBlank(stringJoiner.toString())){
|
|
|
+ if (StringUtils.isNotBlank(stringJoiner.toString())) {
|
|
|
throw ExceptionResultEnum.ERROR.exception(stringJoiner.toString());
|
|
|
}
|
|
|
|
|
@@ -484,4 +507,169 @@ public class MarkPaperServiceImpl extends ServiceImpl<MarkPaperMapper, MarkPaper
|
|
|
public List<MarkPaper> findMarkPaperListByExamId(Long examId) {
|
|
|
return this.baseMapper.findMarkPaperListByExamId(examId);
|
|
|
}
|
|
|
+
|
|
|
+ @Transactional
|
|
|
+ @Override
|
|
|
+ public void importCardJsonData(Long examId, MultipartFile file, String md5) {
|
|
|
+ Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
|
|
|
+ File parentDirVar = null;
|
|
|
+ try {
|
|
|
+ String fileName = FilenameUtils.getName(file.getOriginalFilename());
|
|
|
+
|
|
|
+ if (!fileName.endsWith(SystemConstant.ZIP_PREFIX)) {
|
|
|
+ throw ExceptionResultEnum.ERROR.exception("数据包只能上传后缀为[.zip]的文件");
|
|
|
+ }
|
|
|
+
|
|
|
+ String fileMd5 = DigestUtils.md5Hex(file.getBytes());
|
|
|
+ if (!Objects.equals(fileMd5, md5)) {
|
|
|
+ throw ExceptionResultEnum.MD5_EQUALS_FALSE.exception();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 数据包文件上传
|
|
|
+ parentDirVar = SystemConstant.getFileTempDirVar(SystemConstant.ZIP_PREFIX);
|
|
|
+ FileUtils.copyToFile(file.getInputStream(), parentDirVar);
|
|
|
+ ZipReader zipReader = new ZipReader(parentDirVar);
|
|
|
+ String descriptionJson = "description.json";
|
|
|
+
|
|
|
+ // 读取指定文件内容description.json
|
|
|
+ String descriptionContent = SystemConstant.readJson(zipReader.read(descriptionJson));
|
|
|
+ if (StringUtils.isBlank(descriptionContent)) {
|
|
|
+ throw ExceptionResultEnum.ERROR.exception("数据包description.json文件内容为空");
|
|
|
+ }
|
|
|
+ // 解析description.json内容
|
|
|
+ Description description = JSON.parseObject(descriptionContent, Description.class);
|
|
|
+ List<CourseCard> courseCardList = description.getCourseCardList();
|
|
|
+ if (CollectionUtils.isEmpty(courseCardList)) {
|
|
|
+ throw ExceptionResultEnum.ERROR.exception("没有可导入文件");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 相同课程代码,取第一个题卡
|
|
|
+ Map<String, CourseCard> courseCardMap = courseCardList.stream().collect(Collectors.toMap(m -> m.getCourseCode(), Function.identity(), (v1, v2) -> v1));
|
|
|
+ for (Map.Entry<String, CourseCard> entry : courseCardMap.entrySet()) {
|
|
|
+ String courseCode = entry.getKey();
|
|
|
+ CourseCard courseCard = entry.getValue();
|
|
|
+ String jsonFileName = courseCard.getCode() + SystemConstant.ZIP_PREFIX;
|
|
|
+ String jsonContent = SystemConstant.readJson(zipReader.read(jsonFileName));
|
|
|
+
|
|
|
+ // 解析试卷结构,结构为空,跳过导入
|
|
|
+ List<Struct> structList = CardParseUtils.parseCardContent(jsonContent);
|
|
|
+ if (CollectionUtils.isEmpty(structList)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<BasicCourse> basicCourseList = basicCourseService.listBySchoolIdAndCode(schoolId, courseCode);
|
|
|
+ // 课程代码不存在,跳过导入
|
|
|
+ if (CollectionUtils.isEmpty(basicCourseList)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 课程代码一个对应多个开课学院,报错,文档里数据全部不写入
|
|
|
+ else if (basicCourseList.size() > 1) {
|
|
|
+ throw ExceptionResultEnum.ERROR.exception(String.format("课程[%s(%s)]存在多个开课学院", courseCard.getCourseName(), courseCard.getCourseCode()));
|
|
|
+ }
|
|
|
+ BasicCourse basicCourse = basicCourseList.get(0);
|
|
|
+
|
|
|
+ List<MarkPaper> markPaperList = this.listByExamIdAndCourseIdForModel4(examId, basicCourse.getId());
|
|
|
+ if (CollectionUtils.isEmpty(markPaperList)) {
|
|
|
+ continue;
|
|
|
+ } else if (markPaperList.size() > 1) {
|
|
|
+ throw ExceptionResultEnum.ERROR.exception(String.format("课程[%s(%s)]存在多个试卷", courseCard.getCourseName(), courseCard.getCourseCode()));
|
|
|
+ }
|
|
|
+ MarkPaper markPaper = markPaperList.get(0);
|
|
|
+
|
|
|
+ List<ScanAnswerCard> scanAnswerCardList = scanAnswerCardService.listByExamIdAndPaperNumber(examId, markPaper.getPaperNumber());
|
|
|
+ // 已创建自定义卡格式,跳过导入
|
|
|
+ if (scanAnswerCardList.stream().filter(m -> CardSource.CLIENT.equals(m.getSource())).count() > 1) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 电子卡格式且已适配,跳过导入
|
|
|
+ Optional<ScanAnswerCard> optional = scanAnswerCardList.stream().filter(m -> CardSource.WEB.equals(m.getSource())).findFirst();
|
|
|
+ ScanAnswerCard scanAnswerCard = null;
|
|
|
+ if (optional.isPresent()) {
|
|
|
+ scanAnswerCard = optional.get();
|
|
|
+ if (StringUtils.isNotBlank(scanAnswerCard.getAdapteUri())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 主观题已分组,跳过导入
|
|
|
+ List<MarkQuestion> markQuestionList = markQuestionService.listByExamIdAndPaperNumberAndPaperType(examId, markPaper.getPaperNumber(), markPaper.getPaperType(), false);
|
|
|
+ if (CollectionUtils.isNotEmpty(markQuestionList) && markQuestionList.stream().filter(m -> m.getGroupNumber() != null).count() > 1) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 上传电子卡格式
|
|
|
+ String filePathName = SystemConstant.buildPath(true, UploadFileEnum.CARD.getTitle(), String.valueOf(SystemConstant.getDbUuid())) + fileName;
|
|
|
+ FilePathVo filePathVo = fileUploadService.uploadFile(zipReader.read(jsonFileName), UploadFileEnum.CARD, filePathName, DigestUtils.md5Hex(zipReader.read(jsonFileName)));
|
|
|
+ if (filePathVo != null) {
|
|
|
+ // 删除试卷结构
|
|
|
+ markQuestionService.deleteByExamIdAndPaperNumber(examId, markPaper.getPaperNumber());
|
|
|
+ // 保存试卷结构
|
|
|
+ List<MarkQuestion> markQuestions = new ArrayList<>();
|
|
|
+ for (Struct struct : structList) {
|
|
|
+ MarkQuestion markQuestion = new MarkQuestion();
|
|
|
+ markQuestion.setId(SystemConstant.getDbUuid());
|
|
|
+ markQuestion.setExamId(examId);
|
|
|
+ markQuestion.setPaperNumber(markPaper.getPaperNumber());
|
|
|
+ markQuestion.setPaperType(markPaper.getPaperType());
|
|
|
+ markQuestion.setObjective(struct.getObjective());
|
|
|
+ markQuestion.setMainNumber(struct.getMainNumber());
|
|
|
+ markQuestion.setSubNumber(struct.getSubNumber());
|
|
|
+ markQuestion.setMainTitle(struct.getMainTitle());
|
|
|
+ markQuestion.setOptionCount(struct.getOptionCount());
|
|
|
+ markQuestion.setQuestionType(struct.getType());
|
|
|
+ markQuestion.setPaperIndex(struct.getPaperIndex());
|
|
|
+ markQuestion.setPageIndex(struct.getPageIndex());
|
|
|
+ if (StringUtils.isNotBlank(struct.getAnswer())) {
|
|
|
+ // 客观题有标答时,给分策略默认为全对给分
|
|
|
+ markQuestion.setAnswer(struct.getAnswer());
|
|
|
+ markQuestion.setObjectivePolicy(ObjectivePolicy.NONE);
|
|
|
+ }
|
|
|
+ if (struct.getScore() != null) {
|
|
|
+ markQuestion.setTotalScore(struct.getScore());
|
|
|
+ // 间隔分(整数默认1,小数默认0.5)
|
|
|
+ if (!markQuestion.getObjective()) {
|
|
|
+ markQuestion.setIntervalScore(markQuestion.getTotalScore() % 1 > 0 ? 0.5 : 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ markQuestions.add(markQuestion);
|
|
|
+ }
|
|
|
+ markQuestionService.saveBatch(markQuestions);
|
|
|
+ // 删除卡格式
|
|
|
+ scanAnswerCardService.deleteByExamIdAndPaperNumber(examId, markPaper.getPaperNumber());
|
|
|
+ // 保存
|
|
|
+ scanAnswerCard = new ScanAnswerCard();
|
|
|
+ scanAnswerCard.setId(SystemConstant.getDbUuid());
|
|
|
+ scanAnswerCard.setExamId(examId);
|
|
|
+ scanAnswerCard.setPaperNumber(markPaper.getPaperNumber());
|
|
|
+ scanAnswerCard.setCoursePaperId(markPaper.getCoursePaperId());
|
|
|
+ scanAnswerCard.setPaperType(markPaper.getPaperType());
|
|
|
+ scanAnswerCard.setCardId(null);
|
|
|
+ scanAnswerCard.setNumber(scanAnswerCardService.findMaxCardNumberByExamId(examId) + 1);
|
|
|
+ scanAnswerCard.setSource(CardSource.WEB);
|
|
|
+ scanAnswerCard.setUri(JSON.toJSONString(filePathVo));
|
|
|
+ scanAnswerCard.setMd5(md5);
|
|
|
+ scanAnswerCard.setNeedAdapte(true);
|
|
|
+ scanAnswerCard.setSinglePage(false);// 默认false
|
|
|
+ // 题卡张数
|
|
|
+ int paperCount = CardParseUtils.calcPaperCount(jsonContent, true);
|
|
|
+ scanAnswerCard.setPaperCount(paperCount);
|
|
|
+ scanAnswerCardService.save(scanAnswerCard);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw ExceptionResultEnum.ERROR.exception("上传失败:" + e.getMessage());
|
|
|
+ } finally {
|
|
|
+ if (parentDirVar != null) {
|
|
|
+ FileUtil.deleteFile(parentDirVar);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<MarkPaper> listByExamIdAndCourseIdForModel4(Long examId, Long courseId) {
|
|
|
+ QueryWrapper<MarkPaper> queryWrapper = new QueryWrapper<>();
|
|
|
+ queryWrapper.lambda().eq(MarkPaper::getExamId, examId)
|
|
|
+ .eq(MarkPaper::getCourseId, courseId);
|
|
|
+ return this.list(queryWrapper);
|
|
|
+ }
|
|
|
}
|