From 3a65a27e1791fd707f99977b6d58eac09edfcf60 Mon Sep 17 00:00:00 2001 From: 86158 <461356067@qq.com> Date: Mon, 9 Feb 2026 17:15:14 +0800 Subject: [PATCH] =?UTF-8?q?fix:=E4=BF=AE=E6=94=B9=E5=A4=A7=E5=B1=8F?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E7=82=B9=E4=BD=8D=E6=95=B0=E6=8D=AE=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/device/DeviceController.java | 6 +- .../iot/dal/mysql/device/DeviceMapper.java | 9 + .../iot/service/device/DeviceService.java | 2 +- .../iot/service/device/DeviceServiceImpl.java | 248 ++++++++++++++---- .../admin/goview/vo/GoviewPageReqVO.java | 2 +- .../admin/goview/vo/GoviewRespVO.java | 11 + .../admin/goview/vo/GoviewSaveReqVO.java | 13 +- .../mes/service/goview/GoviewServiceImpl.java | 12 + 8 files changed, 248 insertions(+), 55 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/DeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/DeviceController.java index 8c9cebb32..5042e62e5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/DeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/DeviceController.java @@ -318,10 +318,10 @@ public class DeviceController { @GetMapping("/device-attribute/batchList") @Operation(summary = "获得多个设备的属性数据") - @Parameter(name = "deviceIds", description = "设备ID列表,用逗号分隔", required = true) + @Parameter(name = "goviewId", description = "大屏ID", required = true) @PreAuthorize("@ss.hasPermission('iot:device:query')") - public CommonResult>> getMultiDeviceAttributes(@RequestParam("deviceIds") String deviceIds) { - return success(deviceService.getMultiDeviceAttributes(deviceIds)); + public CommonResult>> getMultiDeviceAttributes(@RequestParam("goviewId") Long goviewId) { + return success(deviceService.getMultiDeviceAttributes(goviewId)); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/DeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/DeviceMapper.java index c066f3f41..bced60a98 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/DeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/DeviceMapper.java @@ -14,6 +14,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; import java.util.Arrays; import java.util.List; @@ -109,4 +110,12 @@ public interface DeviceMapper extends BaseMapperX { int selectIsReference(@Param("deviceId") Long deviceId); + /** + * 根据goviewId查询对应的deviceIds + * + * @param goviewId 可视化大屏ID + * @return deviceIds字符串 + */ + @Select("SELECT device_ids FROM mes_goview WHERE id = #{goviewId}") + String selectDeviceIdsByGoviewId(@Param("goviewId") Long goviewId); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceService.java index ca2e3a1d4..bd622d796 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceService.java @@ -136,7 +136,7 @@ public interface DeviceService { DeviceOperationStatusRespVO getDeviceOperationalStatus(); - List> getMultiDeviceAttributes(String deviceIds); + List> getMultiDeviceAttributes(Long goviewId); List getDeviceAttributeList(Long deviceId); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java index 51a6c209b..22d67ecb3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java @@ -986,68 +986,218 @@ public class DeviceServiceImpl implements DeviceService { } @Override - public List> getMultiDeviceAttributes(String deviceIds) { + public List> getMultiDeviceAttributes(Long goviewId) { List> result = new ArrayList<>(); - // 解析设备ID列表 - if (StringUtils.isBlank(deviceIds)) { - return result; - } - - List idList = Arrays.stream(deviceIds.split(",")) - .map(String::trim) - .map(Long::valueOf) - .collect(Collectors.toList()); + try { + // 直接从数据库查询deviceIds JSON字符串 + String deviceIdsJson = deviceMapper.selectDeviceIdsByGoviewId(goviewId); + if (StringUtils.isBlank(deviceIdsJson)) { + log.info("No deviceIds found for goviewId: {}", goviewId); + return result; + } - // 遍历每个设备ID,获取设备属性数据 - for (Long deviceId : idList) { - // 获取设备信息 - DeviceDO device = deviceMapper.selectById(deviceId); - if (device == null) { - continue; + // 解析JSON格式的deviceIds + Map> deviceAttributeMap = parseDeviceIdsJson(deviceIdsJson); + if (deviceAttributeMap.isEmpty()) { + log.warn("No valid device-attribute mapping found for goviewId: {}", goviewId); + return result; } - // 创建设备层级的Map - Map deviceMap = new HashMap<>(); - deviceMap.put("deviceId", deviceId); - deviceMap.put("deviceName", device.getDeviceName()); + // 批量获取所有设备的最新运行记录,减少数据库查询次数 + Map latestRecordMap = getLatestDeviceOperationRecords(deviceAttributeMap.keySet()); - // 获取设备属性列表 - List attributes = deviceContactModelMapper.selectList( - Wrappers.lambdaQuery() - .eq(DeviceContactModelDO::getDeviceId, deviceId)); - - // 获取设备最新数据 - Map> deviceDataMap = createDeviceDataMap(deviceId); - - // 创建点位集合 - List> attributeList = new ArrayList<>(); - for (DeviceContactModelDO attribute : attributes) { - Map attributeData = new HashMap<>(); - attributeData.put("attributeId", attribute.getId()); - attributeData.put("attributeName", attribute.getAttributeName()); - attributeData.put("attributeCode", attribute.getAttributeCode()); - attributeData.put("dataType", attribute.getDataType()); - attributeData.put("dataUnit", attribute.getDataUnit()); - - // 获取最新数据 - Map latestData = deviceDataMap.get(attribute.getId()); - if (latestData != null) { - attributeData.put("addressValue", adjustByRatio(latestData.get("addressValue"), attribute.getRatio())); - attributeData.put("latestCollectionTime", latestData.get("timestamp")); + log.info("Found {} devices with attribute mappings for goviewId {}: {}", + deviceAttributeMap.size(), goviewId, deviceAttributeMap); + + // 遍历每个设备ID,获取设备属性数据 + for (Map.Entry> entry : deviceAttributeMap.entrySet()) { + Long deviceId = entry.getKey(); + Set attributeIds = entry.getValue(); + + try { + // 获取设备信息 + DeviceDO device = deviceMapper.selectById(deviceId); + if (device == null) { + log.warn("Device not found for ID: {}", deviceId); + continue; + } + + // 创建设备层级的Map + Map deviceMap = new HashMap<>(); + deviceMap.put("deviceId", deviceId); + deviceMap.put("deviceName", device.getDeviceName()); + deviceMap.put("deviceCode", device.getDeviceCode()); + + // 添加设备运行状态 + String operatingStatus = getDeviceOperatingStatus(deviceId, latestRecordMap); + deviceMap.put("operatingStatus", operatingStatus); + + // 获取设备属性列表,只查询指定的属性ID + List attributes = deviceContactModelMapper.selectList( + Wrappers.lambdaQuery() + .eq(DeviceContactModelDO::getDeviceId, deviceId) + .in(DeviceContactModelDO::getId, attributeIds)); + + // 获取设备最新数据 + Map> deviceDataMap = createDeviceDataMap(deviceId); + + // 创建属性集合 + List> attributeList = new ArrayList<>(); + for (DeviceContactModelDO attribute : attributes) { + Map attributeData = new HashMap<>(); + attributeData.put("attributeId", attribute.getId()); + attributeData.put("attributeName", attribute.getAttributeName()); + attributeData.put("attributeCode", attribute.getAttributeCode()); + attributeData.put("dataType", attribute.getDataType()); + attributeData.put("dataUnit", attribute.getDataUnit()); + + // 获取最新数据 + Map latestData = deviceDataMap.get(attribute.getId()); + if (latestData != null) { + attributeData.put("addressValue", adjustByRatio(latestData.get("addressValue"), attribute.getRatio())); + attributeData.put("latestCollectionTime", latestData.get("timestamp")); + } + + attributeList.add(attributeData); + } + + // 将属性集合添加到设备层级 + deviceMap.put("attributes", attributeList); + + // 添加到结果列表 + result.add(deviceMap); + } catch (Exception e) { + log.error("Error processing device ID: {} with attributes: {}", deviceId, attributeIds, e); + // 继续处理其他设备,不中断整体流程 } + } + } catch (Exception e) { + log.error("Failed to get multi-device attributes by goviewId: {}", goviewId, e); + } + + return result; + } + + /** + * 获取设备运行状态 + * @param deviceId 设备ID + * @param latestRecordMap 设备ID到最新运行记录的映射 + * @return 设备运行状态名称 + */ + private String getDeviceOperatingStatus(Long deviceId, Map latestRecordMap) { + DeviceOperationRecordDO record = latestRecordMap.get(deviceId); + if (record != null) { + // 根据运行记录的rule字段获取设备状态 + DeviceStatusEnum statusEnum = DeviceStatusEnum.getByCode(record.getRule()); + return statusEnum != null ? statusEnum.getName() : DeviceStatusEnum.OFFLINE.getName(); + } else { + // 如果没有运行记录,默认为离线状态 + return DeviceStatusEnum.OFFLINE.getName(); + } + } + + /** + * 批量获取设备的最新运行记录 + * @param deviceIds 设备ID集合 + * @return 设备ID到最新运行记录的映射 + */ + private Map getLatestDeviceOperationRecords(Set deviceIds) { + if (deviceIds.isEmpty()) { + return Collections.emptyMap(); + } - attributeList.add(attributeData); + // 查询所有设备的最新运行记录 + List records = deviceOperationRecordMapper.selectList( + Wrappers.lambdaQuery() + .in(DeviceOperationRecordDO::getDeviceId, deviceIds) + .orderByDesc(DeviceOperationRecordDO::getCreateTime)); + + // 构建设备ID到最新记录的映射 + Map latestRecordMap = new HashMap<>(); + for (DeviceOperationRecordDO record : records) { + // 只保留每个设备的第一条记录(因为已经按创建时间倒序排序) + if (!latestRecordMap.containsKey(record.getDeviceId())) { + latestRecordMap.put(record.getDeviceId(), record); } + } - // 将点位集合添加到设备层级 - deviceMap.put("attributes", attributeList); + return latestRecordMap; + } + + /** + * 解析JSON格式的deviceIds字符串 + * @param deviceIdsJson JSON格式的设备和属性映射字符串 + * @return 设备ID到属性ID集合的映射(已去重) + */ + private Map> parseDeviceIdsJson(String deviceIdsJson) { + Map> deviceAttributeMap = new HashMap<>(); - // 添加到结果列表 - result.add(deviceMap); + if (StringUtils.isBlank(deviceIdsJson)) { + return deviceAttributeMap; } - return result; + try { + // 使用Jackson解析JSON字符串 + ObjectMapper objectMapper = new ObjectMapper(); + List> deviceAttributeList = objectMapper.readValue( + deviceIdsJson, new TypeReference>>() {}); + + // 遍历解析结果,构建设备-属性映射并去重 + for (Map item : deviceAttributeList) { + try { + // 提取设备ID + Object deviceIdObj = item.get("deviceId"); + if (deviceIdObj == null) { + log.warn("Device ID is null in item: {}", item); + continue; + } + Long deviceId = null; + if (deviceIdObj instanceof Number) { + deviceId = ((Number) deviceIdObj).longValue(); + } else { + deviceId = Long.parseLong(deviceIdObj.toString()); + } + + // 提取属性ID数组 + List attributeIds = new ArrayList<>(); + Object attributesIdsObj = item.get("attributesIds"); + if (attributesIdsObj instanceof List) { + List attributesList = (List) attributesIdsObj; + for (Object attrIdObj : attributesList) { + if (attrIdObj instanceof Number) { + attributeIds.add(((Number) attrIdObj).longValue()); + } else if (attrIdObj != null) { + try { + attributeIds.add(Long.parseLong(attrIdObj.toString())); + } catch (NumberFormatException e) { + log.warn("Invalid attribute ID: {}", attrIdObj); + } + } + } + } + + // 合并属性ID到现有设备映射中(避免Lambda变量捕获问题) + Set existingAttributes = deviceAttributeMap.get(deviceId); + if (existingAttributes == null) { + // 如果设备不存在,创建新的属性集合 + Set newAttributesSet = new HashSet<>(attributeIds); + deviceAttributeMap.put(deviceId, newAttributesSet); + } else { + // 如果设备已存在,将新的属性ID添加到现有集合中 + for (Long attrId : attributeIds) { + existingAttributes.add(attrId); + } + } + } catch (Exception e) { + log.warn("Error parsing device-attribute item: {}", item, e); + } + } + } catch (Exception e) { + log.error("Error parsing deviceIds JSON: {}", deviceIdsJson, e); + } + + return deviceAttributeMap; } @Override diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/goview/vo/GoviewPageReqVO.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/goview/vo/GoviewPageReqVO.java index 345058ef8..925203eba 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/goview/vo/GoviewPageReqVO.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/goview/vo/GoviewPageReqVO.java @@ -49,7 +49,7 @@ public class GoviewPageReqVO extends PageParam { @Schema(description = "大屏类型") private String type; - @Schema(description = "设备ids") + @Schema(description = "设备ids与点位ids") private String deviceIds; } \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/goview/vo/GoviewRespVO.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/goview/vo/GoviewRespVO.java index 5c8b6ebbd..db6196b8b 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/goview/vo/GoviewRespVO.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/goview/vo/GoviewRespVO.java @@ -63,4 +63,15 @@ public class GoviewRespVO { @ExcelProperty("设备ids") private String deviceIds; + @Schema(description = "设备ids与点位ids列表") + private List deviceIdsList; + + @Data + public static class DevicePointVO { + @Schema(description = "设备ID", example = "12") + private Long deviceId; + @Schema(description = "点位ID列表", example = "[1,5,9]") + private List attributesIds; + } + } \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/goview/vo/GoviewSaveReqVO.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/goview/vo/GoviewSaveReqVO.java index 89f046c58..5f7b71e23 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/goview/vo/GoviewSaveReqVO.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/goview/vo/GoviewSaveReqVO.java @@ -39,7 +39,18 @@ public class GoviewSaveReqVO { @Schema(description = "大屏类型") private String type; - @Schema(description = "设备ids") + @Schema(description = "设备ids与点位ids") private String deviceIds; + @Schema(description = "设备ids与点位ids列表") + private List deviceIdsList; + + @Data + public static class DevicePointVO { + @Schema(description = "设备ID", example = "12") + private Long deviceId; + @Schema(description = "点位ID列表", example = "[1,5,9]") + private List attributesIds; + } + } \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/goview/GoviewServiceImpl.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/goview/GoviewServiceImpl.java index 456e03b54..7e00d8e85 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/goview/GoviewServiceImpl.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/goview/GoviewServiceImpl.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.mes.service.goview; +import com.alibaba.fastjson.JSON; import org.springframework.stereotype.Service; import javax.annotation.Resource; import org.springframework.validation.annotation.Validated; @@ -33,6 +34,11 @@ public class GoviewServiceImpl implements GoviewService { public Long createGoview(GoviewSaveReqVO createReqVO) { // 插入 GoviewDO goview = BeanUtils.toBean(createReqVO, GoviewDO.class); + if (!createReqVO.getDeviceIdsList().isEmpty()){ + String jsonString = JSON.toJSONString(createReqVO.getDeviceIdsList()); + goview.setDeviceIds(jsonString); + + } goviewMapper.insert(goview); // 返回 return goview.getId(); @@ -44,6 +50,12 @@ public class GoviewServiceImpl implements GoviewService { validateGoviewExists(updateReqVO.getId()); // 更新 GoviewDO updateObj = BeanUtils.toBean(updateReqVO, GoviewDO.class); + if (!updateReqVO.getDeviceIdsList().isEmpty()){ + String jsonString = JSON.toJSONString(updateReqVO.getDeviceIdsList()); + updateObj.setDeviceIds(jsonString); + + } + goviewMapper.updateById(updateObj); }