Prechádzať zdrojové kódy

班级详情列表查询

xiatian 1 rok pred
rodič
commit
943b4b9678

+ 10 - 0
distributed-print/src/main/java/com/qmth/distributed/print/api/mark/MarkArchiveController.java

@@ -12,7 +12,9 @@ import com.qmth.teachcloud.common.contant.SystemConstant;
 import com.qmth.teachcloud.common.util.Result;
 import com.qmth.teachcloud.common.util.ResultUtil;
 import com.qmth.teachcloud.mark.bean.archivescore.ArchiveScoreQuery;
+import com.qmth.teachcloud.mark.bean.archivescore.ArchiveStudentQuery;
 import com.qmth.teachcloud.mark.service.MarkPaperService;
+import com.qmth.teachcloud.mark.service.MarkStudentService;
 
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -32,6 +34,8 @@ public class MarkArchiveController {
 
 	@Autowired
 	private MarkPaperService markPaperService;
+	@Autowired
+	private MarkStudentService markStudentService;
 	
 	
     @ApiOperation(value = "成绩管理列表")
@@ -39,4 +43,10 @@ public class MarkArchiveController {
     public Result scoreList(@Validated ArchiveScoreQuery query) {
         return ResultUtil.ok(markPaperService.scoreList(query));
     }
+    
+    @ApiOperation(value = "班级详情列表")
+    @RequestMapping(value = "student/list", method = RequestMethod.POST)
+    public Result studentList(@Validated ArchiveStudentQuery query) {
+        return ResultUtil.ok(markStudentService.studentList(query));
+    }
 }

+ 63 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/bean/archivescore/ArchiveStudentQuery.java

@@ -0,0 +1,63 @@
+package com.qmth.teachcloud.mark.bean.archivescore;
+
+import javax.validation.constraints.NotNull;
+
+import com.qmth.teachcloud.mark.utils.PagerQuery;
+
+public class ArchiveStudentQuery extends PagerQuery {
+	@NotNull(message = "考试Id不能为空")
+	private Long examId;
+	@NotNull(message = "paperNumber不能为空")
+	private String paperNumber;
+	private String college;
+	private String major;
+	private String className;
+	private String studentName;
+	private String studentCode;
+	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 getCollege() {
+		return college;
+	}
+	public void setCollege(String college) {
+		this.college = college;
+	}
+	public String getMajor() {
+		return major;
+	}
+	public void setMajor(String major) {
+		this.major = major;
+	}
+	public String getClassName() {
+		return className;
+	}
+	public void setClassName(String className) {
+		this.className = className;
+	}
+	public String getStudentName() {
+		return studentName;
+	}
+	public void setStudentName(String studentName) {
+		this.studentName = studentName;
+	}
+	public String getStudentCode() {
+		return studentCode;
+	}
+	public void setStudentCode(String studentCode) {
+		this.studentCode = studentCode;
+	}
+
+
+
+
+}

+ 108 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/bean/archivescore/ArchiveStudentVo.java

@@ -0,0 +1,108 @@
+package com.qmth.teachcloud.mark.bean.archivescore;
+
+import java.util.List;
+
+import io.swagger.annotations.ApiModelProperty;
+
+public class ArchiveStudentVo {
+	private Long id;
+
+    @ApiModelProperty(value = "科目代码")
+    private String courseCode;
+
+    @ApiModelProperty(value = "科目名称")
+    private String courseName;
+
+
+    @ApiModelProperty(value = "学号")
+    private String studentCode;
+
+    @ApiModelProperty(value = "姓名")
+    private String studentName;
+
+
+    @ApiModelProperty(value = "学院")
+    private String college;
+
+    @ApiModelProperty(value = "班级")
+    private String className;
+    
+    private Double totalScore;
+    
+    private List<String> sheetUrls;
+
+	public String getCourseCode() {
+		return courseCode;
+	}
+
+	public void setCourseCode(String courseCode) {
+		this.courseCode = courseCode;
+	}
+
+	public String getCourseName() {
+		return courseName;
+	}
+
+	public void setCourseName(String courseName) {
+		this.courseName = courseName;
+	}
+
+	public String getStudentCode() {
+		return studentCode;
+	}
+
+	public void setStudentCode(String studentCode) {
+		this.studentCode = studentCode;
+	}
+
+	public String getStudentName() {
+		return studentName;
+	}
+
+	public void setStudentName(String studentName) {
+		this.studentName = studentName;
+	}
+
+	public String getCollege() {
+		return college;
+	}
+
+	public void setCollege(String college) {
+		this.college = college;
+	}
+
+	public String getClassName() {
+		return className;
+	}
+
+	public void setClassName(String className) {
+		this.className = className;
+	}
+
+	public Double getTotalScore() {
+		return totalScore;
+	}
+
+	public void setTotalScore(Double totalScore) {
+		this.totalScore = totalScore;
+	}
+
+	public List<String> getSheetUrls() {
+		return sheetUrls;
+	}
+
+	public void setSheetUrls(List<String> sheetUrls) {
+		this.sheetUrls = sheetUrls;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+    
+    
+
+}

+ 27 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/bean/archivescore/ScanPaperPageVo.java

@@ -0,0 +1,27 @@
+package com.qmth.teachcloud.mark.bean.archivescore;
+
+public class ScanPaperPageVo {
+
+
+	private Long studentId;
+
+	private String sheetPath;
+
+	public Long getStudentId() {
+		return studentId;
+	}
+
+	public void setStudentId(Long studentId) {
+		this.studentId = studentId;
+	}
+
+	public String getSheetPath() {
+		return sheetPath;
+	}
+
+	public void setSheetPath(String sheetPath) {
+		this.sheetPath = sheetPath;
+	}
+	
+	
+}

+ 4 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/mapper/MarkStudentMapper.java

@@ -3,6 +3,8 @@ 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.mark.bean.archivescore.ArchiveStudentQuery;
+import com.qmth.teachcloud.mark.bean.archivescore.ArchiveStudentVo;
 import com.qmth.teachcloud.mark.bean.scananswer.AnswerQueryDomain;
 import com.qmth.teachcloud.mark.bean.scananswer.AnswerQueryVo;
 import com.qmth.teachcloud.mark.bean.student.StudentQuery;
@@ -36,4 +38,6 @@ public interface MarkStudentMapper extends BaseMapper<MarkStudent> {
 	List<String> querySummary(@Param("query") AnswerQueryDomain query);
 
     List<Long> findIdByExamIdAndPaperNumberAndSubjectiveStatus(@Param("examId") Long examId, @Param("paperNumber") String paperNumber, @Param("unmark") String unmark, @Param("marked") String marked);
+
+	List<ArchiveStudentVo> studentList(@Param("req")ArchiveStudentQuery query);
 }

+ 8 - 1
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/mapper/ScanPaperPageMapper.java

@@ -1,7 +1,12 @@
 package com.qmth.teachcloud.mark.mapper;
 
-import com.qmth.teachcloud.mark.entity.ScanPaperPage;
+import java.util.List;
+
+import org.apache.ibatis.annotations.Param;
+
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.qmth.teachcloud.mark.bean.archivescore.ScanPaperPageVo;
+import com.qmth.teachcloud.mark.entity.ScanPaperPage;
 
 /**
  * <p>
@@ -13,4 +18,6 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  */
 public interface ScanPaperPageMapper extends BaseMapper<ScanPaperPage> {
 
+	List<ScanPaperPageVo> listByStudentIds(@Param("studentIds")List<Long> studentIds);
+
 }

+ 1 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkPaperService.java

@@ -56,4 +56,5 @@ public interface MarkPaperService extends IService<MarkPaper> {
     SettingDto getSetting(Long examId, String paperNumber);
 
 	IPage<ArchiveScoreVo> scoreList(ArchiveScoreQuery query);
+
 }

+ 8 - 4
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkStudentService.java

@@ -1,11 +1,17 @@
 package com.qmth.teachcloud.mark.service;
 
+import java.util.List;
+
+import javax.validation.constraints.NotNull;
+
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.qmth.teachcloud.common.entity.BasicExam;
 import com.qmth.teachcloud.common.entity.SysUser;
 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.omredit.OmrEditDomain;
 import com.qmth.teachcloud.mark.bean.scananswer.AnswerQueryDomain;
 import com.qmth.teachcloud.mark.bean.scananswer.AnswerQueryVo;
@@ -21,10 +27,6 @@ import com.qmth.teachcloud.mark.dto.mark.score.StudentScoreDetailDto;
 import com.qmth.teachcloud.mark.entity.MarkStudent;
 import com.qmth.teachcloud.mark.entity.ScanStudentPaper;
 import com.qmth.teachcloud.mark.params.MarkHeaderResult;
-import com.qmth.teachcloud.mark.params.MarkResult;
-
-import javax.validation.constraints.NotNull;
-import java.util.List;
 
 /**
  * <p>
@@ -99,4 +101,6 @@ public interface MarkStudentService extends IService<MarkStudent> {
     Task getSubjectiveInspectedTask(Long studentId);
 
     void saveSubjectiveInspectedTask(MarkHeaderResult markResult);
+
+	List<ArchiveStudentVo> studentList(ArchiveStudentQuery query);
 }

+ 4 - 4
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/ScanPaperPageService.java

@@ -1,10 +1,10 @@
 package com.qmth.teachcloud.mark.service;
 
-import com.qmth.teachcloud.mark.entity.ScanPaperPage;
-
 import java.util.List;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.qmth.teachcloud.mark.bean.archivescore.ScanPaperPageVo;
+import com.qmth.teachcloud.mark.entity.ScanPaperPage;
 
 /**
  * <p>
@@ -20,6 +20,6 @@ public interface ScanPaperPageService extends IService<ScanPaperPage> {
 
 	List<ScanPaperPage> listByPaperId(Long paperId);
 
-	List<ScanPaperPage> listByPaperList(List<Long> paramList);
-
+	List<ScanPaperPage> listByPaperList(List<Long> paperIds);
+	List<ScanPaperPageVo> listByStudentIds(List<Long> studentIds);
 }

+ 690 - 655
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkStudentServiceImpl.java

@@ -20,6 +20,9 @@ import com.qmth.teachcloud.common.enums.scan.ConditionType;
 import com.qmth.teachcloud.common.service.TeachcloudCommonService;
 import com.qmth.teachcloud.common.util.ServletUtil;
 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.ScanPaperPageVo;
 import com.qmth.teachcloud.mark.bean.omredit.OmrEditDomain;
 import com.qmth.teachcloud.mark.bean.omredit.OmrEditPaper;
 import com.qmth.teachcloud.mark.bean.scananswer.*;
@@ -68,662 +71,694 @@ import java.util.stream.Collectors;
  */
 @Service
 public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkStudent> implements MarkStudentService {
-    @Autowired
-    private MarkPaperService markPaperService;
-    @Autowired
-    private ScanPackageService scanPackageService;
-    @Autowired
-    private ScanPaperService scanPaperService;
-    @Autowired
-    private ScanPaperPageService scanPaperPageService;
-    @Autowired
-    private ScanOmrTaskService scanOmrTaskService;
-    @Autowired
-    private ScanAnswerCardService answerCardService;
-    @Autowired
-    private ScanStudentPaperService studentPaperService;
-    @Resource
-    private MarkQuestionService markQuestionService;
-    @Resource
-    private TeachcloudCommonService teachcloudCommonService;
-    @Autowired
-    private ConcurrentService concurrentService;
-    @Resource
-    private MarkService markService;
-    @Resource
-    private LockService lockService;
-    @Resource
-    private TaskService taskService;
-    @Resource
-    private MarkUserGroupService markUserGroupService;
-
-
-    @Override
-    public List<String> listClassByExamIdAndCourseCode(Long examId, String paperNumber) {
-        QueryWrapper<MarkStudent> queryWrapper = new QueryWrapper<>();
-        queryWrapper.lambda().eq(MarkStudent::getExamId, examId).eq(MarkStudent::getPaperNumber, paperNumber);
-        List<MarkStudent> markStudentList = this.list(queryWrapper);
-
-        List<String> classNameList = new ArrayList<>();
-        if (CollectionUtils.isNotEmpty(markStudentList)) {
-            classNameList = markStudentList.stream().filter(m -> StringUtils.isNotBlank(m.getClassName()))
-                    .map(MarkStudent::getClassName).distinct().collect(Collectors.toList());
-        }
-        return classNameList;
-    }
-
-    @Override
-    public void updateSubjectiveStatusAndScore(Long studentId, SubjectiveStatus status, Double score, String scoreList) {
-        UpdateWrapper<MarkStudent> updateWrapper = new UpdateWrapper<>();
-        updateWrapper.lambda().set(MarkStudent::getSubjectiveStatus, status).set(MarkStudent::getSubjectiveScore, score)
-                .set(MarkStudent::getSubjectiveScoreList, scoreList).eq(MarkStudent::getId, studentId);
-        this.update(updateWrapper);
-    }
-
-    @Override
-    public void updateSubjectiveStatusAndScore(Long examId, String paperNumber, SubjectiveStatus status, double score, String scoreList) {
-        UpdateWrapper<MarkStudent> updateWrapper = new UpdateWrapper<>();
-        updateWrapper.lambda().set(MarkStudent::getSubjectiveStatus, status)
-                .set(MarkStudent::getSubjectiveScore, score)
-                .set(MarkStudent::getSubjectiveScoreList, scoreList)
-                .eq(MarkStudent::getExamId, examId)
-                .eq(MarkStudent::getPaperNumber, paperNumber);
-        this.update(updateWrapper);
-    }
-
-    @Override
-    public ScanExamInfoVo getScanExamInfo(BasicExam exam) {
-        ScanExamInfoVo vo = new ScanExamInfoVo();
-        vo.setId(exam.getId());
-        vo.setName(exam.getName());
-        vo.getAnswerScan().setCourseCount(markPaperService.getCountByExam(exam.getId()));
-        vo.getAnswerScan().setTotalCount(getCount(exam.getId(), null));
-        vo.getAnswerScan().setScannedCount(getCount(exam.getId(), ScanStatus.SCANNED));
-        vo.getPackageScan().setScannedCount(scanPackageService.getCount(exam.getId()));
-        return vo;
-    }
-
-    @Override
-    public IPage<StudentScoreDetailDto> pageStudentScore(Long examId, String paperNumber, String college,
-                                                         String className, String teacher, Integer filter, Boolean absent, Boolean breach, Double startScore,
-                                                         Double endScore, Double subScore, Integer objectiveScoreRateLt, String studentName, String studentCode,
-                                                         Integer pageNumber, Integer pageSize) {
-        if (startScore != null && endScore == null) {
-            throw ExceptionResultEnum.ERROR.exception("请输入结束分数值");
-        }
-        Page<StudentScoreDetailDto> page = new Page<>(pageNumber, pageSize);
-        MarkPaper markPaper = markPaperService.getByExamIdAndPaperNumber(examId, paperNumber);
-        Double objectiveScoreLt = objectiveScoreRateLt == null ? null
-                : Double.parseDouble(new DecimalFormat("####.###")
-                .format(markPaper.getObjectiveScore() * objectiveScoreRateLt / 100));
-        IPage<StudentScoreDetailDto> studentScoreDetailDtoIPage = this.baseMapper.pageStudentScore(page, examId,
-                paperNumber, college, className, teacher, filter, absent, breach, startScore, endScore, subScore,
-                objectiveScoreLt, studentName, studentCode);
-        for (StudentScoreDetailDto scoreDetailDto : studentScoreDetailDtoIPage.getRecords()) {
-            // 原图
-            scoreDetailDto.setSheetUrls(buildSheetUrls(scoreDetailDto.getStudentId()));
-
-        }
-        return studentScoreDetailDtoIPage;
-    }
-
-    @Override
-    public List<SheetUrlDto> buildSheetUrls(Long studentId) {
-        // 原图
-        List<SheetUrlDto> sheetUrls = new ArrayList<>();
-        List<StudentPaperDetailDto> studentPaperDetailDtoList = scanPaperService.listStudentPaperDetail(studentId);
-        for (int i = 0; i < studentPaperDetailDtoList.size(); i++) {
-            StudentPaperDetailDto studentPaperDetailDto = studentPaperDetailDtoList.get(i);
-            sheetUrls.add(new SheetUrlDto(2 * (studentPaperDetailDto.getPaperIndex() - 1) + studentPaperDetailDto.getPageIndex(), teachcloudCommonService.filePreview(studentPaperDetailDto.getSheetPath())));
-        }
-        return sheetUrls;
-    }
-
-    private int getCount(Long examId, ScanStatus status) {
-        QueryWrapper<MarkStudent> wrapper = new QueryWrapper<>();
-        LambdaQueryWrapper<MarkStudent> lw = wrapper.lambda();
-        lw.eq(MarkStudent::getExamId, examId);
-        if (status != null) {
-            lw.eq(MarkStudent::getScanStatus, status);
-        }
-        return baseMapper.selectCount(wrapper);
-    }
-
-    private int getOmrAbsentCount(Long examId, Boolean checked) {
-        QueryWrapper<MarkStudent> wrapper = new QueryWrapper<>();
-        LambdaQueryWrapper<MarkStudent> lw = wrapper.lambda();
-        lw.eq(MarkStudent::getExamId, examId);
-        lw.eq(MarkStudent::getOmrAbsent, true);
-        if (checked != null) {
-            lw.eq(MarkStudent::getOmrAbsentChecked, checked);
-        }
-        return baseMapper.selectCount(wrapper);
-    }
-
-    private int getIncompleteCount(Long examId) {
-        QueryWrapper<MarkStudent> wrapper = new QueryWrapper<>();
-        LambdaQueryWrapper<MarkStudent> lw = wrapper.lambda();
-        lw.eq(MarkStudent::getExamId, examId);
-        lw.eq(MarkStudent::getIncomplete, true);
-        return baseMapper.selectCount(wrapper);
-    }
-
-    @Override
-    public ScanExamCheckInfoVo checkInfo(BasicExam exam) {
-        Long examId = exam.getId();
-        ScanExamCheckInfoVo vo = new ScanExamCheckInfoVo();
-        vo.setId(exam.getId());
-        vo.setName(exam.getName());
-        CheckTask ct = vo.getCheckTask();
-        ct.setUnexistCount(getCount(examId, ScanStatus.UNEXIST));
-        ct.setUnexistCheckedCount(getCount(examId, ScanStatus.MANUAL_ABSENT));
-        ct.setAssignedCount(scanPaperService.getAssignedCount(examId, false));
-        ct.setAssignedCheckedCount(scanPaperService.getAssignedCount(examId, true));
-        ct.setAbsentCheckCount(getOmrAbsentCount(examId, false));
-        ct.setAbsentCheckedCount(getOmrAbsentCount(examId, true));
-        ct.setObjectiveCheckCount(scanOmrTaskService.getCount(examId, OmrTaskStatus.WAITING));
-        ct.setObjectiveCheckedCount(scanOmrTaskService.getCount(examId, OmrTaskStatus.PROCESSED));
-        ct.setIncompleteCount(getIncompleteCount(examId));
-        return vo;
-    }
-
-    /**
-     * 根据考生当前绑定的paper刷新考生状态,需要在外部调用处对考生上锁
-     */
-    @Override
-    @Transactional
-    public void updateStudentByPaper(@NotNull Long userId, @NotNull Long studentId, @NotNull boolean updateOmrTask) {
-        MarkStudent student = this.getById(studentId);
-        if (student == null) {
-            throw new ParameterException("找不到对应的考生");
-        }
-        // 重置状态
-        student.setIncomplete(false);
-        student.setAssigned(false);
-        student.setQuestionFilled(false);
-        student.setOmrAbsent(false);
-        int paperCount = 0;
-        List<ScanStudentPaper> studentPaperList = studentPaperService.findByStudentId(studentId);
-        for (ScanStudentPaper studentPaper : studentPaperList) {
-            paperCount++;
-            // 获取paper详情更新考生状态
-            ScanPaper paper = scanPaperService.getById(studentPaper.getPaperId());
-            student.setAssigned(student.getAssigned() || paper.getAssigned());
-            student.setQuestionFilled(student.getQuestionFilled() || paper.getQuestionFilled());
-            student.setCardNumber(paper.getCardNumber());
-            // 单独判断首张纸正面的识别结果
-            if (studentPaper.getPaperIndex() == 1) {
-                // 根据识别结果更新考生属性
-                ScanPaperPage page = scanPaperPageService.findPaperIdAndIndex(paper.getId(), 1);
-                student.setOmrAbsent(page.getAbsent() == null ? false : page.getAbsent().getResult());
+	@Autowired
+	private MarkPaperService markPaperService;
+	@Autowired
+	private ScanPackageService scanPackageService;
+	@Autowired
+	private ScanPaperService scanPaperService;
+	@Autowired
+	private ScanPaperPageService scanPaperPageService;
+	@Autowired
+	private ScanOmrTaskService scanOmrTaskService;
+	@Autowired
+	private ScanAnswerCardService answerCardService;
+	@Autowired
+	private ScanStudentPaperService studentPaperService;
+	@Resource
+	private MarkQuestionService markQuestionService;
+	@Resource
+	private TeachcloudCommonService teachcloudCommonService;
+	@Autowired
+	private ConcurrentService concurrentService;
+	@Resource
+	private MarkService markService;
+	@Resource
+	private LockService lockService;
+	@Resource
+	private TaskService taskService;
+	@Resource
+	private MarkUserGroupService markUserGroupService;
+
+	@Override
+	public List<String> listClassByExamIdAndCourseCode(Long examId, String paperNumber) {
+		QueryWrapper<MarkStudent> queryWrapper = new QueryWrapper<>();
+		queryWrapper.lambda().eq(MarkStudent::getExamId, examId).eq(MarkStudent::getPaperNumber, paperNumber);
+		List<MarkStudent> markStudentList = this.list(queryWrapper);
+
+		List<String> classNameList = new ArrayList<>();
+		if (CollectionUtils.isNotEmpty(markStudentList)) {
+			classNameList = markStudentList.stream().filter(m -> StringUtils.isNotBlank(m.getClassName()))
+					.map(MarkStudent::getClassName).distinct().collect(Collectors.toList());
+		}
+		return classNameList;
+	}
+
+	@Override
+	public void updateSubjectiveStatusAndScore(Long studentId, SubjectiveStatus status, Double score,
+			String scoreList) {
+		UpdateWrapper<MarkStudent> updateWrapper = new UpdateWrapper<>();
+		updateWrapper.lambda().set(MarkStudent::getSubjectiveStatus, status).set(MarkStudent::getSubjectiveScore, score)
+				.set(MarkStudent::getSubjectiveScoreList, scoreList).eq(MarkStudent::getId, studentId);
+		this.update(updateWrapper);
+	}
+
+	@Override
+	public void updateSubjectiveStatusAndScore(Long examId, String paperNumber, SubjectiveStatus status, double score,
+			String scoreList) {
+		UpdateWrapper<MarkStudent> updateWrapper = new UpdateWrapper<>();
+		updateWrapper.lambda().set(MarkStudent::getSubjectiveStatus, status).set(MarkStudent::getSubjectiveScore, score)
+				.set(MarkStudent::getSubjectiveScoreList, scoreList).eq(MarkStudent::getExamId, examId)
+				.eq(MarkStudent::getPaperNumber, paperNumber);
+		this.update(updateWrapper);
+	}
+
+	@Override
+	public ScanExamInfoVo getScanExamInfo(BasicExam exam) {
+		ScanExamInfoVo vo = new ScanExamInfoVo();
+		vo.setId(exam.getId());
+		vo.setName(exam.getName());
+		vo.getAnswerScan().setCourseCount(markPaperService.getCountByExam(exam.getId()));
+		vo.getAnswerScan().setTotalCount(getCount(exam.getId(), null));
+		vo.getAnswerScan().setScannedCount(getCount(exam.getId(), ScanStatus.SCANNED));
+		vo.getPackageScan().setScannedCount(scanPackageService.getCount(exam.getId()));
+		return vo;
+	}
+
+	@Override
+	public IPage<StudentScoreDetailDto> pageStudentScore(Long examId, String paperNumber, String college,
+			String className, String teacher, Integer filter, Boolean absent, Boolean breach, Double startScore,
+			Double endScore, Double subScore, Integer objectiveScoreRateLt, String studentName, String studentCode,
+			Integer pageNumber, Integer pageSize) {
+		if (startScore != null && endScore == null) {
+			throw ExceptionResultEnum.ERROR.exception("请输入结束分数值");
+		}
+		Page<StudentScoreDetailDto> page = new Page<>(pageNumber, pageSize);
+		MarkPaper markPaper = markPaperService.getByExamIdAndPaperNumber(examId, paperNumber);
+		Double objectiveScoreLt = objectiveScoreRateLt == null ? null
+				: Double.parseDouble(new DecimalFormat("####.###")
+						.format(markPaper.getObjectiveScore() * objectiveScoreRateLt / 100));
+		IPage<StudentScoreDetailDto> studentScoreDetailDtoIPage = this.baseMapper.pageStudentScore(page, examId,
+				paperNumber, college, className, teacher, filter, absent, breach, startScore, endScore, subScore,
+				objectiveScoreLt, studentName, studentCode);
+		for (StudentScoreDetailDto scoreDetailDto : studentScoreDetailDtoIPage.getRecords()) {
+			// 原图
+			scoreDetailDto.setSheetUrls(buildSheetUrls(scoreDetailDto.getStudentId()));
+
+		}
+		return studentScoreDetailDtoIPage;
+	}
+
+	@Override
+	public List<SheetUrlDto> buildSheetUrls(Long studentId) {
+		// 原图
+		List<SheetUrlDto> sheetUrls = new ArrayList<>();
+		List<StudentPaperDetailDto> studentPaperDetailDtoList = scanPaperService.listStudentPaperDetail(studentId);
+		for (int i = 0; i < studentPaperDetailDtoList.size(); i++) {
+			StudentPaperDetailDto studentPaperDetailDto = studentPaperDetailDtoList.get(i);
+			sheetUrls.add(new SheetUrlDto(
+					2 * (studentPaperDetailDto.getPaperIndex() - 1) + studentPaperDetailDto.getPageIndex(),
+					teachcloudCommonService.filePreview(studentPaperDetailDto.getSheetPath())));
+		}
+		return sheetUrls;
+	}
+
+	private int getCount(Long examId, ScanStatus status) {
+		QueryWrapper<MarkStudent> wrapper = new QueryWrapper<>();
+		LambdaQueryWrapper<MarkStudent> lw = wrapper.lambda();
+		lw.eq(MarkStudent::getExamId, examId);
+		if (status != null) {
+			lw.eq(MarkStudent::getScanStatus, status);
+		}
+		return baseMapper.selectCount(wrapper);
+	}
+
+	private int getOmrAbsentCount(Long examId, Boolean checked) {
+		QueryWrapper<MarkStudent> wrapper = new QueryWrapper<>();
+		LambdaQueryWrapper<MarkStudent> lw = wrapper.lambda();
+		lw.eq(MarkStudent::getExamId, examId);
+		lw.eq(MarkStudent::getOmrAbsent, true);
+		if (checked != null) {
+			lw.eq(MarkStudent::getOmrAbsentChecked, checked);
+		}
+		return baseMapper.selectCount(wrapper);
+	}
+
+	private int getIncompleteCount(Long examId) {
+		QueryWrapper<MarkStudent> wrapper = new QueryWrapper<>();
+		LambdaQueryWrapper<MarkStudent> lw = wrapper.lambda();
+		lw.eq(MarkStudent::getExamId, examId);
+		lw.eq(MarkStudent::getIncomplete, true);
+		return baseMapper.selectCount(wrapper);
+	}
+
+	@Override
+	public ScanExamCheckInfoVo checkInfo(BasicExam exam) {
+		Long examId = exam.getId();
+		ScanExamCheckInfoVo vo = new ScanExamCheckInfoVo();
+		vo.setId(exam.getId());
+		vo.setName(exam.getName());
+		CheckTask ct = vo.getCheckTask();
+		ct.setUnexistCount(getCount(examId, ScanStatus.UNEXIST));
+		ct.setUnexistCheckedCount(getCount(examId, ScanStatus.MANUAL_ABSENT));
+		ct.setAssignedCount(scanPaperService.getAssignedCount(examId, false));
+		ct.setAssignedCheckedCount(scanPaperService.getAssignedCount(examId, true));
+		ct.setAbsentCheckCount(getOmrAbsentCount(examId, false));
+		ct.setAbsentCheckedCount(getOmrAbsentCount(examId, true));
+		ct.setObjectiveCheckCount(scanOmrTaskService.getCount(examId, OmrTaskStatus.WAITING));
+		ct.setObjectiveCheckedCount(scanOmrTaskService.getCount(examId, OmrTaskStatus.PROCESSED));
+		ct.setIncompleteCount(getIncompleteCount(examId));
+		return vo;
+	}
+
+	/**
+	 * 根据考生当前绑定的paper刷新考生状态,需要在外部调用处对考生上锁
+	 */
+	@Override
+	@Transactional
+	public void updateStudentByPaper(@NotNull Long userId, @NotNull Long studentId, @NotNull boolean updateOmrTask) {
+		MarkStudent student = this.getById(studentId);
+		if (student == null) {
+			throw new ParameterException("找不到对应的考生");
+		}
+		// 重置状态
+		student.setIncomplete(false);
+		student.setAssigned(false);
+		student.setQuestionFilled(false);
+		student.setOmrAbsent(false);
+		int paperCount = 0;
+		List<ScanStudentPaper> studentPaperList = studentPaperService.findByStudentId(studentId);
+		for (ScanStudentPaper studentPaper : studentPaperList) {
+			paperCount++;
+			// 获取paper详情更新考生状态
+			ScanPaper paper = scanPaperService.getById(studentPaper.getPaperId());
+			student.setAssigned(student.getAssigned() || paper.getAssigned());
+			student.setQuestionFilled(student.getQuestionFilled() || paper.getQuestionFilled());
+			student.setCardNumber(paper.getCardNumber());
+			// 单独判断首张纸正面的识别结果
+			if (studentPaper.getPaperIndex() == 1) {
+				// 根据识别结果更新考生属性
+				ScanPaperPage page = scanPaperPageService.findPaperIdAndIndex(paper.getId(), 1);
+				student.setOmrAbsent(page.getAbsent() == null ? false : page.getAbsent().getResult());
 //                student.setDevice(batchService.findByPaperId(paper.getId()).getDevice());
-            }
-        }
-        // 更新考生状态
-        if (paperCount > 0) {
-            ScanAnswerCard answerCard = answerCardService.findByExamAndNumber(student.getExamId(),
-                    student.getCardNumber());
-            student.setIncomplete(paperCount != answerCard.getPaperCount());
-            student.setScanStatus(ScanStatus.SCANNED);
-        } else {
-            student.setScanStatus(ScanStatus.UNEXIST);
-        }
+			}
+		}
+		// 更新考生状态
+		if (paperCount > 0) {
+			ScanAnswerCard answerCard = answerCardService.findByExamAndNumber(student.getExamId(),
+					student.getCardNumber());
+			student.setIncomplete(paperCount != answerCard.getPaperCount());
+			student.setScanStatus(ScanStatus.SCANNED);
+		} else {
+			student.setScanStatus(ScanStatus.UNEXIST);
+		}
 //        student.setUpdaterId(userId);
 //        student.setUpdateTime(System.currentTimeMillis());
-        this.saveOrUpdate(student);
-        if (updateOmrTask) {
-            // 清除识别对照任务
-            scanOmrTaskService.deleteByStudentId(student.getExamId(), student.getId());
-            // 重新生成识别对照任务
-            scanOmrTaskService.buildTask(ConditionType.FILL_SUSPECT, student.getId());
-        }
-    }
-
-    @Override
-    public MarkStudent findByExamIdAndCoursePaperIdAndStudentCode(Long examId, String coursePaperId,
-                                                                  String studentCode) {
-        QueryWrapper<MarkStudent> wrapper = new QueryWrapper<>();
-        LambdaQueryWrapper<MarkStudent> lw = wrapper.lambda();
-        lw.eq(MarkStudent::getExamId, examId);
-        lw.eq(MarkStudent::getCoursePaperId, coursePaperId);
-        lw.eq(MarkStudent::getStudentCode, studentCode);
-        return baseMapper.selectOne(wrapper);
-    }
-
-    @Override
-    public StudentObjectiveDetailDto getObjectiveInspectedTask(Long studentId) {
-        MarkStudent markStudent = this.getById(studentId);
-        StudentObjectiveDetailDto studentObjectiveDetailDto = new StudentObjectiveDetailDto();
-        if (markStudent != null) {
-            studentObjectiveDetailDto.setStudentId(markStudent.getId());
-            studentObjectiveDetailDto.setStudentName(markStudent.getStudentName());
-            studentObjectiveDetailDto.setStudentCode(markStudent.getStudentCode());
-            studentObjectiveDetailDto.setExamPlace(markStudent.getExamPlace());
-            studentObjectiveDetailDto.setExamRoom(markStudent.getExamRoom());
-            studentObjectiveDetailDto.setExamId(markStudent.getExamId());
-            studentObjectiveDetailDto.setCourseCode(markStudent.getCourseCode());
-            studentObjectiveDetailDto.setCourseName(markStudent.getCourseName());
-            studentObjectiveDetailDto.setPaperNumber(markStudent.getPaperNumber());
-            studentObjectiveDetailDto.setObjectiveScore(markStudent.getObjectiveScore() != null ? markStudent.getObjectiveScore() : 0);
-            studentObjectiveDetailDto.setSubjectiveScore(markStudent.getSubjectiveScore() != null ? markStudent.getSubjectiveScore() : 0);
-            studentObjectiveDetailDto.setUpload(markStudent.getUpload());
-            studentObjectiveDetailDto.setAbsent(markStudent.getAbsent());
-            studentObjectiveDetailDto.setSheetUrls(this.buildSheetUrls(studentId));
-
-            List<MarkQuestion> questions = markQuestionService.listQuestionByExamIdAndPaperNumberAndGroupNumber(markStudent.getExamId(), markStudent.getPaperNumber(), null, true);
-            List<String> answers = markStudent.getAnswerList();
-            int questionCount = questions.size();
-            int answerCount = answers.size();
-
-            List<StudentObjectiveAnswerDto> answerDtoList = new ArrayList<>();
-            Map<Integer, String> titles = new HashMap<>();
-            // 已设置客观题
-            int maxCount = Math.max(questionCount, answerCount);
-            for (int i = 0; i < maxCount; i++) {
-                MarkQuestion q = questionCount > i ? questions.get(i) : null;
-                String answer = answerCount > i ? answers.get(i) : "#";
-                StudentObjectiveAnswerDto studentObjectiveAnswerDto = new StudentObjectiveAnswerDto();
-                studentObjectiveAnswerDto.setMainNumber(q != null ? q.getMainNumber() : 0);
-                studentObjectiveAnswerDto.setSubNumber(q != null ? q.getSubNumber() : 0);
-                studentObjectiveAnswerDto.setAnswer(answer);
-                studentObjectiveAnswerDto.setExist(q != null && q.getTotalScore() > 0);
-                studentObjectiveAnswerDto.setQuestionType(q.getQuestionType());
-                answerDtoList.add(studentObjectiveAnswerDto);
-
-                if (q != null) {
-                    titles.put(q.getMainNumber(), q.getMainTitle());
-                }
-            }
-            studentObjectiveDetailDto.setAnswers(answerDtoList);
-            studentObjectiveDetailDto.setTitles(titles);
-        }
-
-        return studentObjectiveDetailDto;
-    }
-
-    @Override
-    public Boolean saveObjectiveInspectedTask(Long studentId, String answers) {
-        MarkStudent student = this.getById(studentId);
-        answers = StringUtils.trimToEmpty(answers);
-        if (student != null) {
-            student.setAnswers(answers.toUpperCase());
-            this.updateById(student);
-            return saveUploadStudent(student);
-        } else {
-            return false;
-        }
-    }
-
-    @Override
-    public int countUploadedByExamIdAndPaperNumber(Long examId, String paperNumber) {
-        QueryWrapper<MarkStudent> queryWrapper = new QueryWrapper<>();
-        queryWrapper.lambda().eq(MarkStudent::getExamId, examId)
-                .eq(MarkStudent::getPaperNumber, paperNumber)
-                .eq(MarkStudent::getUpload, true)
-                .eq(MarkStudent::getAbsent, false)
-                .eq(MarkStudent::getBreach, false);
-        return this.count(queryWrapper);
-    }
-
-    @Override
-    public boolean updateScanInfo(MarkStudent student) {
-        UpdateWrapper<MarkStudent> updateWrapper = new UpdateWrapper<>();
-        updateWrapper.lambda().set(MarkStudent::getSheetCount, student.getSheetCount())
-                .set(MarkStudent::getAnswers, student.getAnswers())
-                .set(MarkStudent::getBatchCode, student.getBatchCode())
-                .set(MarkStudent::getAbsent, student.getAbsent())
-                .set(MarkStudent::getUpload, true)
-                .set(MarkStudent::getUploadTime, System.currentTimeMillis())
-                .set(MarkStudent::getObjectiveScore, student.getObjectiveScore())
-                .set(MarkStudent::getObjectiveScoreList, student.getObjectiveScoreList())
-                .set(MarkStudent::getCardNumber, student.getCardNumber())
-                .eq(MarkStudent::getId, student.getId());
-        return this.update(updateWrapper);
-
-    }
-
-    @Override
-    public List<MarkStudent> listAbsentOrBreachMarkTaskStudent(Long examId, String paperNumber) {
-        return this.baseMapper.listAbsentOrBreachMarkTaskStudent(examId, paperNumber);
-    }
-
-    @Override
-    public List<MarkStudent> listUnMarkTaskStudent(Long examId, String paperNumber, Integer groupNumber, int pageSize) {
-        Page<MarkStudent> page = new Page<>(1, pageSize);
-        IPage<MarkStudent> markStudentIPage = this.baseMapper.listUnMarkTaskStudent(page, examId, paperNumber, groupNumber);
-        return markStudentIPage.getRecords();
-    }
-
-    /**
-     * 客观题统分
-     * 统分场景:
-     * 1.后台-成绩检查-客观题检查
-     * 2.扫描端-考生图片上传
-     * 3.扫描端-客观题二次识别
-     *
-     * @param student
-     * @return
-     */
-    @Override
-    public boolean saveUploadStudent(MarkStudent student) {
-        MarkStudent old = this.getById(student.getId());
-        if (!student.getAbsent()) {// 正考
-            MarkPaper markPaper = markPaperService.getByExamIdAndPaperNumber(student.getExamId(), student.getPaperNumber());
-            if (markPaper.getStatus().equals(MarkPaperStatus.FINISH)) {
-                markPaperService.updateStatus(markPaper.getExamId(), markPaper.getPaperNumber(), MarkPaperStatus.FORMAL, MarkPaperStatus.FINISH);
-            }
-        }
-        calculateObjectiveScore(student);
-        if (student.getAbsent()) {// 转缺考
-            student.setObjectiveScore(0d);
-            student.setObjectiveScoreList(null);
-        }
-        if (!old.getAbsent() && student.getAbsent()) {// 正考转缺考
-            student.setSubjectiveScore(0d);
-            student.setSubjectiveScoreList(null);
-            this.updateById(student);
-            this.updateSubjectiveStatusAndScore(student.getId(), SubjectiveStatus.UNMARK, 0D, null);
-        }
-        boolean success = this.updateScanInfo(student);
-        if (success) {
-            markPaperService.updateUploadCount(
-                    student.getExamId(),
-                    student.getPaperNumber(),
-                    this.countUploadedByExamIdAndPaperNumber(student.getExamId(), student.getPaperNumber()));
-        }
-        return success;
-    }
-
-    private void calculateObjectiveScore(MarkStudent student) {
-        ScoreCalculateUtil util = ScoreCalculateUtil.instance(student);
-
-        ScoreInfo info = util.calculate(
-                markQuestionService.listQuestionByExamIdAndPaperNumberAndGroupNumber(student.getExamId(),
-                        student.getPaperNumber(), null, true), null);
-        student.setObjectiveScore(info.getObjectiveScore());
-        student.setScoreList(info.getScoreList(), true);
-    }
-
-    @Override
-    @Transactional
-    public void updateStudentAndPaper(@NotNull SysUser user, @NotNull Long id,
-                                      @NotNull List<ScanStudentPaper> studentPaperList) {
-        for (ScanStudentPaper studentPaper : studentPaperList) {
-            studentPaper.setStudentId(id);
-        }
-        // 清空原有绑定关系
-        studentPaperService.removeByStudentId(id);
-        // 保存绑定关系
-        studentPaperService.saveOrUpdateBatch(studentPaperList);
-        // 更新考生状态
-        updateStudentByPaper(user.getId(), id, true);
-    }
-
-    @Override
-    public StudentVo findOne(StudentQuery query) {
-        return baseMapper.findOne(query);
-    }
-
-    @Override
-    public int countByExamIdAndSecretNumber(Long examId, String secretNumber) {
-        QueryWrapper<MarkStudent> queryWrapper = new QueryWrapper<>();
-        queryWrapper.lambda().eq(MarkStudent::getExamId, examId)
-                .eq(MarkStudent::getSecretNumber, secretNumber);
-        return this.count(queryWrapper);
-    }
-
-    @Override
-    public List<MarkStudent> listByExamIdAndCoursePaperId(Long examId, String coursePaperId) {
-        QueryWrapper<MarkStudent> queryWrapper = new QueryWrapper<>();
-        queryWrapper.lambda().eq(MarkStudent::getExamId, examId)
-                .eq(MarkStudent::getCoursePaperId, coursePaperId);
-        return this.list(queryWrapper);
-    }
-
-    @Override
-    public IPage<AnswerQueryVo> query(AnswerQueryDomain query) {
-        // 查询考生分页信息
-        IPage<AnswerQueryVo> iPage = baseMapper.queryPage(new Page<>(query.getPageNumber(), query.getPageSize()),
-                query);
-        if (CollectionUtils.isNotEmpty(iPage.getRecords())) {
-            for (AnswerQueryVo vo : iPage.getRecords()) {
-                if (vo.getIsAbsent() != null && vo.getIsAbsent()) {
-                    vo.setExamStatus(ExamStatus.ABSENT);
-                } else {
-                    vo.setExamStatus(ExamStatus.OK);
-                }
-            }
-        }
-        if (CollectionUtils.isNotEmpty(iPage.getRecords()) && (query.getWithPaper() != null && query.getWithPaper())) {
-            Map<Long, AnswerQueryVo> map = new HashMap<>();
-
-            for (AnswerQueryVo vo : iPage.getRecords()) {
-                List<AnswerPaperVo> papers = new ArrayList<>();
-                vo.setPapers(papers);
-                if (vo.getCardPaperCount() != null) {
-                    for (int i = 1; i <= vo.getCardPaperCount(); i++) {
-                        AnswerPaperVo pv = new AnswerPaperVo();
-                        pv.setNumber(i);
-                        papers.add(pv);
-                    }
-                }
-                map.put(vo.getId(), vo);
-            }
-            // 根据考生id查找绑定paper
-            List<Long> studentIds = iPage.getRecords().stream().map(p -> p.getId()).collect(Collectors.toList());
-            List<StudentPaperVo> paperList = new BatchGetDataUtil<StudentPaperVo, Long>() {
-
-                @Override
-                public List<StudentPaperVo> getData(List<Long> paramList) {
-                    return scanPaperService.listByStudentIds(paramList);
-                }
-            }.getDataForBatch(studentIds, 200);
-
-            if (CollectionUtils.isNotEmpty(paperList)) {
-                Map<Long, AnswerPaperVo> paperMap = new HashMap<>();
-                for (StudentPaperVo p : paperList) {
-                    AnswerQueryVo vo = map.get(p.getStudentId());
-                    if (vo == null) {
-                        continue;
-                    }
-                    List<AnswerPaperVo> papers = vo.getPapers();
-                    if (papers == null) {
-                        continue;
-                    }
-                    if (papers.size() < p.getNumber()) {
-                        continue;
-                    }
-                    AnswerPaperVo pvo = papers.get(p.getNumber() - 1);
-                    pvo.setId(p.getPaperId());
-                    pvo.setNumber(p.getNumber());
-                    pvo.setAssigned(p.getAssigned());
-                    paperMap.put(p.getPaperId(), pvo);
-                }
-                // 查找page
-                List<Long> paperIds = paperList.stream().map(p -> p.getPaperId()).collect(Collectors.toList());
-                List<ScanPaperPage> paperPageList = new BatchGetDataUtil<ScanPaperPage, Long>() {
-
-                    @Override
-                    public List<ScanPaperPage> getData(List<Long> paramList) {
-                        return scanPaperPageService.listByPaperList(paramList);
-                    }
-                }.getDataForBatch(paperIds, 200);
-
-                if (CollectionUtils.isNotEmpty(paperPageList)) {
-                    for (ScanPaperPage p : paperPageList) {
-                        AnswerPaperVo pvo = paperMap.get(p.getPaperId());
-                        if (pvo == null) {
-                            continue;
-                        }
-                        List<AnswerPageVo> pages = pvo.getPages();
-                        if (pages == null) {
-                            pages = new ArrayList<>();
-                            pvo.setPages(pages);
-                        }
-                        AnswerPageVo pageVo = new AnswerPageVo();
-                        pageVo.setIndex(p.getPageIndex());
-                        pageVo.setSheetUri(p.getSheetPath());
-                        if (query.getWithOmrDetail() != null && query.getWithOmrDetail()) {
-                            pageVo.setAbsent(p.getAbsent());
-                            pageVo.setBreach(p.getBreach());
-                            pageVo.setQuestion(p.getQuestion());
-                            pageVo.setRecogData(p.getRecogData());
-                        }
-                        pages.add(pageVo);
-                    }
-                }
-            }
-        }
-        return iPage;
-    }
-
-    @Override
-    public List<String> summary(AnswerQueryDomain query) {
-        // 不分页查询考生准考证号
-        return baseMapper.querySummary(query);
-    }
-
-    @Transactional
-    @Override
-    public UpdateTimeVo omrEdit(Long userId, OmrEditDomain domain) {
-        MarkStudent student = findByExamIdAndStudentCode(domain.getExamId(), domain.getStudentCode());
-        if (student == null) {
-            throw new ParameterException("考生信息未找到");
-        }
-        concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().lock();
-        try {
-            for (OmrEditPaper paperEdit : domain.getPapers()) {
-                ScanStudentPaper sp = studentPaperService.findByStudentIdAndPaperNumber(student.getId(),
-                        paperEdit.getNumber());
-                if (sp == null) {
-                    throw new ParameterException("未找到绑定扫描结果");
-                }
-                ScanPaper paperEntity = scanPaperService.getById(sp.getPaperId());
-                if (paperEntity == null) {
-                    throw new ParameterException("未找到paper信息结果");
-                }
-                paperEntity.setUpdaterId(userId);
-                paperEntity.setUpdateTime(System.currentTimeMillis());
-                List<ScanPaperPage> pages = scanPaperPageService.listByPaperId(paperEntity.getId());
-                for (ScanPaperPage pageEntity : pages) {
-                    paperEdit.updatePage(pageEntity);
-                }
-                scanPaperService.savePaperAndPages(paperEntity, pages);
-            }
-            updateStudentByPaper(userId, student.getId(), false);
-            return UpdateTimeVo.create();
-        } finally {
-            concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().unlock();
-        }
-    }
-
-    @Override
-    public MarkStudent findByExamIdAndStudentCode(Long examId, String studentCode) {
-        if (examId == null) {
-            throw new ParameterException("examId 不能为空");
-        }
-        if (StringUtils.isBlank(studentCode)) {
-            throw new ParameterException("studentCode不能为空");
-        }
-        QueryWrapper<MarkStudent> queryWrapper = new QueryWrapper<>();
-        queryWrapper.lambda().eq(MarkStudent::getExamId, examId);
-        queryWrapper.lambda().eq(MarkStudent::getStudentCode, studentCode);
-        return baseMapper.selectOne(queryWrapper);
-    }
-
-    @Override
-    public long countStudentCountByExamIdAndPaperNumber(Long examId, String paperNumber, String paperType) {
-        QueryWrapper<MarkStudent> queryWrapper = new QueryWrapper<>();
-        queryWrapper.lambda().eq(MarkStudent::getExamId, examId)
-                .eq(MarkStudent::getPaperNumber, paperNumber)
-                .eq(MarkStudent::getPaperType, paperType);
-        return this.count(queryWrapper);
-    }
-
-    @Transactional
-    @Override
-    public AbsentManualUpdateVo absentManualUpdate(Long examId, String coursePaperId, String studentCode) {
-        MarkStudent student = findByExamIdAndCoursePaperIdAndStudentCode(examId, coursePaperId, studentCode);
-        if (student == null) {
-            throw new ParameterException("考生未找到");
-        }
-        if (student.getScanStatus() != ScanStatus.UNEXIST) {
-            throw new ParameterException("考生不是未扫描状态");
-        }
-        LambdaUpdateWrapper<MarkStudent> lw = new LambdaUpdateWrapper<>();
-        lw.set(MarkStudent::getScanStatus, ScanStatus.MANUAL_ABSENT);
-        lw.eq(MarkStudent::getId, student.getId());
-        lw.eq(MarkStudent::getScanStatus, ScanStatus.UNEXIST);
-        update(lw);
-        return AbsentManualUpdateVo.create(ScanStatus.MANUAL_ABSENT);
-    }
-
-    @Transactional
-    @Override
-    public UpdateTimeVo confirm(Long examId, String coursePaperId, String studentCode, Boolean omrAbsent) {
-        LambdaUpdateWrapper<MarkStudent> lw = new LambdaUpdateWrapper<>();
-        lw.set(MarkStudent::getOmrAbsentChecked, true);
-        lw.eq(MarkStudent::getExamId, examId);
-        lw.eq(MarkStudent::getCoursePaperId, coursePaperId);
-        lw.eq(MarkStudent::getStudentCode, studentCode);
-        if (omrAbsent != null) {
-            lw.eq(MarkStudent::getOmrAbsent, omrAbsent);
-        }
-        if (!update(lw)) {
-            throw new ParameterException("考生未找到");
-        }
-        return UpdateTimeVo.create();
-    }
-
-    @Override
-    public List<Long> findIdByExamIdAndPaperNumberAndSubjectiveStatus(Long examId, String paperNumber, SubjectiveStatus unmark, SubjectiveStatus marked) {
-        return this.baseMapper.findIdByExamIdAndPaperNumberAndSubjectiveStatus(examId, paperNumber, unmark.name(), marked.name());
-    }
-
-    @Override
-    public Task getSubjectiveInspectedTask(Long studentId) {
-        Task task = null;
-        if (studentId != null) {
-            SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
-            MarkStudent markStudent = this.getById(studentId);
-            releaseStudent(markStudent);
-            if (markService.applyStudent(markStudent, sysUser.getId())) {
-                task = taskService.build(studentId);
-            }
-        }
-        return task;
-    }
-
-    @Override
-    public void saveSubjectiveInspectedTask(MarkHeaderResult markResult) {
-        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
-        for (MarkHeaderGroupResult groupResult : markResult.getGroups()) {
-            MarkUserGroup markUserGroup = markUserGroupService.getByExamIdAndPaperNumberAndGroupNumberAndUserId(markResult.getExamId(), markResult.getPaperNumber(), groupResult.getGroupNumber(), sysUser.getId());
-            try {
-                lockService.watch(LockType.EXAM_SUBJECT, markUserGroup.getExamId(), markUserGroup.getPaperNumber());
-                lockService.watch(LockType.GROUP, markUserGroup.getExamId(), markUserGroup.getPaperNumber(), markUserGroup.getGroupNumber());
-                lockService.watch(LockType.MARK_USER_GROUP, markUserGroup.getId());
-                lockService.waitlock(LockType.STUDENT, groupResult.getStudentId());
-                markService.submitHeaderTask(groupResult, markUserGroup);
-            } catch (Exception e) {
-                log.error("save task error", e);
-            } finally {
-                lockService.unlock(LockType.STUDENT, groupResult.getStudentId());
-                lockService.unwatch(LockType.MARK_USER_GROUP, markUserGroup.getId());
-                lockService.unwatch(LockType.GROUP, markUserGroup.getExamId(), markUserGroup.getPaperNumber(), markUserGroup.getGroupNumber());
-                lockService.unwatch(LockType.EXAM_SUBJECT, markUserGroup.getExamId(), markUserGroup.getPaperNumber());
-            }
-        }
-    }
-
-    private void releaseStudent(MarkStudent markStudent) {
-        try {
-            lockService.waitlock(LockType.STUDENT, markStudent.getId());
-            markService.releaseByStudent(markStudent);
-        } catch (Exception e) {
-            log.error("release user error", e);
-        } finally {
-            lockService.unlock(LockType.STUDENT, markStudent.getId());
-        }
-    }
+		this.saveOrUpdate(student);
+		if (updateOmrTask) {
+			// 清除识别对照任务
+			scanOmrTaskService.deleteByStudentId(student.getExamId(), student.getId());
+			// 重新生成识别对照任务
+			scanOmrTaskService.buildTask(ConditionType.FILL_SUSPECT, student.getId());
+		}
+	}
+
+	@Override
+	public MarkStudent findByExamIdAndCoursePaperIdAndStudentCode(Long examId, String coursePaperId,
+			String studentCode) {
+		QueryWrapper<MarkStudent> wrapper = new QueryWrapper<>();
+		LambdaQueryWrapper<MarkStudent> lw = wrapper.lambda();
+		lw.eq(MarkStudent::getExamId, examId);
+		lw.eq(MarkStudent::getCoursePaperId, coursePaperId);
+		lw.eq(MarkStudent::getStudentCode, studentCode);
+		return baseMapper.selectOne(wrapper);
+	}
+
+	@Override
+	public StudentObjectiveDetailDto getObjectiveInspectedTask(Long studentId) {
+		MarkStudent markStudent = this.getById(studentId);
+		StudentObjectiveDetailDto studentObjectiveDetailDto = new StudentObjectiveDetailDto();
+		if (markStudent != null) {
+			studentObjectiveDetailDto.setStudentId(markStudent.getId());
+			studentObjectiveDetailDto.setStudentName(markStudent.getStudentName());
+			studentObjectiveDetailDto.setStudentCode(markStudent.getStudentCode());
+			studentObjectiveDetailDto.setExamPlace(markStudent.getExamPlace());
+			studentObjectiveDetailDto.setExamRoom(markStudent.getExamRoom());
+			studentObjectiveDetailDto.setExamId(markStudent.getExamId());
+			studentObjectiveDetailDto.setCourseCode(markStudent.getCourseCode());
+			studentObjectiveDetailDto.setCourseName(markStudent.getCourseName());
+			studentObjectiveDetailDto.setPaperNumber(markStudent.getPaperNumber());
+			studentObjectiveDetailDto
+					.setObjectiveScore(markStudent.getObjectiveScore() != null ? markStudent.getObjectiveScore() : 0);
+			studentObjectiveDetailDto.setSubjectiveScore(
+					markStudent.getSubjectiveScore() != null ? markStudent.getSubjectiveScore() : 0);
+			studentObjectiveDetailDto.setUpload(markStudent.getUpload());
+			studentObjectiveDetailDto.setAbsent(markStudent.getAbsent());
+			studentObjectiveDetailDto.setSheetUrls(this.buildSheetUrls(studentId));
+
+			List<MarkQuestion> questions = markQuestionService.listQuestionByExamIdAndPaperNumberAndGroupNumber(
+					markStudent.getExamId(), markStudent.getPaperNumber(), null, true);
+			List<String> answers = markStudent.getAnswerList();
+			int questionCount = questions.size();
+			int answerCount = answers.size();
+
+			List<StudentObjectiveAnswerDto> answerDtoList = new ArrayList<>();
+			Map<Integer, String> titles = new HashMap<>();
+			// 已设置客观题
+			int maxCount = Math.max(questionCount, answerCount);
+			for (int i = 0; i < maxCount; i++) {
+				MarkQuestion q = questionCount > i ? questions.get(i) : null;
+				String answer = answerCount > i ? answers.get(i) : "#";
+				StudentObjectiveAnswerDto studentObjectiveAnswerDto = new StudentObjectiveAnswerDto();
+				studentObjectiveAnswerDto.setMainNumber(q != null ? q.getMainNumber() : 0);
+				studentObjectiveAnswerDto.setSubNumber(q != null ? q.getSubNumber() : 0);
+				studentObjectiveAnswerDto.setAnswer(answer);
+				studentObjectiveAnswerDto.setExist(q != null && q.getTotalScore() > 0);
+				studentObjectiveAnswerDto.setQuestionType(q.getQuestionType());
+				answerDtoList.add(studentObjectiveAnswerDto);
+
+				if (q != null) {
+					titles.put(q.getMainNumber(), q.getMainTitle());
+				}
+			}
+			studentObjectiveDetailDto.setAnswers(answerDtoList);
+			studentObjectiveDetailDto.setTitles(titles);
+		}
+
+		return studentObjectiveDetailDto;
+	}
+
+	@Override
+	public Boolean saveObjectiveInspectedTask(Long studentId, String answers) {
+		MarkStudent student = this.getById(studentId);
+		answers = StringUtils.trimToEmpty(answers);
+		if (student != null) {
+			student.setAnswers(answers.toUpperCase());
+			this.updateById(student);
+			return saveUploadStudent(student);
+		} else {
+			return false;
+		}
+	}
+
+	@Override
+	public int countUploadedByExamIdAndPaperNumber(Long examId, String paperNumber) {
+		QueryWrapper<MarkStudent> queryWrapper = new QueryWrapper<>();
+		queryWrapper.lambda().eq(MarkStudent::getExamId, examId).eq(MarkStudent::getPaperNumber, paperNumber)
+				.eq(MarkStudent::getUpload, true).eq(MarkStudent::getAbsent, false).eq(MarkStudent::getBreach, false);
+		return this.count(queryWrapper);
+	}
+
+	@Override
+	public boolean updateScanInfo(MarkStudent student) {
+		UpdateWrapper<MarkStudent> updateWrapper = new UpdateWrapper<>();
+		updateWrapper.lambda().set(MarkStudent::getSheetCount, student.getSheetCount())
+				.set(MarkStudent::getAnswers, student.getAnswers())
+				.set(MarkStudent::getBatchCode, student.getBatchCode()).set(MarkStudent::getAbsent, student.getAbsent())
+				.set(MarkStudent::getUpload, true).set(MarkStudent::getUploadTime, System.currentTimeMillis())
+				.set(MarkStudent::getObjectiveScore, student.getObjectiveScore())
+				.set(MarkStudent::getObjectiveScoreList, student.getObjectiveScoreList())
+				.set(MarkStudent::getCardNumber, student.getCardNumber()).eq(MarkStudent::getId, student.getId());
+		return this.update(updateWrapper);
+
+	}
+
+	@Override
+	public List<MarkStudent> listAbsentOrBreachMarkTaskStudent(Long examId, String paperNumber) {
+		return this.baseMapper.listAbsentOrBreachMarkTaskStudent(examId, paperNumber);
+	}
+
+	@Override
+	public List<MarkStudent> listUnMarkTaskStudent(Long examId, String paperNumber, Integer groupNumber, int pageSize) {
+		Page<MarkStudent> page = new Page<>(1, pageSize);
+		IPage<MarkStudent> markStudentIPage = this.baseMapper.listUnMarkTaskStudent(page, examId, paperNumber,
+				groupNumber);
+		return markStudentIPage.getRecords();
+	}
+
+	/**
+	 * 客观题统分 统分场景: 1.后台-成绩检查-客观题检查 2.扫描端-考生图片上传 3.扫描端-客观题二次识别
+	 *
+	 * @param student
+	 * @return
+	 */
+	@Override
+	public boolean saveUploadStudent(MarkStudent student) {
+		MarkStudent old = this.getById(student.getId());
+		if (!student.getAbsent()) {// 正考
+			MarkPaper markPaper = markPaperService.getByExamIdAndPaperNumber(student.getExamId(),
+					student.getPaperNumber());
+			if (markPaper.getStatus().equals(MarkPaperStatus.FINISH)) {
+				markPaperService.updateStatus(markPaper.getExamId(), markPaper.getPaperNumber(), MarkPaperStatus.FORMAL,
+						MarkPaperStatus.FINISH);
+			}
+		}
+		calculateObjectiveScore(student);
+		if (student.getAbsent()) {// 转缺考
+			student.setObjectiveScore(0d);
+			student.setObjectiveScoreList(null);
+		}
+		if (!old.getAbsent() && student.getAbsent()) {// 正考转缺考
+			student.setSubjectiveScore(0d);
+			student.setSubjectiveScoreList(null);
+			this.updateById(student);
+			this.updateSubjectiveStatusAndScore(student.getId(), SubjectiveStatus.UNMARK, 0D, null);
+		}
+		boolean success = this.updateScanInfo(student);
+		if (success) {
+			markPaperService.updateUploadCount(student.getExamId(), student.getPaperNumber(),
+					this.countUploadedByExamIdAndPaperNumber(student.getExamId(), student.getPaperNumber()));
+		}
+		return success;
+	}
+
+	private void calculateObjectiveScore(MarkStudent student) {
+		ScoreCalculateUtil util = ScoreCalculateUtil.instance(student);
+
+		ScoreInfo info = util.calculate(markQuestionService.listQuestionByExamIdAndPaperNumberAndGroupNumber(
+				student.getExamId(), student.getPaperNumber(), null, true), null);
+		student.setObjectiveScore(info.getObjectiveScore());
+		student.setScoreList(info.getScoreList(), true);
+	}
+
+	@Override
+	@Transactional
+	public void updateStudentAndPaper(@NotNull SysUser user, @NotNull Long id,
+			@NotNull List<ScanStudentPaper> studentPaperList) {
+		for (ScanStudentPaper studentPaper : studentPaperList) {
+			studentPaper.setStudentId(id);
+		}
+		// 清空原有绑定关系
+		studentPaperService.removeByStudentId(id);
+		// 保存绑定关系
+		studentPaperService.saveOrUpdateBatch(studentPaperList);
+		// 更新考生状态
+		updateStudentByPaper(user.getId(), id, true);
+	}
+
+	@Override
+	public StudentVo findOne(StudentQuery query) {
+		return baseMapper.findOne(query);
+	}
+
+	@Override
+	public int countByExamIdAndSecretNumber(Long examId, String secretNumber) {
+		QueryWrapper<MarkStudent> queryWrapper = new QueryWrapper<>();
+		queryWrapper.lambda().eq(MarkStudent::getExamId, examId).eq(MarkStudent::getSecretNumber, secretNumber);
+		return this.count(queryWrapper);
+	}
+
+	@Override
+	public List<MarkStudent> listByExamIdAndCoursePaperId(Long examId, String coursePaperId) {
+		QueryWrapper<MarkStudent> queryWrapper = new QueryWrapper<>();
+		queryWrapper.lambda().eq(MarkStudent::getExamId, examId).eq(MarkStudent::getCoursePaperId, coursePaperId);
+		return this.list(queryWrapper);
+	}
+
+	@Override
+	public IPage<AnswerQueryVo> query(AnswerQueryDomain query) {
+		// 查询考生分页信息
+		IPage<AnswerQueryVo> iPage = baseMapper.queryPage(new Page<>(query.getPageNumber(), query.getPageSize()),
+				query);
+		if (CollectionUtils.isNotEmpty(iPage.getRecords())) {
+			for (AnswerQueryVo vo : iPage.getRecords()) {
+				if (vo.getIsAbsent() != null && vo.getIsAbsent()) {
+					vo.setExamStatus(ExamStatus.ABSENT);
+				} else {
+					vo.setExamStatus(ExamStatus.OK);
+				}
+			}
+		}
+		if (CollectionUtils.isNotEmpty(iPage.getRecords()) && (query.getWithPaper() != null && query.getWithPaper())) {
+			Map<Long, AnswerQueryVo> map = new HashMap<>();
+
+			for (AnswerQueryVo vo : iPage.getRecords()) {
+				List<AnswerPaperVo> papers = new ArrayList<>();
+				vo.setPapers(papers);
+				if (vo.getCardPaperCount() != null) {
+					for (int i = 1; i <= vo.getCardPaperCount(); i++) {
+						AnswerPaperVo pv = new AnswerPaperVo();
+						pv.setNumber(i);
+						papers.add(pv);
+					}
+				}
+				map.put(vo.getId(), vo);
+			}
+			// 根据考生id查找绑定paper
+			List<Long> studentIds = iPage.getRecords().stream().map(p -> p.getId()).collect(Collectors.toList());
+			List<StudentPaperVo> paperList = new BatchGetDataUtil<StudentPaperVo, Long>() {
+
+				@Override
+				public List<StudentPaperVo> getData(List<Long> paramList) {
+					return scanPaperService.listByStudentIds(paramList);
+				}
+			}.getDataForBatch(studentIds, 200);
+
+			if (CollectionUtils.isNotEmpty(paperList)) {
+				Map<Long, AnswerPaperVo> paperMap = new HashMap<>();
+				for (StudentPaperVo p : paperList) {
+					AnswerQueryVo vo = map.get(p.getStudentId());
+					if (vo == null) {
+						continue;
+					}
+					List<AnswerPaperVo> papers = vo.getPapers();
+					if (papers == null) {
+						continue;
+					}
+					if (papers.size() < p.getNumber()) {
+						continue;
+					}
+					AnswerPaperVo pvo = papers.get(p.getNumber() - 1);
+					pvo.setId(p.getPaperId());
+					pvo.setNumber(p.getNumber());
+					pvo.setAssigned(p.getAssigned());
+					paperMap.put(p.getPaperId(), pvo);
+				}
+				// 查找page
+				List<Long> paperIds = paperList.stream().map(p -> p.getPaperId()).collect(Collectors.toList());
+				List<ScanPaperPage> paperPageList = new BatchGetDataUtil<ScanPaperPage, Long>() {
+
+					@Override
+					public List<ScanPaperPage> getData(List<Long> paramList) {
+						return scanPaperPageService.listByPaperList(paramList);
+					}
+				}.getDataForBatch(paperIds, 200);
+
+				if (CollectionUtils.isNotEmpty(paperPageList)) {
+					for (ScanPaperPage p : paperPageList) {
+						AnswerPaperVo pvo = paperMap.get(p.getPaperId());
+						if (pvo == null) {
+							continue;
+						}
+						List<AnswerPageVo> pages = pvo.getPages();
+						if (pages == null) {
+							pages = new ArrayList<>();
+							pvo.setPages(pages);
+						}
+						AnswerPageVo pageVo = new AnswerPageVo();
+						pageVo.setIndex(p.getPageIndex());
+						pageVo.setSheetUri(p.getSheetPath());
+						if (query.getWithOmrDetail() != null && query.getWithOmrDetail()) {
+							pageVo.setAbsent(p.getAbsent());
+							pageVo.setBreach(p.getBreach());
+							pageVo.setQuestion(p.getQuestion());
+							pageVo.setRecogData(p.getRecogData());
+						}
+						pages.add(pageVo);
+					}
+				}
+			}
+		}
+		return iPage;
+	}
+
+	@Override
+	public List<String> summary(AnswerQueryDomain query) {
+		// 不分页查询考生准考证号
+		return baseMapper.querySummary(query);
+	}
+
+	@Transactional
+	@Override
+	public UpdateTimeVo omrEdit(Long userId, OmrEditDomain domain) {
+		MarkStudent student = findByExamIdAndStudentCode(domain.getExamId(), domain.getStudentCode());
+		if (student == null) {
+			throw new ParameterException("考生信息未找到");
+		}
+		concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().lock();
+		try {
+			for (OmrEditPaper paperEdit : domain.getPapers()) {
+				ScanStudentPaper sp = studentPaperService.findByStudentIdAndPaperNumber(student.getId(),
+						paperEdit.getNumber());
+				if (sp == null) {
+					throw new ParameterException("未找到绑定扫描结果");
+				}
+				ScanPaper paperEntity = scanPaperService.getById(sp.getPaperId());
+				if (paperEntity == null) {
+					throw new ParameterException("未找到paper信息结果");
+				}
+				paperEntity.setUpdaterId(userId);
+				paperEntity.setUpdateTime(System.currentTimeMillis());
+				List<ScanPaperPage> pages = scanPaperPageService.listByPaperId(paperEntity.getId());
+				for (ScanPaperPage pageEntity : pages) {
+					paperEdit.updatePage(pageEntity);
+				}
+				scanPaperService.savePaperAndPages(paperEntity, pages);
+			}
+			updateStudentByPaper(userId, student.getId(), false);
+			return UpdateTimeVo.create();
+		} finally {
+			concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().unlock();
+		}
+	}
+
+	@Override
+	public MarkStudent findByExamIdAndStudentCode(Long examId, String studentCode) {
+		if (examId == null) {
+			throw new ParameterException("examId 不能为空");
+		}
+		if (StringUtils.isBlank(studentCode)) {
+			throw new ParameterException("studentCode不能为空");
+		}
+		QueryWrapper<MarkStudent> queryWrapper = new QueryWrapper<>();
+		queryWrapper.lambda().eq(MarkStudent::getExamId, examId);
+		queryWrapper.lambda().eq(MarkStudent::getStudentCode, studentCode);
+		return baseMapper.selectOne(queryWrapper);
+	}
+
+	@Override
+	public long countStudentCountByExamIdAndPaperNumber(Long examId, String paperNumber, String paperType) {
+		QueryWrapper<MarkStudent> queryWrapper = new QueryWrapper<>();
+		queryWrapper.lambda().eq(MarkStudent::getExamId, examId).eq(MarkStudent::getPaperNumber, paperNumber)
+				.eq(MarkStudent::getPaperType, paperType);
+		return this.count(queryWrapper);
+	}
+
+	@Transactional
+	@Override
+	public AbsentManualUpdateVo absentManualUpdate(Long examId, String coursePaperId, String studentCode) {
+		MarkStudent student = findByExamIdAndCoursePaperIdAndStudentCode(examId, coursePaperId, studentCode);
+		if (student == null) {
+			throw new ParameterException("考生未找到");
+		}
+		if (student.getScanStatus() != ScanStatus.UNEXIST) {
+			throw new ParameterException("考生不是未扫描状态");
+		}
+		LambdaUpdateWrapper<MarkStudent> lw = new LambdaUpdateWrapper<>();
+		lw.set(MarkStudent::getScanStatus, ScanStatus.MANUAL_ABSENT);
+		lw.eq(MarkStudent::getId, student.getId());
+		lw.eq(MarkStudent::getScanStatus, ScanStatus.UNEXIST);
+		update(lw);
+		return AbsentManualUpdateVo.create(ScanStatus.MANUAL_ABSENT);
+	}
+
+	@Transactional
+	@Override
+	public UpdateTimeVo confirm(Long examId, String coursePaperId, String studentCode, Boolean omrAbsent) {
+		LambdaUpdateWrapper<MarkStudent> lw = new LambdaUpdateWrapper<>();
+		lw.set(MarkStudent::getOmrAbsentChecked, true);
+		lw.eq(MarkStudent::getExamId, examId);
+		lw.eq(MarkStudent::getCoursePaperId, coursePaperId);
+		lw.eq(MarkStudent::getStudentCode, studentCode);
+		if (omrAbsent != null) {
+			lw.eq(MarkStudent::getOmrAbsent, omrAbsent);
+		}
+		if (!update(lw)) {
+			throw new ParameterException("考生未找到");
+		}
+		return UpdateTimeVo.create();
+	}
+
+	@Override
+	public List<Long> findIdByExamIdAndPaperNumberAndSubjectiveStatus(Long examId, String paperNumber,
+			SubjectiveStatus unmark, SubjectiveStatus marked) {
+		return this.baseMapper.findIdByExamIdAndPaperNumberAndSubjectiveStatus(examId, paperNumber, unmark.name(),
+				marked.name());
+	}
+
+	@Override
+	public Task getSubjectiveInspectedTask(Long studentId) {
+		Task task = null;
+		if (studentId != null) {
+			SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+			MarkStudent markStudent = this.getById(studentId);
+			releaseStudent(markStudent);
+			if (markService.applyStudent(markStudent, sysUser.getId())) {
+				task = taskService.build(studentId);
+			}
+		}
+		return task;
+	}
+
+	@Override
+	public void saveSubjectiveInspectedTask(MarkHeaderResult markResult) {
+		SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+		for (MarkHeaderGroupResult groupResult : markResult.getGroups()) {
+			MarkUserGroup markUserGroup = markUserGroupService.getByExamIdAndPaperNumberAndGroupNumberAndUserId(
+					markResult.getExamId(), markResult.getPaperNumber(), groupResult.getGroupNumber(), sysUser.getId());
+			try {
+				lockService.watch(LockType.EXAM_SUBJECT, markUserGroup.getExamId(), markUserGroup.getPaperNumber());
+				lockService.watch(LockType.GROUP, markUserGroup.getExamId(), markUserGroup.getPaperNumber(),
+						markUserGroup.getGroupNumber());
+				lockService.watch(LockType.MARK_USER_GROUP, markUserGroup.getId());
+				lockService.waitlock(LockType.STUDENT, groupResult.getStudentId());
+				markService.submitHeaderTask(groupResult, markUserGroup);
+			} catch (Exception e) {
+				log.error("save task error", e);
+			} finally {
+				lockService.unlock(LockType.STUDENT, groupResult.getStudentId());
+				lockService.unwatch(LockType.MARK_USER_GROUP, markUserGroup.getId());
+				lockService.unwatch(LockType.GROUP, markUserGroup.getExamId(), markUserGroup.getPaperNumber(),
+						markUserGroup.getGroupNumber());
+				lockService.unwatch(LockType.EXAM_SUBJECT, markUserGroup.getExamId(), markUserGroup.getPaperNumber());
+			}
+		}
+	}
+
+	private void releaseStudent(MarkStudent markStudent) {
+		try {
+			lockService.waitlock(LockType.STUDENT, markStudent.getId());
+			markService.releaseByStudent(markStudent);
+		} catch (Exception e) {
+			log.error("release user error", e);
+		} finally {
+			lockService.unlock(LockType.STUDENT, markStudent.getId());
+		}
+	}
+
+	@Override
+	public List<ArchiveStudentVo> studentList(ArchiveStudentQuery query) {
+		List<ArchiveStudentVo> ret = baseMapper.studentList(query);
+		if (CollectionUtils.isNotEmpty(ret)) {
+			fillSheetUrls(ret);
+		}
+		return ret;
+	}
+
+	private void fillSheetUrls(List<ArchiveStudentVo> ret) {
+		List<Long> studentIds = ret.stream().map(p -> p.getId()).collect(Collectors.toList());
+		// 查找page
+		List<ScanPaperPageVo> paperPageList = new BatchGetDataUtil<ScanPaperPageVo, Long>() {
+
+			@Override
+			public List<ScanPaperPageVo> getData(List<Long> studentIds) {
+				return scanPaperPageService.listByStudentIds(studentIds);
+			}
+		}.getDataForBatch(studentIds, 200);
+
+		Map<Long, List<String>> map = new HashMap<>();
+		if (CollectionUtils.isNotEmpty(paperPageList)) {
+			for (ScanPaperPageVo p : paperPageList) {
+				List<String> tem = map.get(p.getStudentId());
+				if (tem == null) {
+					tem = new ArrayList<>();
+					map.put(p.getStudentId(), tem);
+				}
+				tem.add(p.getSheetPath());
+			}
+		}
+		for (ArchiveStudentVo vo : ret) {
+			vo.setSheetUrls(map.get(vo.getId()));
+		}
+	}
 }

+ 6 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/ScanPaperPageServiceImpl.java

@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qmth.boot.core.exception.ParameterException;
+import com.qmth.teachcloud.mark.bean.archivescore.ScanPaperPageVo;
 import com.qmth.teachcloud.mark.entity.ScanPaperPage;
 import com.qmth.teachcloud.mark.mapper.ScanPaperPageMapper;
 import com.qmth.teachcloud.mark.service.ScanPaperPageService;
@@ -59,4 +60,9 @@ public class ScanPaperPageServiceImpl extends ServiceImpl<ScanPaperPageMapper, S
 		return this.list(wrapper);
 	}
 
+	@Override
+	public List<ScanPaperPageVo> listByStudentIds(List<Long> studentIds) {
+		return baseMapper.listByStudentIds(studentIds);
+	}
+
 }

+ 21 - 1
teachcloud-mark/src/main/resources/mapper/MarkStudentMapper.xml

@@ -217,7 +217,7 @@
     </sql>
     <select id="queryPage"
             resultType="com.qmth.teachcloud.mark.bean.scananswer.AnswerQueryVo">
-        select t.*,t.paper_number coursePaperNumber,c.paper_count cardPaperCount,
+        select t.*,t.paper_number coursePaperNumber,c.paper_count cardPaperCount
         from mark_student t
         left join scan_answer_card c on t.exam_id=c.exam_id and t.card_number=c.number
         left join mark_paper s on s.course_paper_id=t.course_paper_id and s.exam_id=t.exam_id
@@ -235,4 +235,24 @@
     <select id="findIdByExamIdAndPaperNumberAndSubjectiveStatus" resultType="java.lang.Long">
         select id from mark_student where exam_id = #{examId} and paper_number = #{paperNumber} and subjective_status in (#{unmark}, #{marked})
     </select>
+    <select id="studentList"
+            resultType="com.qmth.teachcloud.mark.bean.archivescore.ArchiveStudentVo">
+        select t.*,t.objective_score+t.subjective_score totalScore
+        from mark_student t
+        where t.exam_id=#{req.examId} and t.paper_number=#{req.paperNumber}
+        <if test="query.studentCode != null and query.studentCode !=''">
+            and t.student_code=#{query.studentCode}
+        </if>
+        <if test="query.studentName != null and query.studentName !=''">
+            and t.student_name=#{query.studentName}
+        </if>
+        <if test="query.college != null and query.college !=''">
+            and t.college=#{query.college}
+        </if>
+        <if test="query.className != null and query.className !=''">
+            and t.class_name=#{query.className}
+        </if>
+        order by t.id
+    </select>
+    
 </mapper>

+ 14 - 1
teachcloud-mark/src/main/resources/mapper/ScanPaperPageMapper.xml

@@ -17,5 +17,18 @@
         <result column="create_time" property="createTime" />
         <result column="update_time" property="updateTime" />
     </resultMap>
-
+	<select id="listByStudentIds"
+            resultType="com.qmth.teachcloud.mark.bean.archivescore.ScanPaperPageVo">
+        SELECT
+        t.student_id,
+        t.sheetPath
+        FROM
+        scan_student_paper t
+        inner join scan_paper_page p on p.paper_id=t.paper_id
+        WHERE 1=2
+        <foreach collection="studentIds" index="index" item="studentId">
+            or t.student_id=#{studentId}
+        </foreach>
+        order by t.paper_index,p.page_index
+    </select>
 </mapper>