package cn.iocoder.yudao.module.pms.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.SortablePageParam;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.object.PageUtils;
import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils;
import cn.iocoder.yudao.module.pms.ThingsModelDTO;
import cn.iocoder.yudao.module.pms.controller.admin.TableDataInfo;
import cn.iocoder.yudao.module.pms.controller.admin.iotdeviceallotlog.vo.IotDeviceAllotLogPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotdevicecategorytemplateattrs.vo.IotDeviceProperty;
import cn.iocoder.yudao.module.pms.controller.admin.iotdevicematerial.vo.IotDeviceMaterialRespVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotdeviceperson.vo.IotDevicePersonPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotdevicepersonlog.vo.IotDevicePersonLogPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotdevicerunlog.vo.IotDeviceRunLogRespVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotdevicestatuslog.vo.IotDeviceStatusLogPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotmodeltemplateattrs.vo.IotModelTemplateAttrsPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.vo.IotDevicePageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.vo.IotDeviceRespVO;
import cn.iocoder.yudao.module.pms.controller.admin.vo.IotDeviceSaveReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.vo.excel.DeviceImportExcelVO;
import cn.iocoder.yudao.module.pms.dal.dataobject.IotDeviceDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.IotInfoClassifyDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.IotTreeDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotZHBD.DeviceZHBDDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotdeviceallotlog.IotDeviceAllotLogDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotdeviceperson.IotDevicePersonDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicepersonlog.IotDevicePersonLogDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicestatuslog.IotDeviceStatusLogDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotmodel.IotModelDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotmodeltemplateattrs.IotModelTemplateAttrsDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.tdparams.IotTdParamsDO;
import cn.iocoder.yudao.module.pms.dal.mysql.IotDeviceMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.IotInfoClassifyMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.IotTreeMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.TDDeviceMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.iotdeviceallotlog.IotDeviceAllotLogMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.iotdevicepersonlog.IotDevicePersonLogMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.iotdevicerunlog.IotDeviceRunLogMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.iotdevicestatuslog.IotDeviceStatusLogMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.iotmodel.IotModelMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.iotopeationfill.IotOpeationFillMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.tdparams.IotTdParamsMapper;
import cn.iocoder.yudao.module.pms.service.iotbom.IotBomService;
import cn.iocoder.yudao.module.pms.service.iotdevicebom.IotDeviceBomService;
import cn.iocoder.yudao.module.pms.service.iotdevicematerial.IotDeviceMaterialService;
import cn.iocoder.yudao.module.pms.service.iotdeviceperson.IotDevicePersonService;
import cn.iocoder.yudao.module.pms.service.iotdevicerunlog.IotDeviceRunLogService;
import cn.iocoder.yudao.module.pms.service.iotmodeltemplateattrs.IotModelTemplateAttrsService;
import cn.iocoder.yudao.module.pms.service.yanfan.ThingsModelService;
import cn.iocoder.yudao.module.pms.service.yanfan.YfDeviceService;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.dict.DictDataService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.xingyuv.captcha.util.StringUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.*;

/**
 * 设备台账 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class IotDeviceServiceImpl implements IotDeviceService {

    @Resource
    private IotDeviceMapper iotDeviceMapper;
    @Resource
    private IotInfoClassifyMapper iotInfoClassifyMapper;
    @Resource
    private IotTreeMapper iotTreeMapper;
    @Resource
    private DeptService deptService;
    @Resource
    private IotModelMapper iotModelMapper;
    @Resource
    private DictDataService dictDataService;
    @Resource
    private YfDeviceService yfDeviceService;
    @Autowired
    private ThingsModelService thingsModelService;
    @Autowired
    private TDDeviceMapper deviceMapper;
    @Autowired
    private IotBomService iotBomService;
    @Resource
    private RestTemplate restTemplate;
    @Value("${yanfan.url}")
    private String yanfanUrl;
    @Autowired
    private IotDeviceBomService iotDeviceBomService;
    @Resource
    private IotModelTemplateAttrsService iotModelTemplateAttrsService;
    @Resource
    private IotDeviceRunLogService iotDeviceRunLogService;
    @Resource
    private IotDeviceRunLogMapper iotDeviceRunLogMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private AdminUserService adminUserService;
    @Autowired
    private AdminUserApi adminUserApi;
    @Autowired
    private IotDevicePersonService iotDevicePersonService;
    @Autowired
    private IotDeviceMaterialService iotDeviceMaterialService;
    @Autowired
    private IotOpeationFillMapper zhbdmapper;
    private final static String parameter = "lng~~经度,lat~~纬度,today_distance~~当日里程,distance~~总里程,todayoil~~当日油量,totaloil~~总油量,online~~是否在线,oil1~~1路油量,oil2~~2路油量,oil3~~3路油量,oil4~~4路油量,vehicle_name~~车牌号码";
    @Autowired
    private DeptApi deptApi;
    @Autowired
    private IotTdParamsMapper iotTdParamsMapper;

    @Autowired
    private IotDeviceAllotLogMapper iotDeviceAllotLogMapper;
    @Autowired
    private IotDevicePersonLogMapper iotDevicePersonLogMapper;
    @Autowired
    private IotDeviceStatusLogMapper iotDeviceStatusLogMapper;


    @Override
    public String getDeviceCompany(Long id) {
        List<DeptRespDTO> rhdept = deptApi.getDeptByNamePermission("瑞恒兴域");
        Set<Long> rhDeptIds = Collections.emptySet();
        if (CollUtil.isNotEmpty(rhdept)) {
            Long deptId = rhdept.get(0).getId();
            rhDeptIds = deptService.getChildDeptIdListFromCache(deptId);
            rhDeptIds.add(deptId);
        }

        List<DeptRespDTO> rddept = deptApi.getDeptByNamePermission("四川瑞都");
        Set<Long> rdDeptIds = Collections.emptySet();
        if (CollUtil.isNotEmpty(rddept)) {
            Long deptId = rddept.get(0).getId();
            rdDeptIds = deptService.getChildDeptIdListFromCache(deptId);
            rdDeptIds.add(deptId);
        }

        List<DeptRespDTO> rydept = deptApi.getDeptByNamePermission("瑞鹰国际");
        Set<Long> ryDeptIds;
        if (CollUtil.isNotEmpty(rydept)) {
            Long deptId = rydept.get(0).getId();
            ryDeptIds = deptService.getChildDeptIdListFromCache(deptId);
            ryDeptIds.add(deptId);
        }

        IotDeviceDO iotDeviceDO = iotDeviceMapper.selectById(id);
        Long deviceDept = iotDeviceDO.getDeptId();
        if (rhDeptIds.contains(deviceDept)) {
            return "rh";
        } else if (rdDeptIds.contains(deviceDept)) {
            return "rd";
        } else {
            return "ry";
        }
    }

    @Override
    public String getMaxCode(String prefix) {
        IotDevicePageReqVO iotDevicePageReqVO = new IotDevicePageReqVO();
        iotDevicePageReqVO.setYfDeviceCode(prefix);
        List<IotDeviceDO> iotDeviceDOS = iotDeviceMapper.selectList(iotDevicePageReqVO);
        if (iotDeviceDOS == null || iotDeviceDOS.isEmpty()) {
            return "001"; // 列表为空时默认从001开始
        }
        Pattern CODE_PATTERN = Pattern.compile(prefix + "(\\d{3})");
        // 提取所有符合格式的编码的最后三位数字
        List<Integer> suffixNumbers = iotDeviceDOS.stream()
                .map(code -> {
                    Matcher matcher = CODE_PATTERN.matcher(code.getYfDeviceCode());
                    if (matcher.matches()) {
                        try {
                            return Integer.parseInt(matcher.group(1));
                        } catch (NumberFormatException e) {
                            return null; // 忽略格式错误的编码
                        }
                    }
                    return null; // 忽略不符合格式的编码
                })
                .filter(num -> num != null) // 过滤掉空值
                .collect(Collectors.toList());

        // 找到最大的数字
        Integer maxNum = suffixNumbers.stream()
                .mapToInt(Integer::intValue)
                .max()
                .orElse(-1); // 如果没有符合条件的编码，使用-1

        // 计算下一个数字并格式化为三位数字
        int nextNum = maxNum + 1;
        return String.format("%03d", nextNum);
    }

    @Override
    public void templateChange(String categoryId, List<IotDeviceProperty> properties) {
        List<IotDeviceDO> iotDeviceDOS = iotDeviceMapper.selectList("asset_class", categoryId);
        List<IotDeviceDO> collect = iotDeviceDOS.stream().filter(e -> !"".equals(e.getTemplateJson()) && Objects.nonNull(e.getTemplateJson()) && !"[]".equals(e.getTemplateJson())).collect(Collectors.toList());
        List<String> codes = properties.stream().map(IotDeviceProperty::getCode).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(collect)){
            List<IotDeviceProperty> properties1 = JSON.parseArray(collect.get(0).getTemplateJson(), IotDeviceProperty.class);
            List<String> devicePropertyCodes = properties1.stream().map(IotDeviceProperty::getCode).collect(Collectors.toList());
            List<String> needAdd = BeanUtils.getElementsOnlyInFirstList(codes, devicePropertyCodes);
            List<String> needDelete = BeanUtils.getElementsOnlyInFirstList(devicePropertyCodes, codes);
            collect.forEach(device ->{
                List<IotDeviceProperty> deviceProperties = JSON.parseArray(device.getTemplateJson(), IotDeviceProperty.class);
                deviceProperties.removeIf(item -> needDelete.contains(item.getCode()));
                properties.forEach(property -> {
                    if (needAdd.contains(property.getCode())) {
                        deviceProperties.add(property);
                    }
                });
                device.setTemplateJson(JSON.toJSONString(deviceProperties));
                iotDeviceMapper.updateById(device);

            });
        }
    }

    @Override
    public void importDevice(List<DeviceImportExcelVO> list) {
        List<IotDeviceDO> iotDeviceDOS = iotDeviceMapper.selectList();
        for (DeviceImportExcelVO deviceImportExcelVO : list) {
            iotDeviceDOS.stream().filter(e -> e.getDeviceCode().equals(deviceImportExcelVO.getDeviceCode())).forEach(f ->{
//                f.setEnableDate(deviceImportExcelVO.getEnableDate());
//                f.setAssetOwnership(deviceImportExcelVO.getAssetOwnership());
//                f.setUseProject(deviceImportExcelVO.getUseProject());
                if (Objects.nonNull(deviceImportExcelVO.getYfDeviceCode())&&StringUtils.isNotBlank(deviceImportExcelVO.getYfDeviceCode())) {
                    String de = org.apache.commons.lang3.StringUtils.substring(deviceImportExcelVO.getYfDeviceCode(), 0,2);
                    String ee = org.apache.commons.lang3.StringUtils.substring(deviceImportExcelVO.getYfDeviceCode(), 2,4);
                    String ff = org.apache.commons.lang3.StringUtils.substring(deviceImportExcelVO.getYfDeviceCode(), 4,7);
                    f.setYfClass(de+","+ee+","+ff);
                    f.setYfDeviceCode(deviceImportExcelVO.getYfDeviceCode());
                    iotDeviceMapper.updateById(f);
                }
            });
        }
    }

    @Override
    public List<IotDeviceDO> getMapDevice(IotDevicePageReqVO reqVO) {
        Long deptId = reqVO.getDeptId();
        if (Objects.nonNull(deptId)) {
            List<Long> collect = deptApi.getChildDeptList(deptId).stream().map(DeptRespDTO::getId).collect(Collectors.toList());
            collect.add(deptId);
            reqVO.setDeptId(null);
            reqVO.setDeptIds(collect);
        }
        return iotDeviceMapper.selectDataCollect(reqVO);
    }

    public void init() {
        Map<String, String> abc=new HashMap<>();
        abc.put("id","123");
        Map<String, String> abcMap = new HashMap<>();
        abcMap.put("abc", JSON.toJSONString(abc));
        abcMap.put("def",JSON.toJSONString(abc));
        redisTemplate.opsForHash().putAll("TSLV:123_YF214",abcMap);
        Object o = redisTemplate.opsForHash().get("TSLV:123_YF214", "abc");
        System.out.println("333");
    }

    @Override
    public List<ThingsModelDTO> getTdParams(IotDeviceDO iotDeviceDO) {
        List<IotTdParamsDO> paramsDOS1 = iotTdParamsMapper.selectList("device_id", iotDeviceDO.getId());
        TableDataInfo tableDataInfo = restTemplate.getForObject(yanfanUrl + "/prod-api/iot/device/listThingsModel?deviceId="+iotDeviceDO.getYfDeviceId()+"&pageNum=1&pageSize=200", TableDataInfo.class);
        if (tableDataInfo == null) {
            return new ArrayList<>();
        }
        List<ThingsModelDTO> rows = JSON.parseArray(JSON.toJSONString(tableDataInfo.getRows()), ThingsModelDTO.class);
        rows.forEach(e ->{
            IotTdParamsDO paramsDO = paramsDOS1.stream().filter(f -> f.getIdentifier().equals(e.getIdentifier())).findFirst().orElse(null);
            if (Objects.nonNull(paramsDO)) {
                if ("alarm".equals(paramsDO.getIfAlarm())) {
                    e.setIfAlarm("alarm");
                }
            }
        });
        LinkedList<String> zhbds = new LinkedList<>();
        String[] split1 = parameter.split(",");
        Arrays.stream(split1).collect(Collectors.toList()).forEach(e ->{
            String[] split = e.split("~~");
            zhbds.add(split[0]);
        });
        List<String> identifiers = rows.stream().map(ThingsModelDTO::getIdentifier).collect(Collectors.toList());
        //有数采
        List<String> carCodes = zhbdmapper.carList().stream().map(DeviceZHBDDO::getDeviceCode).collect(Collectors.toList());
        if (carCodes.contains(iotDeviceDO.getDeviceCode())) {
            for (String s : split1) {
                String[] split = s.split("~~");
//                if (!identifiers.contains(zhbds.get(2))||!identifiers.contains(zhbds.get(4))){
                    Object o = redisTemplate.opsForHash().get("TSLV:" + iotDeviceDO.getDeviceCode(), split[0]);
                    if (Objects.nonNull(o)) {
                        JSONObject jsonObject = JSON.parseObject(o.toString());
                        ThingsModelDTO modelDTO = new ThingsModelDTO();
                        modelDTO.setIdentifier(split[0]);
                        modelDTO.setModelName(split[1]);
                        if ("online".equals(split[0])){
                            String value = String.valueOf(jsonObject.get("value"));
                            modelDTO.setValue("true".equals(value)?"是":"否");
                        } else {
                            String value = String.valueOf(jsonObject.get("value"));
                            modelDTO.setValue(value);
                        }
                        rows.add(modelDTO);
                    }
//                }
            }
        } else {
            rows.forEach(e ->{
                //如果在中行北斗的话取redis
                if (zhbds.contains(e.getIdentifier())) {
                    Object o = redisTemplate.opsForHash().get("TSLV:" + iotDeviceDO.getDeviceCode(), e.getIdentifier());
                    if (Objects.nonNull(o)) {
                        JSONObject jsonObject = JSON.parseObject(o.toString());
                        if ("online".equals(e.getIdentifier())){
                            String value = String.valueOf(jsonObject.get("value"));
                            e.setValue("true".equals(value)?"是":"否");
                        } else {
                            String value = String.valueOf(jsonObject.get("value"));
                            e.setValue(value);
                        }

                    }
                }

            });
        }
        List<ThingsModelDTO> collect = rows.stream().filter(e -> !"lac".equals(e.getIdentifier()) && !"cell_id".equals(e.getIdentifier()) && !"mcc_mnc".equals(e.getIdentifier())).sorted(Comparator.comparing(ThingsModelDTO::getIdentifier)).collect(Collectors.toList());
        CompletableFuture.runAsync(()->{
            collect.forEach(thingsModelDTO -> {
                List<IotTdParamsDO> paramsDOS = iotTdParamsMapper.selectByMap(ImmutableMap.of("device_id", iotDeviceDO.getId(), "identifier", thingsModelDTO.getIdentifier()));
                if (CollUtil.isEmpty(paramsDOS)) {
                    IotTdParamsDO iotTdParamsDO = new IotTdParamsDO();
                    iotTdParamsDO.setDeviceId(iotDeviceDO.getId());
                    iotTdParamsDO.setDeviceCode(iotDeviceDO.getDeviceCode());
                    iotTdParamsDO.setDeviceName(iotDeviceDO.getDeviceName());
                    iotTdParamsDO.setYfCode(iotDeviceDO.getYfDeviceCode());
                    iotTdParamsDO.setIdentifier(thingsModelDTO.getIdentifier());
                    iotTdParamsDO.setModelName(thingsModelDTO.getModelName());
                    iotTdParamsDO.setModelOrder(Long.valueOf(thingsModelDTO.getModelOrder()));
                    iotTdParamsDO.setDeleted(false);
                    iotTdParamsMapper.insert(iotTdParamsDO);
                }
            });
        });
        return collect;
    }

    @Override
    public List<ThingsModelDTO> getTdGatewayParams(IotDeviceDO iotDeviceDO) {
        List<IotTdParamsDO> paramsDOS1 = iotTdParamsMapper.selectList("device_id", iotDeviceDO.getId());
        TableDataInfo tableDataInfo = restTemplate.getForObject(yanfanUrl + "/prod-api/iot/device/listThingsModel?deviceId="+iotDeviceDO.getYfDeviceId()+"&pageNum=1&pageSize=200", TableDataInfo.class);
        if (tableDataInfo == null) {
            return new ArrayList<>();
        }
        List<ThingsModelDTO> rows = JSON.parseArray(JSON.toJSONString(tableDataInfo.getRows()), ThingsModelDTO.class);
        if (CollUtil.isEmpty(rows)) {
            return new ArrayList<>();
        }
        rows.forEach(e ->{
            IotTdParamsDO paramsDO = paramsDOS1.stream().filter(f -> f.getIdentifier().equals(e.getIdentifier())).findFirst().orElse(null);
            if (Objects.nonNull(paramsDO)) {
                if ("alarm".equals(paramsDO.getIfAlarm())) {
                    e.setIfAlarm("alarm");
                }
            }
        });
        List<ThingsModelDTO> collect = rows.stream().filter(e -> !"lac".equals(e.getIdentifier()) && !"cell_id".equals(e.getIdentifier()) && !"mcc_mnc".equals(e.getIdentifier())).sorted(Comparator.comparing(ThingsModelDTO::getIdentifier)).collect(Collectors.toList());
        CompletableFuture.runAsync(()->{
            collect.forEach(thingsModelDTO -> {
                List<IotTdParamsDO> paramsDOS = iotTdParamsMapper.selectByMap(ImmutableMap.of("device_id", iotDeviceDO.getId(), "identifier", thingsModelDTO.getIdentifier()));
                if (CollUtil.isEmpty(paramsDOS)) {
                    IotTdParamsDO iotTdParamsDO = new IotTdParamsDO();
                    iotTdParamsDO.setDeviceId(iotDeviceDO.getId());
                    iotTdParamsDO.setDeviceCode(iotDeviceDO.getDeviceCode());
                    iotTdParamsDO.setDeviceName(iotDeviceDO.getDeviceName());
                    iotTdParamsDO.setYfCode(iotDeviceDO.getYfDeviceCode());
                    iotTdParamsDO.setIdentifier(thingsModelDTO.getIdentifier());
                    iotTdParamsDO.setModelName(thingsModelDTO.getModelName());
                    iotTdParamsDO.setModelOrder(Long.valueOf(thingsModelDTO.getModelOrder()));
                    iotTdParamsDO.setDeleted(false);
                    iotTdParamsMapper.insert(iotTdParamsDO);
                }
            });
        });
        return collect;
    }

    @Override
    public List<ThingsModelDTO> getTdZhbdParams(IotDeviceDO iotDeviceDO) {
//        List<IotTdParamsDO> paramsDOS1 = iotTdParamsMapper.selectList("device_id", iotDeviceDO.getId());
//        TableDataInfo tableDataInfo = restTemplate.getForObject(yanfanUrl + "/prod-api/iot/device/listThingsModel?deviceId="+iotDeviceDO.getYfDeviceId()+"&pageNum=1&pageSize=200", TableDataInfo.class);
//        if (tableDataInfo == null) {
//            return new ArrayList<>();
//        }
//        List<ThingsModelDTO> rows = JSON.parseArray(JSON.toJSONString(tableDataInfo.getRows()), ThingsModelDTO.class);
        List<ThingsModelDTO> rows = new ArrayList<>();
//        rows.forEach(e ->{
//            IotTdParamsDO paramsDO = paramsDOS1.stream().filter(f -> f.getIdentifier().equals(e.getIdentifier())).findFirst().orElse(null);
//            if (Objects.nonNull(paramsDO)) {
//                if ("alarm".equals(paramsDO.getIfAlarm())) {
//                    e.setIfAlarm("alarm");
//                }
//            }
//        });
        LinkedList<String> zhbds = new LinkedList<>();
        String[] split1 = parameter.split(",");
        Arrays.stream(split1).collect(Collectors.toList()).forEach(e ->{
            String[] split = e.split("~~");
            zhbds.add(split[0]);
        });
//        List<String> identifiers = rows.stream().map(ThingsModelDTO::getIdentifier).collect(Collectors.toList());
        //有数采
        List<String> carCodes = zhbdmapper.carList().stream().map(DeviceZHBDDO::getDeviceCode).collect(Collectors.toList());
//        if (carCodes.contains(iotDeviceDO.getDeviceCode())) {
            for (String s : split1) {
                String[] split = s.split("~~");
//                if (!identifiers.contains(zhbds.get(2))||!identifiers.contains(zhbds.get(4))){
                Object o = redisTemplate.opsForHash().get("TSLV:" + iotDeviceDO.getDeviceCode(), split[0]);
                if (Objects.nonNull(o)) {
                    JSONObject jsonObject = JSON.parseObject(o.toString());
                    ThingsModelDTO modelDTO = new ThingsModelDTO();
                    modelDTO.setIdentifier(split[0]);
                    modelDTO.setModelName(split[1]);
                    if ("online".equals(split[0])){
                        String value = String.valueOf(jsonObject.get("value"));
                        modelDTO.setValue("true".equals(value)?"是":"否");
                    } else {
                        String value = String.valueOf(jsonObject.get("value"));
                        modelDTO.setValue(value);
                    }
                    rows.add(modelDTO);
                }
//                }
            }
//        } else {
//            rows.forEach(e ->{
//                //如果在中行北斗的话取redis
//                if (zhbds.contains(e.getIdentifier())) {
//                    Object o = redisTemplate.opsForHash().get("TSLV:" + iotDeviceDO.getDeviceCode(), e.getIdentifier());
//                    if (Objects.nonNull(o)) {
//                        JSONObject jsonObject = JSON.parseObject(o.toString());
//                        if ("online".equals(e.getIdentifier())){
//                            String value = String.valueOf(jsonObject.get("value"));
//                            e.setValue("true".equals(value)?"是":"否");
//                        } else {
//                            String value = String.valueOf(jsonObject.get("value"));
//                            e.setValue(value);
//                        }
//
//                    }
//                }
//
//            });
//        }
        List<ThingsModelDTO> collect = rows.stream().filter(e -> !"lac".equals(e.getIdentifier()) && !"cell_id".equals(e.getIdentifier()) && !"mcc_mnc".equals(e.getIdentifier())).sorted(Comparator.comparing(ThingsModelDTO::getIdentifier)).collect(Collectors.toList());
        CompletableFuture.runAsync(()->{
            collect.forEach(thingsModelDTO -> {
                List<IotTdParamsDO> paramsDOS = iotTdParamsMapper.selectByMap(ImmutableMap.of("device_id", iotDeviceDO.getId(), "identifier", thingsModelDTO.getIdentifier()));
                if (CollUtil.isEmpty(paramsDOS)) {
                    IotTdParamsDO iotTdParamsDO = new IotTdParamsDO();
                    iotTdParamsDO.setDeviceId(iotDeviceDO.getId());
                    iotTdParamsDO.setDeviceCode(iotDeviceDO.getDeviceCode());
                    iotTdParamsDO.setDeviceName(iotDeviceDO.getDeviceName());
                    iotTdParamsDO.setYfCode(iotDeviceDO.getYfDeviceCode());
                    iotTdParamsDO.setIdentifier(thingsModelDTO.getIdentifier());
                    iotTdParamsDO.setModelName(thingsModelDTO.getModelName());
                    iotTdParamsDO.setModelOrder(Long.valueOf(thingsModelDTO.getModelOrder()));
                    iotTdParamsDO.setDeleted(false);
                    iotTdParamsMapper.insert(iotTdParamsDO);
                }
            });
        });
        return collect;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createIotDevice(IotDeviceSaveReqVO createReqVO) {
        //校验资产编号
        List<IotDeviceDO> iotDeviceDOS = iotDeviceMapper.selectList("device_code", createReqVO.getDeviceCode());
        if (CollUtil.isNotEmpty(iotDeviceDOS)) {
            throw new ServiceException(IOT_DEVICE_EXISTED);
        }
        List<IotDeviceDO> iotDeviceDOSS = iotDeviceMapper.selectList("yf_device_code", createReqVO.getYfDeviceCode());
        if (CollUtil.isNotEmpty(iotDeviceDOSS)) {
            throw new ServiceException(IOT_DEVICE_EXISTED);
        }
        // 插入
        IotDeviceDO iotDevice = BeanUtils.toBean(createReqVO, IotDeviceDO.class);
        iotDevice.setSortColumn(NumberUtils.extractNumber(iotDevice.getDeviceCode()));
        iotDevice.setDeleted(false);
        if (Objects.nonNull(createReqVO.getBrand())) {
            DictDataDO dictData = dictDataService.getDictData(createReqVO.getBrand());
            if (Objects.nonNull(dictData)) {
                iotDevice.setBrandName(dictData.getLabel());
            }
        }
        iotDeviceMapper.insert(iotDevice);
        //插入资料
        IotInfoClassifyDO infoClassifyDO = new IotInfoClassifyDO();
        infoClassifyDO.setName(iotDevice.getDeviceName()+"设备资料");
        infoClassifyDO.setStatus(0);
        infoClassifyDO.setParentId(0L);
        infoClassifyDO.setDeviceId(iotDevice.getId());
        iotInfoClassifyMapper.insert(infoClassifyDO);
        //插入pms树
        IotTreeDO iotTreeDO = new IotTreeDO();
        iotTreeDO.setType("device");
        iotTreeDO.setOriginId(iotDevice.getId());
        iotTreeDO.setName(StringUtils.isNotBlank(iotDevice.getYfDeviceCode())?iotDevice.getYfDeviceCode()+iotDevice.getDeviceName():iotDevice.getDeviceCode()+iotDevice.getDeviceName());
        iotTreeDO.setDeptId(iotDevice.getDeptId());
        List<IotTreeDO> iotTreeDOS = iotTreeMapper.selectListByOriginId(iotDevice.getDeptId(),"dept");
        if (CollUtil.isNotEmpty(iotTreeDOS)) {
            iotTreeDO.setParentId(Objects.nonNull(iotTreeDOS.get(0)) ? iotTreeDOS.get(0).getId() : 0);
            iotTreeMapper.insert(iotTreeDO);
        }
        //维护品牌
        if(Objects.nonNull(createReqVO.getModel())) {
            List<IotModelDO> iotModelDOS = iotModelMapper.selectByMap(ImmutableMap.of("brand", createReqVO.getBrand(), "name", createReqVO.getModel()));
            if (CollUtil.isEmpty(iotModelDOS)) {
                IotModelDO iotModelDO = new IotModelDO();
                iotModelDO.setBrand(createReqVO.getBrand());
                DictDataDO dictData = dictDataService.getDictData(createReqVO.getBrand());
                iotModelDO.setBrandName(Objects.nonNull(dictData)?dictData.getLabel():"");
                iotModelDO.setName(createReqVO.getModel());
                iotModelDO.setStatus(CommonStatusEnum.ENABLE.getStatus());
                iotModelMapper.insert(iotModelDO);
            }
        }
        // 同步设备分类bom
        iotBomService.copyBomByCategory(iotDevice.getAssetClass(), iotDevice.getId());
        // 返回
        return iotDevice.getId();
    }

    @Override
    public void updateIotDevice(IotDeviceSaveReqVO updateReqVO) {
        // 校验存在
        validateIotDeviceExists(updateReqVO.getId());
        // 更新
        IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class);
        if (Objects.nonNull(updateReqVO.getBrand())) {
            DictDataDO dictData = dictDataService.getDictData(updateReqVO.getBrand());
            if (Objects.nonNull(dictData)) {
                updateObj.setBrandName(dictData.getLabel());
            }
        }
        iotDeviceMapper.updateById(updateObj);
        //更新pms树
        List<IotTreeDO> iotTreeDOS = iotTreeMapper.selectListByOriginId(updateObj.getId(), "device");
        if (CollectionUtils.isEmpty(iotTreeDOS)) {
            throw new ServiceException(ErrorCodeConstants.DEPT_NOT_FOUND.getCode(),"无资料库信息");
        }
        IotTreeDO iotTreeDO = iotTreeDOS.get(0);
        iotTreeDO.setName(StringUtils.isNotBlank(updateObj.getYfDeviceCode())?updateObj.getYfDeviceCode()+updateObj.getDeviceName():updateObj.getDeviceCode() +updateObj.getDeviceName());
        iotTreeDO.setDeptId(updateObj.getDeptId());
        iotTreeMapper.updateById(iotTreeDO);
    }

    @Override
    public void deleteIotDevice(Long id) {
        // 校验存在
        validateIotDeviceExists(id);
        // 删除
        iotDeviceMapper.deleteById(id);
        //删除pms树
        iotTreeMapper.deleteByMap(ImmutableMap.of("origin_id", id));
    }

    private void validateIotDeviceExists(Long id) {
        if (iotDeviceMapper.selectById(id) == null) {
            throw exception(IOT_DEVICE_NOT_EXISTS);
        }
    }

    @Override
    public IotDeviceDO getIotDevice(Long id) {
        return iotDeviceMapper.selectById(id);
    }

    @Override
    public PageResult<IotDeviceDO> getIotDevicePage(IotDevicePageReqVO pageReqVO, SortablePageParam sortablePageParam) {
        PageUtils.buildDefaultSortingField(sortablePageParam, IotDeviceDO::getSortColumn);
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
        }

        return iotDeviceMapper.selectPage(pageReqVO,ids, sortablePageParam);
    }

    @Override
    public PageResult<IotDeviceDO> getIotDevicePageApp(IotDevicePageReqVO pageReqVO, SortablePageParam sortablePageParam) {
        PageUtils.buildDefaultSortingField(sortablePageParam, IotDeviceDO::getSortColumn);
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
        }
        if (StringUtils.isNotBlank(pageReqVO.getCommonParam())) {
            List<DeptRespDTO> deptByName = deptApi.getDeptByName(pageReqVO.getCommonParam());
            if (CollUtil.isNotEmpty(deptByName)) {
                pageReqVO.setDeptId(deptByName.get(0).getId());
            }
        }

        return iotDeviceMapper.selectPageApp(pageReqVO,ids, sortablePageParam);
    }

    @Override
    public void updateSort() {
        List<IotDeviceDO> deviceDOS = iotDeviceMapper.selectList();
        deviceDOS.forEach(deviceDO -> {
            deviceDO.setSortColumn(NumberUtils.extractNumber(deviceDO.getDeviceCode()));
            iotDeviceMapper.updateById(deviceDO);
        });
    }

    @Override
    public void updateBrandName() {
        List<IotDeviceDO> deviceDOS = iotDeviceMapper.selectList();
        deviceDOS.forEach(deviceDO -> {
            DictDataDO dictData = dictDataService.getDictData(deviceDO.getBrand());
            if (Objects.nonNull(dictData)) {
                deviceDO.setBrandName(dictData.getLabel());
            }
            iotDeviceMapper.updateById(deviceDO);
        });
    }

    @Override
    public void updateCharge() {
        List<IotDeviceDO> deviceDOS = iotDeviceMapper.selectList();
        deviceDOS.forEach(deviceDO -> {
            Map<Long, String> iotDevicePerson = iotDevicePersonService.getIotDevicePerson(ImmutableList.of(deviceDO.getId()));
            if (Objects.nonNull(iotDevicePerson)) {
                deviceDO.setChargeName(iotDevicePerson.get(deviceDO.getId()));
            }
            iotDeviceMapper.updateById(deviceDO);
        });
    }

    @Override
    public List<IotDeviceDO> getSimpleDeviceList(IotDevicePageReqVO reqVO) {
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(reqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(reqVO.getDeptId());
            ids.add(reqVO.getDeptId());
        }
        return iotDeviceMapper.selectSimpleList(reqVO, ids);
    }

    @Override
    public List<IotDeviceDO> getDevicesByDepts(IotDevicePageReqVO reqVO) {
        if (ObjUtil.isEmpty(reqVO)) {
            throw new ServiceException(IOT_DEPT_NOT_SELECTED);
        }
        // 如果 reqVO.getDeptIds 有值 就是根据选择的部门 查询部门下所有设备
        // 考虑到设备调拨的情况 可以修改 成查询所选部门所属公司下所有设备
        if (CollUtil.isEmpty(reqVO.getDeviceIds()) && CollUtil.isEmpty(reqVO.getDeptIds())) {
            throw new ServiceException(IOT_DEPT_NOT_SELECTED);
        }
        // 需要查询的公司id
        Long deptId = reqVO.getDeptId();
        List<IotDeviceDO> rdDevices = new ArrayList<>();
        if (CollUtil.isNotEmpty(reqVO.getDeptIds()) && ObjUtil.isNotEmpty(deptId)) {
            // 查询选择的部门 选择的部门所属的公司 属于 瑞都 or 5#国 则查询所有 瑞都 or 5#国 下的设备
            // 但是 所选队伍 下的所有设备 需要显示在列表最上面
            List<Long> deptIds = reqVO.getDeptIds();
            Long randomDeptId = deptIds.get(0);
            Set<Long> childDeptIds = new HashSet<>();
            // 查询 瑞都下的所有 部门
            if (deptId == 163l || deptId == 388l) {
                Set<Long> tempChildDeptIds = deptService.getChildDeptIdListFromCache(deptId);
                tempChildDeptIds.add(deptId);
                childDeptIds.addAll(tempChildDeptIds);
            }
            if (childDeptIds.contains(randomDeptId)) {
                // 施工队伍 属于 瑞都 or 5#国  则查询 瑞都 or 5#国 的设备
                reqVO.setDeptIds(new ArrayList<>(childDeptIds));
                // 查询所选施工队伍下所有设备
                IotDevicePageReqVO rdReqVO = new IotDevicePageReqVO();
                rdReqVO.setDeptIds(deptIds);
                rdDevices = iotDeviceMapper.selectSimpleList(rdReqVO, null);
            }
        }
        AtomicReference<List<IotDeviceDO>> devices = new AtomicReference<>(new ArrayList<>());
        // 忽略数据权限
        List<IotDeviceDO> finalRdDevices = rdDevices;
        DataPermissionUtils.executeIgnore(() -> {
            List<IotDeviceDO> resultDevices = iotDeviceMapper.selectSimpleList(reqVO, null);
            devices.set(resultDevices);
            // 如果瑞都日报任务 将施工队伍所属设备显示到设备列表前面
            if (CollUtil.isNotEmpty(resultDevices) && CollUtil.isNotEmpty(finalRdDevices)) {
                // 提取 finalRdDevices 的id集合（快速判断）
                Set<Long> rdDeviceIds = finalRdDevices.stream()
                        .map(IotDeviceDO::getId)
                        .collect(Collectors.toSet());

                // 排序：finalRdDevices 中的元素排前面，保持原有相对顺序
                resultDevices.sort(Comparator.comparingInt(u -> rdDeviceIds.contains(u.getId()) ? 0 : 1));

                // 更新结果集
                devices.set(resultDevices);
            }
        });
        return devices.get();
    }

    @Override
    public PageResult<IotDeviceDO> getIotDeviceTdPage(IotDevicePageReqVO pageReqVO, List<String> codes) {
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
        }

        if ("gateway".equals(pageReqVO.getSource())) {
            return iotDeviceMapper.selectTdPage(pageReqVO,ids,codes);
        } else if ("zhbd".equals(pageReqVO.getSource())) {
            return iotDeviceMapper.selectZhbdTdPage(pageReqVO,ids,codes);
        } else {
            return iotDeviceMapper.selectAllTdPage(pageReqVO,ids,codes);
        }
    }

    @Override
    public PageResult<IotDeviceDO> getIotDeviceTdPageApp(IotDevicePageReqVO pageReqVO, List<String> codes) {
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
        }
        return iotDeviceMapper.selectTdPageApp(pageReqVO,ids);
    }

    /* @Override
    public PageResult<IotDeviceDO> deviceAssociateBomPage(IotDevicePageReqVO pageReqVO) {
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
        }

        return iotDeviceMapper.deviceAssociateBomPage(pageReqVO,ids);
    } */

    @Override
    public PageResult<IotDeviceRespVO> deviceAssociateBomPage(IotDevicePageReqVO pageReqVO) {
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
        }
        try {
            IPage<IotDeviceRespVO> page = iotDeviceMapper.deviceAssociateBomPage(
                    new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO, ids);
            return new PageResult<>(page.getRecords(), page.getTotal());
        } catch (Exception exception) {
            if (exception.getMessage().contains("Table does not exist")) {
                return PageResult.empty();
            }
            throw exception;
        }
    }

    @Override
    public PageResult<IotDeviceRespVO> personRelationDevices(IotDevicePageReqVO pageReqVO) {
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
        }
        // 调拨时间区间搜索 查询在指定时间区间内调拨过的设备
        LocalDateTime[] allotDateTime = pageReqVO.getCreateTime();
        Set<Long> timeDeviceIds = new HashSet<>();
        if (ObjUtil.isNotEmpty(allotDateTime)) {
            IotDevicePersonLogPageReqVO reqVO = new IotDevicePersonLogPageReqVO();
            reqVO.setCreateTime(allotDateTime);
            List<IotDevicePersonLogDO> deviceAllots = iotDevicePersonLogMapper.selectList(reqVO);
            if (CollUtil.isNotEmpty(deviceAllots)) {
                deviceAllots.forEach(allot -> {
                    timeDeviceIds.add(allot.getDeviceId());
                });
                if (CollUtil.isNotEmpty(timeDeviceIds)) {
                    pageReqVO.setDeviceIds(new ArrayList<>(timeDeviceIds));
                }
            } else {
                return PageResult.empty();
            }
        }
        // 根据用户昵称模糊搜索 已经设置过此人作为责任人的设备列表
        Set<Long> deviceIds = new HashSet<>();
        if (StrUtil.isNotBlank(pageReqVO.getNickname())) {
            Set<Long> userIds = new HashSet<>();
            List<AdminUserDO> users = adminUserService.getUserListByNickname(pageReqVO.getNickname());
            List<AdminUserRespDTO> partUsers = adminUserApi.getUserListByUsername(pageReqVO.getNickname());
            if (CollUtil.isNotEmpty(partUsers)) {
                partUsers.forEach(user -> {
                    userIds.add(user.getId());
                });
            }
            if (CollUtil.isNotEmpty(users)) {
                users.forEach(user -> {
                    userIds.add(user.getId());
                });
            }
            if (CollUtil.isNotEmpty(userIds)) {
                // 根据用户id列表查询与用户关联责任人的设备列表
                IotDevicePersonPageReqVO reqVO = new IotDevicePersonPageReqVO();
                reqVO.setPersonIds(userIds);
                List<IotDevicePersonDO> devicePersons = iotDevicePersonService.getByPersonIds(reqVO);
                if (CollUtil.isNotEmpty(devicePersons)) {
                    devicePersons.forEach(devicePerson -> {
                        deviceIds.add(devicePerson.getDeviceId());
                    });
                }
            }
            // 如果 deviceIds 集合为空 说明当前搜索的用户没有关联任何设备
            if (CollUtil.isEmpty(deviceIds)) {
                return PageResult.empty();
            }
        }
        try {
            IPage<IotDeviceRespVO> page = iotDeviceMapper.personRelationDevices(
                    new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO, ids, deviceIds);
            return new PageResult<>(page.getRecords(), page.getTotal());
        } catch (Exception exception) {
            if (exception.getMessage().contains("Table does not exist")) {
                return PageResult.empty();
            }
            throw exception;
        }
    }

    @Override
    public PageResult<IotDeviceRespVO> statusRelationDevices(IotDevicePageReqVO pageReqVO) {
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
        }
        // 调拨时间区间搜索 查询在指定时间区间内调拨过的设备
        LocalDateTime[] allotDateTime = pageReqVO.getCreateTime();
        Set<Long> deviceIds = new HashSet<>();
        if (ObjUtil.isNotEmpty(allotDateTime)) {
            IotDeviceStatusLogPageReqVO reqVO = new IotDeviceStatusLogPageReqVO();
            reqVO.setCreateTime(allotDateTime);
            List<IotDeviceStatusLogDO> deviceAllots = iotDeviceStatusLogMapper.selectList(reqVO);
            if (CollUtil.isNotEmpty(deviceAllots)) {
                deviceAllots.forEach(allot -> {
                    deviceIds.add(allot.getDeviceId());
                });
                if (CollUtil.isNotEmpty(deviceIds)) {
                    pageReqVO.setDeviceIds(new ArrayList<>(deviceIds));
                }
            } else {
                return PageResult.empty();
            }
        }
        try {
            IPage<IotDeviceRespVO> page = iotDeviceMapper.deviceStatuses(
                    new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO, ids);
            return new PageResult<>(page.getRecords(), page.getTotal());
        } catch (Exception exception) {
            if (exception.getMessage().contains("Table does not exist")) {
                return PageResult.empty();
            }
            throw exception;
        }
    }

    @Override
    public PageResult<IotDeviceRespVO> allotRelationDevices(IotDevicePageReqVO pageReqVO) {
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
        }
        // 调拨时间区间搜索 查询在指定时间区间内调拨过的设备
        LocalDateTime[] allotDateTime = pageReqVO.getCreateTime();
        Set<Long> deviceIds = new HashSet<>();
        if (ObjUtil.isNotEmpty(allotDateTime)) {
            IotDeviceAllotLogPageReqVO reqVO = new IotDeviceAllotLogPageReqVO();
            reqVO.setCreateTime(allotDateTime);
            List<IotDeviceAllotLogDO> deviceAllots = iotDeviceAllotLogMapper.selectList(reqVO);
            if (CollUtil.isNotEmpty(deviceAllots)) {
                deviceAllots.forEach(allot -> {
                    deviceIds.add(allot.getDeviceId());
                });
                if (CollUtil.isNotEmpty(deviceIds)) {
                    pageReqVO.setDeviceIds(new ArrayList<>(deviceIds));
                }
            } else {
                return PageResult.empty();
            }
        }
        try {
            IPage<IotDeviceRespVO> page = iotDeviceMapper.deviceAllots(
                    new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO, ids);
            return new PageResult<>(page.getRecords(), page.getTotal());
        } catch (Exception exception) {
            if (exception.getMessage().contains("Table does not exist")) {
                return PageResult.empty();
            }
            throw exception;
        }
    }

    @Override
    public List<IotDeviceRespVO> deviceAssociateBomList(IotDevicePageReqVO pageReqVO) {
        List<IotDeviceRespVO> devices = iotDeviceMapper.deviceAssociateBomList(pageReqVO.getDeviceIds(), pageReqVO.getBomFlag());
        // 调整 累计运行时间 累计运行里程 的逻辑 模板属性中涉及多个累计运行时长 累计运行里程 的 这里不需要赋值
        // 查询所有设备的设备分类
        // 查询设备分类对应的运行记录模板中的多个累计类型的属性列表(匹配相应的累计运行时长 累计运行里程的值)
        Set<Long> deviceCategoryIds = new HashSet<>();
        // 设备id集合 根据设备id查询所有正常的 累计时长 累计公里数
        Set<Long> deviceIds = new HashSet<>();
        // 运行记录模板中涉及多个累计时长 公里数属性的设备id集合
        Set<Long> multipleAttrDeviceIds = new HashSet<>();
        // 运行记录模板中涉及多个累计时长 公里数属性名称集合
        Set<String> multipleAttrNames = new HashSet<>();
        // 设备对应的设备分类 key设备id   value设备分类id
        Map<Long, Long> deviceCategoryPair = new HashMap<>();
        // k设备id   v设备分类包含的模板中与累计运行时长、累计运行公里数相关的属性集合
        Map<Long, List<IotModelTemplateAttrsDO>> deviceAttrsPair = new HashMap<>();
        // k设备id   v设备分类包含的模板中与累计运行时长、累计运行公里数相关的属性(多种累计属性)集合
        Map<Long, List<IotModelTemplateAttrsDO>> deviceMultiAttrsPair = new HashMap<>();
        // 查询所有 设备boms节点的所有上级节点名称 拼接出 全路径 的bom节点
        List<Long> bomNodeIds = new ArrayList<>();
        // key设备id  value设备对应的运行记录模板中涉及多个累计时长累计公里数的属性集合
        Map<Long, List<IotDeviceRunLogRespVO>> deviceRunLogPair = new HashMap<>();
        // 设备所属部门id集合
        Set<Long> deptIds = new HashSet<>();
        // 设备运行模板中正常的 累计时长 累计里程 集合
        Map<Long, IotDeviceRunLogRespVO> deviceRunLogMap = new HashMap<>();
        if (CollUtil.isNotEmpty(devices)) {
            devices.forEach(device -> {
                deviceIds.add(device.getId());
                bomNodeIds.add(Long.valueOf(device.getBomNodeId()));
                deviceCategoryIds.add(device.getAssetClass());
                deviceCategoryPair.put(device.getId(), device.getAssetClass());
                deptIds.add(device.getDeptId());
            });

            // key设备id-bom节点id      value设备物料集合
            Map<String, List<IotDeviceMaterialRespVO>> bomMaterialsPair = iotDeviceMaterialService.bomMaterials(deptIds, deviceIds, new HashSet<>(bomNodeIds));

            if (CollUtil.isNotEmpty(deviceCategoryIds)) {
                // 查询设备分类id集合对应的运行记录模板中涉及 累计运行时长、累计运行公里数 的属性
                IotModelTemplateAttrsPageReqVO singleAttrreqVO = new IotModelTemplateAttrsPageReqVO();
                List<String> codes = new ArrayList<>(Arrays.asList("sc", "gls"));
                singleAttrreqVO.setCodes(codes);
                singleAttrreqVO.setDeviceCategoryIds(new ArrayList<>(deviceCategoryIds));
                singleAttrreqVO.setIsSum(1);  // 累计属性标识
                // 查询标识的累计类型属性 累计运行时长 累计运行公里数 正常的累计属性
                List<IotModelTemplateAttrsDO> accumulatedAttrs = iotModelTemplateAttrsService.getIotDeviceTemplateAttrs(singleAttrreqVO);
                // k设备分类id   v设备分类包含的模板中与累计运行时长 累计运行公里数相关的属性集合
                Map<Long, List<IotModelTemplateAttrsDO>> accumulatedAttrPair = new HashMap<>();
                if (CollUtil.isNotEmpty(accumulatedAttrs)) {
                    accumulatedAttrs.forEach(attr -> {
                        if (accumulatedAttrPair.containsKey(attr.getDeviceCategoryId())) {
                            List<IotModelTemplateAttrsDO> tempAttrs = accumulatedAttrPair.get(attr.getDeviceCategoryId());
                            tempAttrs.add(attr);
                            accumulatedAttrPair.put(attr.getDeviceCategoryId(), tempAttrs);
                        } else {
                            List<IotModelTemplateAttrsDO> tempAttrs = new ArrayList<>();
                            tempAttrs.add(attr);
                            accumulatedAttrPair.put(attr.getDeviceCategoryId(), tempAttrs);
                        }
                    });
                }
                if (CollUtil.isNotEmpty(accumulatedAttrPair)) {
                    accumulatedAttrPair.forEach((k,v) -> {
                        // k设备分类id   v设备分类包含的模板中与累计运行时长 累计运行公里数相关的属性集合
                        deviceCategoryPair.forEach((ik, iv) -> {
                            // ik设备id   iv设备分类id
                            if (iv.equals(k)) {
                                deviceAttrsPair.put(ik, v);
                            }
                        });
                    });
                }

                // 查询设备分类id集合对应的运行记录模板中涉及 累计运行时长、累计运行公里数 的属性
                IotModelTemplateAttrsPageReqVO reqVO = new IotModelTemplateAttrsPageReqVO();
                reqVO.setMultipleFlag("Y");
                reqVO.setDeviceCategoryIds(new ArrayList<>(deviceCategoryIds));
                reqVO.setIsSum(1);  // 累计属性标识
                List<IotModelTemplateAttrsDO> multiAccumulatedAttrs = iotModelTemplateAttrsService.getIotDeviceTemplateAttrs(reqVO);
                // k设备分类id   v设备分类包含的模板中 多个 累计运行时长 累计运行公里数相关的属性集合
                Map<Long, List<IotModelTemplateAttrsDO>> multiAccumulatedAttrPair = new HashMap<>();
                if (CollUtil.isNotEmpty(multiAccumulatedAttrs)) {
                    multiAccumulatedAttrs.forEach(attr -> {
                        if (multiAccumulatedAttrPair.containsKey(attr.getDeviceCategoryId())) {
                            List<IotModelTemplateAttrsDO> tempAttrs = multiAccumulatedAttrPair.get(attr.getDeviceCategoryId());
                            tempAttrs.add(attr);
                            multiAccumulatedAttrPair.put(attr.getDeviceCategoryId(), tempAttrs);
                        } else {
                            List<IotModelTemplateAttrsDO> tempAttrs = new ArrayList<>();
                            tempAttrs.add(attr);
                            multiAccumulatedAttrPair.put(attr.getDeviceCategoryId(), tempAttrs);
                        }
                        multipleAttrNames.add(attr.getName());
                    });
                }
                if (CollUtil.isNotEmpty(multiAccumulatedAttrPair)) {
                    multiAccumulatedAttrPair.forEach((k,v) -> {
                        // k设备分类id   v设备分类包含的模板中 多个累计运行时长 累计运行公里数 相关的属性集合
                        deviceCategoryPair.forEach((ik, iv) -> {
                            // ik设备id   iv设备分类id
                            if (iv.equals(k)) {
                                // key设备id  value设备分类包含的模板中 多个累计运行时长 累计运行公里数 相关的属性集合
                                deviceMultiAttrsPair.put(ik, v);
                                multipleAttrDeviceIds.add(ik);
                            }
                        });
                    });
                }
                // 根据设备id集合查询正常的 累计时长 累计公里数
                deviceRunLogMap = iotDeviceRunLogService.getDeviceRunLogMapAlone(new ArrayList<>(deviceIds), new ArrayList<>(deviceCategoryIds), deviceCategoryPair, null);
                // 没有产生运行记录的单累计属性 返回前端 0 deviceAttrsPair单属性属性集合
                Map<Long, IotDeviceRunLogRespVO> finalDeviceRunLogMap = deviceRunLogMap;
                if (CollUtil.isNotEmpty(deviceAttrsPair)) {
                    deviceAttrsPair.forEach((deviceId, attrs) -> {
                        if (!finalDeviceRunLogMap.containsKey(deviceId)) {
                            // 当前设备没有产生运行记录数据
                            attrs.forEach(attr -> {
                                IotDeviceRunLogRespVO runLog = new IotDeviceRunLogRespVO();
                                runLog.setTotalRunTime(BigDecimal.ZERO);
                                runLog.setTotalMileage(BigDecimal.ZERO);
                                runLog.setPointName(attr.getName());
                                finalDeviceRunLogMap.put(deviceId, runLog);
                            });
                        }
                    });
                }

                // 根据设备id 运行记录模板属性名称 查询对应的 累计运行时长 累计运行公里数
                if (CollUtil.isNotEmpty(multipleAttrDeviceIds) && CollUtil.isNotEmpty(multipleAttrNames)) {
                    // 这里只查询了存在运行记录值的属性 todo 如果还没有记录运行记录数据 也要显示出来
                    List<IotDeviceRunLogRespVO> accumulatedData = iotDeviceRunLogMapper.multipleAccumulatedData(multipleAttrDeviceIds, multipleAttrNames, null);
                    // key设备id  value设备对应的已经生成运行记录的多累计属性名称
                    Map<Long, List<String>> loggedAttrNamePair = new HashMap<>();
                    // 组装每个设备对应的属性 累计时长 累计里程 集合
                    if (CollUtil.isNotEmpty(accumulatedData)) {
                        accumulatedData.forEach(data -> {
                            if (deviceRunLogPair.containsKey(data.getDeviceId())) {
                                List<IotDeviceRunLogRespVO> tempRunLogs = deviceRunLogPair.get(data.getDeviceId());
                                tempRunLogs.add(data);
                                deviceRunLogPair.put(data.getDeviceId(), tempRunLogs);
                            } else {
                                List<IotDeviceRunLogRespVO> tempRunLogs = new ArrayList<>();
                                tempRunLogs.add(data);
                                deviceRunLogPair.put(data.getDeviceId(), tempRunLogs);
                            }
                            // 组装每个设备的多累计属性名称集合
                            if (loggedAttrNamePair.containsKey(data.getDeviceId())) {
                                List<String> tempAttrNames = loggedAttrNamePair.get(data.getDeviceId());
                                tempAttrNames.add(data.getPointName());
                                loggedAttrNamePair.put(data.getDeviceId(), tempAttrNames);
                            } else {
                                List<String> tempAttrNames = new ArrayList<>();
                                tempAttrNames.add(data.getPointName());
                                loggedAttrNamePair.put(data.getDeviceId(), tempAttrNames);
                            }
                        });
                    }
                    // todo 如果还没有记录运行记录数据 也要显示出来
                    deviceMultiAttrsPair.forEach((deviceId, templateAttrs) -> {
                        // 循环每个设备对应的多累计属性集合 找到没有生成运行记录的属性 使用空对象补全
                        List<String> loggedAttrNames;
                        if (loggedAttrNamePair.containsKey(deviceId)) {
                            // 当前设备对应的已经生成运行记录的多累计属性名称集合
                            loggedAttrNames = loggedAttrNamePair.get(deviceId);
                        } else {
                            loggedAttrNames = new ArrayList<>();
                        }
                        List<IotDeviceRunLogRespVO> loggedRunLogs;
                        if (deviceRunLogPair.containsKey(deviceId)) {
                            // 当前设备对应的已经生成运行记录的多累计属性名称集合
                            loggedRunLogs = deviceRunLogPair.get(deviceId);
                        } else {
                            loggedRunLogs = new ArrayList<>();
                        }
                        // 组装没有生成运行记录的多累计属性集合
                        templateAttrs.forEach(attr -> {
                            // 找到没有生成运行记录的多累计属性
                            if (!loggedAttrNames.contains(attr.getName())) {
                                IotDeviceRunLogRespVO tempRunLog = new IotDeviceRunLogRespVO();
                                tempRunLog.setDeviceId(deviceId);
                                tempRunLog.setPointName(attr.getName());
                                tempRunLog.setTotalMileage(BigDecimal.ZERO);
                                tempRunLog.setTotalRunTime(BigDecimal.ZERO);
                                loggedRunLogs.add(tempRunLog);
                            }
                        });
                        deviceRunLogPair.put(deviceId, loggedRunLogs);
                    });

                }
                // 查询 bomNodeIds 集合中每个bom节点的所有上级节点
                Map<Long, String> bomFullPaths = iotDeviceBomService.buildBomFullPaths(bomNodeIds);
                devices.forEach(device -> {
                    String uniqueKey = StrUtil.join("-", device.getId(), device.getBomNodeId());
                    if (bomMaterialsPair.containsKey(uniqueKey)) {
                        device.setDeviceBomMaterials(bomMaterialsPair.get(uniqueKey));
                    }
                    // 保养项全路径名
                    if (bomFullPaths.containsKey(Long.valueOf(device.getBomNodeId()))) {
                        if (StrUtil.isNotBlank(bomFullPaths.get(Long.valueOf(device.getBomNodeId())))) {
                            device.setName(bomFullPaths.get(Long.valueOf(device.getBomNodeId())));
                        }
                    }
                    if (deviceRunLogPair.containsKey(device.getId())) {
                        // 区分开 时间 里程 的累计属性列表 便于前端选择
                        List<IotDeviceRunLogRespVO> mileageRunLogs = new ArrayList<>();
                        List<IotDeviceRunLogRespVO> timeRunLogs = deviceRunLogPair.get(device.getId());
                        timeRunLogs.forEach(log -> {
                            log.setType(1);
                            IotDeviceRunLogRespVO tempRunLog = new IotDeviceRunLogRespVO();
                            BeanUtils.copyProperties(log, tempRunLog);
                            tempRunLog.setType(2);
                            mileageRunLogs.add(tempRunLog);
                        });
                        device.setTimeAccumulatedAttrs(timeRunLogs);
                        device.setMileageAccumulatedAttrs(mileageRunLogs);
                    }
                    // 这里只赋值正常的 累计时长 累计公里数 多个累计属性的需要在保养配置中选择
                    if (CollUtil.isNotEmpty(finalDeviceRunLogMap) && finalDeviceRunLogMap.containsKey(device.getId())) {
                        IotDeviceRunLogRespVO tempRunLog = finalDeviceRunLogMap.get(device.getId());
                        device.setTotalRunTime(tempRunLog.getTotalRunTime());
                        device.setTotalMileage(tempRunLog.getTotalMileage());
                    }
                });
            }
        }
        return devices;
    }

    @Override
    public PageResult<IotDeviceRespVO> deviceAssociateBomListPage(IotDevicePageReqVO pageReqVO) {
        IPage<IotDeviceRespVO> page = iotDeviceMapper.deviceAssociateBomListPage(new Page<>(pageReqVO.getPageNo(),
                pageReqVO.getPageSize()), pageReqVO.getDeviceIds(), pageReqVO.getBomFlag());
        // 查询所有 设备boms节点的所有上级节点名称 拼接出 全路径 的bom节点
        List<Long> bomNodeIds = new ArrayList<>();
        Set<Long> deptIds = new HashSet<>();
        Set<Long> deviceIds = new HashSet<>();
        if (CollUtil.isNotEmpty(page.getRecords())) {
            page.getRecords().forEach(device -> {
                bomNodeIds.add(Long.valueOf(device.getBomNodeId()));
                deptIds.add(device.getDeptId());
                deviceIds.add(device.getId());
            });
            // 查询 bomNodeIds 集合中每个bom节点的所有上级节点
            Map<Long, String> bomFullPaths = iotDeviceBomService.buildBomFullPaths(bomNodeIds);
            page.getRecords().forEach(device -> {
                if (bomFullPaths.containsKey(Long.valueOf(device.getBomNodeId()))) {
                    if (StrUtil.isNotBlank(bomFullPaths.get(Long.valueOf(device.getBomNodeId())))) {
                        device.setName(bomFullPaths.get(Long.valueOf(device.getBomNodeId())));
                    }
                }
            });
        }
        Map<String, List<IotDeviceMaterialRespVO>> bomMaterialsPair = iotDeviceMaterialService.bomMaterials(deptIds, deviceIds, new HashSet<>(bomNodeIds));
        page.getRecords().forEach(device -> {
            String uniqueKey = StrUtil.join("-", device.getId(), device.getBomNodeId());
            if (bomMaterialsPair.containsKey(uniqueKey)) {
                device.setDeviceBomMaterials(bomMaterialsPair.get(uniqueKey));
            }
        });
        return new PageResult<>(page.getRecords(), page.getTotal());
    }

    @Override
    public List<IotDeviceRespVO> getDeviceList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        List<IotDeviceDO> devices = iotDeviceMapper.selectBatchIds(ids);
        return BeanUtils.toBean(devices, IotDeviceRespVO.class);
    }

    public List<IotDeviceDO> getAllDevices(IotDevicePageReqVO pageReqVO) {
        return iotDeviceMapper.selectList(pageReqVO);
    }
}
