fix: 控制器定时控制删除时,实际未删除。

This commit is contained in:
tianyongbao
2026-04-26 11:18:59 +08:00
parent d34e47dbf7
commit e98460af07

View File

@@ -2634,6 +2634,77 @@ public class IotController extends BaseController {
}
}
/**
* 强制同步开关定时控制到设备(运维补救接口)
* 用于修复历史上因错误删除逻辑导致设备端槽位残留的问题:
* 将数据库中该开关当前全量定时列表推送给设备,设备端多余的历史槽位将被覆盖为 isValid=0
*
* @param switchId 开关ID
* @return 操作结果
*/
@Operation(summary = "强制同步定时控制到设备")
@PostMapping("/timingCtrl/syncToDevice")
public R<Void> syncTimingCtrlToDevice(@RequestParam Long switchId) {
try {
// 查询开关信息
DeviceSwitch deviceSwitch = deviceSwitchMapper.selectOne(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<DeviceSwitch>()
.eq(DeviceSwitch::getId, switchId)
.select(DeviceSwitch::getId,
DeviceSwitch::getDeviceId,
DeviceSwitch::getIndex,
DeviceSwitch::getSwitchName)
);
if (deviceSwitch == null) {
return R.fail("开关不存在");
}
// 查询设备信息
Device device = deviceMapper.selectOne(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<Device>()
.eq(Device::getId, deviceSwitch.getDeviceId())
.select(Device::getId, Device::getUserId, Device::getDeviceName,
Device::getIotId, Device::getSerialNum, Device::getWarnCode, Device::getDeadTime)
);
if (device == null) {
return R.fail("设备不存在");
}
// 查询该开关在数据库中的全量定时控制
java.util.List<TimingCtrl> allTimingCtrls = timingCtrlMapper.selectList(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<TimingCtrl>()
.eq(TimingCtrl::getSwitchId, switchId)
);
// 直接构建属性并推送到设备,传 timeCtrlId=-1无匹配项跳过特殊时间重算
// 数据库中不存在的历史槽位不会出现在 listTimingCtrl 中,设备收到后会用 isValid=0 的空槽覆盖
Map<String, Object> properties = new java.util.HashMap<>();
java.util.List<Object> listTimingCtrl = new java.util.ArrayList<>();
for (TimingCtrl tc : allTimingCtrls) {
Map<String, Object> timeCtrl = new java.util.HashMap<>();
timeCtrl.put("timerMode", tc.getLoopType() != null ? tc.getLoopType() - 1 : 0);
timeCtrl.put("isValid", tc.getIsOpen() != null && tc.getIsOpen() == 1 ? 1 : 0);
timeCtrl.put("onTime", String.valueOf(tc.getOpenTime().getTime() / 1000));
timeCtrl.put("offTime", String.valueOf(tc.getCloseTime().getTime() / 1000));
listTimingCtrl.add(timeCtrl);
}
String propertyKey = IOTPropertyName.LOCAL_TIMER_SWITCH + deviceSwitch.getIndex();
properties.put(propertyKey, listTimingCtrl);
boolean setOk = iotCloudService.setProperty(device.getIotId(), properties, false, 0);
if (!setOk) {
return R.fail("推送设备失败");
}
log.info("[SyncTimingCtrl] 强制同步定时控制完成: switchId={}, device={}, 共{}条",
switchId, device.getDeviceName(), listTimingCtrl.size());
return R.ok();
} catch (Exception e) {
log.error("强制同步定时控制失败: {}", e.getMessage(), e);
return R.fail("同步失败: " + e.getMessage());
}
}
/**
* 设置定时控制开关
*
@@ -3043,10 +3114,15 @@ public class IotController extends BaseController {
.eq(TimingCtrl::getSwitchId, dbTimeCtrl.getSwitchId())
);
// 从列表中移除要删除的定时控制(删除场景直接移出列表,回查时 targetIdx < 0 直接返回成功
allTimingCtrls.removeIf(tc -> tc.getId().equals(request.getId()));
// 删除场景:保持槽位数组长度不变,将目标项的 isOpen 置为 0isValid=0
// 不能直接移除,否则设备端槽位会错位,被删项数据残留
allTimingCtrls.forEach(tc -> {
if (tc.getId().equals(request.getId())) {
tc.setIsOpen(0L);
}
});
// 调用设置属性方法,将更新后的定时控制列表同步到设备
// 调用设置属性方法,将完整槽位列表(含已置无效的目标项)同步到设备
boolean success = setPropertyTimeCtrl(deviceSwitch, device, allTimingCtrls, request.getId());
if (!success) {
return R.fail("设置定时控制失败");