Browse Source

3.0.1-下载管理

xiaof 3 years ago
parent
commit
b55685fb95
17 changed files with 605 additions and 19 deletions
  1. 11 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/ExaminationImportDto.java
  2. 11 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/ExamDetailCourse.java
  3. 14 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/ExamTask.java
  4. 1 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/ExamPrintPlanMapper.java
  5. 3 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/DownloadService.java
  6. 1 1
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/ExamPrintPlanService.java
  7. 8 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/PrintCommonService.java
  8. 124 1
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/DownloadServiceImpl.java
  9. 2 2
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamPrintPlanServiceImpl.java
  10. 11 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamTaskServiceImpl.java
  11. 20 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/PrintCommonServiceImpl.java
  12. 44 6
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/util/CreatePdfUtil.java
  13. 3 0
      distributed-print-business/src/main/resources/mapper/ExamPrintPlanMapper.xml
  14. 6 5
      distributed-print/src/main/java/com/qmth/distributed/print/api/DownloadController.java
  15. 2 4
      distributed-print/src/main/java/com/qmth/distributed/print/api/ExamPrintPlanSyncController.java
  16. 77 0
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/service/AttachmentCommonService.java
  17. 267 0
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/service/impl/AttachmentCommonServiceImpl.java

+ 11 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/ExaminationImportDto.java

@@ -60,6 +60,9 @@ public class ExaminationImportDto {
     @ExcelDBFieldDesc(name = "试卷编号",length = 30)
     private String paperNumber;
 
+    @ApiModelProperty(value = "课程创建的任务序号")
+    private String sequence;
+
     @ApiModelProperty(value = "备选字段集合")
     private List<FieldsDto> secondaryFieldList;
 
@@ -177,6 +180,14 @@ public class ExaminationImportDto {
         this.paperNumber = paperNumber;
     }
 
+    public String getSequence() {
+        return sequence;
+    }
+
+    public void setSequence(String sequence) {
+        this.sequence = sequence;
+    }
+
     public List<FieldsDto> getSecondaryFieldList() {
         return secondaryFieldList;
     }

+ 11 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/ExamDetailCourse.java

@@ -46,6 +46,9 @@ public class ExamDetailCourse extends BaseEntity implements Serializable {
     @TableField("paper_number")
     private String paperNumber;
 
+    @TableField("sequence")
+    private String sequence;
+
     @TableField("total_subjects")
     private Integer totalSubjects;
 
@@ -134,6 +137,14 @@ public class ExamDetailCourse extends BaseEntity implements Serializable {
         this.paperNumber = paperNumber;
     }
 
+    public String getSequence() {
+        return sequence;
+    }
+
+    public void setSequence(String sequence) {
+        this.sequence = sequence;
+    }
+
     public Integer getTotalSubjects() {
         return totalSubjects;
     }

+ 14 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/ExamTask.java

@@ -67,6 +67,12 @@ public class ExamTask extends BaseEntity implements Serializable {
      */
     @TableField("paper_number_id")
     private Long paperNumberId;
+
+    /**
+     * 课程创建的任务序号
+     */
+    @TableField("sequence")
+    private String sequence;
     /**
      * 命题开始时间
      */
@@ -212,6 +218,14 @@ public class ExamTask extends BaseEntity implements Serializable {
         this.paperNumberId = paperNumberId;
     }
 
+    public String getSequence() {
+        return sequence;
+    }
+
+    public void setSequence(String sequence) {
+        this.sequence = sequence;
+    }
+
     public Long getStartTime() {
         return startTime;
     }

+ 1 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/ExamPrintPlanMapper.java

@@ -35,6 +35,7 @@ public interface ExamPrintPlanMapper extends BaseMapper<ExamPrintPlan> {
     IPage<PrintPlanResult> findPrintPlanSyncPage(@Param("iPage") Page<PrintPlanResult> iPage,
                                                  @Param("schoolId") Long schoolId,
                                                  @Param("semesterId") Long semesterId,
+                                                 @Param("examId") Long examId,
                                                  @Param("status") String[] status,
                                                  @Param("printPlanId") Long printPlanId,
                                                  @Param("startTime") Long startTime,

+ 3 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/DownloadService.java

@@ -6,6 +6,7 @@ import com.qmth.distributed.print.business.bean.dto.BasicExamDto;
 import com.qmth.distributed.print.business.bean.dto.ExamTaskDetailDto;
 import com.qmth.teachcloud.common.entity.BasicExam;
 
+import javax.servlet.http.HttpServletResponse;
 import java.util.List;
 
 /**
@@ -15,4 +16,6 @@ import java.util.List;
  */
 public interface DownloadService {
     IPage<ExamTaskDetailDto> page(Long semesterId, Long examId, Long orgId, String courseName, Integer pageNumber, Integer pageSize);
+
+    void paperDownload(HttpServletResponse response, Long id) throws Exception;
 }

+ 1 - 1
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/ExamPrintPlanService.java

@@ -41,7 +41,7 @@ public interface ExamPrintPlanService extends IService<ExamPrintPlan> {
      */
     IPage<PrintPlanResult> printPlanPage(Long schoolId, Long semesterId, Long examId, List<Long> printPlanIdList, PrintPlanStatusEnum status, Long startTime, Long endTime, int pageNumber, int pageSize);
 
-    IPage<PrintPlanResult> printPlanSyncPage(Long schoolId, Long semesterId, Long printPlanId, Long startTime, Long endTime, int pageNumber, int pageSize);
+    IPage<PrintPlanResult> printPlanSyncPage(Long schoolId, Long semesterId, Long examId, Long printPlanId, Long startTime, Long endTime, int pageNumber, int pageSize);
 
     /**
      * 印刷计划模糊名称

+ 8 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/PrintCommonService.java

@@ -267,4 +267,12 @@ public interface PrintCommonService {
      * @return
      */
     public String saveTaskAttachment(ByteArrayOutputStream fos, boolean oss) throws IOException;
+
+    /**
+     * 生成任务序号
+     * @param schoolId 学校ID
+     * @param courseCode 课程代码
+     * @return
+     */
+    String createCourseSequence(Long schoolId, String courseCode);
 }

+ 124 - 1
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/DownloadServiceImpl.java

@@ -1,14 +1,38 @@
 package com.qmth.distributed.print.business.service.impl;
 
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.qmth.distributed.print.business.bean.dto.ExamTaskDetailDto;
+import com.qmth.distributed.print.business.entity.*;
+import com.qmth.distributed.print.business.enums.MakeMethodEnum;
+import com.qmth.distributed.print.business.mapper.ExamCardMapper;
+import com.qmth.distributed.print.business.mapper.ExamTaskDetailMapper;
 import com.qmth.distributed.print.business.mapper.ExamTaskMapper;
+import com.qmth.distributed.print.business.service.BasicCardRuleService;
 import com.qmth.distributed.print.business.service.DownloadService;
+import com.qmth.distributed.print.business.service.ExamCardDetailService;
+import com.qmth.distributed.print.business.util.CreatePdfUtil;
+import com.qmth.distributed.print.business.util.HtmlToPdfUtil;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.BasicAttachment;
+import com.qmth.teachcloud.common.enums.CardCreateMethodEnum;
+import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
+import com.qmth.teachcloud.common.enums.PageSizeEnum;
+import com.qmth.teachcloud.common.mapper.BasicAttachmentMapper;
+import com.qmth.teachcloud.common.service.AttachmentCommonService;
 import com.qmth.teachcloud.common.service.TeachcloudCommonService;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
+import org.springframework.util.FileCopyUtils;
 
 import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Set;
 
 @Service
@@ -20,13 +44,112 @@ public class DownloadServiceImpl implements DownloadService {
     @Resource
     ExamTaskMapper examTaskMapper;
 
+    @Resource
+    ExamTaskDetailMapper examTaskDetailMapper;
+
+    @Resource
+    BasicAttachmentMapper basicAttachmentMapper;
+
+    @Resource
+    ExamCardMapper examCardMapper;
+
+    @Resource
+    ExamCardDetailService examCardDetailService;
+
+    @Resource
+    BasicCardRuleService basicCardRuleService;
+
+    @Resource
+    AttachmentCommonService attachmentCommonService;
+
+    @Resource
+    CreatePdfUtil createPdfUtil;
+
     @Override
     public IPage<ExamTaskDetailDto> page(Long semesterId, Long examId, Long orgId, String courseName, Integer pageNumber, Integer pageSize) {
         Page<ExamTaskDetailDto> page = new Page<>(pageNumber, pageSize);
         Set<Long> orgIds = null;
-        if(orgId != null){
+        if (orgId != null) {
             orgIds = teachcloudCommonService.listSubOrgIds(orgId);
         }
         return examTaskMapper.listExamTaskDetailDownload(page, semesterId, examId, courseName, orgIds);
     }
+
+    @Override
+    public void paperDownload(HttpServletResponse response, Long id) throws Exception {
+        ExamTask examTask = examTaskMapper.selectById(id);
+        QueryWrapper<ExamTaskDetail> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(ExamTaskDetail::getExamTaskId, id);
+        ExamTaskDetail examTaskDetail = examTaskDetailMapper.selectOne(queryWrapper);
+        if (examTaskDetail == null) {
+            throw ExceptionResultEnum.ERROR.exception("数据异常");
+        }
+        // 只下载未曝光试卷
+        String unexposedPaperType = examTaskDetail.getUnexposedPaperType();
+        if (StringUtils.isBlank(unexposedPaperType)) {
+            throw ExceptionResultEnum.ERROR.exception("没有未曝光试卷,无法下载");
+        }
+        String paperAttachmentIds = examTaskDetail.getPaperAttachmentIds();
+        List<JSONObject> jsonObjectList = JSONObject.parseArray(paperAttachmentIds, JSONObject.class);
+        // 本地存储目录
+        String rootPath = SystemConstant.TEMP_FILES_DIR + File.separator + System.currentTimeMillis();
+        List<File> fileList = new ArrayList<>();
+        // 试卷
+        List<String> unexposedPaperTypes = Arrays.asList(unexposedPaperType.split(","));
+        for (JSONObject jsonObject : jsonObjectList) {
+            String attachmentId = jsonObject.get("attachmentId").toString();
+            String name = jsonObject.get("name").toString();
+            if (!unexposedPaperTypes.contains(name)) {
+                continue;
+            }
+            BasicAttachment attachment = basicAttachmentMapper.selectById(attachmentId);
+            if (attachment == null) {
+                throw ExceptionResultEnum.ERROR.exception("附件数据异常");
+            }
+            String paperPath = rootPath + File.separator + examTask.getCourseName() + "-" + examTask.getCourseCode() + File.separator + examTask.getPaperNumber();
+            String fileName = "试卷" + "_" + attachment.getName() + "_" + name + attachment.getType();
+            fileList.add(attachmentCommonService.downloadFile(paperPath, fileName, attachment));
+        }
+
+        // 题卡
+        Long cardId = examTaskDetail.getCardId();
+        if (cardId != null) {
+            ExamCard examCard = examCardMapper.selectById(cardId);
+
+            String cardPath = rootPath + File.separator + examTask.getCourseName() + "-" + examTask.getCourseCode() + File.separator + examTask.getPaperNumber();
+            String cardHtmlPath = cardPath + File.separator + "题卡" + "_" + examTask.getCourseName() + SystemConstant.HTML_PREFIX;
+            String cardPdfPath = cardPath + File.separator + "题卡" + "_" + examTask.getCourseName() + SystemConstant.PDF_PREFIX;
+
+            ExamCardDetail examCardDetail = examCardDetailService.getByCardId(examCard.getId());
+            String htmlContent;
+            // 通用模板
+            if (MakeMethodEnum.SELECT.equals(examCard.getMakeMethod()) && CardCreateMethodEnum.UPLOAD.equals(examCard.getCreateMethod())) {
+                htmlContent = createPdfUtil.resetHtmlTemplateBar(examCardDetail.getHtmlContent());
+            } else {
+                BasicCardRule basicCardRule = basicCardRuleService.getById(examTask.getCardRuleId());
+                htmlContent = createPdfUtil.replaceHtmlCard(examCardDetail, basicCardRule);
+            }
+
+            // html
+            File htmlFile = new File(cardHtmlPath);
+            if (!htmlFile.getParentFile().exists()) {
+                htmlFile.getParentFile().mkdirs();
+            }
+            // 生成html文件
+            FileCopyUtils.copy(htmlContent.getBytes(), htmlFile);
+            fileList.add(htmlFile);
+            // 转pdf文件
+            File pdfFile = new File(cardPdfPath);
+            if (!pdfFile.exists()) {
+                pdfFile.createNewFile();
+            }
+            HtmlToPdfUtil.convert(cardHtmlPath, cardPdfPath, PageSizeEnum.A3);
+            fileList.add(pdfFile);
+        }
+        if (fileList.size() == 0) {
+            throw ExceptionResultEnum.ERROR.exception("没有可导出文件");
+        }
+        String zipName = examTask.getCourseName() + "未曝光试卷.zip";
+        attachmentCommonService.zipFiles(response, rootPath, zipName, fileList);
+    }
 }

+ 2 - 2
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamPrintPlanServiceImpl.java

@@ -105,10 +105,10 @@ public class ExamPrintPlanServiceImpl extends ServiceImpl<ExamPrintPlanMapper, E
 
     @Transactional(rollbackFor = Exception.class)
     @Override
-    public IPage<PrintPlanResult> printPlanSyncPage(Long schoolId, Long semesterId, Long printPlanId, Long startTime, Long endTime, int pageNumber, int pageSize) {
+    public IPage<PrintPlanResult> printPlanSyncPage(Long schoolId, Long semesterId, Long examId, Long printPlanId, Long startTime, Long endTime, int pageNumber, int pageSize) {
         Set<Long> orgIds = teachcloudCommonService.listSubOrgIds(null);
         String[] status = {PrintPlanStatusEnum.PRINT_FINISH.name(), PrintPlanStatusEnum.END.name()};
-        IPage<PrintPlanResult> page = examPrintPlanMapper.findPrintPlanSyncPage(new Page<>(pageNumber, pageSize), schoolId, semesterId, status, printPlanId, startTime, endTime, orgIds);
+        IPage<PrintPlanResult> page = examPrintPlanMapper.findPrintPlanSyncPage(new Page<>(pageNumber, pageSize), schoolId, semesterId, examId, status, printPlanId, startTime, endTime, orgIds);
         List<PrintPlanResult> list = page.getRecords();
         for (PrintPlanResult printPlanResult : list) {
             List<Map> variableContent = JSONObject.parseArray(printPlanResult.getVariableContentTemp(), Map.class);

+ 11 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamTaskServiceImpl.java

@@ -416,6 +416,9 @@ public class ExamTaskServiceImpl extends ServiceImpl<ExamTaskMapper, ExamTask> i
             }
             examTask.setPaperNumberId(SystemConstant.getDbUuid());
 
+            String sequence = printCommonService.createCourseSequence(schoolId, examTask.getCourseCode());
+            examTask.setSequence(sequence);
+
             QueryWrapper<BasicExamRule> queryWrapper = new QueryWrapper<>();
             queryWrapper.lambda().eq(BasicExamRule::getSchoolId, examTask.getSchoolId());
             BasicExamRule basicExamRule = basicExamRuleService.getOne(queryWrapper);
@@ -705,8 +708,12 @@ public class ExamTaskServiceImpl extends ServiceImpl<ExamTaskMapper, ExamTask> i
                 // 试卷编号生成规则:年月日(例如:20100419)+0000(例如:0001)顺序编号
                 String paperNumber = printCommonService.createPaperNumber(schoolId);
                 userMap.put("paperNumber", paperNumber);
+
+                String sequence = printCommonService.createCourseSequence(schoolId, courseCode);
+                userMap.put("sequence", sequence);
             }
             examTask.setPaperNumber(userMap.get("paperNumber"));
+            examTask.setSequence(userMap.get("sequence"));
             examTask.setPaperNumberId(SystemConstant.getDbUuid());
             examTask.setStartTime(task.getStartTime());
             examTask.setEndTime(task.getEndTime());
@@ -1658,6 +1665,9 @@ public class ExamTaskServiceImpl extends ServiceImpl<ExamTaskMapper, ExamTask> i
                 examTask.setPaperNumber(paperNumber);
             }
 
+            String sequence = printCommonService.createCourseSequence(schoolId, examTask.getCourseCode());
+            examTask.setSequence(sequence);
+
             examTask.setId(SystemConstant.getDbUuid());
             examTask.setPaperNumberId(SystemConstant.getDbUuid());
             examTask.setSchoolId(schoolId);
@@ -1772,6 +1782,7 @@ public class ExamTaskServiceImpl extends ServiceImpl<ExamTaskMapper, ExamTask> i
                         examDetailCourse.setCourseCode(examTask.getCourseCode());
                         examDetailCourse.setCourseName(examTask.getCourseName());
                         examDetailCourse.setPaperNumber(examTask.getPaperNumber());
+                        examDetailCourse.setSequence(examTask.getSequence());
                         examDetailCourse.setClazzId(examDetailList.getClassId());
                         examDetailCourse.setTotalSubjects(examDetailList.getStudentCount());
                         examDetailCourse.setCreateId(sysUser.getId());

+ 20 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/PrintCommonServiceImpl.java

@@ -1136,4 +1136,24 @@ public class PrintCommonServiceImpl implements PrintCommonService {
         }
         return Objects.nonNull(jsonObject) ? jsonObject.toJSONString() : null;
     }
+
+    @Override
+    public String createCourseSequence(Long schoolId, String courseCode) {
+        String key = "courseCode-" + courseCode + schoolId;
+        String sequence = convertUtil.getIncre("", key, 1);
+        if ("1".equals(sequence)) {
+            QueryWrapper<ExamTask> queryWrapper = new QueryWrapper<>();
+            queryWrapper.lambda().eq(ExamTask::getSchoolId, schoolId).eq(ExamTask::getCourseCode, courseCode);
+            List<ExamTask> examTasks = examTaskService.list(queryWrapper);
+            if (examTasks != null && examTasks.size() > 0) {
+                String maxSequence = examTasks.stream().max(Comparator.comparing(ExamTask::getSequence)).get().getSequence();
+                if (StringUtils.isNotBlank(maxSequence)) {
+                    String incMaxSequence = String.valueOf(Integer.parseInt(maxSequence) + 1);
+                    redisUtil.set(key, incMaxSequence);
+                    return incMaxSequence;
+                }
+            }
+        }
+        return sequence;
+    }
 }

+ 44 - 6
distributed-print-business/src/main/java/com/qmth/distributed/print/business/util/CreatePdfUtil.java

@@ -178,7 +178,7 @@ public class CreatePdfUtil {
         Set<Long> clazzIdSet = new HashSet<>();
         for (ExamDetailCourse examDetailCourse : examDetailCourseList) {
             String clazzInfo = examDetailCourse.getClazzId();
-            if (SystemConstant.strNotNull(clazzInfo)){
+            if (SystemConstant.strNotNull(clazzInfo)) {
                 Set<Long> clazzIdSetCell = Arrays.stream(clazzInfo.split(",")).map(SystemConstant::convertIdToLong).collect(Collectors.toSet());
                 clazzIdSet.addAll(clazzIdSetCell);
             }
@@ -506,9 +506,14 @@ public class CreatePdfUtil {
         cardTemp = cardTemp.replaceAll("\\$\\{examRoom\\}", "");
         cardTemp = cardTemp.replaceAll("\\$\\{paperNumber\\}", "");
 
-        //通用题卡生成卷袋贴条码
-//        String packageCodeDiv = "<div class=\"page-box page-box-0\"><div class=\"package-number\" style=\"position: absolute;width: 200px;height: 40px;top: 10px;right: 25%;margin-left: -100px;text-align: center;z-index: 99;\"><img src=\"data:image/png;base64," + packageCodeImg + "\" style=\"display: block; height: 28px; width: 100%\" /><p style=\"line-height: 1; font-size: 12px; margin: 0;\">" + packageCode + "</p></div>";
-//        cardTemp = cardTemp.replaceAll("<div class=\"page-box page-box-0\">", packageCodeDiv);
+        // 根据题卡规则必选字段,替换相应值,没有则“”
+        List<StudentExtendDto> studentExtendDtos = createExtendObjectNull(basicCardRule);
+        if (studentExtendDtos != null) {
+            for (StudentExtendDto extendDto : studentExtendDtos) {
+                cardTemp = cardTemp.replaceAll("\\$\\{" + extendDto.getFieldName() + "\\}", String.valueOf(extendDto.getValue()));
+            }
+        }
+
         return cardTemp;
     }
 
@@ -983,6 +988,39 @@ public class CreatePdfUtil {
         return studentExtendDtos;
     }
 
+    /**
+     * 题卡规则字段
+     *
+     * @param basicCardRule 题卡规则对象
+     */
+    private List<StudentExtendDto> createExtendObjectNull(BasicCardRule basicCardRule) {
+        if (basicCardRule == null) {
+            return null;
+        }
+        List<JSONObject> requiredFieldsJson = JSONArray.parseArray(basicCardRule.getRequiredFields(), JSONObject.class);
+        List<StudentExtendDto> studentExtendDtos = new ArrayList<>();
+        if (requiredFieldsJson.size() > 0) {
+            for (JSONObject jsonObject : requiredFieldsJson) {
+                StudentExtendDto studentExtendDto = new StudentExtendDto();
+                String code = String.valueOf(jsonObject.get("code"));
+                studentExtendDto.setFieldName(code);
+                studentExtendDto.setValue("");
+                studentExtendDtos.add(studentExtendDto);
+            }
+        }
+        List<JSONObject> extendFieldsJson = JSONArray.parseArray(basicCardRule.getExtendFields(), JSONObject.class);
+        if (extendFieldsJson.size() > 0) {
+            for (JSONObject jsonObject : extendFieldsJson) {
+                StudentExtendDto studentExtendDto = new StudentExtendDto();
+                String code = String.valueOf(jsonObject.get("code"));
+                studentExtendDto.setFieldName(code);
+                studentExtendDto.setValue("");
+                studentExtendDtos.add(studentExtendDto);
+            }
+        }
+        return studentExtendDtos;
+    }
+
     /**
      * 通用题卡html
      *
@@ -1031,10 +1069,10 @@ public class CreatePdfUtil {
         String packageCode = examDetail.getPackageCode() + sequence;
         String packageCodeImg = GoogleBarCodeUtil.createBarCode(packageCode, false);
 
-        if(cardTemp.contains("<div class=\"page-box page-box-A3 page-box-0\">")){
+        if (cardTemp.contains("<div class=\"page-box page-box-A3 page-box-0\">")) {
             String packageCodeDiv = "<div class=\"page-box page-box-A3 page-box-0\"><div class=\"package-number\" style=\"position: absolute;width: 200px;height: 40px;top: 10px;right: 25%;margin-left: -100px;text-align: center;z-index: 99;\"><img src=\"data:image/png;base64," + packageCodeImg + "\" style=\"display: block; height: 28px; width: 100%\" /><p style=\"line-height: 1; font-size: 12px; margin: 0;\">" + packageCode + "</p></div>";
             cardTemp = cardTemp.replaceAll("<div class=\"page-box page-box-A3 page-box-0\">", packageCodeDiv);
-        } else if(cardTemp.contains("<div class=\"page-box page-box-A4 page-box-0\">")){
+        } else if (cardTemp.contains("<div class=\"page-box page-box-A4 page-box-0\">")) {
             String packageCodeDiv = "<div class=\"page-box page-box-A4 page-box-0\"><div class=\"package-number\" style=\"position: absolute;width: 200px;height: 40px;top: 10px;right: 25%;margin-left: -100px;text-align: center;z-index: 99;\"><img src=\"data:image/png;base64," + packageCodeImg + "\" style=\"display: block; height: 28px; width: 100%\" /><p style=\"line-height: 1; font-size: 12px; margin: 0;\">" + packageCode + "</p></div>";
             cardTemp = cardTemp.replaceAll("<div class=\"page-box page-box-A4 page-box-0\">", packageCodeDiv);
         }

+ 3 - 0
distributed-print-business/src/main/resources/mapper/ExamPrintPlanMapper.xml

@@ -148,6 +148,9 @@
             <if test="semesterId!= null and semesterId != ''">
                 and be.semester_id = #{semesterId}
             </if>
+            <if test="examId!= null and examId != ''">
+                and be.id = #{examId}
+            </if>
             <if test="printPlanId!= null and printPlanId != ''">
                 and a.id = #{printPlanId}
             </if>

+ 6 - 5
distributed-print/src/main/java/com/qmth/distributed/print/api/DownloadController.java

@@ -2,6 +2,7 @@ package com.qmth.distributed.print.api;
 
 import com.qmth.boot.api.constant.ApiConstant;
 import com.qmth.distributed.print.business.service.DownloadService;
+import com.qmth.distributed.print.business.service.ExamTaskService;
 import com.qmth.teachcloud.common.bean.result.TaskListResult;
 import com.qmth.teachcloud.common.contant.SystemConstant;
 import io.swagger.annotations.*;
@@ -11,6 +12,7 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
 import javax.validation.constraints.Max;
 import javax.validation.constraints.Min;
 
@@ -49,16 +51,15 @@ public class DownloadController {
     }
 
     /**
-     * 单个科目下载
+     * 单个科目下载(只下载未曝光试卷)
      *
-     * @param examTaskId 任务ID
-     * @return Object
+     * @param id 任务ID
      */
     @ApiOperation(value = "单课程下载")
     @RequestMapping(value = "/download_one", method = RequestMethod.POST)
     @ApiResponses({@ApiResponse(code = 200, message = "单课程下载", response = TaskListResult.class)})
-    public Object downloadOne(@ApiParam(value = "任务ID", required = false) @RequestParam(required = false) Long examTaskId) {
-        return null;
+    public void downloadOne(HttpServletResponse response, @ApiParam(value = "任务ID", required = false) @RequestParam(required = false) Long id) throws Exception {
+        downloadService.paperDownload(response, id);
     }
 
     /**

+ 2 - 4
distributed-print/src/main/java/com/qmth/distributed/print/api/ExamPrintPlanSyncController.java

@@ -3,7 +3,6 @@ package com.qmth.distributed.print.api;
 import com.qmth.boot.api.constant.ApiConstant;
 import com.qmth.distributed.print.business.bean.params.SyncDataParam;
 import com.qmth.distributed.print.business.bean.result.EditResult;
-import com.qmth.distributed.print.business.enums.PrintPlanStatusEnum;
 import com.qmth.distributed.print.business.service.ExamPrintPlanService;
 import com.qmth.teachcloud.common.contant.SystemConstant;
 import com.qmth.teachcloud.common.util.Result;
@@ -16,8 +15,6 @@ import org.springframework.web.bind.annotation.*;
 import javax.annotation.Resource;
 import javax.validation.constraints.Max;
 import javax.validation.constraints.Min;
-import java.util.ArrayList;
-import java.util.List;
 
 /**
  * <p>
@@ -49,13 +46,14 @@ public class ExamPrintPlanSyncController {
     @RequestMapping(value = "/list_sync", method = RequestMethod.POST)
     @ApiResponses({@ApiResponse(code = 200, message = "查询成功", response = Result.class)})
     public Result findPrintPlanPage(@ApiParam(value = "学期ID") @RequestParam(required = false) Long semesterId,
+                                    @ApiParam(value = "考试ID") @RequestParam(required = false) Long examId,
                                     @ApiParam(value = "印刷计划ID") @RequestParam(required = false) Long printPlanId,
                                     @ApiParam(value = "计划创建时间段开始时间") @RequestParam(required = false) Long startTime,
                                     @ApiParam(value = "计划创建时间段结束时间") @RequestParam(required = false) Long endTime,
                                     @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) Integer pageNumber,
                                     @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) Integer pageSize) {
         Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
-        return ResultUtil.ok(examPrintPlanService.printPlanSyncPage(schoolId, semesterId, printPlanId, startTime, endTime, pageNumber, pageSize));
+        return ResultUtil.ok(examPrintPlanService.printPlanSyncPage(schoolId, semesterId, examId, printPlanId, startTime, endTime, pageNumber, pageSize));
     }
 
     /**

+ 77 - 0
teachcloud-common/src/main/java/com/qmth/teachcloud/common/service/AttachmentCommonService.java

@@ -0,0 +1,77 @@
+package com.qmth.teachcloud.common.service;
+
+import com.qmth.teachcloud.common.entity.BasicAttachment;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 试卷、题卡下载、预览等操作公共服务service
+ */
+public interface AttachmentCommonService {
+
+
+    /**
+     * 文件预览
+     *
+     * @param path 文件路径(json格式)
+     * @return String
+     */
+    public String previewFile(String path);
+
+    /**
+     * 文件预览
+     *
+     * @param path 文件路径
+     * @return String
+     */
+    public String previewFile(String path, String type, Boolean isExpire);
+
+    /**
+     * 文件预览
+     *
+     * @param attachmentId 附件ID
+     * @return Map
+     */
+    public Map<String, String> previewFile(Long attachmentId, Boolean isExpire);
+
+
+    /**
+     * 下载文件
+     *
+     * @param rootPath     文件本地存储路径(支持多级)
+     * @param fileName     保存本地文件名
+     * @param attachmentId 附件表对象ID
+     */
+    public File downloadFile(String rootPath, String fileName, Long attachmentId) throws Exception;
+
+    /**
+     * 下载文件
+     *
+     * @param rootPath   文件本地存储路径(支持多级)
+     * @param fileName   保存本地文件名
+     * @param attachment 附件表对象
+     */
+    public File downloadFile(String rootPath, String fileName, BasicAttachment attachment) throws Exception;
+
+    /**
+     * 压缩指定文件集合
+     *
+     * @param response response对象
+     * @param filePath 文件根目录(存储zip文件路径)
+     * @param zipName  zip文件名
+     * @param files    需要下载的文件集合
+     */
+    public void zipFiles(HttpServletResponse response, String filePath, String zipName, List<File> files);
+
+    /**
+     * 下载文件到本地并压缩返回
+     *
+     * @param response response对象
+     * @param filePath 文件根目录
+     * @param zipName  zip文件名
+     */
+    public void zipFiles(HttpServletResponse response, String filePath, String zipName);
+}

+ 267 - 0
teachcloud-common/src/main/java/com/qmth/teachcloud/common/service/impl/AttachmentCommonServiceImpl.java

@@ -0,0 +1,267 @@
+package com.qmth.teachcloud.common.service.impl;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.lang.UUID;
+import cn.hutool.core.util.ZipUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.qmth.teachcloud.common.config.DictionaryConfig;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.BasicAttachment;
+import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
+import com.qmth.teachcloud.common.enums.UploadFileEnum;
+import com.qmth.teachcloud.common.service.AttachmentCommonService;
+import com.qmth.teachcloud.common.service.BasicAttachmentService;
+import com.qmth.teachcloud.common.util.FileStoreUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * 试卷、题卡下载、预览等操作公共服务service impl
+ */
+@Service
+public class AttachmentCommonServiceImpl implements AttachmentCommonService {
+    private final static Logger log = LoggerFactory.getLogger(AttachmentCommonServiceImpl.class);
+
+    /**
+     * 默认目录
+     */
+    private static String TEMP_DIR = SystemConstant.TEMP_FILES_DIR + File.separator + System.currentTimeMillis();
+
+    @Resource
+    DictionaryConfig dictionaryConfig;
+
+    @Resource
+    BasicAttachmentService basicAttachmentService;
+
+    @Resource
+    FileStoreUtil fileStoreUtil;
+
+    /**
+     * 文件预览
+     *
+     * @param path 预览路径
+     * @return String
+     */
+    @Override
+    public String previewFile(String path) {
+        String url;
+        JSONObject jsonObject = JSONObject.parseObject(path);
+        String attachmentType = (String) jsonObject.get(SystemConstant.TYPE);
+        String filePath = (String) jsonObject.get(SystemConstant.PATH);
+        UploadFileEnum uploadFileEnum = UploadFileEnum.valueOf((String) jsonObject.get(SystemConstant.UPLOAD_TYPE));
+        if (Objects.equals(attachmentType, SystemConstant.LOCAL)) {
+            url = SystemConstant.HTTP + dictionaryConfig.sysDomain().getFileHost() + File.separator + filePath;
+        } else {
+            url = fileStoreUtil.getPrivateUrl(filePath, uploadFileEnum.getFssType());
+        }
+        return url;
+    }
+
+    /**
+     * 文件预览
+     *
+     * @param path     附件路径
+     * @param type     保存类型:本地、OSS
+     * @param isExpire url是否带过期时间
+     * @return String
+     */
+    @Override
+    public String previewFile(String path, String type, Boolean isExpire) {
+        if (StringUtils.isBlank(path)) {
+            return null;
+        }
+
+        String pathUrl;
+        if (Objects.equals(type, SystemConstant.LOCAL)) {
+            pathUrl = SystemConstant.HTTP + dictionaryConfig.sysDomain().getFileHost() + File.separator + path;
+        } else {
+            pathUrl = fileStoreUtil.getPrivateUrl(path, fileStoreUtil.getUploadEnumByPath(path).getFssType());
+
+        }
+        return pathUrl;
+    }
+
+    /**
+     * 文件预览
+     *
+     * @param attachmentId 附件ID
+     * @param isExpire     url是否带过期时间
+     * @return String
+     */
+    @Override
+    public Map<String, String> previewFile(Long attachmentId, Boolean isExpire) {
+        BasicAttachment attachment = basicAttachmentService.getById(attachmentId);
+        if (attachment == null) {
+            return null;
+        }
+
+        Map<String, String> map = new HashMap<>();
+
+        String pathUrl;
+        JSONObject jsonObject = JSONObject.parseObject(attachment.getPath());
+        String attachmentType = (String) jsonObject.get(SystemConstant.TYPE);
+        String filePath = (String) jsonObject.get(SystemConstant.PATH);
+        UploadFileEnum uploadFileEnum = jsonObject.get(SystemConstant.UPLOAD_TYPE).toString().contains(UploadFileEnum.HTML.name()) ? UploadFileEnum.HTML : UploadFileEnum.valueOf((String) jsonObject.get(SystemConstant.UPLOAD_TYPE));
+
+        if (Objects.equals(attachmentType, SystemConstant.LOCAL)) {
+            pathUrl = SystemConstant.HTTP + dictionaryConfig.sysDomain().getFileHost() + File.separator + filePath;
+        } else {
+            pathUrl = fileStoreUtil.getPrivateUrl(filePath, uploadFileEnum.getFssType());
+        }
+        map.put("url", pathUrl);
+        if (attachment.getType().equals(".html")) {
+            String htmlMd5 = (String) jsonObject.get("htmlMd5");
+            map.put("md5", htmlMd5);
+        } else {
+            map.put("md5", attachment.getMd5());
+        }
+        return map;
+    }
+
+    @Override
+    public File downloadFile(String rootPath, String fileName, Long attachmentId) throws Exception {
+        BasicAttachment basicAttachment = basicAttachmentService.getById(attachmentId);
+        return downloadFile(rootPath, fileName, basicAttachment);
+    }
+
+    @Override
+    public File downloadFile(String rootPath, String fileName, BasicAttachment basicAttachment) throws Exception {
+        if (basicAttachment == null) {
+            throw ExceptionResultEnum.ERROR.exception("附件信息不存在");
+        }
+        JSONObject object = JSONObject.parseObject(basicAttachment.getPath());
+        String filePath = object.getString(SystemConstant.PATH);
+        String type = object.getString(SystemConstant.TYPE);
+        UploadFileEnum uploadType = Enum.valueOf(UploadFileEnum.class, (String) object.get(SystemConstant.UPLOAD_TYPE));
+
+        // 存储路径为空,使用默认值
+        rootPath = StringUtils.isNotBlank(rootPath) ? rootPath : TEMP_DIR;
+        // 存储文件名为空,使用默认值
+        fileName = StringUtils.isNotBlank(fileName) ? fileName : UUID.fastUUID() + basicAttachment.getType();
+        // 存储文件类型与附件类型不一样,默认改用附件类型
+        if (!fileName.endsWith(basicAttachment.getType())) {
+            fileName = UUID.fastUUID() + basicAttachment.getType();
+        }
+
+        // oss存储
+        if (type.equals(SystemConstant.OSS)) {
+            File localPath = new File(rootPath, fileName);
+            try {
+                return fileStoreUtil.ossDownload(filePath, localPath.getPath(), uploadType.getFssType());
+            } catch (IOException e) {
+                throw ExceptionResultEnum.ERROR.exception("从OSS上下载文件失败");
+            }
+        } else {
+            File file = new File(filePath);
+            if (!file.exists()) {
+                throw ExceptionResultEnum.ERROR.exception("本地文件不存在");
+            }
+            return file;
+        }
+    }
+
+    @Override
+    public void zipFiles(HttpServletResponse response, String filePath, String zipName, List<File> files) {
+        filePath = StringUtils.isNotBlank(filePath) ? filePath : TEMP_DIR;
+        File rootFile = new File(filePath);
+        // 创建保存目录
+        if (!rootFile.exists()) {
+            rootFile.mkdirs();
+        }
+        File zipFile = null;
+        try {
+            zipName = StringUtils.isNotBlank(zipName) ? zipName : UUID.fastUUID() + ".zip";
+            if (!zipName.endsWith(".zip")) {
+                throw ExceptionResultEnum.ERROR.exception("压缩文件必须为zip");
+            }
+            zipFile = FileUtil.file(filePath, zipName);
+            // 压缩文件
+            if (!zipFile.exists()) {
+                zipFile.createNewFile();
+            }
+            File[] srcFiles = files.toArray(new File[0]);
+            ZipUtil.zip(zipFile, true, srcFiles);
+            outputFile(response, zipFile, zipName);
+        } catch (Exception e) {
+            throw ExceptionResultEnum.ERROR.exception("下载失败");
+        } finally {
+            // 删除zip文件
+            FileUtil.del(zipFile);
+            // 删除压缩内容
+            FileUtil.del(filePath);
+        }
+    }
+
+    @Override
+    public void zipFiles(HttpServletResponse response, String filePath, String zipName) {
+        File rootFile = new File(filePath);
+        // 创建保存目录
+        if (!rootFile.exists()) {
+            throw ExceptionResultEnum.ERROR.exception("根目录不存在");
+        }
+        File zipFile = null;
+        try {
+            zipName = StringUtils.isNotBlank(zipName) ? zipName : UUID.fastUUID() + ".zip";
+            if (!zipName.endsWith(".zip")) {
+                throw ExceptionResultEnum.ERROR.exception("压缩文件必须为zip");
+            }
+            zipFile = FileUtil.file(TEMP_DIR, zipName);
+            // 压缩文件
+            if (!zipFile.exists()) {
+                zipFile.createNewFile();
+            }
+            ZipUtil.zip(filePath, zipFile.getAbsolutePath(), true);
+            outputFile(response, zipFile, zipName);
+        } catch (Exception e) {
+            throw ExceptionResultEnum.ERROR.exception("下载失败");
+        } finally {
+            // 删除zip文件
+            FileUtil.del(zipFile);
+            // 删除压缩内容
+            FileUtil.del(filePath);
+        }
+    }
+
+
+    public static void outputFile(HttpServletResponse response, File file, String fileName) {
+        try {
+
+            if (!file.exists()) {
+                response.sendError(404, "File not found!");
+            }
+
+            BufferedInputStream br = new BufferedInputStream(new FileInputStream(file));
+            byte[] buf = new byte[1024];
+            int len = 0;
+
+            String fName = new String(fileName.getBytes(), "ISO-8859-1");
+
+            response.reset();
+            response.setContentType("application/x-msdownload");
+            response.setHeader("Content-Disposition", "attachment; filename=" + fName);
+
+            OutputStream outStream = response.getOutputStream();
+
+            while ((len = br.read(buf)) > 0) {
+                outStream.write(buf, 0, len);
+            }
+
+            br.close();
+            outStream.close();
+        } catch (FileNotFoundException e) {
+            log.error(SystemConstant.LOG_ERROR, e);
+        } catch (IOException e) {
+            log.error(SystemConstant.LOG_ERROR, e);
+        }
+    }
+}