Преглед изворни кода

评卷管理根据学期,考试,课程自动获取对应答题卡相关试卷结构及卡格式数据

wangliang пре 3 месеци
родитељ
комит
38c1b2861b

+ 19 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/initMarkData/ExamDetailCourseInitMarkDto.java

@@ -1,5 +1,8 @@
 package com.qmth.distributed.print.business.bean.dto.initMarkData;
 
+import com.qmth.distributed.print.business.entity.ExamCardModelFour;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+
 /**
  * 课程同步阅卷数据dto
  */
@@ -17,6 +20,22 @@ public class ExamDetailCourseInitMarkDto {
     private Long createId;
     private String packageCode;
 
+    public ExamDetailCourseInitMarkDto() {
+
+    }
+
+    public ExamDetailCourseInitMarkDto(ExamCardModelFour examCardModelFour, String paperNumber, Long userId) {
+        this.schoolId = examCardModelFour.getSchoolId();
+        this.examId = examCardModelFour.getExamId();
+        this.courseId = examCardModelFour.getCourseId();
+        this.paperNumber = paperNumber;
+        this.coursePaperId = examCardModelFour.getId().toString();
+        this.serialNumber = 1;
+        this.paperType = SystemConstant.DEFAULT_PAPER_TYPE_A;
+        this.openAb = false;
+        this.createId = userId;
+    }
+
     public Long getSchoolId() {
         return schoolId;
     }

+ 1 - 1
teachcloud-task/src/main/java/com/qmth/teachcloud/task/service/PrintFinishService.java → distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/PrintFinishService.java

@@ -1,4 +1,4 @@
-package com.qmth.teachcloud.task.service;
+package com.qmth.distributed.print.business.service;
 
 import com.qmth.distributed.print.business.bean.dto.initMarkData.ExamDetailCourseInitMarkDto;
 import com.qmth.distributed.print.business.entity.BasicCardRule;

+ 38 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamCardModelFourServiceImpl.java

@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qmth.boot.core.concurrent.service.ConcurrentService;
+import com.qmth.distributed.print.business.bean.dto.initMarkData.ExamDetailCourseInitMarkDto;
 import com.qmth.distributed.print.business.bean.params.GenericExamCardModelFourParams;
 import com.qmth.distributed.print.business.entity.BasicCardRule;
 import com.qmth.distributed.print.business.entity.ExamCardModelFour;
@@ -16,6 +17,7 @@ import com.qmth.distributed.print.business.mapper.ExamCardModelFourMapper;
 import com.qmth.distributed.print.business.service.BasicCardRuleService;
 import com.qmth.distributed.print.business.service.ExamCardModelFourService;
 import com.qmth.distributed.print.business.service.ExamCardService;
+import com.qmth.distributed.print.business.service.PrintFinishService;
 import com.qmth.distributed.print.business.util.CreatePdfUtil;
 import com.qmth.distributed.print.business.util.HtmlToJpgUtil;
 import com.qmth.distributed.print.business.util.PdfUtil;
@@ -29,7 +31,12 @@ import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
 import com.qmth.teachcloud.common.enums.PageSizeEnum;
 import com.qmth.teachcloud.common.service.*;
 import com.qmth.teachcloud.common.util.*;
+import com.qmth.teachcloud.mark.entity.MarkPaper;
+import com.qmth.teachcloud.mark.entity.ScanAnswerCard;
+import com.qmth.teachcloud.mark.enums.CardSource;
 import com.qmth.teachcloud.mark.enums.LockType;
+import com.qmth.teachcloud.mark.service.MarkPaperService;
+import com.qmth.teachcloud.mark.service.ScanAnswerCardService;
 import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -82,6 +89,15 @@ public class ExamCardModelFourServiceImpl extends ServiceImpl<ExamCardModelFourM
     @Resource
     SysUserService sysUserService;
 
+    @Resource
+    PrintFinishService printFinishService;
+
+    @Resource
+    MarkPaperService markPaperService;
+
+    @Resource
+    ScanAnswerCardService scanAnswerCardService;
+
     /**
      * 新增/修改模式4题卡
      *
@@ -98,6 +114,7 @@ public class ExamCardModelFourServiceImpl extends ServiceImpl<ExamCardModelFourM
         ExamCardModelFour examCardModelFour = null;
         concurrentService.getReadWriteLock(LockType.CUSTOM_MODEL_FOUR_CARD_SAVE + "-" + schoolId + CardTypeEnum.CUSTOM + params.getTitle()).writeLock().tryLock();
         try {
+
             QueryWrapper<ExamCardModelFour> checkTitleQueryWrapper = new QueryWrapper<>();
             checkTitleQueryWrapper.lambda().eq(ExamCardModelFour::getSchoolId, schoolId)
                     .eq(ExamCardModelFour::getTitle, params.getTitle().trim());
@@ -118,6 +135,11 @@ public class ExamCardModelFourServiceImpl extends ServiceImpl<ExamCardModelFourM
                 }
                 examCardModelFour.updateInfo(sysUser.getId());
             }
+            ScanAnswerCard scanAnswerCardDb = scanAnswerCardService.findByExamAndCardIdAndCardSource(examCardModelFour.getExamId(), examCardModelFour.getId(), CardSource.WEB);
+            if (Objects.nonNull(scanAnswerCardDb)) {
+                throw ExceptionResultEnum.ERROR.exception("题卡已扫描不能重复修改");
+            }
+
             examCardModelFour.updateInformation(params);
             try {
                 // content文件
@@ -148,6 +170,22 @@ public class ExamCardModelFourServiceImpl extends ServiceImpl<ExamCardModelFourM
             if (ExamCardStatusEnum.SUBMIT.equals(params.getStatus())) {
                 // 生成题卡图片
                 createJpgImage(examCardModelFour);
+
+                List<MarkPaper> markPaperList = markPaperService.listByExamIdAndCourseIdForModel4(examCardModelFour.getExamId(), examCardModelFour.getCourseId());
+                if (CollectionUtils.isEmpty(markPaperList)) {
+                    throw ExceptionResultEnum.ERROR.exception("未找到试卷信息");
+                }
+                if (markPaperList.size() > 1) {
+                    throw ExceptionResultEnum.ERROR.exception("找到多条试卷信息");
+                }
+                ExamDetailCourseInitMarkDto dto = new ExamDetailCourseInitMarkDto(examCardModelFour, markPaperList.get(0).getPaperNumber(), sysUser.getId());
+                // 解析卡格式中试卷结构并保存
+                printFinishService.insertMarkQuestion(dto.getExamId(), dto.getCourseId(), dto.getPaperNumber(), examCardModelFour.getContent(), null);
+                // 生成并保存卡格式文件(后缀为.json)
+                ScanAnswerCard scanAnswerCard = printFinishService.insertScanAnswerCard(dto, examCardModelFour.getId().toString(), examCardModelFour.getContent());
+                if (scanAnswerCard != null) {
+                    printFinishService.insertScanAnswerCardQuestion(dto.getExamId(), dto.getPaperNumber(), examCardModelFour.getContent(), scanAnswerCard.getNumber());
+                }
             }
             this.saveOrUpdate(examCardModelFour);
             Map<String, String> map = new HashMap<>();

+ 12 - 16
teachcloud-task/src/main/java/com/qmth/teachcloud/task/service/impl/PrintFinishServiceImpl.java → distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/PrintFinishServiceImpl.java

@@ -1,4 +1,4 @@
-package com.qmth.teachcloud.task.service.impl;
+package com.qmth.distributed.print.business.service.impl;
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
@@ -7,28 +7,22 @@ import com.qmth.distributed.print.business.bean.dto.initMarkData.ExamDetailCours
 import com.qmth.distributed.print.business.bean.dto.initMarkData.InitExamDetailDto;
 import com.qmth.distributed.print.business.entity.*;
 import com.qmth.distributed.print.business.enums.CardTypeEnum;
-import com.qmth.teachcloud.common.enums.ExamNumberStyleEnum;
 import com.qmth.distributed.print.business.service.*;
+import com.qmth.distributed.print.business.util.ExamTaskUtil;
 import com.qmth.teachcloud.common.bean.tiku.paperData.answer.TikuAnswer;
 import com.qmth.teachcloud.common.bean.vo.PaperInfoVo;
 import com.qmth.teachcloud.common.contant.SystemConstant;
 import com.qmth.teachcloud.common.entity.BasicAttachment;
 import com.qmth.teachcloud.common.entity.MarkQuestion;
-import com.qmth.teachcloud.common.enums.CardCreateMethodEnum;
-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.*;
 import com.qmth.teachcloud.common.service.BasicAttachmentService;
-import com.qmth.distributed.print.business.util.ExamTaskUtil;
 import com.qmth.teachcloud.mark.bean.answercard.CardFile;
 import com.qmth.teachcloud.mark.bean.vo.parseCard.Struct;
-import com.qmth.teachcloud.mark.bean.vo.parseCard.pic.SubPictureConfig;
 import com.qmth.teachcloud.mark.entity.*;
 import com.qmth.teachcloud.mark.enums.CardSource;
 import com.qmth.teachcloud.mark.service.*;
 import com.qmth.teachcloud.mark.utils.CardParseUtils;
 import com.qmth.teachcloud.mark.utils.FileStoreUtils;
-import com.qmth.teachcloud.task.service.PrintFinishService;
 import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.io.FileUtils;
@@ -262,13 +256,15 @@ public class PrintFinishServiceImpl implements PrintFinishService {
             if (CollectionUtils.isEmpty(markQuestionList)) {
                 // 解析题卡选择试卷的客观题标答和分数
                 Map<String, TikuAnswer> map = new HashMap<>();
-                for (PaperInfoVo paperInfoVo : paperInfoVoList) {
-                    if (paperInfoVo.getPaperId() == null) {
-                        continue;
-                    }
-                    ExamTaskPaperData examTaskPaperData = examTaskPaperDataService.selectByMultiId(new ExamTaskPaperData(examId, paperNumber, paperInfoVo.getPaperId()));
-                    if (examTaskPaperData != null && examTaskPaperData.getTikuAnswer() != null) {
-                        map.put(paperInfoVo.getName(), examTaskPaperData.getTikuAnswer());
+                if (CollectionUtils.isNotEmpty(paperInfoVoList)) {
+                    for (PaperInfoVo paperInfoVo : paperInfoVoList) {
+                        if (paperInfoVo.getPaperId() == null) {
+                            continue;
+                        }
+                        ExamTaskPaperData examTaskPaperData = examTaskPaperDataService.selectByMultiId(new ExamTaskPaperData(examId, paperNumber, paperInfoVo.getPaperId()));
+                        if (examTaskPaperData != null && examTaskPaperData.getTikuAnswer() != null) {
+                            map.put(paperInfoVo.getName(), examTaskPaperData.getTikuAnswer());
+                        }
                     }
                 }
 

+ 60 - 51
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/ScanAnswerCardService.java

@@ -1,51 +1,60 @@
-package com.qmth.teachcloud.mark.service;
-
-import java.util.List;
-
-import org.springframework.web.multipart.MultipartFile;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.qmth.teachcloud.common.bean.marking.CardJpgResult;
-import com.qmth.teachcloud.mark.bean.UriVo;
-import com.qmth.teachcloud.mark.bean.answercard.AnswerCardSaveDomain;
-import com.qmth.teachcloud.mark.bean.answercard.AnswerCardVo;
-import com.qmth.teachcloud.mark.entity.ScanAnswerCard;
-import com.qmth.teachcloud.mark.enums.CardSource;
-
-/**
- * <p>
- * 题卡卡格式表 服务类
- * </p>
- *
- * @author xf
- * @since 2023-09-22
- */
-public interface ScanAnswerCardService extends IService<ScanAnswerCard> {
-
-    ScanAnswerCard findByExamAndNumber(Long examId, Integer cardNumber);
-
-    List<AnswerCardVo> cardList(Long examId, String coursePaperId);
-
-    ScanAnswerCard cardSave(AnswerCardSaveDomain domain);
-
-    Integer findMaxCardNumberByExamId(Long examId);
-
-    void cardDelete(ScanAnswerCard card);
-
-    UriVo adapteUpload(Long examId, String coursePaperId, Integer cardNumber, String md5, Integer dpi,
-                       MultipartFile file, String remark);
-
-    AnswerCardVo cardGet(Long examId, Integer number);
-
-    ScanAnswerCard getByExamIdAndCoursePaperIdAndSerialNumberAndCardId(Long examId, String coursePaperId, Integer serialNumber, Long cardId);
-
-    List<ScanAnswerCard> listByExamIdAndPaperNumber(Long examId, String paperNumber);
-
-    void deleteByExamIdAndPaperNumber(Long examId, String paperNumber);
-
-    List<CardJpgResult> listPageImage(Long examId, String paperNumber);
-
-    List<ScanAnswerCard> listByExamIdAndCoursePaperIdAndSource(Long examId, String coursePaperId, CardSource source);
-
-    AnswerCardVo cardCopy(Long examId, Integer number,String remark);
-}
+package com.qmth.teachcloud.mark.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.qmth.teachcloud.common.bean.marking.CardJpgResult;
+import com.qmth.teachcloud.mark.bean.UriVo;
+import com.qmth.teachcloud.mark.bean.answercard.AnswerCardSaveDomain;
+import com.qmth.teachcloud.mark.bean.answercard.AnswerCardVo;
+import com.qmth.teachcloud.mark.entity.ScanAnswerCard;
+import com.qmth.teachcloud.mark.enums.CardSource;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 题卡卡格式表 服务类
+ * </p>
+ *
+ * @author xf
+ * @since 2023-09-22
+ */
+public interface ScanAnswerCardService extends IService<ScanAnswerCard> {
+
+    ScanAnswerCard findByExamAndNumber(Long examId, Integer cardNumber);
+
+    List<AnswerCardVo> cardList(Long examId, String coursePaperId);
+
+    ScanAnswerCard cardSave(AnswerCardSaveDomain domain);
+
+    Integer findMaxCardNumberByExamId(Long examId);
+
+    void cardDelete(ScanAnswerCard card);
+
+    UriVo adapteUpload(Long examId, String coursePaperId, Integer cardNumber, String md5, Integer dpi,
+                       MultipartFile file, String remark);
+
+    AnswerCardVo cardGet(Long examId, Integer number);
+
+    ScanAnswerCard getByExamIdAndCoursePaperIdAndSerialNumberAndCardId(Long examId, String coursePaperId, Integer serialNumber, Long cardId);
+
+    List<ScanAnswerCard> listByExamIdAndPaperNumber(Long examId, String paperNumber);
+
+    void deleteByExamIdAndPaperNumber(Long examId, String paperNumber);
+
+    List<CardJpgResult> listPageImage(Long examId, String paperNumber);
+
+    List<ScanAnswerCard> listByExamIdAndCoursePaperIdAndSource(Long examId, String coursePaperId, CardSource source);
+
+    AnswerCardVo cardCopy(Long examId, Integer number, String remark);
+
+    /**
+     * 根据examId和cardId以及cardSource获取扫描题卡
+     *
+     * @param examId
+     * @param cardId
+     * @param source
+     * @return
+     */
+    ScanAnswerCard findByExamAndCardIdAndCardSource(Long examId, Long cardId, CardSource source);
+}

+ 419 - 402
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/ScanAnswerCardServiceImpl.java

@@ -1,402 +1,419 @@
-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.UpdateWrapper;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.qmth.boot.core.exception.ParameterException;
-import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
-import com.qmth.teachcloud.common.bean.marking.CardJpgResult;
-import com.qmth.teachcloud.common.bean.marking.scanAnswerCard.AnswerCard;
-import com.qmth.teachcloud.common.bean.marking.scanAnswerCard.AnswerCardPage;
-import com.qmth.teachcloud.common.bean.vo.FilePathVo;
-import com.qmth.teachcloud.common.contant.SystemConstant;
-import com.qmth.teachcloud.common.entity.SysUser;
-import com.qmth.teachcloud.common.enums.mark.MarkPaperStatus;
-import com.qmth.teachcloud.common.enums.scan.OmrField;
-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.ServletUtil;
-import com.qmth.teachcloud.mark.bean.UriVo;
-import com.qmth.teachcloud.mark.bean.answercard.*;
-import com.qmth.teachcloud.mark.entity.MarkPaper;
-import com.qmth.teachcloud.mark.entity.ScanAnswerCard;
-import com.qmth.teachcloud.mark.entity.ScanAnswerCardQuestion;
-import com.qmth.teachcloud.mark.enums.CardSource;
-import com.qmth.teachcloud.mark.mapper.ScanAnswerCardMapper;
-import com.qmth.teachcloud.mark.service.*;
-import com.qmth.teachcloud.mark.utils.FileStoreUtils;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-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.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * <p>
- * 题卡卡格式表 服务实现类
- * </p>
- *
- * @author xf
- * @since 2023-09-22
- */
-@Service
-public class ScanAnswerCardServiceImpl extends ServiceImpl<ScanAnswerCardMapper, ScanAnswerCard>
-        implements ScanAnswerCardService {
-
-    @Autowired
-    private MarkPaperService markPaperService;
-    @Autowired
-    private ScanPaperService scanPaperService;
-    @Resource
-    private MarkFileService markFileService;
-    @Resource
-    private MarkStudentService markStudentService;
-    @Resource
-    private ScanAnswerCardQuestionService scanAnswerCardQuestionService;
-    @Resource
-    private BasicRoleDataPermissionService basicRoleDataPermissionService;
-    @Resource
-    private TeachcloudCommonService teachcloudCommonService;
-    @Resource
-    private FileStoreUtils fileStoreUtils;
-    @Resource
-    private FileUploadService fileUploadService;
-
-    @Override
-    public ScanAnswerCard findByExamAndNumber(Long examId, Integer cardNumber) {
-        if (examId == null) {
-            throw new ParameterException("examId不能为空");
-        }
-        if (cardNumber == null) {
-            throw new ParameterException("cardNumber不能为空");
-        }
-        QueryWrapper<ScanAnswerCard> wrapper = new QueryWrapper<>();
-        LambdaQueryWrapper<ScanAnswerCard> lw = wrapper.lambda();
-        lw.eq(ScanAnswerCard::getExamId, examId);
-        lw.eq(ScanAnswerCard::getNumber, cardNumber);
-        return baseMapper.selectOne(wrapper);
-    }
-
-    @Override
-    public List<AnswerCardVo> cardList(Long examId, String coursePaperId) {
-        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
-        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(sysUser.getSchoolId(), sysUser.getId(), ServletUtil.getRequest().getServletPath());
-        List<AnswerCardVo> answerCardVos = baseMapper.cardList(examId, coursePaperId, MarkPaperStatus.FORMAL.name(), dpr);
-        for (AnswerCardVo answerCardVo : answerCardVos) {
-            answerCardVo.setCanAdapte(scanPaperService.getCountByExamAndCardNumber(examId, answerCardVo.getNumber()) == 0);
-            answerCardVo.setUri(fileStoreUtils.filePreview(answerCardVo.getUri()));
-            answerCardVo.setAdapteUri(fileStoreUtils.filePreview(answerCardVo.getAdapteUri()));
-        }
-        return answerCardVos;
-    }
-
-    @Transactional
-    @Override
-    public ScanAnswerCard cardSave(AnswerCardSaveDomain domain) {
-        boolean singlePage = false;
-        MarkPaper mp = markPaperService.getByExamIdAndCoursePaperId(domain.getExamId(), domain.getCoursePaperId());
-        if (MarkPaperStatus.FINISH.equals(mp.getStatus())) {
-            throw new ParameterException("阅卷已结束");
-        }
-
-        ScanAnswerCard card;
-        if (domain.getNumber() != null) {
-            card = findByExamAndNumber(domain.getExamId(), domain.getNumber());
-            if (card == null) {
-                throw new ParameterException("未找到卡格式信息");
-            }
-            if (CardSource.WEB.equals(card.getSource())) {
-                throw new ParameterException("电子卡格式,不能修改");
-            }
-            int studentCount = scanPaperService.getCountByExamAndCardNumber(domain.getExamId(), domain.getNumber());
-            if (studentCount > 0) {
-                throw new ParameterException("卡格式已被使用,不能修改");
-            }
-        } else {
-            card = new ScanAnswerCard();
-            card.setId(SystemConstant.getDbUuid());
-            card.setExamId(domain.getExamId());
-            card.setPaperNumber(mp.getPaperNumber());
-            card.setPaperType(mp.getPaperType());
-            card.setCoursePaperId(domain.getCoursePaperId());
-            card.setPaperCount(domain.getPaperCount());
-            card.setSinglePage(singlePage);
-            card.setRemark(domain.getRemark());
-            card.setDpi(domain.getDpi());
-            card.setSource(CardSource.CLIENT);
-            card.setNumber(findMaxCardNumberByExamId(domain.getExamId()) + 1);
-            card.setNeedAdapte(false);
-        }
-
-//        CardFile cardFile;
-//        byte[] fileData;
-//        String sliceConfig;
-//        try {
-//            fileData = domain.getFile().getBytes();
-//            // 解析卡格式文件
-//            cardFile = parseCardFile(fileData);
-//            if (singlePage && domain.getPaperCount() != cardFile.getPages().size()) {
-//                throw new ParameterException("卡格式数量不一致");
-//            }
-//            if (!singlePage && domain.getPaperCount() * 2 != cardFile.getPages().size()) {
-//                throw new ParameterException("卡格式数量不一致");
-//            }
-//            // 提取裁切坐标
-//            sliceConfig = cardFile.getSliceConfig().toString();
-//        } catch (IOException e) {
-//            throw new ParameterException("文件解析失败", e);
-//        }
-        String filePath = null;
-        try {
-            filePath = markFileService.uploadAnswerCard(domain.getFile().getInputStream(), domain.getMd5(), domain.getExamId(), domain.getCoursePaperId(), card.getNumber());
-        } catch (IOException e) {
-            throw new ParameterException("文件上传失败", e);
-        }
-//        card.setSliceConfig(sliceConfig);
-        card.setMd5(domain.getMd5());
-        card.setUri(filePath);
-        card.setAdapteMd5(domain.getMd5());
-        card.setAdapteUri(filePath);
-        this.saveOrUpdate(card);
-
-        saveScanAnswerCardQuestion(domain.getExamId(), domain.getCoursePaperId(), domain.getFile(), card.getNumber());
-        return card;
-    }
-
-    /**
-     * 根据卡格式中的结构,更新客观题试卷结构
-     */
-    private void saveScanAnswerCardQuestion(Long examId, String coursePaperId, MultipartFile file, Integer number) {
-        MarkPaper markPaper = markPaperService.getByExamIdAndCoursePaperId(examId, coursePaperId);
-        CardFile cardFile;
-        byte[] fileData;
-        try {
-            fileData = file.getBytes();
-            // 解析卡格式文件
-            cardFile = parseCardFile(fileData);
-            List<ScanAnswerCardQuestion> scanAnswerCardQuestions = new ArrayList<>();
-            int i = 1;
-            for (CardPageWrapper page : cardFile.getPages()) {
-                for (FillArea fillArea : page.getExchange().getFillArea().stream().filter(m -> OmrField.QUESTION.name().equals(m.getField().toUpperCase())).collect(Collectors.toList())) {
-                    for (FillItem item : fillArea.getItems()) {
-                        ScanAnswerCardQuestion scanAnswerCardQuestion = new ScanAnswerCardQuestion();
-                        scanAnswerCardQuestion.setId(SystemConstant.getDbUuid());
-                        scanAnswerCardQuestion.setExamId(examId);
-                        scanAnswerCardQuestion.setPaperNumber(markPaper.getPaperNumber());
-                        scanAnswerCardQuestion.setCoursePaperId(coursePaperId);
-                        scanAnswerCardQuestion.setCardNumber(number);
-                        scanAnswerCardQuestion.setSerialNumber(markPaper.getSerialNumber());
-                        scanAnswerCardQuestion.setMainNumber(item.getMainNumber());
-                        scanAnswerCardQuestion.setSubNumber(item.getSubNumber());
-                        scanAnswerCardQuestion.setOptionCount(item.getOptions().size());
-                        scanAnswerCardQuestion.setQuestionType(fillArea.isSingle() ? 1 : 2);
-                        scanAnswerCardQuestion.setPaperIndex(i / 2 + 1);
-                        scanAnswerCardQuestion.setPageIndex(i % 2 == 1 ? 1 : 2);
-                        scanAnswerCardQuestion.setCreateTime(System.currentTimeMillis());
-                        scanAnswerCardQuestions.add(scanAnswerCardQuestion);
-                    }
-                }
-                i++;
-            }
-
-            if (CollectionUtils.isNotEmpty(scanAnswerCardQuestions)) {
-                // 删除
-                scanAnswerCardQuestionService.deleteByExamIdAndPaperNumberAndCardNumber(examId, markPaper.getPaperNumber(), number);
-                scanAnswerCardQuestionService.saveBatch(scanAnswerCardQuestions);
-            }
-        } catch (IOException e) {
-            throw new ParameterException("文件解析失败", e);
-        }
-    }
-
-    /**
-     * 解析卡格式文件中的裁切图坐标,用于云阅卷同步
-     *
-     * @param data
-     */
-    private CardFile parseCardFile(byte[] data) throws IOException {
-        ObjectMapper objectMapper = new ObjectMapper();
-        return objectMapper.readValue(data, CardFile.class);
-    }
-
-    @Override
-    public Integer findMaxCardNumberByExamId(Long examId) {
-        int number = 0;
-        QueryWrapper<ScanAnswerCard> queryWrapper = new QueryWrapper<>();
-        queryWrapper.lambda().eq(ScanAnswerCard::getExamId, examId);
-        List<ScanAnswerCard> list = this.list(queryWrapper);
-        for (ScanAnswerCard card : list) {
-            if (number < card.getNumber()) {
-                number = card.getNumber();
-            }
-        }
-        return number;
-    }
-
-    @Transactional
-    @Override
-    public void cardDelete(ScanAnswerCard card) {
-        int studentCount = scanPaperService.getCountByExamAndCardNumber(card.getExamId(), card.getNumber());
-        if (studentCount != 0) {
-            throw new ParameterException("卡格式已被使用,无法删除");
-        }
-        UpdateWrapper<ScanAnswerCard> updateWrapper = new UpdateWrapper<>();
-        updateWrapper.lambda().eq(ScanAnswerCard::getExamId, card.getExamId());
-        updateWrapper.lambda().eq(ScanAnswerCard::getNumber, card.getNumber());
-        int count = this.baseMapper.delete(updateWrapper);
-        if (count == 0) {
-            throw new ParameterException("未找到卡格式");
-        }
-    }
-
-    @Transactional
-    @Override
-    public UriVo adapteUpload(Long examId, String coursePaperId, Integer cardNumber, String md5, Integer dpi,
-                              MultipartFile file, String remark) {
-        MarkPaper mp = markPaperService.getByExamIdAndCoursePaperId(examId, coursePaperId);
-        if (MarkPaperStatus.FINISH.equals(mp.getStatus())) {
-            throw new ParameterException("阅卷已结束");
-        }
-        ScanAnswerCard card = findByExamAndNumber(examId, cardNumber);
-        if (card == null) {
-            throw new ParameterException("未找到卡格式信息");
-        }
-        if (!card.getNeedAdapte() || CardSource.CLIENT.equals(card.getSource())) {
-            throw new ParameterException("卡格式无需适配");
-        }
-        int studentCount = scanPaperService.getCountByExamAndCardNumber(examId, cardNumber);
-        if (studentCount > 0) {
-            throw new ParameterException("卡格式已被使用,无法适配");
-        }
-        String filePath;
-        try {
-            filePath = markFileService.uploadAdapteFile(file.getInputStream(), md5, examId, coursePaperId, cardNumber);
-        } catch (IOException e) {
-            throw new ParameterException("文件上传失败", e);
-        }
-        card.setDpi(dpi);
-        card.setAdapteMd5(md5);
-        card.setAdapteUri(filePath);
-        this.updateById(card);
-        UriVo vo = new UriVo();
-        vo.setUri(teachcloudCommonService.filePreview(filePath));
-        return vo;
-    }
-
-    @Override
-    public AnswerCardVo cardGet(Long examId, Integer number) {
-        List<AnswerCardVo> list = baseMapper.cardGet(examId, number);
-        if (CollectionUtils.isEmpty(list)) {
-            throw new ParameterException("未找到卡格式信息");
-        }
-        AnswerCardVo answerCardVo = list.get(0);
-        answerCardVo.setUri(fileStoreUtils.filePreview(answerCardVo.getUri()));
-        answerCardVo.setAdapteUri(fileStoreUtils.filePreview(answerCardVo.getAdapteUri()));
-        return answerCardVo;
-    }
-
-    @Override
-    public ScanAnswerCard getByExamIdAndCoursePaperIdAndSerialNumberAndCardId(Long examId, String coursePaperId, Integer serialNumber, Long cardId) {
-        QueryWrapper<ScanAnswerCard> queryWrapper = new QueryWrapper<>();
-        queryWrapper.lambda().eq(ScanAnswerCard::getExamId, examId)
-                .eq(ScanAnswerCard::getCoursePaperId, coursePaperId)
-                .eq(ScanAnswerCard::getSerialNumber, serialNumber)
-                .eq(ScanAnswerCard::getCardId, cardId);
-        return this.getOne(queryWrapper);
-    }
-
-    @Override
-    public List<ScanAnswerCard> listByExamIdAndPaperNumber(Long examId, String paperNumber) {
-        QueryWrapper<ScanAnswerCard> queryWrapper = new QueryWrapper<>();
-        queryWrapper.lambda().eq(ScanAnswerCard::getExamId, examId)
-                .eq(ScanAnswerCard::getPaperNumber, paperNumber);
-        return this.list(queryWrapper);
-    }
-
-    @Override
-    public void deleteByExamIdAndPaperNumber(Long examId, String paperNumber) {
-        UpdateWrapper<ScanAnswerCard> updateWrapper = new UpdateWrapper<>();
-        updateWrapper.lambda().eq(ScanAnswerCard::getExamId, examId)
-                .eq(ScanAnswerCard::getPaperNumber, paperNumber);
-        this.remove(updateWrapper);
-    }
-
-    @Override
-    public List<CardJpgResult> listPageImage(Long examId, String paperNumber) {
-        List<CardJpgResult> cardJpgResultList = new ArrayList<>();
-        Integer maxCardNumber = markStudentService.maxCardNumber(examId, paperNumber);
-        if (maxCardNumber != null) {
-            ScanAnswerCard scanAnswerCard = this.findByExamAndNumber(examId, maxCardNumber);
-            if (scanAnswerCard != null && StringUtils.isNotBlank(scanAnswerCard.getAdapteUri())) {
-                FilePathVo filePathVo = JSON.parseObject(scanAnswerCard.getAdapteUri(), FilePathVo.class);
-                if (filePathVo != null && StringUtils.isNotBlank(filePathVo.getPath())) {
-                    String jsonContent = SystemConstant.readContent(fileUploadService.downloadFile(filePathVo.getPath(), filePathVo.getUploadType(), filePathVo.getType()));
-                    if (StringUtils.isNotBlank(jsonContent)) {
-                        AnswerCard answerCard = JSON.parseObject(jsonContent, AnswerCard.class);
-                        if (answerCard != null && CollectionUtils.isNotEmpty(answerCard.getPages())) {
-                            int pageIndex = 1;
-                            for (AnswerCardPage page : answerCard.getPages()) {
-                                if (page.getExchange() != null && StringUtils.isNotBlank(page.getExchange().getPageImage())) {
-                                    String pageImage = page.getExchange().getPageImage().replaceAll("\\r\\n", "");
-                                    cardJpgResultList.add(new CardJpgResult("page" + pageIndex, pageIndex, "data:image/png;base64," + pageImage));
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        return cardJpgResultList;
-    }
-
-    @Override
-    public List<ScanAnswerCard> listByExamIdAndCoursePaperIdAndSource(Long examId, String coursePaperId, CardSource source) {
-        QueryWrapper<ScanAnswerCard> queryWrapper = new QueryWrapper<>();
-        queryWrapper.lambda().eq(ScanAnswerCard::getExamId, examId)
-                .eq(ScanAnswerCard::getCoursePaperId, coursePaperId)
-                .eq(ScanAnswerCard::getSource, source);
-        return this.list(queryWrapper);
-    }
-
-    @Override
-    @Transactional
-    public AnswerCardVo cardCopy(Long examId, Integer number,String remark) {
-        ScanAnswerCard old = this.findByExamAndNumber(examId,number);
-        if(old ==null ){
-            throw new ParameterException("未找到卡格式信息");
-        }
-        if (CardSource.CLIENT.equals(old.getSource())) {
-            throw new ParameterException("手工卡格式,无法复制");
-        }
-        ScanAnswerCard card = new ScanAnswerCard();
-        card.setId(SystemConstant.getDbUuid());
-        card.setExamId(old.getExamId());
-        card.setPaperNumber(old.getPaperNumber());
-        card.setPaperType(old.getPaperType());
-        card.setCoursePaperId(old.getCoursePaperId());
-        card.setPaperCount(old.getPaperCount());
-        card.setSinglePage(old.getSinglePage());
-        card.setRemark(old.getRemark());
-        card.setDpi(old.getDpi());
-        card.setSource(CardSource.WEB);
-        card.setNumber(findMaxCardNumberByExamId(examId) + 1);
-        card.setNeedAdapte(false);
-        card.setMd5(old.getMd5());
-        card.setUri(old.getUri());
-        card.setRemark(remark);
-        this.save(card);
-
-        return this.cardGet(examId,card.getNumber());
-    }
-}
+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.UpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.qmth.boot.core.exception.ParameterException;
+import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
+import com.qmth.teachcloud.common.bean.marking.CardJpgResult;
+import com.qmth.teachcloud.common.bean.marking.scanAnswerCard.AnswerCard;
+import com.qmth.teachcloud.common.bean.marking.scanAnswerCard.AnswerCardPage;
+import com.qmth.teachcloud.common.bean.vo.FilePathVo;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.SysUser;
+import com.qmth.teachcloud.common.enums.mark.MarkPaperStatus;
+import com.qmth.teachcloud.common.enums.scan.OmrField;
+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.ServletUtil;
+import com.qmth.teachcloud.mark.bean.UriVo;
+import com.qmth.teachcloud.mark.bean.answercard.*;
+import com.qmth.teachcloud.mark.entity.MarkPaper;
+import com.qmth.teachcloud.mark.entity.ScanAnswerCard;
+import com.qmth.teachcloud.mark.entity.ScanAnswerCardQuestion;
+import com.qmth.teachcloud.mark.enums.CardSource;
+import com.qmth.teachcloud.mark.mapper.ScanAnswerCardMapper;
+import com.qmth.teachcloud.mark.service.*;
+import com.qmth.teachcloud.mark.utils.FileStoreUtils;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+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.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 题卡卡格式表 服务实现类
+ * </p>
+ *
+ * @author xf
+ * @since 2023-09-22
+ */
+@Service
+public class ScanAnswerCardServiceImpl extends ServiceImpl<ScanAnswerCardMapper, ScanAnswerCard>
+        implements ScanAnswerCardService {
+
+    @Autowired
+    private MarkPaperService markPaperService;
+    @Autowired
+    private ScanPaperService scanPaperService;
+    @Resource
+    private MarkFileService markFileService;
+    @Resource
+    private MarkStudentService markStudentService;
+    @Resource
+    private ScanAnswerCardQuestionService scanAnswerCardQuestionService;
+    @Resource
+    private BasicRoleDataPermissionService basicRoleDataPermissionService;
+    @Resource
+    private TeachcloudCommonService teachcloudCommonService;
+    @Resource
+    private FileStoreUtils fileStoreUtils;
+    @Resource
+    private FileUploadService fileUploadService;
+
+    @Override
+    public ScanAnswerCard findByExamAndNumber(Long examId, Integer cardNumber) {
+        if (examId == null) {
+            throw new ParameterException("examId不能为空");
+        }
+        if (cardNumber == null) {
+            throw new ParameterException("cardNumber不能为空");
+        }
+        QueryWrapper<ScanAnswerCard> wrapper = new QueryWrapper<>();
+        LambdaQueryWrapper<ScanAnswerCard> lw = wrapper.lambda();
+        lw.eq(ScanAnswerCard::getExamId, examId);
+        lw.eq(ScanAnswerCard::getNumber, cardNumber);
+        return baseMapper.selectOne(wrapper);
+    }
+
+    @Override
+    public List<AnswerCardVo> cardList(Long examId, String coursePaperId) {
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(sysUser.getSchoolId(), sysUser.getId(), ServletUtil.getRequest().getServletPath());
+        List<AnswerCardVo> answerCardVos = baseMapper.cardList(examId, coursePaperId, MarkPaperStatus.FORMAL.name(), dpr);
+        for (AnswerCardVo answerCardVo : answerCardVos) {
+            answerCardVo.setCanAdapte(scanPaperService.getCountByExamAndCardNumber(examId, answerCardVo.getNumber()) == 0);
+            answerCardVo.setUri(fileStoreUtils.filePreview(answerCardVo.getUri()));
+            answerCardVo.setAdapteUri(fileStoreUtils.filePreview(answerCardVo.getAdapteUri()));
+        }
+        return answerCardVos;
+    }
+
+    @Transactional
+    @Override
+    public ScanAnswerCard cardSave(AnswerCardSaveDomain domain) {
+        boolean singlePage = false;
+        MarkPaper mp = markPaperService.getByExamIdAndCoursePaperId(domain.getExamId(), domain.getCoursePaperId());
+        if (MarkPaperStatus.FINISH.equals(mp.getStatus())) {
+            throw new ParameterException("阅卷已结束");
+        }
+
+        ScanAnswerCard card;
+        if (domain.getNumber() != null) {
+            card = findByExamAndNumber(domain.getExamId(), domain.getNumber());
+            if (card == null) {
+                throw new ParameterException("未找到卡格式信息");
+            }
+            if (CardSource.WEB.equals(card.getSource())) {
+                throw new ParameterException("电子卡格式,不能修改");
+            }
+            int studentCount = scanPaperService.getCountByExamAndCardNumber(domain.getExamId(), domain.getNumber());
+            if (studentCount > 0) {
+                throw new ParameterException("卡格式已被使用,不能修改");
+            }
+        } else {
+            card = new ScanAnswerCard();
+            card.setId(SystemConstant.getDbUuid());
+            card.setExamId(domain.getExamId());
+            card.setPaperNumber(mp.getPaperNumber());
+            card.setPaperType(mp.getPaperType());
+            card.setCoursePaperId(domain.getCoursePaperId());
+            card.setPaperCount(domain.getPaperCount());
+            card.setSinglePage(singlePage);
+            card.setRemark(domain.getRemark());
+            card.setDpi(domain.getDpi());
+            card.setSource(CardSource.CLIENT);
+            card.setNumber(findMaxCardNumberByExamId(domain.getExamId()) + 1);
+            card.setNeedAdapte(false);
+        }
+
+//        CardFile cardFile;
+//        byte[] fileData;
+//        String sliceConfig;
+//        try {
+//            fileData = domain.getFile().getBytes();
+//            // 解析卡格式文件
+//            cardFile = parseCardFile(fileData);
+//            if (singlePage && domain.getPaperCount() != cardFile.getPages().size()) {
+//                throw new ParameterException("卡格式数量不一致");
+//            }
+//            if (!singlePage && domain.getPaperCount() * 2 != cardFile.getPages().size()) {
+//                throw new ParameterException("卡格式数量不一致");
+//            }
+//            // 提取裁切坐标
+//            sliceConfig = cardFile.getSliceConfig().toString();
+//        } catch (IOException e) {
+//            throw new ParameterException("文件解析失败", e);
+//        }
+        String filePath = null;
+        try {
+            filePath = markFileService.uploadAnswerCard(domain.getFile().getInputStream(), domain.getMd5(), domain.getExamId(), domain.getCoursePaperId(), card.getNumber());
+        } catch (IOException e) {
+            throw new ParameterException("文件上传失败", e);
+        }
+//        card.setSliceConfig(sliceConfig);
+        card.setMd5(domain.getMd5());
+        card.setUri(filePath);
+        card.setAdapteMd5(domain.getMd5());
+        card.setAdapteUri(filePath);
+        this.saveOrUpdate(card);
+
+        saveScanAnswerCardQuestion(domain.getExamId(), domain.getCoursePaperId(), domain.getFile(), card.getNumber());
+        return card;
+    }
+
+    /**
+     * 根据卡格式中的结构,更新客观题试卷结构
+     */
+    private void saveScanAnswerCardQuestion(Long examId, String coursePaperId, MultipartFile file, Integer number) {
+        MarkPaper markPaper = markPaperService.getByExamIdAndCoursePaperId(examId, coursePaperId);
+        CardFile cardFile;
+        byte[] fileData;
+        try {
+            fileData = file.getBytes();
+            // 解析卡格式文件
+            cardFile = parseCardFile(fileData);
+            List<ScanAnswerCardQuestion> scanAnswerCardQuestions = new ArrayList<>();
+            int i = 1;
+            for (CardPageWrapper page : cardFile.getPages()) {
+                for (FillArea fillArea : page.getExchange().getFillArea().stream().filter(m -> OmrField.QUESTION.name().equals(m.getField().toUpperCase())).collect(Collectors.toList())) {
+                    for (FillItem item : fillArea.getItems()) {
+                        ScanAnswerCardQuestion scanAnswerCardQuestion = new ScanAnswerCardQuestion();
+                        scanAnswerCardQuestion.setId(SystemConstant.getDbUuid());
+                        scanAnswerCardQuestion.setExamId(examId);
+                        scanAnswerCardQuestion.setPaperNumber(markPaper.getPaperNumber());
+                        scanAnswerCardQuestion.setCoursePaperId(coursePaperId);
+                        scanAnswerCardQuestion.setCardNumber(number);
+                        scanAnswerCardQuestion.setSerialNumber(markPaper.getSerialNumber());
+                        scanAnswerCardQuestion.setMainNumber(item.getMainNumber());
+                        scanAnswerCardQuestion.setSubNumber(item.getSubNumber());
+                        scanAnswerCardQuestion.setOptionCount(item.getOptions().size());
+                        scanAnswerCardQuestion.setQuestionType(fillArea.isSingle() ? 1 : 2);
+                        scanAnswerCardQuestion.setPaperIndex(i / 2 + 1);
+                        scanAnswerCardQuestion.setPageIndex(i % 2 == 1 ? 1 : 2);
+                        scanAnswerCardQuestion.setCreateTime(System.currentTimeMillis());
+                        scanAnswerCardQuestions.add(scanAnswerCardQuestion);
+                    }
+                }
+                i++;
+            }
+
+            if (CollectionUtils.isNotEmpty(scanAnswerCardQuestions)) {
+                // 删除
+                scanAnswerCardQuestionService.deleteByExamIdAndPaperNumberAndCardNumber(examId, markPaper.getPaperNumber(), number);
+                scanAnswerCardQuestionService.saveBatch(scanAnswerCardQuestions);
+            }
+        } catch (IOException e) {
+            throw new ParameterException("文件解析失败", e);
+        }
+    }
+
+    /**
+     * 解析卡格式文件中的裁切图坐标,用于云阅卷同步
+     *
+     * @param data
+     */
+    private CardFile parseCardFile(byte[] data) throws IOException {
+        ObjectMapper objectMapper = new ObjectMapper();
+        return objectMapper.readValue(data, CardFile.class);
+    }
+
+    @Override
+    public Integer findMaxCardNumberByExamId(Long examId) {
+        int number = 0;
+        QueryWrapper<ScanAnswerCard> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(ScanAnswerCard::getExamId, examId);
+        List<ScanAnswerCard> list = this.list(queryWrapper);
+        for (ScanAnswerCard card : list) {
+            if (number < card.getNumber()) {
+                number = card.getNumber();
+            }
+        }
+        return number;
+    }
+
+    @Transactional
+    @Override
+    public void cardDelete(ScanAnswerCard card) {
+        int studentCount = scanPaperService.getCountByExamAndCardNumber(card.getExamId(), card.getNumber());
+        if (studentCount != 0) {
+            throw new ParameterException("卡格式已被使用,无法删除");
+        }
+        UpdateWrapper<ScanAnswerCard> updateWrapper = new UpdateWrapper<>();
+        updateWrapper.lambda().eq(ScanAnswerCard::getExamId, card.getExamId());
+        updateWrapper.lambda().eq(ScanAnswerCard::getNumber, card.getNumber());
+        int count = this.baseMapper.delete(updateWrapper);
+        if (count == 0) {
+            throw new ParameterException("未找到卡格式");
+        }
+    }
+
+    @Transactional
+    @Override
+    public UriVo adapteUpload(Long examId, String coursePaperId, Integer cardNumber, String md5, Integer dpi,
+                              MultipartFile file, String remark) {
+        MarkPaper mp = markPaperService.getByExamIdAndCoursePaperId(examId, coursePaperId);
+        if (MarkPaperStatus.FINISH.equals(mp.getStatus())) {
+            throw new ParameterException("阅卷已结束");
+        }
+        ScanAnswerCard card = findByExamAndNumber(examId, cardNumber);
+        if (card == null) {
+            throw new ParameterException("未找到卡格式信息");
+        }
+        if (!card.getNeedAdapte() || CardSource.CLIENT.equals(card.getSource())) {
+            throw new ParameterException("卡格式无需适配");
+        }
+        int studentCount = scanPaperService.getCountByExamAndCardNumber(examId, cardNumber);
+        if (studentCount > 0) {
+            throw new ParameterException("卡格式已被使用,无法适配");
+        }
+        String filePath;
+        try {
+            filePath = markFileService.uploadAdapteFile(file.getInputStream(), md5, examId, coursePaperId, cardNumber);
+        } catch (IOException e) {
+            throw new ParameterException("文件上传失败", e);
+        }
+        card.setDpi(dpi);
+        card.setAdapteMd5(md5);
+        card.setAdapteUri(filePath);
+        this.updateById(card);
+        UriVo vo = new UriVo();
+        vo.setUri(teachcloudCommonService.filePreview(filePath));
+        return vo;
+    }
+
+    @Override
+    public AnswerCardVo cardGet(Long examId, Integer number) {
+        List<AnswerCardVo> list = baseMapper.cardGet(examId, number);
+        if (CollectionUtils.isEmpty(list)) {
+            throw new ParameterException("未找到卡格式信息");
+        }
+        AnswerCardVo answerCardVo = list.get(0);
+        answerCardVo.setUri(fileStoreUtils.filePreview(answerCardVo.getUri()));
+        answerCardVo.setAdapteUri(fileStoreUtils.filePreview(answerCardVo.getAdapteUri()));
+        return answerCardVo;
+    }
+
+    @Override
+    public ScanAnswerCard getByExamIdAndCoursePaperIdAndSerialNumberAndCardId(Long examId, String coursePaperId, Integer serialNumber, Long cardId) {
+        QueryWrapper<ScanAnswerCard> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(ScanAnswerCard::getExamId, examId)
+                .eq(ScanAnswerCard::getCoursePaperId, coursePaperId)
+                .eq(ScanAnswerCard::getSerialNumber, serialNumber)
+                .eq(ScanAnswerCard::getCardId, cardId);
+        return this.getOne(queryWrapper);
+    }
+
+    @Override
+    public List<ScanAnswerCard> listByExamIdAndPaperNumber(Long examId, String paperNumber) {
+        QueryWrapper<ScanAnswerCard> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(ScanAnswerCard::getExamId, examId)
+                .eq(ScanAnswerCard::getPaperNumber, paperNumber);
+        return this.list(queryWrapper);
+    }
+
+    @Override
+    public void deleteByExamIdAndPaperNumber(Long examId, String paperNumber) {
+        UpdateWrapper<ScanAnswerCard> updateWrapper = new UpdateWrapper<>();
+        updateWrapper.lambda().eq(ScanAnswerCard::getExamId, examId)
+                .eq(ScanAnswerCard::getPaperNumber, paperNumber);
+        this.remove(updateWrapper);
+    }
+
+    @Override
+    public List<CardJpgResult> listPageImage(Long examId, String paperNumber) {
+        List<CardJpgResult> cardJpgResultList = new ArrayList<>();
+        Integer maxCardNumber = markStudentService.maxCardNumber(examId, paperNumber);
+        if (maxCardNumber != null) {
+            ScanAnswerCard scanAnswerCard = this.findByExamAndNumber(examId, maxCardNumber);
+            if (scanAnswerCard != null && StringUtils.isNotBlank(scanAnswerCard.getAdapteUri())) {
+                FilePathVo filePathVo = JSON.parseObject(scanAnswerCard.getAdapteUri(), FilePathVo.class);
+                if (filePathVo != null && StringUtils.isNotBlank(filePathVo.getPath())) {
+                    String jsonContent = SystemConstant.readContent(fileUploadService.downloadFile(filePathVo.getPath(), filePathVo.getUploadType(), filePathVo.getType()));
+                    if (StringUtils.isNotBlank(jsonContent)) {
+                        AnswerCard answerCard = JSON.parseObject(jsonContent, AnswerCard.class);
+                        if (answerCard != null && CollectionUtils.isNotEmpty(answerCard.getPages())) {
+                            int pageIndex = 1;
+                            for (AnswerCardPage page : answerCard.getPages()) {
+                                if (page.getExchange() != null && StringUtils.isNotBlank(page.getExchange().getPageImage())) {
+                                    String pageImage = page.getExchange().getPageImage().replaceAll("\\r\\n", "");
+                                    cardJpgResultList.add(new CardJpgResult("page" + pageIndex, pageIndex, "data:image/png;base64," + pageImage));
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return cardJpgResultList;
+    }
+
+    @Override
+    public List<ScanAnswerCard> listByExamIdAndCoursePaperIdAndSource(Long examId, String coursePaperId, CardSource source) {
+        QueryWrapper<ScanAnswerCard> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(ScanAnswerCard::getExamId, examId)
+                .eq(ScanAnswerCard::getCoursePaperId, coursePaperId)
+                .eq(ScanAnswerCard::getSource, source);
+        return this.list(queryWrapper);
+    }
+
+    @Override
+    @Transactional
+    public AnswerCardVo cardCopy(Long examId, Integer number, String remark) {
+        ScanAnswerCard old = this.findByExamAndNumber(examId, number);
+        if (old == null) {
+            throw new ParameterException("未找到卡格式信息");
+        }
+        if (CardSource.CLIENT.equals(old.getSource())) {
+            throw new ParameterException("手工卡格式,无法复制");
+        }
+        ScanAnswerCard card = new ScanAnswerCard();
+        card.setId(SystemConstant.getDbUuid());
+        card.setExamId(old.getExamId());
+        card.setPaperNumber(old.getPaperNumber());
+        card.setPaperType(old.getPaperType());
+        card.setCoursePaperId(old.getCoursePaperId());
+        card.setPaperCount(old.getPaperCount());
+        card.setSinglePage(old.getSinglePage());
+        card.setRemark(old.getRemark());
+        card.setDpi(old.getDpi());
+        card.setSource(CardSource.WEB);
+        card.setNumber(findMaxCardNumberByExamId(examId) + 1);
+        card.setNeedAdapte(false);
+        card.setMd5(old.getMd5());
+        card.setUri(old.getUri());
+        card.setRemark(remark);
+        this.save(card);
+
+        return this.cardGet(examId, card.getNumber());
+    }
+
+    /**
+     * 根据examId和cardId以及cardSource获取扫描题卡
+     *
+     * @param examId
+     * @param cardId
+     * @param source
+     * @return
+     */
+    @Override
+    public ScanAnswerCard findByExamAndCardIdAndCardSource(Long examId, Long cardId, CardSource source) {
+        QueryWrapper<ScanAnswerCard> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(ScanAnswerCard::getExamId, examId)
+                .eq(ScanAnswerCard::getCardId, cardId)
+                .eq(ScanAnswerCard::getSource, source);
+        return this.getOne(queryWrapper);
+    }
+}

+ 0 - 1
teachcloud-task/src/main/java/com/qmth/teachcloud/task/job/service/impl/JobServiceImpl.java

@@ -28,7 +28,6 @@ import com.qmth.teachcloud.mark.lock.LockService;
 import com.qmth.teachcloud.mark.service.*;
 import com.qmth.teachcloud.mark.utils.TaskLockUtil;
 import com.qmth.teachcloud.task.job.service.JobService;
-import com.qmth.teachcloud.task.service.PrintFinishService;
 import org.apache.commons.collections4.CollectionUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;