package com.yfd.platform.modules.patroltask.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.*;
import cn.hutool.json.JSONArray;
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.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.component.WebSocketServer;
import com.yfd.platform.component.nettyclient.*;
import com.yfd.platform.config.HttpServerConfig;
import com.yfd.platform.config.ParentConfig;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.config.redis.RiisConstants;
import com.yfd.platform.constant.SystemCode;
import com.yfd.platform.modules.basedata.domain.Substation;
import com.yfd.platform.modules.basedata.domain.SubstationArea;
import com.yfd.platform.modules.basedata.domain.SubstationDevice;
import com.yfd.platform.modules.basedata.domain.SubstationPatroldevice;
import com.yfd.platform.modules.basedata.mapper.SubstationAreaMapper;
import com.yfd.platform.modules.basedata.mapper.SubstationPatroldeviceMapper;
import com.yfd.platform.modules.basedata.service.ISubstationDeviceService;
import com.yfd.platform.modules.basedata.service.ISubstationService;
import com.yfd.platform.modules.deviceapi.CameraUtil;
import com.yfd.platform.modules.patroltask.domain.ExaminePlan;
import com.yfd.platform.modules.patroltask.domain.TaskDolog;
import com.yfd.platform.modules.patroltask.domain.TaskResult;
import com.yfd.platform.modules.patroltask.domain.TaskTodo;
import com.yfd.platform.modules.patroltask.mapper.ExaminePlanMapper;
import com.yfd.platform.modules.patroltask.mapper.TaskDologMapper;
import com.yfd.platform.modules.patroltask.mapper.TaskResultMapper;
import com.yfd.platform.modules.patroltask.mapper.TaskTodoMapper;
import com.yfd.platform.modules.patroltask.service.DockTaskService;
import com.yfd.platform.modules.patroltask.service.ITaskTodoService;
import com.yfd.platform.modules.robotapi.domain.PlatformParentSystem;
import com.yfd.platform.modules.robotapi.mapper.PlatformParentSystemMapper;
import com.yfd.platform.modules.robotapi.service.IPlatformParentSystemService;
import com.yfd.platform.system.domain.SysDictionaryItems;
import com.yfd.platform.system.mapper.SysDictionaryItemsMapper;
import com.yfd.platform.system.service.ISysDictionaryItemsService;
import com.yfd.platform.utils.*;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * <p>
 * 巡视任务执行表 服务实现类
 * </p>
 *
 * @since 2023-04-08
 */
@Service
@Slf4j
public class TaskTodoServiceImpl extends ServiceImpl<TaskTodoMapper, TaskTodo> implements ITaskTodoService {


    @Resource
    private SubstationAreaMapper substationAreaMapper;
    @Resource
    SubstationPatroldeviceMapper patroldeviceMapper;

    @Resource
    private ExaminePlanMapper examinePlanMapper;

    @Resource
    private TaskTodoMapper taskTodoMapper;

    @Resource
    private TaskResultMapper taskResultMapper;

    @Resource
    private TaskDologMapper taskDologMapper;

    @Resource
    private SubstationPatroldeviceMapper monitorDeviceMapper;
    @Resource
    private ISysDictionaryItemsService sysDictionaryItemsService;

    @Resource
    private QuartzMultiTaskManage quartztaskManage;

    @Resource
    private ISubstationDeviceService substationDeviceService;
    @Resource
    private ISubstationService substationService;
    //    @Resource
    //    private IStationNodeService stationNodeService;

    @Resource
    private SysDictionaryItemsMapper sysDictionaryItemsMapper;

    @Resource
    private RedisTemplate<String, String> redisTemplate;
    @Resource
    private HttpServerConfig httpServerConfig;

    @Resource
    private ParentConfig parentConfig;

    @Resource
    private HttpRESTfulUtils httpUtil;
    @Resource
    private TLSFTPUtils tlsftpUtils;

    @Resource
    private PlatformParentSystemMapper platformParentSystemMapper;

    //    @Resource
    //    private VideoService videoService;

    /**********************************
     * 用途说明: 查询巡视任务执行情况详情
     * 参数说明 taskTodoId
     * 返回值说明: java.util.Map<java.lang.String,java.lang.Object>
     ***********************************/
    @Override
    public Map<String, Object> getTaskToDo(String taskTodoId) {

        TaskTodo taskTodo = this.getById(taskTodoId);
        // 将对象转换成map
        Map<String, Object> map = BeanUtil.beanToMap(taskTodo);
        LambdaQueryWrapper<TaskResult> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TaskResult::getTaskTodoId, taskTodoId).select(TaskResult::getDeviceName, TaskResult::getAreaId, TaskResult::getAreaName, TaskResult::getMainDeviceName, TaskResult::getComponentName, TaskResult::getPatroldeviceName);
        List<Map<String, Object>> maps = taskResultMapper.selectMaps(queryWrapper);
        List<Map<String, Object>> resultMap = new ArrayList<>();
        for (Map<String, Object> strMap : maps) {
            String areaId = strMap.get("areaId").toString();
            //String deviceId = strMap.get("deviceId").toString();
            SubstationArea substationArea = substationAreaMapper.selectById(areaId);
            String stationName = substationArea.getStationName();
            strMap.put("stationName", stationName);
            resultMap.add(strMap);
        }
        map.put("taskResult", resultMap);
        return map;
    }


    /**********************************
     * 用途说明: 分页查询巡视任务执行情况（前台）
     * 参数说明 page
     * 参数说明 startDate
     * 参数说明 endDate
     * 返回值说明: com.baomidou.mybatisplus.extension.plugins.pagination.Page<java.util.Map<java.lang.String,java.lang
     * .Object>>
     ***********************************/
    @Override
    public Page<Map<String, Object>> getTaskImplementation(Page<Map<String, Object>> page, String stationCode,
                                                           String currentDate, String startDate, String endDate, String taskState, String taskName) {
        return taskTodoMapper.getTaskImplementation(page, stationCode, currentDate, startDate, endDate, taskState, taskName);
    }


    /**********************************
     * 用途说明: 根据任务ID,处理待处理任务
     * 参数说明 taskTodoId 待处理任务ID  optType操作类型
     *  pause：暂停；resume:暂停后恢复 runNow:立即执行 delete: 删除  stop：终止（不可恢复）;
     * optType=delete  删除或取消
     * 返回值说明: 当前任务信息
     ***********************************/
    @Override
    public TaskTodo doCurrentTask(String taskTodoId, String optType) throws InterruptedException {
        //TaskState  0:待执行； 1:已执行；2:正在执行；3:暂停；4:终止；5:未执行；6:超期；
        TaskTodo taskTodo = this.getById(taskTodoId);
        String dotype = "";
        if (SystemCode.TASK_PAUSE_CODE.getCode().equals(optType)) {

            if ("0".equals(taskTodo.getTaskState())) {
                // 待执行暂停
                quartztaskManage.pauseJob(taskTodo);
                taskTodo.setCustom1("2");
            } else {
                // 执行中暂停
                quartztaskManage.interruptJob(taskTodo);
                //                quartztaskManage.deleteJob(taskTodo);
                taskTodo.setCustom1("3");
            }

            taskTodo.setCustom3("1");
            dotype = "手动暂停任务";
            taskTodo.setTaskState("3");
            taskTodoMapper.updateById(taskTodo);
            if (!"0".equals(taskTodo.getTaskState()) && StrUtil.isBlank(taskTodo.getRobotCode())) {
                resumeLowerTask(taskTodo.getStationCode(), taskTodoId, taskTodo.getPriority(), taskTodo.getCustom3());
            }
            WebSocketServer.sendInfo("taskresult_" + taskTodo.getStationCode(), "msg");
        }
        if (SystemCode.TASK_RESUME_CODE.getCode().equals(optType)) {
            String custom1 = taskTodo.getCustom1();
            //暂停后恢复
            if ("2".equals(custom1)) {
                taskTodo.setTaskState("0");
                quartztaskManage.resumeJob(taskTodo);
            } else {
                //                quartztaskManage.addJob(taskTodo);
                taskTodo.setTaskState("2");
                quartztaskManage.runJobNow(taskTodo);
            }

            // 汤伟修改的逻辑
            taskTodo.setCustom1("");
            dotype = "手动恢复任务";
            taskTodoMapper.updateById(taskTodo);
            WebSocketServer.sendInfo("taskresult_" + taskTodo.getStationCode(), "msg");
        }
        if (SystemCode.TASK_RUN_CODE.getCode().equals(optType)) {
            //立即执行
            List<TaskTodo> list = taskTodoMapper.selectList(new LambdaQueryWrapper<TaskTodo>().
                    eq(TaskTodo::getStationCode, taskTodo.getStationCode()).
                    in(TaskTodo::getTaskState, "2").
                    ne(TaskTodo::getTaskTodoId, taskTodo.getTaskTodoId()).orderByDesc(TaskTodo::getPlanStartTime)
            );
            for (TaskTodo taskTodo1 : list) {
                quartztaskManage.interruptJob(taskTodo1); //中断
                // 汤伟加的逻辑
                taskTodo1.setTaskState("3");
                taskTodo1.setCustom3("");
                taskTodo1.setCustom1("3"); //程序控制的中断执行
                taskTodoMapper.updateById(taskTodo1);
            }
            taskTodo.setTaskState("2");
            taskTodo.setCustom3("2");
            taskTodo.setStartTime(DateUtil.date().toString());
            taskTodoMapper.updateById(taskTodo);
            quartztaskManage.runJobNow(taskTodo);
            WebSocketServer.sendInfo("taskresult_" + taskTodo.getStationCode(), "msg");
        }
        if (SystemCode.TASK_DELETE_CODE.getCode().equals(optType) || SystemCode.TASK_STOP_CODE.getCode().equals(optType)) {//删除 或者 终止
            quartztaskManage.deleteJob(taskTodo);
            taskTodo.setTaskState("4");
            dotype = "手动终止任务";
            taskTodoMapper.updateById(taskTodo);
        }
        // 记录任务操作日志
        TaskDolog taskDolog = new TaskDolog();
        taskDolog.setId(IdUtil.fastSimpleUUID());
        taskDolog.setStationCode(taskTodo.getStationCode());
        taskDolog.setTaskCode(taskTodo.getTaskCode());
        taskDolog.setTaskName(taskTodo.getTaskName());
        taskDolog.setTaskTodoid(taskTodo.getTaskTodoId());
        taskDolog.setPlanStartTime(taskTodo.getPlanStartTime());
        taskDolog.setDoType(dotype);
        String logger = "";
        logger = SecurityUtils.getCurrentUsername();
        taskDolog.setLogger(logger);
        taskDolog.setLogTime(new Timestamp(DateUtil.current()));
        taskDolog.setDescription(String.format("%s在%s，对%s[%s]，执行了 [%s] 操作！", logger, DateUtil.now(),
                taskTodo.getTaskName(), taskTodo.getTaskTodoId(), dotype));
        recordTaskDoLog(taskDolog);
        return taskTodo;
    }

    /**********************************
     * 用途说明: 根据任务ID,查询巡视点位清单
     * 参数说明 taskTodoId 待处理任务ID
     * 返回值说明: 任务对象列表
     *
     ***********************************/
    @Override
    public List<Map<String, Object>> queryTaskResult(String taskTodoId) {
        return taskTodoMapper.queryTaskResult(taskTodoId);
    }

    @Override
    //巡视点位 时间是否与检修计划时间冲突
    public int queryExaminePlan(String deviceid, String planStartTime) {
        int count = examinePlanMapper.selectCount(new LambdaQueryWrapper<ExaminePlan>().
                eq(ExaminePlan::getDatastatus, "1").
                like(ExaminePlan::getDeviceList, deviceid).
                lt(ExaminePlan::getStartTime, planStartTime).
                gt(ExaminePlan::getEndTime, planStartTime));
        return count;
    }

    @Override
    //供智能识别程序调用，更新识别结果
    @Transactional(rollbackFor = Exception.class)
    public boolean updateTaskResult(TaskResult taskResult) {
        String todotaskid = taskResult.getTaskTodoId();
        String valid = taskResult.getValid();
        if (valid.equals("0")) {//识别识别
            taskResult.setFlag("4");  //4:巡视失败
        } else if (valid.equals("1")) {//识别成功
            taskResult.setFlag("2");
        }
        taskResult.setTime(DateUtil.now());
        taskResult.setLastmodifydate(new Timestamp(DateUtil.current()));
        taskResultMapper.updateById(taskResult);

        //更新巡视任务
        TaskTodo taskTodo = taskTodoMapper.selectById(todotaskid);
        int sumnum = taskTodo.getDeviceSumnum();
        int percent = 0;
        //已分析完成数量
        int anysislnum = taskResultMapper.selectCount(
                new LambdaQueryWrapper<TaskResult>().
                        eq(TaskResult::getTaskTodoId, todotaskid).
                        ne(TaskResult::getFlag, "0")
        );
        // 赋值执行数量
        List<Map<String, Object>> list = this.getTaskResultById(taskTodo.getTaskTodoId(), null, null, null);
        // 已送检点数
        long patrolCount = list.stream().filter(t -> !("0").equals(t.get("flag")) && !("1").equals(t.get("flag"))).count();
        // 失败的数量
        long failCount =
                list.stream().filter(t -> ("4").equals(t.get("flag")) || ("6").equals(t.get("flag"))).count();
        // 异常数量
        long abnormalCount = list.stream().filter(t -> ("2").equals(t.get("valid1"))).count();
        taskTodo.setDeviceDeforeNum((int) patrolCount);
        taskTodo.setDeviceUnusualnum((int) abnormalCount);
        taskTodo.setDeviceFailureNum((int) failCount);
        //检修跳过数量
        //        int checklnum = taskResultMapper.selectCount(
        //                new LambdaQueryWrapper<TaskResult>().
        //                        eq(TaskResult::getTaskTodoId, todotaskid).
        //                        eq(TaskResult::getFlag, "3")
        //        );
        //        int totalnum = sumnum - checklnum;
        int totalnum = sumnum;
        if (totalnum > 0) {
            //百分之多少
            percent = anysislnum * 100 / totalnum;
            taskTodo.setEndTime(DateUtil.now());
        }
        if (!"100".equals(taskTodo.getTaskProgress())) {
            taskTodo.setTaskProgress(String.valueOf(percent));
        }
//        taskTodo.setTaskProgress(String.valueOf(percent));
        taskTodo.setDeviceNow(taskResult.getDeviceId());
        taskTodo.setLastmodifydate(new Timestamp(DateUtil.current()));
        if (percent == 100) {
            taskTodo.setTaskState("1");//任务已执行
            taskTodo.setTaskEstimatedTime("0");
            taskTodo.setEndTime(DateUtil.now());
        }
        taskTodoMapper.updateById(taskTodo);
        return true;
    }

    @Override
    //更新巡视任务状态和巡视任务执行进度
    //flag:'0未巡视，1：已巡视(图像已采集)，2：已完成（图像已分析）；3:设备检修中；4:巡视失败；5:已修正  6：已巡视(图像采集失败)'
//    @Transactional(rollbackFor = Exception.class)
    public synchronized boolean updateTaskResultStatus(String todotaskid, String taskresultid, String imagefilename, String flag) {
        //更新当前任务巡检点巡视完成状态
        TaskResult taskResult = taskResultMapper.selectById(taskresultid);
        taskResult.setResultId(taskresultid);
        taskResult.setFilePath(imagefilename);
        taskResult.setDefectFilePath(imagefilename);  //检测图赋值和初始图一致
        taskResult.setFlag(flag);
        String now = DateUtil.now();
        taskResult.setPatroldeviceDate(now);
        if ("1".equals(flag)) {
            taskResult.setTime(now);
        }
        taskResult.setLastmodifydate(new Timestamp(DateUtil.current()));
        taskResultMapper.updateById(taskResult);

        //更新当前任务状态及进度信息
        TaskTodo taskTodo = taskTodoMapper.selectById(todotaskid);
        int sumnum = taskTodo.getDeviceSumnum();
        int percent = 0;
        //巡视数量
        int patrolnum =
                taskResultMapper.selectCount(new LambdaQueryWrapper<TaskResult>().eq(TaskResult::getTaskTodoId,
                        todotaskid).ne(TaskResult::getFlag, "0"));

        // 赋值执行数量
        List<Map<String, Object>> list = this.getTaskResultById(taskTodo.getTaskTodoId(), null, null, null);
        // 已送检点数
        long patrolCount = list.stream().filter(t -> !("0").equals(t.get("flag")) && !("1").equals(t.get("flag"))).count();
        // 失败的数量
        long failCount =
                list.stream().filter(t -> ("4").equals(t.get("flag")) || ("6").equals(t.get("flag"))).count();
        // 异常数量
        long abnormalCount = list.stream().filter(t -> ("2").equals(t.get("valid1"))).count();
        taskTodo.setDeviceDeforeNum((int) patrolCount);
        taskTodo.setDeviceUnusualnum((int) abnormalCount);
        taskTodo.setDeviceFailureNum((int) failCount);

        percent = patrolnum * 100 / sumnum;  //百分之多少
        if (!"100".equals(taskTodo.getTaskProgress())) {
            taskTodo.setTaskProgress(String.valueOf(percent));
        }
//        taskTodo.setTaskProgress(String.valueOf(percent));
        boolean b = patrolnum == sumnum;
        if (b) {
            taskTodo.setTaskState("1");
            taskTodo.setEndTime(DateUtil.now());
        }
        taskTodo.setDeviceNow(taskResult.getDeviceId());//当前巡视点
        taskTodo.setLastmodifydate(new Timestamp(DateUtil.current()));
        taskTodoMapper.updateById(taskTodo);
        // 向上级发送任务数据
//        this.sendTaskResult(taskTodo, taskResult);
        String stationCode = taskResult.getStationCode();
        JSONObject jsonObject = new JSONObject();
        String taskTodoId = taskTodo.getTaskTodoId();
        String taskType = taskTodo.getTaskType();
        jsonObject.putOnce("taskTodoId", taskTodoId);
        jsonObject.putOnce("taskType", taskType);
        WebSocketServer.sendInfo("taskresult_" + stationCode, jsonObject.toString());


        // 巡视任务状态发生变化或任务进度发生变化时，区域巡视主机主动向上级系统上报状态数据
        return true;
    }

    /**********************************
     * 用途说明: 上传任务执行信息到上级
     * 参数说明 taskTodo
     * 参数说明 taskResult
     * 返回值说明: void
     ***********************************/
    @Override
    public void sendTaskResult(TaskTodo taskTodo, TaskResult taskResult) {
        String filePath = taskResult.getFilePath();
//        if(StrUtil.isNotBlank(taskResult.getDefectFilePath())){
//            filePath=taskResult.getDefectFilePath();
//        }
        boolean connect = false;
        try {
            List<PlatformParentSystem> list = platformParentSystemMapper.selectList(new LambdaQueryWrapper<PlatformParentSystem>().eq(PlatformParentSystem::getIsEnable, "1"));
            if (list.size() > 0) {
                PlatformParentSystem platformParentSystem = list.get(0);
                if (StrUtil.isNotBlank(filePath)) {
                    if (tlsftpUtils.isConnected()) {
                        tlsftpUtils.disconnect();
                    }
                    filePath = URLDecoder.decode(filePath, "utf-8");
                    String suff = "/home/ftpsuser";
                    connect = tlsftpUtils.connect(platformParentSystem.getFtpIp(), platformParentSystem.getFtpUser(), platformParentSystem.getFtpPassword(), NumberUtil.parseInt(platformParentSystem.getFtpPort()));
                    String path = StrUtil.subBefore(File.separator + filePath, "/", true);
                    tlsftpUtils.upload(suff + path, new File(httpServerConfig.getSnapFilePath() + filePath));
                }
            }
            String patroldeviceCode = taskResult.getPatroldeviceCode();
            String patrolDeviceCode = patroldeviceCode;
            List<SubstationPatroldevice> substationPatroldevices = patroldeviceMapper.selectList(new LambdaQueryWrapper<SubstationPatroldevice>().eq(SubstationPatroldevice::getInternationalId, patroldeviceCode));
            if (substationPatroldevices.size() > 0) {
                SubstationPatroldevice substationPatroldevice = substationPatroldevices.get(0);
                patrolDeviceCode = substationPatroldevice.getPatroldeviceCode();
            }
            JSONObject taskResultData = new JSONObject();
            taskResultData.putOpt("patroldevice_name", taskResult.getPatroldeviceName());
            taskResultData.putOpt("patroldevice_code", patrolDeviceCode);
            taskResultData.putOpt("task_name", taskResult.getTaskName());
            taskResultData.putOpt("task_code", taskResult.getTaskCode());
            taskResultData.putOpt("device_name", taskResult.getDeviceName());
            taskResultData.putOpt("device_id", taskResult.getDeviceId());
            taskResultData.putOpt("value_type", taskResult.getValueType());
            taskResultData.putOpt("value", taskResult.getValue());
            String unit = "";
            if (StrUtil.isNotBlank(taskResult.getUnit())) {
                unit = taskResult.getUnit();
            }
            String value = taskResult.getValue();
            if (!("1".equals(taskResult.getRecognitionType()) || "4".equals(taskResult.getRecognitionType()))) {
                value = taskResult.getDesc();
            }
            taskResultData.putOpt("value_unit", value + unit);
            taskResultData.putOpt("unit", taskResult.getUnit());
            taskResultData.putOpt("time", taskResult.getTime());
            taskResultData.putOpt("recognition_type", taskResult.getRecognitionType());
            taskResultData.putOpt("file_type", taskResult.getFileType());
            taskResultData.putOpt("file_path", filePath);
            String rectangle = taskResult.getRectangle();
//            if(StrUtil.isNotBlank(rectangle)){
//                JSONArray jsonArray = JSONUtil.parseArray(rectangle);
//
//            }
            taskResultData.putOpt("rectangle", "");
            taskResultData.putOpt("task_patrolled_id", taskResult.getTaskTodoId());
            taskResultData.putOpt("valid", taskResult.getValid());
            taskResultData.putOpt("flag", taskResult.getFlag());
            this.sendTaskData(SystemCode.TYPE_TASK_RESULT_CODE.getCode(), "", taskTodo.getStationCode(), taskResultData.toString());
            tlsftpUtils.disconnect();
        } catch (Exception e) {
            if (connect) {
                tlsftpUtils.disconnect();
            }
            log.error(e.getMessage());;

        }
        JSONObject taskData = new JSONObject();
        taskData.putOpt("task_patrolled_id", taskTodo.getTaskTodoId());
        taskData.putOpt("task_name", taskTodo.getTaskName());
        taskData.putOpt("task_code", taskTodo.getTaskCode());
        taskData.putOpt("task_state", taskTodo.getTaskState());
        taskData.putOpt("plan_start_time", taskTodo.getPlanStartTime());
        taskData.putOpt("start_time", taskTodo.getStartTime());
        taskData.putOpt("task_progress", taskTodo.getTaskProgress());
        taskData.putOpt("task_estimated_time", taskTodo.getTaskEstimatedTime());
        taskData.putOpt("description", taskTodo.getDescription());
        this.sendTaskData(SystemCode.TYPE_TASK_STATUS_CODE.getCode(), "", taskTodo.getStationCode(), taskData.toString());
    }

    public void sendTaskData(String Type, String Command, String Code, String Items) {
        String xml = MyXmlUtil.getXml(httpServerConfig.getPatrolServerid(), parentConfig.getParentId(), Type
                , Command, Code, Items);
        log.info(xml);
        MyMessageProtocol messageProtocol = new MyMessageProtocol();
        messageProtocol.setSenderSerialNo(BootSessionCache.getRequestSessionID());
        messageProtocol.setReceiverSerialNo(new Long(0L));
        messageProtocol.setSessionflag(0);
        messageProtocol.setXmllen(xml.getBytes(CharsetUtil.UTF_8).length);
        messageProtocol.setXmlcontent(xml.getBytes(CharsetUtil.UTF_8));
        if (BootNettyClientChannelCache.channelMapCache.size() > 0) {
            for (Map.Entry<String, BootNettyClientChannel> entry :
                    BootNettyClientChannelCache.channelMapCache.entrySet()) {
                BootNettyClientChannel bootNettyChannel = entry.getValue();
                if (bootNettyChannel != null && bootNettyChannel.getChannel().isOpen()) {
                    bootNettyChannel.getChannel().writeAndFlush(messageProtocol);
                }
//                else {
//                    BootNettyClientThread thread = new BootNettyClientThread(parentConfig.getParentIp(),
//                            Integer.parseInt(parentConfig.getTcpPort()), parentConfig);
//                    thread.start();
//                }
            }
        }
//        else {
//            BootNettyClientThread thread = new BootNettyClientThread(parentConfig.getParentIp(),
//                    Integer.parseInt(parentConfig.getTcpPort()), parentConfig);
//            thread.start();
//        }
    }

    @Override
    public boolean pauseLowerTask(String stationcode, String todotaskid, String priority) {
        List<TaskTodo> list = taskTodoMapper.selectList(new LambdaQueryWrapper<TaskTodo>().
                eq(TaskTodo::getStationCode, stationcode).
                in(TaskTodo::getTaskState, "2").
                //优先级低于当前级别任务
                        lt(TaskTodo::getPriority, priority).
                        ne(TaskTodo::getTaskTodoId, todotaskid).orderByDesc(TaskTodo::getPlanStartTime)
        );
        for (TaskTodo taskTodo : list) {
            if ("2".equals(taskTodo.getTaskState())) {
                //执行中
                //中断
                quartztaskManage.interruptJob(taskTodo);
                // 汤伟加的逻辑
                taskTodo.setTaskState("3");
                //程序控制的中断执行
                taskTodo.setCustom1("3");
                taskTodoMapper.updateById(taskTodo);
            }
        }
        return true;
    }

    /**********************************
     * 用途说明: 任务开始前，判断是否有任务等级大于等于当前任务的，有就暂停当前任务
     * 参数说明 stationCode
     * 参数说明 taskTodoId
     * 参数说明 priority
     * 返回值说明: boolean
     ***********************************/
    @Override
    public boolean pauseUpperTask(String stationCode, String taskTodoId, String priority) {
        Integer count = taskTodoMapper.selectCount(new LambdaQueryWrapper<TaskTodo>().
                isNull(TaskTodo::getRobotCode).
                eq(TaskTodo::getStationCode, stationCode).
                eq(TaskTodo::getTaskState, "2").
                //between(TaskTodo::getPlanStartTime,DateUtil.now(),DateUtil.format(enddate,"yyyy-MM-dd HH:mm:ss")).
                        ge(TaskTodo::getPriority, priority).ne(TaskTodo::getTaskTodoId, taskTodoId)//优先级大于等于当前级别
        );
        TaskTodo taskTodo = taskTodoMapper.selectById(taskTodoId);
        Integer count1 = taskTodoMapper.selectCount(new LambdaQueryWrapper<TaskTodo>().
                isNull(TaskTodo::getRobotCode).
                eq(TaskTodo::getStationCode, stationCode).
                eq(TaskTodo::getTaskState, "0").
                eq(TaskTodo::getPlanStartTime, taskTodo.getPlanStartTime()).
                //between(TaskTodo::getPlanStartTime,DateUtil.now(),DateUtil.format(enddate,"yyyy-MM-dd HH:mm:ss")).
                        gt(TaskTodo::getPriority, priority).ne(TaskTodo::getTaskTodoId, taskTodoId)//优先级大于等于当前级别
        );
        if (count > 0 || count1 > 0) {
            /*if ("0".equals(taskTodo.getTaskState())) {//待执行
                quartztaskManage.pauseJob(taskTodo);
                taskTodo.setTaskState("3");
                taskTodo.setCustom1("2"); //程序控制的暂停
                taskTodoMapper.updateById(taskTodo);
            }*/
            if ("2".equals(taskTodo.getTaskState())) {//执行中
                quartztaskManage.interruptJob(taskTodo); //中断
                taskTodo.setTaskState("3");
                taskTodo.setCustom1("3"); //程序控制的中断执行
                taskTodoMapper.updateById(taskTodo);
                WebSocketServer.sendInfo("taskresult_" + taskTodo.getStationCode(), "msg");
            }
        }
        return true;
    }

    @Override
    public boolean resumeLowerTask(String stationcode, String todotaskid, String priority, String custom3) throws InterruptedException {
        DateTime date = DateUtil.date();
        //一天的开始
        Date beginOfDay = DateUtil.beginOfDay(date);
        LambdaQueryWrapper<TaskTodo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TaskTodo::getStationCode, stationcode).
                eq(TaskTodo::getTaskState, "3").
                ne(TaskTodo::getTaskTodoId, todotaskid).
                //程序控制(暂停了的或者中断执行的)
                        in(TaskTodo::getCustom1, "3").
                //优先级低于等于当前级别任务
                //lt(TaskTodo::getPriority, priority)//优先级低于当前级别任务
                        le(TaskTodo::getPriority, priority).ge(TaskTodo::getPlanStartTime, beginOfDay).le(TaskTodo::getPlanStartTime, DateUtil.date());
        if (StrUtil.isBlank(custom3) || "2".equals(custom3)) {
            queryWrapper.and(q -> q.isNull(TaskTodo::getCustom3).or().eq(TaskTodo::getCustom3, ""));
        }
        queryWrapper.orderByAsc(TaskTodo::getPlanStartTime).orderByDesc(TaskTodo::getPriority);
        List<TaskTodo> list = taskTodoMapper.selectList(queryWrapper);
        if (list != null && list.size() > 0) {
            TaskTodo taskTodo = list.get(0);
            taskTodo.setTaskState("2");
            taskTodo.setCustom1("");
            taskTodoMapper.updateById(taskTodo);
            WebSocketServer.sendInfo("taskresult_" + taskTodo.getStationCode(), "msg");
            //如果是手动暂停就恢复，如果是系统暂停立即执行一次
            quartztaskManage.runJobNow(taskTodo);
        }
        return true;
    }

    @Override
    public boolean recordTaskDoLog(TaskDolog taskDolog) {
        taskDologMapper.insert(taskDolog);
        return true;
    }

    @Override
    public List<Map<String, Object>> getTaskToDoStatList(String stationCode, String currentDate, String startDate,
                                                         String endDate, String taskName) {
        return taskTodoMapper.getTaskToDoStatList(stationCode, currentDate, startDate, endDate, taskName);
    }

    @Override
    public Page<Map<String, Object>> getTaskReportList(Page<Map<String, Object>> page, String stationCode,
                                                       String areaId,
                                                       String taskName, String type, String startDate, String endDate
            , String bayId, String patrolType) {
        return taskTodoMapper.getTaskReportList(page, stationCode, areaId, taskName, type, startDate, endDate, bayId,
                patrolType);
    }

    /**********************************
     * 用途说明: 根据任务执行情况查询任务结果
     * 参数说明 taskTodoId 任务执行情况id
     * 返回值说明: java.util.List<com.yfd.platform.modules.patroltask.domain.TaskResult>
     ***********************************/
    @Override
    public List<Map<String, Object>> getTaskResultById(String taskTodoId, String areaId, String bayId, String mainDeviceId) {
        return taskResultMapper.getTaskResultById(taskTodoId, areaId, bayId, mainDeviceId);
    }

    /**********************************
     * 用途说明: 异常点位查询
     * 参数说明 page
     * 参数说明 taskTodoIds
     * 参数说明 taskName
     * 参数说明 deviceName
     * 参数说明 patroldeviceName
     * 参数说明 componentName
     * 参数说明 recognitionType
     * 参数说明 status
     * 参数说明 startDate
     * 参数说明 endDate
     * 返回值说明: com.baomidou.mybatisplus.extension.plugins.pagination.Page<java.util.Map<java.lang.String,java.lang
     * .Object>>
     ***********************************/
    @Override
    public Page<Map<String, Object>> getAbnormalDeviceList(Page<Map<String, Object>> page, String stationCode,
                                                           String areaId,
                                                           String bayId,
                                                           String taskName,
                                                           String deviceName, String patroldeviceName,
                                                           String componentName, String recognitionType, String status,
                                                           String startDate, String endDate) {
        return taskResultMapper.getAbnormalDeviceList(page, stationCode, areaId, bayId, taskName,
                deviceName, patroldeviceName, componentName, recognitionType, status, startDate, endDate);
    }

    /**********************************
     * 用途说明: 导出异常点位
     * 参数说明 records
     * 参数说明 response
     * 返回值说明: void
     ***********************************/
    @Override
    public void exportAbnormalDevice(List<Map<String, Object>> records, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> recognition_type = sysDictionaryItemsService.getDeviceByType("recognition_type");
        List<Map<String, Object>> DeviceClass = sysDictionaryItemsService.getDeviceByType("DeviceClass");
        for (Map<String, Object> record : records) {
            String deviceClass = "";
            if (!Objects.isNull(record.get("deviceClass"))) {
                Map<String, Object> map =
                        DeviceClass.stream().filter(r -> !Objects.isNull(record.get("deviceClass")) && r.get(
                                "itemcode").equals(record.get("deviceClass").toString())).findFirst().orElse(null);
                if (map != null) {
                    deviceClass = map.get("dictname").toString();
                }
            }
            record.put("deviceClassName", deviceClass);
            String recognitionType = "";
            if (!Objects.isNull(record.get("recognitionType"))) {
                Map<String, Object> map = recognition_type.stream().filter(r -> !Objects.isNull(record.get(
                        "recognitionType")) && r.get("itemcode").equals(record.get("recognitionType").toString())).findFirst().orElse(null);
                if (map != null) {
                    recognitionType = map.get("dictname").toString();
                }
            }
            record.put("recognitionTypeName", recognitionType);
            if (ObjectUtil.isNotEmpty(record.get("defectFilePath"))) {
                String filePath = record.get("defectFilePath").toString();
                filePath = URLDecoder.decode(filePath, "utf-8");
                //filePath = filePath.replace("\\", "/");
                //                hashMap.put("巡视图片", new FileInputStream(new File("D:\\riis\\video\\" + filePath)));
                record.put("img", httpServerConfig.getSnapFilePath() + filePath);

            }
            if (ObjectUtil.isNotEmpty(record.get("value"))) {
                String value = record.get("value").toString();
                String unit = ObjectUtil.isNotEmpty(record.get("unit")) ? record.get("unit").toString() : "";
                record.put("value", value + unit);
            }
        }
        String[] headers = {"区域名称", "间隔名称", "设备名称", "部件名称", "点位名称", "点位分类", "识别类型", "巡视结果", "巡视结论", "巡视时间", "巡视图片",
                "审核人",
                "审核时间"};
        String[] keys = {"areaName", "bayName", "taskName", "patroldeviceName", "componentName", "deviceName",
                "deviceClassName",
                "recognitionTypeName", "value", "analysisResult", "time", "img", "cexamineUserName", "examineDate"};
        String imgs = "img";
        FileUtil.excelImg(records, headers, keys, imgs, "", response);
    }

    /**********************************
     * 用途说明: 根据任务执行情况ID查询点位查询
     * 参数说明 page
     * 参数说明 taskTodoId
     * 参数说明 valid
     * 返回值说明: com.baomidou.mybatisplus.extension.plugins.pagination.Page<java.util.Map<java.lang.String,java.lang
     * .Object>>
     ***********************************/
    @Override
    public Page<Map<String, Object>> getTaskDeviceList(Page<Map<String, Object>> page, String taskTodoId,
                                                       String deviceName, String valid) {
        return taskResultMapper.getTaskDeviceList(page, taskTodoId, deviceName, valid);
    }

    /**********************************
     * 用途说明: 查询点位历史曲线
     * 参数说明 deviceId
     * 返回值说明: java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
     ***********************************/
    @Override
    public List<Map<String, Object>> getHistoricalCurve(String deviceId) {
        return taskResultMapper.getHistoricalCurve(deviceId);
    }

    /**********************************
     * 用途说明: 根据巡视任务执行情况ID查看详情
     * 参数说明 taskTodoId
     * 返回值说明: java.util.Map<java.lang.String,java.lang.Object>
     ***********************************/
    @Override
    public Map<String, Object> getTaskTodoById(String taskTodoId, String areaId, String bayId, String mainDeviceId) {
        TaskTodo taskTodo = this.getById(taskTodoId);
        if (taskTodo == null) {
            return null;
        }
        long deviceSumnum = taskTodo.getDeviceSumnum();
        Map<String, Object> map = BeanUtil.beanToMap(taskTodo);
        String stationCode = taskTodo.getStationCode();
        Substation substation =
                substationService.getOne(new LambdaQueryWrapper<Substation>().eq(Substation::getStationCode,
                        stationCode));
        map.put("isStationFlag", substation.getIsStationFlag());
        List<Map<String, Object>> list = this.getTaskResultById(taskTodo.getTaskTodoId(), areaId, bayId, mainDeviceId);
        // 已巡视
        long patrolCount = list.stream().filter(t -> !("0").equals(t.get("flag"))).count();
        map.put("patrolCount", patrolCount);
        // 检修数量
        long serviceCount = list.stream().filter(t -> ("3").equals(t.get("flag"))).count();
        map.put("serviceCount", serviceCount);

        // 成功的数量
        long successCount =
                list.stream().filter(t -> ("2").equals(t.get("flag")) || ("5").equals(t.get("flag"))).count();
        map.put("successCount", successCount);
        // 失败的数量
        long failCount =
                list.stream().filter(t -> ("4").equals(t.get("flag")) || ("6").equals(t.get("flag"))).count();
        map.put("failCount", failCount);
        long normalCount = list.stream().filter(t -> ("1").equals(t.get("valid1"))).count();
        long abnormalCount = list.stream().filter(t -> ("2").equals(t.get("valid1"))).count();
        // 正常数量
        map.put("normalCount", normalCount);
        // 异常数量
        map.put("abnormalCount", abnormalCount);
        long count = deviceSumnum - patrolCount <= 0 ? 0 : deviceSumnum - patrolCount;
        String custom1 = "总点位" + deviceSumnum + "个，已检点位" + patrolCount + "个，未检点位" + count +
                "个，正常点位" + normalCount + "个，异常点位" + abnormalCount + "个";
        String detail = "成功" + successCount + "；失败" + failCount + "；正常" + normalCount + "；异常" + abnormalCount;
        map.put("custom1", custom1);
        map.put("detail", detail);
        return map;
    }

    /**********************************
     * 用途说明: 查询主设备所关联的点位
     * 参数说明 ids
     * 参数说明 meterType
     * 参数说明 recognitionType
     * 参数说明 startDate
     * 参数说明 endDate
     * 返回值说明: java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
     ***********************************/
    @Override
    public List<Map<String, Object>> getDeviceByMainDevice(String mainDeviceId, String meterType, String recognitionType
            , String startDate, String endDate) {
        return taskTodoMapper.getDeviceByMainDevice(mainDeviceId, meterType, recognitionType, startDate, endDate);
    }

    /**********************************
     * 用途说明: 修正巡视结果
     * 参数说明 taskResult
     * 返回值说明: boolean
     ***********************************/
    @Override
    public boolean updateTaskResultById(TaskResult taskResult) {
        int i = taskResultMapper.updateById(taskResult);
        return i > 0;
    }

    /**********************************
     * 用途说明: 数据对比分析列表
     * 参数说明 page
     * 参数说明 deviceId
     * 返回值说明: com.baomidou.mybatisplus.extension.plugins.pagination.Page<java.util.Map<java.lang.String,java.lang
     * .Object>>
     ***********************************/
    @Override
    public Page<Map<String, Object>> getTaskResultList(Page<Map<String, Object>> page, String deviceId,
                                                       String startDate, String endDate) {
        String[] split = deviceId.split(",");
        List<String> idList = Arrays.asList(split);
        LambdaQueryWrapper<TaskResult> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(TaskResult::getDeviceId, idList).eq(TaskResult::getDatastatus, "1");
        // 开始时间判断
        if (StrUtil.isNotBlank(startDate)) {
            queryWrapper.le(TaskResult::getTime, endDate);
        }
        // 结束时间判断
        if (StrUtil.isNotBlank(endDate)) {
            queryWrapper.ge(TaskResult::getTime, startDate);
        }
        queryWrapper.orderByAsc(TaskResult::getTime);
        return taskResultMapper.selectMapsPage(page, queryWrapper);
    }

    /**********************************
     * 用途说明: 数据对比分析曲线
     * 参数说明 deviceId
     * 返回值说明: java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
     ***********************************/
    @Override
    public Map<String, Object> getAnalysisCurve(String deviceId, String startDate, String endDate) {
        String[] split = deviceId.split(",");
        String[] ids = split;
        List<String> dayList = getDays(startDate, endDate);
        List<String> dateList = new ArrayList<>();
        for (String day : dayList) {
            int i = day.indexOf("-");
            dateList.add(day.substring(i + 1));
        }
        Map<String, Object> deviceMap = new HashMap<>();
        deviceMap.put("date", dateList);
        List<Map<String, Object>> maps = new ArrayList<>();
        long l = System.currentTimeMillis();
        for (String id : ids) {
            Map<String, Object> map = new HashMap<>();
            SubstationDevice substationDevice = substationDeviceService.getById(id);
            map.put("id", id);
            map.put("name", substationDevice.getDeviceName());
            List<String> values = new ArrayList<>(dateList.size());

            LambdaQueryWrapper<TaskResult> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(TaskResult::getDatastatus, "1").le(TaskResult::getTime, endDate).ge(TaskResult::getTime,
                    startDate).eq(TaskResult::getDeviceId, id).select(TaskResult::getValue, TaskResult::getUnit, TaskResult::getTime).orderByDesc(TaskResult::getTime);
            List<TaskResult> taskResultList = taskResultMapper.selectList(queryWrapper);
            for (String date : dayList) {
                List<TaskResult> list = taskResultList.stream().filter(t -> t.getTime().contains(date)).collect(Collectors.toList());
                if (list.size() > 0) {
                    TaskResult taskResult = list.get(0);
                    values.add(taskResult.getValue());
                    if (!map.containsKey("unit")) {
                        map.put("unit", taskResult.getUnit());
                    }
                } else {
                    values.add(null);
                }

            }
            map.put("values", values);
            maps.add(map);
        }
        deviceMap.put("device", maps);
        return deviceMap;
    }


    /**********************************
     * 用途说明: 导出数据对比分析列表
     * 参数说明 records
     * 参数说明 response
     * 返回值说明: void
     ***********************************/
    @Override
    public void exportTaskResultList(List<Map<String, Object>> records, String exportFields,
                                     HttpServletResponse response) throws IOException {
        List<Map<String, Object>> recognition_type = sysDictionaryItemsService.getDeviceByType("recognition_type");
        List<Map<String, Object>> types = sysDictionaryItemsService.getDeviceByType("PatrolEquipmentType");
        for (Map<String, Object> record : records) {
            String recognitionType = "";
            if (!Objects.isNull(record.get("recognitionType"))) {
                Map<String, Object> map = recognition_type.stream().filter(r -> r.get("itemcode").equals(record.get(
                        "recognitionType").toString())).findFirst().orElse(null);
                if (map != null) {
                    recognitionType = map.get("dictname").toString();
                }
            }

            String type = "";
            if (!Objects.isNull(record.get("type"))) {
                Map<String, Object> map = types.stream().filter(r -> r.get("itemcode").equals(record.get(
                        "type").toString())).findFirst().orElse(null);
                if (map != null) {
                    type = map.get("dictname").toString();
                }
            }
            record.put("type", type);
            record.put("recognitionTypeName", recognitionType);
            if (ObjectUtil.isNotEmpty(record.get("defectFilePath"))) {
                String filePath = record.get("defectFilePath").toString();
                filePath = URLDecoder.decode(filePath, "utf-8");
                //filePath = filePath.replace("\\", "/");
                //                hashMap.put("巡视图片", new FileInputStream(new File("D:\\riis\\video\\" + filePath)));
                record.put("img", httpServerConfig.getSnapFilePath() + filePath);

            } else {
                String filePath = ObjectUtil.isNotEmpty(record.get("filePath")) ?
                        record.get("filePath").toString() : "";
                filePath = URLDecoder.decode(filePath, "utf-8");
                record.put("img", httpServerConfig.getSnapFilePath() + filePath);
            }
            if (ObjectUtil.isNotEmpty(record.get("value"))) {
                String value = record.get("value").toString();
                String unit = ObjectUtil.isNotEmpty(record.get("unit")) ? record.get("unit").toString() : "";
                record.put("value", value + unit);
            }
        }
        //        String[] headers = {"区域名称", "间隔名称", "设备名称", "部件名称", "巡视点位", "巡视结果", "识别类型", "巡视结论", "巡视时间", "巡视图片"};
        //        String[] keys = {"areaName", "bayName", "patroldeviceName", "componentName", "deviceName", "value",
        //                "recognitionTypeName", "analysisResult", "time", "img"};
        String[] headers = new String[20];
        String[] keys = new String[20];
        String[] fields = exportFields.split(",");
        String imgs = "";
        for (int i = 0; i < fields.length; i++) {
            String[] name = fields[i].split("-");
            keys[i] = name[0];
            if ("img".equals(name[0])) {
                imgs = "img";
            }
            headers[i] = name[1];

        }
        FileUtil.excelImg(records, headers, keys, imgs, "", response);
    }

    /**********************************
     * 用途说明: 导出异常点位(导出全部)
     * 参数说明 page
     * 参数说明 taskTodoId
     * 参数说明 valid
     * 返回值说明: com.baomidou.mybatisplus.extension.plugins.pagination.Page<java.util.Map<java.lang.String,java.lang
     * .Object>>
     ***********************************/
    @Override
    public List<Map<String, Object>> getAbnormalDevice(String stationCode, String taskName,
                                                       String deviceName, String patroldeviceName,
                                                       String componentName, String recognitionType, String status,
                                                       String startDate, String endDate) {

        List<Map<String, Object>> records = taskResultMapper.getAbnormalDevice(stationCode, taskName, deviceName,
                patroldeviceName, componentName, recognitionType, status, startDate, endDate);
        records.forEach(m -> {
            String deviceId = m.get("deviceId").toString();
            SubstationDevice substationDevice = substationDeviceService.getById(deviceId);
            m.put("deviceClass", substationDevice.getDeviceClass());
            String flag = "";
            if (ObjectUtil.isNotEmpty(m.get("flag"))) {
                flag = m.get("flag").toString();
            }
            String valid = "";
            if (ObjectUtil.isNotEmpty(m.get("valid1"))) {
                valid = m.get("valid1").toString();
            }
            if ("4".equals(flag)) {
                m.put("analysisResult", "识别失败");
            } else if ("6".equals(flag)) {
                m.put("analysisResult", "采集失败");
            } else if ("2".equals(valid)) {
                m.put("analysisResult", "异常");
            }
        });
        return records;
    }

    /**********************************
     * 用途说明: 数据对比分析列表(查询符合条件的所有)
     * 参数说明 page
     * 参数说明 deviceId
     * 返回值说明: com.baomidou.mybatisplus.extension.plugins.pagination.Page<java.util.Map<java.lang.String,java.lang
     * .Object>>
     ***********************************/
    @Override
    public List<Map<String, Object>> getTaskResultAll(String deviceId, String startDate, String endDate) {

        String[] split = deviceId.split(",");
        List<String> idList = Arrays.asList(split);
        LambdaQueryWrapper<TaskResult> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(TaskResult::getDeviceId, idList).eq(TaskResult::getDatastatus, "1");
        // 开始时间判断
        if (StrUtil.isNotBlank(startDate)) {
            queryWrapper.le(TaskResult::getTime, endDate);
        }
        // 结束时间判断
        if (StrUtil.isNotBlank(endDate)) {
            queryWrapper.ge(TaskResult::getTime, startDate);
        }
        queryWrapper.orderByDesc(TaskResult::getTime);
        return taskResultMapper.selectMaps(queryWrapper);
    }

    /**********************************
     * 用途说明: 获取当前时间最近的数据行
     * 参数说明
     * 返回值说明: long
     ***********************************/
    @Override
    public long getLastTimePosition(String stationCode, String taskName, String startDate, String endDate, String taskState) {
        LambdaQueryWrapper<TaskTodo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TaskTodo::getStationCode, stationCode);
        if (StrUtil.isNotBlank(taskName)) {
            queryWrapper.like(TaskTodo::getTaskName, taskName);
        }
        if (StrUtil.isNotBlank(startDate)) {
            queryWrapper.le(TaskTodo::getPlanStartTime, endDate);
        }
        if (StrUtil.isNotBlank(endDate)) {
            queryWrapper.ge(TaskTodo::getPlanStartTime, startDate);
        }
        if (StrUtil.isNotBlank(taskState)) {
            queryWrapper.eq(TaskTodo::getTaskState, taskState);
        }
        queryWrapper.ne(TaskTodo::getTaskType, "4");
        queryWrapper.orderByAsc(TaskTodo::getPlanStartTime).orderByAsc(TaskTodo::getTaskTodoId);
        List<TaskTodo> list = this.list(queryWrapper);
        String now = DateUtil.now();
        Date parse = DateUtil.parse(now);
        List<String> collect = list.stream().map(TaskTodo::getTaskState).collect(Collectors.toList());
        if (collect.contains("2")) {
            return (collect.indexOf("2") + 1);
        } else {
            for (int i = 0; i < list.size(); i++) {
                TaskTodo taskTodo = list.get(i);
                String planStartTime = taskTodo.getPlanStartTime();
                Date date = DateUtil.parse(planStartTime);
                if ("0".equals(taskTodo.getTaskState()) && parse.before(date)) {
                    return (i + 1);
                }
            }
        }
        return 0;
    }

    /**********************************
     * 用途说明: 获取两个日期之间的所有日期
     * 参数说明 startTime 开始时间
     * 参数说明 endTime 结束时间
     * 返回值说明: java.util.List<java.lang.String>
     ***********************************/
    public static List<String> getDays(String startDate, String endDate) {
        // 返回的日期集合
        List<String> days = new ArrayList<>();
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        try {
            Date start = dateFormat.parse(startDate);
            Date end = dateFormat.parse(endDate);

            Calendar tempStart = Calendar.getInstance();
            tempStart.setTime(start);

            Calendar tempEnd = Calendar.getInstance();
            tempEnd.setTime(end);
            // 日期加1(包含结束)
            tempEnd.add(Calendar.DATE, +1);
            while (tempStart.before(tempEnd)) {
                days.add(dateFormat.format(tempStart.getTime()));
                tempStart.add(Calendar.DAY_OF_YEAR, 1);
            }
        } catch (Exception e) {
            log.error(e.getMessage());;
        }
        return days;
    }

    @Override
    public boolean updatePatrolDeviceState(String stationcode, String patroldeviceCcode, String isworking) {
        List<SubstationPatroldevice> list = patroldeviceMapper.selectList(new LambdaQueryWrapper<SubstationPatroldevice>().eq(SubstationPatroldevice::getInternationalId, patroldeviceCcode));
        String code = patroldeviceCcode;
        if (list.size() > 0) {
            SubstationPatroldevice substationPatroldevice = list.get(0);
            String channelinfo = substationPatroldevice.getChannelinfo();
            if (JSONUtil.isTypeJSONArray(channelinfo)) {
                JSONArray jarray = JSONUtil.parseArray(channelinfo);
                for (int i = 0; i < jarray.size(); i++) {
                    JSONObject jobj = jarray.getJSONObject(i);
                    if (jobj.getStr("channel_type").equals("2")) { //红外
                        if (ObjUtil.isNotEmpty(jobj.getStr("pan_code"))) {
                            code = jobj.getStr("pan_code");
                        }
                    }
                }
            }
        }
        String rediskey = RiisConstants.Patroldevice_IsWorking + stationcode + "_" + code;
        if ("1".equals(isworking)) {
            redisTemplate.delete(rediskey);
            redisTemplate.opsForValue().set(rediskey, "1", 1, TimeUnit.MINUTES);
        } else {
            redisTemplate.delete(rediskey);
            //            redisTemplate.expire(rediskey, ,TimeUnit.SECONDS);
        }
        return true;
    }

    /**********************************
     * 用途说明: 根据任务执行情况ID查询点位查询
     * 参数说明 taskTodoId
     * 参数说明 deviceName
     * 参数说明 valid
     * 返回值说明: java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
     ***********************************/
    @Override
    public List<Map<String, Object>> getTaskDeviceById(String taskTodoId, String deviceName, String valid) {
        return taskResultMapper.getTaskDeviceById(taskTodoId, deviceName, valid);
    }

    /**********************************
     * 用途说明: 查询联动任务列表
     * 参数说明 page
     * 参数说明 stationCode
     * 参数说明 linkageDeviceName
     * 参数说明 taskName
     * 参数说明 linkageType
     * 参数说明 linkageDeviceType
     * 参数说明 startFormat
     * 参数说明 endFormat
     * 返回值说明: com.baomidou.mybatisplus.extension.plugins.pagination.Page<java.util.Map<java.lang.String,java.lang
     * .Object>>
     ***********************************/
    @Override
    public Page<Map<String, Object>> getLinkTaskTodoList(Page<Map<String, Object>> page, String stationCode,
                                                         String linkageDeviceName, String taskName,
                                                         String linkageType, String linkageDeviceType,
                                                         String startDate, String endDate) {
        return taskTodoMapper.getLinkTaskTodoList(page, stationCode, linkageDeviceName, taskName, linkageType,
                linkageDeviceType, startDate, endDate);
    }

    /**********************************
     * 用途说明: 获取点位数量
     * 参数说明 taskTodoId
     * 返回值说明: long
     ***********************************/
    @Override
    public long getTaskResultCount(String taskTodoId) {
        return taskResultMapper.selectCount(
                new LambdaQueryWrapper<TaskResult>().
                        eq(TaskResult::getTaskTodoId, taskTodoId).
                        notIn(TaskResult::getFlag, "0", "1")
        );
    }

    @Override
    public List<TaskResult> getAbnormalResult(String taskTodoId) {
        return taskResultMapper.getAbnormalResult(taskTodoId);
    }

    /**********************************
     * 用途说明: 巡视设备巡检统计
     * 参数说明 page
     * 参数说明 patrolDeviceCode
     * 参数说明 patrolDeviceName
     * 参数说明 type
     * 返回值说明: com.baomidou.mybatisplus.extension.plugins.pagination.Page<java.util.Map<java.lang.String,java.lang
     * .Object>>
     ***********************************/
    @Override
    public Page<Map<String, Object>> getDeviceInspectionStat(Page<Map<String, Object>> page, String patrolDeviceCode,
                                                             String patrolDeviceName, String type) {
        return taskResultMapper.getDeviceInspectionStat(page, patrolDeviceCode, patrolDeviceName, type);
    }

    /**********************************
     * 用途说明: 巡视设备巡检统计（上报上级）
     * 返回值说明: com.baomidou.mybatisplus.extension.plugins.pagination.Page<java.util.Map<java.lang.String,java.lang
     * .Object>>
     ***********************************/
    @Override
    public List<Map<String, Object>> getDeviceInspectionStat() {
        return taskResultMapper.getPatrolDeviceInspectionStat();
    }

    /**********************************
     * 用途说明: 巡视任务数据统计
     * 参数说明 page
     * 参数说明 type
     * 参数说明 startDate
     * 参数说明 endDate
     * 返回值说明: com.baomidou.mybatisplus.extension.plugins.pagination.Page<java.util.Map<java.lang.String,java.lang
     * .Object>>
     ***********************************/
    @Override
    public Page<Map<String, Object>> getTaskDataStat(Page<Map<String, Object>> page, String stationCode, String type,
                                                     String startDate,
                                                     String endDate) {

        return taskResultMapper.getTaskDataStat(page, stationCode, type, startDate, endDate);

    }

    @Override
    public List<Map<String, Object>> getTaskDataStat(String stationCode, String type, String startDate,
                                                     String endDate) {
        return taskResultMapper.getTaskDataStat("", type, startDate, endDate);
    }

    /**********************************
     * 用途说明: 根据任务id查询未审核告警和数量
     * 参数说明 taskTodoIds
     * 返回值说明: java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
     ***********************************/
    @Override
    public List<Map<String, Object>> getNotCheckAlarmInfo(String taskTodoIds) {
        return taskResultMapper.getNotCheckAlarmInfo(taskTodoIds);
    }

    /**********************************
     * 用途说明: 设置实物ID
     * 参数说明 resultId
     * 参数说明 filePath
     * 返回值说明: void
     ***********************************/
    @Override
    public void setMaterialIdByImg(String resultId, String filePath) {
        String content = FileUtil.resolveCodeByFile(filePath);
        if (StrUtil.isNotBlank(content)) {
            TaskResult taskResult = new TaskResult();
            taskResult.setResultId(resultId);
            taskResult.setMaterialId(content);
            this.updateTaskResultById(taskResult);
        }
    }

    /**********************************
     * 用途说明: 调用温度的sdk识别并给图片加上温度
     * 参数说明 resultId
     * 参数说明 objectId
     * 参数说明 patrolDeviceCode
     * 参数说明 fullfilename
     * 返回值说明: com.alibaba.fastjson.JSONObject
     ***********************************/
    @Override
    public com.alibaba.fastjson.JSONObject callPicAnalyse(String resultId, String objectId, String patrolDeviceCode,
                                                          String rtspurl, String fullfilename, String region, String csvFilePath) throws IOException {
        log.info(region);
        LambdaQueryWrapper<SubstationPatroldevice> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SubstationPatroldevice::getInternationalId, patrolDeviceCode);
        SubstationPatroldevice substationPatroldevice = patroldeviceMapper.selectOne(queryWrapper);
        String manufacturer = substationPatroldevice.getManufacturer();
        if ("haikang".equals(manufacturer) && StrUtil.isNotBlank(rtspurl)) {
            String reg = "//([^/]+)";
            Pattern pattern = Pattern.compile(reg);
            Matcher matcher = pattern.matcher(rtspurl);
            if (!matcher.find()) {
                throw new RuntimeException("rtsp地址错误");
            }
            String group = matcher.group(1);
            int lastAtIndex = group.lastIndexOf('@');
            // 如果找到了@
            if (lastAtIndex != -1) {
                // 检查@后面是否紧跟着IP地址和端口号，但在这个例子中我们假设没有
                // 所以直接替换最后一个@为:
                group = group.substring(0, lastAtIndex) + ":" + group.substring(lastAtIndex + 1);
            } else {
                log.error("rtsp地址错误");
            }
            String[] split = group.split(":");
            String username = split[0];
            String password = split[1];
            String ip = split[2];
            log.info("-------调用callPicAnalyse方法--------");
            return getHaiKangTemperature(resultId, objectId, fullfilename, manufacturer, ip, (short) 8000, username,
                    password, region, csvFilePath);
        }

        if ("dahua".equals(manufacturer) && StrUtil.isNotBlank(rtspurl)) {
            TaskResult taskResult = taskResultMapper.selectById(objectId);
            SubstationDevice substationDevice = substationDeviceService.getById(taskResult.getDeviceId());
            String reg = "//([^/]+)";
            Pattern pattern = Pattern.compile(reg);
            Matcher matcher = pattern.matcher(rtspurl);
            if (!matcher.find()) {
                throw new RuntimeException("rtsp地址错误");
            }
            String group = matcher.group(1);
            int lastAtIndex = group.lastIndexOf('@');
            // 如果找到了@
            if (lastAtIndex != -1) {
                // 检查@后面是否紧跟着IP地址和端口号，但在这个例子中我们假设没有
                // 所以直接替换最后一个@为:
                group = group.substring(0, lastAtIndex) + ":" + group.substring(lastAtIndex + 1);
            } else {
                log.error("rtsp地址错误");
            }
            String[] split = group.split(":");
            String username = split[0];
            String password = split[1];
            String ip = split[2];
            log.info("-------调用callPicAnalyse方法--------");
            String patroldeviceJson = substationDevice.getPatroldeviceJson();
            JSONArray jsonArray = JSONUtil.parseArray(patroldeviceJson);
            if (jsonArray.size() > 0) {
                JSONObject jsonObject = jsonArray.getJSONObject(0);
                int presetId = jsonObject.getInt("patroldevice_pos");
                return getDaHuaTemperature(resultId, objectId, fullfilename, ip, 37777, username, password,
                        substationDevice.getOutsideAngle(), presetId);
            }

        }
        if ("dali".equals(manufacturer) && StrUtil.isNotBlank(rtspurl)) {
            return CameraUtil.callPicAnalyse(resultId, objectId, fullfilename, manufacturer,
                    substationPatroldevice.getIpaddr(), (short) 80, null, null, region, csvFilePath);
        }

        if ("heika".equals(manufacturer)) {
            String reg = "//([^/]+)";
            Pattern pattern = Pattern.compile(reg);
            Matcher matcher = pattern.matcher(rtspurl);
            if (!matcher.find()) {
                throw new RuntimeException("rtsp地址错误");
            }
            String group = matcher.group(1);
            int lastAtIndex = group.lastIndexOf('@');
            // 如果找到了@
            if (lastAtIndex != -1) {
                // 检查@后面是否紧跟着IP地址和端口号，但在这个例子中我们假设没有
                // 所以直接替换最后一个@为:
                group = group.substring(0, lastAtIndex) + ":" + group.substring(lastAtIndex + 1);
            } else {
                log.error("rtsp地址错误");
            }
            String[] split = group.split(":");
            String username = split[0];
            String password = split[1];
            String ip = split[2];
            log.info("-------调用callPicAnalyse方法--------");
            return getHeiKaTemperature(resultId, objectId, fullfilename, manufacturer, ip, (short) 8000, username,
                    password, region, csvFilePath);
        }
        return null;
    }

    private com.alibaba.fastjson.JSONObject getHeiKaTemperature(String resultId, String objectId, String fullfilename
            , String manufacturer, String ip, short port, String username, String password, String region,
                                                                String csvFilePath) {
        // 获取spring bean 中 HttpServerConfig 类实例
        HttpServerConfig config =
                SpringContextHolder.getBean(HttpServerConfig.class);
        // 获取spring bean 中 HttpRESTfulUtils 类实例
        HttpRESTfulUtils httpUtil =
                SpringContextHolder.getBean(HttpRESTfulUtils.class);

        String api = "getTemp";
        if (StrUtil.isNotBlank(config.getHeikaApp())) {
            api = config.getHeikaApp() + "/getTemp";
        }
        Map<String, Object> param = new HashMap<>();
        param.put("resultId", resultId);
        param.put("objectId", objectId);
        param.put("ip", ip);
        param.put("port", port);
        param.put("username", username);
        param.put("password", password);
        param.put("region", region);
        param.put("csvFilePath", csvFilePath);
        param.put("fullfilename", fullfilename);
        com.alibaba.fastjson.JSONObject result = new com.alibaba.fastjson.JSONObject();
        if (StrUtil.isBlank(region)) {
            result.put("code", "201");
            return result;
        }
        com.alibaba.fastjson.JSONObject resultObject = httpUtil.sendHttpPost("json", config.getSdkIp(),
                config.getHeikaPort(), "", api, param, null);
        return null;
    }

    public static com.alibaba.fastjson.JSONObject getDaHuaTemperature(String requestId, String objectId,
                                                                      String filePath, String ip,
                                                                      int port, String username, String password,
                                                                      String outsideAngle,
                                                                      int presetId) {
        // 获取spring bean 中 HttpServerConfig 类实例
        HttpServerConfig config =
                SpringContextHolder.getBean(HttpServerConfig.class);
        // 获取spring bean 中 HttpRESTfulUtils 类实例
        HttpRESTfulUtils httpUtil =
                SpringContextHolder.getBean(HttpRESTfulUtils.class);

        String api = "getTempItem";
        if (StrUtil.isNotBlank(config.getDahuaApp())) {
            api = config.getDahuaApp() + "/getTempItem";
        }
        Map<String, Object> param = new HashMap<>();
        param.put("ip", ip);
        param.put("port", port);
        param.put("username", username);
        param.put("password", password);
        param.put("presetId", presetId);
        param.put("channel", 1);
        com.alibaba.fastjson.JSONObject result = new com.alibaba.fastjson.JSONObject();
        if (StrUtil.isBlank(outsideAngle)) {
            result.put("code", "201");
            return result;
        }
        com.alibaba.fastjson.JSONObject dataPos = com.alibaba.fastjson.JSONObject.parseObject(outsideAngle);
        String type = dataPos.getString("type");
        if ("point".equals(type)) {
            param.put("type", 1);
        }
        if ("line".equals(type)) {
            param.put("type", 2);
        }
        if ("rectangle".equals(type)) {
            param.put("type", 3);
        }
        param.put("ruleId", dataPos.getInteger("ruleId"));
        com.alibaba.fastjson.JSONObject resultObject = httpUtil.sendHttpPost("json", config.getSdkIp(),
                config.getDahuaPort(), "", api, param,
                null);

        if (!"0".equals(resultObject.getString("code"))) {
            result.put("code", "201");
            return result;
        }
        com.alibaba.fastjson.JSONObject data = resultObject.getJSONObject("data");
        String temperature = "";
        if ("point".equals(type)) {
            String aver = data.getString("aver");
            double averD = NumberUtil.parseDouble(aver);
            String averStr = String.format("%.1f", averD);
            temperature = averStr + "," + averStr;
        }
        if ("line".equals(type) || "rectangle".equals(type)) {
            String min = data.getString("min");
            String max = data.getString("max");
            double minD = NumberUtil.parseDouble(min);
            double maxD = NumberUtil.parseDouble(max);
            temperature = String.format("%.1f", minD) + "," + String.format("%.1f", maxD);
        }

        com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
        jsonObject.put("requestId", requestId);
        List<Map<String, Object>> mapList = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        map.put("objectId", objectId);
        List<Map<String, Object>> mapList1 = new ArrayList<>();
        Map<String, Object> map1 = new HashMap<>();
        map1.put("type", "infrared");
        map1.put("value", temperature);
        if (StrUtil.isBlank(temperature)) {
            result.put("code", "201");
            map1.put("code", "2001");
        } else {
            result.put("code", "200");
            map1.put("code", "2000");
            map1.put("conf", "100");
            String imageurl = String.format("http://%s:%s/snapfile?filename=%s", config.getPatrolIp(),
                    config.getPatrolPort(), filePath);
            if (StrUtil.isNotEmpty(config.getPatrolAppname())) {
                imageurl = String.format("http://%s:%s/%s/snapfile?filename=%s", config.getPatrolIp(),
                        config.getPatrolPort(), config.getPatrolAppname(), filePath);
            }
            map1.put("resImagePath", imageurl);
        }
        map1.put("desc", temperature);

        com.alibaba.fastjson.JSONArray pos = dataPos.getJSONArray("pos");
        JSONArray posArray = new JSONArray();
        if ("rectangle".equals(dataPos.getString("type"))) {
            // 左下角
            com.alibaba.fastjson.JSONObject ojb1 = pos.getJSONObject(0);
            Integer x1 = ojb1.getInteger("x");
            Integer y1 = ojb1.getInteger("y");
            ojb1.put("x", x1);
            ojb1.put("y", y1);
            // 右上角
            com.alibaba.fastjson.JSONObject ojb2 = pos.getJSONObject(2);
            Integer x2 = ojb2.getInteger("x");
            Integer y2 = ojb2.getInteger("y");
            ojb2.put("x", x2);
            ojb2.put("y", y2);
            posArray.add(ojb1);
            log.info(ojb1.toString());
            posArray.add(ojb2);
            log.info(ojb2.toString());
        }
        if ("point".equals(dataPos.getString("type"))) {
            // 点坐标
            com.alibaba.fastjson.JSONObject ojb = pos.getJSONObject(0);
            Integer x1 = ojb.getInteger("x");
            Integer y1 = ojb.getInteger("y");
            ojb.put("x", x1);
            ojb.put("y", y1);
            posArray.add(ojb);
        }
        JSONArray dataArray = new JSONArray();
        com.alibaba.fastjson.JSONObject dataJson = new com.alibaba.fastjson.JSONObject();
        dataJson.put("coors", posArray);
        dataArray.add(dataJson);
        map1.put("pos", dataArray);
        mapList1.add(map1);
        map.put("results", mapList1);
        mapList.add(map);
        jsonObject.put("resultList", mapList);
        String api1 = "picAnalyseRetNotify";
        if (StrUtil.isNotBlank(config.getPatrolAppname())) {
            api1 = "riis-system/picAnalyseRetNotify";
        }
        httpUtil.sendHttpPost("json", config.getPatrolIp(), config.getPatrolPort(), "", api1, jsonObject, null);
        return result;
    }

    public static com.alibaba.fastjson.JSONObject getHaiKangTemperature(String requestId, String objectId,
                                                                        String filePath, String manufacturer,
                                                                        String ip, short port, String username,
                                                                        String password,
                                                                        String outsideAngle, String csvFilePath) {
        // 获取spring bean 中 HttpServerConfig 类实例
        HttpServerConfig config =
                SpringContextHolder.getBean(HttpServerConfig.class);
        // 获取spring bean 中 HttpRESTfulUtils 类实例
        HttpRESTfulUtils httpUtil =
                SpringContextHolder.getBean(HttpRESTfulUtils.class);

        String api = "getTempItem";
        if (StrUtil.isNotBlank(config.getHaikangApp())) {
            api = config.getHaikangApp() + "/getTemperature";
        }
        Map<String, Object> param = new HashMap<>();
        param.put("ip", ip);
        param.put("port", port);
        param.put("username", username);
        param.put("password", password);
        param.put("manufacturer", manufacturer);
        param.put("outsideAngle", outsideAngle);
        com.alibaba.fastjson.JSONObject result = new com.alibaba.fastjson.JSONObject();
        File srcImgFile = new File(csvFilePath);
        //文件转化为图片
        Image srcImg = null;
        try {
            srcImg = ImageIO.read(srcImgFile);
        } catch (IOException e) {
            log.error(e.getMessage());;
        }
        if (srcImg == null) {
            result.put("code", "201");
            return result;
        }
        //获取图片的宽
        int srcImgWidth = srcImg.getWidth(null);
        //获取图片的高
        int srcImgHeight = srcImg.getHeight(null);
        param.put("srcImgHeight", srcImgHeight);
        param.put("srcImgWidth", srcImgWidth);
        if (StrUtil.isBlank(outsideAngle)) {
            result.put("code", "201");
            return result;
        }
        com.alibaba.fastjson.JSONObject resultObject = httpUtil.sendHttpPost("json", config.getSdkIp(),
                config.getHaikangPort(), "", api, param, null);
        if (!"0".equals(resultObject.getString("code"))) {
            result.put("code", "201");
            return result;
        }
        log.info(resultObject.toString());
        log.info(outsideAngle);
        String temperature = resultObject.getString("data");
        com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
        jsonObject.put("requestId", requestId);
        List<Map<String, Object>> mapList = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        map.put("objectId", objectId);
        List<Map<String, Object>> mapList1 = new ArrayList<>();
        Map<String, Object> map1 = new HashMap<>();
        map1.put("type", "infrared");
        map1.put("value", temperature);
        if (StrUtil.isBlank(temperature)) {
            result.put("code", "201");
            map1.put("code", "2001");
        } else {
            result.put("code", "200");
            map1.put("code", "2000");
            map1.put("conf", "100");
            String imageurl = String.format("http://%s:%s/snapfile?filename=%s", config.getPatrolIp(),
                    config.getPatrolPort(), filePath);
            if (StrUtil.isNotEmpty(config.getPatrolAppname())) {
                imageurl = String.format("http://%s:%s/%s/snapfile?filename=%s", config.getPatrolIp(),
                        config.getPatrolPort(), config.getPatrolAppname(), filePath);
            }
            map1.put("resImagePath", imageurl);
        }
        map1.put("desc", temperature);
        JSONObject dataPos = JSONUtil.parseObj(outsideAngle);
        JSONArray pos = dataPos.getJSONArray("pos");
        JSONArray posArray = new JSONArray();
        if ("rectangle".equals(dataPos.getStr("type"))) {
            // 左下角
            JSONObject ojb1 = pos.getJSONObject(0);
            // 右上角
            JSONObject ojb2 = pos.getJSONObject(2);
            posArray.add(ojb1);
            posArray.add(ojb2);
        }
        if ("point".equals(dataPos.getStr("type"))) {
            // 点坐标
            JSONObject ojb = pos.getJSONObject(0);
            posArray.add(ojb);
        }
        JSONArray dataArray = new JSONArray();
        JSONObject dataJson = new JSONObject();
        dataJson.putOnce("coors", posArray);
        dataArray.add(dataJson);
        map1.put("pos", dataArray);
        mapList1.add(map1);
        map.put("results", mapList1);
        mapList.add(map);
        jsonObject.put("resultList", mapList);
        String api1 = "picAnalyseRetNotify";
        if (StrUtil.isNotBlank(config.getPatrolAppname())) {
            api1 = "riis-system/picAnalyseRetNotify";
        }
        httpUtil.sendHttpPost("json", config.getPatrolIp(), config.getPatrolPort(), "", api1, jsonObject, null);
        return result;
    }

    /**********************************
     * 用途说明: 调用温度的sdk识别并给图片加上温度
     * 参数说明 resultId
     * 参数说明 objectId
     * 参数说明 patrolDeviceCode
     * 参数说明 fullfilename
     * 返回值说明: com.alibaba.fastjson.JSONObject
     ***********************************/
    @Override
    public com.alibaba.fastjson.JSONObject callSoundAnalyse(String resultId, String objectId) throws IOException {
        com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
        jsonObject.put("requestId", resultId);
        List<Map<String, Object>> mapList = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        map.put("objectId", objectId);
        List<Map<String, Object>> mapList1 = new ArrayList<>();
        Map<String, Object> map1 = new HashMap<>();
        map1.put("type", "sound");
        map1.put("value", 1);
        jsonObject.put("code", "200");
        map1.put("code", "2000");
        map1.put("conf", "1");
        map1.put("resImagePath", "");
        map1.put("desc", "声纹检测");
        mapList1.add(map1);
        map.put("results", mapList1);
        mapList.add(map);
        jsonObject.put("resultList", mapList);
        String api = "picAnalyseRetNotify";
        if (StrUtil.isNotBlank(httpServerConfig.getPatrolAppname())) {
            api = "riis-system/picAnalyseRetNotify";
        }
        httpUtil.sendHttpPost("json", httpServerConfig.getPatrolIp(), httpServerConfig.getPatrolPort(), "", api,
                jsonObject, null);
        return jsonObject;
    }

    /**********************************
     * 用途说明: 设置请求分析主机调用失败的任务为巡视失败
     * 参数说明 stationCode
     * 参数说明 resultId
     * 参数说明 deviceSumnum
     * 参数说明 taskTodoId
     * 返回值说明: void
     ***********************************/
    @Override
    public synchronized void setTaskResultAndTodo(String stationCode, String resultId, Integer deviceSumnum, String taskTodoId) {
        TaskResult taskResult = new TaskResult();
        taskResult.setResultId(resultId);
        taskResult.setFlag("4");
        this.updateTaskResultById(taskResult);
        long taskResultCount = this.getTaskResultCount(taskTodoId);
        TaskTodo taskTodo = this.getById(taskTodoId);
        // 赋值执行数量
        List<Map<String, Object>> list = this.getTaskResultById(taskTodo.getTaskTodoId(), null, null, null);
        // 已送检点数
        long patrolCount = list.stream().filter(t -> !("0").equals(t.get("flag")) && !("1").equals(t.get("flag"))).count();
        // 失败的数量
        long failCount =
                list.stream().filter(t -> ("4").equals(t.get("flag")) || ("6").equals(t.get("flag"))).count();
        // 异常数量
        long abnormalCount = list.stream().filter(t -> ("2").equals(t.get("valid1"))).count();
        LambdaUpdateWrapper<TaskTodo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(TaskTodo::getTaskTodoId, taskTodoId).set(TaskTodo::getDeviceDeforeNum, patrolCount).set(TaskTodo::getDeviceFailureNum, failCount).set(TaskTodo::getDeviceUnusualnum, abnormalCount);
        boolean b = deviceSumnum == taskResultCount;
        if (b) {
            //taskTodo.setTaskState("1"); //已完成
            updateWrapper.set(TaskTodo::getTaskState, "1").set(TaskTodo::getEndTime, DateUtil.now());
        }
        this.update(updateWrapper);
        JSONObject jsonObject = new JSONObject();
        jsonObject.putOnce("taskTodoId", taskTodoId);
        jsonObject.putOnce("taskType", taskTodo.getTaskType());
        WebSocketServer.sendInfo("taskresult_" + taskTodo.getStationCode(), jsonObject.toString());

        //        WebSocketServer.sendInfo("taskresult_" + stationCode, "msg");
    }

    /**********************************
     * 用途说明: 查询联动任务最近十条
     * 参数说明 linkageType 联动类型
     * 返回值说明: java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
     ***********************************/
    @Override
    public List<Map<String, Object>> getLinkTaskRecordLast(String stationCode, String linkageType, String taskName) {
        return taskTodoMapper.getLinkTaskRecordLast(stationCode, linkageType, taskName);
    }

    /**********************************
     * 用途说明: 查询联动控制巡视任务
     * 参数说明 stationCode
     * 参数说明 todoId
     * 参数说明 linkageType
     * 返回值说明: java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
     ***********************************/
    @Override
    public List<Map<String, Object>> getLinkTaskTodo(String stationCode, String todoId, String linkageType) {
        return taskTodoMapper.getLinkTaskTodo(stationCode, todoId, linkageType);
    }

    /**********************************
     * 用途说明: 按照日、周、月统计巡视任务
     * 参数说明 type
     * 返回值说明: java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
     ***********************************/
    @Override
    public List<Map<String, Object>> getTaskDurationStat(String startDate, String endDate, String type) {
        String startFormat = "";
        String endFormat = "";
        if ("3".equals(type)) {
            startDate = startDate + "-01";
            Date parseStart = DateUtil.parse(startDate);
            Date beginOfDay = DateUtil.beginOfMonth(parseStart);
            startFormat = DateUtil.format(beginOfDay, "yyyy-MM-dd HH:mm:ss");
            endDate = endDate + "-01";
            Date parseEnd = DateUtil.parse(endDate);
            //一月的结束
            Date endOfDay = DateUtil.endOfMonth(parseEnd);
            endFormat = DateUtil.format(endOfDay, "yyyy-MM-dd HH:mm:ss");
        } else {
            if (StrUtil.isNotBlank(startDate)) {
                Date parseStart = DateUtil.parse(startDate);
                //一天的开始
                Date beginOfDay = DateUtil.beginOfDay(parseStart);
                startFormat = DateUtil.format(beginOfDay, "yyyy-MM-dd HH:mm:ss");
            }

            if (StrUtil.isNotBlank(startDate)) {
                Date parseEnd = DateUtil.parse(endDate);
                //一天的结束
                Date endOfDay = DateUtil.endOfDay(parseEnd);
                endFormat = DateUtil.format(endOfDay, "yyyy-MM-dd HH:mm:ss");
            }
        }
        return taskTodoMapper.getTaskDurationStat(startFormat, endFormat, type);
    }

    /**********************************
     * 用途说明: 按照日、周、月统计巡视任务导出
     * 参数说明 startDate
     * 参数说明 endDate
     * 参数说明 type
     * 参数说明 response
     * 返回值说明: void
     ***********************************/
    @Override
    public void exportTaskDurationStat(String startDate, String endDate, String type, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> taskDurationStat = this.getTaskDurationStat(startDate, endDate, type);
        taskDurationStat.forEach(t -> {
            t.put("日期", t.remove("stattime"));
            t.put("巡视任务次数", t.remove("num"));
            t.put("巡视时长", t.remove("duration"));
            t.put("发现缺陷种类", t.remove("type"));
            t.put("发现缺陷数量", t.remove("count"));
        });
        FileUtil.downloadExcel(taskDurationStat, response);
    }

    /**********************************
     * 用途说明: 巡视任务数据统计
     * 参数说明 page
     * 参数说明 stationCode
     * 参数说明 type
     * 参数说明 startDate
     * 参数说明 endDate
     * 参数说明 response
     * 返回值说明: void
     ***********************************/
    @Override
    public void exportTaskDataStat(Page<Map<String, Object>> page, String stationCode, String type, String startDate,
                                   String endDate, HttpServletResponse response) throws IOException {
        String startFormat = "";
        String endFormat = "";
        if ("3".equals(type)) {
            startDate = startDate + "-01";
            Date parseStart = DateUtil.parse(startDate);
            Date beginOfDay = DateUtil.beginOfMonth(parseStart);
            startFormat = DateUtil.format(beginOfDay, "yyyy-MM-dd HH:mm:ss");
            endDate = endDate + "-01";
            Date parseEnd = DateUtil.parse(endDate);
            //一月的结束
            Date endOfDay = DateUtil.endOfMonth(parseEnd);
            endFormat = DateUtil.format(endOfDay, "yyyy-MM-dd HH:mm:ss");
        } else {
            if (StrUtil.isNotBlank(startDate)) {
                Date parseStart = DateUtil.parse(startDate);
                //一天的开始
                Date beginOfDay = DateUtil.beginOfDay(parseStart);
                startFormat = DateUtil.format(beginOfDay, "yyyy-MM-dd HH:mm:ss");
            }

            if (StrUtil.isNotBlank(startDate)) {
                Date parseEnd = DateUtil.parse(endDate);
                //一天的结束
                Date endOfDay = DateUtil.endOfDay(parseEnd);
                endFormat = DateUtil.format(endOfDay, "yyyy-MM-dd HH:mm:ss");
            }
        }
        Page<Map<String, Object>> mapPage = this.getTaskDataStat(page, stationCode, type, startFormat, endFormat);
        List<Map<String, Object>> records = mapPage.getRecords();
        records.forEach(r -> {
            String date = r.get("date").toString();
            r.put("time", date);
            if (ObjectUtil.isNotEmpty(r.get("count1")) && ObjectUtil.isNotEmpty(r.get("sum1"))) {
                String count1 = r.get("count1").toString();
                String sum1 = r.get("sum1").toString();
                String format = String.format("%.2f",
                        ((float) Integer.parseInt(sum1) * 100 / Integer.parseInt(count1)));
                r.put("countRate1", format + "%");
            } else {
                r.put("countRate1", "0%");
            }

            if (ObjectUtil.isNotEmpty(r.get("count2")) && ObjectUtil.isNotEmpty(r.get("sum2"))) {
                String count2 = r.get("count2").toString();
                String sum2 = r.get("sum2").toString();
                String format = String.format("%.2f",
                        ((float) Integer.parseInt(sum2) * 100 / Integer.parseInt(count2)));
                r.put("countRate2", format + "%");
            } else {
                r.put("countRate2", "0%");
            }

            if (ObjectUtil.isNotEmpty(r.get("count3")) && ObjectUtil.isNotEmpty(r.get("sum3"))) {
                String count3 = r.get("count3").toString();
                String sum3 = r.get("sum3").toString();
                String format = String.format("%.2f",
                        ((float) Integer.parseInt(sum3) * 100 / Integer.parseInt(count3)));
                r.put("countRate3", format + "%");
            } else {
                r.put("countRate3", "0%");
            }
            if (ObjectUtil.isNotEmpty(r.get("count4")) && ObjectUtil.isNotEmpty(r.get("sum4"))) {
                String count4 = r.get("count4").toString();
                String sum4 = r.get("sum4").toString();
                String format = String.format("%.2f",
                        ((float) Integer.parseInt(sum4) * 100 / Integer.parseInt(count4)));
                r.put("countRate4", format + "%");
            } else {
                r.put("countRate4", "0%");
            }

            if (ObjectUtil.isNotEmpty(r.get("count5")) && ObjectUtil.isNotEmpty(r.get("sum5"))) {
                String count5 = r.get("count5").toString();
                String sum5 = r.get("sum5").toString();
                String format = String.format("%.2f",
                        ((float) Integer.parseInt(sum5) * 100 / Integer.parseInt(count5)));
                r.put("countRate5", format + "%");
            } else {
                r.put("countRate5", "0%");
            }
            if (ObjectUtil.isNotEmpty(r.get("num"))) {
                r.put("num", r.get("num").toString());
            }
            if (ObjectUtil.isNotEmpty(r.get("duration"))) {
                r.put("duration", r.get("duration").toString());
            }
            if (ObjectUtil.isNotEmpty(r.get("type"))) {
                r.put("type", r.get("type").toString());
            }
            if (ObjectUtil.isNotEmpty(r.get("count"))) {
                r.put("count", r.get("count").toString());
            }
        });

        String[] headers = {"时间", "巡视点位漏检率", "巡视任务执行闭环率", "巡视告警人工审核完成率", "巡视告警准确率", "巡视结果人工审核完成率", "巡视任务的次数", "巡视时长",
                "发现缺陷种类", "发现缺陷数量"};
        String[] keys = {"time", "countRate1", "countRate5", "countRate2", "countRate4", "countRate3", "num",
                "duration", "type", "count"};
        FileUtil.excelImg(records, headers, keys, "", "", response);
    }

    /**********************************
     * 用途说明: 获取历史点位
     * 参数说明 startDate 开始时间
     * 参数说明 endDate 结束时间
     * 参数说明 deviceId 点位id
     * 返回值说明: com.baomidou.mybatisplus.extension.plugins.pagination.Page<java.util.Map<java.lang.String,java.lang
     * .Object>>
     ***********************************/
    @Override
    public Page<Map<String, Object>> getHistoryDevice(Page<Map<String, Object>> page, String startDate,
                                                      String endDate, String deviceId) {
        return taskResultMapper.getHistoryDevice(page, startDate, endDate, deviceId);
    }

    /**********************************
     * 用途说明: 查询非同源对比分析列表
     * 参数说明 stationCode 变电站编号
     * 参数说明 taskName 任务名称
     * 参数说明 mainDeviceName 主设备名称
     * 参数说明 componentName 部件名称
     * 参数说明 recognitionType 识别类型
     * 参数说明 startFormat 开始时间
     * 参数说明 endFormat 结束时间
     * 返回值说明: java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
     ***********************************/
    @Override
    public List<Map<String, Object>> getNonHomologousAnalysis(String stationCode, String taskName,
                                                              String mainDeviceName, String componentName,
                                                              String recognitionType,
                                                              String startFormat, String endFormat) {

        LambdaQueryWrapper<TaskResult> queryWrapper = new LambdaQueryWrapper<>();
        // 只针对红外、表记、位置
        queryWrapper.in(TaskResult::getRecognitionType, "1", "2", "4");
        queryWrapper.eq(TaskResult::getFlag, "2");
        if (StrUtil.isNotBlank(stationCode)) {
            queryWrapper.eq(TaskResult::getStationCode, stationCode);
        }
        if (StrUtil.isNotBlank(taskName)) {
            queryWrapper.like(TaskResult::getTaskName, taskName);
        }
        if (StrUtil.isNotBlank(mainDeviceName)) {
            queryWrapper.like(TaskResult::getMainDeviceName, mainDeviceName);
        }
        if (StrUtil.isNotBlank(componentName)) {
            queryWrapper.like(TaskResult::getComponentName, componentName);
        }
        if (StrUtil.isNotBlank(recognitionType)) {
            queryWrapper.eq(TaskResult::getRecognitionType, recognitionType);
        }
        if (StrUtil.isNotBlank(startFormat)) {
            queryWrapper.ge(TaskResult::getPatroldeviceDate, startFormat);
        }
        if (StrUtil.isNotBlank(endFormat)) {
            queryWrapper.le(TaskResult::getPatroldeviceDate, endFormat);
        }
        queryWrapper.orderByAsc(TaskResult::getTaskCode, TaskResult::getDeviceName, TaskResult::getOrderNum);
        List<Map<String, Object>> mapList = taskResultMapper.selectMaps(queryWrapper);
        List<Map<String, Object>> analysisList = new ArrayList<>();
        // 按照任务名称分组
        Map<String, List<Map<String, Object>>> taskNameList =
                mapList.stream().collect(Collectors.groupingBy(m -> m.get("deviceName").toString() + "（" + m.get(
                        "taskName").toString() + "）" + "_" + m.get("taskTodoId").toString(), Collectors.toList()));
        for (String name : taskNameList.keySet()) {
            Map<String, Object> map = new HashMap<>();
            List<Map<String, Object>> deviceList = taskNameList.get(name);
            // 点位绑定两个摄像头或以上则进行数据对比分析
            if (deviceList.size() != 2) {
                continue;
            }
            deviceList.forEach(r -> {
                String v = ObjectUtil.isNotEmpty(r.get("valid")) ? r.get("valid").toString() : "";
                // 结果
                String valid;
                if (Objects.isNull(r.get("reviseValue"))) {
                    valid = v;
                } else {
                    if ("0".equals(r.get("reviseValid").toString())) {
                        valid = "1";
                    } else {
                        valid = "2";
                    }
                }
                String flag = r.get("flag").toString();
                if ("4".equals(flag)) {
                    r.put("analysisResult", "识别失败");
                } else if ("6".equals(flag)) {
                    r.put("analysisResult", "采集失败");
                } else if (StrUtil.isNotBlank(valid) && "1".equals(valid)) {
                    r.put("analysisResult", "正常");
                } else if (StrUtil.isNotBlank(valid) && "2".equals(valid)) {
                    r.put("analysisResult", "异常");
                } else {
                    r.put("analysisResult", "");
                }
            });
            String difference = "";
            Map<String, Object> result1 = deviceList.get(0);
            Map<String, Object> result2 = deviceList.get(1);
            if (ObjectUtil.isEmpty(result1.get("recognitionType"))) {
                continue;
            }
            if ("1".equals(result1.get("recognitionType").toString()) && ObjectUtil.isNotEmpty(result1.get("value")) && ObjectUtil.isNotEmpty(result2.get("value"))) {
                // 表计
                BigDecimal value1 = new BigDecimal(result1.get("value").toString());
                BigDecimal value2 = new BigDecimal(result2.get("value").toString());
                difference = Math.abs(value1.subtract(value2).doubleValue()) + "";
            }

            // 测温
            if ("4".equals(result1.get("recognitionType").toString()) && ObjectUtil.isNotEmpty(result1.get("value")) && ObjectUtil.isNotEmpty(result2.get("value"))) {
                String value = result1.get("value").toString();
                String value1 = result2.get("value").toString();
                String[] split = value.split(",");
                String[] split1 = value1.split(",");
                if (split.length != 2 || split1.length != 2) {
                    break;
                }
                //                BigDecimal v1 = new BigDecimal(split[0]);
                BigDecimal v2 = new BigDecimal(split[0]);
                //                BigDecimal v3 = new BigDecimal(split1[0]);
                BigDecimal v4 = new BigDecimal(split1[0]);
                difference = Math.abs(v2.subtract(v4).doubleValue()) + "";
            }
            if ("2".equals(result1.get("recognitionType").toString())) {
                // 表面
                String desc1 = ObjectUtil.isNotEmpty(result1.get("desc")) ? result1.get("desc").toString() : "";
                String desc2 = ObjectUtil.isNotEmpty(result2.get("desc")) ? result2.get("desc").toString() : "";
                if (StrUtil.isBlank(desc1) && StrUtil.isBlank(desc2)) {
                    difference = "";
                } else if (desc1.equals(desc2)) {
                    difference = "相同";
                } else {
                    difference = "不相同";
                }
            }
            String deviceId = result1.get("deviceId").toString();
            SubstationDevice substationDevice = substationDeviceService.getById(deviceId);
            String patroldeviceJson = substationDevice.getPatroldeviceJson();
            if (StrUtil.isNotBlank(patroldeviceJson)) {
                JSONArray jsonArray = JSONUtil.parseArray(patroldeviceJson);
                JSONObject jsonObject = jsonArray.getJSONObject(1);
                String alertvalue = jsonObject.getStr("alertvalue");
                map.put("alertvalue", alertvalue);
            }
            String title = StrUtil.subBefore(name, "_", false);
            map.put("difference", difference);
            map.put("taskName", title);
            map.put("deviceName", name);
            map.put("resultList", deviceList);
            analysisList.add(map);

        }
        return analysisList;
    }

    /**********************************
     * 用途说明: 查询非同相对比分析列表
     * 参数说明 stationCode 变电站编号
     * 参数说明 taskName 任务名称
     * 参数说明 mainDeviceName 主设备名称
     * 参数说明 componentName 部件名名称
     * 参数说明 recognitionType 识别类型
     * 参数说明 startFormat 开始时间
     * 参数说明 endFormat 结束时间
     * 返回值说明: java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
     ***********************************/
    @Override
    public List<Map<String, Object>> getNonCoherentAnalysis(String stationCode, String taskName,
                                                            String mainDeviceName, String componentName,
                                                            String recognitionType, String startFormat,
                                                            String endFormat) {
        List<Map<String, Object>> mapList = taskResultMapper.getNonCoherentAnalysis("", stationCode, taskName,
                mainDeviceName, componentName, recognitionType, startFormat, endFormat);
        Map<String, List<Map<String, Object>>> taskList =
                mapList.stream().collect(Collectors.groupingBy(m -> m.get("taskName").toString() + "" + m.get(
                        "recognitionType").toString() + "_" + m.get("meterType").toString() + "_" + m.get("startTime").toString(), Collectors.toList()));
        List<Map<String, Object>> nonCoherentList = new ArrayList<>();
        for (String key : taskList.keySet()) {
            List<Map<String, Object>> resultList = taskList.get(key);
            // 结果小于2直接跳过
            if (resultList.size() < 2) {
                continue;
            }
            // 获取相位分组数量
            Set<String> phases = resultList.stream().map(r -> r.get("phase").toString()).collect(Collectors.toSet());
            Set<String> deviceIds =
                    resultList.stream().map(m -> m.get("deviceId").toString()).collect(Collectors.toSet());
            // 相位小于2直接跳过
            if (phases.size() != resultList.size() || deviceIds.size() != resultList.size()) {
                continue;
            }
            resultList.forEach(r -> {
                String v = ObjectUtil.isNotEmpty(r.get("valid")) ? r.get("valid").toString() : "";
                // 结果
                String valid;
                if (Objects.isNull(r.get("reviseValue"))) {
                    valid = v;
                } else {
                    if ("0".equals(r.get("reviseValid").toString())) {
                        valid = "1";
                    } else {
                        valid = "2";
                    }
                }
                String flag = r.get("flag").toString();
                if ("4".equals(flag)) {
                    r.put("analysisResult", "识别失败");
                } else if ("6".equals(flag)) {
                    r.put("analysisResult", "采集失败");
                } else if (StrUtil.isNotBlank(valid) && "1".equals(valid)) {
                    r.put("analysisResult", "正常");
                } else if (StrUtil.isNotBlank(valid) && "2".equals(valid)) {
                    r.put("analysisResult", "异常");
                } else {
                    r.put("analysisResult", "");
                }
            });
            Map<String, Object> map = new LinkedHashMap<>();
            String name = StrUtil.subBefore(key, "_", false);
            String startTime = StrUtil.subAfter(key, "_", true);
            map.put("name", name + "（" + startTime + "）");
            resultList.sort(Comparator.comparing(r -> r.get("phase").toString()));
            map.put("taskResultList", resultList);
            nonCoherentList.add(map);

        }
        return nonCoherentList;
    }

    /**********************************
     * 用途说明: 查询趋势变化点位列表
     * 参数说明 page 分页参数
     * 参数说明 stationCode 变电站名称
     * 参数说明 taskName 任务名称
     * 参数说明 mainDeviceName 主设备名称
     * 参数说明 componentName 部件名称
     * 参数说明 recognitionType 识别类型
     * 参数说明 deviceName 点位名称
     * 参数说明 startFormat 开始时间
     * 参数说明 endFormat 结束时间
     * 返回值说明: com.baomidou.mybatisplus.extension.plugins.pagination.Page<java.util.Map<java.lang.String,java.lang
     * .Object>>
     ***********************************/
    @Override
    public Page<Map<String, Object>> getTrendChangeDeviceList(Page<Map<String, Object>> page, String stationCode,
                                                              String mainDeviceName,
                                                              String componentName, String recognitionType,
                                                              String deviceName, String startFormat,
                                                              String endFormat) {
        QueryWrapper<TaskResult> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("DISTINCT station_code,area_name,bay_name,main_device_name,component_name,recognition_type,device_id,device_name");
        if (StrUtil.isNotBlank(stationCode)) {
            queryWrapper.eq("station_code", stationCode);
        }
        if (StrUtil.isNotBlank(mainDeviceName)) {
            queryWrapper.like("main_device_name", mainDeviceName);
        }
        if (StrUtil.isNotBlank(componentName)) {
            queryWrapper.like("component_name", componentName);
        }
        if (StrUtil.isNotBlank(deviceName)) {
            queryWrapper.like("device_name", deviceName);
        }
        if (StrUtil.isNotBlank(recognitionType)) {
            queryWrapper.eq("recognition_type", recognitionType);
        }
        if (StrUtil.isNotBlank(startFormat)) {
            queryWrapper.ge("patroldevice_date", startFormat);
        }
        if (StrUtil.isNotBlank(endFormat)) {
            queryWrapper.le("patroldevice_date", endFormat);
        }
        queryWrapper.eq("flag", "2");

        return taskResultMapper.selectMapsPage(page, queryWrapper);
    }

    /**********************************
     * 用途说明: 查询趋势变化分析列表
     * 参数说明 deviceId 点位id
     * 参数说明 startFormat 开始时间
     * 参数说明 endFormat 结束时间
     * 返回值说明: java.util.Map<java.lang.String,java.lang.Object>
     ***********************************/
    @Override
    public Map<String, Object> getTrendChangeAnalysisList(String deviceId, String startFormat, String endFormat) {
        LambdaQueryWrapper<TaskResult> queryWrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotBlank(deviceId)) {
            queryWrapper.eq(TaskResult::getDeviceId, deviceId);
        }
        if (StrUtil.isNotBlank(startFormat)) {
            queryWrapper.ge(TaskResult::getPatroldeviceDate, startFormat);
        }
        if (StrUtil.isNotBlank(endFormat)) {
            queryWrapper.le(TaskResult::getPatroldeviceDate, endFormat);
        }
        queryWrapper.eq(TaskResult::getFlag, "2");
        queryWrapper.isNotNull(TaskResult::getPatroldeviceDate);
        queryWrapper.orderByAsc(TaskResult::getPatroldeviceDate);
        queryWrapper.select(TaskResult::getResultId, TaskResult::getDeviceId, TaskResult::getDeviceName,
                TaskResult::getPatroldeviceDate, TaskResult::getValue, TaskResult::getConf, TaskResult::getUnit,
                TaskResult::getDesc);
        List<Map<String, Object>> mapList = taskResultMapper.selectMaps(queryWrapper);
        // 按照日期分组
        Map<String, List<Map<String, Object>>> taskResultMap =
                mapList.stream().collect(Collectors.groupingBy(m -> DateUtil.format(DateUtil.parse(m.get(
                        "patroldeviceDate").toString()), "yyyy-MM-dd")));
        // 按照时间对map集合进行排序
        Map<String, Object> sortMap = new TreeMap<>(String::compareTo);
        sortMap.putAll(taskResultMap);
        Map<String, Object> map = new LinkedHashMap<>();
        List<Map<String, Object>> deviceList = new ArrayList<>();
        map.put("date", sortMap.keySet());
        // 查询一个点位
        for (String date : sortMap.keySet()) {
            List<Map<String, Object>> resultList = taskResultMap.get(date);
            Map<String, Object> result = resultList.get(resultList.size() - 1);
            deviceList.add(result);
        }
        List<String> value = deviceList.stream().map(m -> m.get("value").toString()).collect(Collectors.toList());
        //获取最大值
        String max = Collections.max(value);
        //获取最小值
        String min = Collections.min(value);
        if (StrUtil.isNotBlank(max) && StrUtil.isNotBlank(min)) {
            // 计算差值
            BigDecimal bd1 = new BigDecimal(max);
            BigDecimal bd2 = new BigDecimal(min);
            double difference = bd1.subtract(bd2).doubleValue();
            map.put("max", max);
            map.put("min", min);
            map.put("difference", Math.abs(difference));
        }
        SubstationDevice substationDevice = substationDeviceService.getById(deviceId);
        if (substationDevice != null) {
            map.put("lowerValue", substationDevice.getLowerValue());
            map.put("upperValue", substationDevice.getUpperValue());
        }
        map.put("deviceList", deviceList);
        return map;
    }

    /**********************************
     * 用途说明: 执行一件顺控任务
     * 参数说明 devicelist
     * 返回值说明: void
     ***********************************/
    @Override
    public void executeTask(List<Map<String, Object>> devicelist, TaskTodo quartzJob, String linkageDeviceType) throws InterruptedException {
        String jobName = quartzJob.getTaskName();
        int min = Math.min(devicelist.size(), 3);
        for (int i = 0; i < min; i++) {
            Map<String, Object> map = devicelist.get(i);
            Thread.sleep(1000);
            int finalI = i;
            new Thread(() -> {
                try {
                    String flag = map.get("flag").toString();
                    if (!("0".equals(flag) || "4".equals(flag))) {
                        return;
                    }
                    //排除当前时刻需要检修的巡视点
                    int count = this.queryExaminePlan(map.get("deviceId").toString(),
                            quartzJob.getPlanStartTime());
                    if (count > 0) {
                        //更新当前记录状态，修改为  3:设备检修中
                        this.updateTaskResultStatus(quartzJob.getTaskTodoId(),
                                map.get("resultId").toString(),
                                "", "3");
                        return;//跳过设备检修区间对应的巡视点
                    }
                    //获取typelist 识别类型
                    String pictureAnalysisTypeList = map.get("pictureAnalysisTypeList").toString();
                    JSONArray typelist = new JSONArray();

                    if (StrUtil.isNotEmpty(pictureAnalysisTypeList)) {
                        com.alibaba.fastjson.JSONObject jobj = JSON.parseObject(pictureAnalysisTypeList);

                        if (ObjectUtil.isNotEmpty(jobj.getString("PictureAnalysisType"))) {
                            if (jobj.getString("PictureAnalysisType").equals("meter")) {
                                typelist.add(map.get("outsideFeature").toString());
                            } else {
                                typelist.add(jobj.getString("PictureAnalysisType"));
                            }
                        }
                        if (ObjectUtil.isNotEmpty(jobj.getString("PictureDefectAnalysisType"))) {
                            typelist.add(jobj.getString("PictureDefectAnalysisType"));
                        }
                        if (ObjectUtil.isNotEmpty(jobj.getString("PictureDiscriminateAnalysisType"))) {
                            typelist.add(jobj.getString("PictureDiscriminateAnalysisType"));
                        }
                    }
                    if (typelist.size() == 0) {
                        throw new Exception("未设置识别方式，不能进行图形识别！");
                    }

                    //路径命名格式为：变电站编码/年/月/日/巡视任务编码/CCD
                    //其中 CCD 为可见光图片  FIR  红外图谱文件  Audio 音频文件 Video 视频文件
                    //图片类型
                    String filetype = "CCD";
                    if (ObjectUtil.isNotEmpty(map.get("fileType"))) {
                        switch (map.get("fileType").toString()) {
                            case "1":
                                filetype = "FIR";
                                break;
                            case "2":
                                filetype = "CCD";
                                break;
                            case "3":
                                filetype = "Audio";
                                break;
                            case "4":
                                filetype = "Video";
                                break;
                            default:
                                filetype = "CCD";
                                break;
                        }
                    }
                    String filepath = String.format("%s/%s/%s/%s/%s/%s/",
                            quartzJob.getStationCode(),
                            DateUtil.format(DateUtil.date(), "yyyy"),
                            DateUtil.format(DateUtil.date(), "MM"),
                            DateUtil.format(DateUtil.date(), "dd"),
                            quartzJob.getTaskCode(),
                            filetype
                    );

                    //文件命名格式为：日期_时间_间隔名_设备名_点位名_类型.jpg
//                    String filename = String.format("%s_%s_%s_%s_%s_%s.mp4",
//                            DateUtil.format(DateUtil.date(), "yyyyMMdd"),
//                            DateUtil.format(DateUtil.date(), "HHmmss"),
//                            map.get("bayName").toString(),
//                            map.get("mainDeviceName").toString(),
//                            map.get("deviceName").toString(),
//                            "视频"
//                    );
                    String filename = String.format("%s_%s_%s.mp4",
                            map.get("deviceId").toString(),
                            map.get("patroldeviceCode").toString(),
                            DateUtil.format(DateUtil.date(), "yyyyMMddHHmmss")
                    );

                    String fullfilename = filepath + filename;
                    String rtspurl = String.format("rtsp://%s:%s/rtp/%s_%s", httpServerConfig.getMediaIp(),
                            httpServerConfig.getMonitorRtspPort(),
                            map.get("rtsp_device_code").toString(), map.get("rtsp_channel_code").toString());
                    //设备rstp流地址不为空，优先取摄像头地址
                    if (ObjUtil.isNotEmpty(map.get("rtsp_device_url"))) {
                        rtspurl = map.get("rtsp_device_url").toString();
                    }

                    com.alibaba.fastjson.JSONObject callresult;
                    com.alibaba.fastjson.JSONObject customParams = new com.alibaba.fastjson.JSONObject();
                    typelist.clear();
                    typelist.add("yjsk");
                    log.info("调用摄像机截取视频");
                    String videoStream = map.get("rtsp_device_code").toString() + "_" + map.get(
                            "rtsp_channel_code").toString();
                    log.info("------录制视频------");
                    String finalRtspurl = rtspurl;
                    String finalFullfilename = fullfilename;
                    httpUtil.getMonitorVideo(httpServerConfig.getffmpegPath(), finalRtspurl, finalFullfilename,
                            linkageDeviceType, videoStream);
                    //更新当前记录状态，修改为  1：已巡视(图像已采集)
                    fullfilename = URLEncoder.encode(fullfilename, "utf-8");//转码存储
                    this.updateTaskResultStatus(quartzJob.getTaskTodoId(), map.get("resultId").toString(),
                            fullfilename, "1");

                    // 3、 调用图片识别算法，进行图形识别
                    //表计类型
                    if (ObjectUtil.isNotEmpty(map.get("meterType"))) {
                        customParams.put("meterType", map.get("meterType").toString());
                    }
                    if (ObjectUtil.isNotEmpty(map.get("outsideAngle"))) {
                        customParams.put("TempAngleList", map.get("outsideAngle").toString());
                    }
                    //缺陷识别结果类型
                    if (ObjUtil.isNotEmpty(map.get("defectresulttypes"))) {
                        customParams.put("defectresulttypes", map.get("defectresulttypes").toString());
                    }

                    //基准图
                    if (ObjUtil.isNotEmpty(map.get("patroldeviceBaseimage"))) {
                        customParams.put("imageNormalUrlPath", map.get("patroldeviceBaseimage").toString());
                    }
                    //有效识别区域
                    if (ObjUtil.isNotEmpty(map.get("patroldeviceEffectiveregion"))) {
                        customParams.put("effectiveregion", map.get("patroldeviceEffectiveregion").toString());
                    }

                    log.info("customParams：" + JSONUtil.toJsonStr(customParams));
                    callresult = httpUtil.callPicAnalyse(map.get("resultId").toString(),
                            map.get("deviceId").toString(), JSONUtil.toJsonStr(typelist),
                            JSONUtil.toJsonStr(customParams), fullfilename);

                    // 解除摄像头的工作状态
                    this.updatePatrolDeviceState(map.get("stationCode").toString(),
                            map.get("rtsp_device_code").toString(), "0");

                    if (callresult != null) {
                        String code = callresult.get("code").toString();
                        if ("-2".equals(code) || "201".equals(code)) {
                            // 设置请求分析主机调用失败的任务为巡视失败
                            this.setTaskResultAndTodo(quartzJob.getStationCode(),
                                    map.get("resultId").toString(), quartzJob.getDeviceSumnum(),
                                    quartzJob.getTaskTodoId());
                        }
                    }

                } catch (Exception e) {
                    log.error(String.format("单条任务执行失败，任务名称:%s,时间：%s", jobName, DateUtil.now()));
                    log.error(e.getMessage());;
                    // 解除摄像头的工作状态
                    this.updatePatrolDeviceState(map.get("stationCode").toString(),
                            map.get("rtsp_device_code").toString(), "0");
                    String flag = "4";
                    if ("获取摄像头截图失败".equals(e.getMessage())) {
                        flag = "6";
                    }
                    this.updateTaskResultStatus(quartzJob.getTaskTodoId(), map.get("resultId").toString(),
                            "", flag);
                }
            }).start();
            //摄像头视频流采集图片
        }
    }

    @Override
    public ResponseResult getThreadTask(String taskTodoId) {
        List<Map<String, Object>> deviceList =
                taskResultMapper.selectMaps(new LambdaQueryWrapper<TaskResult>().eq(TaskResult::getTaskTodoId,
                        taskTodoId));
        Map<String, List<Map<String, Object>>> groupedByCode =
                deviceList.stream().collect(Collectors.groupingBy(r -> r.get("patroldeviceCode").toString()));
        // 将分组结果分配到10个新的集合中
        List<List<Map<String, Object>>> collections =
                GroupAndProcessParallel.distributeToTenCollections1(groupedByCode);
        Map<String, String> map = new HashMap<>();
        for (int i = 0; i < collections.size(); i++) {
            List<Map<String, Object>> mapList = collections.get(i);
            map.put("集合" + i, mapList.size() + "");
        }
        log.info(map.toString());
        return ResponseResult.success();
    }

    @Override
    public void sendTaskResultById(String id) {
        TaskResult taskResult = taskResultMapper.selectById(id);
        TaskTodo taskTodo = this.getById(taskResult.getTaskTodoId());
        this.sendTaskResult(taskTodo, taskResult);
    }

    /**********************************
     * 用途说明: 单点识别
     * 参数说明 id 点位Id
     * 返回值说明: boolean
     ***********************************/
    @Override
    public boolean onceAnalyse(String id) throws Exception {
        SubstationDevice substationDevice = substationDeviceService.getById(id);
        String pictureAnalysisTypeList = substationDevice.getPictureAnalysisTypeList();
        JSONArray typelist = new JSONArray();

        com.alibaba.fastjson.JSONObject customParams = new com.alibaba.fastjson.JSONObject();
        if (StrUtil.isNotEmpty(pictureAnalysisTypeList)) {
            com.alibaba.fastjson.JSONObject jobj = JSON.parseObject(pictureAnalysisTypeList);
            if (ObjectUtil.isNotEmpty(jobj.getString("PictureAnalysisType"))) {
                if ("meter".equals(jobj.getString("PictureAnalysisType"))) {
                    customParams.put("meterType", substationDevice.getOutsideFeature());
                }
                typelist.add(jobj.getString("PictureAnalysisType"));
            }
            if (ObjectUtil.isNotEmpty(jobj.getString("PictureDefectAnalysisType"))) {
                JSONArray defectresult = new JSONArray();
                List<String> pictureType = StrUtil.split(jobj.getString(
                        "PictureDefectAnalysisType"), ",");
                List<Map<String, Object>> pictureDefectAnalysisType =
                        sysDictionaryItemsService.getDeviceByType("PictureDefectAnalysisType");
                // 获取到子项
                List<String> itemCodeList =
                        pictureDefectAnalysisType.stream().filter(p -> pictureType.contains(p.get("itemcode").toString())).map(m -> m.get("custom1").toString()).collect(Collectors.toList());

                for (String code : itemCodeList) {
                    JSONArray jsonArray = JSONUtil.parseArray(code);
                    defectresult.addAll(jsonArray);
                    List<String> keyList =
                            jsonArray.stream().map(j -> JSONUtil.parseObj(j).getStr("key")).collect(Collectors.toList());
                    typelist.addAll(keyList);
                }
                if (defectresult.size() > 0) {
                    //缺陷识别结果类型
                    customParams.put("defectresulttypes", defectresult);
                }
            }
            if (ObjectUtil.isNotEmpty(jobj.getString("PictureDiscriminateAnalysisType"))) {
                typelist.add(jobj.getString("PictureDiscriminateAnalysisType"));
            }
        }

        if (typelist.size() == 0) {
            throw new Exception("未设置识别方式，不能进行图形识别！");
        }

        String filetype = "CCD";
        if (ObjectUtil.isNotEmpty(substationDevice.getSaveTypeList())) {
            switch (substationDevice.getSaveTypeList()) {
                case "1":
                    filetype = "FIR";
                    break;
                case "3":
                    filetype = "Audio";
                    break;
                case "4":
                    filetype = "Video";
                    break;
                default:
                    filetype = "CCD";
                    break;
            }
        }
        String filepath = String.format("%s/%s/%s/%s/%s/%s/",
                substationDevice.getStationCode(),
                DateUtil.format(DateUtil.date(), "yyyy"),
                DateUtil.format(DateUtil.date(), "MM"),
                DateUtil.format(DateUtil.date(), "dd"),
                substationDevice.getDeviceName(),
                filetype
        );

        //文件命名格式为：日期_时间_间隔名_设备名_点位名_类型.jpg
//        String filename = String.format("%s_%s_%s_%s_%s_%s.jpg",
//                DateUtil.format(DateUtil.date(), "yyyyMMdd"),
//                DateUtil.format(DateUtil.date(), "HHmmss"),
//                substationDevice.getBayName(),
//                substationDevice.getMainDeviceName(),
//                substationDevice.getDeviceName(),
//                "原图"
//        );
        String patroldeviceJson = substationDevice.getPatroldeviceJson();
        if (StrUtil.isBlank(patroldeviceJson)) {
            throw new RuntimeException("当前点位未绑定摄像机");
        }
        if (!JSONUtil.isTypeJSONArray(patroldeviceJson)) {
            throw new RuntimeException("当前点位未绑定摄像机");
        }
        JSONArray patroldeviceJsonArray = JSONUtil.parseArray(patroldeviceJson);
        if (patroldeviceJsonArray.size() <= 0) {
            throw new RuntimeException("当前点位未绑定摄像机");
        }
        // 取出点位的第一个摄像机
        JSONObject patroldeviceJsonObject = patroldeviceJsonArray.getJSONObject(0);
        // 视频播放编号
        String patroldeviceCode = patroldeviceJsonObject.getStr("patroldevice_code");
        // 视频播放通道
        String patroldeviceChannelcode = patroldeviceJsonObject.getStr("patroldevice_channelcode");
        String filename = String.format("%s_%s_%s.jpg",
                substationDevice.getDeviceId(),
                patroldeviceCode,
                DateUtil.format(DateUtil.date(), "yyyyMMddHHmmss")
        );

        String fullfilename = filepath + filename;
        String csvFilePath = httpServerConfig.getSnapFilePath() + filepath + filename;
        // 视频播放预置位
        String patroldevicePos = patroldeviceJsonObject.getStr("patroldevice_pos");
        String rtspurl = String.format("rtsp://%s:%s/rtp/%s_%s", httpServerConfig.getMediaIp(),
                httpServerConfig.getMonitorRtspPort(), patroldeviceCode, patroldeviceChannelcode);
        JSONObject map = new JSONObject();

        map.putOpt("deviceId", substationDevice.getDeviceId());
        map.putOpt("valid", "0");
        map.putOpt("meterType", substationDevice.getMeterType());
        map.putOpt("recognitionType", substationDevice.getRecognitionTypeList());
        map.putOpt("value", "");
        try {
            //图像检测
            if ("1".equals(httpServerConfig.getFilefromtype())) {
                //锁定摄像机状态(设置摄像机为工作状态，其他地方不能调用预置位操作)
                this.updatePatrolDeviceState(substationDevice.getStationCode(), patroldeviceCode, "1");

                log.info("开始调用摄像头预置位");
                com.alibaba.fastjson.JSONObject callresult1 = httpUtil.callDevicePos(patroldeviceCode,
                        patroldeviceChannelcode, patroldevicePos, null);
                log.info("摄像头预置位调用成功！" + JSONUtil.toJsonStr(callresult1));
                //延迟时间
                Thread.sleep(8000);
                log.info("开始调用视频并截图");
                log.info("rtspurl" + rtspurl);
                httpUtil.getMonitorVideoSnap(httpServerConfig.getffmpegPath(), rtspurl, fullfilename);
                log.info("完成视频截图并保存到对应位置下！,文件名称：" + fullfilename);
            }
        } catch (Exception e) {
            map.putOpt("desc", "采集失败");
            map.putOpt("analysisResult", "采集失败");
            map.putOpt("filePath", "");
            map.putOpt("defectFilePath", "");
            WebSocketServer.sendInfo("deviceresult_" + substationDevice.getStationCode(), map.toString());
        }
        //更新当前记录状态，修改为  1：已巡视(图像已采集)
        //转码存储
        String encodefilename = fullfilename;
        fullfilename = URLEncoder.encode(fullfilename, "utf-8");
        if (ObjectUtil.isNotEmpty(substationDevice.getOutsideAngle())) {
            if (JSONUtil.isTypeJSONArray(substationDevice.getOutsideAngle())) {
                JSONArray jsonArray = JSONUtil.parseArray(substationDevice.getOutsideAngle());
                customParams.put("TempAngleList", jsonArray);
            }
        }

        //有效识别区域
        if (ObjUtil.isNotEmpty(patroldeviceJsonObject.getStr("effective_region"))) {
            customParams.put("effectiveregion", patroldeviceJsonObject.getStr("effective_region"));
        }

        log.info("==============================typelist=======================" + typelist.toString());
        com.alibaba.fastjson.JSONObject callresult = null;
        String resultId = substationDevice.getDeviceId();
        String objectId = substationDevice.getDeviceId();
        if ("infrared".equals(typelist.get(0).toString())) {
            //红外测温
            log.info("进入红外测温方法");
            String outsideAngle = "";
            if (ObjectUtil.isNotEmpty(substationDevice.getOutsideAngle())) {
                outsideAngle = substationDevice.getOutsideAngle();
            }
            // 调用温度的sdk识别并给图片加上温度
            callresult = this.callPicAnalyse(resultId, objectId, patroldeviceCode, rtspurl, fullfilename,
                    outsideAngle, csvFilePath);
        } else {
            callresult = httpUtil.callPicAnalyse(resultId, objectId, JSONUtil.toJsonStr(typelist),
                    JSONUtil.toJsonStr(customParams), encodefilename);
        }
        // 解除摄像头的工作状态
        this.updatePatrolDeviceState(substationDevice.getStationCode(), patroldeviceCode, "0");

        if (callresult != null) {
            String code = callresult.get("code").toString();
            if ("-2".equals(code) || "201".equals(code)) {
                map.putOpt("flag", "4");
                String fileName = URLEncoder.encode(encodefilename, "utf-8");
                map.putOpt("filePath", fileName);
                map.putOpt("defectFilePath", fileName);
                map.putOpt("desc", "巡视失败");
                map.putOpt("analysisResult", "识别失败");
                WebSocketServer.sendInfo("deviceresult_" + substationDevice.getStationCode(), map.toString());
            }
        }
        return true;
    }

    @Override
    public void exportMeterDataByTaskTodoId(String taskTodoId, HttpServletResponse response) {
        List<Map<String, Object>> mapList = taskResultMapper.selectMaps(new LambdaQueryWrapper<TaskResult>().eq(TaskResult::getTaskTodoId, taskTodoId).eq(TaskResult::getRecognitionType,"1"));
        List<Map<String, Object>> recognition_type = sysDictionaryItemsService.getDeviceByType("recognition_type");
        List<Map<String, Object>> DeviceClass = sysDictionaryItemsService.getDeviceByType("DeviceClass");
        // 表计类型
        List<Map<String, Object>> meterTypeList = sysDictionaryItemsService.getDeviceByType("MeterType");
        mapList.forEach(record->{
            String deviceClass = "";
            if (!Objects.isNull(record.get("deviceClass"))) {
                Map<String, Object> map =
                        DeviceClass.stream().filter(r -> !Objects.isNull(record.get("deviceClass")) && r.get(
                                "itemcode").equals(record.get("deviceClass").toString())).findFirst().orElse(null);
                if (map != null) {
                    deviceClass = map.get("dictname").toString();
                }
            }
            record.put("deviceClassName", deviceClass);
            String meterType="";
            if (!Objects.isNull(record.get("meterType"))) {
                Map<String, Object> map = meterTypeList.stream().filter(r -> !Objects.isNull(record.get("meterType")) && r.get(
                                "itemcode").equals(record.get("meterType").toString())).findFirst().orElse(null);
                if (map != null) {
                    meterType = map.get("dictname").toString();
                }
            }
            record.put("meterType", meterType);
            String recognitionType = "";
            if (!Objects.isNull(record.get("recognitionType"))) {
                Map<String, Object> map = recognition_type.stream().filter(r -> !Objects.isNull(record.get(
                        "recognitionType")) && r.get("itemcode").equals(record.get("recognitionType").toString())).findFirst().orElse(null);
                if (map != null) {
                    recognitionType = map.get("dictname").toString();
                }
            }
            record.put("recognitionTypeName", recognitionType);
            if (ObjectUtil.isNotEmpty(record.get("filePath"))) {
                String filePath = record.get("filePath").toString();
                try {
                    filePath = URLDecoder.decode(filePath, "utf-8");
                } catch (UnsupportedEncodingException e) {
                    log.error(e.getMessage());;
                }
                record.put("img", httpServerConfig.getSnapFilePath() + filePath);

            }
            if (ObjectUtil.isNotEmpty(record.get("value"))) {
                String value = record.get("value").toString();
                String unit = ObjectUtil.isNotEmpty(record.get("unit")) ? record.get("unit").toString() : "";
                record.put("value", value + unit);
            }
        });

        String[] headers = {"区域名称", "间隔名称", "设备名称", "部件名称", "点位名称", "点位分类", "识别类型","表计类型", "巡视结果", "巡视结论", "巡视时间", "巡视图片",};
        String[] keys = {"areaName", "bayName",  "mainDeviceName", "componentName", "deviceName", "deviceClassName", "recognitionTypeName", "meterType","value", "analysisResult", "time", "img"};
        String imgs = "img";
        try {
            FileUtil.excelImg(mapList, headers, keys, imgs, "", response);
        } catch (IOException e) {
            log.error(e.getMessage());;
        }
    }

    @Override
    public Page<Map<String, Object>> getResultByPatroldevice(Page<Map<String, Object>> page, String internationalId,
                                                             String mainDeviceId,
                                                             String taskName, String recognitionType, String valid,
                                                             String isReport, String startDate,
                                                             String endDate) {
        return taskResultMapper.getResultByPatroldevice(page, internationalId, mainDeviceId, taskName,
                recognitionType, valid,
                 isReport, startDate, endDate);
    }

}
