package cn.com.qmth.scancentral.service.impl; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import javax.validation.constraints.NotNull; import cn.com.qmth.scancentral.service.*; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; 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.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.google.gson.Gson; import com.qmth.boot.core.collection.PageResult; import com.qmth.boot.core.concurrent.service.ConcurrentService; import com.qmth.boot.core.exception.ParameterException; import com.qmth.boot.core.exception.StatusException; import com.qmth.boot.tools.excel.ExcelReader; import com.qmth.boot.tools.excel.enums.ExcelType; import com.qmth.boot.tools.uuid.FastUUID; import cn.com.qmth.scancentral.bean.AbsentQueryDomain; import cn.com.qmth.scancentral.bean.AnswerDeleteDomain; import cn.com.qmth.scancentral.bean.AnswerQueryDomain; import cn.com.qmth.scancentral.bean.AssignedQueryDomain; import cn.com.qmth.scancentral.bean.ImportCetAbsentDomain; import cn.com.qmth.scancentral.bean.ImportStudentDomain; import cn.com.qmth.scancentral.bean.PageDeleteDomain; import cn.com.qmth.scancentral.bean.User; import cn.com.qmth.scancentral.bean.answersave.ArrayResult; import cn.com.qmth.scancentral.bean.answersave.BoolResult; import cn.com.qmth.scancentral.bean.answersave.StringResult; import cn.com.qmth.scancentral.bean.omredit.OmrEditDomain; import cn.com.qmth.scancentral.bean.omredit.OmrEditPaper; import cn.com.qmth.scancentral.bean.omredit.OmrFieldEditDomain; import cn.com.qmth.scancentral.bean.refix.AnswerRefixDomain; import cn.com.qmth.scancentral.bean.refix.PageRefixDomain; import cn.com.qmth.scancentral.bean.refix.PaperRefixDomain; import cn.com.qmth.scancentral.config.SysProperty; import cn.com.qmth.scancentral.consumer.BreachImportConsumer; import cn.com.qmth.scancentral.consumer.CustStatusImportConsumer; import cn.com.qmth.scancentral.dao.StudentDao; import cn.com.qmth.scancentral.entity.AnswerCardEntity; import cn.com.qmth.scancentral.entity.ExamEntity; import cn.com.qmth.scancentral.entity.OmrGroupEntity; import cn.com.qmth.scancentral.entity.PaperEntity; import cn.com.qmth.scancentral.entity.PaperPageEntity; import cn.com.qmth.scancentral.entity.QuestionEntity; import cn.com.qmth.scancentral.entity.StudentEntity; import cn.com.qmth.scancentral.entity.StudentPaperEntity; import cn.com.qmth.scancentral.entity.SubjectEntity; import cn.com.qmth.scancentral.entity.UserEntity; import cn.com.qmth.scancentral.enums.AsyncTaskStatus; import cn.com.qmth.scancentral.enums.ExamMode; import cn.com.qmth.scancentral.enums.ExamStatus; import cn.com.qmth.scancentral.enums.ExamStatusCheckMode; import cn.com.qmth.scancentral.enums.GroupType; import cn.com.qmth.scancentral.enums.ImageCheckStatus; import cn.com.qmth.scancentral.enums.LockType; import cn.com.qmth.scancentral.enums.OP; import cn.com.qmth.scancentral.enums.OmrField; import cn.com.qmth.scancentral.enums.Role; import cn.com.qmth.scancentral.enums.ScanStatus; import cn.com.qmth.scancentral.enums.UploadStatus; import cn.com.qmth.scancentral.exception.NotFoundExceptions; import cn.com.qmth.scancentral.exception.ParameterExceptions; import cn.com.qmth.scancentral.model.ManualAbsentImportDTO; import cn.com.qmth.scancentral.support.SpringContextHolder; import cn.com.qmth.scancentral.support.TaskLock; import cn.com.qmth.scancentral.support.TaskLockUtil; import cn.com.qmth.scancentral.util.BatchGetDataUtil; import cn.com.qmth.scancentral.util.BatchSetDataUtil; import cn.com.qmth.scancentral.util.MD5Util; import cn.com.qmth.scancentral.util.PageUtil; import cn.com.qmth.scancentral.vo.AbsentInfoVo; import cn.com.qmth.scancentral.vo.AbsentManualImportVo; import cn.com.qmth.scancentral.vo.AbsentQueryVo; import cn.com.qmth.scancentral.vo.AnswerDeleteVo; import cn.com.qmth.scancentral.vo.AnswerExportK12Vo; import cn.com.qmth.scancentral.vo.AnswerExportVo; import cn.com.qmth.scancentral.vo.AnswerRefixVo; import cn.com.qmth.scancentral.vo.ExportCetMarkingQueryVo; import cn.com.qmth.scancentral.vo.ExportCetVo; import cn.com.qmth.scancentral.vo.ImportStudentQueryVo; import cn.com.qmth.scancentral.vo.ImportStudentVo; import cn.com.qmth.scancentral.vo.PaperDeleteVo; import cn.com.qmth.scancentral.vo.ScanAnswerInfoVo; import cn.com.qmth.scancentral.vo.StudentUploadVo; import cn.com.qmth.scancentral.vo.UpdateTimeVo; import cn.com.qmth.scancentral.vo.answerquery.AnswerPageVo; import cn.com.qmth.scancentral.vo.answerquery.AnswerPaperVo; import cn.com.qmth.scancentral.vo.answerquery.AnswerQueryParam; import cn.com.qmth.scancentral.vo.answerquery.AnswerQueryVo; import cn.com.qmth.scancentral.vo.answerquery.StudentPaperVo; import cn.com.qmth.scancentral.vo.assginedcheck.AssginedTaskResult; import cn.com.qmth.scancentral.vo.assginedcheck.AssignedCheckExamRoomExport; import cn.com.qmth.scancentral.vo.assginedcheck.AssignedCheckExport; import cn.com.qmth.scancentral.vo.assginedcheck.AssignedTaskSaveVo; import cn.com.qmth.scancentral.vo.asynctask.BreachAndStatusImportTaskVo; import cn.com.qmth.scancentral.vo.asynctask.ExamStatusImportTaskVo; import cn.com.qmth.scancentral.vo.asynctask.ExamStatusResetTaskVo; import cn.com.qmth.scancentral.vo.paper.PaperCetVo; import cn.com.qmth.scancentral.vo.paper.PaperPageCetVo; import cn.com.qmth.scancentral.vo.student.StudentAnswerVo; import cn.com.qmth.scancentral.vo.student.StudentExamRoomVo; import cn.com.qmth.scancentral.vo.student.StudentPageQuery; import cn.com.qmth.scancentral.vo.student.StudentPageVo; import cn.com.qmth.scancentral.vo.student.StudentQuery; import cn.com.qmth.scancentral.vo.student.StudentVo; import cn.com.qmth.scancentral.vo.studentimport.StudentCountVo; import cn.com.qmth.scancentral.vo.subject.SubjectScanProgressVo; import cn.com.qmth.scancentral.vo.subject.TaskIdVo; import cn.com.qmth.scancentral.vo.task.TaskStatusVo; @Service public class StudentServiceImpl extends ServiceImpl implements StudentService { private static final Logger log = LoggerFactory.getLogger(StudentService.class); private static ExecutorService exec; @Autowired private AsyncTaskService asyncTaskService; @Autowired private PaperService paperService; @Autowired private PaperPageService paperPageService; @Autowired private StudentPaperService studentPaperService; @Autowired private ExamService examService; @Autowired private SubjectService subjectService; @Autowired private BatchService batchService; @Autowired private AnswerCardService answerCardService; @Autowired private ConcurrentService concurrentService; @Autowired private OmrTaskService omrTaskService; @Autowired private OmrGroupService omrGroupService; @Autowired private QuestionService questionService; @Autowired private SysProperty sysProperty; @Autowired private ToolExportService toolExportService; @Autowired private AnswerCardSubjectService answerCardSubjectService; @Autowired private AssignedCheckHistoryService assignedCheckHistoryService; @Autowired private UserService userService; @Autowired private FileService fileService; @Autowired private MarkSiteService markSiteService; @Autowired private ExamRoomService examRoomService; static { int threadCount = 5; exec = new ThreadPoolExecutor(threadCount, threadCount, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(threadCount * 2), r -> { Thread t = new Thread(r); return t; }, (r, executor) -> { if (!executor.isShutdown()) { try { executor.getQueue().put(r); } catch (InterruptedException e) { throw new RuntimeException(e); } } }); } /** * 整体更新考生绑定的paper并刷新考生状态,若集合为空则表示考生无扫描结果,需要在外部调用处对考生上锁 * * @param id * @param studentPaperList */ @Override @Transactional // @Lockable(name = LockType.STUDENT, key = "#id") public void updateStudentAndPaper(@NotNull User user, @NotNull Long id, @NotNull List studentPaperList) { for (StudentPaperEntity studentPaper : studentPaperList) { studentPaper.setStudentId(id); } // 清空原有绑定关系 studentPaperService.removeByStudentId(id); // 保存绑定关系 studentPaperService.saveOrUpdateBatchByMultiId(studentPaperList); // 更新考生状态 updateStudentByPaper(user, id, true); } /** * 根据考生当前绑定的paper刷新考生状态,需要在外部调用处对考生上锁 * * @param id */ @Override @Transactional // @Lockable(name = LockType.STUDENT, key = "#id") public void updateStudentByPaper(@NotNull User user, @NotNull Long id, @NotNull boolean updateOmrTask) { StudentEntity student = baseMapper.selectById(id); if (student == null) { throw new ParameterException("找不到对应的考生"); } ExamEntity exam = examService.getById(student.getExamId()); // 重置状态 student.setIncomplete(false); student.setAssigned(false); student.setAssignedSuspect(false); student.setQuestionFilled(false); student.setSubjectiveFilled(false); student.setDevice(null); student.setCardNumber(null); student.setPaperType("#"); student.setOmrAbsent(false); student.setExamStatus(ExamStatus.OK); int paperCount = 0; List studentPaperList = studentPaperService.findByStudentId(id); int omrExamNumberCount = 0; for (StudentPaperEntity studentPaper : studentPaperList) { paperCount++; // 获取paper详情更新考生状态 PaperEntity paper = paperService.getById(studentPaper.getPaperId()); student.setAssigned(student.getAssigned() || paper.getAssigned()); // student.setAssignedSuspect(student.getAssignedSuspect() || // paper.getAssignedSuspect()); student.setQuestionFilled(student.getQuestionFilled() || paper.getQuestionFilled()); student.setSubjectiveFilled(student.getSubjectiveFilled() || paper.getSubjectiveFilled()); student.setCardNumber(paper.getCardNumber()); // 单独判断首张纸正面的识别结果 if (studentPaper.getPaperNumber() == 1) { // 根据识别结果更新考生属性 PaperPageEntity page = paperPageService.findPaperIdAndIndex(paper.getId(), 1); List paperTypeBarcodeContents = markSiteService .findPaperTypeBarcodeContentByExamAndSubjectCode(student.getExamId(), student.getSubjectCode()); if (paperTypeBarcodeContents == null || paperTypeBarcodeContents.isEmpty()) { paperTypeBarcodeContents = exam.getPaperTypeBarcodeContent(); } if (page.getPaperType() == null || page.getPaperType().getResult().length() == 0 || page.getPaperType().getResult().equals("#")) { student.setPaperType("#"); } else if (CollectionUtils.isNotEmpty(paperTypeBarcodeContents) && !paperTypeBarcodeContents.contains(page.getPaperType().getResult())) { student.setPaperType("?"); } else { student.setPaperType(page.getPaperType().getResult()); } // student.setPaperType(page.getPaperType() != null ? // page.getPaperType().getResult() : "#"); student.setOmrAbsent(page.getAbsent() == null ? false : page.getAbsent().getResult()); student.setDevice(batchService.findByPaperId(paper.getId()).getDevice()); } // 计算识别位数 int paperExamNumberCount = paper.getOmrExamNumber().replace("#", "").length(); if (omrExamNumberCount < paperExamNumberCount) { omrExamNumberCount = paperExamNumberCount; } } // 更新考生状态 if (paperCount > 0) { AnswerCardEntity answerCard = answerCardService.findByExamAndNumber(student.getExamId(), student.getCardNumber()); student.setIncomplete(paperCount != answerCard.getPaperCount()); student.setStatus(ScanStatus.SCANNED); } else { student.setStatus(ScanStatus.UNEXIST); student.setExamStatus(null); } // 更新缺考校验状态 if (exam.getExamNumberFillCount() != null) { resetExamStatus(student, omrExamNumberCount, exam.getExamNumberFillCount()); } student.setFileUploadStatus(UploadStatus.WAITING_UPLOAD); student.setImageCheckStatus(ImageCheckStatus.WAITING); student.setDataUploadStatus(UploadStatus.WAITING_UPLOAD); student.setUpdaterId(user.getId()); student.setUpdateTime(System.currentTimeMillis()); saveOrUpdate(student); // try { // SignatureInfo signatureInfo = new SignatureInfo(SignatureType.TOKEN, // user.getAccount(), // user.getMarkingCloudToken()); // apiClient.studentFileDelete(signatureInfo.toString(), // student.getExamId(), student.getExamNumber()); // } catch (RetrofitResponseError e) { // e.printStackTrace(); // if (e.getCode() == 401) { // throw AuthorizationException.SIGNATURE_INVALID; // } else { // throw e; // } // } if (updateOmrTask) { // 遍历固定任务分组 List gs = omrGroupService.findByExamIdAndSubjectCode(student.getExamId(), student.getSubjectCode()); if (CollectionUtils.isNotEmpty(gs)) { for (OmrGroupEntity g : gs) { concurrentService.getReadWriteLock(LockType.OMR_GROUP + "-" + g.getId()).readLock().lock(); omrTaskService.deleteByStudentIdAndGroupId(g.getId(), student.getId()); // 默认分组重新生成识别对照任务,其他任务不生成 if (g.getFixed()) { omrTaskService.saveTask(g, student.getId()); } concurrentService.getReadWriteLock(LockType.OMR_GROUP + "-" + g.getId()).readLock().unlock(); } } } } @Override public Integer getStudentAnswerCount(Long examId) { if (examId == null) { throw new ParameterException("examId不能为空"); } QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.lambda().eq(StudentEntity::getExamId, examId); queryWrapper.lambda().eq(StudentEntity::getCheckMark, true); return this.count(queryWrapper); } @Override public StudentVo findOne(StudentQuery query) { Long examId = query.getExamId(); String examNumber = query.getExamNumber(); String subjectCode = query.getSubjectCode(); if (StringUtils.isBlank(examNumber) || StringUtils.isBlank(subjectCode)) { throw new ParameterException("examNumber subjectCode不能都为空"); } QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.lambda().eq(StudentEntity::getExamId, examId); queryWrapper.lambda().eq(StudentEntity::getExamNumber, examNumber); queryWrapper.lambda().eq(StudentEntity::getSubjectCode, subjectCode); StudentEntity s = baseMapper.selectOne(queryWrapper); if (s == null) { throw new ParameterException("未找到考生"); } StudentVo vo = StudentVo.of(s); SubjectEntity sub = subjectService.findByExamIdAndCode(examId, s.getSubjectCode()); vo.setSubjectName(sub.getName()); return vo; } @Override public int getCountByExam(Long examId) { QueryWrapper wrapper = new QueryWrapper<>(); LambdaQueryWrapper lw = wrapper.lambda(); lw.eq(StudentEntity::getExamId, examId); return this.count(wrapper); } @Override public int getPackageCountByExam(Long examId) { return baseMapper.getPackageCountByExam(examId); } @Override public int getCountByExamAndScanStatus(Long examId, ScanStatus status) { QueryWrapper wrapper = new QueryWrapper<>(); LambdaQueryWrapper lw = wrapper.lambda(); lw.eq(StudentEntity::getExamId, examId); lw.eq(StudentEntity::getStatus, status); return this.count(wrapper); } @Override public List packageList(StudentQuery query) { List ret = new ArrayList<>(); StudentVo one = findOne(query); if (one != null) { List list = findByExamAndPackage(query.getExamId(), one.getPackageCode(), one.getSubjectCode()); if (CollectionUtils.isNotEmpty(list)) { for (StudentEntity e : list) { StudentVo vo = StudentVo.of(e); vo.setSubjectName(one.getSubjectName()); ret.add(vo); } } } return ret; } @Override public List findByExamAndPackage(Long examId, String packageCode, String subjectCode) { if (examId == null) { throw new ParameterException("examId 不能为空"); } if (StringUtils.isBlank(packageCode)) { throw new ParameterException("packageCode不能为空"); } QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.lambda().eq(StudentEntity::getExamId, examId); queryWrapper.lambda().eq(StudentEntity::getPackageCode, packageCode); if (StringUtils.isNotBlank(subjectCode)) { queryWrapper.lambda().eq(StudentEntity::getSubjectCode, subjectCode); } return this.list(queryWrapper); } @Override public int getAssignedCountByExam(Long examId) { QueryWrapper wrapper = new QueryWrapper<>(); LambdaQueryWrapper lw = wrapper.lambda(); lw.eq(StudentEntity::getExamId, examId); lw.eq(StudentEntity::getAssigned, true); return this.count(wrapper); } @Override public int getUnscannedCountByExam(Long examId) { QueryWrapper wrapper = new QueryWrapper<>(); LambdaQueryWrapper lw = wrapper.lambda(); lw.eq(StudentEntity::getExamId, examId); lw.ne(StudentEntity::getStatus, ScanStatus.SCANNED); return this.count(wrapper); } @Override public int getAbsentSuspectCountByExam(Long examId) { QueryWrapper wrapper = new QueryWrapper<>(); LambdaQueryWrapper lw = wrapper.lambda(); lw.eq(StudentEntity::getExamId, examId); lw.eq(StudentEntity::getAbsentSuspect, true); return this.count(wrapper); } @Override public int getIncompleteCountByExam(Long examId) { QueryWrapper wrapper = new QueryWrapper<>(); LambdaQueryWrapper lw = wrapper.lambda(); lw.eq(StudentEntity::getExamId, examId); lw.eq(StudentEntity::getIncomplete, true); return this.count(wrapper); } @Override public AbsentInfoVo absentInfo(Long examId, GroupType groupType, String groupName) { AbsentInfoVo vo = baseMapper.absentInfo(examId, groupType != null ? groupType.getFieldName() : null, StringUtils.trimToNull(groupName)); if (vo == null) { vo = new AbsentInfoVo(); } return vo; } // private Integer totalCount(Long examId) { // QueryWrapper wrapper = new QueryWrapper<>(); // LambdaQueryWrapper lw = wrapper.lambda(); // lw.eq(StudentEntity::getExamId, examId); // return this.count(wrapper); // } // // private Integer countByStatus(Long examId, ScanStatus st) { // QueryWrapper wrapper = new QueryWrapper<>(); // LambdaQueryWrapper lw = wrapper.lambda(); // lw.eq(StudentEntity::getExamId, examId); // lw.eq(StudentEntity::getStatus, st); // return this.count(wrapper); // } // // private Integer countByAbsentSuspect(Long examId) { // QueryWrapper wrapper = new QueryWrapper<>(); // LambdaQueryWrapper lw = wrapper.lambda(); // lw.eq(StudentEntity::getExamId, examId); // lw.eq(StudentEntity::getAbsentSuspect, true); // return this.count(wrapper); // } // // private Integer countByIncomplete(Long examId) { // QueryWrapper wrapper = new QueryWrapper<>(); // LambdaQueryWrapper lw = wrapper.lambda(); // lw.eq(StudentEntity::getExamId, examId); // lw.eq(StudentEntity::getIncomplete, true); // return this.count(wrapper); // } @Override public PageResult absentQuery(AbsentQueryDomain query) { IPage iPage = baseMapper.absentQueryPage(new Page<>(query.getPageNumber(), query.getPageSize()), query.getGroupType().getFieldName(), query); return PageUtil.of(iPage); } @Override public List absentSummary(AbsentQueryDomain query) { return baseMapper.absentQuerySummary(query.getGroupType().getFieldName(), query); } @Override public List absentExportList(AbsentQueryDomain query) { return baseMapper.absentExportList(new Page<>(query.getPageNumber(), query.getPageSize()), query.getGroupType().getFieldName(), query); } @Transactional @Override public AbsentManualImportVo absentManualImport(Long examId, MultipartFile multipartFile) { List list = null; try { list = ExcelReader.create(ExcelType.XLSX, multipartFile.getInputStream(), 0) .getObjectList(ManualAbsentImportDTO.class); } catch (IOException e) { throw new ParameterException("Excel解析出错", e); } catch (Exception e) { throw new ParameterException("Excel解析出错", e); } if (CollectionUtils.isEmpty(list)) { throw new ParameterException("Excel无内容"); } // if (10001 < lineList.size()) { // throw new ParameterException("数据行数不能超过10000"); // } int updateCount = 0; int ignoreCount = 0; int suspectCount = 0; for (ManualAbsentImportDTO data : list) { String examNumber = trimAndNullIfBlank(data.getExamNumber()); String subjectCode = trimAndNullIfBlank(data.getSubjectCode()); if (StringUtils.isBlank(examNumber)) { throw new ParameterException("examNumber不能为空"); } if (StringUtils.isBlank(subjectCode)) { throw new ParameterException("科目代码不能为空"); } StudentEntity student = this.findByExamAndSubjectCodeAndExamNumber(examId, subjectCode, examNumber); if (student == null) { throw new ParameterException("考生信息未找到:" + examNumber + ":" + subjectCode); } if (ScanStatus.MANUAL_ABSENT.equals(student.getStatus())) { ignoreCount++; } else if (ScanStatus.SCANNED.equals(student.getStatus())) { absentSuspectUpdate(student.getExamId(), student.getSubjectCode(), student.getExamNumber(), true); suspectCount++; } else { absentManualUpdate(student.getExamId(), student.getSubjectCode(), student.getExamNumber()); updateCount++; } } AbsentManualImportVo vo = new AbsentManualImportVo(); vo.setIgnoreCount(ignoreCount); vo.setUpdateCount(updateCount); vo.setSuspectCount(suspectCount); return vo; } private String trimAndNullIfBlank(String s) { if (StringUtils.isBlank(s)) { return null; } return s.trim(); } @Transactional @Override public UpdateTimeVo absentManualUpdate(Long examId, String subjectCode, String examNumber) { StudentEntity student = this.findByExamAndSubjectCodeAndExamNumber(examId, subjectCode, examNumber); if (student == null) { throw new ParameterException("考生未找到:" + examNumber); } if (student.getStatus() != ScanStatus.UNEXIST) { throw new ParameterException("考生不是未扫描状态:" + examNumber); } LambdaUpdateWrapper lw = new LambdaUpdateWrapper<>(); lw.set(StudentEntity::getStatus, ScanStatus.MANUAL_ABSENT); lw.set(StudentEntity::getDataUploadStatus, UploadStatus.WAITING_UPLOAD); lw.eq(StudentEntity::getId, student.getId()); lw.eq(StudentEntity::getStatus, ScanStatus.UNEXIST); update(lw); return UpdateTimeVo.create(); } @Transactional @Override public UpdateTimeVo absentSuspectUpdate(Long examId, String subjectCode, String examNumber, boolean enable) { StudentEntity student = this.findByExamAndSubjectCodeAndExamNumber(examId, subjectCode, examNumber); if (student == null) { throw new ParameterException("考生未找到:" + examNumber); } LambdaUpdateWrapper lw = new LambdaUpdateWrapper<>(); lw.set(StudentEntity::getAbsentSuspect, enable); lw.set(StudentEntity::getDataUploadStatus, UploadStatus.WAITING_UPLOAD); lw.eq(StudentEntity::getId, student.getId()); update(lw); return UpdateTimeVo.create(); } @Override public ScanAnswerInfoVo scanAnswerInfo(Long examId) { return baseMapper.getInfoCountByExam(examId); } @Override public List summary(AnswerQueryDomain query) { // 不分页查询考生准考证号 return baseMapper.querySummary(query); } @Override public List exportList(AnswerQueryDomain query) { // 分页查询考生导出信息 return baseMapper.exportList(new Page<>(query.getPageNumber(), query.getPageSize()), query); } @Override public List exportListK12(AnswerQueryDomain query) { // 分页查询考生导出信息 List list = baseMapper.exportList(new Page<>(query.getPageNumber(), query.getPageSize()), query); List ret = new ArrayList<>(); if (CollectionUtils.isNotEmpty(list)) { for (AnswerExportVo vo : list) { AnswerExportK12Vo kvo = new AnswerExportK12Vo(); BeanUtils.copyProperties(vo, kvo); ret.add(kvo); } } return ret; } @Override public PageResult query(AnswerQueryParam query) { // 查询考生分页信息 IPage iPage = baseMapper.queryPage(new Page<>(query.getPageNumber(), query.getPageSize()), query); if (CollectionUtils.isNotEmpty(iPage.getRecords())) { Map map = new HashMap<>(); for (AnswerQueryVo vo : iPage.getRecords()) { List 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 studentIds = iPage.getRecords().stream().map(p -> p.getId()).collect(Collectors.toList()); List paperList = new BatchGetDataUtil() { @Override public List getData(List paramList) { return paperService.listByStudentIds(paramList); } }.getDataForBatch(studentIds, 20); if (CollectionUtils.isNotEmpty(paperList)) { Map paperMap = new HashMap<>(); for (StudentPaperVo p : paperList) { AnswerQueryVo vo = map.get(p.getStudentId()); if (vo == null) { continue; } List 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 paperIds = paperList.stream().map(p -> p.getPaperId()).collect(Collectors.toList()); List paperPageList = new BatchGetDataUtil() { @Override public List getData(List paramList) { return paperPageService.listByPaperList(paramList); } }.getDataForBatch(paperIds, 20); if (CollectionUtils.isNotEmpty(paperPageList)) { for (PaperPageEntity p : paperPageList) { AnswerPaperVo pvo = paperMap.get(p.getPaperId()); if (pvo == null) { continue; } List pages = pvo.getPages(); if (pages == null) { pages = new ArrayList<>(); pvo.setPages(pages); } AnswerPageVo pageVo = new AnswerPageVo(); pageVo.setIndex(p.getPageIndex()); pageVo.setSheetUri(p.getSheetPath()); pageVo.setSliceUri(p.getSlicePath()); if (query.getWithOmrDetail() != null && query.getWithOmrDetail()) { pageVo.setAbsent(p.getAbsent()); pageVo.setBreach(p.getBreach()); pageVo.setPaperType(p.getPaperType()); pageVo.setQuestion(p.getQuestion()); pageVo.setSelective(p.getSelective()); pageVo.setRecogData(p.getRecogData()); } pages.add(pageVo); } } } } return PageUtil.of(iPage); } @Transactional @Override public void updateFileUploadStatus(@NotNull Long id, @NotNull UploadStatus status) { LambdaUpdateWrapper lw = new LambdaUpdateWrapper<>(); lw.set(StudentEntity::getFileUploadStatus, status); lw.eq(StudentEntity::getId, id); update(lw); } @Transactional @Override public void updateOmrAbsent(@NotNull Long id, @NotNull Boolean omrAbsent) { LambdaUpdateWrapper lw = new LambdaUpdateWrapper<>(); lw.set(StudentEntity::getOmrAbsent, omrAbsent); lw.eq(StudentEntity::getId, id); update(lw); } @Transactional @Override public void deletetByExamIdAndUnCreateTime(Long examId, long createTime) { QueryWrapper wrapper = new QueryWrapper<>(); LambdaQueryWrapper lw = wrapper.lambda(); lw.eq(StudentEntity::getExamId, examId); lw.ne(StudentEntity::getCreateTime, createTime); this.baseMapper.delete(wrapper); } @Override public boolean existUploadData() { return CollectionUtils.isNotEmpty(baseMapper.findToUpload(1)) || CollectionUtils.isNotEmpty(baseMapper.findUploadError(1)); } @Override public List findToUpload(int pageSize) { if (pageSize <= 0) { pageSize = 100; } List result = baseMapper.findToUpload(pageSize); if (CollectionUtils.isEmpty(result)) { result = baseMapper.findUploadError(pageSize); } return result; } @Override public int getCountByExamAndCardNumber(Long examId, Integer number) { QueryWrapper wrapper = new QueryWrapper<>(); LambdaQueryWrapper lw = wrapper.lambda(); lw.eq(StudentEntity::getExamId, examId); lw.eq(StudentEntity::getCardNumber, number); return this.count(wrapper); } @Transactional @Override public int importStudent(List students) { List savelist = new ArrayList(); List updatelist = new ArrayList(); // Map> map =new HashMap>(); for (ImportStudentDomain domain : students) { // Map examMap =map.get(domain.getExamId()); // if(examMap ==null) { // examMap = new HashMap(); // List list2 = this.list(); // for (StudentEntity s : list2) { // examMap.put(s.getExamNumber(), s); // } // map.put(domain.getExamId(), examMap); // } // StudentEntity entity = examMap.get(domain.getExamNumber()); StudentEntity entity = this.findByExamAndSubjectCodeAndExamNumber(domain.getExamId(), domain.getSubjectCode(), domain.getExamNumber()); if (entity == null) { entity = this.findByExamAndSubjectCodeAndExamNumber(domain.getExamId(), domain.getSubjectCode(), domain.getExamNumber()); } if (entity == null) { entity = new StudentEntity(); entity.setStatus(ScanStatus.UNEXIST); entity.setImageCheckStatus(ImageCheckStatus.WAITING); entity.setAbsentSuspect(false); entity.setAssigned(false); entity.setIncomplete(false); entity.setOmrAbsent(false); entity.setQuestionFilled(false); entity.setSubjectiveFilled(false); entity.setPaperType("#"); entity.setCheckMark(false); entity.setAssignedSuspect(false); savelist.add(entity); } else { updatelist.add(entity); } entity.setExamId(domain.getExamId()); entity.setName(domain.getName()); entity.setSubjectCode(domain.getSubjectCode()); entity.setExamNumber(domain.getExamNumber()); entity.setPackageCode(domain.getPackageCode()); entity.setExamRoom(domain.getExamRoom()); entity.setProvince(domain.getProvince()); entity.setExamSite(domain.getExamSite()); entity.setExamSiteName(domain.getExamSiteName()); entity.setSeatNumber(domain.getSeatNumber()); entity.setCampusName(domain.getCampusName()); entity.setCampusCode(domain.getCampusCode()); } if (savelist.size() > 0) { this.saveBatch(savelist); } if (updatelist.size() > 0) { this.updateBatchById(updatelist); } return students.size(); } @Override public StudentEntity findByExamAndSubjectCodeAndExamNumber(Long examId, String subjectCode, String examNumber) { if (examId == null) { throw new ParameterException("examId 不能为空"); } if (StringUtils.isBlank(subjectCode)) { throw new ParameterException("subjectCode不能为空"); } if (StringUtils.isBlank(examNumber)) { throw new ParameterException("examNumber"); } QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.lambda().eq(StudentEntity::getExamId, examId); queryWrapper.lambda().eq(StudentEntity::getSubjectCode, subjectCode); queryWrapper.lambda().eq(StudentEntity::getExamNumber, examNumber); return baseMapper.selectOne(queryWrapper); } @Override public int countByQuery(ImportStudentQueryVo query) { if (query.getExamId() == null) { throw new ParameterException("examId不能为空"); } return baseMapper.countByQuery(query); } @Override public int countCetMarking(ExportCetMarkingQueryVo query) { if (query.getExamId() == null) { throw new ParameterException("examId不能为空"); } return baseMapper.countCetMarking(query); } @Override public List findByQuery(ImportStudentQueryVo query) { if (query.getExamId() == null) { throw new ParameterException("examId不能为空"); } ExamEntity exam = examService.getById(query.getExamId()); if (exam == null) { throw new ParameterException("未找到考试"); } IPage iPage = baseMapper .listPageQuery(new Page(query.getPageNumber(), query.getPageSize()), query); if (query.getWithAnswer() != null && query.getWithAnswer()) { for (ImportStudentVo student : iPage.getRecords()) { List papers = studentPaperService.findByStudentId(student.getId()); List pageList = new ArrayList<>(); for (StudentPaperEntity sp : papers) { List pages = paperPageService.listByPaperId(sp.getPaperId()); pageList.addAll(pages); } List answers = new ArrayList(); for (PaperPageEntity p : pageList) { if (p.getPageIndex() == 1) { student.setPaperType(p.getPaperType() == null ? null : p.getPaperType().getResult()); } disposeQuestionMark(p.getQuestion()); if (p.getQuestion() != null && CollectionUtils.isNotEmpty(p.getQuestion().getResult())) { answers.addAll(p.getQuestion().getResult()); } } student.setAnswer(answers); } } return iPage.getRecords(); } private void disposeQuestionMark(ArrayResult ar) { if (ar != null && CollectionUtils.isNotEmpty(ar.getResult())) { for (int i = 0; i < ar.getResult().size(); i++) { ar.getResult().set(i, ar.getResult().get(i).replaceAll("\\?", "")); } } } @Override public int getOmrAbsentCountByExam(Long examId) { QueryWrapper wrapper = new QueryWrapper<>(); LambdaQueryWrapper lw = wrapper.lambda(); lw.eq(StudentEntity::getExamId, examId); lw.eq(StudentEntity::getOmrAbsent, true); return this.count(wrapper); } @Override public boolean existPictureCopyData() { List list = baseMapper.findToPictureCopy(1); return CollectionUtils.isNotEmpty(list); } @Override public List findToPictureCopy(int pageSize) { if (pageSize <= 0) { pageSize = 100; } return baseMapper.findToPictureCopy(pageSize); } @Override public Double getUploadProgress(Long examId) { // int total = getCountByExamAndScanStatus(examId, ScanStatus.SCANNED); // if (total == 0) { // return 0.0; // } int needUpload = baseMapper.getNeedUploadCount(examId); int uploaded = baseMapper.getUploadedCount(examId); int total = needUpload + uploaded; if (total == 0) { return 0.0; } BigDecimal totalB = new BigDecimal(total); BigDecimal uploadedB = new BigDecimal(uploaded); return uploadedB.divide(totalB, 2, BigDecimal.ROUND_HALF_UP).doubleValue(); } @Transactional @Override public void studentClean(Long examId, String subjectCode) { ExamEntity exam = examService.getById(examId); if (exam == null) { throw ParameterExceptions.EXAM_NOT_FOUND; } if (batchService.getCountByExamAndSubject(examId, subjectCode) > 0) { throw new ParameterException("已开始扫描不能清空"); } LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); wrapper.eq(StudentEntity::getExamId, examId); wrapper.eq(StudentEntity::getSubjectCode, subjectCode); baseMapper.delete(wrapper); examRoomService.clearByExamAndSubject(examId, subjectCode); } @Transactional @Override // @Lockable public PaperDeleteVo paperDelete(User user, PageDeleteDomain domain) { Integer paperNumber = domain.getPaperNumber(); StudentEntity student = this.findByExamAndSubjectCodeAndExamNumber(domain.getExamId(), domain.getSubjectCode(), domain.getExamNumber()); if (student == null) { throw new ParameterException("考生信息未找到"); } concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().lock(); try { updateStudentAndPaper(user, student.getId(), removeStudentPaper(studentPaperService.findByStudentId(student.getId()), paperNumber)); updateAssignedCheckCount(student.getId(), true); PaperDeleteVo vo = new PaperDeleteVo(); vo.setPaperCount(studentPaperService.countByStudentId(student.getId())); vo.setUpdateTime(new Date().getTime()); return vo; } finally { concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().unlock(); } } private List removeStudentPaper(List list, Integer paperNumber) { boolean find = false; List left = new ArrayList<>(); for (StudentPaperEntity entity : list) { if (entity.getPaperNumber().equals(paperNumber)) { find = true; } else { left.add(entity); } } if (!find) { throw new ParameterException("未找到该张扫描结果"); } else if (left.size() > 0 && paperNumber == 1) { throw new StatusException("需先删除其他张之后才能删除第一张"); } else { return left; } } @Transactional @Override // @Lockable public AnswerDeleteVo answerDelete(User user, AnswerDeleteDomain domain) { Long examId = domain.getExamId(); String examNumber = domain.getExamNumber(); StudentEntity student = this.findByExamAndSubjectCodeAndExamNumber(examId, domain.getSubjectCode(), examNumber); if (student == null) { throw new ParameterException("考生信息未找到"); } concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().lock(); try { updateStudentAndPaper(user, student.getId(), new ArrayList<>()); updateAssignedCheckCount(student.getId(), true); AnswerDeleteVo vo = new AnswerDeleteVo(); vo.setStatus(ScanStatus.UNEXIST); vo.setUpdateTime(new Date().getTime()); return vo; } finally { concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().unlock(); } } @Transactional @Override // @Lockable public AnswerRefixVo answerRefix(User user, AnswerRefixDomain domain) { StudentEntity student = this.findByExamAndSubjectCodeAndExamNumber(domain.getExamId(), domain.getSubjectCode(), domain.getExamNumber()); if (student == null) { throw new ParameterException("考生信息未找到"); } AnswerCardEntity answerCard = answerCardService.findByExamAndNumber(domain.getExamId(), domain.getCardNumber()); if (answerCard == null) { throw new ParameterException("卡格式信息未找到"); } boolean allowSubject = answerCardSubjectService.checkSubject(answerCard.getExamId(), answerCard.getNumber(), student.getSubjectCode()); if (!allowSubject) { throw new ParameterException("卡格式与考生科目不匹配"); } // if (domain.getPapers().size() != answerCard.getPaperCount()) { // throw new ParameterException("卡格式张数不一致"); // } ExamEntity exam = examService.getById(student.getExamId()); List paperTypeBarcodeContents = exam.getPaperTypeBarcodeContent(); SubjectEntity subject = subjectService.findByExamIdAndCode(student.getExamId(), student.getSubjectCode()); if (subject.getPaperTypeBarcodeContent() != null && !subject.getPaperTypeBarcodeContent().isEmpty()) { paperTypeBarcodeContents = subject.getPaperTypeBarcodeContent(); } concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().lock(); try { List studentPaperList = studentPaperService.findByStudentId(student.getId()); for (StudentPaperEntity studentPaper : studentPaperList) { PaperRefixDomain paperDomain = domain.findPaperDomain(studentPaper.getPaperNumber(), studentPaper.getPaperId()); if (paperDomain == null) { throw new ParameterException("与考生当前paper不一致,paperNumber=" + studentPaper.getPaperNumber()); } PaperEntity paper = paperService.getById(paperDomain.getId()); if (paper == null) { throw new ParameterException("考生当前paper不存在,paperId=" + paperDomain.getId()); } paper.setCardNumber(answerCard.getNumber()); paper.setMismatch(paperDomain.getMismatch()); List pages = new ArrayList<>(); for (PageRefixDomain pageDomain : paperDomain.getPages()) { PaperPageEntity page = paperPageService.findPaperIdAndIndex(paper.getId(), pageDomain.getIndex()); if (page == null) { throw new ParameterException("与考生当前page不一致,pageIndex=" + pageDomain.getIndex()); } pages.add(pageDomain.update(page, paperTypeBarcodeContents)); } paperService.savePaperAndPages(paper, pages); } updateStudentByPaper(user, student.getId(), true); return AnswerRefixVo.create(); } finally { concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().unlock(); } } @Transactional @Override public UpdateTimeVo omrEdit(User user, OmrEditDomain domain) { StudentEntity student = this.findByExamAndSubjectCodeAndExamNumber(domain.getExamId(), domain.getSubjectCode(), domain.getExamNumber()); if (student == null) { throw new ParameterException("考生信息未找到"); } concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().lock(); try { for (OmrEditPaper paperEdit : domain.getPapers()) { StudentPaperEntity sp = studentPaperService.findByStudentIdAndPaperNumber(student.getId(), paperEdit.getNumber()); if (sp == null) { throw new ParameterException("未找到绑定扫描结果"); } PaperEntity paperEntity = paperService.getById(sp.getPaperId()); if (paperEntity == null) { throw new ParameterException("未找到paper信息结果"); } paperEntity.setUpdaterId(user.getId()); paperEntity.setUpdateTime(System.currentTimeMillis()); List pages = paperPageService.listByPaperId(paperEntity.getId()); for (PaperPageEntity pageEntity : pages) { paperEdit.updatePage(pageEntity); } paperService.savePaperAndPages(paperEntity, pages); } updateStudentByPaper(user, student.getId(), false); return UpdateTimeVo.create(); } finally { concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().unlock(); } } @Transactional @Override public UpdateTimeVo omrFieldEdit(User user, OmrFieldEditDomain domain) { StudentEntity student = this.findByExamAndSubjectCodeAndExamNumber(domain.getExamId(), domain.getSubjectCode(), domain.getExamNumber()); if (student == null) { throw new ParameterException("考生信息未找到"); } concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().lock(); try { StudentPaperEntity sp = studentPaperService.findByStudentIdAndPaperNumber(student.getId(), domain.getPaperNumber()); if (sp == null) { throw new ParameterException("未找到绑定扫描结果"); } PaperEntity paperEntity = paperService.getById(sp.getPaperId()); if (paperEntity == null) { throw new ParameterException("未找到paper信息结果"); } paperEntity.setUpdaterId(user.getId()); paperEntity.setUpdateTime(System.currentTimeMillis()); List pages = paperPageService.listByPaperId(paperEntity.getId()); boolean pageIndexValid = false; for (PaperPageEntity pageEntity : pages) { if (pageEntity.getPageIndex().equals(domain.getPageIndex())) { pageIndexValid = true; Gson gson = new Gson(); if (StringUtils.isBlank(domain.getValue().toString())) { throw new ParameterException("field值为空"); } if (OmrField.ABSENT.equals(domain.getField())) { pageEntity.setAbsent(gson.fromJson(domain.getValue().toString(), BoolResult.class)); } else if (OmrField.BREACH.equals(domain.getField())) { pageEntity.setBreach(gson.fromJson(domain.getValue().toString(), BoolResult.class)); } else if (OmrField.PAPER_TYPE.equals(domain.getField())) { pageEntity.setPaperType(gson.fromJson(domain.getValue().toString(), StringResult.class)); } else if (OmrField.QUESTION.equals(domain.getField())) { pageEntity.setQuestion(gson.fromJson(domain.getValue().toString(), ArrayResult.class)); } else if (OmrField.SELECTIVE.equals(domain.getField())) { pageEntity.setSelective(gson.fromJson(domain.getValue().toString(), ArrayResult.class)); } else { throw new ParameterException("field值错误"); } } } if (!pageIndexValid) { throw new ParameterException("未找到page信息结果"); } paperService.savePaperAndPages(paperEntity, pages); updateStudentByPaper(user, student.getId(), false); return UpdateTimeVo.create(); } finally { concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().unlock(); } } @Transactional @Override public Integer importCetAbsent(List students) { List list = new ArrayList(); for (ImportCetAbsentDomain domain : students) { if (domain.getExamId() == null) { throw new StatusException("考试id不能为空"); } if (domain.getExamNumber() == null) { throw new StatusException("准考证号不能为空"); } // if (domain.getAbsent() == null) { // throw new StatusException("缺考信息不能为空"); // } StudentEntity entity = this.findByExamAndSubjectCodeAndExamNumber(domain.getExamId(), domain.getSubjectCode(), domain.getExamNumber()); if (entity == null) { throw new StatusException("未找到考生"); } entity.setBreachCode(domain.getBreachCode()); // entity.setExamStatus(domain.getAbsent() ? ExamStatus.ABSENT : // null); list.add(entity); } this.updateBatchById(list); return list.size(); } @Override public List exportCetData(ExportCetMarkingQueryVo query) { if (query.getExamId() == null) { throw new ParameterException("examId不能为空"); } ExamEntity exam = examService.getById(query.getExamId()); if (exam == null) { throw new ParameterException("未找到考试"); } if (CollectionUtils.isEmpty(exam.getPaperTypeBarcodeContent())) { throw new ParameterException("该考试条码值未设置"); } if (!ExamMode.CET.equals(exam.getMode())) { throw new ParameterException("该考试不是CET"); } IPage iPage = baseMapper .listCetMarkingPage(new Page(query.getPageNumber(), query.getPageSize()), query); if (CollectionUtils.isNotEmpty(iPage.getRecords())) { String imageTransferDir = sysProperty.getTransferDir(); Map> structs = new HashMap<>(); Map cardMap = new HashMap<>(); new BatchSetDataUtil() { @Override protected void setData(List dataList) { List ids = dataList.stream().map(e -> e.getId()).collect(Collectors.toList()); List totalpages = paperPageService.listByStudentIds(ids); List totalpapers = paperService.findByStudentIds(ids); Map> totalpagesmap = ofPage(totalpages); Map> totalpapersmap = ofPaper(totalpapers); for (ExportCetVo vo : dataList) { disposeStudent(vo, exam, totalpagesmap.get(vo.getId()), totalpapersmap.get(vo.getId()), imageTransferDir, structs, cardMap); } } }.setDataForBatch(iPage.getRecords(), 200); } return iPage.getRecords(); } private void disposeStudent(ExportCetVo student, ExamEntity exam, List pages, List papers, String imageTransferDir, Map> structs, Map cardMap) { int subject = Integer.valueOf(student.getSubjectCode()); if (subject > 2) { if (student.getExamStatus().equals(ExamStatus.ABSENT)) { student.setPaperType("000000"); } else { student.setPaperType("888888"); } } else { if (StringUtils.isBlank(student.getPaperType()) || "#".equals(student.getPaperType())) { student.setPaperType("000000"); } else if ("?".equals(student.getPaperType()) || !exam.getPaperTypeBarcodeContent().contains(student.getPaperType())) { student.setPaperType("999999"); } } Map pmap = new HashMap<>(); for (PaperCetVo v : papers) { pmap.put(v.getId(), v); } student.setAnswer(getCetAnswer(structs, pages, student.getSubjectCode())); AnswerCardEntity card = getCard(cardMap, student.getExamId(), student.getCardNumber()); Set sliceSet = new LinkedHashSet<>(); setCardStatus(student, card, pages, pmap); int index = 0; for (PaperPageCetVo p : pages) { if (CollectionUtils.isNotEmpty(p.getSlicePath())) { for (int i = 0; i < p.getSlicePath().size(); i++) { String sliceName = card.getSliceName().get(index); sliceSet.add(sliceName); index++; } } } // 获取图片大小 List sliceImageInfo = new ArrayList(); student.setSliceImageInfo(sliceImageInfo); for (String sliceName : sliceSet) { String mirrorSlicePath = toolExportService.getCetSliceUri(student.getExamId(), student.getExamNumber(), sliceName); File targetSliceFile = new File(imageTransferDir + "/" + mirrorSlicePath); sliceImageInfo.add(sliceName + "-" + targetSliceFile.length()); } } private Map> ofPage(List list) { Map> map = new HashMap<>(); for (PaperPageCetVo p : list) { List tem = map.get(p.getStudentId()); if (tem == null) { tem = new ArrayList<>(); map.put(p.getStudentId(), tem); } tem.add(p); } return map; } private Map> ofPaper(List list) { Map> map = new HashMap<>(); for (PaperCetVo p : list) { List tem = map.get(p.getStudentId()); if (tem == null) { tem = new ArrayList<>(); map.put(p.getStudentId(), tem); } tem.add(p); } return map; } private AnswerCardEntity getCard(Map cardMap, Long examId, Integer cardNumber) { AnswerCardEntity card = cardMap.get(cardNumber); if (card == null) { card = answerCardService.findByExamAndNumber(examId, cardNumber); cardMap.put(cardNumber, card); } return card; } private void setCardStatus(ExportCetVo student, AnswerCardEntity card, List pages, Map pmap) { int subject = Integer.valueOf(student.getSubjectCode()); if (subject > 2) { setCardStatusSmall(student, card, pages, pmap); } else { setCardStatusCet(student, card, pages, pmap); } } private void setCardStatusSmall(ExportCetVo student, AnswerCardEntity card, List pages, Map pmap) { PaperPageCetVo p = pages.get(0); if (ExamStatus.ABSENT.equals(student.getExamStatus())) { if (pmap.get(p.getPaperId()).getQuestionFilled()) { student.setCardFirst(1); } else { student.setCardFirst(0); } } else { student.setCardFirst(0); } student.setCardSecond(0); } private void setCardStatusCet(ExportCetVo student, AnswerCardEntity card, List pages, Map pmap) { if (card.getPaperCount() == 1) { PaperPageCetVo p = pages.get(0); if (ExamStatus.ABSENT.equals(student.getExamStatus())) { if (pmap.get(p.getPaperId()).getQuestionFilled()) { student.setCardFirst(1); } else if (isPaperTypeValid(p.getPaperType())) { student.setCardFirst(7); } else if (isPaperTypeEmpty(p.getPaperType())) { student.setCardFirst(0); } else { student.setCardFirst(7); } } else { if (isPaperTypeValid(p.getPaperType())) { student.setCardFirst(0); } else { student.setCardFirst(7); } } student.setCardSecond(0); } else { PaperPageCetVo fp = pages.get(0); PaperPageCetVo sp; if (card.getSinglePage()) { sp = pages.get(1); } else { sp = pages.get(2); } if (ExamStatus.ABSENT.equals(student.getExamStatus())) { if (pmap.get(fp.getPaperId()).getQuestionFilled()) { student.setCardFirst(1); } else if (isPaperTypeValid(fp.getPaperType())) { student.setCardFirst(7); } else if (isPaperTypeEmpty(fp.getPaperType())) { student.setCardFirst(0); } else { student.setCardFirst(7); } } else { if (isPaperTypeValid(fp.getPaperType())) { student.setCardFirst(0); } else { student.setCardFirst(7); } } if (ExamStatus.ABSENT.equals(student.getExamStatus())) { if (pmap.get(sp.getPaperId()).getQuestionFilled()) { student.setCardSecond(1); } else if (isPaperTypeValid(fp.getPaperType())) { student.setCardSecond(7); } else if (isPaperTypeEmpty(fp.getPaperType())) { student.setCardSecond(0); } else { student.setCardSecond(7); } } else { if (isPaperTypeValid(fp.getPaperType())) { student.setCardSecond(0); } else { student.setCardSecond(7); } } } } private boolean isPaperTypeEmpty(StringResult sr) { if (sr == null) { return true; } if (StringUtils.isBlank(sr.getResult())) { return true; } if ("#".equals(sr.getResult())) { return true; } return false; } private boolean isPaperTypeValid(StringResult sr) { if (sr == null) { return false; } if (StringUtils.isBlank(sr.getResult())) { return false; } if ("#".equals(sr.getResult()) || "?".equals(sr.getResult())) { return false; } return true; } private String getCetAnswer(Map> structs, List pages, String subjectCode) { List answers = new ArrayList(); List struct = structs.get(subjectCode); if (struct == null) { struct = questionService.findBySubjectCode(subjectCode); if (struct == null) { throw new ParameterException("科目:" + subjectCode + " 未上传试卷结构"); } structs.put(subjectCode, struct); } for (PaperPageCetVo page : pages) { disposeQuestionMark(page.getQuestion()); try { if (page.getQuestion() != null && CollectionUtils.isNotEmpty(page.getQuestion().getResult())) { answers.addAll(page.getQuestion().getResult()); } } catch (Exception e) { throw e; } } for (int i = 0; i < answers.size(); i++) { if ("#".equals(answers.get(i))) { answers.set(i, "."); } if (answers.get(i).length() > 1) { answers.set(i, ">"); } } int subject = Integer.valueOf(subjectCode); if (subject < 3) {// CET4 CET6 return StringUtils.join(answers, ""); } else {// 小语种 List tem = new ArrayList(); int index = 0; for (QuestionEntity s : struct) { if (s.getObjective()) { if (index >= answers.size()) { throw new ParameterException("科目:" + subjectCode + " 试卷结构和题卡客观题数量不一致"); } tem.add(answers.get(index)); index++; } else { tem.add("."); } } return StringUtils.join(tem, ""); } } @Transactional @Override public void updateCheckMark(Long studentId, Boolean tag) { LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); updateWrapper.set(StudentEntity::getCheckMark, tag); updateWrapper.eq(StudentEntity::getId, studentId); this.update(updateWrapper); } @Transactional @Override public void pictureCopy(StudentUploadVo vo) { concurrentService.getReadWriteLock(LockType.STUDENT + "-" + vo.getId()).writeLock().lock(); StudentEntity se = this.getById(vo.getId()); try { if (UploadStatus.WAITING_UPLOAD.equals(se.getFileUploadStatus())) { toolExportService.studentFileCopy(se.getId(), vo.getMode()); this.updateFileUploadStatus(se.getId(), UploadStatus.UPLOADED); } } catch (Exception e) { this.updateFileUploadStatus(se.getId(), UploadStatus.ERROR); log.error("转存文件出错.studentId:" + se.getId(), e); } finally { concurrentService.getReadWriteLock(LockType.STUDENT + "-" + vo.getId()).writeLock().unlock(); } } @Override @Transactional public void resetExamStatus(ExamStatusResetTaskVo vo) { Long examId = vo.getExamId(); Integer examNumberFillCount = vo.getExamNumberFillCount(); QueryWrapper wrapper = new QueryWrapper<>(); LambdaQueryWrapper lw = wrapper.lambda(); lw.eq(StudentEntity::getExamId, examId); List list = this.list(wrapper); for (StudentEntity student : list) { concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().lock(); try { List studentPaperList = studentPaperService.findByStudentId(student.getId()); int omrExamNumberCount = 0; for (StudentPaperEntity studentPaper : studentPaperList) { PaperEntity paper = paperService.getById(studentPaper.getPaperId()); int paperExamNumberCount = paper.getOmrExamNumber().replace("#", "").length(); if (omrExamNumberCount < paperExamNumberCount) { omrExamNumberCount = paperExamNumberCount; } } resetExamStatus(student, omrExamNumberCount, examNumberFillCount); saveOrUpdate(student); } finally { concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().unlock(); } vo.setProgressCount(vo.getProgressCount() + 1); } examService.updateExamNumberFillCount(examId, examNumberFillCount); } private void resetExamStatus(StudentEntity student, Integer omrExamNumberCount, Integer examNumberFillCount) { if (ScanStatus.UNEXIST.equals(student.getStatus())) { student.setExamStatus(null); } else { // 客观题有作答,不缺考 if (student.getQuestionFilled()) { student.setExamStatus(ExamStatus.OK); } else { if (student.getSubjectiveFilled()) { // 客观题未作答,主观题有作答,待确认1 student.setExamStatus(ExamStatus.UNCHECK1); } else { // 客观题未作答,主观题未作答,填涂大于10位 if (omrExamNumberCount >= examNumberFillCount) { if (!"#".equals(student.getPaperType())) { // 客观题未作答,主观题未作答,填涂大于10位,有卷型,待校验2 student.setExamStatus(ExamStatus.UNCHECK2); } else { // 客观题未作答,主观题未作答,填涂大于10位,无卷型,缺考 student.setExamStatus(ExamStatus.ABSENT); } } else { // 客观题未作答,主观题未作答,填涂小于10位,缺考 student.setExamStatus(ExamStatus.ABSENT); } } } } } @Override @Transactional public void updateExamStatus(Long id, ExamStatus examStatus) { LambdaUpdateWrapper lw = new LambdaUpdateWrapper<>(); lw.set(StudentEntity::getExamStatus, examStatus); lw.eq(StudentEntity::getId, id); this.update(lw); } @Override public void importExamStatus(ExamStatusImportTaskVo vo) { Map examNumbers = new HashMap<>(); Map absentMap = new HashMap<>(); InputStream in = null; try { in = new FileInputStream(vo.getFile()); examStatusImportCheck(vo, in, examNumbers, absentMap); } catch (ParameterException e) { vo.setErrMsg(e.getMessage()); vo.setStatus(AsyncTaskStatus.FAILED); throw e; } catch (Exception e) { vo.setErrMsg("系统错误"); vo.setStatus(AsyncTaskStatus.FAILED); throw new ParameterException("系统错误", e); } finally { if (in != null) { try { in.close(); } catch (IOException e) { } } } if (ExamStatusCheckMode.OVERRIDE.equals(vo.getMode())) { for (StudentEntity student : examNumbers.values()) { concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().lock(); try { if (absentMap.get(student.getExamNumber())) { student.setExamStatus(ExamStatus.ABSENT); } else { student.setExamStatus(ExamStatus.OK); } saveOrUpdate(student); vo.setProgressCount(vo.getProgressCount() + 1); } finally { concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().unlock(); } } } if (ExamStatusCheckMode.COMPARE.equals(vo.getMode())) { for (StudentEntity student : examNumbers.values()) { concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().lock(); try { if (absentMap.get(student.getExamNumber()) && !ExamStatus.ABSENT.equals(student.getExamStatus())) { student.setExamStatus(ExamStatus.UNCHECK3); } if (!absentMap.get(student.getExamNumber()) && !ExamStatus.OK.equals(student.getExamStatus())) { student.setExamStatus(ExamStatus.UNCHECK3); } saveOrUpdate(student); vo.setProgressCount(vo.getProgressCount() + 1); } finally { concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().unlock(); } } } } private void examStatusImportCheck(ExamStatusImportTaskVo vo, InputStream in, Map examNumbers, Map absentMap) { List lineList = null; try { lineList = IOUtils.readLines(in, "UTF-8"); } catch (IOException e) { throw new ParameterException("读取文件出错", e); } for (int i = 1; i < lineList.size(); i++) { String line = lineList.get(i); if (StringUtils.isBlank(line)) { continue; } // 已读字符串长度 StringBuilder msg = new StringBuilder(); String[] str = line.split(","); if (str.length != 3) { msg.append(" 无法解析,请检查分隔符和数据"); throw new ParameterException(newError(i + 1, msg.toString())); } String examNumber = str[0]; String absent = str[1]; String subjectCode = str[2]; if (StringUtils.isBlank(subjectCode) || !vo.getSubjectCode().equals(subjectCode)) { msg.append(" 科目代码不正确"); } if (StringUtils.isBlank(examNumber)) { examNumber = null; msg.append(" 准考证号不能为空"); } else if (examNumber.length() < 15) { examNumber = null; msg.append(" 准考证号不能小于15位"); } if (StringUtils.isBlank(absent)) { msg.append(" 缺考标识不能为空"); } else if (!absent.equals("0") && !absent.equals("1")) { msg.append(" 缺考标识只能为0或1"); } if (examNumber != null) { if (examNumbers.containsKey(examNumber)) { msg.append(" 准考证号有重复"); } else { StudentEntity student = this.findByExamAndSubjectCodeAndExamNumber(vo.getExamId(), subjectCode, examNumber); if (student == null) { msg.append(" 准考证号不存在"); } else { examNumbers.put(examNumber, student); absentMap.put(examNumber, absent.equals("1")); } } } if (msg.length() > 0) { throw new ParameterException(newError(i + 1, msg.toString())); } } } private String newError(int lineNum, String msg) { return "第" + lineNum + "行 " + msg; } @Override @Transactional public void updateAssignedCheckCount(Long id, boolean deleteHistory) { if (deleteHistory) { assignedCheckHistoryService.deleteByStudentId(id); } this.baseMapper.updateAssignedCheckCount(id); } @Override public int getCountByExamAndAssignedCheckCount(Long examId, String subjectCode, int assignedCheckCount, OP op) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(StudentEntity::getExamId, examId); if (subjectCode != null) { wrapper.eq(StudentEntity::getSubjectCode, subjectCode); } wrapper.eq(StudentEntity::getAssigned, true); if (OP.EQ == op) { wrapper.eq(StudentEntity::getAssignedCheckCount, assignedCheckCount); } else if (OP.GT == op) { wrapper.gt(StudentEntity::getAssignedCheckCount, assignedCheckCount); } else if (OP.GE == op) { wrapper.ge(StudentEntity::getAssignedCheckCount, assignedCheckCount); } else if (OP.LE == op) { wrapper.le(StudentEntity::getAssignedCheckCount, assignedCheckCount); } else if (OP.LT == op) { wrapper.lt(StudentEntity::getAssignedCheckCount, assignedCheckCount); } return this.count(wrapper); } @Override public int countByExamIdAndExamStatus(Long examId, ExamStatus... examStatus) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(StudentEntity::getExamId, examId); wrapper.in(StudentEntity::getExamStatus, Arrays.asList(examStatus)); return this.count(wrapper); } @Override public List exportAssignedCheckPage(AssignedQueryDomain query) { List ret = this.baseMapper.exportAssignedCheckPage( new Page(query.getPageNumber(), query.getPageSize()), query); return ret; } @Override public PageResult queryAssignedCheckPage(AssignedQueryDomain query) { // 查询考生分页信息 IPage iPage = baseMapper .queryAssignedCheckPage(new Page<>(query.getPageNumber(), query.getPageSize()), query); if (CollectionUtils.isNotEmpty(iPage.getRecords()) && query.getWithPaper()) { Map map = new HashMap<>(); for (AnswerQueryVo vo : iPage.getRecords()) { List papers = new ArrayList<>(); vo.setPapers(papers); if (vo.getAuditorId() != null) { UserEntity au = userService.getById(vo.getAuditorId()); vo.setAuditorName(au.getLoginName()); } // 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 studentIds = iPage.getRecords().stream().map(p -> p.getId()).collect(Collectors.toList()); List paperList = new BatchGetDataUtil() { @Override public List getData(List paramList) { return paperService.listByStudentIds(paramList); } }.getDataForBatch(studentIds, 20); if (CollectionUtils.isNotEmpty(paperList)) { Map paperMap = new HashMap<>(); for (StudentPaperVo p : paperList) { AnswerQueryVo vo = map.get(p.getStudentId()); if (vo == null) { continue; } List papers = vo.getPapers(); if (papers == null) { continue; } // if (papers.size() < p.getNumber()) { // continue; // } if (!p.getAssigned()) { continue; } // AnswerPaperVo pvo = papers.get(p.getNumber() - 1); AnswerPaperVo pvo = new AnswerPaperVo(); pvo.setId(p.getPaperId()); pvo.setNumber(p.getNumber()); pvo.setAssigned(p.getAssigned()); // pvo.setAssignedSuspect(p.getAssignedSuspect()); papers.add(pvo); paperMap.put(p.getPaperId(), pvo); } // 查找page List paperIds = paperList.stream().map(p -> p.getPaperId()).collect(Collectors.toList()); List paperPageList = new BatchGetDataUtil() { @Override public List getData(List paramList) { return paperPageService.listByPaperList(paramList); } }.getDataForBatch(paperIds, 20); if (CollectionUtils.isNotEmpty(paperPageList)) { for (PaperPageEntity p : paperPageList) { AnswerPaperVo pvo = paperMap.get(p.getPaperId()); if (pvo == null) { continue; } List pages = pvo.getPages(); if (pages == null) { pages = new ArrayList<>(); pvo.setPages(pages); } AnswerPageVo pageVo = new AnswerPageVo(); pageVo.setIndex(p.getPageIndex()); pageVo.setSheetUri(p.getSheetPath()); pageVo.setSliceUri(p.getSlicePath()); pages.add(pageVo); } } } } else { for (AnswerQueryVo vo : iPage.getRecords()) { if (vo.getAuditorId() != null) { UserEntity au = userService.getById(vo.getAuditorId()); vo.setAuditorName(au.getLoginName()); } } } return PageUtil.of(iPage); } @Override public boolean apply(StudentEntity t, String account) { TaskLock taskLock = TaskLockUtil.getAssignedCheckTask(t.getExamId() + "_" + t.getSubjectCode()); boolean lock = taskLock.add(t.getId(), account); // 上锁失败直接返回 if (!lock) { return false; } // 重复校验任务状态 if (t.getAssignedCheckCount() == 0 || t.getAssignedCheckCount() == 1) { return true; } else { taskLock.remove(t.getId()); return false; } } @Override public boolean hasAppliedAssignedCheckTask(StudentEntity t, String account) { TaskLock taskLock = TaskLockUtil.getAssignedCheckTask(t.getExamId() + "_" + t.getSubjectCode()); return taskLock.exist(t.getId(), account); } @Override public TaskStatusVo getAssignedCheckTaskStatus(Long examId, String subjectCode, User user) { TaskStatusVo status = new TaskStatusVo(); status.setFinishCount(assignedCheckHistoryService.getCountByUserId(user.getId(), examId, subjectCode)); if (Role.AUDITOR.equals(user.getRole())) { status.setTodoCount(this.getCountByExamAndAssignedCheckCount(examId, subjectCode, 0, OP.EQ)); } else { status.setTodoCount(this.getCountByExamAndAssignedCheckCount(examId, subjectCode, 1, OP.EQ)); } return status; } @Override public void releaseAssignedCheckTaskByUser(Long examId, String subjectCode, String account) { TaskLock taskLock = TaskLockUtil.getAssignedCheckTask(examId + "_" + subjectCode); taskLock.clear(account); } @Override @Transactional public AssignedTaskSaveVo submitAssignedCheckTask(AssginedTaskResult result, User user) { StudentEntity student = getById(result.getId()); if (student == null) { throw new ParameterException("考生信息未找到"); } if (student.getAssignedCheckCount() == 0 && !this.hasAppliedAssignedCheckTask(student, user.getAccount())) { throw new ParameterException("任务非本人领取"); } concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().lock(); try { assignedCheckHistoryService.deleteByStudentIdAndUserRole(student.getId(), user.getRole()); assignedCheckHistoryService.save(user.getId(), student.getId(), student.getExamId()); // for (AssignedTaskResultPaper paper : result.getPapers()) { // paperService.updatePaperAssignedSuspect(student.getId(), // paper.getNumber(), result.getAssignedSuspect()); // } // updateStudentByPaper(user, student.getId(), false); student.setAssignedSuspect(result.getAssignedSuspect()); saveOrUpdate(student); updateAssignedCheckCount(student.getId(), false); } finally { concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().unlock(); } AssignedTaskSaveVo vo = new AssignedTaskSaveVo(); vo.setId(student.getId()); vo.setStatus(this.getAssignedCheckTaskStatus(student.getExamId(), student.getSubjectCode(), user)); return vo; } @Override public PageResult getAssignedCheckTaskHistory(Long examId, String subjectCode, Long pageNumber, Long pageSize, User user) { IPage result = this.baseMapper.getAssignedCheckTaskHistory(new Page<>(pageNumber, pageSize), examId, subjectCode, user.getId()); for (AnswerQueryVo t : result.getRecords()) { t = toTaskVo(t); } return PageUtil.of(result); } @Override public AnswerQueryVo getAssignedCheckTask(Long examId, String subjectCode, User user) { ExamEntity exam = examService.getById(examId); if (exam.getEnableSyncVerify() && Role.AUDITOR.equals(user.getRole())) { throw new ParameterException("已开启实时审核,审核员无法获取任务"); } int retry = 1; AnswerQueryVo task = null; int checkCount = 0; if (Role.AUDITOR.equals(user.getRole())) { checkCount = 0; } else { checkCount = 1; } while (task == null) { IPage list = this.findUnCheck(examId, subjectCode, checkCount, retry, 20); if (list.getRecords().isEmpty()) { break; } for (AnswerQueryVo t : list.getRecords()) { StudentEntity student = this.getById(t.getId()); if (this.apply(student, user.getAccount())) { task = toTaskVo(t); break; } } if (task == null) { retry++; } } if (task == null) { throw NotFoundExceptions.NO_CHECK_ASSIGNED_TASK; } return task; } private IPage findUnCheck(Long examId, String subjectCode, int checkCount, int pageNumber, int pageSize) { return this.baseMapper.findUnCheck(new Page<>(pageNumber, pageSize), examId, subjectCode, checkCount); } private AnswerQueryVo toTaskVo(AnswerQueryVo t) { List papers = new ArrayList<>(); t.setPapers(papers); // if (t.getCardPaperCount() != null) { // for (int i = 1; i <= t.getCardPaperCount(); i++) { // AnswerPaperVo pv = new AnswerPaperVo(); // pv.setNumber(i); // papers.add(pv); // } // } List studentIds = new ArrayList<>(); studentIds.add(t.getId()); List paperList = new BatchGetDataUtil() { @Override public List getData(List paramList) { return paperService.listByStudentIds(paramList); } }.getDataForBatch(studentIds, 20); if (CollectionUtils.isNotEmpty(paperList)) { Map paperMap = new HashMap<>(); for (StudentPaperVo p : paperList) { AnswerQueryVo vo = t; if (vo == null) { continue; } // if (papers.size() < p.getNumber()) { // continue; // } if (!p.getAssigned()) { continue; } AnswerPaperVo pvo = new AnswerPaperVo(); pvo.setId(p.getPaperId()); pvo.setNumber(p.getNumber()); pvo.setAssigned(p.getAssigned()); // pvo.setAssignedSuspect(p.getAssignedSuspect()); papers.add(pvo); paperMap.put(p.getPaperId(), pvo); } // 查找page List paperIds = paperList.stream().map(p -> p.getPaperId()).collect(Collectors.toList()); List paperPageList = new BatchGetDataUtil() { @Override public List getData(List paramList) { return paperPageService.listByPaperList(paramList); } }.getDataForBatch(paperIds, 20); if (CollectionUtils.isNotEmpty(paperPageList)) { for (PaperPageEntity p : paperPageList) { AnswerPaperVo pvo = paperMap.get(p.getPaperId()); if (pvo == null) { continue; } List pages = pvo.getPages(); if (pages == null) { pages = new ArrayList<>(); pvo.setPages(pages); } AnswerPageVo pageVo = new AnswerPageVo(); pageVo.setIndex(p.getPageIndex()); pageVo.setSheetUri(p.getSheetPath()); pageVo.setSliceUri(p.getSlicePath()); pages.add(pageVo); } } } return t; } @Override public StudentAnswerVo studentAnswer(Long batchId, Long studentId) { if (batchId == null) { throw new ParameterException("batchId不能为空"); } if (studentId == null) { throw new ParameterException("studentId不能为空"); } StudentAnswerVo ret = this.baseMapper.getStudentVo(studentId); if (ret == null) { throw new ParameterException("未找到考生信息"); } ret.setPapers(new ArrayList<>()); List paperList = paperService.listByBatchIdAndStudentId(batchId, studentId); if (CollectionUtils.isNotEmpty(paperList)) { Map paperMap = new HashMap<>(); for (StudentPaperVo p : paperList) { AnswerPaperVo pvo = new AnswerPaperVo(); pvo.setId(p.getPaperId()); pvo.setNumber(p.getNumber()); pvo.setAssigned(p.getAssigned()); pvo.setPages(new ArrayList<>()); ret.getPapers().add(pvo); paperMap.put(p.getPaperId(), pvo); } // 查找page List paperIds = paperList.stream().map(p -> p.getPaperId()).collect(Collectors.toList()); List paperPageList = paperPageService.listByPaperList(paperIds); if (CollectionUtils.isNotEmpty(paperPageList)) { for (PaperPageEntity p : paperPageList) { AnswerPaperVo pvo = paperMap.get(p.getPaperId()); if (pvo == null) { continue; } AnswerPageVo pageVo = new AnswerPageVo(); pageVo.setIndex(p.getPageIndex()); pageVo.setSheetUri(p.getSheetPath()); pageVo.setSliceUri(p.getSlicePath()); pageVo.setAbsent(p.getAbsent()); pageVo.setBreach(p.getBreach()); pageVo.setPaperType(p.getPaperType()); pageVo.setQuestion(p.getQuestion()); pageVo.setSelective(p.getSelective()); pageVo.setRecogData(p.getRecogData()); pvo.getPages().add(pageVo); } } } return ret; } @Override public List scanProgress(Long examId, String subjectCode) { return this.baseMapper.scanProgress(examId, subjectCode); } @Override public PageResult studentPage(StudentPageQuery query) { // 查询考生分页信息 IPage iPage = baseMapper.studentPage(new Page<>(query.getPageNumber(), query.getPageSize()), query); if (CollectionUtils.isNotEmpty(iPage.getRecords())) { for (StudentPageVo vo : iPage.getRecords()) { if (ScanStatus.SCANNED.equals(vo.getStatus())) { vo.setScanned("已扫描"); } else { vo.setScanned("未扫描"); } } } return PageUtil.of(iPage); } @Override public List studentList(StudentPageQuery query) { return studentPage(query).getResult(); } @Override public List studentExportList(AnswerQueryDomain query) { return baseMapper.studentExport(new Page<>(query.getPageNumber(), query.getPageSize()), query).getRecords(); } @Override public List studentExamRoomExportList(AnswerQueryDomain query) { return baseMapper.studentExamRoomExport(new Page<>(query.getPageNumber(), query.getPageSize()), query) .getRecords(); } @Override public TaskIdVo breachImport(Long examId, String subjectCode, MultipartFile file) { if (!file.getOriginalFilename().toLowerCase().endsWith(".txt")) { throw new ParameterException("只能是txt文件"); } String taskId = FastUUID.get(); // 暂存临时文件 File temDir = new File("temp/" + taskId + "/"); temDir.mkdirs(); File txt = new File(temDir.getAbsolutePath() + "/breach.txt"); try { file.transferTo(txt); List list = FileUtils.readLines(txt, "utf-8"); if (CollectionUtils.isEmpty(list) || list.size() <= 1) { throw new ParameterException("文件内容为空"); } BreachAndStatusImportTaskVo vo = new BreachAndStatusImportTaskVo(); vo.setTaskId(taskId); vo.setTotalCount(list.size() - 1); vo.setExamId(examId); vo.setSubjectCode(subjectCode); vo.setStatus(AsyncTaskStatus.RUNNING); vo.setProgress(0.0); vo.setTempDir(temDir); vo.setFile(txt); BreachImportConsumer com = SpringContextHolder.getBean(BreachImportConsumer.class); com.setVo(vo); exec.execute(com); asyncTaskService.addTask(vo); return TaskIdVo.create(vo.getTaskId()); } catch (ParameterException e) { throw e; } catch (Exception e) { throw new RuntimeException("系统错误", e); } } @Override public void breachImportDispose(BreachAndStatusImportTaskVo vo) { InputStream in = null; try { in = new FileInputStream(vo.getFile()); breachImportCheck(vo, in); } catch (ParameterException e) { vo.setErrMsg(e.getMessage()); vo.setStatus(AsyncTaskStatus.FAILED); throw e; } catch (Exception e) { vo.setErrMsg("系统错误"); vo.setStatus(AsyncTaskStatus.FAILED); throw new ParameterException("系统错误", e); } finally { if (in != null) { try { in.close(); } catch (IOException e) { } } } // 根据校验结果上传文件 InputStream excelIn = null; try { String md5 = MD5Util.md5Hex(vo.getFile()); excelIn = new FileInputStream(vo.getFile()); fileService.uploadBreach(excelIn, md5, vo.getExamId(), vo.getSubjectCode()); } catch (IOException e) { vo.setErrMsg("系统错误"); vo.setStatus(AsyncTaskStatus.FAILED); throw new ParameterException("系统错误", e); } finally { if (excelIn != null) { try { excelIn.close(); } catch (IOException e) { } } } File info = new File(vo.getTempDir().getAbsolutePath() + "/breach-info.txt"); InputStream infoIn = null; try { FileUtils.write(info, vo.getProgressCount() + "", "utf-8"); String md5 = MD5Util.md5Hex(info); infoIn = new FileInputStream(info); fileService.uploadBreachInfo(infoIn, md5, vo.getExamId(), vo.getSubjectCode()); } catch (IOException e) { vo.setErrMsg("系统错误"); vo.setStatus(AsyncTaskStatus.FAILED); throw new ParameterException("系统错误", e); } finally { if (infoIn != null) { try { infoIn.close(); } catch (IOException e) { } } } vo.setTotalCount(vo.getProgressCount()); vo.setStatus(AsyncTaskStatus.SUCCESS); } private void breachImportCheck(BreachAndStatusImportTaskVo vo, InputStream in) { List lineList = null; try { lineList = IOUtils.readLines(in, "UTF-8"); } catch (IOException e) { throw new ParameterException("读取文件出错", e); } Set examNumberSet = new HashSet<>(); for (int i = 1; i < lineList.size(); i++) { String lineString = lineList.get(i); if (StringUtils.isBlank(lineString)) { continue; } StringBuilder msg = new StringBuilder(); String[] line = lineString.split(","); if (line.length != 4) { msg.append(" 格式错误"); } else { String subjectCode = trimAndNullIfBlank(line[0]); if (StringUtils.isBlank(subjectCode)) { throw new ParameterException(errorMsg(i + 1, " 科目代码不能为空")); } String examNumber = trimAndNullIfBlank(line[1]); if (StringUtils.isBlank(examNumber)) { msg.append(" 准考证号不能为空"); } else { StudentEntity s = findByExamAndSubjectCodeAndExamNumber(vo.getExamId(), vo.getSubjectCode(), examNumber); if (s == null) { msg.append(" 准考证号未找到"); } else { if (examNumberSet.contains(examNumber)) { msg.append(" 准考证号重复"); } else { examNumberSet.add(examNumber); } } } String breach = trimAndNullIfBlank(line[3]); if (StringUtils.isBlank(breach)) { msg.append(" 违纪不能为空"); } else { vo.setProgressCount(vo.getProgressCount() + 1); } } if (msg.length() > 0) { throw new ParameterException(errorMsg(i + 1, msg.toString())); } } } private String errorMsg(int lineNum, String msg) { return "第" + lineNum + "行 " + msg; } @Override public TaskIdVo custStatusImport(Long examId, String subjectCode, MultipartFile file) { if (!file.getOriginalFilename().toLowerCase().endsWith(".txt")) { throw new ParameterException("只能是txt文件"); } String taskId = FastUUID.get(); // 暂存临时文件 File temDir = new File("temp/" + taskId + "/"); temDir.mkdirs(); File txt = new File(temDir.getAbsolutePath() + "/cust-status.txt"); try { file.transferTo(txt); List list = FileUtils.readLines(txt, "utf-8"); if (CollectionUtils.isEmpty(list) || list.size() <= 1) { throw new ParameterException("文件内容为空"); } BreachAndStatusImportTaskVo vo = new BreachAndStatusImportTaskVo(); vo.setTaskId(taskId); vo.setTotalCount(list.size() - 1); vo.setExamId(examId); vo.setSubjectCode(subjectCode); vo.setStatus(AsyncTaskStatus.RUNNING); vo.setProgress(0.0); vo.setTempDir(temDir); vo.setFile(txt); CustStatusImportConsumer com = SpringContextHolder.getBean(CustStatusImportConsumer.class); com.setVo(vo); exec.execute(com); asyncTaskService.addTask(vo); return TaskIdVo.create(vo.getTaskId()); } catch (ParameterException e) { throw e; } catch (Exception e) { throw new RuntimeException("系统错误", e); } } @Override public void custStatusImportDispose(BreachAndStatusImportTaskVo vo) { InputStream in = null; try { in = new FileInputStream(vo.getFile()); custStatusImportCheck(vo, in); } catch (ParameterException e) { vo.setErrMsg(e.getMessage()); vo.setStatus(AsyncTaskStatus.FAILED); throw e; } catch (Exception e) { vo.setErrMsg("系统错误"); vo.setStatus(AsyncTaskStatus.FAILED); throw new ParameterException("系统错误", e); } finally { if (in != null) { try { in.close(); } catch (IOException e) { } } } // 根据校验结果上传文件 InputStream excelIn = null; try { String md5 = MD5Util.md5Hex(vo.getFile()); excelIn = new FileInputStream(vo.getFile()); fileService.uploadCustStatus(excelIn, md5, vo.getExamId(), vo.getSubjectCode()); } catch (IOException e) { vo.setErrMsg("系统错误"); vo.setStatus(AsyncTaskStatus.FAILED); throw new ParameterException("系统错误", e); } finally { if (excelIn != null) { try { excelIn.close(); } catch (IOException e) { } } } File info = new File(vo.getTempDir().getAbsolutePath() + "/cust-status-info.txt"); InputStream infoIn = null; try { FileUtils.write(info, vo.getProgressCount() + "", "utf-8"); String md5 = MD5Util.md5Hex(info); infoIn = new FileInputStream(info); fileService.uploadCustStatusInfo(infoIn, md5, vo.getExamId(), vo.getSubjectCode()); } catch (IOException e) { vo.setErrMsg("系统错误"); vo.setStatus(AsyncTaskStatus.FAILED); throw new ParameterException("系统错误", e); } finally { if (infoIn != null) { try { infoIn.close(); } catch (IOException e) { } } } vo.setTotalCount(vo.getProgressCount()); vo.setStatus(AsyncTaskStatus.SUCCESS); } private void custStatusImportCheck(BreachAndStatusImportTaskVo vo, InputStream in) { List lineList = null; try { lineList = IOUtils.readLines(in, "UTF-8"); } catch (IOException e) { throw new ParameterException("读取文件出错", e); } Set examNumberSet = new HashSet<>(); for (int i = 1; i < lineList.size(); i++) { String lineString = lineList.get(i); if (StringUtils.isBlank(lineString)) { continue; } StringBuilder msg = new StringBuilder(); String[] line = lineString.split(","); if (line.length != 4) { msg.append(" 格式错误"); } else { String subjectCode = trimAndNullIfBlank(line[0]); if (StringUtils.isBlank(subjectCode)) { throw new ParameterException(errorMsg(i + 1, " 科目代码不能为空")); } String examNumber = trimAndNullIfBlank(line[1]); if (StringUtils.isBlank(examNumber)) { msg.append(" 准考证号不能为空"); } else { StudentEntity s = findByExamAndSubjectCodeAndExamNumber(vo.getExamId(), vo.getSubjectCode(), examNumber); if (s == null) { msg.append(" 准考证号未找到"); } else { if (examNumberSet.contains(examNumber)) { msg.append(" 准考证号重复"); } else { examNumberSet.add(examNumber); } } } String breach = trimAndNullIfBlank(line[3]); if (StringUtils.isBlank(breach)) { msg.append(" 考生状态不能为空"); } else { vo.setProgressCount(vo.getProgressCount() + 1); } } if (msg.length() > 0) { throw new ParameterException(errorMsg(i + 1, msg.toString())); } } } @Override public List countStudent(Long examId) { if (examId == null) { throw new ParameterException("examId不能为空"); } return baseMapper.countStudent(examId); } @Override public List exportAssignedCheck(Long examId, String subjectCode) { return baseMapper.exportAssignedCheck(examId, subjectCode); } @Override public void resetAssignedCheck(Long examId, String subjectCode) { TaskLock taskLock = TaskLockUtil.getAssignedCheckTask(examId + "_" + subjectCode); taskLock.clear(); QueryWrapper wrapper = new QueryWrapper<>(); LambdaQueryWrapper lw = wrapper.lambda(); lw.eq(StudentEntity::getExamId, examId); lw.eq(StudentEntity::getSubjectCode, subjectCode); lw.eq(StudentEntity::getAssigned, true); lw.gt(StudentEntity::getAssignedCheckCount, 1); List list = this.list(wrapper); for (StudentEntity student : list) { concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().lock(); try { student.setAbsentSuspect(false); student.setAssignedCheckCount(1); saveOrUpdate(student); assignedCheckHistoryService.deleteByStudentIdAndUserRole(student.getId(), Role.SCHOOL_ADMIN); } finally { concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().unlock(); } } } @Transactional @Override public void updateImageCheckStatus(Long studentId, ImageCheckStatus status) { LambdaUpdateWrapper lw = new LambdaUpdateWrapper<>(); lw.set(StudentEntity::getImageCheckStatus, status); lw.eq(StudentEntity::getId, studentId); update(lw); } // @Transactional // @Override // public void resetFileAndImageCheckStatus(Long examId, String subjectCode, // String examNumber) { // LambdaUpdateWrapper lw = new LambdaUpdateWrapper<>(); // lw.set(StudentEntity::getImageCheckStatus, ImageCheckStatus.WAITING); // lw.set(StudentEntity::getFileUploadStatus, UploadStatus.WAITING_UPLOAD); // lw.eq(StudentEntity::getExamId, examId); // lw.eq(StudentEntity::getSubjectCode, subjectCode); // lw.eq(StudentEntity::getExamNumber, examNumber); // update(lw); // } @Override public boolean existUncheck(Long examId, String subjectCode) { List st = new ArrayList<>(); st.add(ExamStatus.UNCHECK1); st.add(ExamStatus.UNCHECK2); st.add(ExamStatus.UNCHECK3); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(StudentEntity::getExamId, examId); wrapper.eq(StudentEntity::getSubjectCode, subjectCode); wrapper.in(StudentEntity::getExamStatus, st); wrapper.last("LIMIT 1"); return this.getOne(wrapper) != null; } }