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.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
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.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.dto.TechParamItem;
import com.yeejoin.amos.boot.module.common.api.entity.ESEquipmentInfo;
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.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.enums.EquipmentClassifityEnum;
import com.yeejoin.amos.boot.module.ymt.api.mapper.EquipmentCategoryMapper;
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.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.ParsedSum;
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.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.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
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.function.BiConsumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;

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 EmqKeeper emqKeeper;
    private final EquipmentCategoryMapper tzEquipmentCategoryMapper;

    private final StCommonServiceImpl stCommonService;
    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 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");
    private final List<String> companyHandleOtherFields = Arrays.asList("itemCode", "subItemCode", "permitStatus", "equipCategory", "regulatoryLabels", "unitType");
    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 ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());


    @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 = jsonObject.getString("EQU_CATEGORY");
        String equDefine = jsonObject.getString("EQU_DEFINE");
        String vehicleCylinder = "1".equals(jsonObject.getString("WHETHER_VEHICLE_CYLINDER")) ? "vehicleCylinder" : null;
        List<TechParamItem> paramMetaList = TechParamUtil.getParamMetaList(equList, equCategory, equDefine, vehicleCylinder);
        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查询数据字典
        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();

        String orgCode = filter.getString("orgCode");
        boolMust.must(QueryBuilders.prefixQuery("superviseOrgCode", orgCode));

        JSONObject filterParams = null;
        if (!ObjectUtils.isEmpty(filter.get("filterParams"))) {
            filterParams = JSONObject.parseObject(JSONObject.toJSONString(filter.get("filterParams")));
            String filterType = "advanced";
            // 组装人员过滤条件
            this.getPersonBoolQueryBuilder(filterParams, boolMust, filterType);
        }
        // 组装人员排序条件
        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));
                }
                StringBuilder licensesStatus = new StringBuilder();
                if (dto.containsKey("licenses")) {
                    // 以下人员类型有资质要求
                    // 人员类型(newPost)：检验人员：66151、检测人员：66152、作业人员：6552、检查人员：6763
                    // 人员子类型(subPost)： 持证人员:6713、持证人员(P):6764、持证人员(R2):6765
                    String newPost = ObjectUtils.isEmpty(dto.getString("newPost")) ? "" : dto.getString("newPost");
                    String subPost = ObjectUtils.isEmpty(dto.getString("subPost")) ? "" : dto.getString("subPost");
                    if (newPost.contains("66151") || newPost.contains("66152") || newPost.contains("6763") || newPost.contains("6552") || subPost.contains("6713") || subPost.contains("6764") || subPost.contains("6765")) {
                        JSONArray licenses = dto.getJSONArray("licenses");
                        if (!ObjectUtils.isEmpty(licenses)) {
                            List<String> permissionStatusList = new ArrayList<>();
                            for (Object object : licenses) {
                                JSONObject json = JSONObject.parseObject(JSONObject.toJSONString(object));
                                if (!json.containsKey("expiryDate")) {
                                    licensesStatus.append("/无有效期");
                                    continue;
                                }
                                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("超期");
                                    } else if (daysBetween <= 30) {
                                        permissionStatusList.add("临期");
                                    } else {
                                        permissionStatusList.add("正常");
                                    }
                                }
                            }
                            long cq = permissionStatusList.stream().filter(e -> e.equals("超期")).count();
                            long lq = permissionStatusList.stream().filter(e -> e.equals("临期")).count();
                            long zc = permissionStatusList.stream().filter(e -> e.equals("正常")).count();
                            long no = permissionStatusList.stream().filter(e -> e.equals("无有效期")).count();
                            if (cq > 0) {
                                licensesStatus.append("/资质超期");
                            }
                            if (lq > 0) {
                                licensesStatus.append("/资质临期");
                            }
                            if (zc > 0) {
                                licensesStatus.append("/资质正常");
                            }
                            if (no > 0) {
                                licensesStatus.append("/无有效期");
                            }
                        } else {
                            licensesStatus.append("无资质");
                        }
                    } else {
                        licensesStatus.append("无资质要求");
                    }
                }
                String licensesStatusStr = licensesStatus.toString();
                licensesStatusStr = licensesStatusStr.startsWith("/") ? licensesStatusStr.substring(1) : licensesStatusStr;
                licensesStatusStr = licensesStatusStr.endsWith("/") ? licensesStatusStr.substring(0, licensesStatusStr.length() - 1) : licensesStatusStr;
                dto.put("licensesStatus", 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<>();
        getCompanyOrPersonPermitStatusStatic(boolMust, staticMap, StatisticalAnalysisEnum.person.getKey());
        result.put("keyIndicator", staticMap);
        return result;
    }

    /**
     * 组装人员过滤条件
     */
    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";

                            ((JSONArray) v).forEach(item -> {
                                String nestedField = path + "." + k;
                                // 根据证书编号判断有无资质

                                if (k.equals("certNo")) {
                                    NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                            path,
                                            existsQuery(nestedField),
                                            ScoreMode.None
                                    );
                                    // 以下人员类型有资质要求
                                    // 人员类型(newPost)：检验人员：66151、检测人员：66152、作业人员：6552、检查人员：6763
                                    // 人员子类型(subPost)： 持证人员:6713、持证人员(P):6764、持证人员(R2):6765
                                    if (item.equals("1")) {
                                        boolMust.must(nestedQuery);
                                    } else if (item.equals("0")) {
                                        // 无资质
                                        BoolQueryBuilder queryBuilder = this.getNotLicencesBuilderWithPerson();
                                        boolMust.must(queryBuilder);
                                        boolMust.mustNot(nestedQuery);
                                    } else {
                                        // 无资质要求
                                        BoolQueryBuilder queryBuilder = this.getNotNeedLicencesBuilderWithPerson();
                                        boolMust.must(queryBuilder);
                                    }
                                } else if (k.equals("expiryDate")) {
                                    // 不需要资质的人员查询构造条件
                                    BoolQueryBuilder notNeedLicensesQueryBuilder = this.getNotLicencesBuilderWithPerson();
                                    boolMust.must(notNeedLicensesQueryBuilder);
                                    EnhancedDynamicQueryBuilder enhancedDynamicQueryBuilder = new EnhancedDynamicQueryBuilder();
                                    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);
                                        boolMust.must(enhancedDynamicQueryBuilder.build());
                                    } 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);
                                        boolMust.must(enhancedDynamicQueryBuilder.build());
                                    } 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);
                                        boolMust.must(enhancedDynamicQueryBuilder.build());
                                    } else if (item.equals("none")) {
                                        NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                                path,
                                                QueryBuilders.boolQuery().mustNot(existsQuery(nestedField)),
                                                ScoreMode.None
                                        );
                                        enhancedDynamicQueryBuilder.add(nestedQuery, or);
                                        boolMust.must(enhancedDynamicQueryBuilder.build());
                                    }
                                } else if (k.equals("certType") || k.equals("permissionLevel")) {
                                    NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                            path,
                                            QueryBuilders.boolQuery().must(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.should(nestedQuery);
                                }
                            });
                        } else if (k.equals("issueDate")) {
                            JSONArray issueDates = (JSONArray) v;
                            String startDate = DateUtils.convertDateToString(issueDates.getDate(0), DateUtils.DATE_PATTERN);
                            String endDate = DateUtils.convertDateToString(issueDates.getDate(1), DateUtils.DATE_PATTERN);
                            NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                    "licenses",
                                    QueryBuilders.rangeQuery("licenses." + k).gte(startDate).lte(endDate),
                                    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.matchQuery("postName", fuzzyValue));
                        queryBuilder.should(QueryBuilders.matchQuery("subPostName", fuzzyValue));
                        queryBuilder.should(QueryBuilders.wildcardQuery("unitName", "*" + fuzzyValue + "*"));
                        queryBuilder.should(QueryBuilders.wildcardQuery("equipCategoryName", "*" + fuzzyValue + "*"));
                        queryBuilder.should(QueryBuilders.wildcardQuery("superviseOrgName", "*" + 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);
        }
    }

    /**
     * 组装人员排序
     */
    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";
            }
            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");
        boolMust.must(QueryBuilders.prefixQuery("superviseOrgCode", orgCode));
        getCompanyBoolQueryBuilder(filter, boolMust);

        // 排序
        if (!ObjectUtils.isEmpty(filter.get("sort"))) {
            JSONObject sort = JSONObject.parseObject(JSONObject.toJSONString(filter.get("sort")));
            String field = sort.getString("field").equals("permissionStatus") ? "licenses.expiryDate" : 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");
                StringBuilder permissionStatus = new StringBuilder();
                if (dto.containsKey("licenses")) {
                    JSONArray licenses = dto.getJSONArray("licenses");
                    if (!ObjectUtils.isEmpty(licenses)) {
                        List<String> permissionStatusList = new ArrayList<>();
                        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("超期");
                                } else if (daysBetween <= 30) {
                                    permissionStatusList.add("临期");
                                } else {
                                    permissionStatusList.add("正常");
                                }
                            } else {
                                permissionStatusList.add("无有效期");
                            }
                        }
                        long cq = permissionStatusList.stream().filter(e -> e.equals("超期")).count();
                        long lq = permissionStatusList.stream().filter(e -> e.equals("临期")).count();
                        long zc = permissionStatusList.stream().filter(e -> e.equals("正常")).count();
                        long no = permissionStatusList.stream().filter(e -> e.equals("无有效期")).count();
                        if (cq > 0) {
                            permissionStatus.append("/许可超期");
                        }
                        if (lq > 0) {
                            permissionStatus.append("/许可临期");
                        }
                        if (zc > 0) {
                            permissionStatus.append("/许可正常");
                        }
                        if (no > 0) {
                            permissionStatus.append("/无有效期");
                        }
                    }
                } 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.append("/无有效期");
                }
                String permissionStatusStr = permissionStatus.toString();
                permissionStatusStr = permissionStatusStr.startsWith("/") ? permissionStatusStr.substring(1) : permissionStatusStr;
                permissionStatusStr = permissionStatusStr.endsWith("/") ? permissionStatusStr.substring(0, permissionStatusStr.length() - 1) : permissionStatusStr;
                dto.put("permissionStatus", permissionStatusStr);
                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<>();
        getCompanyOrPersonPermitStatusStatic(boolMust, staticMap, StatisticalAnalysisEnum.company.getKey());
        result.put("keyIndicator", staticMap);

        return result;
    }

    /**
     * 构造企业查询条件
     *
     * @param filter
     * @param boolMust
     */
    private void getCompanyBoolQueryBuilder(JSONObject filter, BoolQueryBuilder boolMust) {
        JSONObject filterParams;
        if (!ObjectUtils.isEmpty(filter.get("filterParams"))) {
            filterParams = JSONObject.parseObject(JSONObject.toJSONString(filter.get("filterParams")));
            String filterType = filter.getString("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("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(QueryBuilders.existsQuery(nestedField)),
                                                    ScoreMode.None
                                            );
                                            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);
            }
        }
    }

    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));
        JSONObject filterParams = new JSONObject();
        // 筛选
        if (!ObjectUtils.isEmpty(filter.get("filterParams"))) {
            filterParams = JSONObject.parseObject(JSONObject.toJSONString(filter.get("filterParams")));
            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";
            }
            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 = "无下次检验日期";
                if (dto.containsKey("NEXT_INSPECT_DATE")) {
                    String nextInspectDate = dto.getString("NEXT_INSPECT_DATE");
                    long daysBetween = ChronoUnit.DAYS.between(LocalDate.now(), LocalDate.parse(nextInspectDate, formatter));
                    if (daysBetween <= 0) {
                        inspectStatus = "超期";
                    } else if (daysBetween <= 30) {
                        inspectStatus = "临期";
                    } else {
                        inspectStatus = "正常";
                    }
                    dto.put("inspectStatus", inspectStatus);
                } else {
                    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);
        }


        Map<String, Object> sum = new HashMap<>();
        sum.put("name", "设备总数（台套）");
        sum.put("value", totle);
        statics.add(sum);

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

        if (ObjectUtils.isEmpty(filterParams) || !filterParams.containsKey("EQU_LIST")) {
            filterParams = new JSONObject();
            JSONArray jsonArray = new JSONArray();
            jsonArray.add("all");
            filterParams.put("EQU_LIST", jsonArray);
        }

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

        if (ObjectUtils.isEmpty(equList) || equList.contains("2000") || equList.contains("all")) {
            // 气瓶数量
            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 void getEquipmentBoolQueryBuilder(BoolQueryBuilder boolMust, JSONObject filterParams, String filterType) {
        //快捷筛选和自定义筛选解析筛选规则不一致
        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(QueryBuilders.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(QueryBuilders.existsQuery("USE_ORG_CODE"));
                                    } else {
                                        queryBuilder.should(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery("IS_INTO_MANAGEMENT")))
                                                .should(QueryBuilders.matchQuery("IS_INTO_MANAGEMENT", Boolean.FALSE))
                                                .should(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery("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 (k.equals("USE_DATE") || k.equals("issueDate")) {
                                    boolMust.filter(QueryBuilders.rangeQuery(field).gte(startDate).lt(endDate));
                                } else {
                                    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")) {
                                if (k.equals("EQU_LIST")) {
                                    field = "EQU_LIST_CODE";
                                } else if (k.equals("EQU_CATEGORY")) {
                                    field = "EQU_CATEGORY_CODE";
                                } 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(QueryBuilders.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
                                );
                                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", "*" + fuzzyValue + "*"));
                            queryBuilder.should(QueryBuilders.wildcardQuery("EQU_CATEGORY", "*" + fuzzyValue + "*"));
                            queryBuilder.should(QueryBuilders.wildcardQuery("EQU_DEFINE", "*" + 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", "*" + fuzzyValue + "*"));
                            queryBuilder.should(QueryBuilders.wildcardQuery("ORG_BRANCH_NAME", "*" + fuzzyValue + "*"));
                            queryBuilder.should(QueryBuilders.wildcardQuery("MAINTAIN_UNIT_NAME", "*" + 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");
            JSONArray equListCodes = new JSONArray();
            leftGroup.forEach(item -> {
                JSONObject left = JSONObject.parseObject(JSONObject.toJSONString(item));
                String leftField = left.getString("field");
                String leftValue = left.getString("value");
                if (!ObjectUtils.isEmpty(leftField) && leftField.equals("EQU_LIST_CODE") && !ObjectUtils.isEmpty(leftValue)) {
                    equListCodes.add(leftValue);
                }
            });
            rightGroup.forEach(item -> {
                JSONObject left = JSONObject.parseObject(JSONObject.toJSONString(item));
                String rightField = left.getString("field");
                String rightValue = left.getString("value");
                if (!ObjectUtils.isEmpty(rightField) && rightField.equals("EQU_LIST_CODE") && !ObjectUtils.isEmpty(rightValue)) {
                    equListCodes.add(rightValue);
                }
            });
            filterParams.put("EQU_LIST", equListCodes);
            Boolean isOrGroup = or.equals(filterParams.getString("groupAndOr")) ? Boolean.TRUE : Boolean.FALSE;
            handleAdvancedFilter(boolMust, leftGroup, rightGroup, isOrGroup);
        }
    }

    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).lte(LocalDate.now().plusDays(30).format(formatter)).gte(LocalDate.now().format(formatter))),
                ScoreMode.None
        );
        nearBoolQuery.must(nearNestedQuery);
        Long nearCount = getStatisticCount(nearBoolQuery, StatisticalAnalysisEnum.company.getKey());

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


    private 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) {
        SearchRequest request = new SearchRequest();
        request.indices(StatisticalAnalysisEnum.equip.getKey());
        BigDecimal pipeLong;
        NestedQueryBuilder nestedQueryBuilder = QueryBuilders.nestedQuery("techParams",
                QueryBuilders.boolQuery().must(QueryBuilders.termsQuery("techParams.paramKey", "pipeLength")),
                ScoreMode.None);
        boolMust.must(nestedQueryBuilder);
        builder.query(boolMust).aggregation(AggregationBuilders.nested("longPipe", "techParams").subAggregation(
                        AggregationBuilders.sum("pipeLength").field("techParams.doubleValue")
                )
        );
        request.source(builder);
        try {
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            ParsedSum sumAgg = ((ParsedNested) response.getAggregations()
                    .get("longPipe"))
                    .getAggregations()
                    .get("pipeLength");
            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 && !jsonArray.get(0).equals("all");
        } 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);
        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).filter(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":
                JSONArray inValues = (JSONArray) value;
                NestedQueryBuilder inQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().must(termsQueryBuilder).must(QueryBuilders.termsQuery(path + tail, inValues)),
                        ScoreMode.None
                );
                if (isCustom) {
                    builder.add(inQuery, andOr);
                } else {
                    boolMust.must(inQuery);
                }
                break;
            case "notIn":
                JSONArray notInValues = (JSONArray) value;
                NestedQueryBuilder notInQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().must(termsQueryBuilder).must(QueryBuilders.termsQuery(path + tail, notInValues)),
                        ScoreMode.None
                );
                if (isCustom) {
                    builder.add(QueryBuilders.boolQuery().mustNot(notInQuery), andOr);
                } else {
                    boolMust.mustNot(notInQuery);
                }
                break;
        }
    }

    // 处理高级筛选条件
    private void handleAdvancedFilter(BoolQueryBuilder boolMust, JSONArray leftGroup, JSONArray rightGroup, Boolean isOrGroup) {
        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);
            }
            // 非计数参数处理
            groupHandler(leftGroupList, leftBuilder);
            // 添加左侧筛选条件到最终筛选条件中
            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);
            }
            // 非计数参数处理
            groupHandler(rightGroupList, rightBuilder);

            // 添加右侧筛选条件到最终筛选条件中
            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");
        String fieldType = jsonObject.getString("fieldType");
        String itemCondition = paramRange.getString("itemCondition");
        Object 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) {
        for (Object object : group) {
            JSONObject itemObj = JSONObject.parseObject(JSONObject.toJSONString(object));
            String field = itemObj.getString("field");
            String itemCondition = itemObj.getString("itemCondition");
            Object value = itemObj.get("value");
            String andOr = itemObj.getString("andOr");
            // 组装查询条件
            getItemQuery(field, itemCondition, value, andOr, builder);
        }
    }

    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")) {
                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) {
        // 如果包含需要特殊处理的字段，则调用对应的处理方法，否则调用通用处理方法
        if (equipHandleOtherFields.contains(field) || companyHandleOtherFields.contains(field) || personHandleOtherFields.contains(field)) {
            handleOtherField(field, itemCondition, value, isOr, builder);
        } else {
            field = field.equals("nextInspectDate") ? "NEXT_INSPECT_DATE" : field;
            switch (itemCondition) {
                case "eq":
                    builder.add(QueryBuilders.termQuery(field, value), isOr);
                    break;
                case "neq":
                    builder.add(QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery(field, value)), isOr);
                    break;
                case "like":
                    builder.add(QueryBuilders.boolQuery().must(QueryBuilders.wildcardQuery(field, "*" + value + "*")), isOr);
                    break;
                case "notLike":
                    builder.add(QueryBuilders.boolQuery().mustNot(QueryBuilders.wildcardQuery(field, "*" + value + "*")), isOr);
                    break;
                case "gt":
                    builder.add(QueryBuilders.rangeQuery(field).gt(value.toString()), isOr);
                    break;
                case "gte":
                    builder.add(QueryBuilders.rangeQuery(field).gte(value.toString()), isOr);
                    break;
                case "lt":
                    builder.add(QueryBuilders.rangeQuery(field).lt(value.toString()), isOr);
                    break;
                case "lte":
                    builder.add(QueryBuilders.rangeQuery(field).lte(value.toString()), isOr);
                    break;
                case "between":
                    JSONArray btValues = (JSONArray) value;
                    builder.add(QueryBuilders.rangeQuery(field).gte(Double.parseDouble(btValues.get(0).toString())).lte(Double.parseDouble(btValues.get(1).toString())), isOr);
                    break;
                case "in":
                    builder.add(QueryBuilders.termsQuery(field, value), isOr);
                    break;
                case "notIn":
                    builder.add(QueryBuilders.boolQuery().mustNot(QueryBuilders.termsQuery(field, value)), isOr);
                    break;
            }
        }
    }

    // 特殊处理字段
    private void handleOtherField(String field, String itemCondition, Object value, String isOr, EnhancedDynamicQueryBuilder builder) {
        if (equipHandleOtherFields.contains(field)) {
            equipFieldHandle(field, itemCondition, value, isOr, builder);
        } else if (companyHandleOtherFields.contains(field)) {
            companyFieldHandle(field, itemCondition, value, isOr, builder);
        } else if (personHandleOtherFields.contains(field)) {
            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 = this.getNotLicencesBuilderWithPerson();
                // 无资质要求查询
                BoolQueryBuilder noCertRequestQuery = this.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")) {
                if (value.equals("overdue")) {
                    if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                        NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                path,
                                QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).lt(LocalDate.now().format(formatter))),
                                ScoreMode.None
                        );
                        builder.add(nestedQuery, isOr);
                    } else {
                        NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                path,
                                QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).gte(LocalDate.now().format(formatter))),
                                ScoreMode.None
                        );
                        builder.add(nestedQuery, isOr);
                    }
                } else if (value.equals("near")) {
                    if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                        NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                path,
                                QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).lte(LocalDate.now().plusDays(30).format(formatter)).gte(LocalDate.now().format(formatter))),
                                ScoreMode.None
                        );
                        builder.add(nestedQuery, isOr);
                    } else {
                        NestedQueryBuilder overdueNestedQuery = QueryBuilders.nestedQuery(
                                path,
                                QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).lt(LocalDate.now().format(formatter))),
                                ScoreMode.None
                        );
                        NestedQueryBuilder normalNestedQuery = QueryBuilders.nestedQuery(
                                path,
                                QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).gt(LocalDate.now().plusDays(30).format(formatter))),
                                ScoreMode.None
                        );
                        builder.add(overdueNestedQuery, or);
                        builder.add(normalNestedQuery, or);
                    }
                } else if (value.equals("normal")) {
                    if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                        NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                path,
                                QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).gt(LocalDate.now().plusDays(30).format(formatter))),
                                ScoreMode.None
                        );
                        builder.add(nestedQuery, isOr);
                    } else {
                        NestedQueryBuilder elseNestedQuery = QueryBuilders.nestedQuery(
                                path,
                                QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).lte(LocalDate.now().plusDays(30).format(formatter))),
                                ScoreMode.None
                        );
                        NestedQueryBuilder noLicensesNestedQuery = QueryBuilders.nestedQuery(
                                path,
                                existsQuery(nestedField),
                                ScoreMode.None
                        );
                        builder.add(elseNestedQuery, or);
                    }
                }
            } 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);
                }
            }
        }
    }

    /**
     * 需要资质的人员查询构造条件
     * 无资质:需要资质但是没有填写
     *
     * @return
     */
    private BoolQueryBuilder getNotLicencesBuilderWithPerson() {
        return QueryBuilders.boolQuery()
                .should(QueryBuilders.wildcardQuery("newPost", "*66151*"))
                .should(QueryBuilders.wildcardQuery("newPost", "*66152*"))
                .should(QueryBuilders.boolQuery().must(QueryBuilders.wildcardQuery("newPost", "*6552*"))
                        .must(QueryBuilders.wildcardQuery("subPost", "*6713*")))
                .should(QueryBuilders.boolQuery().must(QueryBuilders.wildcardQuery("newPost", "*6763*"))
                        .should(QueryBuilders.wildcardQuery("subPost", "*6764*"))
                        .should(QueryBuilders.wildcardQuery("subPost", "*6765*"))
                        .minimumShouldMatch(1)
                )
                .minimumShouldMatch(1);
    }

    /**
     * 无资质要求的人员查询构造条件
     * 无资质要求：不需要资质
     *
     * @return
     */
    private BoolQueryBuilder getNotNeedLicencesBuilderWithPerson() {
        return QueryBuilders.boolQuery()
                .mustNot(QueryBuilders.wildcardQuery("newPost", "*66151*"))
                .mustNot(QueryBuilders.wildcardQuery("newPost", "*66152*"))
                .mustNot(QueryBuilders.boolQuery().must(QueryBuilders.wildcardQuery("newPost", "*6552*"))
                        .must(QueryBuilders.wildcardQuery("subPost", "*6713*")))
                .mustNot(QueryBuilders.boolQuery().must(QueryBuilders.wildcardQuery("newPost", "*6763*"))
                        .should(QueryBuilders.wildcardQuery("subPost", "*6764*"))
                        .should(QueryBuilders.wildcardQuery("subPost", "*6765*"))
                        .minimumShouldMatch(1)
                );
    }

    private void companyFieldHandle(String field, String itemCondition, Object value, String isOr, EnhancedDynamicQueryBuilder builder) {
        if (field.equals("itemCode") || field.equals("subItemCode") || field.equals("permitStatus")) {
            String path = "licenses";
            String nestedField = path + "." + (field.equals("permitStatus") ? "expiryDate" : field + ".keyword");
            if (field.equals("permitStatus")) {
                // 无许可到期日期
                NestedQueryBuilder noneQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery(nestedField)),
                        ScoreMode.None
                );
                // 有效许可到期日期
                NestedQueryBuilder existsQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().must(QueryBuilders.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);
                        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);
                        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);
                        builder.add(builders.build(), isOr);
                    }
                } else if (value.equals("none")) {
                    if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                        builder.add(QueryBuilders.boolQuery().must(existsQuery), or);
                    } else {
                        builder.add(QueryBuilders.boolQuery().must(noneQuery), or);
                    }
                }
            } 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")) {
            if (value.equals("overdue")) {
                // 超期：小于当前日期
                if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                    builder.add(QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(field).lt(LocalDate.now().format(formatter))), isOr);
                } else {
                    builder.add(QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(field).gt(LocalDate.now().format(formatter))), isOr);
                }
            } else if (value.equals("near")) {
                // 临期：小于等于当前日期加上30天
                if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                    builder.add(QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(field).gte(LocalDate.now().format(formatter)).lte(LocalDate.now().plusDays(30).format(formatter))), isOr);
                } else {
                    builder.add(QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(field).lt(LocalDate.now().format(formatter))), or);
                    builder.add(QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(field).gt(LocalDate.now().plusDays(30).format(formatter))), or);
                }
            } else {
                // 正常：大于当前日期加上30天
                if (itemCondition.equals("eq") || itemCondition.equals("in")) {
                    builder.add(QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(field).gt(LocalDate.now().plusDays(30).format(formatter))), isOr);
                } else {
                    builder.add(QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(field).lt(LocalDate.now().plusDays(30).format(formatter))), 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));
            }
            NestedQueryBuilder fieldQuery = QueryBuilders.nestedQuery(
                    path,
                    queryBuilder,
                    ScoreMode.None
            );
            builder.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
            );
            builder.add(dateQuery, 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"));
            BoolQueryBuilder noRegisterQuery = QueryBuilders.boolQuery().should(QueryBuilders.boolQuery().mustNot(existsQuery("IS_INTO_MANAGEMENT")))
                    .should(QueryBuilders.matchQuery("IS_INTO_MANAGEMENT", Boolean.FALSE))
                    .should(QueryBuilders.boolQuery().mustNot(existsQuery("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);
                }
            }
        }
    }


    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", "许可正常");
            } else if (1 == i) {
                object.put("key", "near");
                object.put("value", "near");
                object.put("label", "许可临期");
            } else if (2 == i) {
                object.put("key", "overdue");
                object.put("value", "overdue");
                object.put("label", "许可超期");
            } else {
                object.put("key", "none");
                object.put("value", "none");
                object.put("label", "无有效期");
            }
            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 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 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 exportDataAsyncBatchSearch(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;
    }

    private static MultipartFile getEquipMultipartFile(JSONArray records, String fileName, String sheetName) {
        MultipartFile templateExcelFile;
        List<EquipInfoVo> exportData = new ArrayList<>();
        records.forEach(obj -> {
            JSONObject equip = JSONObject.parseObject(JSON.toJSONString(obj));
            EquipInfoVo equipInfoVo = new EquipInfoVo();
            BeanUtil.copyProperties(equip, equipInfoVo, CopyOptions.create().setIgnoreNullValue(true));
            // 最新一条检验信息
            if (!equip.getJSONArray("inspections").isEmpty()) {
                JSONObject inspection = equip.getJSONArray("inspections").getJSONObject(0);
                BeanUtil.copyProperties(inspection, equipInfoVo, CopyOptions.create().setIgnoreNullValue(true));
            }
            // 最新一条维保信息
            if (!equip.getJSONArray("maintenances").isEmpty()) {
                JSONObject maintenances = equip.getJSONArray("maintenances").getJSONObject(0);
                BeanUtil.copyProperties(maintenances, equipInfoVo, CopyOptions.create().setIgnoreNullValue(true));
            }
            // 技术参数
            if (!equip.getJSONArray("techParams").isEmpty()) {
                JSONObject paramsJson = new JSONObject();
                equip.getJSONArray("techParams").forEach(techParam -> {
                    ESEquipmentInfo.TechParam techParamItem = JSONObject.parseObject(JSON.toJSONString(techParam), ESEquipmentInfo.TechParam.class);
                    Optional.ofNullable(techParamItem.getParamKey()).ifPresent(key -> Stream.of(
                                    Optional.ofNullable(techParamItem.getBoolValue()),
                                    Optional.ofNullable(techParamItem.getDateValue()),
                                    Optional.ofNullable(techParamItem.getLongValue()),
                                    Optional.ofNullable(techParamItem.getStrValue()),
                                    Optional.ofNullable(techParamItem.getDoubleValue())
                            )
                            .filter(Optional::isPresent)
                            .findFirst()
                            .ifPresent(value -> paramsJson.put(key, value.get())));
                });
                BeanUtil.copyProperties(paramsJson, equipInfoVo, CopyOptions.create().setIgnoreNullValue(true));
            }
            exportData.add(equipInfoVo);
        });
        templateExcelFile = ExcelUtil.createTemplateExcelFile(fileName, sheetName, exportData, EquipInfoVo.class, null, false);
        return templateExcelFile;
    }

    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 (!licenses.isEmpty()) {
                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 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 = jsonObject.getString("EQU_CATEGORY_CODE");
        String equDefine = jsonObject.getString("EQU_DEFINE_CODE");
        String vehicleCylinder = "1".equals(jsonObject.getString("WHETHER_VEHICLE_CYLINDER")) ? "vehicleCylinder" : null;
        if ("".equals(equList) || null == equList) {
            throw new BaseException("需要先选择设备种类，才能选择技术参数", "200", "需要先选择设备种类，才能选择技术参数");
        }
        List<TechParamItem> paramMetaList = TechParamUtil.getParamMetaList(equList, equCategory, equDefine, vehicleCylinder);
        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("fieldType", paramMetaList.get(i).getParamType());
            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", "资质正常");
            } else if (1 == i) {
                object.put("key", "near");
                object.put("value", "near");
                object.put("label", "资质临期");
            } else if (2 == i) {
                object.put("key", "overdue");
                object.put("value", "overdue");
                object.put("label", "资质超期");
            } else {
                object.put("key", "none");
                object.put("value", "none");
                object.put("label", "无有效期");
            }
            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)) {
            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(QueryBuilders.existsQuery("ORG_BRANCH_CODE")));
                boolMust.must(dynamicQueryBuilder.build());
            } else {
                boolMust.must(QueryBuilders.prefixQuery("ORG_BRANCH_CODE", orgCode));
            }
            data = queryDpEquipStatistics(filter, request, builder, boolMust, tabTotalMap);
        } else if (StatisticalAnalysisEnum.company.getCode().equals(businessType)) {
            boolMust.must(QueryBuilders.prefixQuery("superviseOrgCode", orgCode));
            data = queryDpCompanyStatistics(filter, request, builder, boolMust, tabTotalMap);
        } else {
            boolMust.must(QueryBuilders.prefixQuery("superviseOrgCode", orgCode));
            data = queryDpPersonStatistics(filter, request, builder, boolMust, tabTotalMap);
        }

        getTypeCount(businessType, tabTotalMap, orgCode, data);

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

    private void getTypeCount(String businessType, Map<String, Object> tabTotalMap, String orgCode, List<Map<String, Object>> data) {
        BoolQueryBuilder equipBoolMust = QueryBuilders.boolQuery();
        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(QueryBuilders.existsQuery("ORG_BRANCH_CODE")));
            equipBoolMust.must(dynamicQueryBuilder.build());
        } else {
            equipBoolMust.must(QueryBuilders.prefixQuery("ORG_BRANCH_CODE", orgCode));
        }
        equipBoolMust.mustNot(QueryBuilders.termsQuery("STATUS", Arrays.asList("草稿", "已拒领", "待认领")));
        BoolQueryBuilder companyBoolMust = QueryBuilders.boolQuery();
        companyBoolMust.must(QueryBuilders.prefixQuery("superviseOrgCode", orgCode));
        BoolQueryBuilder personBoolMust = QueryBuilders.boolQuery();
        personBoolMust.must(QueryBuilders.prefixQuery("superviseOrgCode", orgCode));
        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);
            tabTotalMap.put(StatisticalAnalysisEnum.company.getCode(), companyCount);
            tabTotalMap.put(StatisticalAnalysisEnum.person.getCode(), personCount);
        } else if (businessType.equals(StatisticalAnalysisEnum.company.getCode())) {
            // 获取设备总数
            Long equipCount = getStatisticCount(equipBoolMust, equipIndex);
            // 获取人员总数
            Long personCount = getStatisticCount(personBoolMust, personIndex);
            tabTotalMap.put(StatisticalAnalysisEnum.equip.getCode(), equipCount);
            tabTotalMap.put(StatisticalAnalysisEnum.person.getCode(), personCount);
        } else {
            // 获取设备总数
            Long equipCount = getStatisticCount(equipBoolMust, equipIndex);
            // 获取企业总数
            Long companyCount = getStatisticCount(companyBoolMust, companyIndex);
            tabTotalMap.put(StatisticalAnalysisEnum.equip.getCode(), equipCount);
            tabTotalMap.put(StatisticalAnalysisEnum.company.getCode(), companyCount);
        }
    }


    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";
        // 组装人员过滤条件
        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);
        // 一级统计
        if (!is2LeveFlag) {
            return getTotalAggMapsByUnitType(request, builder, boolMust, tabTotalMap, StatisticalAnalysisEnum.person);
        } else {
            // 二级统计
            Map<String, Object> result = new HashMap<>();
            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>> getTotalAggMapsByUnitType(SearchRequest request, SearchSourceBuilder builder, BoolQueryBuilder boolMust, Map<String, Object> tabTotalMap, StatisticalAnalysisEnum statisticalAnalysisEnum) {
        // 计算总数
        long total = this.queryDpStatisticsTotalByIndex(boolMust, statisticalAnalysisEnum.getKey());
        // 聚合查询
        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);
        }
        // 汇总总数
        tabTotalMap.put(statisticalAnalysisEnum.getCode(), total);
        return Collections.singletonList(result);
    }

    private 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) {
        request.indices(StatisticalAnalysisEnum.company.getKey());
        JSONObject filterParams = JSONObject.parseObject(JSONObject.toJSONString(filter.get("filterParams")));
        String unitCategory = filterParams.getString("unitCategory");
        String unitType = filterParams.getJSONArray("unitType").getString(0);
        // 构造企业查询条件
        filter.put("filterType", "advanced");
        getCompanyBoolQueryBuilder(filter, boolMust);

        boolean is2LeveFlag = Optional.of(filter)
                .map(obj -> obj.getJSONObject("filterParams"))
                .map(filterParamsObj -> filterParamsObj.getJSONArray("unitType"))
                .map(unitTypeObj -> !unitTypeObj.isEmpty())
                .orElse(false);
        // 一级统计
        if (!is2LeveFlag) {
            return getTotalAggMapsByUnitType(request, builder, boolMust, tabTotalMap, StatisticalAnalysisEnum.company);
        } else {
            // 二级统计
            Map<String, Object> result = new HashMap<>();
            // 使用单位：使用单位，个人主体 返回管控级别和所属行业
            boolMust.must(QueryBuilders.matchQuery("unitType", unitType));
            if (unitCategory.equals(UnitCategoryEnum.use.getCode())) {
                JSONObject regulatoryLabels = this.getItemGroupStatisticsByItemName(boolMust, StatisticalAnalysisEnum.company.getKey(), "regulatoryLabelsAggName", "regulatoryLabels", this::buildRegulatoryLabelsGroupResult);
                JSONObject industrySupervisor = this.getItemGroupStatisticsByItemName(boolMust, StatisticalAnalysisEnum.company.getKey(), "industrySupervisorAggName", "industrySupervisor", this::buildIndustrySupervisorGroupResult);
                result.put("tabTotalMap", new JSONObject()
                        .fluentPut("regulatoryLabelsTotal", this.sumWithJSONObjectValues(regulatoryLabels))
                        .fluentPut("industrySupervisorTotal", this.sumWithJSONObjectValues(industrySupervisor)));
                result.put("datas", new JSONObject()
                        .fluentPut("regulatoryLabels", regulatoryLabels)
                        .fluentPut("industrySupervisor", industrySupervisor));
            } else if (unitCategory.equals(UnitCategoryEnum.license.getCode())) {// 许可单位：设计单位、制造单位、充装单位、检验机构、检查机构、安装改造维修单位
                JSONObject permitStatus = getPermitStatusGroupStatistics(boolMust);
                result.put("tabTotalMap", new JSONObject()
                        .fluentPut("permitStatusTotal", this.sumWithJSONObjectValues(permitStatus)));
                result.put("datas", new JSONObject()
                        .fluentPut("permitStatus", permitStatus));
            }

            return Collections.singletonList(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");
            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, Long> staticCountByGroup = new HashMap<>();
        getStatisticCountByGroup(request, builder, boolMust, groupField, staticCountByGroup);

        Long equipCount = staticCountByGroup.values().stream().reduce(0L, Long::sum);
        tabTotalMap.put(StatisticalAnalysisEnum.equip.getCode(), equipCount);

        // 组装数据
        List<Map<String, Object>> dataMapList = new ArrayList<>();
        for (Map<String, Object> categoryMap : staticCountByGroupMap) {
            String code = categoryMap.get("value").toString();
            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", ""));
            map.put("value", staticCountByGroup.containsKey(code) ? staticCountByGroup.get(code) : 0L);
            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", "台套");
            // 统计该分类下的数据完整性的分组数量 DATA_QUALITY_SCORE
            BoolQueryBuilder scoreQuery = QueryBuilderUtils.copyBoolQuery(boolMust);
            scoreQuery.must(QueryBuilders.termQuery(groupField, code));
            SearchSourceBuilder scoreBuilder = new SearchSourceBuilder();
            Map<String, Long> scoreCountByGroup = new HashMap<>();
            getStatisticCountByGroup(request, scoreBuilder, scoreQuery, "DATA_QUALITY_SCORE", scoreCountByGroup);
            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 (!ObjectUtils.isEmpty(staticCountByGroup)) {
            statisticOtherCount(request, dataMapList, staticCountByGroup, boolMust, groupField);
        }

        if (!ObjectUtils.isEmpty(equipCode)) {
            tabTotalMap.put(equipCode, dataMapList.stream().mapToLong(map -> (Long) map.get("value")).sum());
        }
        return dataMapList;
    }

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

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

            // 统计该分类下红黄绿码分别的分组数量 NEXT_INSPECT_DATE
            Map<String, Long> nextInspectCountByGroup = new HashMap<>();
            BoolQueryBuilder nextInspectQuery = QueryBuilderUtils.copyBoolQuery(boolMust);
            if (key.equals("NA")) {
                nextInspectQuery.mustNot(QueryBuilders.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", otherCount);
        map.put("img", dpEquipPhotoPrefix + type + dpEquipPhotoSuffix);
        map.put("measurementUnit", "台套");
        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(QueryBuilders.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, Long> staticCountByGroup) {
        builder.query(boolMust);
        if (groupField.equals("DATA_QUALITY_SCORE")) {
            builder.aggregation(AggregationBuilders.terms("groupCount").field(groupField).missing(99).size(50));
        } else {
            builder.aggregation(AggregationBuilders.terms("groupCount").field(groupField).missing("NA").size(50));
        }
        request.source(builder);
        try {
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            Terms terms = response.getAggregations().get("groupCount");
            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";
        // 组装人员过滤条件
        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 = this.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().must(QueryBuilders.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 = this.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();
        // copy一份，避免后续两部分逻辑不一致
        BoolQueryBuilder boolQueryCopy = QueryBuilderUtils.copyBoolQuery(boolQuery);

        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);
//            this.buildGroupResult(itemGroupAgg, result);
            task.accept(itemGroupAgg, result);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }

        CountRequest countRequest = new CountRequest();
        countRequest.indices(indexName);
        countRequest.query(boolQueryCopy);
        CountResponse countResponse;
        try {
            countResponse = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT);
        } catch (Exception exception) {
            throw new RuntimeException(exception);
        }
        result.put("total", ObjectUtils.isEmpty(countResponse) ? 0L : countResponse.getCount());
        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"));
        // 枚举遍历 + 动态匹配
        for (Terms.Bucket bucket : groupAgg.getBuckets()) {
            String bucketKey = bucket.getKeyAsString();
            for (Object obj : regulatoryLabels) {
                JSONObject jsonObject = (JSONObject) obj;
                result.put(jsonObject.getString("value"), 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"));
        // 枚举遍历 + 动态匹配
        for (Terms.Bucket bucket : groupAgg.getBuckets()) {
            String bucketKey = bucket.getKeyAsString();
            for (Object obj : industrySupervisor) {
                JSONObject jsonObject = (JSONObject) obj;
                result.put(jsonObject.getString("value"), 0);
                if (jsonObject.getString("label").equals(bucketKey)) {
                    result.put(jsonObject.getString("value"), bucket.getDocCount());
                    break;
                }
            }
            if (bucketKey.equals("其他")) {
                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().must(QueryBuilders.existsQuery(nestedField)),
                ScoreMode.None
        );
        nothingBoolQuery.must(nothingNestedQuery);
        Long nothingCount = getStatisticCount(nothingBoolQuery, StatisticalAnalysisEnum.company.getKey());
        result.put("wyxq", nothingCount);

        return result;
    }
}