From c386e47e77c5df9e37eabee9bfad595827d98f8b Mon Sep 17 00:00:00 2001 From: tianyongbao Date: Sun, 12 Jul 2026 09:32:01 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=AE=BE=E5=A4=87=E7=AE=A1=E7=90=86?= =?UTF-8?q?=EF=BC=8C=E6=96=B0=E5=A2=9E=E7=89=A9=E7=90=86=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fishery/controller/DeviceController.java | 35 ++++- .../intc/fishery/service/IDeviceService.java | 9 ++ .../service/impl/DeviceServiceImpl.java | 125 ++++++++++++++++++ 3 files changed, 168 insertions(+), 1 deletion(-) diff --git a/intc-modules/intc-fishery/src/main/java/com/intc/fishery/controller/DeviceController.java b/intc-modules/intc-fishery/src/main/java/com/intc/fishery/controller/DeviceController.java index eea8720..3cc67c9 100644 --- a/intc-modules/intc-fishery/src/main/java/com/intc/fishery/controller/DeviceController.java +++ b/intc-modules/intc-fishery/src/main/java/com/intc/fishery/controller/DeviceController.java @@ -148,7 +148,7 @@ public class DeviceController extends BaseController { } /** - * 删除设备管理 + * 删除设备管理(解绑模式:删除后重建设备记录,保留IoT信息) * * @param ids 主键串 */ @@ -160,6 +160,39 @@ public class DeviceController extends BaseController { return toAjax(deviceService.deleteWithValidByIds(List.of(ids), true)); } + /** + * 彻底删除设备及其所有关联数据(物理删除,不重建设备记录) + *

删除范围:设备记录、开关、定时控制、联动控制、故障码记录、校准记录、绑定/解绑记录、TDengine时序数据、Redis告警标记 + *

与普通删除的区别:不重建设备记录,设备彻底从系统中移除

+ * + * @param ids 主键串 + * @return 操作结果 + */ + @SaCheckPermission("fishery:device:remove") + @Log(title = "设备管理", businessType = BusinessType.DELETE) + @DeleteMapping("/hard_delete/{ids}") + public R hardDelete(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + // 1. 删除TDengine时序数据(需在设备记录删除前,通过serialNum清理) + if (deviceSensorDataService != null) { + for (Long id : ids) { + Device device = deviceMapper.selectById(id); + if (device != null && device.getSerialNum() != null && !device.getSerialNum().isBlank()) { + try { + deviceSensorDataService.dropSubTable(device.getSerialNum()); + } catch (Exception e) { + org.slf4j.LoggerFactory.getLogger(DeviceController.class) + .warn("彻底删除-清理TDengine数据失败: deviceId={}, serialNum={}, error={}", + id, device.getSerialNum(), e.getMessage()); + } + } + } + } + + // 2. 执行彻底删除(设备记录、关联数据、Redis标记) + return toAjax(deviceService.hardDeleteByIds(List.of(ids))); + } + /** * 清零设备测试数据(出厂测试用) *

清理范围: diff --git a/intc-modules/intc-fishery/src/main/java/com/intc/fishery/service/IDeviceService.java b/intc-modules/intc-fishery/src/main/java/com/intc/fishery/service/IDeviceService.java index d0c9aab..5cd831a 100644 --- a/intc-modules/intc-fishery/src/main/java/com/intc/fishery/service/IDeviceService.java +++ b/intc-modules/intc-fishery/src/main/java/com/intc/fishery/service/IDeviceService.java @@ -65,4 +65,13 @@ public interface IDeviceService { * @return 是否删除成功 */ Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 彻底删除设备及其所有关联数据(不重建设备记录) + *

删除范围:设备记录、开关、定时控制、联动控制、故障码记录、校准记录、绑定记录、Redis告警标记

+ * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + Boolean hardDeleteByIds(Collection ids); } diff --git a/intc-modules/intc-fishery/src/main/java/com/intc/fishery/service/impl/DeviceServiceImpl.java b/intc-modules/intc-fishery/src/main/java/com/intc/fishery/service/impl/DeviceServiceImpl.java index 8e38c4d..303b0a7 100644 --- a/intc-modules/intc-fishery/src/main/java/com/intc/fishery/service/impl/DeviceServiceImpl.java +++ b/intc-modules/intc-fishery/src/main/java/com/intc/fishery/service/impl/DeviceServiceImpl.java @@ -462,7 +462,132 @@ public class DeviceServiceImpl implements IDeviceService { return true; } + /** + * 彻底删除设备及其所有关联数据(不重建设备记录) + * 与 deleteWithValidByIds 的区别: + * - 不插入解绑记录 + * - 不重建无绑定设备 + * - 额外删除该设备的所有绑定/解绑记录 + * 设备关联数据全部清除,包括:联动控制、故障码、校准记录、开关、定时控制、绑定记录、Redis告警标记 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean hardDeleteByIds(Collection ids) { + // 1. 先查询完整设备信息(删除前需要用到各字段) + List devicesToDelete = baseMapper.selectList( + new LambdaQueryWrapper() + .in(Device::getId, ids) + ); + if (devicesToDelete.isEmpty()) { + return false; + } + for (Device device : devicesToDelete) { + Long deviceId = device.getId(); + + // 2. 删除设备关联的联动控制 + linkedCtrlMapper.delete( + new LambdaQueryWrapper() + .eq(LinkedCtrl::getDeviceId, deviceId) + ); + + // 3. 删除设备关联的故障码记录 + deviceErrorCodeMapper.delete( + new LambdaQueryWrapper() + .eq(DeviceErrorCode::getDeviceId, deviceId) + ); + + // 4. 删除设备关联的校准记录 + deviceCorrectRecordMapper.delete( + new LambdaQueryWrapper() + .eq(DeviceCorrectRecord::getDeviceId, deviceId) + ); + + // 5. 删除设备关联的开关、定时控制、联动绑定 + List switches = deviceSwitchMapper.selectList( + new LambdaQueryWrapper() + .eq(DeviceSwitch::getDeviceId, deviceId) + ); + if (!switches.isEmpty()) { + List switchIds = switches.stream() + .map(DeviceSwitch::getId) + .collect(Collectors.toList()); + + // 删除开关关联的定时控制 + timingCtrlMapper.delete( + new LambdaQueryWrapper() + .in(TimingCtrl::getSwitchId, switchIds) + ); + + // 收集开关关联的联动控制ID + List linkedCtrlIds = switches.stream() + .map(DeviceSwitch::getLinkedCtrlId) + .filter(id -> id != null && id > 0) + .distinct() + .collect(Collectors.toList()); + + // 解除开关与联动控制的绑定 + deviceSwitchMapper.update(null, + new LambdaUpdateWrapper() + .set(DeviceSwitch::getLinkedCtrlId, null) + .eq(DeviceSwitch::getDeviceId, deviceId) + ); + + // 删除联动控制(如果有) + if (!linkedCtrlIds.isEmpty()) { + linkedCtrlMapper.delete( + new LambdaQueryWrapper() + .in(LinkedCtrl::getId, linkedCtrlIds) + ); + } + + // 删除开关 + deviceSwitchMapper.delete( + new LambdaQueryWrapper() + .eq(DeviceSwitch::getDeviceId, deviceId) + ); + } + + // 6. 删除该设备的所有绑定/解绑记录 + if (StringUtils.isNotBlank(device.getSerialNum())) { + deviceBindRecordMapper.delete( + new LambdaQueryWrapper() + .eq(DeviceBindRecord::getSerialNum, device.getSerialNum()) + ); + } + + // 7. 物理删除设备记录 + baseMapper.deleteById(deviceId); + + // 8. 清除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); + } + + // 9. 记录操作日志 + 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); + } + } + + return true; + } /** * 计算设备列表的过期信息