xiaofei il y a 11 mois
Parent
commit
a20bc18cac

+ 3 - 2
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/execute/AsyncDownloadPaperFileBatchService.java

@@ -3,6 +3,7 @@ package com.qmth.distributed.print.business.templete.execute;
 import cn.hutool.core.date.DateUtil;
 import com.qmth.boot.api.exception.ApiException;
 import com.qmth.distributed.print.business.templete.export.AsyncExportTaskTemplete;
+import com.qmth.distributed.print.business.templete.service.DownloadLogicService;
 import com.qmth.distributed.print.business.templete.service.TaskLogicService;
 import com.qmth.teachcloud.common.contant.SpringContextHolder;
 import com.qmth.teachcloud.common.contant.SystemConstant;
@@ -42,8 +43,8 @@ public class AsyncDownloadPaperFileBatchService extends AsyncExportTaskTemplete
         TBTaskService tbTaskService = SpringContextHolder.getBean(TBTaskService.class);
         tbTaskService.updateById(tbTask);
         try {
-            TaskLogicService taskLogicService = SpringContextHolder.getBean(TaskLogicService.class);
-            Map<String, Object> result = taskLogicService.executeDownloadPaperFileBatch(map);
+            DownloadLogicService downloadLogicService = SpringContextHolder.getBean(DownloadLogicService.class);
+            Map<String, Object> result = downloadLogicService.executeDownloadPaperFileBatch(map);
 
             // 特殊的成功信息
             stringJoinerSummary.add(MessageFormat.format("{0}{1}{2}{3}", DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN), FINISH_TITLE, result.containsKey("count") ? Long.valueOf(String.valueOf(result.get("count"))) : "", FINISH_SIZE));

+ 76 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/service/DownloadLogicService.java

@@ -0,0 +1,76 @@
+package com.qmth.distributed.print.business.templete.service;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * @Description: 任务处理逻辑
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2021/3/29
+ */
+public interface DownloadLogicService {
+
+    /**
+     * 处理考务数据逻辑
+     *
+     * @param map 参数
+     * @return 要导出的考务数据
+     */
+    Map<String, Object> executeExaminationLogic(Map<String, Object> map) throws Exception;
+
+    Map<String, Object> executeImportExaminationLogic(Map<String, Object> map) throws Exception;
+
+    /**
+     * 下载pdf
+     *
+     * @param map
+     * @return
+     * @throws IOException
+     */
+    Map<String, Object> executeDownloadPdfLogic(Map<String, Object> map) throws Exception;
+    /**
+     * 导出试卷、题卡pdf
+     *
+     * @param map
+     * @return
+     */
+    Map<String, Object> executeExportPaperAndCardLogic(Map<String, Object> map) throws Exception;
+
+    /**
+     * 处理导入用户数据
+     *
+     * @param map 数据源
+     * @return 结果
+     * @throws Exception 异常
+     */
+    Map<String, Object> executeImportSysUserLogic(Map<String, Object> map) throws Exception;
+
+    /**
+     * 处理命题统计导入数据
+     *
+     * @param map 数据源
+     * @return 结果
+     * @throws Exception 异常
+     */
+    Map<String, Object> executeImportStatisticsLogic(Map<String, Object> map) throws Exception;
+
+    /**
+     * 成绩导出
+     *
+     * @param map
+     * @return
+     */
+    Map<String, Object> executeExportScoreLogic(Map<String, Object> map) throws Exception;
+
+    /**
+     * 成绩轨迹下载
+     *
+     * @param map
+     * @return
+     */
+    Map<String, Object> executeDownloadScoreLogic(Map<String, Object> map) throws Exception;
+
+    Map<String, Object> executeDownloadPaperFileBatch(Map<String, Object> map) throws Exception;
+}

+ 1327 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/service/impl/DownloadLogicServiceImpl.java

@@ -0,0 +1,1327 @@
+package com.qmth.distributed.print.business.templete.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.google.common.collect.Lists;
+import com.google.common.reflect.TypeToken;
+import com.google.gson.Gson;
+import com.qmth.boot.api.exception.ApiException;
+import com.qmth.distributed.print.business.bean.dto.*;
+import com.qmth.distributed.print.business.bean.params.DownloadPaperFileParam;
+import com.qmth.distributed.print.business.bean.result.TSyncExamStudentScoreResult;
+import com.qmth.distributed.print.business.entity.*;
+import com.qmth.distributed.print.business.enums.ImageTrajectoryEnum;
+import com.qmth.distributed.print.business.enums.PaperFileDownloadContentEnum;
+import com.qmth.distributed.print.business.enums.PaperFileDownloadExposureStatusEnum;
+import com.qmth.distributed.print.business.enums.PrintPlanStatusEnum;
+import com.qmth.distributed.print.business.service.*;
+import com.qmth.distributed.print.business.templete.service.DownloadLogicService;
+import com.qmth.distributed.print.business.templete.service.TaskLogicService;
+import com.qmth.distributed.print.business.util.CreatePdfUtil;
+import com.qmth.teachcloud.common.annotation.ExcelDBFieldDesc;
+import com.qmth.teachcloud.common.base.BaseEntity;
+import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
+import com.qmth.teachcloud.common.bean.dto.excel.DescribeImportDto;
+import com.qmth.teachcloud.common.bean.dto.excel.StatisticsImportDto;
+import com.qmth.teachcloud.common.bean.dto.excel.SysUserImportDto;
+import com.qmth.teachcloud.common.bean.dto.excel.export.SysUserErrorExportDto;
+import com.qmth.teachcloud.common.bean.examRule.CodeNameEnableValue;
+import com.qmth.teachcloud.common.bean.examRule.FieldsDto;
+import com.qmth.teachcloud.common.bean.params.ArraysParams;
+import com.qmth.teachcloud.common.bean.result.DictionaryResult;
+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.*;
+import com.qmth.teachcloud.common.enums.*;
+import com.qmth.teachcloud.common.service.*;
+import com.qmth.teachcloud.common.util.*;
+import com.qmth.teachcloud.common.util.excel.ExcelError;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.FileCopyUtils;
+import org.springframework.util.LinkedMultiValueMap;
+
+import javax.annotation.Resource;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+
+/**
+ * @Description: 任务处理逻辑impl
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2021/3/29
+ */
+@Service
+public class DownloadLogicServiceImpl implements DownloadLogicService {
+    private final static Logger log = LoggerFactory.getLogger(DownloadLogicServiceImpl.class);
+
+    @Resource
+    ExamPrintPlanService examPrintPlanService;
+    @Resource
+    ExamTaskService examTaskService;
+    @Resource
+    ExamTaskDetailService examTaskDetailService;
+    @Resource
+    ExamCardService examCardService;
+    @Resource
+    BasicAttachmentService basicAttachmentService;
+    @Resource
+    ExamDetailService examDetailService;
+    @Resource
+    BasicCourseService basicCourseService;
+    @Resource
+    CreatePdfUtil createPdfUtil;
+    @Resource
+    TBTaskPdfService tbTaskPdfService;
+    @Resource
+    BasicRoleDataPermissionService basicRoleDataPermissionService;
+    @Resource
+    SysUserService sysUserService;
+    @Resource
+    FileStoreUtil fileStoreUtil;
+    @Resource
+    SysOrgService sysOrgService;
+    @Resource
+    TCStatisticsService tcStatisticsService;
+    @Resource
+    TCStatisticsTempService tcStatisticsTempService;
+    @Resource
+    TSyncExamStudentScoreService tSyncExamStudentScoreService;
+    @Resource
+    @Lazy
+    PrintCommonService printCommonService;
+    @Resource
+    DownloadService downloadService;
+    @Resource
+    TeachClazzService teachClazzService;
+    @Resource
+    DictionaryConfig dictionaryConfig;
+    @Resource
+    FileUploadService fileUploadService;
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public Map<String, Object> executeExaminationLogic(Map<String, Object> map) throws Exception {
+        List<ExaminationExportDto> examinationExportDtoList = examDetailService.findExaminationExportDtoDatasource(map);
+
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        ExcelUtil.excelMake(ExaminationExportDto.class, examinationExportDtoList, outputStream);
+        InputStream in = new ByteArrayInputStream(outputStream.toByteArray());
+
+        StringJoiner stringJoiner = SystemConstant.getDirName(UploadFileEnum.FILE, true);
+        stringJoiner.add(SystemConstant.getNanoId()).add(".").add(SystemConstant.XLSX);
+
+        JSONObject jsonObject = new JSONObject();
+        String dirName = FileUtil.replaceSplit(stringJoiner.toString());
+        boolean oss = dictionaryConfig.sysDomain().isOss();
+        if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {//上传至oss
+            fileStoreUtil.ossUpload(dirName, in, DigestUtils.md5Hex(new ByteArrayInputStream(outputStream.toByteArray())), fileStoreUtil.getUploadEnumByPath(dirName).getFssType());
+            jsonObject.put(SystemConstant.TYPE, oss ? SystemConstant.OSS : SystemConstant.LOCAL);
+            jsonObject.put(SystemConstant.PATH, dirName);
+        } else {
+            dirName = FileUtil.replaceSplit((dictionaryConfig.fssPublicDomain().getConfig() + File.separator + dirName));
+            fileStoreUtil.copyInputStreamToFile(in, new File(stringJoiner.toString()), DigestUtils.md5Hex(new ByteArrayInputStream(outputStream.toByteArray())), LocalCatalogEnum.LOCAL_FILE);
+            jsonObject.put(SystemConstant.TYPE, SystemConstant.LOCAL);
+            jsonObject.put(SystemConstant.PATH, dirName);
+        }
+        jsonObject.put(SystemConstant.UPLOAD_TYPE, UploadFileEnum.FILE);
+        map.put(SystemConstant.PATH, jsonObject.toString());
+        map.put(SystemConstant.DATA_COUNT, examinationExportDtoList.size());
+        return map;
+    }
+
+    @Transactional
+    @Override
+    public Map<String, Object> executeImportExaminationLogic(Map<String, Object> map) throws Exception {
+        SysUser sysUser = (SysUser) map.get(SystemConstant.USER);
+        TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
+        InputStream inputStream = (InputStream) map.get("inputStream");
+        Long printPlanId = tbTask.getPrintPlanId();
+        Long schoolId = tbTask.getSchoolId();
+        ExamPrintPlan examPrintPlan = examPrintPlanService.getById(printPlanId);
+        if (examPrintPlan == null) {
+            throw ExceptionResultEnum.ERROR.exception("印刷计划不存在");
+        }
+
+        String printPlanName = examPrintPlan.getName();
+        if (!tbTaskPdfService.countByPrintPlanIdAndEntityId(schoolId, printPlanId)) {
+            throw ExceptionResultEnum.ERROR.exception("印刷计划[" + printPlanName + "]有考场正在生成PDF文件,无法导入考务数据");
+        }
+        PrintPlanStatusEnum printPlanStatus = examPrintPlan.getStatus();
+        if (PrintPlanStatusEnum.NEW != printPlanStatus && PrintPlanStatusEnum.READY != printPlanStatus) {
+            throw ExceptionResultEnum.ERROR.exception("印刷计划状态为[" + PrintPlanStatusEnum.NEW.getName() + "、" + PrintPlanStatusEnum.READY.getName() + "]时才可导入,当前状态[" + printPlanStatus.getName() + "]");
+        }
+        // 该学校有效考务规则字段
+        List<FieldsDto> fieldsDtoList = examDetailService.findExaminationFields(schoolId);
+
+        String importFilePath = tbTask.getImportFilePath();
+        Map importFilePathMap = JSONObject.parseObject(importFilePath);
+        String path = String.valueOf(importFilePathMap.get(SystemConstant.PATH));
+        Workbook workbook;
+        if (path.endsWith(SystemConstant.XLSX)) {
+            workbook = new XSSFWorkbook(inputStream);
+        } else if (path.endsWith(SystemConstant.XLS)) {
+            workbook = new HSSFWorkbook(inputStream);
+        } else {
+            throw ExceptionResultEnum.ERROR.exception("不支持的文件格式。只允许上传后缀为" + SystemConstant.XLSX + "、" + SystemConstant.XLS + "的文件");
+        }
+        // 读取第一个工作表
+        Sheet sheet = workbook.getSheetAt(0);
+        if (sheet.getLastRowNum() == 0 && sheet.getPhysicalNumberOfRows() == 0) {
+            throw ExceptionResultEnum.ERROR.exception("第一个sheet为空,考务数据必须放在第一个sheet(工作表)内");
+        }
+        // 第一行为说明内容,不能为空
+        if (sheet.getRow(0) == null || !sheet.getRow(0).getCell(0).getStringCellValue().startsWith("说明")) {
+            throw ExceptionResultEnum.ERROR.exception("表格第一行为说明内容,不能为空,且必须以\"说明\"开头");
+        }
+        // 第二行为表头,不能为空,且校验第一列为学号
+//        if (sheet.getRow(1) == null || !"学号".equals(sheet.getRow(1).getCell(0).getStringCellValue())) {
+//            throw ExceptionResultEnum.ERROR.exception("表格第二行为表头,不能为空,且第一列必须为\"学号\"");
+//        }
+        // 获取sheet行数
+        int totalRows = sheet.getLastRowNum() + 1;
+        // 获取sheet列数(列数从第二行开始记录,因为第一行是说明内容)
+        int totalCells = 0;
+        if (totalRows > 2 && sheet.getRow(1) != null) {
+            totalCells = sheet.getRow(1).getPhysicalNumberOfCells();
+        }
+        // 获取sheet的title(第二行为表头)
+        Row head = sheet.getRow(1);
+        List<String> headList = new ArrayList<>();
+        // 将必填字段匹配excel解析的表头索引
+        for (int i = 0; i < totalCells; i++) {
+            String cellValue = String.valueOf(ExcelUtil.convert(head.getCell(i)));
+            for (FieldsDto fieldsDto : fieldsDtoList) {
+                if (cellValue.equals(fieldsDto.getName())) {
+                    // 如果通用规则必填字段和excel表头匹配上了,则为该必选字段设置其在excel中的索引,并跳出循环体
+                    fieldsDto.setIndex(i);
+                    break;
+                }
+            }
+            headList.add(cellValue);
+        }
+
+        // 搜索所有有效字段 excel中的表头是否包含
+        for (FieldsDto fieldsDto : fieldsDtoList) {
+            if (!headList.contains(fieldsDto.getName())) {
+                throw ExceptionResultEnum.ERROR.exception("考务数据必填字段[" + fieldsDto.getName() + "]在表头中不存在");
+            }
+        }
+
+        List<ExaminationImportDto> examinationImportDtoList = new ArrayList<>();
+
+        // 文件中课程代码对应的课程名称Map
+        Map<String, String> courseCodeNameInExcelMap = new HashMap<>();
+        // 课程管理中课程代码-课程名
+        Map<String, String> courseCodeNameInBasicCourseMap = new HashMap<>();
+        List<BasicCourse> basicCourseList = basicCourseService.list(new QueryWrapper<BasicCourse>().lambda().eq(BasicCourse::getSchoolId, schoolId));
+        basicCourseList.forEach(e -> {
+            courseCodeNameInBasicCourseMap.put(e.getCode(), e.getName());
+        });
+        // 文件中试卷编号对应多个课程代码
+        Map<String, String> paperNumberWithCourseCodeInExcelMap = new HashMap<>();
+        // 试卷编号在考试下有多个命题任务map
+        Map<String, Integer> paperNumberWithExamTaskMap = new HashMap<>();
+        Map<String, String> paperNumberCoureseSequenceMap = new HashMap<>();
+        // 命题任务中试卷编号对应的课程代码map
+        Map<String, String> paperNumberWithCourseCodeInExamTaskMap = new HashMap<>();
+
+        Long examId = examPrintPlan.getExamId();
+        List<ExamTask> examTaskList = examTaskService.list(new QueryWrapper<ExamTask>()
+                .lambda()
+                .eq(ExamTask::getSchoolId, schoolId)
+                .eq(ExamTask::getExamId, examId));
+        for (ExamTask examTask : examTaskList) {
+            String paperNumber = examTask.getPaperNumber();
+            String courseCode = examTask.getCourseCode();
+            paperNumberWithCourseCodeInExamTaskMap.put(paperNumber, courseCode);
+            if (paperNumberWithExamTaskMap.containsKey(paperNumber)) {
+                int count = paperNumberWithExamTaskMap.get(paperNumber);
+                paperNumberWithExamTaskMap.put(paperNumber, count);
+            } else {
+                paperNumberWithExamTaskMap.put(paperNumber, 1);
+            }
+
+            paperNumberCoureseSequenceMap.put(paperNumber, String.valueOf(examTask.getId()));
+        }
+
+        // 从第三行开始为数据(第一行说明,第二行表头,第三行往后为数据)
+        for (int r = 2; r < totalRows; r++) {
+            // excel中的数据错误
+            StringJoiner errorRowDate = new StringJoiner(";\r\n");
+            Row row = sheet.getRow(r);
+            if (row == null || ExcelUtil.isRowAllCellEmpty(row, head)) {
+                // excel中整行为空,直接跳过
+                continue;
+            }
+
+            // 备选字段
+            List<FieldsDto> secondaryFieldList = new ArrayList<>();
+
+            ExaminationImportDto examinationImportDto = new ExaminationImportDto();
+            Field[] examinationImportDtoFields = examinationImportDto.getClass().getDeclaredFields();
+            List<CodeNameEnableValue> requiredFields = new ArrayList<>();
+            for (FieldsDto fieldsDto : fieldsDtoList) {
+                boolean match = false;
+                String name = fieldsDto.getName();
+                String code = fieldsDto.getCode();
+                int index = fieldsDto.getIndex();
+                String level = fieldsDto.getLevel();
+
+                if (Objects.nonNull(row)) {
+                    Cell cell = row.getCell(index);
+                    String cellValue = cell == null ? null : String.valueOf(ExcelUtil.convert(cell));
+                    if (cellValue == null || cellValue.length() < 1 || cellValue.equals("null")) {
+                        cellValue = "";
+                        errorRowDate.add("第" + (r + 1) + "行,第" + (index + 1) + "列,字段[" + name + "]必填");
+                    }
+
+                    for (Field examinationImportDtoField : examinationImportDtoFields) {
+                        ExcelDBFieldDesc excelDBFieldDesc = examinationImportDtoField.getAnnotation(ExcelDBFieldDesc.class);
+                        if (excelDBFieldDesc == null) {
+                            // 如果没有注解,说明该数据库必须字段不是从excel中获得的,直接跳过
+                            continue;
+                        }
+                        // 如果数据库字段中文名和必填字段中文名称对应,则通过反射为数据库必选字段赋值
+                        String dbName = excelDBFieldDesc.name();
+                        int dbLength = excelDBFieldDesc.length();
+                        if (dbName.equals(name)) {
+                            if (dbLength > 0) {
+                                SystemConstant.verifyLength(cellValue, dbLength, dbName);
+                            }
+                            examinationImportDtoField.setAccessible(true);
+                            examinationImportDtoField.set(examinationImportDto, cellValue);
+                            match = true;
+
+                            // 匹配上为必选字段
+                            CodeNameEnableValue codeNameEnableValue = new CodeNameEnableValue();
+                            codeNameEnableValue.setCode(code);
+                            codeNameEnableValue.setName(name);
+                            codeNameEnableValue.setEnable(true);
+                            codeNameEnableValue.setValue(cellValue);
+                            requiredFields.add(codeNameEnableValue);
+                            break;
+                        }
+                    }
+                    if (!match || "secondary".equals(level)) {
+                        // 必选+扩展字段不能匹配到数据库中的字段存放 或者 该字段为扩展字段,则添加到扩展字段中
+                        FieldsDto secondaryField = new FieldsDto();
+                        secondaryField.setCode(code);
+                        secondaryField.setName(name);
+                        secondaryField.setEnable(true);
+                        secondaryField.setValue(cellValue);
+                        secondaryFieldList.add(secondaryField);
+                    }
+                }
+            }
+            examinationImportDto.setRequiredFieldList(requiredFields);
+            examinationImportDto.setSecondaryFieldList(secondaryFieldList);
+            examinationImportDto.setSchoolId(schoolId);
+            // 解析时间
+            try {
+                Map<String, Object> timeMap = ConvertUtil.analyzeStartAndEndTime(examinationImportDto.getExamDate(), examinationImportDto.getExamTime());
+                String examStartTime = String.valueOf(timeMap.get("startTime"));
+                String examEndTime = String.valueOf(timeMap.get("endTime"));
+                examinationImportDto.setExamStartTime(examStartTime);
+                examinationImportDto.setExamEndTime(examEndTime);
+            } catch (Exception e) {
+                errorRowDate.add(e.getMessage());
+            }
+
+            // 唯一关系校验
+            String courseCode = examinationImportDto.getCourseCode();
+            String courseName = examinationImportDto.getCourseName();
+            String paperNumber = examinationImportDto.getPaperNumber();
+            String studentCode = examinationImportDto.getStudentCode();
+            String teacherName = examinationImportDto.getTeacherName();
+            if (StringUtils.isNotBlank(teacherName)) {
+                SysUser user = sysUserService.getByLoginName(schoolId, teacherName);
+                if (user == null) {
+                    errorRowDate.add("任课老师[" + teacherName + "]在用户管理中不存在");
+                } else {
+                    examinationImportDto.setTeacherId(user.getId());
+                }
+            }
+            if (!SystemConstant.isOneNull(courseCode, courseName)) {
+                // 校验1 - 文件中课程代码对应多个不同的课程名称
+                if (courseCodeNameInExcelMap.containsKey(courseCode)) {
+                    String name = courseCodeNameInExcelMap.get(courseCode);
+                    if (!courseName.equals(name)) {
+                        errorRowDate.add("文件中课程代码[" + courseCode + "]对应多个不同的课程名称");
+                    }
+                } else {
+                    courseCodeNameInExcelMap.put(courseCode, courseName);
+                }
+                // 校验2 - 文件中课程代码对应的课程名称和课程管理中对应课程名称不一致
+                String basicName = courseCodeNameInBasicCourseMap.get(courseCode);
+                if (StringUtils.isBlank(basicName)) {
+                    errorRowDate.add(String.format("文件中课程代码[%s]对应课程名称为[%s],课程管理中课程不存在", courseCode, courseName));
+                } else if (!courseName.equals(basicName)) {
+                    errorRowDate.add(String.format("文件中课程代码[%s]对应课程名称为[%s],课程管理中对应课程名称为[%s]", courseCode, courseName, basicName));
+                }
+            }
+            if (!RegexUtil.validStudentCode(studentCode)) {
+                errorRowDate.add("文件中学号[" + studentCode + "]不对,学号只能由数字、字母组成");
+            }
+            if (!SystemConstant.isOneNull(paperNumber, courseCode)) {
+                // 检验4 - 文件中试卷编号[%s]对应多个不同的课程代码[%s]
+                if (paperNumberWithCourseCodeInExcelMap.containsKey(paperNumber)) {
+                    String code = paperNumberWithCourseCodeInExcelMap.get(paperNumber);
+                    if (!courseCode.equals(code)) {
+                        errorRowDate.add(String.format("文件中试卷编号[%s]对应多个不同的课程代码", paperNumber));
+                    }
+                } else {
+                    paperNumberWithCourseCodeInExcelMap.put(paperNumber, courseCode);
+                }
+            }
+            if (SystemConstant.strNotNull(paperNumber)) {
+                //检验5 - 试卷编号[%s]在考试[%s]下有多条命题任务,请联系管理员处理
+                if (paperNumberWithExamTaskMap.containsKey(paperNumber)) {
+                    int count = paperNumberWithExamTaskMap.get(paperNumber);
+                    if (count > 1) {
+                        errorRowDate.add(String.format("试卷编号[%s]在考试[%s]下有多条命题任务,请联系管理员处理", paperNumber, count));
+                    }
+                }
+            }
+            if (!SystemConstant.isOneNull(paperNumber, courseCode)) {
+                //检验6 - 文件中试卷编号[%s]对应课程代码为[%s],命题任务中对应课程代码为[%s]
+                if (paperNumberWithCourseCodeInExamTaskMap.containsKey(paperNumber)) {
+                    String code = paperNumberWithCourseCodeInExamTaskMap.get(paperNumber);
+                    if (!courseCode.equals(code)) {
+                        errorRowDate.add(String.format("文件中试卷编号[%s]对应课程代码为[%s],命题任务中对应课程代码为[%s]", paperNumber, courseCode, code));
+                    }
+                }
+            }
+            examinationImportDto.setCoursePaperId(paperNumberCoureseSequenceMap.get(paperNumber));
+            examinationImportDto.setErrorMessage(errorRowDate.toString());
+            examinationImportDtoList.add(examinationImportDto);
+        }
+        List<String> errorList = examinationImportDtoList.stream()
+                .map(ExaminationImportDto::getErrorMessage)
+                .filter(SystemConstant::strNotNull)
+                .collect(Collectors.toList());
+        if (!CollectionUtils.isEmpty(errorList)) {
+            // 优先处理excel每个独立行的数据异常
+            map.put(SystemConstant.ERROR_DATA_LIST, examinationImportDtoList);
+            map.put("errorList", errorList);
+            map.put("fieldsDtoList", fieldsDtoList);
+            return map;
+        }
+
+        // 按考点+开始时间+课程代码+考场排序
+        examinationImportDtoList.sort(Comparator.comparing(ExaminationImportDto::getExamPlace)
+                .thenComparing(ExaminationImportDto::getExamStartTime)
+                .thenComparing(ExaminationImportDto::getCourseCode)
+                .thenComparing(ExaminationImportDto::getExamRoom)
+        );
+
+        // 卷袋号生成规则
+        try {
+            // 组装exam_detail数据
+            List<Long> examDetailIdList = examDetailService.disposeExamDataByExaminationExcel(examPrintPlan, examinationImportDtoList, sysUser);
+            // 更改印刷计划状态
+            examPrintPlan.setStatus(PrintPlanStatusEnum.READY);
+            examPrintPlanService.updateById(examPrintPlan);
+
+            map.put("examDetailIdList", examDetailIdList);
+            map.put("dataCount", examinationImportDtoList.size());
+        } catch (Exception e) {
+            if (e instanceof DuplicateKeyException) {
+                String errorColumn = e.getCause().toString();
+                String columnStr = errorColumn.substring(errorColumn.lastIndexOf("key") + 3, errorColumn.length()).replaceAll("'", "");
+                String[] data = errorColumn.split("-");
+                data[1] = data[1].substring(0, data[1].indexOf("'"));
+                throw ExceptionResultEnum.SQL_ERROR.exception("[" + FieldUniqueEnum.convertToTitle(columnStr) + "'" + data[1] + "']" + "数据不允许重复插入");
+            } else if (e instanceof ApiException) {
+                ResultUtil.error((ApiException) e, ((ApiException) e).getCode(), e.getMessage());
+            } else {
+                ResultUtil.error(e.getMessage());
+            }
+        }
+        return map;
+    }
+
+    /**
+     * 下载pdf
+     *
+     * @param map
+     * @return
+     */
+    @Override
+    @Transactional
+    public Map<String, Object> executeDownloadPdfLogic(Map<String, Object> map) {
+        List<File> sourceFileList = new ArrayList<>();
+        File zipFile = null;
+        String zipLocalRootPath = null;
+        try {
+            TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
+            JSONArray jsonArray = JSONArray.parseArray(tbTask.getRemark());
+            ArraysParams arraysParams = new ArraysParams(jsonArray.toArray(new Long[jsonArray.size()]));
+            if (Objects.isNull(arraysParams) || arraysParams.getIds().length == 0) {
+                throw ExceptionResultEnum.ERROR.exception("请选择要下载的数据");
+            }
+
+            List<ExamDetailPdfDownloadDto> examDetailList = examDetailService.findPdfDownload(Arrays.asList(arraysParams.getIds()));
+            if (CollectionUtils.isNotEmpty(examDetailList)) {
+                Long time = System.currentTimeMillis();
+
+                zipFile = SystemConstant.getFileTempDirVar(SystemConstant.ZIP_PREFIX);
+                zipLocalRootPath = zipFile.getParent() + File.separator + time;
+
+                for (ExamDetailPdfDownloadDto e : examDetailList) {
+                    StringJoiner dirPath = new StringJoiner("")
+                            .add(zipLocalRootPath).add(File.separator)
+                            .add(e.getSemesterName()).add(File.separator)
+                            .add(e.getExamName()).add(File.separator)
+                            .add(e.getCourseNameCode()).add(File.separator)
+                            .add(e.getPackageCode()).add(File.separator)
+                            .add(e.getCourseNameCode()).add(SystemConstant.HYPHEN)
+                            .add(e.getPaperNumber()).add(SystemConstant.HYPHEN);
+                    //试卷合并文件
+                    if (Objects.nonNull(e.getAttachmentId())) {
+                        BasicAttachment attachment = basicAttachmentService.getById(e.getAttachmentId());
+                        if (attachment != null) {
+                            String fileName = dirPath + PdfTypeEnum.PAPER.getTitle() + SystemConstant.PDF_PREFIX;
+                            File paperFile = fileUploadService.downloadFile(attachment, fileName);
+                            if (Objects.nonNull(paperFile)) {
+                                sourceFileList.add(paperFile);
+                            }
+                        }
+                    }
+
+                    //题卡合并文件
+                    if (Objects.nonNull(e.getCardAttachmentId())) {
+                        BasicAttachment cardAttachment = basicAttachmentService.getById(e.getCardAttachmentId());
+                        if (cardAttachment != null) {
+                            String fileName = dirPath + PdfTypeEnum.CARD_A3.getTitle() + SystemConstant.PDF_PREFIX;
+                            File cardFile = fileUploadService.downloadFile(cardAttachment, fileName);
+                            if (Objects.nonNull(cardFile)) {
+                                sourceFileList.add(cardFile);
+                            }
+                        }
+                    }
+
+                    //卷袋贴/签到表/登记表文件
+                    if (Objects.nonNull(e.getAttachmentPath())) {
+                        JSONObject js = JSONObject.parseObject(e.getAttachmentPath());
+                        List<PrintPathVo> printPathVoList = JSON.parseArray(js.getString(SystemConstant.PATH), PrintPathVo.class);
+                        for (PrintPathVo pathVo : printPathVoList) {
+                            String fileName = dirPath + pathVo.getPrintType().getName() + SystemConstant.PDF_PREFIX;
+                            File cardFile = fileUploadService.downloadFile(pathVo.getType(), pathVo.getUploadType(), pathVo.getPdfPath(), fileName);
+                            if (Objects.nonNull(cardFile)) {
+                                sourceFileList.add(cardFile);
+                            }
+                        }
+                    }
+                }
+                if (!CollectionUtils.isEmpty(sourceFileList)) {
+                    boolean oss = dictionaryConfig.sysDomain().isOss();
+                    StringJoiner stringJoiner = new StringJoiner("");
+                    if (!oss && Objects.nonNull(dictionaryConfig.fssPublicDomain()) && !StringUtils.isBlank(dictionaryConfig.fssPublicDomain().getConfig()) && !dictionaryConfig.fssPublicDomain().getConfig().startsWith(SystemConstant.START_PARENT)) {
+                        stringJoiner.add(dictionaryConfig.fssPublicDomain().getConfig()).add(File.separator);
+                    }
+                    stringJoiner = SystemConstant.getDirName(stringJoiner, UploadFileEnum.FILE, true);
+                    stringJoiner.add("印刷任务管理_批量下载PDF_" + time).add(SystemConstant.ZIP_PREFIX);
+                    String zipDirName = FileUtil.replaceSplit(stringJoiner.toString());
+                    JSONObject jsonObject = SystemConstant.createZip(zipFile, zipLocalRootPath, zipDirName);
+                    tbTask.setResultFilePath(jsonObject.toJSONString());
+                }
+            }
+            map.put(SystemConstant.SIZE, Objects.nonNull(sourceFileList) ? sourceFileList.size() : 0);
+        } catch (Exception e) {
+            log.error(SystemConstant.LOG_ERROR, e);
+            if (e instanceof ApiException) {
+                ResultUtil.error((ApiException) e, ((ApiException) e).getCode(), e.getMessage());
+            } else {
+                ResultUtil.error(e.getMessage());
+            }
+        } finally {
+            if (Objects.nonNull(zipFile)) {
+                zipFile.delete();
+            }
+            if (Objects.nonNull(zipLocalRootPath)) {
+                ConvertUtil.delFolder(zipLocalRootPath);
+            }
+            if (!CollectionUtils.isEmpty(sourceFileList)) {
+                for (File file : sourceFileList) {
+                    file.delete();
+                }
+            }
+        }
+        return map;
+    }
+
+    @Override
+    public Map<String, Object> executeExportPaperAndCardLogic(Map<String, Object> map) {
+        String zipLocalRootPath = null;
+        File zipFile = null;
+        List<File> sourceFileList = null;
+        try {
+            sourceFileList = new ArrayList<>();
+            TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
+
+            Long time = System.currentTimeMillis();
+            boolean oss = dictionaryConfig.sysDomain().isOss();
+            StringJoiner stringJoiner = new StringJoiner("");
+            if (!oss && Objects.nonNull(dictionaryConfig.fssPublicDomain()) && !StringUtils.isBlank(dictionaryConfig.fssPublicDomain().getConfig()) && !dictionaryConfig.fssPublicDomain().getConfig().startsWith(SystemConstant.START_PARENT)) {
+                stringJoiner.add(dictionaryConfig.fssPublicDomain().getConfig()).add(File.separator);
+            }
+            stringJoiner = SystemConstant.getDirName(stringJoiner, UploadFileEnum.FILE, true);
+            stringJoiner.add("卷库查询管理试卷、空白题卡批量下载_" + time).add(SystemConstant.ZIP_PREFIX);
+
+            String zipDirName = FileUtil.replaceSplit(stringJoiner.toString());
+            zipFile = SystemConstant.getFileTempDirVar(SystemConstant.ZIP_PREFIX);
+            zipLocalRootPath = zipFile.getParent() + File.separator + time;
+
+            List<ExamTaskDetailDto> examTasks = (List<ExamTaskDetailDto>) map.get("examTasks");
+            for (ExamTaskDetailDto examTask : examTasks) {
+                ExamTaskDetailPdfDownloadDto examTaskDetailPdfDownloadDto = examTaskDetailService.findPdfDownload(Long.valueOf(examTask.getId()));
+
+                StringJoiner dirPath = new StringJoiner("");
+                dirPath = dirPath.add(zipLocalRootPath).add(File.separator)
+                        .add(examTaskDetailPdfDownloadDto.getSemesterName()).add(File.separator)
+                        .add(examTaskDetailPdfDownloadDto.getExamName()).add(File.separator)
+                        .add(examTaskDetailPdfDownloadDto.getCourseNameCode().replaceAll(" ", "")).add(File.separator)
+                        .add(examTaskDetailPdfDownloadDto.getPaperNumber()).add(File.separator)
+                        .add(examTaskDetailPdfDownloadDto.getCourseNameCode().replaceAll(" ", "")).add(SystemConstant.HYPHEN)
+                        .add(examTaskDetailPdfDownloadDto.getPaperNumber()).add(SystemConstant.HYPHEN);
+                // 试卷
+                String paperAttachmentIds = examTaskDetailPdfDownloadDto.getPaperAttachmentIds();
+                if (StringUtils.isNotBlank(paperAttachmentIds)) {
+                    List<PaperInfoVo> paperInfoVoList = ExamTaskUtil.parsePaperAttachmentPath(paperAttachmentIds);
+                    if (CollectionUtils.isEmpty(paperInfoVoList)) {
+                        throw ExceptionResultEnum.ERROR.exception("试卷信息不存在");
+                    }
+                    for (PaperInfoVo paperInfoVo : paperInfoVoList) {
+                        Long attachmentId = Long.valueOf(paperInfoVo.getAttachmentId());
+                        String name = paperInfoVo.getName();
+                        if (Objects.nonNull(attachmentId)) {
+                            BasicAttachment attachment = basicAttachmentService.getById(attachmentId);
+                            if (Objects.nonNull(attachment)) {
+                                String fileName = dirPath + "试卷" + SystemConstant.HYPHEN + name + attachment.getType();
+                                File paperFile = fileUploadService.downloadFile(attachment, fileName);
+                                sourceFileList.add(paperFile);
+                            }
+                        }
+                        Long cardId = Long.valueOf(paperInfoVo.getCardId());
+                        ExamCard examCard = examCardService.getById(cardId);
+                        Optional.ofNullable(examCard).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("找不到答题卡"));
+
+                        String cardHtmlPath = dirPath + "题卡" + SystemConstant.HYPHEN + name + SystemConstant.HTML_PREFIX;
+                        String cardPdfPath = dirPath + "题卡" + SystemConstant.HYPHEN + name + SystemConstant.PDF_PREFIX;
+                        // 通用题卡
+                        String htmlContent = createPdfUtil.replaceBlankHtmlContent(examCard.getHtmlContent(), examCard.getCourseId());
+                        // html
+                        File localFile = new File(cardHtmlPath);
+                        if (!localFile.exists()) {
+                            localFile.getParentFile().mkdirs();
+                            localFile.createNewFile();
+                        }
+                        // 生成html文件
+                        FileCopyUtils.copy(htmlContent.getBytes(StandardCharsets.UTF_8), localFile);
+                        sourceFileList.add(localFile);
+                        // 转pdf文件
+                        File file = new File(cardPdfPath);
+                        if (!file.exists()) {
+                            file.getParentFile().mkdirs();
+                            file.createNewFile();
+                        }
+                        HtmlToPdfUtil.convert(cardHtmlPath, cardPdfPath, PageSizeEnum.A3);
+                        sourceFileList.add(file);
+                    }
+                }
+            }
+            JSONObject jsonObject = SystemConstant.createZip(zipFile, zipLocalRootPath, zipDirName);
+            tbTask.setResultFilePath(jsonObject.toJSONString());
+            map.put(SystemConstant.DATA_COUNT, examTasks.size());
+        } catch (Exception e) {
+            log.error(SystemConstant.LOG_ERROR, e);
+            if (e instanceof ApiException) {
+                ResultUtil.error((ApiException) e, ((ApiException) e).getCode(), e.getMessage());
+            } else {
+                ResultUtil.error(e.getMessage());
+            }
+        } finally {
+            if (Objects.nonNull(zipFile)) {
+                zipFile.delete();
+            }
+            if (Objects.nonNull(zipLocalRootPath)) {
+                ConvertUtil.delFolder(zipLocalRootPath);
+            }
+            if (!CollectionUtils.isEmpty(sourceFileList)) {
+                for (File file : sourceFileList) {
+                    file.delete();
+                }
+            }
+        }
+        return map;
+    }
+
+
+    @Transactional
+    @Override
+    public Map<String, Object> executeImportSysUserLogic(Map<String, Object> map) throws Exception {
+        InputStream inputStream = (InputStream) map.get("inputStream");
+
+        List<SysUserErrorExportDto> errorDataList = new ArrayList<>();
+        AtomicInteger totalInteger = new AtomicInteger(0);
+        AtomicInteger successInteger = new AtomicInteger(0);
+        List<LinkedMultiValueMap<Integer, Object>> finalList = ExcelUtil.excelReader(inputStream, Lists.newArrayList(SysUserImportDto.class, DescribeImportDto.class), (finalExcelList, finalColumnNameList, finalExcelErrorList) -> {
+            Map<String, SysUserImportDto> checkDtoMap = new HashMap<>();
+
+            for (int i = 0; i < finalExcelList.size(); i++) {
+                LinkedMultiValueMap<Integer, Object> excelMap = finalExcelList.get(i);
+                List<Object> sysUserImportDtoList = excelMap.get(i);
+                if (CollectionUtils.isEmpty(sysUserImportDtoList)) {
+                    continue;
+                }
+                map.put(SystemConstant.DATA_COUNT, sysUserImportDtoList.size());
+                List<SysUserImportDto> removeDataList = new ArrayList<>();
+                Map<String, Integer> phoneNumberMap = new HashMap<>();
+                for (int y = 0; y < Objects.requireNonNull(sysUserImportDtoList).size(); y++) {
+                    SysUserImportDto sysUserImportDto = (SysUserImportDto) sysUserImportDtoList.get(y);
+                    totalInteger.getAndIncrement();
+                    SysUserErrorExportDto sysUserErrorExportDto = new SysUserErrorExportDto();
+                    BeanUtils.copyProperties(sysUserImportDto, sysUserErrorExportDto);
+
+                    String name = sysUserImportDto.getName();
+                    String loginName = sysUserImportDto.getLoginName();
+                    String phoneNumber = sysUserImportDto.getPhoneNumber();
+                    String orgName = sysUserImportDto.getOrgName();
+                    String roleName = sysUserImportDto.getRoleName();
+
+                    StringJoiner errorStringJoiner = new StringJoiner(";");
+                    String errorStringEmpty = ExcelUtil.checkExcelField(sysUserImportDto);
+                    if (errorStringEmpty.length() > 0) {
+                        errorStringJoiner.add(errorStringEmpty);
+                    }
+                    if (checkDtoMap.containsKey(loginName)) {
+                        SysUserImportDto primaryCell = checkDtoMap.get(loginName);
+                        String priName = primaryCell.getName();
+                        String priPhoneNumber = primaryCell.getPhoneNumber();
+                        String priOrgName = primaryCell.getOrgName();
+                        if (!Objects.equals(priName, name)) {
+                            errorStringJoiner.add("用户名/工号[" + loginName + "]的用户存在不同的姓名");
+                        }
+                        if (!Objects.equals(priPhoneNumber, phoneNumber)) {
+                            errorStringJoiner.add("用户名/工号[" + loginName + "]的用户存在不同的手机号");
+                        }
+                        if (!Objects.equals(priOrgName, orgName)) {
+                            errorStringJoiner.add("用户名/工号[" + loginName + "]的用户存在不同的组织架构");
+                        }
+                        String priRoleName = primaryCell.getRoleName();
+                        if (SystemConstant.strNotNull(roleName)) {
+                            priRoleName = priRoleName + SystemConstant.COMMA + roleName;
+                            primaryCell.setRoleName(priRoleName);
+                        }
+                    } else {
+                        checkDtoMap.put(loginName, sysUserImportDto);
+                    }
+
+                    if (StringUtils.isNotBlank(loginName) && !loginName.matches(SystemConstant.REGULAR_EXPRESSION_OF_CODE)) {
+                        errorStringJoiner.add("用户名/工号[" + loginName + "]不符合规范");
+                    }
+                    if (StringUtils.isNotBlank(phoneNumber) && !phoneNumber.matches(SystemConstant.REGULAR_EXPRESSION_OF_PHONE)) {
+                        errorStringJoiner.add("手机号[" + phoneNumber + "]不符合输入规范");
+                    }
+                    if (StringUtils.isNotBlank(phoneNumber)) {
+                        if (phoneNumberMap.containsKey(phoneNumber)) {
+                            errorStringJoiner.add("手机号[" + phoneNumber + "]在文件中重复");
+                        } else {
+                            phoneNumberMap.put(phoneNumber, y);
+                        }
+                    }
+                    String errorString = errorStringJoiner.toString();
+                    if (errorString.length() > 0) {
+                        sysUserErrorExportDto.setErrorMsg(errorString);
+                        errorDataList.add(sysUserErrorExportDto);
+                        removeDataList.add(sysUserImportDto);
+                    } else {
+                        // 校验通过的数据
+                        successInteger.getAndIncrement();
+                    }
+                }
+                sysUserImportDtoList.removeAll(removeDataList);
+            }
+            if (!errorDataList.isEmpty()) {
+                map.put(SystemConstant.ERROR_DATA_LIST, errorDataList);
+            }
+            map.put(SystemConstant.DATA_COUNT, totalInteger.get());
+            map.put(SystemConstant.SUCCESS_DATA_COUNT, successInteger.get());
+            map.put(SystemConstant.ERROR_DATA_COUNT, errorDataList.size());
+            return finalExcelList;
+        }, 2);
+        return sysUserService.executeSysUserImportLogic(finalList, map);
+    }
+
+    @Override
+    @Transactional
+    public Map<String, Object> executeImportStatisticsLogic(Map<String, Object> map) throws Exception {
+        InputStream inputStream = (InputStream) map.get("inputStream");
+        Long examId = SystemConstant.convertIdToLong(String.valueOf(map.get("examId")));
+        SysUser sysUser = (SysUser) map.get(SystemConstant.USER);
+
+        List<LinkedMultiValueMap<Integer, Object>> finalList = ExcelUtil.excelReader(inputStream, Lists.newArrayList(StatisticsImportDto.class), (finalExcelList, finalColumnNameList, finalExcelErrorList) -> {
+            // 只允许导入一个sheet
+            if (finalExcelList.size() > 1) {
+                throw ExceptionResultEnum.ERROR.exception("excel中只允许有一个sheet");
+            }
+            if (finalExcelErrorList.size() > 0) {
+                throw ExceptionResultEnum.ERROR.exception(JSONObject.toJSONString(finalExcelErrorList));
+            }
+            List<ExcelError> excelErrorTemp = new ArrayList<>();
+            // 校验系统中是否存在
+            Map<String, SysOrg> collegeOrgMap = new HashMap<>();
+            Map<String, SysOrg> teachingRoomMap = new HashMap<>();
+            Map<String, BasicCourse> courseMap = new HashMap<>();
+            Map<String, DictionaryResult> clazzMap = new HashMap<>();
+            String batchNo = SystemConstant.getNanoId();
+            List<TCStatisticsTemp> tcStatisticsImportTempList = new ArrayList<>();
+
+            for (int i = 0; i < finalExcelList.size(); i++) {
+                LinkedMultiValueMap<Integer, Object> excelMap = finalExcelList.get(i);
+                List<Object> statisticsTempList = excelMap.get(i);
+                for (int y = 0; y < Objects.requireNonNull(statisticsTempList).size(); y++) {
+                    StatisticsImportDto statisticsImportDto = (StatisticsImportDto) statisticsTempList.get(y);
+                    SysOrg collegeOrg = this.validSysOrgExists(collegeOrgMap, statisticsImportDto.getCollegeName(), sysUser.getSchoolId(), excelErrorTemp, (y + 1), (i + 1), "开课学院");
+                    SysOrg teachingRoomOrg = this.validSysOrgExists(teachingRoomMap, statisticsImportDto.getTeachingRoomName(), sysUser.getSchoolId(), excelErrorTemp, (y + 1), (i + 1), "开课学院");
+                    BasicCourse basicCourse = this.validBasicCourseExists(courseMap, statisticsImportDto.getCourseName(), sysUser.getSchoolId(), statisticsImportDto.getCourseCode(), excelErrorTemp, (y + 1), (i + 1));
+                    String teacherName = statisticsImportDto.getTeacherName();
+                    String clazzNames = statisticsImportDto.getClazzName();
+                    List<DictionaryResult> dictionaryResultList = new ArrayList<>();
+                    for (String clazzName : clazzNames.split(",")) {
+                        DictionaryResult clazz = this.validBasicClazzExists(clazzMap, clazzName, sysUser.getSchoolId(), excelErrorTemp, (y + 1), (i + 1));
+                        dictionaryResultList.add(clazz);
+                    }
+                    String clazzIds = dictionaryResultList.stream().map(e -> String.valueOf(e.getId())).collect(Collectors.joining(","));
+
+
+                    if (excelErrorTemp.size() == 0) {
+
+                        TCStatisticsTemp tcStatistics = new TCStatisticsTemp(
+                                examId,
+                                collegeOrg.getId(),
+                                collegeOrg.getName(),
+                                teachingRoomOrg.getId(),
+                                teachingRoomOrg.getName(),
+                                basicCourse.getName(),
+                                basicCourse.getCode(),
+                                teacherName,
+                                clazzIds,
+                                clazzNames,
+                                batchNo,
+                                sysUser.getId());
+                        tcStatisticsImportTempList.add(tcStatistics);
+                    }
+                }
+            }
+            if (excelErrorTemp.size() > 0) {
+                List<String> errors = excelErrorTemp.stream().map(ExcelError::getExcelErrorType).collect(Collectors.toList());
+                throw ExceptionResultEnum.ERROR.exception(JSONObject.toJSONString(errors));
+            }
+            //加入删除(根据考试id和当前登录人)
+            tcStatisticsService.removeImportData(examId, sysUser.getId());
+            tcStatisticsTempService.saveBatch(tcStatisticsImportTempList);
+            map.put("dataCount", tcStatisticsImportTempList.size());
+            tcStatisticsService.importJoinData(tcStatisticsImportTempList);
+            tcStatisticsTempService.removeByIds(tcStatisticsImportTempList.stream().map(BaseEntity::getId).collect(Collectors.toSet()));
+            return finalExcelList;
+        }, 2);
+        return map;
+    }
+
+    /**
+     * 成绩导出
+     *
+     * @param map
+     * @return
+     * @throws Exception
+     */
+    @Override
+    public Map<String, Object> executeExportScoreLogic(Map<String, Object> map) throws Exception {
+        ByteArrayOutputStream fos = null;
+        try {
+            SysUser sysUser = (SysUser) map.get(SystemConstant.USER);
+            Long semesterId = null, examId = null, clazzId = null;
+            String courseCode = null;
+            semesterId = Objects.nonNull(map.get("semesterId")) ? Long.valueOf(map.get("semesterId").toString()) : null;
+            examId = Objects.nonNull(map.get("examId")) ? Long.valueOf(map.get("examId").toString()) : null;
+            clazzId = Objects.nonNull(map.get("clazzId")) ? Long.valueOf(map.get("clazzId").toString()) : null;
+            courseCode = Objects.nonNull(map.get("courseCode")) ? (String) map.get("courseCode") : null;
+            String servletPath = Objects.nonNull(map.get("servletPath")) ? (String) map.get("servletPath") : null;
+
+            fos = new ByteArrayOutputStream();
+            List<TSyncExamStudentScoreResult> tSyncExamStudentScoreResultList = tSyncExamStudentScoreService.export(sysUser, semesterId, examId, clazzId, courseCode, servletPath);
+            ExcelUtil.excelMake(TSyncExamStudentScoreResult.class, tSyncExamStudentScoreResultList, fos);
+            String excelExportFilePath = printCommonService.saveTaskAttachment(fos, (boolean) map.get(SystemConstant.OSS));
+            map.computeIfAbsent("count", v -> Objects.isNull(tSyncExamStudentScoreResultList) ? 0 : tSyncExamStudentScoreResultList.size());
+            TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
+            tbTask.setResultFilePath(excelExportFilePath);
+        } catch (Exception e) {
+            log.error(SystemConstant.LOG_ERROR, e);
+        } finally {
+            if (Objects.nonNull(fos)) {
+                fos.flush();
+                fos.close();
+            }
+        }
+        return map;
+    }
+
+    /**
+     * 成绩轨迹下载
+     *
+     * @param map
+     * @return
+     * @throws Exception
+     */
+    @Override
+    @Transactional
+    public Map<String, Object> executeDownloadScoreLogic(Map<String, Object> map) throws Exception {
+        File zipFile = null;
+        List<File> sourceFiles = null;
+        List<TSyncExamStudentScore> errorTSyncExamStudentScoreList = null;
+        boolean oss = dictionaryConfig.sysDomain().isOss();
+        try {
+            SysUser sysUser = (SysUser) map.get(SystemConstant.USER);
+            Long semesterId = null, examId = null, clazzId = null;
+            String courseCode = null;
+            semesterId = Objects.nonNull(map.get("semesterId")) ? (Long) map.get("semesterId") : null;
+            examId = Objects.nonNull(map.get("examId")) ? (Long) map.get("examId") : null;
+            clazzId = Objects.nonNull(map.get("clazzId")) ? (Long) map.get("clazzId") : null;
+            courseCode = Objects.nonNull(map.get("courseCode")) ? (String) map.get("courseCode") : null;
+
+            String servletPath = Objects.nonNull(map.get("servletPath")) ? (String) map.get("servletPath") : null;
+
+            List<TSyncExamStudentScoreResult> tSyncExamStudentScoreResultList = tSyncExamStudentScoreService.export(sysUser, semesterId, examId, clazzId, courseCode, servletPath);
+            if (Objects.nonNull(tSyncExamStudentScoreResultList) && tSyncExamStudentScoreResultList.size() > 0) {
+                List<TSyncExamStudentScore> tSyncExamStudentScoreList = new Gson().fromJson(JacksonUtil.parseJson(tSyncExamStudentScoreResultList), new TypeToken<List<TSyncExamStudentScore>>() {
+                }.getType());
+                Long time = System.currentTimeMillis();
+                StringJoiner stringJoiner = new StringJoiner("");
+                if (!oss && Objects.nonNull(dictionaryConfig.fssPublicDomain()) && !StringUtils.isBlank(dictionaryConfig.fssPublicDomain().getConfig()) && !dictionaryConfig.fssPublicDomain().getConfig().startsWith(SystemConstant.START_PARENT)) {
+                    stringJoiner.add(dictionaryConfig.fssPublicDomain().getConfig()).add(File.separator);
+                }
+                stringJoiner = SystemConstant.getDirName(stringJoiner, UploadFileEnum.FILE, true);
+                stringJoiner.add("成绩轨迹下载_" + time).add(SystemConstant.ZIP_PREFIX);
+
+                String zipDirName = FileUtil.replaceSplit(stringJoiner.toString());
+                zipFile = SystemConstant.getFileTempDirVar(SystemConstant.ZIP_PREFIX);
+
+                sourceFiles = new LinkedList<>();
+                List<TSyncExamStudentScore> updateTSyncExamStudentScoreList = new ArrayList<>();
+                errorTSyncExamStudentScoreList = new ArrayList<>();
+                for (TSyncExamStudentScore t : tSyncExamStudentScoreList) {
+                    try {
+                        boolean update = Objects.isNull(t.getTrajectoryUrls()) ? true : false;
+                        t = tSyncExamStudentScoreService.createImageTrajectory(t, ImageTrajectoryEnum.DOWNLOAD, false, sysUser.getId());
+                        if (Objects.nonNull(t.getTrajectoryFileList())) {
+                            sourceFiles.addAll(t.getTrajectoryFileList());
+                        } else {
+                            errorTSyncExamStudentScoreList.add(t);
+                        }
+                        if (update || Objects.isNull(t.getTrajectoryUrls())) {
+                            updateTSyncExamStudentScoreList.add(t);
+                        }
+                    } catch (Exception e) {
+                        log.error(SystemConstant.LOG_ERROR, e);
+                        errorTSyncExamStudentScoreList.add(t);
+                    }
+                }
+                tSyncExamStudentScoreService.saveOrUpdateBatch(updateTSyncExamStudentScoreList);
+                if (!sourceFiles.isEmpty()) {
+                    JSONObject jsonObject = SystemConstant.createZip(zipFile, sourceFiles, zipDirName);
+                    TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
+                    tbTask.setResultFilePath(jsonObject.toJSONString());
+                } else {
+                    throw ExceptionResultEnum.ERROR.exception("阅卷方式未使用轨迹阅卷,无轨迹图");
+                }
+            } else {
+                throw ExceptionResultEnum.ERROR.exception("没有可下载数据");
+            }
+            map.computeIfAbsent("count", v -> tSyncExamStudentScoreResultList.size());
+            if (Objects.nonNull(errorTSyncExamStudentScoreList) && errorTSyncExamStudentScoreList.size() > 0) {
+                StringJoiner stringJoiner = new StringJoiner("").add("\r\n");
+                for (TSyncExamStudentScore t : errorTSyncExamStudentScoreList) {
+                    stringJoiner.add("[").add(t.getName()).add(",").add(t.getExamNumber()).add("]\r\n");
+                }
+                List<TSyncExamStudentScore> finalErrorTSyncExamStudentScoreList = errorTSyncExamStudentScoreList;
+                map.computeIfAbsent("error", v -> "其中未下载成功数据" + finalErrorTSyncExamStudentScoreList.size() + "条:" + stringJoiner.toString());
+            }
+        } catch (Exception e) {
+            log.error(SystemConstant.LOG_ERROR, e);
+            if (e instanceof ApiException) {
+                ResultUtil.error((ApiException) e, e.getMessage());
+            } else {
+                ResultUtil.error(e.getMessage());
+            }
+        } finally {
+            if (Objects.nonNull(zipFile)) {
+                zipFile.delete();
+            }
+            if (oss && !CollectionUtils.isEmpty(sourceFiles)) {
+                for (File f : sourceFiles) {
+                    f.delete();
+                }
+            }
+        }
+        return map;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public Map<String, Object> executeDownloadPaperFileBatch(Map<String, Object> map) {
+        TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
+        DownloadPaperFileParam downloadPaperFileParam = (DownloadPaperFileParam) map.get("downloadPaperFileParam");
+        Long semesterId = downloadPaperFileParam.getSemesterId();
+        Long examId = downloadPaperFileParam.getExamId();
+        Long orgId = downloadPaperFileParam.getOrgId();
+        PaperFileDownloadContentEnum paperFileDownloadContent = downloadPaperFileParam.getPaperFileDownloadContentType();
+        if (paperFileDownloadContent == null) {
+            throw ExceptionResultEnum.ERROR.exception("请选择下载文件");
+        }
+        PaperFileDownloadExposureStatusEnum paperFileDownloadExposureStatus = downloadPaperFileParam.getPaperFileDownloadExposureStatus();
+        if ((PaperFileDownloadContentEnum.ONLY_PAPER.equals(paperFileDownloadContent) || PaperFileDownloadContentEnum.PAPER_AND_CARD.equals(paperFileDownloadContent)) && Objects.isNull(paperFileDownloadExposureStatus)) {
+            throw ExceptionResultEnum.ERROR.exception("请选择试卷状态");
+        }
+        Boolean namedByCourseInfo = downloadPaperFileParam.getNamedByCourseInfo();
+        Boolean namedByPaperNumber = downloadPaperFileParam.getNamedByPaperNumber();
+        Boolean namedByOriginalFile = downloadPaperFileParam.getNamedByOriginalFile();
+        if (!namedByCourseInfo && !namedByPaperNumber && !namedByOriginalFile) {
+            throw ExceptionResultEnum.ERROR.exception("请选择至少一种命名规则");
+        }
+
+        String courseName = downloadPaperFileParam.getCourseName();
+        Set<Long> idSet = downloadPaperFileParam.getIdSet();
+
+        File zipFile = null;
+        String zipLocalRootPath = null;
+        try {
+            boolean oss = dictionaryConfig.sysDomain().isOss();
+            StringJoiner stringJoiner = new StringJoiner("");
+            if (!oss && Objects.nonNull(dictionaryConfig.fssPublicDomain()) && !StringUtils.isBlank(dictionaryConfig.fssPublicDomain().getConfig()) && !dictionaryConfig.fssPublicDomain().getConfig().startsWith(SystemConstant.START_PARENT)) {
+                stringJoiner.add(dictionaryConfig.fssPublicDomain().getConfig()).add(File.separator);
+            }
+            stringJoiner = SystemConstant.getDirName(stringJoiner, UploadFileEnum.FILE, true);
+            stringJoiner.add("批量下载文件_" + System.currentTimeMillis()).add(SystemConstant.ZIP_PREFIX);
+
+            String zipDirName = FileUtil.replaceSplit(stringJoiner.toString());
+            zipFile = SystemConstant.getFileTempDirVarForZip(SystemConstant.getNanoId(), SystemConstant.ZIP_PREFIX);
+            zipLocalRootPath = zipFile.getParent() + File.separator + System.currentTimeMillis();
+
+            boolean downloadPaper = paperFileDownloadContent != null && (PaperFileDownloadContentEnum.ONLY_PAPER.equals(paperFileDownloadContent) || PaperFileDownloadContentEnum.PAPER_AND_CARD.equals(paperFileDownloadContent));
+            boolean downloadCard = paperFileDownloadContent != null && (PaperFileDownloadContentEnum.ONLY_CARD.equals(paperFileDownloadContent) || PaperFileDownloadContentEnum.PAPER_AND_CARD.equals(paperFileDownloadContent));
+
+            SysUser requestUser = (SysUser) map.get(SystemConstant.USER);
+            DataPermissionRule dpr = null;
+            if (CollectionUtils.isEmpty(idSet)) {
+                dpr = basicRoleDataPermissionService.findDataPermission(653L, requestUser);
+            }
+            // 查询待下载数据
+            List<ExamTaskDetailDto> examTaskDetailDtoList = downloadService.listExamQuery(semesterId, examId, orgId, courseName, idSet, dpr);
+            List<ExamTaskPaperExportDto> examTaskPaperExportDtoList = new ArrayList<>();
+            for (ExamTaskDetailDto examTaskDetailDto : examTaskDetailDtoList) {
+                ExamTaskPaperExportDto examTaskPaperExportDto = new ExamTaskPaperExportDto(examTaskDetailDto);
+                examTaskPaperExportDtoList.add(examTaskPaperExportDto);
+                List<PaperInfoVo> paperInfoVoList = ExamTaskUtil.parsePaperAttachmentPath(examTaskDetailDto.getPaperAttachmentIds());
+                // 选择曝光卷型
+                if (PaperFileDownloadExposureStatusEnum.EXPOSED_PAPER.equals(paperFileDownloadExposureStatus)) {
+                    if (StringUtils.isBlank(examTaskDetailDto.getExposedPaperType())) {
+                        examTaskPaperExportDto.setResult("没有曝光卷型,下载失败");
+                        continue;
+                    } else {
+                        paperInfoVoList = ExamTaskUtil.parsePaperAttachmentPath(examTaskDetailDto.getPaperAttachmentIds(), examTaskDetailDto.getExposedPaperType());
+                    }
+                }
+                // 选择未曝光卷型
+                if (PaperFileDownloadExposureStatusEnum.UNEXPOSED_PAPER.equals(paperFileDownloadExposureStatus)) {
+                    if (StringUtils.isBlank(examTaskDetailDto.getUnexposedPaperType())) {
+                        examTaskPaperExportDto.setResult("没有未曝光卷型,下载失败");
+                        continue;
+                    } else {
+                        paperInfoVoList = ExamTaskUtil.parsePaperAttachmentPath(examTaskDetailDto.getPaperAttachmentIds(), examTaskDetailDto.getUnexposedPaperType());
+                    }
+                }
+
+                if (CollectionUtils.isEmpty(paperInfoVoList)) {
+                    examTaskPaperExportDto.setResult("所选试卷状态未查询到上传的试卷信息,下载失败");
+                    continue;
+                }
+
+                // 命名规则
+                StringJoiner sj = new StringJoiner(SystemConstant.HYPHEN);
+                if (namedByCourseInfo) {
+                    sj.add(examTaskDetailDto.getCourseName()).add(examTaskDetailDto.getCourseCode());
+                }
+                if (namedByPaperNumber) {
+                    sj.add(examTaskDetailDto.getPaperNumber());
+                }
+                String fileNamePath = sj.toString();
+
+                // 目录规则(课程名称(课程代码)/试卷编号)
+                String secondPath = examTaskDetailDto.getCourseName() + SystemConstant.HYPHEN + examTaskDetailDto.getCourseCode() + File.separator + examTaskDetailDto.getPaperNumber();
+                for (PaperInfoVo paperInfoVo : paperInfoVoList) {
+                    // 下载试卷
+                    if (downloadPaper) {
+                        // 不管什么命名规则,默认都加上卷型前缀
+                        String paperFileNamePath = "试卷" + SystemConstant.HYPHEN + paperInfoVo.getName() + SystemConstant.HYPHEN + fileNamePath;
+                        // 原文件名
+                        if (namedByOriginalFile) {
+                            paperFileNamePath = paperFileNamePath + SystemConstant.HYPHEN + paperInfoVo.getFilename();
+                        } else {
+                            paperFileNamePath = paperFileNamePath + "." + FilenameUtils.getExtension(paperInfoVo.getFilename());
+                        }
+                        Long attachmentId = Long.valueOf(paperInfoVo.getAttachmentId());
+                        if (Objects.nonNull(attachmentId)) {
+                            BasicAttachment attachment = basicAttachmentService.getById(attachmentId);
+                            if (Objects.nonNull(attachment)) {
+                                String fileName = trimWhiteSpace(zipLocalRootPath + File.separator + secondPath + File.separator + spliceFileName(paperFileNamePath, SystemConstant.PDF_PREFIX));
+                                fileUploadService.downloadFile(attachment, fileName);
+                            }
+                        }
+                    }
+                    // 下载题卡
+                    if (downloadCard) {
+                        Long cardId = Long.valueOf(paperInfoVo.getCardId());
+                        ExamCard examCard = examCardService.getById(cardId);
+                        Optional.ofNullable(examCard).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("找不到答题卡"));
+
+                        String cardHtmlPath = zipLocalRootPath + File.separator + secondPath + File.separator + "题卡" + SystemConstant.HYPHEN + paperInfoVo.getName() + SystemConstant.HYPHEN + fileNamePath;
+                        String cardPdfPath = zipLocalRootPath + File.separator + secondPath + File.separator + "题卡" + SystemConstant.HYPHEN + paperInfoVo.getName() + SystemConstant.HYPHEN + fileNamePath;
+                        // 原文件名
+                        if (namedByOriginalFile) {
+                            cardHtmlPath = trimWhiteSpace(cardHtmlPath + SystemConstant.HYPHEN + examCard.getTitle() + SystemConstant.HTML_PREFIX);
+                            cardPdfPath = trimWhiteSpace(cardPdfPath + SystemConstant.HYPHEN + examCard.getTitle() + SystemConstant.PDF_PREFIX);
+                        } else {
+                            cardHtmlPath = trimWhiteSpace(cardHtmlPath + SystemConstant.HTML_PREFIX);
+                            cardPdfPath = trimWhiteSpace(cardPdfPath + SystemConstant.PDF_PREFIX);
+                        }
+
+                        // html
+                        File localFile = new File(cardHtmlPath);
+                        if (!localFile.exists()) {
+                            localFile.getParentFile().mkdirs();
+                            localFile.createNewFile();
+                        }
+                        // 通用题卡
+                        String htmlContent = createPdfUtil.replaceBlankHtmlContent(examCard.getHtmlContent(), examCard.getCourseId());
+                        // 生成html文件
+                        FileCopyUtils.copy(htmlContent.getBytes(StandardCharsets.UTF_8), localFile);
+                        // 转pdf文件
+                        File file = new File(cardPdfPath);
+                        if (!file.exists()) {
+                            file.getParentFile().mkdirs();
+                            file.createNewFile();
+                        }
+                        HtmlToPdfUtil.convert(cardHtmlPath, cardPdfPath, PageSizeEnum.A3);
+                    }
+                    examTaskPaperExportDto.setResult("下载成功");
+                }
+            }
+
+            // 导出文件excel
+            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+            ExcelUtil.excelMake(ExamTaskPaperExportDto.class, examTaskPaperExportDtoList, outputStream);
+            InputStream in = new ByteArrayInputStream(outputStream.toByteArray());
+
+            String excelLocalPath = zipLocalRootPath + File.separator + "下载清单" + "." + SystemConstant.XLSX;
+            FileUtils.copyInputStreamToFile(in, new File(excelLocalPath));
+            // 所有试卷
+            JSONObject jsonObject = SystemConstant.createZip(zipFile, zipLocalRootPath, zipDirName);
+            tbTask.setResultFilePath(jsonObject.toJSONString());
+            map.put("count", examTaskDetailDtoList.size());
+        } catch (Exception e) {
+            log.error(SystemConstant.LOG_ERROR, e);
+        } finally {
+            if (Objects.nonNull(zipFile)) {
+                zipFile.delete();
+            }
+            if (Objects.nonNull(zipLocalRootPath)) {
+                ConvertUtil.delFolder(zipLocalRootPath);
+            }
+        }
+        return map;
+    }
+
+    /**
+     * 验证机构是否存在
+     *
+     * @param orgMap         机构map
+     * @param key            机构名称
+     * @param schoolId       学校id
+     * @param excelErrorTemp 错误信息
+     * @param row            行
+     * @param sheet          区
+     * @param cloumnName     cloumnName
+     * @return 机构
+     */
+    private SysOrg validSysOrgExists(Map<String, SysOrg> orgMap,
+                                     String key,
+                                     Long schoolId,
+                                     List<ExcelError> excelErrorTemp,
+                                     int row,
+                                     int sheet,
+                                     String cloumnName) {
+        SysOrg sysOrg = null;
+        if (!orgMap.containsKey(key)) {//不存在查询
+            QueryWrapper<SysOrg> sysOrgQueryWrapper = new QueryWrapper<>();
+            sysOrgQueryWrapper.lambda().eq(SysOrg::getSchoolId, schoolId)
+                    .eq(SysOrg::getName, key)
+                    .eq(SysOrg::getEnable, true);
+            sysOrg = sysOrgService.getOne(sysOrgQueryWrapper);
+        } else {
+            sysOrg = orgMap.get(key);
+        }
+        if (Objects.isNull(sysOrg)) {
+            excelErrorTemp.add(new ExcelError(row, "excel第" + sheet + "个sheet第" + row + "行[" + cloumnName + "]不存在"));
+        } else {
+            SysOrg finalSysOrg = sysOrg;
+            orgMap.computeIfAbsent(key, v -> finalSysOrg);
+        }
+        return sysOrg;
+    }
+
+    /**
+     * 验证课程是否存在
+     *
+     * @param courseMap      courseMap
+     * @param key            课程名称
+     * @param schoolId       学校id
+     * @param value          课程编号
+     * @param excelErrorTemp 错误信息
+     * @param row            行
+     * @param sheet          区
+     * @return 基础课程
+     */
+    private BasicCourse validBasicCourseExists(Map<String, BasicCourse> courseMap,
+                                               String key,
+                                               Long schoolId,
+                                               String value,
+                                               List<ExcelError> excelErrorTemp,
+                                               int row,
+                                               int sheet) {
+        BasicCourse basicCourse = null;
+        if (!courseMap.containsKey(key)) {//不存在查询
+            QueryWrapper<BasicCourse> basicCourseQueryWrapper = new QueryWrapper<>();
+            basicCourseQueryWrapper.lambda().eq(BasicCourse::getSchoolId, schoolId)
+                    .eq(BasicCourse::getName, key)
+                    .eq(BasicCourse::getCode, value)
+                    .eq(BasicCourse::getEnable, true);
+            basicCourse = basicCourseService.getOne(basicCourseQueryWrapper);
+        } else {
+            basicCourse = courseMap.get(key);
+        }
+        if (Objects.isNull(basicCourse)) {
+            excelErrorTemp.add(new ExcelError(row, "excel第" + sheet + "个sheet第" + row + "行[" + "课程代码" + "]不存在"));
+        } else {
+            BasicCourse finalBasicCourse = basicCourse;
+            courseMap.computeIfAbsent(key, v -> finalBasicCourse);
+        }
+        return basicCourse;
+    }
+
+
+    /**
+     * 验证班级是否存在
+     *
+     * @param clazzMap       班级map
+     * @param key            班级名称
+     * @param schoolId       学校id
+     * @param excelErrorTemp 错误信息
+     * @param row            行
+     * @param sheet          区
+     * @return 班级信息
+     */
+    private DictionaryResult validBasicClazzExists(Map<String, DictionaryResult> clazzMap,
+                                                   String key,
+                                                   Long schoolId,
+                                                   List<ExcelError> excelErrorTemp,
+                                                   int row,
+                                                   int sheet) {
+        DictionaryResult clazz = null;
+        if (!clazzMap.containsKey(key)) {//不存在查询
+            TeachClazz teachClazz = teachClazzService.getOne(new QueryWrapper<TeachClazz>().lambda().eq(TeachClazz::getSchoolId, schoolId).eq(TeachClazz::getClazzName, key));
+            if (Objects.nonNull(teachClazz)) {
+                clazz = new DictionaryResult();
+                clazz.setId(teachClazz.getId());
+                clazz.setName(teachClazz.getClazzName());
+            } else {
+//                QueryWrapper<BasicClazz> basicClazzQueryWrapper = new QueryWrapper<>();
+//                basicClazzQueryWrapper.lambda().eq(BasicClazz::getSchoolId, schoolId)
+//                        .eq(BasicClazz::getClazzName, key)
+//                        .eq(BasicClazz::getEnable, true);
+//                BasicClazz basicClazz = basicClazzService.getOne(basicClazzQueryWrapper);
+//                if (Objects.nonNull(basicClazz)) {
+//                    clazz = new DictionaryResult();
+//                    clazz.setId(basicClazz.getId());
+//                    clazz.setName(basicClazz.getClazzName());
+//                }
+            }
+        } else {
+            clazz = clazzMap.get(key);
+        }
+        if (Objects.isNull(clazz)) {
+            excelErrorTemp.add(new ExcelError(row, "excel第" + sheet + "个sheet第" + row + "行[" + "班级名称" + "]不存在"));
+        } else {
+            DictionaryResult finalClazz = clazz;
+            clazzMap.computeIfAbsent(key, v -> finalClazz);
+        }
+        return clazz;
+    }
+
+    /**
+     * 过滤掉所有空格(前、中、后)
+     *
+     * @param value value
+     */
+    private static String trimWhiteSpace(String value) {
+        return StringUtils.deleteWhitespace(value);
+    }
+
+    /**
+     * 校验并拼接文件名(后缀)
+     *
+     * @param fileName 原文件名
+     * @param suffix   后缀
+     */
+    private static String spliceFileName(String fileName, String suffix) {
+        if (StringUtils.isAnyBlank(fileName, suffix)) {
+            return fileName;
+        }
+        if (!suffix.startsWith(SystemConstant.ORG_POINT)) {
+            suffix = SystemConstant.ORG_POINT + suffix;
+        }
+        if (!fileName.endsWith(suffix)) {
+            return fileName + suffix;
+        }
+        return fileName;
+    }
+}

+ 5 - 6
distributed-print-business/src/main/resources/mapper/ExamTaskMapper.xml

@@ -1065,7 +1065,7 @@
                     AND EXISTS( SELECT 1 FROM (select course_id from teach_course where exam_id = #{examId} and user_id = #{dpr.courseUserId}) tc WHERE tc.course_id = a.course_id)
                 </if>
                 <if test="dpr.orgIdSet != null and dpr.orgIdSet != '' and dpr.orgIdSet.size > 0">
-                    AND su.org_id IN
+                    AND bc.teaching_room_id IN
                     <foreach collection="dpr.orgIdSet" item="item" index="index" open="(" separator="," close=")">
                         #{item}
                     </foreach>
@@ -1081,8 +1081,8 @@
             a.card_rule_id cardRuleId,
             be.name examName,
             bs.name semesterName,
-            a.course_code courseCode,
-            a.course_name courseName,
+            bc.code courseCode,
+            bc.name courseName,
             a.paper_number paperNumber,
             b.enable,
             b.paper_type paperType,
@@ -1095,8 +1095,7 @@
                 LEFT JOIN
             exam_task_detail b ON a.id = b.exam_task_id
                 LEFT JOIN
-            basic_course bc ON a.school_id = bc.school_id
-                AND a.course_code = bc.code
+            basic_course bc ON a.course_id = bc.id
                 LEFT JOIN
             basic_card_rule e ON a.card_rule_id = e.id
                 LEFT JOIN
@@ -1136,7 +1135,7 @@
                     AND a.user_id = #{dpr.requestUserId}
                 </if>
                 <if test="dpr.orgIdSet != null and dpr.orgIdSet != '' and dpr.orgIdSet.size > 0">
-                    AND su.org_id IN
+                    AND bc.teaching_room_id IN
                     <foreach collection="dpr.orgIdSet" item="item" index="index" open="(" separator="," close=")">
                         #{item}
                     </foreach>

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

@@ -333,7 +333,7 @@ public class SystemConstant {
     public static final String COMMA_OF_CHINESE = ",";
     public static final String PAUSE_SIGN = "、";
     public static final String ORG_SPLIT = "/";
-//    public static final String ORG_POINT = "\\.";
+    public static final String ORG_POINT = ".";
     public static final String PUSH_OPERATE_NOTICE = "操作成功,请去基础配置 -> 系统设置 -> 同步管理中查看结果";
     public static final String EXCEL_PROTECT_KEY = "Qmth87863577";
     public static final String ZIP_ENCRYPT_PWD = "qmthzip";