package com.yeejoin.amos.boot.module.jg.biz.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yeejoin.amos.boot.biz.common.bo.CompanyBo;
import com.yeejoin.amos.boot.biz.common.bo.ReginParams;
import com.yeejoin.amos.boot.biz.common.utils.RedisKey;
import com.yeejoin.amos.boot.biz.common.utils.RedisUtils;
import com.yeejoin.amos.boot.biz.common.utils.SnowflakeIdUtil;
import com.yeejoin.amos.boot.module.common.api.dao.ESEquipmentCategory;
import com.yeejoin.amos.boot.module.common.api.dto.ESEquipmentCategoryDto;
import com.yeejoin.amos.boot.module.jg.api.converter.DictParamsConverter;
import com.yeejoin.amos.boot.module.jg.api.converter.EquCategoryConverter;
import com.yeejoin.amos.boot.module.jg.api.converter.EquDefineConverter;
import com.yeejoin.amos.boot.module.jg.api.dto.*;
import com.yeejoin.amos.boot.module.jg.api.entity.*;
import com.yeejoin.amos.boot.module.jg.api.enums.BusinessTypeEnum;
import com.yeejoin.amos.boot.module.jg.api.mapper.JgUseRegistrationMapper;
import com.yeejoin.amos.boot.module.jg.biz.feign.TzsServiceFeignClient;
import com.yeejoin.amos.boot.module.jg.biz.service.*;
import com.yeejoin.amos.boot.module.ymt.api.entity.*;
import com.yeejoin.amos.boot.module.ymt.api.enums.ApplicationFormTypeEnum;
import com.yeejoin.amos.boot.module.ymt.api.enums.EquimentEnum;
import com.yeejoin.amos.boot.module.ymt.api.enums.EquipmentClassifityEnum;
import com.yeejoin.amos.boot.module.ymt.api.enums.FlowStatusEnum;
import com.yeejoin.amos.boot.module.ymt.api.mapper.CategoryOtherInfoMapper;
import com.yeejoin.amos.boot.module.ymt.api.mapper.TzBaseEnterpriseInfoMapper;
import com.yeejoin.amos.feign.privilege.Privilege;
import com.yeejoin.amos.feign.privilege.model.AgencyUserModel;
import com.yeejoin.amos.feign.privilege.model.CompanyModel;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;
import org.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;
import org.typroject.tyboot.core.restful.exception.instance.BadRequest;
import org.typroject.tyboot.core.restful.utils.ResponseModel;
import java.io.InputStream;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static com.alibaba.fastjson.JSON.toJSONString;

@Slf4j
@Service
@RequiredArgsConstructor
public class DataDockServiceImpl {
    private final SnowflakeIdUtil sequence;
    private final ESEquipmentCategory esEquipmentCategory;
    private final CategoryOtherInfoMapper categoryOtherInfoMapper;
    private final IIdxBizJgUseInfoService idxBizJgUseInfoService;
    private final IIdxBizJgProjectContraptionService idxBizJgProjectContraptionService;
    private final IdxBizJgDesignInfoServiceImpl idxBizJgDesignInfoService;
    private final IdxBizJgFactoryInfoServiceImpl idxBizJgFactoryInfoService;
    private final IdxBizJgRegisterInfoServiceImpl idxBizJgRegisterInfoServiceImpl;
    private final IdxBizJgSupervisionInfoServiceImpl idxBizJgSupervisionInfoService;
    private final IdxBizJgOtherInfoServiceImpl idxBizJgOtherInfoService;
    private final IIdxBizJgTechParamsVehicleService iIdxBizJgTechParamsVehicleService;
    private final IIdxBizJgTechParamsLiftingService iIdxBizJgTechParamsLiftingService;
    private final IIdxBizJgTechParamsBoilerService iIdxBizJgTechParamsBoilerService;
    private final IIdxBizJgTechParamsVesselService iIdxBizJgTechParamsVesselService;
    private final IIdxBizJgTechParamsPipelineService iIdxBizJgTechParamsPipelineService;
    private final IdxBizJgInspectionDetectionInfoServiceImpl idxBizJgInspectionDetectionInfoService;
    private final IIdxBizJgTechParamsRidesService iIdxBizJgTechParamsRidesService;
    private final IIdxBizJgTechParamsRopewayService iIdxBizJgTechParamsRopewayService;
    private final IIdxBizJgTechParamsElevatorService iIdxBizJgTechParamsElevatorService;
    private final IdxBizJgProjectContraptionServiceImpl idxBizJgProjectContraptionServiceImpl;
    private final IdxBizJgConstructionInfoServiceImpl idxBizJgConstructionInfoService;
    private final JgInstallationNoticeServiceImpl installationNoticeService;
    private final TzBaseEnterpriseInfoMapper tzBaseEnterpriseInfoMapper;
    private final JgUseRegistrationManageServiceImpl jgUseRegistrationManageService;
    private final RedisUtils redisUtils;
    private final JgUseRegistrationServiceImpl jgUseRegistrationServiceImpl;
    private final JgUseRegistrationEqServiceImpl jgUseRegistrationEqServiceImpl;
    private final TzsServiceFeignClient tzsServiceFeignClient;
    private final CommonServiceImpl commonService;
    private final JgRegistrationHistoryServiceImpl jgRegistrationHistoryService;
    private final JgCertificateChangeRecordServiceImpl certificateChangeRecordService;
    private final JgCertificateChangeRecordEqServiceImpl certificateChangeRecordEqService;

    private final Map<String, Object> resultError = new HashMap<>();
    private final JgUseRegistrationMapper jgUseRegistrationMapper;
    List<String> useInnerCodeList = new ArrayList<>();// 单位内部编号集合
    List<String> equCodeList = new ArrayList<>();// 设备代码集合
    List<String> factoryNumList = new ArrayList<>();// 出厂编码集合
    List<String> useOrgCodeList = new ArrayList<>();// 使用登记证集合
    Map<String, List<String>> projectContraptionMap = new HashMap<>();// 工程装置名称集合

    /**
     * 西安数据对接-保存设备信息
     *
     * @param equLists 数据集
     * @return 保存结果
     */
    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    public boolean xiAnSaveEquipmentData(List<Map<String, Object>> equLists) {
        CompletableFuture.allOf(equLists.stream().map(equ -> CompletableFuture.runAsync(() -> saveEquipmentDataInTransaction(equ, "jg_his_xa", null))).toArray(CompletableFuture[]::new)).join();
        return Boolean.TRUE;
    }

    public void saveEquipmentDataInTransaction(Map<String, Object> equ, String dataSource, String remark) {
        try {
            // transactionTemplate.execute(status -> {
            String record = UUID.randomUUID().toString();
            String equList = String.valueOf(equ.get("equList"));
            // 压力管道保存 工程装置表信息  必须在saveUseInfo之前进行，需要提前生成工程装置id
            saveProjectContraption(equ, equList);
            // 保存到设备表
            saveUseInfo(equ, record, dataSource, remark);
            saveDesignInfo(equ, record);
            saveFactoryInfo(equ, record);
            saveRegisterInfo(equ, record, equList);
            saveSupervisionInfo(equ, record);
            saveOtherInfo(equ, record, equList);
            // 保存技术参数
            saveTechParams(equ, record, equList);
            // 保存到ES
            saveEquInfoToEs(record);
            // return null;
            // });
        } catch (Exception e) {
            e.printStackTrace();
            log.error("{}数据：保存时出现异常，对应数据：{}", dataSource, JSONObject.toJSONString(equ));
            log.error("异常信息：{}", e.getMessage());
            throw new RuntimeException(e);
        }
    }

    public Integer writeOrgBranchCode2YanChang(String remark) {
        List<String> records = idxBizJgUseInfoService.lambdaQuery().select(IdxBizJgUseInfo::getRecord).eq(IdxBizJgUseInfo::getRemark, remark).list().stream().map(IdxBizJgUseInfo::getRecord).collect(Collectors.toList());

        idxBizJgSupervisionInfoService.lambdaUpdate().set(IdxBizJgSupervisionInfo::getOrgBranchCode, "50*74*160*12478").set(IdxBizJgSupervisionInfo::getOrgBranchName, "交口河镇市场监管所").in(IdxBizJgSupervisionInfo::getRecord, records).update();
        records.forEach(record -> {
            esEquipmentCategory.deleteById(record);
            this.saveEquInfoToEs(record);
        });
        return records.size();
    }

    /**
     * 根据name获取市区县Code
     *
     * @param name
     * @return code
     */
    private String getRegionCode(String name, String key) {
        return Optional.ofNullable((List<LinkedHashMap>) redisUtils.get(key))
                .flatMap(list -> list.stream()
                        .filter(item -> String.valueOf(item.get("regionName"))
                                .equals(name))
                        .map(item -> String.valueOf(item.get("regionCode")))
                        .findFirst())
                .orElse("");
    }

    /**
     * 保存工程装置表信息
     */
    private void saveProjectContraption(Map<String, Object> equ, String equList) {
        if (EquipmentClassifityEnum.YLGD.getCode().equals(equList)) {
            IdxBizJgProjectContraption projectContraption = JSON.parseObject(JSON.toJSONString(equ), IdxBizJgProjectContraption.class);
            if (!ValidationUtil.isEmpty(projectContraption)) {
                String useUnitCode = String.valueOf(equ.get("useUnitCode")).trim();// 使用单位Code
                String useUnit = String.valueOf(equ.get("useUnit")).trim();// 使用单位名称
                String proConName = String.valueOf(equ.get("projectContraption")).trim();// 工程装置名称

                // 查询该企业下是否已经有该工程装置名称 有-》追加 update   无-》新增 save
                IdxBizJgProjectContraption oldContraption = idxBizJgProjectContraptionService.lambdaQuery()
                        .eq(IdxBizJgProjectContraption::getUseUnitCreditCode, useUnitCode)
                        .eq(IdxBizJgProjectContraption::getUseUnitName, useUnit)
                        .eq(IdxBizJgProjectContraption::getProjectContraption, proConName)
                        .list().stream().findFirst().orElse(null);

                projectContraption.setRecDate(new Date());

                if (ObjectUtils.isEmpty(oldContraption)) { // save
                    Long sequenceNbr = sequence.nextId();
                    projectContraption.setSequenceNbr(sequenceNbr);
                    projectContraption.setUseUnitCreditCode(useUnitCode);
                    projectContraption.setUseUnitName(useUnit);
                    projectContraption.setEquList(equList);
                    projectContraption.setEquListName(EquipmentClassifityEnum.getNameByCode(equList));
                    projectContraption.setEquCategory((String) equ.get("equCategory"));
                    projectContraption.setEquCategoryName(EquCategoryConverter.getKeyByValue((String) equ.get("equCategory")));
                    projectContraption.setEquDefine((String) equ.get("equDefine"));
                    projectContraption.setEquDefineName(EquDefineConverter.getKeyByValue((String) equ.get("equDefine")));
                    projectContraption.setPipelineLength(Double.parseDouble((String) equ.get("pipeLength")));
                    projectContraption.setUseRegistrationCode((String) equ.get("useOrgCode"));
                    projectContraption.setIsIntoManagement(Boolean.FALSE);
                    idxBizJgProjectContraptionService.save(projectContraption);
                    equ.put("projectContraptionId", sequenceNbr);
                } else { // update
                    equ.put("projectContraptionId", oldContraption.getSequenceNbr());
                    projectContraption.setSequenceNbr(oldContraption.getSequenceNbr());

                    Double oldPipelineLength = oldContraption.getPipelineLength();
                    projectContraption.setPipelineLength(Double.sum(oldPipelineLength, Double.parseDouble((String) equ.get("pipeLength"))));
                    idxBizJgProjectContraptionService.updateById(projectContraption);
                }
            }
        }
    }

    /**
     * 保存使用信息表
     *
     * @param equ
     * @param record
     */
    private void saveUseInfo(Map<String, Object> equ, String record, String dataSource, String remark) {
        log.error("数据===>{}", JSONObject.toJSONString(equ));
        IdxBizJgUseInfo useInfo = JSON.parseObject(JSON.toJSONString(equ), IdxBizJgUseInfo.class);
        if (!ValidationUtil.isEmpty(useInfo)) {
            TzBaseEnterpriseInfo enterpriseInfo = tzBaseEnterpriseInfoMapper.selectOne(new LambdaQueryWrapper<TzBaseEnterpriseInfo>()
                    .eq(TzBaseEnterpriseInfo::getUseUnitCode, String.valueOf(equ.get("useUnitCode")).trim()));
            if (!ValidationUtil.isEmpty(enterpriseInfo)) {
                String provinceName = enterpriseInfo.getProvince();
                String provinceCode = "610000";
                String cityName = enterpriseInfo.getCity();
                String cityCode = "";
                if (!ValidationUtil.isEmpty(cityName)) {
                    cityCode = getRegionCode(cityName, "CITY");
                }
                String districtName = enterpriseInfo.getDistrict();
                String districtCode = "";
                if (!ValidationUtil.isEmpty(districtName)) {
                    districtCode = getRegionCode(districtName, "COUNTY");
                }
                useInfo.setProvince(provinceCode);
                useInfo.setProvinceName(provinceName);
                useInfo.setCity(cityCode);
                useInfo.setCityName(cityName);
                useInfo.setCounty(districtCode);
                useInfo.setCountyName(districtName);
                useInfo.setStreetName(enterpriseInfo.getStreet());
                if (ValidationUtil.isEmpty(enterpriseInfo.getLatitude()) && !ValidationUtil.isEmpty(enterpriseInfo.getLongitude())) {
                    useInfo.setLongitudeLatitude(String.format("{\"latitude\":\"%s\",\"longitude\":\"%s\"}", enterpriseInfo.getLatitude(), enterpriseInfo.getLongitude()));
                }
            }
            useInfo.setRecDate(new Date());
            useInfo.setRecord(record);
            useInfo.setDataSource(dataSource);
            useInfo.setIsNotEs("1");
            useInfo.setIsIntoManagement(Boolean.FALSE);
            useInfo.setUseUnitCreditCode(String.valueOf(equ.get("useUnitCode")).trim());
            useInfo.setUseUnitName(String.valueOf(equ.get("useUnit")).trim());
            useInfo.setRemark(remark);
            useInfo.setProjectContraptionId(String.valueOf(equ.get("projectContraptionId")));
            idxBizJgUseInfoService.save(useInfo);
        }
    }

    /**
     * 保存设计信息表
     *
     * @param equ
     * @param record
     */
    private void saveDesignInfo(Map<String, Object> equ, String record) {
        log.error("数据===>{}", JSONObject.toJSONString(equ));
        IdxBizJgDesignInfo designInfo = JSON.parseObject(JSON.toJSONString(equ), IdxBizJgDesignInfo.class);
        if (!ValidationUtil.isEmpty(designInfo)) {
            designInfo.setRecord(record);
            designInfo.setRecDate(new Date());
            idxBizJgDesignInfoService.save(designInfo);
        }
    }

    /**
     * 保存制造信息
     *
     * @param equ
     * @param record
     */
    private void saveFactoryInfo(Map<String, Object> equ, String record) {
        log.error("数据===>{}", JSONObject.toJSONString(equ));
        IdxBizJgFactoryInfo factoryInfo = JSON.parseObject(JSON.toJSONString(equ), IdxBizJgFactoryInfo.class);
        if (!ValidationUtil.isEmpty(factoryInfo)) {
            factoryInfo.setRecord(record);
            factoryInfo.setRecDate(new Date());
            idxBizJgFactoryInfoService.save(factoryInfo);
        }
    }

    /**
     * 保存注册登记信息表
     *
     * @param equ
     * @param record
     */
    private void saveRegisterInfo(Map<String, Object> equ, String record, String equList) {
        log.error("数据===>{}", JSONObject.toJSONString(equ));
        IdxBizJgRegisterInfo registerInfo = JSON.parseObject(JSON.toJSONString(equ), IdxBizJgRegisterInfo.class);
        if (!ValidationUtil.isEmpty(registerInfo)) {
            registerInfo.setRecord(record);
            registerInfo.setRecDate(new Date());
            registerInfo.setRegisterState("6045");
            if (EquipmentClassifityEnum.YLGD.getCode().equals(equList)) {
                registerInfo.setEquCodeType("2");
                registerInfo.setProductName((String) equ.get("pipeName"));
            }
            idxBizJgRegisterInfoServiceImpl.save(registerInfo);
        }
    }

    /**
     * 保存监督管理信息表
     *
     * @param equ
     * @param record
     */
    private void saveSupervisionInfo(Map<String, Object> equ, String record) {
        log.error("数据===>{}", JSONObject.toJSONString(equ));
        IdxBizJgSupervisionInfo supervisionInfo = JSON.parseObject(JSON.toJSONString(equ), IdxBizJgSupervisionInfo.class);
        log.error("数据===hou>{}", JSONObject.toJSONString(supervisionInfo));
        if (ObjectUtils.isEmpty(supervisionInfo)) return;
        supervisionInfo.setRecord(record);
        supervisionInfo.setRecDate(new Date());

        // 获取符合条件的公司 Map
        Map<String, String> countyMap;
        try {
            countyMap = Optional.ofNullable(Privilege.companyClient.queryAgencyList("county").getResult())
                    .orElse(Collections.emptyList())
                    .stream()
                    .filter(v -> "1442687786065854466".equals(String.valueOf(v.getParentId())))
                    .collect(Collectors.toMap(CompanyModel::getCompanyCode, CompanyModel::getCompanyName, (a, b) -> a));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        // 提取 companyCode
        String companyCode = Optional.ofNullable(equ.get("equCodeType"))
                .filter(type -> Objects.equals(type, 1)).flatMap(type -> Optional.ofNullable(equ.get("equCode"))
                        .map(String::valueOf).map(String::trim)
                        .filter(code -> code.length() >= 9)
                        .map(code -> code.substring(3, 9)))
                .orElse("");

        // 直接获取公司名称
        String companyName = countyMap.get(companyCode);
        if (companyName != null) {
            supervisionInfo.setOrgBranchCode(companyCode);
            supervisionInfo.setOrgBranchName(companyName);
        } else {
            // 通过 useUnitCode 查询属地监管部门
            String useUnitCode = String.valueOf(equ.get("useUnitCode")).trim();
            CompanyModel companyModel = Privilege.companyClient.queryByCompanyCode(useUnitCode).getResult();

            if (companyModel != null) {
                String orgCode = companyModel.getOrgCode();
                if (orgCode != null && orgCode.contains("*")) {
                    String superOrgCode = orgCode.substring(0, orgCode.lastIndexOf("*"));
                    supervisionInfo.setOrgBranchCode(superOrgCode);
                    Optional.ofNullable(Privilege.companyClient.queryByOrgcode(superOrgCode).getResult())
                            .map(result -> JSON.parseObject(JSON.toJSONString(result)).getString("compnay"))
                            .map(json -> JSON.parseObject(json, CompanyModel.class))
                            .map(CompanyModel::getCompanyName)
                            .ifPresent(supervisionInfo::setOrgBranchName);
                }
            } else {
                supervisionInfo.setOrgBranchCode("610100");
                supervisionInfo.setOrgBranchName("西安市市场监督管理局");
            }
        }
        idxBizJgSupervisionInfoService.save(supervisionInfo);
    }

    /**
     * 保存其他信息表
     *
     * @param equ
     * @param record
     */
    private void saveOtherInfo(Map<String, Object> equ, String record, String equList) {
        log.error("数据===>{}", JSONObject.toJSONString(equ));
        IdxBizJgOtherInfo otherInfo = JSON.parseObject(JSON.toJSONString(equ), IdxBizJgOtherInfo.class);
        if (!ValidationUtil.isEmpty(otherInfo)) {
            otherInfo.setRecord(record);
            otherInfo.setClaimStatus("已认领");
            otherInfo.setRecDate(new Date());
            if (EquipmentClassifityEnum.DT.getCode().equals(equList)) {
                otherInfo.setCode96333Type("2");
            }
            idxBizJgOtherInfoService.save(otherInfo);
        }
    }

    /**
     * 保存技术参数
     *
     * @param equ
     * @param record
     * @param equList
     */
    private void saveTechParams(Map<String, Object> equ, String record, String equList) {
        if (EquipmentClassifityEnum.QZJX.getCode().equals(equList)) {
            saveLiftingParams(equ, record);
        } else if (EquipmentClassifityEnum.CC.getCode().equals(equList)) {
            saveVehicleParams(equ, record);
        } else if (EquipmentClassifityEnum.GL.getCode().equals(equList)) {
            saveBoilerParams(equ, record);
        } else if (EquipmentClassifityEnum.YLRQ.getCode().equals(equList)) {
            saveVesselParams(equ, record);
        } else if (EquipmentClassifityEnum.YLGD.getCode().equals(equList)) {
            savePipelineParams(equ, record);
        } else if (EquipmentClassifityEnum.YLSS.getCode().equals(equList)) {
            saveRidesParams(equ, record);
        } else if (EquipmentClassifityEnum.KYSD.getCode().equals(equList)) {
            saveRopewayParams(equ, record);
        } else if (EquipmentClassifityEnum.DT.getCode().equals(equList)) {
            saveElevatorParams(equ, record);
        }
    }

    /**
     * 保存起重机械技术参数
     *
     * @param equ
     * @param record
     */
    private void saveLiftingParams(Map<String, Object> equ, String record) {
        log.error("数据===>{}", JSONObject.toJSONString(equ));
        IdxBizJgTechParamsLifting equipTechParamLifting = JSON.parseObject(JSON.toJSONString(equ), IdxBizJgTechParamsLifting.class);
        if (!ValidationUtil.isEmpty(equipTechParamLifting)) {
            equipTechParamLifting.setRecord(record);
            equipTechParamLifting.setRecDate(new Date());
            iIdxBizJgTechParamsLiftingService.saveOrUpdateData(equipTechParamLifting);
        }
    }

    /**
     * 保存场内机动车辆技术参数
     *
     * @param equ
     * @param record
     */
    private void saveVehicleParams(Map<String, Object> equ, String record) {
        log.error("数据===>{}", JSONObject.toJSONString(equ));
        IdxBizJgTechParamsVehicle equipTechParamVehicle = JSON.parseObject(JSON.toJSONString(equ), IdxBizJgTechParamsVehicle.class);
        if (!ValidationUtil.isEmpty(equipTechParamVehicle)) {
            equipTechParamVehicle.setRecord(record);
            equipTechParamVehicle.setRecDate(new Date());
            iIdxBizJgTechParamsVehicleService.saveOrUpdateData(equipTechParamVehicle);
        }
    }

    /**
     * 保存锅炉技术参数
     *
     * @param equ
     * @param record
     */
    private void saveBoilerParams(Map<String, Object> equ, String record) {
        log.error("数据===>{}", JSONObject.toJSONString(equ));
        IdxBizJgTechParamsBoiler equipTechParamBoiler = JSON.parseObject(JSON.toJSONString(equ), IdxBizJgTechParamsBoiler.class);
        if (!ValidationUtil.isEmpty(equipTechParamBoiler)) {
            equipTechParamBoiler.setRecord(record);
            equipTechParamBoiler.setRecDate(new Date());
            iIdxBizJgTechParamsBoilerService.saveOrUpdateData(equipTechParamBoiler);
        }
    }

    /**
     * 保存压力容器技术参数
     *
     * @param equ
     * @param record
     */
    private void saveVesselParams(Map<String, Object> equ, String record) {
        log.error("数据===>{}", JSONObject.toJSONString(equ));
        IdxBizJgTechParamsVessel equipTechParamVessel = JSON.parseObject(JSON.toJSONString(equ), IdxBizJgTechParamsVessel.class);
        if (!ValidationUtil.isEmpty(equipTechParamVessel)) {
            equipTechParamVessel.setRecord(record);
            equipTechParamVessel.setRecDate(new Date());
            iIdxBizJgTechParamsVesselService.saveOrUpdateData(equipTechParamVessel);
        }
    }

    /**
     * 保存压力管道技术参数
     *
     * @param equ
     * @param record
     */
    private void savePipelineParams(Map<String, Object> equ, String record) {
        log.error("数据===>{}", JSONObject.toJSONString(equ));
        IdxBizJgTechParamsPipeline equipTechParamPipeline = JSON.parseObject(JSON.toJSONString(equ), IdxBizJgTechParamsPipeline.class);
        if (!ValidationUtil.isEmpty(equipTechParamPipeline)) {
            equipTechParamPipeline.setWallThickness(String.valueOf(equ.get("wallThickness_YLGD")));
            equipTechParamPipeline.setMedium(String.valueOf(equ.get("medium_YLGD")));
            equipTechParamPipeline.setTemperature(String.valueOf(equ.get("temperature_YLGD")));
            equipTechParamPipeline.setDeviceLevel(String.valueOf(equ.get("deviceLevel_YLGD")));
            equipTechParamPipeline.setWorkTemperature(String.valueOf(equ.get("workTemperature_YLGD")));
            equipTechParamPipeline.setRecord(record);
            equipTechParamPipeline.setRecDate(new Date());
            iIdxBizJgTechParamsPipelineService.saveOrUpdateData(equipTechParamPipeline);
        }
    }

    /**
     * 保存大型游乐设施技术参数
     *
     * @param equ
     * @param record
     */
    private void saveRidesParams(Map<String, Object> equ, String record) {
        log.error("数据===>{}", JSONObject.toJSONString(equ));
        IdxBizJgTechParamsRides equipTechParamRides = JSON.parseObject(JSON.toJSONString(equ), IdxBizJgTechParamsRides.class);
        if (!ValidationUtil.isEmpty(equipTechParamRides)) {
            equipTechParamRides.setRecord(record);
            equipTechParamRides.setRecDate(new Date());
            equipTechParamRides.setRunningSpeed(String.valueOf(equ.get("runningSpeed_DXYLSS")));
            equipTechParamRides.setSlideLength(String.valueOf(equ.get("slideLength_DXYLSS")));
            equipTechParamRides.setOperatingHeight(String.valueOf(equ.get("operatingHeight_DXYLSS")));
            iIdxBizJgTechParamsRidesService.saveOrUpdateData(equipTechParamRides);
        }
    }

    /**
     * 保存客运索道技术参数
     *
     * @param equ
     * @param record
     */
    private void saveRopewayParams(Map<String, Object> equ, String record) {
        log.error("数据===>{}", JSONObject.toJSONString(equ));
        IdxBizJgTechParamsRopeway equipTechParamRopeway = JSON.parseObject(JSON.toJSONString(equ), IdxBizJgTechParamsRopeway.class);
        if (!ValidationUtil.isEmpty(equipTechParamRopeway)) {
            equipTechParamRopeway.setRecord(record);
            equipTechParamRopeway.setRecDate(new Date());
            iIdxBizJgTechParamsRopewayService.saveOrUpdateData(equipTechParamRopeway);
        }
    }

    /**
     * 保存电梯技术参数
     *
     * @param equ
     * @param record
     */
    private void saveElevatorParams(Map<String, Object> equ, String record) {
        log.error("数据===>{}", JSONObject.toJSONString(equ));
        IdxBizJgTechParamsElevator equipTechParamElevator = JSON.parseObject(JSON.toJSONString(equ), IdxBizJgTechParamsElevator.class);
        if (!ValidationUtil.isEmpty(equipTechParamElevator)) {
            equipTechParamElevator.setRecord(record);
            equipTechParamElevator.setRecDate(new Date());
            iIdxBizJgTechParamsElevatorService.saveOrUpdateData(equipTechParamElevator);
        }
    }


    /**
     * 保存设备数据至es
     *
     * @param record 设备唯一编码
     */
    private void saveEquInfoToEs(String record) {
        Map<String, Object> map = categoryOtherInfoMapper.selectDataById(record);
        ESEquipmentCategoryDto equipmentCategoryDto = JSON.parseObject(toJSONString(map), ESEquipmentCategoryDto.class);
        if (!ObjectUtils.isEmpty(equipmentCategoryDto)) {
            long time = Timestamp.valueOf(map.get("REC_DATE").toString().substring(0, 19)).getTime();
            equipmentCategoryDto.setREC_DATE(time);
            esEquipmentCategory.save(equipmentCategoryDto);
        }
    }

    /**
     * 八大类历史设备导入
     *
     * @param file
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Object dataCheckAndImportEquipmentData(String remark, MultipartFile file) {

        List<EquipInfoExcelDto> equipInfoExcelDtos;
        try {
            // 1, 数据读取 + 格式、类型异常检查
            equipInfoExcelDtos = this.checkData(file);
        } catch (Exception e) {
            throw new BadRequest(String.format("参数校验失败，详细请看返回信息：%s", e.getMessage()));
        }

        // 2, 保存设备数据
        this.batchSaveEquipmentData(remark, equipInfoExcelDtos);
        return Boolean.TRUE;
    }

    /**
     * excel 文件读取，字段校验
     *
     * @param file excel 文件
     * @return 设备数据
     * @throws Exception 异常信息
     */
    public List<EquipInfoExcelDto> checkData(MultipartFile file) {
        List<EquipInfoExcelDto> dataList = new ArrayList<>();
        resultError.clear();
        useInnerCodeList.clear();
        equCodeList.clear();
        factoryNumList.clear();
        useOrgCodeList.clear();
        projectContraptionMap.clear();

        try {
            InputStream inputStream = file.getInputStream();
            ExcelReader excelReader = EasyExcel.read(inputStream).build();
            List<ReadSheet> sheetList = excelReader.excelExecutor().sheetList(); // 获取所有 sheet

            for (ReadSheet readSheet : sheetList) {
                String sheetName = readSheet.getSheetName();
                int sheetNo = readSheet.getSheetNo();

                // 忽略填充设备种类类别品种的三级联动sheet页
                if (sheetName.contains("忽略")) {
                    continue;
                }
                Map<String, Object> sheetError = new HashMap<>();
                EasyExcel.read(file.getInputStream(), EquipInfoExcelDto.class, new AnalysisEventListener<EquipInfoExcelDto>() {
                    // 每读一行都会执行
                    @Override
                    public void invoke(EquipInfoExcelDto data, AnalysisContext context) {
                        // 数据检查
                        checkExcelData(sheetName, data, context, sheetError);
                        // if (!ValidationUtil.isEmpty(data.getUseInnerCode())) {
                        //     useInnerCodeList.add(data.getUseInnerCode());
                        // }
                        equCodeList.add(data.getEquCode());
                        useOrgCodeList.add(data.getUseOrgCode());
                        dataList.add(data);
                    }

                    // 每个sheet页读完都会执行
                    @Override
                    public void doAfterAllAnalysed(AnalysisContext context) {
                        // 记录每一个sheet页的错误集
                        if (!ValidationUtil.isEmpty(sheetError)) {
                            resultError.put(String.format("%s sheet页", sheetName), sheetError);
                        }
                    }
                }).headRowNumber(4).sheet(sheetNo, sheetName).doRead();
            }

            excelReader.finish(); // 关闭 reader，释放资源

            if (CollectionUtils.isEmpty(dataList)) {
                resultError.put("allSheet", "你上传了一个空数据的Excel文档!");
                throw new BadRequest("你上传了一个空数据的Excel文档!");
            }

            // 检查 resultError中的每一项，若存在内容，则有错误信息，直接抛异常
            if (!ValidationUtil.isEmpty(resultError)) {
                throw new BadRequest(JSON.toJSONString(resultError));
            }

            return dataList;
        } catch (Exception e) {
            throw new BadRequest(e.getMessage());
        }
    }

    /**
     * excel数据字段校验
     *
     * @param sheetName sheet页名称
     * @param data      excel数据
     * @param context
     */
    public void checkExcelData(String sheetName, EquipInfoExcelDto data, AnalysisContext context, Map<String, Object> sheetError) {
        ReadRowHolder readRowHolder = context.readRowHolder();
        int rowIndex = readRowHolder.getRowIndex() + 1;
        StringBuffer rowError = new StringBuffer();
        log.info("开始解析数据，第{}条数据", rowIndex);
        // 是否起重机械
        boolean isQZJX = !ValidationUtil.isEmpty(data.getEquList()) && EquipmentClassifityEnum.QZJX.getCode().equals(data.getEquList());
        // 是否场内机动车辆
        boolean isCNJDXL = !ValidationUtil.isEmpty(data.getEquList()) && EquipmentClassifityEnum.CC.getCode().equals(data.getEquList());
        // 是否锅炉
        boolean isGL = !ValidationUtil.isEmpty(data.getEquList()) && EquipmentClassifityEnum.GL.getCode().equals(data.getEquList());
        // 是否压力容器
        boolean isYLRQ = !ValidationUtil.isEmpty(data.getEquList()) && EquipmentClassifityEnum.YLRQ.getCode().equals(data.getEquList());
        // 是否压力管道
        boolean isYLGD = !ValidationUtil.isEmpty(data.getEquList()) && EquipmentClassifityEnum.YLGD.getCode().equals(data.getEquList());
        // 是否大型游乐设施
        boolean isDXYNSS = !ValidationUtil.isEmpty(data.getEquList()) && EquipmentClassifityEnum.YLSS.getCode().equals(data.getEquList());
        // 是否客运索道
        boolean isKYSD = !ValidationUtil.isEmpty(data.getEquList()) && EquipmentClassifityEnum.KYSD.getCode().equals(data.getEquList());
        // 是否电梯
        boolean isDT = !ValidationUtil.isEmpty(data.getEquList()) && EquipmentClassifityEnum.DT.getCode().equals(data.getEquList());

        try {
            log.info("解析第{}行数据：{}", rowIndex, JSON.toJSONString(data));

            // 通用字段检查 每一个sheet页都有的基本信息，设计信息，制造信息和使用信息
            this.commonFieldCheck(data, rowError);

            // 起重机械----技术参数 检查
            if (isQZJX) {
                this.QZJXTechnicalParamsCheck(data, rowError);
            }
            // 场内机动车辆----技术参数 检查
            if (isCNJDXL) {
                this.CNJDCLTechnicalParamsCheck(data, rowError);
            }
            // 锅炉----技术参数 检查
            if (isGL) {
                this.GLTechnicalParamsCheck(data, rowError);
            }
            // 压力容器----技术参数 检查
            if (isYLRQ) {
                this.YLRQTechnicalParamsCheck(data, rowError);
            }
            // 压力管道----技术参数 检查
            if (isYLGD) {
                this.YLGDTechnicalParamsCheck(data, rowError);
            }
            // 大型游乐设施----技术参数 检查
            if (isDXYNSS) {
                this.DXYLSSTechnicalParamsCheck(data, rowError);
            }
            // 客运索道----技术参数 检查
            if (isKYSD) {
                this.KYSDTechnicalParamsCheck(data, rowError);
            }
            // 电梯----技术参数 检查
            if (isDT) {
                this.DTTechnicalParamsCheck(data, rowError);
            }

            if (!StringUtils.isBlank(rowError)) {
                String excelErrorStr = "Excel 第[%s]行";
                sheetError.put(String.format(excelErrorStr, rowIndex), rowError);
            }

        } catch (Exception e) {
            log.error(String.format("sheet页：[%s] -> 对应行索引数: [%s] -> 失败的 Excel 数据: [%s]", sheetName, rowIndex, JSON.toJSONString(data)), e);
            throw e;
        }
    }

    /**
     * 通用字段检查 每一个sheet页都有的基本信息，设计信息，制造信息和使用信息
     *
     * @param data     源数据
     * @param rowError 错误集合
     */
    private void commonFieldCheck(EquipInfoExcelDto data, StringBuffer rowError) {

        boolean isYLRQ = !ObjectUtils.isEmpty(data.getEquList()) && EquipmentClassifityEnum.YLRQ.getCode().equals(data.getEquList());// 是否压力容器
        boolean isYLGD = !ObjectUtils.isEmpty(data.getEquList()) && EquipmentClassifityEnum.YLGD.getCode().equals(data.getEquList());// 是否压力管道
        boolean isDT = !ObjectUtils.isEmpty(data.getEquList()) && EquipmentClassifityEnum.DT.getCode().equals(data.getEquList());// 是否电梯
        boolean isCC = !ObjectUtils.isEmpty(data.getEquList()) && EquipmentClassifityEnum.CC.getCode().equals(data.getEquList());// 是否场车
        boolean isQZJX = !ObjectUtils.isEmpty(data.getEquList()) && EquipmentClassifityEnum.QZJX.getCode().equals(data.getEquList());// 是否起重机械

        // 基本信息
        checkNotBlank(data.getEquList(), "设备种类不能为空；", rowError);
        checkNotBlank(data.getEquCategory(), "设备类别不能为空；", rowError);
        // checkNotBlank(data.getUseInnerCode(), "单位内编号不能为空；", rowError);
        // if (useInnerCodeList.contains(data.getUseInnerCode())) {
        //     rowError.append("单位内编号不能重复；");
        // }
        // checkNotBlank(data.getEquType(), "设备型号不能为空；", rowError);
        if (!isYLGD) {
            checkNotBlank(data.getProductName(), "产品名称不能为空；", rowError);
            checkNotBlank(data.getEquCodeType(), "有无设备代码不能为空；", rowError);
            if ("1".equals(data.getEquCodeType())) {
                checkNotBlank(data.getEquCode(), "设备代码不能为空；", rowError);
                String equCode = data.getEquCode();
                if (!StringUtils.isEmpty(equCode)) {
                    if (equCode.matches("[a-zA-Z0-9]+")) {
                        // if (equCode.length() < 17) {
                        //     rowError.append("设备代码不能小于17位；");
                        // }
                        // if (equCode.length() > 20) {
                        //     rowError.append("设备代码不能大于20位；");
                        // }
                    } else {
                        rowError.append("设备代码不能包含特殊字符；");
                    }
                }
                if (equCodeList.contains(data.getEquCode())) {
                    rowError.append("设备代码不能重复；");
                }
                this.checkEquCodeUniqueness(data.getEquCode(), rowError);
            } else {
                data.setEquCode("");
            }
        }
        if (isYLGD) {// 校验压力管道特有的参数
            checkNotBlank(data.getPipeName(), "管道名称不能为空；", rowError);
            checkNotBlank(data.getProjectContraption(), "工程（装置）名称不能为空；", rowError);
            checkNotBlank(data.getProjectContraptionNo(), "工程（装置）编号不能为空；", rowError);
            // 使用登记证编号校验
            List<IdxBizJgRegisterInfo> idxBizJgRegisterInfos = idxBizJgRegisterInfoServiceImpl.getBaseMapper().selectList(new LambdaQueryWrapper<IdxBizJgRegisterInfo>().eq(IdxBizJgRegisterInfo::getUseOrgCode, data.getUseOrgCode()).notLike(IdxBizJgRegisterInfo::getUseOrgCode, "管"));
            if (!idxBizJgRegisterInfos.isEmpty()) {
                rowError.append("使用登记证编号已存在系统中；");
            }
            List<IdxBizJgProjectContraption> projectContraptions = idxBizJgProjectContraptionService.lambdaQuery().eq(IdxBizJgProjectContraption::getEquList, EquipmentClassifityEnum.YLGD.getCode()).eq(IdxBizJgProjectContraption::getUseRegistrationCode, data.getUseOrgCode()).eq(IdxBizJgProjectContraption::getProjectContraption, data.getProjectContraption()).eq(IdxBizJgProjectContraption::getProjectContraptionNo, data.getProjectContraptionNo()).list();
            if (!projectContraptions.isEmpty()) {
                rowError.append("使用登记证编号已存在系统中；");
            }
            // 同一工程装置下管道编号不能重复
            if (!ValidationUtil.isEmpty(data.getProjectContraption())) {

                String useUnitCode = String.valueOf(data.getUseUnitCode()).trim();// 使用单位Code
                String useUnit = String.valueOf(data.getUseUnit()).trim();// 使用单位名称
                String proConName = data.getProjectContraption().trim();// 工程装置名称

                // 查询该企业下工程装置名称
                IdxBizJgProjectContraption oldContraption = idxBizJgProjectContraptionService.lambdaQuery()
                        .eq(IdxBizJgProjectContraption::getUseUnitCreditCode, useUnitCode)
                        .eq(IdxBizJgProjectContraption::getUseUnitName, useUnit)
                        .eq(IdxBizJgProjectContraption::getProjectContraption, proConName)
                        .list().stream().findFirst().orElse(null);
                Optional.ofNullable(oldContraption).ifPresent(old -> {
                    List<String> pipelineNumberList = idxBizJgProjectContraptionServiceImpl.getBaseMapper()
                            .selectEquipList(String.valueOf(old.getSequenceNbr()))
                            .stream()
                            .map(item -> (String) item.get("pipelineNumber"))
                            .collect(Collectors.toList());
                    if (pipelineNumberList.contains(data.getPipelineNumber())) {
                        rowError.append(String.format("系统中工程装置（%s）下已经存在管道编号（%s）；", data.getProjectContraption(), data.getPipelineNumber()));
                    }
                });

                List<String> list = projectContraptionMap.get(data.getProjectContraption());
                if (null != list) {
                    // 判断该装置下是否已经存在该管道编号
                    if (list.contains(data.getPipelineNumber())) {
                        rowError.append(String.format("同一工程装置（%s）下管道编号不能重复；", data.getProjectContraption()));
                    }
                    list.add(data.getPipelineNumber());
                } else {
                    list = new ArrayList<>();
                }
                projectContraptionMap.put(data.getProjectContraption(), list);
            }
        } else {
            data.setProjectContraption("");
        }
        if (isYLRQ) {// 校验压力容器特有的参数
            boolean isGasCylinder = !org.apache.commons.lang3.ObjectUtils.isEmpty(data.getEquCategory()) && "2300".equals(data.getEquCategory());// 是否气瓶
            boolean isFixedGasCylinder = !org.apache.commons.lang3.ObjectUtils.isEmpty(data.getEquCategory()) && "2100".equals(data.getEquCategory());// 是否固定式压力容器
            boolean isOxygenChamber = !org.apache.commons.lang3.ObjectUtils.isEmpty(data.getEquCategory()) && "2400".equals(data.getEquCategory());// 是否氧舱
            boolean isMobilePressureVessel = !org.apache.commons.lang3.ObjectUtils.isEmpty(data.getEquCategory()) && "2200".equals(data.getEquCategory());// 是否移动式压力容器
            boolean isSpecialGasCylinder = isGasCylinder && !org.apache.commons.lang3.ObjectUtils.isEmpty(data.getEquDefine()) && "23T0".equals(data.getEquDefine());// 是否特种气瓶
            boolean isCarGasCylinder = isSpecialGasCylinder && (!org.apache.commons.lang3.ObjectUtils.isEmpty(data.getWhetherVehicleCylinder()) && "1".equals(data.getWhetherVehicleCylinder()));// 是否车用气瓶
            if (isGasCylinder) { // 是气瓶
                if (!isSpecialGasCylinder) { // 不是特种气瓶
                    data.setWhetherVehicleCylinder("");
                    checkNotBlank(data.getInformationSituation(), "信息化管理情况不能为空；", rowError);
                    if (!org.apache.commons.lang3.ObjectUtils.isEmpty(data.getInformationSituation())) {
                        checkNotBlank(data.getInformationManageCode(), "二维码或者电子标签编号不能为空；", rowError);
                    }
                }
                if (isSpecialGasCylinder) { // 是特种气瓶
                    checkNotBlank(data.getWhetherVehicleCylinder(), "是否车用气瓶不能为空；", rowError);
                    if (!isCarGasCylinder) {// 不是车用气瓶
                        checkNotBlank(data.getInformationSituation(), "信息化管理情况不能为空；", rowError);
                        if (!org.apache.commons.lang3.ObjectUtils.isEmpty(data.getInformationSituation())) {
                            checkNotBlank(data.getInformationManageCode(), "二维码或者电子标签编号不能为空；", rowError);
                        }
                    }
                    if (isCarGasCylinder) { // 是车用气瓶
                        data.setInformationSituation("");
                        data.setInformationManageCode("");
                        checkFactoryNumUniqueness(data, rowError);// 校验出厂编号/产品编码唯一性
                    }
                }
                data.setWhetherSphericalTank("");
                data.setWhetherSkidMountedPressureVessel("");
            }
            if (isFixedGasCylinder) { // 是固定式压力容器
                checkNotBlank(data.getWhetherSphericalTank(), "是否球罐不能为空；", rowError);
                checkNotBlank(data.getWhetherSkidMountedPressureVessel(), "是否撬装式压力容器不能为空；", rowError);
                data.setInformationSituation("");
                data.setInformationManageCode("");
            }
            if (isMobilePressureVessel) {// 是移动式压力容器
                data.setWhetherSkidMountedPressureVessel("");
                data.setWhetherVehicleCylinder("");
                data.setWhetherSphericalTank("");
                data.setInformationSituation("");
                data.setInformationManageCode("");
            }
            if (isOxygenChamber) {// 是氧舱
                data.setWhetherSkidMountedPressureVessel("");
                data.setWhetherVehicleCylinder("");
                data.setWhetherSphericalTank("");
                data.setInformationSituation("");
                data.setInformationManageCode("");
            }
        }
        checkNotBlank(data.getUseOrgCode(), "使用登记证编号不能为空；", rowError);
        if (!StringUtils.isEmpty(data.getUseOrgCode())) {
            if (!this.useOrgCodeRegularMatching(data)) {
                rowError.append("使用登记证编号格式不正确；");
            }
            if (!isYLGD && useOrgCodeList.contains(data.getUseOrgCode())) {
                rowError.append("使用登记证编号不能重复；");
            }
            try {
                idxBizJgRegisterInfoServiceImpl.checkUseRegistrationCode(data.getUseOrgCode(), "set");
            } catch (Exception e) {
                rowError.append(e.getMessage());
            }
            if (!isYLGD && commonService.useRegistrationCertificateAccountUnique(data.getUseOrgCode(), null)) {
                rowError.append("使用登记证编号已存在系统中；");
            }
        }
        // 使用信息
        checkNotBlank(data.getUseUnitCode(), "使用单位统一社会信用代码不能为空；", rowError);
        Optional.ofNullable(data.getUseUnitCode()).ifPresent(v -> checkCreditCode(v, "使用单位统一社会信用代码格式不正确；", rowError));
        checkNotBlank(data.getUseUnit(), "使用单位名称不能为空；", rowError);
        // 设计信息  电梯、场车、起重机械无"设计信息"
        if (!isDT && !isCC && !isQZJX) {

            // checkNotBlank(data.getDesignUnitCreditCode(), "设计单位统一社会信用代码不能为空；", rowError);
            Optional.ofNullable(data.getDesignUnitCreditCode()).ifPresent(v -> checkCreditCode(v, "设计单位统一社会信用代码格式不正确；", rowError));
            // checkNotBlank(data.getDesignUnitName(), "设计单位名称不能为空；", rowError);
            // checkNotBlank(data.getDesignUseDate(), "设计使用年限不能为空；", rowError);
            // Optional.ofNullable(data.getDesignUseDate()).ifPresent(v -> checkDateFormatNumber(v, "设计使用年限不能为数字以外的其他类型；", rowError));
            if (!ValidationUtil.isEmpty(data.getDesignUseDate())) {
                data.setDesignUseDate(data.getDesignUseDate().replace("年", "").replace("/", ""));
            }
            // checkNotBlank(data.getDesignDate(), "设计日期不能为空；", rowError);
            if (!ValidationUtil.isEmpty(data.getDesignDate())) {
                if ("—".equals(data.getDesignDate().trim()) || "/".equals(data.getDesignDate().trim())) {
                    data.setDesignDate(null);
                    return;
                }
                data.setDesignDate(data.getDesignDate().trim().replace("—", ""));
                String formattedDate = checkDateFormatCorrect(data.getDesignDate().trim(), "设计日期格式不正确；", rowError);
                if (formattedDate != null) {
                    data.setDesignDate(formattedDate);
                }
            }

            if (!ValidationUtil.isEmpty(data.getAppraisalDate())) {
                data.setAppraisalDate(data.getAppraisalDate().trim().replace("—", ""));
                String formattedDate = checkDateFormatCorrect(data.getAppraisalDate().trim(), "设计文件鉴定日期格式不正确；", rowError);
                if (formattedDate != null) {
                    data.setAppraisalDate(formattedDate);
                }
            }

            if (ValidationUtil.isEmpty(data.getDesignUnitCreditCode()) || ValidationUtil.isEmpty(data.getDesignUnitName()) || ValidationUtil.isEmpty(data.getDesignUseDate()) || ValidationUtil.isEmpty(data.getDesignDate())) {
                data.setDesignIsComplete("2");
            } else {
                data.setDesignIsComplete("1");
            }
        }
        // 制造信息
        if (!isYLGD) {
            // checkNotBlank(data.getProduceUnitCreditCode(), "制造单位统一社会信用代码不能为空；", rowError);
            Optional.ofNullable(data.getProduceUnitCreditCode()).ifPresent(v -> checkCreditCode(v, "制造单位统一社会信用代码格式不正确；", rowError));
            // checkNotBlank(data.getProduceUnitName(), "制造单位名称不能为空；", rowError);
            // checkNotBlank(data.getProduceLicenseNum(), "制造许可编号不能为空；", rowError);
            // checkNotBlank(data.getFactoryNum(), "出厂编号/产品编码不能为空；", rowError);
            // checkNotBlank(data.getProduceDate(), "制造日期不能为空；", rowError);

            if (!ValidationUtil.isEmpty(data.getProduceDate())) {
                data.setProduceDate(data.getProduceDate().trim().replace("—", ""));
                String formattedDate = checkDateFormatCorrect(data.getProduceDate().trim(), "制造日期格式不正确；", rowError);
                if (formattedDate != null) {
                    data.setProduceDate(formattedDate);
                }
            }

            if (ValidationUtil.isEmpty(data.getProduceUnitCreditCode()) || ValidationUtil.isEmpty(data.getProduceUnitName()) || ValidationUtil.isEmpty(data.getProduceLicenseNum()) || ValidationUtil.isEmpty(data.getFactoryNum()) || ValidationUtil.isEmpty(data.getProduceDate())) {
                data.setFactoryIsComplete("2");
            } else {
                data.setFactoryIsComplete("1");
            }
        }
    }

    /**
     * 检查并格式化上传Excel中的日期格式
     *
     * @param date         待检查数据
     * @param errorMessage 错误内容
     * @param rowError     错误集
     * @return 格式化后的日期字符串，如果格式不正确则返回null
     */
    private String checkDateFormatCorrect(String date, String errorMessage, StringBuffer rowError) {
        String res = date.trim().replace("/", "-").replace(".", "-")
                .replace("年", "-").replace("月", "-").replace("日", "");

        // 处理不同格式的日期
        // 2017-12
        if (res.matches("\\d{4}\\-\\d{2}")) {
            res = res + "-01";
        }
        // 2017-1
        if (res.matches("\\d{4}\\-\\d{1}")) {
            res = res.substring(0, res.length() - 1) + "0" + res.substring(res.length() - 1) + "-01";
        }
        // 2023-5-5
        if (res.matches("\\d{4}\\-\\d{1}\\-\\d{1}")) {
            res = res.substring(0, res.length() - 3) + "0" + res.substring(res.length() - 3, res.length() - 1) + "0" + res.substring(res.length() - 1);
        }
        // 2023-5-15
        if (res.matches("\\d{4}\\-\\d{1}\\-\\d{2}")) {
            res = res.substring(0, res.length() - 4) + "0" + res.substring(res.length() - 4);
        }

        if (!res.matches("\\d{4}-\\d{2}-\\d{2}") && !res.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")) {
            rowError.append(errorMessage);
            return null;
        }
        return res;
    }

    /**
     * 检查上传Excel中的统一信用代码格式
     *
     * @param code         待检查数据
     * @param errorMessage 错误内容
     * @param rowError     错误集
     */
    private void checkCreditCode(String code, String errorMessage, StringBuffer rowError) {
        String regex = "^[A-Z0-9]{15}(?:[A-Z0-9]{3})?$";
        if (!code.matches(regex)) {
            rowError.append(errorMessage);
        }
    }

    /**
     * 检查上传Excel中的数字格式是否正确
     *
     * @param date         待检查数据
     * @param errorMessage 错误内容
     * @param rowError     错误集
     */
    private void checkDateFormatNumber(String date, String errorMessage, StringBuffer rowError) {
        if (!NumberUtils.isCreatable(date)) {
            rowError.append(errorMessage);
        }
    }

    /**
     * 车用气瓶业务里面的 出厂编号/产品编码 校验唯一性（产品编号在车用气瓶范围内全局唯一）
     *
     * @param data
     */
    private void checkFactoryNumUniqueness(EquipInfoExcelDto data, StringBuffer rowError) {
        Integer count = commonService.checkFactoryNumUniquenessForVehicleCylinder(data.getFactoryNum(), null);
        if (count > 0) {
            rowError.append("出厂编号/产品编码系统中已存在！");
        }
    }

    /**
     * 根据设备代码检查唯一性
     *
     * @param equCode
     * @param rowError
     */
    private void checkEquCodeUniqueness(String equCode, StringBuffer rowError) {
        Boolean bool = commonService.checkEquCodeUniqueness(equCode);
        if (bool) {
            rowError.append("设备代码系统中已存在；");
        }
    }

    /**
     * 起重机械----技术参数 检查
     *
     * @param data
     * @param rowError
     */
    private void QZJXTechnicalParamsCheck(EquipInfoExcelDto data, StringBuffer rowError) {
    }

    /**
     * 场内机动车辆----技术参数 检查
     *
     * @param data
     * @param rowError
     */
    private void CNJDCLTechnicalParamsCheck(EquipInfoExcelDto data, StringBuffer rowError) {
    }

    /**
     * 锅炉----技术参数 检查
     *
     * @param data
     * @param rowError
     */
    private void GLTechnicalParamsCheck(EquipInfoExcelDto data, StringBuffer rowError) {
    }

    /**
     * 压力容器----技术参数 检查
     *
     * @param data
     * @param rowError
     */
    private void YLRQTechnicalParamsCheck(EquipInfoExcelDto data, StringBuffer rowError) {
        // checkNotBlank(data.getSingleBottleVolume(), "单瓶容积不能为空；", rowError);
        // checkNotBlank(data.getChargingMedium(), "充装介质不能为空；", rowError);
        // checkNotBlank(data.getNominalWorkingPressure(), "公称工作压力不能为空；", rowError);
    }

    /**
     * 压力管道----技术参数 检查
     *
     * @param data
     * @param rowError
     */
    private void YLGDTechnicalParamsCheck(EquipInfoExcelDto data, StringBuffer rowError) {
        checkNotBlank(data.getWallThickness_YLGD(), "公称壁厚不能为空；", rowError);
        checkNotBlank(data.getNominalDiameter(), "公称直径不能为空；", rowError);
        checkNotBlank(data.getPipeLength(), "管道长度不能为空；", rowError);
        checkNotBlank(data.getPressure(), "设计-压力不能为空；", rowError);
        checkNotBlank(data.getMedium_YLGD(), "设计-介质不能为空；", rowError);
        checkNotBlank(data.getTemperature_YLGD(), "设计-温度不能为空；", rowError);
        checkNotBlank(data.getPipelineNumber(), "管道编号不能为空；", rowError);
        checkNotBlank(data.getDeviceLevel_YLGD(), "管道级别不能为空；", rowError);
        Optional.ofNullable(data.getStartePosition()).ifPresent(v -> {
            if (v.split("-").length <= 1) {
                rowError.append("起/始位置 （经纬度）格式不正确");
            }
        });
        if (!ObjectUtils.isEmpty(data.getStartePosition()) && data.getStartePosition().split("-").length == 2) {
            String[] split = data.getStartePosition().split("-");
            data.setStartePosition(String.format("{\"latitude\":%s,\"longitude\":%s}", split[0], split[1]));
        }
    }

    /**
     * 检查字段是否为空，如果为空则追加错误信息到result
     *
     * @param value        待检查字段
     * @param errorMessage 错误信息
     * @param rowError     结果集
     */
    private void checkNotBlank(String value, String errorMessage, StringBuffer rowError) {
        if (StringUtils.isBlank(value)) {
            rowError.append(errorMessage);
        }
    }

    /**
     * 大型游乐设施----技术参数 检查
     *
     * @param data
     * @param rowError
     */
    private void DXYLSSTechnicalParamsCheck(EquipInfoExcelDto data, StringBuffer rowError) {
    }

    /**
     * 客运索道----技术参数 检查
     *
     * @param data
     * @param rowError
     */
    private void KYSDTechnicalParamsCheck(EquipInfoExcelDto data, StringBuffer rowError) {
    }

    /**
     * 使用等级证编号格式匹配
     *
     * @param data
     * @return 匹配通过true，反之false
     */
    private Boolean useOrgCodeRegularMatching(EquipInfoExcelDto data) {
        String useOrgCode = data.getUseOrgCode().replace("（", "(").replace("）", ")");
        data.setUseOrgCode(useOrgCode);
        // 梯00陕A00000(24) 起11陕K0127(15)
        String rule01 = "^[\\u4e00-\\u9fa5][0-9A-Z]{2}陕[A-Z0-9]{4,}\\(\\d{2}\\)$";
        boolean flage01 = Pattern.matches(rule01, useOrgCode);

        // 起17泾河0104(21) 锅10沣西 00004(20)
        String rule02 = "^[\\u4e00-\\u9fa5][0-9A-Z]{2}[\\u4e00-\\u9fa5]{2}[A-Z0-9]{4,5}\\(\\d{2}\\)$";
        boolean flage02 = Pattern.matches(rule02, useOrgCode);

        // CNG-A-01-A-116729
        String rule03 = "^[a-zA-Z]{3}-[a-zA-Z]-[0-9]{2}-[a-zA-Z]-\\d{6,8}$";
        boolean flage03 = Pattern.matches(rule03, useOrgCode);

        // 3010-610322-201212-3723
        String rule04 = "^\\d{4}-\\d{6}-\\d{4}(0[1-9]|1[0-2])-\\d{4}$";
        boolean flage04 = Pattern.matches(rule04, useOrgCode);

        // 容1LS陕G0053 起11陕K0127 容2LE陕DM6043
        String rule05 = "^[\\u4e00-\\u9fa5][0-9A-Z]{2,3}[\\u4e00-\\u9fa5][A-Z0-9]{5,6}$";
        boolean flage05 = Pattern.matches(rule05, useOrgCode);

        // CC20160091
        String rule06 = "^[A-Z]{2}[0-9]{8}$";
        boolean flage06 = Pattern.matches(rule06, useOrgCode);

        // 容15陕C00176(19)B10
        String rule07 = "^[\\u4e00-\\u9fa5][0-9A-Z]{2}陕[A-Z0-9]{5,}\\(\\d{2}\\)[A-Z0-9]{3}$";
        boolean flage07 = Pattern.matches(rule07, useOrgCode);

        // 锅10秦汉0006(6020)(20)
        String rule08 = "^[\\u4e00-\\u9fa5][0-9A-Z]{2}[\\u4e00-\\u9fa5]{2}[A-Z0-9]{4}\\(\\d{4}\\)\\(\\d{2}\\)$";
        boolean flage08 = Pattern.matches(rule08, useOrgCode);

        // 锅陕KB0415 游20陕DP00002 锅陕FF587
        String rule09 = "^[\\u4e00-\\u9fa5]{1}[0-9]{0,2}[\\u4e00-\\u9fa5]{1}[A-Z]{1,2}[0-9]{3,6}$";
        boolean flage09 = Pattern.matches(rule09, useOrgCode);

        // 陕TK20142429
        String rule10 = "^[\\u4e00-\\u9fa5]{1}[A-Z]{1,2}[0-9]{8}$";
        boolean flage10 = Pattern.matches(rule10, useOrgCode);

        // 4010610300200106-1105
        String rule11 = "^[0-9]{16}\\-[0-9]{4}$";
        boolean flage11 = Pattern.matches(rule11, useOrgCode);

        // 容IIIMC陕G-1202
        String rule12 = "^[\\u4e00-\\u9fa5]{1}[A-Z]{5}[\\u4e00-\\u9fa5]{1}[A-Z]{1}-[0-9]{4}$";
        boolean flage12 = Pattern.matches(rule12, useOrgCode);

        // AT2011-076
        String rule13 = "^[A-Z]{2,3}[0-9]{2,4}-[0-9]{3,5}$";
        boolean flage13 = Pattern.matches(rule13, useOrgCode);

        // 610302--0561
        String rule14 = "^[0-9]{6}--[0-9]{4}$";
        boolean flage14 = Pattern.matches(rule14, useOrgCode);

        // XTS泰3546(F8N9G787)
        String rule15 = "^[A-Z]{3}[\\u4e00-\\u9fa5][0-9]{4}\\([A-Z0-9]{4,9}\\)$";
        boolean flage15 = Pattern.matches(rule15, useOrgCode);

        // 梯12秦汉1611(SJE2021103783)(23)
        String rule16 = "^[\\u4e00-\\u9fa5][0-9A-Z]{2}[\\u4e00-\\u9fa5]{1,2}[0-9]{4}\\([A-Z0-9]{4,15}\\)\\(\\d{2}\\)$";
        boolean flage16 = Pattern.matches(rule16, useOrgCode);

        // 锅20空港051(16)(1510574)
        String rule17 = "^[\\u4e00-\\u9fa5][0-9A-Z]{2}[\\u4e00-\\u9fa5]{1,2}[0-9]{3,8}\\(\\d{2}\\)\\([A-Z0-9]{4,15}\\)$";
        boolean flage17 = Pattern.matches(rule17, useOrgCode);

        // 容IIMR陕EH0515
        String rule18 = "^[\\u4e00-\\u9fa5]{1}[A-Z]{2,5}[\\u4e00-\\u9fa5]{1}[A-Z0-9]{4,9}$";
        boolean flage18 = Pattern.matches(rule18, useOrgCode);

        // 锅陕B10006(24)     车0036(21)
        String rule19 = "^[\\u4e00-\\u9fa5]{1,2}[A-Z]{0,1}[0-9]{4,6}\\(\\d{2}\\)$";
        boolean flage19 = Pattern.matches(rule19, useOrgCode);

        // 容1LE陕D三0384
        String rule20 = "^[\\u4e00-\\u9fa5]{1}[A-Z0-9]{3}[\\u4e00-\\u9fa5]{1}[A-Z]{1}[\\u4e00-\\u9fa5]{1}[0-9]{4,6}$";
        boolean flage20 = Pattern.matches(rule20, useOrgCode);

        // 384
        String rule21 = "^[0-9]{3,4}$";
        boolean flage21 = Pattern.matches(rule21, useOrgCode);

        // 梯12空港0063(20H2G20-590-6)(22)   梯12秦汉0509(2013-11-443)(16)
        String rule22 = "^[\\u4e00-\\u9fa5][0-9A-Z]{2}[\\u4e00-\\u9fa5]{1,2}[0-9]{4}\\([A-Z0-9]{4,7}-[A-Z0-9]{2,3}-[A-Z0-9]{1,3}\\)\\(\\d{2}\\)$";
        boolean flage22 = Pattern.matches(rule22, useOrgCode);

        // 游A10陕CA00116(23)
        String rule23 = "^[\\u4e00-\\u9fa5][0-9A-Z]{3}陕[A-Z0-9]{5,7}\\(\\d{2}\\)$";
        boolean flage23 = Pattern.matches(rule23, useOrgCode);

        // 容IIIMC陕D三0384(2K13B3-03)
        String rule24 = "^[\\u4e00-\\u9fa5]{1}[A-Z0-9]{5}[\\u4e00-\\u9fa5]{1}[A-Z]{1}[\\u4e00-\\u9fa5]{1}[0-9]{4,6}\\([A-Z0-9]{6}-[0-9]{2}\\)$";
        boolean flage24 = Pattern.matches(rule24, useOrgCode);

        // 陕YN0:004
        String rule25 = "^[\\u4e00-\\u9fa5][A-Z]{2}[0-9]{1}:[0-9]{3}$";
        boolean flage25 = Pattern.matches(rule25, useOrgCode);

        // 起1100001(21)
        String rule26 = "^[\\u4e00-\\u9fa5][A-Z0-9]{7}\\(\\d{2}\\)$";
        boolean flage26 = Pattern.matches(rule26, useOrgCode);

        // 梯12秦汉0750(SLT03159-2020)(21)
        String rule27 = "^[\\u4e00-\\u9fa5][0-9A-Z]{2}[\\u4e00-\\u9fa5]{1,2}[0-9]{4}\\([A-Z0-9]{4,8}-[A-Z0-9]{4}\\)\\(\\d{2}\\)$";
        boolean flage27 = Pattern.matches(rule27, useOrgCode);

        // G-01-T-003548
        String rule28 = "^[a-zA-Z]{1}-[0-9]{2}-[A-Z]-\\d{6}$";
        boolean flage28 = Pattern.matches(rule28, useOrgCode);

        // 客1LS0013
        String rule29 = "^[\\u4e00-\\u9fa5]{1}[0-9]{1}[A-Z]{1,2}[0-9]{4}$";
        boolean flage29 = Pattern.matches(rule29, useOrgCode);

        // T20090311
        String rule30 = "^[A-Za-z]\\d{4}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])$";
        boolean flage30 = Pattern.matches(rule30, useOrgCode);

        // 容2MS陕JI0487
        String rule31 = "^容\\d[A-Z]{2}陕[A-Z]{2}\\d{4}$";
        boolean flage31 = Pattern.matches(rule31, useOrgCode);

        // 3MR陕J0032
        String rule32 = "^\\d[A-Z]{2}陕[A-Z]\\d{4}$";
        boolean flage32 = Pattern.matches(rule32, useOrgCode);


        return flage01 || flage02 || flage03 || flage04 || flage05 || flage06 || flage07 || flage08 || flage09 || flage10 || flage11 || flage12 || flage13 || flage14 || flage15 || flage16 || flage17 || flage18 || flage19 || flage20 || flage21 || flage22 || flage23 || flage24 || flage25 || flage26 || flage27 || flage28 || flage29 || flage30 || flage31 || flage32;
    }


    /**
     * 电梯----技术参数 检查
     *
     * @param data
     * @param rowError
     */
    private void DTTechnicalParamsCheck(EquipInfoExcelDto data, StringBuffer rowError) {
    }

    /**
     * 批量异步保存设备数据
     *
     * @param equipInfoExcelDtos
     */
    public void batchSaveEquipmentData(String remark, List<EquipInfoExcelDto> equipInfoExcelDtos) {

        equipInfoExcelDtos.forEach(equ -> this.saveEquipmentDataInTransaction((Map<String, Object>) JSON.parseObject(JSON.toJSONString(equ), Map.class), "jg_his", remark));
        // int batchSize = 1000;
        // int totalSize = equipInfoExcelDtos.size();
        // for (int i = 0; i < totalSize; i += batchSize) {
        //     List<EquipInfoExcelDto> batch = equipInfoExcelDtos.subList(i, Math.min(totalSize, i + batchSize));
        //     try {
        //         CompletableFuture.allOf(batch.stream().map(equ -> CompletableFuture.runAsync(
        //                         () -> this.saveEquipmentDataInTransaction((Map<String, Object>) JSON.parseObject(JSON.toJSONString(equ), Map.class), "jg_his", remark)
        //                 )
        //         ).toArray(CompletableFuture[]::new)).join();
        //     } catch (Exception e) {
        //         log.error("数据上传，保存设备数据失败: {}", e.getMessage());
        //         throw new BadRequest("数据上传，保存设备数据失败！");
        //     }
        // }
    }

    /**
     * 检查管道的excel数据格式
     *
     * @param multipartFile 文件
     * @param isGYGD        是否工业管道
     * @return 结果集合
     * @throws Exception 检测不通过，异常情况描述
     */
    public Object checkGDData(MultipartFile multipartFile, Boolean isGYGD) throws Exception {
        List<PipingExcelDto> dataList = new ArrayList<>();
        List<String> resultGDError = new ArrayList<>();
        List<String> pipelineNumList = new ArrayList<>();
        try {
            EasyExcel.read(multipartFile.getInputStream(), PipingExcelDto.class, new AnalysisEventListener<PipingExcelDto>() {
                @Override
                public void invoke(PipingExcelDto data, AnalysisContext context) {
                    resultGDError.add(checkGDExcelData(data, context, isGYGD, pipelineNumList).toString());
                    dataList.add(data);
                }

                @Override
                public void doAfterAllAnalysed(AnalysisContext context) {
                    if (CollectionUtils.isEmpty(dataList)) {
                        log.info("你上传了一个空数据的Excel文档!");
                        resultGDError.add("你上传了一个空数据的Excel文档!");
                        throw new BadRequest("你上传了一个空数据的Excel文档!");
                    }
                }
            }).headRowNumber(4).sheet().doRead();
            if (resultGDError.stream().anyMatch(input -> !input.isEmpty())) {
                throw new BadRequest("上传失败！");
            }
            return dataList;
        } catch (Exception e) {
            throw new Exception(resultGDError.stream()
                    .filter(s -> !s.isEmpty())
                    .collect(Collectors.joining("<br/>")));
        }
    }

    public StringBuffer checkGDExcelData(PipingExcelDto data, AnalysisContext context, Boolean isGYGD, List<String> pipelineNumList) {

        StringBuffer rowError = new StringBuffer();
        ReadRowHolder readRowHolder = context.readRowHolder();
        int rowIndex = readRowHolder.getRowIndex() + 1;
        try {
            log.info("解析第{}行数据：{}", rowIndex, JSON.toJSONString(data));
            checkNotBlank(data.getPipeName(), "管道名称不能为空；", rowError);
            checkNotBlank(data.getDesignUnitCreditCode(), "设计单位统一社会信用代码不能为空；", rowError);
            checkNotBlank(data.getDesignUnitName(), "设计单位名称不能为空；", rowError);
            checkNotBlank(data.getInspectOrgCode(), "检验检测机构统一社会信用代码不能为空；", rowError);
            checkNotBlank(data.getInspectOrgName(), "检验检测机构名称不能为空；", rowError);
            checkNotBlank(data.getInspectConclusion(), "检验结论不能为空；", rowError);
            checkNotBlank(data.getInspectType(), "检验类型不能为空；", rowError);
            checkNotBlank(data.getInspectDate(), "检验日期不能为空；", rowError);
            Optional.ofNullable(data.getInspectDate()).ifPresent(v -> checkDateFormatCorrect(v, "检验日期格式不正确；", rowError));
            checkNotBlank(data.getInspectStaff(), "检验人员名称不能为空；", rowError);
            checkNotBlank(data.getNextInspectDate(), "下次检验日期不能为空；", rowError);
            Optional.ofNullable(data.getNextInspectDate()).ifPresent(v -> checkDateFormatCorrect(v, "下次检验日期格式不正确；", rowError));
            checkNotBlank(data.getInspectReportNo(), "检验报告编号不能为空；", rowError);
            checkNotBlank(data.getUscUnitCreditCode(), "安装单位统一社会信用代码不能为空；", rowError);
            checkNotBlank(data.getUscUnitName(), "安装单位名称不能为空；", rowError);
            // 技术参数
            checkNotBlank(data.getWallThickness(), "公称壁厚不能为空；", rowError);
            Optional.ofNullable(data.getWallThickness()).ifPresent(item -> checkPipeSpecifications(item, "公称壁厚请输入数字或者/分割的范围，如2/6；", rowError));
            checkNotBlank(data.getNominalDiameter(), "公称直径不能为空；", rowError);
            Optional.ofNullable(data.getNominalDiameter()).ifPresent(item -> checkPipeSpecifications(item, "公称直径请输入数字或者/分割的范围，如2/6；", rowError));
            checkNotBlank(data.getPipeLength(), "管道长度不能为空；", rowError);
            Optional.ofNullable(data.getPipeLength()).ifPresent(item -> checkDateFormatNumber(item, "管道长度必须为数字", rowError));
            checkNotBlank(data.getPressure(), "设计-压力不能为空；", rowError);
            checkNotBlank(data.getMedium(), "设计-介质不能为空；", rowError);
            checkNotBlank(data.getTemperature(), "设计-温度不能为空；", rowError);
            checkNotBlank(data.getPipelineNumber(), "管道编号不能为空；", rowError);
            Optional.ofNullable(data.getPipelineNumber()).ifPresent(v -> {
                if (pipelineNumList.contains(v)) {
                    rowError.append("管道编号不能重复");
                } else {
                    pipelineNumList.add(v);
                }
            });
            checkNotBlank(data.getDeviceLevel(), "管道级别不能为空；", rowError);


            // 工业管道校验使用信息
            if (isGYGD) {
                // todo
            }

            // 如果存在错误信息，则抛出 BadRequest 异常
            if (rowError.length() > 0) {
                rowError.insert(0, "Excel第[" + rowIndex + "]行 -> ");
            }

        } catch (Exception e) {
            log.error("行索引数: [{}] -> 失败的 Excel 数据: [{}]", rowIndex, JSON.toJSONString(data), e);
            throw e;
        }
        return rowError;
    }

    /**
     * 管道规格格式校验
     *
     * @param item
     * @param errorMessage
     * @param rowError
     */
    public void checkPipeSpecifications(String item, String errorMessage, StringBuffer rowError) {
        String regex = "^\\d(\\d*[.]?\\d*)([-/]\\d*[.]?\\d*)?$";
        if (!item.matches(regex)) {
            rowError.append(errorMessage);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public Object savePipingData(Map<String, Object> paramMap) {
        // 获取数据
        JSONObject equipInfo = JSON.parseObject(toJSONString(paramMap.get("equipInfo")), JSONObject.class);
        JSONObject attachmentUpload = JSON.parseObject(toJSONString(paramMap.get("attachmentUpload")), JSONObject.class);
        JSONArray equListsJSONArr = JSONArray.parseArray(toJSONString(attachmentUpload.get("equLists")));
        List<PipingExcelDto> equLists = equListsJSONArr.toJavaList(PipingExcelDto.class);
        for (int i = 0; i < equLists.size(); i++) {
            PipingExcelDto equ = equLists.get(i);
            JSONObject equJson = JSON.parseObject(toJSONString(equListsJSONArr.get(i)));
            JSONArray fileDataArray = equJson.getJSONArray("fileData");

            if (fileDataArray == null || fileDataArray.isEmpty()) {
                continue;
            }

            for (Object arr : fileDataArray) {
                JSONObject fileData = JSON.parseObject(toJSONString(arr));
                if (ValidationUtil.isEmpty(fileData) || !"inspectReport".equals(fileData.getString("key"))) {
                    continue;
                }
                JSONArray value = fileData.getJSONArray("value");
                if (value != null) {
                    equ.setInspectReport(value.toJSONString());
                }
            }
        }
        ReginParams reginParams = JSONObject.parseObject(redisUtils.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken())).toString(), ReginParams.class);
        // 监管——历史——管道——批量
        String dataSource = "jg_his_gd_pl";
        // 公共参数提取
        EquipRequestParamsDto paramsDto = this.extractCommonData(dataSource, reginParams, equipInfo, equLists);
        // 是否工业管道
        boolean isGYGD = "8300".equals(paramsDto.getEquCategoryCode());
        boolean haveUseRegistration = false;
        // 确保使用登记证和工程装置在该单位下都是不存在的，方可导入数据
        if (isGYGD) {
            haveUseRegistration = this.checkTheUnitRegManageAlreadyExists(paramsDto, haveUseRegistration);
        }
        this.checkTheUnitProConMatching(paramsDto);
        this.checkTheUnitProConAlreadyExists(paramsDto);
        // 生成工程装置表信息
        IdxBizJgProjectContraption proCon = this.saveProjectContraption(paramsDto);
        // 保存管道对应的idx表数据
        List<String> records = this.savePipInfoToIdxTables(equLists, paramsDto, proCon);
        if (isGYGD) {
            // 生成使用登记表信息 + 设备关系表 + 历史表
            JgUseRegistration useReg = this.saveUseRegAndEq(paramsDto, records, proCon);
            // 生成使用登记证表数据
            if (!haveUseRegistration){
                JgUseRegistrationManage regManage = this.saveUseRegManage(paramsDto, useReg);
                // 流水表
                this.saveCertChangeRecord(useReg, regManage, records, paramsDto);
            }
        }
        return Boolean.TRUE;
    }

    public void saveCertChangeRecord(JgUseRegistration useReg, JgUseRegistrationManage regManage, List<String> records, EquipRequestParamsDto paramsDto) {
        Long changeRecordId = sequence.nextId();
        JgCertificateChangeRecord changeRecord = new JgCertificateChangeRecord()
                .setApplyNo(useReg.getApplyNo())
                .setReceiveOrgName(useReg.getReceiveOrgName())
                .setAuditPassDate(new Date())
                .setRegType(BusinessTypeEnum.JG_USAGE_REGISTRATION.getName())
                .setRegDate(useReg.getCreateDate())
                .setChangeContent(this.buildRecordContent(useReg, paramsDto))
                .setUseRegistrationCode(useReg.getUseRegistrationCode())
                .setReceiveCompanyCode(useReg.getReceiveCompanyOrgCode())
                .setCertificateNo(regManage.getCertificateNo())
                .setUseUnitCreditCode(useReg.getUseUnitCreditCode())
                .setUseUnitName(useReg.getUseUnitName())
                .setEquCategory(paramsDto.getEquCategoryCode())
                .setCreateDate(new Date());
        certificateChangeRecordService.save(changeRecord);
        records.forEach(record -> {
            JgCertificateChangeRecordEq changeRecordEq = new JgCertificateChangeRecordEq();
            changeRecordEq.setChangeRecordId(String.valueOf(changeRecordId));
            changeRecordEq.setEquId(record);
            certificateChangeRecordEqService.save(changeRecordEq);
        });
    }

    public String buildRecordContent(JgUseRegistration useReg, EquipRequestParamsDto paramsDto) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
        return paramsDto.getCompanyName() + "的" + paramsDto.getExecUserName() + "办理了【" + "历史设备登记" + "】，" +
                "单号【" + useReg.getApplyNo() + "】，办理日期" + simpleDateFormat.format(new Date());
    }

    /**
     * 检查本单位是否存在使用登记证编号 + 不能是系统未生成的
     *
     * @param paramsDto 设备请求参数
     */
    public boolean checkTheUnitRegManageAlreadyExists(EquipRequestParamsDto paramsDto, boolean haveUseRegistration) {
        // 1. 判断是否使用未来系统生成编号
        idxBizJgRegisterInfoServiceImpl.checkUseRegistrationCode(paramsDto.getUseOrgCode(), "unit");
        // 2. 获取使用登记管理列表
        List<JgUseRegistration> useRegistrationList = jgUseRegistrationMapper.selectList(
                new LambdaQueryWrapper<JgUseRegistration>()
                        .eq(JgUseRegistration::getUseRegistrationCode, paramsDto.getUseOrgCode())
                        .eq(JgUseRegistration::getIsDelete, 0)
                        .eq(JgUseRegistration::getStatus, "已完成")
                        .orderByDesc(JgUseRegistration::getRecDate)
                        .last("limit 1"));

        if (!useRegistrationList.isEmpty()) {
            if (useRegistrationList.stream().filter(map -> !"1".equals(map.getRegType())).count() > 1) {
                throw new BadRequest("该使用登记证编号已由系统自动生成，不能导入，请确认使用登记证编号是否正确！");
            }
            if (useRegistrationList.stream().anyMatch(map -> !paramsDto.getCompanyCode().equals(map.getUseUnitCreditCode()))) {
                throw new BadRequest("该使用登记证编号在其他企业使用，不能导入，请确认使用登记证编号是否正确！");
            }
            haveUseRegistration = true;
        }
        return haveUseRegistration;
    }

    /**
     * 公共参数提取
     *
     * @param equipInfo
     * @param equLists
     * @return
     */
    public EquipRequestParamsDto extractCommonData(String dataSource, ReginParams reginParams, JSONObject equipInfo, List<PipingExcelDto> equLists) {
        AgencyUserModel userModel = reginParams.getUserModel();
        CompanyBo company = reginParams.getCompany();
        String orgBranchCode = String.valueOf(equipInfo.get("orgBranchCode"));
        String equListCode = String.valueOf(equipInfo.get("EQU_LIST"));
        String equCategoryCode = String.valueOf(equipInfo.get("EQU_CATEGORY"));
        String equDefineCode = String.valueOf(equipInfo.get("EQU_DEFINE"));
        String receiveOrgCode = Optional.ofNullable(equipInfo.get("RECEIVE_ORG_CODE")).map(String::valueOf).orElse(null);
        String inspectUnitCreditCode = Optional.ofNullable(equLists.get(0).getInspectOrgCode()).orElse("");
        String inspectUnitName = Optional.ofNullable(equLists.get(0).getInspectOrgName()).orElse("");
        String useOrgCode = Optional.ofNullable(equipInfo.get("USE_ORG_CODE")).map(String::valueOf).orElse(null);
        String province = String.valueOf(equipInfo.get("province"));
        String city = String.valueOf(equipInfo.get("city"));
        String county = String.valueOf(equipInfo.get("county"));
        String street = String.valueOf(equipInfo.get("street"));
        String address = String.valueOf(equipInfo.get("address"));
        String usePlace = String.valueOf(equipInfo.get("usePlace"));
        return new EquipRequestParamsDto().setCompanyCode(company.getCompanyCode().split("_")[0])
                .setProvince(province)
                .setProvinceName("陕西省")
                .setCity(city)
                .setCityName(this.getRegionName("CITY", "CITY".toLowerCase(), equipInfo))
                .setCounty(county)
                .setCountyName(this.getRegionName("REGION", "COUNTY".toLowerCase(), equipInfo))
                .setStreet(street)
                .setStreetName(this.getRegionName("STREET", "STREET".toLowerCase(), equipInfo))
                .setAddress(address)
                .setUsePlace(usePlace)
                .setCompanyName(company.getCompanyName())
                .setCompanyAddress(company.getAddress())
                .setExecUserId(userModel.getUserId())
                .setExecUserName(userModel.getUserName())
                .setEquListCode(equListCode)
                .setEquListName(EquipmentClassifityEnum.getNameByCode(equListCode))
                .setEquCategoryCode(equCategoryCode)
                .setEquCategoryName(EquCategoryConverter.getKeyByValue(equCategoryCode))
                .setEquDefineCode(equDefineCode).setEquDefineName(EquDefineConverter.getKeyByValue(equDefineCode))
                .setDataSource(dataSource)
                .setOrgBranchCode(orgBranchCode.split("_").length > 1 ? orgBranchCode.split("_")[0] : "")
                .setOrgBranchName(orgBranchCode.split("_").length > 1 ? orgBranchCode.split("_")[1] : "")
                .setUseOrgCode(useOrgCode)
                .setVehicleApanage(String.valueOf(equipInfo.get("VEHICLE_APANAGE")))
                .setReceiveOrgCode(Optional.ofNullable(receiveOrgCode)
                                           .map(code -> code.split("_"))
                                           .filter(parts -> parts.length > 0)
                                           .map(parts -> parts[0])
                                           .orElse(null))
                .setReceiveOrgName(Optional.ofNullable(receiveOrgCode)
                                           .map(code -> code.split("_"))
                                           .filter(parts -> parts.length > 1)
                                           .map(parts -> parts[1])
                                           .orElse(null))
                .setProjectContraption(String.valueOf(equipInfo.get("PROJECT_CONTRAPTION")))
                .setProjectContraptionNo(String.valueOf(equipInfo.get("PROJECT_CONTRAPTION_NO")))
                .setProductPhoto(toJSONString(equipInfo.get("PRODUCT_PHOTO")))
                .setProductQualificationCertificate(toJSONString(equipInfo.get("PRODUCT_QUALIFICATION_CERTIFICATE")))
                .setOtherAccessories(toJSONString(equipInfo.get("OTHER_ACCESSORIES")))
                .setPipelineLength(equLists.stream().mapToDouble(item -> Double.parseDouble(item.getPipeLength())).sum())
                .setInspectUnitCreditCode(inspectUnitCreditCode)
                .setInspectUnitName(inspectUnitName)
                .setEquCode(installationNoticeService.generateEquCode(equListCode, equCategoryCode, equDefineCode, new Date(), receiveOrgCode));
    }

    /**
     * 根据code获取市区县名字
     *
     * @param key     key
     * @param codeKey codeKey
     * @param mapData 表单信息
     * @return name
     */
    private String getRegionName(String key, String codeKey, JSONObject mapData) {
        return Optional.ofNullable((List<LinkedHashMap>) redisUtils.get(key))
                .flatMap(list -> list.stream()
                        .filter(item -> String.valueOf(item.get("regionCode"))
                                .equals(String.valueOf(mapData.get(codeKey))))
                        .map(item -> (String) item.get("regionName"))
                        .findFirst())
                .orElse("");
    }

    /**
     * 检查本单位是否已存在该工程装置
     * 存在则抛出异常
     *
     * @param paramsDto
     */
    public void checkTheUnitProConAlreadyExists(EquipRequestParamsDto paramsDto) {
        Integer count = idxBizJgProjectContraptionService.lambdaQuery().select(IdxBizJgProjectContraption::getPipelineLength).eq(IdxBizJgProjectContraption::getUseUnitCreditCode, paramsDto.getCompanyCode()).eq(IdxBizJgProjectContraption::getUseUnitName, paramsDto.getCompanyName())
                // 限制到设备类别
                .eq(IdxBizJgProjectContraption::getEquCategory, paramsDto.getEquCategoryCode()).eq(IdxBizJgProjectContraption::getIsIntoManagement, Boolean.TRUE).eq(IdxBizJgProjectContraption::getIsDelete, Boolean.FALSE).eq(IdxBizJgProjectContraption::getProjectContraption, paramsDto.getProjectContraption()).eq(IdxBizJgProjectContraption::getProjectContraptionNo, paramsDto.getProjectContraptionNo()).count();
        // 存在数据 名称和编号能一一对应，限制不让导入
        if (count > 0) {
            throw new BadRequest("系统已存在该工程装置！");
        }
    }

    /**
     * 检查本单位下工程装置名称和工程装置编号是不是一一对应的
     * 不对应抛出异常
     *
     * @param paramsDto
     */
    private void checkTheUnitProConMatching(EquipRequestParamsDto paramsDto) {
        Integer existsConflictNum = idxBizJgProjectContraptionService.lambdaQuery().eq(IdxBizJgProjectContraption::getUseUnitCreditCode, paramsDto.getCompanyCode()).eq(IdxBizJgProjectContraption::getUseUnitName, paramsDto.getCompanyName())
                .eq(IdxBizJgProjectContraption::getIsIntoManagement, Boolean.TRUE)
                .eq(IdxBizJgProjectContraption::getIsDelete, Boolean.FALSE)
                .and(wrapper -> wrapper.ne(IdxBizJgProjectContraption::getProjectContraptionNo, paramsDto.getProjectContraptionNo()).eq(IdxBizJgProjectContraption::getProjectContraption, paramsDto.getProjectContraption())
                        .or().eq(IdxBizJgProjectContraption::getProjectContraptionNo, paramsDto.getProjectContraptionNo()).ne(IdxBizJgProjectContraption::getProjectContraption, paramsDto.getProjectContraption())
                )
                .count();
        if (existsConflictNum > 0) {
            throw new BadRequest("工程装置名称或编号与本单位下的已存在的数据冲突！");
        }
    }

    /**
     * 保存管道对应的idx表数据
     *
     * @param equLists
     * @param paramsDto
     */
    public List<String> savePipInfoToIdxTables(List<PipingExcelDto> equLists, EquipRequestParamsDto paramsDto, IdxBizJgProjectContraption proCon) {
        List<String> recordList = new ArrayList<>();
        List<IdxBizJgUseInfo> useInfoList = new ArrayList<>();
        List<IdxBizJgDesignInfo> designInfoList = new ArrayList<>();
        List<IdxBizJgFactoryInfo> factoryInfoList = new ArrayList<>();
        List<IdxBizJgConstructionInfo> constructionInfoList = new ArrayList<>();
        List<IdxBizJgRegisterInfo> registerInfoList = new ArrayList<>();
        List<IdxBizJgSupervisionInfo> supervisionInfoList = new ArrayList<>();
        List<IdxBizJgOtherInfo> otherInfoList = new ArrayList<>();
        List<IdxBizJgTechParamsPipeline> paramsPipelineList = new ArrayList<>();
        List<ESEquipmentCategoryDto> esEquipmentCategoryList = new ArrayList<>();
        List<IdxBizJgInspectionDetectionInfo> inspectionDetectionInfoList = new ArrayList<>();

        for (PipingExcelDto pipeline : equLists) {
            String record = UUID.randomUUID().toString();
            recordList.add(record);
            // 使用信息
            IdxBizJgUseInfo useInfo = JSON.parseObject(toJSONString(pipeline), IdxBizJgUseInfo.class);
            useInfo.setRecord(record);
            useInfo.setSequenceNbr(null);
            useInfo.setRecDate(new Date());
            useInfo.setDataSource(paramsDto.getDataSource());
            useInfo.setIsIntoManagement(Boolean.TRUE);
            useInfo.setEquState(EquimentEnum.ZAIYONG.getCode().toString());
            useInfo.setUseUnitCreditCode(paramsDto.getCompanyCode());
            useInfo.setUseUnitName(paramsDto.getCompanyName());
            useInfo.setProjectContraption(paramsDto.getProjectContraption());
            useInfo.setProjectContraptionId(paramsDto.getProjectContraptionSeq());
            BeanUtils.copyProperties(paramsDto, useInfo);
            useInfoList.add(useInfo);

            // 检验检测信息
            IdxBizJgInspectionDetectionInfo inspectionDetectionInfo = JSON.parseObject(toJSONString(pipeline), IdxBizJgInspectionDetectionInfo.class);
            if (!ValidationUtil.isEmpty(inspectionDetectionInfo)) {
                inspectionDetectionInfo.setRecord(record);
                inspectionDetectionInfo.setRecDate(new Date());
                inspectionDetectionInfo.setSequenceNbr(null);
                if (inspectionDetectionInfo.getNextInspectDate() != null) {
                    inspectionDetectionInfo.setNextInspectDate(DateUtil.parse(DateUtil.format(inspectionDetectionInfo.getNextInspectDate(), DatePattern.NORM_DATE_PATTERN)));
                }
                // dictName -> dictCode
                inspectionDetectionInfo.setInspectType(InspectTypeConverter.dictMap.get(inspectionDetectionInfo.getInspectType()));
                inspectionDetectionInfo.setInspectConclusion(InspectConclusionConverter.dictMap.get(inspectionDetectionInfo.getInspectConclusion()));
                inspectionDetectionInfoList.add(inspectionDetectionInfo);
            }

            // 设计信息
            IdxBizJgDesignInfo designInfo = JSON.parseObject(toJSONString(pipeline), IdxBizJgDesignInfo.class);
            designInfo.setRecord(record);
            designInfo.setRecDate(new Date());
            designInfo.setSequenceNbr(null);
            designInfoList.add(designInfo);

            // 制造信息
            IdxBizJgFactoryInfo factoryInfo = JSON.parseObject(toJSONString(pipeline), IdxBizJgFactoryInfo.class);
            factoryInfo.setRecord(record);
            factoryInfo.setRecDate(new Date());
            factoryInfo.setSequenceNbr(null);
            factoryInfoList.add(factoryInfo);

            // 施工信息
            IdxBizJgConstructionInfo constructionInfo = JSON.parseObject(toJSONString(pipeline), IdxBizJgConstructionInfo.class);
            constructionInfo.setRecord(record);
            constructionInfo.setRecDate(new Date());
            constructionInfo.setSequenceNbr(null);
            constructionInfoList.add(constructionInfo);

            // 注册登记信息
            IdxBizJgRegisterInfo registerInfo = JSON.parseObject(toJSONString(pipeline), IdxBizJgRegisterInfo.class);
            registerInfo.setRecord(record);
            registerInfo.setUseOrgCode(paramsDto.getUseOrgCode());
            registerInfo.setRegisterState("6045");
            registerInfo.setEquCode(paramsDto.getEquCode());
            registerInfo.setEquList(paramsDto.getEquListCode());
            registerInfo.setEquCategory(paramsDto.getEquCategoryCode());
            registerInfo.setEquDefine(paramsDto.getEquDefineCode());
            registerInfo.setRecDate(new Date());
            registerInfo.setSequenceNbr(null);
            registerInfo.setEquCodeType("2");
            registerInfo.setRegisterState(idxBizJgRegisterInfoServiceImpl.getRegCode());
            registerInfo.setEquCode(paramsDto.getEquCode());

            // 监督管理
            IdxBizJgSupervisionInfo supervisionInfo = JSON.parseObject(toJSONString(pipeline), IdxBizJgSupervisionInfo.class);
            supervisionInfo.setRecord(record);
            supervisionInfo.setRecDate(new Date());
            supervisionInfo.setSequenceNbr(null);
            supervisionInfoList.add(supervisionInfo);

            // 其他信息
            IdxBizJgOtherInfo otherInfo = JSON.parseObject(toJSONString(pipeline), IdxBizJgOtherInfo.class);
            otherInfo.setRecord(record);
            otherInfo.setSequenceNbr(null);
            otherInfo.setSupervisoryCode(proCon.getSupervisoryCode());
            otherInfo.setClaimStatus("已认领");
            otherInfo.setRecDate(new Date());
            otherInfoList.add(otherInfo);

            // 管道技术参数
            IdxBizJgTechParamsPipeline pipelineInfo = JSON.parseObject(toJSONString(pipeline), IdxBizJgTechParamsPipeline.class);
            if (!ValidationUtil.isEmpty(pipelineInfo)) {
                pipelineInfo.setRecord(record);
                pipelineInfo.setRecDate(new Date());
                pipelineInfo.setSequenceNbr(null);
                // 字典name -》 字典code
                pipelineInfo.setDeviceLevel(DictParamsConverter.dictMap.get(pipelineInfo.getDeviceLevel()));
                paramsPipelineList.add(pipelineInfo);
            }
            registerInfo.setProductName(pipelineInfo.getPipeName());
            registerInfoList.add(registerInfo);

            // es
            ESEquipmentCategoryDto esEquipmentDto = JSON.parseObject(toJSONString(pipeline), ESEquipmentCategoryDto.class);
            esEquipmentDto.setDATA_SOURCE(paramsDto.getDataSource());
            esEquipmentDto.setREC_DATE(System.currentTimeMillis());
            esEquipmentDto.setSEQUENCE_NBR(record);
            esEquipmentDto.setIS_INTO_MANAGEMENT(Boolean.TRUE);
            esEquipmentDto.setEQU_CATEGORY_CODE(paramsDto.getEquCategoryCode());
            esEquipmentDto.setEQU_CATEGORY(paramsDto.getEquCategoryName());
            esEquipmentDto.setEQU_LIST_CODE(paramsDto.getEquListCode());
            esEquipmentDto.setEQU_LIST(paramsDto.getEquListName());
            esEquipmentDto.setEQU_DEFINE_CODE(paramsDto.getEquDefineCode());
            esEquipmentDto.setEQU_DEFINE(paramsDto.getEquDefineName());
            esEquipmentDto.setSTATUS("已认领");
            esEquipmentDto.setEQU_STATE(EquimentEnum.ZAIYONG.getCode());
            esEquipmentDto.setUSC_UNIT_CREDIT_CODE(pipeline.getUscUnitCreditCode());
            esEquipmentDto.setUSC_UNIT_NAME(pipeline.getUscUnitName());
            esEquipmentDto.setPROJECT_CONTRAPTION(paramsDto.getProjectContraption());
            esEquipmentDto.setPRODUCT_NAME(pipelineInfo.getPipeName());
            esEquipmentDto.setProjectContraptionId(paramsDto.getProjectContraptionSeq());
            esEquipmentDto.setUSE_ORG_CODE(paramsDto.getUseOrgCode());
            esEquipmentDto.setSUPERVISORY_CODE(proCon.getSupervisoryCode());
            esEquipmentDto.setUSE_UNIT_CREDIT_CODE(paramsDto.getCompanyCode());
            esEquipmentDto.setUSE_UNIT_NAME(paramsDto.getCompanyName());
            esEquipmentDto.setADDRESS(paramsDto.getAddress());
            esEquipmentDto.setUSE_PLACE(paramsDto.getProvinceName() + "/" + paramsDto.getCityName() + "/" + paramsDto.getCountyName() + "/" + paramsDto.getStreetName());
            esEquipmentDto.setUSE_PLACE_CODE(paramsDto.getProvince() + "#" + paramsDto.getCity() + "#" + paramsDto.getCounty() + "#" + paramsDto.getStreet());
            esEquipmentDto.setUSE_SITE_CODE(paramsDto.getUsePlace());
            esEquipmentDto.setORG_BRANCH_CODE(paramsDto.getOrgBranchCode());
            esEquipmentDto.setORG_BRANCH_NAME(paramsDto.getOrgBranchName());
            esEquipmentDto.setEQU_STATE(1);
            esEquipmentDto.setEQU_CODE(paramsDto.getEquCode());
            if (inspectionDetectionInfo.getNextInspectDate() != null) {
                esEquipmentDto.setNEXT_INSPECT_DATE(inspectionDetectionInfo.getNextInspectDate().getTime());
            }
            esEquipmentCategoryList.add(esEquipmentDto);
        }
        idxBizJgUseInfoService.saveBatch(useInfoList);
        idxBizJgDesignInfoService.saveBatch(designInfoList);
        idxBizJgConstructionInfoService.saveBatch(constructionInfoList);
        idxBizJgFactoryInfoService.saveBatch(factoryInfoList);
        idxBizJgRegisterInfoServiceImpl.saveBatch(registerInfoList);
        idxBizJgOtherInfoService.saveBatch(otherInfoList);
        idxBizJgSupervisionInfoService.saveBatch(supervisionInfoList);
        iIdxBizJgTechParamsPipelineService.saveBatch(paramsPipelineList);
        idxBizJgInspectionDetectionInfoService.saveBatch(inspectionDetectionInfoList);
        esEquipmentCategory.saveAll(esEquipmentCategoryList);

        return recordList;
    }

    /**
     * 生成使用登记表信息 + 设备关系表 + 历史表
     *
     * @param paramsDto
     */
    public JgUseRegistration saveUseRegAndEq(EquipRequestParamsDto paramsDto, List<String> records, IdxBizJgProjectContraption proCon) {
        ResponseModel<List<String>> listResponseModel = tzsServiceFeignClient.applicationFormCode(ApplicationFormTypeEnum.SYDJ.getCode(), 1);
        String applyNo = listResponseModel.getResult().get(0);
        Long useRegseq = sequence.nextId();
        JgUseRegistration useReg = new JgUseRegistration()
                .setSupervisoryCode(proCon.getSupervisoryCode())
                .setUseUnitCreditCode(paramsDto.getCompanyCode())
                .setUseUnitName(paramsDto.getCompanyName())
                .setApplyNo(applyNo)
                .setAuditStatus(FlowStatusEnum.TO_BE_FINISHED.getName())
                .setStatus(FlowStatusEnum.TO_BE_FINISHED.getName())
                .setReceiveOrgName(paramsDto.getReceiveOrgName())
                .setInspectUnitCreditCode(paramsDto.getInspectUnitCreditCode())
                .setInspectUnitName(paramsDto.getInspectUnitName())
                .setAuditPassDate(new Date()).setRegType("1").setRegDate(new Date())
                .setUseRegistrationCode(paramsDto.getUseOrgCode())
                .setReceiveOrgCode(paramsDto.getReceiveOrgCode())
                .setReceiveCompanyCode(paramsDto.getReceiveOrgCode())
                // .setReceiveCompanyOrgCode()
                .setReceiveOrgName(paramsDto.getReceiveOrgName())
                .setUseAddress("")
                .setManageType("unit")
                .setCreateDate(new Date())
                .setCreateUserId(paramsDto.getExecUserId())
                .setCreateUserName(paramsDto.getExecUserName())
                .setProjectContraptionId(String.valueOf(proCon.getSequenceNbr()))
                .setProjectContraption(paramsDto.getProjectContraption())
                .setRegDate(new Date());
        useReg.setSequenceNbr(useRegseq);
        jgUseRegistrationServiceImpl.save(useReg);

        records.forEach(record -> {
            JgUseRegistrationEq useRegEq = new JgUseRegistrationEq();
            useRegEq.setEquipTransferId(String.valueOf(useReg.getSequenceNbr()));
            useRegEq.setRecDate(new Date());
            useRegEq.setEquId(record);
            useRegEq.setRecUserId(paramsDto.getExecUserId());
            useRegEq.setRecUserName(paramsDto.getExecUserName());
            jgUseRegistrationEqServiceImpl.save(useRegEq);
        });

        JSONObject changeData = getJgUseRegistrationChangeData(paramsDto, records, applyNo);

        JgRegistrationHistory registrationHistory = JgRegistrationHistory.builder()
                .registrationClass("使用登记")
                .changeData(JSON.toJSONString(changeData))
                .status("history")
                .currentDocumentId(String.valueOf(useRegseq))
                .build();
        registrationHistory.setRecDate(new Date());
        registrationHistory.setCreateDate(new Date());
        registrationHistory.setRecUserId(paramsDto.getExecUserId());
        registrationHistory.setCreateUserId(paramsDto.getExecUserId());
        registrationHistory.setRecUserName(paramsDto.getExecUserName());
        jgRegistrationHistoryService.save(registrationHistory);
        return useReg;
    }

    private JSONObject getJgUseRegistrationChangeData(EquipRequestParamsDto paramsDto, List<String> records, String spplyNo) {
        String record = Optional.ofNullable(records.get(0)).orElse("");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("receiveOrgCode", paramsDto.getReceiveOrgCode() + "_" + paramsDto.getReceiveOrgName());
        jsonObject.put("status", FlowStatusEnum.TO_BE_FINISHED.getName());
        jsonObject.put("applyNo", spplyNo);
        jsonObject.remove("submit");
        jsonObject.remove("instanceId");
        if (!ObjectUtils.isEmpty(jsonObject.get("factoryUseSiteStreet"))) {
            jsonObject.put("factoryUseSiteStreet", String.valueOf(Long.valueOf(jsonObject.get("factoryUseSiteStreet").toString())));
        }
        IdxBizJgProjectContraption projectContraption = idxBizJgProjectContraptionService.getById(paramsDto.getProjectContraptionSeq());
        jsonObject.put("pipelineLength", projectContraption.getPipelineLength());
        jsonObject.put("useUnitCreditCode", paramsDto.getCompanyCode());
        jsonObject.put("useUnitName", paramsDto.getCompanyName());
        IdxBizJgConstructionInfo constructionInfo = idxBizJgConstructionInfoService.lambdaQuery().eq(IdxBizJgConstructionInfo::getRecord, record).orderByDesc(IdxBizJgConstructionInfo::getRecDate).one();
        jsonObject.put("uscUnitCreditCode", constructionInfo.getUscUnitCreditCode());
        jsonObject.put("uscUnitName", constructionInfo.getUscUnitName());
        IdxBizJgInspectionDetectionInfo inspectionDetectionInfo = idxBizJgInspectionDetectionInfoService.lambdaQuery().eq(IdxBizJgInspectionDetectionInfo::getRecord, record).orderByDesc(IdxBizJgInspectionDetectionInfo::getRecDate).one();
        JSONObject inspectionDetectionInfoJO = (JSONObject) JSON.toJSON(inspectionDetectionInfo);
        jsonObject.putAll(inspectionDetectionInfoJO);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        jsonObject.put("inspectDate", sdf.format(inspectionDetectionInfo.getInspectDate()));
        jsonObject.put("nextInspectDate", sdf.format(inspectionDetectionInfo.getNextInspectDate()));
        jsonObject.put("orgBranchCode", paramsDto.getOrgBranchCode() + "_" + paramsDto.getOrgBranchName());
        jsonObject.put("projectContraption", projectContraption.getProjectContraption());
        jsonObject.put("projectContraptionNo", projectContraption.getProjectContraptionNo());
        jsonObject.put("equipmentLists", jgUseRegistrationServiceImpl.getBaseMapper().queryForUnitPipelineEquipment(records));
        jsonObject.put("useRegistrationCode", paramsDto.getUseOrgCode());
        // 转化 附件 字段
        this.convertStringToJsonObject(jsonObject, JgUseRegistrationServiceImpl.jsonFields);
        return jsonObject;
    }

    /**
     * 生成使用登记证管理表信息
     *
     * @param paramsDto
     */
    public JgUseRegistrationManage saveUseRegManage(EquipRequestParamsDto paramsDto, JgUseRegistration useReg) {
        Map<String, String> equType = new HashMap<>();
        equType.put("equListCode", paramsDto.getEquCategoryCode());
        equType.put("equCategoryCode", paramsDto.getEquDefineCode());
        JgUseRegistrationManage registrationManage = JgUseRegistrationManage.builder()
                .equListCode(paramsDto.getEquListCode())
                .equList(paramsDto.getEquListName())
                .equCategoryCode(paramsDto.getEquCategoryCode())
                .equCategory(paramsDto.getEquCategoryName())
                .equDefineCode(paramsDto.getEquDefineCode())
                .equDefine(paramsDto.getEquDefineName())
                .useUnitName(paramsDto.getCompanyName())
                .useUnitCreditCode(paramsDto.getCompanyCode())
                .applyNo(useReg.getApplyNo())
                .receiveCompanyCode(paramsDto.getReceiveOrgCode())
                .receiveOrgName(paramsDto.getReceiveOrgName())
                .auditPassDate(new Date())
                .useRegistrationCode(paramsDto.getUseOrgCode())
                .certificateNo(commonService.generateCertificateNo(equType, new Date(), paramsDto.getReceiveOrgCode()))
                .regType(BusinessTypeEnum.JG_HISTORY_USAGE_REGISTRATION.getName())
                .certificateStatus("已登记")
                .regDate(new Date())
                // .equUseAddress()
                .createDate(new Date())
                .createUserId(paramsDto.getExecUserId())
                .useUnitAddress(paramsDto.getCompanyAddress())
                .manageType("unit")
                .isScrap("0")
                .version(1)
                .build();
        jgUseRegistrationManageService.save(registrationManage);
        return registrationManage;
    }

    /**
     * 生成工程装置表信息
     *
     * @param paramsDto
     */
    public IdxBizJgProjectContraption saveProjectContraption(EquipRequestParamsDto paramsDto) {
        Long seq = sequence.nextId();
        IdxBizJgProjectContraption contraption = IdxBizJgProjectContraption.builder()
                .projectContraption(paramsDto.getProjectContraption())
                .projectContraptionNo(paramsDto.getProjectContraptionNo())
                .useUnitCreditCode(paramsDto.getCompanyCode())
                .useUnitName(paramsDto.getCompanyName())
                // .uscUnitCreditCode().uscUnitName()
                .equList(paramsDto.getEquListCode())
                .equListName(paramsDto.getEquListName())
                .equCategory(paramsDto.getEquCategoryCode())
                .equCategoryName(paramsDto.getEquCategoryName())
                .equDefine(paramsDto.getEquDefineCode())
                .equDefineName(paramsDto.getEquDefineName())
                .pipelineLength(paramsDto.getPipelineLength())
                .productPhoto(paramsDto.getProductPhoto())
                .useRegistrationCode(paramsDto.getUseOrgCode())
                .otherAccessories(paramsDto.getOtherAccessories())
                .orgCode(paramsDto.getOrgBranchCode())
                .orgName(paramsDto.getOrgBranchName())
                .productQualificationCertificate(paramsDto.getProductQualificationCertificate())
                .province(paramsDto.getProvince()).provinceName(paramsDto.getProvinceName()).city(paramsDto.getCity()).cityName(paramsDto.getCityName())
                .county(paramsDto.getCounty()).countyName(paramsDto.getCountyName()).street(paramsDto.getStreet()).streetName(paramsDto.getStreetName())
                .address(paramsDto.getAddress())
                .supervisoryCode(idxBizJgRegisterInfoServiceImpl.getSupervisoryCode(paramsDto.getVehicleApanage(), paramsDto.getEquCategoryCode())).isIntoManagement(Boolean.TRUE).dataSource(paramsDto.getDataSource()).equCode(paramsDto.getEquCode()).isFirstMerge(Boolean.FALSE).build();
        contraption.setSequenceNbr(seq);
        paramsDto.setProjectContraptionSeq(String.valueOf(seq));
        idxBizJgProjectContraptionService.save(contraption);
        return contraption;
    }

    public void convertStringToJsonObject(Object obj, String[] jsonFields) {
        if (obj instanceof JSONObject) {
            JSONObject jsonObject = (JSONObject) obj;
            for (String field : jsonFields) {
                if (jsonObject.get(field) != null && jsonObject.get(field) instanceof String) {
                    jsonObject.put(field, JSON.parse(JSONObject.toJSONString(jsonObject.get(field))));
                }
            }
        } else if (obj instanceof Map) {
            Map<String, Object> map = (Map<String, Object>) obj;
            for (String field : jsonFields) {
                if (map.containsKey(field) && map.get(field) instanceof String) {
                    map.put(field, JSON.parse(JSONObject.toJSONString(map.get(field))));
                }
            }
        } else {
            // 处理其他类型
            System.out.println("Unsupported Object Type");
        }
    }
}
