Browse Source

数据重复性校验

caozixuan 3 years ago
parent
commit
67ee47c995

+ 11 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/result/analyze/GradeInitResult.java

@@ -29,6 +29,9 @@ public class GradeInitResult {
     @ApiModelProperty(value = "试卷名称")
     private String paperName;
 
+    @ApiModelProperty(value = "试卷初始化状态")
+    private String status;
+
     public String getSemesterName() {
         return semesterName;
     }
@@ -84,4 +87,12 @@ public class GradeInitResult {
     public void setPaperName(String paperName) {
         this.paperName = paperName;
     }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
 }

+ 22 - 1
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/GradeInitializeServiceImpl.java

@@ -5,12 +5,17 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.qmth.distributed.print.business.bean.result.analyze.GradeInitResult;
 import com.qmth.distributed.print.business.mapper.GradeInitializeMapper;
 import com.qmth.distributed.print.business.service.GradeInitializeService;
+import com.qmth.teachcloud.common.contant.SystemConstant;
 import com.qmth.teachcloud.common.entity.SysUser;
+import com.qmth.teachcloud.common.enums.GradeAnalyzePaperStatusEnum;
 import com.qmth.teachcloud.common.util.ServletUtil;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * @Description: 教研分析对接-数据初始化服务实现类
@@ -27,7 +32,23 @@ public class GradeInitializeServiceImpl implements GradeInitializeService {
     public IPage<GradeInitResult> findNeedAnalyzedPaper(Long semesterId, Long examId, String courseCode, SysUser requestUser, int pageNumber, int pageSize) {
         Long schoolId = requestUser.getSchoolId();
         Long userId = requestUser.getId();
-        return gradeInitializeMapper.findNeedAnalyzedPaper(new Page<>(pageNumber, pageSize), semesterId, examId, courseCode, userId, schoolId);
+        List<String> finished = new ArrayList<>();
+        finished.add(GradeAnalyzePaperStatusEnum.READY_TO_CALCULATE.getDesc());
+        finished.add(GradeAnalyzePaperStatusEnum.CALCULATING.getDesc());
+        finished.add(GradeAnalyzePaperStatusEnum.FINISH_CALCULATE.getDesc());
+        IPage<GradeInitResult> page = gradeInitializeMapper.findNeedAnalyzedPaper(new Page<>(pageNumber, pageSize), semesterId, examId, courseCode, userId, schoolId);
+        for (GradeInitResult record : page.getRecords()) {
+            String status = record.getStatus();
+            if (SystemConstant.strNotNull(status)) {
+                if (Arrays.stream(status.split(",")).anyMatch(finished::contains)) {
+                    status = "已提交";
+                } else {
+                    status = "未提交";
+                }
+                record.setStatus(status);
+            }
+        }
+        return page;
     }
 
     @Override

+ 5 - 3
distributed-print-business/src/main/resources/mapper/GradeInitializeMapper.xml

@@ -11,7 +11,8 @@
             et.course_name AS courseName,
             et.paper_number AS paperNumber,
             pnpt.paper_type AS paperType,
-            pnpt.paper_name AS paperName
+            pnpt.paper_name AS paperName,
+            pnpt.status AS status
         FROM
             exam_task et
                 INNER JOIN
@@ -21,7 +22,8 @@
                  school_id,
                  paper_number,
                  paper_type,
-                 MAX(paper_name) AS paper_name
+                 MAX(paper_name) AS paper_name,
+                 GROUP_CONCAT(status) AS status
              FROM
                  grade_batch_paper
              GROUP BY school_id , paper_number , paper_type) pnpt ON et.school_id = pnpt.school_id
@@ -73,7 +75,7 @@
         MAX(paper_name) AS paper_name
         FROM
         grade_batch_paper
-        where status = "SETTING_GRADE_PAPER_PARAM"
+        where status = 'SETTING_GRADE_PAPER_PARAM'
         GROUP BY school_id , paper_number , paper_type) pnpt ON et.school_id = pnpt.school_id
         AND et.paper_number = pnpt.paper_number
         AND LOCATE(pnpt.paper_type, etd.relate_paper_type)

+ 65 - 0
teachcloud-report-business/src/main/java/com/qmth/teachcloud/report/business/bean/dto/BasicExamCourseDataMd5.java

@@ -0,0 +1,65 @@
+package com.qmth.teachcloud.report.business.bean.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @Description: t_b_exam_course 表各个从开放接口获取的数据的md5
+ * @Author: CaoZixuan
+ * @Date: 2022-06-14
+ */
+public class BasicExamCourseDataMd5 {
+    @ApiModelProperty(value = "获取试卷接口数据md5")
+    private String paperMd5;
+
+    @ApiModelProperty(value = "获取维度接口数据md5")
+    private String dimensionMd5;
+
+    @ApiModelProperty(value = "获取结构接口数据md5")
+    private String structMd5;
+
+    @ApiModelProperty(value = "获取模块接口数据md5")
+    private String moduleMd5;
+
+    @ApiModelProperty(value = "获取成绩接口数据md5")
+    private String studentScoreMd5;
+
+    public String getPaperMd5() {
+        return paperMd5;
+    }
+
+    public void setPaperMd5(String paperMd5) {
+        this.paperMd5 = paperMd5;
+    }
+
+    public String getDimensionMd5() {
+        return dimensionMd5;
+    }
+
+    public void setDimensionMd5(String dimensionMd5) {
+        this.dimensionMd5 = dimensionMd5;
+    }
+
+    public String getStructMd5() {
+        return structMd5;
+    }
+
+    public void setStructMd5(String structMd5) {
+        this.structMd5 = structMd5;
+    }
+
+    public String getModuleMd5() {
+        return moduleMd5;
+    }
+
+    public void setModuleMd5(String moduleMd5) {
+        this.moduleMd5 = moduleMd5;
+    }
+
+    public String getStudentScoreMd5() {
+        return studentScoreMd5;
+    }
+
+    public void setStudentScoreMd5(String studentScoreMd5) {
+        this.studentScoreMd5 = studentScoreMd5;
+    }
+}

+ 13 - 0
teachcloud-report-business/src/main/java/com/qmth/teachcloud/report/business/entity/TBExamCourse.java

@@ -2,6 +2,7 @@ package com.qmth.teachcloud.report.business.entity;
 
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.qmth.teachcloud.common.base.BaseEntity;
+import com.qmth.teachcloud.report.business.bean.dto.BasicExamCourseDataMd5;
 import com.qmth.teachcloud.report.business.enums.PublishStatusEnum;
 import com.qmth.teachcloud.report.business.enums.TestStatusEnum;
 import io.swagger.annotations.ApiModel;
@@ -58,6 +59,10 @@ public class TBExamCourse extends BaseEntity implements Serializable {
     @TableField(value = "teach_college_name")
     private String teachCollegeName;
 
+    @ApiModelProperty(value = "开放接口获取的数据md5记录")
+    @TableField(value = "open_data_md5")
+    private String openDataMd5;
+
     public Long getSchoolId() {
         return schoolId;
     }
@@ -133,4 +138,12 @@ public class TBExamCourse extends BaseEntity implements Serializable {
     public void setTeachCollegeName(String teachCollegeName) {
         this.teachCollegeName = teachCollegeName;
     }
+
+    public String getOpenDataMd5() {
+        return openDataMd5;
+    }
+
+    public void setOpenDataMd5(String openDataMd5) {
+        this.openDataMd5 = openDataMd5;
+    }
 }

+ 14 - 10
teachcloud-report-business/src/main/java/com/qmth/teachcloud/report/business/service/AnalyzeDataGetAndEditService.java

@@ -20,7 +20,7 @@ public interface AnalyzeDataGetAndEditService {
      * @param schoolId   学校id
      * @throws IOException 结果
      */
-    void tbPaperDispose(Long examId, String courseCode, Long schoolId) throws IOException;
+    boolean tbPaperDispose(Long examId, String courseCode, Long schoolId) throws IOException;
 
     /**
      * 基础试卷维度表全表删除后新增't_b_dimension'
@@ -29,7 +29,7 @@ public interface AnalyzeDataGetAndEditService {
      * @param courseCode 课程编号
      * @param schoolId   学校id
      */
-    void tbPaperDimensionDispose(Long examId, String courseCode, Long schoolId) throws IOException;
+    boolean tbPaperDimensionDispose(Long examId, String courseCode, Long schoolId) throws IOException;
 
     /**
      * 基础试卷结构根据试卷id删除后新增't_b_paper_struct'
@@ -38,24 +38,28 @@ public interface AnalyzeDataGetAndEditService {
      * @param courseCode 课程编号
      * @param schoolId   学校id
      */
-    void tbPaperStructDispose(Long examId, String courseCode, Long schoolId) throws IOException;
+    boolean tbPaperStructDispose(Long examId, String courseCode, Long schoolId) throws IOException;
 
     /**
      * 基础模块评价和二级维度熟练度定义 't_b_module_config'和 't_b_module_proficiency'
-     * @param examId 考试id
+     *
+     * @param examId     考试id
      * @param courseCode 课程编号
-     * @param schoolId 学校id
+     * @param schoolId   学校id
      * @throws IOException 异常
      */
-    void tbPaperModuleDispose(Long examId, String courseCode, Long schoolId) throws IOException;
+    boolean tbPaperModuleDispose(Long examId, String courseCode, Long schoolId) throws IOException;
 
-    void tbExamStudentScoreDatasourceDispose(Long examId, String courseCode, Long schoolId) throws IOException;
+    boolean tbExamStudentScoreDatasourceDispose(Long examId, String courseCode, Long schoolId) throws IOException;
 
     /**
      * 基础数据获取和新增总控
-     * @param examId 考试id
+     *
+     * @param examId     考试id
      * @param courseCode 课程编号
-     * @param schoolId 学校id
+     * @param schoolId   学校id
+     * @return 是否重算
+     * @throws IOException 异常
      */
-    void dataGetAndEdit(Long examId,String courseCode,Long schoolId) throws IOException;
+    boolean dataGetAndEdit(Long examId, String courseCode, Long schoolId) throws IOException;
 }

+ 7 - 1
teachcloud-report-business/src/main/java/com/qmth/teachcloud/report/business/service/impl/AnalyzeDataCheckServiceImpl.java

@@ -13,6 +13,7 @@ import org.springframework.transaction.annotation.Transactional;
 import javax.annotation.Resource;
 import java.io.IOException;
 import java.math.BigDecimal;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 
@@ -95,9 +96,13 @@ public class AnalyzeDataCheckServiceImpl implements AnalyzeDataCheckService {
         Long examId = calculateParams.getExamId();
         Long schoolId = calculateParams.getSchoolId();
         List<String> courseCodeList = calculateParams.getCourseCode();
+        List<String> needRepeatCourseCodeList = new ArrayList<>();
         for (String courseCode : courseCodeList) {
             // 新增
-            analyzeDataGetAndEditService.dataGetAndEdit(examId, courseCode, schoolId);
+            if (analyzeDataGetAndEditService.dataGetAndEdit(examId, courseCode, schoolId)){
+                // 如果要重算 则记录该课程
+                needRepeatCourseCodeList.add(courseCode);
+            }
             // 检查
             this.checkPaperTotal(schoolId, examId, courseCode);
             this.checkExamStudentAnswer(schoolId, examId, courseCode);
@@ -106,5 +111,6 @@ public class AnalyzeDataCheckServiceImpl implements AnalyzeDataCheckService {
             this.importConfigData(schoolId, examId, courseCode);
             this.triggerAssign(schoolId, examId, courseCode);
         }
+        calculateParams.setRepeatCalculateCourseCodeList(needRepeatCourseCodeList);
     }
 }

+ 385 - 159
teachcloud-report-business/src/main/java/com/qmth/teachcloud/report/business/service/impl/AnalyzeDataGetAndEditServiceImpl.java

@@ -1,5 +1,6 @@
 package com.qmth.teachcloud.report.business.service.impl;
 
+import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.qmth.teachcloud.common.bean.params.UserSaveParams;
 import com.qmth.teachcloud.common.contant.SystemConstant;
@@ -13,6 +14,7 @@ import com.qmth.teachcloud.common.service.BasicCourseService;
 import com.qmth.teachcloud.common.service.SysOrgService;
 import com.qmth.teachcloud.common.service.SysRoleService;
 import com.qmth.teachcloud.common.service.SysUserService;
+import com.qmth.teachcloud.report.business.bean.dto.BasicExamCourseDataMd5;
 import com.qmth.teachcloud.report.business.bean.dto.printOpen.*;
 import com.qmth.teachcloud.report.business.bean.dto.query.TBSchoolClazzDto;
 import com.qmth.teachcloud.report.business.bean.dto.query.TBSchoolCollegeDto;
@@ -20,6 +22,7 @@ import com.qmth.teachcloud.report.business.bean.dto.query.TBSchoolTeacherDto;
 import com.qmth.teachcloud.report.business.entity.*;
 import com.qmth.teachcloud.report.business.enums.NumberTypeEnum;
 import com.qmth.teachcloud.report.business.service.*;
+import org.apache.commons.codec.digest.DigestUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -79,80 +82,131 @@ public class AnalyzeDataGetAndEditServiceImpl implements AnalyzeDataGetAndEditSe
 
     @Transactional(rollbackFor = Exception.class)
     @Override
-    public void tbPaperDispose(Long examId, String courseCode, Long schoolId) throws IOException {
+    public boolean tbPaperDispose(Long examId, String courseCode, Long schoolId) throws IOException {
+        boolean repeat = false;
         if (tbExamCourseService.verifyExamCourseCantRun(examId, schoolId, courseCode, null)) {
             throw ExceptionResultEnum.ERROR.exception("课程编号为【" + courseCode + "】的课程不能进行数据更改");
         }
         String courseName = basicCourseService.findByCourseCode(courseCode, schoolId).getName();
         PaperConfig paperConfig = callPrintOpenApiService.callPaperConfig(examId, courseCode);
-
-        BigDecimal coefficient = BigDecimal.ZERO;
-        if (Objects.nonNull(paperConfig.getCoefficient())) {
-            coefficient = BigDecimal.valueOf(Double.parseDouble(String.valueOf(paperConfig.getCoefficient())));
-        }
-        String paperType = paperConfig.getPaperType();
-        List<TBPaper> oldList = tbPaperService.list(new QueryWrapper<TBPaper>().lambda()
-                .eq(TBPaper::getExamId, examId).eq(TBPaper::getCourseCode, courseCode).eq(TBPaper::getPaperType, paperType));
-        Long id;
-        if (oldList.size() == 1) {
-            id = oldList.get(0).getId();
-        } else if (oldList.size() < 1) {
-            id = SystemConstant.getDbUuid();
+        // md5 检验
+        TBExamCourse tbExamCourse = tbExamCourseService.getOne(new QueryWrapper<TBExamCourse>().lambda()
+                .eq(TBExamCourse::getSchoolId, schoolId)
+                .eq(TBExamCourse::getExamId, examId)
+                .eq(TBExamCourse::getCourseCode, courseCode));
+        BasicExamCourseDataMd5 md5 = JSON.parseObject(tbExamCourse.getOpenDataMd5(),BasicExamCourseDataMd5.class);
+        String oldMd5 = "";
+        if (Objects.nonNull(md5)) {
+            oldMd5 = md5.getPaperMd5();
         } else {
-            throw ExceptionResultEnum.ERROR.exception("表数据异常[t_b_paper]");
+            md5 = new BasicExamCourseDataMd5();
         }
+        String currentMd5 = this.buildPaperDataMd5(paperConfig);
+        if (!currentMd5.equals(oldMd5)) {
+            // md5 不一致需要重算
+            repeat = true;
+            md5.setPaperMd5(currentMd5);
+            tbExamCourse.setOpenDataMd5(JSON.toJSONString(md5));
+            tbExamCourseService.saveOrUpdate(tbExamCourse);
+
+
+            BigDecimal coefficient = BigDecimal.ZERO;
+            if (Objects.nonNull(paperConfig.getCoefficient())) {
+                coefficient = BigDecimal.valueOf(Double.parseDouble(String.valueOf(paperConfig.getCoefficient())));
+            }
+            String paperType = paperConfig.getPaperType();
+            List<TBPaper> oldList = tbPaperService.list(new QueryWrapper<TBPaper>().lambda()
+                    .eq(TBPaper::getExamId, examId).eq(TBPaper::getCourseCode, courseCode).eq(TBPaper::getPaperType, paperType));
+            Long id;
+            if (oldList.size() == 1) {
+                id = oldList.get(0).getId();
+            } else if (oldList.size() < 1) {
+                id = SystemConstant.getDbUuid();
+            } else {
+                throw ExceptionResultEnum.ERROR.exception("表数据异常[t_b_paper]");
+            }
 
-        TBPaper tbPaper = new TBPaper();
-        tbPaper.setExamId(examId);
-        tbPaper.setCourseCode(courseCode);
-        tbPaper.setCourseName(courseName);
-        tbPaper.setPaperType(paperConfig.getPaperType());
-        Long startTime = tbPaper.getStartTime();
-        Long endTime = tbPaper.getEndTime();
-        if (!SystemConstant.isOneNull(startTime, endTime)) {
-            tbPaper.setStartTime(startTime);
-            tbPaper.setEndTime(endTime);
+            TBPaper tbPaper = new TBPaper();
+            tbPaper.setExamId(examId);
+            tbPaper.setCourseCode(courseCode);
+            tbPaper.setCourseName(courseName);
+            tbPaper.setPaperType(paperConfig.getPaperType());
+            Long startTime = tbPaper.getStartTime();
+            Long endTime = tbPaper.getEndTime();
+            if (!SystemConstant.isOneNull(startTime, endTime)) {
+                tbPaper.setStartTime(startTime);
+                tbPaper.setEndTime(endTime);
+            }
+            tbPaper.setCoefficient(coefficient);
+            tbPaper.setTotalScore(paperConfig.getTotalScore());
+            tbPaper.setPassScore(paperConfig.getPassScore());
+            tbPaper.setScoreType(paperConfig.getScoreType());
+            tbPaper.setId(id);
+            tbPaperService.saveOrUpdate(tbPaper);
         }
-        tbPaper.setCoefficient(coefficient);
-        tbPaper.setTotalScore(paperConfig.getTotalScore());
-        tbPaper.setPassScore(paperConfig.getPassScore());
-        tbPaper.setScoreType(paperConfig.getScoreType());
-        tbPaper.setId(id);
-        tbPaperService.saveOrUpdate(tbPaper);
+        return repeat;
     }
 
     @Transactional(rollbackFor = Exception.class)
     @Override
-    public void tbPaperDimensionDispose(Long examId, String courseCode, Long schoolId) throws IOException {
+    public boolean tbPaperDimensionDispose(Long examId, String courseCode, Long schoolId) throws IOException {
+        boolean repeat = false;
         if (tbExamCourseService.verifyExamCourseCantRun(examId, schoolId, courseCode, null)) {
             throw ExceptionResultEnum.ERROR.exception("课程编号为【" + courseCode + "】的课程不能进行数据更改");
         }
         List<PaperDimension> paperDimensionList = callPrintOpenApiService.callPaperDimension(examId, courseCode);
-        String courseName = basicCourseService.findByCourseCode(courseCode, schoolId).getName();
 
-        List<TBDimension> tbDimensionList = paperDimensionList.stream().flatMap(e -> {
-            TBDimension tbDimension = new TBDimension();
-            tbDimension.setId(SystemConstant.getDbUuid());
-            tbDimension.setExamId(examId);
-            tbDimension.setCourseCode(courseCode);
-            tbDimension.setCourseName(courseName);
-            tbDimension.setDimensionType(e.getDimensionType().getDesc());
-            tbDimension.setCodePrimary(e.getCodePrimary());
-            tbDimension.setNamePrimary(e.getNamePrimary());
-            tbDimension.setCodeSecond(e.getCodeSecond());
-            tbDimension.setNameSecond(e.getNameSecond());
-            tbDimension.setInterpretation(e.getInterpretation());
-            return Stream.of(tbDimension);
-        }).collect(Collectors.toList());
-        // 根据课程编号删除已有
-        tbDimensionService.remove(new QueryWrapper<TBDimension>().lambda().eq(TBDimension::getExamId, examId).eq(TBDimension::getCourseCode, courseCode));
-        // 批量新增
-        tbDimensionService.saveBatch(tbDimensionList);
+        // md5 检验
+        TBExamCourse tbExamCourse = tbExamCourseService.getOne(new QueryWrapper<TBExamCourse>().lambda()
+                .eq(TBExamCourse::getSchoolId,schoolId)
+                .eq(TBExamCourse::getExamId,examId)
+                .eq(TBExamCourse::getCourseCode,courseCode));
+        BasicExamCourseDataMd5 md5 = JSON.parseObject(tbExamCourse.getOpenDataMd5(),BasicExamCourseDataMd5.class);
+        String oldMd5 = "";
+        if (Objects.nonNull(md5)){
+            oldMd5 = md5.getDimensionMd5();
+        }
+        String currentMd5 = this.buildDimensionDataMd5(paperDimensionList);
+        if (!currentMd5.equals(oldMd5)) {
+            // md5 不一致需要重算
+            repeat = true;
+            md5.setDimensionMd5(currentMd5);
+            tbExamCourse.setOpenDataMd5(JSON.toJSONString(md5));
+            tbExamCourseService.saveOrUpdate(tbExamCourse);
+            // -- --
+
+            String courseName = basicCourseService.findByCourseCode(courseCode, schoolId).getName();
+            List<TBDimension> old = tbDimensionService.list(new QueryWrapper<TBDimension>().lambda().eq(TBDimension::getExamId, examId).eq(TBDimension::getCourseCode, courseCode));
+            if (old != null && old.size() > 0){
+                repeat = this.checkTBDimensionRepeat(old,paperDimensionList);
+            }
+
+            List<TBDimension> tbDimensionList = paperDimensionList.stream().flatMap(e -> {
+                TBDimension tbDimension = new TBDimension();
+                tbDimension.setId(SystemConstant.getDbUuid());
+                tbDimension.setExamId(examId);
+                tbDimension.setCourseCode(courseCode);
+                tbDimension.setCourseName(courseName);
+                tbDimension.setDimensionType(e.getDimensionType().getDesc());
+                tbDimension.setCodePrimary(e.getCodePrimary());
+                tbDimension.setNamePrimary(e.getNamePrimary());
+                tbDimension.setCodeSecond(e.getCodeSecond());
+                tbDimension.setNameSecond(e.getNameSecond());
+                tbDimension.setInterpretation(e.getInterpretation());
+                return Stream.of(tbDimension);
+            }).collect(Collectors.toList());
+            // 根据课程编号删除已有
+            tbDimensionService.remove(new QueryWrapper<TBDimension>().lambda().eq(TBDimension::getExamId, examId).eq(TBDimension::getCourseCode, courseCode));
+            // 批量新增
+            tbDimensionService.saveBatch(tbDimensionList);
+        }
+        return repeat;
     }
 
     @Transactional(rollbackFor = Exception.class)
     @Override
-    public void tbPaperStructDispose(Long examId, String courseCode, Long schoolId) throws IOException {
+    public boolean tbPaperStructDispose(Long examId, String courseCode, Long schoolId) throws IOException {
+        boolean repeat = false;
         if (tbExamCourseService.verifyExamCourseCantRun(examId, schoolId, courseCode, null)) {
             throw ExceptionResultEnum.ERROR.exception("课程编号为【" + courseCode + "】的课程不能进行数据更改");
         }
@@ -165,139 +219,211 @@ public class AnalyzeDataGetAndEditServiceImpl implements AnalyzeDataGetAndEditSe
 
         List<PaperStructure> paperStructureList = callPrintOpenApiService.callPaperStruct(examId, courseCode);
 
-        List<TBPaperStruct> tbPaperStructList = paperStructureList.stream().flatMap(e -> {
-            TBPaperStruct tbPaperStruct = new TBPaperStruct();
-            tbPaperStruct.setId(SystemConstant.getDbUuid());
-            tbPaperStruct.setPaperId(paperId);
-            tbPaperStruct.setQuestionName(e.getQuestionName());
-            tbPaperStruct.setNumberType(e.getNumberType().getDesc());
-            tbPaperStruct.setBigQuestionNumber(e.getBigQuestionNumber());
-            tbPaperStruct.setSmallQuestionNumber(e.getSmallQuestionNumber());
-            tbPaperStruct.setQuestionType(e.getBigTopicName());
-            tbPaperStruct.setFullScore(e.getFullScore());
-            tbPaperStruct.setScoreRules(e.getScoreRules());
-            String knowledgeDimension = e.getKnowledgeDimension();
-            String abilityDimension = e.getAbilityDimension();
-            // TODO: 2022/6/9  校验的实现
-            analyzeDataCheckService.checkPaperStructInDimensionDatasource(knowledgeDimension, abilityDimension, examId, courseCode);
-            tbPaperStruct.setKnowledgeDimension(knowledgeDimension);
-            tbPaperStruct.setAbilityDimension(abilityDimension);
-            return Stream.of(tbPaperStruct);
-        }).collect(Collectors.toList());
+        // md5 检验
+        TBExamCourse tbExamCourse = tbExamCourseService.getOne(new QueryWrapper<TBExamCourse>().lambda()
+                .eq(TBExamCourse::getSchoolId,schoolId)
+                .eq(TBExamCourse::getExamId,examId)
+                .eq(TBExamCourse::getCourseCode,courseCode));
+        BasicExamCourseDataMd5 md5 = JSON.parseObject(tbExamCourse.getOpenDataMd5(),BasicExamCourseDataMd5.class);
+        String oldMd5 = "";
+        if (Objects.nonNull(md5)){
+            oldMd5 = md5.getStructMd5();
+        }
+        String currentMd5 = this.buildStructDataMd5(paperStructureList);
+        //因为t_b_paper表是做更新操作的所以当结构数据md5一致,即使是t_b_paper的数据改了,也不影响试卷结构数据所绑定的paper_id 所以不用重新算
+        if (!currentMd5.equals(oldMd5)) {
+            // md5 不一致需要重算
+            repeat = true;
+            md5.setStructMd5(currentMd5);
+            tbExamCourse.setOpenDataMd5(JSON.toJSONString(md5));
+            tbExamCourseService.saveOrUpdate(tbExamCourse);
+            // -- --
+
+            List<TBPaperStruct> tbPaperStructList = paperStructureList.stream().flatMap(e -> {
+                TBPaperStruct tbPaperStruct = new TBPaperStruct();
+                tbPaperStruct.setId(SystemConstant.getDbUuid());
+                tbPaperStruct.setPaperId(paperId);
+                tbPaperStruct.setQuestionName(e.getQuestionName());
+                tbPaperStruct.setNumberType(e.getNumberType().getDesc());
+                tbPaperStruct.setBigQuestionNumber(e.getBigQuestionNumber());
+                tbPaperStruct.setSmallQuestionNumber(e.getSmallQuestionNumber());
+                tbPaperStruct.setQuestionType(e.getBigTopicName());
+                tbPaperStruct.setFullScore(e.getFullScore());
+                tbPaperStruct.setScoreRules(e.getScoreRules());
+                String knowledgeDimension = e.getKnowledgeDimension();
+                String abilityDimension = e.getAbilityDimension();
+                // TODO: 2022/6/9  校验的实现
+                analyzeDataCheckService.checkPaperStructInDimensionDatasource(knowledgeDimension, abilityDimension, examId, courseCode);
+                tbPaperStruct.setKnowledgeDimension(knowledgeDimension);
+                tbPaperStruct.setAbilityDimension(abilityDimension);
+                return Stream.of(tbPaperStruct);
+            }).collect(Collectors.toList());
 
-        // 删除试卷id下所有试卷结构
-        tbPaperStructService.remove(new QueryWrapper<TBPaperStruct>().lambda().eq(TBPaperStruct::getPaperId, paperId));
-        // 新增试卷id下的试卷结构
-        tbPaperStructService.saveBatch(tbPaperStructList);
+            // 删除试卷id下所有试卷结构
+            tbPaperStructService.remove(new QueryWrapper<TBPaperStruct>().lambda().eq(TBPaperStruct::getPaperId, paperId));
+            // 新增试卷id下的试卷结构
+            tbPaperStructService.saveBatch(tbPaperStructList);
+        }
+        return repeat;
     }
 
     @Transactional(rollbackFor = Exception.class)
     @Override
-    public void tbPaperModuleDispose(Long examId, String courseCode, Long schoolId) throws IOException {
+    public boolean tbPaperModuleDispose(Long examId, String courseCode, Long schoolId) throws IOException {
+        boolean repeat = false;
         if (tbExamCourseService.verifyExamCourseCantRun(examId, schoolId, courseCode, null)) {
             throw ExceptionResultEnum.ERROR.exception("课程编号为【" + courseCode + "】的课程不能进行数据更改");
         }
         String courseName = basicCourseService.findByCourseCode(courseCode, schoolId).getName();
         List<PaperEvaluation> paperEvaluationList = callPrintOpenApiService.callPaperModule(examId, courseCode);
 
-        List<TBModuleProficiency> tbModuleProficiencyList = new ArrayList<>();
-        List<TBModuleConfig> tbModuleConfigList = new ArrayList<>();
-        Map<DimensionEnum, PaperEvaluation> checkDimensionType = new HashMap<>();
-        for (PaperEvaluation paperEvaluation : paperEvaluationList) {
-            // 校验大的数据结构
-            DimensionEnum moduleType = paperEvaluation.getModuleType();
-            if (checkDimensionType.containsKey(moduleType)) {
-                throw ExceptionResultEnum.ERROR.exception("模块数据存在相同模块类型【" + moduleType + "】异常");
-            }
-            checkDimensionType.put(moduleType, paperEvaluation);
-
-            String interpret = paperEvaluation.getInterpret();
-            String remark = paperEvaluation.getRemark();
-            String formula = paperEvaluation.getFormula().getDesc();
-
-            // 解析并生成't_b_module_proficiency' 二级维度精熟度
-            List<SecondaryDimensionLevelDefine> secondaryDimensionLevelDefineList = paperEvaluation.getSecondaryDimensionLevelDefineList();
-            List<TBModuleProficiency> tbModuleProficiencyCell = secondaryDimensionLevelDefineList.stream().flatMap(e -> {
-                TBModuleProficiency tbModuleProficiency = new TBModuleProficiency();
-                tbModuleProficiency.setId(SystemConstant.getDbUuid());
-                tbModuleProficiency.setExamId(examId);
-                tbModuleProficiency.setCourseCode(courseCode);
-                tbModuleProficiency.setCourseName(courseName);
-                tbModuleProficiency.setModuleType(moduleType.getDesc());
-                tbModuleProficiency.setInterpret(interpret);
-                tbModuleProficiency.setRemark(remark);
-                tbModuleProficiency.setDefine(SystemConstant.strNotNull(e.getDefine())?e.getDefine().trim():null);
-                tbModuleProficiency.setLevel(e.getLevel());
-                tbModuleProficiency.setMin(e.getMin());
-                tbModuleProficiency.setMax(e.getMax());
-                tbModuleProficiency.setScope(e.getScope());
-                return Stream.of(tbModuleProficiency);
-            }).collect(Collectors.toList());
-            tbModuleProficiencyList.addAll(tbModuleProficiencyCell);
-
-            // 解析并生成't_b_module_config' 维度模块等级评价及建议
-            List<ModuleEvaluation> moduleEvaluationList = paperEvaluation.getModuleEvaluationList();
-            List<TBModuleConfig> tbModuleConfigCell = moduleEvaluationList.stream().flatMap(e -> {
-                TBModuleConfig tbModuleConfig = new TBModuleConfig();
-                tbModuleConfig.setId(SystemConstant.getDbUuid());
-                tbModuleConfig.setExamId(examId);
-                tbModuleConfig.setCourseCode(courseCode);
-                tbModuleConfig.setCourseName(courseName);
-                tbModuleConfig.setModuleType(moduleType.getDesc());
-                tbModuleConfig.setFormula(formula);
-                tbModuleConfig.setScope(e.getScope());
-                tbModuleConfig.setLevelCode(e.getLevelCode());
-                tbModuleConfig.setLevelName(e.getLevelName());
-                tbModuleConfig.setResult(e.getResult());
-                tbModuleConfig.setAdvice(e.getAdvice());
-                if (DimensionEnum.KNOWLEDGE.equals(moduleType)) {
-                    tbModuleConfig.setAttribute("knowledgeDimension");
-                } else if (DimensionEnum.ABILITY.equals(moduleType)) {
-                    tbModuleConfig.setAttribute("abilityDimension");
+        // md5 检验
+        TBExamCourse tbExamCourse = tbExamCourseService.getOne(new QueryWrapper<TBExamCourse>().lambda()
+                .eq(TBExamCourse::getSchoolId,schoolId)
+                .eq(TBExamCourse::getExamId,examId)
+                .eq(TBExamCourse::getCourseCode,courseCode));
+        BasicExamCourseDataMd5 md5 = JSON.parseObject(tbExamCourse.getOpenDataMd5(),BasicExamCourseDataMd5.class);
+        String oldMd5 = "";
+        if (Objects.nonNull(md5)){
+            oldMd5 = md5.getModuleMd5();
+        }
+        String currentMd5 = this.buildModuleDataMd5(paperEvaluationList);
+        if (!currentMd5.equals(oldMd5)) {
+            // md5 不一致需要重算
+            repeat = true;
+            md5.setModuleMd5(currentMd5);
+            tbExamCourse.setOpenDataMd5(JSON.toJSONString(md5));
+            tbExamCourseService.saveOrUpdate(tbExamCourse);
+            // -- --
+
+            List<TBModuleProficiency> tbModuleProficiencyList = new ArrayList<>();
+            List<TBModuleConfig> tbModuleConfigList = new ArrayList<>();
+            Map<DimensionEnum, PaperEvaluation> checkDimensionType = new HashMap<>();
+            for (PaperEvaluation paperEvaluation : paperEvaluationList) {
+                // 校验大的数据结构
+                DimensionEnum moduleType = paperEvaluation.getModuleType();
+                if (checkDimensionType.containsKey(moduleType)) {
+                    throw ExceptionResultEnum.ERROR.exception("模块数据存在相同模块类型【" + moduleType + "】异常");
                 }
-                return Stream.of(tbModuleConfig);
-            }).collect(Collectors.toList());
-            tbModuleConfigList.addAll(tbModuleConfigCell);
+                checkDimensionType.put(moduleType, paperEvaluation);
+
+                String interpret = paperEvaluation.getInterpret();
+                String remark = paperEvaluation.getRemark();
+                String formula = paperEvaluation.getFormula().getDesc();
+
+                // 解析并生成't_b_module_proficiency' 二级维度精熟度
+                List<SecondaryDimensionLevelDefine> secondaryDimensionLevelDefineList = paperEvaluation.getSecondaryDimensionLevelDefineList();
+                List<TBModuleProficiency> tbModuleProficiencyCell = secondaryDimensionLevelDefineList.stream().flatMap(e -> {
+                    TBModuleProficiency tbModuleProficiency = new TBModuleProficiency();
+                    tbModuleProficiency.setId(SystemConstant.getDbUuid());
+                    tbModuleProficiency.setExamId(examId);
+                    tbModuleProficiency.setCourseCode(courseCode);
+                    tbModuleProficiency.setCourseName(courseName);
+                    tbModuleProficiency.setModuleType(moduleType.getDesc());
+                    tbModuleProficiency.setInterpret(interpret);
+                    tbModuleProficiency.setRemark(remark);
+                    tbModuleProficiency.setDefine(SystemConstant.strNotNull(e.getDefine()) ? e.getDefine().trim() : null);
+                    tbModuleProficiency.setLevel(e.getLevel());
+                    tbModuleProficiency.setMin(e.getMin());
+                    tbModuleProficiency.setMax(e.getMax());
+                    tbModuleProficiency.setScope(e.getScope());
+                    return Stream.of(tbModuleProficiency);
+                }).collect(Collectors.toList());
+                tbModuleProficiencyList.addAll(tbModuleProficiencyCell);
+
+                // 解析并生成't_b_module_config' 维度模块等级评价及建议
+                List<ModuleEvaluation> moduleEvaluationList = paperEvaluation.getModuleEvaluationList();
+                List<TBModuleConfig> tbModuleConfigCell = moduleEvaluationList.stream().flatMap(e -> {
+                    TBModuleConfig tbModuleConfig = new TBModuleConfig();
+                    tbModuleConfig.setId(SystemConstant.getDbUuid());
+                    tbModuleConfig.setExamId(examId);
+                    tbModuleConfig.setCourseCode(courseCode);
+                    tbModuleConfig.setCourseName(courseName);
+                    tbModuleConfig.setModuleType(moduleType.getDesc());
+                    tbModuleConfig.setFormula(formula);
+                    tbModuleConfig.setScope(e.getScope());
+                    tbModuleConfig.setLevelCode(e.getLevelCode());
+                    tbModuleConfig.setLevelName(e.getLevelName());
+                    tbModuleConfig.setResult(e.getResult());
+                    tbModuleConfig.setAdvice(e.getAdvice());
+                    if (DimensionEnum.KNOWLEDGE.equals(moduleType)) {
+                        tbModuleConfig.setAttribute("knowledgeDimension");
+                    } else if (DimensionEnum.ABILITY.equals(moduleType)) {
+                        tbModuleConfig.setAttribute("abilityDimension");
+                    }
+                    return Stream.of(tbModuleConfig);
+                }).collect(Collectors.toList());
+                tbModuleConfigList.addAll(tbModuleConfigCell);
+            }
+            // 删除后新增
+            tbModuleProficiencyService.remove(new QueryWrapper<TBModuleProficiency>().lambda()
+                    .eq(TBModuleProficiency::getExamId, examId)
+                    .eq(TBModuleProficiency::getCourseCode, courseCode));
+            tbModuleProficiencyService.saveBatch(tbModuleProficiencyList);
+
+            tbModuleConfigService.remove(new QueryWrapper<TBModuleConfig>().lambda()
+                    .eq(TBModuleConfig::getExamId, examId)
+                    .eq(TBModuleConfig::getCourseCode, courseCode));
+            tbModuleConfigService.saveBatch(tbModuleConfigList);
         }
-        // 删除后新增
-        tbModuleProficiencyService.remove(new QueryWrapper<TBModuleProficiency>().lambda()
-                .eq(TBModuleProficiency::getExamId, examId)
-                .eq(TBModuleProficiency::getCourseCode, courseCode));
-        tbModuleProficiencyService.saveBatch(tbModuleProficiencyList);
-
-        tbModuleConfigService.remove(new QueryWrapper<TBModuleConfig>().lambda()
-                .eq(TBModuleConfig::getExamId, examId)
-                .eq(TBModuleConfig::getCourseCode, courseCode));
-        tbModuleConfigService.saveBatch(tbModuleConfigList);
+        return repeat;
     }
 
     @Transactional(rollbackFor = Exception.class)
     @Override
-    public void tbExamStudentScoreDatasourceDispose(Long examId, String courseCode, Long schoolId) throws IOException {
+    public boolean tbExamStudentScoreDatasourceDispose(Long examId, String courseCode, Long schoolId) throws IOException {
+        boolean repeat = false;
         if (tbExamCourseService.verifyExamCourseCantRun(examId, schoolId, courseCode, null)) {
             throw ExceptionResultEnum.ERROR.exception("课程编号为【" + courseCode + "】的课程不能进行数据更改");
         }
         String courseName = basicCourseService.findByCourseCode(courseCode, schoolId).getName();
         List<ExamStudentScore> examStudentScoreList = callPrintOpenApiService.callExamStudentScore(examId, courseCode);
-
-        // 1.创建班级数据
-        this.createTBSchoolClazz(examStudentScoreList, schoolId);
-        // 2.筛选并创建学校学院表
-        this.createCollegeInfo(examStudentScoreList, schoolId);
-        // 3.筛选并创建教师
-        this.saveTeacherInfo(examStudentScoreList, examId, courseCode, schoolId);
-        // 4.创建学生及作答
-        this.saveExamStudentScore(examStudentScoreList, examId, courseCode, courseName, schoolId);
+        // md5 检查
+        TBExamCourse tbExamCourse = tbExamCourseService.getOne(new QueryWrapper<TBExamCourse>().lambda()
+                .eq(TBExamCourse::getSchoolId,schoolId)
+                .eq(TBExamCourse::getExamId,examId)
+                .eq(TBExamCourse::getCourseCode,courseCode));
+        BasicExamCourseDataMd5 md5 = JSON.parseObject(tbExamCourse.getOpenDataMd5(),BasicExamCourseDataMd5.class);
+        String oldMd5 = "";
+        if (Objects.nonNull(md5)){
+            oldMd5 = md5.getStudentScoreMd5();
+        }
+        String currentMd5 = this.buildExamStudentDataMd5(examStudentScoreList);
+
+        //因为t_b_paper表是做更新操作的所以当学生数据md5一致,即使是t_b_paper的数据改了,也不影响学生数据所绑定的paper_id 所以不用重新算
+        if (!currentMd5.equals(oldMd5)){
+            // md5 不一致需要重算
+            repeat = true;
+            md5.setStudentScoreMd5(currentMd5);
+            tbExamCourse.setOpenDataMd5(JSON.toJSONString(md5));
+            tbExamCourseService.saveOrUpdate(tbExamCourse);
+            // -- --
+
+            // 1.创建班级数据
+            this.createTBSchoolClazz(examStudentScoreList, schoolId);
+            // 2.筛选并创建学校学院表
+            this.createCollegeInfo(examStudentScoreList, schoolId);
+            // 3.筛选并创建教师
+            this.saveTeacherInfo(examStudentScoreList, examId, courseCode, schoolId);
+            // 4.创建学生及作答
+            this.saveExamStudentScore(examStudentScoreList, examId, courseCode, courseName, schoolId);
+        }
+        return repeat;
     }
 
     @Transactional(rollbackFor = Exception.class)
     @Override
-    public void dataGetAndEdit(Long examId, String courseCode, Long schoolId) throws IOException {
-        this.tbPaperDispose(examId, courseCode, schoolId);
-        this.tbPaperDimensionDispose(examId, courseCode, schoolId);
-        this.tbPaperStructDispose(examId, courseCode, schoolId);
-        this.tbPaperModuleDispose(examId, courseCode, schoolId);
-        this.tbExamStudentScoreDatasourceDispose(examId, courseCode, schoolId);
+    public boolean dataGetAndEdit(Long examId, String courseCode, Long schoolId) throws IOException {
+        boolean repeat = false;
+        boolean repeatForPaper = this.tbPaperDispose(examId, courseCode, schoolId);
+        boolean repeatForDimension = this.tbPaperDimensionDispose(examId, courseCode, schoolId);
+        boolean repeatForStruct = this.tbPaperStructDispose(examId, courseCode, schoolId);
+        boolean repeatForModule = this.tbPaperModuleDispose(examId, courseCode, schoolId);
+        boolean repeatForExamStudentScore = this.tbExamStudentScoreDatasourceDispose(examId, courseCode, schoolId);
+        if (repeatForPaper || repeatForDimension || repeatForStruct || repeatForModule || repeatForExamStudentScore){
+            repeat = true;
+        }
+        return repeat;
     }
 
     /**
@@ -635,4 +761,104 @@ public class AnalyzeDataGetAndEditServiceImpl implements AnalyzeDataGetAndEditSe
         tbExamRecordService.saveBatch(tbExamRecordList);
         tbAnswerService.saveBatch(tbAnswerList);
     }
+
+    /**
+     * 检验基础试卷有变动需要重新计算
+     *
+     * @param old     旧的试卷
+     * @param current 现在的试卷
+     * @return 1:重算 - 0 :不用
+     */
+    private boolean checkTBPaperRepeat(TBPaper old, PaperConfig current) {
+        String oldStr = old.getPaperType() + old.getScoreType() + old.getCoefficient() + old.getTotalScore() + old.getPassScore();
+        String currentStr = current.getPaperType() + current.getScoreType() + current.getCoefficient() + current.getTotalScore() + current.getPassScore();
+        return !currentStr.equals(oldStr);
+    }
+
+    /**
+     * 检验维度点变动的重新计算
+     *
+     * @param old     旧维度
+     * @param current 新维度
+     * @return 1:重算 - 0 :不用
+     */
+    private boolean checkTBDimensionRepeat(List<TBDimension> old, List<PaperDimension> current) {
+        if (old.isEmpty() || current.size() != old.size()) {
+            return false;
+        } else {
+            old = old.stream().sorted(Comparator.comparing(TBDimension::getDimensionType)
+                            .thenComparing(TBDimension::getCodePrimary)
+                            .thenComparing(TBDimension::getCodeSecond))
+                    .collect(Collectors.toList());
+            current = current.stream().sorted(Comparator.comparing(PaperDimension::getDimensionType)
+                            .thenComparing(PaperDimension::getCodePrimary)
+                            .thenComparing(PaperDimension::getCodeSecond))
+                    .collect(Collectors.toList());
+
+            List<String> oldStrList = old.stream().flatMap(e -> {
+                String x = e.getDimensionType() + e.getNamePrimary() + e.getCodePrimary() + e.getNameSecond() + e.getCodeSecond() + e.getInterpretation();
+                return Stream.of(x);
+            }).collect(Collectors.toList());
+            List<String> currentStrList = current.stream().flatMap(e -> {
+                String x = e.getDimensionType() + e.getNamePrimary() + e.getCodePrimary() + e.getNameSecond() + e.getCodeSecond() + e.getInterpretation();
+                return Stream.of(x);
+            }).collect(Collectors.toList());
+            return !oldStrList.toString().equals(currentStrList.toString());
+        }
+    }
+
+    /**
+     * 构建试卷信息md5
+     * @param paperConfig 试卷配置
+     * @return md5
+     */
+    private String buildPaperDataMd5(PaperConfig paperConfig){
+        return DigestUtils.md5Hex(JSON.toJSONString(paperConfig));
+    }
+
+    /**
+     * 构建维度信息md5
+     * @param paperDimensionList 维度信息
+     * @return MD5
+     */
+    private String buildDimensionDataMd5(List<PaperDimension> paperDimensionList){
+        paperDimensionList = paperDimensionList.stream().sorted(Comparator.comparing(PaperDimension::getDimensionType)
+                        .thenComparing(PaperDimension::getCodePrimary)
+                        .thenComparing(PaperDimension::getCodeSecond))
+                .collect(Collectors.toList());
+        return DigestUtils.md5Hex(JSON.toJSONString(paperDimensionList));
+    }
+
+    /**
+     * 构建结构信息md5
+     * @param paperStructureList 试卷结构信息
+     * @return MD5
+     */
+    private String buildStructDataMd5(List<PaperStructure> paperStructureList){
+        paperStructureList = paperStructureList.stream().sorted(Comparator.comparing(PaperStructure::getNumberType)
+                .thenComparing(PaperStructure::getBigQuestionNumber)
+                .thenComparing(PaperStructure::getSmallQuestionNumber)).collect(Collectors.toList());
+        return DigestUtils.md5Hex(JSON.toJSONString(paperStructureList));
+    }
+
+    /**
+     * 构建模块信息MD5
+     * @param paperEvaluationList 试卷模块信息
+     * @return MD5
+     */
+    private String buildModuleDataMd5(List<PaperEvaluation> paperEvaluationList){
+        paperEvaluationList = paperEvaluationList.stream().sorted(Comparator.comparing(PaperEvaluation::getModuleType))
+                .collect(Collectors.toList());
+        return DigestUtils.md5Hex(JSON.toJSONString(paperEvaluationList));
+    }
+
+    /**
+     * 构建学生成绩数据md5
+     * @param examStudentScoreList 学生成绩数据
+     * @return md5
+     */
+    private String buildExamStudentDataMd5(List<ExamStudentScore> examStudentScoreList){
+        examStudentScoreList = examStudentScoreList.stream().sorted(Comparator.comparing(ExamStudentScore::getStudentCode)).collect(Collectors.toList());
+        return DigestUtils.md5Hex(JSON.toJSONString(examStudentScoreList));
+    }
 }