package cn.cecep.talroad.service.impl;

import cn.cecep.talroad.common.core.constant.HttpStatus;
import cn.cecep.talroad.common.core.domain.R;
import cn.cecep.talroad.common.core.exception.BussinessException;
import cn.cecep.talroad.common.core.utils.DateUtils;
import cn.cecep.talroad.common.core.utils.StringUtils;
import cn.cecep.talroad.common.core.web.domain.AjaxResult;
import cn.cecep.talroad.common.security.utils.SecurityUtils;
import cn.cecep.talroad.domain.*;
import cn.cecep.talroad.domain.analysis.PcRaProblemType;
import cn.cecep.talroad.enums.AmProblemAuditResultEnum;
import cn.cecep.talroad.enums.AmProblemAuditTypeEnum;
import cn.cecep.talroad.enums.AmProblemProcessTypeEnum;
import cn.cecep.talroad.enums.AmProblemStatusEnum;
import cn.cecep.talroad.feign.BaseRegionService;
import cn.cecep.talroad.mapper.*;
import cn.cecep.talroad.service.*;
import cn.cecep.talroad.service.analysis.IPcRaProblemTypeService;
import cn.cecep.talroad.service.analysis.ISRaOnlineEmissionsGasService;
import cn.cecep.talroad.service.analysis.ISRaOnlineEmissionsWaterService;
import cn.cecep.talroad.vo.*;
import cn.cecep.talroad.vo.analysis.FactoryOutletStaticsVo;
import cn.cecep.talroad.vo.analysis.PcRaProblemTypeVo;
import cn.cecep.talroad.vo.query.AmProblemFiQuery;
import cn.cecep.talroad.vo.query.SEnvGasMonRealQuery;
import cn.cecep.talroad.vo.query.SEnvWaterMonRealQuery;
import cn.cecep.talroad.vo.query.analysis.SRaOnlineEmissionsGasQuery;
import cn.cecep.talroad.vo.query.analysis.SRaOnlineEmissionsWaterQuery;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateRange;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.nacos.common.utils.UuidUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;


@Service
@Slf4j
public class AmProblemFiServiceImpl extends ServiceImpl<AmProblemFiMapper, AmProblemFi> implements IAmProblemFiService {
    @Autowired
    private AmProblemFiMapper amProblemFiMapper;

    @Autowired
    private IPcRaProblemTypeService problemTypeService;

    @Autowired
    private IProductionManageService productionManageService;

    @Autowired
    private PcOutletMapper outletMapper;

    @Autowired
    private BasDeviceMapper basDeviceMapper;

    @Autowired
    private BasDeviceSiteMapper basDeviceSiteMapper;

    @Autowired
    @Qualifier("baseRegionService")
    private BaseRegionService baseRegionService;

    @Autowired
    private ISRaOnlineEmissionsGasService onlineEmissionsGasService;

    @Autowired
    private ISRaOnlineEmissionsWaterService onlineEmissionsWaterService;

    @Autowired
    private ISEnvWaterMonRealService envWaterMonRealService;

    @Autowired
    private ISEnvGasMonRealService envGasMonRealService;

    @Autowired
    private PcFactoryMapper factoryMapper;

    @Autowired
    private IAmProblemFiProcessService amProblemFiProcessService;

    @Autowired
    private IMonElecRealService monElecRealService;

    @Autowired
    private AmProblemFiVideoMapper amProblemFiVideoMapper;

    @Value("${amproblem.zf.url}")
    private String zfUrl;

    public static List<Map<String, Object>> removeFalseHave0(List<Map<String, Object>> myList) {
        List<Map<String, Object>> filteredList = new ArrayList<>();
        for (Map<String, Object> item : myList) {
            boolean have0 = (boolean) item.get("have0");
            if (have0) {
                Map<String, Object> filteredItem = new HashMap<>();
                filteredItem.put("have0", true);
                filteredItem.put("value", item.get("value"));
                filteredItem.put("label", item.get("label"));
                filteredItem.put("parentId", item.get("parentId"));
                if (item.containsKey("children")) {
                    List<Map<String, Object>> children = (List<Map<String, Object>>) item.get("children");
                    List<Map<String, Object>> filteredChildren = removeFalseHave0(children);
                    if (!filteredChildren.isEmpty()) {
                        filteredItem.put("children", filteredChildren);
                    }
                }
                filteredList.add(filteredItem);
            }
        }
        return filteredList;
    }

    @Override
    public List<EChartsVO.Sunburst> getChartData(AmProblemFiQuery.ChartDataParam param, String regionCode) {
        List<String> regionCodes = new ArrayList<>();
        R<List<String>> r = baseRegionService.getRegionCodeListChild(regionCode);
        if (r.getCode() == 200) {
            regionCodes = r.getData();
        }
        // 补全结束日期格式，解决查询结果不包含结束日期
        param.setEndTime(getEndTime(param.getDateType(), param.getEndTime()));

        // 按照问题类型分组，统计数量
        List<Map<String, Object>> data = amProblemFiMapper.selectChartData(param, regionCodes);

        if (data.isEmpty()) {
            return new ArrayList<>();
        }

        // 所有问题分类节点map，key为问题分类id
        Map<String, EChartsVO.Sunburst> sunburstMap = new HashMap<>();

        List<PcRaProblemTypeVo> problemTypeVos = problemTypeService.selectProblemTypeVoList();

        // 问题总数
        long sum = data.stream().mapToLong(o -> (Long) o.get("count")).sum();

        // 遍历查询到的问题分类，将问题分类本身以及父分类封装到sunburstMap中，并计算问题数量、所占百分比
        for (Map<String, Object> map : data) {
            String problemType = (String) map.get("problemType");
            Long count = (Long) map.get("count");

            PcRaProblemTypeVo typeVo = problemTypeVos.stream().filter(o -> o.getId().equals(problemType)).findFirst().orElse(null);

            if (typeVo == null) {
                throw new RuntimeException("预警报警信息表中存在未知的的问题类型【id=" + problemType + "】");
            }

            /*
                遍历问题分类的路径，放入到sunburstMap中，由于不同的子级问题分类可能属于同一父级，因此需要先判断sunburstMap是否已存在
             */
            for (PcRaProblemType type : typeVo.getPath()) {
                EChartsVO.Sunburst sunburst = sunburstMap.get(type.getId());

                // sunburstMap中不存在
                if (sunburst == null) {
                    BigDecimal divide = BigDecimal.valueOf(count * 100).divide(BigDecimal.valueOf(sum), 2, BigDecimal.ROUND_HALF_UP);

                    sunburst = new EChartsVO.Sunburst();
                    sunburst.setValue(count);
                    sunburst.setId(type.getId());
                    sunburst.setParentId(type.getParentId());
                    sunburst.setName(type.getName() + "\n" + divide.stripTrailingZeros().toPlainString() + "%");

                    sunburst.setChildren(new ArrayList<>());

                    sunburstMap.put(type.getId(), sunburst);
                } else {
                    // 已存在，累加问题数量，并重新计算百分比
                    sunburst.setValue(sunburst.getValue() + count);

                    BigDecimal divide = BigDecimal.valueOf(sunburst.getValue() * 100).divide(BigDecimal.valueOf(sum), 2, BigDecimal.ROUND_HALF_UP);
                    sunburst.setName(type.getName() + "\n" + divide.stripTrailingZeros().toPlainString() + "%");
                }
            }
        }

        // 构建树，遍历所有问题分类，添加到父级分类的children属性中
        for (EChartsVO.Sunburst sunburst : sunburstMap.values()) {
            EChartsVO.Sunburst parent = sunburstMap.get(sunburst.getParentId());
            if (parent != null) {
                parent.getChildren().add(sunburst);
            }
        }

        // 返回所有的顶级节点
        return sunburstMap.values().stream().filter(o -> o.getParentId() == null).collect(Collectors.toList());
    }

    /**
     * 根据日期类型，获取指定日期的结束时间
     */
    private String getEndTime(String dateType, String time) {
        if (StringUtils.isEmpty(time)) {
            return time;
        }
        Date date = DateUtils.parseDate(time);

        DateTime dateTime;
        if (dateType.equals("D")) {
            dateTime = DateUtil.endOfDay(date);
        } else {
            dateTime = DateUtil.endOfMonth(date);
        }
        return DateUtil.format(dateTime, "yyyy-MM-dd HH:mm:ss");
    }

    @Override
    public EChartsVO getTrendData(AmProblemFiQuery.ChartDataParam param) {
        // 补全结束日期格式，解决查询结果不包含结束日期
        param.setEndTime(getEndTime(param.getDateType(), param.getEndTime()));

        // 按日期分组，统计数量
        List<Map<String, Object>> trendData = baseMapper.selectTrendData(param);

        List<String> xdata = DateUtils.getRangeTimes("D".equals(param.getDateType()) ? "D" : "N", param.getStartTime(), param.getEndTime());

        // 遍历x轴，保证系列值与x轴数据一一对应
        List<Object> values = xdata.stream().map(time -> {
            Map<String, Object> map = trendData.stream().filter(o -> time.equals(o.get("analyseTime"))).findFirst().orElse(null);
            return map == null ? null : map.get("count");
        }).collect(Collectors.toList());

        EChartsVO.SeriesObj ser = new EChartsVO.SeriesObj();
        ser.setValues(values);

        EChartsVO chartsVO = new EChartsVO();
        chartsVO.setSeries(Arrays.asList(ser));
        chartsVO.setXData(xdata);
        return chartsVO;
    }

    @Override
    public List<AmProblemFiVo> selectList(Page<AmProblemFiVo> page, AmProblemFiQuery query) {

        // 若未指定，查询当前用户区域下的数据
        if (StringUtils.isEmpty(query.getRegionCode()) && !query.getNoRegion()) {
            String userRegionCode = SecurityUtils.getLoginUser().getSysUser().getRegionCode();

            if (StringUtils.isEmpty(userRegionCode)) {
                return new ArrayList<>();
            }
            R<List<String>> r = baseRegionService.getRegionCodeListChild(userRegionCode);
            if (r.getCode() == R.SUCCESS) {
                query.setRegionCodeList(r.getData());
            } else {
                return new ArrayList<>();
            }
        }

        List<AmProblemFiVo> problemDataVos;
        if (page == null) {
            problemDataVos = baseMapper.selectProblemFiList(query);
        } else {
            problemDataVos = baseMapper.selectProblemFiPage(page, query);
            page.setRecords(problemDataVos);
        }
        if (problemDataVos.isEmpty()) {
            return problemDataVos;
        }
        List<PcRaProblemTypeVo> problemTypeVos = problemTypeService.selectProblemTypeVoList();

        for (AmProblemFiVo vo : problemDataVos) {
            PcRaProblemTypeVo typeVo = problemTypeVos.stream().filter(o -> o.getId().equals(vo.getProblemType())).findFirst().orElse(null);
            if (typeVo != null) {
                String problemTypeName = typeVo.getPath().stream().map(PcRaProblemType::getName).collect(Collectors.joining("-"));
                vo.setProblemTypeName(problemTypeName);
                vo.setRoute(typeVo.getRoute());
            }
        }
        return problemDataVos;
    }

    @Override
    public AmProblemFiVo.Detail getInfo(String id) {
        AmProblemFi problemFi = getById(id);
        AmProblemFiVo.Detail vo = new AmProblemFiVo.Detail();
        BeanUtils.copyProperties(problemFi, vo);

        /*
            设置污染要素
         */
        if ("1".equals(problemFi.getPollutantSourceAi())) {
            vo.setPollutionTypeName("气污染要素");
        } else if ("2".equals(problemFi.getPollutantSourceAi())) {
            vo.setPollutionTypeName("水污染要素");
        }

        /*
            设置问题监控视频、截图
         */
        List<AmProblemFiVideo.Vo> videoPictures = baseMapper.selectAmProblemFiVideo(id);

        List<AmProblemFiVideo.Vo> videos = videoPictures.stream()
                // 视频截图按照视频id分组
                .collect(Collectors.groupingBy(AmProblemFiVideo.Vo::getDevId, LinkedHashMap::new, Collectors.toList()))
                .entrySet().stream().map(entry -> {
                    AmProblemFiVideo.Vo vo1 = entry.getValue().get(0);

                    // 找到path不为空的作为视频封面
                    AmProblemFiVideo.Vo vo2 = entry.getValue().stream()
                            .filter(o -> o.getVideoPath() != null && !"non-exit".equals(o.getVideoPath())).findFirst().orElse(null);
                    AmProblemFiVideo.Vo videoVo = new AmProblemFiVideo.Vo();
                    videoVo.setDevId(vo1.getDevId());
                    videoVo.setDevName(vo1.getDevName());
                    videoVo.setDevSource(vo1.getDevSource());
                    videoVo.setStartTime(vo1.getStartTime());
                    videoVo.setEndTime(vo1.getEndTime());
                    videoVo.setVideoPath(vo2 != null ? vo2.getVideoPath() : null);
                    return videoVo;
                }).collect(Collectors.toList());
        vo.setVideos(videos);
        vo.setVideoPictures(videoPictures);

        /*
            设置问题状态
         */
        PcRaProblemType problemType = problemTypeService.getById(problemFi.getProblemType());
        // 若问题类型的路由是“IssuesInfoPage”表示需要验证，若反馈人为空，表示该问题未验证
        if (problemType != null && "IssuesInfoPage".equals(problemType.getRoute()) && problemFi.getModelValidPerson() == null) {
            vo.setStatus("2");
        } else {
            vo.setStatus("1");
        }

        /*
            设置问题所属企业名称
         */
        PcFactory factory = factoryMapper.selectById(problemFi.getFactoryId());
        if (factory != null) {
            vo.setFactoryName(factory.getFactoryName());
            vo.setRegionName(factory.getCountryName());
        }

        /*
            设置问题类型名称
         */
        vo.setProblemTypeName(problemTypeService.getPathName(problemFi.getProblemType()));

        /*
            设置问题描述
         */
        try {
            if (StringUtils.isNotBlank(problemFi.getExtraCzp())) {
                Map<String, Object> extraCzp = JSON.parseObject(problemFi.getExtraCzp(), new TypeReference<Map<String, Object>>() {});
                String problemDetailsCzp = (String) extraCzp.get("problemDetailsCzp");

                if (StringUtils.isNotBlank(problemDetailsCzp)) {
                    if (StringUtils.isBlank(vo.getProblemDetails())) {
                        vo.setProblemDetails(problemDetailsCzp);
                    } else {
                        vo.setProblemDetails(vo.getProblemDetails() + problemDetailsCzp);
                    }
                }
            }
        } catch (Exception e) {
            log.info("解析extraCzp异常 问题id={}", id, e);
        }
        return vo;
    }

    @Override
    public void updateModelValid(AmProblemFiVo.ModelValidForm form) {
        update(new UpdateWrapper<AmProblemFi>()
                .set("model_valid_db", form.getModelValidDb())
                .set("model_valid_video", form.getModelValidVideo())
                .set("model_valid_details", form.getModelValidDetails())
                .set("model_valid_person", form.getModelValidPerson())
                .set("model_valid_time", new Date())
                .eq("id", form.getId()));
    }

    @Override
    public IProductionManageService.FrameDataVo logicExceptionData(String id, String startTime, String endTime, Long pageNum, Long pageSize) {
        AmProblemFi problemFi = getById(id);

        IProductionManageService.SearchVo searchVo = new IProductionManageService.SearchVo(startTime, endTime, pageNum, pageSize);
        searchVo.setDataType(problemFi.getDataType());

        Map<String, Object> extra = null;
        try {
            extra = JSON.parseObject(problemFi.getExtra(), new TypeReference<Map<String, Object>>() {
            });
        } catch (Exception e) {
            log.info("解析extra异常 问题id={}", id, e);
        }

        /*
            设置在线监测点位
         */
        PcOutlet outlet = outletMapper.selectById(problemFi.getStationId());
        if (outlet != null) {
            // 在线监测点位展示的污染物
            List<AmProblemFiVo.PollutantVo> pollutantVos = new ArrayList<>();

            // 关联分析监测点的主要污染物
            if (StringUtils.isNotEmpty(problemFi.getParamProperty())) {
                AmProblemFiVo.PollutantVo pollutantVo = new AmProblemFiVo.PollutantVo();
                pollutantVo.setProp(problemFi.getParamProperty());

                // 设置主要监测物的标记区域
                pollutantVo.setMarkArea(getMarkArea(problemFi));

                // 设置主要监测物的标记线
                pollutantVo.setMarkLine(getMarkLine(problemFi));

                // 设置主要监测物的上下限数据
                pollutantVo.setPollutantLimitMap(getPollutantLimitMap(problemFi, startTime, endTime));

                pollutantVo.setProblemParam(true);

                pollutantVos.add(pollutantVo);
            }

            try {
                List<String> onlineParams = (List<String>) extra.get("onlineParams");

                // 监测点其它参数
                if (onlineParams != null) {
                    for (String onlineParam : onlineParams) {
                        AmProblemFiVo.PollutantVo pollutantVo = new AmProblemFiVo.PollutantVo();
                        pollutantVo.setProp(onlineParam);
                        pollutantVos.add(pollutantVo);
                    }
                }
            } catch (Exception e) {
                log.info("解析extra.onlineParams异常 问题id={}", id, e);
            }

            PcOutletVo.SimpleVo outletSimpleVo = new PcOutletVo.SimpleVo();
            BeanUtils.copyProperties(outlet, outletSimpleVo);
            outletSimpleVo.setPollutantVos(pollutantVos);

            searchVo.setOutletSimpleVo(Arrays.asList(outletSimpleVo));
        }

        /*
            设置关联的dcs点位
         */
        searchVo.setDeviceSimpleVo(getDeviceSimpleVo(problemFi));

        /*
            设置关联的分表计电点位
         */
        searchVo.setMergeDeviceSiteSimpleVo(getDeviceSiteSimpleVo(problemFi));

        searchVo.setDeviceSimpleStatusVos(getDeviceSimpleStatusVos(problemFi));

        /*
            dcs && online
         */
        searchVo.setDcsOnlineVos(getDcsOnlineVos(problemFi));

        return productionManageService.getFrameData(searchVo);
    }

    /**
     * 获取问题时间标记区域
     * @param problemFi
     * @return
     */
    private EChartsVO.MarkArea getMarkArea(AmProblemFi problemFi) {
        // “长期区间范围不变”不需要标记区域
        if ("001009002".equals(problemFi.getProblemType())) {
            return null;
        }

        if (StringUtils.isNotEmpty(problemFi.getDataType()) &&
                StringUtils.isNotEmpty(problemFi.getProblemStartTime()) &&
                StringUtils.isNotEmpty(problemFi.getProblemEndTime())) {
            EChartsVO.MarkArea markArea = new EChartsVO.MarkArea(new ArrayList<>());

            Map<String, String> map1 = new HashMap<>();
            map1.put("xAxis", DateUtils.format(problemFi.getDataType(), problemFi.getProblemStartTime()));
            Map<String, String> map2 = new HashMap<>();
            map2.put("xAxis", DateUtils.format(problemFi.getDataType(), problemFi.getProblemEndTime()));

            markArea.getData().add(Arrays.asList(map1, map2));
            return markArea;
        }
        return null;
    }

    /**
     * 获取问题时间标记区域
     */
    private EChartsVO.MarkArea getMarkArea(List<List<String>> rangeList) {
        if (rangeList == null || rangeList.isEmpty()) {
            return null;
        }
        EChartsVO.MarkArea markArea = new EChartsVO.MarkArea(new ArrayList<>());

        for (List<String> list : rangeList) {
            if (list == null || list.size() < 2) {
                continue;
            }
            Map<String, String> map1 = new HashMap<>();
            map1.put("xAxis", DateUtils.format("M", list.get(0)));
            Map<String, String> map2 = new HashMap<>();
            map2.put("xAxis", DateUtils.format("M", list.get(1)));
            markArea.getData().add(Arrays.asList(map1, map2));
        }
        return markArea;
    }

    private EChartsVO.MarkLine getMarkLine(AmProblemFi problemFi) {
        EChartsVO.MarkLine markLine = new EChartsVO.MarkLine(new ArrayList<>());

        // “长期区间范围不变”的标记线特殊处理
        if ("001009002".equals(problemFi.getProblemType())) {
            Map<String, String> labelMap = new HashMap<>();
            labelMap.put("formatter", "{b}: {c}");
            try {
                markLine.getData().add(
                        new HashMap<String, Object>() {{
                            put("name", "下限");
                            put("yAxis", new BigDecimal(problemFi.getPredictLowerLimit()).setScale(6, BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toPlainString());
                            put("label", labelMap);
                        }}
                );
            } catch (Exception e) {
            }
            try {
                markLine.getData().add(
                        new HashMap<String, Object>() {{
                            put("name", "上限");
                            put("yAxis", new BigDecimal(problemFi.getPredictUpperLimit()).setScale(6, BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toPlainString());
                            put("label", labelMap);
                        }}
                );
            } catch (Exception e) {
            }
            try {
                markLine.getData().add(
                        new HashMap<String, String>() {{
                            put("xAxis", DateUtils.format(problemFi.getDataType(), problemFi.getProblemStartTime()));
                        }}
                );
            } catch (Exception e) {
            }
        } else if ("001008002".equals(problemFi.getProblemType())) {
            Map<String, String> labelMap = new HashMap<>();
            labelMap.put("formatter", "{b}: {c}");
            try {
                markLine.getData().add(
                        new HashMap<String, Object>() {{
                            put("name", "标准值");
                            put("yAxis", new BigDecimal(problemFi.getPredictUpperLimit()).setScale(6, BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toPlainString());
                            put("label", labelMap);
                        }}
                );
            } catch (Exception e) {
            }
        } else {
            String markLineName = "001001003".equals(problemFi.getProblemType()) ? "方差" : "均值";

            // 前均值/前方差
            if (problemFi.getMeanBefore() != null &&
                    StringUtils.isNotEmpty(problemFi.getInputStartTime()) && StringUtils.isNotEmpty(problemFi.getProblemStartTime())) {
                String value = problemFi.getMeanBefore().setScale(2, BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toPlainString();

                Map<String, Object> map1 = new HashMap<>();
                map1.put("name", markLineName + value);
                map1.put("coord", new String[]{DateUtils.format(problemFi.getDataType(), problemFi.getInputStartTime()), value});
                Map<String, Object> map2 = new HashMap<>();
                map2.put("coord", new String[]{DateUtils.format(problemFi.getDataType(), problemFi.getProblemStartTime()), value});
                markLine.getData().add(Arrays.asList(map1, map2));
            }
            // 后均值/后方差
            if (problemFi.getMeanAfter() != null &&
                    StringUtils.isNotEmpty(problemFi.getProblemStartTime()) && StringUtils.isNotEmpty(problemFi.getInputEndTime())) {
                String value = problemFi.getMeanAfter().setScale(2, BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toPlainString();

                Map<String, Object> map1 = new HashMap<>();
                map1.put("name", markLineName + value);
                map1.put("coord", new String[]{DateUtils.format(problemFi.getDataType(), problemFi.getProblemStartTime()), value});
                Map<String, Object> map2 = new HashMap<>();
                map2.put("coord", new String[]{DateUtils.format(problemFi.getDataType(), problemFi.getInputEndTime()), value});
                markLine.getData().add(Arrays.asList(map1, map2));
            }
        }
        return markLine;
    }

    /**
     * 获取污染物上下限的数据
     */
    private Map<String, AmProblemFiVo.PollutantLimitVo> getPollutantLimitMap(AmProblemFi problemFi, String startTime, String endTime) {
        List<String> lowerLimits = null;
        List<String> upperLimits = null;
        try {
            lowerLimits = JSON.parseArray(problemFi.getPredictLowerLimit(), String.class);
            upperLimits = JSON.parseArray(problemFi.getPredictUpperLimit(), String.class);
        } catch (Exception e) {
            log.info("解析上下限异常 问题id={}", problemFi.getId(), e);
        }

        // 上下限存在并且ai分析时间存在
        if ((lowerLimits != null || upperLimits != null) &&
                StringUtils.isNotEmpty(problemFi.getInputStartTime()) &&
                StringUtils.isNotEmpty(problemFi.getInputEndTime())) {
            Date st = DateUtils.parseDate(startTime);
            Date et = DateUtils.parseDate(endTime);
            Date ist = DateUtils.parseDate(problemFi.getInputStartTime());
            Date iet = DateUtils.parseDate(problemFi.getInputEndTime());

            // 页面传入的时间范围与ai分析时间范围有交集
            if ((ist.compareTo(st) >= 0 && ist.compareTo(et) <= 0) || (iet.compareTo(st) >= 0 && iet.compareTo(et) <= 0)) {
                DateField dateField = null;
                String format = null;

                switch (problemFi.getDataType()) {
                    case "M":
                        dateField = DateField.MINUTE;
                        format = "yyyy-MM-dd HH:mm";
                        break;
                    case "H":
                        dateField = DateField.HOUR_OF_DAY;
                        format = "yyyy-MM-dd HH";
                        break;
                    case "D":
                        dateField = DateField.DAY_OF_YEAR;
                        format = "yyyy-MM-dd";
                        break;
                }

                // 主要污染物上下限数据
                Map<String, AmProblemFiVo.PollutantLimitVo> pollutantLimitMap = new HashMap<>();
                int index = 0;

                DateRange range = DateUtil.range(ist, iet, dateField);

                for (DateTime dateTime : range) {
                    AmProblemFiVo.PollutantLimitVo limitVo = new AmProblemFiVo.PollutantLimitVo();
                    limitVo.setLowerLimit(lowerLimits != null && lowerLimits.size() > index ? lowerLimits.get(index) : null);
                    limitVo.setUpperLimit(upperLimits != null && upperLimits.size() > index ? upperLimits.get(index) : null);

                    // 由于前端上下限系列是叠加展示的，上限的系列值=上限-下限
                    if (StringUtils.isNotEmpty(limitVo.getLowerLimit()) && StringUtils.isNotEmpty(limitVo.getUpperLimit())) {
                        limitVo.setUpperLimit(new BigDecimal(limitVo.getUpperLimit()).subtract(new BigDecimal(limitVo.getLowerLimit())).stripTrailingZeros().toPlainString());
                    }
                    pollutantLimitMap.put(dateTime.toString(format), limitVo);
                    index++;
                }
                return pollutantLimitMap;
            }
        }
        return null;
    }

    private List<BasDeviceVo.SimpleStatusVo> getDeviceSimpleStatusVos(AmProblemFi problemFi) {
        List<String> deviceIdList = null;
        try {
            Map<String, Object> extra = JSON.parseObject(problemFi.getExtra(), new TypeReference<Map<String, Object>>() {
            });
            deviceIdList = (List<String>) extra.get("real_time_analysis_run");
        } catch (Exception e) {
            log.info("解析extra.dcsDeviceList异常 问题id={}", problemFi.getId(), e);
        }
        if (deviceIdList != null && deviceIdList.size() > 0) {
            List<BasDevice> basDevices = basDeviceMapper.selectList(new QueryWrapper<BasDevice>().in("device_id", deviceIdList).orderByAsc("industry", "device_id"));
            return basDevices.stream().map(o -> {
                BasDeviceVo.SimpleStatusVo simpleVo = new BasDeviceVo.SimpleStatusVo();
                BeanUtils.copyProperties(o, simpleVo);
                return simpleVo;
            }).collect(Collectors.toList());
        }
        return null;
    }

    /**
     * 获取问题关联的dcs设备vo
     * @param problemFi
     * @return
     */
    private List<BasDeviceVo.SimpleVo> getDeviceSimpleVo(AmProblemFi problemFi) {
        Map<String, Map<String, Object>> dcsDeviceMap = null;
        try {
            Map<String, Object> extra = JSON.parseObject(problemFi.getExtra(), new TypeReference<Map<String, Object>>() {
            });
            List<Map<String, Object>> dcsDeviceList = (List<Map<String, Object>>) extra.get("dcsDeviceList");
            if (dcsDeviceList == null) {
                return null;
            }
            dcsDeviceMap = dcsDeviceList.stream().collect(Collectors.toMap(o -> (String) o.get("deviceId"), o -> o));
        } catch (Exception e) {
            log.info("解析extra.dcsDeviceList异常 问题id={}", problemFi.getId(), e);
        }
        if (dcsDeviceMap != null && dcsDeviceMap.size() > 0) {
            List<BasDevice> basDevices = basDeviceMapper.selectList(new QueryWrapper<BasDevice>().in("device_id", dcsDeviceMap.keySet()).orderByAsc("industry", "device_id"));
            Map<String, Map<String, Object>> finalDcsDeviceMap = dcsDeviceMap;

            return basDevices.stream().map(o -> {
                BasDeviceVo.SimpleVo simpleVo = new BasDeviceVo.SimpleVo();
                BeanUtils.copyProperties(o, simpleVo);
                try {
                    Map<String, Object> map = finalDcsDeviceMap.get(o.getDeviceId());
                    List<String> params = (List<String>) map.get("params");
                    simpleVo.setPollutantVos(
                            params.stream().map(paramCode -> {
                                AmProblemFiVo.PollutantVo pollutantVo = new AmProblemFiVo.PollutantVo();
                                pollutantVo.setProp(paramCode);

                                // 设置标记区域
                                if (StringUtils.isNotEmpty(problemFi.getProblemStartTime()) &&
                                        StringUtils.isNotEmpty(problemFi.getProblemEndTime())) {
                                    EChartsVO.MarkArea markArea = new EChartsVO.MarkArea(new ArrayList<>());

                                    Map<String, String> map1 = new HashMap<>();
                                    map1.put("xAxis", DateUtils.format("R", problemFi.getProblemStartTime()));
                                    Map<String, String> map2 = new HashMap<>();
                                    map2.put("xAxis", DateUtils.format("R", problemFi.getProblemEndTime()));

                                    markArea.getData().add(Arrays.asList(map1, map2));
                                    pollutantVo.setMarkArea(markArea);
                                }
                                return pollutantVo;
                            }).collect(Collectors.toList())
                    );
                } catch (Exception e) {
                    simpleVo.setPollutantVos(new ArrayList<>());
                }
                return simpleVo;
            }).collect(Collectors.toList());
        }
        return null;
    }

    /**
     * 获取问题关联的dcs设备与在线监测的vo
     */
    private List<BasDeviceVo.DcsOnlineVo> getDcsOnlineVos(AmProblemFi problemFi) {
        if (StringUtils.isBlank(problemFi.getExtraCzp())) {
            return null;
        }

        PcOutlet outlet = outletMapper.selectById(problemFi.getStationId());
        if (outlet == null) {
            return null;
        }

        Map<String, Map<String, Object>> dcsDeviceMap = null;
        try {
            Map<String, Object> extraCzp = JSON.parseObject(problemFi.getExtraCzp(), new TypeReference<Map<String, Object>>() {});
            List<Map<String, Object>> dcsDeviceList = (List<Map<String, Object>>) extraCzp.get("dcsOnlineList");
            if (dcsDeviceList == null) {
                return null;
            }
            dcsDeviceMap = dcsDeviceList.stream().collect(Collectors.toMap(o -> (String) o.get("deviceId"), o -> o));
        } catch (Exception e) {
            log.info("解析extraCzp.dcsOnlineList异常 问题id={}", problemFi.getId(), e);
        }
        if (dcsDeviceMap == null || dcsDeviceMap.isEmpty()) {
            return null;
        }

        List<BasDevice> basDevices = basDeviceMapper.selectList(new QueryWrapper<BasDevice>()
                .in("device_id", dcsDeviceMap.keySet()).orderByAsc("industry", "device_id")
        );
        Map<String, Map<String, Object>> finalDcsDeviceMap = dcsDeviceMap;

        return basDevices.stream().map(basDevice -> {
            BasDeviceVo.SimpleVo simpleVo = new BasDeviceVo.SimpleVo();
            simpleVo.setDeviceId(basDevice.getDeviceId());
            simpleVo.setName(basDevice.getName());
            simpleVo.setPollutantVos(new ArrayList<>());
            try {
                Map<String, Object> map = finalDcsDeviceMap.get(basDevice.getDeviceId());
                List<String> dcsParams = (List<String>) map.get("dcsParams");

                List<AmProblemFiVo.PollutantVo> dcsPollutantVos = dcsParams.stream().map(paramCode -> {
                    AmProblemFiVo.PollutantVo pollutantVo = new AmProblemFiVo.PollutantVo();
                    pollutantVo.setProp(paramCode);
                    return pollutantVo;
                }).collect(Collectors.toList());
                simpleVo.setPollutantVos(dcsPollutantVos);
            } catch (Exception e) {
                log.info("解析extraCzp dcsParams异常 问题id={}", problemFi.getId(), e);
            }


            PcOutletVo.SimpleVo outletSimpleVo = new PcOutletVo.SimpleVo();
            BeanUtils.copyProperties(outlet, outletSimpleVo);
            outletSimpleVo.setPollutantVos(new ArrayList<>());
            try {
                Map<String, Object> map = finalDcsDeviceMap.get(basDevice.getDeviceId());
                List<Map<String, Object>> onlineInfo = (List<Map<String, Object>>) map.get("onlineInfo");

                List<AmProblemFiVo.PollutantVo> pollutantVos = onlineInfo.stream().map(onlineMap -> {
                    String onlineParam = (String) onlineMap.get("onlineParam");
                    List<List<String>> start_end_time = (List<List<String>>) onlineMap.get("problem_start_end_time");

                    AmProblemFiVo.PollutantVo pollutantVo = new AmProblemFiVo.PollutantVo();
                    pollutantVo.setProp(onlineParam);

                    // 设置主要监测物的标记区域
                    pollutantVo.setMarkArea(getMarkArea(start_end_time));

                    // 设置主要监测物的标记线
                    pollutantVo.setMarkLine(getMarkLine(problemFi));

                    pollutantVo.setProblemParam(true);

                    return pollutantVo;
                }).collect(Collectors.toList());

                outletSimpleVo.setPollutantVos(pollutantVos);
            } catch (Exception e) {
                log.info("解析extraCzp.dcsOnlineList异常 问题id={}", problemFi.getId(), e);
            }

            BasDeviceVo.DcsOnlineVo dcsOnlineVo = new BasDeviceVo.DcsOnlineVo();
            dcsOnlineVo.setDcsSimpleVo(simpleVo);
            dcsOnlineVo.setOnlineSimpleVo(outletSimpleVo);
            return dcsOnlineVo;
        }).collect(Collectors.toList());
    }

    /**
     * 获取问题关联的分表计电点位vo
     * @param problemFi
     * @return
     */
    private List<BasDeviceSiteVo.SimpleVo> getDeviceSiteSimpleVo(AmProblemFi problemFi) {
        Map<String, Map<String, Object>> elecDeviceSiteMap = null;
        try {
            Map<String, Object> extra = JSON.parseObject(problemFi.getExtra(), new TypeReference<Map<String, Object>>() {
            });
            List<Map<String, Object>> elecDeviceSiteList = (List<Map<String, Object>>) extra.get("elecDeviceSiteList");
            if (elecDeviceSiteList == null) {
                return null;
            }
            elecDeviceSiteMap = elecDeviceSiteList.stream().collect(Collectors.toMap(o -> (String) o.get("deviceSiteId"), o -> o));
        } catch (Exception e) {
            log.info("解析extra.elecDeviceSiteList异常 问题id={}", problemFi.getId(), e);
        }
        if (elecDeviceSiteMap != null && elecDeviceSiteMap.size() > 0) {
            List<BasDeviceSite> sites = basDeviceSiteMapper.selectList(new QueryWrapper<BasDeviceSite>().in("id", elecDeviceSiteMap.keySet()).orderByAsc("device_id", "id"));
            Map<String, Map<String, Object>> finalElecDeviceSiteMap = elecDeviceSiteMap;

            return sites.stream().map(o -> {
                BasDeviceSiteVo.SimpleVo simpleVo = new BasDeviceSiteVo.SimpleVo();
                BeanUtils.copyProperties(o, simpleVo);
                try {
                    Map<String, Object> map = finalElecDeviceSiteMap.get(o.getId());
                    List<String> params = (List<String>) map.get("params");
                    simpleVo.setPollutantVos(
                            params.stream().map(paramCode -> {
                                AmProblemFiVo.PollutantVo pollutantVo = new AmProblemFiVo.PollutantVo();
                                pollutantVo.setProp(paramCode);
                                // 设置标记区域
                                if (StringUtils.isNotEmpty(problemFi.getProblemStartTime()) &&
                                        StringUtils.isNotEmpty(problemFi.getProblemEndTime())) {
                                    EChartsVO.MarkArea markArea = new EChartsVO.MarkArea(new ArrayList<>());

                                    Map<String, String> map1 = new HashMap<>();
                                    map1.put("xAxis", DateUtils.format("QH", problemFi.getProblemStartTime()));
                                    Map<String, String> map2 = new HashMap<>();
                                    map2.put("xAxis", DateUtils.format("QH", problemFi.getProblemEndTime()));

                                    markArea.getData().add(Arrays.asList(map1, map2));
                                    pollutantVo.setMarkArea(markArea);
                                }
                                return pollutantVo;
                            }).collect(Collectors.toList())
                    );
                } catch (Exception e) {
                    simpleVo.setPollutantVos(new ArrayList<>());
                }
                return simpleVo;
            }).collect(Collectors.toList());
        }
        return null;
    }

    @Override
    public IProductionManageService.FrameDataVo detail002(String id, String startTime, String endTime, Long pageNum, Long pageSize) {
        AmProblemFi problemFi = getById(id);

        IProductionManageService.SearchVo searchVo = new IProductionManageService.SearchVo(startTime, endTime, pageNum, pageSize);

        // 设置关联的dcs点位
        searchVo.setDeviceSimpleVo(getDeviceSimpleVo(problemFi));

        return productionManageService.getFrameData(searchVo);
    }

    @Override
    public EChartsVO detail003004(String id, String startTime, String endTime) {
        AmProblemFi problemFi = getById(id);

        if (problemFi == null) {
            throw new BussinessException("关联分析问题不存在，id=" + id);
        }

        Map<String, Object> extra = null;
        try {
            extra = JSON.parseObject(problemFi.getExtra(), new TypeReference<Map<String, Object>>() {
            });
        } catch (Exception e) {
            log.info("解析extra异常 问题id={}", id, e);
        }

        EChartsVO vo = new EChartsVO();
        vo.setXData(new ArrayList<>());
        vo.setSeries(new ArrayList<>());

        if (extra != null) {
            String type = (String) extra.get("type");
            String pollutantCode = (String) extra.get("pollutantCode");
            String allowableValue = (String) extra.get("allowableValue");
            String factoryId = problemFi.getFactoryId();

            if ("water".equals(type)) {
                SRaOnlineEmissionsWaterQuery.CharDataSearchVo searchVo = new SRaOnlineEmissionsWaterQuery.CharDataSearchVo(factoryId, startTime, endTime, pollutantCode, allowableValue);
                vo = onlineEmissionsWaterService.getChartData(searchVo);
            } else if ("gas".equals(type)) {
                SRaOnlineEmissionsGasQuery.CharDataSearchVo searchVo = new SRaOnlineEmissionsGasQuery.CharDataSearchVo(factoryId, startTime, endTime, pollutantCode, allowableValue);
                vo = onlineEmissionsGasService.getChartData(searchVo);
            }
        }
        return vo;
    }

    @Override
    public EChartsVO detail003002(String id, String startTime, String endTime) {
        AmProblemFi problemFi = getById(id);
        if (problemFi == null) {
            throw new BussinessException("关联分析问题不存在，id=" + id);
        }
        EChartsVO vo = new EChartsVO();
        vo.setXData(new ArrayList<>());
        vo.setSeries(new ArrayList<>());

        PcOutlet onlinePoint = outletMapper.selectById(problemFi.getStationId());

        // 监测点不存在返回空数据
        if (onlinePoint == null) {
            return vo;
        }

        Map<String, Object> extra = null;
        try {
            extra = JSON.parseObject(problemFi.getExtra(), new TypeReference<Map<String, Object>>() {
            });
        } catch (Exception e) {
            log.info("解析extra异常 问题id={}", id, e);
        }
        String pollutantCode = extra != null ? (String) extra.get("pollutantCode") : null;
        Object allowableValue = extra != null ? extra.get("allowableValue") : null;

        // 设置标准值标记线
        EChartsVO.MarkLine markLine = new EChartsVO.MarkLine(new ArrayList<>());
        if (allowableValue != null && StringUtils.isNotEmpty(allowableValue.toString())) {

            Map<String, String> labelMap = new HashMap<>();
            labelMap.put("formatter", "{b}: {c}");

            markLine.getData().add(
                    new HashMap<String, Object>() {{
                        put("name", "标准值");
                        put("yAxis", new BigDecimal(allowableValue.toString()).setScale(2, BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toPlainString());
                        put("label", labelMap);
                    }}
            );
        }

        // 废气监测点
        if ("4".equals(onlinePoint.getPollutantType()) && "1".equals(onlinePoint.getPollutantOutletType())) {
            SEnvGasMonRealQuery query = new SEnvGasMonRealQuery();
            query.setDataType("003002".equals(problemFi.getProblemType()) ? "H" : "M");
            query.setOutletId(onlinePoint.getId());
            query.setMonitoringStartTime(startTime);
            query.setMonitoringEndTime(endTime);

            // 根据污染物code获取在线监测的参数
            SEnvGasMonRealServiceImpl.PollutantEnum pollutantEnum = SEnvGasMonRealServiceImpl.PollutantEnum.getByCode(pollutantCode);
            if (pollutantEnum == null) {
                return vo;
            } else {
                AmProblemFiVo.PollutantVo pvo = new AmProblemFiVo.PollutantVo();
                pvo.setProp(pollutantEnum.prop + "Convert"); // 查询折算值的曲线图数据
                pvo.setMarkLine(markLine);

                query.setPollutantVos(Arrays.asList(pvo));
            }
            vo = envGasMonRealService.getCharData(query);
        } else if ("4".equals(onlinePoint.getPollutantType()) && "2".equals(onlinePoint.getPollutantOutletType())) { // 废水监测点
            SEnvWaterMonRealQuery query = new SEnvWaterMonRealQuery();
            query.setDataType("003002".equals(problemFi.getProblemType()) ? "H" : "M");
            query.setOutletId(onlinePoint.getId());
            query.setMonitoringStartTime(startTime);
            query.setMonitoringEndTime(endTime);

            // 根据污染物code获取在线监测的参数
            SEnvWaterMonRealServiceImpl.PollutantEnum pollutantEnum = SEnvWaterMonRealServiceImpl.PollutantEnum.getByCode(pollutantCode);
            if (pollutantEnum == null) {
                return vo;
            } else {
                AmProblemFiVo.PollutantVo pvo = new AmProblemFiVo.PollutantVo();
                pvo.setProp(pollutantEnum.prop);
                pvo.setMarkLine(markLine);
                query.setPollutantVos(Arrays.asList(pvo));
            }
            vo = envWaterMonRealService.getCharData(query);
        }
        return vo;
    }

    @Override
    public IProductionManageService.FrameDataVo dcsElec(String id, String startTime, String endTime, Long pageNum, Long pageSize) {
        AmProblemFi problemFi = getById(id);

        IProductionManageService.SearchVo searchVo = new IProductionManageService.SearchVo(startTime, endTime, pageNum, pageSize);

        // 设置关联的dcs点位
        searchVo.setDeviceSimpleVo(getDeviceSimpleVo(problemFi));

        // 设置关联的分表计电点位
        searchVo.setMergeDeviceSiteSimpleVo(getDeviceSiteSimpleVo(problemFi));
        return productionManageService.getFrameData(searchVo);
    }

    @Override
    public List<AmProblemFiVo.CountVo> getProblemTypeCount(String problemType) {
        String userRegionCode = SecurityUtils.getLoginUser().getSysUser().getRegionCode();
        if (StringUtils.isEmpty(userRegionCode)) {
            return new ArrayList<>();
        }
        R<List<String>> r = baseRegionService.getRegionCodeListChild(userRegionCode);
        if (r.getCode() != R.SUCCESS) {
            return new ArrayList<>();
        }

        AmProblemFiQuery.ChartDataParam param = new AmProblemFiQuery.ChartDataParam();
        param.setProblemTypeStartWith(problemType);

        // 按照问题类型分组，统计数量
        List<Map<String, Object>> data = amProblemFiMapper.selectChartData(param, r.getData());

        return data.stream().map(o -> {
            AmProblemFiVo.CountVo countVo = new AmProblemFiVo.CountVo();
            countVo.setCount((Long) o.get("count"));
            countVo.setName((String) o.get("problemTypeName"));
            return countVo;
        }).collect(Collectors.toList());
    }

    /**
     * 根据问题类型和时间段返回数据
     *
     * @param problemType
     * @param dateStr
     * @param dateStrEnd
     * @return
     */
    @Override
    public List<AmProblemFi> getProblemByTypeAndTime(String problemType, String dateStr, String dateStrEnd) {
        return amProblemFiMapper.getProblemByTypeAndTime(problemType, dateStr, dateStrEnd);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void rectifyRequired(AmProblemFiProcess param) {
        Assert.hasText(param.getProblemId(), "问题ID必填");
        Assert.hasText(param.getProcessUserName(), "处理人必填");
        Assert.notNull(param.getRectifyLimitStartTime(), "整改期限必填");
        Assert.notNull(param.getRectifyLimitEndTime(), "整改期限必填");
        Assert.notNull(param.getProblemAuditType(), "问题审核人类型必填");
        Assert.notNull(param.getFlownodeId(), "问题流程ID必填");
        final AmProblemFi problemFi = getById(param.getProblemId());
        Assert.notNull(problemFi, "问题不存在");
        problemFi.setProblemStatus(AmProblemStatusEnum.WAIT_RECTIFY.getValue());
        problemFi.setProblemAuditType(AmProblemAuditTypeEnum.valueOfByValue(param.getProblemAuditType()).getValue());
        problemFi.setRectifyLimitStartTime(param.getRectifyLimitStartTime());
        problemFi.setRectifyLimitEndTime(param.getRectifyLimitEndTime());
        problemFi.setFlownodeId(param.getFlownodeId());
        problemFi.setIsShow("1");
        problemFi.setType(1);
        updateById(problemFi);
        param.setProcessType(AmProblemProcessTypeEnum.V1.getValue());
        param.setProcessTypeDesc(AmProblemProcessTypeEnum.V1.getDesc());
        param.setCreateTime(new Date());
        param.setUpdateTime(new Date());
        amProblemFiProcessService.save(param);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void rectifySave(AmProblemFiProcess param) {
        Assert.hasText(param.getProblemId(), "问题ID必填");
        Assert.hasText(param.getProcessUserName(), "处理人必填");
        Assert.notNull(param.getRectifyTime(), "整改完成时间必填");
        Assert.notNull(param.getRectifyRemark(), "整改描述必填");
        Assert.notNull(param.getRectifyFile(), "整改文件必填");
        AmProblemFi problemFi = getById(param.getProblemId());
        Assert.notNull(problemFi, "问题不存在");
        problemFi.setProblemStatus(AmProblemStatusEnum.WAIT_AUDIT.getValue());
        problemFi.setRectifyTime(param.getRectifyTime());
        System.out.println("执法推送企业报警数据保存======"+problemFi);
        updateById(problemFi);
        AmProblemFiProcess amProblemFiProcess = amProblemFiProcessService.selectByProblemId(param.getProblemId());
        if(amProblemFiProcess!=null&&amProblemFiProcess.getProcessType().equals(AmProblemProcessTypeEnum.V1.getValue())){
            param.setFlownodeId(amProblemFiProcess.getFlownodeId());
        }else {
            throw new RuntimeException("请先进行整改期限");
        }
        param.setProcessType(AmProblemProcessTypeEnum.V2.getValue());
        param.setProcessTypeDesc(AmProblemProcessTypeEnum.V2.getDesc());
        param.setCreateTime(new Date());
        param.setProblemId(param.getProblemId());
        param.setId(UUID.randomUUID().toString().replace("-", ""));
        amProblemFiProcessService.save(param);
        sendExtZg(problemFi,param);
    }

    private void sendExtZg(AmProblemFi problemFi, AmProblemFiProcess param) {
        Map<String, Object> params = new HashMap<>();
        params.put("flownodeId", param.getFlownodeId());
        params.put("problemId", param.getProblemId());
        params.put("rectCompleteTime", DateUtil.formatDate(param.getRectifyTime()));
        params.put("rectInfo", param.getRectifyRemark());
        params.put("rectifyLimitStartTime", DateUtil.formatDate(param.getRectifyLimitStartTime()));
        params.put("rectifyLimitEndTime", DateUtil.formatDate(param.getRectifyLimitEndTime()));
        params.put("rectifyLimitSum", param.getRectifyLimitSum());
        final String rectifyFile = param.getRectifyFile();
        if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotBlank(rectifyFile)) {
            final String names = Stream.of(rectifyFile.split(",")).map(e -> e.substring(e.lastIndexOf("/")+1)).collect(Collectors.joining(","));
            params.put("fileName", names);
            params.put("fileUrl", rectifyFile);
        }
        params.put("processUserId", param.getProcessUserId());
        params.put("processUserName", param.getProcessUserName());
//        params.put("auditResult", param.getAuditResult());
//        params.put("failReason", param.getFailReason());
//        params.put("auditRemark", param.getAuditRemark());
        String body = JSON.toJSONString(params);
        log.info("sync zg zf : {}", body);
         String result = HttpUtil.createPost(zfUrl)
                .auth(SecurityUtils.getToken())
                .body(body)
                .execute()
                .body();
        log.info("sync 响应 : {}", result);
        JSONObject json = JSON.parseObject(result);
        Integer code = json.getInteger(AjaxResult.CODE_TAG);
        if (HttpStatus.SUCCESS != code) {
            throw new BussinessException("远程调用整改同步执法系统异常 !" + zfUrl + " ," + "远程调用整改同步执法系统异常：" + result);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void auditResult(AmProblemFiProcess param) {
        Assert.hasText(param.getProblemId(), "问题ID必填");
        Assert.hasText(param.getProcessUserName(), "处理人必填");
        Assert.notNull(param.getAuditResult(), "审核结果必填");
        if (AmProblemAuditResultEnum.UN_PASS.getValue().equals(param.getAuditResult())) {
//            Assert.notNull(param.getFailReason(), "审核不通过原因必填");
            param.setFailReason(param.getAuditRemark());
        }
        final AmProblemFi problemFi = getById(param.getProblemId());
        Assert.notNull(problemFi, "问题不存在");
        if (AmProblemAuditResultEnum.PASS.getValue().equals(param.getAuditResult())) {
            problemFi.setProblemStatus(AmProblemStatusEnum.PASS.getValue());
        } else if (AmProblemAuditResultEnum.UN_PASS.getValue().equals(param.getAuditResult())) {
            problemFi.setProblemStatus(AmProblemStatusEnum.UN_PASS.getValue());
        } else {
            throw new IllegalArgumentException("未知的审核结果：" + param.getAuditResult());
        }
        updateById(problemFi);
        AmProblemFiProcess amProblemFiProcess = amProblemFiProcessService.selectByProblemId(param.getProblemId());
        //当是市局审核且上一次是分局审核的时候为true
        boolean b = amProblemFiProcess != null && param.getProblemAuditType().equals(AmProblemAuditTypeEnum.SJ.getValue())
                && AmProblemAuditTypeEnum.FJ.getValue().equals(amProblemFiProcess.getProblemAuditType());
        //当上面判断为true，或者上一条为待审核时，放行
        if(amProblemFiProcess!=null&&(amProblemFiProcess.getProcessType().equals(AmProblemProcessTypeEnum.V2.getValue())||b)){
            param.setFlownodeId(amProblemFiProcess.getFlownodeId());
        }else {
            throw new RuntimeException("先进行整改信息填写或已经被市局审核通过了");

        }
        param.setProcessType(AmProblemProcessTypeEnum.V3.getValue());
        param.setProcessTypeDesc(AmProblemProcessTypeEnum.V3.getDesc());
        param.setCreateTime(new Date());
        param.setUpdateTime(new Date());
        amProblemFiProcessService.save(param);
//        if (AmProblemAuditTypeEnum.ZS.getValue().equals(problemFi.getProblemAuditType())) {
//            sendExt(problemFi,param);
//        }
    }

    private void sendExt(AmProblemFi problemFi, AmProblemFiProcess param) {
        final AmProblemFiProcess lastZg = amProblemFiProcessService.getOne(Wrappers.<AmProblemFiProcess>lambdaQuery()
                .eq(AmProblemFiProcess::getProblemId, param.getProblemId())
                .eq(AmProblemFiProcess::getProcessType, AmProblemProcessTypeEnum.V2.getValue())
                .orderByDesc(AmProblemFiProcess::getCreateTime)
                .last(" LIMIT 1 ")
        );
        if (lastZg == null) {
            throw new BussinessException("上次整改信息未找到");
        }
        Map<String, Object> params = new HashMap<>();
        params.put("flownodeId", problemFi.getFlownodeId());
        params.put("problemId", param.getProblemId());
        params.put("rectCompleteTime", DateUtil.formatDate(lastZg.getRectifyTime()));
        params.put("rectInfo", lastZg.getRectifyRemark());
        final String rectifyFile = lastZg.getRectifyFile();
        if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotBlank(rectifyFile)) {
            final String names = Stream.of(rectifyFile.split(",")).map(e -> e.substring(e.lastIndexOf("/")+1)).collect(Collectors.joining(","));
            params.put("fileName", names);
            params.put("fileUrl", rectifyFile);
        }
        params.put("processUserId", param.getProcessUserId());
        params.put("processUserName", param.getProcessUserName());
        params.put("auditResult", param.getAuditResult());
        params.put("failReason", param.getFailReason());
        params.put("auditRemark", param.getAuditRemark());
        String body = JSON.toJSONString(params);
        log.info("sync zf : {}", body);
        final String result = HttpUtil.createPost(zfUrl)
                .auth(SecurityUtils.getToken())
                .body(body)
                .execute()
                .body();
        JSONObject json = JSON.parseObject(result);
        Integer code = json.getInteger(AjaxResult.CODE_TAG);
        if (HttpStatus.SUCCESS != code) {
            throw new BussinessException("同步执法系统异常：" + result);
        }


    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void yjSign(AmProblemFiProcess param) {
        Assert.hasText(param.getProblemId(), "问题ID必填");
        final AmProblemFi problemFi = getById(param.getProblemId());
        Assert.notNull(problemFi, "问题不存在");
        problemFi.setProblemStatus(AmProblemStatusEnum.PASS.getValue());
        problemFi.setSignTime(new Date());
        updateById(problemFi);
    }

    @Override
    public Integer countByFactoryId(String factoryId, Integer type){
        Assert.notNull(factoryId, "企业ID不存在");
        QueryWrapper<AmProblemFi> wrapper = new QueryWrapper<>();
        wrapper.eq("factory_id", factoryId);
        wrapper.eq("type", type);
        wrapper.and(QueryWrapper -> QueryWrapper.isNull("is_show").or().like("is_show", "1"));
        if(1==type){
            wrapper.isNotNull("rectify_limit_start_time");
            wrapper.isNotNull("rectify_limit_end_time");
        }
        return amProblemFiMapper.selectCount(wrapper);
    }

    @Override
    public EChartsVO elecMerge(String id, String startTime, String endTime) {
        AmProblemFi problemFi = getById(id);

        List<BasDeviceSiteVo.SimpleVo> deviceSiteSimpleVo = getDeviceSiteSimpleVo(problemFi);

        return monElecRealService.getCharData(deviceSiteSimpleVo, startTime, endTime);
    }

    @Override
    public Object addCause(AmProblemFi param) {
        AmProblemFi byId = getById(param.getId());
        if (!AmProblemStatusEnum.PASS.getValue().equals(byId.getProblemStatus())) {
            throw new BussinessException("问题状态不是签收状态");
        }
        if(byId.getProblemCause() != null){
            throw new BussinessException("问题已添加原因");
        }
       byId.setProblemCause(param.getProblemCause());
        byId.setProblemCauseTime(param.getProblemCauseTime());
        byId.setProblemCauseFile(param.getProblemCauseFile());
        return updateById(byId);
    }

    @Override
    public List<Map<String, Object>> getAListOfAlerts(String type,String topType) {
        QueryWrapper<PcRaProblemType> sort = new QueryWrapper<PcRaProblemType>().orderByAsc("sort");
        if(StringUtils.isNotBlank(type)&&"1".equals(type)) {
            sort.ne("problem_type", "0");
        }else if (StringUtils.isNotBlank(type)&&"0".equals(type)){
            sort.ne("problem_type", "1");
        }
        sort.eq("is_status","1");
        List<PcRaProblemType> problemTypes = problemTypeService.list(sort);

        // 转为map列表
        List<Map<String, Object>> mapList = problemTypes.stream().map(o -> {
            Map<String, Object> map = new HashMap<>();
            map.put("value", o.getId());
            map.put("label", o.getName());
            map.put("parentId", o.getParentId());
            if(StringUtils.isNotBlank(topType)){
                map.put("have0", (topType).equals(o.getTopType()));
            }else {
                map.put("have0", (type).equals(o.getProblemType()));
            }
            return map;
        }).collect(Collectors.toList());

        // 以问题id为key, 转为map
        Map<String, Map<String, Object>> keyMap = mapList.stream().collect(Collectors.toMap(o -> (String) o.get("value"), o -> o));
        // 添加到父节点children属性下
        for (Map<String, Object> map : mapList) {
            Map<String, Object> parent = keyMap.get((String) map.get("parentId"));
            boolean b;
            if (parent != null) {
                List<Map<String, Object>> children = (List<Map<String, Object>>) parent.get("children");
                if (children == null) {
                    children = new ArrayList<>();
                }
                b = children.stream().anyMatch(c ->(c.get("have0")!=null&&(boolean)c.get("have0")));
                children.add(map);
                parent.put("children", children);
                parent.put("have0",b);
            }

        }

        // 返回所有顶级节点
        List<Map<String, Object>> parentId = mapList.stream().filter(o -> o.get("parentId") == null).collect(Collectors.toList());
        //只保留全是预警的。去掉只有全部的级联关系的数据
        parentId = removeFalseHave0(parentId);
        return parentId;
    }

    @Override
    public List<FactoryOutletStaticsVo> selectStatisDataByMonth(Date startTime, Date endTime) {
        return amProblemFiMapper.selectStatisDataByMonth(startTime,endTime);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean rectifyUpdate(AmProblemFiVo param) {
        AmProblemFi amProblemFi=new AmProblemFi();
        BeanUtils.copyProperties(param, amProblemFi);
        amProblemFi.setProblemStatus(AmProblemStatusEnum.WAIT_RECTIFY.getValue());
        baseMapper.updateById(amProblemFi);
        AmProblemFiProcess process = new AmProblemFiProcess();
        process.setId(UuidUtils.generateUuid());
        process.setProblemId(param.getId());
        process.setProcessType(AmProblemProcessTypeEnum.V1.getValue());
        process.setProcessTypeDesc(AmProblemProcessTypeEnum.V1.getDesc());
        process.setProcessUserId(SecurityUtils.getLoginUser().getSysUser().getUserId().toString());
        process.setProcessUserName(SecurityUtils.getLoginUser().getSysUser().getNickName());
        process.setRectifyLimitStartTime(param.getRectifyLimitStartTime());
        process.setRectifyLimitEndTime(param.getRectifyLimitEndTime());
        process.setRectifyLimitSum(param.getRectifyLimitSum());
        process.setCreateTime(new Date());
        process.setFlownodeId(UuidUtils.generateUuid());
//        executorService.submit(() -> {
            // 在新线程中调用 method2 方法
            sendExtZg(amProblemFi,process);
//        });
        return amProblemFiProcessService.save(process);
    }
}
