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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
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.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yeejoin.amos.boot.biz.common.annotation.TechnicalParameter;
import com.yeejoin.amos.boot.biz.common.dao.mapper.DataDictionaryMapper;
import com.yeejoin.amos.boot.biz.common.dto.ByteArrayMultipartFile;
import com.yeejoin.amos.boot.biz.common.entity.BaseEntity;
import com.yeejoin.amos.boot.biz.common.entity.DataDictionary;
import com.yeejoin.amos.boot.biz.common.excel.ExcelUtil;
import com.yeejoin.amos.boot.biz.common.service.impl.DataDictionaryServiceImpl;
import com.yeejoin.amos.boot.biz.common.utils.DateUtils;
import com.yeejoin.amos.boot.biz.common.utils.RequestContextWrapper;
import com.yeejoin.amos.boot.module.common.api.dao.EsEquipmentDao;
import com.yeejoin.amos.boot.module.common.api.dto.ESEquipmentCategoryDto;
import com.yeejoin.amos.boot.module.common.api.dto.TechParamItem;
import com.yeejoin.amos.boot.module.common.api.entity.ESEquipmentInfo;
import com.yeejoin.amos.boot.module.common.api.enums.StatisticalAnalysisEnum;
import com.yeejoin.amos.boot.module.common.api.enums.UnitTypeNewEnum;
import com.yeejoin.amos.boot.module.common.biz.service.impl.EsSearchServiceImpl;
import com.yeejoin.amos.boot.module.common.biz.service.impl.TZSCommonServiceImpl;
import com.yeejoin.amos.boot.module.common.biz.utils.TechParamUtil;
import com.yeejoin.amos.boot.module.statistcs.biz.utils.JsonUtils;
import com.yeejoin.amos.boot.module.statistcs.biz.utils.MinioUtils;
import com.yeejoin.amos.boot.module.statistcs.biz.utils.QueryBuilderUtils;
import com.yeejoin.amos.boot.module.statistcs.factory.DynamicQueryBuilder;
import com.yeejoin.amos.boot.module.statistcs.factory.EnhancedDynamicQueryBuilder;
import com.yeejoin.amos.boot.module.statistics.api.enums.*;
import com.yeejoin.amos.boot.module.statistics.api.mapper.CommonBaseMapper;
import com.yeejoin.amos.boot.module.statistics.api.mapper.TzsCustomFilterMapper;
import com.yeejoin.amos.boot.module.statistics.api.vo.CompanyInfoVo;
import com.yeejoin.amos.boot.module.statistics.api.vo.EquipInfoVo;
import com.yeejoin.amos.boot.module.statistics.api.vo.PersonVo;
import com.yeejoin.amos.boot.module.ymt.api.dto.EquipmentCategoryDto;
import com.yeejoin.amos.boot.module.ymt.api.entity.IdxBizJgUseInfo;
import com.yeejoin.amos.boot.module.ymt.api.entity.TzBaseEnterpriseInfo;
import com.yeejoin.amos.boot.module.ymt.api.entity.TzsUserInfo;
import com.yeejoin.amos.boot.module.ymt.api.enums.EquipmentClassifityEnum;
import com.yeejoin.amos.boot.module.ymt.api.mapper.EquipmentCategoryMapper;
import com.yeejoin.amos.boot.module.ymt.api.mapper.IdxBizJgUseInfoMapper;
import com.yeejoin.amos.boot.module.ymt.api.mapper.TzBaseEnterpriseInfoMapper;
import com.yeejoin.amos.boot.module.ymt.api.mapper.TzsUserInfoMapper;
import com.yeejoin.amos.feign.systemctl.Systemctl;
import com.yeejoin.amos.feign.systemctl.model.DictionarieValueModel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.client.core.CountResponse;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.ParsedSum;
import org.elasticsearch.search.aggregations.metrics.SumAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;
import org.typroject.tyboot.component.emq.EmqKeeper;
import org.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.foundation.exception.BaseException;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;

import static com.yeejoin.amos.boot.module.common.biz.service.impl.TZSCommonServiceImpl.*;
import static org.elasticsearch.index.query.QueryBuilders.existsQuery;

/**
 * 综合统计分析服务实现类
 *
 * @author system_generator
 * @date 2025-06-24
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class ComprehensiveStatisticalAnalysisServiceImpl {

    @Value("classpath:/json/equipCategory.json")
    private Resource equipCategory;

    @Value("classpath:/json/unitTypeLimitUserType.json")
    private Resource unitTypeLimitUserType;

    private final TzsCustomFilterMapper tzsCustomFilterMapper;
    private final DataDictionaryServiceImpl dataDictionaryService;
    private final DataDictionaryMapper dataDictionaryMapper;
    private final EmqKeeper emqKeeper;
    private final TZSCommonServiceImpl tzsCommonService;

    private final RestHighLevelClient restHighLevelClient;
    private final String DOWN_LOAD_START_TEMP = "{\"id\":\"%s\",\"status\":\"starting\",\"fileName\":\"%s\",\"time\":\"%s\"}";
    private final String DOWNLOAD_TOPIC = "/topic/download/excel/%s";
    private final String BUCKET_NAME = "upload";
    private final String UPLOAD_PATH = "/tzs/excelTempFile";
    private final List<String> equList = Arrays.asList("1000", "2000", "3000", "4000", "5000", "6000", "8000", "9000");
    // 大屏统计图片路径前缀
    private final String dpEquipPhotoPrefix = "/upload/tzs/dpscreen/statistic/equip/";
    // 大屏统计图片路径后缀
    private final String dpEquipPhotoSuffix = ".png";

    private final List<String> equipHandleOtherFields = Arrays.asList("techParam", "paramRange", "JDJY", "DQJY", "SCJY", "DTJY", "QZ_OR_TANK", "EQU_STATE", "NEXT_INSPECT_DATE", "registerStatus");
    private final List<String> companyHandleOtherFields = Arrays.asList("itemCode", "subItemCode", "permitStatus", "equipCategory", "regulatoryLabels", "unitType", "expiryDate");
    private final List<String> personHandleOtherFields = Arrays.asList("newPost", "subPost", "certNo", "expiryDate", "certType", "permissionLevel", "jobItem", "permissionItem", "issueDate", "equipType");

    private final String or = "or";
    private final String and = "and";

    private final EsEquipmentDao esEquipmentDao;

    private final IdxBizJgUseInfoMapper idxBizJgUseInfoMapper;
    private final TzBaseEnterpriseInfoMapper tzBaseEnterpriseInfoMapper;
    private final TzsUserInfoMapper tzsUserInfoMapper;
    private final CommonBaseMapper commonMapper;

    private final ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    private final EsSearchServiceImpl esSearchService;

    @Autowired
    EquipmentCategoryMapper equipmentCategoryMapper;

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");


    public List<Map<String, Object>> queryEquipmentCategory(String key) {
        List<Map<String, Object>> list;
        Map<String, List<Map<String, Object>>> resourceJson = JsonUtils.getResourceJson(equipCategory);
        if (key == null) {
            list = resourceJson.get(EquipmentClassifityEnum.ZHTJFX.getCode());
        } else {
            list = tzsCustomFilterMapper.selectEquipmentCategoryByParentId(key);
        }

        return list;
    }

    public JSONArray queryEquipmentSearchData(JSONObject jsonObject) {
        String equList = jsonObject.getString("EQU_LIST");
        String equCategory = "all".equals(jsonObject.getString("EQU_CATEGORY")) ? null : jsonObject.getString("EQU_CATEGORY");
        String equDefine = "all".equals(jsonObject.getString("EQU_DEFINE")) ? null : jsonObject.getString("EQU_DEFINE");
        String vehicleCylinder = "1".equals(jsonObject.getString("WHETHER_VEHICLE_CYLINDER")) ? "vehicleCylinder" : null;
        List<TechParamItem> paramMetaList = new ArrayList<>();
        if (vehicleCylinder != null) {
            paramMetaList = TechParamUtil.getParamMetaList(equList, equCategory, equDefine, vehicleCylinder);
        } else {
            paramMetaList = TechParamUtil.getParamMetaList(equList, equCategory, equDefine);
        }
        JSONArray list = new JSONArray();
        for (int i = 0; i < paramMetaList.size(); i++) {
            JSONObject object = new JSONObject();
            object.put("key", paramMetaList.get(i).getParamKey());
            object.put("value", paramMetaList.get(i).getParamKey());
            object.put("label", paramMetaList.get(i).getParamLabel());
            object.put("unit", paramMetaList.get(i).getUnit());
            JSONObject skillConfig = new JSONObject();
            skillConfig.put("conditions", getConditionList(paramMetaList.get(i).getParamType(), paramMetaList.get(i).getDictCode()));
            if (!ValidationUtil.isEmpty(paramMetaList.get(i).getDictCode())) {
                skillConfig.put("type", "select");
                skillConfig.put("data", getData(paramMetaList.get(i).getDictCode()));
            } else if (TechnicalParameter.ParamType.BIG_DECIMAL.equals(paramMetaList.get(i).getParamType())) {
                skillConfig.put("type", "inputNumber");
            } else if (TechnicalParameter.ParamType.STRING.equals(paramMetaList.get(i).getParamType())) {
                skillConfig.put("type", "input");
            } else if (TechnicalParameter.ParamType.DATE.equals(paramMetaList.get(i).getParamType())) {
                skillConfig.put("type", "date");
            }
            skillConfig.put("fieldType", paramMetaList.get(i).getParamType());
            skillConfig.put("isMulti", false);
            object.put("skillConfig", skillConfig);
            list.add(object);
        }
        return list;
    }

    public JSONArray getData(String dictCode) {
        JSONArray jsonArray = new JSONArray();
        //根据dictCode查询数据字典
        if (dictCode.contains(",")) {
            for (String code : dictCode.split(",")) {
                LambdaQueryWrapper<DataDictionary> queryWrapper = new LambdaQueryWrapper();
                queryWrapper.eq(DataDictionary::getType, code);
                queryWrapper.eq(DataDictionary::getIsDelete, Boolean.FALSE);
                queryWrapper.isNotNull(DataDictionary::getParent);
                List<DataDictionary> dictionaries = dataDictionaryMapper.selectList(queryWrapper);
                for (DataDictionary dictionary : dictionaries) {
                    JSONObject object = new JSONObject();
                    object.put("label", dictionary.getName());
                    object.put("value", dictionary.getCode());
                    object.put("key", dictionary.getCode());
                    jsonArray.add(object);
                }
            }
        } else {
            List<DataDictionary> dictionaries = dataDictionaryService.getByType(dictCode);
            for (DataDictionary dictionary : dictionaries) {
                JSONObject object = new JSONObject();
                object.put("label", dictionary.getName());
                object.put("value", dictionary.getCode());
                object.put("key", dictionary.getCode());
                jsonArray.add(object);
            }
        }

        return jsonArray;
    }

    public JSONArray queryDicDataNew(String dictCode) {
        JSONArray jsonArray = new JSONArray();
        //根据dictCode查询数据字典
        List<DataDictionary> dictionaries = dataDictionaryService.getByType(dictCode);
        for (DataDictionary dictionary : dictionaries) {
            JSONObject object = new JSONObject();
            object.put("label", dictionary.getName());
            object.put("value", dictionary.getName());
            object.put("key", dictionary.getCode());
            jsonArray.add(object);
        }
        return jsonArray;
    }

    private JSONArray getConditionList(TechnicalParameter.ParamType value, String dictCode) {
        return ConditionEnum.getByCode(ValidationUtil.isEmpty(dictCode) ? value : null);
    }

    public JSONArray queryAdvancedSearch(String type) {
        JSONArray all = new JSONArray();
        if ("equip".equals(type)) {
            all = EquipAdvanceSearchEnum.getAll();
        } else if ("company".equals(type)) {
            all = CompanyAdvanceSearchEnum.getAll();
        } else if ("person".equals(type)) {
            all = PersonAdvanceSearchEnum.getAll();
        }
        return all;
    }

    public JSONObject queryForPage(JSONObject filter) {
        JSONObject result = new JSONObject();
        Integer current = ObjectUtils.isEmpty(filter.getInteger("current")) ? 1 : filter.getInteger("current");
        Integer size = ObjectUtils.isEmpty(filter.getInteger("size")) ? 20 : filter.getInteger("size");

        Page<JSONObject> page = new Page<>(current, size);
        String businessType = filter.getString("businessType");
        if (ObjectUtils.isEmpty(businessType)) {
            JSONObject statics = new JSONObject();
            statics.put("totalCount", null);
            result.put("statics", statics);
            page.setRecords(new ArrayList<>());
            page.setTotal(0);
            result.put("pageData", page);
            result.put("businessType", businessType);
            return result;
        }
        if (StatisticalAnalysisEnum.equip.getCode().equals(businessType)) {
            result = queryEquipmentPage(filter, page, current, size);
        } else if (StatisticalAnalysisEnum.company.getCode().equals(businessType)) {
            result = queryCompanyPage(filter, page, current, size);
        } else {
            result = queryPersonPage(filter, page, current, size);
        }
        result.put("businessType", businessType);
        return result;
    }

    private JSONObject queryPersonPage(JSONObject filter, Page<JSONObject> page, Integer current, Integer size) {

        JSONObject result = new JSONObject();

        SearchRequest request = new SearchRequest();
        request.indices(StatisticalAnalysisEnum.person.getKey());
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.trackTotalHits(true);
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
        JSONObject filterParams = null;
        String licensesStatusStr = "";
        String filterType = filter.getString("filterType");

        if (!ObjectUtils.isEmpty(filter.get("filterParams"))) {
            filterParams = JSONObject.parseObject(JSONObject.toJSONString(filter.get("filterParams")));
            if (filterParams.containsKey("dp_filter_business_type")) {
                String businessType = filterParams.getString("dp_filter_business_type");
                if (StatisticalAnalysisEnum.person.getCode().equals(businessType)) {
                    companyBoolMust(boolMust, "company");
                } else if (StatisticalAnalysisEnum.inspectionPerson.getCode().equals(businessType)) {
                    companyBoolMust(boolMust, "inspection");
                    boolMust.mustNot(QueryBuilders.wildcardQuery("unitType.keyword", "*检验检测机构*"));
                }
            }
            // 组装人员过滤条件
            String orgCode = filter.getString("orgCode");
            personOrgCodeBoolMust(orgCode, boolMust, StatisticalAnalysisEnum.person.getCode());
            this.getPersonBoolQueryBuilder(filterParams, boolMust, filterType);
            if ("custom".equals(filterType)) {
                JSONArray leftGroup = filterParams.getJSONArray("group1");
                JSONArray rightGroup = filterParams.getJSONArray("group2");
                licensesStatusStr = getFilterPermitStatusOrLicensesStatus(leftGroup, rightGroup, StatisticalAnalysisEnum.person.getCode());
            } else {
                // 资质判断
                if (filterParams.containsKey("expiryDate")) {
                    Object permitStatus = filterParams.get("expiryDate");
                    if (permitStatus instanceof JSONArray) {
                        JSONArray jsonArray = (JSONArray) permitStatus;
                        if (!ObjectUtils.isEmpty(jsonArray) && !jsonArray.contains("all") && jsonArray.size() == 1) {
                            licensesStatusStr = jsonArray.get(0).toString();
                        }
                    }
                }
                if (filterParams.containsKey("certNo") && filterParams.getJSONArray("certNo").size() == 1 && "0".equals(filterParams.getJSONArray("certNo").get(0).toString())) {
                    licensesStatusStr = noLicenseReq;
                }
            }
        }

        // 组装人员排序条件
        this.getPersonBoolQuerySort(filter, builder);

        builder.query(boolMust);
        builder.from((current - 1) * size);
        builder.size(size);
        request.source(builder);

        List<JSONObject> list = new LinkedList<>();
        long totle = 0;
        try {
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            for (SearchHit hit : response.getHits().getHits()) {
                JSONObject jsonObject = (JSONObject) JSONObject.toJSON(hit);
                JSONObject dto = jsonObject.getJSONObject("sourceAsMap");
                if (dto.containsKey("identification") && !ObjectUtils.isEmpty(dto.get("identification"))) {
                    JSONArray jsonArray = JSONObject.parseArray(dto.get("identification").toString());
                    if (!ObjectUtils.isEmpty(jsonArray)) {
                        dto.put("identification", JSONObject.parseObject(JSONObject.parseArray(dto.get("identification").toString()).get(0).toString()).get("url"));
                    }
                }
                if (dto.containsKey("equipType")) {
                    String[] equipCodes = dto.get("equipType").toString().split(",");
                    StringBuilder equipTypes = new StringBuilder();
                    for (String equipType : equipCodes) {
                        equipTypes.append(EquipmentClassifityEnum.getNameByCode(equipType) + ",");
                    }
                    dto.put("equipType", equipTypes.substring(0, equipTypes.length() - 1));
                }
                dto.put("licensesStatus", tzsCommonService.getLicensesStatusWithEsUserInfo(dto, licensesStatusStr));
                list.add(dto);
            }
            totle = Objects.requireNonNull(response.getInternalResponse().hits().getTotalHits()).value;
            page.setRecords(list);
            page.setTotal(totle);
            result.put("pageData", page);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        List<Map<String, Object>> statics = new ArrayList<>();
        Map<String, Object> sum = new HashMap<>();
        sum.put("name", "人员总数（人）");
        sum.put("value", totle);
        statics.add(sum);
        result.put("statics", statics);

        // 获取许可状态统计
        List<Map<String, Object>> staticMap = new ArrayList<>();
        if (!"".equals(licensesStatusStr)) {
            getFilterCompanyOrPersonPermitStatusStatic(staticMap, StatisticalAnalysisEnum.person.getKey(), licensesStatusStr, totle);
        } else {
            getCompanyOrPersonPermitStatusStatic(boolMust, staticMap, StatisticalAnalysisEnum.person.getKey());
        }
        result.put("keyIndicator", staticMap);
        return result;
    }

    public void personOrgCodeBoolMust(String orgCode, BoolQueryBuilder boolMust, String type) {
        String superviseOrgCodeKey = type.equals(StatisticalAnalysisEnum.person.getCode()) ? "superviseOrgCode" : "superviseOrgCode.keyword";
        String officeRegion = commonMapper.getCompanyCodeByOrgCode(orgCode);
        BoolQueryBuilder queryBuilder1 = QueryBuilders.boolQuery();
        BoolQueryBuilder queryBuilder2 = QueryBuilders.boolQuery();
        EnhancedDynamicQueryBuilder enhancedDynamicQueryBuilder = new EnhancedDynamicQueryBuilder();
        queryBuilder1.must(QueryBuilders.termQuery(superviseOrgCodeKey, "50"))
                .must(QueryBuilders.wildcardQuery("officeRegion", "*" + officeRegion + "*"));
        queryBuilder2.mustNot(QueryBuilders.termQuery(superviseOrgCodeKey, "50"))
                .must(QueryBuilders.prefixQuery(superviseOrgCodeKey, orgCode));
        enhancedDynamicQueryBuilder.add(queryBuilder1, or);
        enhancedDynamicQueryBuilder.add(queryBuilder2, or);
        boolMust.must(enhancedDynamicQueryBuilder.build());
    }

    /**
     * 组装人员过滤条件
     */
    private void getPersonBoolQueryBuilder(JSONObject filterParams, BoolQueryBuilder boolMust, String filterType) {
        deleteUnitCategory(filterParams);
        // 快捷筛选和自定义筛选解析筛选规则不一致
        if (filterType.equals("advanced")) {
            filterParams.forEach((k, v) -> {
                if (v instanceof JSONArray) {
                    if (!((JSONArray) v).contains("all") && ((JSONArray) v).size() > 0) {
                        String field = k;
                        if (k.equals("newPost") || k.equals("subPost") || k.equals("equipType")) {
                            DynamicQueryBuilder dynamicQueryBuilder = new DynamicQueryBuilder();
                            EnhancedDynamicQueryBuilder enhancedDynamicQueryBuilder = new EnhancedDynamicQueryBuilder();
                            ((JSONArray) v).forEach(item -> enhancedDynamicQueryBuilder.add(QueryBuilders.wildcardQuery(field, "*" + item + "*"), or));
                            dynamicQueryBuilder.and(enhancedDynamicQueryBuilder.build().minimumShouldMatch(1));
                            boolMust.must(dynamicQueryBuilder.build());
                        } else if (k.equals("unitType")) {
                            DynamicQueryBuilder dynamicQueryBuilder = new DynamicQueryBuilder();
                            EnhancedDynamicQueryBuilder enhancedDynamicQueryBuilder = new EnhancedDynamicQueryBuilder();
                            ((JSONArray) v).forEach(item ->
                                    enhancedDynamicQueryBuilder.add(QueryBuilders.wildcardQuery(field + ".keyword", "*" + item + "*"), or));
                            dynamicQueryBuilder.and(enhancedDynamicQueryBuilder.build().minimumShouldMatch(1));
                            boolMust.must(dynamicQueryBuilder.build());
                        } else if (k.equals("education")) {
                            TermsQueryBuilder termsQuery = QueryBuilders.termsQuery(field, (JSONArray) v);
                            boolMust.must(termsQuery);
                        } else if (k.equals("certNo") || k.equals("expiryDate") || k.equals("permissionLevel") || k.equals("certType") || k.equals("jobItem") || k.equals("permissionItem")) {
                            String path = "licenses";
                            EnhancedDynamicQueryBuilder licencesQueryBuilder = new EnhancedDynamicQueryBuilder();
                            ((JSONArray) v).forEach(item -> {
                                String nestedField = path + "." + k;
                                // 根据证书编号判断有无资质
                                if (k.equals("certNo")) {
                                    NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                            path,
                                            existsQuery(nestedField),
                                            ScoreMode.None
                                    );
                                    // ***********************************************************************************************************************************
                                    // 注意 ： 若要修改下面的【无资质】和【无资质要求】逻辑，请同步修改 tzsCommonService.buildExpiryDateQueryBuilder()方法中的后半部分 ***************
                                    // ***********************************************************************************************************************************

                                    // 以下人员类型有资质要求
                                    // 人员类型(newPost)：检验人员：66151、检测人员：66152、作业人员：6552、检查人员：6763、检验检测区域负责人：6667
                                    // 人员子类型(subPost)： 持证人员:6713、持证人员(P):6764、持证人员(R2):6765
                                    if (item.equals("1")) {
                                        licencesQueryBuilder.add(nestedQuery, or);
                                    } else if (item.equals("0")) {
                                        // 无资质
                                        DynamicQueryBuilder queryBuilder = new DynamicQueryBuilder();
                                        queryBuilder.and(tzsCommonService.getNotLicencesBuilderWithPerson());
                                        queryBuilder.and(QueryBuilders.boolQuery().mustNot(nestedQuery));
                                        licencesQueryBuilder.add(queryBuilder.build(), or);
                                    } else {
                                        // 无资质要求
                                        licencesQueryBuilder.add(tzsCommonService.getNotNeedLicencesBuilderWithPerson(), or);
                                    }
                                } else if (k.equals("expiryDate")) {
                                    // 无有效期 / 资质正常 / 资质临期 / 资质超期
                                    tzsCommonService.buildExpiryDateQueryBuilder(boolMust, item.toString(), path, nestedField);
                                } else if (k.equals("certType") || k.equals("permissionLevel")) {
                                    NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                            path,
                                            QueryBuilders.termsQuery(nestedField, (JSONArray) v),
                                            ScoreMode.None
                                    );
                                    boolMust.must(nestedQuery);
                                } else {
                                    NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                            path,
                                            QueryBuilders.boolQuery().must(QueryBuilders.wildcardQuery(nestedField, "*" + item + "*")),
                                            ScoreMode.None
                                    );
                                    boolMust.must(nestedQuery);
                                }
                            });
                            boolMust.must(licencesQueryBuilder.build());
                        } else if (k.equals("issueDate")) {
                            JSONArray issueDates = (JSONArray) v;
                            Date startDate = issueDates.getDate(0);
                            Date endDate = issueDates.getDate(1);
                            if (!"".equals(startDate) && !"".equals(endDate) && !ObjectUtils.isEmpty(startDate) && !ObjectUtils.isEmpty(endDate)) {
                                String startDateString = DateUtils.convertDateToString(startDate, DateUtils.DATE_PATTERN);
                                String endDateString = DateUtils.convertDateToString(endDate, DateUtils.DATE_PATTERN);
                                NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                        "licenses",
                                        QueryBuilders.rangeQuery("licenses." + k).gte(startDateString).lte(endDateString),
                                        ScoreMode.None
                                );
                                boolMust.filter(nestedQuery);
                            }
                        }
                    }
                } else if (v instanceof String) {
                    if (k.equals("fuzzyInput")) {
                        String fuzzyValue = String.valueOf(v);
                        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
                        queryBuilder.should(QueryBuilders.wildcardQuery("name", "*" + fuzzyValue + "*"));
                        queryBuilder.should(QueryBuilders.wildcardQuery("postName.keyword", "*" + fuzzyValue + "*"));
                        queryBuilder.should(QueryBuilders.wildcardQuery("subPostName.keyword", "*" + fuzzyValue + "*"));
                        queryBuilder.should(QueryBuilders.wildcardQuery("unitName", "*" + fuzzyValue + "*"));
                        queryBuilder.should(QueryBuilders.wildcardQuery("equipTypeName.keyword", "*" + fuzzyValue + "*"));
                        queryBuilder.should(QueryBuilders.wildcardQuery("superviseOrgName.keyword", "*" + fuzzyValue + "*"));
                        queryBuilder.should(QueryBuilders.wildcardQuery("address", "*" + fuzzyValue + "*"));
                        queryBuilder.minimumShouldMatch(1);
                        boolMust.must(queryBuilder);
                    } else if (k.equals("unitCategory")) {
                        if (!"".equals(v) && !ObjectUtils.isEmpty(v) && !"all".equals(v)) {
                            String category = v.toString();
                            JSONArray unitTypeByType = UnitTypeNewEnum.getUnitTypeByType(category);
                            List<String> list = unitTypeByType.stream().map(e -> JSONObject.parseObject(JSONObject.toJSONString(e)).get("value").toString()).collect(Collectors.toList());
                            list.forEach(item -> boolMust.should(QueryBuilders.wildcardQuery("unitType.keyword", "*" + item + "*")).minimumShouldMatch(1));
                        }
                    }
                }
            });
        } else {
            JSONArray leftGroup = filterParams.getJSONArray("group1");
            JSONArray rightGroup = filterParams.getJSONArray("group2");
            Boolean isOrGroup = or.equals(filterParams.getString("groupAndOr")) ? Boolean.TRUE : Boolean.FALSE;
            handleAdvancedFilter(boolMust, leftGroup, rightGroup, isOrGroup, StatisticalAnalysisEnum.person.getCode());
        }
    }

    /**
     * 组装人员排序
     */
    private void getPersonBoolQuerySort(JSONObject filter, SearchSourceBuilder builder) {
        // 排序
        if (!ObjectUtils.isEmpty(filter.get("sort"))) {
            JSONObject sort = JSONObject.parseObject(JSONObject.toJSONString(filter.get("sort")));
            String field = sort.getString("field");
            if (field.equals("subPostName")) {
                field = "subPost";
            } else if (field.equals("postName")) {
                field = "newPost";
            } else if (field.equals("superviseOrgName")) {
                field = "superviseOrgCode";
            } else if (field.equals("licensesStauts")) {
                field = "licenseMinExpiryDate";
            }
            builder.sort(field, sort.getString("order").equals("desc") ? SortOrder.DESC : SortOrder.ASC);
        }
    }

    private JSONObject queryCompanyPage(JSONObject filter, Page<JSONObject> page, Integer current, Integer size) {

        JSONObject result = new JSONObject();

        SearchRequest request = new SearchRequest();
        request.indices(StatisticalAnalysisEnum.company.getKey());
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.trackTotalHits(true);
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();

        String orgCode = filter.getString("orgCode");
        personOrgCodeBoolMust(orgCode, boolMust, StatisticalAnalysisEnum.company.getCode());

        JSONObject filterParams = JSONObject.parseObject(JSONObject.toJSONString(filter.get("filterParams")));
        String filterType = filter.getString("filterType");

        if (!ObjectUtils.isEmpty(filter.get("filterParams"))) {
            if (filterParams.containsKey("dp_filter_business_type")) {
                String businessType = filterParams.getString("dp_filter_business_type");
                if (StatisticalAnalysisEnum.company.getCode().equals(businessType)) {
                    companyBoolMust(boolMust, businessType);
                } else if (StatisticalAnalysisEnum.inspectionCompany.getCode().equals(businessType)) {
                    companyBoolMust(boolMust, "inspection");
                    boolMust.mustNot(QueryBuilders.wildcardQuery("unitType.keyword", "*检验检测机构*"));
                }
            }
            getCompanyBoolQueryBuilder(filterParams, filterType, boolMust);
        }

        String permitStatusStr = "";
        if (filterParams.containsKey("permitStatus")) {
            Object permitStatus = filterParams.get("permitStatus");
            if (permitStatus instanceof JSONArray) {
                JSONArray jsonArray = (JSONArray) permitStatus;
                if (!ObjectUtils.isEmpty(jsonArray) && !jsonArray.contains("all") && jsonArray.size() == 1) {
                    permitStatusStr = jsonArray.get(0).toString();
                }
            }
        }

        if ("custom".equals(filterType)) {
            JSONArray leftGroup = filterParams.getJSONArray("group1");
            JSONArray rightGroup = filterParams.getJSONArray("group2");
            permitStatusStr = getFilterPermitStatusOrLicensesStatus(leftGroup, rightGroup, StatisticalAnalysisEnum.company.getCode());
        }

        // 排序
        if (!ObjectUtils.isEmpty(filter.get("sort"))) {
            JSONObject sort = JSONObject.parseObject(JSONObject.toJSONString(filter.get("sort")));
            String field = sort.getString("field").equals("permissionStatus") ? "licenseMinExpiryDate" : sort.getString("field") + ".keyword";
            SortOrder sortOrder = sort.getString("order").equals("desc") ? SortOrder.DESC : SortOrder.ASC;
            FieldSortBuilder sortBuilder = SortBuilders.fieldSort(field).order(sortOrder);
            builder.sort(sortBuilder);
        }

        builder.query(boolMust);
        builder.from((current - 1) * size);
        builder.size(size);
        request.source(builder);

        List<JSONObject> list = new LinkedList<>();
        long totle = 0;
        try {
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            for (SearchHit hit : response.getHits().getHits()) {
                JSONObject jsonObject = (JSONObject) JSONObject.toJSON(hit);
                JSONObject dto = jsonObject.getJSONObject("sourceAsMap");
                String permissionStatus = "";
                String overdueStr = permitStatusMap.get(overdue);
                String nearStr = permitStatusMap.get(near);
                String normalStr = permitStatusMap.get(normal);
                String noneStr = permitStatusMap.get(none);
                if (dto.containsKey("licenses")) {
                    if (!"".equals(permitStatusStr)) {
                        permissionStatus = permitStatusMap.get(permitStatusStr);
                    } else {
                        List<String> permissionStatusList = new ArrayList<>();
                        JSONArray licenses = dto.getJSONArray("licenses");
                        if (!ObjectUtils.isEmpty(licenses)) {
                            for (Object object : licenses) {
                                JSONObject json = JSONObject.parseObject(JSONObject.toJSONString(object));
                                String expiryDate = json.getString("expiryDate");
                                if (!ObjectUtils.isEmpty(expiryDate)) {
                                    long daysBetween = ChronoUnit.DAYS.between(LocalDate.now(), LocalDate.parse(expiryDate, formatter));
                                    if (daysBetween <= 0) {
                                        permissionStatusList.add(overdueStr);
                                    } else if (daysBetween <= 30) {
                                        permissionStatusList.add(nearStr);
                                    } else {
                                        permissionStatusList.add(normalStr);
                                    }
                                } else {
                                    permissionStatusList.add(noneStr);
                                }
                            }
                            long cq = permissionStatusList.stream().filter(e -> e.equals(overdueStr)).count();
                            long lq = permissionStatusList.stream().filter(e -> e.equals(nearStr)).count();
                            long no = permissionStatusList.stream().filter(e -> e.equals(noneStr)).count();
                            long zc = permissionStatusList.stream().filter(e -> e.equals(normalStr)).count();
                            if (cq > 0) {
                                permissionStatus = overdueStr;
                            } else if (lq > 0) {
                                permissionStatus = nearStr;
                            } else if (no > 0) {
                                permissionStatus = noneStr;
                            } else if (zc > 0) {
                                permissionStatus = normalStr;
                            }
                        } else {
                            permissionStatus = noneStr;
                        }
                    }
                } else if (!dto.containsKey("licenses") && (dto.get("unitType").toString().contains("检测单位") ||
                        dto.get("unitType").toString().contains("检验单位") ||
                        dto.get("unitType").toString().contains("制造单位") ||
                        dto.get("unitType").toString().contains("充装单位") ||
                        dto.get("unitType").toString().contains("设计单位") ||
                        dto.get("unitType").toString().contains("安装改造维修单位"))) {
                    permissionStatus = noneStr;
                }
                if (dto.get("unitType").equals("使用单位") || dto.get("unitType").equals("个人主体")) {
                    permissionStatus = null;
                }
                dto.put("permissionStatus", permissionStatus);
                list.add(dto);
            }
            totle = Objects.requireNonNull(response.getInternalResponse().hits().getTotalHits()).value;
            page.setRecords(list);
            page.setTotal(totle);
            result.put("pageData", page);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }


        List<Map<String, Object>> statics = new ArrayList<>();
        Map<String, Object> sum = new HashMap<>();
        sum.put("name", "企业总数（个）");
        sum.put("value", totle);
        statics.add(sum);
        result.put("statics", statics);

        // 获取许可状态统计
        List<Map<String, Object>> staticMap = new ArrayList<>();
        if (!"".equals(permitStatusStr)) {
            getFilterCompanyOrPersonPermitStatusStatic(staticMap, StatisticalAnalysisEnum.company.getKey(), permitStatusStr, totle);
        } else {
            getCompanyOrPersonPermitStatusStatic(boolMust, staticMap, StatisticalAnalysisEnum.company.getKey());
        }
        result.put("keyIndicator", staticMap);

        return result;
    }

    private void getFilterCompanyOrPersonPermitStatusStatic(List<Map<String, Object>> staticMap, String index, String statusStr, long totle) {
        Map<String, Object> normalMap = new HashMap<>();
        String normalName = index.equals(StatisticalAnalysisEnum.company.getKey()) ? permitStatusMap.get(normal) : licensesStatusMap.get(normal);
        String nearName = index.equals(StatisticalAnalysisEnum.company.getKey()) ? permitStatusMap.get(near) : licensesStatusMap.get(near);
        normalMap.put("name", normalName);
        Map<String, Object> nearMap = new HashMap<>();
        nearMap.put("name", nearName);
        if (statusStr.equals(normal)) {
            normalMap.put("value", totle);
            nearMap.put("value", 0);
        } else if (statusStr.equals(near)) {
            nearMap.put("value", 0);
            nearMap.put("value", totle);
        } else {
            nearMap.put("value", 0);
            nearMap.put("value", 0);
        }
        staticMap.add(normalMap);
        staticMap.add(nearMap);
    }

    /**
     * 构造企业查询条件
     *
     * @param filterParams
     * @param filterType
     * @param boolMust
     */
    private void getCompanyBoolQueryBuilder(JSONObject filterParams, String filterType, BoolQueryBuilder boolMust) {
        deleteUnitCategory(filterParams);
        //快捷筛选和自定义筛选解析筛选规则不一致
        if (filterType.equals("advanced")) {
            filterParams.forEach((k, v) -> {
                if (v instanceof JSONArray) {
                    if (!((JSONArray) v).contains("all") && ((JSONArray) v).size() > 0) {
                        String field = k;
                        if (k.equals("regulatoryLabels") || k.equals("equipCategory") || k.equals("unitType")) {
                            DynamicQueryBuilder dynamicQueryBuilder = new DynamicQueryBuilder();
                            EnhancedDynamicQueryBuilder enhancedDynamicQueryBuilder = new EnhancedDynamicQueryBuilder();
                            ((JSONArray) v).forEach(item -> enhancedDynamicQueryBuilder.add(QueryBuilders.wildcardQuery(field + ".keyword", "*" + item + "*"), or));
                            dynamicQueryBuilder.and(enhancedDynamicQueryBuilder.build().minimumShouldMatch(1));
                            boolMust.must(dynamicQueryBuilder.build());
                        } else if (k.equals("industrySupervisor") || k.equals("operatingStatus")) {
                            TermsQueryBuilder termsQuery = QueryBuilders.termsQuery(field + ".keyword", ((JSONArray) v));
                            boolMust.must(termsQuery);
                        } else if (k.equals("itemCode") || k.equals("subItemCode") || k.equals("permitStatus")) {
                            String path = "licenses";
                            EnhancedDynamicQueryBuilder enhancedDynamicQueryBuilder = new EnhancedDynamicQueryBuilder();
                            ((JSONArray) v).forEach(item -> {
                                String nestedField = path + "." + (k.equals("permitStatus") ? "expiryDate" : k + ".keyword");
                                if (k.equals("permitStatus")) {
                                    if (item.equals(overdue)) {
                                        // 超期：小于当前日期
                                        NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                                path,
                                                QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery(nestedField).lt(LocalDate.now().format(formatter))),
                                                ScoreMode.None
                                        );
                                        enhancedDynamicQueryBuilder.add(nestedQuery, or);
                                    } else if (item.equals(near)) {
                                        // 临期：小于等于当前日期加上30天
                                        NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                                path,
                                                QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery(nestedField).lte(LocalDate.now().plusDays(30).format(formatter)).gte(LocalDate.now().format(formatter))),
                                                ScoreMode.None
                                        );
                                        enhancedDynamicQueryBuilder.add(nestedQuery, or);
                                    } else if (item.equals(normal)) {
                                        // 正常：大于当前日期加上30天
                                        NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                                path,
                                                QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery(nestedField).gt(LocalDate.now().plusDays(30).format(formatter))),
                                                ScoreMode.None
                                        );
                                        enhancedDynamicQueryBuilder.add(nestedQuery, or);
                                    } else if (item.equals(none)) {
                                        NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                                path,
                                                QueryBuilders.boolQuery().mustNot(existsQuery(nestedField)),
                                                ScoreMode.None
                                        );
                                        NestedQueryBuilder noneQuery = QueryBuilders.nestedQuery(
                                                path,
                                                QueryBuilders.boolQuery().mustNot(existsQuery(path)),
                                                ScoreMode.None
                                        );
                                        enhancedDynamicQueryBuilder.add(noneQuery, or);
                                        enhancedDynamicQueryBuilder.add(nestedQuery, or);
                                    }
                                } else {
                                    // 创建嵌套查询
                                    NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                            path,
                                            QueryBuilders.termsQuery(nestedField, item),
                                            ScoreMode.None
                                    );
                                    enhancedDynamicQueryBuilder.add(nestedQuery, or);
                                }
                            });
                            boolMust.must(enhancedDynamicQueryBuilder.build());
                        }
                    }
                } else if (v instanceof String) {
                    if (k.equals("fuzzyInput")) {
                        String fuzzyValue = String.valueOf(v);
                        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
                        queryBuilder.should(QueryBuilders.wildcardQuery("useUnit.keyword", "*" + fuzzyValue + "*"));
                        queryBuilder.should(QueryBuilders.wildcardQuery("address.keyword", "*" + fuzzyValue + "*"));
                        queryBuilder.should(QueryBuilders.wildcardQuery("superviseOrgName.keyword", "*" + fuzzyValue + "*"));
                        queryBuilder.should(QueryBuilders.wildcardQuery("equipCategoryName.keyword", "*" + fuzzyValue + "*"));
                        queryBuilder.should(QueryBuilders.wildcardQuery("contactUser.keyword", "*" + fuzzyValue + "*"));
                        queryBuilder.minimumShouldMatch(1);
                        boolMust.must(queryBuilder);
                    } else if (k.equals("unitCategory")) {
                        if (!"".equals(v) && !ObjectUtils.isEmpty(v) && !"all".equals(v)) {
                            String category = v.toString();
                            JSONArray unitTypeByType = UnitTypeNewEnum.getUnitTypeByType(category);
                            List<String> list = unitTypeByType.stream().map(e -> JSONObject.parseObject(JSONObject.toJSONString(e)).get("value").toString()).collect(Collectors.toList());
                            EnhancedDynamicQueryBuilder enhancedDynamicQueryBuilder = new EnhancedDynamicQueryBuilder();
                            list.forEach(item -> enhancedDynamicQueryBuilder.add(QueryBuilders.boolQuery().should(QueryBuilders.wildcardQuery("unitType.keyword", "*" + item + "*")), or));
                            boolMust.must(enhancedDynamicQueryBuilder.build());
                        }
                    }
                }
            });
        } else {
            JSONArray leftGroup = filterParams.getJSONArray("group1");
            JSONArray rightGroup = filterParams.getJSONArray("group2");
            Boolean isOrGroup = or.equals(filterParams.getString("groupAndOr")) ? Boolean.TRUE : Boolean.FALSE;
            handleAdvancedFilter(boolMust, leftGroup, rightGroup, isOrGroup, StatisticalAnalysisEnum.company.getCode());
        }
    }

    private String getFilterPermitStatusOrLicensesStatus(JSONArray leftGroup, JSONArray rightGroup, String code) {
        String filed = code.equals(StatisticalAnalysisEnum.company.getCode()) ? "permitStatus" : "expiryDate";
        List<Object> LeftNoLicenseList = leftGroup.stream().filter(e -> "certNo".equals(((JSONObject) e).getString("field")) && ((JSONObject) e).containsKey("value") && ((JSONObject) e).getString("value").equals("0") && ((JSONObject) e).containsKey("itemCondition") && !((JSONObject) e).getString("itemCondition").equals("notIn")).collect(Collectors.toList());
        List<Object> rightNoLicenseList = rightGroup.stream().filter(e -> "certNo".equals(((JSONObject) e).getString("field")) && ((JSONObject) e).containsKey("value") && ((JSONObject) e).getString("value").equals("0") && ((JSONObject) e).containsKey("itemCondition") && !((JSONObject) e).getString("itemCondition").equals("notIn")).collect(Collectors.toList());
        Boolean noLicense = false;
        if (LeftNoLicenseList.size() > 0 || rightNoLicenseList.size() > 0) {
            noLicense = true;
        }
        List<Object> leftPermitList = leftGroup.stream().filter(e -> filed.equals(((JSONObject) e).getString("field")) && ((JSONObject) e).containsKey("value") && ((JSONObject) e).containsKey("itemCondition") && !((JSONObject) e).getString("itemCondition").equals("notIn")).collect(Collectors.toList());
        List<Object> rightPermitList = rightGroup.stream().filter(e -> filed.equals(((JSONObject) e).getString("field")) && ((JSONObject) e).containsKey("value") && ((JSONObject) e).containsKey("itemCondition") && !((JSONObject) e).getString("itemCondition").equals("notIn")).collect(Collectors.toList());
        int count = 0;
        Boolean isLeft = false;
        Boolean isRight = false;
        if (!ObjectUtils.isEmpty(leftPermitList) && leftPermitList.size() == 1) {
            count += 1;
            isLeft = true;
        }
        if (!ObjectUtils.isEmpty(rightPermitList) && rightPermitList.size() == 1) {
            count += 1;
            isRight = true;
        }
        String statusStr = "";
        if (count == 1 && isLeft && !noLicense) {
            statusStr = ((JSONObject) leftPermitList.get(0)).getString("value");
        } else if (count == 1 && isRight && !noLicense) {
            statusStr = ((JSONObject) rightPermitList.get(0)).getString("value");
        }
        return statusStr;
    }

    private void deleteUnitCategory(JSONObject filterParams) {
        if (filterParams.containsKey("unitType") && !filterParams.getString("unitType").contains("all") && !filterParams.getString("unitType").contains("[]")) {
            filterParams.remove("unitCategory");
        }
        if (filterParams.containsKey("regulatoryLabels") && !filterParams.getString("regulatoryLabels").contains("all") && !filterParams.getString("regulatoryLabels").contains("[]")) {
            filterParams.remove("unitCategory");
        }

    }

    private JSONObject queryEquipmentPage(JSONObject filter, Page<JSONObject> page, Integer current, Integer size) {

        JSONObject result = new JSONObject();

        SearchRequest request = new SearchRequest();
        request.indices(StatisticalAnalysisEnum.equip.getKey());
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.trackTotalHits(true);
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();

        String orgCode = filter.getString("orgCode");
        boolMust.must(QueryBuilders.prefixQuery("ORG_BRANCH_CODE", orgCode));
        boolMust.mustNot(QueryBuilders.termsQuery("STATUS", Arrays.asList("草稿", "已拒领", "待认领")));
        JSONObject filterParams = new JSONObject();
        // 筛选
        if (!ObjectUtils.isEmpty(filter.get("filterParams"))) {
            filterParams = JSONObject.parseObject(JSONObject.toJSONString(filter.get("filterParams")));
            if (filterParams.containsKey("dp_filter_business_type") && filterParams.containsKey("DATA_QUALITY_SCORE") && !filterParams.containsKey("EQU_LIST")) {
                List<String> equListCode = Arrays.asList("1000", "2000", "3000", "4000", "5000", "6000", "9000");
                boolMust.must(QueryBuilders.termsQuery("EQU_LIST_CODE", equListCode));
                boolMust.mustNot(QueryBuilders.termQuery("EQU_CATEGORY_CODE", "2300"));
            }
            if (filterParams.containsKey("other")) {
                if (!filterParams.containsKey("EQU_LIST")) {
                    boolMust.mustNot(QueryBuilders.termsQuery("EQU_LIST_CODE", equList));
                } else if (!filterParams.containsKey("EQU_CATEGORY")) {
                    JSONArray jsonArray = (JSONArray) filterParams.get("EQU_LIST");
                    if (!ObjectUtils.isEmpty(jsonArray)) {
                        List<String> subCodes = tzsCustomFilterMapper.getSubCodes(String.valueOf(jsonArray.get(0)));
                        boolMust.mustNot(QueryBuilders.termsQuery("EQU_CATEGORY_CODE", subCodes));
                    }
                } else if (!filterParams.containsKey("EQU_DEFINE")) {
                    JSONArray jsonArray = (JSONArray) filterParams.get("EQU_CATEGORY");
                    if (!ObjectUtils.isEmpty(jsonArray)) {
                        List<String> subCodes = tzsCustomFilterMapper.getSubCodes(String.valueOf(jsonArray.get(0)));
                        boolMust.mustNot(QueryBuilders.termsQuery("EQU_DEFINE_CODE", subCodes));
                    }
                }
            }
            String filterType = filter.getString("filterType");
            // 组装查询条件
            getEquipmentBoolQueryBuilder(boolMust, filterParams, filterType);
        }

        //  排序
        if (!ObjectUtils.isEmpty(filter.get("sort"))) {
            JSONObject sort = JSONObject.parseObject(JSONObject.toJSONString(filter.get("sort")));
            String field = sort.getString("field");
            if (field.equals("EQU_LIST")) {
                field = "EQU_LIST_CODE";
            } else if (field.equals("EQU_CATEGORY")) {
                field = "EQU_CATEGORY_CODE";
            } else if (field.equals("EQU_DEFINE")) {
                field = "EQU_DEFINE_CODE";
            } else if (field.equals("ORG_BRANCH_NAME")) {
                field = "ORG_BRANCH_CODE";
            } else if (field.equals("USE_UNIT_NAME")) {
                field = "USE_UNIT_CREDIT_CODE";
            } else if (field.equals("inspectStatus")) {
                field = "NEXT_INSPECT_DATE";
            }
            builder.sort(field, sort.getString("order").equals("desc") ? SortOrder.DESC : SortOrder.ASC);
        }

        builder.query(boolMust);
        List<Map<String, Object>> statics = new ArrayList<>();

        builder.from((current - 1) * size);
        builder.size(size);
        request.source(builder);

        List<JSONObject> list = new LinkedList<>();
        long totle = 0;
        try {
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            for (SearchHit hit : response.getHits().getHits()) {
                JSONObject jsonObject = (JSONObject) JSONObject.toJSON(hit);
                JSONObject dto = jsonObject.getJSONObject("sourceAsMap");
                dto.put("record", dto.get("SEQUENCE_NBR"));
                dto.put("equipAddress", dto.get("USE_PLACE") + "/" + dto.get("ADDRESS"));
                String dataQualityScore = ObjectUtils.isEmpty(dto.get("DATA_QUALITY_SCORE")) ? null : DataQualityScoreEnum.getLabelByCode(dto.get("DATA_QUALITY_SCORE").toString());
                dto.put("DATA_QUALITY_SCORE", dataQualityScore);
                dto.put("WHETHER_VEHICLE_CYLINDER", ObjectUtils.isEmpty(dto.get("WHETHER_VEHICLE_CYLINDER")) ? "" : "1".equals(dto.get("WHETHER_VEHICLE_CYLINDER")) ? "是" : "否");
                dto.put("WHETHER_SKID_MOUNTED_PRESSURE_VESSEL", ObjectUtils.isEmpty(dto.get("WHETHER_SKID_MOUNTED_PRESSURE_VESSEL")) ? "" : "1".equals(dto.get("WHETHER_SKID_MOUNTED_PRESSURE_VESSEL")) ? "是" : "否");
                dto.put("whetherSphericalTank", ObjectUtils.isEmpty(dto.get("whetherSphericalTank")) ? "" : "1".equals(dto.get("whetherSphericalTank")) ? "是" : "否");
                dto.put("EQU_STATE", ObjectUtils.isEmpty(dto.get("EQU_STATE")) ? "无" : EquipStateEnum.getNameByCode(dto.get("EQU_STATE").toString()));
                String inspectStatus = inspectionStatusMap.get(none);
                if (dto.containsKey("NEXT_INSPECT_DATE")) {
                    String nextInspectDate = dto.getString("NEXT_INSPECT_DATE");
                    if (!ObjectUtils.isEmpty(nextInspectDate) && !nextInspectDate.isEmpty()) {
                        long daysBetween = ChronoUnit.DAYS.between(LocalDate.now(), LocalDate.parse(nextInspectDate, formatter));
                        if (daysBetween < 0) {
                            inspectStatus = inspectionStatusMap.get(overdue);
                        } else if (daysBetween <= 30) {
                            inspectStatus = inspectionStatusMap.get(near);
                        } else {
                            inspectStatus = inspectionStatusMap.get(normal);
                        }
                    }
                }
                if (!ValidationUtil.isEmpty(dto.getString("INFORMATION_SITUATION"))) {
                    String informationSituation = dto.getString("INFORMATION_SITUATION");
                    boolean integer = isInteger(informationSituation);
                    if (integer) {
                        informationSituation = InformationManageTypeEnum.getName(informationSituation);
                    }
                    dto.put("INFORMATION_SITUATION", informationSituation);
                }
                Optional.ofNullable(dto.getJSONArray("inspections"))
                        .ifPresent(arr -> arr.forEach(o -> {
                            JSONObject j = (JSONObject) o;
                            String v = j.getString("inspectReportNo");
                            j.put("inspectReportNo", (v == null || "null".equalsIgnoreCase(v)) ? "" : v);
                        }));
                if (!ValidationUtil.isEmpty(dto.getString("CYLINDER_CATEGORY")) && "2300".equals(dto.getString("EQU_CATEGORY_CODE"))) {
                    String cylinderCategory = dto.getString("CYLINDER_CATEGORY");
                    boolean integer = isInteger(cylinderCategory);
                    if (integer) {
                        cylinderCategory = CylinderCategoryEnum.getName(cylinderCategory);
                    }
                    dto.put("CYLINDER_CATEGORY", cylinderCategory);
                }else{
                    dto.put("CYLINDER_CATEGORY", "");
                }
                dto.put("inspectStatus", inspectStatus);
                list.add(dto);
            }
            totle = Objects.requireNonNull(response.getInternalResponse().hits().getTotalHits()).value;
            page.setRecords(list);
            page.setTotal(totle);
            result.put("pageData", page);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        List<Map<String, Object>> equipStatusMap = new ArrayList<>();
        getEquipStatusStatic(boolMust, builder, equipStatusMap);
        result.put("keyIndicator", equipStatusMap);

        String equList = ObjectUtils.isEmpty(filterParams) || "".equals(filterParams.get("equList").toString()) ? "all" : filterParams.get("equList").toString();
        String equCategory = ObjectUtils.isEmpty(filterParams) || "".equals(filterParams.get("equCategory").toString()) ? "all" : filterParams.get("equCategory").toString();

        if (!equList.equals("8000") && !equCategory.equals("2300")) {
            BoolQueryBuilder queryBuilder = QueryBuilderUtils.copyBoolQuery(boolMust);
            queryBuilder.mustNot(QueryBuilders.termQuery("EQU_LIST_CODE", "8000"))
                    .mustNot(QueryBuilders.termQuery("EQU_CATEGORY_CODE", "2300"));
            Long count = getStatisticCount(queryBuilder, StatisticalAnalysisEnum.equip.getKey());
            Map<String, Object> sum = new HashMap<>();
            sum.put("name", "设备总数（台套）");
            sum.put("value", count);
            statics.add(sum);
        }

        if (equList.contains("8000") || equList.contains("all")) {
            // 获取压力管道长度
            BigDecimal pipeLength = getPipeLength(boolMust, builder, "pipeLength");
            Map<String, Object> pipeMap = new HashMap<>();
            pipeMap.put("name", "压力管道（千米）");
            pipeMap.put("value", pipeLength.divide(new BigDecimal(1000), 2, BigDecimal.ROUND_HALF_UP));
            statics.add(pipeMap);
        }


        if (equList.contains("all") || (equList.contains("2000") && "all".equals(equCategory)) || equCategory.contains("2300")) {
            // 气瓶数量
            CountRequest countRequest = new CountRequest();
            countRequest.indices(StatisticalAnalysisEnum.equip.getKey());
            boolMust.must(QueryBuilders.termQuery("EQU_CATEGORY_CODE", "2300"));
            countRequest.query(boolMust);
            CountResponse response = null;
            try {
                response = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            Map<String, Object> gasMap = new HashMap<>();
            gasMap.put("name", "气瓶（个）");
            gasMap.put("value", ObjectUtils.isEmpty(response) ? 0 : response.getCount());
            statics.add(gasMap);
        }
        result.put("statics", statics);
        return result;
    }


    private static boolean isInteger(String s) {
        try {
            Integer.parseInt(s);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }


    private void handleOrgCode(BoolQueryBuilder boolMust, String orgCode) {
        if (orgCode.equals("50")) {
            DynamicQueryBuilder dynamicQueryBuilder = new DynamicQueryBuilder();
            dynamicQueryBuilder.or(QueryBuilders.prefixQuery("ORG_BRANCH_CODE", orgCode));
            dynamicQueryBuilder.or(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("ORG_BRANCH_CODE", "")));
            dynamicQueryBuilder.or(QueryBuilders.boolQuery().mustNot(existsQuery("ORG_BRANCH_CODE")));
            boolMust.must(dynamicQueryBuilder.build());
        } else {
            boolMust.must(QueryBuilders.prefixQuery("ORG_BRANCH_CODE", orgCode));
        }
    }

    private void getEquipmentBoolQueryBuilder(BoolQueryBuilder boolMust, JSONObject filterParams, String filterType) {
        HashSet<String> equListCodes = new HashSet<>();
        HashSet<String> equCategoryCodes = new HashSet<>();
        //快捷筛选和自定义筛选解析筛选规则不一致
        if (filterType.equals("advanced")) {
            JSONObject finalFilterParams = filterParams;
            filterParams.forEach((k, v) -> {
                if (k.equals("techParam")) {
                    JSONArray techParams = (JSONArray) v;
                    if (!techParams.contains("all") && techParams.size() == 1) {
                        JSONObject paramRangeJson = JSONObject.parseObject(JSONObject.toJSONString(finalFilterParams.get("paramRange")));
                        String paramKey = techParams.getString(0);
                        String condition = paramRangeJson.getString("condition");
                        Object value = paramRangeJson.getString("value");
                        String fieldType = paramRangeJson.getString("fieldType");
                        if (!ObjectUtils.isEmpty(condition) && !ObjectUtils.isEmpty(value) && !ObjectUtils.isEmpty(fieldType)) {
                            getParamQuery(paramKey, condition, value, fieldType, false, boolMust, null, null);
                        }
                    }
                } else if (!k.equals("paramRange")) {
                    if (v instanceof JSONArray) {
                        // 判断是否需要解析参数
                        Boolean parseParam = getParamAnalysis(v);
                        if (parseParam) {
                            String field = k;
                            if (k.equals("NEXT_INSPECT_DATE")) {
                                String finalField = field;
                                EnhancedDynamicQueryBuilder queryBuilder = new EnhancedDynamicQueryBuilder();
                                ((JSONArray) v).forEach(item -> {
                                    if (item.equals(overdue)) {
                                        // 超期：小于当前日期
                                        queryBuilder.add(QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(finalField).lt(LocalDate.now().format(formatter))), or);
                                    } else if (item.equals(near)) {
                                        // 临期：小于等于当前日期加上30天
                                        queryBuilder.add(QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(finalField).gte(LocalDate.now().format(formatter)).lte(LocalDate.now().plusDays(30).format(formatter))), or);
                                    } else if (item.equals(normal)) {
                                        // 正常：大于当前日期加上30天
                                        queryBuilder.add(QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(finalField).gt(LocalDate.now().plusDays(30).format(formatter))), or);
                                    } else {
                                        queryBuilder.add(QueryBuilders.boolQuery().mustNot(existsQuery(finalField)), or);
                                    }
                                });
                                boolMust.must(queryBuilder.build());
                            } else if (k.equals("registerStatus")) {
                                EnhancedDynamicQueryBuilder enhancedDynamicQueryBuilder = new EnhancedDynamicQueryBuilder();
                                ((JSONArray) v).forEach(item -> {
                                    BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
                                    if ("1".equals(item)) {
                                        queryBuilder.must(QueryBuilders.termsQuery("IS_INTO_MANAGEMENT", Boolean.TRUE))
                                                .must(existsQuery("USE_ORG_CODE"))
                                                .mustNot(QueryBuilders.termQuery("USE_ORG_CODE", ""));
                                    } else {
                                        queryBuilder
                                                .should(QueryBuilders.boolQuery().mustNot(existsQuery("IS_INTO_MANAGEMENT")))
                                                .should(QueryBuilders.termQuery("IS_INTO_MANAGEMENT", Boolean.FALSE))
                                                .should(QueryBuilders.boolQuery().mustNot(existsQuery("USE_ORG_CODE")))
                                                .should(QueryBuilders.termQuery("USE_ORG_CODE", ""))
                                                .minimumShouldMatch(1);
                                    }
                                    enhancedDynamicQueryBuilder.add(queryBuilder, or);
                                });
                                boolMust.must(enhancedDynamicQueryBuilder.build());
                            } else if (k.equals("PRODUCE_DATE") || k.equals("issueDate") || k.equals("designDate") || k.equals("nextInspectDate") || k.equals("USE_DATE")) {
                                field = k.equals("nextInspectDate") ? "NEXT_INSPECT_DATE" : k;
                                JSONArray dates = (JSONArray) v;
                                String startDate = dates.getString(0);
                                String endDate = dates.getString(1);
                                if (!"".equals(startDate) && !"".equals(endDate) && !ObjectUtils.isEmpty(startDate) && !ObjectUtils.isEmpty(endDate)) {
                                    boolMust.filter(QueryBuilders.rangeQuery(field).gte(startDate).lte(endDate));
                                }
                            } else if (k.equals("EQU_LIST") || k.equals("EQU_CATEGORY") || k.equals("EQU_DEFINE") || k.equals("DATA_QUALITY_SCORE")) {
                                JSONArray jsonArray = (JSONArray) v;
                                if (k.equals("EQU_LIST")) {
                                    field = "EQU_LIST_CODE";
                                    equListCodes.addAll((jsonArray).toJavaList(String.class));
                                } else if (k.equals("EQU_CATEGORY")) {
                                    field = "EQU_CATEGORY_CODE";
                                    equCategoryCodes.addAll((jsonArray).toJavaList(String.class));
                                } else if (k.equals("EQU_DEFINE")) {
                                    field = "EQU_DEFINE_CODE";
                                }
                                TermsQueryBuilder termsQuery = QueryBuilders.termsQuery(field, (JSONArray) v);
                                boolMust.must(termsQuery);
                            } else if (k.equals("EQU_STATE")) {
                                EnhancedDynamicQueryBuilder queryBuilder = new EnhancedDynamicQueryBuilder();
                                ((JSONArray) v).forEach(item -> {
                                    if (!item.equals("99")) {
                                        queryBuilder.add(QueryBuilders.matchQuery(k, item.toString()), or);
                                    } else {
                                        queryBuilder.add(QueryBuilders.boolQuery().mustNot(existsQuery(k)), or);
                                    }
                                });
                                boolMust.must(queryBuilder.build());
                            } else if (k.equals("JDJY") || k.equals("DQJY") || k.equals("SCJY") || k.equals("DTJY")) {
                                String path = "inspections";
                                String typeField = path + ".inspectType";
                                String dateField = path + ".inspectDate";
                                BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
                                if (k.equals("JDJY")) {
                                    queryBuilder.must(QueryBuilders.wildcardQuery(typeField, "*JDJY*"));
                                } else {
                                    queryBuilder.must(QueryBuilders.termsQuery(typeField, k));
                                }
                                NestedQueryBuilder fieldQuery = QueryBuilders.nestedQuery(
                                        path,
                                        queryBuilder,
                                        ScoreMode.None
                                );
                                JSONArray dates = (JSONArray) v;
                                String startDate = dates.getString(0);
                                String endDate = dates.getString(1);
                                NestedQueryBuilder dateQuery = QueryBuilders.nestedQuery(
                                        path,
                                        QueryBuilders.rangeQuery(dateField).gte(startDate).lte(endDate),
                                        ScoreMode.None
                                );
                                if (!"".equals(startDate) && !"".equals(endDate)) {
                                    boolMust.must(fieldQuery);
                                    boolMust.filter(dateQuery);
                                }
                            } else if (k.equals("QZ_OR_TANK")) {
                                EnhancedDynamicQueryBuilder queryBuilder = new EnhancedDynamicQueryBuilder();
                                ((JSONArray) v).forEach(item -> {
                                    if (!"".equals(item)) {
                                        queryBuilder.add(QueryBuilders.matchQuery(item.toString(), "1"), or);
                                    }
                                });
                                boolMust.must(queryBuilder.build());
                            }
                        }
                    } else if (v instanceof String) {
                        if (k.equals("fuzzyInput")) {
                            String fuzzyValue = String.valueOf(v);
                            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
                            queryBuilder.should(QueryBuilders.wildcardQuery("EQU_LIST.keyword", "*" + fuzzyValue + "*"));
                            queryBuilder.should(QueryBuilders.wildcardQuery("EQU_CATEGORY.keyword", "*" + fuzzyValue + "*"));
                            queryBuilder.should(QueryBuilders.wildcardQuery("EQU_DEFINE.keyword", "*" + fuzzyValue + "*"));
                            queryBuilder.should(QueryBuilders.wildcardQuery("PRODUCT_NAME", "*" + fuzzyValue + "*"));
                            queryBuilder.should(QueryBuilders.wildcardQuery("USE_ORG_CODE", "*" + fuzzyValue + "*"));
                            queryBuilder.should(QueryBuilders.wildcardQuery("USE_UNIT_NAME", "*" + fuzzyValue + "*"));
                            queryBuilder.should(QueryBuilders.wildcardQuery("SAFETY_MANAGER.keyword", "*" + fuzzyValue + "*"));
                            queryBuilder.should(QueryBuilders.wildcardQuery("ORG_BRANCH_NAME", "*" + fuzzyValue + "*"));
                            queryBuilder.should(QueryBuilders.wildcardQuery("MAINTAIN_UNIT_NAME", "*" + fuzzyValue + "*"));
                            queryBuilder.should(QueryBuilders.wildcardQuery("FACTORY_NUM", "*" + fuzzyValue + "*"));
                            queryBuilder.should(QueryBuilders.wildcardQuery("EQU_CODE", "*" + fuzzyValue + "*"));
                            queryBuilder.should(QueryBuilders.wildcardQuery("CODE96333", "*" + fuzzyValue + "*"));
                            queryBuilder.should(QueryBuilders.wildcardQuery("SUPERVISORY_CODE", "*" + fuzzyValue + "*"));
                            queryBuilder.minimumShouldMatch(1);
                            boolMust.must(queryBuilder);
                        } else if (k.equals("WHETHER_VEHICLE_CYLINDER")) {
                            if (!"".equals(v)) {
                                boolMust.must(QueryBuilders.matchQuery(k, v.toString()));
                            }
                        }
                    }
                }
            });
        } else {
            JSONArray leftGroup = filterParams.getJSONArray("group1");
            JSONArray rightGroup = filterParams.getJSONArray("group2");
            Boolean isOrGroup = or.equals(filterParams.getString("groupAndOr")) ? Boolean.TRUE : Boolean.FALSE;
            handleAdvancedFilter(boolMust, leftGroup, rightGroup, isOrGroup, StatisticalAnalysisEnum.equip.getCode());
            equListCodes.add("all");
            equCategoryCodes.add("all");
        }
        filterParams.put("equList", String.join(",", equListCodes));
        filterParams.put("equCategory", String.join(",", equCategoryCodes));
    }

    private void getEquipStatusStatic(BoolQueryBuilder boolMust, SearchSourceBuilder builder, List<Map<String, Object>> statics) {
        SearchRequest request = new SearchRequest();
        request.indices(StatisticalAnalysisEnum.equip.getKey());
        builder.query(boolMust);
        builder.aggregation(AggregationBuilders.terms("equipStatus").field("EQU_STATE").missing(99));
        request.source(builder);
        Map<String, Long> staticsMap = new HashMap<>();
        try {
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            Terms terms = response.getAggregations().get("equipStatus");
            for (Terms.Bucket bucket : terms.getBuckets()) {
                String key = bucket.getKeyAsString();
                long docCount = bucket.getDocCount();
                staticsMap.put(key, docCount);
            }
            Map<String, Object> zyMap = new HashMap<>();
            Map<String, Object> tyMap = new HashMap<>();
            Map<String, Object> otherMap = new HashMap<>();
            long zy = staticsMap.containsKey(EquipStateEnum.ZY.getCode()) ? staticsMap.get(EquipStateEnum.ZY.getCode()) : 0;
            long ty = staticsMap.containsKey(EquipStateEnum.TY.getCode()) ? staticsMap.get(EquipStateEnum.TY.getCode()) : 0;
            long bf = staticsMap.containsKey(EquipStateEnum.BF.getCode()) ? staticsMap.get(EquipStateEnum.BF.getCode()) : 0;
            long zx = staticsMap.containsKey(EquipStateEnum.ZX.getCode()) ? staticsMap.get(EquipStateEnum.ZX.getCode()) : 0;
            long wzt = staticsMap.containsKey(EquipStateEnum.WZT.getCode()) ? staticsMap.get(EquipStateEnum.WZT.getCode()) : 0;
            long wdj = staticsMap.containsKey("0") ? staticsMap.get("0") : 0;
            long other = wdj + bf + zx + wzt;
            zyMap.put("name", "在用");
            zyMap.put("value", zy);
            tyMap.put("name", "停用");
            tyMap.put("value", ty);
            otherMap.put("name", "其他");
            otherMap.put("value", other);
            statics.add(zyMap);
            statics.add(tyMap);
            statics.add(otherMap);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    private void getCompanyOrPersonPermitStatusStatic(BoolQueryBuilder boolMust, List<Map<String, Object>> statics, String index) {
        String path = "licenses";
        String nestedField = path + ".expiryDate";

        BoolQueryBuilder normalBoolQuery = QueryBuilderUtils.copyBoolQuery(boolMust);
        NestedQueryBuilder normalNestedQuery = QueryBuilders.nestedQuery(
                path,
                QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery(nestedField).gt(LocalDate.now().plusDays(30).format(formatter))),
                ScoreMode.None
        );
        normalBoolQuery.must(normalNestedQuery);

        Long normalCount = getStatisticCount(normalBoolQuery, index);

        BoolQueryBuilder nearBoolQuery = QueryBuilderUtils.copyBoolQuery(boolMust);
        NestedQueryBuilder nearNestedQuery = QueryBuilders.nestedQuery(
                path,
                QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery(nestedField).lt(LocalDate.now().plusDays(30).format(formatter)).gte(LocalDate.now().format(formatter))),
                ScoreMode.None
        );
        nearBoolQuery.must(nearNestedQuery);
        Long nearCount = getStatisticCount(nearBoolQuery, index);

        Map<String, Object> normalMap = new HashMap<>();
        normalMap.put("name", index.equals(StatisticalAnalysisEnum.company.getKey()) ? "许可正常" : "资质正常");
        normalMap.put("value", normalCount);
        statics.add(normalMap);

        Map<String, Object> nearMap = new HashMap<>();
        nearMap.put("name", index.equals(StatisticalAnalysisEnum.company.getKey()) ? "许可临期" : "资质临期");
        nearMap.put("value", nearCount);
        statics.add(nearMap);
    }


    public Long getStatisticCount(BoolQueryBuilder builder, String index) {
        CountRequest countRequest = new CountRequest();
        countRequest.indices(index);
        CountResponse response = null;
        countRequest.query(builder);
        try {
            response = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return ObjectUtils.isEmpty(response) ? 0 : response.getCount();
    }

    private BigDecimal getPipeLength(BoolQueryBuilder boolMust, SearchSourceBuilder builder, String countField) {
        SearchRequest request = new SearchRequest();
        request.indices(StatisticalAnalysisEnum.equip.getKey());
        BigDecimal pipeLong;
        BoolQueryBuilder pipeLengthQuery = QueryBuilderUtils.copyBoolQuery(boolMust);
        pipeLengthQuery.must(QueryBuilders.existsQuery("pipeLength"));
        pipeLengthQuery.must(existsQuery("SUPERVISORY_CODE"));
        pipeLengthQuery.mustNot(QueryBuilders.termQuery("SUPERVISORY_CODE", ""));
        SumAggregationBuilder pipeLengthAgg = AggregationBuilders.sum(countField).field("pipeLength").missing(0);
        builder.query(pipeLengthQuery);
        builder.aggregation(pipeLengthAgg).size(0);
        request.source(builder);
        try {
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            ParsedSum sumAgg = response.getAggregations().get(countField);
            double value = sumAgg.getValue();
            pipeLong = new BigDecimal(value);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return pipeLong;
    }

    private Boolean getParamAnalysis(Object v) {
        Boolean result = false;
        if (v instanceof JSONArray) {
            JSONArray jsonArray = (JSONArray) v;
            result = jsonArray.size() != 0 && null != jsonArray.get(0) && !"all".equals(jsonArray.get(0));
        } else if (v instanceof String) {
            if ("null".equals(v) || "".equals(v) || null == v) {
                result = true;
            }
        }
        return result;
    }

    private void getParamQuery(String paramKey, String condition, Object value, String fieldType, Boolean isCustom, BoolQueryBuilder boolMust, EnhancedDynamicQueryBuilder builder, String andOr) {
        String path = "techParams";
        String nestedFieldKey = path + ".paramKey";
        String tail = "BIG_DECIMAL".equals(fieldType) ? ".doubleValue" : ".strValue";
        TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery(nestedFieldKey, paramKey);
        if ("chargingMedium".equals(paramKey)) {
            List<DictionarieValueModel> fillingMedium = Systemctl.dictionarieClient.dictValues("FILLING_MEDIUM").getResult();
            Object finalValue = value;
            List<DictionarieValueModel> collect = fillingMedium.stream().filter(e -> e.getDictDataValue().contains(finalValue.toString())).collect(Collectors.toList());
            if (!ObjectUtils.isEmpty(collect)) {
                if (collect.size() == 1) {
                    value = collect.get(0).getDictDataKey();
                }
                if (collect.size() > 1) {
                    value = collect.stream().map(DictionarieValueModel::getDictDataKey).collect(Collectors.toList());
                    condition = "in";
                }
            }
        }
        switch (condition) {
            case "eq":
                NestedQueryBuilder eqQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().must(termsQueryBuilder).must(QueryBuilders.termsQuery(path + tail, value)),
                        ScoreMode.None
                );
                if (isCustom) {
                    builder.add(eqQuery, andOr);
                } else {
                    boolMust.must(eqQuery);
                }
                break;
            case "neq":
                NestedQueryBuilder neqQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().must(termsQueryBuilder).mustNot(QueryBuilders.termsQuery(path + tail, value)),
                        ScoreMode.None
                );
                if (isCustom) {
                    builder.add(neqQuery, andOr);
                } else {
                    boolMust.mustNot(neqQuery);
                }
                break;
            case "like":
                NestedQueryBuilder likeQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().must(termsQueryBuilder).must(QueryBuilders.wildcardQuery(path + tail, "*" + value + "*")),
                        ScoreMode.None
                );
                if (isCustom) {
                    builder.add(likeQuery, andOr);
                } else {
                    boolMust.must(likeQuery);
                }
                break;
            case "notLike":
                NestedQueryBuilder notLikeQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().must(termsQueryBuilder).must(QueryBuilders.wildcardQuery(path + tail, "*" + value + "*")),
                        ScoreMode.None
                );
                if (isCustom) {
                    builder.add(QueryBuilders.boolQuery().mustNot(notLikeQuery), andOr);
                } else {
                    boolMust.mustNot(notLikeQuery);
                }
                break;
            case "gt":
                NestedQueryBuilder gtQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().must(termsQueryBuilder).must(QueryBuilders.rangeQuery(path + tail).gt(value.toString())),
                        ScoreMode.None
                );
                if (isCustom) {
                    builder.add(gtQuery, andOr);
                } else {
                    boolMust.must(gtQuery);
                }
                break;
            case "gte":
                NestedQueryBuilder gteQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().must(termsQueryBuilder).must(QueryBuilders.rangeQuery(path + tail).gte(value.toString())),
                        ScoreMode.None
                );
                if (isCustom) {
                    builder.add(gteQuery, andOr);
                } else {
                    boolMust.must(gteQuery);
                }
                break;
            case "lt":
                NestedQueryBuilder ltQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().must(termsQueryBuilder).must(QueryBuilders.rangeQuery(path + tail).lt(value.toString())),
                        ScoreMode.None
                );
                if (isCustom) {
                    builder.add(ltQuery, andOr);
                } else {
                    boolMust.must(ltQuery);
                }
                break;
            case "lte":
                NestedQueryBuilder lteQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().must(termsQueryBuilder).must(QueryBuilders.rangeQuery(path + tail).lte(value.toString())),
                        ScoreMode.None
                );
                if (isCustom) {
                    builder.add(lteQuery, andOr);
                } else {
                    boolMust.must(lteQuery);
                }
                break;
            case "between":
                JSONArray btValues = (JSONArray) value;
                NestedQueryBuilder betweenQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().must(termsQueryBuilder).must(QueryBuilders.rangeQuery(path + tail).gte(Double.parseDouble(btValues.get(0).toString())).lte(Double.parseDouble(btValues.get(1).toString()))),
                        ScoreMode.None
                );
                if (isCustom) {
                    builder.add(betweenQuery, andOr);
                } else {
                    boolMust.must(betweenQuery);
                }
                break;
            case "in":
                BoolQueryBuilder boolQuery = QueryBuilders.boolQuery().must(termsQueryBuilder);
                if (value instanceof String) {
                    boolQuery.must(QueryBuilders.termQuery(path + tail, value));
                } else {
                    JSONArray inValues = new JSONArray();
                    if (value instanceof JSONArray) {
                        inValues = (JSONArray) value;
                    }
                    if (value instanceof List) {
                        // value转化为jsONArray
                        inValues.addAll((List) value);
                    }
                    boolQuery.must(QueryBuilders.termsQuery(path + tail, inValues));
                }
                NestedQueryBuilder inQuery = QueryBuilders.nestedQuery(
                        path,
                        boolQuery,
                        ScoreMode.None
                );
                if (isCustom) {
                    builder.add(inQuery, andOr);
                } else {
                    boolMust.must(inQuery);
                }
                break;
            case "notIn":
                BoolQueryBuilder notInBoolQuery = QueryBuilders.boolQuery().must(termsQueryBuilder);
                if (value instanceof String) {
                    notInBoolQuery.mustNot(QueryBuilders.termQuery(path + tail, value));
                } else {
                    JSONArray inValues = new JSONArray();
                    if (value instanceof JSONArray) {
                        inValues = (JSONArray) value;
                    }
                    if (value instanceof List) {
                        // value转化为jsONArray
                        inValues.addAll((List) value);
                    }
                    notInBoolQuery.mustNot(QueryBuilders.termsQuery(path + tail, inValues));
                }
                NestedQueryBuilder notInQuery = QueryBuilders.nestedQuery(
                        path,
                        notInBoolQuery,
                        ScoreMode.None
                );
                if (isCustom) {
                    builder.add(QueryBuilders.boolQuery().mustNot(notInQuery), andOr);
                } else {
                    boolMust.must(notInQuery);
                }
                break;
        }
    }

    // 处理高级筛选条件
    private void handleAdvancedFilter(BoolQueryBuilder boolMust, JSONArray leftGroup, JSONArray rightGroup, Boolean isOrGroup, String type) {
        DynamicQueryBuilder mainBuilder = new DynamicQueryBuilder();
        EnhancedDynamicQueryBuilder leftBuilder = new EnhancedDynamicQueryBuilder();
        if (!ObjectUtils.isEmpty(leftGroup)) {
            // 处理左侧分组
            JSONObject leftTechParam = new JSONObject();
            JSONObject leftParamRange = new JSONObject();
            JSONArray leftGroupList = new JSONArray();
            // 剥离计数参数
            getTechParam(leftGroup, leftGroupList, leftTechParam, leftParamRange);
            // 如果技术参数和分组不为空，添加技术参数筛选条件到左侧筛选条件中
            if (!ObjectUtils.isEmpty(leftTechParam) && !ObjectUtils.isEmpty(leftParamRange)) {
                addTechParam(leftTechParam, leftParamRange, leftBuilder);
            }
            if (!ObjectUtils.isEmpty(leftGroupList)) {
                // 非计数参数处理
                groupHandler(leftGroupList, leftBuilder, type);
                // 添加左侧筛选条件到最终筛选条件中
                if (isOrGroup) {
                    mainBuilder.or(leftBuilder.build());
                } else {
                    mainBuilder.and(leftBuilder.build());
                }
            }
        }

        if (!ObjectUtils.isEmpty(rightGroup)) {
            // 处理右侧分组
            EnhancedDynamicQueryBuilder rightBuilder = new EnhancedDynamicQueryBuilder();
            JSONObject rightTechParam = new JSONObject();
            JSONObject rightParamRange = new JSONObject();
            JSONArray rightGroupList = new JSONArray();
            // 剥离计数参数
            getTechParam(rightGroup, rightGroupList, rightTechParam, rightParamRange);
            // 如果技术参数和分组不为空，添加技术参数筛选条件到右侧筛选条件中
            if (!ObjectUtils.isEmpty(rightTechParam) && !ObjectUtils.isEmpty(rightParamRange)) {
                addTechParam(rightTechParam, rightParamRange, rightBuilder);
            }
            if (!ObjectUtils.isEmpty(rightGroupList)) {
                // 非计数参数处理
                groupHandler(rightGroupList, rightBuilder, type);
                // 添加右侧筛选条件到最终筛选条件中
                if (isOrGroup) {
                    mainBuilder.or(rightBuilder.build());
                } else {
                    mainBuilder.and(rightBuilder.build());
                }
            }
        }

        // 组装最终筛选条件
        boolMust.must(mainBuilder.build());
    }

    private void addTechParam(JSONObject techParam, JSONObject paramRange, EnhancedDynamicQueryBuilder builder) {
        JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(techParam));
        String field = jsonObject.getString("value");
        JSONObject js = (JSONObject) jsonObject.get("skillConfig");
        String fieldType = js.getString("fieldType");
        String itemCondition = paramRange.getString("itemCondition");
        Object value = null;
        if (paramRange.get("value") instanceof JSONObject) {
            JSONObject jsValue = (JSONObject) paramRange.get("value");
            value = jsValue.get("value");
        } else {
            value = paramRange.get("value");
        }
        String andOr = paramRange.getString("andOr");
        getParamQuery(field, itemCondition, value, fieldType, true, null, builder, andOr);
    }

    private void groupHandler(JSONArray group, EnhancedDynamicQueryBuilder builder, String type) {
        for (int i = 0; i < group.size(); i++) {
            JSONObject itemObj = group.getJSONObject(i);
            String andOr = i == 0 ? null : itemObj.getString("andOr");
            if (group.size() > 1 && i == 0) {
                JSONObject nextItemObj = group.getJSONObject(i + 1);
                andOr = nextItemObj.getString("andOr").equals(or) ? or : and;
            }
            String field = itemObj.getString("field");
            String itemCondition = itemObj.getString("itemCondition");
            Object value = itemObj.get("value");
            // 组装查询条件
            getItemQuery(field, itemCondition, value, andOr, builder, type);
        }
    }

    private void getTechParam(JSONArray group, JSONArray resultGroup, JSONObject techParam, JSONObject paramRange) {
        // 剥离技术参数分组
        group.forEach(item -> {
            JSONObject itemObj = JSONObject.parseObject(JSONObject.toJSONString(item));
            if (itemObj.containsKey("field") && itemObj.containsKey("value") && !"".equals(itemObj.get("value"))) {
                if (!"".equals(itemObj.get("value")) && null != itemObj.get("value") && !"all".equals(itemObj.get("value"))) {
                    if (itemObj.getString("field").equals("techParam")) {
                        techParam.putAll(itemObj);
                    } else if (itemObj.getString("field").equals("paramRange")) {
                        paramRange.putAll(itemObj);
                    } else {
                        resultGroup.add(itemObj);
                    }
                }
            }
        });
    }

    private void getItemQuery(String field, String itemCondition, Object value, String isOr, EnhancedDynamicQueryBuilder builder, String type) {
        // 如果包含需要特殊处理的字段，则调用对应的处理方法，否则调用通用处理方法
        if (equipHandleOtherFields.contains(field) || companyHandleOtherFields.contains(field) || personHandleOtherFields.contains(field)) {
            handleOtherField(field, itemCondition, value, isOr, builder, type);
        } else {
            field = field.equals("nextInspectDate") ? "NEXT_INSPECT_DATE" : field.equals("use_date") ? "USE_DATE" : field;
            String finalField = field;
            if (!itemCondition.contains("gt") && !itemCondition.contains("lt") && !itemCondition.equals("between")) {
                FieldType esType;
                if (StatisticalAnalysisEnum.equip.getCode().equals(type)) {
                    esType = EquipAdvanceSearchEnum.getEsType.get(field);
                } else if (StatisticalAnalysisEnum.company.getCode().equals(type)) {
                    esType = CompanyAdvanceSearchEnum.getEsType.get(field);
                } else {
                    esType = PersonAdvanceSearchEnum.getEsType.get(field);
                }
                finalField = FieldType.Text.equals(esType) ? field + ".keyword" : field;
            }
            switch (itemCondition) {
                case "eq":
                    builder.add(QueryBuilders.termQuery(finalField, value), isOr);
                    break;
                case "neq":
                    builder.add(QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery(finalField, value)), isOr);
                    break;
                case "like":
                    builder.add(QueryBuilders.boolQuery().must(QueryBuilders.wildcardQuery(finalField, "*" + value + "*")), isOr);
                    break;
                case "notLike":
                    builder.add(QueryBuilders.boolQuery().mustNot(QueryBuilders.wildcardQuery(finalField, "*" + value + "*")), isOr);
                    break;
                case "gt":
                    builder.add(QueryBuilders.rangeQuery(finalField).gt(value.toString()), isOr);
                    break;
                case "gte":
                    builder.add(QueryBuilders.rangeQuery(finalField).gte(value.toString()), isOr);
                    break;
                case "lt":
                    builder.add(QueryBuilders.rangeQuery(finalField).lt(value.toString()), isOr);
                    break;
                case "lte":
                    builder.add(QueryBuilders.rangeQuery(finalField).lte(value.toString()), isOr);
                    break;
                case "between":
                    JSONArray btValues = (JSONArray) value;
                    builder.add(QueryBuilders.rangeQuery(finalField).gte(Double.parseDouble(btValues.get(0).toString())).lte(Double.parseDouble(btValues.get(1).toString())), isOr);
                    break;
                case "in":
                    builder.add(QueryBuilders.termsQuery(finalField, value), isOr);
                    break;
                case "notIn":
                    builder.add(QueryBuilders.boolQuery().mustNot(QueryBuilders.termsQuery(finalField, value)), isOr);
                    break;
            }
        }
    }

    // 特殊处理字段
    private void handleOtherField(String field, String itemCondition, Object value, String isOr, EnhancedDynamicQueryBuilder builder, String type) {
        if (equipHandleOtherFields.contains(field) && StatisticalAnalysisEnum.equip.getCode().equals(type)) {
            equipFieldHandle(field, itemCondition, value, isOr, builder);
        } else if (companyHandleOtherFields.contains(field) && StatisticalAnalysisEnum.company.getCode().equals(type)) {
            companyFieldHandle(field, itemCondition, value, isOr, builder);
        } else if ((personHandleOtherFields.contains(field) && StatisticalAnalysisEnum.person.getCode().equals(type))) {
            personFieldHandle(field, itemCondition, value, isOr, builder);
        }
    }

    private void personFieldHandle(String field, String itemCondition, Object value, String isOr, EnhancedDynamicQueryBuilder builder) {
        if (field.equals("newPost") || field.equals("subPost") || field.equals("equipType")) {
            if (itemCondition.equals("eq")) {
                builder.add(QueryBuilders.termQuery(field, value), isOr);
            } else if (itemCondition.equals("in")) {
                builder.add(QueryBuilders.wildcardQuery(field, "*" + value + "*"), isOr);
            } else {
                builder.add(QueryBuilders.boolQuery().mustNot(QueryBuilders.wildcardQuery(field, "*" + value + "*")), isOr);
            }
        } else {
            String path = "licenses";
            String nestedField = path + "." + field;
            // 根据证书编号判断有无资质
            if (field.equals("certNo")) {
                NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                        path,
                        existsQuery(nestedField),
                        ScoreMode.None
                );
                // 无资质查询
                BoolQueryBuilder noCertQuery = tzsCommonService.getNotLicencesBuilderWithPerson();
                // 无资质要求查询
                BoolQueryBuilder noCertRequestQuery = tzsCommonService.getNotNeedLicencesBuilderWithPerson();

                if (value.equals("1")) {
                    if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                        builder.add(nestedQuery, isOr);
                    } else {
                        builder.add(QueryBuilders.boolQuery().mustNot(nestedQuery), isOr);
                    }
                } else if (value.equals("0")) {
                    if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                        EnhancedDynamicQueryBuilder noLicensesQuery = new EnhancedDynamicQueryBuilder();
                        noLicensesQuery.add(QueryBuilders.boolQuery().mustNot(nestedQuery), and);
                        noLicensesQuery.add(noCertQuery, and);
                        builder.add(noLicensesQuery.build(), isOr);
                    } else {
                        EnhancedDynamicQueryBuilder builders = new EnhancedDynamicQueryBuilder();
                        builders.add(nestedQuery, and);
                        builders.add(noCertRequestQuery, and);
                        builder.add(builders.build(), isOr);
                    }
                } else {
                    if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                        builder.add(noCertRequestQuery, isOr);
                    } else {
                        EnhancedDynamicQueryBuilder builders = new EnhancedDynamicQueryBuilder();
                        builders.add(nestedQuery, and);
                        builders.add(noCertQuery, and);
                        builder.add(builders.build(), isOr);
                    }
                }
            } else if (field.equals("expiryDate")) {
                // 无资质到期日期
                NestedQueryBuilder noneQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().mustNot(existsQuery(nestedField)),
                        ScoreMode.None
                );
                // 有资质到期日期
                NestedQueryBuilder existsQuery = QueryBuilders.nestedQuery(
                        path,
                        existsQuery(nestedField),
                        ScoreMode.None
                );
                // 正常资质到期日期
                NestedQueryBuilder normalNestedQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).gt(LocalDate.now().plusDays(30).format(formatter))),
                        ScoreMode.None
                );
                // 超期资质到期日期
                NestedQueryBuilder overdueNestedQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).lt(LocalDate.now().format(formatter))),
                        ScoreMode.None
                );
                // 临期资质到期日期
                NestedQueryBuilder nearNestedQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).lte(LocalDate.now().plusDays(30).format(formatter)).gte(LocalDate.now().format(formatter))),
                        ScoreMode.None
                );
                NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                        path,
                        existsQuery(nestedField),
                        ScoreMode.None
                );
                builder.add(nestedQuery, and);
                if (value.equals(overdue)) {
                    if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                        builder.add(QueryBuilders.boolQuery().must(overdueNestedQuery), isOr);
                    } else {
                        EnhancedDynamicQueryBuilder builders = new EnhancedDynamicQueryBuilder();
                        NestedQueryBuilder otherQuery = QueryBuilders.nestedQuery(
                                path,
                                QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).gte(LocalDate.now().format(formatter))),
                                ScoreMode.None
                        );
                        builders.add(QueryBuilders.boolQuery().must(otherQuery), or);
                        builders.add(QueryBuilders.boolQuery().must(noneQuery), or);
                        builders.add(QueryBuilders.boolQuery().mustNot(overdueNestedQuery), and);
                        builder.add(builders.build(), isOr);
                    }
                } else if (value.equals(near)) {
                    if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                        builder.add(QueryBuilders.boolQuery().must(nearNestedQuery), isOr);
                    } else {
                        EnhancedDynamicQueryBuilder builders = new EnhancedDynamicQueryBuilder();
                        builders.add(QueryBuilders.boolQuery().must(overdueNestedQuery), or);
                        builders.add(QueryBuilders.boolQuery().must(normalNestedQuery), or);
                        builders.add(QueryBuilders.boolQuery().must(noneQuery), or);
                        builders.add(QueryBuilders.boolQuery().mustNot(nearNestedQuery), and);
                        builder.add(builders.build(), isOr);
                    }
                } else if (value.equals(normal)) {
                    if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                        builder.add(normalNestedQuery, isOr);
                    } else {
                        EnhancedDynamicQueryBuilder builders = new EnhancedDynamicQueryBuilder();
                        NestedQueryBuilder otherQuery = QueryBuilders.nestedQuery(
                                path,
                                QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).lte(LocalDate.now().plusDays(30).format(formatter))),
                                ScoreMode.None
                        );
                        builders.add(QueryBuilders.boolQuery().must(otherQuery), or);
                        builders.add(QueryBuilders.boolQuery().must(noneQuery), or);
                        builders.add(QueryBuilders.boolQuery().mustNot(normalNestedQuery), and);
                        builder.add(builders.build(), isOr);
                    }
                } else if (value.equals(none)) {
                    if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                        builder.add(noneQuery, and);
                    } else {
                        builder.add(existsQuery, and);
                    }
                }
            } else if (field.equals("issueDate")) {
                BoolQueryBuilder query = QueryBuilders.boolQuery();
                switch (itemCondition) {
                    case "eq":
                        query.must(QueryBuilders.termQuery(nestedField, value));
                        break;
                    case "lt":
                        query.must(QueryBuilders.rangeQuery(nestedField).lt(value));
                        break;
                    case "lte":
                        query.must(QueryBuilders.rangeQuery(nestedField).lte(value));
                        break;
                    case "gt":
                        query.must(QueryBuilders.rangeQuery(nestedField).gt(value));
                        break;
                    case "gte":
                        query.must(QueryBuilders.rangeQuery(nestedField).gte(value));
                        break;
                }
                NestedQueryBuilder dateQuery = QueryBuilders.nestedQuery(
                        path,
                        query,
                        ScoreMode.None
                );
                builder.add(dateQuery, isOr);
            } else {
                NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.wildcardQuery(nestedField, "*" + value + "*"),
                        ScoreMode.None
                );
                if (itemCondition.equals("eq")) {
                    NestedQueryBuilder eqNestedQuery = QueryBuilders.nestedQuery(
                            path,
                            QueryBuilders.termQuery(nestedField, value),
                            ScoreMode.None
                    );
                    builder.add(eqNestedQuery, isOr);
                } else if (itemCondition.equals("in")) {
                    builder.add(nestedQuery, isOr);
                } else {
                    builder.add(QueryBuilders.boolQuery().mustNot(nestedQuery), isOr);
                }
            }
        }
    }

    private void companyFieldHandle(String field, String itemCondition, Object value, String isOr, EnhancedDynamicQueryBuilder builder) {
        if (field.equals("itemCode") || field.equals("subItemCode") || field.equals("permitStatus") || field.equals("expiryDate")) {
            String path = "licenses";
            String nestedField = path + "." + (field.equals("permitStatus") || field.equals("expiryDate") ? "expiryDate" : field + ".keyword");
            if (field.equals("permitStatus")) {
                // 无许可到期日期
                NestedQueryBuilder noneQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().mustNot(existsQuery(nestedField)),
                        ScoreMode.None
                );
                // 有许可到期日期
                NestedQueryBuilder existsQuery = QueryBuilders.nestedQuery(
                        path,
                        existsQuery(nestedField),
                        ScoreMode.None
                );
                // 正常许可到期日期
                NestedQueryBuilder normalNestedQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).gt(LocalDate.now().plusDays(30).format(formatter))),
                        ScoreMode.None
                );
                // 超期许可到期日期
                NestedQueryBuilder overdueNestedQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).lt(LocalDate.now().format(formatter))),
                        ScoreMode.None
                );
                // 临期许可到期日期
                NestedQueryBuilder nearNestedQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).lte(LocalDate.now().plusDays(30).format(formatter)).gte(LocalDate.now().format(formatter))),
                        ScoreMode.None
                );
                if (value.equals(overdue)) {
                    if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                        builder.add(QueryBuilders.boolQuery().must(overdueNestedQuery), isOr);
                    } else {
                        EnhancedDynamicQueryBuilder builders = new EnhancedDynamicQueryBuilder();
                        NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                path,
                                QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).gte(LocalDate.now().format(formatter))),
                                ScoreMode.None
                        );
                        builders.add(QueryBuilders.boolQuery().must(nestedQuery), or);
                        builders.add(QueryBuilders.boolQuery().must(noneQuery), or);
                        builders.add(QueryBuilders.boolQuery().mustNot(overdueNestedQuery), and);
                        builder.add(builders.build(), isOr);
                    }
                } else if (value.equals(near)) {
                    if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                        builder.add(QueryBuilders.boolQuery().must(nearNestedQuery), isOr);
                    } else {
                        EnhancedDynamicQueryBuilder builders = new EnhancedDynamicQueryBuilder();
                        builders.add(QueryBuilders.boolQuery().must(overdueNestedQuery), or);
                        builders.add(QueryBuilders.boolQuery().must(normalNestedQuery), or);
                        builders.add(QueryBuilders.boolQuery().must(noneQuery), or);
                        builders.add(QueryBuilders.boolQuery().mustNot(nearNestedQuery), and);
                        builder.add(builders.build(), isOr);
                    }
                } else if (value.equals(normal)) {
                    if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                        builder.add(normalNestedQuery, isOr);
                    } else {
                        EnhancedDynamicQueryBuilder builders = new EnhancedDynamicQueryBuilder();
                        NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                path,
                                QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).lte(LocalDate.now().plusDays(30).format(formatter))),
                                ScoreMode.None
                        );
                        builders.add(QueryBuilders.boolQuery().must(nestedQuery), or);
                        builders.add(QueryBuilders.boolQuery().must(noneQuery), or);
                        builders.add(QueryBuilders.boolQuery().mustNot(normalNestedQuery), and);
                        builder.add(builders.build(), isOr);
                    }
                } else if (value.equals(none)) {
                    if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                        builder.add(noneQuery, and);
                    } else {
                        builder.add(existsQuery, and);
                    }
                }
            } else if (field.equals("expiryDate")) {
                BoolQueryBuilder query = QueryBuilders.boolQuery();
                switch (itemCondition) {
                    case "eq":
                        query.must(QueryBuilders.termQuery(nestedField, value));
                        break;
                    case "lt":
                        query.must(QueryBuilders.rangeQuery(nestedField).lt(value));
                        break;
                    case "lte":
                        query.must(QueryBuilders.rangeQuery(nestedField).lte(value));
                        break;
                    case "gt":
                        query.must(QueryBuilders.rangeQuery(nestedField).gt(value));
                        break;
                    case "gte":
                        query.must(QueryBuilders.rangeQuery(nestedField).gte(value));
                        break;
                }
                NestedQueryBuilder dateQuery = QueryBuilders.nestedQuery(
                        path,
                        query,
                        ScoreMode.None
                );
                builder.add(dateQuery, isOr);
            } else {
                if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                    // 创建嵌套查询
                    NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                            path,
                            QueryBuilders.termsQuery(nestedField, value),
                            ScoreMode.None
                    );
                    builder.add(QueryBuilders.boolQuery().must(nestedQuery), isOr);
                } else {
                    NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                            path,
                            QueryBuilders.termsQuery(nestedField, value),
                            ScoreMode.None
                    );
                    builder.add(QueryBuilders.boolQuery().mustNot(nestedQuery), isOr);
                }
            }
        } else {
            if (itemCondition.equals("eq")) {
                builder.add(QueryBuilders.termQuery(field + ".keyword", value), isOr);
            } else if (itemCondition.equals("in")) {
                builder.add(QueryBuilders.wildcardQuery(field + ".keyword", "*" + value + "*"), isOr);
            } else {
                builder.add(QueryBuilders.boolQuery().mustNot(QueryBuilders.wildcardQuery(field + ".keyword", "*" + value + "*")), isOr);
            }
        }
    }

    private void equipFieldHandle(String field, String itemCondition, Object value, String isOr, EnhancedDynamicQueryBuilder builder) {
        if (field.equals("NEXT_INSPECT_DATE")) {
            BoolQueryBuilder overdueQuery = QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(field).lt(LocalDate.now().format(formatter)));
            BoolQueryBuilder nearQuery = QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(field).gte(LocalDate.now().format(formatter)).lte(LocalDate.now().plusDays(30).format(formatter)));
            BoolQueryBuilder normalQuery = QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(field).gt(LocalDate.now().plusDays(30).format(formatter)));
            BoolQueryBuilder noneQuery = QueryBuilders.boolQuery().mustNot(existsQuery(field));
            DynamicQueryBuilder builders = new DynamicQueryBuilder();
            if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                if (value.equals(overdue)) {
                    builder.add(overdueQuery, isOr);
                } else if (value.equals(near)) {
                    builder.add(nearQuery, isOr);
                } else if (value.equals(normal)) {
                    builder.add(normalQuery, isOr);
                } else {
                    builder.add(noneQuery, isOr);
                }
            } else {
                if (value.equals(overdue)) {
                    builders.or(nearQuery);
                    builders.or(normalQuery);
                    builders.or(noneQuery);
                    builder.add(builders.build(), isOr);
                } else if (value.equals(near)) {
                    builders.or(overdueQuery);
                    builders.or(normalQuery);
                    builders.or(noneQuery);
                    builder.add(builders.build(), isOr);
                } else if (value.equals(normal)) {
                    builders.or(overdueQuery);
                    builders.or(nearQuery);
                    builders.or(noneQuery);
                    builder.add(builders.build(), isOr);
                } else {
                    builder.add(QueryBuilders.boolQuery().must(existsQuery(field)), isOr);
                }
            }
        } else if (field.equals("USE_DATE")) {
            if (value.equals("15")) {
                // 15年以上：大于当前日期减去15年
                if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                    builder.add(QueryBuilders.rangeQuery(field).gt(LocalDate.now().minusYears(15).format(formatter)), isOr);
                } else {
                    builder.add(QueryBuilders.rangeQuery(field).lte(LocalDate.now().minusYears(15).format(formatter)), isOr);
                }
            } else if (value.equals("10-15")) {
                // 10-15年：小于当前日期减去15年，大于等于当前日期减去10年
                if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                    builder.add(QueryBuilders.rangeQuery(field).lt(LocalDate.now().minusYears(15).format(formatter)).gte(LocalDate.now().minusYears(10).format(formatter)), isOr);
                } else {
                    builder.add(QueryBuilders.rangeQuery(field).gte(LocalDate.now().minusYears(15).format(formatter)), or);
                    builder.add(QueryBuilders.rangeQuery(field).lte(LocalDate.now().minusYears(10).format(formatter)), or);
                }
            } else if (value.equals("5-10")) {
                // 5-10年：小于当前日期减去10年，大于等于当前日期减去5年
                if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                    builder.add(QueryBuilders.rangeQuery(field).lt(LocalDate.now().minusYears(10).format(formatter)).gte(LocalDate.now().minusYears(5).format(formatter)), isOr);
                } else {
                    builder.add(QueryBuilders.rangeQuery(field).gte(LocalDate.now().minusYears(10).format(formatter)), or);
                    builder.add(QueryBuilders.rangeQuery(field).lte(LocalDate.now().minusYears(5).format(formatter)), or);
                }
            } else if (value.equals("0-5")) {
                // 0-5年：小于当前日期减去5年
                if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                    builder.add(QueryBuilders.rangeQuery(field).lt(LocalDate.now().minusYears(5).format(formatter)), isOr);
                } else {
                    builder.add(QueryBuilders.rangeQuery(field).gte(LocalDate.now().minusYears(5).format(formatter)), isOr);
                }
            }
        } else if (field.equals("JDJY") || field.equals("DQJY") || field.equals("SCJY") || field.equals("DTJY")) {
            String path = "inspections";
            String typeField = path + ".inspectType";
            String dateField = path + ".inspectDate";
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
            if (field.equals("JDJY")) {
                queryBuilder.must(QueryBuilders.wildcardQuery(typeField, "*JDJY*"));
            } else {
                queryBuilder.must(QueryBuilders.termsQuery(typeField, field));
            }
            EnhancedDynamicQueryBuilder queryBuilders = new EnhancedDynamicQueryBuilder();
            NestedQueryBuilder fieldQuery = QueryBuilders.nestedQuery(
                    path,
                    queryBuilder,
                    ScoreMode.None
            );
            queryBuilders.add(fieldQuery, and);
            BoolQueryBuilder query = QueryBuilders.boolQuery();
            switch (itemCondition) {
                case "lt":
                    query.must(QueryBuilders.rangeQuery(dateField).lt(value));
                    break;
                case "lte":
                    query.must(QueryBuilders.rangeQuery(dateField).lte(value));
                    break;
                case "gt":
                    query.must(QueryBuilders.rangeQuery(dateField).gt(value));
                    break;
                case "gte":
                    query.must(QueryBuilders.rangeQuery(dateField).gte(value));
                    break;
            }
            NestedQueryBuilder dateQuery = QueryBuilders.nestedQuery(
                    path,
                    query,
                    ScoreMode.None
            );
            queryBuilders.add(dateQuery, and);
            builder.add(queryBuilders.build(), isOr);
        } else if (field.equals("QZ_OR_TANK")) {
            if (!"".equals(value) && value != null) {
                if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                    builder.add(QueryBuilders.matchQuery(value.toString(), "1"), isOr);
                } else {
                    builder.add(QueryBuilders.matchQuery(value.toString(), "0"), isOr);
                }
            }
        } else if (field.equals("registerStatus")) {
            BoolQueryBuilder registerQuery = QueryBuilders.boolQuery().must(QueryBuilders.termsQuery("IS_INTO_MANAGEMENT", Boolean.TRUE))
                    .must(existsQuery("USE_ORG_CODE"))
                    .mustNot(QueryBuilders.termQuery("USE_ORG_CODE", ""));
            BoolQueryBuilder noRegisterQuery = QueryBuilders.boolQuery()
                    .should(QueryBuilders.boolQuery().mustNot(existsQuery("IS_INTO_MANAGEMENT")))
                    .should(QueryBuilders.termQuery("IS_INTO_MANAGEMENT", Boolean.FALSE))
                    .should(QueryBuilders.boolQuery().mustNot(existsQuery("USE_ORG_CODE")))
                    .should(QueryBuilders.termQuery("USE_ORG_CODE", ""))
                    .minimumShouldMatch(1);
            if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                if (value.equals("1")) {
                    builder.add(registerQuery, isOr);
                } else {
                    builder.add(noRegisterQuery, isOr);
                }
            } else {
                if (value.equals("1")) {
                    builder.add(noRegisterQuery, isOr);
                } else {
                    builder.add(registerQuery, isOr);
                }
            }
        } else if (field.equals("EQU_STATE")) {
            if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                if (!value.equals("99")) {
                    builder.add(QueryBuilders.termQuery(field, value), isOr);
                } else {
                    builder.add(QueryBuilders.boolQuery().mustNot(existsQuery(field)), isOr);
                }
            } else {
                if (!value.equals("99")) {
                    DynamicQueryBuilder dynamicQueryBuilder = new DynamicQueryBuilder();
                    dynamicQueryBuilder.or(QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery(field, value)));
                    dynamicQueryBuilder.or(QueryBuilders.boolQuery().mustNot(existsQuery(field)));
                    builder.add(dynamicQueryBuilder.build(), isOr);
                } else {
                    builder.add(QueryBuilders.boolQuery().must(existsQuery(field)), isOr);
                }
            }
        }
    }


    public JSONArray queryUnitType(String type) {
        return UnitTypeNewEnum.getUnitTypeByType(type);
    }

    public JSONObject queryCompanySearchData(String type) {
        JSONObject result = new JSONObject();
        //获取企业分类
        result.put("unitCategory", getUnitCategory());
        //获取企业类型
        result.put("unitType", UnitTypeNewEnum.getUnitTypeByType(type));

        //获取企业等级
        result.put("regulatoryLabels", deployDictionary(dataDictionaryService.getByType("QYBQ")));

        //行业主管部门
        result.put("industrySupervisor", deployDictionary(dataDictionaryService.getByType("HYZGBM")));
        //经营状态
        result.put("operatingStatus", deployDictionaryNew(dataDictionaryService.getByType("jyzt")));

        //许可状态
        result.put("permitStatus", getPermitStatus());

        //监管设备类型
        Map<String, List<Map<String, Object>>> resourceJson = JsonUtils.getResourceJson(equipCategory);
        List<Map<String, Object>> equipCategory = resourceJson.get(EquipmentClassifityEnum.ZHTJFX.getCode());
        result.put("equipCategory", equipCategory);

        return result;
    }

    public JSONArray getPermitStatus() {
        JSONArray permitStatus = new JSONArray();
        for (int i = 0; i < 4; i++) {
            JSONObject object = new JSONObject();
            if (0 == i) {
                object.put("key", normal);
                object.put("value", normal);
                object.put("label", permitStatusMap.get(normal));
            } else if (1 == i) {
                object.put("key", near);
                object.put("value", near);
                object.put("label", permitStatusMap.get(near));
            } else if (2 == i) {
                object.put("key", overdue);
                object.put("value", overdue);
                object.put("label", permitStatusMap.get(overdue));
            } else {
                object.put("key", none);
                object.put("value", none);
                object.put("label", permitStatusMap.get(none));
            }
            permitStatus.add(object);
        }
        return permitStatus;
    }


    private static JSONArray getUnitCategory() {
        JSONArray unitCategory = new JSONArray();
        for (int i = 0; i < 3; i++) {
            JSONObject object = new JSONObject();
            if (0 == i) {
                object.put("key", "all");
                object.put("value", "all");
                object.put("label", "全部");
            } else if (1 == i) {
                object.put("key", "use");
                object.put("value", "use");
                object.put("label", "使用单位");
            } else {
                object.put("key", "license");
                object.put("value", "license");
                object.put("label", "许可单位");
            }
            unitCategory.add(object);
        }
        return unitCategory;
    }

    public JSONObject queryPersonSearchData(String type) {
        JSONObject result = new JSONObject();
        //有无资质
        JSONArray certNoData = new JSONArray();
        for (int i = 0; i < 3; i++) {
            JSONObject object = new JSONObject();
            if (0 == i) {
                object.put("key", "2");
                object.put("value", "2");
                object.put("label", "无资质要求");
            } else if (1 == i) {
                object.put("key", "1");
                object.put("value", "1");
                object.put("label", "有资质");
            } else if (2 == i) {
                object.put("key", "0");
                object.put("value", "0");
                object.put("label", "无资质");
            }
            certNoData.add(object);
        }
        result.put("certNo", certNoData);
        //资质状态
        result.put("expiryDate", queryExpiryDate());
        //证书类型
        List<DictionarieValueModel> certType = Systemctl.dictionarieClient.dictValues("CERT_TYPE").getResult();
        JSONArray certTypeArray = new JSONArray();
        for (int i = 0; i < certType.size(); i++) {
            JSONObject object = new JSONObject();
            object.put("key", certType.get(i).getDictDataKey());
            object.put("value", certType.get(i).getDictDataKey());
            object.put("label", certType.get(i).getDictDataValue());
            certTypeArray.add(object);
        }
        result.put("certType", certTypeArray);
        //证书级别
        List<DictionarieValueModel> RYJB_JC = Systemctl.dictionarieClient.dictValues("RYJB_JC").getResult();
        List<DictionarieValueModel> RYJB_JY = Systemctl.dictionarieClient.dictValues("RYJB_JY").getResult();
        JSONArray permissionLevelArray = new JSONArray();
        for (int i = 0; i < RYJB_JC.size(); i++) {
            JSONObject object = new JSONObject();
            object.put("key", RYJB_JC.get(i).getDictDataKey());
            object.put("value", RYJB_JC.get(i).getDictDataKey());
            object.put("label", RYJB_JC.get(i).getDictDataValue());
            permissionLevelArray.add(object);
        }
        for (int i = 0; i < RYJB_JY.size(); i++) {
            JSONObject object = new JSONObject();
            object.put("key", RYJB_JY.get(i).getDictDataKey());
            object.put("value", RYJB_JY.get(i).getDictDataKey());
            object.put("label", RYJB_JY.get(i).getDictDataValue());
            permissionLevelArray.add(object);
        }
        result.put("permissionLevel", permissionLevelArray);
        //学历
        result.put("education", deployDictionary(dataDictionaryService.getByType("QYRYXL")));
        //监管设备类型
        Map<String, List<Map<String, Object>>> resourceJson = JsonUtils.getResourceJson(equipCategory);
        List<Map<String, Object>> equipCategory = resourceJson.get(EquipmentClassifityEnum.ZHTJFX.getCode());
        result.put("equipType", equipCategory);
        //获取企业分类
        result.put("unitCategory", getUnitCategory());
        //获取企业类型
        result.put("unitType", UnitTypeNewEnum.getUnitTypeByType(type));
        return result;
    }

    public JSONArray deployDictionary(List<DataDictionary> list) {
        JSONArray result = new JSONArray();
        for (int i = 0; i < list.size(); i++) {
            JSONObject object = new JSONObject();
            object.put("key", list.get(i).getCode());
            object.put("value", list.get(i).getCode());
            object.put("label", list.get(i).getName());
            object.put("extendCode", list.get(i).getExtend());
            result.add(object);
        }

        return result;
    }

    /**
     * 特殊处理字典，value为name
     *
     * @param list
     * @return
     */
    public JSONArray deployDictionaryNew(List<DataDictionary> list) {
        list = list.stream().sorted(Comparator.comparing(DataDictionary::getSortNum)).collect(Collectors.toList());
        JSONArray result = new JSONArray();
        for (int i = 0; i < list.size(); i++) {
            JSONObject object = new JSONObject();
            object.put("key", list.get(i).getCode());
            object.put("value", list.get(i).getName());
            object.put("label", list.get(i).getName());
            result.add(object);
        }

        return result;
    }

    public JSONArray queryXK(String type) {
        JSONArray result = new JSONArray();
        if (ValidationUtil.isEmpty(type)) {
            List<DataDictionary> xkxm = dataDictionaryService.lambdaQuery().like(DataDictionary::getType, "XKXM").eq(BaseEntity::getIsDelete, false).list();
            result = deployDictionary(xkxm);
        } else {
            List<DataDictionary> childrenxkxm = dataDictionaryService.lambdaQuery().eq(DataDictionary::getTypeDesc, type).eq(BaseEntity::getIsDelete, false).list();
            result = deployDictionary(childrenxkxm);
        }
        return result;
    }

    public JSONArray querySubXK(String type) {
        JSONArray result = new JSONArray();
        List<DataDictionary> childrenxkxm = new ArrayList<>();
        if (ValidationUtil.isEmpty(type)) {
//            childrenxkxm = dataDictionaryService.lambdaQuery()
//                    .likeRight(DataDictionary::getCode, "XK")
//                    .isNotNull(DataDictionary::getTypeDesc)
//                    .eq(BaseEntity::getIsDelete, false).list();
            throw new BaseException("请先选择许可项目，才能选择子许可项目", "200", "请先选择许可项目，才能选择子许可项目");
        } else {
            childrenxkxm = dataDictionaryService.lambdaQuery().eq(DataDictionary::getTypeDesc, type).eq(BaseEntity::getIsDelete, false).list();
        }
        result = deployDictionary(childrenxkxm);
        return result;
    }


    public JSONArray queryRYLX(JSONObject params) {
        JSONArray result = new JSONArray();

        JSONArray unitType = params.containsKey("unitType") && !"".equals(params.get("unitType")) ? JSONObject.parseArray(JSONObject.toJSONString(params.get("unitType"))) : new JSONArray();
        String newPost = params.containsKey("newPost") ? params.get("newPost").toString() : "";

        List<String> typeList = new ArrayList<>(Arrays.asList(
                "QYRYGW",
                "QYRYGW-SYDW",
                "QYRYGW-SCDW",
                "QYRYGW-INSTALL",
                "QYRYGW-INSPECTION"
        ));
        List<DataDictionary> allPost = dataDictionaryService.lambdaQuery()
                .select(DataDictionary::getName, DataDictionary::getCode)
                .eq(DataDictionary::getIsDelete, false)
                .isNull(DataDictionary::getParent)
                .in(DataDictionary::getType, typeList)
                .list();

        if (!"".equals(newPost)) {
            List<DataDictionary> childrenrylx = dataDictionaryService.lambdaQuery()
                    .in(DataDictionary::getParent, newPost)
                    .like(DataDictionary::getType, "QYRYGW")
                    .orderByAsc(DataDictionary::getSortNum)
                    .list();
            result = deployDictionary(childrenrylx);
        }

        if (!ObjectUtils.isEmpty(unitType) && !unitType.contains("all")) {
            try {
                ArrayList<String> postDictCodeList = new ArrayList<>();
                JsonNode jsonNode = new ObjectMapper().readTree(unitTypeLimitUserType.getInputStream());
                unitType.forEach(item -> {
                    JsonNode companyTypeNode = jsonNode.get(item.toString());
                    if (companyTypeNode != null && companyTypeNode.isObject()) {
                        Iterator<Map.Entry<String, JsonNode>> fields = companyTypeNode.fields();
                        while (fields.hasNext()) {
                            Map.Entry<String, JsonNode> entry = fields.next();
                            String postCode = entry.getKey();
                            postDictCodeList.add(postCode); // 主岗位
                        }
                    }
                });
                result = deployDictionary(allPost.stream()
                        .filter(item -> postDictCodeList.contains(item.getCode()))
                        .collect(Collectors.toList()));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        if ("".equals(newPost) && (ObjectUtils.isEmpty(unitType) || unitType.contains("all"))) {
            result = deployDictionary(allPost);
        }

        return result;
    }

    public JSONArray queryRYLX(String type) {
        JSONArray result = new JSONArray();
        if (ValidationUtil.isEmpty(type)) {
            List<String> typeList = new ArrayList<>(Arrays.asList(
                    "QYRYGW",
                    "QYRYGW-SYDW",
                    "QYRYGW-SCDW",
                    "QYRYGW-INSTALL",
                    "QYRYGW-INSPECTION"
            ));
            result = deployDictionary(dataDictionaryService.lambdaQuery()
                    .select(DataDictionary::getName, DataDictionary::getCode)
                    .eq(DataDictionary::getIsDelete, false)
                    .isNull(DataDictionary::getParent)
                    .in(DataDictionary::getType, typeList)
                    .list());
        } else {
            List<DataDictionary> childrenrylx = dataDictionaryService.lambdaQuery()
                    .in(DataDictionary::getParent, type)
                    .like(DataDictionary::getType, "QYRYGW")
                    .orderByAsc(DataDictionary::getSortNum)
                    .list();
            ;
            result = deployDictionary(childrenrylx);
        }
        return result;
    }

    public JSONArray querySubRYLX(String type) {
        JSONArray result = new JSONArray();
        if (ValidationUtil.isEmpty(type)) {
            throw new BaseException("请先选择人员类型，才能选择子类型", "200", "请先选择人员类型，才能选择子类型");
        } else {
            List<DataDictionary> childrenrylx = dataDictionaryService.lambdaQuery()
                    .in(DataDictionary::getParent, type)
                    .like(DataDictionary::getType, "QYRYGW")
                    .orderByAsc(DataDictionary::getSortNum)
                    .list();
            result = deployDictionary(childrenrylx);
        }
        return result;
    }

    /**
     * 开始下载 发送消息
     */
    public void startDownLoadMsg(String fileName, String uuid) {
        try {
            emqKeeper.getMqttClient().publish(String.format(DOWNLOAD_TOPIC, RequestContext.getToken()),
                    String.format(DOWN_LOAD_START_TEMP, uuid, fileName, new Date().getTime()).getBytes(StandardCharsets.UTF_8),
                    2, false);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    /**
     * 发送主题消息，给企业推送excel 结束下载提醒
     *
     * @param topic      主体格式为： /download/excel/${token}
     * @param jsonObject 文件名称 + excel文件路径（minio）
     */
    public void sendDownLoadExcelMsg(String topic, JSONObject jsonObject) {
        try {
            emqKeeper.getMqttClient().publish(topic, JSONObject.toJSONString(jsonObject).getBytes(StandardCharsets.UTF_8), 2, false);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    /**
     * 综合统计分析接口-导出
     *
     * @param filter 过滤条件
     */
    public void export(JSONObject filter) {
        String uuid = UUID.randomUUID().toString();
        // 业务类型
        String businessType = filter.getString("businessType");
        // fileName
        String fileName = "综合统计分析-" + StatisticalAnalysisEnum.getEnumByCode(businessType).getName() + "数据";
        // sheetName
        String sheetName = "综合统计分析-" + StatisticalAnalysisEnum.getEnumByCode(businessType).getName() + "列表";
        // 开始下载提醒
        this.startDownLoadMsg(fileName, uuid);
        // 查询数据
        JSONArray records = this.exportDataAsyncBatchSearch(filter);
        MultipartFile templateExcelFile;
        // 数据转化 + 附件生成
        if (StatisticalAnalysisEnum.equip.getCode().equals(businessType)) {
            templateExcelFile = getEquipMultipartFile(records, fileName, sheetName);
        } else if (StatisticalAnalysisEnum.company.getCode().equals(businessType)) {
            templateExcelFile = getCompanyMultipartFile(records, fileName, sheetName);
        } else {
            templateExcelFile = getPersonMultipartFile(records, fileName, sheetName);
        }
        // 上传minio服务器
        String urlString = MinioUtils.uploadExcelFile(templateExcelFile, BUCKET_NAME, UPLOAD_PATH);
        // 提醒下载
        this.sendDownLoadExcelMsg(String.format(DOWNLOAD_TOPIC, RequestContext.getToken()), new JSONObject()
                .fluentPut("id", uuid)
                .fluentPut("status", "done")
                .fluentPut("fileName", fileName)
                .fluentPut("url", urlString)
                .fluentPut("time", new Date().getTime()));
    }

    public JSONArray exportDataAsyncBatchSearch1(JSONObject filter) {
        JSONArray result = new JSONArray();
        int pageSize = 1000;
        // 查询首页数据
        filter.fluentPut("size", pageSize).fluentPut("current", 1);
        JSONObject jsonData1 = this.queryForPage(filter);
        // 获取 result -> pageData -> records
        JSONObject pageData1 = jsonData1.getJSONObject("pageData");
        JSONArray records1 = pageData1.getJSONArray("records");
        result.addAll(records1);

        long total = pageData1.getLong("total");
        int totalPage = (int) Math.ceil((double) total / pageSize);

        // 用于收集所有分页结果
        List<CompletableFuture<JSONArray>> futures = new ArrayList<>();

        RequestContextWrapper contextWrapper = RequestContextWrapper.capture();
        // 多线程处理从第2页开始的数据
        for (int i = 2; i <= totalPage; i++) {
            int pageIndex = i;
            CompletableFuture<JSONArray> future = CompletableFuture.supplyAsync(() -> {
                // 恢复上下文到子线程
                contextWrapper.apply();
                filter.fluentPut("size", pageSize).fluentPut("current", pageIndex);
                JSONObject jsonData2 = this.queryForPage(filter);
                // 获取 result -> pageData -> records
                JSONObject pageData2 = jsonData2.getJSONObject("pageData");
                return pageData2.getJSONArray("records");
            }, executorService);
            futures.add(future);
        }

        // 等待所有线程完成
        for (CompletableFuture<JSONArray> future : futures) {
            try {
                result.addAll(future.get());
            } catch (InterruptedException | ExecutionException e) {
                log.error("分页查询线程执行失败", e);
            }
        }
        return result;
    }

    public JSONArray exportDataAsyncBatchSearch(JSONObject filter) {
        JSONArray result = new JSONArray();
        int batchSize = 5000; // 每页记录数，根据数据量可调大一些

        // 查询第一页
        filter.fluentPut("size", batchSize).fluentPut("current", 1);
        JSONObject firstPage = this.queryForPage(filter);
        JSONObject pageData = firstPage.getJSONObject("pageData");
        result.addAll(pageData.getJSONArray("records"));

        long total = pageData.getLong("total");
        int totalPage = (int) Math.ceil((double) total / batchSize);
        if (totalPage <= 1) return result; // 只有一页，直接返回

        RequestContextWrapper contextWrapper = RequestContextWrapper.capture();

        // 计算批次，每批处理 N 页，减少线程压力
        int batchThreads = Math.min(totalPage - 1, Runtime.getRuntime().availableProcessors());
        int pagesPerThread = (int) Math.ceil((double)(totalPage - 1) / batchThreads);

        List<CompletableFuture<JSONArray>> futures = new ArrayList<>();

        for (int i = 0; i < batchThreads; i++) {
            int startPage = 2 + i * pagesPerThread;
            int endPage = Math.min(startPage + pagesPerThread - 1, totalPage);

            CompletableFuture<JSONArray> future = CompletableFuture.supplyAsync(() -> {
                contextWrapper.apply(); // 恢复上下文一次
                JSONArray batchResult = new JSONArray();
                for (int page = startPage; page <= endPage; page++) {
                    filter.fluentPut("current", page);
                    JSONObject pageJson = this.queryForPage(filter);
                    JSONArray records = pageJson.getJSONObject("pageData").getJSONArray("records");
                    batchResult.addAll(records);
                }
                return batchResult;
            }, executorService);

            futures.add(future);
        }

        // 等待所有线程完成
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

        // 收集结果
        for (CompletableFuture<JSONArray> future : futures) {
            try {
                result.addAll(future.get());
            } catch (Exception e) {
                log.error("分页查询线程执行失败", e);
            }
        }
        return result;
    }

    private static MultipartFile getEquipMultipartFile(JSONArray records, String fileName, String sheetName) {
        // 临时文件
        File tempFile = new File(System.getProperty("java.io.tmpdir"), fileName + ".xlsx");

        ExcelWriter excelWriter = null;
        try {
            excelWriter = EasyExcel.write(tempFile, EquipInfoVo.class)
                    .excelType(ExcelTypeEnum.XLSX)
                    .build();

            WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();

            List<EquipInfoVo> batchData = new ArrayList<>(1000); // 每批 1000 条

            for (Object record : records) {
                JSONObject equip = (JSONObject) record;
                Map<String, Object> combinedMap = new HashMap<>();

                // 基础字段
                equip.forEach((k, v) -> combinedMap.put(k, v != null ? String.valueOf(v) : null));

                // 最新检验
                JSONArray inspections = equip.getJSONArray("inspections");
                if (inspections != null && !inspections.isEmpty()) {
                    JSONObject inspection = inspections.getJSONObject(0);
                    inspection.forEach((k, v) -> combinedMap.put(k, v != null ? String.valueOf(v) : null));
                }

                // 最新维保
                JSONArray maintenances = equip.getJSONArray("maintenances");
                if (maintenances != null && !maintenances.isEmpty()) {
                    JSONObject maintenance = maintenances.getJSONObject(0);
                    maintenance.forEach((k, v) -> combinedMap.put(k, v != null ? String.valueOf(v) : null));
                }

                // RECORD 特殊逻辑
                if ("3000".equals(String.valueOf(equip.get("EQU_LIST_CODE"))) &&
                        String.valueOf(equip.get("DATA_SOURCE")).contains("jg_his_xa")) {
                    combinedMap.put("RECORD", String.valueOf(equip.get("SEQUENCE_NBR")));
                }

                // 技术参数
                JSONArray techParams = equip.getJSONArray("techParams");
                if (techParams != null && !techParams.isEmpty()) {
                    for (int k = 0; k < techParams.size(); k++) {
                        JSONObject param = techParams.getJSONObject(k);
                        String key = param.getString("paramKey");
                        if (key == null) continue;

                        Object value = param.getOrDefault("strValue",
                                param.getOrDefault("boolValue",
                                        param.getOrDefault("dateValue",
                                                param.getOrDefault("longValue",
                                                        param.get("doubleValue")))));

                        if (value != null) {
                            combinedMap.put(key, String.valueOf(value));
                        }
                    }
                }

                // Map → VO，并过滤非法日期
                EquipInfoVo vo = new EquipInfoVo();
                combinedMap.replaceAll((k, v) -> {
                    if (v != null && v.toString().startsWith("-0001")) return null; // 过滤非法日期
                    return v;
                });
                BeanUtil.copyProperties(combinedMap, vo, CopyOptions.create().setIgnoreNullValue(true));

                batchData.add(vo);

                // 批量写入
                if (batchData.size() >= 1000) {
                    excelWriter.write(batchData, writeSheet);
                    batchData.clear();
                }
            }

            // 写入剩余数据
            if (!batchData.isEmpty()) {
                excelWriter.write(batchData, writeSheet);
            }

        } catch (Exception e) {
            throw new RuntimeException("生成Excel失败", e);
        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }

        // 返回 MultipartFile
        try {
            return new ByteArrayMultipartFile(
                    fileName,
                    fileName + ".xlsx",
                    "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                    Files.readAllBytes(tempFile.toPath())
            );
        } catch (IOException e) {
            throw new RuntimeException("Excel文件读取失败", e);
        } finally {
            tempFile.delete();
        }
    }

    private static MultipartFile getCompanyMultipartFile(JSONArray records, String fileName, String sheetName) {
        MultipartFile templateExcelFile;
        List<CompanyInfoVo> exportData = new ArrayList<>();
        records.forEach(company -> {
            String jsonString = JSON.toJSONString(company);
            CompanyInfoVo companyInfoVo = JSONObject.parseObject(jsonString, CompanyInfoVo.class);
            JSONArray licenses = JSON.parseArray(JSON.toJSONString(JSON.parseObject(jsonString).get("licenses")));
            if (!ObjectUtils.isEmpty(licenses)) {
                licenses.forEach(lic -> {
                    JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(lic));
                    CompanyInfoVo temp = jsonObject.toJavaObject(CompanyInfoVo.class);
                    BeanUtil.copyProperties(companyInfoVo, temp, CopyOptions.create().setIgnoreNullValue(true));
                    exportData.add(temp);
                });
            } else {
                exportData.add(companyInfoVo);
            }
        });
        templateExcelFile = ExcelUtil.createTemplateExcelFile(fileName, sheetName, exportData, CompanyInfoVo.class, null, false);
        return templateExcelFile;
    }

    private static MultipartFile getPersonMultipartFile(JSONArray records, String fileName, String sheetName) {
        MultipartFile templateExcelFile;
        List<PersonVo> exportData = new ArrayList<>();
        records.forEach(company -> {
            String jsonString = JSON.toJSONString(company);
            PersonVo personVo = JSONObject.parseObject(jsonString, PersonVo.class);
            JSONArray licenses = JSON.parseArray(JSON.toJSONString(JSON.parseObject(jsonString).get("licenses")));
            if (!licenses.isEmpty()) {
                licenses.forEach(lic -> {
                    JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(lic));
                    PersonVo temp = jsonObject.toJavaObject(PersonVo.class);
                    BeanUtil.copyProperties(personVo, temp, CopyOptions.create().setIgnoreNullValue(true));
                    exportData.add(temp);
                });
            } else {
                exportData.add(personVo);
            }
        });
        templateExcelFile = ExcelUtil.createTemplateExcelFile(fileName, sheetName, exportData, PersonVo.class, null, false);
        return templateExcelFile;
    }


    public JSONArray queryZYXM(String type) {
        JSONArray result = new JSONArray();
        if ("特种设备安全管理和作业人员证".equals(type)) {
            List<DictionarieValueModel> certType = Systemctl.dictionarieClient.dictValues("JOB_ITEM").getResult();
            for (DictionarieValueModel certTypeModel : certType) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("key", certTypeModel.getDictDataKey());
                jsonObject.put("value", certTypeModel.getDictDataKey());
                jsonObject.put("label", certTypeModel.getDictDataValue());
                result.add(jsonObject);
            }
        } else {
            List<DictionarieValueModel> certType = Systemctl.dictionarieClient.dictValues("ZZXM_" + type).getResult();
            for (DictionarieValueModel certTypeModel : certType) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("key", certTypeModel.getDictDataKey());
                jsonObject.put("value", certTypeModel.getDictDataKey());
                jsonObject.put("label", certTypeModel.getDictDataValue());
                result.add(jsonObject);
            }
        }
        return result;
    }


    public JSONArray queryTypeZYXM(String type) {
        JSONArray result = new JSONArray();
        if ("特种设备安全管理和作业人员证".equals(type)) {
            List<DictionarieValueModel> certType = Systemctl.dictionarieClient.dictValues("JOB_ITEM").getResult();
            for (DictionarieValueModel certTypeModel : certType) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("key", certTypeModel.getDictDataKey());
                jsonObject.put("value", certTypeModel.getDictDataKey());
                jsonObject.put("label", certTypeModel.getDictDataValue());
                result.add(jsonObject);
            }
        } else {
            throw new BaseException("请先选择证书类型，才能选择作业项目", "200", "请先选择证书类型，才能选择作业项目");
        }
        return result;
    }


    public JSONArray queryLevelZYXM(String type) {
        JSONArray result = new JSONArray();
        if (!ObjectUtils.isEmpty(type)) {
            List<DictionarieValueModel> certType = Systemctl.dictionarieClient.dictValues("JOB_ITEM").getResult();
            for (DictionarieValueModel certTypeModel : certType) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("key", certTypeModel.getDictDataKey());
                jsonObject.put("value", certTypeModel.getDictDataKey());
                jsonObject.put("label", certTypeModel.getDictDataValue());
                result.add(jsonObject);
            }
        } else {
            throw new BaseException("请先选择证书级别，才能选择项目", "200", "请先选择证书级别，才能选择项目");
        }
        return result;
    }

    public JSONArray queryUnitByOrgCode(String orgCode) {
        SearchRequest searchRequest = new SearchRequest("idx_biz_enterprise_info");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.wildcardQuery("superviseOrgCode.keyword", QueryParser.escape(orgCode) + "*"));
        searchSourceBuilder.query(boolQueryBuilder);
        searchRequest.source(searchSourceBuilder);

        JSONArray result = new JSONArray();
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            for (SearchHit hit : searchResponse.getHits().getHits()) {
                JSONObject jsonObject = ((JSONObject) JSONObject.toJSON(hit)).getJSONObject("sourceAsMap");
                JSONObject dto = new JSONObject();
                dto.put("key", jsonObject.getString("useCode"));
                dto.put("value", jsonObject.getString("useCode"));
                dto.put("label", jsonObject.getString("useUnit"));
                result.add(dto);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return result;
    }

    public JSONArray queryEquipList() {
        List<EquipmentCategoryDto> equipmentCategoryDtos = equipmentCategoryMapper.selectClassify();
        JSONArray equipCategoryData = new JSONArray();
        for (int i = 0; i < equipmentCategoryDtos.size(); i++) {
            JSONObject object = new JSONObject();
            object.put("key", equipmentCategoryDtos.get(i).getCode());
            object.put("value", equipmentCategoryDtos.get(i).getCode());
            object.put("label", equipmentCategoryDtos.get(i).getName());
            equipCategoryData.add(object);
        }
        return equipCategoryData;
    }

    public JSONArray queryEquCategory(String type) {
        JSONArray result = tzsCustomFilterMapper.queryEquCategory(type, "EQU_CATEGORY");
        return result;
    }

    public JSONArray queryEquDefine(String type) {
        JSONArray result = tzsCustomFilterMapper.queryEquCategory(type, "EQU_DEFINE");
        return result;
    }

    public JSONArray queryEquState() {
        return EquipStateEnum.getAll();
    }

    public JSONArray queryIsSupervisoryCode() {
        return IsSupervisoryCodeEnum.getAll();
    }

    public JSONArray queryDataQualityScore() {
        return DataQualityScoreEnum.getAll();
    }

    public JSONArray queryUscDate() {
        return UscDateEnum.getAll();
    }

    public JSONArray queryTechParam(JSONObject jsonObject) {

        String equList = jsonObject.getString("EQU_LIST_CODE");
        String equCategory = "all".equals(jsonObject.getString("EQU_CATEGORY_CODE")) ? null : jsonObject.getString("EQU_CATEGORY");
        String equDefine = "all".equals(jsonObject.getString("EQU_DEFINE_CODE")) ? null : jsonObject.getString("EQU_DEFINE");
        String vehicleCylinder = "1".equals(jsonObject.getString("WHETHER_VEHICLE_CYLINDER")) ? "vehicleCylinder" : null;
        if ("".equals(equList) || null == equList) {
            throw new BaseException("需要先选择设备种类，才能选择技术参数", "200", "需要先选择设备种类，才能选择技术参数");
        }
        List<TechParamItem> paramMetaList = new ArrayList<>();
        if (vehicleCylinder != null) {
            paramMetaList = TechParamUtil.getParamMetaList(equList, equCategory, equDefine, vehicleCylinder);
        } else {
            paramMetaList = TechParamUtil.getParamMetaList(equList, equCategory, equDefine);
        }
        JSONArray list = new JSONArray();
        for (int i = 0; i < paramMetaList.size(); i++) {
            JSONObject object = new JSONObject();
            object.put("key", paramMetaList.get(i).getParamKey());
            object.put("value", paramMetaList.get(i).getParamKey());
            object.put("label", paramMetaList.get(i).getParamLabel());
            object.put("unit", paramMetaList.get(i).getUnit());
            JSONObject skillConfig = new JSONObject();
            skillConfig.put("conditions", getConditionList(paramMetaList.get(i).getParamType(), paramMetaList.get(i).getDictCode()));
            if (!ValidationUtil.isEmpty(paramMetaList.get(i).getDictCode())) {
                skillConfig.put("type", "select");
                skillConfig.put("data", getData(paramMetaList.get(i).getDictCode()));
            } else if (TechnicalParameter.ParamType.BIG_DECIMAL.equals(paramMetaList.get(i).getParamType())) {
                skillConfig.put("type", "inputNumber");
            } else if (TechnicalParameter.ParamType.STRING.equals(paramMetaList.get(i).getParamType())) {
                skillConfig.put("type", "input");
            } else if (TechnicalParameter.ParamType.DATE.equals(paramMetaList.get(i).getParamType())) {
                skillConfig.put("type", "date");
            }
            skillConfig.put("fieldType", paramMetaList.get(i).getParamType());
            skillConfig.put("isMulti", false);
            object.put("skillConfig", skillConfig);
            list.add(object);
        }
        return list;
    }

    public JSONArray queryCertType() {
        //证书类型
        List<DictionarieValueModel> certType = Systemctl.dictionarieClient.dictValues("CERT_TYPE").getResult();
        JSONArray certTypeArray = new JSONArray();
        for (int i = 0; i < certType.size(); i++) {
            JSONObject object = new JSONObject();
            object.put("key", certType.get(i).getDictDataKey());
            object.put("value", certType.get(i).getDictDataKey());
            object.put("label", certType.get(i).getDictDataValue());
            certTypeArray.add(object);
        }
        return certTypeArray;
    }

    public JSONArray queryPermissionLevel() {
        //证书级别
        List<DictionarieValueModel> RYJB_JC = Systemctl.dictionarieClient.dictValues("RYJB_JC").getResult();
        List<DictionarieValueModel> RYJB_JY = Systemctl.dictionarieClient.dictValues("RYJB_JY").getResult();
        JSONArray permissionLevelArray = new JSONArray();
        for (int i = 0; i < RYJB_JC.size(); i++) {
            JSONObject object = new JSONObject();
            object.put("key", RYJB_JC.get(i).getDictDataKey());
            object.put("value", RYJB_JC.get(i).getDictDataKey());
            object.put("label", RYJB_JC.get(i).getDictDataValue());
            permissionLevelArray.add(object);
        }
        for (int i = 0; i < RYJB_JY.size(); i++) {
            JSONObject object = new JSONObject();
            object.put("key", RYJB_JY.get(i).getDictDataKey());
            object.put("value", RYJB_JY.get(i).getDictDataKey());
            object.put("label", RYJB_JY.get(i).getDictDataValue());
            permissionLevelArray.add(object);
        }
        return permissionLevelArray;
    }

    public JSONArray queryCertNo() {
        JSONArray certNoData = new JSONArray();
        for (int i = 0; i < 3; i++) {
            JSONObject object = new JSONObject();
            if (0 == i) {
                object.put("key", "2");
                object.put("value", "2");
                object.put("label", "无资质要求");
            } else if (1 == i) {
                object.put("key", "1");
                object.put("value", "1");
                object.put("label", "有资质");
            } else if (2 == i) {
                object.put("key", "0");
                object.put("value", "0");
                object.put("label", "无资质");
            }
            certNoData.add(object);
        }
        return certNoData;
    }

    public JSONArray queryExpiryDate() {
        //资质状态
        JSONArray permissionStatus = new JSONArray();
        for (int i = 0; i < 4; i++) {
            JSONObject object = new JSONObject();
            if (0 == i) {
                object.put("key", normal);
                object.put("value", normal);
                object.put("label", licensesStatusMap.get(normal));
            } else if (1 == i) {
                object.put("key", near);
                object.put("value", near);
                object.put("label", licensesStatusMap.get(near));
            } else if (2 == i) {
                object.put("key", overdue);
                object.put("value", overdue);
                object.put("label", licensesStatusMap.get(overdue));
            } else {
                object.put("key", none);
                object.put("value", none);
                object.put("label", licensesStatusMap.get(none));
            }
            permissionStatus.add(object);
        }
        return permissionStatus;
    }


    public JSONArray queryInspectionDate() {
        //资质状态
        JSONArray permissionStatus = new JSONArray();
        for (int i = 0; i < 4; i++) {
            JSONObject object = new JSONObject();
            if (0 == i) {
                object.put("key", normal);
                object.put("value", normal);
                object.put("label", inspectionStatusMap.get(normal));
            } else if (1 == i) {
                object.put("key", near);
                object.put("value", near);
                object.put("label", inspectionStatusMap.get(near));
            } else if (2 == i) {
                object.put("key", overdue);
                object.put("value", overdue);
                object.put("label", inspectionStatusMap.get(overdue));
            } else {
                object.put("key", none);
                object.put("value", none);
                object.put("label", inspectionStatusMap.get(none));
            }
            permissionStatus.add(object);
        }
        return permissionStatus;
    }

    public JSONArray queryVehicleCylinder() {
        //是否车用气瓶
        JSONArray vehicleCylinder = new JSONArray();
        for (int i = 0; i < 2; i++) {
            JSONObject object = new JSONObject();
            if (0 == i) {
                object.put("key", "0");
                object.put("value", "0");
                object.put("label", "否");
            } else {
                object.put("key", "1");
                object.put("value", "1");
                object.put("label", "是");
            }
            vehicleCylinder.add(object);
        }
        return vehicleCylinder;
    }

    public JSONArray queryQzOrTank() {
        //撬装球罐
        JSONArray qzOrTank = new JSONArray();
        for (int i = 0; i < 2; i++) {
            JSONObject object = new JSONObject();
            if (0 == i) {
                object.put("key", "WHETHER_SKID_MOUNTED_PRESSURE_VESSEL");
                object.put("value", "WHETHER_SKID_MOUNTED_PRESSURE_VESSEL");
                object.put("label", "撬装设备");
            } else {
                object.put("key", "whetherSphericalTank");
                object.put("value", "whetherSphericalTank");
                object.put("label", "球罐");
            }
            qzOrTank.add(object);
        }
        return qzOrTank;
    }

    public JSONArray queryRegisterStatus() {
        //登记状态
        JSONArray registerStatus = new JSONArray();
        for (int i = 0; i < 2; i++) {
            JSONObject object = new JSONObject();
            if (0 == i) {
                object.put("key", "0");
                object.put("value", "0");
                object.put("label", "未登记");
            } else {
                object.put("key", "1");
                object.put("value", "1");
                object.put("label", "已登记");
            }
            registerStatus.add(object);
        }
        return registerStatus;
    }

    public JSONObject queryDpStatistics(JSONObject filter) {

        JSONObject result = new JSONObject();
        String businessType = filter.getString("businessType");
        if (ObjectUtils.isEmpty(businessType)) {
            return result;
        }

        SearchRequest request = new SearchRequest();
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.trackTotalHits(true);
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();

        Map<String, Object> tabTotalMap = new HashMap<>();
        String orgCode = filter.getString("orgCode");

        List<Map<String, Object>> data = new ArrayList<>();
        if (StatisticalAnalysisEnum.equip.getCode().equals(businessType)) {
            boolMust.must(QueryBuilders.prefixQuery("ORG_BRANCH_CODE", orgCode));
            data = queryDpEquipStatistics(filter, request, builder, boolMust, tabTotalMap);
        } else if (StatisticalAnalysisEnum.company.getCode().equals(businessType)) {
            personOrgCodeBoolMust(orgCode, boolMust,StatisticalAnalysisEnum.company.getCode());
            data = queryDpCompanyStatistics(filter, request, builder, boolMust, tabTotalMap);
        } else if (StatisticalAnalysisEnum.person.getCode().equals(businessType)) {
            personOrgCodeBoolMust(orgCode, boolMust,StatisticalAnalysisEnum.person.getCode());
            data = queryDpPersonStatistics(filter, request, builder, boolMust, tabTotalMap);
        } else if (StatisticalAnalysisEnum.inspectionCompany.getCode().equals(businessType)) {
            personOrgCodeBoolMust(orgCode, boolMust,StatisticalAnalysisEnum.company.getCode());
            data = queryDpInspectionCompanyStatistics(filter, request, builder, boolMust, tabTotalMap);
        } else {
            personOrgCodeBoolMust(orgCode, boolMust,StatisticalAnalysisEnum.person.getCode());
            data = queryDpInspectionPersonStatistics(filter, request, builder, boolMust, tabTotalMap);
        }

        getTypeCount(businessType, tabTotalMap, orgCode, data);

        result.put("tabTotalMap", tabTotalMap);
        result.put("datas", data);
        return result;
    }

    private List<Map<String, Object>> queryDpInspectionPersonStatistics(JSONObject filter, SearchRequest request, SearchSourceBuilder builder, BoolQueryBuilder boolMust, Map<String, Object> tabTotalMap) {

        request.indices(StatisticalAnalysisEnum.inspectionPerson.getKey());
        JSONObject filterParams = JSONObject.parseObject(JSONObject.toJSONString(filter.get("filterParams")));
        String filterType = "advanced";
        // 组装人员过滤条件
        this.getPersonBoolQueryBuilder(filterParams, boolMust, filterType);
        // 通过是否传参 unitType 单位类型 区分一二级查询
        boolean is2LeveFlag = Optional.of(filter)
                .map(obj -> obj.getJSONObject("filterParams"))
                .map(filterParamsObj -> filterParams.getJSONArray("unitType"))
                .map(unitTypeObj -> !unitTypeObj.isEmpty())
                .orElse(false);
        Map<String, Object> result = new HashMap<>();
        boolMust.mustNot(QueryBuilders.wildcardQuery("unitType.keyword", "*检验检测机构*"));
        // 一级统计
        if (!is2LeveFlag) {
            BoolQueryBuilder companyUnitTypeBoolMust = QueryBuilders.boolQuery();
            companyBoolMust(companyUnitTypeBoolMust, "inspection");
            boolMust.must(companyUnitTypeBoolMust);
            result = getTotalAggMapsByUnitType(request, builder, boolMust, tabTotalMap, StatisticalAnalysisEnum.inspectionPerson);
        } else {
            tabTotalMap.put(StatisticalAnalysisEnum.inspectionPerson.getCode(), this.queryDpStatisticsTotalByIndex(boolMust, StatisticalAnalysisEnum.inspectionPerson.getKey()));
            JSONObject expiryDateStatus = this.getExpiryDateStatusGroupStatistics(boolMust);
            JSONObject personType = this.getPersonTypeGroupStatistics(boolMust);
            result.put("tabTotalMap", new JSONObject()
                    .fluentPut("expiryDateStatusTotal", this.sumWithJSONObjectValues(expiryDateStatus))
                    .fluentPut("personTypeTotal", this.sumWithJSONObjectValues(personType)));
            result.put("datas", new JSONObject()
                    .fluentPut("expiryDateStatus", expiryDateStatus)
                    .fluentPut("personType", personType));
        }
        return Collections.singletonList(result);
    }

    private List<Map<String, Object>> queryDpInspectionCompanyStatistics(JSONObject filter, SearchRequest request, SearchSourceBuilder builder, BoolQueryBuilder boolMust, Map<String, Object> tabTotalMap) {

        request.indices(StatisticalAnalysisEnum.inspectionCompany.getKey());
        JSONObject filterParams = JSONObject.parseObject(JSONObject.toJSONString(filter.get("filterParams")));

        // 构造企业查询条件
        filter.put("filterType", "advanced");

        if (!ObjectUtils.isEmpty(filter.get("filterParams"))) {
            String filterType = filter.getString("filterType");
            getCompanyBoolQueryBuilder(filterParams, filterType, boolMust);
        }

        boolean is2LeveFlag = Optional.of(filter)
                .map(obj -> obj.getJSONObject("filterParams"))
                .map(filterParamsObj -> filterParamsObj.getJSONArray("unitType"))
                .map(unitTypeObj -> !unitTypeObj.isEmpty())
                .orElse(false);

        Map<String, Object> result = new HashMap<>();
        // 一级统计
        boolMust.mustNot(QueryBuilders.wildcardQuery("unitType.keyword", "*检验检测机构*"));
        if (!is2LeveFlag) {
            BoolQueryBuilder companyUnitTypeBoolMust = QueryBuilders.boolQuery();
            companyBoolMust(companyUnitTypeBoolMust, "inspection");
            boolMust.must(companyUnitTypeBoolMust);
            result = getTotalAggMapsByUnitType(request, builder, boolMust, tabTotalMap, StatisticalAnalysisEnum.inspectionCompany);
        } else {
            Long companyCount = getStatisticCount(boolMust, StatisticalAnalysisEnum.inspectionCompany.getKey());
            getTotalAggMapsByUnitType(request, builder, boolMust, tabTotalMap, StatisticalAnalysisEnum.inspectionCompany);
            JSONObject permitStatus = getPermitStatusGroupStatistics(boolMust);
            result.put("datas", new JSONObject()
                    .fluentPut("permitStatus", permitStatus));
            result.put("tabTotalMap", new JSONObject()
                    .fluentPut("permitStatusTotal", companyCount));
        }

        return Collections.singletonList(result);
    }

    private void getTypeCount(String businessType, Map<String, Object> tabTotalMap, String orgCode, List<Map<String, Object>> data) {
        BoolQueryBuilder equipBoolMust = QueryBuilders.boolQuery();
        equipBoolMust.must(QueryBuilders.prefixQuery("ORG_BRANCH_CODE", orgCode));
        equipBoolMust.mustNot(QueryBuilders.termsQuery("STATUS", Arrays.asList("草稿", "已拒领", "待认领")));
        equipBoolMust.mustNot(QueryBuilders.termQuery("EQU_CATEGORY_CODE", "2300"));
        equipBoolMust.mustNot(QueryBuilders.termQuery("EQU_LIST_CODE", "8000"));
        equipBoolMust.must(QueryBuilders.termsQuery("EQU_LIST_CODE", Arrays.asList("1000", "2000", "3000", "4000", "5000", "6000", "9000")));

        BoolQueryBuilder companyUnitTypeBoolMust = QueryBuilders.boolQuery();
        companyBoolMust(companyUnitTypeBoolMust, "company");

        BoolQueryBuilder inspectionUnitTypeBoolMust = QueryBuilders.boolQuery();
        companyBoolMust(inspectionUnitTypeBoolMust, "inspection");

        BoolQueryBuilder companyBoolMust = QueryBuilders.boolQuery();
        companyBoolMust.must(QueryBuilders.prefixQuery("superviseOrgCode.keyword", orgCode));
        companyBoolMust.must(companyUnitTypeBoolMust);

        BoolQueryBuilder personBoolMust = QueryBuilders.boolQuery();
        personOrgCodeBoolMust(orgCode, personBoolMust, StatisticalAnalysisEnum.person.getCode());
        personBoolMust.must(companyUnitTypeBoolMust);

        BoolQueryBuilder inspectionCompanyBoolMust = QueryBuilders.boolQuery();
        inspectionCompanyBoolMust.must(QueryBuilders.prefixQuery("superviseOrgCode.keyword", orgCode));
        inspectionCompanyBoolMust.must(inspectionUnitTypeBoolMust);
        inspectionCompanyBoolMust.mustNot(QueryBuilders.wildcardQuery("unitType.keyword", "*检验检测机构*"));


        BoolQueryBuilder inspectionPersonBoolMust = QueryBuilders.boolQuery();
        personOrgCodeBoolMust(orgCode, personBoolMust, StatisticalAnalysisEnum.person.getCode());
        inspectionPersonBoolMust.must(inspectionUnitTypeBoolMust);
        inspectionPersonBoolMust.mustNot(QueryBuilders.wildcardQuery("unitType.keyword", "*检验检测机构*"));

        String equipIndex = StatisticalAnalysisEnum.equip.getKey();
        String companyIndex = StatisticalAnalysisEnum.company.getKey();
        String personIndex = StatisticalAnalysisEnum.person.getKey();


        if (businessType.equals(StatisticalAnalysisEnum.equip.getCode())) {
            // 获取企业总数
            Long companyCount = getStatisticCount(companyBoolMust, companyIndex);
            // 获取人员总数
            Long personCount = getStatisticCount(personBoolMust, personIndex);
            // 获取检验检测机构总数
            Long inspectionCompanyCount = getStatisticCount(inspectionCompanyBoolMust, companyIndex);
            // 获取检验检测机构人员总数
            Long inspectionPersonCount = getStatisticCount(inspectionPersonBoolMust, personIndex);
            tabTotalMap.put(StatisticalAnalysisEnum.company.getCode(), companyCount);
            tabTotalMap.put(StatisticalAnalysisEnum.person.getCode(), personCount);
            tabTotalMap.put(StatisticalAnalysisEnum.inspectionCompany.getCode(), inspectionCompanyCount);
            tabTotalMap.put(StatisticalAnalysisEnum.inspectionPerson.getCode(), inspectionPersonCount);
        } else if (businessType.equals(StatisticalAnalysisEnum.company.getCode())) {
            // 获取设备总数
            Long equipCount = getStatisticCount(equipBoolMust, equipIndex);
            // 获取人员总数
            Long personCount = getStatisticCount(personBoolMust, personIndex);
            // 获取检验检测机构总数
            Long inspectionCompanyCount = getStatisticCount(inspectionCompanyBoolMust, companyIndex);
            // 获取检验检测机构人员总数
            Long inspectionPersonCount = getStatisticCount(inspectionPersonBoolMust, personIndex);
            tabTotalMap.put(StatisticalAnalysisEnum.equip.getCode(), equipCount);
            tabTotalMap.put(StatisticalAnalysisEnum.person.getCode(), personCount);
            tabTotalMap.put(StatisticalAnalysisEnum.inspectionCompany.getCode(), inspectionCompanyCount);
            tabTotalMap.put(StatisticalAnalysisEnum.inspectionPerson.getCode(), inspectionPersonCount);
        } else if (businessType.equals(StatisticalAnalysisEnum.person.getCode())) {
            // 获取设备总数
            Long equipCount = getStatisticCount(equipBoolMust, equipIndex);
            // 获取企业总数
            Long companyCount = getStatisticCount(companyBoolMust, companyIndex);
            // 获取检验检测机构总数
            Long inspectionCompanyCount = getStatisticCount(inspectionCompanyBoolMust, companyIndex);
            // 获取检验检测机构人员总数
            Long inspectionPersonCount = getStatisticCount(inspectionPersonBoolMust, personIndex);
            tabTotalMap.put(StatisticalAnalysisEnum.equip.getCode(), equipCount);
            tabTotalMap.put(StatisticalAnalysisEnum.company.getCode(), companyCount);
            tabTotalMap.put(StatisticalAnalysisEnum.inspectionCompany.getCode(), inspectionCompanyCount);
            tabTotalMap.put(StatisticalAnalysisEnum.inspectionPerson.getCode(), inspectionPersonCount);
        } else if (businessType.equals(StatisticalAnalysisEnum.inspectionCompany.getCode())) {
            // 获取设备总数
            Long equipCount = getStatisticCount(equipBoolMust, equipIndex);
            // 获取企业总数
            Long companyCount = getStatisticCount(companyBoolMust, companyIndex);
            // 获取人员总数
            Long personCount = getStatisticCount(personBoolMust, personIndex);
            // 获取检验检测机构人员总数
            Long inspectionPersonCount = getStatisticCount(inspectionPersonBoolMust, personIndex);
            tabTotalMap.put(StatisticalAnalysisEnum.equip.getCode(), equipCount);
            tabTotalMap.put(StatisticalAnalysisEnum.company.getCode(), companyCount);
            tabTotalMap.put(StatisticalAnalysisEnum.person.getCode(), personCount);
            tabTotalMap.put(StatisticalAnalysisEnum.inspectionPerson.getCode(), inspectionPersonCount);
        } else {
            // 获取设备总数
            Long equipCount = getStatisticCount(equipBoolMust, equipIndex);
            // 获取企业总数
            Long companyCount = getStatisticCount(companyBoolMust, companyIndex);
            // 获取人员总数
            Long personCount = getStatisticCount(personBoolMust, personIndex);
            // 获取检验检测机构总数
            Long inspectionCompanyCount = getStatisticCount(inspectionCompanyBoolMust, companyIndex);
            tabTotalMap.put(StatisticalAnalysisEnum.equip.getCode(), equipCount);
            tabTotalMap.put(StatisticalAnalysisEnum.company.getCode(), companyCount);
            tabTotalMap.put(StatisticalAnalysisEnum.person.getCode(), personCount);
            tabTotalMap.put(StatisticalAnalysisEnum.inspectionCompany.getCode(), inspectionCompanyCount);
        }
    }


    private List<Map<String, Object>> queryDpPersonStatistics(JSONObject filter, SearchRequest request, SearchSourceBuilder builder,
                                                              BoolQueryBuilder boolMust, Map<String, Object> tabTotalMap) {
        request.indices(StatisticalAnalysisEnum.person.getKey());

        JSONObject filterParams = JSONObject.parseObject(JSONObject.toJSONString(filter.get("filterParams")));
        String filterType = "advanced";
        String unitCategory = filterParams.getString("unitCategory");
        // 组装人员过滤条件
        this.getPersonBoolQueryBuilder(filterParams, boolMust, filterType);

        // 通过是否传参 unitType 单位类型 区分一二级查询
        boolean is2LeveFlag = Optional.of(filter)
                .map(obj -> obj.getJSONObject("filterParams"))
                .map(filterParamsObj -> filterParams.getJSONArray("unitType"))
                .map(unitTypeObj -> !unitTypeObj.isEmpty())
                .orElse(false);

        boolean is3LeveFlag = Optional.of(filter)
                .map(obj -> obj.getJSONObject("filterParams"))
                .map(filterParamsObj -> filterParamsObj.getJSONArray("threeLevel"))
                .map(threeLevelObj -> !threeLevelObj.isEmpty())
                .orElse(false);
        Map<String, Object> result = new HashMap<>();
        // 一级统计
        if (!is2LeveFlag) {
            BoolQueryBuilder countBoolMust = QueryBuilderUtils.copyBoolQuery(boolMust);
            companyBoolMust(countBoolMust, "company");
            long total = this.queryDpStatisticsTotalByIndex(countBoolMust, StatisticalAnalysisEnum.person.getKey());
            // 汇总总数
            tabTotalMap.put(StatisticalAnalysisEnum.person.getCode(), total);
            result = getUseAndProductAndFillingStatistics(boolMust, StatisticalAnalysisEnum.person.getKey());
        } else if (!is3LeveFlag) {
            if (unitCategory.equals(UnitCategoryEnum.use.getCode())) {
                companyBoolMust(boolMust, UnitCategoryEnum.use.getCode());
                long total = this.queryDpStatisticsTotalByIndex(boolMust, StatisticalAnalysisEnum.person.getKey());
                result.put("tabTotalMap", new JSONObject().fluentPut("personTypeTotal", total));
                Map<String, Object> totalAggMapsByUnitType = getTotalAggMapsByUnitType(request, builder, boolMust, tabTotalMap, StatisticalAnalysisEnum.person);
                result.put("datas",totalAggMapsByUnitType);
            } else if (unitCategory.equals(UnitCategoryEnum.produce.getCode())) {
                companyBoolMust(boolMust, UnitCategoryEnum.produce.getCode());
                long total = this.queryDpStatisticsTotalByIndex(boolMust, StatisticalAnalysisEnum.person.getKey());
                result.put("tabTotalMap", new JSONObject().fluentPut("personTypeTotal", total));
                Map<String, Object> totalAggMapsByUnitType = getTotalAggMapsByUnitType(request, builder, boolMust, tabTotalMap, StatisticalAnalysisEnum.person);
                result.put("datas",totalAggMapsByUnitType);
            } else {
                companyBoolMust(boolMust, UnitCategoryEnum.filling.getCode());
                JSONObject expiryDateStatus = this.getExpiryDateStatusGroupStatistics(boolMust);
                JSONObject personType = this.getPersonTypeGroupStatistics(boolMust);
                result.put("tabTotalMap", new JSONObject()
                        .fluentPut("expiryDateStatusTotal", this.sumWithJSONObjectValues(expiryDateStatus))
                        .fluentPut("personTypeTotal", this.sumWithJSONObjectValues(personType)));
                result.put("datas", new JSONObject()
                        .fluentPut("expiryDateStatus", expiryDateStatus)
                        .fluentPut("personType", personType));
            }
        } else {
            JSONArray threeLevel = filterParams.getJSONArray("threeLevel");
            String filterCode = threeLevel.getString(0);
            boolMust.must(QueryBuilders.wildcardQuery("unitType.keyword", "*" + filterCode + "*"));
            tabTotalMap.put(StatisticalAnalysisEnum.person.getCode(), this.queryDpStatisticsTotalByIndex(boolMust, StatisticalAnalysisEnum.person.getKey()));
            JSONObject expiryDateStatus = this.getExpiryDateStatusGroupStatistics(boolMust);
            JSONObject personType = this.getPersonTypeGroupStatistics(boolMust);
            result.put("tabTotalMap", new JSONObject()
                    .fluentPut("expiryDateStatusTotal", this.sumWithJSONObjectValues(expiryDateStatus))
                    .fluentPut("personTypeTotal", this.sumWithJSONObjectValues(personType)));
            result.put("datas", new JSONObject()
                    .fluentPut("expiryDateStatus", expiryDateStatus)
                    .fluentPut("personType", personType));
        }
        return Collections.singletonList(result);
    }

    public void companyBoolMust(BoolQueryBuilder boolMust, String type) {
        if ("company".equals(type)) {
            boolMust.should(QueryBuilders.wildcardQuery("unitType.keyword", "*" + UnitTypeEnum.sydw.getName() + "*"))
                    .should(QueryBuilders.wildcardQuery("unitType.keyword", "*" + UnitTypeEnum.grzt.getName() + "*"))
                    .should(QueryBuilders.wildcardQuery("unitType.keyword", "*" + UnitTypeEnum.zzdw.getName() + "*"))
                    .should(QueryBuilders.wildcardQuery("unitType.keyword", "*" + UnitTypeEnum.sjdw.getName() + "*"))
                    .should(QueryBuilders.wildcardQuery("unitType.keyword", "*" + UnitTypeEnum.azgzwxdw.getName() + "*"))
                    .should(QueryBuilders.wildcardQuery("unitType.keyword", "*" + UnitTypeEnum.czdw.getName() + "*"))
                    .minimumShouldMatch(1);
        } else if (UnitCategoryEnum.use.getCode().equals(type)) {
            boolMust.should(QueryBuilders.wildcardQuery("unitType.keyword", "*" + UnitTypeEnum.sydw.getName() + "*"))
                    .should(QueryBuilders.wildcardQuery("unitType.keyword", "*" + UnitTypeEnum.grzt.getName() + "*"))
                    .minimumShouldMatch(1);
        } else if (UnitCategoryEnum.produce.getCode().equals(type)) {
            boolMust.should(QueryBuilders.wildcardQuery("unitType.keyword", "*" + UnitTypeEnum.zzdw.getName() + "*"))
                    .should(QueryBuilders.wildcardQuery("unitType.keyword", "*" + UnitTypeEnum.sjdw.getName() + "*"))
                    .should(QueryBuilders.wildcardQuery("unitType.keyword", "*" + UnitTypeEnum.azgzwxdw.getName() + "*"))
                    .minimumShouldMatch(1);
        } else if (UnitCategoryEnum.filling.getCode().equals(type)) {
            boolMust.must(QueryBuilders.wildcardQuery("unitType.keyword", "*" + UnitTypeEnum.czdw.getName() + "*"));
        } else if (UnitCategoryEnum.inspection.getCode().equals(type)) {
            boolMust.should(QueryBuilders.wildcardQuery("unitType.keyword", "*" + UnitTypeEnum.jyjg.getName() + "*"))
                    .should(QueryBuilders.wildcardQuery("unitType.keyword", "*" + UnitTypeEnum.jcjg.getName() + "*"))
                    .minimumShouldMatch(1);
        }
    }


    private Map<String, Object> getTotalAggMapsByUnitType(SearchRequest request, SearchSourceBuilder builder, BoolQueryBuilder boolMust, Map<String, Object> tabTotalMap, StatisticalAnalysisEnum statisticalAnalysisEnum) {
        long total = this.queryDpStatisticsTotalByIndex(boolMust, statisticalAnalysisEnum.getKey());
        // 汇总总数
        tabTotalMap.put(statisticalAnalysisEnum.getCode(), total);
        // 聚合查询
        builder.size(0);// 不返回任何文档，只返回聚合结果
        String aggName = "unit_types_split";
        QueryBuilderUtils.buildSplitFieldAggCondition(builder, "unitType.keyword", "#", aggName, "其他");
        builder.query(boolMust);
        request.source(builder);

        Map<String, Object> result = new HashMap<>();
        try {
            SearchResponse searchResponse = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            // 解析聚合结果
            Terms unitTypesTerms = searchResponse.getAggregations().get(aggName);
            this.buildPersonWithCompanyTypeGroupResult(unitTypesTerms, result);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return result;
    }

    public void buildPersonWithCompanyTypeGroupResult(Terms unitTypesTerms, Map<String, Object> result) {
        if (unitTypesTerms != null) {
            for (Terms.Bucket bucket : unitTypesTerms.getBuckets()) {
                if (bucket.getKeyAsString().equals(UnitTypeEnum.sydw.getName())) {
                    result.put("sydw", bucket.getDocCount());
                }
                if (bucket.getKeyAsString().equals(UnitTypeNewEnum.grzt.getLabel())) {
                    result.put("grzt", bucket.getDocCount());
                }
                if (bucket.getKeyAsString().equals(UnitTypeNewEnum.sjdw.getLabel())) {
                    result.put("sjdw", bucket.getDocCount());
                }
                if (bucket.getKeyAsString().equals(UnitTypeNewEnum.zzdw.getLabel())) {
                    result.put("zzdw", bucket.getDocCount());
                }
                if (bucket.getKeyAsString().equals(UnitTypeNewEnum.azgzwxdw.getLabel())) {
                    result.put("azgzwxdw", bucket.getDocCount());
                }
                if (bucket.getKeyAsString().equals(UnitTypeNewEnum.czdw.getLabel())) {
                    result.put("czdw", bucket.getDocCount());
                }
                if (bucket.getKeyAsString().equals(UnitTypeNewEnum.jyjg.getLabel())) {
                    result.put("jyjg", bucket.getDocCount());
                }
                if (bucket.getKeyAsString().equals(UnitTypeNewEnum.jcjg.getLabel())) {
                    result.put("jcjg", bucket.getDocCount());
                }
            }
        }
    }

    private long queryDpStatisticsTotalByIndex(BoolQueryBuilder boolMust, String index) {
        CountRequest countRequest = new CountRequest();
        countRequest.indices(index);
        countRequest.query(boolMust);
        CountResponse countResponse;
        try {
            countResponse = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT);
        } catch (Exception exception) {
            throw new RuntimeException(exception);
        }
        return ObjectUtils.isEmpty(countResponse) ? 0 : countResponse.getCount();
    }

    private List<Map<String, Object>> queryDpCompanyStatistics(JSONObject filter, SearchRequest request, SearchSourceBuilder builder, BoolQueryBuilder boolMust, Map<String, Object> tabTotalMap) {
        Map<String, Object> result = new HashMap<>();
        request.indices(StatisticalAnalysisEnum.company.getKey());
        JSONObject filterParams = JSONObject.parseObject(JSONObject.toJSONString(filter.get("filterParams")));
        String unitCategory = filterParams.getString("unitCategory");

        // 构造企业查询条件
        filter.put("filterType", "advanced");

        if (!ObjectUtils.isEmpty(filter.get("filterParams"))) {
            String filterType = filter.getString("filterType");
            getCompanyBoolQueryBuilder(filterParams, filterType, boolMust);
        }

        boolean is2LeveFlag = Optional.of(filter)
                .map(obj -> obj.getJSONObject("filterParams"))
                .map(filterParamsObj -> filterParamsObj.getJSONArray("unitType"))
                .map(unitTypeObj -> !unitTypeObj.isEmpty())
                .orElse(false);

        boolean is3LeveFlag = Optional.of(filter)
                .map(obj -> obj.getJSONObject("filterParams"))
                .map(filterParamsObj -> filterParamsObj.getJSONArray("threeLevel"))
                .map(threeLevelObj -> !threeLevelObj.isEmpty())
                .orElse(false);
        // 一级统计
        if (!is2LeveFlag) {
            BoolQueryBuilder countBoolMust = QueryBuilderUtils.copyBoolQuery(boolMust);
            companyBoolMust(countBoolMust, "company");
            long total = this.queryDpStatisticsTotalByIndex(countBoolMust, StatisticalAnalysisEnum.company.getKey());
            // 汇总总数
            tabTotalMap.put(StatisticalAnalysisEnum.company.getCode(), total);
            return Collections.singletonList(getUseAndProductAndFillingStatistics(boolMust, StatisticalAnalysisEnum.company.getKey()));
        } else if (!is3LeveFlag) {
            Long companyCount = getStatisticCount(boolMust, StatisticalAnalysisEnum.company.getKey());
            JSONObject industrySupervisor = this.getItemGroupStatisticsByItemName(boolMust,
                    StatisticalAnalysisEnum.company.getKey(),
                    "industrySupervisorAggName",
                    "industrySupervisor",
                    this::buildIndustrySupervisorGroupResult);
            if (unitCategory.equals(UnitCategoryEnum.use.getType())) {
                getTotalAggMapsByUnitType(request, builder, boolMust, tabTotalMap, StatisticalAnalysisEnum.company);
                JSONObject regulatoryLabels = this.getItemGroupStatisticsByItemName(boolMust,
                        StatisticalAnalysisEnum.company.getKey(),
                        "regulatoryLabelsAggName",
                        "regulatoryLabels",
                        this::buildRegulatoryLabelsGroupResult);
                Long levelControl1 = 0L;
                Long levelControl2 = 0L;
                Long levelControl3 = 0L;
                for (String key : regulatoryLabels.keySet()) {
                    if (key.contains("levelControl1")) {
                        levelControl1 += regulatoryLabels.getLong(key);
                    } else if (key.contains("levelControl2")) {
                        levelControl2 += regulatoryLabels.getLong(key);
                    } else if (key.contains("levelControl3")) {
                        levelControl3 += regulatoryLabels.getLong(key);
                    }
                }
                Map<String, Long> levelControlMap = new HashMap<>();
                levelControlMap.put("levelControl1", levelControl1);
                levelControlMap.put("levelControl2", levelControl2);
                levelControlMap.put("levelControl3", levelControl3);
                result.put("datas", new JSONObject()
                        .fluentPut("regulatoryLabels", levelControlMap)
                        .fluentPut("industrySupervisor", industrySupervisor));
                result.put("tabTotalMap", new JSONObject()
                        .fluentPut("regulatoryLabelsTotal", companyCount)
                        .fluentPut("industrySupervisorTotal", this.sumWithJSONObjectValues(industrySupervisor)));
            } else if (unitCategory.equals(UnitCategoryEnum.produce.getCode())) {
                Map<String, Object> datas = getTotalAggMapsByUnitType(request, builder, boolMust, tabTotalMap, StatisticalAnalysisEnum.company);
                Map<String, Object> productMap = new HashMap<>();
                productMap.put("design", datas.get("sjdw"));
                productMap.put("factory", datas.get("zzdw"));
                productMap.put("construction", datas.get("azgzwxdw"));
                result.put("datas", new JSONObject()
                        .fluentPut("companyType", productMap)
                        .fluentPut("industrySupervisor", industrySupervisor));
                result.put("tabTotalMap", new JSONObject()
                        .fluentPut("companyTotal", companyCount)
                        .fluentPut("industrySupervisorTotal", this.sumWithJSONObjectValues(industrySupervisor)));
            } else if (unitCategory.equals(UnitCategoryEnum.filling.getCode())) {
                getTotalAggMapsByUnitType(request, builder, boolMust, tabTotalMap, StatisticalAnalysisEnum.company);
                JSONObject permitStatus = getPermitStatusGroupStatistics(boolMust);
                result.put("datas", new JSONObject()
                        .fluentPut("permitStatus", permitStatus)
                        .fluentPut("industrySupervisor", industrySupervisor));
                result.put("tabTotalMap", new JSONObject()
                        .fluentPut("permitStatusTotal", companyCount)
                        .fluentPut("industrySupervisorTotal", this.sumWithJSONObjectValues(industrySupervisor)));
            }
            return Collections.singletonList(result);
        } else if (is3LeveFlag) {
            JSONArray threeLevel = filterParams.getJSONArray("threeLevel");
            String filterCode = threeLevel.getString(0);
            Map<String, Long> levelControlMap = new HashMap<>();
            Map<String, Object> companyMap = new HashMap<>();
            JSONObject permitStatus = new JSONObject();
            if (unitCategory.equals(UnitCategoryEnum.use.getCode())) {
                if (filterCode.equals("levelControl1") || filterCode.equals("levelControl2")) {
                    boolMust.must(QueryBuilders.wildcardQuery("regulatoryLabels.keyword", (filterCode.contains("1") ? "*一级管控*" : "*二级管控*")));
                    getTotalAggMapsByUnitType(request, builder, boolMust, tabTotalMap, StatisticalAnalysisEnum.company);
                    JSONObject regulatoryLabels = this.getItemGroupStatisticsByItemName(boolMust,
                            StatisticalAnalysisEnum.company.getKey(),
                            "regulatoryLabelsAggName",
                            "regulatoryLabels",
                            this::buildRegulatoryLabelsGroupResult);
                    for (String key : regulatoryLabels.keySet()) {
                        if (key.contains(filterCode)) {
                            levelControlMap.put(key, regulatoryLabels.getLong(key));
                        }
                    }
                } else {
                    Map<String, Object> datas = getTotalAggMapsByUnitType(request, builder, boolMust, tabTotalMap, StatisticalAnalysisEnum.company);
                    companyMap.put("use", datas.get("sydw"));
                    companyMap.put("grzt", datas.get("grzt"));
                }
            } else if (unitCategory.equals(UnitCategoryEnum.produce.getCode())) {
                boolMust.must(QueryBuilders.wildcardQuery("unitType.keyword", "*" + filterCode + "*"));
                getTotalAggMapsByUnitType(request, builder, boolMust, tabTotalMap, StatisticalAnalysisEnum.company);
                permitStatus = getPermitStatusGroupStatistics(boolMust);
            }
            Long companyCount = getStatisticCount(boolMust, StatisticalAnalysisEnum.company.getKey());
            JSONObject industrySupervisor = this.getItemGroupStatisticsByItemName(boolMust,
                    StatisticalAnalysisEnum.company.getKey(),
                    "industrySupervisorAggName",
                    "industrySupervisor",
                    this::buildIndustrySupervisorGroupResult);
            if (unitCategory.equals(UnitCategoryEnum.use.getCode())) {
                if (filterCode.equals("levelControl1") || filterCode.equals("levelControl2")) {
                    result.put("datas", new JSONObject()
                            .fluentPut("regulatoryLabels", levelControlMap)
                            .fluentPut("industrySupervisor", industrySupervisor));
                    result.put("tabTotalMap", new JSONObject()
                            .fluentPut("regulatoryLabelsTotal", companyCount)
                            .fluentPut("industrySupervisorTotal", this.sumWithJSONObjectValues(industrySupervisor)));
                } else {
                    result.put("datas", new JSONObject()
                            .fluentPut("company", companyMap)
                            .fluentPut("industrySupervisor", industrySupervisor));
                    result.put("tabTotalMap", new JSONObject()
                            .fluentPut("regulatoryLabelsTotal", companyCount)
                            .fluentPut("industrySupervisorTotal", this.sumWithJSONObjectValues(industrySupervisor)));
                }
            } else if (unitCategory.equals(UnitCategoryEnum.produce.getCode())) {
                result.put("datas", new JSONObject()
                        .fluentPut("permitStatus", permitStatus)
                        .fluentPut("industrySupervisor", industrySupervisor));
                result.put("tabTotalMap", new JSONObject()
                        .fluentPut("permitStatusTotal", companyCount)
                        .fluentPut("industrySupervisorTotal", this.sumWithJSONObjectValues(industrySupervisor)));

            }
            return Collections.singletonList(result);
        }
        return Collections.singletonList(result);
    }

    private Map<String, Object> getUseAndProductAndFillingStatistics(BoolQueryBuilder boolMust, String index) {
        Map<String, Object> result = new HashMap<>();
        BoolQueryBuilder useBoolMust = QueryBuilderUtils.copyBoolQuery(boolMust);
        companyBoolMust(useBoolMust, UnitCategoryEnum.use.getCode());
        BoolQueryBuilder produceBoolMust = QueryBuilderUtils.copyBoolQuery(boolMust);
        companyBoolMust(produceBoolMust, UnitCategoryEnum.produce.getCode());
        BoolQueryBuilder fillingBoolMust = QueryBuilderUtils.copyBoolQuery(boolMust);
        companyBoolMust(fillingBoolMust, UnitCategoryEnum.filling.getCode());
        Long useCount = getStatisticCount(useBoolMust, index);
        Long produceCount = getStatisticCount(produceBoolMust, index);
        Long fillingCount = getStatisticCount(fillingBoolMust, index);
        result.put("use", useCount);
        result.put("produce", produceCount);
        result.put("filling", fillingCount);
        return result;
    }

    private List<Map<String, Object>> queryDpEquipStatistics(JSONObject filter, SearchRequest request, SearchSourceBuilder builder, BoolQueryBuilder boolMust, Map<String, Object> tabTotalMap) {

        request.indices(StatisticalAnalysisEnum.equip.getKey());
        JSONObject filterParams = new JSONObject();
        // 筛选
        if (!ObjectUtils.isEmpty(filter.get("filterParams"))) {
            filterParams = JSONObject.parseObject(JSONObject.toJSONString(filter.get("filterParams")));
            String filterType = "advanced";
            // 组装查询条件
            getEquipmentBoolQueryBuilder(boolMust, filterParams, filterType);
        }

        JSONArray typeData = filter.getJSONArray("typeData");
        String groupField = null;

        List<Map<String, Object>> staticCountByGroupMap = new ArrayList<>();

        String equipCode = null;
        if (!ObjectUtils.isEmpty(typeData)) {
            String id = null;
            JSONObject jsonObject = new JSONObject();
            if (typeData.size() == 1) {
                groupField = "EQU_CATEGORY_CODE";
                jsonObject = JSONObject.parseObject(JSONObject.toJSONString(typeData.get(0)));
            } else if (typeData.size() == 2) {
                groupField = "EQU_DEFINE_CODE";
                jsonObject = JSONObject.parseObject(JSONObject.toJSONString(typeData.get(1)));
            }
            id = jsonObject.getString("key");
            equipCode = jsonObject.getString("code");
            // 当前端点击气瓶时候，将分组字段修改为设备类别
            if (equipCode.equals("2300")) {
                groupField = "EQU_DEFINE_CODE";
            }
            staticCountByGroupMap = tzsCustomFilterMapper.selectEquipmentCategoryByParentId(id);
        } else {
            groupField = "EQU_LIST_CODE";
            Map<String, List<Map<String, Object>>> resourceJson = JsonUtils.getResourceJson(equipCategory);
            staticCountByGroupMap = resourceJson.get(EquipmentClassifityEnum.ZHTJFX.getCode());
        }
        boolMust.mustNot(QueryBuilders.termsQuery("STATUS", Arrays.asList("草稿", "已拒领", "待认领")));

        Map<String, Object> staticCountByGroup = new HashMap<>();
        // 组装数据
        List<Map<String, Object>> resultList = new ArrayList<>();
        List<Map<String, Object>> dataMapList = new ArrayList<>();
        // 当设备默认进入时候，提前复制前置查询条件，供气瓶提级使用
        BoolQueryBuilder gasBoolQueryBuilder = new BoolQueryBuilder();
        if (groupField.equals("EQU_LIST_CODE")) {
            gasBoolQueryBuilder = QueryBuilderUtils.copyBoolQuery(boolMust);
        }
        if (!"2300".equals(equipCode)) {
            boolMust.mustNot(QueryBuilders.matchQuery("EQU_CATEGORY_CODE", "2300"));
        }
        getStatisticCountByGroup(request, builder, boolMust, groupField, staticCountByGroup, "noGas");

        AtomicReference<Long> otherCount = new AtomicReference<>(0L);
        staticCountByGroup.forEach((key, value) -> {
            if (!key.startsWith("8") && !key.equals("NA")) {
                otherCount.updateAndGet(v -> v + Long.valueOf(value.toString()));
            }
        });
        tabTotalMap.put(StatisticalAnalysisEnum.equip.getCode(), otherCount.toString());

        List<String> codes = new ArrayList<>();
        BoolQueryBuilder pipeBoolMust = QueryBuilderUtils.copyBoolQuery(boolMust);
        Long oneClassCount = 0L;
        Long twoClassCount = 0L;
        Long threeClassCount = 0L;
        for (Map<String, Object> categoryMap : staticCountByGroupMap) {
            BoolQueryBuilder queryBuilder = QueryBuilderUtils.copyBoolQuery(pipeBoolMust);
            String code = categoryMap.get("value").toString();
            codes.add(code);
            // 去除类别中的气瓶
            if (code.equals("2300")) {
                staticCountByGroup.remove(code);
                continue;
            }
            Map<String, Object> map = new HashMap<>();
            map.put("key", categoryMap.get("key"));
            map.put("label", categoryMap.get("label"));
            map.put("code", categoryMap.get("value"));
            map.put("fieldKey", groupField.replace("_CODE", ""));
            Object value = staticCountByGroup.containsKey(code) ? staticCountByGroup.get(code) : 0L;
            if (code.startsWith("8")) {
                queryBuilder.must(QueryBuilders.termQuery(groupField, code));
                BigDecimal pipeLength = getPipeLength(queryBuilder, builder, code);
                value = pipeLength.divide(new BigDecimal(1000), 4, BigDecimal.ROUND_HALF_UP);
            }
            map.put("value", value);
            map.put("img", dpEquipPhotoPrefix + code + dpEquipPhotoSuffix);
            Integer count = tzsCustomFilterMapper.selectEquipmentCategoryCountByParentId(categoryMap.get("key").toString());
            map.put("noChild", 0 == count ? Boolean.TRUE : Boolean.FALSE);
            map.put("measurementUnit", code.startsWith("8") ? "千米" : code.startsWith("2") ? "个" : "台套");
            map.put("noBottom", code.startsWith("8") ? Boolean.TRUE : Boolean.FALSE);
            // 统计该分类下的数据完整性的分组数量 DATA_QUALITY_SCORE
            BoolQueryBuilder scoreQuery = QueryBuilderUtils.copyBoolQuery(boolMust);
            scoreQuery.must(QueryBuilders.termQuery(groupField, code));
            SearchSourceBuilder scoreBuilder = new SearchSourceBuilder();
            Map<String, Object> scoreCountByGroup = new HashMap<>();
            getStatisticCountByGroup(request, scoreBuilder, scoreQuery, "DATA_QUALITY_SCORE", scoreCountByGroup, "scoreCount");
            if (!code.startsWith("8")) {
                for (String key : scoreCountByGroup.keySet()) {
                    if ("1".equals(key)) {
                        oneClassCount += (Long) scoreCountByGroup.get(key);
                    } else if ("2".equals(key)) {
                        twoClassCount += (Long) scoreCountByGroup.get(key);
                    } else if ("3".equals(key)) {
                        threeClassCount += (Long) scoreCountByGroup.get(key);
                    }
                }
            }
            map.put("DATA_QUALITY_SCORE", scoreCountByGroup);
            // 统计该分类下红黄绿码分别的分组数量 NEXT_INSPECT_DATE
            Map<String, Long> nextInspectCountByGroup = new HashMap<>();
            BoolQueryBuilder nextInspectQuery = QueryBuilderUtils.copyBoolQuery(boolMust);
            nextInspectQuery.must(QueryBuilders.termQuery(groupField, code));
            getStatisticCountByDate(StatisticalAnalysisEnum.equip.getKey(), "NEXT_INSPECT_DATE", nextInspectQuery, nextInspectCountByGroup);
            map.put("NEXT_INSPECT_DATE", nextInspectCountByGroup);
            staticCountByGroup.remove(code);
            dataMapList.add(map);
        }

        // 将气瓶提级
        if (groupField.equals("EQU_LIST_CODE")) {
            List<Map<String, Object>> gasList = new ArrayList<>();
            Map<String, Object> gas = new HashMap<>();
            String code = "2300";
            String fieldKey = "EQU_CATEGORY_CODE";
            gas.put("key", "19");
            gas.put("label", "气瓶");
            gas.put("value", code);
            gasList.add(gas);
            Map<String, Object> gasCountByGroup = new HashMap<>();
            gasBoolQueryBuilder.must(QueryBuilders.matchQuery(fieldKey, code));
            getStatisticCountByGroup(request, builder, gasBoolQueryBuilder, fieldKey, gasCountByGroup, "gas");
            Map<String, Object> map = new HashMap<>();
            map.put("key", gas.get("key"));
            map.put("label", gas.get("label"));
            map.put("code", gas.get("value"));
            map.put("fieldKey", fieldKey.replace("_CODE", ""));
            Object value = gasCountByGroup.containsKey(code) ? gasCountByGroup.get(code) : 0L;
            map.put("value", value);
            map.put("img", dpEquipPhotoPrefix + code + dpEquipPhotoSuffix);
            Integer count = tzsCustomFilterMapper.selectEquipmentCategoryCountByParentId(gas.get("key").toString());
            map.put("noChild", 0 == count ? Boolean.TRUE : Boolean.FALSE);
            map.put("measurementUnit", "个");
            map.put("noBottom", Boolean.FALSE);
            // 统计该分类下的数据完整性的分组数量 DATA_QUALITY_SCORE
            BoolQueryBuilder scoreQuery = QueryBuilderUtils.copyBoolQuery(gasBoolQueryBuilder);
            scoreQuery.must(QueryBuilders.termQuery(fieldKey, code));
            SearchSourceBuilder scoreBuilder = new SearchSourceBuilder();
            Map<String, Object> scoreCountByGroup = new HashMap<>();
            getStatisticCountByGroup(request, scoreBuilder, scoreQuery, "DATA_QUALITY_SCORE", scoreCountByGroup, "scoreCount");
            map.put("DATA_QUALITY_SCORE", scoreCountByGroup);
            // 统计该分类下红黄绿码分别的分组数量 NEXT_INSPECT_DATE
            Map<String, Long> nextInspectCountByGroup = new HashMap<>();
            BoolQueryBuilder nextInspectQuery = QueryBuilderUtils.copyBoolQuery(gasBoolQueryBuilder);
            nextInspectQuery.must(QueryBuilders.termQuery(fieldKey, code));
            getStatisticCountByDate(StatisticalAnalysisEnum.equip.getKey(), "NEXT_INSPECT_DATE", nextInspectQuery, nextInspectCountByGroup);
            map.put("NEXT_INSPECT_DATE", nextInspectCountByGroup);
            dataMapList.add(map);
        }

        BigDecimal otherPipeLength = new BigDecimal(0);
        // 其他种类的
        if (!groupField.equals("EQU_LIST_CODE") && !ObjectUtils.isEmpty(equipCode) && equipCode.startsWith("8")) {
            if (groupField.equals("EQU_CATEGORY_CODE")) {
                pipeBoolMust.mustNot(QueryBuilders.termsQuery("EQU_CATEGORY_CODE", codes));
            }
            if (groupField.equals("EQU_DEFINE_CODE")) {
                pipeBoolMust.mustNot(QueryBuilders.termsQuery("EQU_DEFINE_CODE", codes));
            }
            BigDecimal pipeLength = getPipeLength(pipeBoolMust, builder, "other");
            BigDecimal divide = pipeLength.divide(new BigDecimal(1000), 4, BigDecimal.ROUND_HALF_UP);
            otherPipeLength = otherPipeLength.add(divide);
            staticCountByGroup.put("N/A", otherPipeLength);
        }

        // 统计种类/类别/品种数据不对的数据字段
        if (!ObjectUtils.isEmpty(staticCountByGroup)) {
            statisticOtherCount(request, dataMapList, staticCountByGroup, boolMust, groupField, equipCode);
        }

        if (!ObjectUtils.isEmpty(equipCode)) {
            if (equipCode.startsWith("8")) {
                BigDecimal pipeLengthCount = new BigDecimal(0);
                for (Map<String, Object> map : dataMapList) {
                    BigDecimal value = (BigDecimal) map.get("value");
                    pipeLengthCount = pipeLengthCount.add(value);
                }
                tabTotalMap.put(equipCode, pipeLengthCount);
            } else {
                tabTotalMap.put(equipCode, dataMapList.stream().mapToLong(map -> (Long) map.get("value")).sum());
            }
        }
        for (int i = 1; i < 4; i++) {
            Map<String, Object> map = new HashMap<>();
            map.put("key", i);
            map.put("code", i);
            map.put("noChild", Boolean.TRUE);
            map.put("noBottom", Boolean.TRUE);
            map.put("fieldKey", "DATA_QUALITY_SCORE");
            String imgUrl = String.format("/upload/tzs/dpscreen/statistic/datalevel%s.png", i);
            map.put("img", imgUrl);
            map.put("label", i == 1 ? "一类设备" : i == 2 ? "二类设备" : "三类设备");
            map.put("value", i == 1 ? oneClassCount : i == 2 ? twoClassCount : threeClassCount);
            resultList.add(map);
        }
        resultList.addAll(dataMapList);
        return resultList;
    }

    private void statisticOtherCount(SearchRequest request, List<Map<String, Object>> dataMapList, Map<String, Object> staticCountByGroup, BoolQueryBuilder boolMust, String groupField, String equipCode) {
        String type = "other";
        Long otherCount = 0L;
        BigDecimal otherPipeLength = new BigDecimal(0);
        Long oneCount = 0L;
        Long twoCount = 0L;
        Long threeCount = 0L;
        Long redCount = 0L;
        Long yellowCount = 0L;
        Long greenCount = 0L;
        Long grayCount = 0L;

        Boolean isOther = false;
        for (String key : staticCountByGroup.keySet()) {
            otherCount += staticCountByGroup.get(key) instanceof Long ? (Long) staticCountByGroup.get(key) : 0L;
            if (staticCountByGroup.get(key) instanceof BigDecimal) {
                isOther = true;
                otherPipeLength = otherPipeLength.add((BigDecimal) staticCountByGroup.get(key));
            }
            // 统计该分类下的数据完整性的分组数量 DATA_QUALITY_SCORE
            BoolQueryBuilder scoreQuery = QueryBuilderUtils.copyBoolQuery(boolMust);
            if (key.equals("NA")) {
                scoreQuery.mustNot(existsQuery(groupField));
            } else {
                scoreQuery.must(QueryBuilders.termQuery(groupField, key));
            }
            SearchSourceBuilder scoreBuilder = new SearchSourceBuilder();
            Map<String, Object> scoreCountByGroup = new HashMap<>();
            getStatisticCountByGroup(request, scoreBuilder, scoreQuery, "DATA_QUALITY_SCORE", scoreCountByGroup, "scoreCount");
            oneCount += scoreCountByGroup.containsKey("1") ? (Long) scoreCountByGroup.get("1") : 0L;
            twoCount += scoreCountByGroup.containsKey("2") ? (Long) scoreCountByGroup.get("2") : 0L;
            threeCount += scoreCountByGroup.containsKey("3") ? (Long) scoreCountByGroup.get("3") : 0L;

            // 统计该分类下红黄绿码分别的分组数量 NEXT_INSPECT_DATE
            Map<String, Long> nextInspectCountByGroup = new HashMap<>();
            BoolQueryBuilder nextInspectQuery = QueryBuilderUtils.copyBoolQuery(boolMust);
            if (key.equals("NA")) {
                nextInspectQuery.mustNot(existsQuery(groupField));
            } else {
                nextInspectQuery.must(QueryBuilders.termQuery(groupField, key));
            }
            getStatisticCountByDate(StatisticalAnalysisEnum.equip.getKey(), "NEXT_INSPECT_DATE", nextInspectQuery, nextInspectCountByGroup);
            redCount += nextInspectCountByGroup.containsKey("red") ? nextInspectCountByGroup.get("red") : 0L;
            yellowCount += nextInspectCountByGroup.containsKey("yellow") ? nextInspectCountByGroup.get("yellow") : 0L;
            greenCount += nextInspectCountByGroup.containsKey("green") ? nextInspectCountByGroup.get("green") : 0L;
            grayCount += nextInspectCountByGroup.containsKey("gray") ? nextInspectCountByGroup.get("gray") : 0L;
        }
        Map<String, Object> map = new HashMap<>();
        map.put("key", type);
        map.put("label", "其他");
        map.put("code", type);
        map.put("fieldKey", type);
        map.put("noChild", Boolean.TRUE);
        map.put("value", isOther ? otherPipeLength : otherCount);
        map.put("img", dpEquipPhotoPrefix + type + dpEquipPhotoSuffix);
        map.put("measurementUnit", equipCode != null && equipCode.startsWith("8") ? "千米" : equipCode != null && equipCode.startsWith("2") ? "个" : "台套");
        map.put("noBottom", equipCode != null && equipCode.startsWith("8") ? Boolean.TRUE : Boolean.FALSE);
        Map<String, Long> scoreCount = new HashMap<>();
        scoreCount.put("1", oneCount);
        scoreCount.put("2", twoCount);
        scoreCount.put("3", threeCount);
        map.put("DATA_QUALITY_SCORE", scoreCount);
        Map<String, Long> nextInspectCount = new HashMap<>();
        nextInspectCount.put("red", redCount);
        nextInspectCount.put("yellow", yellowCount);
        nextInspectCount.put("green", greenCount);
        nextInspectCount.put("gray", grayCount);
        map.put("NEXT_INSPECT_DATE", nextInspectCount);
        dataMapList.add(map);
    }

    private void getStatisticCountByDate(String index, String field, BoolQueryBuilder nextInspectQuery, Map<String, Long> nextInspectCountByGroup) {
        // 超期
        BoolQueryBuilder overdueQuery = QueryBuilderUtils.copyBoolQuery(nextInspectQuery);
        overdueQuery.filter(QueryBuilders.rangeQuery(field).lt(LocalDate.now().format(formatter)));
        Long overdueCount = getStatisticCount(overdueQuery, index);
        // 临期
        BoolQueryBuilder nearQuery = QueryBuilderUtils.copyBoolQuery(nextInspectQuery);
        nearQuery.filter(QueryBuilders.rangeQuery(field).gte(LocalDate.now().format(formatter)).lte(LocalDate.now().plusDays(30).format(formatter)));
        Long nearCount = getStatisticCount(nearQuery, index);
        // 正常
        BoolQueryBuilder normalQuery = QueryBuilderUtils.copyBoolQuery(nextInspectQuery);
        normalQuery.filter(QueryBuilders.rangeQuery(field).gt(LocalDate.now().plusDays(30).format(formatter)));
        Long normalCount = getStatisticCount(normalQuery, index);
        // 无日期
        BoolQueryBuilder noFieldQuery = QueryBuilderUtils.copyBoolQuery(nextInspectQuery);
        noFieldQuery.mustNot(existsQuery(field));
        Long noFieldCount = getStatisticCount(noFieldQuery, index);
        nextInspectCountByGroup.put("red", overdueCount);
        nextInspectCountByGroup.put("yellow", nearCount);
        nextInspectCountByGroup.put("green", normalCount);
        nextInspectCountByGroup.put("gray", noFieldCount);
    }

    private void getStatisticCountByGroup(SearchRequest request, SearchSourceBuilder builder, BoolQueryBuilder boolMust, String groupField, Map<String, Object> staticCountByGroup, String groupKey) {
        builder.query(boolMust);
        if (groupField.equals("DATA_QUALITY_SCORE")) {
            builder.aggregation(AggregationBuilders.terms(groupKey).field(groupField).missing(99).size(50));
        } else {
            builder.aggregation(AggregationBuilders.terms(groupKey).field(groupField).missing("NA").size(50));
        }
        request.source(builder);
        try {
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            Terms terms = response.getAggregations().get(groupKey);
            for (Terms.Bucket bucket : terms.getBuckets()) {
                staticCountByGroup.put(bucket.getKeyAsString(), bucket.getDocCount());
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 大屏综合统计查询接口--人员统计
     *
     * @param filter 过滤条件
     * @return 按照 【资质状态】 【人员类型】分组统计返回
     */
    public JSONObject queryDpStatisticsForPerson(JSONObject filter) {

        JSONObject result = new JSONObject();
        String businessType = filter.getString("businessType");
        if (ObjectUtils.isEmpty(businessType)) {
            return result;
        }

        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        String orgCode = filter.getString("orgCode");
//        boolQuery.must(QueryBuilders.prefixQuery("superviseOrgCode", orgCode));

        JSONObject filterParams = JSONObject.parseObject(JSONObject.toJSONString(filter.get("filterParams")));
        String filterType = "advanced";
        // 组装人员过滤条件
        personOrgCodeBoolMust(orgCode, boolQuery, StatisticalAnalysisEnum.person.getCode());
        this.getPersonBoolQueryBuilder(filterParams, boolQuery, filterType);
        // 查询
        JSONObject expiryDateStatus = this.getExpiryDateStatusGroupStatistics(boolQuery);
        JSONObject personType = this.getPersonTypeGroupStatistics(boolQuery);
        result.put("tabTotalMap", new JSONObject()
                .fluentPut("expiryDateStatusTotal", this.sumWithJSONObjectValues(expiryDateStatus))
                .fluentPut("personTypeTotal", this.sumWithJSONObjectValues(personType)));
        result.put("datas", new JSONObject()
                .fluentPut("expiryDateStatus", expiryDateStatus)
                .fluentPut("personType", personType));
        return result;
    }

    /**
     * 对JSONObject类型的所有values求和
     *
     * @param jsonObject
     * @return
     */
    private long sumWithJSONObjectValues(JSONObject jsonObject) {
        long result = 0L;
        for (String key : jsonObject.keySet()) {
            long longValue = Long.parseLong(jsonObject.getString(key));
            result += longValue;
        }
        return result;
    }

    /**
     * 大屏综合统计查询接口--人员统计 【资质状态】分组统计
     */
    private JSONObject getExpiryDateStatusGroupStatistics(BoolQueryBuilder boolQuery) {
        JSONObject result = new JSONObject();

        String path = "licenses";
        String nestedField = path + ".expiryDate";
        // 需要资质的人员必须条件
        BoolQueryBuilder needLicensesQueryBuilder = tzsCommonService.getNotLicencesBuilderWithPerson();
        // 资质正常
        BoolQueryBuilder normalBoolQuery = QueryBuilderUtils.copyBoolQuery(boolQuery);
        NestedQueryBuilder normalNestedQuery = QueryBuilders.nestedQuery(
                path,
                QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery(nestedField).gt(LocalDate.now().plusDays(30).format(formatter))),
                ScoreMode.None
        );
        normalBoolQuery.must(normalNestedQuery);
        normalBoolQuery.must(needLicensesQueryBuilder);
        Long normalCount = getStatisticCount(normalBoolQuery, StatisticalAnalysisEnum.person.getKey());
        result.put("zzzc", normalCount);

        // 资质临期
        BoolQueryBuilder nearBoolQuery = QueryBuilderUtils.copyBoolQuery(boolQuery);
        NestedQueryBuilder nearNestedQuery = QueryBuilders.nestedQuery(
                path,
                QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery(nestedField).lte(LocalDate.now().plusDays(30).format(formatter)).gte(LocalDate.now().format(formatter))),
                ScoreMode.None
        );
        nearBoolQuery.must(nearNestedQuery);
        nearBoolQuery.must(needLicensesQueryBuilder);
        Long nearCount = getStatisticCount(nearBoolQuery, StatisticalAnalysisEnum.person.getKey());
        result.put("zzlq", nearCount);

        // 资质超期
        BoolQueryBuilder overBoolQuery = QueryBuilderUtils.copyBoolQuery(boolQuery);
        NestedQueryBuilder overNestedQuery = QueryBuilders.nestedQuery(
                path,
                QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery(nestedField).lte(LocalDate.now().format(formatter))),
                ScoreMode.None
        );
        overBoolQuery.must(overNestedQuery);
        overBoolQuery.must(needLicensesQueryBuilder);
        Long overCount = getStatisticCount(overBoolQuery, StatisticalAnalysisEnum.person.getKey());
        result.put("zzcq", overCount);

        // 无有效期
        BoolQueryBuilder nothingBoolQuery = QueryBuilderUtils.copyBoolQuery(boolQuery);
        NestedQueryBuilder nothingNestedQuery = QueryBuilders.nestedQuery(
                path,
                QueryBuilders.boolQuery().mustNot(existsQuery(nestedField)),
                ScoreMode.None
        );
        nothingBoolQuery.must(nothingNestedQuery);
        nothingBoolQuery.must(needLicensesQueryBuilder);
        Long nothingCount = getStatisticCount(nothingBoolQuery, StatisticalAnalysisEnum.person.getKey());
        result.put("wyxq", nothingCount);

        // 无资质 : 需要资质的人员没有资质的情况
        BoolQueryBuilder notLicensesBoolQuery = QueryBuilderUtils.copyBoolQuery(boolQuery);

        DynamicQueryBuilder mainBuilder = new DynamicQueryBuilder();
        EnhancedDynamicQueryBuilder enhancedDynamicQueryBuilder = new EnhancedDynamicQueryBuilder();
        NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                path,
                existsQuery(nestedField),
                ScoreMode.None
        );

        EnhancedDynamicQueryBuilder noLicensesQuery = new EnhancedDynamicQueryBuilder();
        noLicensesQuery.add(QueryBuilders.boolQuery().mustNot(nestedQuery), and);
        noLicensesQuery.add(needLicensesQueryBuilder, and);
        enhancedDynamicQueryBuilder.add(noLicensesQuery.build(), "AND");

        mainBuilder.and(enhancedDynamicQueryBuilder.build());
        notLicensesBoolQuery.must(mainBuilder.build());
        Long otLicensesCount = getStatisticCount(notLicensesBoolQuery, StatisticalAnalysisEnum.person.getKey());
        result.put("wzz", otLicensesCount);

        // 无资质要求查询
        // BoolQueryBuilder notNeedLicensesBoolQuery = QueryBuilderUtils.copyBoolQuery(boolQuery);
        // // 不需要资质的人员查询构造条件
        // BoolQueryBuilder notNeedLicensesQueryBuilder = tzsCommonService.getNotNeedLicencesBuilderWithPerson();
        // DynamicQueryBuilder mainBuilderNotNeed = new DynamicQueryBuilder();
        // EnhancedDynamicQueryBuilder dynamicQueryBuilder = new EnhancedDynamicQueryBuilder();
        //
        // EnhancedDynamicQueryBuilder notNeedLicensesQuery = new EnhancedDynamicQueryBuilder();
        // notNeedLicensesQuery.add(notNeedLicensesQueryBuilder, and);
        // dynamicQueryBuilder.add(notNeedLicensesQuery.build(), "AND");
        //
        // mainBuilderNotNeed.and(dynamicQueryBuilder.build());
        // notNeedLicensesBoolQuery.must(mainBuilderNotNeed.build());
        // Long notNeedLicensesCount = getStatisticCount(notNeedLicensesBoolQuery, StatisticalAnalysisEnum.person.getKey());
        // result.put("wzzyq", notNeedLicensesCount);
        return result;
    }

    /**
     * 大屏综合统计查询接口--人员统计 【人员类型】分组统计
     */
    private JSONObject getPersonTypeGroupStatistics(BoolQueryBuilder boolQuery) {

        JSONObject result = new JSONObject();
        // copy一份，避免后续两部分逻辑不一致
        BoolQueryBuilder boolQueryCopy = QueryBuilderUtils.copyBoolQuery(boolQuery);

        // 除作业人员外的所有
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.trackTotalHits(true);
        searchSourceBuilder.size(0);// 不返回任何文档，只返回聚合结果
        SearchRequest searchRequest = new SearchRequest();
        String aggName = "personTypeGroupAgg";
        QueryBuilderUtils.buildSplitFieldAggCondition(searchSourceBuilder, "postName.keyword", ",", aggName, "其他");
        searchSourceBuilder.query(boolQuery);
        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            Terms personTypeGroupAgg = searchResponse.getAggregations().get(aggName);
            this.buildPersonWithPersonTypeGroupResult(personTypeGroupAgg, result);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }

        // 作业人员取 : 仅持证人员
        CountRequest countRequest = new CountRequest();
        countRequest.indices(StatisticalAnalysisEnum.person.getKey());
        boolQueryCopy.must(QueryBuilders.matchQuery("subPostName", "持证人员").operator(Operator.AND));
        countRequest.query(boolQueryCopy);
        CountResponse countResponse;
        try {
            countResponse = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT);
        } catch (Exception exception) {
            throw new RuntimeException(exception);
        }
        result.put("zyczry", ObjectUtils.isEmpty(countResponse) ? 0L : countResponse.getCount());
        return result;
    }

    /**
     * 大屏综合统计查询接口--企业监管标签分组统计
     */
    private JSONObject getItemGroupStatisticsByItemName(BoolQueryBuilder boolQuery, String indexName, String aggName, String itemName, BiConsumer<Terms, JSONObject> task) {

        JSONObject result = new JSONObject();

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.trackTotalHits(true);
        searchSourceBuilder.size(0);// 不返回任何文档，只返回聚合结果
        SearchRequest searchRequest = new SearchRequest();
        QueryBuilderUtils.buildSplitFieldAggCondition(searchSourceBuilder, itemName + ".keyword", "，", aggName, "其他");
        searchSourceBuilder.query(boolQuery);
        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            Terms itemGroupAgg = searchResponse.getAggregations().get(aggName);
            task.accept(itemGroupAgg, result);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
        return result;
    }

    private void buildPersonWithPersonTypeGroupResult(Terms personTypeGroupAgg, JSONObject result) {
        result.fluentPut("zyfzr", 0L).fluentPut("aqzj", 0L).fluentPut("aqy", 0L).fluentPut("jyry", 0L).fluentPut("jcry", 0L).fluentPut("zlaqzj", 0L).fluentPut("zlaqy", 0L);
        if (personTypeGroupAgg != null) {
            for (Terms.Bucket bucket : personTypeGroupAgg.getBuckets()) {
                if (bucket.getKeyAsString().equals(PersonTypeEnum.zyfzr.getName())) {
                    result.put("zyfzr", bucket.getDocCount());
                }
                if (bucket.getKeyAsString().equals(PersonTypeEnum.aqzj.getName())) {
                    result.put("aqzj", bucket.getDocCount());
                }
                if (bucket.getKeyAsString().equals(PersonTypeEnum.aqy.getName())) {
                    result.put("aqy", bucket.getDocCount());
                }
                if (bucket.getKeyAsString().equals(PersonTypeEnum.jyry.getName())) {
                    result.put("jyry", bucket.getDocCount());
                }
                if (bucket.getKeyAsString().equals(PersonTypeEnum.jcry.getName())) {
                    result.put("jcry", bucket.getDocCount());
                }
                if (bucket.getKeyAsString().equals(PersonTypeEnum.zlaqzj.getName())) {
                    result.put("zlaqzj", bucket.getDocCount());
                }
                if (bucket.getKeyAsString().equals(PersonTypeEnum.zlaqy.getName())) {
                    result.put("zlaqy", bucket.getDocCount());
                }
            }
        }
    }

    private void buildRegulatoryLabelsGroupResult(Terms groupAgg, JSONObject result) {
        if (groupAgg == null) {
            return;
        }
        JSONArray regulatoryLabels = deployDictionary(dataDictionaryService.getByType("QYBQ"));

        Map<String, String> keyToValueMap = new HashMap<>();
        for (Object obj : regulatoryLabels) {
            if (obj instanceof JSONObject) {
                String key = ((JSONObject) obj).getString("key");
                String value = ((JSONObject) obj).getString("extendCode");
                if (key != null && value != null) {
                    keyToValueMap.put(key, value);
                    result.put(value, 0); // 初始化为 0
                }
            }
        }

        for (Terms.Bucket bucket : groupAgg.getBuckets()) {
            String bucketKey = bucket.getKeyAsString();
            String mappedValue = keyToValueMap.get(bucketKey);
            if (mappedValue != null) {
                result.put(mappedValue, bucket.getDocCount());
            } else if ("其他".equals(bucketKey)) {
                result.put("other", bucket.getDocCount());
            }
        }

//        for (Terms.Bucket bucket : groupAgg.getBuckets()) {
//            String bucketKey = bucket.getKeyAsString();
//            for (Object obj : regulatoryLabels) {
//                JSONObject jsonObject = (JSONObject) obj;
//                result.put(jsonObject.getString("extendCode"), 0);
//                if (jsonObject.getString("label").equals(bucketKey)) {
//                    result.put(jsonObject.getString("extendCode"), bucket.getDocCount());
//                    break;
//                }
//            }
//            if (bucketKey.equals("其他")) {
//                result.put("other", bucket.getDocCount());
//            }
//        }
    }

    private void buildIndustrySupervisorGroupResult(Terms groupAgg, JSONObject result) {
        if (groupAgg == null) {
            return;
        }
        JSONArray industrySupervisor = deployDictionary(dataDictionaryService.getByType("HYZGBM"));

        Map<String, String> keyToValueMap = new HashMap<>();
        for (Object obj : industrySupervisor) {
            if (obj instanceof JSONObject) {
                String key = ((JSONObject) obj).getString("key");
                String value = ((JSONObject) obj).getString("value");
                if (key != null && value != null) {
                    keyToValueMap.put(key, value);
                    result.put(value, 0); // 初始化为 0
                }
            }
        }
        // 处理 buckets
        for (Terms.Bucket bucket : groupAgg.getBuckets()) {
            String bucketKey = bucket.getKeyAsString();
            String mappedValue = keyToValueMap.get(bucketKey);
            if (mappedValue != null) {
                result.put(mappedValue, bucket.getDocCount());
            } else if ("其他".equals(bucketKey)) {
                result.put("other", bucket.getDocCount());
            }
        }
    }

    private JSONObject getPermitStatusGroupStatistics(BoolQueryBuilder boolQuery) {
        JSONObject result = new JSONObject();

        String path = "licenses";
        String nestedField = path + ".expiryDate";
        // 许可正常
        BoolQueryBuilder normalBoolQuery = QueryBuilderUtils.copyBoolQuery(boolQuery);
        NestedQueryBuilder normalNestedQuery = QueryBuilders.nestedQuery(
                path,
                QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery(nestedField).gt(LocalDate.now().plusDays(30).format(formatter))),
                ScoreMode.None
        );
        normalBoolQuery.must(normalNestedQuery);
        Long normalCount = getStatisticCount(normalBoolQuery, StatisticalAnalysisEnum.company.getKey());
        result.put("xkzc", normalCount);

        // 许可临期
        BoolQueryBuilder nearBoolQuery = QueryBuilderUtils.copyBoolQuery(boolQuery);
        NestedQueryBuilder nearNestedQuery = QueryBuilders.nestedQuery(
                path,
                QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery(nestedField).lte(LocalDate.now().plusDays(30).format(formatter)).gte(LocalDate.now().format(formatter))),
                ScoreMode.None
        );
        nearBoolQuery.must(nearNestedQuery);
        Long nearCount = getStatisticCount(nearBoolQuery, StatisticalAnalysisEnum.company.getKey());
        result.put("xklq", nearCount);

        // 许可超期
        BoolQueryBuilder overBoolQuery = QueryBuilderUtils.copyBoolQuery(boolQuery);
        NestedQueryBuilder overNestedQuery = QueryBuilders.nestedQuery(
                path,
                QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery(nestedField).lte(LocalDate.now().format(formatter))),
                ScoreMode.None
        );
        overBoolQuery.must(overNestedQuery);
        Long overCount = getStatisticCount(overBoolQuery, StatisticalAnalysisEnum.company.getKey());
        result.put("xkcq", overCount);

        // 无有效期
        BoolQueryBuilder nothingBoolQuery = QueryBuilderUtils.copyBoolQuery(boolQuery);
        NestedQueryBuilder nothingNestedQuery = QueryBuilders.nestedQuery(
                path,
                QueryBuilders.boolQuery().mustNot(existsQuery(nestedField)),
                ScoreMode.None
        );
        nothingBoolQuery.must(nothingNestedQuery);
        Long nothingCount = getStatisticCount(nothingBoolQuery, StatisticalAnalysisEnum.company.getKey());
        result.put("wyxq", nothingCount);

        return result;
    }

    public Integer addGasRecordToSupervision() {
        Integer count = 500000;
        Integer times = 0;
        if (count != 0) {
            times = count / 5000;
            int last = count % 5000;
            if (last > 0) {
                times++;
            }
        } else {
            return 0;
        }
        Page<String> recordDtoPage = new Page<>();
        Integer total = 0;
        for (int j = 0; j <= times; j++) {
            recordDtoPage.setCurrent(j + 1);
            recordDtoPage.setSize(5000);
            Page<String> refreshRecords = tzsCustomFilterMapper.selectGasRecords(recordDtoPage);
            if (!ObjectUtils.isEmpty(refreshRecords) && refreshRecords.getRecords().size() > 0) {
                total += refreshRecords.getRecords().size();
                tzsCustomFilterMapper.addGas(refreshRecords.getRecords());
            }
        }
        return total;
    }

    public Object updateDataByOrgBranchCode(String code, Integer limit) {
        SearchRequest request = new SearchRequest();
        request.indices(StatisticalAnalysisEnum.equip.getKey());
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.trackTotalHits(true);
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
        // 1、从数据库查询对应设备类型下50*X得数据record
        Integer count = tzsCustomFilterMapper.selectRecordCount(code);
        if (count == 0) {
            return "数据库中该数据分类下无需要修改的数据";
        }
        limit = count > limit ? limit : count;
        List<String> records = tzsCustomFilterMapper.selectRecords(code, limit);
        // 2、从es中查询对应record的数据
        boolMust.must(QueryBuilders.termsQuery("SEQUENCE_NBR.keyword", records));
        builder.query(boolMust);
        builder.from(0);
        builder.size(limit);
        request.source(builder);
        // 数据库和es中都为50*X的数据集合
        List<String> allNotDateList = new ArrayList<>();
        // 数据库中为50*X的数据集合，但es中不为50*X的数据集合
        List<Map<String, Object>> dataList = new ArrayList<>();
        try {
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            for (SearchHit hit : response.getHits().getHits()) {
                JSONObject jsonObject = (JSONObject) JSONObject.toJSON(hit);
                JSONObject dto = jsonObject.getJSONObject("sourceAsMap");
                if (dto.containsKey("ORG_BRANCH_CODE")) {
                    //3、判断查询回来的数据中是否为50*X,如果是50*X，则记录下来进行做置空处理/如果不为50*X，则记录下来进行数据库修复
                    if ("50*X".equals(dto.getString("ORG_BRANCH_CODE"))) {
                        allNotDateList.add(dto.getString("SEQUENCE_NBR"));
                    } else {
                        Map<String, Object> dataMap = new HashMap<>();
                        dataMap.put("record", dto.getString("SEQUENCE_NBR"));
                        dataMap.put("orgBranchCode", dto.getString("ORG_BRANCH_CODE"));
                        dataList.add(dataMap);
                    }
                }
            }
            //4、是50*X的进行es和数据库的双向修改/不是50*X的只需要做数据库修改
            if (!ObjectUtils.isEmpty(allNotDateList)) {
                tzsCustomFilterMapper.setOrgBranchCodeIsNullByRecords(allNotDateList);
                Iterable<ESEquipmentInfo> allById = esEquipmentDao.findAllById(allNotDateList);
                if (!ObjectUtils.isEmpty(allById)) {
                    for (ESEquipmentInfo esEquipmentInfo : allById) {
                        esEquipmentInfo.setORG_BRANCH_CODE("");
                    }
                }
                esEquipmentDao.saveAll(allById);
            }
            // 修改为es中的数据
            if (!ObjectUtils.isEmpty(dataList)) {
                tzsCustomFilterMapper.updateOrgBranchCodeByRecords(dataList);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return records;
    }

    public Object getDataDifference(String code) {
        Map<String, Object> result = new HashMap<>();
        List<String> dataBase;
        List<String> esData;
        String index = StatisticalAnalysisEnum.getKey.get(code);
        List<String> dataBaseAllList = new ArrayList<>();
        List<String> esAllList = new ArrayList<>();
        if (code.equals(StatisticalAnalysisEnum.equip.getCode())) {
            LambdaQueryWrapper<IdxBizJgUseInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.select(IdxBizJgUseInfo::getRecord);
            List<IdxBizJgUseInfo> list = idxBizJgUseInfoMapper.selectList(lambdaQueryWrapper);
            dataBaseAllList = list.stream().map(IdxBizJgUseInfo::getRecord).collect(Collectors.toList());
            esData = getEsData(Long.valueOf(list.size()), index, dataBaseAllList);
            dataBase = getBaseData(Long.valueOf(list.size()), index, dataBaseAllList);
        } else {
            if (code.equals(StatisticalAnalysisEnum.company.getCode())) {
                LambdaQueryWrapper<TzBaseEnterpriseInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
                lambdaQueryWrapper.select(TzBaseEnterpriseInfo::getUseCode);
                lambdaQueryWrapper.eq(TzBaseEnterpriseInfo::getIsDelete, Boolean.FALSE);
                List<TzBaseEnterpriseInfo> list = tzBaseEnterpriseInfoMapper.selectList(lambdaQueryWrapper);
                dataBaseAllList = list.stream().map(TzBaseEnterpriseInfo::getUseCode).collect(Collectors.toList());
            } else if (code.equals(StatisticalAnalysisEnum.person.getCode())) {
                LambdaQueryWrapper<TzsUserInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
                lambdaQueryWrapper.select(TzsUserInfo::getCertificateNum);
                lambdaQueryWrapper.eq(TzsUserInfo::getIsDelete, Boolean.FALSE);
                lambdaQueryWrapper.isNotNull(TzsUserInfo::getCertificateNum);
                List<TzsUserInfo> tzsUserInfos = tzsUserInfoMapper.selectList(lambdaQueryWrapper);
                dataBaseAllList = tzsUserInfos.stream().map(TzsUserInfo::getCertificateNum).collect(Collectors.toList());
            }
            SearchRequest request = new SearchRequest();
            request.indices(index);
            SearchSourceBuilder builder = new SearchSourceBuilder();
            BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
            boolMust.must(QueryBuilders.prefixQuery("superviseOrgCode", "50"));
            builder.trackTotalHits(true);
            builder.from(0);
            builder.size(1000000);
            request.source(builder);
            try {
                SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
                for (SearchHit hit : response.getHits().getHits()) {
                    JSONObject jsonObject = (JSONObject) JSONObject.toJSON(hit);
                    JSONObject dto = jsonObject.getJSONObject("sourceAsMap");
                    if (code.equals(StatisticalAnalysisEnum.company.getCode())) {
                        esAllList.add(dto.getString("useCode"));
                    } else if (code.equals(StatisticalAnalysisEnum.person.getCode())) {
                        esAllList.add(dto.getString("certificateNum"));
                    }
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            esData = findElementsInANotInB(esAllList, dataBaseAllList);
            dataBase = findElementsInANotInB(dataBaseAllList, esAllList);
        }
        result.put("dataBase", dataBase);
        result.put("esData", esData);
        return result;
    }

    private List<String> getBaseData(Long count, String index, List<String> dataBaseAllList) {
        List<String> result = new ArrayList<>();
        Integer size = 10000;
        Long times;
        if (count != 0) {
            times = count / size;
            Long last = count % size;
            if (last > 0) {
                times++;
            }
        } else {
            return result;
        }
        Long total = 0L;
        for (int j = 0; j <= times; j++) {
            // 按照size和j从dataBaseAllList中分批次取数据
            if (j * size >= count) {
                break;
            }
            total += (j + 1) * size - 1;
            log.info("当前处理数据量：{}/{}", total, count);
            List<String> dataBaseRecords = dataBaseAllList.subList(j * size, (j + 1) * size - 1 > count ? count.intValue() : (j + 1) * size - 1);
            SearchRequest request = new SearchRequest();
            request.indices(index);
            SearchSourceBuilder builder = new SearchSourceBuilder();
            builder.trackTotalHits(true);
            BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
            boolMust.must(QueryBuilders.termsQuery("id", dataBaseRecords));
            boolMust.must(QueryBuilders.prefixQuery("ORG_BRANCH_CODE", "50"));
            boolMust.mustNot(QueryBuilders.termsQuery("STATUS", Arrays.asList("草稿", "已拒领", "待认领")));
            builder.from(0);
            builder.size(size);
            request.source(builder);
            List<String> esSearchRecords = new ArrayList<>();
            try {
                SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
                for (SearchHit hit : response.getHits().getHits()) {
                    JSONObject jsonObject = (JSONObject) JSONObject.toJSON(hit);
                    JSONObject dto = jsonObject.getJSONObject("sourceAsMap");
                    esSearchRecords.add(dto.getString("id"));
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            result = findElementsInANotInB(dataBaseAllList, esSearchRecords);
        }
        return result;
    }

    private List<String> getEsData(Long count, String index, List<String> dataBaseAllList) {
        Integer size = 10000;
        List<String> result = new ArrayList<>();
        Long times;
        if (count != 0) {
            times = count / size;
            Long last = count % size;
            if (last > 0) {
                times++;
            }
        } else {
            return result;
        }

        for (int j = 0; j <= times; j++) {
            SearchRequest request = new SearchRequest();
            request.indices(index);
            SearchSourceBuilder builder = new SearchSourceBuilder();
            builder.trackTotalHits(true);
            builder.from((j * size) >= count ? count.intValue() : (j * size));
            builder.size(size);
            request.source(builder);
            List<String> esSearchRecords = new ArrayList<>();
            try {
                SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
                for (SearchHit hit : response.getHits().getHits()) {
                    JSONObject jsonObject = (JSONObject) JSONObject.toJSON(hit);
                    JSONObject dto = jsonObject.getJSONObject("sourceAsMap");
                    esSearchRecords.add(dto.getString("SEQUENCE_NBR"));
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            if (!ObjectUtils.isEmpty(esSearchRecords)) {
                LambdaQueryWrapper<IdxBizJgUseInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
                lambdaQueryWrapper.select(IdxBizJgUseInfo::getRecord);
                lambdaQueryWrapper.in(IdxBizJgUseInfo::getRecord, esSearchRecords);
                List<IdxBizJgUseInfo> list = idxBizJgUseInfoMapper.selectList(lambdaQueryWrapper);
                dataBaseAllList = list.stream().map(IdxBizJgUseInfo::getRecord).collect(Collectors.toList());
            }
            List<String> elementsInANotInB = findElementsInANotInB(esSearchRecords, dataBaseAllList);
            result.addAll(elementsInANotInB);
        }
        return result;
    }

    // 找出AList中不在BList中的元素
    public static List<String> findElementsInANotInB(List<String> listA, List<String> listB) {
        Set<String> bSet = Collections.synchronizedSet(new HashSet<>(listB));

        return listA.parallelStream()
                .filter(element -> !bSet.contains(element))
                .collect(Collectors.toList());
    }

    /**
     * 获取数据库与ES数据差异：找出ES比数据库多的记录ID
     */
    public Object getDataDifferenceV2() {
        Map<String, Object> result = new HashMap<>();
        List<String> extraInEs;

        // 获取索引
        String index = "idx_biz_view_jg_all";
        // 1. 查询数据库中所有设备 record
        //List<String> dbRecords = idxBizJgUseInfoMapper.selectEquipsClaimStatus();
        LambdaQueryWrapper<IdxBizJgUseInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.select(IdxBizJgUseInfo::getRecord);
        List<IdxBizJgUseInfo> list = idxBizJgUseInfoMapper.selectList(lambdaQueryWrapper);
        List<String> dbRecords = list.stream().map(IdxBizJgUseInfo::getRecord).collect(Collectors.toList());
        log.info("数据库设备记录数: {}", dbRecords.size());
        // 2. 从ES中查询对应记录
        List<String> esRecords = getEsDataV2(index);
        log.info("ES设备记录数: {}", esRecords.size());

        // 3. 对比差异（ES比DB多的记录）
        extraInEs = findElementsInANotInB(esRecords, dbRecords);
        log.info("ES比数据库多的记录数: {}", extraInEs.size());

        result.put("extraInEs", extraInEs);
        return result;
    }

    /**
     * 从 ES 中拉取索引中所有的 SEQUENCE_NBR（match_all）
     */
    private List<String> getEsDataV2(String index) {
        // 使用 match_all 查询，拉取所有文档（通过 scroll 分批）
        log.info("ES 全量查询开始, index={}, 时间={}", index, System.currentTimeMillis());
        //BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
        //      .must(QueryBuilders.termsQuery("STATUS", Collections.singletonList("已认领")));
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.matchAllQuery());
        // 线程安全的结果容器
        List<String> esIds = Collections.synchronizedList(new ArrayList<>());

        try {
            esSearchService.searchResponseInBatch(index, boolQuery, 2000, searchHits -> {
                // 每个批次只解析需要的字段
                List<String> batchIds = searchHits.stream()
                        .map(hit -> {
                            ESEquipmentCategoryDto dto = JSONObject.parseObject(hit.getSourceAsString(), ESEquipmentCategoryDto.class);
                            return dto == null ? null : dto.getSEQUENCE_NBR();
                        })
                        .filter(Objects::nonNull)
                        .collect(Collectors.toList());
                esIds.addAll(batchIds);
            });
        } catch (Exception ex) {
            log.error("ES 全量查询异常, index={}, 错误={}", index, ex.getMessage(), ex);
            throw new RuntimeException("ES 查询失败: " + ex.getMessage(), ex);
        }
        // 去重并返回
        return esIds.stream().distinct().collect(Collectors.toList());
    }

}
