From 70627b54d3e4d59f447ec911fc335be4a9b9e88e Mon Sep 17 00:00:00 2001 From: HuangHuiKang Date: Tue, 28 Jul 2026 11:36:12 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=96=B0=E5=A2=9Eiot=E7=89=A9=E8=81=94?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E7=BB=9F=E8=AE=A1=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/device/DeviceController.java | 6 ++ .../vo/DeviceStatusStatisticsRespVO.java | 25 +++++++ .../iot/service/device/DeviceService.java | 3 + .../iot/service/device/DeviceServiceImpl.java | 66 ++++++++++++++++--- .../mes/api/deviceledger/DeviceLedgerApi.java | 10 +++ .../api/deviceledger/DeviceLedgerApiImpl.java | 38 +++++++++++ 6 files changed, 139 insertions(+), 9 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceStatusStatisticsRespVO.java create mode 100644 yudao-module-mes/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/deviceledger/DeviceLedgerApi.java create mode 100644 yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/api/deviceledger/DeviceLedgerApiImpl.java 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 5bd7ec9a3..b756dc158 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 @@ -118,6 +118,12 @@ public class DeviceController { return success(pageResult); } + @GetMapping("/status-statistics") + @Operation(summary = "获得物联设备状态统计") + public CommonResult getDeviceStatusStatistics(@Valid DevicePageReqVO pageReqVO) { + return success(deviceService.getDeviceStatusStatistics(pageReqVO)); + } + @GetMapping("/available-list") @Operation(summary = "获取设备下拉列表(全量+是否已选+已删除标识)") // @PreAuthorize("@ss.hasPermission('iot:device:query')") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceStatusStatisticsRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceStatusStatisticsRespVO.java new file mode 100644 index 000000000..f56d981b1 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceStatusStatisticsRespVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 物联设备状态统计 Resp VO") +@Data +public class DeviceStatusStatisticsRespVO { + + @Schema(description = "总数") + private Long totalCount; + + @Schema(description = "运行数") + private Long runningCount; + + @Schema(description = "待机数") + private Long standbyCount; + + @Schema(description = "报警数") + private Long alarmCount; + + @Schema(description = "离线数") + private Long offlineCount; + +} 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 04c1967aa..fcf38cd83 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 @@ -72,6 +72,9 @@ public interface DeviceService { * @return 物联设备分页 */ PageResult getDevicePage(DevicePageReqVO pageReqVO); + + DeviceStatusStatisticsRespVO getDeviceStatusStatistics(DevicePageReqVO pageReqVO); + List selectList(DevicePageReqVO reqVO); // ==================== 子表(设备属性) ==================== 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 cccf137d1..4d98d9e09 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 @@ -51,6 +51,7 @@ import cn.iocoder.yudao.module.iot.framework.mqtt.config.DefaultBizTopicSet; import cn.iocoder.yudao.module.iot.framework.mqtt.consumer.IMqttservice; import cn.iocoder.yudao.module.iot.framework.mqtt.consumer.IotMqttRuntimeCache; import cn.iocoder.yudao.module.iot.util.MapListStatsCalculator; +import cn.iocoder.yudao.module.mes.api.deviceledger.DeviceLedgerApi; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; @@ -154,6 +155,9 @@ public class DeviceServiceImpl implements DeviceService { @Resource private ErpProductUnitMapper productUnitMapper; + @Resource + private DeviceLedgerApi deviceLedgerApi; + // @Resource // private GatewayService gatewayService; @@ -447,6 +451,7 @@ public class DeviceServiceImpl implements DeviceService { r -> r, (r1, r2) -> r1.getCreateTime().isAfter(r2.getCreateTime()) ? r1 : r2 )); + Set maintenanceIotDeviceIds = getMaintenanceIotDeviceIds(deviceIds); // 4. 转换分页 DTO PageResult deviceRespVOPageResult = BeanUtils.toBean(deviceDOPageResult, DeviceRespVO.class); @@ -461,13 +466,7 @@ public class DeviceServiceImpl implements DeviceService { } // 设置运行状态 - DeviceOperationRecordDO record = latestRecordMap.get(deviceId); - if (record != null) { - deviceRespVO.setOperatingStatus(DeviceStatusEnum.getByCode(record.getRule()).getName()); - } else { - deviceRespVO.setOperatingStatus(DeviceStatusEnum.OFFLINE.getName()); - - } + deviceRespVO.setOperatingStatus(resolveDeviceOperatingStatus(deviceId, latestRecordMap.get(deviceId), maintenanceIotDeviceIds)); } @@ -476,6 +475,43 @@ public class DeviceServiceImpl implements DeviceService { return deviceRespVOPageResult; } + @Override + public DeviceStatusStatisticsRespVO getDeviceStatusStatistics(DevicePageReqVO pageReqVO) { + List deviceList = deviceMapper.selectList(pageReqVO); + List deviceIds = deviceList.stream() + .map(DeviceDO::getId) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + Map latestRecordMap = tdengineService.selectLatestByDeviceAndRuleMinimal(deviceIds, null).stream() + .collect(Collectors.toMap( + DeviceOperationRecordDO::getDeviceId, + r -> r, + (r1, r2) -> r1.getCreateTime().isAfter(r2.getCreateTime()) ? r1 : r2 + )); + Set maintenanceIotDeviceIds = getMaintenanceIotDeviceIds(deviceIds); + + DeviceStatusStatisticsRespVO respVO = new DeviceStatusStatisticsRespVO(); + respVO.setTotalCount((long) deviceList.size()); + respVO.setRunningCount(0L); + respVO.setStandbyCount(0L); + respVO.setAlarmCount(0L); + respVO.setOfflineCount(0L); + for (Long deviceId : deviceIds) { + String operatingStatus = resolveDeviceOperatingStatus(deviceId, latestRecordMap.get(deviceId), maintenanceIotDeviceIds); + if (StringUtils.equals(operatingStatus, DeviceStatusEnum.RUNNING.getName())) { + respVO.setRunningCount(respVO.getRunningCount() + 1); + } else if (StringUtils.equals(operatingStatus, DeviceStatusEnum.STANDBY.getName())) { + respVO.setStandbyCount(respVO.getStandbyCount() + 1); + } else if (StringUtils.equals(operatingStatus, DeviceStatusEnum.FAULT_STANDBY.getName()) + || StringUtils.equals(operatingStatus, DeviceStatusEnum.ALARM_RUNNING.getName())) { + respVO.setAlarmCount(respVO.getAlarmCount() + 1); + } else { + respVO.setOfflineCount(respVO.getOfflineCount() + 1); + } + } + return respVO; + } + private PageResult getDevicePageByOperatingStatus(DevicePageReqVO pageReqVO) { List deviceList = deviceMapper.selectList(pageReqVO); List deviceRespVOList = BeanUtils.toBean(deviceList, DeviceRespVO.class); @@ -491,12 +527,14 @@ public class DeviceServiceImpl implements DeviceService { (r1, r2) -> r1.getCreateTime().isAfter(r2.getCreateTime()) ? r1 : r2 )); + Set maintenanceIotDeviceIds = getMaintenanceIotDeviceIds(deviceIds); + for (DeviceRespVO deviceRespVO : deviceRespVOList) { Long deviceId = deviceRespVO.getId(); if (latestTsMap.get(deviceId) != null) { deviceRespVO.setCollectionTime(latestTsMap.get(deviceId)); } - deviceRespVO.setOperatingStatus(resolveDeviceOperatingStatus(latestRecordMap.get(deviceId))); + deviceRespVO.setOperatingStatus(resolveDeviceOperatingStatus(deviceId, latestRecordMap.get(deviceId), maintenanceIotDeviceIds)); } List filteredList = deviceRespVOList.stream() @@ -535,7 +573,10 @@ public class DeviceServiceImpl implements DeviceService { } } - private String resolveDeviceOperatingStatus(DeviceOperationRecordDO record) { + private String resolveDeviceOperatingStatus(Long deviceId, DeviceOperationRecordDO record, Set maintenanceIotDeviceIds) { + if (maintenanceIotDeviceIds.contains(deviceId)) { + return DeviceStatusEnum.ALARM_RUNNING.getName(); + } if (record == null) { return DeviceStatusEnum.OFFLINE.getName(); } @@ -543,6 +584,13 @@ public class DeviceServiceImpl implements DeviceService { return status != null ? status.getName() : DeviceStatusEnum.OFFLINE.getName(); } + private Set getMaintenanceIotDeviceIds(Collection deviceIds) { + if (CollUtil.isEmpty(deviceIds)) { + return Collections.emptySet(); + } + return deviceLedgerApi.getMaintenanceIotDeviceIds(deviceIds); + } + private boolean matchesOperatingStatus(String actualStatus, String expectedStatus) { if (StringUtils.equals(actualStatus, expectedStatus)) { return true; diff --git a/yudao-module-mes/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/deviceledger/DeviceLedgerApi.java b/yudao-module-mes/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/deviceledger/DeviceLedgerApi.java new file mode 100644 index 000000000..6c62d96ca --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/deviceledger/DeviceLedgerApi.java @@ -0,0 +1,10 @@ +package cn.iocoder.yudao.module.mes.api.deviceledger; + +import java.util.Collection; +import java.util.Set; + +public interface DeviceLedgerApi { + + Set getMaintenanceIotDeviceIds(Collection iotDeviceIds); + +} diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/api/deviceledger/DeviceLedgerApiImpl.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/api/deviceledger/DeviceLedgerApiImpl.java new file mode 100644 index 000000000..d040e7b1e --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/api/deviceledger/DeviceLedgerApiImpl.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.mes.api.deviceledger; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.module.mes.controller.admin.deviceledger.enums.DeviceLedgerStatusEnum; +import cn.iocoder.yudao.module.mes.dal.dataobject.deviceledger.DeviceLedgerDO; +import cn.iocoder.yudao.module.mes.dal.mysql.deviceledger.DeviceLedgerMapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +@Service +public class DeviceLedgerApiImpl implements DeviceLedgerApi { + + @Resource + private DeviceLedgerMapper deviceLedgerMapper; + + @Override + public Set getMaintenanceIotDeviceIds(Collection iotDeviceIds) { + if (CollUtil.isEmpty(iotDeviceIds)) { + return Collections.emptySet(); + } + return deviceLedgerMapper.selectList(Wrappers.lambdaQuery() + .select(DeviceLedgerDO::getDvId) + .in(DeviceLedgerDO::getDvId, iotDeviceIds) + .eq(DeviceLedgerDO::getDeviceStatus, DeviceLedgerStatusEnum.MAINTENANCE.getCode())) + .stream() + .map(DeviceLedgerDO::getDvId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + } + +}