20260117:纯计算物模型下沉到设备端
This commit is contained in:
parent
faa11dc37a
commit
d12016e04a
@ -129,7 +129,7 @@ emqx:
|
|||||||
ApiSecret: emqx.api.123
|
ApiSecret: emqx.api.123
|
||||||
# sip 配置
|
# sip 配置
|
||||||
sip:
|
sip:
|
||||||
enabled: true # 是否启用视频监控SIP,true为启用
|
enabled: false # 是否启用视频监控SIP,true为启用
|
||||||
## 本地调试时,绑定网卡局域网IP,设备在同一局域网,设备接入IP填写绑定IP
|
## 本地调试时,绑定网卡局域网IP,设备在同一局域网,设备接入IP填写绑定IP
|
||||||
## 部署服务端时,默认绑定容器IP,设备接入IP填写服务器公网IP
|
## 部署服务端时,默认绑定容器IP,设备接入IP填写服务器公网IP
|
||||||
ip: 192.168.110.160 # 本服务启动的 IP
|
ip: 192.168.110.160 # 本服务启动的 IP
|
||||||
|
|||||||
@ -239,10 +239,18 @@ public interface FastBeeConstant {
|
|||||||
String DEVICE_PRE_KEY = "TSLV:";
|
String DEVICE_PRE_KEY = "TSLV:";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 物模型缓存
|
* 物模型缓存(产品级)
|
||||||
|
* Key格式:TSL:{productId} hKey: identifier value: thingsModel
|
||||||
*/
|
*/
|
||||||
String TSL_PRE_KEY = "TSL:";
|
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:";
|
String MODBUS_PRE_KEY = "MODBUS:";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -54,13 +54,21 @@ public class RedisKeyBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 物模型缓存key
|
* 物模型缓存key(产品级)
|
||||||
* 物模型命名空间:Key:TSL:{productId} hkey: identity value: thingsModel
|
* 物模型命名空间:Key:TSL:{productId} hkey: identity value: thingsModel
|
||||||
*/
|
*/
|
||||||
public static String buildTSLCacheKey(Long productId) {
|
public static String buildTSLCacheKey(Long productId) {
|
||||||
return FastBeeConstant.REDIS.TSL_PRE_KEY + 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) {
|
public static String buildModbusKey(Long productId) {
|
||||||
return FastBeeConstant.REDIS.MODBUS_PRE_KEY + productId;
|
return FastBeeConstant.REDIS.MODBUS_PRE_KEY + productId;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,6 +39,11 @@ public class ThingsModelSimpleItem {
|
|||||||
**/
|
**/
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否纯计算型物模型
|
||||||
|
*/
|
||||||
|
private boolean isCalculated;
|
||||||
|
|
||||||
|
|
||||||
public ThingsModelSimpleItem(String id, String value, String remark) {
|
public ThingsModelSimpleItem(String id, String value, String remark) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
@ -88,4 +93,12 @@ public class ThingsModelSimpleItem {
|
|||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isCalculated() {
|
||||||
|
return isCalculated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCalculated(boolean calculated) {
|
||||||
|
isCalculated = calculated;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,11 +19,9 @@ import com.fastbee.common.utils.StringUtils;
|
|||||||
import com.fastbee.common.utils.gateway.CRC16Utils;
|
import com.fastbee.common.utils.gateway.CRC16Utils;
|
||||||
import com.fastbee.common.utils.modbus.BitUtils;
|
import com.fastbee.common.utils.modbus.BitUtils;
|
||||||
import com.fastbee.helper.ModbusProtocolHelper;
|
import com.fastbee.helper.ModbusProtocolHelper;
|
||||||
import com.fastbee.iot.cache.ICalculatedThingsModelCache;
|
|
||||||
import com.fastbee.iot.cache.IModbusConfigCache;
|
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.domain.ModbusConfig;
|
||||||
import com.fastbee.iot.mapper.DeviceMapper;
|
|
||||||
import com.fastbee.iot.mapper.ModbusConfigMapper;
|
import com.fastbee.iot.mapper.ModbusConfigMapper;
|
||||||
import com.fastbee.iot.model.ThingsModels.ThingsModelValueItem;
|
import com.fastbee.iot.model.ThingsModels.ThingsModelValueItem;
|
||||||
import com.fastbee.iot.service.ISubGatewayService;
|
import com.fastbee.iot.service.ISubGatewayService;
|
||||||
@ -40,7 +38,6 @@ import javax.annotation.Resource;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -63,14 +60,12 @@ public class ModbusProtocol implements IProtocol {
|
|||||||
private IModbusConfigCache modbusConfigCache;
|
private IModbusConfigCache modbusConfigCache;
|
||||||
@Resource
|
@Resource
|
||||||
private ISubGatewayService subGatewayService;
|
private ISubGatewayService subGatewayService;
|
||||||
@Resource
|
|
||||||
private DeviceMapper deviceMapper;
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ModbusConfigMapper modbusConfigMapper;
|
private ModbusConfigMapper modbusConfigMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ICalculatedThingsModelCache calculatedThingsModelCache;
|
private ITSLCache itslCache;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DeviceReport decode(DeviceData deviceData, String clientId) {
|
public DeviceReport decode(DeviceData deviceData, String clientId) {
|
||||||
@ -103,16 +98,16 @@ public class ModbusProtocol implements IProtocol {
|
|||||||
case Read01:
|
case Read01:
|
||||||
case Read02:
|
case Read02:
|
||||||
//起始地址
|
//起始地址
|
||||||
String address0102 = getCacheModbusAddress(deviceData.getSerialNumber(), slaveId, code);
|
String address0102 = getCacheModbusAddress(productId, slaveId, code);
|
||||||
//读线圈或读离散型寄存器处理
|
//读线圈或读离散型寄存器处理
|
||||||
handleRead0102(productId, message, address0102, values);
|
handleRead0102(productId, message, address0102, values);
|
||||||
break;
|
break;
|
||||||
case Read03:
|
case Read03:
|
||||||
case Read04:
|
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;
|
break;
|
||||||
case Write06:
|
case Write06:
|
||||||
case Write05:
|
case Write05:
|
||||||
@ -191,13 +186,14 @@ public class ModbusProtocol implements IProtocol {
|
|||||||
/**
|
/**
|
||||||
* 处理读保持寄存器/输入寄存器
|
* 处理读保持寄存器/输入寄存器
|
||||||
*
|
*
|
||||||
|
* @param serialNumber 设备序列号
|
||||||
* @param productId 产品id
|
* @param productId 产品id
|
||||||
* @param message 数据
|
* @param message 数据
|
||||||
* @param address 起始地址
|
* @param address 起始地址
|
||||||
* @param simpleItemList 返回的物模型值
|
* @param simpleItemList 返回的物模型值
|
||||||
* @param sourceStr 原始报文字符串
|
* @param sourceStr 原始报文字符串
|
||||||
*/
|
*/
|
||||||
private void handleRead0304(Long productId, ModbusRtu message, String address, List<ThingsModelSimpleItem> simpleItemList, String sourceStr) {
|
private void handleRead0304(String serialNumber, Long productId, ModbusRtu message, String address, List<ThingsModelSimpleItem> simpleItemList, String sourceStr) {
|
||||||
short[] data = message.getData();
|
short[] data = message.getData();
|
||||||
int length = data.length;
|
int length = data.length;
|
||||||
if (length == 1) {
|
if (length == 1) {
|
||||||
@ -318,50 +314,35 @@ public class ModbusProtocol implements IProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 处理纯计算物模型:查询产品下所有纯计算物模型,构造 ThingsModelSimpleItem,值为 "0"
|
// 处理纯计算物模型:查询产品下所有纯计算物模型,构造 ThingsModelSimpleItem,值为 "0"
|
||||||
handleCalculatedThingsModels(productId, simpleItemList, isReadOnly);
|
handleCalculatedThingsModels(serialNumber, simpleItemList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理纯计算物模型
|
* 从redis获取 纯计算物模型(设备级别物模型)
|
||||||
* 从缓存获取纯计算物模型列表,构造 ThingsModelSimpleItem,值为 "0"
|
|
||||||
* 后续在计算环节会统一处理所有物模型(包括纯计算物模型)
|
|
||||||
*
|
*
|
||||||
* @param productId 产品ID
|
* @param serialNumber 设备编号
|
||||||
* @param simpleItemList 物模型值列表
|
* @param simpleItemList 物模型值列表
|
||||||
* @param isReadOnly 是否只读
|
|
||||||
*/
|
*/
|
||||||
private void handleCalculatedThingsModels(Long productId, List<ThingsModelSimpleItem> simpleItemList, int isReadOnly) {
|
private void handleCalculatedThingsModels(String serialNumber, List<ThingsModelSimpleItem> simpleItemList) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 从缓存获取纯计算物模型标识符集合(支持产品级别和设备级别)
|
Map<String, ThingsModelValueItem> calculatedModelMap = itslCache.getDeviceCalculatedModelMap(serialNumber);
|
||||||
Set<String> calculatedIdentifiers = calculatedThingsModelCache.getCalculatedIdentifiers(productId, null);
|
|
||||||
|
|
||||||
if (calculatedIdentifiers.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取已上报的物模型标识符集合(避免重复)
|
|
||||||
Set<String> reportedIdentifiers = simpleItemList.stream()
|
|
||||||
.map(ThingsModelSimpleItem::getId)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
|
|
||||||
// 为纯计算物模型构造 ThingsModelSimpleItem
|
|
||||||
for (String identifier : calculatedIdentifiers) {
|
|
||||||
// 跳过已上报的物模型
|
|
||||||
if (reportedIdentifiers.contains(identifier)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构造 ThingsModelSimpleItem,值为 "0"
|
// 构造 ThingsModelSimpleItem,值为 "0"
|
||||||
|
for (Map.Entry<String, ThingsModelValueItem> entry : calculatedModelMap.entrySet()) {
|
||||||
|
String identifier = entry.getKey();
|
||||||
|
|
||||||
ThingsModelSimpleItem simpleItem = new ThingsModelSimpleItem();
|
ThingsModelSimpleItem simpleItem = new ThingsModelSimpleItem();
|
||||||
simpleItem.setId(identifier);
|
simpleItem.setId(identifier);
|
||||||
simpleItem.setValue("0"); // 初始值设为0,后续在计算环节会重新计算
|
simpleItem.setValue("0"); // 初始值设为0,后续在计算环节会重新计算
|
||||||
simpleItem.setTs(DateUtils.getNowDate());
|
simpleItem.setTs(DateUtils.getNowDate());
|
||||||
|
simpleItem.setCalculated(true);
|
||||||
simpleItemList.add(simpleItem);
|
simpleItemList.add(simpleItem);
|
||||||
log.debug("=>添加纯计算物模型到上报列表,产品ID:[{}],标识符:[{}]", productId, identifier);
|
log.debug("=>添加纯计算物模型到上报列表,设备:[{}],标识符:[{}]", serialNumber, identifier);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} 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);
|
// String key = RedisKeyBuilder.buildModbusRuntimeCacheKey(serialNumber);
|
||||||
// Set<String> commandSet = redisCache.zRange(key, 0, -1);
|
// Set<String> commandSet = redisCache.zRange(key, 0, -1);
|
||||||
//
|
//
|
||||||
@ -502,13 +483,14 @@ public class ModbusProtocol implements IProtocol {
|
|||||||
// log.warn("解析指令异常: {}", e.getMessage());
|
// log.warn("解析指令异常: {}", e.getMessage());
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
// todo 拿缓存
|
||||||
|
|
||||||
// 2. 无匹配时查询数据库
|
// 2. 无匹配时查询数据库
|
||||||
try {
|
try {
|
||||||
Device device = deviceMapper.selectDeviceBySerialNumber(serialNumber);
|
// Device device = deviceMapper.selectDeviceBySerialNumber(serialNumber);
|
||||||
if (device == null) return "0";
|
// if (device == null) return "0";
|
||||||
|
|
||||||
List<ModbusConfig> configs = modbusConfigMapper.selectModbusConfigListByProductId(device.getProductId());
|
List<ModbusConfig> configs = modbusConfigMapper.selectModbusConfigListByProductId(productId);
|
||||||
if (CollectionUtils.isEmpty(configs)) return "0";
|
if (CollectionUtils.isEmpty(configs)) return "0";
|
||||||
|
|
||||||
return configs.stream()
|
return configs.stream()
|
||||||
|
|||||||
@ -125,12 +125,13 @@ public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder {
|
|||||||
if (minDelim != null) {
|
if (minDelim != null) {
|
||||||
int minDelimLength = minDelim.value.length;
|
int minDelimLength = minDelim.value.length;
|
||||||
ByteBuf frame = null;
|
ByteBuf frame = null;
|
||||||
|
boolean keepDelimiterForNextFrame = shouldKeepDelimiterForNextFrame(minDelim) && minFrameLength > 0;
|
||||||
|
|
||||||
if (discardingTooLongFrame) {
|
if (discardingTooLongFrame) {
|
||||||
// 如果true,将长度不符合报文丢弃
|
// 如果true,将长度不符合报文丢弃
|
||||||
// 初始化原来的值
|
// 初始化原来的值
|
||||||
discardingTooLongFrame = false;
|
discardingTooLongFrame = false;
|
||||||
buffer.skipBytes(minFrameLength + minDelimLength);
|
buffer.skipBytes(minFrameLength + (keepDelimiterForNextFrame ? 0 : minDelimLength));
|
||||||
|
|
||||||
int tooLongFrameLength = this.tooLongFrameLength;
|
int tooLongFrameLength = this.tooLongFrameLength;
|
||||||
this.tooLongFrameLength = 0;
|
this.tooLongFrameLength = 0;
|
||||||
@ -142,10 +143,16 @@ public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder {
|
|||||||
/*小于最小长度帧处理*/
|
/*小于最小长度帧处理*/
|
||||||
if (minFrameLength > maxFrameLength) {
|
if (minFrameLength > maxFrameLength) {
|
||||||
//放弃读取帧
|
//放弃读取帧
|
||||||
buffer.skipBytes(minFrameLength + minDelimLength);
|
buffer.skipBytes(minFrameLength + (keepDelimiterForNextFrame ? 0 : minDelimLength));
|
||||||
fail(minFrameLength);
|
fail(minFrameLength);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (keepDelimiterForNextFrame) {
|
||||||
|
frame = buffer.readRetainedSlice(minFrameLength);
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
/*是否需要跳过某字节*/
|
/*是否需要跳过某字节*/
|
||||||
if (minDelim.strip) {
|
if (minDelim.strip) {
|
||||||
//忽略长度等于0的报文
|
//忽略长度等于0的报文
|
||||||
@ -183,6 +190,15 @@ public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 7E 分隔符需要保留给下一帧作为帧头使用(仅在存在前置数据时)。
|
||||||
|
*/
|
||||||
|
private boolean shouldKeepDelimiterForNextFrame(Delimiter delimiter) {
|
||||||
|
return !delimiter.strip
|
||||||
|
&& delimiter.value.length == 1
|
||||||
|
&& (delimiter.value[0] & 0xFF) == 0x7E;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检测7E帧格式(注册包/心跳包)
|
* 检测7E帧格式(注册包/心跳包)
|
||||||
* 注册包格式:7E(1) + 80(1) + MAC地址(6) + 7E(1) = 9字节
|
* 注册包格式:7E(1) + 80(1) + MAC地址(6) + 7E(1) = 9字节
|
||||||
|
|||||||
@ -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<String> getCalculatedIdentifiersByProduct(Long productId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取设备下的纯计算物模型标识符集合
|
|
||||||
* 如果设备有自定义物模型,返回设备级别的;否则返回产品级别的
|
|
||||||
* @param productId 产品ID
|
|
||||||
* @param deviceId 设备ID(可选,未来扩展)
|
|
||||||
* @return 纯计算物模型标识符集合
|
|
||||||
*/
|
|
||||||
Set<String> getCalculatedIdentifiers(Long productId, Long deviceId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置产品下的纯计算物模型标识符集合
|
|
||||||
* @param productId 产品ID
|
|
||||||
* @param identifiers 纯计算物模型标识符集合
|
|
||||||
*/
|
|
||||||
void setCalculatedIdentifiersByProduct(Long productId, Set<String> identifiers);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 刷新产品下的纯计算物模型缓存
|
|
||||||
* @param productId 产品ID
|
|
||||||
*/
|
|
||||||
void refreshCalculatedCache(Long productId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清除产品下的纯计算物模型缓存
|
|
||||||
* @param productId 产品ID
|
|
||||||
*/
|
|
||||||
void clearCalculatedCache(Long productId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断是否使用 Redis 缓存
|
|
||||||
* @return true-使用Redis,false-使用本地缓存
|
|
||||||
*/
|
|
||||||
boolean isRedisCacheEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ public interface ITSLCache {
|
|||||||
* \"name\":\"光强\",\"order\":0,\"regId\":\"light\",\"type\":1}]}
|
* \"name\":\"光强\",\"order\":0,\"regId\":\"light\",\"type\":1}]}
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public String setCacheThingsModelByProductId(Long productId);
|
String setCacheThingsModelByProductId(Long productId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取map物模型 --返回 Map<String, PropertyDto>
|
* 获取map物模型 --返回 Map<String, PropertyDto>
|
||||||
@ -90,7 +90,7 @@ public interface ITSLCache {
|
|||||||
* value:PropertyDto
|
* value:PropertyDto
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public Map<String, ThingsModelValueItem> setCacheThMapByProductId(Long productId);
|
Map<String, ThingsModelValueItem> setCacheThMapByProductId(Long productId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取单个物模型缓存
|
* 获取单个物模型缓存
|
||||||
@ -99,6 +99,40 @@ public interface ITSLCache {
|
|||||||
* @param identify 标识符
|
* @param identify 标识符
|
||||||
* @return PropertyDto
|
* @return PropertyDto
|
||||||
*/
|
*/
|
||||||
public ThingsModelValueItem getSingleThingModels(Long productId, String identify);
|
ThingsModelValueItem getSingleThingModels(Long productId, String identify);
|
||||||
|
|
||||||
|
// ==================== 设备级计算物模型缓存方法 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备级计算物模型缓存(Map形式)
|
||||||
|
*
|
||||||
|
* @param serialNumber 设备ID
|
||||||
|
* @return Map<标识符, ThingsModelValueItem>
|
||||||
|
*/
|
||||||
|
Map<String, ThingsModelValueItem> getDeviceCalculatedModelMap(String serialNumber);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新设备级计算物模型缓存
|
||||||
|
*
|
||||||
|
* @param serialNumber 设备ID
|
||||||
|
* @return Map<标识符, ThingsModelValueItem>
|
||||||
|
*/
|
||||||
|
Map<String, ThingsModelValueItem> refreshDeviceCalculatedModelCache(String serialNumber);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除设备级计算物模型缓存
|
||||||
|
*
|
||||||
|
* @param serialNumber 设备ID
|
||||||
|
*/
|
||||||
|
void clearDeviceCalculatedModelCache(String serialNumber);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取单个设备级计算物模型
|
||||||
|
*
|
||||||
|
* @param serialNumber 设备ID
|
||||||
|
* @param identifier 标识符
|
||||||
|
* @return ThingsModelValueItem
|
||||||
|
*/
|
||||||
|
ThingsModelValueItem getSingleDeviceCalculatedModel(String serialNumber, String identifier);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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<String>(纯计算物模型标识符集合)
|
|
||||||
*/
|
|
||||||
private final ConcurrentHashMap<Long, Set<String>> calculatedCache = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设备级别缓存:deviceId -> Set<String>(未来扩展)
|
|
||||||
* 当设备有自定义物模型选择时使用
|
|
||||||
*/
|
|
||||||
private final ConcurrentHashMap<Long, Set<String>> 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<String> getCalculatedIdentifiersByProduct(Long productId) {
|
|
||||||
if (productId == null) {
|
|
||||||
return Collections.emptySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从本地缓存获取
|
|
||||||
Set<String> identifiers = calculatedCache.get(productId);
|
|
||||||
if (identifiers != null) {
|
|
||||||
return identifiers;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 缓存未命中,从数据库加载
|
|
||||||
refreshCalculatedCache(productId);
|
|
||||||
return calculatedCache.getOrDefault(productId, Collections.emptySet());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<String> getCalculatedIdentifiers(Long productId, Long deviceId) {
|
|
||||||
// 如果设备有自定义物模型选择,优先返回设备级别的
|
|
||||||
if (deviceId != null) {
|
|
||||||
Set<String> deviceIdentifiers = deviceCalculatedCache.get(deviceId);
|
|
||||||
if (deviceIdentifiers != null) {
|
|
||||||
return deviceIdentifiers;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 否则返回产品级别的
|
|
||||||
return getCalculatedIdentifiersByProduct(productId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setCalculatedIdentifiersByProduct(Long productId, Set<String> 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<ThingsModel> allThingsModels = thingsModelService.selectThingsModelList(queryModel);
|
|
||||||
|
|
||||||
if (CollectionUtils.isEmpty(allThingsModels)) {
|
|
||||||
calculatedCache.put(productId, Collections.emptySet());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 筛选出纯计算物模型(isCalculated == 1)
|
|
||||||
Set<String> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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<ThingsModel> allThingsModels = thingsModelService.selectThingsModelList(queryModel);
|
|
||||||
|
|
||||||
if (CollectionUtils.isEmpty(allThingsModels)) {
|
|
||||||
setCalculatedIdentifiersByProduct(productId, Collections.emptySet());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 筛选出纯计算物模型(isCalculated == 1)
|
|
||||||
Set<String> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
@ -76,6 +76,10 @@ public class ModbusConfigCacheImpl implements IModbusConfigCache {
|
|||||||
resultMap.put(entry.getKey() + "", valueStr);
|
resultMap.put(entry.getKey() + "", valueStr);
|
||||||
}
|
}
|
||||||
String modbusKey = RedisKeyBuilder.buildModbusKey(productId);
|
String modbusKey = RedisKeyBuilder.buildModbusKey(productId);
|
||||||
|
// 先删除缓存,再插入缓存——完成缓存更新
|
||||||
|
if (redisCache.containsKey(modbusKey)) {
|
||||||
|
redisCache.deleteObject(modbusKey);
|
||||||
|
}
|
||||||
redisCache.hashPutAll(modbusKey, resultMap);
|
redisCache.hashPutAll(modbusKey, resultMap);
|
||||||
return listMap;
|
return listMap;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,10 +23,7 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -159,13 +156,11 @@ public class TSLCacheImpl implements ITSLCache {
|
|||||||
/*组装成原格式数据*/
|
/*组装成原格式数据*/
|
||||||
Map<String, List<ThingsModelValueItem>> result = thingsModelMap.values().stream().map(x -> JSON.parseObject(x, ThingsModelValueItem.class))
|
Map<String, List<ThingsModelValueItem>> result = thingsModelMap.values().stream().map(x -> JSON.parseObject(x, ThingsModelValueItem.class))
|
||||||
.collect(Collectors.groupingBy(dto -> ThingsModelType.getName(dto.getType())));
|
.collect(Collectors.groupingBy(dto -> ThingsModelType.getName(dto.getType())));
|
||||||
if (result != null) {
|
|
||||||
for (List<ThingsModelValueItem> itemList : result.values()) {
|
for (List<ThingsModelValueItem> itemList : result.values()) {
|
||||||
for (ThingsModelValueItem item : itemList) {
|
for (ThingsModelValueItem item : itemList) {
|
||||||
convertModelName(item, SecurityUtils.getLanguage());
|
convertModelName(item, SecurityUtils.getLanguage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
String jsonString = JSON.toJSONString(result);
|
String jsonString = JSON.toJSONString(result);
|
||||||
Product product = new Product();
|
Product product = new Product();
|
||||||
product.setProductId(productId);
|
product.setProductId(productId);
|
||||||
@ -289,6 +284,7 @@ public class TSLCacheImpl implements ITSLCache {
|
|||||||
// 数据库查询物模型集合
|
// 数据库查询物模型集合
|
||||||
ThingsModel model = new ThingsModel();
|
ThingsModel model = new ThingsModel();
|
||||||
model.setProductId(productId);
|
model.setProductId(productId);
|
||||||
|
model.setIsCalculated(0); // 只查询产品级物模型
|
||||||
model.setLimitValue(SecurityUtils.getLanguage());
|
model.setLimitValue(SecurityUtils.getLanguage());
|
||||||
List<ThingsModel> thingsModels = thingsModelService.selectThingsModelList(model);
|
List<ThingsModel> thingsModels = thingsModelService.selectThingsModelList(model);
|
||||||
//modbus配置参数整合到物模型
|
//modbus配置参数整合到物模型
|
||||||
@ -325,12 +321,132 @@ public class TSLCacheImpl implements ITSLCache {
|
|||||||
|
|
||||||
/*缓存到redis*/
|
/*缓存到redis*/
|
||||||
String cacheKey = RedisKeyBuilder.buildTSLCacheKey(productId);
|
String cacheKey = RedisKeyBuilder.buildTSLCacheKey(productId);
|
||||||
//先删除缓存
|
// 先删除缓存
|
||||||
if (redisCache.containsKey(cacheKey)) {
|
if (redisCache.containsKey(cacheKey)) {
|
||||||
redisCache.deleteObject(cacheKey);
|
redisCache.deleteObject(cacheKey);
|
||||||
}
|
}
|
||||||
|
// 再插入缓存——完成缓存更新
|
||||||
redisCache.hashPutAll(cacheKey, thingsModelMap);
|
redisCache.hashPutAll(cacheKey, thingsModelMap);
|
||||||
return thingsModelMap;
|
return thingsModelMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 设备级计算物模型缓存方法 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备级计算物模型缓存(Map形式)
|
||||||
|
*
|
||||||
|
* @param serialNumber 设备ID
|
||||||
|
* @return Map<标识符, ThingsModelValueItem>
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Map<String, ThingsModelValueItem> getDeviceCalculatedModelMap(String serialNumber) {
|
||||||
|
if (StringUtils.isEmpty(serialNumber)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
String cacheKey = RedisKeyBuilder.buildDeviceTSLCacheKey(serialNumber);
|
||||||
|
Map<String, Object> map = redisCache.getCacheMap(cacheKey);
|
||||||
|
if (!CollectionUtils.isEmpty(map)) {
|
||||||
|
Map<String, ThingsModelValueItem> 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<String, ThingsModelValueItem> refreshDeviceCalculatedModelCache(String serialNumber) {
|
||||||
|
if (StringUtils.isEmpty(serialNumber)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
// 从数据库查询设备级计算物模型
|
||||||
|
ThingsModel model = new ThingsModel();
|
||||||
|
model.setSerialNumber(serialNumber);
|
||||||
|
model.setIsCalculated(1); // 查询设备级物模型
|
||||||
|
List<ThingsModel> models = thingsModelService.selectThingsModelList(model);
|
||||||
|
if (CollectionUtils.isEmpty(models)) {
|
||||||
|
// 清除可能存在的旧缓存
|
||||||
|
clearDeviceCalculatedModelCache(serialNumber);
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换为缓存格式
|
||||||
|
Map<String, String> 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<String, ThingsModelValueItem> modelMap = getDeviceCalculatedModelMap(serialNumber);
|
||||||
|
return modelMap.get(identifier);
|
||||||
|
}
|
||||||
|
ThingsModelValueItem item = JSONObject.parseObject(itemStr, ThingsModelValueItem.class);
|
||||||
|
convertModelName(item, SecurityUtils.getLanguage());
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,8 +43,8 @@ public class TSLValueCacheImpl implements ITSLValueCache {
|
|||||||
public List<ValueItem> getCacheDeviceStatus(Long productId, String deviceNumber) {
|
public List<ValueItem> getCacheDeviceStatus(Long productId, String deviceNumber) {
|
||||||
String key = RedisKeyBuilder.buildTSLVCacheKey(productId, deviceNumber);
|
String key = RedisKeyBuilder.buildTSLVCacheKey(productId, deviceNumber);
|
||||||
Map<String, String> map = redisCache.hashEntity(key);
|
Map<String, String> map = redisCache.hashEntity(key);
|
||||||
List<ValueItem> valueList = new ArrayList<>();
|
List<ValueItem> valueList;
|
||||||
if (map == null || map.size() == 0) {
|
if (map == null || map.isEmpty()) {
|
||||||
// 缓存设备状态(物模型值)到redis
|
// 缓存设备状态(物模型值)到redis
|
||||||
valueList = addCacheDeviceStatus(productId, deviceNumber);
|
valueList = addCacheDeviceStatus(productId, deviceNumber);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -63,6 +63,18 @@ public class ThingsModel extends BaseEntity {
|
|||||||
@ApiModelProperty("产品名称")
|
@ApiModelProperty("产品名称")
|
||||||
private String productName;
|
private String productName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备ID(0表示产品级物模型,>0表示设备级计算物模型)
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "设备ID", notes = "0表示产品级物模型,>0表示设备级计算物模型")
|
||||||
|
private Long deviceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备编号
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("设备编号")
|
||||||
|
private String serialNumber;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 租户ID
|
* 租户ID
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -156,7 +156,6 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
@Value("${server.tcp.port}")
|
@Value("${server.tcp.port}")
|
||||||
private Long tcpPort;
|
private Long tcpPort;
|
||||||
|
|
||||||
|
|
||||||
// select cache
|
// select cache
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -165,7 +164,8 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
* @param deviceId 设备主键
|
* @param deviceId 设备主键
|
||||||
* @return 设备
|
* @return 设备
|
||||||
*/
|
*/
|
||||||
// @Cacheable(cacheNames = "Device", key = "#root.methodName + ':' + #serialNumber", unless = "#result == null")
|
// @Cacheable(cacheNames = "Device", key = "#root.methodName + ':' +
|
||||||
|
// #serialNumber", unless = "#result == null")
|
||||||
@Override
|
@Override
|
||||||
public Device selectDeviceByDeviceId(Long deviceId) {
|
public Device selectDeviceByDeviceId(Long deviceId) {
|
||||||
Device device = deviceMapper.selectDeviceByDeviceId(deviceId);
|
Device device = deviceMapper.selectDeviceByDeviceId(deviceId);
|
||||||
@ -174,7 +174,7 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
// redis中获取设备状态(物模型值)
|
// redis中获取设备状态(物模型值)
|
||||||
device.setThingsModelValue(JSONObject.toJSONString(list));
|
device.setThingsModelValue(JSONObject.toJSONString(list));
|
||||||
}
|
}
|
||||||
//查询关联的监控设备
|
// 查询关联的监控设备
|
||||||
SipRelation sipRelation = new SipRelation();
|
SipRelation sipRelation = new SipRelation();
|
||||||
sipRelation.setReDeviceId(deviceId);
|
sipRelation.setReDeviceId(deviceId);
|
||||||
List<SipRelation> sipRelationList = sipRelationService.selectSipRelationList(sipRelation);
|
List<SipRelation> sipRelationList = sipRelationService.selectSipRelationList(sipRelation);
|
||||||
@ -280,7 +280,8 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
*/
|
*/
|
||||||
@Caching(evict = {
|
@Caching(evict = {
|
||||||
@CacheEvict(cacheNames = "Device", key = "'selectDeviceBySerialNumber:' + #device.getSerialNumber()"),
|
@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 = "'selectDeviceStatusAndTransportStatus:' + #device.getSerialNumber()"),
|
||||||
@CacheEvict(cacheNames = "Device", key = "'selectProtocolBySerialNumber:' + #device.getSerialNumber()"),
|
@CacheEvict(cacheNames = "Device", key = "'selectProtocolBySerialNumber:' + #device.getSerialNumber()"),
|
||||||
@CacheEvict(cacheNames = "Device", key = "'selectShortDeviceBySerialNumber:' + #device.getSerialNumber()")
|
@CacheEvict(cacheNames = "Device", key = "'selectShortDeviceBySerialNumber:' + #device.getSerialNumber()")
|
||||||
@ -312,7 +313,8 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
|
|
||||||
@Caching(evict = {
|
@Caching(evict = {
|
||||||
@CacheEvict(cacheNames = "Device", key = "'selectDeviceBySerialNumber:' + #device.getSerialNumber()"),
|
@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 = "'selectDeviceStatusAndTransportStatus:' + #device.getSerialNumber()"),
|
||||||
@CacheEvict(cacheNames = "Device", key = "'selectProtocolBySerialNumber:' + #device.getSerialNumber()"),
|
@CacheEvict(cacheNames = "Device", key = "'selectProtocolBySerialNumber:' + #device.getSerialNumber()"),
|
||||||
@CacheEvict(cacheNames = "Device", key = "'selectShortDeviceBySerialNumber:' + #device.getSerialNumber()")
|
@CacheEvict(cacheNames = "Device", key = "'selectShortDeviceBySerialNumber:' + #device.getSerialNumber()")
|
||||||
@ -331,7 +333,7 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
@CacheEvict(cacheNames = "Device", allEntries = true)
|
@CacheEvict(cacheNames = "Device", allEntries = true)
|
||||||
@Override
|
@Override
|
||||||
public AjaxResult deleteDeviceByDeviceId(Long deviceId) {
|
public AjaxResult deleteDeviceByDeviceId(Long deviceId) {
|
||||||
//查询设备
|
// 查询设备
|
||||||
Device device = deviceMapper.selectDeviceByDeviceId(deviceId);
|
Device device = deviceMapper.selectDeviceByDeviceId(deviceId);
|
||||||
SysUser user = getLoginUser().getUser();
|
SysUser user = getLoginUser().getUser();
|
||||||
Long sceneUserId;
|
Long sceneUserId;
|
||||||
@ -356,7 +358,8 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
}
|
}
|
||||||
// 设备下不能有场景联动
|
// 设备下不能有场景联动
|
||||||
List<SceneDeviceBindVO> sceneDeviceBindVOList = sceneDeviceMapper.listSceneDeviceBind(device.getSerialNumber());
|
List<SceneDeviceBindVO> 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("删除失败,请先删除对应设备下的场景联动");
|
return AjaxResult.error("删除失败,请先删除对应设备下的场景联动");
|
||||||
}
|
}
|
||||||
// 查绑定用户被分享用户配置的场景,需要把场景删掉
|
// 查绑定用户被分享用户配置的场景,需要把场景删掉
|
||||||
@ -412,12 +415,12 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
String key = RedisKeyBuilder.buildTSLVCacheKey(device.getProductId(), device.getSerialNumber());
|
String key = RedisKeyBuilder.buildTSLVCacheKey(device.getProductId(), device.getSerialNumber());
|
||||||
redisCache.deleteObject(key);
|
redisCache.deleteObject(key);
|
||||||
// 删除设备
|
// 删除设备
|
||||||
deviceMapper.deleteDeviceByDeviceIds(new Long[]{deviceId});
|
deviceMapper.deleteDeviceByDeviceIds(new Long[] { deviceId });
|
||||||
// redis中删除规则脚本
|
// redis中删除规则脚本
|
||||||
String cacheKey = RedisKeyBuilder.buildDeviceMsgCacheKey(device.getSerialNumber());
|
String cacheKey = RedisKeyBuilder.buildDeviceMsgCacheKey(device.getSerialNumber());
|
||||||
redisCache.deleteObject(cacheKey);
|
redisCache.deleteObject(cacheKey);
|
||||||
// 删除设备
|
// 删除设备
|
||||||
deviceMapper.deleteDeviceByDeviceIds(new Long[]{deviceId});
|
deviceMapper.deleteDeviceByDeviceIds(new Long[] { deviceId });
|
||||||
// 删除tcp协议设备缓存
|
// 删除tcp协议设备缓存
|
||||||
String tcpKey1 = RedisKeyBuilder.buildModbusTcpCacheKey(device.getSerialNumber());
|
String tcpKey1 = RedisKeyBuilder.buildModbusTcpCacheKey(device.getSerialNumber());
|
||||||
String tcpKey2 = RedisKeyBuilder.buildModbusTcpRuntimeCacheKey(device.getSerialNumber());
|
String tcpKey2 = RedisKeyBuilder.buildModbusTcpRuntimeCacheKey(device.getSerialNumber());
|
||||||
@ -445,7 +448,6 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO-2.3 查询设备统计信息
|
* TODO-2.3 查询设备统计信息
|
||||||
*
|
*
|
||||||
@ -486,7 +488,6 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
return deviceMapper.selectProductAuthenticate(model);
|
return deviceMapper.selectProductAuthenticate(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新设备的物模型
|
* 更新设备的物模型
|
||||||
*
|
*
|
||||||
@ -497,33 +498,47 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@DSTransactional
|
@DSTransactional
|
||||||
public List<ThingsModelSimpleItem> reportDeviceThingsModelValue(ThingsModelValuesInput input, int type, boolean isShadow) {
|
public List<ThingsModelSimpleItem> reportDeviceThingsModelValue(ThingsModelValuesInput input, int type,
|
||||||
String key = RedisKeyBuilder.buildTSLVCacheKey(input.getProductId(), input.getDeviceNumber());
|
boolean isShadow) {
|
||||||
|
String serialNumber = input.getDeviceNumber();
|
||||||
|
String key = RedisKeyBuilder.buildTSLVCacheKey(input.getProductId(), serialNumber);
|
||||||
Map<String, String> maps = new HashMap<>();
|
Map<String, String> maps = new HashMap<>();
|
||||||
List<ThingsModelSimpleItem> list = new ArrayList<>();
|
List<ThingsModelSimpleItem> list = new ArrayList<>();
|
||||||
|
|
||||||
//属性存储集合
|
// 属性存储集合
|
||||||
List<DeviceLog> deviceLogList = new ArrayList<>();
|
List<DeviceLog> deviceLogList = new ArrayList<>();
|
||||||
//指令存储集合
|
// 指令存储集合
|
||||||
List<FunctionLog> functionLogList = new ArrayList<>();
|
List<FunctionLog> functionLogList = new ArrayList<>();
|
||||||
//事件存储集合
|
// 事件存储集合
|
||||||
List<EventLog> eventLogList = new ArrayList<>();
|
List<EventLog> eventLogList = new ArrayList<>();
|
||||||
// 获取当前时间
|
// 获取当前时间
|
||||||
Date nowDate = DateUtils.getNowDate();
|
Date nowDate = DateUtils.getNowDate();
|
||||||
for (ThingsModelSimpleItem item : input.getThingsModelValueRemarkItem()) {
|
List<ThingsModelSimpleItem> thingsModelValueRemarkItem = input.getThingsModelValueRemarkItem();
|
||||||
|
// 判断是否有纯计算物模型 有:需要获取设备级别物模型 无:直接使用产品级别物模型即可
|
||||||
|
boolean isCalculated = thingsModelValueRemarkItem.stream().anyMatch(ThingsModelSimpleItem::isCalculated);
|
||||||
|
Map<String, ThingsModelValueItem> calculatedModelMap = new HashMap<>();
|
||||||
|
if (isCalculated) {
|
||||||
|
calculatedModelMap = itslCache.getDeviceCalculatedModelMap(serialNumber);
|
||||||
|
}
|
||||||
|
for (ThingsModelSimpleItem item : thingsModelValueRemarkItem) {
|
||||||
String identity = item.getId();
|
String identity = item.getId();
|
||||||
String serialNumber = input.getDeviceNumber();
|
|
||||||
if (identity.startsWith("array_")) {
|
if (identity.startsWith("array_")) {
|
||||||
identity = identity.substring(9);
|
identity = identity.substring(9);
|
||||||
}
|
}
|
||||||
|
ThingsModelValueItem thingModels;
|
||||||
ThingsModelValueItem thingModels = thingsModelService.getSingleThingModels(input.getProductId(), identity);
|
if (item.isCalculated()) {
|
||||||
|
// itslCache.getSingleDeviceCalculatedModel(serialNumber, identity);
|
||||||
|
thingModels = calculatedModelMap.get(identity);
|
||||||
|
} else {
|
||||||
|
thingModels = thingsModelService.getSingleThingModels(input.getProductId(), identity);
|
||||||
|
}
|
||||||
if (Objects.isNull(thingModels)) {
|
if (Objects.isNull(thingModels)) {
|
||||||
log.warn("=>查询物模型为空[{}],标识符:[{}]", input.getProductId(), identity);
|
log.warn("=>查询物模型为空[{}],标识符:[{}]", input.getProductId(), identity);
|
||||||
continue; // 跳过当前物模型的处理
|
continue; // 跳过当前物模型的处理
|
||||||
}
|
}
|
||||||
// 获取设备实时值
|
// 获取设备实时值
|
||||||
ValueItem cacheIdentifier = itslValueCache.getCacheIdentifier(input.getProductId(), input.getDeviceNumber(), thingModels.getId());
|
ValueItem cacheIdentifier = itslValueCache.getCacheIdentifier(input.getProductId(), serialNumber,
|
||||||
|
thingModels.getId());
|
||||||
if (Objects.isNull(cacheIdentifier)) {
|
if (Objects.isNull(cacheIdentifier)) {
|
||||||
log.warn("=>查询物模型值为空[{}],标识符:[{}]", input.getProductId(), identity);
|
log.warn("=>查询物模型值为空[{}],标识符:[{}]", input.getProductId(), identity);
|
||||||
}
|
}
|
||||||
@ -531,9 +546,9 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
String value = item.getValue();
|
String value = item.getValue();
|
||||||
item.setName(thingModels.getName());
|
item.setName(thingModels.getName());
|
||||||
|
|
||||||
/* ★★★★★★★★★★★★★★★★★★★★★★ 数据计算 -开始 ★★★★★★★★★★★★★★★★★★★★★★*/
|
/* ★★★★★★★★★★★★★★★★★★★★★★ 数据计算 -开始 ★★★★★★★★★★★★★★★★★★★★★★ */
|
||||||
//有计算公式的,经过计算公式
|
// 有计算公式的,经过计算公式
|
||||||
if (thingModels != null && thingModels.getFormula() != null && !"".equals(thingModels.getFormula())) {
|
if (thingModels.getFormula() != null && StringUtils.isNotEmpty(thingModels.getFormula())) {
|
||||||
Map<String, String> params = new HashMap<>();
|
Map<String, String> params = new HashMap<>();
|
||||||
// %s 表示当前物模型的值(保持向后兼容)
|
// %s 表示当前物模型的值(保持向后兼容)
|
||||||
params.put("%s", value);
|
params.put("%s", value);
|
||||||
@ -549,7 +564,7 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
try {
|
try {
|
||||||
// 优先从当前消息中查找
|
// 优先从当前消息中查找
|
||||||
String refValue = null;
|
String refValue = null;
|
||||||
for (ThingsModelSimpleItem currentItem : input.getThingsModelValueRemarkItem()) {
|
for (ThingsModelSimpleItem currentItem : thingsModelValueRemarkItem) {
|
||||||
String currentId = currentItem.getId();
|
String currentId = currentItem.getId();
|
||||||
if (currentId.startsWith("array_")) {
|
if (currentId.startsWith("array_")) {
|
||||||
currentId = currentId.substring(9);
|
currentId = currentId.substring(9);
|
||||||
@ -564,9 +579,8 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
if (refValue == null) {
|
if (refValue == null) {
|
||||||
ValueItem refValueItem = itslValueCache.getCacheIdentifier(
|
ValueItem refValueItem = itslValueCache.getCacheIdentifier(
|
||||||
input.getProductId(),
|
input.getProductId(),
|
||||||
input.getDeviceNumber(),
|
serialNumber,
|
||||||
refIdentifier
|
refIdentifier);
|
||||||
);
|
|
||||||
if (refValueItem != null && StringUtils.isNotEmpty(refValueItem.getValue())) {
|
if (refValueItem != null && StringUtils.isNotEmpty(refValueItem.getValue())) {
|
||||||
refValue = refValueItem.getValue();
|
refValue = refValueItem.getValue();
|
||||||
}
|
}
|
||||||
@ -590,15 +604,15 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
log.info("=>纯计算物模型结果[{}],标识符:[{}],结果:{}", input.getProductId(), identity, value);
|
log.info("=>纯计算物模型结果[{}],标识符:[{}],结果:{}", input.getProductId(), identity, value);
|
||||||
item.setValue(value);
|
item.setValue(value);
|
||||||
}
|
}
|
||||||
/* ★★★★★★★★★★★★★★★★★★★★★★ 数据计算 -结束 ★★★★★★★★★★★★★★★★★★★★★★*/
|
/* ★★★★★★★★★★★★★★★★★★★★★★ 数据计算 -结束 ★★★★★★★★★★★★★★★★★★★★★★ */
|
||||||
|
|
||||||
/* ★★★★★★★★★★★★★★★★★★★★★★ 处理数据 - 开始 ★★★★★★★★★★★★★★★★★★★★★★*/
|
/* ★★★★★★★★★★★★★★★★★★★★★★ 处理数据 - 开始 ★★★★★★★★★★★★★★★★★★★★★★ */
|
||||||
ValueItem valueItem = new ValueItem();
|
ValueItem valueItem = new ValueItem();
|
||||||
valueItem.setId(identity);
|
valueItem.setId(identity);
|
||||||
if (id.startsWith("array_")) {
|
if (id.startsWith("array_")) {
|
||||||
// 查询是否有缓存,如果没有先进行缓存
|
// 查询是否有缓存,如果没有先进行缓存
|
||||||
if (!redisCache.containsKey(key)) {
|
if (!redisCache.containsKey(key)) {
|
||||||
Device device = this.selectDeviceBySerialNumber(input.getDeviceNumber());
|
Device device = this.selectDeviceBySerialNumber(serialNumber);
|
||||||
this.selectDeviceByDeviceId(device.getDeviceId());
|
this.selectDeviceByDeviceId(device.getDeviceId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -623,7 +637,7 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
valueItem.setShadow(String.join(",", shadows));
|
valueItem.setShadow(String.join(",", shadows));
|
||||||
}
|
}
|
||||||
redisCache.setCacheMapValue(key, identity, JSONObject.toJSONString(valueItem));
|
redisCache.setCacheMapValue(key, identity, JSONObject.toJSONString(valueItem));
|
||||||
//maps.put(identity, JSONObject.toJSONString(valueItem));
|
// maps.put(identity, JSONObject.toJSONString(valueItem));
|
||||||
} else {
|
} else {
|
||||||
if (isShadow) {
|
if (isShadow) {
|
||||||
valueItem.setShadow(value);
|
valueItem.setShadow(value);
|
||||||
@ -638,11 +652,11 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
}
|
}
|
||||||
maps.put(identity, JSONObject.toJSONString(valueItem));
|
maps.put(identity, JSONObject.toJSONString(valueItem));
|
||||||
}
|
}
|
||||||
/* ★★★★★★★★★★★★★★★★★★★★★★ 处理数据 - 结束 ★★★★★★★★★★★★★★★★★★★★★★*/
|
/* ★★★★★★★★★★★★★★★★★★★★★★ 处理数据 - 结束 ★★★★★★★★★★★★★★★★★★★★★★ */
|
||||||
|
|
||||||
/*★★★★★★★★★★★★★★★★★★★★★★ 存储数据 - 开始 ★★★★★★★★★★★★★★★★★★★★★★*/
|
/* ★★★★★★★★★★★★★★★★★★★★★★ 存储数据 - 开始 ★★★★★★★★★★★★★★★★★★★★★★ */
|
||||||
ThingsModelType modelType = ThingsModelType.getType(thingModels.getType());
|
ThingsModelType modelType = ThingsModelType.getType(thingModels.getType());
|
||||||
Device device = this.selectDeviceBySerialNumber(input.getDeviceNumber());
|
Device device = this.selectDeviceBySerialNumber(serialNumber);
|
||||||
switch (modelType) {
|
switch (modelType) {
|
||||||
case PROP:
|
case PROP:
|
||||||
if (1 == thingModels.getIsHistory()) {
|
if (1 == thingModels.getIsHistory()) {
|
||||||
@ -670,7 +684,7 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
FunctionLog function = new FunctionLog();
|
FunctionLog function = new FunctionLog();
|
||||||
function.setCreateTime(nowDate);
|
function.setCreateTime(nowDate);
|
||||||
function.setFunValue(value);
|
function.setFunValue(value);
|
||||||
function.setSerialNumber(input.getDeviceNumber());
|
function.setSerialNumber(serialNumber);
|
||||||
function.setIdentify(id);
|
function.setIdentify(id);
|
||||||
function.setShowValue(value);
|
function.setShowValue(value);
|
||||||
// 属性获取
|
// 属性获取
|
||||||
@ -703,22 +717,20 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
redisCache.hashPutAll(key, maps);
|
redisCache.hashPutAll(key, maps);
|
||||||
// 存储历史数据——批量
|
// 存储历史数据——批量
|
||||||
if (!CollectionUtils.isEmpty(deviceLogList) && !isShadow) {
|
if (!CollectionUtils.isEmpty(deviceLogList) && !isShadow) {
|
||||||
// for (DeviceLog deviceLog : deviceLogList) {
|
// for (DeviceLog deviceLog : deviceLogList) {
|
||||||
// logService.saveDeviceLog(deviceLog);
|
// logService.saveDeviceLog(deviceLog);
|
||||||
// }
|
// }
|
||||||
logService.saveDeviceLogBatch(deviceLogList);
|
logService.saveDeviceLogBatch(deviceLogList);
|
||||||
}
|
}
|
||||||
//指令存储,影子模式不存储
|
// 指令存储,影子模式不存储
|
||||||
if (!CollectionUtils.isEmpty(functionLogList) && !isShadow) {
|
if (!CollectionUtils.isEmpty(functionLogList) && !isShadow) {
|
||||||
functionLogService.insertBatch(functionLogList);
|
functionLogService.insertBatch(functionLogList);
|
||||||
}
|
}
|
||||||
if (!CollectionUtils.isEmpty(eventLogList)) {
|
if (!CollectionUtils.isEmpty(eventLogList)) {
|
||||||
//事件存储
|
// 事件存储
|
||||||
eventLogService.saveBatch(eventLogList);
|
eventLogService.saveBatch(eventLogList);
|
||||||
}
|
}
|
||||||
/* ★★★★★★★★★★★★★★★★★★★★★★ 存储数据 - 结束 ★★★★★★★★★★★★★★★★★★★★★★*/
|
/* ★★★★★★★★★★★★★★★★★★★★★★ 存储数据 - 结束 ★★★★★★★★★★★★★★★★★★★★★★ */
|
||||||
|
|
||||||
// 注意:纯计算物模型已在 ModbusProtocol 中构造 ThingsModelSimpleItem(值为0)
|
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@ -751,17 +763,17 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<Device> selectDeviceList(Device device) {
|
public List<Device> selectDeviceList(Device device) {
|
||||||
// SysUser user = getLoginUser().getUser();
|
// SysUser user = getLoginUser().getUser();
|
||||||
// List<SysRole> roles = user.getRoles();
|
// List<SysRole> roles = user.getRoles();
|
||||||
// for (int i = 0; i < roles.size(); i++) {
|
// for (int i = 0; i < roles.size(); i++) {
|
||||||
// if (roles.get(i).getRoleKey().equals("tenant")) {
|
// if (roles.get(i).getRoleKey().equals("tenant")) {
|
||||||
// // 租户查看产品下所有设备
|
// // 租户查看产品下所有设备
|
||||||
// device.setTenantId(user.getUserId());
|
// device.setTenantId(user.getUserId());
|
||||||
// } else if (roles.get(i).getRoleKey().equals("general")) {
|
// } else if (roles.get(i).getRoleKey().equals("general")) {
|
||||||
// // 用户查看自己设备
|
// // 用户查看自己设备
|
||||||
// device.setUserId(user.getUserId());
|
// device.setUserId(user.getUserId());
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
return deviceMapper.selectDeviceList(device);
|
return deviceMapper.selectDeviceList(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -773,17 +785,17 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<Device> selectUnAuthDeviceList(Device device) {
|
public List<Device> selectUnAuthDeviceList(Device device) {
|
||||||
// SysUser user = getLoginUser().getUser();
|
// SysUser user = getLoginUser().getUser();
|
||||||
// List<SysRole> roles = user.getRoles();
|
// List<SysRole> roles = user.getRoles();
|
||||||
// for (int i = 0; i < roles.size(); i++) {
|
// for (int i = 0; i < roles.size(); i++) {
|
||||||
// if (roles.get(i).getRoleKey().equals("tenant")) {
|
// if (roles.get(i).getRoleKey().equals("tenant")) {
|
||||||
// // 租户查看产品下所有设备
|
// // 租户查看产品下所有设备
|
||||||
// device.setTenantId(user.getUserId());
|
// device.setTenantId(user.getUserId());
|
||||||
// } else if (roles.get(i).getRoleKey().equals("general")) {
|
// } else if (roles.get(i).getRoleKey().equals("general")) {
|
||||||
// // 用户查看自己设备
|
// // 用户查看自己设备
|
||||||
// device.setUserId(user.getUserId());
|
// device.setUserId(user.getUserId());
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
return deviceMapper.selectUnAuthDeviceList(device);
|
return deviceMapper.selectUnAuthDeviceList(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -795,17 +807,17 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<Device> selectDeviceListByGroup(Device device) {
|
public List<Device> selectDeviceListByGroup(Device device) {
|
||||||
// SysUser user = getLoginUser().getUser();
|
// SysUser user = getLoginUser().getUser();
|
||||||
// List<SysRole> roles = user.getRoles();
|
// List<SysRole> roles = user.getRoles();
|
||||||
// for (int i = 0; i < roles.size(); i++) {
|
// for (int i = 0; i < roles.size(); i++) {
|
||||||
// if (roles.get(i).getRoleKey().equals("tenant")) {
|
// if (roles.get(i).getRoleKey().equals("tenant")) {
|
||||||
// // 租户查看产品下所有设备
|
// // 租户查看产品下所有设备
|
||||||
// device.setTenantId(user.getUserId());
|
// device.setTenantId(user.getUserId());
|
||||||
// } else if (roles.get(i).getRoleKey().equals("general")) {
|
// } else if (roles.get(i).getRoleKey().equals("general")) {
|
||||||
// // 用户查看自己设备
|
// // 用户查看自己设备
|
||||||
// device.setUserId(user.getUserId());
|
// device.setUserId(user.getUserId());
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
return deviceMapper.selectDeviceListByGroup(device);
|
return deviceMapper.selectDeviceListByGroup(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -845,7 +857,8 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
SysUser user = getLoginUser().getUser();
|
SysUser user = getLoginUser().getUser();
|
||||||
if (null != user.getDept()) {
|
if (null != user.getDept()) {
|
||||||
Long tenantId = user.getDept().getDeptUserId();
|
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 {
|
} else {
|
||||||
serialNumberList = list.stream().map(DeviceShortOutput::getSerialNumber).collect(Collectors.toList());
|
serialNumberList = list.stream().map(DeviceShortOutput::getSerialNumber).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
@ -870,19 +883,42 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
@Override
|
@Override
|
||||||
public DeviceShortOutput selectDeviceRunningStatusByDeviceId(Long deviceId) {
|
public DeviceShortOutput selectDeviceRunningStatusByDeviceId(Long deviceId) {
|
||||||
DeviceShortOutput device = deviceMapper.selectDeviceRunningStatusByDeviceId(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 properties = thingsModelObject.getJSONArray("properties");
|
||||||
JSONArray functions = thingsModelObject.getJSONArray("functions");
|
JSONArray functions = thingsModelObject.getJSONArray("functions");
|
||||||
List<ValueItem> thingsModelValueItems = itslValueCache.getCacheDeviceStatus(device.getProductId(), device.getSerialNumber());
|
List<ValueItem> thingsModelValueItems = itslValueCache.getCacheDeviceStatus(device.getProductId(),
|
||||||
|
device.getSerialNumber());
|
||||||
// 物模型转换赋值
|
// 物模型转换赋值
|
||||||
List<ThingsModelValueItem> thingsList = new ArrayList<>();
|
List<ThingsModelValueItem> thingsList = new ArrayList<>();
|
||||||
//判断一下properties 和 functions是否为空, 否则报空指针
|
// 判断一下properties 和 functions是否为空, 否则报空指针
|
||||||
if (!CollectionUtils.isEmpty(properties)) {
|
if (!CollectionUtils.isEmpty(properties)) {
|
||||||
thingsList.addAll(convertJsonToThingsList(properties, thingsModelValueItems, 1));
|
thingsList.addAll(convertJsonToThingsList(properties, thingsModelValueItems, 1));
|
||||||
}
|
}
|
||||||
if (!CollectionUtils.isEmpty(functions)) {
|
if (!CollectionUtils.isEmpty(functions)) {
|
||||||
thingsList.addAll(convertJsonToThingsList(functions, thingsModelValueItems, 2));
|
thingsList.addAll(convertJsonToThingsList(functions, thingsModelValueItems, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. 获取设备级计算物模型并合并
|
||||||
|
Map<String, ThingsModelValueItem> 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);
|
device.setThingsModels(thingsList);
|
||||||
return device;
|
return device;
|
||||||
|
|
||||||
@ -897,7 +933,8 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Async
|
@Async
|
||||||
public List<ThingsModelValueItem> convertJsonToThingsList(JSONArray jsonArray, List<ValueItem> thingsModelValues, Integer type) {
|
public List<ThingsModelValueItem> convertJsonToThingsList(JSONArray jsonArray, List<ValueItem> thingsModelValues,
|
||||||
|
Integer type) {
|
||||||
List<ThingsModelValueItem> thingsModelList = new ArrayList<>();
|
List<ThingsModelValueItem> thingsModelList = new ArrayList<>();
|
||||||
for (int i = 0; i < jsonArray.size(); i++) {
|
for (int i = 0; i < jsonArray.size(); i++) {
|
||||||
ThingsModelValueItem thingsModel = new ThingsModelValueItem();
|
ThingsModelValueItem thingsModel = new ThingsModelValueItem();
|
||||||
@ -905,11 +942,15 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
JSONObject datatypeJson = thingsJson.getJSONObject("datatype");
|
JSONObject datatypeJson = thingsJson.getJSONObject("datatype");
|
||||||
thingsModel.setId(thingsJson.getString("id"));
|
thingsModel.setId(thingsJson.getString("id"));
|
||||||
thingsModel.setName(thingsJson.getString("name"));
|
thingsModel.setName(thingsJson.getString("name"));
|
||||||
thingsModel.setIsMonitor(thingsJson.getInteger("isMonitor") == null ? 0 : thingsJson.getInteger("isMonitor"));
|
thingsModel
|
||||||
thingsModel.setIsReadonly(thingsJson.getInteger("isReadonly") == null ? 0 : thingsJson.getInteger("isReadonly"));
|
.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.setIsChart(thingsJson.getInteger("isChart") == null ? 0 : thingsJson.getInteger("isChart"));
|
||||||
thingsModel.setIsSharePerm(thingsJson.getInteger("isSharePerm") == null ? 0 : thingsJson.getInteger("isSharePerm"));
|
thingsModel.setIsSharePerm(
|
||||||
thingsModel.setIsHistory(thingsJson.getInteger("isHistory") == null ? 0 : thingsJson.getInteger("isHistory"));
|
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.setIsApp(thingsJson.getInteger("isApp") == null ? 0 : thingsJson.getInteger("isApp"));
|
||||||
thingsModel.setOrder(thingsJson.getInteger("order") == null ? 0 : thingsJson.getInteger("order"));
|
thingsModel.setOrder(thingsJson.getInteger("order") == null ? 0 : thingsJson.getInteger("order"));
|
||||||
thingsModel.setType(type);
|
thingsModel.setType(type);
|
||||||
@ -957,9 +998,10 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
* @param parentIdentifier 上级标识符
|
* @param parentIdentifier 上级标识符
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private Datatype convertJsonToDataType(JSONObject datatypeJson, List<ValueItem> thingsModelValues, Integer type, String parentIdentifier) {
|
private Datatype convertJsonToDataType(JSONObject datatypeJson, List<ValueItem> thingsModelValues, Integer type,
|
||||||
|
String parentIdentifier) {
|
||||||
Datatype dataType = new Datatype();
|
Datatype dataType = new Datatype();
|
||||||
//有些物模型数据定义为空的情况兼容
|
// 有些物模型数据定义为空的情况兼容
|
||||||
if (datatypeJson == null) {
|
if (datatypeJson == null) {
|
||||||
return dataType;
|
return dataType;
|
||||||
}
|
}
|
||||||
@ -986,10 +1028,12 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
} else if (dataType.getType().equals("object")) {
|
} else if (dataType.getType().equals("object")) {
|
||||||
JSONArray jsonArray = JSON.parseArray(datatypeJson.getString("params"));
|
JSONArray jsonArray = JSON.parseArray(datatypeJson.getString("params"));
|
||||||
// 物模型值过滤(parentId_开头)
|
// 物模型值过滤(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<ThingsModelValueItem> thingsList = convertJsonToThingsList(jsonArray, thingsModelValues, type);
|
List<ThingsModelValueItem> 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);
|
dataType.setParams(thingsList);
|
||||||
} else if (dataType.getType().equals("array")) {
|
} else if (dataType.getType().equals("array")) {
|
||||||
dataType.setArrayType(datatypeJson.getString("arrayType"));
|
dataType.setArrayType(datatypeJson.getString("arrayType"));
|
||||||
@ -998,10 +1042,12 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
// 对象数组
|
// 对象数组
|
||||||
JSONArray jsonArray = datatypeJson.getJSONArray("params");
|
JSONArray jsonArray = datatypeJson.getJSONArray("params");
|
||||||
// 物模型值过滤(parentId_开头)
|
// 物模型值过滤(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<ThingsModelValueItem> thingsList = convertJsonToThingsList(jsonArray, thingsModelValues, type);
|
List<ThingsModelValueItem> 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<ThingsModel>[] arrayParams = new List[dataType.getArrayCount()];
|
List<ThingsModel>[] arrayParams = new List[dataType.getArrayCount()];
|
||||||
for (int i = 0; i < dataType.getArrayCount(); i++) {
|
for (int i = 0; i < dataType.getArrayCount(); i++) {
|
||||||
@ -1053,7 +1099,7 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
throw new ServiceException("设备编号:" + device.getSerialNumber() + " 已经存在,新增失败");
|
throw new ServiceException("设备编号:" + device.getSerialNumber() + " 已经存在,新增失败");
|
||||||
}
|
}
|
||||||
SysUser sysUser = getLoginUser().getUser();
|
SysUser sysUser = getLoginUser().getUser();
|
||||||
//添加设备
|
// 添加设备
|
||||||
device.setCreateTime(DateUtils.getNowDate());
|
device.setCreateTime(DateUtils.getNowDate());
|
||||||
device.setTenantId(sysUser.getDept().getDeptUserId());
|
device.setTenantId(sysUser.getDept().getDeptUserId());
|
||||||
device.setTenantName(sysUser.getDept().getDeptUserName());
|
device.setTenantName(sysUser.getDept().getDeptUserName());
|
||||||
@ -1067,7 +1113,8 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
setLocation(user.getLoginIp(), device);
|
setLocation(user.getLoginIp(), device);
|
||||||
deviceMapper.insertDevice(device);
|
deviceMapper.insertDevice(device);
|
||||||
// 处理modbus产品
|
// 处理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);
|
this.handleModbusConfig(device, product);
|
||||||
}
|
}
|
||||||
// redis缓存设备默认状态(物模型值)
|
// redis缓存设备默认状态(物模型值)
|
||||||
@ -1104,15 +1151,18 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
productSubGatewayList.sort(Comparator.comparing(ProductSubGatewayVO::getSlaveId));
|
productSubGatewayList.sort(Comparator.comparing(ProductSubGatewayVO::getSlaveId));
|
||||||
List<Long> subProductIdList = productSubGatewayList.stream().map(ProductSubGatewayVO::getSubProductId).collect(Collectors.toList());
|
List<Long> subProductIdList = productSubGatewayList.stream().map(ProductSubGatewayVO::getSubProductId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
LambdaQueryWrapper<ProductModbusJob> queryWrapper1 = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<ProductModbusJob> queryWrapper1 = new LambdaQueryWrapper<>();
|
||||||
queryWrapper1.in(ProductModbusJob::getProductId, subProductIdList);
|
queryWrapper1.in(ProductModbusJob::getProductId, subProductIdList);
|
||||||
List<ProductModbusJob> productModbusJobList = productModbusJobMapper.selectList(queryWrapper1);
|
List<ProductModbusJob> productModbusJobList = productModbusJobMapper.selectList(queryWrapper1);
|
||||||
Map<Long, List<ProductModbusJob>> productModbusJobMap = productModbusJobList.stream().collect(Collectors.groupingBy(ProductModbusJob::getProductId));
|
Map<Long, List<ProductModbusJob>> productModbusJobMap = productModbusJobList.stream()
|
||||||
|
.collect(Collectors.groupingBy(ProductModbusJob::getProductId));
|
||||||
// 新增子设备、绑定子设备、子设备生成轮询
|
// 新增子设备、绑定子设备、子设备生成轮询
|
||||||
for (ProductSubGatewayVO productSubGatewayVO : productSubGatewayList) {
|
for (ProductSubGatewayVO productSubGatewayVO : productSubGatewayList) {
|
||||||
Device addDevice = new Device();
|
Device addDevice = new Device();
|
||||||
addDevice.setDeviceName(productSubGatewayVO.getSubProductName() + "_" + productSubGatewayVO.getSlaveId());
|
addDevice.setDeviceName(
|
||||||
|
productSubGatewayVO.getSubProductName() + "_" + productSubGatewayVO.getSlaveId());
|
||||||
addDevice.setProductId(productSubGatewayVO.getSubProductId());
|
addDevice.setProductId(productSubGatewayVO.getSubProductId());
|
||||||
addDevice.setProductName(productSubGatewayVO.getSubProductName());
|
addDevice.setProductName(productSubGatewayVO.getSubProductName());
|
||||||
String serialNumber = this.generationDeviceNum(1);
|
String serialNumber = this.generationDeviceNum(1);
|
||||||
@ -1134,7 +1184,8 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
subGateway.setCreateBy(addDevice.getCreateBy());
|
subGateway.setCreateBy(addDevice.getCreateBy());
|
||||||
subGateway.setCreateTime(new Date());
|
subGateway.setCreateTime(new Date());
|
||||||
subGatewayMapper.insertGateway(subGateway);
|
subGatewayMapper.insertGateway(subGateway);
|
||||||
List<ProductModbusJob> productModbusList = productModbusJobMap.get(productSubGatewayVO.getSubProductId());
|
List<ProductModbusJob> productModbusList = productModbusJobMap
|
||||||
|
.get(productSubGatewayVO.getSubProductId());
|
||||||
if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(productModbusList)) {
|
if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(productModbusList)) {
|
||||||
for (ProductModbusJob productModbusJob : productModbusList) {
|
for (ProductModbusJob productModbusJob : productModbusList) {
|
||||||
ModbusJob modbusJob = new ModbusJob();
|
ModbusJob modbusJob = new ModbusJob();
|
||||||
@ -1164,12 +1215,12 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public AjaxResult deviceRelateUser(DeviceRelateUserInput params) {
|
public AjaxResult deviceRelateUser(DeviceRelateUserInput params) {
|
||||||
Long userId = params.getUserId(); //终端用户id
|
Long userId = params.getUserId(); // 终端用户id
|
||||||
// 查询用户信息
|
// 查询用户信息
|
||||||
SysUser sysUser = userService.selectUserById(userId);
|
SysUser sysUser = userService.selectUserById(userId);
|
||||||
for (DeviceNumberAndProductId item : params.getDeviceNumberAndProductIds()) {
|
for (DeviceNumberAndProductId item : params.getDeviceNumberAndProductIds()) {
|
||||||
Device existDevice = deviceMapper.selectDeviceBySerialNumber(item.getDeviceNumber());
|
Device existDevice = deviceMapper.selectDeviceBySerialNumber(item.getDeviceNumber());
|
||||||
//查看设备是否已经分配
|
// 查看设备是否已经分配
|
||||||
if (!Objects.isNull(existDevice)) {
|
if (!Objects.isNull(existDevice)) {
|
||||||
if (null != sysUser.getDeptId()) {
|
if (null != sysUser.getDeptId()) {
|
||||||
return AjaxResult.error("租户不允许绑定已存在的设备,设备编号:" + item.getDeviceNumber());
|
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 deviceUser = new DeviceUser();
|
||||||
deviceUser.setUserId(sysUser.getUserId());
|
deviceUser.setUserId(sysUser.getUserId());
|
||||||
@ -1265,13 +1317,14 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
@Override
|
@Override
|
||||||
public ThingsModelShadow getDeviceShadowThingsModel(Device device) {
|
public ThingsModelShadow getDeviceShadowThingsModel(Device device) {
|
||||||
// 物模型值
|
// 物模型值
|
||||||
List<ValueItem> thingsModelValueItems = itslValueCache.getCacheDeviceStatus(device.getProductId(), device.getSerialNumber());
|
List<ValueItem> thingsModelValueItems = itslValueCache.getCacheDeviceStatus(device.getProductId(),
|
||||||
|
device.getSerialNumber());
|
||||||
ThingsModelShadow shadow = new ThingsModelShadow();
|
ThingsModelShadow shadow = new ThingsModelShadow();
|
||||||
// 查询出设置的影子值
|
// 查询出设置的影子值
|
||||||
//List<ThingsModelValueItem> shadowList = new ArrayList<>();
|
// List<ThingsModelValueItem> shadowList = new ArrayList<>();
|
||||||
for (ValueItem item : thingsModelValueItems) {
|
for (ValueItem item : thingsModelValueItems) {
|
||||||
if (!item.getShadow().equals(item.getValue()) && !item.getShadow().isEmpty()) {
|
if (!item.getShadow().equals(item.getValue()) && !item.getShadow().isEmpty()) {
|
||||||
//处理id
|
// 处理id
|
||||||
String id = item.getId();
|
String id = item.getId();
|
||||||
if (item.getShadow().contains(",")) {
|
if (item.getShadow().contains(",")) {
|
||||||
String[] shadows = item.getShadow().split(",");
|
String[] shadows = item.getShadow().split(",");
|
||||||
@ -1297,7 +1350,6 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
return shadow;
|
return shadow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成设备唯一编号
|
* 生成设备唯一编号
|
||||||
*
|
*
|
||||||
@ -1308,7 +1360,7 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
// 设备编号:D + userId + 15位随机字母和数字
|
// 设备编号:D + userId + 15位随机字母和数字
|
||||||
SysUser user = getLoginUser().getUser();
|
SysUser user = getLoginUser().getUser();
|
||||||
String number;
|
String number;
|
||||||
//Hex随机字符串
|
// Hex随机字符串
|
||||||
if (type == 3) {
|
if (type == 3) {
|
||||||
number = toolService.generateRandomHex(12);
|
number = toolService.generateRandomHex(12);
|
||||||
} else {
|
} else {
|
||||||
@ -1433,8 +1485,8 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
deviceUserMapper.insertDeviceUser(deviceUser);
|
deviceUserMapper.insertDeviceUser(deviceUser);
|
||||||
}
|
}
|
||||||
// 更新设备用户信息 多租户版本不需要
|
// 更新设备用户信息 多租户版本不需要
|
||||||
// device.setTenantId(device.getTenantId());
|
// device.setTenantId(device.getTenantId());
|
||||||
// device.setTenantName(sysUser.getUserName());
|
// device.setTenantName(sysUser.getUserName());
|
||||||
}
|
}
|
||||||
device.setUpdateTime(DateUtils.getNowDate());
|
device.setUpdateTime(DateUtils.getNowDate());
|
||||||
if (deviceEntity.getActiveTime() == null || deviceEntity.getActiveTime().equals("")) {
|
if (deviceEntity.getActiveTime() == null || deviceEntity.getActiveTime().equals("")) {
|
||||||
@ -1459,7 +1511,6 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
return deviceMapper.selectDevicesByProductId(productId, hasSub);
|
return deviceMapper.selectDevicesByProductId(productId, hasSub);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量更新设备状态
|
* 批量更新设备状态
|
||||||
*
|
*
|
||||||
@ -1472,7 +1523,7 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
if (CollectionUtils.isEmpty(serialNumbers)) {
|
if (CollectionUtils.isEmpty(serialNumbers)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//设备离线
|
// 设备离线
|
||||||
if (DeviceStatus.OFFLINE.equals(status)) {
|
if (DeviceStatus.OFFLINE.equals(status)) {
|
||||||
deviceMapper.batchChangeOffline(serialNumbers);
|
deviceMapper.batchChangeOffline(serialNumbers);
|
||||||
} else if (DeviceStatus.ONLINE.equals(status)) {
|
} else if (DeviceStatus.ONLINE.equals(status)) {
|
||||||
@ -1514,21 +1565,28 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
String password;
|
String password;
|
||||||
if (ProductAuthConstant.AUTHORIZE.equals(deviceMqttVO.getIsAuthorize())) {
|
if (ProductAuthConstant.AUTHORIZE.equals(deviceMqttVO.getIsAuthorize())) {
|
||||||
// 查询产品授权码
|
// 查询产品授权码
|
||||||
List<ProductAuthorize> productAuthorizeList = productAuthorizeService.listByProductId(deviceMqttVO.getProductId());
|
List<ProductAuthorize> productAuthorizeList = productAuthorizeService
|
||||||
|
.listByProductId(deviceMqttVO.getProductId());
|
||||||
if (CollectionUtils.isEmpty(productAuthorizeList)) {
|
if (CollectionUtils.isEmpty(productAuthorizeList)) {
|
||||||
throw new ServiceException("产品已启用授权,获取设备授权码失败,请先配置授权码");
|
throw new ServiceException("产品已启用授权,获取设备授权码失败,请先配置授权码");
|
||||||
}
|
}
|
||||||
List<ProductAuthorize> collect = productAuthorizeList.stream().filter(p -> p.getProductId().equals(deviceMqttVO.getDeviceId())).collect(Collectors.toList());
|
List<ProductAuthorize> collect = productAuthorizeList.stream()
|
||||||
ProductAuthorize productAuthorize = CollectionUtils.isEmpty(collect) ? productAuthorizeList.get(0) : collect.get(0);
|
.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();
|
password = deviceMqttVO.getMqttPassword() + "&" + productAuthorize.getAuthorizeCode();
|
||||||
} else {
|
} else {
|
||||||
password = deviceMqttVO.getMqttPassword();
|
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.setClientId(clientId).setUsername(deviceMqttVO.getMqttAccount()).setPasswd(password)
|
||||||
connectVO.setSubscribeTopic("/" + deviceMqttVO.getProductId() + "/" + deviceMqttVO.getSerialNumber() + "/function/get");
|
.setPort(brokerPort);
|
||||||
connectVO.setReportTopic("/" + deviceMqttVO.getProductId() + "/" + deviceMqttVO.getSerialNumber() + "/property/post");
|
connectVO.setSubscribeTopic(
|
||||||
|
"/" + deviceMqttVO.getProductId() + "/" + deviceMqttVO.getSerialNumber() + "/function/get");
|
||||||
|
connectVO.setReportTopic(
|
||||||
|
"/" + deviceMqttVO.getProductId() + "/" + deviceMqttVO.getSerialNumber() + "/property/post");
|
||||||
return connectVO;
|
return connectVO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1548,7 +1606,7 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
*/
|
*/
|
||||||
private void setLocation(String ip, Device device) {
|
private void setLocation(String ip, Device device) {
|
||||||
String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp";
|
String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp";
|
||||||
//String address = "未知地址";
|
// String address = "未知地址";
|
||||||
// 内网不查询
|
// 内网不查询
|
||||||
if (IpUtils.internalIp(ip)) {
|
if (IpUtils.internalIp(ip)) {
|
||||||
device.setNetworkAddress("内网IP");
|
device.setNetworkAddress("内网IP");
|
||||||
@ -1576,13 +1634,15 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
String BAIDU_URL = "http://api.map.baidu.com/geocoding/v3/";
|
String BAIDU_URL = "http://api.map.baidu.com/geocoding/v3/";
|
||||||
city = StrUtil.isEmpty(city) ? "湖南省长沙市岳麓区" : city;
|
city = StrUtil.isEmpty(city) ? "湖南省长沙市岳麓区" : city;
|
||||||
String encodedAddress = URLEncoder.encode(city, StandardCharsets.UTF_8.toString());
|
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)) {
|
if (!StringUtils.isEmpty(baiduResponse)) {
|
||||||
JSONObject baiduObject = JSONObject.parseObject(baiduResponse);
|
JSONObject baiduObject = JSONObject.parseObject(baiduResponse);
|
||||||
JSONObject location = baiduObject.getJSONObject("result").getJSONObject("location");
|
JSONObject location = baiduObject.getJSONObject("result").getJSONObject("location");
|
||||||
device.setLongitude(location.getBigDecimal("lng"));
|
device.setLongitude(location.getBigDecimal("lng"));
|
||||||
device.setLatitude(location.getBigDecimal("lat"));
|
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);
|
return deviceMapper.getDeviceNumsByProductId(productId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重置设备状态
|
* 重置设备状态
|
||||||
*
|
*
|
||||||
@ -1616,7 +1675,8 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
if (null == product) {
|
if (null == product) {
|
||||||
return "导入失败,产品信息为空";
|
return "导入失败,产品信息为空";
|
||||||
}
|
}
|
||||||
List<String> serialNumberList = deviceImportVOList.stream().map(DeviceImportVO::getSerialNumber).collect(Collectors.toList());
|
List<String> serialNumberList = deviceImportVOList.stream().map(DeviceImportVO::getSerialNumber)
|
||||||
|
.collect(Collectors.toList());
|
||||||
List<String> oldSerialNumberList = deviceMapper.checkExistBySerialNumbers(serialNumberList);
|
List<String> oldSerialNumberList = deviceMapper.checkExistBySerialNumbers(serialNumberList);
|
||||||
if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(oldSerialNumberList)) {
|
if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(oldSerialNumberList)) {
|
||||||
return "以下设备编号(" + JSON.toJSONString(oldSerialNumberList) + ")已存在,请修改后重试";
|
return "以下设备编号(" + JSON.toJSONString(oldSerialNumberList) + ")已存在,请修改后重试";
|
||||||
@ -1645,12 +1705,16 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
int result = deviceMapper.insertBatchDevice(deviceList);
|
int result = deviceMapper.insertBatchDevice(deviceList);
|
||||||
// 新增导入记录
|
// 新增导入记录
|
||||||
DeviceRecord deviceRecord = new DeviceRecord();
|
DeviceRecord deviceRecord = new DeviceRecord();
|
||||||
deviceRecord.setOperateDeptId(loginUser.getDeptId()).setProductId(productId).setType(DeviceRecordTypeEnum.IMPORT.getType())
|
deviceRecord.setOperateDeptId(loginUser.getDeptId()).setProductId(productId)
|
||||||
.setTotal(deviceList.size()).setTenantId(loginUser.getUser().getDept().getDeptUserId()).setTenantName(loginUser.getUser().getDept().getDeptUserName());
|
.setType(DeviceRecordTypeEnum.IMPORT.getType())
|
||||||
|
.setTotal(deviceList.size()).setTenantId(loginUser.getUser().getDept().getDeptUserId())
|
||||||
|
.setTenantName(loginUser.getUser().getDept().getDeptUserName());
|
||||||
if (result > 0) {
|
if (result > 0) {
|
||||||
deviceRecord.setStatus(StatusEnum.SUCCESS.getStatus()).setSuccessQuantity(deviceList.size()).setFailQuantity(0);
|
deviceRecord.setStatus(StatusEnum.SUCCESS.getStatus()).setSuccessQuantity(deviceList.size())
|
||||||
|
.setFailQuantity(0);
|
||||||
} else {
|
} 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());
|
deviceRecord.setCreateBy(loginUser.getUsername());
|
||||||
deviceRecordMapper.insertDeviceRecord(deviceRecord);
|
deviceRecordMapper.insertDeviceRecord(deviceRecord);
|
||||||
@ -1664,7 +1728,8 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
if (null == product) {
|
if (null == product) {
|
||||||
return "导入失败,产品信息为空";
|
return "导入失败,产品信息为空";
|
||||||
}
|
}
|
||||||
List<String> serialNumberList = deviceAssignmentVOS.stream().map(DeviceAssignmentVO::getSerialNumber).collect(Collectors.toList());
|
List<String> serialNumberList = deviceAssignmentVOS.stream().map(DeviceAssignmentVO::getSerialNumber)
|
||||||
|
.collect(Collectors.toList());
|
||||||
List<String> oldSerialNumberList = deviceMapper.checkExistBySerialNumbers(serialNumberList);
|
List<String> oldSerialNumberList = deviceMapper.checkExistBySerialNumbers(serialNumberList);
|
||||||
if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(oldSerialNumberList)) {
|
if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(oldSerialNumberList)) {
|
||||||
return "以下设备编号(" + JSON.toJSONString(oldSerialNumberList) + ")已存在,请修改后重试";
|
return "以下设备编号(" + JSON.toJSONString(oldSerialNumberList) + ")已存在,请修改后重试";
|
||||||
@ -1701,8 +1766,11 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
int result = deviceMapper.insertBatchDevice(deviceList);
|
int result = deviceMapper.insertBatchDevice(deviceList);
|
||||||
// 新增导入记录
|
// 新增导入记录
|
||||||
DeviceRecord deviceRecord = new DeviceRecord();
|
DeviceRecord deviceRecord = new DeviceRecord();
|
||||||
deviceRecord.setOperateDeptId(loginUser.getDeptId()).setTargetDeptId(deptId).setTargetDeptId(deptId).setProductId(productId).setDistributeType(DeviceDistributeTypeEnum.IMPORT.getType())
|
deviceRecord.setOperateDeptId(loginUser.getDeptId()).setTargetDeptId(deptId).setTargetDeptId(deptId)
|
||||||
.setType(DeviceRecordTypeEnum.ASSIGNMENT.getType()).setTotal(deviceList.size()).setTenantId(loginUser.getUser().getDept().getDeptUserId()).setTenantName(loginUser.getUser().getDept().getDeptUserName());
|
.setProductId(productId).setDistributeType(DeviceDistributeTypeEnum.IMPORT.getType())
|
||||||
|
.setType(DeviceRecordTypeEnum.ASSIGNMENT.getType()).setTotal(deviceList.size())
|
||||||
|
.setTenantId(loginUser.getUser().getDept().getDeptUserId())
|
||||||
|
.setTenantName(loginUser.getUser().getDept().getDeptUserName());
|
||||||
List<DeviceRecord> deviceRecordList = new ArrayList<>();
|
List<DeviceRecord> deviceRecordList = new ArrayList<>();
|
||||||
if (result > 0) {
|
if (result > 0) {
|
||||||
deviceRecord.setStatus(StatusEnum.SUCCESS.getStatus());
|
deviceRecord.setStatus(StatusEnum.SUCCESS.getStatus());
|
||||||
@ -1717,10 +1785,15 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
int insertRecordStatus = deviceRecordMapper.insertDeviceRecord(deviceRecord);
|
int insertRecordStatus = deviceRecordMapper.insertDeviceRecord(deviceRecord);
|
||||||
for (Device device : deviceList) {
|
for (Device device : deviceList) {
|
||||||
DeviceRecord deviceRecord1 = new DeviceRecord();
|
DeviceRecord deviceRecord1 = new DeviceRecord();
|
||||||
deviceRecord1.setOperateDeptId(loginUser.getDeptId()).setTargetDeptId(deptId).setProductId(productId).setDeviceId(device.getDeviceId())
|
deviceRecord1.setOperateDeptId(loginUser.getDeptId()).setTargetDeptId(deptId).setProductId(productId)
|
||||||
.setType(DeviceRecordTypeEnum.ASSIGNMENT_DETAIL.getType()).setParentId(deviceRecord.getId()).setSerialNumber(device.getSerialNumber())
|
.setDeviceId(device.getDeviceId())
|
||||||
.setDistributeType(DeviceDistributeTypeEnum.IMPORT.getType()).setTenantId(loginUser.getUser().getDept().getDeptUserId()).setTenantName(loginUser.getUser().getDept().getDeptUserName());
|
.setType(DeviceRecordTypeEnum.ASSIGNMENT_DETAIL.getType()).setParentId(deviceRecord.getId())
|
||||||
deviceRecord1.setStatus(insertRecordStatus > 0 ? StatusEnum.SUCCESS.getStatus() : StatusEnum.FAIL.getStatus());
|
.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());
|
deviceRecord1.setCreateBy(loginUser.getUsername());
|
||||||
deviceRecordList.add(deviceRecord1);
|
deviceRecordList.add(deviceRecord1);
|
||||||
}
|
}
|
||||||
@ -1750,11 +1823,14 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
if (null == sysUser) {
|
if (null == sysUser) {
|
||||||
return AjaxResult.error("机构管理员不存在");
|
return AjaxResult.error("机构管理员不存在");
|
||||||
}
|
}
|
||||||
List<Long> deviceIdList = Arrays.stream(deviceIds.split(",")).map(d -> Long.parseLong(d.trim())).distinct().collect(Collectors.toList());
|
List<Long> deviceIdList = Arrays.stream(deviceIds.split(",")).map(d -> Long.parseLong(d.trim())).distinct()
|
||||||
|
.collect(Collectors.toList());
|
||||||
int result = deviceMapper.updateTenantIdByDeptIds(deptUserId, sysUser.getUserName(), deviceIdList);
|
int result = deviceMapper.updateTenantIdByDeptIds(deptUserId, sysUser.getUserName(), deviceIdList);
|
||||||
DeviceRecord deviceRecord = new DeviceRecord();
|
DeviceRecord deviceRecord = new DeviceRecord();
|
||||||
deviceRecord.setOperateDeptId(user.getDeptId()).setTargetDeptId(deptId).setTargetDeptId(deptId).setDistributeType(DeviceDistributeTypeEnum.SELECT.getType())
|
deviceRecord.setOperateDeptId(user.getDeptId()).setTargetDeptId(deptId).setTargetDeptId(deptId)
|
||||||
.setType(DeviceRecordTypeEnum.ASSIGNMENT.getType()).setTotal(deviceIdList.size()).setTenantId(user.getDept().getDeptUserId()).setTenantName(user.getDept().getDeptUserName());
|
.setDistributeType(DeviceDistributeTypeEnum.SELECT.getType())
|
||||||
|
.setType(DeviceRecordTypeEnum.ASSIGNMENT.getType()).setTotal(deviceIdList.size())
|
||||||
|
.setTenantId(user.getDept().getDeptUserId()).setTenantName(user.getDept().getDeptUserName());
|
||||||
if (result > 0) {
|
if (result > 0) {
|
||||||
deviceRecord.setStatus(StatusEnum.SUCCESS.getStatus());
|
deviceRecord.setStatus(StatusEnum.SUCCESS.getStatus());
|
||||||
deviceRecord.setSuccessQuantity(deviceIdList.size());
|
deviceRecord.setSuccessQuantity(deviceIdList.size());
|
||||||
@ -1773,8 +1849,10 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
deviceRecord1.setOperateDeptId(user.getDeptId()).setTargetDeptId(deptId).setDeviceId(device.getDeviceId())
|
deviceRecord1.setOperateDeptId(user.getDeptId()).setTargetDeptId(deptId).setDeviceId(device.getDeviceId())
|
||||||
.setProductId(device.getProductId()).setSerialNumber(device.getSerialNumber())
|
.setProductId(device.getProductId()).setSerialNumber(device.getSerialNumber())
|
||||||
.setType(DeviceRecordTypeEnum.ASSIGNMENT_DETAIL.getType()).setParentId(deviceRecord.getId())
|
.setType(DeviceRecordTypeEnum.ASSIGNMENT_DETAIL.getType()).setParentId(deviceRecord.getId())
|
||||||
.setDistributeType(DeviceDistributeTypeEnum.SELECT.getType()).setTenantId(user.getDept().getDeptUserId()).setTenantName(user.getDept().getDeptUserName());
|
.setDistributeType(DeviceDistributeTypeEnum.SELECT.getType())
|
||||||
deviceRecord1.setStatus(insertRecordStatus > 0 ? StatusEnum.SUCCESS.getStatus() : StatusEnum.FAIL.getStatus());
|
.setTenantId(user.getDept().getDeptUserId()).setTenantName(user.getDept().getDeptUserName());
|
||||||
|
deviceRecord1
|
||||||
|
.setStatus(insertRecordStatus > 0 ? StatusEnum.SUCCESS.getStatus() : StatusEnum.FAIL.getStatus());
|
||||||
deviceRecord1.setCreateBy(user.getUserName());
|
deviceRecord1.setCreateBy(user.getUserName());
|
||||||
deviceRecordList.add(deviceRecord1);
|
deviceRecordList.add(deviceRecord1);
|
||||||
}
|
}
|
||||||
@ -1795,7 +1873,8 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
if (null == sysUser) {
|
if (null == sysUser) {
|
||||||
return AjaxResult.error("机构管理员不存在");
|
return AjaxResult.error("机构管理员不存在");
|
||||||
}
|
}
|
||||||
List<Long> deviceIdList = Arrays.stream(deviceIds.split(",")).map(d -> Long.parseLong(d.trim())).distinct().collect(Collectors.toList());
|
List<Long> deviceIdList = Arrays.stream(deviceIds.split(",")).map(d -> Long.parseLong(d.trim())).distinct()
|
||||||
|
.collect(Collectors.toList());
|
||||||
int result = deviceMapper.updateTenantIdByDeptIds(deptUserId, sysUser.getUserName(), deviceIdList);
|
int result = deviceMapper.updateTenantIdByDeptIds(deptUserId, sysUser.getUserName(), deviceIdList);
|
||||||
List<DeviceRecord> deviceRecordList = new ArrayList<>();
|
List<DeviceRecord> deviceRecordList = new ArrayList<>();
|
||||||
List<Device> deviceList = deviceMapper.selectDeviceListByDeviceIds(deviceIdList);
|
List<Device> deviceList = deviceMapper.selectDeviceListByDeviceIds(deviceIdList);
|
||||||
@ -1803,7 +1882,9 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
DeviceRecord deviceRecord1 = new DeviceRecord();
|
DeviceRecord deviceRecord1 = new DeviceRecord();
|
||||||
deviceRecord1.setOperateDeptId(deptId).setTargetDeptId(recoveryDeptId).setDeviceId(device.getDeviceId())
|
deviceRecord1.setOperateDeptId(deptId).setTargetDeptId(recoveryDeptId).setDeviceId(device.getDeviceId())
|
||||||
.setProductId(device.getProductId()).setSerialNumber(device.getSerialNumber())
|
.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.setStatus(result > 0 ? StatusEnum.SUCCESS.getStatus() : StatusEnum.FAIL.getStatus());
|
||||||
deviceRecord1.setCreateBy(loginUser.getUsername());
|
deviceRecord1.setCreateBy(loginUser.getUsername());
|
||||||
deviceRecordList.add(deviceRecord1);
|
deviceRecordList.add(deviceRecord1);
|
||||||
@ -1833,16 +1914,16 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
return deviceMapper.selectDeviceByChannelId(channelId);
|
return deviceMapper.selectDeviceByChannelId(channelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ThingsModelDTO> listThingsModel(Long deviceId) {
|
public List<ThingsModelDTO> listThingsModel(Long deviceId) {
|
||||||
DeviceShortOutput device = deviceMapper.selectDeviceRunningStatusByDeviceId(deviceId);
|
DeviceShortOutput device = deviceMapper.selectDeviceRunningStatusByDeviceId(deviceId);
|
||||||
if (null == device) {
|
if (null == device) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
//管理员可以下发,其他看指令控制
|
// 管理员可以下发,其他看指令控制
|
||||||
int canSend = getLoginUser().getUserId().equals(getLoginUser().getDeptUserId()) ? 1 : 0;
|
int canSend = getLoginUser().getUserId().equals(getLoginUser().getDeptUserId()) ? 1 : 0;
|
||||||
List<ThingsModelDTO> list = thingsModelService.getCacheAndHandleArrayByProductId(device.getProductId(), device.getSerialNumber());
|
List<ThingsModelDTO> list = thingsModelService.getCacheAndHandleArrayByProductId(device.getProductId(),
|
||||||
|
device.getSerialNumber());
|
||||||
for (ThingsModelDTO thingsModelDTO : list) {
|
for (ThingsModelDTO thingsModelDTO : list) {
|
||||||
thingsModelDTO.setProductId(device.getProductId());
|
thingsModelDTO.setProductId(device.getProductId());
|
||||||
thingsModelDTO.setSerialNumber(device.getSerialNumber());
|
thingsModelDTO.setSerialNumber(device.getSerialNumber());
|
||||||
@ -1853,7 +1934,8 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
subGateway.setGwDeviceId(deviceId);
|
subGateway.setGwDeviceId(deviceId);
|
||||||
List<SubDeviceListVO> subDeviceListVOList = subGatewayMapper.selectGatewayList(subGateway);
|
List<SubDeviceListVO> subDeviceListVOList = subGatewayMapper.selectGatewayList(subGateway);
|
||||||
for (SubDeviceListVO subDeviceListVO : subDeviceListVOList) {
|
for (SubDeviceListVO subDeviceListVO : subDeviceListVOList) {
|
||||||
List<ThingsModelDTO> subList = thingsModelService.getCacheAndHandleArrayByProductId(subDeviceListVO.getSubProductId(), subDeviceListVO.getSubDeviceNo());
|
List<ThingsModelDTO> subList = thingsModelService.getCacheAndHandleArrayByProductId(
|
||||||
|
subDeviceListVO.getSubProductId(), subDeviceListVO.getSubDeviceNo());
|
||||||
for (ThingsModelDTO thingsModelDTO : subList) {
|
for (ThingsModelDTO thingsModelDTO : subList) {
|
||||||
thingsModelDTO.setProductId(subDeviceListVO.getSubProductId());
|
thingsModelDTO.setProductId(subDeviceListVO.getSubProductId());
|
||||||
thingsModelDTO.setSerialNumber(subDeviceListVO.getSubDeviceNo());
|
thingsModelDTO.setSerialNumber(subDeviceListVO.getSubDeviceNo());
|
||||||
@ -1863,21 +1945,22 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
}
|
}
|
||||||
list.addAll(subList);
|
list.addAll(subList);
|
||||||
}
|
}
|
||||||
//指令控制
|
// 指令控制
|
||||||
jurisdictionThingsModel(list, deviceId);
|
jurisdictionThingsModel(list, deviceId);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void jurisdictionThingsModel(List<ThingsModelDTO> list, Long deviceId) {
|
private void jurisdictionThingsModel(List<ThingsModelDTO> list, Long deviceId) {
|
||||||
Long userId = SecurityUtils.getUserId();
|
Long userId = SecurityUtils.getUserId();
|
||||||
//查询是否有指令控制
|
// 查询是否有指令控制
|
||||||
List<OrderControl> orderControls = orderControlService.selectByUserId(userId, deviceId);
|
List<OrderControl> orderControls = orderControlService.selectByUserId(userId, deviceId);
|
||||||
if (CollectionUtils.isEmpty(orderControls)) return;
|
if (CollectionUtils.isEmpty(orderControls))
|
||||||
|
return;
|
||||||
List<Long> modelIdList = new ArrayList<>();
|
List<Long> modelIdList = new ArrayList<>();
|
||||||
for (OrderControl control : orderControls) {
|
for (OrderControl control : orderControls) {
|
||||||
String selectOrder = control.getSelectOrder();
|
String selectOrder = control.getSelectOrder();
|
||||||
String[] split = selectOrder.split(",");
|
String[] split = selectOrder.split(",");
|
||||||
//判断是否生效
|
// 判断是否生效
|
||||||
boolean just = just(control);
|
boolean just = just(control);
|
||||||
if (just) {
|
if (just) {
|
||||||
List<Long> ids = Arrays.stream(split).map(Long::valueOf).collect(Collectors.toList());
|
List<Long> ids = Arrays.stream(split).map(Long::valueOf).collect(Collectors.toList());
|
||||||
@ -1906,11 +1989,12 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateByOrder(Long userId, Long deviceId) {
|
public void updateByOrder(Long userId, Long deviceId) {
|
||||||
//处理指令权限问题 ,非管理员角色
|
// 处理指令权限问题 ,非管理员角色
|
||||||
List<OrderControl> controlList = orderControlService.selectByUserId(userId, deviceId);
|
List<OrderControl> 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)) {
|
if (!CollectionUtils.isEmpty(controlList)) {
|
||||||
//更新次数
|
// 更新次数
|
||||||
OrderControl control = controlList.get(0);
|
OrderControl control = controlList.get(0);
|
||||||
control.setCount(control.getCount() - 1);
|
control.setCount(control.getCount() - 1);
|
||||||
orderControlService.updateOrderControl(control);
|
orderControlService.updateOrderControl(control);
|
||||||
@ -1928,7 +2012,6 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
return deviceMapper.listDeviceGroupByGroupIds(groupIds);
|
return deviceMapper.listDeviceGroupByGroupIds(groupIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询产品下所有设备,返回设备编号
|
* 查询产品下所有设备,返回设备编号
|
||||||
*
|
*
|
||||||
@ -1940,7 +2023,4 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
return deviceMapper.selectSerialNumbersByProductId(productId);
|
return deviceMapper.selectSerialNumbersByProductId(productId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -125,6 +125,7 @@ public class ModbusConfigServiceImpl implements IModbusConfigService {
|
|||||||
this.updateModbusConfig(config);
|
this.updateModbusConfig(config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 将寄存器配置保存到redis缓存
|
||||||
modbusConfigCache.setModbusConfigCacheByProductId(productId);
|
modbusConfigCache.setModbusConfigCacheByProductId(productId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import com.fastbee.common.exception.ServiceException;
|
|||||||
import com.fastbee.common.utils.DateUtils;
|
import com.fastbee.common.utils.DateUtils;
|
||||||
import com.fastbee.common.utils.SecurityUtils;
|
import com.fastbee.common.utils.SecurityUtils;
|
||||||
import com.fastbee.common.utils.StringUtils;
|
import com.fastbee.common.utils.StringUtils;
|
||||||
import com.fastbee.iot.cache.ICalculatedThingsModelCache;
|
|
||||||
import com.fastbee.iot.cache.ITSLCache;
|
import com.fastbee.iot.cache.ITSLCache;
|
||||||
import com.fastbee.iot.domain.*;
|
import com.fastbee.iot.domain.*;
|
||||||
import com.fastbee.iot.mapper.*;
|
import com.fastbee.iot.mapper.*;
|
||||||
@ -68,8 +67,6 @@ public class ThingsModelServiceImpl implements IThingsModelService {
|
|||||||
private ITSLValueCache thingModelCache;
|
private ITSLValueCache thingModelCache;
|
||||||
@Resource
|
@Resource
|
||||||
private ITSLCache itslCache;
|
private ITSLCache itslCache;
|
||||||
@Resource
|
|
||||||
private ICalculatedThingsModelCache calculatedThingsModelCache;
|
|
||||||
|
|
||||||
private static List<SceneModelData> getSceneModelData(SceneModelDevice sceneModelDevice, List<ThingsModelDTO> thingsModelDTOList) {
|
private static List<SceneModelData> getSceneModelData(SceneModelDevice sceneModelDevice, List<ThingsModelDTO> thingsModelDTOList) {
|
||||||
List<SceneModelData> modelDataList = new ArrayList<>();
|
List<SceneModelData> modelDataList = new ArrayList<>();
|
||||||
@ -142,11 +139,16 @@ public class ThingsModelServiceImpl implements IThingsModelService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int insertThingsModel(ThingsModel thingsModel) {
|
public int insertThingsModel(ThingsModel thingsModel) {
|
||||||
|
// 去除计算公式中的空格
|
||||||
|
if (StringUtils.isNotEmpty(thingsModel.getFormula())) {
|
||||||
|
thingsModel.setFormula(thingsModel.getFormula().replaceAll("\\s+", ""));
|
||||||
|
}
|
||||||
ThingsModel input = new ThingsModel();
|
ThingsModel input = new ThingsModel();
|
||||||
input.setProductId(thingsModel.getProductId());
|
input.setProductId(thingsModel.getProductId());
|
||||||
|
input.setIsCalculated(0); // 只需要查产品的物模型即可
|
||||||
input.setLanguage(SecurityUtils.getLanguage());
|
input.setLanguage(SecurityUtils.getLanguage());
|
||||||
List<ThingsModel> list = thingsModelMapper.selectThingsModelList(input);
|
List<ThingsModel> 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) {
|
if (!isRepeat) {
|
||||||
SysUser user = getLoginUser().getUser();
|
SysUser user = getLoginUser().getUser();
|
||||||
if (null != user.getDeptId()) {
|
if (null != user.getDeptId()) {
|
||||||
@ -157,21 +159,19 @@ public class ThingsModelServiceImpl implements IThingsModelService {
|
|||||||
thingsModel.setTenantName(user.getUserName());
|
thingsModel.setTenantName(user.getUserName());
|
||||||
}
|
}
|
||||||
thingsModel.setCreateTime(DateUtils.getNowDate());
|
thingsModel.setCreateTime(DateUtils.getNowDate());
|
||||||
// 自动判断是否为纯计算物模型:如果公式包含{},则设置为1(纯计算)
|
// 插入物模型数据库
|
||||||
if (thingsModel.getIsCalculated() == null) {
|
|
||||||
thingsModel.setIsCalculated(determineIsCalculated(thingsModel.getFormula()));
|
|
||||||
}
|
|
||||||
int result = thingsModelMapper.insertThingsModel(thingsModel);
|
int result = thingsModelMapper.insertThingsModel(thingsModel);
|
||||||
// 更新redis缓存
|
// 更新redis缓存:IsCalculated=1为纯计算物模型
|
||||||
|
if (thingsModel.getIsCalculated() != null && thingsModel.getIsCalculated() == 1) {
|
||||||
|
itslCache.refreshDeviceCalculatedModelCache(thingsModel.getSerialNumber());
|
||||||
|
} else {
|
||||||
itslCache.setCacheThingsModelByProductId(thingsModel.getProductId());
|
itslCache.setCacheThingsModelByProductId(thingsModel.getProductId());
|
||||||
// 刷新纯计算物模型缓存
|
|
||||||
if (result > 0) {
|
|
||||||
calculatedThingsModelCache.refreshCalculatedCache(thingsModel.getProductId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result > 0) {
|
if (result > 0) {
|
||||||
// 更新场景管理变量
|
// 更新场景管理变量
|
||||||
List<SceneModelDevice> sceneModelDeviceList = sceneModelDeviceMapper.listDeviceByProductId(thingsModel.getProductId());
|
List<SceneModelDevice> sceneModelDeviceList = sceneModelDeviceMapper.listDeviceByProductId(thingsModel.getProductId());
|
||||||
if (org.apache.commons.collections4.CollectionUtils.isEmpty(sceneModelDeviceList)) {
|
if (CollectionUtils.isEmpty(sceneModelDeviceList)) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
List<ThingsModelDTO> thingsModelDTOList = this.changeObjectOrArray(thingsModel);
|
List<ThingsModelDTO> thingsModelDTOList = this.changeObjectOrArray(thingsModel);
|
||||||
@ -219,15 +219,15 @@ public class ThingsModelServiceImpl implements IThingsModelService {
|
|||||||
thingsModel.setIsChart(template.getIsChart());
|
thingsModel.setIsChart(template.getIsChart());
|
||||||
thingsModel.setIsHistory(template.getIsHistory());
|
thingsModel.setIsHistory(template.getIsHistory());
|
||||||
thingsModel.setModelOrder(template.getModelOrder());
|
thingsModel.setModelOrder(template.getModelOrder());
|
||||||
thingsModel.setIsCalculated(determineIsCalculated(thingsModel.getFormula()));
|
thingsModel.setIsCalculated(0);
|
||||||
Boolean isRepeat = dbList.stream().anyMatch(x -> x.getIdentifier().equals(thingsModel.getIdentifier()));
|
boolean isRepeat = dbList.stream().anyMatch(x -> x.getIdentifier().equals(thingsModel.getIdentifier()));
|
||||||
if (isRepeat) {
|
if (isRepeat) {
|
||||||
repeatCount = repeatCount + 1;
|
repeatCount = repeatCount + 1;
|
||||||
} else {
|
} else {
|
||||||
list.add(thingsModel);
|
list.add(thingsModel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (list.size() > 0) {
|
if (!list.isEmpty()) {
|
||||||
int result = thingsModelMapper.insertBatchThingsModel(list);
|
int result = thingsModelMapper.insertBatchThingsModel(list);
|
||||||
if (result > 0) {
|
if (result > 0) {
|
||||||
// 更新场景管理变量
|
// 更新场景管理变量
|
||||||
@ -245,8 +245,6 @@ public class ThingsModelServiceImpl implements IThingsModelService {
|
|||||||
}
|
}
|
||||||
//更新redis缓存
|
//更新redis缓存
|
||||||
itslCache.setCacheThingsModelByProductId(input.getProductId());
|
itslCache.setCacheThingsModelByProductId(input.getProductId());
|
||||||
// 刷新纯计算物模型缓存
|
|
||||||
calculatedThingsModelCache.refreshCalculatedCache(input.getProductId());
|
|
||||||
}
|
}
|
||||||
return repeatCount;
|
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());
|
Boolean isRepeat = list.stream().anyMatch(x -> x.getIdentifier().equals(thingsModel.getIdentifier()) && x.getModelId().longValue() != thingsModel.getModelId());
|
||||||
if (!isRepeat) {
|
if (!isRepeat) {
|
||||||
thingsModel.setUpdateTime(DateUtils.getNowDate());
|
thingsModel.setUpdateTime(DateUtils.getNowDate());
|
||||||
// 自动判断是否为纯计算物模型:如果公式包含{},则设置为1(纯计算)
|
|
||||||
if (thingsModel.getIsCalculated() == null) {
|
|
||||||
thingsModel.setIsCalculated(determineIsCalculated(thingsModel.getFormula()));
|
|
||||||
}
|
|
||||||
int result = thingsModelMapper.updateThingsModel(thingsModel);
|
int result = thingsModelMapper.updateThingsModel(thingsModel);
|
||||||
// 更新redis缓存
|
// 更新redis缓存
|
||||||
|
if (thingsModel.getIsCalculated() != null && thingsModel.getIsCalculated() == 1) {
|
||||||
|
itslCache.refreshDeviceCalculatedModelCache(thingsModel.getSerialNumber());
|
||||||
|
} else {
|
||||||
itslCache.setCacheThingsModelByProductId(thingsModel.getProductId());
|
itslCache.setCacheThingsModelByProductId(thingsModel.getProductId());
|
||||||
// 刷新纯计算物模型缓存
|
|
||||||
if (result > 0) {
|
|
||||||
calculatedThingsModelCache.refreshCalculatedCache(thingsModel.getProductId());
|
|
||||||
}
|
}
|
||||||
if (result > 0) {
|
if (result > 0) {
|
||||||
List<SceneModelData> sceneModelDataList = sceneModelDataMapper.selectSceneDeviceThingsModelList(thingsModel.getModelId());
|
List<SceneModelData> sceneModelDataList = sceneModelDataMapper.selectSceneDeviceThingsModelList(thingsModel.getModelId());
|
||||||
@ -320,12 +314,9 @@ public class ThingsModelServiceImpl implements IThingsModelService {
|
|||||||
if (result > 0) {
|
if (result > 0) {
|
||||||
sceneModelDataMapper.deleteThingsModelByDatasourceId(modelIds);
|
sceneModelDataMapper.deleteThingsModelByDatasourceId(modelIds);
|
||||||
}
|
}
|
||||||
// 更新redis缓存
|
// 更新redis缓存 产品和设备物模型都干掉
|
||||||
itslCache.setCacheThingsModelByProductId(thingsModel.getProductId());
|
itslCache.setCacheThingsModelByProductId(thingsModel.getProductId());
|
||||||
// 刷新纯计算物模型缓存
|
itslCache.refreshDeviceCalculatedModelCache(thingsModel.getSerialNumber());
|
||||||
if (result > 0 && thingsModel != null && thingsModel.getProductId() != null) {
|
|
||||||
calculatedThingsModelCache.refreshCalculatedCache(thingsModel.getProductId());
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -341,12 +332,11 @@ public class ThingsModelServiceImpl implements IThingsModelService {
|
|||||||
ThingsModel thingsModel = thingsModelMapper.selectThingsModelByModelId(modelId, SecurityUtils.getLanguage());
|
ThingsModel thingsModel = thingsModelMapper.selectThingsModelByModelId(modelId, SecurityUtils.getLanguage());
|
||||||
int result = thingsModelMapper.deleteThingsModelByModelId(modelId);
|
int result = thingsModelMapper.deleteThingsModelByModelId(modelId);
|
||||||
// 更新redis缓存
|
// 更新redis缓存
|
||||||
if (thingsModel != null && thingsModel.getProductId() != null) {
|
if (thingsModel != null) {
|
||||||
|
if (thingsModel.getProductId() != null) {
|
||||||
itslCache.setCacheThingsModelByProductId(thingsModel.getProductId());
|
itslCache.setCacheThingsModelByProductId(thingsModel.getProductId());
|
||||||
// 刷新纯计算物模型缓存
|
|
||||||
if (result > 0) {
|
|
||||||
calculatedThingsModelCache.refreshCalculatedCache(thingsModel.getProductId());
|
|
||||||
}
|
}
|
||||||
|
itslCache.refreshDeviceCalculatedModelCache(thingsModel.getSerialNumber());
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -354,8 +344,8 @@ public class ThingsModelServiceImpl implements IThingsModelService {
|
|||||||
/**
|
/**
|
||||||
* 获取单个物模型获取
|
* 获取单个物模型获取
|
||||||
*
|
*
|
||||||
* @param productId
|
* @param productId 产品ID
|
||||||
* @param identify
|
* @param identify 物模型标识符
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@ -695,6 +685,7 @@ public class ThingsModelServiceImpl implements IThingsModelService {
|
|||||||
if (null == productId) {
|
if (null == productId) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
// 1、获取产品物模型
|
||||||
Map<String, ThingsModelValueItem> map = itslCache.getCacheThMapByProductId(productId);
|
Map<String, ThingsModelValueItem> map = itslCache.getCacheThMapByProductId(productId);
|
||||||
List<ThingsModelDTO> thingsModelDTOList = new ArrayList<>();
|
List<ThingsModelDTO> thingsModelDTOList = new ArrayList<>();
|
||||||
for (Map.Entry<String, ThingsModelValueItem> entry : map.entrySet()) {
|
for (Map.Entry<String, ThingsModelValueItem> entry : map.entrySet()) {
|
||||||
@ -702,6 +693,15 @@ public class ThingsModelServiceImpl implements IThingsModelService {
|
|||||||
thingsModelDTOList.addAll(this.changeObjectOrArray(thingsModel));
|
thingsModelDTOList.addAll(this.changeObjectOrArray(thingsModel));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. 获取设备级计算物模型并合并
|
||||||
|
if (StringUtils.isNotEmpty(serialNumber)) {
|
||||||
|
Map<String, ThingsModelValueItem> deviceCalculatedMap = itslCache.getDeviceCalculatedModelMap(serialNumber);
|
||||||
|
for (Map.Entry<String, ThingsModelValueItem> entry : deviceCalculatedMap.entrySet()) {
|
||||||
|
ThingsModel thingsModel = this.propertyDtoChangeThingsModel(entry.getValue());
|
||||||
|
thingsModelDTOList.addAll(this.changeObjectOrArray(thingsModel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
thingsModelDTOList.sort(Comparator.comparing(ThingsModelDTO::getModelOrder));
|
thingsModelDTOList.sort(Comparator.comparing(ThingsModelDTO::getModelOrder));
|
||||||
if (StringUtils.isEmpty(serialNumber)) {
|
if (StringUtils.isEmpty(serialNumber)) {
|
||||||
return thingsModelDTOList;
|
return thingsModelDTOList;
|
||||||
|
|||||||
@ -163,15 +163,71 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="selectDeviceVo">
|
<sql id="selectDeviceVo">
|
||||||
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
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<sql id="selectDeviceShortVo">
|
<sql id="selectDeviceShortVo">
|
||||||
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
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<sql id="selectWebhookDeviceVo">
|
<sql id="selectWebhookDeviceVo">
|
||||||
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
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<select id="selectDeviceList" parameterType="com.fastbee.iot.domain.Device" resultMap="DeviceResult">
|
<select id="selectDeviceList" parameterType="com.fastbee.iot.domain.Device" resultMap="DeviceResult">
|
||||||
|
|||||||
@ -10,6 +10,8 @@
|
|||||||
<result property="modelName_en_US" column="model_name_en_us"/>
|
<result property="modelName_en_US" column="model_name_en_us"/>
|
||||||
<result property="productId" column="product_id"/>
|
<result property="productId" column="product_id"/>
|
||||||
<result property="productName" column="product_name"/>
|
<result property="productName" column="product_name"/>
|
||||||
|
<result property="deviceId" column="device_id"/>
|
||||||
|
<result property="serialNumber" column="serial_number"/>
|
||||||
<result property="tenantId" column="tenant_id"/>
|
<result property="tenantId" column="tenant_id"/>
|
||||||
<result property="tenantName" column="tenant_name"/>
|
<result property="tenantName" column="tenant_name"/>
|
||||||
<result property="identifier" column="identifier"/>
|
<result property="identifier" column="identifier"/>
|
||||||
@ -52,6 +54,8 @@
|
|||||||
model_name,
|
model_name,
|
||||||
product_id,
|
product_id,
|
||||||
product_name,
|
product_name,
|
||||||
|
device_id,
|
||||||
|
serial_number,
|
||||||
tenant_id,
|
tenant_id,
|
||||||
tenant_name,
|
tenant_name,
|
||||||
identifier,
|
identifier,
|
||||||
@ -79,72 +83,134 @@
|
|||||||
<select id="selectThingsModelList" parameterType="com.fastbee.iot.domain.ThingsModel" resultMap="ThingsModelResult">
|
<select id="selectThingsModelList" parameterType="com.fastbee.iot.domain.ThingsModel" resultMap="ThingsModelResult">
|
||||||
select m.model_id,
|
select m.model_id,
|
||||||
case
|
case
|
||||||
when #{language} = 'zh-CN' then m.model_name
|
when #{language}
|
||||||
when #{language} = 'en-US' then t.en_us
|
= 'zh-CN' THEN m.model_name WHEN #{language}
|
||||||
else m.model_name
|
= 'en-US' THEN t.en_us ELSE m.model_name END AS model_name,
|
||||||
end as model_name,
|
m.model_name AS model_name_zh_cn,
|
||||||
m.model_name as model_name_zh_cn, t.en_us as model_name_en_us,
|
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.product_id,
|
||||||
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.product_name,
|
||||||
m.create_time, m.update_by, m.update_time, m.remark, m.is_readonly, m.model_order
|
m.device_id,
|
||||||
from iot_things_model m
|
m.serial_number,
|
||||||
left join iot_things_model_translate t on m.model_id = t.id
|
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
|
||||||
<where>
|
<where>
|
||||||
<if test="productId != null">
|
<if test="productId != null">
|
||||||
and m.product_id = #{productId}
|
AND m.product_id = #{productId}
|
||||||
|
</if>
|
||||||
|
<if test="serialNumber != null">
|
||||||
|
AND m.serial_number = #{serialNumber}
|
||||||
|
</if>
|
||||||
|
<if test="deviceId != null">
|
||||||
|
AND m.device_id = #{deviceId}
|
||||||
</if>
|
</if>
|
||||||
<if test="type!=null">
|
<if test="type!=null">
|
||||||
and type = #{type}
|
AND type = #{type}
|
||||||
</if>
|
</if>
|
||||||
<if test="isChart != null ">
|
<if test="isChart != null ">
|
||||||
and is_chart = #{isChart}
|
AND is_chart = #{isChart}
|
||||||
</if>
|
</if>
|
||||||
<if test="isHistory != null ">
|
<if test="isHistory != null ">
|
||||||
and is_history = #{isHistory}
|
AND is_history = #{isHistory}
|
||||||
</if>
|
</if>
|
||||||
<if test="isMonitor != null ">
|
<if test="isMonitor != null ">
|
||||||
and is_monitor = #{isMonitor}
|
AND is_monitor = #{isMonitor}
|
||||||
</if>
|
</if>
|
||||||
<if test="isReadonly != null ">
|
<if test="isReadonly != null ">
|
||||||
and is_readonly = #{isReadonly}
|
AND is_readonly = #{isReadonly}
|
||||||
|
</if>
|
||||||
|
<if test="isCalculated != null ">
|
||||||
|
AND is_calculated = #{isCalculated}
|
||||||
</if>
|
</if>
|
||||||
<if test="modelIdList != null ">
|
<if test="modelIdList != null ">
|
||||||
model_id in
|
model_id IN
|
||||||
<foreach collection="modelIdList" item="item" separator="," open="(" close=")">
|
<foreach collection="modelIdList" item="item" separator="," open="(" close=")">
|
||||||
#{item}
|
#{item}
|
||||||
</foreach>
|
</foreach>
|
||||||
</if>
|
</if>
|
||||||
</where>
|
</where>
|
||||||
order by model_order desc,create_time desc
|
ORDER BY
|
||||||
|
model_order DESC,
|
||||||
|
create_time DESC
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectThingsModelPermList" resultMap="ThingsModelPermResult">
|
<select id="selectThingsModelPermList" resultMap="ThingsModelPermResult">
|
||||||
select case
|
select case
|
||||||
when #{language} = 'zh-CN' then m.model_name
|
when #{language}
|
||||||
when #{language} = 'en-US' then t.en_us
|
= 'zh-CN' THEN m.model_name WHEN #{language}
|
||||||
else m.model_name
|
= 'en-US' THEN t.en_us ELSE m.model_name END AS model_name,
|
||||||
end as model_name,
|
m.identifier,
|
||||||
m.identifier, m.is_share_perm, m.remark
|
m.is_share_perm,
|
||||||
from iot_things_model m
|
m.remark
|
||||||
left join iot_things_model_translate t on m.model_id = t.id
|
FROM
|
||||||
where m.product_id=#{productId} and is_share_perm=1
|
iot_things_model m
|
||||||
order by model_order desc,create_time desc
|
LEFT JOIN iot_things_model_translate t ON m.model_id = t.id
|
||||||
|
WHERE
|
||||||
|
m.product_id = #{productId}
|
||||||
|
AND is_share_perm = 1
|
||||||
|
ORDER BY
|
||||||
|
model_order DESC,
|
||||||
|
create_time DESC
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|
||||||
<select id="selectThingsModelListByProductIds" parameterType="String" resultMap="ThingsModelResult">
|
<select id="selectThingsModelListByProductIds" parameterType="String" resultMap="ThingsModelResult">
|
||||||
select m.model_id,
|
select m.model_id,
|
||||||
case
|
case
|
||||||
when #{language} = 'zh-CN' then m.model_name
|
when #{language}
|
||||||
when #{language} = 'en-US' then t.en_us
|
= 'zh-CN' THEN m.model_name WHEN #{language}
|
||||||
else m.model_name
|
= 'en-US' THEN t.en_us ELSE m.model_name END AS model_name,
|
||||||
end as model_name,
|
m.product_id,
|
||||||
m.product_id, m.product_name, m.tenant_id, m.tenant_name, m.identifier, m.type, m.datatype, m.formula,
|
m.product_name,
|
||||||
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.tenant_id,
|
||||||
m.create_time, m.update_by, m.update_time, m.remark, m.is_readonly, m.model_order
|
m.tenant_name,
|
||||||
from iot_things_model m
|
m.identifier,
|
||||||
left join iot_things_model_translate t on m.model_id = t.id
|
m.type,
|
||||||
where is_chart=1 and m.product_id in
|
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
|
||||||
|
WHERE
|
||||||
|
is_chart = 1
|
||||||
|
AND m.product_id IN
|
||||||
<foreach item="productId" collection="array" open="(" separator="," close=")">
|
<foreach item="productId" collection="array" open="(" separator="," close=")">
|
||||||
#{productId}
|
#{productId}
|
||||||
</foreach>
|
</foreach>
|
||||||
@ -153,43 +219,85 @@
|
|||||||
<select id="selectThingsModelByModelId" resultMap="ThingsModelResult">
|
<select id="selectThingsModelByModelId" resultMap="ThingsModelResult">
|
||||||
select m.model_id,
|
select m.model_id,
|
||||||
case
|
case
|
||||||
when #{language} = 'zh-CN' then m.model_name
|
when #{language}
|
||||||
when #{language} = 'en-US' then t.en_us
|
= 'zh-CN' THEN m.model_name WHEN #{language}
|
||||||
else m.model_name
|
= 'en-US' THEN t.en_us ELSE m.model_name END AS model_name,
|
||||||
end as model_name,
|
m.product_id,
|
||||||
m.product_id, m.product_name, m.tenant_id, m.tenant_name, m.identifier, m.type, m.datatype, m.formula,
|
m.product_name,
|
||||||
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.serial_number,
|
||||||
m.create_time, m.update_by, m.update_time, m.remark, m.is_readonly, m.model_order
|
m.tenant_id,
|
||||||
from iot_things_model m
|
m.tenant_name,
|
||||||
left join iot_things_model_translate t on m.model_id = t.id
|
m.identifier,
|
||||||
where model_id = #{modelId}
|
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}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectSingleThingsModel" parameterType="com.fastbee.iot.domain.ThingsModel" resultMap="ThingsModelResult">
|
<select id="selectSingleThingsModel" parameterType="com.fastbee.iot.domain.ThingsModel" resultMap="ThingsModelResult">
|
||||||
select m.model_id,
|
select m.model_id,
|
||||||
case
|
case
|
||||||
when #{language} = 'zh-CN' then m.model_name
|
when #{language}
|
||||||
when #{language} = 'en-US' then t.en_us
|
= 'zh-CN' THEN m.model_name WHEN #{language}
|
||||||
else m.model_name
|
= 'en-US' THEN t.en_us ELSE m.model_name END AS model_name,
|
||||||
end as model_name,
|
m.product_id,
|
||||||
m.product_id, m.product_name, m.tenant_id, m.tenant_name, m.identifier, m.type, m.datatype, m.formula,
|
m.product_name,
|
||||||
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.tenant_id,
|
||||||
m.create_time, m.update_by, m.update_time, m.remark, m.is_readonly, m.model_order
|
m.tenant_name,
|
||||||
from iot_things_model m
|
m.identifier,
|
||||||
left join iot_things_model_translate t on m.model_id = t.id
|
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
|
||||||
<where>
|
<where>
|
||||||
<if test="productId != null">
|
<if test="productId != null">
|
||||||
and m.product_id = #{productId}
|
AND m.product_id = #{productId}
|
||||||
</if>
|
</if>
|
||||||
<if test="identifier !=null and identifier != ''">
|
<if test="identifier !=null and identifier != ''">
|
||||||
and identifier = #{identifier}
|
AND identifier = #{identifier}
|
||||||
</if>
|
</if>
|
||||||
</where>
|
</where>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<insert id="insertThingsModel" parameterType="com.fastbee.iot.domain.ThingsModel" useGeneratedKeys="true"
|
<insert id="insertThingsModel" parameterType="com.fastbee.iot.domain.ThingsModel" useGeneratedKeys="true"
|
||||||
keyProperty="modelId">
|
keyProperty="modelId">
|
||||||
insert into iot_things_model
|
INSERT INTO
|
||||||
|
iot_things_model
|
||||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
<if test="modelName != null and modelName != ''">
|
<if test="modelName != null and modelName != ''">
|
||||||
model_name,
|
model_name,
|
||||||
@ -200,6 +308,12 @@
|
|||||||
<if test="productName != null and productName != ''">
|
<if test="productName != null and productName != ''">
|
||||||
product_name,
|
product_name,
|
||||||
</if>
|
</if>
|
||||||
|
<if test="deviceId != null">
|
||||||
|
device_id,
|
||||||
|
</if>
|
||||||
|
<if test="serialNumber != null and serialNumber != ''">
|
||||||
|
serial_number,
|
||||||
|
</if>
|
||||||
<if test="tenantId != null">
|
<if test="tenantId != null">
|
||||||
tenant_id,
|
tenant_id,
|
||||||
</if>
|
</if>
|
||||||
@ -274,6 +388,12 @@
|
|||||||
<if test="productName != null and productName != ''">
|
<if test="productName != null and productName != ''">
|
||||||
#{productName},
|
#{productName},
|
||||||
</if>
|
</if>
|
||||||
|
<if test="deviceId != null">
|
||||||
|
#{deviceId},
|
||||||
|
</if>
|
||||||
|
<if test="serialNumber != null and serialNumber != ''">
|
||||||
|
#{serialNumber},
|
||||||
|
</if>
|
||||||
<if test="tenantId != null">
|
<if test="tenantId != null">
|
||||||
#{tenantId},
|
#{tenantId},
|
||||||
</if>
|
</if>
|
||||||
@ -342,7 +462,8 @@
|
|||||||
|
|
||||||
<insert id="insertBatchThingsModel" parameterType="com.fastbee.iot.domain.ThingsModel" useGeneratedKeys="true"
|
<insert id="insertBatchThingsModel" parameterType="com.fastbee.iot.domain.ThingsModel" useGeneratedKeys="true"
|
||||||
keyProperty="modelId">
|
keyProperty="modelId">
|
||||||
INSERT INTO iot_things_model (
|
INSERT INTO
|
||||||
|
iot_things_model (
|
||||||
model_name,
|
model_name,
|
||||||
product_id,
|
product_id,
|
||||||
product_name,
|
product_name,
|
||||||
@ -365,18 +486,31 @@
|
|||||||
)
|
)
|
||||||
VALUES
|
VALUES
|
||||||
<foreach item="model" collection="list" separator=",">
|
<foreach item="model" collection="list" separator=",">
|
||||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
<trim prefix="(" suffix=")" suffixOverrides=",">#{model.modelName},
|
||||||
#{model.modelName},#{model.productId},#{model.productName},#{model.tenantId},
|
#{model.productId},
|
||||||
#{model.tenantName},#{model.identifier},#{model.type},#{model.datatype},
|
#{model.productName},
|
||||||
#{model.specs},#{model.isChart},#{model.isSharePerm},#{model.isHistory},
|
#{model.tenantId},
|
||||||
#{model.isMonitor},#{model.isApp},#{model.isReadonly},#{model.createBy},#{model.createTime},
|
#{model.tenantName},
|
||||||
#{model.formula},#{model.isCalculated}
|
#{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}
|
||||||
</trim>
|
</trim>
|
||||||
</foreach>
|
</foreach>
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
<update id="updateThingsModel" parameterType="com.fastbee.iot.domain.ThingsModel">
|
<update id="updateThingsModel" parameterType="com.fastbee.iot.domain.ThingsModel">
|
||||||
update iot_things_model
|
UPDATE iot_things_model
|
||||||
<trim prefix="SET" suffixOverrides=",">
|
<trim prefix="SET" suffixOverrides=",">
|
||||||
<if test="modelName != null and modelName != ''">
|
<if test="modelName != null and modelName != ''">
|
||||||
model_name = #{modelName},
|
model_name = #{modelName},
|
||||||
@ -387,6 +521,12 @@
|
|||||||
<if test="productName != null and productName != ''">
|
<if test="productName != null and productName != ''">
|
||||||
product_name = #{productName},
|
product_name = #{productName},
|
||||||
</if>
|
</if>
|
||||||
|
<if test="deviceId != null">
|
||||||
|
device_id = #{deviceId},
|
||||||
|
</if>
|
||||||
|
<if test="serialNumber != null and serialNumber != ''">
|
||||||
|
serial_number = #{serialNumber},
|
||||||
|
</if>
|
||||||
<if test="tenantId != null">
|
<if test="tenantId != null">
|
||||||
tenant_id = #{tenantId},
|
tenant_id = #{tenantId},
|
||||||
</if>
|
</if>
|
||||||
@ -451,17 +591,20 @@
|
|||||||
model_order = #{modelOrder},
|
model_order = #{modelOrder},
|
||||||
</if>
|
</if>
|
||||||
</trim>
|
</trim>
|
||||||
where model_id = #{modelId}
|
WHERE
|
||||||
|
model_id = #{modelId}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
<delete id="deleteThingsModelByModelId" parameterType="Long">
|
<delete id="deleteThingsModelByModelId" parameterType="Long">
|
||||||
delete
|
DELETE FROM iot_things_model
|
||||||
from iot_things_model
|
WHERE
|
||||||
where model_id = #{modelId}
|
model_id = #{modelId}
|
||||||
</delete>
|
</delete>
|
||||||
|
|
||||||
<delete id="deleteThingsModelByModelIds" parameterType="String">
|
<delete id="deleteThingsModelByModelIds" parameterType="String">
|
||||||
delete from iot_things_model where model_id in
|
DELETE FROM iot_things_model
|
||||||
|
WHERE
|
||||||
|
model_id IN
|
||||||
<foreach item="modelId" collection="array" open="(" separator="," close=")">
|
<foreach item="modelId" collection="array" open="(" separator="," close=")">
|
||||||
#{modelId}
|
#{modelId}
|
||||||
</foreach>
|
</foreach>
|
||||||
@ -475,16 +618,17 @@
|
|||||||
m.is_history as isHistory,
|
m.is_history as isHistory,
|
||||||
m.specs as dataType,
|
m.specs as dataType,
|
||||||
case
|
case
|
||||||
when #{language} = 'zh-CN' then m.model_name
|
when #{language}
|
||||||
when #{language} = 'en-US' then t.en_us
|
= 'zh-CN' THEN m.model_name WHEN #{language}
|
||||||
else m.model_name
|
= 'en-US' THEN t.en_us ELSE m.model_name END AS name,
|
||||||
end as name,
|
m.type AS type,
|
||||||
m.type as type,
|
m.formula AS formula,
|
||||||
m.formula as formula,
|
FROM
|
||||||
from iot_things_model m
|
iot_things_model m
|
||||||
left join iot_things_model_translate t on m.model_id = t.id
|
LEFT JOIN iot_things_model_translate t ON m.model_id = t.id
|
||||||
where m.product_id = #{productId,jdbcType=BIGINT}
|
WHERE
|
||||||
and m.identifier in
|
m.product_id = #{productId,jdbcType=BIGINT}
|
||||||
|
AND m.identifier IN
|
||||||
<foreach collection="ids" item="item" open="(" separator="," close=")">
|
<foreach collection="ids" item="item" open="(" separator="," close=")">
|
||||||
#{item}
|
#{item}
|
||||||
</foreach>
|
</foreach>
|
||||||
@ -492,43 +636,50 @@
|
|||||||
|
|
||||||
|
|
||||||
<delete id="deleteThingsModelByProductId" parameterType="long">
|
<delete id="deleteThingsModelByProductId" parameterType="long">
|
||||||
delete from iot_things_model where product_id = #{productId}
|
DELETE FROM iot_things_model
|
||||||
|
WHERE
|
||||||
|
product_id = #{productId}
|
||||||
</delete>
|
</delete>
|
||||||
|
|
||||||
<select id="listSimByProductIds" resultType="com.fastbee.iot.model.ThingsModelSimVO">
|
<select id="listSimByProductIds" resultType="com.fastbee.iot.model.ThingsModelSimVO">
|
||||||
select m.product_id, m.identifier,
|
select m.product_id, m.identifier,
|
||||||
case
|
case
|
||||||
when #{language} = 'zh-CN' then m.model_name
|
when #{language}
|
||||||
when #{language} = 'en-US' then t.en_us
|
= 'zh-CN' THEN m.model_name WHEN #{language}
|
||||||
else m.model_name
|
= 'en-US' THEN t.en_us ELSE m.model_name END AS model_name,
|
||||||
end as model_name,
|
m.type AS thingsModelType,
|
||||||
m.type as thingsModelType,
|
|
||||||
m.datatype
|
m.datatype
|
||||||
from iot_things_model m
|
FROM
|
||||||
left join iot_things_model_translate t on m.model_id = t.id
|
iot_things_model m
|
||||||
where m.product_id in
|
LEFT JOIN iot_things_model_translate t ON m.model_id = t.id
|
||||||
|
WHERE
|
||||||
|
m.product_id IN
|
||||||
<foreach collection="productIdList" item="productId" open="(" separator="," close=")">
|
<foreach collection="productIdList" item="productId" open="(" separator="," close=")">
|
||||||
#{productId}
|
#{productId}
|
||||||
</foreach>
|
</foreach>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="getSpecsByProductIdAndIdentifier" resultType="java.lang.String">
|
<select id="getSpecsByProductIdAndIdentifier" resultType="java.lang.String">
|
||||||
select specs
|
SELECT
|
||||||
from iot_things_model
|
specs
|
||||||
where product_id = #{productId}
|
FROM
|
||||||
and identifier = #{identifier}
|
iot_things_model
|
||||||
|
WHERE
|
||||||
|
product_id = #{productId}
|
||||||
|
AND identifier = #{identifier}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="listSceneModelDataByModelIds" resultType="com.fastbee.iot.domain.ThingsModel">
|
<select id="listSceneModelDataByModelIds" resultType="com.fastbee.iot.domain.ThingsModel">
|
||||||
select m.model_id, m.identifier,
|
select m.model_id, m.identifier,
|
||||||
case
|
case
|
||||||
when #{language} = 'zh-CN' then m.model_name
|
when #{language}
|
||||||
when #{language} = 'en-US' then t.en_us
|
= 'zh-CN' THEN m.model_name WHEN #{language}
|
||||||
else m.model_name
|
= 'en-US' THEN t.en_us ELSE m.model_name END AS model_name,
|
||||||
end as model_name,
|
FROM
|
||||||
from iot_things_model m
|
iot_things_model m
|
||||||
left join iot_things_model_translate t on m.model_id = t.id
|
LEFT JOIN iot_things_model_translate t ON m.model_id = t.id
|
||||||
where m.model_id in
|
WHERE
|
||||||
|
m.model_id IN
|
||||||
<foreach collection="modelIdList" item="modelId" open="(" separator="," close=")">
|
<foreach collection="modelIdList" item="modelId" open="(" separator="," close=")">
|
||||||
#{modelId}
|
#{modelId}
|
||||||
</foreach>
|
</foreach>
|
||||||
@ -538,40 +689,50 @@
|
|||||||
<select id="getModbusConfigUnSelectThingsModel" resultMap="ThingsModelAndModbusResult">
|
<select id="getModbusConfigUnSelectThingsModel" resultMap="ThingsModelAndModbusResult">
|
||||||
select m.model_id, m.identifier,
|
select m.model_id, m.identifier,
|
||||||
case
|
case
|
||||||
when #{language} = 'zh-CN' then m.model_name
|
when #{language}
|
||||||
when #{language} = 'en-US' then t.en_us
|
= 'zh-CN' THEN m.model_name WHEN #{language}
|
||||||
|
= 'en-US' then t.en_us
|
||||||
else m.model_name
|
else m.model_name
|
||||||
end as model_name,
|
end as model_name,
|
||||||
m.datatype,
|
m.datatype,
|
||||||
case
|
case
|
||||||
when (select count(1) from iot_modbus_config c where c.product_id = #{productId} and c.identifier = m.identifier) > 0 then 0
|
when (select count(1) from iot_modbus_config c where c.product_id = #{productId}
|
||||||
|
and c.identifier = m.identifier) > 0 then 0
|
||||||
else 1
|
else 1
|
||||||
end as is_select
|
end as is_select
|
||||||
from iot_things_model m
|
from iot_things_model m
|
||||||
left join iot_things_model_translate t on m.model_id = t.id
|
left join iot_things_model_translate t on m.model_id = t.id
|
||||||
where m.product_id = #{productId}
|
where m.product_id = #{productId}
|
||||||
|
AND m.del_flag = 0
|
||||||
|
AND m.is_calculated = 0
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectThingsModelListByModelIds" resultType="com.fastbee.iot.domain.ThingsModel">
|
<select id="selectThingsModelListByModelIds" resultType="com.fastbee.iot.domain.ThingsModel">
|
||||||
select model_id, type
|
SELECT
|
||||||
from iot_things_model where model_id in
|
model_id,
|
||||||
|
type
|
||||||
|
FROM
|
||||||
|
iot_things_model
|
||||||
|
WHERE
|
||||||
|
model_id IN
|
||||||
<foreach item="modelId" collection="modelIdList" open="(" separator="," close=")">
|
<foreach item="modelId" collection="modelIdList" open="(" separator="," close=")">
|
||||||
#{modelId}
|
#{modelId}
|
||||||
</foreach>
|
</foreach>
|
||||||
and del_flag = 0
|
AND del_flag = 0
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectThingsModelBySerialNumber" resultMap="ThingsModelResult">
|
<select id="selectThingsModelBySerialNumber" resultMap="ThingsModelResult">
|
||||||
select m.model_id, m.identifier,
|
select m.model_id, m.identifier,
|
||||||
case
|
case
|
||||||
when #{language} = 'zh-CN' then m.model_name
|
when #{language}
|
||||||
when #{language} = 'en-US' then t.en_us
|
= 'zh-CN' THEN m.model_name WHEN #{language}
|
||||||
else m.model_name
|
= 'en-US' THEN t.en_us ELSE m.model_name END AS model_name
|
||||||
end as model_name
|
FROM
|
||||||
from iot_things_model m
|
iot_things_model m
|
||||||
inner join iot_device d on m.product_id = d.product_id
|
INNER JOIN iot_device d ON m.product_id = d.product_id
|
||||||
left join iot_things_model_translate t on m.model_id = t.id
|
LEFT JOIN iot_things_model_translate t ON m.model_id = t.id
|
||||||
where d.device_id = #{deviceId}
|
WHERE
|
||||||
and m.is_readonly = 0
|
d.device_id = #{deviceId}
|
||||||
|
AND m.is_readonly = 0
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@ -33,3 +33,14 @@ WHERE `formula` IS NOT NULL
|
|||||||
AND `formula` != ''
|
AND `formula` != ''
|
||||||
AND `formula` LIKE '%{%}%'
|
AND `formula` LIKE '%{%}%'
|
||||||
AND `del_flag` = '0';
|
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`);
|
||||||
|
|||||||
@ -109,6 +109,7 @@
|
|||||||
"device.device-edit.148398-80": "Alert user",
|
"device.device-edit.148398-80": "Alert user",
|
||||||
"device.device-edit.148398-81": "equipment alarm ",
|
"device.device-edit.148398-81": "equipment alarm ",
|
||||||
"device.device-edit.148398-82": "Voice intercom",
|
"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-0": "Please Select A Device Slave:",
|
||||||
"device.device-functionlog.399522-1": "Please Select A Device Slave",
|
"device.device-functionlog.399522-1": "Please Select A Device Slave",
|
||||||
"device.device-functionlog.399522-2": "Slave Address:$",
|
"device.device-functionlog.399522-2": "Slave Address:$",
|
||||||
|
|||||||
@ -298,7 +298,6 @@
|
|||||||
"product.product-things-model.142341-52": "Please enter the step size, for example: 1",
|
"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-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": "%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-54-2": "Supported operators: +, -, *, /, % (modulo), ^ (power), parentheses ().",
|
||||||
"product.product-things-model.142341-55": "For example:",
|
"product.product-things-model.142341-55": "For example:",
|
||||||
"product.product-things-model.142341-56": "Add: %s+10",
|
"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-59": "Divide: %s/10",
|
||||||
"product.product-things-model.142341-60": "Divide (retain decimals): %s%10.00",
|
"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": "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-62": "Control Formula",
|
||||||
"product.product-things-model.142341-63": "Boolean value",
|
"product.product-things-model.142341-63": "Boolean value",
|
||||||
"product.product-things-model.142341-64": "For example: Close",
|
"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-67": "Tips",
|
||||||
"product.product-modbus-task.894593-68": "determine",
|
"product.product-modbus-task.894593-68": "determine",
|
||||||
"product.product-modbus-task.894593-69": "cancel",
|
"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"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -109,6 +109,7 @@
|
|||||||
"device.device-edit.148398-80": "告警用户",
|
"device.device-edit.148398-80": "告警用户",
|
||||||
"device.device-edit.148398-81": "设备告警",
|
"device.device-edit.148398-81": "设备告警",
|
||||||
"device.device-edit.148398-82": "语音对讲",
|
"device.device-edit.148398-82": "语音对讲",
|
||||||
|
"device.device-edit.148398-83": "计算公式",
|
||||||
"device.device-functionlog.399522-0": "请选择设备从机:",
|
"device.device-functionlog.399522-0": "请选择设备从机:",
|
||||||
"device.device-functionlog.399522-1": "请选择设备从机",
|
"device.device-functionlog.399522-1": "请选择设备从机",
|
||||||
"device.device-functionlog.399522-2": "从机地址:$",
|
"device.device-functionlog.399522-2": "从机地址:$",
|
||||||
|
|||||||
@ -296,9 +296,8 @@
|
|||||||
"product.product-things-model.142341-50": "请输入单位,例如:℃",
|
"product.product-things-model.142341-50": "请输入单位,例如:℃",
|
||||||
"product.product-things-model.142341-51": "步长",
|
"product.product-things-model.142341-51": "步长",
|
||||||
"product.product-things-model.142341-52": "请输入步长,例如:1",
|
"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": "公式中的%s为占位符,表示当前物模型的值。",
|
||||||
"product.product-things-model.142341-54-1": "使用{标识符}可以引用其他物模型的值,支持多个物模型参与计算。",
|
|
||||||
"product.product-things-model.142341-54-2": "支持运算符:+、-、*、/、%、^(幂运算)、括号()。",
|
"product.product-things-model.142341-54-2": "支持运算符:+、-、*、/、%、^(幂运算)、括号()。",
|
||||||
"product.product-things-model.142341-55": "如:",
|
"product.product-things-model.142341-55": "如:",
|
||||||
"product.product-things-model.142341-56": "加:%s+10",
|
"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-59": "除:%s/10",
|
||||||
"product.product-things-model.142341-60": "除(保留小数):%s%10.00",
|
"product.product-things-model.142341-60": "除(保留小数):%s%10.00",
|
||||||
"product.product-things-model.142341-61": "保留小数",
|
"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-62": "控制公式",
|
||||||
"product.product-things-model.142341-63": "布尔值",
|
"product.product-things-model.142341-63": "布尔值",
|
||||||
"product.product-things-model.142341-64": "例如:关闭",
|
"product.product-things-model.142341-64": "例如:关闭",
|
||||||
@ -551,5 +546,9 @@
|
|||||||
"product.product-modbus-task.894593-67": "提示",
|
"product.product-modbus-task.894593-67": "提示",
|
||||||
"product.product-modbus-task.894593-68": "确定",
|
"product.product-modbus-task.894593-68": "确定",
|
||||||
"product.product-modbus-task.894593-69": "取消",
|
"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": "新增计算模型"
|
||||||
}
|
}
|
||||||
@ -135,6 +135,13 @@
|
|||||||
<!-- <real-time-status ref="realTimeStatus" :device="form" @statusEvent="getDeviceStatusData($event)" /> -->
|
<!-- <real-time-status ref="realTimeStatus" :device="form" @statusEvent="getDeviceStatusData($event)" /> -->
|
||||||
<running-status ref="runningStatus" :device="form" @statusEvent="getDeviceStatusData($event)" />
|
<running-status ref="runningStatus" :device="form" @statusEvent="getDeviceStatusData($event)" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
|
<!-- 设备级别物模型 -->
|
||||||
|
<el-tab-pane name="calculatedModel" :disabled="form.deviceId == 0" v-if="form.deviceType !== 3" lazy>
|
||||||
|
<span slot="label"><span style="color: red">* </span>{{$t('device.device-edit.148398-83')}}</span>
|
||||||
|
<device-things-model ref="deviceThingsModel" :device="form" />
|
||||||
|
</el-tab-pane>
|
||||||
|
|
||||||
<el-tab-pane
|
<el-tab-pane
|
||||||
name="deviceSub"
|
name="deviceSub"
|
||||||
:disabled="form.deviceId == 0"
|
:disabled="form.deviceId == 0"
|
||||||
@ -342,6 +349,7 @@ import deviceVariable from './device-variable';
|
|||||||
import deviceInlineVideo from './device-inline-video';
|
import deviceInlineVideo from './device-inline-video';
|
||||||
import deviceFuncLog from './device-functionlog';
|
import deviceFuncLog from './device-functionlog';
|
||||||
import deviceSub from './device-sub';
|
import deviceSub from './device-sub';
|
||||||
|
import deviceThingsModel from './device-things-model.vue';
|
||||||
import vueQr from 'vue-qr';
|
import vueQr from 'vue-qr';
|
||||||
import { loadBMap } from '@/utils/map.js';
|
import { loadBMap } from '@/utils/map.js';
|
||||||
import { deviceSynchronization, getDevice, addDevice, updateDevice, generatorDeviceNum, getMqttConnect } from '@/api/iot/device';
|
import { deviceSynchronization, getDevice, addDevice, updateDevice, generatorDeviceNum, getMqttConnect } from '@/api/iot/device';
|
||||||
@ -383,6 +391,7 @@ export default {
|
|||||||
instructionParsing,
|
instructionParsing,
|
||||||
deviceModbusTask,
|
deviceModbusTask,
|
||||||
deviceInlineVideo,
|
deviceInlineVideo,
|
||||||
|
deviceThingsModel,
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
activeName(val) {
|
activeName(val) {
|
||||||
|
|||||||
606
vue/src/views/iot/device/device-things-model.vue
Normal file
606
vue/src/views/iot/device/device-things-model.vue
Normal file
@ -0,0 +1,606 @@
|
|||||||
|
<template>
|
||||||
|
<div style="padding-left: 20px">
|
||||||
|
<el-row :gutter="10" class="mb8">
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['iot:model:add']">
|
||||||
|
新增
|
||||||
|
</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="warning" plain icon="el-icon-refresh" size="mini" @click="getList" v-hasPermi="['iot:model:list']">
|
||||||
|
刷新
|
||||||
|
</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-link type="danger" style="padding-top: 5px" :underline="false">
|
||||||
|
设备级物模型,基于产品物模型进行公式计算
|
||||||
|
</el-link>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-table v-loading="loading" :data="modelList" size="mini" :border="false">
|
||||||
|
<el-table-column label="物模型名称" align="center" prop="modelName" width="200" />
|
||||||
|
<el-table-column label="标识符" align="center" prop="identifier" />
|
||||||
|
<el-table-column label="图表展示" align="center" width="80">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<dict-tag :options="dict.type.iot_yes_no" :value="scope.row.isChart" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="实时监测" align="center" width="80">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<dict-tag :options="dict.type.iot_yes_no" :value="scope.row.isMonitor" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="历史存储" align="center" width="80">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<dict-tag :options="dict.type.iot_yes_no" :value="scope.row.isHistory" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="数据类型" align="center" prop="datatype" width="80">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<dict-tag :options="dict.type.iot_data_type" :value="scope.row.datatype" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="数据定义" align="left" header-align="center" prop="specs" min-width="150" class-name="specsColor">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<div v-html="formatSpecsDisplay(scope.row.specs)"></div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="计算公式" align="left" prop="formula" min-width="180">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-tooltip v-if="scope.row.formula" :content="scope.row.formula" placement="top" effect="light">
|
||||||
|
<span class="formula-tag">{{ scope.row.formula }}</span>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="排序" align="center" prop="modelOrder" width="80" />
|
||||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button size="mini" type="text" icon="el-icon-view" @click="handleEdit(scope.row)" v-hasPermi="['iot:model:edit']">
|
||||||
|
修改
|
||||||
|
</el-button>
|
||||||
|
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['iot:model:remove']">
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
|
||||||
|
|
||||||
|
<!-- 添加或修改物模型对话框 -->
|
||||||
|
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="600px" append-to-body v-dialogDrag>
|
||||||
|
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
|
||||||
|
<el-form-item label="物模型名称" prop="modelName">
|
||||||
|
<el-input v-model="form.modelName" placeholder="请输入物模型名称" style="width: 385px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="标识符" prop="identifier">
|
||||||
|
<el-input v-model="form.identifier" placeholder="请输入标识符" style="width: 385px" :disabled="!!form.modelId" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="排序" prop="modelOrder">
|
||||||
|
<el-input v-model="form.modelOrder" placeholder="请输入排序" type="number" style="width: 385px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="模型特性" prop="property">
|
||||||
|
<el-checkbox name="isChart" label="图表展示" v-model="form.isChart" :true-label="1" :false-label="0"></el-checkbox>
|
||||||
|
<el-checkbox name="isMonitor" label="实时监测" v-model="form.isMonitor" :true-label="1" :false-label="0"></el-checkbox>
|
||||||
|
<el-checkbox name="isHistory" label="历史存储" v-model="form.isHistory" :true-label="1" :false-label="0"></el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
<el-divider></el-divider>
|
||||||
|
<el-form-item label="数据类型" prop="datatype">
|
||||||
|
<el-select v-model="form.datatype" placeholder="请选择数据类型" style="width: 175px">
|
||||||
|
<el-option key="integer" label="整数(integer)" value="integer"></el-option>
|
||||||
|
<el-option key="decimal" label="小数(decimal)" value="decimal"></el-option>
|
||||||
|
<el-option key="string" label="字符串(string)" value="string"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<div v-if="form.datatype == 'integer' || form.datatype == 'decimal'">
|
||||||
|
<el-form-item label="取值范围">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="9">
|
||||||
|
<el-input v-model="specsForm.min" placeholder="最小值" type="number" />
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="2" align="center">~</el-col>
|
||||||
|
<el-col :span="9">
|
||||||
|
<el-input v-model="specsForm.max" placeholder="最大值" type="number" />
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="单位">
|
||||||
|
<el-input v-model="specsForm.unit" placeholder="请输入单位,如:℃、%" style="width: 385px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="步长">
|
||||||
|
<el-input v-model="specsForm.step" placeholder="请输入步长" type="number" style="width: 385px" />
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="form.datatype == 'string'">
|
||||||
|
<el-form-item label="数据长度">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="9">
|
||||||
|
<el-input v-model="specsForm.maxLength" placeholder="请输入最大长度" type="number" />
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="14" :offset="1">字节(Byte),默认1024</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-form-item label="计算公式" prop="formula">
|
||||||
|
<template slot="label">
|
||||||
|
<span slot="label">{{$t('device.device-edit.148398-83')}}</span>
|
||||||
|
<el-tooltip style="cursor: pointer" effect="light" placement="top">
|
||||||
|
<div slot="content">
|
||||||
|
用于对原始值进行计算后存储和显示<br />
|
||||||
|
公式中使用产品物模型标识符,并用大括号包裹<br />
|
||||||
|
支持运算符:+ - * / % ^(次方) sqrt(开方)<br />
|
||||||
|
<br />
|
||||||
|
<strong>示例:</strong><br />
|
||||||
|
压力=K*频率平方-常数:1.5*{frequency}^2-100
|
||||||
|
</div>
|
||||||
|
<i class="el-icon-question" />
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
<div class="formula-editor-container">
|
||||||
|
<!-- 运算符按钮组 -->
|
||||||
|
<div class="operator-section">
|
||||||
|
<span class="section-label">运算符:</span>
|
||||||
|
<div class="operator-buttons">
|
||||||
|
<el-button style="color: #f56c6c" size="mini" title="加法" @click="insertOperator('+')">+</el-button>
|
||||||
|
<el-button style="color: #f56c6c" size="mini" title="减法" @click="insertOperator('-')">−</el-button>
|
||||||
|
<el-button style="color: #f56c6c" size="mini" title="乘法" @click="insertOperator('*')">×</el-button>
|
||||||
|
<el-button style="color: #f56c6c" size="mini" title="除法" @click="insertOperator('/')">÷</el-button>
|
||||||
|
<el-button style="color: #f56c6c" size="mini" title="次方" @click="insertOperator('^')">^</el-button>
|
||||||
|
<el-button style="color: #f56c6c" size="mini" title="开方" @click="insertOperator('sqrt')">sqrt</el-button>
|
||||||
|
<el-button style="color: #f56c6c" size="mini" title="取余" @click="insertOperator('%')">%</el-button>
|
||||||
|
<el-button style="color: #f56c6c" size="mini" title="左括号" @click="insertOperator('(')">(</el-button>
|
||||||
|
<el-button style="color: #f56c6c" size="mini" title="右括号" @click="insertOperator(')')">)</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 物模型变量区域 -->
|
||||||
|
<div class="variable-section" v-loading="loadingModels">
|
||||||
|
<span class="section-label">产品通用物模型变量:</span>
|
||||||
|
<div class="variable-tags">
|
||||||
|
<el-tag
|
||||||
|
v-for="model in productModels"
|
||||||
|
:key="model.identifier"
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
effect="plain"
|
||||||
|
class="var-tag"
|
||||||
|
@click="insertVariable(model.identifier)"
|
||||||
|
:title="model.identifier"
|
||||||
|
>
|
||||||
|
{{ model.modelName }}
|
||||||
|
</el-tag>
|
||||||
|
<span v-if="productModels.length === 0 && !loadingModels" class="no-data">暂无可用物模型</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 输入框和清空按钮 -->
|
||||||
|
<div class="formula-input-section">
|
||||||
|
<el-input v-model="form.formula" type="textarea" :rows="2" placeholder="输入或点击上方运算符、物模型变量构建公式" class="formula-input" />
|
||||||
|
<el-button type="danger" plain size="small" title="清空公式" @click="form.formula = ''" class="clear-btn">清空</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="submitForm" v-show="form.modelId">修 改</el-button>
|
||||||
|
<el-button type="primary" @click="submitForm" v-show="!form.modelId">新 增</el-button>
|
||||||
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.specsColor {
|
||||||
|
background-color: #fcfcfc;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 公式编辑器容器 */
|
||||||
|
.formula-editor-container {
|
||||||
|
width: 420px;
|
||||||
|
border: 1px solid #e4e7ed;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 14px;
|
||||||
|
background: linear-gradient(to bottom, #fafbfc, #ffffff);
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 运算符区域 */
|
||||||
|
.operator-section {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-label {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operator-buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operator-buttons .el-button {
|
||||||
|
min-width: 38px;
|
||||||
|
height: 32px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operator-buttons .el-button--default {
|
||||||
|
background: #fff;
|
||||||
|
border-color: #dcdfe6;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operator-buttons .el-button--default:hover {
|
||||||
|
color: #409eff;
|
||||||
|
border-color: #409eff;
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 物模型变量区域 */
|
||||||
|
.variable-section {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
padding-top: 12px;
|
||||||
|
border-top: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.variable-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
max-height: 80px;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 2px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.var-tag {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 0 10px;
|
||||||
|
height: 26px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.var-tag:hover {
|
||||||
|
background-color: #409eff;
|
||||||
|
color: #fff;
|
||||||
|
border-color: #409eff;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 2px 6px rgba(64, 158, 255, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-data {
|
||||||
|
color: #c0c4cc;
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 输入框和清空按钮区域 */
|
||||||
|
.formula-input-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10px;
|
||||||
|
padding-top: 12px;
|
||||||
|
border-top: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-input {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-input ::v-deep .el-textarea__inner {
|
||||||
|
font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
|
||||||
|
font-size: 13px;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: #fff;
|
||||||
|
border-color: #dcdfe6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-input ::v-deep .el-textarea__inner:focus {
|
||||||
|
border-color: #409eff;
|
||||||
|
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.clear-btn {
|
||||||
|
height: 54px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clear-btn:hover {
|
||||||
|
background-color: #fef0f0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { listModel, getModel, addModel, updateModel, delModel } from '@/api/iot/model';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'DeviceThingsModel',
|
||||||
|
dicts: ['iot_data_type', 'iot_yes_no'],
|
||||||
|
props: {
|
||||||
|
device: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
loadingModels: false,
|
||||||
|
dialogVisible: false,
|
||||||
|
dialogTitle: '',
|
||||||
|
total: 0,
|
||||||
|
modelList: [],
|
||||||
|
productModels: [],
|
||||||
|
queryParams: {
|
||||||
|
productId: 0,
|
||||||
|
deviceId: 0,
|
||||||
|
isCalculated: 1,
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
modelId: null,
|
||||||
|
modelName: '',
|
||||||
|
identifier: '',
|
||||||
|
productId: 0,
|
||||||
|
productName: '',
|
||||||
|
deviceId: 0,
|
||||||
|
serialNumber: '',
|
||||||
|
tenantId: 0,
|
||||||
|
tenantName: '',
|
||||||
|
type: 1,
|
||||||
|
datatype: 'decimal',
|
||||||
|
formula: '',
|
||||||
|
isCalculated: 1,
|
||||||
|
specs: '',
|
||||||
|
isChart: 1,
|
||||||
|
isHistory: 1,
|
||||||
|
isMonitor: 1,
|
||||||
|
isReadonly: 1,
|
||||||
|
modelOrder: 0,
|
||||||
|
remark: '',
|
||||||
|
},
|
||||||
|
specsForm: {
|
||||||
|
type: 'decimal',
|
||||||
|
max: 100,
|
||||||
|
min: 0,
|
||||||
|
step: 1,
|
||||||
|
unit: '',
|
||||||
|
maxLength: 1024,
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
modelName: [{ required: true, message: '请输入物模型名称', trigger: 'blur' }],
|
||||||
|
identifier: [
|
||||||
|
{ required: true, message: '请输入标识符', trigger: 'blur' },
|
||||||
|
{ pattern: /^[a-zA-Z][a-zA-Z0-9_]*$/, message: '以字母开头,只含字母、数字、下划线', trigger: 'blur' },
|
||||||
|
],
|
||||||
|
datatype: [{ required: true, message: '请选择数据类型', trigger: 'change' }],
|
||||||
|
formula: [{ required: true, message: '请输入计算公式', trigger: 'blur' }],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
device: {
|
||||||
|
handler(val) {
|
||||||
|
if (val && val.deviceId) {
|
||||||
|
this.queryParams.productId = val.productId || 0;
|
||||||
|
this.queryParams.deviceId = val.deviceId || 0;
|
||||||
|
this.getList();
|
||||||
|
this.loadProductModels();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true,
|
||||||
|
deep: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/** 查询设备计算物模型列表 */
|
||||||
|
getList() {
|
||||||
|
if (!this.queryParams.deviceId) return;
|
||||||
|
this.loading = true;
|
||||||
|
listModel(this.queryParams)
|
||||||
|
.then((response) => {
|
||||||
|
this.modelList = response.rows || [];
|
||||||
|
this.total = response.total || 0;
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 加载产品物模型(用于公式变量选择) */
|
||||||
|
loadProductModels() {
|
||||||
|
if (!this.device.productId) return;
|
||||||
|
this.loadingModels = true;
|
||||||
|
listModel({
|
||||||
|
productId: this.device.productId,
|
||||||
|
deviceId: 0,
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 200,
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
// 过滤掉纯计算物模型(只保留设备上报的物模型)
|
||||||
|
this.productModels = (response.rows || []).filter((m) => m.isCalculated !== 1);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.loadingModels = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 表单重置 */
|
||||||
|
resetForm() {
|
||||||
|
this.form = {
|
||||||
|
modelId: null,
|
||||||
|
modelName: '',
|
||||||
|
identifier: '',
|
||||||
|
productId: this.device.productId || 0,
|
||||||
|
productName: this.device.productName || '',
|
||||||
|
deviceId: this.device.deviceId || 0,
|
||||||
|
serialNumber: this.device.serialNumber || '',
|
||||||
|
tenantId: this.device.tenantId || 0,
|
||||||
|
tenantName: this.device.tenantName || '',
|
||||||
|
type: 1,
|
||||||
|
datatype: 'decimal',
|
||||||
|
formula: '',
|
||||||
|
isCalculated: 1,
|
||||||
|
specs: '',
|
||||||
|
isChart: 1,
|
||||||
|
isHistory: 1,
|
||||||
|
isMonitor: 1,
|
||||||
|
isReadonly: 1,
|
||||||
|
modelOrder: 0,
|
||||||
|
remark: '',
|
||||||
|
};
|
||||||
|
this.specsForm = {
|
||||||
|
type: 'decimal',
|
||||||
|
max: 100,
|
||||||
|
min: 0,
|
||||||
|
step: 1,
|
||||||
|
unit: '',
|
||||||
|
maxLength: 1024,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/** 新增按钮操作 */
|
||||||
|
handleAdd() {
|
||||||
|
this.resetForm();
|
||||||
|
this.dialogTitle = '新增计算物模型';
|
||||||
|
this.dialogVisible = true;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.form && this.$refs.form.clearValidate();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 修改按钮操作 */
|
||||||
|
handleEdit(row) {
|
||||||
|
this.resetForm();
|
||||||
|
this.dialogTitle = '修改计算物模型';
|
||||||
|
getModel(row.modelId).then((response) => {
|
||||||
|
const data = response.data || {};
|
||||||
|
this.form = { ...this.form, ...data };
|
||||||
|
if (data.specs) {
|
||||||
|
try {
|
||||||
|
this.specsForm = JSON.parse(data.specs);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('解析specs失败', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.dialogVisible = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 删除按钮操作 */
|
||||||
|
handleDelete(row) {
|
||||||
|
this.$modal
|
||||||
|
.confirm(`是否确认删除物模型"${row.modelName}"?`)
|
||||||
|
.then(() => delModel(row.modelId))
|
||||||
|
.then(() => {
|
||||||
|
this.$modal.msgSuccess('删除成功');
|
||||||
|
this.getList();
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
},
|
||||||
|
/** 插入运算符 */
|
||||||
|
insertOperator(op) {
|
||||||
|
this.form.formula = (this.form.formula || '') + op;
|
||||||
|
},
|
||||||
|
/** 插入变量(标识符使用大括号包裹) */
|
||||||
|
insertVariable(identifier) {
|
||||||
|
this.form.formula = (this.form.formula || '') + `{${identifier}}`;
|
||||||
|
},
|
||||||
|
/** 格式化物模型specs */
|
||||||
|
formatThingsSpecs() {
|
||||||
|
var data = {};
|
||||||
|
data.type = this.form.datatype;
|
||||||
|
if (this.form.datatype == 'integer' || this.form.datatype == 'decimal') {
|
||||||
|
data.min = Number(this.specsForm.min ? this.specsForm.min : 0);
|
||||||
|
data.max = Number(this.specsForm.max ? this.specsForm.max : 100);
|
||||||
|
data.unit = this.specsForm.unit ? this.specsForm.unit : '';
|
||||||
|
data.step = Number(this.specsForm.step ? this.specsForm.step : 1);
|
||||||
|
} else if (this.form.datatype == 'string') {
|
||||||
|
data.maxLength = Number(this.specsForm.maxLength ? this.specsForm.maxLength : 1024);
|
||||||
|
}
|
||||||
|
return JSON.stringify(data);
|
||||||
|
},
|
||||||
|
/** 格式化显示数据定义 */
|
||||||
|
formatSpecsDisplay(json) {
|
||||||
|
if (json == null || json == undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let specs = JSON.parse(json);
|
||||||
|
if (specs.type === 'integer' || specs.type === 'decimal') {
|
||||||
|
return (
|
||||||
|
`<span style='width:50%;display:inline-block;'>最大值:<span style="color:#F56C6C">` +
|
||||||
|
specs.max +
|
||||||
|
`</span></span>最小值:<span style="color:#F56C6C">` +
|
||||||
|
specs.min +
|
||||||
|
`</span><br /><span style='width:50%;display:inline-block;'>步长:<span style="color:#F56C6C">` +
|
||||||
|
specs.step +
|
||||||
|
`</span></span>单位:<span style="color:#F56C6C">` +
|
||||||
|
specs.unit
|
||||||
|
);
|
||||||
|
} else if (specs.type === 'string') {
|
||||||
|
return `数据长度:<span style="color:#F56C6C">` + specs.maxLength + '</span>';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
/** 提交按钮 */
|
||||||
|
submitForm() {
|
||||||
|
this.$refs.form.validate((valid) => {
|
||||||
|
if (!valid) return;
|
||||||
|
|
||||||
|
// 格式化specs
|
||||||
|
this.form.specs = this.formatThingsSpecs();
|
||||||
|
this.form.isCalculated = 1;
|
||||||
|
this.form.isReadonly = 1;
|
||||||
|
this.form.type = 1;
|
||||||
|
// 去除公式中的空格
|
||||||
|
if (this.form.formula) {
|
||||||
|
this.form.formula = this.form.formula.replace(/\s+/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
const request = this.form.modelId ? updateModel(this.form) : addModel(this.form);
|
||||||
|
request.then(() => {
|
||||||
|
this.$modal.msgSuccess(this.form.modelId ? '修改成功' : '新增成功');
|
||||||
|
this.dialogVisible = false;
|
||||||
|
this.getList();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.formula-tag {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 140px;
|
||||||
|
color: #d85a5a;
|
||||||
|
font-family: 'SF Mono', Monaco, Menlo, Consolas, monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
vertical-align: middle;
|
||||||
|
padding: 4px 10px;
|
||||||
|
border: 1px solid rgba(216, 90, 90, 0.35);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: linear-gradient(135deg, rgba(255, 235, 235, 0.8) 0%, rgba(255, 245, 245, 0.6) 100%);
|
||||||
|
box-shadow: 0 1px 3px rgba(216, 90, 90, 0.1);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -74,6 +74,8 @@ export default {
|
|||||||
productId: 0,
|
productId: 0,
|
||||||
// 1-属性,2-功能,3-事件,4-属性和功能
|
// 1-属性,2-功能,3-事件,4-属性和功能
|
||||||
type: 4,
|
type: 4,
|
||||||
|
// 产品管理页面只显示设备上报的物模型,不显示纯计算物模型
|
||||||
|
isCalculated: 0,
|
||||||
},
|
},
|
||||||
form: {},
|
form: {},
|
||||||
// 产品
|
// 产品
|
||||||
|
|||||||
@ -195,7 +195,7 @@
|
|||||||
<span style="color: red" v-hasPermi="['iot:model:list']">*</span>
|
<span style="color: red" v-hasPermi="['iot:model:list']">*</span>
|
||||||
{{ $t('product.product-edit.473153-38') }}
|
{{ $t('product.product-edit.473153-38') }}
|
||||||
</span>
|
</span>
|
||||||
<product-things-model ref="productThingsModel" :product="form" @updateModel="updateModel" />
|
<product-things-model ref="productThingsModel" :product="form" :isCalculated="0" @updateModel="updateModel" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<!-- 子产品 -->
|
<!-- 子产品 -->
|
||||||
<el-tab-pane name="productSub" :disabled="form.productId == 0" v-if="form.deviceType == 2 && (form.protocolCode == 'MODBUS-RTU' || form.protocolCode == 'MODBUS-TCP')" lazy>
|
<el-tab-pane name="productSub" :disabled="form.productId == 0" v-if="form.deviceType == 2 && (form.protocolCode == 'MODBUS-RTU' || form.protocolCode == 'MODBUS-TCP')" lazy>
|
||||||
|
|||||||
@ -401,6 +401,7 @@ export default {
|
|||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 1000,
|
pageSize: 1000,
|
||||||
productId: 0,
|
productId: 0,
|
||||||
|
isCalculated: 0,
|
||||||
},
|
},
|
||||||
thingsTotal: 0,
|
thingsTotal: 0,
|
||||||
// 表单参数
|
// 表单参数
|
||||||
|
|||||||
@ -196,8 +196,6 @@
|
|||||||
<br />
|
<br />
|
||||||
{{ $t('product.product-things-model.142341-54') }}
|
{{ $t('product.product-things-model.142341-54') }}
|
||||||
<br />
|
<br />
|
||||||
{{ $t('product.product-things-model.142341-54-1') }}
|
|
||||||
<br />
|
|
||||||
{{ $t('product.product-things-model.142341-54-2') }}
|
{{ $t('product.product-things-model.142341-54-2') }}
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
@ -211,16 +209,7 @@
|
|||||||
<br />
|
<br />
|
||||||
{{ $t('product.product-things-model.142341-59') }}
|
{{ $t('product.product-things-model.142341-59') }}
|
||||||
<br />
|
<br />
|
||||||
{{ $t('product.product-things-model.142341-60') }}({{ $t('product.product-things-model.142341-61') }}):%s%10.00
|
{{ $t('product.product-things-model.142341-60') }}({{ $t('product.product-things-model.142341-61') }})
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<strong>{{ $t('product.product-things-model.142341-61-1') }}</strong>
|
|
||||||
<br />
|
|
||||||
{{ $t('product.product-things-model.142341-61-2') }}
|
|
||||||
<br />
|
|
||||||
{{ $t('product.product-things-model.142341-61-3') }}
|
|
||||||
<br />
|
|
||||||
{{ $t('product.product-things-model.142341-61-4') }}
|
|
||||||
<br />
|
<br />
|
||||||
</div>
|
</div>
|
||||||
<i class="el-icon-question" />
|
<i class="el-icon-question" />
|
||||||
@ -417,6 +406,10 @@ export default {
|
|||||||
type: Object,
|
type: Object,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
|
isCalculated: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
// 获取到父组件传递的productId后,刷新列表
|
// 获取到父组件传递的productId后,刷新列表
|
||||||
@ -425,6 +418,10 @@ export default {
|
|||||||
if (this.productInfo && this.productInfo.productId != 0) {
|
if (this.productInfo && this.productInfo.productId != 0) {
|
||||||
this.queryParams.productId = this.productInfo.productId;
|
this.queryParams.productId = this.productInfo.productId;
|
||||||
this.productId = this.productInfo.productId;
|
this.productId = this.productInfo.productId;
|
||||||
|
// 设置isCalculated查询条件(产品管理页面只显示设备上报的物模型,不显示纯计算物模型)
|
||||||
|
if (this.isCalculated !== null) {
|
||||||
|
this.queryParams.isCalculated = this.isCalculated;
|
||||||
|
}
|
||||||
this.getList();
|
this.getList();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user