diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java index bb5fa92ae8..c4ef83a4ac 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java @@ -1,8 +1,9 @@ package cn.iocoder.yudao.module.iot.controller.admin.statistics; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsDeviceMessageSummaryRespVO; import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsSummaryRespVO; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService; @@ -18,6 +19,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.time.LocalDateTime; +import java.util.Map; @Tag(name = "管理后台 - IoT 数据统计") @RestController @@ -35,38 +37,41 @@ public class IotStatisticsController { private IotDeviceLogService deviceLogService; // TODO @super:description 非必要,可以不写哈 - @GetMapping("/main") - @Operation(summary = "获取首页的数据统计", description = "用于IOT首页的数据统计") - public CommonResult getIotMainStats(@Valid IotStatisticsReqVO reqVO){ - // TODO @super:新增 get-summary 接口,返回:总数、今日新增、数量、状态 - IotStatisticsRespVO iotStatisticsRespVO = new IotStatisticsRespVO(); + @GetMapping("/get-summary") + @Operation(summary = "获取IOT数据统计") + public CommonResult getIotStatisticsSummary(){ + IotStatisticsSummaryRespVO respVO = new IotStatisticsSummaryRespVO(); // 获取总数 - iotStatisticsRespVO.setCategoryTotal(productCategoryService.getProductCategoryCount(null)); - iotStatisticsRespVO.setProductTotal(productService.getProductCount(null)); - iotStatisticsRespVO.setDeviceTotal(deviceService.getDeviceCount(null)); - iotStatisticsRespVO.setReportTotal(deviceLogService.getDeviceLogCount(null)); + respVO.setProductCategoryCount(productCategoryService.getProductCategoryCount(null)); + respVO.setProductCount(productService.getProductCount(null)); + respVO.setDeviceCount(deviceService.getDeviceCount(null)); + respVO.setDeviceMessageCount(deviceLogService.getDeviceLogCount(null)); // 获取今日新增数量 LocalDateTime todayStart = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0); - iotStatisticsRespVO.setCategoryTodayTotal(productCategoryService.getProductCategoryCount(todayStart)); - iotStatisticsRespVO.setProductTodayTotal(productService.getProductCount(todayStart)); - iotStatisticsRespVO.setDeviceTodayTotal(deviceService.getDeviceCount(todayStart)); - iotStatisticsRespVO.setReportTodayTotal(deviceLogService.getDeviceLogCount(todayStart)); + respVO.setProductCategoryTodayCount(productCategoryService.getProductCategoryCount(todayStart)); + respVO.setProductTodayCount(productService.getProductCount(todayStart)); + respVO.setDeviceTodayCount(deviceService.getDeviceCount(todayStart)); + respVO.setDeviceMessageTodayCount(deviceLogService.getDeviceLogCount(todayStart)); // 获取各个品类下设备数量统计 - iotStatisticsRespVO.setDeviceStatsOfCategory( - productCategoryService.getDeviceCountsOfProductCategory() - ); + respVO.setProductCategoryDeviceCounts(productCategoryService.getProductCategoryDeviceCountMap()); // 获取设备状态数量统计 - iotStatisticsRespVO.setOnlineTotal(deviceService.getDeviceCountByState(IotDeviceStateEnum.ONLINE.getState())); - iotStatisticsRespVO.setOfflineTotal(deviceService.getDeviceCountByState(IotDeviceStateEnum.OFFLINE.getState())); - iotStatisticsRespVO.setNeverOnlineTotal(deviceService.getDeviceCountByState(IotDeviceStateEnum.INACTIVE.getState())); + Map deviceCountMap = deviceService.getDeviceCountMapByState(); + respVO.setDeviceOnlineCount(deviceCountMap.getOrDefault(IotDeviceStateEnum.ONLINE.getState(), 0L)); + respVO.setDeviceOfflineCount(deviceCountMap.getOrDefault(IotDeviceStateEnum.OFFLINE.getState(), 0L)); + respVO.setDeviceInactiveCount(deviceCountMap.getOrDefault(IotDeviceStateEnum.INACTIVE.getState(), 0L)); - // TODO @super:新增 get-log-summary 接口,返回 + return CommonResult.success(respVO); + } + @GetMapping("/get-log-summary") + @Operation(summary = "获取IOT上下行消息数据统计") + public CommonResult getIotStatisticsDeviceMessageSummary(@Valid IotStatisticsReqVO reqVO){ // 根据传入时间范围获取设备上下行消息数量统计 - iotStatisticsRespVO.setDeviceUpMessageStats(deviceLogService.getDeviceLogUpCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime())); - iotStatisticsRespVO.setDeviceDownMessageStats(deviceLogService.getDeviceLogDownCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime())); + IotStatisticsDeviceMessageSummaryRespVO iotStatisticsRespVO = new IotStatisticsDeviceMessageSummaryRespVO(); + iotStatisticsRespVO.setUpstreamCounts(deviceLogService.getDeviceLogUpCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime())); + iotStatisticsRespVO.setDownstreamCounts(deviceLogService.getDeviceLogDownCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime())); return CommonResult.success(iotStatisticsRespVO); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsDeviceMessageSummaryRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsDeviceMessageSummaryRespVO.java new file mode 100644 index 0000000000..250c63e2ab --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsDeviceMessageSummaryRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.iot.controller.admin.statistics.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Schema(description = "管理后台 - Iot 上下行消息数量统计 Response VO") +@Data +public class IotStatisticsDeviceMessageSummaryRespVO { + @Schema(description = "每小时上行数据数量统计") + private List> upstreamCounts; + + @Schema(description = "每小时下行数据数量统计") + private List> downstreamCounts; + + // TODO @super:如果只有这两个字段,使用 KeyValue 这个键值对 +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsReqVO.java index 4a225bc5a5..acffe1299f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsReqVO.java @@ -11,12 +11,12 @@ public class IotStatisticsReqVO { // TODO @supper:times 直接传递哈; // TODO 2super:private 不要丢了 - @Schema(description = "查询起始时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") + @Schema(description = "查询起始时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1658486600000") @NotNull(message = "查询起始时间不能为空") - Long startTime; + private Long startTime; - @Schema(description = "查询结束时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") + @Schema(description = "查询结束时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1758486600000") @NotNull(message = "查询结束时间不能为空") - Long endTime; + private Long endTime; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsSummaryRespVO.java similarity index 59% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsRespVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsSummaryRespVO.java index 0e68c078d0..0ad1f9ff4f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsSummaryRespVO.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.statistics.vo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import java.util.List; +import java.util.Map; // TODO @super:Total 全部改成 Count // TODO @super:IotStatisticsSummaryRespVO @@ -12,90 +12,58 @@ import java.util.List; */ @Schema(description = "管理后台 - Iot 统计 Response VO") @Data -public class IotStatisticsRespVO { +public class IotStatisticsSummaryRespVO { // TODO @super:productCategory 哈 @Schema(description = "品类数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") - private long categoryTotal; + private long productCategoryCount; @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") - private long productTotal; + private long productCount; @Schema(description = "设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") - private long deviceTotal; + private long deviceCount; // TODO @super:deviceMessageCount;设备消息数量 @Schema(description = "上报数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") - private long reportTotal; + private long deviceMessageCount; // TODO @super:productCategory 哈 @Schema(description = "今日新增品类数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") - private long categoryTodayTotal; + private long productCategoryTodayCount; @Schema(description = "今日新增产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") - private long productTodayTotal; + private long productTodayCount; @Schema(description = "今日新增设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") - private long deviceTodayTotal; + private long deviceTodayCount; // TODO @super:deviceMessageCount;今日设备消息数量 @Schema(description = "今日新增上报数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") - private long reportTodayTotal; + private long deviceMessageTodayCount; // TODO @super:deviceOnlineCount @Schema(description = "在线数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "80") - private long onlineTotal; + private long deviceOnlineCount; // TODO @super:deviceOfflineCount @Schema(description = "离线数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15") - private long offlineTotal; + private long deviceOfflineCount; // TODO @super:deviceInactivECount @Schema(description = "待激活设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") - private long neverOnlineTotal; + private long deviceInactiveCount; // TODO @super:1)类型改成 Map,key 分类名、value 设备数量;2)deviceStatsOfCategory => productCategoryDeviceCounts @Schema(description = "按品类统计的设备数量") - private List deviceStatsOfCategory; + private Map productCategoryDeviceCounts; // TODO @super:貌似界面里,用不到这个字段??? - @Schema(description = "上报数据数量统计") - private List reportDataStats; + // TODO @super:deviceUpMessageStats、deviceDownMessageStats 单独抽到 IotStatisticsDeviceMessageSummaryRespVO,然后里面属性就是 upstreamCounts、downstreamCounts - @Schema(description = "上行数据数量统计") - private List deviceUpMessageStats; - - @Schema(description = "下行数据数量统计") - private List deviceDownMessageStats; - - // TODO @super:如果只有这两个字段,使用 KeyValue 这个键值对 - @Schema(description = "时间数据") - @Data - public static class TimeData { - - @Schema(description = "时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1646092800000") - private long time; - - @Schema(description = "数据值", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") - private Object data; - - } - - @Schema(description = "数据项") - @Data - public static class DataItem { - - @Schema(description = "数据项名", requiredMode = Schema.RequiredMode.REQUIRED, example = "智能家居") - private String name; - - @Schema(description = "数据项值", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") - private Object value; - - } - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index cceeb53385..128b026f50 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -8,10 +8,13 @@ import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePa import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; import javax.annotation.Nullable; import java.time.LocalDateTime; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** * IoT 设备 Mapper @@ -81,4 +84,18 @@ public interface IotDeviceMapper extends BaseMapperX { .eqIfPresent(IotDeviceDO::getState, state)); } + /** + * 查询指定产品下各状态的设备数量 + * + * @return 设备数量统计列表 + */ + List> selectDeviceCountMapByProductId(); + + /** + * 查询各个状态下的设备数量 + * + * @return 设备数量统计列表 + */ + List> selectDeviceCountGroupByState(); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java index f63a14be95..5ba4a81772 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java @@ -37,10 +37,5 @@ public interface IotProductMapper extends BaseMapperX { .geIfPresent(IotProductDO::getCreateTime, createTime)); } - default List selectListByCategoryId(Long categoryId) { - return selectList(new LambdaQueryWrapperX() - .eq(IotProductDO::getCategoryId, categoryId) - .orderByDesc(IotProductDO::getId)); - } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java index df64aefb30..9efe2ec805 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.iot.dal.tdengine; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS; import com.baomidou.mybatisplus.annotation.InterceptorIgnore; @@ -10,6 +9,7 @@ import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import java.util.List; +import java.util.Map; /** * 设备日志 {@link IotDeviceLogDO} Mapper 接口 @@ -60,27 +60,17 @@ public interface IotDeviceLogMapper { // TODO @super:1)上行、下行,不写在 mapper 里,而是通过参数传递,这样,selectDeviceLogUpCountByHour、selectDeviceLogDownCountByHour 可以合并; // TODO @super:2)不能只基于 identifier 来计算,而是要 type + identifier 成对 /** - * 获得每个小时设备上行消息数量统计 - * - * @param deviceKey 设备标识 - * @param startTime 开始时间 - * @param endTime 结束时间 - * @return 每小时消息数量统计 + * 查询每个小时设备上行消息数量 */ - List selectDeviceLogUpCountByHour(@Param("deviceKey") String deviceKey, - @Param("startTime") Long startTime, - @Param("endTime") Long endTime); + List> selectDeviceLogUpCountByHour(@Param("deviceKey") String deviceKey, + @Param("startTime") Long startTime, + @Param("endTime") Long endTime); /** - * 获得每个小时设备下行消息数量统计 - * - * @param deviceKey 设备标识 - * @param startTime 开始时间 - * @param endTime 结束时间 - * @return 每小时消息数量统计 + * 查询每个小时设备下行消息数量 */ - List selectDeviceLogDownCountByHour(@Param("deviceKey") String deviceKey, - @Param("startTime") Long startTime, - @Param("endTime") Long endTime); + List> selectDeviceLogDownCountByHour(@Param("deviceKey") String deviceKey, + @Param("startTime") Long startTime, + @Param("endTime") Long endTime); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index 6d48b38d29..0e50f4a27a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.service.device; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; import jakarta.validation.Valid; import jakarta.validation.constraints.NotEmpty; @@ -10,6 +11,7 @@ import javax.annotation.Nullable; import java.time.LocalDateTime; import java.util.Collection; import java.util.List; +import java.util.Map; /** * IoT 设备 Service 接口 @@ -111,7 +113,7 @@ public interface IotDeviceService { IotDeviceDO getDeviceByDeviceKey(String deviceKey); /** - * ��得设备分页 + * 获得设备分页 * * @param pageReqVO 分页查询 * @return IoT 设备分页 @@ -194,13 +196,6 @@ public interface IotDeviceService { */ Long getDeviceCount(@Nullable LocalDateTime createTime); - /** - * 获得设备数量,基于状态 - * - * @param state 状态 - * @return 设备数量 - */ - Long getDeviceCountByState(Integer state); /** * 获得所有设备列表 @@ -217,4 +212,19 @@ public interface IotDeviceService { */ IotDeviceMqttConnectionParamsRespVO getMqttConnectionParams(Long deviceId); + /** + * 获得各个产品下的设备数量 Map + * + * @return key: 产品编号, value: 设备数量 + */ + Map getDeviceCountMapByProductId(); + + /** + * 获得各个状态下的设备数量 Map + * + * @return key: 设备状态枚举 {@link IotDeviceStateEnum} + * value: 设备数量 + */ + Map getDeviceCountMapByState(); + } \ 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/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 4d4892733b..b6c0969d17 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -35,6 +35,7 @@ import org.springframework.validation.annotation.Validated; import javax.annotation.Nullable; import java.time.LocalDateTime; import java.util.*; +import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; @@ -430,14 +431,30 @@ public class IotDeviceServiceImpl implements IotDeviceService { } // TODO @super:是不是 groupby 查询,更高效;不过 controller,还是要考虑 null 的情况;不过可以直接枚举 foreach 处理下 - @Override - public Long getDeviceCountByState(Integer state) { - return deviceMapper.selectCountByState(state); - } @Override public List getDeviceList() { return deviceMapper.selectList(); } + @Override + public Map getDeviceCountMapByProductId() { + // 查询结果转换成Map + List> list = deviceMapper.selectDeviceCountMapByProductId(); + return list.stream().collect(Collectors.toMap( + map -> Long.valueOf(map.get("key").toString()), + map -> Integer.valueOf(map.get("value").toString()) + )); + } + + @Override + public Map getDeviceCountMapByState() { + // 查询结果转换成Map + List> list = deviceMapper.selectDeviceCountGroupByState(); + return list.stream().collect(Collectors.toMap( + map -> Integer.valueOf(map.get("key").toString()), + map -> Long.valueOf(map.get("value").toString()) + )); + } + } \ 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/data/IotDeviceLogService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java index 592217bb60..e1a15aaa16 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java @@ -2,13 +2,14 @@ package cn.iocoder.yudao.module.iot.service.device.data; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsDeviceMessageSummaryRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import javax.annotation.Nullable; import java.time.LocalDateTime; import java.util.List; +import java.util.Map; /** * IoT 设备日志数据 Service 接口 @@ -50,25 +51,25 @@ public interface IotDeviceLogService { /** * 获得每个小时设备上行消息数量统计 * - * @param deviceKey 设备标识,如果为空,则统计所有设备 - * @param startTime 开始时间,如果为空,则不限制开始时间 - * @param endTime 结束时间,如果为空,则不限制结束时间 - * @return 每小时消息数量统计列表 + * @param deviceKey 设备标识 + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return key: 时间戳, value: 消息数量 */ - List getDeviceLogUpCountByHour(@Nullable String deviceKey, - @Nullable Long startTime, - @Nullable Long endTime); + List> getDeviceLogUpCountByHour(@Nullable String deviceKey, + @Nullable Long startTime, + @Nullable Long endTime); /** * 获得每个小时设备下行消息数量统计 * - * @param deviceKey 设备标识,如果为空,则统计所有设备 - * @param startTime 开始时间,如果为空,则不限制开始时间 - * @param endTime 结束时间,如果为空,则不限制结束时间 - * @return 每小时消息数量统计列表 + * @param deviceKey 设备标识 + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return key: 时间戳, value: 消息数量 */ - List getDeviceLogDownCountByHour(@Nullable String deviceKey, - @Nullable Long startTime, - @Nullable Long endTime); + List> getDeviceLogDownCountByHour(@Nullable String deviceKey, + @Nullable Long startTime, + @Nullable Long endTime); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java index a5ac4a8c1b..29b57402b5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java @@ -1,12 +1,13 @@ package cn.iocoder.yudao.module.iot.service.device.data; +import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsDeviceMessageSummaryRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogMapper; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; @@ -17,10 +18,11 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.sql.Timestamp; import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** * IoT 设备日志数据 Service 实现类 @@ -71,37 +73,39 @@ public class IotDeviceLogServiceImpl implements IotDeviceLogService { @Override public Long getDeviceLogCount(LocalDateTime createTime) { - Long time = null; - if (createTime != null) { // todo @super:1)LocalDateTimeUtil.toEpochMilli(createTime);2)直接表达式,更简洁 time != null ? createTime.toInstant(ZoneOffset.UTC).toEpochMilli() : null; - time = createTime.toInstant(ZoneOffset.UTC).toEpochMilli(); - } - return deviceLogMapper.selectCountByCreateTime(time); + return deviceLogMapper.selectCountByCreateTime(createTime != null ? LocalDateTimeUtil.toEpochMilli(createTime) : null); } // TODO @super:加一个参数,Boolean upstream:true 上行,false 下行,null 不过滤 @Override - public List getDeviceLogUpCountByHour(String deviceKey, Long startTime, Long endTime) { - try { - return deviceLogMapper.selectDeviceLogUpCountByHour(deviceKey, startTime, endTime); - } catch (Exception exception) { - if (exception.getMessage().contains("Table does not exist")) { - return new ArrayList<>(); - } - throw exception; - } + public List> getDeviceLogUpCountByHour(String deviceKey, Long startTime, Long endTime) { + List> list = deviceLogMapper.selectDeviceLogUpCountByHour(deviceKey, startTime, endTime); + return list.stream() + .map(map -> { + // 从Timestamp获取时间戳 + Timestamp timestamp = (Timestamp) map.get("time"); + Long timeMillis = timestamp.getTime(); + // 消息数量转换 + Integer count = ((Number) map.get("data")).intValue(); + return Map.of(timeMillis, count); + }) + .collect(Collectors.toList()); } @Override - public List getDeviceLogDownCountByHour(String deviceKey, Long startTime, Long endTime) { - try { - return deviceLogMapper.selectDeviceLogDownCountByHour(deviceKey, startTime, endTime); - } catch (Exception exception) { - if (exception.getMessage().contains("Table does not exist")) { - return new ArrayList<>(); - } - throw exception; - } + public List> getDeviceLogDownCountByHour(String deviceKey, Long startTime, Long endTime) { + List> list = deviceLogMapper.selectDeviceLogDownCountByHour(deviceKey, startTime, endTime); + return list.stream() + .map(map -> { + // 从Timestamp获取时间戳 + Timestamp timestamp = (Timestamp) map.get("time"); + Long timeMillis = timestamp.getTime(); + // 消息数量转换 + Integer count = ((Number) map.get("data")).intValue(); + return Map.of(timeMillis, count); + }) + .collect(Collectors.toList()); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java index 8d6ccdadaa..662d161c10 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.iot.service.product; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategoryPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategorySaveReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductCategoryDO; import jakarta.validation.Valid; @@ -100,6 +99,6 @@ public interface IotProductCategoryService { * * @return 品类设备统计列表 */ - List getDeviceCountsOfProductCategory(); + Map getProductCategoryDeviceCountMap(); } \ 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/product/IotProductCategoryServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java index d8b9af1fb3..5499937fde 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java @@ -5,8 +5,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategoryPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategorySaveReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductCategoryDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductCategoryMapper; @@ -16,11 +14,7 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import java.time.LocalDateTime; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; +import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_CATEGORY_NOT_EXISTS; @@ -103,54 +97,30 @@ public class IotProductCategoryServiceImpl implements IotProductCategoryService } @Override - public List getDeviceCountsOfProductCategory() { + public Map getProductCategoryDeviceCountMap() { // 1. 获取所有数据 List categoryList = productCategoryMapper.selectList(); List productList = productService.getProductList(); // TODO @super:不要 list 查询,返回内存,而是查询一个 Map - List deviceList = deviceService.getDeviceList(); + Map deviceCountMapByProductId = deviceService.getDeviceCountMapByProductId(); // 2. 统计每个分类下的设备数量 Map categoryDeviceCountMap = new HashMap<>(); - + // 2.1 初始化所有分类的计数为0 for (IotProductCategoryDO category : categoryList) { categoryDeviceCountMap.put(category.getName(), 0); - // TODO @super:直接这里面计算,不用多个循环。产品本身也不多,不用构建 Map,直接 filter 就好了 - } - - // 2.2 构建产品ID到分类的映射 - Map productCategoryMap = new HashMap<>(); - for (IotProductDO product : productList) { - Long categoryId = product.getCategoryId(); - IotProductCategoryDO category = categoryList.stream() - .filter(c -> c.getId().equals(categoryId)) - .findFirst() - .orElse(null); - if (category != null) { - productCategoryMap.put(product.getId(), category); + + // 2.2 找到该分类下的所有产品,累加设备数量 + for (IotProductDO product : productList) { + if (Objects.equals(product.getCategoryId(), category.getId())) { + Integer deviceCount = deviceCountMapByProductId.getOrDefault(product.getId(), 0); + categoryDeviceCountMap.merge(category.getName(), deviceCount, Integer::sum); + } } } - // 2.3 统计每个分类下的设备数量 - for (IotDeviceDO device : deviceList) { - Long productId = device.getProductId(); - IotProductCategoryDO category = productCategoryMap.get(productId); - if (category != null) { - String categoryName = category.getName(); - categoryDeviceCountMap.merge(categoryName, 1, Integer::sum); - } - } - - // 3. 转换为 DataItem 列表 - return categoryDeviceCountMap.entrySet().stream() - .map(entry -> { - IotStatisticsRespVO.DataItem dataItem = new IotStatisticsRespVO.DataItem(); - dataItem.setName(entry.getKey()); - dataItem.setValue(entry.getValue()); - return dataItem; - }) - .collect(Collectors.toList()); + return categoryDeviceCountMap; } } \ 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/product/IotProductService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java index 5d6f7c788a..8497d73aa9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java @@ -102,13 +102,5 @@ public interface IotProductService { */ Long getProductCount(@Nullable LocalDateTime createTime); - // TODO @super:用不到的,删除下哈 - /** - * 获得产品列表,基于分类编号 - * - * @param categoryId 分类编号 - * @return 产品列表 - */ - List getProductListByCategoryId(Long categoryId); } \ 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/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index 848da74d65..4a7263c27b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -143,9 +143,5 @@ public class IotProductServiceImpl implements IotProductService { return productMapper.selectCountByCreateTime(createTime); } - @Override - public List getProductListByCategoryId(Long categoryId) { - return productMapper.selectListByCategoryId(categoryId); - } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogMapper.xml index 4a4c3d6bde..932a9a862c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogMapper.xml @@ -65,7 +65,7 @@ - SELECT TIMETRUNCATE(ts, 1h) as time, COUNT(*) as data @@ -93,7 +93,7 @@ ORDER BY time ASC - SELECT TIMETRUNCATE(ts, 1h) as time, COUNT(*) as data diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml new file mode 100644 index 0000000000..8404729cce --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml @@ -0,0 +1,25 @@ + + + + + + + + + \ No newline at end of file