package com.zd.laboratory.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.zd.common.core.constant.*;
import com.zd.common.core.domain.R;
import com.zd.common.core.enums.HardwareOperate;
import com.zd.common.core.enums.HardwareTypeEnum;
import com.zd.common.core.enums.SenseType;
import com.zd.common.core.exception.ServiceException;
import com.zd.common.core.utils.Assert;
import com.zd.common.core.utils.PageHelperUtil;
import com.zd.common.core.utils.SecurityUtils;
import com.zd.common.core.web.domain.AjaxResult;
import com.zd.common.core.web.domain.ResultData;
import com.zd.common.redis.service.RedisService;
import com.zd.common.security.utils.DictUtils;
import com.zd.laboratory.config.HardwareFunctionStatusConfig;
import com.zd.laboratory.domain.LabSubject;
import com.zd.laboratory.domain.*;
import com.zd.laboratory.domain.dto.LabSubListQuery;
import com.zd.laboratory.domain.vo.*;
import com.zd.laboratory.domain.vo.LabSubjectVO;
import com.zd.laboratory.mapper.*;
import com.zd.laboratory.mqtt.entiy.EquipmentStatus;
import com.zd.laboratory.mqtt.service.impl.SubMessageSendManager;
import com.zd.laboratory.service.*;
import com.zd.laboratory.socket.command.Symbol;
import com.zd.laboratory.socket.service.SocketService;
import com.zd.laboratory.socket.vo.TransmissionVo;
import com.zd.laboratory.utils.FunctionMapperUtil;
import com.zd.system.api.RemoteUserService;
import com.zd.system.api.chemical.RemoteChemicalAlarmService;
import com.zd.system.api.chemical.RemoteChemicalService;
import com.zd.system.api.domain.SubQueryConfig;
import com.zd.system.api.domain.SysDictData;
import com.zd.system.api.domain.SysUser;
import com.zd.system.api.laboratory.domain.*;
import com.zd.system.api.laboratory.domain.vo.HardwareCVO;
import com.zd.system.api.laboratory.domain.vo.LabSubClassVO;
import com.zd.system.api.laboratory.domain.vo.SenseValVO;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 实验室管理服务
 *
 * @Author: zhoupan
 * @Date: 2021/09/17/15:14
 * @Description:
 */
@Service
@EnableConfigurationProperties(HardwareFunctionStatusConfig.class)
public class LabSubjectManagerService {

    Logger logger = LoggerFactory.getLogger(LabSubjectManagerService.class);

    @Autowired
    ILabSubjectService subjectService;
    @Autowired
    LabHardwareMapper hardwareMapper;
    @Autowired
    LabSensorMapper sensorMapper;
    @Autowired
    HardwareFunctionStatusConfig hardwareFunctionStatusConfig;
    @Autowired
    ILabSubjectLayoutService subjectLayoutService;
    @Autowired
    private LabSubjectMapper labSubjectMapper;
    @Autowired
    private ILabSubjectLayoutService labSubjectLayoutService;
    @Autowired
    private LabSubjectHardwarePositionMapper labSubjectHardwarePostionMapper;
    @Autowired
    private RemoteUserService userService;
    @Autowired
    private RedisService redisService;
    @Autowired
    ILabSensorService labSensorService;
    @Autowired
    private SubMessageSendManager subMessageSendManager;
    @Autowired
    private ILabHazardSubjectRelationService labHazardSubjectRelationService;
    @Autowired
    private LabRiskPlanMapper labRiskPlanMapper;

    @Autowired
    RemoteChemicalAlarmService remoteChemicalAlarmService;
    @Autowired
    private RemoteChemicalService remoteChemicalService;

    private Map<Control.CommTypeEnums, ControlService> controlServiceMap = new HashMap<>();

    /**
     * 最低危险等级
     */
//    @Autowired
//    private LabSubClassVO getNONELabSubClassVO;
    @Autowired
    private FunctionMapperUtil functionMapperUtil;
    @Autowired
    private SocketService socketService;
    @Autowired
    private ILabControlService labControlService;


    public LabSubjectManagerService(List<ControlService> controlServices) {
        controlServiceMap = controlServices.stream().collect(Collectors.toMap(a -> a.comTypeEnums(), Function.identity()));

    }

    /**
     * 设备-执行命令
     *
     * @param labHardware
     * @param functionStatus
     * @return
     */
    public ResultData excutingComm(LabHardware labHardware, FunctionStatus functionStatus) {
        if (functionStatus.getCommTypeEnums() == null) return ResultData.fail("不存在控制类型！");
        ControlService controlService = controlServiceMap.get(functionStatus.getCommTypeEnums());
        if (controlService == null) return ResultData.fail("不存在控制类型！");
        if (labHardware == null || labHardware.getRelayCode() == null) {
            logger.error("硬件不存在或未关联继电器！id：{}，名称：{}", labHardware.getId(), labHardware.getName());
            return ResultData.fail(StrUtil.format("硬件不存在或未关联继电器！id：{}，名称：{}", labHardware.getId(), labHardware.getName()));
        }
        if (labHardware.getBit() == null) {
            logger.error("硬件不存在或未关联继电器！id：{},名称:{}", labHardware.getId(), labHardware.getName());
            return ResultData.fail(StrUtil.format("未关联继电器位！id：{}，名称：{}", labHardware.getId(), labHardware.getName()));

        }

        //新老继电器调用方法
        Symbol.command command = null;
        if (functionStatus.getCmd().equals("00")) {
            command = Symbol.command.close;
        } else if (functionStatus.getCmd().equals("01")) {
            command = Symbol.command.open;
        } else {
            return ResultData.fail("继电器指令错误!!");
        }

        logger.info("预案调用硬件:=====================硬件id" + labHardware.getId() + "==========硬件指令:====" + command.toString());
        return ResultData.success(control(labHardware.getId(), command));

        //老继电器调用方法
//        return controlService.execution(labHardware, functionStatus);

    }

    public void test(Long id){
        LabHardwareVO labHardwareVO = hardwareMapper.selectLabHardwareById(id);
    }

    /**
     * 控制电源开关设备
     *
     * @param id
     */
    public Boolean control(Long id, Symbol.command command) {
        //通过设备编号获取设备详细信息
        LabHardwareVO labHardwareVO = hardwareMapper.selectLabHardwareById(id);
        if (labHardwareVO == null || labHardwareVO.getRelayCode() == null) {
            logger.error("硬件不存在或未关联继电器！id：{}", id);
            return false;
        }
        if (labHardwareVO.getBit() == null) {
            logger.error("未关联继电器位！id：{},名称:{}", id, labHardwareVO.getName());
            return false;
        }
        if (labHardwareVO.getHardwareType() == 2) {
            AjaxResult ajaxResult = socketService.sendMqttCommand(labHardwareVO.getId(), labHardwareVO.getRelayCode(), command, labHardwareVO.getBit(),labHardwareVO.getSubjectId());
            boolean equals = ajaxResult.get(AjaxResult.CODE_TAG).equals(200);
            if (equals) {
                //添加记录
                labControlService.manualCreateLabControlAndSave(labHardwareVO, Symbol.order.control, command);
            }
        } else {
            AjaxResult ajaxResult = socketService.sendCommand(Symbol.order.control, labHardwareVO.getRelayCode(), command, labHardwareVO.getBit());
            boolean equals = ajaxResult.get(AjaxResult.CODE_TAG).equals(200);
            if (equals) {
                //添加记录
                labControlService.manualCreateLabControlAndSave(labHardwareVO, Symbol.order.control, command);
            }
            return equals;
        }
        return true;
    }



    /**
     * 控制智能报警开关设备
     *
     * @param id
     */
    public Boolean alarmControl(Long id, Symbol.command command) {
        //通过设备编号获取设备详细信息
        LabHardwareVO labHardwareVO = hardwareMapper.selectLabHardwareById(id);
        if(Symbol.command.close==command){
            //远程调用报警设备数据，校验是否是声光报警
            Map <String,String> alarmMap = new HashMap<>();
            alarmMap.put("terminalNum",labHardwareVO.getHardwareNum());
            alarmMap.put("alarmMode","2");
            alarmMap.put("handlingStatus","1");

            R<List <LinkedHashMap<String,String>>> alarmList = remoteChemicalAlarmService.getList(alarmMap);
            Optional.ofNullable(alarmList.getData()).orElseGet(Collections::emptyList).stream()
                    .forEach(a->{
                        Map <String,String> alarmUpMap = new HashMap<>();
                        alarmUpMap.put("id",a.get("id"));
                        alarmUpMap.put("handlingUserId",SecurityUtils.getUserId()+"");
                        alarmUpMap.put("handlingContent","手动关闭智能声光报警");
                        remoteChemicalAlarmService.updateStatus(alarmUpMap);
//                        if(!updateAlarm.getData()){
//                            logger.error("智能声光报警日志处理失败，报警设备编号："+labHardwareVO.getHardwareNum());
//                        }
                    });
        }

        if (labHardwareVO == null || labHardwareVO.getRelayCode() == null) {
            logger.error("硬件不存在或未关联继电器！id：{}", id);
            return false;
        }
        if (labHardwareVO.getBit() == null) {
            logger.error("未关联继电器位！id：{},名称:{}", id, labHardwareVO.getName());
            return false;
        }
        if (labHardwareVO.getHardwareType() == 2) {
            AjaxResult ajaxResult = socketService.sendMqttCommand(labHardwareVO.getId(), labHardwareVO.getRelayCode(), command, labHardwareVO.getBit(),labHardwareVO.getSubjectId());
            boolean equals = ajaxResult.get(AjaxResult.CODE_TAG).equals(200);
            if (equals) {
                //添加记录
                labControlService.manualCreateLabControlAndSave(labHardwareVO, Symbol.order.control, command);
            }
        } else {
            AjaxResult ajaxResult = socketService.sendCommand(Symbol.order.control, labHardwareVO.getRelayCode(), command, labHardwareVO.getBit());
            boolean equals = ajaxResult.get(AjaxResult.CODE_TAG).equals(200);
            if (equals) {
                //添加记录
                labControlService.manualCreateLabControlAndSave(labHardwareVO, Symbol.order.control, command);
            }
            return equals;
        }
        return true;
    }


    /**
     * 获取实验室简要信息 - 风险信息中获取实验室相关信息
     *
     * @param id
     * @return
     */
    public SubSimpleVO querySubSimpleVOById(Long id) {
        //查询实验室
        LabSubject subject = new LabSubject();
        subject.setId(id);
        List<LabSubjectVO> labSubjects = labSubjectMapper.selectLabSubjectVOList(subject);
        LabSubjectVO subjectVO = Optional.ofNullable(labSubjects)
                .filter(a -> a.size() > 0)
                .map(a -> a.get(0))
                .orElse(null);
        Assert.isNotNull(subjectVO, "实验室不存在");
        SubSimpleVO subSimpleVO = new SubSimpleVO();
        subSimpleVO.setSubName(subjectVO.getName());
        subSimpleVO.setSubId(id);
        subSimpleVO.setDeptName(subjectVO.getDeptName());
        subSimpleVO.setSafeUserName(subjectVO.getSafeUserName());
        subSimpleVO.setSafeUserPhone(subjectVO.getSafeUserPhone());
        //负责人
        if (subjectVO.getAdminId() != null) {
            //获取用户
            R<SysUser> userResult = userService.getUserInfoByUserId(subjectVO.getAdminId(), SecurityConstants.INNER);
            if (userResult.getData() != null) {
                subSimpleVO.setAdminName(userResult.getData().getNickName());
                subSimpleVO.setAdminPhone(userResult.getData().getPhonenumber());
            }

        }
        //视频设备ID
        List<HardwareCVO> hardwareCVOS = queryHardwareCVOSBySubId(id);
        List<String> collect = Optional.ofNullable(hardwareCVOS)
                .orElseGet(Collections::emptyList)
                .stream()
                .filter(a -> HardwareTypeEnum.VIDEO_MONITOR.equals(a.getHardwareTypeEnum()))
                .filter(a -> StrUtil.isNotBlank(a.getHardwareNUM()))
                .map(a -> a.getHardwareNUM())
                .collect(Collectors.toList());
        subSimpleVO.setTvIds(collect);
        return subSimpleVO;

    }

    public SubSimpleVO querySubSimpleVO(Long id) {
        //查询实验室
        LabSubject subject = new LabSubject();
        subject.setId(id);
        List<LabSubjectVO> labSubjects = labSubjectMapper.selectLabSubjectVOList(subject);
        LabSubjectVO subjectVO = Optional.ofNullable(labSubjects)
                .filter(a -> a.size() > 0)
                .map(a -> a.get(0))
                .orElseThrow(() -> {
                    return new ServiceException("实验室不存在");
                });

        subjectVO.setQrCodeUrl(subjectVO.getId() + "-" + Optional.ofNullable(subjectVO.getRoom()).orElse(""));
        return conversionSubSimpleVO(subjectVO);
    }

    /**
     * 一体机获取实验室信息
     *
     * @param subject
     * @return
     */
    private SubSimpleVO conversionSubSimpleVO(LabSubjectVO subject) {
        SubSimpleVO subSimpleVO = new SubSimpleVO();
        //设置实验室名称
        subSimpleVO.setSubName(subject.getName());
        subSimpleVO.setSubId(subject.getId());
        //设置
        List<SysDictData> dictDatas = DictUtils.getDictCache("lab_onepc_outcheck");

        List<String> newDictDatas = new ArrayList<>();
        if(StringUtils.isNotBlank(subject.getCheckOut())){
            newDictDatas = Optional.ofNullable(subject.getCheckOut()).map(b -> b.split(",")).map(b -> Arrays.asList(b))
                    .orElseGet(null).stream().map(b -> Optional.ofNullable(dictDatas).filter(a -> a.size() > 0)
                            .orElseGet(Collections::emptyList).stream()
                            .filter(a -> b.equals(a.getDictValue())).findFirst().orElseGet(null))
                    .map(SysDictData::getDictLabel).collect(Collectors.toList());
        }

        //离开检查
        subSimpleVO.setOutCheck(newDictDatas);

        //进入检查
        //设置
        if (StrUtil.isNotBlank(subject.getCheckIn())) {
            List<SysDictData> check_in = DictUtils.getDictCache("sub_check_in");
            Optional.ofNullable(subject.getCheckIn().split(","))
                    .filter(a -> a.length > 0)
                    .ifPresent(a -> {
                        List<Map<String, String>> list = new ArrayList<>();

                        subSimpleVO.setInCheck(list);
                        Arrays.stream(a).map(c -> {
                            Optional<SysDictData> first = check_in.stream().filter(d -> c.equals(d.getDictValue())).findFirst();
                            return first;
                        }).filter(c -> c.isPresent())
                                .forEach(c -> {
                                    c.ifPresent(d -> {
                                        Map<String, String> map = new HashMap<>(2);
                                        map.put("code", d.getDictValue());
                                        map.put("name", d.getDictLabel());
                                        list.add(map);

                                    });
                                });
                    });

        }

        //设置学科类型
        subSimpleVO.setSubClass(DictUtils.getDictCacheLable("subject_class", subject.getSubDept()));
        //设置负责人
        subSimpleVO.setAdminName(subject.getAdminName());
        subSimpleVO.setAdminPhone(subject.getAdminPhone());
        //获取危险等级
        //LabSubClassVO subclassVo = getSubClassVO(subject);

        //设置危险等级名称
        subSimpleVO.setDangerName(subject.getTypeName());
        //设置危险等级
        subSimpleVO.setDangerLevel(subject.getLevelName());
        subSimpleVO.setDangerColor(subject.getFiedColor());
        //设置地址
        List<SubAddrr> subAddrrs = subjectLayoutService.selectAddrrByLayoutIds(subject.getLayoutId());
        subSimpleVO.setAddress(Optional.ofNullable(subAddrrs)
                .filter(a -> a.size() > 0)
                .map(a -> a.get(0))
                .map(SubAddrr::addrrPlus)
                .orElseGet(() -> StrUtil.EMPTY));
        //设置安全联系信息
//        subSimpleVO.setSafeUserPhone(subject.getSafeUserPhone());
//        subSimpleVO.setSafeUserName(subject.getSafeUserName());
        subSimpleVO.setAdminUserDesc(subject.getAdminName()+" "+subject.getAdminPhone());
        subSimpleVO.setSafeUserDesc(labSubjectMapper.queryUserNameBySafeUserByOnepc(subject.getSafeUserId()));
        subSimpleVO.setSafeUserName(labSubjectMapper.queryUserNameBySafeUserId(subject.getSafeUserId()));
        subSimpleVO.setSafeUserPhone(labSubjectMapper.queryUserPhoneBySafeUserId(subject.getSafeUserId()));
        subSimpleVO.setDeptName(subject.getDeptName());

        //=====安全警示牌=====
        SubSimpleVO.SafeInfo safeInfo = new SubSimpleVO.SafeInfo();
        subSimpleVO.setSubSafeInfo(safeInfo);
        safeInfo.setQrCode(subject.getQrCode());

        // 安全警示标示
        Optional.ofNullable(subject.getSafeSigns())
                .map(a -> a.split(","))
                .ifPresent(a -> {
                    safeInfo.setSafeSigns(Arrays.asList(a));
                });
        //主要危险类别--字典
        Optional.ofNullable(subject.getHazardCategory())
                .map(a -> a.split(","))
                .ifPresent(a -> {
                    List<SysDictData> sys_safety_warning = DictUtils.getDictCache("sys_hazard_category");
                    List<String> collect1 = getList(a, sys_safety_warning);
                    safeInfo.setHazardCategory(collect1);
                });
        //安全防控措施
        Optional.ofNullable(subject.getRiskMeasure())
                .map(a -> a.split(","))
                .ifPresent(a -> {
                    // 安全警示标示
                    List<SysDictData> sys_safety_warning = DictUtils.getDictCache("sys_risk_measure");
                    List<String> collect1 = getList(a, sys_safety_warning);
                    safeInfo.setRiskMeasure(collect1);
                });
        //安全防控措施
        Optional.ofNullable(subject.getOutfire())
                .map(a -> a.split(","))
                .ifPresent(a -> {
                    // 安全警示标示
                    List<SysDictData> sys_safety_warning = DictUtils.getDictCache("sys_extinguishing_key_points");
                    List<String> collect1 = getList(a, sys_safety_warning);
                    safeInfo.setOutfire(collect1);
                });

        // 实验室+安全检查二维码
        subSimpleVO.setQrCodeUrl(subject.getQrCodeUrl());
        return subSimpleVO;


    }

    public LabSubClassVO getSubClassVO(LabSubjectVO subject) {
        return getSubClassVO(subject.getId());
    }

    public LabSubClassVO getSubClassVO(Long id) {
        List<LabSubClassVO> labSubClassVOS = subjectService.querySubClassesByIds(id);
//        LabSubClassVO subclassVo = Optional.ofNullable(labSubClassVOS)
//                .filter(a -> a.size() > 0)
//                .map(a -> a.get(0))
//                .orElse(getNONELabSubClassVO);
//        return subclassVo;
        if (labSubClassVOS.size() > 0) {
            return labSubClassVOS.get(0);
        }
        return null;
    }


    private List<String> getList(String[] a, List<SysDictData> sys_safety_warning) {
        Map<String, SysDictData> collect = Optional.ofNullable(sys_safety_warning)
                .orElseGet(Collections::emptyList)
                .stream()
                .collect(Collectors.toMap(b -> b.getDictValue(), Function.identity()));
        return Arrays.stream(a).map(c -> collect.get(c))
                .filter(d -> d != null)
                .map(d -> d.getDictLabel())
                .collect(Collectors.toList());
    }


    /**
     * 查询实验室控制数据列表- 数据权限（包括负责人）
     *
     * @return
     */
    public List<LabSubjectVO> querySubCListVO(LabSubListQuery labSubListQuery) {
        LabSubject subject = new LabSubject();
        BeanUtils.copyProperties(labSubListQuery, subject);
        //todo 暂未实现负责人数据权限，所以数据不包括负责人数据

        //1.获取权限的分页数据
        PageHelperUtil.startPage();
        List<LabSubjectVO> labSubjects = subjectService.selectLabSubjectListAUTH(subject);
        List<Long> subIds = new ArrayList<>();
        labSubjects.forEach( a -> {
            // 危险源
            List<LabHazardSubVO> hazards = labHazardSubjectRelationService.queryHazardSubListVO(a.getId());

            List<LabHazardVO> hazardList = new ArrayList<>();

            hazards.forEach(b -> {
                LabHazardVO hazardSubVO = new LabHazardVO();
                BeanUtils.copyProperties(b, hazardSubVO);
                hazardList.add(hazardSubVO);
            });
            a.setLabHazardList(hazardList);

            a.setSafeUserName(labSubjectMapper.queryUserNameBySafeUserId(a.getSafeUserId()));

            subIds.add(a.getId());


        });
        try {
            // 实验室化学品临界量计算
            R r = remoteChemicalService.queryCriticaliBySubId(subIds);
            if(r.getCode() == HttpStatus.SUCCESS){
                List<Map<String, Object>> list = (List<Map<String, Object>>) r.getData();
                list.forEach(map -> {
                    for (LabSubjectVO s : labSubjects) {
                        if (Objects.equals(s.getId(), Long.parseLong(map.get("subId") + ""))) {
                            s.setRiskIndicator(map.get("criticali") + "");
                            break;
                        }
                    }
                });

            }
        }catch (Exception e){

        }

        // 2.5 页面改变，接口加分页，并拆成两部分
        return labSubjects;

//         return createSubControllerVO(labSubjects, true, true, true, true, true);
    }

    public LabSubjectControllerVO querySubById(Long id, Integer type) {
        LabSubject subject = new LabSubject();
        subject.setId(id);
        List<LabSubjectVO> labSubjects = subjectService.selectLabSubjectListAUTH(subject);
        List<LabSubjectControllerVO> list = createSubControllerVO(labSubjects, true, true, true, true, true);
        if(list.size() > 0){
            LabSubjectControllerVO subjectControllerVO = list.get(0);
            subjectControllerVO.setSafeUserNameAdminPhone(labSubjectMapper.queryUserNameBySafeUserInfo(subjectControllerVO.getSafeUserId()));
            subjectControllerVO.setSafeUserName(labSubjectMapper.queryUserNameBySafeUserId(subjectControllerVO.getSafeUserId()));
            subjectControllerVO.setSafeUserPhone(labSubjectMapper.queryUserPhoneBySafeUserId(subjectControllerVO.getSafeUserId()));
            if(type == 0) {

                LabSubjectControllerVO.SafeInfo safeInfo = new LabSubjectControllerVO.SafeInfo();
                subjectControllerVO.setSafeInfo(safeInfo);

                // 安全警示标示
                Optional.ofNullable(subjectControllerVO.getSafeSigns())
                        .map(a -> a.split(","))
                        .ifPresent(a -> {
                            safeInfo.setSafeSigns(Arrays.asList(a));
                        });
                //主要危险类别
                Optional.ofNullable(subjectControllerVO.getHazardCategory())
                        .map(a -> a.split(","))
                        .ifPresent(a -> {
                            List<SysDictData> sys_safety_warning = DictUtils.getDictCache("sys_hazard_category");
                            List<String> collect1 = getList(a, sys_safety_warning);
                            safeInfo.setHazardCategory(collect1);
                        });
                //安全防控措施
                Optional.ofNullable(subjectControllerVO.getRiskMeasure())
                        .map(a -> a.split(","))
                        .ifPresent(a -> {
                            // 安全警示标示
                            List<SysDictData> sys_safety_warning = DictUtils.getDictCache("sys_risk_measure");
                            List<String> collect1 = getList(a, sys_safety_warning);
                            safeInfo.setRiskMeasure(collect1);
                        });
                //灭火要点
                Optional.ofNullable(subjectControllerVO.getOutfire())
                        .map(a -> a.split(","))
                        .ifPresent(a -> {
                            // 安全警示标示
                            List<SysDictData> sys_safety_warning = DictUtils.getDictCache("sys_extinguishing_key_points");
                            List<String> collect1 = getList(a, sys_safety_warning);
                            safeInfo.setOutfire(collect1);
                        });

                // 穿戴检查项
                Optional.ofNullable(subjectControllerVO.getCheckIn())
                        .map(a -> a.split(","))
                        .ifPresent(a -> {
                            List<SysDictData> sys_safety_warning = DictUtils.getDictCache("sub_check_in");
                            List<String> collect1 = getList(a, sys_safety_warning);
                            safeInfo.setCheckInData(collect1);
                        });
                // 离开检查项
                Optional.ofNullable(subjectControllerVO.getCheckOut())
                        .map(a -> a.split(","))
                        .ifPresent(a -> {
                            List<SysDictData> sys_safety_warning = DictUtils.getDictCache("lab_onepc_outcheck");
                            List<String> collect1 = getList(a, sys_safety_warning);
                            safeInfo.setCheckOutData(collect1);
                        });

                // 危险源
                List<LabHazardSubVO> hazards = labHazardSubjectRelationService.queryHazardSubListVO(subjectControllerVO.getId());

                List<LabSubjectControllerVO.LabHazardSubVO> hazardList = new ArrayList<>();

                hazards.forEach(a -> {
                    LabSubjectControllerVO.LabHazardSubVO hazardSubVO = new LabSubjectControllerVO.LabHazardSubVO();
                    BeanUtils.copyProperties(a, hazardSubVO);
                    hazardSubVO.setLabel(a.getAnotherName()+"-"+a.getAnotherCode());
                    hazardList.add(hazardSubVO);
                });
                subjectControllerVO.setHazardList(hazardList);

                // 关联预案
                subjectControllerVO.setRiskPlanList(labRiskPlanMapper.selectRiskPlanCountBySubId(subjectControllerVO.getId()));
            }

            return subjectControllerVO;
        }

        throw new ServiceException("未查询到数据，ID无效！");
    }

    /**
     * 查询我管理的实验室-即我作为负责人的实验室
     *
     * @return
     */
    public List<LabSubjectControllerVO> queryMyAadminSubCListVO() {
        LabSubject subject = new LabSubject();
        subject.setAdminId(SecurityUtils.getUserId());
        //不展示禁用数据
//        subject.setIsDel(false);
        List<LabSubjectVO> labSubjects = labSubjectMapper.selectLabSubjectVOList(subject);
        return createSubControllerVO(labSubjects, false, true, true, false, true);
    }

    /**
     * 获取实验室传感器
     *
     * @param id
     * @return
     */
    public List<SenseValVO> querySenseValVOSBySubId(Long id) {
        //2.获取传感器
        List<LabSensor> labSensors = sensorMapper.selectSensorBySubIds(id);
        return Optional.ofNullable(labSensors).orElseGet(Collections::emptyList)
                .stream()
                .map(a -> getSenseValVO(a))
                .collect(Collectors.toList());

    }

    /**
     * 获取实验室测点功能
     *
     * @param id
     * @return
     */
    public List<SensorFunctionStatus> querySenseFunctionBySubId(Long id) {
        List<LabSensor> labSensors = sensorMapper.selectSensorBySubIds(id);
        return getSensorFunctionStatuses(labSensors, true);
    }

    /**
     * 获取实验室数据
     *
     * @param subjectId
     * @return
     */
    public List<SensorFunctionStatus> querySenseNewFunctionBySubId(Long subjectId) {
        List<LabSensor> labSensors = sensorMapper.selectSensorBySubIds(subjectId);
        updateLabHardwareFunctionStatuses(subjectId);

        return getSensorFunctionStatuses(labSensors, true);
//        return getSensorNewFunctionStatuses(labSensors, subjectId);
    }

    /**
     * 获取继电器数据
     *
     * @param subjectId
     * @return
     */
    private void updateLabHardwareFunctionStatuses(Long subjectId) {
        List<LabHardware> hardwareList = hardwareMapper.selectNewLabHardwareBySubIds(subjectId);
        JSONObject jsonObject = redisService.getCacheObject(CacheConstants.SENSOR_DATA_KEY + subjectId);
        List<EquipmentStatus> equipmentStatusList = new ArrayList<>();
        for (LabHardware labHardware : hardwareList) {
            String value = jsonObject.getString(labHardware.getConfigName());
            String status = jsonObject.getString(labHardware.getConfigStatus());
            if (StringUtils.isEmpty(value) || StringUtils.isEmpty(status)) {
                continue;
            }
            if (status.equals("0")) {
                labHardware.setOperate(HardwareOperate.OFFLINE);
            } else if (status.equals("1") && value.equals("1")) {
                labHardware.setOperate(HardwareOperate.OPEN);
            } else if (status.equals("1") && value.equals("0")) {
                labHardware.setOperate(HardwareOperate.CLOSE);
            } else if (status.equals("1")) {
                labHardware.setOperate(HardwareOperate.ONLINE);
            } else {
                labHardware.setOperate(HardwareOperate.EXCEPTION);
            }
            hardwareMapper.updateLabHardwareStatusById(labHardware);
            Integer key = redisService.getCacheObject(CacheConstants.RELAY_STATUS_KEY + labHardware.getId());
            if (key == labHardware.getOperate().getCode()) {
                //发送继电器状态
                EquipmentStatus equipmentStatus = new EquipmentStatus();
                equipmentStatus.setNum(labHardware.getId() + "");
                equipmentStatus.setHardwareOperate(labHardware.getOperate());
                equipmentStatusList.add(equipmentStatus);
            }
        }
        if (equipmentStatusList.size() > 0) {
            subMessageSendManager.sendNewHardwareUpdate(equipmentStatusList);
        }
    }

    /**
     * 获取实验室测点功能 : 根据网关ID
     *
     * @param gatewayId
     * @return
     */
    public List<SensorFunctionStatus> querySenseFunctionBySubId(String gatewayId) {
        //通过缓存获取数据
        Long subId = labSensorService.getCacheSubByGateway(gatewayId);
        if (subId == null) return null;
        List<LabSensor> labSensors = sensorMapper.selectSensorBySubIds(subId);
        return getSensorFunctionStatuses(labSensors, true);
    }


    /**
     * 获取指定传感器下的测点数据
     *
     * @param labSensors
     * @param isInitVal  是否初始化值
     * @return
     */
    public List<SensorFunctionStatus> getSensorFunctionStatuses(List<LabSensor> labSensors, Boolean isInitVal) {
        return getSensorFunctionStatuses(labSensors, isInitVal, true);
    }

    /**
     * 获取指定传感器下的测点数据
     *
     * @param labSensors
     * @param isInitVal  是否初始化值
     * @param isInitWran 是否初始化预警
     * @return
     */
    public List<SensorFunctionStatus> getSensorFunctionStatuses(List<LabSensor> labSensors, Boolean isInitVal, Boolean isInitWran) {
        //按名字显示
        if (CollUtil.isEmpty(labSensors)) return Collections.emptyList();

        Long subId = labSensors.get(0).getSubjectId();

        /*JSONObject jsonObject = redisService.getCacheObject(CacheConstants.SENSOR_DATA_KEY + subId);
        if (null == jsonObject) {
            return getSensorFunctionOldStatuses(labSensors, isInitVal);
        } else {
            return getSensorFunctionNewStatuses(labSensors);
        }*/

        List<SensorFunctionStatus> list = getSensorFunctionOldStatuses(labSensors, isInitVal);
        JSONObject jsonObject = redisService.getCacheObject(CacheConstants.SENSOR_DATA_KEY + subId);
        logger.info("传感器合并：云盒设备："+ JSONUtil.toJsonStr(list));
        if(jsonObject != null){
            list = getSensorFunctionNewStatusesTwo(list, subId);
            logger.info("传感器合并：采集器设备："+ JSONUtil.toJsonStr(list));
        }
        return list;
    }

    /**
     * 旧的云盒的数据组装
     *
     * @param labSensors
     * @param isInitVal
     * @return
     */
    private List<SensorFunctionStatus> getSensorFunctionOldStatuses(List<LabSensor> labSensors, Boolean isInitVal) {
        if (CollUtil.isEmpty(labSensors)) return Collections.emptyList();
        final Set<String> wran = redisService.getCacheSet(Constants.WRAN_KEY + labSensors.get(0).getSubjectId());
        final Map<SenseType, List<SensorFunctionStatus>> sensorFunctionStatusListMap = hardwareFunctionStatusConfig.getSensorFunctionStatusListMap();
        Map<String, Map<String, List<SensorFunctionStatus>>> tempMap = new HashMap<>();
        return Optional.ofNullable(labSensors).orElseGet(Collections::emptyList)
                .stream()
                .map(a -> {
                    if (isInitVal && !tempMap.containsKey(a.getGatewayId())) {
                        Map<String, List<SensorFunctionStatus>> transmissionMultiple = getTransmissionMultiple(a.getGatewayId());
                        tempMap.put(a.getGatewayId(), transmissionMultiple);
                    }
                    List<SensorFunctionStatus> list = sensorFunctionStatusListMap.get(a.getType());
                    return Optional.ofNullable(list).orElseGet(Collections::emptyList).stream().map(c -> {
                        SensorFunctionStatus sensorFunctionStatus = new SensorFunctionStatus();
                        sensorFunctionStatus.setFunNum(c.getFunNum());
                        sensorFunctionStatus.setDescribe(a.getName());
                        sensorFunctionStatus.setFuncName(c.getDescribe());
                        sensorFunctionStatus.setOrder(c.getOrder());
                        sensorFunctionStatus.setHardwareNum(a.getGatewayId());
                        sensorFunctionStatus.setUnit(c.getUnit());
                        sensorFunctionStatus.setNumberDecimal(c.getNumberDecimal());
                        sensorFunctionStatus.setRouteNum(a.getRouteNum());
                        sensorFunctionStatus.setId(a.getId());
                        sensorFunctionStatus.setType(a.getType());
                        sensorFunctionStatus.setConfigName(a.getConfigName());

                        if (wran != null && wran.contains(c.getFunNum())) {
                            sensorFunctionStatus.setHasWarn(true);
                        }
                        return sensorFunctionStatus;
                    }).collect(Collectors.toList());
                })
                .filter(a -> CollUtil.isNotEmpty(a))
                .flatMap(List::stream)
                .map(a -> {
                    Map<String, List<SensorFunctionStatus>> stringSensorFunctionStatusMap = tempMap.get(a.getHardwareNum());
                    if (CollUtil.isNotEmpty(stringSensorFunctionStatusMap)) {
                        String val = Optional.ofNullable(stringSensorFunctionStatusMap.get(a.getFunNum())).orElse(Collections.emptyList()).stream().filter(c -> c.getRouteNum().equals(a.getRouteNum())).map(c -> c.getVal()).findFirst().orElse(null);
                        a.setVal(val);
                    }
                    return a;
                })
                .sorted((c, d) -> NumberUtil.compare(c.getOrder(), d.getOrder()))
                .collect(Collectors.toList());
    }

    /**
     * 新采集器数据的组装
     *
     * @param labSensors
     * @return
     */
    private List<SensorFunctionStatus> getSensorFunctionNewStatuses(List<LabSensor> labSensors) {
        //按名字显示
        if (CollUtil.isEmpty(labSensors)) {
            return Collections.emptyList();
        }
        JSONObject jsonObject = redisService.getCacheObject(CacheConstants.SENSOR_DATA_KEY + labSensors.get(0).getSubjectId());
        //获取
        final Map<SenseType, List<SensorFunctionStatus>> sensorFunctionStatusListMap = hardwareFunctionStatusConfig.getSensorFunctionStatusListMap();
        return Optional.ofNullable(labSensors).orElseGet(Collections::emptyList).stream()
                .map(a -> {
                    List<SensorFunctionStatus> list = sensorFunctionStatusListMap.get(a.getType());
                    return Optional.ofNullable(list).orElseGet(Collections::emptyList).stream().map(c -> {
                        if (null != jsonObject) {
                            c.setVal(jsonObject.getString(a.getConfigName()));
                        }
                        SensorFunctionStatus sensorFunctionStatus = new SensorFunctionStatus();
                        sensorFunctionStatus.setFunNum(c.getFunNum());
                        sensorFunctionStatus.setDescribe(a.getName());
                        sensorFunctionStatus.setFuncName(c.getDescribe());
                        sensorFunctionStatus.setOrder(c.getOrder());
                        sensorFunctionStatus.setHardwareNum(a.getGatewayId());
                        sensorFunctionStatus.setUnit(c.getUnit());
                        sensorFunctionStatus.setNumberDecimal(c.getNumberDecimal());
                        sensorFunctionStatus.setRouteNum(a.getRouteNum());
                        sensorFunctionStatus.setVal(c.getVal());
                        return sensorFunctionStatus;
                    }).collect(Collectors.toList());
                }).filter(a -> CollUtil.isNotEmpty(a)).flatMap(List::stream)
                .sorted((c, d) -> NumberUtil.compare(c.getOrder(), d.getOrder()))
                .collect(Collectors.toList());
    }

    /**
     * 新采集器数据的组装
     *
     * @param labSensors
     * @return
     */
    private List<SensorFunctionStatus> getSensorFunctionNewStatusesTwo(List<SensorFunctionStatus> labSensors, Long subId) {
        //按名字显示
        if (CollUtil.isEmpty(labSensors)) {
            return Collections.emptyList();
        }
        JSONObject jsonObject = redisService.getCacheObject(CacheConstants.SENSOR_DATA_KEY + subId);
        //获取
        final Map<SenseType, List<SensorFunctionStatus>> sensorFunctionStatusListMap = hardwareFunctionStatusConfig.getSensorFunctionStatusListMap();
        return Optional.ofNullable(labSensors).orElseGet(Collections::emptyList).stream()
                .map(a -> {
                    List<SensorFunctionStatus> list = sensorFunctionStatusListMap.get(a.getType());
                    return Optional.ofNullable(list).orElseGet(Collections::emptyList).stream().map(c -> {
                        if(StringUtils.isBlank(a.getConfigName())){

                            return a;
                        }else {
                            c.setVal(jsonObject.getString(a.getConfigName()));

                            SensorFunctionStatus sensorFunctionStatus = new SensorFunctionStatus();
                            sensorFunctionStatus.setFunNum(c.getFunNum());
                            sensorFunctionStatus.setDescribe(a.getDescribe());
                            sensorFunctionStatus.setFuncName(c.getDescribe());
                            sensorFunctionStatus.setOrder(c.getOrder());
                            sensorFunctionStatus.setHardwareNum(a.getHardwareNum());
                            sensorFunctionStatus.setUnit(c.getUnit());
                            sensorFunctionStatus.setNumberDecimal(c.getNumberDecimal());
                            sensorFunctionStatus.setRouteNum(a.getRouteNum());
                            sensorFunctionStatus.setVal(c.getVal());
                            return sensorFunctionStatus;
                        }

                    }).distinct().collect(Collectors.toList());
                }).filter(a -> CollUtil.isNotEmpty(a)).flatMap(List::stream)
                .sorted((c, d) -> NumberUtil.compare(c.getOrder(), d.getOrder()))
                .collect(Collectors.toList());
    }


    /**
     * 获取指定传感器下新采集器的测点数据getSensorNewFunctionStatuses
     *
     * @param labSensors
     * @return
     */
    public List<SensorFunctionStatus> getSensorNewFunctionStatuses(List<LabSensor> labSensors, Long subjectId) {
        //按名字显示
        if (CollUtil.isEmpty(labSensors)) {
            return Collections.emptyList();
        }
        JSONObject jsonObject = redisService.getCacheObject(CacheConstants.SENSOR_DATA_KEY + subjectId);
        //获取
        final Map<SenseType, List<SensorFunctionStatus>> sensorFunctionStatusListMap = hardwareFunctionStatusConfig.getSensorFunctionStatusListMap();
        return Optional.ofNullable(labSensors).orElseGet(Collections::emptyList).stream()
                .map(a -> {
                    List<SensorFunctionStatus> list = sensorFunctionStatusListMap.get(a.getType());
                    return Optional.ofNullable(list).orElseGet(Collections::emptyList).stream().map(c -> {
                        if (null != jsonObject) {
                            c.setVal(jsonObject.getString(a.getConfigName()));
                            String compare = jsonObject.getString(a.getConfigStatus());
                            if (("1").equals(compare)) {
                                redisService.setCacheObject(CacheConstants.SENSOR_DATA_KEY_ISONLINE + a.getId() + "," + a.getSubjectId(), compare, 1L, TimeUnit.MINUTES);
                            }
                        }
                        SensorFunctionStatus sensorFunctionStatus = new SensorFunctionStatus();
                        sensorFunctionStatus.setFunNum(c.getFunNum());
                        sensorFunctionStatus.setDescribe(a.getName());
                        sensorFunctionStatus.setFuncName(c.getDescribe());
                        sensorFunctionStatus.setOrder(c.getOrder());
                        sensorFunctionStatus.setHardwareNum(a.getGatewayId());
                        sensorFunctionStatus.setUnit(c.getUnit());
                        sensorFunctionStatus.setNumberDecimal(c.getNumberDecimal());
                        sensorFunctionStatus.setRouteNum(a.getRouteNum());
                        sensorFunctionStatus.setVal(c.getVal());
                        logger.info("&&^^&&" + JSONObject.toJSONString(sensorFunctionStatus));
                        return sensorFunctionStatus;
                    }).collect(Collectors.toList());
                }).filter(a -> CollUtil.isNotEmpty(a)).flatMap(List::stream)
                .sorted((c, d) -> NumberUtil.compare(c.getOrder(), d.getOrder()))
                .collect(Collectors.toList());
    }


    /**
     * 获取测点的缓存数据
     *
     * @param id
     * @return
     */
    public Map<String, SensorFunctionStatus> getTransmission(String id) {
        TransmissionVo transmissionVo = null;
        if (org.apache.commons.lang3.StringUtils.isNotBlank(id) && redisService.hasKey(CacheConstants.GATEWAY_KEY + id)) {
            String str = redisService.getCacheObject(CacheDevice.SENSOR_KEY.getRedisKey() + id);
            if (StringUtils.isNotBlank(str)) {
                transmissionVo = JSONObject.parseObject(str, TransmissionVo.class);
            }
        }
        if (transmissionVo == null || StrUtil.isBlank(transmissionVo.getA3())) {
            return Collections.emptyMap();
        }
        SensorConfig sensorConfig = socketService.saveRelayInfo(transmissionVo.getA3(), Integer.parseInt(transmissionVo.getA6(), Character.FORMAT) / 4, 2);
        //可能存在多个一样类型的传感器功能
        return Optional.ofNullable(functionMapperUtil.confiSensorData(transmissionVo, sensorConfig))
                .orElseGet(Collections::emptyList)
                .stream()
                .collect(Collectors.toMap(a -> a.getFunNum(), Function.identity()));

    }

    /**
     * 获取测点的缓存数据 ： 支持多个重复测点
     *
     * @param id
     * @return
     */
    public Map<String, List<SensorFunctionStatus>> getTransmissionMultiple(String id) {
        TransmissionVo transmissionVo = null;
        if (org.apache.commons.lang3.StringUtils.isNotBlank(id) && redisService.hasKey(CacheConstants.GATEWAY_KEY + id)) {
            String str = redisService.getCacheObject(CacheDevice.SENSOR_KEY.getRedisKey() + id);
            if (StringUtils.isNotBlank(str)) {
                transmissionVo = JSONObject.parseObject(str, TransmissionVo.class);
            }
        }
        if (transmissionVo == null || StrUtil.isBlank(transmissionVo.getA3())) {
            return Collections.emptyMap();
        }
        SensorConfig sensorConfig = socketService.saveRelayInfo(transmissionVo.getA3(), Integer.parseInt(transmissionVo.getA6(), Character.FORMAT) / 4, 2);
        //可能存在多个一样类型的传感器功能
        return Optional.ofNullable(functionMapperUtil.confiSensorData(transmissionVo, sensorConfig))
                .orElseGet(Collections::emptyList)
                .stream()
                .collect(Collectors.groupingBy(a -> a.getFunNum()));

    }

    public SubLayoutVO querySubLayoutById(Long id) {
        LabSubjectLayout labSubjectLayout = new LabSubjectLayout();
        labSubjectLayout.setSubjectId(id);
        List<LabSubjectLayout> labSubjectLayouts = labSubjectLayoutService.selectLabSubjectLayoutList(labSubjectLayout);
        if (CollUtil.isEmpty(labSubjectLayouts)) return null;
        LabSubjectLayout labSubjectLayout1 = labSubjectLayouts.get(0);
        SubLayoutVO subLayoutVO = new SubLayoutVO();

        subLayoutVO.setHeight(labSubjectLayout1.getLayHeight());
        subLayoutVO.setWidth(labSubjectLayout1.getLayWidth());

        LabSubjectHardwarePosition position = new LabSubjectHardwarePosition();
        position.setLabSubjectId(id);
        List<LabSubjectHardwarePosition> hardwarePositionList = labSubjectHardwarePostionMapper.selectLabSubjectHardwarePositionList(position);
        subLayoutVO.setLabSubjectHardwarePosition(hardwarePositionList);
        return subLayoutVO;
    }


    /**
     * 获取实验室设备
     *
     * @param id
     * @return
     */
    public List<HardwareCVO> queryHardwareCVOSBySubId(Long id) {
        List<LabHardware> labSensors = hardwareMapper.selectLabHardwareBySubIds(id);
        return Optional.ofNullable(labSensors).orElseGet(Collections::emptyList)
                .stream()
                .map(a -> getHardwareCVO(a))
                .collect(Collectors.toList());

    }

    /**
     * 完善重点实验室数据
     * 完善传感器和地址数据
     *
     * @param labSubjects
     * @return
     */
    public List<LabSubjectControllerVO> completeMainSubInfo(List<? extends LabSubject> labSubjects) {


        return createSubControllerVO(labSubjects, false, false, false, false, true);
    }

    /**
     * 生成实验室控制VO
     * 2021年11月12日 增加了{@link SubQueryManager} 请看其中的方法
     *
     * @param labSubjects
     * @param flag             是否计算权限（数据权限>负责人 ，数据权限会覆盖负责人 ）
     * @param iflabSubClassVOS 是否计算危险等级
     * @param iflabHardwares   是否计算可控设备
     * @param iflabSensors     是否计算传感器
     * @return
     */
    @Deprecated
    private List<LabSubjectControllerVO> createSubControllerVO(List<? extends LabSubject> labSubjects, boolean flag, boolean iflabSubClassVOS, boolean iflabHardwares, boolean iflabSensors, boolean ifFunction) {
        List<LabSubjectControllerVO> list = null;
        if (CollUtil.isNotEmpty(labSubjects)) {
            Long[] longs = labSubjects.stream().map(a -> a.getId()).toArray(Long[]::new);
            //0.获取危险等级
//            List<LabSubClassVO> labSubClassVOS = null;
//            if (iflabSubClassVOS) {
//                labSubClassVOS = subjectService.querySubClassesByIds(longs);
//            }
            List<LabHardware> labHardwares = null;
            if (iflabHardwares) {
                //1.可控设备
                labHardwares = hardwareMapper.selectLabHardwareBySubIds(longs);
            }
            List<LabSensor> labSensors = null;
            boolean flagUpdate = false;
            //获取测点列表
            if (ifFunction) {
                //2.获取传感器
                labSensors = sensorMapper.selectSensorBySubIds(longs);
            }
            if (iflabSensors && ifFunction == false) {
                //2.获取传感器
                labSensors = sensorMapper.selectSensorBySubIds(longs);
            }
            //2.1.获取详细地址后面做(已完成)
            Long[] layoutIds = labSubjects.stream().map(a -> a.getLayoutId()).filter(a -> a != null).toArray(Long[]::new);
            List<SubAddrr> subAddrrs = subjectLayoutService.selectAddrrByLayoutIds(layoutIds);
            Map<Long, SubAddrr> subAddrrMap = subAddrrs.stream().collect(Collectors.toMap(SubAddrr::getId, Function.identity()));
            //3.获取实验室是否拥有数据权限
            //3 获取实验室数据权限（杨森的需求：仅负责人时不能修改实验室） 后面做(已完成)
            List<LabSubjectVO> labSubjectsDataScope = null;
            if (flag) {
                // 实验权限覆盖后面做(已完成)
                LabSubject subject = new LabSubject();
//                subject.setAdminId(SecurityUtils.getUserIdEx());
                //获取我的实验室
                labSubjectsDataScope = subjectService.selectLabSubjectListDataScope(subject);
            }
            Map<Long, Long> mapSubDataScope = Optional.ofNullable(labSubjectsDataScope).orElseGet(Collections::emptyList)
                    .stream().collect(Collectors.toMap(a -> a.getId(), a -> a.getId()));
            //4.传感器和可控设备都转为vo数据,并映射为map表
            Map<Long, List<HardwareCVO>> mapHardwareCVO = Optional.ofNullable(labHardwares).orElse(new ArrayList<>(0)).stream().map(a -> {
                HardwareCVO hardware = getHardwareCVO(a);


                return hardware;
            }).collect(Collectors.groupingBy(HardwareCVO::getSubId));

            Map<Long, List<LabSensor>> mapSenseTemp = Optional.ofNullable(labSensors)
                    .orElse(Arrays.asList())
                    .stream()
                    .collect(Collectors.groupingBy(LabSensor::getSubjectId));
            Map<Long, List<SenseValVO>> mapSenseValVO = Optional.ofNullable(labSensors).orElse(Arrays.asList()).stream().map(a -> {
                SenseValVO senseValVO = getSenseValVO(a);
                return senseValVO;
            }).collect(Collectors.groupingBy(SenseValVO::getSubId));
//            //映射危险等级 需求变更
//            Map<Long, LabSubClassVO> subClassMap = Optional.ofNullable(labSubClassVOS)
//                    .orElse(Arrays.asList())
//                    .stream()
//                    .collect(Collectors.toMap(a -> a.getSubjectId(), Function.identity()));
            //5.转为实验室vo 数据 ,组装设备和权限到实验室
            list = labSubjects.stream().map(a -> {
                a.setQrCodeUrl(a.getId() + "-" + Optional.ofNullable(a.getRoom()).orElse(""));

                LabSubjectControllerVO scVO = new LabSubjectControllerVO();
                BeanUtils.copyProperties(a, scVO);

                if (iflabSensors) {
                    scVO.setSenseVOList(mapSenseValVO.get(a.getId()));
                }
                if (iflabHardwares) {
                    scVO.setLabHardwareVOList(mapHardwareCVO.get(a.getId()));
                }
                //设置测点列表
                if (ifFunction) {
                    List<LabSensor> labSensors1 = mapSenseTemp.get(a.getId());
                    List<SensorFunctionStatus> sensorFunctionStatuses = getSensorFunctionStatuses(labSensors1, true);
                    scVO.setSensorFunctionStatusList(sensorFunctionStatuses);
                    logger.info("setSensorFunctionStatusList:" + JSONObject.toJSONString(scVO.getSensorFunctionStatusList()));

                }
                //设置危险等级
                if (iflabSubClassVOS) {
                    LabSubClassVO labSubClassVO = new LabSubClassVO();
                    if (scVO.getLevel() != null) {
                        labSubClassVO.setDangerLevel(Long.valueOf(scVO.getLevel()));
                    }
                    scVO.setSubClassVO(labSubClassVO);
                }
                //需求变化， 危险等级不再和危险品关联，直接和实验室关联

                //设置地址信息 后面做(已完成)
                scVO.setSubAddrr(subAddrrMap.get(a.getLayoutId()));
                if (flag) {
                    scVO.setAdmin(Boolean.FALSE);
                    //实验权限覆盖 后面做(已完成)
                    if (mapSubDataScope.containsKey(a.getId())) {
                        scVO.setAdmin(Boolean.TRUE);
                    }
                }
                return scVO;
            }).collect(Collectors.toList());
        }
        return list;

    }

    /**
     * 异步执行 查询危险等级
     *
     * @param longs
     * @return
     */
    @Async("labExecutor")
    public CompletableFuture<Map<Long, LabSubClassVO>> querySubClass(Long... longs) {
        logger.info("查询安全等级线程:{}", Thread.currentThread().getName());
        //查询
        List<LabSubClassVO> labSubClassVOS = subjectService.querySubClassesByIds(longs);
        //映射危险等级
        Map<Long, LabSubClassVO> subClassMap = Optional.ofNullable(labSubClassVOS)
                .orElse(Arrays.asList())
                .stream()
                .collect(Collectors.toMap(a -> a.getSubjectId(), Function.identity()));
        return CompletableFuture.completedFuture(subClassMap);
    }


    /**
     * 异步执行 获取实验室硬件
     *
     * @param longs
     * @return
     */
    @Async("labExecutor")
    public CompletableFuture<Integer> queryHardwares(Map<Long, SubDiyVO> subDiyVOMap, Long... longs) {
        int re = 0;
        List<LabHardware> labHardwares = hardwareMapper.selectLabHardwareBySubIds(longs);
        //传感器和可控设备都转为vo数据,并映射为map表
        Map<Long, List<HardwareCVO>> mapHardwareCVO = Optional.ofNullable(labHardwares).orElse(new ArrayList<>(0)).stream().map(a -> {
            HardwareCVO hardware = getHardwareCVO(a);
            return hardware;
        }).collect(Collectors.groupingBy(HardwareCVO::getSubId));
        Optional.ofNullable(mapHardwareCVO)
                .ifPresent(a -> {
                    a.entrySet().forEach(b -> {
                        subDiyVOMap.computeIfPresent(b.getKey(), (k, v) -> {
                            v.setLabHardwareVOList(b.getValue());
                            return v;
                        });
                    });

                });
        re = 1;
        return CompletableFuture.completedFuture(re);
    }


    /**
     * 异步查询地址
     *
     * @param labSubjects
     * @return
     */
    @Async("labExecutor")
    public CompletableFuture<Map<Long, SubAddrr>> querySubAddrs(List<LabSubjectVO> labSubjects) {

        Long[] layoutIds = labSubjects.stream().map(a -> a.getLayoutId()).filter(a -> a != null).toArray(Long[]::new);
        List<SubAddrr> subAddrrs = subjectLayoutService.selectAddrrByLayoutIds(layoutIds);
        Map<Long, SubAddrr> subAddrrMap = Optional.ofNullable(subAddrrs).orElse(Collections.emptyList()).stream().collect(Collectors.toMap(SubAddrr::getId, Function.identity()));
        return CompletableFuture.completedFuture(subAddrrMap);
    }

    /**
     * 异步执行 获取实验室测点功能列表
     *
     * @param longs
     * @return
     */
    @Async("labExecutor")
    public CompletableFuture<Integer> querySensorsFunction(SubQueryConfig subQueryConfig, Map<Long, SubDiyVO> subDiyVOMap, Long... longs) {
        int re = 0;
        logger.info("组装传感器测点功能线程1:{}", Thread.currentThread().getName());
        //获取传感器
        List<LabSensor> labSensors = sensorMapper.selectSensorBySubIds(longs);
        logger.info("组装传感器测点功能线程2:{}", Thread.currentThread().getName());
        Map<Long, List<LabSensor>> mapSenseTemp = Optional.ofNullable(labSensors)
                .orElse(Arrays.asList())
                .stream()
                .collect(Collectors.groupingBy(LabSensor::getSubjectId));


        mapSenseTemp.entrySet().forEach(b -> {
            subDiyVOMap.computeIfPresent(b.getKey(), (k, v) -> {
                List<LabSensor> labSensors1 = mapSenseTemp.get(k);
                //初始化测点方法
                List<SensorFunctionStatus> sensorFunctionStatuses = getSensorFunctionStatuses(labSensors1, subQueryConfig.getInitSensorFunctionValue(), subQueryConfig.getInitWarnSensorFunction());
                v.setSensorFunctionList(sensorFunctionStatuses);
                //如果需要查询预警信息
                return v;
            });
        });
        re = 1;
        return CompletableFuture.completedFuture(re);
    }

    @Async("labExecutor")
    public CompletableFuture<Map<Long, List<LabSensor>>> querySensorsFunction(Long... longs) {
        logger.info("组装传感器测点功能线程:{}", Thread.currentThread().getName());
        //获取传感器
        List<LabSensor> labSensors = sensorMapper.selectSensorBySubIds(longs);
        Map<Long, List<LabSensor>> mapSenseTemp = Optional.ofNullable(labSensors)
                .orElse(Arrays.asList())
                .stream()
                .collect(Collectors.groupingBy(LabSensor::getSubjectId));
        return CompletableFuture.completedFuture(mapSenseTemp);
    }

    private LabSubClassVO getLabSubClassVO(LabSubClassVO subClassVO) {
        return subClassVO;
        //return Optional.ofNullable(subClassVO).orElseGet(() -> this.getNONELabSubClassVO);
    }

    /**
     * 传感器转换为公共的设备展示数据
     *
     * @param a
     * @return
     */
    private SenseValVO getSenseValVO(LabSensor a) {
        SenseValVO senseValVO = new SenseValVO();
        senseValVO.setSubId(a.getSubjectId());
        senseValVO.setHardwareName(a.getName());
        senseValVO.setSenseType(a.getType());
        //todo 这里需要考虑设备唯一码从哪里来
//                senseValVO.setHardwareNUM();
        return senseValVO;
    }

    /**
     * 硬件转换为公共的设备展示数据
     *
     * @param a
     * @return
     */
    public HardwareCVO getHardwareCVO(LabHardware a) {
        //todo 这里需要考虑设备唯一码从哪里来
        // hardware.setHardwareNUM();
        HardwareCVO hardware = new HardwareCVO();
        hardware.setId(a.getId().toString());
        hardware.setHardwareName(a.getName());
        hardware.setHardwareTypeEnum(a.getType());
        hardware.setSubId(a.getSubjectId());
        hardware.setState(a.getOperate() == null ? HardwareOperate.OFFLINE : a.getOperate());
        hardware.setHardwareNUM(a.getHardwareNum());
        //默认不在线
        hardware.setSwitchEnums(Control.SwitchEnums.NO_ONLINE);
        //初始化开关状态 (开关类型)
        if (a.getHardwareType() == 2) {
            Integer code=redisService.getCacheObject(CacheConstants.RELAY_STATUS_KEY+a.getId());
            if(null==code){
                if(null!=a.getOperate() && a.getOperate().getCode()==3){
                    hardware.setSwitchEnums(Control.SwitchEnums.ON);
                }
                if(null!=a.getOperate() &&  a.getOperate().getCode()==4){
                    hardware.setSwitchEnums(Control.SwitchEnums.OFF);
                }
            }else{
                //开
                if(code==3){
                    hardware.setSwitchEnums(Control.SwitchEnums.ON);
                    hardware.setState(HardwareOperate.OPEN);
                }
                if(code==4){
                    hardware.setSwitchEnums(Control.SwitchEnums.OFF);
                    hardware.setState(HardwareOperate.CLOSE);
                }
            }
        } else {
            if (StrUtil.isNotBlank(a.getRelayCode()) && a.getBit() != null) {
                Map<Integer, Control.SwitchEnums> switchEnums = socketService.getSwitchEnums(a.getRelayCode());
                if (switchEnums != null) {
                    Control.SwitchEnums switchEnums1 = switchEnums.get(a.getBit());
                    hardware.setSwitchEnums(switchEnums1);
                }
            }
        }

//        //初始化一体机&视频状态
//        else if(HardwareTypeEnum.ONE_MACHINE.equals(a.getType())&&StrUtil.isNotBlank(a.getHardwareNum()))
//        {
//            Object cacheObject = redisService.getCacheObject(CacheConstants.HEARTBEAT + a.getHardwareNum());
//            if(cacheObject!=null)
//            {
//                hardware.setSwitchEnums(Control.SwitchEnums.ON);
//            }
//        }
        //不再使用
//        hardware.setFunctionStatus(hardwareFunctionStatusConfig.conversionByCode(a.getType(), a.getFunctionStatus()));
//        hardware.setFunctionStatusList(hardwareFunctionStatusConfig.getFunctionStatus(a.getType()));
        return hardware;
    }


    /**
     * 楼栋实验室统计
     *
     * @param ids
     * @return
     */
    public List<TotalByID> queryBuildingSubTotal(Long... ids) {
        return subjectService.queryCountByBuildIds(ids);
    }

}
