瀏覽代碼

Merge branch 'dev_v2.2.1' into release_v2.2.1
merge

wangliang 3 年之前
父節點
當前提交
73096702ee
共有 100 個文件被更改,包括 6303 次插入584 次删除
  1. 2 2
      distributed-print-business/pom.xml
  2. 9 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/CardRuleDto.java
  3. 92 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/ExamPaperObjectiveStructureDto.java
  4. 73 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/ExamPaperStructureDto.java
  5. 73 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/ExamPaperSubjectiveStructureDto.java
  6. 12 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/params/PrintPlanParams.java
  7. 28 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/params/TSchoolPrivilegeParam.java
  8. 49 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/result/DictionaryResult.java
  9. 27 3
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/result/PrintPlanResult.java
  10. 338 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/result/TSyncExamStudentScoreResult.java
  11. 14 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/BasicCardRule.java
  12. 43 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/BasicMessage.java
  13. 225 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/ExamPaperStructure.java
  14. 16 3
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/ExamPrintPlan.java
  15. 11 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/ExamStudent.java
  16. 39 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/TBSyncTask.java
  17. 397 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/TSyncExamStudentScore.java
  18. 41 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/enums/DictionaryEnum.java
  19. 48 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/enums/ExamPaperStructureStatusEnum.java
  20. 45 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/enums/ExamPrintPlanSyncStatusEnum.java
  21. 42 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/enums/ImageTrajectoryEnum.java
  22. 21 1
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/enums/MessageEnum.java
  23. 31 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/BasicSemesterMapper.java
  24. 22 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/ExamPaperStructureMapper.java
  25. 2 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/ExamPrintPlanMapper.java
  26. 3 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/ExamStudentMapper.java
  27. 1 1
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/ExamTaskMapper.java
  28. 28 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/TBSyncTaskMapper.java
  29. 77 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/TSyncExamStudentScoreMapper.java
  30. 35 12
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/BasicMessageService.java
  31. 5 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/DataSyncService.java
  32. 30 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/ExamPaperStructureService.java
  33. 6 2
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/ExamPrintPlanService.java
  34. 3 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/ExamStudentService.java
  35. 25 4
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/PrintCommonService.java
  36. 14 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/SsoService.java
  37. 22 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/TBSyncTaskService.java
  38. 93 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/TSyncExamStudentScoreService.java
  39. 199 221
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/BasicMessageServiceImpl.java
  40. 134 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/BasicSemesterServiceImpl.java
  41. 325 168
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/DataSyncServiceImpl.java
  42. 3 6
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamDetailCourseServiceImpl.java
  43. 380 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamPaperStructureServiceImpl.java
  44. 22 13
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamPrintPlanServiceImpl.java
  45. 6 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamStudentServiceImpl.java
  46. 3 1
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamTaskServiceImpl.java
  47. 71 2
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/PrintCommonServiceServiceImpl.java
  48. 61 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/SsoServiceImpl.java
  49. 48 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/TBSyncTaskServiceImpl.java
  50. 262 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/TSyncExamStudentScoreServiceImpl.java
  51. 67 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/execute/AsyncScoreBatchDownloadService.java
  52. 65 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/execute/AsyncScoreExportService.java
  53. 67 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/execute/AsyncScorePushService.java
  54. 16 2
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/execute/AsyncSysUserDataImportService.java
  55. 72 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/execute/AsyncUserPushService.java
  56. 1 1
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/export/AsyncExportTaskTemplete.java
  57. 140 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/push/AsyncPushTaskTemplate.java
  58. 27 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/service/PushLogicService.java
  59. 16 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/service/TaskLogicService.java
  60. 162 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/service/impl/PushLogicServiceImpl.java
  61. 155 8
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/service/impl/TaskLogicServiceImpl.java
  62. 135 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/util/SmsUtils.java
  63. 2 1
      distributed-print-business/src/main/resources/mapper/BasicCardRuleMapper.xml
  64. 54 0
      distributed-print-business/src/main/resources/mapper/ExamPaperStructureMapper.xml
  65. 11 0
      distributed-print-business/src/main/resources/mapper/ExamPrintPlanMapper.xml
  66. 24 3
      distributed-print-business/src/main/resources/mapper/ExamStudentMapper.xml
  67. 70 40
      distributed-print-business/src/main/resources/mapper/ExamTaskMapper.xml
  68. 40 0
      distributed-print-business/src/main/resources/mapper/TBSyncTaskMapper.xml
  69. 93 0
      distributed-print-business/src/main/resources/mapper/TSyncExamStudentScoreMapper.xml
  70. 2 2
      distributed-print/pom.xml
  71. 1 1
      distributed-print/src/main/java/com/qmth/distributed/print/api/BasicClazzController.java
  72. 64 0
      distributed-print/src/main/java/com/qmth/distributed/print/api/BasicMajorController.java
  73. 100 0
      distributed-print/src/main/java/com/qmth/distributed/print/api/BasicMessageController.java
  74. 86 0
      distributed-print/src/main/java/com/qmth/distributed/print/api/BasicSemesterController.java
  75. 90 0
      distributed-print/src/main/java/com/qmth/distributed/print/api/ExamPaperStructureController.java
  76. 3 2
      distributed-print/src/main/java/com/qmth/distributed/print/api/ExamPrintPlanController.java
  77. 3 2
      distributed-print/src/main/java/com/qmth/distributed/print/api/ExamPrintPlanSyncController.java
  78. 168 0
      distributed-print/src/main/java/com/qmth/distributed/print/api/MenuCustomController.java
  79. 56 0
      distributed-print/src/main/java/com/qmth/distributed/print/api/SsoController.java
  80. 209 56
      distributed-print/src/main/java/com/qmth/distributed/print/api/SysController.java
  81. 20 2
      distributed-print/src/main/java/com/qmth/distributed/print/api/SysUserController.java
  82. 55 0
      distributed-print/src/main/java/com/qmth/distributed/print/api/TBSyncTaskController.java
  83. 205 0
      distributed-print/src/main/java/com/qmth/distributed/print/api/TSyncExamStudentScoreController.java
  84. 35 0
      distributed-print/src/main/java/com/qmth/distributed/print/api/WorkController.java
  85. 24 6
      distributed-print/src/main/resources/application-36dev.properties
  86. 23 5
      distributed-print/src/main/resources/application-dev.properties
  87. 6 0
      distributed-print/src/main/resources/application-release.properties
  88. 6 0
      distributed-print/src/main/resources/application-test.properties
  89. 2 2
      distributed-print/src/test/java/com/qmth/distributed/print/CreateSchoolPrivilegeTest.java
  90. 1 1
      distributed-print/src/test/java/com/qmth/distributed/print/ServiceTest.java
  91. 51 0
      distributed-print/src/test/java/com/qmth/distributed/print/SyncHelpTest.java
  92. 1 1
      pom.xml
  93. 2 2
      teachcloud-common-api/pom.xml
  94. 2 2
      teachcloud-common/pom.xml
  95. 20 0
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/annotation/DBVerify.java
  96. 60 0
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/bean/dto/PaperDTO.java
  97. 55 0
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/bean/dto/QuestionDTO.java
  98. 122 0
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/bean/dto/SysRolePrivilegeDto.java
  99. 38 6
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/bean/dto/excel/BasicStudentImportDto.java
  100. 20 0
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/bean/params/BasicClazzParams.java

+ 2 - 2
distributed-print-business/pom.xml

@@ -4,7 +4,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.qmth.distributed.print.business</groupId>
     <artifactId>distributed-print-business</artifactId>
-    <version>2.2.0</version>
+    <version>2.2.1</version>
     <build>
         <plugins>
             <plugin>
@@ -22,7 +22,7 @@
     <parent>
         <groupId>com.qmth.distributed.print.service</groupId>
         <artifactId>distributed-print-service</artifactId>
-        <version>2.2.0</version>
+        <version>2.2.1</version>
     </parent>
 
     <dependencies>

+ 9 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/CardRuleDto.java

@@ -18,6 +18,7 @@ public class CardRuleDto {
     private PaperTypeEnum paperType;
     private Boolean examAbsent;
     private Boolean writeSign;
+    private Boolean discipline;
     private String requiredFields;
     private String extendFields;
     private String titleRule;
@@ -86,6 +87,14 @@ public class CardRuleDto {
         this.writeSign = writeSign;
     }
 
+    public Boolean getDiscipline() {
+        return discipline;
+    }
+
+    public void setDiscipline(Boolean discipline) {
+        this.discipline = discipline;
+    }
+
     public String getRequiredFields() {
         return requiredFields;
     }

+ 92 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/ExamPaperObjectiveStructureDto.java

@@ -0,0 +1,92 @@
+package com.qmth.distributed.print.business.bean.dto;
+
+import com.qmth.teachcloud.common.annotation.ExcelNote;
+
+import java.io.Serializable;
+
+/**
+ * @Date: 2021/10/28.
+ */
+public class ExamPaperObjectiveStructureDto implements Serializable {
+
+    @ExcelNote(value = "科目代码")
+    private String courseCode;
+    @ExcelNote(value = "科目名称")
+    private String courseName;
+    @ExcelNote(value = "试卷类型")
+    private String paperType;
+    @ExcelNote(value = "大题名称")
+    private String mainName;
+    @ExcelNote(value = "大题号(只能用小写数字)")
+    private String mainNumber;
+    @ExcelNote(value = "小题号(只能用小写数字)")
+    private String subNumber;
+    @ExcelNote(value = "标准答案")
+    private String answer;
+    @ExcelNote(value = "小题满分")
+    private String score;
+
+    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 getPaperType() {
+        return paperType;
+    }
+
+    public void setPaperType(String paperType) {
+        this.paperType = paperType;
+    }
+
+    public String getMainName() {
+        return mainName;
+    }
+
+    public void setMainName(String mainName) {
+        this.mainName = mainName;
+    }
+
+    public String getMainNumber() {
+        return mainNumber;
+    }
+
+    public void setMainNumber(String mainNumber) {
+        this.mainNumber = mainNumber;
+    }
+
+    public String getSubNumber() {
+        return subNumber;
+    }
+
+    public void setSubNumber(String subNumber) {
+        this.subNumber = subNumber;
+    }
+
+    public String getAnswer() {
+        return answer;
+    }
+
+    public void setAnswer(String answer) {
+        this.answer = answer;
+    }
+
+    public String getScore() {
+        return score;
+    }
+
+    public void setScore(String score) {
+        this.score = score;
+    }
+}

+ 73 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/ExamPaperStructureDto.java

@@ -0,0 +1,73 @@
+package com.qmth.distributed.print.business.bean.dto;
+
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * @Date: 2021/10/28.
+ */
+public class ExamPaperStructureDto {
+
+    private String paperType;
+    private MultipartFile subjectiveQuestionFile;
+    private String subjectiveQuestionMd5;
+    private MultipartFile objectiveQuestionFile;
+    private String objectiveQuestionMd5;
+    private MultipartFile standardAnswerFile;
+    private String standardAnswerMd5;
+
+    public String getPaperType() {
+        return paperType;
+    }
+
+    public void setPaperType(String paperType) {
+        this.paperType = paperType;
+    }
+
+    public MultipartFile getSubjectiveQuestionFile() {
+        return subjectiveQuestionFile;
+    }
+
+    public void setSubjectiveQuestionFile(MultipartFile subjectiveQuestionFile) {
+        this.subjectiveQuestionFile = subjectiveQuestionFile;
+    }
+
+    public String getSubjectiveQuestionMd5() {
+        return subjectiveQuestionMd5;
+    }
+
+    public void setSubjectiveQuestionMd5(String subjectiveQuestionMd5) {
+        this.subjectiveQuestionMd5 = subjectiveQuestionMd5;
+    }
+
+    public MultipartFile getObjectiveQuestionFile() {
+        return objectiveQuestionFile;
+    }
+
+    public void setObjectiveQuestionFile(MultipartFile objectiveQuestionFile) {
+        this.objectiveQuestionFile = objectiveQuestionFile;
+    }
+
+    public String getObjectiveQuestionMd5() {
+        return objectiveQuestionMd5;
+    }
+
+    public void setObjectiveQuestionMd5(String objectiveQuestionMd5) {
+        this.objectiveQuestionMd5 = objectiveQuestionMd5;
+    }
+
+    public MultipartFile getStandardAnswerFile() {
+        return standardAnswerFile;
+    }
+
+    public void setStandardAnswerFile(MultipartFile standardAnswerFile) {
+        this.standardAnswerFile = standardAnswerFile;
+    }
+
+    public String getStandardAnswerMd5() {
+        return standardAnswerMd5;
+    }
+
+    public void setStandardAnswerMd5(String standardAnswerMd5) {
+        this.standardAnswerMd5 = standardAnswerMd5;
+    }
+}

+ 73 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/ExamPaperSubjectiveStructureDto.java

@@ -0,0 +1,73 @@
+package com.qmth.distributed.print.business.bean.dto;
+
+import com.qmth.teachcloud.common.annotation.ExcelNote;
+
+import java.io.Serializable;
+
+/**
+ * @Date: 2021/10/28.
+ */
+
+public class ExamPaperSubjectiveStructureDto implements Serializable {
+
+    @ExcelNote(value = "科目代码")
+    private String courseCode;
+    @ExcelNote(value = "科目名称")
+    private String courseName;
+    @ExcelNote(value = "大题名称")
+    private String mainName;
+    @ExcelNote(value = "大题号(只能用小写数字)")
+    private String mainNumber;
+    @ExcelNote(value = "小题号(只能用小写数字)")
+    private String subNumber;
+    @ExcelNote(value = "小题满分")
+    private String score;
+
+    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 getMainName() {
+        return mainName;
+    }
+
+    public void setMainName(String mainName) {
+        this.mainName = mainName;
+    }
+
+    public String getMainNumber() {
+        return mainNumber;
+    }
+
+    public void setMainNumber(String mainNumber) {
+        this.mainNumber = mainNumber;
+    }
+
+    public String getSubNumber() {
+        return subNumber;
+    }
+
+    public void setSubNumber(String subNumber) {
+        this.subNumber = subNumber;
+    }
+
+    public String getScore() {
+        return score;
+    }
+
+    public void setScore(String score) {
+        this.score = score;
+    }
+}

+ 12 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/params/PrintPlanParams.java

@@ -26,6 +26,10 @@ public class PrintPlanParams {
     @ApiModelProperty(value = "学校id")
     private Long schoolId;
 
+    @JsonSerialize(using = ToStringSerializer.class)
+    @ApiModelProperty(value = "学期ID")
+    private Long semesterId;
+
     @JsonSerialize(using = ToStringSerializer.class)
     @ApiModelProperty(value = "机构id")
     private Long orgId;
@@ -88,6 +92,14 @@ public class PrintPlanParams {
         this.schoolId = schoolId;
     }
 
+    public Long getSemesterId() {
+        return semesterId;
+    }
+
+    public void setSemesterId(Long semesterId) {
+        this.semesterId = semesterId;
+    }
+
     public Long getOrgId() {
         return orgId;
     }

+ 28 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/params/TSchoolPrivilegeParam.java

@@ -0,0 +1,28 @@
+package com.qmth.distributed.print.business.bean.params;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.qmth.teachcloud.common.entity.TSchoolPrivilege;
+
+/**
+ * @Description: 学校自定义菜单 param
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2021/10/30
+ */
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class TSchoolPrivilegeParam extends TSchoolPrivilege {
+
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long[] privilegeIds;
+
+    public Long[] getPrivilegeIds() {
+        return privilegeIds;
+    }
+
+    public void setPrivilegeIds(Long[] privilegeIds) {
+        this.privilegeIds = privilegeIds;
+    }
+}

+ 49 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/result/DictionaryResult.java

@@ -0,0 +1,49 @@
+package com.qmth.distributed.print.business.bean.result;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+
+/**
+ * @Description: 字典查询公共返回接口
+ * @Author: CaoZixuan
+ * @Date: 2021-11-02
+ */
+public class DictionaryResult implements Serializable {
+
+    @JsonSerialize(using = ToStringSerializer.class)
+    @ApiModelProperty(value = "主键")
+    private Long id;
+
+    @ApiModelProperty(value = "名称")
+    private String name;
+
+    @ApiModelProperty(value = "编号")
+    private String code;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+}

+ 27 - 3
distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/result/PrintPlanResult.java

@@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
 import com.qmth.distributed.print.business.enums.BackupMethodEnum;
 import com.qmth.distributed.print.business.enums.DrawRuleEnum;
+import com.qmth.distributed.print.business.enums.ExamPrintPlanSyncStatusEnum;
 import com.qmth.distributed.print.business.enums.PrintPlanStatusEnum;
 import io.swagger.annotations.ApiModelProperty;
 
@@ -22,6 +23,13 @@ public class PrintPlanResult {
     @ApiModelProperty(value = "印刷计划id")
     private Long id;
 
+    @JsonSerialize(using = ToStringSerializer.class)
+    @ApiModelProperty(value = "学期ID")
+    private Long semesterId;
+
+    @ApiModelProperty(value = "学期名称")
+    private String semesterName;
+
     @ApiModelProperty(value = "印刷计划名称")
     private String name;
 
@@ -86,7 +94,7 @@ public class PrintPlanResult {
     private String thirdRelateName;
 
     @ApiModelProperty("是否同步成功")
-    private Boolean syncStatus;
+    private ExamPrintPlanSyncStatusEnum syncStatus;
 
     public Long getId() {
         return id;
@@ -96,6 +104,22 @@ public class PrintPlanResult {
         this.id = id;
     }
 
+    public Long getSemesterId() {
+        return semesterId;
+    }
+
+    public void setSemesterId(Long semesterId) {
+        this.semesterId = semesterId;
+    }
+
+    public String getSemesterName() {
+        return semesterName;
+    }
+
+    public void setSemesterName(String semesterName) {
+        this.semesterName = semesterName;
+    }
+
     public String getName() {
         return name;
     }
@@ -256,11 +280,11 @@ public class PrintPlanResult {
         this.thirdRelateName = thirdRelateName;
     }
 
-    public Boolean getSyncStatus() {
+    public ExamPrintPlanSyncStatusEnum getSyncStatus() {
         return syncStatus;
     }
 
-    public void setSyncStatus(Boolean syncStatus) {
+    public void setSyncStatus(ExamPrintPlanSyncStatusEnum syncStatus) {
         this.syncStatus = syncStatus;
     }
 }

+ 338 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/result/TSyncExamStudentScoreResult.java

@@ -0,0 +1,338 @@
+package com.qmth.distributed.print.business.bean.result;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.qmth.teachcloud.common.annotation.ExcelProperty;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * @Description: 成绩同步result
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2021/11/1
+ */
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class TSyncExamStudentScoreResult implements Serializable {
+
+    @ApiModelProperty(value = "主键")
+    @JsonSerialize(using = ToStringSerializer.class)
+    Long id;
+
+    @ApiModelProperty(value = "学期id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    Long semesterId;
+
+    @ExcelProperty(name = "学期", width = 30, index = 1)
+    @ApiModelProperty(value = "学期")
+    String semesterName;
+
+    @ApiModelProperty(value = "云阅卷考试id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    Long examId;
+
+    @ApiModelProperty(value = "云阅卷考试编码")
+    String examCode;
+
+    @ExcelProperty(name = "姓名", width = 30, index = 2)
+    @ApiModelProperty(value = "考生姓名")
+    String name;
+
+    @ExcelProperty(name = "学号", width = 30, index = 3)
+    @ApiModelProperty(value = "学号")
+    String studentCode;
+
+    @ApiModelProperty(value = "准考证号")
+    String examNumber;
+
+    @ApiModelProperty(value = "学院id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    Long orgId;
+
+    @ExcelProperty(name = "院系", width = 30, index = 4)
+    @ApiModelProperty(value = "学院名称")
+    String orgName;
+
+    @ApiModelProperty(value = "专业id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    Long majorId;
+
+    @ApiModelProperty(value = "专业名称")
+    @ExcelProperty(name = "专业", width = 30, index = 5)
+    String majorName;
+
+    @ApiModelProperty(value = "班级id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    Long clazzId;
+
+    @ExcelProperty(name = "班级", width = 30, index = 6)
+    @ApiModelProperty(value = "班级")
+    String clazzName;
+
+    @ApiModelProperty(value = "课程编码")
+    String courseCode;
+
+    @ExcelProperty(name = "课程名称", width = 30, index = 7)
+    @ApiModelProperty(value = "课程名称")
+    String courseName;
+
+    @ApiModelProperty(value = "考生状态,1-正常,2-缺考(包含未上传),3-违纪")
+    Integer status;
+
+    @ApiModelProperty(value = "考生状态")
+    String statusStr;
+
+    @ApiModelProperty(value = "轨迹图url")
+    String trajectoryUrls;
+
+    @ApiModelProperty(value = "轨迹坐标")
+    String trajectoryCoordinate;
+
+    @ApiModelProperty(value = "同步时间")
+    Long syncTime;
+
+    @ApiModelProperty(value = "原卷url")
+    private String sheetUrls;
+
+    @ExcelProperty(name = "成绩总分", width = 30, index = 8)
+    @ApiModelProperty(value = "总分")
+    private Double totalScore;
+
+    @ApiModelProperty(value = "客观题分数")
+    private Double objectiveScore;
+
+    @ApiModelProperty(value = "主观题分数")
+    private Double subjectiveScore;
+
+    @ApiModelProperty(value = "阅卷数据")
+    private String syncData;
+
+    public String getSyncData() {
+        return syncData;
+    }
+
+    public void setSyncData(String syncData) {
+        this.syncData = syncData;
+    }
+
+    public String getExamNumber() {
+        return examNumber;
+    }
+
+    public void setExamNumber(String examNumber) {
+        this.examNumber = examNumber;
+    }
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public String getExamCode() {
+        return examCode;
+    }
+
+    public void setExamCode(String examCode) {
+        this.examCode = examCode;
+    }
+
+    public String getSemesterName() {
+        return semesterName;
+    }
+
+    public void setSemesterName(String semesterName) {
+        this.semesterName = semesterName;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getStatusStr() {
+        if (Objects.nonNull(getStatus())) {
+            String statusStr = null;
+            switch (getStatus()) {
+                case 1:
+                    statusStr = "正常";
+                    break;
+                case 2:
+                    statusStr = "缺考";
+                    break;
+                default:
+                    statusStr = "违纪";
+                    break;
+            }
+            return statusStr;
+        } else {
+            return statusStr;
+        }
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getSemesterId() {
+        return semesterId;
+    }
+
+    public void setSemesterId(Long semesterId) {
+        this.semesterId = semesterId;
+    }
+
+    public String getStudentCode() {
+        return studentCode;
+    }
+
+    public void setStudentCode(String studentCode) {
+        this.studentCode = studentCode;
+    }
+
+    public Long getOrgId() {
+        return orgId;
+    }
+
+    public void setOrgId(Long orgId) {
+        this.orgId = orgId;
+    }
+
+    public String getOrgName() {
+        return orgName;
+    }
+
+    public void setOrgName(String orgName) {
+        this.orgName = orgName;
+    }
+
+    public Long getMajorId() {
+        return majorId;
+    }
+
+    public void setMajorId(Long majorId) {
+        this.majorId = majorId;
+    }
+
+    public String getMajorName() {
+        return majorName;
+    }
+
+    public void setMajorName(String majorName) {
+        this.majorName = majorName;
+    }
+
+    public Long getClazzId() {
+        return clazzId;
+    }
+
+    public void setClazzId(Long clazzId) {
+        this.clazzId = clazzId;
+    }
+
+    public String getClazzName() {
+        return clazzName;
+    }
+
+    public void setClazzName(String clazzName) {
+        this.clazzName = clazzName;
+    }
+
+    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 Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public void setStatusStr(String statusStr) {
+        this.statusStr = statusStr;
+    }
+
+    public String getTrajectoryUrls() {
+        return trajectoryUrls;
+    }
+
+    public void setTrajectoryUrls(String trajectoryUrls) {
+        this.trajectoryUrls = trajectoryUrls;
+    }
+
+    public String getTrajectoryCoordinate() {
+        return trajectoryCoordinate;
+    }
+
+    public void setTrajectoryCoordinate(String trajectoryCoordinate) {
+        this.trajectoryCoordinate = trajectoryCoordinate;
+    }
+
+    public Long getSyncTime() {
+        return syncTime;
+    }
+
+    public void setSyncTime(Long syncTime) {
+        this.syncTime = syncTime;
+    }
+
+    public String getSheetUrls() {
+        return sheetUrls;
+    }
+
+    public void setSheetUrls(String sheetUrls) {
+        this.sheetUrls = sheetUrls;
+    }
+
+    public Double getTotalScore() {
+        return totalScore;
+    }
+
+    public void setTotalScore(Double totalScore) {
+        this.totalScore = totalScore;
+    }
+
+    public Double getObjectiveScore() {
+        return objectiveScore;
+    }
+
+    public void setObjectiveScore(Double objectiveScore) {
+        this.objectiveScore = objectiveScore;
+    }
+
+    public Double getSubjectiveScore() {
+        return subjectiveScore;
+    }
+
+    public void setSubjectiveScore(Double subjectiveScore) {
+        this.subjectiveScore = subjectiveScore;
+    }
+}

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

@@ -59,6 +59,12 @@ public class BasicCardRule extends BaseEntity implements Serializable {
      */
     @TableField("write_sign")
     private Boolean writeSign;
+
+    /**
+     * 0-禁用,1-启用
+     */
+    @TableField("discipline")
+    private Boolean discipline;
     /**
      * 必选字段
      */
@@ -161,6 +167,14 @@ public class BasicCardRule extends BaseEntity implements Serializable {
         this.writeSign = writeSign;
     }
 
+    public Boolean getDiscipline() {
+        return discipline;
+    }
+
+    public void setDiscipline(Boolean discipline) {
+        this.discipline = discipline;
+    }
+
     public String getRequiredFields() {
         return requiredFields;
     }

+ 43 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/BasicMessage.java

@@ -38,12 +38,31 @@ public class BasicMessage extends BaseEntity implements Serializable {
     @TableField("user_id")
     private Long userId;
 
+    /**
+     * 用户名称
+     */
+    @JsonSerialize(using = ToStringSerializer.class)
+    @TableField("user_name")
+    private String userName;
+
     /**
      * 手机号
      */
     @TableField("mobile_number")
     private String mobileNumber;
 
+    /**
+     * 试卷编号
+     */
+    @TableField("paper_number")
+    private String paperNumber;
+
+    /**
+     * 课程代码
+     */
+    @TableField("course_code")
+    private String courseCode;
+
     /**
      * 业务id
      */
@@ -133,6 +152,14 @@ public class BasicMessage extends BaseEntity implements Serializable {
         this.userId = userId;
     }
 
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
     public String getMobileNumber() {
         return mobileNumber;
     }
@@ -141,6 +168,22 @@ public class BasicMessage extends BaseEntity implements Serializable {
         this.mobileNumber = mobileNumber;
     }
 
+    public String getPaperNumber() {
+        return paperNumber;
+    }
+
+    public void setPaperNumber(String paperNumber) {
+        this.paperNumber = paperNumber;
+    }
+
+    public String getCourseCode() {
+        return courseCode;
+    }
+
+    public void setCourseCode(String courseCode) {
+        this.courseCode = courseCode;
+    }
+
     public Long getBusinessId() {
         return businessId;
     }

+ 225 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/ExamPaperStructure.java

@@ -0,0 +1,225 @@
+package com.qmth.distributed.print.business.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.qmth.distributed.print.business.enums.ExamPaperStructureStatusEnum;
+import com.qmth.teachcloud.common.base.BaseEntity;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * 考试试卷结构表
+ * </p>
+ *
+ * @author xf
+ */
+@TableName("exam_paper_structure")
+public class ExamPaperStructure extends BaseEntity implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "学校id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    @TableField("school_id")
+    private Long schoolId;
+
+    @ApiModelProperty(value = "学期ID")
+    @JsonSerialize(using = ToStringSerializer.class)
+    @TableField(value = "semester_id")
+    private Long semesterId;
+
+    /**
+     * 学期名称
+     */
+    @TableField("semester_name")
+    private String semesterName;
+
+    @ApiModelProperty(value = "云阅卷考试ID")
+    @JsonSerialize(using = ToStringSerializer.class)
+    @TableField(value = "third_relate_id")
+    private Long thirdRelateId;
+
+    /**
+     * 云阅卷考试名称
+     */
+    @TableField("third_relate_name")
+    private String thirdRelateName;
+
+    /**
+     * 试卷编号
+     */
+    @TableField("paper_number")
+    private String paperNumber;
+
+    /**
+     * 课程代码
+     */
+    @TableField("course_code")
+    private String courseCode;
+    /**
+     * 课程名称
+     */
+    @TableField("course_name")
+    private String courseName;
+    /**
+     * 试卷类型
+     */
+    @TableField("paper_type")
+    private String paperType;
+    /**
+     * 状态
+     */
+    private ExamPaperStructureStatusEnum status;
+    /**
+     * 试卷原卷和标答附件ID
+     */
+    @TableField("paper_answer")
+    private String paperAnswer;
+    /**
+     * 客观题试卷结构JSON
+     */
+    @TableField("objective_structure")
+    private String objectiveStructure;
+    /**
+     * 主观题试卷结构JSON
+     */
+    @TableField("subjective_structure")
+    private String subjectiveStructure;
+    /**
+     * 命题老师ID
+     */
+    @JsonSerialize(using = ToStringSerializer.class)
+    @TableField("proposition_teacher_id")
+    private Long propositionTeacherId;
+
+    /**
+     * 0-禁用,1-启用
+     */
+    private Boolean enable;
+
+    public Long getSchoolId() {
+        return schoolId;
+    }
+
+    public void setSchoolId(Long schoolId) {
+        this.schoolId = schoolId;
+    }
+
+    public Long getSemesterId() {
+        return semesterId;
+    }
+
+    public void setSemesterId(Long semesterId) {
+        this.semesterId = semesterId;
+    }
+
+    public String getSemesterName() {
+        return semesterName;
+    }
+
+    public void setSemesterName(String semesterName) {
+        this.semesterName = semesterName;
+    }
+
+    public Long getThirdRelateId() {
+        return thirdRelateId;
+    }
+
+    public void setThirdRelateId(Long thirdRelateId) {
+        this.thirdRelateId = thirdRelateId;
+    }
+
+    public String getThirdRelateName() {
+        return thirdRelateName;
+    }
+
+    public void setThirdRelateName(String thirdRelateName) {
+        this.thirdRelateName = thirdRelateName;
+    }
+
+    public String getPaperNumber() {
+        return paperNumber;
+    }
+
+    public void setPaperNumber(String paperNumber) {
+        this.paperNumber = 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 getPaperType() {
+        return paperType;
+    }
+
+    public void setPaperType(String paperType) {
+        this.paperType = paperType;
+    }
+
+    public ExamPaperStructureStatusEnum getStatus() {
+        return status;
+    }
+
+    public void setStatus(ExamPaperStructureStatusEnum status) {
+        this.status = status;
+    }
+
+    public String getPaperAnswer() {
+        return paperAnswer;
+    }
+
+    public void setPaperAnswer(String paperAnswer) {
+        this.paperAnswer = paperAnswer;
+    }
+
+    public String getObjectiveStructure() {
+        return objectiveStructure;
+    }
+
+    public void setObjectiveStructure(String objectiveStructure) {
+        this.objectiveStructure = objectiveStructure;
+    }
+
+    public String getSubjectiveStructure() {
+        return subjectiveStructure;
+    }
+
+    public void setSubjectiveStructure(String subjectiveStructure) {
+        this.subjectiveStructure = subjectiveStructure;
+    }
+
+    public Long getPropositionTeacherId() {
+        return propositionTeacherId;
+    }
+
+    public void setPropositionTeacherId(Long propositionTeacherId) {
+        this.propositionTeacherId = propositionTeacherId;
+    }
+
+    public Boolean getEnable() {
+        return enable;
+    }
+
+    public void setEnable(Boolean enable) {
+        this.enable = enable;
+    }
+}

+ 16 - 3
distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/ExamPrintPlan.java

@@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
 import com.qmth.distributed.print.business.enums.BackupMethodEnum;
 import com.qmth.distributed.print.business.enums.DrawRuleEnum;
+import com.qmth.distributed.print.business.enums.ExamPrintPlanSyncStatusEnum;
 import com.qmth.distributed.print.business.enums.PrintPlanStatusEnum;
 import com.qmth.teachcloud.common.base.BaseEntity;
 import io.swagger.annotations.ApiModelProperty;
@@ -106,7 +107,19 @@ public class ExamPrintPlan extends BaseEntity implements Serializable {
     private String thirdRelateName;
 
     @TableField("sync_status")
-    private Boolean syncStatus;
+    private ExamPrintPlanSyncStatusEnum syncStatus;
+
+    @ApiModelProperty(value = "学期id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long semesterId;
+
+    public Long getSemesterId() {
+        return semesterId;
+    }
+
+    public void setSemesterId(Long semesterId) {
+        this.semesterId = semesterId;
+    }
 
     public static long getSerialVersionUID() {
         return serialVersionUID;
@@ -224,11 +237,11 @@ public class ExamPrintPlan extends BaseEntity implements Serializable {
         this.thirdRelateName = thirdRelateName;
     }
 
-    public Boolean getSyncStatus() {
+    public ExamPrintPlanSyncStatusEnum getSyncStatus() {
         return syncStatus;
     }
 
-    public void setSyncStatus(Boolean syncStatus) {
+    public void setSyncStatus(ExamPrintPlanSyncStatusEnum syncStatus) {
         this.syncStatus = syncStatus;
     }
 }

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

@@ -63,6 +63,9 @@ public class ExamStudent extends BaseEntity implements Serializable {
     @TableField("clazz_id")
     private String clazzId;
 
+    @TableField("clazz_name")
+    private String clazzName;
+
     @JsonSerialize(using = ToStringSerializer.class)
     @ApiModelProperty(value = "附件id")
     @TableField(value = "attachment_id")
@@ -179,6 +182,14 @@ public class ExamStudent extends BaseEntity implements Serializable {
         this.clazzId = clazzId;
     }
 
+    public String getClazzName() {
+        return clazzName;
+    }
+
+    public void setClazzName(String clazzName) {
+        this.clazzName = clazzName;
+    }
+
     public Boolean getSyncStatus() {
         return syncStatus;
     }

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

@@ -5,8 +5,11 @@ import com.baomidou.mybatisplus.annotation.TableField;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
 import com.qmth.teachcloud.common.base.BaseEntity;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.enums.PushTypeEnum;
 import com.qmth.teachcloud.common.enums.TaskResultEnum;
 import com.qmth.teachcloud.common.enums.TaskStatusEnum;
+import com.qmth.teachcloud.common.enums.TaskTypeEnum;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
@@ -32,6 +35,10 @@ public class TBSyncTask extends BaseEntity implements Serializable {
     @TableField(value = "org_id", updateStrategy = FieldStrategy.IGNORED)
     private Long orgId;
 
+    @ApiModelProperty(value = "推送类型,USER_PUSH:用户推送")
+    @TableField(value = "type")
+    private PushTypeEnum type;
+
     @ApiModelProperty(value = "第三方关联id")
     @JsonSerialize(using = ToStringSerializer.class)
     @TableField("third_relate_id")
@@ -70,6 +77,22 @@ public class TBSyncTask extends BaseEntity implements Serializable {
     @TableField(value = "error_message", updateStrategy = FieldStrategy.IGNORED)
     private String errorMessage;
 
+    @ApiModelProperty(value = "报告路径")
+    @TableField(value = "report_file_path")
+    private String reportFilePath;
+
+    public TBSyncTask() {
+    }
+
+    public TBSyncTask(PushTypeEnum type, TaskStatusEnum status, Long createId, Long schoolId) {
+        setId(SystemConstant.getDbUuid());
+        this.type = type;
+        this.status = status;
+        setCreateId(createId);
+        setCreateTime(System.currentTimeMillis());
+        this.schoolId = schoolId;
+    }
+
     public static long getSerialVersionUID() {
         return serialVersionUID;
     }
@@ -161,4 +184,20 @@ public class TBSyncTask extends BaseEntity implements Serializable {
     public void setErrorMessage(String errorMessage) {
         this.errorMessage = errorMessage;
     }
+
+    public PushTypeEnum getType() {
+        return type;
+    }
+
+    public void setType(PushTypeEnum type) {
+        this.type = type;
+    }
+
+    public String getReportFilePath() {
+        return reportFilePath;
+    }
+
+    public void setReportFilePath(String reportFilePath) {
+        this.reportFilePath = reportFilePath;
+    }
 }

+ 397 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/TSyncExamStudentScore.java

@@ -0,0 +1,397 @@
+package com.qmth.distributed.print.business.entity;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * <p>
+ * 同步考生成绩表
+ * </p>
+ *
+ * @author wangliang
+ * @since 2021-10-28
+ */
+@ApiModel(value = "TSyncExamStudentScore对象", description = "同步考生成绩表")
+public class TSyncExamStudentScore implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long id;
+
+    @ApiModelProperty(value = "学校id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long schoolId;
+
+    @ApiModelProperty(value = "机构id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long orgId;
+
+    @ApiModelProperty(value = "学期id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long semesterId;
+
+    @ApiModelProperty(value = "云阅卷考试id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long examId;
+
+    @ApiModelProperty(value = "云阅卷考试标识")
+    private String examCode;
+
+    @ApiModelProperty(value = "准考证号")
+    private String examNumber;
+
+    @ApiModelProperty(value = "学号")
+    private String studentCode;
+
+    @ApiModelProperty(value = "姓名")
+    private String name;
+
+    @ApiModelProperty(value = "科目代码")
+    private String subjectCode;
+
+    @ApiModelProperty(value = "科目名称")
+    private String subjectName;
+
+    @ApiModelProperty(value = "试卷类型")
+    private String paperType;
+
+    @ApiModelProperty(value = "学院")
+    private String college;
+
+    @ApiModelProperty(value = "班级")
+    private String clazzName;
+
+    @ApiModelProperty(value = "教师")
+    private String teacher;
+
+    @ApiModelProperty(value = "考生状态,1-正常,2-缺考(包含未上传),3-违纪")
+    private Integer status;
+
+    @ApiModelProperty(value = "原卷url")
+    private String sheetUrls;
+
+    @ApiModelProperty(value = "总分")
+    private Double totalScore;
+
+    @ApiModelProperty(value = "客观题分数")
+    private Double objectiveScore;
+
+    @ApiModelProperty(value = "主观题分数")
+    private Double subjectiveScore;
+
+    @ApiModelProperty(value = "同步数据json")
+    private String syncData;
+
+    @ApiModelProperty(value = "轨迹图地址")
+    private String trajectoryUrls;
+
+    @ApiModelProperty(value = "创建人id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long createId;
+
+    @ApiModelProperty(value = "创建时间")
+    private Long createTime;
+
+    @ApiModelProperty(value = "专业id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long majorId;
+
+    @ApiModelProperty(value = "班级id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long clazzId;
+
+    @ApiModelProperty(value = "轨迹图文件")
+    @TableField(exist = false)
+    private List<File> trajectoryFileList;
+
+    public void setErrorInfo() {
+        this.trajectoryFileList = null;
+        this.trajectoryUrls = null;
+//        this.path = null;
+    }
+
+    public TSyncExamStudentScore() {
+
+    }
+
+    public TSyncExamStudentScore(Map map) {
+        this.id = SystemConstant.getDbUuid();
+        this.schoolId = (Long) map.get(SystemConstant.SCHOOL_ID);
+        this.orgId = (Long) map.get("orgId");
+        this.semesterId = (Long) map.get("semesterId");
+        this.majorId = (Long) map.get("majorId");
+        this.clazzId = (Long) map.get("clazzId");
+        this.examId = Long.parseLong(String.valueOf(map.get("examId")));
+        this.examCode = (String) map.get("examCode");
+        this.examNumber = (String) map.get("examNumber");
+        this.studentCode = (String) map.get("studentCode");
+        this.name = (String) map.get("name");
+        this.subjectCode = (String) map.get("subjectCode");
+        this.subjectName = (String) map.get("subjectName");
+        this.paperType = (String) map.get("paperType");
+        this.college = (String) map.get("college");
+        this.clazzName = (String) map.get("className");
+        this.teacher = (String) map.get("teacher");
+        this.status = (Integer) map.get("status");
+        JSONArray jsonArray = (JSONArray) map.get("sheetUrls");
+        if (Objects.nonNull(jsonArray) && jsonArray.size() > 0) {
+            this.sheetUrls = jsonArray.toJSONString();
+        }
+        this.totalScore = Double.parseDouble(String.valueOf(map.get("totalScore")));
+        this.objectiveScore = Double.parseDouble(String.valueOf(map.get("objectiveScore")));
+        this.subjectiveScore = Double.parseDouble(String.valueOf(map.get("subjectiveScore")));
+        this.createId = (Long) map.get("userId");
+        this.createTime = System.currentTimeMillis();
+
+        JSONObject jsonObject = new JSONObject();
+        JSONArray objectiveScoreDetailJsonArray = (JSONArray) map.get("objectiveScoreDetail");
+        JSONArray subjectiveScoreDetailJsonArray = (JSONArray) map.get("subjectiveScoreDetail");
+        JSONObject markTagsJsonObject = (JSONObject) map.get("markTags");
+        if (Objects.nonNull(objectiveScoreDetailJsonArray) && objectiveScoreDetailJsonArray.size() > 0) {
+            jsonObject.put("objectiveScoreDetail", objectiveScoreDetailJsonArray.toJSONString());
+        }
+        if (Objects.nonNull(subjectiveScoreDetailJsonArray) && subjectiveScoreDetailJsonArray.size() > 0) {
+            jsonObject.put("subjectiveScoreDetail", subjectiveScoreDetailJsonArray.toJSONString());
+        }
+        if (Objects.nonNull(markTagsJsonObject)) {
+            jsonObject.put("markTags", markTagsJsonObject.toJSONString());
+        }
+        if (!jsonObject.isEmpty()) {
+            this.syncData = jsonObject.toJSONString();
+        }
+    }
+
+    public Long getClazzId() {
+        return clazzId;
+    }
+
+    public void setClazzId(Long clazzId) {
+        this.clazzId = clazzId;
+    }
+
+    public Long getMajorId() {
+        return majorId;
+    }
+
+    public void setMajorId(Long majorId) {
+        this.majorId = majorId;
+    }
+
+    public List<File> getTrajectoryFileList() {
+        return trajectoryFileList;
+    }
+
+    public void setTrajectoryFileList(List<File> trajectoryFileList) {
+        this.trajectoryFileList = trajectoryFileList;
+    }
+
+    public Long getSemesterId() {
+        return semesterId;
+    }
+
+    public void setSemesterId(Long semesterId) {
+        this.semesterId = semesterId;
+    }
+
+    public static long getSerialVersionUID() {
+        return serialVersionUID;
+    }
+
+    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 getOrgId() {
+        return orgId;
+    }
+
+    public void setOrgId(Long orgId) {
+        this.orgId = orgId;
+    }
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public String getExamCode() {
+        return examCode;
+    }
+
+    public void setExamCode(String examCode) {
+        this.examCode = examCode;
+    }
+
+    public String getExamNumber() {
+        return examNumber;
+    }
+
+    public void setExamNumber(String examNumber) {
+        this.examNumber = examNumber;
+    }
+
+    public String getStudentCode() {
+        return studentCode;
+    }
+
+    public void setStudentCode(String studentCode) {
+        this.studentCode = studentCode;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public String getSubjectName() {
+        return subjectName;
+    }
+
+    public void setSubjectName(String subjectName) {
+        this.subjectName = subjectName;
+    }
+
+    public String getPaperType() {
+        return paperType;
+    }
+
+    public void setPaperType(String paperType) {
+        this.paperType = paperType;
+    }
+
+    public String getCollege() {
+        return college;
+    }
+
+    public void setCollege(String college) {
+        this.college = college;
+    }
+
+    public String getClazzName() {
+        return clazzName;
+    }
+
+    public void setClazzName(String clazzName) {
+        this.clazzName = clazzName;
+    }
+
+    public String getTeacher() {
+        return teacher;
+    }
+
+    public void setTeacher(String teacher) {
+        this.teacher = teacher;
+    }
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public String getSheetUrls() {
+        return sheetUrls;
+    }
+
+    public void setSheetUrls(String sheetUrls) {
+        this.sheetUrls = sheetUrls;
+    }
+
+    public Double getTotalScore() {
+        return totalScore;
+    }
+
+    public void setTotalScore(Double totalScore) {
+        this.totalScore = totalScore;
+    }
+
+    public Double getObjectiveScore() {
+        return objectiveScore;
+    }
+
+    public void setObjectiveScore(Double objectiveScore) {
+        this.objectiveScore = objectiveScore;
+    }
+
+    public Double getSubjectiveScore() {
+        return subjectiveScore;
+    }
+
+    public void setSubjectiveScore(Double subjectiveScore) {
+        this.subjectiveScore = subjectiveScore;
+    }
+
+    public String getSyncData() {
+        return syncData;
+    }
+
+    public void setSyncData(String syncData) {
+        this.syncData = syncData;
+    }
+
+    public String getTrajectoryUrls() {
+        return trajectoryUrls;
+    }
+
+    public void setTrajectoryUrls(String trajectoryUrls) {
+        this.trajectoryUrls = trajectoryUrls;
+    }
+
+    public Long getCreateId() {
+        return createId;
+    }
+
+    public void setCreateId(Long createId) {
+        this.createId = createId;
+    }
+
+    public Long getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Long createTime) {
+        this.createTime = createTime;
+    }
+}

+ 41 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/enums/DictionaryEnum.java

@@ -0,0 +1,41 @@
+package com.qmth.distributed.print.business.enums;
+
+import java.util.Objects;
+
+/**
+ * @Description: 字典管理枚举
+ * @Author: CaoZixuan
+ * @Date: 2021-11-02
+ */
+public enum DictionaryEnum {
+    CAMPUS("校区"),
+    SEMESTER("学期"),
+    COLLEGE("学院"),
+    MAJOR("专业"),
+    CLAZZ("班级"),
+    STUDENT("学生");
+    private final String desc;
+
+    DictionaryEnum(String desc) {
+        this.desc = desc;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+    /**
+     * 状态转换 toName
+     *
+     * @param title
+     * @return
+     */
+    public static String convertToName(String title) {
+        for (DictionaryEnum e : DictionaryEnum.values()) {
+            if (Objects.equals(title, e.getDesc())) {
+                return e.name();
+            }
+        }
+        return null;
+    }
+}

+ 48 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/enums/ExamPaperStructureStatusEnum.java

@@ -0,0 +1,48 @@
+package com.qmth.distributed.print.business.enums;
+
+import com.qmth.teachcloud.common.enums.EnumResult;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 考试试卷结构同步状态
+ */
+public enum ExamPaperStructureStatusEnum {
+
+    INIT("未开始"),
+    UPLOAD_FINISH("上传完成"),
+    START_SYNC("开始同步"),
+    PAPER_FINISH("试卷同步成功"),
+    ANSWER_FINISH("标答同步成功"),
+    OBJECTIVE_FINISH("客观题结构同步成功"),
+    SUBJECTIVE_FINISH("主观题结构同步成功"),
+    FINISH("结束");
+
+    ExamPaperStructureStatusEnum(String desc) {
+        this.desc = desc;
+    }
+
+    private String desc;
+
+    public String getDesc() {
+        return desc;
+    }
+
+    /**
+     * @return
+     */
+    public static List<EnumResult> listTypes() {
+        List<EnumResult> list = new ArrayList<EnumResult>();
+        for (ExamPaperStructureStatusEnum value : ExamPaperStructureStatusEnum.values()) {
+            EnumResult result = new EnumResult();
+            result.setName(value.name());
+            result.setOrdinal(value.ordinal());
+            result.setCode(null);
+            result.setDesc(value.getDesc());
+            list.add(result);
+        }
+        return list;
+    }
+
+}

+ 45 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/enums/ExamPrintPlanSyncStatusEnum.java

@@ -0,0 +1,45 @@
+package com.qmth.distributed.print.business.enums;
+
+import com.qmth.teachcloud.common.enums.EnumResult;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 考试试卷结构同步状态
+ */
+public enum ExamPrintPlanSyncStatusEnum {
+
+    INIT("未开始"),
+    START_SYNC("开始同步"),
+    EXAM_FINISH("考试同步成功"),
+    STUDENT_FINISH("考生同步成功"),
+    FINISH("题卡同步成功,已结束");
+
+    ExamPrintPlanSyncStatusEnum(String desc) {
+        this.desc = desc;
+    }
+
+    private String desc;
+
+    public String getDesc() {
+        return desc;
+    }
+
+    /**
+     * @return
+     */
+    public static List<EnumResult> listTypes() {
+        List<EnumResult> list = new ArrayList<EnumResult>();
+        for (ExamPrintPlanSyncStatusEnum value : ExamPrintPlanSyncStatusEnum.values()) {
+            EnumResult result = new EnumResult();
+            result.setName(value.name());
+            result.setOrdinal(value.ordinal());
+            result.setCode(null);
+            result.setDesc(value.getDesc());
+            list.add(result);
+        }
+        return list;
+    }
+
+}

+ 42 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/enums/ImageTrajectoryEnum.java

@@ -0,0 +1,42 @@
+package com.qmth.distributed.print.business.enums;
+
+import java.util.Objects;
+
+/**
+ * @Description: 生成原卷动态轨迹图 enum
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2021/11/3
+ */
+public enum ImageTrajectoryEnum {
+
+    PREVIEW("预览"),
+
+    DOWNLOAD("下载");
+
+    private String title;
+
+    private ImageTrajectoryEnum(String title) {
+        this.title = title;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * 状态转换 toName
+     *
+     * @param title
+     * @return
+     */
+    public static String convertToName(String title) {
+        for (ImageTrajectoryEnum e : ImageTrajectoryEnum.values()) {
+            if (Objects.equals(title, e.getTitle())) {
+                return e.name();
+            }
+        }
+        return null;
+    }
+}

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

@@ -1,5 +1,10 @@
 package com.qmth.distributed.print.business.enums;
 
+import com.qmth.teachcloud.common.enums.EnumResult;
+
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * @Description: 发送消息枚举类
  * @Author: CaoZixuan
@@ -37,7 +42,8 @@ public enum MessageEnum {
     NOTICE_OF_AUDIT_WILL_EXPIRE("审核待办到期预警通知","${userName}您好,您还有${count}条审核待办即将逾期,请您尽快处理!"),
     NOTICE_OF_AUDIT_OVERDUE("审核待办逾期通知","${userName}您好,您有${count}条审核待办已逾期!"),
 
-    NOTICE_OF_AUDIT_REJECT("审核驳回生成通知","${userName}您好,${courseNameAndPaperNumber}试卷审核未通过,请您尽快处理!");
+    NOTICE_OF_AUDIT_REJECT("审核驳回生成通知","${userName}您好,${courseNameAndPaperNumber}试卷审核未通过,请您尽快处理!"),
+    NOTICE_OF_UPLOAD_STRUCTURE("试卷结构标答上传通知","${userName}您好,${courseNameAndPaperNumber}试卷印刷任务已经完成,请上传试卷结构及标答生成阅卷任务,请您尽快处理!");
 
 
     MessageEnum(String name, String template) {
@@ -48,6 +54,20 @@ public enum MessageEnum {
     private final String name;
     private final String template;
 
+
+    public static List<EnumResult> listTypes() {
+        List<EnumResult> list = new ArrayList<>();
+        for (MessageEnum value : MessageEnum.values()) {
+            EnumResult result = new EnumResult();
+            result.setName(value.name());
+            result.setOrdinal(value.ordinal());
+            result.setCode(null);
+            result.setDesc(value.getName());
+            list.add(result);
+        }
+        return list;
+    }
+
     public String getName() {
         return name;
     }

+ 31 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/BasicSemesterMapper.java

@@ -0,0 +1,31 @@
+package com.qmth.distributed.print.business.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.qmth.teachcloud.common.entity.BasicSemester;
+import com.qmth.teachcloud.common.bean.result.BasicSemesterResult;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Set;
+
+/**
+ * <p>
+ * 学期字典表 Mapper 接口
+ * </p>
+ *
+ * @author wangliang
+ * @since 2021-10-28
+ */
+public interface BasicSemesterMapper extends BaseMapper<BasicSemester> {
+    /**
+     * 基础学期分页查询
+     * @param iPage 分页参数
+     * @param schoolId 学校id
+     * @param orgIds 权限id
+     * @return 分页结果
+     */
+    IPage<BasicSemesterResult> findBasicSemesterPage(@Param("iPage") Page<BasicSemesterResult> iPage,
+                                                    @Param("schoolId") Long schoolId,
+                                                    @Param("orgIds") Set<Long> orgIds);
+}

+ 22 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/ExamPaperStructureMapper.java

@@ -0,0 +1,22 @@
+package com.qmth.distributed.print.business.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.qmth.distributed.print.business.entity.ExamPaperStructure;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 考试试卷结构 Mapper 接口
+ * </p>
+ *
+ * @author xf
+ */
+public interface ExamPaperStructureMapper extends BaseMapper<ExamPaperStructure> {
+    IPage<ExamPaperStructure> listByPropositionTeacherId(@Param("page") Page<ExamPaperStructure> page, @Param("schoolId") Long schoolId, @Param("propositionTeacherId") Long propositionTeacherId, @Param("syncStatus") String syncStatus, @Param("structureStatusEnums") String[] structureStatusEnums);
+
+    List<ExamPaperStructure> listByPropositionTeacherId(@Param("schoolId") Long schoolId, @Param("propositionTeacherId") Long propositionTeacherId, @Param("syncStatus") String syncStatus, @Param("structureStatusEnums") String[] structureStatusEnums);
+}

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

@@ -24,6 +24,7 @@ import java.util.Set;
 public interface ExamPrintPlanMapper extends BaseMapper<ExamPrintPlan> {
     IPage<PrintPlanResult> findPrintPlanPage(@Param("iPage") Page<PrintPlanResult> iPage,
                                              @Param("schoolId") Long schoolId,
+                                             @Param("semesterId") Long semesterId,
                                              @Param("printPlanIdList") List<Long> printPlanIdList,
                                              @Param("status") PrintPlanStatusEnum status,
                                              @Param("startTime") Long startTime,
@@ -32,6 +33,7 @@ public interface ExamPrintPlanMapper extends BaseMapper<ExamPrintPlan> {
 
     IPage<PrintPlanResult> findPrintPlanSyncPage(@Param("iPage") Page<PrintPlanResult> iPage,
                                              @Param("schoolId") Long schoolId,
+                                             @Param("semesterId") Long semesterId,
                                              @Param("status") String[] status,
                                              @Param("printPlanId") Long printPlanId,
                                              @Param("startTime") Long startTime,

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

@@ -4,6 +4,7 @@ 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 com.qmth.teachcloud.common.entity.SysOrg;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
@@ -35,4 +36,6 @@ public interface ExamStudentMapper extends BaseMapper<ExamStudent> {
     void insertBatch(@Param("examStudents") List<ExamStudent> examStudents);
 
     List<ExamStudent> listExamStudentBySchoolIdAndClazzId(@Param("schoolId") Long schoolId, @Param("classId") String classId);
+
+    SysOrg getSysOrgByBelongOrgId(String studentCode);
 }

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

@@ -34,7 +34,7 @@ public interface ExamTaskMapper extends BaseMapper<ExamTask> {
 
     IPage<ExamTaskDto> listTaskReviewUnaudited(Page<ExamTaskDto> page, @Param("schoolId") Long schoolId, @Param("courseCode") String courseCode, @Param("paperNumber") String paperNumber, @Param("userId") Long userId, @Param("cardRuleId") Long cardRuleId, @Param("startTime") Long startTime, @Param("endTime") Long endTime, @Param("orgIds") Set<Long> orgIds, @Param("startCreateTime") Long startCreateTime, @Param("endCreateTime") Long endCreateTime, @Param("createName") String createName, @Param("currentUserId") Long currentUserId);
 
-    IPage<ExamTaskDto> listTaskReviewAudited(Page<ExamTaskDto> page, @Param("schoolId") Long schoolId, @Param("reviewStatus") String reviewStatus, @Param("courseCode") String courseCode, @Param("paperNumber") String paperNumber, @Param("userId") Long userId, @Param("cardRuleId") Long cardRuleId, @Param("startTime") Long startTime, @Param("endTime") Long endTime, @Param("orgIds") Set<Long> orgIds, @Param("startCreateTime") Long startCreateTime, @Param("endCreateTime") Long endCreateTime, @Param("createName") String createName);
+    IPage<ExamTaskDto> listTaskReviewAudited(Page<ExamTaskDto> page, @Param("schoolId") Long schoolId, @Param("reviewStatus") String reviewStatus, @Param("courseCode") String courseCode, @Param("paperNumber") String paperNumber, @Param("userId") Long userId, @Param("cardRuleId") Long cardRuleId, @Param("startTime") Long startTime, @Param("endTime") Long endTime, @Param("orgIds") Set<Long> orgIds, @Param("startCreateTime") Long startCreateTime, @Param("endCreateTime") Long endCreateTime, @Param("createName") String createName, @Param("currentUserId") Long currentUserId);
 
     IPage<ExamTaskDetailDto> listTaskPaper(Page<ExamTaskDetailDto> page, @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, @Param("makeMethod") MakeMethodEnum makeMethod, @Param("cardRuleId") Long cardRuleId);
 

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

@@ -1,7 +1,16 @@
 package com.qmth.distributed.print.business.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.qmth.distributed.print.business.entity.TBSyncTask;
+import com.qmth.teachcloud.common.bean.result.SyncListResult;
+import com.qmth.teachcloud.common.enums.PushTypeEnum;
+import com.qmth.teachcloud.common.enums.TaskResultEnum;
+import com.qmth.teachcloud.common.enums.TaskStatusEnum;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Set;
 
 /**
  * <p>
@@ -9,4 +18,23 @@ import com.qmth.distributed.print.business.entity.TBSyncTask;
  * </p>
  */
 public interface TBSyncTaskMapper extends BaseMapper<TBSyncTask> {
+
+    /**
+     * 同步任务管理分页查询
+     * @param iPage 分页参数
+     * @param schoolId 学校id
+     * @param status 任务状态
+     * @param type 同步任务类型
+     * @param result 任务结果
+     * @param createId 创建人主键
+     * @param orgIds 数据权限集合
+     * @return 分页结果
+     */
+    IPage<SyncListResult> query(@Param("iPage") Page<SyncListResult> iPage,
+                                @Param("schoolId") Long schoolId,
+                                @Param("status") TaskStatusEnum status,
+                                @Param("type") PushTypeEnum type,
+                                @Param("result") TaskResultEnum result,
+                                @Param("createId") Long createId,
+                                @Param("orgIds") Set<Long> orgIds);
 }

+ 77 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/mapper/TSyncExamStudentScoreMapper.java

@@ -0,0 +1,77 @@
+package com.qmth.distributed.print.business.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.qmth.distributed.print.business.bean.result.TSyncExamStudentScoreResult;
+import com.qmth.distributed.print.business.entity.TSyncExamStudentScore;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * 同步考生成绩表 Mapper 接口
+ * </p>
+ *
+ * @author wangliang
+ * @since 2021-10-28
+ */
+public interface TSyncExamStudentScoreMapper extends BaseMapper<TSyncExamStudentScore> {
+
+    /**
+     * 同步成绩查询列表
+     *
+     * @param iPage
+     * @param schoolId
+     * @param semesterId
+     * @param orgId
+     * @param majorId
+     * @param clazzId
+     * @param courseCode
+     * @return
+     */
+    public IPage<TSyncExamStudentScoreResult> list(IPage<Map> iPage,
+                                                   @Param("schoolId") Long schoolId,
+                                                   @Param("semesterId") Long semesterId,
+                                                   @Param("orgId") Long orgId,
+                                                   @Param("majorId") Long majorId,
+                                                   @Param("clazzId") Long clazzId,
+                                                   @Param("courseCode") String courseCode);
+
+    /**
+     * 成绩导出
+     *
+     * @param schoolId
+     * @param semesterId
+     * @param orgId
+     * @param majorId
+     * @param clazzId
+     * @param courseCode
+     * @return
+     */
+    public List<TSyncExamStudentScoreResult> export(@Param("schoolId") Long schoolId,
+                                                    @Param("semesterId") Long semesterId,
+                                                    @Param("orgId") Long orgId,
+                                                    @Param("majorId") Long majorId,
+                                                    @Param("clazzId") Long clazzId,
+                                                    @Param("courseCode") String courseCode);
+
+    /**
+     * 成绩导出计数
+     *
+     * @param schoolId
+     * @param semesterId
+     * @param orgId
+     * @param majorId
+     * @param clazzId
+     * @param courseCode
+     * @return
+     */
+    public int exportCount(@Param("schoolId") Long schoolId,
+                           @Param("semesterId") Long semesterId,
+                           @Param("orgId") Long orgId,
+                           @Param("majorId") Long majorId,
+                           @Param("clazzId") Long clazzId,
+                           @Param("courseCode") String courseCode);
+}

+ 35 - 12
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/BasicMessageService.java

@@ -1,14 +1,15 @@
 package com.qmth.distributed.print.business.service;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.qmth.distributed.print.business.entity.BasicMessage;
 import com.qmth.distributed.print.business.entity.ExamTask;
 import com.qmth.distributed.print.business.enums.MessageEnum;
 import com.qmth.teachcloud.common.bean.params.ApproveUserResult;
 import com.qmth.teachcloud.common.entity.SysUser;
+import com.qmth.teachcloud.common.enums.EnumResult;
 
 import java.util.List;
-import java.util.Set;
 
 /**
  * @Description: 短信消息发送
@@ -17,17 +18,6 @@ import java.util.Set;
  */
 public interface BasicMessageService extends IService<BasicMessage> {
 
-    /**
-     * 保存消息发送日志(以下参数必传)
-     *
-     * @param userId         接收人id
-     * @param mobileNumber   接收人电话
-     * @param businessId     业务id
-     * @param variableParams 变量参数
-     * @param messageType    消息类型
-     */
-    void saveMessageSendLog(Long userId, String mobileNumber, Long businessId, String variableParams, Long createId, MessageEnum messageType, String remark);
-
     /**
      * 命题任务审核消息处理
      *
@@ -72,4 +62,37 @@ public interface BasicMessageService extends IService<BasicMessage> {
      * @param messageType
      */
     void sendNoticeTaskAuditFlow(ExamTask examTask, List<ApproveUserResult> users, MessageEnum messageType);
+
+    /**
+     * 发送给命题老师-试卷结构标答上传通知
+     * @param paperNumber 试卷编号
+     * @param courseCode 课程代码
+     * @param userId 命题老师ID
+     * @param messageType 短信类型
+     * @param sysUser
+     */
+    void sendNoticeUploadStructure(String paperNumber, String courseCode, Long userId, MessageEnum messageType, SysUser sysUser);
+
+    /**
+     * 查询
+     * @param messageType
+     * @param sendStatus
+     * @param mobileNumber
+     * @param pageNumber
+     * @param pageSize
+     * @return
+     */
+    IPage<BasicMessage> listByMessageType(MessageEnum messageType, Boolean sendStatus, String mobileNumber, Integer pageNumber, Integer pageSize);
+
+    /**
+     * 查询短信类型
+     * @return
+     */
+    List<EnumResult> listMessageTypes();
+
+    /**
+     * 短信失败重发
+     * @param id
+     */
+    void resendSmsTaskById(Long id);
 }

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

@@ -1,9 +1,11 @@
 package com.qmth.distributed.print.business.service;
 
 import com.qmth.distributed.print.business.bean.params.SyncDataParam;
+import com.qmth.distributed.print.business.entity.ExamPaperStructure;
 
 /**
  * 同步数据到云阅卷 服务类
+ *
  * @Date: 2021/5/20.
  */
 public interface DataSyncService {
@@ -12,4 +14,7 @@ public interface DataSyncService {
     void syncDataCloud(Long printPlanId, Long thirdRelateId);
 
     void syncDataMerge(SyncDataParam syncDataParam);
+
+    void syncPaperStructure(ExamPaperStructure examPaperStructure);
+
 }

+ 30 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/ExamPaperStructureService.java

@@ -0,0 +1,30 @@
+package com.qmth.distributed.print.business.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.qmth.distributed.print.business.entity.ExamPaperStructure;
+import com.qmth.distributed.print.business.enums.ExamPaperStructureStatusEnum;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * 试卷结构 服务类
+ * </p>
+ *
+ * @author xf
+ */
+public interface ExamPaperStructureService extends IService<ExamPaperStructure> {
+
+    IPage<ExamPaperStructure> listByPropositionTeacherId(Integer pageNumber, Integer pageSize, String[] structureStatusEnums);
+
+    ExamPaperStructure upload(String examPaperStructure, String md5, MultipartFile[] files);
+
+    void updateStatusById(Long id, ExamPaperStructureStatusEnum startSync);
+
+    List<Map> preStructure(Long id);
+
+    long countByPropositionTeacherId();
+}

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

@@ -11,6 +11,7 @@ import com.qmth.distributed.print.business.bean.result.PrintPlanBrief;
 import com.qmth.distributed.print.business.bean.result.PrintPlanResult;
 import com.qmth.distributed.print.business.entity.ExamPrintPlan;
 import com.qmth.distributed.print.business.enums.PrintPlanStatusEnum;
+import com.qmth.teachcloud.common.entity.SysUser;
 
 import java.util.List;
 import java.util.Map;
@@ -28,6 +29,7 @@ public interface ExamPrintPlanService extends IService<ExamPrintPlan> {
      * 印刷计划分页查询
      *
      * @param schoolId   学校id
+     * @param semesterId
      * @param printPlanIdList  印刷计划id集合
      * @param status     印刷计划状态
      * @param startTime  印刷计划创建时间开始
@@ -36,9 +38,9 @@ public interface ExamPrintPlanService extends IService<ExamPrintPlan> {
      * @param pageSize   分页容量
      * @return 分页查询结果
      */
-    IPage<PrintPlanResult> printPlanPage(Long schoolId, List<Long> printPlanIdList, PrintPlanStatusEnum status, Long startTime, Long endTime, int pageNumber, int pageSize);
+    IPage<PrintPlanResult> printPlanPage(Long schoolId, Long semesterId, List<Long> printPlanIdList, PrintPlanStatusEnum status, Long startTime, Long endTime, int pageNumber, int pageSize);
 
-    IPage<PrintPlanResult> printPlanSyncPage(Long schoolId, Long printPlanId, Long startTime, Long endTime, int pageNumber, int pageSize);
+    IPage<PrintPlanResult> printPlanSyncPage(Long schoolId, Long semesterId, Long printPlanId, Long startTime, Long endTime, int pageNumber, int pageSize);
 
     /**
      * 印刷计划模糊名称
@@ -101,4 +103,6 @@ public interface ExamPrintPlanService extends IService<ExamPrintPlan> {
      * @return 印刷计划
      */
     ExamPrintPlan findByExamDetailId(Long examDetailId);
+
+    void sendNoticeUploadStructure(Long id, SysUser sysUser);
 }

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

@@ -5,6 +5,7 @@ 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.teachcloud.common.entity.SysOrg;
 
 import java.util.List;
 import java.util.Map;
@@ -39,4 +40,6 @@ public interface ExamStudentService extends IService<ExamStudent> {
     void insertBatch(List<ExamStudent> examStudents);
 
     List<ExamStudent> listExamStudentBySchoolIdAndClazzId(Long schoolId, String classId);
+
+    SysOrg getSysOrgByBelongOrgId(String studentCode);
 }

+ 25 - 4
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/PrintCommonService.java

@@ -6,17 +6,18 @@ import com.qmth.distributed.print.business.bean.dto.PdfDto;
 import com.qmth.distributed.print.business.bean.params.SerialNumberParams;
 import com.qmth.distributed.print.business.entity.ExamDetail;
 import com.qmth.distributed.print.business.entity.ExamStudent;
-import com.qmth.distributed.print.business.entity.ExamTaskPrint;
 import com.qmth.teachcloud.common.entity.BasicAttachment;
 import com.qmth.teachcloud.common.entity.BasicCourse;
 import com.qmth.teachcloud.common.entity.SysOrg;
 import com.qmth.teachcloud.common.entity.SysUser;
 import com.qmth.teachcloud.common.enums.ClassifyEnum;
+import com.qmth.teachcloud.common.enums.PushTypeEnum;
 import com.qmth.teachcloud.common.enums.TaskTypeEnum;
 import com.qmth.teachcloud.common.enums.UploadFileEnum;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.web.multipart.MultipartFile;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.List;
 import java.util.Map;
@@ -58,12 +59,13 @@ public interface PrintCommonService {
 
     /**
      * 保存html附件和该html转成pdf的附件
-     * @param fileName 文件名称
+     *
+     * @param fileName    文件名称
      * @param htmlContent html内容
-     * @param userId 创建人
+     * @param userId      创建人
      * @return 附件对象
      */
-    public BasicAttachment saveAttachmentHtmlAndPdf(String fileName, String htmlContent,Long userId) throws IOException;
+    public BasicAttachment saveAttachmentHtmlAndPdf(String fileName, String htmlContent, Long userId) throws IOException;
 
     /**
      * 保存附件公用
@@ -200,6 +202,14 @@ public interface PrintCommonService {
      */
     public Map<String, Object> saveTask(Long printPlanId, TaskTypeEnum taskTypeEnum);
 
+    /**
+     * 保存推送
+     *
+     * @param pushTypeEnum 推送类型
+     * @return 结果
+     */
+    Map<String, Object> savePush(PushTypeEnum pushTypeEnum);
+
     /**
      * 校验课程关联考场是否提交打印
      *
@@ -232,6 +242,7 @@ public interface PrintCommonService {
 
     /**
      * 保存考务数据
+     *
      * @param schoolId
      * @param extendFields
      * @param classIds
@@ -242,8 +253,18 @@ public interface PrintCommonService {
 
     /**
      * 生成准考证号
+     *
      * @param serialNumberParams
      * @return
      */
     public String createTempNumber(SerialNumberParams serialNumberParams);
+
+    /**
+     * 保存任务附件(导出)
+     *
+     * @param fos
+     * @param oss
+     * @return
+     */
+    public String saveTaskAttachment(ByteArrayOutputStream fos, boolean oss) throws IOException;
 }

+ 14 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/SsoService.java

@@ -0,0 +1,14 @@
+package com.qmth.distributed.print.business.service;
+
+import java.util.Map;
+
+/**
+ * 单点登录 服务类
+ *
+ * @Date: 2021/5/20.
+ */
+public interface SsoService {
+    Map<String, Object> markerLoginInfo();
+
+    Map<String, Object> markerLeaderLoginInfo();
+}

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

@@ -1,8 +1,16 @@
 package com.qmth.distributed.print.business.service;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.qmth.distributed.print.business.entity.ExamPrintPlan;
 import com.qmth.distributed.print.business.entity.TBSyncTask;
+import com.qmth.teachcloud.common.bean.result.SyncListResult;
+import com.qmth.teachcloud.common.entity.SysUser;
+import com.qmth.teachcloud.common.enums.PushTypeEnum;
+import com.qmth.teachcloud.common.enums.TaskResultEnum;
+import com.qmth.teachcloud.common.enums.TaskStatusEnum;
+
+import java.util.Map;
 
 /**
  * <p>
@@ -12,4 +20,18 @@ import com.qmth.distributed.print.business.entity.TBSyncTask;
 public interface TBSyncTaskService extends IService<TBSyncTask> {
 
     TBSyncTask saveTask(ExamPrintPlan examPrintPlan);
+
+    TBSyncTask savePushCommon(PushTypeEnum pushTypeEnum, Map map, SysUser sysUser);
+
+    /**
+     * 同步任务管理分页查询
+     * @param schoolId 学校id
+     * @param status 任务状态
+     * @param type 同步任务类型
+     * @param result 任务结果
+     * @param pageNumber 分页页数
+     * @param pageSize 分页容量
+     * @return 分页结果
+     */
+    IPage<SyncListResult> query(Long schoolId, TaskStatusEnum status, PushTypeEnum type, TaskResultEnum result,int pageNumber,int pageSize);
 }

+ 93 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/TSyncExamStudentScoreService.java

@@ -0,0 +1,93 @@
+package com.qmth.distributed.print.business.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.qmth.distributed.print.business.bean.result.TSyncExamStudentScoreResult;
+import com.qmth.distributed.print.business.entity.TSyncExamStudentScore;
+import com.qmth.distributed.print.business.enums.ImageTrajectoryEnum;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * 同步考生成绩表 服务类
+ * </p>
+ *
+ * @author wangliang
+ * @since 2021-10-28
+ */
+public interface TSyncExamStudentScoreService extends IService<TSyncExamStudentScore> {
+
+    /**
+     * 同步成绩查询列表
+     *
+     * @param iPage
+     * @param semesterId
+     * @param orgId
+     * @param majorId
+     * @param clazzId
+     * @param courseCode
+     * @return
+     */
+    public IPage<TSyncExamStudentScoreResult> list(IPage<Map> iPage,
+                                                   Long semesterId,
+                                                   Long orgId,
+                                                   Long majorId,
+                                                   Long clazzId,
+                                                   String courseCode);
+
+    /**
+     * 成绩导出
+     *
+     * @param schoolId
+     * @param semesterId
+     * @param orgId
+     * @param majorId
+     * @param clazzId
+     * @param courseCode
+     * @return
+     */
+    public List<TSyncExamStudentScoreResult> export(Long schoolId,
+                                                    Long semesterId,
+                                                    Long orgId,
+                                                    Long majorId,
+                                                    Long clazzId,
+                                                    String courseCode);
+
+    /**
+     * 成绩导出计数
+     *
+     * @param schoolId
+     * @param semesterId
+     * @param orgId
+     * @param majorId
+     * @param clazzId
+     * @param courseCode
+     * @return
+     */
+    public int exportCount(Long schoolId,
+                           Long semesterId,
+                           Long orgId,
+                           Long majorId,
+                           Long clazzId,
+                           String courseCode);
+
+    /**
+     * 创建动态轨迹图
+     *
+     * @param tSyncExamStudentScore
+     * @param imageTrajectoryEnum
+     * @return
+     */
+    public TSyncExamStudentScore createImageTrajectory(TSyncExamStudentScore tSyncExamStudentScore, ImageTrajectoryEnum imageTrajectoryEnum);
+
+    /**
+     * 生成zip文件
+     *
+     * @param tSyncExamStudentScore
+     * @throws IOException
+     */
+    public void createZipFile(TSyncExamStudentScore tSyncExamStudentScore) throws IOException;
+}

+ 199 - 221
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/BasicMessageServiceImpl.java

@@ -1,15 +1,10 @@
 package com.qmth.distributed.print.business.service.impl;
 
 import com.alibaba.fastjson.JSON;
-import com.aliyuncs.DefaultAcsClient;
-import com.aliyuncs.IAcsClient;
-import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
 import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
-import com.aliyuncs.exceptions.ClientException;
-import com.aliyuncs.http.MethodType;
-import com.aliyuncs.profile.DefaultProfile;
-import com.aliyuncs.profile.IClientProfile;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qmth.distributed.print.business.entity.BasicMessage;
 import com.qmth.distributed.print.business.entity.ExamTask;
@@ -17,19 +12,21 @@ import com.qmth.distributed.print.business.enums.MessageEnum;
 import com.qmth.distributed.print.business.mapper.BasicMessageMapper;
 import com.qmth.distributed.print.business.service.BasicMessageService;
 import com.qmth.distributed.print.business.service.ExamTaskService;
+import com.qmth.distributed.print.business.util.SmsUtils;
 import com.qmth.teachcloud.common.bean.params.ApproveUserResult;
-import com.qmth.teachcloud.common.config.DictionaryConfig;
 import com.qmth.teachcloud.common.contant.SpringContextHolder;
 import com.qmth.teachcloud.common.contant.SystemConstant;
 import com.qmth.teachcloud.common.entity.SysConfig;
 import com.qmth.teachcloud.common.entity.SysUser;
+import com.qmth.teachcloud.common.enums.EnumResult;
 import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
 import com.qmth.teachcloud.common.service.CommonCacheService;
 import com.qmth.teachcloud.common.service.SysConfigService;
 import com.qmth.teachcloud.common.util.ServletUtil;
 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 javax.annotation.Resource;
 import java.util.*;
@@ -44,128 +41,173 @@ import java.util.stream.Collectors;
 public class BasicMessageServiceImpl extends ServiceImpl<BasicMessageMapper, BasicMessage> implements BasicMessageService {
     @Resource
     private SysConfigService sysConfigService;
-    @Resource
-    private DictionaryConfig dictionaryConfig;
+
     @Resource
     private CommonCacheService commonCacheService;
 
-    @Transactional(rollbackFor = Exception.class)
-    @Override
-    public void saveMessageSendLog(Long userId, String mobileNumber, Long businessId, String variableParams, Long createId, MessageEnum messageType, String remark) {
-        String schoolId = ServletUtil.getRequestHeaderSchoolId().toString();
-        BasicMessage basicMessage = new BasicMessage();
-        // code和content
-        Map<String, String> enumInfo = this.getCodeAndContentByEnum(messageType);
-        String templateCode = enumInfo.get("templateCode");
-        String templateContent = enumInfo.get("templateContent");
+    @Autowired
+    private SmsUtils smsUtils;
 
-        String errorMessage = null;
-        if (SystemConstant.strNotNull(mobileNumber)){
-            try {
-                // 其他方法调用所传入的参数,必须校验有值
-                this.checkData(userId, variableParams, messageType);
+    @Override
+    public IPage<BasicMessage> listByMessageType(MessageEnum messageType, Boolean sendStatus, String mobileNumber, Integer pageNumber, Integer pageSize) {
+        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
+        Page<BasicMessage> page = new Page<>(pageNumber, pageSize);
+        QueryWrapper<BasicMessage> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(BasicMessage::getSchoolId, schoolId);
+        if (!Objects.isNull(messageType)) {
+            queryWrapper.lambda().eq(BasicMessage::getMessageType, messageType);
+        }
+        if (Objects.nonNull(sendStatus)) {
+            if (sendStatus) {
+                queryWrapper.lambda().eq(BasicMessage::getSendStatus, "OK");
+            } else {
+                queryWrapper.lambda().ne(BasicMessage::getSendStatus, "OK");
+            }
+        }
+        if (StringUtils.isNotBlank(mobileNumber)) {
+            queryWrapper.lambda().like(BasicMessage::getMobileNumber, "%" + mobileNumber + "%");
+        }
+        queryWrapper.lambda().orderByDesc(BasicMessage::getCreateTime);
+        return this.page(page, queryWrapper);
+    }
 
-                // 短信提示系统是否启用配置验证
-                SysConfig sysConfig = sysConfigService.getByKey("sys.message.enable");
-                if (sysConfig == null) {
-                    throw ExceptionResultEnum.ERROR.exception("未找到短信配置");
-                }
-                if (sysConfig.getConfigValue() == null) {
-                    throw ExceptionResultEnum.ERROR.exception("短信消息提示启用开关未设置");
-                }
-                if (sysConfig.getConfigValue().equals("false")) {
-                    throw ExceptionResultEnum.ERROR.exception("短信消息提示已关闭");
-                }
+    @Override
+    public List<EnumResult> listMessageTypes() {
+        return MessageEnum.listTypes();
+    }
 
-                SendSmsResponse sendSmsResponse = sendSms(mobileNumber, templateCode, variableParams);
+    @Override
+    public void resendSmsTaskById(Long id) {
+        BasicMessage basicMessage = this.getById(id);
+        if (Objects.isNull(basicMessage)) {
+            return;
+        }
+        this.saveMessageResendLog(basicMessage);
+    }
 
-                if (sendSmsResponse.getCode() != null) {
+    /**
+     * 发送短信
+     *
+     * @param userId
+     * @param userName
+     * @param mobileNumber
+     * @param paperNumber
+     * @param courseCode
+     * @param variableParams
+     * @param messageType
+     * @param createId
+     * @param remark
+     */
+    public void saveMessageSendLog(Long schoolId, Long userId, String userName, String mobileNumber, String paperNumber, String courseCode, String variableParams, MessageEnum messageType, Long createId, String remark) {
+        BasicMessage basicMessage = new BasicMessage();
+        String templateCode = null;
+        try {
+            // code和content
+            Map<String, String> enumInfo = smsUtils.getCodeAndContentByEnum(messageType);
+            if (!enumInfo.containsKey("templateCode")) {
+                throw ExceptionResultEnum.ERROR.exception("未找到短信模板Code");
+            }
+            templateCode = enumInfo.get("templateCode");
+            if (StringUtils.isBlank(templateCode)) {
+                throw ExceptionResultEnum.ERROR.exception("阿里云短信模板Code必填");
+            }
 
-                    basicMessage.setSendStatus(sendSmsResponse.getCode());
-                    basicMessage.setSendResult(sendSmsResponse.getMessage());
+            // 发送短信参数配置验证
+            SysConfig sysConfig = sysConfigService.getByKey("sys.message.enable");
+            if (sysConfig == null) {
+                throw ExceptionResultEnum.ERROR.exception("未找到发送短信开关配置参数,默认不发送");
+            }
+            if (sysConfig.getConfigValue() == null) {
+                throw ExceptionResultEnum.ERROR.exception("未正确配置发送短信开关参数,默认不发送");
+            }
+            if (sysConfig.getConfigValue().equals("false")) {
+                throw ExceptionResultEnum.ERROR.exception("发送短信开关设置为已关闭");
+            }
 
-                } else {
-                    throw ExceptionResultEnum.ERROR.exception(sendSmsResponse.getMessage());
-                }
-            } catch (Exception e) {
-                errorMessage = e.getMessage();
-            } finally {
-                // 传入的必填字段
-                basicMessage.setSchoolId(Long.valueOf(schoolId));
-                basicMessage.setUserId(userId);
-                basicMessage.setMobileNumber(mobileNumber);
-                basicMessage.setBusinessId(businessId);
-                basicMessage.setVariableParams(variableParams);
-                basicMessage.setCreateId(createId);
-                basicMessage.setMessageType(messageType);
-                basicMessage.setRemark(remark);
-                basicMessage.setResendCount(0);
+            // 参数校验
+            if (StringUtils.isBlank(userName)) {
+                throw ExceptionResultEnum.ERROR.exception("用户名称必填");
+            }
+            if (StringUtils.isBlank(mobileNumber)) {
+                throw ExceptionResultEnum.ERROR.exception("用户手机号必填");
+            }
+            if (StringUtils.isBlank(variableParams)) {
+                throw ExceptionResultEnum.ERROR.exception("短信内容参数值必填");
+            }
 
-                // 经过处理的新字段
-                basicMessage.setId(SystemConstant.getDbUuid());
-                basicMessage.setBusinessOperate(messageType.getName());
-                basicMessage.setCreateTime(System.currentTimeMillis());
-                basicMessage.setTemplateCode(templateCode);
-                if (errorMessage != null && errorMessage.length() > 0) {
-                    basicMessage.setSendStatus("SYSTEM_ERROR");
-                    basicMessage.setSendResult(errorMessage);
-                }
-                this.save(basicMessage);
+            // 调用阿里云短信平台发送短信
+            SendSmsResponse sendSmsResponse = smsUtils.sendSms(mobileNumber, templateCode, variableParams);
+            if (sendSmsResponse == null) {
+                throw ExceptionResultEnum.ERROR.exception("阿里云短信发送接口调用失败");
             }
+            basicMessage.setSendStatus(sendSmsResponse.getCode());
+            basicMessage.setSendResult(sendSmsResponse.getMessage());
+
+        } catch (Exception e) {
+            basicMessage.setSendStatus("SYSTEM_ERROR");
+            basicMessage.setSendResult(e.getMessage());
+        } finally {
+            basicMessage.setId(SystemConstant.getDbUuid());
+            basicMessage.setSchoolId(schoolId);
+            basicMessage.setUserId(userId);
+            basicMessage.setUserName(userName);
+            basicMessage.setMobileNumber(mobileNumber);
+            basicMessage.setPaperNumber(paperNumber);
+            basicMessage.setCourseCode(courseCode);
+            basicMessage.setTemplateCode(templateCode);
+            basicMessage.setVariableParams(variableParams);
+            basicMessage.setMessageType(messageType);
+            basicMessage.setBusinessOperate(messageType.getName());
+            basicMessage.setRemark(remark);
+            basicMessage.setResendCount(0);
+            basicMessage.setCreateId(createId);
+            basicMessage.setCreateTime(System.currentTimeMillis());
+            this.save(basicMessage);
         }
     }
 
     /**
-     * 发送短信
-     * @param mobileNumber
-     * @param templateCode
-     * @param variableParams
-     * @return
-     * @throws ClientException
+     * 失败重发
+     *
+     * @param basicMessage
      */
-    private SendSmsResponse sendSms(String mobileNumber, String templateCode, String variableParams) throws ClientException {
-        System.setProperty("sun.net.client.defaultConnectTimeout", "180000");
-        System.setProperty("sun.net.client.defaultReadTimeout", "18000");
-        // 初始化ascClient需要的几个参数
-        final String product = "Dysmsapi";// 短信API产品名称(短信产品名固定,无需修改)
-        final String domain = "dysmsapi.aliyuncs.com";// 短信API产品域名(接口地址固定,无需修改)
-        // 替换成你的AK
-        final String accessKeyId = dictionaryConfig.smsDomain().getAliyunSMSKey();// 你的accessKeyId,参考本文档步骤2
-        final String accessKeySecret = dictionaryConfig.smsDomain().getAliyunSMSSecret();// 你的accessKeySecret,参考本文档步骤2
-        // 初始化ascClient,暂时不支持多region(请勿修改)
-        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
-        DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
-        IAcsClient acsClient = new DefaultAcsClient(profile);
-        // 组装请求对象
-        SendSmsRequest request = new SendSmsRequest();
-        // 使用post提交
-        request.setMethod(MethodType.POST);
-        // 必填:待发送手机号。支持以逗号分隔的形式进行批量调用,批量上限为1000个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式;发送国际/港澳台消息时,接收号码格式为00+国际区号+号码,如“0085200000000”
-        request.setPhoneNumbers(mobileNumber);
-        // 必填:短信签名-可在短信控制台中找到
-        request.setSignName(dictionaryConfig.smsDomain().getAliyunSMSSignName());
-        // 必填:短信模板-可在短信控制台中找到
-        request.setTemplateCode(templateCode);
-        // 可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
-        // 友情提示:如果JSON中需要带换行符,请参照标准的JSON协议对换行符的要求,比如短信内容中包含\r\n的情况在JSON中需要表示成\\r\\n,否则会导致JSON在服务端解析失败
-        request.setTemplateParam(variableParams);
-        // 可选-上行短信扩展码(扩展码字段控制在7位或以下,无特殊需求用户请忽略此字段)
-        // request.setSmsUpExtendCode("90997");
-        // 可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
-//             request.setOutId("yourOutId");
-        // 请求失败这里会抛ClientException异常
+    public void saveMessageResendLog(BasicMessage basicMessage) {
+        try {
+            if (basicMessage == null) {
+                return;
+            }
+            if ("OK".equals(basicMessage.getSendStatus())) {
+                return;
+            }
 
-        SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
-        return sendSmsResponse;
+            if (!StringUtils.isBlank(basicMessage.getMobileNumber())) {
+                // 调用阿里云短信平台发送短信
+                SendSmsResponse sendSmsResponse = smsUtils.sendSms(basicMessage.getMobileNumber(), basicMessage.getTemplateCode(), basicMessage.getVariableParams());
+                if (sendSmsResponse == null) {
+                    throw ExceptionResultEnum.ERROR.exception("阿里云短信发送接口调用失败");
+                }
+                basicMessage.setSendStatus(sendSmsResponse.getCode());
+                basicMessage.setSendResult(sendSmsResponse.getMessage());
+            }
+        } catch (Exception e) {
+            basicMessage.setSendStatus("SYSTEM_ERROR");
+            basicMessage.setSendResult(e.getMessage());
+        } finally {
+            // 重试次数+1
+            basicMessage.setResendCount(basicMessage.getResendCount() + 1);
+            this.updateById(basicMessage);
+        }
     }
 
-    @Transactional(rollbackFor = Exception.class)
+
     @Override
     public void noticeOfExamTaskAudit(List<Long> examTaskIdList, MessageEnum messageType, SysUser sysUser) {
+        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
         ExamTaskService examTaskService = SpringContextHolder.getBean(ExamTaskService.class);
         for (Long examTaskId : examTaskIdList) {
             ExamTask examTask = examTaskService.getById(examTaskId);
             if (Objects.nonNull(examTask)) {
+                String courseCode = examTask.getCourseCode();
                 String courseName = examTask.getCourseName();
                 String paperNumber = examTask.getPaperNumber();
                 // 获取短信接收对象的信息
@@ -180,7 +222,11 @@ public class BasicMessageServiceImpl extends ServiceImpl<BasicMessageMapper, Bas
                     jsonMap.put("courseName", courseName);
                     jsonMap.put("paperNumber", paperNumber);
                     String variableParams = JSON.toJSONString(jsonMap);
-                    this.saveMessageSendLog(userId, mobileNumber, examTaskId, variableParams, sysUser.getId(), messageType, null);
+                    String remark = String.format("命题任务ID:%s", examTaskId);
+                    this.saveMessageSendLog(schoolId, userId, userName, mobileNumber, paperNumber, courseCode, variableParams, messageType, sysUser.getId(), remark);
+                } else {
+                    String remark = String.format("命题任务ID:%s,用户不存在", examTaskId);
+                    this.saveMessageSendLog(schoolId, userId, null, null, paperNumber, courseCode, null, messageType, sysUser.getId(), remark);
                 }
             }
         }
@@ -195,6 +241,7 @@ public class BasicMessageServiceImpl extends ServiceImpl<BasicMessageMapper, Bas
     @Override
     public void sendNoticeTaskCreate(ExamTask... examTasks) {
         SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
         // 指派命题老师的命题任务
         Map<Long, List<String>> collects = Arrays.stream(examTasks).filter(m -> m.getUserId() != null).collect(Collectors.groupingBy(ExamTask::getUserId, Collectors.mapping(m -> String.valueOf(m.getId()), Collectors.toList())));
         for (Map.Entry<Long, List<String>> longListEntry : collects.entrySet()) {
@@ -210,13 +257,17 @@ public class BasicMessageServiceImpl extends ServiceImpl<BasicMessageMapper, Bas
                 jsonMap.put("count", ids.size());
                 String variableParams = JSON.toJSONString(jsonMap);
                 String remark = String.format("命题任务ID:%s", String.join(",", ids));
-                this.saveMessageSendLog(userId, mobileNumber, null, variableParams, sysUser.getId(), MessageEnum.NOTICE_OF_EXAM_TASK_CREATED, remark);
+                this.saveMessageSendLog(schoolId, userId, userName, mobileNumber, null, null, variableParams, MessageEnum.NOTICE_OF_EXAM_TASK_CREATED, sysUser.getId(), remark);
+            } else {
+                String remark = String.format("命题任务ID:%s,用户不存在", String.join(",", ids));
+                this.saveMessageSendLog(schoolId, userId, null, null, null, null, null, MessageEnum.NOTICE_OF_EXAM_TASK_CREATED, sysUser.getId(), remark);
             }
         }
     }
 
     @Override
     public void sendNoticeTaskAuditCreateOrReview(ExamTask examTask, MessageEnum messageType) {
+        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
         SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
         // 考务老师(命题任务创建人)
         Long userId = examTask.getCreateId();
@@ -224,19 +275,25 @@ public class BasicMessageServiceImpl extends ServiceImpl<BasicMessageMapper, Bas
         if (Objects.nonNull(user)) {
             String userName = user.getRealName();
             String mobileNumber = user.getMobileNumber();
+            String paperNumber = examTask.getPaperNumber();
+            String courseCode = examTask.getCourseCode();
 
             Map<String, Object> jsonMap = new HashMap<>();
             jsonMap.put("userName", userName);
-            StringJoiner sj = new StringJoiner("、").add(examTask.getCourseName()).add(examTask.getPaperNumber());
+            StringJoiner sj = new StringJoiner("、").add(courseCode).add(paperNumber);
             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);
+            this.saveMessageSendLog(schoolId, userId, userName, mobileNumber, paperNumber, courseCode, variableParams, messageType, sysUser.getId(), remark);
+        } else {
+            String remark = String.format("命题任务ID:%s,用户不存在", examTask.getId().toString());
+            this.saveMessageSendLog(schoolId, userId, null, null, null, null, null, messageType, sysUser.getId(), remark);
         }
     }
 
     @Override
     public void sendNoticeExpireOrOverdue(MessageEnum messageType, Long userId, List<String> ids) {
+        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
         // 考务老师(命题任务创建人)
         SysUser user = commonCacheService.userCache(userId);
         if (Objects.nonNull(user)) {
@@ -247,14 +304,17 @@ public class BasicMessageServiceImpl extends ServiceImpl<BasicMessageMapper, Bas
             jsonMap.put("count", ids.size());
             String variableParams = JSON.toJSONString(jsonMap);
             String remark = String.format("命题任务ID:%s", String.join(",", ids));
-            this.saveMessageSendLog(userId, mobileNumber, null, variableParams, null, messageType, remark);
+            this.saveMessageSendLog(schoolId, userId, userName, mobileNumber, null, null, variableParams, messageType, null, remark);
+        } else {
+            String remark = String.format("命题任务ID:%s,用户不存在", String.join(",", ids));
+            this.saveMessageSendLog(schoolId, userId, null, null, null, null, null, messageType, null, remark);
         }
     }
 
     @Override
     public void resendSmsTask() {
         SysConfig sysConfig = sysConfigService.getByKey("sys.message.resendCount");
-        if(sysConfig != null){
+        if (sysConfig != null) {
             Integer resendCount = StringUtils.isBlank(sysConfig.getConfigValue()) ? 0 : Integer.valueOf(sysConfig.getConfigValue());
             QueryWrapper<BasicMessage> queryWrapper = new QueryWrapper<>();
             queryWrapper.lambda().ne(BasicMessage::getSendStatus, "OK").lt(BasicMessage::getResendCount, resendCount);
@@ -269,125 +329,43 @@ public class BasicMessageServiceImpl extends ServiceImpl<BasicMessageMapper, Bas
 
     @Override
     public void sendNoticeTaskAuditFlow(ExamTask examTask, List<ApproveUserResult> users, MessageEnum messageType) {
+        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
         SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
         // 考务老师(命题任务创建人)
         for (ApproveUserResult user : users) {
             String userName = user.getRealName();
             String mobileNumber = user.getMobileNumber();
-            if(StringUtils.isNotBlank(mobileNumber)) {
-                Map<String, Object> jsonMap = new HashMap<>();
-                jsonMap.put("userName", userName);
-                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(user.getId(), mobileNumber, examTask.getId(), variableParams, sysUser.getId(), messageType, remark);
-            }
-        }
-    }
-
-    /**
-     * 自动重发
-     * @param basicMessage
-     */
-    private void saveMessageResendLog(BasicMessage basicMessage) {
-        String errorMessage = null;
-        try {
-            SendSmsResponse sendSmsResponse = sendSms(basicMessage.getMobileNumber(), basicMessage.getTemplateCode(), basicMessage.getVariableParams());
-            if (sendSmsResponse.getCode() != null) {
-                basicMessage.setSendStatus(sendSmsResponse.getCode());
-                basicMessage.setSendResult(sendSmsResponse.getMessage());
-            } else {
-                throw ExceptionResultEnum.ERROR.exception(sendSmsResponse.getMessage());
-            }
-        } catch (Exception e) {
-            errorMessage = e.getMessage();
-        } finally {
-            // 重试次数+1
-            basicMessage.setResendCount(basicMessage.getResendCount() + 1);
-            // 经过处理的新字段
-            if (errorMessage != null && errorMessage.length() > 0) {
-                basicMessage.setSendStatus("SYSTEM_ERROR");
-                basicMessage.setSendResult(errorMessage);
-            }
-            this.updateById(basicMessage);
+            String paperNumber = examTask.getPaperNumber();
+            String courseCode = examTask.getCourseCode();
+            Map<String, Object> jsonMap = new HashMap<>();
+            jsonMap.put("userName", userName);
+            StringJoiner sj = new StringJoiner("、").add(courseCode).add(paperNumber);
+            jsonMap.put("courseNameAndPaperNumber", sj.toString());
+            String variableParams = JSON.toJSONString(jsonMap);
+            String remark = String.format("命题任务ID:%s", examTask.getId().toString());
+            this.saveMessageSendLog(schoolId, user.getId(), userName, mobileNumber, paperNumber, courseCode, variableParams, messageType, sysUser.getId(), remark);
         }
     }
 
-    private void checkData(Object... objects) {
-        for (Object object : objects) {
-            if (Objects.isNull(object)) {
-                throw ExceptionResultEnum.ERROR.exception("调用发送短信方法时必传参数缺失");
-            } else if (object instanceof String) {
-                String param = String.valueOf(object);
-                if (param.length() == 0 || param.equals("null")) {
-                    throw ExceptionResultEnum.ERROR.exception("调用发送短信方法时必传参数缺失");
-                }
-            } else if (object instanceof Long) {
-                Long param = SystemConstant.convertIdToLong(String.valueOf(object));
-                if (param == null || param == 0) {
-                    throw ExceptionResultEnum.ERROR.exception("调用发送短信方法时必传参数缺失");
-                }
-            }
+    @Override
+    public void sendNoticeUploadStructure(String paperNumber, String courseCode, Long userId, MessageEnum messageType, SysUser sysUser) {
+        QueryWrapper<BasicMessage> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(BasicMessage::getPaperNumber, paperNumber).eq(BasicMessage::getCourseCode, courseCode).eq(BasicMessage::getUserId, userId).eq(BasicMessage::getMessageType, messageType);
+        List<BasicMessage> list = this.list(queryWrapper);
+        if (!CollectionUtils.isEmpty(list)) {
+            return;
         }
-    }
+        SysUser user = commonCacheService.userCache(userId);
+        if (Objects.nonNull(user)) {
+            String userName = user.getRealName();
+            String mobileNumber = user.getMobileNumber();
 
-    private Map<String, String> getCodeAndContentByEnum(MessageEnum messageEnum) {
-        Map<String, String> result = new HashMap<>();
-        String templateContent = null;
-        String templateCode = null;
-        switch (messageEnum) {
-            case NOTICE_OF_AUDIT_PASS:
-                templateCode = dictionaryConfig.smsDomain().getAliyunSMSAuditPassCode();
-                templateContent = messageEnum.getTemplate();
-                break;
-            case NOTICE_OF_AUDIT_NOT_PASS:
-                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;
-            case NOTICE_OF_AUDIT_REJECT:
-                templateCode = dictionaryConfig.smsDomain().getAliyunSMSAuditRejectCode();
-                templateContent = messageEnum.getTemplate();
-                break;
+            Map<String, Object> jsonMap = new HashMap<>();
+            jsonMap.put("userName", userName);
+            StringJoiner sj = new StringJoiner("、").add(courseCode).add(paperNumber);
+            jsonMap.put("courseNameAndPaperNumber", sj.toString());
+            String variableParams = JSON.toJSONString(jsonMap);
+            this.saveMessageSendLog(sysUser.getSchoolId(), userId, userName, mobileNumber, paperNumber, courseCode, variableParams, messageType, sysUser.getId(), null);
         }
-        result.put("templateContent", templateContent);
-        result.put("templateCode", templateCode);
-        return result;
     }
 }

+ 134 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/BasicSemesterServiceImpl.java

@@ -0,0 +1,134 @@
+package com.qmth.distributed.print.business.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.qmth.distributed.print.business.entity.ExamPrintPlan;
+import com.qmth.distributed.print.business.mapper.BasicSemesterMapper;
+import com.qmth.distributed.print.business.service.ExamPrintPlanService;
+import com.qmth.teachcloud.common.bean.params.BasicSemesterParams;
+import com.qmth.teachcloud.common.bean.result.BasicSemesterResult;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.BasicSemester;
+import com.qmth.teachcloud.common.entity.SysUser;
+import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
+import com.qmth.teachcloud.common.service.BasicSemesterService;
+import com.qmth.teachcloud.common.util.ServletUtil;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 学期字典表 服务实现类
+ * </p>
+ *
+ * @author wangliang
+ * @since 2021-10-28
+ */
+@Service
+public class BasicSemesterServiceImpl extends ServiceImpl<BasicSemesterMapper, BasicSemester> implements BasicSemesterService {
+    @Resource
+    ExamPrintPlanService examPrintPlanService;
+
+    @Override
+    public IPage<BasicSemesterResult> basicSemesterPage(Long schoolId, int pageNumber, int pageSize) {
+        return this.baseMapper.findBasicSemesterPage(new Page<>(pageNumber, pageSize), schoolId, null);
+    }
+
+    @Transactional
+    @Override
+    public Long saveBasicSemester(BasicSemesterParams basicSemesterParams) throws IllegalAccessException {
+        SystemConstant.verifyDBFields(basicSemesterParams, basicSemesterParams.getClass());
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        Long id = basicSemesterParams.getId();
+        Long schoolId = sysUser.getSchoolId();
+        String semesterName = basicSemesterParams.getSemesterName();
+        Long startTime = basicSemesterParams.getStartTime();
+        Long endTime = basicSemesterParams.getEndTime();
+
+        // 校验学期唯一性
+        BasicSemester checkName = this.getOne(new QueryWrapper<BasicSemester>().lambda()
+                .eq(BasicSemester::getEnable, true)
+                .eq(BasicSemester::getSchoolId, schoolId)
+                .eq(BasicSemester::getName, semesterName));
+        if (Objects.nonNull(checkName) && !checkName.getId().equals(id)) {
+            throw ExceptionResultEnum.ERROR.exception("学期名称【" + semesterName + "】重复");
+        }
+        if (SystemConstant.longNotNull(id)) {
+            // 编辑
+            BasicSemester old = this.getById(id);
+            if (Objects.isNull(old) || old.getEnable().equals(false)) {
+                throw ExceptionResultEnum.ERROR.exception("所选学期不存在或被禁用");
+            }
+            this.update(new UpdateWrapper<BasicSemester>().lambda()
+                    .eq(BasicSemester::getId, id)
+                    .set(BasicSemester::getName, semesterName)
+                    .set(BasicSemester::getStartTime, startTime)
+                    .set(BasicSemester::getEndTime, endTime));
+        } else {
+            // 新增
+            id = SystemConstant.getDbUuid();
+            BasicSemester basicSemester = new BasicSemester();
+            basicSemester.setId(id);
+            basicSemester.setEnable(true);
+            basicSemester.setName(semesterName);
+            basicSemester.setSchoolId(schoolId);
+            basicSemester.setCode(null);
+            basicSemester.setStartTime(startTime);
+            basicSemester.setEndTime(endTime);
+            basicSemester.setOrgId(sysUser.getOrgId());
+            basicSemester.setInUsed(false);
+            this.save(basicSemester);
+        }
+        return id;
+    }
+
+    @Transactional
+    @Override
+    public boolean deleteBasicSemesterById(Long id) {
+        List<ExamPrintPlan> examPrintPlanList = examPrintPlanService.list(new QueryWrapper<ExamPrintPlan>().lambda().eq(ExamPrintPlan::getSemesterId, id));
+        if (examPrintPlanList.size() > 0) {
+            throw ExceptionResultEnum.ERROR.exception("印刷计划中已使用了该学期,不能删除");
+        }
+        return this.removeById(id);
+    }
+
+    @Override
+    public List<BasicSemester> list(Long schoolId, Boolean inUsed) {
+        QueryWrapper<BasicSemester> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(BasicSemester::getSchoolId, schoolId).eq(BasicSemester::getEnable, true);
+        if (Objects.nonNull(inUsed)) {
+            queryWrapper.lambda().eq(BasicSemester::getInUsed, inUsed);
+        }
+        return this.list(queryWrapper);
+    }
+
+    @Transactional
+    @Override
+    public boolean setInUsed(Long id) {
+        BasicSemester semester = this.getById(id);
+        // 只能设置一个当前使用学期
+        if(!semester.getInUsed()){
+            QueryWrapper<BasicSemester> queryWrapper = new QueryWrapper<>();
+            queryWrapper.lambda().eq(BasicSemester::getSchoolId, semester.getSchoolId());
+            List<BasicSemester> list = this.list(queryWrapper);
+            if(!CollectionUtils.isEmpty(list)) {
+                list = list.stream().map(m -> {
+                    m.setInUsed(false);
+                    return m;
+                }).collect(Collectors.toList());
+                this.updateBatchById(list);
+            }
+        }
+        semester.setInUsed(!semester.getInUsed());
+        return this.updateById(semester);
+    }
+}

+ 325 - 168
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/DataSyncServiceImpl.java

@@ -4,38 +4,45 @@ 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.boot.api.exception.ApiException;
+import com.qmth.distributed.print.business.bean.dto.ExamPaperObjectiveStructureDto;
+import com.qmth.distributed.print.business.bean.dto.ExamPaperSubjectiveStructureDto;
 import com.qmth.distributed.print.business.bean.dto.SyncExamCardDto;
 import com.qmth.distributed.print.business.bean.dto.SyncExamStudentDto;
 import com.qmth.distributed.print.business.bean.params.SyncDataParam;
 import com.qmth.distributed.print.business.entity.*;
+import com.qmth.distributed.print.business.enums.ExamPaperStructureStatusEnum;
+import com.qmth.distributed.print.business.enums.ExamPrintPlanSyncStatusEnum;
 import com.qmth.distributed.print.business.enums.PrintPlanStatusEnum;
 import com.qmth.distributed.print.business.service.*;
-import com.qmth.distributed.print.business.util.HttpKit;
-import com.qmth.teachcloud.common.SignatureEntityTest;
-import com.qmth.teachcloud.common.config.DictionaryConfig;
+import com.qmth.teachcloud.common.bean.dto.QuestionDTO;
 import com.qmth.teachcloud.common.contant.SystemConstant;
-import com.qmth.teachcloud.common.entity.BasicSchool;
+import com.qmth.teachcloud.common.entity.BasicAttachment;
 import com.qmth.teachcloud.common.entity.SysConfig;
+import com.qmth.teachcloud.common.entity.SysOrg;
+import com.qmth.teachcloud.common.entity.SysUser;
 import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
+import com.qmth.teachcloud.common.enums.SyncFileTypeEnum;
 import com.qmth.teachcloud.common.enums.TaskResultEnum;
 import com.qmth.teachcloud.common.enums.TaskStatusEnum;
-import com.qmth.teachcloud.common.service.CommonCacheService;
+import com.qmth.teachcloud.common.service.BasicAttachmentService;
 import com.qmth.teachcloud.common.service.SysConfigService;
+import com.qmth.teachcloud.common.service.TeachcloudCommonService;
+import com.qmth.teachcloud.common.sync.StmmsUtils;
 import com.qmth.teachcloud.common.util.ServletUtil;
-import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 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;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
 
 /**
  * @Date: 2021/5/20.
@@ -51,12 +58,6 @@ public class DataSyncServiceImpl implements DataSyncService {
     @Autowired
     private TBSyncTaskService tbSyncTaskService;
 
-    @Autowired
-    private DictionaryConfig dictionaryConfig;
-
-    @Autowired
-    private CommonCacheService commonCacheService;
-
     @Autowired
     private ExamStudentService examStudentService;
 
@@ -66,14 +67,24 @@ public class DataSyncServiceImpl implements DataSyncService {
     @Autowired
     private ExamCardService examCardService;
 
+    @Autowired
+    private ExamPaperStructureService examPaperStructureService;
+
     @Autowired
     private SysConfigService sysConfigService;
 
-    private ExecutorService executors = Executors.newFixedThreadPool(5);
+    @Autowired
+    private TeachcloudCommonService teachcloudCommonService;
+
+    @Autowired
+    private BasicAttachmentService basicAttachmentService;
+
+    @Autowired
+    StmmsUtils stmmsUtils;
+
+    ExecutorService executorService = Executors.newFixedThreadPool(5);
 
-    private static final String SAVE_EXAM_TYPE = "SCAN_IMAGE";
     private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
-    private static final String POST_METHOD = "POST";
 
     /**
      * 定时任务批量同步
@@ -81,13 +92,14 @@ public class DataSyncServiceImpl implements DataSyncService {
     @Override
     public void syncToCloudReview() {
         // 查询可同步计划(同步状态为空:未同步,false:同步失败)
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
         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, null, examPrintPlan.getName()));
+                executorService.execute(syncBaseData(examPrintPlan, null, examPrintPlan.getName(), sysUser));
             }
         }
     }
@@ -100,6 +112,7 @@ public class DataSyncServiceImpl implements DataSyncService {
      */
     @Override
     public void syncDataCloud(Long printPlanId, Long thirdRelateId) {
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
         ExamPrintPlan examPrintPlan = examPrintPlanService.getById(printPlanId);
         if (examPrintPlan == null) {
             throw ExceptionResultEnum.ERROR.exception("印刷计划数据异常");
@@ -109,189 +122,337 @@ public class DataSyncServiceImpl implements DataSyncService {
         }
         Long relateId = Objects.isNull(thirdRelateId) ? examPrintPlan.getThirdRelateId() : thirdRelateId;
         String thirdRelateName = Objects.isNull(examPrintPlan.getThirdRelateId()) ? examPrintPlan.getName() : examPrintPlan.getThirdRelateName();
-        executors.execute(syncData(examPrintPlan, relateId, thirdRelateName));
+        executorService.execute(syncBaseData(examPrintPlan, relateId, thirdRelateName, sysUser));
 
     }
 
     @Override
     public void syncDataMerge(SyncDataParam syncDataParam) {
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
         List<Long> printPlans = syncDataParam.getList();
         if (CollectionUtils.isEmpty(printPlans)) {
             throw ExceptionResultEnum.ERROR.exception("请选择需要合并的印刷任务");
         }
 
-        if(Objects.isNull(syncDataParam.getThirdRelateId()) && Objects.isNull(syncDataParam.getThirdRelateName())){
+        if (Objects.isNull(syncDataParam.getThirdRelateId()) && Objects.isNull(syncDataParam.getThirdRelateName())) {
             throw ExceptionResultEnum.ERROR.exception("考试ID、考试名称至少填一个");
         }
 
         // todo 校验印刷计划是否完成
         if (syncDataParam.getThirdRelateId() == null) {
-            Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
             String time = String.valueOf(System.currentTimeMillis());
             QueryWrapper<ExamPrintPlan> printPlanQueryWrapper = new QueryWrapper<>();
             printPlanQueryWrapper.lambda().in(ExamPrintPlan::getId, syncDataParam.getList());
             List<ExamPrintPlan> examPrintPlans = examPrintPlanService.list(printPlanQueryWrapper);
             ExamPrintPlan examPrintPlan = examPrintPlans.stream().max(Comparator.comparingLong(ExamPrintPlan::getExamEndTime)).get();
             String examTime = DateUtil.format(new Date(examPrintPlan.getExamEndTime()), DATE_FORMAT);
-            syncDataParam.setThirdRelateId(getExamId(schoolId, time, syncDataParam.getThirdRelateName(), examTime));
+            syncDataParam.setThirdRelateId(stmmsUtils.syncExam(examPrintPlan.getSchoolId(), time, syncDataParam.getThirdRelateName(), examTime));
         }
 
         for (Long printPlanId : printPlans) {
             ExamPrintPlan printPlan = examPrintPlanService.getById(printPlanId);
-            executors.execute(syncData(printPlan, syncDataParam.getThirdRelateId(), syncDataParam.getThirdRelateName()));
+            executorService.execute(syncBaseData(printPlan, syncDataParam.getThirdRelateId(), syncDataParam.getThirdRelateName(), sysUser));
         }
     }
 
-    private TimerTask syncData(ExamPrintPlan examPrintPlan, Long thirdRelateId, String thirdRelateName) {
+    @Override
+    public void syncPaperStructure(ExamPaperStructure examPaperStructure) {
+        executorService.execute(syncStructure(examPaperStructure));
+    }
+
+    /**
+     * 同步基础信息
+     *
+     * @param examPrintPlan
+     * @param thirdRelateId
+     * @param thirdRelateName
+     * @return
+     */
+    private TimerTask syncBaseData(ExamPrintPlan examPrintPlan, Long thirdRelateId, String thirdRelateName, SysUser sysUser) {
         return new TimerTask() {
             @Override
             public void run() {
                 SysConfig sysConfig = sysConfigService.getByKey("sys.sync.enable");
                 if (sysConfig != null && "true".equals(sysConfig.getConfigValue())) {
                     TBSyncTask syncTask = tbSyncTaskService.saveTask(examPrintPlan);
-                    doSyncCore(examPrintPlan, thirdRelateId, thirdRelateName, syncTask);
+                    doSyncBaseData(examPrintPlan, thirdRelateId, thirdRelateName, syncTask, sysUser);
                 }
             }
         };
     }
 
+    /**
+     * 同步试卷结构信息
+     *
+     * @param examPaperStructure
+     * @return
+     */
+    private TimerTask syncStructure(ExamPaperStructure examPaperStructure) {
+        return new TimerTask() {
+            @Override
+            public void run() {
+                SysConfig sysConfig = sysConfigService.getByKey("sys.sync.enable");
+                if (sysConfig != null && "true".equals(sysConfig.getConfigValue())) {
+                    doSyncStructure(examPaperStructure);
+                }
+            }
+        };
+    }
+
+    public void doSyncStructure(ExamPaperStructure examPaperStructure) {
+
+        // 开始同步
+        examPaperStructureService.updateStatusById(examPaperStructure.getId(), ExamPaperStructureStatusEnum.START_SYNC);
+        ExamPaperStructureStatusEnum status = ExamPaperStructureStatusEnum.UPLOAD_FINISH;
+        try {
+            String paperAnswer = examPaperStructure.getPaperAnswer();
+            if (StringUtils.isBlank(paperAnswer)) {
+                throw ExceptionResultEnum.ERROR.exception("没有找到标答文件");
+            }
+
+            String paperTypes = examPaperStructure.getPaperType();
+            if (StringUtils.isBlank(paperTypes)) {
+                throw ExceptionResultEnum.ERROR.exception("没有找到试卷类型");
+            }
+
+            List<String> paperTypeList = Arrays.asList(paperTypes.split(","));
+
+            AtomicInteger atomicInteger = new AtomicInteger(0);
+            // 同步试卷
+            List<JSONObject> paperAnswerJsons = JSONObject.parseArray(paperAnswer, JSONObject.class);
+            for (JSONObject paperAnswerJson : paperAnswerJsons) {
+                if (!paperAnswerJson.containsKey("paperType") || !paperAnswerJson.containsKey("paper")) {
+                    throw ExceptionResultEnum.ERROR.exception("没有找到试卷文件");
+                }
+                String paperType = paperAnswerJson.getString("paperType");
+                String paper = paperAnswerJson.getString("paper");
+                if (StringUtils.isAnyBlank(paperType, paper)) {
+                    throw ExceptionResultEnum.ERROR.exception("没有找到试卷文件");
+                }
+
+                if (!paperTypeList.contains(paperType)) {
+                    throw ExceptionResultEnum.ERROR.exception("试卷对应的类型有误");
+                }
+
+                // 同步试卷文件
+                File paperFile = downFileFromFss(paper, paperType, SyncFileTypeEnum.PAPER);
+                String syncPaperFileUrl = stmmsUtils.syncFile(examPaperStructure.getSchoolId(), String.valueOf(examPaperStructure.getThirdRelateId()), examPaperStructure.getPaperNumber() + paperType, SyncFileTypeEnum.PAPER, paperFile);
+                if (StringUtils.isNotBlank(syncPaperFileUrl)) {
+                    atomicInteger.getAndIncrement();
+                }
+                // 试卷文件保存url
+                paperAnswerJson.put("paperUrl", syncPaperFileUrl);
+            }
+            if (atomicInteger.intValue() - paperAnswerJsons.size() == 0) {
+                status = ExamPaperStructureStatusEnum.PAPER_FINISH;
+                examPaperStructure.setPaperAnswer(JSONObject.toJSONString(paperAnswerJsons));
+            }
+
+            // 同步标答
+            atomicInteger.set(0);
+            for (JSONObject paperAnswerJson : paperAnswerJsons) {
+                if (!paperAnswerJson.containsKey("paperType") || !paperAnswerJson.containsKey("answer")) {
+                    throw ExceptionResultEnum.ERROR.exception("没有找到标答文件");
+                }
+                String paperType = paperAnswerJson.getString("paperType");
+                String answer = paperAnswerJson.getString("answer");
+                if (StringUtils.isAnyBlank(paperType, answer)) {
+                    throw ExceptionResultEnum.ERROR.exception("没有找到标答文件");
+                }
+
+                if (!paperTypeList.contains(paperType)) {
+                    throw ExceptionResultEnum.ERROR.exception("标答对应的试卷类型有误");
+                }
+
+                // 同步标答文件
+                File answerFile = downFileFromFss(answer, paperType, SyncFileTypeEnum.ANSWER);
+                String syncAnswerFileUrl = stmmsUtils.syncFile(examPaperStructure.getSchoolId(), String.valueOf(examPaperStructure.getThirdRelateId()), examPaperStructure.getPaperNumber() + paperType, SyncFileTypeEnum.ANSWER, answerFile);
+                if (StringUtils.isNotBlank(syncAnswerFileUrl)) {
+                    atomicInteger.getAndIncrement();
+                }
+                // 标答文件保存url
+                paperAnswerJson.put("answerUrl", syncAnswerFileUrl);
+            }
+            if (atomicInteger.intValue() - paperAnswerJsons.size() == 0) {
+                status = ExamPaperStructureStatusEnum.ANSWER_FINISH;
+                examPaperStructure.setPaperAnswer(JSONObject.toJSONString(paperAnswerJsons));
+            }
+
+            // 同步客观题
+            atomicInteger.set(0);
+            String objectiveStructure = examPaperStructure.getObjectiveStructure();
+            if (StringUtils.isBlank(objectiveStructure)) {
+                throw ExceptionResultEnum.ERROR.exception("没有找到客观题数据");
+            }
+            List<JSONObject> objectiveJsons = JSONObject.parseArray(objectiveStructure, JSONObject.class);
+            for (JSONObject objectiveJson : objectiveJsons) {
+                if (!objectiveJson.containsKey("paperType") || !objectiveJson.containsKey("content")) {
+                    throw ExceptionResultEnum.ERROR.exception("客观题文件未上传");
+                }
+                String objectivePaperType = objectiveJson.getString("paperType");
+                String objectiveContent = objectiveJson.getString("content");
+                if (StringUtils.isAnyBlank(objectivePaperType, objectiveContent)) {
+                    throw ExceptionResultEnum.ERROR.exception("没有找到客观题数据");
+                }
+                if (!paperTypeList.contains(objectivePaperType)) {
+                    throw ExceptionResultEnum.ERROR.exception("客观题对应的试卷类型有误");
+                }
+
+                List<ExamPaperObjectiveStructureDto> objectiveStructureDtos = JSONObject.parseArray(objectiveContent, ExamPaperObjectiveStructureDto.class);
+                List<QuestionDTO> syncObjectiveStructureDatas = objectiveStructureDtos.stream().map(m -> {
+                    QuestionDTO syncStructureData = new QuestionDTO();
+                    syncStructureData.setMainNumber(Integer.valueOf(m.getMainNumber()));
+                    syncStructureData.setSubNumber(m.getSubNumber());
+                    syncStructureData.setMainTitle(m.getMainName());
+                    syncStructureData.setTotalScore(Double.valueOf(m.getScore()));
+                    syncStructureData.setAnswer(m.getAnswer());
+                    return syncStructureData;
+                }).collect(Collectors.toList());
+                boolean syncObjectiveStructure = stmmsUtils.syncPaperStructure(examPaperStructure.getSchoolId(), String.valueOf(examPaperStructure.getThirdRelateId()), examPaperStructure.getPaperNumber() + objectivePaperType, true, null, syncObjectiveStructureDatas);
+                if (syncObjectiveStructure) {
+                    atomicInteger.getAndIncrement();
+                }
+            }
+            if (atomicInteger.intValue() - paperAnswerJsons.size() == 0) {
+                status = ExamPaperStructureStatusEnum.OBJECTIVE_FINISH;
+            }
+
+            // 同步主观题
+            atomicInteger.set(0);
+            String subjectiveStructure = examPaperStructure.getSubjectiveStructure();
+            if (StringUtils.isBlank(subjectiveStructure)) {
+                throw ExceptionResultEnum.ERROR.exception("没有找到主观题数据");
+            }
+            List<JSONObject> subjectiveJsons = JSONObject.parseArray(subjectiveStructure, JSONObject.class);
+            for (JSONObject subjectiveJson : subjectiveJsons) {
+                if (!subjectiveJson.containsKey("paperType") || !subjectiveJson.containsKey("content")) {
+                    throw ExceptionResultEnum.ERROR.exception("主观题文件未上传");
+                }
+                String subjectivePaperType = subjectiveJson.getString("paperType");
+                String subjectiveContent = subjectiveJson.getString("content");
+                if (StringUtils.isAnyBlank(subjectivePaperType, subjectiveContent)) {
+                    throw ExceptionResultEnum.ERROR.exception("没有找到主观题数据");
+                }
+                List<ExamPaperSubjectiveStructureDto> subjectiveStructureDtos = JSONObject.parseArray(subjectiveContent, ExamPaperSubjectiveStructureDto.class);
+                List<QuestionDTO> syncSubjectiveStructureDatas = subjectiveStructureDtos.stream().map(m -> {
+                    QuestionDTO syncStructureData = new QuestionDTO();
+                    syncStructureData.setMainNumber(Integer.valueOf(m.getMainNumber()));
+                    syncStructureData.setSubNumber(m.getSubNumber());
+                    syncStructureData.setMainTitle(m.getMainName());
+                    syncStructureData.setTotalScore(Double.valueOf(m.getScore()));
+                    return syncStructureData;
+                }).collect(Collectors.toList());
+                boolean syncSubjectiveStructure = stmmsUtils.syncPaperStructure(examPaperStructure.getSchoolId(), String.valueOf(examPaperStructure.getThirdRelateId()), examPaperStructure.getPaperNumber() + subjectivePaperType, false, null, syncSubjectiveStructureDatas);
+                if (syncSubjectiveStructure) {
+                    atomicInteger.getAndIncrement();
+                }
+            }
+            if (atomicInteger.intValue() - paperAnswerJsons.size() == 0) {
+                status = ExamPaperStructureStatusEnum.FINISH;
+            }
+
+        } catch (ApiException e) {
+            throw ExceptionResultEnum.ERROR.exception("试卷结构同步失败:" + e.getMessage());
+        } finally {
+            examPaperStructure.setStatus(status);
+            examPaperStructureService.updateById(examPaperStructure);
+        }
+    }
+
     /**
      * 同步核心方法
      *
      * @param thirdRelateName
      * @param syncTask
      */
-    @Transactional
-    public void doSyncCore(ExamPrintPlan examPrintPlan, Long thirdRelateId, String thirdRelateName, TBSyncTask syncTask) {
+    public void doSyncBaseData(ExamPrintPlan examPrintPlan, Long thirdRelateId, String thirdRelateName, TBSyncTask syncTask, SysUser sysUser) {
         UpdateWrapper<ExamPrintPlan> updateWrapper = new UpdateWrapper<>();
+        ExamPrintPlanSyncStatusEnum syncStatus = ExamPrintPlanSyncStatusEnum.INIT;
         try {
             if (!PrintPlanStatusEnum.END.equals(examPrintPlan.getStatus()) && !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, thirdRelateId, thirdRelateName);
-            syncTask.setThirdRelateId(printPlan.getThirdRelateId());
+            thirdRelateId = saveExam(examPrintPlan, thirdRelateId);
+            syncStatus = ExamPrintPlanSyncStatusEnum.EXAM_FINISH;
+            syncTask.setThirdRelateId(thirdRelateId);
             // 考试同步成功,才能同步考生和题卡
-            if (Objects.nonNull(printPlan.getThirdRelateId())) {
-                studentSave(printPlan);
-                cardUpload(printPlan);
+            if (Objects.nonNull(thirdRelateId)) {
+                updateWrapper.lambda().set(ExamPrintPlan::getThirdRelateId, thirdRelateId).set(ExamPrintPlan::getThirdRelateName, thirdRelateName);
+                saveStudent(examPrintPlan.getSchoolId(), examPrintPlan.getId(), thirdRelateId);
+                syncStatus = ExamPrintPlanSyncStatusEnum.STUDENT_FINISH;
+                cardUpload(examPrintPlan.getSchoolId(), examPrintPlan.getId(), thirdRelateId);
+                syncStatus = ExamPrintPlanSyncStatusEnum.FINISH;
             } else {
                 throw ExceptionResultEnum.ERROR.exception("无法获取云阅卷考试,同步数据失败");
             }
 
-            // 更新计划状态
-            updateWrapper.lambda().set(ExamPrintPlan::getSyncStatus, true).eq(ExamPrintPlan::getId, examPrintPlan.getId());
-
             // 更新日志表
             syncTask.setResult(TaskResultEnum.SUCCESS);
             syncTask.setErrorMessage(null);
         } catch (Exception e) {
             syncTask.setResult(TaskResultEnum.ERROR);
             syncTask.setErrorMessage(e.getMessage());
-            updateWrapper.lambda().set(ExamPrintPlan::getSyncStatus, false).eq(ExamPrintPlan::getId, examPrintPlan.getId());
         } finally {
             syncTask.setStatus(TaskStatusEnum.FINISH);
             tbSyncTaskService.saveOrUpdate(syncTask);
+            updateWrapper.lambda().set(ExamPrintPlan::getSyncStatus, syncStatus).eq(ExamPrintPlan::getId, examPrintPlan.getId());
             examPrintPlanService.update(updateWrapper);
+            // 同步成功,发送短信
+            if(ExamPrintPlanSyncStatusEnum.FINISH.equals(syncStatus)) {
+                examPrintPlanService.sendNoticeUploadStructure(examPrintPlan.getId(), sysUser);
+            }
         }
 
     }
 
-    /**
-     * 校验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
-     * @param thirdRelateName
      * @return
      */
-    public ExamPrintPlan examSave(ExamPrintPlan examPrintPlan, Long thirdRelateId, String thirdRelateName) {
+    public Long saveExam(ExamPrintPlan examPrintPlan, Long thirdRelateId) {
         try {
             if (Objects.isNull(thirdRelateId)) {
                 String code = String.valueOf(examPrintPlan.getId());
                 String name = examPrintPlan.getName();
                 String examTime = DateUtil.format(new Date(examPrintPlan.getExamEndTime()), DATE_FORMAT);
-                thirdRelateId = getExamId(examPrintPlan.getSchoolId(), code, name, examTime);
+                thirdRelateId = stmmsUtils.syncExam(examPrintPlan.getSchoolId(), code, name, examTime);
             }
-            UpdateWrapper<ExamPrintPlan> updateWrapper = new UpdateWrapper<>();
-            updateWrapper.lambda().set(ExamPrintPlan::getThirdRelateId, thirdRelateId)
-                    .set(ExamPrintPlan::getThirdRelateName, thirdRelateName)
-                    .set(ExamPrintPlan::getSyncStatus, null)
-                    .eq(ExamPrintPlan::getId, examPrintPlan.getId());
-            examPrintPlanService.update(updateWrapper);
-            return examPrintPlanService.getById(examPrintPlan.getId());
+            return thirdRelateId;
         } catch (Exception e) {
             throw ExceptionResultEnum.ERROR.exception(e.getMessage());
         }
     }
 
-    public Long getExamId(Long schoolId, String code, String name, String examTime) {
-        String hostUrl = dictionaryConfig.syncDataDomain().getHostUrl();
-        String examSaveUrl = dictionaryConfig.syncDataDomain().getExamSaveUrl();
-        String postUrl = hostUrl.concat(examSaveUrl);
-        //参数
-        Map<String, String> map = new HashMap<>();
-        map.put("code", code);
-        map.put("name", name);
-        map.put("examTime", examTime);
-        map.put("type", SAVE_EXAM_TYPE);
-
-        String result = HttpKit.sendPost(postUrl, getHeaders(schoolId, examSaveUrl), map, null, null, null);
-        JSONObject jsonObject = JSONObject.parseObject(result);
-        if (jsonObject.containsKey("id")) {
-            return Long.valueOf(jsonObject.get("id").toString());
-        } else {
-            throw ExceptionResultEnum.ERROR.exception("考试同步失败");
-        }
-    }
-
     /**
      * 新增考生
      *
      * @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());
+    public void saveStudent(Long schoolId, Long examPrintPlanId, Long thirdRelateId) {
+        List<SyncExamStudentDto> examStudents = examStudentService.listStudentByPrintPlanIdAndSyncStatus(examPrintPlanId);
         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")) {
+                String examId = String.valueOf(thirdRelateId);
+                String examNumber = examStudent.getTicketNumber();
+                String studentCode = examStudent.getStudentCode();
+                String name = examStudent.getStudentName();
+                SysOrg sysOrg = examStudentService.getSysOrgByBelongOrgId(studentCode);
+                String college = Objects.nonNull(sysOrg) && StringUtils.isNotBlank(sysOrg.getName()) ? sysOrg.getName() : "无";
+                String className = StringUtils.isBlank(examStudent.getClazzName()) ? getClassName(examStudent.getExtendFields()) : examStudent.getClazzName();
+                String teacher = "无";
+                String subjectCode = examStudent.getPaperNumber() + examStudent.getPaperType(); // 取试卷编号
+                String subjectName = examStudent.getCourseName();
+                boolean syncStudent = stmmsUtils.syncStudent(schoolId, examId, examNumber, studentCode, name, college, className, teacher, subjectCode, subjectName, null, null, null, null);
+
+                if (syncStudent) {
                     UpdateWrapper<ExamStudent> updateWrapper = new UpdateWrapper<>();
                     updateWrapper.lambda().set(ExamStudent::getSyncStatus, true).eq(ExamStudent::getId, examStudent.getId());
                     examStudentService.update(updateWrapper);
@@ -303,15 +464,12 @@ public class DataSyncServiceImpl implements DataSyncService {
     }
 
     /**
-     * 推送题卡
+     * 同步题卡
      *
      * @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());
+    public void cardUpload(Long schoolId, Long examPrintPlanId, Long thirdRelateId) {
+        List<ExamDetailCourse> examDetailCourses = examDetailService.listSyncPaperNumberByPrintPlanId(examPrintPlanId);
         if (CollectionUtils.isEmpty(examDetailCourses)) {
             return;
         }
@@ -322,92 +480,66 @@ public class DataSyncServiceImpl implements DataSyncService {
             }
 
             if (syncExamCardDtos.size() > 1) {
-//                throw ExceptionResultEnum.ERROR.exception(String.format("数据异常,通过学校:%s,课程代码:%s,试卷编号:%s查出多个题卡数据", examDetailCours.getSchoolId(), examDetailCours.getCourseCode(), examDetailCours.getPaperNumber()));
                 log.info("数据异常,通过学校:{},课程代码:{},试卷编号:{}查出{}个题卡数据", examDetailCours.getSchoolId(), examDetailCours.getCourseCode(), examDetailCours.getPaperNumber(), syncExamCardDtos.size());
                 return;
             }
 
+            String paperType = examDetailCours.getPaperType();
+            if (StringUtils.isBlank(paperType)) {
+                log.info("数据异常,通过学校:{},课程代码:{},试卷编号:{}查出绑定试卷类型为空", examDetailCours.getSchoolId(), examDetailCours.getCourseCode(), examDetailCours.getPaperNumber());
+                return;
+            }
+
             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);
+                for (String s : paperType.split(",")) {
+                    //生成json文件
+                    File file = null;
+                    try {
+                        // 文件临时目录
+                        String filePath = getTempDir(SyncFileTypeEnum.CARD);
+                        file = createJsonFile(filePath, syncExamCardDto.getContent());
+                        if (file.exists()) {
+                            String uploadCardUrl = stmmsUtils.syncFile(schoolId, String.valueOf(thirdRelateId), syncExamCardDto.getPaperNumber() + s, SyncFileTypeEnum.CARD, file);
+                            if (StringUtils.isNotBlank(uploadCardUrl)) {
+                                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();
                         }
-                    }
-                } catch (Exception e) {
-                    throw ExceptionResultEnum.ERROR.exception(e.getMessage());
-                } finally {
-                    if (file != null && file.exists()) {
-                        file.delete();
                     }
                 }
             }
-
         }
     }
 
     /**
-     * http请求头
+     * 上传文件临时目录
      *
-     * @param url
+     * @param type
      * @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;
+    private String getTempDir(SyncFileTypeEnum type) {
+        return SystemConstant.TEMP_FILES_DIR + File.separator + "upload-temp" + File.separator + type.name().toLowerCase() + File.separator + System.currentTimeMillis();
     }
 
     /**
-     * 签名
+     * 通过扩展字段,获取班级名称
      *
-     * @param schoolId
-     * @param time
-     * @param url
+     * @param extendCloumn
      * @return
      */
-    private String createSign(Long schoolId, long time, String url) {
-        BasicSchool basicSchool = commonCacheService.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())) {
+            if (Objects.equals("className", map.get("code").toString())
+                    || Objects.equals("clazzName", map.get("code").toString())) {
                 return map.get("value").toString();
             }
         }
@@ -440,4 +572,29 @@ public class DataSyncServiceImpl implements DataSyncService {
         }
         return file;
     }
+
+    /**
+     * 下载附件临时文件
+     *
+     * @param attachmentId
+     * @param name
+     * @param type
+     * @return
+     */
+    private File downFileFromFss(String attachmentId, String name, SyncFileTypeEnum type) {
+        try {
+            if (Objects.nonNull(attachmentId)) {
+                BasicAttachment attachment = basicAttachmentService.getById(attachmentId);
+                if (attachment == null) {
+                    throw ExceptionResultEnum.ERROR.exception("附件数据异常");
+                }
+                String fileName = attachment.getName() + "-" + name + attachment.getType();
+                File file = teachcloudCommonService.copyFile(getTempDir(type), fileName, attachment);
+                return file;
+            }
+        } catch (Exception e) {
+            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
+        }
+        return null;
+    }
 }

+ 3 - 6
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamDetailCourseServiceImpl.java

@@ -10,15 +10,12 @@ import com.qmth.distributed.print.business.mapper.ExamDetailCourseMapper;
 import com.qmth.distributed.print.business.service.ExamDetailCourseService;
 import com.qmth.teachcloud.common.contant.SystemConstant;
 import com.qmth.teachcloud.common.entity.BasicCourse;
-import com.qmth.teachcloud.common.enums.TaskStatusEnum;
-import com.qmth.teachcloud.common.util.ConvertUtil;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.stream.Collectors;
 
 /**
  * <p>
@@ -34,8 +31,8 @@ public class ExamDetailCourseServiceImpl extends ServiceImpl<ExamDetailCourseMap
     @Transactional(rollbackFor = Exception.class)
     @Override
     public double calculatePackagesByDetailId(Long examDetailId) {
-        System.out.println(this.count(new QueryWrapper<ExamDetailCourse>().lambda().eq(ExamDetailCourse::getExamDetailId,examDetailId)));
-        return this.count(new QueryWrapper<ExamDetailCourse>().lambda().eq(ExamDetailCourse::getExamDetailId,examDetailId));
+        System.out.println(this.count(new QueryWrapper<ExamDetailCourse>().lambda().eq(ExamDetailCourse::getExamDetailId, examDetailId)));
+        return this.count(new QueryWrapper<ExamDetailCourse>().lambda().eq(ExamDetailCourse::getExamDetailId, examDetailId));
     }
 
     @Override
@@ -64,7 +61,7 @@ public class ExamDetailCourseServiceImpl extends ServiceImpl<ExamDetailCourseMap
 
     @Override
     public List<String> listPaperNumberByPrintPlanId(String param, List<Long> printPlanIdList, Set<Long> orgIds) {
-        return this.baseMapper.listPaperNumberByPrintPlanId(SystemConstant.translateSpecificSign(param), printPlanIdList,orgIds);
+        return this.baseMapper.listPaperNumberByPrintPlanId(SystemConstant.translateSpecificSign(param), printPlanIdList, orgIds);
     }
 
     @Override

+ 380 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamPaperStructureServiceImpl.java

@@ -0,0 +1,380 @@
+package com.qmth.distributed.print.business.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.google.common.collect.Lists;
+import com.qmth.boot.api.exception.ApiException;
+import com.qmth.distributed.print.business.bean.dto.ExamPaperObjectiveStructureDto;
+import com.qmth.distributed.print.business.bean.dto.ExamPaperStructureDto;
+import com.qmth.distributed.print.business.bean.dto.ExamPaperSubjectiveStructureDto;
+import com.qmth.distributed.print.business.entity.ExamPaperStructure;
+import com.qmth.distributed.print.business.entity.ExamTask;
+import com.qmth.distributed.print.business.entity.ExamTaskDetail;
+import com.qmth.distributed.print.business.enums.ExamPaperStructureStatusEnum;
+import com.qmth.distributed.print.business.enums.ExamPrintPlanSyncStatusEnum;
+import com.qmth.distributed.print.business.mapper.ExamPaperStructureMapper;
+import com.qmth.distributed.print.business.service.ExamPaperStructureService;
+import com.qmth.distributed.print.business.service.ExamTaskDetailService;
+import com.qmth.distributed.print.business.service.ExamTaskService;
+import com.qmth.distributed.print.business.service.PrintCommonService;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.BasicAttachment;
+import com.qmth.teachcloud.common.entity.SysUser;
+import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
+import com.qmth.teachcloud.common.enums.UploadFileEnum;
+import com.qmth.teachcloud.common.service.BasicAttachmentService;
+import com.qmth.teachcloud.common.sync.StmmsUtils;
+import com.qmth.teachcloud.common.util.ExcelUtil;
+import com.qmth.teachcloud.common.util.ResultUtil;
+import com.qmth.teachcloud.common.util.ServletUtil;
+import com.qmth.teachcloud.common.util.excel.ExcelError;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+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;
+
+import javax.annotation.Resource;
+import java.io.IOException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 试卷结构 服务实现类
+ * </p>
+ */
+@Service
+public class ExamPaperStructureServiceImpl extends ServiceImpl<ExamPaperStructureMapper, ExamPaperStructure> implements ExamPaperStructureService {
+
+    @Autowired
+    ExamTaskService examTaskService;
+
+    @Autowired
+    ExamTaskDetailService examTaskDetailService;
+
+    @Resource
+    @Lazy
+    PrintCommonService printCommonService;
+
+    @Resource
+    BasicAttachmentService basicAttachmentService;
+
+    @Autowired
+    StmmsUtils stmmsUtils;
+
+    @Override
+    public IPage<ExamPaperStructure> listByPropositionTeacherId(Integer pageNumber, Integer pageSize, String[] structureStatusEnums) {
+        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        Page<ExamPaperStructure> page = new Page<>(pageNumber, pageSize);
+        IPage<ExamPaperStructure> examPaperStructureIPage = this.baseMapper.listByPropositionTeacherId(page, schoolId, sysUser.getId(), ExamPrintPlanSyncStatusEnum.FINISH.name(), structureStatusEnums);
+        return examPaperStructureIPage;
+    }
+
+    @Transactional
+    @Override
+    public ExamPaperStructure upload(String examPaperStructure, String md5, MultipartFile[] files) {
+
+        ExamPaperStructure examPaperStructureTemp = JSONObject.parseObject(examPaperStructure, ExamPaperStructure.class);
+        if (Objects.isNull(examPaperStructureTemp.getId())) {
+            // 保存
+            examPaperStructureTemp.setId(SystemConstant.getDbUuid());
+            this.save(examPaperStructureTemp);
+        } else {
+            examPaperStructureTemp = this.getById(examPaperStructureTemp.getId());
+        }
+
+        // 组装ExamPaperStructureDto
+        List<ExamPaperStructureDto> examPaperStructureDtos = createExamPaperStructure(md5, examPaperStructureTemp.getPaperType(), files);
+        List<BasicAttachment> basicAttachmentList = new ArrayList<>();
+
+        List<Map<String, Object>> paperAnswerList = new ArrayList<>();
+        List<Map<String, Object>> subjectiveStructureList = new ArrayList<>();
+        List<Map<String, Object>> objectiveStructureList = new ArrayList<>();
+
+        // 试卷卷型及原卷附件ID
+        Map<String, String> paperMap = createExamTaskAttachmentIds(examPaperStructureTemp);
+
+        // 上传试卷结构、标答文件
+        for (ExamPaperStructureDto examPaperStructureDto : examPaperStructureDtos) {
+            Map<String, Object> paperAnswerMap = new HashMap<>();
+            paperAnswerMap.put("paperType", examPaperStructureDto.getPaperType());
+            Map<String, Object> subjectiveStructureMap = new HashMap<>();
+            subjectiveStructureMap.put("paperType", examPaperStructureDto.getPaperType());
+            Map<String, Object> objectiveStructureMap = new HashMap<>();
+            objectiveStructureMap.put("paperType", examPaperStructureDto.getPaperType());
+            try {
+                // 主观题附件
+                BasicAttachment subjectiveBasicAttachment = printCommonService.saveAttachment(examPaperStructureDto.getSubjectiveQuestionFile(), examPaperStructureDto.getSubjectiveQuestionMd5(), UploadFileEnum.UPLOAD);
+                if (Objects.isNull(subjectiveBasicAttachment)) {
+                    throw ExceptionResultEnum.ATTACHMENT_ERROR.exception();
+                }
+                // 解析试卷结构
+                List<Object> subjectiveStructrue = analyzPaperSubjectiveStructure(examPaperStructureDto.getSubjectiveQuestionFile());
+                subjectiveStructureMap.put("content", CollectionUtils.isEmpty(subjectiveStructrue) ? null : subjectiveStructrue);
+                // 客观题附件
+                basicAttachmentList.add(subjectiveBasicAttachment);
+                BasicAttachment objectiveBasicAttachment = printCommonService.saveAttachment(examPaperStructureDto.getObjectiveQuestionFile(), examPaperStructureDto.getObjectiveQuestionMd5(), UploadFileEnum.UPLOAD);
+                if (Objects.isNull(objectiveBasicAttachment)) {
+                    throw ExceptionResultEnum.ATTACHMENT_ERROR.exception();
+                }
+                // 解析试卷结构
+                List<Object> objectiveStructure = analyzPaperObjectiveStructure(examPaperStructureDto.getObjectiveQuestionFile());
+                objectiveStructureMap.put("content", CollectionUtils.isEmpty(objectiveStructure) ? null : objectiveStructure);
+                // 标答附件
+                basicAttachmentList.add(objectiveBasicAttachment);
+                BasicAttachment answerBasicAttachment = printCommonService.saveAttachment(examPaperStructureDto.getStandardAnswerFile(), examPaperStructureDto.getStandardAnswerMd5(), UploadFileEnum.UPLOAD);
+                if (Objects.isNull(answerBasicAttachment)) {
+                    throw ExceptionResultEnum.ATTACHMENT_ERROR.exception();
+                }
+                paperAnswerMap.put("answer", answerBasicAttachment.getId());
+                basicAttachmentList.add(answerBasicAttachment);
+
+                // 试卷原卷
+                paperAnswerMap.put("paper", paperMap.get(examPaperStructureDto.getPaperType()));
+                paperAnswerList.add(paperAnswerMap);
+                subjectiveStructureList.add(subjectiveStructureMap);
+                objectiveStructureList.add(objectiveStructureMap);
+            } catch (Exception e) {
+                log.error("请求出错", e);
+                for (BasicAttachment basicAttachment : basicAttachmentList) {
+                    basicAttachmentService.deleteAttachment(basicAttachment);
+                }
+                if (e instanceof ApiException) {
+                    ResultUtil.error((ApiException) e, e.getMessage());
+                } else {
+                    ResultUtil.error(e.getMessage());
+                }
+            }
+        }
+
+        // 保存
+        examPaperStructureTemp.setPaperAnswer(JSONObject.toJSONString(paperAnswerList));
+        examPaperStructureTemp.setSubjectiveStructure(JSONObject.toJSONString(subjectiveStructureList));
+        examPaperStructureTemp.setObjectiveStructure(JSONObject.toJSONString(objectiveStructureList));
+        // 上传成功
+        examPaperStructureTemp.setStatus(ExamPaperStructureStatusEnum.UPLOAD_FINISH);
+
+        this.updateById(examPaperStructureTemp);
+        return examPaperStructureTemp;
+    }
+
+    @Override
+    public void updateStatusById(Long id, ExamPaperStructureStatusEnum status) {
+        UpdateWrapper<ExamPaperStructure> updateWrapper = new UpdateWrapper<>();
+        updateWrapper.lambda().set(ExamPaperStructure::getStatus, status).eq(ExamPaperStructure::getId, id);
+        this.update(updateWrapper);
+    }
+
+    @Override
+    public List<Map> preStructure(Long id) {
+        if (Objects.isNull(id)) {
+            throw ExceptionResultEnum.ERROR.exception("参数有误");
+        }
+        ExamPaperStructure examPaperStructure = this.getById(id);
+        if (!ExamPaperStructureStatusEnum.FINISH.equals(examPaperStructure.getStatus())) {
+            throw ExceptionResultEnum.ERROR.exception("试卷结构没有同步成功");
+        }
+        String paperType = examPaperStructure.getPaperType();
+        List<Map> list = new ArrayList<>();
+        for (String str : paperType.split(",")) {
+            Map<String, Object> map = new HashMap<>();
+            map.put("paperType", str);
+            List<Map> paperStructure = stmmsUtils.queryPaperStructure(examPaperStructure.getSchoolId(), String.valueOf(examPaperStructure.getThirdRelateId()), examPaperStructure.getPaperNumber() + str, null);
+            map.put("content", paperStructure);
+            list.add(map);
+        }
+        return list;
+    }
+
+    @Override
+    public long countByPropositionTeacherId() {
+        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        String[] structureStatusEnums = new String[]{ExamPaperStructureStatusEnum.FINISH.name()};
+        List<ExamPaperStructure> examPaperStructureList= this.baseMapper.listByPropositionTeacherId(schoolId, sysUser.getId(), ExamPrintPlanSyncStatusEnum.FINISH.name(), structureStatusEnums);
+        return CollectionUtils.isEmpty(examPaperStructureList) ? 0 : examPaperStructureList.size();
+    }
+
+
+    private Map<String, String> createExamTaskAttachmentIds(ExamPaperStructure examPaperStructure) {
+        ExamTask examTask = examTaskService.getByCourseCodeAndPaperNumber(examPaperStructure.getSchoolId(), examPaperStructure.getCourseCode(), examPaperStructure.getPaperNumber());
+
+        QueryWrapper<ExamTaskDetail> examTaskDetailQueryWrapper = new QueryWrapper<>();
+        examTaskDetailQueryWrapper.lambda().eq(ExamTaskDetail::getExamTaskId, examTask.getId());
+        ExamTaskDetail examTaskDetail = examTaskDetailService.getOne(examTaskDetailQueryWrapper);
+
+        String paperAttachmentIds = examTaskDetail.getPaperAttachmentIds();
+        List<Map> list = JSONObject.parseArray(paperAttachmentIds, Map.class);
+        if (CollectionUtils.isEmpty(list)) {
+            throw ExceptionResultEnum.ERROR.exception("未找到关联的试卷文件");
+        }
+
+        Map<String, String> paperMap = list.stream().collect(Collectors.toMap(m -> m.get("name").toString(), m -> m.get("attachmentId").toString()));
+
+        return paperMap;
+    }
+
+    /**
+     * 解析excel文件内容
+     *
+     * @param file
+     * @return
+     */
+    private List<Object> analyzPaperSubjectiveStructure(MultipartFile file) throws
+            IOException, NoSuchFieldException {
+        List<LinkedMultiValueMap<Integer, Object>> finalList = ExcelUtil.excelReader(file.getInputStream(), Lists.newArrayList(ExamPaperSubjectiveStructureDto.class), (finalExcelList, finalColumnNameList, finalExcelErrorList) -> {
+            List<ExcelError> excelErrorTemp = new ArrayList<>();
+            // 只允许导入一个sheet
+            if (finalExcelList.size() > 1) {
+                throw ExceptionResultEnum.ERROR.exception("excel中只允许有一个sheet");
+            }
+            for (int i = 0; i < finalExcelList.size(); i++) {
+                LinkedMultiValueMap<Integer, Object> excelMap = finalExcelList.get(i);
+                List<Object> examTaskTempList = excelMap.get(i);
+                for (int y = 0; y < examTaskTempList.size(); y++) {
+                    ExamPaperSubjectiveStructureDto subjectiveStructureDto = (ExamPaperSubjectiveStructureDto) examTaskTempList.get(y);
+                    if (StringUtils.isBlank(subjectiveStructureDto.getCourseCode())) {
+                        excelErrorTemp.add(new ExcelError(y + 1, "excel第" + (i + 1) + "个sheet第" + (y + 1) + "行[课程代码]必填"));
+                    }
+                    if (StringUtils.isBlank(subjectiveStructureDto.getCourseName())) {
+                        excelErrorTemp.add(new ExcelError(y + 1, "excel第" + (i + 1) + "个sheet第" + (y + 1) + "行[课程名称]必填"));
+                    }
+                    if (StringUtils.isBlank(subjectiveStructureDto.getMainName())) {
+                        excelErrorTemp.add(new ExcelError(y + 1, "excel第" + (i + 1) + "个sheet第" + (y + 1) + "行[大题名称]必填"));
+                    }
+                    if (subjectiveStructureDto.getMainNumber() == null) {
+                        excelErrorTemp.add(new ExcelError(y + 1, "excel第" + (i + 1) + "个sheet第" + (y + 1) + "行[大题号]必填"));
+                    }
+                    if (StringUtils.isBlank(subjectiveStructureDto.getSubNumber())) {
+                        excelErrorTemp.add(new ExcelError(y + 1, "excel第" + (i + 1) + "个sheet第" + (y + 1) + "行[小题号]必填"));
+                    }
+                    if (StringUtils.isBlank(subjectiveStructureDto.getScore())) {
+                        excelErrorTemp.add(new ExcelError(y + 1, "excel第" + (i + 1) + "个sheet第" + (y + 1) + "行[小题满分]必填"));
+                    }
+                }
+            }
+            if (excelErrorTemp.size() > 0) {
+                List<String> errors = excelErrorTemp.stream().map(m -> m.getExcelErrorType()).collect(Collectors.toList());
+                throw ExceptionResultEnum.ERROR.exception(JSONObject.toJSONString(errors));
+            }
+            return finalExcelList;
+        });
+        List<Object> list = new ArrayList<>();
+        for (LinkedMultiValueMap<Integer, Object> map : finalList) {
+            for (Map.Entry<Integer, List<Object>> entry : map.entrySet()) {
+                list.addAll(entry.getValue());
+            }
+        }
+        return list;
+    }
+
+    /**
+     * 解析excel文件内容
+     *
+     * @param file
+     * @return
+     */
+    private List<Object> analyzPaperObjectiveStructure(MultipartFile file) throws IOException, NoSuchFieldException {
+        List<LinkedMultiValueMap<Integer, Object>> finalList = ExcelUtil.excelReader(file.getInputStream(), Lists.newArrayList(ExamPaperObjectiveStructureDto.class), (finalExcelList, finalColumnNameList, finalExcelErrorList) -> {
+            List<ExcelError> excelErrorTemp = new ArrayList<>();
+            // 只允许导入一个sheet
+            if (finalExcelList.size() > 1) {
+                throw ExceptionResultEnum.ERROR.exception("excel中只允许有一个sheet");
+            }
+            for (int i = 0; i < finalExcelList.size(); i++) {
+                LinkedMultiValueMap<Integer, Object> excelMap = finalExcelList.get(i);
+                List<Object> examTaskTempList = excelMap.get(i);
+                for (int y = 0; y < examTaskTempList.size(); y++) {
+                    ExamPaperObjectiveStructureDto objectiveStructureDto = (ExamPaperObjectiveStructureDto) examTaskTempList.get(y);
+                    if (StringUtils.isBlank(objectiveStructureDto.getCourseCode())) {
+                        excelErrorTemp.add(new ExcelError(y + 1, "excel第" + (i + 1) + "个sheet第" + (y + 1) + "行[课程代码]必填"));
+                    }
+                    if (StringUtils.isBlank(objectiveStructureDto.getCourseName())) {
+                        excelErrorTemp.add(new ExcelError(y + 1, "excel第" + (i + 1) + "个sheet第" + (y + 1) + "行[课程名称]必填"));
+                    }
+                    if (StringUtils.isBlank(objectiveStructureDto.getPaperType())) {
+                        excelErrorTemp.add(new ExcelError(y + 1, "excel第" + (i + 1) + "个sheet第" + (y + 1) + "行[试卷类型]必填"));
+                    }
+                    if (StringUtils.isBlank(objectiveStructureDto.getMainName())) {
+                        excelErrorTemp.add(new ExcelError(y + 1, "excel第" + (i + 1) + "个sheet第" + (y + 1) + "行[大题名称]必填"));
+                    }
+                    if (objectiveStructureDto.getMainNumber() == null) {
+                        excelErrorTemp.add(new ExcelError(y + 1, "excel第" + (i + 1) + "个sheet第" + (y + 1) + "行[大题号]必填"));
+                    }
+                    if (StringUtils.isBlank(objectiveStructureDto.getSubNumber())) {
+                        excelErrorTemp.add(new ExcelError(y + 1, "excel第" + (i + 1) + "个sheet第" + (y + 1) + "行[小题号]必填"));
+                    }
+                    if (StringUtils.isBlank(objectiveStructureDto.getAnswer())) {
+                        excelErrorTemp.add(new ExcelError(y + 1, "excel第" + (i + 1) + "个sheet第" + (y + 1) + "行[标准答案]必填"));
+                    }
+                    if (StringUtils.isBlank(objectiveStructureDto.getScore())) {
+                        excelErrorTemp.add(new ExcelError(y + 1, "excel第" + (i + 1) + "个sheet第" + (y + 1) + "行[小题满分]必填"));
+                    }
+                }
+            }
+            if (excelErrorTemp.size() > 0) {
+                List<String> errors = excelErrorTemp.stream().map(m -> m.getExcelErrorType()).collect(Collectors.toList());
+                throw ExceptionResultEnum.ERROR.exception(JSONObject.toJSONString(errors));
+            }
+            return finalExcelList;
+        });
+        List<Object> list = new ArrayList<>();
+        for (LinkedMultiValueMap<Integer, Object> map : finalList) {
+            for (Map.Entry<Integer, List<Object>> entry : map.entrySet()) {
+                list.addAll(entry.getValue());
+            }
+        }
+        return list;
+    }
+
+    /**
+     * 组装ExamPaperStructureDto
+     *
+     * @param md5
+     * @param paperType
+     * @param files
+     * @return
+     */
+    private List<ExamPaperStructureDto> createExamPaperStructure(String md5, String paperType, MultipartFile[] files) {
+        int COUNT = 3;
+        if (files.length == 0) {
+            throw ExceptionResultEnum.ERROR.exception("请上传文件");
+        }
+        if (StringUtils.isBlank(paperType)) {
+            throw ExceptionResultEnum.ERROR.exception("试卷卷型有误");
+        }
+        String[] paperTypes = paperType.split(",");
+        if (paperTypes.length * COUNT - files.length != 0) {
+            throw ExceptionResultEnum.ERROR.exception("上传文件有误");
+        }
+        if (StringUtils.isBlank(md5)) {
+            throw ExceptionResultEnum.ERROR.exception("上传文件有误");
+        }
+        String[] md5s = md5.split(",");
+        if (md5s.length - files.length != 0) {
+            throw ExceptionResultEnum.ERROR.exception("上传文件有误");
+        }
+        List<ExamPaperStructureDto> list = new ArrayList<>();
+        for (int i = 0; i < paperTypes.length; i++) {
+            ExamPaperStructureDto examPaperStructureDto = new ExamPaperStructureDto();
+            examPaperStructureDto.setPaperType(paperTypes[i]);
+            examPaperStructureDto.setObjectiveQuestionFile(files[COUNT * i]);
+            examPaperStructureDto.setObjectiveQuestionMd5(md5s[COUNT * i]);
+            examPaperStructureDto.setSubjectiveQuestionFile(files[COUNT * i + 1]);
+            examPaperStructureDto.setSubjectiveQuestionMd5(md5s[COUNT * i + 1]);
+            examPaperStructureDto.setStandardAnswerFile(files[COUNT * i + 2]);
+            examPaperStructureDto.setStandardAnswerMd5(md5s[COUNT * i + 2]);
+            list.add(examPaperStructureDto);
+        }
+        return list;
+    }
+}

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

@@ -12,14 +12,8 @@ import com.qmth.distributed.print.business.bean.params.SyncDataParam;
 import com.qmth.distributed.print.business.bean.result.PrintPlanBrief;
 import com.qmth.distributed.print.business.bean.result.PrintPlanResult;
 import com.qmth.distributed.print.business.bean.result.TemplatePrintInfoResult;
-import com.qmth.distributed.print.business.entity.BasicExamRule;
-import com.qmth.distributed.print.business.entity.ClientPrintData;
-import com.qmth.distributed.print.business.entity.ExamDetail;
-import com.qmth.distributed.print.business.entity.ExamPrintPlan;
-import com.qmth.distributed.print.business.enums.ExamDataSourceEnum;
-import com.qmth.distributed.print.business.enums.ExamDetailStatusEnum;
-import com.qmth.distributed.print.business.enums.PrintPlanStatusEnum;
-import com.qmth.distributed.print.business.enums.TemplateTypeEnum;
+import com.qmth.distributed.print.business.entity.*;
+import com.qmth.distributed.print.business.enums.*;
 import com.qmth.distributed.print.business.mapper.ExamPrintPlanMapper;
 import com.qmth.distributed.print.business.service.*;
 import com.qmth.teachcloud.common.contant.SystemConstant;
@@ -62,12 +56,18 @@ public class ExamPrintPlanServiceImpl extends ServiceImpl<ExamPrintPlanMapper, E
     @Resource
     private BasicSchoolService basicSchoolService;
 
+    @Autowired
+    private ExamTaskService examTaskService;
+
     @Autowired
     private BasicAttachmentService basicAttachmentService;
 
     @Resource
     private BasicExamRuleService basicExamRuleService;
 
+    @Autowired
+    private BasicMessageService basicMessageService;
+
     @Resource
     private TBTaskService tbTaskService;
 
@@ -85,9 +85,9 @@ public class ExamPrintPlanServiceImpl extends ServiceImpl<ExamPrintPlanMapper, E
 
     @Transactional(rollbackFor = Exception.class)
     @Override
-    public IPage<PrintPlanResult> printPlanPage(Long schoolId, List<Long> printPlanIdList, PrintPlanStatusEnum status, Long startTime, Long endTime, int pageNumber, int pageSize) {
+    public IPage<PrintPlanResult> printPlanPage(Long schoolId, Long semesterId, List<Long> printPlanIdList, PrintPlanStatusEnum status, Long startTime, Long endTime, int pageNumber, int pageSize) {
         Set<Long> orgIds = teachcloudCommonService.listSubOrgIds(null);
-        IPage<PrintPlanResult> page = examPrintPlanMapper.findPrintPlanPage(new Page<>(pageNumber, pageSize), schoolId, printPlanIdList, status, startTime, endTime, orgIds);
+        IPage<PrintPlanResult> page = examPrintPlanMapper.findPrintPlanPage(new Page<>(pageNumber, pageSize), schoolId, semesterId, printPlanIdList, status, startTime, endTime, orgIds);
         List<PrintPlanResult> list = page.getRecords();
         for (PrintPlanResult printPlanResult : list) {
             List<Map> variableContent = JSONObject.parseArray(printPlanResult.getVariableContentTemp(), Map.class);
@@ -105,10 +105,10 @@ public class ExamPrintPlanServiceImpl extends ServiceImpl<ExamPrintPlanMapper, E
 
     @Transactional(rollbackFor = Exception.class)
     @Override
-    public IPage<PrintPlanResult> printPlanSyncPage(Long schoolId, Long printPlanId, Long startTime, Long endTime, int pageNumber, int pageSize) {
+    public IPage<PrintPlanResult> printPlanSyncPage(Long schoolId,Long semesterId, Long printPlanId, Long startTime, Long endTime, int pageNumber, int pageSize) {
         Set<Long> orgIds = teachcloudCommonService.listSubOrgIds(null);
         String[] status = {PrintPlanStatusEnum.PRINT_FINISH.name(), PrintPlanStatusEnum.END.name()};
-        IPage<PrintPlanResult> page = examPrintPlanMapper.findPrintPlanSyncPage(new Page<>(pageNumber, pageSize), schoolId, status, printPlanId, startTime, endTime, orgIds);
+        IPage<PrintPlanResult> page = examPrintPlanMapper.findPrintPlanSyncPage(new Page<>(pageNumber, pageSize), schoolId,semesterId, status, printPlanId, startTime, endTime, orgIds);
         List<PrintPlanResult> list = page.getRecords();
         for (PrintPlanResult printPlanResult : list) {
             List<Map> variableContent = JSONObject.parseArray(printPlanResult.getVariableContentTemp(), Map.class);
@@ -233,7 +233,6 @@ public class ExamPrintPlanServiceImpl extends ServiceImpl<ExamPrintPlanMapper, E
     @Override
     public Boolean savePrintPlan(PrintPlanParams printPlanParams) {
         boolean result;
-        System.out.println("JSON = " + printPlanParams.getOrdinaryContent());
         SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
         Long id = printPlanParams.getId();
         Long schoolId = printPlanParams.getSchoolId();
@@ -273,6 +272,7 @@ public class ExamPrintPlanServiceImpl extends ServiceImpl<ExamPrintPlanMapper, E
             }
             examPrintPlan.setId(SystemConstant.getDbUuid());
             examPrintPlan.setStatus(PrintPlanStatusEnum.NEW);
+            examPrintPlan.setSyncStatus(ExamPrintPlanSyncStatusEnum.INIT);
             result = this.save(examPrintPlan);
         } else {
             // 包含印刷计划id -> 编辑印刷计划
@@ -467,6 +467,15 @@ public class ExamPrintPlanServiceImpl extends ServiceImpl<ExamPrintPlanMapper, E
         return examPrintPlan;
     }
 
+    @Override
+    public void sendNoticeUploadStructure(Long id, SysUser sysUser) {
+        List<ExamDetailCourse> examDetailCourses = examDetailService.listSyncPaperNumberByPrintPlanId(id);
+        for (ExamDetailCourse examDetailCours : examDetailCourses) {
+            ExamTask examTask = examTaskService.getByCourseCodeAndPaperNumber(examDetailCours.getSchoolId(), examDetailCours.getCourseCode(), examDetailCours.getPaperNumber());
+            basicMessageService.sendNoticeUploadStructure(examTask.getPaperNumber(), examTask.getCourseCode(), examTask.getUserId(), MessageEnum.NOTICE_OF_UPLOAD_STRUCTURE, sysUser);
+        }
+    }
+
 
     /**
      * 查找子机构

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

@@ -10,6 +10,7 @@ import com.qmth.distributed.print.business.entity.ExamDetailCourse;
 import com.qmth.distributed.print.business.entity.ExamStudent;
 import com.qmth.distributed.print.business.mapper.ExamStudentMapper;
 import com.qmth.distributed.print.business.service.ExamStudentService;
+import com.qmth.teachcloud.common.entity.SysOrg;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
 
@@ -89,4 +90,9 @@ public class ExamStudentServiceImpl extends ServiceImpl<ExamStudentMapper, ExamS
     public List<ExamStudent> listExamStudentBySchoolIdAndClazzId(Long schoolId, String classId) {
         return this.baseMapper.listExamStudentBySchoolIdAndClazzId(schoolId, classId);
     }
+
+    @Override
+    public SysOrg getSysOrgByBelongOrgId(String studentCode) {
+        return this.baseMapper.getSysOrgByBelongOrgId(studentCode);
+    }
 }

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

@@ -753,7 +753,8 @@ public class ExamTaskServiceImpl extends ServiceImpl<ExamTaskMapper, ExamTask> i
         createName = SystemConstant.translateSpecificSign(createName);
         Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
         Set<Long> orgIds = teachcloudCommonService.listSubOrgIds(null);
-        IPage<ExamTaskDto> examTaskDtoIPage = this.baseMapper.listTaskReviewAudited(new Page<>(pageNumber, pageSize), schoolId, reviewStatus, courseCode, paperNumber, userId, cardRuleId, startTime, endTime, orgIds, startCreateTime, endCreateTime, createName);
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        IPage<ExamTaskDto> examTaskDtoIPage = this.baseMapper.listTaskReviewAudited(new Page<>(pageNumber, pageSize), schoolId, reviewStatus, courseCode, paperNumber, userId, cardRuleId, startTime, endTime, orgIds, startCreateTime, endCreateTime, createName, sysUser.getId());
         return examTaskDtoIPage;
     }
 
@@ -1653,6 +1654,7 @@ public class ExamTaskServiceImpl extends ServiceImpl<ExamTaskMapper, ExamTask> i
             // 课程+试卷编号
             examPrintPlan.setName(examTask.getCourseName() + examTask.getPaperNumber());
             examPrintPlan.setStatus(PrintPlanStatusEnum.READY);
+            examPrintPlan.setSyncStatus(ExamPrintPlanSyncStatusEnum.INIT);
             examPrintPlan.setCreateId(sysUser.getId());
             examPrintPlanService.save(examPrintPlan);
 

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

@@ -11,7 +11,6 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.itextpdf.text.DocumentException;
 import com.itextpdf.text.pdf.PdfReader;
 import com.qmth.boot.api.exception.ApiException;
-import com.qmth.boot.tools.codec.CodecUtils;
 import com.qmth.boot.tools.models.ByteArray;
 import com.qmth.distributed.print.business.bean.dto.PdfDto;
 import com.qmth.distributed.print.business.bean.params.SerialNumberParams;
@@ -19,7 +18,6 @@ import com.qmth.distributed.print.business.entity.*;
 import com.qmth.distributed.print.business.enums.ExamDetailStatusEnum;
 import com.qmth.distributed.print.business.enums.PrintPlanStatusEnum;
 import com.qmth.distributed.print.business.service.*;
-import com.qmth.distributed.print.business.templete.execute.AsyncCreatePdfTempleteService;
 import com.qmth.distributed.print.business.util.HtmlToPdfUtil;
 import com.qmth.distributed.print.business.util.PdfUtil;
 import com.qmth.teachcloud.common.bean.dto.MqDto;
@@ -98,6 +96,9 @@ public class PrintCommonServiceServiceImpl implements PrintCommonService {
     @Resource
     TBTaskService tbTaskService;
 
+    @Resource
+    TBSyncTaskService tbSyncTaskService;
+
     @Resource
     ExamDetailService examDetailService;
 
@@ -901,6 +902,25 @@ public class PrintCommonServiceServiceImpl implements PrintCommonService {
         return map;
     }
 
+    @Transactional
+    @Override
+    public Map<String, Object> savePush(PushTypeEnum pushTypeEnum) {
+        Map<String, Object> map = null;
+        try {
+            map = new HashMap<>();
+            TBSyncTask tbSyncTask = tbSyncTaskService.savePushCommon(pushTypeEnum, map, null);
+            tbSyncTaskService.save(tbSyncTask);
+        } catch (Exception e) {
+            log.error("请求出错", e);
+            if (e instanceof ApiException) {
+                ResultUtil.error((ApiException) e, e.getMessage());
+            } else {
+                ResultUtil.error(e.getMessage());
+            }
+        }
+        return map;
+    }
+
     /**
      * 校验课程关联考场是否提交打印
      *
@@ -1037,4 +1057,53 @@ public class PrintCommonServiceServiceImpl implements PrintCommonService {
     public String createTempNumber(SerialNumberParams serialNumberParams) {
         return convertUtil.getIncre(serialNumberParams.getPrefix(), serialNumberParams.getModel(), serialNumberParams.getDigit());
     }
+
+    /**
+     * 保存任务附件(导出)
+     *
+     * @param fos
+     * @param oss
+     * @return
+     */
+    @Override
+    public String saveTaskAttachment(ByteArrayOutputStream fos, boolean oss) throws IOException {
+        InputStream inputStream = null;
+        JSONObject jsonObject = null;
+        try {
+            inputStream = new ByteArrayInputStream(fos.toByteArray());
+            LocalDateTime nowTime = LocalDateTime.now();
+            StringJoiner stringJoiner = new StringJoiner("");
+            if (!oss) {
+                stringJoiner.add(SystemConstant.TEMP_FILES_DIR).add(File.separator);
+            }
+            stringJoiner.add(UploadFileEnum.FILE.getTitle()).add(File.separator);
+            stringJoiner.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(SystemConstant.getUuid()).add(".").add(SystemConstant.XLSX);
+            jsonObject = new JSONObject();
+            String dirName = stringJoiner.toString().replaceAll("\\\\", "/");
+            if (oss) {//上传至oss
+                fileStoreUtil.ossUpload(dirName, inputStream, DigestUtils.md5Hex(new ByteArrayInputStream(fos.toByteArray())), UploadFileEnum.FILE.getFssType());
+                jsonObject.put(SystemConstant.TYPE, SystemConstant.OSS);
+            } else {
+                File finalFile = new File(stringJoiner.toString());
+                if (!finalFile.exists()) {
+                    finalFile.getParentFile().mkdirs();
+                    finalFile.createNewFile();
+                }
+                FileUtils.copyInputStreamToFile(inputStream, finalFile);
+                jsonObject.put(SystemConstant.TYPE, SystemConstant.LOCAL);
+            }
+            jsonObject.put(SystemConstant.PATH, dirName);
+            jsonObject.put(SystemConstant.UPLOAD_TYPE, UploadFileEnum.FILE);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (Objects.nonNull(inputStream)) {
+                inputStream.close();
+            }
+        }
+        return Objects.nonNull(jsonObject) ? jsonObject.toJSONString() : null;
+    }
 }

+ 61 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/SsoServiceImpl.java

@@ -0,0 +1,61 @@
+package com.qmth.distributed.print.business.service.impl;
+
+import com.qmth.distributed.print.business.service.SsoService;
+import com.qmth.teachcloud.common.entity.SysUser;
+import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
+import com.qmth.teachcloud.common.enums.userPush.SpecialPrivilegeEnum;
+import com.qmth.teachcloud.common.service.SysUserService;
+import com.qmth.teachcloud.common.sync.StmmsUtils;
+import com.qmth.teachcloud.common.util.ServletUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+
+/**
+ * @Date: 2021/5/20.
+ */
+@Service
+public class SsoServiceImpl implements SsoService {
+
+    private final static Logger log = LoggerFactory.getLogger(SsoServiceImpl.class);
+
+    @Autowired
+    private SysUserService sysUserService;
+
+    @Autowired
+    StmmsUtils stmmsUtils;
+
+    @Override
+    public Map<String, Object> markerLoginInfo() {
+        try {
+            SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+            SpecialPrivilegeEnum userSpecialPrivilege = sysUserService.findUserSpecialPrivilegeByUserId(sysUser.getId());
+            if (SpecialPrivilegeEnum.UNIDENTIFIED.equals(userSpecialPrivilege)
+                    || SpecialPrivilegeEnum.SUBJECT_HEADER.equals(userSpecialPrivilege)) {
+                throw ExceptionResultEnum.ERROR.exception("该用户没有评卷员角色,无法登录");
+            }
+            return stmmsUtils.markLogin(sysUser);
+        } catch (Exception e) {
+            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
+        }
+    }
+
+    @Override
+    public Map<String, Object> markerLeaderLoginInfo() {
+        try {
+            SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+            SpecialPrivilegeEnum userSpecialPrivilege = sysUserService.findUserSpecialPrivilegeByUserId(sysUser.getId());
+            if (SpecialPrivilegeEnum.UNIDENTIFIED.equals(userSpecialPrivilege)
+                    || SpecialPrivilegeEnum.MARKER.equals(userSpecialPrivilege)) {
+                throw ExceptionResultEnum.ERROR.exception("该用户没有科组长角色,无法登录");
+            }
+            return stmmsUtils.markLeaderLogin(sysUser);
+        } catch (Exception e) {
+            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
+        }
+    }
+
+}

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

@@ -1,26 +1,44 @@
 package com.qmth.distributed.print.business.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.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.mapper.TBSyncTaskMapper;
 import com.qmth.distributed.print.business.service.TBSyncTaskService;
+import com.qmth.teachcloud.common.bean.result.SyncListResult;
 import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.SysUser;
 import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
+import com.qmth.teachcloud.common.enums.PushTypeEnum;
+import com.qmth.teachcloud.common.enums.TaskResultEnum;
 import com.qmth.teachcloud.common.enums.TaskStatusEnum;
+import com.qmth.teachcloud.common.util.ServletUtil;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
 
 /**
  * @Date: 2021/5/20.
  */
 @Service
 public class TBSyncTaskServiceImpl extends ServiceImpl<TBSyncTaskMapper, TBSyncTask> implements TBSyncTaskService {
+    @Resource
+    TBSyncTaskMapper tbSyncTaskMapper;
+
     @Override
     public TBSyncTask saveTask(ExamPrintPlan examPrintPlan) {
         QueryWrapper<TBSyncTask> queryWrapper = new QueryWrapper<>();
         queryWrapper.lambda().eq(TBSyncTask::getSchoolId, examPrintPlan.getSchoolId())
                 .eq(TBSyncTask::getPrintPlanId, examPrintPlan.getId())
+                .eq(TBSyncTask::getType, PushTypeEnum.EXAM_PUSH)
                 .ne(TBSyncTask::getStatus, TaskStatusEnum.FINISH);
         TBSyncTask tbSyncTask = this.getOne(queryWrapper);
         if (tbSyncTask != null) {
@@ -31,10 +49,40 @@ public class TBSyncTaskServiceImpl extends ServiceImpl<TBSyncTaskMapper, TBSyncT
             tbSyncTask.setSchoolId(examPrintPlan.getSchoolId());
             tbSyncTask.setPrintPlanId(examPrintPlan.getId());
             tbSyncTask.setPrintPlanName(examPrintPlan.getName());
+            tbSyncTask.setType(PushTypeEnum.EXAM_PUSH);
             tbSyncTask.setStatus(TaskStatusEnum.INIT);
             tbSyncTask.setCreateTime(System.currentTimeMillis());
         }
         this.save(tbSyncTask);
         return tbSyncTask;
     }
+
+    @Transactional
+    @Override
+    public TBSyncTask savePushCommon(PushTypeEnum pushTypeEnum, Map map, SysUser sysUser) {
+        SysUser requestUser = Objects.nonNull(sysUser) ? sysUser : (SysUser) ServletUtil.getRequestUser();
+        TBSyncTask tbSyncTask = new TBSyncTask(pushTypeEnum,
+                TaskStatusEnum.INIT,
+                requestUser.getId(),
+                requestUser.getSchoolId());
+
+        map.computeIfAbsent(SystemConstant.TB_SYNC_TASK, v -> tbSyncTask);
+        map.computeIfAbsent(SystemConstant.USER, v -> requestUser);
+        map.computeIfAbsent(SystemConstant.TB_SYNC_TASK_ID, v -> tbSyncTask.getId());
+        return tbSyncTask;
+    }
+
+    @Override
+    public IPage<SyncListResult> query(Long schoolId, TaskStatusEnum status, PushTypeEnum type, TaskResultEnum result, int pageNumber, int pageSize) {
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        Set<Long> orgIds = null;
+        IPage<SyncListResult> page = tbSyncTaskMapper.query(new Page<>(pageNumber, pageSize), schoolId, status, type, result, sysUser.getId(), orgIds);
+        List<SyncListResult> list = page.getRecords();
+        for (SyncListResult syncListResult : list) {
+            syncListResult.setStatus(Objects.nonNull(syncListResult.getStatus()) ? TaskStatusEnum.valueOf(syncListResult.getStatus()).getTitle() : null);
+            syncListResult.setType(Objects.nonNull(syncListResult.getType()) ? PushTypeEnum.valueOf(syncListResult.getType()).getTitle() : null);
+            syncListResult.setResult(Objects.nonNull(syncListResult.getResult()) ? TaskResultEnum.valueOf(syncListResult.getResult()).getTitle() : null);
+        }
+        return page;
+    }
 }

+ 262 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/TSyncExamStudentScoreServiceImpl.java

@@ -0,0 +1,262 @@
+package com.qmth.distributed.print.business.service.impl;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.qmth.distributed.print.business.bean.result.TSyncExamStudentScoreResult;
+import com.qmth.distributed.print.business.entity.TSyncExamStudentScore;
+import com.qmth.distributed.print.business.enums.ImageTrajectoryEnum;
+import com.qmth.distributed.print.business.mapper.TSyncExamStudentScoreMapper;
+import com.qmth.distributed.print.business.service.TSyncExamStudentScoreService;
+import com.qmth.teachcloud.common.config.DictionaryConfig;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.SysUser;
+import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
+import com.qmth.teachcloud.common.enums.UploadFileEnum;
+import com.qmth.teachcloud.common.util.*;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.io.IOUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.time.LocalDateTime;
+import java.util.*;
+
+/**
+ * <p>
+ * 同步考生成绩表 服务实现类
+ * </p>
+ *
+ * @author wangliang
+ * @since 2021-10-28
+ */
+@Service
+public class TSyncExamStudentScoreServiceImpl extends ServiceImpl<TSyncExamStudentScoreMapper, TSyncExamStudentScore> implements TSyncExamStudentScoreService {
+
+    @Resource
+    TSyncExamStudentScoreMapper tSyncExamStudentScoreMapper;
+
+    @Resource
+    DictionaryConfig dictionaryConfig;
+
+    @Resource
+    FileStoreUtil fileStoreUtil;
+
+    /**
+     * 同步成绩查询列表
+     *
+     * @param iPage
+     * @param semesterId
+     * @param orgId
+     * @param majorId
+     * @param clazzId
+     * @param courseCode
+     * @return
+     */
+    @Override
+    public IPage<TSyncExamStudentScoreResult> list(IPage<Map> iPage, Long semesterId, Long orgId, Long majorId, Long clazzId, String courseCode) {
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        return tSyncExamStudentScoreMapper.list(iPage, sysUser.getSchoolId(), semesterId, orgId, majorId, clazzId, courseCode);
+    }
+
+    /**
+     * 成绩导出
+     *
+     * @param schoolId
+     * @param semesterId
+     * @param orgId
+     * @param majorId
+     * @param clazzId
+     * @param courseCode
+     * @return
+     */
+    @Override
+    public List<TSyncExamStudentScoreResult> export(Long schoolId, Long semesterId, Long orgId, Long majorId, Long clazzId, String courseCode) {
+        return tSyncExamStudentScoreMapper.export(schoolId, semesterId, orgId, majorId, clazzId, courseCode);
+    }
+
+    /**
+     * 成绩导出计数
+     *
+     * @param schoolId
+     * @param semesterId
+     * @param orgId
+     * @param majorId
+     * @param clazzId
+     * @param courseCode
+     * @return
+     */
+    @Override
+    public int exportCount(Long schoolId, Long semesterId, Long orgId, Long majorId, Long clazzId, String courseCode) {
+        return tSyncExamStudentScoreMapper.exportCount(schoolId, semesterId, orgId, majorId, clazzId, courseCode);
+    }
+
+    /**
+     * 创建动态轨迹图
+     *
+     * @param tSyncExamStudentScore
+     * @param imageTrajectoryEnum
+     * @return
+     */
+    @Override
+    public TSyncExamStudentScore createImageTrajectory(TSyncExamStudentScore tSyncExamStudentScore, ImageTrajectoryEnum imageTrajectoryEnum) {
+        List<File> fileSourceList = new ArrayList<>(), fileTargetList = new ArrayList<>();
+        try {
+            Optional.ofNullable(tSyncExamStudentScore.getSheetUrls()).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("未获取到考生原卷地址"));
+            Optional.ofNullable(tSyncExamStudentScore.getSyncData()).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("未获取到考生作答数据"));
+            StringJoiner stringJoiner = new StringJoiner("");
+            stringJoiner.add(SystemConstant.TEMP_FILES_DIR).add(File.separator);
+            if (Objects.isNull(tSyncExamStudentScore.getTrajectoryUrls())) {
+                JSONArray jsonArray = JSONArray.parseArray(tSyncExamStudentScore.getSheetUrls());
+                JSONObject syncDataJson = JSONObject.parseObject(tSyncExamStudentScore.getSyncData());
+                Optional.ofNullable(syncDataJson.get("markTags")).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("未获取到考生轨迹坐标数据"));
+                JSONObject markTagsJson = JSONObject.parseObject(syncDataJson.get("markTags").toString());
+                boolean oss = dictionaryConfig.sysDomain().isOss();
+                JSONObject jsonObject = new JSONObject();
+                jsonObject.put(SystemConstant.UPLOAD_TYPE, UploadFileEnum.FILE);
+                if (oss) {
+                    jsonObject.put(SystemConstant.TYPE, SystemConstant.OSS);
+                } else {
+                    jsonObject.put(SystemConstant.TYPE, SystemConstant.LOCAL);
+                }
+                JSONArray jsonImageTrajectoryPathArray = new JSONArray();
+                for (int i = 0; i < jsonArray.size(); i++) {
+                    JSONArray markTagJsonArray = (JSONArray) markTagsJson.get(i + 1);
+                    if (Objects.isNull(markTagJsonArray) || markTagJsonArray.size() == 0) {
+                        continue;
+                    }
+                    String url = (String) jsonArray.get(i);
+                    String format = url.substring(url.lastIndexOf("."), url.length());
+                    LocalDateTime nowTime = LocalDateTime.now();
+                    StringJoiner dirJpgName = new StringJoiner("");
+                    dirJpgName.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(tSyncExamStudentScore.getExamNumber())
+                            .add(File.separator).add(SystemConstant.getUuid()).add(format);
+                    File fileSource = new File(stringJoiner.toString() + dirJpgName.toString());
+                    if (!fileSource.exists()) {
+                        fileSource.getParentFile().mkdirs();
+                        fileSource.createNewFile();
+                    }
+                    fileSource = HttpUtil.httpDownload(url, fileSource.getPath());
+                    fileSourceList.add(fileSource);
+
+                    StringJoiner dirTargetJpgName = new StringJoiner("");
+                    dirTargetJpgName.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(tSyncExamStudentScore.getExamNumber())
+                            .add(File.separator).add(SystemConstant.getUuid()).add(format);
+                    File fileTarget = new File(stringJoiner.toString() + dirTargetJpgName.toString());
+                    if (!fileTarget.exists()) {
+                        fileTarget.getParentFile().mkdirs();
+                        fileTarget.createNewFile();
+                    }
+
+                    ImageTrajectoryUtil.createImage(fileSource, fileTarget, markTagJsonArray);
+                    fileTargetList.add(fileTarget);
+                    if (oss) {
+                        fileStoreUtil.ossUpload(dirTargetJpgName.toString(), fileTarget, DigestUtils.md5Hex(new FileInputStream(fileTarget)), UploadFileEnum.FILE.getFssType());
+                    }
+                    jsonImageTrajectoryPathArray.add(dirTargetJpgName.toString());
+                }
+                if (Objects.nonNull(jsonImageTrajectoryPathArray) && jsonImageTrajectoryPathArray.size() > 0) {
+                    jsonObject.put(SystemConstant.PATH, jsonImageTrajectoryPathArray.toJSONString());
+                    tSyncExamStudentScore.setTrajectoryUrls(jsonObject.toJSONString());
+                }
+            } else {
+                JSONObject jsonObject = JSONObject.parseObject(tSyncExamStudentScore.getTrajectoryUrls());
+                String ossType = (String) jsonObject.get(SystemConstant.TYPE);
+                JSONArray jsonArray = JSONArray.parseArray(jsonObject.get(SystemConstant.PATH).toString());
+                if (Objects.equals(ossType, SystemConstant.OSS)) {
+                    for (int i = 0; i < jsonArray.size(); i++) {
+                        String url = (String) jsonArray.get(i);
+                        fileTargetList.add(fileStoreUtil.ossDownload(url, stringJoiner.toString() + url, UploadFileEnum.FILE.getFssType()));
+                    }
+                } else {
+                    for (int i = 0; i < jsonArray.size(); i++) {
+                        String url = (String) jsonArray.get(i);
+                        fileTargetList.add(new File(stringJoiner.toString() + url));
+                    }
+                }
+            }
+            if (Objects.nonNull(fileTargetList) && fileTargetList.size() > 0) {
+                tSyncExamStudentScore.setTrajectoryFileList(fileTargetList);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            tSyncExamStudentScore.setErrorInfo();
+            if (Objects.nonNull(fileTargetList)) {
+                for (File f : fileTargetList) {
+                    f.delete();
+                }
+            }
+        } finally {
+            if (Objects.nonNull(fileSourceList)) {
+                for (File f : fileSourceList) {
+                    f.delete();
+                }
+            }
+        }
+        return tSyncExamStudentScore;
+    }
+
+    /**
+     * 生成zip文件
+     *
+     * @param tSyncExamStudentScore
+     * @throws IOException
+     */
+    @Override
+    public void createZipFile(TSyncExamStudentScore tSyncExamStudentScore) throws IOException {
+        File zipFile = null;
+        OutputStream outputStream = null;
+        try {
+            if (Objects.nonNull(tSyncExamStudentScore.getTrajectoryFileList())) {
+                StringJoiner stringJoiner = new StringJoiner("");
+                stringJoiner.add(SystemConstant.TEMP_FILES_DIR).add(File.separator);
+                LocalDateTime nowTime = LocalDateTime.now();
+                StringJoiner dirZipName = new StringJoiner("");
+                dirZipName.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(SystemConstant.getUuid()).add(SystemConstant.ZIP_PREFIX);
+                zipFile = new File(stringJoiner.toString() + dirZipName.toString());
+                if (!zipFile.exists()) {
+                    zipFile.getParentFile().mkdirs();
+                    zipFile.createNewFile();
+                }
+                FileUtil.doZip(zipFile, Arrays.asList(tSyncExamStudentScore.getTrajectoryFileList().get(0).getParentFile()));
+                HttpServletResponse response = ServletUtil.getResponse();
+//                response.setContentType("image/jpeg");
+//                outputStream = new BufferedOutputStream(response.getOutputStream());
+//                IOUtils.copy(new FileInputStream(zipFile), outputStream);
+                response.reset();
+                response.setHeader("Content-Disposition", "attachment;fileName=" + zipFile.getName());
+                response.addHeader("Content-Length", "" + zipFile.length());
+                response.setContentType("application/octet-stream;charset=UTF-8");
+                outputStream = new BufferedOutputStream(response.getOutputStream());
+                IOUtils.copy(new FileInputStream(zipFile), outputStream);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (Objects.nonNull(outputStream)) {
+                outputStream.flush();
+                outputStream.close();
+            }
+            if (Objects.nonNull(zipFile)) {
+                zipFile.delete();
+            }
+        }
+    }
+}

+ 67 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/execute/AsyncScoreBatchDownloadService.java

@@ -0,0 +1,67 @@
+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.templete.export.AsyncExportTaskTemplete;
+import com.qmth.distributed.print.business.templete.service.TaskLogicService;
+import com.qmth.teachcloud.common.contant.SpringContextHolder;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.TBTask;
+import com.qmth.teachcloud.common.enums.TaskResultEnum;
+import com.qmth.teachcloud.common.enums.TaskStatusEnum;
+import com.qmth.teachcloud.common.service.TBTaskService;
+import com.qmth.teachcloud.common.util.Result;
+import com.qmth.teachcloud.common.util.ResultUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import java.text.MessageFormat;
+import java.util.Date;
+import java.util.Map;
+import java.util.Objects;
+import java.util.StringJoiner;
+
+/**
+ * @Description: 成绩批量下载
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2021/11/1
+ */
+@Service
+public class AsyncScoreBatchDownloadService extends AsyncExportTaskTemplete {
+
+    public static final String OBJ_TITLE = "成绩轨迹";
+    public static final String BEGIN_TITLE = "->开始准备处理下载的";
+    private final static Logger log = LoggerFactory.getLogger(AsyncScoreBatchDownloadService.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.executeDownloadScoreLogic(map);
+            stringJoinerSummary.add(MessageFormat.format("{0}{1}{2}{3}{4}", DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN), FINISH_TITLE, Long.valueOf(String.valueOf(result.get("count"))), FINISH_SIZE, Objects.nonNull(result.get("error")) ? (String) result.get("error") : ""));
+            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();
+    }
+}

+ 65 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/execute/AsyncScoreExportService.java

@@ -0,0 +1,65 @@
+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.templete.export.AsyncExportTaskTemplete;
+import com.qmth.distributed.print.business.templete.service.TaskLogicService;
+import com.qmth.teachcloud.common.contant.SpringContextHolder;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.TBTask;
+import com.qmth.teachcloud.common.enums.TaskResultEnum;
+import com.qmth.teachcloud.common.enums.TaskStatusEnum;
+import com.qmth.teachcloud.common.service.TBTaskService;
+import com.qmth.teachcloud.common.util.Result;
+import com.qmth.teachcloud.common.util.ResultUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import java.text.MessageFormat;
+import java.util.Date;
+import java.util.Map;
+import java.util.StringJoiner;
+
+/**
+ * @Description: 成绩导出
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2021/11/1
+ */
+@Service
+public class AsyncScoreExportService extends AsyncExportTaskTemplete {
+
+    public static final String OBJ_TITLE = "成绩";
+    private final static Logger log = LoggerFactory.getLogger(AsyncScoreExportService.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.executeExportScoreLogic(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();
+    }
+}

+ 67 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/execute/AsyncScorePushService.java

@@ -0,0 +1,67 @@
+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.TBSyncTask;
+import com.qmth.distributed.print.business.service.TBSyncTaskService;
+import com.qmth.distributed.print.business.templete.push.AsyncPushTaskTemplate;
+import com.qmth.distributed.print.business.templete.service.PushLogicService;
+import com.qmth.teachcloud.common.contant.SpringContextHolder;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.enums.TaskResultEnum;
+import com.qmth.teachcloud.common.enums.TaskStatusEnum;
+import com.qmth.teachcloud.common.util.Result;
+import com.qmth.teachcloud.common.util.ResultUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import java.text.MessageFormat;
+import java.util.Date;
+import java.util.Map;
+import java.util.Objects;
+import java.util.StringJoiner;
+
+/**
+ * @Description: 成绩查询推送模板
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2021/11/2
+ */
+@Service
+public class AsyncScorePushService extends AsyncPushTaskTemplate {
+
+    private final static Logger log = LoggerFactory.getLogger(AsyncSysUserDataImportService.class);
+
+    public static final String OBJ_TITLE = "成绩信息";
+
+    @Override
+    public Result pushTask(Map<String, Object> map) {
+        TBSyncTask tbSyncTask = (TBSyncTask) map.get(SystemConstant.TB_SYNC_TASK);
+        StringJoiner stringJoinerSummary = new StringJoiner("\n")
+                .add(MessageFormat.format("{0}{1}{2}", DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN), BEGIN_TITLE, OBJ_TITLE));
+        tbSyncTask.setStatus(TaskStatusEnum.RUNNING);
+        TBSyncTaskService tbSyncTaskService = SpringContextHolder.getBean(TBSyncTaskService.class);
+        tbSyncTaskService.updateById(tbSyncTask);
+        try {
+            PushLogicService pushLogicService = SpringContextHolder.getBean(PushLogicService.class);
+            Map<String, Object> result = pushLogicService.executeScorePushLogic(map);
+            stringJoinerSummary.add(MessageFormat.format("{0}{1}{2}{3}{4}{5}{6}", DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN), FINISH_TITLE, Integer.parseInt(String.valueOf(result.get("count"))), SUCCESS_TITLE, Integer.parseInt(String.valueOf(result.get("correct"))), FINISH_SIZE, Objects.nonNull(result.get("error")) ? (String) result.get("error") : ""));
+            tbSyncTask.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()));
+            tbSyncTask.setResult(TaskResultEnum.ERROR);
+            if (e instanceof ApiException) {
+                ResultUtil.error((ApiException) e, e.getMessage());
+            } else {
+                ResultUtil.error(e.getMessage());
+            }
+        } finally {//生成txt文件
+            tbSyncTask.setSummary(stringJoinerSummary.toString());
+            super.createTxt(tbSyncTask);
+        }
+        return ResultUtil.ok(map);
+    }
+}

+ 16 - 2
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/execute/AsyncSysUserDataImportService.java

@@ -4,11 +4,14 @@ import cn.hutool.core.date.DateUtil;
 import com.qmth.boot.api.exception.ApiException;
 import com.qmth.distributed.print.business.templete.importData.AsyncImportTaskTemplete;
 import com.qmth.distributed.print.business.templete.service.TaskLogicService;
+import com.qmth.teachcloud.common.bean.params.UserPushParam;
 import com.qmth.teachcloud.common.contant.SpringContextHolder;
 import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.SysUser;
 import com.qmth.teachcloud.common.entity.TBTask;
 import com.qmth.teachcloud.common.enums.TaskResultEnum;
 import com.qmth.teachcloud.common.enums.TaskStatusEnum;
+import com.qmth.teachcloud.common.service.SysUserService;
 import com.qmth.teachcloud.common.service.TBTaskService;
 import com.qmth.teachcloud.common.util.Result;
 import com.qmth.teachcloud.common.util.ResultUtil;
@@ -16,10 +19,12 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 
+import javax.annotation.Resource;
 import java.io.IOException;
 import java.io.InputStream;
 import java.text.MessageFormat;
 import java.util.Date;
+import java.util.List;
 import java.util.Map;
 import java.util.StringJoiner;
 
@@ -34,6 +39,9 @@ public class AsyncSysUserDataImportService extends AsyncImportTaskTemplete {
 
     public static final String OBJ_TITLE = "用户基本信息";
 
+    @Resource
+    private SysUserService sysUserService;
+
     @Override
     public Result importTask(Map<String, Object> map) throws IOException, Exception {
         TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
@@ -48,9 +56,15 @@ public class AsyncSysUserDataImportService extends AsyncImportTaskTemplete {
         try {
             TaskLogicService taskLogicService = SpringContextHolder.getBean(TaskLogicService.class);
 
-            // 执行导入基础学生数据
+            // 执行导入基础用户数据
             Map<String, Object> result = taskLogicService.executeImportSysUserLogic(map);
-
+            // 执行用户同步数据
+            SysUser sysUser = (SysUser) map.get(SystemConstant.SYS_USER);
+            Long schoolId = sysUser.getSchoolId();
+            List<UserPushParam> userPushParamList = (List<UserPushParam>) result.get("userPushParamList");
+            if (userPushParamList != null && userPushParamList.size() > 0){
+                sysUserService.userPushService(userPushParamList,sysUser.getId());
+            }
 
             stringJoinerSummary.add(MessageFormat.format("{0}{1}{2}{3}", DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN), FINISH_TITLE, Long.valueOf(String.valueOf(result.get("dataCount"))), FINISH_SIZE));
             tbTask.setResult(TaskResultEnum.SUCCESS);

+ 72 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/execute/AsyncUserPushService.java

@@ -0,0 +1,72 @@
+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.TBSyncTask;
+import com.qmth.distributed.print.business.service.TBSyncTaskService;
+import com.qmth.distributed.print.business.templete.push.AsyncPushTaskTemplate;
+import com.qmth.distributed.print.business.templete.service.PushLogicService;
+import com.qmth.distributed.print.business.templete.service.TaskLogicService;
+import com.qmth.teachcloud.common.contant.SpringContextHolder;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.TBTask;
+import com.qmth.teachcloud.common.enums.TaskResultEnum;
+import com.qmth.teachcloud.common.enums.TaskStatusEnum;
+import com.qmth.teachcloud.common.service.TBTaskService;
+import com.qmth.teachcloud.common.util.Result;
+import com.qmth.teachcloud.common.util.ResultUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import java.text.MessageFormat;
+import java.util.Date;
+import java.util.Map;
+import java.util.StringJoiner;
+
+/**
+ * @Description: 用户推送模板(异步任务)
+ * @Author: CaoZixuan
+ * @Date: 2021-10-31
+ */
+@Service
+public class AsyncUserPushService extends AsyncPushTaskTemplate {
+
+    private final static Logger log = LoggerFactory.getLogger(AsyncSysUserDataImportService.class);
+
+    public static final String OBJ_TITLE = "用户信息";
+
+    @Override
+    public Result pushTask(Map<String, Object> map) throws Exception {
+        TBSyncTask tbSyncTask = (TBSyncTask) map.get(SystemConstant.TB_SYNC_TASK);
+
+
+        StringJoiner stringJoinerSummary = new StringJoiner("\n")
+                .add(MessageFormat.format("{0}{1}{2}", DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN), BEGIN_TITLE, OBJ_TITLE));
+        tbSyncTask.setStatus(TaskStatusEnum.RUNNING);
+        TBSyncTaskService tbSyncTaskService = SpringContextHolder.getBean(TBSyncTaskService.class);
+        tbSyncTaskService.updateById(tbSyncTask);
+        try {
+            PushLogicService pushLogicService = SpringContextHolder.getBean(PushLogicService.class);
+
+            // 执行需要重新同步的用户同步数据
+            Map<String, Object> result = pushLogicService.executeUserPushLogic(map);
+            System.out.println(Integer.parseInt(String.valueOf(result.get("correct"))));
+            stringJoinerSummary.add(MessageFormat.format("{0}{1}{2}{3}{4}{5}", DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN), FINISH_TITLE, Integer.parseInt(String.valueOf(result.get("count"))),SUCCESS_TITLE,Integer.parseInt(String.valueOf(result.get("correct"))), FINISH_SIZE));
+            tbSyncTask.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文件
+            tbSyncTask.setSummary(stringJoinerSummary.toString());
+            super.createTxt(tbSyncTask);
+        }
+        return ResultUtil.ok(map);
+    }
+}

+ 1 - 1
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/export/AsyncExportTaskTemplete.java

@@ -41,7 +41,7 @@ public abstract class AsyncExportTaskTemplete {
     private final static Logger log = LoggerFactory.getLogger(AsyncImportTaskTemplete.class);
     public static final String BEGIN_TITLE = "->开始准备处理导出的";
     public static final String FINISH_TITLE = "->数据处理结束,共处理了";
-    public static final String FINISH_SIZE = "条数据";
+    public static final String FINISH_SIZE = "条数据";
     public static final String EXCEPTION_TITLE = "->数据处理发生异常!";
     public static final String EXCEPTION_DATA = "错误信息:";
     public static final String TXT_PREFIX = ".txt";

+ 140 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/push/AsyncPushTaskTemplate.java

@@ -0,0 +1,140 @@
+package com.qmth.distributed.print.business.templete.push;
+
+import cn.hutool.core.date.DateUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.qmth.boot.api.exception.ApiException;
+import com.qmth.distributed.print.business.entity.TBSyncTask;
+import com.qmth.distributed.print.business.service.TBSyncTaskService;
+import com.qmth.distributed.print.business.templete.importData.AsyncImportTaskTemplete;
+import com.qmth.teachcloud.common.config.DictionaryConfig;
+import com.qmth.teachcloud.common.contant.SpringContextHolder;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.TBTask;
+import com.qmth.teachcloud.common.enums.TaskResultEnum;
+import com.qmth.teachcloud.common.enums.TaskStatusEnum;
+import com.qmth.teachcloud.common.enums.TaskTypeEnum;
+import com.qmth.teachcloud.common.enums.UploadFileEnum;
+import com.qmth.teachcloud.common.service.TBTaskService;
+import com.qmth.teachcloud.common.util.FileStoreUtil;
+import com.qmth.teachcloud.common.util.Result;
+import com.qmth.teachcloud.common.util.ResultUtil;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Async;
+
+import javax.annotation.Resource;
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.text.MessageFormat;
+import java.time.LocalDateTime;
+import java.util.Date;
+import java.util.Map;
+import java.util.Objects;
+import java.util.StringJoiner;
+
+/**
+ * @Description: 异步推送模板
+ * @Author: CaoZixuan
+ * @Date: 2021-10-31
+ */
+public abstract class AsyncPushTaskTemplate {
+    @Resource
+    private DictionaryConfig dictionaryConfig;
+    @Resource
+    private TBSyncTaskService tbSyncTaskService;
+
+    private final static Logger log = LoggerFactory.getLogger(AsyncPushTaskTemplate.class);
+
+    public static final String BEGIN_TITLE = "->开始准备处理同步的";
+    public static final String EXCEPTION_TITLE = "->数据处理发生异常!";
+    public static final String EXCEPTION_DATA = "错误信息:";
+    public static final String FINISH_TITLE = "->数据处理结束,共需处理";
+    public static final String SUCCESS_TITLE = "条数据,其中成功处理了";
+    public static final String FINISH_SIZE = "条数据。";
+    public static final String TXT_PREFIX = ".txt";
+    public static final String EXCEPTION_CREATE_TXT_TITLE = "->创建导出日志时发生异常!";
+
+    /**
+     * 异步导入任务
+     *
+     * @param map
+     * @return
+     * @throws IOException
+     */
+    @Async
+    public abstract Result pushTask(Map<String, Object> map) throws IOException, Exception;
+
+    /**
+     * 创建txt文件
+     *
+     * @param tbSyncTask
+     */
+    public void createTxt(TBSyncTask tbSyncTask) {
+//        OssUtil ossUtil = SpringContextHolder.getBean(OssUtil.class);
+        TBTaskService tbTaskService = SpringContextHolder.getBean(TBTaskService.class);
+        ByteArrayOutputStream out = null;
+        InputStream inputStream = null;
+        try {
+            out = new ByteArrayOutputStream();
+            out.write(tbSyncTask.getSummary().getBytes(StandardCharsets.UTF_8));
+            byte[] bookByteAry = out.toByteArray();
+            inputStream = new ByteArrayInputStream(bookByteAry);
+            LocalDateTime nowTime = LocalDateTime.now();
+            StringJoiner stringJoiner = new StringJoiner("");
+            stringJoiner.add(UploadFileEnum.FILE.getTitle()).add(File.separator);
+            stringJoiner.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(SystemConstant.getUuid()).add(TXT_PREFIX);
+            String path = stringJoiner.toString().replaceAll("\\\\","/");
+            boolean oss = dictionaryConfig.sysDomain().isOss();
+
+            JSONObject json = new JSONObject();
+            if (oss) {//上传至oss
+                FileStoreUtil fileStoreUtil = SpringContextHolder.getBean(FileStoreUtil.class);
+                fileStoreUtil.ossUpload(path, inputStream, DigestUtils.md5Hex(new ByteArrayInputStream(bookByteAry)), fileStoreUtil.getUploadEnumByPath(stringJoiner.toString()).getFssType());
+                json.put(SystemConstant.TYPE, SystemConstant.OSS);
+            } else {//上传至服务器
+                File finalFile = new File(stringJoiner.toString());
+                if (!finalFile.exists()) {
+                    finalFile.getParentFile().mkdirs();
+                    finalFile.createNewFile();
+                }
+                FileUtils.copyInputStreamToFile(inputStream, finalFile);
+                json.put(SystemConstant.TYPE, SystemConstant.LOCAL);
+            }
+            json.put(SystemConstant.PATH, path);
+            json.put(SystemConstant.UPLOAD_TYPE, UploadFileEnum.FILE);
+
+            tbSyncTask.setReportFilePath(json.toJSONString());
+        } catch (Exception e) {
+            log.error("请求出错", e);
+            StringJoiner stringJoinerSummary = new StringJoiner("").add(tbSyncTask.getSummary()).add("\n");
+            stringJoinerSummary.add(MessageFormat.format("{0}{1}{2}{3}", DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN), EXCEPTION_CREATE_TXT_TITLE, EXCEPTION_DATA, e.getMessage()));
+            tbSyncTask.setSummary(stringJoinerSummary.toString());
+            tbSyncTask.setResult(TaskResultEnum.ERROR);
+            if (e instanceof ApiException) {
+                ResultUtil.error((ApiException) e, e.getMessage());
+            } else {
+                ResultUtil.error(e.getMessage());
+            }
+        } finally {
+            try {
+                if (Objects.nonNull(inputStream)) {
+                    inputStream.close();
+                }
+                if (Objects.nonNull(out)) {
+                    out.flush();
+                    out.close();
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            tbSyncTask.setStatus(TaskStatusEnum.FINISH);
+            tbSyncTaskService.updateById(tbSyncTask);
+        }
+    }
+}

+ 27 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/service/PushLogicService.java

@@ -0,0 +1,27 @@
+package com.qmth.distributed.print.business.templete.service;
+
+import java.util.Map;
+
+/**
+ * @Description: 同步推送处理逻辑接口
+ * @Author: CaoZixuan
+ * @Date: 2021-11-01
+ */
+public interface PushLogicService {
+
+    /**
+     * 用户推送异步任务处理方法
+     *
+     * @param map 任务源
+     * @return 结果
+     */
+    Map<String, Object> executeUserPushLogic(Map<String, Object> map) throws IllegalAccessException;
+
+    /**
+     * 成绩查询推送异步任务处理方法
+     *
+     * @param map 任务源
+     * @return 结果
+     */
+    Map<String, Object> executeScorePushLogic(Map<String, Object> map) throws Exception;
+}

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

@@ -107,4 +107,20 @@ public interface TaskLogicService {
      * @throws Exception 异常
      */
     Map<String, Object> executeImportStatisticsLogic(Map<String, Object> map) throws Exception;
+
+    /**
+     * 成绩导出
+     *
+     * @param map
+     * @return
+     */
+    Map<String, Object> executeExportScoreLogic(Map<String, Object> map) throws Exception;
+
+    /**
+     * 成绩轨迹下载
+     *
+     * @param map
+     * @return
+     */
+    Map<String, Object> executeDownloadScoreLogic(Map<String, Object> map) throws Exception;
 }

+ 162 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/service/impl/PushLogicServiceImpl.java

@@ -0,0 +1,162 @@
+package com.qmth.distributed.print.business.templete.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.qmth.distributed.print.business.entity.ExamStudent;
+import com.qmth.distributed.print.business.entity.TSyncExamStudentScore;
+import com.qmth.distributed.print.business.service.ExamStudentService;
+import com.qmth.distributed.print.business.service.TSyncExamStudentScoreService;
+import com.qmth.distributed.print.business.templete.service.PushLogicService;
+import com.qmth.teachcloud.common.bean.result.SyncCountResult;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.BasicClazz;
+import com.qmth.teachcloud.common.entity.BasicMajor;
+import com.qmth.teachcloud.common.entity.BasicStudent;
+import com.qmth.teachcloud.common.entity.SysUser;
+import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
+import com.qmth.teachcloud.common.service.BasicClazzService;
+import com.qmth.teachcloud.common.service.BasicMajorService;
+import com.qmth.teachcloud.common.service.BasicStudentService;
+import com.qmth.teachcloud.common.service.SysUserService;
+import com.qmth.teachcloud.common.sync.StmmsUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.LinkedMultiValueMap;
+
+import javax.annotation.Resource;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @Description: 同步推送处理逻辑接口实现类
+ * @Author: CaoZixuan
+ * @Date: 2021-11-01
+ */
+@Service
+public class PushLogicServiceImpl implements PushLogicService {
+    private final static Logger log = LoggerFactory.getLogger(PushLogicServiceImpl.class);
+
+    @Resource
+    private SysUserService sysUserService;
+
+    @Resource
+    StmmsUtils stmmsUtils;
+
+    @Resource
+    BasicClazzService basicClazzService;
+
+    @Resource
+    TSyncExamStudentScoreService tSyncExamStudentScoreService;
+
+    @Resource
+    BasicStudentService basicStudentService;
+
+    @Resource
+    ExamStudentService examStudentService;
+
+    @Resource
+    BasicMajorService basicMajorService;
+
+    @Override
+    public Map<String, Object> executeUserPushLogic(Map<String, Object> map) throws IllegalAccessException {
+        int correct = 0;
+        int count = 0;
+        SysUser sysUser = (SysUser) map.get(SystemConstant.SYS_USER);
+        SyncCountResult syncCountResult = sysUserService.needPushAgainOperate(sysUser);
+        map.put("correct", syncCountResult.getCorrectCount());
+        map.put("count", syncCountResult.getTotalCount());
+        return map;
+    }
+
+    /**
+     * 成绩查询推送异步任务处理方法
+     *
+     * @param map 任务源
+     * @return
+     * @throws IllegalAccessException
+     */
+    @Override
+    @Transactional
+    public Map<String, Object> executeScorePushLogic(Map<String, Object> map) throws Exception {
+        SysUser sysUser = (SysUser) map.get(SystemConstant.USER);
+        Long schoolId = sysUser.getSchoolId();
+        LinkedMultiValueMap<Long, Integer> semesterExamIdMap = (LinkedMultiValueMap<Long, Integer>) map.get("semesterExamIdMap");
+        List<TSyncExamStudentScore> tSyncExamStudentScoreList = new ArrayList<>();
+        List<String> errorTSyncExamStudentScoreList = new ArrayList<>();
+        AtomicInteger count = new AtomicInteger(0);
+        try {
+            semesterExamIdMap.forEach((k, v) -> {
+                for (Integer examId : v) {
+                    int totalCount = stmmsUtils.getStudentCount(schoolId, examId, null, null, null, null, null, null, null, true);
+                    count.set(count.get() + totalCount);
+                    log.info("云阅卷:考试成绩考生数量查询接口调用,返回数量:{}", totalCount);
+                    if (totalCount > 0) {
+                        int pageSize = stmmsUtils.getDefaultPageSize();
+                        int mod = totalCount % pageSize;
+                        int pageNos = mod == 0 ? totalCount / pageSize : totalCount / pageSize + 1;
+                        for (int i = 1; i <= pageNos; i++) {
+                            List<Map> students = stmmsUtils.getStudentScore(schoolId, examId, null, null, null, null, null, null, null, true, i, pageSize);
+                            for (Map student : students) {
+                                try {
+                                    Long orgId = null, clazzId = null, majorId = null;
+                                    if (Objects.nonNull(student.get("studentCode")) && !Objects.equals("无", student.get("studentCode"))) {
+                                        //先查学生表
+                                        QueryWrapper<BasicStudent> basicStudentQueryWrapper = new QueryWrapper<>();
+                                        basicStudentQueryWrapper.lambda().eq(BasicStudent::getSchoolId, sysUser.getSchoolId())
+                                                .eq(BasicStudent::getStudentCode, student.get("studentCode"));
+                                        BasicStudent basicStudent = basicStudentService.getOne(basicStudentQueryWrapper);
+                                        if (Objects.isNull(basicStudent)) {//如果学生表为空,则查考生表
+                                            QueryWrapper<ExamStudent> examStudentQueryWrapper = new QueryWrapper<>();
+                                            examStudentQueryWrapper.lambda().eq(ExamStudent::getSchoolId, sysUser.getSchoolId())
+                                                    .eq(ExamStudent::getStudentCode, student.get("studentCode"));
+                                            ExamStudent examStudent = examStudentService.getOne(examStudentQueryWrapper);
+                                            Optional.ofNullable(examStudent).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("未找到此考生信息"));
+                                            clazzId = Long.parseLong(examStudent.getClazzId());
+                                            if (Objects.nonNull(clazzId)) {
+                                                BasicClazz basicClazz = basicClazzService.getById(clazzId);
+                                                if (Objects.nonNull(basicClazz)) {
+                                                    majorId = basicClazz.getMajorId();
+                                                    BasicMajor basicMajor = basicMajorService.getById(majorId);
+                                                    orgId = basicMajor.getBelongOrgId();
+                                                }
+                                            }
+                                        } else {
+                                            orgId = basicStudent.getBelongOrgId();
+                                            clazzId = basicStudent.getClazzId();
+                                            majorId = basicStudent.getMajorId();
+                                        }
+                                    }
+                                    student.put(SystemConstant.SCHOOL_ID, schoolId);
+                                    student.put("semesterId", k);
+                                    student.put("orgId", orgId);
+                                    student.put("clazzId", clazzId);
+                                    student.put("majorId", majorId);
+                                    student.put("userId", sysUser.getId());
+                                    tSyncExamStudentScoreList.add(new TSyncExamStudentScore(student));
+                                } catch (Exception e) {
+                                    log.info("同步学生成绩信息失败:{}", e.getMessage());
+                                    e.printStackTrace();
+                                    errorTSyncExamStudentScoreList.add(student.get("name") + "," + student.get("examNumber") + "\r\n");
+                                }
+                            }
+                        }
+                        if (tSyncExamStudentScoreList.size() > 0) {
+                            tSyncExamStudentScoreService.remove(new QueryWrapper<TSyncExamStudentScore>().lambda().eq(TSyncExamStudentScore::getSchoolId, schoolId).eq(TSyncExamStudentScore::getExamId, Long.parseLong(String.valueOf(examId))));
+                            tSyncExamStudentScoreService.saveOrUpdateBatch(tSyncExamStudentScoreList);
+                        }
+                    }
+                }
+            });
+            map.computeIfAbsent("count", e -> count.get());
+            map.computeIfAbsent("correct", e -> tSyncExamStudentScoreList.size());
+            if (Objects.nonNull(errorTSyncExamStudentScoreList) && errorTSyncExamStudentScoreList.size() > 0) {
+                map.computeIfAbsent("error", e -> "未同步成功数据" + errorTSyncExamStudentScoreList.size() + "条:\r\n" + errorTSyncExamStudentScoreList.toString());
+            }
+        } catch (Exception e) {
+            log.info("云阅卷:接口调用失败:{}", e.getMessage());
+            throw new RuntimeException("云阅卷:接口调用失败:" + e.getMessage());
+        }
+        return map;
+    }
+}

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

@@ -15,6 +15,7 @@ import com.itextpdf.text.DocumentException;
 import com.qmth.boot.api.exception.ApiException;
 import com.qmth.distributed.print.business.bean.dto.*;
 import com.qmth.distributed.print.business.bean.params.SerialNumberParams;
+import com.qmth.distributed.print.business.bean.result.TSyncExamStudentScoreResult;
 import com.qmth.distributed.print.business.cache.CreatePdfCacheUtil;
 import com.qmth.distributed.print.business.entity.*;
 import com.qmth.distributed.print.business.enums.*;
@@ -42,6 +43,7 @@ import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.data.redis.support.atomic.RedisAtomicLong;
 import org.springframework.stereotype.Service;
@@ -159,6 +161,13 @@ public class TaskLogicServiceImpl implements TaskLogicService {
     @Resource
     TCStatisticsTempService tcStatisticsTempService;
 
+    @Resource
+    TSyncExamStudentScoreService tSyncExamStudentScoreService;
+
+    @Resource
+    @Lazy
+    PrintCommonService printCommonService;
+
     /**
      * 创建pdf前置条件
      *
@@ -1127,7 +1136,7 @@ public class TaskLogicServiceImpl implements TaskLogicService {
                     String studentName = basicStudentImportDto.getStudentName();
                     String studentCode = basicStudentImportDto.getStudentCode();
                     String phoneNumber = basicStudentImportDto.getPhoneNumber();
-                    String clazz = basicStudentImportDto.getClazz();
+                    String clazzName = basicStudentImportDto.getClazzName();
 
                     // 检验excel中
                     // 检验学号
@@ -1173,7 +1182,7 @@ public class TaskLogicServiceImpl implements TaskLogicService {
         InputStream inputStream = (InputStream) map.get("inputStream");
         List<LinkedMultiValueMap<Integer, Object>> finalList = ExcelUtil.excelReader(inputStream, Lists.newArrayList(BasicCourseImportDto.class, DescribeImportDto.class), (finalExcelList, finalColumnNameList, finalExcelErrorList) -> {
             List<ExcelError> excelErrorTemp = new ArrayList<>();
-            Map<String, String> checkMap = new HashMap<>();
+//            Map<String, String> checkMap = new HashMap<>();
             for (int i = 0; i < finalExcelList.size(); i++) {
                 LinkedMultiValueMap<Integer, Object> excelMap = finalExcelList.get(i);
                 List<Object> basicCourseImportDtoList = excelMap.get(i);
@@ -1189,11 +1198,11 @@ public class TaskLogicServiceImpl implements TaskLogicService {
                     String clazz = basicCourseImportDto.getClazz();
 
                     // 检验excel中
-                    if (checkMap.containsKey(courseCode)) {
-                        throw ExceptionResultEnum.ERROR.exception("导入的excel中包含在重复的【课程编号】:" + courseCode);
-                    } else {
-                        checkMap.put(courseCode, courseName);
-                    }
+//                    if (checkMap.containsKey(courseCode)) {
+//                        throw ExceptionResultEnum.ERROR.exception("导入的excel中包含在重复的【课程编号】:" + courseCode);
+//                    } else {
+//                        checkMap.put(courseCode, courseName);
+//                    }
 
                     excelErrorTemp.addAll(ExcelUtil.checkExcelField(basicCourseImportDto, y, i));
                     if (Objects.isNull(courseCode) || courseCode.length() > 30 || !courseCode.matches(SystemConstant.REGULAR_EXPRESSION_OF_CODE)) {
@@ -1248,7 +1257,7 @@ public class TaskLogicServiceImpl implements TaskLogicService {
                         checkCode.put(code, name);
                     }
                     // 如果电话有值则检验电话excel中唯一性
-                    if (SystemConstant.strNotNull(phoneNumber)){
+                    if (SystemConstant.strNotNull(phoneNumber)) {
                         if (checkPhoneMap.containsKey(phoneNumber)) {
                             throw ExceptionResultEnum.ERROR.exception("导入的excel中包含在重复的【电话号码】:" + phoneNumber);
                         } else {
@@ -1394,6 +1403,144 @@ public class TaskLogicServiceImpl implements TaskLogicService {
         return map;
     }
 
+    /**
+     * 成绩导出
+     *
+     * @param map
+     * @return
+     * @throws Exception
+     */
+    @Override
+    public Map<String, Object> executeExportScoreLogic(Map<String, Object> map) throws Exception {
+        ByteArrayOutputStream fos = null;
+        try {
+            SysUser sysUser = (SysUser) map.get(SystemConstant.USER);
+            Long semesterId = null, orgId = null, majorId = null, clazzId = null;
+            String courseCode = null;
+            semesterId = Objects.nonNull(map.get("semesterId")) ? (Long) map.get(semesterId) : null;
+            orgId = Objects.nonNull(map.get("orgId")) ? (Long) map.get(orgId) : null;
+            majorId = Objects.nonNull(map.get("majorId")) ? (Long) map.get("majorId") : null;
+            clazzId = Objects.nonNull(map.get("clazzId")) ? (Long) map.get("clazzId") : null;
+            courseCode = Objects.nonNull(map.get("courseCode")) ? (String) map.get("courseCode") : null;
+
+            fos = new ByteArrayOutputStream();
+            List<TSyncExamStudentScoreResult> tSyncExamStudentScoreResultList = tSyncExamStudentScoreService.export(sysUser.getSchoolId(), semesterId, orgId, majorId, clazzId, courseCode);
+            ExcelUtil.excelMake(TSyncExamStudentScoreResult.class, tSyncExamStudentScoreResultList, fos);
+            String excelExportFilePath = printCommonService.saveTaskAttachment(fos, (boolean) map.get(SystemConstant.OSS));
+            map.computeIfAbsent("count", v -> Objects.isNull(tSyncExamStudentScoreResultList) ? 0 : tSyncExamStudentScoreResultList.size());
+            TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
+            tbTask.setResultFilePath(excelExportFilePath);
+        } catch (Exception e) {
+            log.error("请求出错", e);
+            e.printStackTrace();
+        } finally {
+            if (Objects.nonNull(fos)) {
+                fos.flush();
+                fos.close();
+            }
+        }
+        return map;
+    }
+
+    /**
+     * 成绩轨迹下载
+     *
+     * @param map
+     * @return
+     * @throws Exception
+     */
+    @Override
+    @Transactional
+    public Map<String, Object> executeDownloadScoreLogic(Map<String, Object> map) throws Exception {
+        File zipFile = null;
+        List<File> sourceFiles = null;
+        List<TSyncExamStudentScore> errorTSyncExamStudentScoreList = null;
+        try {
+            SysUser sysUser = (SysUser) map.get(SystemConstant.USER);
+            Long semesterId = null, orgId = null, majorId = null, clazzId = null;
+            String courseCode = null;
+            semesterId = Objects.nonNull(map.get("semesterId")) ? (Long) map.get("semesterId") : null;
+            orgId = Objects.nonNull(map.get("orgId")) ? (Long) map.get("orgId") : null;
+            majorId = Objects.nonNull(map.get("majorId")) ? (Long) map.get("majorId") : null;
+            clazzId = Objects.nonNull(map.get("clazzId")) ? (Long) map.get("clazzId") : null;
+            courseCode = Objects.nonNull(map.get("courseCode")) ? (String) map.get("courseCode") : null;
+
+            List<TSyncExamStudentScoreResult> tSyncExamStudentScoreResultList = tSyncExamStudentScoreService.export(sysUser.getSchoolId(), semesterId, orgId, majorId, clazzId, courseCode);
+            if (Objects.nonNull(tSyncExamStudentScoreResultList) && tSyncExamStudentScoreResultList.size() > 0) {
+                List<TSyncExamStudentScore> tSyncExamStudentScoreList = new Gson().fromJson(JacksonUtil.parseJson(tSyncExamStudentScoreResultList), new TypeToken<List<TSyncExamStudentScore>>() {
+                }.getType());
+                LocalDateTime nowTime = LocalDateTime.now();
+                StringJoiner stringJoiner = new StringJoiner("");
+                stringJoiner.add(SystemConstant.TEMP_FILES_DIR).add(File.separator);
+                StringJoiner dirZipName = new StringJoiner("");
+                dirZipName.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(SystemConstant.getUuid()).add(SystemConstant.ZIP_PREFIX);
+                zipFile = new File(stringJoiner.toString() + dirZipName.toString());
+                if (!zipFile.exists()) {
+                    zipFile.getParentFile().mkdirs();
+                    zipFile.createNewFile();
+                }
+                sourceFiles = new LinkedList<>();
+                List<TSyncExamStudentScore> updateTSyncExamStudentScoreList = new ArrayList<>();
+                errorTSyncExamStudentScoreList = new ArrayList<>();
+                for (TSyncExamStudentScore t : tSyncExamStudentScoreList) {
+                    try {
+                        boolean update = Objects.isNull(t.getTrajectoryUrls()) ? true : false;
+                        t = tSyncExamStudentScoreService.createImageTrajectory(t, ImageTrajectoryEnum.DOWNLOAD);
+                        if (Objects.nonNull(t.getTrajectoryFileList())) {
+                            sourceFiles.add(t.getTrajectoryFileList().get(0).getParentFile());
+                        } else {
+                            errorTSyncExamStudentScoreList.add(t);
+                        }
+                        if (update || Objects.isNull(t.getTrajectoryUrls())) {
+                            updateTSyncExamStudentScoreList.add(t);
+                        }
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                        errorTSyncExamStudentScoreList.add(t);
+                    }
+                }
+                tSyncExamStudentScoreService.saveOrUpdateBatch(updateTSyncExamStudentScoreList);
+                if (Objects.nonNull(sourceFiles) && sourceFiles.size() > 0) {
+                    FileUtil.doZip(zipFile, sourceFiles);
+                    boolean oss = (boolean) map.get(SystemConstant.OSS);
+                    JSONObject jsonObject = new JSONObject();
+                    if (oss) {//上传至oss
+                        fileStoreUtil.ossUpload(dirZipName.toString(), zipFile, DigestUtils.md5Hex(new FileInputStream(zipFile)), UploadFileEnum.FILE.getFssType());
+                        jsonObject.put(SystemConstant.TYPE, SystemConstant.OSS);
+                        jsonObject.put(SystemConstant.PATH, dirZipName.toString());
+                    } else {
+                        jsonObject.put(SystemConstant.TYPE, SystemConstant.LOCAL);
+                        jsonObject.put(SystemConstant.PATH, stringJoiner.toString() + dirZipName.toString());
+                    }
+                    jsonObject.put(SystemConstant.UPLOAD_TYPE, UploadFileEnum.FILE);
+                    TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
+                    tbTask.setResultFilePath(jsonObject.toJSONString());
+                }
+            }
+            map.computeIfAbsent("count", v -> tSyncExamStudentScoreResultList.size());
+            if (Objects.nonNull(errorTSyncExamStudentScoreList) && errorTSyncExamStudentScoreList.size() > 0) {
+                StringJoiner stringJoiner = new StringJoiner("").add("\r\n");
+                for (TSyncExamStudentScore t : errorTSyncExamStudentScoreList) {
+                    stringJoiner.add("[").add(t.getName()).add(",").add(t.getExamNumber()).add("]\r\n");
+                }
+                List<TSyncExamStudentScore> finalErrorTSyncExamStudentScoreList = errorTSyncExamStudentScoreList;
+                map.computeIfAbsent("error", v -> "其中未下载成功数据" + finalErrorTSyncExamStudentScoreList.size() + "条:" + stringJoiner.toString());
+            }
+        } catch (Exception e) {
+            log.error("请求出错", e);
+            e.printStackTrace();
+        } finally {
+            if (Objects.nonNull(zipFile)) {
+                zipFile.delete();
+            }
+        }
+        return map;
+    }
+
 
     public String createTempNumber(SerialNumberParams serialNumberParams) {
         return convertUtil.getIncre(serialNumberParams.getPrefix(), serialNumberParams.getModel(), serialNumberParams.getDigit());

+ 135 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/util/SmsUtils.java

@@ -0,0 +1,135 @@
+package com.qmth.distributed.print.business.util;
+
+import com.aliyuncs.DefaultAcsClient;
+import com.aliyuncs.IAcsClient;
+import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
+import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
+import com.aliyuncs.exceptions.ClientException;
+import com.aliyuncs.http.MethodType;
+import com.aliyuncs.profile.DefaultProfile;
+import com.aliyuncs.profile.IClientProfile;
+import com.qmth.distributed.print.business.enums.MessageEnum;
+import com.qmth.teachcloud.common.config.DictionaryConfig;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @Date: 2021/11/5.
+ */
+@Component
+public class SmsUtils {
+
+    @Resource
+    private DictionaryConfig dictionaryConfig;
+
+    /**
+     * 发送短信
+     *
+     * @param mobileNumber
+     * @param templateCode
+     * @param variableParams
+     * @return
+     * @throws ClientException
+     */
+    public SendSmsResponse sendSms(String mobileNumber, String templateCode, String variableParams) throws ClientException {
+        System.setProperty("sun.net.client.defaultConnectTimeout", "180000");
+        System.setProperty("sun.net.client.defaultReadTimeout", "18000");
+        // 初始化ascClient需要的几个参数
+        final String product = "Dysmsapi";// 短信API产品名称(短信产品名固定,无需修改)
+        final String domain = "dysmsapi.aliyuncs.com";// 短信API产品域名(接口地址固定,无需修改)
+        // 替换成你的AK
+        final String accessKeyId = dictionaryConfig.smsDomain().getAliyunSMSKey();// 你的accessKeyId,参考本文档步骤2
+        final String accessKeySecret = dictionaryConfig.smsDomain().getAliyunSMSSecret();// 你的accessKeySecret,参考本文档步骤2
+        // 初始化ascClient,暂时不支持多region(请勿修改)
+        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
+        DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
+        IAcsClient acsClient = new DefaultAcsClient(profile);
+        // 组装请求对象
+        SendSmsRequest request = new SendSmsRequest();
+        // 使用post提交
+        request.setMethod(MethodType.POST);
+        // 必填:待发送手机号。支持以逗号分隔的形式进行批量调用,批量上限为1000个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式;发送国际/港澳台消息时,接收号码格式为00+国际区号+号码,如“0085200000000”
+        request.setPhoneNumbers(mobileNumber);
+        // 必填:短信签名-可在短信控制台中找到
+        request.setSignName(dictionaryConfig.smsDomain().getAliyunSMSSignName());
+        // 必填:短信模板-可在短信控制台中找到
+        request.setTemplateCode(templateCode);
+        // 可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
+        // 友情提示:如果JSON中需要带换行符,请参照标准的JSON协议对换行符的要求,比如短信内容中包含\r\n的情况在JSON中需要表示成\\r\\n,否则会导致JSON在服务端解析失败
+        request.setTemplateParam(variableParams);
+        // 可选-上行短信扩展码(扩展码字段控制在7位或以下,无特殊需求用户请忽略此字段)
+        // request.setSmsUpExtendCode("90997");
+        // 可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
+//             request.setOutId("yourOutId");
+        // 请求失败这里会抛ClientException异常
+
+        SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
+        return sendSmsResponse;
+    }
+
+    public Map<String, String> getCodeAndContentByEnum(MessageEnum messageEnum) {
+        Map<String, String> result = new HashMap<>();
+        String templateContent = null;
+        String templateCode = null;
+        switch (messageEnum) {
+            case NOTICE_OF_AUDIT_PASS:
+                templateCode = dictionaryConfig.smsDomain().getAliyunSMSAuditPassCode();
+                templateContent = messageEnum.getTemplate();
+                break;
+            case NOTICE_OF_AUDIT_NOT_PASS:
+                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;
+            case NOTICE_OF_AUDIT_REJECT:
+                templateCode = dictionaryConfig.smsDomain().getAliyunSMSAuditRejectCode();
+                templateContent = messageEnum.getTemplate();
+                break;
+            case NOTICE_OF_UPLOAD_STRUCTURE:
+                templateCode = dictionaryConfig.smsDomain().getAliyunSMSUploadStructureCode();
+                templateContent = messageEnum.getTemplate();
+                break;
+        }
+        result.put("templateContent", templateContent);
+        result.put("templateCode", templateCode);
+        return result;
+    }
+}

+ 2 - 1
distributed-print-business/src/main/resources/mapper/BasicCardRuleMapper.xml

@@ -11,6 +11,7 @@
         <result column="paper_type" property="paperType" />
         <result column="exam_absent" property="examAbsent" />
         <result column="write_sign" property="writeSign" />
+        <result column="discipline" property="discipline" />
         <result column="required_fields" property="requiredFields" />
         <result column="extend_fields" property="extendFields" />
         <result column="title_rule" property="titleRule" />
@@ -27,7 +28,7 @@
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        select id, school_id, name, exam_number_style, paper_type, exam_absent, write_sign, required_fields, extend_fields, title_rule, attention, objective_attention, subjective_attention, enable, remark, create_id, create_time, update_id, update_time from basic_card_rule
+        select id, school_id, name, exam_number_style, paper_type, exam_absent, write_sign, discipline, required_fields, extend_fields, title_rule, attention, objective_attention, subjective_attention, enable, remark, create_id, create_time, update_id, update_time from basic_card_rule
     </sql>
     <select id="listPage" resultType="com.qmth.distributed.print.business.bean.dto.CardRuleDto">
         <include refid="Base_Column_List"></include>

+ 54 - 0
distributed-print-business/src/main/resources/mapper/ExamPaperStructureMapper.xml

@@ -0,0 +1,54 @@
+<?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.ExamPaperStructureMapper">
+    <select id="listByPropositionTeacherId"
+            resultType="com.qmth.distributed.print.business.entity.ExamPaperStructure">
+        SELECT
+            eps.id,
+            epp.school_id schoolId,
+            epp.semester_id semesterId,
+            bs.name semesterName,
+            epp.third_relate_id thirdRelateId,
+            epp.third_relate_name thirdRelateName,
+            edc.paper_number paperNumber,
+            edc.course_code courseCode,
+            edc.course_name courseName,
+            edc.paper_type paperType,
+            IFNULL(eps.status, 'INIT') status,
+            eps.paper_answer paperAnswer,
+            et.user_id propositionTeacherId
+        FROM
+            exam_print_plan epp
+                LEFT JOIN
+            basic_semester bs ON epp.semester_id = bs.name
+                LEFT JOIN
+            (SELECT DISTINCT
+                a.print_plan_id,
+                    a.school_id,
+                    b.paper_number,
+                    b.course_code,
+                    b.course_name,
+                    b.paper_type
+            FROM
+                exam_detail a
+            LEFT JOIN exam_detail_course b ON a.id = b.exam_detail_id) edc ON epp.id = edc.print_plan_id
+                LEFT JOIN
+            exam_task et ON edc.school_id = et.school_id
+                AND edc.paper_number = et.paper_number
+                AND edc.course_code = et.course_code
+                LEFT JOIN
+            exam_paper_structure eps ON edc.school_id = eps.school_id
+                AND edc.paper_number = eps.paper_number
+                AND edc.course_code = eps.course_code
+        WHERE
+            epp.school_id = #{schoolId}
+            and et.user_id = #{propositionTeacherId}
+            and epp.sync_status = #{syncStatus}
+            <if test="structureStatusEnums != null">
+                AND ifnull(eps.status, 'INIT') NOT IN
+                <foreach collection="structureStatusEnums" item="item" index="index" open="(" separator="," close=")">
+                    #{item}
+                </foreach>
+            </if>
+    </select>
+</mapper>

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

@@ -32,6 +32,8 @@
             resultType="com.qmth.distributed.print.business.bean.result.PrintPlanResult">
         SELECT
             a.id,
+            a.semester_id semesterId,
+            c.name semesterName,
             a.name,
             a.exam_start_time AS examStartTime,
             a.exam_end_time AS examEndTime,
@@ -60,10 +62,15 @@
             exam_print_plan a
                 LEFT JOIN
             sys_user b on a.create_id = b.id
+                LEFT JOIN
+            basic_semester c on a.semester_id = c.id
         <where>
             <if test="schoolId != null and schoolId != ''">
                 and a.school_id = #{schoolId}
             </if>
+            <if test="semesterId != null and semesterId != ''">
+                and a.semester_id = #{semesterId}
+            </if>
             <if test="printPlanIdList != null and printPlanIdList.size() > 0">
                 and a.id IN
                 <foreach collection="printPlanIdList" item="item" index="index" open="(" separator="," close=")">
@@ -92,6 +99,7 @@
             resultType="com.qmth.distributed.print.business.bean.result.PrintPlanResult">
         SELECT
         a.id,
+        a.semester_id semesterId,
         a.name,
         a.exam_start_time AS examStartTime,
         a.exam_end_time AS examEndTime,
@@ -128,6 +136,9 @@
             <if test="schoolId != null and schoolId != ''">
                 and a.school_id = #{schoolId}
             </if>
+            <if test="semesterId!= null and semesterId != ''">
+                and a.semester_id = #{semesterId}
+            </if>
             <if test="printPlanId!= null and printPlanId != ''">
                 and a.id = #{printPlanId}
             </if>

+ 24 - 3
distributed-print-business/src/main/resources/mapper/ExamStudentMapper.xml

@@ -23,9 +23,9 @@
         school_id, exam_detail_course_id, student_name, student_code, ticket_number, site_number, print_paper, print_card, extend_fields, paper_type
     </sql>
     <insert id="insertBatch">
-        insert into exam_student (id, school_id, org_id, exam_detail_course_id, student_name, student_code, ticket_number, site_number, extend_fields, clazz_id, create_id) values
+        insert into exam_student (id, school_id, org_id, exam_detail_course_id, student_name, student_code, ticket_number, site_number, extend_fields, clazz_id, clazz_name, create_id) values
         <foreach collection="examStudents" separator="," item="item">
-            (#{item.id}, #{item.schoolId}, #{item.orgId}, #{item.examDetailCourseId}, #{item.studentName}, #{item.studentCode}, #{item.ticketNumber}, #{item.siteNumber}, #{item.extendFields}, #{item.clazzId}, #{item.createId})
+            (#{item.id}, #{item.schoolId}, #{item.orgId}, #{item.examDetailCourseId}, #{item.studentName}, #{item.studentCode}, #{item.ticketNumber}, #{item.siteNumber}, #{item.extendFields}, #{item.clazzId}, #{item.clazzName}, #{item.createId})
         </foreach>
     </insert>
     <select id="getStudentDetail" resultType="java.util.Map">
@@ -102,6 +102,7 @@
             a.student_name studentName,
             a.student_code studentCode,
             a.ticket_number ticketNumber,
+            a.clazz_name clazzName,
             a.extend_fields extendFields,
             a.paper_type paperType
         FROM
@@ -115,7 +116,27 @@
     </select>
     <select id="listExamStudentBySchoolIdAndClazzId"
             resultType="com.qmth.distributed.print.business.entity.ExamStudent">
-        select student_name studentName, student_code studentCode, clazz_id clazzId from basic_student where school_id = #{schoolId} and clazz_id = #{classId}
+        SELECT
+            bs.student_name studentName,
+            bs.student_code studentCode,
+            bs.clazz_id clazzId,
+            bc.clazz_name clazzName
+        FROM
+            basic_student bs
+                LEFT JOIN
+            basic_clazz bc ON bs.school_id = bc.school_id and bs.clazz_id = bc.id
+        where bs.school_id = #{schoolId}
+            and bs.clazz_id = #{classId}
+    </select>
+    <select id="getSysOrgByBelongOrgId" resultType="com.qmth.teachcloud.common.entity.SysOrg">
+        SELECT
+            so.id, so.name
+        FROM
+            basic_student bs
+                LEFT JOIN
+            sys_org so ON bs.belong_org_id = so.id
+        WHERE
+            bs.student_code = #{studentCode}
     </select>
 
 </mapper>

+ 70 - 40
distributed-print-business/src/main/resources/mapper/ExamTaskMapper.xml

@@ -106,7 +106,6 @@
                         and a.status = #{status}
                     </otherwise>
                 </choose>
-                and a.status = #{status}
             </if>
             <if test="cardRuleId != null and cardRuleId != ''">
                 and a.card_rule_id = #{cardRuleId}
@@ -318,48 +317,85 @@
     </select>
     <select id="listTaskReviewAudited" resultType="com.qmth.distributed.print.business.bean.dto.ExamTaskDto">
         SELECT
-            distinct a.id,
-            a.school_id schoolId,
-            a.course_code courseCode,
-            a.course_name courseName,
-            a.specialty,
-            a.paper_number paperNumber,
-            a.card_rule_id cardRuleId,
-            case a.card_rule_id when -1 then '全部通卡' else b.name end cardRuleName,
-            a.user_id userId,
-            c.real_name userName,
-            d.real_name createName,
-            a.start_time startTime,
-            a.end_time endTime,
-            f.status auditStatus,
-            a.review_status reviewStatus,
-            a.enable,
-            a.create_id createId,
-            a.create_time createTime,
-            a.status,
-            a.flow_id flowId,
-            f.setup,
-            f.status as flowStatus,
-            a.teacher_name teacherName,
-            a.lecturer_name lecturerName,
-            e.name teachingRoomName
+        distinct a.id,
+        a.school_id schoolId,
+        a.course_code courseCode,
+        a.course_name courseName,
+        a.specialty,
+        a.paper_number paperNumber,
+        a.card_rule_id cardRuleId,
+        case a.card_rule_id when -1 then '全部通卡' else b.name end cardRuleName,
+        a.user_id userId,
+        c.real_name userName,
+        d.real_name createName,
+        a.start_time startTime,
+        a.end_time endTime,
+        f.status auditStatus,
+        a.review_status reviewStatus,
+        a.enable,
+        a.create_id createId,
+        a.create_time createTime,
+        a.status,
+        a.flow_id flowId,
+        f.setup,
+        f.status as flowStatus,
+        a.teacher_name teacherName,
+        a.lecturer_name lecturerName,
+        e.name teachingRoomName
         FROM
-            exam_task a
+        exam_task a
         LEFT JOIN
-            basic_card_rule b ON a.card_rule_id = b.id
+        basic_card_rule b ON a.card_rule_id = b.id
         LEFT JOIN
-            sys_user c ON a.user_id = c.id
+        sys_user c ON a.user_id = c.id
         LEFT JOIN
-            sys_user d ON a.create_id = d.id
+        sys_user d ON a.create_id = d.id
         LEFT JOIN t_f_flow_approve f ON
-            a.flow_id = f.flow_id
+        a.flow_id = f.flow_id
         LEFT JOIN t_f_flow_approve_log tffal ON
-            a.flow_id = tffal.flow_id
+        a.flow_id = tffal.flow_id
         LEFT JOIN
-            sys_org e ON a.teaching_room_id = e.id
+        sys_org e ON a.teaching_room_id = e.id
         <where>
             a.enable = true and a.review = true
-            and EXISTS (select distinct t.PROC_INST_ID_ from ACT_HI_TASKINST t where t.TASK_DEF_KEY_ <![CDATA[ <> ]]> 'usertask1' and t.END_TIME_ is not null and t.PROC_INST_ID_ = a.flow_id)
+            and (f.status = 'AUDITING' or f.status = 'FINISH')
+            and EXISTS (
+            select
+            aht.PROC_INST_ID_
+            from
+            ACT_HI_TASKINST aht
+            where
+            aht.TASK_DEF_KEY_ <![CDATA[ <> ]]> 'usertask1'
+            and aht.ASSIGNEE_ = cast(#{currentUserId} as char)
+            and aht.END_TIME_ is not null
+            union all
+            select
+            t.PROC_INST_ID_
+            from
+            (
+            select
+            ahi.*
+            from
+            ACT_HI_IDENTITYLINK ahi
+            where
+            ahi.TYPE_ = 'candidate'
+            and exists(
+            select
+            distinct aht.id_
+            from
+            ACT_HI_TASKINST aht
+            where
+            aht.TASK_DEF_KEY_ <![CDATA[ <> ]]> 'usertask1'
+            and aht.ASSIGNEE_ is null
+            and aht.END_TIME_ is not null
+            and ahi.TASK_ID_ = aht.id_)
+            and ahi.USER_ID_ = cast(#{currentUserId} as char)) temp
+            join ACT_HI_TASKINST t on
+            t.ID_ = temp.TASK_ID_
+            join t_f_flow_approve_log tffal on
+            tffal.flow_id = t.PROC_INST_ID_
+            where (tffal.primary_approve_id = #{currentUserId} or tffal.second_approve_id = #{currentUserId})
+            and t.PROC_INST_ID_ = a.flow_id)
             <if test="schoolId != null and schoolId != ''">
                 and a.school_id = #{schoolId}
             </if>
@@ -393,12 +429,6 @@
             <if test="createName != null and createName != ''">
                 and d.real_name like concat('%',#{createName},'%')
             </if>
-            <if test="orgIds != null">
-                AND a.org_id IN
-                <foreach collection="orgIds" item="item" index="index" open="(" separator="," close=")">
-                    #{item}
-                </foreach>
-            </if>
         </where>
         order by a.create_time desc
     </select>

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

@@ -1,4 +1,44 @@
 <?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">
+    <select id="query" resultType="com.qmth.teachcloud.common.bean.result.SyncListResult">
+        SELECT
+            tbst.id,
+            tbst.type,
+            tbst.status,
+            tbst.result,
+            if(ISNULL(tbst.report_file_path),false,true) as hasReportFile,
+            tbst.error_message as errorMessage,
+            tbst.create_id as createId,
+            tbst.create_time as createTime,
+            su.real_name as createName
+        FROM
+            t_b_sync_task tbst
+                LEFT JOIN
+            sys_user su ON tbst.create_id = su.id
+        <where>
+            <if test="schoolId != null and schoolId != ''">
+                and tbst.school_id = #{schoolId}
+            </if>
+            <if test="status != null">
+                and tbst.status = #{status}
+            </if>
+            <if test="type != null">
+                and tbst.type = #{type}
+            </if>
+            <if test="result != null">
+                and tbst.result = #{result}
+            </if>
+            <if test="orgIds != null">
+                AND su.org_id IN
+                <foreach collection="orgIds" item="item" index="index" open="(" separator="," close=")">
+                    #{item}
+                </foreach>
+            </if>
+            <if test="orgIds == null and createId != null and createId != ''">
+                and tbst.create_id = #{createId}
+            </if>
+        </where>
+        order by tbst.create_time desc
+    </select>
 </mapper>

+ 93 - 0
distributed-print-business/src/main/resources/mapper/TSyncExamStudentScoreMapper.xml

@@ -0,0 +1,93 @@
+<?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.TSyncExamStudentScoreMapper">
+
+    <sql id="headCommonSql">
+         select
+            tsess.id,
+            bs.id as semesterId,
+            bs.name as semesterName,
+            tsess.exam_id as examId,
+            tsess.exam_code as examCode,
+            tsess.name,
+            tsess.student_code as studentCode,
+            tsess.exam_number as examNumber,
+            so.id as orgId,
+            so.name as orgName,
+            bm.id as majorId,
+            bm.name as majorName,
+            bc.id as clazz_id,
+            bc.clazz_name as clazzName,
+            tsess.subject_code as courseCode,
+            tsess.subject_name as courseName,
+            tsess.total_score as totalScore,
+            tsess.objective_score as objectiveScore,
+            tsess.subjective_score as subjectiveScore,
+            tsess.sheet_urls as sheetUrls,
+            tsess.status,
+            tsess.create_time as syncTime
+    </sql>
+
+    <sql id="middleCommonSql">
+        join basic_semester bs on
+            bs.id = tsess.semester_id
+        join basic_student bs2 on
+            bs2.student_code = tsess.student_code
+        join basic_clazz bc on
+            bc.id = tsess.clazz_id
+        join exam_student es on
+            es.student_code = tsess.student_code
+        join basic_major bm on
+            bm.id = tsess.major_id
+        join sys_org so on
+            so.id = tsess.org_id
+    </sql>
+
+    <sql id="footCommonSql">
+        <where>
+            <if test="schoolId != null and schoolId != ''">
+                and tsess.school_id = #{schoolId}
+            </if>
+            <if test="semesterId != null and semesterId != ''">
+                and tsess.semester_id = #{semesterId}
+            </if>
+            <if test="orgId != null and orgId != ''">
+                and tsess.org_id = #{orgId}
+            </if>
+            <if test="majorId != null and majorId != ''">
+                and tsess.major_id = #{majorId}
+            </if>
+            <if test="clazzId != null and clazzId != ''">
+                and tsess.clazz_id = #{clazzId}
+            </if>
+            <if test="courseCode != null and courseCode != ''">
+                and tsess.subject_code = #{courseCode}
+            </if>
+        </where>
+    </sql>
+
+    <select id="list" resultType="com.qmth.distributed.print.business.bean.result.TSyncExamStudentScoreResult">
+        <include refid="headCommonSql"/>
+        from
+        t_sync_exam_student_score tsess
+        <include refid="middleCommonSql"/>
+        <include refid="footCommonSql"/>
+    </select>
+
+    <select id="export" resultType="com.qmth.distributed.print.business.bean.result.TSyncExamStudentScoreResult">
+        <include refid="headCommonSql"/>
+        ,tsess.trajectory_urls as trajectoryUrls,
+        tsess.sync_data as trajectoryCoordinate,
+        tsess.sync_data as syncData
+        from
+        t_sync_exam_student_score tsess
+        <include refid="middleCommonSql"/>
+        <include refid="footCommonSql"/>
+    </select>
+
+    <select id="exportCount" resultType="java.lang.Integer">
+        select count(1) from t_sync_exam_student_score tsess
+        <include refid="middleCommonSql"/>
+        <include refid="footCommonSql"/>
+    </select>
+</mapper>

+ 2 - 2
distributed-print/pom.xml

@@ -4,13 +4,13 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.qmth.distributed.print</groupId>
     <artifactId>distributed-print</artifactId>
-    <version>2.2.0</version>
+    <version>2.2.1</version>
     <packaging>jar</packaging>
 
     <parent>
         <groupId>com.qmth.distributed.print.service</groupId>
         <artifactId>distributed-print-service</artifactId>
-        <version>2.2.0</version>
+        <version>2.2.1</version>
     </parent>
 
     <dependencies>

+ 1 - 1
distributed-print/src/main/java/com/qmth/distributed/print/api/BasicClazzController.java

@@ -57,7 +57,7 @@ public class BasicClazzController {
     @ApiOperation(value = "班级基本信息管理-新增/编辑")
     @RequestMapping(value = "/save", method = RequestMethod.POST)
     @ApiResponses({@ApiResponse(code = 200, message = "更新成功", response = EditResult.class)})
-    public Result saveBasicClazz(@Valid @RequestBody BasicClazzParams basicClazzParams, BindingResult bindingResult) {
+    public Result saveBasicClazz(@Valid @RequestBody BasicClazzParams basicClazzParams, BindingResult bindingResult) throws IllegalAccessException {
         if (bindingResult.hasErrors()) {
             return ResultUtil.error(bindingResult.getAllErrors().get(0).getDefaultMessage());
         }

+ 64 - 0
distributed-print/src/main/java/com/qmth/distributed/print/api/BasicMajorController.java

@@ -0,0 +1,64 @@
+package com.qmth.distributed.print.api;
+
+
+import com.qmth.boot.api.constant.ApiConstant;
+import com.qmth.teachcloud.common.bean.params.BasicMajorParams;
+import com.qmth.distributed.print.business.bean.result.EditResult;
+import com.qmth.teachcloud.common.entity.SysUser;
+import com.qmth.teachcloud.common.service.BasicMajorService;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.util.Result;
+import com.qmth.teachcloud.common.util.ResultUtil;
+import com.qmth.teachcloud.common.util.ServletUtil;
+import io.swagger.annotations.*;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+
+/**
+ * <p>
+ * 专业字典表 前端控制器
+ * </p>
+ *
+ * @author wangliang
+ * @since 2021-10-28
+ */
+@Api(tags = "专业管理controller")
+@RestController
+@RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + "/${prefix.url.basic}/major")
+public class BasicMajorController {
+    @Resource
+    private BasicMajorService basicMajorService;
+
+    @ApiOperation(value = "专业管理-查询")
+    @RequestMapping(value = "/query", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "查询成功", response = Result.class)})
+    public Result findBasicMajorList(@ApiParam(value = "专业名称") @RequestParam(required = false) String majorName,
+                                     @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) Integer pageNumber,
+                                     @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) Integer pageSize) {
+        Long schoolId = SystemConstant.convertIdToLong(ServletUtil.getRequestHeaderSchoolId().toString());
+        return ResultUtil.ok(basicMajorService.basicMajorPage(schoolId, majorName, pageNumber, pageSize));
+    }
+
+    @ApiOperation(value = "专业管理-新增/编辑")
+    @RequestMapping(value = "/save", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "更新成功", response = EditResult.class)})
+    public Result saveBasicMajor(@Valid @RequestBody BasicMajorParams basicMajorParams, BindingResult bindingResult) throws IllegalAccessException {
+        if (bindingResult.hasErrors()) {
+            return ResultUtil.error(bindingResult.getAllErrors().get(0).getDefaultMessage());
+        }
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        return ResultUtil.ok(basicMajorService.saveBasicMajor(basicMajorParams,sysUser));
+    }
+
+    @ApiOperation(value = "专业管理-删除(逻辑)")
+    @RequestMapping(value = "/delete", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "删除成功", response = EditResult.class)})
+    public Result deleteBasicMajor(@ApiParam(value = "专业id", required = true) @RequestParam String id) {
+        return ResultUtil.ok(basicMajorService.deleteBasicMajorById(SystemConstant.convertIdToLong(id)));
+    }
+}

+ 100 - 0
distributed-print/src/main/java/com/qmth/distributed/print/api/BasicMessageController.java

@@ -0,0 +1,100 @@
+package com.qmth.distributed.print.api;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.qmth.boot.api.constant.ApiConstant;
+import com.qmth.distributed.print.business.bean.result.EditResult;
+import com.qmth.distributed.print.business.entity.BasicMessage;
+import com.qmth.distributed.print.business.enums.MessageEnum;
+import com.qmth.distributed.print.business.service.BasicMessageService;
+import com.qmth.distributed.print.business.service.PrintCommonService;
+import com.qmth.distributed.print.business.templete.execute.AsyncCourseDataImportService;
+import com.qmth.teachcloud.common.bean.params.BasicCourseParams;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.BasicCourse;
+import com.qmth.teachcloud.common.entity.SysUser;
+import com.qmth.teachcloud.common.entity.TBTask;
+import com.qmth.teachcloud.common.enums.EnumResult;
+import com.qmth.teachcloud.common.enums.TaskTypeEnum;
+import com.qmth.teachcloud.common.service.BasicCourseService;
+import com.qmth.teachcloud.common.util.Result;
+import com.qmth.teachcloud.common.util.ResultUtil;
+import com.qmth.teachcloud.common.util.ServletUtil;
+import com.sun.org.apache.xpath.internal.operations.Bool;
+import io.swagger.annotations.*;
+import org.springframework.validation.BindingResult;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 短信发送日志 前端控制器
+ * </p>
+ *
+ * @author xf
+ */
+@Api(tags = "短信发送日志Controller")
+@RestController
+@RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + "/${prefix.url.basic}/message")
+@Validated
+public class BasicMessageController {
+
+    @Resource
+    private BasicMessageService basicMessageService;
+
+    /**
+     * 查询短信类型
+     *
+     * @return
+     */
+    @ApiOperation(value = "查询短信类型")
+    @RequestMapping(value = "/list_message_types", method = RequestMethod.POST)
+    public Result listType() {
+        List<EnumResult> list = basicMessageService.listMessageTypes();
+        return ResultUtil.ok(list);
+    }
+
+    /**
+     * 查询
+     *
+     * @param messageType
+     * @param pageNumber
+     * @param pageSize
+     * @return
+     */
+    @ApiOperation(value = "查询")
+    @RequestMapping(value = "/list", method = RequestMethod.POST)
+    public Result list(@RequestParam(value = "messageType", required = false) MessageEnum messageType,
+                       @RequestParam(value = "sendStatus", required = false) Boolean sendStatus,
+                       @RequestParam(value = "mobileNumber", required = false) String mobileNumber,
+                       @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) Integer pageNumber,
+                       @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) Integer pageSize) {
+        IPage<BasicMessage> messageIPage = basicMessageService.listByMessageType(messageType, sendStatus, mobileNumber, pageNumber, pageSize);
+        return ResultUtil.ok(messageIPage);
+    }
+
+    /**
+     * 短信失败重发
+     *
+     * @param id
+     * @return
+     */
+    @ApiOperation(value = "短信失败重发")
+    @RequestMapping(value = "/resend", method = RequestMethod.POST)
+    public Result list(@RequestParam(value = "id", required = false) Long id) {
+        basicMessageService.resendSmsTaskById(id);
+        return ResultUtil.ok(true, null);
+    }
+}
+

+ 86 - 0
distributed-print/src/main/java/com/qmth/distributed/print/api/BasicSemesterController.java

@@ -0,0 +1,86 @@
+package com.qmth.distributed.print.api;
+
+
+import com.qmth.boot.api.constant.ApiConstant;
+import com.qmth.distributed.print.business.bean.result.EditResult;
+import com.qmth.teachcloud.common.service.BasicSemesterService;
+import com.qmth.teachcloud.common.bean.params.BasicSemesterParams;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.util.Result;
+import com.qmth.teachcloud.common.util.ResultUtil;
+import com.qmth.teachcloud.common.util.ServletUtil;
+import io.swagger.annotations.*;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+
+/**
+ * <p>
+ * 学期字典表 前端控制器
+ * </p>
+ *
+ * @author wangliang
+ * @since 2021-10-28
+ */
+@Api(tags = "学期管理controller")
+@RestController
+@RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + "/${prefix.url.basic}/semester")
+public class BasicSemesterController {
+    @Resource
+    private BasicSemesterService basicSemesterService;
+
+    @ApiOperation(value = "学期管理-查询")
+    @RequestMapping(value = "/query", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "查询成功", response = Result.class)})
+    public Result findBasicSemesterList(@ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) Integer pageNumber,
+                                        @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) Integer pageSize) {
+        Long schoolId = SystemConstant.convertIdToLong(ServletUtil.getRequestHeaderSchoolId().toString());
+        return ResultUtil.ok(basicSemesterService.basicSemesterPage(schoolId,pageNumber,pageSize));
+    }
+
+    /**
+     * 模糊查询
+     * @param inUsed 1:只查询当前使用的学期  0:只查询不是当前使用的学期  null:查询所有
+     * @return
+     */
+    @ApiOperation(value = "学期模糊查询")
+    @RequestMapping(value = "/list", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "查询成功", response = Result.class)})
+    public Result list(@RequestParam(value = "inUsed", required = false) Boolean inUsed) {
+        Long schoolId = SystemConstant.convertIdToLong(ServletUtil.getRequestHeaderSchoolId().toString());
+        return ResultUtil.ok(basicSemesterService.list(schoolId, inUsed));
+    }
+
+    @ApiOperation(value = "学期管理-新增/编辑")
+    @RequestMapping(value = "/save", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "更新成功", response = EditResult.class)})
+    public Result saveBasicSemester(@Valid @RequestBody BasicSemesterParams basicSemesterParams, BindingResult bindingResult) throws IllegalAccessException {
+        if (bindingResult.hasErrors()) {
+            return ResultUtil.error(bindingResult.getAllErrors().get(0).getDefaultMessage());
+        }
+        return ResultUtil.ok(basicSemesterService.saveBasicSemester(basicSemesterParams));
+    }
+
+    @ApiOperation(value = "学期管理-删除(逻辑)")
+    @RequestMapping(value = "/delete", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "删除成功", response = EditResult.class)})
+    public Result deleteBasicSemester(@ApiParam(value = "学期id", required = true) @RequestParam String id) {
+        return ResultUtil.ok(basicSemesterService.deleteBasicSemesterById(SystemConstant.convertIdToLong(id)));
+    }
+
+    /**
+     * 设置为当前使用学期
+     * @param id
+     * @return
+     */
+    @ApiOperation(value = "学期管理-设置为当前使用学期")
+    @RequestMapping(value = "/set_in_used", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "更新成功", response = EditResult.class)})
+    public Result saveBasicSemester(@RequestParam("id") Long id) {
+        return ResultUtil.ok(basicSemesterService.setInUsed(id));
+    }
+}

+ 90 - 0
distributed-print/src/main/java/com/qmth/distributed/print/api/ExamPaperStructureController.java

@@ -0,0 +1,90 @@
+package com.qmth.distributed.print.api;
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.qmth.boot.api.constant.ApiConstant;
+import com.qmth.distributed.print.business.entity.ExamPaperStructure;
+import com.qmth.distributed.print.business.service.DataSyncService;
+import com.qmth.distributed.print.business.service.ExamPaperStructureService;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.util.Result;
+import com.qmth.teachcloud.common.util.ResultUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * 试卷结构 前端控制器
+ * </p>
+ *
+ * @author xf
+ */
+@Api(tags = "试卷结构Controller")
+@RestController
+@RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + "/${prefix.url.exam}/structure")
+public class ExamPaperStructureController {
+
+    @Autowired
+    private ExamPaperStructureService examPaperStructureService;
+
+    @Autowired
+    private DataSyncService dataSyncService;
+
+    /**
+     * 查询
+     *
+     * @return
+     */
+    @ApiOperation(value = "查询")
+    @RequestMapping(value = "/list", method = RequestMethod.POST)
+    public Result list(@RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) Integer pageNumber,
+                       @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) Integer pageSize) {
+        IPage<ExamPaperStructure> examPaperStructureIPage = examPaperStructureService.listByPropositionTeacherId(pageNumber, pageSize, null);
+        return ResultUtil.ok(examPaperStructureIPage);
+    }
+
+
+    /**
+     * 上传
+     *
+     * @param md5   文件md5
+     * @param files 文件数组
+     * @return
+     */
+    @ApiOperation(value = "上传试卷结构、标答")
+    @RequestMapping(value = "/upload", method = RequestMethod.POST)
+    public Result upload(@RequestParam("examPaperStructure") String examPaperStructure,
+                         @RequestParam("md5") String md5,
+                         @RequestParam("files") MultipartFile[] files) {
+        ExamPaperStructure examPaper = examPaperStructureService.upload(examPaperStructure, md5, files);
+        // 推送云阅卷
+        dataSyncService.syncPaperStructure(examPaper);
+        return ResultUtil.ok(String.valueOf(examPaper.getId()), null);
+    }
+
+    /**
+     * 试卷结构预览
+     *
+     * @param id id
+     * @return
+     */
+    @ApiOperation(value = "试卷结构预览")
+    @RequestMapping(value = "/preview_structure", method = RequestMethod.POST)
+    public Result preStructure(@RequestParam("id") Long id) {
+        List<Map> list = examPaperStructureService.preStructure(id);
+        return ResultUtil.ok(list);
+    }
+
+}
+

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

@@ -75,7 +75,8 @@ public class ExamPrintPlanController {
     @ApiOperation(value = "印刷计划查询")
     @RequestMapping(value = "/list", method = RequestMethod.POST)
     @ApiResponses({@ApiResponse(code = 200, message = "查询成功", response = Result.class)})
-    public Result findPrintPlanPage(@ApiParam(value = "印刷计划id集合") @RequestParam(required = false) List<String> printPlanIdList,
+    public Result findPrintPlanPage(@ApiParam(value = "学期ID") @RequestParam(required = false) Long semesterId,
+                                    @ApiParam(value = "印刷计划id集合") @RequestParam(required = false) List<String> printPlanIdList,
                                     @ApiParam(value = "印刷计划状态") @RequestParam(required = false) PrintPlanStatusEnum status,
                                     @ApiParam(value = "计划创建时间段开始时间") @RequestParam(required = false) Long startTime,
                                     @ApiParam(value = "计划创建时间段结束时间") @RequestParam(required = false) Long endTime,
@@ -87,7 +88,7 @@ public class ExamPrintPlanController {
             printPlanIdList = new ArrayList<>();
         }
         List<Long> idList = printPlanIdList.stream().map(SystemConstant::convertIdToLong).collect(Collectors.toList());
-        return ResultUtil.ok(examPrintPlanService.printPlanPage(schoolId, idList, status, startTime, endTime, pageNumber, pageSize));
+        return ResultUtil.ok(examPrintPlanService.printPlanPage(schoolId,semesterId, idList, status, startTime, endTime, pageNumber, pageSize));
     }
 
     @ApiOperation(value = "印刷计划模糊查询")

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

@@ -48,13 +48,14 @@ public class ExamPrintPlanSyncController {
     @ApiOperation(value = "印刷计划合并管理-计划查询")
     @RequestMapping(value = "/list_sync", method = RequestMethod.POST)
     @ApiResponses({@ApiResponse(code = 200, message = "查询成功", response = Result.class)})
-    public Result findPrintPlanPage(@ApiParam(value = "印刷计划ID") @RequestParam(required = false) Long printPlanId,
+    public Result findPrintPlanPage(@ApiParam(value = "学期ID") @RequestParam(required = false) Long semesterId,
+                                    @ApiParam(value = "印刷计划ID") @RequestParam(required = false) Long printPlanId,
                                     @ApiParam(value = "计划创建时间段开始时间") @RequestParam(required = false) Long startTime,
                                     @ApiParam(value = "计划创建时间段结束时间") @RequestParam(required = false) Long endTime,
                                     @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) Integer pageNumber,
                                     @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) Integer pageSize) {
         Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
-        return ResultUtil.ok(examPrintPlanService.printPlanSyncPage(schoolId, printPlanId, startTime, endTime, pageNumber, pageSize));
+        return ResultUtil.ok(examPrintPlanService.printPlanSyncPage(schoolId, semesterId, printPlanId, startTime, endTime, pageNumber, pageSize));
     }
 
     /**

+ 168 - 0
distributed-print/src/main/java/com/qmth/distributed/print/api/MenuCustomController.java

@@ -0,0 +1,168 @@
+package com.qmth.distributed.print.api;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.qmth.boot.api.constant.ApiConstant;
+import com.qmth.distributed.print.business.bean.params.TSchoolPrivilegeParam;
+import com.qmth.teachcloud.common.bean.dto.PrivilegeDto;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.*;
+import com.qmth.teachcloud.common.enums.PrivilegeEnum;
+import com.qmth.teachcloud.common.service.*;
+import com.qmth.teachcloud.common.util.Result;
+import com.qmth.teachcloud.common.util.ResultUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.security.NoSuchAlgorithmException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @Description: 菜单权限修改
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2021/10/29
+ */
+@Api(tags = "菜单权限修改Controller")
+@RestController
+@RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + "/${prefix.url.menu}")
+//@Aac(auth = BOOL.FALSE, strict = BOOL.FALSE)
+public class MenuCustomController {
+
+    @Resource
+    SysPrivilegeService sysPrivilegeService;
+
+    @Resource
+    TSchoolPrivilegeService tSchoolPrivilegeService;
+
+    @Resource
+    SysRolePrivilegeService sysRolePrivilegeService;
+
+    @Resource
+    SysRoleService sysRoleService;
+
+    @Resource
+    CommonCacheService commonCacheService;
+
+    @Resource
+    SysUserRoleService sysUserRoleService;
+
+    @Resource
+    TeachcloudCommonService commonService;
+
+    @ApiOperation(value = "查询自定义菜单权限")
+    @ApiResponses({@ApiResponse(code = 200, message = "菜单权限信息", response = SysPrivilege.class)})
+    @RequestMapping(value = "/custom/list", method = RequestMethod.POST)
+    public Result rolePrivilegeCountSync() {
+        QueryWrapper<SysPrivilege> sysPrivilegeQueryWrapper = new QueryWrapper<>();
+        sysPrivilegeQueryWrapper.lambda().eq(SysPrivilege::getEnable, true)
+                .eq(SysPrivilege::getEnable, true)
+                .eq(SysPrivilege::getDefaultAuth, false)
+                .ne(SysPrivilege::getType, PrivilegeEnum.URL)
+                .notIn(SysPrivilege::getId, SystemConstant.MENU_MANAGE);
+        List<SysPrivilege> sysPrivilegeList = sysPrivilegeService.list(sysPrivilegeQueryWrapper);
+        List<PrivilegeDto> privilegeDtoList = null;
+        if (Objects.nonNull(sysPrivilegeList) && sysPrivilegeList.size() > 0) {
+            Set<Long> privilegeIds = new HashSet<>();
+            Map<Long, SysPrivilege> sysPrivilegeMap = new HashMap<>();
+            for (SysPrivilege s : sysPrivilegeList) {
+                if (!Objects.equals(s.getType(), PrivilegeEnum.MENU)) {
+                    privilegeIds.add(s.getId());
+                }
+                sysPrivilegeMap.put(s.getId(), s);
+            }
+            for (Long l : privilegeIds) {
+                List<SysPrivilege> sysPrivileges = sysPrivilegeService.findByConnectByParentId(l);
+                for (SysPrivilege s : sysPrivileges) {
+                    sysPrivilegeMap.put(s.getId(), s);
+                }
+            }
+            privilegeDtoList = (List<PrivilegeDto>) sysPrivilegeService.getMenuTreeCommon(sysPrivilegeMap.values());
+        }
+        return ResultUtil.ok(privilegeDtoList);
+    }
+
+    @ApiOperation(value = "学校新增/修改自定义菜单权限")
+    @ApiResponses({@ApiResponse(code = 200, message = "常规信息", response = ResultUtil.class)})
+    @RequestMapping(value = "/custom/save", method = RequestMethod.POST)
+    @Transactional
+    public Result getRolePrivileges(@Valid @RequestBody TSchoolPrivilegeParam tSchoolPrivilegeParam, BindingResult bindingResult) throws NoSuchAlgorithmException {
+        if (bindingResult.hasErrors()) {
+            return ResultUtil.error(bindingResult.getAllErrors().get(0).getDefaultMessage());
+        }
+        Set<Long> roleSetIds = null;
+        QueryWrapper<TSchoolPrivilege> tSchoolPrivilegeQueryWrapper = new QueryWrapper<>();
+        tSchoolPrivilegeQueryWrapper.lambda().eq(TSchoolPrivilege::getSchoolId, tSchoolPrivilegeParam.getSchoolId());
+        List<TSchoolPrivilege> tSchoolPrivileges = tSchoolPrivilegeService.list(tSchoolPrivilegeQueryWrapper);
+        if (Objects.nonNull(tSchoolPrivileges) && tSchoolPrivileges.size() > 0) {//编辑
+            Set<Long> changePrivilegeSetIds = tSchoolPrivileges.stream().filter(s -> !Arrays.asList(tSchoolPrivilegeParam.getPrivilegeIds()).contains(s.getPrivilegeId()))
+                    .collect(Collectors.toList())
+                    .stream().map(s -> s.getPrivilegeId())
+                    .collect(Collectors.toSet());
+            //数据发生改变
+            if (changePrivilegeSetIds.size() > 0) {
+                List<SysPrivilege> sysPrivilegeList = sysPrivilegeService.listByIds(changePrivilegeSetIds);
+                sysPrivilegeList = sysPrivilegeList.stream().filter(s -> !Objects.equals(s.getType(), PrivilegeEnum.MENU)).collect(Collectors.toList());
+                changePrivilegeSetIds = sysPrivilegeList.stream().map(s -> s.getId()).collect(Collectors.toSet());
+
+                if (changePrivilegeSetIds.size() > 0) {
+                    //查询该菜单下所有角色,删除该角色所发生改变的菜单数据
+                    QueryWrapper<SysRole> sysRoleQueryWrapper = new QueryWrapper<>();
+                    sysRoleQueryWrapper.lambda().eq(SysRole::getSchoolId, tSchoolPrivilegeParam.getSchoolId());
+                    List<SysRole> sysRoleList = sysRoleService.list(sysRoleQueryWrapper);
+
+                    if (Objects.nonNull(sysRoleList) && sysRoleList.size() > 0) {
+                        QueryWrapper<SysRolePrivilege> sysRolePrivilegeQueryWrapper = new QueryWrapper<>();
+                        sysRolePrivilegeQueryWrapper.lambda()
+                                .in(SysRolePrivilege::getRoleId, sysRoleList.stream().map(s -> s.getId()).collect(Collectors.toList()))
+                                .in(SysRolePrivilege::getPrivilegeId, changePrivilegeSetIds);
+                        List<SysRolePrivilege> sysRolePrivilegeList = sysRolePrivilegeService.list(sysRolePrivilegeQueryWrapper);
+                        //仅删除绑定了该权限的角色用户缓存
+                        roleSetIds = sysRolePrivilegeList.stream().map(s -> s.getRoleId()).collect(Collectors.toSet());
+                        sysRolePrivilegeService.remove(sysRolePrivilegeQueryWrapper);
+                    }
+                }
+            }
+            tSchoolPrivilegeService.remove(tSchoolPrivilegeQueryWrapper);
+        }
+        Long[] privilegeIds = tSchoolPrivilegeParam.getPrivilegeIds();
+        if (Objects.nonNull(privilegeIds) && privilegeIds.length > 0) {
+            List<TSchoolPrivilege> tSchoolPrivilegeList = new ArrayList<>();
+            for (int i = 0; i < privilegeIds.length; i++) {
+                tSchoolPrivilegeList.add(new TSchoolPrivilege(tSchoolPrivilegeParam.getSchoolId(), privilegeIds[i]));
+            }
+            tSchoolPrivilegeService.saveBatch(tSchoolPrivilegeList);
+        }
+
+        //清缓存
+        if (Objects.nonNull(roleSetIds) && roleSetIds.size() > 0) {
+            for (Long l : roleSetIds) {
+                commonCacheService.updateRoleCache(l);
+                commonCacheService.updateRolePrivilegeCache(l);
+                //绑定该角色的用户都需要清除鉴权缓存
+                List<SysUserRole> sysUserRoleList = sysUserRoleService.listByRoleId(l);
+                for (SysUserRole s : sysUserRoleList) {
+                    commonService.removeUserInfo(s.getUserId(), true);
+                }
+            }
+        }
+        return ResultUtil.ok(true);
+    }
+
+    @ApiOperation(value = "学校已绑定自定义菜单权限列表")
+    @ApiResponses({@ApiResponse(code = 200, message = "常规信息", response = ResultUtil.class)})
+    @RequestMapping(value = "/custom/get_school_custom_privileges", method = RequestMethod.POST)
+    public Result getRolePrivileges(@RequestParam(value = "schoolId", required = true) Long schoolId) {
+        List<TSchoolPrivilege> tSchoolPrivilegeList = tSchoolPrivilegeService.findBySchoolId(schoolId);
+        return ResultUtil.ok(tSchoolPrivilegeList.stream().map(s -> String.valueOf(s.getPrivilegeId())).collect(Collectors.toList()));
+    }
+}

+ 56 - 0
distributed-print/src/main/java/com/qmth/distributed/print/api/SsoController.java

@@ -0,0 +1,56 @@
+package com.qmth.distributed.print.api;
+
+
+import com.qmth.boot.api.constant.ApiConstant;
+import com.qmth.distributed.print.business.service.SsoService;
+import com.qmth.teachcloud.common.util.Result;
+import com.qmth.teachcloud.common.util.ResultUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+
+/**
+ * <p>
+ * 单点登录 前端控制器
+ * </p>
+ *
+ * @author xf
+ */
+@Api(tags = "单点登录Controller")
+@RestController
+@RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + "/${prefix.url.exam}/sso")
+public class SsoController {
+
+    @Autowired
+    SsoService ssoService;
+
+    /**
+     * 评卷员单点登录
+     *
+     * @return
+     */
+    @ApiOperation(value = "评卷员单点登录")
+    @RequestMapping(value = "/marker_login", method = RequestMethod.POST)
+    public Result markerLogin() {
+        Map<String, Object> map = ssoService.markerLoginInfo();
+        return ResultUtil.ok(map);
+    }
+
+    /**
+     * 评卷员单点登录
+     *
+     * @return
+     */
+    @ApiOperation(value = "评卷员单点登录")
+    @RequestMapping(value = "/marker_leader_login", method = RequestMethod.POST)
+    public Result markerLeaderLogin() {
+        Map<String, Object> map = ssoService.markerLeaderLoginInfo();
+        return ResultUtil.ok(map);
+    }
+}
+

+ 209 - 56
distributed-print/src/main/java/com/qmth/distributed/print/api/SysController.java

@@ -1,16 +1,20 @@
 package com.qmth.distributed.print.api;
 
-import cn.hutool.core.date.DateUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 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.params.LoginParam;
+import com.qmth.distributed.print.business.bean.result.DictionaryResult;
 import com.qmth.distributed.print.business.bean.result.EditResult;
-import com.qmth.distributed.print.business.enums.SystemCodeEnum;
+import com.qmth.distributed.print.business.entity.ExamPrintPlan;
+import com.qmth.distributed.print.business.entity.TBSyncTask;
+import com.qmth.distributed.print.business.enums.DictionaryEnum;
 import com.qmth.distributed.print.business.service.BasicVerifyCodeService;
+import com.qmth.distributed.print.business.service.ExamPrintPlanService;
 import com.qmth.distributed.print.business.service.PrintCommonService;
+import com.qmth.distributed.print.business.service.TBSyncTaskService;
 import com.qmth.teachcloud.common.bean.auth.AuthBean;
 import com.qmth.teachcloud.common.bean.result.LoginResult;
 import com.qmth.teachcloud.common.bean.result.UserLoginCheckResult;
@@ -18,17 +22,15 @@ import com.qmth.teachcloud.common.config.DictionaryConfig;
 import com.qmth.teachcloud.common.contant.SystemConstant;
 import com.qmth.teachcloud.common.entity.*;
 import com.qmth.teachcloud.common.enums.*;
+import com.qmth.teachcloud.common.enums.userPush.SpecialPrivilegeEnum;
 import com.qmth.teachcloud.common.service.*;
-import com.qmth.teachcloud.common.util.ConvertUtil;
 import com.qmth.teachcloud.common.util.Result;
 import com.qmth.teachcloud.common.util.ResultUtil;
 import com.qmth.teachcloud.common.util.ServletUtil;
 import io.swagger.annotations.*;
-import org.apache.catalina.User;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.BindingResult;
 import org.springframework.web.bind.annotation.*;
@@ -37,10 +39,7 @@ import org.springframework.web.multipart.MultipartFile;
 import javax.annotation.Resource;
 import javax.validation.Valid;
 import java.security.NoSuchAlgorithmException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -52,14 +51,14 @@ import java.util.stream.Collectors;
 public class SysController {
     private final static Logger log = LoggerFactory.getLogger(SysController.class);
 
-    @Autowired
-    private SysUserService sysUserService;
+    @Resource
+    SysUserService sysUserService;
 
-    @Autowired
-    private BasicVerifyCodeService basicVerifyCodeService;
+    @Resource
+    BasicVerifyCodeService basicVerifyCodeService;
 
-    @Autowired
-    private DictionaryConfig dictionaryConfig;
+    @Resource
+    DictionaryConfig dictionaryConfig;
 
     @Resource
     CommonCacheService commonCacheService;
@@ -73,23 +72,35 @@ public class SysController {
     @Resource
     BasicAttachmentService basicAttachmentService;
 
-    @Autowired
-    private SysConfigService sysConfigService;
-
-    @Autowired
-    private SysUserRoleService sysUserRoleService;
+    @Resource
+    SysUserRoleService sysUserRoleService;
 
     @Resource
     TeachcloudCommonService teachcloudCommonService;
 
     @Resource
-    ConvertUtil convertUtil;
+    SysOrgService sysOrgService;
 
     @Resource
-    BasicCampusService basicCampusService;
+    BasicMajorService basicMajorService;
+
+    @Resource
+    BasicClazzService basicClazzService;
 
     @Resource
-    BasicCourseService basicCourseService;
+    BasicStudentService basicStudentService;
+
+    @Resource
+    BasicSemesterService basicSemesterService;
+
+    @Resource
+    ExamPrintPlanService examPrintPlanService;
+
+    @Resource
+    TBSyncTaskService tbSyncTaskService;
+
+    @Resource
+    BasicCampusService basicCampusService;
 
     /**
      * 登录
@@ -266,21 +277,29 @@ public class SysController {
     @ApiResponses({@ApiResponse(code = 200, message = "返回信息", response = EditResult.class)})
     public Result fileDownload(@ApiParam(value = "任务id", required = true) @RequestParam String id,
                                @ApiParam(value = "下载文件类型", required = true) @RequestParam DownloadFileEnum type) {
-        TBTask tbTask = tbTaskService.getById(Long.parseLong(id));
-        if (Objects.isNull(tbTask)) {
-            throw ExceptionResultEnum.TASK_NO_DATA.exception();
-        }
         String path = null;
-        switch (type.ordinal()) {
-            case 0:
-                path = tbTask.getImportFilePath();
-                break;
-            case 1:
-                path = tbTask.getReportFilePath();
-                break;
-            default:
-                path = tbTask.getResultFilePath();
-                break;
+        if (DownloadFileEnum.SYNC_REPORT.equals(type)) {
+            TBSyncTask tbSyncTask = tbSyncTaskService.getById(SystemConstant.convertIdToLong(id));
+            if (Objects.isNull(tbSyncTask)) {
+                throw ExceptionResultEnum.SYNC_TASK_NO_DATA.exception();
+            }
+            path = tbSyncTask.getReportFilePath();
+        } else {
+            TBTask tbTask = tbTaskService.getById(Long.parseLong(id));
+            if (Objects.isNull(tbTask)) {
+                throw ExceptionResultEnum.TASK_NO_DATA.exception();
+            }
+            switch (type) {
+                case IMPORT_FILE:
+                    path = tbTask.getImportFilePath();
+                    break;
+                case TASK_REPORT:
+                    path = tbTask.getReportFilePath();
+                    break;
+                case RESULT:
+                    path = tbTask.getResultFilePath();
+                    break;
+            }
         }
         if (Objects.isNull(path)) {
             throw ExceptionResultEnum.PATH_NO_DATA.exception();
@@ -318,25 +337,159 @@ public class SysController {
 //    @Aac(auth = BOOL.FALSE)
     public Result getCode(@ApiParam(value = "编码类型", required = true) @RequestParam SystemCodeEnum type) {
         SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
-        Long schoolId = sysUser.getSchoolId();
-        String date = DateUtil.today().replace("-", "");
-        String paperNumber = "";
-        int count = 0;
-        do {
-            paperNumber = convertUtil.getIncre(date, type.getModel() + schoolId, type.getDigit());
-            switch (type) {
-                case CAMPUS_CODE:
-                    count = basicCampusService.count(new QueryWrapper<BasicCampus>().lambda()
-                            .eq(BasicCampus::getCampusCode, paperNumber)
-                            .eq(BasicCampus::getSchoolId, schoolId));
-                    break;
-                case COURSE_CODE:
-                    count = basicCourseService.count(new QueryWrapper<BasicCourse>().lambda()
-                            .eq(BasicCourse::getCode, paperNumber)
-                            .eq(BasicCourse::getSchoolId, schoolId));
-                    break;
+        String number = teachcloudCommonService.getSysIncrCode(type, sysUser);
+        return ResultUtil.ok((Object) number);
+    }
+
+    @ApiOperation(value = "共用接口-查询字典")
+    @RequestMapping(value = "/get_dictionary", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "查询成功", response = Result.class)})
+    public Result findDictionaryList(@ApiParam(value = "校区id") @RequestParam(required = false) String campusId,
+                                     @ApiParam(value = "学期id") @RequestParam(required = false) String semesterId,
+                                     @ApiParam(value = "学院id") @RequestParam(required = false) String collegeId,
+                                     @ApiParam(value = "专业id") @RequestParam(required = false) String majorId,
+                                     @ApiParam(value = "班级id") @RequestParam(required = false) String clazzId,
+                                     @ApiParam(value = "学生id") @RequestParam(required = false) String studentId,
+                                     @ApiParam(value = "查询字典对象") @RequestParam(required = true) DictionaryEnum dictionaryEnum) {
+        Long schoolId = SystemConstant.convertIdToLong(ServletUtil.getRequestHeaderSchoolId().toString());
+        List<DictionaryResult> dictionaryResultList = new ArrayList<>();
+        switch (dictionaryEnum) {
+            case CAMPUS:
+                List<BasicCampus> basicCampusList = basicCampusService.list(new QueryWrapper<BasicCampus>().lambda().eq(BasicCampus::getSchoolId, schoolId));
+                dictionaryResultList = basicCampusList.stream().map(e -> {
+                    DictionaryResult dictionaryResult = new DictionaryResult();
+                    dictionaryResult.setName(e.getCampusName());
+                    dictionaryResult.setCode(e.getCampusCode());
+                    dictionaryResult.setId(e.getId());
+                    return dictionaryResult;
+                }).collect(Collectors.toList());
+                break;
+            case SEMESTER:
+                List<BasicSemester> basicSemesterList = basicSemesterService.list(new QueryWrapper<BasicSemester>().lambda().eq(BasicSemester::getSchoolId, schoolId).eq(BasicSemester::getEnable, true));
+                dictionaryResultList = basicSemesterList.stream().map(e -> {
+                    DictionaryResult dictionaryResult = new DictionaryResult();
+                    dictionaryResult.setId(e.getId());
+                    dictionaryResult.setCode(e.getCode());
+                    dictionaryResult.setName(e.getName());
+                    return dictionaryResult;
+                }).collect(Collectors.toList());
+                break;
+            case COLLEGE:
+                if (Objects.nonNull(semesterId)) {
+                    QueryWrapper<ExamPrintPlan> examPrintPlanQueryWrapper = new QueryWrapper<>();
+                    examPrintPlanQueryWrapper.select(" DISTINCT org_id as orgId ")
+                            .eq("semester_id", SystemConstant.convertIdToLong(semesterId));
+                    List<ExamPrintPlan> examPrintPlanList = examPrintPlanService.list(examPrintPlanQueryWrapper);
+                    if (Objects.nonNull(examPrintPlanList) && examPrintPlanList.size() > 0) {
+                        Set<Long> orgIdSet = examPrintPlanList.stream().map(s -> s.getOrgId()).collect(Collectors.toSet());
+                        QueryWrapper<SysOrg> sysOrgQueryWrapper = new QueryWrapper<>();
+                        sysOrgQueryWrapper.lambda().in(SysOrg::getId, orgIdSet);
+                        List<SysOrg> sysOrgList = sysOrgService.list(sysOrgQueryWrapper);
+                        dictionaryResultList = sysOrgList.stream().map(e -> {
+                            DictionaryResult dictionaryResult = new DictionaryResult();
+                            dictionaryResult.setId(e.getId());
+                            dictionaryResult.setCode(e.getCode());
+                            dictionaryResult.setName(e.getName());
+                            return dictionaryResult;
+                        }).collect(Collectors.toList());
+                    }
+                } else {
+                    List<SysOrg> sysOrgList = sysOrgService.list(new QueryWrapper<SysOrg>().lambda().eq(SysOrg::getSchoolId, schoolId).eq(SysOrg::getEnable, true));
+                    dictionaryResultList = sysOrgList.stream().map(e -> {
+                        DictionaryResult dictionaryResult = new DictionaryResult();
+                        dictionaryResult.setId(e.getId());
+                        dictionaryResult.setCode(e.getCode());
+                        dictionaryResult.setName(e.getName());
+                        return dictionaryResult;
+                    }).collect(Collectors.toList());
+                }
+                break;
+            case MAJOR:
+                QueryWrapper<BasicMajor> majorQueryWrapper = new QueryWrapper<>();
+                majorQueryWrapper.lambda()
+                        .eq(BasicMajor::getSchoolId, schoolId)
+                        .eq(BasicMajor::getEnable, true);
+
+                if (SystemConstant.longNotNull(SystemConstant.convertIdToLong(collegeId))) {
+                    majorQueryWrapper.lambda().eq(BasicMajor::getBelongOrgId, collegeId);
+                }
+                List<BasicMajor> basicMajorList = basicMajorService.list(majorQueryWrapper);
+                dictionaryResultList = basicMajorList.stream().map(e -> {
+                    DictionaryResult dictionaryResult = new DictionaryResult();
+                    dictionaryResult.setId(e.getId());
+                    dictionaryResult.setCode(e.getCode());
+                    dictionaryResult.setName(e.getName());
+                    return dictionaryResult;
+                }).collect(Collectors.toList());
+                break;
+            case CLAZZ:
+                QueryWrapper<BasicClazz> clazzQueryWrapper = new QueryWrapper<>();
+                clazzQueryWrapper.lambda().eq(BasicClazz::getSchoolId, schoolId).eq(BasicClazz::getEnable, true);
+                if (SystemConstant.longNotNull(SystemConstant.convertIdToLong(campusId))) {
+                    clazzQueryWrapper.lambda().eq(BasicClazz::getCampusId, campusId);
+                }
+                if (SystemConstant.longNotNull(SystemConstant.convertIdToLong(majorId))) {
+                    clazzQueryWrapper.lambda().eq(BasicClazz::getMajorId, majorId);
+                }
+                List<BasicClazz> basicClazzList = basicClazzService.list(clazzQueryWrapper);
+                dictionaryResultList = basicClazzList.stream().map(e -> {
+                    DictionaryResult dictionaryResult = new DictionaryResult();
+                    dictionaryResult.setId(e.getId());
+                    dictionaryResult.setCode(e.getClazzCode());
+                    dictionaryResult.setName(e.getClazzName());
+                    return dictionaryResult;
+                }).collect(Collectors.toList());
+                break;
+            case STUDENT:
+                QueryWrapper<BasicStudent> studentQueryWrapper = new QueryWrapper<>();
+                studentQueryWrapper.lambda().eq(BasicStudent::getSchoolId, schoolId).eq(BasicStudent::getEnable, true);
+                if (SystemConstant.longNotNull(SystemConstant.convertIdToLong(campusId))) {
+                    studentQueryWrapper.lambda().eq(BasicStudent::getCampusId, campusId);
+                }
+                if (SystemConstant.longNotNull(SystemConstant.convertIdToLong(collegeId))) {
+                    studentQueryWrapper.lambda().eq(BasicStudent::getBelongOrgId, collegeId);
+                }
+                if (SystemConstant.longNotNull(SystemConstant.convertIdToLong(majorId))) {
+                    studentQueryWrapper.lambda().eq(BasicStudent::getMajorId, majorId);
+                }
+                if (SystemConstant.longNotNull(SystemConstant.convertIdToLong(clazzId))) {
+                    studentQueryWrapper.lambda().eq(BasicStudent::getClazzId, clazzId);
+                }
+                if (SystemConstant.longNotNull(SystemConstant.convertIdToLong(studentId))) {
+                    studentQueryWrapper.lambda().eq(BasicStudent::getId, studentId);
+                }
+                List<BasicStudent> basicStudentList = basicStudentService.list(studentQueryWrapper);
+                dictionaryResultList = basicStudentList.stream().map(e -> {
+                    DictionaryResult dictionaryResult = new DictionaryResult();
+                    dictionaryResult.setId(e.getId());
+                    dictionaryResult.setCode(e.getStudentCode());
+                    dictionaryResult.setName(e.getStudentName());
+                    return dictionaryResult;
+                }).collect(Collectors.toList());
+                break;
+        }
+        return ResultUtil.ok(dictionaryResultList);
+    }
+
+    /**
+     * 获取用户阅卷角色
+     *
+     * @return
+     */
+    @ApiOperation(value = "获取用户阅卷角色")
+    @RequestMapping(value = "/get_open_role", method = RequestMethod.POST)
+    public Result getOpenRole() {
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        SpecialPrivilegeEnum userSpecialPrivilege = sysUserService.findUserSpecialPrivilegeByUserId(sysUser.getId());
+        List<SpecialPrivilegeEnum> list = new ArrayList<>();
+        if (!SpecialPrivilegeEnum.UNIDENTIFIED.equals(userSpecialPrivilege)) {
+            if (SpecialPrivilegeEnum.COMPOSITE.equals(userSpecialPrivilege)) {
+                list.add(SpecialPrivilegeEnum.MARKER);
+                list.add(SpecialPrivilegeEnum.SUBJECT_HEADER);
+            } else {
+                list.add(userSpecialPrivilege);
             }
-        } while (count > 0);
-        return ResultUtil.ok((Object) paperNumber);
+        }
+        return ResultUtil.ok(list);
     }
 }

+ 20 - 2
distributed-print/src/main/java/com/qmth/distributed/print/api/SysUserController.java

@@ -4,12 +4,15 @@ import com.qmth.boot.api.annotation.Aac;
 import com.qmth.boot.api.annotation.BOOL;
 import com.qmth.boot.api.constant.ApiConstant;
 import com.qmth.distributed.print.business.bean.result.EditResult;
+import com.qmth.distributed.print.business.entity.TBSyncTask;
 import com.qmth.distributed.print.business.service.PrintCommonService;
 import com.qmth.distributed.print.business.templete.execute.AsyncSysUserDataImportService;
+import com.qmth.distributed.print.business.templete.execute.AsyncUserPushService;
 import com.qmth.teachcloud.common.bean.params.UserSaveParams;
 import com.qmth.teachcloud.common.contant.SystemConstant;
 import com.qmth.teachcloud.common.entity.SysUser;
 import com.qmth.teachcloud.common.entity.TBTask;
+import com.qmth.teachcloud.common.enums.PushTypeEnum;
 import com.qmth.teachcloud.common.enums.TaskTypeEnum;
 import com.qmth.teachcloud.common.service.SysUserService;
 import com.qmth.teachcloud.common.util.Result;
@@ -54,6 +57,8 @@ public class SysUserController {
     private PrintCommonService printCommonService;
     @Resource
     private AsyncSysUserDataImportService asyncSysUserDataImportService;
+    @Resource
+    private AsyncUserPushService asyncUserPushService;
 
     /**
      * 查询
@@ -112,7 +117,7 @@ public class SysUserController {
      */
     @ApiOperation(value = "新增/修改")
     @RequestMapping(value = "/save", method = RequestMethod.POST)
-    public Result save(@ApiParam(value = "用户信息", required = true) @Valid @RequestBody UserSaveParams userSaveParams, BindingResult bindingResult) {
+    public Result save(@ApiParam(value = "用户信息", required = true) @Valid @RequestBody UserSaveParams userSaveParams, BindingResult bindingResult) throws IllegalAccessException {
         if (bindingResult.hasErrors()) {
             return ResultUtil.error(bindingResult.getAllErrors().get(0).getDefaultMessage());
         }
@@ -142,7 +147,7 @@ public class SysUserController {
      */
     @ApiOperation(value = "启用/禁用")
     @RequestMapping(value = "/enable", method = RequestMethod.POST)
-    public Result enable(@RequestBody SysUser user) throws NoSuchAlgorithmException {
+    public Result enable(@RequestBody SysUser user) throws NoSuchAlgorithmException, IllegalAccessException {
         return ResultUtil.ok(sysUserService.enable(user));
     }
 
@@ -194,5 +199,18 @@ public class SysUserController {
         TBTask tbTask = Objects.nonNull(map.get(SystemConstant.TASK)) ? (TBTask) map.get(SystemConstant.TASK) : null;
         return Objects.nonNull(tbTask) ? ResultUtil.ok(tbTask.getId()) : ResultUtil.error("创建任务失败");
     }
+
+    @ApiOperation(value = "用户管理-用户推送(异步)")
+    @RequestMapping(value = "/push", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "返回信息", response = EditResult.class)})
+    public Result sysUserPush() throws Exception {
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        Map<String, Object> map = printCommonService.savePush(PushTypeEnum.USER_PUSH);
+        map.put(SystemConstant.SYS_USER, sysUser);
+
+        asyncUserPushService.pushTask(map);
+        TBSyncTask tbSyncTask = Objects.nonNull(map.get(SystemConstant.TB_SYNC_TASK)) ? (TBSyncTask) map.get(SystemConstant.TB_SYNC_TASK) : null;
+        return Objects.nonNull(tbSyncTask) ? ResultUtil.ok(tbSyncTask.getId()) : ResultUtil.error("创建同步推送任务失败");
+    }
 }
 

+ 55 - 0
distributed-print/src/main/java/com/qmth/distributed/print/api/TBSyncTaskController.java

@@ -0,0 +1,55 @@
+package com.qmth.distributed.print.api;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.qmth.boot.api.constant.ApiConstant;
+import com.qmth.distributed.print.business.service.TBSyncTaskService;
+import com.qmth.teachcloud.common.bean.result.SyncListResult;
+import com.qmth.teachcloud.common.bean.result.TaskListResult;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.enums.PushTypeEnum;
+import com.qmth.teachcloud.common.enums.TaskResultEnum;
+import com.qmth.teachcloud.common.enums.TaskStatusEnum;
+import com.qmth.teachcloud.common.util.Result;
+import com.qmth.teachcloud.common.util.ResultUtil;
+import com.qmth.teachcloud.common.util.ServletUtil;
+import io.swagger.annotations.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+
+/**
+ * @Description: 同步任务管理-前端控制器
+ * @Author: CaoZixuan
+ * @Date: 2021-11-08
+ */
+@Api(tags = "数据管理-任务管理Controller")
+@RestController
+@RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + "/${prefix.url.data}")
+@Validated
+public class TBSyncTaskController {
+    private final static Logger log = LoggerFactory.getLogger(TBSyncTaskController.class);
+
+    @Resource
+    TBSyncTaskService tbSyncTaskService;
+
+    @ApiOperation(value = "同步管理查询接口")
+    @RequestMapping(value = "/sync/query", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "任务管理列表信息", response = TaskListResult.class)})
+    public Result syncQuery(@ApiParam(value = "任务状态") @RequestParam(required = false) TaskStatusEnum status,
+                            @ApiParam(value = "同步类型") @RequestParam(required = false) PushTypeEnum type,
+                            @ApiParam(value = "同步数据结果") @RequestParam(required = false) TaskResultEnum result,
+                            @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) Integer pageNumber,
+                            @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) Integer pageSize) {
+        Long schoolId = SystemConstant.convertIdToLong(String.valueOf(ServletUtil.getRequestHeaderSchoolId()));
+        IPage<SyncListResult> page = tbSyncTaskService.query(schoolId,status,type,result,pageNumber,pageSize);
+        return ResultUtil.ok(page);
+    }
+}

+ 205 - 0
distributed-print/src/main/java/com/qmth/distributed/print/api/TSyncExamStudentScoreController.java

@@ -0,0 +1,205 @@
+package com.qmth.distributed.print.api;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.qmth.boot.api.constant.ApiConstant;
+import com.qmth.distributed.print.business.bean.result.EditResult;
+import com.qmth.distributed.print.business.bean.result.TSyncExamStudentScoreResult;
+import com.qmth.distributed.print.business.entity.ExamPrintPlan;
+import com.qmth.distributed.print.business.entity.TBSyncTask;
+import com.qmth.distributed.print.business.entity.TSyncExamStudentScore;
+import com.qmth.distributed.print.business.enums.ImageTrajectoryEnum;
+import com.qmth.distributed.print.business.service.ExamPrintPlanService;
+import com.qmth.distributed.print.business.service.PrintCommonService;
+import com.qmth.distributed.print.business.service.TSyncExamStudentScoreService;
+import com.qmth.distributed.print.business.templete.execute.AsyncScoreBatchDownloadService;
+import com.qmth.distributed.print.business.templete.execute.AsyncScoreExportService;
+import com.qmth.distributed.print.business.templete.execute.AsyncScorePushService;
+import com.qmth.teachcloud.common.config.DictionaryConfig;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.SysUser;
+import com.qmth.teachcloud.common.entity.TBTask;
+import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
+import com.qmth.teachcloud.common.enums.PushTypeEnum;
+import com.qmth.teachcloud.common.enums.TaskTypeEnum;
+import com.qmth.teachcloud.common.service.BasicClazzService;
+import com.qmth.teachcloud.common.service.SysOrgService;
+import com.qmth.teachcloud.common.util.Result;
+import com.qmth.teachcloud.common.util.ResultUtil;
+import com.qmth.teachcloud.common.util.ServletUtil;
+import io.swagger.annotations.*;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * <p>
+ * 同步考生成绩表 前端控制器
+ * </p>
+ *
+ * @author wangliang
+ * @since 2021-10-28
+ */
+@Api(tags = "成绩归档Controller")
+@RestController
+@RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + "/${prefix.url.sync}")
+//@Aac(auth = BOOL.FALSE, strict = BOOL.FALSE)
+@Validated
+public class TSyncExamStudentScoreController {
+
+    @Resource
+    TSyncExamStudentScoreService tSyncExamStudentScoreService;
+
+    @Resource
+    PrintCommonService printCommonService;
+
+    @Resource
+    AsyncScoreExportService asyncScoreExportService;
+
+    @Resource
+    DictionaryConfig dictionaryConfig;
+
+    @Resource
+    AsyncScorePushService asyncScorePushService;
+
+    @Resource
+    AsyncScoreBatchDownloadService asyncScoreBatchDownloadService;
+
+    @Resource
+    ExamPrintPlanService examPrintPlanService;
+
+    @Resource
+    SysOrgService sysOrgService;
+
+    @Resource
+    BasicClazzService basicClazzService;
+
+    @ApiOperation(value = "成绩归档查询列表")
+    @ApiResponses({@ApiResponse(code = 200, message = "成绩查询信息", response = TSyncExamStudentScoreResult.class)})
+    @RequestMapping(value = "/score/list", method = RequestMethod.POST)
+    public Result list(@ApiParam(value = "学期id", required = true) @RequestParam String semesterId,
+                       @ApiParam(value = "学院id", required = false) @RequestParam(required = false) String orgId,
+                       @ApiParam(value = "专业id", required = false) @RequestParam(required = false) String majorId,
+                       @ApiParam(value = "班级id", required = false) @RequestParam(required = false) String clazzId,
+                       @ApiParam(value = "课程编码", required = false) @RequestParam(required = false) String courseCode,
+                       @ApiParam(value = "页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) Integer pageNumber,
+                       @ApiParam(value = "数量", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) Integer pageSize) {
+        return ResultUtil.ok(tSyncExamStudentScoreService.list(new Page<>(pageNumber, pageSize),
+                SystemConstant.convertIdToLong(semesterId),
+                SystemConstant.convertIdToLong(orgId),
+                SystemConstant.convertIdToLong(majorId),
+                SystemConstant.convertIdToLong(clazzId),
+                courseCode));
+    }
+
+    @ApiOperation(value = "成绩导出")
+    @ApiResponses({@ApiResponse(code = 200, message = "同步信息", response = TBTask.class)})
+    @RequestMapping(value = "/score/export", method = RequestMethod.POST)
+    public Result export(@ApiParam(value = "学期id", required = true) @RequestParam String semesterId,
+                         @ApiParam(value = "学院id", required = false) @RequestParam(required = false) String orgId,
+                         @ApiParam(value = "专业id", required = false) @RequestParam(required = false) String majorId,
+                         @ApiParam(value = "班级id", required = false) @RequestParam(required = false) String clazzId,
+                         @ApiParam(value = "课程编码", required = false) @RequestParam(required = false) String courseCode) {
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        int count = tSyncExamStudentScoreService.exportCount(sysUser.getSchoolId()
+                , SystemConstant.convertIdToLong(semesterId)
+                , SystemConstant.convertIdToLong(orgId)
+                , SystemConstant.convertIdToLong(majorId)
+                , SystemConstant.convertIdToLong(clazzId), courseCode);
+        if (count == 0) {
+            throw ExceptionResultEnum.ERROR.exception("没有成绩信息");
+        }
+        Map<String, Object> map = printCommonService.saveTask(TaskTypeEnum.SCORE_EXPORT);
+        map.computeIfAbsent("semesterId", v -> SystemConstant.convertIdToLong(semesterId));
+        map.computeIfAbsent("orgId", v -> SystemConstant.convertIdToLong(orgId));
+        map.computeIfAbsent("majorId", v -> SystemConstant.convertIdToLong(majorId));
+        map.computeIfAbsent("clazzId", v -> SystemConstant.convertIdToLong(clazzId));
+        map.computeIfAbsent("courseCode", v -> courseCode);
+        map.computeIfAbsent(SystemConstant.OSS, v -> dictionaryConfig.sysDomain().isOss());
+        asyncScoreExportService.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("创建任务失败");
+    }
+
+    @ApiOperation(value = "成绩查询同步")
+    @ApiResponses({@ApiResponse(code = 200, message = "同步异步任务信息", response = TBSyncTask.class)})
+    @RequestMapping(value = "/score/sync", method = RequestMethod.POST)
+    public Result sync(@ApiParam(value = "学期id", required = true) @RequestParam String semesterId) {
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        QueryWrapper<ExamPrintPlan> examPrintPlanQueryWrapper = new QueryWrapper<ExamPrintPlan>();
+        examPrintPlanQueryWrapper.select(" DISTINCT third_relate_id ").eq("school_id", sysUser.getSchoolId())
+                .eq("semester_id", SystemConstant.convertIdToLong(semesterId));
+        List<ExamPrintPlan> examPrintPlanList = examPrintPlanService.list(examPrintPlanQueryWrapper);
+        if (Objects.isNull(examPrintPlanList) || examPrintPlanList.size() == 0) {
+            throw ExceptionResultEnum.ERROR.exception("此学期学院下未找到需要同步的考试记录");
+        }
+        LinkedMultiValueMap<Long, Integer> semesterExamIdMap = new LinkedMultiValueMap<>();
+        for (ExamPrintPlan e : examPrintPlanList) {
+            semesterExamIdMap.add(Long.valueOf(semesterId), Integer.parseInt(String.valueOf(e.getThirdRelateId())));
+        }
+        Map<String, Object> map = printCommonService.savePush(PushTypeEnum.SCORE_PUSH);
+        map.computeIfAbsent("semesterExamIdMap", v -> semesterExamIdMap);
+        asyncScorePushService.pushTask(map);
+        TBSyncTask tbSyncTask = Objects.nonNull(map.get(SystemConstant.TB_SYNC_TASK)) ? (TBSyncTask) map.get(SystemConstant.TB_SYNC_TASK) : null;
+        return Objects.nonNull(tbSyncTask) ? ResultUtil.ok(tbSyncTask.getId()) : ResultUtil.error("创建同步推送任务失败");
+    }
+
+    @CrossOrigin(maxAge = 3600) //支持跨域
+    @ApiOperation(value = "成绩动态轨迹图下载")
+    @ApiResponses({@ApiResponse(code = 200, message = "常规信息", response = EditResult.class)})
+    @RequestMapping(value = "/score/download", method = RequestMethod.POST)
+    @Transactional
+    public void download(@ApiParam(value = "学号", required = true) @RequestParam String studentCode) throws Exception {
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        QueryWrapper<TSyncExamStudentScore> tSyncExamStudentScoreQueryWrapper = new QueryWrapper<>();
+        tSyncExamStudentScoreQueryWrapper.lambda().eq(TSyncExamStudentScore::getSchoolId, sysUser.getSchoolId()).eq(TSyncExamStudentScore::getStudentCode, studentCode);
+        TSyncExamStudentScore tSyncExamStudentScore = tSyncExamStudentScoreService.getOne(tSyncExamStudentScoreQueryWrapper);
+        Optional.ofNullable(tSyncExamStudentScore).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("未找到此考生信息"));
+        boolean update = Objects.isNull(tSyncExamStudentScore.getTrajectoryUrls()) ? true : false;
+        tSyncExamStudentScore = tSyncExamStudentScoreService.createImageTrajectory(tSyncExamStudentScore, ImageTrajectoryEnum.PREVIEW);
+        Optional.ofNullable(tSyncExamStudentScore.getTrajectoryUrls()).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("资源未获取到,请稍候再试"));
+        if (update || Objects.isNull(tSyncExamStudentScore.getTrajectoryUrls())) {
+            tSyncExamStudentScoreService.updateById(tSyncExamStudentScore);
+        }
+        tSyncExamStudentScoreService.createZipFile(tSyncExamStudentScore);
+    }
+
+    @ApiOperation(value = "成绩动态轨迹图一键下载")
+    @ApiResponses({@ApiResponse(code = 200, message = "同步信息", response = TBTask.class)})
+    @RequestMapping(value = "/score/batch_download", method = RequestMethod.POST)
+    public Result batchDownload(@ApiParam(value = "学期id", required = true) @RequestParam String semesterId,
+                                @ApiParam(value = "学院id", required = false) @RequestParam(required = false) String orgId,
+                                @ApiParam(value = "专业id", required = false) @RequestParam(required = false) String majorId,
+                                @ApiParam(value = "班级id", required = false) @RequestParam(required = false) String clazzId,
+                                @ApiParam(value = "课程编码", required = false) @RequestParam(required = false) String courseCode) {
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        int count = tSyncExamStudentScoreService.exportCount(sysUser.getSchoolId()
+                , SystemConstant.convertIdToLong(semesterId)
+                , SystemConstant.convertIdToLong(orgId)
+                , SystemConstant.convertIdToLong(majorId)
+                , SystemConstant.convertIdToLong(clazzId), courseCode);
+        if (count == 0) {
+            throw ExceptionResultEnum.ERROR.exception("没有成绩信息");
+        }
+        Map<String, Object> map = printCommonService.saveTask(TaskTypeEnum.SCORE_DOWNLOAD);
+        map.computeIfAbsent("semesterId", v -> SystemConstant.convertIdToLong(semesterId));
+        map.computeIfAbsent("orgId", v -> SystemConstant.convertIdToLong(orgId));
+        map.computeIfAbsent("majorId", v -> SystemConstant.convertIdToLong(majorId));
+        map.computeIfAbsent("clazzId", v -> SystemConstant.convertIdToLong(clazzId));
+        map.computeIfAbsent("courseCode", v -> courseCode);
+        map.computeIfAbsent(SystemConstant.OSS, v -> dictionaryConfig.sysDomain().isOss());
+        asyncScoreBatchDownloadService.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("创建任务失败");
+    }
+}

+ 35 - 0
distributed-print/src/main/java/com/qmth/distributed/print/api/WorkController.java

@@ -1,11 +1,15 @@
 package com.qmth.distributed.print.api;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.qmth.boot.api.annotation.Aac;
 import com.qmth.boot.api.annotation.BOOL;
 import com.qmth.boot.api.constant.ApiConstant;
 import com.qmth.distributed.print.business.bean.result.WorkResult;
+import com.qmth.distributed.print.business.entity.ExamPaperStructure;
+import com.qmth.distributed.print.business.enums.ExamPaperStructureStatusEnum;
 import com.qmth.distributed.print.business.enums.ExamStatusEnum;
+import com.qmth.distributed.print.business.service.ExamPaperStructureService;
 import com.qmth.distributed.print.business.service.ExamTaskService;
 import com.qmth.teachcloud.common.contant.SystemConstant;
 import com.qmth.teachcloud.common.entity.SysUser;
@@ -13,6 +17,7 @@ import com.qmth.teachcloud.common.util.Result;
 import com.qmth.teachcloud.common.util.ResultUtil;
 import com.qmth.teachcloud.common.util.ServletUtil;
 import io.swagger.annotations.*;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
@@ -22,6 +27,7 @@ import org.springframework.web.bind.annotation.RestController;
 import javax.annotation.Resource;
 import javax.validation.constraints.Max;
 import javax.validation.constraints.Min;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -41,6 +47,9 @@ public class WorkController {
     @Resource
     ExamTaskService examTaskService;
 
+    @Autowired
+    ExamPaperStructureService examPaperStructureService;
+
     @ApiOperation(value = "获取待办接口")
     @RequestMapping(value = "/exam/task/ready", method = RequestMethod.POST)
     @ApiResponses({@ApiResponse(code = 200, message = "返回信息", response = WorkResult.class)})
@@ -57,5 +66,31 @@ public class WorkController {
         SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
         return ResultUtil.ok(examTaskService.getFlowTaskReadyList(new Page<>(SystemConstant.PAGE_NUMBER, SystemConstant.PAGE_SIZE), SystemConstant.getHeadOrUserSchoolId(), sysUser.getOrgId(), sysUser.getId()).getRecords().size());
     }
+
+    /**
+     * 阅卷待办任务-数量
+     *
+     * @return
+     */
+    @ApiOperation(value = "阅卷待办任务-数量")
+    @RequestMapping(value = "/structure/task/ready_count", method = RequestMethod.POST)
+    public Result countStructure() {
+        long count = examPaperStructureService.countByPropositionTeacherId();
+        return ResultUtil.ok(count);
+    }
+
+    /**
+     * 阅卷待办任务-数量
+     *
+     * @return
+     */
+    @ApiOperation(value = "阅卷待办任务-列表")
+    @RequestMapping(value = "/structure/task/ready", method = RequestMethod.POST)
+    public Result list(@RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) Integer pageNumber,
+                       @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) Integer pageSize) {
+        String[] structureStatusEnums = new String[]{ExamPaperStructureStatusEnum.FINISH.name()};
+        IPage<ExamPaperStructure> examPaperStructureIPage = examPaperStructureService.listByPropositionTeacherId(pageNumber, pageSize, structureStatusEnums);
+        return ResultUtil.ok(examPaperStructureIPage);
+    }
 }
 

+ 24 - 6
distributed-print/src/main/resources/application-36dev.properties

@@ -12,8 +12,7 @@ spring.application.name=distributed-print
 #\u6570\u636E\u6E90\u914D\u7F6E
 db.host=192.168.10.136
 db.port=3306
-#db.name=distributed-print-v2.2.0
-db.name=distributed-v2.2.0-test
+db.name=distributed-print-v2.2.1
 db.username=root
 db.password=Qmth87863577!
 
@@ -109,6 +108,8 @@ prefix.url.work=admin/work
 prefix.url.client=admin/client
 prefix.url.flow=admin/flow
 prefix.url.statistics=admin/statistics
+prefix.url.sync=admin/sync
+prefix.url.menu=admin/menu
 
 #\u65E5\u671F\u683C\u5F0F\u5316
 spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
@@ -122,13 +123,28 @@ com.qmth.logging.file-path=/ONLINE_EXAM/distributed/tomcat/logs/distributed-prin
 #spring.profiles.include=task
 
 #\uFFFD\uFFFD\uFFFD\u013E\uFFFD\uFFFD\uFFFD\uFFFDurl
-sync.config.hostUrl=http://localhost:8080/
-#\u036C\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
+sync.config.hostUrl=http://192.168.10.224:80
+\u036C\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
 sync.config.examSaveUrl=/api/exam/save
 #\u036C\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
 sync.config.studentSaveUrl=/api/exam/student/save
 #\u036C\uFFFD\uFFFD\uFFFD\u2FE8
-sync.config.cardUploadUrl=/api/file/card/upload
+sync.config.fileUploadUrl=/api/file/{type}/upload
+# \uFFFD\u053E\uFFFD\u1E79\uFFFD\uFFFD\u046F\uFFFD\u04FF\uFFFD
+sync.config.queryPaperStructure=/api/exam/paper/query
+#\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u00BC
+sync.config.markLoginUrl=/open/mark/login
+#\uFFFD\uFFFD\uFFFD\u9CE4\uFFFD\uFFFD\u00BC
+sync.config.markLeaderLoginUrl=/open/subject_header/login
+#\uFFFD\u027C\uFFFD\uFFFD\u0634\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
+sync.config.studentCountUrl=/api/exam/student/count
+#\uFFFD\u027C\uFFFD\uFFFD\u0634\uFFFD
+sync.config.studentScoreUrl=/api/exam/student/score
+# \u036C\uFFFD\uFFFD\uFFFD\u053E\uFFFD\u1E79
+sync.config.structureUrl=/api/exam/paper/save
+# \uFFFD\u00FB\uFFFD\u036C\uFFFD\uFFFD
+sync.config.userSaveUrl=/api/user/external/save
+
 
 sms.config.smsNormalCode=qmth
 sms.config.codeExpiredTime=2
@@ -160,4 +176,6 @@ sms.config.aliyunSMSAuditWillExpireCode=SMS_217436302
 #\uFFFD\uFFFD\u02F4\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u0368\u05AA
 sms.config.aliyunSMSAuditOverdueCode=SMS_217416271
 #\uFFFD\uFFFD\uFFFD\uFFFD
-sms.config.aliyunSMSAuditRejectCode=SMS_225394754
+sms.config.aliyunSMSAuditRejectCode=SMS_225394754
+# \uFFFD\u053E\uFFFD\u1E79\uFFFD\uFFFD\uFFFD\uFFFD\u03F4\uFFFD\u0368\u05AA
+sms.config.aliyunSMSUploadStructureCode=SMS_227253569

+ 23 - 5
distributed-print/src/main/resources/application-dev.properties

@@ -13,9 +13,9 @@ spring.application.name=distributed-print
 db.host=localhost
 db.port=3306
 #db.name=distributed-v2.2.0
-db.name=distributed-v2.2.0-test
+db.name=distributed-print-v2.2.1
 db.username=root
-db.password=123456789
+db.password=root
 
 #redis\u6570\u636E\u6E90\u914D\u7F6E
 com.qmth.redis.host=${db.host}
@@ -109,6 +109,8 @@ prefix.url.work=admin/work
 prefix.url.client=admin/client
 prefix.url.flow=admin/flow
 prefix.url.statistics=admin/statistics
+prefix.url.sync=admin/sync
+prefix.url.menu=admin/menu
 
 #\u65E5\u671F\u683C\u5F0F\u5316
 spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
@@ -128,7 +130,21 @@ sync.config.examSaveUrl=/api/exam/save
 #\u036C\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
 sync.config.studentSaveUrl=/api/exam/student/save
 #\u036C\uFFFD\uFFFD\uFFFD\u2FE8
-sync.config.cardUploadUrl=/api/file/card/upload
+sync.config.fileUploadUrl=/api/file/{type}/upload
+# 试卷结构查询接口
+sync.config.queryPaperStructure=/api/exam/paper/query
+#\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u00BC
+sync.config.markLoginUrl=/open/mark/login
+#科组长登录
+sync.config.markLeaderLoginUrl=/open/subject_header/login
+#\uFFFD\u027C\uFFFD\uFFFD\u0634\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
+sync.config.studentCountUrl=/api/exam/student/count
+#\uFFFD\u027C\uFFFD\uFFFD\u0634\uFFFD
+sync.config.studentScoreUrl=/api/exam/student/score
+# 同步试卷结构
+sync.config.structureUrl=/api/exam/paper/save
+# 用户同步
+sync.config.userSaveUrl=/api/user/external/save
 
 
 sms.config.smsNormalCode=qmth
@@ -160,5 +176,7 @@ sms.config.aliyunSMSAuditReviewCode=SMS_217416269
 sms.config.aliyunSMSAuditWillExpireCode=SMS_217436302
 #\uFFFD\uFFFD\u02F4\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u0368\u05AA
 sms.config.aliyunSMSAuditOverdueCode=SMS_217416271
-#驳回
-sms.config.aliyunSMSAuditRejectCode=SMS_225394754
+#\uFFFD\uFFFD\uFFFD\uFFFD
+sms.config.aliyunSMSAuditRejectCode=SMS_225394754
+# 试卷结构标答上传通知
+sms.config.aliyunSMSUploadStructureCode=SMS_227253569

+ 6 - 0
distributed-print/src/main/resources/application-release.properties

@@ -128,6 +128,12 @@ sync.config.examSaveUrl=/api/exam/save
 sync.config.studentSaveUrl=/api/exam/student/save
 #\u036C\uFFFD\uFFFD\uFFFD\u2FE8
 sync.config.cardUploadUrl=/api/file/card/upload
+#第三方登录
+sync.config.markLoginUrl=/open/mark/login
+#成绩回传考生数量
+sync.config.studentCountUrl=/api/exam/student/count
+#成绩回传
+sync.config.studentScoreUrl=/api/exam/student/score
 
 
 sms.config.smsNormalCode=8635

+ 6 - 0
distributed-print/src/main/resources/application-test.properties

@@ -128,6 +128,12 @@ sync.config.examSaveUrl=/api/exam/save
 sync.config.studentSaveUrl=/api/exam/student/save
 #\u540C\u6B65\u9898\u5361
 sync.config.cardUploadUrl=/api/file/card/upload
+#第三方登录
+sync.config.markLoginUrl=/open/mark/login
+#成绩回传考生数量
+sync.config.studentCountUrl=/api/exam/student/count
+#成绩回传
+sync.config.studentScoreUrl=/api/exam/student/score
 
 
 sms.config.smsNormalCode=8635

+ 2 - 2
distributed-print/src/test/java/com/qmth/distributed/print/CreateSchoolPrivilegeTest.java

@@ -28,7 +28,7 @@ public class CreateSchoolPrivilegeTest {
     @Test
     public void test(){
         QueryWrapper<SysPrivilege> queryWrapper = new QueryWrapper<>();
-        queryWrapper.lambda().eq(SysPrivilege::getSchoolId, SCHOOL_ID);
+//        queryWrapper.lambda().eq(SysPrivilege::getSchoolId, SCHOOL_ID);
         List<SysPrivilege> sysPrivileges = sysPrivilegeService.list(queryWrapper);
         Map<Long, Long> map = new HashMap<>();
         List<SysPrivilege> newList = new ArrayList<>();
@@ -36,7 +36,7 @@ public class CreateSchoolPrivilegeTest {
             Long id = SystemConstant.getDbUuid();
             map.put(sysPrivilege.getId(), id);
             sysPrivilege.setId(id);
-            sysPrivilege.setSchoolId(137l);
+//            sysPrivilege.setSchoolId(137l);
             newList.add(sysPrivilege);
         }
         for (SysPrivilege sysPrivilege : newList) {

+ 1 - 1
distributed-print/src/test/java/com/qmth/distributed/print/ServiceTest.java

@@ -101,7 +101,7 @@ public class ServiceTest {
         Long createId = 1L;
         MessageEnum messageType = MessageEnum.NOTICE_OF_AUDIT_PASS;
 
-        basicMessageService.saveMessageSendLog(userId, mobileNumber, businessId, variableParams, createId, messageType, null);
+//        basicMessageService.saveMessageSendLog(userId, "李四", mobileNumber, businessId, variableParams, createId, messageType, null);
     }
 
     @Test

+ 51 - 0
distributed-print/src/test/java/com/qmth/distributed/print/SyncHelpTest.java

@@ -0,0 +1,51 @@
+package com.qmth.distributed.print;
+
+import com.qmth.teachcloud.common.bean.params.UserPushParam;
+import com.qmth.teachcloud.common.enums.userPush.SpecialPrivilegeEnum;
+import com.qmth.teachcloud.common.service.SysUserService;
+import com.qmth.teachcloud.common.sync.StmmsUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+
+/**
+ * @Description: 推送云阅卷帮助类
+ * @Author: CaoZixuan
+ * @Date: 2021-10-27
+ */
+@SpringBootTest
+@RunWith(SpringRunner.class)
+public class SyncHelpTest {
+
+    @Resource
+    private StmmsUtils stmmsUtils;
+    @Resource
+    private SysUserService sysUserService;
+
+    @Test
+    public void testSyncUser() throws IllegalAccessException {
+        int x = 0;
+        while (x < 10){
+            x ++;
+            UserPushParam userPushParam = new UserPushParam();
+            if (x < 7){
+                userPushParam.setAccount(String.valueOf(x));
+            }
+            if (x % 2 == 1){
+                userPushParam.setRole(SpecialPrivilegeEnum.MARKER);
+            }else {
+                userPushParam.setRole(SpecialPrivilegeEnum.SUBJECT_HEADER);
+            }
+            userPushParam.setSchoolId(2L);
+            stmmsUtils.syncUser(userPushParam);
+        }
+    }
+
+    @Test
+    public void testAutoPushUserErrorData() throws IllegalAccessException {
+        sysUserService.autoPushUserErrorData();
+    }
+}

+ 1 - 1
pom.xml

@@ -4,7 +4,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.qmth.distributed.print.service</groupId>
     <artifactId>distributed-print-service</artifactId>
-    <version>2.2.0</version>
+    <version>2.2.1</version>
     <packaging>pom</packaging>
 
     <modules>

+ 2 - 2
teachcloud-common-api/pom.xml

@@ -4,13 +4,13 @@
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>com.qmth.teachcloud.common.api</groupId>
 	<artifactId>teachcloud-common-api</artifactId>
-	<version>2.2.0</version>
+	<version>2.2.1</version>
 	<packaging>jar</packaging>
 
 	<parent>
 		<groupId>com.qmth.distributed.print.service</groupId>
 		<artifactId>distributed-print-service</artifactId>
-		<version>2.2.0</version>
+		<version>2.2.1</version>
 	</parent>
 
 	<dependencies>

+ 2 - 2
teachcloud-common/pom.xml

@@ -4,13 +4,13 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.qmth.teachcloud.common</groupId>
     <artifactId>teachcloud-common</artifactId>
-    <version>2.2.0</version>
+    <version>2.2.1</version>
     <packaging>jar</packaging>
 
     <parent>
         <groupId>com.qmth.distributed.print.service</groupId>
         <artifactId>distributed-print-service</artifactId>
-        <version>2.2.0</version>
+        <version>2.2.1</version>
     </parent>
 
     <dependencies>

+ 20 - 0
teachcloud-common/src/main/java/com/qmth/teachcloud/common/annotation/DBVerify.java

@@ -0,0 +1,20 @@
+package com.qmth.teachcloud.common.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * @Description: 数据库映射类字段校验注解
+ * @Author: CaoZixuan
+ * @Date: 2021-05-11
+ */
+@Retention(RetentionPolicy.RUNTIME) //定义注解运行策略
+public @interface DBVerify {
+    String value();
+
+    boolean required() default false;
+
+    int min() default 0; //属性接收长度限制默认0,为0的不校验长度,最小长度
+
+    int max() default 0; //属性接收长度限制默认0,为0的不校验长度,最大长度
+}

+ 60 - 0
teachcloud-common/src/main/java/com/qmth/teachcloud/common/bean/dto/PaperDTO.java

@@ -0,0 +1,60 @@
+package com.qmth.teachcloud.common.bean.dto;
+
+import java.util.List;
+
+public class PaperDTO {
+
+    private Integer examId;
+
+    private String subjectCode;
+
+    private String paperType;
+
+    private Boolean objective;
+
+    private List<QuestionDTO> questions;
+
+    public PaperDTO() {
+    }
+
+    public Integer getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Integer examId) {
+        this.examId = examId;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public String getPaperType() {
+        return paperType;
+    }
+
+    public void setPaperType(String paperType) {
+        this.paperType = paperType;
+    }
+
+    public Boolean getObjective() {
+        return objective;
+    }
+
+    public void setObjective(Boolean objective) {
+        this.objective = objective;
+    }
+
+    public List<QuestionDTO> getQuestions() {
+        return questions;
+    }
+
+    public void setQuestions(List<QuestionDTO> questions) {
+        this.questions = questions;
+    }
+
+}

+ 55 - 0
teachcloud-common/src/main/java/com/qmth/teachcloud/common/bean/dto/QuestionDTO.java

@@ -0,0 +1,55 @@
+package com.qmth.teachcloud.common.bean.dto;
+
+public class QuestionDTO {
+
+    private Integer mainNumber;
+
+    private String subNumber;
+
+    private String mainTitle;
+
+    private String answer;
+
+    private Double totalScore;
+
+    public Integer getMainNumber() {
+        return mainNumber;
+    }
+
+    public void setMainNumber(Integer mainNumber) {
+        this.mainNumber = mainNumber;
+    }
+
+    public String getSubNumber() {
+        return subNumber;
+    }
+
+    public void setSubNumber(String subNumber) {
+        this.subNumber = subNumber;
+    }
+
+    public String getMainTitle() {
+        return mainTitle;
+    }
+
+    public void setMainTitle(String mainTitle) {
+        this.mainTitle = mainTitle;
+    }
+
+    public String getAnswer() {
+        return answer;
+    }
+
+    public void setAnswer(String answer) {
+        this.answer = answer;
+    }
+
+    public Double getTotalScore() {
+        return totalScore;
+    }
+
+    public void setTotalScore(Double totalScore) {
+        this.totalScore = totalScore;
+    }
+
+}

+ 122 - 0
teachcloud-common/src/main/java/com/qmth/teachcloud/common/bean/dto/SysRolePrivilegeDto.java

@@ -0,0 +1,122 @@
+package com.qmth.teachcloud.common.bean.dto;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.qmth.teachcloud.common.enums.PrivilegeEnum;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+
+/**
+ * @Description: 修改角色privilege
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2021/10/29
+ */
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class SysRolePrivilegeDto implements Serializable {
+
+    @ApiModelProperty(value = "角色权限id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    Long rolePrivilegeId;
+
+    @ApiModelProperty(value = "学校名称")
+    String schoolName;
+
+    @ApiModelProperty(value = "学校编码")
+    String schoolCode;
+
+    @ApiModelProperty(value = "角色id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    Long roleId;
+
+    @ApiModelProperty(value = "角色名称")
+    String roleName;
+
+    @ApiModelProperty(value = "权限id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    Long privilegeId;
+
+    @ApiModelProperty(value = "权限名称")
+    String privilegeName;
+
+    @ApiModelProperty(value = "权限url")
+    String privilegeUrl;
+
+    @ApiModelProperty(value = "权限类别")
+    PrivilegeEnum privilegeType;
+
+    public Long getRolePrivilegeId() {
+        return rolePrivilegeId;
+    }
+
+    public void setRolePrivilegeId(Long rolePrivilegeId) {
+        this.rolePrivilegeId = rolePrivilegeId;
+    }
+
+    public String getSchoolName() {
+        return schoolName;
+    }
+
+    public void setSchoolName(String schoolName) {
+        this.schoolName = schoolName;
+    }
+
+    public String getSchoolCode() {
+        return schoolCode;
+    }
+
+    public void setSchoolCode(String schoolCode) {
+        this.schoolCode = schoolCode;
+    }
+
+    public Long getRoleId() {
+        return roleId;
+    }
+
+    public void setRoleId(Long roleId) {
+        this.roleId = roleId;
+    }
+
+    public String getRoleName() {
+        return roleName;
+    }
+
+    public void setRoleName(String roleName) {
+        this.roleName = roleName;
+    }
+
+    public Long getPrivilegeId() {
+        return privilegeId;
+    }
+
+    public void setPrivilegeId(Long privilegeId) {
+        this.privilegeId = privilegeId;
+    }
+
+    public String getPrivilegeName() {
+        return privilegeName;
+    }
+
+    public void setPrivilegeName(String privilegeName) {
+        this.privilegeName = privilegeName;
+    }
+
+    public String getPrivilegeUrl() {
+        return privilegeUrl;
+    }
+
+    public void setPrivilegeUrl(String privilegeUrl) {
+        this.privilegeUrl = privilegeUrl;
+    }
+
+    public PrivilegeEnum getPrivilegeType() {
+        return privilegeType;
+    }
+
+    public void setPrivilegeType(PrivilegeEnum privilegeType) {
+        this.privilegeType = privilegeType;
+    }
+}

+ 38 - 6
teachcloud-common/src/main/java/com/qmth/teachcloud/common/bean/dto/excel/BasicStudentImportDto.java

@@ -22,9 +22,17 @@ public class BasicStudentImportDto implements Serializable {
     @ExcelNote(value = "手机号")
     private String phoneNumber;
 
+    @ExcelNote(value = "校区")
+    private String campusName;
+
+    @ExcelNote(value = "学院")
+    private String collegeName;
+
+    @ExcelNote(value = "专业")
+    private String majorName;
+
     @ExcelNote(value = "班级")
-    @NotNull
-    private String clazz;
+    private String clazzName;
 
     public String getStudentName() {
         return studentName;
@@ -50,11 +58,35 @@ public class BasicStudentImportDto implements Serializable {
         this.phoneNumber = phoneNumber;
     }
 
-    public String getClazz() {
-        return clazz;
+    public String getCampusName() {
+        return campusName;
+    }
+
+    public void setCampusName(String campusName) {
+        this.campusName = campusName;
+    }
+
+    public String getCollegeName() {
+        return collegeName;
+    }
+
+    public void setCollegeName(String collegeName) {
+        this.collegeName = collegeName;
+    }
+
+    public String getMajorName() {
+        return majorName;
+    }
+
+    public void setMajorName(String majorName) {
+        this.majorName = majorName;
+    }
+
+    public String getClazzName() {
+        return clazzName;
     }
 
-    public void setClazz(String clazz) {
-        this.clazz = clazz;
+    public void setClazzName(String clazzName) {
+        this.clazzName = clazzName;
     }
 }

+ 20 - 0
teachcloud-common/src/main/java/com/qmth/teachcloud/common/bean/params/BasicClazzParams.java

@@ -2,6 +2,7 @@ package com.qmth.teachcloud.common.bean.params;
 
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.qmth.teachcloud.common.annotation.DBVerify;
 import io.swagger.annotations.ApiModelProperty;
 import org.hibernate.validator.constraints.Length;
 import org.hibernate.validator.constraints.Range;
@@ -17,20 +18,31 @@ public class BasicClazzParams {
 
     @JsonSerialize(using = ToStringSerializer.class)
     @ApiModelProperty(value = "班级id(修改时必填)")
+    @DBVerify(value = "班级id")
     private Long id;
 
     @JsonSerialize(using = ToStringSerializer.class)
     @ApiModelProperty(value = "校区主键")
     @NotNull(message = "请选择校区")
     @Range(min = 1L, message = "请选择校区")
+    @DBVerify(value = "校区",required = true)
     private Long campusId;
 
+    @JsonSerialize(using = ToStringSerializer.class)
+    @ApiModelProperty(value = "专业id")
+    @NotNull(message = "请选择专业")
+    @Range(min = 1L, message = "请选择专业")
+    @DBVerify(value = "专业",required = true)
+    private Long majorId;
+
     @ApiModelProperty(value = "班级编号")
+    @DBVerify(value = "班级编号")
     private String clazzCode;
 
     @ApiModelProperty(value = "班级名称")
     @NotNull(message = "请输入班级名称")
     @Length(min = 1,message = "请输入班级名称")
+    @DBVerify(value = "班级名称",required = true)
     private String clazzName;
 
     public Long getId() {
@@ -64,4 +76,12 @@ public class BasicClazzParams {
     public void setClazzName(String clazzName) {
         this.clazzName = clazzName;
     }
+
+    public Long getMajorId() {
+        return majorId;
+    }
+
+    public void setMajorId(Long majorId) {
+        this.majorId = majorId;
+    }
 }

Some files were not shown because too many files changed in this diff