feat(iot): 新增产品 TDengine 表结构同步接口

This commit is contained in:
YunaiV
2026-02-10 13:12:12 +08:00
parent b800d274a4
commit baa779a271
6 changed files with 51 additions and 4 deletions

View File

@@ -0,0 +1,5 @@
### 请求 /iot/product/sync-property-table 接口 => 成功
POST {{baseUrl}}/iot/product/sync-property-table
Content-Type: application/json
tenant-id: {{adminTenantId}}
Authorization: Bearer {{token}}

View File

@@ -141,6 +141,14 @@ public class IotProductController {
result.getData().getList()); result.getData().getList());
} }
@PostMapping("/sync-property-table")
@Operation(summary = "同步产品属性表结构到 TDengine")
@PreAuthorize("@ss.hasPermission('iot:product:update')")
public CommonResult<Boolean> syncProductPropertyTable() {
productService.syncProductPropertyTable();
return success(true);
}
@GetMapping("/simple-list") @GetMapping("/simple-list")
@Operation(summary = "获取产品的精简信息列表", description = "主要用于前端的下拉选项") @Operation(summary = "获取产品的精简信息列表", description = "主要用于前端的下拉选项")
@Parameter(name = "deviceType", description = "设备类型", example = "1") @Parameter(name = "deviceType", description = "设备类型", example = "1")

View File

@@ -38,6 +38,10 @@ public interface IotProductMapper extends BaseMapperX<IotProductDO> {
.apply("LOWER(product_key) = {0}", productKey.toLowerCase())); .apply("LOWER(product_key) = {0}", productKey.toLowerCase()));
} }
default List<IotProductDO> selectListByStatus(Integer status) {
return selectList(IotProductDO::getStatus, status);
}
default Long selectCountByCreateTime(@Nullable LocalDateTime createTime) { default Long selectCountByCreateTime(@Nullable LocalDateTime createTime) {
return selectCount(new LambdaQueryWrapperX<IotProductDO>() return selectCount(new LambdaQueryWrapperX<IotProductDO>()
.geIfPresent(IotProductDO::getCreateTime, createTime)); .geIfPresent(IotProductDO::getCreateTime, createTime));

View File

@@ -149,4 +149,11 @@ public interface IotProductService {
*/ */
void validateProductsExist(Collection<Long> ids); void validateProductsExist(Collection<Long> ids);
/**
* 同步产品的 TDengine 表结构
*
* 目的:当 MySQL 和 TDengine 不同步时,强制将已发布产品的表结构同步到 TDengine 中
*/
void syncProductPropertyTable();
} }

View File

@@ -15,6 +15,7 @@ import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
import cn.iocoder.yudao.module.iot.service.device.property.IotDevicePropertyService; import cn.iocoder.yudao.module.iot.service.device.property.IotDevicePropertyService;
import com.baomidou.dynamic.datasource.annotation.DSTransactional; import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
@@ -34,6 +35,7 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
* *
* @author ahh * @author ahh
*/ */
@Slf4j
@Service @Service
@Validated @Validated
public class IotProductServiceImpl implements IotProductService { public class IotProductServiceImpl implements IotProductService {
@@ -178,6 +180,27 @@ public class IotProductServiceImpl implements IotProductService {
return productMapper.selectByIds(ids); return productMapper.selectByIds(ids);
} }
@Override
public void syncProductPropertyTable() {
// 1. 获取所有已发布的产品
List<IotProductDO> products = productMapper.selectListByStatus(
IotProductStatusEnum.PUBLISHED.getStatus());
log.info("[syncProductPropertyTable][开始同步,已发布产品数量({})]", products.size());
// 2. 遍历同步 TDengine 表结构(创建产品超级表数据模型)
int successCount = 0;
for (IotProductDO product : products) {
try {
devicePropertyDataService.defineDevicePropertyData(product.getId());
successCount++;
log.info("[syncProductPropertyTable][产品({}/{}) 同步成功]", product.getId(), product.getName());
} catch (Exception e) {
log.error("[syncProductPropertyTable][产品({}/{}) 同步失败]", product.getId(), product.getName(), e);
}
}
log.info("[syncProductPropertyTable][同步完成,成功({}/{})个]", successCount, products.size());
}
@Override @Override
public void validateProductsExist(Collection<Long> ids) { public void validateProductsExist(Collection<Long> ids) {
if (CollUtil.isEmpty(ids)) { if (CollUtil.isEmpty(ids)) {

View File

@@ -7,7 +7,7 @@ import lombok.RequiredArgsConstructor;
import java.util.Arrays; import java.util.Arrays;
/** /**
* IoT Modbus 模式枚举 * IoT Modbus 工作模式枚举
* *
* @author 芋道源码 * @author 芋道源码
*/ */
@@ -16,18 +16,18 @@ import java.util.Arrays;
public enum IotModbusModeEnum implements ArrayValuable<Integer> { public enum IotModbusModeEnum implements ArrayValuable<Integer> {
POLLING(1, "云端轮询"), POLLING(1, "云端轮询"),
ACTIVE_REPORT(2, "主动上报"); ACTIVE_REPORT(2, "边缘采集");
public static final Integer[] ARRAYS = Arrays.stream(values()) public static final Integer[] ARRAYS = Arrays.stream(values())
.map(IotModbusModeEnum::getMode) .map(IotModbusModeEnum::getMode)
.toArray(Integer[]::new); .toArray(Integer[]::new);
/** /**
* 模式 * 工作模式
*/ */
private final Integer mode; private final Integer mode;
/** /**
* 名称 * 模式名称
*/ */
private final String name; private final String name;