package com.njcn.gather.result.service.impl;

import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.njcn.common.pojo.enums.common.DataStateEnum;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.utils.PubUtils;
import com.njcn.gather.detection.handler.SocketContrastResponseService;
import com.njcn.gather.detection.pojo.enums.DetectionCodeEnum;
import com.njcn.gather.detection.pojo.enums.ResultEnum;
import com.njcn.gather.detection.pojo.enums.SourceOperateCodeEnum;
import com.njcn.gather.detection.pojo.param.PreDetectionParam;
import com.njcn.gather.detection.pojo.po.AdPair;
import com.njcn.gather.detection.pojo.po.DevData;
import com.njcn.gather.detection.pojo.vo.AlignDataVO;
import com.njcn.gather.detection.pojo.vo.DetectionData;
import com.njcn.gather.detection.service.IAdPariService;
import com.njcn.gather.detection.service.impl.DetectionServiceImpl;
import com.njcn.gather.detection.util.socket.CnSocketUtil;
import com.njcn.gather.detection.util.socket.FormalTestManager;
import com.njcn.gather.device.pojo.enums.CommonEnum;
import com.njcn.gather.device.pojo.enums.PatternEnum;
import com.njcn.gather.device.pojo.po.PqDev;
import com.njcn.gather.device.pojo.po.PqStandardDev;
import com.njcn.gather.device.pojo.vo.PqDevVO;
import com.njcn.gather.device.service.IPqDevService;
import com.njcn.gather.device.service.IPqDevSubService;
import com.njcn.gather.device.service.IPqStandardDevService;
import com.njcn.gather.err.service.IPqErrSysService;
import com.njcn.gather.monitor.pojo.po.PqMonitor;
import com.njcn.gather.monitor.service.IPqMonitorService;
import com.njcn.gather.plan.pojo.enums.DataSourceEnum;
import com.njcn.gather.plan.pojo.po.AdPlan;
import com.njcn.gather.plan.pojo.po.AdPlanTestConfig;
import com.njcn.gather.plan.service.IAdPlanService;
import com.njcn.gather.plan.service.IAdPlanTestConfigService;
import com.njcn.gather.pojo.enums.DetectionResponseEnum;
import com.njcn.gather.report.pojo.DevReportParam;
import com.njcn.gather.report.pojo.constant.PowerConstant;
import com.njcn.gather.report.pojo.enums.AffectEnum;
import com.njcn.gather.report.pojo.enums.ItemReportKeyEnum;
import com.njcn.gather.report.pojo.enums.PowerIndexEnum;
import com.njcn.gather.report.pojo.result.ContrastTestResult;
import com.njcn.gather.report.pojo.result.SingleTestResult;
import com.njcn.gather.result.pojo.enums.ResultUnitEnum;
import com.njcn.gather.result.pojo.param.DataCheckRequest;
import com.njcn.gather.result.pojo.param.ResultParam;
import com.njcn.gather.result.pojo.vo.*;
import com.njcn.gather.result.service.DataCheckAsyncNotifier;
import com.njcn.gather.result.service.IResultService;
import com.njcn.gather.result.util.AngleResultAssembler;
import com.njcn.gather.result.util.PowerResultAssembler;
import com.njcn.gather.result.util.UnbalanceResultAssembler;
import com.njcn.gather.script.mapper.PqScriptMapper;
import com.njcn.gather.script.pojo.param.PqScriptCheckDataParam;
import com.njcn.gather.script.pojo.param.PqScriptIssueParam;
import com.njcn.gather.script.pojo.po.PqScriptCheckData;
import com.njcn.gather.script.pojo.po.PqScriptDtls;
import com.njcn.gather.script.pojo.po.SourceIssue;
import com.njcn.gather.script.pojo.vo.PqScriptDtlDataVO;
import com.njcn.gather.script.service.IPqScriptCheckDataService;
import com.njcn.gather.script.service.IPqScriptDtlsService;
import com.njcn.gather.script.util.ScriptDtlsDesc;
import com.njcn.gather.storage.mapper.TableGenMapper;
import com.njcn.gather.storage.pojo.param.SingleNonHarmParam;
import com.njcn.gather.storage.pojo.param.StorageParam;
import com.njcn.gather.storage.pojo.po.*;
import com.njcn.gather.storage.pojo.vo.RawDataVO;
import com.njcn.gather.storage.pojo.vo.RawResultDataVO;
import com.njcn.gather.storage.service.ContrastHarmonicService;
import com.njcn.gather.storage.service.ContrastNonHarmonicService;
import com.njcn.gather.storage.service.SimAndDigHarmonicService;
import com.njcn.gather.storage.service.SimAndDigNonHarmonicService;
import com.njcn.gather.system.dictionary.pojo.enums.DictDataEnum;
import com.njcn.gather.system.dictionary.pojo.po.DictData;
import com.njcn.gather.system.dictionary.pojo.po.DictTree;
import com.njcn.gather.system.dictionary.service.IDictDataService;
import com.njcn.gather.system.dictionary.service.IDictTreeService;
import com.njcn.gather.util.StorageUtil;
import com.njcn.http.util.RestTemplateUtil;
import com.njcn.web.utils.ExcelUtil;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.njcn.gather.plan.pojo.enums.DataSourceEnum.*;

/**
 * @author caozehui
 * @data 2024-12-30
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ResultServiceImpl implements IResultService {

    private final IAdPlanService adPlanService;
    private final IAdPlanTestConfigService adPlanTestConfigService;
    private final IPqDevService pqDevService;
    private final IPqStandardDevService pqStandardDevService;
    private final SimAndDigNonHarmonicService simAndDigNonHarmonicService;
    private final SimAndDigHarmonicService simAndDigHarmonicService;
    private final ContrastHarmonicService contrastHarmonicService;
    private final ContrastNonHarmonicService contrastNonHarmonicService;
    private final IPqScriptDtlsService pqScriptDtlsService;
    private final PqScriptMapper scriptMapper;
    private final IDictTreeService dictTreeService;
    private final IPqScriptCheckDataService pqScriptCheckDataService;
    private final TableGenMapper tableGenMapper;
    private final DetectionServiceImpl detectionServiceImpl;
    private final IDictDataService dictDataService;
    private final IPqScriptCheckDataService iPqScriptCheckDataService;
    private final IPqDevService iPqDevService;
    private final IAdPariService adPairService;
    private final IPqMonitorService pqMonitorService;
    private final IPqErrSysService pqErrSysService;
    private final IPqStandardDevService standardDevService;
    private final IPqDevSubService pqDevSubService;
    private final DataCheckAsyncNotifier dataCheckAsyncNotifier;
    private final RestTemplateUtil restTemplateUtil;

    @org.springframework.beans.factory.annotation.Value("${dataCheck.url}")
    private String url;
    private static final DateTimeFormatter CHECKSQUARE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private final Map<String, NotifyState> notifyStates = new ConcurrentHashMap<>();

    /**
     * 谐波类code，取树形字典表中的code
     */
    private final List<String> HARMONIC_TYPE_CODE = Arrays.asList("HV", "HI", "HP", "HSV", "HSI");


    @Override
    public void tryNotifyThirdPartyAfterFormalTest(PreDetectionParam param) {
        if (param == null || !SourceOperateCodeEnum.ALL_TEST.getValue().equals(FormalTestManager.reCheckType)) {
            return;
        }
        if (ObjectUtil.isNull(FormalTestManager.checkStartTime)
                || StrUtil.isBlank(param.getPlanId())
                || CollUtil.isEmpty(param.getDevIds())
                || CollUtil.isEmpty(FormalTestManager.monitorIdListComm)) {
            return;
        }

        LocalDateTime batchEndTime = pqDevSubService.resolveBatchMaxCheckEndTime(param.getDevIds());
        if (ObjectUtil.isNull(batchEndTime)) {
            log.warn("checksquare notify skipped, batch end time is empty, planId={}, devIds={}", param.getPlanId(), param.getDevIds());
            return;
        }

        List<String> sortedDevIds = param.getDevIds().stream().sorted().collect(Collectors.toList());
        String notifyKey = param.getPlanId() + "|" + String.join(",", sortedDevIds) + "|"
                + CHECKSQUARE_TIME_FORMATTER.format(FormalTestManager.checkStartTime) + "|" + FormalTestManager.reCheckType;
        if (notifyStates.get(notifyKey) != null) {
            return;
        }
        if (notifyStates.putIfAbsent(notifyKey, NotifyState.running()) != null) {
            return;
        }

        DataCheckNotifyContext context = DataCheckNotifyContext.builder()
                .notifyKey(notifyKey)
                .planId(param.getPlanId())
                .sortedDevIds(sortedDevIds)
                .lineIds(new ArrayList<>(FormalTestManager.monitorIdListComm))
                .timeStart(FormalTestManager.checkStartTime)
                .timeEnd(batchEndTime)
                .reCheckType(FormalTestManager.reCheckType)
                .build();
        dataCheckAsyncNotifier.notifyAsync(context, notifyStates);
    }

    @Override
    public DataCheckResultVO createChecksquareTaskByDevId(String devId) {
        if (StrUtil.isBlank(devId)) {
            throw new BusinessException(CommonResponseEnum.FAIL, "设备id不能为空");
        }

        List<PqMonitor> monitorList = pqMonitorService.listPqMonitorByDevIds(Collections.singletonList(devId));
        if (CollUtil.isEmpty(monitorList)) {
            throw new BusinessException(CommonResponseEnum.FAIL, "该设备监测点不存在");
        }

//        PqDevSub devSub = pqDevSubService.getOne(new LambdaQueryWrapper<PqDevSub>()
//                .eq(PqDevSub::getDevId, devId), false);
//        if (ObjectUtil.isNull(devSub)
//                || ObjectUtil.isNull(devSub.getCheckStartTime())
//                || ObjectUtil.isNull(devSub.getCheckEndTime())) {
//            throw new BusinessException(CommonResponseEnum.FAIL, "该设备检测开始时间或结束时间为空");
//        }

        DataCheckRequest request = new DataCheckRequest();
//        request.setLineIds(monitorList.stream().map(PqMonitor::getId).collect(Collectors.toList()));
//        request.setIndicatorCodes(Collections.emptyList());
//        request.setTimeStart(CHECKSQUARE_TIME_FORMATTER.format(devSub.getCheckStartTime()));
//        request.setTimeEnd(CHECKSQUARE_TIME_FORMATTER.format(devSub.getCheckEndTime()));
        request.setLineIds(Arrays.asList("ee9a33337bfd4d5588c00a2dbef6bc7e"));
        request.setIndicatorCodes(Arrays.asList("V_RMS"));
        request.setTimeStart("2026-06-08 00:00:00");
        request.setTimeEnd("2026-06-08 23:59:59");
        String s = restTemplateUtil.postJson(url, request, String.class);
        JSONObject obj = JSONUtil.parseObj(s);
        DataCheckResultVO data = BeanUtil.copyProperties(obj.get("data"), DataCheckResultVO.class);
        return data;
    }

    public enum NotifyStatus {
        RUNNING, SUCCESS, FAIL
    }

    @Value
    public static class NotifyState {
        NotifyStatus status;
        int failCount;
        String lastError;
        LocalDateTime triggerTime;

        public static NotifyState running() {
            return new NotifyState(NotifyStatus.RUNNING, 0, null, LocalDateTime.now());
        }
    }

    @Override
    public FormContentVO getFormContent(ResultParam.QueryParam queryParam) {
        FormContentVO formContentVO = new FormContentVO();
        AdPlan plan = adPlanService.getById(queryParam.getPlanId());
        formContentVO.setErrorSysId(plan.getErrorSysId());
        String scriptId = null;
        if (ObjectUtil.isNotNull(plan)) {
            formContentVO.setDataRule(plan.getDataRule());
            scriptId = plan.getScriptId();
            adPlanService.visualize(Collections.singletonList(plan));
            formContentVO.setScriptName(plan.getScriptId());
        }
        formContentVO.setDeviceName(pqDevService.getById(queryParam.getDeviceId()).getName());

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

        List<SimAndDigBaseResult> allResultList = new ArrayList<>();
        //只查询指定的脚本类型
        if (ObjectUtil.isNotNull(queryParam.getScriptType())) {
            List<Integer> indexList = pqScriptDtlsService.getIndexList(queryParam.getScriptType(), scriptId);
            DictTree dictTree = dictTreeService.getById(queryParam.getScriptType());

            if (HARMONIC_TYPE_CODE.contains(dictTree.getCode())) {
                allResultList.addAll(simAndDigHarmonicService.get(scriptId, indexList, queryParam.getDeviceId(), queryParam.getChnNum(), plan.getCode() + ""));
            } else {
                allResultList.addAll(simAndDigNonHarmonicService.listSimAndDigBaseResult(scriptId, indexList, queryParam.getDeviceId(), queryParam.getChnNum(), plan.getCode() + ""));
            }
        } else {  //查询所有的脚本类型
            allResultList.addAll(simAndDigHarmonicService.get(scriptId, null, queryParam.getDeviceId(), queryParam.getChnNum(), plan.getCode() + ""));
            allResultList.addAll(simAndDigNonHarmonicService.listSimAndDigBaseResult(scriptId, null, queryParam.getDeviceId(), queryParam.getChnNum(), plan.getCode() + ""));
        }


        if (ObjectUtil.isNotEmpty(allResultList)) {
            Map<String, List<SimAndDigBaseResult>> chnMap = allResultList.stream().collect(
                    Collectors.groupingBy(obj -> obj.getDevMonitorId().substring(obj.getDevMonitorId().lastIndexOf("_") + 1))
            );
            chnMap.forEach((chn, list) -> {
                Map<String, String> map = new HashMap<>();
                map.put("value", chn);
                Set<Integer> collect = list.stream().filter(obj -> obj.getResultFlag() != 4).map(SimAndDigBaseResult::getResultFlag).collect(Collectors.toSet());
                map.put("label", conform(collect) + "");

                chnList.add(map);
            });
        }

        chnList.sort(Comparator.comparingInt(o -> Integer.parseInt(o.get("value"))));
        formContentVO.setChnList(chnList);
        return formContentVO;
    }

    @Override
    public List<TreeDataVO> treeData(ResultParam param) {
        //根据所有的检测脚本查询出检测信息
        List<PqScriptDtls> dtlsList = pqScriptDtlsService.list(new MPJLambdaWrapper<PqScriptDtls>()
                .selectAll(PqScriptDtls.class)
                .eq(StrUtil.isNotBlank(param.getScriptId()), PqScriptDtls::getScriptId, param.getScriptId())
                .eq(StrUtil.isNotBlank(param.getScriptType()), PqScriptDtls::getScriptType, param.getScriptType())
                .ne(PqScriptDtls::getScriptIndex, -1)
                .eq(StrUtil.isNotBlank(param.getDevId()), PqScriptDtls::getEnable, DataStateEnum.ENABLE.getCode())
        );
        Map<Integer, Set<Integer>> resultMap = new HashMap<>(5);
        if (StrUtil.isNotBlank(param.getDevId())) {
            List<SimAndDigBaseResult> allResultList = new ArrayList<>();
            List<Integer> indexList = new ArrayList<>();
            if (StrUtil.isNotBlank(param.getScriptType())) {
                indexList = pqScriptDtlsService.getIndexList(param.getScriptType(), param.getScriptId());
            }
            allResultList.addAll(simAndDigNonHarmonicService.listSimAndDigBaseResult(param.getScriptId(), indexList, param.getDevId(), param.getDevNum(), param.getCode()));
            allResultList.addAll(simAndDigHarmonicService.get(param.getScriptId(), indexList, param.getDevId(), param.getDevNum(), param.getCode()));
            if (CollUtil.isNotEmpty(allResultList)) {
                resultMap = allResultList.stream().collect(Collectors.groupingBy(SimAndDigBaseResult::getSort, Collectors.mapping(SimAndDigBaseResult::getResultFlag, Collectors.toSet())));
            }
        }

        Map<String, List<PqScriptDtls>> dtlsSortMap = dtlsList.stream()
                .sorted(Comparator.comparing(PqScriptDtls::getScriptIndex))
                .collect(Collectors.groupingBy(PqScriptDtls::getScriptType, LinkedHashMap::new, Collectors.toList()));
        List<DictTree> dictTreeById = dictTreeService.getDictTreeById(new ArrayList<>(dtlsSortMap.keySet()));

        Map<String, DictTree> dictTreeMap = dictTreeById.stream().collect(Collectors.toMap(DictTree::getId, Function.identity()));
        // 影响量文案统一由 AffectEnum 提供；大小写不敏感 Map，兼容 Script_SubType 的大小写差异
        Map<String, String> subName = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
        for (AffectEnum affectEnum : AffectEnum.values()) {
            subName.put(affectEnum.getKey(), affectEnum.getDesc());
        }
        Boolean isValueType = scriptMapper.selectScriptIsValueType(param.getScriptId());

        List<TreeDataVO> infoVOS = new ArrayList<>();
        //根据检测大项进行分组展示
        Map<Integer, Set<Integer>> finalResultMap = resultMap;
        dtlsSortMap.forEach((key, value) -> {
            DictTree dictTree = dictTreeMap.get(key);
            if (ObjectUtil.isNotNull(dictTree)) {
                List<TreeDataVO> scriptSubList = new ArrayList<>();
                //大相检测信息
                TreeDataVO infoVO = new TreeDataVO();
                infoVO.setScriptTypeName(dictTree.getName());
                infoVO.setScriptTypeCode(dictTree.getId());
                //额定条件下频率准确度测试
                LinkedHashMap<String, List<PqScriptDtls>> subTypeMap = value.stream()
                        .sorted(Comparator.comparing(PqScriptDtls::getScriptIndex))
                        .filter(x -> "Base".equalsIgnoreCase(x.getScriptSubType()))
                        .collect(Collectors.groupingBy(PqScriptDtls::getScriptSubType, LinkedHashMap::new, Collectors.toList()));
                subTypeMap.forEach((subKey, subValue) -> {
                    if (!"VOLTAGE".equals(dictTree.getCode())) {
                        TreeDataVO subType = new TreeDataVO();
                        subType.setScriptTypeName(!subName.containsKey(subKey) ? "" : subName.get(subKey).replace("XX", dictTree.getName()));
                        subType.setScriptTypeCode(subKey);
                        LinkedHashMap<Integer, List<PqScriptDtls>> indexMap = subValue.stream()
                                .sorted(Comparator.comparing(PqScriptDtls::getScriptIndex))
                                .collect(Collectors.groupingBy(PqScriptDtls::getScriptIndex, LinkedHashMap::new, Collectors.toList()));
                        List<TreeDataVO> subTypeList = new ArrayList<>();
                        indexMap.forEach((index, scriptDtlIndexList) -> {
                            TreeDataVO dtlType = new TreeDataVO();
                            dtlType.setIndex(index);
                            dtlType.setScriptType(scriptDtlIndexList.get(0).getScriptType());
                            dtlType.setScriptTypeCode(subKey);
                            ratedScriptTypeName(scriptDtlIndexList, isValueType, dtlType, dictTree);
                            dtlType.setSourceDesc(ScriptDtlsDesc.getStringBuffer(scriptDtlIndexList, false, isValueType).toString());
                            if (finalResultMap.containsKey(index)) {
                                dtlType.setFly(conform(finalResultMap.get(index)));
                            }
                            subTypeList.add(dtlType);
                        });
                        if (CollUtil.isNotEmpty(subTypeList)) {
                            subType.setChildren(subTypeList);
                            scriptSubList.add(subType);
                        }
                    } else {
                        dipScriptTypeName(subValue, scriptSubList, finalResultMap, isValueType, "电压暂降测量准确度测试", 20, 85);
                        dipScriptTypeName(subValue, scriptSubList, finalResultMap, isValueType, "电压暂升测量准确度测试", 110, 200);
                        dipScriptTypeName(subValue, scriptSubList, finalResultMap, isValueType, "电压中断测量准确度测试", 0, 10);
                    }

                });


                //单影响量下频率准确度测试
                LinkedHashMap<String, List<PqScriptDtls>> subSingleTypeMap = value.stream()
                        .sorted(Comparator.comparing(PqScriptDtls::getScriptIndex))
                        .filter(x -> !"Base".equalsIgnoreCase(x.getScriptSubType()) && !StrUtil.containsIgnoreCase(x.getScriptSubType(), "Many"))
                        .collect(Collectors.groupingBy(PqScriptDtls::getScriptSubType, LinkedHashMap::new, Collectors.toList()));
                if (CollUtil.isNotEmpty(subSingleTypeMap)) {
                    TreeDataVO subType = new TreeDataVO();
                    subType.setScriptTypeName(!subName.containsKey("Single") ? "" : subName.get("Single").replace("XX", dictTree.getName()));
                    subType.setScriptTypeCode(dictTree.getCode());
                    //单影响量下频率准测量集合
                    List<TreeDataVO> subSingleList = new ArrayList<>();
                    subSingleTypeMap.forEach((subKey, subValue) -> {
                        TreeDataVO treeDataVO = new TreeDataVO();
                        treeDataVO.setScriptTypeName(!subName.containsKey(subKey) ? "" : subName.get(subKey).replace("XX", dictTree.getName()));
                        treeDataVO.setScriptTypeCode(subKey);
                        List<TreeDataVO> subTypeList = new ArrayList<>();

                        LinkedHashMap<Integer, List<PqScriptDtls>> indexMap = subValue.stream()
                                .sorted(Comparator.comparing(PqScriptDtls::getScriptIndex))
                                .collect(Collectors.groupingBy(PqScriptDtls::getScriptIndex, LinkedHashMap::new, Collectors.toList()));
                        indexMap.forEach((index, scriptDtlIndexList) -> {
                            TreeDataVO dtlType = new TreeDataVO();
                            dtlType.setIndex(index);
                            dtlType.setScriptType(scriptDtlIndexList.get(0).getScriptType());
                            dtlType.setScriptTypeCode(subKey);
                            if ("Harm".equalsIgnoreCase(subKey)) {
                                harmScriptTypeName(scriptDtlIndexList, dictTree, isValueType, dtlType);
                            }
                            if ("VOL".equalsIgnoreCase(subKey)) {
                                volScriptTypeName(scriptDtlIndexList, dictTree, isValueType, dtlType);
                            }
                            if ("Freq".equalsIgnoreCase(subKey)) {
                                freqScriptTypeName(scriptDtlIndexList, dictTree, isValueType, dtlType);
                            }
                            dtlType.setSourceDesc(ScriptDtlsDesc.getStringBuffer(scriptDtlIndexList, false, isValueType).toString());
                            if (finalResultMap.containsKey(index)) {
                                dtlType.setFly(conform(finalResultMap.get(index)));
                            }
                            subTypeList.add(dtlType);
                        });
                        if (CollUtil.isNotEmpty(subTypeList)) {
                            treeDataVO.setChildren(subTypeList);
                            subSingleList.add(treeDataVO);
                        }
                    });
                    if (CollUtil.isNotEmpty(subSingleList)) {
                        subType.setChildren(subSingleList);
                        scriptSubList.add(subType);
                    }
                }
                //多影响量下xx
                LinkedHashMap<String, List<PqScriptDtls>> subManyTypeMap = value.stream()
                        .sorted(Comparator.comparing(PqScriptDtls::getScriptIndex))
                        .filter(x -> StrUtil.containsIgnoreCase(x.getScriptSubType(), "Many"))
                        .collect(Collectors.groupingBy(PqScriptDtls::getScriptSubType, LinkedHashMap::new, Collectors.toList()));
                if (CollUtil.isNotEmpty(subManyTypeMap)) {
                    TreeDataVO subType = new TreeDataVO();
                    subType.setScriptTypeName(!subName.containsKey("Many") ? "" : subName.get("Many").replace("XX", dictTree.getName()));
                    subType.setScriptTypeCode(dictTree.getCode());
                    //多影响量下xx准测量集合
                    List<TreeDataVO> subSingleList = new ArrayList<>();
                    subManyTypeMap.forEach((subKey, subValue) -> {
                        TreeDataVO treeDataVO = new TreeDataVO();
                        treeDataVO.setScriptTypeName(!subName.containsKey(subKey) ? "" : subName.get(subKey).replace("XX", dictTree.getName()));
                        treeDataVO.setScriptTypeCode(subKey);
                        List<TreeDataVO> subTypeList = new ArrayList<>();

                        LinkedHashMap<Integer, List<PqScriptDtls>> indexMap = subValue.stream()
                                .sorted(Comparator.comparing(PqScriptDtls::getScriptIndex))
                                .collect(Collectors.groupingBy(PqScriptDtls::getScriptIndex, LinkedHashMap::new, Collectors.toList()));
                        indexMap.forEach((index, scriptDtlIndexList) -> {
                            TreeDataVO dtlType = new TreeDataVO();
                            dtlType.setIndex(index);
                            dtlType.setScriptType(scriptDtlIndexList.get(0).getScriptType());
                            dtlType.setScriptTypeCode(subKey);
                            if ("Many-Vol-Harm-InHarm".equalsIgnoreCase(subKey)) {
                                volAndHarmAndInHarmScriptTypeName(scriptDtlIndexList, dictTree, isValueType, dtlType);
                            }
                            if ("Many-IMBV-Harm-InHarm".equalsIgnoreCase(subKey)) {
                                imbvAndHarmAndInHarmScriptTypeName(scriptDtlIndexList, dictTree, isValueType, dtlType);
                            }
                            if ("Many-Freq-Harm-InHarm".equalsIgnoreCase(subKey)) {
                                freqAndHarmAndInHarmScriptTypeName(scriptDtlIndexList, dictTree, isValueType, dtlType);
                            }
                            dtlType.setSourceDesc(ScriptDtlsDesc.getStringBuffer(scriptDtlIndexList, false, isValueType).toString());
                            if (finalResultMap.containsKey(index)) {
                                dtlType.setFly(conform(finalResultMap.get(index)));
                            }
                            subTypeList.add(dtlType);
                        });
                        if (CollUtil.isNotEmpty(subTypeList)) {
                            treeDataVO.setChildren(subTypeList);
                            subSingleList.add(treeDataVO);
                        }
                    });
                    if (CollUtil.isNotEmpty(subSingleList)) {
                        subType.setChildren(subSingleList);
                        scriptSubList.add(subType);
                    }
                }
                if (CollUtil.isNotEmpty(scriptSubList)) {
                    infoVO.setChildren(scriptSubList);
                    infoVOS.add(infoVO);
                }
            }
        });
        return infoVOS;
    }

    private void dipScriptTypeName(List<PqScriptDtls> subValue, List<TreeDataVO> subTypeList, Map<Integer, Set<Integer>> finalResultMap, Boolean isValueType, String name, Integer start, Integer end) {
        List<TreeDataVO> info = new ArrayList<>();
        List<PqScriptDtls> dip = subValue.stream()
//                .filter(x -> "Dip".equals(x.getValueType()) && "A".equals(x.getPhase()))
                .filter(x -> "Dip".equals(x.getValueType()))
                .filter(x -> x.getTransValue() >= start && x.getTransValue() <= end)
                .sorted(Comparator.comparing(PqScriptDtls::getScriptIndex))
                .collect(Collectors.toList());
        LinkedHashMap<Integer, List<PqScriptDtls>> idxDipMap = dip.stream().collect(Collectors.groupingBy(d -> d.getScriptIndex(), LinkedHashMap::new, Collectors.toList()));

        dip.clear();
        idxDipMap.forEach((idx, scriptDtlList) -> {
            scriptDtlList.sort(Comparator.comparing(PqScriptDtls::getPhase));
            dip.add(scriptDtlList.get(0));
        });

        TreeDataVO vo = new TreeDataVO();
        vo.setScriptTypeName(name);
        vo.setScriptTypeCode("Base_" + start + "_" + end);
        TreeDataVO dlt;
        for (PqScriptDtls dtls : dip) {
            dlt = new TreeDataVO();
            List<PqScriptDtls> scriptDtlIndexList = subValue.stream().filter(x -> dtls.getScriptIndex().equals(x.getScriptIndex())).collect(Collectors.toList());
            //特征幅值=20%Un，持续时间=1周波
            dlt.setScriptTypeName("特征幅值=" + dtls.getTransValue() + "%Un，持续时间=" + dtls.getRetainTime() + "周波");
            dlt.setIndex(dtls.getScriptIndex());
            dlt.setScriptType(scriptDtlIndexList.get(0).getScriptType());
            dlt.setScriptTypeCode("Base_" + start + "_" + end);
            dlt.setSourceDesc(ScriptDtlsDesc.getStringBuffer(scriptDtlIndexList, false, isValueType).toString());
            if (finalResultMap.containsKey(dtls.getScriptIndex())) {
                dlt.setFly(conform(finalResultMap.get(dtls.getScriptIndex())));
            }
            info.add(dlt);

        }
        if (CollUtil.isNotEmpty(info)) {
            vo.setChildren(info);
            subTypeList.add(vo);
        }
    }

    private void ratedScriptTypeName(List<PqScriptDtls> scriptDtlIndexList, Boolean isValueType, TreeDataVO dtlType, DictTree dictTree) {
        ResultUnitEnum resultUnitEnumByCode = ResultUnitEnum.getResultUnitEnumByCode(dictTree.getCode());
        String unitV;
        String unitI;
        if (isValueType) {
            unitV = ResultUnitEnum.V_RELATIVE.getUnit();
            unitI = ResultUnitEnum.I_RELATIVE.getUnit();
        } else {
            unitV = ResultUnitEnum.V_ABSOLUTELY.getUnit();
            unitI = ResultUnitEnum.I_ABSOLUTELY.getUnit();
        }
        switch (resultUnitEnumByCode) {
            /**
             * 频率
             */
            case FREQ:
                List<PqScriptDtls> f = scriptDtlIndexList.stream().filter(x -> "Freq".equals(x.getValueType())).collect(Collectors.toList());
                dtlType.setScriptTypeName(dictTree.getName() + "=" + f.get(0).getValue() + ResultUnitEnum.FREQ.getUnit());
                break;
            case P: {
                List<PqScriptDtls> v = scriptDtlIndexList.stream().filter(x -> "VOL".equals(x.getValueType())).collect(Collectors.toList());
                List<PqScriptDtls> i = scriptDtlIndexList.stream().filter(x -> "CUR".equals(x.getValueType())).collect(Collectors.toList());
                List<PqScriptDtls> aDtl1 = scriptDtlIndexList.stream().filter(x -> "A".equals(x.getPhase()) && "VOL".equals(x.getValueType())).collect(Collectors.toList());
                List<PqScriptDtls> aDtl2 = scriptDtlIndexList.stream().filter(x -> "A".equals(x.getPhase()) && "CUR".equals(x.getValueType())).collect(Collectors.toList());

                double cosValue = Math.cos((aDtl1.get(0).getAngle() - aDtl2.get(0).getAngle()) / 180 * Math.PI);
                BigDecimal bigDecimal = BigDecimal.valueOf(cosValue).setScale(6, BigDecimal.ROUND_HALF_UP);

                dtlType.setScriptTypeName(ResultUnitEnum.V_RELATIVE.getName() + "=" + v.get(0).getValue() + unitV
                        + " " + ResultUnitEnum.I_RELATIVE.getName() + "=" + i.get(0).getValue() + unitI
                        + " cos(φ)=" + bigDecimal.doubleValue());
            }
            break;
            /**
             * 电压
             */
            case V_RELATIVE:
            case V_ABSOLUTELY:
                List<PqScriptDtls> v = scriptDtlIndexList.stream().filter(x -> "VOL".equals(x.getValueType())).collect(Collectors.toList());
                dtlType.setScriptTypeName(dictTree.getName() + "=" + v.get(0).getValue() + unitV);
                break;
            /**
             * 电流
             */
            case I_RELATIVE:
            case I_ABSOLUTELY:
                List<PqScriptDtls> I = scriptDtlIndexList.stream().filter(x -> "CUR".equals(x.getValueType())).collect(Collectors.toList());
                dtlType.setScriptTypeName(dictTree.getName() + "=" + I.get(0).getValue() + unitI);
                break;
            /**
             * 谐波电压
             * 谐波电流
             */
            case HV:
            case HI:
                String valueType;
                if ("HV".equals(dictTree.getCode())) {
                    valueType = "Harm_V";
                } else {
                    valueType = "Harm_I";
                }
                List<PqScriptDtls> hv = scriptDtlIndexList.stream().filter(x -> valueType.equals(x.getValueType())).collect(Collectors.toList());
                LinkedHashMap<Double, List<PqScriptDtls>> harmNumMap = hv.stream()
                        .sorted(Comparator.comparing(PqScriptDtls::getHarmNum))
                        .collect(Collectors.groupingBy(PqScriptDtls::getHarmNum, LinkedHashMap::new, Collectors.toList()));
                if (harmNumMap.size() > 1) {
                    //叠加2~50次谐波电压（含有率为GB/T）
                    dtlType.setScriptTypeName("叠加" + harmNumMap.entrySet().iterator().next().getValue().get(0).getHarmNum() + "~" +
                            new ArrayList<>(harmNumMap.entrySet()).get(harmNumMap.size() - 1).getValue().get(0).getHarmNum()
                            + "次" + dictTree.getName()); // + "（含有率为GB/T）"
                } else {
                    //叠加5%的2次谐波电压
                    dtlType.setScriptTypeName("叠加" + hv.get(0).getValue() + ResultUnitEnum.HV.getUnit() + "的" + hv.get(0).getHarmNum() + "次" + dictTree.getName());
                }
                break;
            /**
             * 间谐波电压
             * 间谐波电流
             */
            case HSV:
            case HSI:
                //叠加1.5/5.5/7.5/49.5次间谐波，含有率为。。。
                String in;
                if ("HSV".equals(dictTree.getCode())) {
                    in = "InHarm_V";
                } else {
                    in = "InHarm_I";
                }
                List<PqScriptDtls> harmInNumList = scriptDtlIndexList.stream().filter(x -> in.equals(x.getValueType()) && "A".equals(x.getPhase()))
                        .sorted(Comparator.comparing(PqScriptDtls::getHarmNum))
                        .distinct().collect(Collectors.toList());

                if (harmInNumList.size() > 1) {
                    StringBuffer a = new StringBuffer();
                    a.append("叠加");
                    for (int i = 0; i < harmInNumList.size(); i++) {
                        if (i == harmInNumList.size() - 1) {
                            a.append(harmInNumList.get(i).getHarmNum());
                        } else {
                            a.append(harmInNumList.get(i).getHarmNum() + "/");
                        }
                    }
                    a.append("次" + dictTree.getName());
                    dtlType.setScriptTypeName(a.toString());
                } else {
                    //叠加5%的2次谐波电压
                    dtlType.setScriptTypeName("叠加" + harmInNumList.get(0).getValue() + ResultUnitEnum.HV.getUnit() + "的" + harmInNumList.get(0).getHarmNum() + "次" + dictTree.getName());
                }

                break;
            /**
             * 三相电压不平衡度
             */
            case IMBV:
                List<PqScriptCheckData> list = pqScriptCheckDataService.list(new MPJLambdaWrapper<PqScriptCheckData>()
                        .eq(PqScriptCheckData::getScriptId, scriptDtlIndexList.get(0).getScriptId())
                        .eq(PqScriptCheckData::getScriptIndex, scriptDtlIndexList.get(0).getScriptIndex())
                );
                //三相负序电压不平衡度=0%
                dtlType.setScriptTypeName(dictTree.getName() + "=" + list.get(0).getValue() + ResultUnitEnum.IMBV.getUnit());
                break;
            /**
             * 三相电流不平衡度
             */
            case IMBA:
                List<PqScriptCheckData> imba = pqScriptCheckDataService.list(new MPJLambdaWrapper<PqScriptCheckData>()
                        .eq(PqScriptCheckData::getScriptId, scriptDtlIndexList.get(0).getScriptId())
                        .eq(PqScriptCheckData::getScriptIndex, scriptDtlIndexList.get(0).getScriptIndex())
                );
                //三相负序电流不平衡度=0%
                dtlType.setScriptTypeName(dictTree.getName() + "=" + imba.get(0).getValue() + ResultUnitEnum.IMBV.getUnit());
                break;
            /**
             * 谐波有功功率
             */
            case HP:
                //10%的2次谐波电压，40%的2次谐波电流
                List<PqScriptDtls> hpv = scriptDtlIndexList.stream().filter(x -> "Harm_V".equals(x.getValueType())).collect(Collectors.toList());
                List<PqScriptDtls> hpI = scriptDtlIndexList.stream().filter(x -> "Harm_I".equals(x.getValueType())).collect(Collectors.toList());
                LinkedHashMap<Double, List<PqScriptDtls>> harmNumVMap = hpv.stream()
                        .sorted(Comparator.comparing(PqScriptDtls::getHarmNum))
                        .collect(Collectors.groupingBy(PqScriptDtls::getHarmNum, LinkedHashMap::new, Collectors.toList()));

                LinkedHashMap<Double, List<PqScriptDtls>> harmNumIMap = hpI.stream()
                        .sorted(Comparator.comparing(PqScriptDtls::getHarmNum))
                        .collect(Collectors.groupingBy(PqScriptDtls::getHarmNum, LinkedHashMap::new, Collectors.toList()));
                StringBuffer a = new StringBuffer();
                if (harmNumVMap.size() > 1) {
                    ArrayList<List<PqScriptDtls>> lists = new ArrayList<>(harmNumVMap.values());
                    Map<Double, List<PqScriptDtls>> hpvMap = lists.stream().flatMap(x -> x.stream().filter(j -> "A".equals(j.getPhase()))).collect(Collectors.groupingBy(PqScriptDtls::getValue));
                    hpvMap.forEach((key, value) -> {
                        a.append(key.intValue() + ResultUnitEnum.HV.getUnit() + "的");
                        for (int i = 0; i < value.size(); i++) {
                            if (i == value.size() - 1) {
                                a.append(value.get(i).getHarmNum().intValue());
                            } else {
                                a.append(value.get(i).getHarmNum().intValue() + "、");
                            }
                        }
                        a.append("次" + ResultUnitEnum.HV.getName());
                    });
                } else {
                    PqScriptDtls dtls = harmNumVMap.entrySet().iterator().next().getValue().get(0);
                    a.append(dtls.getValue().intValue() + ResultUnitEnum.HV.getUnit() + "的" + dtls.getHarmNum().intValue() + ResultUnitEnum.HV.getName());
                }
                a.append(",");
                if (harmNumIMap.size() > 1) {
                    ArrayList<List<PqScriptDtls>> lists = new ArrayList<>(harmNumIMap.values());
                    Map<Double, List<PqScriptDtls>> hpvMap = lists.stream().flatMap(x -> x.stream().filter(j -> "A".equals(j.getPhase()))).collect(Collectors.groupingBy(PqScriptDtls::getValue));
                    hpvMap.forEach((key, value) -> {
                        a.append(key.intValue() + ResultUnitEnum.HI.getUnit() + "的");
                        for (int i = 0; i < value.size(); i++) {
                            if (i == value.size() - 1) {
                                a.append(value.get(i).getHarmNum().intValue());
                            } else {
                                a.append(value.get(i).getHarmNum().intValue() + "、");
                            }
                        }
                        a.append("次" + ResultUnitEnum.HI.getName());
                    });
                } else {
                    PqScriptDtls dtls = harmNumIMap.entrySet().iterator().next().getValue().get(0);
                    a.append(dtls.getValue().intValue() + ResultUnitEnum.HI.getUnit() + "的" + dtls.getHarmNum().intValue() + "次" + ResultUnitEnum.HI.getName());
                }
                dtlType.setScriptTypeName(a.toString());
                break;
            /**
             * 闪变
             */
            case F:
                //Pst=1(变动率=1.459%*1)
                List<PqScriptDtls> flicker = scriptDtlIndexList.stream().filter(x -> "Flicker".equals(x.getValueType())).collect(Collectors.toList());
                dtlType.setScriptTypeName("变动频度=" + flicker.get(0).getChagFre() + "次/min，" + "变动率=" + flicker.get(0).getChagValue() + "%");
                break;
            /**
             * 暂态
             */
            case VOLTAGE_MAG:
            case VOLTAGE_DUR:
            case ANGLE: {
                List<PqScriptDtls> aDtlV = scriptDtlIndexList.stream().filter(x -> "A".equals(x.getPhase()) && "VOL".equals(x.getValueType())).collect(Collectors.toList());
                List<PqScriptDtls> aDtlI = scriptDtlIndexList.stream().filter(x -> "A".equals(x.getPhase()) && "CUR".equals(x.getValueType())).collect(Collectors.toList());
                List<PqScriptDtls> bDtlV = scriptDtlIndexList.stream().filter(x -> "B".equals(x.getPhase()) && "VOL".equals(x.getValueType())).collect(Collectors.toList());
                List<PqScriptDtls> bDtlI = scriptDtlIndexList.stream().filter(x -> "B".equals(x.getPhase()) && "CUR".equals(x.getValueType())).collect(Collectors.toList());
                List<PqScriptDtls> cDtlV = scriptDtlIndexList.stream().filter(x -> "C".equals(x.getPhase()) && "VOL".equals(x.getValueType())).collect(Collectors.toList());
                List<PqScriptDtls> cDtlI = scriptDtlIndexList.stream().filter(x -> "C".equals(x.getPhase()) && "CUR".equals(x.getValueType())).collect(Collectors.toList());

                StringBuilder scriptTypeName = new StringBuilder();
                if (CollUtil.isNotEmpty(aDtlV)) {
                    scriptTypeName.append("A相：电压相角=" + aDtlV.get(0).getAngle() + ResultUnitEnum.ANGLE.getUnit());
                }
                if (CollUtil.isNotEmpty(aDtlI)) {
                    scriptTypeName.append(",电流相角=" + aDtlI.get(0).getAngle() + ResultUnitEnum.ANGLE.getUnit());
                }
                if (CollUtil.isNotEmpty(bDtlV)) {
                    scriptTypeName.append(";B相：电压相角=" + bDtlV.get(0).getAngle() + ResultUnitEnum.ANGLE.getUnit());
                }
                if (CollUtil.isNotEmpty(bDtlI)) {
                    scriptTypeName.append(",电流相角=" + bDtlI.get(0).getAngle() + ResultUnitEnum.ANGLE.getUnit());
                }
                if (CollUtil.isNotEmpty(cDtlV)) {
                    scriptTypeName.append(";C相：电压相角=" + cDtlV.get(0).getAngle() + ResultUnitEnum.ANGLE.getUnit());
                }
                if (CollUtil.isNotEmpty(cDtlI)) {
                    scriptTypeName.append(",电流相角=" + cDtlI.get(0).getAngle() + ResultUnitEnum.ANGLE.getUnit());
                }
                dtlType.setScriptTypeName(scriptTypeName.toString());
            }
            break;
            default:
                break;
        }
    }

    private void harmScriptTypeName(List<PqScriptDtls> dtls, DictTree dictTree, Boolean isValueType, TreeDataVO dtlType) {
        ResultUnitEnum resultUnitEnumByCode = ResultUnitEnum.getResultUnitEnumByCode(dictTree.getCode());
        switch (resultUnitEnumByCode) {
            /**
             * 频率
             */
            case FREQ:
                List<PqScriptDtls> f = dtls.stream().filter(x -> "Freq".equals(x.getValueType())).collect(Collectors.toList());
                dtlType.setScriptTypeName("叠加多次谐波对" + dictTree.getName() + "=" + f.get(0).getValue() + ResultUnitEnum.FREQ.getUnit() + "的影响");
                break;
            /**
             * 电压
             */
            case V_RELATIVE:
            case V_ABSOLUTELY:
                String unit;
                if (isValueType) {
                    unit = ResultUnitEnum.V_RELATIVE.getUnit();
                } else {
                    unit = ResultUnitEnum.V_ABSOLUTELY.getUnit();
                }
                List<PqScriptDtls> v = dtls.stream().filter(x -> "VOL".equals(x.getValueType())).collect(Collectors.toList());
                dtlType.setScriptTypeName("叠加多次谐波对" + dictTree.getName() + "=" + v.get(0).getValue() + unit + "的影响");
                break;
            /**
             * 电流
             */
            case I_RELATIVE:
            case I_ABSOLUTELY:
                break;
            /**
             * 谐波电压
             */
            case HV:
                break;
            /**
             * 谐波电流
             */
            case HI:
                break;
            /**
             * 间谐波电压
             */
            case HSV:
                break;
            /**
             * 间谐波电流
             */
            case HSI:
                break;
            /**
             * 三相电压不平衡度
             */
            case IMBV:
                break;
            /**
             * 三相电流不平衡度
             */
            case IMBA:
                break;
            /**
             * 谐波有功功率
             */
            case HP:
                break;
            /**
             * 闪变
             */
            case F:
                break;
            /**
             * 暂态
             */
            case VOLTAGE_MAG:
            case VOLTAGE_DUR:
                break;
            default:
                break;
        }
    }

    private void volScriptTypeName(List<PqScriptDtls> dtls, DictTree dictTree, Boolean isValueType, TreeDataVO dtlType) {
        ResultUnitEnum resultUnitEnumByCode = ResultUnitEnum.getResultUnitEnumByCode(dictTree.getCode());
        switch (resultUnitEnumByCode) {
            /**
             * 频率
             */
            case FREQ:
                String unit;
                if (isValueType) {
                    unit = ResultUnitEnum.V_RELATIVE.getUnit();
                } else {
                    unit = ResultUnitEnum.V_ABSOLUTELY.getUnit();
                }
                List<PqScriptDtls> f = dtls.stream().filter(x -> "Freq".equals(x.getValueType())).collect(Collectors.toList());
                List<PqScriptDtls> v = dtls.stream().filter(x -> "VOL".equals(x.getValueType())).collect(Collectors.toList());
                dtlType.setScriptTypeName(v.get(0).getValue().intValue() + unit + "对" + dictTree.getName() + "=" + f.get(0).getValue() + ResultUnitEnum.FREQ.getUnit() + "的影响");
                break;
            /**
             * 电压
             */
            case V_RELATIVE:
            case V_ABSOLUTELY:
                break;
            /**
             * 电流
             */
            case I_RELATIVE:
            case I_ABSOLUTELY:
                break;
            /**
             * 谐波电压
             */
            case HV:
                //电压有效值10%，3次谐波电压，含有率
                List<PqScriptDtls> hvv = dtls.stream().filter(x -> "VOL".equals(x.getValueType())).collect(Collectors.toList());
                List<PqScriptDtls> hv = dtls.stream().filter(x -> "Harm_V".equals(x.getValueType())).collect(Collectors.toList());
                dtlType.setScriptTypeName("电压有效值" + hvv.get(0).getValue().intValue() + ResultUnitEnum.HV.getUnit() + "," + hv.get(0).getHarmNum().intValue() + "次" + dictTree.getName());
                break;
            /**
             * 谐波电流
             */
            case HI:
                List<PqScriptDtls> hiv = dtls.stream().filter(x -> "VOL".equals(x.getValueType())).collect(Collectors.toList());
                List<PqScriptDtls> hi = dtls.stream().filter(x -> "Harm_I".equals(x.getValueType())).collect(Collectors.toList());
                dtlType.setScriptTypeName("电压有效值" + hiv.get(0).getValue().intValue() + ResultUnitEnum.HI.getUnit() + "," + hi.get(0).getHarmNum().intValue() + "次" + dictTree.getName());
                break;
            /**
             * 间谐波电压
             */
            case HSV:
                List<PqScriptDtls> hsvv = dtls.stream().filter(x -> "VOL".equals(x.getValueType())).collect(Collectors.toList());
                List<PqScriptDtls> hsv = dtls.stream().filter(x -> "InHarm_V".equals(x.getValueType())).collect(Collectors.toList());
                dtlType.setScriptTypeName("电压有效值" + hsvv.get(0).getValue().intValue() + ResultUnitEnum.HSV.getUnit() + "," + hsv.get(0).getHarmNum() + "次" + dictTree.getName());
                break;
            /**
             * 间谐波电流
             */
            case HSI:
                List<PqScriptDtls> hsiv = dtls.stream().filter(x -> "VOL".equals(x.getValueType())).collect(Collectors.toList());
                List<PqScriptDtls> hsi = dtls.stream().filter(x -> "InHarm_I".equals(x.getValueType())).collect(Collectors.toList());
                dtlType.setScriptTypeName("电压有效值" + hsiv.get(0).getValue().intValue() + ResultUnitEnum.HSI.getUnit() + "," + hsi.get(0).getHarmNum() + "次" + dictTree.getName());
                break;
            /**
             * 三相电压不平衡度
             */
            case IMBV:
                break;
            /**
             * 三相电流不平衡度
             */
            case IMBA:
                break;
            /**
             * 谐波有功功率
             */
            case HP:
                break;
            /**
             * 闪变
             */
            case F:
                break;
            /**
             * 暂态
             */
            case VOLTAGE_MAG:
            case VOLTAGE_DUR:
                break;
            default:
                break;
        }
    }

    private void freqScriptTypeName(List<PqScriptDtls> dtls, DictTree dictTree, Boolean isValueType, TreeDataVO dtlType) {
        ResultUnitEnum resultUnitEnumByCode = ResultUnitEnum.getResultUnitEnumByCode(dictTree.getCode());
        switch (resultUnitEnumByCode) {
            /**
             * 频率
             */
            case FREQ:
                break;
            /**
             * 电压
             */
            case V_RELATIVE:
            case V_ABSOLUTELY:
                String unit;
                if (isValueType) {
                    unit = ResultUnitEnum.V_RELATIVE.getUnit();
                } else {
                    unit = ResultUnitEnum.V_ABSOLUTELY.getUnit();
                }
                List<PqScriptDtls> f = dtls.stream().filter(x -> "Freq".equals(x.getValueType())).collect(Collectors.toList());
                List<PqScriptDtls> v = dtls.stream().filter(x -> "VOL".equals(x.getValueType())).collect(Collectors.toList());
                dtlType.setScriptTypeName("频率=" + f.get(0).getValue() + ResultUnitEnum.FREQ.getUnit() + "," + dictTree.getName() + "=" + v.get(0).getValue() + unit);
                break;
            /**
             * 电流
             */
            case I_RELATIVE:
            case I_ABSOLUTELY:
                break;
            /**
             * 谐波电压
             */
            case HV:
                //基波频率为42.5Hz,2次谐波电压
                List<PqScriptDtls> hvf = dtls.stream().filter(x -> "Freq".equals(x.getValueType())).collect(Collectors.toList());
                List<PqScriptDtls> hv = dtls.stream().filter(x -> "Harm_V".equals(x.getValueType())).collect(Collectors.toList());
                dtlType.setScriptTypeName("基波频率为" + hvf.get(0).getValue() + ResultUnitEnum.FREQ.getUnit() + "," + hv.get(0).getHarmNum().intValue() + "次" + dictTree.getName());
                break;
            /**
             * 谐波电流
             */
            case HI:
                List<PqScriptDtls> hif = dtls.stream().filter(x -> "Freq".equals(x.getValueType())).collect(Collectors.toList());
                List<PqScriptDtls> hi = dtls.stream().filter(x -> "Harm_I".equals(x.getValueType())).collect(Collectors.toList());
                dtlType.setScriptTypeName("基波频率为" + hif.get(0).getValue() + ResultUnitEnum.FREQ.getUnit() + "," + hi.get(0).getHarmNum().intValue() + "次" + dictTree.getName());
                break;
            /**
             * 间谐波电压
             */
            case HSV:
                List<PqScriptDtls> hsvf = dtls.stream().filter(x -> "Freq".equals(x.getValueType())).collect(Collectors.toList());
                List<PqScriptDtls> hsv = dtls.stream().filter(x -> "InHarm_V".equals(x.getValueType())).collect(Collectors.toList());
                dtlType.setScriptTypeName("基波频率为" + hsvf.get(0).getValue() + ResultUnitEnum.FREQ.getUnit() + "," + hsv.get(0).getHarmNum() + "次" + dictTree.getName());
                break;
            /**
             * 间谐波电流
             */
            case HSI:
                List<PqScriptDtls> hsif = dtls.stream().filter(x -> "Freq".equals(x.getValueType())).collect(Collectors.toList());
                List<PqScriptDtls> hsi = dtls.stream().filter(x -> "InHarm_I".equals(x.getValueType())).collect(Collectors.toList());
                dtlType.setScriptTypeName("基波频率为" + hsif.get(0).getValue() + ResultUnitEnum.FREQ.getUnit() + "," + hsi.get(0).getHarmNum() + "次" + dictTree.getName());
                break;
            /**
             * 三相电压不平衡度
             */
            case IMBV:
                break;
            /**
             * 三相电流不平衡度
             */
            case IMBA:
                break;
            /**
             * 谐波有功功率
             */
            case HP:
                break;
            /**
             * 闪变
             */
            case F:
                break;
            /**
             * 暂态
             */
            case VOLTAGE_MAG:
            case VOLTAGE_DUR:
                //频率=42.5H在，特征幅值=60%Un，持续时间=1周波
                List<PqScriptDtls> dipf = dtls.stream().filter(x -> "Freq".equals(x.getValueType())).collect(Collectors.toList());
                List<PqScriptDtls> dip = dtls.stream().filter(x -> "Dip".equals(x.getValueType())).collect(Collectors.toList());
                dtlType.setScriptTypeName("频率=" + dipf.get(0).getValue() + ResultUnitEnum.FREQ.getUnit() + ",特征幅值=" + dip.get(0).getTransValue().intValue() + "%Un，持续时间=" + dip.get(0).getRetainTime().intValue() + "周波");
                break;
            default:
                break;
        }
    }

    private void volAndHarmAndInHarmScriptTypeName(List<PqScriptDtls> dtls, DictTree dictTree, Boolean isValueType, TreeDataVO dtlType) {
        ResultUnitEnum resultUnitEnumByCode = ResultUnitEnum.getResultUnitEnumByCode(dictTree.getCode());
        List<PqScriptDtls> f = dtls.stream().filter(x -> "Freq".equals(x.getValueType())).collect(Collectors.toList());
        String unit;
        if (isValueType) {
            unit = ResultUnitEnum.V_RELATIVE.getUnit();
        } else {
            unit = ResultUnitEnum.V_ABSOLUTELY.getUnit();
        }
        List<PqScriptDtls> v = dtls.stream().filter(x -> "VOL".equals(x.getValueType())).collect(Collectors.toList());
        switch (resultUnitEnumByCode) {
            /**
             * 频率
             */
            case FREQ:
                dtlType.setScriptTypeName("电压：" + v.get(0).getValue() + unit + "，叠加多次谐波和间谐波对" + dictTree.getName() + "=" + f.get(0).getValue() + ResultUnitEnum.FREQ.getUnit() + "的影响");
                break;
            /**
             * 电压
             */
            case V_RELATIVE:
            case V_ABSOLUTELY:
                break;
            /**
             * 电流
             */
            case I_RELATIVE:
            case I_ABSOLUTELY:
                break;
            /**
             * 谐波电压
             */
            case HV:
                break;
            /**
             * 谐波电流
             */
            case HI:
                break;
            /**
             * 间谐波电压
             */
            case HSV:
                break;
            /**
             * 间谐波电流
             */
            case HSI:
                break;
            /**
             * 三相电压不平衡度
             */
            case IMBV:
                break;
            /**
             * 三相电流不平衡度
             */
            case IMBA:
                break;
            /**
             * 谐波有功功率
             */
            case HP:
                break;
            /**
             * 闪变
             */
            case F:
                break;
            /**
             * 暂态
             */
            case VOLTAGE_MAG:
            case VOLTAGE_DUR:
                break;
            default:
                break;
        }
    }

    private void imbvAndHarmAndInHarmScriptTypeName(List<PqScriptDtls> dtls, DictTree dictTree, Boolean isValueType, TreeDataVO dtlType) {
        ResultUnitEnum resultUnitEnumByCode = ResultUnitEnum.getResultUnitEnumByCode(dictTree.getCode());
        List<PqScriptDtls> f = dtls.stream().filter(x -> "Freq".equals(x.getValueType())).collect(Collectors.toList());
        switch (resultUnitEnumByCode) {
            /**
             * 频率
             */
            case FREQ:
                dtlType.setScriptTypeName("三项电压不平衡和叠加多次谐波和间谐波对" + dictTree.getName() + "=" + f.get(0).getValue() + ResultUnitEnum.FREQ.getUnit() + "的影响");
                break;
            /**
             * 电压
             */
            case V_RELATIVE:
            case V_ABSOLUTELY:
                String unit;
                if (isValueType) {
                    unit = ResultUnitEnum.V_RELATIVE.getUnit();
                } else {
                    unit = ResultUnitEnum.V_ABSOLUTELY.getUnit();
                }
                List<PqScriptDtls> v = dtls.stream().filter(x -> "VOL".equals(x.getValueType())).collect(Collectors.toList());
                dtlType.setScriptTypeName("三项电压不平衡和叠加多次谐波和间谐波对" + dictTree.getName() + "=" + v.get(0).getValue() + unit + "的影响");
                break;
            /**
             * 电流
             */
            case I_RELATIVE:
            case I_ABSOLUTELY:
                break;
            /**
             * 谐波电压
             */
            case HV:
                break;
            /**
             * 谐波电流
             */
            case HI:
                break;
            /**
             * 间谐波电压
             */
            case HSV:
                break;
            /**
             * 间谐波电流
             */
            case HSI:
                break;
            /**
             * 三相电压不平衡度
             */
            case IMBV:
                break;
            /**
             * 三相电流不平衡度
             */
            case IMBA:
                break;
            /**
             * 谐波有功功率
             */
            case HP:
                break;
            /**
             * 闪变
             */
            case F:
                break;
            /**
             * 暂态
             */
            case VOLTAGE_MAG:
            case VOLTAGE_DUR:
                break;
            default:
                break;
        }
    }

    private void freqAndHarmAndInHarmScriptTypeName(List<PqScriptDtls> dtls, DictTree dictTree, Boolean isValueType, TreeDataVO dtlType) {
        ResultUnitEnum resultUnitEnumByCode = ResultUnitEnum.getResultUnitEnumByCode(dictTree.getCode());
        switch (resultUnitEnumByCode) {
            /**
             * 频率
             */
            case FREQ:
                break;
            /**
             * 电压
             */
            case V_RELATIVE:
            case V_ABSOLUTELY:
                String unit;
                if (isValueType) {
                    unit = ResultUnitEnum.V_RELATIVE.getUnit();
                } else {
                    unit = ResultUnitEnum.V_ABSOLUTELY.getUnit();
                }
                List<PqScriptDtls> v = dtls.stream().filter(x -> "VOL".equals(x.getValueType())).collect(Collectors.toList());
                List<PqScriptDtls> f = dtls.stream().filter(x -> "Freq".equals(x.getValueType())).collect(Collectors.toList());
                dtlType.setScriptTypeName("频率：" + f.get(0).getValue() + ResultUnitEnum.FREQ.getUnit() + "，叠加多次谐波和间谐波对" + dictTree.getName() + "=" + v.get(0).getValue() + unit + "的影响");
                break;
            /**
             * 电流
             */
            case I_RELATIVE:
            case I_ABSOLUTELY:
                break;
            /**
             * 谐波电压
             */
            case HV:
                break;
            /**
             * 谐波电流
             */
            case HI:
                break;
            /**
             * 间谐波电压
             */
            case HSV:
                break;
            /**
             * 间谐波电流
             */
            case HSI:
                break;
            /**
             * 三相电压不平衡度
             */
            case IMBV:
                break;
            /**
             * 三相电流不平衡度
             */
            case IMBA:
                break;
            /**
             * 谐波有功功率
             */
            case HP:
                break;
            /**
             * 闪变
             */
            case F:
                break;
            /**
             * 暂态
             */
            case VOLTAGE_MAG:
            case VOLTAGE_DUR:
                break;
            default:
                break;
        }
    }

    @Override
    public ResultVO resultData(ResultParam param) {
        StorageParam storage = new StorageParam();
        storage.setIndex(param.getIndex());
        storage.setScriptId(param.getScriptId());
        storage.setDevId(param.getDevId());
        storage.setDevNum(param.getDevNum());
        storage.setCode(param.getCode());
        DictTree dictTree = dictTreeService.getById(param.getScriptType());
        List<Double> harmNum = new ArrayList<>();
        if (HARMONIC_TYPE_CODE.contains(dictTree.getCode())) {
            List<PqScriptCheckData> list = pqScriptCheckDataService.list(new MPJLambdaWrapper<PqScriptCheckData>()
                    .distinct()
                    .select(PqScriptCheckData::getHarmNum)
                    .eq(PqScriptCheckData::getScriptId, param.getScriptId())
                    .isNotNull(PqScriptCheckData::getHarmNum)
                    .eq(PqScriptCheckData::getScriptIndex, param.getIndex())
            );
            harmNum = list.stream().sorted(Comparator.comparing(PqScriptCheckData::getHarmNum))
                    .map(PqScriptCheckData::getHarmNum).distinct().collect(Collectors.toList());
        }
        ResultVO resultVO = new ResultVO();
        if (CollUtil.isEmpty(harmNum)) {
            resultVO.setRawData(simAndDigNonHarmonicService.listNonHarmData(storage));
            resultVO.setResultData(simAndDigNonHarmonicService.listNonHarmResultData(storage));
        } else {
            storage.setHarmNum(harmNum);
            resultVO.setRawData(simAndDigHarmonicService.listHarmData(storage));
            resultVO.setResultData(simAndDigHarmonicService.listHarmResultData(storage));
        }
        return resultVO;
    }

    @Override
    public ResultVO resultDataForReport(ResultParam param) {
        StorageParam storage = new StorageParam();
        storage.setIndex(param.getIndex());
        storage.setScriptId(param.getScriptId());
        storage.setDevId(param.getDevId());
        storage.setDevNum(param.getDevNum());
        storage.setCode(param.getCode());
        DictTree dictTree = dictTreeService.getById(param.getScriptType());
        List<Double> harmNum = new ArrayList<>();
        if (HARMONIC_TYPE_CODE.contains(dictTree.getCode())) {
            List<PqScriptCheckData> list = pqScriptCheckDataService.list(new MPJLambdaWrapper<PqScriptCheckData>()
                    .distinct()
                    .select(PqScriptCheckData::getHarmNum)
                    .eq(PqScriptCheckData::getScriptId, param.getScriptId())
                    .isNotNull(PqScriptCheckData::getHarmNum)
                    .eq(PqScriptCheckData::getScriptIndex, param.getIndex())
            );
            harmNum = list.stream().sorted(Comparator.comparing(PqScriptCheckData::getHarmNum))
                    .map(PqScriptCheckData::getHarmNum).distinct().collect(Collectors.toList());
        }
        ResultVO resultVO = new ResultVO();
        if (CollUtil.isEmpty(harmNum)) {
            resultVO.setResultData(simAndDigNonHarmonicService.listNonHarmResultData(storage));
        } else {
            storage.setHarmNum(harmNum);
            resultVO.setResultData(simAndDigHarmonicService.listHarmResultData(storage));
        }
        return resultVO;
    }

    @Override
    public void exportRawData(ResultParam param) {
        StorageParam storage = new StorageParam();
        storage.setIndex(param.getIndex());
        storage.setScriptId(param.getScriptId());
        storage.setDevId(param.getDevId());
        storage.setDevNum(param.getDevNum());
        storage.setCode(param.getCode());
        DictTree dictTree = dictTreeService.getById(param.getScriptType());
        List<Double> harmNum = new ArrayList<>();
        if (HARMONIC_TYPE_CODE.contains(dictTree.getCode())) {
            List<PqScriptCheckData> list = pqScriptCheckDataService.list(new MPJLambdaWrapper<PqScriptCheckData>()
                    .distinct()
                    .select(PqScriptCheckData::getHarmNum)
                    .eq(PqScriptCheckData::getScriptId, param.getScriptId())
                    .isNotNull(PqScriptCheckData::getHarmNum)
                    .eq(PqScriptCheckData::getScriptIndex, param.getIndex())
            );
            harmNum = list.stream().sorted(Comparator.comparing(PqScriptCheckData::getHarmNum))
                    .map(PqScriptCheckData::getHarmNum).distinct().collect(Collectors.toList());
        }

        Map<String, List<RawDataVO>> rawDataMap = null;
        if (CollUtil.isEmpty(harmNum)) {
            rawDataMap = simAndDigNonHarmonicService.listNonHarmData(storage);
        } else {
            storage.setHarmNum(harmNum);
            rawDataMap = simAndDigHarmonicService.listHarmData(storage);
        }

        if (ObjectUtil.isNotEmpty(rawDataMap)) {
            List<Map<String, Object>> sheetsList = new ArrayList<>();
            rawDataMap.forEach((k, v) -> {
                HashMap sheet = new HashMap<>();
                ExportParams exportParams = new ExportParams();
                exportParams.setSheetName(k);
                sheet.put("title", exportParams);
                if (isTPhase(v)) {
                    List<RawDataExcel.TRawDataExcel> rawDataExcelList = BeanUtil.copyToList(v, RawDataExcel.TRawDataExcel.class);
                    sheet.put("data", rawDataExcelList);
                    sheet.put("entity", RawDataExcel.TRawDataExcel.class);
                } else {
                    List<RawDataExcel.NotTRawDataExcel> rawDataExcelList = BeanUtil.copyToList(v, RawDataExcel.NotTRawDataExcel.class);
                    sheet.put("data", rawDataExcelList);
                    sheet.put("entity", RawDataExcel.NotTRawDataExcel.class);
                }
                sheetsList.add(sheet);
            });
            ExcelUtil.exportExcel("原始数据.xlsx", sheetsList);
        } else {
            throw new BusinessException(DetectionResponseEnum.RAW_DATA_NOT_EXIST);
        }
    }

    @Override
    @Transactional
    public void changeErrorSystem(ResultParam.ChangeErrorSystemParam param) {
        DictData dictData = dictDataService.getDictDataById(param.getPatternId());
        if (PatternEnum.CONTRAST.getValue().equals(dictData.getCode())) {
            this.createTempResultTable(param.getCode() + "_temp", true);
            this.contrastCalculateResult(param.getPlanId(), param.getCode() + "_temp", param.getErrorSysId(), param.getDeviceId(), false, param.getDataRuleId());
        } else {
            this.createTempResultTable(param.getCode() + "_temp", false);
            this.simAndDigCalculateResult(param.getPlanId(), param.getScriptId(), param.getCode() + "_temp", param.getErrorSysId(), param.getDeviceId(), param.getDataRuleId());
        }
    }

    @Override
    public void deleteTempTable(String code) {
        code = code + "_temp";
        this.dropTempResultTable(code);
    }

    @Override
    public void reCalculate(ResultParam.ChangeErrorSystemParam param) {
        DictData dictData = dictDataService.getDictDataById(param.getPatternId());
        if (PatternEnum.CONTRAST.getValue().equals(dictData.getCode())) {
            this.contrastCalculateResult(param.getPlanId(), param.getCode(), param.getErrorSysId(), param.getDeviceId(), true, param.getDataRuleId());
        } else {
            this.simAndDigCalculateResult(param.getPlanId(), param.getScriptId(), param.getCode(), param.getErrorSysId(), param.getDeviceId(), param.getDataRuleId());
        }
    }

    /**
     * 获取某测试大项的检测项内容，主要针对表格需要填充的值
     * 注：虽然测试项区是三相，他们的标准值可能不同，但是误差范围是一致的
     * 1、区分额定条件、单影响量条件、单影响量条件
     * 2、区分scriptIndex
     * 3、区分谐波次数（有必要的情况下）
     *
     * @param dtlDataVOList 检测项脚本
     * @param planCode      计划编号
     * @param devId         被检设备id
     * @param lineNo        回路号
     * @param tableKeys     表格key
     */
    @Override
    public SingleTestResult getFinalContent(List<PqScriptDtlDataVO> dtlDataVOList, String planCode, String devId, Integer lineNo, List<String> tableKeys) {
        SingleTestResult singleTestResult = new SingleTestResult();
        // 用 LinkedHashMap 保住下方按 AffectEnum.sort + Script_Index 排好的影响量小节顺序，一路保到下游 fillContentInTemplate 按 entrySet 顺序消费
        Map<String/*subType影响量，额定或某单影响量*/, List<Map<String/*误差范围*/, List<Map<String/*填充key*/, String/*实际值*/>>>>> finalContent = new LinkedHashMap<>();
        if (CollUtil.isNotEmpty(dtlDataVOList)) {
            // 首先区分测试条件；分组前先按 AffectEnum.sort（额定→单影响→多影响）排序，同档内再按 Script_Index 升序，
            // 收进 LinkedHashMap，使各影响量小节顺序固定为：额定、单影响量、多影响量
            Map<String, List<PqScriptDtlDataVO>> subTypeMap = dtlDataVOList.stream()
                    .sorted(Comparator
                            .comparingInt((PqScriptDtlDataVO v) -> {
                                AffectEnum ae = AffectEnum.getByKey(v.getScriptSubType());
                                return ae == null ? Integer.MAX_VALUE : ae.getSort(); // 识别不了的 subType 沉底
                            })
                            .thenComparingInt(v -> v.getScriptIndex() == null ? Integer.MAX_VALUE : v.getScriptIndex()))
                    .collect(Collectors.groupingBy(PqScriptDtlDataVO::getScriptSubType, LinkedHashMap::new, Collectors.toList()));
            subTypeMap.forEach((subType, scriptDtlDataVOList) -> {
                AffectEnum affectEnum = AffectEnum.getByKey(subType);
                if (Objects.nonNull(affectEnum)) {
                    String scriptCode = scriptDtlDataVOList.get(0).getScriptCode();
                    String scriptId = scriptDtlDataVOList.get(0).getScriptId();
                    PowerIndexEnum indexEnum = PowerIndexEnum.getByKey(scriptCode);
                    if (Objects.nonNull(indexEnum)) {
                        String affectName = affectEnum.getDesc().replaceAll("XX", indexEnum.getDesc());
                        // 同一个影响量下，获取出子脚本信息
                        List<Integer> indexList = scriptDtlDataVOList.stream().map(PqScriptDtlDataVO::getScriptIndex).distinct().collect(Collectors.toList());
                        List<PqScriptCheckData> scriptCheckDataList = pqScriptCheckDataService.listCheckData(scriptId, indexList);
                        List<String> valueTypeList = scriptCheckDataList.stream().map(PqScriptCheckData::getValueType).distinct().collect(Collectors.toList());
                        if (PowerIndexEnum.P.getKey().equalsIgnoreCase(scriptCode)) {
                            SingleNonHarmParam param = new SingleNonHarmParam(planCode, devId, lineNo, valueTypeList, indexList);
                            List<SimAndDigNonHarmonicResult> powerResults = simAndDigNonHarmonicService.queryBySortListWithAdTypeCode(param);
                            List<Map<String, String>> keyFillMapList = PowerResultAssembler.assembleRows(powerResults, scriptDtlDataVOList);
                            if (CollUtil.isEmpty(keyFillMapList)) {
                                log.warn("生成功率类表格数据跳过，结果表数据为空，planCode={}, devId={}, lineNo={}, scriptCode={}, scriptIndexList={}",
                                        planCode, devId, lineNo, scriptCode, indexList);
                                return;
                            }
                            Map<String, List<Map<String, String>>> errorScoperMap = keyFillMapList.stream()
                                    .collect(Collectors.groupingBy(map -> map.get(ItemReportKeyEnum.ERROR_SCOPE.getKey()), LinkedHashMap::new, Collectors.toList()));
                            List<Map<String, List<Map<String, String>>>> errorList = new ArrayList<>();
                            errorList.add(errorScoperMap);
                            finalContent.put(affectName, errorList);
                            return;
                        }
                        if (PowerIndexEnum.ANGLE.getKey().equalsIgnoreCase(scriptCode)) {
                            SingleNonHarmParam param = new SingleNonHarmParam(planCode, devId, lineNo, valueTypeList, indexList);
                            List<SimAndDigNonHarmonicResult> angleResults = simAndDigNonHarmonicService.queryBySortListWithAdTypeCode(param);
                            List<Map<String, String>> keyFillMapList = AngleResultAssembler.assembleRows(angleResults);
                            if (CollUtil.isEmpty(keyFillMapList)) {
                                log.warn("生成基波相位类表格数据跳过，结果表数据为空，planCode={}, devId={}, lineNo={}, scriptCode={}, scriptIndexList={}",
                                        planCode, devId, lineNo, scriptCode, indexList);
                                return;
                            }
                            Map<String, List<Map<String, String>>> errorScoperMap = keyFillMapList.stream()
                                    .collect(Collectors.groupingBy(map -> map.get(ItemReportKeyEnum.ERROR_SCOPE.getKey()), LinkedHashMap::new, Collectors.toList()));
                            List<Map<String, List<Map<String, String>>>> errorList = new ArrayList<>();
                            errorList.add(errorScoperMap);
                            finalContent.put(affectName, errorList);
                            return;
                        }
                        if (PowerIndexEnum.IMBV.getKey().equalsIgnoreCase(scriptCode)
                                || PowerIndexEnum.IMBA.getKey().equalsIgnoreCase(scriptCode)) {
                            SingleNonHarmParam param = new SingleNonHarmParam(planCode, devId, lineNo, valueTypeList, indexList);
                            List<SimAndDigNonHarmonicResult> unbalanceResults = simAndDigNonHarmonicService.queryBySortListWithAdTypeCode(param);
                            List<Map<String, String>> keyFillMapList = UnbalanceResultAssembler.assembleRows(unbalanceResults);
                            if (CollUtil.isEmpty(keyFillMapList)) {
                                log.warn("生成不平衡度类表格数据跳过，结果表数据为空，planCode={}, devId={}, lineNo={}, scriptCode={}, scriptIndexList={}",
                                        planCode, devId, lineNo, scriptCode, indexList);
                                return;
                            }
                            Map<String, List<Map<String, String>>> errorScoperMap = keyFillMapList.stream()
                                    .collect(Collectors.groupingBy(map -> map.get(ItemReportKeyEnum.ERROR_SCOPE.getKey()), LinkedHashMap::new, Collectors.toList()));
                            List<Map<String, List<Map<String, String>>>> errorList = new ArrayList<>();
                            errorList.add(errorScoperMap);
                            finalContent.put(affectName, errorList);
                            return;
                        }
                        // 稍作区分，暂态的脚本同一个scriptIndex可以有两个指标，其余脚本每个checkData的valueType对应一个指标结果
                        if (PowerConstant.VOLTAGE.equalsIgnoreCase(scriptCode)) {
                            // 暂态的valueType通常只有2个，一个特征幅值，一个持续时间
                            List<Map<String, String>> keyFillMapList = new ArrayList<>();
                            for (Integer sort : indexList) {
                                SingleNonHarmParam param = new SingleNonHarmParam(planCode, devId, lineNo, valueTypeList, Collections.singletonList(sort));
                                List<SimAndDigNonHarmonicResult> nonHarmList = simAndDigNonHarmonicService.queryByCondition(param);
                                if (CollUtil.isEmpty(nonHarmList)) {
                                    log.warn("生成暂态类表格数据跳过，结果表数据为空，planCode={}, devId={}, lineNo={}, scriptCode={}, scriptIndex={}",
                                            planCode, devId, lineNo, scriptCode, sort);
                                    continue;
                                }
                                Map<String, String> keyFillMap = new HashMap<>(16);
                                if (fillVoltagePhaseData(nonHarmList, keyFillMap, tableKeys)) {
                                    keyFillMapList.add(keyFillMap);
                                }
                            }
                            if (CollUtil.isEmpty(keyFillMapList)) {
                                log.warn("生成暂态类表格数据跳过，当前脚本无可填充结果，planCode={}, devId={}, lineNo={}, scriptCode={}, scriptIndexList={}",
                                        planCode, devId, lineNo, scriptCode, indexList);
                                return;
                            }
                            // 需要对所有填充进行按误差范围分组
                            Map<String, List<Map<String, String>>> errorScoperMap = keyFillMapList.stream()
                                    .collect(Collectors.groupingBy(map -> map.get(ItemReportKeyEnum.ERROR_SCOPE.getKey())));
                            // 分组后，还需要针对特征幅值标准值进行一个升序
                            errorScoperMap.forEach((errorScope, maps) -> {
                                PubUtils.sortByDoubleValue(maps, ItemReportKeyEnum.STANDARD_MAG.getKey());
                            });
                            List<Map<String, List<Map<String, String>>>> errorList = new ArrayList<>();
                            errorList.add(errorScoperMap);
                            // 最后赋值返回
                            finalContent.put(affectName, errorList);
                        } else {
                            for (String valueType : valueTypeList) {
                                if (PowerConstant.TIME.contains(scriptCode)) {
                                    // 查询结果数据，经过上层处理谐波类此处的scriptIndex确保只有一个
                                    if (indexList.size() == 1) {
                                        // 获取谐波数据
                                        SingleNonHarmParam param = new SingleNonHarmParam(planCode, devId, lineNo, valueType, indexList.get(0));
                                        SimAndDigHarmonicResult singleResult = simAndDigHarmonicService.getSingleResult(param);
                                        if (Objects.isNull(singleResult)) {
                                            log.warn("生成谐波类表格数据跳过，结果表数据为空，planCode={}, devId={}, lineNo={}, scriptCode={}, valueType={}, scriptIndex={}",
                                                    planCode, devId, lineNo, scriptCode, valueType, indexList.get(0));
                                            continue;
                                        }
                                        // 注：如果ABC的标准值一致，则同步到standard中
                                        Map<Double, List<PqScriptCheckData>> checkDataHarmNumMap = scriptCheckDataList.stream().collect(Collectors.groupingBy(PqScriptCheckData::getHarmNum));
                                        List<Map<String, String>> keyFillMapList = new ArrayList<>();
                                        checkDataHarmNumMap.forEach((harmNum, dtlsList) -> {
                                            Map<String, String> keyFillMap = new HashMap<>();
                                            // 次数需要区分谐波&间谐波
                                            String time;
                                            if (harmNum % 1 == 0) {
                                                // 谐波，需要转为正数字符串
                                                time = String.valueOf(harmNum.intValue());
                                            } else {
                                                // 间谐波，保留小数位转为字符串
                                                time = String.format("%.1f", harmNum);
                                            }
                                            keyFillMap.put(ItemReportKeyEnum.TIME.getKey(), time);
                                            // 将间谐波次数取整1.5取2，2.5取3
                                            double timeDouble = Math.round(harmNum);
                                            int timeInt = (int) timeDouble;
                                            // 填充结果数据
                                            if (fillThreePhaseData(singleResult, timeInt, keyFillMap, scriptCode)) {
                                                fillHarmonicScriptStandard(keyFillMap, scriptCode, dtlsList);
                                                fillHarmonicPowerSourceSettings(keyFillMap, scriptCode, scriptDtlDataVOList);
                                                keyFillMapList.add(keyFillMap);
                                            }
                                        });
                                        if (CollUtil.isNotEmpty(keyFillMapList)) {
                                            // 按次数排序
                                            PubUtils.sortByDoubleValue(keyFillMapList, ItemReportKeyEnum.TIME.getKey());
                                            // 取出任意一次谐波数据的误差范围作为key
                                            String titleScope = keyFillMapList.get(0).get(ItemReportKeyEnum.ERROR_SCOPE.getKey());
                                            Map<String, List<Map<String, String>>> errorScoperMap = new HashMap<>();
                                            errorScoperMap.put(titleScope, keyFillMapList);
                                            List<Map<String, List<Map<String, String>>>> errorScoperMapList = new ArrayList<>();
                                            errorScoperMapList.add(errorScoperMap);
                                            finalContent.put(affectName, errorScoperMapList);
                                        }
                                    } else {
                                        log.error("生成谐波类表格数据失败，脚本配置不支持，请核实。");
                                        throw new BusinessException("生成谐波类表格数据失败，脚本配置不支持，请核实。");
                                    }
                                } else {
                                    // 非谐波的需要区分是否为ABC相还是T相
                                    if (PowerConstant.THREE_PHASE.contains(scriptCode)) {
                                        // 获取该三相的数据
                                        SingleNonHarmParam param = new SingleNonHarmParam(planCode, devId, lineNo, Collections.singletonList(valueType), indexList);
                                        List<SimAndDigNonHarmonicResult> nonHarmList = simAndDigNonHarmonicService.queryByCondition(param);
                                        if (CollUtil.isEmpty(nonHarmList)) {
                                            log.warn("生成三相类表格数据跳过，结果表数据为空，planCode={}, devId={}, lineNo={}, scriptCode={}, valueType={}, scriptIndexList={}",
                                                    planCode, devId, lineNo, scriptCode, valueType, indexList);
                                            continue;
                                        }
                                        List<Map<String, String>> keyFillMapList = new ArrayList<>();
                                        for (SimAndDigNonHarmonicResult SimAndDigNonHarmonicResult : nonHarmList) {
                                            Map<String, String> keyFillMap = new HashMap<>(16);
                                            if (fillThreePhaseData(SimAndDigNonHarmonicResult, null, keyFillMap, scriptCode)) {
                                                keyFillMapList.add(keyFillMap);
                                            }
                                        }
                                        if (CollUtil.isNotEmpty(keyFillMapList)) {
                                            // 需要对所有的填充进行按误差范围分组
                                            Map<String, List<Map<String, String>>> errorScoperMap = keyFillMapList.stream()
                                                    .collect(Collectors.groupingBy(map -> map.get(ItemReportKeyEnum.ERROR_SCOPE.getKey())));
                                            // 分组后，还需要针对标准值进行一个升序
                                            errorScoperMap.forEach((errorScope, maps) -> {
                                                PubUtils.sortByDoubleValue(maps, ItemReportKeyEnum.STANDARD.getKey());
                                            });
                                            List<Map<String, List<Map<String, String>>>> errorList = new ArrayList<>();
                                            errorList.add(errorScoperMap);
                                            // 最后赋值返回
                                            finalContent.put(affectName, errorList);
                                        }
                                    } else {
                                        // 非三相且非暂态，通常只有一个数据，所以直接赋值即可
                                        List<Map<String, String>> keyFillMapList = new ArrayList<>();
                                        SingleNonHarmParam param = new SingleNonHarmParam(planCode, devId, lineNo, Collections.singletonList(valueType), indexList);
                                        List<SimAndDigNonHarmonicResult> nonHarmList = simAndDigNonHarmonicService.queryByCondition(param);
                                        if (CollUtil.isEmpty(nonHarmList)) {
                                            log.warn("生成T相类表格数据跳过，结果表数据为空，planCode={}, devId={}, lineNo={}, scriptCode={}, valueType={}, scriptIndexList={}",
                                                    planCode, devId, lineNo, scriptCode, valueType, indexList);
                                            continue;
                                        }
                                        for (SimAndDigNonHarmonicResult simAndDigNonHarmonicResult : nonHarmList) {
                                            Map<String, String> keyFillMap = new HashMap<>(8);
                                            if (fillTPhaseData(simAndDigNonHarmonicResult, null, keyFillMap)) {
                                                keyFillMapList.add(keyFillMap);
                                            }
                                        }
                                        if (CollUtil.isNotEmpty(keyFillMapList)) {
                                            // 需要对所有填充进行按误差范围分组
                                            Map<String, List<Map<String, String>>> errorScoperMap = keyFillMapList.stream()
                                                    .collect(Collectors.groupingBy(map -> map.get(ItemReportKeyEnum.ERROR_SCOPE.getKey())));
                                            // 分组后，还需要针对特征幅值标准值进行一个升序
                                            errorScoperMap.forEach((errorScope, maps) -> {
                                                PubUtils.sortByDoubleValue(maps, ItemReportKeyEnum.STANDARD.getKey());
                                            });
                                            List<Map<String, List<Map<String, String>>>> errorList = new ArrayList<>();
                                            errorList.add(errorScoperMap);
                                            // 最后赋值返回
                                            finalContent.put(affectName, errorList);
                                        }
                                    }
                                }
                            }
                        }
                    } else {
                        log.error("未找到合适的脚本信息");
                    }
                } else {
                    log.error("未找到合适的测量条件");
                }
            });
        }
        // 返回之前做下总结性判断
        singleTestResult.setQualified(judgeQualified(finalContent));
        singleTestResult.setDetail(finalContent);
        return singleTestResult;
    }


    /**
     * 三相的相关数据处理
     * 包含：谐波、间谐波、电压、电流、功率、闪变
     *
     * @param singleResult 可能是谐波类，也有可能是电压电流，需要区分下结果
     * @param timeInt      谐波类需要传指定次数
     * @param keyFillMap   待填充的集合Map
     */
    private boolean fillThreePhaseData(Object singleResult, Integer timeInt, Map<String, String> keyFillMap, String scriptCode) {
//        boolean isCurrentI = "I".equalsIgnoreCase(scriptCode);
        DetectionData tempA = getResultData(singleResult, timeInt, PowerConstant.PHASE_A);
        DetectionData tempB = getResultData(singleResult, timeInt, PowerConstant.PHASE_B);
        DetectionData tempC = getResultData(singleResult, timeInt, PowerConstant.PHASE_C);
        if (Objects.isNull(tempA) && Objects.isNull(tempB) && Objects.isNull(tempC)) {
            return false;
        }
        // 待填充Key
        String standard = "/", standardA = "/", standardB = "/", standardC = "/",
                testA = "/", testB = "/", testC = "/",
                errorA = "/", errorB = "/", errorC = "/",
                resultA = "/", resultB = "/", resultC = "/", result = "/",
                errorScope = "/", unit = "", scriptDetail = "/";

        if (Objects.nonNull(tempA)) {
            standardA = PubUtils.doubleRoundStr(4, tempA.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempA.getResultData());
            testA = PubUtils.doubleRoundStr(4, tempA.getData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempA.getData());
            if (Objects.nonNull(tempA.getErrorData())) {
                errorA = PubUtils.doubleRoundStr(4, tempA.getErrorData().doubleValue());
            }
            resultA = tempA.getIsData() == 1 ? "合格" : tempA.getIsData() == 2 ? "不合格" : "/";
            errorScope = tempA.getRadius() == null ? "/" : tempA.getRadius();
            unit = tempA.getUnit() == null ? "" : tempA.getUnit();
            standard = PubUtils.doubleRoundStr(4, tempA.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempA.getResultData());
        }
        if (Objects.nonNull(tempB)) {
            standardB = PubUtils.doubleRoundStr(4, tempB.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempB.getResultData());
            testB = PubUtils.doubleRoundStr(4, tempB.getData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempB.getData());
            if (Objects.nonNull(tempB.getErrorData())) {
                errorB = PubUtils.doubleRoundStr(4, tempB.getErrorData().doubleValue());
            }
            resultB = tempB.getIsData() == 1 ? "合格" : tempB.getIsData() == 2 ? "不合格" : "/";
            if (errorScope.equals("/")) {
                errorScope = tempB.getRadius() == null ? "/" : tempB.getRadius();
            }
            if (StrUtil.isBlank(unit)) {
                unit = tempB.getUnit() == null ? "" : tempB.getUnit();
            }
            if (standard.equals("/")) {
                standard = PubUtils.doubleRoundStr(4, tempB.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempB.getResultData());
            }
        }
        if (Objects.nonNull(tempC)) {
            standardC = PubUtils.doubleRoundStr(4, tempC.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempC.getResultData());
            testC = PubUtils.doubleRoundStr(4, tempC.getData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempC.getData());
            if (Objects.nonNull(tempC.getErrorData())) {
                errorC = PubUtils.doubleRoundStr(4, tempC.getErrorData().doubleValue());
            }
            resultC = tempC.getIsData() == 1 ? "合格" : tempC.getIsData() == 2 ? "不合格" : "/";
            if (errorScope.equals("/")) {
                errorScope = tempC.getRadius() == null ? "/" : tempC.getRadius();
            }
            if (StrUtil.isBlank(unit)) {
                unit = tempC.getUnit() == null ? "" : tempC.getUnit();
            }
            if (standard.equals("/")) {
                standard = PubUtils.doubleRoundStr(4, tempC.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempC.getResultData());
            }
        }
        // 浙江脚本特殊处理
//        if (isCurrentI) {
//            resultA = "/";
//            resultB = "/";
//            resultC = "/";
//        }
        if (standardA.equals(standardB) && standardA.equals(standardC)) {
            standard = standardA;
        }
        // 处理脚本输出
        scriptDetail = dealScriptDetail(scriptCode, standard);
        keyFillMap.put(ItemReportKeyEnum.SCRIPT_DETAIL.getKey(), scriptDetail);
        // 标准值
        keyFillMap.put(ItemReportKeyEnum.STANDARD.getKey(), standard);
        keyFillMap.put(ItemReportKeyEnum.STANDARD_A.getKey(), standardA);
        keyFillMap.put(ItemReportKeyEnum.STANDARD_B.getKey(), standardB);
        keyFillMap.put(ItemReportKeyEnum.STANDARD_C.getKey(), standardC);
        // 测试值
        keyFillMap.put(ItemReportKeyEnum.TEST_A.getKey(), testA);
        keyFillMap.put(ItemReportKeyEnum.TEST_B.getKey(), testB);
        keyFillMap.put(ItemReportKeyEnum.TEST_C.getKey(), testC);
        // 误差值
        keyFillMap.put(ItemReportKeyEnum.ERROR_A.getKey(), errorA);
        keyFillMap.put(ItemReportKeyEnum.ERROR_B.getKey(), errorB);
        keyFillMap.put(ItemReportKeyEnum.ERROR_C.getKey(), errorC);
        // 结果
        keyFillMap.put(ItemReportKeyEnum.RESULT_A.getKey(), resultA);
        keyFillMap.put(ItemReportKeyEnum.RESULT_B.getKey(), resultB);
        keyFillMap.put(ItemReportKeyEnum.RESULT_C.getKey(), resultC);
        if (resultA.equals("不合格") || resultB.equals("不合格") || resultC.equals("不合格")) {
            result = "不合格";
        } else if (!resultA.equals("/") || !resultB.equals("/") || !resultC.equals("/")) {
            result = "合格";
        }
        keyFillMap.put(ItemReportKeyEnum.RESULT.getKey(), result);
        errorScope = dealErrorScope(errorScope).concat(unit);
        keyFillMap.put(ItemReportKeyEnum.ERROR_SCOPE.getKey(), errorScope);
        if (PowerIndexEnum.HI.getKey().equalsIgnoreCase(scriptCode)) {
            fillBaseCurrentData(singleResult, keyFillMap);
        }
        return true;
    }

    /**
     * HI 新模板明细显示谐波电流含有率，装配期需要同一条谐波结果中的三相基波电流作为分母。
     */
    private void fillBaseCurrentData(Object singleResult, Map<String, String> keyFillMap) {
        putBaseCurrent(singleResult, PowerConstant.PHASE_A, ItemReportKeyEnum.BASE_CURRENT_A.getKey(), keyFillMap);
        putBaseCurrent(singleResult, PowerConstant.PHASE_B, ItemReportKeyEnum.BASE_CURRENT_B.getKey(), keyFillMap);
        putBaseCurrent(singleResult, PowerConstant.PHASE_C, ItemReportKeyEnum.BASE_CURRENT_C.getKey(), keyFillMap);
    }

    private void putBaseCurrent(Object singleResult, String phase, String testKey, Map<String, String> keyFillMap) {
        DetectionData base = getResultData(singleResult, 1, phase);
        keyFillMap.put(testKey, formatBaseCurrent(base == null ? null : base.getData()));
    }

    private String formatBaseCurrent(Double value) {
        String formatted = value == null ? "" : PubUtils.doubleRoundStr(4, value);
        return formatted == null ? "" : formatted;
    }

    /**
     * HI 的标准源输出值在云南模板中展示含有率，优先沿用脚本下发的百分比值。
     */
    private void fillHarmonicScriptStandard(Map<String, String> keyFillMap, String scriptCode, List<PqScriptCheckData> checkDataList) {
        if (!PowerIndexEnum.HI.getKey().equalsIgnoreCase(scriptCode) || CollUtil.isEmpty(checkDataList)) {
            return;
        }
        if (StrUtil.isNotBlank(keyFillMap.get(ItemReportKeyEnum.STANDARD_RATE.getKey()))) {
            return;
        }
        PqScriptCheckData standard = firstCheckValue(checkDataList);
        if (standard == null || standard.getValue() == null) {
            return;
        }
        String value = PubUtils.doubleRoundStr(4, standard.getValue());
        if (value != null) {
            keyFillMap.put(ItemReportKeyEnum.STANDARD_RATE.getKey(), value);
        }
    }

    private PqScriptCheckData firstCheckValue(List<PqScriptCheckData> checkDataList) {
        for (String phase : Arrays.asList(PowerConstant.PHASE_A, PowerConstant.PHASE_B, PowerConstant.PHASE_C)) {
            for (PqScriptCheckData data : checkDataList) {
                if (phase.equalsIgnoreCase(data.getPhase()) && data.getValue() != null) {
                    return data;
                }
            }
        }
        return checkDataList.stream().filter(data -> data.getValue() != null).findFirst().orElse(null);
    }

    /**
     * HP 新模板表头需要基波电压/基波电流设置值，来源是同一 scriptIndex 的 VOL/CUR 脚本明细。
     */
    private void fillHarmonicPowerSourceSettings(Map<String, String> keyFillMap, String scriptCode,
                                                 List<? extends PqScriptDtls> scriptDetails) {
        if (!PowerIndexEnum.HP.getKey().equalsIgnoreCase(scriptCode) || CollUtil.isEmpty(scriptDetails)) {
            return;
        }
        putScriptSetting(keyFillMap, ItemReportKeyEnum.STANDARD_V.getKey(), firstScriptSetting(scriptDetails, "VOL"));
        putScriptSetting(keyFillMap, ItemReportKeyEnum.STANDARD_I.getKey(), firstScriptSetting(scriptDetails, "CUR"));
    }

    private void putScriptSetting(Map<String, String> keyFillMap, String key, PqScriptDtls detail) {
        if (detail == null || detail.getValue() == null || StrUtil.isNotBlank(keyFillMap.get(key))) {
            return;
        }
        String value = PubUtils.doubleRoundStr(4, detail.getValue());
        if (StrUtil.isNotBlank(value)) {
            keyFillMap.put(key, value);
        }
    }

    private PqScriptDtls firstScriptSetting(List<? extends PqScriptDtls> scriptDetails, String valueType) {
        for (String phase : Arrays.asList(PowerConstant.PHASE_A, PowerConstant.PHASE_B, PowerConstant.PHASE_C)) {
            for (PqScriptDtls detail : scriptDetails) {
                if (valueType.equalsIgnoreCase(detail.getValueType())
                        && phase.equalsIgnoreCase(detail.getPhase())
                        && detail.getValue() != null) {
                    return detail;
                }
            }
        }
        return scriptDetails.stream()
                .filter(detail -> valueType.equalsIgnoreCase(detail.getValueType()) && detail.getValue() != null)
                .findFirst()
                .orElse(null);
    }

    /**
     * 针对浙江杭州处理脚本输出细节，todo... 需要更改更合理的方式，现在算是写死的了部分
     * 目前浙江这边就是（间）谐波电压/电流
     */
    private String dealScriptDetail(String scriptCode, String standard) {
        String scriptDetail = "";
        PowerIndexEnum powerIndexEnum = PowerIndexEnum.getByKey(scriptCode);
        if (powerIndexEnum != null) {
            switch (powerIndexEnum) {
                case HV:
                case HSV:
                    // 注：基波电压幅值57.74V，基波频率50.0Hz。
                    scriptDetail = "注：基波电压幅值57.74V，基波频率50.0Hz。";
                    break;
                case HI:
                    // 电流是幅值，需要与5A得出百分比
                    try {
                        String temp = PubUtils.doubleRoundStr(1, (Double.parseDouble(standard) / 5.0) * 100);
                        scriptDetail = "注：基波电流幅值5.000A，基波频率50.0Hz,各次谐波电流含有率均为" + temp + "%。";
                    } catch (Exception e) {
                        log.error("dealScriptDetail error:{}", e);
                    }
                    break;
                case HSI:
                    // 电流是幅值，需要与5A得出百分比
                    try {
                        String temp = PubUtils.doubleRoundStr(1, (Double.parseDouble(standard) / 5.0) * 100);
                        scriptDetail = "注：基波电流幅值5.000A，基波频率50.0Hz,各次间谐波电流含有率均为" + temp + "%。";
                    } catch (Exception e) {
                        log.error("dealScriptDetail error:{}", e);
                    }
                    break;
                default:
                    break;
            }
        }
        return scriptDetail;
    }


    /**
     * T相的相关数据处理，非暂态数据
     * 包含：三相电压/电流不平衡度、频率，其中三相电压/电流实际ABC中存了正序/负序/零序电压
     *
     * @param singleResult 可能是谐波类，也有可能是电压电流，需要区分下结果
     * @param timeInt      谐波类需要传指定次数
     * @param keyFillMap   待填充的集合Map
     */
    private boolean fillTPhaseData(Object singleResult, Integer timeInt, Map<String, String> keyFillMap) {
        String standard = "/", test = "/", error = "/", result = "/", errorScope = "/", unit = "";
        DetectionData tempT = getResultData(singleResult, timeInt, PowerConstant.PHASE_T);
        if (Objects.isNull(tempT)) {
            return false;
        }
        standard = PubUtils.doubleRoundStr(4, tempT.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempT.getResultData());
        test = PubUtils.doubleRoundStr(4, tempT.getData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempT.getData());
        if (Objects.nonNull(tempT.getErrorData())) {
            error = PubUtils.doubleRoundStr(4, tempT.getErrorData().doubleValue());
        }
        result = tempT.getIsData() == 1 ? "合格" : tempT.getIsData() == 2 ? "不合格" : "/";
        unit = tempT.getUnit() == null ? "" : tempT.getUnit();
        errorScope = tempT.getRadius() == null ? "/" : tempT.getRadius();
        keyFillMap.put(ItemReportKeyEnum.STANDARD.getKey(), standard);
        keyFillMap.put(ItemReportKeyEnum.TEST.getKey(), test);
        keyFillMap.put(ItemReportKeyEnum.ERROR.getKey(), error);
        keyFillMap.put(ItemReportKeyEnum.RESULT.getKey(), result);
        errorScope = dealErrorScope(errorScope).concat(unit);
        keyFillMap.put(ItemReportKeyEnum.ERROR_SCOPE.getKey(), errorScope);
        return true;
    }

    /**
     * 针对暂态的数据填充
     *
     * @param nonHarmList 暂态的结果集
     * @param keyFillMap  待填充的集合Map
     * @param tableKeys   模板表格中的key
     */
    private boolean fillVoltagePhaseData(List<SimAndDigNonHarmonicResult> nonHarmList, Map<String, String> keyFillMap, List<String> tableKeys) {
        String standardMag = "/", standardDur = "/",
                testMag = "/", testDur = "/",
                errorMag = "/", errorDur = "/",
                resultMag = "/", resultDur = "/", result,
                errorScope, errorScopeMag = "/", errorScopeDur = "/",
                unitMag = "", unitDur = "";
        boolean hasData = false;
        for (SimAndDigNonHarmonicResult adNonHarmonicResult : nonHarmList) {
            DetectionData tempT = getResultData(adNonHarmonicResult, null, PowerConstant.PHASE_T);
            if (Objects.isNull(tempT)) {
                continue;
            }
            hasData = true;
            // 需要判断adNonHarmonicResult是特征幅值还是持续时间
            String adType = adNonHarmonicResult.getAdType();
            DictTree temp = dictTreeService.getById(adType);
            if (temp.getCode().equalsIgnoreCase("MAG")) {
                // 特征幅值
                standardMag = PubUtils.doubleRoundStr(4, tempT.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempT.getResultData());
                testMag = PubUtils.doubleRoundStr(4, tempT.getData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempT.getData());
                if (Objects.nonNull(tempT.getErrorData())) {
                    errorMag = PubUtils.doubleRoundStr(4, tempT.getErrorData().doubleValue());
                }
                resultMag = tempT.getIsData() == 1 ? "合格" : tempT.getIsData() == 2 ? "不合格" : "/";
                unitMag = tempT.getUnit();
                errorScopeMag = tempT.getRadius();
            } else if (temp.getCode().equalsIgnoreCase("DUR")) {
                // 持续时间，需要注意时间单位处理，默认是秒
                String timeUnit = "s";
                for (String tableKey : tableKeys) {
                    if (tableKey.contains("standardDur")) {
                        //截取单位
                        String[] tempStr = tableKey.split(StrPool.UNDERLINE);
                        if (tempStr.length > 1) {
                            if (tempStr[1].equalsIgnoreCase("ms")) {
                                timeUnit = "ms";
                            }
                        }
                        break;
                    }
                }
                if (Objects.nonNull(tempT.getResultData())) {
                    standardDur = PubUtils.doubleRoundStr(4, tempT.getResultData());
                }
                if (Objects.nonNull(tempT.getData())) {
                    testDur = PubUtils.doubleRoundStr(4, tempT.getData());
                }
                if (Objects.nonNull(tempT.getErrorData())) {
                    errorDur = PubUtils.doubleRoundStr(4, tempT.getErrorData().doubleValue());
                }
                if (Objects.nonNull(tempT.getIsData())) {
                    resultDur = tempT.getIsData() == 1 ? "合格" : "不合格";
                }
                if (StrUtil.isNotBlank(tempT.getUnit())) {
                    unitDur = tempT.getUnit();
                }
                if (StrUtil.isNotBlank(tempT.getRadius())) {
                    errorScopeDur = tempT.getRadius();
                }
                if (timeUnit.equalsIgnoreCase("ms")) {
                    // 如果是ms，上述的一些数据需要重新处理
                    if (!standardDur.equalsIgnoreCase("/")) {
                        standardDur = PubUtils.doubleRoundStr(4, Double.parseDouble(standardDur) * 1000);
                    }
                    if (!testDur.equalsIgnoreCase("/")) {
                        testDur = PubUtils.doubleRoundStr(4, Double.parseDouble(testDur) * 1000);
                    }
                    if (!errorDur.equalsIgnoreCase("/")) {
                        errorDur = PubUtils.doubleRoundStr(4, Double.parseDouble(errorDur) * 1000);
                    }
                    if (!errorScopeDur.equalsIgnoreCase("/")) {
                        if (errorScopeDur.contains("~")) {
                            String[] tempStr = errorScopeDur.split("~");
                            errorScopeDur = PubUtils.doubleRoundStr(0, Double.parseDouble(tempStr[0]) * 1000).concat("~").concat(PubUtils.doubleRoundStr(0, Double.parseDouble(tempStr[1]) * 1000));
                        }
                    }
                    unitDur = "ms";
                }
            }
        }
        if (!hasData) {
            return false;
        }
        errorScopeMag = dealErrorScope(errorScopeMag).concat(StrUtil.isBlank(unitMag) ? "" : unitMag);
        errorScopeDur = dealErrorScope(errorScopeDur).concat(StrUtil.isBlank(unitDur) ? "" : unitDur);

        errorScope = "特征幅值：".concat(errorScopeMag).concat(StrPool.COMMA).concat("持续时间：").concat(errorScopeDur);
        keyFillMap.put(ItemReportKeyEnum.ERROR_SCOPE.getKey(), errorScope);
        // 标准值
        keyFillMap.put(ItemReportKeyEnum.STANDARD_MAG.getKey(), standardMag);
        keyFillMap.put(ItemReportKeyEnum.STANDARD_DUR.getKey(), standardDur);
        // 测试值
        keyFillMap.put(ItemReportKeyEnum.TEST_MAG.getKey(), testMag);
        keyFillMap.put(ItemReportKeyEnum.TEST_DUR.getKey(), testDur);
        // 误差
        keyFillMap.put(ItemReportKeyEnum.ERROR_MAG.getKey(), errorMag);
        keyFillMap.put(ItemReportKeyEnum.ERROR_DUR.getKey(), errorDur);
        // 结果
        keyFillMap.put(ItemReportKeyEnum.RESULT_MAG.getKey(), resultMag);
        keyFillMap.put(ItemReportKeyEnum.RESULT_DUR.getKey(), resultDur);
        // 综合结果
        result = resultMag;
        if (!resultDur.equals("/") && result.equals("合格")) {
            if (resultDur.equals("不合格")) {
                result = "不合格";
            }
        }
        keyFillMap.put(ItemReportKeyEnum.RESULT.getKey(), result);
        return true;
    }


    /**
     * 处理下误差范围，如果正负数一致时调整为±的形式
     * 数据库中一般形式为：-0.1155~0.1155
     *
     * @param errorScope 误差范围
     */
    private String dealErrorScope(String errorScope) {
        if (StrUtil.isBlank(errorScope)) {
            return "/";
        }
        if (errorScope.contains("~")) {
            String[] split = errorScope.split("~");
            String begin = split[0];
            if (begin.contains(StrPool.DASHED)) {
                begin = begin.substring(1);
            }
            String end = split[1];
            if (end.equalsIgnoreCase(begin)) {
                return "±" + begin;
            }
        }
        return errorScope;
    }

    /**
     * 遍历所有的结果，是否存在不合格，但凡有一个不合格就返回false
     *
     * @param finalContent 最终结果
     */
    private boolean judgeQualified(Map<String, List<Map<String, List<Map<String, String>>>>> finalContent) {
        List<String> results = finalContent.values().parallelStream()
                .flatMap(List::stream)
                .flatMap(m -> m.values().stream())
                .flatMap(List::stream)
                .filter(map -> map.containsKey(ItemReportKeyEnum.RESULT.getKey()))
                .map(map -> map.get(ItemReportKeyEnum.RESULT.getKey()))
                .collect(Collectors.toList());
        List<String> qualifiedList = results.stream().filter("不合格"::equals).collect(Collectors.toList());
        return CollUtil.isEmpty(qualifiedList);
    }

    /**
     * 根据谐波结果数据获取局的测试数据
     *
     * @param singleResult 谐波数据
     * @param timeInt      次数
     * @param phaseA       相别
     */
    private DetectionData getResultData(Object singleResult, Integer timeInt, String phaseA) {
        if (Objects.isNull(singleResult)) {
            return null;
        }
        String fieldName = phaseA.toLowerCase().concat("Value");
        if (Objects.nonNull(timeInt)) {
            fieldName = fieldName.concat(String.valueOf(timeInt));
        }
        String filedValue;
        try {
            filedValue = (String) ReflectUtil.getFieldValue(singleResult, fieldName);
        } catch (Exception exception) {
            throw new BusinessException("获取对象字段属性失败");
        }
        if (StrUtil.isBlank(filedValue)) {
            return null;
        }
        return JSONUtil.toBean(filedValue, DetectionData.class);
    }

    @Override
    public FormContentVO getContrastFormContent(ResultParam.QueryParam queryParam) {
        FormContentVO formContentVO = new FormContentVO();

        AdPlan plan = adPlanService.getById(queryParam.getPlanId());
        PqDev dev = pqDevService.getById(queryParam.getDeviceId());
        formContentVO.setDataRule(plan.getDataRule());
        formContentVO.setDeviceName(dev.getName());
        formContentVO.setErrorSysId(plan.getErrorSysId());

        List<DictTree> dictTreeList = null;
        List<String> adTypeList = null;
        if (StrUtil.isNotBlank(queryParam.getScriptType())) {
            if (DataSourceEnum.WAVE_DATA.getValue().equals(queryParam.getScriptType())) {
                List<Map<String, String>> bigTestItem = adPlanService.getBigTestItem(1, queryParam.getPlanId(), Collections.singletonList(queryParam.getDeviceId()), queryParam.getPatternId(), DataSourceEnum.WAVE_DATA.getValue());
                List<String> ids = bigTestItem.stream().filter(x -> !DetectionCodeEnum.FREQ.getCode().equals(x.get("code"))).map(x -> x.get("id")).collect(Collectors.toList());
                dictTreeList = dictTreeService.getDictTreeById(ids);
            } else {
                dictTreeList = dictTreeService.getDictTreeById(Collections.singletonList(queryParam.getScriptType()));
            }
            List<String> fatherIdList = dictTreeList.stream().map(DictTree::getId).collect(Collectors.toList());
            List<DictTree> childDictTreeList = dictTreeService.listByFatherIds(fatherIdList);
            adTypeList = childDictTreeList.stream().map(DictTree::getId).collect(Collectors.toList());
        }
        List<ContrastBaseResult> allResultList = new ArrayList<>();

        List<ContrastNonHarmonicResult> contrastNonHarmonicResults = contrastNonHarmonicService.listAllResultData(String.valueOf(plan.getCode()), null, null, false, null, queryParam.getDeviceId(), adTypeList);
        contrastNonHarmonicResults.addAll(contrastNonHarmonicService.listAllResultData(String.valueOf(plan.getCode()), null, null, true, null, queryParam.getDeviceId(), adTypeList));
        List<ContrastHarmonicResult> contrastHarmonicResults = contrastHarmonicService.listAllResultData(String.valueOf(plan.getCode()), null, null, false, null, queryParam.getDeviceId(), adTypeList);
        contrastHarmonicResults.addAll(contrastHarmonicService.listAllResultData(String.valueOf(plan.getCode()), null, null, true, null, queryParam.getDeviceId(), adTypeList));
        allResultList.addAll(contrastHarmonicResults);
        allResultList.addAll(contrastNonHarmonicResults);

        Map<String, List<Integer>> chnMap = new TreeMap<>();
        Map<String, List<ContrastBaseResult>> devMonitorIdMap = allResultList.stream().collect(Collectors.groupingBy(ContrastBaseResult::getDevMonitorId));
        devMonitorIdMap.forEach((devMonitorId, resultList) -> {
            Integer maxNum = resultList.stream().map(ContrastBaseResult::getNum).max(Comparator.comparing(Integer::valueOf)).orElse(1);
            List<Integer> numList = Stream.iterate(1, n -> n + 1).limit(maxNum).collect(Collectors.toList());
            String[] split = devMonitorId.split(CnSocketUtil.SPLIT_TAG);
            chnMap.put(split[1], numList);
        });

        AdPlanTestConfig adPlanTestConfig = adPlanTestConfigService.getByPlanId(queryParam.getPlanId());
        formContentVO.setWaveNumTotal(adPlanTestConfig.getWaveRecord());

        formContentVO.setChnMap(chnMap);
        return formContentVO;
    }

    @Override
    public ContrastResultVO getContrastResult(ResultParam.QueryParam queryParam) {
        ContrastResultVO contrastResultVO = new ContrastResultVO();

        List<DictTree> dictTreeList = dictTreeService.getDictTreeById(Collections.singletonList(queryParam.getScriptType()));

        List<String> fatherIdList = dictTreeList.stream().map(DictTree::getId).collect(Collectors.toList());
        List<DictTree> childDictTreeList = dictTreeService.listByFatherIds(fatherIdList);
        List<String> adTypeList = childDictTreeList.stream().map(DictTree::getId).collect(Collectors.toList());
        DictTree dictTree = dictTreeList.get(0);

        String unit = StorageUtil.unit(dictTree.getCode());
        if (PowerIndexEnum.HV.getKey().equals(dictTree.getCode()) || PowerIndexEnum.HI.getKey().equals(dictTree.getCode())) {
            unit = "%";
            if (PowerIndexEnum.HI.getKey().equals(dictTree.getCode())) {
                unit = "A";
            }
        }
        if (PowerIndexEnum.HSV.getKey().equals(dictTree.getCode()) || PowerIndexEnum.HSI.getKey().equals(dictTree.getCode())) {
            unit = "%";
            if (PowerIndexEnum.HSI.getKey().equals(dictTree.getCode())) {
                unit = "A";
            }
        }

        contrastResultVO.setResultMap(this.getResultMap(dictTree, adTypeList, queryParam.getDeviceId() + CnSocketUtil.SPLIT_TAG + queryParam.getChnNum(), unit, queryParam.getNum(), queryParam.getWaveNum(), queryParam.getIsWave(), queryParam.getCode()));
        contrastResultVO.setRawDataMap(this.getRawDataMap(dictTree, adTypeList, queryParam.getDeviceId() + CnSocketUtil.SPLIT_TAG + queryParam.getChnNum(), unit, queryParam.getNum(), queryParam.getWaveNum(), queryParam.getIsWave(), queryParam.getCode(), contrastResultVO.getResultMap().keySet().stream().collect(Collectors.toList())));
        return contrastResultVO;
    }


    @Override
    public List<MonitorResultVO> getMonitorResult(String devId) {
        PqDev dev = pqDevService.getById(devId);
        AdPlan plan = adPlanService.getById(dev.getPlanId());
        String errorSysName = pqErrSysService.getPqErrSysById(plan.getErrorSysId()).getName();

        List<PqMonitor> pqMonitorList = pqMonitorService.lambdaQuery().eq(PqMonitor::getDevId, devId).isNotNull(PqMonitor::getResultType).list();
        List<MonitorResultVO> list = new ArrayList<>();
        if (CollUtil.isEmpty(pqMonitorList)) {
            return list;
        }
        MonitorResultVO result;
        // 根据通道号排序
        pqMonitorList.sort(Comparator.comparing(PqMonitor::getNum));
        for (PqMonitor pqMonitor : pqMonitorList) {
            result = new MonitorResultVO();
            result.setMonitorId(pqMonitor.getDevId() + CnSocketUtil.SPLIT_TAG + pqMonitor.getNum());
            result.setErrorSysName(errorSysName);
            result.setMonitorNum(pqMonitor.getNum());

            result.setQualifiedNum(pqMonitor.getQualifiedNum());

            List<AdPair> records = adPairService.page(new Page<>(1, 1),
                            new LambdaQueryWrapper<AdPair>().eq(AdPair::getDevMonitorId, result.getMonitorId())
                                    .eq(AdPair::getPlanId, plan.getId()).orderByDesc(AdPair::getNum))
                    .getRecords();
            if (CollUtil.isNotEmpty(records)) {
                result.setTotalNum(records.get(0).getNum());
                result.setUnQualifiedNum(result.getTotalNum() - result.getQualifiedNum());
            }

            String resultType = pqMonitor.getResultType();
            result.setResultType(resultType);
            DataSourceEnum dataSourceEnum = DataSourceEnum.ofByValue(resultType);
            switch (Objects.requireNonNull(dataSourceEnum)) {
                case REAL_DATA:
                    result.setCheckResult(pqMonitor.getRealtimeResult());
                    result.setWhichTime(pqMonitor.getRealtimeNum());
                    result.setResultOrigin(dataSourceEnum.getMsg());
                    break;
                case WAVE_DATA:
                    result.setCheckResult(pqMonitor.getRecordedResult());
                    // 1_2 第【1】次录波【2】数据
                    List<String> waveData = StrUtil.split(pqMonitor.getRecordedNum(), CnSocketUtil.SPLIT_TAG);
                    result.setWhichTime(waveData.get(0));
                    result.setResultType(resultType + CnSocketUtil.SPLIT_TAG + waveData.get(1));
                    result.setResultOrigin(dataSourceEnum.getMsg() + waveData.get(1));
                    break;
                case MINUTE_STATISTICS_AVG:
                    result.setCheckResult(pqMonitor.getStatisticsResult());
                    result.setWhichTime(pqMonitor.getStatisticsNum());
                    result.setResultOrigin(dataSourceEnum.getMsg());
                    break;
                case MINUTE_STATISTICS_MAX:
                    result.setCheckResult(pqMonitor.getStatisticsResult());
                    result.setWhichTime(pqMonitor.getStatisticsNum());
                    result.setResultOrigin(dataSourceEnum.getMsg());
                    break;
                case MINUTE_STATISTICS_MIN:
                    result.setCheckResult(pqMonitor.getStatisticsResult());
                    result.setWhichTime(pqMonitor.getStatisticsNum());
                    result.setResultOrigin(dataSourceEnum.getMsg());
                    break;
                case MINUTE_STATISTICS_CP95:
                    result.setCheckResult(pqMonitor.getStatisticsResult());
                    result.setWhichTime(pqMonitor.getStatisticsNum());
                    result.setResultOrigin(dataSourceEnum.getMsg());
                    break;
                default:
                    break;
            }


            list.add(result);

        }
        return list;
    }

    @Override
    public Map<Integer, List<DataSourceResultVO>> getMonitorDataSourceResult(String monitorId) {
        // key为第几次检测，value为所对应的下拉框内容
        Map<Integer, List<DataSourceResultVO>> result = new HashMap<>();

        String[] split = monitorId.split(CnSocketUtil.SPLIT_TAG);
        PqDev dev = pqDevService.getById(split[0]);
        String planId = dev.getPlanId();
        AdPlan plan = adPlanService.getById(planId);
        if (!plan.getFatherPlanId().equals(CommonEnum.FATHER_ID.getValue())) {
            plan = adPlanService.getById(plan.getFatherPlanId());
        }
        AdPlan finalPlan = plan;
        // 实时数据结果
        List<ContrastNonHarmonicResult> realNonHarmonicResults = contrastNonHarmonicService.listAllResultData(String.valueOf(finalPlan.getCode()), null, null, false, DataSourceEnum.REAL_DATA.getValue(), monitorId, null);
        Map<Integer, List<ContrastNonHarmonicResult>> realNumNonHarmonicMap = realNonHarmonicResults.stream()
                .sorted(Comparator.comparing(ContrastNonHarmonicResult::getNum))
                .collect(Collectors.groupingBy(ContrastNonHarmonicResult::getNum, LinkedHashMap::new, Collectors.toList()));

        List<ContrastHarmonicResult> realHarmonicResults = contrastHarmonicService.listAllResultData(String.valueOf(finalPlan.getCode()), null, null, false, DataSourceEnum.REAL_DATA.getValue(), monitorId, null);
        Map<Integer, List<ContrastHarmonicResult>> realNumHarmonicMap = realHarmonicResults.stream()
                .sorted(Comparator.comparing(ContrastHarmonicResult::getNum))
                .collect(Collectors.groupingBy(ContrastHarmonicResult::getNum, LinkedHashMap::new, Collectors.toList()));

        Map<Integer, List<Integer>> realNumResutMap = new TreeMap<>();
        realNumNonHarmonicMap.forEach((num, resultList) -> {
            realNumResutMap.put(num, resultList.stream().map(ContrastNonHarmonicResult::getResultFlag).distinct().collect(Collectors.toList()));
        });
        realNumHarmonicMap.forEach((num, resultList) -> {
            List<Integer> list = realNumResutMap.getOrDefault(num, new ArrayList<>());
            list.addAll(resultList.stream().map(ContrastHarmonicResult::getResultFlag).distinct().collect(Collectors.toList()));
            realNumResutMap.put(num, list);
        });

        realNumResutMap.forEach((num, resultList) -> {
            List<DataSourceResultVO> dataSourceResultVOList = new ArrayList<>();
            DataSourceResultVO realDataSourceResultVO = new DataSourceResultVO();
            realDataSourceResultVO.setDataSourceCode(DataSourceEnum.REAL_DATA.getValue());
            realDataSourceResultVO.setDataSourceName(DataSourceEnum.REAL_DATA.getMsg());
            realDataSourceResultVO.setCheckResult(StorageUtil.getInteger(resultList));
            dataSourceResultVOList.add(realDataSourceResultVO);

            result.put(num, dataSourceResultVOList);
        });


        // 录波数据结果
        Map<Integer, Map<Integer, List<Integer>>> waveNumMap = new TreeMap<>();
        List<ContrastNonHarmonicResult> waveNonHarmonicResults = contrastNonHarmonicService.listAllResultData(String.valueOf(finalPlan.getCode()), null, null, true, null, monitorId, null);
        Map<Integer, List<ContrastNonHarmonicResult>> waveNumNonHarmonicMap = waveNonHarmonicResults.stream()
                .sorted(Comparator.comparing(ContrastNonHarmonicResult::getNum))
                .collect(Collectors.groupingBy(ContrastNonHarmonicResult::getNum, LinkedHashMap::new, Collectors.toList()));
        List<ContrastHarmonicResult> waveHarmonicResults = contrastHarmonicService.listAllResultData(String.valueOf(finalPlan.getCode()), null, null, true, null, monitorId, null);
        Map<Integer, List<ContrastHarmonicResult>> waveNumHarmonicMap = waveHarmonicResults.stream()
                .sorted(Comparator.comparing(ContrastHarmonicResult::getNum))
                .collect(Collectors.groupingBy(ContrastHarmonicResult::getNum, LinkedHashMap::new, Collectors.toList()));

        waveNumNonHarmonicMap.forEach((num, resultList) -> {
            LinkedHashMap<Integer, List<ContrastNonHarmonicResult>> collect = resultList.stream()
                    .sorted(Comparator.comparing(ContrastNonHarmonicResult::getWaveNum))
                    .collect(Collectors.groupingBy(ContrastNonHarmonicResult::getWaveNum, LinkedHashMap::new, Collectors.toList()));

            Map<Integer, List<Integer>> map = new TreeMap<>();
            collect.forEach((waveNum, resultList1) -> {
                map.put(waveNum, resultList1.stream().map(ContrastNonHarmonicResult::getResultFlag).distinct().collect(Collectors.toList()));
            });
            waveNumMap.put(num, map);
        });

        waveNumHarmonicMap.forEach((num, resultList) -> {
            Map<Integer, List<Integer>> map = waveNumMap.getOrDefault(num, new TreeMap<>());

            LinkedHashMap<Integer, List<ContrastHarmonicResult>> collect = resultList.stream().sorted(Comparator.comparing(ContrastHarmonicResult::getWaveNum))
                    .collect(Collectors.groupingBy(ContrastHarmonicResult::getWaveNum, LinkedHashMap::new, Collectors.toList()));
            collect.forEach((waveNum, resultList1) -> {
                List<Integer> list = map.getOrDefault(waveNum, new ArrayList<>());
                list.addAll(resultList1.stream().map(ContrastHarmonicResult::getResultFlag).distinct().collect(Collectors.toList()));
                map.put(waveNum, list);
            });
            waveNumMap.put(num, map);
        });

        waveNumMap.forEach((num, map) -> {
            List<DataSourceResultVO> orDefault = result.getOrDefault(num, new ArrayList<>());
            map.forEach((waveNum, resultList) -> {
                DataSourceResultVO waveDataSourceResultVO = new DataSourceResultVO();
                waveDataSourceResultVO.setDataSourceCode(DataSourceEnum.WAVE_DATA.getValue() + CnSocketUtil.SPLIT_TAG + waveNum);
                waveDataSourceResultVO.setDataSourceName(DataSourceEnum.WAVE_DATA.getMsg() + StrUtil.SPACE + waveNum);
                waveDataSourceResultVO.setCheckResult(StorageUtil.getInteger(resultList));
                orDefault.add(waveDataSourceResultVO);
            });
            result.put(num, orDefault);
        });

        String dataRule = finalPlan.getDatasourceId();
        String[] split1 = dataRule.split(CnSocketUtil.SPLIT_TAG);
        DataSourceEnum dataType = null;
        for (String s : split1) {
            if (MINUTE_STATISTICS_AVG.getValue().equals(s)) {
                dataType = MINUTE_STATISTICS_AVG;
                break;
            }
            if (MINUTE_STATISTICS_CP95.getValue().equals(s)) {
                dataType = MINUTE_STATISTICS_CP95;
                break;
            }
            if (MINUTE_STATISTICS_MAX.getValue().equals(s)) {
                dataType = MINUTE_STATISTICS_MAX;
                break;
            }
            if (MINUTE_STATISTICS_MIN.getValue().equals(s)) {
                dataType = MINUTE_STATISTICS_MIN;
                break;
            }
        }

        // 统计数据
        if (ObjectUtil.isNotNull(dataType)) {
            List<ContrastNonHarmonicResult> statisticsNonHarmonicResults = contrastNonHarmonicService.listAllResultData(String.valueOf(finalPlan.getCode()), null, null, false, dataType.getValue(), monitorId, null);
            Map<Integer, List<ContrastNonHarmonicResult>> statisticsNumNonHarmonicMap = statisticsNonHarmonicResults.stream()
                    .sorted(Comparator.comparing(ContrastNonHarmonicResult::getNum))
                    .collect(Collectors.groupingBy(ContrastNonHarmonicResult::getNum, LinkedHashMap::new, Collectors.toList()));

            List<ContrastHarmonicResult> statisticsHarmonicResults = contrastHarmonicService.listAllResultData(String.valueOf(finalPlan.getCode()), null, null, false, dataType.getValue(), monitorId, null);
            Map<Integer, List<ContrastHarmonicResult>> statisticsNumHarmonicMap = statisticsHarmonicResults.stream()
                    .sorted(Comparator.comparing(ContrastHarmonicResult::getNum))
                    .collect(Collectors.groupingBy(ContrastHarmonicResult::getNum, LinkedHashMap::new, Collectors.toList()));

            Map<Integer, List<Integer>> statisticsNumResutMap = new TreeMap<>();
            statisticsNumNonHarmonicMap.forEach((num, resultList) -> {
                statisticsNumResutMap.put(num, resultList.stream().map(ContrastNonHarmonicResult::getResultFlag).distinct().collect(Collectors.toList()));
            });
            statisticsNumHarmonicMap.forEach((num, resultList) -> {
                List<Integer> list = statisticsNumResutMap.getOrDefault(num, new ArrayList<>());
                list.addAll(resultList.stream().map(ContrastHarmonicResult::getResultFlag).distinct().collect(Collectors.toList()));
                statisticsNumResutMap.put(num, list);
            });

            DataSourceEnum finalDataType = dataType;
            statisticsNumResutMap.forEach((num, resultList) -> {
                List<DataSourceResultVO> dataSourceResultVOList = new ArrayList<>();
                DataSourceResultVO realDataSourceResultVO = new DataSourceResultVO();
                realDataSourceResultVO.setDataSourceCode(finalDataType.getValue());
                realDataSourceResultVO.setDataSourceName(finalDataType.getMsg());
                realDataSourceResultVO.setCheckResult(StorageUtil.getInteger(resultList));
                dataSourceResultVOList.add(realDataSourceResultVO);

                result.put(num, dataSourceResultVOList);
            });
        }
        return result;
    }

    @Override
    public Boolean updateMonitorResult(MonitorResultVO resultParams) {
        String monitorId = resultParams.getMonitorId();
        String[] split = monitorId.split(CnSocketUtil.SPLIT_TAG);
        PqMonitor monitor = pqMonitorService.lambdaQuery().eq(PqMonitor::getDevId, split[0]).eq(PqMonitor::getNum, split[1]).one();
        if (monitor == null) {
            throw new BusinessException(CommonResponseEnum.FAIL, "该设备监测点不存在");
        }
        String whichTime = resultParams.getWhichTime();
        Integer checkResult = resultParams.getCheckResult();
        String resultType = resultParams.getResultType();
        if (StrUtil.contains(resultType, DataSourceEnum.WAVE_DATA.getValue())) {
            monitor.setResultType(resultType.substring(0, resultType.lastIndexOf(CnSocketUtil.SPLIT_TAG)));
            monitor.setRecordedResult(checkResult);
            monitor.setRecordedNum(whichTime + resultType.substring(resultType.lastIndexOf(CnSocketUtil.SPLIT_TAG)));
            monitor.setRealtimeResult(null);
            monitor.setRealtimeNum(null);
            monitor.setStatisticsResult(null);
            monitor.setStatisticsNum(null);
        } else if (StrUtil.equals(resultType, DataSourceEnum.REAL_DATA.getValue())) {
            monitor.setResultType(resultType);
            monitor.setRealtimeResult(checkResult);
            monitor.setRealtimeNum(whichTime);
            monitor.setRecordedResult(null);
            monitor.setRecordedNum(null);
            monitor.setStatisticsResult(null);
            monitor.setStatisticsNum(null);
        } else {
            monitor.setResultType(resultType);
            monitor.setStatisticsResult(checkResult);
            monitor.setStatisticsNum(whichTime);
            monitor.setRealtimeResult(null);
            monitor.setRealtimeNum(null);
            monitor.setRecordedResult(null);
            monitor.setRecordedNum(null);
        }
        boolean flag = pqMonitorService.updateById(monitor);

        pqDevService.updateResult(split[0], null);

        return flag;
    }

    @Override
    public List<ContrastTestItemVO> getCheckItem(String planId, String devId, String chnNum, Integer num, String code) {
//        PqDev dev = pqDevService.getById(devId);
        AdPlan plan = adPlanService.getById(planId);
//        String code = String.valueOf(plan.getCode());

        String monitorId = devId + CnSocketUtil.SPLIT_TAG + chnNum;

        List<ContrastNonHarmonicResult> realNoHarmonicResults = contrastNonHarmonicService.listAllResultData(code, num, null, false, null, monitorId, null);
        List<ContrastHarmonicResult> realHarmonicResults = contrastHarmonicService.listAllResultData(code, num, null, false, null, monitorId, null);

        Map<String, List<Integer>> checkItemResultMap = realNoHarmonicResults.stream().collect(Collectors.groupingBy(ContrastNonHarmonicResult::getAdType, Collectors.mapping(ContrastNonHarmonicResult::getResultFlag, Collectors.toList())));
        checkItemResultMap.putAll(realHarmonicResults.stream().collect(Collectors.groupingBy(ContrastHarmonicResult::getAdType, Collectors.mapping(ContrastHarmonicResult::getResultFlag, Collectors.toList()))));

        List<ContrastTestItemVO> result = new ArrayList<>();
        checkItemResultMap.forEach((adType, resultList) -> {
            ContrastTestItemVO contrastTestItemVO = new ContrastTestItemVO();
            DictTree childDictTree = dictTreeService.getById(adType);
            DictTree fatherDictTree = dictTreeService.getById(childDictTree.getPid());
            contrastTestItemVO.setId(fatherDictTree.getId());
            contrastTestItemVO.setCode(fatherDictTree.getCode());
            contrastTestItemVO.setScriptName(fatherDictTree.getName());
            contrastTestItemVO.setResultFlag(StorageUtil.getInteger(resultList));
            result.add(contrastTestItemVO);
        });

        checkItemResultMap.clear();

        List<ContrastNonHarmonicResult> waveNoHarmonicResults = contrastNonHarmonicService.listAllResultData(code, num, null, true, null, monitorId, null);
        List<ContrastHarmonicResult> waveHarmonicResults = contrastHarmonicService.listAllResultData(code, num, null, true, null, monitorId, null);
        if (CollUtil.isNotEmpty(waveNoHarmonicResults) && CollUtil.isNotEmpty(waveHarmonicResults)) {
            checkItemResultMap.putAll(waveNoHarmonicResults.stream().collect(Collectors.groupingBy(ContrastNonHarmonicResult::getAdType, Collectors.mapping(ContrastNonHarmonicResult::getResultFlag, Collectors.toList()))));
            checkItemResultMap.putAll(waveHarmonicResults.stream().collect(Collectors.groupingBy(ContrastHarmonicResult::getAdType, Collectors.mapping(ContrastHarmonicResult::getResultFlag, Collectors.toList()))));

            ContrastTestItemVO contrastTestItemVO = new ContrastTestItemVO();
            contrastTestItemVO.setId(DataSourceEnum.WAVE_DATA.getValue());
            contrastTestItemVO.setCode(DataSourceEnum.WAVE_DATA.getValue());
            contrastTestItemVO.setScriptName(DataSourceEnum.WAVE_DATA.getMsg());

            List<ContrastTestItemVO> setSubItems = new ArrayList<>();
            checkItemResultMap.forEach((adType, resultList) -> {
                ContrastTestItemVO subContrastTestItemVO = new ContrastTestItemVO();
                DictTree childDictTree = dictTreeService.getById(adType);
                DictTree fatherDictTree = dictTreeService.getById(childDictTree.getPid());
                subContrastTestItemVO.setId(fatherDictTree.getId());
                subContrastTestItemVO.setCode(fatherDictTree.getCode());
                subContrastTestItemVO.setScriptName(fatherDictTree.getName());
                subContrastTestItemVO.setResultFlag(StorageUtil.getInteger(resultList));
                setSubItems.add(subContrastTestItemVO);
            });
            contrastTestItemVO.setResultFlag(StorageUtil.getInteger(checkItemResultMap.values().stream().flatMap(List::stream).distinct().collect(Collectors.toList())));
            contrastTestItemVO.setSubItems(setSubItems);
            result.add(contrastTestItemVO);
        }

        return result;
    }

    /**
     * 获取对比结果
     *
     * @param devReportParam 设备报告参数
     * @param pqDevVO        设备信息 省去一次sql查询
     */
    @Override
    public Map<Integer, List<ContrastTestResult>> getContrastResultForReport(DevReportParam devReportParam, PqDevVO pqDevVO) {
        Map<Integer/*回路号*/, List<ContrastTestResult>> finalContent = new LinkedHashMap<>();
        // 获取该设备下参与测试的回路（已有检测结论的）
        List<MonitorResultVO> monitorResultVOS = this.getMonitorResult(devReportParam.getDevId());
        if (CollectionUtil.isNotEmpty(monitorResultVOS)) {
            Collections.sort(monitorResultVOS);
            // 获取该计划下所有的检测指标，注：如果用户应用的是录波数据，频率这个指标不用出结果，因为当前的算法无法得出合理的结果
            List<String> scriptList = adPlanService.getScriptListContrast(devReportParam.getPlanId());
            // 对测试项按字典表排个序
            scriptList = dictTreeService.sort(scriptList);
            AdPlan adPlan = adPlanService.getById(devReportParam.getPlanId());
            if (CollectionUtil.isNotEmpty(scriptList)) {
                for (MonitorResultVO monitorResultVO : monitorResultVOS) {
                    List<ContrastTestResult> contrastTestResults = new ArrayList<>();
                    int monitorNum = monitorResultVO.getMonitorNum();
                    // 看看当前这个回路结论的来源，可能是某次的实时数据、某次的测试下的某次录波数据、某次统计数据
                    for (String scriptId : scriptList) {
                        // 获取该指标的code，需要判断是否为谐波还是非谐波的指标
                        DictTree dictTree = dictTreeService.getById(scriptId);
                        // 本处的scriptId为父级，我需要获取自己
                        List<String> subScriptIds = dictTreeService.getChildIds(scriptId);
                        String scriptCode = dictTree.getCode();
                        if (PowerConstant.TIME.contains(scriptCode)) {
                            // 谐波类，谐波类稍微特殊一点，存在2~50次的数据，所以需要特殊处理
                            ContrastTestResult contrastTestResult = getContrastResultHarm(monitorResultVO, subScriptIds, adPlan.getCode(), dictTree);
                            if (Objects.nonNull(contrastTestResult)) {
                                contrastTestResults.add(contrastTestResult);
                            }
                        } else {
                            // 非谐波类，非谐波需要注意T相和三相
                            ContrastTestResult contrastTestResult = getContrastResultNonHarm(monitorResultVO, subScriptIds, adPlan.getCode(), dictTree);
                            if (Objects.nonNull(contrastTestResult)) {
                                contrastTestResults.add(contrastTestResult);
                            }
                        }
                    }
                    finalContent.put(monitorNum, contrastTestResults);
                }
            }
            return finalContent;
        }
        return Collections.emptyMap();
    }


    /**
     * 获取谐波类数据的结果数据
     *
     * @param monitorResultVO 数据来源信息
     * @param subScriptIds    实际检测指标id
     * @param planCode        计划code，表名需要
     * @param dictTree        测试指标信息
     * @return 结果数据
     */
    @Override
    public ContrastTestResult getContrastResultHarm(MonitorResultVO monitorResultVO, List<String> subScriptIds, Integer planCode, DictTree dictTree) {
        ContrastHarmonicResult result = contrastHarmonicService.getContrastResultHarm(planCode, monitorResultVO.getMonitorId(), subScriptIds, monitorResultVO.getResultType(), Integer.parseInt(monitorResultVO.getWhichTime()));
        // 收集组数数据
        int numOfData = contrastHarmonicService.getNumOfData(planCode, monitorResultVO.getMonitorId(), subScriptIds, monitorResultVO.getResultType(), Integer.parseInt(monitorResultVO.getWhichTime()));
        if (Objects.nonNull(result)) {
            // 谐波类的获取2~50次的数据
            ContrastTestResult contrastTestResult = new ContrastTestResult();
            contrastTestResult.setScriptCode(dictTree.getCode());
            contrastTestResult.setScriptName(dictTree.getName());
            contrastTestResult.setHarmonic(true);

            // 判断是否为间谐波
            boolean isInterHarmonic = "HSV".equals(dictTree.getCode()) || "HSI".equals(dictTree.getCode());

            // 根据指标代码确定小数位数
            Integer decimalPlaces = getDecimalPlacesByScriptCode(dictTree.getCode());

            // 默认结果是符合的,后续解析过程中存在不符合的，则改为不符合
            // 构建谐波数据结果Map: 次数 -> 相别 -> List<Map<占位符名称, 占位符值>>
            List<Map<String, Map<String, Map<String, String>>>> harmonicResult = new ArrayList<>();
            List<String> allResult = new ArrayList<>();

            // 收集特殊情况信息
            Map<Integer, List<String>> zeroFilteredMap = new LinkedHashMap<>(); // 双零过滤的次数和相别
            Map<Integer, Map<String, List<String>>> unComparableMap = new LinkedHashMap<>(); // 无法比较的次数和相别（按组数分组）
            Map<Integer, Map<String, List<String>>> unqualifiedMap = new LinkedHashMap<>(); // 不符合的次数和相别（按组数分组）
            int totalDataPoints = 0; // 统计总的数据点数
            int zeroFilteredPoints = 0; // 统计双零过滤的数据点数

            // 间谐波从1开始，普通谐波从2开始
            int startHarmNum = isInterHarmonic ? 1 : 2;
            // 遍历谐波次数
            for (int harmNum = startHarmNum; harmNum <= 50; harmNum++) {
                String harmKey = String.valueOf(harmNum);
                Map<String, Map<String, Map<String, String>>> checkResultHarmonic = new LinkedHashMap<>();
                List<String> zeroFilteredPhases = new ArrayList<>(); // 当前次数被过滤的相别

                try {
                    Map<String, Map<String, String>> phaseData = new LinkedHashMap<>();
                    boolean hasNonZeroData = false; // 标记是否有非双零数据

                    for (String phase : PowerConstant.PHASE_ABC) {
                        Field field = result.getClass().getDeclaredField(phase + "Value" + harmKey);
                        field.setAccessible(true);
                        String valueJson = (String) field.get(result);
                        Map<String, String> singlePhaseData = parseHarmonicPhaseData(valueJson, phase.toUpperCase() + "相", harmNum, numOfData, dictTree.getCode(), decimalPlaces);

                        if (CollUtil.isNotEmpty(singlePhaseData)) {
                            totalDataPoints++; // 统计总数据点

                            // 检查是否为双零情况
                            String standardVal = singlePhaseData.get(ItemReportKeyEnum.STANDARD.getKey());
                            String testVal = singlePhaseData.get(ItemReportKeyEnum.TEST.getKey());

                            // 判断是否为双零（标准值和被检值都为0或"0.0"或"0"）
                            boolean isZeroFiltered = isZeroValue(standardVal) && isZeroValue(testVal);

                            if (isZeroFiltered) {
                                zeroFilteredPoints++; // 统计双零点
                                // 双零情况，记录但不加入结果判定
                                zeroFilteredPhases.add(phase.toUpperCase() + "相");
                                // 将结果改为特殊标记，不参与整体结论判定
                                singlePhaseData.put(ItemReportKeyEnum.RESULT.getKey(), "符合");
                            } else {
                                // 有非双零数据
                                hasNonZeroData = true;
                                // 非双零情况，正常处理结果
                                String resultTemp = singlePhaseData.get(ItemReportKeyEnum.RESULT.getKey());
                                if (StrUtil.isNotBlank(resultTemp)) {
                                    allResult.add(resultTemp);
                                    // 收集特殊情况
                                    if ("无法比较".equals(resultTemp)) {
                                        String numOfDataStr = singlePhaseData.get(ItemReportKeyEnum.NUM_OF_DATA.getKey());
                                        unComparableMap.computeIfAbsent(harmNum, k -> new LinkedHashMap<>())
                                                .computeIfAbsent(numOfDataStr, k -> new ArrayList<>())
                                                .add(phase.toUpperCase() + "相");
                                    } else if ("不符合".equals(resultTemp)) {
                                        String numOfDataStr = singlePhaseData.get(ItemReportKeyEnum.NUM_OF_DATA.getKey());
                                        unqualifiedMap.computeIfAbsent(harmNum, k -> new LinkedHashMap<>())
                                                .computeIfAbsent(numOfDataStr, k -> new ArrayList<>())
                                                .add(phase.toUpperCase() + "相");
                                    }
                                }
                            }

                            phaseData.put(phase.toUpperCase() + "相", singlePhaseData);
                        }
                    }

                    // 记录当前次数的双零过滤情况
                    if (!zeroFilteredPhases.isEmpty()) {
                        zeroFilteredMap.put(harmNum, zeroFilteredPhases);
                    }

                    // 只有当该次谐波有非双零数据时，才添加到结果集中
                    if (hasNonZeroData) {
                        checkResultHarmonic.put(harmKey, phaseData);
                        // 如果该次谐波有数据，添加到结果Map中
                        if (CollUtil.isNotEmpty(checkResultHarmonic)) {
                            harmonicResult.add(checkResultHarmonic);
                        }
                    }
                } catch (NoSuchFieldException | IllegalAccessException e) {
                    log.warn("获取第{}次谐波数据失败: {}", harmNum, e.getMessage());
                }
            }

            // 判断是否所有数据都是双零
            boolean allDataIsZero = (totalDataPoints > 0 && totalDataPoints == zeroFilteredPoints);

            // 生成specialCase描述
            String specialCase = generateHarmonicSpecialCase(zeroFilteredMap, unComparableMap, unqualifiedMap,
                    totalDataPoints, zeroFilteredPoints, isInterHarmonic);

            // 设置检测结果
            String overallResult;
            if (allDataIsZero) {
                // 如果所有数据都是双零，结果为符合
                overallResult = "符合";
            } else {
                // 根据所有相数据的结果判断总体结论
                overallResult = determineOverallResult(allResult);
            }

            contrastTestResult.setResult(overallResult);
            contrastTestResult.setSpecialCase(specialCase);
            contrastTestResult.setCheckResultHarmonic(harmonicResult);

            return contrastTestResult;
        }
        return null;
    }

    /**
     * 判断值是否为零
     *
     * @param value 字符串值
     * @return 是否为零
     */
    private boolean isZeroValue(String value) {
        if (StrUtil.isBlank(value) || "/".equals(value) || "null".equals(value)) {
            return false; // 空值或无效值不算零
        }
        try {
            double d = Double.parseDouble(value);
            return d == 0.0;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    /**
     * 生成谐波类特殊情况描述
     *
     * @param zeroFilteredMap    双零过滤的次数和相别
     * @param unComparableMap    无法比较的次数和相别
     * @param unqualifiedMap     不符合的次数和相别
     * @param totalDataPoints    总数据点数
     * @param zeroFilteredPoints 双零过滤的数据点数
     * @param isInterHarmonic    是否为间谐波
     * @return 特殊情况描述
     */
    private String generateHarmonicSpecialCase(Map<Integer, List<String>> zeroFilteredMap,
                                               Map<Integer, Map<String, List<String>>> unComparableMap,
                                               Map<Integer, Map<String, List<String>>> unqualifiedMap,
                                               int totalDataPoints, int zeroFilteredPoints,
                                               boolean isInterHarmonic) {
        StringBuilder specialCaseDesc = new StringBuilder();
        boolean hasZeroFiltered = false;
        boolean allZero = false;

        // 1. 检查双零过滤情况
        if (!zeroFilteredMap.isEmpty()) {
            hasZeroFiltered = true;
            // 判断是否所有数据都是双零
            allZero = (totalDataPoints > 0 && totalDataPoints == zeroFilteredPoints);

            if (allZero) {
                // 所有次数的所有相别都是双零，直接返回
                specialCaseDesc.append("注：因所有谐波次数的标准值与被检值均为0，检测结论为符合。");
                return specialCaseDesc.toString();
            }
        }

        // 2. 处理无法比较情况
        if (!unComparableMap.isEmpty()) {
            if (specialCaseDesc.length() > 0) {
                specialCaseDesc.append(" ");
            } else {
                specialCaseDesc.append("注：");
            }

            // 合并相同情况的次数和相别
            Map<String, Map<String, List<Integer>>> groupedUnComparable = new LinkedHashMap<>();
            for (Map.Entry<Integer, Map<String, List<String>>> harmEntry : unComparableMap.entrySet()) {
                Integer harmNum = harmEntry.getKey();
                for (Map.Entry<String, List<String>> dataEntry : harmEntry.getValue().entrySet()) {
                    String numOfData = dataEntry.getKey();
                    List<String> phases = dataEntry.getValue();
                    String phaseKey = String.join("、", phases);
                    groupedUnComparable.computeIfAbsent(numOfData, k -> new LinkedHashMap<>())
                            .computeIfAbsent(phaseKey, k -> new ArrayList<>())
                            .add(harmNum);
                }
            }

            // 生成描述
            for (Map.Entry<String, Map<String, List<Integer>>> dataEntry : groupedUnComparable.entrySet()) {
                for (Map.Entry<String, List<Integer>> phaseEntry : dataEntry.getValue().entrySet()) {
                    String phases = phaseEntry.getKey();
                    List<Integer> harmNums = phaseEntry.getValue();
                    specialCaseDesc.append("第").append(formatHarmNumbers(harmNums, isInterHarmonic)).append("次谐波");
                    // 如果是T相，则不拼接相别
                    if (!"T相".equals(phases)) {
                        specialCaseDesc.append(phases);
                    }
                    specialCaseDesc.append("无样本数据满足误差比较的前置条件，无法执行有效性判定。");
                }
            }
        }

        // 3. 处理不符合情况
        if (!unqualifiedMap.isEmpty()) {
            if (specialCaseDesc.length() > 0) {
                specialCaseDesc.append(" ");
            } else {
                specialCaseDesc.append("注：");
            }

            // 重新组织数据结构：收集所有相同组数的次数-相别组合
            Map<String, List<String>> groupedByNumOfData = new LinkedHashMap<>();

            for (Map.Entry<Integer, Map<String, List<String>>> harmEntry : unqualifiedMap.entrySet()) {
                Integer harmNum = harmEntry.getKey();
                for (Map.Entry<String, List<String>> dataEntry : harmEntry.getValue().entrySet()) {
                    String numOfData = dataEntry.getKey();
                    List<String> phases = dataEntry.getValue();

                    // 如果一个次数下有多个相别，合并成一个描述
                    String harmPhaseDesc;
                    String displayHarmNum = getDisplayHarmNumber(harmNum, isInterHarmonic);
                    if (phases.size() == 1) {
                        harmPhaseDesc = "第" + displayHarmNum + "次谐波" + phases.get(0);
                    } else {
                        harmPhaseDesc = "第" + displayHarmNum + "次谐波" + String.join("、", phases);
                    }
                    groupedByNumOfData.computeIfAbsent(numOfData, k -> new ArrayList<>())
                            .add(harmPhaseDesc);
                }
            }

            // 生成描述
            for (Map.Entry<String, List<String>> entry : groupedByNumOfData.entrySet()) {
                String numOfData = entry.getKey();
                List<String> harmPhaseList = entry.getValue();

                // 合并描述：第4次谐波A相、B相、C相、第32次谐波A相、第44次谐波C相
                specialCaseDesc.append(String.join("、", harmPhaseList));
                specialCaseDesc.append("收集有效组数为").append(numOfData)
                        .append("组，误差计算结果不符合误差标准要求。");
            }
        }

        // 4. 最后添加双零过滤的笼统描述（如果有部分双零）
        if (hasZeroFiltered && !allZero) {
            if (specialCaseDesc.length() > 0) {
                specialCaseDesc.append(" ");
            } else {
                specialCaseDesc.append("注：");
            }
            specialCaseDesc.append("表格不展示标准值与被检值均为0的数据。");
        }

        return specialCaseDesc.length() > 0 ? specialCaseDesc.toString() : null;
    }

    /**
     * 获取显示用的谐波次数
     *
     * @param harmNum         原始次数（2-50）
     * @param isInterHarmonic 是否为间谐波
     * @return 显示用的次数字符串
     */
    private String getDisplayHarmNumber(int harmNum, boolean isInterHarmonic) {
        if (isInterHarmonic) {
            // 间谐波：2->1.5, 3->2.5, 4->3.5 ... 50->49.5
            double displayNum = harmNum - 0.5;
            // 如果是整数则显示整数，否则显示小数
            if (displayNum == (int) displayNum) {
                return String.valueOf((int) displayNum);
            }
            return String.valueOf(displayNum);
        }
        return String.valueOf(harmNum);
    }

    /**
     * 格式化谐波次数列表
     *
     * @param harmNumbers     谐波次数列表
     * @param isInterHarmonic 是否为间谐波
     * @return 格式化的字符串，如"2、3、5"或"2-5、7、9-11"（间谐波为"1.5、2.5、3.5"）
     */
    private String formatHarmNumbers(List<Integer> harmNumbers, boolean isInterHarmonic) {
        if (harmNumbers.isEmpty()) {
            return "";
        }
        if (harmNumbers.size() == 1) {
            return getDisplayHarmNumber(harmNumbers.get(0), isInterHarmonic);
        }

        Collections.sort(harmNumbers);

        if (isInterHarmonic) {
            // 间谐波不使用范围表示，直接用顿号分隔
            List<String> displayNumbers = new ArrayList<>();
            for (Integer harmNum : harmNumbers) {
                displayNumbers.add(getDisplayHarmNumber(harmNum, true));
            }
            return String.join("、", displayNumbers);
        } else {
            // 普通谐波使用范围表示
            List<String> parts = new ArrayList<>();
            int start = harmNumbers.get(0);
            int end = start;

            for (int i = 1; i < harmNumbers.size(); i++) {
                int current = harmNumbers.get(i);
                if (current == end + 1) {
                    end = current;
                } else {
                    if (start == end) {
                        parts.add(String.valueOf(start));
                    } else if (end - start == 1) {
                        parts.add(start + "、" + end);
                    } else {
                        parts.add(start + "-" + end);
                    }
                    start = current;
                    end = current;
                }
            }

            // 处理最后一组
            if (start == end) {
                parts.add(String.valueOf(start));
            } else if (end - start == 1) {
                parts.add(start + "、" + end);
            } else {
                parts.add(start + "-" + end);
            }

            return String.join("、", parts);
        }
    }

    /**
     * 获取非谐波类数据的结果数据
     *
     * @param monitorResultVO 数据来源信息
     * @param subScriptId     实际检测指标id
     * @param planCode        计划code，表名需要
     * @param dictTree        测试指标信息
     * @return 结果数据
     */
    private ContrastTestResult getContrastResultNonHarm(MonitorResultVO monitorResultVO, List<String> subScriptId, Integer planCode, DictTree dictTree) {
        ContrastNonHarmonicResult result = contrastNonHarmonicService.getContrastResultHarm(planCode, monitorResultVO.getMonitorId(), subScriptId, monitorResultVO.getResultType(), Integer.parseInt(monitorResultVO.getWhichTime()));
        // 收集组数数据
        int numOfData = contrastNonHarmonicService.getNumOfData(planCode, monitorResultVO.getMonitorId(), subScriptId, monitorResultVO.getResultType(), Integer.parseInt(monitorResultVO.getWhichTime()));
        if (Objects.nonNull(result)) {
            // 非谐波类
            ContrastTestResult contrastTestResult = new ContrastTestResult();
            contrastTestResult.setScriptCode(dictTree.getCode());
            contrastTestResult.setScriptName(dictTree.getName());
            contrastTestResult.setHarmonic(false);
            List<String> allResult = new ArrayList<>();
            Map<String, Map<String, String>> checkResultNonHarmonic = new LinkedHashMap<>();
            // 根据指标代码确定小数位数
            Integer decimalPlaces = getDecimalPlacesByScriptCode(dictTree.getCode());
            try {
                // 非谐波的需要注意是否为T相还是ABC三相的
                if (PowerConstant.T_PHASE.contains(dictTree.getCode())) {
                    Field field;
                    if (PowerConstant.TB_PHASE.contains(dictTree.getCode())) {
                        field = result.getClass().getDeclaredField("bValue");
                    } else {
                        field = result.getClass().getDeclaredField("tValue");
                    }
                    field.setAccessible(true);
                    String valueJson = (String) field.get(result);
                    Map<String, String> singlePhaseData = parseNonHarmonicPhaseData(valueJson, "T相", numOfData, dictTree.getCode(), decimalPlaces);
                    checkResultNonHarmonic.put("T相", singlePhaseData);
                    if (CollUtil.isNotEmpty(singlePhaseData)) {
                        String resultTemp = singlePhaseData.get(ItemReportKeyEnum.RESULT.getKey());
                        if (StrUtil.isNotBlank(resultTemp)) {
                            allResult.add(resultTemp);
                        }
                    }
                } else {
                    // ABC三相
                    for (String phase : PowerConstant.PHASE_ABC) {
                        Field field = result.getClass().getDeclaredField(phase + "Value");
                        field.setAccessible(true);
                        String valueJson = (String) field.get(result);
                        Map<String, String> singlePhaseData = parseNonHarmonicPhaseData(valueJson, phase.toUpperCase() + "相", numOfData, dictTree.getCode(), decimalPlaces);
                        checkResultNonHarmonic.put(phase.toUpperCase() + "相", singlePhaseData);
                        if (CollUtil.isNotEmpty(singlePhaseData)) {
                            String resultTemp = singlePhaseData.get(ItemReportKeyEnum.RESULT.getKey());
                            if (StrUtil.isNotBlank(resultTemp)) {
                                allResult.add(resultTemp);
                            }
                        }
                    }
                }

                // 生成 specialCase 描述
                StringBuilder specialCaseDesc = new StringBuilder();
                List<String> unComparablePhases = new ArrayList<>();
                Map<String, List<String>> unqualifiedPhasesMap = new LinkedHashMap<>(); // 按组数分组

                // 遍历每个相别的结果，收集特殊情况信息
                for (Map.Entry<String, Map<String, String>> entry : checkResultNonHarmonic.entrySet()) {
                    String phase = entry.getKey();
                    Map<String, String> phaseData = entry.getValue();
                    String phaseResult = phaseData.get(ItemReportKeyEnum.RESULT.getKey());

                    if ("无法比较".equals(phaseResult)) {
                        unComparablePhases.add(phase);
                    } else if ("不符合".equals(phaseResult)) {
                        String numOfDataStr = phaseData.get(ItemReportKeyEnum.NUM_OF_DATA.getKey());
                        // 按组数分组存储相别
                        unqualifiedPhasesMap.computeIfAbsent(numOfDataStr, k -> new ArrayList<>()).add(phase);
                    }
                }

                // 生成无法比较的描述
                if (!unComparablePhases.isEmpty()) {
                    specialCaseDesc.append("注：");
                    // 如果只有T相，则不拼接相别
                    if (unComparablePhases.size() == 1 && "T相".equals(unComparablePhases.get(0))) {
                        // T相不拼接相别
                    } else {
                        // 其他情况拼接相别
                        if (unComparablePhases.size() == 1) {
                            specialCaseDesc.append(unComparablePhases.get(0));
                        } else {
                            specialCaseDesc.append(String.join("、", unComparablePhases));
                        }
                    }
                    specialCaseDesc.append("无样本数据满足误差比较的前置条件，无法执行有效性判定。");
                }

                // 生成不符合的描述（合并相同组数的相别）
                if (!unqualifiedPhasesMap.isEmpty()) {
                    if (specialCaseDesc.length() > 0) {
                        specialCaseDesc.append(" ");
                    } else {
                        specialCaseDesc.append("注：");
                    }
                    for (Map.Entry<String, List<String>> entry : unqualifiedPhasesMap.entrySet()) {
                        String numOfDataStr = entry.getKey();
                        List<String> phases = entry.getValue();
                        if (phases.size() == 1) {
                            specialCaseDesc.append(phases.get(0));
                        } else {
                            specialCaseDesc.append(String.join("、", phases));
                        }
                        specialCaseDesc.append("收集有效组数为").append(numOfDataStr).append("组，误差计算结果不符合误差标准要求。");
                        if (unqualifiedPhasesMap.size() > 1) {
                            specialCaseDesc.append(" ");
                        }
                    }
                }

                // 设置检测结果 - 根据所有相数据的结果判断总体结论
                String overallResult = determineOverallResult(allResult);
                contrastTestResult.setResult(overallResult);
                contrastTestResult.setSpecialCase(specialCaseDesc.length() > 0 ? specialCaseDesc.toString() : null);
                contrastTestResult.setCheckResultNonHarmonic(checkResultNonHarmonic);
                return contrastTestResult;
            } catch (Exception e) {
                log.warn("获取{}数据失败", dictTree.getName());
            }
        }
        return null;
    }

    /**
     * 解析非谐波数据
     *
     * @param valueJson     JSON格式的数据
     * @param phase         相别标识
     * @param numOfData     收集组数
     * @param scriptCode    脚本代码，用于判断是否需要特殊格式化
     * @param decimalPlaces 小数位数，null则不格式化
     * @return 解析后的数据列表
     */
    private Map<String, String> parseNonHarmonicPhaseData(String valueJson, String phase, int numOfData, String scriptCode, Integer decimalPlaces) {
        try {
            // 解析JSON数据，假设是 DetectionData 对象列表
            List<DetectionData> dataList = JSON.parseArray(valueJson, DetectionData.class);
            Map<String, String> dataMap = new LinkedHashMap<>();
            if (CollUtil.isNotEmpty(dataList)) {
                DetectionData detectionData = dataList.get(0);
                // 相别
                dataMap.put(ItemReportKeyEnum.PHASE.getKey(), phase);
                // 有效组数 todo... 目前是对齐组数
                dataMap.put(ItemReportKeyEnum.NUM_OF_DATA.getKey(), String.valueOf(numOfData));
                // 标准值 - 根据参数决定是否格式化
                String standardValue = String.valueOf(detectionData.getResultData());
                if (decimalPlaces != null && detectionData.getResultData() != null) {
                    standardValue = formatSignificantDigits(detectionData.getResultData(), decimalPlaces);
                }
                dataMap.put(ItemReportKeyEnum.STANDARD.getKey(), standardValue);
                // 被检值 - 根据参数决定是否格式化
                String testValue = String.valueOf(detectionData.getData());
                if (decimalPlaces != null && detectionData.getData() != null) {
                    testValue = formatSignificantDigits(detectionData.getData(), decimalPlaces);
                }
                dataMap.put(ItemReportKeyEnum.TEST.getKey(), testValue);
                // 误差 - 根据参数决定是否格式化
                String errorValue = String.valueOf(detectionData.getErrorData());
                if (decimalPlaces != null && detectionData.getErrorData() != null) {
                    errorValue = formatSignificantDigits(detectionData.getErrorData().doubleValue(), decimalPlaces);
                } else {
                    errorValue = "/";
                }
                dataMap.put(ItemReportKeyEnum.ERROR.getKey(), errorValue);
                // 误差范围 - 根据参数决定是否格式化
                String errorScope = String.valueOf(detectionData.getRadius());
                if (decimalPlaces != null && detectionData.getRadius() != null) {
                    errorScope = formatErrorRange(detectionData.getRadius(), decimalPlaces);
                } else {
                    errorScope = "/";
                }
                dataMap.put(ItemReportKeyEnum.A_ERROR_SCOPE.getKey(), errorScope);
                // 结论
                dataMap.put(ItemReportKeyEnum.RESULT.getKey(), getTestResult(detectionData.getIsData()));
            } else {
                // 相别
                dataMap.put(ItemReportKeyEnum.PHASE.getKey(), phase);
                // 有效组数
                dataMap.put(ItemReportKeyEnum.NUM_OF_DATA.getKey(), String.valueOf(0));
                // 标准值
                dataMap.put(ItemReportKeyEnum.STANDARD.getKey(), "/");
                // 被检值
                dataMap.put(ItemReportKeyEnum.TEST.getKey(), "/");
                // 误差
                dataMap.put(ItemReportKeyEnum.ERROR.getKey(), "/");
                // 误差范围
                dataMap.put(ItemReportKeyEnum.A_ERROR_SCOPE.getKey(), "/");
                // 结论
                dataMap.put(ItemReportKeyEnum.RESULT.getKey(), "无法比较");
            }
            return dataMap;
        } catch (Exception e) {
            log.warn("获取数据失败");

        }
        return new HashMap<>();
    }


    /**
     * 根据所有相数据的检测结果判断总体指标结论
     * 判断原则：所有都符合就符合，有一个不符合就不符合，如果所有都是无法比较就无法比较
     *
     * @param allResult 所有相数据的检测结果集合
     * @return 总体指标结论
     */
    private String determineOverallResult(List<String> allResult) {
        if (CollUtil.isEmpty(allResult)) {
            return "无法比较";
        }

        // 统计各种结果的数量
        // 是否有不符合
        boolean hasUnqualified = false;
        // 是否有符合
        boolean hasQualified = false;
        // 是否有无法比较
        boolean hasUncomparable = false;

        for (String result : allResult) {
            if ("不符合".equals(result)) {
                hasUnqualified = true;
            } else if ("符合".equals(result)) {
                hasQualified = true;
            } else if ("无法比较".equals(result)) {
                hasUncomparable = true;
            }
        }

        // 按照优先级判断：有一个不符合就不符合
        if (hasUnqualified) {
            return "不符合";
        }

        // 如果没有不符合，且有符合的，就是符合
        if (hasQualified) {
            return "符合";
        }

        // 如果全部都是无法比较
        if (hasUncomparable) {
            return "无法比较";
        }

        // 默认返回无法比较（理论上不会到这里）
        return "无法比较";
    }

    /**
     * 解析谐波相数据
     *
     * @param jsonData      JSON格式的数据
     * @param phase         相别标识
     * @param harmNum       谐波次数
     * @param numOfData     收集组数
     * @param scriptCode    脚本代码，用于判断是否需要特殊格式化
     * @param decimalPlaces 小数位数，null则不格式化
     * @return 解析后的数据列表
     */
    private Map<String, String> parseHarmonicPhaseData(String jsonData, String phase, int harmNum, int numOfData, String scriptCode, Integer decimalPlaces) {
        try {
            // 解析JSON数据，假设是 DetectionData 对象列表
            List<DetectionData> dataList = JSON.parseArray(jsonData, DetectionData.class);
            Map<String, String> dataMap = new LinkedHashMap<>();
            if (CollUtil.isNotEmpty(dataList)) {
                DetectionData detectionData = dataList.get(0);
                // 次数 - 从数据对象中获取实际次数（间谐波为1.5、2.5等）
                String timeValue;
                if (detectionData.getNum() != null) {
                    double numValue = detectionData.getNum();
                    // 如果是整数，则只显示整数部分（如2.0显示为2）
                    if (numValue == Math.floor(numValue)) {
                        timeValue = String.valueOf((int) numValue);
                    } else {
                        timeValue = String.valueOf(numValue);
                    }
                } else {
                    timeValue = String.valueOf(harmNum);
                }
                dataMap.put(ItemReportKeyEnum.TIME.getKey(), timeValue);
                // 相别
                dataMap.put(ItemReportKeyEnum.PHASE.getKey(), phase);
                // 有效组数 todo... 目前是对齐组数
                dataMap.put(ItemReportKeyEnum.NUM_OF_DATA.getKey(), String.valueOf(numOfData));

                // 标准值 - 根据参数决定是否格式化
                String standardValue = String.valueOf(detectionData.getResultData());
                if (decimalPlaces != null && detectionData.getResultData() != null) {
                    standardValue = formatSignificantDigits(detectionData.getResultData(), decimalPlaces);
                }
                dataMap.put(ItemReportKeyEnum.STANDARD.getKey(), standardValue);

                // 被检值 - 根据参数决定是否格式化
                String testValue = String.valueOf(detectionData.getData());
                if (decimalPlaces != null && detectionData.getData() != null) {
                    testValue = formatSignificantDigits(detectionData.getData(), decimalPlaces);
                }
                dataMap.put(ItemReportKeyEnum.TEST.getKey(), testValue);

                // 误差 - 根据参数决定是否格式化
                String errorValue = String.valueOf(detectionData.getErrorData());
                if (decimalPlaces != null && detectionData.getErrorData() != null) {
                    errorValue = formatSignificantDigits(detectionData.getErrorData().doubleValue(), decimalPlaces);
                } else {
                    errorValue = "/";
                }
                dataMap.put(ItemReportKeyEnum.ERROR.getKey(), errorValue);

                // 误差范围 - 根据参数决定是否格式化
                String errorScope = String.valueOf(detectionData.getRadius());
                if (decimalPlaces != null && detectionData.getRadius() != null) {
                    errorScope = formatErrorRange(detectionData.getRadius(), decimalPlaces);
                } else {
                    errorScope = "/";
                }
                dataMap.put(ItemReportKeyEnum.A_ERROR_SCOPE.getKey(), errorScope);

                // 结论
                dataMap.put(ItemReportKeyEnum.RESULT.getKey(), getTestResult(detectionData.getIsData()));
            } else {
                // 次数 - 数据为空时用循环变量作为兜底
                dataMap.put(ItemReportKeyEnum.TIME.getKey(), String.valueOf(harmNum));
                // 相别
                dataMap.put(ItemReportKeyEnum.PHASE.getKey(), phase);
                // 有效组数
                dataMap.put(ItemReportKeyEnum.NUM_OF_DATA.getKey(), "0");
                // 标准值
                dataMap.put(ItemReportKeyEnum.STANDARD.getKey(), "/");
                // 被检值
                dataMap.put(ItemReportKeyEnum.TEST.getKey(), "/");
                // 误差
                dataMap.put(ItemReportKeyEnum.ERROR.getKey(), "/");
                // 误差范围
                dataMap.put(ItemReportKeyEnum.A_ERROR_SCOPE.getKey(), "/");
                // 结论
                dataMap.put(ItemReportKeyEnum.RESULT.getKey(), "无法比较");
            }
            return dataMap;
        } catch (Exception e) {
            log.error("解析{}第{}次谐波数据失败: {}", phase, harmNum, e.getMessage());
        }

        return new HashMap<>();
    }

    /**
     * 检查是否有不合格的数据
     *
     * @param dataList 数据列表
     * @return true表示有不合格数据
     */
    private boolean hasUnqualifiedData(List<Map<String, String>> dataList) {
        if (CollUtil.isEmpty(dataList)) {
            return false;
        }
        for (Map<String, String> data : dataList) {
            String resultFlag = data.get("resultFlag");
            // resultFlag: 1-合格，2-不合格，4-无法比较
            if ("2".equals(resultFlag)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取检测结果
     *
     * @param monitorResultVO 回路检测结论信息
     */
    private String getTestResult(MonitorResultVO monitorResultVO) {
        Integer checkResult = monitorResultVO.getCheckResult();
        return getTestResult(checkResult);
    }

    /**
     * 获取检测结果
     *
     * @param checkResult 回路检测结论信息
     */
    private String getTestResult(Integer checkResult) {
        switch (checkResult) {
            case 2:
                return "不符合";
            case 4:
                return "无法比较";
            default:
                // 因为只有 1、2、4，所以这里直接返回符合
                return "符合";
        }
    }

    private Map<String, List<RawResultDataVO>> getResultMap(DictTree dictTree, List<String> adTypeList, String monitorId, String unit, Integer num, Integer waveNum, Boolean isWave, String code) {
        Map<String, List<RawResultDataVO>> resultMap = new LinkedHashMap<>();

        List<ContrastNonHarmonicResult> contrastNonHarmonicResults = contrastNonHarmonicService.listAllResultData(code, num, waveNum, isWave, null, monitorId, adTypeList);
        List<ContrastHarmonicResult> contrastHarmonicResults = contrastHarmonicService.listAllResultData(code, num, waveNum, isWave, null, monitorId, adTypeList);

        if (CollUtil.isNotEmpty(contrastNonHarmonicResults)) {
            ContrastNonHarmonicResult contrastNonHarmonicResult = contrastNonHarmonicResults.get(0);
            List<RawResultDataVO.DetectionData> aList = JSON.parseArray(contrastNonHarmonicResult.getAValue() + "", RawResultDataVO.DetectionData.class);
            List<RawResultDataVO.DetectionData> bList = JSON.parseArray(contrastNonHarmonicResult.getBValue() + "", RawResultDataVO.DetectionData.class);
            List<RawResultDataVO.DetectionData> cList = JSON.parseArray(contrastNonHarmonicResult.getCValue() + "", RawResultDataVO.DetectionData.class);
            List<RawResultDataVO.DetectionData> tList = JSON.parseArray(contrastNonHarmonicResult.getTValue() + "", RawResultDataVO.DetectionData.class);

            List<RawResultDataVO> rawResultDataVOList = new ArrayList<>();
            if (CollUtil.isNotEmpty(aList) && CollUtil.isNotEmpty(bList) && CollUtil.isNotEmpty(cList)) {
                for (int i = 0; i < aList.size(); i++) {
                    RawResultDataVO dataVO = new RawResultDataVO();
                    dataVO.setUnit(unit);
                    dataVO.setDataA(aList.get(i));
                    dataVO.setDataB(bList.get(i));
                    dataVO.setDataC(cList.get(i));
                    dataVO.setRadius(aList.get(i).getRadius());
                    dataVO.setIsData(StorageUtil.setResultFlag(Arrays.asList(aList.get(i), bList.get(i), cList.get(i))));
                    rawResultDataVOList.add(dataVO);
                }
            } else if (CollUtil.isNotEmpty(bList)) {
                for (int i = 0; i < bList.size(); i++) {
                    RawResultDataVO dataVO = new RawResultDataVO();
                    dataVO.setUnit(unit);
                    dataVO.setDataB(bList.get(i));
                    dataVO.setRadius(bList.get(i).getRadius());
                    dataVO.setIsData(StorageUtil.setResultFlag(Arrays.asList(bList.get(i))));
                    rawResultDataVOList.add(dataVO);
                }
            } else if (CollUtil.isNotEmpty(tList)) {
                for (int i = 0; i < tList.size(); i++) {
                    RawResultDataVO dataVO = new RawResultDataVO();
                    dataVO.setUnit(unit);
                    dataVO.setDataT(tList.get(i));
                    dataVO.setRadius(tList.get(i).getRadius());
                    dataVO.setIsData(StorageUtil.setResultFlag(Arrays.asList(tList.get(i))));
                    rawResultDataVOList.add(dataVO);
                }
            }
            resultMap.put(dictTree.getName(), rawResultDataVOList);
        }

        if (CollUtil.isNotEmpty(contrastHarmonicResults)) {
            ContrastHarmonicResult contrastHarmonicResult = contrastHarmonicResults.get(0);
            List<Double> harmonicNum = null;
            if (PowerIndexEnum.HV.getKey().equals(dictTree.getCode()) || PowerIndexEnum.HI.getKey().equals(dictTree.getCode()) || PowerIndexEnum.HP.getKey().equals(dictTree.getCode())) {
                harmonicNum = Stream.iterate(2.0, n -> n + 1).limit(49).collect(Collectors.toList());
            }
            if (PowerIndexEnum.HSV.getKey().equals(dictTree.getCode()) || PowerIndexEnum.HSI.getKey().equals(dictTree.getCode())) {
                harmonicNum = Stream.iterate(0.5, n -> n + 1).limit(50).collect(Collectors.toList());
            }
            for (Double n : harmonicNum) {
                try {
                    int i = StorageUtil.isHarmOrInHarm(n).intValue();

                    Field fieldA = contrastHarmonicResult.getClass().getDeclaredField("aValue" + i);
                    fieldA.setAccessible(true);
                    List<RawResultDataVO.DetectionData> aList = JSON.parseArray(fieldA.get(contrastHarmonicResult) + "", RawResultDataVO.DetectionData.class);

                    Field fieldB = contrastHarmonicResult.getClass().getDeclaredField("bValue" + i);
                    fieldB.setAccessible(true);
                    List<RawResultDataVO.DetectionData> bList = JSON.parseArray(fieldB.get(contrastHarmonicResult) + "", RawResultDataVO.DetectionData.class);

                    Field fieldC = contrastHarmonicResult.getClass().getDeclaredField("cValue" + i);
                    fieldC.setAccessible(true);
                    List<RawResultDataVO.DetectionData> cList = JSON.parseArray(fieldC.get(contrastHarmonicResult) + "", RawResultDataVO.DetectionData.class);

                    List<RawResultDataVO> rawResultDataVOList = new ArrayList<>();
                    List<Integer> isDataList = new ArrayList<>();
                    for (int j = 0; j < aList.size(); j++) {
                        RawResultDataVO dataVO = new RawResultDataVO();
                        dataVO.setHarmNum(n);
                        dataVO.setUnit(unit);
                        dataVO.setDataA(aList.get(j));
                        dataVO.setDataB(bList.get(j));
                        dataVO.setDataC(cList.get(j));
                        dataVO.setRadius(aList.get(j).getRadius());
                        dataVO.setIsData(StorageUtil.setResultFlag(Arrays.asList(aList.get(j), bList.get(j), cList.get(j))));
                        isDataList.add(dataVO.getIsData());
                        rawResultDataVOList.add(dataVO);
                    }
                    Integer isData = StorageUtil.getInteger(isDataList);
                    resultMap.put(n + (isData == ResultEnum.NOT_QUALIFIED.getValue() ? "(不符合)" : (isData == ResultEnum.NO_ERROR_SYS.getValue() ? "(/)" : "")), rawResultDataVOList);
                } catch (NoSuchFieldException e) {
                    throw new RuntimeException(e);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return resultMap;
    }

    private Map<String, List<AlignDataVO.RawData>> getRawDataMap(DictTree dictTree, List<String> adTypeList, String monitorId, String unit, Integer num, Integer waveNum, Boolean isWave, String code, List<String> keys) {
        Map<String, List<AlignDataVO.RawData>> rawMap = new LinkedHashMap<>();

        List<ContrastNonHarmonicResult> devNonHarmonicRawDataList = contrastNonHarmonicService.listAllRawData(code, num, waveNum, isWave, null, 0, monitorId, adTypeList);
        List<ContrastNonHarmonicResult> stdDevNonHarmonicRawDataList = contrastNonHarmonicService.listAllRawData(code, num, waveNum, isWave, null, 1, monitorId, adTypeList);
        List<ContrastHarmonicResult> devHarmonicRawDataList = contrastHarmonicService.listAllRawData(code, num, waveNum, isWave, null, 0, monitorId, adTypeList);
        List<ContrastHarmonicResult> stdDevHarmonicRawDataList = contrastHarmonicService.listAllRawData(code, num, waveNum, isWave, null, 1, monitorId, adTypeList);

        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
        List<AlignDataVO.RawData> rawDataVOList = new ArrayList<>();
        for (int i = 0; i < devNonHarmonicRawDataList.size(); i++) {
            AlignDataVO.RawData rawDataVO = new AlignDataVO.RawData();
            rawDataVO.setUnit(unit);
            ContrastNonHarmonicResult contrastNonHarmonicResultDev = devNonHarmonicRawDataList.get(i);
            rawDataVO.setTimeDev(contrastNonHarmonicResultDev.getTimeId().format(dtf));

            rawDataVO.setUbDev(getValue(contrastNonHarmonicResultDev.getBValue()));
            rawDataVO.setUtDev(getValue(contrastNonHarmonicResultDev.getTValue()));

            ContrastNonHarmonicResult contrastNonHarmonicResultStdDev = stdDevNonHarmonicRawDataList.get(i);
            rawDataVO.setTimeStdDev(contrastNonHarmonicResultStdDev.getTimeId().format(dtf));
            if (!PowerIndexEnum.IMBV.getKey().equals(dictTree.getCode()) && !PowerIndexEnum.IMBA.getKey().equals(dictTree.getCode())) {
                rawDataVO.setUaDev(getValue(contrastNonHarmonicResultDev.getAValue()));
                rawDataVO.setUcDev(getValue(contrastNonHarmonicResultDev.getCValue()));
                rawDataVO.setUaStdDev(getValue(contrastNonHarmonicResultStdDev.getAValue()));
                rawDataVO.setUcStdDev(getValue(contrastNonHarmonicResultStdDev.getCValue()));
            }

            rawDataVO.setUbStdDev(getValue(contrastNonHarmonicResultStdDev.getBValue()));
            rawDataVO.setUtStdDev(getValue(contrastNonHarmonicResultStdDev.getTValue()));

            rawDataVOList.add(rawDataVO);
        }
        if (CollUtil.isNotEmpty(rawDataVOList)) {
            rawMap.put(dictTree.getName(), rawDataVOList);
        }

        if (CollUtil.isNotEmpty(devHarmonicRawDataList) && CollUtil.isNotEmpty(stdDevHarmonicRawDataList)) {
            List<Double> harmonicNum = null;
            boolean isHarm = true;
            if (PowerIndexEnum.HV.getKey().equals(dictTree.getCode()) || PowerIndexEnum.HI.getKey().equals(dictTree.getCode()) || PowerIndexEnum.HP.getKey().equals(dictTree.getCode())) {
                harmonicNum = Stream.iterate(2.0, n -> n + 1).limit(49).collect(Collectors.toList());
                isHarm = true;
            }
            if (PowerIndexEnum.HSV.getKey().equals(dictTree.getCode()) || PowerIndexEnum.HSI.getKey().equals(dictTree.getCode())) {
                harmonicNum = Stream.iterate(0.5, n -> n + 1).limit(50).collect(Collectors.toList());
                isHarm = false;
            }
            for (Double n : harmonicNum) {
                List<AlignDataVO.RawData> rawDataVOList1 = new ArrayList<>();
                int i = StorageUtil.isHarmOrInHarm(n).intValue();
                for (int j = 0; j < devHarmonicRawDataList.size(); j++) {
                    AlignDataVO.RawData rawDataVO = new AlignDataVO.RawData();
                    rawDataVO.setUnit(unit);
                    ContrastHarmonicResult devHarmonicResult = devHarmonicRawDataList.get(j);
                    ContrastHarmonicResult stdDevHarmonicResult = stdDevHarmonicRawDataList.get(j);

                    rawDataVO.setTimeDev(devHarmonicResult.getTimeId().format(dtf));
                    rawDataVO.setTimeStdDev(stdDevHarmonicResult.getTimeId().format(dtf));

                    try {
                        Field fieldA = devHarmonicResult.getClass().getDeclaredField("aValue" + i);
                        fieldA.setAccessible(true);
                        Double aValue = JSON.parseObject(fieldA.get(devHarmonicResult) + "", Double.class);

                        rawDataVO.setUaDev(aValue);
                        Field fieldB = devHarmonicResult.getClass().getDeclaredField("bValue" + i);
                        fieldB.setAccessible(true);
                        Double bValue = JSON.parseObject(fieldB.get(devHarmonicResult) + "", Double.class);
                        rawDataVO.setUbDev(bValue);

                        Field fieldC = devHarmonicResult.getClass().getDeclaredField("cValue" + i);
                        fieldC.setAccessible(true);
                        Double cValue = JSON.parseObject(fieldC.get(devHarmonicResult) + "", Double.class);
                        rawDataVO.setUcDev(cValue);

                        Field fieldAStdDev = stdDevHarmonicResult.getClass().getDeclaredField("aValue" + i);
                        fieldAStdDev.setAccessible(true);
                        Double aValueStdDev = JSON.parseObject(fieldAStdDev.get(stdDevHarmonicResult) + "", Double.class);
                        rawDataVO.setUaStdDev(aValueStdDev);

                        Field fieldBStdDev = stdDevHarmonicResult.getClass().getDeclaredField("bValue" + i);
                        fieldBStdDev.setAccessible(true);
                        Double bValueStdDev = JSON.parseObject(fieldBStdDev.get(stdDevHarmonicResult) + "", Double.class);
                        rawDataVO.setUbStdDev(bValueStdDev);

                        Field fieldCStdDev = stdDevHarmonicResult.getClass().getDeclaredField("cValue" + i);
                        fieldCStdDev.setAccessible(true);
                        Double cValueStdDev = JSON.parseObject(fieldCStdDev.get(stdDevHarmonicResult) + "", Double.class);
                        rawDataVO.setUcStdDev(cValueStdDev);
                    } catch (NoSuchFieldException e) {
                        throw new RuntimeException(e);
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }
                    rawDataVOList1.add(rawDataVO);
                }
                int num1 = n.intValue();
                num1 = isHarm ? num1 - 2 : num1;
                String key = keys.get(num1);
                rawMap.put(key, rawDataVOList1);
            }
        }

        return rawMap;
    }

    private Double getValue(String value) {
        if (ObjectUtil.isNull(value)) {
            return null;
        } else {
            return Double.valueOf(value);
        }
    }


    private Integer conform(Set<Integer> numbers) {
        if (CollUtil.isNotEmpty(numbers)) {
            if (numbers.size() > 1) {
                if (numbers.contains(2)) {
                    return 2;
                }
            }
            return numbers.iterator().next();
        } else {
            return 4;
        }
    }

    private boolean isTPhase(List<RawDataVO> rawDataVOList) {
        String dataT = rawDataVOList.get(0).getDataT();
        if (ObjectUtil.isNotNull(dataT)) {
            return true;
        }
        return false;
    }

    /**
     * 拷贝结果表
     *
     * @param code
     * @param isContrast
     */
    private void createTempResultTable(String code, boolean isContrast) {
        this.dropTempResultTable(code);
        String oldCode = code.replace("_temp", "");
        tableGenMapper.genNonHarmonicResultTable(code, isContrast);
        StringBuilder A = new StringBuilder();
        StringBuilder B = new StringBuilder();
        StringBuilder C = new StringBuilder();
        for (int i = 1; i <= 50; i++) {
            if (i == 1) {
                A.append("A_Value_").append(i).append(" json  NULL COMMENT 'A相基波',");
                B.append("B_Value_").append(i).append(" json  NULL COMMENT 'B相基波',");
                C.append("C_Value_").append(i).append(" json  NULL COMMENT 'C相基波',");
            } else {
                A.append("A_Value_").append(i).append(" json  NULL COMMENT '").append(i).append("次A相谐波',");
                B.append("B_Value_").append(i).append(" json  NULL COMMENT '").append(i).append("次B相谐波',");
                C.append("C_Value_").append(i).append(" json  NULL COMMENT '").append(i).append("次C相谐波',");
            }
        }

        String sql1 = "CREATE TABLE if not exists AD_Harmonic_Result_" + code + " (\n" +
                "    Dev_Monitor_Id CHAR(34) NOT NULL COMMENT '监测点Id',\n" +
                "    Time_Id DATETIME(3) NULL COMMENT '时间',\n" +
                "    AD_Type CHAR(32) NOT NULL COMMENT '检测指标，字典表',\n" +
                "    Data_Type CHAR(32) NOT NULL COMMENT '数据指标，只有数据源为分钟统计时候才会使用（最大、最小、平均、CP95，默认平均值），字典表',\n" +
                "    Result_Flag int(1) NOT NULL COMMENT '1合格 2不合格 4无法处理',\n" +
                A + B + C +
                (isContrast ?
                        "Id char(32) COLLATE utf8mb4_bin NOT NULL COMMENT '主键Id',\n" +
                                "Std_Dev_Monitor_Id CHAR(34) NOT NULL COMMENT '标准设备监测点Id',\n" +
                                "Num tinyint(1) unsigned DEFAULT 0 COMMENT '第几次检测',\n" +
                                "Flag tinyint(1) unsigned DEFAULT NULL COMMENT '0表示被检设备数据，1表示标准设备数据',\n" +
                                "A_Value_0 json  NULL COMMENT 'A相基波有效值',\n" +
                                "B_Value_0 json  NULL COMMENT 'B相基波有效值',\n" +
                                "C_Value_0 json  NULL COMMENT 'B相基波有效值',\n" +
                                "Wave_Num tinyint(1) unsigned DEFAULT null COMMENT '录波数据第几组',\n" +
                                "PRIMARY KEY (Id)\n"
                        :
                        "    Script_Id CHAR(32) NOT NULL COMMENT '检测脚本表Id',\n" +
                                "    Sort int(4) NOT NULL COMMENT '总检测脚本中的测试项序号',\n" +
                                "    PRIMARY KEY (Dev_Monitor_Id,Script_Id, Sort, AD_Type)\n"
                ) + ") COMMENT='谐波类检测结果表';";
        tableGenMapper.genAdHarmonicTable(sql1);

        sql1 = "CREATE TABLE ad_non_harmonic_" + code + " LIKE ad_non_harmonic_" + oldCode;
        tableGenMapper.genAdHarmonicTable(sql1);
        sql1 = "INSERT INTO ad_non_harmonic_" + code + " SELECT * FROM ad_non_harmonic_" + oldCode;
        tableGenMapper.genAdHarmonicTable(sql1);
        sql1 = "CREATE TABLE ad_harmonic_" + code + " LIKE ad_harmonic_" + oldCode;
        tableGenMapper.genAdHarmonicTable(sql1);
        sql1 = "INSERT INTO ad_harmonic_" + code + " SELECT * FROM ad_harmonic_" + oldCode;
        tableGenMapper.genAdHarmonicTable(sql1);
    }

    private void dropTempResultTable(String code) {
        tableGenMapper.genAdHarmonicTable("drop table if exists AD_Non_Harmonic_Result_" + code + ",AD_Harmonic_Result_" + code + "," + "ad_non_harmonic_" + code + "," + "ad_harmonic_" + code);
    }

    /**
     * 数模-根据原始数据、误差体系id、计算检测结果
     *
     * @param planId
     * @param code
     * @param errorSysId
     * @param devId
     */
    private void simAndDigCalculateResult(String planId, String scriptId, String code, String errorSysId, String devId, String dataRuleId) {
        String oldCode = code.replace("_temp", "");
        PreDetectionParam param = new PreDetectionParam();
        param.setCode(code);
        param.setErrorSysId(errorSysId);
        param.setDevIds(Arrays.asList(devId));

        Map<String, String> devIdMapComm = new HashMap<>();
//        PqDev dev = pqDevService.getById(devId);
        devIdMapComm.put(devId, devId);

        DictDataEnum dataRule;
//        SysTestConfig oneConfig = sysTestConfigService.getOneConfig();
//        if (ObjectUtil.isNotNull(oneConfig)) {
//            dataRule = DictDataEnum.getDictDataEnumByCode(oneConfig.getDataRule());
//        } else {
//            dataRule = DictDataEnum.SECTION_VALUE;
//        }
//        AdPlan plan = adPlanService.getById(planId);
        DictData dictData = dictDataService.getDictDataById(dataRuleId);
        if (ObjectUtil.isNotNull(dictData)) {
            dataRule = DictDataEnum.getDictDataEnumByCode(dictData.getCode());
        } else {
            dataRule = DictDataEnum.SECTION_VALUE;
        }

        List<SimAndDigNonHarmonicResult> allNonHarmonicRawData = simAndDigNonHarmonicService.listAllSimAndDigRawData(scriptId, oldCode, devId);
        LinkedHashMap<Integer, List<SimAndDigNonHarmonicResult>> nonHarmonicMap = allNonHarmonicRawData.stream().sorted(Comparator.comparing(SimAndDigNonHarmonicResult::getSort))
                .collect(Collectors.groupingBy(SimAndDigNonHarmonicResult::getSort, LinkedHashMap::new, Collectors.toList()));
        List<SimAndDigHarmonicResult> allHarmonicRawData = simAndDigHarmonicService.listAllRawData(scriptId, oldCode, devId);
        LinkedHashMap<Integer, List<SimAndDigHarmonicResult>> harmonicMap = allHarmonicRawData.stream().sorted(Comparator.comparing(SimAndDigHarmonicResult::getSort))
                .collect(Collectors.groupingBy(SimAndDigHarmonicResult::getSort, LinkedHashMap::new, Collectors.toList()));

        PqScriptIssueParam issueParam = new PqScriptIssueParam();
        issueParam.setPlanId(planId);
//        issueParam.setSourceId();
//        issueParam.setScriptType();
//        issueParam.setScriptSubType();

        issueParam.setDevIds(Arrays.asList(devId));
        issueParam.setScriptId(scriptId);
        issueParam.setIsPhaseSequence(CommonEnum.FORMAL_TEST.getValue());
        List<SourceIssue> sourceIssues = pqScriptDtlsService.listSourceIssue(issueParam);

        sourceIssues.forEach(sourceIssue -> {
            List<SimAndDigNonHarmonicResult> nonHarmonicResults = nonHarmonicMap.get(sourceIssue.getIndex());
            List<SimAndDigHarmonicResult> harmonicResults = harmonicMap.get(sourceIssue.getIndex());
            List<DevData> realDataXiList = new ArrayList<>();
            if (CollUtil.isNotEmpty(nonHarmonicResults)) {
                realDataXiList.addAll(this.simAndDigToList(nonHarmonicResults, null, true));
            }
            if (CollUtil.isNotEmpty(harmonicResults)) {
                if (DetectionCodeEnum.V2_50.getCode().equals(harmonicResults.get(0).getAdType()) || DetectionCodeEnum.I2_50.getCode().equals(harmonicResults.get(0).getAdType()) || DetectionCodeEnum.P2_50.getCode().equals(harmonicResults.get(0).getAdType())) {
                    realDataXiList.addAll(this.simAndDigToList(null, harmonicResults, true));
                } else {
                    realDataXiList.addAll(this.simAndDigToList(null, harmonicResults, false));
                }
            }

            detectionServiceImpl.processing(realDataXiList, param, devIdMapComm, sourceIssue, dataRule);
        });

        PqScriptCheckDataParam checkDataParam = new PqScriptCheckDataParam();
        checkDataParam.setScriptId(scriptId);
        checkDataParam.setIsValueTypeName(false);
        List<String> valueType = iPqScriptCheckDataService.getValueType(checkDataParam);

        iPqDevService.updateResult(param.getDevIds(), valueType, param.getCode(), param.getUserId(), param.getTemperature(), param.getHumidity(), false);
    }

    /**
     * 比对-根据原始数据、误差体系id、计算检测结果
     *
     * @param planId
     * @param code
     * @param errorSysId
     * @param deviceId
     * @param updateResult
     */
    private void contrastCalculateResult(String planId, String code, String errorSysId, String deviceId, boolean updateResult, String dataRuleId) {
        String oldCode = code.replace("_temp", "");

        Map<String, String> devIdMapComm = new HashMap<>();
        PqDev dev = pqDevService.getById(deviceId);
        devIdMapComm.put(dev.getIp(), deviceId);

        AdPlan plan = adPlanService.getById(planId);

        String dataSourceId = plan.getDatasourceId();
        String[] dataSourceIds = dataSourceId.split(StrUtil.COMMA);

        DataSourceEnum nonWaveDataSourceEnum = DataSourceEnum.REAL_DATA;
        for (String ds : dataSourceIds) {
            DataSourceEnum dataSourceEnum = DataSourceEnum.ofByValue(ds);
            switch (dataSourceEnum) {
                case MINUTE_STATISTICS_MIN:
                    nonWaveDataSourceEnum = MINUTE_STATISTICS_MIN;
                    break;
                case MINUTE_STATISTICS_MAX:
                    nonWaveDataSourceEnum = MINUTE_STATISTICS_MAX;
                    break;
                case MINUTE_STATISTICS_AVG:
                    nonWaveDataSourceEnum = DataSourceEnum.MINUTE_STATISTICS_AVG;
                    break;
                case MINUTE_STATISTICS_CP95:
                    nonWaveDataSourceEnum = MINUTE_STATISTICS_CP95;
                    break;
            }
        }
        DataSourceEnum finalNonWaveDataSourceEnum = nonWaveDataSourceEnum;

        BiMap<String, String> testItemMap = HashBiMap.create();
        List<String> testItemIds = Arrays.asList(plan.getTestItem().split(","));
        List<DictTree> dictTreeList = dictTreeService.getDictTreeById(testItemIds);
        List<String> fatherIdList = dictTreeList.stream().map(DictTree::getId).collect(Collectors.toList());
        List<DictTree> childDictTreeList = dictTreeService.listByFatherIds(fatherIdList);
        if (CollUtil.isNotEmpty(childDictTreeList)) {
            List<String> collect1 = SocketContrastResponseService.testItemCodeMap.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
            testItemMap.putAll(childDictTreeList.stream().filter(x -> collect1.contains(x.getCode())).collect(Collectors.toMap(obj -> DetectionCodeEnum.REAL_PREFIX.getCode() + obj.getCode(), obj -> obj.getId())));
        }

        DictDataEnum dataRule;
        DictData dictData = dictDataService.getDictDataById(dataRuleId);
        if (ObjectUtil.isNotNull(dictData)) {
            dataRule = DictDataEnum.getDictDataEnumByCode(dictData.getCode());
        } else {
            dataRule = DictDataEnum.SECTION_VALUE;
        }

        if (updateResult) {
            pqMonitorService.lambdaUpdate().set(PqMonitor::getRecordedResult, null)
                    .set(PqMonitor::getRealtimeNum, null)
                    .set(PqMonitor::getRecordedResult, null)
                    .set(PqMonitor::getRecordedNum, null)
                    .set(PqMonitor::getStatisticsResult, null)
                    .set(PqMonitor::getStatisticsNum, null)
                    .set(PqMonitor::getResultType, null)
                    .set(PqMonitor::getQualifiedNum, 0)
                    .eq(PqMonitor::getDevId, deviceId)
//                    .eq(PqMonitor::getNum, Integer.parseInt(chnNum))
                    .eq(PqMonitor::getCheckFlag, 1)
                    .update();
        }

//        String monitorId = deviceId + CnSocketUtil.SPLIT_TAG + chnNum;
        List<AdPair> adPairList = adPairService.listByDevIds(Arrays.asList(deviceId));
        Map<Integer, List<AdPair>> numAdPairsMap = adPairList.stream().collect(Collectors.groupingBy(AdPair::getNum, Collectors.toList()));

        numAdPairsMap.forEach((num, pairList) -> {
            Map<String, Integer> numMap = new HashMap<>();
            Map<String, List<AdPair>> devMonitroIdMap = pairList.stream().collect(Collectors.groupingBy(AdPair::getDevMonitorId, Collectors.toList()));
            devMonitroIdMap.forEach((devMonitorId, pairList1) -> {
                BiMap<String, String> parsIp = HashBiMap.create();
                BiMap<String, String> parsId = HashBiMap.create();
                String[] split1 = devMonitorId.split(CnSocketUtil.SPLIT_TAG);
                AdPair adPair = pairList1.get(0);
                String[] split2 = adPair.getStdDevMonitorId().split(CnSocketUtil.SPLIT_TAG);

                PqStandardDev standardDev = standardDevService.getById(split2[0]);
                parsIp.put(dev.getIp() + CnSocketUtil.SPLIT_TAG + split1[1], standardDev.getIp() + CnSocketUtil.SPLIT_TAG + split2[1]);
                parsId.put(dev.getId() + CnSocketUtil.SPLIT_TAG + split1[1], standardDev.getId() + CnSocketUtil.SPLIT_TAG + split2[1]);
                numMap.put(devMonitorId, num);
                numMap.put(adPair.getStdDevMonitorId(), num);
                devIdMapComm.put(standardDev.getIp(), standardDev.getId());

                List<ContrastNonHarmonicResult> devNonHarmonicRawDataList = contrastNonHarmonicService.listAllRawData(oldCode, num, null, false, null, 0, devMonitorId, null);
                List<ContrastNonHarmonicResult> stdDevNonHarmonicRawDataList = contrastNonHarmonicService.listAllRawData(oldCode, num, null, false, null, 1, devMonitorId, null);
                List<ContrastHarmonicResult> devHarmonicRawDataList = contrastHarmonicService.listAllRawData(oldCode, num, null, false, null, 0, devMonitorId, null);
                List<ContrastHarmonicResult> stdDevHarmonicRawDataList = contrastHarmonicService.listAllRawData(oldCode, num, null, false, null, 1, devMonitorId, null);

                List<DevData> devData = contrastToList(devNonHarmonicRawDataList, devHarmonicRawDataList, testItemMap, 0);
                List<DevData> standardDevData = contrastToList(stdDevNonHarmonicRawDataList, stdDevHarmonicRawDataList, testItemMap, 1);

                if (CollUtil.isNotEmpty(devData) && CollUtil.isNotEmpty(standardDevData)) {
                    detectionServiceImpl.processing(devData, standardDevData, parsIp, devIdMapComm, testItemMap.keySet().stream().collect(Collectors.toList()), errorSysId, dataRule, numMap, code, null, finalNonWaveDataSourceEnum);

                    if (updateResult) {
                        pqMonitorService.updateMonitorResult(devMonitorId, null, finalNonWaveDataSourceEnum, num, null, oldCode);
                        pqDevService.updateResult(split1[0], null);
                    }
                }

                AdPlanTestConfig adPlanTestConfig = adPlanTestConfigService.getByPlanId(planId);
                for (int i = 1; i <= adPlanTestConfig.getWaveRecord(); i++) {
                    devNonHarmonicRawDataList = contrastNonHarmonicService.listAllRawData(oldCode, num, i, true, null, 0, devMonitorId, null);
                    stdDevNonHarmonicRawDataList = contrastNonHarmonicService.listAllRawData(oldCode, num, i, true, null, 1, devMonitorId, null);
                    devHarmonicRawDataList = contrastHarmonicService.listAllRawData(oldCode, num, i, true, null, 0, devMonitorId, null);
                    stdDevHarmonicRawDataList = contrastHarmonicService.listAllRawData(oldCode, num, i, true, null, 1, devMonitorId, null);

                    devData = contrastToList(devNonHarmonicRawDataList, devHarmonicRawDataList, testItemMap, 0);
                    standardDevData = contrastToList(stdDevNonHarmonicRawDataList, stdDevHarmonicRawDataList, testItemMap, 1);
                    detectionServiceImpl.processing(devData, standardDevData, parsIp, devIdMapComm, testItemMap.keySet().stream().collect(Collectors.toList()), errorSysId, dataRule, numMap, oldCode, i, DataSourceEnum.WAVE_DATA);
                }

                if (updateResult) {
                    pqMonitorService.updateMonitorResult(devMonitorId, null, WAVE_DATA, num, adPlanTestConfig.getWaveRecord(), oldCode);
                    pqDevService.updateResult(split1[0], null);
                }
            });
        });
    }

    private List<DevData> simAndDigToList(List<SimAndDigNonHarmonicResult> nonHarm, List<SimAndDigHarmonicResult> harm, boolean containBaseHarm) {
        List<DevData> info = new ArrayList<>();
//        if (CollUtil.isNotEmpty(nonHarm)) {
        if (CollUtil.isNotEmpty(nonHarm)) {
            Map<String, List<SimAndDigNonHarmonicResult>> noHarmMap = nonHarm.stream()
                    .collect(Collectors.groupingBy(x -> x.getDevMonitorId() + "_" + x.getTimeId().format(DateTimeFormatter.ofPattern(DatePattern.UTC_SIMPLE_MS_PATTERN)) + "_" + x.getSort()));
            noHarmMap.forEach((key, value) -> {
                String[] split = key.split("_");
                DevData data = new DevData();
                data.setTime(split[2]);
                data.setId(split[0] + "_" + split[1]);
                List<DevData.SqlDataDTO> sqlDataDTOS = new ArrayList<>();
                DevData.SqlDataDTO sqlDataDTO;
                for (SimAndDigNonHarmonicResult result : value) {
                    sqlDataDTO = new DevData.SqlDataDTO();
                    sqlDataDTO.setType(result.getDataType());
                    sqlDataDTO.setDesc(result.getAdType());
                    DevData.SqlDataDTO.ListDTO listDTO = new DevData.SqlDataDTO.ListDTO();
                    listDTO.setA(StrUtil.isNotBlank(result.getAValue()) ? Double.valueOf(result.getAValue()) : null);
                    listDTO.setB(StrUtil.isNotBlank(result.getBValue()) ? Double.valueOf(result.getBValue()) : null);
                    listDTO.setC(StrUtil.isNotBlank(result.getCValue()) ? Double.valueOf(result.getCValue()) : null);
                    listDTO.setT(StrUtil.isNotBlank(result.getTValue()) ? Double.valueOf(result.getTValue()) : null);
                    sqlDataDTO.setList(listDTO);
                    sqlDataDTOS.add(sqlDataDTO);
                }
                data.setSqlData(sqlDataDTOS);
                info.add(data);
            });
        }
        if (CollUtil.isNotEmpty(harm)) {
            Map<String, List<SimAndDigHarmonicResult>> harmMap = harm.stream()
                    .collect(Collectors.groupingBy(x -> x.getDevMonitorId() + "_" + x.getTimeId().format(DateTimeFormatter.ofPattern(DatePattern.UTC_SIMPLE_MS_PATTERN))));
            harmMap.forEach((key, value) -> {
                List<DevData> collect = info.stream().filter(x -> key.equals(x.getId() + "_" + x.getTime())).collect(Collectors.toList());
                List<DevData.SqlDataDTO> sqlDataDTOS = new ArrayList<>();
                DevData.SqlDataDTO sqlDataDTO;
                List<DevData.SqlDataHarmDTO> sqlDataHarmDTOS = new ArrayList<>();
                DevData.SqlDataHarmDTO dataHarmDTO;
                for (SimAndDigHarmonicResult harmonicResult : value) {
                    if (containBaseHarm) {
                        sqlDataDTO = new DevData.SqlDataDTO();
                        sqlDataDTO.setType(harmonicResult.getDataType());
                        if (DetectionCodeEnum.V2_50.getCode().equals(harmonicResult.getAdType())) {
                            sqlDataDTO.setDesc(DetectionCodeEnum.U1.getCode());
                        } else if (DetectionCodeEnum.I2_50.getCode().equals(harmonicResult.getAdType())) {
                            sqlDataDTO.setDesc(DetectionCodeEnum.I1.getCode());
                        } else {
                            sqlDataDTO.setDesc(harmonicResult.getAdType());
                        }
                        DevData.SqlDataDTO.ListDTO listDTO = new DevData.SqlDataDTO.ListDTO();
                        listDTO.setA(StrUtil.isNotBlank(harmonicResult.getAValue1()) ? Double.valueOf(harmonicResult.getAValue1()) : null);
                        listDTO.setB(StrUtil.isNotBlank(harmonicResult.getBValue1()) ? Double.valueOf(harmonicResult.getBValue1()) : null);
                        listDTO.setC(StrUtil.isNotBlank(harmonicResult.getCValue1()) ? Double.valueOf(harmonicResult.getCValue1()) : null);
                        sqlDataDTO.setList(listDTO);
                        sqlDataDTOS.add(sqlDataDTO);
                    }

                    dataHarmDTO = new DevData.SqlDataHarmDTO();
                    dataHarmDTO.setType(harmonicResult.getDataType());
                    dataHarmDTO.setDesc(harmonicResult.getAdType());
                    dataHarmDTO.setNum(containBaseHarm ? 49 : 50);
                    DevData.SqlDataHarmDTO.ListDTO listHarmDTO = new DevData.SqlDataHarmDTO.ListDTO();
                    listHarmDTO.setA(reflectHarmonicValue("a", harmonicResult, containBaseHarm));
                    listHarmDTO.setB(reflectHarmonicValue("b", harmonicResult, containBaseHarm));
                    listHarmDTO.setC(reflectHarmonicValue("c", harmonicResult, containBaseHarm));
                    dataHarmDTO.setList(listHarmDTO);
                    sqlDataHarmDTOS.add(dataHarmDTO);
                }
                if (CollUtil.isNotEmpty(collect)) {
                    collect.get(0).setSqlDataHarm(sqlDataHarmDTOS);
                } else {
                    String[] split = key.split("_");
                    DevData data = new DevData();
                    data.setTime(split[2]);
                    data.setId(split[0] + "_" + split[1]);
                    data.setSqlData(sqlDataDTOS);
                    data.setSqlDataHarm(sqlDataHarmDTOS);
                    info.add(data);
                }
            });

        }
        return info;
    }

    private List<DevData> contrastToList(List<ContrastNonHarmonicResult> nonHarm, List<ContrastHarmonicResult> harm, BiMap<String, String> testItemMap, Integer flag) {
        List<DevData> info = new ArrayList<>();

        Map<String, List<ContrastNonHarmonicResult>> devMonitorIdMap1 = null;
        if (flag == 0) {
            devMonitorIdMap1 = nonHarm.stream().collect(Collectors.groupingBy(ContrastNonHarmonicResult::getDevMonitorId, Collectors.toList()));
        } else {
            devMonitorIdMap1 = nonHarm.stream().collect(Collectors.groupingBy(ContrastNonHarmonicResult::getStdDevMonitorId, Collectors.toList()));
        }
        devMonitorIdMap1.forEach((devMonitorId, value) -> {
            Map<LocalDateTime, List<ContrastNonHarmonicResult>> timeListMap = value.stream().collect(Collectors.groupingBy(ContrastNonHarmonicResult::getTimeId, Collectors.toList()));
            timeListMap.forEach((time, value1) -> {
                DevData devData = new DevData();
                String[] split = devMonitorId.split(CnSocketUtil.SPLIT_TAG);
                if (flag == 0) {
                    PqDev dev = pqDevService.getById(split[0]);
                    devData.setId(dev.getIp() + CnSocketUtil.SPLIT_TAG + split[1]);
                } else {
                    PqStandardDev standardDev = pqStandardDevService.getById(split[0]);
                    devData.setId(standardDev.getIp() + CnSocketUtil.SPLIT_TAG + split[1]);
                }
                devData.setTime(time.format(DateTimeFormatter.ofPattern(DatePattern.ISO8601_PATTERN)));
                List<DevData.SqlDataDTO> sqlData = new ArrayList<>();

                value1.forEach(x -> {
                    DevData.SqlDataDTO sqlDataDTO = new DevData.SqlDataDTO();
                    DevData.SqlDataDTO.ListDTO listDTO = new DevData.SqlDataDTO.ListDTO();
                    listDTO.setA(StrUtil.isNotBlank(x.getAValue()) ? Double.valueOf(x.getAValue()) : null);
                    listDTO.setB(StrUtil.isNotBlank(x.getBValue()) ? Double.valueOf(x.getBValue()) : null);
                    listDTO.setC(StrUtil.isNotBlank(x.getCValue()) ? Double.valueOf(x.getCValue()) : null);
                    listDTO.setT(StrUtil.isNotBlank(x.getTValue()) ? Double.valueOf(x.getTValue()) : null);
                    sqlDataDTO.setType(x.getDataType());
                    sqlDataDTO.setDesc(testItemMap.inverse().get(x.getAdType()).replace(DetectionCodeEnum.REAL_PREFIX.getCode(), ""));
                    sqlDataDTO.setList(listDTO);
                    sqlData.add(sqlDataDTO);
                });
                devData.setSqlData(sqlData);
                info.add(devData);
            });
        });

        Map<String, List<ContrastHarmonicResult>> devMonitorIdMap2 = null;
        if (flag == 0) {
            devMonitorIdMap2 = harm.stream().collect(Collectors.groupingBy(ContrastHarmonicResult::getDevMonitorId, Collectors.toList()));
        } else {
            devMonitorIdMap2 = harm.stream().collect(Collectors.groupingBy(ContrastHarmonicResult::getStdDevMonitorId, Collectors.toList()));
        }

        devMonitorIdMap2.forEach((devMonitorId, value) -> {
            Map<LocalDateTime, List<ContrastHarmonicResult>> timeListMap = value.stream().collect(Collectors.groupingBy(ContrastHarmonicResult::getTimeId, Collectors.toList()));

            String[] split1 = devMonitorId.split(CnSocketUtil.SPLIT_TAG);
            timeListMap.forEach((time, value1) -> {
//                DevData devData = info.stream().filter(x -> x.getTime().equals(time.format(DateTimeFormatter.ofPattern(DatePattern.ISO8601_PATTERN)))).findFirst().orElse(null);
                DevData devData = null;
                for (int i = 0; i < info.size(); i++) {
                    DevData devData1 = info.get(i);
                    if (time.format(DateTimeFormatter.ofPattern(DatePattern.ISO8601_PATTERN)).equals(devData1.getTime()) && devData1.getId().split(CnSocketUtil.SPLIT_TAG)[1].equals(split1[1])) {
                        devData = devData1;
                        break;
                    }
                }
                if (ObjectUtil.isNotNull(devData)) {
                    String[] split = devMonitorId.split(CnSocketUtil.SPLIT_TAG);
                    if (flag == 0) {
                        PqDev dev = pqDevService.getById(split[0]);
                        devData.setId(dev.getIp() + CnSocketUtil.SPLIT_TAG + split[1]);
                    } else {
                        PqStandardDev standardDev = pqStandardDevService.getById(split[0]);
                        devData.setId(standardDev.getIp() + CnSocketUtil.SPLIT_TAG + split[1]);
                    }

                    devData.setTime(time.format(DateTimeFormatter.ofPattern(DatePattern.ISO8601_PATTERN)));
                    List<DevData.SqlDataDTO> sqlData = devData.getSqlData();
                    List<DevData.SqlDataHarmDTO> sqlDataHarm = new ArrayList<>();
                    value1.forEach(x -> {
                        DevData.SqlDataHarmDTO dataHarmDTO = new DevData.SqlDataHarmDTO();
                        dataHarmDTO.setType(x.getDataType());
                        String desc = testItemMap.inverse().get(x.getAdType()).replace(DetectionCodeEnum.REAL_PREFIX.getCode(), "");
                        dataHarmDTO.setDesc(desc);
                        boolean notContainBaseHarm = false;
                        if (DetectionCodeEnum.V2_50.getCode().equals(desc) || DetectionCodeEnum.PV2_50.getCode().equals(desc) || DetectionCodeEnum.I2_50.getCode().equals(desc) || DetectionCodeEnum.P2_50.getCode().equals(desc)) {
                            dataHarmDTO.setNum(49);
                            notContainBaseHarm = true;
                        }
                        if (DetectionCodeEnum.SV_1_49.getCode().equals(desc) || DetectionCodeEnum.PSV_1_49.getCode().equals(desc) || DetectionCodeEnum.SI_1_49.getCode().equals(desc)) {
                            dataHarmDTO.setNum(50);
                            notContainBaseHarm = false;
                        }

                        DevData.SqlDataHarmDTO.ListDTO listHarmDTO = new DevData.SqlDataHarmDTO.ListDTO();
                        listHarmDTO.setA(reflectHarmonicValue("a", x, notContainBaseHarm));
                        listHarmDTO.setB(reflectHarmonicValue("b", x, notContainBaseHarm));
                        listHarmDTO.setC(reflectHarmonicValue("c", x, notContainBaseHarm));
                        dataHarmDTO.setList(listHarmDTO);
                        sqlDataHarm.add(dataHarmDTO);

                        if (DetectionCodeEnum.V2_50.getCode().equals(desc) || DetectionCodeEnum.PV2_50.getCode().equals(desc) || DetectionCodeEnum.SV_1_49.getCode().equals(desc) || DetectionCodeEnum.PSV_1_49.getCode().equals(desc)) {
                            DevData.SqlDataDTO sqlDataDTO = new DevData.SqlDataDTO();
                            sqlDataDTO.setType(x.getDataType());
                            DevData.SqlDataDTO.ListDTO listDTO = new DevData.SqlDataDTO.ListDTO();
                            listDTO.setA(StrUtil.isNotBlank(x.getAValue0()) ? Double.valueOf(x.getAValue0()) : null);
                            listDTO.setB(StrUtil.isNotBlank(x.getBValue0()) ? Double.valueOf(x.getBValue0()) : null);
                            listDTO.setC(StrUtil.isNotBlank(x.getCValue0()) ? Double.valueOf(x.getAValue0()) : null);
                            sqlDataDTO.setList(listDTO);

                            if (DetectionCodeEnum.PV2_50.getCode().equals(desc) || DetectionCodeEnum.PSV_1_49.getCode().equals(desc)) {
                                sqlDataDTO.setDesc(DetectionCodeEnum.PU1.getCode());
                            } else {
                                sqlDataDTO.setDesc(DetectionCodeEnum.U1.getCode());
                            }
                            if (!sqlData.stream().anyMatch(s -> s.getDesc().equals(sqlDataDTO.getDesc()))) {
                                sqlData.add(sqlDataDTO);
                            }
                        }
                    });

                    devData.setSqlDataHarm(sqlDataHarm);
                    devData.setSqlData(sqlData);
                }
            });
        });

        return info;
    }

    private <T extends BaseResult> List<String> reflectHarmonicValue(String phase, T adHarmonicResult, boolean notContainBaseHarm) {
        List<String> info = new ArrayList<>();
        for (int i = notContainBaseHarm ? 2 : 1; i <= 50; i++) {
            String fieldName = phase + "Value" + i;
            try {
                Field idField = null;
                if (adHarmonicResult instanceof SimAndDigHarmonicResult) {
                    idField = SimAndDigHarmonicResult.class.getDeclaredField(fieldName);
                }
                if (adHarmonicResult instanceof ContrastHarmonicResult) {
                    idField = ContrastHarmonicResult.class.getDeclaredField(fieldName);
                }
                idField.setAccessible(true);
                String value = idField.get(adHarmonicResult) + "";
                info.add(value);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
        return info;
    }

    /**
     * 格式化数值，保留指定的小数位数
     *
     * @param value         原始数值
     * @param decimalPlaces 小数位数
     * @return 格式化后的字符串
     */
    private String formatSignificantDigits(double value, int decimalPlaces) {
        if (value == 0.0) {
            return "0";
        }

        // 使用BigDecimal进行精确计算
        BigDecimal bd = new BigDecimal(String.valueOf(value));

        // 保留指定的小数位数，四舍五入
        bd = bd.setScale(decimalPlaces, BigDecimal.ROUND_HALF_UP);

        // 移除末尾的零（可选，根据需要决定是否保留）
        String result = bd.stripTrailingZeros().toPlainString();

        return result;
    }

    /**
     * 格式化误差范围，将 "-0.057735~0.057735" 格式化为 "±0.05774"
     *
     * @param radiusValue 误差范围值（通常是正数，表示±范围）
     * @return 格式化后的误差范围字符串
     */
    private String formatErrorRange(double radiusValue) {
        return formatErrorRangeWithDecimalPlaces(radiusValue, 5);
    }

    /**
     * 格式化误差范围，支持自定义小数位数
     *
     * @param radiusValue 误差范围值（通常是正数，表示±范围）
     * @param decimalPlaces 小数位数
     * @return 格式化后的误差范围字符串
     */
    /**
     * 格式化误差范围字符串，支持处理"-0.05~0.05"格式并转换为"±0.05"格式
     *
     * @param errorRange    误差范围字符串
     * @param decimalPlaces 小数位数
     * @return 格式化后的误差范围
     */
    private String formatErrorRange(String errorRange, Integer decimalPlaces) {
        if (errorRange == null || decimalPlaces == null) {
            return errorRange;
        }

        try {
            // 尝试直接解析为数字
            double radiusValue = Double.parseDouble(errorRange);
            return formatErrorRangeWithDecimalPlaces(radiusValue, decimalPlaces);
        } catch (NumberFormatException e) {
            // 处理"-0.05~0.05"这种格式
            if (errorRange.contains("~")) {
                String[] parts = errorRange.split("~");
                if (parts.length == 2) {
                    try {
                        double minValue = Double.parseDouble(parts[0].trim());
                        double maxValue = Double.parseDouble(parts[1].trim());
                        // 取绝对值的最大值作为范围
                        double absMax = Math.max(Math.abs(minValue), Math.abs(maxValue));
                        return formatErrorRangeWithDecimalPlaces(absMax, decimalPlaces);
                    } catch (NumberFormatException ex) {
                        log.warn("无法解析误差范围格式: {}", errorRange);
                    }
                }
            }
            // 如果无法解析，返回原值
            return errorRange;
        }
    }

    private String formatErrorRangeWithDecimalPlaces(double radiusValue, int decimalPlaces) {
        if (radiusValue == 0.0) {
            return "±0";
        }

        // 取绝对值并保留指定小数位数
        double absValue = Math.abs(radiusValue);
        String formattedValue = formatSignificantDigits(absValue, decimalPlaces);

        return "±" + formattedValue;
    }

    /**
     * 根据指标代码获取对应的小数位数
     *
     * @param scriptCode 指标代码
     * @return 小数位数，null表示不格式化
     */
    private Integer getDecimalPlacesByScriptCode(String scriptCode) {
        if (scriptCode == null) {
            return null;
        }
        switch (scriptCode) {
            // 保留2位小数
            case "FREQ":  // 频率
                return 4;
            // 保留3位小数
            case "I":  // 电流
                return 5;
            // 保留4位小数
            case "IMBV": // 电压不平衡度
            case "IMBA": // 电流不平衡度
                return 4;
            // 保留5位小数
            case "V":  // 电压
            case "HV":   // 电压谐波
            case "HI":   // 电流谐波
            case "HP":   // 功率谐波
            case "HSV":  // 电压间谐波
            case "HSI":  // 电流间谐波
                return 5;
            // 其他指标不格式化
            default:
                return null;
        }
    }
}
