Parcourir la source

评卷管理/成绩检查增加导出

wangliang il y a 11 mois
Parent
commit
7a9d6e4e2a
16 fichiers modifiés avec 2350 ajouts et 1770 suppressions
  1. 11 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/result/TeachCourseResult.java
  2. 3 10
      distributed-print-business/src/main/resources/mapper/TeachCourseMapper.xml
  3. 91 72
      distributed-print/src/main/java/com/qmth/distributed/print/api/mark/MarkStudentController.java
  4. 25 11
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/bean/archivescore/ArchiveStudentQuery.java
  5. 52 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/dto/mark/score/StudentScoreDetailDto.java
  6. 66 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/dto/mark/score/StudentScoreDetailExportDto.java
  7. 132 91
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/mapper/MarkStudentMapper.java
  8. 45 41
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/mapper/ScanOmrTaskMapper.java
  9. 95 85
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkPaperService.java
  10. 223 186
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkStudentService.java
  11. 46 44
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/ScanOmrTaskService.java
  12. 461 422
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkPaperServiceImpl.java
  13. 175 5
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkStudentServiceImpl.java
  14. 684 677
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/ScanOmrTaskServiceImpl.java
  15. 202 126
      teachcloud-mark/src/main/resources/mapper/MarkStudentMapper.xml
  16. 39 0
      teachcloud-mark/src/main/resources/mapper/ScanOmrTaskMapper.xml

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

@@ -38,6 +38,17 @@ public class TeachCourseResult {
     @ApiModelProperty(value = "用户名称(教师名称)")
     private String userName;
 
+    @ApiModelProperty(value = "开课学院")
+    private String college;
+
+    public String getCollege() {
+        return college;
+    }
+
+    public void setCollege(String college) {
+        this.college = college;
+    }
+
     public Long getId() {
         return id;
     }

+ 3 - 10
distributed-print-business/src/main/resources/mapper/TeachCourseMapper.xml

@@ -6,13 +6,14 @@
             resultType="com.qmth.distributed.print.business.bean.result.TeachCourseResult">
         SELECT
             tc.id,
-            GROUP_CONCAT(bc.code, '(', so.name, ')') as courseCode,
+            bc.code as courseCode,
             bc.name AS courseName,
             tc.create_id AS createId,
             tc.create_time AS createTime,
             tc.user_id AS userId,
             su.login_name as userLoginName,
-            su.real_name AS userName
+            su.real_name AS userName,
+            so.name as college
         FROM
             teach_course tc
                 INNER JOIN
@@ -43,14 +44,6 @@
                 </if>
             </if>
         </where>
-        group by
-            tc.id,
-            bc.name,
-            tc.create_id,
-            tc.create_time,
-            tc.user_id,
-            su.login_name,
-            su.real_name
         ORDER BY tc.create_time DESC
     </select>
 </mapper>

+ 91 - 72
distributed-print/src/main/java/com/qmth/distributed/print/api/mark/MarkStudentController.java

@@ -1,73 +1,92 @@
-package com.qmth.distributed.print.api.mark;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.qmth.boot.api.constant.ApiConstant;
-import com.qmth.teachcloud.common.annotation.OperationLogDetail;
-import com.qmth.teachcloud.common.contant.SystemConstant;
-import com.qmth.teachcloud.common.enums.log.OperationTypeEnum;
-import com.qmth.teachcloud.common.util.Result;
-import com.qmth.teachcloud.common.util.ResultUtil;
-import com.qmth.teachcloud.mark.dto.mark.score.StudentScoreDetailDto;
-import com.qmth.teachcloud.mark.service.MarkStudentService;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
-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;
-
-/**
- * <p>
- * 考试考生库 前端控制器
- * </p>
- *
- * @author xf
- * @since 2023-09-22
- */
-@Api(tags = "评卷-考生")
-@RestController
-@RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + SystemConstant.PREFIX_URL_MARK + "/student")
-public class MarkStudentController {
-
-    @Resource
-    MarkStudentService markStudentService;
-
-    /**
-     * 详情列表
-     */
-    @ApiOperation(value = "详情列表")
-    @RequestMapping(value = "/score", method = RequestMethod.POST)
-    public Result listStudentScore(@ApiParam(value = "考试ID", required = true) @RequestParam Long examId, @ApiParam(value = "试卷编号", required = true) @RequestParam String paperNumber,
-                                   @ApiParam(value = "学院") @RequestParam(required = false) String college, @ApiParam(value = "专业") @RequestParam(required = false) String majorName,
-                                   @ApiParam(value = "班级") @RequestParam(required = false) String teachClassName,
-                                   @ApiParam(value = "班级") @RequestParam(required = false) String className, @ApiParam(value = "任课老师") @RequestParam(required = false) String teacher,
-                                   @ApiParam(value = "0:无 1:客观题0分 2:客观题0分,主观题有分 3:主观题0分,客观题有分") @RequestParam(required = false) Integer filter,
-                                   @ApiParam(value = "状态") @RequestParam(required = false) String status, @ApiParam(value = "是否违纪") @RequestParam(required = false) Boolean breach,
-                                   @ApiParam(value = "总分开始") @RequestParam(required = false) Double startScore, @ApiParam(value = "总分结束") @RequestParam(required = false) Double endScore,
-                                   @ApiParam(value = "主观题总分开始") @RequestParam(required = false) Double subjectiveStartScore,
-                                   @ApiParam(value = "主观题总分结束") @RequestParam(required = false) Double subjectiveEndScore,
-                                   @ApiParam(value = "客观题总分开始") @RequestParam(required = false) Double objectiveStartScore,
-                                   @ApiParam(value = "客观题总分结束") @RequestParam(required = false) Double objectiveEndScore, @ApiParam(value = "小题得分") @RequestParam(required = false) Double subScore,
-                                   @ApiParam(value = "客观题分小于x%") @RequestParam(required = false) Integer objectiveScoreRateLt, @ApiParam(value = "姓名") @RequestParam(required = false) String studentName,
-                                   @ApiParam(value = "学号") @RequestParam(required = false) String studentCode, @ApiParam(value = "排序方式") @RequestParam(required = false) String orderType,
-                                   @ApiParam(value = "排序字段") @RequestParam(required = false) String orderField, @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) Integer pageNumber,
-                                   @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) Integer pageSize) {
-        IPage<StudentScoreDetailDto> scoreListDtoIPage = markStudentService.pageStudentScore(examId, paperNumber,
-                college, majorName,teachClassName, className, teacher, filter, status, breach, startScore, endScore,
-                subjectiveStartScore, subjectiveEndScore, objectiveStartScore, objectiveEndScore, subScore,
-                objectiveScoreRateLt, studentName, studentCode, orderType, orderField, pageNumber, pageSize);
-        return ResultUtil.ok(scoreListDtoIPage);
-    }
-
-    @ApiOperation(value = "客观题统分")
-    @RequestMapping(value = "/objective/calculate", method = RequestMethod.POST)
-    @OperationLogDetail(operationType = OperationTypeEnum.SAVE, detail = "客观题统分操作,考试ID:{{examId}}、试卷编号:{{paperNumber}}")
-    public Result calcObjectiveScore(@ApiParam(value = "考试ID", required = true) @RequestParam Long examId, @ApiParam(value = "试卷编号", required = true) @RequestParam String paperNumber) {
-        return ResultUtil.ok(markStudentService.calcObjectiveScore(examId, paperNumber));
-    }
+package com.qmth.distributed.print.api.mark;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.qmth.boot.api.constant.ApiConstant;
+import com.qmth.teachcloud.common.annotation.OperationLogDetail;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.enums.log.OperationTypeEnum;
+import com.qmth.teachcloud.common.util.Result;
+import com.qmth.teachcloud.common.util.ResultUtil;
+import com.qmth.teachcloud.mark.dto.mark.score.StudentScoreDetailDto;
+import com.qmth.teachcloud.mark.service.MarkStudentService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+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;
+
+/**
+ * <p>
+ * 考试考生库 前端控制器
+ * </p>
+ *
+ * @author xf
+ * @since 2023-09-22
+ */
+@Api(tags = "评卷-考生")
+@RestController
+@RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + SystemConstant.PREFIX_URL_MARK + "/student")
+public class MarkStudentController {
+
+    @Resource
+    MarkStudentService markStudentService;
+
+    @ApiOperation(value = "详情列表")
+    @RequestMapping(value = "/score", method = RequestMethod.POST)
+    public Result listStudentScore(@ApiParam(value = "考试ID", required = true) @RequestParam Long examId, @ApiParam(value = "试卷编号", required = true) @RequestParam String paperNumber,
+                                   @ApiParam(value = "学院") @RequestParam(required = false) String college, @ApiParam(value = "专业") @RequestParam(required = false) String majorName,
+                                   @ApiParam(value = "班级") @RequestParam(required = false) String teachClassName,
+                                   @ApiParam(value = "班级") @RequestParam(required = false) String className, @ApiParam(value = "任课老师") @RequestParam(required = false) String teacher,
+                                   @ApiParam(value = "0:无 1:客观题0分 2:客观题0分,主观题有分 3:主观题0分,客观题有分") @RequestParam(required = false) Integer filter,
+                                   @ApiParam(value = "状态") @RequestParam(required = false) String status, @ApiParam(value = "是否违纪") @RequestParam(required = false) Boolean breach,
+                                   @ApiParam(value = "总分开始") @RequestParam(required = false) Double startScore, @ApiParam(value = "总分结束") @RequestParam(required = false) Double endScore,
+                                   @ApiParam(value = "主观题总分开始") @RequestParam(required = false) Double subjectiveStartScore,
+                                   @ApiParam(value = "主观题总分结束") @RequestParam(required = false) Double subjectiveEndScore,
+                                   @ApiParam(value = "客观题总分开始") @RequestParam(required = false) Double objectiveStartScore,
+                                   @ApiParam(value = "客观题总分结束") @RequestParam(required = false) Double objectiveEndScore, @ApiParam(value = "小题得分") @RequestParam(required = false) Double subScore,
+                                   @ApiParam(value = "客观题分小于x%") @RequestParam(required = false) Integer objectiveScoreRateLt, @ApiParam(value = "姓名") @RequestParam(required = false) String studentName,
+                                   @ApiParam(value = "学号") @RequestParam(required = false) String studentCode, @ApiParam(value = "排序方式") @RequestParam(required = false) String orderType,
+                                   @ApiParam(value = "排序字段") @RequestParam(required = false) String orderField, @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) Integer pageNumber,
+                                   @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) Integer pageSize) {
+        IPage<StudentScoreDetailDto> scoreListDtoIPage = markStudentService.pageStudentScore(examId, paperNumber,
+                college, majorName, teachClassName, className, teacher, filter, status, breach, startScore, endScore,
+                subjectiveStartScore, subjectiveEndScore, objectiveStartScore, objectiveEndScore, subScore,
+                objectiveScoreRateLt, studentName, studentCode, orderType, orderField, pageNumber, pageSize);
+        return ResultUtil.ok(scoreListDtoIPage);
+    }
+
+    @ApiOperation(value = "客观题统分")
+    @RequestMapping(value = "/objective/calculate", method = RequestMethod.POST)
+    @OperationLogDetail(operationType = OperationTypeEnum.SAVE, detail = "客观题统分操作,考试ID:{{examId}}、试卷编号:{{paperNumber}}")
+    public Result calcObjectiveScore(@ApiParam(value = "考试ID", required = true) @RequestParam Long examId, @ApiParam(value = "试卷编号", required = true) @RequestParam String paperNumber) {
+        return ResultUtil.ok(markStudentService.calcObjectiveScore(examId, paperNumber));
+    }
+
+    @ApiOperation(value = "成绩导出")
+    @RequestMapping(value = "score/export", method = RequestMethod.POST)
+    public void scoreExport(@ApiParam(value = "考试ID", required = true) @RequestParam Long examId, @ApiParam(value = "试卷编号", required = true) @RequestParam String paperNumber,
+                            @ApiParam(value = "学院") @RequestParam(required = false) String college, @ApiParam(value = "专业") @RequestParam(required = false) String majorName,
+                            @ApiParam(value = "班级") @RequestParam(required = false) String teachClassName,
+                            @ApiParam(value = "班级") @RequestParam(required = false) String className, @ApiParam(value = "任课老师") @RequestParam(required = false) String teacher,
+                            @ApiParam(value = "0:无 1:客观题0分 2:客观题0分,主观题有分 3:主观题0分,客观题有分") @RequestParam(required = false) Integer filter,
+                            @ApiParam(value = "状态") @RequestParam(required = false) String status, @ApiParam(value = "是否违纪") @RequestParam(required = false) Boolean breach,
+                            @ApiParam(value = "总分开始") @RequestParam(required = false) Double startScore, @ApiParam(value = "总分结束") @RequestParam(required = false) Double endScore,
+                            @ApiParam(value = "主观题总分开始") @RequestParam(required = false) Double subjectiveStartScore,
+                            @ApiParam(value = "主观题总分结束") @RequestParam(required = false) Double subjectiveEndScore,
+                            @ApiParam(value = "客观题总分开始") @RequestParam(required = false) Double objectiveStartScore,
+                            @ApiParam(value = "客观题总分结束") @RequestParam(required = false) Double objectiveEndScore, @ApiParam(value = "小题得分") @RequestParam(required = false) Double subScore,
+                            @ApiParam(value = "客观题分小于x%") @RequestParam(required = false) Integer objectiveScoreRateLt, @ApiParam(value = "姓名") @RequestParam(required = false) String studentName,
+                            @ApiParam(value = "学号") @RequestParam(required = false) String studentCode, @ApiParam(value = "排序方式") @RequestParam(required = false) String orderType,
+                            @ApiParam(value = "排序字段") @RequestParam(required = false) String orderField) {
+        markStudentService.pageStudentScoreExport(examId, paperNumber,
+                college, majorName, teachClassName, className, teacher, filter, status, breach, startScore, endScore,
+                subjectiveStartScore, subjectiveEndScore, objectiveStartScore, objectiveEndScore, subScore,
+                objectiveScoreRateLt, studentName, studentCode, orderType, orderField);
+    }
 }

+ 25 - 11
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/bean/archivescore/ArchiveStudentQuery.java

@@ -1,11 +1,14 @@
 package com.qmth.teachcloud.mark.bean.archivescore;
 
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
 import com.qmth.teachcloud.mark.utils.PagerQuery;
 
 import javax.validation.constraints.NotNull;
 
 public class ArchiveStudentQuery extends PagerQuery {
     @NotNull(message = "考试Id不能为空")
+    @JsonSerialize(using = ToStringSerializer.class)
     private Long examId;
     @NotNull(message = "paperNumber不能为空")
     private String paperNumber;
@@ -36,6 +39,17 @@ public class ArchiveStudentQuery extends PagerQuery {
     private String orderType;
     private String orderField;
 
+    public ArchiveStudentQuery() {
+
+    }
+
+    public ArchiveStudentQuery(Long examId, String orderType, String orderField, String paperNumber) {
+        this.examId = examId;
+        this.orderType = orderType;
+        this.orderField = orderField;
+        this.paperNumber = paperNumber;
+    }
+
     public Long getExamId() {
         return examId;
     }
@@ -165,18 +179,18 @@ public class ArchiveStudentQuery extends PagerQuery {
     }
 
     public String getOrderType() {
-		return orderType;
-	}
+        return orderType;
+    }
 
-	public void setOrderType(String orderType) {
-		this.orderType = orderType;
-	}
+    public void setOrderType(String orderType) {
+        this.orderType = orderType;
+    }
 
-	public String getOrderField() {
-		return orderField;
-	}
+    public String getOrderField() {
+        return orderField;
+    }
 
-	public void setOrderField(String orderField) {
-		this.orderField = orderField;
-	}
+    public void setOrderField(String orderField) {
+        this.orderField = orderField;
+    }
 }

+ 52 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/dto/mark/score/StudentScoreDetailDto.java

@@ -2,14 +2,19 @@ package com.qmth.teachcloud.mark.dto.mark.score;
 
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.qmth.teachcloud.common.entity.MarkQuestion;
 import com.qmth.teachcloud.common.enums.BasicExamStudentStatusEnum;
 import com.qmth.teachcloud.common.enums.ScanStatus;
 import com.qmth.teachcloud.common.enums.mark.SubjectiveStatus;
+import com.qmth.teachcloud.mark.dto.mark.ScoreItem;
+import org.apache.commons.lang3.StringUtils;
 
+import java.util.LinkedList;
 import java.util.List;
 
 public class StudentScoreDetailDto {
 
+    public static final String SPLIT = ";";
     @JsonSerialize(using = ToStringSerializer.class)
     private Long studentId;
     @JsonSerialize(using = ToStringSerializer.class)
@@ -49,6 +54,24 @@ public class StudentScoreDetailDto {
     private Boolean objectiveCheckFlag;
     private BasicExamStudentStatusEnum studentStatus;
     private String studentStatusDisplay;
+    private String collegeName;
+    private BasicExamStudentStatusEnum status;
+
+    public BasicExamStudentStatusEnum getStatus() {
+        return status;
+    }
+
+    public void setStatus(BasicExamStudentStatusEnum status) {
+        this.status = status;
+    }
+
+    public String getCollegeName() {
+        return collegeName;
+    }
+
+    public void setCollegeName(String collegeName) {
+        this.collegeName = collegeName;
+    }
 
     public Long getStudentId() {
         return studentId;
@@ -329,4 +352,33 @@ public class StudentScoreDetailDto {
     public void setStudentStatusDisplay(String studentStatusDisplay) {
         this.studentStatusDisplay = studentStatusDisplay;
     }
+
+    public List<ScoreItem> getScoreList(boolean objective, List<MarkQuestion> questionList) {
+        List<ScoreItem> scoreList = new LinkedList<ScoreItem>();
+        try {
+            String[] values = StringUtils.split(objective ? objectiveScoreList : subjectiveScoreList, SPLIT);
+            int i = 0;
+            for (String value : values) {
+                i++;
+                if (questionList.size() < i) {
+                    break;
+                }
+                MarkQuestion question = questionList.get(i - 1);
+                if (question.getTotalScore() == null || question.getTotalScore() == 0) {
+                    continue;
+                }
+                ScoreItem item = ScoreItem.parse(value, objective);
+                item.setObjective(objective);
+                item.setMainNumber(question.getMainNumber());
+                item.setTitle(question.getMainTitle());
+                item.setTotalScore(question.getTotalScore());
+                item.setSubNumber(question.getSubNumber());
+                if (item != null) {
+                    scoreList.add(item);
+                }
+            }
+        } catch (Exception e) {
+        }
+        return scoreList;
+    }
 }

+ 66 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/dto/mark/score/StudentScoreDetailExportDto.java

@@ -0,0 +1,66 @@
+package com.qmth.teachcloud.mark.dto.mark.score;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+public class StudentScoreDetailExportDto implements Serializable {
+
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long examId;
+    private String paperNumber;
+    private String teachClassName;
+
+    public StudentScoreDetailExportDto() {
+
+    }
+
+    public StudentScoreDetailExportDto(StudentScoreDetailDto studentScoreDetailDto) {
+        this.examId = studentScoreDetailDto.getExamId();
+        this.paperNumber = studentScoreDetailDto.getPaperNumber();
+        this.teachClassName = studentScoreDetailDto.getTeachClassName();
+    }
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public String getPaperNumber() {
+        return paperNumber;
+    }
+
+    public void setPaperNumber(String paperNumber) {
+        this.paperNumber = paperNumber;
+    }
+
+    public String getTeachClassName() {
+        return teachClassName;
+    }
+
+    public void setTeachClassName(String teachClassName) {
+        this.teachClassName = teachClassName;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        StudentScoreDetailExportDto that = (StudentScoreDetailExportDto) o;
+        return Objects.equals(examId, that.examId) && Objects.equals(paperNumber, that.paperNumber) && Objects.equals(teachClassName, that.teachClassName);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(examId, paperNumber, teachClassName);
+    }
+}

+ 132 - 91
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/mapper/MarkStudentMapper.java

@@ -1,91 +1,132 @@
-package com.qmth.teachcloud.mark.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.bean.dto.DataPermissionRule;
-import com.qmth.teachcloud.common.entity.BasicTeachClazz;
-import com.qmth.teachcloud.mark.bean.archivescore.*;
-import com.qmth.teachcloud.mark.bean.scananswer.AnswerQueryDomain;
-import com.qmth.teachcloud.mark.bean.scananswer.AnswerQueryVo;
-import com.qmth.teachcloud.mark.bean.student.MarkStudentQuery;
-import com.qmth.teachcloud.mark.bean.student.StudentQuery;
-import com.qmth.teachcloud.mark.bean.student.StudentVo;
-import com.qmth.teachcloud.mark.dto.UnexistStudentDto;
-import com.qmth.teachcloud.mark.dto.mark.MarkStudentVo;
-import com.qmth.teachcloud.mark.dto.mark.score.StudentScoreDetailDto;
-import com.qmth.teachcloud.mark.entity.MarkStudent;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-
-/**
- * <p>
- * 考试考生库 Mapper 接口
- * </p>
- *
- * @author xf
- * @since 2023-09-22
- */
-public interface MarkStudentMapper extends BaseMapper<MarkStudent> {
-
-    IPage<StudentScoreDetailDto> pageStudentScore(@Param("page") Page<StudentScoreDetailDto> page, @Param("examId") Long examId, @Param("paperNumber") String paperNumber, @Param("college") String college,
-                                                  @Param("majorName") String majorName, @Param("teachClassName") String teachClassName, @Param("className") String className, @Param("teacher") String teacher, @Param("filter") Integer filter,
-                                                  @Param("status") String status, @Param("breach") Boolean breach, @Param("startScore") Double startScore, @Param("endScore") Double endScore,
-                                                  @Param("subjectiveStartScore") Double subjectiveStartScore, @Param("subjectiveEndScore") Double subjectiveEndScore,
-                                                  @Param("objectiveStartScore") Double objectiveStartScore,
-                                                  @Param("objectiveEndScore") Double objectiveEndScore, @Param("subScore") Double subScore, @Param("objectiveScoreLt") Double objectiveScoreLt,
-                                                  @Param("studentName") String studentName, @Param("studentCode") String studentCode, @Param("orderType") String orderType,
-                                                  @Param("orderField") String orderField, @Param("dpr") DataPermissionRule dpr);
-
-    List<MarkStudent> listAbsentOrBreachMarkTaskStudent(@Param("examId") Long examId,
-                                                        @Param("paperNumber") String paperNumber);
-
-    IPage<MarkStudent> listUnMarkTaskStudent(@Param("page") Page<MarkStudent> page, @Param("examId") Long examId,
-                                             @Param("paperNumber") String paperNumber, @Param("groupNumber") Integer groupNumber);
-
-    StudentVo findOne(@Param("query") StudentQuery query);
-
-    IPage<AnswerQueryVo> queryPage(Page<AnswerQueryVo> page, @Param("query") AnswerQueryDomain query, @Param("dpr") DataPermissionRule dpr);
-
-    List<String> querySummary(@Param("query") AnswerQueryDomain query, @Param("dpr") DataPermissionRule dpr);
-
-    List<Long> findIdByExamIdAndPaperNumber(@Param("examId") Long examId, @Param("paperNumber") String paperNumber);
-
-    List<ArchiveStudentVo> studentList(@Param("schoolId") Long schoolId, @Param("req") ArchiveStudentQuery query, @Param("dpr") DataPermissionRule dpr);
-
-    OverViewVo overview(@Param("schoolId") Long schoolId, @Param("req") ArchiveStudentQuery query, @Param("dpr") DataPermissionRule dpr);
-
-    int getCountByScoreRange(@Param("examId") Long examId, @Param("paperNumber") String paperNumber,
-                             @Param("start") Double start, @Param("end") Double end);
-
-    List<CollegeVo> college(@Param("schoolId") Long schoolId, @Param("req") ArchiveStudentQuery query, @Param("dpr") DataPermissionRule dpr);
-
-    List<ClassVo> classData(@Param("schoolId") Long schoolId, @Param("req") ArchiveStudentQuery query, @Param("dpr") DataPermissionRule dpr);
-
-    List<TeacherVo> teacher(@Param("schoolId") Long schoolId, @Param("req") ArchiveStudentQuery query, @Param("dpr") DataPermissionRule dpr);
-
-    List<UnexistStudentDto> listUnexistStudentByExamIdAndCoursePaperId(@Param("examId") Long examId, @Param("courseId") Long courseId, @Param("coursePaperId") String coursePaperId,
-                                                                       @Param("status") String status, @Param("dpr") DataPermissionRule dpr);
-
-    IPage<ArchiveStudentVo> studentList(@Param("page") Page<ArchiveStudentVo> page, @Param("schoolId") Long schoolId, @Param("req") ArchiveStudentQuery query, @Param("dpr") DataPermissionRule dpr);
-
-    List<TeacherClassVo> teacherClass(@Param("schoolId") Long schoolId, @Param("req") ArchiveStudentQuery query, @Param("dpr") DataPermissionRule dpr);
-
-    int selectCountByQuery(@Param("markStudent") MarkStudent markStudent, @Param("dpr") DataPermissionRule dpr);
-
-    int countAssigned(@Param("markStudent") MarkStudent markStudent, @Param("dpr") DataPermissionRule dpr);
-
-    List<MarkStudent> listScanCollegeByExamIdAndCourseCodeAndCoursePaperId(@Param("examId") Long examId, @Param("courseCode") String courseCode, @Param("coursePaperId") String coursePaperId,
-                                                                           @Param("status") String status, @Param("dpr") DataPermissionRule dpr);
-
-    BasicTeachClazz getBasicTeachClazzById(Long clazzId);
-
-    Integer maxCardNumber(@Param("examId") Long examId, @Param("paperNumber") String paperNumber, @Param("paperType") String paperType);
-
-    MarkStudent selectByExamIdAndCoursePaperIdAndStudentCode(@Param("examId") Long examId, @Param("coursePaperId") String coursePaperId, @Param("studentCode") String studentCode);
-
-    List<MarkStudentVo> listMarkStudentVo(@Param("markStudentQuery") MarkStudentQuery markStudentQuery);
-
-    IPage<MarkStudentVo> listMarkStudentVo(@Param("page") Page<MarkStudentVo> page, @Param("markStudentQuery") MarkStudentQuery markStudentQuery);
-}
+package com.qmth.teachcloud.mark.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.bean.dto.DataPermissionRule;
+import com.qmth.teachcloud.common.entity.BasicTeachClazz;
+import com.qmth.teachcloud.mark.bean.archivescore.*;
+import com.qmth.teachcloud.mark.bean.scananswer.AnswerQueryDomain;
+import com.qmth.teachcloud.mark.bean.scananswer.AnswerQueryVo;
+import com.qmth.teachcloud.mark.bean.student.MarkStudentQuery;
+import com.qmth.teachcloud.mark.bean.student.StudentQuery;
+import com.qmth.teachcloud.mark.bean.student.StudentVo;
+import com.qmth.teachcloud.mark.dto.UnexistStudentDto;
+import com.qmth.teachcloud.mark.dto.mark.MarkStudentVo;
+import com.qmth.teachcloud.mark.dto.mark.score.StudentScoreDetailDto;
+import com.qmth.teachcloud.mark.entity.MarkStudent;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 考试考生库 Mapper 接口
+ * </p>
+ *
+ * @author xf
+ * @since 2023-09-22
+ */
+public interface MarkStudentMapper extends BaseMapper<MarkStudent> {
+
+    IPage<StudentScoreDetailDto> pageStudentScore(@Param("page") Page<StudentScoreDetailDto> page, @Param("examId") Long examId, @Param("paperNumber") String paperNumber, @Param("college") String college,
+                                                  @Param("majorName") String majorName, @Param("teachClassName") String teachClassName, @Param("className") String className, @Param("teacher") String teacher, @Param("filter") Integer filter,
+                                                  @Param("status") String status, @Param("breach") Boolean breach, @Param("startScore") Double startScore, @Param("endScore") Double endScore,
+                                                  @Param("subjectiveStartScore") Double subjectiveStartScore, @Param("subjectiveEndScore") Double subjectiveEndScore,
+                                                  @Param("objectiveStartScore") Double objectiveStartScore,
+                                                  @Param("objectiveEndScore") Double objectiveEndScore, @Param("subScore") Double subScore, @Param("objectiveScoreLt") Double objectiveScoreLt,
+                                                  @Param("studentName") String studentName, @Param("studentCode") String studentCode, @Param("orderType") String orderType,
+                                                  @Param("orderField") String orderField, @Param("dpr") DataPermissionRule dpr);
+
+    /**
+     * 评卷管理/成绩检查/成绩详情导出
+     *
+     * @param examId
+     * @param paperNumber
+     * @param college
+     * @param majorName
+     * @param teachClassName
+     * @param className
+     * @param teacher
+     * @param filter
+     * @param status
+     * @param breach
+     * @param startScore
+     * @param endScore
+     * @param subjectiveStartScore
+     * @param subjectiveEndScore
+     * @param objectiveStartScore
+     * @param objectiveEndScore
+     * @param subScore
+     * @param objectiveScoreLt
+     * @param studentName
+     * @param studentCode
+     * @param orderType
+     * @param orderField
+     * @param dpr
+     * @return
+     */
+    List<StudentScoreDetailDto> pageStudentScoreExport(@Param("examId") Long examId, @Param("paperNumber") String paperNumber, @Param("college") String college,
+                                                       @Param("majorName") String majorName, @Param("teachClassName") String teachClassName, @Param("className") String className, @Param("teacher") String teacher, @Param("filter") Integer filter,
+                                                       @Param("status") String status, @Param("breach") Boolean breach, @Param("startScore") Double startScore, @Param("endScore") Double endScore,
+                                                       @Param("subjectiveStartScore") Double subjectiveStartScore, @Param("subjectiveEndScore") Double subjectiveEndScore,
+                                                       @Param("objectiveStartScore") Double objectiveStartScore,
+                                                       @Param("objectiveEndScore") Double objectiveEndScore, @Param("subScore") Double subScore, @Param("objectiveScoreLt") Double objectiveScoreLt,
+                                                       @Param("studentName") String studentName, @Param("studentCode") String studentCode, @Param("orderType") String orderType,
+                                                       @Param("orderField") String orderField, @Param("dpr") DataPermissionRule dpr);
+
+    List<MarkStudent> listAbsentOrBreachMarkTaskStudent(@Param("examId") Long examId,
+                                                        @Param("paperNumber") String paperNumber);
+
+    IPage<MarkStudent> listUnMarkTaskStudent(@Param("page") Page<MarkStudent> page, @Param("examId") Long examId,
+                                             @Param("paperNumber") String paperNumber, @Param("groupNumber") Integer groupNumber);
+
+    StudentVo findOne(@Param("query") StudentQuery query);
+
+    IPage<AnswerQueryVo> queryPage(Page<AnswerQueryVo> page, @Param("query") AnswerQueryDomain query, @Param("dpr") DataPermissionRule dpr);
+
+    List<String> querySummary(@Param("query") AnswerQueryDomain query, @Param("dpr") DataPermissionRule dpr);
+
+    List<Long> findIdByExamIdAndPaperNumber(@Param("examId") Long examId, @Param("paperNumber") String paperNumber);
+
+    List<ArchiveStudentVo> studentList(@Param("schoolId") Long schoolId, @Param("req") ArchiveStudentQuery query, @Param("dpr") DataPermissionRule dpr);
+
+    OverViewVo overview(@Param("schoolId") Long schoolId, @Param("req") ArchiveStudentQuery query, @Param("dpr") DataPermissionRule dpr);
+
+    int getCountByScoreRange(@Param("examId") Long examId, @Param("paperNumber") String paperNumber,
+                             @Param("start") Double start, @Param("end") Double end);
+
+    List<CollegeVo> college(@Param("schoolId") Long schoolId, @Param("req") ArchiveStudentQuery query, @Param("dpr") DataPermissionRule dpr);
+
+    List<ClassVo> classData(@Param("schoolId") Long schoolId, @Param("req") ArchiveStudentQuery query, @Param("dpr") DataPermissionRule dpr);
+
+    List<TeacherVo> teacher(@Param("schoolId") Long schoolId, @Param("req") ArchiveStudentQuery query, @Param("dpr") DataPermissionRule dpr);
+
+    List<UnexistStudentDto> listUnexistStudentByExamIdAndCoursePaperId(@Param("examId") Long examId, @Param("courseId") Long courseId, @Param("coursePaperId") String coursePaperId,
+                                                                       @Param("status") String status, @Param("dpr") DataPermissionRule dpr);
+
+    IPage<ArchiveStudentVo> studentList(@Param("page") Page<ArchiveStudentVo> page, @Param("schoolId") Long schoolId, @Param("req") ArchiveStudentQuery query, @Param("dpr") DataPermissionRule dpr);
+
+    List<TeacherClassVo> teacherClass(@Param("schoolId") Long schoolId, @Param("req") ArchiveStudentQuery query, @Param("dpr") DataPermissionRule dpr);
+
+    int selectCountByQuery(@Param("markStudent") MarkStudent markStudent, @Param("dpr") DataPermissionRule dpr);
+
+    int countAssigned(@Param("markStudent") MarkStudent markStudent, @Param("dpr") DataPermissionRule dpr);
+
+    int countAssignedNew(@Param("markStudent") MarkStudent markStudent, @Param("dpr") DataPermissionRule dpr, @Param("teachClassName") String teachClassName);
+
+    List<MarkStudent> listScanCollegeByExamIdAndCourseCodeAndCoursePaperId(@Param("examId") Long examId, @Param("courseCode") String courseCode, @Param("coursePaperId") String coursePaperId,
+                                                                           @Param("status") String status, @Param("dpr") DataPermissionRule dpr);
+
+    BasicTeachClazz getBasicTeachClazzById(Long clazzId);
+
+    Integer maxCardNumber(@Param("examId") Long examId, @Param("paperNumber") String paperNumber, @Param("paperType") String paperType);
+
+    MarkStudent selectByExamIdAndCoursePaperIdAndStudentCode(@Param("examId") Long examId, @Param("coursePaperId") String coursePaperId, @Param("studentCode") String studentCode);
+
+    List<MarkStudentVo> listMarkStudentVo(@Param("markStudentQuery") MarkStudentQuery markStudentQuery);
+
+    IPage<MarkStudentVo> listMarkStudentVo(@Param("page") Page<MarkStudentVo> page, @Param("markStudentQuery") MarkStudentQuery markStudentQuery);
+
+    int countOmrAbsentStudent(@Param("examId") Long examId, @Param("paperNumber") String paperNumber, @Param("paperType") String paperType, @Param("isOmrAbsentConfirm") boolean isOmrAbsentConfirm, @Param("teachClassName") String teachClassName);
+}

+ 45 - 41
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/mapper/ScanOmrTaskMapper.java

@@ -1,41 +1,45 @@
-package com.qmth.teachcloud.mark.mapper;
-
-import java.util.List;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
-import org.apache.ibatis.annotations.Param;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
-import com.qmth.teachcloud.mark.dto.ScanStudentDto;
-import com.qmth.teachcloud.mark.entity.ScanOmrTask;
-import com.qmth.teachcloud.mark.enums.OmrTaskStatus;
-
-/**
- * <p>
- * Mapper 接口
- * </p>
- *
- * @author xf
- * @since 2023-09-22
- */
-public interface ScanOmrTaskMapper extends BaseMapper<ScanOmrTask> {
-
-    List<ScanOmrTask> findUnMarked(@Param(value = "examId") Long examId, @Param(value = "pageNumber") int pageNumber,
-                                   @Param(value = "pageSize") int pageSize, @Param(value = "status") OmrTaskStatus status);
-
-    IPage<ScanStudentDto> listByExamIdAndStatusAndUserId(@Param("page") Page<ScanStudentDto> page,
-                                                         @Param(value = "examId") Long examId,
-                                                         @Param("courseId") Long courseId,
-                                                         @Param("coursePaperId") String coursePaperId,
-                                                         @Param(value = "status") OmrTaskStatus status,
-                                                         @Param("studentCodeOrName") String studentCodeOrName,
-                                                         @Param("markPaperStatus") String markPaperStatus, @Param("dpr") DataPermissionRule dpr);
-
-    int getStudentCountByExamAndStatusAndUserId(@Param(value = "examId") Long examId,
-                                                @Param("courseId") Long courseId, @Param("coursePaperId") String coursePaperId, @Param(value = "status") String status, @Param("markPaperStatus") String markPaperStatus, @Param("dpr") DataPermissionRule dpr);
-
-    int countOmrTask(@Param("scanOmrTask") ScanOmrTask scanOmrTask, @Param("dpr") DataPermissionRule dpr);
-}
+package com.qmth.teachcloud.mark.mapper;
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
+import org.apache.ibatis.annotations.Param;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
+import com.qmth.teachcloud.mark.dto.ScanStudentDto;
+import com.qmth.teachcloud.mark.entity.ScanOmrTask;
+import com.qmth.teachcloud.mark.enums.OmrTaskStatus;
+
+/**
+ * <p>
+ * Mapper 接口
+ * </p>
+ *
+ * @author xf
+ * @since 2023-09-22
+ */
+public interface ScanOmrTaskMapper extends BaseMapper<ScanOmrTask> {
+
+    List<ScanOmrTask> findUnMarked(@Param(value = "examId") Long examId, @Param(value = "pageNumber") int pageNumber,
+                                   @Param(value = "pageSize") int pageSize, @Param(value = "status") OmrTaskStatus status);
+
+    IPage<ScanStudentDto> listByExamIdAndStatusAndUserId(@Param("page") Page<ScanStudentDto> page,
+                                                         @Param(value = "examId") Long examId,
+                                                         @Param("courseId") Long courseId,
+                                                         @Param("coursePaperId") String coursePaperId,
+                                                         @Param(value = "status") OmrTaskStatus status,
+                                                         @Param("studentCodeOrName") String studentCodeOrName,
+                                                         @Param("markPaperStatus") String markPaperStatus, @Param("dpr") DataPermissionRule dpr);
+
+    int getStudentCountByExamAndStatusAndUserId(@Param(value = "examId") Long examId,
+                                                @Param("courseId") Long courseId, @Param("coursePaperId") String coursePaperId, @Param(value = "status") String status, @Param("markPaperStatus") String markPaperStatus, @Param("dpr") DataPermissionRule dpr);
+
+    int getStudentCountByExamAndStatusAndUserIdNew(@Param(value = "examId") Long examId,
+                                                @Param("courseId") Long courseId, @Param("coursePaperId") String coursePaperId, @Param(value = "status") String status, @Param("markPaperStatus") String markPaperStatus, @Param("dpr") DataPermissionRule dpr,
+                                                   @Param("teachClassName") String teachClassName);
+
+    int countOmrTask(@Param("scanOmrTask") ScanOmrTask scanOmrTask, @Param("dpr") DataPermissionRule dpr);
+}

+ 95 - 85
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkPaperService.java

@@ -1,85 +1,95 @@
-package com.qmth.teachcloud.mark.service;
-
-import java.util.List;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
-import com.qmth.teachcloud.common.bean.dto.mark.MarkSettingDto;
-import com.qmth.teachcloud.common.bean.params.mark.setting.MarkPaperSettingParam;
-import com.qmth.teachcloud.common.enums.mark.MarkPaperStatus;
-import com.qmth.teachcloud.mark.bean.document.ArchivePaperQuery;
-import com.qmth.teachcloud.mark.bean.document.ArchivePaperVo;
-import com.qmth.teachcloud.mark.bean.archivescore.ArchiveScoreQuery;
-import com.qmth.teachcloud.mark.bean.archivescore.ArchiveScoreVo;
-import com.qmth.teachcloud.mark.dto.mark.score.CheckScoreListDto;
-import com.qmth.teachcloud.mark.dto.mark.score.MarkPaperPackageDto;
-import com.qmth.teachcloud.mark.dto.mark.score.SettingDto;
-import com.qmth.teachcloud.mark.entity.MarkPaper;
-
-/**
- * <p>
- * 考试科目表 服务类
- * </p>
- *
- * @author xf
- * @since 2023-09-22
- */
-public interface MarkPaperService extends IService<MarkPaper> {
-
-    IPage<MarkSettingDto> listPaperSetting(Long examId, Long courseId, String paperNumber, Boolean groupStatus, Integer pageNumber, Integer pageSize);
-
-    MarkPaper getByExamIdAndPaperNumber(Long examId, String paperNumber);
-
-    MarkPaper getByExamIdAndPaperNumberAndPaperType(Long examId, String paperNumber, String paperType);
-
-    void savePaperSetting(MarkPaper markPaper);
-
-    void saveBatchPaperSetting(MarkPaperSettingParam markPaperSettingParam);
-
-    Boolean finishPaper(Long examId, List<String> paperNumbers, MarkPaperStatus status);
-
-    List<MarkPaper> listQualityMarkPaperByStatus(MarkPaperStatus formal, int uploadCount);
-
-    int getCourseCount(Long id, Long courseId, String coursePaperId, MarkPaperStatus status, DataPermissionRule dpr);
-
-    int getPaperNumberCount(Long id, Long courseId, String coursePaperId, MarkPaperStatus status, DataPermissionRule dpr);
-
-    IPage<CheckScoreListDto> listStudentScoreList(Long examId, Long courseId, String paperNumber, Integer pageNumber,
-            Integer pageSize);
-
-    void updateStatus(Long examId, String paperNumber, MarkPaperStatus newStatus, MarkPaperStatus currentStatus);
-
-    void updateUploadCount(Long examId, String paperNumber, int countUploaded);
-
-    IPage<MarkPaperPackageDto> listPackage(Long examId, String paperNumber, String packageCode, Integer pageNumber,
-            Integer pageSize);
-
-    MarkPaper getByExamIdAndCoursePaperId(Long examId, String coursePaperId);
-
-    List<MarkPaper> listByExamId(Long examId, MarkPaperStatus status, DataPermissionRule dpr);
-
-    void updateGroupStatusByExamIdAndPaperNumber(boolean groupStatus, Long examId, String paperNumber);
-
-    int countByPropositionTeacherId(boolean status);
-
-    void updateStudentCountByExamIdAndPaperNumberAndPaperType(Long examId, String paperNumber, String paperType);
-
-    SettingDto getSetting(Long examId, String paperNumber);
-
-    IPage<ArchiveScoreVo> scoreList(ArchiveScoreQuery query);
-
-    void deleteByExamIdAndPaperNumber(Long examId, String paperNumber);
-
-    void updateAbsentCount(Long examId, String paperNumber, int absentCount);
-
-    IPage<ArchivePaperVo> documentList(ArchivePaperQuery query);
-
-    /**
-     * 根据考试id查询markPaper信息(只查课程信息和试卷编号)
-     *
-     * @param examId 考试id
-     * @return List<MarkPaper>
-     */
-    List<MarkPaper> findMarkPaperListByExamId(Long examId);
-}
+package com.qmth.teachcloud.mark.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
+import com.qmth.teachcloud.common.bean.dto.mark.MarkSettingDto;
+import com.qmth.teachcloud.common.bean.params.mark.setting.MarkPaperSettingParam;
+import com.qmth.teachcloud.common.enums.mark.MarkPaperStatus;
+import com.qmth.teachcloud.mark.bean.archivescore.ArchiveScoreQuery;
+import com.qmth.teachcloud.mark.bean.archivescore.ArchiveScoreVo;
+import com.qmth.teachcloud.mark.bean.document.ArchivePaperQuery;
+import com.qmth.teachcloud.mark.bean.document.ArchivePaperVo;
+import com.qmth.teachcloud.mark.dto.mark.score.CheckScoreListDto;
+import com.qmth.teachcloud.mark.dto.mark.score.MarkPaperPackageDto;
+import com.qmth.teachcloud.mark.dto.mark.score.SettingDto;
+import com.qmth.teachcloud.mark.entity.MarkPaper;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 考试科目表 服务类
+ * </p>
+ *
+ * @author xf
+ * @since 2023-09-22
+ */
+public interface MarkPaperService extends IService<MarkPaper> {
+
+    IPage<MarkSettingDto> listPaperSetting(Long examId, Long courseId, String paperNumber, Boolean groupStatus, Integer pageNumber, Integer pageSize);
+
+    MarkPaper getByExamIdAndPaperNumber(Long examId, String paperNumber);
+
+    MarkPaper getByExamIdAndPaperNumberAndPaperType(Long examId, String paperNumber, String paperType);
+
+    void savePaperSetting(MarkPaper markPaper);
+
+    void saveBatchPaperSetting(MarkPaperSettingParam markPaperSettingParam);
+
+    Boolean finishPaper(Long examId, List<String> paperNumbers, MarkPaperStatus status);
+
+    /**
+     * 校验试卷
+     *
+     * @param examId
+     * @param paperNumber
+     * @param teachClassName
+     * @return
+     */
+    Boolean finishPaper(Long examId, String paperNumber, String teachClassName);
+
+    List<MarkPaper> listQualityMarkPaperByStatus(MarkPaperStatus formal, int uploadCount);
+
+    int getCourseCount(Long id, Long courseId, String coursePaperId, MarkPaperStatus status, DataPermissionRule dpr);
+
+    int getPaperNumberCount(Long id, Long courseId, String coursePaperId, MarkPaperStatus status, DataPermissionRule dpr);
+
+    IPage<CheckScoreListDto> listStudentScoreList(Long examId, Long courseId, String paperNumber, Integer pageNumber,
+                                                  Integer pageSize);
+
+    void updateStatus(Long examId, String paperNumber, MarkPaperStatus newStatus, MarkPaperStatus currentStatus);
+
+    void updateUploadCount(Long examId, String paperNumber, int countUploaded);
+
+    IPage<MarkPaperPackageDto> listPackage(Long examId, String paperNumber, String packageCode, Integer pageNumber,
+                                           Integer pageSize);
+
+    MarkPaper getByExamIdAndCoursePaperId(Long examId, String coursePaperId);
+
+    List<MarkPaper> listByExamId(Long examId, MarkPaperStatus status, DataPermissionRule dpr);
+
+    void updateGroupStatusByExamIdAndPaperNumber(boolean groupStatus, Long examId, String paperNumber);
+
+    int countByPropositionTeacherId(boolean status);
+
+    void updateStudentCountByExamIdAndPaperNumberAndPaperType(Long examId, String paperNumber, String paperType);
+
+    SettingDto getSetting(Long examId, String paperNumber);
+
+    IPage<ArchiveScoreVo> scoreList(ArchiveScoreQuery query);
+
+    void deleteByExamIdAndPaperNumber(Long examId, String paperNumber);
+
+    void updateAbsentCount(Long examId, String paperNumber, int absentCount);
+
+    IPage<ArchivePaperVo> documentList(ArchivePaperQuery query);
+
+    /**
+     * 根据考试id查询markPaper信息(只查课程信息和试卷编号)
+     *
+     * @param examId 考试id
+     * @return List<MarkPaper>
+     */
+    List<MarkPaper> findMarkPaperListByExamId(Long examId);
+}

+ 223 - 186
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkStudentService.java

@@ -1,186 +1,223 @@
-package com.qmth.teachcloud.mark.service;
-
-import java.util.List;
-import java.util.Set;
-
-import javax.servlet.http.HttpServletResponse;
-import javax.validation.constraints.NotNull;
-
-import com.alibaba.fastjson.JSONObject;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
-import com.qmth.teachcloud.common.entity.BasicExam;
-import com.qmth.teachcloud.common.entity.BasicExamStudent;
-import com.qmth.teachcloud.common.entity.SysUser;
-import com.qmth.teachcloud.common.enums.ScanStatus;
-import com.qmth.teachcloud.common.enums.mark.MarkPaperStatus;
-import com.qmth.teachcloud.common.enums.mark.SubjectiveStatus;
-import com.qmth.teachcloud.mark.bean.UpdateTimeVo;
-import com.qmth.teachcloud.mark.bean.archivescore.ArchiveStudentQuery;
-import com.qmth.teachcloud.mark.bean.archivescore.ArchiveStudentVo;
-import com.qmth.teachcloud.mark.bean.archivescore.MarkStudentScoreVo;
-import com.qmth.teachcloud.mark.bean.archivescore.ScoreReportVo;
-import com.qmth.teachcloud.mark.bean.omredit.OmrEditDomain;
-import com.qmth.teachcloud.mark.bean.scananswer.AnswerQueryDomain;
-import com.qmth.teachcloud.mark.bean.scananswer.AnswerQueryVo;
-import com.qmth.teachcloud.mark.bean.scanexaminfo.ScanExamCheckInfoVo;
-import com.qmth.teachcloud.mark.bean.scanexaminfo.ScanExamInfoVo;
-import com.qmth.teachcloud.mark.bean.student.AbsentManualUpdateVo;
-import com.qmth.teachcloud.mark.bean.student.MarkStudentQuery;
-import com.qmth.teachcloud.mark.bean.student.StudentQuery;
-import com.qmth.teachcloud.mark.bean.student.StudentVo;
-import com.qmth.teachcloud.mark.dto.mark.MarkStudentVo;
-import com.qmth.teachcloud.mark.dto.mark.manage.Task;
-import com.qmth.teachcloud.mark.dto.mark.score.SheetUrlDto;
-import com.qmth.teachcloud.mark.dto.mark.score.StudentObjectiveDetailDto;
-import com.qmth.teachcloud.mark.dto.mark.score.StudentScoreDetailDto;
-import com.qmth.teachcloud.mark.entity.MarkPaper;
-import com.qmth.teachcloud.mark.entity.MarkStudent;
-import com.qmth.teachcloud.mark.entity.ScanStudentPaper;
-import com.qmth.teachcloud.mark.params.MarkHeaderResult;
-import org.apache.ibatis.annotations.Param;
-
-/**
- * <p>
- * 考试考生库 服务类
- * </p>
- *
- * @author xf
- * @since 2023-09-22
- */
-public interface MarkStudentService extends IService<MarkStudent> {
-
-    List<String> listClassByExamIdAndCourseCode(Long examId, String paperNumber);
-
-    void updateSubjectiveStatusAndScore(Long studentId, SubjectiveStatus status, Double score, String scoreList);
-
-    void updateSubjectiveStatusAndScore(Long examId, String paperNumber, SubjectiveStatus status, Double score,
-                                        String scoreList);
-
-    ScanExamInfoVo getScanExamInfo(BasicExam exam, Long courseId, String coursePaperId);
-
-    IPage<StudentScoreDetailDto> pageStudentScore(Long examId, String paperNumber, String college, String majorName,String teachClassName,
-                                                  String className, String teacher, Integer filter, String status, Boolean breach, Double startScore, Double endScore,
-                                                  Double subjectiveStartScore, Double subjectiveEndScore, Double objectiveStartScore, Double objectiveEndScore,
-                                                  Double subScore, Integer objectiveScoreRateLt, String studentName, String studentCode, String orderType,
-                                                  String orderField, Integer pageNumber, Integer pageSize);
-
-    List<SheetUrlDto> buildSheetUrls(Long studentId);
-
-    ScanExamCheckInfoVo checkInfo(BasicExam exam, Long courseId, String coursePaperId);
-
-    /**
-     * 根据考生当前绑定的paper刷新考生状态,需要在外部调用处对考生上锁
-     */
-    void updateStudentByPaper(@NotNull Long userId, @NotNull Long studentId, @NotNull boolean updateOmrTask);
-
-    MarkStudent findByExamIdAndCoursePaperIdAndStudentCode(Long examId, String coursePaperId, String studentCode);
-
-    MarkStudent findByExamIdAndPaperNumberAndStudentCode(Long examId, String paperNumber, String studentCode);
-
-    List<MarkStudent> listByStudentId(Long studentId);
-
-    StudentObjectiveDetailDto getObjectiveInspectedTask(Long studentId);
-
-    Boolean saveObjectiveInspectedTask(Long studentId, String answers);
-
-    int countUploadedByExamIdAndPaperNumber(Long examId, String paperNumber);
-
-    boolean updateScanInfo(MarkStudent student);
-
-    List<MarkStudent> listAbsentOrBreachMarkTaskStudent(Long examId, String paperNumber);
-
-    List<MarkStudent> listUnMarkTaskStudent(Long examId, String paperNumber, Integer groupNumber, int pageSize);
-
-    boolean saveUploadStudent(MarkStudent student);
-
-    void calculateObjectiveScore(MarkStudent student);
-
-    void updateStudentAndPaper(SysUser user, Long studentId, List<ScanStudentPaper> studentPaperList);
-
-    StudentVo findOne(StudentQuery query);
-
-    int countByExamIdAndSecretNumber(Long examId, String secretNumber);
-
-    List<MarkStudent> listByExamIdAndCoursePaperId(Long examId, String coursePaperId);
-
-    IPage<AnswerQueryVo> query(AnswerQueryDomain query);
-
-    List<String> summary(AnswerQueryDomain query);
-
-    UpdateTimeVo omrEdit(Long userId, OmrEditDomain domain);
-
-    long countByExamIdAndPaperNumber(Long examId, String paperNumber, String paperType);
-
-    AbsentManualUpdateVo absentManualUpdate(Long examId, String coursePaperId, String studentCode, ScanStatus status);
-
-    UpdateTimeVo confirm(Long examId, String coursePaperId, String studentCode, Boolean omrAbsent);
-
-    List<Long> findIdByExamIdAndPaperNumber(Long examId, String paperNumber);
-
-    Task getSubjectiveInspectedTask(Long studentId);
-
-    void saveSubjectiveInspectedTask(MarkHeaderResult markResult);
-
-    IPage<ArchiveStudentVo> studentList(ArchiveStudentQuery query);
-
-    void scoreExport(ArchiveStudentQuery query, HttpServletResponse response);
-
-    ScoreReportVo scoreReport(ArchiveStudentQuery query);
-
-    void exportUnexist(Long examId, Long courseId, String coursePaperId, HttpServletResponse response);
-
-    int countByExamIdAndPaperNumberAndMarkStatus(Long examId, String paperNumber, SubjectiveStatus status);
-
-    void updateCheckInfo(Long studentId, Long userId);
-
-    int countOmrAbsentStudent(Long examId, String paperNumber, String paperType, boolean isOmrAbsentConfirm);
-
-    void scoreReportDownload(JSONObject jsonObject, HttpServletResponse response);
-
-    void deleteByExamIdAndPaperNumber(Long examId, String paperNumber);
-
-    boolean calcObjectiveScore(Long examId, String paperNumber);
-
-    IPage<MarkStudent> pageByExamAndPaperNumber(Long examId, String paperNumber, int pageNumber, int pageSize);
-
-    void updateObjectiveScoreAndScoreList(MarkStudent markStudent);
-
-    boolean updateAssignConfirm(Long studentId, boolean assignConfirm);
-
-    int getAssignedCount(Long examId, Boolean checked, Long courseId, String coursePaperId, MarkPaperStatus status,
-                         DataPermissionRule dpr);
-
-    int countAbsentByExamIdAndPaperNumber(Long examId, String paperNumber);
-
-    List<MarkStudent> listScanCollegeByExamIdAndCourseCodeAndCoursePaperId(Long examId, String courseCode,
-                                                                           String coursePaperId, String status, DataPermissionRule dpr);
-
-    int countUnexistByExamIdAndPaperNumberAndPaperType(Long examId, String paperNumber, String paperType);
-
-    void updateStudentAnswer(@NotNull Long studentId);
-
-    List<MarkStudentScoreVo> listMarkStudentScoreList(Long examId, String paperNumber);
-
-    void trackExport(Long examId, String paperNumber, HttpServletResponse response);
-
-    void sheetExport(Long examId, String paperNumber, HttpServletResponse response);
-
-    void updateByBasicExamStudent(BasicExamStudent basicExamStudent, MarkPaper markPaper, Set<String> secretNumberSet);
-
-    void deleteByExamIdAndPaperNumberAndStudentCode(Long examId, String paperNumber, String studentCode);
-
-    Integer maxCardNumber(Long examId, String paperNumber, String paperType);
-
-    void scoreDownload(ArchiveStudentQuery query, HttpServletResponse response);
-
-    Boolean missScanUpdate(Long examId, String coursePaperId, String studentCode, Boolean missScan);
-
-    MarkStudentVo getMarkStudentVoByStudentId(Long studentId);
-
-    List<MarkStudentVo> listMarkStudentVo(MarkStudentQuery markStudentQuery);
-
-    IPage<MarkStudentVo> pageMarkStudentVo(Page<MarkStudentVo> page, MarkStudentQuery markStudentQuery);
-}
+package com.qmth.teachcloud.mark.service;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
+import com.qmth.teachcloud.common.entity.BasicExam;
+import com.qmth.teachcloud.common.entity.BasicExamStudent;
+import com.qmth.teachcloud.common.entity.SysUser;
+import com.qmth.teachcloud.common.enums.ScanStatus;
+import com.qmth.teachcloud.common.enums.mark.MarkPaperStatus;
+import com.qmth.teachcloud.common.enums.mark.SubjectiveStatus;
+import com.qmth.teachcloud.mark.bean.UpdateTimeVo;
+import com.qmth.teachcloud.mark.bean.archivescore.ArchiveStudentQuery;
+import com.qmth.teachcloud.mark.bean.archivescore.ArchiveStudentVo;
+import com.qmth.teachcloud.mark.bean.archivescore.MarkStudentScoreVo;
+import com.qmth.teachcloud.mark.bean.archivescore.ScoreReportVo;
+import com.qmth.teachcloud.mark.bean.omredit.OmrEditDomain;
+import com.qmth.teachcloud.mark.bean.scananswer.AnswerQueryDomain;
+import com.qmth.teachcloud.mark.bean.scananswer.AnswerQueryVo;
+import com.qmth.teachcloud.mark.bean.scanexaminfo.ScanExamCheckInfoVo;
+import com.qmth.teachcloud.mark.bean.scanexaminfo.ScanExamInfoVo;
+import com.qmth.teachcloud.mark.bean.student.AbsentManualUpdateVo;
+import com.qmth.teachcloud.mark.bean.student.MarkStudentQuery;
+import com.qmth.teachcloud.mark.bean.student.StudentQuery;
+import com.qmth.teachcloud.mark.bean.student.StudentVo;
+import com.qmth.teachcloud.mark.dto.mark.MarkStudentVo;
+import com.qmth.teachcloud.mark.dto.mark.manage.Task;
+import com.qmth.teachcloud.mark.dto.mark.score.SheetUrlDto;
+import com.qmth.teachcloud.mark.dto.mark.score.StudentObjectiveDetailDto;
+import com.qmth.teachcloud.mark.dto.mark.score.StudentScoreDetailDto;
+import com.qmth.teachcloud.mark.entity.MarkPaper;
+import com.qmth.teachcloud.mark.entity.MarkStudent;
+import com.qmth.teachcloud.mark.entity.ScanStudentPaper;
+import com.qmth.teachcloud.mark.params.MarkHeaderResult;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * <p>
+ * 考试考生库 服务类
+ * </p>
+ *
+ * @author xf
+ * @since 2023-09-22
+ */
+public interface MarkStudentService extends IService<MarkStudent> {
+
+    List<String> listClassByExamIdAndCourseCode(Long examId, String paperNumber);
+
+    void updateSubjectiveStatusAndScore(Long studentId, SubjectiveStatus status, Double score, String scoreList);
+
+    void updateSubjectiveStatusAndScore(Long examId, String paperNumber, SubjectiveStatus status, Double score,
+                                        String scoreList);
+
+    ScanExamInfoVo getScanExamInfo(BasicExam exam, Long courseId, String coursePaperId);
+
+    IPage<StudentScoreDetailDto> pageStudentScore(Long examId, String paperNumber, String college, String majorName, String teachClassName,
+                                                  String className, String teacher, Integer filter, String status, Boolean breach, Double startScore, Double endScore,
+                                                  Double subjectiveStartScore, Double subjectiveEndScore, Double objectiveStartScore, Double objectiveEndScore,
+                                                  Double subScore, Integer objectiveScoreRateLt, String studentName, String studentCode, String orderType,
+                                                  String orderField, Integer pageNumber, Integer pageSize);
+
+    /**
+     * 评卷管理/成绩检查/成绩详情导出
+     *
+     * @param examId
+     * @param paperNumber
+     * @param college
+     * @param majorName
+     * @param teachClassName
+     * @param className
+     * @param teacher
+     * @param filter
+     * @param status
+     * @param breach
+     * @param startScore
+     * @param endScore
+     * @param subjectiveStartScore
+     * @param subjectiveEndScore
+     * @param objectiveStartScore
+     * @param objectiveEndScore
+     * @param subScore
+     * @param objectiveScoreRateLt
+     * @param studentName
+     * @param studentCode
+     * @param orderType
+     * @param orderField
+     * @return
+     */
+    List<StudentScoreDetailDto> pageStudentScoreExport(Long examId, String paperNumber, String college, String majorName, String teachClassName,
+                                                       String className, String teacher, Integer filter, String status, Boolean breach, Double startScore, Double endScore,
+                                                       Double subjectiveStartScore, Double subjectiveEndScore, Double objectiveStartScore, Double objectiveEndScore,
+                                                       Double subScore, Integer objectiveScoreRateLt, String studentName, String studentCode, String orderType,
+                                                       String orderField);
+
+
+    List<SheetUrlDto> buildSheetUrls(Long studentId);
+
+    ScanExamCheckInfoVo checkInfo(BasicExam exam, Long courseId, String coursePaperId);
+
+    /**
+     * 根据考生当前绑定的paper刷新考生状态,需要在外部调用处对考生上锁
+     */
+    void updateStudentByPaper(@NotNull Long userId, @NotNull Long studentId, @NotNull boolean updateOmrTask);
+
+    MarkStudent findByExamIdAndCoursePaperIdAndStudentCode(Long examId, String coursePaperId, String studentCode);
+
+    MarkStudent findByExamIdAndPaperNumberAndStudentCode(Long examId, String paperNumber, String studentCode);
+
+    List<MarkStudent> listByStudentId(Long studentId);
+
+    StudentObjectiveDetailDto getObjectiveInspectedTask(Long studentId);
+
+    Boolean saveObjectiveInspectedTask(Long studentId, String answers);
+
+    int countUploadedByExamIdAndPaperNumber(Long examId, String paperNumber);
+
+    boolean updateScanInfo(MarkStudent student);
+
+    List<MarkStudent> listAbsentOrBreachMarkTaskStudent(Long examId, String paperNumber);
+
+    List<MarkStudent> listUnMarkTaskStudent(Long examId, String paperNumber, Integer groupNumber, int pageSize);
+
+    boolean saveUploadStudent(MarkStudent student);
+
+    void calculateObjectiveScore(MarkStudent student);
+
+    void updateStudentAndPaper(SysUser user, Long studentId, List<ScanStudentPaper> studentPaperList);
+
+    StudentVo findOne(StudentQuery query);
+
+    int countByExamIdAndSecretNumber(Long examId, String secretNumber);
+
+    List<MarkStudent> listByExamIdAndCoursePaperId(Long examId, String coursePaperId);
+
+    IPage<AnswerQueryVo> query(AnswerQueryDomain query);
+
+    List<String> summary(AnswerQueryDomain query);
+
+    UpdateTimeVo omrEdit(Long userId, OmrEditDomain domain);
+
+    long countByExamIdAndPaperNumber(Long examId, String paperNumber, String paperType);
+
+    AbsentManualUpdateVo absentManualUpdate(Long examId, String coursePaperId, String studentCode, ScanStatus status);
+
+    UpdateTimeVo confirm(Long examId, String coursePaperId, String studentCode, Boolean omrAbsent);
+
+    List<Long> findIdByExamIdAndPaperNumber(Long examId, String paperNumber);
+
+    Task getSubjectiveInspectedTask(Long studentId);
+
+    void saveSubjectiveInspectedTask(MarkHeaderResult markResult);
+
+    IPage<ArchiveStudentVo> studentList(ArchiveStudentQuery query);
+
+    void scoreExport(ArchiveStudentQuery query, HttpServletResponse response);
+
+    ScoreReportVo scoreReport(ArchiveStudentQuery query);
+
+    void exportUnexist(Long examId, Long courseId, String coursePaperId, HttpServletResponse response);
+
+    int countByExamIdAndPaperNumberAndMarkStatus(Long examId, String paperNumber, SubjectiveStatus status);
+
+    void updateCheckInfo(Long studentId, Long userId);
+
+    int countOmrAbsentStudent(Long examId, String paperNumber, String paperType, boolean isOmrAbsentConfirm);
+
+    int countOmrAbsentStudent(Long examId, String paperNumber, String paperType, boolean isOmrAbsentConfirm, String teachClassName);
+
+    void scoreReportDownload(JSONObject jsonObject, HttpServletResponse response);
+
+    void deleteByExamIdAndPaperNumber(Long examId, String paperNumber);
+
+    boolean calcObjectiveScore(Long examId, String paperNumber);
+
+    IPage<MarkStudent> pageByExamAndPaperNumber(Long examId, String paperNumber, int pageNumber, int pageSize);
+
+    void updateObjectiveScoreAndScoreList(MarkStudent markStudent);
+
+    boolean updateAssignConfirm(Long studentId, boolean assignConfirm);
+
+    int getAssignedCount(Long examId, Boolean checked, Long courseId, String coursePaperId, MarkPaperStatus status,
+                         DataPermissionRule dpr);
+
+    int getAssignedCount(Long examId, Boolean checked, Long courseId, String coursePaperId, MarkPaperStatus status,
+                         DataPermissionRule dpr, String teachClassName);
+
+    int countAbsentByExamIdAndPaperNumber(Long examId, String paperNumber);
+
+    List<MarkStudent> listScanCollegeByExamIdAndCourseCodeAndCoursePaperId(Long examId, String courseCode,
+                                                                           String coursePaperId, String status, DataPermissionRule dpr);
+
+    int countUnexistByExamIdAndPaperNumberAndPaperType(Long examId, String paperNumber, String paperType);
+
+    void updateStudentAnswer(@NotNull Long studentId);
+
+    List<MarkStudentScoreVo> listMarkStudentScoreList(Long examId, String paperNumber);
+
+    void trackExport(Long examId, String paperNumber, HttpServletResponse response);
+
+    void sheetExport(Long examId, String paperNumber, HttpServletResponse response);
+
+    void updateByBasicExamStudent(BasicExamStudent basicExamStudent, MarkPaper markPaper, Set<String> secretNumberSet);
+
+    void deleteByExamIdAndPaperNumberAndStudentCode(Long examId, String paperNumber, String studentCode);
+
+    Integer maxCardNumber(Long examId, String paperNumber, String paperType);
+
+    void scoreDownload(ArchiveStudentQuery query, HttpServletResponse response);
+
+    Boolean missScanUpdate(Long examId, String coursePaperId, String studentCode, Boolean missScan);
+
+    MarkStudentVo getMarkStudentVoByStudentId(Long studentId);
+
+    List<MarkStudentVo> listMarkStudentVo(MarkStudentQuery markStudentQuery);
+
+    IPage<MarkStudentVo> pageMarkStudentVo(Page<MarkStudentVo> page, MarkStudentQuery markStudentQuery);
+}

+ 46 - 44
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/ScanOmrTaskService.java

@@ -1,44 +1,46 @@
-package com.qmth.teachcloud.mark.service;
-
-import java.util.List;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import org.apache.ibatis.annotations.Param;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
-import com.qmth.teachcloud.common.enums.mark.MarkPaperStatus;
-import com.qmth.teachcloud.common.enums.scan.ConditionType;
-import com.qmth.teachcloud.mark.dto.*;
-import com.qmth.teachcloud.mark.entity.ScanOmrTask;
-import com.qmth.teachcloud.mark.enums.OmrTaskStatus;
-
-/**
- * <p>
- *  服务类
- * </p>
- *
- * @author xf
- * @since 2023-09-22
- */
-public interface ScanOmrTaskService extends IService<ScanOmrTask> {
-	
-	List<ScanOmrTask> buildTask(@Param("c") ConditionType c, @Param("studentId") Long studentId);
-
-	ScanOmrStudent getTask(Long studentId);
-
-	ScanOmrTaskSaveDto submitTask(List<ScanOmrTaskResultDto> result, Long userId);
-
-	ScanOmrTaskStatusDto getStatus(Long examId, Long courseId, String coursePaperId);
-
-	int getFinishStudentCountByExamAndUserId(Long examId, Long courseId, String coursePaperId, String status,DataPermissionRule dpr);
-
-	void deleteByStudentId(Long examId, Long studentId);
-
-	int getCount(Long examId, OmrTaskStatus status, String courseCode, String coursePaperId, MarkPaperStatus markPaperStatus, DataPermissionRule dpr);
-
-	IPage<ScanStudentDto> list(Long examId, Long courseId, String coursePaperId, OmrTaskStatus status, String studentCodeOrName, Integer pageNumber, Integer pageSize);
-
-	void saveTask(Long studentId);
-
-}
+package com.qmth.teachcloud.mark.service;
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.apache.ibatis.annotations.Param;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
+import com.qmth.teachcloud.common.enums.mark.MarkPaperStatus;
+import com.qmth.teachcloud.common.enums.scan.ConditionType;
+import com.qmth.teachcloud.mark.dto.*;
+import com.qmth.teachcloud.mark.entity.ScanOmrTask;
+import com.qmth.teachcloud.mark.enums.OmrTaskStatus;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author xf
+ * @since 2023-09-22
+ */
+public interface ScanOmrTaskService extends IService<ScanOmrTask> {
+	
+	List<ScanOmrTask> buildTask(@Param("c") ConditionType c, @Param("studentId") Long studentId);
+
+	ScanOmrStudent getTask(Long studentId);
+
+	ScanOmrTaskSaveDto submitTask(List<ScanOmrTaskResultDto> result, Long userId);
+
+	ScanOmrTaskStatusDto getStatus(Long examId, Long courseId, String coursePaperId);
+
+	int getFinishStudentCountByExamAndUserId(Long examId, Long courseId, String coursePaperId, String status,DataPermissionRule dpr);
+
+    int getFinishStudentCountByExamAndUserId(Long examId, Long courseId, String coursePaperId, String status,DataPermissionRule dpr,String teachClassName);
+
+    void deleteByStudentId(Long examId, Long studentId);
+
+	int getCount(Long examId, OmrTaskStatus status, String courseCode, String coursePaperId, MarkPaperStatus markPaperStatus, DataPermissionRule dpr);
+
+	IPage<ScanStudentDto> list(Long examId, Long courseId, String coursePaperId, OmrTaskStatus status, String studentCodeOrName, Integer pageNumber, Integer pageSize);
+
+	void saveTask(Long studentId);
+
+}

+ 461 - 422
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkPaperServiceImpl.java

@@ -1,422 +1,461 @@
-package com.qmth.teachcloud.mark.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
-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.teachcloud.common.bean.dto.DataPermissionRule;
-import com.qmth.teachcloud.common.bean.dto.mark.MarkSettingDto;
-import com.qmth.teachcloud.common.bean.params.mark.setting.MarkPaperSettingConfig;
-import com.qmth.teachcloud.common.bean.params.mark.setting.MarkPaperSettingList;
-import com.qmth.teachcloud.common.bean.params.mark.setting.MarkPaperSettingParam;
-import com.qmth.teachcloud.common.entity.MarkQuestion;
-import com.qmth.teachcloud.common.entity.SysUser;
-import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
-import com.qmth.teachcloud.common.enums.mark.MarkMode;
-import com.qmth.teachcloud.common.enums.mark.MarkPaperStatus;
-import com.qmth.teachcloud.common.enums.mark.SubjectiveStatus;
-import com.qmth.teachcloud.common.service.BasicRoleDataPermissionService;
-import com.qmth.teachcloud.common.service.TeachcloudCommonService;
-import com.qmth.teachcloud.common.util.ServletUtil;
-import com.qmth.teachcloud.mark.bean.archivescore.ArchiveScoreQuery;
-import com.qmth.teachcloud.mark.bean.archivescore.ArchiveScoreVo;
-import com.qmth.teachcloud.mark.bean.document.ArchivePaperQuery;
-import com.qmth.teachcloud.mark.bean.document.ArchivePaperVo;
-import com.qmth.teachcloud.mark.dto.mark.score.CheckScoreListDto;
-import com.qmth.teachcloud.mark.dto.mark.score.MarkPaperPackageDto;
-import com.qmth.teachcloud.mark.dto.mark.score.SettingDto;
-import com.qmth.teachcloud.mark.entity.MarkPaper;
-import com.qmth.teachcloud.mark.entity.MarkStudent;
-import com.qmth.teachcloud.mark.entity.ScanPackage;
-import com.qmth.teachcloud.mark.enums.OmrTaskStatus;
-import com.qmth.teachcloud.mark.mapper.MarkPaperMapper;
-import com.qmth.teachcloud.mark.service.*;
-import com.qmth.teachcloud.mark.utils.Calculator;
-import org.apache.commons.collections4.CollectionUtils;
-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 javax.annotation.Resource;
-import java.util.List;
-import java.util.Objects;
-import java.util.stream.Collectors;
-
-/**
- * <p>
- * 考试科目表 服务实现类
- * </p>
- *
- * @author xf
- * @since 2023-09-22
- */
-@Service
-public class MarkPaperServiceImpl extends ServiceImpl<MarkPaperMapper, MarkPaper> implements MarkPaperService {
-
-    @Resource
-    private ScanPackageService scanPackageService;
-    @Resource
-    private ScanOmrTaskService scanOmrTaskService;
-    @Resource
-    private TeachcloudCommonService teachcloudCommonService;
-    @Resource
-    private BasicRoleDataPermissionService basicRoleDataPermissionService;
-    @Resource
-    private MarkQuestionService markQuestionService;
-    @Resource
-    private MarkStudentService markStudentService;
-    @Resource
-    private MarkUserGroupService markUserGroupService;
-    @Resource
-    private MarkDocumentService markDocumentService;
-
-
-    @Override
-    public IPage<MarkSettingDto> listPaperSetting(Long examId, Long courseId, String paperNumber, Boolean groupStatus, Integer pageNumber, Integer pageSize) {
-        Page<MarkSettingDto> page = new Page<>(pageNumber, pageSize);
-        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
-        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(sysUser.getSchoolId(), sysUser.getId(), "/api/admin/mark/setting/list");
-        IPage<MarkSettingDto> markSettingDtoIPage = this.baseMapper.listPaperSetting(page, sysUser.getSchoolId(), examId, courseId, paperNumber, groupStatus, dpr);
-        for (MarkSettingDto record : markSettingDtoIPage.getRecords()) {
-            if (Objects.nonNull(record.getMarkMode())) {
-                record.setMarkModeDisplay(record.getMarkMode().getName());
-            }
-        }
-        return markSettingDtoIPage;
-    }
-
-    @Override
-    public MarkPaper getByExamIdAndPaperNumber(Long examId, String paperNumber) {
-        QueryWrapper<MarkPaper> queryWrapper = new QueryWrapper<>();
-        queryWrapper.lambda().eq(MarkPaper::getExamId, examId)
-                .eq(MarkPaper::getPaperNumber, paperNumber);
-        return this.getOne(queryWrapper);
-    }
-
-    @Override
-    public MarkPaper getByExamIdAndPaperNumberAndPaperType(Long examId, String paperNumber, String paperType) {
-        QueryWrapper<MarkPaper> queryWrapper = new QueryWrapper<>();
-        LambdaQueryWrapper<MarkPaper> lambda = queryWrapper.lambda();
-        lambda.eq(MarkPaper::getExamId, examId)
-                .eq(MarkPaper::getPaperNumber, paperNumber);
-        if (StringUtils.isNotBlank(paperType)) {
-            lambda.eq(MarkPaper::getPaperType, paperType);
-        }
-        return this.getOne(queryWrapper);
-    }
-
-    @Transactional
-    @Override
-    public void savePaperSetting(MarkPaper markPaper) {
-        MarkPaper markPaperOld = this.getByExamIdAndPaperNumber(markPaper.getExamId(), markPaper.getPaperNumber());
-        if (markPaperOld == null) {
-            throw ExceptionResultEnum.ERROR.exception("评卷设置数据不存在");
-        }
-        // 评卷是否结束
-        if (MarkPaperStatus.FINISH.equals(markPaperOld.getStatus())) {
-            throw ExceptionResultEnum.ERROR.exception("科目已结束评卷,无法修改参数");
-        }
-        UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
-        LambdaUpdateWrapper<MarkPaper> lambda = updateWrapper.lambda();
-        lambda.set(MarkPaper::getMarkMode, markPaper.getMarkMode())
-                .set(MarkPaper::getForceMode, !MarkMode.UNLIMITED.equals(markPaper.getMarkMode()))
-                .set(MarkPaper::getMarkStartTime, markPaper.getMarkStartTime())
-                .set(MarkPaper::getMarkEndTime, markPaper.getMarkEndTime())
-                .set(MarkPaper::getPassScore, markPaper.getPassScore())
-                .set(MarkPaper::getExcellentScore, markPaper.getExcellentScore())
-                .set(MarkPaper::getSheetView, markPaper.getSheetView())
-                .set(MarkPaper::getShowObjectScore, markPaper.getShowObjectScore())
-                .set(MarkPaper::getAutoScroll, markPaper.getAutoScroll())
-                .set(MarkPaper::getOpenDoubleMarking, markPaper.getOpenDoubleMarking())
-                .eq(MarkPaper::getExamId, markPaper.getExamId())
-                .eq(MarkPaper::getPaperNumber, markPaper.getPaperNumber());
-        if (StringUtils.isNotBlank(markPaper.getSheetConfig())) {
-            lambda.set(MarkPaper::getSheetConfig, markPaper.getSheetConfig());
-        }
-        // 更新评卷员模式
-        markUserGroupService.updateMode(markPaper.getExamId(), markPaper.getPaperNumber(), null, null, MarkMode.UNLIMITED.equals(markPaper.getMarkMode()) ? MarkMode.TRACK : markPaper.getMarkMode());
-        this.update(updateWrapper);
-    }
-
-    @Transactional
-    @Override
-    public void saveBatchPaperSetting(MarkPaperSettingParam markPaperSettingParam) {
-        List<MarkPaperSettingList> list = markPaperSettingParam.getList();
-        if (CollectionUtils.isEmpty(list)) {
-            throw ExceptionResultEnum.ERROR.exception("请选择要设置的数据");
-        }
-
-        MarkPaperSettingConfig config = markPaperSettingParam.getConfig();
-        if (config == null) {
-            throw ExceptionResultEnum.ERROR.exception("未找到参数值,请先设置");
-        }
-
-        for (MarkPaperSettingList markPaperSettingList : list) {
-            MarkPaper markPaperOld = this.getByExamIdAndPaperNumber(markPaperSettingList.getExamId(), markPaperSettingList.getPaperNumber());
-            if (markPaperOld == null) {
-                throw ExceptionResultEnum.ERROR.exception("评卷设置数据不存在");
-            }
-            // 评卷是否结束
-            if (MarkPaperStatus.FINISH.equals(markPaperOld.getStatus())) {
-                throw ExceptionResultEnum.ERROR.exception("科目已结束评卷,无法修改参数");
-            }
-
-            UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
-            LambdaUpdateWrapper<MarkPaper> lambda = updateWrapper.lambda();
-            lambda.set(MarkPaper::getMarkMode, config.getMarkMode())
-                    .set(MarkPaper::getForceMode, !MarkMode.UNLIMITED.equals(config.getMarkMode()))
-                    .set(MarkPaper::getMarkStartTime, config.getMarkStartTime())
-                    .set(MarkPaper::getMarkEndTime, config.getMarkEndTime())
-                    .set(MarkPaper::getPassScore, config.getPassScore())
-                    .set(MarkPaper::getExcellentScore, config.getExcellentScore())
-                    .set(MarkPaper::getShowObjectScore, config.getShowObjectScore())
-                    .set(MarkPaper::getAutoScroll, config.getAutoScroll())
-                    .set(MarkPaper::getOpenDoubleMarking, config.getOpenDoubleMarking())
-                    .eq(MarkPaper::getExamId, markPaperSettingList.getExamId())
-                    .eq(MarkPaper::getPaperNumber, markPaperSettingList.getPaperNumber());
-            // 更新评卷员模式
-            markUserGroupService.updateMode(markPaperSettingList.getExamId(), markPaperSettingList.getPaperNumber(), null, null, MarkMode.UNLIMITED.equals(config.getMarkMode()) ? MarkMode.TRACK : config.getMarkMode());
-            this.update(updateWrapper);
-        }
-    }
-
-    @Override
-    public Boolean finishPaper(Long examId, List<String> paperNumbers, MarkPaperStatus status) {
-        for (String paperNumber : paperNumbers) {
-            MarkPaper markPaper = this.getByExamIdAndPaperNumber(examId, paperNumber);
-            if (MarkPaperStatus.FINISH.equals(status)) {
-                String courseInfo = String.format("%s[%s],试卷编号%s,", markPaper.getCourseName(), markPaper.getCourseCode(), markPaper.getPaperNumber());
-                // 主观题是否全部分组
-                List<MarkQuestion> markQuestionObjectiveList = markQuestionService.listQuestionByExamIdAndPaperNumberAndGroupNumber(examId, paperNumber, null, true);
-                if (CollectionUtils.isNotEmpty(markQuestionObjectiveList)) {
-                    if (markQuestionObjectiveList.stream().filter(m -> StringUtils.isBlank(m.getAnswer())).count() > 0) {
-                        throw ExceptionResultEnum.ERROR.exception(courseInfo + "客观题标答未设置,无法结束评卷");
-                    }
-                }
-
-                // 主观题是否全部分组
-                List<MarkQuestion> markQuestionSubjectiveList = markQuestionService.listQuestionByExamIdAndPaperNumberAndGroupNumber(examId, paperNumber, null, false);
-                // 没有主观题,不校验考生评卷
-                if (CollectionUtils.isNotEmpty(markQuestionSubjectiveList)) {
-                    if (markQuestionSubjectiveList.stream().filter(m -> m.getGroupNumber() == null).count() > 0) {
-                        throw ExceptionResultEnum.ERROR.exception(courseInfo + "主观题未全部分组,无法结束评卷");
-                    }
-                    // 未缺考、未违纪且已上传图片的考生全部评完
-                    if (markStudentService.countByExamIdAndPaperNumberAndMarkStatus(examId, paperNumber, SubjectiveStatus.UNMARK) > 0) {
-                        throw ExceptionResultEnum.ERROR.exception(courseInfo + "考生未全部评完,无法结束评卷");
-                    }
-                    // 未全部扫描,不能结束
-                    if (markStudentService.countUnexistByExamIdAndPaperNumberAndPaperType(examId, paperNumber, markPaper.getPaperType()) > 0) {
-                        throw ExceptionResultEnum.ERROR.exception(courseInfo + "有考生未扫描未核对,请在扫描客户端进行确认操作后再结束阅卷");
-                    }
-                    // 识别缺考未确认完,不能结束
-                    if (markStudentService.countOmrAbsentStudent(examId, paperNumber, markPaper.getPaperType(), false) > 0) {
-                        throw ExceptionResultEnum.ERROR.exception(courseInfo + "识别缺考记录未核对,请在扫描客户端进行确认操作后再结束阅卷");
-                    }
-                    // 人工绑定未做完,不能结束
-                    if (markStudentService.getAssignedCount(examId, false, markPaper.getCourseId(), markPaper.getCoursePaperId(), MarkPaperStatus.FORMAL, null) > 0) {
-                        throw ExceptionResultEnum.ERROR.exception(courseInfo + "人工绑定记录未核对,请在扫描客户端进行确认操作后再结束阅卷");
-                    }
-                    // 客观题检查未做完,不能结束
-                    if (scanOmrTaskService.getFinishStudentCountByExamAndUserId(examId, markPaper.getCourseId(), markPaper.getCoursePaperId(), OmrTaskStatus.WAITING.name(), null) > 0) {
-                        throw ExceptionResultEnum.ERROR.exception(courseInfo + "客观题存在识别嫌疑需要人工确认,请在扫描客户端进行确认操作后再结束阅卷");
-                    }
-                }
-
-                // 结束评卷时,客观题统分
-                List<MarkStudent> markStudentList = markStudentService.listByExamIdAndCoursePaperId(examId, markPaper.getCoursePaperId());
-                for (MarkStudent markStudent : markStudentList) {
-                    markStudentService.calculateObjectiveScore(markStudent);
-                }
-
-                // 结束评卷时,文档进行归档
-                markDocumentService.initMarkDocument(markPaper);
-            }
-
-            UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
-            updateWrapper.lambda().set(MarkPaper::getStatus, status)
-                    .eq(MarkPaper::getExamId, examId)
-                    .eq(MarkPaper::getPaperNumber, paperNumber);
-            this.update(updateWrapper);
-        }
-
-        return true;
-    }
-
-    @Override
-    public List<MarkPaper> listQualityMarkPaperByStatus(MarkPaperStatus status, int uploadCount) {
-        return this.baseMapper.listQualityMarkPaperByStatus(status.name(), uploadCount);
-    }
-
-    @Override
-    public int getCourseCount(Long examId, Long courseId, String coursePaperId, MarkPaperStatus status, DataPermissionRule dpr) {
-        return baseMapper.getCourseCount(examId, courseId, coursePaperId, status.name(), dpr);
-    }
-
-    @Override
-    public int getPaperNumberCount(Long examId, Long courseId, String coursePaperId, MarkPaperStatus status, DataPermissionRule dpr) {
-        return baseMapper.getPaperNumberCount(examId, courseId, coursePaperId, status.name(), dpr);
-    }
-
-    @Override
-    public IPage<CheckScoreListDto> listStudentScoreList(Long examId, Long courseId, String paperNumber, Integer pageNumber, Integer pageSize) {
-        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
-        Page<CheckScoreListDto> page = new Page<>(pageNumber, pageSize);
-        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(sysUser.getSchoolId(), sysUser.getId(), ServletUtil.getRequest().getServletPath());
-        return this.baseMapper.listStudentScoreList(page, examId, courseId, paperNumber, dpr);
-    }
-
-    @Override
-    public void updateStatus(Long examId, String paperNumber, MarkPaperStatus newStatus, MarkPaperStatus currentStatus) {
-        UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
-        updateWrapper.lambda().set(MarkPaper::getStatus, newStatus)
-                .eq(MarkPaper::getExamId, examId)
-                .eq(MarkPaper::getPaperNumber, paperNumber)
-                .eq(MarkPaper::getStatus, currentStatus);
-        this.update(updateWrapper);
-    }
-
-    @Override
-    public void updateUploadCount(Long examId, String paperNumber, int countUploaded) {
-        UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
-        updateWrapper.lambda().set(MarkPaper::getUploadCount, countUploaded)
-                .eq(MarkPaper::getExamId, examId)
-                .eq(MarkPaper::getPaperNumber, paperNumber);
-        this.update(updateWrapper);
-    }
-
-    @Override
-    public IPage<MarkPaperPackageDto> listPackage(Long examId, String paperNumber, String packageCode, Integer pageNumber, Integer pageSize) {
-        MarkPaper markPaper = this.getByExamIdAndPaperNumber(examId, paperNumber);
-        Page<MarkPaperPackageDto> page = new Page<>(pageNumber, pageSize);
-        IPage<MarkPaperPackageDto> markPaperPackageDtoIPage = this.baseMapper.listPackage(page, examId, markPaper.getCoursePaperId(), packageCode);
-        for (MarkPaperPackageDto packageDto : markPaperPackageDtoIPage.getRecords()) {
-            List<ScanPackage> scanPackageList = scanPackageService.listByExamIdAndCoursePaperIdAndPackageCode(examId, markPaper.getCoursePaperId(), packageDto.getPackageCode());
-            List<String> urls = scanPackageList.stream().map(m -> teachcloudCommonService.filePreview(m.getPath())).collect(Collectors.toList());
-            packageDto.setCount(urls.size());
-            packageDto.setUrls(urls);
-        }
-        return markPaperPackageDtoIPage;
-    }
-
-    @Override
-    public MarkPaper getByExamIdAndCoursePaperId(Long examId, String coursePaperId) {
-        QueryWrapper<MarkPaper> wrapper = new QueryWrapper<>();
-        wrapper.lambda().eq(MarkPaper::getExamId, examId)
-                .eq(MarkPaper::getCoursePaperId, coursePaperId);
-        wrapper.last("LIMIT 1");
-        return this.getOne(wrapper);
-    }
-
-    @Override
-    public List<MarkPaper> listByExamId(Long examId, MarkPaperStatus status, DataPermissionRule dpr) {
-        return this.baseMapper.listByExamId(examId, status.name(), dpr);
-    }
-
-    @Override
-    public void updateGroupStatusByExamIdAndPaperNumber(boolean groupStatus, Long examId, String paperNumber) {
-        UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
-        updateWrapper.lambda().set(MarkPaper::getGroupStatus, groupStatus)
-                .eq(MarkPaper::getExamId, examId)
-                .eq(MarkPaper::getPaperNumber, paperNumber);
-        this.update(updateWrapper);
-    }
-
-    @Override
-    public int countByPropositionTeacherId(boolean status) {
-        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
-        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
-        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(schoolId, sysUser.getId(), "/api/admin/mark/setting/list");
-        List<MarkSettingDto> markSettingDtoList = this.baseMapper.listPaperSetting(schoolId, null, null, null, status, dpr);
-        return CollectionUtils.isEmpty(markSettingDtoList) ? 0 : markSettingDtoList.size();
-    }
-
-    @Override
-    public void updateStudentCountByExamIdAndPaperNumberAndPaperType(Long examId, String paperNumber, String paperType) {
-        long count = markStudentService.countByExamIdAndPaperNumber(examId, paperNumber, paperType);
-        UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
-        LambdaUpdateWrapper<MarkPaper> lambda = updateWrapper.lambda();
-        lambda.set(MarkPaper::getStudentCount, count)
-                .eq(MarkPaper::getExamId, examId)
-                .eq(MarkPaper::getPaperNumber, paperNumber);
-        if (StringUtils.isNotBlank(paperType)) {
-            lambda.eq(MarkPaper::getPaperType, paperType);
-        }
-        this.update(updateWrapper);
-    }
-
-    @Override
-    public SettingDto getSetting(Long examId, String paperNumber) {
-        SettingDto settingDto = new SettingDto();
-        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
-        settingDto.setExamId(examId);
-        settingDto.setPaperNumber(paperNumber);
-        settingDto.setUserName(sysUser.getRealName());
-        MarkPaper markPaper = this.getByExamIdAndPaperNumber(examId, paperNumber);
-        if (markPaper != null) {
-            settingDto.setCourseCode(markPaper.getCourseCode());
-            settingDto.setCourseName(markPaper.getCourseName());
-            if (StringUtils.isNotBlank(markPaper.getPaperFilePath())) {
-                settingDto.setPaperUrl(teachcloudCommonService.filePreview(markPaper.getPaperFilePath()));
-            }
-            if (StringUtils.isNotBlank(markPaper.getAnswerFilePath())) {
-                settingDto.setAnswerUrl(teachcloudCommonService.filePreview(markPaper.getAnswerFilePath()));
-            }
-        }
-        return settingDto;
-    }
-
-    @Override
-    public IPage<ArchiveScoreVo> scoreList(ArchiveScoreQuery query) {
-        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
-        Page<ArchiveScoreVo> page = new Page<>(query.getPageNumber(), query.getPageSize());
-        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(sysUser.getSchoolId(), sysUser.getId(), ServletUtil.getRequest().getServletPath());
-        IPage<ArchiveScoreVo> ret = this.baseMapper.scoreList(page, sysUser.getSchoolId(), query, dpr);
-        if (CollectionUtils.isNotEmpty(ret.getRecords())) {
-            for (ArchiveScoreVo vo : ret.getRecords()) {
-                double total = vo.getStudentCount() - vo.getAbsentCount();
-                vo.setPassRate(Calculator.divide2String(Calculator.multiply(vo.getPassCount(), 100), total, 2));
-                vo.setExcellentRate(Calculator.divide2String(Calculator.multiply(vo.getExcellentCount(), 100), total, 2));
-                vo.setAvgScore(Calculator.round(vo.getAvgScore(), 2));
-                vo.setMinScore(Calculator.round(vo.getMinScore(), 2));
-                vo.setMaxScore(Calculator.round(vo.getMaxScore(), 2));
-            }
-        }
-        return ret;
-    }
-
-    @Override
-    public void deleteByExamIdAndPaperNumber(Long examId, String paperNumber) {
-        UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
-        updateWrapper.lambda().eq(MarkPaper::getExamId, examId)
-                .eq(MarkPaper::getPaperNumber, paperNumber);
-        this.remove(updateWrapper);
-    }
-
-    @Override
-    public void updateAbsentCount(Long examId, String paperNumber, int absentCount) {
-        UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
-        updateWrapper.lambda().set(MarkPaper::getAbsentCount, absentCount)
-                .eq(MarkPaper::getExamId, examId)
-                .eq(MarkPaper::getPaperNumber, paperNumber);
-        this.update(updateWrapper);
-    }
-
-    @Override
-    public IPage<ArchivePaperVo> documentList(ArchivePaperQuery query) {
-        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
-        Page<ArchiveScoreVo> page = new Page<>(query.getPageNumber(), query.getPageSize());
-        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(sysUser.getSchoolId(), sysUser.getId(), ServletUtil.getRequest().getServletPath());
-        IPage<ArchivePaperVo> ret = this.baseMapper.documentList(page, query, dpr);
-        return ret;
-    }
-
-    @Override
-    public List<MarkPaper> findMarkPaperListByExamId(Long examId) {
-        return this.baseMapper.findMarkPaperListByExamId(examId);
-    }
-}
+package com.qmth.teachcloud.mark.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+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.teachcloud.common.bean.dto.DataPermissionRule;
+import com.qmth.teachcloud.common.bean.dto.mark.MarkSettingDto;
+import com.qmth.teachcloud.common.bean.params.mark.setting.MarkPaperSettingConfig;
+import com.qmth.teachcloud.common.bean.params.mark.setting.MarkPaperSettingList;
+import com.qmth.teachcloud.common.bean.params.mark.setting.MarkPaperSettingParam;
+import com.qmth.teachcloud.common.entity.MarkQuestion;
+import com.qmth.teachcloud.common.entity.SysUser;
+import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
+import com.qmth.teachcloud.common.enums.mark.MarkMode;
+import com.qmth.teachcloud.common.enums.mark.MarkPaperStatus;
+import com.qmth.teachcloud.common.enums.mark.SubjectiveStatus;
+import com.qmth.teachcloud.common.service.BasicRoleDataPermissionService;
+import com.qmth.teachcloud.common.service.TeachcloudCommonService;
+import com.qmth.teachcloud.common.util.ServletUtil;
+import com.qmth.teachcloud.mark.bean.archivescore.ArchiveScoreQuery;
+import com.qmth.teachcloud.mark.bean.archivescore.ArchiveScoreVo;
+import com.qmth.teachcloud.mark.bean.document.ArchivePaperQuery;
+import com.qmth.teachcloud.mark.bean.document.ArchivePaperVo;
+import com.qmth.teachcloud.mark.dto.mark.score.CheckScoreListDto;
+import com.qmth.teachcloud.mark.dto.mark.score.MarkPaperPackageDto;
+import com.qmth.teachcloud.mark.dto.mark.score.SettingDto;
+import com.qmth.teachcloud.mark.entity.MarkPaper;
+import com.qmth.teachcloud.mark.entity.MarkStudent;
+import com.qmth.teachcloud.mark.entity.ScanPackage;
+import com.qmth.teachcloud.mark.enums.OmrTaskStatus;
+import com.qmth.teachcloud.mark.mapper.MarkPaperMapper;
+import com.qmth.teachcloud.mark.service.*;
+import com.qmth.teachcloud.mark.utils.Calculator;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 考试科目表 服务实现类
+ * </p>
+ *
+ * @author xf
+ * @since 2023-09-22
+ */
+@Service
+public class MarkPaperServiceImpl extends ServiceImpl<MarkPaperMapper, MarkPaper> implements MarkPaperService {
+
+    @Resource
+    private ScanPackageService scanPackageService;
+    @Resource
+    private ScanOmrTaskService scanOmrTaskService;
+    @Resource
+    private TeachcloudCommonService teachcloudCommonService;
+    @Resource
+    private BasicRoleDataPermissionService basicRoleDataPermissionService;
+    @Resource
+    private MarkQuestionService markQuestionService;
+    @Resource
+    private MarkStudentService markStudentService;
+    @Resource
+    private MarkUserGroupService markUserGroupService;
+    @Resource
+    private MarkDocumentService markDocumentService;
+
+
+    @Override
+    public IPage<MarkSettingDto> listPaperSetting(Long examId, Long courseId, String paperNumber, Boolean groupStatus, Integer pageNumber, Integer pageSize) {
+        Page<MarkSettingDto> page = new Page<>(pageNumber, pageSize);
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(sysUser.getSchoolId(), sysUser.getId(), "/api/admin/mark/setting/list");
+        IPage<MarkSettingDto> markSettingDtoIPage = this.baseMapper.listPaperSetting(page, sysUser.getSchoolId(), examId, courseId, paperNumber, groupStatus, dpr);
+        for (MarkSettingDto record : markSettingDtoIPage.getRecords()) {
+            if (Objects.nonNull(record.getMarkMode())) {
+                record.setMarkModeDisplay(record.getMarkMode().getName());
+            }
+        }
+        return markSettingDtoIPage;
+    }
+
+    @Override
+    public MarkPaper getByExamIdAndPaperNumber(Long examId, String paperNumber) {
+        QueryWrapper<MarkPaper> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(MarkPaper::getExamId, examId)
+                .eq(MarkPaper::getPaperNumber, paperNumber);
+        return this.getOne(queryWrapper);
+    }
+
+    @Override
+    public MarkPaper getByExamIdAndPaperNumberAndPaperType(Long examId, String paperNumber, String paperType) {
+        QueryWrapper<MarkPaper> queryWrapper = new QueryWrapper<>();
+        LambdaQueryWrapper<MarkPaper> lambda = queryWrapper.lambda();
+        lambda.eq(MarkPaper::getExamId, examId)
+                .eq(MarkPaper::getPaperNumber, paperNumber);
+        if (StringUtils.isNotBlank(paperType)) {
+            lambda.eq(MarkPaper::getPaperType, paperType);
+        }
+        return this.getOne(queryWrapper);
+    }
+
+    @Transactional
+    @Override
+    public void savePaperSetting(MarkPaper markPaper) {
+        MarkPaper markPaperOld = this.getByExamIdAndPaperNumber(markPaper.getExamId(), markPaper.getPaperNumber());
+        if (markPaperOld == null) {
+            throw ExceptionResultEnum.ERROR.exception("评卷设置数据不存在");
+        }
+        // 评卷是否结束
+        if (MarkPaperStatus.FINISH.equals(markPaperOld.getStatus())) {
+            throw ExceptionResultEnum.ERROR.exception("科目已结束评卷,无法修改参数");
+        }
+        UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
+        LambdaUpdateWrapper<MarkPaper> lambda = updateWrapper.lambda();
+        lambda.set(MarkPaper::getMarkMode, markPaper.getMarkMode())
+                .set(MarkPaper::getForceMode, !MarkMode.UNLIMITED.equals(markPaper.getMarkMode()))
+                .set(MarkPaper::getMarkStartTime, markPaper.getMarkStartTime())
+                .set(MarkPaper::getMarkEndTime, markPaper.getMarkEndTime())
+                .set(MarkPaper::getPassScore, markPaper.getPassScore())
+                .set(MarkPaper::getExcellentScore, markPaper.getExcellentScore())
+                .set(MarkPaper::getSheetView, markPaper.getSheetView())
+                .set(MarkPaper::getShowObjectScore, markPaper.getShowObjectScore())
+                .set(MarkPaper::getAutoScroll, markPaper.getAutoScroll())
+                .set(MarkPaper::getOpenDoubleMarking, markPaper.getOpenDoubleMarking())
+                .eq(MarkPaper::getExamId, markPaper.getExamId())
+                .eq(MarkPaper::getPaperNumber, markPaper.getPaperNumber());
+        if (StringUtils.isNotBlank(markPaper.getSheetConfig())) {
+            lambda.set(MarkPaper::getSheetConfig, markPaper.getSheetConfig());
+        }
+        // 更新评卷员模式
+        markUserGroupService.updateMode(markPaper.getExamId(), markPaper.getPaperNumber(), null, null, MarkMode.UNLIMITED.equals(markPaper.getMarkMode()) ? MarkMode.TRACK : markPaper.getMarkMode());
+        this.update(updateWrapper);
+    }
+
+    @Transactional
+    @Override
+    public void saveBatchPaperSetting(MarkPaperSettingParam markPaperSettingParam) {
+        List<MarkPaperSettingList> list = markPaperSettingParam.getList();
+        if (CollectionUtils.isEmpty(list)) {
+            throw ExceptionResultEnum.ERROR.exception("请选择要设置的数据");
+        }
+
+        MarkPaperSettingConfig config = markPaperSettingParam.getConfig();
+        if (config == null) {
+            throw ExceptionResultEnum.ERROR.exception("未找到参数值,请先设置");
+        }
+
+        for (MarkPaperSettingList markPaperSettingList : list) {
+            MarkPaper markPaperOld = this.getByExamIdAndPaperNumber(markPaperSettingList.getExamId(), markPaperSettingList.getPaperNumber());
+            if (markPaperOld == null) {
+                throw ExceptionResultEnum.ERROR.exception("评卷设置数据不存在");
+            }
+            // 评卷是否结束
+            if (MarkPaperStatus.FINISH.equals(markPaperOld.getStatus())) {
+                throw ExceptionResultEnum.ERROR.exception("科目已结束评卷,无法修改参数");
+            }
+
+            UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
+            LambdaUpdateWrapper<MarkPaper> lambda = updateWrapper.lambda();
+            lambda.set(MarkPaper::getMarkMode, config.getMarkMode())
+                    .set(MarkPaper::getForceMode, !MarkMode.UNLIMITED.equals(config.getMarkMode()))
+                    .set(MarkPaper::getMarkStartTime, config.getMarkStartTime())
+                    .set(MarkPaper::getMarkEndTime, config.getMarkEndTime())
+                    .set(MarkPaper::getPassScore, config.getPassScore())
+                    .set(MarkPaper::getExcellentScore, config.getExcellentScore())
+                    .set(MarkPaper::getShowObjectScore, config.getShowObjectScore())
+                    .set(MarkPaper::getAutoScroll, config.getAutoScroll())
+                    .set(MarkPaper::getOpenDoubleMarking, config.getOpenDoubleMarking())
+                    .eq(MarkPaper::getExamId, markPaperSettingList.getExamId())
+                    .eq(MarkPaper::getPaperNumber, markPaperSettingList.getPaperNumber());
+            // 更新评卷员模式
+            markUserGroupService.updateMode(markPaperSettingList.getExamId(), markPaperSettingList.getPaperNumber(), null, null, MarkMode.UNLIMITED.equals(config.getMarkMode()) ? MarkMode.TRACK : config.getMarkMode());
+            this.update(updateWrapper);
+        }
+    }
+
+    @Override
+    public Boolean finishPaper(Long examId, List<String> paperNumbers, MarkPaperStatus status) {
+        for (String paperNumber : paperNumbers) {
+            MarkPaper markPaper = this.getByExamIdAndPaperNumber(examId, paperNumber);
+            if (MarkPaperStatus.FINISH.equals(status)) {
+                String courseInfo = String.format("%s[%s],试卷编号%s,", markPaper.getCourseName(), markPaper.getCourseCode(), markPaper.getPaperNumber());
+                // 主观题是否全部分组
+                List<MarkQuestion> markQuestionObjectiveList = markQuestionService.listQuestionByExamIdAndPaperNumberAndGroupNumber(examId, paperNumber, null, true);
+                if (CollectionUtils.isNotEmpty(markQuestionObjectiveList)) {
+                    if (markQuestionObjectiveList.stream().filter(m -> StringUtils.isBlank(m.getAnswer())).count() > 0) {
+                        throw ExceptionResultEnum.ERROR.exception(courseInfo + "客观题标答未设置,无法结束评卷");
+                    }
+                }
+
+                // 主观题是否全部分组
+                List<MarkQuestion> markQuestionSubjectiveList = markQuestionService.listQuestionByExamIdAndPaperNumberAndGroupNumber(examId, paperNumber, null, false);
+                // 没有主观题,不校验考生评卷
+                if (CollectionUtils.isNotEmpty(markQuestionSubjectiveList)) {
+                    if (markQuestionSubjectiveList.stream().filter(m -> m.getGroupNumber() == null).count() > 0) {
+                        throw ExceptionResultEnum.ERROR.exception(courseInfo + "主观题未全部分组,无法结束评卷");
+                    }
+                    // 未缺考、未违纪且已上传图片的考生全部评完
+                    if (markStudentService.countByExamIdAndPaperNumberAndMarkStatus(examId, paperNumber, SubjectiveStatus.UNMARK) > 0) {
+                        throw ExceptionResultEnum.ERROR.exception(courseInfo + "考生未全部评完,无法结束评卷");
+                    }
+                    // 未全部扫描,不能结束
+                    if (markStudentService.countUnexistByExamIdAndPaperNumberAndPaperType(examId, paperNumber, markPaper.getPaperType()) > 0) {
+                        throw ExceptionResultEnum.ERROR.exception(courseInfo + "有考生未扫描未核对,请在扫描客户端进行确认操作后再结束阅卷");
+                    }
+                    // 识别缺考未确认完,不能结束
+                    if (markStudentService.countOmrAbsentStudent(examId, paperNumber, markPaper.getPaperType(), false) > 0) {
+                        throw ExceptionResultEnum.ERROR.exception(courseInfo + "识别缺考记录未核对,请在扫描客户端进行确认操作后再结束阅卷");
+                    }
+                    // 人工绑定未做完,不能结束
+                    if (markStudentService.getAssignedCount(examId, false, markPaper.getCourseId(), markPaper.getCoursePaperId(), MarkPaperStatus.FORMAL, null) > 0) {
+                        throw ExceptionResultEnum.ERROR.exception(courseInfo + "人工绑定记录未核对,请在扫描客户端进行确认操作后再结束阅卷");
+                    }
+                    // 客观题检查未做完,不能结束
+                    if (scanOmrTaskService.getFinishStudentCountByExamAndUserId(examId, markPaper.getCourseId(), markPaper.getCoursePaperId(), OmrTaskStatus.WAITING.name(), null) > 0) {
+                        throw ExceptionResultEnum.ERROR.exception(courseInfo + "客观题存在识别嫌疑需要人工确认,请在扫描客户端进行确认操作后再结束阅卷");
+                    }
+                }
+
+                // 结束评卷时,客观题统分
+                List<MarkStudent> markStudentList = markStudentService.listByExamIdAndCoursePaperId(examId, markPaper.getCoursePaperId());
+                for (MarkStudent markStudent : markStudentList) {
+                    markStudentService.calculateObjectiveScore(markStudent);
+                }
+
+                // 结束评卷时,文档进行归档
+                markDocumentService.initMarkDocument(markPaper);
+            }
+
+            UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
+            updateWrapper.lambda().set(MarkPaper::getStatus, status)
+                    .eq(MarkPaper::getExamId, examId)
+                    .eq(MarkPaper::getPaperNumber, paperNumber);
+            this.update(updateWrapper);
+        }
+
+        return true;
+    }
+
+    /**
+     * 校验试卷
+     *
+     * @param examId
+     * @param paperNumber
+     * @param teachClassName
+     * @return
+     */
+    @Override
+    public Boolean finishPaper(Long examId, String paperNumber, String teachClassName) {
+        MarkPaper markPaper = this.getByExamIdAndPaperNumber(examId, paperNumber);
+        String courseInfo = String.format("%s[%s],试卷编号%s,", markPaper.getCourseName(), markPaper.getCourseCode(), markPaper.getPaperNumber());
+        // 主观题是否全部分组
+        List<MarkQuestion> markQuestionObjectiveList = markQuestionService.listQuestionByExamIdAndPaperNumberAndGroupNumber(examId, paperNumber, null, true);
+        if (CollectionUtils.isNotEmpty(markQuestionObjectiveList)) {
+            if (markQuestionObjectiveList.stream().filter(m -> StringUtils.isBlank(m.getAnswer())).count() > 0) {
+                throw ExceptionResultEnum.ERROR.exception(courseInfo + "客观题标答未设置,无法结束评卷");
+            }
+        }
+
+        // 主观题是否全部分组
+        List<MarkQuestion> markQuestionSubjectiveList = markQuestionService.listQuestionByExamIdAndPaperNumberAndGroupNumber(examId, paperNumber, null, false);
+        // 没有主观题,不校验考生评卷
+        if (CollectionUtils.isNotEmpty(markQuestionSubjectiveList)) {
+            // 识别缺考未确认完,不能结束
+            if (markStudentService.countOmrAbsentStudent(examId, paperNumber, markPaper.getPaperType(), false, teachClassName) > 0) {
+                throw ExceptionResultEnum.ERROR.exception(courseInfo + "识别缺考记录未核对,请在扫描客户端进行确认操作后再导出成绩");
+            }
+            // 人工绑定未做完,不能结束
+            if (markStudentService.getAssignedCount(examId, false, markPaper.getCourseId(), markPaper.getCoursePaperId(), MarkPaperStatus.FORMAL, null, teachClassName) > 0) {
+                throw ExceptionResultEnum.ERROR.exception(courseInfo + "人工绑定记录未核对,请在扫描客户端进行确认操作后再导出成绩");
+            }
+            // 客观题检查未做完,不能结束
+            if (scanOmrTaskService.getFinishStudentCountByExamAndUserId(examId, markPaper.getCourseId(), markPaper.getCoursePaperId(), OmrTaskStatus.WAITING.name(), null, teachClassName) > 0) {
+                throw ExceptionResultEnum.ERROR.exception(courseInfo + "客观题存在识别嫌疑需要人工确认,请在扫描客户端进行确认操作后再导出成绩");
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public List<MarkPaper> listQualityMarkPaperByStatus(MarkPaperStatus status, int uploadCount) {
+        return this.baseMapper.listQualityMarkPaperByStatus(status.name(), uploadCount);
+    }
+
+    @Override
+    public int getCourseCount(Long examId, Long courseId, String coursePaperId, MarkPaperStatus status, DataPermissionRule dpr) {
+        return baseMapper.getCourseCount(examId, courseId, coursePaperId, status.name(), dpr);
+    }
+
+    @Override
+    public int getPaperNumberCount(Long examId, Long courseId, String coursePaperId, MarkPaperStatus status, DataPermissionRule dpr) {
+        return baseMapper.getPaperNumberCount(examId, courseId, coursePaperId, status.name(), dpr);
+    }
+
+    @Override
+    public IPage<CheckScoreListDto> listStudentScoreList(Long examId, Long courseId, String paperNumber, Integer pageNumber, Integer pageSize) {
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        Page<CheckScoreListDto> page = new Page<>(pageNumber, pageSize);
+        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(sysUser.getSchoolId(), sysUser.getId(), ServletUtil.getRequest().getServletPath());
+        return this.baseMapper.listStudentScoreList(page, examId, courseId, paperNumber, dpr);
+    }
+
+    @Override
+    public void updateStatus(Long examId, String paperNumber, MarkPaperStatus newStatus, MarkPaperStatus currentStatus) {
+        UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
+        updateWrapper.lambda().set(MarkPaper::getStatus, newStatus)
+                .eq(MarkPaper::getExamId, examId)
+                .eq(MarkPaper::getPaperNumber, paperNumber)
+                .eq(MarkPaper::getStatus, currentStatus);
+        this.update(updateWrapper);
+    }
+
+    @Override
+    public void updateUploadCount(Long examId, String paperNumber, int countUploaded) {
+        UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
+        updateWrapper.lambda().set(MarkPaper::getUploadCount, countUploaded)
+                .eq(MarkPaper::getExamId, examId)
+                .eq(MarkPaper::getPaperNumber, paperNumber);
+        this.update(updateWrapper);
+    }
+
+    @Override
+    public IPage<MarkPaperPackageDto> listPackage(Long examId, String paperNumber, String packageCode, Integer pageNumber, Integer pageSize) {
+        MarkPaper markPaper = this.getByExamIdAndPaperNumber(examId, paperNumber);
+        Page<MarkPaperPackageDto> page = new Page<>(pageNumber, pageSize);
+        IPage<MarkPaperPackageDto> markPaperPackageDtoIPage = this.baseMapper.listPackage(page, examId, markPaper.getCoursePaperId(), packageCode);
+        for (MarkPaperPackageDto packageDto : markPaperPackageDtoIPage.getRecords()) {
+            List<ScanPackage> scanPackageList = scanPackageService.listByExamIdAndCoursePaperIdAndPackageCode(examId, markPaper.getCoursePaperId(), packageDto.getPackageCode());
+            List<String> urls = scanPackageList.stream().map(m -> teachcloudCommonService.filePreview(m.getPath())).collect(Collectors.toList());
+            packageDto.setCount(urls.size());
+            packageDto.setUrls(urls);
+        }
+        return markPaperPackageDtoIPage;
+    }
+
+    @Override
+    public MarkPaper getByExamIdAndCoursePaperId(Long examId, String coursePaperId) {
+        QueryWrapper<MarkPaper> wrapper = new QueryWrapper<>();
+        wrapper.lambda().eq(MarkPaper::getExamId, examId)
+                .eq(MarkPaper::getCoursePaperId, coursePaperId);
+        wrapper.last("LIMIT 1");
+        return this.getOne(wrapper);
+    }
+
+    @Override
+    public List<MarkPaper> listByExamId(Long examId, MarkPaperStatus status, DataPermissionRule dpr) {
+        return this.baseMapper.listByExamId(examId, status.name(), dpr);
+    }
+
+    @Override
+    public void updateGroupStatusByExamIdAndPaperNumber(boolean groupStatus, Long examId, String paperNumber) {
+        UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
+        updateWrapper.lambda().set(MarkPaper::getGroupStatus, groupStatus)
+                .eq(MarkPaper::getExamId, examId)
+                .eq(MarkPaper::getPaperNumber, paperNumber);
+        this.update(updateWrapper);
+    }
+
+    @Override
+    public int countByPropositionTeacherId(boolean status) {
+        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(schoolId, sysUser.getId(), "/api/admin/mark/setting/list");
+        List<MarkSettingDto> markSettingDtoList = this.baseMapper.listPaperSetting(schoolId, null, null, null, status, dpr);
+        return CollectionUtils.isEmpty(markSettingDtoList) ? 0 : markSettingDtoList.size();
+    }
+
+    @Override
+    public void updateStudentCountByExamIdAndPaperNumberAndPaperType(Long examId, String paperNumber, String paperType) {
+        long count = markStudentService.countByExamIdAndPaperNumber(examId, paperNumber, paperType);
+        UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
+        LambdaUpdateWrapper<MarkPaper> lambda = updateWrapper.lambda();
+        lambda.set(MarkPaper::getStudentCount, count)
+                .eq(MarkPaper::getExamId, examId)
+                .eq(MarkPaper::getPaperNumber, paperNumber);
+        if (StringUtils.isNotBlank(paperType)) {
+            lambda.eq(MarkPaper::getPaperType, paperType);
+        }
+        this.update(updateWrapper);
+    }
+
+    @Override
+    public SettingDto getSetting(Long examId, String paperNumber) {
+        SettingDto settingDto = new SettingDto();
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        settingDto.setExamId(examId);
+        settingDto.setPaperNumber(paperNumber);
+        settingDto.setUserName(sysUser.getRealName());
+        MarkPaper markPaper = this.getByExamIdAndPaperNumber(examId, paperNumber);
+        if (markPaper != null) {
+            settingDto.setCourseCode(markPaper.getCourseCode());
+            settingDto.setCourseName(markPaper.getCourseName());
+            if (StringUtils.isNotBlank(markPaper.getPaperFilePath())) {
+                settingDto.setPaperUrl(teachcloudCommonService.filePreview(markPaper.getPaperFilePath()));
+            }
+            if (StringUtils.isNotBlank(markPaper.getAnswerFilePath())) {
+                settingDto.setAnswerUrl(teachcloudCommonService.filePreview(markPaper.getAnswerFilePath()));
+            }
+        }
+        return settingDto;
+    }
+
+    @Override
+    public IPage<ArchiveScoreVo> scoreList(ArchiveScoreQuery query) {
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        Page<ArchiveScoreVo> page = new Page<>(query.getPageNumber(), query.getPageSize());
+        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(sysUser.getSchoolId(), sysUser.getId(), ServletUtil.getRequest().getServletPath());
+        IPage<ArchiveScoreVo> ret = this.baseMapper.scoreList(page, sysUser.getSchoolId(), query, dpr);
+        if (CollectionUtils.isNotEmpty(ret.getRecords())) {
+            for (ArchiveScoreVo vo : ret.getRecords()) {
+                double total = vo.getStudentCount() - vo.getAbsentCount();
+                vo.setPassRate(Calculator.divide2String(Calculator.multiply(vo.getPassCount(), 100), total, 2));
+                vo.setExcellentRate(Calculator.divide2String(Calculator.multiply(vo.getExcellentCount(), 100), total, 2));
+                vo.setAvgScore(Calculator.round(vo.getAvgScore(), 2));
+                vo.setMinScore(Calculator.round(vo.getMinScore(), 2));
+                vo.setMaxScore(Calculator.round(vo.getMaxScore(), 2));
+            }
+        }
+        return ret;
+    }
+
+    @Override
+    public void deleteByExamIdAndPaperNumber(Long examId, String paperNumber) {
+        UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
+        updateWrapper.lambda().eq(MarkPaper::getExamId, examId)
+                .eq(MarkPaper::getPaperNumber, paperNumber);
+        this.remove(updateWrapper);
+    }
+
+    @Override
+    public void updateAbsentCount(Long examId, String paperNumber, int absentCount) {
+        UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
+        updateWrapper.lambda().set(MarkPaper::getAbsentCount, absentCount)
+                .eq(MarkPaper::getExamId, examId)
+                .eq(MarkPaper::getPaperNumber, paperNumber);
+        this.update(updateWrapper);
+    }
+
+    @Override
+    public IPage<ArchivePaperVo> documentList(ArchivePaperQuery query) {
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        Page<ArchiveScoreVo> page = new Page<>(query.getPageNumber(), query.getPageSize());
+        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(sysUser.getSchoolId(), sysUser.getId(), ServletUtil.getRequest().getServletPath());
+        IPage<ArchivePaperVo> ret = this.baseMapper.documentList(page, query, dpr);
+        return ret;
+    }
+
+    @Override
+    public List<MarkPaper> findMarkPaperListByExamId(Long examId) {
+        return this.baseMapper.findMarkPaperListByExamId(examId);
+    }
+}

+ 175 - 5
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkStudentServiceImpl.java

@@ -31,7 +31,10 @@ import com.qmth.teachcloud.common.enums.PageSizeEnum;
 import com.qmth.teachcloud.common.enums.ScanStatus;
 import com.qmth.teachcloud.common.enums.mark.MarkPaperStatus;
 import com.qmth.teachcloud.common.enums.mark.SubjectiveStatus;
-import com.qmth.teachcloud.common.service.*;
+import com.qmth.teachcloud.common.service.BasicRoleDataPermissionService;
+import com.qmth.teachcloud.common.service.FileUploadService;
+import com.qmth.teachcloud.common.service.SysUserService;
+import com.qmth.teachcloud.common.service.TeachcloudCommonService;
 import com.qmth.teachcloud.common.util.*;
 import com.qmth.teachcloud.mark.bean.UpdateTimeVo;
 import com.qmth.teachcloud.mark.bean.archivescore.*;
@@ -101,20 +104,21 @@ import java.util.stream.Collectors;
 @Service
 public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkStudent> implements MarkStudentService {
 
-    @Resource
-    private SysUserService sysUserService;
-    @Resource
-    private BasicCourseService basicCourseService;
     @Autowired
     private MarkPaperService markPaperService;
+
     @Resource
     private MarkPaperPackageService markPaperPackageService;
+
     @Autowired
     private ScanPackageService scanPackageService;
+
     @Autowired
     private ScanPaperService scanPaperService;
+
     @Autowired
     private ScanPaperPageService scanPaperPageService;
+
     @Autowired
     private ScanOmrTaskService scanOmrTaskService;
 
@@ -153,6 +157,7 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
 
     @Resource
     private FileUploadService fileUploadService;
+
     @Resource
     private MarkTrackService markTrackService;
 
@@ -277,6 +282,153 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
         return studentScoreDetailDtoIPage;
     }
 
+    /**
+     * 评卷管理/成绩检查/成绩详情导出
+     *
+     * @param examId
+     * @param paperNumber
+     * @param college
+     * @param majorName
+     * @param teachClassName
+     * @param className
+     * @param teacher
+     * @param filter
+     * @param status
+     * @param breach
+     * @param startScore
+     * @param endScore
+     * @param subjectiveStartScore
+     * @param subjectiveEndScore
+     * @param objectiveStartScore
+     * @param objectiveEndScore
+     * @param subScore
+     * @param objectiveScoreRateLt
+     * @param studentName
+     * @param studentCode
+     * @param orderType
+     * @param orderField
+     * @return
+     */
+    @Override
+    public List<StudentScoreDetailDto> pageStudentScoreExport(Long examId, String paperNumber, String college, String majorName, String teachClassName, String className, String teacher, Integer filter, String status, Boolean breach, Double startScore, Double endScore, Double subjectiveStartScore, Double subjectiveEndScore, Double objectiveStartScore, Double objectiveEndScore, Double subScore, Integer objectiveScoreRateLt, String studentName, String studentCode, String orderType, String orderField) {
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        if (startScore != null && endScore == null) {
+            throw ExceptionResultEnum.ERROR.exception("请输入试卷总分结束分数值");
+        }
+        if (objectiveStartScore != null && objectiveEndScore == null) {
+            throw ExceptionResultEnum.ERROR.exception("请输入客观题总分结束分数值");
+        }
+        if (subjectiveStartScore != null && subjectiveEndScore == null) {
+            throw ExceptionResultEnum.ERROR.exception("请输入主观题总分结束分数值");
+        }
+        college = SystemConstant.translateSpecificSign(college);
+        majorName = SystemConstant.translateSpecificSign(majorName);
+        className = SystemConstant.translateSpecificSign(className);
+        teacher = SystemConstant.translateSpecificSign(teacher);
+
+        MarkPaper markPaper = markPaperService.getByExamIdAndPaperNumber(examId, paperNumber);
+        Double objectiveScoreLt = objectiveScoreRateLt == null ?
+                null :
+                Calculator.round(Calculator.divide(Calculator.multiply(markPaper.getObjectiveScore(), Double.parseDouble(String.valueOf(objectiveScoreRateLt))), 100), 2);
+        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(sysUser.getSchoolId(), sysUser.getId(), "/api/admin/mark/setting/scoreList");
+        List<StudentScoreDetailDto> studentScoreDetailDtoList = this.baseMapper.pageStudentScoreExport(examId,
+                paperNumber, college, majorName, teachClassName, className, teacher, filter, status, breach, startScore, endScore,
+                subjectiveStartScore, subjectiveEndScore, objectiveStartScore, objectiveEndScore, subScore,
+                objectiveScoreLt, studentName, studentCode, orderType, orderField, dpr);
+        Set<StudentScoreDetailExportDto> studentScoreDetailExportDtoSet = new HashSet<>();
+        for (StudentScoreDetailDto scoreDetailDto : studentScoreDetailDtoList) {
+            studentScoreDetailExportDtoSet.add(new StudentScoreDetailExportDto(scoreDetailDto));
+            // 原图
+            scoreDetailDto.setSheetUrls(buildSheetUrls(scoreDetailDto.getStudentId()));
+            scoreDetailDto.setSheetPath(null);
+            // 状态
+            if (ScanStatus.UNEXIST.equals(scoreDetailDto.getScanStatus())) {
+                scoreDetailDto.setStatusDisplay("未扫描");
+            } else if (ScanStatus.MANUAL_ABSENT.equals(scoreDetailDto.getScanStatus()) || scoreDetailDto.getAbsent() || scoreDetailDto.getOmrAbsent()) {
+                scoreDetailDto.setStatusDisplay("缺考");
+            } else if (!scoreDetailDto.getAbsent() && !scoreDetailDto.getOmrAbsent() && scoreDetailDto.getUpload() && ScanStatus.SCANNED.equals(scoreDetailDto.getScanStatus())) {
+                scoreDetailDto.setStatusDisplay("正常");
+            }
+
+            // 主观题检查标记
+            scoreDetailDto.setSubjectiveCheckFlag(
+                    !scoreDetailDto.getAbsent() && !scoreDetailDto.getOmrAbsent() && scoreDetailDto.getUpload() && ScanStatus.SCANNED.equals(scoreDetailDto.getScanStatus())
+                            && SubjectiveStatus.MARKED.equals(scoreDetailDto.getSubjectiveStatus()) && StringUtils.isNotBlank(scoreDetailDto.getSubjectiveScore()) && StringUtils.isNotBlank(
+                            scoreDetailDto.getSubjectiveScoreList()));
+            // 客观题检查标记
+            scoreDetailDto.setObjectiveCheckFlag(
+                    !scoreDetailDto.getAbsent() && !scoreDetailDto.getOmrAbsent() && scoreDetailDto.getUpload() && ScanStatus.SCANNED.equals(scoreDetailDto.getScanStatus()) && StringUtils.isNotBlank(
+                            scoreDetailDto.getObjectiveScore()) && StringUtils.isNotBlank(scoreDetailDto.getObjectiveScoreList()));
+
+            // 格式化分数
+            scoreDetailDto.setObjectiveScore(Calculator.round(scoreDetailDto.getObjectiveScore(), 1));
+            scoreDetailDto.setSubjectiveScore(Calculator.round(scoreDetailDto.getSubjectiveScore(), 1));
+            scoreDetailDto.setTotalScore(Calculator.round(scoreDetailDto.getTotalScore(), 1));
+        }
+
+        if (!CollectionUtils.isEmpty(studentScoreDetailExportDtoSet)) {
+            for (StudentScoreDetailExportDto s : studentScoreDetailExportDtoSet) {
+                markPaperService.finishPaper(s.getExamId(), s.getPaperNumber(), s.getTeachClassName());
+            }
+        }
+
+        HttpServletResponse response = ServletUtil.getResponse();
+        //生成表头
+        String[] columnName = new String[]{"学生姓名", "学号", "学院", "班级", "课程代码", "课程名称", "状态", "客观分", "主观分",
+                "成绩"};
+        List<MarkQuestion> oQuestionList = markQuestionService.listQuestionByExamIdAndPaperNumberAndGroupNumber(examId, paperNumber, null, true);
+        List<MarkQuestion> sQuestionList = markQuestionService.listQuestionByExamIdAndPaperNumberAndGroupNumber(examId, paperNumber, null, false);
+        List<String> columnNameList = new ArrayList<>(Arrays.asList(columnName));
+        for (MarkQuestion question : oQuestionList) {
+            columnNameList.add(question.getMainTitle() + " " + question.getMainNumber() + "-" + question.getSubNumber() + "选项");
+            columnNameList.add(question.getMainTitle() + " " + question.getMainNumber() + "-" + question.getSubNumber() + "得分");
+        }
+        for (MarkQuestion question : sQuestionList) {
+            columnNameList.add(question.getMainTitle() + " " + question.getMainNumber() + "-" + question.getSubNumber());
+        }
+        String[] columnNames = columnNameList.toArray(new String[0]);
+        //生成动态内容
+        List<String[]> columnValues = new ArrayList<>();
+//        List<ArchiveStudentVo> ret = baseMapper.studentList(schoolId, query, null);
+        for (StudentScoreDetailDto s : studentScoreDetailDtoList) {
+            List<String> valueList = new ArrayList<>();
+            valueList.add(s.getStudentName());
+            valueList.add(s.getStudentCode());
+            valueList.add(s.getCollegeName());
+            valueList.add(s.getClassName());
+            valueList.add(s.getCourseCode());
+            valueList.add(s.getCourseName());
+            valueList.add(Objects.nonNull(s.getStatus()) ? s.getStatus().getName() : null);
+            valueList.add(s.getObjectiveScore() == null ? "" : s.getObjectiveScore().toString());
+            valueList.add(s.getSubjectiveScore() == null ? "" : s.getSubjectiveScore().toString());
+            valueList.add(s.getTotalScore() == null ? "" : s.getTotalScore().toString());
+            for (ScoreItem item : s.getScoreList(true, oQuestionList)) {
+                valueList.add(item.getAnswer());
+                valueList.add(item.getScore() == null ? "" : item.getScore().toString());
+            }
+            for (ScoreItem item : s.getScoreList(false, sQuestionList)) {
+                valueList.add(item.getScore().toString());
+            }
+            String[] columnValue = valueList.toArray(new String[valueList.size()]);
+            columnValues.add(columnValue);
+        }
+        try {
+            log.debug("导出Excel开始...");
+            response.setHeader("Content-Disposition", "inline;filename=" + URLEncoder.encode("成绩导出", SystemConstant.CHARSET_NAME) + ".xlsx");
+            response.setContentType("application/vnd.ms-excel");
+            ServletOutputStream outputStream = response.getOutputStream();
+            ExcelWriter writer = ExcelWriter.create(ExcelType.XLSX);
+            writer.writeDataArrays("成绩导出", null, columnNames, columnValues.listIterator());
+            writer.output(outputStream);
+            outputStream.flush();
+            outputStream.close();
+            log.debug("导出Excel结束");
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return studentScoreDetailDtoList;
+    }
+
     @Override
     public List<SheetUrlDto> buildSheetUrls(Long studentId) {
         // 原图
@@ -1160,6 +1312,11 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
         return this.count(queryWrapper);
     }
 
+    @Override
+    public int countOmrAbsentStudent(Long examId, String paperNumber, String paperType, boolean isOmrAbsentConfirm, String teachClassName) {
+        return this.baseMapper.countOmrAbsentStudent(examId, paperNumber, paperType, isOmrAbsentConfirm, teachClassName);
+    }
+
     @Override
     public void scoreReportDownload(JSONObject jsonObject, HttpServletResponse response) {
         String rootPath = null;
@@ -1377,6 +1534,19 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
         return baseMapper.countAssigned(markStudent, dpr);
     }
 
+    @Override
+    public int getAssignedCount(Long examId, Boolean checked, Long courseId, String coursePaperId,
+                                MarkPaperStatus status, DataPermissionRule dpr, String teachClassName) {
+        MarkStudent markStudent = new MarkStudent();
+        markStudent.setExamId(examId);
+        markStudent.setCourseId(courseId);
+        markStudent.setCoursePaperId(coursePaperId);
+        markStudent.setAssigned(true);
+        markStudent.setAssignConfirmed(checked);
+        markStudent.setMarkPaperStatus(status.name());
+        return baseMapper.countAssignedNew(markStudent, dpr, teachClassName);
+    }
+
     @Override
     public int countAbsentByExamIdAndPaperNumber(Long examId, String paperNumber) {
         QueryWrapper<MarkStudent> queryWrapper = new QueryWrapper<>();

+ 684 - 677
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/ScanOmrTaskServiceImpl.java

@@ -1,677 +1,684 @@
-package com.qmth.teachcloud.mark.service.impl;
-
-import java.util.*;
-import java.util.stream.Collectors;
-
-import javax.annotation.Resource;
-import javax.validation.constraints.NotNull;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.qmth.teachcloud.mark.dto.mark.MarkStudentVo;
-import org.apache.commons.collections4.CollectionUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
-import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.qmth.boot.core.concurrent.service.ConcurrentService;
-import com.qmth.boot.core.exception.ParameterException;
-import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
-import com.qmth.teachcloud.common.contant.SystemConstant;
-import com.qmth.teachcloud.common.entity.MarkQuestion;
-import com.qmth.teachcloud.common.entity.SysUser;
-import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
-import com.qmth.teachcloud.common.enums.QuestionType;
-import com.qmth.teachcloud.common.enums.ScanStatus;
-import com.qmth.teachcloud.common.enums.mark.MarkPaperStatus;
-import com.qmth.teachcloud.common.enums.scan.ConditionType;
-import com.qmth.teachcloud.common.enums.scan.OmrField;
-import com.qmth.teachcloud.common.service.BasicRoleDataPermissionService;
-import com.qmth.teachcloud.common.service.TeachcloudCommonService;
-import com.qmth.teachcloud.common.util.ServletUtil;
-import com.qmth.teachcloud.mark.bean.OmrTaskItem;
-import com.qmth.teachcloud.mark.bean.OmrTaskPage;
-import com.qmth.teachcloud.mark.dto.*;
-import com.qmth.teachcloud.mark.entity.*;
-import com.qmth.teachcloud.mark.enums.LockType;
-import com.qmth.teachcloud.mark.enums.OmrTaskStatus;
-import com.qmth.teachcloud.mark.mapper.ScanOmrTaskMapper;
-import com.qmth.teachcloud.mark.service.*;
-
-/**
- * <p>
- * 服务实现类
- * </p>
- *
- * @author xf
- * @since 2023-09-22
- */
-@Service
-public class ScanOmrTaskServiceImpl extends ServiceImpl<ScanOmrTaskMapper, ScanOmrTask> implements ScanOmrTaskService {
-
-    @Autowired
-    private ScanStudentPaperService studentPaperService;
-
-    @Autowired
-    private MarkStudentService studentService;
-
-    @Autowired
-    private ScanPaperService paperService;
-
-    @Autowired
-    private ScanPaperPageService pageService;
-
-    @Autowired
-    private ConcurrentService concurrentService;
-
-    @Autowired
-    private MarkQuestionService questionService;
-
-    @Resource
-    private MarkPaperService markPaperService;
-
-    @Resource
-    private TeachcloudCommonService teachcloudCommonService;
-
-    @Resource
-    private BasicRoleDataPermissionService basicRoleDataPermissionService;
-
-    private static final String OMR_SUSPECT = "?";
-
-    private static final String OMR_BLANK = "#";
-
-    @Override
-    @Transactional
-    public List<ScanOmrTask> buildTask(ConditionType c, Long studentId) {
-        List<ScanStudentPaper> paperIds = clearAndToDispose(c, studentId);
-        if (CollectionUtils.isEmpty(paperIds)) {
-            return null;
-        }
-        MarkStudent student = studentService.getById(studentId);
-        // 所有客观题空白
-        boolean allObjectiveBlank = isAllBlank(paperIds);
-        if(allObjectiveBlank){
-            return null;
-        }
-        List<OmrTaskDto> retList = new ArrayList<>();
-        boolean multi_blank = false;
-        boolean single_blank = false;
-        int multi_blank_count = 0;
-        int single_blank_count = 0;
-        for (ScanStudentPaper spe : paperIds) {
-            ScanPaper paper = paperService.getById(spe.getPaperId());
-            if (paper == null) {
-                throw new ParameterException("paper不存在");
-            }
-            if(paper.getInvalid()){
-                continue;
-            }
-            Long paperId = spe.getPaperId();
-            ScanOmrTask task = new ScanOmrTask();
-            task.setId(SystemConstant.getDbUuid());
-            task.setCardNumber(paper.getCardNumber());
-            task.setExamId(paper.getExamId());
-            task.setConditions(c);
-            task.setPaperId(paperId);
-            task.setPaperIndex(spe.getPaperIndex());
-            task.setStatus(OmrTaskStatus.WAITING);
-            task.setStudentId(spe.getStudentId());
-            task.setPages(new ArrayList<>());
-            List<ScanPaperPage> pageList = pageService.listByPaperId(paperId);
-            OmrTaskDto taskDto = new OmrTaskDto(task);
-            retList.add(taskDto);
-            // 循环试卷
-            for (ScanPaperPage pageEntity : pageList) {
-                OmrTaskPageDto pageDto = new OmrTaskPageDto(pageEntity.getPageIndex());
-                taskDto.getPage().add(pageDto);
-                List<OmrTaskItem> items = pageDto.getItems();
-                // 分组类型
-                // 识别嫌疑
-                if (ConditionType.FILL_SUSPECT.equals(c)) {
-                    for (int i = 0; pageEntity.getQuestion() != null && pageEntity.getQuestion().getResult() != null
-                            && i < pageEntity.getQuestion().getResult().size(); i++) {
-                        String result = pageEntity.getQuestion().getResult().get(i);
-                        if (result != null && result.startsWith(OMR_SUSPECT)) {
-                            OmrTaskItem item = new OmrTaskItem();
-                            item.setIndex(i + 1);
-                            item.setField(OmrField.QUESTION);
-                            item.setOmrResult(result);
-                            items.add(item);
-                        }
-                    }
-                    pageDto.setItems(items);
-                }
-                if (ConditionType.QUESTION_BLANK.equals(c)) {
-                    for (int i = 0; pageEntity.getQuestion() != null && pageEntity.getQuestion().getResult() != null
-                            && i < pageEntity.getQuestion().getResult().size(); i++) {
-                        String result = pageEntity.getQuestion().getResult().get(i);
-                        if (result != null && result.contains(OMR_BLANK)) {
-                            OmrTaskItem item = new OmrTaskItem();
-                            item.setIndex(i + 1);
-                            item.setField(OmrField.QUESTION);
-                            item.setOmrResult(result);
-                            items.add(item);
-                        }
-                    }
-                    pageDto.setItems(items);
-                }
-                // 卷型空选
-                // if (ConditionType.PAPER_TYPE_BLANK.equals(c)) {
-                // if (pageEntity.getPaperType() != null
-                // && pageEntity.getPaperType().getResult().contains(OMR_BLANK)) {
-                // OmrTaskItem item = new OmrTaskItem();
-                // item.setIndex(1);
-                // item.setField(OmrField.PAPER_TYPE);
-                // item.setOmrResult(pageEntity.getPaperType().getResult());
-                // items.add(item);
-                // }
-                // }
-                // 卷型多选
-                // if (ConditionType.PAPER_TYPE_EXCEED.equals(c)) {
-                // if ((!pageEntity.getPaperType().getResult().contains(OMR_SUSPECT)
-                // && pageEntity.getPaperType().getResult().length() > 2)
-                // || (pageEntity.getPaperType().getResult().contains(OMR_SUSPECT)
-                // && pageEntity.getPaperType().getResult().length() > 1)) {
-                // OmrTaskItem item = new OmrTaskItem();
-                // item.setField(OmrField.PAPER_TYPE);
-                // item.setOmrResult(pageEntity.getPaperType().getResult());
-                // items.add(item);
-                // }
-                // }
-//                if (ConditionType.QUESTION_MULTI_BLANK.equals(c) && ScanStatus.SCANNED.equals(student.getScanStatus())) {
-//                    List<MarkQuestion> questiongList = questionService
-//                            .listByExamIdAndPaperNumberAndPaperIndexAndPageIndex(student.getExamId(),
-//                                    student.getPaperNumber(), spe.getPaperIndex(), pageEntity.getPageIndex(),true);
-//                    if (pageEntity.getQuestion() == null || pageEntity.getQuestion().getResult() == null
-//                            || questiongList.isEmpty()) {
-//                        continue;
-//                    }
-//                    int size = pageEntity.getQuestion().getResult().size() > questiongList.size() ? questiongList.size()
-//                            : pageEntity.getQuestion().getResult().size();
-//                    for (int i = 0; i < size; i++) {
-//                        String result = pageEntity.getQuestion().getResult().get(i);
-//                        MarkQuestion question = questiongList.get(i);
-//                        if (question.getQuestionType().equals(QuestionType.MULTIPLE.getValue()) && result != null
-//                                && result.contains(OMR_BLANK)) {
-//                            OmrTaskItem item = new OmrTaskItem();
-//                            item.setIndex(i + 1);
-//                            item.setField(OmrField.QUESTION);
-//                            item.setOmrResult(result);
-//                            pageDto.getPageMultiBlankItems().add(item);
-//                            multi_blank_count++;
-//                            if (multi_blank_count > 0) {
-//                                multi_blank = true;
-//                            }
-//                        }
-//                    }
-//                }
-//                if (ConditionType.QUESTION_SINGLE_BLANK.equals(c) && ScanStatus.SCANNED.equals(student.getScanStatus())) {
-//                    List<MarkQuestion> questiongList = questionService
-//                            .listByExamIdAndPaperNumberAndPaperIndexAndPageIndex(student.getExamId(),
-//                                    student.getPaperNumber(), spe.getPaperIndex(), pageEntity.getPageIndex(),true);
-//                    if (pageEntity.getQuestion() == null || pageEntity.getQuestion().getResult() == null
-//                            || questiongList.isEmpty()) {
-//                        continue;
-//                    }
-//                    int size = pageEntity.getQuestion().getResult().size() > questiongList.size() ? questiongList.size()
-//                            : pageEntity.getQuestion().getResult().size();
-//                    for (int i = 0; i < size; i++) {
-//                        String result = pageEntity.getQuestion().getResult().get(i);
-//                        MarkQuestion question = questiongList.get(i);
-//                        if ((question.getQuestionType().equals(QuestionType.SINGLE.getValue())||question.getQuestionType().equals(QuestionType.TRUE_OR_FALSE.getValue()))
-//                                && result != null
-//                                && result.contains(OMR_BLANK)) {
-//                            OmrTaskItem item = new OmrTaskItem();
-//                            item.setIndex(i + 1);
-//                            item.setField(OmrField.QUESTION);
-//                            item.setOmrResult(result);
-//                            pageDto.getPageSingleBlankItems().add(item);
-//                            single_blank_count++;
-//                            if (single_blank_count > 0) {
-//                                single_blank = true;
-//                            }
-//                        }
-//                    }
-//                }
-                if (ConditionType.QUESTION_SINGLE_EXCEED.equals(c) && ScanStatus.SCANNED.equals(student.getScanStatus())) {
-                    List<MarkQuestion> questiongList = questionService
-                            .listByExamIdAndPaperNumberAndPaperIndexAndPageIndex(student.getExamId(),
-                                    student.getPaperNumber(), spe.getPaperIndex(), pageEntity.getPageIndex(),true);
-                    if (pageEntity.getQuestion() == null || pageEntity.getQuestion().getResult() == null
-                            || questiongList.isEmpty()) {
-                        continue;
-                    }
-                    int size = pageEntity.getQuestion().getResult().size() > questiongList.size() ? questiongList.size()
-                            : pageEntity.getQuestion().getResult().size();
-                    for (int i = 0; i < size; i++) {
-                        String result = pageEntity.getQuestion().getResult().get(i);
-                        MarkQuestion question = questiongList.get(i);
-                        String newStr = result.replace(OMR_SUSPECT, "");
-                        if ((question.getQuestionType().equals(QuestionType.SINGLE.getValue())||question.getQuestionType().equals(QuestionType.TRUE_OR_FALSE.getValue()))
-                                && result != null
-                                && newStr.length() > 1) {
-                            OmrTaskItem item = new OmrTaskItem();
-                            item.setIndex(i + 1);
-                            item.setField(OmrField.QUESTION);
-                            item.setOmrResult(result);
-                            items.add(item);
-                        }
-                    }
-                    pageDto.setItems(items);
-                }
-            }
-        }
-        List<ScanOmrTask> result = new ArrayList<>();
-        if (retList.size() == 0) {
-            return result;
-        }
-        for (OmrTaskDto dto : retList) {
-            for (OmrTaskPageDto pageDto : dto.getPage()) {
-                if (multi_blank) {
-                    pageDto.getItems().addAll(pageDto.getPageMultiBlankItems());
-                }
-                if (single_blank) {
-                    pageDto.getItems().addAll(pageDto.getPageSingleBlankItems());
-                }
-                if (pageDto.getItems().size() > 0) {
-                    OmrTaskPage page = new OmrTaskPage();
-                    page.setItems(pageDto.getItems());
-                    page.setIndex(pageDto.getPageIndex());
-                    dto.getTask().getPages().add(page);
-                }
-            }
-            if (dto.getTask().getPages().size() > 0) {
-                result.add(dto.getTask());
-            }
-        }
-        return result;
-    }
-
-    private List<ScanStudentPaper> clearAndToDispose(ConditionType c, Long studentId) {
-        List<ScanStudentPaper> spes = studentPaperService.findByStudentId(studentId);
-        if (CollectionUtils.isEmpty(spes)) {
-            return spes;
-        }
-        List<ScanOmrTask> tasks = getByStudent(c, studentId);
-        if (CollectionUtils.isEmpty(tasks)) {
-            return spes;
-        }
-        Map<Integer, Long> speMap = new HashMap<>();
-        for (ScanStudentPaper spe : spes) {
-            speMap.put(spe.getPaperIndex(), spe.getPaperId());
-        }
-        Map<Integer, Long> taskMap = new HashMap<>();
-        for (ScanOmrTask t : tasks) {
-            taskMap.put(t.getPaperIndex(), t.getPaperId());
-        }
-        if (ConditionType.FILL_SUSPECT.equals(c)) {
-            List<ScanStudentPaper> ret = new ArrayList<>();
-            for (ScanStudentPaper spe : spes) {
-                Long paperId = taskMap.get(spe.getPaperIndex());
-                if (paperId == null) {// 没有task的直接创建
-                    ret.add(spe);
-                } else if (paperId.longValue() != spe.getPaperId().longValue()) {// 和task不一致的删除并创建
-                    delete(c, studentId, paperId);
-                    ret.add(spe);
-                }
-            }
-            for (ScanOmrTask t : tasks) {
-                if (speMap.get(t.getPaperIndex()) == null) {// 不在绑定关系的task删除
-                    delete(c, studentId, t.getPaperId());
-                }
-            }
-            return ret;
-        } else {
-            if (spes.size() != tasks.size()) {// 数量不一致的删除重建
-                delete(c, studentId);
-                return spes;
-            }
-            for (ScanOmrTask t : tasks) {
-                if (!t.getPaperId().equals(speMap.get(t.getPaperIndex()))) {// 有一个不一致的删除重建
-                    delete(c, studentId);
-                    return spes;
-                }
-            }
-            return null;// 完全一致的不处理
-        }
-    }
-
-    private List<ScanOmrTask> getByStudent(ConditionType c, Long studentId) {
-        QueryWrapper<ScanOmrTask> wrapper = new QueryWrapper<>();
-        LambdaQueryWrapper<ScanOmrTask> lw = wrapper.lambda();
-        lw.eq(ScanOmrTask::getConditions, c);
-        lw.eq(ScanOmrTask::getStudentId, studentId);
-        return baseMapper.selectList(wrapper);
-    }
-
-    private void delete(ConditionType c, Long studentId, Long paperId) {
-        UpdateWrapper<ScanOmrTask> wrapper = new UpdateWrapper<>();
-        LambdaUpdateWrapper<ScanOmrTask> lw = wrapper.lambda();
-        lw.eq(ScanOmrTask::getConditions, c);
-        lw.eq(ScanOmrTask::getStudentId, studentId);
-        lw.eq(ScanOmrTask::getPaperId, paperId);
-        this.baseMapper.delete(wrapper);
-    }
-
-    private void delete(ConditionType c, Long studentId) {
-        UpdateWrapper<ScanOmrTask> wrapper = new UpdateWrapper<>();
-        LambdaUpdateWrapper<ScanOmrTask> lw = wrapper.lambda();
-        lw.eq(ScanOmrTask::getConditions, c);
-        lw.eq(ScanOmrTask::getStudentId, studentId);
-        this.baseMapper.delete(wrapper);
-    }
-
-    private boolean isAllBlank(List<ScanStudentPaper> paperIds) {
-        for (ScanStudentPaper spe : paperIds) {
-            ScanPaper paper = paperService.getById(spe.getPaperId());
-            if (paper == null) {
-                throw new ParameterException("paper不存在");
-            }
-            List<ScanPaperPage> pageList = pageService.listByPaperId(spe.getPaperId());
-            for (ScanPaperPage pageEntity : pageList) {
-                for (int i = 0; pageEntity.getQuestion() != null && pageEntity.getQuestion().getResult() != null
-                        && i < pageEntity.getQuestion().getResult().size(); i++) {
-                    String result = pageEntity.getQuestion().getResult().get(i);
-                    if (!"#".equals(result)) {
-                        return false;
-                    }
-                }
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public ScanOmrStudent getTask(Long studentId) {
-        MarkStudentVo student = studentService.getMarkStudentVoByStudentId(studentId);
-        if (student == null) {
-            throw ExceptionResultEnum.ERROR.exception("没有识别对照任务");
-        }
-        QueryWrapper<ScanOmrTask> wrapper = new QueryWrapper<>();
-        LambdaQueryWrapper<ScanOmrTask> lw = wrapper.lambda();
-        lw.eq(ScanOmrTask::getStudentId, studentId);
-        List<ScanOmrTask> list = baseMapper.selectList(wrapper);
-        if (list.isEmpty()) {
-            throw ExceptionResultEnum.ERROR.exception("没有识别对照任务");
-        }
-        ScanOmrStudent scanOmrStudent = new ScanOmrStudent();
-        scanOmrStudent.setCardNumber(student.getCardNumber());
-        scanOmrStudent.setStudentCode(student.getStudentCode());
-        scanOmrStudent.setStudentName(student.getStudentName());
-        scanOmrStudent.setCourseCode(student.getCourseCode());
-        scanOmrStudent.setCourseName(student.getCourseName());
-        scanOmrStudent.setCoursePaperId(student.getCoursePaperId());
-        scanOmrStudent.setCoursePaperNumber(student.getPaperNumber());
-        scanOmrStudent.setTasks(toTaskVo(list));
-        return scanOmrStudent;
-    }
-
-    private List<ScanOmrTaskDto> toTaskVo(List<ScanOmrTask> tasks) {
-        List<ScanOmrTaskDto> list = new ArrayList<ScanOmrTaskDto>();
-        for (ScanOmrTask task : tasks) {
-            ScanOmrTaskDto vo = new ScanOmrTaskDto();
-            vo.setId(task.getId());
-            vo.setPaperId(task.getPaperId());
-            vo.setPaperNum(task.getPaperIndex());
-            vo.setConditions(task.getConditions());
-            List<ScanOmrTaskPageDto> pages = new ArrayList<>();
-            for (OmrTaskPage taskPage : task.getPages()) {
-                ScanOmrTaskPageDto page = new ScanOmrTaskPageDto();
-                Map<Integer, List<String>> question = new HashMap<>();
-                // Map<Integer, List<String>> selective = new HashMap<>();
-                for (OmrTaskItem item : taskPage.getItems()) {
-                    // if (OmrField.ABSENT.equals(item.getField())) {
-                    // page.setAbsent(getBooleanItem(item));
-                    // }
-                    // if (OmrField.BREACH.equals(item.getField())) {
-                    // page.setBreach(getBooleanItem(item));
-                    // }
-                    // if (OmrField.PAPER_TYPE.equals(item.getField())) {
-                    // page.setPaperType(getStringItem(item));
-                    // }
-                    if (OmrField.QUESTION.equals(item.getField())) {
-                        List<String> content = getStringItem(item);
-                        if (content != null) {
-                            question.put(item.getIndex(), content);
-                        }
-                    }
-                    // if (OmrField.SELECTIVE.equals(item.getField())) {
-                    // List<String> content = getStringItem(item);
-                    // if (content != null) {
-                    // selective.put(item.getIndex(), content);
-                    // }
-                    // }
-                }
-                if (question.size() > 0) {
-                    page.setQuestion(question);
-                }
-                // if (selective.size() > 0) {
-                // page.setSelective(selective);
-                // }
-                // 有需要仲裁的数据才返回结构
-                if (page.getAbsent() != null || page.getBreach() != null || page.getPaperType() != null
-                        || page.getQuestion() != null || page.getSelective() != null) {
-                    page.setIndex(taskPage.getIndex());
-                    ScanPaperPage p = pageService.findPaperIdAndIndex(task.getPaperId(), taskPage.getIndex());
-                    page.setRecogData(p.getRecogData());
-                    page.setUri(teachcloudCommonService.filePreview(p.getSheetPath()));
-                    pages.add(page);
-                }
-            }
-            vo.setPages(pages);
-            list.add(vo);
-        }
-        return list;
-    }
-
-    private List<String> getStringItem(OmrTaskItem item) {
-        // 只取最新的值
-        List<String> value = new ArrayList<>();
-        if (item.getSecondResult() != null) {
-            value.add(item.getSecondResult());
-        } else if (item.getFirstResult() != null && item.getSecondResult() == null) {
-            value.add(item.getFirstResult());
-        } else {
-            value.add(item.getOmrResult());
-        }
-        return value;
-    }
-
-    private List<Boolean> getBooleanItem(OmrTaskItem item) {
-        List<Boolean> value = new ArrayList<>();
-        value.add(Boolean.valueOf(item.getOmrResult()));
-        if (item.getFirstResult() != null && item.getSecondResult() == null) {
-            value.add(Boolean.valueOf(item.getFirstResult()));
-        } else if (item.getSecondResult() != null) {
-            value.add(Boolean.valueOf(item.getSecondResult()));
-        }
-        return value;
-    }
-
-    @Override
-    @Transactional
-    public ScanOmrTaskSaveDto submitTask(@NotNull List<ScanOmrTaskResultDto> results, @NotNull Long userId) {
-        Long studentId = null;
-        for (ScanOmrTaskResultDto result : results) {
-            ScanOmrTask task = this.getById(result.getId());
-            if (task == null) {
-                throw new ParameterException("任务不存在");
-            }
-            if (studentId == null) {
-                studentId = task.getStudentId();
-            }
-            if (!Objects.equals(studentId, task.getStudentId())) {
-                throw new ParameterException("任务非同一个学生");
-            }
-            MarkStudent markStudent = studentService.getById(studentId);
-            if (markStudent == null) {
-                throw new ParameterException("考生不存在");
-            }
-            MarkPaper markPaper = markPaperService.getByExamIdAndCoursePaperId(markStudent.getExamId(),
-                    markStudent.getCoursePaperId());
-            if (markPaper == null) {
-                throw new ParameterException("课程不存在");
-            }
-            if (MarkPaperStatus.FINISH.equals(markPaper.getStatus())) {
-                throw ExceptionResultEnum.MARK_PAPER_FINISH.exception();
-            }
-            concurrentService.getReadWriteLock(LockType.STUDENT + "-" + task.getStudentId()).writeLock().lock();
-
-            try {
-                for (OmrTaskPage page : task.getPages()) {
-                    ScanOmrTaskResultPageDto pageVo = result.findPage(page.getIndex());
-                    if (pageVo == null) {
-                        throw new ParameterException("page[" + page.getIndex() + "]不存在");
-                    }
-                    for (OmrTaskItem item : page.getItems()) {
-                        // if (OmrField.ABSENT.equals(item.getField())) {
-                        // if (pageVo.getAbsent() == null) {
-                        // throw new ParameterException("page[" + page.getIndex() + "].absent不存在");
-                        // }
-                        // item.setFirstResult(pageVo.getAbsent().toString());
-                        // }
-                        // if (OmrField.BREACH.equals(item.getField())) {
-                        // if (pageVo.getBreach() == null) {
-                        // throw new ParameterException("page[" + page.getIndex() + "].breach不存在");
-                        // }
-                        // item.setFirstResult(pageVo.getBreach().toString());
-                        // }
-                        if (OmrField.QUESTION.equals(item.getField())) {
-                            String content = pageVo.getQuestion() != null ? pageVo.getQuestion().get(item.getIndex())
-                                    : null;
-                            if (content == null) {
-                                throw new ParameterException(
-                                        "page[" + page.getIndex() + "].question[" + item.getIndex() + "]不存在");
-                            }
-                            item.setFirstResult(content);
-                        }
-                        // if (OmrField.SELECTIVE.equals(item.getField())) {
-                        // String content = pageVo.getSelective() != null ?
-                        // pageVo.getSelective().get(item.getIndex())
-                        // : null;
-                        // if (content == null) {
-                        // throw new ParameterException(
-                        // "page[" + page.getIndex() + "].selective[" + item.getIndex() + "]不存在");
-                        // }
-                        // item.setFirstResult(content);
-                        // }
-                    }
-                }
-                task.setStatus(OmrTaskStatus.PROCESSED);
-                updatePaperResult(result, task.getPaperId(), userId);
-                task.setUserId(userId);
-                task.setUpdateTime(System.currentTimeMillis());
-                this.saveOrUpdate(task);
-            } finally {
-                concurrentService.getReadWriteLock(LockType.STUDENT + "-" + task.getStudentId()).writeLock().unlock();
-            }
-        }
-        ScanOmrTaskSaveDto vo = new ScanOmrTaskSaveDto();
-        vo.setStudentId(studentId);
-        vo.setUpdateTime(System.currentTimeMillis());
-        return vo;
-    }
-
-    private void updatePaperResult(ScanOmrTaskResultDto result, Long paperId, Long userId) {
-        ScanPaper paper = paperService.getById(paperId);
-        ScanStudentPaper sp = studentPaperService.findByPaperId(paperId);
-        if (paper == null) {
-            throw new ParameterException("未找到paper信息");
-        }
-        if (sp == null) {
-            throw new ParameterException("paper未绑定考生");
-        }
-        List<ScanPaperPage> pages = pageService.listByPaperId(paperId);
-        if (CollectionUtils.isEmpty(pages)) {
-            throw new ParameterException("未找到page信息");
-        }
-        for (ScanPaperPage page : pages) {
-            ScanOmrTaskResultPageDto vo = result.findPage(page.getPageIndex());
-            if (vo != null) {
-                vo.update(page);
-            }
-        }
-        paperService.savePaperAndPages(paper, pages);
-        studentService.updateStudentAnswer(sp.getStudentId());
-    }
-
-    @Override
-    public ScanOmrTaskStatusDto getStatus(Long examId, Long courseId, String coursePaperId) {
-        SysUser user = (SysUser) ServletUtil.getRequestUser();
-        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(user.getSchoolId(), user.getId(),
-                ServletUtil.getRequest().getServletPath());
-        ScanOmrTaskStatusDto status = new ScanOmrTaskStatusDto();
-        status.setFinishCount(this.getFinishStudentCountByExamAndUserId(examId, courseId, coursePaperId,
-                OmrTaskStatus.PROCESSED.name(), dpr));
-        status.setTodoCount(this.getFinishStudentCountByExamAndUserId(examId, courseId, coursePaperId,
-                OmrTaskStatus.WAITING.name(), dpr));
-        return status;
-    }
-
-    @Override
-    public int getFinishStudentCountByExamAndUserId(Long examId, Long courseId, String coursePaperId, String status,
-            DataPermissionRule dpr) {
-        return this.baseMapper.getStudentCountByExamAndStatusAndUserId(examId, courseId, coursePaperId, status,
-                MarkPaperStatus.FORMAL.name(), dpr);
-    }
-
-    @Transactional
-    @Override
-    public void deleteByStudentId(Long examId, Long studentId) {
-        QueryWrapper<ScanOmrTask> wrapper = new QueryWrapper<>();
-        LambdaQueryWrapper<ScanOmrTask> lw = wrapper.lambda();
-        lw.eq(ScanOmrTask::getExamId, examId);
-        lw.eq(ScanOmrTask::getStudentId, studentId);
-        List<ScanOmrTask> tasks = baseMapper.selectList(wrapper);
-        if (CollectionUtils.isEmpty(tasks)) {
-            return;
-        }
-        concurrentService.getReadWriteLock(LockType.STUDENT + "-" + studentId).writeLock().lock();
-        try {
-            List<Long> ids = tasks.stream().map(e -> e.getId()).collect(Collectors.toList());
-            this.removeByIds(ids);
-        } finally {
-            concurrentService.getReadWriteLock(LockType.STUDENT + "-" + studentId).writeLock().unlock();
-        }
-    }
-
-    @Override
-    public int getCount(Long examId, OmrTaskStatus status, String courseCode, String coursePaperId,
-            MarkPaperStatus markPaperStatus, DataPermissionRule dpr) {
-        ScanOmrTask scanOmrTask = new ScanOmrTask();
-        scanOmrTask.setExamId(examId);
-        scanOmrTask.setCourseCode(courseCode);
-        scanOmrTask.setCoursePaperId(coursePaperId);
-        scanOmrTask.setStatus(status);
-        scanOmrTask.setMarkPaperStatus(markPaperStatus.name());
-        return baseMapper.countOmrTask(scanOmrTask, dpr);
-    }
-
-    @Override
-    public IPage<ScanStudentDto> list(Long examId, Long courseId, String coursePaperId, OmrTaskStatus status, String studentCodeOrName, Integer pageNumber, Integer pageSize) {
-        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
-        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(sysUser.getSchoolId(),
-                sysUser.getId(), ServletUtil.getRequest().getServletPath());
-        return this.baseMapper.listByExamIdAndStatusAndUserId(new Page<>(pageNumber, pageSize), examId, courseId, coursePaperId, status, studentCodeOrName,
-                MarkPaperStatus.FORMAL.name(), dpr);
-    }
-
-    @Override
-    public void saveTask(Long studentId) {
-        List<ScanOmrTask> omrTaskList = new ArrayList<ScanOmrTask>();
-        for (ConditionType c : ConditionType.values()) {
-            List<ScanOmrTask> omrTask = this.buildTask(c, studentId);
-            if (omrTask!=null && !omrTask.isEmpty()) {
-                omrTaskList.addAll(omrTask);
-            }
-        }
-        if (!omrTaskList.isEmpty()) {
-            this.saveBatch(omrTaskList);
-        }
-    }
-}
+package com.qmth.teachcloud.mark.service.impl;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+import javax.annotation.Resource;
+import javax.validation.constraints.NotNull;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.qmth.teachcloud.mark.dto.mark.MarkStudentVo;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.qmth.boot.core.concurrent.service.ConcurrentService;
+import com.qmth.boot.core.exception.ParameterException;
+import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.MarkQuestion;
+import com.qmth.teachcloud.common.entity.SysUser;
+import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
+import com.qmth.teachcloud.common.enums.QuestionType;
+import com.qmth.teachcloud.common.enums.ScanStatus;
+import com.qmth.teachcloud.common.enums.mark.MarkPaperStatus;
+import com.qmth.teachcloud.common.enums.scan.ConditionType;
+import com.qmth.teachcloud.common.enums.scan.OmrField;
+import com.qmth.teachcloud.common.service.BasicRoleDataPermissionService;
+import com.qmth.teachcloud.common.service.TeachcloudCommonService;
+import com.qmth.teachcloud.common.util.ServletUtil;
+import com.qmth.teachcloud.mark.bean.OmrTaskItem;
+import com.qmth.teachcloud.mark.bean.OmrTaskPage;
+import com.qmth.teachcloud.mark.dto.*;
+import com.qmth.teachcloud.mark.entity.*;
+import com.qmth.teachcloud.mark.enums.LockType;
+import com.qmth.teachcloud.mark.enums.OmrTaskStatus;
+import com.qmth.teachcloud.mark.mapper.ScanOmrTaskMapper;
+import com.qmth.teachcloud.mark.service.*;
+
+/**
+ * <p>
+ * 服务实现类
+ * </p>
+ *
+ * @author xf
+ * @since 2023-09-22
+ */
+@Service
+public class ScanOmrTaskServiceImpl extends ServiceImpl<ScanOmrTaskMapper, ScanOmrTask> implements ScanOmrTaskService {
+
+    @Autowired
+    private ScanStudentPaperService studentPaperService;
+
+    @Autowired
+    private MarkStudentService studentService;
+
+    @Autowired
+    private ScanPaperService paperService;
+
+    @Autowired
+    private ScanPaperPageService pageService;
+
+    @Autowired
+    private ConcurrentService concurrentService;
+
+    @Autowired
+    private MarkQuestionService questionService;
+
+    @Resource
+    private MarkPaperService markPaperService;
+
+    @Resource
+    private TeachcloudCommonService teachcloudCommonService;
+
+    @Resource
+    private BasicRoleDataPermissionService basicRoleDataPermissionService;
+
+    private static final String OMR_SUSPECT = "?";
+
+    private static final String OMR_BLANK = "#";
+
+    @Override
+    @Transactional
+    public List<ScanOmrTask> buildTask(ConditionType c, Long studentId) {
+        List<ScanStudentPaper> paperIds = clearAndToDispose(c, studentId);
+        if (CollectionUtils.isEmpty(paperIds)) {
+            return null;
+        }
+        MarkStudent student = studentService.getById(studentId);
+        // 所有客观题空白
+        boolean allObjectiveBlank = isAllBlank(paperIds);
+        if (allObjectiveBlank) {
+            return null;
+        }
+        List<OmrTaskDto> retList = new ArrayList<>();
+        boolean multi_blank = false;
+        boolean single_blank = false;
+        int multi_blank_count = 0;
+        int single_blank_count = 0;
+        for (ScanStudentPaper spe : paperIds) {
+            ScanPaper paper = paperService.getById(spe.getPaperId());
+            if (paper == null) {
+                throw new ParameterException("paper不存在");
+            }
+            if (paper.getInvalid()) {
+                continue;
+            }
+            Long paperId = spe.getPaperId();
+            ScanOmrTask task = new ScanOmrTask();
+            task.setId(SystemConstant.getDbUuid());
+            task.setCardNumber(paper.getCardNumber());
+            task.setExamId(paper.getExamId());
+            task.setConditions(c);
+            task.setPaperId(paperId);
+            task.setPaperIndex(spe.getPaperIndex());
+            task.setStatus(OmrTaskStatus.WAITING);
+            task.setStudentId(spe.getStudentId());
+            task.setPages(new ArrayList<>());
+            List<ScanPaperPage> pageList = pageService.listByPaperId(paperId);
+            OmrTaskDto taskDto = new OmrTaskDto(task);
+            retList.add(taskDto);
+            // 循环试卷
+            for (ScanPaperPage pageEntity : pageList) {
+                OmrTaskPageDto pageDto = new OmrTaskPageDto(pageEntity.getPageIndex());
+                taskDto.getPage().add(pageDto);
+                List<OmrTaskItem> items = pageDto.getItems();
+                // 分组类型
+                // 识别嫌疑
+                if (ConditionType.FILL_SUSPECT.equals(c)) {
+                    for (int i = 0; pageEntity.getQuestion() != null && pageEntity.getQuestion().getResult() != null
+                            && i < pageEntity.getQuestion().getResult().size(); i++) {
+                        String result = pageEntity.getQuestion().getResult().get(i);
+                        if (result != null && result.startsWith(OMR_SUSPECT)) {
+                            OmrTaskItem item = new OmrTaskItem();
+                            item.setIndex(i + 1);
+                            item.setField(OmrField.QUESTION);
+                            item.setOmrResult(result);
+                            items.add(item);
+                        }
+                    }
+                    pageDto.setItems(items);
+                }
+                if (ConditionType.QUESTION_BLANK.equals(c)) {
+                    for (int i = 0; pageEntity.getQuestion() != null && pageEntity.getQuestion().getResult() != null
+                            && i < pageEntity.getQuestion().getResult().size(); i++) {
+                        String result = pageEntity.getQuestion().getResult().get(i);
+                        if (result != null && result.contains(OMR_BLANK)) {
+                            OmrTaskItem item = new OmrTaskItem();
+                            item.setIndex(i + 1);
+                            item.setField(OmrField.QUESTION);
+                            item.setOmrResult(result);
+                            items.add(item);
+                        }
+                    }
+                    pageDto.setItems(items);
+                }
+                // 卷型空选
+                // if (ConditionType.PAPER_TYPE_BLANK.equals(c)) {
+                // if (pageEntity.getPaperType() != null
+                // && pageEntity.getPaperType().getResult().contains(OMR_BLANK)) {
+                // OmrTaskItem item = new OmrTaskItem();
+                // item.setIndex(1);
+                // item.setField(OmrField.PAPER_TYPE);
+                // item.setOmrResult(pageEntity.getPaperType().getResult());
+                // items.add(item);
+                // }
+                // }
+                // 卷型多选
+                // if (ConditionType.PAPER_TYPE_EXCEED.equals(c)) {
+                // if ((!pageEntity.getPaperType().getResult().contains(OMR_SUSPECT)
+                // && pageEntity.getPaperType().getResult().length() > 2)
+                // || (pageEntity.getPaperType().getResult().contains(OMR_SUSPECT)
+                // && pageEntity.getPaperType().getResult().length() > 1)) {
+                // OmrTaskItem item = new OmrTaskItem();
+                // item.setField(OmrField.PAPER_TYPE);
+                // item.setOmrResult(pageEntity.getPaperType().getResult());
+                // items.add(item);
+                // }
+                // }
+//                if (ConditionType.QUESTION_MULTI_BLANK.equals(c) && ScanStatus.SCANNED.equals(student.getScanStatus())) {
+//                    List<MarkQuestion> questiongList = questionService
+//                            .listByExamIdAndPaperNumberAndPaperIndexAndPageIndex(student.getExamId(),
+//                                    student.getPaperNumber(), spe.getPaperIndex(), pageEntity.getPageIndex(),true);
+//                    if (pageEntity.getQuestion() == null || pageEntity.getQuestion().getResult() == null
+//                            || questiongList.isEmpty()) {
+//                        continue;
+//                    }
+//                    int size = pageEntity.getQuestion().getResult().size() > questiongList.size() ? questiongList.size()
+//                            : pageEntity.getQuestion().getResult().size();
+//                    for (int i = 0; i < size; i++) {
+//                        String result = pageEntity.getQuestion().getResult().get(i);
+//                        MarkQuestion question = questiongList.get(i);
+//                        if (question.getQuestionType().equals(QuestionType.MULTIPLE.getValue()) && result != null
+//                                && result.contains(OMR_BLANK)) {
+//                            OmrTaskItem item = new OmrTaskItem();
+//                            item.setIndex(i + 1);
+//                            item.setField(OmrField.QUESTION);
+//                            item.setOmrResult(result);
+//                            pageDto.getPageMultiBlankItems().add(item);
+//                            multi_blank_count++;
+//                            if (multi_blank_count > 0) {
+//                                multi_blank = true;
+//                            }
+//                        }
+//                    }
+//                }
+//                if (ConditionType.QUESTION_SINGLE_BLANK.equals(c) && ScanStatus.SCANNED.equals(student.getScanStatus())) {
+//                    List<MarkQuestion> questiongList = questionService
+//                            .listByExamIdAndPaperNumberAndPaperIndexAndPageIndex(student.getExamId(),
+//                                    student.getPaperNumber(), spe.getPaperIndex(), pageEntity.getPageIndex(),true);
+//                    if (pageEntity.getQuestion() == null || pageEntity.getQuestion().getResult() == null
+//                            || questiongList.isEmpty()) {
+//                        continue;
+//                    }
+//                    int size = pageEntity.getQuestion().getResult().size() > questiongList.size() ? questiongList.size()
+//                            : pageEntity.getQuestion().getResult().size();
+//                    for (int i = 0; i < size; i++) {
+//                        String result = pageEntity.getQuestion().getResult().get(i);
+//                        MarkQuestion question = questiongList.get(i);
+//                        if ((question.getQuestionType().equals(QuestionType.SINGLE.getValue())||question.getQuestionType().equals(QuestionType.TRUE_OR_FALSE.getValue()))
+//                                && result != null
+//                                && result.contains(OMR_BLANK)) {
+//                            OmrTaskItem item = new OmrTaskItem();
+//                            item.setIndex(i + 1);
+//                            item.setField(OmrField.QUESTION);
+//                            item.setOmrResult(result);
+//                            pageDto.getPageSingleBlankItems().add(item);
+//                            single_blank_count++;
+//                            if (single_blank_count > 0) {
+//                                single_blank = true;
+//                            }
+//                        }
+//                    }
+//                }
+                if (ConditionType.QUESTION_SINGLE_EXCEED.equals(c) && ScanStatus.SCANNED.equals(student.getScanStatus())) {
+                    List<MarkQuestion> questiongList = questionService
+                            .listByExamIdAndPaperNumberAndPaperIndexAndPageIndex(student.getExamId(),
+                                    student.getPaperNumber(), spe.getPaperIndex(), pageEntity.getPageIndex(), true);
+                    if (pageEntity.getQuestion() == null || pageEntity.getQuestion().getResult() == null
+                            || questiongList.isEmpty()) {
+                        continue;
+                    }
+                    int size = pageEntity.getQuestion().getResult().size() > questiongList.size() ? questiongList.size()
+                            : pageEntity.getQuestion().getResult().size();
+                    for (int i = 0; i < size; i++) {
+                        String result = pageEntity.getQuestion().getResult().get(i);
+                        MarkQuestion question = questiongList.get(i);
+                        String newStr = result.replace(OMR_SUSPECT, "");
+                        if ((question.getQuestionType().equals(QuestionType.SINGLE.getValue()) || question.getQuestionType().equals(QuestionType.TRUE_OR_FALSE.getValue()))
+                                && result != null
+                                && newStr.length() > 1) {
+                            OmrTaskItem item = new OmrTaskItem();
+                            item.setIndex(i + 1);
+                            item.setField(OmrField.QUESTION);
+                            item.setOmrResult(result);
+                            items.add(item);
+                        }
+                    }
+                    pageDto.setItems(items);
+                }
+            }
+        }
+        List<ScanOmrTask> result = new ArrayList<>();
+        if (retList.size() == 0) {
+            return result;
+        }
+        for (OmrTaskDto dto : retList) {
+            for (OmrTaskPageDto pageDto : dto.getPage()) {
+                if (multi_blank) {
+                    pageDto.getItems().addAll(pageDto.getPageMultiBlankItems());
+                }
+                if (single_blank) {
+                    pageDto.getItems().addAll(pageDto.getPageSingleBlankItems());
+                }
+                if (pageDto.getItems().size() > 0) {
+                    OmrTaskPage page = new OmrTaskPage();
+                    page.setItems(pageDto.getItems());
+                    page.setIndex(pageDto.getPageIndex());
+                    dto.getTask().getPages().add(page);
+                }
+            }
+            if (dto.getTask().getPages().size() > 0) {
+                result.add(dto.getTask());
+            }
+        }
+        return result;
+    }
+
+    private List<ScanStudentPaper> clearAndToDispose(ConditionType c, Long studentId) {
+        List<ScanStudentPaper> spes = studentPaperService.findByStudentId(studentId);
+        if (CollectionUtils.isEmpty(spes)) {
+            return spes;
+        }
+        List<ScanOmrTask> tasks = getByStudent(c, studentId);
+        if (CollectionUtils.isEmpty(tasks)) {
+            return spes;
+        }
+        Map<Integer, Long> speMap = new HashMap<>();
+        for (ScanStudentPaper spe : spes) {
+            speMap.put(spe.getPaperIndex(), spe.getPaperId());
+        }
+        Map<Integer, Long> taskMap = new HashMap<>();
+        for (ScanOmrTask t : tasks) {
+            taskMap.put(t.getPaperIndex(), t.getPaperId());
+        }
+        if (ConditionType.FILL_SUSPECT.equals(c)) {
+            List<ScanStudentPaper> ret = new ArrayList<>();
+            for (ScanStudentPaper spe : spes) {
+                Long paperId = taskMap.get(spe.getPaperIndex());
+                if (paperId == null) {// 没有task的直接创建
+                    ret.add(spe);
+                } else if (paperId.longValue() != spe.getPaperId().longValue()) {// 和task不一致的删除并创建
+                    delete(c, studentId, paperId);
+                    ret.add(spe);
+                }
+            }
+            for (ScanOmrTask t : tasks) {
+                if (speMap.get(t.getPaperIndex()) == null) {// 不在绑定关系的task删除
+                    delete(c, studentId, t.getPaperId());
+                }
+            }
+            return ret;
+        } else {
+            if (spes.size() != tasks.size()) {// 数量不一致的删除重建
+                delete(c, studentId);
+                return spes;
+            }
+            for (ScanOmrTask t : tasks) {
+                if (!t.getPaperId().equals(speMap.get(t.getPaperIndex()))) {// 有一个不一致的删除重建
+                    delete(c, studentId);
+                    return spes;
+                }
+            }
+            return null;// 完全一致的不处理
+        }
+    }
+
+    private List<ScanOmrTask> getByStudent(ConditionType c, Long studentId) {
+        QueryWrapper<ScanOmrTask> wrapper = new QueryWrapper<>();
+        LambdaQueryWrapper<ScanOmrTask> lw = wrapper.lambda();
+        lw.eq(ScanOmrTask::getConditions, c);
+        lw.eq(ScanOmrTask::getStudentId, studentId);
+        return baseMapper.selectList(wrapper);
+    }
+
+    private void delete(ConditionType c, Long studentId, Long paperId) {
+        UpdateWrapper<ScanOmrTask> wrapper = new UpdateWrapper<>();
+        LambdaUpdateWrapper<ScanOmrTask> lw = wrapper.lambda();
+        lw.eq(ScanOmrTask::getConditions, c);
+        lw.eq(ScanOmrTask::getStudentId, studentId);
+        lw.eq(ScanOmrTask::getPaperId, paperId);
+        this.baseMapper.delete(wrapper);
+    }
+
+    private void delete(ConditionType c, Long studentId) {
+        UpdateWrapper<ScanOmrTask> wrapper = new UpdateWrapper<>();
+        LambdaUpdateWrapper<ScanOmrTask> lw = wrapper.lambda();
+        lw.eq(ScanOmrTask::getConditions, c);
+        lw.eq(ScanOmrTask::getStudentId, studentId);
+        this.baseMapper.delete(wrapper);
+    }
+
+    private boolean isAllBlank(List<ScanStudentPaper> paperIds) {
+        for (ScanStudentPaper spe : paperIds) {
+            ScanPaper paper = paperService.getById(spe.getPaperId());
+            if (paper == null) {
+                throw new ParameterException("paper不存在");
+            }
+            List<ScanPaperPage> pageList = pageService.listByPaperId(spe.getPaperId());
+            for (ScanPaperPage pageEntity : pageList) {
+                for (int i = 0; pageEntity.getQuestion() != null && pageEntity.getQuestion().getResult() != null
+                        && i < pageEntity.getQuestion().getResult().size(); i++) {
+                    String result = pageEntity.getQuestion().getResult().get(i);
+                    if (!"#".equals(result)) {
+                        return false;
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public ScanOmrStudent getTask(Long studentId) {
+        MarkStudentVo student = studentService.getMarkStudentVoByStudentId(studentId);
+        if (student == null) {
+            throw ExceptionResultEnum.ERROR.exception("没有识别对照任务");
+        }
+        QueryWrapper<ScanOmrTask> wrapper = new QueryWrapper<>();
+        LambdaQueryWrapper<ScanOmrTask> lw = wrapper.lambda();
+        lw.eq(ScanOmrTask::getStudentId, studentId);
+        List<ScanOmrTask> list = baseMapper.selectList(wrapper);
+        if (list.isEmpty()) {
+            throw ExceptionResultEnum.ERROR.exception("没有识别对照任务");
+        }
+        ScanOmrStudent scanOmrStudent = new ScanOmrStudent();
+        scanOmrStudent.setCardNumber(student.getCardNumber());
+        scanOmrStudent.setStudentCode(student.getStudentCode());
+        scanOmrStudent.setStudentName(student.getStudentName());
+        scanOmrStudent.setCourseCode(student.getCourseCode());
+        scanOmrStudent.setCourseName(student.getCourseName());
+        scanOmrStudent.setCoursePaperId(student.getCoursePaperId());
+        scanOmrStudent.setCoursePaperNumber(student.getPaperNumber());
+        scanOmrStudent.setTasks(toTaskVo(list));
+        return scanOmrStudent;
+    }
+
+    private List<ScanOmrTaskDto> toTaskVo(List<ScanOmrTask> tasks) {
+        List<ScanOmrTaskDto> list = new ArrayList<ScanOmrTaskDto>();
+        for (ScanOmrTask task : tasks) {
+            ScanOmrTaskDto vo = new ScanOmrTaskDto();
+            vo.setId(task.getId());
+            vo.setPaperId(task.getPaperId());
+            vo.setPaperNum(task.getPaperIndex());
+            vo.setConditions(task.getConditions());
+            List<ScanOmrTaskPageDto> pages = new ArrayList<>();
+            for (OmrTaskPage taskPage : task.getPages()) {
+                ScanOmrTaskPageDto page = new ScanOmrTaskPageDto();
+                Map<Integer, List<String>> question = new HashMap<>();
+                // Map<Integer, List<String>> selective = new HashMap<>();
+                for (OmrTaskItem item : taskPage.getItems()) {
+                    // if (OmrField.ABSENT.equals(item.getField())) {
+                    // page.setAbsent(getBooleanItem(item));
+                    // }
+                    // if (OmrField.BREACH.equals(item.getField())) {
+                    // page.setBreach(getBooleanItem(item));
+                    // }
+                    // if (OmrField.PAPER_TYPE.equals(item.getField())) {
+                    // page.setPaperType(getStringItem(item));
+                    // }
+                    if (OmrField.QUESTION.equals(item.getField())) {
+                        List<String> content = getStringItem(item);
+                        if (content != null) {
+                            question.put(item.getIndex(), content);
+                        }
+                    }
+                    // if (OmrField.SELECTIVE.equals(item.getField())) {
+                    // List<String> content = getStringItem(item);
+                    // if (content != null) {
+                    // selective.put(item.getIndex(), content);
+                    // }
+                    // }
+                }
+                if (question.size() > 0) {
+                    page.setQuestion(question);
+                }
+                // if (selective.size() > 0) {
+                // page.setSelective(selective);
+                // }
+                // 有需要仲裁的数据才返回结构
+                if (page.getAbsent() != null || page.getBreach() != null || page.getPaperType() != null
+                        || page.getQuestion() != null || page.getSelective() != null) {
+                    page.setIndex(taskPage.getIndex());
+                    ScanPaperPage p = pageService.findPaperIdAndIndex(task.getPaperId(), taskPage.getIndex());
+                    page.setRecogData(p.getRecogData());
+                    page.setUri(teachcloudCommonService.filePreview(p.getSheetPath()));
+                    pages.add(page);
+                }
+            }
+            vo.setPages(pages);
+            list.add(vo);
+        }
+        return list;
+    }
+
+    private List<String> getStringItem(OmrTaskItem item) {
+        // 只取最新的值
+        List<String> value = new ArrayList<>();
+        if (item.getSecondResult() != null) {
+            value.add(item.getSecondResult());
+        } else if (item.getFirstResult() != null && item.getSecondResult() == null) {
+            value.add(item.getFirstResult());
+        } else {
+            value.add(item.getOmrResult());
+        }
+        return value;
+    }
+
+    private List<Boolean> getBooleanItem(OmrTaskItem item) {
+        List<Boolean> value = new ArrayList<>();
+        value.add(Boolean.valueOf(item.getOmrResult()));
+        if (item.getFirstResult() != null && item.getSecondResult() == null) {
+            value.add(Boolean.valueOf(item.getFirstResult()));
+        } else if (item.getSecondResult() != null) {
+            value.add(Boolean.valueOf(item.getSecondResult()));
+        }
+        return value;
+    }
+
+    @Override
+    @Transactional
+    public ScanOmrTaskSaveDto submitTask(@NotNull List<ScanOmrTaskResultDto> results, @NotNull Long userId) {
+        Long studentId = null;
+        for (ScanOmrTaskResultDto result : results) {
+            ScanOmrTask task = this.getById(result.getId());
+            if (task == null) {
+                throw new ParameterException("任务不存在");
+            }
+            if (studentId == null) {
+                studentId = task.getStudentId();
+            }
+            if (!Objects.equals(studentId, task.getStudentId())) {
+                throw new ParameterException("任务非同一个学生");
+            }
+            MarkStudent markStudent = studentService.getById(studentId);
+            if (markStudent == null) {
+                throw new ParameterException("考生不存在");
+            }
+            MarkPaper markPaper = markPaperService.getByExamIdAndCoursePaperId(markStudent.getExamId(),
+                    markStudent.getCoursePaperId());
+            if (markPaper == null) {
+                throw new ParameterException("课程不存在");
+            }
+            if (MarkPaperStatus.FINISH.equals(markPaper.getStatus())) {
+                throw ExceptionResultEnum.MARK_PAPER_FINISH.exception();
+            }
+            concurrentService.getReadWriteLock(LockType.STUDENT + "-" + task.getStudentId()).writeLock().lock();
+
+            try {
+                for (OmrTaskPage page : task.getPages()) {
+                    ScanOmrTaskResultPageDto pageVo = result.findPage(page.getIndex());
+                    if (pageVo == null) {
+                        throw new ParameterException("page[" + page.getIndex() + "]不存在");
+                    }
+                    for (OmrTaskItem item : page.getItems()) {
+                        // if (OmrField.ABSENT.equals(item.getField())) {
+                        // if (pageVo.getAbsent() == null) {
+                        // throw new ParameterException("page[" + page.getIndex() + "].absent不存在");
+                        // }
+                        // item.setFirstResult(pageVo.getAbsent().toString());
+                        // }
+                        // if (OmrField.BREACH.equals(item.getField())) {
+                        // if (pageVo.getBreach() == null) {
+                        // throw new ParameterException("page[" + page.getIndex() + "].breach不存在");
+                        // }
+                        // item.setFirstResult(pageVo.getBreach().toString());
+                        // }
+                        if (OmrField.QUESTION.equals(item.getField())) {
+                            String content = pageVo.getQuestion() != null ? pageVo.getQuestion().get(item.getIndex())
+                                    : null;
+                            if (content == null) {
+                                throw new ParameterException(
+                                        "page[" + page.getIndex() + "].question[" + item.getIndex() + "]不存在");
+                            }
+                            item.setFirstResult(content);
+                        }
+                        // if (OmrField.SELECTIVE.equals(item.getField())) {
+                        // String content = pageVo.getSelective() != null ?
+                        // pageVo.getSelective().get(item.getIndex())
+                        // : null;
+                        // if (content == null) {
+                        // throw new ParameterException(
+                        // "page[" + page.getIndex() + "].selective[" + item.getIndex() + "]不存在");
+                        // }
+                        // item.setFirstResult(content);
+                        // }
+                    }
+                }
+                task.setStatus(OmrTaskStatus.PROCESSED);
+                updatePaperResult(result, task.getPaperId(), userId);
+                task.setUserId(userId);
+                task.setUpdateTime(System.currentTimeMillis());
+                this.saveOrUpdate(task);
+            } finally {
+                concurrentService.getReadWriteLock(LockType.STUDENT + "-" + task.getStudentId()).writeLock().unlock();
+            }
+        }
+        ScanOmrTaskSaveDto vo = new ScanOmrTaskSaveDto();
+        vo.setStudentId(studentId);
+        vo.setUpdateTime(System.currentTimeMillis());
+        return vo;
+    }
+
+    private void updatePaperResult(ScanOmrTaskResultDto result, Long paperId, Long userId) {
+        ScanPaper paper = paperService.getById(paperId);
+        ScanStudentPaper sp = studentPaperService.findByPaperId(paperId);
+        if (paper == null) {
+            throw new ParameterException("未找到paper信息");
+        }
+        if (sp == null) {
+            throw new ParameterException("paper未绑定考生");
+        }
+        List<ScanPaperPage> pages = pageService.listByPaperId(paperId);
+        if (CollectionUtils.isEmpty(pages)) {
+            throw new ParameterException("未找到page信息");
+        }
+        for (ScanPaperPage page : pages) {
+            ScanOmrTaskResultPageDto vo = result.findPage(page.getPageIndex());
+            if (vo != null) {
+                vo.update(page);
+            }
+        }
+        paperService.savePaperAndPages(paper, pages);
+        studentService.updateStudentAnswer(sp.getStudentId());
+    }
+
+    @Override
+    public ScanOmrTaskStatusDto getStatus(Long examId, Long courseId, String coursePaperId) {
+        SysUser user = (SysUser) ServletUtil.getRequestUser();
+        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(user.getSchoolId(), user.getId(),
+                ServletUtil.getRequest().getServletPath());
+        ScanOmrTaskStatusDto status = new ScanOmrTaskStatusDto();
+        status.setFinishCount(this.getFinishStudentCountByExamAndUserId(examId, courseId, coursePaperId,
+                OmrTaskStatus.PROCESSED.name(), dpr));
+        status.setTodoCount(this.getFinishStudentCountByExamAndUserId(examId, courseId, coursePaperId,
+                OmrTaskStatus.WAITING.name(), dpr));
+        return status;
+    }
+
+    @Override
+    public int getFinishStudentCountByExamAndUserId(Long examId, Long courseId, String coursePaperId, String status,
+                                                    DataPermissionRule dpr) {
+        return this.baseMapper.getStudentCountByExamAndStatusAndUserId(examId, courseId, coursePaperId, status,
+                MarkPaperStatus.FORMAL.name(), dpr);
+    }
+
+    @Override
+    public int getFinishStudentCountByExamAndUserId(Long examId, Long courseId, String coursePaperId, String status,
+                                                    DataPermissionRule dpr, String teachClassName) {
+        return this.baseMapper.getStudentCountByExamAndStatusAndUserIdNew(examId, courseId, coursePaperId, status,
+                MarkPaperStatus.FORMAL.name(), dpr, teachClassName);
+    }
+
+    @Transactional
+    @Override
+    public void deleteByStudentId(Long examId, Long studentId) {
+        QueryWrapper<ScanOmrTask> wrapper = new QueryWrapper<>();
+        LambdaQueryWrapper<ScanOmrTask> lw = wrapper.lambda();
+        lw.eq(ScanOmrTask::getExamId, examId);
+        lw.eq(ScanOmrTask::getStudentId, studentId);
+        List<ScanOmrTask> tasks = baseMapper.selectList(wrapper);
+        if (CollectionUtils.isEmpty(tasks)) {
+            return;
+        }
+        concurrentService.getReadWriteLock(LockType.STUDENT + "-" + studentId).writeLock().lock();
+        try {
+            List<Long> ids = tasks.stream().map(e -> e.getId()).collect(Collectors.toList());
+            this.removeByIds(ids);
+        } finally {
+            concurrentService.getReadWriteLock(LockType.STUDENT + "-" + studentId).writeLock().unlock();
+        }
+    }
+
+    @Override
+    public int getCount(Long examId, OmrTaskStatus status, String courseCode, String coursePaperId,
+                        MarkPaperStatus markPaperStatus, DataPermissionRule dpr) {
+        ScanOmrTask scanOmrTask = new ScanOmrTask();
+        scanOmrTask.setExamId(examId);
+        scanOmrTask.setCourseCode(courseCode);
+        scanOmrTask.setCoursePaperId(coursePaperId);
+        scanOmrTask.setStatus(status);
+        scanOmrTask.setMarkPaperStatus(markPaperStatus.name());
+        return baseMapper.countOmrTask(scanOmrTask, dpr);
+    }
+
+    @Override
+    public IPage<ScanStudentDto> list(Long examId, Long courseId, String coursePaperId, OmrTaskStatus status, String studentCodeOrName, Integer pageNumber, Integer pageSize) {
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(sysUser.getSchoolId(),
+                sysUser.getId(), ServletUtil.getRequest().getServletPath());
+        return this.baseMapper.listByExamIdAndStatusAndUserId(new Page<>(pageNumber, pageSize), examId, courseId, coursePaperId, status, studentCodeOrName,
+                MarkPaperStatus.FORMAL.name(), dpr);
+    }
+
+    @Override
+    public void saveTask(Long studentId) {
+        List<ScanOmrTask> omrTaskList = new ArrayList<ScanOmrTask>();
+        for (ConditionType c : ConditionType.values()) {
+            List<ScanOmrTask> omrTask = this.buildTask(c, studentId);
+            if (omrTask != null && !omrTask.isEmpty()) {
+                omrTaskList.addAll(omrTask);
+            }
+        }
+        if (!omrTaskList.isEmpty()) {
+            this.saveBatch(omrTaskList);
+        }
+    }
+}

+ 202 - 126
teachcloud-mark/src/main/resources/mapper/MarkStudentMapper.xml

@@ -44,7 +44,8 @@
         <result column="breach_code" property="breachCode"/>
         <result column="card_number" property="cardNumber"/>
     </resultMap>
-    <select id="pageStudentScore" resultType="com.qmth.teachcloud.mark.dto.mark.score.StudentScoreDetailDto">
+
+    <sql id="pageStudentScoreCommon">
         SELECT
         ms.id studentId,
         ms.exam_id examId,
@@ -53,6 +54,8 @@
         ms.paper_number paperNumber,
         bes.student_name studentName,
         bes.student_code studentCode,
+        bes.college_name collegeName,
+        bes.status,
         ms.secret_number secretNumber,
         bes.college_name college,
         bes.major_name majorName,
@@ -87,139 +90,148 @@
         LEFT JOIN
         sys_user su1 ON bes.teacher_id = su1.id
         <where>
-        <if test="college != null and college != ''">
-            AND bes.college_name LIKE CONCAT('%', #{college}, '%')
-        </if>
-        <if test="majorName != null and majorName != ''">
-            AND bes.major_name LIKE CONCAT('%', #{majorName}, '%')
-        </if>
-        <if test="teachClassName != null and teachClassName != ''">
-            AND bes.teach_class_name LIKE CONCAT('%', #{teachClassName}, '%')
-        </if>
-        <if test="className != null and className != ''">
-            AND bes.class_name LIKE CONCAT('%', #{className}, '%')
-        </if>
-        <if test="teacher != null and teacher != ''">
-            AND su1.real_name LIKE CONCAT('%', #{teacher},'%')
-        </if>
-        <if test="filter != null">
-            <choose>
-                <when test="filter == 1">
-                    AND ms.objective_score = 0
-                </when>
-                <when test="filter == 2">
-                    AND ms.objective_score = 0 AND ms.subjective_score > 0
-                </when>
-                <when test="filter == 3">
-                    AND ms.objective_score > 0 AND ms.subjective_score = 0
-                </when>
-            </choose>
-        </if>
-        <if test="status != null">
-            <choose>
-                <when test="status == 'ABSENT'">
-                    AND (ms.is_absent = 1 OR ms.omr_absent = 1 OR ms.scan_status = 'MANUAL_ABSENT')
-                </when>
-                <when test="status == 'NORMAL'">
-                    AND (ms.is_absent = 0 and ms.omr_absent = 0 and ms.scan_status = 'SCANNED' AND ms.is_upload = 1)
-                </when>
-                <otherwise>
-                    AND (ms.scan_status = 'UNEXIST')
-                </otherwise>
-            </choose>
-        </if>
-        <if test="breach != null">
-            AND ms.is_breach = #{breach}
-        </if>
-        <if test="startScore != null">
-            <choose>
-                <when test="startScore == 0">
-                    AND (ms.is_absent = 1 OR ms.is_breach = 1 OR ((ifnull(ms.subjective_score, 0) +
-                    ifnull(ms.objective_score, 0)) &gt;= #{startScore} AND (ifnull(ms.subjective_score,0) +
-                    ifnull(ms.objective_score,0)) &lt;= #{endScore}))
-                </when>
-                <otherwise>
-                    AND (ms.is_absent = 0 AND ms.is_breach = 0 AND ((ifnull(ms.subjective_score,0) +
-                    ifnull(ms.objective_score,0)) &gt;= #{startScore} AND (ifnull(ms.subjective_score,0) +
-                    ifnull(ms.objective_score,0)) &lt;= #{endScore}))
-                </otherwise>
-            </choose>
-        </if>
-        <if test="subjectiveStartScore != null">
-            <choose>
-                <when test="subjectiveStartScore == 0">
-                    AND (ms.is_absent = 1 OR ms.is_breach = 1
-                    OR ((ifnull(ms.subjective_score, 0) &gt;= #{subjectiveStartScore}
-                    AND ifnull(ms.subjective_score, 0) &lt;= #{subjectiveEndScore})))
-                </when>
-                <otherwise>
-                    AND (ms.is_absent = 0 AND ms.is_breach = 0
-                    AND ((ifnull(ms.subjective_score, 0) &gt;= #{subjectiveStartScore}
-                    AND ifnull(ms.subjective_score, 0) &lt;= #{subjectiveEndScore})))
-                </otherwise>
-            </choose>
-        </if>
-        <if test="objectiveStartScore != null">
-            <choose>
-                <when test="objectiveStartScore == 0">
-                    AND (ms.is_absent = 1 OR ms.is_breach = 1
-                    OR ((ifnull(ms.objective_score, 0) &gt;= #{objectiveStartScore}
-                    AND ifnull(ms.objective_score, 0) &lt;= #{objectiveEndScore})))
-                </when>
-                <otherwise>
-                    AND (ms.is_absent = 0 AND ms.is_breach = 0
-                    AND ((ifnull(ms.objective_score, 0) &gt;= #{objectiveStartScore}
-                    AND ifnull(ms.objective_score, 0) &lt;= #{objectiveEndScore})))
-                </otherwise>
-            </choose>
-        </if>
-        <if test="subScore != null">
-            AND exists (SELECT 1 FROM mark_subjective_score mss WHERE ms.id = mss.student_id AND mss.score =
-            #{subScore})
-        </if>
-        <if test="objectiveScoreLt != null">
-            AND ms.objective_score &lt; #{objectiveScoreLt}
-        </if>
-        <if test="studentName != null and studentName != ''">
-            AND bes.student_name like concat('%',#{studentName}, '%')
-        </if>
-        <if test="studentCode != null and studentCode != ''">
-            AND bes.student_code = #{studentCode}
-        </if>
-        <if test="orderType != null and orderType != '' and orderField != null and orderField != ''">
-            <choose>
-                <when test="orderField == 'totalScore'">
-                    <if test="orderType == 'ASC'">
-                        order by (ifnull(ms.objective_score, 0) + ifnull(ms.subjective_score, 0)) ASC
-                    </if>
-                    <if test="orderType == 'DESC'">
-                        order by (ifnull(ms.objective_score, 0) + ifnull(ms.subjective_score, 0)) DESC
-                    </if>
-                </when>
-                <otherwise>
-                    order by #{orderField} #{orderType}
-                </otherwise>
-            </choose>
-        </if>
-        <if test="dpr != null">
-            <if test="dpr.requestUserId != null">
-                AND bes.teacher_id = #{dpr.requestUserId}
+            <if test="college != null and college != ''">
+                AND bes.college_name LIKE CONCAT('%', #{college}, '%')
+            </if>
+            <if test="majorName != null and majorName != ''">
+                AND bes.major_name LIKE CONCAT('%', #{majorName}, '%')
+            </if>
+            <if test="teachClassName != null and teachClassName != ''">
+                AND bes.teach_class_name LIKE CONCAT('%', #{teachClassName}, '%')
+            </if>
+            <if test="className != null and className != ''">
+                AND bes.class_name LIKE CONCAT('%', #{className}, '%')
+            </if>
+            <if test="teacher != null and teacher != ''">
+                AND su1.real_name LIKE CONCAT('%', #{teacher},'%')
+            </if>
+            <if test="filter != null">
+                <choose>
+                    <when test="filter == 1">
+                        AND ms.objective_score = 0
+                    </when>
+                    <when test="filter == 2">
+                        AND ms.objective_score = 0 AND ms.subjective_score > 0
+                    </when>
+                    <when test="filter == 3">
+                        AND ms.objective_score > 0 AND ms.subjective_score = 0
+                    </when>
+                </choose>
             </if>
-            <if test="dpr.courseUserId != null">
-                AND EXISTS( SELECT 1 FROM (select course_id from teach_course where exam_id = #{examId} and user_id = #{dpr.courseUserId}) tc WHERE tc.course_id = ms.course_id)
+            <if test="status != null">
+                <choose>
+                    <when test="status == 'ABSENT'">
+                        AND (ms.is_absent = 1 OR ms.omr_absent = 1 OR ms.scan_status = 'MANUAL_ABSENT')
+                    </when>
+                    <when test="status == 'NORMAL'">
+                        AND (ms.is_absent = 0 and ms.omr_absent = 0 and ms.scan_status = 'SCANNED' AND ms.is_upload = 1)
+                    </when>
+                    <otherwise>
+                        AND (ms.scan_status = 'UNEXIST')
+                    </otherwise>
+                </choose>
+            </if>
+            <if test="breach != null">
+                AND ms.is_breach = #{breach}
+            </if>
+            <if test="startScore != null">
+                <choose>
+                    <when test="startScore == 0">
+                        AND (ms.is_absent = 1 OR ms.is_breach = 1 OR ((ifnull(ms.subjective_score, 0) +
+                        ifnull(ms.objective_score, 0)) &gt;= #{startScore} AND (ifnull(ms.subjective_score,0) +
+                        ifnull(ms.objective_score,0)) &lt;= #{endScore}))
+                    </when>
+                    <otherwise>
+                        AND (ms.is_absent = 0 AND ms.is_breach = 0 AND ((ifnull(ms.subjective_score,0) +
+                        ifnull(ms.objective_score,0)) &gt;= #{startScore} AND (ifnull(ms.subjective_score,0) +
+                        ifnull(ms.objective_score,0)) &lt;= #{endScore}))
+                    </otherwise>
+                </choose>
+            </if>
+            <if test="subjectiveStartScore != null">
+                <choose>
+                    <when test="subjectiveStartScore == 0">
+                        AND (ms.is_absent = 1 OR ms.is_breach = 1
+                        OR ((ifnull(ms.subjective_score, 0) &gt;= #{subjectiveStartScore}
+                        AND ifnull(ms.subjective_score, 0) &lt;= #{subjectiveEndScore})))
+                    </when>
+                    <otherwise>
+                        AND (ms.is_absent = 0 AND ms.is_breach = 0
+                        AND ((ifnull(ms.subjective_score, 0) &gt;= #{subjectiveStartScore}
+                        AND ifnull(ms.subjective_score, 0) &lt;= #{subjectiveEndScore})))
+                    </otherwise>
+                </choose>
+            </if>
+            <if test="objectiveStartScore != null">
+                <choose>
+                    <when test="objectiveStartScore == 0">
+                        AND (ms.is_absent = 1 OR ms.is_breach = 1
+                        OR ((ifnull(ms.objective_score, 0) &gt;= #{objectiveStartScore}
+                        AND ifnull(ms.objective_score, 0) &lt;= #{objectiveEndScore})))
+                    </when>
+                    <otherwise>
+                        AND (ms.is_absent = 0 AND ms.is_breach = 0
+                        AND ((ifnull(ms.objective_score, 0) &gt;= #{objectiveStartScore}
+                        AND ifnull(ms.objective_score, 0) &lt;= #{objectiveEndScore})))
+                    </otherwise>
+                </choose>
+            </if>
+            <if test="subScore != null">
+                AND exists (SELECT 1 FROM mark_subjective_score mss WHERE ms.id = mss.student_id AND mss.score =
+                #{subScore})
+            </if>
+            <if test="objectiveScoreLt != null">
+                AND ms.objective_score &lt; #{objectiveScoreLt}
+            </if>
+            <if test="studentName != null and studentName != ''">
+                AND bes.student_name like concat('%',#{studentName}, '%')
+            </if>
+            <if test="studentCode != null and studentCode != ''">
+                AND bes.student_code = #{studentCode}
+            </if>
+            <if test="orderType != null and orderType != '' and orderField != null and orderField != ''">
+                <choose>
+                    <when test="orderField == 'totalScore'">
+                        <if test="orderType == 'ASC'">
+                            order by (ifnull(ms.objective_score, 0) + ifnull(ms.subjective_score, 0)) ASC
+                        </if>
+                        <if test="orderType == 'DESC'">
+                            order by (ifnull(ms.objective_score, 0) + ifnull(ms.subjective_score, 0)) DESC
+                        </if>
+                    </when>
+                    <otherwise>
+                        order by #{orderField} #{orderType}
+                    </otherwise>
+                </choose>
             </if>
-            <if test="dpr.orgIdSet != null and dpr.orgIdSet != '' and dpr.orgIdSet.size > 0">
-                AND bc.teaching_room_id IN
-                <foreach collection="dpr.orgIdSet" item="item" index="index" open="(" separator="," close=")">
-                    #{item}
-                </foreach>
+            <if test="dpr != null">
+                <if test="dpr.requestUserId != null">
+                    AND bes.teacher_id = #{dpr.requestUserId}
+                </if>
+                <if test="dpr.courseUserId != null">
+                    AND EXISTS( SELECT 1 FROM (select course_id from teach_course where exam_id = #{examId} and user_id = #{dpr.courseUserId}) tc WHERE tc.course_id = ms.course_id)
+                </if>
+                <if test="dpr.orgIdSet != null and dpr.orgIdSet != '' and dpr.orgIdSet.size > 0">
+                    AND bc.teaching_room_id IN
+                    <foreach collection="dpr.orgIdSet" item="item" index="index" open="(" separator="," close=")">
+                        #{item}
+                    </foreach>
+                </if>
             </if>
-        </if>
         </where>
         <if test="orderType == null or orderType == '' or orderField == null or orderField == ''">
             order by bes.student_code
         </if>
+    </sql>
+
+    <select id="pageStudentScore" resultType="com.qmth.teachcloud.mark.dto.mark.score.StudentScoreDetailDto">
+        <include refid="pageStudentScoreCommon" />
+    </select>
+
+    <select id="pageStudentScoreExport" resultType="com.qmth.teachcloud.mark.dto.mark.score.StudentScoreDetailDto">
+        <include refid="pageStudentScoreCommon" />
     </select>
+
     <select id="listAbsentOrBreachMarkTaskStudent" resultMap="BaseResultMap">
         SELECT *
         FROM mark_student ms
@@ -860,4 +872,68 @@
         </where>
     </select>
 
+    <select id="countOmrAbsentStudent" resultType="java.lang.Integer">
+        select count(1) from mark_student ms
+        left join basic_exam_student bes on bes.id = ms.basic_student_id
+        <where> 1 = 1
+            <if test="examId != null and examId != ''">
+                and ms.exam_id = #{examId}
+            </if>
+            <if test="paperNumber != null and paperNumber != ''">
+                and ms.paper_number = #{paperNumber}
+            </if>
+            <if test="paperType != null and paperType != ''">
+                and ms.paper_type = #{paperType}
+            </if>
+                and ms.omr_absent = true
+            <if test="isOmrAbsentConfirm != null and isOmrAbsentConfirm != '' or isOmrAbsentConfirm == 0">
+                and ms.omr_absent_checked = #{isOmrAbsentConfirm}
+            </if>
+            <if test="teachClassName != null and teachClassName != ''">
+                and bes.teach_class_name = #{teachClassName}
+            </if>
+        </where>
+    </select>
+
+    <select id="countAssignedNew" resultType="java.lang.Integer">
+        SELECT
+        count(1)
+        FROM
+        mark_student ms
+        LEFT JOIN sys_user su ON ms.create_id = su.id
+        left join basic_exam_student bes on bes.id = ms.basic_student_id
+        <where>
+            ms.exam_id = #{markStudent.examId}
+            <if test="markStudent.courseId != null">
+                AND ms.course_id = #{markStudent.courseId}
+            </if>
+            <if test="markStudent.coursePaperId != null">
+                AND ms.course_paper_id = #{markStudent.coursePaperId}
+            </if>
+            <if test="markStudent.assigned != null">
+                AND ms.assigned = #{markStudent.assigned}
+            </if>
+            <if test="markStudent.assignConfirmed != null">
+                AND ms.assign_confirmed = #{markStudent.assignConfirmed}
+            </if>
+            <if test="dpr != null">
+                <if test="dpr.requestUserId != null">
+                    AND ms.create_id = #{dpr.requestUserId}
+                </if>
+                <if test="dpr.orgIdSet != null and dpr.orgIdSet != '' and dpr.orgIdSet.size > 0">
+                    AND su.org_id IN
+                    <foreach collection="dpr.orgIdSet" item="item" index="index" open="(" separator="," close=")">
+                        #{item}
+                    </foreach>
+                </if>
+            </if>
+            <if test="markStudent.markPaperStatus != null">
+                AND exists(select 1 from mark_paper mp where ms.exam_id = mp.exam_id and ms.paper_number =
+                mp.paper_number and ms.paper_type = mp.paper_type and mp.status = #{markStudent.markPaperStatus})
+            </if>
+            <if test="teachClassName != null and teachClassName != ''">
+                and bes.teach_class_name = #{teachClassName}
+            </if>
+        </where>
+    </select>
 </mapper>

+ 39 - 0
teachcloud-mark/src/main/resources/mapper/ScanOmrTaskMapper.xml

@@ -109,6 +109,45 @@
 		</where>
 	</select>
 
+    <select id="getStudentCountByExamAndStatusAndUserIdNew" resultType="int">
+        select
+        count(1)
+        from mark_student s left join sys_user su on s.create_id = su.id
+        left join basic_exam_student bes on bes.id = s.basic_student_id
+        <where>
+            <if test="examId != null">
+                and s.exam_id = #{examId}
+            </if>
+            <if test="courseId != null">
+                and s.course_id = #{courseId}
+            </if>
+            <if test="coursePaperId != null and coursePaperId != ''">
+                and s.course_paper_id = #{coursePaperId}
+            </if>
+            <if test="teachClassName != null and teachClassName != ''">
+                and bes.teach_class_name = #{teachClassName}
+            </if>
+            and exists (select 1 from mark_paper mp where s.exam_id = mp.exam_id and s.course_paper_id = mp.course_paper_id and s.paper_type = mp.paper_type and mp.status = #{markPaperStatus})
+            and exists(select 1
+            from scan_omr_task t
+            where t.exam_id = #{examId}
+            and t.status=#{status}
+            and s.id = t.student_id
+            <if test="dpr != null">
+                <if test="dpr.requestUserId != null">
+                    AND s.create_id = #{dpr.requestUserId}
+                </if>
+                <if test="dpr.orgIdSet != null and dpr.orgIdSet != '' and dpr.orgIdSet.size > 0">
+                    AND su.org_id IN
+                    <foreach collection="dpr.orgIdSet" item="item" index="index" open="(" separator="," close=")">
+                        #{item}
+                    </foreach>
+                </if>
+            </if>
+            )
+        </where>
+    </select>
+
     <select id="countOmrTask" resultType="java.lang.Integer">
 		SELECT
 			COUNT(distinct  sot.student_id)