fix: 设备解绑后,新生成一个无用户无塘口的设备信息。

This commit is contained in:
tianyongbao
2026-05-12 05:49:27 +08:00
parent b643662856
commit 02cf52aed4

View File

@@ -9,6 +9,7 @@ import com.intc.common.core.utils.MapstructUtils;
import com.intc.common.core.utils.StringUtils;
import com.intc.common.mybatis.core.page.PageQuery;
import com.intc.common.mybatis.core.page.TableDataInfo;
import com.intc.common.redis.utils.RedisUtils;
import com.intc.fishery.domain.AquUser;
import com.intc.fishery.domain.Device;
import com.intc.fishery.domain.DeviceBindRecord;
@@ -20,6 +21,8 @@ import com.intc.fishery.domain.Pond;
import com.intc.fishery.domain.TimingCtrl;
import com.intc.fishery.domain.bo.DeviceBo;
import com.intc.fishery.domain.vo.DeviceVo;
import com.intc.fishery.constant.DefineDeviceWarnCode;
import com.intc.fishery.mapper.AquUserMapper;
import com.intc.fishery.mapper.DeviceBindRecordMapper;
import com.intc.fishery.mapper.DeviceCorrectRecordMapper;
import com.intc.fishery.mapper.DeviceErrorCodeMapper;
@@ -28,6 +31,7 @@ import com.intc.fishery.mapper.DeviceSwitchMapper;
import com.intc.fishery.mapper.LinkedCtrlMapper;
import com.intc.fishery.mapper.TimingCtrlMapper;
import com.intc.fishery.service.IDeviceService;
import com.intc.fishery.utils.MessageOpRecordUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -49,6 +53,7 @@ import lombok.extern.slf4j.Slf4j;
public class DeviceServiceImpl implements IDeviceService {
private final DeviceMapper baseMapper;
private final AquUserMapper aquUserMapper;
private final DeviceBindRecordMapper deviceBindRecordMapper;
private final DeviceCorrectRecordMapper deviceCorrectRecordMapper;
private final DeviceErrorCodeMapper deviceErrorCodeMapper;
@@ -56,6 +61,11 @@ public class DeviceServiceImpl implements IDeviceService {
private final LinkedCtrlMapper linkedCtrlMapper;
private final TimingCtrlMapper timingCtrlMapper;
/** Redis 离线等待标记前缀(与 DeviceDataHandler 保持一致) */
private static final String DEVICE_OFFLINE_WAIT_KEY_PREFIX = "device:offline:wait:";
/** Redis 溶解氧探头离线等待标记前缀 */
private static final String DETECTOR_OXY_OFFLINE_WAIT_KEY_PREFIX = "device:detector:oxy:offline:wait:";
/**
* 查询设备管理
*
@@ -224,8 +234,18 @@ public class DeviceServiceImpl implements IDeviceService {
}
/**
* 校验并批量删除设备管理信息
* 删除顺序:故障码 -> 校准记录 -> 定时控制 -> 开关(先解除联动控制引用) -> 联动控制 -> 设备
* 校验并批量删除设备管理信息(参考 C# DeleteDevice 逻辑)
* <p>
* 处理流程:
* 1. 查询完整设备信息与用户信息
* 2. 新增解绑记录
* 3. 删除联动控制
* 4. 删除关联数据(故障码、校准记录、定时控制、开关)
* 5. 删除设备
* 6. 非管理员用户创建新的无绑定设备保留IoT信息
* 7. 清除告警数据warnCode + Redis离线等待标记
* 8. 记录操作日志
* </p>
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
@@ -234,85 +254,23 @@ public class DeviceServiceImpl implements IDeviceService {
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
}
// 1. 删除设备关联的故障码记录
deviceErrorCodeMapper.delete(
new LambdaQueryWrapper<DeviceErrorCode>()
.in(DeviceErrorCode::getDeviceId, ids)
);
// 2. 删除设备关联的校准记录
deviceCorrectRecordMapper.delete(
new LambdaQueryWrapper<DeviceCorrectRecord>()
.in(DeviceCorrectRecord::getDeviceId, ids)
);
// 3. 查询设备关联的开关
List<DeviceSwitch> switches = deviceSwitchMapper.selectList(
new LambdaQueryWrapper<DeviceSwitch>()
.in(DeviceSwitch::getDeviceId, ids)
);
if (!switches.isEmpty()) {
// 收集开关ID
List<Long> switchIds = switches.stream()
.map(DeviceSwitch::getId)
.collect(Collectors.toList());
// 4. 删除开关关联的定时控制
timingCtrlMapper.delete(
new LambdaQueryWrapper<TimingCtrl>()
.in(TimingCtrl::getSwitchId, switchIds)
);
// 收集开关关联的联动控制ID
List<Long> linkedCtrlIds = switches.stream()
.map(DeviceSwitch::getLinkedCtrlId)
.filter(id -> id != null && id > 0)
.distinct()
.collect(Collectors.toList());
// 5. 解除开关与联动控制的绑定
deviceSwitchMapper.update(null,
new LambdaUpdateWrapper<DeviceSwitch>()
.set(DeviceSwitch::getLinkedCtrlId, null)
.in(DeviceSwitch::getDeviceId, ids)
);
// 6. 删除联动控制(如果有)
if (!linkedCtrlIds.isEmpty()) {
linkedCtrlMapper.delete(
new LambdaQueryWrapper<LinkedCtrl>()
.in(LinkedCtrl::getId, linkedCtrlIds)
);
}
// 7. 删除开关
deviceSwitchMapper.delete(
new LambdaQueryWrapper<DeviceSwitch>()
.in(DeviceSwitch::getDeviceId, ids)
);
}
// 8. 删除设备本身关联的联动控制
linkedCtrlMapper.delete(
new LambdaQueryWrapper<LinkedCtrl>()
.in(LinkedCtrl::getDeviceId, ids)
);
// 9. 查询要删除的设备信息,添加解绑记录
// 1. 先查询完整设备信息(删除前需要用到各字段)
List<Device> devicesToDelete = baseMapper.selectList(
new LambdaQueryWrapper<Device>()
.in(Device::getId, ids)
.select(Device::getId, Device::getUserId, Device::getIotId,
Device::getDeviceType, Device::getSerialNum)
);
if (devicesToDelete.isEmpty()) {
return false;
}
// 为每个设备添加解绑记录
for (Device device : devicesToDelete) {
Long deviceId = device.getId();
// 2. 新增解绑记录
try {
DeviceBindRecord unbindRecord = new DeviceBindRecord();
unbindRecord.setUserId(device.getUserId());
@@ -322,15 +280,135 @@ public class DeviceServiceImpl implements IDeviceService {
unbindRecord.setSerialNum(device.getSerialNum());
deviceBindRecordMapper.insert(unbindRecord);
log.info("添加设备解绑记录: deviceId={}, userId={}, serialNum={}",
device.getId(), device.getUserId(), device.getSerialNum());
deviceId, device.getUserId(), device.getSerialNum());
} catch (Exception e) {
log.error("添加设备解绑记录失败: deviceId={}, error={}", device.getId(), e.getMessage(), e);
// 不影响删除流程,继续执行
log.error("添加设备解绑记录失败: deviceId={}, error={}", deviceId, e.getMessage(), e);
}
// 3. 删除设备关联的联动控制
linkedCtrlMapper.delete(
new LambdaQueryWrapper<LinkedCtrl>()
.eq(LinkedCtrl::getDeviceId, deviceId)
);
// 4. 删除设备关联的故障码记录
deviceErrorCodeMapper.delete(
new LambdaQueryWrapper<DeviceErrorCode>()
.eq(DeviceErrorCode::getDeviceId, deviceId)
);
// 5. 删除设备关联的校准记录
deviceCorrectRecordMapper.delete(
new LambdaQueryWrapper<DeviceCorrectRecord>()
.eq(DeviceCorrectRecord::getDeviceId, deviceId)
);
// 6. 查询设备关联的开关,删除定时控制、解除联动绑定后删除开关
List<DeviceSwitch> switches = deviceSwitchMapper.selectList(
new LambdaQueryWrapper<DeviceSwitch>()
.eq(DeviceSwitch::getDeviceId, deviceId)
);
if (!switches.isEmpty()) {
List<Long> switchIds = switches.stream()
.map(DeviceSwitch::getId)
.collect(Collectors.toList());
// 删除开关关联的定时控制
timingCtrlMapper.delete(
new LambdaQueryWrapper<TimingCtrl>()
.in(TimingCtrl::getSwitchId, switchIds)
);
// 收集开关关联的联动控制ID
List<Long> linkedCtrlIds = switches.stream()
.map(DeviceSwitch::getLinkedCtrlId)
.filter(id -> id != null && id > 0)
.distinct()
.collect(Collectors.toList());
// 解除开关与联动控制的绑定
deviceSwitchMapper.update(null,
new LambdaUpdateWrapper<DeviceSwitch>()
.set(DeviceSwitch::getLinkedCtrlId, null)
.eq(DeviceSwitch::getDeviceId, deviceId)
);
// 删除联动控制(如果有)
if (!linkedCtrlIds.isEmpty()) {
linkedCtrlMapper.delete(
new LambdaQueryWrapper<LinkedCtrl>()
.in(LinkedCtrl::getId, linkedCtrlIds)
);
}
// 删除开关
deviceSwitchMapper.delete(
new LambdaQueryWrapper<DeviceSwitch>()
.eq(DeviceSwitch::getDeviceId, deviceId)
);
}
// 7. 删除设备记录
baseMapper.deleteById(deviceId);
// 8. 用户创建新的无绑定设备保留IoT信息清除用户和塘口关联
if (device.getUserId() != null) {
try {
AquUser user = aquUserMapper.selectById(device.getUserId());
if (user != null) {
Device newDevice = new Device();
newDevice.setUserId(null);
newDevice.setIsOxygenUsed(device.getIsOxygenUsed());
newDevice.setIotId(device.getIotId());
newDevice.setSerialNum(device.getSerialNum());
newDevice.setDeviceName(device.getDeviceName());
newDevice.setDeviceType(device.getDeviceType());
newDevice.setIccId(device.getIccId());
newDevice.setBindTime(device.getBindTime());
newDevice.setDeadTime(device.getDeadTime());
newDevice.setPondId(null);
newDevice.setSalinityCompensation(0.0);
newDevice.setOxyWarnLower(device.getOxyWarnLower());
newDevice.setOxyWarnCallOpen(0);
newDevice.setOxyWarnCallNoDis(0);
newDevice.setTempWarnCallOpen(0);
newDevice.setTempWarnCallNoDis(0);
newDevice.setWarnCode(DefineDeviceWarnCode.None);
newDevice.setCategory(device.getCategory());
baseMapper.insert(newDevice);
log.info("已为用户重建无绑定设备: oldDeviceId={}, newDeviceId={}, serialNum={}",
deviceId, newDevice.getId(), device.getSerialNum());
}
} catch (Exception e) {
log.error("重建无绑定设备失败: deviceId={}, error={}", deviceId, e.getMessage(), e);
}
}
// 9. 清除告警数据Redis离线等待标记
try {
String serialNum = device.getSerialNum();
if (StringUtils.isNotBlank(serialNum)) {
RedisUtils.deleteObject(DEVICE_OFFLINE_WAIT_KEY_PREFIX + serialNum);
RedisUtils.deleteObject(DETECTOR_OXY_OFFLINE_WAIT_KEY_PREFIX + serialNum);
log.info("已清除设备Redis告警标记: serialNum={}", serialNum);
}
} catch (Exception e) {
log.error("清除Redis告警标记失败: deviceId={}, error={}", deviceId, e.getMessage(), e);
}
// 10. 记录操作日志
try {
MessageOpRecordUtil.addMessageOpRecordUser(
device.getUserId(), device.getUserId(),
"设备操作",
String.format("%s(%s),解除绑定。", device.getDeviceName(), device.getSerialNum())
);
} catch (Exception e) {
log.error("记录操作日志失败: deviceId={}, error={}", deviceId, e.getMessage(), e);
}
}
// 10. 最后删除设备
return baseMapper.deleteByIds(ids) > 0;
return true;
}