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

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itextpdf.text.pdf.PdfReader;
import com.qmth.boot.api.exception.ApiException;
import com.qmth.distributed.print.business.bean.dto.PdfDto;
import com.qmth.distributed.print.business.bean.dto.PdfPackageDto;
import com.qmth.distributed.print.business.bean.dto.PdfSignDto;
import com.qmth.distributed.print.business.bean.excel.ExcelField;
import com.qmth.distributed.print.business.bean.params.ExamTaskStudentObjectParam;
import com.qmth.distributed.print.business.bean.result.ScoreResult;
import com.qmth.distributed.print.business.entity.*;
import com.qmth.distributed.print.business.enums.ExamDetailStatusEnum;
import com.qmth.distributed.print.business.enums.PrintPlanStatusEnum;
import com.qmth.distributed.print.business.mapper.TCUsualScoreMapper;
import com.qmth.distributed.print.business.service.*;
import com.qmth.distributed.print.business.util.CreatePrintPdfUtil;
import com.qmth.distributed.print.business.util.PdfUtil;
import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
import com.qmth.teachcloud.common.bean.result.TbTaskDetailResult;
import com.qmth.teachcloud.common.bean.vo.FilePathVo;
import com.qmth.teachcloud.common.bean.vo.PrintPathVo;
import com.qmth.teachcloud.common.config.DictionaryConfig;
import com.qmth.teachcloud.common.contant.SpringContextHolder;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.*;
import com.qmth.teachcloud.common.enums.*;
import com.qmth.teachcloud.common.mapper.BasicCourseMapper;
import com.qmth.teachcloud.common.service.*;
import com.qmth.teachcloud.common.util.*;
import com.qmth.teachcloud.mark.entity.MarkPaper;
import com.qmth.teachcloud.mark.service.MarkPaperService;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Description: 公共服务service impl
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2021/3/26
 */
@Service
public class PrintCommonServiceImpl implements PrintCommonService {
    private final static Logger log = LoggerFactory.getLogger(PrintCommonServiceImpl.class);

    @Resource
    private DictionaryConfig dictionaryConfig;

    @Resource
    BasicAttachmentService basicAttachmentService;

    @Resource
    @Lazy
    private ExamTaskService examTaskService;

    @Resource
    private BasicCourseMapper basicCourseMapper;

    @Resource
    @Lazy
    BasicCourseService basicCourseService;

    @Resource
    ExamDetailCourseService examDetailCourseService;

    @Resource
    SysOrgService sysOrgService;

    @Resource
    private SysUserService sysUserService;

    @Resource
    TBTaskService tbTaskService;

    @Resource
    TBTaskPdfService tbTaskPdfService;

    @Resource
    @Lazy
    ExamDetailService examDetailService;

    @Resource
    @Lazy
    ExamTaskDetailService examTaskDetailService;

    @Resource
    ExamPrintPlanService examPrintPlanService;

    @Resource
    TFFlowApproveService tfFlowApproveService;

    @Resource
    private FileStoreUtil fileStoreUtil;

    @Resource
    private FileUploadService fileUploadService;

    @Resource
    TeachcloudCommonService teachcloudCommonService;

    @Resource
    RedisUtil redisUtil;

    @Resource
    BasicExamService basicExamService;

    @Resource
    GradeBatchPaperService gradeBatchPaperService;
    @Resource
    BasicTeachClazzService basicTeachClazzService;
    @Resource
    BasicExamStudentService basicExamStudentService;

    @Resource
    CreatePrintPdfUtil createPrintPdfUtil;

    @Resource
    CommonCacheService commonCacheService;

    @Resource
    RedisCounterUtil redisCounterUtil;

    @Resource
    MarkPaperService markPaperService;

    @Resource
    TCUsualScoreMapper tcUsualScoreMapper;

    @Resource
    BasicRoleDataPermissionService basicRoleDataPermissionService;

    @Resource
    @Lazy
    TCFinalScoreService tcFinalScoreService;

    @Resource
    @Lazy
    TCPaperStructService tcPaperStructService;

    /**
     * 保存附件
     *
     * @param classifyEnum
     * @param examDetail
     * @param basicAttachment
     * @param pdfList
     * @param printCount
     * @param sequence
     * @return
     */
    @Override
    @Transactional
    public BasicAttachment saveAttachmentPdf(ClassifyEnum classifyEnum, ExamDetail examDetail, BasicAttachment basicAttachment, List<PdfDto> pdfList, Integer printCount, Integer sequence) {
        File htmlFileTemp = null;
        try {
            boolean oss = dictionaryConfig.sysDomain().isOss();
            JSONObject jsonObject = JSONObject.parseObject(basicAttachment.getPath());
            String type = basicAttachment.getType(), filePath = null, url = null, ossStr = null;
            File htmlFile = null;

            StringJoiner pdfStringJoiner = new StringJoiner("");
            if (Objects.nonNull(type) && Objects.equals(type, SystemConstant.HTML_PREFIX)) {
                filePath = (String) jsonObject.get(SystemConstant.PATH);
                UploadFileEnum uploadType = Enum.valueOf(UploadFileEnum.class, (String) jsonObject.get(SystemConstant.UPLOAD_TYPE));
                if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {
                    ossStr = oss ? SystemConstant.OSS : SystemConstant.LOCAL;
                    htmlFileTemp = SystemConstant.getFileTempVar(SystemConstant.HTML_PREFIX);

                    htmlFile = fileStoreUtil.ossDownload(filePath, htmlFileTemp, uploadType.getFssType());
                } else {
                    ossStr = SystemConstant.LOCAL;
                    if (Objects.nonNull(dictionaryConfig.fssPublicDomain()) && !StringUtils.isBlank(dictionaryConfig.fssPublicDomain().getConfig()) && filePath.contains(dictionaryConfig.fssPublicDomain().getConfig())) {
                        htmlFile = new File(filePath);
                    } else {
                        htmlFileTemp = SystemConstant.getFileTempVar(SystemConstant.HTML_PREFIX);
                        htmlFile = fileStoreUtil.ossDownload(filePath, htmlFileTemp, uploadType.getFssType());
                    }
                    if (Objects.nonNull(dictionaryConfig.fssPrivateDomain()) && !StringUtils.isBlank(dictionaryConfig.fssPrivateDomain().getConfig()) && !dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT)) {
                        pdfStringJoiner.add(dictionaryConfig.fssPrivateDomain().getConfig()).add(File.separator);
                    }
                }
            }

            pdfStringJoiner = SystemConstant.getDirName(pdfStringJoiner, UploadFileEnum.PDF, true);
            pdfStringJoiner.add(SystemConstant.getNanoId()).add(SystemConstant.PDF_PREFIX);
            String pdfDirName = pdfStringJoiner.toString();
            File pdfFileTemp = SystemConstant.getFileTempVar(SystemConstant.PDF_PREFIX);
            HtmlToPdfUtil.convert(htmlFile.getPath(), pdfFileTemp.getPath(), PageSizeEnum.A4);

            String htmlFileMd5 = DigestUtils.md5Hex(new FileInputStream(htmlFile));
            String pdfFileMd5 = DigestUtils.md5Hex(new FileInputStream(pdfFileTemp));
            if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {
                fileStoreUtil.ossUpload(pdfDirName, pdfFileTemp, pdfFileMd5, fileStoreUtil.getUploadEnumByPath(pdfDirName).getFssType());
            } else {
                fileStoreUtil.localUpload(pdfDirName, new FileInputStream(pdfFileTemp), pdfFileMd5, LocalCatalogEnum.LOCAL_PDF);
            }

            PdfDto pdfDto = PdfUtil.addPdfPage(pdfFileTemp);
            PrintPathVo printPathVo = new PrintPathVo(classifyEnum, UploadFileEnum.PDF, ossStr, pdfDirName, pdfFileMd5, filePath, htmlFileMd5);
            examDetail.setAttachmentPath(parseAttachmentPath(examDetail.getAttachmentPath(), printPathVo));
            basicAttachment.setPages(pdfDto.getActualPageCount());
            for (int i = 0; i < printCount; i++) {
                pdfList.add(new PdfDto(pdfFileTemp.getPath(), PageSizeEnum.A4, pdfDto.getPageCount(), sequence));
            }
        } 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 (htmlFileTemp != null) {
                FileUtil.deleteFile(htmlFileTemp);
            }
        }
        return basicAttachment;
    }

    /**
     * 保存附件
     *
     * @param examDetail
     * @param pdfList
     * @param printCount
     * @param fileTempList
     */
    @Override
    @Transactional
    public void saveAttachmentSignPdf(PdfSignDto pdfFillDto, ExamDetail examDetail, List<PdfDto> pdfList, Integer printCount, List<File> fileTempList, BasicTemplate basicTemplate) {
        try {
            boolean oss = dictionaryConfig.sysDomain().isOss();
            StringJoiner pdfStringJoiner = new StringJoiner("");
            String ossStr = null;
            if (!oss && Objects.nonNull(dictionaryConfig.fssPrivateDomain()) && !StringUtils.isBlank(dictionaryConfig.fssPrivateDomain().getConfig()) && !dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT)) {
                pdfStringJoiner.add(dictionaryConfig.fssPrivateDomain().getConfig()).add(File.separator);
            }
            pdfStringJoiner = SystemConstant.getDirName(pdfStringJoiner, UploadFileEnum.PDF, true);
            pdfStringJoiner.add(SystemConstant.getNanoId()).add(SystemConstant.PDF_PREFIX);

            File pdfFileTemp = SystemConstant.getFileTempVar(SystemConstant.PDF_PREFIX);
            fileTempList.add(pdfFileTemp);
            pdfFileTemp = createPrintPdfUtil.createSignPdf(pdfFillDto, pdfFileTemp.getPath(), basicTemplate);
            // 校验签到表是否自动分页。2页及以上的pdf，每页后面都需要补一个空白页
            // 补空白页
            if (basicTemplate != null && basicTemplate.getAddBlankPage()) {
                // 补空白页
                PdfUtil.addPdfEmptyPage(pdfFileTemp);
            }

            String pdfDirName = FileUtil.replaceSplit(pdfStringJoiner.toString());
            //pdf生成和上传
            String pdfFileMd5 = DigestUtils.md5Hex(new FileInputStream(pdfFileTemp));
            if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {
                ossStr = oss ? SystemConstant.OSS : SystemConstant.LOCAL;
                fileStoreUtil.ossUpload(pdfDirName, pdfFileTemp, pdfFileMd5, fileStoreUtil.getUploadEnumByPath(pdfDirName).getFssType());
            } else {
                ossStr = SystemConstant.LOCAL;
                fileStoreUtil.localUpload(pdfDirName, new FileInputStream(pdfFileTemp), pdfFileMd5, LocalCatalogEnum.LOCAL_PDF);
            }
            PdfDto pdfDto = PdfUtil.addPdfPage(pdfFileTemp);
            PrintPathVo printPathVo = new PrintPathVo(ClassifyEnum.SIGN, UploadFileEnum.PDF, ossStr, pdfDirName, pdfFileMd5, null, null);
            examDetail.setAttachmentPath(parseAttachmentPath(examDetail.getAttachmentPath(), printPathVo));
            for (int i = 0; i < printCount; i++) {
                pdfList.add(new PdfDto(pdfFileTemp.getPath(), PageSizeEnum.A4, pdfDto.getPageCount(), 2));
            }
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
    }

    @Override
    @Transactional
    public void saveAttachmentSignPdf(PdfSignDto pdfFillDto, ExamDetail examDetail, Integer printCount, BasicTemplate basicTemplate) {
        File pdfFileTemp = null;
        try {
            boolean oss = dictionaryConfig.sysDomain().isOss();
            StringJoiner pdfStringJoiner = new StringJoiner("");
            String ossStr = null;
            if (!oss && Objects.nonNull(dictionaryConfig.fssPrivateDomain()) && !StringUtils.isBlank(dictionaryConfig.fssPrivateDomain().getConfig()) && !dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT)) {
                pdfStringJoiner.add(dictionaryConfig.fssPrivateDomain().getConfig()).add(File.separator);
            }
            pdfStringJoiner = SystemConstant.getDirName(pdfStringJoiner, UploadFileEnum.PDF, true);
            pdfStringJoiner.add(PdfUtil.md5FileName(CreatePdfTypeEnum.SIGN.name() + examDetail.getId())).add(SystemConstant.PDF_PREFIX);

            pdfFileTemp = SystemConstant.getFileTempVar(SystemConstant.PDF_PREFIX);
            pdfFileTemp = createPrintPdfUtil.createSignPdf(pdfFillDto, pdfFileTemp.getPath(), basicTemplate);
            // 校验签到表是否自动分页。2页及以上的pdf，每页后面都需要补一个空白页
            // 补空白页
            if (basicTemplate != null && basicTemplate.getAddBlankPage()) {
                // 补空白页
                PdfUtil.addPdfEmptyPage(pdfFileTemp);
            }

            String pdfDirName = FileUtil.replaceSplit(pdfStringJoiner.toString());
            //pdf生成和上传
            String pdfFileMd5 = DigestUtils.md5Hex(new FileInputStream(pdfFileTemp));
            if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {
                ossStr = oss ? SystemConstant.OSS : SystemConstant.LOCAL;
                fileStoreUtil.ossUpload(pdfDirName, pdfFileTemp, pdfFileMd5, fileStoreUtil.getUploadEnumByPath(pdfDirName).getFssType());
            } else {
                ossStr = SystemConstant.LOCAL;
                fileStoreUtil.localUpload(pdfDirName, new FileInputStream(pdfFileTemp), pdfFileMd5, LocalCatalogEnum.LOCAL_PDF);
            }
            PdfDto pdfDto = PdfUtil.addPdfPage(pdfFileTemp);
            PrintPathVo printPathVo = new PrintPathVo(ClassifyEnum.SIGN, UploadFileEnum.PDF, ossStr, pdfDirName, pdfFileMd5, null, null);
            examDetail.setAttachmentPath(parseAttachmentPath(examDetail.getAttachmentPath(), printPathVo));
//            for (int i = 0; i < printCount; i++) {
//                pdfList.add(new PdfDto(pdfFileTemp.getPath(), PageSizeEnum.A4, pdfDto.getPageCount(), 2));
//            }
        } 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 (pdfFileTemp != null) {
                FileUtil.deleteFile(pdfFileTemp);
            }
        }
    }

    @Override
    public String parseAttachmentPath(String attachmentPath, PrintPathVo printPathVo) {
        List<PrintPathVo> printPathVos = new ArrayList<>();
        JSONObject jsonObject = new JSONObject();
        if (StringUtils.isNotBlank(attachmentPath)) {
            jsonObject = JSONObject.parseObject(attachmentPath);
            String objectString = jsonObject.getString(SystemConstant.PATH);
            if (StringUtils.isNotBlank(objectString)) {
                printPathVos = JSON.parseArray(objectString, PrintPathVo.class);
            }
        }
        List<PrintPathVo> finalList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(printPathVos)) {
            for (PrintPathVo pathVo : printPathVos) {
                if (!pathVo.getPrintType().equals(printPathVo.getPrintType())) {
                    finalList.add(pathVo);
                }
            }
        }
        finalList.add(printPathVo);
        finalList.sort(Comparator.comparing(PrintPathVo::getIndex));

        jsonObject.put(SystemConstant.PATH, finalList);
        return jsonObject.toJSONString();
    }

    /**
     * 成绩管理导入excel校验
     *
     * @param file
     * @param examId
     * @param courseCode
     * @param paperNumber
     * @return
     */
    @Override
    public MarkPaper scoreImportExcelVaild(MultipartFile file, Long examId, String courseCode, String paperNumber) throws IOException {
        String reqFileMd5 = ServletUtil.getRequestMd5();
        String fileMd5 = DigestUtils.md5Hex(file.getBytes());
        if (!Objects.equals(fileMd5, reqFileMd5)) {
            throw ExceptionResultEnum.MD5_EQUALS_FALSE.exception();
        }
        return this.getMarkPaper(examId, courseCode, paperNumber);
    }

    /**
     * 获取阅卷数据
     *
     * @param examId
     * @param paperNumber
     * @return
     */
    @Override
    public MarkPaper getMarkPaper(Long examId, String courseCode, String paperNumber) {
        MarkPaper markPaper = markPaperService.getByExamIdAndPaperNumber(examId, paperNumber);
        if (Objects.isNull(markPaper)) {
            BasicCourse basicCourse = basicCourseService.getByCode(courseCode);
            Objects.requireNonNull(basicCourse, "未找到基础课程信息");
            markPaper = new MarkPaper(examId, courseCode, basicCourse.getName(), paperNumber, 100d, 60d);
        }
        return markPaper;
    }

    /**
     * 成绩管理动态生成excel
     *
     * @param describe
     * @param sheetName
     * @param fileName
     * @param excelFieldList
     * @throws IOException
     */
    @Override
    public void scoreDownLoadExaminationTemplate(String describe, String sheetName, String fileName, List<ExcelField> excelFieldList) throws IOException {
        HttpServletResponse response = ServletUtil.getResponse();
        log.debug("导出Excel开始...");
        XSSFWorkbook wb = new XSSFWorkbook();
        response.setHeader("Content-Disposition", "inline;filename=" + URLEncoder.encode(fileName, SystemConstant.CHARSET_NAME) + ExcelUtil.DEFALUT_EXT);
        response.setContentType(ExcelUtil.DEFALUT_CONTENT_TYPE);
        XSSFSheet sheet = wb.createSheet(sheetName);

        Font headFont = wb.createFont();
        headFont.setFontHeightInPoints((short) 12);
        headFont.setFontName("宋体");
        headFont.setBold(true);

        Font defaultFont = wb.createFont();
        defaultFont.setFontHeightInPoints((short) 12);
        defaultFont.setFontName("宋体");

        Font describeFont = wb.createFont();
        describeFont.setFontHeightInPoints((short) 12);
        describeFont.setFontName("宋体");
        describeFont.setColor(IndexedColors.RED.getIndex());

        int cellCount = excelFieldList.size();
        // 说明
        XSSFCellStyle describeStyle = wb.createCellStyle();
        describeStyle.setAlignment(HorizontalAlignment.LEFT);
        describeStyle.setFont(describeFont);
        describe = describe.trim();
        XSSFRow rowDescribe = sheet.createRow(0);
        rowDescribe.setHeightInPoints(195); //行高设置成195px
        for (int i = 0; i < cellCount; i++) {
            XSSFCell cell = rowDescribe.createCell(i);
            if (i == 0) {
                cell.setCellValue(describe);
                cell.setCellStyle(describeStyle);
            }
        }
        CellRangeAddress region = new CellRangeAddress(0, 0, 0, cellCount - 1);
        sheet.addMergedRegion(region);

        // 表头行
        XSSFCellStyle headerStyle = wb.createCellStyle();
        headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        headerStyle.setAlignment(HorizontalAlignment.CENTER);
        headerStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        headerStyle.setFont(headFont);
        XSSFRow rowHead = sheet.createRow(1);
        for (int i = 0; i < excelFieldList.size(); i++) {
            XSSFCell cell = rowHead.createCell(i);
            cell.setCellValue(excelFieldList.get(i).getName());
            cell.setCellStyle(headerStyle);
            if (excelFieldList.get(i).getComment()) {
                // 前四个参数是坐标点,后四个参数是编辑和显示批注时的大小.
                XSSFDrawing p = sheet.createDrawingPatriarch();
                XSSFComment comment = p.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6));
                // 输入批注信息
                comment.setString(new XSSFRichTextString("必填"));
                cell.setCellComment(comment);
            }
        }

        // 样例行
        XSSFCellStyle exampleStyle = wb.createCellStyle();
        exampleStyle.setAlignment(HorizontalAlignment.LEFT);
        exampleStyle.setFont(defaultFont);
        XSSFRow rowExample = sheet.createRow(2);
        for (int i = 0; i < excelFieldList.size(); i++) {
            XSSFCell cell = rowExample.createCell(i);
            if (excelFieldList.get(i).getCode().startsWith("score")) {
                cell.setCellValue(new Random().nextInt(100) + 1);
            } else if (excelFieldList.get(i).getCode().startsWith("key")) {
                cell.setCellValue(new Random().nextInt(10) + 1);
            } else {
                cell.setCellValue(excelFieldList.get(i).getValue());
            }
            cell.setCellStyle(exampleStyle);
        }

        for (int i = 0; i < cellCount; i++) {
            sheet.autoSizeColumn(i);
            sheet.setColumnWidth(i, sheet.getColumnWidth(i) * 17 / 10);
        }
        ServletOutputStream outputStream = response.getOutputStream();
        wb.write(outputStream);
        outputStream.flush();
        outputStream.close();
        log.debug("导出Excel结束...");
    }

    /**
     * 成绩管理列表
     *
     * @param iPage
     * @param examId
     * @param courseCode
     * @return
     */
    @Override
    public IPage<ScoreResult> scoreList(IPage<Map> iPage, Long examId, String courseCode) {
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(sysUser.getSchoolId(), sysUser.getId(), ServletUtil.getRequest().getServletPath());
        return tcUsualScoreMapper.scoreList(iPage, examId, courseCode, dpr);
    }

    /**
     * 获取成绩管理需要的锁
     *
     * @param examId
     * @param courseCode
     * @param paperNumber
     * @param teachCourseId
     */
    @Override
    public void getLock(Long examId, String courseCode, String paperNumber, Long teachCourseId) {
        tcFinalScoreService.getFinalScoreSyncLock(examId, courseCode, paperNumber, teachCourseId);
        tcFinalScoreService.getFinalScoreImportLock(examId, courseCode, paperNumber, teachCourseId);
        tcPaperStructService.getPaperStructSyncLock(examId, courseCode, paperNumber, teachCourseId);
        tcPaperStructService.getPaperStructImportLock(examId, courseCode, paperNumber, teachCourseId);
    }

    /**
     * 保存html附件
     *
     * @param fileName
     * @param htmlContent
     * @param userId
     * @param localFileList
     * @param fileTempList
     * @return
     * @throws IOException
     */
    @Override
    @Transactional
    public BasicAttachment saveAttachmentHtml(String fileName, String htmlContent, Long userId, List<PdfDto> localFileList, List<File> fileTempList) throws IOException {
        BasicAttachment basicAttachment = null;
        PdfDto pdfDto = null;
        try {
            File htmlFileTemp = SystemConstant.getFileTempVar(SystemConstant.HTML_PREFIX);
            File pdfFileTemp = SystemConstant.getFileTempVar(SystemConstant.PDF_PREFIX);
            fileTempList.add(htmlFileTemp);
            fileTempList.add(pdfFileTemp);

            FileCopyUtils.copy(htmlContent.getBytes(StandardCharsets.UTF_8), htmlFileTemp);
            boolean oss = dictionaryConfig.sysDomain().isOss();
            StringJoiner stringJoiner = new StringJoiner("");
            StringJoiner pdfStringJoiner = 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);
            }
            if (!oss && Objects.nonNull(dictionaryConfig.fssPrivateDomain()) && !StringUtils.isBlank(dictionaryConfig.fssPrivateDomain().getConfig()) && !dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT)) {
                pdfStringJoiner.add(dictionaryConfig.fssPrivateDomain().getConfig()).add(File.separator);
            }
            stringJoiner = SystemConstant.getDirName(stringJoiner, UploadFileEnum.HTML, true);
            stringJoiner.add(SystemConstant.getNanoId()).add(SystemConstant.HTML_PREFIX);

            pdfStringJoiner = SystemConstant.getDirName(pdfStringJoiner, UploadFileEnum.PDF, true);
            pdfStringJoiner.add(SystemConstant.getNanoId()).add(SystemConstant.PDF_PREFIX);

            JSONObject jsonObject = new JSONObject();
            String htmlDirName = FileUtil.replaceSplit(stringJoiner.toString());
            String pdfDirName = FileUtil.replaceSplit(pdfStringJoiner.toString());

            //html生成和上传
            String htmlFileMd5 = DigestUtils.md5Hex(new FileInputStream(htmlFileTemp));
            if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {
                jsonObject.put(SystemConstant.TYPE, oss ? SystemConstant.OSS : SystemConstant.LOCAL);
                fileStoreUtil.ossUpload(htmlDirName, htmlFileTemp, htmlFileMd5, fileStoreUtil.getUploadEnumByPath(htmlDirName).getFssType());
            } else {
                fileStoreUtil.localUpload(htmlDirName, new FileInputStream(htmlFileTemp), htmlFileMd5, LocalCatalogEnum.LOCAL_FILE);
                jsonObject.put(SystemConstant.TYPE, SystemConstant.LOCAL);
            }
            jsonObject.put(SystemConstant.HTML_PATH, htmlDirName);

            HtmlToPdfUtil.convert(htmlFileTemp.getPath(), pdfFileTemp.getPath(), PageSizeEnum.A3);

            //pdf生成和上传
            String pdfFileMd5 = DigestUtils.md5Hex(new FileInputStream(pdfFileTemp));
            if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {
                fileStoreUtil.ossUpload(pdfDirName, pdfFileTemp, pdfFileMd5, fileStoreUtil.getUploadEnumByPath(pdfDirName).getFssType());
            } else {
                fileStoreUtil.localUpload(pdfDirName, new FileInputStream(pdfFileTemp), pdfFileMd5, LocalCatalogEnum.LOCAL_PDF);
            }

            pdfDto = PdfUtil.addPdfPage(pdfFileTemp);
            localFileList.add(new PdfDto(pdfFileTemp.getPath(), PageSizeEnum.A3, pdfDto.getPageCount()));
            jsonObject.put(SystemConstant.PATH, pdfDirName);
            jsonObject.put("htmlMd5", htmlFileMd5);
            jsonObject.put("pdfMd5", pdfFileMd5);

            jsonObject.put(SystemConstant.UPLOAD_TYPE, new UploadFileEnum[]{
                    UploadFileEnum.HTML, UploadFileEnum.PDF
            });
            basicAttachment = new BasicAttachment(jsonObject.toJSONString(), fileName, SystemConstant.HTML_PREFIX, new BigDecimal(htmlContent.getBytes(StandardCharsets.UTF_8).length), htmlFileMd5, userId);
            basicAttachment.setPages(pdfDto.getActualPageCount());
            basicAttachmentService.save(basicAttachment);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            basicAttachmentService.deleteAttachment(basicAttachment);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return basicAttachment;
    }

    /**
     * 保存html附件
     *
     * @param fileName
     * @param htmlContent
     * @param userId
     * @param localFileList
     * @param fileTempList
     * @return
     */
    @Override
    @Transactional
    public BasicAttachment saveAttachmentPdfFromHtml(String fileName, String htmlContent, Long userId, List<PdfDto> localFileList, List<File> fileTempList) {
        BasicAttachment basicAttachment = null;
        File htmlFileTemp = null;
        try {
            htmlFileTemp = SystemConstant.getFileTempVar(SystemConstant.HTML_PREFIX);
            FileCopyUtils.copy(htmlContent.getBytes(StandardCharsets.UTF_8), htmlFileTemp);

            return saveAttachmentPdfFromHtml(fileName, htmlFileTemp, userId, localFileList, fileTempList, PageSizeEnum.A3);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            basicAttachmentService.deleteAttachment(basicAttachment);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        } finally {
            if (htmlFileTemp != null) {
                FileUtil.deleteFile(htmlFileTemp);
            }
        }
        return basicAttachment;
    }

    @Override
    @Transactional
    public BasicAttachment saveAttachmentPdfFromHtml(String fileName, File file, Long userId, List<PdfDto> localFileList, List<File> fileTempList, PageSizeEnum pageSizeEnum) {
        BasicAttachment basicAttachment = null;
        File pdfFileTemp = null;
        try {

            pdfFileTemp = SystemConstant.getFileTempVar(SystemConstant.PDF_PREFIX);
            // html转pdf
            HtmlToPdfUtil.convert(file.getPath(), pdfFileTemp.getPath(), pageSizeEnum);

            //pdf上传
            String pdfDirName = SystemConstant.getNanoId() + SystemConstant.PDF_PREFIX;
            FilePathVo filePathVo = fileUploadService.uploadFile(pdfFileTemp, UploadFileEnum.PDF, pdfDirName);

            PdfDto pdfDto = PdfUtil.addPdfPage(pdfFileTemp);
            if (localFileList != null) {
                localFileList.add(new PdfDto(pdfFileTemp.getPath(), pageSizeEnum, pdfDto.getPageCount()));
            }
            basicAttachment = new BasicAttachment(JSON.toJSONString(filePathVo), fileName, SystemConstant.PDF_PREFIX, new BigDecimal(file.length()), filePathVo.getMd5(), userId);
            basicAttachment.setPages(pdfDto.getActualPageCount());
            basicAttachmentService.save(basicAttachment);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            basicAttachmentService.deleteAttachment(basicAttachment);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        } finally {
            if (file != null) {
                FileUtil.deleteFile(file);
            }
            if (fileTempList != null && pdfFileTemp != null) {
                fileTempList.add(pdfFileTemp);
            }
        }
        return basicAttachment;
    }

    /**
     * 保存html附件和该html转成pdf的附件
     *
     * @param fileName    文件名称
     * @param htmlContent html内容
     * @param userId      创建人
     * @return 两个附件对象
     */
    @Transactional
    @Override
    public BasicAttachment saveAttachmentHtmlAndPdf(String fileName, String htmlContent, Long userId) {
        BasicAttachment basicAttachment = null;
        File htmlFile = null, pdfFile = null;
        try {
            byte[] bytes = htmlContent.getBytes(StandardCharsets.UTF_8);
            int size = bytes.length;
            boolean oss = dictionaryConfig.sysDomain().isOss();
            StringJoiner stringJoiner = new StringJoiner("");
            StringJoiner pdfStringJoiner = 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);
            }
            if (!oss && Objects.nonNull(dictionaryConfig.fssPrivateDomain()) && !StringUtils.isBlank(dictionaryConfig.fssPrivateDomain().getConfig()) && !dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT)) {
                pdfStringJoiner.add(dictionaryConfig.fssPrivateDomain().getConfig()).add(File.separator);
            }
            stringJoiner = SystemConstant.getDirName(stringJoiner, UploadFileEnum.HTML, true);
            stringJoiner.add(SystemConstant.getNanoId()).add(SystemConstant.HTML_PREFIX);

            pdfStringJoiner = SystemConstant.getDirName(pdfStringJoiner, UploadFileEnum.PDF, true);
            pdfStringJoiner.add(SystemConstant.getNanoId()).add(SystemConstant.PDF_PREFIX);

            String htmlDirName = stringJoiner.toString();
            String pdfDirName = pdfStringJoiner.toString();

            JSONObject jsonObject = new JSONObject();
            jsonObject.put(SystemConstant.PATH, htmlDirName);
            jsonObject.put(SystemConstant.PDF_PATH, pdfDirName);

            htmlFile = SystemConstant.getFileTempVar(SystemConstant.HTML_PREFIX);
            pdfFile = SystemConstant.getFileTempVar(SystemConstant.PDF_PREFIX);

            FileCopyUtils.copy(htmlContent.getBytes(StandardCharsets.UTF_8), htmlFile);

            HtmlToPdfUtil.convert(htmlFile.getPath(), pdfFile.getPath(), PageSizeEnum.A4);
            String htmlFileMd5 = DigestUtils.md5Hex(new FileInputStream(htmlFile));
            String pdfFileMd5 = DigestUtils.md5Hex(new FileInputStream(pdfFile));
            jsonObject.put("htmlMd5", htmlFileMd5);
            jsonObject.put("pdfMd5", pdfFileMd5);
            if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {//上传至oss
                jsonObject.put(SystemConstant.TYPE, oss ? SystemConstant.OSS : SystemConstant.LOCAL);
                fileStoreUtil.ossUpload(htmlDirName, htmlContent, fileStoreUtil.getUploadEnumByPath(htmlDirName).getFssType());
//                File pdfFile = asposePdfUtil.documentToPdf(localHtmlFile.getPath(), destUrl, PaperSize.A3);
                fileStoreUtil.ossUpload(pdfDirName, pdfFile, pdfFileMd5, fileStoreUtil.getUploadEnumByPath(pdfDirName).getFssType());
            } else {//上传至服务器
                jsonObject.put(SystemConstant.TYPE, SystemConstant.LOCAL);
                fileStoreUtil.localUpload(htmlDirName, new FileInputStream(htmlFile), htmlFileMd5, LocalCatalogEnum.LOCAL_PDF);
            }
            jsonObject.put(SystemConstant.UPLOAD_TYPE, new UploadFileEnum[]{
                    UploadFileEnum.HTML, UploadFileEnum.PDF
            });
            basicAttachment = new BasicAttachment(jsonObject.toJSONString(), fileName, SystemConstant.HTML_PREFIX, new BigDecimal(size), htmlFileMd5, userId);
            basicAttachmentService.save(basicAttachment);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            basicAttachmentService.deleteAttachment(basicAttachment);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        } finally {
            if (Objects.nonNull(htmlFile)) {
                htmlFile.delete();
            }
            if (Objects.nonNull(pdfFile)) {
                pdfFile.delete();
            }
        }
        return basicAttachment;
    }

    /**
     * 保存附件公用
     *
     * @param file
     * @param md5
     * @param type
     * @param objId
     * @return
     */
    @Override
    public BasicAttachment saveAttachmentCommon(MultipartFile file, String md5, UploadFileEnum type, Long objId) {
        Optional.ofNullable(type).orElseThrow(() -> ExceptionResultEnum.ATTACHMENT_TYPE_EMPTY.exception());

        BasicAttachment basicAttachment = null;
        try {
            SysUser requestUser = (SysUser) ServletUtil.getRequestUser();
            String fileName = FilenameUtils.getBaseName(file.getOriginalFilename());
            String format = "." + FilenameUtils.getExtension(file.getOriginalFilename());

            SysConfig sysConfig = commonCacheService.addSysConfigCache(SystemConstant.ATTACHMENT_TYPE);
            Optional.ofNullable(sysConfig).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("未配置附件类型"));
            List<String> attachmentTypeList = Arrays.asList(sysConfig.getConfigValue().replaceAll("\\[", "").replaceAll("\\]", "").split(","));
            if (Objects.nonNull(format)) {
                long count = attachmentTypeList.stream().filter(s -> format.equalsIgnoreCase(s)).count();
                if (count == 0) {
                    throw ExceptionResultEnum.ERROR.exception("文件格式只能为" + attachmentTypeList.toString());
                }
            }

            SysConfig sysConfigLength = commonCacheService.addSysConfigCache(SystemConstant.ATTACHMENT_LENGTH);
            Optional.ofNullable(sysConfigLength).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("未配置附件名称长度"));
            int attachmentLength = Integer.parseInt(sysConfigLength.getConfigValue());
            if (Objects.nonNull(fileName) && fileName.length() > attachmentLength) {
                throw ExceptionResultEnum.ERROR.exception("文件名长度不能超过" + attachmentLength + "个字符");
            }
            long size = file.getSize();
            BigDecimal b = new BigDecimal(size);
            BigDecimal num = new BigDecimal(1024);
            b = b.divide(num, 2, BigDecimal.ROUND_HALF_UP).divide(num, 2, BigDecimal.ROUND_HALF_UP)
                    .setScale(2, BigDecimal.ROUND_HALF_UP);

            SysConfig sysConfigSize = commonCacheService.addSysConfigCache(SystemConstant.ATTACHMENT_SIZE);
            Optional.ofNullable(sysConfigSize).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("未配置附件大小"));
            double attachmentSize = Double.valueOf(sysConfigSize.getConfigValue());
            if (b.doubleValue() > attachmentSize) {
                throw ExceptionResultEnum.ERROR.exception("文件大小不能超过" + attachmentSize + "MB");
            }
            log.info("fileName:{}", fileName);
            log.info("format:{}", format);
            log.info("size:{}", b);
            log.info("getOriginalFilename:{}", file.getOriginalFilename());
            String fileMd5 = DigestUtils.md5Hex(file.getBytes());
            log.info("fileMd5:{}", fileMd5);
            log.info("md5:{}", md5);
            if (!Objects.equals(fileMd5, md5)) {
                throw ExceptionResultEnum.MD5_EQUALS_FALSE.exception();
            }
            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, type, true);
            stringJoiner.add(SystemConstant.getNanoId()).add(format);

            JSONObject jsonObject = new JSONObject();
            String dirName = FileUtil.replaceSplit(stringJoiner.toString());
            if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {//上传至oss
                fileStoreUtil.ossUpload(dirName, file.getInputStream(), md5, type.getFssType());
                jsonObject.put(SystemConstant.TYPE, oss ? SystemConstant.OSS : SystemConstant.LOCAL);
                jsonObject.put(SystemConstant.PATH, dirName);
            } else {//上传至服务器
                fileStoreUtil.localUpload(dirName, file.getInputStream(), md5, LocalCatalogEnum.LOCAL_FILE);
                jsonObject.put(SystemConstant.TYPE, SystemConstant.LOCAL);
                jsonObject.put(SystemConstant.PATH, dirName);
            }
            jsonObject.put(SystemConstant.UPLOAD_TYPE, type);

            basicAttachment = new BasicAttachment(jsonObject.toJSONString(), fileName, format, b, fileMd5, requestUser.getId(), objId);
            basicAttachmentService.save(basicAttachment);

            // pdf需要读取总页数
            Integer pages = 0;
            if (SystemConstant.PDF_PREFIX.equals(format)) {
                PdfReader pdfReader = new PdfReader(file.getBytes());
                pages = pdfReader.getNumberOfPages();
            }
            basicAttachment.setPages(pages);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            basicAttachmentService.deleteAttachment(basicAttachment);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return basicAttachment;
    }

    /**
     * 保存附件
     *
     * @param file
     * @param md5
     * @param type
     * @return
     */
    @Override
    @Transactional
    public BasicAttachment saveAttachment(MultipartFile file, String md5, UploadFileEnum type) {
        return saveAttachmentCommon(file, md5, type, null);
    }

    /**
     * 科目删除
     *
     * @param id
     * @return
     */
    @Override
    public boolean remove(Long id) {
        BasicCourse basicCourse = basicCourseMapper.selectById(id);
        QueryWrapper<ExamTask> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ExamTask::getSchoolId, basicCourse.getSchoolId()).eq(ExamTask::getCourseCode, basicCourse.getCode());
        int count = examTaskService.count(queryWrapper);
        if (count > 0) {
            throw ExceptionResultEnum.ERROR.exception("课程[" + basicCourse.getName() + "（" + basicCourse.getCode() + "）]绑定命题任务，不能删除");
        }
        return basicCourseService.removeById(id);
    }

    /**
     * 分页查询
     *
     * @param code
     * @param name
     * @param pageNumber
     * @param pageSize
     * @return
     */
    @Override
    public IPage<BasicCourse> list(String code, String name, Integer pageNumber, Integer pageSize) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        code = SystemConstant.translateSpecificSign(code);
        name = SystemConstant.translateSpecificSign(name);
        Page<BasicCourse> page = new Page<>(pageNumber, pageSize);
        IPage<BasicCourse> courseIPage = basicCourseMapper.listPage(page, schoolId, SystemConstant.translateSpecificSign(code), SystemConstant.translateSpecificSign(name));
        return courseIPage;
    }

    /**
     * 科目查询
     *
     * @param param
     * @param printPlanIdList
     * @return
     */
    @Override
    public List<BasicCourse> list(String param, List<Long> printPlanIdList, Long teachingRoomId) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        SysUser requestUser = (SysUser) ServletUtil.getRequestUser();
        SysOrg sysOrg = sysOrgService.getById(requestUser.getOrgId());
        Set<Long> orgIds = teachcloudCommonService.listSubOrgIds(teachingRoomId);
//        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(schoolId, requestUser.getId(), ServletUtil.getRequest().getServletPath());
        /*if (Objects.nonNull(teachingRoomId)) {
            orgIds = new HashSet<>(Arrays.asList(teachingRoomId));
        } else {
            orgIds = teachcloudCommonService.listSubOrgIds(teachingRoomId);
        }*/
        if (CollectionUtils.isEmpty(printPlanIdList)) {
            QueryWrapper<BasicCourse> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(BasicCourse::getSchoolId, schoolId)
                    .eq(BasicCourse::getEnable, true);
            if (sysOrg != null && !OrgTypeEnum.PRINTING_HOUSE.equals(sysOrg.getType())) {
                queryWrapper.lambda().in(BasicCourse::getTeachingRoomId, orgIds);
            }
            if (StringUtils.isNotBlank(param)) {
                queryWrapper.lambda().and(i -> i.like(BasicCourse::getCode, SystemConstant.translateSpecificSign(param))
                        .or().like(BasicCourse::getName, SystemConstant.translateSpecificSign(param)));
            }
            return basicCourseService.list(queryWrapper);
        } else {
            return examDetailCourseService.listCoursesByPrintPlanId(param, printPlanIdList);
        }
    }

    /**
     * 机构禁用
     *
     * @param org
     * @return
     */
    @Override
    public boolean enable(SysOrg org) {
        // 禁用时，校验机构
        if (!org.getEnable()) {
            validateOrg(org.getId());
        }
        UpdateWrapper<SysOrg> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().set(SysOrg::getEnable, org.getEnable()).eq(SysOrg::getId, org.getId());
        return sysOrgService.update(updateWrapper);
    }

    /**
     * 机构删除
     *
     * @param id
     * @return
     */
    @Transactional
    @Override
    public boolean sysOrgRemove(Long id) {
        // 机构校验
        validateOrg(id);
        boolean result = sysOrgService.removeById(id);

        Long schoolId = SystemConstant.convertIdToLong(String.valueOf(ServletUtil.getRequestHeaderSchoolId()));
        commonCacheService.removeOrgCollegeLevelCache(schoolId);
        return result;
    }

    private void validateOrg(Long id) {
        // 机构下是否有用户
        List<SysUser> sysUsers = sysUserService.listByOrgId(id);
        if (!CollectionUtils.isEmpty(sysUsers)) {
            throw ExceptionResultEnum.ERROR.exception("该机构下有用户，不能删除");
        }

        // 机构下是否有子机构
        QueryWrapper<SysOrg> orgQueryWrapper = new QueryWrapper<>();
        orgQueryWrapper.lambda().eq(SysOrg::getParentId, id);
        List<SysOrg> sysOrgs = sysOrgService.list(orgQueryWrapper);
        if (!CollectionUtils.isEmpty(sysOrgs)) {
            throw ExceptionResultEnum.ERROR.exception("该机构下有子机构，不能删除");
        }
    }

    /**
     * 保存任务
     *
     * @param file
     * @param taskTypeEnum
     * @return
     */
    @Override
    @Transactional
    public Map<String, Object> saveTask(MultipartFile file, TaskTypeEnum taskTypeEnum) {
        BasicAttachment basicAttachment = null;
        Map<String, Object> map = null;
        try {
            PrintCommonService printCommonService = SpringContextHolder.getBean(PrintCommonService.class);
            basicAttachment = printCommonService.saveAttachment(file, ServletUtil.getRequestMd5(), UploadFileEnum.FILE);
            if (Objects.isNull(basicAttachment)) {
                throw ExceptionResultEnum.ATTACHMENT_ERROR.exception();
            } else {
                map = new HashMap<>();
                TBTask tbTask = tbTaskService.saveTaskCommon(basicAttachment, taskTypeEnum, map, null);
                tbTaskService.save(tbTask);
            }
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (Objects.nonNull(basicAttachment)) {
                basicAttachmentService.deleteAttachment(basicAttachment);
            }
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return map;
    }

    @Override
    public Map<String, Object> saveTask(MultipartFile file, Long examId, TaskTypeEnum taskTypeEnum) {
        BasicAttachment basicAttachment = null;
        Map<String, Object> map = null;
        try {
            PrintCommonService printCommonService = SpringContextHolder.getBean(PrintCommonService.class);
            BasicExam basicExam = basicExamService.getById(examId);
            if (Objects.isNull(basicExam)) {
                throw ExceptionResultEnum.ERROR.exception("考试不存在");
            }
            Long semesterId = SystemConstant.convertIdToLong(basicExam.getSemesterId());
            basicAttachment = printCommonService.saveAttachment(file, ServletUtil.getRequestMd5(), UploadFileEnum.FILE);
            if (Objects.isNull(basicAttachment)) {
                throw ExceptionResultEnum.ATTACHMENT_ERROR.exception();
            } else {
                map = new HashMap<>();
                TBTask tbTask = tbTaskService.saveTaskCommon(basicAttachment, taskTypeEnum, map, null);
                tbTask.setSemesterId(semesterId);
                tbTask.setExamId(examId);
                tbTaskService.save(tbTask);
            }
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (Objects.nonNull(basicAttachment)) {
                basicAttachmentService.deleteAttachment(basicAttachment);
            }
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return map;
    }

    @Override
    @Transactional
    public Map<String, Object> saveTask(Long printPlanId, MultipartFile file, TaskTypeEnum taskTypeEnum) {
        BasicAttachment basicAttachment = null;
        Map<String, Object> map = null;
        try {
            PrintCommonService printCommonService = SpringContextHolder.getBean(PrintCommonService.class);
            basicAttachment = printCommonService.saveAttachment(file, ServletUtil.getRequestMd5(), UploadFileEnum.FILE);
            if (Objects.isNull(basicAttachment)) {
                throw ExceptionResultEnum.ATTACHMENT_ERROR.exception();
            } else {
                map = new HashMap<>();
                TBTask tbTask = tbTaskService.saveTaskCommon(basicAttachment, taskTypeEnum, map, null);
                tbTask.setPrintPlanId(printPlanId);
                ExamPrintPlan examPrintPlan = examPrintPlanService.getById(printPlanId);
                if (examPrintPlan != null) {
                    BasicExam basicExam = basicExamService.getById(examPrintPlan.getExamId());
                    if (basicExam != null) {
                        tbTask.setSemesterId(Long.valueOf(basicExam.getSemesterId()));
                        tbTask.setExamId(basicExam.getId());
                    }
                }
                tbTaskService.save(tbTask);
            }
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (Objects.nonNull(basicAttachment)) {
                basicAttachmentService.deleteAttachment(basicAttachment);
            }
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return map;
    }

    @Override
    @Transactional
    public Map<String, Object> saveTask(TaskTypeEnum taskTypeEnum) {
        Map<String, Object> map = null;
        try {
            map = new HashMap<>();
            TBTask tbTask = tbTaskService.saveTaskCommon(null, taskTypeEnum, map, null);
            tbTaskService.save(tbTask);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return map;
    }

    @Override
    @Transactional
    public Map<String, Object> saveTask(Long printPlanId, TaskTypeEnum taskTypeEnum) {
        Map<String, Object> map = null;
        try {
            map = new HashMap<>();
            TBTask tbTask = tbTaskService.saveTaskCommon(null, taskTypeEnum, map, null);
            tbTask.setPrintPlanId(printPlanId);
            tbTaskService.save(tbTask);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return map;
    }

    /**
     * 校验课程关联考场是否提交打印
     *
     * @param schoolId
     * @param printPlanId
     * @param examId
     * @param courseCode
     * @param paperNumber
     * @return
     */
    @Override
    public Boolean checkExamDetailStatus(Long schoolId, Long printPlanId, Long examId, String courseCode, String paperNumber) {
        List<ExamDetail> examDetails;
        if (printPlanId != null) {
            examDetails = examDetailService.listByPrintPlanIdAndCourseCodeAndPaperNumber(schoolId, printPlanId, courseCode, paperNumber);
        } else {
            examDetails = examDetailService.listByCourseCodeAndPaperNumber(schoolId, examId, courseCode, paperNumber);
        }
        if (CollectionUtils.isNotEmpty(examDetails)) {
            long count = examDetails.stream().filter(m -> !ExamDetailStatusEnum.NEW.name().equals(m.getStatus().name()) && !ExamDetailStatusEnum.READY.name().equals(m.getStatus().name())).count();
            if (count > 0) {
                throw ExceptionResultEnum.ERROR.exception("部分考场pdf文件开始印刷，不能修改");
            }
        }
        return true;
    }

    /**
     * 生成唯一的试卷编号
     *
     * @param schoolId
     * @return
     */
    @Override
    public String createPaperNumber(Long schoolId, Long examId) {
        String date = DateUtil.today().replace(SystemConstant.HYPHEN, "");
        String counter = redisCounterUtil.getCounter(schoolId, 5, "paperNumber", date);
        String paperNumber = date + counter;
        QueryWrapper<ExamTask> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ExamTask::getSchoolId, schoolId).eq(ExamTask::getExamId, examId).eq(ExamTask::getPaperNumber, paperNumber);
        ExamTask examTask = examTaskService.getOne(queryWrapper);
        if (examTask != null) {
            return createPaperNumber(schoolId, examId);
        } else {
            return paperNumber;
        }
    }

    @Override
    public void checkExamDataAndCreatePdfTask(Long schoolId, Long examId, String courseCode, String paperNumber, SysUser user) {
        // 校验命题任务是否提交
        ExamTask examTask = examTaskService.getByExamIdAndCourseCodeAndPaperNumber(examId, courseCode, paperNumber);
        BasicExam basicExam = basicExamService.getById(examTask.getExamId());
        if (basicExam != null && ExamModelEnum.MODEL3.equals(basicExam.getExamModel())) {
            log.info("考试模式为模式3，不生成pdf");
            return;
        }

        if (examTask != null && !examTask.getEnable()) {
            log.info("命题任务已禁用");
            return;
        }
        ExamTaskDetail examTaskDetail = examTaskDetailService.getByExamTaskId(examTask.getId());
        if (!examTaskDetail.getEnable()) {
            log.info("卷库已禁用");
            return;
        }

        boolean canCreatePdf = true;
        if (examTask.getReview()) {
            TFFlowApprove tfFlowApprove = tfFlowApproveService.findByFlowId(examTask.getFlowId());
            // 1.命题任务已完成
            if (tfFlowApprove == null || tfFlowApprove.getStatus() != FlowStatusEnum.FINISH) {
                canCreatePdf = false;
            }
        }

        if (canCreatePdf) {
            // 2.校验考务数据是否导入
            List<ExamDetail> examDetailList = examDetailService.listByCourseCodeAndPaperNumber(schoolId, examId, courseCode, paperNumber);
            if (CollectionUtils.isNotEmpty(examDetailList)) {
                // 3.检查examDetailId下有无其它课程
                for (ExamDetail examDetail : examDetailList) {
                    List<ExamDetailCourse> examDetailCourses = examDetailCourseService.listByExamDetailIdAndStatus(examDetail.getId());
                    // 4.没有未完成的命题任务
                    if (examDetailCourses.isEmpty()) {
                        // 更新考场状态为初始新建状态
                        examDetailService.updateStatusById(examDetail.getId(), ExamDetailStatusEnum.NEW);

                        // 所有考场都撤回，印刷任务状态改为就绪
                        examPrintPlanService.updateStatusById(examDetail.getPrintPlanId(), PrintPlanStatusEnum.READY);
                        TbTaskDetailResult tbTaskDetailResult = examDetailCourseService.getByExamDetailId(examDetail.getId());
                        tbTaskPdfService.saveTask(tbTaskDetailResult, examDetail.getPrintPlanId(), user, examDetail.getId());
                    }
                }
            } else {
                if (ExamModelEnum.MODEL1.equals(basicExam.getExamModel()) || ExamModelEnum.MODEL4.equals(basicExam.getExamModel())) {
                    // 自动关联考生表中数据，并生成考场信息
                    List<ExamDetail> examDetailList1 = examTaskService.matchBasicExamStudent(basicExam, examTask, examTaskDetail, user);
                    if (CollectionUtils.isNotEmpty(examDetailList1)) {
                        for (ExamDetail examDetail : examDetailList1) {
                            // 更新考场状态为初始新建状态
                            examDetailService.updateStatusById(examDetail.getId(), ExamDetailStatusEnum.NEW);

                            // 所有考场都撤回，印刷任务状态改为就绪
                            examPrintPlanService.updateStatusById(examDetail.getPrintPlanId(), PrintPlanStatusEnum.READY);
                            TbTaskDetailResult tbTaskDetailResult = examDetailCourseService.getByExamDetailId(examDetail.getId());
                            tbTaskPdfService.saveTask(tbTaskDetailResult, examDetail.getPrintPlanId(), user, examDetail.getId());
                        }
                    }
                }
            }
        }
    }

    /**
     * 校验是否可以提交
     *
     * @param schoolId
     * @param courseCode
     * @param paperNumber
     * @param user
     */
    @Override
    public void checkDataMakeup(Long schoolId, ExamDetail examDetail, String courseCode, String paperNumber, SysUser user) {
        // 校验命题任务是否提交
        ExamTask examTask = examTaskService.getByExamIdAndCourseCodeAndPaperNumber(examDetail.getExamId(), courseCode, paperNumber);
        BasicExam basicExam = basicExamService.getById(examTask.getExamId());
        if (basicExam != null && ExamModelEnum.MODEL3.equals(basicExam.getExamModel())) {
            log.info("考试模式为模式3，不生成pdf");
            return;
        }

        if (examTask != null && !examTask.getEnable()) {
            log.info("命题任务已禁用");
            return;
        }
        ExamTaskDetail examTaskDetail = examTaskDetailService.getByExamTaskId(examTask.getId());
        if (!examTaskDetail.getEnable()) {
            log.info("卷库已禁用");
            return;
        }

        boolean canCreatePdf = true;
        if (examTask.getReview()) {
            TFFlowApprove tfFlowApprove = tfFlowApproveService.findByFlowId(examTask.getFlowId());
            // 1.命题任务已完成
            if (tfFlowApprove == null || tfFlowApprove.getStatus() != FlowStatusEnum.FINISH) {
                canCreatePdf = false;
            }
        }

        if (canCreatePdf) {
            //所有考场都撤回，印刷任务状态改为就绪
            examPrintPlanService.updateStatusById(examDetail.getPrintPlanId(), PrintPlanStatusEnum.READY);
            //创建pdf生成任务
            TbTaskDetailResult tbTaskDetailResult = examDetailCourseService.getByExamDetailId(examDetail.getId());
            tbTaskPdfService.saveTask(tbTaskDetailResult, examDetail.getPrintPlanId(), user, examDetail.getId());
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<ExamStudent> createBatchStudentByStudentList(Long examId, ExamTask examTask, String extendFields, List<ExamTaskStudentObjectParam> examTaskStudentObjectParamList, Long examDetailCourseId, SysUser sysUser) {
        AtomicInteger atomicInteger = new AtomicInteger(1);

        List<ExamStudent> examStudentList = new ArrayList<>();
        for (ExamTaskStudentObjectParam student : examTaskStudentObjectParamList) {
            // 禁用考生
            if (!student.isEnable()) {
                continue;
            }
            Long studentId = student.getStudentId();
            BasicExamStudent basicExamStudent = basicExamStudentService.getById(studentId);
            if (basicExamStudent == null) {
                throw ExceptionResultEnum.ERROR.exception("ID[" + studentId + "]的考生不存在");
            }
            ExamStudent examStudent = new ExamStudent();
            examStudent.setSchoolId(sysUser.getSchoolId());
            examStudent.setId(SystemConstant.getDbUuid());
            examStudent.setOrgId(sysUser.getOrgId());
            examStudent.setExamDetailCourseId(examDetailCourseId);
            examStudent.setStudentName(basicExamStudent.getStudentName());
            examStudent.setStudentCode(basicExamStudent.getStudentCode());
            examStudent.setExamId(examId);
            examStudent.setPaperNumber(examTask.getPaperNumber());
            examStudent.setCoursePaperId(String.valueOf(examTask.getId()));
            examStudent.setCollegeName(basicExamStudent.getCollege());
            examStudent.setMajorName(basicExamStudent.getMajor());
            examStudent.setSiteNumber(String.valueOf(atomicInteger.getAndIncrement()));
            examStudent.setTeacherId(basicExamStudent.getTeacherId());
            examStudent.setExtendFields(extendFields);
            examStudent.setCreateId(sysUser.getId());
            // 教学班数据
            examStudent.setTeachClazzId(basicExamStudent.getClazzId());
            BasicTeachClazz basicTeachClazz = basicTeachClazzService.getById(basicExamStudent.getClazzId());
            examStudent.setTeachClazzName(basicTeachClazz != null ? basicTeachClazz.getClazzName() : null);
            examStudentList.add(examStudent);
        }
        return examStudentList;
    }

    /**
     * 保存任务附件(导出)
     *
     * @param fos
     * @param oss
     * @return
     */
    @Override
    public String saveTaskAttachment(ByteArrayOutputStream fos, boolean oss) throws IOException {
        InputStream inputStream = null;
        JSONObject jsonObject = null;
        try {
            inputStream = new ByteArrayInputStream(fos.toByteArray());
            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(SystemConstant.getNanoId()).add(".").add(SystemConstant.XLSX);

            jsonObject = new JSONObject();
            String dirName = FileUtil.replaceSplit(stringJoiner.toString());
            if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {//上传至oss
                fileStoreUtil.ossUpload(dirName, inputStream, DigestUtils.md5Hex(new ByteArrayInputStream(fos.toByteArray())), UploadFileEnum.FILE.getFssType());
                jsonObject.put(SystemConstant.TYPE, oss ? SystemConstant.OSS : SystemConstant.LOCAL);
            } else {
                fileStoreUtil.copyInputStreamToFile(inputStream, new File(stringJoiner.toString()), DigestUtils.md5Hex(new ByteArrayInputStream(fos.toByteArray())), LocalCatalogEnum.LOCAL_FILE);
                jsonObject.put(SystemConstant.TYPE, SystemConstant.LOCAL);
            }
            jsonObject.put(SystemConstant.PATH, dirName);
            jsonObject.put(SystemConstant.UPLOAD_TYPE, UploadFileEnum.FILE);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
        } finally {
            if (Objects.nonNull(inputStream)) {
                inputStream.close();
            }
        }
        return Objects.nonNull(jsonObject) ? jsonObject.toJSONString() : null;
    }

    @Override
    public String createCourseSequence(Long schoolId, String courseCode) {
        boolean lock = redisUtil.lock(SystemConstant.REDIS_LOCK_COURSE_CODE_SEQUENCE_PREFIX + schoolId + "-" + courseCode, SystemConstant.REDIS_LOCK_PAPER_NUMBER_TIME_OUT);
        if (!lock) {
            throw ExceptionResultEnum.ERROR.exception("正在生成课程编号中，请稍候再试！");
        }
        try {
            String sequence = commonCacheService.addExamTaskSequence(schoolId, courseCode);
            if ("0".equals(sequence)) {
                QueryWrapper<ExamTask> queryWrapper = new QueryWrapper<>();
                queryWrapper.lambda().eq(ExamTask::getSchoolId, schoolId).eq(ExamTask::getCourseCode, courseCode);
                List<ExamTask> examTasks = examTaskService.list(queryWrapper);
                if (examTasks != null && examTasks.size() > 0) {
                    String maxSequence = examTasks.stream().max(Comparator.comparing(ExamTask::getSequence)).get().getSequence();
                    if (StringUtils.isNotBlank(maxSequence)) {
                        sequence = maxSequence;
                    }
                }
            }
            return commonCacheService.updateExamTaskSequence(schoolId, courseCode, sequence);
        } finally {
            redisUtil.releaseCourseSequenceLock(SystemConstant.REDIS_LOCK_COURSE_CODE_SEQUENCE_PREFIX + schoolId + "-" + courseCode);
        }
    }

    @Override
    public void updateGradeBatchStatus(Long schoolId, Long examId, String paperNumber, String paperType) {
        QueryWrapper<GradeBatchPaper> gradeBatchPaperQueryWrapper = new QueryWrapper<>();
        gradeBatchPaperQueryWrapper.lambda()
                .eq(GradeBatchPaper::getSchoolId, schoolId)
                .eq(GradeBatchPaper::getExamId, examId)
                .eq(GradeBatchPaper::getPaperNumber, paperNumber)
                .eq(GradeBatchPaper::getPaperType, paperType);
        List<GradeBatchPaper> gradeBatchPaperList = gradeBatchPaperService.list(gradeBatchPaperQueryWrapper);
        if (!gradeBatchPaperList.isEmpty()) {
            for (GradeBatchPaper gradeBatchPaper : gradeBatchPaperList) {
                QueryWrapper<GradeBatchPaper> queryWrapperList = new QueryWrapper<>();
                queryWrapperList.lambda().eq(GradeBatchPaper::getBatchId, gradeBatchPaper.getBatchId()).eq(GradeBatchPaper::getExamId, examId);
                List<GradeBatchPaper> gradeBatchPaperAll = gradeBatchPaperService.list(queryWrapperList);
                if (!gradeBatchPaperAll.isEmpty()) {
                    long count = gradeBatchPaperAll.stream().filter(m -> !GradeAnalyzePaperStatusEnum.READY_TO_CALCULATE.equals(m.getStatus())).count();
                    if (count == 0) {
                        // 更新批次状态
                        UpdateWrapper<GradeBatch> updateWrapper = new UpdateWrapper<>();
                        updateWrapper.lambda().set(GradeBatch::getStatus, GradeAnalyzePaperStatusEnum.READY_TO_CALCULATE).eq(GradeBatch::getId, gradeBatchPaper.getBatchId());
                    }
                }
            }
        }
    }

    /**
     * 生成卷袋贴
     *
     * @param pdfPackageDto
     * @param examDetail
     * @param pdfList
     * @param printCount
     * @param fileTempList
     */
    @Override
    public void saveAttachmentPackagePdf(PdfPackageDto pdfPackageDto, ExamDetail examDetail, List<PdfDto> pdfList, Integer printCount, List<File> fileTempList) {
        try {
            boolean oss = dictionaryConfig.sysDomain().isOss();
            StringJoiner pdfStringJoiner = new StringJoiner("");
            String ossStr = null;
            if (!oss && Objects.nonNull(dictionaryConfig.fssPrivateDomain()) && !StringUtils.isBlank(dictionaryConfig.fssPrivateDomain().getConfig()) && !dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT)) {
                pdfStringJoiner.add(dictionaryConfig.fssPrivateDomain().getConfig()).add(File.separator);
            }
            pdfStringJoiner = SystemConstant.getDirName(pdfStringJoiner, UploadFileEnum.PDF, true);
            pdfStringJoiner.add(SystemConstant.getNanoId()).add(SystemConstant.PDF_PREFIX);

            String pdfDirName = FileUtil.replaceSplit(pdfStringJoiner.toString());
            File pdfFileTemp = SystemConstant.getFileTempVar(SystemConstant.PDF_PREFIX);
            fileTempList.add(pdfFileTemp);
            createPrintPdfUtil.createPackagePdf(pdfPackageDto, pdfFileTemp.getPath());
            //pdf生成和上传
            String pdfFileMd5 = DigestUtils.md5Hex(new FileInputStream(pdfFileTemp));
            if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {
                ossStr = oss ? SystemConstant.OSS : SystemConstant.LOCAL;
                fileStoreUtil.ossUpload(pdfDirName, pdfFileTemp, pdfFileMd5, fileStoreUtil.getUploadEnumByPath(pdfDirName).getFssType());
            } else {
                ossStr = SystemConstant.LOCAL;
                fileStoreUtil.localUpload(pdfDirName, new FileInputStream(pdfFileTemp), pdfFileMd5, LocalCatalogEnum.LOCAL_PDF);
            }

            PdfDto pdfDto = PdfUtil.addPdfPage(pdfFileTemp);
            PrintPathVo printPathVo = new PrintPathVo(ClassifyEnum.PACKAGE, UploadFileEnum.PDF, ossStr, pdfDirName, pdfFileMd5, null, null);
            examDetail.setAttachmentPath(parseAttachmentPath(examDetail.getAttachmentPath(), printPathVo));

            for (int i = 0; i < printCount; i++) {
                pdfList.add(new PdfDto(pdfFileTemp.getPath(), PageSizeEnum.A4, pdfDto.getPageCount(), 2));
            }
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
    }

    @Override
    public void saveAttachmentPackagePdf(PdfPackageDto pdfPackageDto, ExamDetail examDetail, Integer printCount) {
        File pdfFileTemp = null;
        try {
            boolean oss = dictionaryConfig.sysDomain().isOss();
            StringJoiner pdfStringJoiner = new StringJoiner("");
            String ossStr = null;
            if (!oss && Objects.nonNull(dictionaryConfig.fssPrivateDomain()) && !StringUtils.isBlank(dictionaryConfig.fssPrivateDomain().getConfig()) && !dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT)) {
                pdfStringJoiner.add(dictionaryConfig.fssPrivateDomain().getConfig()).add(File.separator);
            }
            pdfStringJoiner = SystemConstant.getDirName(pdfStringJoiner, UploadFileEnum.PDF, true);
            pdfStringJoiner.add(PdfUtil.md5FileName(CreatePdfTypeEnum.PACKAGE.name() + examDetail.getId())).add(SystemConstant.PDF_PREFIX);

            String pdfDirName = FileUtil.replaceSplit(pdfStringJoiner.toString());
            pdfFileTemp = SystemConstant.getFileTempVar(SystemConstant.PDF_PREFIX);
            createPrintPdfUtil.createPackagePdf(pdfPackageDto, pdfFileTemp.getPath());
            //pdf生成和上传
            String pdfFileMd5 = DigestUtils.md5Hex(new FileInputStream(pdfFileTemp));
            if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {
                ossStr = oss ? SystemConstant.OSS : SystemConstant.LOCAL;
                fileStoreUtil.ossUpload(pdfDirName, pdfFileTemp, pdfFileMd5, fileStoreUtil.getUploadEnumByPath(pdfDirName).getFssType());
            } else {
                ossStr = SystemConstant.LOCAL;
                fileStoreUtil.localUpload(pdfDirName, new FileInputStream(pdfFileTemp), pdfFileMd5, LocalCatalogEnum.LOCAL_PDF);
            }

            PdfDto pdfDto = PdfUtil.addPdfPage(pdfFileTemp);
            PrintPathVo printPathVo = new PrintPathVo(ClassifyEnum.PACKAGE, UploadFileEnum.PDF, ossStr, pdfDirName, pdfFileMd5, null, null);
            examDetail.setAttachmentPath(parseAttachmentPath(examDetail.getAttachmentPath(), printPathVo));

//            for (int i = 0; i < printCount; i++) {
//                pdfList.add(new PdfDto(pdfFileTemp.getPath(), PageSizeEnum.A4, pdfDto.getPageCount(), 2));
//            }
        } 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 (pdfFileTemp != null) {
                FileUtil.deleteFile(pdfFileTemp);
            }
        }
    }
}
