소스 검색

3.4.4 update-20250401,bug修改

xiaofei 2 달 전
부모
커밋
f42726b6c8
15개의 변경된 파일457개의 추가작업 그리고 303개의 파일을 삭제
  1. 18 40
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/SubjectiveStructDto.java
  2. 121 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/SubjectiveStructImportDto.java
  3. 3 0
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/BasicMessageServiceImpl.java
  4. 8 2
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamDetailServiceImpl.java
  5. 8 1
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/PrintFinishServiceImpl.java
  6. 1 6
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/execute/AsyncBasicExamStudentImportService.java
  7. 91 11
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/execute/AsyncSubjectiveStructImportService.java
  8. 178 240
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/service/impl/ImportLogicServiceImpl.java
  9. BIN
      distributed-print/src/main/resources/temps/subjectiveStruct.xlsx
  10. 1 0
      teachcloud-common/src/main/java/com/qmth/teachcloud/common/contant/SystemConstant.java
  11. 2 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkQuestionService.java
  12. 8 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkQuestionServiceImpl.java
  13. 14 3
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkServiceImpl.java
  14. 3 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkStudentServiceImpl.java
  15. 1 0
      teachcloud-mark/src/main/resources/mapper/MarkUserQuestionMapper.xml

+ 18 - 40
distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/SubjectiveStructDto.java

@@ -5,72 +5,58 @@ import com.qmth.teachcloud.common.annotation.ExcelError;
 import com.qmth.teachcloud.common.annotation.ExcelProperty;
 import io.swagger.annotations.ApiModelProperty;
 
+import java.io.Serializable;
+
 /**
  * @Description: 主观题结构Dto
  * @Author: CaoZixuan
  * @Date: 2024-04-09
  */
-public class SubjectiveStructDto {
+public class SubjectiveStructDto implements Serializable {
 
     @ApiModelProperty(value = "课程代码")
     @ExcelColumn(name = "课程代码", index = 1, nullable = true)
-    @ExcelProperty(name = "课程代码", width = 20, index = 1)
     private String courseCode;
 
     @ApiModelProperty(value = "课程名称")
     @ExcelColumn(name = "课程名称", index = 2, nullable = true)
-    @ExcelProperty(name = "课程名称", width = 20, index = 2)
     private String courseName;
 
     @ApiModelProperty(value = "试卷编号")
     @ExcelColumn(name = "试卷编号", index = 3, nullable = true)
-    @ExcelProperty(name = "试卷编号", width = 20, index = 3)
     private String paperNumber;
 
     @ApiModelProperty(value = "大题名称")
     @ExcelColumn(name = "大题名称", index = 4, nullable = true)
-    @ExcelProperty(name = "大题名称", width = 20, index = 4)
     private String mainTitle;
 
     @ApiModelProperty(value = "大题号(只能用小写数字)")
     @ExcelColumn(name = "大题号(只能用小写数字)", index = 5, nullable = true)
-    @ExcelProperty(name = "大题号(只能用小写数字)", width = 20, index = 5)
     private Integer mainNumber;
 
     @ApiModelProperty(value = "小题号(只能用小写数字)")
     @ExcelColumn(name = "小题号(只能用小写数字)", index = 6, nullable = true)
-    @ExcelProperty(name = "小题号(只能用小写数字)", width = 20, index = 6)
     private Integer subNumber;
 
     @ApiModelProperty(value = "小题满分")
     @ExcelColumn(name = "小题满分", index = 7, nullable = true)
-    @ExcelProperty(name = "小题满分", width = 20, index = 7)
     private Double totalScore;
 
-    @ApiModelProperty(value = "评卷间隔分")
-    @ExcelColumn(name = "间隔分", index = 8, nullable = true)
-    @ExcelProperty(name = "间隔分", width = 20, index = 8)
+    @ApiModelProperty(value = "评卷最小分")
+    @ExcelColumn(name = "最小分", index = 8, nullable = true)
     private Double intervalScore;
 
-    @ApiModelProperty(value = "评卷分组序号")
-    @ExcelColumn(name = "评卷分组(只能用小写数字)", index = 9, nullable = true)
-    @ExcelProperty(name = "评卷分组(只能用小写数字)", width = 20, index = 9)
-    private Integer groupNumber;
-
-    @ApiModelProperty(value = "评卷员数量(系统生成)")
-    @ExcelColumn(name = "评卷员数量(系统生成)", index = 10)
-    @ExcelProperty(name = "评卷员数量(系统生成)", width = 20, index = 10)
-    private Integer markerCount;
-
     @ApiModelProperty(value = "绑定工号(英文逗号分隔)")
-    @ExcelColumn(name = "绑定工号(英文逗号分隔)", index = 11)
-    @ExcelProperty(name = "绑定工号(英文逗号分隔)", width = 20, index = 11)
+    @ExcelColumn(name = "绑定工号(英文逗号分隔)", index = 9, nullable = true)
     private String markerCodes;
 
     @ApiModelProperty(value = "错误信息")
-    @ExcelError
+    @ExcelColumn(name = "错误信息", index = 10, nullable = true)
     private String errorMsg;
 
+    @ApiModelProperty(value = "课程ID")
+    private Long courseId;
+
     public String getCourseCode() {
         return courseCode;
     }
@@ -135,22 +121,6 @@ public class SubjectiveStructDto {
         this.intervalScore = intervalScore;
     }
 
-    public Integer getGroupNumber() {
-        return groupNumber;
-    }
-
-    public void setGroupNumber(Integer groupNumber) {
-        this.groupNumber = groupNumber;
-    }
-
-    public Integer getMarkerCount() {
-        return markerCount;
-    }
-
-    public void setMarkerCount(Integer markerCount) {
-        this.markerCount = markerCount;
-    }
-
     public String getMarkerCodes() {
         return markerCodes;
     }
@@ -159,6 +129,14 @@ public class SubjectiveStructDto {
         this.markerCodes = markerCodes;
     }
 
+    public Long getCourseId() {
+        return courseId;
+    }
+
+    public void setCourseId(Long courseId) {
+        this.courseId = courseId;
+    }
+
     public String getErrorMsg() {
         return errorMsg;
     }

+ 121 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/SubjectiveStructImportDto.java

@@ -0,0 +1,121 @@
+package com.qmth.distributed.print.business.bean.dto;
+
+import com.qmth.boot.tools.excel.annotation.ExcelColumn;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+
+/**
+ * @Description: 主观题结构Dto
+ */
+public class SubjectiveStructImportDto implements Serializable {
+
+    @ApiModelProperty(value = "课程代码")
+    @ExcelColumn(name = "课程代码", index = 1, nullable = true)
+    private String courseCode;
+
+    @ApiModelProperty(value = "课程名称")
+    @ExcelColumn(name = "课程名称", index = 2, nullable = true)
+    private String courseName;
+
+    @ApiModelProperty(value = "试卷编号")
+    @ExcelColumn(name = "试卷编号", index = 3, nullable = true)
+    private String paperNumber;
+
+    @ApiModelProperty(value = "大题名称")
+    @ExcelColumn(name = "大题名称", index = 4, nullable = true)
+    private String mainTitle;
+
+    @ApiModelProperty(value = "大题号(只能用小写数字)")
+    @ExcelColumn(name = "大题号(只能用小写数字)", index = 5, nullable = true)
+    private Integer mainNumber;
+
+    @ApiModelProperty(value = "小题号(只能用小写数字)")
+    @ExcelColumn(name = "小题号(只能用小写数字)", index = 6, nullable = true)
+    private Integer subNumber;
+
+    @ApiModelProperty(value = "小题满分")
+    @ExcelColumn(name = "小题满分", index = 7, nullable = true)
+    private Double totalScore;
+
+    @ApiModelProperty(value = "评卷最小分")
+    @ExcelColumn(name = "最小分", index = 8, nullable = true)
+    private Double intervalScore;
+
+    @ApiModelProperty(value = "绑定工号(英文逗号分隔)")
+    @ExcelColumn(name = "绑定工号(英文逗号分隔)", index = 9, nullable = true)
+    private String markerCodes;
+
+    public String getCourseCode() {
+        return courseCode;
+    }
+
+    public void setCourseCode(String courseCode) {
+        this.courseCode = courseCode;
+    }
+
+    public String getCourseName() {
+        return courseName;
+    }
+
+    public void setCourseName(String courseName) {
+        this.courseName = courseName;
+    }
+
+    public String getPaperNumber() {
+        return paperNumber;
+    }
+
+    public void setPaperNumber(String paperNumber) {
+        this.paperNumber = paperNumber;
+    }
+
+    public String getMainTitle() {
+        return mainTitle;
+    }
+
+    public void setMainTitle(String mainTitle) {
+        this.mainTitle = mainTitle;
+    }
+
+    public Integer getMainNumber() {
+        return mainNumber;
+    }
+
+    public void setMainNumber(Integer mainNumber) {
+        this.mainNumber = mainNumber;
+    }
+
+    public Integer getSubNumber() {
+        return subNumber;
+    }
+
+    public void setSubNumber(Integer subNumber) {
+        this.subNumber = subNumber;
+    }
+
+    public Double getTotalScore() {
+        return totalScore;
+    }
+
+    public void setTotalScore(Double totalScore) {
+        this.totalScore = totalScore;
+    }
+
+    public Double getIntervalScore() {
+        return intervalScore;
+    }
+
+    public void setIntervalScore(Double intervalScore) {
+        this.intervalScore = intervalScore;
+    }
+
+    public String getMarkerCodes() {
+        return markerCodes;
+    }
+
+    public void setMarkerCodes(String markerCodes) {
+        this.markerCodes = markerCodes;
+    }
+
+}

+ 3 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/BasicMessageServiceImpl.java

@@ -26,6 +26,7 @@ import com.qmth.teachcloud.common.service.CommonCacheService;
 import com.qmth.teachcloud.common.service.SysConfigService;
 import com.qmth.teachcloud.common.util.ServletUtil;
 import com.qmth.teachcloud.common.util.SmsSendUtil;
+import com.qmth.teachcloud.mark.service.MarkQuestionService;
 import com.qmth.teachcloud.mark.service.MarkUserQuestionService;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -60,6 +61,8 @@ public class BasicMessageServiceImpl extends ServiceImpl<BasicMessageMapper, Bas
 
     @Resource
     MarkUserQuestionService markUserQuestionService;
+    @Resource
+    private MarkQuestionService markQuestionService;
 
     @Override
     public IPage<BasicMessage> listByMessageType(MessageEnum messageType, Boolean sendStatus, String mobileNumber, Integer pageNumber, Integer pageSize) {

+ 8 - 2
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/ExamDetailServiceImpl.java

@@ -198,6 +198,12 @@ public class ExamDetailServiceImpl extends ServiceImpl<ExamDetailMapper, ExamDet
     public List<JSONObject> taskViewPDF(Long examDetailId) {
         ExamDetail examDetail = this.getById(examDetailId);
         List<JSONObject> list = new ArrayList<>();
+        if (StringUtils.isNotBlank(examDetail.getMergePdfPath())) {
+            JSONObject jsonObject = new JSONObject();
+            jsonObject.put(SystemConstant.TYPE, PdfTypeEnum.MERGE_PDF);
+            jsonObject.put("url", teachcloudCommonService.filePreview(examDetail.getMergePdfPath()));
+            list.add(jsonObject);
+        }
         if (examDetail.getAttachmentId() != null) {
             JSONObject jsonObject = new JSONObject();
             jsonObject.put(SystemConstant.TYPE, PdfTypeEnum.PAPER);
@@ -352,10 +358,10 @@ public class ExamDetailServiceImpl extends ServiceImpl<ExamDetailMapper, ExamDet
             } else if ("examTime".equals(fieldsDto.getCode())) {
                 cell.setCellValue("10:00-12:00");
                 cell.setCellStyle(exampleStyle);
-            } else if("studentCode".equals(fieldsDto.getCode())){
+            } else if ("studentCode".equals(fieldsDto.getCode())) {
                 cell.setCellValue("20240101");
                 cell.setCellStyle(exampleStyle);
-            }else {
+            } else {
                 cell.setCellValue("测试" + fieldsNameList.get(i).getName());
                 cell.setCellStyle(exampleStyle);
             }

+ 8 - 1
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/PrintFinishServiceImpl.java

@@ -348,8 +348,15 @@ public class PrintFinishServiceImpl implements PrintFinishService {
             if (examTaskPaperData != null && examTaskPaperData.getAnswerPdfAttachmentId() != null) {
                 BasicAttachment basicAttachment = basicAttachmentService.getById(examTaskPaperData.getAnswerPdfAttachmentId());
                 if (basicAttachment != null && StringUtils.isNotBlank(basicAttachment.getPath())) {
+                    List<MarkPaperFileDto> subjectiveAnswerFileDtoList = new ArrayList<>();
+                    for (String s : markPaper.getPaperTypeList()) {
+                        MarkPaperFileDto subjectivePaperFileDto = new MarkPaperFileDto();
+                        subjectivePaperFileDto.setPaperType(s);
+                        subjectivePaperFileDto.setFilePathVo(JSON.parseObject(basicAttachment.getPath(), FilePathVo.class));
+                        subjectiveAnswerFileDtoList.add(subjectivePaperFileDto);
+                    }
                     UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
-                    updateWrapper.lambda().set(MarkPaper::getAnswerFilePath, basicAttachment.getPath())
+                    updateWrapper.lambda().set(MarkPaper::getAnswerFilePath, JSON.toJSONString(subjectiveAnswerFileDtoList))
                             .eq(MarkPaper::getId, markPaper.getId());
                     markPaperService.update(updateWrapper);
                 }

+ 1 - 6
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/execute/AsyncBasicExamStudentImportService.java

@@ -14,10 +14,8 @@ import com.qmth.teachcloud.common.bean.examRule.CodeNameEnableValue;
 import com.qmth.teachcloud.common.bean.vo.FilePathVo;
 import com.qmth.teachcloud.common.contant.SpringContextHolder;
 import com.qmth.teachcloud.common.contant.SystemConstant;
-import com.qmth.teachcloud.common.entity.BasicExam;
 import com.qmth.teachcloud.common.entity.BasicExamStudent;
 import com.qmth.teachcloud.common.entity.TBTask;
-import com.qmth.teachcloud.common.enums.ExamModelEnum;
 import com.qmth.teachcloud.common.enums.TaskResultEnum;
 import com.qmth.teachcloud.common.enums.TaskStatusEnum;
 import com.qmth.teachcloud.common.enums.UploadFileEnum;
@@ -25,7 +23,6 @@ import com.qmth.teachcloud.common.service.FileUploadService;
 import com.qmth.teachcloud.common.service.TBTaskService;
 import com.qmth.teachcloud.common.util.Result;
 import com.qmth.teachcloud.common.util.ResultUtil;
-import com.qmth.teachcloud.mark.service.MarkPaperService;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -56,8 +53,6 @@ public class AsyncBasicExamStudentImportService extends AsyncImportTaskTemplete
     public static final String FINISH_SUCCESS_SIZE = "条数据,失败";
     public static final String FINISH_ERROR_SIZE = "条数据";
 
-    @Resource
-    private BasicExamService basicExamService;
     @Resource
     private TeachCourseService teachCourseService;
     @Resource
@@ -130,7 +125,7 @@ public class AsyncBasicExamStudentImportService extends AsyncImportTaskTemplete
         } catch (Exception e) {
             tbTask.setResult(TaskResultEnum.ERROR);
             stringJoinerSummary.add(MessageFormat.format("{0}{1}{2}{3}", DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN), EXCEPTION_TITLE, EXCEPTION_DATA, e.getMessage()));
-        } finally {//生成文件
+        } finally {
             tbTask.setStatus(TaskStatusEnum.FINISH);
             tbTask.setSummary(stringJoinerSummary.toString());
             tbTaskService.updateById(tbTask);

+ 91 - 11
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/execute/AsyncSubjectiveStructImportService.java

@@ -1,26 +1,46 @@
 package com.qmth.distributed.print.business.templete.execute;
 
 import cn.hutool.core.date.DateUtil;
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.qmth.boot.tools.excel.ExcelWriter;
+import com.qmth.boot.tools.excel.enums.ExcelType;
+import com.qmth.distributed.print.business.bean.dto.SubjectiveStructDto;
+import com.qmth.distributed.print.business.bean.dto.importFile.BasicExamStudentImport;
 import com.qmth.distributed.print.business.templete.importData.AsyncImportTaskTemplete;
 import com.qmth.distributed.print.business.templete.importData.SyncImportTaskTemplate;
 import com.qmth.distributed.print.business.templete.service.ImportLogicService;
 import com.qmth.distributed.print.business.templete.service.TaskLogicService;
+import com.qmth.teachcloud.common.bean.examRule.CodeNameEnableValue;
+import com.qmth.teachcloud.common.bean.vo.FilePathVo;
 import com.qmth.teachcloud.common.contant.SpringContextHolder;
 import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.MarkQuestion;
 import com.qmth.teachcloud.common.entity.TBTask;
 import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
 import com.qmth.teachcloud.common.enums.TaskResultEnum;
 import com.qmth.teachcloud.common.enums.TaskStatusEnum;
+import com.qmth.teachcloud.common.enums.UploadFileEnum;
+import com.qmth.teachcloud.common.service.FileUploadService;
 import com.qmth.teachcloud.common.service.TBTaskService;
 import com.qmth.teachcloud.common.util.Result;
 import com.qmth.teachcloud.common.util.ResultUtil;
+import com.qmth.teachcloud.mark.entity.MarkPaper;
+import com.qmth.teachcloud.mark.entity.MarkUserQuestion;
+import com.qmth.teachcloud.mark.service.MarkPaperService;
+import com.qmth.teachcloud.mark.service.MarkQuestionService;
+import com.qmth.teachcloud.mark.service.MarkUserQuestionService;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
 
+import javax.annotation.Resource;
+import java.io.File;
+import java.io.FileOutputStream;
 import java.io.InputStream;
 import java.text.MessageFormat;
-import java.util.Date;
-import java.util.Map;
-import java.util.StringJoiner;
+import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * @Description: 试卷主观题结构导入同步任务
@@ -32,6 +52,15 @@ public class AsyncSubjectiveStructImportService extends AsyncImportTaskTemplete
 
     public static final String OBJ_TITLE = "主观题结构导入";
 
+    @Resource
+    private MarkQuestionService markQuestionService;
+    @Resource
+    private MarkUserQuestionService markUserQuestionService;
+    @Resource
+    private MarkPaperService markPaperService;
+    @Resource
+    private FileUploadService fileUploadService;
+
     @Override
     public Result importTask(Map<String, Object> map) throws Exception {
         TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
@@ -45,19 +74,70 @@ public class AsyncSubjectiveStructImportService extends AsyncImportTaskTemplete
             map.put("inputStream", inputStream);
             ImportLogicService importLogicService = SpringContextHolder.getBean(ImportLogicService.class);
             // 执行导入考务数据
-            importLogicService.executeImportSubjectiveStructLogic(map);
-            tbTask.setResult(TaskResultEnum.SUCCESS);
-            stringJoinerSummary.add("导入主观题结构成功");
+            Map<String, Object> result = importLogicService.executeImportSubjectiveStructLogic(map);
+            boolean hasError = Boolean.parseBoolean(String.valueOf(result.get(SystemConstant.HAS_ERROR_DATA)));
+
+            if (hasError) {
+                SystemConstant.addSummary(stringJoinerSummary, "有异常数据,开始生成错误文件");
+                tbTask.setResult(TaskResultEnum.ERROR);
+                // 有异常数据
+                List<SubjectiveStructDto> errorDataList = JSON.parseArray(JSON.toJSONString(result.get(SystemConstant.ERROR_DATA_LIST)), SubjectiveStructDto.class);
+                try {
+                    File excelFileTemp = SystemConstant.getFileTempVar(SystemConstant.EXCEL_PREFIX);
+                    this.createErrorExcelFile(errorDataList, excelFileTemp);
+                    String fileName = SystemConstant.getNanoId() + SystemConstant.EXCEL_PREFIX;
+                    FilePathVo filePathVo = fileUploadService.uploadFile(excelFileTemp, UploadFileEnum.FILE, fileName);
+                    tbTask.setErrorFilePath(JSON.toJSONString(filePathVo));
+                    SystemConstant.addSummary(stringJoinerSummary, "错误文件生成生成,请到\"导入结果查询\"中,下载错误文件");
+                } catch (Exception e) {
+                    SystemConstant.addSummary(stringJoinerSummary, "错误文件生成失败," + e.getMessage());
+                }
+            } else {
+                SystemConstant.addSummary(stringJoinerSummary, "数据校验通过,开始写入试卷结构数据库");
+                List<MarkQuestion> markQuestions = JSON.parseArray(JSON.toJSONString(result.get(SystemConstant.DATASOURCE)), MarkQuestion.class);
+                markQuestionService.saveOrUpdateBatch(markQuestions);
+                SystemConstant.addSummary(stringJoinerSummary, "写入试卷结构数据库完成,开始写入用户-结构数据库");
+
+                // 更新扫描阅卷数据
+                List<MarkUserQuestion> markUserQuestions = JSON.parseArray(JSON.toJSONString(result.get(SystemConstant.DATASOURCE1)), MarkUserQuestion.class);
+                markUserQuestionService.saveOrUpdateBatch(markUserQuestions);
+                // 更改试卷结构状态为已提交
+                Set<String> paperNumberSet = markQuestions.stream().map(MarkQuestion::getPaperNumber).collect(Collectors.toSet());
+                if (CollectionUtils.isNotEmpty(paperNumberSet)) {
+                    markPaperService.update(new UpdateWrapper<MarkPaper>().lambda()
+                            .set(MarkPaper::getQuestionStatus, true)
+                            .set(MarkPaper::getGroupStatus, true)
+                            .eq(MarkPaper::getExamId, tbTask.getExamId())
+                            .in(MarkPaper::getPaperNumber, paperNumberSet));
+                }
+                SystemConstant.addSummary(stringJoinerSummary, "写入用户-结构数据库完成,导入结束");
+                tbTask.setResult(TaskResultEnum.SUCCESS);
+
+                stringJoinerSummary.add(MessageFormat.format("{0}{1}{2}{3}{4}{5}{6}{7}",
+                        DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN), FINISH_TITLE, markQuestions.size(),
+                        FINISH_TOTAL_SIZE, markQuestions.size(), FINISH_SUCCESS_SIZE, 0, FINISH_ERROR_SIZE));
+            }
         } catch (Exception e) {
-            // 导入异常错误信息写入summary
-            stringJoinerSummary.add("导入主观题结构失败," + EXCEPTION_DATA + System.lineSeparator() + e.getMessage());
             tbTask.setResult(TaskResultEnum.ERROR);
-            throw ExceptionResultEnum.ERROR.exception("导入主观题结构失败,请通过'导入结果查询'查看错误原因");
-        } finally {//生成文件
-            tbTask.setSummary(stringJoinerSummary.toString());
+            stringJoinerSummary.add(MessageFormat.format("{0}{1}{2}{3}", DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN), EXCEPTION_TITLE, EXCEPTION_DATA, e.getMessage()));
+        } finally {
             tbTask.setStatus(TaskStatusEnum.FINISH);
+            tbTask.setSummary(stringJoinerSummary.toString());
             tbTaskService.updateById(tbTask);
         }
         return ResultUtil.ok();
     }
+
+    private void createErrorExcelFile(List<SubjectiveStructDto> list, File excelFileTemp) {
+        try {
+            FileOutputStream outputStream = new FileOutputStream(excelFileTemp);
+            ExcelWriter writer = ExcelWriter.create(ExcelType.XLSX);
+            writer.writeObjects("主观题导入数据", null, SubjectiveStructDto.class, list.listIterator());
+            writer.output(outputStream);
+            outputStream.flush();
+            outputStream.close();
+        } catch (Exception e) {
+
+        }
+    }
 }

+ 178 - 240
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/service/impl/ImportLogicServiceImpl.java

@@ -8,6 +8,7 @@ import com.qmth.boot.tools.excel.enums.ExcelType;
 import com.qmth.boot.tools.excel.model.DataMap;
 import com.qmth.distributed.print.business.bean.dto.ObjectiveStructDto;
 import com.qmth.distributed.print.business.bean.dto.SubjectiveStructDto;
+import com.qmth.distributed.print.business.bean.dto.SubjectiveStructImportDto;
 import com.qmth.distributed.print.business.bean.dto.importFile.BasicExamStudentImport;
 import com.qmth.distributed.print.business.bean.dto.importFile.BasicExamStudentParseDto;
 import com.qmth.distributed.print.business.entity.BasicExamRule;
@@ -23,12 +24,15 @@ import com.qmth.teachcloud.common.bean.examRule.CodeNameEnableDisabledValue;
 import com.qmth.teachcloud.common.bean.examRule.CodeNameEnableValue;
 import com.qmth.teachcloud.common.bean.params.UserSaveParams;
 import com.qmth.teachcloud.common.bean.result.ExcelResult;
+import com.qmth.teachcloud.common.bean.result.SysUserResult;
 import com.qmth.teachcloud.common.contant.SystemConstant;
 import com.qmth.teachcloud.common.entity.*;
 import com.qmth.teachcloud.common.enums.*;
 import com.qmth.teachcloud.common.service.*;
 import com.qmth.teachcloud.common.util.ConvertUtil;
+import com.qmth.teachcloud.mark.bean.answerbatch.Paper;
 import com.qmth.teachcloud.mark.entity.MarkPaper;
+import com.qmth.teachcloud.mark.entity.MarkUserQuestion;
 import com.qmth.teachcloud.mark.service.MarkPaperService;
 import com.qmth.teachcloud.mark.service.MarkQuestionAnswerService;
 import com.qmth.teachcloud.mark.service.MarkQuestionService;
@@ -1096,271 +1100,205 @@ public class ImportLogicServiceImpl implements ImportLogicService {
             throw ExceptionResultEnum.ERROR.exception("考试不存在");
         }
         if (!ExamModelEnum.MODEL4.equals(basicExam.getExamModel())) {
-            throw ExceptionResultEnum.ERROR.exception("仅针对模式4的考试可以导入");
+            throw ExceptionResultEnum.ERROR.exception("非模式4的考试,无法使用此功能");
         }
-        SysRole markerRole = sysRoleService.getOne(
-                new QueryWrapper<SysRole>().lambda().eq(SysRole::getType, RoleTypeEnum.MARKER));
+        SysRole markerRole = sysRoleService.getOne(new QueryWrapper<SysRole>().lambda().eq(SysRole::getType, RoleTypeEnum.MARKER));
         if (Objects.isNull(markerRole)) {
-            throw ExceptionResultEnum.ERROR.exception("缺少评卷员角色");
+            throw ExceptionResultEnum.ERROR.exception("系统中未查询到评卷员角色,请联系管理员");
         }
 
-        // 课程编号名称校验
-        Map<String, Set<String>> courseCheckMap = basicCourseService.list(
-                new QueryWrapper<BasicCourse>().lambda().eq(BasicCourse::getSchoolId, schoolId)).stream().collect(
-                Collectors.toMap(BasicCourse::getCode, v -> new HashSet<>(Collections.singletonList(v.getName())),
-                        (Set<String> v1, Set<String> v2) -> {
-                            v1.addAll(v2);
-                            return v1;
-                        }));
         List<MarkPaper> markPaperList = markPaperService.findMarkPaperListByExamId(examId);
-        // 题号重复校验
-        // 导入的客观题题号集合
-        Set<String> questionNumberCheckSet = new HashSet<>();
-        // 该试卷已存在的客观题题号集合
-        Set<String> dbObjectiveQuestionNumberSet = markQuestionService.list(
-                        new QueryWrapper<MarkQuestion>().lambda().eq(MarkQuestion::getExamId, examId)
-                                .eq(MarkQuestion::getObjective, true)).stream()
-                .map(e -> e.getPaperNumber() + SystemConstant.HYPHEN + e.getMainNumber() + SystemConstant.HYPHEN + e.getSubNumber()).collect(Collectors.toSet());
+        Map<String, MarkPaper> markPaperCourseMap = markPaperList.stream().collect(Collectors.toMap(MarkPaper::getCourseCode, Function.identity()));
+        Map<String, MarkPaper> markPaperPaperNumberMap = markPaperList.stream().collect(Collectors.toMap(MarkPaper::getPaperNumber, Function.identity()));
 
-        ExcelResult<SubjectiveStructDto> excelResult = ConvertUtil.analyzeExcel(inputStream, SubjectiveStructDto.class,
-                true, 0);
-        List<SubjectiveStructDto> subjectiveStructDtoList = excelResult.getDatasource();
-        for (SubjectiveStructDto subjectiveStructDto : subjectiveStructDtoList) {
-            List<String> excelErrorList = new ArrayList<>();
-            // 公共异常提示
-            String excelErrorCommonNotice = "";
+        List<MarkQuestion> markQuestionList = markQuestionService.listByExamIdAndObjective(examId, false);
+        Set<String> subjectivePaperNumberSet = markQuestionList.stream().map(MarkQuestion::getPaperNumber).collect(Collectors.toSet());
 
-            String courseCode = subjectiveStructDto.getCourseCode();
-            String courseName = subjectiveStructDto.getCourseName();
-            String paperNumber = subjectiveStructDto.getPaperNumber();
-            Integer mainNumber = subjectiveStructDto.getMainNumber();
-            Integer subNumber = subjectiveStructDto.getSubNumber();
-            Integer markerCount = subjectiveStructDto.getMarkerCount();
-            String markerCodes = subjectiveStructDto.getMarkerCodes();
-            String errorMsg = subjectiveStructDto.getErrorMsg();
+        List<MarkQuestion> markQuestionList1 = markQuestionService.listByExamIdAndObjective(examId, true);
+        Set<String> objectivePaperNumberSet = markQuestionList1.stream().map(m -> SystemConstant.mergeString(SystemConstant.HYPHEN, m.getPaperNumber(), m.getMainNumber(), m.getSubNumber())).collect(Collectors.toSet());
 
-            // 1.题号重复校验
-            if (SystemConstant.strNotNull(paperNumber) && mainNumber != null && subNumber != null) {
-                excelErrorCommonNotice = String.format("课程代码为[%s],试卷编号为[%s],大题号为[%s],小题号为[%s]的数据异常 : ", courseCode,
-                        paperNumber, mainNumber, subNumber);
-                String questionNumberKey =
-                        courseCode + SystemConstant.HYPHEN + paperNumber + SystemConstant.HYPHEN + mainNumber + SystemConstant.HYPHEN + subNumber;
-                if (questionNumberCheckSet.contains(questionNumberKey)) {
-                    excelErrorList.add("excel中题号重复");
-                } else {
-                    questionNumberCheckSet.add(questionNumberKey);
+        List<SysUserResult> sysUserList = sysUserService.listBySchoolId(schoolId);
+        Map<String, SysUserResult> sysUserMap = sysUserList.stream().collect(Collectors.toMap(SysUserResult::getLoginName, Function.identity()));
+
+        ExcelReader excelReader = ExcelReader.create(ExcelType.XLSX, inputStream, 0);
+        List<SubjectiveStructImportDto> subjectiveStructDtoList = excelReader.getObjectList(SubjectiveStructImportDto.class);
+
+        // 课程下试卷编号map
+        Map<String, String> coursePaperNumberMap = new HashMap<>();
+        // 课程、试卷编号下大题号、小题号
+        Map<String, String> coursePaperQuestionMap = new HashMap<>();
+
+        List<MarkQuestion> markQuestions = new ArrayList<>();
+        List<MarkUserQuestion> markUserQuestions = new ArrayList<>();
+        boolean hasError = false;
+        List<SubjectiveStructDto> subjectiveStructDtos = new ArrayList<>();
+        // 按课程+试卷编号分组
+        for (SubjectiveStructImportDto subjectiveStructImportDto : subjectiveStructDtoList) {
+            SubjectiveStructDto subjectiveStructDto = new SubjectiveStructDto();
+            BeanUtils.copyProperties(subjectiveStructImportDto, subjectiveStructDto);
+            try {
+                List<String> errorList = new ArrayList<>();
+
+                if (StringUtils.isBlank(subjectiveStructDto.getCourseCode())) {
+                    errorList.add("课程代码不能为空");
                 }
-                if (dbObjectiveQuestionNumberSet.contains(questionNumberKey)) {
-                    excelErrorList.add("该题号已存在客观题中");
+                if (StringUtils.isBlank(subjectiveStructDto.getCourseName())) {
+                    errorList.add("课程名称不能为空");
+                }
+                if (StringUtils.isBlank(subjectiveStructDto.getPaperNumber())) {
+                    errorList.add("试卷编号不能为空");
+                }
+                Integer mainNumber = subjectiveStructDto.getMainNumber();
+                if (mainNumber == null) {
+                    errorList.add("大题号不能为空");
+                }
+                Integer subNumber = subjectiveStructDto.getSubNumber();
+                if (subNumber == null) {
+                    errorList.add("小题号不能为空");
+                }
+                Double totalScore = subjectiveStructDto.getTotalScore();
+                if (totalScore == null) {
+                    errorList.add("小题满分不能为空");
+                }
+                Double intervalScore = subjectiveStructDto.getIntervalScore();
+                if (intervalScore == null) {
+                    errorList.add("小题号不能为空");
+                }
+                if (StringUtils.isBlank(subjectiveStructDto.getMarkerCodes())) {
+                    errorList.add("绑定工号不能为空");
                 }
-            }
 
-            // 2.校验课程代码,课程名称,试卷在考试下是否存在
-            if (SystemConstant.strNotNull(courseCode) && SystemConstant.strNotNull(courseName) && SystemConstant.strNotNull(paperNumber)) {
-                if (!courseCheckMap.containsKey(courseCode)) {
-                    excelErrorList.add("课程代码不存在");
-                } else if (!courseCheckMap.get(courseCode).contains(courseName)) {
-                    excelErrorList.add("课程代码名称不匹配");
+                if (CollectionUtils.isNotEmpty(errorList)) {
+                    throw ExceptionResultEnum.ERROR.exception(String.join(";", errorList));
                 }
-                if (markPaperList.stream().noneMatch(
-                        m -> m.getPaperNumber().equals(paperNumber) && m.getCourseCode().equals(courseCode) && m.getCourseName().equals(courseName))) {
-                    excelErrorList.add("考试课程中不存在该试卷,请先创建试卷");
+
+                if (totalScore < intervalScore) {
+                    errorList.add("最小分不能大于小题满分");
+                    throw ExceptionResultEnum.ERROR.exception(String.join(";", errorList));
                 }
-            }
 
-            // 3.评卷员校验
-            if (Objects.isNull(markerCount) && Objects.isNull(markerCodes)) {
-                excelErrorList.add("[评卷员数量(系统生成)]和[绑定工号(英文逗号分隔)]不能同时为空");
-            }
+                String courseCode = subjectiveStructDto.getCourseCode().trim();
+                String courseName = subjectiveStructDto.getCourseName().trim();
+                String paperNumber = subjectiveStructDto.getPaperNumber().trim();
 
-            // 整理异常信息
-            if (CollectionUtils.isNotEmpty(excelErrorList)) {
-                if (SystemConstant.strNotNull(errorMsg)) {
-                    errorMsg = errorMsg + "、" + excelErrorCommonNotice + String.join("、", excelErrorList);
+                // 课程是否存在
+                if (!markPaperCourseMap.containsKey(courseCode)) {
+                    errorList.add("未查询到此课程");
+                    throw ExceptionResultEnum.ERROR.exception(String.join(";", errorList));
                 } else {
-                    errorMsg = excelErrorCommonNotice + String.join("、", excelErrorList);
-                }
-                subjectiveStructDto.setErrorMsg(errorMsg);
-            }
-        }
-        if (subjectiveStructDtoList.stream().anyMatch(e -> SystemConstant.strNotNull(e.getErrorMsg()))) {
-            // 抛出excel解析异常
-            throw ExceptionResultEnum.ERROR.exception(
-                    subjectiveStructDtoList.stream().map(SubjectiveStructDto::getErrorMsg).filter(SystemConstant::strNotNull).collect(Collectors.joining(System.lineSeparator())));
-        } else {
-            List<String> paperErrorList = new ArrayList<>();
-            // 试卷编号-> 题目集合 Map
-            Map<String, List<SubjectiveStructDto>> paperQuestionsMap = subjectiveStructDtoList.stream().collect(Collectors.groupingBy(SubjectiveStructDto::getPaperNumber));
-            paperQuestionsMap.forEach((paperNumber, paperQuestionList) -> {
-                // todo 2025-02-25
-                if(true) /*(markGroupService.countByExamIdAndPaperNumber(examId, paperNumber) > 0) {
-                    paperErrorList.add(String.format("[试卷编号]%s,已存在分组,请先删除该试卷的所有分组再导入试题", paperNumber));
-                } else */{
-                    MarkPaper markPaper = markPaperService.getByExamIdAndPaperNumber(examId, paperNumber);
-                    Long courseId = markPaper.getCourseId();
-                    BasicCourse basicCourse = basicCourseService.getById(courseId);
-                    String orgName;
-                    Long orgId;
-                    if (Objects.isNull(basicCourse)) {
-                        throw ExceptionResultEnum.ERROR.exception("无法找到课程");
-                    } else {
-                        Long teachingRoomId = basicCourse.getTeachingRoomId();
-                        SysOrg sysOrg = sysOrgService.getById(teachingRoomId);
-                        if (Objects.isNull(sysOrg)) {
-                            throw ExceptionResultEnum.ERROR.exception("无法找到机构");
-                        }
-                        orgName = sysOrg.getName();
-                        orgId = sysOrg.getId();
+                    MarkPaper markPaper = markPaperCourseMap.get(courseCode);
+                    if (!courseName.equals(markPaper.getCourseName())) {
+                        errorList.add("评卷设置中,课程名称为[" + markPaper.getCourseName() + "]");
+                        throw ExceptionResultEnum.ERROR.exception(String.join(";", errorList));
                     }
+                    subjectiveStructDto.setCourseId(markPaper.getCourseId());
+                }
 
-                    // 优先删除该试卷的主观题
-                    markQuestionService.remove(
-                            new QueryWrapper<MarkQuestion>().lambda().eq(MarkQuestion::getExamId, examId)
-                                    .eq(MarkQuestion::getPaperNumber, paperNumber).eq(MarkQuestion::getObjective, false));
-
-                    // 试卷下分组集合
-                    List<Integer> groupNumberList = paperQuestionList.stream().map(SubjectiveStructDto::getGroupNumber)
-                            .distinct().sorted().collect(Collectors.toList());
-
-                    // 评卷员序号
-                    AtomicInteger markerNumber = new AtomicInteger(0);
-                    for (Integer groupNumber : groupNumberList) {
-                        List<String> groupErrorList = new ArrayList<>();
-                        // 分组下题目集合
-                        List<SubjectiveStructDto> groupQuestionList = paperQuestionList.stream()
-                                .filter(e -> e.getGroupNumber().equals(groupNumber)).collect(Collectors.toList());
-
-                        String paperNumberGroupNumberNotice = String.format("[试卷编号]%s,[评卷分组(只能用小写数字)]%s,的", paperNumber,
-                                groupNumber);
-
-                        Integer markerCount = null;
-                        String markerCodes = null;
-                        List<Integer> markerCountList = groupQuestionList.stream().map(SubjectiveStructDto::getMarkerCount).distinct().collect(Collectors.toList());
-                        if (CollectionUtils.isNotEmpty(markerCountList)) {
-                            if (markerCountList.size() > 1) {
-                                groupErrorList.add("[评卷员数量(系统生成)]不一致");
-                            } else if (markerCountList.size() == 1) {
-                                markerCount = markerCountList.get(0);
-                            }
-                        }
+                // 试卷编号是否存在
+                if (!markPaperPaperNumberMap.containsKey(paperNumber)) {
+                    errorList.add("未查询到此试卷编号");
+                    throw ExceptionResultEnum.ERROR.exception(String.join(";", errorList));
+                }
 
-                        List<String> markerCodesList = groupQuestionList.stream().map(SubjectiveStructDto::getMarkerCodes).distinct().collect(Collectors.toList());
-                        if (CollectionUtils.isNotEmpty(markerCodesList)) {
-                            if (markerCodesList.size() > 1) {
-                                groupErrorList.add("[绑定工号(英文逗号分隔)]不一致");
-                            } else if (markerCodesList.size() == 1) {
-                                markerCodes = markerCodesList.get(0);
-                            }
-                        }
+                // 试卷编号是否设置了主观题
+                if (subjectivePaperNumberSet.contains(paperNumber)) {
+                    errorList.add("试卷编号设置了主观题");
+                    throw ExceptionResultEnum.ERROR.exception(String.join(";", errorList));
+                }
 
-                        // 组装评卷员信息
-                        List<MarkUser> markUsers = new ArrayList<>();
-                        if (SystemConstant.strNotNull(markerCodes)) {
-                            // 优先以绑定工号为准
-                            String[] markerCodeArray = markerCodes.split(SystemConstant.COMMA);
-                            for (String markerCode : markerCodeArray) {
-                                SysUser sysUser = sysUserService.getOne(
-                                        new QueryWrapper<SysUser>().lambda().eq(SysUser::getSchoolId, schoolId).eq(SysUser::getLoginName, markerCode).last(SystemConstant.LIMIT1));
-                                if (Objects.isNull(sysUser)) {
-                                    groupErrorList.add(paperNumberGroupNumberNotice + String.format(
-                                            "[绑定工号(英文逗号分隔)]中的%s,在系统中不存在请先创建用户", markerCode));
-                                } else {
-                                    // 添加评卷员信息
-                                    MarkUser markUser = new MarkUser();
-                                    markUser.setUserId(sysUser.getId());
-                                    markUser.setLoginName(sysUser.getLoginName());
-                                    markUser.setName(sysUser.getRealName());
-                                    markUser.setOrgName(orgName);
-                                    markUsers.add(markUser);
-                                }
-                            }
-                        } else if (Objects.nonNull(markerCount) && markerCount > 0) {
-                            // 没有绑定工号且评卷员生成数量大于0,生成评卷员(或使用之前工号相同的评卷员)
-                            for (int i = 0; i < markerCount; i++) {
-                                int num = markerNumber.incrementAndGet();
-                                if (num > 99) {
-                                    paperErrorList.add("[试卷编号]%s的[评卷员数量(系统生成)]总有效数量不能超过99");
-                                    break;
-                                }
-                                String markerCode = paperNumber + String.format("%02d", num);
-
-                                SysUser sysUser = sysUserService.getOne(
-                                        new QueryWrapper<SysUser>().lambda().eq(SysUser::getSchoolId, schoolId).eq(SysUser::getLoginName, markerCode).last(SystemConstant.LIMIT1));
-
-                                MarkUser markUser = new MarkUser();
-                                markUser.setLoginName(markerCode);
-                                markUser.setOrgName(orgName);
-                                markUsers.add(markUser);
-                                if (Objects.nonNull(sysUser)) {
-                                    markUser.setUserId(sysUser.getId());
-                                    markUser.setName(sysUser.getRealName());
-                                } else {
-                                    // 创建用户
-                                    UserSaveParams userSaveParams = new UserSaveParams();
-                                    userSaveParams.setSchoolId(schoolId);
-                                    userSaveParams.setLoginName(markerCode);
-                                    userSaveParams.setRealName(markerCode);
-                                    userSaveParams.setCode(markerCode);
-                                    userSaveParams.setPassword(SystemConstant.DEFAULT_PASSWORD);
-                                    userSaveParams.setOrgId(orgId);
-                                    userSaveParams.setEnable(true);
-                                    userSaveParams.setRoleIds(new Long[]{markerRole.getId()});
-                                    try {
-                                        markUser.setUserId(sysUserService.saveUser(userSaveParams, requestUser.getId()));
-                                        markUser.setName(markerCode);
-                                    } catch (IllegalAccessException e) {
-                                        e.printStackTrace();
-                                    }
-                                }
-                            }
-                        }
-                        if (CollectionUtils.isEmpty(groupErrorList) && CollectionUtils.isEmpty(paperErrorList)) {
-                            // 创建评卷试题
-                            List<MarkQuestion> markQuestionList = paperQuestionList.stream().filter(e -> groupNumber.equals(e.getGroupNumber())).flatMap(e -> {
-                                MarkQuestion markQuestion = new MarkQuestion();
-                                markQuestion.setExamId(examId);
-                                markQuestion.setPaperNumber(paperNumber);
-                                markQuestion.setPaperType(OptionsEnum.A.getCode());
-                                markQuestion.setObjective(false);
-                                markQuestion.setMainNumber(e.getMainNumber());
-                                markQuestion.setSubNumber(e.getSubNumber());
-                                markQuestion.setMainTitle(e.getMainTitle());
-                                markQuestion.setTotalScore(e.getTotalScore());
-                                markQuestion.setIntervalScore(e.getIntervalScore());
-                                markQuestion.setQuestionType(QuestionType.QUESTION_ANSWER.getValue());
-                                return Stream.of(markQuestion);
-                            }).collect(Collectors.toList());
-                            markQuestionService.saveBatch(markQuestionList);
-
-//                            MarkGroupDto markGroupDto = new MarkGroupDto();
-//                            markGroupDto.setDoubleEnable(false);
-//                            markGroupDto.setGroupNumber(groupNumber);
-//                            markGroupDto.setMarkers(markUsers);
-//                            markGroupDto.setQuestions(markQuestionList);
-//                            markGroupDto.setPictureConfigs(new ArrayList<>());
-//                            MarkGroupSingleDto markGroupSingleDto = new MarkGroupSingleDto();
-//                            markGroupSingleDto.setExamId(examId);
-//                            markGroupSingleDto.setPaperNumber(paperNumber);
-//                            markGroupSingleDto.setGroupInfo(markGroupDto);
-//                            markGroupService.saveGroup(markGroupSingleDto);
-                        }
-                        if (CollectionUtils.isNotEmpty(groupErrorList)) {
-                            String groupErrorMsg = paperNumberGroupNumberNotice + String.join(",", groupErrorList);
-                            paperErrorList.add(groupErrorMsg);
+                // 校验课程下试卷编号唯一
+                if (coursePaperNumberMap.containsKey(courseCode)) {
+                    if (!paperNumber.equals(coursePaperNumberMap.get(courseCode))) {
+                        errorList.add("课程存在不同试卷编号");
+                        throw ExceptionResultEnum.ERROR.exception(String.join(";", errorList));
+                    }
+                } else {
+                    coursePaperNumberMap.put(courseCode, paperNumber);
+                }
+
+                // 校验试卷编号唯一
+                if (coursePaperNumberMap.containsValue(paperNumber)) {
+                    for (Map.Entry<String, String> entry : coursePaperNumberMap.entrySet()) {
+                        if (entry.getValue().equals(paperNumber) && !courseCode.equals(entry.getKey())) {
+                            errorList.add("试卷编号已被其它课程占用");
+                            throw ExceptionResultEnum.ERROR.exception(String.join(";", errorList));
                         }
                     }
                 }
-            });
-            if (CollectionUtils.isNotEmpty(paperErrorList)) {
-                throw ExceptionResultEnum.ERROR.exception(String.join(System.lineSeparator(), paperErrorList));
-            }
-            // 更改试卷结构状态为已提交
-            Set<String> paperNumberSet = paperQuestionsMap.keySet();
-            if (CollectionUtils.isNotEmpty(paperNumberSet)) {
-                markPaperService.update(new UpdateWrapper<MarkPaper>().lambda().eq(MarkPaper::getExamId, examId)
-                        .in(MarkPaper::getPaperNumber, paperNumberSet).set(MarkPaper::getQuestionStatus, true));
+
+                // 题号重复校验
+                String coursePaper = SystemConstant.mergeString(SystemConstant.HYPHEN, courseCode, paperNumber);
+                String questionNumber = SystemConstant.mergeString(SystemConstant.HYPHEN, mainNumber, subNumber);
+                if (coursePaperQuestionMap.containsKey(coursePaper)) {
+                    if (questionNumber.equals(coursePaperQuestionMap.get(coursePaper))) {
+                        errorList.add("存在相同大题号、小题号");
+                        throw ExceptionResultEnum.ERROR.exception(String.join(";", errorList));
+                    }
+                } else {
+                    coursePaperQuestionMap.put(coursePaper, questionNumber);
+                }
+
+                // 题号是否被客观题使用
+                if (objectivePaperNumberSet.contains(SystemConstant.mergeString(SystemConstant.HYPHEN, paperNumber, mainNumber, subNumber))) {
+                    errorList.add("大题号、小题号已被客观题使用");
+                    throw ExceptionResultEnum.ERROR.exception(String.join(";", errorList));
+                }
+
+                // 组装数据
+                assembleSubjectiveImportData(examId, subjectiveStructDto, markQuestions, markUserQuestions, sysUserMap);
+            } catch (Exception e) {
+                hasError = true;
+                subjectiveStructDto.setErrorMsg(e.getMessage());
+            } finally {
+                subjectiveStructDtos.add(subjectiveStructDto);
             }
         }
+
+        map.put(SystemConstant.ERROR_DATA_LIST, subjectiveStructDtos);
+        map.put(SystemConstant.DATASOURCE, markQuestions);
+        map.put(SystemConstant.DATASOURCE1, markUserQuestions);
+        map.put(SystemConstant.DATA_COUNT, subjectiveStructDtos.size());
+        map.put(SystemConstant.HAS_ERROR_DATA, hasError);
+
         return map;
     }
+
+    private void assembleSubjectiveImportData(Long examId, SubjectiveStructDto subjectiveStructDto, List<MarkQuestion> markQuestions, List<MarkUserQuestion> markUserQuestions, Map<String, SysUserResult> sysUserMap) {
+        MarkQuestion markQuestion = new MarkQuestion();
+        markQuestion.setId(SystemConstant.getDbUuid());
+        markQuestion.setExamId(examId);
+        markQuestion.setCourseId(subjectiveStructDto.getCourseId());
+        markQuestion.setPaperNumber(subjectiveStructDto.getPaperNumber());
+        markQuestion.setObjective(false);
+        markQuestion.setMainNumber(subjectiveStructDto.getMainNumber());
+        markQuestion.setSubNumber(subjectiveStructDto.getSubNumber());
+        markQuestion.setMainTitle(subjectiveStructDto.getMainTitle());
+        markQuestion.setOptionCount(0);
+        markQuestion.setQuestionType(QuestionType.QUESTION_ANSWER.getValue());
+        markQuestion.setDoubleRate(0D);// 单评为0,双评为1
+        markQuestion.setTotalScore(subjectiveStructDto.getTotalScore());
+        // 间隔分(整数默认1,小数默认0.5)
+        markQuestion.setIntervalScore(subjectiveStructDto.getIntervalScore());
+        markQuestions.add(markQuestion);
+
+        // 评卷员
+        String markerCodes = subjectiveStructDto.getMarkerCodes();
+        if (StringUtils.isNotBlank(markerCodes)) {
+            for (String code : markerCodes.split(SystemConstant.COMMA)) {
+                if (sysUserMap.containsKey(code.trim())) {
+                    MarkUserQuestion markUserQuestion = new MarkUserQuestion();
+                    markUserQuestion.setId(SystemConstant.getDbUuid());
+                    markUserQuestion.setExamId(examId);
+                    markUserQuestion.setPaperNumber(subjectiveStructDto.getPaperNumber());
+                    markUserQuestion.setQuestionId(markQuestion.getId());
+                    markUserQuestion.setUserId(sysUserMap.get(code.trim()).getId());
+                    markUserQuestion.setEnable(true);
+                    markUserQuestions.add(markUserQuestion);
+                } else {
+                    throw ExceptionResultEnum.ERROR.exception("工号" + code + "用户不存在");
+                }
+            }
+        }
+
+    }
 }

BIN
distributed-print/src/main/resources/temps/subjectiveStruct.xlsx


+ 1 - 0
teachcloud-common/src/main/java/com/qmth/teachcloud/common/contant/SystemConstant.java

@@ -345,6 +345,7 @@ public class SystemConstant {
 
     public static final String ERROR_DATA_LIST = "errorDataList";
     public static final String DATASOURCE = "datasource";
+    public static final String DATASOURCE1 = "datasource1";
     public static final String DATA_COUNT = "dataCount";
     public static final String SUCCESS_DATA_COUNT = "successDataCount";
     public static final String ERROR_DATA_COUNT = "errorDataCount";

+ 2 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkQuestionService.java

@@ -116,4 +116,6 @@ public interface MarkQuestionService extends IService<MarkQuestion> {
     MarkQuestionSubjectiveStepStatusDto stepStatus(Long examId, String paperNumber);
 
     void updatePic(String content, List<MarkQuestion> markQuestions);
+
+    List<MarkQuestion> listByExamIdAndObjective(Long examId, boolean objective);
 }

+ 8 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkQuestionServiceImpl.java

@@ -863,4 +863,12 @@ public class MarkQuestionServiceImpl extends ServiceImpl<MarkQuestionMapper, Mar
         }
     }
 
+    @Override
+    public List<MarkQuestion> listByExamIdAndObjective(Long examId, boolean objective) {
+        QueryWrapper<MarkQuestion> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(MarkQuestion::getExamId, examId)
+                .eq(MarkQuestion::getObjective, objective);
+        return this.list(queryWrapper);
+    }
+
 }

+ 14 - 3
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkServiceImpl.java

@@ -371,6 +371,17 @@ public class MarkServiceImpl implements MarkService {
         }
     }
 
+    private void checkStudentQuestionForInspect(MarkStudent markStudent, MarkQuestion markQuestion) {
+        Long studentId = markStudent.getId();
+        if (calculateQuestion(markQuestion, studentId)) {
+            //更新考生分组分数
+            updateStudentQuestionScore(studentId, markQuestion, markQuestion.getMarkScore());
+            checkStudentSubjective(studentId, markQuestion.getExamId(), markQuestion.getPaperNumber(), markStudent.getVersion());
+        } else {
+            markStudentService.updateSubjectiveStatusAndScore(studentId, SubjectiveStatus.UNMARK);
+        }
+    }
+
     @Override
     @Transactional
     public void checkStudentSubjective(Long studentId, Long examId, String paperNumber, Integer version) {
@@ -933,11 +944,11 @@ public class MarkServiceImpl implements MarkService {
                 markTaskService.updateHeaderResult(markStudent.getExamId(), markStudent.getPaperNumber(),
                         result.getQuestionId(), markStudent.getId(), userId, result.getMarkerScore(), result.getMarkerTrackList(), result.getMarkerTagList(), currentTime, MarkTaskStatus.MARKED);
                 updateMarkedCount(markStudent.getExamId(), markStudent.getPaperNumber(), result.getQuestionId());
-                resetStudentStatus(markStudent.getId());
+//                resetStudentStatus(markStudent.getId());
                 markStudentService.updateCheckInfo(markStudent.getId(), userId);
                 MarkQuestion markQuestion = markQuestionService.getById(result.getQuestionId());
                 markQuestion.setMarkScore(result.getMarkerScore());
-                checkStudentQuestion(markStudent.getId(), markQuestion);
+                checkStudentQuestionForInspect(markStudent, markQuestion);
             } catch (ApiException e) {
                 throw ExceptionResultEnum.ERROR.exception(e.getMessage());
             } finally {
@@ -996,7 +1007,7 @@ public class MarkServiceImpl implements MarkService {
         page.addOrder(orderItem);
         IPage<MarkTask> list = markTaskService.listPageHistory(page, userId, examId, paperNumber, secretNumber, markerScore, MarkTaskStatus.MARKED, MarkTaskStatus.ARBITRATED, MarkTaskStatus.WAIT_ARBITRATE, MarkTaskStatus.PROBLEM);
         List<Task> recordsDtos = new ArrayList<>();
-        List<MarkTaskStatus> markTaskStatuses = Arrays.asList(MarkTaskStatus.MARKED, MarkTaskStatus.WAIT_ARBITRATE, MarkTaskStatus.PROBLEM);
+        List<MarkTaskStatus> markTaskStatuses = Arrays.asList(MarkTaskStatus.MARKED, MarkTaskStatus.ARBITRATED, MarkTaskStatus.WAIT_ARBITRATE, MarkTaskStatus.PROBLEM);
         for (MarkTask markTask : list.getRecords()) {
             List<MarkTask> markTaskList = markTaskService.listByStudentIdAndMarkerId(markTask.getStudentId(), userId, markTaskStatuses);
             Task dto = taskService.build(userId, markTaskList);

+ 3 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkStudentServiceImpl.java

@@ -1235,6 +1235,9 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
         if (studentId != null) {
             Long userId = ServletUtil.getRequestUserId();
             MarkStudent markStudent = this.getById(studentId);
+            if (SubjectiveStatus.UNMARK.equals(markStudent.getSubjectiveStatus())) {
+                throw ExceptionResultEnum.ERROR.exception("数据正在统分中,请稍后再试");
+            }
             markService.releaseByStudent(markStudent);
             if (markService.applyStudent(markStudent, userId)) {
                 task = taskService.build(studentId);

+ 1 - 0
teachcloud-mark/src/main/resources/mapper/MarkUserQuestionMapper.xml

@@ -291,6 +291,7 @@
             <if test="paperNumber != null and paperNumber != ''">
                 and muq.paper_number = #{paperNumber}
             </if>
+                and muq.enable = true and mq.task_count > 0 and mq.task_count > mq.marked_count
         </where>
         group by
             muq.exam_id,