xiaofei vor 11 Monaten
Ursprung
Commit
3e4e5f365a
22 geänderte Dateien mit 393 neuen und 67 gelöschten Zeilen
  1. 1 2
      paper-library-business/src/main/java/com/qmth/paper/library/business/service/ClientService.java
  2. 2 1
      paper-library-business/src/main/java/com/qmth/paper/library/business/service/PaperScanTaskService.java
  3. 8 4
      paper-library-business/src/main/java/com/qmth/paper/library/business/service/impl/ClientServiceImpl.java
  4. 4 2
      paper-library-business/src/main/java/com/qmth/paper/library/business/service/impl/ExamStudentServiceImpl.java
  5. 3 4
      paper-library-business/src/main/java/com/qmth/paper/library/business/service/impl/PaperScanTaskServiceImpl.java
  6. 1 1
      paper-library-business/src/main/java/com/qmth/paper/library/business/templete/execute/AsyncExamStudentImportService.java
  7. 36 40
      paper-library-business/src/main/java/com/qmth/paper/library/business/templete/service/impl/TaskLogicServiceImpl.java
  8. 0 0
      paper-library-business/src/main/resources/mapper/BasicBatchNumberService.xml
  9. 4 0
      paper-library-common/pom.xml
  10. 12 0
      paper-library-common/src/main/java/com/qmth/paper/library/common/bean/result/LoginResult.java
  11. 106 0
      paper-library-common/src/main/java/com/qmth/paper/library/common/entity/BasicBatchNumber.java
  12. 6 0
      paper-library-common/src/main/java/com/qmth/paper/library/common/enums/AlphabetEnum.java
  13. 1 0
      paper-library-common/src/main/java/com/qmth/paper/library/common/lock/LockType.java
  14. 17 0
      paper-library-common/src/main/java/com/qmth/paper/library/common/mapper/BasicBatchNumberMapper.java
  15. 25 0
      paper-library-common/src/main/java/com/qmth/paper/library/common/service/BasicBatchNumberService.java
  16. 118 0
      paper-library-common/src/main/java/com/qmth/paper/library/common/service/impl/BasicBatchNumberServiceImpl.java
  17. 1 1
      paper-library-common/src/main/java/com/qmth/paper/library/common/service/impl/BasicFieldServiceImpl.java
  18. 5 5
      paper-library-common/src/main/java/com/qmth/paper/library/common/service/impl/TBTaskServiceImpl.java
  19. 13 0
      paper-library-common/src/main/resources/mapper/BasicBatchNumberMapper.xml
  20. 2 2
      paper-library-common/src/main/resources/mapper/TBTaskMapper.xml
  21. 15 2
      paper-library/src/main/java/com/qmth/paper/library/api/ClientController.java
  22. 13 3
      paper-library/src/main/resources/db-log/xf.sql

+ 1 - 2
paper-library-business/src/main/java/com/qmth/paper/library/business/service/ClientService.java

@@ -1,7 +1,6 @@
 package com.qmth.paper.library.business.service;
 
 import com.qmth.paper.library.business.entity.PaperScanTask;
-import io.swagger.models.auth.In;
 import org.springframework.web.multipart.MultipartFile;
 
 /**
@@ -15,7 +14,7 @@ public interface ClientService {
 
     void checkPrivilege(Long userId);
 
-    boolean pictureUpload(Long paperScanTaskId, String studentCode, Integer x, Integer y, Integer width, Integer height, Integer rotate, MultipartFile frontFile, String frontMd5, MultipartFile versoFile, String versoMd5);
+    boolean pictureUpload(Long paperScanTaskId, String studentCode, Integer x, Integer y, Integer width, Integer height, Integer rotate, MultipartFile frontFile, String frontMd5, MultipartFile versoFile, String versoMd5, Long scanUserId, String batchNo);
 
     boolean otherUpload(Long paperScanTaskId, MultipartFile frontFile, String frontMd5, MultipartFile versoFile, String versoMd5);
 }

+ 2 - 1
paper-library-business/src/main/java/com/qmth/paper/library/business/service/PaperScanTaskService.java

@@ -6,6 +6,7 @@ import com.qmth.paper.library.business.bean.result.PaperScanTaskDetailResult;
 import com.qmth.paper.library.business.bean.result.PaperScanTaskResult;
 import com.qmth.paper.library.business.entity.PaperScanTask;
 import com.qmth.paper.library.common.entity.ExamStudent;
+import com.qmth.paper.library.common.entity.TBTask;
 import com.qmth.paper.library.common.enums.RecognitionTypeEnum;
 import com.qmth.paper.library.common.enums.StoreTypeEnum;
 
@@ -39,7 +40,7 @@ public interface PaperScanTaskService extends IService<PaperScanTask> {
 
     void updateStudentCount(PaperScanTask paperScanTask);
 
-    void updatePaperScanTask(Long examId, RecognitionTypeEnum recognitionType, StoreTypeEnum storeType, List<ExamStudent> examStudentList, Long createId);
+    void updatePaperScanTask(Long examId, RecognitionTypeEnum recognitionType, StoreTypeEnum storeType, List<ExamStudent> examStudentList, TBTask tbTask);
 
     List<PaperScanTask> listByExamId(Long examId);
 }

+ 8 - 4
paper-library-business/src/main/java/com/qmth/paper/library/business/service/impl/ClientServiceImpl.java

@@ -15,6 +15,7 @@ import com.qmth.paper.library.common.entity.SysPrivilege;
 import com.qmth.paper.library.common.enums.ExceptionResultEnum;
 import com.qmth.paper.library.common.enums.StoreTypeEnum;
 import com.qmth.paper.library.common.enums.UploadFileEnum;
+import com.qmth.paper.library.common.service.BasicBatchNumberService;
 import com.qmth.paper.library.common.service.CommonCacheService;
 import com.qmth.paper.library.common.service.SysPrivilegeService;
 import com.qmth.paper.library.common.util.ServletUtil;
@@ -52,7 +53,7 @@ public class ClientServiceImpl implements ClientService {
     @Resource
     private BasicExamService basicExamService;
     @Resource
-    private CommonCacheService commonCacheService;
+    private BasicBatchNumberService basicBatchNumberService;
 
     @Override
     public PaperScanTask pageScanTask(Long examId, String courseCode) {
@@ -74,8 +75,7 @@ public class ClientServiceImpl implements ClientService {
 
     @Transactional
     @Override
-    public boolean pictureUpload(Long paperScanTaskId, String studentCode, Integer x, Integer y, Integer width, Integer height, Integer rotate, MultipartFile frontFile, String frontMd5, MultipartFile versoFile, String versoMd5) {
-        Long userId = Long.valueOf(ServletUtil.getRequestHeaderUserId().toString());
+    public boolean pictureUpload(Long paperScanTaskId, String studentCode, Integer x, Integer y, Integer width, Integer height, Integer rotate, MultipartFile frontFile, String frontMd5, MultipartFile versoFile, String versoMd5, Long scanUserId, String batchNo) {
         Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
 
         if (Objects.isNull(frontFile) || frontFile.getSize() == 0) {
@@ -105,7 +105,8 @@ public class ClientServiceImpl implements ClientService {
             PaperLibrary paperLibrary = new PaperLibrary();
             paperLibrary.setId(SystemConstant.getDbUuid());
             paperLibrary.setPaperScanTaskId(paperScanTaskId);
-            paperLibrary.setCreateId(userId);
+            paperLibrary.setBatchNo(batchNo); // 提交批次号
+            paperLibrary.setCreateId(scanUserId);
             paperLibrary.setCreateTime(System.currentTimeMillis());
             // 校验是否存在,不存在创建考生并绑定上
             ExamStudent examStudent = examStudentService.getByExamIdAndCourseCodeAndStudentCode(paperScanTask.getExamId(), paperScanTask.getCourseCode(), recognitionVo.getBindResult());
@@ -145,6 +146,9 @@ public class ClientServiceImpl implements ClientService {
                 paperScanTaskService.update(updateWrapper);
 
                 examStudentService.updateBindCount(examStudent.getId());
+
+                // 更新批次号
+                basicBatchNumberService.updateBatchNo(paperScanTask.getExamId(), scanUserId, batchNo);
             }
             return true;
 

+ 4 - 2
paper-library-business/src/main/java/com/qmth/paper/library/business/service/impl/ExamStudentServiceImpl.java

@@ -1,5 +1,6 @@
 package com.qmth.paper.library.business.service.impl;
 
+import cn.hutool.core.collection.ArrayIter;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -265,10 +266,11 @@ public class ExamStudentServiceImpl extends ServiceImpl<ExamStudentMapper, ExamS
             response.setContentType("application/vnd.ms-excel");
             ServletOutputStream outputStream = response.getOutputStream();
             ExcelWriter writer = ExcelWriter.create(ExcelType.XLSX);
-            writer.writeDataArrays(sheetName, null, columnNameList.toArray(new String[columnNameList.size()]), null);
+            List<String[]> columnValues = new ArrayList<>();
+            writer.writeDataArrays(sheetName, null, columnNameList.toArray(new String[columnNameList.size()]), columnValues.listIterator());
 
             // 必填字段
-            List<String> requireFields = Arrays.asList(new String[]{BasicFieldEnum.STUDENT_CODE.getName(), BasicFieldEnum.STUDENT_NAME.getName(), BasicFieldEnum.COURSE_CODE.getName(), BasicFieldEnum.CLASS_NAME.getName()});
+            List<String> requireFields = Arrays.asList(new String[]{BasicFieldEnum.STUDENT_CODE.getName(), BasicFieldEnum.STUDENT_NAME.getName(), BasicFieldEnum.COURSE_CODE.getName(), BasicFieldEnum.COURSE_NAME.getName()});
 
             List<Integer> columnNameIndexList = new ArrayList<>();
             List<Integer> columnNameRequireIndexList = new ArrayList<>();

+ 3 - 4
paper-library-business/src/main/java/com/qmth/paper/library/business/service/impl/PaperScanTaskServiceImpl.java

@@ -144,7 +144,7 @@ public class PaperScanTaskServiceImpl extends ServiceImpl<PaperScanTaskMapper, P
 
     @Transactional
     @Override
-    public void updatePaperScanTask(Long examId, RecognitionTypeEnum recognitionType, StoreTypeEnum storeType, List<ExamStudent> examStudentList, Long createId) {
+    public void updatePaperScanTask(Long examId, RecognitionTypeEnum recognitionType, StoreTypeEnum storeType, List<ExamStudent> examStudentList, TBTask tbTask) {
         Map<String, String> stringMap = examStudentList.stream().collect(Collectors.toMap(ExamStudent::getCourseCode, ExamStudent::getCourseName, (oldValue, newValue) -> oldValue));
         List<ExamCourse> examCourses = new ArrayList<>();
         for (Map.Entry<String, String> entry : stringMap.entrySet()) {
@@ -152,15 +152,14 @@ public class PaperScanTaskServiceImpl extends ServiceImpl<PaperScanTaskMapper, P
         }
         examCourseService.saveOrUpdateBatchByMultiId(examCourses);
 
-        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
         List<PaperScanTask> paperScanTaskList = new ArrayList<>();
         for (ExamCourse examCourse : examCourses) {
             int studentCount = Math.toIntExact(examStudentList.stream().filter(m -> m.getCourseCode().equals(examCourse.getCourseCode())).count());
             PaperScanTask paperScanTask = this.getByExamIdAndCourseCode(examId, examCourse.getCourseCode());
             if (paperScanTask == null) {
                 String scanTaskName = String.format("%s(%s)", examCourse.getCourseName(), examCourse.getCourseCode());
-                String scanTaskCode = paperLibraryCommonService.getScanTaskCode(schoolId);
-                paperScanTask = new PaperScanTask(schoolId, examId, scanTaskCode, scanTaskName, examCourse.getCourseCode(), examCourse.getCourseName(), recognitionType, storeType, studentCount);
+                String scanTaskCode = paperLibraryCommonService.getScanTaskCode(tbTask.getSchoolId());
+                paperScanTask = new PaperScanTask(tbTask.getSchoolId(), examId, scanTaskCode, scanTaskName, examCourse.getCourseCode(), examCourse.getCourseName(), recognitionType, storeType, studentCount);
             } else {
                 paperScanTask.setStudentCount(studentCount);
             }

+ 1 - 1
paper-library-business/src/main/java/com/qmth/paper/library/business/templete/execute/AsyncExamStudentImportService.java

@@ -107,7 +107,7 @@ public class AsyncExamStudentImportService extends AsyncImportTaskTemplate {
                 RecognitionTypeEnum recognitionType = (RecognitionTypeEnum) map.get("recognitionType");
                 StoreTypeEnum storeType = (StoreTypeEnum) map.get("storeType");
                 // 更新扫描任务数据
-                paperScanTaskService.updatePaperScanTask(tbTask.getExamId(), recognitionType, storeType, examStudentList, tbTask.getCreateId());
+                paperScanTaskService.updatePaperScanTask(tbTask.getExamId(), recognitionType, storeType, examStudentList, tbTask);
                 SystemConstant.addSummary(stringJoinerSummary, "更新扫描任务数据完成,导入结束");
                 tbTask.setResult(TaskResultEnum.SUCCESS);
 

+ 36 - 40
paper-library-business/src/main/java/com/qmth/paper/library/business/templete/service/impl/TaskLogicServiceImpl.java

@@ -89,6 +89,7 @@ public class TaskLogicServiceImpl implements TaskLogicService {
     private BasicExamService basicExamService;
     @Resource
     private PictureManageService pictureManageService;
+    @Resource
     private BasicFieldService basicFieldService;
 
     @Transactional
@@ -303,14 +304,14 @@ public class TaskLogicServiceImpl implements TaskLogicService {
             TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
             DownloadPictureParams downLoadPaperParams = JSON.parseObject(tbTask.getRemark(), DownloadPictureParams.class);
             List<PictureManageDetailResult> studentList = pictureManageService.listPictureResult(downLoadPaperParams);
-            
+
             rootPath = fileStoreUtil.buildPath(UploadFileEnum.DOWNLOAD, true, String.valueOf(System.currentTimeMillis()));
             String dirName = SystemConstant.getUuid() + SystemConstant.ZIP_SUFFIX;
             zipFile = new File(rootPath + dirName);
             if (!zipFile.getParentFile().exists()) {
                 boolean dirSuccess = zipFile.getParentFile().mkdirs();
-                if(!dirSuccess){
-                    log.error(String.format("[图片管理],目录创建失败,dirPath:%s",rootPath));
+                if (!dirSuccess) {
+                    log.error(String.format("[图片管理],目录创建失败,dirPath:%s", rootPath));
                     throw ExceptionResultEnum.ERROR.exception("目录创建失败");
                 }
             }
@@ -320,7 +321,7 @@ public class TaskLogicServiceImpl implements TaskLogicService {
             Map<Long, Integer> successMap = new HashMap<>();
             Map<Long, Integer> errorMap = new HashMap<>();
 
-            for(PictureManageDetailResult student : studentList) {
+            for (PictureManageDetailResult student : studentList) {
                 Long studentId = student.getStudentId();
                 successMap.putIfAbsent(studentId, 0);
                 errorMap.putIfAbsent(studentId, 0);
@@ -348,7 +349,7 @@ public class TaskLogicServiceImpl implements TaskLogicService {
                         }
                     }
                 }
-                
+
             }
 
             if (!CollectionUtils.isEmpty(sourceFileList)) {
@@ -383,8 +384,8 @@ public class TaskLogicServiceImpl implements TaskLogicService {
             }
             if (Objects.nonNull(dictionaryConfig.sysDomain()) && fileStoreUtil.isOssStore() && Objects.nonNull(zipFile)) {
                 boolean success = zipFile.delete();
-                if(!success) {
-                    log.warn(String.format("[图片管理],临时zip目录删除失败,zipPath:%s",zipFile.getPath()));
+                if (!success) {
+                    log.warn(String.format("[图片管理],临时zip目录删除失败,zipPath:%s", zipFile.getPath()));
                 }
             }
         }
@@ -392,7 +393,7 @@ public class TaskLogicServiceImpl implements TaskLogicService {
     }
 
     private void createPictureDownloadExcel(String zipLocalRootPath, List<PictureManageDetailResult> list, Map<Long, Integer> successMap,
-            Map<Long, Integer> errorMap) throws IOException {
+                                            Map<Long, Integer> errorMap) throws IOException {
         String fileName = "下载记录清单.xlsx";
         XSSFWorkbook wb = new XSSFWorkbook();
         XSSFSheet sheet = wb.createSheet("数据");
@@ -448,7 +449,7 @@ public class TaskLogicServiceImpl implements TaskLogicService {
 
         XSSFRow headRow = sheet.createRow(0);
         // 表头
-        String[] fieldsNameList = {"学号", "姓名", "学期", "考试", "扫描批次号", "课程名称(代码)","任课老师", "教学班", "学院", "专业", "班级",  "绑定图片数量(张)", "下载成功数量(页)", "下载失败(页)"};
+        String[] fieldsNameList = {"学号", "姓名", "学期", "考试", "扫描批次号", "课程名称(代码)", "任课老师", "教学班", "学院", "专业", "班级", "绑定图片数量(张)", "下载成功数量(页)", "下载失败(页)"};
         for (int i = 0; i < fieldsNameList.length; i++) {
             XSSFCell cell = headRow.createCell(i);
             cell.setCellValue(fieldsNameList[i]);
@@ -487,7 +488,7 @@ public class TaskLogicServiceImpl implements TaskLogicService {
             XSSFCell cell5 = row.createCell(5);
             cell5.setCellStyle(lockStyle);
             cell5.setCellStyle(dataStyle);
-            cell5.setCellValue(result.getCourseName()+"("+result.getCourseCode()+")");
+            cell5.setCellValue(result.getCourseName() + "(" + result.getCourseCode() + ")");
 
             XSSFCell cell6 = row.createCell(6);
             cell6.setCellStyle(lockStyle);
@@ -580,7 +581,7 @@ public class TaskLogicServiceImpl implements TaskLogicService {
         List<PaperScanTask> paperScanTaskList = paperScanTaskService.listByExamId(examId);
         Map<String, StoreTypeEnum> stringStoreTypeMap = paperScanTaskList.stream().collect(Collectors.toMap(PaperScanTask::getCourseCode, PaperScanTask::getStoreType));
 
-        Map<String, String> courseMap = examStudentList.stream().collect(Collectors.toMap(ExamStudent::getCourseCode, ExamStudent::getCourseName));
+        Map<String, String> courseMap = examStudentList.stream().collect(Collectors.toMap(ExamStudent::getCourseCode, ExamStudent::getCourseName, (v1, v2) -> v2));
         Map<String, List<String>> studentCodeMap = new HashMap<>();
         // 是否有错误提示
         boolean hasError = false;
@@ -590,7 +591,6 @@ public class TaskLogicServiceImpl implements TaskLogicService {
             BeanUtils.copyProperties(examStudentImport, examStudent);
             examStudent.setExtendFields(CollectionUtils.isNotEmpty(examStudentImport.getExtendFieldList()) ? JSON.toJSONString(examStudentImport.getExtendFieldList()) : null);
 
-            StringJoiner stringJoiner = new StringJoiner(";");
             // 学号去掉空格
             examStudent.setStudentCode(StringUtils.isNotBlank(examStudentImport.getStudentCode()) ? StringUtils.deleteWhitespace(examStudentImport.getStudentCode()) : null);
             // 课程代码去掉空格
@@ -655,45 +655,41 @@ public class TaskLogicServiceImpl implements TaskLogicService {
                 String key = examStudent.getCourseCode() + SystemConstant.HYPHEN + examStudent.getStudentCode();
                 if (courseIdStudentCodeMap.containsKey(key)) {
                     ExamStudent student = courseIdStudentCodeMap.get(key);
-
                     // 校验存储方式
                     if (stringStoreTypeMap.containsKey(examStudent.getCourseCode())) {
-                        StoreTypeEnum courseCodeStoreType = stringStoreTypeMap.get(examStudent.getCourseCode());
-                        if (StoreTypeEnum.ROOM.equals(courseCodeStoreType) && !examStudent.getExamRoom().equals(student.getExamRoom())) {
-                            errorMsg.add("考场不能更改,原考场为[" + student.getExamRoom() + "]");
-                        }
-                        if (StoreTypeEnum.CLASS.equals(courseCodeStoreType) && !examStudent.getClassName().equals(student.getClassName())) {
-                            errorMsg.add("班级不能更改,原班级为[" + student.getClassName() + "]");
+                        // 已扫描,不能修改考场或班级
+                        if (paperLibraryService.countByStudentId(student.getId()) > 0) {
+                            StoreTypeEnum courseCodeStoreType = stringStoreTypeMap.get(examStudent.getCourseCode());
+                            if (StoreTypeEnum.ROOM.equals(courseCodeStoreType) && !examStudent.getExamRoom().equals(student.getExamRoom())) {
+                                errorMsg.add("考生已扫描,不能更改考场,原考场为[" + student.getExamRoom() + "]");
+                            }
+                            if (StoreTypeEnum.CLASS.equals(courseCodeStoreType) && !examStudent.getClassName().equals(student.getClassName())) {
+                                errorMsg.add("考生已扫描,不能更改班级,原班级为[" + student.getClassName() + "]");
+                            }
                         }
                     }
                     examStudent.setId(student.getId());
                 }
             }
 
-            if (StringUtils.isNotBlank(errorMsg.toString())) {
-                throw ExceptionResultEnum.ERROR.exception(errorMsg.toString());
-            }
+            if (errorMsg.toString().length() > 0) {
+                examStudentImport.setErrorMsg(errorMsg.toString());
+            } else {
 
-            if (examStudent.getId() == null) {
-                examStudent.setId(SystemConstant.getDbUuid());
-            }
-            examStudent.setSchoolId(sysUser.getSchoolId());
-            examStudent.setSemesterId(semesterId);
-            examStudent.setExamId(examId);
-            examStudent.setCreateId(sysUser.getId());
-            examStudent.setCreateTime(System.currentTimeMillis());
-
-            if (stringJoiner.toString().length() > 0) {
-                examStudentImport.setErrorMsg(stringJoiner.toString());
+                if (examStudent.getId() == null) {
+                    examStudent.setId(SystemConstant.getDbUuid());
+                }
+                examStudent.setSchoolId(sysUser.getSchoolId());
+                examStudent.setSemesterId(semesterId);
+                examStudent.setExamId(examId);
+                examStudent.setCreateId(sysUser.getId());
+                examStudent.setCreateTime(System.currentTimeMillis());
+                examStudents.add(examStudent);
             }
 
-            if (!hasError && stringJoiner.toString().length() > 0) {
+            if (!hasError && errorMsg.toString().length() > 0) {
                 hasError = true;
             }
-
-            if (stringJoiner.toString().length() == 0) {
-                examStudents.add(examStudent);
-            }
         }
 
         map.put(SystemConstant.ERROR_DATA_LIST, examStudentImportList);
@@ -848,7 +844,7 @@ public class TaskLogicServiceImpl implements TaskLogicService {
     }
 
     private ExamStudentParseDto parseImportExamStudentData(Long schoolId, InputStream inputStream) {
-        ExcelReader excelReader = ExcelReader.create(ExcelType.XLSX, inputStream, 1);
+        ExcelReader excelReader = ExcelReader.create(ExcelType.XLSX, inputStream, 0);
         List<DataMap> dataMapList;
         try {
             dataMapList = excelReader.getDataMapList();
@@ -864,7 +860,7 @@ public class TaskLogicServiceImpl implements TaskLogicService {
             // 必填字段
             Map<String, BasicField> requiredMap = basicFieldList.stream().filter(m -> m.getBasicField()).collect(Collectors.toMap(BasicField::getName, e -> e));
             // 扩展字段
-            Map<String, BasicField> extendMap = basicFieldList.stream().filter(m -> !m.getBasicField()).collect(Collectors.toMap(BasicField::getName, e -> e));
+            Map<String, BasicField> extendMap = basicFieldList.stream().filter(m -> !m.getBasicField() && m.getEnable()).collect(Collectors.toMap(BasicField::getName, e -> e));
 
             // 通用规则表头
             List<String> actualTitleList = Stream.concat(requiredMap.keySet().stream(), extendMap.keySet().stream()).collect(Collectors.toList());

+ 0 - 0
paper-library-business/src/main/resources/mapper/ExamCourseMapper.xml → paper-library-business/src/main/resources/mapper/BasicBatchNumberService.xml


+ 4 - 0
paper-library-common/pom.xml

@@ -188,5 +188,9 @@
             <groupId>com.github.jeffreyning</groupId>
             <artifactId>mybatisplus-plus</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.qmth.boot</groupId>
+            <artifactId>core-concurrent</artifactId>
+        </dependency>
     </dependencies>
 </project>

+ 12 - 0
paper-library-common/src/main/java/com/qmth/paper/library/common/bean/result/LoginResult.java

@@ -2,6 +2,7 @@ package com.qmth.paper.library.common.bean.result;
 
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.qmth.paper.library.common.entity.BasicBatchNumber;
 import com.qmth.paper.library.common.enums.AppSourceEnum;
 import com.qmth.paper.library.common.util.ServletUtil;
 import com.qmth.paper.library.common.entity.BasicSchool;
@@ -68,6 +69,9 @@ public class LoginResult implements Serializable {
     @ApiModelProperty(name = "是否开启条码识别")
     Boolean openBarCode;
 
+    @ApiModelProperty(name = "保存批次信息")
+    private BasicBatchNumber basicBatchNumber;
+
     public String getReturnUrl() {
         return returnUrl;
     }
@@ -216,6 +220,14 @@ public class LoginResult implements Serializable {
         this.userLoginCheckResult = userLoginCheckResult;
     }
 
+    public BasicBatchNumber getBasicBatchNumber() {
+        return basicBatchNumber;
+    }
+
+    public void setBasicBatchNumber(BasicBatchNumber basicBatchNumber) {
+        this.basicBatchNumber = basicBatchNumber;
+    }
+
     public class SchoolNativeBean implements Serializable {
 
         @ApiModelProperty(value = "id")

+ 106 - 0
paper-library-common/src/main/java/com/qmth/paper/library/common/entity/BasicBatchNumber.java

@@ -0,0 +1,106 @@
+package com.qmth.paper.library.common.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.io.Serializable;
+
+import com.github.jeffreyning.mybatisplus.anno.MppMultiId;
+import com.qmth.paper.library.common.enums.ExceptionResultEnum;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author xf
+ * @since 2024-08-01
+ */
+@TableName("basic_batch_number")
+@ApiModel(value="BasicBatchNumber对象", description="")
+public class BasicBatchNumber implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "考试ID")
+    @MppMultiId(value = "exam_id")
+    private Long examId;
+
+    @ApiModelProperty(value = "用户ID")
+    @MppMultiId(value = "user_id")
+    private Long userId;
+
+    @ApiModelProperty(value = "字母(前缀)")
+    private String alphabet;
+
+    @ApiModelProperty(value = "序号")
+    private Integer sequence;
+
+    @TableField(exist = false)
+    private String batchNo;
+
+    public BasicBatchNumber() {
+    }
+
+    public BasicBatchNumber(Long examId, Long userId) {
+        this.examId = examId;
+        this.userId = userId;
+    }
+
+    public BasicBatchNumber(Long examId, Long userId, String alphabet, Integer sequence) {
+        this.examId = examId;
+        this.userId = userId;
+        this.alphabet = alphabet;
+        this.sequence = sequence;
+    }
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+    public Long getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Long userId) {
+        this.userId = userId;
+    }
+    public String getAlphabet() {
+        return alphabet;
+    }
+
+    public void setAlphabet(String alphabet) {
+        this.alphabet = alphabet;
+    }
+    public Integer getSequence() {
+        return sequence;
+    }
+
+    public void setSequence(Integer sequence) {
+        this.sequence = sequence;
+    }
+
+    public String getBatchNo() {
+        return this.alphabet + this.sequence;
+    }
+
+    public void setBatchNo(String batchNo) {
+        this.batchNo = batchNo;
+    }
+
+    @Override
+    public String toString() {
+        return "BasicBatchNumber{" +
+            "examId=" + examId +
+            ", userId=" + userId +
+            ", alphabet=" + alphabet +
+            ", sequence=" + sequence +
+        "}";
+    }
+}

+ 6 - 0
paper-library-common/src/main/java/com/qmth/paper/library/common/enums/AlphabetEnum.java

@@ -0,0 +1,6 @@
+package com.qmth.paper.library.common.enums;
+
+public enum AlphabetEnum {
+
+    A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X ,Y, Z
+}

+ 1 - 0
paper-library-common/src/main/java/com/qmth/paper/library/common/lock/LockType.java

@@ -3,6 +3,7 @@ package com.qmth.paper.library.common.lock;
 public enum LockType {
     BIND_PAPER_TASK("绑定图片任务"),
     GET_SEQUENCE("获取图片自增数"),
+    GET_ALPHABET("获取批次号前缀"),
     SCAN_TASK_SEQUENCE("获取任务编号自增数");
 
     private String name;

+ 17 - 0
paper-library-common/src/main/java/com/qmth/paper/library/common/mapper/BasicBatchNumberMapper.java

@@ -0,0 +1,17 @@
+package com.qmth.paper.library.common.mapper;
+
+import com.github.jeffreyning.mybatisplus.base.MppBaseMapper;
+import com.qmth.paper.library.common.entity.BasicBatchNumber;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author xf
+ * @since 2024-08-01
+ */
+public interface BasicBatchNumberMapper extends MppBaseMapper<BasicBatchNumber> {
+
+}

+ 25 - 0
paper-library-common/src/main/java/com/qmth/paper/library/common/service/BasicBatchNumberService.java

@@ -0,0 +1,25 @@
+package com.qmth.paper.library.common.service;
+
+import com.github.jeffreyning.mybatisplus.service.IMppService;
+import com.qmth.paper.library.common.entity.BasicBatchNumber;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+import java.util.List;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author xf
+ * @since 2024-08-01
+ */
+public interface BasicBatchNumberService extends IMppService<BasicBatchNumber> {
+
+
+    BasicBatchNumber getOrAddByExamIdAndUserId(Long examId, Long userId);
+
+    List<BasicBatchNumber> listByExamId(Long examId);
+
+    void updateBatchNo(Long examId, Long scanUserId, String batchNo);
+}

+ 118 - 0
paper-library-common/src/main/java/com/qmth/paper/library/common/service/impl/BasicBatchNumberServiceImpl.java

@@ -0,0 +1,118 @@
+package com.qmth.paper.library.common.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.github.jeffreyning.mybatisplus.service.MppServiceImpl;
+import com.qmth.paper.library.common.entity.BasicBatchNumber;
+import com.qmth.paper.library.common.enums.AlphabetEnum;
+import com.qmth.paper.library.common.enums.ExceptionResultEnum;
+import com.qmth.paper.library.common.lock.LockService;
+import com.qmth.paper.library.common.lock.LockType;
+import com.qmth.paper.library.common.mapper.BasicBatchNumberMapper;
+import com.qmth.paper.library.common.service.BasicBatchNumberService;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 服务实现类
+ * </p>
+ *
+ * @author xf
+ * @since 2024-08-01
+ */
+@Service
+public class BasicBatchNumberServiceImpl extends MppServiceImpl<BasicBatchNumberMapper, BasicBatchNumber> implements BasicBatchNumberService {
+
+    @Resource
+    private LockService lockService;
+
+    @Override
+    public BasicBatchNumber getOrAddByExamIdAndUserId(Long examId, Long userId) {
+        BasicBatchNumber basicBatchNumber = this.selectByMultiId(new BasicBatchNumber(examId, userId));
+        if (basicBatchNumber == null) {
+            basicBatchNumber = new BasicBatchNumber(examId, userId, this.getUnusedAlphabet(examId), 0);
+            this.saveOrUpdateByMultiId(basicBatchNumber);
+        }
+        return basicBatchNumber;
+    }
+
+    @Override
+    public List<BasicBatchNumber> listByExamId(Long examId) {
+        QueryWrapper<BasicBatchNumber> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(BasicBatchNumber::getExamId, examId);
+        return this.list(queryWrapper);
+    }
+
+    @Override
+    public void updateBatchNo(Long examId, Long scanUserId, String batchNo) {
+        try {
+            BasicBatchNumber basicBatchNumber = this.getOrAddByExamIdAndUserId(examId, scanUserId);
+            String[] batchNoArray = this.splitBatchNo(batchNo);
+            if (batchNoArray.length == 2) {
+                basicBatchNumber.setAlphabet(batchNoArray[0]);
+                basicBatchNumber.setSequence(Integer.valueOf(batchNoArray[1]));
+                this.updateByMultiId(basicBatchNumber);
+            }
+        } catch (Exception e) {
+            // 失败不抛出异常
+        }
+
+    }
+
+    private String[] splitBatchNo(String batchNo) {
+        String regex = "[A-Z]";
+        String[] strings = new String[2];
+        Pattern pattern = Pattern.compile(regex);
+        Matcher matcher = pattern.matcher(batchNo);
+        if (matcher.find()) {
+            String alphabet = matcher.group();
+            strings[0] = alphabet;
+            strings[1] = batchNo.replace(alphabet, "");
+        }
+        return strings;
+    }
+
+    private String getUnusedAlphabet(Long examId) {
+        try {
+            lockService.waitlock(LockType.GET_ALPHABET, examId);
+            // 26个英文字母集合
+            List<String> alphabetList = Arrays.stream(AlphabetEnum.values()).map(m -> m.name()).distinct().collect(Collectors.toList());
+            List<BasicBatchNumber> basicBatchNumberList = this.listByExamId(examId);
+            if (CollectionUtils.isEmpty(basicBatchNumberList)) {
+                return alphabetList.get(0);
+            } else {
+                List<String> usedAlphabetList = basicBatchNumberList.stream().map(BasicBatchNumber::getAlphabet).distinct().collect(Collectors.toList());
+                List<String> unusedAlphabetList = (List<String>) CollectionUtils.subtract(alphabetList, usedAlphabetList);
+                if (CollectionUtils.isNotEmpty(unusedAlphabetList)) {
+                    return unusedAlphabetList.get(0);
+                } else {
+                    // 一位用完了,使用两位组合
+                    for (String s1 : alphabetList) {
+                        for (String s2 : alphabetList) {
+                            String alphabetDouble = s1.concat(s2);
+                            if (usedAlphabetList.contains(alphabetDouble)) {
+                                continue;
+                            }
+                            return alphabetDouble;
+                        }
+                    }
+                    return alphabetList.get(0);
+                }
+            }
+        } catch (Exception e) {
+            throw ExceptionResultEnum.ERROR.exception("获取批次号失败:" + e.getMessage());
+        } finally {
+            lockService.unlock(LockType.GET_ALPHABET, examId);
+        }
+
+    }
+
+
+}

+ 1 - 1
paper-library-common/src/main/java/com/qmth/paper/library/common/service/impl/BasicFieldServiceImpl.java

@@ -54,7 +54,7 @@ public class BasicFieldServiceImpl extends ServiceImpl<BasicFieldMapper, BasicFi
     @Override
     public boolean savaData(List<BasicField> list) {
         Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
-        SysUser sysUser = (SysUser) ServletUtil.getRequestHeaderUserId();
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
         // 校验code是否重复
         StringJoiner stringJoiner = new StringJoiner(";");
         Map<String, List<BasicField>> codeMap = list.stream().collect(Collectors.groupingBy(BasicField::getCode));

+ 5 - 5
paper-library-common/src/main/java/com/qmth/paper/library/common/service/impl/TBTaskServiceImpl.java

@@ -91,11 +91,11 @@ public class TBTaskServiceImpl extends ServiceImpl<TBTaskMapper, TBTask> impleme
                 JSONObject jsonObject = JSON.parseObject(importFilePath, JSONObject.class);
                 record.setImportFilePath(libraryCommonService.preViewPath(jsonObject.getString(SystemConstant.PATH), jsonObject.getString(SystemConstant.UPLOAD_TYPE), jsonObject.getString(SystemConstant.TYPE), false));
             }
-//            String txtFilePath = record.getTxtFilePath();
-//            if (StringUtils.isNotBlank(txtFilePath)) {
-//                JSONObject jsonObject = JSON.parseObject(txtFilePath, JSONObject.class);
-//                record.setTxtFilePath(libraryCommonService.preViewPath(jsonObject.getString(SystemConstant.PATH), jsonObject.getString(SystemConstant.UPLOAD_TYPE), jsonObject.getString(SystemConstant.TYPE), false));
-//            }
+            String errorFilePath = record.getErrorFilePath();
+            if (StringUtils.isNotBlank(errorFilePath)) {
+                JSONObject jsonObject = JSON.parseObject(errorFilePath, JSONObject.class);
+                record.setErrorFilePath(libraryCommonService.preViewPath(jsonObject.getString(SystemConstant.PATH), jsonObject.getString(SystemConstant.UPLOAD_TYPE), jsonObject.getString(SystemConstant.TYPE), false));
+            }
             String exportFilePath = record.getExportFilePath();
             if (StringUtils.isNotBlank(exportFilePath)) {
                 JSONObject jsonObject = JSON.parseObject(exportFilePath, JSONObject.class);

+ 13 - 0
paper-library-common/src/main/resources/mapper/BasicBatchNumberMapper.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.qmth.paper.library.common.mapper.BasicBatchNumberMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.qmth.paper.library.common.entity.BasicBatchNumber">
+        <id column="exam_id" property="examId" />
+        <result column="user_id" property="userId" />
+        <result column="alphabet" property="alphabet" />
+        <result column="sequence" property="sequence" />
+    </resultMap>
+
+</mapper>

+ 2 - 2
paper-library-common/src/main/resources/mapper/TBTaskMapper.xml

@@ -6,14 +6,14 @@
         select
             tbt.id,
             tbt.school_id schoolId,
-            tbt.org_id orgId,
+            tbt.exam_id examId,
             tbt.`type`,
             tbt.status,
             tbt.`result`,
             tbt.import_file_name importFileName,
             tbt.import_file_path importFilePath,
             tbt.export_file_path exportFilePath,
-            tbt.txt_file_path txtFilePath,
+            tbt.error_file_path errorFilePath,
             tbt.summary,
             tbt.`remark`,
             tbt.create_time as createTime,

+ 15 - 2
paper-library/src/main/java/com/qmth/paper/library/api/ClientController.java

@@ -12,6 +12,7 @@ import com.qmth.paper.library.common.entity.BasicSchool;
 import com.qmth.paper.library.common.entity.SysUser;
 import com.qmth.paper.library.common.enums.AppSourceEnum;
 import com.qmth.paper.library.common.enums.ExceptionResultEnum;
+import com.qmth.paper.library.common.service.BasicBatchNumberService;
 import com.qmth.paper.library.common.service.BasicSchoolService;
 import com.qmth.paper.library.common.service.LibraryCommonService;
 import com.qmth.paper.library.common.service.SysUserService;
@@ -46,6 +47,8 @@ public class ClientController {
     @Resource
     private BasicSchoolService basicSchoolService;
     @Resource
+    private BasicBatchNumberService basicBatchNumberService;
+    @Resource
     private LibraryCommonService libraryCommonService;
 
     /**
@@ -102,8 +105,10 @@ public class ClientController {
                                 @ApiParam(value = "正面图片", required = true) @RequestParam MultipartFile frontFile,
                                 @ApiParam(value = "正面图片md5", required = true) @RequestParam String frontMd5,
                                 @ApiParam(value = "背面图片", required = true) @RequestParam MultipartFile versoFile,
-                                @ApiParam(value = "背面图片md5", required = true) @RequestParam String versoMd5) {
-        return ResultUtil.ok(clientService.pictureUpload(paperScanTaskId, studentCode, x, y, width, height, rotate, frontFile, frontMd5, versoFile, versoMd5));
+                                @ApiParam(value = "背面图片md5", required = true) @RequestParam String versoMd5,
+                                @ApiParam(value = "采集用户ID", required = true) @RequestParam Long scanUserId,
+                                @ApiParam(value = "批次号", required = true) @RequestParam String batchNo) {
+        return ResultUtil.ok(clientService.pictureUpload(paperScanTaskId, studentCode, x, y, width, height, rotate, frontFile, frontMd5, versoFile, versoMd5, scanUserId, batchNo));
     }
 
     @ApiOperation(value = "上传其它图片")
@@ -116,4 +121,12 @@ public class ClientController {
                               @ApiParam(value = "背面图片md5", required = true) @RequestParam String versoMd5) {
         return ResultUtil.ok(clientService.otherUpload(paperScanTaskId, frontFile, frontMd5, versoFile, versoMd5));
     }
+
+    @ApiOperation(value = "查询批次号")
+    @PostMapping("/batch_no/get")
+    @ApiResponses({@ApiResponse(code = 200, message = "查询成功", response = Result.class)})
+    public Result getBatchNumber(@ApiParam(value = "考试ID", required = true) @RequestParam Long examId,
+                              @ApiParam(value = "用户ID", required = true) @RequestParam Long userId) {
+        return ResultUtil.ok(basicBatchNumberService.getOrAddByExamIdAndUserId(examId, userId));
+    }
 }

+ 13 - 3
paper-library/src/main/resources/db-log/xf.sql

@@ -32,6 +32,16 @@ UPDATE `sys_privilege` SET `related` = '32,33' WHERE (`id` = '26');
 
 INSERT INTO `sys_privilege` (`id`, `name`, `url`, `type`, `parent_id`, `sequence`, `property`, `enable`, `default_auth`, `front_display`) VALUES ('567', '查询列表', '/api/admin/basic/filetype/list', 'URL', '560', '4', 'AUTH', '1', '1', '1');
 
-INSERT INTO `sys_privilege` (`id`, `name`, `url`, `type`, `parent_id`, `sequence`, `enable`, `default_auth`, `front_display`) VALUES ('205', '根据考号获取考生信息', '/api/admin/client/student/get', 'URL', '200', '5', '1', '1', '1');
-INSERT INTO `sys_privilege` (`id`, `name`, `url`, `type`, `parent_id`, `sequence`, `enable`, `default_auth`, `front_display`) VALUES ('206', '获取考生/班级', '/api/admin/client/classroom/get', 'URL', '200', '6', '1', '1', '1');
-UPDATE `sys_privilege` SET `related` = '30,202,203,204,205,206,565,567' WHERE (`id` = '200');
+INSERT INTO `sys_privilege` (`id`, `name`, `url`, `type`, `parent_id`, `sequence`, `property`, `enable`, `default_auth`, `front_display`) VALUES ('205', '根据考号获取考生信息', '/api/admin/client/student/get', 'URL', '200', '5','AUTH', '1', '1', '1');
+INSERT INTO `sys_privilege` (`id`, `name`, `url`, `type`, `parent_id`, `sequence`, `property`, `enable`, `default_auth`, `front_display`) VALUES ('206', '获取考生/班级', '/api/admin/client/classroom/get', 'URL', '200', '6', 'AUTH', '1', '1', '1');
+INSERT INTO `sys_privilege` (`id`, `name`, `url`, `type`, `parent_id`, `sequence`, `property`, `enable`, `default_auth`, `front_display`) VALUES ('207', '获取批次号', '/api/admin/client/batch_no/get', 'URL', '200', '7', 'AUTH', '1', '1', '1');
+UPDATE `sys_privilege` SET `related` = '30,202,203,204,205,206,207,565,567' WHERE (`id` = '200');
+
+CREATE TABLE `basic_batch_number` (
+        `exam_id` BIGINT(20) NOT NULL COMMENT '考试ID',
+        `user_id` BIGINT(20) NOT NULL COMMENT '用户ID',
+        `alphabet` VARCHAR(4) NULL COMMENT '字母(前缀)',
+        `sequence` INT NULL COMMENT '序号',
+        PRIMARY KEY (`exam_id`, `user_id`));
+
+INSERT INTO `sys_privilege` (`id`, `name`, `url`, `type`, `parent_id`, `sequence`, `property`, `enable`, `default_auth`, `front_display`) VALUES ('207', '获取批次号', '/api/admin/client/get_batch_number', 'URL', '200', '7', 'AUTH', '1', '1', '1');