package com.qmth.distributed.print.business.templete.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.google.common.collect.Lists;
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.distributed.print.business.bean.dto.*;
import com.qmth.distributed.print.business.bean.params.DownloadPaperFileParam;
import com.qmth.distributed.print.business.bean.params.SerialNumberParams;
import com.qmth.distributed.print.business.bean.result.DictionaryResult;
import com.qmth.distributed.print.business.bean.result.TSyncExamStudentScoreResult;
import com.qmth.distributed.print.business.cache.CreatePdfCacheUtil;
import com.qmth.distributed.print.business.entity.*;
import com.qmth.distributed.print.business.enums.*;
import com.qmth.distributed.print.business.service.*;
import com.qmth.distributed.print.business.templete.service.TaskLogicService;
import com.qmth.distributed.print.business.util.CreatePdfUtil;
import com.qmth.distributed.print.business.util.CreatePrintPdfUtil;
import com.qmth.distributed.print.business.util.HtmlToPdfUtil;
import com.qmth.teachcloud.common.annotation.ExcelDBFieldDesc;
import com.qmth.teachcloud.common.base.BaseEntity;
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.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.io.FileUtils;
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.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.LinkedMultiValueMap;

import javax.annotation.Resource;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Description: 任务处理逻辑impl
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2021/3/29
 */
@Service
public class TaskLogicServiceImpl implements TaskLogicService {
    private final static Logger log = LoggerFactory.getLogger(TaskLogicServiceImpl.class);

    @Resource
    ExamDetailService detailService;

    @Resource
    ExamDetailCourseService detailCourseService;

    @Resource
    ExamPrintPlanService examPrintPlanService;

    @Resource
    ExamTaskService examTaskService;

    @Resource
    ExamTaskDetailService examTaskDetailService;

    @Resource
    ExamCardService examCardService;

    @Resource
    ExamCardDetailService examCardDetailService;

    @Resource
    ExamStudentService examStudentService;

    @Resource
    BasicAttachmentService basicAttachmentService;

    @Resource
    ExamDetailService examDetailService;

//    @Resource
//    OssUtil ossUtil;

    @Resource
    CommonCacheService commonCacheService;

    @Resource
    BasicCourseService basicCourseService;

    @Resource
    CreatePdfUtil createPdfUtil;

    @Resource
    CreatePrintPdfUtil createPrintPdfUtil;

    @Resource
    RedisTemplate<String, Object> redisTemplate;

    @Resource
    BasicExamRuleService basicExamRuleService;

    @Resource
    TBTaskService tbTaskService;

    @Resource
    BasicCardRuleService basicCardRuleService;

    @Resource
    TeachcloudCommonService teachcloudCommonService;

    @Resource
    ConvertUtil convertUtil;

    @Autowired
    ExamDetailCourseService examDetailCourseService;

    @Autowired
    BasicStudentService basicStudentService;

    @Autowired
    ExamTaskPrintService examTaskPrintService;

    @Resource
    SysUserService sysUserService;

    @Resource
    FileStoreUtil fileStoreUtil;

    @Resource
    BasicClazzService basicClazzService;

    @Resource
    SysOrgService sysOrgService;

    @Resource
    TCStatisticsService tcStatisticsService;

    @Resource
    TCStatisticsTempService tcStatisticsTempService;

    @Resource
    TSyncExamStudentScoreService tSyncExamStudentScoreService;

    @Resource
    @Lazy
    PrintCommonService printCommonService;

    @Resource
    private DownloadService downloadService;

    @Resource
    private TeachClazzService teachClazzService;

    @Resource
    DictionaryConfig dictionaryConfig;

    @Resource
    BasicPrintConfigService basicPrintConfigService;

    /**
     * 创建pdf前置条件
     *
     * @param map
     * @return
     */
    @Override
    @Transactional
    public Map<String, Object> createPdfPrepose(Map<String, Object> map) {
        TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
        SysUser sysUser = (SysUser) map.get(SystemConstant.USER);
        Long examDetailId = tbTask.getEntityId();
        List<Long> examDetailIds = Objects.nonNull(map.get("examDetailIds")) ? (List<Long>) map.get("examDetailIds") : null;
        //查询printPlan
        ExamPrintPlan examPrintPlan = examPrintPlanService.getById(tbTask.getPrintPlanId());
        if (Objects.isNull(examPrintPlan)) {
            throw ExceptionResultEnum.EXAM_PRINT_IS_NULL.exception();
        }
        UpdateWrapper<ExamDetail> examDetailQueryWrapper = new UpdateWrapper<>();
        examDetailQueryWrapper.lambda().eq(ExamDetail::getSchoolId, sysUser.getSchoolId())
                .eq(ExamDetail::getPrintPlanId, tbTask.getPrintPlanId());
        if (Objects.nonNull(examDetailId)) {
            examDetailQueryWrapper.lambda().eq(ExamDetail::getId, examDetailId);
        } else if (Objects.nonNull(examDetailIds)) {
            examDetailQueryWrapper.lambda().in(ExamDetail::getId, examDetailIds);
        }
        examDetailQueryWrapper.lambda().set(ExamDetail::getStatus, ExamDetailStatusEnum.NEW)
                .set(ExamDetail::getAttachmentPath, null);
        detailService.update(examDetailQueryWrapper);

        //所有考场都撤回，印刷任务状态改为就绪
        QueryWrapper<ExamDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ExamDetail::getPrintPlanId, tbTask.getPrintPlanId())
                .notIn(ExamDetail::getStatus, ExamDetailStatusEnum.NEW, ExamDetailStatusEnum.READY);
        List<ExamDetail> examDetails = detailService.list(queryWrapper);
        if (CollectionUtils.isEmpty(examDetails)) {
            UpdateWrapper<ExamPrintPlan> printPlanUpdateWrapper = new UpdateWrapper<>();
            printPlanUpdateWrapper.lambda().set(ExamPrintPlan::getStatus, PrintPlanStatusEnum.READY).eq(ExamPrintPlan::getId, tbTask.getPrintPlanId());
            examPrintPlanService.update(printPlanUpdateWrapper);
        }
        return map;
    }

    /**
     * 创建pdf核心逻辑
     *
     * @param examDetailCourseList
     * @param examPrintPlan        印刷计划
     * @param examDetail           考场对象
     * @param sysUser              当前用户
     * @param paperTypeParam       试卷类型
     * @param basicAttachmentList  附件集合
     * @param attachmentIds
     * @param fileTempList
     * @param list
     */
    @Transactional
    public List<BasicAttachment> createPdfCoreLogic(List<ExamDetailCourse> examDetailCourseList,
                                                    ExamPrintPlan examPrintPlan,
                                                    ExamDetail examDetail,
                                                    SysUser sysUser,
                                                    String paperTypeParam,
                                                    List<BasicAttachment> basicAttachmentList,
                                                    Set<Long> attachmentIds,
                                                    List<File> fileTempList,
                                                    List<PdfDto>... list
    ) throws Exception {
        if (Objects.nonNull(examDetailCourseList) && examDetailCourseList.size() > 0) {
            Map<Long, BasicCardRule> basicCardRuleMap = new HashMap<>();
            for (ExamDetailCourse examDetailCourse : examDetailCourseList) {
                List<PdfDto> studentPaperPdfList = new ArrayList<>();//所有试卷
                List<PdfDto> studentCardPdfList = new ArrayList<>();//所有题卡
                List<PdfDto> backupPaperPdfList = new ArrayList<>();//备份试卷
                List<PdfDto> backupCardPdfList = new ArrayList<>();//备份题卡

                String printContent = examPrintPlan.getPrintContent();
                if (StringUtils.isBlank(printContent)) {
                    return null;
                }
                //查询试卷
                List<ExamTask> examTaskList = examTaskService.findByFlowStatus(sysUser.getSchoolId(), examPrintPlan.getExamId(), examDetailCourse.getCourseCode(), examDetailCourse.getCourseName(), examDetailCourse.getPaperNumber(), FlowStatusEnum.FINISH);
                if (Objects.isNull(examTaskList) || examTaskList.size() == 0) {
                    throw ExceptionResultEnum.EXAM_TASK_IS_NULL.exception();
                }
                Set<Long> examTaskIds = examTaskList.stream().map(ExamTask::getId).collect(Collectors.toSet());
                Map<Long, ExamTask> examTaskMap = examTaskList.stream().collect(Collectors.toMap(ExamTask::getId, Function.identity(), (dto1, dto2) -> dto1));

                QueryWrapper<ExamTaskDetail> examTaskDetailQueryWrapper = new QueryWrapper<>();
                examTaskDetailQueryWrapper.lambda().in(ExamTaskDetail::getExamTaskId, examTaskIds).eq(ExamTaskDetail::getEnable, true);
                List<ExamTaskDetail> examTaskDetailList = examTaskDetailService.list(examTaskDetailQueryWrapper);

                JSONObject jsonObject = new JSONObject();
                JSONArray jsonArray = new JSONArray();
                JSONArray stuJsonArray = new JSONArray();
                Map<String, ExamCard> examCardMap = new HashMap<>();
                for (ExamTaskDetail examTaskDetail : examTaskDetailList) {
                    JSONArray jsonArrayPaper = JSONArray.parseArray(examTaskDetail.getPaperAttachmentIds());
                    ExamCard examCard = null;
                    for (int i = 0; i < jsonArrayPaper.size(); i++) {
                        JSONObject object = jsonArrayPaper.getJSONObject(i);
                        if (Objects.nonNull(object.get("cardId")) && !Objects.equals("", object.get("cardId"))) {
                            examCard = examCardService.getById(Long.parseLong((String) object.get("cardId")));
                            if (Objects.isNull(examCard)) {
                                throw ExceptionResultEnum.EXAM_CARD_IS_NULL.exception();
                            }
                            examCardMap.put((String) object.get("name"), examCard);
                        }
                    }
                    //查询题卡
//                    ExamCard examCard = examCardService.getById(examTaskDetail.getCardId());
//                    if (Objects.isNull(examCard)) {
//                        throw ExceptionResultEnum.EXAM_CARD_IS_NULL.exception();
//                    }

                    ExamTask examTask = examTaskMap.get(examTaskDetail.getExamTaskId());

                    //查询题卡规则
                    BasicCardRule basicCardRule = null;
                    if (!basicCardRuleMap.containsKey(examTask.getCardRuleId())) {
                        basicCardRule = basicCardRuleService.getById(examTask.getCardRuleId());
                        BasicCardRule finalBasicCardRule = basicCardRule;
                        basicCardRuleMap.computeIfAbsent(examTask.getCardRuleId(), v -> finalBasicCardRule);
                    } else {
                        basicCardRule = basicCardRuleMap.get(examTask.getCardRuleId());
                    }

                    //拼装key
                    StringJoiner stringJoiner = new StringJoiner("_");
                    stringJoiner.add(String.valueOf(examDetail.getSchoolId()))
                            .add(String.valueOf(examPrintPlan.getExamId()))
                            .add(String.valueOf(examDetail.getExamStartTime()))
                            .add(String.valueOf(examDetail.getExamEndTime()))
                            .add(examDetailCourse.getCourseCode())
                            .add(examDetailCourse.getPaperNumber());
                    String key = stringJoiner.toString();

                    String paperType;
                    if (Objects.nonNull(paperTypeParam)) {
                        paperType = paperTypeParam;
                        CreatePdfCacheUtil.setPaperType(key, paperType);
                    } else {
                        paperType = createPdfUtil.getPaperType(examPrintPlan.getDrawRule(), examTaskDetail, key);//抽取卷型
                    }
                    //查询考生
                    QueryWrapper<ExamStudent> examStudentQueryWrapper = new QueryWrapper<>();
                    examStudentQueryWrapper.lambda().eq(ExamStudent::getExamDetailCourseId, examDetailCourse.getId());
                    List<ExamStudent> examStudentList = examStudentService.list(examStudentQueryWrapper);

                    // 查询考试
//                    BasicExam basicExam = basicExamService.getById(examTask.getExamId());
                    //
                    List<String> paperTypes = Arrays.stream(paperType.split(",")).sorted(Comparator.comparing(String::valueOf)).collect(Collectors.toList());
                    int backupCount = SystemConstant.calcBackupCount(examDetail.getBackupCount(), examDetail.getTotalSubjects(), 1);

                    // 当前关联试卷类型
                    List<String> relatePaperTypes = new ArrayList<>();
                    if (StringUtils.isNotBlank(examTaskDetail.getRelatePaperType())) {
                        String[] strings = examTaskDetail.getRelatePaperType().split(",");
                        if (strings.length > 0) {
                            relatePaperTypes.addAll(Arrays.asList(strings));
                        }
                    }

                    // 考生实际关联试卷类型
                    List<String> studentPaperTypes = new ArrayList<>();
                    if (examStudentList != null && !examStudentList.isEmpty()) {
                        AtomicInteger atomicInteger = new AtomicInteger(0);
                        for (ExamStudent t : examStudentList) {
                            int i1 = atomicInteger.getAndIncrement();
                            int mod = i1 % examTaskDetail.getDrawCount();
                            t.setPaperType(paperTypes.get(mod));
                            if (!relatePaperTypes.contains(t.getPaperType())) {
                                relatePaperTypes.add(t.getPaperType());
                            }
                            if (!studentPaperTypes.contains(t.getPaperType())) {
                                studentPaperTypes.add(t.getPaperType());
                            }
                        }
                    }

                    examTaskDetail.setRelatePaperType(String.join(",", relatePaperTypes));
                    examDetailCourse.setPaperType(String.join(",", studentPaperTypes));

                    // 试卷数据组装
                    if (printContent.contains("PAPER")) {
                        List<PaperPdfDto> paperPdfDto = createPdfUtil.getPaperPdfFile(examDetailCourse.getPaperType(), examTaskDetail, fileTempList);

                        //获取试卷pdf
                        PdfDto pdfDto = createPdfUtil.getPaperPdf(paperPdfDto, backupCount, backupPaperPdfList);
                        if (Objects.nonNull(pdfDto)) {
                            examDetailCourse.setPaperPagesA3(pdfDto.getPageCount());
                        } else {
                            examDetailCourse.setPaperPagesA3(examDetailCourse.getPaperPagesA3());
                        }
                        // 备用试卷
                        list[0].addAll(backupPaperPdfList);

                        if (examStudentList != null && examStudentList.size() > 0) {
                            for (ExamStudent t : examStudentList) {
                                if (Objects.nonNull(pdfDto)) {
                                    String[] waterMarkNames = {t.getStudentName(), t.getTicketNumber()};
                                    createPdfUtil.getExamStudentPaperPdf(t.getPaperType(), paperPdfDto, studentPaperPdfList, waterMarkNames);
                                }
                            }
                        } else if (examDetail.getPrintCount() != null) {
                            AtomicInteger atomicInteger = new AtomicInteger(0);
                            int i = 0;
                            while (i < examDetail.getPrintCount()) {
                                int seq = atomicInteger.getAndIncrement();
                                int mod = seq % examTaskDetail.getDrawCount();
                                if (Objects.nonNull(pdfDto)) {
                                    createPdfUtil.getExamStudentPaperPdf(paperTypes.get(mod), paperPdfDto, studentPaperPdfList, null);
                                }
                                i++;
                            }
                        } else {
                            throw ExceptionResultEnum.ERROR.exception("数据错误：未找到考生或者印刷数量");
                        }
                        // 考生试卷
                        list[2].addAll(studentPaperPdfList);
                    }

                    // 题卡数据组装
                    basicAttachmentList = Objects.isNull(basicAttachmentList) ? new ArrayList<>() : basicAttachmentList;
                    if (printContent.contains("CARD")) {
                        Map<String, ExamCardDetail> examCardDetailMap = new HashMap<>();
                        Map<String, String> cardContentMap = new HashMap<>();
                        for (String s : examDetailCourse.getPaperType().split(",")) {
                            examCard = examCardMap.get(s);
                            Optional.ofNullable(examCard).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("卷型" + s + "题卡不存在"));

                            QueryWrapper<ExamCardDetail> examCardDetailQueryWrapper = new QueryWrapper<>();
                            examCardDetailQueryWrapper.lambda().eq(ExamCardDetail::getCardId, examCard.getId());
                            ExamCardDetail examCardDetail = examCardDetailService.getOne(examCardDetailQueryWrapper);

                            createPdfUtil.getCardAttachmentId(examCardDetail, attachmentIds);

                            //把模板页面上的 ${} 替换成实际内容
                            String cardContent = createPdfUtil.resetHtmlTemplateBar(examCardDetail.getHtmlContent());

                            for (int i = 1; i <= backupCount; i++) {
                                BasicAttachment basicAttachment = createPdfUtil.cardHtml(String.format(SystemConstant.DATE_TIME_FORMAT, i), cardContent, examDetail, examDetailCourse, s, jsonArray, sysUser.getId(), backupCardPdfList, basicCardRule, fileTempList);
                                examDetailCourse.setCardPagesA3(basicAttachment.getPages());
                                basicAttachmentList.add(basicAttachment);
                            }
                            examCardDetailMap.put(s, examCardDetail);
                            cardContentMap.put(s, cardContent);
                        }
                        // 备用题卡
                        list[1].addAll(backupCardPdfList);

                        if (examStudentList != null && examStudentList.size() > 0) {
                            for (ExamStudent t : examStudentList) {
                                // 用带条码的模板
                                basicAttachmentList.add(createPdfUtil.examStudentHtml(examCardDetailMap.get(t.getPaperType()).getHtmlContent(), t, paperType, examDetail, examDetailCourse, sysUser.getId(), studentCardPdfList, basicCardRule, fileTempList));
                            }
                        } else if (examDetail.getPrintCount() != null) {
                            AtomicInteger atomicInteger = new AtomicInteger(0);
                            Map<String, BasicAttachment> stringBasicAttachmentMap = new HashMap<>();
                            int i = 0;
                            while (i < examDetail.getPrintCount()) {
                                int seq = atomicInteger.getAndIncrement();
                                int mod = seq % examTaskDetail.getDrawCount();
                                String tempPaperType = paperTypes.get(mod);
                                BasicAttachment basicAttachment = createPdfUtil.examStudentHtml(cardContentMap.get(tempPaperType), null, tempPaperType, examDetail, examDetailCourse, sysUser.getId(), studentCardPdfList, basicCardRule, fileTempList);

                                if (!stringBasicAttachmentMap.containsKey(tempPaperType)) {
                                    stringBasicAttachmentMap.put(tempPaperType, basicAttachment);
                                    JSONObject object = new JSONObject();
                                    object.put("name", tempPaperType);
                                    object.put("attachmentId", basicAttachment.getId());
                                    stuJsonArray.add(object);

                                    // 用不带条码的模板
                                    basicAttachmentList.add(basicAttachment);
                                }
                                i++;
                            }
                        } else {
                            throw ExceptionResultEnum.ERROR.exception("数据错误：未找到考生或者印刷数量");
                        }
                        // 题卡
                        list[3].addAll(studentCardPdfList);
                        jsonObject.put("card", jsonArray);
                        examDetailCourse.setAttachmentId(jsonObject.toJSONString());
                        examDetailCourse.setCommonAttachmentId(stuJsonArray.toJSONString());
                    }
                    examStudentService.saveOrUpdateBatch(examStudentList);
                }
                examDetailCourse.setAttachmentId(jsonObject.toJSONString());
                examTaskDetailService.saveOrUpdateBatch(examTaskDetailList);
            }
            detailCourseService.saveOrUpdateBatch(examDetailCourseList);
        }
        return basicAttachmentList;
    }

    /**
     * 创建A4文件
     *
     * @param examPrintPlan
     * @param examDetail
     * @param basicSchool
     * @param examDetailCourseList
     * @param fileTempList
     * @param list
     * @throws IOException
     * @throws DocumentException
     */
    @Transactional
    public void createA4File(ExamPrintPlan examPrintPlan, ExamDetail examDetail, BasicSchool basicSchool, List<ExamDetailCourse> examDetailCourseList, List<File> fileTempList, List<PdfDto>... list) throws Exception {
        // 印品
        String ordinaryContent = examPrintPlan.getOrdinaryContent();
        if (StringUtils.isNotBlank(ordinaryContent)) {
            //获取普通印品
            JSONArray jsonArrayOrdinary = JSONArray.parseArray(ordinaryContent);
            for (int i = 0; i < jsonArrayOrdinary.size(); i++) {
                JSONObject jsonObjectOrdinary = jsonArrayOrdinary.getJSONObject(i);
                if (Objects.nonNull(jsonObjectOrdinary.get("attachmentId")) && !Objects.equals("", jsonObjectOrdinary.get("attachmentId"))) {
                    Long attachmentId = Long.parseLong((String) jsonObjectOrdinary.get("attachmentId"));
                    BasicAttachment basicAttachment = basicAttachmentService.getById(attachmentId);
                    createPdfUtil.createCheckIn(examDetail, basicAttachment, list[0], (Integer) jsonObjectOrdinary.get("backupCount"), fileTempList);
                }
            }
        }

        String variableContent = examPrintPlan.getVariableContent();
        if (StringUtils.isNotBlank(variableContent)) {
            List<Long> examDetailCourseListIds = examDetailCourseList.stream().map(BaseEntity::getId).collect(Collectors.toList());
            List<ExamStudentCourseDto> examStudentCourseDtoList = examStudentService.queryBySchoolIdAndExamDetailCourseIds(basicSchool.getId(), examDetailCourseListIds);
            //获取变量印品
            JSONArray jsonArrayVariable = JSONArray.parseArray(variableContent);
            for (int i = 0; i < jsonArrayVariable.size(); i++) {
                JSONObject jsonObjectVariable = jsonArrayVariable.getJSONObject(i);
                String type = (String) jsonObjectVariable.get("type");
                if (Objects.nonNull(jsonObjectVariable.get("templateId")) && !Objects.equals("", jsonObjectVariable.get("templateId"))) {
                    Long templateId = Long.parseLong((String) jsonObjectVariable.get("templateId"));
                    if (Objects.nonNull(type) && Objects.equals(type.toUpperCase(), "SIGN")) {//签到表
                        createPdfUtil.createSignBook(templateId, basicSchool.getName(), examDetail, examStudentCourseDtoList, list[1], (Integer) jsonObjectVariable.get("backupCount"), examDetailCourseList, fileTempList);
                    } else if (Objects.nonNull(type) && Objects.equals(type.toUpperCase(), "PACKAGE")) {//卷袋贴
                        Integer backupCount = SystemConstant.calcBackupCount(examDetail.getBackupCount(), examDetail.getTotalSubjects(), 1);
                        createPdfUtil.createPaperPackage(templateId, basicSchool.getName(), examDetail, examStudentCourseDtoList, list[1], backupCount, (Integer) jsonObjectVariable.get("backupCount"), examDetailCourseList, examPrintPlan.getExamId(), fileTempList);
                    }
                }
            }
        }

        list[1].sort((o1, o2) -> o1.getSequence() > o2.getSequence() ? 1 : -1);
    }

    /**
     * 创建pdf逻辑
     *
     * @param map
     * @return
     */
    @Override
//    @Transactional
    public Map<String, Object> executeCreatePdfLogic(Map<String, Object> map) throws IOException {
        List<BasicAttachment> basicAttachmentList = null;
        List<File> fileTempList = new ArrayList<>();
        try {
            TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
            SysUser sysUser = (SysUser) map.get(SystemConstant.USER);
            Long examDetailId = tbTask.getEntityId();
            List<Long> examDetailIds = Objects.nonNull(map.get("examDetailIds")) ? (List<Long>) map.get("examDetailIds") : null;
            List<Long> examDetailCourseIds = Objects.nonNull(map.get("examDetailCourseIds")) ? (List<Long>) map.get("examDetailCourseIds") : null;
            String paperTypeParam = Objects.nonNull(map.get("paperType")) ? (String) map.get("paperType") : null;

            //查询printPlan
            ExamPrintPlan examPrintPlan = examPrintPlanService.getById(tbTask.getPrintPlanId());
            if (Objects.isNull(examPrintPlan)) {
                throw ExceptionResultEnum.EXAM_PRINT_IS_NULL.exception();
            }

            BasicSchool basicSchool = commonCacheService.schoolCache(examPrintPlan.getSchoolId());
            BasicPrintConfig basicPrintConfig = basicPrintConfigService.getByExamIdAndOrgId(examPrintPlan.getExamId(), examPrintPlan.getOrgId());
            if (Objects.isNull(basicPrintConfig)) {
                throw ExceptionResultEnum.EXAM_PRINT_CONFIG_IS_NULL.exception();
            }

            //查询examDetail
            QueryWrapper<ExamDetail> examDetailQueryWrapper = new QueryWrapper<>();
            examDetailQueryWrapper.lambda().eq(ExamDetail::getSchoolId, sysUser.getSchoolId())
                    .eq(ExamDetail::getPrintPlanId, tbTask.getPrintPlanId());
            if (Objects.nonNull(examDetailId)) {
                examDetailQueryWrapper.lambda().eq(ExamDetail::getId, examDetailId);
            } else if (Objects.nonNull(examDetailIds)) {
                examDetailQueryWrapper.lambda().in(ExamDetail::getId, examDetailIds);
            }
            List<ExamDetail> examDetailList = detailService.list(examDetailQueryWrapper);
            if (Objects.isNull(examDetailList) || examDetailList.size() == 0) {
                throw ExceptionResultEnum.EXAM_DETAIL_IS_NULL.exception();
            }
            Set<Long> attachmentIds = new HashSet<>();
//            Set<File> ftlList = new HashSet<>();
            for (ExamDetail examDetail : examDetailList) {
                tbTask.setObjName(examDetail.getExamRoom() + SystemConstant.HYPHEN + examDetail.getExamPlace());
                //查询examDetailCourse
                QueryWrapper<ExamDetailCourse> examDetailCourseQueryWrapper = new QueryWrapper<>();
                if (Objects.nonNull(examDetailCourseIds) && examDetailCourseIds.size() > 0) {
                    examDetailCourseQueryWrapper.lambda().in(ExamDetailCourse::getId, examDetailCourseIds);
                } else {
                    examDetailCourseQueryWrapper.lambda().eq(ExamDetailCourse::getExamDetailId, examDetail.getId());
                }
                List<ExamDetailCourse> examDetailCourseList = detailCourseService.list(examDetailCourseQueryWrapper);
                List<PdfDto> variablePdfList = new ArrayList<>();//变量印品(签到表、卷袋贴)
                List<PdfDto> ordinaryPdfList = new ArrayList<>();//普通印品(登记表)
                List<PdfDto> paperPdfList = new ArrayList<>();//所有试卷
                List<PdfDto> examStudentPdfList = new ArrayList<>();//所有题卡
                List<PdfDto> backupPaperPdfList = new ArrayList<>();//备份试卷
                List<PdfDto> backupCardPdfList = new ArrayList<>();//备份题卡

                //创建pdf核心逻辑
                basicAttachmentList = createPdfCoreLogic(examDetailCourseList,
                        examPrintPlan,
                        examDetail,
                        sysUser,
                        paperTypeParam,
                        basicAttachmentList,
                        attachmentIds,
                        fileTempList,
                        backupPaperPdfList,
                        backupCardPdfList,
                        paperPdfList,
                        examStudentPdfList);

                createA4File(examPrintPlan, examDetail, basicSchool, examDetailCourseList, fileTempList, ordinaryPdfList, variablePdfList);

                //合并A3（试卷+题卡+备用试卷+备用题卡）
//                String dirNameA3 = createPdfUtil.mergeA3Pdf(paperPdfList, examStudentPdfList, backupPaperPdfList, backupCardPdfList);
                //合并（试卷+备用试卷）
                String dirNamePaper = createPdfUtil.mergeA3Pdf(fileTempList, paperPdfList, backupPaperPdfList);
                //合并A4（签到表+卷袋贴+登记表）
                String dirNameA4 = createPdfUtil.mergeA4Pdf(fileTempList, variablePdfList, ordinaryPdfList);
                //合并A3（题卡+备用题卡）
                String dirNameCardA3 = createPdfUtil.mergeA3Pdf(fileTempList, examStudentPdfList, backupCardPdfList);

//                BasicAttachment attachment = createPdfUtil.mergePdfSaveDb(dirNameA4, dirNameA3, dirNameCardA3, tbTask, sysUser.getId(), examDetail, basicExamRule, mergePdfDeleteList);
                BasicAttachment attachment = createPdfUtil.mergePdfSaveDb(dirNamePaper, dirNameCardA3, tbTask, sysUser.getId(), examDetail, basicPrintConfig, fileTempList);
                if (basicAttachmentList != null) {
                    basicAttachmentList.add(attachment);
                }

                examDetailService.updateById(examDetail);
            }
            updateExamPrintPlan(basicPrintConfig, examPrintPlan);
            map.computeIfAbsent("size", v -> examDetailList.size());
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (Objects.nonNull(dictionaryConfig.sysDomain()) && dictionaryConfig.sysDomain().isOss()) {
                basicAttachmentService.batchDeleteAttachment(basicAttachmentList);
            }
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        } finally {
            if (!CollectionUtils.isEmpty(fileTempList)) {
                for (File file : fileTempList) {
                    file.delete();
                }
            }
        }
        return map;
    }

    /**
     * 更新考试计划
     *
     * @param basicPrintConfig
     * @param examPrintPlan
     */
    @Transactional
    public void updateExamPrintPlan(BasicPrintConfig basicPrintConfig, ExamPrintPlan examPrintPlan) {
        if (PrintMethodEnum.AUTO == basicPrintConfig.getPrintMethod()) {
            examPrintPlan.setStatus(PrintPlanStatusEnum.PRINTING);
            examPrintPlanService.updateById(examPrintPlan);
        }
    }

    @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 = stringJoiner.toString().replaceAll("\\\\", SystemConstant.ORG_SPLIT);
        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 = (dictionaryConfig.fssPublicDomain().getConfig() + File.separator + dirName).replaceAll("\\\\", SystemConstant.ORG_SPLIT);
            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();
        if (!tbTaskService.countByPrintPlanIdAndEntityId(schoolId, printPlanId, null)) {
            throw ExceptionResultEnum.ERROR.exception("当前印刷计划正在生成pdf文件,无法导入考务数据");
        }
        Long userId = tbTask.getCreateId();
        ExamPrintPlan examPrintPlan = examPrintPlanService.getById(printPlanId);

        if (examPrintPlan == null) {
            throw ExceptionResultEnum.ERROR.exception("印刷计划不存在");
        }

        PrintPlanStatusEnum printPlanStatus = examPrintPlan.getStatus();
        if (PrintPlanStatusEnum.NEW != printPlanStatus && PrintPlanStatusEnum.READY != printPlanStatus) {
            throw ExceptionResultEnum.ERROR.exception(printPlanStatus + "状态下的印刷计划不允许导入");
        }

        String printPlanName = examPrintPlan.getName();

        // 该学校有效考务数据
        List<FieldsDto> fieldsDtoList = examDetailService.findExaminationFields(schoolId);
        if (fieldsDtoList.size() == 0) {
            throw ExceptionResultEnum.ERROR.exception("该学校没有设置考务数据");
        }
        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("文件格式异常");
        }
        // 读取第一个工作表
        Sheet sheet = workbook.getSheetAt(0);
        if (sheet.getLastRowNum() == 0 && sheet.getPhysicalNumberOfRows() == 0) {
            throw ExceptionResultEnum.ERROR.exception("第一个sheet为空,考务数据必须放在第一个sheet（工作表）内");
        }
        // 获取sheet行数
        int totalRows = sheet.getPhysicalNumberOfRows();
        // 获取sheet列数
        int totalCells = 0;
        if (totalRows > 1 && sheet.getRow(0) != null) {
            totalCells = sheet.getRow(0).getPhysicalNumberOfCells();
        }
        // 获取sheet的title
        Row head = sheet.getRow(0);
        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);
                }
            }
            headList.add(cellValue);
        }

        // 搜索所有有效字段 excel中的表头是否包含
        for (FieldsDto fieldsDto : fieldsDtoList) {
            if (!headList.contains(fieldsDto.getName())) {
                throw ExceptionResultEnum.ERROR.exception("学校考务必填字段 ：'" + fieldsDto.getName() + "' 不存在");
            }
        }
        List<ExaminationImportDto> examinationImportDtoList = new ArrayList<>();
        for (int r = 1; r < totalRows; r++) {
            Row row = sheet.getRow(r);
            if (ExcelUtil.isRowAllCellEmpty(row, head)) {
                // excel中整行为空，直接跳过
                continue;
            }

            List<FieldsDto> secondaryFieldList = new ArrayList<>(); // 备选字段

            ExaminationImportDto examinationImportDto = new ExaminationImportDto();
            Field[] examinationImportDtoFields = examinationImportDto.getClass().getDeclaredFields();
            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);
                    if (cell == null) {
                        throw ExceptionResultEnum.ERROR.exception("excel中第[" + (r + 1) + "]行,第[" + (index + 1) + "]列,字段[" + name + "]必填");
                    }
                    String cellValue = String.valueOf(ExcelUtil.convert(cell));
                    if (cellValue == null || cellValue.length() < 1 || cellValue.equals("null")) {
                        throw ExceptionResultEnum.ERROR.exception("excel中第[" + (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;
                            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);
                    }
                }
            }
            // 校验试卷编号
            examTaskService.verifyCourseCodeByPaperNumber(schoolId, examPrintPlan.getExamId(), examinationImportDto.getPaperNumber(), examinationImportDto.getCourseCode());

            // 校验课程信息
            basicCourseService.verifyCourseInfo(schoolId, examinationImportDto.getCourseCode(), examinationImportDto.getCourseName(), userId);

            // 解析时间
            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.setSecondaryFieldList(secondaryFieldList);
            examinationImportDto.setExamStartTime(examStartTime);
            examinationImportDto.setExamEndTime(examEndTime);
            examinationImportDto.setSchoolId(schoolId);
            examinationImportDto.setPrintPlanId(printPlanId);
            examinationImportDto.setPrintPlanName(printPlanName);
            examinationImportDtoList.add(examinationImportDto);
        }

        // 按考点+开始时间+课程代码+考场排序
        examinationImportDtoList.sort(
                Comparator.comparing(ExaminationImportDto::getExamPlace)
                        .thenComparing(ExaminationImportDto::getExamStartTime)
                        .thenComparing(ExaminationImportDto::getCourseCode)
                        .thenComparing(ExaminationImportDto::getExamRoom)
        );

        // 校验课程代码和试卷编号在印刷计划下是1对1的关系
        List<String> paperNumberList = examinationImportDtoList.stream().map(ExaminationImportDto::getPaperNumber).distinct().collect(Collectors.toList());
        for (String paperNumber : paperNumberList) {
            List<String> tmp = examinationImportDtoList.stream().filter(e -> paperNumber.equals(e.getPaperNumber()))
                    .map(ExaminationImportDto::getCourseCode).distinct().collect(Collectors.toList());
            if (tmp.size() != 1) {
                throw ExceptionResultEnum.ERROR.exception("试卷编号为 " + paperNumber + ",对应多个课程代码 : " + tmp);
            }
        }

        // 删除印刷计划下的考务数据
        examDetailService.deleteExaminationData(printPlanId, null);

        // 卷袋号生成规则
        SerialNumberParams serialNumberParams = new SerialNumberParams("packageCode-" + schoolId, "1", 6);
        String key = serialNumberParams.getModel() + serialNumberParams.getPrefix();
        RedisAtomicLong counter = new RedisAtomicLong(key, Objects.requireNonNull(redisTemplate.getConnectionFactory()));
        Long value = counter.get();
        String date = DateUtil.today().replace(SystemConstant.HYPHEN, "");
        String keyStudent = "ticketNumber" + tbTask.getSchoolId() + date.substring(2, date.length());
        RedisAtomicLong counterStudent = new RedisAtomicLong(keyStudent, Objects.requireNonNull(redisTemplate.getConnectionFactory()));
        Long valueStudent = counterStudent.get();
        try {
            // 组装exam_detail数据
            List<Long> examDetailIdList = examDetailService.disposeExamDetailByExaminationExcel(examPrintPlan, examinationImportDtoList, userId, serialNumberParams, sysUser);
            // 组装exam_detail_course数据
            examDetailService.disposeExamDetailCourseByExaminationExcel(examinationImportDtoList, userId, sysUser);
            // 组装exam_student数据
            examDetailService.disposeExamStudentByExaminationExcel(examPrintPlan.getExamId(), examinationImportDtoList, userId, sysUser);

            // 更改印刷计划状态
            examPrintPlan.setStatus(PrintPlanStatusEnum.READY);
            examPrintPlanService.updateById(examPrintPlan);

            map.put("examDetailIdList", examDetailIdList);
            map.put("dataCount", examinationImportDtoList.size());
        } catch (Exception e) {
            redisTemplate.opsForValue().set(key, value);
            redisTemplate.opsForValue().set(keyStudent, valueStudent);
            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, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return map;
    }

    /**
     * 下载pdf
     *
     * @param map
     * @return
     * @throws IOException
     */
    @Override
    @Transactional
    public Map<String, Object> executeDownloadPdfLogic(Map<String, Object> map) throws Exception {
        List<File> sourceFileList = null;
        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("数组id为空");
            }

            List<ExamDetailPdfDownloadDto> examDetailList = examDetailService.findPdfDownload(Arrays.asList(arraysParams.getIds()));
            if (!CollectionUtils.isEmpty(examDetailList)) {
                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("印刷任务管理_批量下载PDF_" + time).add(SystemConstant.ZIP_PREFIX);

                String zipDirName = stringJoiner.toString().replaceAll("\\\\", SystemConstant.ORG_SPLIT);
                zipFile = SystemConstant.getFileTempDirVar(SystemConstant.ZIP_PREFIX);
                zipLocalRootPath = zipFile.getParent() + File.separator + time;

                sourceFileList = new ArrayList<>(examDetailList.size() * 5);
                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());
                        File paperFile = getAttachmentFile(attachment, dirPath.toString() + PdfTypeEnum.PAPER.getTitle() + SystemConstant.PDF_PREFIX);
                        if (Objects.nonNull(paperFile)) {
                            sourceFileList.add(paperFile);
                        }
                    }

                    //题卡合并文件
                    if (Objects.nonNull(e.getCardAttachmentId())) {
                        BasicAttachment cardAttachment = basicAttachmentService.getById(e.getCardAttachmentId());
                        File cardFile = getAttachmentFile(cardAttachment, dirPath.toString() + PdfTypeEnum.CARD_A3.getTitle() + SystemConstant.PDF_PREFIX);
                        if (Objects.nonNull(cardFile)) {
                            sourceFileList.add(cardFile);
                        }
                    }

                    //卷袋贴/签到表/登记表文件
                    if (Objects.nonNull(e.getCardAttachmentId())) {
                        JSONObject js = JSONObject.parseObject(e.getAttachmentPath());
                        JSONArray jsonArrayTemp = js.getJSONArray(SystemConstant.PATH);
                        for (int i = 0; i < jsonArrayTemp.size(); i++) {
                            JSONObject object = jsonArrayTemp.getJSONObject(i);
                            PdfTypeEnum pdfTypeEnum = PdfTypeEnum.valueOf((String) object.get("printType"));
                            switch (pdfTypeEnum) {
                                case PACKAGE:
                                case SIGN:
                                case CHECK_IN:
                                    File file = getJsonFile(object, dirPath.toString() + pdfTypeEnum.getTitle() + SystemConstant.PDF_PREFIX);
                                    if (Objects.nonNull(file)) {
                                        sourceFileList.add(file);
                                    }
                                    break;
                                default:
                                    break;
                            }
                        }
                    }
                }
                if (!CollectionUtils.isEmpty(sourceFileList)) {
                    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, 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;
    }

    /**
     * 获取附件文件
     *
     * @param jsonObject
     * @param pathName
     * @return
     * @throws Exception
     */
    private File getJsonFile(JSONObject jsonObject, String pathName) throws Exception {
        File file = new File(pathName);
        if (!file.exists()) {
            file.getParentFile().mkdirs();
            file.createNewFile();
        }
        String attachmentType = jsonObject.getString(SystemConstant.TYPE);
        if (Objects.nonNull(attachmentType) && !Objects.equals(attachmentType, SystemConstant.LOCAL)) {
            file = fileStoreUtil.ossDownload(jsonObject.getString(SystemConstant.PDF_PATH), file, UploadFileEnum.PDF.getFssType());
        } else {
            File sourceFile = null;
            if (dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT) || dictionaryConfig.fssPublicDomain().getConfig().startsWith(SystemConstant.START_PARENT)) {
                sourceFile = new File(dictionaryConfig.fssPrivateDomain().getConfig(), jsonObject.getString(SystemConstant.PDF_PATH));
            } else {
                sourceFile = new File(jsonObject.getString(SystemConstant.PDF_PATH));
            }
            FileUtils.copyFile(sourceFile, file);
        }
        return file;
    }

    /**
     * 获取附件文件
     *
     * @param attachment
     * @param pathName
     * @return
     * @throws Exception
     */
    private File getAttachmentFile(BasicAttachment attachment, String pathName) throws Exception {
        File file = null;
        if (Objects.nonNull(attachment) && Objects.nonNull(attachment.getPath())) {
            file = new File(pathName);
            if (!file.exists()) {
                file.getParentFile().mkdirs();
                file.createNewFile();
            }
            JSONObject jsonObject = JSONObject.parseObject(attachment.getPath());
            String attachmentType = jsonObject.getString(SystemConstant.TYPE);
            UploadFileEnum uploadFileEnum = UploadFileEnum.valueOf(jsonObject.getString(SystemConstant.UPLOAD_TYPE));
            if (Objects.nonNull(attachmentType) && !Objects.equals(attachmentType, SystemConstant.LOCAL)) {
                file = fileStoreUtil.ossDownload(jsonObject.getString(SystemConstant.PATH), file, uploadFileEnum.getFssType());
            } else {
                File sourceFile = null;
                if (dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT) || dictionaryConfig.fssPublicDomain().getConfig().startsWith(SystemConstant.START_PARENT)) {
                    sourceFile = new File(dictionaryConfig.fssPrivateDomain().getConfig(), jsonObject.getString(SystemConstant.PATH));
                } else {
                    sourceFile = new File(jsonObject.getString(SystemConstant.PATH));
                }
                FileUtils.copyFile(sourceFile, file);
            }
        }
        return file;
    }

    @Override
    @Transactional
    public Map<String, Object> executeExportSampleLogic(Map<String, Object> map) throws Exception {
        File zipFile = null;
        String zipLocalRootPath = null;
        try {
            int count = 0;
            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 = stringJoiner.toString().replaceAll("\\\\", SystemConstant.ORG_SPLIT);
            zipFile = SystemConstant.getFileTempDirVar(SystemConstant.ZIP_PREFIX);
            zipLocalRootPath = zipFile.getParent() + File.separator + time;

            // 跟文件路径
            Long[] ids = (Long[]) map.get("ids");
            for (Long id : ids) {
                ExamTask examTask = examTaskService.getById(id);
                if (Objects.isNull(examTask)) {
                    throw ExceptionResultEnum.ERROR.exception("未找到命题任务");
                }
                String examTaskSign = examTask.getCourseName() + SystemConstant.HYPHEN + examTask.getPaperNumber();
                String firstPath = zipLocalRootPath + File.separator + examTaskSign;
                ReviewSampleDto reviewSampleDto = examTaskService.findReviewSampleInfoByExamTaskId(id);

                // 收集处理试卷和题卡
                List<ExamPaperInfoDto> paperInfoDtoList = JSONObject.parseArray(reviewSampleDto.getPaperAttachmentIds(), ExamPaperInfoDto.class);
                if (Objects.isNull(paperInfoDtoList)) {
                    throw ExceptionResultEnum.ERROR.exception("试卷信息不存在");
                }
                Set<Long> attPaperIds = new HashSet<>();
                List<ExamCardDto> examCardDtoList = new ArrayList<>();
                for (ExamPaperInfoDto paperInfo : paperInfoDtoList) {
                    Long attachmentId = paperInfo.getAttachmentId();
                    Long cardId = paperInfo.getCardId();
                    String paperType = paperInfo.getName();
                    if (SystemConstant.longNotNull(attachmentId)) {
                        attPaperIds.add(attachmentId);
                    }
                    if (SystemConstant.longNotNull(cardId)) {
                        ExamCardDto examCardDto = new ExamCardDto();
                        examCardDto.setCardId(cardId);
                        examCardDto.setPaperType(paperType);
                        examCardDtoList.add(examCardDto);
                    }
                }
                if (attPaperIds.size() > 0) {
                    List<BasicAttachment> paperAttachmentList = basicAttachmentService.listByIds(attPaperIds);
                    for (BasicAttachment paperAttachment : paperAttachmentList) {
                        JSONObject jsonObject = JSONObject.parseObject(paperAttachment.getPath());
                        UploadFileEnum uploadFileEnum = UploadFileEnum.valueOf((String) jsonObject.get(SystemConstant.UPLOAD_TYPE));
                        String paperPath = firstPath + File.separator + "试卷" + File.separator + paperAttachment.getName() + paperAttachment.getType();
                        if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {
                            fileStoreUtil.ossDownload((String) jsonObject.get(SystemConstant.PATH), paperPath, uploadFileEnum.getFssType());
                        } else {
                            FileUtil.copyFile(jsonObject.getString(SystemConstant.PATH), paperPath);
                        }
                        count++;
                    }
                }

                // 处理审核样品
                List<Map> confirmInfo = JSONObject.parseArray(reviewSampleDto.getPaperConfirmAttachmentIds(), Map.class);
                Set<Long> attConfirmIds = new HashSet<>();
                for (Map confirmMap : confirmInfo) {
                    if (Objects.isNull(confirmMap.get("attachmentId"))) {
                        throw ExceptionResultEnum.ERROR.exception("未找到附件id");
                    }
                    Long attachmentId = Long.valueOf(String.valueOf(confirmMap.get("attachmentId")));
                    attConfirmIds.add(attachmentId);
                }
                if (attConfirmIds.size() > 0) {
                    List<BasicAttachment> confirmAttachmentList = basicAttachmentService.listByIds(attConfirmIds);
                    for (BasicAttachment confirmAttachment : confirmAttachmentList) {
                        JSONObject jsonObject = JSONObject.parseObject(confirmAttachment.getPath());
                        UploadFileEnum uploadFileEnum = UploadFileEnum.valueOf((String) jsonObject.get(SystemConstant.UPLOAD_TYPE));
                        String confirmPath = firstPath + File.separator + "审核样本" + File.separator + confirmAttachment.getName() + confirmAttachment.getType();
                        if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {
                            fileStoreUtil.ossDownload((String) jsonObject.get(SystemConstant.PATH), confirmPath, uploadFileEnum.getFssType());
                        } else {
                            FileUtil.copyFile(jsonObject.getString(SystemConstant.PATH), confirmPath);
                        }
                        count++;
                    }
                }

                // 处理题卡
                for (ExamCardDto examCardDto : examCardDtoList) {
                    Long cardId = examCardDto.getCardId();
                    String paperType = examCardDto.getPaperType();
                    ExamCard examCard = examCardService.getById(cardId);
                    if (Objects.isNull(examCard)) {
                        throw ExceptionResultEnum.ERROR.exception("找不到答题卡");
                    }
                    MakeMethodEnum makeMethodEnum = examCard.getMakeMethod();
                    if (MakeMethodEnum.SELECT.equals(makeMethodEnum) && CardCreateMethodEnum.UPLOAD.equals(examCard.getCreateMethod())) {
                        Long attachmentId = examCard.getAttachmentId();
                        if (attachmentId == null || attachmentId == 0) {
                            throw ExceptionResultEnum.ERROR.exception("找不到模板对应的附件");
                        }
                        BasicAttachment cardAttachment = basicAttachmentService.getById(attachmentId);
                        if (Objects.isNull(cardAttachment)) {
                            throw ExceptionResultEnum.ERROR.exception("找不到附件");
                        }
                        JSONObject jsonObject = JSONObject.parseObject(cardAttachment.getPath());
                        // 题卡路径
                        String cardPath = firstPath + File.separator + "题卡" + File.separator + cardAttachment.getName() + cardAttachment.getType();
                        if (SystemConstant.strNotNull(paperType)) {
                            cardPath = cardPath + "(" + paperType + ")";
                        }
                        UploadFileEnum uploadFileEnum = UploadFileEnum.valueOf((String) jsonObject.get(SystemConstant.UPLOAD_TYPE));

                        if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {
                            fileStoreUtil.ossDownload((String) jsonObject.get(SystemConstant.PATH), cardPath, uploadFileEnum.getFssType());
                        } else {
                            FileUtil.copyFile(jsonObject.getString(SystemConstant.PATH), cardPath);
                        }
                    } else {
                        List<ExamCardDetail> examCardDetailList = examCardDetailService.list(new QueryWrapper<ExamCardDetail>().lambda().eq(ExamCardDetail::getCardId, cardId));
                        if (examCardDetailList.size() != 1) {
                            throw ExceptionResultEnum.ERROR.exception("题卡明细信息异常");
                        }
                        ExamCardDetail examCardDetail = examCardDetailService.getByCardId(cardId);
                        String htmlContent = examCardDetail.getHtmlContent();
                        byte[] bytes = htmlContent.getBytes(StandardCharsets.UTF_8);

                        // 题卡路径
                        String cardPath = firstPath + File.separator + "题卡" + File.separator + examCard.getTitle();
                        if (SystemConstant.strNotNull(paperType)) {
                            cardPath = cardPath + "(" + paperType + ")";
                        }
                        cardPath = cardPath + SystemConstant.HTML_PREFIX;

                        File localFile = new File(cardPath);
                        if (!localFile.getParentFile().exists()) {
                            localFile.getParentFile().mkdirs();
                        }
                        FileCopyUtils.copy(bytes, localFile);
                    }
                }
                count++;
            }
            JSONObject jsonObject = SystemConstant.createZip(zipFile, zipLocalRootPath, zipDirName);
            tbTask.setResultFilePath(jsonObject.toJSONString());
            map.put("count", count);
        } 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 (Objects.nonNull(zipLocalRootPath)) {
                ConvertUtil.delFolder(zipLocalRootPath);
            }
        }
        return map;
    }

    @Override
    public Map<String, Object> executeExportPaperAndCardLogic(Map<String, Object> map) throws Exception {
        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 = stringJoiner.toString().replaceAll("\\\\", SystemConstant.ORG_SPLIT);
            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()).add(File.separator)
                        .add(examTaskDetailPdfDownloadDto.getPaperNumber()).add(File.separator)
                        .add(examTaskDetailPdfDownloadDto.getCourseNameCode()).add(SystemConstant.HYPHEN)
                        .add(examTaskDetailPdfDownloadDto.getPaperNumber()).add(SystemConstant.HYPHEN);
                // 试卷
                String paperAttachmentIds = examTaskDetailPdfDownloadDto.getPaperAttachmentIds();
                if (StringUtils.isNotBlank(paperAttachmentIds)) {
                    List<Map> paperInfo = JSONObject.parseArray(paperAttachmentIds, Map.class);
                    if (Objects.isNull(paperInfo)) {
                        throw ExceptionResultEnum.ERROR.exception("试卷信息不存在");
                    }
                    for (Map paperMap : paperInfo) {
                        if (Objects.nonNull(paperMap.get("attachmentId")) && String.valueOf(paperMap.get("attachmentId")).length() > 0 && !String.valueOf(paperMap.get("attachmentId")).equals("null")) {
                            String name = paperMap.get("name").toString();
                            Long attachmentId = Long.valueOf(String.valueOf(paperMap.get("attachmentId")));
                            BasicAttachment attachment = basicAttachmentService.getById(attachmentId);
                            if (Objects.nonNull(attachment)) {
                                File paperFile = getAttachmentFile(attachment, dirPath.toString() + "试卷" + SystemConstant.HYPHEN + name + attachment.getType());
                                sourceFileList.add(paperFile);
                            }
                        }
                        ExamCard examCard = examCardService.getById(Long.parseLong((String) paperMap.get("cardId")));
                        Optional.ofNullable(examCard).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("找不到答题卡"));

                        MakeMethodEnum makeMethodEnum = examCard.getMakeMethod();

                        String cardHtmlPath = dirPath.toString() + "题卡" + SystemConstant.HYPHEN + paperMap.get("name") + SystemConstant.HTML_PREFIX;
                        String cardPdfPath = dirPath.toString() + "题卡" + SystemConstant.HYPHEN + paperMap.get("name") + SystemConstant.PDF_PREFIX;
                        // 通用题卡
                        ExamCardDetail examCardDetail = examCardDetailService.getByCardId(examCard.getId());
                        String htmlContent;
                        if (MakeMethodEnum.SELECT.equals(makeMethodEnum)) {
                            htmlContent = createPdfUtil.resetHtmlTemplateBar(examCardDetail.getHtmlContent());
                        } else {
                            BasicCardRule basicCardRule = basicCardRuleService.getById(examTask.getCardRuleId());
                            htmlContent = createPdfUtil.replaceHtmlCard(examCardDetail, basicCardRule);
                        }
                        // 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, 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> executeImportBasicStudentLogic(Map<String, Object> map) throws Exception {
        InputStream inputStream = (InputStream) map.get("inputStream");
        List<String> studentCodeList = new ArrayList<>();
        List<BasicStudentErrorExportDto> errorDataList = new ArrayList<>();
        AtomicInteger totalInteger = new AtomicInteger(0);
        AtomicInteger successInteger = new AtomicInteger(0);
        List<LinkedMultiValueMap<Integer, Object>> finalList = ExcelUtil.excelReader(inputStream, Lists.newArrayList(BasicStudentImportDto.class, DescribeImportDto.class), (finalExcelList, finalColumnNameList, finalExcelErrorList) -> {
            Map<String, String> checkCodeMap = new HashMap<>();
            Map<String, String> checkPhoneMap = new HashMap<>();
            for (int i = 0; i < finalExcelList.size(); i++) {
                LinkedMultiValueMap<Integer, Object> excelMap = finalExcelList.get(i);
                List<Object> basicStudentImportDtoList = excelMap.get(i);
                assert basicStudentImportDtoList != null;
                if (basicStudentImportDtoList.get(0) instanceof DescribeImportDto) {
                    continue;
                }
                for (int y = 0; y < Objects.requireNonNull(basicStudentImportDtoList).size(); y++) {
                    BasicStudentImportDto basicStudentImportDto = (BasicStudentImportDto) basicStudentImportDtoList.get(y);
                    totalInteger.getAndIncrement();

                    BasicStudentErrorExportDto basicStudentErrorExportDto = new BasicStudentErrorExportDto();
                    BeanUtils.copyProperties(basicStudentImportDto, basicStudentErrorExportDto);


                    String studentName = basicStudentImportDto.getStudentName();
                    String studentCode = basicStudentImportDto.getStudentCode();
                    String phoneNumber = basicStudentImportDto.getPhoneNumber();
                    String clazzName = basicStudentImportDto.getClazzName();
                    studentCodeList.add(studentCode);

                    StringJoiner errorStringJoiner = new StringJoiner(";");
                    String errorStringEmpty = ExcelUtil.checkExcelField(basicStudentImportDto);
                    if (errorStringEmpty.length() > 0) {
                        errorStringJoiner.add(errorStringEmpty);
                    }

                    // 检验学号
                    if (SystemConstant.strNotNull(studentCode)) {
                        if (checkCodeMap.containsKey(studentCode)) {
                            errorStringJoiner.add("学号[" + studentCode + "]重复");
                        } else {
                            checkCodeMap.put(studentCode, studentName);
                        }
                    }
                    // 如果电话有值则检验电话excel中唯一性
                    if (SystemConstant.strNotNull(phoneNumber)) {
                        if (checkPhoneMap.containsKey(phoneNumber)) {
                            errorStringJoiner.add("手机号[" + phoneNumber + "]重复");
                        } else {
                            checkPhoneMap.put(phoneNumber, studentCode);
                        }
                    }

                    if (Objects.isNull(studentName) || studentName.length() > 30) {
                        errorStringJoiner.add("[姓名]最长30个字符");
                    }
                    if (Objects.isNull(studentCode) || studentCode.length() > 30 || !studentCode.matches(SystemConstant.REGULAR_EXPRESSION_OF_CODE)) {
                        errorStringJoiner.add("[学号]最长30个字符");
                    }
                    if (Objects.nonNull(phoneNumber) && !phoneNumber.matches(SystemConstant.REGULAR_EXPRESSION_OF_PHONE)) {
                        errorStringJoiner.add("[手机号]不符合规范");
                    }
                    String errorString = errorStringJoiner.toString();
                    if (errorString.length() > 0) {
                        basicStudentErrorExportDto.setErrorMsg(errorString);
                        errorDataList.add(basicStudentErrorExportDto);
                        basicStudentImportDtoList.remove(y);
                    } else {
                        // 校验通过的数据
                        successInteger.getAndIncrement();
                    }
                }
            }
            if (!errorDataList.isEmpty()) {
                map.put(SystemConstant.ERROR_DATA_LIST, errorDataList);
            }
            map.put("studentCodeList", studentCodeList);
            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;
        });
        return basicStudentService.executeBasicStudentImportLogic(finalList, 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 (sysUserImportDtoList.isEmpty() || sysUserImportDtoList.get(0) instanceof DescribeImportDto) {
                    continue;
                }
                map.put(SystemConstant.DATA_COUNT, sysUserImportDtoList.size());
                List<SysUserImportDto> duplicateData = new ArrayList<>();
                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 code = sysUserImportDto.getCode();
                    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(code)) {
                        SysUserImportDto primaryCell = checkDtoMap.get(code);
                        String priName = primaryCell.getName();
                        String priPhoneNumber = primaryCell.getPhoneNumber();
                        String priOrgName = primaryCell.getOrgName();
                        if (!Objects.equals(priName, name)) {
                            errorStringJoiner.add("工号[" + code + "]的用户存在不同的姓名");
                        }
                        if (!Objects.equals(priPhoneNumber, phoneNumber)) {
                            errorStringJoiner.add("工号[" + code + "]的用户存在不同的手机号");
                        }
                        if (!Objects.equals(priOrgName, orgName)) {
                            errorStringJoiner.add("工号[" + code + "]的用户存在不同的组织架构");
                        }
                        String priRoleName = primaryCell.getRoleName();
                        if (SystemConstant.strNotNull(roleName)) {
                            priRoleName = priRoleName + SystemConstant.COMMA + roleName;
                            primaryCell.setRoleName(priRoleName);
                        }
                        duplicateData.add(sysUserImportDto);
                    } else {
                        checkDtoMap.put(code, sysUserImportDto);
                    }

                    if (Objects.isNull(code) || code.length() > 30 || !code.matches(SystemConstant.REGULAR_EXPRESSION_OF_CODE)) {
                        errorStringJoiner.add("[工号]不符合规范,最长30个字符");
                    }
                    if (Objects.isNull(name) || name.length() > 30) {
                        errorStringJoiner.add("[姓名]不符合输入规范,最长30个字符");
                    }
                    if (Objects.nonNull(phoneNumber) && !phoneNumber.matches(SystemConstant.REGULAR_EXPRESSION_OF_PHONE)) {
                        errorStringJoiner.add("[手机号]不符合输入规范");
                    }

                    String errorString = errorStringJoiner.toString();
                    if (errorString.length() > 0) {
                        sysUserErrorExportDto.setErrorMsg(errorString);
                        errorDataList.add(sysUserErrorExportDto);
                        sysUserImportDtoList.remove(y);
                    } else {
                        // 校验通过的数据
                        successInteger.getAndIncrement();
                    }
                }
            }
            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;
        });
        return sysUserService.executeSysUserImportLogic(finalList, map);
    }

    @Transactional
    @Override
    public Map<String, Object> executeImportBasicClazzLogic(Map<String, Object> map) throws Exception {
        InputStream inputStream = (InputStream) map.get("inputStream");
        System.out.println(inputStream);
        List<LinkedMultiValueMap<Integer, Object>> finalList = ExcelUtil.excelReader(inputStream, Lists.newArrayList(BasicClazzImportDto.class, DescribeImportDto.class), (finalExcelList, finalColumnNameList, finalExcelErrorList) -> {
            List<ExcelError> excelErrorTemp = new ArrayList<>();
            Map<String, String> checkNameMap = new HashMap<>();
            for (int i = 0; i < finalExcelList.size(); i++) {
                LinkedMultiValueMap<Integer, Object> excelMap = finalExcelList.get(i);
                List<Object> basicClazzImportDtoList = excelMap.get(i);
                assert basicClazzImportDtoList != null;
                if (basicClazzImportDtoList.get(0) instanceof DescribeImportDto) {
                    continue;
                }
                for (int y = 0; y < Objects.requireNonNull(basicClazzImportDtoList).size(); y++) {
                    BasicClazzImportDto basicClazzImportDto = (BasicClazzImportDto) basicClazzImportDtoList.get(y);
                    String clazzName = basicClazzImportDto.getClazzName();

                    // 检验excel中
                    // 检验学号
                    if (checkNameMap.containsKey(clazzName)) {
                        throw ExceptionResultEnum.ERROR.exception("导入的excel中包含在重复的【班级名称】：" + clazzName);
                    } else {
                        checkNameMap.put(clazzName, clazzName);
                    }

                    excelErrorTemp.addAll(ExcelUtil.checkExcelField(basicClazzImportDto, y, i));
                    if (Objects.isNull(clazzName) || clazzName.length() > 50) {
                        excelErrorTemp.add(new ExcelError(y + 1, "excel第" + (i + 1) + "个sheet第" + (y + 1) + "行[学号]不符合输入规范"));
                    }
                }
            }
            if (excelErrorTemp.size() > 0) {
                throw ExceptionResultEnum.ERROR.exception(JSONObject.toJSONString(excelErrorTemp));
            }
            return finalExcelList;
        });
        return basicClazzService.executeBasicClazzImportLogic(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;
        });
        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 = stringJoiner.toString().replaceAll("\\\\", SystemConstant.ORG_SPLIT);
                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) throws Exception {
        TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
        DownloadPaperFileParam downloadPaperFileParam = (DownloadPaperFileParam) map.get("downloadPaperFileParam");
        Long schoolId = tbTask.getSchoolId();
        Long semesterId = downloadPaperFileParam.getSemesterId();
        Long examId = downloadPaperFileParam.getExamId();
        Long orgId = downloadPaperFileParam.getOrgId();
        Boolean namedByCourseInfo = downloadPaperFileParam.getNamedByCourseInfo();
        Boolean namedByPaperNumber = downloadPaperFileParam.getNamedByPaperNumber();
        Boolean namedByOriginalFile = downloadPaperFileParam.getNamedByOriginalFile();
        PaperFileDownloadContentEnum paperFileDownloadContent = downloadPaperFileParam.getPaperFileDownloadContentType();
        PaperFileDownloadExposureStatusEnum paperFileDownloadExposureStatus = downloadPaperFileParam.getPaperFileDownloadExposureStatus();
        String specialSuccessMessage = "";
        if (Objects.nonNull(paperFileDownloadExposureStatus)) {
            switch (paperFileDownloadExposureStatus) {
                case EXPOSED_PAPER: // 曝光的
                    specialSuccessMessage = "所选择的命题任务中没有已曝光的试卷";
                    break;
                case UNEXPOSED_PAPER: // 未曝光的
                    specialSuccessMessage = "所选择的命题任务中没有未曝光的试卷";
                    break;
                default:
                    break;
            }
        }

        String courseName = downloadPaperFileParam.getCourseName();
        Set<Long> idSet = downloadPaperFileParam.getIdSet();

        // 如果idSet集合为空且查询条件的机构id也为空，则请求用户的机构id作为机构数据权限带入查询
        SysUser requestUser = (SysUser) map.get(SystemConstant.USER);
        if ((idSet == null || idSet.size() == 0) && !SystemConstant.longNotNull(orgId)) {
            orgId = requestUser.getOrgId();
        }

        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 = stringJoiner.toString().replaceAll("\\\\", SystemConstant.ORG_SPLIT);
            zipFile = SystemConstant.getFileTempDirVarForZip(SystemConstant.getNanoId(), SystemConstant.ZIP_PREFIX);
            zipLocalRootPath = zipFile.getParent() + File.separator + System.currentTimeMillis();

            ExamTaskPaperDto examTaskPaperDto = downloadService.findDownloadContent(schoolId, semesterId, examId, orgId, courseName, idSet);
            // 导出文件excel
            List<ExamTaskPaperExportDto> examTaskPaperExportDtoList = examTaskPaperDto.getExamTaskPaperExportDtoList();

            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ExcelUtil.excelMake(ExamTaskPaperExportDto.class, examTaskPaperExportDtoList, outputStream);
            InputStream in = new ByteArrayInputStream(outputStream.toByteArray());

            String excelName = "试卷使用清单";
            if (Objects.nonNull(paperFileDownloadExposureStatus)) {
                excelName = excelName + paperFileDownloadExposureStatus.getDesc();
            }
            String excelLocalPath = zipLocalRootPath + File.separator + excelName + "." + SystemConstant.XLSX;
            FileUtils.copyInputStreamToFile(in, new File(excelLocalPath));

            // 所有试卷信息
            List<ExamTaskPaperFileDto> examTaskPaperFileDtoList = examTaskPaperDto.getExamTaskPaperFileDtoList();
            if (examTaskPaperFileDtoList.size() == 0) {
                throw ExceptionResultEnum.ERROR.exception("没有找到任何试卷信息");
            }
            // 二级路径 课程
            Set<String> courseSet = examTaskPaperFileDtoList.stream().map(e -> e.getCourseName() + SystemConstant.HYPHEN + e.getCourseCode()).collect(Collectors.toSet());
            // 文件数以一级目录文件为准（初始1是excel）
            int count = 1;
            for (String course : courseSet) {
                // 三级路径 课程代码-课程名称/试卷编号
                int courseCount = 0;
                Set<String> paperNumberSet = examTaskPaperFileDtoList
                        .stream()
                        .filter(e -> course.equals(e.getCourseName() + SystemConstant.HYPHEN + e.getCourseCode()))
                        .map(ExamTaskPaperFileDto::getPaperNumber)
                        .collect(Collectors.toSet());
                for (String paperNumber : paperNumberSet) {
                    // 试卷下文件集
                    List<ExamTaskPaperFileDto> paperCellList = examTaskPaperFileDtoList
                            .stream()
                            .filter(e -> paperNumber.equals(e.getPaperNumber()))
                            .collect(Collectors.toList());

                    // 文件路径
                    String filePath = zipLocalRootPath + File.separator + course + File.separator + paperNumber + File.separator;

                    // 试卷文件曝光度筛选
                    if (Objects.nonNull(paperFileDownloadExposureStatus)) {
                        switch (paperFileDownloadExposureStatus) {
                            case EXPOSED_PAPER: // 曝光的
                                paperCellList = paperCellList.stream().filter(ExamTaskPaperFileDto::getExposureStatus).collect(Collectors.toList());
                                if (paperCellList.size() > 0) {
                                    specialSuccessMessage = "";
                                }
                                break;
                            case UNEXPOSED_PAPER: // 未曝光的
                                paperCellList = paperCellList.stream().filter(e -> !e.getExposureStatus()).collect(Collectors.toList());
                                if (paperCellList.size() > 0) {
                                    specialSuccessMessage = "";
                                }
                                break;
                            case ALL_PAPER: // 全部试卷
                                break;
                            default:
                                break;
                        }
                    }

                    if (Objects.isNull(paperFileDownloadContent)) {
                        continue;
                    }
                    switch (paperFileDownloadContent) {
                        case ONLY_CARD: // 只下载题卡
                            for (ExamTaskPaperFileDto examTaskPaperFileDto : paperCellList) {
                                Long examCardId = examTaskPaperFileDto.getExamCardId();
                                Long cardRuleId = examTaskPaperFileDto.getCardRuleId();
                                ExamCard examCard = examCardService.getById(examCardId);
                                if (examCard != null) {
                                    ExamCardDetail examCardDetail = examCardDetailService.getByCardId(examCardId);
                                    String htmlContent;
                                    if (MakeMethodEnum.SELECT.equals(examCard.getMakeMethod()) && CardCreateMethodEnum.UPLOAD.equals(examCard.getCreateMethod())) {
                                        htmlContent = createPdfUtil.resetHtmlTemplateBar(examCardDetail.getHtmlContent());
                                    } else {
                                        BasicCardRule basicCardRule = basicCardRuleService.getById(cardRuleId);
                                        htmlContent = createPdfUtil.replaceHtmlCard(examCardDetail, basicCardRule);
                                    }

                                    byte[] bytes = htmlContent.getBytes(StandardCharsets.UTF_8);
                                    String cardName = "题卡-";
                                    if (namedByCourseInfo) {
                                        cardName = cardName + course;
                                    }
                                    if (namedByPaperNumber) {
                                        cardName = cardName + paperNumber;
                                    }
                                    if (namedByOriginalFile) {
                                        cardName = cardName + examCardService.getById(examCardId).getTitle();
                                    }
                                    cardName = cardName + SystemConstant.HYPHEN + examTaskPaperFileDto.getPaperType();
                                    String cardLocalHtmlPath = filePath + cardName + SystemConstant.HTML_PREFIX;
                                    String cardLocalPdfPath = filePath + cardName + SystemConstant.PDF_PREFIX;

                                    File localFile = new File(cardLocalHtmlPath);
                                    if (!localFile.getParentFile().exists()) {
                                        boolean mkr = localFile.getParentFile().mkdirs();
                                    }
                                    FileCopyUtils.copy(bytes, localFile);

                                    File pdfFile = new File(cardLocalPdfPath);
                                    if (!pdfFile.exists()) {
                                        boolean cf = pdfFile.createNewFile();
                                    }
                                    HtmlToPdfUtil.convert(cardLocalHtmlPath, cardLocalPdfPath, PageSizeEnum.A3);
                                }
                                specialSuccessMessage = "";
                                courseCount = 1;
                            }
                            break;
                        case ONLY_PAPER: // 只下载试卷
                            for (ExamTaskPaperFileDto examTaskPaperFileDto : paperCellList) {
                                String paperName = "试卷-";
                                if (namedByCourseInfo) {
                                    paperName = paperName + course;
                                }
                                if (namedByPaperNumber) {
                                    paperName = paperName + paperNumber;
                                }
                                if (namedByOriginalFile) {
                                    paperName = paperName + examTaskPaperFileDto.getPaperName();
                                }
                                paperName = paperName + SystemConstant.HYPHEN + examTaskPaperFileDto.getPaperType();
                                String paperLocalPath = filePath + paperName + examTaskPaperFileDto.getPaperSuffix();
                                String paperPath = examTaskPaperFileDto.getPaperPath();
                                if (StringUtils.isNotBlank(paperPath)) {
                                    if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {
                                        fileStoreUtil.ossDownload(paperPath, paperLocalPath, fileStoreUtil.getUploadEnumByPath(paperPath).getFssType());
                                    } else {
                                        FileUtil.copyFile(paperPath, paperLocalPath);
                                    }
                                }
                                courseCount = 1;
                            }
                            break;
                        case PAPER_AND_CARD: // 全部下载
                            for (ExamTaskPaperFileDto examTaskPaperFileDto : paperCellList) {
                                // 题卡
                                Long examCardId = examTaskPaperFileDto.getExamCardId();
                                Long cardRuleId = examTaskPaperFileDto.getCardRuleId();
                                ExamCard examCard = examCardService.getById(examCardId);
                                if (examCard == null) {
                                    ExamCardDetail examCardDetail = examCardDetailService.getByCardId(examCardId);
                                    String htmlContent;
                                    if (MakeMethodEnum.SELECT.equals(examCard.getMakeMethod()) && CardCreateMethodEnum.UPLOAD.equals(examCard.getCreateMethod())) {
                                        htmlContent = createPdfUtil.resetHtmlTemplateBar(examCardDetail.getHtmlContent());
                                    } else {
                                        BasicCardRule basicCardRule = basicCardRuleService.getById(cardRuleId);
                                        htmlContent = createPdfUtil.replaceHtmlCard(examCardDetail, basicCardRule);
                                    }

                                    byte[] bytes = htmlContent.getBytes(StandardCharsets.UTF_8);
                                    String cardName = "题卡-";
                                    if (namedByCourseInfo) {
                                        cardName = cardName + course;
                                    }
                                    if (namedByPaperNumber) {
                                        cardName = cardName + paperNumber;
                                    }
                                    if (namedByOriginalFile) {
                                        cardName = cardName + examCardService.getById(examCardId).getTitle();
                                    }
                                    cardName = cardName + SystemConstant.HYPHEN + examTaskPaperFileDto.getPaperType();
                                    String cardLocalHtmlPath = filePath + cardName + SystemConstant.HTML_PREFIX;
                                    String cardLocalPdfPath = filePath + cardName + SystemConstant.PDF_PREFIX;
                                    File localCardFile = new File(cardLocalHtmlPath);
                                    if (!localCardFile.getParentFile().exists()) {
                                        boolean mkr = localCardFile.getParentFile().mkdirs();
                                    }
                                    FileCopyUtils.copy(bytes, localCardFile);

                                    File cardPdfFile = new File(cardLocalPdfPath);
                                    if (!cardPdfFile.exists()) {
                                        boolean cf = cardPdfFile.createNewFile();
                                    }
                                    HtmlToPdfUtil.convert(cardLocalHtmlPath, cardLocalPdfPath, PageSizeEnum.A3);
                                }
                                // 试卷
                                String paperName = "试卷-";
                                if (namedByCourseInfo) {
                                    paperName = paperName + course;
                                }
                                if (namedByPaperNumber) {
                                    paperName = paperName + paperNumber;
                                }
                                if (namedByOriginalFile) {
                                    paperName = paperName + examTaskPaperFileDto.getPaperName();
                                }
                                paperName = paperName + SystemConstant.HYPHEN + examTaskPaperFileDto.getPaperType();
                                String paperLocalPath = filePath + paperName + examTaskPaperFileDto.getPaperSuffix();
                                String paperPath = examTaskPaperFileDto.getPaperPath();
                                if (StringUtils.isNotBlank(paperPath)) {
                                    if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {
                                        fileStoreUtil.ossDownload(paperPath, paperLocalPath, fileStoreUtil.getUploadEnumByPath(paperPath).getFssType());
                                    } else {
                                        FileUtil.copyFile(paperPath, paperLocalPath);
                                    }
                                }
                                courseCount = 1;
                            }
                            break;
                        default:
                            break;
                    }
                }
                count = count + courseCount;
            }
            JSONObject jsonObject = SystemConstant.createZip(zipFile, zipLocalRootPath, zipDirName);
            tbTask.setResultFilePath(jsonObject.toJSONString());
            map.put("count", count);
            map.put("specialSuccessMessage", specialSuccessMessage);
        } 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;
    }


    public String createTempNumber(SerialNumberParams serialNumberParams) {
        return convertUtil.getIncre(serialNumberParams.getPrefix(), serialNumberParams.getModel(), serialNumberParams.getDigit());
    }

    /**
     * 验证机构是否存在
     *
     * @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 userMap
     * @param key
     * @param schoolId
     * @param excelErrorTemp
     * @param row
     * @param sheet
     * @param cloumnName
     * @return
     */
    private SysUser validSysUserExists(Map<String, SysUser> userMap,
                                       String key,
                                       Long schoolId,
                                       List<ExcelError> excelErrorTemp,
                                       int row,
                                       int sheet,
                                       String cloumnName) {
        SysUser sysUser = null;
        if (!userMap.containsKey(key)) {//不存在查询
            QueryWrapper<SysUser> sysUserQueryWrapper = new QueryWrapper<>();
            sysUserQueryWrapper.lambda().eq(SysUser::getSchoolId, schoolId)
                    .eq(SysUser::getRealName, key)
                    .eq(SysUser::getEnable, true);
            sysUser = sysUserService.getOne(sysUserQueryWrapper);
        } else {
            sysUser = userMap.get(key);
        }
        if (Objects.isNull(sysUser)) {
            excelErrorTemp.add(new ExcelError(row, "excel第" + sheet + "个sheet第" + row + "行[" + cloumnName + "]不存在"));
        } else {
            SysUser finalSysUser = sysUser;
            userMap.computeIfAbsent(key, v -> finalSysUser);
        }
        return sysUser;
    }

    /**
     * 验证班级是否存在
     *
     * @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::getTeachClazzName, key));
            if (Objects.nonNull(teachClazz)) {
                clazz = new DictionaryResult();
                clazz.setId(teachClazz.getId());
                clazz.setName(teachClazz.getTeachClazzName());
            } 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;
    }
}
