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

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.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.dto.EquipInfoExcelDto;
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.EquipmentClassifityEnum;
import com.yeejoin.amos.boot.module.ymt.api.mapper.CategoryOtherInfoMapper;
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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;
import org.typroject.tyboot.core.restful.exception.instance.BadRequest;

import java.io.InputStream;
import java.sql.Timestamp;
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 IIdxBizJgTechParamsRidesService iIdxBizJgTechParamsRidesService;
    private final IIdxBizJgTechParamsRopewayService iIdxBizJgTechParamsRopewayService;
    private final IIdxBizJgTechParamsElevatorService iIdxBizJgTechParamsElevatorService;
    private final IdxBizJgProjectContraptionServiceImpl idxBizJgProjectContraptionServiceImpl;
    private final TransactionTemplate transactionTemplate;
    private final CommonServiceImpl commonService;

    private final Map<String, Object> resultError = new HashMap<>();
    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;
    }

    private 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());
        }
    }

    /**
     * 保存工程装置表信息
     */
    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)
                        .one();

                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(EquipmentClassifityEnum.getNameByCode((String) equ.get("equCategory")));
                    projectContraption.setEquDefine((String) equ.get("equDefine"));
                    projectContraption.setEquDefineName(EquipmentClassifityEnum.getNameByCode((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) {
        IdxBizJgUseInfo useInfo = JSON.parseObject(JSON.toJSONString(equ), IdxBizJgUseInfo.class);
        if (!ValidationUtil.isEmpty(useInfo)) {
            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) {
        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) {
        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) {
        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");
            }
            idxBizJgRegisterInfoServiceImpl.save(registerInfo);
        }
    }

    /**
     * 保存监督管理信息表
     *
     * @param equ
     * @param record
     */
    private void saveSupervisionInfo(Map<String, Object> equ, String record) {
        IdxBizJgSupervisionInfo supervisionInfo = JSON.parseObject(JSON.toJSONString(equ), IdxBizJgSupervisionInfo.class);
        if (!ValidationUtil.isEmpty(supervisionInfo)) {
            supervisionInfo.setRecord(record);
            supervisionInfo.setRecDate(new Date());
            idxBizJgSupervisionInfoService.save(supervisionInfo);
        }
    }

    /**
     * 保存其他信息表
     *
     * @param equ
     * @param record
     */
    private void saveOtherInfo(Map<String, Object> equ, String record, String equList) {
        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) {
        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) {
        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) {
        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) {
        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) {
        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) {
        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) {
        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) {
        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)
    @GlobalTransactional(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);
                        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 (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)
                        .one();
                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 (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) {
            if (ValidationUtil.isEmpty(data.getDesignUnitCreditCode()) || ValidationUtil.isEmpty(data.getDesignUnitName()) || ValidationUtil.isEmpty(data.getDesignUseDate()) || ValidationUtil.isEmpty(data.getDesignDate())) {
                data.setDesignIsComplete("2");
            } else {
                data.setDesignIsComplete("1");
            }
            // 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));
            // checkNotBlank(data.getDesignDate(), "设计日期不能为空；", rowError);
            Optional.ofNullable(data.getDesignDate()).ifPresent(v -> checkDateFormatCorrect(v, "设计日期格式不正确；", rowError));
            Optional.ofNullable(data.getAppraisalDate()).ifPresent(v -> checkDateFormatCorrect(v, "设计文件鉴定日期格式不正确；", rowError));

        }
        // 制造信息
        if (!isYLGD) {
            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");
            }
            // 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);
            Optional.ofNullable(data.getProduceDate()).ifPresent(v -> checkDateFormatCorrect(v, "制造日期格式不正确；", rowError));
        }
    }

    /**
     * 检查上传Excel中的日期格式是否正确
     *
     * @param date         待检查数据
     * @param errorMessage 错误内容
     * @param rowError     错误集
     */
    private void checkDateFormatCorrect(String date, String errorMessage, StringBuffer rowError) {
        if (!date.matches("\\d{4}-\\d{2}-\\d{2}")) {
            rowError.append(errorMessage);
        }
    }

    /**
     * 检查上传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 (!org.apache.commons.lang3.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();

        // 梯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);


        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;
    }


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

    /**
     * 批量异步保存设备数据
     *
     * @param equipInfoExcelDtos
     */
    public void batchSaveEquipmentData(String remark, List<EquipInfoExcelDto> equipInfoExcelDtos) {
        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("数据上传，保存设备数据失败！");
            }
        }
    }
}
