瀏覽代碼

Merge branch 'dev_v2.0.1' of http://git.qmth.com.cn/wangliang/distributed-print-service into dev_v2.0.1

xiaof 4 年之前
父節點
當前提交
e707485940
共有 50 個文件被更改,包括 1724 次插入116 次删除
  1. 0 11
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/ExamStudentCourseDto.java
  2. 4 4
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/ExaminationImportDto.java
  3. 65 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/SyncExamCardDto.java
  4. 40 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/SyncExamStudentDto.java
  5. 12 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/config/DictionaryConfig.java
  6. 80 8
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/domain/SmsDomain.java
  7. 47 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/domain/SyncDataDomain.java
  8. 10 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/ExamCard.java
  9. 21 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/ExamPrintPlan.java
  10. 10 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/ExamStudent.java
  11. 175 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/TBSyncTask.java
  12. 2 2
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/enums/MessageEnum.java
  13. 2 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/enums/TaskTypeEnum.java
  14. 3 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/ExamCardMapper.java
  15. 5 2
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/ExamDetailMapper.java
  16. 3 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/ExamStudentMapper.java
  17. 2 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/ExamTaskMapper.java
  18. 12 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/TBSyncTaskMapper.java
  19. 11 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/DataSyncService.java
  20. 3 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/ExamCardService.java
  21. 5 2
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/ExamDetailService.java
  22. 2 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/ExamPrintPlanService.java
  23. 3 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/ExamStudentService.java
  24. 5 4
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/ExamTaskService.java
  25. 15 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/TBSyncTaskService.java
  26. 38 2
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/BasicMessageServiceImpl.java
  27. 372 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/DataSyncServiceImpl.java
  28. 6 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamCardServiceImpl.java
  29. 9 4
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamDetailServiceImpl.java
  30. 8 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamPrintPlanServiceImpl.java
  31. 6 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamStudentServiceImpl.java
  32. 31 1
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamTaskServiceImpl.java
  33. 40 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/TBSyncTaskServiceImpl.java
  34. 3 1
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/TBTaskServiceImpl.java
  35. 69 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/execute/AsyncPaperReviewPdfExportService.java
  36. 8 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/service/TaskLogicService.java
  37. 113 5
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/service/impl/TaskLogicServiceImpl.java
  38. 55 12
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/util/CreatePdfUtil.java
  39. 198 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/util/HttpKit.java
  40. 1 1
      distributed-print-business/src/main/resources/db/init-data.sql
  41. 27 0
      distributed-print-business/src/main/resources/db/init-table.sql
  42. 24 0
      distributed-print-business/src/main/resources/mapper/ExamCardMapper.xml
  43. 25 0
      distributed-print-business/src/main/resources/mapper/ExamDetailMapper.xml
  44. 23 0
      distributed-print-business/src/main/resources/mapper/ExamStudentMapper.xml
  45. 4 0
      distributed-print-business/src/main/resources/mapper/TBSyncTaskMapper.xml
  46. 13 0
      distributed-print-task/src/main/java/com/qmth/distributed/print/task/job/service/impl/JobServiceImpl.java
  47. 15 3
      distributed-print/src/main/java/com/qmth/distributed/print/api/ExamPrintPlanController.java
  48. 45 26
      distributed-print/src/main/java/com/qmth/distributed/print/api/ExamTaskController.java
  49. 23 25
      distributed-print/src/main/java/com/qmth/distributed/print/start/StartRunning.java
  50. 31 3
      distributed-print/src/main/resources/application.properties

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

@@ -28,17 +28,6 @@ public class ExamStudentCourseDto extends ExamStudent {
     @ApiModelProperty("试卷编号")
     private String paperNumber;
 
-    @ApiModelProperty("排序用")
-    String ascii;
-
-    public String getAscii() {
-        return ascii;
-    }
-
-    public void setAscii(String ascii) {
-        this.ascii = ascii;
-    }
-
     public String getPaperNumber() {
         return paperNumber;
     }

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

@@ -13,19 +13,19 @@ import java.util.List;
 public class ExaminationImportDto {
 
     @ApiModelProperty(value = "学号")
-    @ExcelDBFieldDesc(name = "学号",length = 20)
+    @ExcelDBFieldDesc(name = "学号",length = 30)
     private String studentCode;
 
     @ApiModelProperty(value = "考号")
-    @ExcelDBFieldDesc(name = "考号",length = 20)
+    @ExcelDBFieldDesc(name = "考号",length = 30)
     private String ticketNumber;
 
     @ApiModelProperty(value = "座位号")
-    @ExcelDBFieldDesc(name = "座位号",length = 15)
+    @ExcelDBFieldDesc(name = "座位号",length = 30)
     private String siteNumber;
 
     @ApiModelProperty(value = "姓名")
-    @ExcelDBFieldDesc(name = "姓名",length = 50)
+    @ExcelDBFieldDesc(name = "姓名",length = 30)
     private String studentName;
 
     @ApiModelProperty(value = "课程代码")

+ 65 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/SyncExamCardDto.java

@@ -0,0 +1,65 @@
+package com.qmth.distributed.print.business.bean.dto;
+
+import com.qmth.distributed.print.business.entity.ExamCard;
+
+/**
+ * @Description: 题卡同步 DTO
+ */
+public class SyncExamCardDto extends ExamCard {
+
+    private String courseCode;
+
+    private String courseName;
+
+    private String paperNumber;
+
+    private String title;
+
+    private String content;
+
+    @Override
+    public String getCourseCode() {
+        return courseCode;
+    }
+
+    @Override
+    public void setCourseCode(String courseCode) {
+        this.courseCode = courseCode;
+    }
+
+    @Override
+    public String getCourseName() {
+        return courseName;
+    }
+
+    @Override
+    public void setCourseName(String courseName) {
+        this.courseName = courseName;
+    }
+
+    public String getPaperNumber() {
+        return paperNumber;
+    }
+
+    public void setPaperNumber(String paperNumber) {
+        this.paperNumber = paperNumber;
+    }
+
+    @Override
+    public String getTitle() {
+        return title;
+    }
+
+    @Override
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+}

+ 40 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/SyncExamStudentDto.java

@@ -0,0 +1,40 @@
+package com.qmth.distributed.print.business.bean.dto;
+
+import com.qmth.distributed.print.business.entity.ExamStudent;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @Description: 考生同步 DTO
+ */
+public class SyncExamStudentDto extends ExamStudent {
+
+    private String courseCode;
+
+    private String courseName;
+
+    private String paperNumber;
+
+    public String getCourseCode() {
+        return courseCode;
+    }
+
+    public void setCourseCode(String courseCode) {
+        this.courseCode = courseCode;
+    }
+
+    public String getCourseName() {
+        return courseName;
+    }
+
+    public void setCourseName(String courseName) {
+        this.courseName = courseName;
+    }
+
+    public String getPaperNumber() {
+        return paperNumber;
+    }
+
+    public void setPaperNumber(String paperNumber) {
+        this.paperNumber = paperNumber;
+    }
+}

+ 12 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/config/DictionaryConfig.java

@@ -69,4 +69,16 @@ public class DictionaryConfig {
     public OrgCenterDomain orgCenterDomain() {
         return new OrgCenterDomain();
     }
+
+
+    /**
+     * 机构用户中心配置
+     *
+     * @return
+     */
+    @Bean
+    @ConfigurationProperties(prefix = "sync.config", ignoreUnknownFields = false)
+    public SyncDataDomain syncDataDomain() {
+        return new SyncDataDomain();
+    }
 }

+ 80 - 8
distributed-print-business/src/main/java/com/qmth/distributed/print/business/domain/SmsDomain.java

@@ -6,22 +6,23 @@ package com.qmth.distributed.print.business.domain;
 public class SmsDomain {
 
     String smsNormalCode;
-
     Integer codeExpiredTime;
-
     Integer codeSendInterval;
-
     String aliyunSMSKey;
-
     String aliyunSMSSecret;
-
     String aliyunSMSSignName;
-
     String aliyunSMSTplCode;
-
     String aliyunSMSAuditPassCode;
-
     String aliyunSMSAuditNotPassCode;
+    String aliyunSMSExamTaskCreatedCode;
+    String aliyunSMSExamTaskWillExpireCode;
+    String aliyunSMSExamTaskOverdueCode;
+    String aliyunSMSAllocationWillExpireCode;
+    String aliyunSMSAllocationOverdueCode;
+    String aliyunSMSAuditCreatedCode;
+    String aliyunSMSAuditReviewCode;
+    String aliyunSMSAuditWillExpireCode;
+    String aliyunSMSAuditOverdueCode;
 
     public String getSmsNormalCode() {
         return smsNormalCode;
@@ -95,4 +96,75 @@ public class SmsDomain {
         this.aliyunSMSAuditNotPassCode = aliyunSMSAuditNotPassCode;
     }
 
+    public String getAliyunSMSExamTaskCreatedCode() {
+        return aliyunSMSExamTaskCreatedCode;
+    }
+
+    public void setAliyunSMSExamTaskCreatedCode(String aliyunSMSExamTaskCreatedCode) {
+        this.aliyunSMSExamTaskCreatedCode = aliyunSMSExamTaskCreatedCode;
+    }
+
+    public String getAliyunSMSExamTaskWillExpireCode() {
+        return aliyunSMSExamTaskWillExpireCode;
+    }
+
+    public void setAliyunSMSExamTaskWillExpireCode(String aliyunSMSExamTaskWillExpireCode) {
+        this.aliyunSMSExamTaskWillExpireCode = aliyunSMSExamTaskWillExpireCode;
+    }
+
+    public String getAliyunSMSExamTaskOverdueCode() {
+        return aliyunSMSExamTaskOverdueCode;
+    }
+
+    public void setAliyunSMSExamTaskOverdueCode(String aliyunSMSExamTaskOverdueCode) {
+        this.aliyunSMSExamTaskOverdueCode = aliyunSMSExamTaskOverdueCode;
+    }
+
+    public String getAliyunSMSAllocationWillExpireCode() {
+        return aliyunSMSAllocationWillExpireCode;
+    }
+
+    public void setAliyunSMSAllocationWillExpireCode(String aliyunSMSAllocationWillExpireCode) {
+        this.aliyunSMSAllocationWillExpireCode = aliyunSMSAllocationWillExpireCode;
+    }
+
+    public String getAliyunSMSAllocationOverdueCode() {
+        return aliyunSMSAllocationOverdueCode;
+    }
+
+    public void setAliyunSMSAllocationOverdueCode(String aliyunSMSAllocationOverdueCode) {
+        this.aliyunSMSAllocationOverdueCode = aliyunSMSAllocationOverdueCode;
+    }
+
+    public String getAliyunSMSAuditCreatedCode() {
+        return aliyunSMSAuditCreatedCode;
+    }
+
+    public void setAliyunSMSAuditCreatedCode(String aliyunSMSAuditCreatedCode) {
+        this.aliyunSMSAuditCreatedCode = aliyunSMSAuditCreatedCode;
+    }
+
+    public String getAliyunSMSAuditReviewCode() {
+        return aliyunSMSAuditReviewCode;
+    }
+
+    public void setAliyunSMSAuditReviewCode(String aliyunSMSAuditReviewCode) {
+        this.aliyunSMSAuditReviewCode = aliyunSMSAuditReviewCode;
+    }
+
+    public String getAliyunSMSAuditWillExpireCode() {
+        return aliyunSMSAuditWillExpireCode;
+    }
+
+    public void setAliyunSMSAuditWillExpireCode(String aliyunSMSAuditWillExpireCode) {
+        this.aliyunSMSAuditWillExpireCode = aliyunSMSAuditWillExpireCode;
+    }
+
+    public String getAliyunSMSAuditOverdueCode() {
+        return aliyunSMSAuditOverdueCode;
+    }
+
+    public void setAliyunSMSAuditOverdueCode(String aliyunSMSAuditOverdueCode) {
+        this.aliyunSMSAuditOverdueCode = aliyunSMSAuditOverdueCode;
+    }
 }

+ 47 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/domain/SyncDataDomain.java

@@ -0,0 +1,47 @@
+package com.qmth.distributed.print.business.domain;
+
+/**
+ * @Description: 同步云阅卷参数
+ */
+public class SyncDataDomain {
+
+    String hostUrl;
+
+    String examSaveUrl;
+
+    String studentSaveUrl;
+
+    String cardUploadUrl;
+
+    public String getHostUrl() {
+        return hostUrl;
+    }
+
+    public void setHostUrl(String hostUrl) {
+        this.hostUrl = hostUrl;
+    }
+
+    public String getExamSaveUrl() {
+        return examSaveUrl;
+    }
+
+    public void setExamSaveUrl(String examSaveUrl) {
+        this.examSaveUrl = examSaveUrl;
+    }
+
+    public String getStudentSaveUrl() {
+        return studentSaveUrl;
+    }
+
+    public void setStudentSaveUrl(String studentSaveUrl) {
+        this.studentSaveUrl = studentSaveUrl;
+    }
+
+    public String getCardUploadUrl() {
+        return cardUploadUrl;
+    }
+
+    public void setCardUploadUrl(String cardUploadUrl) {
+        this.cardUploadUrl = cardUploadUrl;
+    }
+}

+ 10 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/ExamCard.java

@@ -58,6 +58,9 @@ public class ExamCard extends BaseEntity implements Serializable {
     @TableField("template_id")
     private Long templateId;
 
+    @TableField("sync_status")
+    private Boolean syncStatus;
+
     public Long getSchoolId() {
         return schoolId;
     }
@@ -122,4 +125,11 @@ public class ExamCard extends BaseEntity implements Serializable {
         this.templateId = templateId;
     }
 
+    public Boolean getSyncStatus() {
+        return syncStatus;
+    }
+
+    public void setSyncStatus(Boolean syncStatus) {
+        this.syncStatus = syncStatus;
+    }
 }

+ 21 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/ExamPrintPlan.java

@@ -90,6 +90,12 @@ public class ExamPrintPlan extends BaseEntity implements Serializable {
     private String ordinaryContent;
     private PrintPlanStatusEnum status;
 
+    @TableField("third_relate_id")
+    private Long thirdRelateId;
+
+    @TableField("sync_status")
+    private Boolean syncStatus;
+
     public Long getSchoolId() {
         return schoolId;
     }
@@ -178,4 +184,19 @@ public class ExamPrintPlan extends BaseEntity implements Serializable {
         this.status = status;
     }
 
+    public Long getThirdRelateId() {
+        return thirdRelateId;
+    }
+
+    public void setThirdRelateId(Long thirdRelateId) {
+        this.thirdRelateId = thirdRelateId;
+    }
+
+    public Boolean getSyncStatus() {
+        return syncStatus;
+    }
+
+    public void setSyncStatus(Boolean syncStatus) {
+        this.syncStatus = syncStatus;
+    }
 }

+ 10 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/ExamStudent.java

@@ -50,6 +50,8 @@ public class ExamStudent extends BaseEntity implements Serializable {
     @ApiModelProperty(value = "附件id")
     @TableField(value = "attachment_id")
     private Long attachmentId;
+    @TableField(value = "sync_status")
+    private Boolean syncStatus;
 
     public static long getSerialVersionUID() {
         return serialVersionUID;
@@ -142,4 +144,12 @@ public class ExamStudent extends BaseEntity implements Serializable {
     public void setPaperType(String paperType) {
         this.paperType = paperType;
     }
+
+    public Boolean getSyncStatus() {
+        return syncStatus;
+    }
+
+    public void setSyncStatus(Boolean syncStatus) {
+        this.syncStatus = syncStatus;
+    }
 }

+ 175 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/TBSyncTask.java

@@ -0,0 +1,175 @@
+package com.qmth.distributed.print.business.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.qmth.distributed.print.business.enums.TaskResultEnum;
+import com.qmth.distributed.print.business.enums.TaskStatusEnum;
+import com.qmth.distributed.print.business.enums.TaskTypeEnum;
+import com.qmth.distributed.print.common.contant.SystemConstant;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 同步任务表
+ * </p>
+ */
+@ApiModel(value = "TBSyncTask对象", description = "同步任务表")
+public class TBSyncTask implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @JsonSerialize(using = ToStringSerializer.class)
+    @ApiModelProperty(value = "主键")
+    @TableId(value = "id")
+    private Long id;
+
+    @JsonSerialize(using = ToStringSerializer.class)
+    @ApiModelProperty(value = "学校id")
+    @TableField(value = "school_id")
+    private Long schoolId;
+
+    @JsonSerialize(using = ToStringSerializer.class)
+    @ApiModelProperty(value = "印刷计划id")
+    @TableField(value = "print_plan_id")
+    private Long printPlanId;
+
+    @ApiModelProperty(value = "印刷计划名称")
+    @TableField(value = "print_plan_name")
+    private String printPlanName;
+
+    @ApiModelProperty(value = "任务状态,INIT:未开始,RUNNING:进行中,FINISH:已完成")
+    @TableField(value = "status")
+    private TaskStatusEnum status;
+
+    @ApiModelProperty(value = "实时摘要信息")
+    @TableField(value = "summary")
+    private String summary;
+
+    @ApiModelProperty(value = "数据结果,SUCCESS:成功,ERROR:失败")
+    @TableField(value = "result")
+    private TaskResultEnum result;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "create_time", fill = FieldFill.INSERT)//新增执行
+    private Long createTime;
+
+    @JsonSerialize(using = ToStringSerializer.class)
+    @ApiModelProperty(value = "创建人id")
+    @TableField("create_id")
+    private Long createId;
+
+    @ApiModelProperty(value = "备注")
+    @TableField(value = "remark")
+    private String remark;
+
+    @ApiModelProperty(value = "重试次数")
+    @TableField(value = "reset_count")
+    private int resetCount;
+
+    @ApiModelProperty(value = "错误原因")
+    @TableField(value = "error_message", updateStrategy = FieldStrategy.IGNORED)
+    private String errorMessage;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getSchoolId() {
+        return schoolId;
+    }
+
+    public void setSchoolId(Long schoolId) {
+        this.schoolId = schoolId;
+    }
+
+    public Long getPrintPlanId() {
+        return printPlanId;
+    }
+
+    public void setPrintPlanId(Long printPlanId) {
+        this.printPlanId = printPlanId;
+    }
+
+    public String getPrintPlanName() {
+        return printPlanName;
+    }
+
+    public void setPrintPlanName(String printPlanName) {
+        this.printPlanName = printPlanName;
+    }
+
+    public TaskStatusEnum getStatus() {
+        return status;
+    }
+
+    public void setStatus(TaskStatusEnum status) {
+        this.status = status;
+    }
+
+    public String getSummary() {
+        return summary;
+    }
+
+    public void setSummary(String summary) {
+        this.summary = summary;
+    }
+
+    public TaskResultEnum getResult() {
+        return result;
+    }
+
+    public void setResult(TaskResultEnum result) {
+        this.result = result;
+    }
+
+    public Long getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Long createTime) {
+        this.createTime = createTime;
+    }
+
+    public Long getCreateId() {
+        return createId;
+    }
+
+    public void setCreateId(Long createId) {
+        this.createId = createId;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    public int getResetCount() {
+        return resetCount;
+    }
+
+    public void setResetCount(int resetCount) {
+        this.resetCount = resetCount;
+    }
+
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    public void setErrorMessage(String errorMessage) {
+        this.errorMessage = errorMessage;
+    }
+}

+ 2 - 2
distributed-print-business/src/main/java/com/qmth/distributed/print/business/enums/MessageEnum.java

@@ -31,8 +31,8 @@ public enum MessageEnum {
      * 审核待办提醒
      */
     // 命题任务被命题老师提交后触发,业务id为命题任务id,短信发送给考务老师 examTask.getCreateId()
-    NOTICE_OF_AUDIT_CREATED("审核待办生成通知","${userName}您好,${courseName}课程、${paperNumber}试卷已提交入库,请您尽快审核!"),
-    NOTICE_OF_AUDIT_REVIEW("审核待办修改申请通知","${userName}您好,${courseName}课程、${paperNumber}试卷重新提交修改申请,请您尽快审核!"),
+    NOTICE_OF_AUDIT_CREATED("审核待办生成通知","${userName}您好,${courseNameAndPaperNumber}试卷已提交入库,请您尽快审核!"),
+    NOTICE_OF_AUDIT_REVIEW("审核待办修改申请通知","${userName}您好,${courseNameAndPaperNumber}试卷重新提交修改申请,请您尽快审核!"),
     // 定时任务查询触发,业务id为考务老师id,短信发送给考务老师
     NOTICE_OF_AUDIT_WILL_EXPIRE("审核待办到期预警通知","${userName}您好,您还有${count}条审核待办即将逾期,请您尽快处理!"),
     NOTICE_OF_AUDIT_OVERDUE("审核待办逾期通知","${userName}您好,您有${count}条审核待办已逾期!"),

+ 2 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/enums/TaskTypeEnum.java

@@ -21,6 +21,8 @@ public enum TaskTypeEnum {
 
     PRINT_PDF_DOWNLOAD("批量下载pdf"),
 
+    PAPER_AND_CARD_PDF_DOWNLOAD("卷库查询管理试卷、空白题卡批量下载pdf"),
+
     CREATE_PDF("生成pdf");
 
     private String title;

+ 3 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/ExamCardMapper.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.qmth.distributed.print.business.bean.dto.CardCustDto;
 import com.qmth.distributed.print.business.bean.dto.CardDetailDto;
+import com.qmth.distributed.print.business.bean.dto.SyncExamCardDto;
 import com.qmth.distributed.print.business.entity.ExamCard;
 import org.apache.ibatis.annotations.Param;
 
@@ -29,4 +30,6 @@ public interface ExamCardMapper extends BaseMapper<ExamCard> {
     List<ExamCard> listCustom(@Param("schoolId") Long schoolId, @Param("orgId") Long orgId, @Param("courseCode") String courseCode, @Param("type") String type);
 
     CardDetailDto getCardDetailBySelect(Long cardId);
+
+    List<SyncExamCardDto> listSyncCardByCourseCodeAndPaperNumber(@Param("schoolId") Long schoolId, @Param("courseCode") String courseCode, @Param("paperNumber") String paperNumber);
 }

+ 5 - 2
distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/ExamDetailMapper.java

@@ -7,6 +7,7 @@ import com.qmth.distributed.print.business.bean.dto.*;
 import com.qmth.distributed.print.business.bean.result.ExaminationDetailResult;
 import com.qmth.distributed.print.business.bean.result.ExaminationResult;
 import com.qmth.distributed.print.business.entity.ExamDetail;
+import com.qmth.distributed.print.business.entity.ExamDetailCourse;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
@@ -23,7 +24,7 @@ import java.util.Set;
  */
 public interface ExamDetailMapper extends BaseMapper<ExamDetail> {
 
-    IPage<PrintTaskDto> listPrintTask(Page<PrintTaskDto> page, @Param("schoolId") Long schoolId, @Param("printPlanId") Long printPlanId, @Param("status") String status, @Param("courseCode") String courseCode, @Param("paperNumber") String paperNumber, @Param("examPlace") String examPlace, @Param("examRoom") String examRoom, @Param("examStartTime") Long examStartTime, @Param("examEndTime") Long examEndTime, @Param("orgIds") Set<Long> orgIds);
+    IPage<PrintTaskDto> listPrintTask(Page<PrintTaskDto> page, @Param("schoolId") Long schoolId, @Param("printPlanId") Long printPlanId, @Param("status") String status, @Param("courseCode") String courseCode, @Param("paperNumber") String paperNumber, @Param("examPlace") String examPlace, @Param("examRoom") String examRoom, @Param("examStartTime") Long examStartTime, @Param("examEndTime") Long examEndTime, @Param("printStartTime") Long printStartTime, @Param("printEndTime") Long printEndTime, @Param("orgIds") Set<Long> orgIds);
 
     IPage<ExaminationResult> findBriefPage(@Param("page") Page<ExaminationResult> page,
                                            @Param("schoolId") Long schoolId,
@@ -48,11 +49,13 @@ public interface ExamDetailMapper extends BaseMapper<ExamDetail> {
     IPage<ExaminationDetailResult> findDetailPageById(@Param("page") Page<ExaminationDetailResult> page,
                                                   @Param("examDetailId") Long examDetailId);
 
-    PrintTaskTotalDto taskTotalData(@Param("schoolId") Long schoolId, @Param("printPlanId") Long printPlanId, @Param("status") String status, @Param("courseCode") String courseCode, @Param("paperNumber") String paperNumber, @Param("examPlace") String examPlace, @Param("examRoom") String examRoom, @Param("examStartTime") Long examStartTime, @Param("examEndTime") Long examEndTime, @Param("orgIds") Set<Long> orgIds);
+    PrintTaskTotalDto taskTotalData(@Param("schoolId") Long schoolId, @Param("printPlanId") Long printPlanId, @Param("status") String status, @Param("courseCode") String courseCode, @Param("paperNumber") String paperNumber, @Param("examPlace") String examPlace, @Param("examRoom") String examRoom, @Param("examStartTime") Long examStartTime, @Param("examEndTime") Long examEndTime, @Param("printStartTime") Long printStartTime, @Param("printEndTime") Long printEndTime, @Param("orgIds") Set<Long> orgIds);
 
     IPage<ClientExamStudentDto> listClientExamStudentPage(Page<ClientExamStudentDto> page, @Param("schoolId") Long schoolId, @Param("examDetailId") Long examDetailId, @Param("ticketNumber") String ticketNumber, @Param("studentName") String studentName, @Param("courseCode") String courseCode);
 
     List<Map> listStudentByExamDetailId(@Param("schoolId") Long schoolId, @Param("examDetailId") Long examDetailId, @Param("ticketNumber") String ticketNumber, @Param("type") String type);
 
     Integer selectPaperCount(@Param("schoolId") Long schoolId, @Param("printPlanId") Long printPlanId, @Param("status") String status, @Param("courseCode") String courseCode, @Param("paperNumber") String paperNumber, @Param("examPlace") String examPlace, @Param("examRoom") String examRoom, @Param("examStartTime") Long examStartTime, @Param("examEndTime") Long examEndTime, @Param("orgIds") Set<Long> orgIds);
+
+    List<ExamDetailCourse> listSyncPaperNumberByPrintPlanId(Long printPlanId);
 }

+ 3 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/ExamStudentMapper.java

@@ -2,6 +2,7 @@ package com.qmth.distributed.print.business.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qmth.distributed.print.business.bean.dto.ExamStudentCourseDto;
+import com.qmth.distributed.print.business.bean.dto.SyncExamStudentDto;
 import com.qmth.distributed.print.business.entity.ExamStudent;
 import org.apache.ibatis.annotations.Param;
 
@@ -28,4 +29,6 @@ public interface ExamStudentMapper extends BaseMapper<ExamStudent> {
      * @return
      */
     List<ExamStudentCourseDto> queryBySchoolIdAndExamDetailCourseIds(@Param("schoolId") Long schoolId, @Param("examDetailCourseIds") List<Long> examDetailCourseIds);
+
+    List<SyncExamStudentDto> listStudentByPrintPlanIdAndSyncStatus(Long printPlanId);
 }

+ 2 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/ExamTaskMapper.java

@@ -87,4 +87,6 @@ public interface ExamTaskMapper extends BaseMapper<ExamTask> {
     List<ExamTask> listExamTaskExpire(@Param("startTime") Long startTime, @Param("endTime") Long endTime, @Param("status") String[] status);
 
     List<ExamTask> listExamTaskAuditExpire(@Param("startTime") Long startTime, @Param("endTime") Long endTime);
+
+    List<ExamTaskDetailDto> listTaskPaper(@Param("schoolId") Long schoolId, @Param("courseCode") String courseCode, @Param("paperNumber") String paperNumber, @Param("startTime") Long startTime, @Param("endTime") Long endTime, @Param("orgIds") Set<Long> orgIds, @Param("containsQuestionTeacher") boolean containsQuestionTeacher, @Param("userId") Long userId);
 }

+ 12 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/TBSyncTaskMapper.java

@@ -0,0 +1,12 @@
+package com.qmth.distributed.print.business.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.qmth.distributed.print.business.entity.TBSyncTask;
+
+/**
+ * <p>
+ * 同步数据 Mapper 接口
+ * </p>
+ */
+public interface TBSyncTaskMapper extends BaseMapper<TBSyncTask> {
+}

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

@@ -0,0 +1,11 @@
+package com.qmth.distributed.print.business.service;
+
+/**
+ * 同步数据到云阅卷 服务类
+ * @Date: 2021/5/20.
+ */
+public interface DataSyncService {
+    void syncToCloudReview();
+
+    void syncDataCloud(Long printPlanId);
+}

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

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.qmth.distributed.print.business.bean.dto.CardCustDto;
 import com.qmth.distributed.print.business.bean.dto.CardDetailDto;
+import com.qmth.distributed.print.business.bean.dto.SyncExamCardDto;
 import com.qmth.distributed.print.business.bean.params.ArraysParams;
 import com.qmth.distributed.print.business.bean.params.ExamCardParams;
 import com.qmth.distributed.print.business.entity.ExamCard;
@@ -36,4 +37,6 @@ public interface ExamCardService extends IService<ExamCard> {
     List<ExamCard> listSelectCard(String courseCode, Long cardRuleId, String paperType);
 
     void downloadFiles(HttpServletResponse response, ArraysParams arraysParams);
+
+    List<SyncExamCardDto> listSyncCardByCourseCodeAndPaperNumber(Long schoolId, String courseCode, String paperNumber);
 }

+ 5 - 2
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/ExamDetailService.java

@@ -8,6 +8,7 @@ import com.qmth.distributed.print.business.bean.result.ExaminationDetailResult;
 import com.qmth.distributed.print.business.bean.result.ExaminationResult;
 import com.qmth.distributed.print.business.bean.result.SummarizedDataResult;
 import com.qmth.distributed.print.business.entity.ExamDetail;
+import com.qmth.distributed.print.business.entity.ExamDetailCourse;
 
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
@@ -38,9 +39,9 @@ public interface ExamDetailService extends IService<ExamDetail> {
      */
     double calculateTotalPackages(Long printPlanId);
 
-    IPage<PrintTaskDto> listPrintTask(Long printPlanId, String status, String courseCode, String paperNumber, String examPlace, String examRoom, Long examStartTime, Long examEndTime, Integer pageNumber, Integer pageSize);
+    IPage<PrintTaskDto> listPrintTask(Long printPlanId, String status, String courseCode, String paperNumber, String examPlace, String examRoom, Long examStartTime, Long examEndTime, Long printStartTime, Long printEndTime, Integer pageNumber, Integer pageSize);
 
-    PrintTaskTotalDto taskTotalData(Long printPlanId, String status, String courseCode, String paperNumber, String examPlace, String examRoom, Long examStartTime, Long examEndTime);
+    PrintTaskTotalDto taskTotalData(Long printPlanId, String status, String courseCode, String paperNumber, String examPlace, String examRoom, Long examStartTime, Long examEndTime, Long printStartTime, Long printEndTime);
 
     String taskViewPDF(Long examDetailId);
 
@@ -182,4 +183,6 @@ public interface ExamDetailService extends IService<ExamDetail> {
     List<ExamDetail> listByCourseCodeAndPaperNumberAndPaperTypeIsNull(Long schoolId, String courseCode, String paperNumber);
 
     List<ExamDetail> listByCourseCodeAndPaperNumber(Long schoolId, String courseCode, String paperNumber);
+
+    List<ExamDetailCourse> listSyncPaperNumberByPrintPlanId(Long printPlanId);
 }

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

@@ -87,4 +87,6 @@ public interface ExamPrintPlanService extends IService<ExamPrintPlan> {
     IPage<ClientPrintStatisticsDto> listClientPrintStatistics(Page<ClientPrintStatisticsDto> page, Long schoolId, String printPlanId, String examPlace, Long examStartTime, Long examEndTime, String courseCode, String paperNumber, Set<Long> orgIds);
 
     ClientPrintStatisticsTotalDto clientStatisticsTotalData(String printPlanId, String examPlace, Long examStartTime, Long examEndTime, String courseCode, String paperNumber);
+
+    void syncDataCloud(Long printPlanId);
 }

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

@@ -2,6 +2,7 @@ package com.qmth.distributed.print.business.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.qmth.distributed.print.business.bean.dto.ExamStudentCourseDto;
+import com.qmth.distributed.print.business.bean.dto.SyncExamStudentDto;
 import com.qmth.distributed.print.business.entity.ExamDetailCourse;
 import com.qmth.distributed.print.business.entity.ExamStudent;
 
@@ -32,4 +33,6 @@ public interface ExamStudentService extends IService<ExamStudent> {
      * @return
      */
     List<ExamStudentCourseDto> queryBySchoolIdAndExamDetailCourseIds(Long schoolId, List<Long> examDetailCourseIds);
+
+    List<SyncExamStudentDto> listStudentByPrintPlanIdAndSyncStatus(Long printPlanId);
 }

+ 5 - 4
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/ExamTaskService.java

@@ -4,10 +4,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.qmth.distributed.print.business.bean.dto.*;
 import com.qmth.distributed.print.business.bean.result.WorkResult;
-import com.qmth.distributed.print.business.entity.ExamTask;
-import com.qmth.distributed.print.business.entity.ExamTaskDetail;
-import com.qmth.distributed.print.business.entity.ExamTaskReviewLog;
-import com.qmth.distributed.print.business.entity.SysUser;
+import com.qmth.distributed.print.business.entity.*;
 import com.qmth.distributed.print.business.enums.ExamStatusEnum;
 import org.springframework.web.multipart.MultipartFile;
 
@@ -132,4 +129,8 @@ public interface ExamTaskService extends IService<ExamTask> {
      * 发送已逾期数据短信提醒
      */
     void sendSmsOverdueTask();
+
+    List<ExamTaskDetailDto> listTaskPaper(String courseCode, String paperNumber, Long startTime, Long endTime);
+
+    TBTask taskDownloadPdf(String courseCode, String paperNumber, Long startTime, Long endTime);
 }

+ 15 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/TBSyncTaskService.java

@@ -0,0 +1,15 @@
+package com.qmth.distributed.print.business.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.qmth.distributed.print.business.entity.ExamPrintPlan;
+import com.qmth.distributed.print.business.entity.TBSyncTask;
+
+/**
+ * <p>
+ * 同步数据 服务类
+ * </p>
+ */
+public interface TBSyncTaskService extends IService<TBSyncTask> {
+
+    TBSyncTask saveTask(ExamPrintPlan examPrintPlan);
+}

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

@@ -223,8 +223,8 @@ public class BasicMessageServiceImpl extends ServiceImpl<BasicMessageMapper, Bas
 
             Map<String, Object> jsonMap = new HashMap<>();
             jsonMap.put("userName", userName);
-            jsonMap.put("courseName", examTask.getCourseName());
-            jsonMap.put("paperNumber", examTask.getPaperNumber());
+            StringJoiner sj = new StringJoiner("、").add(examTask.getCourseName()).add(examTask.getPaperNumber());
+            jsonMap.put("courseNameAndPaperNumber", sj.toString());
             String variableParams = JSON.toJSONString(jsonMap);
             String remark = String.format("命题任务ID:%s", examTask.getId().toString());
             this.saveMessageSendLog(userId, mobileNumber, examTask.getId(), variableParams, sysUser.getId(), messageType, remark);
@@ -322,6 +322,42 @@ public class BasicMessageServiceImpl extends ServiceImpl<BasicMessageMapper, Bas
                 templateCode = dictionaryConfig.smsDomain().getAliyunSMSAuditNotPassCode();
                 templateContent = messageEnum.getTemplate();
                 break;
+            case NOTICE_OF_EXAM_TASK_CREATED:
+                templateCode = dictionaryConfig.smsDomain().getAliyunSMSExamTaskCreatedCode();
+                templateContent = messageEnum.getTemplate();
+                break;
+            case NOTICE_OF_EXAM_TASK_WILL_EXPIRE:
+                templateCode = dictionaryConfig.smsDomain().getAliyunSMSExamTaskWillExpireCode();
+                templateContent = messageEnum.getTemplate();
+                break;
+            case NOTICE_OF_EXAM_TASK_OVERDUE:
+                templateCode = dictionaryConfig.smsDomain().getAliyunSMSExamTaskOverdueCode();
+                templateContent = messageEnum.getTemplate();
+                break;
+            case NOTICE_OF_ALLOCATION_WILL_EXPIRE:
+                templateCode = dictionaryConfig.smsDomain().getAliyunSMSAllocationWillExpireCode();
+                templateContent = messageEnum.getTemplate();
+                break;
+            case NOTICE_OF_ALLOCATION_OVERDUE:
+                templateCode = dictionaryConfig.smsDomain().getAliyunSMSAllocationOverdueCode();
+                templateContent = messageEnum.getTemplate();
+                break;
+            case NOTICE_OF_AUDIT_CREATED:
+                templateCode = dictionaryConfig.smsDomain().getAliyunSMSAuditCreatedCode();
+                templateContent = messageEnum.getTemplate();
+                break;
+            case NOTICE_OF_AUDIT_REVIEW:
+                templateCode = dictionaryConfig.smsDomain().getAliyunSMSAuditReviewCode();
+                templateContent = messageEnum.getTemplate();
+                break;
+            case NOTICE_OF_AUDIT_WILL_EXPIRE:
+                templateCode = dictionaryConfig.smsDomain().getAliyunSMSAuditWillExpireCode();
+                templateContent = messageEnum.getTemplate();
+                break;
+            case NOTICE_OF_AUDIT_OVERDUE:
+                templateCode = dictionaryConfig.smsDomain().getAliyunSMSAuditOverdueCode();
+                templateContent = messageEnum.getTemplate();
+                break;
         }
         result.put("templateContent", templateContent);
         result.put("templateCode", templateCode);

+ 372 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/DataSyncServiceImpl.java

@@ -0,0 +1,372 @@
+package com.qmth.distributed.print.business.service.impl;
+
+import cn.hutool.core.date.DateUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.qmth.boot.tools.signature.SignatureType;
+import com.qmth.distributed.print.business.bean.dto.SyncExamCardDto;
+import com.qmth.distributed.print.business.bean.dto.SyncExamStudentDto;
+import com.qmth.distributed.print.business.config.DictionaryConfig;
+import com.qmth.distributed.print.business.entity.*;
+import com.qmth.distributed.print.business.enums.PrintPlanStatusEnum;
+import com.qmth.distributed.print.business.enums.TaskResultEnum;
+import com.qmth.distributed.print.business.enums.TaskStatusEnum;
+import com.qmth.distributed.print.business.service.*;
+import com.qmth.distributed.print.business.util.HttpKit;
+import com.qmth.distributed.print.common.SignatureEntityTest;
+import com.qmth.distributed.print.common.contant.SystemConstant;
+import com.qmth.distributed.print.common.enums.ExceptionResultEnum;
+import org.apache.commons.codec.digest.DigestUtils;
+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.util.CollectionUtils;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * @Date: 2021/5/20.
+ */
+@Service
+public class DataSyncServiceImpl implements DataSyncService {
+
+    @Autowired
+    private ExamPrintPlanService examPrintPlanService;
+
+    @Autowired
+    private TBSyncTaskService tbSyncTaskService;
+
+    @Autowired
+    private DictionaryConfig dictionaryConfig;
+
+    @Autowired
+    private CacheService cacheService;
+
+    @Autowired
+    private ExamStudentService examStudentService;
+
+    @Autowired
+    private ExamDetailService examDetailService;
+
+    @Autowired
+    private ExamCardService examCardService;
+
+    private ExecutorService executors = Executors.newFixedThreadPool(5);
+
+    private static final String SAVE_EXAM_TYPE = "MULTI_MEDIA";
+    private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
+    private static final String POST_METHOD = "POST";
+
+    /**
+     * 定时任务批量同步
+     */
+    @Override
+    public void syncToCloudReview() {
+        // 查询可同步计划(同步状态为空:未同步,false:同步失败)
+        QueryWrapper<ExamPrintPlan> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(ExamPrintPlan::getStatus, PrintPlanStatusEnum.END)
+                .and(q -> q.isNull(ExamPrintPlan::getSyncStatus).or().eq(ExamPrintPlan::getSyncStatus, false));
+        List<ExamPrintPlan> examPrintPlans = examPrintPlanService.list(queryWrapper);
+        if (!CollectionUtils.isEmpty(examPrintPlans)) {
+            for (ExamPrintPlan examPrintPlan : examPrintPlans) {
+                executors.execute(syncData(examPrintPlan));
+            }
+        }
+    }
+
+    /**
+     * 单个同步
+     *
+     * @param printPlanId
+     */
+    @Override
+    public void syncDataCloud(Long printPlanId) {
+        ExamPrintPlan examPrintPlan = examPrintPlanService.getById(printPlanId);
+        if (examPrintPlan == null) {
+            throw ExceptionResultEnum.ERROR.exception("印刷计划数据异常");
+        }
+        if (!PrintPlanStatusEnum.PRINT_FINISH.equals(examPrintPlan.getStatus())) {
+            throw ExceptionResultEnum.ERROR.exception("印刷计划未结束,不能同步数据");
+        }
+        if (Objects.nonNull(examPrintPlan.getSyncStatus()) && examPrintPlan.getSyncStatus()) {
+            throw ExceptionResultEnum.ERROR.exception("印刷计划数据同步成功");
+        }
+        executors.execute(syncData(examPrintPlan));
+    }
+
+    private TimerTask syncData(ExamPrintPlan examPrintPlan) {
+        return new TimerTask() {
+            @Override
+            public void run() {
+                TBSyncTask syncTask = tbSyncTaskService.saveTask(examPrintPlan);
+                doSyncCore(examPrintPlan, syncTask);
+            }
+        };
+    }
+
+    /**
+     * 同步核心方法
+     *
+     * @param syncTask
+     */
+    @Transactional
+    public void doSyncCore(ExamPrintPlan examPrintPlan, TBSyncTask syncTask) {
+        try {
+            if (!PrintPlanStatusEnum.PRINT_FINISH.equals(examPrintPlan.getStatus())) {
+                throw ExceptionResultEnum.ERROR.exception("印刷计划未结束,不能同步数据");
+            }
+            // 校验同步url
+            validatUrl();
+            UpdateWrapper<TBSyncTask> tbSyncTaskUpdateWrapper = new UpdateWrapper<>();
+            tbSyncTaskUpdateWrapper.lambda().set(TBSyncTask::getStatus, TaskStatusEnum.RUNNING).eq(TBSyncTask::getId, syncTask.getId());
+            tbSyncTaskService.update(tbSyncTaskUpdateWrapper);
+
+            // 同步计划 -> 对应云阅卷考试
+            ExamPrintPlan printPlan = examSave(examPrintPlan);
+            // 考试同步成功,才能同步考生和题卡
+            if (Objects.nonNull(printPlan.getThirdRelateId())) {
+                studentSave(printPlan);
+                cardUpload(printPlan);
+            }
+
+            // 更新计划状态
+            UpdateWrapper<ExamPrintPlan> updateWrapper = new UpdateWrapper<>();
+            updateWrapper.lambda().set(ExamPrintPlan::getSyncStatus, true).eq(ExamPrintPlan::getId, examPrintPlan.getId());
+            examPrintPlanService.update(updateWrapper);
+
+            // 更新日志表
+            syncTask.setResult(TaskResultEnum.SUCCESS);
+        } catch (Exception e) {
+            syncTask.setResult(TaskResultEnum.ERROR);
+            syncTask.setErrorMessage(e.getMessage());
+        } finally {
+            syncTask.setStatus(TaskStatusEnum.FINISH);
+            tbSyncTaskService.saveOrUpdate(syncTask);
+        }
+
+    }
+
+    /**
+     * 校验url是否非空
+     */
+    private void validatUrl() {
+        String hostUrl = dictionaryConfig.syncDataDomain().getHostUrl();
+        String examSaveUrl = dictionaryConfig.syncDataDomain().getExamSaveUrl();
+        String studentSaveUrl = dictionaryConfig.syncDataDomain().getStudentSaveUrl();
+        String cardUploadUrl = dictionaryConfig.syncDataDomain().getCardUploadUrl();
+
+        if (StringUtils.isAnyBlank(hostUrl, examSaveUrl, studentSaveUrl, cardUploadUrl)) {
+            throw ExceptionResultEnum.ERROR.exception("云阅卷同步接口URL未正确配置");
+        }
+    }
+
+    /**
+     * 创建考试
+     *
+     * @param examPrintPlan
+     * @return
+     */
+    public ExamPrintPlan examSave(ExamPrintPlan examPrintPlan) {
+        String hostUrl = dictionaryConfig.syncDataDomain().getHostUrl();
+        String examSaveUrl = dictionaryConfig.syncDataDomain().getExamSaveUrl();
+        String postUrl = hostUrl.concat(examSaveUrl);
+        try {
+            //参数
+            Map<String, String> map = new HashMap<>();
+            map.put("code", String.valueOf(examPrintPlan.getId()));
+            map.put("name", examPrintPlan.getName());
+            map.put("examTime", DateUtil.format(new Date(examPrintPlan.getExamEndTime()), DATE_FORMAT));
+            map.put("type", SAVE_EXAM_TYPE);
+
+            String result = HttpKit.sendPost(postUrl, getHeaders(examPrintPlan.getSchoolId(), examSaveUrl), map, null, null, null);
+            JSONObject jsonObject = JSONObject.parseObject(result);
+            if (jsonObject.containsKey("id")) {
+                Long id = Long.valueOf(jsonObject.get("id").toString());
+                UpdateWrapper<ExamPrintPlan> updateWrapper = new UpdateWrapper<>();
+                updateWrapper.lambda().set(ExamPrintPlan::getThirdRelateId, id).eq(ExamPrintPlan::getId, examPrintPlan.getId());
+                examPrintPlanService.update(updateWrapper);
+                return examPrintPlanService.getById(examPrintPlan.getId());
+            }
+        } catch (Exception e) {
+            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
+        }
+
+        return null;
+    }
+
+    /**
+     * 新增考生
+     *
+     * @return
+     */
+    public void studentSave(ExamPrintPlan examPrintPlan) {
+        String hostUrl = dictionaryConfig.syncDataDomain().getHostUrl();
+        String studentSaveUrl = dictionaryConfig.syncDataDomain().getStudentSaveUrl();
+        String postUrl = hostUrl.concat(studentSaveUrl);
+
+        List<SyncExamStudentDto> examStudents = examStudentService.listStudentByPrintPlanIdAndSyncStatus(examPrintPlan.getId());
+        for (SyncExamStudentDto examStudent : examStudents) {
+            try {
+                //参数
+                Map<String, String> map = new HashMap<>();
+                map.put("examId", String.valueOf(examPrintPlan.getThirdRelateId()));
+                map.put("examNumber", examStudent.getTicketNumber());
+                map.put("studentCode", examStudent.getStudentCode());
+                map.put("name", examStudent.getStudentName());
+                map.put("college", "无");
+                map.put("className", getClassName(examStudent.getExtendFields()));
+                map.put("teacher", "无");
+                map.put("subjectCode", examStudent.getPaperNumber()); // 取试卷编号
+                map.put("subjectName", examStudent.getCourseName());
+
+                String result = HttpKit.sendPost(postUrl, getHeaders(examPrintPlan.getSchoolId(), studentSaveUrl), map, null, null, null);
+                JSONObject jsonObject = JSONObject.parseObject(result);
+                if (jsonObject.containsKey("updateTime")) {
+                    UpdateWrapper<ExamStudent> updateWrapper = new UpdateWrapper<>();
+                    updateWrapper.lambda().set(ExamStudent::getSyncStatus, true).eq(ExamStudent::getId, examStudent.getId());
+                    examStudentService.update(updateWrapper);
+                }
+            } catch (Exception e) {
+                throw ExceptionResultEnum.ERROR.exception(e.getMessage());
+            }
+        }
+    }
+
+    /**
+     * 推送题卡
+     *
+     * @return
+     */
+    public void cardUpload(ExamPrintPlan examPrintPlan) {
+        String hostUrl = dictionaryConfig.syncDataDomain().getHostUrl();
+        String cardUploadUrl = dictionaryConfig.syncDataDomain().getCardUploadUrl();
+        String postUrl = hostUrl.concat(cardUploadUrl);
+        List<ExamDetailCourse> examDetailCourses = examDetailService.listSyncPaperNumberByPrintPlanId(examPrintPlan.getId());
+        if (CollectionUtils.isEmpty(examDetailCourses)) {
+            return;
+        }
+        for (ExamDetailCourse examDetailCours : examDetailCourses) {
+            List<SyncExamCardDto> syncExamCardDtos = examCardService.listSyncCardByCourseCodeAndPaperNumber(examDetailCours.getSchoolId(), examDetailCours.getCourseCode(), examDetailCours.getPaperNumber());
+            if (CollectionUtils.isEmpty(syncExamCardDtos) || syncExamCardDtos.size() != 1) {
+                throw ExceptionResultEnum.ERROR.exception(String.format("数据异常,通过学校:%s,课程代码:%s,试卷编号:%s查出多个题卡数据", examDetailCours.getSchoolId(), examDetailCours.getCourseCode(), examDetailCours.getPaperNumber()));
+            }
+
+            SyncExamCardDto syncExamCardDto = syncExamCardDtos.get(0);
+            if (StringUtils.isNotEmpty(syncExamCardDto.getContent())) {
+                //生成json文件
+                File file = null;
+                try {
+                    String filePath = SystemConstant.TEMP_FILES_DIR + File.separator + "card-upload" + File.separator + System.currentTimeMillis();
+                    file = createJsonFile(filePath, syncExamCardDto.getContent());
+                    Map<String, String> files = new HashMap<>();
+                    if (file.exists()) {
+                        files.put(syncExamCardDto.getTitle(), file.getPath());
+                    }
+
+                    //表单数据
+                    Map<String, String> formText = new HashMap<>();
+                    formText.put("examId", String.valueOf(examPrintPlan.getThirdRelateId()));
+                    formText.put("subjectCode", syncExamCardDto.getPaperNumber());
+                    formText.put("format", "json");
+                    formText.put("md5", DigestUtils.md5Hex(new FileInputStream(file)));
+
+
+                    String result = HttpKit.sendPost(postUrl, getHeaders(examDetailCours.getSchoolId(), cardUploadUrl), formText, files, null, null);
+                    JSONObject jsonObject = JSONObject.parseObject(result);
+                    if (jsonObject.containsKey("success")) {
+                        String success = jsonObject.get("success").toString();
+                        if (Boolean.valueOf(success)) {
+                            UpdateWrapper<ExamCard> updateWrapper = new UpdateWrapper<>();
+                            updateWrapper.lambda().set(ExamCard::getSyncStatus, true).eq(ExamCard::getId, syncExamCardDto.getId());
+                            examCardService.update(updateWrapper);
+                        }
+                    }
+                } catch (Exception e) {
+                    throw ExceptionResultEnum.ERROR.exception(e.getMessage());
+                } finally {
+                    if (file != null && file.exists()) {
+                        file.delete();
+                    }
+                }
+            }
+
+        }
+    }
+
+    /**
+     * http请求头
+     *
+     * @param url
+     * @return
+     */
+    private Map<String, String> getHeaders(Long schoolId, String url) {
+        long time = System.currentTimeMillis();
+        Map<String, String> header = new HashMap<>();
+        header.put(SystemConstant.HEADER_AUTHORIZATION, createSign(schoolId, time, url));
+        header.put(SystemConstant.HEADER_TIME, String.valueOf(time));
+        return header;
+    }
+
+    /**
+     * 签名
+     *
+     * @param schoolId
+     * @param time
+     * @param url
+     * @return
+     */
+    private String createSign(Long schoolId, long time, String url) {
+        BasicSchool basicSchool = cacheService.schoolCache(schoolId);
+        if (basicSchool == null) {
+            throw ExceptionResultEnum.ERROR.exception("学校不存在");
+        } else {
+            if (!basicSchool.getEnable()) {
+                throw ExceptionResultEnum.ERROR.exception("学校已禁用");
+            }
+        }
+        String signature = SignatureEntityTest.build(SignatureType.SECRET, POST_METHOD, url, time, basicSchool.getAccessKey(), basicSchool.getAccessSecret());
+        return signature;
+    }
+
+    private String getClassName(String extendCloumn) {
+        List<Map> mapList = JSONObject.parseArray(extendCloumn, Map.class);
+        for (Map map : mapList) {
+            if (Objects.equals("className", map.get("code").toString())) {
+                return map.get("value").toString();
+            }
+        }
+        return "无";
+    }
+
+    /*
+     * 生成文件
+     * @param file 文件路径+文件名称
+     * @param conent 要生成的文件内容
+     */
+    public static File createJsonFile(String url, String conent) {
+
+        File file = new File(url);
+        if (!file.exists()) {
+            file.mkdirs();
+        }
+        BufferedWriter out = null;
+        file = new File(file, UUID.randomUUID().toString() + ".json");
+        try {
+            file.createNewFile();
+            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, true)));
+            out.write(conent);
+        } catch (Exception e) {
+        } finally {
+            try {
+                out.close();
+            } catch (IOException e) {
+            }
+        }
+        return file;
+    }
+}

+ 6 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamCardServiceImpl.java

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qmth.distributed.print.business.bean.dto.CardCustDto;
 import com.qmth.distributed.print.business.bean.dto.CardDetailDto;
+import com.qmth.distributed.print.business.bean.dto.SyncExamCardDto;
 import com.qmth.distributed.print.business.bean.params.ArraysParams;
 import com.qmth.distributed.print.business.bean.params.ExamCardParams;
 import com.qmth.distributed.print.business.entity.*;
@@ -246,6 +247,11 @@ public class ExamCardServiceImpl extends ServiceImpl<ExamCardMapper, ExamCard> i
         commonService.downloadFileAndZip(response, rootPath, time);
     }
 
+    @Override
+    public List<SyncExamCardDto> listSyncCardByCourseCodeAndPaperNumber(Long schoolId, String courseCode, String paperNumber) {
+        return this.baseMapper.listSyncCardByCourseCodeAndPaperNumber(schoolId, courseCode, paperNumber);
+    }
+
 
     /**
      * 数据验证

+ 9 - 4
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamDetailServiceImpl.java

@@ -105,19 +105,19 @@ public class ExamDetailServiceImpl extends ServiceImpl<ExamDetailMapper, ExamDet
     }
 
     @Override
-    public IPage<PrintTaskDto> listPrintTask(Long printPlanId, String status, String courseCode, String paperNumber, String examPlace, String examRoom, Long examStartTime, Long examEndTime, Integer pageNumber, Integer pageSize) {
+    public IPage<PrintTaskDto> listPrintTask(Long printPlanId, String status, String courseCode, String paperNumber, String examPlace, String examRoom, Long examStartTime, Long examEndTime, Long printStartTime, Long printEndTime, Integer pageNumber, Integer pageSize) {
         Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
         Set<Long> orgIds = commonService.listSubOrgIds(null);
         Page<PrintTaskDto> page = new Page<>(pageNumber, pageSize);
-        IPage<PrintTaskDto> pirntTaskDtoIPage = this.baseMapper.listPrintTask(page, schoolId, printPlanId, status, courseCode, paperNumber, examPlace, examRoom, examStartTime, examEndTime, orgIds);
+        IPage<PrintTaskDto> pirntTaskDtoIPage = this.baseMapper.listPrintTask(page, schoolId, printPlanId, status, courseCode, paperNumber, examPlace, examRoom, examStartTime, examEndTime,printStartTime, printEndTime,  orgIds);
         return pirntTaskDtoIPage;
     }
 
     @Override
-    public PrintTaskTotalDto taskTotalData(Long printPlanId, String status, String courseCode, String paperNumber, String examPlace, String examRoom, Long examStartTime, Long examEndTime) {
+    public PrintTaskTotalDto taskTotalData(Long printPlanId, String status, String courseCode, String paperNumber, String examPlace, String examRoom, Long examStartTime, Long examEndTime, Long printStartTime, Long printEndTime) {
         Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
         Set<Long> orgIds = commonService.listSubOrgIds(null);
-        PrintTaskTotalDto printTaskTotalDto = this.baseMapper.taskTotalData(schoolId, printPlanId, status, courseCode, paperNumber, examPlace, examRoom, examStartTime, examEndTime, orgIds);
+        PrintTaskTotalDto printTaskTotalDto = this.baseMapper.taskTotalData(schoolId, printPlanId, status, courseCode, paperNumber, examPlace, examRoom, examStartTime, examEndTime, printStartTime, printEndTime, orgIds);
 
         if (printTaskTotalDto != null) {
             // 试卷总计
@@ -748,6 +748,11 @@ public class ExamDetailServiceImpl extends ServiceImpl<ExamDetailMapper, ExamDet
         return null;
     }
 
+    @Override
+    public List<ExamDetailCourse> listSyncPaperNumberByPrintPlanId(Long printPlanId) {
+        return this.baseMapper.listSyncPaperNumberByPrintPlanId(printPlanId);
+    }
+
     @Transactional(rollbackFor = Exception.class)
     @Override
     public void deleteExaminationData(Long printPlanId) {

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

@@ -72,6 +72,9 @@ public class ExamPrintPlanServiceImpl extends ServiceImpl<ExamPrintPlanMapper, E
     @Autowired
     private ClientPrintDataService clientPrintDataService;
 
+    @Autowired
+    private DataSyncService dataSyncService;
+
     @Transactional(rollbackFor = Exception.class)
     @Override
     public IPage<PrintPlanResult> printPlanPage(Long schoolId, Long printPlanId, PrintPlanStatusEnum status, Long startTime, Long endTime, int pageNumber, int pageSize) {
@@ -389,6 +392,11 @@ public class ExamPrintPlanServiceImpl extends ServiceImpl<ExamPrintPlanMapper, E
         return clientPrintStatisticsTotalDto;
     }
 
+    @Override
+    public void syncDataCloud(Long printPlanId) {
+        dataSyncService.syncDataCloud(printPlanId);
+    }
+
 
     /**
      * 查找子机构

+ 6 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamStudentServiceImpl.java

@@ -5,6 +5,7 @@ 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.qmth.distributed.print.business.bean.dto.ExamStudentCourseDto;
+import com.qmth.distributed.print.business.bean.dto.SyncExamStudentDto;
 import com.qmth.distributed.print.business.entity.ExamDetailCourse;
 import com.qmth.distributed.print.business.entity.ExamStudent;
 import com.qmth.distributed.print.business.mapper.ExamStudentMapper;
@@ -73,4 +74,9 @@ public class ExamStudentServiceImpl extends ServiceImpl<ExamStudentMapper, ExamS
     public List<ExamStudentCourseDto> queryBySchoolIdAndExamDetailCourseIds(Long schoolId, List<Long> examDetailCourseIds) {
         return examStudentMapper.queryBySchoolIdAndExamDetailCourseIds(schoolId, examDetailCourseIds);
     }
+
+    @Override
+    public List<SyncExamStudentDto> listStudentByPrintPlanIdAndSyncStatus(Long printPlanId) {
+        return this.baseMapper.listStudentByPrintPlanIdAndSyncStatus(printPlanId);
+    }
 }

+ 31 - 1
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamTaskServiceImpl.java

@@ -16,6 +16,7 @@ import com.qmth.distributed.print.business.enums.*;
 import com.qmth.distributed.print.business.mapper.ExamTaskMapper;
 import com.qmth.distributed.print.business.service.*;
 import com.qmth.distributed.print.business.templete.execute.AsyncCreatePdfTempleteService;
+import com.qmth.distributed.print.business.templete.execute.AsyncPaperReviewPdfExportService;
 import com.qmth.distributed.print.business.util.ConvertUtil;
 import com.qmth.distributed.print.business.util.ExcelUtil;
 import com.qmth.distributed.print.business.util.ServletUtil;
@@ -27,6 +28,7 @@ import org.apache.commons.lang3.time.DateUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
 import org.springframework.util.LinkedMultiValueMap;
 import org.springframework.web.multipart.MultipartFile;
 
@@ -110,6 +112,9 @@ public class ExamTaskServiceImpl extends ServiceImpl<ExamTaskMapper, ExamTask> i
     @Autowired
     private BasicMessageService basicMessageService;
 
+    @Resource
+    AsyncPaperReviewPdfExportService asyncPaperReviewPdfExportService;
+
 
     @Override
     public List<ExamTask> listByCourseCode(Long schoolId, String code) {
@@ -387,7 +392,7 @@ public class ExamTaskServiceImpl extends ServiceImpl<ExamTaskMapper, ExamTask> i
                 List<BlurryUserDto> blurryUserDtoList;
 
                 QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
-                queryWrapper.lambda().eq(SysUser::getLoginName, examTaskTemp.getUserAccount());
+                queryWrapper.lambda().eq(SysUser::getSchoolId, schoolId).eq(SysUser::getLoginName, examTaskTemp.getUserAccount());
                 SysUser sysUser1 = sysUserService.getOne(queryWrapper);
                 if (sysUser1 != null) {
                     blurryUserDtoList = listUsers(examTaskTemp.getCourseCode(), String.valueOf(sysUser1.getId()));
@@ -1188,4 +1193,29 @@ public class ExamTaskServiceImpl extends ServiceImpl<ExamTaskMapper, ExamTask> i
             }
         }
     }
+
+    @Override
+    public List<ExamTaskDetailDto> listTaskPaper(String courseCode, String paperNumber, Long startTime, Long endTime) {
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        // 查询用户角色是否包含命题老师
+        List<SysRole> list = sysUserRoleService.listRoleByUserId(sysUser.getId());
+        boolean containsQuestionTeacher = list.stream().filter(m -> RoleTypeEnum.QUESTION_TEACHER.equals(m.getType())).count() > 0;
+        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
+        Set<Long> orgIds = commonService.listSubOrgIds(null);
+        List<ExamTaskDetailDto> examTaskDetailDtos = this.baseMapper.listTaskPaper(schoolId, courseCode, paperNumber, startTime, endTime, orgIds, containsQuestionTeacher, sysUser.getId());
+        return examTaskDetailDtos;
+    }
+
+    @Override
+    public TBTask taskDownloadPdf(String courseCode, String paperNumber, Long startTime, Long endTime) {
+        List<ExamTaskDetailDto> examTasks = this.listTaskPaper(courseCode, paperNumber, startTime, endTime);
+        if (CollectionUtils.isEmpty(examTasks)) {
+            throw ExceptionResultEnum.ERROR.exception("没有可导出数据");
+        }
+        Map<String, Object> map = tbTaskService.saveTask(TaskTypeEnum.PAPER_AND_CARD_PDF_DOWNLOAD, null, (SysUser) ServletUtil.getRequestUser());
+        map.put("examTasks", examTasks);
+        asyncPaperReviewPdfExportService.exportTask(map);
+        TBTask tbTask = Objects.nonNull(map.get(SystemConstant.TASK)) ? (TBTask) map.get(SystemConstant.TASK) : null;
+        return tbTask;
+    }
 }

+ 40 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/TBSyncTaskServiceImpl.java

@@ -0,0 +1,40 @@
+package com.qmth.distributed.print.business.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.qmth.distributed.print.business.entity.ExamPrintPlan;
+import com.qmth.distributed.print.business.entity.TBSyncTask;
+import com.qmth.distributed.print.business.enums.TaskStatusEnum;
+import com.qmth.distributed.print.business.mapper.TBSyncTaskMapper;
+import com.qmth.distributed.print.business.service.TBSyncTaskService;
+import com.qmth.distributed.print.common.contant.SystemConstant;
+import com.qmth.distributed.print.common.enums.ExceptionResultEnum;
+import org.springframework.stereotype.Service;
+
+/**
+ * @Date: 2021/5/20.
+ */
+@Service
+public class TBSyncTaskServiceImpl extends ServiceImpl<TBSyncTaskMapper, TBSyncTask> implements TBSyncTaskService {
+    @Override
+    public TBSyncTask saveTask(ExamPrintPlan examPrintPlan) {
+        QueryWrapper<TBSyncTask> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(TBSyncTask::getSchoolId, examPrintPlan.getSchoolId())
+                .eq(TBSyncTask::getPrintPlanId, examPrintPlan.getId())
+                .ne(TBSyncTask::getStatus, TaskStatusEnum.FINISH);
+        TBSyncTask tbSyncTask = this.getOne(queryWrapper);
+        if (tbSyncTask != null) {
+            throw ExceptionResultEnum.ERROR.exception("计划下有数据正在同步");
+        } else {
+            tbSyncTask = new TBSyncTask();
+            tbSyncTask.setId(SystemConstant.getDbUuid());
+            tbSyncTask.setSchoolId(examPrintPlan.getSchoolId());
+            tbSyncTask.setPrintPlanId(examPrintPlan.getId());
+            tbSyncTask.setPrintPlanName(examPrintPlan.getName());
+            tbSyncTask.setStatus(TaskStatusEnum.INIT);
+            tbSyncTask.setCreateTime(System.currentTimeMillis());
+        }
+        this.save(tbSyncTask);
+        return tbSyncTask;
+    }
+}

+ 3 - 1
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/TBTaskServiceImpl.java

@@ -256,7 +256,9 @@ public class TBTaskServiceImpl extends ServiceImpl<TBTaskMapper, TBTask> impleme
         Map<String, Object> map = new HashMap<>();
         try {
             TBTask tbTask = saveTaskCommon(null, taskTypeEnum, map, sysUser);
-            tbTask.setRemark(JacksonUtil.parseJson(arraysParams.getIds()));
+            if(Objects.nonNull(arraysParams)) {
+                tbTask.setRemark(JacksonUtil.parseJson(arraysParams.getIds()));
+            }
             this.save(tbTask);
         } catch (Exception e) {
             log.error("请求出错", e);

+ 69 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/execute/AsyncPaperReviewPdfExportService.java

@@ -0,0 +1,69 @@
+package com.qmth.distributed.print.business.templete.execute;
+
+import cn.hutool.core.date.DateUtil;
+import com.qmth.boot.api.exception.ApiException;
+import com.qmth.distributed.print.business.entity.ExamTask;
+import com.qmth.distributed.print.business.entity.TBTask;
+import com.qmth.distributed.print.business.enums.TaskResultEnum;
+import com.qmth.distributed.print.business.enums.TaskStatusEnum;
+import com.qmth.distributed.print.business.service.TBTaskService;
+import com.qmth.distributed.print.business.templete.export.AsyncExportTaskTemplete;
+import com.qmth.distributed.print.business.templete.service.TaskLogicService;
+import com.qmth.distributed.print.common.contant.SpringContextHolder;
+import com.qmth.distributed.print.common.contant.SystemConstant;
+import com.qmth.distributed.print.common.util.Result;
+import com.qmth.distributed.print.common.util.ResultUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.text.MessageFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.StringJoiner;
+
+/**
+ * @Description: 异步任务-命题任务审核样本导出
+ * @Author: CaoZixuan
+ * @Date: 2021-04-19
+ */
+@Service
+public class AsyncPaperReviewPdfExportService extends AsyncExportTaskTemplete {
+    @Resource
+    TaskLogicService taskLogicService;
+
+    public static final String OBJ_TITLE = "试卷、题卡pdf导出";
+    private final static Logger log = LoggerFactory.getLogger(AsyncPaperReviewPdfExportService.class);
+
+    @Override
+    public Result exportTask(Map<String, Object> map) {
+        TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
+
+        StringJoiner stringJoinerSummary = new StringJoiner("\n")
+                .add(MessageFormat.format("{0}{1}{2}", DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN), BEGIN_TITLE, OBJ_TITLE));
+        tbTask.setStatus(TaskStatusEnum.RUNNING);
+        TBTaskService tbTaskService = SpringContextHolder.getBean(TBTaskService.class);
+        tbTaskService.updateById(tbTask);
+        try {
+            TaskLogicService taskLogicService = SpringContextHolder.getBean(TaskLogicService.class);
+            Map<String, Object> result = taskLogicService.executeExportPaperAndCardLogic(map);
+            stringJoinerSummary.add(MessageFormat.format("{0}{1}{2}{3}", DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN), FINISH_TITLE, Long.valueOf(String.valueOf(result.get("count"))), FINISH_SIZE));
+            tbTask.setResult(TaskResultEnum.SUCCESS);
+        } catch (Exception e) {
+            log.error("请求出错", e);
+            stringJoinerSummary.add(MessageFormat.format("{0}{1}{2}{3}", DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN), EXCEPTION_TITLE, EXCEPTION_DATA, e.getMessage()));
+            tbTask.setResult(TaskResultEnum.ERROR);
+            if (e instanceof ApiException) {
+                ResultUtil.error((ApiException) e, e.getMessage());
+            } else {
+                ResultUtil.error(e.getMessage());
+            }
+        } finally {//生成txt文件
+            tbTask.setSummary(stringJoinerSummary.toString());
+            super.createTxt(tbTask);
+        }
+        return ResultUtil.ok();
+    }
+}

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

@@ -54,4 +54,12 @@ public interface TaskLogicService {
      * @return
      */
     public Map<String, Object> executeExportSampleLogic(Map<String, Object> map) throws IOException;
+
+    /**
+     * 导出试卷、题卡pdf
+     *
+     * @param map
+     * @return
+     */
+    Map<String, Object> executeExportPaperAndCardLogic(Map<String, Object> map) throws IOException;
 }

+ 113 - 5
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/service/impl/TaskLogicServiceImpl.java

@@ -1,5 +1,6 @@
 package com.qmth.distributed.print.business.templete.service.impl;
 
+import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ZipUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
@@ -18,10 +19,7 @@ import com.qmth.distributed.print.business.entity.*;
 import com.qmth.distributed.print.business.enums.*;
 import com.qmth.distributed.print.business.service.*;
 import com.qmth.distributed.print.business.templete.service.TaskLogicService;
-import com.qmth.distributed.print.business.util.ConvertUtil;
-import com.qmth.distributed.print.business.util.CreatePdfUtil;
-import com.qmth.distributed.print.business.util.ExcelUtil;
-import com.qmth.distributed.print.business.util.OssUtil;
+import com.qmth.distributed.print.business.util.*;
 import com.qmth.distributed.print.common.contant.SystemConstant;
 import com.qmth.distributed.print.common.enums.ExceptionResultEnum;
 import com.qmth.distributed.print.common.util.FileUtil;
@@ -29,6 +27,7 @@ import com.qmth.distributed.print.common.util.HexUtils;
 import com.qmth.distributed.print.common.util.ResultUtil;
 import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.time.DateUtils;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.Row;
@@ -684,6 +683,14 @@ public class TaskLogicServiceImpl implements TaskLogicService {
             examinationImportDtoList.add(examinationImportDto);
         }
 
+        // 按考点+开始时间+课程代码+考场排序
+        examinationImportDtoList.sort(
+                Comparator.comparing(ExaminationImportDto::getExamPlace)
+                        .thenComparing(ExaminationImportDto::getExamStartTime)
+                        .thenComparing(ExaminationImportDto::getCourseCode)
+                        .thenComparing(ExaminationImportDto::getExamRoom)
+        );
+
         System.out.println(JSON.toJSONString(examinationImportDtoList));
 
         // 校验课程代码和试卷编号在印刷计划下是1对1的关系
@@ -700,7 +707,7 @@ public class TaskLogicServiceImpl implements TaskLogicService {
         examDetailService.deleteExaminationData(printPlanId);
 
         // 卷袋号生成规则
-        SerialNumberParams serialNumberParams = new SerialNumberParams("packageCode-", "1", 6);
+        SerialNumberParams serialNumberParams = new SerialNumberParams("packageCode-" + schoolId, "1", 6);
         String key = serialNumberParams.getModel() + serialNumberParams.getPrefix();
         RedisAtomicLong counter = new RedisAtomicLong(key, Objects.requireNonNull(redisTemplate.getConnectionFactory()));
         Long value = counter.get();
@@ -937,4 +944,105 @@ public class TaskLogicServiceImpl implements TaskLogicService {
         map.put("count", count);
         return map;
     }
+
+    @Override
+    public Map<String, Object> executeExportPaperAndCardLogic(Map<String, Object> map) throws IOException {
+        TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
+        String yyyyMMddHH24mmss = DateUtil.format(new Date(), "yyyyMMddHHmmss");
+        BasicSchool basicSchool = cacheService.schoolCache(tbTask.getSchoolId());
+        LocalDateTime nowTime = LocalDateTime.now();
+        StringJoiner zipJoiner = new StringJoiner("")
+                .add(SystemConstant.TEMP_FILES_DIR).add(File.separator);
+        StringJoiner dirName = new StringJoiner("")
+                .add(UploadFileEnum.FILE.getTitle()).add(File.separator)
+                .add(String.valueOf(nowTime.getYear())).add(File.separator)
+                .add(String.format("%02d", nowTime.getMonthValue())).add(File.separator)
+                .add(String.format("%02d", nowTime.getDayOfMonth()))
+                .add(File.separator)
+                .add(yyyyMMddHH24mmss).add("_").add(basicSchool.getName()).add("_").add("试卷导出文件").add(SystemConstant.ZIP_PREFIX);
+        String dirNameTmp = dirName.toString().replaceAll("\\\\", "/");
+
+        // 根文件路径
+        String zipLocalRootPath = SystemConstant.TEMP_FILES_DIR + File.separator + System.currentTimeMillis();
+
+        List<ExamTaskDetailDto> examTasks = (List<ExamTaskDetailDto>) map.get("examTasks");
+        for (ExamTaskDetailDto examTask : examTasks) {
+            ExamTaskDetail examTaskDetail = examTaskDetailService.getByExamTaskId(Long.valueOf(examTask.getId()));
+
+            // 试卷
+            String paperAttachmentIds = examTaskDetail.getPaperAttachmentIds();
+            if (StringUtils.isNotBlank(paperAttachmentIds)) {
+                List<Map> paperInfo = JSONObject.parseArray(paperAttachmentIds, Map.class);
+                if (Objects.isNull(paperInfo)) {
+                    throw ExceptionResultEnum.ERROR.exception("试卷信息不存在");
+                }
+                for (Map paperMap : paperInfo) {
+                    if (Objects.nonNull(paperMap.get("attachmentId")) && String.valueOf(paperMap.get("attachmentId")).length() > 0 && !String.valueOf(paperMap.get("attachmentId")).equals("null")) {
+                        String name = paperMap.get("name").toString();
+                        Long attachmentId = Long.valueOf(String.valueOf(paperMap.get("attachmentId")));
+                        BasicAttachment attachment = basicAttachmentService.getById(attachmentId);
+                        if (Objects.nonNull(attachment)) {
+                            JSONObject jsonObject = JSONObject.parseObject(attachment.getPath());
+                            String paperPath = zipLocalRootPath + File.separator + examTask.getPaperNumber() + File.separator + "试卷" + "_" + examTask.getPaperNumber() + "_" + name + attachment.getType();
+                            ossUtil.ossDownload((String) jsonObject.get(SystemConstant.PATH), paperPath);
+                        }
+                    }
+                }
+            }
+
+            // 题卡
+            // 处理题卡
+            ExamCard examCard = examCardService.getById(examTaskDetail.getCardId());
+            if (Objects.isNull(examCard)) {
+                throw ExceptionResultEnum.ERROR.exception("找不到答题卡");
+            }
+            MakeMethodEnum makeMethodEnum = examCard.getMakeMethod();
+
+            String cardPath = zipLocalRootPath + File.separator + examTask.getPaperNumber();
+            String cardHtmlPath = cardPath + File.separator + "题卡" + "_" + examTask.getPaperNumber() + SystemConstant.HTML_PREFIX;
+            String cardPdfPath = cardPath + File.separator + "题卡" + "_" + examTask.getPaperNumber() + SystemConstant.PDF_PREFIX;
+            // 通用题卡
+            ExamCardDetail examCardDetail = examCardDetailService.getByCardId(examCard.getId());
+            String htmlContent;
+            if (MakeMethodEnum.SELECT.equals(makeMethodEnum)) {
+                htmlContent = createPdfUtil.replaceHtmlTemplete(examCardDetail);
+            } else {
+                BasicCardRule basicCardRule = basicCardRuleService.getById(examTask.getCardRuleId());
+                htmlContent = createPdfUtil.replaceHtmlCard(examCardDetail, basicCardRule);
+            }
+            // html
+            File localFile = new File(cardHtmlPath);
+            if (!localFile.getParentFile().exists()) {
+                localFile.getParentFile().mkdirs();
+            }
+            // 生成html文件
+            FileCopyUtils.copy(htmlContent.getBytes(), localFile);
+            // 转pdf文件
+            File file = new File(cardPdfPath);
+            if (!file.exists()) {
+                file.createNewFile();
+            }
+            HtmlToPdfUtil.convert(cardHtmlPath, cardPdfPath, PageSizeEnum.A3);
+        }
+
+        File zipFile = new File(zipJoiner.toString() + dirNameTmp);
+        if (!zipFile.getParentFile().exists()) {
+            zipFile.getParentFile().mkdirs();
+        }
+        if (!zipFile.exists()) {
+            zipFile.createNewFile();
+        }
+
+        ZipUtil.zip(zipLocalRootPath, zipFile.getPath(), false);
+        ossUtil.ossUpload(dirNameTmp, zipFile, BinaryUtil.toBase64String(HexUtils.decodeHex(DigestUtils.md5Hex(new FileInputStream(zipFile)))));
+        JSONObject jsonObject = new JSONObject();
+        jsonObject.put(SystemConstant.PATH, dirNameTmp);
+        jsonObject.put(SystemConstant.TYPE, SystemConstant.OSS);
+        jsonObject.put(SystemConstant.UPLOAD_TYPE, UploadFileEnum.FILE);
+        tbTask.setResultFilePath(jsonObject.toJSONString());
+        ConvertUtil.delFolder(zipLocalRootPath);
+        zipFile.delete();
+        map.put("count", 1);
+        return map;
+    }
 }

+ 55 - 12
distributed-print-business/src/main/java/com/qmth/distributed/print/business/util/CreatePdfUtil.java

@@ -166,20 +166,20 @@ public class CreatePdfUtil {
 //            maxSite = tempList.stream().max((a, b) -> a.getSiteNumber().compareTo(b.getSiteNumber())).get().getSiteNumber();
 //        }
 
-        for (ExamStudentCourseDto e : examStudentList) {
-            char[] chars = e.getSiteNumber().toLowerCase().toCharArray();
-            String ascii = "";
-            for (int i = 0; i < chars.length; i++) {
-                ascii = ascii + chars[i];
-            }
-            e.setAscii(ascii);
-        }
-
         Optional<ExamStudentCourseDto> minSite = null;
         Optional<ExamStudentCourseDto> maxSite = null;
-        if (Objects.nonNull(examStudentList) && examStudentList.size() > 0) {
-            minSite = examStudentList.stream().min(Comparator.comparing(s -> Integer.parseInt(s.getAscii())));
-            maxSite = examStudentList.stream().max(Comparator.comparing(s -> Integer.parseInt(s.getAscii())));
+        List<ExamStudentCourseDto> tempList = examStudentList.stream().filter(s -> (Objects.nonNull(s.getSiteNumber()) && !Objects.equals("", s.getSiteNumber().trim()))).collect(Collectors.toList());
+        if (Objects.nonNull(tempList) && tempList.size() > 0) {
+//            for (ExamStudentCourseDto e : tempList) {
+//                char[] chars = e.getSiteNumber().toLowerCase().toCharArray();
+//                String ascii = "";
+//                for (int i = 0; i < chars.length; i++) {
+//                    ascii = ascii + chars[i];
+//                }
+//                e.setAscii(ascii.hashCode());
+//            }
+            minSite = tempList.stream().min(Comparator.comparing(s -> s.getSiteNumber().hashCode()));
+            maxSite = tempList.stream().max(Comparator.comparing(s -> s.getSiteNumber().hashCode()));
         }
 
         htmlMap.put("minSite", Optional.ofNullable(minSite).map(s -> s.get().getSiteNumber()).orElse(""));
@@ -324,6 +324,49 @@ public class CreatePdfUtil {
         return content;
     }
 
+    /**
+     * 替换自定义题卡参数
+     *
+     * @param examCardDetail
+     * @return
+     * @throws IOException
+     */
+    public String replaceHtmlCard(ExamCardDetail examCardDetail, BasicCardRule basicCardRule) throws IOException {
+        //通用题卡
+        String cardTemp = examCardDetail.getHtmlContent();
+        cardTemp = cardTemp.replaceAll("\\$\\{paperTypeName\\}", "");
+        //随机生成试卷条码并将图片转成base64
+        cardTemp = cardTemp.replaceAll("\\$\\{paperType\\}", "");
+        cardTemp = cardTemp.replaceAll("<img src=\"data:image/png;base64,\\$\\{examNumber\\}\">", "");
+        cardTemp = cardTemp.replaceAll("\\$\\{examNumberStr\\}", "");
+        if (Objects.nonNull(basicCardRule) && Objects.nonNull(basicCardRule.getExtendFields())) {
+            JSONArray jsonObjectExtend = (JSONArray) JSONArray.parse(basicCardRule.getExtendFields());//扩展字段
+            if (Objects.nonNull(jsonObjectExtend)) {
+                for (int i = 0; i < jsonObjectExtend.size(); i++) {
+                    JSONObject object = (JSONObject) jsonObjectExtend.get(i);
+                    cardTemp = cardTemp.replaceAll("\\$\\{" + object.get("code") + "\\}", "");
+                }
+            }
+        }
+        cardTemp = cardTemp.replaceAll("\\$\\{examDate\\}", "");
+        cardTemp = cardTemp.replaceAll("\\$\\{examTime\\}", "");
+        cardTemp = cardTemp.replaceAll("\\$\\{ticketNumber\\}", "");
+        cardTemp = cardTemp.replaceAll("\\$\\{siteNumber\\}", "");
+        cardTemp = cardTemp.replaceAll("\\$\\{paperTypeName\\}", "");
+        cardTemp = cardTemp.replaceAll("\\$\\{studentCode\\}", "");
+        cardTemp = cardTemp.replaceAll("\\$\\{studentName\\}", "");
+        cardTemp = cardTemp.replaceAll("\\$\\{courseName\\}", "");
+        cardTemp = cardTemp.replaceAll("\\$\\{courseCode\\}", "");
+        cardTemp = cardTemp.replaceAll("\\$\\{examPlace\\}", "");
+        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);
+        return cardTemp;
+    }
+
     /**
      * 获取题卡attachmentId
      *

+ 198 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/util/HttpKit.java

@@ -0,0 +1,198 @@
+package com.qmth.distributed.print.business.util;
+
+import com.qmth.distributed.print.common.enums.ExceptionResultEnum;
+
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Date;
+import java.util.Map;
+
+public class HttpKit {
+
+    /**
+     * 向指定 URL 发送POST方法的请求
+     *
+     * @param url    发送请求的 URL
+     * @param params 请求的参数集合
+     * @return 远程资源的响应结果
+     */
+    @SuppressWarnings("unused")
+    public static String sendPost(String url, Map<String, String> params, Map<String, String> requestHeader) {
+        OutputStreamWriter out = null;
+        BufferedReader in = null;
+        StringBuilder result = new StringBuilder();
+        try {
+            URL realUrl = new URL(url);
+            HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
+            // 发送POST请求必须设置如下两行
+            conn.setDoOutput(true);
+            conn.setDoInput(true);
+            // POST方法
+            conn.setRequestMethod("POST");
+            // 设置通用的请求属性
+            conn.setRequestProperty("accept", "*/*");
+            conn.setRequestProperty("connection", "Keep-Alive");
+            conn.setRequestProperty("user-agent",
+                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
+            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+            if (requestHeader != null && requestHeader.size() > 0) {
+                for (Map.Entry<String, String> entry : requestHeader.entrySet()) {
+                    conn.setRequestProperty(entry.getKey(), entry.getValue());
+                }
+            }
+//            conn.setRequestProperty("Authorization", authorization);
+            conn.connect();
+            // 获取URLConnection对象对应的输出流
+            out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
+            // 发送请求参数
+            if (params != null) {
+                StringBuilder param = new StringBuilder();
+                for (Map.Entry<String, String> entry : params.entrySet()) {
+                    if (param.length() > 0) {
+                        param.append("&");
+                    }
+                    param.append(entry.getKey());
+                    param.append("=");
+                    param.append(entry.getValue());
+                }
+                out.write(param.toString());
+            }
+            // flush输出流的缓冲
+            out.flush();
+            // 定义BufferedReader输入流来读取URL的响应
+            in = new BufferedReader(
+                    new InputStreamReader(conn.getInputStream(), "UTF-8"));
+            String line;
+            while ((line = in.readLine()) != null) {
+                result.append(line);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        //使用finally块来关闭输出流、输入流
+        finally {
+            try {
+                if (out != null) {
+                    out.close();
+                }
+                if (in != null) {
+                    in.close();
+                }
+            } catch (IOException ex) {
+                ex.printStackTrace();
+            }
+        }
+        return result.toString();
+    }
+
+    /**
+     * 发送post请求
+     *
+     * @param requestUrl       请求url
+     * @param requestHeader    请求头
+     * @param formTexts        表单数据
+     * @param files            上传文件
+     * @param requestEncoding  请求编码
+     * @param responseEncoding 响应编码
+     * @return 页面响应html
+     */
+    public static String sendPost(String requestUrl, Map<String, String> requestHeader, Map<String, String> formTexts, Map<String, String> files, String requestEncoding, String responseEncoding) {
+        OutputStream out = null;
+        BufferedReader reader = null;
+        String result = "";
+        try {
+            if (requestUrl == null || requestUrl.isEmpty()) {
+                return result;
+            }
+            URL realUrl = new URL(requestUrl);
+            HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
+            connection.setRequestProperty("accept", "text/html, application/xhtml+xml, image/jxr, */*");
+            connection.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0");
+            if (requestHeader != null && requestHeader.size() > 0) {
+                for (Map.Entry<String, String> entry : requestHeader.entrySet()) {
+                    connection.setRequestProperty(entry.getKey(), entry.getValue());
+                }
+            }
+            connection.setDoOutput(true);
+            connection.setDoInput(true);
+            connection.setRequestMethod("POST");
+            if (requestEncoding == null || requestEncoding.isEmpty()) {
+                requestEncoding = "UTF-8";
+            }
+            if (responseEncoding == null || responseEncoding.isEmpty()) {
+                responseEncoding = "UTF-8";
+            }
+            if (files == null || files.size() == 0) {
+                connection.setRequestProperty("content-type", "application/x-www-form-urlencoded");
+                out = new DataOutputStream(connection.getOutputStream());
+                if (formTexts != null && formTexts.size() > 0) {
+                    String formData = "";
+                    for (Map.Entry<String, String> entry : formTexts.entrySet()) {
+                        formData += entry.getKey() + "=" + entry.getValue() + "&";
+                    }
+                    formData = formData.substring(0, formData.length() - 1);
+                    out.write(formData.getBytes(requestEncoding));
+                }
+            } else {
+                String boundary = "-----------------------------" + new Date().getTime();
+                connection.setRequestProperty("content-type", "multipart/form-data; boundary=" + boundary);
+                out = new DataOutputStream(connection.getOutputStream());
+                if (formTexts != null && formTexts.size() > 0) {
+                    StringBuilder sbFormData = new StringBuilder();
+                    for (Map.Entry<String, String> entry : formTexts.entrySet()) {
+                        sbFormData.append("--" + boundary + "\r\n");
+                        sbFormData.append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"\r\n\r\n");
+                        sbFormData.append(entry.getValue() + "\r\n");
+                    }
+                    out.write(sbFormData.toString().getBytes(requestEncoding));
+                }
+                for (Map.Entry<String, String> entry : files.entrySet()) {
+                    String fileName = entry.getKey();
+                    String filePath = entry.getValue();
+                    if (fileName == null || fileName.isEmpty() || filePath == null || filePath.isEmpty()) {
+                        continue;
+                    }
+                    File file = new File(filePath);
+                    if (!file.exists()) {
+                        continue;
+                    }
+                    out.write(("--" + boundary + "\r\n").getBytes(requestEncoding));
+                    out.write(("Content-Disposition: form-data; name=\"file\"; filename=\"" + file.getName() + "\"\r\n").getBytes(requestEncoding));
+                    out.write(("Content-Type: application/octet-stream\r\n\r\n").getBytes(requestEncoding));
+                    DataInputStream in = new DataInputStream(new FileInputStream(file));
+                    int bytes = 0;
+                    byte[] bufferOut = new byte[1024];
+                    while ((bytes = in.read(bufferOut)) != -1) {
+                        out.write(bufferOut, 0, bytes);
+                    }
+                    in.close();
+                    out.write(("\r\n").getBytes(requestEncoding));
+                }
+                out.write(("--" + boundary + "--").getBytes(requestEncoding));
+            }
+            out.flush();
+            out.close();
+//            out = null;
+            reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), responseEncoding));
+            String line;
+            while ((line = reader.readLine()) != null) {
+                result += line;
+            }
+        } catch (Exception e) {
+            throw ExceptionResultEnum.ERROR.exception("发送POST请求出现异常:" + e.getMessage());
+        } finally {
+            try {
+                if (out != null) {
+                    out.close();
+                }
+                if (reader != null) {
+                    reader.close();
+                }
+            } catch (IOException ex) {
+                ex.printStackTrace();
+            }
+        }
+        return result;
+    }
+}

+ 1 - 1
distributed-print-business/src/main/resources/db/init-data.sql

@@ -5,4 +5,4 @@ INSERT INTO `sys_config` VALUES (2, 'sys.warning.days', '预警天数', '3',NULL
 INSERT INTO `sys_config` VALUES (3, 'sys.code.enable', '是否启用短信验证码', 'true', 'true-启用,false-禁用', 1, NULL, NULL, NULL);
 INSERT INTO `sys_config` VALUES (4, 'sys.message.enable', '是否启用短信消息提示', 'true', 'true-启用,false-禁用', 1, NULL, NULL, NULL);
 INSERT INTO `sys_config` VALUES (5, 'sys.message.resendCount', '失败短信重试次数', '3', NULL, 1, NULL, NULL, NULL);
-
+INSERT INTO `sys_config` VALUES (6, 'sys.sync.enable', '是否开启数据同步云阅卷', 'true', 'true-启用,false-禁用', 1, NULL, NULL, NULL);

+ 27 - 0
distributed-print-business/src/main/resources/db/init-table.sql

@@ -274,6 +274,7 @@ CREATE TABLE `exam_card`  (
   `update_time` bigint(20) NULL DEFAULT NULL,
   `type` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '题卡类型:GENERIC-通卡,CUSTOM-自定义',
   `template_id` bigint(20) NULL DEFAULT NULL COMMENT 'type=GENERIC时必传',
+  `sync_status` tinyint(1) NULL COMMENT '是否同步成功',
   PRIMARY KEY (`id`) USING BTREE
 ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '题卡' ROW_FORMAT = Dynamic;
 
@@ -371,6 +372,8 @@ CREATE TABLE `exam_print_plan`  (
   `create_time` bigint(20) NULL DEFAULT NULL,
   `update_id` bigint(20) NULL DEFAULT NULL,
   `update_time` bigint(20) NULL DEFAULT NULL,
+  `third_relate_id` bigint(20) NULL COMMENT '第三方系统关联ID(目前只有云阅卷)',
+  `sync_status` tinyint(1) NULL COMMENT '是否同步成功',
   PRIMARY KEY (`id`) USING BTREE
 ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '印刷计划管理' ROW_FORMAT = Dynamic;
 
@@ -395,6 +398,7 @@ CREATE TABLE `exam_student`  (
   `update_id` bigint(20) NULL DEFAULT NULL,
   `update_time` bigint(20) NULL DEFAULT NULL,
   `attachment_id` bigint(20) NULL DEFAULT NULL COMMENT '附件id',
+  `sync_status` tinyint(1) NULL COMMENT '是否同步成功',
   PRIMARY KEY (`id`) USING BTREE
 ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '考生' ROW_FORMAT = Dynamic;
 
@@ -927,6 +931,7 @@ INSERT INTO `sys_privilege` VALUES (187,'客户端登录','/api/admin/client/use
 INSERT INTO `sys_privilege` VALUES (188,'考务明细查询-学生明细','/api/admin/exam/print/get_student_detail','URL',45,2,'SYS',NULL,1619502584844,1);
 INSERT INTO `sys_privilege` VALUES (189,'卷库查询-修改','/api/admin/exam/task/paper_update','URL',42,4,'AUTH',NULL,1619502584844,1);
 INSERT INTO `sys_privilege` VALUES (190,'任务管理-重新生成pdf','/api/admin/data/task/reset_create_pdf','URL',113,2,'AUTH',NULL,1619502584844,1);
+INSERT INTO `sys_privilege` VALUES (191,'卷库查询-批量下载试卷PDF、题卡', '/api/admin/exam/task/paper_card_download_pdf', 'URL', 42, 5, 'AUTH',NULL, 1619502584844, '1');
 INSERT INTO `sys_privilege` VALUES (199,'客户端','client','MENU',NULL,22,NULL,NULL,1619502252306,1);
 INSERT INTO `sys_privilege` VALUES (200,'试卷打样-查询列表','/api/admin/client/paper_try/list','URL',199,2,'AUTH',NULL,NULL,1);
 INSERT INTO `sys_privilege` VALUES (201,'试卷打样-查看/试印/重印','/api/admin/client/paper_try/print','URL',199,3,'AUTH',NULL,NULL,1);
@@ -1260,6 +1265,8 @@ INSERT INTO `sys_role_privilege` VALUES (1384755205368247213, 6, 213, 1);
 INSERT INTO `sys_role_privilege` VALUES (1384755205368247214, 6, 214, 1);
 INSERT INTO `sys_role_privilege` VALUES (1384755205368247215, 6, 215, 1);
 INSERT INTO `sys_role_privilege` VALUES (1384755205368247216, 6, 216, 1);
+INSERT INTO `sys_role_privilege` VALUES (1384755205368247217, 3, 191, 1);
+INSERT INTO `sys_role_privilege` VALUES (1384755205368247218, 4, 191, 1);
 
 -- ----------------------------
 -- Table structure for sys_user
@@ -1603,6 +1610,26 @@ CREATE TABLE `t_b_task`  (
   PRIMARY KEY (`id`) USING BTREE
 ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '导入导出任务表' ROW_FORMAT = Dynamic;
 
+-- ----------------------------
+-- Table structure for t_b_sync_task
+-- ----------------------------
+DROP TABLE IF EXISTS `t_b_sync_task`;
+CREATE TABLE `t_b_sync_task`  (
+  `id` bigint(20) NOT NULL COMMENT '主键',
+  `school_id` bigint(20) NULL DEFAULT NULL COMMENT '学校id',
+  `print_plan_id` bigint(20) NULL DEFAULT NULL COMMENT '印刷计划id',
+  `print_plan_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
+  `status` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '任务状态,INIT:未开始,RUNNING:进行中,FINISH:已完成',
+  `summary` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '实时摘要信息',
+  `result` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '数据结果,SUCCESS:成功,ERROR:失败',
+  `create_id` bigint(20) NULL DEFAULT NULL COMMENT '创建人id',
+  `create_time` bigint(20) NULL DEFAULT NULL COMMENT '创建时间',
+  `remark` mediumtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '备注',
+  `reset_count` int(11) NULL DEFAULT 0 COMMENT '重试次数',
+  `error_message` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '人工错误原因',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '导入导出任务表' ROW_FORMAT = Dynamic;
+
 -- ----------------------------
 -- Table structure for t_g_error
 -- ----------------------------

+ 24 - 0
distributed-print-business/src/main/resources/mapper/ExamCardMapper.xml

@@ -150,4 +150,28 @@
             exam_card_detail b ON a.id = b.card_id
         where a.id = #{cardId}
     </select>
+    <select id="listSyncCardByCourseCodeAndPaperNumber"
+            resultType="com.qmth.distributed.print.business.bean.dto.SyncExamCardDto">
+        SELECT
+            c.id,
+            a.school_id schoolId,
+            a.course_code courseCode,
+            a.paper_number paperNumber,
+            c.title,
+            d.content
+        FROM
+            exam_task a
+                LEFT JOIN
+            exam_task_detail b ON a.id = b.exam_task_id
+                LEFT JOIN
+            exam_card c ON b.card_id = c.id
+                LEFT JOIN
+            exam_card_detail d ON c.id = d.card_id
+        WHERE
+            a.school_id = #{schoolId}
+                AND a.course_code = #{courseCode}
+                AND a.paper_number = #{paperNumber}
+                AND c.status = 'SUBMIT'
+                AND c.make_method != 'SELECT'
+    </select>
 </mapper>

+ 25 - 0
distributed-print-business/src/main/resources/mapper/ExamDetailMapper.xml

@@ -90,6 +90,12 @@
                 <if test="examEndTime != null and examEndTime != ''">
                     and b.exam_end_time &lt; #{examEndTime}
                 </if>
+                <if test="printStartTime != null and printStartTime != ''">
+                    and b.print_start_time &gt; #{printStartTime}
+                </if>
+                <if test="printEndTime != null and printEndTime != ''">
+                    and b.print_start_time &lt; #{printEndTime}
+                </if>
                 <if test="orgIds != null">
                     AND d.org_id IN
                     <foreach collection="orgIds" item="item" index="index" open="(" separator="," close=")">
@@ -294,6 +300,12 @@
             <if test="examEndTime != null and examEndTime != ''">
                 and b.exam_end_time &lt; #{examEndTime}
             </if>
+            <if test="printStartTime != null and printStartTime != ''">
+                and b.print_start_time &gt; #{printStartTime}
+            </if>
+            <if test="printEndTime != null and printEndTime != ''">
+                and b.print_start_time &lt; #{printEndTime}
+            </if>
             <if test="orgIds != null">
                 AND d.org_id IN
                 <foreach collection="orgIds" item="item" index="index" open="(" separator="," close=")">
@@ -399,5 +411,18 @@
             </if>
         </where>
     </select>
+    <select id="listSyncPaperNumberByPrintPlanId"
+            resultType="com.qmth.distributed.print.business.entity.ExamDetailCourse">
+        SELECT DISTINCT
+            b.school_id schoolId,
+            b.course_code courseCode,
+            b.paper_number paperNumber
+        FROM
+            exam_detail a
+                LEFT JOIN
+            exam_detail_course b ON a.id = b.exam_detail_id
+        WHERE
+            a.print_plan_id = #{printPlanId}
+    </select>
 
 </mapper>

+ 23 - 0
distributed-print-business/src/main/resources/mapper/ExamStudentMapper.xml

@@ -85,5 +85,28 @@
             </where>
             order by edc.course_code
     </select>
+    <select id="listStudentByPrintPlanIdAndSyncStatus"
+            resultType="com.qmth.distributed.print.business.bean.dto.SyncExamStudentDto">
+        SELECT
+            a.id,
+            b.course_code courseCode,
+            b.course_name courseName,
+            b.paper_number paperNumber,
+            a.student_name studentName,
+            a.student_code studentCode,
+            a.ticket_number ticketNumber,
+            a.extend_fields extendFields,
+            a.paper_type paperType
+        FROM
+            exam_student a
+                LEFT JOIN
+            exam_detail_course b ON a.exam_detail_course_id = b.id
+                LEFT JOIN
+            exam_detail c ON b.exam_detail_id = c.id
+        WHERE
+            c.print_plan_id = #{printPlanId}
+                AND (a.sync_status IS NULL
+                OR a.sync_status = FALSE)
+    </select>
 
 </mapper>

+ 4 - 0
distributed-print-business/src/main/resources/mapper/TBSyncTaskMapper.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.qmth.distributed.print.business.mapper.TBSyncTaskMapper">
+</mapper>

+ 13 - 0
distributed-print-task/src/main/java/com/qmth/distributed/print/task/job/service/impl/JobServiceImpl.java

@@ -3,6 +3,7 @@ package com.qmth.distributed.print.task.job.service.impl;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.qmth.distributed.print.business.entity.ExamDetail;
 import com.qmth.distributed.print.business.entity.ExamPrintPlan;
+import com.qmth.distributed.print.business.entity.SysConfig;
 import com.qmth.distributed.print.business.enums.PrintPlanStatusEnum;
 import com.qmth.distributed.print.business.service.*;
 import com.qmth.distributed.print.task.job.service.JobService;
@@ -46,6 +47,12 @@ public class JobServiceImpl implements JobService {
     @Autowired
     BasicMessageService basicMessageService;
 
+    @Autowired
+    DataSyncService dataSyncService;
+
+    @Autowired
+    private SysConfigService sysConfigService;
+
     @Override
     public void updateSchoolInfo() throws IOException {
         orgCenterDataDisposeService.updateSchoolInfo();
@@ -74,6 +81,12 @@ public class JobServiceImpl implements JobService {
             }
         }
         examPrintPlanService.saveOrUpdateBatch(examPrintPlanList);
+
+        // 2021-05-20 同步数据到云阅卷
+        SysConfig sysConfig = sysConfigService.getByKey("sys.code.enable");
+        if(Objects.nonNull(sysConfig) && sysConfig.getConfigValue() == "true") {
+            dataSyncService.syncToCloudReview();
+        }
     }
 
     /**

+ 15 - 3
distributed-print/src/main/java/com/qmth/distributed/print/api/ExamPrintPlanController.java

@@ -198,9 +198,11 @@ public class ExamPrintPlanController {
                            @RequestParam(value = "examRoom", required = false) String examRoom,
                            @RequestParam(value = "examStartTime", required = false) Long examStartTime,
                            @RequestParam(value = "examEndTime", required = false) Long examEndTime,
+                           @RequestParam(value = "printStartTime", required = false) Long printStartTime,
+                           @RequestParam(value = "printEndTime", required = false) Long printEndTime,
                            @RequestParam Integer pageNumber,
                            @RequestParam Integer pageSize) {
-        IPage<PrintTaskDto> examTasks = examDetailService.listPrintTask(printPlanId, status, courseCode, paperNumber, examPlace, examRoom, examStartTime, examEndTime, pageNumber, pageSize);
+        IPage<PrintTaskDto> examTasks = examDetailService.listPrintTask(printPlanId, status, courseCode, paperNumber, examPlace, examRoom, examStartTime, examEndTime, printStartTime, printEndTime, pageNumber, pageSize);
         return ResultUtil.ok(examTasks);
     }
 
@@ -266,8 +268,10 @@ public class ExamPrintPlanController {
                                 @RequestParam(value = "examPlace", required = false) String examPlace,
                                 @RequestParam(value = "examRoom", required = false) String examRoom,
                                 @RequestParam(value = "examStartTime", required = false) Long examStartTime,
-                                @RequestParam(value = "examEndTime", required = false) Long examEndTime) {
-        PrintTaskTotalDto printTaskTotalDto = examDetailService.taskTotalData(printPlanId, status, courseCode, paperNumber, examPlace, examRoom, examStartTime, examEndTime);
+                                @RequestParam(value = "examEndTime", required = false) Long examEndTime,
+                                @RequestParam(value = "printStartTime", required = false) Long printStartTime,
+                                @RequestParam(value = "printEndTime", required = false) Long printEndTime) {
+        PrintTaskTotalDto printTaskTotalDto = examDetailService.taskTotalData(printPlanId, status, courseCode, paperNumber, examPlace, examRoom, examStartTime, examEndTime, printStartTime, printEndTime);
         return ResultUtil.ok(printTaskTotalDto);
     }
 
@@ -315,5 +319,13 @@ public class ExamPrintPlanController {
         TBTask tbTask = Objects.nonNull(map.get(SystemConstant.TASK)) ? (TBTask) map.get(SystemConstant.TASK) : null;
         return Objects.nonNull(tbTask) ? ResultUtil.ok(new EditResult(tbTask.getId())) : ResultUtil.error("创建任务失败");
     }
+
+    @ApiOperation(value = "同步失败-手动同步")
+    @RequestMapping(value = "/sync_data_cloud", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "返回信息", response = EditResult.class)})
+    public Result syncDataCloud(@RequestParam(value = "printPlanId") Long printPlanId) throws Exception {
+        examPrintPlanService.syncDataCloud(printPlanId);
+        return ResultUtil.ok(true);
+    }
 }
 

+ 45 - 26
distributed-print/src/main/java/com/qmth/distributed/print/api/ExamTaskController.java

@@ -1,24 +1,29 @@
 package com.qmth.distributed.print.api;
 
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.qmth.boot.api.annotation.Aac;
+import com.qmth.boot.api.annotation.BOOL;
 import com.qmth.boot.api.constant.ApiConstant;
 import com.qmth.boot.api.exception.ApiException;
 import com.qmth.distributed.print.business.bean.dto.*;
 import com.qmth.distributed.print.business.bean.params.ArraysParams;
+import com.qmth.distributed.print.business.bean.result.EditResult;
 import com.qmth.distributed.print.business.entity.*;
 import com.qmth.distributed.print.business.enums.*;
 import com.qmth.distributed.print.business.service.*;
+import com.qmth.distributed.print.business.templete.execute.AsyncPaperReviewPdfExportService;
 import com.qmth.distributed.print.business.templete.execute.AsyncTaskReviewSampleExportService;
 import com.qmth.distributed.print.business.util.ServletUtil;
 import com.qmth.distributed.print.common.contant.SystemConstant;
 import com.qmth.distributed.print.common.enums.ExceptionResultEnum;
 import com.qmth.distributed.print.common.util.Result;
 import com.qmth.distributed.print.common.util.ResultUtil;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.*;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.CollectionUtils;
 import org.springframework.validation.BindingResult;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
@@ -66,6 +71,7 @@ public class ExamTaskController {
 
     @Resource
     private BasicMessageService basicMessageService;
+
     /**
      * 查询
      *
@@ -158,10 +164,10 @@ public class ExamTaskController {
     @RequestMapping(value = "/save", method = RequestMethod.POST)
     public Result save(@RequestBody ExamTask examTask) {
         ExamTask task = examTaskService.saveExamTask(examTask);
-        // todo 发送短信
-        /*if(task.getId() != null){
+        //发送短信
+        if (task.getId() != null) {
             basicMessageService.sendNoticeTaskCreate(task);
-        }*/
+        }
         return ResultUtil.ok(true);
     }
 
@@ -206,11 +212,11 @@ public class ExamTaskController {
     @RequestMapping(value = "/save_batch", method = RequestMethod.POST)
     public Result saveBatch(@RequestBody ExamTask task) {
         List<ExamTask> examTasks = examTaskService.saveBatch(task);
-        /*if(examTasks != null && examTasks.size() > 0){
-            // todo 发送短信
+        if (examTasks != null && examTasks.size() > 0) {
+            // 发送短信
             ExamTask[] tasks = examTasks.toArray(new ExamTask[examTasks.size()]);
             basicMessageService.sendNoticeTaskCreate(tasks);
-        }*/
+        }
         return ResultUtil.ok(true);
     }
 
@@ -290,10 +296,10 @@ public class ExamTaskController {
             // 校验是否可以提交打印状态
             commonService.checkData(examTask.getSchoolId(), examTask.getCourseCode(), examTask.getPaperNumber(), (SysUser) ServletUtil.getRequestUser());
         }
-        // todo 待审核状态,发送短信
-        /*if(ExamStatusEnum.SUBMIT.name().equals(examTask.getStatus())){
+        //待审核状态,发送短信
+        if (ExamStatusEnum.SUBMIT.equals(examTask.getStatus())) {
             basicMessageService.sendNoticeTaskAuditCreateOrReview(examTask, MessageEnum.NOTICE_OF_AUDIT_CREATED);
-        }*/
+        }
 
         return ResultUtil.ok(isSuccess);
     }
@@ -384,10 +390,10 @@ public class ExamTaskController {
             // 校验是否可以提交打印状态
             commonService.checkData(examTask.getSchoolId(), examTask.getCourseCode(), examTask.getPaperNumber(), sysUser);
             // 发送审核通过短信通知
-            basicMessageService.noticeOfExamTaskAudit(examTaskIdList, MessageEnum.NOTICE_OF_AUDIT_PASS,sysUser);
-        }else if (isSuccess && taskReviewLog.getReviewStatus().name().equals(ReviewStatusEnum.NOT_PASS.name())){
+            basicMessageService.noticeOfExamTaskAudit(examTaskIdList, MessageEnum.NOTICE_OF_AUDIT_PASS, sysUser);
+        } else if (isSuccess && taskReviewLog.getReviewStatus().name().equals(ReviewStatusEnum.NOT_PASS.name())) {
             // 发送审核不通过短信通知
-            basicMessageService.noticeOfExamTaskAudit(examTaskIdList, MessageEnum.NOTICE_OF_AUDIT_NOT_PASS,sysUser);
+            basicMessageService.noticeOfExamTaskAudit(examTaskIdList, MessageEnum.NOTICE_OF_AUDIT_NOT_PASS, sysUser);
         }
         return ResultUtil.ok(isSuccess);
     }
@@ -406,10 +412,10 @@ public class ExamTaskController {
         boolean isSuccess = examTaskService.taskReviewSaveBatch(taskReviewLog);
         if (isSuccess && taskReviewLog.getReviewStatus().name().equals(ReviewStatusEnum.PASS.name())) {
             // 发送审核通过短信通知
-            basicMessageService.noticeOfExamTaskAudit(examTaskIdList, MessageEnum.NOTICE_OF_AUDIT_PASS,sysUser);
-        }else if (isSuccess && taskReviewLog.getReviewStatus().name().equals(ReviewStatusEnum.NOT_PASS.name())){
+            basicMessageService.noticeOfExamTaskAudit(examTaskIdList, MessageEnum.NOTICE_OF_AUDIT_PASS, sysUser);
+        } else if (isSuccess && taskReviewLog.getReviewStatus().name().equals(ReviewStatusEnum.NOT_PASS.name())) {
             // 发送审核不通过短信通知
-            basicMessageService.noticeOfExamTaskAudit(examTaskIdList, MessageEnum.NOTICE_OF_AUDIT_NOT_PASS,sysUser);
+            basicMessageService.noticeOfExamTaskAudit(examTaskIdList, MessageEnum.NOTICE_OF_AUDIT_NOT_PASS, sysUser);
         }
         return ResultUtil.ok(isSuccess);
     }
@@ -422,7 +428,7 @@ public class ExamTaskController {
         }
         Long[] ids = arraysParams.getIds();
         Map<String, Object> map = tbTaskService.saveTask(TaskTypeEnum.SAMPLE_EXPORT);
-        map.put("ids",ids);
+        map.put("ids", ids);
         asyncTaskReviewSampleExportService.exportTask(map);
         TBTask tbTask = Objects.nonNull(map.get(SystemConstant.TASK)) ? (TBTask) map.get(SystemConstant.TASK) : null;
         return Objects.nonNull(tbTask) ? ResultUtil.ok(tbTask.getId()) : ResultUtil.error("创建任务失败");
@@ -454,6 +460,7 @@ public class ExamTaskController {
 
     /**
      * 下载
+     *
      * @param response
      * @param examTaskId
      */
@@ -474,13 +481,13 @@ public class ExamTaskController {
     public Result taskPaperEnable(@RequestBody ExamTaskDetail examTaskDetail) throws IOException {
         boolean isSuccess = examTaskDetailService.enable(examTaskDetail);
         // 启用,触发考场生成pdf
-        if(examTaskDetail.getEnable()){
+        if (examTaskDetail.getEnable()) {
             SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
             ExamTask examTask = examTaskService.getById(examTaskDetail.getId());
             // 校验课程关联考场,是否已经提交打印
             Boolean isCreate = commonService.checkExamDetailStatus(examTask.getSchoolId(), null, examTask.getCourseCode(), examTask.getPaperNumber());
             // 校验是否可以提交打印状态
-            if(isCreate) {
+            if (isCreate) {
                 commonService.checkData(examTask.getSchoolId(), examTask.getCourseCode(), examTask.getPaperNumber(), sysUser);
             }
         }
@@ -489,6 +496,7 @@ public class ExamTaskController {
 
     /**
      * 卷库查询-卷库修改
+     *
      * @param examTaskDetail
      * @return
      */
@@ -496,22 +504,33 @@ public class ExamTaskController {
     @RequestMapping(value = "/paper_update", method = RequestMethod.POST)
     public Result taskPaperUpdate(@RequestBody ExamTaskDetail examTaskDetail) throws IOException {
         boolean isSuccess = examTaskDetailService.paperUpdate(examTaskDetail);
-        if(isSuccess){
+        if (isSuccess) {
             ExamTask examTask = examTaskService.getById(examTaskDetail.getExamTaskId());
-            if(examTask.getReview()){
-                // todo 发送短信
-//                basicMessageService.sendNoticeTaskAuditCreateOrReview(examTask, MessageEnum.NOTICE_OF_AUDIT_REVIEW);
+            if (examTask.getReview()) {
+                // 发送短信
+                basicMessageService.sendNoticeTaskAuditCreateOrReview(examTask, MessageEnum.NOTICE_OF_AUDIT_REVIEW);
             } else {
                 SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
                 // 校验课程关联考场,是否已经提交打印
                 Boolean isCreate = commonService.checkExamDetailStatus(examTask.getSchoolId(), null, examTask.getCourseCode(), examTask.getPaperNumber());
                 // 校验是否可以提交打印状态
-                if(isCreate) {
+                if (isCreate) {
                     commonService.checkData(examTask.getSchoolId(), examTask.getCourseCode(), examTask.getPaperNumber(), sysUser);
                 }
             }
         }
         return ResultUtil.ok(isSuccess);
     }
+
+    @ApiOperation(value = "卷库查询-批量下载试卷PDF、题卡")
+    @RequestMapping(value = "/paper_card_download_pdf", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "返回信息", response = EditResult.class)})
+    public Result paperCardDownloadPdf(@RequestParam(value = "courseCode", required = false) String courseCode,
+                                  @RequestParam(value = "paperNumber", required = false) String paperNumber,
+                                  @RequestParam(value = "startTime", required = false) Long startTime,
+                                  @RequestParam(value = "endTime", required = false) Long endTime) {
+        TBTask tbTask = examTaskService.taskDownloadPdf(courseCode, paperNumber, startTime, endTime);
+        return Objects.nonNull(tbTask) ? ResultUtil.ok(new EditResult(tbTask.getId())) : ResultUtil.error("创建任务失败");
+    }
 }
 

+ 23 - 25
distributed-print/src/main/java/com/qmth/distributed/print/start/StartRunning.java

@@ -4,9 +4,7 @@ import com.qmth.distributed.print.business.service.OrgCenterDataDisposeService;
 import com.qmth.distributed.print.business.service.TBTaskService;
 import com.qmth.distributed.print.common.contant.SystemConstant;
 import com.qmth.distributed.print.task.enums.JobEnum;
-import com.qmth.distributed.print.task.job.ResendSmsJob;
-import com.qmth.distributed.print.task.job.ResetCreatePdfJob;
-import com.qmth.distributed.print.task.job.TimedSyncSchoolJob;
+import com.qmth.distributed.print.task.job.*;
 import com.qmth.distributed.print.task.service.QuartzService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -61,29 +59,29 @@ public class StartRunning implements CommandLineRunner {
 //        quartzService.addJob(ResetCreatePdfJob.class, JobEnum.RESET_CREATE_PDF_JOB.name(), JobEnum.RESET_CREATE_PDF_JOB_GROUP.name(), "0 0/1 * * * ?", taskJobMap);
 //        log.info("增加重新生成pdf定时任务 end");
 
-//        log.info("增加任务到期提醒定时任务 start");
-//        Map expireJobMap = new HashMap();
-//        expireJobMap.computeIfAbsent("name", v -> SendSmsExpireJob.class.getName());
-//        quartzService.deleteJob(JobEnum.SMS_NOTICE_TASK_EXPIRE_JOB.name(), JobEnum.SMS_NOTICE_TASK_EXPIRE_JOB_GROUP.name());
-//        // 每天15点定时任务
-//        quartzService.addJob(SendSmsExpireJob.class, JobEnum.SMS_NOTICE_TASK_EXPIRE_JOB.name(), JobEnum.SMS_NOTICE_TASK_EXPIRE_JOB_GROUP.name(), "0 0 15 * * ?", expireJobMap);
-//        log.info("增加任务到期提醒定时任务 end");
-//
-//        log.info("增加任务逾期提醒定时任务 start");
-//        Map orverdueJobMap = new HashMap();
-//        orverdueJobMap.computeIfAbsent("name", v -> SendSmsOverdueJob.class.getName());
-//        quartzService.deleteJob(JobEnum.SMS_NOTICE_TASK_OVERDUE_JOB.name(), JobEnum.SMS_NOTICE_TASK_OVERDUE_JOB_GROUP.name());
-//        // 每天9点定时任务
-//        quartzService.addJob(SendSmsOverdueJob.class, JobEnum.SMS_NOTICE_TASK_OVERDUE_JOB.name(), JobEnum.SMS_NOTICE_TASK_OVERDUE_JOB_GROUP.name(), "0 0 9 * * ?", orverdueJobMap);
-//        log.info("增加任务逾期提醒定时任务 end");
+        log.info("增加任务到期提醒定时任务 start");
+        Map expireJobMap = new HashMap();
+        expireJobMap.computeIfAbsent("name", v -> SendSmsExpireJob.class.getName());
+        quartzService.deleteJob(JobEnum.SMS_NOTICE_TASK_EXPIRE_JOB.name(), JobEnum.SMS_NOTICE_TASK_EXPIRE_JOB_GROUP.name());
+        // 每天15点定时任务
+        quartzService.addJob(SendSmsExpireJob.class, JobEnum.SMS_NOTICE_TASK_EXPIRE_JOB.name(), JobEnum.SMS_NOTICE_TASK_EXPIRE_JOB_GROUP.name(), "0 0 15 * * ?", expireJobMap);
+        log.info("增加任务到期提醒定时任务 end");
 
-//        log.info("增加短信发送失败重发定时任务 start");
-//        Map rensendJobMap = new HashMap();
-//        rensendJobMap.computeIfAbsent("name", v -> ResendSmsJob.class.getName());
-//        quartzService.deleteJob(JobEnum.SMS_NOTICE_TASK_RESEND_JOB.name(), JobEnum.SMS_NOTICE_TASK_RESEND_JOB_GROUP.name());
-//        // 每隔1小时定时任务
-//        quartzService.addJob(ResendSmsJob.class, JobEnum.SMS_NOTICE_TASK_RESEND_JOB.name(), JobEnum.SMS_NOTICE_TASK_RESEND_JOB_GROUP.name(), "0 */30 * * * ?", rensendJobMap);
-//        log.info("增加短信发送失败重发定时任务 end");
+        log.info("增加任务逾期提醒定时任务 start");
+        Map orverdueJobMap = new HashMap();
+        orverdueJobMap.computeIfAbsent("name", v -> SendSmsOverdueJob.class.getName());
+        quartzService.deleteJob(JobEnum.SMS_NOTICE_TASK_OVERDUE_JOB.name(), JobEnum.SMS_NOTICE_TASK_OVERDUE_JOB_GROUP.name());
+        // 每天9点定时任务
+        quartzService.addJob(SendSmsOverdueJob.class, JobEnum.SMS_NOTICE_TASK_OVERDUE_JOB.name(), JobEnum.SMS_NOTICE_TASK_OVERDUE_JOB_GROUP.name(), "0 0 9 * * ?", orverdueJobMap);
+        log.info("增加任务逾期提醒定时任务 end");
+
+        log.info("增加短信发送失败重发定时任务 start");
+        Map rensendJobMap = new HashMap();
+        rensendJobMap.computeIfAbsent("name", v -> ResendSmsJob.class.getName());
+        quartzService.deleteJob(JobEnum.SMS_NOTICE_TASK_RESEND_JOB.name(), JobEnum.SMS_NOTICE_TASK_RESEND_JOB_GROUP.name());
+        // 每隔1小时定时任务
+        quartzService.addJob(ResendSmsJob.class, JobEnum.SMS_NOTICE_TASK_RESEND_JOB.name(), JobEnum.SMS_NOTICE_TASK_RESEND_JOB_GROUP.name(), "0 0/30 * * * ?", rensendJobMap);
+        log.info("增加短信发送失败重发定时任务 end");
 
         log.info("服务器启动时执行 end");
     }

+ 31 - 3
distributed-print/src/main/resources/application.properties

@@ -12,9 +12,9 @@ spring.application.name=distributed-print
 #\u6570\u636E\u6E90\u914D\u7F6E
 db.host=localhost
 db.port=3306
-db.name=distributed-36
+db.name=distributed-print-v2.0.1
 db.username=root
-db.password=123456789
+db.password=root
 
 #redis\u6570\u636E\u6E90\u914D\u7F6E
 com.qmth.redis.host=${db.host}
@@ -95,6 +95,16 @@ com.qmth.logging.file-path=/Users/king/Downloads/distributed-print.log
 #\u5F15\u5165task\u914D\u7F6E\u6587\u4EF6
 spring.profiles.include=task
 
+#云阅卷相关url
+sync.config.hostUrl=http://localhost:8080/
+#同步考试
+sync.config.examSaveUrl=/api/exam/save
+#同步考生
+sync.config.studentSaveUrl=/api/exam/student/save
+#同步题卡
+sync.config.cardUploadUrl=/api/file/card/upload
+
+
 sms.config.smsNormalCode=qmth
 sms.config.codeExpiredTime=2
 sms.config.codeSendInterval=60
@@ -105,4 +115,22 @@ sms.config.aliyunSMSSecret=97aBLBfkQR5mzCiQa82yWLAH57eUd8
 sms.config.aliyunSMSSignName=\u9038\u6559\u4E91
 sms.config.aliyunSMSTplCode=SMS_147416565
 sms.config.aliyunSMSAuditPassCode=SMS_216425141
-sms.config.aliyunSMSAuditNotPassCode=SMS_216275156
+sms.config.aliyunSMSAuditNotPassCode=SMS_216275156
+#命题任务待办生成通知
+sms.config.aliyunSMSExamTaskCreatedCode=SMS_217436292
+#命题任务待办到期预警通知
+sms.config.aliyunSMSExamTaskWillExpireCode=SMS_217436295
+#命题任务待办逾期通知
+sms.config.aliyunSMSExamTaskOverdueCode=SMS_217426313
+#命题分配待办到期预警通知
+sms.config.aliyunSMSAllocationWillExpireCode=SMS_217406305
+#命题分配待办逾期通知
+sms.config.aliyunSMSAllocationOverdueCode=SMS_217406308
+#审核待办生成通知
+sms.config.aliyunSMSAuditCreatedCode=SMS_217436298
+#审核待办修改申请通知
+sms.config.aliyunSMSAuditReviewCode=SMS_217416269
+#审核待办到期预警通知
+sms.config.aliyunSMSAuditWillExpireCode=SMS_217436302
+#审核待办逾期通知
+sms.config.aliyunSMSAuditOverdueCode=SMS_217416271