diff --git a/fastbee-admin/src/main/resources/application-dev.yml b/fastbee-admin/src/main/resources/application-dev.yml index c73727ba..68a7be53 100644 --- a/fastbee-admin/src/main/resources/application-dev.yml +++ b/fastbee-admin/src/main/resources/application-dev.yml @@ -129,7 +129,7 @@ emqx: ApiSecret: emqx.api.123 # sip 配置 sip: - enabled: true # 是否启用视频监控SIP,true为启用 + enabled: false # 是否启用视频监控SIP,true为启用 ## 本地调试时,绑定网卡局域网IP,设备在同一局域网,设备接入IP填写绑定IP ## 部署服务端时,默认绑定容器IP,设备接入IP填写服务器公网IP ip: 192.168.110.160 # 本服务启动的 IP diff --git a/fastbee-common/src/main/java/com/fastbee/common/constant/FastBeeConstant.java b/fastbee-common/src/main/java/com/fastbee/common/constant/FastBeeConstant.java index ec6d5b7f..65dbaa7e 100644 --- a/fastbee-common/src/main/java/com/fastbee/common/constant/FastBeeConstant.java +++ b/fastbee-common/src/main/java/com/fastbee/common/constant/FastBeeConstant.java @@ -239,10 +239,18 @@ public interface FastBeeConstant { String DEVICE_PRE_KEY = "TSLV:"; /** - * 物模型缓存 + * 物模型缓存(产品级) + * Key格式:TSL:{productId} hKey: identifier value: thingsModel */ String TSL_PRE_KEY = "TSL:"; + /** + * 设备级计算物模型缓存 + * Key格式:TSLD:{deviceId} hKey: identifier value: thingsModel + * 用于存储设备级别的纯计算物模型,device_id > 0 + */ + String TSLD_PRE_KEY = "TSLD:"; + String MODBUS_PRE_KEY = "MODBUS:"; /** diff --git a/fastbee-common/src/main/java/com/fastbee/common/core/redis/RedisKeyBuilder.java b/fastbee-common/src/main/java/com/fastbee/common/core/redis/RedisKeyBuilder.java index 067576fd..18d5ecd2 100644 --- a/fastbee-common/src/main/java/com/fastbee/common/core/redis/RedisKeyBuilder.java +++ b/fastbee-common/src/main/java/com/fastbee/common/core/redis/RedisKeyBuilder.java @@ -54,13 +54,21 @@ public class RedisKeyBuilder { } /** - * 物模型缓存key + * 物模型缓存key(产品级) * 物模型命名空间:Key:TSL:{productId} hkey: identity value: thingsModel */ public static String buildTSLCacheKey(Long productId) { return FastBeeConstant.REDIS.TSL_PRE_KEY + productId; } + /** + * 设备级计算物模型缓存key + * 物模型命名空间:Key:TSLD:{SerialNumber} hkey: identity value: thingsModel + */ + public static String buildDeviceTSLCacheKey(String serialNumber) { + return FastBeeConstant.REDIS.TSLD_PRE_KEY + serialNumber; + } + public static String buildModbusKey(Long productId) { return FastBeeConstant.REDIS.MODBUS_PRE_KEY + productId; } diff --git a/fastbee-common/src/main/java/com/fastbee/common/core/thingsModel/ThingsModelSimpleItem.java b/fastbee-common/src/main/java/com/fastbee/common/core/thingsModel/ThingsModelSimpleItem.java index 0fe2ebd0..5744fa02 100644 --- a/fastbee-common/src/main/java/com/fastbee/common/core/thingsModel/ThingsModelSimpleItem.java +++ b/fastbee-common/src/main/java/com/fastbee/common/core/thingsModel/ThingsModelSimpleItem.java @@ -39,6 +39,11 @@ public class ThingsModelSimpleItem { **/ private String remark; + /** + * 是否纯计算型物模型 + */ + private boolean isCalculated; + public ThingsModelSimpleItem(String id, String value, String remark) { this.id = id; @@ -88,4 +93,12 @@ public class ThingsModelSimpleItem { public void setName(String name) { this.name = name; } + + public boolean isCalculated() { + return isCalculated; + } + + public void setCalculated(boolean calculated) { + isCalculated = calculated; + } } diff --git a/fastbee-protocol/fastbee-protocol-collect/src/main/java/com/fastbee/modbus/codec/ModbusProtocol.java b/fastbee-protocol/fastbee-protocol-collect/src/main/java/com/fastbee/modbus/codec/ModbusProtocol.java index d82b03e6..6aa9e07c 100644 --- a/fastbee-protocol/fastbee-protocol-collect/src/main/java/com/fastbee/modbus/codec/ModbusProtocol.java +++ b/fastbee-protocol/fastbee-protocol-collect/src/main/java/com/fastbee/modbus/codec/ModbusProtocol.java @@ -19,11 +19,9 @@ import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.gateway.CRC16Utils; import com.fastbee.common.utils.modbus.BitUtils; import com.fastbee.helper.ModbusProtocolHelper; -import com.fastbee.iot.cache.ICalculatedThingsModelCache; import com.fastbee.iot.cache.IModbusConfigCache; -import com.fastbee.iot.domain.Device; +import com.fastbee.iot.cache.ITSLCache; import com.fastbee.iot.domain.ModbusConfig; -import com.fastbee.iot.mapper.DeviceMapper; import com.fastbee.iot.mapper.ModbusConfigMapper; import com.fastbee.iot.model.ThingsModels.ThingsModelValueItem; import com.fastbee.iot.service.ISubGatewayService; @@ -40,7 +38,6 @@ import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; @@ -63,14 +60,12 @@ public class ModbusProtocol implements IProtocol { private IModbusConfigCache modbusConfigCache; @Resource private ISubGatewayService subGatewayService; - @Resource - private DeviceMapper deviceMapper; @Resource private ModbusConfigMapper modbusConfigMapper; @Resource - private ICalculatedThingsModelCache calculatedThingsModelCache; + private ITSLCache itslCache; @Override public DeviceReport decode(DeviceData deviceData, String clientId) { @@ -103,16 +98,16 @@ public class ModbusProtocol implements IProtocol { case Read01: case Read02: //起始地址 - String address0102 = getCacheModbusAddress(deviceData.getSerialNumber(), slaveId, code); + String address0102 = getCacheModbusAddress(productId, slaveId, code); //读线圈或读离散型寄存器处理 handleRead0102(productId, message, address0102, values); break; case Read03: case Read04: //起始地址 - String address0304 = getCacheModbusAddress(deviceData.getSerialNumber(), slaveId, code); + String address0304 = getCacheModbusAddress(productId, slaveId, code); //读输入、保持寄存器 - handleRead0304(productId, message, address0304, values, hexDump); + handleRead0304(deviceData.getSerialNumber(), productId, message, address0304, values, hexDump); break; case Write06: case Write05: @@ -191,13 +186,14 @@ public class ModbusProtocol implements IProtocol { /** * 处理读保持寄存器/输入寄存器 * + * @param serialNumber 设备序列号 * @param productId 产品id * @param message 数据 * @param address 起始地址 * @param simpleItemList 返回的物模型值 * @param sourceStr 原始报文字符串 */ - private void handleRead0304(Long productId, ModbusRtu message, String address, List simpleItemList, String sourceStr) { + private void handleRead0304(String serialNumber, Long productId, ModbusRtu message, String address, List simpleItemList, String sourceStr) { short[] data = message.getData(); int length = data.length; if (length == 1) { @@ -318,50 +314,35 @@ public class ModbusProtocol implements IProtocol { } // 处理纯计算物模型:查询产品下所有纯计算物模型,构造 ThingsModelSimpleItem,值为 "0" - handleCalculatedThingsModels(productId, simpleItemList, isReadOnly); + handleCalculatedThingsModels(serialNumber, simpleItemList); } } /** - * 处理纯计算物模型 - * 从缓存获取纯计算物模型列表,构造 ThingsModelSimpleItem,值为 "0" - * 后续在计算环节会统一处理所有物模型(包括纯计算物模型) + * 从redis获取 纯计算物模型(设备级别物模型) * - * @param productId 产品ID + * @param serialNumber 设备编号 * @param simpleItemList 物模型值列表 - * @param isReadOnly 是否只读 */ - private void handleCalculatedThingsModels(Long productId, List simpleItemList, int isReadOnly) { + private void handleCalculatedThingsModels(String serialNumber, List simpleItemList) { + try { - // 从缓存获取纯计算物模型标识符集合(支持产品级别和设备级别) - Set calculatedIdentifiers = calculatedThingsModelCache.getCalculatedIdentifiers(productId, null); - - if (calculatedIdentifiers.isEmpty()) { - return; - } - - // 获取已上报的物模型标识符集合(避免重复) - Set reportedIdentifiers = simpleItemList.stream() - .map(ThingsModelSimpleItem::getId) - .collect(Collectors.toSet()); - - // 为纯计算物模型构造 ThingsModelSimpleItem - for (String identifier : calculatedIdentifiers) { - // 跳过已上报的物模型 - if (reportedIdentifiers.contains(identifier)) { - continue; - } - - // 构造 ThingsModelSimpleItem,值为 "0" + Map calculatedModelMap = itslCache.getDeviceCalculatedModelMap(serialNumber); + + // 构造 ThingsModelSimpleItem,值为 "0" + for (Map.Entry entry : calculatedModelMap.entrySet()) { + String identifier = entry.getKey(); + ThingsModelSimpleItem simpleItem = new ThingsModelSimpleItem(); simpleItem.setId(identifier); simpleItem.setValue("0"); // 初始值设为0,后续在计算环节会重新计算 simpleItem.setTs(DateUtils.getNowDate()); + simpleItem.setCalculated(true); simpleItemList.add(simpleItem); - log.debug("=>添加纯计算物模型到上报列表,产品ID:[{}],标识符:[{}]", productId, identifier); + log.debug("=>添加纯计算物模型到上报列表,设备:[{}],标识符:[{}]", serialNumber, identifier); } } catch (Exception e) { - log.error("=>处理纯计算物模型时发生错误,产品ID:[{}],错误:{}", productId, e.getMessage(), e); + log.error("=>处理纯计算物模型时发生错误,设备:[{}],错误:{}", serialNumber, e.getMessage(), e); } } @@ -484,9 +465,9 @@ public class ModbusProtocol implements IProtocol { } /** - * 获取modbus地址 + * 获取寄存器最小modbus地址,从最小的寄存器地址开始解码 */ - private String getCacheModbusAddress(String serialNumber, int salveId, int code) { + private String getCacheModbusAddress(Long productId, int salveId, int code) { // String key = RedisKeyBuilder.buildModbusRuntimeCacheKey(serialNumber); // Set commandSet = redisCache.zRange(key, 0, -1); // @@ -502,13 +483,14 @@ public class ModbusProtocol implements IProtocol { // log.warn("解析指令异常: {}", e.getMessage()); // } // } + // todo 拿缓存 // 2. 无匹配时查询数据库 try { - Device device = deviceMapper.selectDeviceBySerialNumber(serialNumber); - if (device == null) return "0"; +// Device device = deviceMapper.selectDeviceBySerialNumber(serialNumber); +// if (device == null) return "0"; - List configs = modbusConfigMapper.selectModbusConfigListByProductId(device.getProductId()); + List configs = modbusConfigMapper.selectModbusConfigListByProductId(productId); if (CollectionUtils.isEmpty(configs)) return "0"; return configs.stream() diff --git a/fastbee-server/iot-server-core/src/main/java/com/fastbee/server/handler/DelimiterBasedFrameDecoder.java b/fastbee-server/iot-server-core/src/main/java/com/fastbee/server/handler/DelimiterBasedFrameDecoder.java index 7e48b12f..6e0d5c9d 100644 --- a/fastbee-server/iot-server-core/src/main/java/com/fastbee/server/handler/DelimiterBasedFrameDecoder.java +++ b/fastbee-server/iot-server-core/src/main/java/com/fastbee/server/handler/DelimiterBasedFrameDecoder.java @@ -125,12 +125,13 @@ public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder { if (minDelim != null) { int minDelimLength = minDelim.value.length; ByteBuf frame = null; + boolean keepDelimiterForNextFrame = shouldKeepDelimiterForNextFrame(minDelim) && minFrameLength > 0; if (discardingTooLongFrame) { // 如果true,将长度不符合报文丢弃 // 初始化原来的值 discardingTooLongFrame = false; - buffer.skipBytes(minFrameLength + minDelimLength); + buffer.skipBytes(minFrameLength + (keepDelimiterForNextFrame ? 0 : minDelimLength)); int tooLongFrameLength = this.tooLongFrameLength; this.tooLongFrameLength = 0; @@ -142,10 +143,16 @@ public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder { /*小于最小长度帧处理*/ if (minFrameLength > maxFrameLength) { //放弃读取帧 - buffer.skipBytes(minFrameLength + minDelimLength); + buffer.skipBytes(minFrameLength + (keepDelimiterForNextFrame ? 0 : minDelimLength)); fail(minFrameLength); return null; } + + if (keepDelimiterForNextFrame) { + frame = buffer.readRetainedSlice(minFrameLength); + return frame; + } + /*是否需要跳过某字节*/ if (minDelim.strip) { //忽略长度等于0的报文 @@ -182,6 +189,15 @@ public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder { return null; } } + + /** + * 7E 分隔符需要保留给下一帧作为帧头使用(仅在存在前置数据时)。 + */ + private boolean shouldKeepDelimiterForNextFrame(Delimiter delimiter) { + return !delimiter.strip + && delimiter.value.length == 1 + && (delimiter.value[0] & 0xFF) == 0x7E; + } /** * 检测7E帧格式(注册包/心跳包) diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/ICalculatedThingsModelCache.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/ICalculatedThingsModelCache.java deleted file mode 100644 index b785bb0c..00000000 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/ICalculatedThingsModelCache.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.fastbee.iot.cache; - -import java.util.Set; - -/** - * 纯计算物模型缓存接口 - * 支持产品级别和设备级别的缓存 - * 支持本地缓存和 Redis 缓存的切换 - * - * @author Sumuxi - * @date 2026-01-02 - */ -public interface ICalculatedThingsModelCache { - - /** - * 获取产品下的纯计算物模型标识符集合 - * @param productId 产品ID - * @return 纯计算物模型标识符集合 - */ - Set getCalculatedIdentifiersByProduct(Long productId); - - /** - * 获取设备下的纯计算物模型标识符集合 - * 如果设备有自定义物模型,返回设备级别的;否则返回产品级别的 - * @param productId 产品ID - * @param deviceId 设备ID(可选,未来扩展) - * @return 纯计算物模型标识符集合 - */ - Set getCalculatedIdentifiers(Long productId, Long deviceId); - - /** - * 设置产品下的纯计算物模型标识符集合 - * @param productId 产品ID - * @param identifiers 纯计算物模型标识符集合 - */ - void setCalculatedIdentifiersByProduct(Long productId, Set identifiers); - - /** - * 刷新产品下的纯计算物模型缓存 - * @param productId 产品ID - */ - void refreshCalculatedCache(Long productId); - - /** - * 清除产品下的纯计算物模型缓存 - * @param productId 产品ID - */ - void clearCalculatedCache(Long productId); - - /** - * 判断是否使用 Redis 缓存 - * @return true-使用Redis,false-使用本地缓存 - */ - boolean isRedisCacheEnabled(); -} - diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/ITSLCache.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/ITSLCache.java index 3c512bbb..ff959769 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/ITSLCache.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/ITSLCache.java @@ -61,7 +61,7 @@ public interface ITSLCache { * \"name\":\"光强\",\"order\":0,\"regId\":\"light\",\"type\":1}]} *

*/ - public String setCacheThingsModelByProductId(Long productId); + String setCacheThingsModelByProductId(Long productId); /** * 获取map物模型 --返回 Map @@ -90,7 +90,7 @@ public interface ITSLCache { * value:PropertyDto *

*/ - public Map setCacheThMapByProductId(Long productId); + Map setCacheThMapByProductId(Long productId); /** * 获取单个物模型缓存 @@ -99,6 +99,40 @@ public interface ITSLCache { * @param identify 标识符 * @return PropertyDto */ - public ThingsModelValueItem getSingleThingModels(Long productId, String identify); + ThingsModelValueItem getSingleThingModels(Long productId, String identify); + + // ==================== 设备级计算物模型缓存方法 ==================== + + /** + * 获取设备级计算物模型缓存(Map形式) + * + * @param serialNumber 设备ID + * @return Map<标识符, ThingsModelValueItem> + */ + Map getDeviceCalculatedModelMap(String serialNumber); + + /** + * 刷新设备级计算物模型缓存 + * + * @param serialNumber 设备ID + * @return Map<标识符, ThingsModelValueItem> + */ + Map refreshDeviceCalculatedModelCache(String serialNumber); + + /** + * 清除设备级计算物模型缓存 + * + * @param serialNumber 设备ID + */ + void clearDeviceCalculatedModelCache(String serialNumber); + + /** + * 获取单个设备级计算物模型 + * + * @param serialNumber 设备ID + * @param identifier 标识符 + * @return ThingsModelValueItem + */ + ThingsModelValueItem getSingleDeviceCalculatedModel(String serialNumber, String identifier); } diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/impl/CalculatedThingsModelCacheImpl.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/impl/CalculatedThingsModelCacheImpl.java deleted file mode 100644 index 23858419..00000000 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/impl/CalculatedThingsModelCacheImpl.java +++ /dev/null @@ -1,149 +0,0 @@ -package com.fastbee.iot.cache.impl; - -import com.fastbee.iot.cache.ICalculatedThingsModelCache; -import com.fastbee.iot.domain.ThingsModel; -import com.fastbee.iot.service.IThingsModelService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; - -import javax.annotation.Resource; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - -/** - * 纯计算物模型缓存实现(本地缓存) - * 使用 ConcurrentHashMap 维护本地缓存 - * 适用于计算型物模型数量较少、单机部署的场景 - * - * @author sumuxi - * @date 2026/01/02 - */ -@Service("calculatedThingsModelCache") -@ConditionalOnProperty(name = "fastbee.cache.calculated-things-model.use-redis", havingValue = "false", matchIfMissing = true) -@Slf4j -public class CalculatedThingsModelCacheImpl implements ICalculatedThingsModelCache { - - /** - * 本地缓存:productId -> Set(纯计算物模型标识符集合) - */ - private final ConcurrentHashMap> calculatedCache = new ConcurrentHashMap<>(); - - /** - * 设备级别缓存:deviceId -> Set(未来扩展) - * 当设备有自定义物模型选择时使用 - */ - private final ConcurrentHashMap> deviceCalculatedCache = new ConcurrentHashMap<>(); - - @Resource - private IThingsModelService thingsModelService; - - /** - * 是否启用 Redis 缓存(通过配置控制) - * 默认 false,使用本地缓存 - * 当计算型物模型数量较多或需要集群部署时,设置为 true - */ - @Value("${fastbee.cache.calculated-things-model.use-redis:false}") - private boolean useRedisCache; - - /** - * 本地缓存大小阈值 - * 超过此阈值建议切换到 Redis 缓存 - */ - @Value("${fastbee.cache.calculated-things-model.local-cache-threshold:1000}") - private int localCacheThreshold; - - @Override - public Set getCalculatedIdentifiersByProduct(Long productId) { - if (productId == null) { - return Collections.emptySet(); - } - - // 从本地缓存获取 - Set identifiers = calculatedCache.get(productId); - if (identifiers != null) { - return identifiers; - } - - // 缓存未命中,从数据库加载 - refreshCalculatedCache(productId); - return calculatedCache.getOrDefault(productId, Collections.emptySet()); - } - - @Override - public Set getCalculatedIdentifiers(Long productId, Long deviceId) { - // 如果设备有自定义物模型选择,优先返回设备级别的 - if (deviceId != null) { - Set deviceIdentifiers = deviceCalculatedCache.get(deviceId); - if (deviceIdentifiers != null) { - return deviceIdentifiers; - } - } - - // 否则返回产品级别的 - return getCalculatedIdentifiersByProduct(productId); - } - - @Override - public void setCalculatedIdentifiersByProduct(Long productId, Set identifiers) { - if (productId == null) { - return; - } - - // 检查缓存大小,超过阈值时记录警告 - if (calculatedCache.size() > localCacheThreshold) { - log.warn("=>纯计算物模型本地缓存大小超过阈值[{}],建议切换到Redis缓存", localCacheThreshold); - } - - calculatedCache.put(productId, identifiers != null ? identifiers : Collections.emptySet()); - } - - @Override - public void refreshCalculatedCache(Long productId) { - if (productId == null) { - return; - } - - try { - // 查询产品下所有物模型 - ThingsModel queryModel = new ThingsModel(); - queryModel.setProductId(productId); - List allThingsModels = thingsModelService.selectThingsModelList(queryModel); - - if (CollectionUtils.isEmpty(allThingsModels)) { - calculatedCache.put(productId, Collections.emptySet()); - return; - } - - // 筛选出纯计算物模型(isCalculated == 1) - Set calculatedIdentifiers = allThingsModels.stream() - .filter(model -> model.getIsCalculated() != null && model.getIsCalculated() == 1) - .map(ThingsModel::getIdentifier) - .collect(Collectors.toSet()); - - calculatedCache.put(productId, calculatedIdentifiers); - log.debug("=>刷新纯计算物模型本地缓存成功,产品ID:[{}],数量:[{}]", productId, calculatedIdentifiers.size()); - } catch (Exception e) { - log.error("=>刷新纯计算物模型本地缓存失败,产品ID:[{}],错误:{}", productId, e.getMessage(), e); - calculatedCache.put(productId, Collections.emptySet()); - } - } - - @Override - public void clearCalculatedCache(Long productId) { - if (productId != null) { - calculatedCache.remove(productId); - } - } - - @Override - public boolean isRedisCacheEnabled() { - return useRedisCache; - } -} - diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/impl/CalculatedThingsModelRedisCacheImpl.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/impl/CalculatedThingsModelRedisCacheImpl.java deleted file mode 100644 index 91e435de..00000000 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/impl/CalculatedThingsModelRedisCacheImpl.java +++ /dev/null @@ -1,163 +0,0 @@ -/* -package com.fastbee.iot.cache.impl; - -import com.alibaba.fastjson2.JSON; -import com.fastbee.common.core.redis.RedisCache; -import com.fastbee.common.core.redis.RedisKeyBuilder; -import com.fastbee.iot.cache.ICalculatedThingsModelCache; -import com.fastbee.iot.domain.ThingsModel; -import com.fastbee.iot.service.IThingsModelService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; - -import javax.annotation.Resource; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -*/ -/** - * 纯计算物模型缓存实现(Redis缓存) - * 使用 Redis 维护缓存,支持集群部署 - * 适用于计算型物模型数量较多、集群部署的场景 - * - * @author Sumuxi - * @date 2026-01-02 - *//* - -@Service("calculatedThingsModelRedisCache") -@ConditionalOnProperty(name = "fastbee.cache.calculated-things-model.use-redis", havingValue = "true") -@Slf4j -public class CalculatedThingsModelRedisCacheImpl implements ICalculatedThingsModelCache { - - */ -/** - * 缓存过期时间(秒),默认 24 小时 - *//* - - @Value("${fastbee.cache.calculated-things-model.redis-ttl:86400}") - private long redisTtl; - - @Resource - private RedisCache redisCache; - - @Resource - private IThingsModelService thingsModelService; - - @Override - public Set getCalculatedIdentifiersByProduct(Long productId) { - if (productId == null) { - return Collections.emptySet(); - } - - String cacheKey = RedisKeyBuilder.buildCalculatedThingsModelKey(productId); - String cacheValue = redisCache.getCacheObject(cacheKey); - - if (cacheValue != null) { - try { - @SuppressWarnings("unchecked") - Set result = JSON.parseObject(cacheValue, Set.class); - return result != null ? result : Collections.emptySet(); - } catch (Exception e) { - log.warn("=>解析纯计算物模型Redis缓存失败,产品ID:[{}],错误:{}", productId, e.getMessage()); - } - } - - // 缓存未命中,从数据库加载 - refreshCalculatedCache(productId); - cacheValue = redisCache.getCacheObject(cacheKey); - if (cacheValue != null) { - try { - @SuppressWarnings("unchecked") - Set result = JSON.parseObject(cacheValue, Set.class); - return result != null ? result : Collections.emptySet(); - } catch (Exception e) { - log.warn("=>解析纯计算物模型Redis缓存失败,产品ID:[{}],错误:{}", productId, e.getMessage()); - } - } - - return Collections.emptySet(); - } - - @Override - public Set getCalculatedIdentifiers(Long productId, Long deviceId) { - // 如果设备有自定义物模型选择,优先返回设备级别的 - if (deviceId != null) { - String deviceCacheKey = RedisKeyBuilder.buildCalculatedThingsModelDeviceKey(deviceId); - String deviceCacheValue = redisCache.getCacheObject(deviceCacheKey); - if (deviceCacheValue != null) { - try { - @SuppressWarnings("unchecked") - Set result = JSON.parseObject(deviceCacheValue, Set.class); - return result != null ? result : Collections.emptySet(); - } catch (Exception e) { - log.warn("=>解析设备纯计算物模型Redis缓存失败,设备ID:[{}],错误:{}", deviceId, e.getMessage()); - } - } - } - - // 否则返回产品级别的 - return getCalculatedIdentifiersByProduct(productId); - } - - @Override - public void setCalculatedIdentifiersByProduct(Long productId, Set identifiers) { - if (productId == null) { - return; - } - - String cacheKey = RedisKeyBuilder.buildCalculatedThingsModelKey(productId); - String cacheValue = JSON.toJSONString(identifiers != null ? identifiers : Collections.emptySet()); - redisCache.setCacheObject(cacheKey, cacheValue, (int) redisTtl, java.util.concurrent.TimeUnit.SECONDS); - } - - @Override - public void refreshCalculatedCache(Long productId) { - if (productId == null) { - return; - } - - try { - // 查询产品下所有物模型 - ThingsModel queryModel = new ThingsModel(); - queryModel.setProductId(productId); - List allThingsModels = thingsModelService.selectThingsModelList(queryModel); - - if (CollectionUtils.isEmpty(allThingsModels)) { - setCalculatedIdentifiersByProduct(productId, Collections.emptySet()); - return; - } - - // 筛选出纯计算物模型(isCalculated == 1) - Set calculatedIdentifiers = allThingsModels.stream() - .filter(model -> model.getIsCalculated() != null && model.getIsCalculated() == 1) - .map(ThingsModel::getIdentifier) - .collect(Collectors.toSet()); - - setCalculatedIdentifiersByProduct(productId, calculatedIdentifiers); - log.debug("=>刷新纯计算物模型Redis缓存成功,产品ID:[{}],数量:[{}]", productId, calculatedIdentifiers.size()); - } catch (Exception e) { - log.error("=>刷新纯计算物模型Redis缓存失败,产品ID:[{}],错误:{}", productId, e.getMessage(), e); - setCalculatedIdentifiersByProduct(productId, Collections.emptySet()); - } - } - - @Override - public void clearCalculatedCache(Long productId) { - if (productId != null) { - String cacheKey = RedisKeyBuilder.buildCalculatedThingsModelKey(productId); - redisCache.deleteObject(cacheKey); - } - } - - @Override - public boolean isRedisCacheEnabled() { - return true; - } -} - -*/ diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/impl/ModbusConfigCacheImpl.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/impl/ModbusConfigCacheImpl.java index 5d441339..971ca208 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/impl/ModbusConfigCacheImpl.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/impl/ModbusConfigCacheImpl.java @@ -76,6 +76,10 @@ public class ModbusConfigCacheImpl implements IModbusConfigCache { resultMap.put(entry.getKey() + "", valueStr); } String modbusKey = RedisKeyBuilder.buildModbusKey(productId); + // 先删除缓存,再插入缓存——完成缓存更新 + if (redisCache.containsKey(modbusKey)) { + redisCache.deleteObject(modbusKey); + } redisCache.hashPutAll(modbusKey, resultMap); return listMap; } diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/impl/TSLCacheImpl.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/impl/TSLCacheImpl.java index 36a9c596..877f416b 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/impl/TSLCacheImpl.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/impl/TSLCacheImpl.java @@ -23,10 +23,7 @@ import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import javax.annotation.Resource; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -159,11 +156,9 @@ public class TSLCacheImpl implements ITSLCache { /*组装成原格式数据*/ Map> result = thingsModelMap.values().stream().map(x -> JSON.parseObject(x, ThingsModelValueItem.class)) .collect(Collectors.groupingBy(dto -> ThingsModelType.getName(dto.getType()))); - if (result != null) { - for (List itemList : result.values()) { - for (ThingsModelValueItem item : itemList) { - convertModelName(item, SecurityUtils.getLanguage()); - } + for (List itemList : result.values()) { + for (ThingsModelValueItem item : itemList) { + convertModelName(item, SecurityUtils.getLanguage()); } } String jsonString = JSON.toJSONString(result); @@ -289,6 +284,7 @@ public class TSLCacheImpl implements ITSLCache { // 数据库查询物模型集合 ThingsModel model = new ThingsModel(); model.setProductId(productId); + model.setIsCalculated(0); // 只查询产品级物模型 model.setLimitValue(SecurityUtils.getLanguage()); List thingsModels = thingsModelService.selectThingsModelList(model); //modbus配置参数整合到物模型 @@ -325,12 +321,132 @@ public class TSLCacheImpl implements ITSLCache { /*缓存到redis*/ String cacheKey = RedisKeyBuilder.buildTSLCacheKey(productId); - //先删除缓存 + // 先删除缓存 if (redisCache.containsKey(cacheKey)) { redisCache.deleteObject(cacheKey); } + // 再插入缓存——完成缓存更新 redisCache.hashPutAll(cacheKey, thingsModelMap); return thingsModelMap; } + // ==================== 设备级计算物模型缓存方法 ==================== + + /** + * 获取设备级计算物模型缓存(Map形式) + * + * @param serialNumber 设备ID + * @return Map<标识符, ThingsModelValueItem> + */ + @Override + public Map getDeviceCalculatedModelMap(String serialNumber) { + if (StringUtils.isEmpty(serialNumber)) { + return Collections.emptyMap(); + } + String cacheKey = RedisKeyBuilder.buildDeviceTSLCacheKey(serialNumber); + Map map = redisCache.getCacheMap(cacheKey); + if (!CollectionUtils.isEmpty(map)) { + Map itemMap = map.values().stream() + .map(v -> JSON.parseObject(v.toString(), ThingsModelValueItem.class)) + .collect(Collectors.toMap(ThingsModelValueItem::getId, Function.identity())); + for (ThingsModelValueItem item : itemMap.values()) { + convertModelName(item, SecurityUtils.getLanguage()); + } + return itemMap; + } + // 缓存未命中,从数据库加载 + return refreshDeviceCalculatedModelCache(serialNumber); + } + + /** + * 刷新设备级计算物模型缓存 + * + * @param serialNumber 设备ID + * @return Map<标识符, ThingsModelValueItem> + */ + @Override + public Map refreshDeviceCalculatedModelCache(String serialNumber) { + if (StringUtils.isEmpty(serialNumber)) { + return Collections.emptyMap(); + } + // 从数据库查询设备级计算物模型 + ThingsModel model = new ThingsModel(); + model.setSerialNumber(serialNumber); + model.setIsCalculated(1); // 查询设备级物模型 + List models = thingsModelService.selectThingsModelList(model); + if (CollectionUtils.isEmpty(models)) { + // 清除可能存在的旧缓存 + clearDeviceCalculatedModelCache(serialNumber); + return Collections.emptyMap(); + } + + // 转换为缓存格式 + Map cacheMap = models.stream().collect(Collectors.toMap( + ThingsModel::getIdentifier, + thingsModel -> { + ThingsModelValueItem dto = new ThingsModelValueItem(); + BeanUtils.copyProperties(thingsModel, dto); + dto.setDatatype(JSONObject.parseObject(thingsModel.getSpecs(), Datatype.class)) + .setId(thingsModel.getIdentifier()) + .setName(thingsModel.getModelName()) + .setName_zh_CN(thingsModel.getModelName_zh_CN()) + .setName_en_US(thingsModel.getModelName_en_US()) + .setOrder(thingsModel.getModelOrder()) + .setModelId(thingsModel.getModelId()) + .setFormula(thingsModel.getFormula()) + .setIsCalculated(thingsModel.getIsCalculated()); + return JSONObject.toJSONString(dto); + } + )); + + // 缓存到Redis——先删再写 + String cacheKey = RedisKeyBuilder.buildDeviceTSLCacheKey(serialNumber); + if (redisCache.containsKey(cacheKey)) { + redisCache.deleteObject(cacheKey); + } + redisCache.hashPutAll(cacheKey, cacheMap); + + // 返回转换后的Map + return cacheMap.values().stream() + .map(v -> JSON.parseObject(v, ThingsModelValueItem.class)) + .collect(Collectors.toMap(ThingsModelValueItem::getId, Function.identity())); + } + + /** + * 清除设备级计算物模型缓存 + * + * @param serialNumber 设备ID + */ + @Override + public void clearDeviceCalculatedModelCache(String serialNumber) { + if (StringUtils.isNotEmpty(serialNumber)) { + String cacheKey = RedisKeyBuilder.buildDeviceTSLCacheKey(serialNumber); + redisCache.deleteObject(cacheKey); + } + } + + /** + * 获取单个设备级计算物模型 + * + * @param serialNumber 设备ID + * @param identifier 标识符 + * @return ThingsModelValueItem + */ + @Override + public ThingsModelValueItem getSingleDeviceCalculatedModel(String serialNumber, String identifier) { + if (StringUtils.isEmpty(serialNumber) || StringUtils.isEmpty(identifier)) { + return null; + } + String cacheKey = RedisKeyBuilder.buildDeviceTSLCacheKey(serialNumber); + String itemStr = redisCache.getCacheMapValue(cacheKey, identifier); + if (StringUtils.isEmpty(itemStr)) { + // 尝试刷新缓存后再获取 + Map modelMap = getDeviceCalculatedModelMap(serialNumber); + return modelMap.get(identifier); + } + ThingsModelValueItem item = JSONObject.parseObject(itemStr, ThingsModelValueItem.class); + convertModelName(item, SecurityUtils.getLanguage()); + return item; + } + } diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/impl/TSLValueCacheImpl.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/impl/TSLValueCacheImpl.java index c4e0bfae..20100f7c 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/impl/TSLValueCacheImpl.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/cache/impl/TSLValueCacheImpl.java @@ -43,8 +43,8 @@ public class TSLValueCacheImpl implements ITSLValueCache { public List getCacheDeviceStatus(Long productId, String deviceNumber) { String key = RedisKeyBuilder.buildTSLVCacheKey(productId, deviceNumber); Map map = redisCache.hashEntity(key); - List valueList = new ArrayList<>(); - if (map == null || map.size() == 0) { + List valueList; + if (map == null || map.isEmpty()) { // 缓存设备状态(物模型值)到redis valueList = addCacheDeviceStatus(productId, deviceNumber); } else { diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/domain/ThingsModel.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/domain/ThingsModel.java index 6ad5372d..5a25dd40 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/domain/ThingsModel.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/domain/ThingsModel.java @@ -63,6 +63,18 @@ public class ThingsModel extends BaseEntity { @ApiModelProperty("产品名称") private String productName; + /** + * 设备ID(0表示产品级物模型,>0表示设备级计算物模型) + */ + @ApiModelProperty(value = "设备ID", notes = "0表示产品级物模型,>0表示设备级计算物模型") + private Long deviceId; + + /** + * 设备编号 + */ + @ApiModelProperty("设备编号") + private String serialNumber; + /** * 租户ID */ diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/DeviceServiceImpl.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/DeviceServiceImpl.java index 24fd58cb..a2481b84 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/DeviceServiceImpl.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/DeviceServiceImpl.java @@ -156,7 +156,6 @@ public class DeviceServiceImpl implements IDeviceService { @Value("${server.tcp.port}") private Long tcpPort; - // select cache /** @@ -165,7 +164,8 @@ public class DeviceServiceImpl implements IDeviceService { * @param deviceId 设备主键 * @return 设备 */ -// @Cacheable(cacheNames = "Device", key = "#root.methodName + ':' + #serialNumber", unless = "#result == null") + // @Cacheable(cacheNames = "Device", key = "#root.methodName + ':' + + // #serialNumber", unless = "#result == null") @Override public Device selectDeviceByDeviceId(Long deviceId) { Device device = deviceMapper.selectDeviceByDeviceId(deviceId); @@ -174,7 +174,7 @@ public class DeviceServiceImpl implements IDeviceService { // redis中获取设备状态(物模型值) device.setThingsModelValue(JSONObject.toJSONString(list)); } - //查询关联的监控设备 + // 查询关联的监控设备 SipRelation sipRelation = new SipRelation(); sipRelation.setReDeviceId(deviceId); List sipRelationList = sipRelationService.selectSipRelationList(sipRelation); @@ -280,7 +280,8 @@ public class DeviceServiceImpl implements IDeviceService { */ @Caching(evict = { @CacheEvict(cacheNames = "Device", key = "'selectDeviceBySerialNumber:' + #device.getSerialNumber()"), -// @CacheEvict(cacheNames = "Device", key = "'selectDeviceByDeviceId:' + #device.getSerialNumber()"), + // @CacheEvict(cacheNames = "Device", key = "'selectDeviceByDeviceId:' + + // #device.getSerialNumber()"), @CacheEvict(cacheNames = "Device", key = "'selectDeviceStatusAndTransportStatus:' + #device.getSerialNumber()"), @CacheEvict(cacheNames = "Device", key = "'selectProtocolBySerialNumber:' + #device.getSerialNumber()"), @CacheEvict(cacheNames = "Device", key = "'selectShortDeviceBySerialNumber:' + #device.getSerialNumber()") @@ -312,7 +313,8 @@ public class DeviceServiceImpl implements IDeviceService { @Caching(evict = { @CacheEvict(cacheNames = "Device", key = "'selectDeviceBySerialNumber:' + #device.getSerialNumber()"), -// @CacheEvict(cacheNames = "Device", key = "'selectDeviceByDeviceId:' + #device.getSerialNumber()"), + // @CacheEvict(cacheNames = "Device", key = "'selectDeviceByDeviceId:' + + // #device.getSerialNumber()"), @CacheEvict(cacheNames = "Device", key = "'selectDeviceStatusAndTransportStatus:' + #device.getSerialNumber()"), @CacheEvict(cacheNames = "Device", key = "'selectProtocolBySerialNumber:' + #device.getSerialNumber()"), @CacheEvict(cacheNames = "Device", key = "'selectShortDeviceBySerialNumber:' + #device.getSerialNumber()") @@ -331,7 +333,7 @@ public class DeviceServiceImpl implements IDeviceService { @CacheEvict(cacheNames = "Device", allEntries = true) @Override public AjaxResult deleteDeviceByDeviceId(Long deviceId) { - //查询设备 + // 查询设备 Device device = deviceMapper.selectDeviceByDeviceId(deviceId); SysUser user = getLoginUser().getUser(); Long sceneUserId; @@ -356,7 +358,8 @@ public class DeviceServiceImpl implements IDeviceService { } // 设备下不能有场景联动 List sceneDeviceBindVOList = sceneDeviceMapper.listSceneDeviceBind(device.getSerialNumber()); - if (null != sceneDeviceBindVOList.stream().filter(s -> s.getUserId().equals(sceneUserId)).findAny().orElse(null)) { + if (null != sceneDeviceBindVOList.stream().filter(s -> s.getUserId().equals(sceneUserId)).findAny() + .orElse(null)) { return AjaxResult.error("删除失败,请先删除对应设备下的场景联动"); } // 查绑定用户被分享用户配置的场景,需要把场景删掉 @@ -393,7 +396,7 @@ public class DeviceServiceImpl implements IDeviceService { if (null != shareSceneIds && shareSceneIds.length > 0) { sceneService.deleteSceneBySceneIds(shareSceneIds); } - // 删除设备分组。 租户、管理员和设备所有者 + // 删除设备分组。 租户、管理员和设备所有者 deviceMapper.deleteDeviceGroupByDeviceId(new UserIdDeviceIdModel(null, deviceId)); // 删除设备用户。 deviceUserMapper.deleteDeviceUserByDeviceId(new UserIdDeviceIdModel(null, deviceId)); @@ -402,7 +405,7 @@ public class DeviceServiceImpl implements IDeviceService { // deviceJobService.deleteJobByDeviceIds(new Long[]{deviceId}); // 批量删除设备监测日志 logService.deleteDeviceLogByDeviceNumber(device.getSerialNumber()); - // 批量删除设备事件日志 DeviceNumber + // 批量删除设备事件日志 DeviceNumber eventLogService.deleteEventLogBySerialNumber(device.getSerialNumber()); // 批量删除设备功能日志 functionLogService.deleteFunctionLogByDeviceNumber(device.getSerialNumber()); @@ -412,12 +415,12 @@ public class DeviceServiceImpl implements IDeviceService { String key = RedisKeyBuilder.buildTSLVCacheKey(device.getProductId(), device.getSerialNumber()); redisCache.deleteObject(key); // 删除设备 - deviceMapper.deleteDeviceByDeviceIds(new Long[]{deviceId}); + deviceMapper.deleteDeviceByDeviceIds(new Long[] { deviceId }); // redis中删除规则脚本 String cacheKey = RedisKeyBuilder.buildDeviceMsgCacheKey(device.getSerialNumber()); redisCache.deleteObject(cacheKey); // 删除设备 - deviceMapper.deleteDeviceByDeviceIds(new Long[]{deviceId}); + deviceMapper.deleteDeviceByDeviceIds(new Long[] { deviceId }); // 删除tcp协议设备缓存 String tcpKey1 = RedisKeyBuilder.buildModbusTcpCacheKey(device.getSerialNumber()); String tcpKey2 = RedisKeyBuilder.buildModbusTcpRuntimeCacheKey(device.getSerialNumber()); @@ -445,7 +448,6 @@ public class DeviceServiceImpl implements IDeviceService { return AjaxResult.success(); } - /** * TODO-2.3 查询设备统计信息 * @@ -486,7 +488,6 @@ public class DeviceServiceImpl implements IDeviceService { return deviceMapper.selectProductAuthenticate(model); } - /** * 更新设备的物模型 * @@ -497,33 +498,47 @@ public class DeviceServiceImpl implements IDeviceService { */ @Override @DSTransactional - public List reportDeviceThingsModelValue(ThingsModelValuesInput input, int type, boolean isShadow) { - String key = RedisKeyBuilder.buildTSLVCacheKey(input.getProductId(), input.getDeviceNumber()); + public List reportDeviceThingsModelValue(ThingsModelValuesInput input, int type, + boolean isShadow) { + String serialNumber = input.getDeviceNumber(); + String key = RedisKeyBuilder.buildTSLVCacheKey(input.getProductId(), serialNumber); Map maps = new HashMap<>(); List list = new ArrayList<>(); - //属性存储集合 + // 属性存储集合 List deviceLogList = new ArrayList<>(); - //指令存储集合 + // 指令存储集合 List functionLogList = new ArrayList<>(); - //事件存储集合 + // 事件存储集合 List eventLogList = new ArrayList<>(); // 获取当前时间 Date nowDate = DateUtils.getNowDate(); - for (ThingsModelSimpleItem item : input.getThingsModelValueRemarkItem()) { + List thingsModelValueRemarkItem = input.getThingsModelValueRemarkItem(); + // 判断是否有纯计算物模型 有:需要获取设备级别物模型 无:直接使用产品级别物模型即可 + boolean isCalculated = thingsModelValueRemarkItem.stream().anyMatch(ThingsModelSimpleItem::isCalculated); + Map calculatedModelMap = new HashMap<>(); + if (isCalculated) { + calculatedModelMap = itslCache.getDeviceCalculatedModelMap(serialNumber); + } + for (ThingsModelSimpleItem item : thingsModelValueRemarkItem) { String identity = item.getId(); - String serialNumber = input.getDeviceNumber(); if (identity.startsWith("array_")) { identity = identity.substring(9); } - - ThingsModelValueItem thingModels = thingsModelService.getSingleThingModels(input.getProductId(), identity); + ThingsModelValueItem thingModels; + if (item.isCalculated()) { + // itslCache.getSingleDeviceCalculatedModel(serialNumber, identity); + thingModels = calculatedModelMap.get(identity); + } else { + thingModels = thingsModelService.getSingleThingModels(input.getProductId(), identity); + } if (Objects.isNull(thingModels)) { log.warn("=>查询物模型为空[{}],标识符:[{}]", input.getProductId(), identity); continue; // 跳过当前物模型的处理 } // 获取设备实时值 - ValueItem cacheIdentifier = itslValueCache.getCacheIdentifier(input.getProductId(), input.getDeviceNumber(), thingModels.getId()); + ValueItem cacheIdentifier = itslValueCache.getCacheIdentifier(input.getProductId(), serialNumber, + thingModels.getId()); if (Objects.isNull(cacheIdentifier)) { log.warn("=>查询物模型值为空[{}],标识符:[{}]", input.getProductId(), identity); } @@ -531,9 +546,9 @@ public class DeviceServiceImpl implements IDeviceService { String value = item.getValue(); item.setName(thingModels.getName()); - /* ★★★★★★★★★★★★★★★★★★★★★★ 数据计算 -开始 ★★★★★★★★★★★★★★★★★★★★★★*/ - //有计算公式的,经过计算公式 - if (thingModels != null && thingModels.getFormula() != null && !"".equals(thingModels.getFormula())) { + /* ★★★★★★★★★★★★★★★★★★★★★★ 数据计算 -开始 ★★★★★★★★★★★★★★★★★★★★★★ */ + // 有计算公式的,经过计算公式 + if (thingModels.getFormula() != null && StringUtils.isNotEmpty(thingModels.getFormula())) { Map params = new HashMap<>(); // %s 表示当前物模型的值(保持向后兼容) params.put("%s", value); @@ -549,7 +564,7 @@ public class DeviceServiceImpl implements IDeviceService { try { // 优先从当前消息中查找 String refValue = null; - for (ThingsModelSimpleItem currentItem : input.getThingsModelValueRemarkItem()) { + for (ThingsModelSimpleItem currentItem : thingsModelValueRemarkItem) { String currentId = currentItem.getId(); if (currentId.startsWith("array_")) { currentId = currentId.substring(9); @@ -564,9 +579,8 @@ public class DeviceServiceImpl implements IDeviceService { if (refValue == null) { ValueItem refValueItem = itslValueCache.getCacheIdentifier( input.getProductId(), - input.getDeviceNumber(), - refIdentifier - ); + serialNumber, + refIdentifier); if (refValueItem != null && StringUtils.isNotEmpty(refValueItem.getValue())) { refValue = refValueItem.getValue(); } @@ -590,15 +604,15 @@ public class DeviceServiceImpl implements IDeviceService { log.info("=>纯计算物模型结果[{}],标识符:[{}],结果:{}", input.getProductId(), identity, value); item.setValue(value); } - /* ★★★★★★★★★★★★★★★★★★★★★★ 数据计算 -结束 ★★★★★★★★★★★★★★★★★★★★★★*/ + /* ★★★★★★★★★★★★★★★★★★★★★★ 数据计算 -结束 ★★★★★★★★★★★★★★★★★★★★★★ */ - /* ★★★★★★★★★★★★★★★★★★★★★★ 处理数据 - 开始 ★★★★★★★★★★★★★★★★★★★★★★*/ + /* ★★★★★★★★★★★★★★★★★★★★★★ 处理数据 - 开始 ★★★★★★★★★★★★★★★★★★★★★★ */ ValueItem valueItem = new ValueItem(); valueItem.setId(identity); if (id.startsWith("array_")) { // 查询是否有缓存,如果没有先进行缓存 if (!redisCache.containsKey(key)) { - Device device = this.selectDeviceBySerialNumber(input.getDeviceNumber()); + Device device = this.selectDeviceBySerialNumber(serialNumber); this.selectDeviceByDeviceId(device.getDeviceId()); } @@ -623,7 +637,7 @@ public class DeviceServiceImpl implements IDeviceService { valueItem.setShadow(String.join(",", shadows)); } redisCache.setCacheMapValue(key, identity, JSONObject.toJSONString(valueItem)); - //maps.put(identity, JSONObject.toJSONString(valueItem)); + // maps.put(identity, JSONObject.toJSONString(valueItem)); } else { if (isShadow) { valueItem.setShadow(value); @@ -638,11 +652,11 @@ public class DeviceServiceImpl implements IDeviceService { } maps.put(identity, JSONObject.toJSONString(valueItem)); } - /* ★★★★★★★★★★★★★★★★★★★★★★ 处理数据 - 结束 ★★★★★★★★★★★★★★★★★★★★★★*/ + /* ★★★★★★★★★★★★★★★★★★★★★★ 处理数据 - 结束 ★★★★★★★★★★★★★★★★★★★★★★ */ - /*★★★★★★★★★★★★★★★★★★★★★★ 存储数据 - 开始 ★★★★★★★★★★★★★★★★★★★★★★*/ + /* ★★★★★★★★★★★★★★★★★★★★★★ 存储数据 - 开始 ★★★★★★★★★★★★★★★★★★★★★★ */ ThingsModelType modelType = ThingsModelType.getType(thingModels.getType()); - Device device = this.selectDeviceBySerialNumber(input.getDeviceNumber()); + Device device = this.selectDeviceBySerialNumber(serialNumber); switch (modelType) { case PROP: if (1 == thingModels.getIsHistory()) { @@ -670,7 +684,7 @@ public class DeviceServiceImpl implements IDeviceService { FunctionLog function = new FunctionLog(); function.setCreateTime(nowDate); function.setFunValue(value); - function.setSerialNumber(input.getDeviceNumber()); + function.setSerialNumber(serialNumber); function.setIdentify(id); function.setShowValue(value); // 属性获取 @@ -703,22 +717,20 @@ public class DeviceServiceImpl implements IDeviceService { redisCache.hashPutAll(key, maps); // 存储历史数据——批量 if (!CollectionUtils.isEmpty(deviceLogList) && !isShadow) { -// for (DeviceLog deviceLog : deviceLogList) { -// logService.saveDeviceLog(deviceLog); -// } + // for (DeviceLog deviceLog : deviceLogList) { + // logService.saveDeviceLog(deviceLog); + // } logService.saveDeviceLogBatch(deviceLogList); } - //指令存储,影子模式不存储 + // 指令存储,影子模式不存储 if (!CollectionUtils.isEmpty(functionLogList) && !isShadow) { functionLogService.insertBatch(functionLogList); } if (!CollectionUtils.isEmpty(eventLogList)) { - //事件存储 + // 事件存储 eventLogService.saveBatch(eventLogList); } - /* ★★★★★★★★★★★★★★★★★★★★★★ 存储数据 - 结束 ★★★★★★★★★★★★★★★★★★★★★★*/ - - // 注意:纯计算物模型已在 ModbusProtocol 中构造 ThingsModelSimpleItem(值为0) + /* ★★★★★★★★★★★★★★★★★★★★★★ 存储数据 - 结束 ★★★★★★★★★★★★★★★★★★★★★★ */ return list; } @@ -751,17 +763,17 @@ public class DeviceServiceImpl implements IDeviceService { */ @Override public List selectDeviceList(Device device) { -// SysUser user = getLoginUser().getUser(); -// List roles = user.getRoles(); -// for (int i = 0; i < roles.size(); i++) { -// if (roles.get(i).getRoleKey().equals("tenant")) { -// // 租户查看产品下所有设备 -// device.setTenantId(user.getUserId()); -// } else if (roles.get(i).getRoleKey().equals("general")) { -// // 用户查看自己设备 -// device.setUserId(user.getUserId()); -// } -// } + // SysUser user = getLoginUser().getUser(); + // List roles = user.getRoles(); + // for (int i = 0; i < roles.size(); i++) { + // if (roles.get(i).getRoleKey().equals("tenant")) { + // // 租户查看产品下所有设备 + // device.setTenantId(user.getUserId()); + // } else if (roles.get(i).getRoleKey().equals("general")) { + // // 用户查看自己设备 + // device.setUserId(user.getUserId()); + // } + // } return deviceMapper.selectDeviceList(device); } @@ -773,17 +785,17 @@ public class DeviceServiceImpl implements IDeviceService { */ @Override public List selectUnAuthDeviceList(Device device) { -// SysUser user = getLoginUser().getUser(); -// List roles = user.getRoles(); -// for (int i = 0; i < roles.size(); i++) { -// if (roles.get(i).getRoleKey().equals("tenant")) { -// // 租户查看产品下所有设备 -// device.setTenantId(user.getUserId()); -// } else if (roles.get(i).getRoleKey().equals("general")) { -// // 用户查看自己设备 -// device.setUserId(user.getUserId()); -// } -// } + // SysUser user = getLoginUser().getUser(); + // List roles = user.getRoles(); + // for (int i = 0; i < roles.size(); i++) { + // if (roles.get(i).getRoleKey().equals("tenant")) { + // // 租户查看产品下所有设备 + // device.setTenantId(user.getUserId()); + // } else if (roles.get(i).getRoleKey().equals("general")) { + // // 用户查看自己设备 + // device.setUserId(user.getUserId()); + // } + // } return deviceMapper.selectUnAuthDeviceList(device); } @@ -795,17 +807,17 @@ public class DeviceServiceImpl implements IDeviceService { */ @Override public List selectDeviceListByGroup(Device device) { -// SysUser user = getLoginUser().getUser(); -// List roles = user.getRoles(); -// for (int i = 0; i < roles.size(); i++) { -// if (roles.get(i).getRoleKey().equals("tenant")) { -// // 租户查看产品下所有设备 -// device.setTenantId(user.getUserId()); -// } else if (roles.get(i).getRoleKey().equals("general")) { -// // 用户查看自己设备 -// device.setUserId(user.getUserId()); -// } -// } + // SysUser user = getLoginUser().getUser(); + // List roles = user.getRoles(); + // for (int i = 0; i < roles.size(); i++) { + // if (roles.get(i).getRoleKey().equals("tenant")) { + // // 租户查看产品下所有设备 + // device.setTenantId(user.getUserId()); + // } else if (roles.get(i).getRoleKey().equals("general")) { + // // 用户查看自己设备 + // device.setUserId(user.getUserId()); + // } + // } return deviceMapper.selectDeviceListByGroup(device); } @@ -845,7 +857,8 @@ public class DeviceServiceImpl implements IDeviceService { SysUser user = getLoginUser().getUser(); if (null != user.getDept()) { Long tenantId = user.getDept().getDeptUserId(); - serialNumberList = list.stream().filter(d -> tenantId.equals(d.getTenantId())).map(DeviceShortOutput::getSerialNumber).collect(Collectors.toList()); + serialNumberList = list.stream().filter(d -> tenantId.equals(d.getTenantId())) + .map(DeviceShortOutput::getSerialNumber).collect(Collectors.toList()); } else { serialNumberList = list.stream().map(DeviceShortOutput::getSerialNumber).collect(Collectors.toList()); } @@ -870,19 +883,42 @@ public class DeviceServiceImpl implements IDeviceService { @Override public DeviceShortOutput selectDeviceRunningStatusByDeviceId(Long deviceId) { DeviceShortOutput device = deviceMapper.selectDeviceRunningStatusByDeviceId(deviceId); - JSONObject thingsModelObject = JSONObject.parseObject(itslCache.getCacheThingsModelByProductId(device.getProductId())); + // 1. 获取产品级物模型 + JSONObject thingsModelObject = JSONObject + .parseObject(itslCache.getCacheThingsModelByProductId(device.getProductId())); JSONArray properties = thingsModelObject.getJSONArray("properties"); JSONArray functions = thingsModelObject.getJSONArray("functions"); - List thingsModelValueItems = itslValueCache.getCacheDeviceStatus(device.getProductId(), device.getSerialNumber()); + List thingsModelValueItems = itslValueCache.getCacheDeviceStatus(device.getProductId(), + device.getSerialNumber()); // 物模型转换赋值 List thingsList = new ArrayList<>(); - //判断一下properties 和 functions是否为空, 否则报空指针 + // 判断一下properties 和 functions是否为空, 否则报空指针 if (!CollectionUtils.isEmpty(properties)) { thingsList.addAll(convertJsonToThingsList(properties, thingsModelValueItems, 1)); } if (!CollectionUtils.isEmpty(functions)) { thingsList.addAll(convertJsonToThingsList(functions, thingsModelValueItems, 2)); } + + // 2. 获取设备级计算物模型并合并 + Map deviceCalculatedMap = itslCache + .getDeviceCalculatedModelMap(device.getSerialNumber()); + if (!CollectionUtils.isEmpty(deviceCalculatedMap)) { + for (ThingsModelValueItem item : deviceCalculatedMap.values()) { + // 获取缓存值 + ValueItem valueItem = thingsModelValueItems.stream() + .filter(v -> v.getId().equals(item.getId())) + .findFirst() + .orElse(null); + if (valueItem != null) { + item.setValue(valueItem.getValue()); + item.setShadow(valueItem.getShadow()); + item.setTs(valueItem.getTs()); + } + thingsList.add(item); + } + } + device.setThingsModels(thingsList); return device; @@ -897,7 +933,8 @@ public class DeviceServiceImpl implements IDeviceService { * @return */ @Async - public List convertJsonToThingsList(JSONArray jsonArray, List thingsModelValues, Integer type) { + public List convertJsonToThingsList(JSONArray jsonArray, List thingsModelValues, + Integer type) { List thingsModelList = new ArrayList<>(); for (int i = 0; i < jsonArray.size(); i++) { ThingsModelValueItem thingsModel = new ThingsModelValueItem(); @@ -905,11 +942,15 @@ public class DeviceServiceImpl implements IDeviceService { JSONObject datatypeJson = thingsJson.getJSONObject("datatype"); thingsModel.setId(thingsJson.getString("id")); thingsModel.setName(thingsJson.getString("name")); - thingsModel.setIsMonitor(thingsJson.getInteger("isMonitor") == null ? 0 : thingsJson.getInteger("isMonitor")); - thingsModel.setIsReadonly(thingsJson.getInteger("isReadonly") == null ? 0 : thingsJson.getInteger("isReadonly")); + thingsModel + .setIsMonitor(thingsJson.getInteger("isMonitor") == null ? 0 : thingsJson.getInteger("isMonitor")); + thingsModel.setIsReadonly( + thingsJson.getInteger("isReadonly") == null ? 0 : thingsJson.getInteger("isReadonly")); thingsModel.setIsChart(thingsJson.getInteger("isChart") == null ? 0 : thingsJson.getInteger("isChart")); - thingsModel.setIsSharePerm(thingsJson.getInteger("isSharePerm") == null ? 0 : thingsJson.getInteger("isSharePerm")); - thingsModel.setIsHistory(thingsJson.getInteger("isHistory") == null ? 0 : thingsJson.getInteger("isHistory")); + thingsModel.setIsSharePerm( + thingsJson.getInteger("isSharePerm") == null ? 0 : thingsJson.getInteger("isSharePerm")); + thingsModel + .setIsHistory(thingsJson.getInteger("isHistory") == null ? 0 : thingsJson.getInteger("isHistory")); thingsModel.setIsApp(thingsJson.getInteger("isApp") == null ? 0 : thingsJson.getInteger("isApp")); thingsModel.setOrder(thingsJson.getInteger("order") == null ? 0 : thingsJson.getInteger("order")); thingsModel.setType(type); @@ -957,9 +998,10 @@ public class DeviceServiceImpl implements IDeviceService { * @param parentIdentifier 上级标识符 * @return */ - private Datatype convertJsonToDataType(JSONObject datatypeJson, List thingsModelValues, Integer type, String parentIdentifier) { + private Datatype convertJsonToDataType(JSONObject datatypeJson, List thingsModelValues, Integer type, + String parentIdentifier) { Datatype dataType = new Datatype(); - //有些物模型数据定义为空的情况兼容 + // 有些物模型数据定义为空的情况兼容 if (datatypeJson == null) { return dataType; } @@ -986,10 +1028,12 @@ public class DeviceServiceImpl implements IDeviceService { } else if (dataType.getType().equals("object")) { JSONArray jsonArray = JSON.parseArray(datatypeJson.getString("params")); // 物模型值过滤(parentId_开头) - thingsModelValues = thingsModelValues.stream().filter(x -> x.getId().startsWith(parentIdentifier)).collect(Collectors.toList()); + thingsModelValues = thingsModelValues.stream().filter(x -> x.getId().startsWith(parentIdentifier)) + .collect(Collectors.toList()); List thingsList = convertJsonToThingsList(jsonArray, thingsModelValues, type); // 排序 - thingsList = thingsList.stream().sorted(Comparator.comparing(ThingsModelValueItem::getOrder).reversed()).collect(Collectors.toList()); + thingsList = thingsList.stream().sorted(Comparator.comparing(ThingsModelValueItem::getOrder).reversed()) + .collect(Collectors.toList()); dataType.setParams(thingsList); } else if (dataType.getType().equals("array")) { dataType.setArrayType(datatypeJson.getString("arrayType")); @@ -998,10 +1042,12 @@ public class DeviceServiceImpl implements IDeviceService { // 对象数组 JSONArray jsonArray = datatypeJson.getJSONArray("params"); // 物模型值过滤(parentId_开头) - thingsModelValues = thingsModelValues.stream().filter(x -> x.getId().startsWith(parentIdentifier)).collect(Collectors.toList()); + thingsModelValues = thingsModelValues.stream().filter(x -> x.getId().startsWith(parentIdentifier)) + .collect(Collectors.toList()); List thingsList = convertJsonToThingsList(jsonArray, thingsModelValues, type); // 排序 - thingsList = thingsList.stream().sorted(Comparator.comparing(ThingsModelValueItem::getOrder).reversed()).collect(Collectors.toList()); + thingsList = thingsList.stream().sorted(Comparator.comparing(ThingsModelValueItem::getOrder).reversed()) + .collect(Collectors.toList()); // 数组类型物模型里面对象赋值 List[] arrayParams = new List[dataType.getArrayCount()]; for (int i = 0; i < dataType.getArrayCount(); i++) { @@ -1053,7 +1099,7 @@ public class DeviceServiceImpl implements IDeviceService { throw new ServiceException("设备编号:" + device.getSerialNumber() + " 已经存在,新增失败"); } SysUser sysUser = getLoginUser().getUser(); - //添加设备 + // 添加设备 device.setCreateTime(DateUtils.getNowDate()); device.setTenantId(sysUser.getDept().getDeptUserId()); device.setTenantName(sysUser.getDept().getDeptUserName()); @@ -1067,7 +1113,8 @@ public class DeviceServiceImpl implements IDeviceService { setLocation(user.getLoginIp(), device); deviceMapper.insertDevice(device); // 处理modbus产品 - if (FastBeeConstant.PROTOCOL.ModbusRtu.equals(product.getProtocolCode()) || FastBeeConstant.PROTOCOL.ModbusTcp.equals(product.getProtocolCode())) { + if (FastBeeConstant.PROTOCOL.ModbusRtu.equals(product.getProtocolCode()) + || FastBeeConstant.PROTOCOL.ModbusTcp.equals(product.getProtocolCode())) { this.handleModbusConfig(device, product); } // redis缓存设备默认状态(物模型值) @@ -1104,15 +1151,18 @@ public class DeviceServiceImpl implements IDeviceService { return; } productSubGatewayList.sort(Comparator.comparing(ProductSubGatewayVO::getSlaveId)); - List subProductIdList = productSubGatewayList.stream().map(ProductSubGatewayVO::getSubProductId).collect(Collectors.toList()); + List subProductIdList = productSubGatewayList.stream().map(ProductSubGatewayVO::getSubProductId) + .collect(Collectors.toList()); LambdaQueryWrapper queryWrapper1 = new LambdaQueryWrapper<>(); queryWrapper1.in(ProductModbusJob::getProductId, subProductIdList); List productModbusJobList = productModbusJobMapper.selectList(queryWrapper1); - Map> productModbusJobMap = productModbusJobList.stream().collect(Collectors.groupingBy(ProductModbusJob::getProductId)); + Map> productModbusJobMap = productModbusJobList.stream() + .collect(Collectors.groupingBy(ProductModbusJob::getProductId)); // 新增子设备、绑定子设备、子设备生成轮询 for (ProductSubGatewayVO productSubGatewayVO : productSubGatewayList) { Device addDevice = new Device(); - addDevice.setDeviceName(productSubGatewayVO.getSubProductName() + "_" + productSubGatewayVO.getSlaveId()); + addDevice.setDeviceName( + productSubGatewayVO.getSubProductName() + "_" + productSubGatewayVO.getSlaveId()); addDevice.setProductId(productSubGatewayVO.getSubProductId()); addDevice.setProductName(productSubGatewayVO.getSubProductName()); String serialNumber = this.generationDeviceNum(1); @@ -1134,7 +1184,8 @@ public class DeviceServiceImpl implements IDeviceService { subGateway.setCreateBy(addDevice.getCreateBy()); subGateway.setCreateTime(new Date()); subGatewayMapper.insertGateway(subGateway); - List productModbusList = productModbusJobMap.get(productSubGatewayVO.getSubProductId()); + List productModbusList = productModbusJobMap + .get(productSubGatewayVO.getSubProductId()); if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(productModbusList)) { for (ProductModbusJob productModbusJob : productModbusList) { ModbusJob modbusJob = new ModbusJob(); @@ -1164,12 +1215,12 @@ public class DeviceServiceImpl implements IDeviceService { @Override @Transactional(rollbackFor = Exception.class) public AjaxResult deviceRelateUser(DeviceRelateUserInput params) { - Long userId = params.getUserId(); //终端用户id + Long userId = params.getUserId(); // 终端用户id // 查询用户信息 SysUser sysUser = userService.selectUserById(userId); for (DeviceNumberAndProductId item : params.getDeviceNumberAndProductIds()) { Device existDevice = deviceMapper.selectDeviceBySerialNumber(item.getDeviceNumber()); - //查看设备是否已经分配 + // 查看设备是否已经分配 if (!Objects.isNull(existDevice)) { if (null != sysUser.getDeptId()) { return AjaxResult.error("租户不允许绑定已存在的设备,设备编号:" + item.getDeviceNumber()); @@ -1183,7 +1234,8 @@ public class DeviceServiceImpl implements IDeviceService { } } // 先删除设备的所有用户 - //deviceUserMapper.deleteDeviceUserByDeviceId(new UserIdDeviceIdModel(null, existDevice.getDeviceId())); + // deviceUserMapper.deleteDeviceUserByDeviceId(new UserIdDeviceIdModel(null, + // existDevice.getDeviceId())); // 添加新的设备用户 DeviceUser deviceUser = new DeviceUser(); deviceUser.setUserId(sysUser.getUserId()); @@ -1265,13 +1317,14 @@ public class DeviceServiceImpl implements IDeviceService { @Override public ThingsModelShadow getDeviceShadowThingsModel(Device device) { // 物模型值 - List thingsModelValueItems = itslValueCache.getCacheDeviceStatus(device.getProductId(), device.getSerialNumber()); + List thingsModelValueItems = itslValueCache.getCacheDeviceStatus(device.getProductId(), + device.getSerialNumber()); ThingsModelShadow shadow = new ThingsModelShadow(); // 查询出设置的影子值 - //List shadowList = new ArrayList<>(); + // List shadowList = new ArrayList<>(); for (ValueItem item : thingsModelValueItems) { if (!item.getShadow().equals(item.getValue()) && !item.getShadow().isEmpty()) { - //处理id + // 处理id String id = item.getId(); if (item.getShadow().contains(",")) { String[] shadows = item.getShadow().split(","); @@ -1297,7 +1350,6 @@ public class DeviceServiceImpl implements IDeviceService { return shadow; } - /** * 生成设备唯一编号 * @@ -1308,7 +1360,7 @@ public class DeviceServiceImpl implements IDeviceService { // 设备编号:D + userId + 15位随机字母和数字 SysUser user = getLoginUser().getUser(); String number; - //Hex随机字符串 + // Hex随机字符串 if (type == 3) { number = toolService.generateRandomHex(12); } else { @@ -1433,8 +1485,8 @@ public class DeviceServiceImpl implements IDeviceService { deviceUserMapper.insertDeviceUser(deviceUser); } // 更新设备用户信息 多租户版本不需要 -// device.setTenantId(device.getTenantId()); -// device.setTenantName(sysUser.getUserName()); + // device.setTenantId(device.getTenantId()); + // device.setTenantName(sysUser.getUserName()); } device.setUpdateTime(DateUtils.getNowDate()); if (deviceEntity.getActiveTime() == null || deviceEntity.getActiveTime().equals("")) { @@ -1459,7 +1511,6 @@ public class DeviceServiceImpl implements IDeviceService { return deviceMapper.selectDevicesByProductId(productId, hasSub); } - /** * 批量更新设备状态 * @@ -1472,7 +1523,7 @@ public class DeviceServiceImpl implements IDeviceService { if (CollectionUtils.isEmpty(serialNumbers)) { return; } - //设备离线 + // 设备离线 if (DeviceStatus.OFFLINE.equals(status)) { deviceMapper.batchChangeOffline(serialNumbers); } else if (DeviceStatus.ONLINE.equals(status)) { @@ -1514,21 +1565,28 @@ public class DeviceServiceImpl implements IDeviceService { String password; if (ProductAuthConstant.AUTHORIZE.equals(deviceMqttVO.getIsAuthorize())) { // 查询产品授权码 - List productAuthorizeList = productAuthorizeService.listByProductId(deviceMqttVO.getProductId()); + List productAuthorizeList = productAuthorizeService + .listByProductId(deviceMqttVO.getProductId()); if (CollectionUtils.isEmpty(productAuthorizeList)) { throw new ServiceException("产品已启用授权,获取设备授权码失败,请先配置授权码"); } - List collect = productAuthorizeList.stream().filter(p -> p.getProductId().equals(deviceMqttVO.getDeviceId())).collect(Collectors.toList()); - ProductAuthorize productAuthorize = CollectionUtils.isEmpty(collect) ? productAuthorizeList.get(0) : collect.get(0); + List collect = productAuthorizeList.stream() + .filter(p -> p.getProductId().equals(deviceMqttVO.getDeviceId())).collect(Collectors.toList()); + ProductAuthorize productAuthorize = CollectionUtils.isEmpty(collect) ? productAuthorizeList.get(0) + : collect.get(0); password = deviceMqttVO.getMqttPassword() + "&" + productAuthorize.getAuthorizeCode(); } else { password = deviceMqttVO.getMqttPassword(); } - String clientId = ProductAuthConstant.CLIENT_ID_AUTH_TYPE_SIMPLE + "&" + deviceMqttVO.getSerialNumber() + "&" + deviceMqttVO.getProductId() + "&" + deviceMqttVO.getTenantId(); + String clientId = ProductAuthConstant.CLIENT_ID_AUTH_TYPE_SIMPLE + "&" + deviceMqttVO.getSerialNumber() + "&" + + deviceMqttVO.getProductId() + "&" + deviceMqttVO.getTenantId(); // 组装返回结果 - connectVO.setClientId(clientId).setUsername(deviceMqttVO.getMqttAccount()).setPasswd(password).setPort(brokerPort); - connectVO.setSubscribeTopic("/" + deviceMqttVO.getProductId() + "/" + deviceMqttVO.getSerialNumber() + "/function/get"); - connectVO.setReportTopic("/" + deviceMqttVO.getProductId() + "/" + deviceMqttVO.getSerialNumber() + "/property/post"); + connectVO.setClientId(clientId).setUsername(deviceMqttVO.getMqttAccount()).setPasswd(password) + .setPort(brokerPort); + connectVO.setSubscribeTopic( + "/" + deviceMqttVO.getProductId() + "/" + deviceMqttVO.getSerialNumber() + "/function/get"); + connectVO.setReportTopic( + "/" + deviceMqttVO.getProductId() + "/" + deviceMqttVO.getSerialNumber() + "/property/post"); return connectVO; } @@ -1548,7 +1606,7 @@ public class DeviceServiceImpl implements IDeviceService { */ private void setLocation(String ip, Device device) { String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp"; - //String address = "未知地址"; + // String address = "未知地址"; // 内网不查询 if (IpUtils.internalIp(ip)) { device.setNetworkAddress("内网IP"); @@ -1576,13 +1634,15 @@ public class DeviceServiceImpl implements IDeviceService { String BAIDU_URL = "http://api.map.baidu.com/geocoding/v3/"; city = StrUtil.isEmpty(city) ? "湖南省长沙市岳麓区" : city; String encodedAddress = URLEncoder.encode(city, StandardCharsets.UTF_8.toString()); - String baiduResponse = HttpUtils.sendGet(BAIDU_URL, "address=" + encodedAddress + "&output=json&ak=" + baiduAK, Constants.UTF8); + String baiduResponse = HttpUtils.sendGet(BAIDU_URL, "address=" + encodedAddress + "&output=json&ak=" + baiduAK, + Constants.UTF8); if (!StringUtils.isEmpty(baiduResponse)) { JSONObject baiduObject = JSONObject.parseObject(baiduResponse); JSONObject location = baiduObject.getJSONObject("result").getJSONObject("location"); device.setLongitude(location.getBigDecimal("lng")); device.setLatitude(location.getBigDecimal("lat")); - System.out.println(device.getSerialNumber() + "- 设置经度:" + location.getBigDecimal("lng") + ",设置纬度:" + location.getBigDecimal("lat")); + System.out.println(device.getSerialNumber() + "- 设置经度:" + location.getBigDecimal("lng") + ",设置纬度:" + + location.getBigDecimal("lat")); } } @@ -1597,7 +1657,6 @@ public class DeviceServiceImpl implements IDeviceService { return deviceMapper.getDeviceNumsByProductId(productId); } - /** * 重置设备状态 * @@ -1616,7 +1675,8 @@ public class DeviceServiceImpl implements IDeviceService { if (null == product) { return "导入失败,产品信息为空"; } - List serialNumberList = deviceImportVOList.stream().map(DeviceImportVO::getSerialNumber).collect(Collectors.toList()); + List serialNumberList = deviceImportVOList.stream().map(DeviceImportVO::getSerialNumber) + .collect(Collectors.toList()); List oldSerialNumberList = deviceMapper.checkExistBySerialNumbers(serialNumberList); if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(oldSerialNumberList)) { return "以下设备编号(" + JSON.toJSONString(oldSerialNumberList) + ")已存在,请修改后重试"; @@ -1645,12 +1705,16 @@ public class DeviceServiceImpl implements IDeviceService { int result = deviceMapper.insertBatchDevice(deviceList); // 新增导入记录 DeviceRecord deviceRecord = new DeviceRecord(); - deviceRecord.setOperateDeptId(loginUser.getDeptId()).setProductId(productId).setType(DeviceRecordTypeEnum.IMPORT.getType()) - .setTotal(deviceList.size()).setTenantId(loginUser.getUser().getDept().getDeptUserId()).setTenantName(loginUser.getUser().getDept().getDeptUserName()); + deviceRecord.setOperateDeptId(loginUser.getDeptId()).setProductId(productId) + .setType(DeviceRecordTypeEnum.IMPORT.getType()) + .setTotal(deviceList.size()).setTenantId(loginUser.getUser().getDept().getDeptUserId()) + .setTenantName(loginUser.getUser().getDept().getDeptUserName()); if (result > 0) { - deviceRecord.setStatus(StatusEnum.SUCCESS.getStatus()).setSuccessQuantity(deviceList.size()).setFailQuantity(0); + deviceRecord.setStatus(StatusEnum.SUCCESS.getStatus()).setSuccessQuantity(deviceList.size()) + .setFailQuantity(0); } else { - deviceRecord.setStatus(StatusEnum.FAIL.getStatus()).setSuccessQuantity(0).setFailQuantity(deviceList.size()); + deviceRecord.setStatus(StatusEnum.FAIL.getStatus()).setSuccessQuantity(0) + .setFailQuantity(deviceList.size()); } deviceRecord.setCreateBy(loginUser.getUsername()); deviceRecordMapper.insertDeviceRecord(deviceRecord); @@ -1664,7 +1728,8 @@ public class DeviceServiceImpl implements IDeviceService { if (null == product) { return "导入失败,产品信息为空"; } - List serialNumberList = deviceAssignmentVOS.stream().map(DeviceAssignmentVO::getSerialNumber).collect(Collectors.toList()); + List serialNumberList = deviceAssignmentVOS.stream().map(DeviceAssignmentVO::getSerialNumber) + .collect(Collectors.toList()); List oldSerialNumberList = deviceMapper.checkExistBySerialNumbers(serialNumberList); if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(oldSerialNumberList)) { return "以下设备编号(" + JSON.toJSONString(oldSerialNumberList) + ")已存在,请修改后重试"; @@ -1701,8 +1766,11 @@ public class DeviceServiceImpl implements IDeviceService { int result = deviceMapper.insertBatchDevice(deviceList); // 新增导入记录 DeviceRecord deviceRecord = new DeviceRecord(); - deviceRecord.setOperateDeptId(loginUser.getDeptId()).setTargetDeptId(deptId).setTargetDeptId(deptId).setProductId(productId).setDistributeType(DeviceDistributeTypeEnum.IMPORT.getType()) - .setType(DeviceRecordTypeEnum.ASSIGNMENT.getType()).setTotal(deviceList.size()).setTenantId(loginUser.getUser().getDept().getDeptUserId()).setTenantName(loginUser.getUser().getDept().getDeptUserName()); + deviceRecord.setOperateDeptId(loginUser.getDeptId()).setTargetDeptId(deptId).setTargetDeptId(deptId) + .setProductId(productId).setDistributeType(DeviceDistributeTypeEnum.IMPORT.getType()) + .setType(DeviceRecordTypeEnum.ASSIGNMENT.getType()).setTotal(deviceList.size()) + .setTenantId(loginUser.getUser().getDept().getDeptUserId()) + .setTenantName(loginUser.getUser().getDept().getDeptUserName()); List deviceRecordList = new ArrayList<>(); if (result > 0) { deviceRecord.setStatus(StatusEnum.SUCCESS.getStatus()); @@ -1717,10 +1785,15 @@ public class DeviceServiceImpl implements IDeviceService { int insertRecordStatus = deviceRecordMapper.insertDeviceRecord(deviceRecord); for (Device device : deviceList) { DeviceRecord deviceRecord1 = new DeviceRecord(); - deviceRecord1.setOperateDeptId(loginUser.getDeptId()).setTargetDeptId(deptId).setProductId(productId).setDeviceId(device.getDeviceId()) - .setType(DeviceRecordTypeEnum.ASSIGNMENT_DETAIL.getType()).setParentId(deviceRecord.getId()).setSerialNumber(device.getSerialNumber()) - .setDistributeType(DeviceDistributeTypeEnum.IMPORT.getType()).setTenantId(loginUser.getUser().getDept().getDeptUserId()).setTenantName(loginUser.getUser().getDept().getDeptUserName()); - deviceRecord1.setStatus(insertRecordStatus > 0 ? StatusEnum.SUCCESS.getStatus() : StatusEnum.FAIL.getStatus()); + deviceRecord1.setOperateDeptId(loginUser.getDeptId()).setTargetDeptId(deptId).setProductId(productId) + .setDeviceId(device.getDeviceId()) + .setType(DeviceRecordTypeEnum.ASSIGNMENT_DETAIL.getType()).setParentId(deviceRecord.getId()) + .setSerialNumber(device.getSerialNumber()) + .setDistributeType(DeviceDistributeTypeEnum.IMPORT.getType()) + .setTenantId(loginUser.getUser().getDept().getDeptUserId()) + .setTenantName(loginUser.getUser().getDept().getDeptUserName()); + deviceRecord1 + .setStatus(insertRecordStatus > 0 ? StatusEnum.SUCCESS.getStatus() : StatusEnum.FAIL.getStatus()); deviceRecord1.setCreateBy(loginUser.getUsername()); deviceRecordList.add(deviceRecord1); } @@ -1750,11 +1823,14 @@ public class DeviceServiceImpl implements IDeviceService { if (null == sysUser) { return AjaxResult.error("机构管理员不存在"); } - List deviceIdList = Arrays.stream(deviceIds.split(",")).map(d -> Long.parseLong(d.trim())).distinct().collect(Collectors.toList()); + List deviceIdList = Arrays.stream(deviceIds.split(",")).map(d -> Long.parseLong(d.trim())).distinct() + .collect(Collectors.toList()); int result = deviceMapper.updateTenantIdByDeptIds(deptUserId, sysUser.getUserName(), deviceIdList); DeviceRecord deviceRecord = new DeviceRecord(); - deviceRecord.setOperateDeptId(user.getDeptId()).setTargetDeptId(deptId).setTargetDeptId(deptId).setDistributeType(DeviceDistributeTypeEnum.SELECT.getType()) - .setType(DeviceRecordTypeEnum.ASSIGNMENT.getType()).setTotal(deviceIdList.size()).setTenantId(user.getDept().getDeptUserId()).setTenantName(user.getDept().getDeptUserName()); + deviceRecord.setOperateDeptId(user.getDeptId()).setTargetDeptId(deptId).setTargetDeptId(deptId) + .setDistributeType(DeviceDistributeTypeEnum.SELECT.getType()) + .setType(DeviceRecordTypeEnum.ASSIGNMENT.getType()).setTotal(deviceIdList.size()) + .setTenantId(user.getDept().getDeptUserId()).setTenantName(user.getDept().getDeptUserName()); if (result > 0) { deviceRecord.setStatus(StatusEnum.SUCCESS.getStatus()); deviceRecord.setSuccessQuantity(deviceIdList.size()); @@ -1773,8 +1849,10 @@ public class DeviceServiceImpl implements IDeviceService { deviceRecord1.setOperateDeptId(user.getDeptId()).setTargetDeptId(deptId).setDeviceId(device.getDeviceId()) .setProductId(device.getProductId()).setSerialNumber(device.getSerialNumber()) .setType(DeviceRecordTypeEnum.ASSIGNMENT_DETAIL.getType()).setParentId(deviceRecord.getId()) - .setDistributeType(DeviceDistributeTypeEnum.SELECT.getType()).setTenantId(user.getDept().getDeptUserId()).setTenantName(user.getDept().getDeptUserName()); - deviceRecord1.setStatus(insertRecordStatus > 0 ? StatusEnum.SUCCESS.getStatus() : StatusEnum.FAIL.getStatus()); + .setDistributeType(DeviceDistributeTypeEnum.SELECT.getType()) + .setTenantId(user.getDept().getDeptUserId()).setTenantName(user.getDept().getDeptUserName()); + deviceRecord1 + .setStatus(insertRecordStatus > 0 ? StatusEnum.SUCCESS.getStatus() : StatusEnum.FAIL.getStatus()); deviceRecord1.setCreateBy(user.getUserName()); deviceRecordList.add(deviceRecord1); } @@ -1795,7 +1873,8 @@ public class DeviceServiceImpl implements IDeviceService { if (null == sysUser) { return AjaxResult.error("机构管理员不存在"); } - List deviceIdList = Arrays.stream(deviceIds.split(",")).map(d -> Long.parseLong(d.trim())).distinct().collect(Collectors.toList()); + List deviceIdList = Arrays.stream(deviceIds.split(",")).map(d -> Long.parseLong(d.trim())).distinct() + .collect(Collectors.toList()); int result = deviceMapper.updateTenantIdByDeptIds(deptUserId, sysUser.getUserName(), deviceIdList); List deviceRecordList = new ArrayList<>(); List deviceList = deviceMapper.selectDeviceListByDeviceIds(deviceIdList); @@ -1803,7 +1882,9 @@ public class DeviceServiceImpl implements IDeviceService { DeviceRecord deviceRecord1 = new DeviceRecord(); deviceRecord1.setOperateDeptId(deptId).setTargetDeptId(recoveryDeptId).setDeviceId(device.getDeviceId()) .setProductId(device.getProductId()).setSerialNumber(device.getSerialNumber()) - .setType(DeviceRecordTypeEnum.RECOVERY.getType()).setTenantId(loginUser.getUser().getDept().getDeptUserId()).setTenantName(loginUser.getUser().getDept().getDeptUserName()); + .setType(DeviceRecordTypeEnum.RECOVERY.getType()) + .setTenantId(loginUser.getUser().getDept().getDeptUserId()) + .setTenantName(loginUser.getUser().getDept().getDeptUserName()); deviceRecord1.setStatus(result > 0 ? StatusEnum.SUCCESS.getStatus() : StatusEnum.FAIL.getStatus()); deviceRecord1.setCreateBy(loginUser.getUsername()); deviceRecordList.add(deviceRecord1); @@ -1833,16 +1914,16 @@ public class DeviceServiceImpl implements IDeviceService { return deviceMapper.selectDeviceByChannelId(channelId); } - @Override public List listThingsModel(Long deviceId) { DeviceShortOutput device = deviceMapper.selectDeviceRunningStatusByDeviceId(deviceId); if (null == device) { return new ArrayList<>(); } - //管理员可以下发,其他看指令控制 + // 管理员可以下发,其他看指令控制 int canSend = getLoginUser().getUserId().equals(getLoginUser().getDeptUserId()) ? 1 : 0; - List list = thingsModelService.getCacheAndHandleArrayByProductId(device.getProductId(), device.getSerialNumber()); + List list = thingsModelService.getCacheAndHandleArrayByProductId(device.getProductId(), + device.getSerialNumber()); for (ThingsModelDTO thingsModelDTO : list) { thingsModelDTO.setProductId(device.getProductId()); thingsModelDTO.setSerialNumber(device.getSerialNumber()); @@ -1853,7 +1934,8 @@ public class DeviceServiceImpl implements IDeviceService { subGateway.setGwDeviceId(deviceId); List subDeviceListVOList = subGatewayMapper.selectGatewayList(subGateway); for (SubDeviceListVO subDeviceListVO : subDeviceListVOList) { - List subList = thingsModelService.getCacheAndHandleArrayByProductId(subDeviceListVO.getSubProductId(), subDeviceListVO.getSubDeviceNo()); + List subList = thingsModelService.getCacheAndHandleArrayByProductId( + subDeviceListVO.getSubProductId(), subDeviceListVO.getSubDeviceNo()); for (ThingsModelDTO thingsModelDTO : subList) { thingsModelDTO.setProductId(subDeviceListVO.getSubProductId()); thingsModelDTO.setSerialNumber(subDeviceListVO.getSubDeviceNo()); @@ -1863,21 +1945,22 @@ public class DeviceServiceImpl implements IDeviceService { } list.addAll(subList); } - //指令控制 + // 指令控制 jurisdictionThingsModel(list, deviceId); return list; } private void jurisdictionThingsModel(List list, Long deviceId) { Long userId = SecurityUtils.getUserId(); - //查询是否有指令控制 + // 查询是否有指令控制 List orderControls = orderControlService.selectByUserId(userId, deviceId); - if (CollectionUtils.isEmpty(orderControls)) return; + if (CollectionUtils.isEmpty(orderControls)) + return; List modelIdList = new ArrayList<>(); for (OrderControl control : orderControls) { String selectOrder = control.getSelectOrder(); String[] split = selectOrder.split(","); - //判断是否生效 + // 判断是否生效 boolean just = just(control); if (just) { List ids = Arrays.stream(split).map(Long::valueOf).collect(Collectors.toList()); @@ -1906,11 +1989,12 @@ public class DeviceServiceImpl implements IDeviceService { @Override public void updateByOrder(Long userId, Long deviceId) { - //处理指令权限问题 ,非管理员角色 + // 处理指令权限问题 ,非管理员角色 List controlList = orderControlService.selectByUserId(userId, deviceId); - controlList = controlList.stream().filter(control -> Objects.equals(control.getStatus(), "1")).collect(Collectors.toList()); + controlList = controlList.stream().filter(control -> Objects.equals(control.getStatus(), "1")) + .collect(Collectors.toList()); if (!CollectionUtils.isEmpty(controlList)) { - //更新次数 + // 更新次数 OrderControl control = controlList.get(0); control.setCount(control.getCount() - 1); orderControlService.updateOrderControl(control); @@ -1928,7 +2012,6 @@ public class DeviceServiceImpl implements IDeviceService { return deviceMapper.listDeviceGroupByGroupIds(groupIds); } - /** * 查询产品下所有设备,返回设备编号 * @@ -1940,7 +2023,4 @@ public class DeviceServiceImpl implements IDeviceService { return deviceMapper.selectSerialNumbersByProductId(productId); } - - } - diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/ModbusConfigServiceImpl.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/ModbusConfigServiceImpl.java index 11847954..d39cda66 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/ModbusConfigServiceImpl.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/ModbusConfigServiceImpl.java @@ -125,6 +125,7 @@ public class ModbusConfigServiceImpl implements IModbusConfigService { this.updateModbusConfig(config); } } + // 将寄存器配置保存到redis缓存 modbusConfigCache.setModbusConfigCacheByProductId(productId); } diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/ThingsModelServiceImpl.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/ThingsModelServiceImpl.java index a2fb98ab..c037fb95 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/ThingsModelServiceImpl.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/ThingsModelServiceImpl.java @@ -12,7 +12,6 @@ import com.fastbee.common.exception.ServiceException; import com.fastbee.common.utils.DateUtils; import com.fastbee.common.utils.SecurityUtils; import com.fastbee.common.utils.StringUtils; -import com.fastbee.iot.cache.ICalculatedThingsModelCache; import com.fastbee.iot.cache.ITSLCache; import com.fastbee.iot.domain.*; import com.fastbee.iot.mapper.*; @@ -68,8 +67,6 @@ public class ThingsModelServiceImpl implements IThingsModelService { private ITSLValueCache thingModelCache; @Resource private ITSLCache itslCache; - @Resource - private ICalculatedThingsModelCache calculatedThingsModelCache; private static List getSceneModelData(SceneModelDevice sceneModelDevice, List thingsModelDTOList) { List modelDataList = new ArrayList<>(); @@ -142,11 +139,16 @@ public class ThingsModelServiceImpl implements IThingsModelService { */ @Override public int insertThingsModel(ThingsModel thingsModel) { + // 去除计算公式中的空格 + if (StringUtils.isNotEmpty(thingsModel.getFormula())) { + thingsModel.setFormula(thingsModel.getFormula().replaceAll("\\s+", "")); + } ThingsModel input = new ThingsModel(); input.setProductId(thingsModel.getProductId()); + input.setIsCalculated(0); // 只需要查产品的物模型即可 input.setLanguage(SecurityUtils.getLanguage()); List list = thingsModelMapper.selectThingsModelList(input); - Boolean isRepeat = list.stream().anyMatch(x -> x.getIdentifier().equals(thingsModel.getIdentifier())); + boolean isRepeat = list.stream().anyMatch(x -> x.getIdentifier().equals(thingsModel.getIdentifier())); if (!isRepeat) { SysUser user = getLoginUser().getUser(); if (null != user.getDeptId()) { @@ -157,21 +159,19 @@ public class ThingsModelServiceImpl implements IThingsModelService { thingsModel.setTenantName(user.getUserName()); } thingsModel.setCreateTime(DateUtils.getNowDate()); - // 自动判断是否为纯计算物模型:如果公式包含{},则设置为1(纯计算) - if (thingsModel.getIsCalculated() == null) { - thingsModel.setIsCalculated(determineIsCalculated(thingsModel.getFormula())); - } + // 插入物模型数据库 int result = thingsModelMapper.insertThingsModel(thingsModel); - // 更新redis缓存 - itslCache.setCacheThingsModelByProductId(thingsModel.getProductId()); - // 刷新纯计算物模型缓存 - if (result > 0) { - calculatedThingsModelCache.refreshCalculatedCache(thingsModel.getProductId()); + // 更新redis缓存:IsCalculated=1为纯计算物模型 + if (thingsModel.getIsCalculated() != null && thingsModel.getIsCalculated() == 1) { + itslCache.refreshDeviceCalculatedModelCache(thingsModel.getSerialNumber()); + } else { + itslCache.setCacheThingsModelByProductId(thingsModel.getProductId()); } + if (result > 0) { // 更新场景管理变量 List sceneModelDeviceList = sceneModelDeviceMapper.listDeviceByProductId(thingsModel.getProductId()); - if (org.apache.commons.collections4.CollectionUtils.isEmpty(sceneModelDeviceList)) { + if (CollectionUtils.isEmpty(sceneModelDeviceList)) { return result; } List thingsModelDTOList = this.changeObjectOrArray(thingsModel); @@ -219,15 +219,15 @@ public class ThingsModelServiceImpl implements IThingsModelService { thingsModel.setIsChart(template.getIsChart()); thingsModel.setIsHistory(template.getIsHistory()); thingsModel.setModelOrder(template.getModelOrder()); - thingsModel.setIsCalculated(determineIsCalculated(thingsModel.getFormula())); - Boolean isRepeat = dbList.stream().anyMatch(x -> x.getIdentifier().equals(thingsModel.getIdentifier())); + thingsModel.setIsCalculated(0); + boolean isRepeat = dbList.stream().anyMatch(x -> x.getIdentifier().equals(thingsModel.getIdentifier())); if (isRepeat) { repeatCount = repeatCount + 1; } else { list.add(thingsModel); } } - if (list.size() > 0) { + if (!list.isEmpty()) { int result = thingsModelMapper.insertBatchThingsModel(list); if (result > 0) { // 更新场景管理变量 @@ -245,8 +245,6 @@ public class ThingsModelServiceImpl implements IThingsModelService { } //更新redis缓存 itslCache.setCacheThingsModelByProductId(input.getProductId()); - // 刷新纯计算物模型缓存 - calculatedThingsModelCache.refreshCalculatedCache(input.getProductId()); } return repeatCount; } @@ -271,16 +269,12 @@ public class ThingsModelServiceImpl implements IThingsModelService { Boolean isRepeat = list.stream().anyMatch(x -> x.getIdentifier().equals(thingsModel.getIdentifier()) && x.getModelId().longValue() != thingsModel.getModelId()); if (!isRepeat) { thingsModel.setUpdateTime(DateUtils.getNowDate()); - // 自动判断是否为纯计算物模型:如果公式包含{},则设置为1(纯计算) - if (thingsModel.getIsCalculated() == null) { - thingsModel.setIsCalculated(determineIsCalculated(thingsModel.getFormula())); - } int result = thingsModelMapper.updateThingsModel(thingsModel); // 更新redis缓存 - itslCache.setCacheThingsModelByProductId(thingsModel.getProductId()); - // 刷新纯计算物模型缓存 - if (result > 0) { - calculatedThingsModelCache.refreshCalculatedCache(thingsModel.getProductId()); + if (thingsModel.getIsCalculated() != null && thingsModel.getIsCalculated() == 1) { + itslCache.refreshDeviceCalculatedModelCache(thingsModel.getSerialNumber()); + } else { + itslCache.setCacheThingsModelByProductId(thingsModel.getProductId()); } if (result > 0) { List sceneModelDataList = sceneModelDataMapper.selectSceneDeviceThingsModelList(thingsModel.getModelId()); @@ -320,12 +314,9 @@ public class ThingsModelServiceImpl implements IThingsModelService { if (result > 0) { sceneModelDataMapper.deleteThingsModelByDatasourceId(modelIds); } - // 更新redis缓存 + // 更新redis缓存 产品和设备物模型都干掉 itslCache.setCacheThingsModelByProductId(thingsModel.getProductId()); - // 刷新纯计算物模型缓存 - if (result > 0 && thingsModel != null && thingsModel.getProductId() != null) { - calculatedThingsModelCache.refreshCalculatedCache(thingsModel.getProductId()); - } + itslCache.refreshDeviceCalculatedModelCache(thingsModel.getSerialNumber()); return result; } @@ -341,12 +332,11 @@ public class ThingsModelServiceImpl implements IThingsModelService { ThingsModel thingsModel = thingsModelMapper.selectThingsModelByModelId(modelId, SecurityUtils.getLanguage()); int result = thingsModelMapper.deleteThingsModelByModelId(modelId); // 更新redis缓存 - if (thingsModel != null && thingsModel.getProductId() != null) { - itslCache.setCacheThingsModelByProductId(thingsModel.getProductId()); - // 刷新纯计算物模型缓存 - if (result > 0) { - calculatedThingsModelCache.refreshCalculatedCache(thingsModel.getProductId()); + if (thingsModel != null) { + if (thingsModel.getProductId() != null) { + itslCache.setCacheThingsModelByProductId(thingsModel.getProductId()); } + itslCache.refreshDeviceCalculatedModelCache(thingsModel.getSerialNumber()); } return result; } @@ -354,8 +344,8 @@ public class ThingsModelServiceImpl implements IThingsModelService { /** * 获取单个物模型获取 * - * @param productId - * @param identify + * @param productId 产品ID + * @param identify 物模型标识符 * @return */ @Override @@ -695,6 +685,7 @@ public class ThingsModelServiceImpl implements IThingsModelService { if (null == productId) { return new ArrayList<>(); } + // 1、获取产品物模型 Map map = itslCache.getCacheThMapByProductId(productId); List thingsModelDTOList = new ArrayList<>(); for (Map.Entry entry : map.entrySet()) { @@ -702,6 +693,15 @@ public class ThingsModelServiceImpl implements IThingsModelService { thingsModelDTOList.addAll(this.changeObjectOrArray(thingsModel)); } + // 2. 获取设备级计算物模型并合并 + if (StringUtils.isNotEmpty(serialNumber)) { + Map deviceCalculatedMap = itslCache.getDeviceCalculatedModelMap(serialNumber); + for (Map.Entry entry : deviceCalculatedMap.entrySet()) { + ThingsModel thingsModel = this.propertyDtoChangeThingsModel(entry.getValue()); + thingsModelDTOList.addAll(this.changeObjectOrArray(thingsModel)); + } + } + thingsModelDTOList.sort(Comparator.comparing(ThingsModelDTO::getModelOrder)); if (StringUtils.isEmpty(serialNumber)) { return thingsModelDTOList; diff --git a/fastbee-service/fastbee-iot-service/src/main/resources/mapper/iot/DeviceMapper.xml b/fastbee-service/fastbee-iot-service/src/main/resources/mapper/iot/DeviceMapper.xml index be3cfb54..53bb3997 100644 --- a/fastbee-service/fastbee-iot-service/src/main/resources/mapper/iot/DeviceMapper.xml +++ b/fastbee-service/fastbee-iot-service/src/main/resources/mapper/iot/DeviceMapper.xml @@ -163,15 +163,71 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - select device_id, device_name, product_id, product_name, tenant_id, tenant_name, serial_number,gw_dev_code, firmware_version, status, rssi,is_shadow ,is_simulate,location_way,things_model_value,network_address, network_ip, longitude, latitude, active_time, create_time, update_time, img_url,summary,remark,slave_id from iot_device + select device_id, + device_name, + product_id, + product_name, + tenant_id, + tenant_name, + serial_number, + gw_dev_code, + firmware_version, + status, + rssi, + is_shadow, + is_simulate, + location_way, + things_model_value, + network_address, + network_ip, + longitude, + latitude, + active_time, + create_time, + update_time, + img_url, + summary, + remark, + slave_id + from iot_device - select device_id, device_name, product_id, product_name, tenant_id, tenant_name, serial_number, firmware_version, status,rssi,is_shadow ,is_simulate,location_way,things_model_value, active_time,img_url,slave_id from iot_device + select device_id, + device_name, + product_id, + product_name, + tenant_id, + tenant_name, + serial_number, + firmware_version, + status, + rssi, + is_shadow, + is_simulate, + location_way, + things_model_value, + active_time, + img_url, + slave_id + from iot_device - select device_id, device_name,product_id, serial_number,tenant_id, tenant_name, status,is_shadow,is_simulate, rssi ,location_way,things_model_value, active_time from iot_device + select device_id, + device_name, + product_id, + serial_number, + tenant_id, + tenant_name, + status, + is_shadow, + is_simulate, + rssi, + location_way, + things_model_value, + active_time + from iot_device select m.model_id, case - when #{language} = 'zh-CN' then m.model_name - when #{language} = 'en-US' then t.en_us - else m.model_name - end as model_name, - m.model_name as model_name_zh_cn, t.en_us as model_name_en_us, - m.product_id, m.product_name, m.tenant_id, m.tenant_name, m.identifier, m.type, m.datatype, m.formula, - m.is_calculated, m.specs, m.is_chart, m.is_share_perm, m.is_history, m.is_monitor, m.is_app, m.del_flag, m.create_by, - m.create_time, m.update_by, m.update_time, m.remark, m.is_readonly, m.model_order - from iot_things_model m - left join iot_things_model_translate t on m.model_id = t.id + when #{language} + = 'zh-CN' THEN m.model_name WHEN #{language} + = 'en-US' THEN t.en_us ELSE m.model_name END AS model_name, + m.model_name AS model_name_zh_cn, + t.en_us AS model_name_en_us, + m.product_id, + m.product_name, + m.device_id, + m.serial_number, + m.tenant_id, + m.tenant_name, + m.identifier, + m.type, + m.datatype, + m.formula, + m.is_calculated, + m.specs, + m.is_chart, + m.is_share_perm, + m.is_history, + m.is_monitor, + m.is_app, + m.del_flag, + m.create_by, + m.create_time, + m.update_by, + m.update_time, + m.remark, + m.is_readonly, + m.model_order + FROM + iot_things_model m + LEFT JOIN iot_things_model_translate t ON m.model_id = t.id - and m.product_id = #{productId} + AND m.product_id = #{productId} + + + AND m.serial_number = #{serialNumber} + + + AND m.device_id = #{deviceId} - and type = #{type} + AND type = #{type} - and is_chart = #{isChart} + AND is_chart = #{isChart} - and is_history = #{isHistory} + AND is_history = #{isHistory} - and is_monitor = #{isMonitor} + AND is_monitor = #{isMonitor} - and is_readonly = #{isReadonly} + AND is_readonly = #{isReadonly} + + + AND is_calculated = #{isCalculated} - model_id in + model_id IN #{item} - order by model_order desc,create_time desc + ORDER BY + model_order DESC, + create_time DESC select m.model_id, - case - when #{language} = 'zh-CN' then m.model_name - when #{language} = 'en-US' then t.en_us - else m.model_name - end as model_name, - m.product_id, m.product_name, m.tenant_id, m.tenant_name, m.identifier, m.type, m.datatype, m.formula, - m.specs, m.is_chart, m.is_share_perm, m.is_history, m.is_monitor, m.is_app, m.del_flag, m.create_by, - m.create_time, m.update_by, m.update_time, m.remark, m.is_readonly, m.model_order - from iot_things_model m - left join iot_things_model_translate t on m.model_id = t.id - where model_id = #{modelId} + case + when #{language} + = 'zh-CN' THEN m.model_name WHEN #{language} + = 'en-US' THEN t.en_us ELSE m.model_name END AS model_name, + m.product_id, + m.product_name, + m.serial_number, + m.tenant_id, + m.tenant_name, + m.identifier, + m.type, + m.datatype, + m.formula, + m.specs, + m.is_chart, + m.is_share_perm, + m.is_history, + m.is_monitor, + m.is_app, + m.del_flag, + m.create_by, + m.create_time, + m.update_by, + m.update_time, + m.remark, + m.is_readonly, + m.model_order + FROM + iot_things_model m + LEFT JOIN iot_things_model_translate t ON m.model_id = t.id + WHERE + model_id = #{modelId} - insert into iot_things_model + INSERT INTO + iot_things_model model_name, @@ -200,6 +308,12 @@ product_name, + + device_id, + + + serial_number, + tenant_id, @@ -274,6 +388,12 @@ #{productName}, + + #{deviceId}, + + + #{serialNumber}, + #{tenantId}, @@ -342,41 +462,55 @@ - INSERT INTO iot_things_model ( - model_name, - product_id, - product_name, - tenant_id, - tenant_name, - identifier, - type, - datatype, - specs, - is_chart, - is_share_perm, - is_history, - is_monitor, - is_app, - is_readonly, - create_by, - create_time, - formula, - is_calculated - ) + INSERT INTO + iot_things_model ( + model_name, + product_id, + product_name, + tenant_id, + tenant_name, + identifier, + type, + datatype, + specs, + is_chart, + is_share_perm, + is_history, + is_monitor, + is_app, + is_readonly, + create_by, + create_time, + formula, + is_calculated + ) VALUES - - #{model.modelName},#{model.productId},#{model.productName},#{model.tenantId}, - #{model.tenantName},#{model.identifier},#{model.type},#{model.datatype}, - #{model.specs},#{model.isChart},#{model.isSharePerm},#{model.isHistory}, - #{model.isMonitor},#{model.isApp},#{model.isReadonly},#{model.createBy},#{model.createTime}, - #{model.formula},#{model.isCalculated} + #{model.modelName}, + #{model.productId}, + #{model.productName}, + #{model.tenantId}, + #{model.tenantName}, + #{model.identifier}, + #{model.type}, + #{model.datatype}, + #{model.specs}, + #{model.isChart}, + #{model.isSharePerm}, + #{model.isHistory}, + #{model.isMonitor}, + #{model.isApp}, + #{model.isReadonly}, + #{model.createBy}, + #{model.createTime}, + #{model.formula}, + #{model.isCalculated} - update iot_things_model + UPDATE iot_things_model model_name = #{modelName}, @@ -387,6 +521,12 @@ product_name = #{productName}, + + device_id = #{deviceId}, + + + serial_number = #{serialNumber}, + tenant_id = #{tenantId}, @@ -451,17 +591,20 @@ model_order = #{modelOrder}, - where model_id = #{modelId} + WHERE + model_id = #{modelId} - delete - from iot_things_model - where model_id = #{modelId} + DELETE FROM iot_things_model + WHERE + model_id = #{modelId} - delete from iot_things_model where model_id in + DELETE FROM iot_things_model + WHERE + model_id IN #{modelId} @@ -475,16 +618,17 @@ m.is_history as isHistory, m.specs as dataType, case - when #{language} = 'zh-CN' then m.model_name - when #{language} = 'en-US' then t.en_us - else m.model_name - end as name, - m.type as type, - m.formula as formula, - from iot_things_model m - left join iot_things_model_translate t on m.model_id = t.id - where m.product_id = #{productId,jdbcType=BIGINT} - and m.identifier in + when #{language} + = 'zh-CN' THEN m.model_name WHEN #{language} + = 'en-US' THEN t.en_us ELSE m.model_name END AS name, + m.type AS type, + m.formula AS formula, + FROM + iot_things_model m + LEFT JOIN iot_things_model_translate t ON m.model_id = t.id + WHERE + m.product_id = #{productId,jdbcType=BIGINT} + AND m.identifier IN #{item} @@ -492,43 +636,50 @@ - delete from iot_things_model where product_id = #{productId} + DELETE FROM iot_things_model + WHERE + product_id = #{productId} select m.model_id, m.identifier, - case - when #{language} = 'zh-CN' then m.model_name - when #{language} = 'en-US' then t.en_us - else m.model_name - end as model_name, - m.datatype, - case - when (select count(1) from iot_modbus_config c where c.product_id = #{productId} and c.identifier = m.identifier) > 0 then 0 - else 1 - end as is_select + case + when #{language} + = 'zh-CN' THEN m.model_name WHEN #{language} + = 'en-US' then t.en_us + else m.model_name + end as model_name, + m.datatype, + case + when (select count(1) from iot_modbus_config c where c.product_id = #{productId} + and c.identifier = m.identifier) > 0 then 0 + else 1 + end as is_select from iot_things_model m left join iot_things_model_translate t on m.model_id = t.id where m.product_id = #{productId} + AND m.del_flag = 0 + AND m.is_calculated = 0 diff --git a/sql/add_field_extension_file.sql b/sql/add_field_extension_file.sql index 69e6cacb..9f0a795a 100644 --- a/sql/add_field_extension_file.sql +++ b/sql/add_field_extension_file.sql @@ -32,4 +32,15 @@ SET `is_calculated` = 1 WHERE `formula` IS NOT NULL AND `formula` != '' AND `formula` LIKE '%{%}%' - AND `del_flag` = '0'; \ No newline at end of file + AND `del_flag` = '0'; + +-- 1. 添加 device_id 字段(默认为0,表示产品级物模型) +ALTER TABLE `iot_things_model` + ADD COLUMN `device_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '设备ID,0表示产品级物模型,>0表示设备级计算物模型' AFTER `product_name`; + +-- 2. 添加 serial_number 字段 +ALTER TABLE `iot_things_model` + ADD COLUMN `serial_number` varchar(64) NULL DEFAULT NULL COMMENT '设备编号' AFTER `device_id`; + +-- 3. 添加索引(设备编号索引) +ALTER TABLE `iot_things_model` ADD INDEX `idx_calculated_serial` (`is_calculated`, `serial_number`); diff --git a/vue/src/lang/en-US/device.json b/vue/src/lang/en-US/device.json index 076cef08..d7fd9d71 100644 --- a/vue/src/lang/en-US/device.json +++ b/vue/src/lang/en-US/device.json @@ -109,6 +109,7 @@ "device.device-edit.148398-80": "Alert user", "device.device-edit.148398-81": "equipment alarm ", "device.device-edit.148398-82": "Voice intercom", + "device.device-edit.148398-83": "Calculation Formula", "device.device-functionlog.399522-0": "Please Select A Device Slave:", "device.device-functionlog.399522-1": "Please Select A Device Slave", "device.device-functionlog.399522-2": "Slave Address:$", diff --git a/vue/src/lang/en-US/product.json b/vue/src/lang/en-US/product.json index 74273d47..372f4dea 100644 --- a/vue/src/lang/en-US/product.json +++ b/vue/src/lang/en-US/product.json @@ -298,7 +298,6 @@ "product.product-things-model.142341-52": "Please enter the step size, for example: 1", "product.product-things-model.142341-53": "The upstream data of the device is displayed after being calculated using a formula.", "product.product-things-model.142341-54": "%s in the formula is a placeholder representing the current thing model value.", - "product.product-things-model.142341-54-1": "Use {identifier} to reference values from other thing models, supporting multiple thing models in calculations.", "product.product-things-model.142341-54-2": "Supported operators: +, -, *, /, % (modulo), ^ (power), parentheses ().", "product.product-things-model.142341-55": "For example:", "product.product-things-model.142341-56": "Add: %s+10", @@ -307,10 +306,6 @@ "product.product-things-model.142341-59": "Divide: %s/10", "product.product-things-model.142341-60": "Divide (retain decimals): %s%10.00", "product.product-things-model.142341-61": "Retain decimals", - "product.product-things-model.142341-61-1": "Examples of referencing other thing models:", - "product.product-things-model.142341-61-2": "Pressure = K * frequency^2 - constant: 1.5*{frequency}^2-100", - "product.product-things-model.142341-61-3": "Speed = distance / time: {distance}/{time}", - "product.product-things-model.142341-61-4": "Mixed calculation: %s*{factor}+{offset}", "product.product-things-model.142341-62": "Control Formula", "product.product-things-model.142341-63": "Boolean value", "product.product-things-model.142341-64": "For example: Close", @@ -551,5 +546,9 @@ "product.product-modbus-task.894593-67": "Tips", "product.product-modbus-task.894593-68": "determine", "product.product-modbus-task.894593-69": "cancel", - "product.product-modbus-task.894593-70": "Cancelled" + "product.product-modbus-task.894593-70": "Cancelled", + "product.product-things-model.142341-200": "Click symbols to build the formula", + "product.product-things-model.142341-201": "Reference product model identifiers", + "product.product-things-model.142341-202": "No available identifiers", + "product.product-things-model.142341-203": "Add Calculated Model" } diff --git a/vue/src/lang/zh-CN/device.json b/vue/src/lang/zh-CN/device.json index 25ab4513..d801e79e 100644 --- a/vue/src/lang/zh-CN/device.json +++ b/vue/src/lang/zh-CN/device.json @@ -109,6 +109,7 @@ "device.device-edit.148398-80": "告警用户", "device.device-edit.148398-81": "设备告警", "device.device-edit.148398-82": "语音对讲", + "device.device-edit.148398-83": "计算公式", "device.device-functionlog.399522-0": "请选择设备从机:", "device.device-functionlog.399522-1": "请选择设备从机", "device.device-functionlog.399522-2": "从机地址:$", diff --git a/vue/src/lang/zh-CN/product.json b/vue/src/lang/zh-CN/product.json index 8152dd70..8789fd1d 100644 --- a/vue/src/lang/zh-CN/product.json +++ b/vue/src/lang/zh-CN/product.json @@ -296,9 +296,8 @@ "product.product-things-model.142341-50": "请输入单位,例如:℃", "product.product-things-model.142341-51": "步长", "product.product-things-model.142341-52": "请输入步长,例如:1", - "product.product-things-model.142341-53": "设备上行数据经计算公式计算后显示 。", + "product.product-things-model.142341-53": "设备上行数据经计算公式计算后显示。", "product.product-things-model.142341-54": "公式中的%s为占位符,表示当前物模型的值。", - "product.product-things-model.142341-54-1": "使用{标识符}可以引用其他物模型的值,支持多个物模型参与计算。", "product.product-things-model.142341-54-2": "支持运算符:+、-、*、/、%、^(幂运算)、括号()。", "product.product-things-model.142341-55": "如:", "product.product-things-model.142341-56": "加:%s+10", @@ -307,10 +306,6 @@ "product.product-things-model.142341-59": "除:%s/10", "product.product-things-model.142341-60": "除(保留小数):%s%10.00", "product.product-things-model.142341-61": "保留小数", - "product.product-things-model.142341-61-1": "引用其他物模型示例:", - "product.product-things-model.142341-61-2": "压力=K*频率平方-常数:1.5*{frequency}^2-100", - "product.product-things-model.142341-61-3": "速度=路程/时间:{distance}/{time}", - "product.product-things-model.142341-61-4": "混合计算:%s*{factor}+{offset}", "product.product-things-model.142341-62": "控制公式", "product.product-things-model.142341-63": "布尔值", "product.product-things-model.142341-64": "例如:关闭", @@ -551,5 +546,9 @@ "product.product-modbus-task.894593-67": "提示", "product.product-modbus-task.894593-68": "确定", "product.product-modbus-task.894593-69": "取消", - "product.product-modbus-task.894593-70": "已取消" -} + "product.product-modbus-task.894593-70": "已取消", + "product.product-things-model.142341-200": "点击符号快速拼接", + "product.product-things-model.142341-201": "引用产品物模型标识", + "product.product-things-model.142341-202": "暂无可用标识", + "product.product-things-model.142341-203": "新增计算模型" +} \ No newline at end of file diff --git a/vue/src/views/iot/device/device-edit.vue b/vue/src/views/iot/device/device-edit.vue index b0d42052..7b86eab6 100644 --- a/vue/src/views/iot/device/device-edit.vue +++ b/vue/src/views/iot/device/device-edit.vue @@ -135,6 +135,13 @@ + + + + * {{$t('device.device-edit.148398-83')}} + + + +
+ + + + 新增 + + + + + 刷新 + + + + + 设备级物模型,基于产品物模型进行公式计算 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + ~ + + + + + + + + + + + +
+ +
+ + + + + + 字节(Byte),默认1024 + + +
+ + + +
+ +
+ +
+ + + − + × + ÷ + ^ + sqrt + % + ( + ) +
+
+ +
+ +
+ + {{ model.modelName }} + + 暂无可用物模型 +
+
+ +
+ + 清空 +
+
+
+
+ + +
+
+ + + + + + + + + diff --git a/vue/src/views/iot/product/product-app.vue b/vue/src/views/iot/product/product-app.vue index 135c39eb..e25478a8 100644 --- a/vue/src/views/iot/product/product-app.vue +++ b/vue/src/views/iot/product/product-app.vue @@ -74,6 +74,8 @@ export default { productId: 0, // 1-属性,2-功能,3-事件,4-属性和功能 type: 4, + // 产品管理页面只显示设备上报的物模型,不显示纯计算物模型 + isCalculated: 0, }, form: {}, // 产品 diff --git a/vue/src/views/iot/product/product-edit.vue b/vue/src/views/iot/product/product-edit.vue index d0324936..5e8307bb 100644 --- a/vue/src/views/iot/product/product-edit.vue +++ b/vue/src/views/iot/product/product-edit.vue @@ -195,7 +195,7 @@ * {{ $t('product.product-edit.473153-38') }} - +
diff --git a/vue/src/views/iot/product/product-modbus.vue b/vue/src/views/iot/product/product-modbus.vue index 841ecbc1..c297f742 100644 --- a/vue/src/views/iot/product/product-modbus.vue +++ b/vue/src/views/iot/product/product-modbus.vue @@ -401,6 +401,7 @@ export default { pageNum: 1, pageSize: 1000, productId: 0, + isCalculated: 0, }, thingsTotal: 0, // 表单参数 diff --git a/vue/src/views/iot/product/product-things-model.vue b/vue/src/views/iot/product/product-things-model.vue index f29b2eab..4bd8e79f 100644 --- a/vue/src/views/iot/product/product-things-model.vue +++ b/vue/src/views/iot/product/product-things-model.vue @@ -196,8 +196,6 @@
{{ $t('product.product-things-model.142341-54') }}
- {{ $t('product.product-things-model.142341-54-1') }} -
{{ $t('product.product-things-model.142341-54-2') }}

@@ -211,16 +209,7 @@
{{ $t('product.product-things-model.142341-59') }}
- {{ $t('product.product-things-model.142341-60') }}({{ $t('product.product-things-model.142341-61') }}):%s%10.00 -
-
- {{ $t('product.product-things-model.142341-61-1') }} -
- {{ $t('product.product-things-model.142341-61-2') }} -
- {{ $t('product.product-things-model.142341-61-3') }} -
- {{ $t('product.product-things-model.142341-61-4') }} + {{ $t('product.product-things-model.142341-60') }}({{ $t('product.product-things-model.142341-61') }})
@@ -417,6 +406,10 @@ export default { type: Object, default: null, }, + isCalculated: { + type: Number, + default: 0, + }, }, watch: { // 获取到父组件传递的productId后,刷新列表 @@ -425,6 +418,10 @@ export default { if (this.productInfo && this.productInfo.productId != 0) { this.queryParams.productId = this.productInfo.productId; this.productId = this.productInfo.productId; + // 设置isCalculated查询条件(产品管理页面只显示设备上报的物模型,不显示纯计算物模型) + if (this.isCalculated !== null) { + this.queryParams.isCalculated = this.isCalculated; + } this.getList(); } },