caozixuan 3 rokov pred
rodič
commit
a36143a66a

+ 1 - 1
distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/marking/Question.java

@@ -88,7 +88,7 @@ public class Question {
         if (!a.getSubNumber().equals(b.getSubNumber())) {
             return false;
         }
-        if (!a.getTotalScore().setScale(2, RoundingMode.HALF_UP).equals(b.getTotalScore().setScale(2, RoundingMode.HALF_UP))) {
+        if (a.getTotalScore().compareTo(b.getTotalScore()) != 0) {
             return false;
         }
         return a.getMainTitle().equals(b.getMainTitle());

+ 7 - 8
teachcloud-common/src/main/java/com/qmth/teachcloud/common/service/impl/BasicCourseServiceImpl.java

@@ -117,15 +117,14 @@ public class BasicCourseServiceImpl extends ServiceImpl<BasicCourseMapper, Basic
         // 向'basic_course'表新增数据 - 教研分析用
         List<BasicCourse> basicCourseList = this.list(new QueryWrapper<BasicCourse>().lambda()
                 .eq(BasicCourse::getSchoolId, schoolId).eq(BasicCourse::getCode, courseCode));
-        if (basicCourseList.size() > 0) {
-            throw ExceptionResultEnum.ERROR.exception("已存在学校id为【" + schoolId + "】,课程编号为【" + courseCode + "】的课程");
+        if (basicCourseList.size() == 0) {
+            BasicCourse basicCourse = new BasicCourse();
+            basicCourse.setId(SystemConstant.getDbUuid());
+            basicCourse.setCode(courseCode);
+            basicCourse.setName(courseName);
+            basicCourse.setSchoolId(schoolId);
+            this.save(basicCourse);
         }
-        BasicCourse basicCourse = new BasicCourse();
-        basicCourse.setId(SystemConstant.getDbUuid());
-        basicCourse.setCode(courseCode);
-        basicCourse.setName(courseName);
-        basicCourse.setSchoolId(schoolId);
-        this.save(basicCourse);
     }
 
     @Override

+ 106 - 0
teachcloud-report-business/src/main/java/com/qmth/teachcloud/report/business/bean/dto/Answer.java

@@ -0,0 +1,106 @@
+package com.qmth.teachcloud.report.business.bean.dto;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @Description: 考生作答
+ * @Author: CaoZixuan
+ * @Date: 2022-06-15
+ */
+public class Answer {
+    @ApiModelProperty(value = "题号类型(客观题、主观题)")
+    @TableField(value = "number_type")
+    private String numberType;
+
+    @ApiModelProperty(value = "大题号")
+    @TableField(value = "main_number")
+    private String mainNumber;
+
+    @ApiModelProperty(value = "小题号")
+    @TableField(value = "sub_number")
+    private String subNumber;
+
+    public String getNumberType() {
+        return numberType;
+    }
+
+    public void setNumberType(String numberType) {
+        this.numberType = numberType;
+    }
+
+    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;
+    }
+
+    /**
+     * 判断两个题目是否完全相同
+     * <p>
+     * 1.题目类型(主观题,客观题)
+     * 2.大题号
+     * 3.小题号
+     * </p>
+     *
+     * @param a 题目a
+     * @param b 题目b
+     * @return true:相同 false:不相同
+     */
+    public static boolean matchTwoAnswer(Answer a, Answer b) {
+        if (!a.getNumberType().equals(b.getNumberType())) {
+            return false;
+        }
+        if (!a.getMainNumber().equals(b.getMainNumber())) {
+            return false;
+        }
+        return a.getSubNumber().equals(b.getSubNumber());
+    }
+
+    /**
+     * 匹配两个题目集合是否在关键字段上相同
+     *
+     * @param ql1 题目集合1
+     * @param ql2 题目集合2
+     * @return true:相同 false:不相同
+     */
+    public static boolean matchTwoAnswerList(List<Answer> ql1, List<Answer> ql2) {
+        // 两个结构内元素数量不一致直接返回错误
+        if (ql1.size() != ql2.size()) {
+            return false;
+        }
+
+        // 排序
+        List<Answer> ql1Sort = ql1.stream().sorted(Comparator.comparing(Answer::getNumberType)
+                        .thenComparing(Answer::getMainNumber)
+                        .thenComparing(Answer::getSubNumber))
+                .collect(Collectors.toList());
+        List<Answer> ql2Sort = ql2.stream().sorted(Comparator.comparing(Answer::getNumberType)
+                        .thenComparing(Answer::getMainNumber)
+                        .thenComparing(Answer::getSubNumber))
+                .collect(Collectors.toList());
+
+        for (int i = 0; i < ql1Sort.size(); i++) {
+            Answer q1 = ql1Sort.get(i);
+            Answer q2 = ql2Sort.get(i);
+            if (!Answer.matchTwoAnswer(q1, q2)) {
+                return false;
+            }
+        }
+        return true;
+    }
+}

+ 0 - 10
teachcloud-report-business/src/main/java/com/qmth/teachcloud/report/business/service/AnalyzeDataCheckService.java

@@ -11,16 +11,6 @@ import java.io.IOException;
  */
 public interface AnalyzeDataCheckService {
 
-    /**
-     * 编辑试卷结构时的内部校验 - 校验试卷结构涉及的知识和能力维度都在试卷维度池当中
-     *
-     * @param knowledgeDimension 知识维度
-     * @param abilityDimension   能力维度
-     * @param examId             考试id
-     * @param courseCode         课程编号
-     */
-    void checkPaperStructInDimensionDatasource(String knowledgeDimension, String abilityDimension, Long examId, String courseCode);
-
     /**
      * 试卷整体检查 - 检查试卷结构't_b_paper_struct'表中各小题总分之和是否和试卷总分一致't_b_paper'
      *

+ 89 - 19
teachcloud-report-business/src/main/java/com/qmth/teachcloud/report/business/service/impl/AnalyzeDataCheckServiceImpl.java

@@ -1,11 +1,13 @@
 package com.qmth.teachcloud.report.business.service.impl;
 
+import cn.hutool.log.Log;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.qmth.teachcloud.common.enums.DimensionEnum;
 import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
 import com.qmth.teachcloud.common.service.BasicCourseService;
+import com.qmth.teachcloud.report.business.bean.dto.Answer;
 import com.qmth.teachcloud.report.business.bean.params.CalculateParams;
-import com.qmth.teachcloud.report.business.entity.TBPaper;
-import com.qmth.teachcloud.report.business.entity.TBPaperStruct;
+import com.qmth.teachcloud.report.business.entity.*;
 import com.qmth.teachcloud.report.business.service.*;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -13,9 +15,9 @@ 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;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * @Description:
@@ -40,12 +42,12 @@ public class AnalyzeDataCheckServiceImpl implements AnalyzeDataCheckService {
     private BasicCourseService basicCourseService;
     @Resource
     private AnalyzeDataGetAndEditService analyzeDataGetAndEditService;
-
-    @Transactional(rollbackFor = Exception.class)
-    @Override
-    public void checkPaperStructInDimensionDatasource(String knowledgeDimension, String abilityDimension, Long examId, String courseCode) {
-        // TODO: 2022/6/9  
-    }
+    @Resource
+    private TBExamRecordService tbExamRecordService;
+    @Resource
+    private TBAnswerService tbAnswerService;
+    @Resource
+    private TBExamStudentService tbExamStudentService;
 
     @Transactional(rollbackFor = Exception.class)
     @Override
@@ -70,7 +72,75 @@ public class AnalyzeDataCheckServiceImpl implements AnalyzeDataCheckService {
     @Transactional(rollbackFor = Exception.class)
     @Override
     public void checkExamStudentAnswer(Long schoolId, Long examId, String courseCode) {
-        // TODO: 2022/6/9  
+        TBPaper tbPaper = tbPaperService.getOne(new QueryWrapper<TBPaper>().lambda()
+                .eq(TBPaper::getExamId,examId)
+                .eq(TBPaper::getCourseCode,courseCode));
+        if (Objects.isNull(tbPaper)){
+            throw ExceptionResultEnum.ERROR.exception("未找到试卷信息");
+        }
+        Long paperId = tbPaper.getId();
+        // 试卷结构蓝图
+        List<TBPaperStruct> tbPaperStructList = tbPaperStructService.list(new QueryWrapper<TBPaperStruct>().lambda()
+                .eq(TBPaperStruct::getPaperId,paperId));
+
+        List<TBExamRecord> tbExamRecordList = tbExamRecordService.list(new QueryWrapper<TBExamRecord>().lambda().eq(TBExamRecord::getPaperId,paperId));
+        if (tbExamRecordList.isEmpty()){
+            throw ExceptionResultEnum.ERROR.exception("没有找到考生成绩记录");
+        }
+        List<Long> examStudentIdList = tbExamRecordList.stream().map(TBExamRecord::getExamStudentId).collect(Collectors.toList());
+
+        // 考生(不缺考的)
+        List<TBExamStudent> tbExamStudentList = tbExamStudentService.list(new QueryWrapper<TBExamStudent>()
+                .lambda()
+                .in(TBExamStudent::getId,examStudentIdList))
+                .stream()
+                .filter(e -> !e.getAbsent())
+                .collect(Collectors.toList());
+        List<Long> effectStudentIdList = tbExamStudentList.stream().map(TBExamStudent::getId).collect(Collectors.toList());
+        int effectExamStudentCount = tbExamStudentList.size();
+        // 有效的考生成绩记录
+        List<TBExamRecord> effectTBExamRecordList = tbExamRecordList.stream().filter(e -> effectStudentIdList.contains(e.getExamStudentId())).collect(Collectors.toList());
+        List<Long> effectRecordIdList = effectTBExamRecordList.stream().map(TBExamRecord::getId).collect(Collectors.toList());
+        if (effectRecordIdList.isEmpty()){
+            throw ExceptionResultEnum.ERROR.exception("缺少有效的考生");
+        }
+
+        // 作答
+        // 1.考生人数对应检查 - 本地试卷结构数量 * 考生数 =? 考生作答总记录数
+        List<TBAnswer> tbAnswerList = tbAnswerService.list(new QueryWrapper<TBAnswer>().lambda().in(TBAnswer::getExamRecordId,effectRecordIdList));
+        int answerCount = 0;
+        Map<Integer,Long> recordAnswerCountCheckMap = new HashMap<>();
+        Map<Long,List<TBAnswer>> recordAnswerMap = new HashMap<>();
+        for (Long effectRecordId : effectRecordIdList) {
+            List<TBAnswer> cell = tbAnswerList.stream().filter(e -> Objects.equals(e.getExamRecordId(), effectRecordId)).collect(Collectors.toList());
+            recordAnswerMap.put(effectRecordId,cell);
+            recordAnswerCountCheckMap.put(cell.size(),effectRecordId);
+        }
+
+        if (recordAnswerCountCheckMap.keySet().size() > 1){
+            throw ExceptionResultEnum.ERROR.exception("同一个试卷不同考生作答记录数量不一致");
+        }
+
+        List<TBAnswer> effectAnswerList = recordAnswerMap.get(effectRecordIdList.get(0));
+        // 2.试卷结构对应检查 - 本地的试卷结构和考生作答的结构中 题目类型,大题号,小题号是否对应
+        List<Answer> al1 = effectAnswerList.stream().flatMap(e -> {
+            Answer answer = new Answer();
+            answer.setNumberType(e.getNumberType());
+            answer.setMainNumber(e.getMainNumber());
+            answer.setSubNumber(e.getSubNumber());
+            return Stream.of(answer);
+        }).collect(Collectors.toList());
+
+        List<Answer> al2 = tbPaperStructList.stream().flatMap(e -> {
+            Answer answer = new Answer();
+            answer.setNumberType(e.getNumberType());
+            answer.setMainNumber(e.getBigQuestionNumber());
+            answer.setSubNumber(e.getSmallQuestionNumber());
+            return Stream.of(answer);
+        }).collect(Collectors.toList());
+        if (!Answer.matchTwoAnswerList(al1,al2)){
+            throw ExceptionResultEnum.ERROR.exception("考生作答中的试卷结构和试卷结构不一致(检查内容 : 题目类型(主观题、客观题),大题号,小题号)");
+        }
     }
 
     @Transactional(rollbackFor = Exception.class)
@@ -102,14 +172,14 @@ public class AnalyzeDataCheckServiceImpl implements AnalyzeDataCheckService {
             if (analyzeDataGetAndEditService.dataGetAndEdit(examId, courseCode, schoolId)){
                 // 如果要重算 则记录该课程
                 needRepeatCourseCodeList.add(courseCode);
-            }
-            // 检查
-            this.checkPaperTotal(schoolId, examId, courseCode);
-            this.checkExamStudentAnswer(schoolId, examId, courseCode);
+                // 检查
+                this.checkPaperTotal(schoolId, examId, courseCode);
+                this.checkExamStudentAnswer(schoolId, examId, courseCode);
 
-            // 触发分析的前置操作
-            this.importConfigData(schoolId, examId, courseCode);
-            this.triggerAssign(schoolId, examId, courseCode);
+                // 触发分析的前置操作
+                this.importConfigData(schoolId, examId, courseCode);
+                this.triggerAssign(schoolId, examId, courseCode);
+            }
         }
         calculateParams.setRepeatCalculateCourseCodeList(needRepeatCourseCodeList);
     }

+ 32 - 7
teachcloud-report-business/src/main/java/com/qmth/teachcloud/report/business/service/impl/AnalyzeDataGetAndEditServiceImpl.java

@@ -76,9 +76,6 @@ public class AnalyzeDataGetAndEditServiceImpl implements AnalyzeDataGetAndEditSe
     @Resource
     private TBAnswerService tbAnswerService;
 
-    @Resource
-    private AnalyzeDataCheckService analyzeDataCheckService;
-
 
     @Transactional(rollbackFor = Exception.class)
     @Override
@@ -238,6 +235,21 @@ public class AnalyzeDataGetAndEditServiceImpl implements AnalyzeDataGetAndEditSe
             tbExamCourse.setOpenDataMd5(JSON.toJSONString(md5));
             tbExamCourseService.saveOrUpdate(tbExamCourse);
             // -- --
+            List<TBDimension> tbDimensionList = tbDimensionService.list(new QueryWrapper<TBDimension>()
+                    .lambda()
+                    .eq(TBDimension::getExamId,examId)
+                    .eq(TBDimension::getCourseCode,courseCode));
+
+            // 知识 - 二级维度
+            List<String> knowledgeDatasource = tbDimensionList.stream()
+                    .filter(e -> DimensionEnum.KNOWLEDGE.getDesc().equals(e.getDimensionType()))
+                    .map(TBDimension::getCodeSecond).distinct()
+                    .collect(Collectors.toList());
+            // 能力 - 一级维度
+            List<String> abilityDatasource = tbDimensionList.stream()
+                    .filter(e -> DimensionEnum.ABILITY.getDesc().equals(e.getDimensionType()))
+                    .map(TBDimension::getCodePrimary).distinct()
+                    .collect(Collectors.toList());
 
             List<TBPaperStruct> tbPaperStructList = paperStructureList.stream().flatMap(e -> {
                 TBPaperStruct tbPaperStruct = new TBPaperStruct();
@@ -252,10 +264,23 @@ public class AnalyzeDataGetAndEditServiceImpl implements AnalyzeDataGetAndEditSe
                 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);
+                // 校验试卷结构每题的维度点都在该科目的维度池中(知识二级能力一级)
+                if (SystemConstant.strNotNull(knowledgeDimension)){
+                    for (String knowledge : knowledgeDimension.split(",")) {
+                        if (!knowledgeDatasource.contains(knowledge)){
+                            throw ExceptionResultEnum.ERROR.exception("试卷结构知识点二级维度【" + knowledge + "】不在知识维度池中");
+                        }
+                    }
+                    tbPaperStruct.setKnowledgeDimension(knowledgeDimension);
+                }
+                if (SystemConstant.strNotNull(abilityDimension)){
+                    for (String ability : abilityDimension.split(",")) {
+                        if (!abilityDatasource.contains(ability)){
+                            throw ExceptionResultEnum.ERROR.exception("试卷结构能力点一级维度【" + ability + "】不在能力维度池中");
+                        }
+                    }
+                    tbPaperStruct.setAbilityDimension(abilityDimension);
+                }
                 return Stream.of(tbPaperStruct);
             }).collect(Collectors.toList());