package com.yunyan.business.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.parser.PdfTextExtractor;
import com.yunyan.business.constant.BusinessCacheConstants;
import com.yunyan.business.constant.FinalDataStatus;
import com.yunyan.business.constant.TemplateEpType;
import com.yunyan.business.document.templateEpStrategy.AnnotationTplStrategyFactory;
import com.yunyan.business.document.templateEpStrategy.TplStrategy;
import com.yunyan.business.document.utils.FileDataUtil;
import com.yunyan.business.document.y22.*;
import com.yunyan.business.document.y22.pojo.finalExcelY22.*;
import com.yunyan.business.document.y23.budget.ReadBudgetExcelT6Y22Utils;
import com.yunyan.business.document.y23.budget.ReadBudgetFileJsonDataUtils;
import com.yunyan.business.document.y23.budget.UpdateReportBudgetData;
import com.yunyan.business.document.y23.budget.pojo.budgetY23.BudgetDataVo;
import com.yunyan.business.document.y23.budget.pojo.budgetY23.BudgetP3p5SubDeptVo;
import com.yunyan.business.document.y23.budget.pojo.budgetY23.BudgetP3p8DeptVo;
import com.yunyan.business.document.y23.budget.pojo.budgetY23.update.UpdateBudgetP3Vo;
import com.yunyan.business.document.y23.finalData.FinalExcelDataVo23Utils;
import com.yunyan.business.document.y23.finalData.UpdateReportF2023Data;
import com.yunyan.business.domain.CourseCode;
import com.yunyan.business.domain.FinalData;
import com.yunyan.business.domain.ReportExplain;
import com.yunyan.business.domain.ReportFill;
import com.yunyan.business.mapper.FinalDataMapper;
import com.yunyan.business.pojo.admin.dto.*;
import com.yunyan.business.pojo.admin.vo.*;
import com.yunyan.business.service.*;
import com.yunyan.business.utils.CrawlWebDateUtils;
import com.yunyan.common.annotation.DataScope;
import com.yunyan.common.config.YunYanConfig;
import com.yunyan.common.constant.Constants;
import com.yunyan.common.core.domain.AjaxResultVo;
import com.yunyan.common.core.domain.entity.SysDept;
import com.yunyan.common.core.domain.entity.SysUser;
import com.yunyan.common.core.redis.RedisCache;
import com.yunyan.common.exception.ServiceException;
import com.yunyan.common.utils.DateUtils;
import com.yunyan.common.utils.SecurityUtils;
import com.yunyan.common.utils.StringUtils;
import com.yunyan.common.utils.file.FileUploadUtils;
import com.yunyan.common.utils.file.FileUtils;
import com.yunyan.common.utils.file.ZipFileUtils;
import com.yunyan.common.utils.http.HttpUtils;
import com.yunyan.common.utils.spring.SpringUtils;
import com.yunyan.framework.config.ServerConfig;
import com.yunyan.system.service.ISysDeptService;
import com.yunyan.system.service.ISysOperLogService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.CheckReturnValue;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.zip.ZipOutputStream;

/**
 * 报告数据Service业务层处理
 *
 * @author yunyan
 * @date 2023-07-27
 */
@Slf4j
@Service
public class FinalDataServiceImpl extends ServiceImpl<FinalDataMapper, FinalData> implements IFinalDataService
{
    @Autowired
    private FinalDataMapper finalDataMapper;

    @Autowired
    private ServerConfig serverConfig;

    @Autowired
    private ISysDeptService sysDeptService;

    private static final String FILE_DELIMETER = ",";

    @Autowired
    private ICourseCodeService courseCodeService;

    @Autowired
    private IFillDateService fillDateService;

    @Autowired
    private ISyncService syncService;

    @Autowired
    private ITermService termService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ISysOperLogService sysOperLogService;

    @Autowired
    private IReportTermService reportTermService;

    @Autowired
    private IReportDeptService reportDeptService;

    @Autowired
    private IReportFillService reportFillService;

    @Autowired
    private IReportExplainService reportExplainService;


    /**
     * 查询报告数据列表
     *
     * @param dto 报告数据
     * @return 报告数据
     */
    @DataScope(deptAlias = "t", userAlias = "t")
    @Override
    public List<FinalDataListVo> selectFinalDataList(FinalDataListDto dto)
    {
        return finalDataMapper.selectFinalDataList(dto);
    }

    @DataScope(deptAlias = "t", userAlias = "t")
    @Override
    public List<FinalDataExportListVo> selectFinalDataExportList(FinalDataListDto dto) {
        return finalDataMapper.selectFinalDataExportList(dto);
    }

    @DataScope(deptAlias = "t", userAlias = "t")
    @Override
    public List<FinalDataPublicSiteListVo> selectFinalDataPublicSiteList(FinalDataListDto dto)
    {
        return finalDataMapper.selectFinalDataPublicSiteList(dto);
    }

    /**
    * 新增
    * @param
    * @return
    */
    @Override
    public AjaxResultVo add(FinalData dto) {
        FinalData entity = dto;

        this.save(entity);
        return AjaxResultVo.success();
    }

    /**
     * 编辑
     * @param
     * @return
     */
    @Override
    public AjaxResultVo edit(FinalData dto) {

        FinalData entity = this.getById(dto.getId());
        if(null == entity) {
            return AjaxResultVo.error("非法操作");
        }

        entity = new FinalData();
        BeanUtils.copyProperties(dto, entity);

        this.updateById(entity);
        return AjaxResultVo.success();
    }

    /**
     * 详情
     * @param id
     * @return
     */
    @Override
    public AjaxResultVo info(Long id) {
        FinalData entity = this.getById(id);
        if(null == entity) {
            return AjaxResultVo.error("数据查询异常~");
        }

        return AjaxResultVo.success(entity);
    }

    /**
    *
    *申请审核报告数据 目前审核和保存同步都是一起进行
    * @author loovi
    * @date
    */
    @Override
    public AjaxResultVo applyAuditFinalData(Long id){
        // 根据id查找决算数据
        FinalData finalData = finalDataMapper.selectById(id);
        // 如果未查到则抛异常
        if(Objects.isNull(finalData)){
            throw new RuntimeException("审核报告数据不存在");
        }
        // 如果决算数据审核状态不是未审核，不可以申请审核 ,4,5 可以
        if( !finalData.getStatus().equals(FinalDataStatus.FILL_DATA.getCode()) && !finalData.getStatus().equals(FinalDataStatus.FILL_DATA_NO_APPLY.getCode())   ){
            throw new RuntimeException("填报中的状态才可以申请审核");
        }
        // 获取当前用户信息
        SysUser user = SecurityUtils.getLoginUser().getUser();

        // 若决算数据已申请审核，则审核报告数据
        LambdaUpdateWrapper<FinalData> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.set(FinalData::getStatus, FinalDataStatus.APPLY_AUDIT.getCode())
                .set(FinalData::getAuditBy, user.getUserName())
                .set(FinalData::getAuditTime, new Date())
                .eq(FinalData::getId,finalData.getId());

        // 更新决算数据审核状态
        int line = finalDataMapper.update(null, lambdaUpdateWrapper);

        //生成 文档, 保存时, 已调用, 不用重新生成
        //syncService.generateDocument(id);

        return AjaxResultVo.success("已申请审核"+line+"条决算数据",line);
    }

    /**
    *审核决算
    *
    * @author loovi
    * @date
    */
    @Override
    public AjaxResultVo auditFinalData(FinalAuditDto dto){
        Long id = dto.getId() ;
        Integer status = dto.getStatus();
        //驳回原因
        String auditRemark = StringUtils.isNotBlank(dto.getAuditRemark()) ? dto.getAuditRemark() : "";
        //String twoAuditRemark = StringUtils.isNotBlank(dto.getTwoAuditRemark()) ? dto.getTwoAuditRemark() : "";
        // 如果传入的审核状态有误，则抛异常
        if(status < FinalDataStatus.PASS_ONE_AUDIT.getCode()||status > FinalDataStatus.REJECT_TWO_AUDIT.getCode()){
            //throw new RuntimeException("传入审核状态有误，请重新请求");
        }
        // 根据id查找决算数据
        FinalData finalData = finalDataMapper.selectById(id);
        // 如果未查到则抛异常
        if(Objects.isNull(finalData)){
            throw new RuntimeException("审核报告数据不存在");
        }
        // 如果决算数据审核状态为未审核，提示先申请审核
        if( !finalData.getStatus().equals(FinalDataStatus.APPLY_AUDIT.getCode()) && !finalData.getStatus().equals(FinalDataStatus.PASS_ONE_AUDIT.getCode())  ){
            //throw new RuntimeException("当前状态不需要审核");
        }

        String auditRemarkStage = "";
        String twoAuditRemark = dto.getTwoAuditRemark();
        if(FinalDataStatus.REJECT_ONE_AUDIT.getCode().equals(dto.getStatus())) {
            auditRemarkStage = "单位内审驳回";
            auditRemark = StringUtils.isNotBlank(auditRemark) ? auditRemarkStage + ": " + auditRemark : "";
        }
        if(FinalDataStatus.REJECT_TWO_AUDIT.getCode().equals(dto.getStatus()) && StringUtils.isNotBlank(twoAuditRemark)) {
            twoAuditRemark = "财政审核驳回: " + twoAuditRemark;
        }

        // 获取当前用户信息
        SysUser user = SecurityUtils.getLoginUser().getUser();
        // 若决算数据已申请审核，则审核报告数据
        LambdaUpdateWrapper<FinalData> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.set(FinalData::getStatus,status)
                .set(FinalData::getUpdateTime, new Date())
                .eq(FinalData::getId,finalData.getId());
        //审核时给状态, 可能会退回
        if( status.equals(FinalDataStatus.PASS_ONE_AUDIT.getCode()) || status.equals(FinalDataStatus.REJECT_ONE_AUDIT.getCode()) ||
                status.equals(FinalDataStatus.PASS_TWO_AUDIT.getCode()) || status.equals(FinalDataStatus.REJECT_TWO_AUDIT.getCode())
        ) {
            lambdaUpdateWrapper.set(FinalData::getAuditBy, user.getUserName())
                    .set(FinalData::getAuditTime, new Date())
                    .set(FinalData::getAuditRemark, auditRemark);

            if(StringUtils.isNotBlank(twoAuditRemark)) {
                lambdaUpdateWrapper.set(FinalData::getTwoAuditRemark, twoAuditRemark);
            }
        }

        //报告退回
        if( status.equals(FinalDataStatus.FILL_DATA.getCode()) ) {
            lambdaUpdateWrapper.set(FinalData::getAuditRemark, auditRemark);
        }

        // 更新决算数据审核状态
        int line = finalDataMapper.update(null,lambdaUpdateWrapper);
        return AjaxResultVo.success("已审核"+line+"条报告数据",line);
    }

    @Override
    public AjaxResultVo auditBatchFinalData(FinalAuditBatchDto dto) {

        int line = 0;
        for (Long id : dto.getIdList()) {
            Integer status = dto.getStatus();
            //驳回原因
            String auditRemark = StringUtils.isNotBlank(dto.getAuditRemark()) ? dto.getAuditRemark() : "";
            // 如果传入的审核状态有误，则抛异常
            if(status < FinalDataStatus.PASS_ONE_AUDIT.getCode()||status > FinalDataStatus.REJECT_TWO_AUDIT.getCode()){
            }
            // 根据id查找决算数据
            FinalData finalData = finalDataMapper.selectById(id);
            // 如果未查到则抛异常
            if(Objects.isNull(finalData)){
                throw new RuntimeException("审核报告数据不存在");
            }

            String auditRemarkStage = "";
            String twoAuditRemark = dto.getTwoAuditRemark();
            if(FinalDataStatus.REJECT_ONE_AUDIT.getCode().equals(dto.getStatus())) {
                auditRemarkStage = "单位内审驳回";
                auditRemark = StringUtils.isNotBlank(auditRemark) ? auditRemarkStage + ": " + auditRemark : "";
            }
            if(FinalDataStatus.REJECT_TWO_AUDIT.getCode().equals(dto.getStatus()) && StringUtils.isNotBlank(twoAuditRemark)) {
                twoAuditRemark = "财政审核驳回: " + twoAuditRemark;
            }

            // 获取当前用户信息
            SysUser user = SecurityUtils.getLoginUser().getUser();
            // 若决算数据已申请审核，则审核报告数据
            LambdaUpdateWrapper<FinalData> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            lambdaUpdateWrapper.set(FinalData::getStatus,status)
                    .set(FinalData::getUpdateTime, new Date())
                    .eq(FinalData::getId,finalData.getId());
            //审核时给状态, 可能会退回
            if( status.equals(FinalDataStatus.PASS_ONE_AUDIT.getCode()) || status.equals(FinalDataStatus.REJECT_ONE_AUDIT.getCode()) ||
                    status.equals(FinalDataStatus.PASS_TWO_AUDIT.getCode()) || status.equals(FinalDataStatus.REJECT_TWO_AUDIT.getCode())
            ) {
                lambdaUpdateWrapper.set(FinalData::getAuditBy, user.getUserName())
                        .set(FinalData::getAuditTime, new Date())
                        .set(FinalData::getAuditRemark, auditRemark);

                if(StringUtils.isNotBlank(twoAuditRemark)) {
                    lambdaUpdateWrapper.set(FinalData::getTwoAuditRemark, twoAuditRemark);
                }
            }

            //报告退回
            if( status.equals(FinalDataStatus.FILL_DATA.getCode()) ) {
                lambdaUpdateWrapper.set(FinalData::getAuditRemark, auditRemark);
            }

            // 更新决算数据审核状态
            line += finalDataMapper.update(null,lambdaUpdateWrapper);
        }

        return AjaxResultVo.success("已处理" + line + "条报告数据",line);
    }

    /**
    *网站填报
    *
    * @author loovi
    * @date
    */
    @Override
    public AjaxResultVo websiteFill(WebsiteFillDto websiteFillDto){
        // 根据id查找决算数据
        FinalData finalData = finalDataMapper.selectById(websiteFillDto.getId());
        // 如果未查到则抛异常
        if(Objects.isNull(finalData)){
            throw new RuntimeException("审核报告数据不存在");
        }
        // 如果决算数据没有二审核通过则，提示先通过审核
        if(!finalData.getStatus().equals(FinalDataStatus.PASS_TWO_AUDIT.getCode())){
//            throw new RuntimeException("决算数据没有二审核通过，请先审核通过后填报网址");
            log.error("决算数据没有二审核通过，请先审核通过后填报网址");
        }
        // 获取当前用户信息
        SysUser user = SecurityUtils.getLoginUser().getUser();
        // 若通过二审核则进行网站填报
        LambdaUpdateWrapper<FinalData> lambdaUpdateWrapper =new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.set(FinalData::getPublicSite,websiteFillDto.getPublicSite())
                .set(FinalData::getPublicDownloadUrl,websiteFillDto.getPublicDownloadUrl())
                //是否公开, 使用 网站内容中的标题是否包含来判断
                .set(FinalData::getPublicStatus, 0)
                .set(FinalData::getStatus, FinalDataStatus.FILL_WEBSITE.getCode())
                .set(FinalData::getUpdateBy,user.getUserName())
                .set(FinalData::getUpdateTime,new Date())
                .eq(FinalData::getId,websiteFillDto.getId());

        //没有选公开时间时，取当前时间
        if(null == websiteFillDto.getPublicTime()) {
            lambdaUpdateWrapper.set(FinalData::getPublicTime,new Date());
        }

        // 更新决算数据信息
        int line = finalDataMapper.update(null, lambdaUpdateWrapper);

        //调用 网址的内容状态
        syncService.checkWebsiteFillStatue(finalData.getId(), websiteFillDto.getPublicSite());

        return AjaxResultVo.success("已填写"+line+"条决算数据的网站信息",line);
    }
    /**
    * 远程PDF与本地PDF文件比较
    *
    * @author loovi
    * @date
    */
    @Deprecated
    @Override
    public AjaxResultVo PDFComparator(Long id)  {
        FinalData finalData = finalDataMapper.selectById(id);
        if(Objects.isNull(finalData)){
            throw new RuntimeException("决算数据不存在");
        }
        // 获取远程文件url
        String remotePDFUrl = finalData.getPublicSite()+finalData.getPublicDownloadUrl();
        // 本机地址的文件路径
        String localPath = YunYanConfig.getProfile();
        String localFilePath = localPath + StringUtils.substringAfter(finalData.getPdfUrl(), Constants.RESOURCE_PREFIX);

        //比较信息 todo 是否保存 比较信息
        StringBuilder msg = new StringBuilder();

        //文件读取器
        PdfReader remotePdfReader = null;
        PdfReader localPdfReader = null;
        try {
            try {
                // 远程文件URL
                URL remoteFileUrl = new URL(remotePDFUrl);
                // 加载远程PDF文件
                remotePdfReader = new PdfReader(remoteFileUrl);
            } catch (IOException e) {
                msg.append("读取远程的pdf文件异常 ");
                log.error("读取远程的pdf文件异常, [{}], [{}]", e.getMessage(), e);
            }

            try {
                // 加载本地PDF文件
                localPdfReader = new PdfReader(localFilePath);
            } catch (IOException e) {
                msg.append("读取本地的pdf文件异常 ");
                log.error("读取本地的pdf文件异常, [{}], [{}]", e.getMessage(), e);
            }

            // 比较远程和本地文件的页数
            int remotePages = remotePdfReader.getNumberOfPages();
            int localPages = localPdfReader.getNumberOfPages();
            if (remotePages != localPages) {
                msg.append("远程文件和本地文件页数不一致 ");
                log.error("远程文件和本地文件页数不一致");
                //throw new RuntimeException("远程文件和本地文件页数不一致");
            }
            // 比较远程和本地文件每页的内容
            for (int i = 1; i <= remotePages; i++) {

                String remotePageContent = PdfTextExtractor.getTextFromPage(remotePdfReader, i);
                remotePageContent = remotePageContent.replaceAll("\\s+|\\.+", "");

                String localPageContent = PdfTextExtractor.getTextFromPage(localPdfReader, i);
                localPageContent = localPageContent.replaceAll("\\s+|\\.+", "");

                if (!remotePageContent.equals(localPageContent)) {
                    msg.append("第 " + i + " 页内容不一致 ");
                    log.error("第 " + i + " 页内容不一致");
                }
            }
        } catch (IOException e ) {
            msg.append("比较pdf文件异常 ");
            log.error("比较pdf文件异常, [{}], [{}]", e.getMessage(), e);
        } catch (Exception e) {
            msg.append("比较pdf文件异常 ");
            log.error("比较pdf文件异常, [{}], [{}]", e.getMessage(), e);
        } finally {
            // 关闭读取器
            if(null != remotePdfReader) {
                remotePdfReader.close();
            }
            if(null != localPdfReader) {
                localPdfReader.close();
            }
        }

        FinalData updateEntity = new FinalData();
        updateEntity.setId(finalData.getId());
        if(msg.length() == 0) {
            updateEntity.setPublicConsistent(1);
        } else {
            updateEntity.setPublicConsistent(0);
        }
        this.updateById(updateEntity);

        if(msg.length() == 0) {
            return AjaxResultVo.success("远程文件和本地文件内容一致");
        } else {
            return AjaxResultVo.error("远程文件和本地文件内容不一致");
        }
    }
    //    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResultVo finalImportExcel(FinalImportExcelDto dto) {

        if(dto.getDataType().equals(0)) {
            //新数据的处理
            finalImportExcelNewYear(dto);
        } else if(dto.getDataType().equals(1)) {
            //对比上一年数据的处理
            finalImportExcelLastYear(dto);
        }/* else if(dto.getDataType().equals(2)) {
            //对比本年 预算数据的处理
            finalImportExcelBudget(dto);
        }*/

        return null;
    }

    @Override
    public AjaxResultVo<FinalDataGeneratePDFVo> generatePDF(Long id) {
        FinalDataGeneratePDFVo vo = new FinalDataGeneratePDFVo();
        //1.判断条件是否符合生成的情况

        //2.生成 DOC, 转成PDF
        FinalData finalData = this.getById(id);
        if(null == finalData) {
            return AjaxResultVo.error("查询数据异常, 请稍后再试~");
        }

        //获取部门名
        if(StringUtils.isNotBlank(finalData.getExcelDeptName())) {
            vo.setDeptName(finalData.getExcelDeptName());
        }

        if(StringUtils.isNotBlank(finalData.getPdfUrl()) ) {
            vo.setPdfUrl(finalData.getPdfUrl());
            return AjaxResultVo.success(vo);
        }

        if( 1 == finalData.getType()) {
            return generatePDFType1(finalData);
        } else if( 2 == finalData.getType()) {
            return generatePDFType2(finalData);
        } else {
            return AjaxResultVo.error("出现异常， 请稍后再试~");
        }

    }

    /**
     * 生成决算的文档
     * @param finalData
     * @return
     */
    private AjaxResultVo generatePDFType1(FinalData finalData) {
        FinalDataGeneratePDFVo vo = new FinalDataGeneratePDFVo();
        //1.判断条件是否符合生成的情况

        Long id = finalData.getId();
        //FinalExcelDataVo dataVo = JSONUtil.toBean(finalData.getJsonTableContent(), FinalExcelDataVo.class);

        //判断 redis 是否存在 正在生成中
        String generateDocumentKey = BusinessCacheConstants.GENERATE_DOCUMENT_FINAL_FLAG + id;
        if (redisCache.hasKey(generateDocumentKey)) {
            log.error("文档在生成中, 请稍后再试~");
            return AjaxResultVo.error("文档在生成中, 请稍后再试~");
        }

        try {
            TplStrategy tplStrategy = AnnotationTplStrategyFactory.getTemplateStrategy(finalData.getTemplateExportType());
            tplStrategy.exportSave(this, id);
        } catch (Exception e) {
            log.error("生成文档异常");
            return AjaxResultVo.error("预览异常， 请稍后再试, 或者联系管理员~");
        }

        finalData = this.getById(id);
        if(null == finalData) {
            return AjaxResultVo.error("查询数据异常, 请稍后再试~");
        }

        //获取部门名
        if(StringUtils.isNotBlank(finalData.getExcelDeptName())) {
            vo.setDeptName(finalData.getExcelDeptName());
        }

//        if(StringUtils.isNotBlank(finalData.getPdfUrl()) && finalData.getStatus() >= FinalDataStatus.APPLY_AUDIT.getCode() ) {
        if(StringUtils.isNotBlank(finalData.getPdfUrl()) ) {
            vo.setPdfUrl(finalData.getPdfUrl());
            return AjaxResultVo.success(vo);
        }

        return AjaxResultVo.error("出现异常， 请稍后再试~");
    }

    /**
     * 生成预算的文档
     * @param finalData
     * @return
     */
    private AjaxResultVo generatePDFType2(FinalData finalData) {
        FinalDataGeneratePDFVo vo = new FinalDataGeneratePDFVo();
        //1.判断条件是否符合生成的情况

        Long id = finalData.getId();

        //判断 redis 是否存在 正在生成中
        String generateDocumentKey = BusinessCacheConstants.GENERATE_DOCUMENT_FINAL_FLAG + id;
        if (redisCache.hasKey(generateDocumentKey)) {
            log.error("文档在生成中, 请稍后再试~");
            return AjaxResultVo.error("文档在生成中, 请稍后再试~");
        }

        try {
            TplStrategy tplStrategy = AnnotationTplStrategyFactory.getTemplateStrategy(finalData.getTemplateExportType());
            tplStrategy.exportSave(this, id);
        } catch (Exception e) {
            log.error("生成文档异常");
            return AjaxResultVo.error("预览异常， 请稍后再试, 或者联系管理员~");
        }

        finalData = this.getById(id);
        if(null == finalData) {
            return AjaxResultVo.error("查询数据异常, 请稍后再试~");
        }

        //获取部门名
        if(StringUtils.isNotBlank(finalData.getExcelDeptName())) {
            vo.setDeptName(finalData.getExcelDeptName());
        }

//        if(StringUtils.isNotBlank(finalData.getPdfUrl()) && finalData.getStatus() >= FinalDataStatus.APPLY_AUDIT.getCode() ) {
        if(StringUtils.isNotBlank(finalData.getPdfUrl()) ) {
            vo.setPdfUrl(finalData.getPdfUrl());
            return AjaxResultVo.success(vo);
        }

        return AjaxResultVo.error("出现异常， 请稍后再试~");
    }

    /**
     * 新数据的决算(当年数据)
     * @param dto
     */
    private void finalImportExcelNewYear( FinalImportExcelDto dto) {
        //查询编码
        List<CourseCode> codeList = courseCodeService.getCodeListByType(1);

        try
        {
            //日志中 记录 导入的记录
            JSONObject jsonObject = new JSONObject();
            jsonObject.fluentPut("date", DateUtil.formatDateTime(new Date()));
            List<String> noInDeptList = new ArrayList<>();
            List<String> noInBudgetDataList = new ArrayList<>();
            List<String> exceptionList = new ArrayList<>();

            // 本机地址的文件路径
            String localPath = YunYanConfig.getProfile();
            ArrayList< String> fileNamesList = dto.getFileNamesList();
            ArrayList< String> originalFilenamesList = dto.getOriginalFilenamesList();

            //p3p8部分 不用填报的单位
            List<FinalP3T8NoFillDeptVo> p3T8NoFillDeptVoList = ReadFileNoFIllDeptUtils.readData();

            //多线程 处理
            //每个线程至少同步30条记录，计算线程数，不超过10个线程
            //int threadSize = Math.min((int) Math.ceil(fileNames.length / 30D), 10);
            int threadSize = Math.min((int) Math.ceil(fileNamesList.size() / 30D), 10);
//            threadSize = 2;
            //计算平均每个任务数
            //int taskNum = (int) Math.ceil(fileNames.length / (float) threadSize);
            int taskNum = (int) Math.ceil(fileNamesList.size() / (float) threadSize);

            final Integer[] successNum = new Integer[]{0};

            List<Future> taskList = new ArrayList<>();
            ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
            for (int j = 0, size = threadSize - 1; j <= size; j++) {

                List<String> subFileNamesList= fileNamesList.subList(j * taskNum, j < size ? (j + 1) * taskNum : fileNamesList.size());
                List<String> subOriginalFilenamesList= originalFilenamesList.subList(j * taskNum, j < size ? (j + 1) * taskNum : originalFilenamesList.size());
                taskList.add(executor.submit(() -> {
                    //保存 excel的 决算的本年数据
                    saveExcelFinalNewData(subFileNamesList, localPath, subOriginalFilenamesList, codeList, dto, noInDeptList, noInBudgetDataList, exceptionList, successNum, p3T8NoFillDeptVoList);
                }));
            }
            for (Future f : taskList) {
                while (true) {
                    if (f.isDone() && !f.isCancelled()) {
                        //log.debug("导入的文件线程 结束");
                        break;
                    }
                }
            }

            jsonObject.putArray("noInBudgetDataList");
            jsonObject.putArray("noInDeptList");
            jsonObject.putArray("exceptionList");
            jsonObject.getJSONArray("noInBudgetDataList").fluentAddAll(noInBudgetDataList);
            jsonObject.getJSONArray("noInDeptList").fluentAddAll(noInDeptList);
            jsonObject.getJSONArray("exceptionList").fluentAddAll(exceptionList);
            //成功
            jsonObject.fluentPut("successNum", String.format("插入的数量: %s", successNum[0]));

            //记录日志 如果是 没有异常的, 返回 0
            Integer operStatus = noInBudgetDataList.isEmpty() && noInDeptList.isEmpty() && exceptionList.isEmpty() ? 0 : 1;
            sysOperLogService.insertOperlog(sysOperLogService.createSysOperLog("决算采集-本年", 1, "com.yunyan.web.controller.business.FinalDataController.finalImportExcel()",
                    "POST", operStatus, jsonObject.toJSONString()));
        }
        catch (Exception e)
        {
            log.error("决算导入出现异常: [{}] - [{}]", e.getMessage(), e);
        }
    }


    /**
     * 保存 excel的 决算的本年数据
     * @param subFileNamesList 文件名
     * @param localPath 本地位置
     * @param subOriginalFilenamesList 源文件名
     * @param codeList 编码列表
     * @param dto
     * @param noInDeptList 不在部门中的异常
     * @param noInBudgetDataList 没有预算数据的异常
     * @param exceptionList 导入异常的list
     * @param successNum
     * @param p3T8NoFillDeptVoList p3t8部分未填报的部门
     */
    private void saveExcelFinalNewData(List<String> subFileNamesList, String localPath, List<String> subOriginalFilenamesList, List<CourseCode> codeList,
                                       FinalImportExcelDto dto, List<String> noInDeptList, List<String> noInBudgetDataList, List<String> exceptionList, Integer[] successNum, List<FinalP3T8NoFillDeptVo> p3T8NoFillDeptVoList) {
        //读取 本地的本年的 预算
        //List<BudgetP3p5SubDeptVo> p2p5SubDeptVoList = null;
        //上次的区域
        String area = dto.getArea();
        int i = 0;
        //年份
        String year = dto.getYear();
        Integer deptNameBy = dto.getDeptNameBy();

        SysDept sysDeptArea = sysDeptService.getfinalExportTypeByArea(area);
        if(null == sysDeptArea || StringUtils.isBlank(sysDeptArea.getFinalExportType())) {
            exceptionList.add("区域还未设置模板类型~");
            return;
        }

        //预算表8 的 主要用于更新p3p4部分的项
        List<BudgetP3p8DeptVo> p2p8DeptList = null;

        for (String fileName : subFileNamesList) {

            String absolutePathName = localPath + StringUtils.substringAfter(fileName, Constants.RESOURCE_PREFIX);
            String originalFilename = subOriginalFilenamesList.size() - 1 >= i ? subOriginalFilenamesList.get(i++) : "";
            try {
                FinalData finalData = new FinalData();
                //类型
                finalData.setType(1);

                //读取 excel
                FinalExcelDataVo finalExcelDataVo = ReadFinalExcelY22Utils.getSheetInfos(null, absolutePathName);
                //log.debug("原文件名: [{}]- [{}], 读取文件 [{}] 已完成, 新保存的文件名: [{}]", file.getName(), file.getOriginalFilename(), fileName, newFileName);

                //读取 excel中的编制单位名称
                String deptName = finalExcelDataVo.getDeptName();
                if(null != deptNameBy && 2 == deptNameBy) {
                    //田东 部分部门的取 文件名的 编制单位来匹配
                    deptName = originalFilename.substring(0, originalFilename.lastIndexOf(".XLS"));
                }
                //替换 前2个字 为广西的 , 去掉首个
                deptName = UpdateReportFinalData.replaceStartIndexStr(deptName, "广西", "");
                finalExcelDataVo.setDeptName(deptName);

                //设置表6的编码 设置 p3p3部分的款级
                UpdateReportFinalData.updateCourseCode(finalExcelDataVo, codeList);

                //保存的excel数据
                finalData.setExcelTitle(originalFilename);
                finalData.setExcelUrl(fileName);
                finalData.setExcelDeptName(finalExcelDataVo.getDeptName());
                //关联部门id
                SysDept sysDept=  sysDeptService.getDeptByName(finalData.getExcelDeptName(), "");
                FinalP1Vo finalP1Vo = new FinalP1Vo();
                if(null != sysDept) {
                    //判断 是否是需要采集的 平果地区 判断 是否采集, 不依据 二级或者主管单位
                    /*if("平果".equals(sysDept.getArea()) && "0".equals(sysDept.getImportFlag()) ) {
                        exceptionList.add(String.format("[%s] 在[%s] 地区设置不采集", deptName, sysDept.getArea()));
                        continue;
                    }*/

                    finalData.setDeptId(sysDept.getDeptId());
                    finalData.setParentDeptId(sysDept.getParentId());

                    finalExcelDataVo.setDeptCode(sysDept.getDeptCode());
                    //设置编制单位
                    finalData.setExcelDeptName(sysDept.getDeptName());

                    //设置 决算的导出模板
                    //SysDept sysDeptArea = sysDeptService.getfinalExportTypeByAncestors(sysDept.getAncestors(), sysDept.getDeptId());
                    if(null != sysDeptArea && StringUtils.isNotBlank(sysDeptArea.getFinalExportType())) {
                        finalData.setTemplateExportType(sysDeptArea.getFinalExportType());
                    }

                    //区域 来查询  预算数据的文件
                    if(StringUtils.isBlank(area) || !area.equals(sysDept.getArea()) ) {
                        area = sysDept.getArea();
                        //p2p5SubDeptVoList = ReadBudgetExcelT6Y22Utils.readDataP3t5(area);
                        p2p8DeptList = ReadBudgetExcelT6Y22Utils.readDataT8(area, year);
                    }

                    //取文件里的数据 预算
                    BudgetP3p5SubDeptVo p2p5SubDeptVo = ReadBudgetExcelT6Y22Utils.readDataP3t5(sysDept.getDeptCode(), sysDept.getArea(), year);
                    if(null == p2p5SubDeptVo) {
                        log.debug("没有p3t2部分的年初预算");
                        noInBudgetDataList.add(String.format("[%s] 没有第三部分第二小部分的年初预算", deptName));
                    }
                    FinalY22CompareLastUtils.compareDataBudget(finalExcelDataVo, p2p5SubDeptVo, sysDept.getArea(), year);
                    //设置p3p4的项
                    FinalY22CompareLastUtils.compareDataP3T4Budget(finalExcelDataVo, p2p8DeptList, sysDept.getDeptCode());

                    //设置p3p8的自评是否显示
                    /*if(StringUtils.isNumeric(finalExcelDataVo.getDeptCode())) {
                        finalExcelDataVo.getDeptCode();
                        finalExcelDataVo.getP3T8Vo().setNoFillFlag(ReadFileNoFIllDeptUtils.checkP8fillDept(p3T8NoFillDeptVoList, area, Integer.valueOf(finalExcelDataVo.getDeptCode())));
                    }*/

                } else {
                    finalData.setDeptId(0L);
                    finalData.setParentDeptId(0L);
                    finalP1Vo.setDuty("");
                    finalP1Vo.setSettings("");
                    finalP1Vo.setBudgetInfo("");
                    finalExcelDataVo.setDeptCode("");

                    finalExcelDataVo.setP1Vo(finalP1Vo);

                    noInDeptList.add(String.format("[%s] 决算单位没有在单位管理中", deptName));

                }
                finalData.setUserId(0L);

                //部门信息不直接保存 todo
                //finalExcelDataVo.setP1Vo(finalP1Vo);

                //rowNo 排序
                FinalY22Utils.setListRowNo(finalExcelDataVo);

                //状态
                finalData.setStatus(FinalDataStatus.YEAR_DATA.getCode());
                //取传值的年份
                finalData.setYear(year);

                //保存 excel读取数据
                /*String jsonTableContent = JSONUtil.toJsonStr(finalExcelDataVo);
                finalData.setJsonTableContent(jsonTableContent);
                boolean saveRes = this.save(finalData);*/

                //保存 excel读取数据
                String jsonTableContent = JSONUtil.toJsonStr(finalExcelDataVo);
                boolean saveRes = this.saveFinalDataAndReportExplain(finalData, jsonTableContent, null);

                if(saveRes) {
                    successNum[0]++;

                    //保存 报告的 部门概况信息
                    //FinalP1Vo finalP1Vo1 = reportDeptService.saveForUpdateNewDept(finalData.getDeptId(), finalData.getId(), year, finalData.getType());
                }

            } catch (Exception e) {
                log.error("读取 决算以及保存的过程异常: [{}],  [{}]", e.getMessage(), e);

                exceptionList.add(String.format("[%s] 决算单位导入的出现异常：[%s]", originalFilename, e.getMessage()));

                /*String errMsgDept = String.format("\n[%s] [%s]文件中的- [%s] 决算单位导入的出现异常：[%s]", DateUtil.formatDateTime(new Date()), originalFilename, originalFilename, e.getMessage());
                saveExcelImportLog(errMsgDept, "决算数据导入的异常问题");*/
            }

        }
    }

    /**
     * 记录 决算导入的 日志到文件
     * @param errMsgDept
     * @param fileName
     */
    private void saveExcelImportLog(String errMsgDept, String fileName) {
        if(StringUtils.isBlank(errMsgDept)) {
            return;
        }

        String defaultBaseDir = YunYanConfig.getProfile();
        String errMsgFileName = StringUtils.format("{}/{}.{}", DateUtils.datePath(), FilenameUtils.getBaseName(fileName),  "txt");
        String errMsgFilePath = defaultBaseDir + File.separator + ".." + File.separator + "businessLog" + File.separator;
        String errMsgFilePathName = errMsgFilePath + errMsgFileName;
        File errMsgFile = new File(errMsgFilePathName);
        if (!errMsgFile.exists())
        {
            if (!errMsgFile.getParentFile().exists())
            {
                errMsgFile.getParentFile().mkdirs();
            }
            if(!errMsgFile.exists()) {
                try {
                    errMsgFile.createNewFile();
                } catch (IOException e) {
                    log.debug("创建文件失败");
                }
            }
        }

        if( errMsgFile!= null && errMsgFile.isFile() && errMsgFile.exists()) {
            //文件记录
            FileUtil.appendUtf8String(errMsgDept, errMsgFile);
        }
    }

    /**
     * 去年的数据(对比用)
     * 不用进行保存， 进行关联
     * @param
     * @param dto
     */
    private void finalImportExcelLastYear(FinalImportExcelDto dto) {
        try
        {
            JSONObject jsonObject = new JSONObject();
            jsonObject.fluentPut("date", DateUtil.formatDateTime(new Date()));
            List<String> noInYearList = new ArrayList<>();
            List<String> exceptionList = new ArrayList<>();

            // 本机地址的文件路径
            String localPath = YunYanConfig.getProfile();
            ArrayList< String> fileNamesList = dto.getFileNamesList();
            ArrayList< String> originalFilenamesList = dto.getOriginalFilenamesList();

            /*String[] fileNames = dto.getFileNames().split(FILE_DELIMETER);
            String[] newFileNames = dto.getNewFileNames().split(FILE_DELIMETER);
            String[] originalFilenames = dto.getOriginalFilenames().split(FILE_DELIMETER);

            //数组转 list
            ArrayList< String> fileNamesList = new ArrayList<>(fileNames.length);
            Collections.addAll(fileNamesList, fileNames);
            ArrayList< String> originalFilenamesList = new ArrayList<>(originalFilenames.length);
            Collections.addAll(originalFilenamesList, originalFilenames);*/

            //成功的数量
            final Integer[] successNum = new Integer[]{0};

            //多线程 处理
            //每个线程至少同步30条记录，计算线程数，不超过10个线程
            int threadSize = Math.min((int) Math.ceil(fileNamesList.size() / 30D), 10);
//            threadSize = 2;
            //计算平均每个任务数
            int taskNum = (int) Math.ceil(fileNamesList.size() / (float) threadSize);

            List<Future> taskList = new ArrayList<>();
            ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
            for (int j = 0, size = threadSize - 1; j <= size; j++) {

                List<String> subFileNamesList= fileNamesList.subList(j * taskNum, j < size ? (j + 1) * taskNum : fileNamesList.size());
                List<String> subOriginalFilenamesList= originalFilenamesList.subList(j * taskNum, j < size ? (j + 1) * taskNum : originalFilenamesList.size());
                taskList.add(executor.submit(() -> {

                    //保存 excel的 决算的去年数据
                    saveExcelFinalLastData(subFileNamesList, localPath,subOriginalFilenamesList, dto, noInYearList, exceptionList, successNum);
                }));
            }
            for (Future f : taskList) {
                while (true) {
                    if (f.isDone() && !f.isCancelled()) {
                        //log.debug("导入的文件线程 结束");
                        break;
                    }
                }
            }

            jsonObject.putArray("noInYearList");
            jsonObject.putArray("exceptionList");
            jsonObject.getJSONArray("noInYearList").fluentAddAll(noInYearList);
            jsonObject.getJSONArray("exceptionList").fluentAddAll(exceptionList);

            //成功
            jsonObject.fluentPut("successNum", String.format("插入的数量: %s", successNum[0]));

            /*Integer operStatus = 1;
            if(noInYearList.isEmpty() && exceptionList.isEmpty() ) {
                //如果是 没有异常的, 返回 0
                operStatus = 0;
            }*/

            /*SysOperLog operLog = new SysOperLog();
            operLog.setTitle("决算导入-去年数据");
            operLog.setBusinessType(2);
            operLog.setMethod("com.yunyan.web.controller.business.FinalDataController.finalImportExcel()");
            operLog.setRequestMethod("PUST");
            operLog.setOperName("");
            operLog.setStatus(operStatus);
            operLog.setJsonResult(jsonObject.toJSONString());
            sysOperLogService.insertOperlog(operLog);*/
            //记录日志 如果是 没有异常的, 返回 0
            Integer operStatus =  noInYearList.isEmpty() && exceptionList.isEmpty() ? 0 : 1;
            sysOperLogService.insertOperlog(sysOperLogService.createSysOperLog("决算采集-去年", 2, "com.yunyan.web.controller.business.FinalDataController.finalImportExcel()",
                    "PUST", operStatus, jsonObject.toJSONString()));

        }
        catch (Exception e)
        {
            log.debug("导入决算的去年数据异常: [{}] [{}]", e.getMessage(), e);
//            return AjaxResult.error(e.getMessage());
        }
    }

    /**
     * 保存 决算的 excel数据 前一年的
     * @param subFileNamesList
     * @param localPath
     * @param subOriginalFilenamesList
     * @param dto
     * @param noInYearList
     * @param exceptionList
     */
    private void saveExcelFinalLastData(List<String> subFileNamesList, String localPath, List<String> subOriginalFilenamesList,
                                        FinalImportExcelDto dto, List<String> noInYearList, List<String> exceptionList, Integer[] successNum) {

        //年份
        String year = dto.getYear();
        Integer deptNameBy = dto.getDeptNameBy();

        //上次的区域
        String area = dto.getArea();
        SysDept sysDeptArea = sysDeptService.getfinalExportTypeByArea(area);
        if(null == sysDeptArea || StringUtils.isBlank(sysDeptArea.getFinalExportType())) {
            exceptionList.add("区域还未设置模板类型~");
            return;
        }

        int i = 0;
        for (String fileName : subFileNamesList ) {
            String absolutePathName = localPath + StringUtils.substringAfter(fileName, Constants.RESOURCE_PREFIX);
            String originalFilename = subOriginalFilenamesList.size() - 1 >= i ? subOriginalFilenamesList.get(i++) : "";
            try {
                //读取 excel
                FinalExcelDataVo finalExcelLastYearDataVo = ReadFinalExcelY22Utils.getSheetInfos(null, absolutePathName, 1);
                //读取 excel中的编制单位名称
                String deptName = finalExcelLastYearDataVo.getDeptName();
                if(null != deptNameBy && 2 == deptNameBy) {
                    //田东 部分部门的取 文件名的 编制单位来匹配
                    deptName = originalFilename.substring(0, originalFilename.lastIndexOf(".XLS"));
                }

                //替换 前2个字 为广西的 , 去掉首个
                deptName = UpdateReportFinalData.replaceStartIndexStr(deptName, "广西", "");
                finalExcelLastYearDataVo.setDeptName(deptName);

                List<FinalData> finalDataList = this.lambdaQuery().eq(FinalData::getExcelDeptName, deptName).eq(FinalData::getType, 1)
                        .eq(FinalData::getYear, year).eq(FinalData::getStatus, FinalDataStatus.YEAR_DATA.getCode())
                        .select(FinalData::getId, FinalData::getDeptId).orderByDesc(FinalData::getId).list();

                FinalData finalData = null;
                if(!finalDataList.isEmpty()) {
                    finalData = finalDataList.get(0);
                }
                if(null == finalData) {
                    log.error("[{}] 未查到已导入的决算年份的数据~, 请先导入决算年份的数据， 再导入前一年的数据", deptName);

                    noInYearList.add(String.format("[%s] 决算单位没有在已导入的本年数据中", deptName));
                    continue;
                }

                //查询 报告数据json
                ReportExplain reportExplain = reportExplainService.getReportExplainByReportId(finalData.getId());
                String jsonContent = reportExplain.getJsonContent();
                if(null == reportExplain || StringUtils.isBlank(jsonContent)) {
                    log.error("[{}] 未查到已导入的决算年份的报告数据~, 请先导入决算年份的数据， 再导入前一年的数据", deptName);

                    noInYearList.add(String.format("[%s] 决算单位没有在已导入的本年数据中", deptName));
                    continue;
                }

                //json数据
                FinalExcelDataVo dataVo = JSONUtil.toBean(jsonContent, FinalExcelDataVo.class);
                // 对比 本年的数据， 保存
                FinalY22CompareLastUtils.compareData(dataVo, finalExcelLastYearDataVo);

                //json 转对象
                String jsonTableContent = JSONUtil.toJsonStr(dataVo);
                // 去年的 json对象  保存 excel读取数据, 去年
                //String jsonLastYearContent = JSONUtil.toJsonStr(finalExcelLastYearDataVo);

                //更新 保存 去年的 excel数据
                FinalData updateEntity = new FinalData();
                updateEntity.setId(finalData.getId());
                updateEntity.setStatus(FinalDataStatus.LAST_DATA.getCode());
                //保存 去年的 数据的 excel
                updateEntity.setExcelUrlLast(fileName);
                //保存去年的对比数据
                //updateEntity.setJsonTableContent(jsonTableContent);
                //保存去年的 excel数据
                //updateEntity.setJsonLastYearContent(jsonLastYearContent);
                //boolean updateRes = this.updateById(updateEntity);

                //保存 excel读取数据
                boolean updateRes = this.saveFinalDataAndReportExplain(updateEntity, jsonTableContent, reportExplain.getId());


                if(updateRes) {
                    successNum[0]++;
                }
            } catch (Exception e) {
                log.error("读取 预决算以及保存的过程异常: [{}],  [{}]", e.getMessage(), e);
                exceptionList.add(String.format("[%s] 决算单位导入的出现异常：[%s]", originalFilename, e.getMessage()));
            }
        }
    }

    @Override
    public AjaxResultVo getTableInfo(Long id) {
        FinalData finalData = this.getById(id);
        if(null == finalData) {
            return AjaxResultVo.error("查询数据异常, 请稍后再试~");
        }

        //查询 报告的数据
        ReportExplain reportExplain = reportExplainService.getReportExplainByReportId(finalData.getId());
        if(null == reportExplain) {
            return AjaxResultVo.error("数据报告读取失败, 请稍后再试, 或请联系管理员~");
        }

        String jsonContent = reportExplain.getJsonContent();
        if(StringUtils.isBlank(jsonContent)) {
            return AjaxResultVo.error("数据还未读取, 请联系管理员~");
        }

        FinalDataTableVo tableVo = new FinalDataTableVo();
        BeanUtils.copyProperties(finalData, tableVo);

        //部门信息
        String area = "";
        SysDept sysDept = sysDeptService.getById(finalData.getDeptId());
        if(!Objects.isNull(sysDept)) {
            area = sysDept.getArea();
            tableVo.setArea(sysDept.getArea());
        }

        FinalExcelDataVo dataVo = FinalExcelDataVo23Utils.getFinalExcelDataVoByJson(jsonContent, finalData.getYear(), area);
        if(Objects.isNull(dataVo)) {
            return AjaxResultVo.error("报告数据为空, 请稍后再试, 或请联系管理员~");
        }
        tableVo.setDv(dataVo);
        //dataVo = JSONUtil.toBean(jsonContent, FinalExcelDataVo.class);
        if(StringUtils.isBlank(dataVo.getTemplateExportType())) {
            //如还未设置 模板就设置 23年决算
            dataVo.setTemplateExportType(finalData.getTemplateExportType());
        }

        //判断 是否已经超出 单位的填报日期
        int fillDateNum = fillDateService.getFillDateValidNum(1, finalData.getDeptId(), finalData.getYear());
        if(fillDateNum == 0) {
            log.info("不符合填报日期");
        }
        tableVo.setFillDateNum(fillDateNum);

        //查询部门概况信息
        FinalP1Vo finalP1Vo = reportDeptService.getDeptInfo(finalData.getDeptId(),  finalData.getYear(), finalData.getType());
        dataVo.setP1Vo(finalP1Vo);

        //更新 百色市的 其他用车的 数量
        //UpdateReportF2023Data.updateFillData(dataVo);

        return AjaxResultVo.success(tableVo);
    }

    @Override
    public AjaxResultVo getBudgetInfo(Long id) {
        FinalData finalData = this.getById(id);
        if(null == finalData) {
            return AjaxResultVo.error("查询数据异常, 请稍后再试~");
        }

        //查询 报告的数据
        ReportExplain reportExplain = reportExplainService.getReportExplainByReportId(finalData.getId());
        if(null == reportExplain) {
            return AjaxResultVo.error("数据报告读取失败, 请稍后再试, 或请联系管理员~");
        }

        String jsonContent = reportExplain.getJsonContent();
        if(StringUtils.isBlank(jsonContent)) {
            return AjaxResultVo.error("数据还未读取, 请联系管理员~");
        }

        BudgetDataTableVo tableVo = new BudgetDataTableVo();
        BeanUtils.copyProperties(finalData, tableVo);

        BudgetDataVo dataVo = new BudgetDataVo();
        dataVo = JSONUtil.toBean(jsonContent, BudgetDataVo.class);
        tableVo.setDv(dataVo);

        //判断 是否已经超出 单位的填报日期
        /*int fillDateNum = fillDateService.getFillDateValidNum(2, finalData.getDeptId(), finalData.getYear());
        if(fillDateNum == 0) {
            log.info("不符合填报日期");
        }
        tableVo.setFillDateNum(fillDateNum);*/

        //查询部门概况信息
        FinalP1Vo finalP1Vo = reportDeptService.getDeptInfo(finalData.getDeptId(),  finalData.getYear(), finalData.getType());
        dataVo.setP1Vo(finalP1Vo);

        //取消 预算查询时的部门保存
        /*SysDept sysDept = sysDeptService.getById(finalData.getDeptId());
        FinalP1Vo finalP1Vo = new FinalP1Vo();
        if (null != sysDept) {
            //保存 报告的 部门概况信息
            finalP1Vo = reportDeptService.saveForUpdateNewDept(sysDept,  finalData.getYear(), finalData.getType(), true);
        } else {
            finalP1Vo.setDuty("");
            finalP1Vo.setSettings("");
        }
        dataVo.setP1Vo(finalP1Vo);*/

        return AjaxResultVo.success(tableVo);
    }

    @Deprecated
    @Override
    public AjaxResultVo termEdit(TermEditDto dto) {
        FinalData finalData = this.getById(dto.getId());
        if(null == finalData) {
            return AjaxResultVo.error("查询数据异常, 请稍后再试~");
        }

        /*if(StringUtils.isBlank(finalData.getJsonTableContent())) {
            return AjaxResultVo.error("数据还未读取, 请联系管理员~");
        }

        FinalExcelDataVo dataVo = new FinalExcelDataVo();
        dataVo = JSONUtil.toBean(finalData.getJsonTableContent(), FinalExcelDataVo.class);
        //目前直接取全部
        //dataVo.setTermList(dto.getTermList());

        //更新 保存 excel数据
        FinalData updateEntity = new FinalData();
        updateEntity.setId(finalData.getId());
        //保存 excel读取数据, 去年
        String jsonTableContent = JSONUtil.toJsonStr(dataVo);
        updateEntity.setJsonTableContent(jsonTableContent);
        this.updateById(updateEntity);*/

        return AjaxResultVo.success("名词解释保存成功");
    }

    @Override
    public AjaxResultVo changeOverview(FinalDataTableDto dto) {
        FinalData finalData = this.getById(dto.getId());
        if(null == finalData) {
            return AjaxResultVo.error("查询数据异常, 请稍后再试~");
        }

        //查询 报告的数据
        ReportExplain reportExplain = reportExplainService.getReportExplainByReportId(finalData.getId());
        String jsonContent = reportExplain.getJsonContent();
        if(null == reportExplain || StringUtils.isBlank(jsonContent)) {
            return AjaxResultVo.error("数据还未读取, 请联系管理员~");
        }

        if(!Objects.isNull(dto.getDv().getP1Vo())) {
            reportDeptService.changeDeptOverview(dto.getDv().getP1Vo(), finalData.getDeptId(), finalData.getYear(), finalData.getType());
        }

        //部门信息填入
        String area = "";
        SysDept sysDept = sysDeptService.getById(finalData.getDeptId());
        if(null != sysDept) {
            area = sysDept.getArea();
            //设置名词解释
            List<FinalP4T1TermVo> termVoList = reportTermService.saveForNewTerm(sysDept.getArea(), finalData.getYear(), finalData.getType());
        } else {
            return AjaxResultVo.error("单位信息查询异常~");
        }

        //取旧数据 与新修改的数据
        FinalExcelDataVo dataVo = FinalExcelDataVo23Utils.getFinalExcelDataVoByJson(jsonContent, finalData.getYear(), area);
        FinalExcelDataVo updateVo = dto.getDv();

        if(StringUtils.isBlank(dataVo.getTemplateExportType())) {
            //如还未设置 模板就设置 23年决算
            dataVo.setTemplateExportType(finalData.getTemplateExportType());
        }

        //更新 填报的信息
        UpdateReportFinalData.updateFillData(dataVo, updateVo);

        //更新 保存 excel数据 保存在 ReportExplain
        FinalData updateEntity = new FinalData();
        updateEntity.setId(finalData.getId());
        updateEntity.setStatus(FinalDataStatus.FILL_DATA.getCode());

        //保存情况说明
        String jsonTableContent = JSONUtil.toJsonStr(dataVo);
        ReportExplain reportExplainUpdate = new ReportExplain();
        reportExplainUpdate.setId(reportExplain.getId());
        reportExplainUpdate.setJsonContent(jsonTableContent);
        boolean updateRes = this.saveFinalDataAndReportExplain(updateEntity, jsonTableContent, reportExplain.getId());


        //保存 填报的数据
        String jsonFillContent = JSONUtil.toJsonStr(updateVo);
        boolean resFillUpdate = reportFillService.saveOrUpdateFille(finalData.getId(), jsonFillContent);

        //判断是否是有更新，旧文件去掉，并删除
        String localPath = YunYanConfig.getOfficePath();
        FileDataUtil.deleteUrlFile(localPath, finalData.getJsonFileContent(), finalData.getPdfUrl());

        //生成 文档
        syncService.generateDocument(dto.getId());

        return AjaxResultVo.success();
    }

    @Override
    public AjaxResultVo changeOverviewBudget(BudgetDataEditDto dto) {
        Long reportId = dto.getId();
        FinalData finalData = this.getById(dto.getId());
        if(null == finalData) {
            return AjaxResultVo.error("查询数据异常, 请稍后再试~");
        }

        //部门信息填入 另外的接口
        SysDept sysDept = sysDeptService.getById(finalData.getDeptId());
        String area = "";
        if(null != sysDept) {
            area = sysDept.getArea();
            //设置名词解释
            List<FinalP4T1TermVo> termVoList = reportTermService.saveForNewTerm(sysDept.getArea(), finalData.getYear(), finalData.getType());
        } else {
            return AjaxResultVo.error("单位信息查询异常~");
        }

        //查询 报告的数据
        ReportExplain reportExplain = reportExplainService.getReportExplainByReportId(finalData.getId());
        if(null == reportExplain || StringUtils.isBlank(reportExplain.getJsonContent())) {
            return AjaxResultVo.error("数据还未读取, 请联系管理员~");
        }

        if(!Objects.isNull(dto.getDv().getP1Vo())) {
            reportDeptService.changeDeptOverview(dto.getDv().getP1Vo(), finalData.getDeptId(), finalData.getYear(), finalData.getType());
        }

        //取旧数据 与新修改的数据
        BudgetDataVo dataVo = JSONUtil.toBean(reportExplain.getJsonContent(), BudgetDataVo.class);
        UpdateBudgetP3Vo updateVo = dto.getDv();


        //更新 填报的信息
        UpdateReportBudgetData.updateFillData(dataVo.getExplainVo(), updateVo);

        //更新 列表的 情况说明 excel数据
        FinalData updateEntity = new FinalData();
        updateEntity.setId(finalData.getId());
        //未填报过的 未填报状态
        if(finalData.getStatus() < FinalDataStatus.FILL_DATA.getCode() ) {
            updateEntity.setStatus(FinalDataStatus.FILL_DATA.getCode());
        }
        if(null != dto.getStatus() &&  dto.getStatus().equals(FinalDataStatus.FILL_DATA.getCode()) ) {
            updateEntity.setStatus(FinalDataStatus.FILL_DATA.getCode());
        }
        //设置 已填报未申请
        if(null != dto.getStatus() &&  dto.getStatus().equals(FinalDataStatus.FILL_DATA_NO_APPLY.getCode())) {
            updateEntity.setStatus(FinalDataStatus.FILL_DATA_NO_APPLY.getCode());
        }
        //设置敏感词检测更新的状态
        if(!Objects.isNull(dto.getCheckAlertStatus())) {
            updateEntity.setCheckAlertStatus(dto.getCheckAlertStatus());
        }

        //判断 10部分的 是否开展单位的自评
        if(1 != dataVo.getExplainVo().getP3p10Vo().getP4Vo().getNoProjectFlag() ) {
            boolean checkNoInDeptP3p10 = ReadBudgetFileJsonDataUtils.readNoInDeptP3p10BudgetData(finalData.getYear(), area, dataVo.getDeptCode());
            if(checkNoInDeptP3p10) {
                dataVo.getExplainVo().getP3p10Vo().getP4Vo().setNoProjectFlag(1);
            } else {
                dataVo.getExplainVo().getP3p10Vo().getP4Vo().setNoProjectFlag(0);
            }
        }

        //保存情况说明
        String jsonTableContent = JSONUtil.toJsonStr(dataVo);
        ReportExplain reportExplainUpdate = new ReportExplain();
        reportExplainUpdate.setId(reportExplain.getId());
        reportExplainUpdate.setJsonContent(jsonTableContent);
        boolean updateRes = this.saveFinalDataAndReportExplain(updateEntity, jsonTableContent, reportExplain.getId());

        //保存 填报的数据
        String jsonFillContent = JSONUtil.toJsonStr(updateVo);
        boolean resFillUpdate = reportFillService.saveOrUpdateFille(finalData.getId(), jsonFillContent);

        //判断是否是有更新，旧文件去掉，并删除
        String localPath = YunYanConfig.getOfficePath();
        FileDataUtil.deleteUrlFile(localPath, finalData.getJsonFileContent(), finalData.getPdfUrl());

        //生成 文档
        syncService.generateDocument(dto.getId());

        return AjaxResultVo.success();
    }

    @Override
    public AjaxResultVo changeOverviewBudgetAuditText(BudgetDataEditDto dto) {
        Long reportId = dto.getId();
        FinalData finalData = this.getById(dto.getId());
        if(null == finalData) {
            return AjaxResultVo.error("查询数据异常, 请稍后再试~");
        }

        //查询 报告的数据
        ReportExplain reportExplain = reportExplainService.getReportExplainByReportId(finalData.getId());
        if(null == reportExplain || StringUtils.isBlank(reportExplain.getJsonContent())) {
            return AjaxResultVo.error("数据还未读取, 请联系管理员~");
        }

        //取旧数据 与新修改的数据
        BudgetDataVo dataVo = JSONUtil.toBean(reportExplain.getJsonContent(), BudgetDataVo.class);
        UpdateBudgetP3Vo updateVo = dto.getDv();

        //更新 审核内容的信息
        if(StringUtils.isNotBlank(updateVo.getAuditText())) {
            dataVo.setAuditText(updateVo.getAuditText());
        }

        //更新 列表的 情况说明 excel数据
        FinalData updateEntity = new FinalData();
        updateEntity.setId(finalData.getId());

        //这里未设置 审核的状态
        if(null != dto.getStatus()) {
            //updateEntity.setStatus(dto.getStatus());
        }

        //保存情况说明
        String jsonTableContent = JSONUtil.toJsonStr(dataVo);
        ReportExplain reportExplainUpdate = new ReportExplain();
        reportExplainUpdate.setId(reportExplain.getId());
        reportExplainUpdate.setJsonContent(jsonTableContent);
        boolean updateRes = this.saveFinalDataAndReportExplain(updateEntity, jsonTableContent, reportExplain.getId());

        //保存 填报的数据
        String jsonFillContent = JSONUtil.toJsonStr(updateVo);
        boolean resFillUpdate = reportFillService.saveOrUpdateFille(finalData.getId(), jsonFillContent);

        return AjaxResultVo.success();
    }

    @Override
    public AjaxResultVo checkUrl(CheckUrlDto dto) {
        //检测网址的正常性
        Boolean publicUrlFlag =  HttpUtils.checkUrlConnection(dto.getUrl());
        if(publicUrlFlag) {
            return AjaxResultVo.success("网址可访问");
        }

        return AjaxResultVo.error("网址不可访问");
    }

    @Override
    public AjaxResultVo<FinalDataDownloadFileVo> exportReport(Long id) {

        FinalData finalData = this.getById(id);
        if(null == finalData) {
            return AjaxResultVo.error("查询数据异常, 请稍后再试~");
        }

        /*if(finalData.getExcelDeptName().contains("桂平") && (finalData.getStatus() < FinalDataStatus.REJECT_TWO_AUDIT.getCode()) && (finalData.getStatus() != FinalDataStatus.PASS_TWO_AUDIT.getCode()) ) {
            return AjaxResultVo.error("财政确认通过后才能导出");
        }*/

        if(StringUtils.isNotBlank(finalData.getPdfUrl())) {
            FinalDataDownloadFileVo fileVo = JSONUtil.toBean(finalData.getJsonFileContent(), FinalDataDownloadFileVo.class);
            if(null != fileVo) {
                return AjaxResultVo.success(fileVo);
            }
        }

        if(StringUtils.isBlank(finalData.getPdfUrl())) {
            //判断 redis 是否存在 正在生成中
            String generateDocumentKey = BusinessCacheConstants.GENERATE_DOCUMENT_FINAL_FLAG + id;
            if (redisCache.hasKey(generateDocumentKey)) {
                log.error("文档在生成中, 请稍后再试~");
                return AjaxResultVo.error("文档在生成中, 请稍后再试~");
            }

            try {
                TplStrategy tplStrategy = AnnotationTplStrategyFactory.getTemplateStrategy(finalData.getTemplateExportType());
                tplStrategy.exportSave(this, id);
            } catch (Exception e) {
                log.error("生成文档异常");
                return AjaxResultVo.error("预览异常， 请稍后再试, 或者联系管理员~");
            }

            finalData = this.getById(id);
            if(null == finalData) {
                return AjaxResultVo.error("查询数据异常, 请稍后再试~");
            }

            if(StringUtils.isNotBlank(finalData.getPdfUrl())) {
                FinalDataDownloadFileVo fileVo = JSONUtil.toBean(finalData.getJsonFileContent(), FinalDataDownloadFileVo.class);
                if(null != fileVo) {
                    return AjaxResultVo.success(fileVo);
                }
            }
        }

        return AjaxResultVo.error("下载异常, 请稍后再试， 或联系管理员~");
    }

    @Override
    public AjaxResultVo<ExcelDeptInfoVo> finalDataService(Long deptId) {
        FinalData finalData = lambdaQuery().eq(FinalData::getDeptId, deptId).eq(FinalData::getType, 1).select(FinalData::getId).last("and rownum = 1 order by create_time desc").one();
        ExcelDeptInfoVo deptInfoVo = new ExcelDeptInfoVo();
        if( null == finalData ) {
            return AjaxResultVo.error("部门人数还未从决算中导入");
        }

        //查询 报告的数据
        ReportExplain reportExplain = reportExplainService.getReportExplainByReportId(finalData.getId());
        if(null == reportExplain) {
            return AjaxResultVo.error("数据报告读取失败, 请稍后再试, 或请联系管理员~");
        }

        String jsonContent = reportExplain.getJsonContent();
        if(StringUtils.isBlank(jsonContent)) {
            return AjaxResultVo.error("数据还未读取, 请联系管理员~");
        }

        //json数据
        FinalExcelDataVo dataVo = JSONUtil.toBean(jsonContent, FinalExcelDataVo.class);
        if(null == dataVo || null == dataVo.getDeptInfoVo()) {
            return AjaxResultVo.error("决算中的部门人数还未导入");
        }
        deptInfoVo = dataVo.getDeptInfoVo();

        return AjaxResultVo.success(deptInfoVo);
    }

    @Override
    public void selectExportZip(HttpServletResponse response, FinalDataSelectExportDto dto) {

        FinalDataExportDto exportDto = new FinalDataExportDto();
        exportDto.setIdList(dto.getIdList());
        exportDto.setZipName(dto.getZipName());
        exportZip(response, exportDto);

    }

    /**
     * 全部的 zip压缩包
     * @param list
     */
    private void getZipFileNameList(List<FinalDataExportZipListVo> list) {
        for (FinalDataExportZipListVo finalData : list) {
            FinalDataDownloadFileVo fileVo = new FinalDataDownloadFileVo();
            fileVo.setList(new ArrayList<>());
            finalData.setFileVo(fileVo);
            //如果没有文件的话, 跳过
            if(StringUtils.isBlank(finalData.getJsonFileContent())) {
                continue;
            }

            fileVo = JSONUtil.toBean(finalData.getJsonFileContent(), FinalDataDownloadFileVo.class);
            if(null == fileVo) {
                continue;
            }
            List<FinalDataDownloadFileItemVo> fileVoTempList = fileVo.getList().stream().filter(i->!"pdf".equals(i.getFileExtension())).collect(Collectors.toList());
            fileVo.setList(fileVoTempList);
            finalData.setFileVo(fileVo);
        }
    }

    @Override
    public void exportZip(HttpServletResponse response, FinalDataExportDto dto) {
        String zipName = dto.getZipName();
        if(StringUtils.isBlank(zipName)) {
            zipName = "报告文件_" + DateUtils.dateTimeNow() ;
        }

        //1.查询 文件名, 限制区域等
        List<FinalDataExportZipListVo> list = finalDataMapper.selectFinalDataExportZipList(dto);

        if(list.isEmpty()) {
            throw new ServiceException("未有符合导出的数据");
        }

        //2. 压缩文件名
        /*ArrayList<String> fileList = new ArrayList<>();
        getZipFileNameList(list, fileList);*/
        getZipFileNameList(list);

        //文件路径
        ZipOutputStream zipOutputStream = null;

        //设置响应头
        response.reset();
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLUtil.encode(zipName , StandardCharsets.UTF_8) + ".zip");
        response.setContentType("application/zip");
        //设置文件名称
        // response.setHeader("Content-Length", String.valueOf(count)); //传出文件长度，这样前端可以实现下载进度条
        try {
            zipOutputStream = new ZipOutputStream(response.getOutputStream());
        } catch (IOException e) {
            log.debug("zipOutputStream异常: [{}], [{}]", e.getMessage(), e);
            throw new ServiceException("zipOutputStream流异常");
        }

        // 本机地址的文件路径
        String localPath = YunYanConfig.getProfile();

        //记录 压缩文件名
        Map<String, Integer> fineNameMap = new HashMap<>();

        int fileZipNum = 0;
        for(FinalDataExportZipListVo finalData : list ) {
            //如果没有文件的话, 跳过
            if( null == finalData.getFileVo()) {
                continue;
            }
            String innerFileNameBase = String.format("%s_%s", finalData.getDeptCode(), finalData.getDeptName());

            //生成 打包文件
            for(FinalDataDownloadFileItemVo fileItemVo : finalData.getFileVo().getList() ) {
                try {
                    String absolutePathName = localPath + StringUtils.substringAfter(fileItemVo.getUrl(), Constants.RESOURCE_PREFIX);
                    File file = new File(absolutePathName);
                    if(!file.exists()) {
                        log.info("[{}]文件不存在", absolutePathName);
                        // 记录
                        continue;
                    }

                    String innerFileName = innerFileNameBase;

                    //判断 是否是 类型6附件时,
                    if(null != fileItemVo.getType() && 6 == fileItemVo.getType()) {
                        innerFileName += "_" + "三公经费";
                    }

                    innerFileName += "_" + DateUtil.format(finalData.getGenerateTime(), "yyyy-MM-dd");

                    //判断 是否是 类型4附件时,
                    if(null != fileItemVo.getType() && 4 == fileItemVo.getType()) {
                        innerFileName = fileItemVo.getName();
                    }

                    String zipFileName = innerFileName;
                    if(fineNameMap.containsKey(innerFileName)) {
                        zipFileName += ".(" + fineNameMap.get(innerFileName).intValue() + ")";
                    }
                    boolean zipResult = ZipFileUtils.toZip(zipOutputStream, file, zipFileName);
                    if(zipResult) {
                        fileZipNum++;
                        if(fineNameMap.containsKey(innerFileName)) {
                            fineNameMap.put(innerFileName, fineNameMap.get(innerFileName).intValue() + 1);
                        } else {
                            fineNameMap.put(innerFileName, 2);
                        }
                    }
                } catch (Exception e) {
                    // 记录 异常的文件
                    log.error("文件压缩打包异常: [{}], [{}]", e.getMessage(), e);
                }
            }
        }

        if(0 == fileZipNum) {
            throw new ServiceException("无符合的数据");
        }


        //关闭资源
        if (null != zipOutputStream) {
            try {
                zipOutputStream.close();
            } catch (IOException e) {
                log.error("文件IO关闭异常: [{}], [{}]", e.getMessage(), e);
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveFinalDataAndReportExplain(FinalData finalData, String jsonTableContent, Long reportExplainId) {
        boolean saveFinalRes = this.saveOrUpdate(finalData);
        if(!saveFinalRes) {
            return saveFinalRes;
        }

        //保存的 explain
        ReportExplain reportExplain = new ReportExplain();
        if(null != reportExplainId) {
            reportExplain.setId(reportExplainId);
        }
        reportExplain.setReportId(finalData.getId());
        reportExplain.setJsonContent(jsonTableContent);
        boolean saveExplainRes = reportExplainService.saveOrUpdate(reportExplain);

        return saveExplainRes;
    }

    @Override
    public AjaxResultVo infositeFill(InfositeFillDto dto) {
        // 根据id查找决算数据
        FinalData finalData = finalDataMapper.selectById(dto.getId());
        // 如果未查到则抛异常
        if(Objects.isNull(finalData)){
            throw new RuntimeException("审核报告数据不存在");
        }

        // 如果决算数据没有二审核通过则，提示先通过审核
        if(!finalData.getStatus().equals(FinalDataStatus.PASS_TWO_AUDIT.getCode())){
            log.error("决算数据没有二审核通过，请先审核通过后填报");
        }

        // 获取当前用户信息
        SysUser user = SecurityUtils.getLoginUser().getUser();
        // 若通过二审核则进行网站填报
        LambdaUpdateWrapper<FinalData> lambdaUpdateWrapper =new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.set(FinalData::getInfoSite, dto.getInfoSite())
                .eq(FinalData::getId, dto.getId());

        // 更新决算数据信息
        int line = finalDataMapper.update(null, lambdaUpdateWrapper);

        return AjaxResultVo.success();
    }

    @Override
    public AjaxResultVo checkWebsiteFillStatue(FinalDataListDto dto) {

        //检测 redis状态
        String redisKey = BusinessCacheConstants.WEBSITE_FILL_STATUS_CHECK;

        if (redisCache.hasKey(redisKey)) {
            log.error("正在检测公开网址中, 请稍后再试~");
            throw new ServiceException("正在检测公开网址中, 请稍后再试~");
        }

        List<FinalDataListVo> list = finalDataMapper.selectFinalDataList(dto);

        if(!list.isEmpty()) {
            redisCache.setCacheObject(redisKey, 1, 60, TimeUnit.SECONDS);
        } else {
            log.error("没有符合检测条件的公开网址");
            return AjaxResultVo.error("没有符合的条件");
        }

        //多线程 处理
        //每个线程至少同步30条记录，计算线程数，不超过10个线程
        int threadSize = Math.min((int) Math.ceil(list.size() / 30D), 10);
//            threadSize = 2;
        //计算平均每个任务数
        int taskNum = (int) Math.ceil(list.size() / (float) threadSize);

        final Integer[] successNum = new Integer[]{0};

        // 本机地址的文件路径
        String localPath = YunYanConfig.getProfile();

        List<Future> taskList = new ArrayList<>();
        ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
        for (int j = 0, size = threadSize - 1; j <= size; j++) {
            List<FinalDataListVo> dataList = list.subList(j * taskNum, j < size ? (j + 1) * taskNum : list.size());
            taskList.add(executor.submit(() -> {
                //保存 excel的 决算的本年数据
                for (FinalDataListVo finalData : dataList) {
                    try {

                        String publicSite = finalData.getPublicSite();

                        if(StringUtils.isBlank(publicSite)) {
                            continue;
                        }

                        Integer publicSiteAccess = 0;

                        //检测网址的正常性
                        Boolean publicUrlFlag =  HttpUtils.checkUrlConnection(finalData.getPublicSite());
                        if(publicUrlFlag) {
                            publicSiteAccess = 1;
                        }

                        //获取日期
                        String createDateStr = CrawlWebDateUtils.getDate(publicSite);

                        //获取标题 判断= 2024年度部门预算, 预算或者决算
                        Integer publicStatus = 0;
                        if(finalData.getType() == 2 ) {
                            String articleTitleH1 = CrawlWebDateUtils.getArticleTitleH1(publicSite);
                            String articleTitleCompare1 = DateUtil.thisYear() + "年";
                            String articleTitleCompare2 = "部门预算";
                            if(StringUtils.isNotBlank(articleTitleH1) && articleTitleH1.contains(articleTitleCompare1) && articleTitleH1.contains(articleTitleCompare2)) {
                                publicStatus = 1;
                            }
                        }
                        //如果是决算的, 又变了 div class="newsView bgwhite"  div.newsTitle
                        if(finalData.getType() == 1) {
                            publicStatus = 1;

                            //2024年 决算
                            String articleTitleH1 = "";
                            if(!TemplateEpType.Y2023FT2BS.getCode().equals(finalData.getTemplateExportType())) {
                                //不是 百色市时
                                articleTitleH1 = CrawlWebDateUtils.getArticleTitleH1(publicSite);
                            } else {
                                //2023 百色时
                                articleTitleH1 = CrawlWebDateUtils.getArticleTitle2023BaiseFinalNewsTitle(publicSite);
                            }
                            String articleTitleCompare1 = (DateUtil.thisYear() - 1)  + "年";
                            String articleTitleCompare2 = "部门决算";
                            if(StringUtils.isNotBlank(articleTitleH1) && articleTitleH1.contains(articleTitleCompare1) && articleTitleH1.contains(articleTitleCompare2)) {
                                publicStatus = 1;
                            }
                        }


                        FinalData updateEntity = new FinalData();
                        updateEntity.setId(finalData.getId());
                        updateEntity.setPublicSiteAccess(publicSiteAccess);
                        updateEntity.setPublicStatus(publicStatus);
                        if(StringUtils.isNotBlank(createDateStr)) {
                            //"yyyy-MM-dd hh:mm"
                            try {
                                Date publicTime = DateUtil.parse(createDateStr);
                                updateEntity.setPublicTime(publicTime);
                            } catch (Exception e) {
                             log.error("解析日期异常~[{}] - [{}]", e.getMessage(), e);
                            }
                        }

                        this.updateById(updateEntity);
                    } catch (Exception e) {
                        log.debug("异常信息 [{}], [{}]", e.getMessage(), e);
                    }

                }
            }));
        }
        for (Future f : taskList) {
            while (true) {
                if (f.isDone() && !f.isCancelled()) {
                    log.debug("导入的文件线程 结束");
                    break;
                }
            }
        }

        //删除 redis key
        if (redisCache.hasKey(redisKey)) {
            redisCache.deleteObject(redisKey);
        }

        return AjaxResultVo.success();
    }

    @Override
    public Long getLastFillReportId(Long deptId, Integer year) {
        LambdaQueryWrapper<FinalData> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FinalData::getDeptId, deptId);
        queryWrapper.eq(FinalData::getYear, year);
        queryWrapper.orderByDesc(FinalData::getCreateTime);
        List<FinalData> finalDataList = this.list(queryWrapper);
        if(!finalDataList.isEmpty() && finalDataList.size() > 1) {
            return finalDataList.get(1).getId();
        }

        return null;
    }
}
