Merge branch 'feature/iot' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into feature/iot

This commit is contained in:
YunaiV 2025-02-27 12:50:33 +08:00
commit 2a65e3bd2e
20 changed files with 586 additions and 4 deletions

View File

@ -0,0 +1,75 @@
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.IotStatisticsReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO;
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;
import cn.iocoder.yudao.module.iot.service.product.IotProductCategoryService;
import cn.iocoder.yudao.module.iot.service.product.IotProductService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
@Tag(name = "管理后台 - IoT 数据统计")
@RestController
@RequestMapping("/iot/statistics")
@Validated
public class IotStatisticsController {
@Resource
private IotDeviceService iotDeviceService;
@Resource
private IotProductCategoryService iotProductCategoryService;
@Resource
private IotProductService iotProductService;
@Resource
private IotDeviceLogService iotDeviceLogService;
@GetMapping("/main")
@Operation(summary = "获取IOT首页的数据统计", description = "用于IOT首页的数据统计")
public CommonResult<IotStatisticsRespVO> getIotMainStats(@Valid IotStatisticsReqVO reqVO){
IotStatisticsRespVO iotStatisticsRespVO = new IotStatisticsRespVO();
// 获取总数
iotStatisticsRespVO.setCategoryTotal(iotProductCategoryService.getProductCategoryCount(null));
iotStatisticsRespVO.setProductTotal(iotProductService.getProductCount(null));
iotStatisticsRespVO.setDeviceTotal(iotDeviceService.getDeviceCount(null));
iotStatisticsRespVO.setReportTotal(iotDeviceLogService.getDeviceLogCount(null));
// 获取今日新增数量
LocalDateTime todayStart = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0);
iotStatisticsRespVO.setCategoryTodayTotal(iotProductCategoryService.getProductCategoryCount(todayStart));
iotStatisticsRespVO.setProductTodayTotal(iotProductService.getProductCount(todayStart));
iotStatisticsRespVO.setDeviceTodayTotal(iotDeviceService.getDeviceCount(todayStart));
iotStatisticsRespVO.setReportTodayTotal(iotDeviceLogService.getDeviceLogCount(todayStart));
// 获取各个品类下设备数量统计
iotStatisticsRespVO.setDeviceStatsOfCategory(
iotProductCategoryService.getDeviceCountsOfProductCategory()
);
// 获取设备状态数量统计
iotStatisticsRespVO.setOnlineTotal(iotDeviceService.getDeviceCountByState(IotDeviceStateEnum.ONLINE.getState()));
iotStatisticsRespVO.setOfflineTotal(iotDeviceService.getDeviceCountByState(IotDeviceStateEnum.OFFLINE.getState()));
iotStatisticsRespVO.setNeverOnlineTotal(iotDeviceService.getDeviceCountByState(IotDeviceStateEnum.INACTIVE.getState()));
// 根据传入时间范围获取设备上下行消息数量统计
iotStatisticsRespVO.setDeviceUpMessageStats(iotDeviceLogService.getDeviceLogUpCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime()));
iotStatisticsRespVO.setDeviceDownMessageStats(iotDeviceLogService.getDeviceLogDownCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime()));
return CommonResult.success(iotStatisticsRespVO);
}
}

View File

@ -0,0 +1,16 @@
package cn.iocoder.yudao.module.iot.controller.admin.statistics.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Schema(description = "管理后台 - Iot统计 Request VO")
@Data
public class IotStatisticsReqVO {
@Schema(description = "查询起始时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
@NotNull(message = "查询起始时间不能为空")
Long startTime;
@Schema(description = "查询结束时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
@NotNull(message = "查询结束时间不能为空")
Long endTime;
}

View File

@ -0,0 +1,78 @@
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;
@Schema(description = "管理后台 - Iot统计 Response VO")
@Data
public class IotStatisticsRespVO {
@Schema(description = "品类数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
private long categoryTotal;
@Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
private long productTotal;
@Schema(description = "设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
private long deviceTotal;
@Schema(description = "上报数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
private long reportTotal;
@Schema(description = "今日新增品类数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
private long categoryTodayTotal;
@Schema(description = "今日新增产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
private long productTodayTotal;
@Schema(description = "今日新增设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
private long deviceTodayTotal;
@Schema(description = "今日新增上报数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
private long reportTodayTotal;
@Schema(description = "在线数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "80")
private long onlineTotal;
@Schema(description = "离线数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15")
private long offlineTotal;
@Schema(description = "待激活设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
private long neverOnlineTotal;
@Schema(description = "上报数据数量统计")
private List<TimeData> reportDataStats;
@Schema(description = "上行数据数量统计")
private List<TimeData> deviceUpMessageStats;
@Schema(description = "下行数据数量统计")
private List<TimeData> deviceDownMessageStats;
@Schema(description = "按品类统计的设备数量")
private List<DataItem> deviceStatsOfCategory;
@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;
}
}

View File

@ -9,6 +9,7 @@ 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 java.time.LocalDateTime;
import java.util.List;
/**
@ -69,4 +70,26 @@ public interface IotDeviceMapper extends BaseMapperX<IotDeviceDO> {
.apply("FIND_IN_SET(" + groupId + ",group_ids) > 0"));
}
/**
* 统计设备数量
*
* @param createTime 创建时间如果为空则统计所有设备数量
* @return 设备数量
*/
default Long selectCountByCreateTime(LocalDateTime createTime) {
return selectCount(new LambdaQueryWrapperX<IotDeviceDO>()
.geIfPresent(IotDeviceDO::getCreateTime, createTime));
}
/**
* 统计指定状态的设备数量
*
* @param state 状态
* @return 设备数量
*/
default Long selectCountByState(Integer state) {
return selectCount(new LambdaQueryWrapperX<IotDeviceDO>()
.eqIfPresent(IotDeviceDO::getState, state));
}
}

View File

@ -6,7 +6,9 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategoryPageReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductCategoryDO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDateTime;
import java.util.List;
/**
@ -28,4 +30,15 @@ public interface IotProductCategoryMapper extends BaseMapperX<IotProductCategory
return selectList(IotProductCategoryDO::getStatus, status);
}
/**
* 统计产品分类数量
*
* @param createTime 创建时间如果为空则统计所有分类数量
* @return 产品分类数量
*/
default Long selectCountByCreateTime(LocalDateTime createTime) {
return selectCount(new LambdaQueryWrapperX<IotProductCategoryDO>()
.geIfPresent(IotProductCategoryDO::getCreateTime, createTime));
}
}

View File

@ -8,6 +8,9 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.ibatis.annotations.Mapper;
import java.time.LocalDateTime;
import java.util.List;
/**
* IoT 产品 Mapper
*
@ -28,4 +31,27 @@ public interface IotProductMapper extends BaseMapperX<IotProductDO> {
.apply("LOWER(product_key) = {0}", productKey.toLowerCase()));
}
/**
* 统计产品数量
*
* @param createTime 创建时间如果为空则统计所有产品数量
* @return 产品数量
*/
default Long selectCountByCreateTime(LocalDateTime createTime) {
return selectCount(new LambdaQueryWrapperX<IotProductDO>()
.geIfPresent(IotProductDO::getCreateTime, createTime));
}
/**
* 获得产品列表基于分类编号
*
* @param categoryId 分类编号
* @return 产品列表
*/
default List<IotProductDO> selectListByCategoryId(Long categoryId) {
return selectList(new LambdaQueryWrapperX<IotProductDO>()
.eq(IotProductDO::getCategoryId, categoryId)
.orderByDesc(IotProductDO::getId));
}
}

View File

@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelP
import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
import org.apache.ibatis.annotations.Mapper;
import java.time.LocalDateTime;
import java.util.List;
/**
@ -72,4 +73,15 @@ public interface IotThingModelMapper extends BaseMapperX<IotThingModelDO> {
IotThingModelDO::getName, name);
}
/**
* 统计物模型数量
*
* @param createTime 创建时间如果为空则统计所有物模型数量
* @return 物模型数量
*/
default Long selectCountByCreateTime(LocalDateTime createTime) {
return selectCount(new LambdaQueryWrapperX<IotThingModelDO>()
.geIfPresent(IotThingModelDO::getCreateTime, createTime));
}
}

View File

@ -1,6 +1,7 @@
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;
@ -8,6 +9,9 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDateTime;
import java.util.List;
/**
* 设备日志 {@link IotDeviceLogDO} Mapper 接口
*/
@ -46,4 +50,36 @@ public interface IotDeviceLogMapper {
IPage<IotDeviceLogDO> selectPage(IPage<IotDeviceLogDO> page,
@Param("reqVO") IotDeviceLogPageReqVO reqVO);
/**
* 统计设备日志数量
*
* @param createTime 创建时间如果为空则统计所有日志数量
* @return 日志数量
*/
Long selectCountByCreateTime(@Param("createTime") Long createTime);
/**
* 获得每个小时设备上行消息数量统计
*
* @param deviceKey 设备标识
* @param startTime 开始时间
* @param endTime 结束时间
* @return 每小时消息数量统计
*/
List<IotStatisticsRespVO.TimeData> selectDeviceLogUpCountByHour(@Param("deviceKey") String deviceKey,
@Param("startTime") Long startTime,
@Param("endTime") Long endTime);
/**
* 获得每个小时设备下行消息数量统计
*
* @param deviceKey 设备标识
* @param startTime 开始时间
* @param endTime 结束时间
* @return 每小时消息数量统计
*/
List<IotStatisticsRespVO.TimeData> selectDeviceLogDownCountByHour(@Param("deviceKey") String deviceKey,
@Param("startTime") Long startTime,
@Param("endTime") Long endTime);
}

View File

@ -7,6 +7,7 @@ import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import javax.annotation.Nullable;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
@ -185,6 +186,29 @@ public interface IotDeviceService {
*/
IotDeviceImportRespVO importDevice(List<IotDeviceImportExcelVO> importDevices, boolean updateSupport);
/**
* 获得设备数量
*
* @param createTime 创建时间如果为空则统计所有设备数量
* @return 设备数量
*/
Long getDeviceCount(LocalDateTime createTime);
/**
* 获得设备数量基于状态
*
* @param state 状态
* @return 设备数量
*/
Long getDeviceCountByState(Integer state);
/**
* 获得所有设备列表
*
* @return 设备列表
*/
List<IotDeviceDO> getDeviceList();
/**
* 获取 MQTT 连接参数
*

View File

@ -424,4 +424,19 @@ public class IotDeviceServiceImpl implements IotDeviceService {
return SpringUtil.getBean(getClass());
}
@Override
public Long getDeviceCount(LocalDateTime createTime) {
return deviceMapper.selectCountByCreateTime(createTime);
}
@Override
public Long getDeviceCountByState(Integer state) {
return deviceMapper.selectCountByState(state);
}
@Override
public List<IotDeviceDO> getDeviceList() {
return deviceMapper.selectList();
}
}

View File

@ -2,8 +2,13 @@ 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.dal.dataobject.device.IotDeviceLogDO;
import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDateTime;
import java.util.List;
/**
* IoT 设备日志数据 Service 接口
@ -34,4 +39,32 @@ public interface IotDeviceLogService {
*/
PageResult<IotDeviceLogDO> getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO);
/**
* 获得设备日志数量
*
* @param createTime 创建时间如果为空则统计所有日志数量
* @return 日志数量
*/
Long getDeviceLogCount(LocalDateTime createTime);
/**
* 获得每个小时设备上行消息数量统计
*
* @param deviceKey 设备标识如果为空则统计所有设备
* @param startTime 开始时间如果为空则不限制开始时间
* @param endTime 结束时间如果为空则不限制结束时间
* @return 每小时消息数量统计列表
*/
List<IotStatisticsRespVO.TimeData> getDeviceLogUpCountByHour(String deviceKey, Long startTime, Long endTime);
/**
* 获得每个小时设备下行消息数量统计
*
* @param deviceKey 设备标识如果为空则统计所有设备
* @param startTime 开始时间如果为空则不限制开始时间
* @param endTime 结束时间如果为空则不限制结束时间
* @return 每小时消息数量统计列表
*/
List<IotStatisticsRespVO.TimeData> getDeviceLogDownCountByHour( String deviceKey, Long startTime, Long endTime);
}

View File

@ -6,6 +6,7 @@ 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.dal.dataobject.device.IotDeviceLogDO;
import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogMapper;
import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
@ -16,6 +17,11 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
/**
* IoT 设备日志数据 Service 实现类
*
@ -63,4 +69,37 @@ public class IotDeviceLogServiceImpl implements IotDeviceLogService {
}
}
@Override
public Long getDeviceLogCount(LocalDateTime createTime) {
Long time = null;
if (createTime != null) {
time = createTime.toInstant(ZoneOffset.UTC).toEpochMilli();
}
return deviceLogMapper.selectCountByCreateTime(time);
}
@Override
public List<IotStatisticsRespVO.TimeData> 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;
}
}
@Override
public List<IotStatisticsRespVO.TimeData> 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;
}
}
}

View File

@ -3,9 +3,11 @@ 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;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@ -83,4 +85,19 @@ public interface IotProductCategoryService {
*/
List<IotProductCategoryDO> getProductCategoryListByStatus(Integer status);
/**
* 获得产品分类数量
*
* @param createTime 创建时间如果为空则统计所有分类数量
* @return 产品分类数量
*/
Long getProductCategoryCount(LocalDateTime createTime);
/**
* 获得各个品类下设备数量统计
*
* @return 品类设备统计列表
*/
List<IotStatisticsRespVO.DataItem> getDeviceCountsOfProductCategory();
}

View File

@ -5,14 +5,23 @@ 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;
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
import cn.iocoder.yudao.module.iot.service.product.IotProductCategoryService;
import jakarta.annotation.Resource;
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 static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_CATEGORY_NOT_EXISTS;
@ -29,7 +38,12 @@ public class IotProductCategoryServiceImpl implements IotProductCategoryService
@Resource
private IotProductCategoryMapper productCategoryMapper;
@Override
@Resource
private IotProductService productService;
@Resource
private IotDeviceService deviceService;
public Long createProductCategory(IotProductCategorySaveReqVO createReqVO) {
// 插入
IotProductCategoryDO productCategory = BeanUtils.toBean(createReqVO, IotProductCategoryDO.class);
@ -84,4 +98,58 @@ public class IotProductCategoryServiceImpl implements IotProductCategoryService
return productCategoryMapper.selectListByStatus(status);
}
@Override
public Long getProductCategoryCount(LocalDateTime createTime) {
return productCategoryMapper.selectCountByCreateTime(createTime);
}
@Override
public List<IotStatisticsRespVO.DataItem> getDeviceCountsOfProductCategory() {
// 1. 获取所有数据
List<IotProductCategoryDO> categoryList = productCategoryMapper.selectList();
List<IotProductDO> productList = productService.getProductList();
List<IotDeviceDO> deviceList = deviceService.getDeviceList();
// 2. 统计每个分类下的设备数量
Map<String, Integer> categoryDeviceCountMap = new HashMap<>();
// 2.1 初始化所有分类的计数为0
for (IotProductCategoryDO category : categoryList) {
categoryDeviceCountMap.put(category.getName(), 0);
}
// 2.2 构建产品ID到分类的映射
Map<Long, IotProductCategoryDO> 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.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());
}
}

View File

@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProduc
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import jakarta.validation.Valid;
import java.time.LocalDateTime;
import java.util.List;
/**
@ -92,4 +93,20 @@ public interface IotProductService {
*/
List<IotProductDO> getProductList();
/**
* 获得产品数量
*
* @param createTime 创建时间如果为空则统计所有产品数量
* @return 产品数量
*/
Long getProductCount(LocalDateTime createTime);
/**
* 获得产品列表基于分类编号
*
* @param categoryId 分类编号
* @return 产品列表
*/
List<IotProductDO> getProductListByCategoryId(Long categoryId);
}

View File

@ -15,6 +15,7 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
@ -137,4 +138,14 @@ public class IotProductServiceImpl implements IotProductService {
return productMapper.selectList();
}
@Override
public Long getProductCount(LocalDateTime createTime) {
return productMapper.selectCountByCreateTime(createTime);
}
@Override
public List<IotProductDO> getProductListByCategoryId(Long categoryId) {
return productMapper.selectListByCategoryId(categoryId);
}
}

View File

@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelS
import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
import jakarta.validation.Valid;
import java.time.LocalDateTime;
import java.util.List;
/**
@ -80,4 +81,12 @@ public interface IotThingModelService {
*/
List<IotThingModelDO> getThingModelList(IotThingModelListReqVO reqVO);
/**
* 获得物模型数量
*
* @param createTime 创建时间如果为空则统计所有物模型数量
* @return 物模型数量
*/
Long getThingModelCount(LocalDateTime createTime);
}

View File

@ -29,6 +29,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.time.LocalDateTime;
import java.util.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -363,4 +364,9 @@ public class IotThingModelServiceImpl implements IotThingModelService {
return SpringUtil.getBean(getClass());
}
@Override
public Long getThingModelCount(LocalDateTime createTime) {
return thingModelMapper.selectCountByCreateTime(createTime);
}
}

View File

@ -55,4 +55,68 @@
ORDER BY ts DESC
</select>
<select id="selectCountByCreateTime" resultType="Long">
SELECT COUNT(*)
FROM device_log
<where>
<if test="createTime != null">
AND ts >= #{createTime}
</if>
</where>
</select>
<select id="selectDeviceLogUpCountByHour" resultType="cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO$TimeData">
SELECT
TIMETRUNCATE(ts, 1h) as time,
COUNT(*) as data
FROM
<choose>
<when test="deviceKey != null and deviceKey != ''">
device_log_${deviceKey}
</when>
<otherwise>
device_log
</otherwise>
</choose>
<where>
<if test="startTime != null">
AND ts >= #{startTime}
</if>
<if test="endTime != null">
AND ts &lt;= #{endTime}
</if>
AND (
identifier IN ('online', 'offline', 'pull', 'progress', 'report', 'register', 'register_sub')
)
</where>
GROUP BY TIMETRUNCATE(ts, 1h)
ORDER BY time ASC
</select>
<select id="selectDeviceLogDownCountByHour" resultType="cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO$TimeData">
SELECT
TIMETRUNCATE(ts, 1h) as time,
COUNT(*) as data
FROM
<choose>
<when test="deviceKey != null and deviceKey != ''">
device_log_${deviceKey}
</when>
<otherwise>
device_log
</otherwise>
</choose>
<where>
<if test="startTime != null">
AND ts >= #{startTime}
</if>
<if test="endTime != null">
AND ts &lt;= #{endTime}
</if>
AND identifier IN ('set', 'get', 'upgrade', 'unregister_sub', 'topology_add')
</where>
GROUP BY TIMETRUNCATE(ts, 1h)
ORDER BY time ASC
</select>
</mapper>

View File

@ -78,10 +78,10 @@ spring:
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
data:
redis:
host: 127.0.0.1 # 地址
host: chaojiniu.top # 地址
port: 6379 # 端口
database: 1 # 数据库索引
# password: 123456 # 密码,建议生产环境开启
database: 15 # 数据库索引
password: fsknKD7UvQYZsyf2hXXn # 密码,建议生产环境开启
--- #################### 定时任务相关配置 ####################