20260116:设备下沉第一版,理解错误
This commit is contained in:
parent
268fd71b22
commit
382025e049
@ -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
|
||||||
|
|||||||
@ -244,6 +244,10 @@ public interface FastBeeConstant {
|
|||||||
String TSL_PRE_KEY = "TSL:";
|
String TSL_PRE_KEY = "TSL:";
|
||||||
|
|
||||||
String MODBUS_PRE_KEY = "MODBUS:";
|
String MODBUS_PRE_KEY = "MODBUS:";
|
||||||
|
/**
|
||||||
|
* 设备级 modbus 缓存
|
||||||
|
*/
|
||||||
|
String MODBUS_DEVICE_PRE_KEY = "MODBUS:DEV:";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* modbus缓存指令
|
* modbus缓存指令
|
||||||
|
|||||||
@ -65,6 +65,13 @@ public class RedisKeyBuilder {
|
|||||||
return FastBeeConstant.REDIS.MODBUS_PRE_KEY + productId;
|
return FastBeeConstant.REDIS.MODBUS_PRE_KEY + productId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备级 modbus 配置缓存 key
|
||||||
|
*/
|
||||||
|
public static String buildModbusDeviceKey(Long deviceId) {
|
||||||
|
return FastBeeConstant.REDIS.MODBUS_DEVICE_PRE_KEY + deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 录像缓存key
|
* 录像缓存key
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -24,6 +24,7 @@ import com.fastbee.iot.enums.DeviceType;
|
|||||||
import com.fastbee.iot.model.DeviceStatusVO;
|
import com.fastbee.iot.model.DeviceStatusVO;
|
||||||
import com.fastbee.iot.model.modbus.ModbusPollJob;
|
import com.fastbee.iot.model.modbus.ModbusPollJob;
|
||||||
import com.fastbee.iot.service.IDeviceService;
|
import com.fastbee.iot.service.IDeviceService;
|
||||||
|
import com.fastbee.iot.service.IDeviceModbusParamsService;
|
||||||
import com.fastbee.iot.service.IModbusJobService;
|
import com.fastbee.iot.service.IModbusJobService;
|
||||||
import com.fastbee.iot.service.IModbusParamsService;
|
import com.fastbee.iot.service.IModbusParamsService;
|
||||||
import com.fastbee.mq.producer.MessageProducer;
|
import com.fastbee.mq.producer.MessageProducer;
|
||||||
@ -73,6 +74,8 @@ public class DevicePropFetchConsumer {
|
|||||||
private ISessionStore sessionStore;
|
private ISessionStore sessionStore;
|
||||||
@Resource
|
@Resource
|
||||||
private IModbusParamsService modbusParamsService;
|
private IModbusParamsService modbusParamsService;
|
||||||
|
@Resource
|
||||||
|
private IDeviceModbusParamsService deviceModbusParamsService;
|
||||||
@Value("${server.broker.enabled}")
|
@Value("${server.broker.enabled}")
|
||||||
private Boolean enabled;
|
private Boolean enabled;
|
||||||
|
|
||||||
@ -197,8 +200,9 @@ public class DevicePropFetchConsumer {
|
|||||||
//如果是网关子设备,则检测子设备是否在特定时间内有数据上报
|
//如果是网关子设备,则检测子设备是否在特定时间内有数据上报
|
||||||
if (modbusJob.getDeviceType() == DeviceType.SUB_GATEWAY.getCode()) {
|
if (modbusJob.getDeviceType() == DeviceType.SUB_GATEWAY.getCode()) {
|
||||||
long deterTime = 300L; //这里默认使用5分钟,如果轮询时间大于5分钟,请在配置参数设置更长时间
|
long deterTime = 300L; //这里默认使用5分钟,如果轮询时间大于5分钟,请在配置参数设置更长时间
|
||||||
ModbusParams params = modbusParamsService.getModbusParamsByDeviceId(modbusJob.getSubDeviceId());
|
// 优先使用设备级配置,无则回退到产品级配置
|
||||||
if (!Objects.isNull(params)) {
|
ModbusParams params = deviceModbusParamsService.getEffectiveParams(modbusJob.getSubDeviceId());
|
||||||
|
if (!Objects.isNull(params) && !Objects.isNull(params.getDeterTimer())) {
|
||||||
deterTime = Long.parseLong(params.getDeterTimer());
|
deterTime = Long.parseLong(params.getDeterTimer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,76 @@
|
|||||||
|
package com.fastbee.controller.modbus;
|
||||||
|
|
||||||
|
import com.fastbee.common.annotation.Log;
|
||||||
|
import com.fastbee.common.core.controller.BaseController;
|
||||||
|
import com.fastbee.common.core.domain.AjaxResult;
|
||||||
|
import com.fastbee.common.core.page.TableDataInfo;
|
||||||
|
import com.fastbee.common.enums.BusinessType;
|
||||||
|
import com.fastbee.iot.cache.IModbusConfigCache;
|
||||||
|
import com.fastbee.iot.domain.DeviceModbusConfig;
|
||||||
|
import com.fastbee.iot.model.modbus.DeviceModbusConfigVO;
|
||||||
|
import com.fastbee.iot.service.IDeviceModbusConfigService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备级 modbus 配置
|
||||||
|
*
|
||||||
|
* @author gpt
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/deviceModbus/config")
|
||||||
|
@Api(tags = "设备modbus配置")
|
||||||
|
public class DeviceModbusConfigController extends BaseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IDeviceModbusConfigService deviceModbusConfigService;
|
||||||
|
@Autowired
|
||||||
|
private IModbusConfigCache modbusConfigCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询设备modbus配置列表
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('modbus:config:list')")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(DeviceModbusConfig config) {
|
||||||
|
startPage();
|
||||||
|
List<DeviceModbusConfig> list = deviceModbusConfigService.selectDeviceModbusConfigList(config);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量新增或修改设备modbus配置
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('modbus:config:add')")
|
||||||
|
@Log(title = "设备modbus配置", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping("/addBatch")
|
||||||
|
@ApiOperation("批量新增或修改设备modbus配置")
|
||||||
|
public AjaxResult addBatch(@RequestBody DeviceModbusConfigVO vo) {
|
||||||
|
deviceModbusConfigService.addOrUpDeviceModbusConfigBatch(vo.getConfigList(), vo.getProductId(), vo.getDeviceId(), vo.getDelIds());
|
||||||
|
// 刷新设备缓存
|
||||||
|
modbusConfigCache.setModbusConfigCacheByDeviceId(vo.getProductId(), vo.getDeviceId());
|
||||||
|
return AjaxResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除设备modbus配置
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('modbus:config:remove')")
|
||||||
|
@Log(title = "设备modbus配置", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable Long[] ids,
|
||||||
|
@RequestParam(required = false) Long productId,
|
||||||
|
@RequestParam(required = false) Long deviceId) {
|
||||||
|
int rows = deviceModbusConfigService.deleteDeviceModbusConfigByIds(ids);
|
||||||
|
if (rows > 0 && deviceId != null) {
|
||||||
|
// 删除后刷新对应设备的寄存器缓存,避免解析仍命中旧配置
|
||||||
|
modbusConfigCache.setModbusConfigCacheByDeviceId(productId, deviceId);
|
||||||
|
}
|
||||||
|
return toAjax(rows);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,82 @@
|
|||||||
|
package com.fastbee.controller.modbus;
|
||||||
|
|
||||||
|
import com.fastbee.common.core.controller.BaseController;
|
||||||
|
import com.fastbee.common.core.domain.AjaxResult;
|
||||||
|
import com.fastbee.iot.domain.DeviceModbusParams;
|
||||||
|
import com.fastbee.iot.service.IDeviceModbusParamsService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import io.swagger.annotations.ApiParam;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备modbus配置参数Controller
|
||||||
|
*
|
||||||
|
* @author Sumuxi
|
||||||
|
* @date 2026/1/14
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/modbus/device/params")
|
||||||
|
@Api(tags = "设备modbus配置参数")
|
||||||
|
public class DeviceModbusParamsController extends BaseController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IDeviceModbusParamsService deviceModbusParamsService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据设备ID获取设备modbus配置参数
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('modbus:params:query')")
|
||||||
|
@GetMapping(value = "/getByDeviceId")
|
||||||
|
@ApiOperation("根据设备ID获取设备modbus配置参数")
|
||||||
|
public AjaxResult getByDeviceId(@ApiParam("设备ID") @RequestParam Long deviceId) {
|
||||||
|
return success(deviceModbusParamsService.getByDeviceId(deviceId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备的有效modbus配置参数(设备级 > 产品级)
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('modbus:params:query')")
|
||||||
|
@GetMapping(value = "/getEffective")
|
||||||
|
@ApiOperation("获取设备的有效modbus配置参数(设备级优先,回退到产品级)")
|
||||||
|
public AjaxResult getEffective(
|
||||||
|
@ApiParam("设备ID") @RequestParam Long deviceId,
|
||||||
|
@ApiParam("产品ID") @RequestParam Long productId) {
|
||||||
|
return success(deviceModbusParamsService.getEffectiveParams(deviceId, productId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增或更新设备modbus配置参数
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('modbus:params:edit')")
|
||||||
|
@PostMapping("/addOrUpdate")
|
||||||
|
@ApiOperation("新增或更新设备modbus配置参数")
|
||||||
|
public AjaxResult addOrUpdate(@RequestBody DeviceModbusParams params) {
|
||||||
|
return toAjax(deviceModbusParamsService.addOrUpdate(params));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据设备ID删除设备modbus配置参数
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('modbus:params:remove')")
|
||||||
|
@DeleteMapping("/deleteByDeviceId/{deviceId}")
|
||||||
|
@ApiOperation("根据设备ID删除设备modbus配置参数")
|
||||||
|
public AjaxResult deleteByDeviceId(@PathVariable Long deviceId) {
|
||||||
|
return toAjax(deviceModbusParamsService.deleteByDeviceId(deviceId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除设备modbus配置参数
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('modbus:params:remove')")
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
@ApiOperation("批量删除设备modbus配置参数")
|
||||||
|
public AjaxResult remove(@PathVariable Long[] ids) {
|
||||||
|
return toAjax(deviceModbusParamsService.removeByIds(Arrays.asList(ids)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -97,22 +97,23 @@ public class ModbusProtocol implements IProtocol {
|
|||||||
matchSubDev(report, deviceData.getSerialNumber(), slaveId);
|
matchSubDev(report, deviceData.getSerialNumber(), slaveId);
|
||||||
String serialNumber = report.getSerialNumber();
|
String serialNumber = report.getSerialNumber();
|
||||||
Long productId = report.getProductId();
|
Long productId = report.getProductId();
|
||||||
|
Long deviceId = getDeviceIdBySerial(serialNumber);
|
||||||
ModbusCode modbusCode = ModbusCode.getInstance(code);
|
ModbusCode modbusCode = ModbusCode.getInstance(code);
|
||||||
List<ThingsModelSimpleItem> values = new ArrayList<>();
|
List<ThingsModelSimpleItem> values = new ArrayList<>();
|
||||||
switch (modbusCode) {
|
switch (modbusCode) {
|
||||||
case Read01:
|
case Read01:
|
||||||
case Read02:
|
case Read02:
|
||||||
//起始地址
|
//起始地址(从设备级Redis缓存获取)
|
||||||
String address0102 = getCacheModbusAddress(deviceData.getSerialNumber(), slaveId, code);
|
String address0102 = getCacheModbusAddress(productId, deviceId);
|
||||||
//读线圈或读离散型寄存器处理
|
//读线圈或读离散型寄存器处理
|
||||||
handleRead0102(productId, message, address0102, values);
|
handleRead0102(productId, deviceId, message, address0102, values);
|
||||||
break;
|
break;
|
||||||
case Read03:
|
case Read03:
|
||||||
case Read04:
|
case Read04:
|
||||||
//起始地址
|
//起始地址(从设备级Redis缓存获取)
|
||||||
String address0304 = getCacheModbusAddress(deviceData.getSerialNumber(), slaveId, code);
|
String address0304 = getCacheModbusAddress(productId, deviceId);
|
||||||
//读输入、保持寄存器
|
//读输入、保持寄存器
|
||||||
handleRead0304(productId, message, address0304, values, hexDump);
|
handleRead0304(productId, deviceId, message, address0304, values, hexDump);
|
||||||
break;
|
break;
|
||||||
case Write06:
|
case Write06:
|
||||||
case Write05:
|
case Write05:
|
||||||
@ -144,18 +145,19 @@ public class ModbusProtocol implements IProtocol {
|
|||||||
* 读线圈或读离散型寄存器处理
|
* 读线圈或读离散型寄存器处理
|
||||||
*
|
*
|
||||||
* @param productId 产品id
|
* @param productId 产品id
|
||||||
|
* @param deviceId 设备id(覆盖)
|
||||||
* @param message 数据集合
|
* @param message 数据集合
|
||||||
* @param address 起始地址
|
* @param address 起始地址
|
||||||
* @param simpleItemList 返回的物模型值
|
* @param simpleItemList 返回的物模型值
|
||||||
*/
|
*/
|
||||||
private void handleRead0102(Long productId, ModbusRtu message, String address, List<ThingsModelSimpleItem> simpleItemList) {
|
private void handleRead0102(Long productId, Long deviceId, ModbusRtu message, String address, List<ThingsModelSimpleItem> simpleItemList) {
|
||||||
//字节数
|
//字节数
|
||||||
int bitCount = message.getBitCount();
|
int bitCount = message.getBitCount();
|
||||||
//字节数据集合
|
//字节数据集合
|
||||||
byte[] byteDatas = message.getBitData();
|
byte[] byteDatas = message.getBitData();
|
||||||
String hexDump = ByteBufUtil.hexDump(byteDatas);
|
String hexDump = ByteBufUtil.hexDump(byteDatas);
|
||||||
//处理多个的情况
|
//处理多个的情况
|
||||||
Map<Integer, List<ModbusConfig>> modbusConfigMap = modbusConfigCache.getModbusConfigCacheByProductId(productId);
|
Map<Integer, List<ModbusConfig>> modbusConfigMap = modbusConfigCache.getModbusConfigCacheByDeviceId(productId, deviceId);
|
||||||
if (CollectionUtils.isEmpty(modbusConfigMap)) {
|
if (CollectionUtils.isEmpty(modbusConfigMap)) {
|
||||||
log.warn("寄存器地址:{},不存在", address);
|
log.warn("寄存器地址:{},不存在", address);
|
||||||
return;
|
return;
|
||||||
@ -192,17 +194,18 @@ public class ModbusProtocol implements IProtocol {
|
|||||||
* 处理读保持寄存器/输入寄存器
|
* 处理读保持寄存器/输入寄存器
|
||||||
*
|
*
|
||||||
* @param productId 产品id
|
* @param productId 产品id
|
||||||
|
* @param deviceId 设备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(Long productId, Long deviceId, 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) {
|
||||||
//单个寄存器上报情况处理
|
//单个寄存器上报情况处理
|
||||||
List<ModbusConfig> modbusConfig = modbusConfigCache.getSingleModbusConfig(productId, address);
|
List<ModbusConfig> modbusConfig = getConfigByAddress(productId, deviceId, address);
|
||||||
if (CollectionUtils.isEmpty(modbusConfig)) {
|
if (CollectionUtils.isEmpty(modbusConfig)) {
|
||||||
log.warn("寄存器地址:{},不存在", address);
|
log.warn("寄存器地址:{},不存在", address);
|
||||||
return;
|
return;
|
||||||
@ -239,7 +242,7 @@ public class ModbusProtocol implements IProtocol {
|
|||||||
// 原数据字符串(保持完整,不截取)
|
// 原数据字符串(保持完整,不截取)
|
||||||
String dataHex = sourceStr.substring(6, sourceStr.length() - 4);
|
String dataHex = sourceStr.substring(6, sourceStr.length() - 4);
|
||||||
//处理多个情况
|
//处理多个情况
|
||||||
Map<Integer, List<ModbusConfig>> modbusConfigMap = modbusConfigCache.getModbusConfigCacheByProductId(productId);
|
Map<Integer, List<ModbusConfig>> modbusConfigMap = modbusConfigCache.getModbusConfigCacheByDeviceId(productId, deviceId);
|
||||||
if (CollectionUtils.isEmpty(modbusConfigMap)) {
|
if (CollectionUtils.isEmpty(modbusConfigMap)) {
|
||||||
log.warn("寄存器数据不存在");
|
log.warn("寄存器数据不存在");
|
||||||
return;
|
return;
|
||||||
@ -373,7 +376,8 @@ public class ModbusProtocol implements IProtocol {
|
|||||||
private void handleMsgReply(ModbusRtu message, DeviceReport report, ModbusCode code) {
|
private void handleMsgReply(ModbusRtu message, DeviceReport report, ModbusCode code) {
|
||||||
//单个寄存器上报情况处理
|
//单个寄存器上报情况处理
|
||||||
String address = message.getAddress() + "";
|
String address = message.getAddress() + "";
|
||||||
List<ModbusConfig> modbusConfig = modbusConfigCache.getSingleModbusConfig(report.getProductId(), address);
|
Long deviceId = getDeviceIdBySerial(report.getSerialNumber());
|
||||||
|
List<ModbusConfig> modbusConfig = getConfigByAddress(report.getProductId(), deviceId, address);
|
||||||
if (CollectionUtils.isEmpty(modbusConfig)) {
|
if (CollectionUtils.isEmpty(modbusConfig)) {
|
||||||
log.warn("寄存器地址:{},不存在", address);
|
log.warn("寄存器地址:{},不存在", address);
|
||||||
return;
|
return;
|
||||||
@ -416,6 +420,30 @@ public class ModbusProtocol implements IProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据设备编号获取设备ID
|
||||||
|
*/
|
||||||
|
private Long getDeviceIdBySerial(String serialNumber) {
|
||||||
|
Device device = deviceMapper.selectDeviceBySerialNumber(serialNumber);
|
||||||
|
return device == null ? null : device.getDeviceId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据地址获取设备优先的配置列表
|
||||||
|
*/
|
||||||
|
private List<ModbusConfig> getConfigByAddress(Long productId, Long deviceId, String address) {
|
||||||
|
Map<Integer, List<ModbusConfig>> modbusConfigMap = modbusConfigCache.getModbusConfigCacheByDeviceId(productId, deviceId);
|
||||||
|
if (CollectionUtils.isEmpty(modbusConfigMap)) {
|
||||||
|
return java.util.Collections.emptyList();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
int ad = Integer.parseInt(address);
|
||||||
|
return modbusConfigMap.getOrDefault(ad, java.util.Collections.emptyList());
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return java.util.Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FunctionCallBackBo encode(MQSendMessageBo message) {
|
public FunctionCallBackBo encode(MQSendMessageBo message) {
|
||||||
FunctionCallBackBo callBack = new FunctionCallBackBo();
|
FunctionCallBackBo callBack = new FunctionCallBackBo();
|
||||||
@ -484,39 +512,26 @@ public class ModbusProtocol implements IProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取modbus地址
|
* 获取modbus起始地址
|
||||||
|
* 从设备级Redis缓存获取配置,返回最小寄存器地址
|
||||||
|
*
|
||||||
|
* @param productId 产品ID
|
||||||
|
* @param deviceId 设备ID
|
||||||
|
* @return 起始地址
|
||||||
*/
|
*/
|
||||||
private String getCacheModbusAddress(String serialNumber, int salveId, int code) {
|
private String getCacheModbusAddress(Long productId, Long deviceId) {
|
||||||
// String key = RedisKeyBuilder.buildModbusRuntimeCacheKey(serialNumber);
|
|
||||||
// Set<String> commandSet = redisCache.zRange(key, 0, -1);
|
|
||||||
//
|
|
||||||
// // 1. 遍历匹配指令
|
|
||||||
// for (String command : commandSet) {
|
|
||||||
// try {
|
|
||||||
// Mparams params = ModbusUtils.getModbusParams(command);
|
|
||||||
// redisCache.zRem(key, command); // 删除缓存
|
|
||||||
// if (params.getSlaveId() == salveId && params.getCode() == code) {
|
|
||||||
// return String.valueOf(params.getAddress());
|
|
||||||
// }
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// log.warn("解析指令异常: {}", e.getMessage());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 2. 无匹配时查询数据库
|
|
||||||
try {
|
try {
|
||||||
Device device = deviceMapper.selectDeviceBySerialNumber(serialNumber);
|
// 从设备级Redis缓存获取Modbus配置(key: buildModbusDeviceKey(deviceId))
|
||||||
if (device == null) return "0";
|
Map<Integer, List<ModbusConfig>> modbusConfigMap = modbusConfigCache.getModbusConfigCacheByDeviceId(productId, deviceId);
|
||||||
|
if (CollectionUtils.isEmpty(modbusConfigMap)) {
|
||||||
List<ModbusConfig> configs = modbusConfigMapper.selectModbusConfigListByProductId(device.getProductId());
|
return "0";
|
||||||
if (CollectionUtils.isEmpty(configs)) return "0";
|
}
|
||||||
|
return modbusConfigMap.keySet().stream()
|
||||||
return configs.stream()
|
.mapToInt(Integer::intValue)
|
||||||
.mapToInt(ModbusConfig::getAddress)
|
|
||||||
.min()
|
.min()
|
||||||
.orElse(0) + "";
|
.orElse(0) + "";
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("数据库查询异常: {}", e.getMessage());
|
log.error("获取Modbus配置缓存异常: {}", e.getMessage());
|
||||||
return "0";
|
return "0";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,9 @@ import com.fastbee.common.utils.StringUtils;
|
|||||||
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.IModbusConfigCache;
|
import com.fastbee.iot.cache.IModbusConfigCache;
|
||||||
|
import com.fastbee.iot.domain.Device;
|
||||||
import com.fastbee.iot.domain.ModbusConfig;
|
import com.fastbee.iot.domain.ModbusConfig;
|
||||||
|
import com.fastbee.iot.mapper.DeviceMapper;
|
||||||
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;
|
||||||
import com.fastbee.modbustcp.model.ModbusTcp;
|
import com.fastbee.modbustcp.model.ModbusTcp;
|
||||||
@ -57,6 +59,8 @@ public class ModbusTcpProtocol implements IProtocol {
|
|||||||
private IModbusConfigCache modbusConfigCache;
|
private IModbusConfigCache modbusConfigCache;
|
||||||
@Resource
|
@Resource
|
||||||
private ISubGatewayService subGatewayService;
|
private ISubGatewayService subGatewayService;
|
||||||
|
@Resource
|
||||||
|
private DeviceMapper deviceMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DeviceReport decode(DeviceData deviceData, String clientId) {
|
public DeviceReport decode(DeviceData deviceData, String clientId) {
|
||||||
@ -79,6 +83,7 @@ public class ModbusTcpProtocol implements IProtocol {
|
|||||||
matchSubDev(report, deviceData.getSerialNumber(), slaveId);
|
matchSubDev(report, deviceData.getSerialNumber(), slaveId);
|
||||||
String serialNumber = report.getSerialNumber();
|
String serialNumber = report.getSerialNumber();
|
||||||
Long productId = report.getProductId();
|
Long productId = report.getProductId();
|
||||||
|
Long deviceId = getDeviceIdBySerial(serialNumber);
|
||||||
ModbusCode modbusCode = ModbusCode.getInstance(code);
|
ModbusCode modbusCode = ModbusCode.getInstance(code);
|
||||||
List<ThingsModelSimpleItem> values = new ArrayList<>();
|
List<ThingsModelSimpleItem> values = new ArrayList<>();
|
||||||
switch (modbusCode) {
|
switch (modbusCode) {
|
||||||
@ -87,7 +92,7 @@ public class ModbusTcpProtocol implements IProtocol {
|
|||||||
//起始地址
|
//起始地址
|
||||||
ModbusTcp rawModbusTcpRtu = getCacheModbusAddress(deviceData.getSerialNumber(), message.getTransactionIdentifier());
|
ModbusTcp rawModbusTcpRtu = getCacheModbusAddress(deviceData.getSerialNumber(), message.getTransactionIdentifier());
|
||||||
//读线圈或读离散型寄存器处理
|
//读线圈或读离散型寄存器处理
|
||||||
handleRead0102(productId, message, rawModbusTcpRtu, values);
|
handleRead0102(productId, deviceId, message, rawModbusTcpRtu, values);
|
||||||
break;
|
break;
|
||||||
case Read03:
|
case Read03:
|
||||||
case Read04:
|
case Read04:
|
||||||
@ -98,7 +103,7 @@ public class ModbusTcpProtocol implements IProtocol {
|
|||||||
String addressStr = sourceData.substring(17, 20);
|
String addressStr = sourceData.substring(17, 20);
|
||||||
int address = Integer.parseInt(addressStr, 16);
|
int address = Integer.parseInt(addressStr, 16);
|
||||||
//读输入、保持寄存器
|
//读输入、保持寄存器
|
||||||
handleRead0304(productId, message, String.valueOf(address), values, hexDump);
|
handleRead0304(productId, deviceId, message, String.valueOf(address), values, hexDump);
|
||||||
break;
|
break;
|
||||||
case Write06:
|
case Write06:
|
||||||
case Write05:
|
case Write05:
|
||||||
@ -130,18 +135,19 @@ public class ModbusTcpProtocol implements IProtocol {
|
|||||||
* 读线圈或读离散型寄存器处理
|
* 读线圈或读离散型寄存器处理
|
||||||
*
|
*
|
||||||
* @param productId 产品id
|
* @param productId 产品id
|
||||||
|
* @param deviceId 设备id(覆盖)
|
||||||
* @param message 数据集合
|
* @param message 数据集合
|
||||||
* @param modbusTcpRtu 下发报文
|
* @param modbusTcpRtu 下发报文
|
||||||
* @param simpleItemList 返回的物模型值
|
* @param simpleItemList 返回的物模型值
|
||||||
*/
|
*/
|
||||||
private void handleRead0102(Long productId, ModbusTcp message, ModbusTcp modbusTcpRtu, List<ThingsModelSimpleItem> simpleItemList) {
|
private void handleRead0102(Long productId, Long deviceId, ModbusTcp message, ModbusTcp modbusTcpRtu, List<ThingsModelSimpleItem> simpleItemList) {
|
||||||
//字节数
|
//字节数
|
||||||
int bitCount = message.getBitCount();
|
int bitCount = message.getBitCount();
|
||||||
//字节数据集合
|
//字节数据集合
|
||||||
byte[] byteDatas = message.getBitData();
|
byte[] byteDatas = message.getBitData();
|
||||||
String hexDump = ByteBufUtil.hexDump(byteDatas);
|
String hexDump = ByteBufUtil.hexDump(byteDatas);
|
||||||
//处理多个的情况
|
//处理多个的情况
|
||||||
Map<Integer, List<ModbusConfig>> modbusConfigMap = modbusConfigCache.getModbusConfigCacheByProductId(productId);
|
Map<Integer, List<ModbusConfig>> modbusConfigMap = modbusConfigCache.getModbusConfigCacheByDeviceId(productId, deviceId);
|
||||||
if (CollectionUtils.isEmpty(modbusConfigMap)) {
|
if (CollectionUtils.isEmpty(modbusConfigMap)) {
|
||||||
log.warn("寄存器地址:{},不存在", modbusTcpRtu.getAddress());
|
log.warn("寄存器地址:{},不存在", modbusTcpRtu.getAddress());
|
||||||
return;
|
return;
|
||||||
@ -221,17 +227,18 @@ public class ModbusTcpProtocol implements IProtocol {
|
|||||||
* 处理读保持寄存器/输入寄存器
|
* 处理读保持寄存器/输入寄存器
|
||||||
*
|
*
|
||||||
* @param productId 产品id
|
* @param productId 产品id
|
||||||
|
* @param deviceId 设备id(覆盖)
|
||||||
* @param message 数据
|
* @param message 数据
|
||||||
* @param address 起始地址
|
* @param address 起始地址
|
||||||
* @param simpleItemList 返回的物模型值
|
* @param simpleItemList 返回的物模型值
|
||||||
* @param sourceStr 原始报文字符串
|
* @param sourceStr 原始报文字符串
|
||||||
*/
|
*/
|
||||||
private void handleRead0304(Long productId, ModbusTcp message, String address, List<ThingsModelSimpleItem> simpleItemList, String sourceStr) {
|
private void handleRead0304(Long productId, Long deviceId, ModbusTcp 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) {
|
||||||
//单个寄存器上报情况处理
|
//单个寄存器上报情况处理
|
||||||
List<ModbusConfig> modbusConfig = modbusConfigCache.getSingleModbusConfig(productId, address);
|
List<ModbusConfig> modbusConfig = getConfigByAddress(productId, deviceId, address);
|
||||||
if (CollectionUtils.isEmpty(modbusConfig)) {
|
if (CollectionUtils.isEmpty(modbusConfig)) {
|
||||||
log.warn("寄存器地址:{},不存在", address);
|
log.warn("寄存器地址:{},不存在", address);
|
||||||
return;
|
return;
|
||||||
@ -268,7 +275,7 @@ public class ModbusTcpProtocol implements IProtocol {
|
|||||||
//原数据字符串
|
//原数据字符串
|
||||||
String dataHex = sourceStr.substring(6, sourceStr.length() - 4);
|
String dataHex = sourceStr.substring(6, sourceStr.length() - 4);
|
||||||
//处理多个情况
|
//处理多个情况
|
||||||
Map<Integer, List<ModbusConfig>> modbusConfigMap = modbusConfigCache.getModbusConfigCacheByProductId(productId);
|
Map<Integer, List<ModbusConfig>> modbusConfigMap = modbusConfigCache.getModbusConfigCacheByDeviceId(productId, deviceId);
|
||||||
if (CollectionUtils.isEmpty(modbusConfigMap)) {
|
if (CollectionUtils.isEmpty(modbusConfigMap)) {
|
||||||
log.warn("寄存器数据不存在");
|
log.warn("寄存器数据不存在");
|
||||||
return;
|
return;
|
||||||
@ -329,7 +336,8 @@ public class ModbusTcpProtocol implements IProtocol {
|
|||||||
private void handleMsgReply(ModbusTcp message, DeviceReport report, ModbusCode code) {
|
private void handleMsgReply(ModbusTcp message, DeviceReport report, ModbusCode code) {
|
||||||
//单个寄存器上报情况处理
|
//单个寄存器上报情况处理
|
||||||
String address = message.getAddress() + "";
|
String address = message.getAddress() + "";
|
||||||
List<ModbusConfig> modbusConfig = modbusConfigCache.getSingleModbusConfig(report.getProductId(), address);
|
Long deviceId = getDeviceIdBySerial(report.getSerialNumber());
|
||||||
|
List<ModbusConfig> modbusConfig = getConfigByAddress(report.getProductId(), deviceId, address);
|
||||||
if (CollectionUtils.isEmpty(modbusConfig)) {
|
if (CollectionUtils.isEmpty(modbusConfig)) {
|
||||||
log.warn("寄存器地址:{},不存在", address);
|
log.warn("寄存器地址:{},不存在", address);
|
||||||
return;
|
return;
|
||||||
@ -372,6 +380,24 @@ public class ModbusTcpProtocol implements IProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Long getDeviceIdBySerial(String serialNumber) {
|
||||||
|
Device device = deviceMapper.selectDeviceBySerialNumber(serialNumber);
|
||||||
|
return device == null ? null : device.getDeviceId();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ModbusConfig> getConfigByAddress(Long productId, Long deviceId, String address) {
|
||||||
|
Map<Integer, List<ModbusConfig>> modbusConfigMap = modbusConfigCache.getModbusConfigCacheByDeviceId(productId, deviceId);
|
||||||
|
if (CollectionUtils.isEmpty(modbusConfigMap)) {
|
||||||
|
return java.util.Collections.emptyList();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
int ad = Integer.parseInt(address);
|
||||||
|
return modbusConfigMap.getOrDefault(ad, java.util.Collections.emptyList());
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return java.util.Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FunctionCallBackBo encode(MQSendMessageBo message) {
|
public FunctionCallBackBo encode(MQSendMessageBo message) {
|
||||||
FunctionCallBackBo callBack = new FunctionCallBackBo();
|
FunctionCallBackBo callBack = new FunctionCallBackBo();
|
||||||
|
|||||||
@ -11,7 +11,9 @@ import com.fastbee.common.core.thingsModel.ThingsModelSimpleItem;
|
|||||||
import com.fastbee.common.utils.DateUtils;
|
import com.fastbee.common.utils.DateUtils;
|
||||||
import com.fastbee.common.utils.modbus.BitUtils;
|
import com.fastbee.common.utils.modbus.BitUtils;
|
||||||
import com.fastbee.iot.cache.IModbusConfigCache;
|
import com.fastbee.iot.cache.IModbusConfigCache;
|
||||||
|
import com.fastbee.iot.domain.Device;
|
||||||
import com.fastbee.iot.domain.ModbusConfig;
|
import com.fastbee.iot.domain.ModbusConfig;
|
||||||
|
import com.fastbee.iot.mapper.DeviceMapper;
|
||||||
import com.fastbee.iot.model.ThingsModels.ThingsModelValueItem;
|
import com.fastbee.iot.model.ThingsModels.ThingsModelValueItem;
|
||||||
import com.fastbee.pakModbus.model.PakModbusRtu;
|
import com.fastbee.pakModbus.model.PakModbusRtu;
|
||||||
import com.fastbee.protocol.base.protocol.IProtocol;
|
import com.fastbee.protocol.base.protocol.IProtocol;
|
||||||
@ -80,6 +82,8 @@ public class ModbusRtuPakProtocol implements IProtocol {
|
|||||||
private ModbusRtuPakEncoder rtuPakEncoder;
|
private ModbusRtuPakEncoder rtuPakEncoder;
|
||||||
@Resource
|
@Resource
|
||||||
private IModbusConfigCache modbusConfigCache;
|
private IModbusConfigCache modbusConfigCache;
|
||||||
|
@Resource
|
||||||
|
private DeviceMapper deviceMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DeviceReport decode(DeviceData deviceData, String clientId) {
|
public DeviceReport decode(DeviceData deviceData, String clientId) {
|
||||||
@ -94,11 +98,14 @@ public class ModbusRtuPakProtocol implements IProtocol {
|
|||||||
return report;
|
return report;
|
||||||
}
|
}
|
||||||
PakModbusRtu message = rtuPakDecoder.decode(buf);
|
PakModbusRtu message = rtuPakDecoder.decode(buf);
|
||||||
|
Long deviceId = getDeviceIdBySerial(deviceData.getSerialNumber());
|
||||||
|
report.setSerialNumber(deviceData.getSerialNumber());
|
||||||
|
report.setProductId(deviceData.getProductId());
|
||||||
List<ThingsModelSimpleItem> values = new ArrayList<>();
|
List<ThingsModelSimpleItem> values = new ArrayList<>();
|
||||||
short[] data = message.getData();
|
short[] data = message.getData();
|
||||||
for (int i = 0; i < data.length; i++) {
|
for (int i = 0; i < data.length; i++) {
|
||||||
int address = message.getAddress() + i;
|
int address = message.getAddress() + i;
|
||||||
handleModbusDataType(deviceData.getProductId(), address + "", data[i] + "", values);
|
handleModbusDataType(deviceData.getProductId(), deviceId, address + "", data[i] + "", values);
|
||||||
}
|
}
|
||||||
report.setClientId(clientId);
|
report.setClientId(clientId);
|
||||||
report.setThingsModelSimpleItem(values);
|
report.setThingsModelSimpleItem(values);
|
||||||
@ -113,10 +120,10 @@ public class ModbusRtuPakProtocol implements IProtocol {
|
|||||||
* @param productId
|
* @param productId
|
||||||
* @param values
|
* @param values
|
||||||
*/
|
*/
|
||||||
private void handleModbusDataType(Long productId, String address, String value, List<ThingsModelSimpleItem> values) {
|
private void handleModbusDataType(Long productId, Long deviceId, String address, String value, List<ThingsModelSimpleItem> values) {
|
||||||
|
|
||||||
int nValue = Integer.parseInt(value);
|
int nValue = Integer.parseInt(value);
|
||||||
List<ModbusConfig> modbusConfig = modbusConfigCache.getSingleModbusConfig(productId, address);
|
List<ModbusConfig> modbusConfig = getConfigByAddress(productId, deviceId, address);
|
||||||
if (CollectionUtils.isEmpty(modbusConfig)) {
|
if (CollectionUtils.isEmpty(modbusConfig)) {
|
||||||
log.warn("寄存器地址:{},不存在", address);
|
log.warn("寄存器地址:{},不存在", address);
|
||||||
return;
|
return;
|
||||||
@ -158,6 +165,24 @@ public class ModbusRtuPakProtocol implements IProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Long getDeviceIdBySerial(String serialNumber) {
|
||||||
|
Device device = deviceMapper.selectDeviceBySerialNumber(serialNumber);
|
||||||
|
return device == null ? null : device.getDeviceId();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ModbusConfig> getConfigByAddress(Long productId, Long deviceId, String address) {
|
||||||
|
Map<Integer, List<ModbusConfig>> modbusConfigMap = modbusConfigCache.getModbusConfigCacheByDeviceId(productId, deviceId);
|
||||||
|
if (CollectionUtils.isEmpty(modbusConfigMap)) {
|
||||||
|
return java.util.Collections.emptyList();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
int ad = Integer.parseInt(address);
|
||||||
|
return modbusConfigMap.getOrDefault(ad, java.util.Collections.emptyList());
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return java.util.Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FunctionCallBackBo encode(MQSendMessageBo bo) {
|
public FunctionCallBackBo encode(MQSendMessageBo bo) {
|
||||||
|
|||||||
@ -13,7 +13,6 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public interface IModbusConfigCache {
|
public interface IModbusConfigCache {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取modbus参数 --返回 Map<String, ModbusConfig>
|
* 获取modbus参数 --返回 Map<String, ModbusConfig>
|
||||||
*
|
*
|
||||||
@ -46,4 +45,18 @@ public interface IModbusConfigCache {
|
|||||||
* @return ModbusConfig
|
* @return ModbusConfig
|
||||||
*/
|
*/
|
||||||
public List<ModbusConfig> getSingleModbusConfig(Long productId, String identify);
|
public List<ModbusConfig> getSingleModbusConfig(Long productId, String identify);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备维度的modbus参数(设备优先,产品兜底)
|
||||||
|
*
|
||||||
|
* @param productId 产品id(兜底用)
|
||||||
|
* @param deviceId 设备id(优先)
|
||||||
|
* @return address -> configs
|
||||||
|
*/
|
||||||
|
Map<Integer, List<ModbusConfig>> getModbusConfigCacheByDeviceId(Long productId, Long deviceId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新设备维度缓存
|
||||||
|
*/
|
||||||
|
Map<Integer, List<ModbusConfig>> setModbusConfigCacheByDeviceId(Long productId, Long deviceId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import com.fastbee.common.core.redis.RedisKeyBuilder;
|
|||||||
import com.fastbee.common.utils.StringUtils;
|
import com.fastbee.common.utils.StringUtils;
|
||||||
import com.fastbee.iot.cache.IModbusConfigCache;
|
import com.fastbee.iot.cache.IModbusConfigCache;
|
||||||
import com.fastbee.iot.domain.ModbusConfig;
|
import com.fastbee.iot.domain.ModbusConfig;
|
||||||
|
import com.fastbee.iot.service.IDeviceModbusConfigService;
|
||||||
import com.fastbee.iot.service.IModbusConfigService;
|
import com.fastbee.iot.service.IModbusConfigService;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
@ -27,6 +28,8 @@ public class ModbusConfigCacheImpl implements IModbusConfigCache {
|
|||||||
@Resource
|
@Resource
|
||||||
private IModbusConfigService modbusConfigService;
|
private IModbusConfigService modbusConfigService;
|
||||||
@Resource
|
@Resource
|
||||||
|
private IDeviceModbusConfigService deviceModbusConfigService;
|
||||||
|
@Resource
|
||||||
private RedisCache redisCache;
|
private RedisCache redisCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -104,4 +107,37 @@ public class ModbusConfigCacheImpl implements IModbusConfigCache {
|
|||||||
return modbusConfigList;
|
return modbusConfigList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Integer, List<ModbusConfig>> getModbusConfigCacheByDeviceId(Long productId, Long deviceId) {
|
||||||
|
// 现在仅按设备配置解析,不再回落到产品模板
|
||||||
|
if (deviceId == null) {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
String modbusKey = RedisKeyBuilder.buildModbusDeviceKey(deviceId);
|
||||||
|
Map<String, String> map = redisCache.hashEntity(modbusKey);
|
||||||
|
if (!CollectionUtils.isEmpty(map)) {
|
||||||
|
Map<Integer, List<ModbusConfig>> resultMap = new HashMap<>();
|
||||||
|
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||||
|
List<ModbusConfig> modbusConfigList = JSON.parseArray(entry.getValue(), ModbusConfig.class);
|
||||||
|
resultMap.put(Integer.parseInt(entry.getKey()), modbusConfigList);
|
||||||
|
}
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
|
return setModbusConfigCacheByDeviceId(productId, deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Integer, List<ModbusConfig>> setModbusConfigCacheByDeviceId(Long productId, Long deviceId) {
|
||||||
|
String modbusKey = RedisKeyBuilder.buildModbusDeviceKey(deviceId);
|
||||||
|
Map<String, String> resultMap = new HashMap<>();
|
||||||
|
// 仅使用设备维度的寄存器配置,不再合并产品模板
|
||||||
|
List<ModbusConfig> deviceConfigs = deviceModbusConfigService.selectDeviceConfigs(productId, deviceId);
|
||||||
|
Map<Integer, List<ModbusConfig>> listMap = deviceConfigs.stream().collect(Collectors.groupingBy(ModbusConfig::getAddress));
|
||||||
|
for (Map.Entry<Integer, List<ModbusConfig>> entry : listMap.entrySet()) {
|
||||||
|
String valueStr = JSONObject.toJSONString(entry.getValue());
|
||||||
|
resultMap.put(entry.getKey() + "", valueStr);
|
||||||
|
}
|
||||||
|
redisCache.hashPutAll(modbusKey, resultMap);
|
||||||
|
return listMap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,27 @@
|
|||||||
|
package com.fastbee.iot.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 设备级 modbus 配置对象 iot_device_modbus_config,
|
||||||
|
* 继承产品级 modbus 配置对象 iot_modbus_config,允许设备对产品模板做覆盖
|
||||||
|
*
|
||||||
|
* @author Sumuxi
|
||||||
|
* @date 2026/1/14
|
||||||
|
*/
|
||||||
|
@ApiModel(value = "DeviceModbusConfig", description = "设备modbus配置 iot_device_modbus_config")
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
@TableName("iot_device_modbus_config")
|
||||||
|
public class DeviceModbusConfig extends ModbusConfig {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** 所属设备id */
|
||||||
|
@ApiModelProperty(value = "所属设备id")
|
||||||
|
private Long deviceId;
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package com.fastbee.iot.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 设备modbus配置参数对象 iot_device_modbus_params,
|
||||||
|
* 继承产品modbus配置参数对象 iot_modbus_params
|
||||||
|
*
|
||||||
|
* @author Sumuxi
|
||||||
|
* @date 2026/1/14
|
||||||
|
*/
|
||||||
|
@ApiModel(value = "DeviceModbusParams", description = "设备modbus配置参数 iot_device_modbus_params")
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
@TableName("iot_device_modbus_params")
|
||||||
|
public class DeviceModbusParams extends ModbusParams {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** 所属设备id */
|
||||||
|
@ApiModelProperty(value = "所属设备id")
|
||||||
|
@TableField("device_id")
|
||||||
|
private Long deviceId;
|
||||||
|
}
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
package com.fastbee.iot.mapper;
|
||||||
|
|
||||||
|
import com.fastbee.iot.domain.DeviceModbusConfig;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备级 modbus 配置 Mapper
|
||||||
|
*/
|
||||||
|
public interface DeviceModbusConfigMapper {
|
||||||
|
|
||||||
|
DeviceModbusConfig selectDeviceModbusConfigById(Long id);
|
||||||
|
|
||||||
|
List<DeviceModbusConfig> selectDeviceModbusConfigList(DeviceModbusConfig config);
|
||||||
|
|
||||||
|
int insertDeviceModbusConfig(DeviceModbusConfig config);
|
||||||
|
|
||||||
|
int updateDeviceModbusConfig(DeviceModbusConfig config);
|
||||||
|
|
||||||
|
int deleteDeviceModbusConfigById(Long id);
|
||||||
|
|
||||||
|
int deleteDeviceModbusConfigByIds(Long[] ids);
|
||||||
|
|
||||||
|
List<DeviceModbusConfig> selectShortListByDeviceId(DeviceModbusConfig config);
|
||||||
|
|
||||||
|
DeviceModbusConfig selectByIdentify(@Param("deviceId") Long deviceId, @Param("identity") String identity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量插入设备modbus配置
|
||||||
|
*
|
||||||
|
* @param list 配置列表
|
||||||
|
* @return 插入行数
|
||||||
|
*/
|
||||||
|
int insertModbusConfigBatch(@Param("list") List<DeviceModbusConfig> list);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量更新设备modbus配置
|
||||||
|
*
|
||||||
|
* @param list 配置列表
|
||||||
|
* @return 更新行数
|
||||||
|
*/
|
||||||
|
int updateModbusConfigBatch(@Param("list") List<DeviceModbusConfig> list);
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package com.fastbee.iot.mapper;
|
||||||
|
|
||||||
|
import com.fastbee.framework.mybatis.mapper.BaseMapperX;
|
||||||
|
import com.fastbee.iot.domain.DeviceModbusParams;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备modbus配置参数Mapper接口
|
||||||
|
*
|
||||||
|
* @author Sumuxi
|
||||||
|
* @date 2026/1/14
|
||||||
|
*/
|
||||||
|
public interface DeviceModbusParamsMapper extends BaseMapperX<DeviceModbusParams> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据设备id获取modbus配置参数
|
||||||
|
*
|
||||||
|
* @param deviceId 设备id
|
||||||
|
* @return DeviceModbusParams
|
||||||
|
*/
|
||||||
|
DeviceModbusParams getByDeviceId(@Param("deviceId") Long deviceId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据设备id删除配置
|
||||||
|
*
|
||||||
|
* @param deviceId 设备id
|
||||||
|
* @return 影响行数
|
||||||
|
*/
|
||||||
|
int deleteByDeviceId(@Param("deviceId") Long deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
package com.fastbee.iot.model.modbus;
|
||||||
|
|
||||||
|
import com.fastbee.iot.domain.DeviceModbusConfig;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备级 modbus 配置批量提交 VO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class DeviceModbusConfigVO {
|
||||||
|
|
||||||
|
/** 产品id */
|
||||||
|
private Long productId;
|
||||||
|
|
||||||
|
/** 设备id */
|
||||||
|
private Long deviceId;
|
||||||
|
|
||||||
|
/** modbus配置列表 */
|
||||||
|
private List<DeviceModbusConfig> configList;
|
||||||
|
|
||||||
|
/** 删除的id集合 */
|
||||||
|
private Long[] delIds;
|
||||||
|
}
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
package com.fastbee.iot.service;
|
||||||
|
|
||||||
|
import com.fastbee.iot.domain.DeviceModbusConfig;
|
||||||
|
import com.fastbee.iot.domain.ModbusConfig;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备级 modbus 配置 Service
|
||||||
|
*/
|
||||||
|
public interface IDeviceModbusConfigService {
|
||||||
|
|
||||||
|
DeviceModbusConfig selectDeviceModbusConfigById(Long id);
|
||||||
|
|
||||||
|
List<DeviceModbusConfig> selectDeviceModbusConfigList(DeviceModbusConfig config);
|
||||||
|
|
||||||
|
int insertDeviceModbusConfig(DeviceModbusConfig config);
|
||||||
|
|
||||||
|
int updateDeviceModbusConfig(DeviceModbusConfig config);
|
||||||
|
|
||||||
|
int deleteDeviceModbusConfigByIds(Long[] ids);
|
||||||
|
|
||||||
|
int deleteDeviceModbusConfigById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量新增或更新设备级配置
|
||||||
|
*/
|
||||||
|
void addOrUpDeviceModbusConfigBatch(List<DeviceModbusConfig> configList, Long productId, Long deviceId, Long[] delIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备级简要字段
|
||||||
|
*/
|
||||||
|
List<DeviceModbusConfig> selectShortListByDeviceId(DeviceModbusConfig config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据设备和标识符获取配置
|
||||||
|
*/
|
||||||
|
DeviceModbusConfig selectByIdentify(Long deviceId, String identity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合并设备覆盖后的最终配置列表(转为 ModbusConfig 供解析和缓存)
|
||||||
|
*/
|
||||||
|
List<ModbusConfig> selectMergedConfig(Long productId, Long deviceId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅设备维度的配置列表(转为 ModbusConfig 供解析和缓存)
|
||||||
|
*/
|
||||||
|
List<ModbusConfig> selectDeviceConfigs(Long productId, Long deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,102 @@
|
|||||||
|
package com.fastbee.iot.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.fastbee.iot.domain.DeviceModbusParams;
|
||||||
|
import com.fastbee.iot.domain.ModbusParams;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备modbus配置参数Service接口
|
||||||
|
*
|
||||||
|
* @author Sumuxi
|
||||||
|
* @date 2026/1/14
|
||||||
|
*/
|
||||||
|
public interface IDeviceModbusParamsService extends IService<DeviceModbusParams> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据设备id获取modbus配置参数
|
||||||
|
*
|
||||||
|
* @param deviceId 设备id
|
||||||
|
* @return DeviceModbusParams
|
||||||
|
*/
|
||||||
|
DeviceModbusParams getByDeviceId(Long deviceId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据设备id获取modbus配置参数(带缓存)
|
||||||
|
*
|
||||||
|
* @param deviceId 设备id
|
||||||
|
* @return DeviceModbusParams
|
||||||
|
*/
|
||||||
|
DeviceModbusParams getByDeviceIdWithCache(Long deviceId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备的有效modbus配置参数(自动获取productId)
|
||||||
|
* 如果设备级配置存在则返回设备级,否则返回产品级默认配置
|
||||||
|
* 推荐使用此方法,便于平滑切换
|
||||||
|
*
|
||||||
|
* @param deviceId 设备id
|
||||||
|
* @return ModbusParams
|
||||||
|
*/
|
||||||
|
ModbusParams getEffectiveParams(Long deviceId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备的有效modbus配置参数
|
||||||
|
* 如果设备级配置存在则返回设备级,否则返回产品级默认配置
|
||||||
|
*
|
||||||
|
* @param deviceId 设备id
|
||||||
|
* @param productId 产品id
|
||||||
|
* @return ModbusParams
|
||||||
|
*/
|
||||||
|
ModbusParams getEffectiveParams(Long deviceId, Long productId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增设备modbus配置参数
|
||||||
|
*
|
||||||
|
* @param params 设备modbus配置参数
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
Boolean insertParams(DeviceModbusParams params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增或更新设备modbus配置参数
|
||||||
|
*
|
||||||
|
* @param params 设备modbus配置参数
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean addOrUpdate(DeviceModbusParams params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改设备modbus配置参数
|
||||||
|
*
|
||||||
|
* @param params 设备modbus配置参数
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
Boolean updateParams(DeviceModbusParams params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据设备id删除配置
|
||||||
|
*
|
||||||
|
* @param deviceId 设备id
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
Boolean deleteByDeviceId(Long deviceId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除设备modbus配置参数
|
||||||
|
*
|
||||||
|
* @param ids 待删除的主键集合
|
||||||
|
* @param isValid 是否进行有效性校验
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
Boolean deleteByIds(Long[] ids, Boolean isValid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据设备id列表查询配置列表
|
||||||
|
*
|
||||||
|
* @param deviceIds 设备id列表
|
||||||
|
* @return 配置列表
|
||||||
|
*/
|
||||||
|
List<DeviceModbusParams> selectByDeviceIds(List<Long> deviceIds);
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,164 @@
|
|||||||
|
package com.fastbee.iot.service.impl;
|
||||||
|
|
||||||
|
import com.fastbee.common.exception.ServiceException;
|
||||||
|
import com.fastbee.common.utils.DateUtils;
|
||||||
|
import com.fastbee.common.utils.SecurityUtils;
|
||||||
|
import com.fastbee.iot.domain.DeviceModbusConfig;
|
||||||
|
import com.fastbee.iot.domain.ModbusConfig;
|
||||||
|
import com.fastbee.iot.mapper.DeviceModbusConfigMapper;
|
||||||
|
import com.fastbee.iot.mapper.ModbusConfigMapper;
|
||||||
|
import com.fastbee.iot.service.IDeviceModbusConfigService;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备级 modbus 配置 Service 实现
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class DeviceModbusConfigServiceImpl implements IDeviceModbusConfigService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DeviceModbusConfigMapper deviceModbusConfigMapper;
|
||||||
|
@Resource
|
||||||
|
private ModbusConfigMapper modbusConfigMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeviceModbusConfig selectDeviceModbusConfigById(Long id) {
|
||||||
|
return deviceModbusConfigMapper.selectDeviceModbusConfigById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DeviceModbusConfig> selectDeviceModbusConfigList(DeviceModbusConfig config) {
|
||||||
|
return deviceModbusConfigMapper.selectDeviceModbusConfigList(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int insertDeviceModbusConfig(DeviceModbusConfig config) {
|
||||||
|
config.setCreateTime(DateUtils.getNowDate());
|
||||||
|
return deviceModbusConfigMapper.insertDeviceModbusConfig(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int updateDeviceModbusConfig(DeviceModbusConfig config) {
|
||||||
|
config.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
return deviceModbusConfigMapper.updateDeviceModbusConfig(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteDeviceModbusConfigByIds(Long[] ids) {
|
||||||
|
return deviceModbusConfigMapper.deleteDeviceModbusConfigByIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteDeviceModbusConfigById(Long id) {
|
||||||
|
return deviceModbusConfigMapper.deleteDeviceModbusConfigById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void addOrUpDeviceModbusConfigBatch(List<DeviceModbusConfig> configList, Long productId, Long deviceId, Long[] delIds) {
|
||||||
|
if (Objects.isNull(productId)) {
|
||||||
|
throw new ServiceException("产品id不能为空");
|
||||||
|
}
|
||||||
|
if (Objects.isNull(deviceId)) {
|
||||||
|
throw new ServiceException("设备id不能为空");
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isEmpty(configList)) {
|
||||||
|
throw new ServiceException("modbus配置数据不能为空");
|
||||||
|
}
|
||||||
|
if (delIds != null && delIds.length > 0) {
|
||||||
|
this.deleteDeviceModbusConfigByIds(delIds);
|
||||||
|
}
|
||||||
|
List<DeviceModbusConfig> insertModbusConfigs = new ArrayList<>();
|
||||||
|
List<DeviceModbusConfig> updateModbusConfigs = new ArrayList<>();
|
||||||
|
for (DeviceModbusConfig config : configList) {
|
||||||
|
config.setProductId(productId);
|
||||||
|
config.setDeviceId(deviceId);
|
||||||
|
if (Objects.isNull(config.getId())) {
|
||||||
|
config.setCreateBy(SecurityUtils.getUsername());
|
||||||
|
config.setCreateTime(DateUtils.getNowDate());
|
||||||
|
//this.insertDeviceModbusConfig(config);
|
||||||
|
insertModbusConfigs.add(config);
|
||||||
|
} else {
|
||||||
|
config.setUpdateBy(SecurityUtils.getUsername());
|
||||||
|
config.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
//this.updateDeviceModbusConfig(config);
|
||||||
|
updateModbusConfigs.add(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!CollectionUtils.isEmpty(insertModbusConfigs)) {
|
||||||
|
deviceModbusConfigMapper.insertModbusConfigBatch(insertModbusConfigs);
|
||||||
|
}
|
||||||
|
if (!CollectionUtils.isEmpty(updateModbusConfigs)) {
|
||||||
|
deviceModbusConfigMapper.updateModbusConfigBatch(updateModbusConfigs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DeviceModbusConfig> selectShortListByDeviceId(DeviceModbusConfig config) {
|
||||||
|
return deviceModbusConfigMapper.selectShortListByDeviceId(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeviceModbusConfig selectByIdentify(Long deviceId, String identity) {
|
||||||
|
return deviceModbusConfigMapper.selectByIdentify(deviceId, identity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ModbusConfig> selectMergedConfig(Long productId, Long deviceId) {
|
||||||
|
List<DeviceModbusConfig> deviceList = selectShortListByDeviceId(buildShortConfig(deviceId, productId, null));
|
||||||
|
List<ModbusConfig> productList = Collections.emptyList();
|
||||||
|
if (productId != null) {
|
||||||
|
ModbusConfig p = new ModbusConfig();
|
||||||
|
p.setProductId(productId);
|
||||||
|
productList = new ArrayList<>(Optional.ofNullable(modbusConfigMapper.selectShortListByProductId(p)).orElse(Collections.emptyList()));
|
||||||
|
}
|
||||||
|
Map<String, ModbusConfig> merged = new LinkedHashMap<>();
|
||||||
|
// 产品模板
|
||||||
|
for (ModbusConfig config : productList) {
|
||||||
|
merged.put(config.getIdentifier(), config);
|
||||||
|
}
|
||||||
|
// 设备覆盖(同 identifier 覆盖产品)
|
||||||
|
for (DeviceModbusConfig deviceConfig : deviceList) {
|
||||||
|
merged.put(deviceConfig.getIdentifier(), convert(deviceConfig));
|
||||||
|
}
|
||||||
|
return new ArrayList<>(merged.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
private DeviceModbusConfig buildShortConfig(Long deviceId, Long productId, Integer type) {
|
||||||
|
DeviceModbusConfig config = new DeviceModbusConfig();
|
||||||
|
config.setDeviceId(deviceId);
|
||||||
|
config.setProductId(productId);
|
||||||
|
config.setType(type);
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于兼容 cache 逻辑的转换
|
||||||
|
*/
|
||||||
|
private ModbusConfig convert(DeviceModbusConfig config) {
|
||||||
|
ModbusConfig target = new ModbusConfig();
|
||||||
|
BeanUtils.copyProperties(config, target);
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ModbusConfig> selectDeviceConfigs(Long productId, Long deviceId) {
|
||||||
|
List<DeviceModbusConfig> deviceList = selectShortListByDeviceId(buildShortConfig(deviceId, productId, null));
|
||||||
|
return deviceList.stream().map(this::convert).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 供单元测试或特殊场景调用,避免直接依赖 service 造成循环
|
||||||
|
*/
|
||||||
|
protected List<ModbusConfig> selectProductShortList(ModbusConfig config) {
|
||||||
|
return modbusConfigMapper.selectShortListByProductId(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,131 @@
|
|||||||
|
package com.fastbee.iot.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.fastbee.common.utils.DateUtils;
|
||||||
|
import com.fastbee.common.utils.SecurityUtils;
|
||||||
|
import com.fastbee.iot.domain.Device;
|
||||||
|
import com.fastbee.iot.domain.DeviceModbusParams;
|
||||||
|
import com.fastbee.iot.domain.ModbusParams;
|
||||||
|
import com.fastbee.iot.mapper.DeviceMapper;
|
||||||
|
import com.fastbee.iot.mapper.DeviceModbusParamsMapper;
|
||||||
|
import com.fastbee.iot.service.IDeviceModbusParamsService;
|
||||||
|
import com.fastbee.iot.service.IModbusParamsService;
|
||||||
|
import org.springframework.cache.annotation.CacheEvict;
|
||||||
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备modbus配置参数Service业务层处理
|
||||||
|
*
|
||||||
|
* @author Sumuxi
|
||||||
|
* @date 2026/1/14
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class DeviceModbusParamsServiceImpl extends ServiceImpl<DeviceModbusParamsMapper, DeviceModbusParams>
|
||||||
|
implements IDeviceModbusParamsService {
|
||||||
|
|
||||||
|
private static final String CACHE_NAME = "DeviceModbusParams";
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IModbusParamsService modbusParamsService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DeviceMapper deviceMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeviceModbusParams getByDeviceId(Long deviceId) {
|
||||||
|
return baseMapper.getByDeviceId(deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Cacheable(cacheNames = CACHE_NAME, key = "#deviceId")
|
||||||
|
public DeviceModbusParams getByDeviceIdWithCache(Long deviceId) {
|
||||||
|
return baseMapper.getByDeviceId(deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ModbusParams getEffectiveParams(Long deviceId) {
|
||||||
|
// 优先返回设备级配置
|
||||||
|
DeviceModbusParams deviceParams = this.getByDeviceId(deviceId);
|
||||||
|
if (Objects.nonNull(deviceParams)) {
|
||||||
|
return deviceParams;
|
||||||
|
}
|
||||||
|
// 查询设备获取productId,回退到产品级默认配置
|
||||||
|
Device device = deviceMapper.selectDeviceByDeviceId(deviceId);
|
||||||
|
if (Objects.nonNull(device) && Objects.nonNull(device.getProductId())) {
|
||||||
|
return modbusParamsService.getModbusParamsByProductId(device.getProductId());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ModbusParams getEffectiveParams(Long deviceId, Long productId) {
|
||||||
|
// 优先返回设备级配置
|
||||||
|
DeviceModbusParams deviceParams = this.getByDeviceId(deviceId);
|
||||||
|
if (Objects.nonNull(deviceParams)) {
|
||||||
|
return deviceParams;
|
||||||
|
}
|
||||||
|
// 返回产品级默认配置
|
||||||
|
return modbusParamsService.getModbusParamsByProductId(productId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean insertParams(DeviceModbusParams params) {
|
||||||
|
params.setCreateBy(SecurityUtils.getUsername());
|
||||||
|
params.setCreateTime(DateUtils.getNowDate());
|
||||||
|
return this.save(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CacheEvict(cacheNames = CACHE_NAME, key = "#params.deviceId")
|
||||||
|
public boolean addOrUpdate(DeviceModbusParams params) {
|
||||||
|
Long deviceId = params.getDeviceId();
|
||||||
|
DeviceModbusParams existing = this.getByDeviceId(deviceId);
|
||||||
|
if (Objects.nonNull(existing)) {
|
||||||
|
params.setId(existing.getId());
|
||||||
|
params.setUpdateBy(SecurityUtils.getUsername());
|
||||||
|
params.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
} else {
|
||||||
|
params.setCreateBy(SecurityUtils.getUsername());
|
||||||
|
params.setCreateTime(DateUtils.getNowDate());
|
||||||
|
}
|
||||||
|
return this.saveOrUpdate(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CacheEvict(cacheNames = CACHE_NAME, key = "#params.deviceId")
|
||||||
|
public Boolean updateParams(DeviceModbusParams params) {
|
||||||
|
params.setUpdateBy(SecurityUtils.getUsername());
|
||||||
|
params.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
return this.updateById(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CacheEvict(cacheNames = CACHE_NAME, key = "#deviceId")
|
||||||
|
public Boolean deleteByDeviceId(Long deviceId) {
|
||||||
|
return baseMapper.deleteByDeviceId(deviceId) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CacheEvict(cacheNames = CACHE_NAME, allEntries = true)
|
||||||
|
public Boolean deleteByIds(Long[] ids, Boolean isValid) {
|
||||||
|
if (isValid) {
|
||||||
|
// 可以在此添加业务校验逻辑
|
||||||
|
}
|
||||||
|
return this.removeByIds(Arrays.asList(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DeviceModbusParams> selectByDeviceIds(List<Long> deviceIds) {
|
||||||
|
LambdaQueryWrapper<DeviceModbusParams> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.in(DeviceModbusParams::getDeviceId, deviceIds);
|
||||||
|
return baseMapper.selectList(queryWrapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -109,7 +109,7 @@ public class ModbusConfigServiceImpl implements IModbusConfigService {
|
|||||||
assert !Objects.isNull(productId) : "产品id不能为空";
|
assert !Objects.isNull(productId) : "产品id不能为空";
|
||||||
assert !CollectionUtils.isEmpty(modbusConfigList) : "modbus配置数据不能为空";
|
assert !CollectionUtils.isEmpty(modbusConfigList) : "modbus配置数据不能为空";
|
||||||
if (!CollectionUtils.isEmpty(Arrays.asList(ids))) {
|
if (!CollectionUtils.isEmpty(Arrays.asList(ids))) {
|
||||||
//要删除的id集合不为空,则先进行删除操作
|
// 要删除的id集合不为空,则先进行删除操作
|
||||||
this.deleteModbusConfigByIds(ids);
|
this.deleteModbusConfigByIds(ids);
|
||||||
}
|
}
|
||||||
for (ModbusConfig config : modbusConfigList) {
|
for (ModbusConfig config : modbusConfigList) {
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import com.fastbee.iot.mapper.SubGatewayMapper;
|
|||||||
import com.fastbee.iot.model.gateWay.GateSubDeviceVO;
|
import com.fastbee.iot.model.gateWay.GateSubDeviceVO;
|
||||||
import com.fastbee.iot.model.gateWay.SubDeviceAddVO;
|
import com.fastbee.iot.model.gateWay.SubDeviceAddVO;
|
||||||
import com.fastbee.iot.model.gateWay.SubDeviceListVO;
|
import com.fastbee.iot.model.gateWay.SubDeviceListVO;
|
||||||
|
import com.fastbee.iot.service.IDeviceModbusParamsService;
|
||||||
import com.fastbee.iot.service.IDeviceService;
|
import com.fastbee.iot.service.IDeviceService;
|
||||||
import com.fastbee.iot.service.IModbusParamsService;
|
import com.fastbee.iot.service.IModbusParamsService;
|
||||||
import com.fastbee.iot.service.ISubGatewayService;
|
import com.fastbee.iot.service.ISubGatewayService;
|
||||||
@ -33,6 +34,8 @@ public class SubGatewayServiceImpl implements ISubGatewayService {
|
|||||||
private SubGatewayMapper gatewayMapper;
|
private SubGatewayMapper gatewayMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private IModbusParamsService modbusParamsService;
|
private IModbusParamsService modbusParamsService;
|
||||||
|
@Resource
|
||||||
|
private IDeviceModbusParamsService deviceModbusParamsService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询网关与子设备关联
|
* 查询网关与子设备关联
|
||||||
@ -125,7 +128,8 @@ public class SubGatewayServiceImpl implements ISubGatewayService {
|
|||||||
List<SubGateway> list = new ArrayList<>();
|
List<SubGateway> list = new ArrayList<>();
|
||||||
if (subDeviceIds.length > 0) {
|
if (subDeviceIds.length > 0) {
|
||||||
for (Long subDeviceId : subDeviceIds) {
|
for (Long subDeviceId : subDeviceIds) {
|
||||||
ModbusParams modbusParams = modbusParamsService.getModbusParamsByDeviceId(subDeviceId);
|
// 优先使用设备级配置,无则回退到产品级配置
|
||||||
|
ModbusParams modbusParams = deviceModbusParamsService.getEffectiveParams(subDeviceId);
|
||||||
SubGateway subGateway = new SubGateway();
|
SubGateway subGateway = new SubGateway();
|
||||||
subGateway.setSubDeviceId(subDeviceId);
|
subGateway.setSubDeviceId(subDeviceId);
|
||||||
subGateway.setGwDeviceId(gwDeviceId);
|
subGateway.setGwDeviceId(gwDeviceId);
|
||||||
|
|||||||
@ -0,0 +1,406 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.fastbee.iot.mapper.DeviceModbusConfigMapper">
|
||||||
|
<resultMap id="DeviceModbusConfigResult" type="com.fastbee.iot.domain.DeviceModbusConfig">
|
||||||
|
<result property="id" column="id"/>
|
||||||
|
<result property="deviceId" column="device_id"/>
|
||||||
|
<result property="productId" column="product_id"/>
|
||||||
|
<result property="identifier" column="identifier"/>
|
||||||
|
<result property="slave" column="slave"/>
|
||||||
|
<result property="address" column="address"/>
|
||||||
|
<result property="isReadonly" column="is_readonly"/>
|
||||||
|
<result property="dataType" column="data_type"/>
|
||||||
|
<result property="quantity" column="quantity"/>
|
||||||
|
<result property="type" column="type"/>
|
||||||
|
<result property="bitOrder" column="bit_order"/>
|
||||||
|
<result property="sort" column="sort"/>
|
||||||
|
<result property="delFlag" column="del_flag"/>
|
||||||
|
<result property="createBy" column="create_by"/>
|
||||||
|
<result property="createTime" column="create_time"/>
|
||||||
|
<result property="updateBy" column="update_by"/>
|
||||||
|
<result property="updateTime" column="update_time"/>
|
||||||
|
<result property="remark" column="remark"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<sql id="selectDeviceModbusConfigVo">
|
||||||
|
select id,
|
||||||
|
device_id,
|
||||||
|
product_id,
|
||||||
|
identifier,
|
||||||
|
slave,
|
||||||
|
address,
|
||||||
|
is_readonly,
|
||||||
|
data_type,
|
||||||
|
quantity,
|
||||||
|
type,
|
||||||
|
bit_order,
|
||||||
|
sort,
|
||||||
|
del_flag,
|
||||||
|
create_by,
|
||||||
|
create_time,
|
||||||
|
update_by,
|
||||||
|
update_time,
|
||||||
|
remark
|
||||||
|
from iot_device_modbus_config
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<select id="selectDeviceModbusConfigList" parameterType="com.fastbee.iot.domain.DeviceModbusConfig"
|
||||||
|
resultMap="DeviceModbusConfigResult">
|
||||||
|
<include refid="selectDeviceModbusConfigVo"/>
|
||||||
|
<where>
|
||||||
|
<if test="identifier != null and identifier != ''">
|
||||||
|
and identifier = #{identifier}
|
||||||
|
</if>
|
||||||
|
<if test="address != null ">
|
||||||
|
and address = #{address}
|
||||||
|
</if>
|
||||||
|
<if test="isReadonly != null ">
|
||||||
|
and is_readonly = #{isReadonly}
|
||||||
|
</if>
|
||||||
|
<if test="dataType != null and dataType != ''">
|
||||||
|
and data_type = #{dataType}
|
||||||
|
</if>
|
||||||
|
<if test="quantity != null ">
|
||||||
|
and quantity = #{quantity}
|
||||||
|
</if>
|
||||||
|
<if test="type != null ">
|
||||||
|
and type = #{type}
|
||||||
|
</if>
|
||||||
|
<if test="productId != null ">
|
||||||
|
and product_id = #{productId}
|
||||||
|
</if>
|
||||||
|
<if test="deviceId != null ">
|
||||||
|
and device_id = #{deviceId}
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
order by sort,id
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectDeviceModbusConfigById" parameterType="Long" resultMap="DeviceModbusConfigResult">
|
||||||
|
<include refid="selectDeviceModbusConfigVo"/>
|
||||||
|
where id = #{id}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<insert id="insertDeviceModbusConfig" parameterType="com.fastbee.iot.domain.DeviceModbusConfig">
|
||||||
|
insert into iot_device_modbus_config
|
||||||
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">
|
||||||
|
id,
|
||||||
|
</if>
|
||||||
|
<if test="deviceId != null">
|
||||||
|
device_id,
|
||||||
|
</if>
|
||||||
|
<if test="productId != null">
|
||||||
|
product_id,
|
||||||
|
</if>
|
||||||
|
<if test="identifier != null and identifier != ''">
|
||||||
|
identifier,
|
||||||
|
</if>
|
||||||
|
<if test="slave != null">
|
||||||
|
slave,
|
||||||
|
</if>
|
||||||
|
<if test="address != null">
|
||||||
|
address,
|
||||||
|
</if>
|
||||||
|
<if test="isReadonly != null">
|
||||||
|
is_readonly,
|
||||||
|
</if>
|
||||||
|
<if test="dataType != null and dataType != ''">
|
||||||
|
data_type,
|
||||||
|
</if>
|
||||||
|
<if test="quantity != null">
|
||||||
|
quantity,
|
||||||
|
</if>
|
||||||
|
<if test="type != null">
|
||||||
|
type,
|
||||||
|
</if>
|
||||||
|
<if test="delFlag != null">
|
||||||
|
del_flag,
|
||||||
|
</if>
|
||||||
|
<if test="createBy != null">
|
||||||
|
create_by,
|
||||||
|
</if>
|
||||||
|
<if test="createTime != null">
|
||||||
|
create_time,
|
||||||
|
</if>
|
||||||
|
<if test="updateBy != null">
|
||||||
|
update_by,
|
||||||
|
</if>
|
||||||
|
<if test="updateTime != null">
|
||||||
|
update_time,
|
||||||
|
</if>
|
||||||
|
<if test="remark != null">
|
||||||
|
remark,
|
||||||
|
</if>
|
||||||
|
<if test="sort != null">
|
||||||
|
sort,
|
||||||
|
</if>
|
||||||
|
<if test="bitOrder != null">
|
||||||
|
bit_order,
|
||||||
|
</if>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="id != null">
|
||||||
|
#{id},
|
||||||
|
</if>
|
||||||
|
<if test="deviceId != null">
|
||||||
|
#{deviceId},
|
||||||
|
</if>
|
||||||
|
<if test="productId != null">
|
||||||
|
#{productId},
|
||||||
|
</if>
|
||||||
|
<if test="identifier != null and identifier != ''">
|
||||||
|
#{identifier},
|
||||||
|
</if>
|
||||||
|
<if test="slave != null">
|
||||||
|
#{slave},
|
||||||
|
</if>
|
||||||
|
<if test="address != null">
|
||||||
|
#{address},
|
||||||
|
</if>
|
||||||
|
<if test="isReadonly != null">
|
||||||
|
#{isReadonly},
|
||||||
|
</if>
|
||||||
|
<if test="dataType != null and dataType != ''">
|
||||||
|
#{dataType},
|
||||||
|
</if>
|
||||||
|
<if test="quantity != null">
|
||||||
|
#{quantity},
|
||||||
|
</if>
|
||||||
|
<if test="type != null">
|
||||||
|
#{type},
|
||||||
|
</if>
|
||||||
|
<if test="delFlag != null">
|
||||||
|
#{delFlag},
|
||||||
|
</if>
|
||||||
|
<if test="createBy != null">
|
||||||
|
#{createBy},
|
||||||
|
</if>
|
||||||
|
<if test="createTime != null">
|
||||||
|
#{createTime},
|
||||||
|
</if>
|
||||||
|
<if test="updateBy != null">
|
||||||
|
#{updateBy},
|
||||||
|
</if>
|
||||||
|
<if test="updateTime != null">
|
||||||
|
#{updateTime},
|
||||||
|
</if>
|
||||||
|
<if test="remark != null">
|
||||||
|
#{remark},
|
||||||
|
</if>
|
||||||
|
<if test="sort != null">
|
||||||
|
#{sort},
|
||||||
|
</if>
|
||||||
|
<if test="bitOrder != null">
|
||||||
|
#{bitOrder},
|
||||||
|
</if>
|
||||||
|
</trim>
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<update id="updateDeviceModbusConfig" parameterType="com.fastbee.iot.domain.DeviceModbusConfig">
|
||||||
|
update iot_device_modbus_config
|
||||||
|
<trim prefix="SET" suffixOverrides=",">
|
||||||
|
<if test="deviceId != null">
|
||||||
|
device_id = #{deviceId},
|
||||||
|
</if>
|
||||||
|
<if test="productId != null">
|
||||||
|
product_id = #{productId},
|
||||||
|
</if>
|
||||||
|
<if test="identifier != null and identifier != ''">
|
||||||
|
identifier = #{identifier},
|
||||||
|
</if>
|
||||||
|
<if test="slave != null">
|
||||||
|
slave = #{slave},
|
||||||
|
</if>
|
||||||
|
<if test="address != null">
|
||||||
|
address = #{address},
|
||||||
|
</if>
|
||||||
|
<if test="isReadonly != null">
|
||||||
|
is_readonly = #{isReadonly},
|
||||||
|
</if>
|
||||||
|
<if test="dataType != null and dataType != ''">
|
||||||
|
data_type = #{dataType},
|
||||||
|
</if>
|
||||||
|
<if test="quantity != null">
|
||||||
|
quantity = #{quantity},
|
||||||
|
</if>
|
||||||
|
<if test="type != null">
|
||||||
|
type = #{type},
|
||||||
|
</if>
|
||||||
|
<if test="delFlag != null">
|
||||||
|
del_flag = #{delFlag},
|
||||||
|
</if>
|
||||||
|
<if test="createBy != null">
|
||||||
|
create_by = #{createBy},
|
||||||
|
</if>
|
||||||
|
<if test="createTime != null">
|
||||||
|
create_time = #{createTime},
|
||||||
|
</if>
|
||||||
|
<if test="updateBy != null">
|
||||||
|
update_by = #{updateBy},
|
||||||
|
</if>
|
||||||
|
<if test="updateTime != null">
|
||||||
|
update_time = #{updateTime},
|
||||||
|
</if>
|
||||||
|
<if test="remark != null">
|
||||||
|
remark = #{remark},
|
||||||
|
</if>
|
||||||
|
<if test="sort != null">
|
||||||
|
sort = #{sort},
|
||||||
|
</if>
|
||||||
|
<if test="bitOrder != null">
|
||||||
|
bit_order = #{bitOrder},
|
||||||
|
</if>
|
||||||
|
</trim>
|
||||||
|
where id = #{id}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<delete id="deleteDeviceModbusConfigById" parameterType="Long">
|
||||||
|
delete
|
||||||
|
from iot_device_modbus_config
|
||||||
|
where id = #{id}
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<delete id="deleteDeviceModbusConfigByIds" parameterType="Long">
|
||||||
|
delete from iot_device_modbus_config where id in
|
||||||
|
<foreach collection="array" item="id" open="(" separator="," close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<select id="selectShortListByDeviceId" parameterType="com.fastbee.iot.domain.DeviceModbusConfig"
|
||||||
|
resultMap="DeviceModbusConfigResult">
|
||||||
|
select id,
|
||||||
|
device_id,
|
||||||
|
product_id,
|
||||||
|
identifier,
|
||||||
|
slave,
|
||||||
|
address,
|
||||||
|
bit_order,
|
||||||
|
is_readonly,
|
||||||
|
data_type,
|
||||||
|
quantity,
|
||||||
|
type,
|
||||||
|
sort
|
||||||
|
from iot_device_modbus_config
|
||||||
|
<where>
|
||||||
|
<if test="deviceId != null ">
|
||||||
|
and device_id = #{deviceId}
|
||||||
|
</if>
|
||||||
|
<if test="productId != null ">
|
||||||
|
and product_id = #{productId}
|
||||||
|
</if>
|
||||||
|
<if test="type != null ">
|
||||||
|
and type = #{type}
|
||||||
|
</if>
|
||||||
|
<if test="address != null ">
|
||||||
|
and address = #{address}
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
order by sort,id
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectByIdentify" resultMap="DeviceModbusConfigResult">
|
||||||
|
<include refid="selectDeviceModbusConfigVo"/>
|
||||||
|
where device_id = #{deviceId}
|
||||||
|
and identifier = #{identity}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 批量插入设备modbus配置 -->
|
||||||
|
<insert id="insertModbusConfigBatch" parameterType="java.util.List">
|
||||||
|
insert into iot_device_modbus_config (
|
||||||
|
device_id, product_id, identifier, slave, address, is_readonly,
|
||||||
|
data_type, quantity, type, bit_order, sort, del_flag,
|
||||||
|
create_by, create_time, update_by, update_time, remark
|
||||||
|
) values
|
||||||
|
<foreach collection="list" item="item" separator=",">
|
||||||
|
(
|
||||||
|
#{item.deviceId}, #{item.productId}, #{item.identifier}, #{item.slave}, #{item.address}, #{item.isReadonly},
|
||||||
|
#{item.dataType}, #{item.quantity}, #{item.type}, #{item.bitOrder}, #{item.sort}, #{item.delFlag},
|
||||||
|
#{item.createBy}, #{item.createTime}, #{item.updateBy}, #{item.updateTime}, #{item.remark}
|
||||||
|
)
|
||||||
|
</foreach>
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<!-- 批量更新设备modbus配置(使用 CASE WHEN 单条SQL实现) -->
|
||||||
|
<update id="updateModbusConfigBatch" parameterType="java.util.List">
|
||||||
|
update iot_device_modbus_config
|
||||||
|
<trim prefix="set" suffixOverrides=",">
|
||||||
|
<trim prefix="device_id = case" suffix="end,">
|
||||||
|
<foreach collection="list" item="item">
|
||||||
|
when id = #{item.id} then #{item.deviceId}
|
||||||
|
</foreach>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="product_id = case" suffix="end,">
|
||||||
|
<foreach collection="list" item="item">
|
||||||
|
when id = #{item.id} then #{item.productId}
|
||||||
|
</foreach>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="identifier = case" suffix="end,">
|
||||||
|
<foreach collection="list" item="item">
|
||||||
|
when id = #{item.id} then #{item.identifier}
|
||||||
|
</foreach>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="slave = case" suffix="end,">
|
||||||
|
<foreach collection="list" item="item">
|
||||||
|
when id = #{item.id} then #{item.slave}
|
||||||
|
</foreach>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="address = case" suffix="end,">
|
||||||
|
<foreach collection="list" item="item">
|
||||||
|
when id = #{item.id} then #{item.address}
|
||||||
|
</foreach>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="is_readonly = case" suffix="end,">
|
||||||
|
<foreach collection="list" item="item">
|
||||||
|
when id = #{item.id} then #{item.isReadonly}
|
||||||
|
</foreach>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="data_type = case" suffix="end,">
|
||||||
|
<foreach collection="list" item="item">
|
||||||
|
when id = #{item.id} then #{item.dataType}
|
||||||
|
</foreach>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="quantity = case" suffix="end,">
|
||||||
|
<foreach collection="list" item="item">
|
||||||
|
when id = #{item.id} then #{item.quantity}
|
||||||
|
</foreach>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="type = case" suffix="end,">
|
||||||
|
<foreach collection="list" item="item">
|
||||||
|
when id = #{item.id} then #{item.type}
|
||||||
|
</foreach>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="bit_order = case" suffix="end,">
|
||||||
|
<foreach collection="list" item="item">
|
||||||
|
when id = #{item.id} then #{item.bitOrder}
|
||||||
|
</foreach>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="sort = case" suffix="end,">
|
||||||
|
<foreach collection="list" item="item">
|
||||||
|
when id = #{item.id} then #{item.sort}
|
||||||
|
</foreach>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="update_by = case" suffix="end,">
|
||||||
|
<foreach collection="list" item="item">
|
||||||
|
when id = #{item.id} then #{item.updateBy}
|
||||||
|
</foreach>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="update_time = case" suffix="end,">
|
||||||
|
<foreach collection="list" item="item">
|
||||||
|
when id = #{item.id} then #{item.updateTime}
|
||||||
|
</foreach>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="remark = case" suffix="end,">
|
||||||
|
<foreach collection="list" item="item">
|
||||||
|
when id = #{item.id} then #{item.remark}
|
||||||
|
</foreach>
|
||||||
|
</trim>
|
||||||
|
</trim>
|
||||||
|
where id in
|
||||||
|
<foreach collection="list" item="item" open="(" separator="," close=")">
|
||||||
|
#{item.id}
|
||||||
|
</foreach>
|
||||||
|
</update>
|
||||||
|
</mapper>
|
||||||
|
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.fastbee.iot.mapper.DeviceModbusParamsMapper">
|
||||||
|
|
||||||
|
<resultMap type="com.fastbee.iot.domain.DeviceModbusParams" id="DeviceModbusParamsResult">
|
||||||
|
<result property="id" column="id"/>
|
||||||
|
<result property="deviceId" column="device_id"/>
|
||||||
|
<result property="productId" column="product_id"/>
|
||||||
|
<result property="pollType" column="poll_type"/>
|
||||||
|
<result property="slaveId" column="slave_id"/>
|
||||||
|
<result property="statusDeter" column="status_deter"/>
|
||||||
|
<result property="deterTimer" column="deter_timer"/>
|
||||||
|
<result property="pollLength" column="poll_length"/>
|
||||||
|
<result property="createBy" column="create_by"/>
|
||||||
|
<result property="createTime" column="create_time"/>
|
||||||
|
<result property="updateBy" column="update_by"/>
|
||||||
|
<result property="updateTime" column="update_time"/>
|
||||||
|
<result property="remark" column="remark"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<sql id="selectDeviceModbusParamsVo">
|
||||||
|
select id, device_id, product_id, poll_type, poll_length, slave_id, status_deter, deter_timer,
|
||||||
|
create_by, create_time, update_by, update_time, remark
|
||||||
|
from iot_device_modbus_params
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<select id="getByDeviceId" resultMap="DeviceModbusParamsResult">
|
||||||
|
<include refid="selectDeviceModbusParamsVo"/>
|
||||||
|
where device_id = #{deviceId}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<delete id="deleteByDeviceId">
|
||||||
|
delete from iot_device_modbus_params where device_id = #{deviceId}
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
|
|
||||||
@ -801,6 +801,38 @@ CREATE TABLE `iot_modbus_config` (
|
|||||||
-- Records of iot_modbus_config
|
-- Records of iot_modbus_config
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for iot_device_modbus_config
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `iot_device_modbus_config`;
|
||||||
|
CREATE TABLE `iot_device_modbus_config` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '业务id',
|
||||||
|
`device_id` bigint(20) NOT NULL COMMENT '所属设备id',
|
||||||
|
`product_id` bigint(20) NOT NULL COMMENT '所属产品id',
|
||||||
|
`identifier` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '关联属性',
|
||||||
|
`slave` int(10) NULL DEFAULT NULL COMMENT '从机地址',
|
||||||
|
`address` int(10) NOT NULL COMMENT '寄存器地址',
|
||||||
|
`is_readonly` tinyint(1) NOT NULL COMMENT '是否只读(0-否,1-是)',
|
||||||
|
`data_type` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'modbus数据类型',
|
||||||
|
`quantity` int(2) NULL DEFAULT NULL COMMENT '读取个数',
|
||||||
|
`type` tinyint(1) NOT NULL COMMENT '寄存器类型 1-IO寄存器 2-数据寄存器',
|
||||||
|
`bit_order` int(2) NULL DEFAULT NULL COMMENT 'bit位排序',
|
||||||
|
`sort` int(6) NULL DEFAULT NULL COMMENT '排序',
|
||||||
|
`del_flag` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
|
||||||
|
`create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '创建者',
|
||||||
|
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '更新者',
|
||||||
|
`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
|
||||||
|
`remark` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
KEY `idx_device_id` (`device_id`) USING BTREE COMMENT '设备id索引',
|
||||||
|
KEY `idx_product_id` (`product_id`) USING BTREE COMMENT '产品id索引'
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '设备modbus配置表' ROW_FORMAT = DYNAMIC;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of iot_device_modbus_config
|
||||||
|
-- ----------------------------
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for iot_modbus_job
|
-- Table structure for iot_modbus_job
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
@ -848,6 +880,33 @@ CREATE TABLE `iot_modbus_params` (
|
|||||||
-- Records of iot_modbus_params
|
-- Records of iot_modbus_params
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for iot_device_modbus_params
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `iot_device_modbus_params`;
|
||||||
|
CREATE TABLE `iot_device_modbus_params` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '业务id',
|
||||||
|
`device_id` bigint(20) NOT NULL COMMENT '设备id',
|
||||||
|
`product_id` bigint(20) NOT NULL COMMENT '产品id',
|
||||||
|
`poll_type` tinyint(1) NULL DEFAULT NULL COMMENT '是否启动云端轮训(0-云端轮训,1-边缘采集)',
|
||||||
|
`slave_id` int(3) NULL DEFAULT NULL COMMENT '默认的子设备地址',
|
||||||
|
`status_deter` tinyint(1) NULL DEFAULT NULL COMMENT '子设备状态判断方式 1-设备数据 2- 网关',
|
||||||
|
`deter_timer` varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '设备数据来判断子设备状态的时长(s)',
|
||||||
|
`poll_length` int(3) NULL DEFAULT NULL COMMENT '批量读取的个数',
|
||||||
|
`create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '创建者',
|
||||||
|
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '更新者',
|
||||||
|
`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
|
||||||
|
`remark` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
UNIQUE KEY `uk_device_id` (`device_id`) USING BTREE COMMENT '设备唯一索引',
|
||||||
|
KEY `idx_product_id` (`product_id`) USING BTREE COMMENT '产品id索引'
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci COMMENT = '设备modbus配置参数' ROW_FORMAT = DYNAMIC;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of iot_device_modbus_params
|
||||||
|
-- ----------------------------
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for iot_product
|
-- Table structure for iot_product
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
|
|||||||
@ -73,3 +73,54 @@ ALTER TABLE `iot_firmware`
|
|||||||
ALTER TABLE `iot_things_model_translate`
|
ALTER TABLE `iot_things_model_translate`
|
||||||
ADD COLUMN `product_id` bigint(20) NULL DEFAULT NULL COMMENT '产品ID';
|
ADD COLUMN `product_id` bigint(20) NULL DEFAULT NULL COMMENT '产品ID';
|
||||||
|
|
||||||
|
-- 设备级modbus配置表(用于设备覆盖产品模板)
|
||||||
|
CREATE TABLE IF NOT EXISTS `iot_device_modbus_config` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '业务id',
|
||||||
|
`device_id` bigint(20) NOT NULL COMMENT '所属设备id',
|
||||||
|
`product_id` bigint(20) NOT NULL COMMENT '所属产品id(兜底物模型)',
|
||||||
|
`identifier` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '关联属性',
|
||||||
|
`slave` int(10) DEFAULT NULL COMMENT '从机地址',
|
||||||
|
`address` int(10) NOT NULL COMMENT '寄存器地址',
|
||||||
|
`is_readonly` tinyint(1) NOT NULL COMMENT '是否只读(0-否,1-是)',
|
||||||
|
`data_type` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT 'modbus数据类型',
|
||||||
|
`quantity` int(2) DEFAULT NULL COMMENT '读取个数',
|
||||||
|
`type` tinyint(1) NOT NULL COMMENT '寄存器类型 1-IO寄存器 2-数据寄存器',
|
||||||
|
`bit_order` int(2) DEFAULT NULL COMMENT 'bit位排序',
|
||||||
|
`sort` int(6) DEFAULT NULL COMMENT '排序',
|
||||||
|
`del_flag` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
|
||||||
|
`create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '' COMMENT '创建者',
|
||||||
|
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '' COMMENT '更新者',
|
||||||
|
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||||
|
`remark` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '备注',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
UNIQUE KEY `uk_device_identifier` (`device_id`,`identifier`),
|
||||||
|
KEY `idx_device_address_bit` (`device_id`,`address`,`bit_order`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=DYNAMIC COMMENT='设备级modbus配置表(覆盖产品模板)';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 设备级modbus配置参数表 iot_device_modbus_params
|
||||||
|
-- 继承自产品级 iot_modbus_params,用于设备级别的个性化配置
|
||||||
|
-- @author Sumuxi
|
||||||
|
-- @date 2026/1/14
|
||||||
|
-- ----------------------------
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `iot_device_modbus_params`;
|
||||||
|
CREATE TABLE `iot_device_modbus_params` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '业务id',
|
||||||
|
`device_id` bigint(20) NOT NULL COMMENT '设备id',
|
||||||
|
`product_id` bigint(20) NOT NULL COMMENT '产品id',
|
||||||
|
`poll_type` tinyint(1) NULL DEFAULT NULL COMMENT '是否启动云端轮训(0-云端轮训,1-边缘采集)',
|
||||||
|
`slave_id` int(3) NULL DEFAULT NULL COMMENT '默认的子设备地址',
|
||||||
|
`status_deter` tinyint(1) NULL DEFAULT NULL COMMENT '子设备状态判断方式 1-设备数据 2- 网关',
|
||||||
|
`deter_timer` varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '设备数据来判断子设备状态的时长(s)',
|
||||||
|
`poll_length` int(3) NULL DEFAULT NULL COMMENT '批量读取的个数',
|
||||||
|
`create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '创建者',
|
||||||
|
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '更新者',
|
||||||
|
`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
|
||||||
|
`remark` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
UNIQUE KEY `uk_device_id` (`device_id`) USING BTREE COMMENT '设备唯一索引',
|
||||||
|
KEY `idx_product_id` (`product_id`) USING BTREE COMMENT '产品id索引'
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci COMMENT = '设备modbus配置参数' ROW_FORMAT = DYNAMIC;
|
||||||
|
|||||||
54
sql/yack.sql
54
sql/yack.sql
@ -3538,3 +3538,57 @@ CREATE TABLE `qrtz_simprop_triggers`
|
|||||||
PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE,
|
PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE,
|
||||||
CONSTRAINT `QRTZ_SIMPROP_TRIGGERS_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`)
|
CONSTRAINT `QRTZ_SIMPROP_TRIGGERS_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='同步机制的行锁表';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='同步机制的行锁表';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- 设备级modbus配置表(用于设备覆盖产品模板)
|
||||||
|
CREATE TABLE IF NOT EXISTS `iot_device_modbus_config` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '业务id',
|
||||||
|
`device_id` bigint(20) NOT NULL COMMENT '所属设备id',
|
||||||
|
`product_id` bigint(20) NOT NULL COMMENT '所属产品id(兜底物模型)',
|
||||||
|
`identifier` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '关联属性',
|
||||||
|
`slave` int(10) DEFAULT NULL COMMENT '从机地址',
|
||||||
|
`address` int(10) NOT NULL COMMENT '寄存器地址',
|
||||||
|
`is_readonly` tinyint(1) NOT NULL COMMENT '是否只读(0-否,1-是)',
|
||||||
|
`data_type` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT 'modbus数据类型',
|
||||||
|
`quantity` int(2) DEFAULT NULL COMMENT '读取个数',
|
||||||
|
`type` tinyint(1) NOT NULL COMMENT '寄存器类型 1-IO寄存器 2-数据寄存器',
|
||||||
|
`bit_order` int(2) DEFAULT NULL COMMENT 'bit位排序',
|
||||||
|
`sort` int(6) DEFAULT NULL COMMENT '排序',
|
||||||
|
`del_flag` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
|
||||||
|
`create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '' COMMENT '创建者',
|
||||||
|
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '' COMMENT '更新者',
|
||||||
|
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||||
|
`remark` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '备注',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
UNIQUE KEY `uk_device_identifier` (`device_id`,`identifier`),
|
||||||
|
KEY `idx_device_address_bit` (`device_id`,`address`,`bit_order`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=DYNAMIC COMMENT='设备级modbus配置表(覆盖产品模板)';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 设备级modbus配置参数表 iot_device_modbus_params
|
||||||
|
-- 继承自产品级 iot_modbus_params,用于设备级别的个性化配置
|
||||||
|
-- @author Sumuxi
|
||||||
|
-- @date 2026/1/14
|
||||||
|
-- ----------------------------
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `iot_device_modbus_params`;
|
||||||
|
CREATE TABLE `iot_device_modbus_params` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '业务id',
|
||||||
|
`device_id` bigint(20) NOT NULL COMMENT '设备id',
|
||||||
|
`product_id` bigint(20) NOT NULL COMMENT '产品id',
|
||||||
|
`poll_type` tinyint(1) NULL DEFAULT NULL COMMENT '是否启动云端轮训(0-云端轮训,1-边缘采集)',
|
||||||
|
`slave_id` int(3) NULL DEFAULT NULL COMMENT '默认的子设备地址',
|
||||||
|
`status_deter` tinyint(1) NULL DEFAULT NULL COMMENT '子设备状态判断方式 1-设备数据 2- 网关',
|
||||||
|
`deter_timer` varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '设备数据来判断子设备状态的时长(s)',
|
||||||
|
`poll_length` int(3) NULL DEFAULT NULL COMMENT '批量读取的个数',
|
||||||
|
`create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '创建者',
|
||||||
|
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '更新者',
|
||||||
|
`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
|
||||||
|
`remark` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
UNIQUE KEY `uk_device_id` (`device_id`) USING BTREE COMMENT '设备唯一索引',
|
||||||
|
KEY `idx_product_id` (`product_id`) USING BTREE COMMENT '产品id索引'
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci COMMENT = '设备modbus配置参数' ROW_FORMAT = DYNAMIC;
|
||||||
|
|||||||
28
vue/src/api/iot/deviceModbusConfig.js
Normal file
28
vue/src/api/iot/deviceModbusConfig.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
// 查询设备modbus配置列表
|
||||||
|
export function listDeviceConfig(query) {
|
||||||
|
return request({
|
||||||
|
url: '/deviceModbus/config/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量新增或更新设备modbus配置
|
||||||
|
export function addDeviceBatch(data) {
|
||||||
|
return request({
|
||||||
|
url: '/deviceModbus/config/addBatch',
|
||||||
|
method: 'post',
|
||||||
|
data: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除设备modbus配置
|
||||||
|
export function delDeviceConfig(ids) {
|
||||||
|
return request({
|
||||||
|
url: '/deviceModbus/config/' + ids,
|
||||||
|
method: 'delete',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,19 +1,18 @@
|
|||||||
export function loadBMap() {
|
export function loadBMap() {
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
if (typeof BMap !== 'undefined') {
|
if (typeof BMap !== 'undefined') {
|
||||||
resolve(BMap)
|
resolve(BMap)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
window.onBMapCallback = function() {
|
window.onBMapCallback = function () {
|
||||||
resolve(BMap)
|
resolve(BMap)
|
||||||
}
|
}
|
||||||
// 使用https协议需要添加一下meta标签
|
// 使用https协议需要添加一下meta标签
|
||||||
var protocolStr = document.location.protocol;
|
var protocolStr = document.location.protocol;
|
||||||
if(protocolStr == "https:")
|
if (protocolStr == "https:") {
|
||||||
{
|
|
||||||
let meta = document.createElement('meta')
|
let meta = document.createElement('meta')
|
||||||
meta.httpEquiv = 'Content-Security-Policy'
|
meta.httpEquiv = 'Content-Security-Policy'
|
||||||
meta.content ='upgrade-insecure-requests'
|
meta.content = 'upgrade-insecure-requests'
|
||||||
meta.onerror = reject
|
meta.onerror = reject
|
||||||
document.head.appendChild(meta)
|
document.head.appendChild(meta)
|
||||||
}
|
}
|
||||||
@ -21,7 +20,7 @@ export function loadBMap() {
|
|||||||
let script = document.createElement('script')
|
let script = document.createElement('script')
|
||||||
script.type = 'text/javascript'
|
script.type = 'text/javascript'
|
||||||
script.src =
|
script.src =
|
||||||
'http://api.map.baidu.com/api?v=2.0&ak='+ process.env.VUE_APP_BAI_DU_AK +'&s=1&__ec_v__=20190126&callback=onBMapCallback'
|
'http://api.map.baidu.com/api?v=2.0&ak=' + process.env.VUE_APP_BAI_DU_AK + '&s=1&__ec_v__=20190126&callback=onBMapCallback'
|
||||||
script.onerror = reject
|
script.onerror = reject
|
||||||
document.head.appendChild(script)
|
document.head.appendChild(script)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-card style="margin: 6px; padding-bottom: 100px">
|
<el-card style="margin: 6px; padding-bottom: 100px" v-loading="pageLoading" element-loading-text="加载中...">
|
||||||
<el-tabs id="deviceDetailTab" v-model="activeName" tab-position="left" @tab-click="tabChange" style="padding: 10px; min-height: 400px" lazy>
|
<el-tabs id="deviceDetailTab" v-model="activeName" tab-position="left" @tab-click="tabChange" style="padding: 10px; min-height: 400px" lazy>
|
||||||
<el-tab-pane name="basic">
|
<el-tab-pane name="basic">
|
||||||
<span slot="label">{{ $t('device.device-edit.148398-0') }}</span>
|
<span slot="label">{{ $t('device.device-edit.148398-0') }}</span>
|
||||||
@ -175,6 +175,16 @@
|
|||||||
<device-timer ref="deviceTimer" :device="form" />
|
<device-timer ref="deviceTimer" :device="form" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
|
<el-tab-pane
|
||||||
|
name="deviceModbusConfig"
|
||||||
|
:disabled="form.deviceId == 0"
|
||||||
|
v-if="form.protocolCode == 'MODBUS-RTU' || form.protocolCode == 'MODBUS-TCP' || form.protocolCode == 'MODBUS-JSON-HP'"
|
||||||
|
lazy
|
||||||
|
>
|
||||||
|
<span slot="label"><span style="color: red">*</span>{{ $t('product.product-edit.473153-80') }}</span>
|
||||||
|
<device-modbus ref="deviceModbusConfig" :device="form" />
|
||||||
|
</el-tab-pane>
|
||||||
|
|
||||||
<el-tab-pane name="deviceUser" :disabled="form.deviceId == 0" lazy>
|
<el-tab-pane name="deviceUser" :disabled="form.deviceId == 0" lazy>
|
||||||
<span slot="label">{{ $t('device.device-edit.148398-48') }}</span>
|
<span slot="label">{{ $t('device.device-edit.148398-48') }}</span>
|
||||||
<device-user ref="deviceUser" :device="form" @userEvent="getUserData($event)" />
|
<device-user ref="deviceUser" :device="form" @userEvent="getUserData($event)" />
|
||||||
@ -329,6 +339,7 @@ import deviceMonitor from './device-monitor';
|
|||||||
import deviceStatistic from './device-statistic';
|
import deviceStatistic from './device-statistic';
|
||||||
import instructionParsing from './instruction-parsing';
|
import instructionParsing from './instruction-parsing';
|
||||||
import deviceModbusTask from './device-modbus-task';
|
import deviceModbusTask from './device-modbus-task';
|
||||||
|
import deviceModbus from './device-modbus';
|
||||||
import deviceTimer from './device-timer';
|
import deviceTimer from './device-timer';
|
||||||
import channel from '../sip/channel';
|
import channel from '../sip/channel';
|
||||||
import player from '@/views/components/player/player.vue';
|
import player from '@/views/components/player/player.vue';
|
||||||
@ -367,6 +378,7 @@ export default {
|
|||||||
runningStatus,
|
runningStatus,
|
||||||
productList,
|
productList,
|
||||||
deviceTimer,
|
deviceTimer,
|
||||||
|
deviceModbus,
|
||||||
deviceFuncLog,
|
deviceFuncLog,
|
||||||
deviceVideo,
|
deviceVideo,
|
||||||
siptalk,
|
siptalk,
|
||||||
@ -415,6 +427,8 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
// 页面加载状态
|
||||||
|
pageLoading: false,
|
||||||
// 二维码内容
|
// 二维码内容
|
||||||
qrText: 'fastbee',
|
qrText: 'fastbee',
|
||||||
// 打开设备配置对话框
|
// 打开设备配置对话框
|
||||||
@ -500,6 +514,8 @@ export default {
|
|||||||
this.form.deviceId = this.$route.query && this.$route.query.deviceId;
|
this.form.deviceId = this.$route.query && this.$route.query.deviceId;
|
||||||
if (this.form.deviceId != 0) {
|
if (this.form.deviceId != 0) {
|
||||||
// this.connectMqtt();
|
// this.connectMqtt();
|
||||||
|
// 开启页面加载状态
|
||||||
|
this.pageLoading = true;
|
||||||
this.getDevice(this.form.deviceId);
|
this.getDevice(this.form.deviceId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -726,6 +742,9 @@ export default {
|
|||||||
this.form.protocolCode = response.data.protocolCode;
|
this.form.protocolCode = response.data.protocolCode;
|
||||||
// 获取设备状态和物模型
|
// 获取设备状态和物模型
|
||||||
this.getDeviceStatusWitchThingsModel(response);
|
this.getDeviceStatusWitchThingsModel(response);
|
||||||
|
}).catch(() => {
|
||||||
|
// 请求失败时关闭加载状态
|
||||||
|
this.pageLoading = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/**用户是否拥有分享设备权限*/
|
/**用户是否拥有分享设备权限*/
|
||||||
@ -962,6 +981,10 @@ export default {
|
|||||||
|
|
||||||
this.$modal.alertSuccess(this.$t('device.device-edit.148398-70'));
|
this.$modal.alertSuccess(this.$t('device.device-edit.148398-70'));
|
||||||
this.loadMap();
|
this.loadMap();
|
||||||
|
// Modbus协议设备新建后跳转到Modbus配置页面
|
||||||
|
if (this.form.protocolCode == 'MODBUS-RTU' || this.form.protocolCode == 'MODBUS-TCP' || this.form.protocolCode == 'MODBUS-JSON-HP') {
|
||||||
|
this.activeName = 'deviceModbusConfig';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -970,30 +993,38 @@ export default {
|
|||||||
},
|
},
|
||||||
/** 获取设备状态和物模型 **/
|
/** 获取设备状态和物模型 **/
|
||||||
async getDeviceStatusWitchThingsModel(response) {
|
async getDeviceStatusWitchThingsModel(response) {
|
||||||
// 获取缓存物模型
|
try {
|
||||||
response.data.cacheThingsModel = await this.getCacheThingsModdel(response.data.productId);
|
// 并行获取缓存物模型和设备运行状态,加快加载速度
|
||||||
// 获取设备运行状态
|
const [cacheThingsModel, thingsModels] = await Promise.all([
|
||||||
response.data.thingsModels = await this.getDeviceStatus(response.data);
|
this.getCacheThingsModdel(response.data.productId),
|
||||||
//分享设备过滤没有权限的物模型
|
this.getDeviceStatus(response.data),
|
||||||
// if (response.data.isOwner == 0) {
|
]);
|
||||||
// for (let i = 0; i < response.data.thingsModels.length; i++) {
|
response.data.cacheThingsModel = cacheThingsModel;
|
||||||
// if (response.data.userPerms.indexOf(response.data.thingsModels[i].id) == -1) {
|
response.data.thingsModels = thingsModels;
|
||||||
// response.data.thingsModels.splice(i--, 1);
|
//分享设备过滤没有权限的物模型
|
||||||
// }
|
// if (response.data.isOwner == 0) {
|
||||||
// }
|
// for (let i = 0; i < response.data.thingsModels.length; i++) {
|
||||||
// }
|
// if (response.data.userPerms.indexOf(response.data.thingsModels[i].id) == -1) {
|
||||||
// 格式化物模型,拆分出监测值,数组添加前缀
|
// response.data.thingsModels.splice(i--, 1);
|
||||||
this.formatThingsModel(response.data);
|
// }
|
||||||
this.form = response.data;
|
// }
|
||||||
// 解析设备摘要
|
// }
|
||||||
if (this.form.summary != null && this.form.summary != '') {
|
// 格式化物模型,拆分出监测值,数组添加前缀
|
||||||
this.summary = JSON.parse(this.form.summary);
|
this.formatThingsModel(response.data);
|
||||||
|
this.form = response.data;
|
||||||
|
// 解析设备摘要
|
||||||
|
if (this.form.summary != null && this.form.summary != '') {
|
||||||
|
this.summary = JSON.parse(this.form.summary);
|
||||||
|
}
|
||||||
|
this.oldDeviceStatus = this.form.status;
|
||||||
|
this.loadMap();
|
||||||
|
//Mqtt订阅
|
||||||
|
this.connectMqtt();
|
||||||
|
this.mqttSubscribe(this.form);
|
||||||
|
} finally {
|
||||||
|
// 关闭页面加载状态
|
||||||
|
this.pageLoading = false;
|
||||||
}
|
}
|
||||||
this.oldDeviceStatus = this.form.status;
|
|
||||||
this.loadMap();
|
|
||||||
//Mqtt订阅
|
|
||||||
this.connectMqtt();
|
|
||||||
this.mqttSubscribe(this.form);
|
|
||||||
},
|
},
|
||||||
/**选择产品 */
|
/**选择产品 */
|
||||||
selectProduct() {
|
selectProduct() {
|
||||||
|
|||||||
854
vue/src/views/iot/device/device-modbus.vue
Normal file
854
vue/src/views/iot/device/device-modbus.vue
Normal file
@ -0,0 +1,854 @@
|
|||||||
|
<template>
|
||||||
|
<div class="modbus-wrap">
|
||||||
|
<div style="margin-bottom: 0px" v-if="showParamsSection">
|
||||||
|
<div class="card-title">
|
||||||
|
<div style="display: flex; justify-content: flex-start; margin-bottom: 30px">
|
||||||
|
<!-- <svg-icon icon-class="modbus" style="font-size: 20px;margin-top: 4px;margin-right: 10px;" /> -->
|
||||||
|
<div class="title" style="font-size: 22px">{{ $t('product.product-modbus.562372-0') }}</div>
|
||||||
|
<el-tooltip class="item" effect="dark" :content="$t('product.product-modbus.562372-1')" placement="top">
|
||||||
|
<i class="el-icon-question" style="margin-left: 10px; margin-top: 5px; font-size: large" />
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="button-group" style="margin-top: -10px">
|
||||||
|
<el-button type="primary" plain icon="el-icon-edit" size="mini" @click="setSlave" v-if="!enableSetSlave && deviceId > 0">{{ $t('product.product-modbus.562372-2') }}</el-button>
|
||||||
|
<el-button type="primary" plain size="mini" @click="saveSlave" v-if="enableSetSlave" v-hasPermi="['modbus:config:edit']">{{ $t('product.product-modbus.562372-3') }}</el-button>
|
||||||
|
<el-button type="info" plain size="mini" @click="cancelSlave" v-if="enableSetSlave">{{ $t('product.product-modbus.562372-4') }}</el-button>
|
||||||
|
</div>
|
||||||
|
<el-form ref="form" :model="form" label-width="180px" :rules="rules" style="margin-left: -150px">
|
||||||
|
<el-form-item label="">
|
||||||
|
<el-tooltip placement="top">
|
||||||
|
<div slot="content" class="test_div">
|
||||||
|
{{ $t('product.product-modbus.562372-6') }}
|
||||||
|
<br />
|
||||||
|
{{ $t('product.product-modbus.562372-7') }}
|
||||||
|
<br />
|
||||||
|
{{ $t('product.product-modbus.562372-8') }}
|
||||||
|
</div>
|
||||||
|
<!-- elementui图标库:显示黑色的问号图标 -->
|
||||||
|
<i class="el-icon-question" style="color: dodgerblue" />
|
||||||
|
<span>{{ $t('product.product-modbus.562372-5') }}</span>
|
||||||
|
</el-tooltip>
|
||||||
|
<span style="margin-right: 10px">{{ $t('product.product-modbus.562372-5') }}</span>
|
||||||
|
<el-radio-group :disabled="!enableSetSlave" v-model="form.statusDeter">
|
||||||
|
<el-radio v-for="dict in dict.type.device_status_deter" :key="dict.value" :label="Number(dict.value)">
|
||||||
|
{{ dict.label }}
|
||||||
|
</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="form.statusDeter == '1'" label="">
|
||||||
|
<span>
|
||||||
|
<el-tooltip placement="top">
|
||||||
|
<div slot="content" class="test_div">
|
||||||
|
{{ $t('product.product-modbus.562372-10') }}
|
||||||
|
</div>
|
||||||
|
<!-- elementui图标库:显示黑色的问号图标 -->
|
||||||
|
<i class="el-icon-question" style="color: dodgerblue" />
|
||||||
|
</el-tooltip>
|
||||||
|
</span>
|
||||||
|
<span style="margin-right: 10px">{{ $t('product.product-modbus.562372-9') }}</span>
|
||||||
|
<el-select :disabled="!enableSetSlave" v-model="form.deterTimer" :placeholder="$t('product.product-modbus.562372-11')">
|
||||||
|
<el-option v-for="dict in dict.type.iot_modbus_poll_time" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
|
||||||
|
</el-select>
|
||||||
|
<span style="font-size: 14px; color: darkgrey">{{ $t('product.product-modbus.562372-12') }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="">
|
||||||
|
<span style="margin-right: 10px">{{ $t('product.product-modbus.562372-13') }}</span>
|
||||||
|
<el-radio-group :disabled="!enableSetSlave" v-model="form.pollType" @change="changePollType">
|
||||||
|
<el-radio v-for="dict in dict.type.data_collect_type" :key="dict.value" :label="Number(dict.value)">{{ dict.label }}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="" prop="slaveId">
|
||||||
|
<span style="margin-right: 10px">{{ $t('product.product-modbus.562372-14') }}</span>
|
||||||
|
<el-input :disabled="!enableSetSlave" v-model="form.slaveId" size="small" :label="$t('product.product-modbus.562372-15')" style="width: 230px" type="number"></el-input>
|
||||||
|
<span style="font-size: 14px; color: darkgrey">{{ $t('product.product-modbus.562372-16') }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<el-divider></el-divider>
|
||||||
|
</div>
|
||||||
|
<!-- IO寄存器 -->
|
||||||
|
<div class="head">
|
||||||
|
<div class="card-title">
|
||||||
|
<div style="display: flex; justify-content: flex-start; margin-bottom: 10px">
|
||||||
|
<!-- <svg-icon icon-class="modbus" style="font-size: 20px;margin-top: 4px;margin-right: 10px;" /> -->
|
||||||
|
<div class="title" style="font-size: 22px">{{ $t('product.product-modbus.562372-17') }}</div>
|
||||||
|
<el-tooltip class="item" effect="dark" :content="$t('product.product-modbus.562372-18')" placement="top">
|
||||||
|
<i class="el-icon-question" style="margin-left: 10px; margin-top: 5px; font-size: large" />
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="button-group">
|
||||||
|
<el-button type="primary" plain icon="el-icon-edit" size="mini" @click="editIOModbus" v-if="!enableEditIO && deviceId > 0">{{ $t('product.product-modbus.562372-19') }}</el-button>
|
||||||
|
<el-button type="primary" plain size="mini" @click="submitFormIO" v-if="enableEditIO" v-hasPermi="['modbus:config:edit']">{{ $t('product.product-modbus.562372-22') }}</el-button>
|
||||||
|
<el-button type="info" plain size="mini" @click="handleCancelIO" v-if="enableEditIO">{{ $t('product.product-modbus.562372-23') }}</el-button>
|
||||||
|
<div class="right-btns">
|
||||||
|
<el-button type="primary" plain icon="el-icon-upload" v-if="enableImportExport" size="mini" @click.stop="batchImport('isSelectIo')" v-hasPermi="['modbus:config:import']">
|
||||||
|
{{ $t('product.product-modbus.562372-20') }}
|
||||||
|
</el-button>
|
||||||
|
<el-button plain icon="el-icon-download" v-if="enableImportExport" size="mini" @click.stop="exportModbus('isSelectIo')" v-hasPermi="['modbus:config:export']">
|
||||||
|
{{ $t('product.product-modbus.562372-21') }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-table style="margin-bottom: 10px" v-loading="loadingIO" :data="configList" :key="configTableKey" data-key="id" ref="IOTable">
|
||||||
|
<el-table-column :label="$t('product.product-modbus.562372-24')" align="center" prop="sort"></el-table-column>
|
||||||
|
<el-table-column :label="$t('product.product-modbus.562372-25')" align="center" prop="identifier">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-select
|
||||||
|
filterable
|
||||||
|
:disabled="!enableEditIO"
|
||||||
|
v-model="scope.row.identifier"
|
||||||
|
:placeholder="$t('product.product-modbus.562372-26')"
|
||||||
|
:ref="`selectIo${scope.$index}`"
|
||||||
|
size="mini"
|
||||||
|
@change="(e) => updateSelectThingsModel({ newVal: e, oldVal: $refs[`selectIo${scope.$index}`].value, justiceSelect: 'isSelectIo' })"
|
||||||
|
>
|
||||||
|
<el-option key="0" label="" value="" disabled style="width: 300px">
|
||||||
|
<span style="float: left">{{ $t('product.product-modbus.562372-27') }}</span>
|
||||||
|
<span style="float: right; color: #8492a6; font-size: 13px">{{ $t('product.product-modbus.562372-28') }}</span>
|
||||||
|
</el-option>
|
||||||
|
<el-option v-for="item in thingsModelList" :key="item.identifier" :label="`${item.modelName} (${item.identifier})`" :value="item.identifier" style="width: 300px" :disabled="!item.isSelectIo">
|
||||||
|
<span style="float: left">{{ item.modelName }}</span>
|
||||||
|
<span style="float: right; color: #8492a6; font-size: 13px">{{ item.identifier }}</span>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :label="$t('product.product-modbus.562372-29')" align="center" prop="slave">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-input-number :disabled="!enableEditIO" v-model="scope.row.slave" size="small" :min="1" :max="256" :label="$t('product.product-modbus.562372-29')"></el-input-number>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :label="$t('product.product-modbus.562372-30')" align="center" prop="address">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-input-number :disabled="!enableEditIO" v-model="scope.row.address" size="small" :min="0" :max="400000" :label="$t('product.product-modbus.562372-30')"></el-input-number>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :label="$t('product.product-modbus.562372-31')" align="center" prop="isReadonly">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-radio-group :disabled="!enableEditIO" size="mini" v-model="scope.row.isReadonly">
|
||||||
|
<el-radio-button label="0">{{ $t('product.product-modbus.562372-32') }}</el-radio-button>
|
||||||
|
<el-radio-button label="1">{{ $t('product.product-modbus.562372-33') }}</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :label="$t('product.product-modbus.562372-311')" align="center" prop="bitOrder">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-input-number :disabled="!enableEditIO" v-model="scope.row.bitOrder" size="small" :min="0" :max="15" :label="$t('product.product-modbus.562372-311')"></el-input-number>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :label="$t('product.product-modbus.562372-34')" align="center" class-name="small-padding fixed-width">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button v-if="enableEditIO" size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row, scope.$index, configList, 'isSelectIo')" v-hasPermi="['iot:config:remove']">
|
||||||
|
{{ $t('product.product-modbus.562372-35') }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<pagination v-show="total > 0" :total="total" :page.sync="queryParamsIO.pageNum" :limit.sync="queryParamsIO.pageSize" @pagination="getIOList" />
|
||||||
|
|
||||||
|
<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-if="enableEditIO">{{ $t('product.product-modbus.562372-36') }}</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAddBatch('isSelectIo')" v-if="enableEditIO">{{ $t('product.product-modbus.562372-37') }}</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<!-- 数据寄存器 -->
|
||||||
|
<div class="head">
|
||||||
|
<el-divider></el-divider>
|
||||||
|
<div class="card-title">
|
||||||
|
<div style="display: flex; justify-content: flex-start; margin-bottom: 10px">
|
||||||
|
<!-- <svg-icon icon-class="modbus" style="font-size: 20px;margin-top: 4px;margin-right: 10px;" /> -->
|
||||||
|
<div class="title" style="font-size: 22px">{{ $t('product.product-modbus.562372-38') }}</div>
|
||||||
|
<el-tooltip class="item" effect="dark" :content="$t('product.product-modbus.562372-39')" placement="top">
|
||||||
|
<i class="el-icon-question" style="margin-left: 10px; margin-top: 5px; font-size: large" />
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="button-group">
|
||||||
|
<el-button type="primary" plain icon="el-icon-edit" size="mini" @click="editDataModbus" v-if="!enableEditData && deviceId > 0">{{ $t('product.product-modbus.562372-19') }}</el-button>
|
||||||
|
<el-button type="primary" plain size="mini" @click="submitFormData" v-if="enableEditData" v-hasPermi="['modbus:config:edit']">{{ $t('product.product-modbus.562372-22') }}</el-button>
|
||||||
|
<el-button type="info" plain size="mini" @click="handleCancelData" v-if="enableEditData">{{ $t('product.product-modbus.562372-23') }}</el-button>
|
||||||
|
<div class="right-btns">
|
||||||
|
<el-button type="primary" plain icon="el-icon-upload" v-if="enableImportExport" size="mini" @click.stop="batchImport('isSelectData')" v-hasPermi="['modbus:config:import']">
|
||||||
|
{{ $t('product.product-modbus.562372-40') }}
|
||||||
|
</el-button>
|
||||||
|
<el-button plain icon="el-icon-download" v-if="enableImportExport" size="mini" @click.stop="exportModbus('isSelectIo')" v-hasPermi="['modbus:config:export']">
|
||||||
|
{{ $t('product.product-modbus.562372-41') }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-table style="margin-bottom: 10px" v-loading="loadingData" :data="dataModbusList" :key="dataTableKey" ref="Dataable">
|
||||||
|
<el-table-column :label="$t('product.product-modbus.562372-24')" align="center" prop="sort"></el-table-column>
|
||||||
|
<el-table-column :label="$t('product.product-modbus.562372-25')" align="center" prop="identifier" width="250px">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-select
|
||||||
|
filterable
|
||||||
|
:disabled="!enableEditData"
|
||||||
|
v-model="scope.row.identifier"
|
||||||
|
:placeholder="$t('product.product-modbus.562372-26')"
|
||||||
|
size="mini"
|
||||||
|
:ref="`selectData${scope.$index}`"
|
||||||
|
@change="(e) => updateSelectThingsModel({ newVal: e, oldVal: $refs[`selectData${scope.$index}`].value, justiceSelect: 'isSelectData' })"
|
||||||
|
>
|
||||||
|
<el-option key="0" label="" value="" disabled style="width: 300px">
|
||||||
|
<span style="float: left">{{ $t('product.product-modbus.562372-27') }}</span>
|
||||||
|
<span style="float: right; color: #8492a6; font-size: 13px">{{ $t('product.product-modbus.562372-28') }}</span>
|
||||||
|
</el-option>
|
||||||
|
<el-option v-for="item in thingsModelList" :key="item.identifier" :label="`${item.modelName} (${item.identifier})`" :value="item.identifier" style="width: 300px" :disabled="!item.isSelectData">
|
||||||
|
<!-- 判断是否可选 -->
|
||||||
|
<span style="float: left">{{ item.modelName }}</span>
|
||||||
|
<span style="float: right; color: #8492a6; font-size: 13px">{{ item.identifier }}</span>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :label="$t('product.product-modbus.562372-29')" align="center" prop="identifier" width="170px">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-input-number :disabled="!enableEditData" v-model="scope.row.slave" size="small" :min="1" :max="256" :label="$t('product.product-modbus.562372-29')"></el-input-number>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :label="$t('product.product-modbus.562372-30')" align="center" prop="address" width="170px">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-input-number :disabled="!enableEditData" v-model="scope.row.address" size="small" :min="0" :max="400000" :label="$t('product.product-modbus.562372-30')"></el-input-number>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :label="$t('product.product-modbus.562372-31')" align="center" prop="isReadonly" width="170px">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-radio-group :disabled="!enableEditData" size="mini" v-model="scope.row.isReadonly">
|
||||||
|
<el-radio-button label="0">{{ $t('product.product-modbus.562372-32') }}</el-radio-button>
|
||||||
|
<el-radio-button label="1">{{ $t('product.product-modbus.562372-33') }}</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
<!-- <el-tag v-show="!enableEditData">{{scope.row.isReadonly=='0'?'只读':'读写'}}</el-tag> -->
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :label="$t('product.product-modbus.562372-42')" align="center" prop="dataType" width="200px">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-select :disabled="!enableEditData" size="mini" v-model="scope.row.dataType" :placeholder="$t('product.product-modbus.562372-42')" style="display: inline-block; padding-right: 10px">
|
||||||
|
<el-option v-for="dict in dict.type.iot_modbus_data_type" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :label="$t('product.product-modbus.562372-43')" align="center" prop="quantity" width="170px">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-input-number :disabled="!enableEditData" v-model="scope.row.quantity" size="small" :min="1" :max="256" :label="$t('product.product-modbus.562372-43')"></el-input-number>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :label="$t('product.product-modbus.562372-34')" align="center" class-name="small-padding fixed-width">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button v-if="enableEditData" size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row, scope.$index, dataModbusList, 'isSelectData')" v-hasPermi="['iot:config:remove']">
|
||||||
|
{{ $t('product.product-modbus.562372-35') }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<pagination v-show="dataTotal > 0" :total="dataTotal" :page.sync="queryParamsData.pageNum" :limit.sync="queryParamsData.pageSize" @pagination="getDataList" />
|
||||||
|
|
||||||
|
<el-row :gutter="10" class="mb8">
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAddData" v-if="enableEditData">{{ $t('product.product-modbus.562372-44') }}</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAddBatch('isSelectData')" v-if="enableEditData">{{ $t('product.product-modbus.562372-45') }}</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<!-- 选择物模型 -->
|
||||||
|
<things-list ref="thingsListRef" :productId="productId" @productEvent="getThingsData($event)" :justiceSelect="justiceSelect" />
|
||||||
|
<!-- 批量导入 -->
|
||||||
|
<import-batch ref="importBatchRef" :productId="productId" @data-imported="handleDataImport" :justiceSelect="justiceSelect" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { listDeviceConfig, addDeviceBatch } from '@/api/iot/deviceModbusConfig';
|
||||||
|
import { getlListModbus } from '@/api/iot/model';
|
||||||
|
// 设备复用产品的物模型选择列表
|
||||||
|
import thingsList from '../product/things-model-list';
|
||||||
|
// 设备复用产品的批量导入组件
|
||||||
|
import importBatch from '../product/components/batchImportModbus';
|
||||||
|
import Sortable from 'sortablejs';
|
||||||
|
import { addOrUpdate, getByProductId } from '@/api/iot/params';
|
||||||
|
import { listProductJob } from '@/api/iot/modbusJob';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'device-modbus',
|
||||||
|
dicts: ['iot_modbus_data_type', 'iot_yes_no', 'data_collect_type', 'device_status_deter', 'iot_modbus_poll_time'],
|
||||||
|
props: {
|
||||||
|
device: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
thingsList,
|
||||||
|
importBatch,
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
// 获取到父组件传递的productId后,刷新列表
|
||||||
|
device: function (newVal, oldVal) {
|
||||||
|
this.productInfo = newVal;
|
||||||
|
if (this.productInfo && this.productInfo.productId != 0) {
|
||||||
|
this.thingsModelParams.productId = this.productInfo.productId;
|
||||||
|
this.queryParamsIO.productId = this.productInfo.productId;
|
||||||
|
this.queryParamsData.productId = this.productInfo.productId;
|
||||||
|
this.queryParamsIO.deviceId = this.productInfo.deviceId;
|
||||||
|
this.queryParamsData.deviceId = this.productInfo.deviceId;
|
||||||
|
this.productId = this.productInfo.productId;
|
||||||
|
this.deviceId = this.productInfo.deviceId;
|
||||||
|
this.getIOList();
|
||||||
|
this.getDataList();
|
||||||
|
this.getThingsModelList();
|
||||||
|
this.getParams();
|
||||||
|
this.sendPollType();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
enableEditIO: function (n, old) {
|
||||||
|
//设置行是否拖拽
|
||||||
|
if (this.sortableIo) this.sortableIo.option('disabled', !n);
|
||||||
|
//关闭编辑刷新页面
|
||||||
|
if (!n) {
|
||||||
|
this.getIOList();
|
||||||
|
this.getThingsModelList();
|
||||||
|
}
|
||||||
|
//清空删除数组
|
||||||
|
this.delIoIds = [];
|
||||||
|
this.getThingsModelList();
|
||||||
|
},
|
||||||
|
enableEditData: function (n, old) {
|
||||||
|
//设置行是否拖拽
|
||||||
|
if (this.sortableData) this.sortableData.option('disabled', !n);
|
||||||
|
//关闭编辑刷新页面
|
||||||
|
if (!n) {
|
||||||
|
this.getDataList();
|
||||||
|
this.getThingsModelList();
|
||||||
|
}
|
||||||
|
//清空删除数组
|
||||||
|
this.delDataIds = [];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 遮罩层
|
||||||
|
loadingIO: true,
|
||||||
|
loadingData: true,
|
||||||
|
// 选中数组
|
||||||
|
ids: [],
|
||||||
|
// 非单个禁用
|
||||||
|
single: true,
|
||||||
|
// 非多个禁用
|
||||||
|
multiple: true,
|
||||||
|
// 显示搜索条件
|
||||||
|
showSearch: true,
|
||||||
|
// 总条数
|
||||||
|
total: 0,
|
||||||
|
// modbus配置表格数据
|
||||||
|
configList: [],
|
||||||
|
//io表格是否可以编辑
|
||||||
|
enableEditIO: false,
|
||||||
|
//子设备配置是否可编辑
|
||||||
|
enableSetSlave: false,
|
||||||
|
// 弹出层标题
|
||||||
|
title: '',
|
||||||
|
// 是否显示弹出层
|
||||||
|
open: false,
|
||||||
|
// 查询参数
|
||||||
|
queryParamsIO: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
identifier: null,
|
||||||
|
address: null,
|
||||||
|
isReadonly: null,
|
||||||
|
dataType: null,
|
||||||
|
quantity: null,
|
||||||
|
type: 1,
|
||||||
|
productId: 0,
|
||||||
|
deviceId: 0,
|
||||||
|
},
|
||||||
|
// 查询参数
|
||||||
|
queryParamsData: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
identifier: null,
|
||||||
|
address: null,
|
||||||
|
isReadonly: null,
|
||||||
|
dataType: null,
|
||||||
|
quantity: null,
|
||||||
|
type: 2,
|
||||||
|
productId: 0,
|
||||||
|
deviceId: 0,
|
||||||
|
},
|
||||||
|
//产品id
|
||||||
|
productId: 0,
|
||||||
|
//设备id
|
||||||
|
deviceId: 0,
|
||||||
|
//数据寄存器
|
||||||
|
dataModbusList: [],
|
||||||
|
//io表格是否可以编辑
|
||||||
|
enableEditData: false,
|
||||||
|
//数据寄存器总条数
|
||||||
|
dataTotal: 0,
|
||||||
|
// 数据寄存器遮罩层
|
||||||
|
dataLoading: true,
|
||||||
|
|
||||||
|
//可选属性
|
||||||
|
thingsModelList: [],
|
||||||
|
//物模型遮罩层
|
||||||
|
thingsLoading: true,
|
||||||
|
//thingsModel
|
||||||
|
thingsModelParams: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 1000,
|
||||||
|
productId: 0,
|
||||||
|
},
|
||||||
|
thingsTotal: 0,
|
||||||
|
// 表单参数
|
||||||
|
form: {
|
||||||
|
statusDeter: 1,
|
||||||
|
slaveId: null,
|
||||||
|
pollType: 0,
|
||||||
|
deterTimer: '300',
|
||||||
|
},
|
||||||
|
productInfo: {},
|
||||||
|
// 表单校验
|
||||||
|
rules: {
|
||||||
|
slaveId: [{ required: true, message: this.$t('product.product-modbus.562372-46'), trigger: 'blur' }],
|
||||||
|
address: [{ required: true, message: this.$t('product.product-modbus.562372-47'), trigger: 'blur' }],
|
||||||
|
isReadonly: [{ required: true, message: this.$t('product.product-modbus.562372-48'), trigger: 'blur' }],
|
||||||
|
dataType: [{ required: true, message: this.$t('product.product-modbus.562372-49'), trigger: 'change' }],
|
||||||
|
quantity: [{ required: true, message: this.$t('product.product-modbus.562372-50'), trigger: 'blur' }],
|
||||||
|
type: [{ required: true, message: this.$t('product.product-modbus.562372-51'), trigger: 'change' }],
|
||||||
|
},
|
||||||
|
//IO行拖拽对象
|
||||||
|
sortableIo: null,
|
||||||
|
//ioTable的key值,主要用于拖拽后重绘
|
||||||
|
configTableKey: 0,
|
||||||
|
//ioTable删除的id
|
||||||
|
delIoIds: [],
|
||||||
|
//数据寄存器行拖拽对象
|
||||||
|
sortableData: null,
|
||||||
|
//dataTable的key值,主要用于拖拽后重绘
|
||||||
|
dataTableKey: 1000,
|
||||||
|
//dataTable删除的id
|
||||||
|
delDataIds: [],
|
||||||
|
//判断多选物模型是io还是data,isSelectIo是判断是否可选io的,isSelectData是判断数据寄存器的,都是false不可选,true可选
|
||||||
|
justiceSelect: 'isSelectData',
|
||||||
|
jobTotal: 0,
|
||||||
|
// 设备模式下默认关闭导入导出按钮
|
||||||
|
enableImportExport: false,
|
||||||
|
// 显示网关子设备配置(状态判断/采集方式/默认子设备地址)
|
||||||
|
showParamsSection: true,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.rowDropIo();
|
||||||
|
this.rowDropData();
|
||||||
|
if (this.device && this.device.deviceId) {
|
||||||
|
this.productInfo = this.device;
|
||||||
|
this.productId = this.device.productId;
|
||||||
|
this.deviceId = this.device.deviceId;
|
||||||
|
this.queryParamsIO.productId = this.device.productId;
|
||||||
|
this.queryParamsIO.deviceId = this.device.deviceId;
|
||||||
|
this.queryParamsData.productId = this.device.productId;
|
||||||
|
this.queryParamsData.deviceId = this.device.deviceId;
|
||||||
|
this.thingsModelParams.productId = this.device.productId;
|
||||||
|
this.getIOList();
|
||||||
|
this.getDataList();
|
||||||
|
this.getThingsModelList();
|
||||||
|
this.getParams();
|
||||||
|
this.getTaskList(this.productInfo.productId);
|
||||||
|
this.sendPollType();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/** 查询modbusIO寄存器列表 */
|
||||||
|
getIOList() {
|
||||||
|
this.loadingIO = true;
|
||||||
|
listDeviceConfig(this.queryParamsIO).then((response) => {
|
||||||
|
this.configList = response.rows;
|
||||||
|
this.total = response.total;
|
||||||
|
this.loadingIO = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//传值
|
||||||
|
sendPollType() {
|
||||||
|
if (!this.showParamsSection) return;
|
||||||
|
this.$emit('sendPollType', this.form.pollType);
|
||||||
|
},
|
||||||
|
handleDataImport(data) {
|
||||||
|
this.configList = data;
|
||||||
|
},
|
||||||
|
/** 查询modbus数据寄存器列表 */
|
||||||
|
getDataList() {
|
||||||
|
this.loadingData = true;
|
||||||
|
listDeviceConfig(this.queryParamsData).then((response) => {
|
||||||
|
this.dataModbusList = response.rows;
|
||||||
|
this.dataTotal = response.total;
|
||||||
|
this.loadingData = false;
|
||||||
|
});
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.Dataable.bodyWrapper.scrollTop = 0;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 查询产品物模型列表 */
|
||||||
|
getThingsModelList() {
|
||||||
|
this.thingsLoading = true;
|
||||||
|
getlListModbus(this.thingsModelParams).then((response) => {
|
||||||
|
this.$refs.thingsListRef.modelList = response.rows;
|
||||||
|
this.thingsModelList = response.rows;
|
||||||
|
this.thingsTotal = response.total;
|
||||||
|
this.thingsLoading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 取消按钮
|
||||||
|
cancel() {
|
||||||
|
this.open = false;
|
||||||
|
this.reset();
|
||||||
|
},
|
||||||
|
// 表单重置
|
||||||
|
reset() {
|
||||||
|
this.form = {
|
||||||
|
statusDeter: 1,
|
||||||
|
slaveId: null,
|
||||||
|
// pollType: '0',
|
||||||
|
deterTime: '300',
|
||||||
|
};
|
||||||
|
this.resetForm('form');
|
||||||
|
},
|
||||||
|
|
||||||
|
// 多选框选中数据
|
||||||
|
handleSelectionChange(selection) {
|
||||||
|
this.ids = selection.map((item) => item.id);
|
||||||
|
this.single = selection.length !== 1;
|
||||||
|
this.multiple = !selection.length;
|
||||||
|
},
|
||||||
|
/** 新增IO寄存器行操作 */
|
||||||
|
handleAdd() {
|
||||||
|
var d = {
|
||||||
|
identifier: '',
|
||||||
|
slave: 1,
|
||||||
|
address: 1,
|
||||||
|
isReadonly: 1,
|
||||||
|
type: 1,
|
||||||
|
quantity: 1,
|
||||||
|
sort: this.configList.length + 1,
|
||||||
|
};
|
||||||
|
this.configList.push(d);
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$refs.IOTable.setCurrentRow(d);
|
||||||
|
}, 10);
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 新增数据寄存器行操作 */
|
||||||
|
handleAddData() {
|
||||||
|
var d = {
|
||||||
|
identifier: '',
|
||||||
|
slave: 1,
|
||||||
|
address: 1,
|
||||||
|
isReadonly: 1,
|
||||||
|
dataType: 'ushort',
|
||||||
|
quantity: 1,
|
||||||
|
type: 2,
|
||||||
|
sort: this.dataModbusList.length + 1,
|
||||||
|
};
|
||||||
|
this.dataModbusList.push(d);
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$refs.Dataable.setCurrentRow(d);
|
||||||
|
}, 10);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleAddBatch(justiceSelect) {
|
||||||
|
this.justiceSelect = justiceSelect;
|
||||||
|
this.$refs.thingsListRef.open = true;
|
||||||
|
this.$refs.thingsListRef.selectedList = justiceSelect == 'isSelectData' ? this.dataModbusList : this.configList;
|
||||||
|
this.$refs.thingsListRef.getList();
|
||||||
|
},
|
||||||
|
/**点击编辑IO控制器*/
|
||||||
|
editIOModbus() {
|
||||||
|
this.enableEditIO = !this.enableEditIO;
|
||||||
|
},
|
||||||
|
/**点击取消IO寄存器编辑按钮*/
|
||||||
|
handleCancelIO() {
|
||||||
|
this.enableEditIO = !this.enableEditIO;
|
||||||
|
},
|
||||||
|
/**点击取消数据寄存器编辑按钮*/
|
||||||
|
handleCancelData() {
|
||||||
|
this.enableEditData = !this.enableEditData;
|
||||||
|
},
|
||||||
|
/**点击编辑数据寄存器*/
|
||||||
|
editDataModbus() {
|
||||||
|
this.enableEditData = !this.enableEditData;
|
||||||
|
},
|
||||||
|
|
||||||
|
/** IO寄存器提交按钮 */
|
||||||
|
submitFormIO() {
|
||||||
|
const configList = [];
|
||||||
|
this.configList.forEach((config, index) => {
|
||||||
|
if (config.identifier) {
|
||||||
|
config.sort = configList.length + 1;
|
||||||
|
configList.push(config);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.loadingIO = true;
|
||||||
|
const data = { productId: this.productId, deviceId: this.deviceId, configList: configList, delIds: this.delIoIds };
|
||||||
|
addDeviceBatch(data)
|
||||||
|
.then((response) => {
|
||||||
|
this.$modal.msgSuccess('保存成功');
|
||||||
|
this.getIOList();
|
||||||
|
this.open = false;
|
||||||
|
this.loadingIO = false;
|
||||||
|
this.enableEditIO = false;
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
this.loadingIO = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 数据寄存器提交按钮 */
|
||||||
|
submitFormData() {
|
||||||
|
const dataModbusList = [];
|
||||||
|
this.dataModbusList.forEach((dataModbus, index) => {
|
||||||
|
if (dataModbus.identifier) {
|
||||||
|
dataModbus.sort = dataModbusList.length + 1;
|
||||||
|
dataModbusList.push(dataModbus);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.loadingData = true;
|
||||||
|
const data = { productId: this.productId, deviceId: this.deviceId, configList: dataModbusList, delIds: this.delDataIds };
|
||||||
|
addDeviceBatch(data)
|
||||||
|
.then((response) => {
|
||||||
|
this.$modal.msgSuccess(this.$t('product.product-modbus.562372-52'));
|
||||||
|
this.open = false;
|
||||||
|
this.enableEditData = false;
|
||||||
|
this.loadingData = false;
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
this.loadingData = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 删除按钮操作 */
|
||||||
|
handleDelete(row, index, list, justiceSelect) {
|
||||||
|
const item = list.splice(index, 1)[0];
|
||||||
|
//如果是删除数据寄存器,并且有id就存id
|
||||||
|
if (justiceSelect == 'isSelectData' && row.id) this.delDataIds.push(row.id);
|
||||||
|
//如果是删除io,并且有id就存id
|
||||||
|
if (justiceSelect == 'isSelectIo' && row.id) this.delIoIds.push(row.id);
|
||||||
|
//处理选项是否可选
|
||||||
|
this.updateSelectThingsModel({ justiceSelect, oldVal: item.identifier });
|
||||||
|
},
|
||||||
|
|
||||||
|
/*获取选择的物模型*/
|
||||||
|
getThingsData(ids) {
|
||||||
|
const list = this.justiceSelect == 'isSelectData' ? this.dataModbusList : this.configList;
|
||||||
|
ids.forEach((id, index) => {
|
||||||
|
const findIndex = list.findIndex((item) => item.identifier == id);
|
||||||
|
if (findIndex == -1) {
|
||||||
|
list.push({
|
||||||
|
identifier: id,
|
||||||
|
slave: 1,
|
||||||
|
address: 1,
|
||||||
|
isReadonly: 1,
|
||||||
|
dataType: 'ushort',
|
||||||
|
quantity: 1,
|
||||||
|
type: this.justiceSelect == 'isSelectData' ? 2 : 1,
|
||||||
|
sort: list.length + 1,
|
||||||
|
});
|
||||||
|
this.updateSelectThingsModel({ justiceSelect: this.justiceSelect, newVal: id });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io拖拽行
|
||||||
|
*/
|
||||||
|
rowDropIo() {
|
||||||
|
const tbodyIo = this.$refs.IOTable.$el.children[2].children[0].children[1];
|
||||||
|
this.sortableIo = new Sortable(tbodyIo, {
|
||||||
|
disabled: true,
|
||||||
|
onEnd: ({ newIndex, oldIndex, to }) => {
|
||||||
|
this.dealDrop(this.configList, newIndex, oldIndex);
|
||||||
|
this.configTableKey++;
|
||||||
|
this.sortableIo.destroy();
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.rowDropIo();
|
||||||
|
this.sortableIo.option('disabled', false);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 数据寄存器拖拽
|
||||||
|
*/
|
||||||
|
rowDropData() {
|
||||||
|
const tbodyData = this.$refs.Dataable.$el.children[2].children[0].children[1];
|
||||||
|
this.sortableData = new Sortable(tbodyData, {
|
||||||
|
disabled: true,
|
||||||
|
onEnd: ({ newIndex, oldIndex, to }) => {
|
||||||
|
this.dealDrop(this.dataModbusList, newIndex, oldIndex);
|
||||||
|
this.dataTableKey++;
|
||||||
|
this.sortableData.destroy();
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.rowDropData();
|
||||||
|
this.sortableData.option('disabled', false);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//处理拖拽后的数据
|
||||||
|
dealDrop(list, newIndex, oldIndex) {
|
||||||
|
if (oldIndex == newIndex) return;
|
||||||
|
//找到选中那列,移除出数组
|
||||||
|
const curRow = list.splice(oldIndex, 1)[0];
|
||||||
|
//将选择中那列查到新位置
|
||||||
|
list.splice(newIndex, 0, curRow);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 更新物模型是否可选
|
||||||
|
*/
|
||||||
|
updateSelectThingsModel({ oldVal, newVal, justiceSelect }) {
|
||||||
|
//直接改前后值
|
||||||
|
const oldIndex = oldVal ? this.thingsModelList.findIndex((thingsModel) => thingsModel.identifier == oldVal) : -1;
|
||||||
|
const newIndex = newVal ? this.thingsModelList.findIndex((thingsModel) => thingsModel.identifier == newVal) : -1;
|
||||||
|
if (oldIndex != -1) this.thingsModelList[oldIndex][justiceSelect] = true;
|
||||||
|
if (newIndex != -1) this.thingsModelList[newIndex][justiceSelect] = false;
|
||||||
|
},
|
||||||
|
/**批量导入 */
|
||||||
|
batchImport(justiceSelect) {
|
||||||
|
this.justiceSelect = justiceSelect;
|
||||||
|
this.$refs.importBatchRef.upload.importDeviceDialog = true;
|
||||||
|
},
|
||||||
|
/**导出 */
|
||||||
|
exportModbus(justiceSelect) {
|
||||||
|
const type = justiceSelect == 'isSelectData' ? 2 : 1;
|
||||||
|
const name = justiceSelect == 'isSelectData' ? this.$t('product.product-modbus.562372-17') : this.$t('product.product-modbus.562372-38');
|
||||||
|
this.download('/modbus/config/exportModbus?type=' + type, {}, `${name}_${new Date().getTime()}.xlsx`);
|
||||||
|
},
|
||||||
|
/**获取modbus参数配置*/
|
||||||
|
getParams() {
|
||||||
|
if (!this.showParamsSection) return;
|
||||||
|
const params = { productId: this.productId };
|
||||||
|
getByProductId(params).then((response) => {
|
||||||
|
if (response.data) {
|
||||||
|
this.form = response.data;
|
||||||
|
this.sendPollType();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**编辑modbus配置参数*/
|
||||||
|
setSlave() {
|
||||||
|
this.enableSetSlave = !this.enableSetSlave;
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 保存modbus配置参数 */
|
||||||
|
saveSlave() {
|
||||||
|
this.$refs['form'].validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
this.enableSetSlave = !this.enableSetSlave;
|
||||||
|
this.form.productId = this.productId;
|
||||||
|
addOrUpdate(this.form).then((response) => {
|
||||||
|
this.$modal.msgSuccess(this.$t('product.product-modbus.562372-53'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.sendPollType();
|
||||||
|
},
|
||||||
|
//改变采集方式
|
||||||
|
changePollType() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.getTaskList(this.productInfo.productId);
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.form.pollType === 1) {
|
||||||
|
if (this.jobTotal > 0) {
|
||||||
|
this.$confirm(this.$t('product.product-modbus.562372-312'), this.$t('product.product-modbus.562372-313'), {
|
||||||
|
confirmButtonText: this.$t('product.product-modbus.562372-314'),
|
||||||
|
cancelButtonText: this.$t('product.product-modbus.562372-315'),
|
||||||
|
type: 'warning',
|
||||||
|
})
|
||||||
|
.then(() => {})
|
||||||
|
.catch(() => {
|
||||||
|
this.form.pollType = 0;
|
||||||
|
this.$message({
|
||||||
|
type: 'info',
|
||||||
|
message: this.$t('product.product-modbus.562372-316'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
},
|
||||||
|
/** 查询轮训任务列列表 */
|
||||||
|
getTaskList(productId) {
|
||||||
|
this.loading = true;
|
||||||
|
const params = {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
productId: productId,
|
||||||
|
};
|
||||||
|
listProductJob(params).then((response) => {
|
||||||
|
this.jobList = response.rows;
|
||||||
|
this.jobTotal = response.total;
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**取消*/
|
||||||
|
cancelSlave() {
|
||||||
|
this.enableSetSlave = !this.enableSetSlave;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.el-input-number.is-disabled .el-input__inner {
|
||||||
|
color: #111315;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select .el-input.is-disabled .el-input__inner {
|
||||||
|
color: #0c0d0e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-radio-button__orig-radio:disabled:checked + .el-radio-button__inner {
|
||||||
|
background-color: #409eff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.head {
|
||||||
|
.head-title {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-top: 16px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tips {
|
||||||
|
color: grey;
|
||||||
|
line-height: 36px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-group {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.right-btns {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.test_div {
|
||||||
|
width: 300px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -544,10 +544,10 @@ export default {
|
|||||||
// 控制模块标题
|
// 控制模块标题
|
||||||
title: '设备控制 ',
|
title: '设备控制 ',
|
||||||
// 未启用设备影子
|
// 未启用设备影子
|
||||||
shadowUnEnable: false,
|
shadowUnEnable: true,
|
||||||
// 控制项标题背景
|
// 控制项标题背景(默认灰色表示离线/未激活状态)
|
||||||
statusColor: {
|
statusColor: {
|
||||||
background: '#67C23A',
|
background: '#909399',
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
minWidth: '100px',
|
minWidth: '100px',
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user