Commit 8bcfd40847ca789433c9cc8a3e1fc1400b9673df

Authored by 芋道源码
Committed by Gitee
2 parents 6e1ec8b3 0f0ebda4

!1266 对IOT首页功能的code review的修改

Merge pull request !1266 from alwayssuper/feature/iot
Showing 17 changed files with 217 additions and 209 deletions
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java
1 1 package cn.iocoder.yudao.module.iot.controller.admin.statistics;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsDeviceMessageSummaryRespVO;
4 5 import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsReqVO;
5   -import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsSummaryRespVO;
6 7 import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
7 8 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
8 9 import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService;
... ... @@ -18,6 +19,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
18 19 import org.springframework.web.bind.annotation.RestController;
19 20  
20 21 import java.time.LocalDateTime;
  22 +import java.util.Map;
21 23  
22 24 @Tag(name = "管理后台 - IoT 数据统计")
23 25 @RestController
... ... @@ -35,38 +37,41 @@ public class IotStatisticsController {
35 37 private IotDeviceLogService deviceLogService;
36 38  
37 39 // TODO @super:description 非必要,可以不写哈
38   - @GetMapping("/main")
39   - @Operation(summary = "获取首页的数据统计", description = "用于IOT首页的数据统计")
40   - public CommonResult<IotStatisticsRespVO> getIotMainStats(@Valid IotStatisticsReqVO reqVO){
41   - // TODO @super:新增 get-summary 接口,返回:总数、今日新增、数量、状态
42   - IotStatisticsRespVO iotStatisticsRespVO = new IotStatisticsRespVO();
  40 + @GetMapping("/get-summary")
  41 + @Operation(summary = "获取IOT数据统计")
  42 + public CommonResult<IotStatisticsSummaryRespVO> getIotStatisticsSummary(){
  43 + IotStatisticsSummaryRespVO respVO = new IotStatisticsSummaryRespVO();
43 44 // 获取总数
44   - iotStatisticsRespVO.setCategoryTotal(productCategoryService.getProductCategoryCount(null));
45   - iotStatisticsRespVO.setProductTotal(productService.getProductCount(null));
46   - iotStatisticsRespVO.setDeviceTotal(deviceService.getDeviceCount(null));
47   - iotStatisticsRespVO.setReportTotal(deviceLogService.getDeviceLogCount(null));
  45 + respVO.setProductCategoryCount(productCategoryService.getProductCategoryCount(null));
  46 + respVO.setProductCount(productService.getProductCount(null));
  47 + respVO.setDeviceCount(deviceService.getDeviceCount(null));
  48 + respVO.setDeviceMessageCount(deviceLogService.getDeviceLogCount(null));
48 49  
49 50 // 获取今日新增数量
50 51 LocalDateTime todayStart = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0);
51   - iotStatisticsRespVO.setCategoryTodayTotal(productCategoryService.getProductCategoryCount(todayStart));
52   - iotStatisticsRespVO.setProductTodayTotal(productService.getProductCount(todayStart));
53   - iotStatisticsRespVO.setDeviceTodayTotal(deviceService.getDeviceCount(todayStart));
54   - iotStatisticsRespVO.setReportTodayTotal(deviceLogService.getDeviceLogCount(todayStart));
  52 + respVO.setProductCategoryTodayCount(productCategoryService.getProductCategoryCount(todayStart));
  53 + respVO.setProductTodayCount(productService.getProductCount(todayStart));
  54 + respVO.setDeviceTodayCount(deviceService.getDeviceCount(todayStart));
  55 + respVO.setDeviceMessageTodayCount(deviceLogService.getDeviceLogCount(todayStart));
55 56  
56 57 // 获取各个品类下设备数量统计
57   - iotStatisticsRespVO.setDeviceStatsOfCategory(
58   - productCategoryService.getDeviceCountsOfProductCategory()
59   - );
  58 + respVO.setProductCategoryDeviceCounts(productCategoryService.getProductCategoryDeviceCountMap());
60 59  
61 60 // 获取设备状态数量统计
62   - iotStatisticsRespVO.setOnlineTotal(deviceService.getDeviceCountByState(IotDeviceStateEnum.ONLINE.getState()));
63   - iotStatisticsRespVO.setOfflineTotal(deviceService.getDeviceCountByState(IotDeviceStateEnum.OFFLINE.getState()));
64   - iotStatisticsRespVO.setNeverOnlineTotal(deviceService.getDeviceCountByState(IotDeviceStateEnum.INACTIVE.getState()));
  61 + Map<Integer, Long> deviceCountMap = deviceService.getDeviceCountMapByState();
  62 + respVO.setDeviceOnlineCount(deviceCountMap.getOrDefault(IotDeviceStateEnum.ONLINE.getState(), 0L));
  63 + respVO.setDeviceOfflineCount(deviceCountMap.getOrDefault(IotDeviceStateEnum.OFFLINE.getState(), 0L));
  64 + respVO.setDeviceInactiveCount(deviceCountMap.getOrDefault(IotDeviceStateEnum.INACTIVE.getState(), 0L));
65 65  
66   - // TODO @super:新增 get-log-summary 接口,返回
  66 + return CommonResult.success(respVO);
  67 + }
  68 + @GetMapping("/get-log-summary")
  69 + @Operation(summary = "获取IOT上下行消息数据统计")
  70 + public CommonResult<IotStatisticsDeviceMessageSummaryRespVO> getIotStatisticsDeviceMessageSummary(@Valid IotStatisticsReqVO reqVO){
67 71 // 根据传入时间范围获取设备上下行消息数量统计
68   - iotStatisticsRespVO.setDeviceUpMessageStats(deviceLogService.getDeviceLogUpCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime()));
69   - iotStatisticsRespVO.setDeviceDownMessageStats(deviceLogService.getDeviceLogDownCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime()));
  72 + IotStatisticsDeviceMessageSummaryRespVO iotStatisticsRespVO = new IotStatisticsDeviceMessageSummaryRespVO();
  73 + iotStatisticsRespVO.setUpstreamCounts(deviceLogService.getDeviceLogUpCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime()));
  74 + iotStatisticsRespVO.setDownstreamCounts(deviceLogService.getDeviceLogDownCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime()));
70 75  
71 76 return CommonResult.success(iotStatisticsRespVO);
72 77 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsDeviceMessageSummaryRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.statistics.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.util.List;
  7 +import java.util.Map;
  8 +
  9 +@Schema(description = "管理后台 - Iot 上下行消息数量统计 Response VO")
  10 +@Data
  11 +public class IotStatisticsDeviceMessageSummaryRespVO {
  12 + @Schema(description = "每小时上行数据数量统计")
  13 + private List<Map<Long, Integer>> upstreamCounts;
  14 +
  15 + @Schema(description = "每小时下行数据数量统计")
  16 + private List<Map<Long, Integer>> downstreamCounts;
  17 +
  18 + // TODO @super:如果只有这两个字段,使用 KeyValue 这个键值对
  19 +}
... ...
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 {
11 11 // TODO @supper:times 直接传递哈;
12 12 // TODO 2super:private 不要丢了
13 13  
14   - @Schema(description = "查询起始时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
  14 + @Schema(description = "查询起始时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1658486600000")
15 15 @NotNull(message = "查询起始时间不能为空")
16   - Long startTime;
  16 + private Long startTime;
17 17  
18   - @Schema(description = "查询结束时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
  18 + @Schema(description = "查询结束时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1758486600000")
19 19 @NotNull(message = "查询结束时间不能为空")
20   - Long endTime;
  20 + private Long endTime;
21 21  
22 22 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsRespVO.java renamed to 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;
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.Data;
5 5  
6   -import java.util.List;
  6 +import java.util.Map;
7 7  
8 8 // TODO @super:Total 全部改成 Count
9 9 // TODO @super:IotStatisticsSummaryRespVO
... ... @@ -12,90 +12,58 @@ import java.util.List;
12 12 */
13 13 @Schema(description = "管理后台 - Iot 统计 Response VO")
14 14 @Data
15   -public class IotStatisticsRespVO {
  15 +public class IotStatisticsSummaryRespVO {
16 16  
17 17 // TODO @super:productCategory 哈
18 18 @Schema(description = "品类数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
19   - private long categoryTotal;
  19 + private long productCategoryCount;
20 20  
21 21 @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
22   - private long productTotal;
  22 + private long productCount;
23 23  
24 24 @Schema(description = "设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
25   - private long deviceTotal;
  25 + private long deviceCount;
26 26  
27 27 // TODO @super:deviceMessageCount;设备消息数量
28 28 @Schema(description = "上报数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
29   - private long reportTotal;
  29 + private long deviceMessageCount;
30 30  
31 31 // TODO @super:productCategory 哈
32 32 @Schema(description = "今日新增品类数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
33   - private long categoryTodayTotal;
  33 + private long productCategoryTodayCount;
34 34  
35 35 @Schema(description = "今日新增产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
36   - private long productTodayTotal;
  36 + private long productTodayCount;
37 37  
38 38 @Schema(description = "今日新增设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
39   - private long deviceTodayTotal;
  39 + private long deviceTodayCount;
40 40  
41 41 // TODO @super:deviceMessageCount;今日设备消息数量
42 42 @Schema(description = "今日新增上报数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
43   - private long reportTodayTotal;
  43 + private long deviceMessageTodayCount;
44 44  
45 45 // TODO @super:deviceOnlineCount
46 46  
47 47 @Schema(description = "在线数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "80")
48   - private long onlineTotal;
  48 + private long deviceOnlineCount;
49 49  
50 50 // TODO @super:deviceOfflineCount
51 51  
52 52 @Schema(description = "离线数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15")
53   - private long offlineTotal;
  53 + private long deviceOfflineCount;
54 54  
55 55 // TODO @super:deviceInactivECount
56 56  
57 57 @Schema(description = "待激活设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
58   - private long neverOnlineTotal;
  58 + private long deviceInactiveCount;
59 59  
60 60 // TODO @super:1)类型改成 Map,key 分类名、value 设备数量;2)deviceStatsOfCategory => productCategoryDeviceCounts
61 61 @Schema(description = "按品类统计的设备数量")
62   - private List<DataItem> deviceStatsOfCategory;
  62 + private Map<String, Integer> productCategoryDeviceCounts;
63 63  
64 64 // TODO @super:貌似界面里,用不到这个字段???
65   - @Schema(description = "上报数据数量统计")
66   - private List<TimeData> reportDataStats;
67 65  
68   - // TODO @super:deviceUpMessageStats、deviceDownMessageStats 单独抽到 IotStatisticsDeviceMessageSummaryRespVO,然后里面属性就是 upstreamCounts、downstreamCounts
69   -
70   - @Schema(description = "上行数据数量统计")
71   - private List<TimeData> deviceUpMessageStats;
72   -
73   - @Schema(description = "下行数据数量统计")
74   - private List<TimeData> deviceDownMessageStats;
75   -
76   - // TODO @super:如果只有这两个字段,使用 KeyValue 这个键值对
77   - @Schema(description = "时间数据")
78   - @Data
79   - public static class TimeData {
80   -
81   - @Schema(description = "时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1646092800000")
82   - private long time;
83   -
84   - @Schema(description = "数据值", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
85   - private Object data;
86 66  
87   - }
88   -
89   - @Schema(description = "数据项")
90   - @Data
91   - public static class DataItem {
92   -
93   - @Schema(description = "数据项名", requiredMode = Schema.RequiredMode.REQUIRED, example = "智能家居")
94   - private String name;
95   -
96   - @Schema(description = "数据项值", requiredMode = Schema.RequiredMode.REQUIRED, example = "50")
97   - private Object value;
98   -
99   - }
  67 + // TODO @super:deviceUpMessageStats、deviceDownMessageStats 单独抽到 IotStatisticsDeviceMessageSummaryRespVO,然后里面属性就是 upstreamCounts、downstreamCounts
100 68  
101 69 }
... ...
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
8 8 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
9 9 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
10 10 import org.apache.ibatis.annotations.Mapper;
  11 +import org.apache.ibatis.annotations.Param;
11 12  
12 13 import javax.annotation.Nullable;
13 14 import java.time.LocalDateTime;
14 15 import java.util.List;
  16 +import java.util.Map;
  17 +import java.util.stream.Collectors;
15 18  
16 19 /**
17 20 * IoT 设备 Mapper
... ... @@ -81,4 +84,18 @@ public interface IotDeviceMapper extends BaseMapperX&lt;IotDeviceDO&gt; {
81 84 .eqIfPresent(IotDeviceDO::getState, state));
82 85 }
83 86  
  87 + /**
  88 + * 查询指定产品下各状态的设备数量
  89 + *
  90 + * @return 设备数量统计列表
  91 + */
  92 + List<Map<String, Object>> selectDeviceCountMapByProductId();
  93 +
  94 + /**
  95 + * 查询各个状态下的设备数量
  96 + *
  97 + * @return 设备数量统计列表
  98 + */
  99 + List<Map<String, Object>> selectDeviceCountGroupByState();
  100 +
84 101 }
85 102 \ No newline at end of file
... ...
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&lt;IotProductDO&gt; {
37 37 .geIfPresent(IotProductDO::getCreateTime, createTime));
38 38 }
39 39  
40   - default List<IotProductDO> selectListByCategoryId(Long categoryId) {
41   - return selectList(new LambdaQueryWrapperX<IotProductDO>()
42   - .eq(IotProductDO::getCategoryId, categoryId)
43   - .orderByDesc(IotProductDO::getId));
44   - }
45 40  
46 41 }
47 42 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java
1 1 package cn.iocoder.yudao.module.iot.dal.tdengine;
2 2  
3 3 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO;
4   -import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO;
5 4 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO;
6 5 import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS;
7 6 import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
... ... @@ -10,6 +9,7 @@ import org.apache.ibatis.annotations.Mapper;
10 9 import org.apache.ibatis.annotations.Param;
11 10  
12 11 import java.util.List;
  12 +import java.util.Map;
13 13  
14 14 /**
15 15 * 设备日志 {@link IotDeviceLogDO} Mapper 接口
... ... @@ -60,27 +60,17 @@ public interface IotDeviceLogMapper {
60 60 // TODO @super:1)上行、下行,不写在 mapper 里,而是通过参数传递,这样,selectDeviceLogUpCountByHour、selectDeviceLogDownCountByHour 可以合并;
61 61 // TODO @super:2)不能只基于 identifier 来计算,而是要 type + identifier 成对
62 62 /**
63   - * 获得每个小时设备上行消息数量统计
64   - *
65   - * @param deviceKey 设备标识
66   - * @param startTime 开始时间
67   - * @param endTime 结束时间
68   - * @return 每小时消息数量统计
  63 + * 查询每个小时设备上行消息数量
69 64 */
70   - List<IotStatisticsRespVO.TimeData> selectDeviceLogUpCountByHour(@Param("deviceKey") String deviceKey,
71   - @Param("startTime") Long startTime,
72   - @Param("endTime") Long endTime);
  65 + List<Map<String, Object>> selectDeviceLogUpCountByHour(@Param("deviceKey") String deviceKey,
  66 + @Param("startTime") Long startTime,
  67 + @Param("endTime") Long endTime);
73 68  
74 69 /**
75   - * 获得每个小时设备下行消息数量统计
76   - *
77   - * @param deviceKey 设备标识
78   - * @param startTime 开始时间
79   - * @param endTime 结束时间
80   - * @return 每小时消息数量统计
  70 + * 查询每个小时设备下行消息数量
81 71 */
82   - List<IotStatisticsRespVO.TimeData> selectDeviceLogDownCountByHour(@Param("deviceKey") String deviceKey,
83   - @Param("startTime") Long startTime,
84   - @Param("endTime") Long endTime);
  72 + List<Map<String, Object>> selectDeviceLogDownCountByHour(@Param("deviceKey") String deviceKey,
  73 + @Param("startTime") Long startTime,
  74 + @Param("endTime") Long endTime);
85 75  
86 76 }
... ...
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;
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*;
5 5 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
  6 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
6 7 import jakarta.validation.Valid;
7 8 import jakarta.validation.constraints.NotEmpty;
8 9  
... ... @@ -10,6 +11,7 @@ import javax.annotation.Nullable;
10 11 import java.time.LocalDateTime;
11 12 import java.util.Collection;
12 13 import java.util.List;
  14 +import java.util.Map;
13 15  
14 16 /**
15 17 * IoT 设备 Service 接口
... ... @@ -111,7 +113,7 @@ public interface IotDeviceService {
111 113 IotDeviceDO getDeviceByDeviceKey(String deviceKey);
112 114  
113 115 /**
114   - * ��得设备分页
  116 + * 获得设备分页
115 117 *
116 118 * @param pageReqVO 分页查询
117 119 * @return IoT 设备分页
... ... @@ -194,13 +196,6 @@ public interface IotDeviceService {
194 196 */
195 197 Long getDeviceCount(@Nullable LocalDateTime createTime);
196 198  
197   - /**
198   - * 获得设备数量,基于状态
199   - *
200   - * @param state 状态
201   - * @return 设备数量
202   - */
203   - Long getDeviceCountByState(Integer state);
204 199  
205 200 /**
206 201 * 获得所有设备列表
... ... @@ -217,4 +212,19 @@ public interface IotDeviceService {
217 212 */
218 213 IotDeviceMqttConnectionParamsRespVO getMqttConnectionParams(Long deviceId);
219 214  
  215 + /**
  216 + * 获得各个产品下的设备数量 Map
  217 + *
  218 + * @return key: 产品编号, value: 设备数量
  219 + */
  220 + Map<Long, Integer> getDeviceCountMapByProductId();
  221 +
  222 + /**
  223 + * 获得各个状态下的设备数量 Map
  224 + *
  225 + * @return key: 设备状态枚举 {@link IotDeviceStateEnum}
  226 + * value: 设备数量
  227 + */
  228 + Map<Integer, Long> getDeviceCountMapByState();
  229 +
220 230 }
221 231 \ No newline at end of file
... ...
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;
35 35 import javax.annotation.Nullable;
36 36 import java.time.LocalDateTime;
37 37 import java.util.*;
  38 +import java.util.stream.Collectors;
38 39  
39 40 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
40 41 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
... ... @@ -430,14 +431,30 @@ public class IotDeviceServiceImpl implements IotDeviceService {
430 431 }
431 432  
432 433 // TODO @super:是不是 groupby 查询,更高效;不过 controller,还是要考虑 null 的情况;不过可以直接枚举 foreach 处理下
433   - @Override
434   - public Long getDeviceCountByState(Integer state) {
435   - return deviceMapper.selectCountByState(state);
436   - }
437 434  
438 435 @Override
439 436 public List<IotDeviceDO> getDeviceList() {
440 437 return deviceMapper.selectList();
441 438 }
442 439  
  440 + @Override
  441 + public Map<Long, Integer> getDeviceCountMapByProductId() {
  442 + // 查询结果转换成Map
  443 + List<Map<String, Object>> list = deviceMapper.selectDeviceCountMapByProductId();
  444 + return list.stream().collect(Collectors.toMap(
  445 + map -> Long.valueOf(map.get("key").toString()),
  446 + map -> Integer.valueOf(map.get("value").toString())
  447 + ));
  448 + }
  449 +
  450 + @Override
  451 + public Map<Integer, Long> getDeviceCountMapByState() {
  452 + // 查询结果转换成Map
  453 + List<Map<String, Object>> list = deviceMapper.selectDeviceCountGroupByState();
  454 + return list.stream().collect(Collectors.toMap(
  455 + map -> Integer.valueOf(map.get("key").toString()),
  456 + map -> Long.valueOf(map.get("value").toString())
  457 + ));
  458 + }
  459 +
443 460 }
444 461 \ No newline at end of file
... ...
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;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO;
5   -import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO;
  5 +import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsDeviceMessageSummaryRespVO;
6 6 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO;
7 7 import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
8 8  
9 9 import javax.annotation.Nullable;
10 10 import java.time.LocalDateTime;
11 11 import java.util.List;
  12 +import java.util.Map;
12 13  
13 14 /**
14 15 * IoT 设备日志数据 Service 接口
... ... @@ -50,25 +51,25 @@ public interface IotDeviceLogService {
50 51 /**
51 52 * 获得每个小时设备上行消息数量统计
52 53 *
53   - * @param deviceKey 设备标识,如果为空,则统计所有设备
54   - * @param startTime 开始时间,如果为空,则不限制开始时间
55   - * @param endTime 结束时间,如果为空,则不限制结束时间
56   - * @return 每小时消息数量统计列表
  54 + * @param deviceKey 设备标识
  55 + * @param startTime 开始时间
  56 + * @param endTime 结束时间
  57 + * @return key: 时间戳, value: 消息数量
57 58 */
58   - List<IotStatisticsRespVO.TimeData> getDeviceLogUpCountByHour(@Nullable String deviceKey,
59   - @Nullable Long startTime,
60   - @Nullable Long endTime);
  59 + List<Map<Long, Integer>> getDeviceLogUpCountByHour(@Nullable String deviceKey,
  60 + @Nullable Long startTime,
  61 + @Nullable Long endTime);
61 62  
62 63 /**
63 64 * 获得每个小时设备下行消息数量统计
64 65 *
65   - * @param deviceKey 设备标识,如果为空,则统计所有设备
66   - * @param startTime 开始时间,如果为空,则不限制开始时间
67   - * @param endTime 结束时间,如果为空,则不限制结束时间
68   - * @return 每小时消息数量统计列表
  66 + * @param deviceKey 设备标识
  67 + * @param startTime 开始时间
  68 + * @param endTime 结束时间
  69 + * @return key: 时间戳, value: 消息数量
69 70 */
70   - List<IotStatisticsRespVO.TimeData> getDeviceLogDownCountByHour(@Nullable String deviceKey,
71   - @Nullable Long startTime,
72   - @Nullable Long endTime);
  71 + List<Map<Long, Integer>> getDeviceLogDownCountByHour(@Nullable String deviceKey,
  72 + @Nullable Long startTime,
  73 + @Nullable Long endTime);
73 74  
74 75 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java
1 1 package cn.iocoder.yudao.module.iot.service.device.data;
2 2  
  3 +import cn.hutool.core.date.LocalDateTimeUtil;
3 4 import cn.hutool.core.util.IdUtil;
4 5 import cn.hutool.core.util.StrUtil;
5 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 7 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
7 8 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
8 9 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO;
9   -import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO;
  10 +import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsDeviceMessageSummaryRespVO;
10 11 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO;
11 12 import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogMapper;
12 13 import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
... ... @@ -17,10 +18,11 @@ import lombok.extern.slf4j.Slf4j;
17 18 import org.springframework.stereotype.Service;
18 19 import org.springframework.validation.annotation.Validated;
19 20  
  21 +import java.sql.Timestamp;
20 22 import java.time.LocalDateTime;
21   -import java.time.ZoneOffset;
22   -import java.util.ArrayList;
23 23 import java.util.List;
  24 +import java.util.Map;
  25 +import java.util.stream.Collectors;
24 26  
25 27 /**
26 28 * IoT 设备日志数据 Service 实现类
... ... @@ -71,37 +73,39 @@ public class IotDeviceLogServiceImpl implements IotDeviceLogService {
71 73  
72 74 @Override
73 75 public Long getDeviceLogCount(LocalDateTime createTime) {
74   - Long time = null;
75   - if (createTime != null) {
76 76 // todo @super:1)LocalDateTimeUtil.toEpochMilli(createTime);2)直接表达式,更简洁 time != null ? createTime.toInstant(ZoneOffset.UTC).toEpochMilli() : null;
77   - time = createTime.toInstant(ZoneOffset.UTC).toEpochMilli();
78   - }
79   - return deviceLogMapper.selectCountByCreateTime(time);
  77 + return deviceLogMapper.selectCountByCreateTime(createTime != null ? LocalDateTimeUtil.toEpochMilli(createTime) : null);
80 78 }
81 79  
82 80 // TODO @super:加一个参数,Boolean upstream:true 上行,false 下行,null 不过滤
83 81 @Override
84   - public List<IotStatisticsRespVO.TimeData> getDeviceLogUpCountByHour(String deviceKey, Long startTime, Long endTime) {
85   - try {
86   - return deviceLogMapper.selectDeviceLogUpCountByHour(deviceKey, startTime, endTime);
87   - } catch (Exception exception) {
88   - if (exception.getMessage().contains("Table does not exist")) {
89   - return new ArrayList<>();
90   - }
91   - throw exception;
92   - }
  82 + public List<Map<Long, Integer>> getDeviceLogUpCountByHour(String deviceKey, Long startTime, Long endTime) {
  83 + List<Map<String, Object>> list = deviceLogMapper.selectDeviceLogUpCountByHour(deviceKey, startTime, endTime);
  84 + return list.stream()
  85 + .map(map -> {
  86 + // 从Timestamp获取时间戳
  87 + Timestamp timestamp = (Timestamp) map.get("time");
  88 + Long timeMillis = timestamp.getTime();
  89 + // 消息数量转换
  90 + Integer count = ((Number) map.get("data")).intValue();
  91 + return Map.of(timeMillis, count);
  92 + })
  93 + .collect(Collectors.toList());
93 94 }
94 95  
95 96 @Override
96   - public List<IotStatisticsRespVO.TimeData> getDeviceLogDownCountByHour(String deviceKey, Long startTime, Long endTime) {
97   - try {
98   - return deviceLogMapper.selectDeviceLogDownCountByHour(deviceKey, startTime, endTime);
99   - } catch (Exception exception) {
100   - if (exception.getMessage().contains("Table does not exist")) {
101   - return new ArrayList<>();
102   - }
103   - throw exception;
104   - }
  97 + public List<Map<Long, Integer>> getDeviceLogDownCountByHour(String deviceKey, Long startTime, Long endTime) {
  98 + List<Map<String, Object>> list = deviceLogMapper.selectDeviceLogDownCountByHour(deviceKey, startTime, endTime);
  99 + return list.stream()
  100 + .map(map -> {
  101 + // 从Timestamp获取时间戳
  102 + Timestamp timestamp = (Timestamp) map.get("time");
  103 + Long timeMillis = timestamp.getTime();
  104 + // 消息数量转换
  105 + Integer count = ((Number) map.get("data")).intValue();
  106 + return Map.of(timeMillis, count);
  107 + })
  108 + .collect(Collectors.toList());
105 109 }
106 110  
107 111 }
... ...
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;
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategoryPageReqVO;
5 5 import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategorySaveReqVO;
6   -import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO;
7 6 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductCategoryDO;
8 7 import jakarta.validation.Valid;
9 8  
... ... @@ -100,6 +99,6 @@ public interface IotProductCategoryService {
100 99 *
101 100 * @return 品类设备统计列表
102 101 */
103   - List<IotStatisticsRespVO.DataItem> getDeviceCountsOfProductCategory();
  102 + Map<String, Integer> getProductCategoryDeviceCountMap();
104 103  
105 104 }
106 105 \ No newline at end of file
... ...
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;
5 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6 6 import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategoryPageReqVO;
7 7 import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategorySaveReqVO;
8   -import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO;
9   -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
10 8 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductCategoryDO;
11 9 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
12 10 import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductCategoryMapper;
... ... @@ -16,11 +14,7 @@ import org.springframework.stereotype.Service;
16 14 import org.springframework.validation.annotation.Validated;
17 15  
18 16 import java.time.LocalDateTime;
19   -import java.util.Collection;
20   -import java.util.HashMap;
21   -import java.util.List;
22   -import java.util.Map;
23   -import java.util.stream.Collectors;
  17 +import java.util.*;
24 18  
25 19 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
26 20 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_CATEGORY_NOT_EXISTS;
... ... @@ -103,54 +97,30 @@ public class IotProductCategoryServiceImpl implements IotProductCategoryService
103 97 }
104 98  
105 99 @Override
106   - public List<IotStatisticsRespVO.DataItem> getDeviceCountsOfProductCategory() {
  100 + public Map<String, Integer> getProductCategoryDeviceCountMap() {
107 101 // 1. 获取所有数据
108 102 List<IotProductCategoryDO> categoryList = productCategoryMapper.selectList();
109 103 List<IotProductDO> productList = productService.getProductList();
110 104 // TODO @super:不要 list 查询,返回内存,而是查询一个 Map<productId, count>
111   - List<IotDeviceDO> deviceList = deviceService.getDeviceList();
  105 + Map<Long, Integer> deviceCountMapByProductId = deviceService.getDeviceCountMapByProductId();
112 106  
113 107 // 2. 统计每个分类下的设备数量
114 108 Map<String, Integer> categoryDeviceCountMap = new HashMap<>();
115   -
  109 +
116 110 // 2.1 初始化所有分类的计数为0
117 111 for (IotProductCategoryDO category : categoryList) {
118 112 categoryDeviceCountMap.put(category.getName(), 0);
119   - // TODO @super:直接这里面计算,不用多个循环。产品本身也不多,不用构建 Map,直接 filter 就好了
120   - }
121   -
122   - // 2.2 构建产品ID到分类的映射
123   - Map<Long, IotProductCategoryDO> productCategoryMap = new HashMap<>();
124   - for (IotProductDO product : productList) {
125   - Long categoryId = product.getCategoryId();
126   - IotProductCategoryDO category = categoryList.stream()
127   - .filter(c -> c.getId().equals(categoryId))
128   - .findFirst()
129   - .orElse(null);
130   - if (category != null) {
131   - productCategoryMap.put(product.getId(), category);
132   - }
133   - }
134   -
135   - // 2.3 统计每个分类下的设备数量
136   - for (IotDeviceDO device : deviceList) {
137   - Long productId = device.getProductId();
138   - IotProductCategoryDO category = productCategoryMap.get(productId);
139   - if (category != null) {
140   - String categoryName = category.getName();
141   - categoryDeviceCountMap.merge(categoryName, 1, Integer::sum);
  113 +
  114 + // 2.2 找到该分类下的所有产品,累加设备数量
  115 + for (IotProductDO product : productList) {
  116 + if (Objects.equals(product.getCategoryId(), category.getId())) {
  117 + Integer deviceCount = deviceCountMapByProductId.getOrDefault(product.getId(), 0);
  118 + categoryDeviceCountMap.merge(category.getName(), deviceCount, Integer::sum);
  119 + }
142 120 }
143 121 }
144 122  
145   - // 3. 转换为 DataItem 列表
146   - return categoryDeviceCountMap.entrySet().stream()
147   - .map(entry -> {
148   - IotStatisticsRespVO.DataItem dataItem = new IotStatisticsRespVO.DataItem();
149   - dataItem.setName(entry.getKey());
150   - dataItem.setValue(entry.getValue());
151   - return dataItem;
152   - })
153   - .collect(Collectors.toList());
  123 + return categoryDeviceCountMap;
154 124 }
155 125  
156 126 }
157 127 \ No newline at end of file
... ...
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 {
102 102 */
103 103 Long getProductCount(@Nullable LocalDateTime createTime);
104 104  
105   - // TODO @super:用不到的,删除下哈
106   - /**
107   - * 获得产品列表,基于分类编号
108   - *
109   - * @param categoryId 分类编号
110   - * @return 产品列表
111   - */
112   - List<IotProductDO> getProductListByCategoryId(Long categoryId);
113 105  
114 106 }
115 107 \ No newline at end of file
... ...
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 {
143 143 return productMapper.selectCountByCreateTime(createTime);
144 144 }
145 145  
146   - @Override
147   - public List<IotProductDO> getProductListByCategoryId(Long categoryId) {
148   - return productMapper.selectListByCategoryId(categoryId);
149   - }
150 146  
151 147 }
152 148 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogMapper.xml
... ... @@ -65,7 +65,7 @@
65 65 </where>
66 66 </select>
67 67  
68   - <select id="selectDeviceLogUpCountByHour" resultType="cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO$TimeData">
  68 + <select id="selectDeviceLogUpCountByHour" resultType="java.util.Map">
69 69 SELECT
70 70 TIMETRUNCATE(ts, 1h) as time,
71 71 COUNT(*) as data
... ... @@ -93,7 +93,7 @@
93 93 ORDER BY time ASC
94 94 </select>
95 95  
96   - <select id="selectDeviceLogDownCountByHour" resultType="cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO$TimeData">
  96 + <select id="selectDeviceLogDownCountByHour" resultType="java.util.Map">
97 97 SELECT
98 98 TIMETRUNCATE(ts, 1h) as time,
99 99 COUNT(*) as data
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper
  3 + PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4 + "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5 +<mapper namespace="cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper">
  6 +
  7 + <select id="selectDeviceCountGroupByState" resultType="java.util.Map">
  8 + SELECT
  9 + state AS `key`,
  10 + COUNT(1) AS `value`
  11 + FROM iot_device
  12 + WHERE deleted = 0
  13 + GROUP BY state
  14 + </select>
  15 +
  16 + <select id="selectDeviceCountMapByProductId" resultType="java.util.Map">
  17 + SELECT
  18 + product_id AS `key`,
  19 + COUNT(1) AS `value`
  20 + FROM iot_device
  21 + WHERE deleted = 0
  22 + GROUP BY product_id
  23 + </select>
  24 +
  25 +</mapper>
0 26 \ No newline at end of file
... ...