Selaa lähdekoodia

fix:客观题导入

caozixuan 1 vuosi sitten
vanhempi
commit
0db2799d96

+ 133 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/bean/dto/ObjectiveStructDto.java

@@ -0,0 +1,133 @@
+package com.qmth.distributed.print.business.bean.dto;
+
+import com.qmth.boot.tools.excel.annotation.ExcelColumn;
+import com.qmth.teachcloud.common.annotation.ExcelError;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @Description: 客观题结构Dto
+ * @Author: CaoZixuan
+ * @Date: 2024/04/08
+ */
+public class ObjectiveStructDto {
+
+    @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 String answer;
+
+    @ApiModelProperty(value = "小题满分")
+    @ExcelColumn(name = "小题满分", index = 8, nullable = true)
+    private Double totalScore;
+
+    @ApiModelProperty(value = "题型(1-单选,2-多选,3-判断)")
+    @ExcelColumn(name = "题型(1-单选,2-多选,3-判断)", index = 9, nullable = true)
+    private Integer questionType;
+
+    @ApiModelProperty(value = "错误信息")
+    @ExcelError
+    private String errorMsg;
+
+    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 String getAnswer() {
+        return answer;
+    }
+
+    public void setAnswer(String answer) {
+        this.answer = answer;
+    }
+
+    public Double getTotalScore() {
+        return totalScore;
+    }
+
+    public void setTotalScore(Double totalScore) {
+        this.totalScore = totalScore;
+    }
+
+    public Integer getQuestionType() {
+        return questionType;
+    }
+
+    public void setQuestionType(Integer questionType) {
+        this.questionType = questionType;
+    }
+
+    public String getErrorMsg() {
+        return errorMsg;
+    }
+
+    public void setErrorMsg(String errorMsg) {
+        this.errorMsg = errorMsg;
+    }
+}

+ 60 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/execute/SyncObjectiveStructImportService.java

@@ -0,0 +1,60 @@
+package com.qmth.distributed.print.business.templete.execute;
+
+import cn.hutool.core.date.DateUtil;
+import com.qmth.distributed.print.business.templete.importData.SyncImportTaskTemplate;
+import com.qmth.distributed.print.business.templete.service.TaskLogicService;
+import com.qmth.teachcloud.common.contant.SpringContextHolder;
+import com.qmth.teachcloud.common.contant.SystemConstant;
+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.service.TBTaskService;
+import com.qmth.teachcloud.common.util.Result;
+import com.qmth.teachcloud.common.util.ResultUtil;
+import org.springframework.stereotype.Service;
+
+import java.io.InputStream;
+import java.text.MessageFormat;
+import java.util.Date;
+import java.util.Map;
+import java.util.StringJoiner;
+
+/**
+ * @Description: 试卷客观题结构导入同步任务
+ * @Author: CaoZixuan
+ * @Date: 2024/04/08
+ */
+@Service
+public class SyncObjectiveStructImportService extends SyncImportTaskTemplate {
+
+    public static final String OBJ_TITLE = "客观题结构导入";
+
+    @Override
+    public Result importTask(Map<String, Object> map) throws Exception {
+        TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
+        StringJoiner stringJoinerSummary = new StringJoiner("\n").add(
+                MessageFormat.format("{0}{1}{2}", DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN),
+                        BEGIN_TITLE, OBJ_TITLE));
+        tbTask.setStatus(TaskStatusEnum.RUNNING);
+        TBTaskService tbTaskService = SpringContextHolder.getBean(TBTaskService.class);
+        tbTaskService.updateById(tbTask);
+        try (InputStream inputStream = super.getUploadFileInputStream(tbTask)) {
+            map.put("inputStream", inputStream);
+            TaskLogicService taskLogicService = SpringContextHolder.getBean(TaskLogicService.class);
+            // 执行导入考务数据
+            taskLogicService.executeImportObjectiveStructLogic(map);
+            tbTask.setResult(TaskResultEnum.SUCCESS);
+        } 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());
+            tbTask.setStatus(TaskStatusEnum.FINISH);
+            tbTaskService.updateById(tbTask);
+        }
+        return ResultUtil.ok();
+    }
+}

+ 11 - 3
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/service/TaskLogicService.java

@@ -1,6 +1,5 @@
 package com.qmth.distributed.print.business.templete.service;
 
-import com.qmth.distributed.print.business.bean.dto.MarkStudentImportDto;
 import com.qmth.teachcloud.common.entity.BasicExamStudent;
 
 import java.io.IOException;
@@ -142,7 +141,16 @@ public interface TaskLogicService {
     /**
      * 保存阅卷数据
      *
-     * @param examId                   考试id
+     * @param examId 考试id
      */
-    void saveMarkStudent(Long examId, List<BasicExamStudent> basicExamStudentList );
+    void saveMarkStudent(Long examId, List<BasicExamStudent> basicExamStudentList);
+
+    /**
+     * 处理客观题结构导入
+     *
+     * @param map 数据源
+     * @return 结果
+     * @throws Exception 异常
+     */
+    Map<String, Object> executeImportObjectiveStructLogic(Map<String, Object> map) throws Exception;
 }

+ 146 - 5
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/service/impl/TaskLogicServiceImpl.java

@@ -10,8 +10,6 @@ import com.google.common.reflect.TypeToken;
 import com.google.gson.Gson;
 import com.itextpdf.text.DocumentException;
 import com.qmth.boot.api.exception.ApiException;
-import com.qmth.teachcloud.common.bean.result.ExcelResult;
-import com.qmth.teachcloud.common.bean.vo.PrintPathVo;
 import com.qmth.distributed.print.business.bean.dto.*;
 import com.qmth.distributed.print.business.bean.examRule.CodeNameEnableValue;
 import com.qmth.distributed.print.business.bean.examRule.FieldsDto;
@@ -30,7 +28,9 @@ import com.qmth.teachcloud.common.bean.dto.excel.*;
 import com.qmth.teachcloud.common.bean.dto.excel.export.BasicStudentErrorExportDto;
 import com.qmth.teachcloud.common.bean.dto.excel.export.SysUserErrorExportDto;
 import com.qmth.teachcloud.common.bean.params.ArraysParams;
+import com.qmth.teachcloud.common.bean.result.ExcelResult;
 import com.qmth.teachcloud.common.bean.vo.PaperInfoVo;
+import com.qmth.teachcloud.common.bean.vo.PrintPathVo;
 import com.qmth.teachcloud.common.config.DictionaryConfig;
 import com.qmth.teachcloud.common.contant.SystemConstant;
 import com.qmth.teachcloud.common.entity.*;
@@ -39,14 +39,14 @@ import com.qmth.teachcloud.common.service.*;
 import com.qmth.teachcloud.common.util.*;
 import com.qmth.teachcloud.common.util.excel.ExcelError;
 import com.qmth.teachcloud.mark.entity.MarkPaper;
-import com.qmth.teachcloud.mark.entity.MarkStudent;
+import com.qmth.teachcloud.mark.params.MarkQuestionParams;
 import com.qmth.teachcloud.mark.service.MarkPaperService;
+import com.qmth.teachcloud.mark.service.MarkQuestionService;
 import com.qmth.teachcloud.mark.service.MarkStudentService;
 import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.time.DateUtils;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.Row;
@@ -71,7 +71,6 @@ import java.nio.charset.StandardCharsets;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 /**
  * @Description: 任务处理逻辑impl
@@ -151,6 +150,8 @@ public class TaskLogicServiceImpl implements TaskLogicService {
     MarkPaperService markPaperService;
     @Resource
     MarkStudentService markStudentService;
+    @Resource
+    MarkQuestionService markQuestionService;
 
     /**
      * 创建pdf前置条件
@@ -2317,6 +2318,146 @@ public class TaskLogicServiceImpl implements TaskLogicService {
         }
     }
 
+    @Transactional
+    @Override
+    public Map<String, Object> executeImportObjectiveStructLogic(Map<String, Object> map) throws Exception {
+        SysUser requestUser = (SysUser) map.get(SystemConstant.USER);
+        InputStream inputStream = (InputStream) map.get("inputStream");
+        Long examId = SystemConstant.convertIdToLong(String.valueOf(map.get("examId")));
+        Long schoolId = requestUser.getSchoolId();
+        BasicExam basicExam = basicExamService.getById(examId);
+        if (Objects.isNull(basicExam)) {
+            throw ExceptionResultEnum.ERROR.exception("考试不存在");
+        }
+        if (!ExamModelEnum.MODEL4.equals(basicExam.getExamModel())) {
+            throw ExceptionResultEnum.ERROR.exception("仅针对模式4的考试可以导入");
+        }
+        // 课程编号名称校验
+        Map<String, String> courseCheckMap = basicCourseService.list(
+                        new QueryWrapper<BasicCourse>().lambda().eq(BasicCourse::getSchoolId, schoolId)).stream()
+                .collect(Collectors.toMap(BasicCourse::getCode, BasicCourse::getName));
+        List<MarkPaper> markPaperList = markPaperService.list(
+                new QueryWrapper<MarkPaper>().lambda().eq(MarkPaper::getExamId, examId));
+        // 题号重复校验
+        Set<String> paperCheckSet = new HashSet<>();
+
+        ExcelResult<ObjectiveStructDto> excelResult = ConvertUtil.analyzeExcel(inputStream, ObjectiveStructDto.class,
+                true, 0);
+        List<ObjectiveStructDto> objectiveStructDtoList = excelResult.getDatasource();
+        List<MarkQuestion> markQuestionList = new ArrayList<>();
+        for (ObjectiveStructDto objectiveStructDto : objectiveStructDtoList) {
+            List<String> logicErrorList = new ArrayList<>();
+            // 公共异常提示
+            String logicErrorCommonNotice = "";
+
+            // 行索引
+            String courseCode = objectiveStructDto.getCourseCode();
+            String courseName = objectiveStructDto.getCourseName();
+            String paperNumber = objectiveStructDto.getPaperNumber();
+            String mainTitle = objectiveStructDto.getMainTitle();
+            Integer mainNumber = objectiveStructDto.getMainNumber();
+            Integer subNumber = objectiveStructDto.getSubNumber();
+            String answer = objectiveStructDto.getAnswer();
+            Double totalScore = objectiveStructDto.getTotalScore();
+            Integer questionType = objectiveStructDto.getQuestionType();
+            String errorMsg = objectiveStructDto.getErrorMsg();
+
+            // 1.判断题号重复
+            if (SystemConstant.strNotNull(paperNumber) && mainNumber != null && subNumber != null) {
+                logicErrorCommonNotice = String.format("试卷编号为[%s],大题号为[%s],小题号为[%s]的数据异常 : ", paperNumber, mainNumber,
+                        subNumber);
+                String questionKey = paperNumber + SystemConstant.HYPHEN + mainNumber + SystemConstant.HYPHEN + subNumber;
+                if (paperCheckSet.contains(questionKey)) {
+                    logicErrorList.add("题号重复");
+                } else {
+                    paperCheckSet.add(questionKey);
+                }
+            }
+
+            // 2.校验课程编号,课程名称,试卷在考试下是否存在
+            if (SystemConstant.strNotNull(courseCode) && SystemConstant.strNotNull(courseName) && SystemConstant.strNotNull(paperNumber)) {
+                if (!courseCheckMap.containsKey(courseCode)) {
+                    logicErrorList.add("课程编号不存在");
+                } else if (!courseCheckMap.get(courseCode).equals(courseName)) {
+                    logicErrorList.add("课程编号名称不匹配");
+                }
+                if (markPaperList.stream().noneMatch(m -> m.getPaperNumber().equals(paperNumber) && m.getCourseCode().equals(courseCode))) {
+                    logicErrorList.add("试卷不存在");
+                }
+            }
+            // 3.客观题答案必须是OptionsEnum中的编号
+            if (SystemConstant.strNotNull(answer)) {
+                for (String s : answer.split("")) {
+                    if (OptionsEnum.getByCode(s) == null) {
+                        logicErrorList.add("客观题答案必须是[A-Z]中的大写英文字母");
+                        break;
+                    }
+                }
+            }
+
+            // 4.判断答案是否符合题型
+            if (questionType != null && SystemConstant.strNotNull(answer)) {
+                //单选题的答案只能有一个
+                if (Objects.equals(QuestionType.SINGLE.getValue(), questionType)) {
+                    if (answer.length() > 1) {
+                        logicErrorList.add("单选题答案只能有一个");
+                    }
+                }
+                //判断题的答案只能为A&B
+                if (Objects.equals(QuestionType.TRUE_OR_FALSE.getValue(), questionType)) {
+                    if (!OptionsEnum.A.getCode().equals(answer) && !OptionsEnum.B.getCode().equals(answer)) {
+                        logicErrorList.add("判断题答案只能为A&B");
+                    }
+                }
+            }
+
+            // 整理异常信息
+            if (CollectionUtils.isNotEmpty(logicErrorList)) {
+                errorMsg = errorMsg + logicErrorCommonNotice + String.join(";", logicErrorList);
+                objectiveStructDto.setErrorMsg(errorMsg);
+            } else {
+                MarkQuestion markQuestion = new MarkQuestion();
+                markQuestion.setExamId(examId);
+                markQuestion.setPaperNumber(paperNumber);
+                markQuestion.setPaperType(OptionsEnum.A.getCode());
+                markQuestion.setObjective(true);
+                markQuestion.setMainNumber(mainNumber);
+                markQuestion.setSubNumber(subNumber);
+                markQuestion.setMainTitle(mainTitle);
+                markQuestion.setAnswer(answer);
+                markQuestion.setTotalScore(totalScore);
+                markQuestion.setObjectivePolicy(ObjectivePolicy.NONE);
+                markQuestion.setQuestionType(questionType);
+                markQuestionList.add(markQuestion);
+            }
+        }
+
+        if (objectiveStructDtoList.stream().anyMatch(e -> SystemConstant.strNotNull(e.getErrorMsg()))) {
+            // 抛出excel解析异常
+            throw ExceptionResultEnum.ERROR.exception(
+                    objectiveStructDtoList.stream().map(ObjectiveStructDto::getErrorMsg).filter(SystemConstant::strNotNull).collect(Collectors.joining(System.lineSeparator())));
+        } else {
+            // 保存客观题结构
+            Map<String, List<MarkQuestion>> markQuestionMap = markQuestionList.stream().collect(Collectors.groupingBy(MarkQuestion::getPaperNumber));
+            markQuestionMap.forEach((k, v) -> {
+                // 优先删除该试卷编号下的客观题
+                markQuestionService.remove(new QueryWrapper<MarkQuestion>().lambda().eq(MarkQuestion::getExamId, examId)
+                        .eq(MarkQuestion::getPaperNumber, k).eq(MarkQuestion::getObjective, true));
+
+                MarkQuestionParams markQuestionParams = new MarkQuestionParams();
+                markQuestionParams.setQuestions(v);
+                markQuestionParams.setExamId(examId);
+                markQuestionParams.setPaperNumber(k);
+                try {
+                    markQuestionService.saveQuestions(markQuestionParams);
+                } catch (Exception e) {
+                    throw ExceptionResultEnum.ERROR.exception(e.getMessage());
+                }
+            });
+        }
+        return map;
+    }
+
     /**
      * 验证机构是否存在
      *

+ 5 - 0
distributed-print-business/src/main/resources/db/log/脚本-caozx.sql

@@ -0,0 +1,5 @@
+-- 2024/04/08
+INSERT INTO sys_privilege (id, name, url, type, parent_id, sequence, property, enable, default_auth, front_display) VALUES ('1135', '客观题导入', '/api/admin/mark/setting/objective_struct/import', 'URL', '897', '17', 'AUTH', '1', '1', '1');
+INSERT INTO sys_privilege (id, name, url, type, parent_id, sequence, property, enable, default_auth, front_display) VALUES ('1136', '主观题导入', '/api/admin/mark/setting/subjective_struct/import', 'URL', '897', '18', 'AUTH', '1', '1', '1');
+INSERT INTO sys_privilege (id, name, url, type, parent_id, sequence, property, related, enable, default_auth, front_display) VALUES ('1137', '客观题导入', 'ObjectiveStructImport', 'BUTTON', '897', '6', 'AUTH', '1135', '1', '0', '1');
+INSERT INTO sys_privilege (id, name, url, type, parent_id, sequence, property, related, enable, default_auth, front_display) VALUES ('1138', '主观题导入', 'SubjectiveStructImport', 'BUTTON', '897', '7', 'AUTH', '1136', '1', '0', '1');

+ 18 - 1
distributed-print/src/main/java/com/qmth/distributed/print/api/mark/MarkSettingController.java

@@ -1,14 +1,16 @@
 package com.qmth.distributed.print.api.mark;
 
-
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.qmth.boot.api.constant.ApiConstant;
 import com.qmth.distributed.print.business.entity.ExamTaskDetail;
 import com.qmth.distributed.print.business.service.ExamTaskDetailService;
+import com.qmth.distributed.print.business.service.PrintCommonService;
+import com.qmth.distributed.print.business.templete.execute.SyncObjectiveStructImportService;
 import com.qmth.teachcloud.common.annotation.OperationLogDetail;
 import com.qmth.teachcloud.common.bean.dto.mark.MarkSettingDto;
 import com.qmth.teachcloud.common.bean.vo.PaperInfoVo;
 import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.enums.TaskTypeEnum;
 import com.qmth.teachcloud.common.enums.log.CustomizedOperationTypeEnum;
 import com.qmth.teachcloud.common.util.ExamTaskUtil;
 import com.qmth.teachcloud.common.util.Result;
@@ -24,12 +26,14 @@ import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
 import org.apache.commons.collections4.CollectionUtils;
 import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.constraints.Max;
 import javax.validation.constraints.Min;
 import java.util.List;
+import java.util.Map;
 
 /**
  * <p>
@@ -50,6 +54,10 @@ public class MarkSettingController {
     private MarkTaskService markTaskService;
     @Resource
     private ExamTaskDetailService examTaskDetailService;
+    @Resource
+    private PrintCommonService printCommonService;
+    @Resource
+    private SyncObjectiveStructImportService syncObjectiveStructImportService;
 
     /**
      * 评卷设置数据列表
@@ -129,4 +137,13 @@ public class MarkSettingController {
                 paperNumber, pageNumber, pageSize);
         return ResultUtil.ok(scoreListDtoIPage);
     }
+
+    @ApiOperation(value = "客观题导入")
+    @RequestMapping(value = "/objective_struct/import", method = RequestMethod.POST)
+    public Result objectiveStructImport(@ApiParam(value = "考试ID", required = true) @RequestParam String examId,
+            @ApiParam(value = "标答excel文件",required = true) @RequestParam MultipartFile file) throws Exception {
+        Map<String, Object> map = printCommonService.saveTask(file, SystemConstant.convertIdToLong(examId), TaskTypeEnum.OBJECTIVE_STRUCT_IMPORT);
+        map.put("examId", SystemConstant.convertIdToLong(examId));
+        return syncObjectiveStructImportService.importTask(map);
+    }
 }

+ 21 - 6
teachcloud-common/src/main/java/com/qmth/teachcloud/common/bean/result/ExcelResult.java

@@ -3,6 +3,8 @@ package com.qmth.teachcloud.common.bean.result;
 import io.swagger.annotations.ApiModelProperty;
 
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * @Description: excel结果
@@ -17,8 +19,11 @@ public class ExcelResult<T> {
     @ApiModelProperty("是否成功")
     private boolean success;
 
-    @ApiModelProperty("报错信息")
-    private String errorMsg;
+    /**
+     * 报错信息map : key为行数,value为报错信息
+     */
+    @ApiModelProperty("报错信息map")
+    private Map<Integer, String> errorMap;
 
     public List<T> getDatasource() {
         return datasource;
@@ -36,11 +41,21 @@ public class ExcelResult<T> {
         this.success = success;
     }
 
-    public String getErrorMsg() {
-        return errorMsg;
+    public Map<Integer, String> getErrorMap() {
+        return errorMap;
+    }
+
+    public void setErrorMap(Map<Integer, String> errorMap) {
+        this.errorMap = errorMap;
     }
 
-    public void setErrorMsg(String errorMsg) {
-        this.errorMsg = errorMsg;
+    /**
+     * 获取报错信息
+     *
+     * @return 报错文本信息
+     */
+    public String getErrorMsg() {
+        return errorMap.entrySet().stream().map(entry -> String.format("第[%s]行,%s", entry.getKey(), entry.getValue()))
+                .collect(Collectors.joining(System.lineSeparator()));
     }
 }

+ 3 - 1
teachcloud-common/src/main/java/com/qmth/teachcloud/common/enums/TaskTypeEnum.java

@@ -25,7 +25,9 @@ public enum TaskTypeEnum {
     STATISTICS_IMPORT("命题统计导入"),
     SCORE_EXPORT("成绩导出"),
     SCORE_DOWNLOAD("成绩轨迹下载"),
-    DOWNLOAD_PAPER_FILE_BATCH("批量下载试卷文件");
+    DOWNLOAD_PAPER_FILE_BATCH("批量下载试卷文件"),
+    OBJECTIVE_STRUCT_IMPORT("客观题导入"),
+    SUBJECTIVE_STRUCT_IMPORT("主观题导入");
 
     private String title;
 

+ 9 - 9
teachcloud-common/src/main/java/com/qmth/teachcloud/common/util/ConvertUtil.java

@@ -57,13 +57,15 @@ public class ConvertUtil {
         String endTimeStr = date + " " + arr[1];
         if (Objects.isNull(DateDisposeUtils.parseDate(startTimeStr)) || Objects.isNull(DateDisposeUtils.parseDate(endTimeStr))) {
             throw ExceptionResultEnum.ERROR.exception(
-                    "提供的日期时间格式异常(考试日期列应使用文本格式) \n考试日期[" + date + "]应该使用如下的格式(考试日期:2021-09-01 或 2021/09/01 或 2021.09.01)" + "\n考试时间[" + time + "]应该使用如下的格式(考试时间:18:00-20:00)");
+                    "提供的日期时间格式异常(考试日期列应使用文本格式) \n考试日期[" + date + "]应该使用如下的格式(考试日期:2021-09-01 或 2021/09/01 或 2021.09.01)"
+                            + "\n考试时间[" + time + "]应该使用如下的格式(考试时间:18:00-20:00)");
         }
         long startTime = DateDisposeUtils.parseDate(startTimeStr).getTime();
         long endTime = DateDisposeUtils.parseDate(endTimeStr).getTime();
-        if (!SystemConstant.longNotNull(startTime) || !SystemConstant.longNotNull(endTime)){
+        if (!SystemConstant.longNotNull(startTime) || !SystemConstant.longNotNull(endTime)) {
             throw ExceptionResultEnum.ERROR.exception(
-                    "提供的日期时间格式异常(考试日期列应使用文本格式) \n考试日期[" + date + "]应该使用如下的格式(考试日期:2021-09-01 或 2021/09/01 或 2021.09.01)" + "\n考试时间[" + time + "]应该使用如下的格式(考试时间:18:00-20:00)");
+                    "提供的日期时间格式异常(考试日期列应使用文本格式) \n考试日期[" + date + "]应该使用如下的格式(考试日期:2021-09-01 或 2021/09/01 或 2021.09.01)"
+                            + "\n考试时间[" + time + "]应该使用如下的格式(考试时间:18:00-20:00)");
         }
         if (startTime >= endTime) {
             throw ExceptionResultEnum.ERROR.exception("开始时间要小于结束时间 时间: " + time);
@@ -154,7 +156,7 @@ public class ConvertUtil {
         ExcelReader excelReader = ExcelReader.create(ExcelType.XLSX, inputStream, columnNameRow);
         List<String[]> excelDatasource = excelReader.getDataArrayList();
         List<T> dtoList = new ArrayList<>();
-        List<String> errorMsgList = new ArrayList<>();
+        Map<Integer, String> errorMap = new HashMap<>();
         AtomicInteger rowIndex = new AtomicInteger(columnNameRow + 1);
         if (CollectionUtils.isNotEmpty(excelDatasource)) {
             List<String> columnNameList = Arrays.asList(excelReader.getColumnNames());
@@ -212,12 +214,12 @@ public class ConvertUtil {
                 if (CollectionUtils.isNotEmpty(excelErrorList)) {
                     // 有异常数据
                     analyzeResult = false;
-                    String errorMsg = String.join(",", excelErrorList);
+                    String errorMsg = String.format("第[%s]行,%s", index, String.join(",", excelErrorList));
                     if (fillError && Objects.nonNull(errorField)) {
                         errorField.setAccessible(true);
                         errorField.set(dto, errorMsg);
                     }
-                    errorMsgList.add(String.format("第[%s]行异常:[%s]", index, errorMsg));
+                    errorMap.put(index, errorMsg);
                 }
                 dtoList.add(dto);
             }
@@ -225,9 +227,7 @@ public class ConvertUtil {
         ExcelResult<T> excelResult = new ExcelResult<>();
         excelResult.setSuccess(analyzeResult);
         excelResult.setDatasource(dtoList);
-        if (CollectionUtils.isNotEmpty(errorMsgList)) {
-            excelResult.setErrorMsg(String.join(";\n", errorMsgList));
-        }
+        excelResult.setErrorMap(errorMap);
         return excelResult;
     }