【新增功能】 设备历史数据展示
This commit is contained in:
parent
624f5283b3
commit
d7b8cf547f
|
@ -4,24 +4,24 @@ import lombok.Data;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @ClassDescription: 查询可视化所需入参对象
|
||||
* @ClassName: SelectDto
|
||||
* @Author: andyz
|
||||
* @Date: 2022-07-29 14:12:26
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Data
|
||||
public class SelectVisualDto {
|
||||
|
||||
// @NotBlank(message = "invalid operation: tableName can not be empty")
|
||||
/**
|
||||
* 数据库名称
|
||||
*/
|
||||
private String dataBaseName;
|
||||
|
||||
// @NotBlank(message = "invalid operation: tableName can not be empty")
|
||||
/**
|
||||
* 表名
|
||||
*/
|
||||
private String tableName;
|
||||
|
||||
// @NotBlank(message = "invalid operation: fieldName can not be empty") //属性
|
||||
/**
|
||||
* 属性
|
||||
*/
|
||||
private String fieldName;
|
||||
|
||||
/**
|
||||
* 查询类型,0历史数据,1实时数据,2聚合数据
|
||||
*/
|
||||
|
@ -39,10 +39,15 @@ public class SelectVisualDto {
|
|||
* 比如1s,1m,1h,1d代表1秒,1分钟,1小时,1天
|
||||
*/
|
||||
private String interval;
|
||||
// @NotNull(message = "invalid operation: startTime can not be null")
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
private Long startTime;
|
||||
|
||||
// @NotNull(message = "invalid operation: endTime can not be null")
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
private Long endTime;
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.device;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
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.device.vo.deviceData.IotDeviceDataReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataRespVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotTimeDataRespVO;
|
||||
import cn.iocoder.yudao.module.iot.service.device.IotDeviceDataService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
@ -16,6 +18,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
|
@ -35,4 +38,11 @@ public class IotDeviceDataController {
|
|||
return success(BeanUtils.toBean(list, IotDeviceDataRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/history-data")
|
||||
@Operation(summary = "获取设备属性历史数据")
|
||||
public CommonResult<PageResult<IotTimeDataRespVO>> getDevicePropertiesHistoryData(@Valid IotDeviceDataReqVO deviceDataReqVO) {
|
||||
PageResult<Map<String, Object>> list = deviceDataService.getDevicePropertiesHistoryData(deviceDataReqVO);
|
||||
return success(BeanUtils.toBean(list, IotTimeDataRespVO.class));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,13 +1,18 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备数据 Request VO")
|
||||
@Data
|
||||
public class IotDeviceDataReqVO {
|
||||
public class IotDeviceDataReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
|
||||
private Long deviceId;
|
||||
|
@ -18,4 +23,9 @@ public class IotDeviceDataReqVO {
|
|||
@Schema(description = "属性名称", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String name;
|
||||
|
||||
@Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
@Size(min = 2, max = 2, message = "请选择时间范围")
|
||||
private LocalDateTime[] times;
|
||||
|
||||
}
|
|
@ -1,16 +1,14 @@
|
|||
package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine;
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 统计的时间数据
|
||||
*/
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TimeData {
|
||||
public class IotTimeDataRespVO {
|
||||
|
||||
/**
|
||||
* 时间
|
|
@ -88,6 +88,7 @@ public interface TdEngineMapper {
|
|||
|
||||
/**
|
||||
* 创建表 - 创建超级表的子表
|
||||
*
|
||||
* @param tableDO 表信息
|
||||
*/
|
||||
@InterceptorIgnore(tenantLine = "true")
|
||||
|
@ -114,6 +115,7 @@ public interface TdEngineMapper {
|
|||
|
||||
Map<String, Object> getLastData(SelectDto selectDto);
|
||||
|
||||
@InterceptorIgnore(tenantLine = "true")
|
||||
List<Map<String, Object>> getHistoryData(SelectVisualDto selectVisualDto);
|
||||
|
||||
List<Map<String, Object>> getRealtimeData(SelectVisualDto selectVisualDto);
|
||||
|
@ -122,5 +124,6 @@ public interface TdEngineMapper {
|
|||
|
||||
List<Map<String, Object>> getLastDataByTags(TagsSelectDao tagsSelectDao);
|
||||
|
||||
|
||||
}
|
||||
@InterceptorIgnore(tenantLine = "true")
|
||||
Long getHistoryCount(SelectVisualDto selectVisualDto);
|
||||
}
|
|
@ -1,10 +1,12 @@
|
|||
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.deviceData.IotDeviceDataReqVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* IoT 设备数据 Service 接口
|
||||
|
@ -30,4 +32,12 @@ public interface IotDeviceDataService {
|
|||
* @return 设备属性最新数据
|
||||
*/
|
||||
List<IotDeviceDataDO> getDevicePropertiesLatestData(@Valid IotDeviceDataReqVO deviceId);
|
||||
|
||||
/**
|
||||
* 获得设备属性历史数据
|
||||
*
|
||||
* @param deviceDataReqVO 设备属性历史数据 Request VO
|
||||
* @return 设备属性历史数据
|
||||
*/
|
||||
PageResult<Map<String, Object>> getDevicePropertiesHistoryData(@Valid IotDeviceDataReqVO deviceDataReqVO);
|
||||
}
|
|
@ -1,27 +1,38 @@
|
|||
package cn.iocoder.yudao.module.iot.service.device;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataReqVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO;
|
||||
import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineMapper;
|
||||
import cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto;
|
||||
import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum;
|
||||
import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService;
|
||||
import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class IotDeviceDataServiceImpl implements IotDeviceDataService {
|
||||
|
||||
@Value("${spring.datasource.dynamic.datasource.tdengine.url}")
|
||||
private String url;
|
||||
|
||||
@Resource
|
||||
private IotDeviceService deviceService;
|
||||
@Resource
|
||||
|
@ -32,6 +43,9 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService {
|
|||
@Resource
|
||||
private DeviceDataRedisDAO deviceDataRedisDAO;
|
||||
|
||||
@Resource
|
||||
private TdEngineMapper tdEngineMapper;
|
||||
|
||||
@Override
|
||||
public void saveDeviceData(String productKey, String deviceName, String message) {
|
||||
// 1. 根据产品 key 和设备名称,获得设备信息
|
||||
|
@ -91,4 +105,33 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService {
|
|||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<Map<String, Object>> getDevicePropertiesHistoryData(IotDeviceDataReqVO deviceDataReqVO) {
|
||||
PageResult<Map<String, Object>> pageResult = new PageResult<>();
|
||||
// 1. 获取设备信息
|
||||
IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId());
|
||||
// 2. 获取设备属性历史数据
|
||||
SelectVisualDto selectVisualDto = new SelectVisualDto();
|
||||
selectVisualDto.setDataBaseName(getDatabaseName());
|
||||
selectVisualDto.setTableName(getDeviceTableName(device.getProductKey(), device.getDeviceName()));
|
||||
selectVisualDto.setFieldName(deviceDataReqVO.getIdentifier());
|
||||
selectVisualDto.setStartTime(DateUtil.date(deviceDataReqVO.getTimes()[0].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime());
|
||||
selectVisualDto.setEndTime(DateUtil.date(deviceDataReqVO.getTimes()[1].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime());
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("rows", deviceDataReqVO.getPageSize());
|
||||
params.put("page", (deviceDataReqVO.getPageNo() - 1) * deviceDataReqVO.getPageSize());
|
||||
selectVisualDto.setParams(params);
|
||||
pageResult.setList(tdEngineMapper.getHistoryData(selectVisualDto));
|
||||
pageResult.setTotal(tdEngineMapper.getHistoryCount(selectVisualDto));
|
||||
return pageResult;
|
||||
}
|
||||
|
||||
private String getDatabaseName() {
|
||||
return url.substring(url.lastIndexOf("/") + 1);
|
||||
}
|
||||
|
||||
private static String getDeviceTableName(String productKey, String deviceName) {
|
||||
return String.format("device_%s_%s", productKey.toLowerCase(), deviceName.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -292,17 +292,18 @@
|
|||
|
||||
<select id="getHistoryData" resultType="java.util.Map"
|
||||
parameterType="cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto">
|
||||
SELECT #{fieldName}, ts
|
||||
FROM #{dataBaseName}.#{tableName}
|
||||
WHERE ts BETWEEN #{startTime} AND #{endTime}
|
||||
LIMIT #{num}
|
||||
SELECT ${fieldName} as data, time
|
||||
FROM ${dataBaseName}.${tableName}
|
||||
WHERE time BETWEEN #{startTime} AND #{endTime}
|
||||
AND ${fieldName} IS NOT NULL
|
||||
ORDER BY time DESC
|
||||
LIMIT #{params.rows} offset #{params.page}
|
||||
</select>
|
||||
|
||||
<select id="getRealtimeData" resultType="java.util.Map"
|
||||
parameterType="cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto">
|
||||
SELECT #{fieldName}, ts
|
||||
SELECT #{fieldName}, time
|
||||
FROM #{dataBaseName}.#{tableName}
|
||||
LIMIT #{num}
|
||||
</select>
|
||||
|
||||
<select id="getAggregateData" resultType="java.util.Map"
|
||||
|
@ -316,5 +317,11 @@
|
|||
<select id="describeSuperTable" resultType="java.util.Map">
|
||||
DESCRIBE ${dataBaseName}.${superTableName}
|
||||
</select>
|
||||
<select id="getHistoryCount" resultType="java.lang.Long">
|
||||
SELECT count(time)
|
||||
FROM ${dataBaseName}.${tableName}
|
||||
WHERE time BETWEEN #{startTime} AND #{endTime}
|
||||
AND ${fieldName} IS NOT NULL
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
|
Loading…
Reference in New Issue