From a8c2d005a8f172197d4b4b3315d013d33abfe1b6 Mon Sep 17 00:00:00 2001 From: 2995840376 <2995840376@xiaomi.com> Date: Tue, 27 Oct 2026 12:35:52 +0800 Subject: [PATCH] =?UTF-8?q?feat(B10):=20=E4=BA=A7=E5=93=81<->=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E5=8F=8D=E5=90=91=E6=9F=A5=E8=AF=A2=20-=20=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E5=88=97=E8=A1=A8=E5=8F=AF=E6=8C=89=E4=BA=A7=E5=93=81?= =?UTF-8?q?=E8=BF=87=E6=BB=A4=E5=B9=B6=E5=B1=95=E7=A4=BA=E6=89=80=E5=B1=9E?= =?UTF-8?q?=E4=BA=A7=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 后端: - DeviceQuery 新增 productId(精确) 与 productKeyword(按产品名/编码模糊) - DeviceServiceImpl.pageDevices 支持两种产品维度过滤 productKeyword 场景: 先解析匹配的 product_id 集合再约束 device, 集合为空时用 1=0 保证不误返回全部 - 新增 fillProductInfo(): 批量回填设备所属产品名称与业务编码 (一次 selectBatchIds, 避免 N+1) - Device 实体新增非持久化展示字段 productName / productKey 验证: mvn -pl iot-common,iot-device -am compile 通过 --- .../java/com/iot/device/dto/DeviceQuery.java | 6 +++ .../java/com/iot/device/entity/Device.java | 10 ++++ .../service/impl/DeviceServiceImpl.java | 49 ++++++++++++++++++- 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/backend/iot-device/src/main/java/com/iot/device/dto/DeviceQuery.java b/backend/iot-device/src/main/java/com/iot/device/dto/DeviceQuery.java index 9d1d1ac..258d1b6 100644 --- a/backend/iot-device/src/main/java/com/iot/device/dto/DeviceQuery.java +++ b/backend/iot-device/src/main/java/com/iot/device/dto/DeviceQuery.java @@ -49,6 +49,12 @@ public class DeviceQuery { @Schema(description = "是否为网关(1=网关)") private Integer isGateway; + @Schema(description = "所属产品ID(按产品过滤设备)") + private Long productId; + + @Schema(description = "所属产品关键字(按产品名/编码模糊查询)") + private String productKeyword; + @Schema(description = "页码") @Builder.Default private Integer pageNum = 1; diff --git a/backend/iot-device/src/main/java/com/iot/device/entity/Device.java b/backend/iot-device/src/main/java/com/iot/device/entity/Device.java index c24ddc9..29204fb 100644 --- a/backend/iot-device/src/main/java/com/iot/device/entity/Device.java +++ b/backend/iot-device/src/main/java/com/iot/device/entity/Device.java @@ -130,6 +130,16 @@ public class Device extends BaseEntity { @Schema(description = "备注") private String remark; + // ===== 关联展示字段(非持久化,列表查询时按 product_id 批量回填)===== + + @Schema(description = "所属产品名称") + @TableField(exist = false) + private String productName; + + @Schema(description = "所属产品业务编码") + @TableField(exist = false) + private String productKey; + // ===== 中控屏本地执行相关(executionSource=LOCAL_PANEL 时生效) ===== /** diff --git a/backend/iot-device/src/main/java/com/iot/device/service/impl/DeviceServiceImpl.java b/backend/iot-device/src/main/java/com/iot/device/service/impl/DeviceServiceImpl.java index be429f0..6d1771f 100644 --- a/backend/iot-device/src/main/java/com/iot/device/service/impl/DeviceServiceImpl.java +++ b/backend/iot-device/src/main/java/com/iot/device/service/impl/DeviceServiceImpl.java @@ -26,6 +26,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; /** * 设备服务实现 @@ -150,9 +153,53 @@ public class DeviceServiceImpl extends ServiceImpl impleme // 网关→子设备:按父网关过滤 .eq(StringUtils.hasText(query.getParentDeviceId()), Device::getParentDeviceId, query.getParentDeviceId()) .eq(query.getIsGateway() != null, Device::getIsGateway, query.getIsGateway()) + // 产品维度过滤:支持按 productId 精确查,或按产品名/编码模糊查 + .eq(query.getProductId() != null && query.getProductId() > 0, Device::getProductId, query.getProductId()) .orderByDesc(Device::getUpdateTime); - return page(new Page<>(query.getPageNum(), query.getPageSize()), wrapper); + // 按产品关键字过滤:先解析出匹配的 product_id 集合,再约束 device + if (StringUtils.hasText(query.getProductKeyword())) { + List pids = productMapper.selectList(new LambdaQueryWrapper() + .like(StringUtils.hasText(query.getProductKeyword()), Product::getName, query.getProductKeyword()) + .or().like(StringUtils.hasText(query.getProductKeyword()), Product::getProductKey, query.getProductKeyword())) + .stream().map(Product::getId).toList(); + wrapper.and(w -> { + if (pids.isEmpty()) { + w.apply("1 = 0"); + } else { + w.in(Device::getProductId, pids); + } + }); + } + + Page result = page(new Page<>(query.getPageNum(), query.getPageSize()), wrapper); + fillProductInfo(result.getRecords()); + return result; + } + + /** + * 批量回填设备所属产品名称与业务编码(供后台设备列表展示"所属产品"列)。 + */ + private void fillProductInfo(List devices) { + if (devices == null || devices.isEmpty()) { + return; + } + Set pids = devices.stream() + .map(Device::getProductId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + if (pids.isEmpty()) { + return; + } + Map productMap = productMapper.selectBatchIds(pids).stream() + .collect(Collectors.toMap(Product::getId, p -> p)); + for (Device d : devices) { + Product p = d.getProductId() == null ? null : productMap.get(d.getProductId()); + if (p != null) { + d.setProductName(p.getName()); + d.setProductKey(p.getProductKey()); + } + } } @Override