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;
+ }
/**
* 计算设备列表的过期信息