fix: 绑定功能优化完善,新增清零功能接口。
This commit is contained in:
@@ -107,6 +107,14 @@
|
|||||||
<artifactId>intc-system</artifactId>
|
<artifactId>intc-system</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- TDengine 模块(用于清理设备时序数据) -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.intc</groupId>
|
||||||
|
<artifactId>intc-tdengine</artifactId>
|
||||||
|
<version>5.5.0</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -30,18 +30,25 @@ import com.intc.fishery.domain.vo.PublicDeviceLinkedCtrl;
|
|||||||
import com.intc.fishery.domain.vo.PublicDeviceDeadInfo;
|
import com.intc.fishery.domain.vo.PublicDeviceDeadInfo;
|
||||||
import com.intc.fishery.domain.vo.PublicDeviceTypeAndSerialNum;
|
import com.intc.fishery.domain.vo.PublicDeviceTypeAndSerialNum;
|
||||||
import com.intc.fishery.domain.Device;
|
import com.intc.fishery.domain.Device;
|
||||||
|
import com.intc.fishery.domain.DeviceBindRecord;
|
||||||
import com.intc.fishery.domain.DeviceSwitch;
|
import com.intc.fishery.domain.DeviceSwitch;
|
||||||
|
import com.intc.fishery.domain.DeviceErrorCode;
|
||||||
import com.intc.fishery.domain.Pond;
|
import com.intc.fishery.domain.Pond;
|
||||||
import com.intc.fishery.domain.LinkedCtrl;
|
import com.intc.fishery.domain.LinkedCtrl;
|
||||||
import com.intc.fishery.domain.DeviceCorrectRecord;
|
import com.intc.fishery.domain.DeviceCorrectRecord;
|
||||||
import com.intc.fishery.mapper.DeviceMapper;
|
import com.intc.fishery.mapper.DeviceMapper;
|
||||||
import com.intc.fishery.mapper.DeviceSwitchMapper;
|
import com.intc.fishery.mapper.DeviceSwitchMapper;
|
||||||
|
import com.intc.fishery.mapper.DeviceBindRecordMapper;
|
||||||
|
import com.intc.fishery.mapper.DeviceErrorCodeMapper;
|
||||||
import com.intc.fishery.mapper.PondMapper;
|
import com.intc.fishery.mapper.PondMapper;
|
||||||
import com.intc.fishery.mapper.LinkedCtrlMapper;
|
import com.intc.fishery.mapper.LinkedCtrlMapper;
|
||||||
import com.intc.fishery.mapper.DeviceCorrectRecordMapper;
|
import com.intc.fishery.mapper.DeviceCorrectRecordMapper;
|
||||||
import com.intc.fishery.constant.DefineDeviceWarnCode;
|
import com.intc.fishery.constant.DefineDeviceWarnCode;
|
||||||
import com.intc.fishery.utils.MessageOpRecordUtil;
|
import com.intc.fishery.utils.MessageOpRecordUtil;
|
||||||
import com.intc.common.core.config.properties.DeviceTypeProperties;
|
import com.intc.common.core.config.properties.DeviceTypeProperties;
|
||||||
|
import com.intc.common.redis.utils.RedisUtils;
|
||||||
|
import com.intc.tdengine.service.IDeviceSensorDataService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@@ -69,8 +76,13 @@ public class DeviceController extends BaseController {
|
|||||||
private final PondMapper pondMapper;
|
private final PondMapper pondMapper;
|
||||||
private final LinkedCtrlMapper linkedCtrlMapper;
|
private final LinkedCtrlMapper linkedCtrlMapper;
|
||||||
private final DeviceCorrectRecordMapper deviceCorrectRecordMapper;
|
private final DeviceCorrectRecordMapper deviceCorrectRecordMapper;
|
||||||
|
private final DeviceBindRecordMapper deviceBindRecordMapper;
|
||||||
|
private final DeviceErrorCodeMapper deviceErrorCodeMapper;
|
||||||
private final DeviceTypeProperties deviceTypeProperties;
|
private final DeviceTypeProperties deviceTypeProperties;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private IDeviceSensorDataService deviceSensorDataService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询设备管理列表
|
* 查询设备管理列表
|
||||||
*/
|
*/
|
||||||
@@ -148,6 +160,106 @@ public class DeviceController extends BaseController {
|
|||||||
return toAjax(deviceService.deleteWithValidByIds(List.of(ids), true));
|
return toAjax(deviceService.deleteWithValidByIds(List.of(ids), true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清零设备测试数据(出厂测试用)
|
||||||
|
* <p>清理范围:
|
||||||
|
* <ul>
|
||||||
|
* <li>有效期(deadTime)、告警状态(warnCode)、实时传感器值、最后上数时间</li>
|
||||||
|
* <li>TDengine时序数据(删除设备子表,清除所有历史传感器数据)</li>
|
||||||
|
* <li>设备绑定/解绑记录</li>
|
||||||
|
* <li>设备校准记录</li>
|
||||||
|
* <li>设备故障码记录</li>
|
||||||
|
* <li>Redis告警标记</li>
|
||||||
|
* </ul>
|
||||||
|
* 清零后,设备重新绑定时会自动重新计算365天有效期。</p>
|
||||||
|
*
|
||||||
|
* @param id 设备ID
|
||||||
|
* @return 操作结果
|
||||||
|
*/
|
||||||
|
@SaCheckPermission("fishery:device:edit")
|
||||||
|
@Log(title = "设备管理", businessType = BusinessType.UPDATE)
|
||||||
|
@RepeatSubmit()
|
||||||
|
@PutMapping("/resetTestData/{id}")
|
||||||
|
public R<Void> resetTestData(@NotNull(message = "主键不能为空")
|
||||||
|
@PathVariable Long id) {
|
||||||
|
Device device = deviceMapper.selectById(id);
|
||||||
|
if (device == null) {
|
||||||
|
return R.fail("设备不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
String serialNum = device.getSerialNum();
|
||||||
|
|
||||||
|
// 1. 清零设备表:有效期、告警状态、实时传感器值、最后上数时间
|
||||||
|
deviceMapper.update(null,
|
||||||
|
new LambdaUpdateWrapper<Device>()
|
||||||
|
.eq(Device::getId, id)
|
||||||
|
.set(Device::getDeadTime, null)
|
||||||
|
.set(Device::getWarnCode, DefineDeviceWarnCode.None)
|
||||||
|
.set(Device::getLastReportTime, null)
|
||||||
|
.set(Device::getValueDissolvedOxygen, null)
|
||||||
|
.set(Device::getValueTemperature, null)
|
||||||
|
.set(Device::getValueSaturability, null)
|
||||||
|
.set(Device::getValuePh, null)
|
||||||
|
.set(Device::getValueSalinity, null)
|
||||||
|
.set(Device::getValueBattery, null)
|
||||||
|
.set(Device::getIsOxygenWarnExist, 0)
|
||||||
|
.set(Device::getIsTempWarnExist, 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 2. 删除TDengine时序数据(设备子表,含所有历史传感器数据)
|
||||||
|
if (deviceSensorDataService != null && serialNum != null && !serialNum.isBlank()) {
|
||||||
|
try {
|
||||||
|
deviceSensorDataService.dropSubTable(serialNum);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// TDengine清理失败不阻断主流程
|
||||||
|
org.slf4j.LoggerFactory.getLogger(DeviceController.class)
|
||||||
|
.warn("清理TDengine数据失败: deviceId={}, serialNum={}, error={}", id, serialNum, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 删除设备绑定/解绑记录
|
||||||
|
deviceBindRecordMapper.delete(
|
||||||
|
new LambdaQueryWrapper<DeviceBindRecord>()
|
||||||
|
.eq(DeviceBindRecord::getSerialNum, serialNum)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 4. 删除设备校准记录
|
||||||
|
deviceCorrectRecordMapper.delete(
|
||||||
|
new LambdaQueryWrapper<DeviceCorrectRecord>()
|
||||||
|
.eq(DeviceCorrectRecord::getDeviceId, id)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 5. 删除设备故障码记录
|
||||||
|
deviceErrorCodeMapper.delete(
|
||||||
|
new LambdaQueryWrapper<DeviceErrorCode>()
|
||||||
|
.eq(DeviceErrorCode::getDeviceId, id)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 6. 清除Redis告警标记
|
||||||
|
if (serialNum != null && !serialNum.isBlank()) {
|
||||||
|
try {
|
||||||
|
RedisUtils.deleteObject("device:offline:wait:" + serialNum);
|
||||||
|
RedisUtils.deleteObject("device:detector:oxy:offline:wait:" + serialNum);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Redis清理失败不影响主流程
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. 记录操作日志
|
||||||
|
if (device.getUserId() != null) {
|
||||||
|
MessageOpRecordUtil.addMessageOpRecordUser(
|
||||||
|
device.getUserId(),
|
||||||
|
"设备管理",
|
||||||
|
String.format("%s(%s),清零设备测试数据。", device.getDeviceName(), serialNum)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
org.slf4j.LoggerFactory.getLogger(DeviceController.class)
|
||||||
|
.info("清零设备测试数据(设备未绑定用户): deviceId={}, serialNum={}", id, serialNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询用户所有设备简化列表
|
* 查询用户所有设备简化列表
|
||||||
* type=1: 返回完整信息(包含塘口信息和开关列表)
|
* type=1: 返回完整信息(包含塘口信息和开关列表)
|
||||||
|
|||||||
@@ -402,6 +402,9 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
try {
|
try {
|
||||||
AquUser user = aquUserMapper.selectById(device.getUserId());
|
AquUser user = aquUserMapper.selectById(device.getUserId());
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
|
// 管理员(出厂测试人员)解绑时清空有效期,普通用户解绑时保留有效期(防止解绑续命)
|
||||||
|
boolean isManager = user.getIsManager() != null && user.getIsManager() == 1L;
|
||||||
|
|
||||||
Device newDevice = new Device();
|
Device newDevice = new Device();
|
||||||
newDevice.setUserId(null);
|
newDevice.setUserId(null);
|
||||||
newDevice.setIsOxygenUsed(device.getIsOxygenUsed());
|
newDevice.setIsOxygenUsed(device.getIsOxygenUsed());
|
||||||
@@ -411,7 +414,8 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
newDevice.setDeviceType(device.getDeviceType());
|
newDevice.setDeviceType(device.getDeviceType());
|
||||||
newDevice.setIccId(device.getIccId());
|
newDevice.setIccId(device.getIccId());
|
||||||
newDevice.setBindTime(device.getBindTime());
|
newDevice.setBindTime(device.getBindTime());
|
||||||
newDevice.setDeadTime(device.getDeadTime());
|
// 管理员解绑时清空有效期(出厂测试),普通用户解绑时保留有效期
|
||||||
|
newDevice.setDeadTime(isManager ? null : device.getDeadTime());
|
||||||
newDevice.setPondId(null);
|
newDevice.setPondId(null);
|
||||||
newDevice.setSalinityCompensation(0.0);
|
newDevice.setSalinityCompensation(0.0);
|
||||||
newDevice.setOxyWarnLower(device.getOxyWarnLower());
|
newDevice.setOxyWarnLower(device.getOxyWarnLower());
|
||||||
@@ -423,8 +427,8 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
newDevice.setWarnCode(DefineDeviceWarnCode.None);
|
newDevice.setWarnCode(DefineDeviceWarnCode.None);
|
||||||
newDevice.setCategory(device.getCategory());
|
newDevice.setCategory(device.getCategory());
|
||||||
baseMapper.insert(newDevice);
|
baseMapper.insert(newDevice);
|
||||||
log.info("已为用户重建无绑定设备: oldDeviceId={}, newDeviceId={}, serialNum={}",
|
log.info("已为用户重建无绑定设备: oldDeviceId={}, newDeviceId={}, serialNum={}, isManager={}, deadTime={}",
|
||||||
deviceId, newDevice.getId(), device.getSerialNum());
|
deviceId, newDevice.getId(), device.getSerialNum(), isManager, newDevice.getDeadTime());
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("重建无绑定设备失败: deviceId={}, error={}", deviceId, e.getMessage(), e);
|
log.error("重建无绑定设备失败: deviceId={}, error={}", deviceId, e.getMessage(), e);
|
||||||
|
|||||||
@@ -1151,11 +1151,12 @@ public class IotController extends BaseController {
|
|||||||
device.setIotId(iotId);
|
device.setIotId(iotId);
|
||||||
device.setSerialNum(bo.getSerialNum());
|
device.setSerialNum(bo.getSerialNum());
|
||||||
device.setDeviceType(2); // 2-测控一体机
|
device.setDeviceType(2); // 2-测控一体机
|
||||||
device.setDeadTime(new Date(now.getTime() + 365L * 24 * 60 * 60 * 1000)); // 一年后到期
|
device.setDeadTime(new Date(now.getTime() + 365L * 24 * 60 * 60 * 1000));
|
||||||
} else {
|
} else {
|
||||||
// 检查是否已过期
|
// 管理员解绑会清空有效期(null),普通用户解绑会保留有效期。仅null时才设置365天
|
||||||
if (device.getDeadTime() != null && now.after(device.getDeadTime())) {
|
if (device.getDeadTime() == null) {
|
||||||
warnCode |= DefineDeviceWarnCode.DeviceTimeDead;
|
log.info("测控一体机重新绑定,有效期已被管理员解绑清空,重新设置: serialNum={}", bo.getSerialNum());
|
||||||
|
device.setDeadTime(new Date(now.getTime() + 365L * 24 * 60 * 60 * 1000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1575,12 +1576,13 @@ public class IotController extends BaseController {
|
|||||||
device.setIotId(iotId);
|
device.setIotId(iotId);
|
||||||
device.setSerialNum(bo.getSerialNum());
|
device.setSerialNum(bo.getSerialNum());
|
||||||
device.setDeviceType(1); // 1-水质检测仪
|
device.setDeviceType(1); // 1-水质检测仪
|
||||||
device.setDeadTime(new Date(now.getTime() + 365L * 24 * 60 * 60 * 1000)); // 一年后到期
|
|
||||||
device.setIsOxygenUsed(1);
|
device.setIsOxygenUsed(1);
|
||||||
|
device.setDeadTime(new Date(now.getTime() + 365L * 24 * 60 * 60 * 1000));
|
||||||
} else {
|
} else {
|
||||||
// 检查是否已过期
|
// 管理员解绑会清空有效期(null),普通用户解绑会保留有效期。仅null时才设置365天
|
||||||
if (device.getDeadTime() != null && now.after(device.getDeadTime())) {
|
if (device.getDeadTime() == null) {
|
||||||
warnCode |= DefineDeviceWarnCode.DeviceTimeDead;
|
log.info("水质检测仪重新绑定,有效期已被管理员解绑清空,重新设置: serialNum={}", bo.getSerialNum());
|
||||||
|
device.setDeadTime(new Date(now.getTime() + 365L * 24 * 60 * 60 * 1000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1832,7 +1834,13 @@ public class IotController extends BaseController {
|
|||||||
device.setIotId(iotId);
|
device.setIotId(iotId);
|
||||||
device.setSerialNum(bo.getSerialNum());
|
device.setSerialNum(bo.getSerialNum());
|
||||||
device.setDeviceType(3); // 3-太阳能网控
|
device.setDeviceType(3); // 3-太阳能网控
|
||||||
device.setDeadTime(new Date(now.getTime() + 365L * 24 * 60 * 60 * 1000)); // 一年后到期
|
device.setDeadTime(new Date(now.getTime() + 365L * 24 * 60 * 60 * 1000));
|
||||||
|
} else {
|
||||||
|
// 管理员解绑会清空有效期(null),普通用户解绑会保留有效期。仅null时才设置365天
|
||||||
|
if (device.getDeadTime() == null) {
|
||||||
|
log.info("太阳能网控重新绑定,有效期已被管理员解绑清空,重新设置: serialNum={}", bo.getSerialNum());
|
||||||
|
device.setDeadTime(new Date(now.getTime() + 365L * 24 * 60 * 60 * 1000));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置基本信息
|
// 设置基本信息
|
||||||
|
|||||||
@@ -87,4 +87,13 @@ public interface DeviceSensorDataMapper {
|
|||||||
@InterceptorIgnore(tenantLine = "true")
|
@InterceptorIgnore(tenantLine = "true")
|
||||||
DeviceSensorData getLatestReportTime(@Param("serialNum") String serialNum);
|
DeviceSensorData getLatestReportTime(@Param("serialNum") String serialNum);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除设备子表(清除该设备的所有时序数据)
|
||||||
|
*
|
||||||
|
* @param serialNum 设备序列号
|
||||||
|
*/
|
||||||
|
@DS("taos")
|
||||||
|
@InterceptorIgnore(tenantLine = "true")
|
||||||
|
void dropSubTable(@Param("serialNum") String serialNum);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,4 +46,11 @@ public interface IDeviceSensorDataService {
|
|||||||
* @return 最新上数时间字符串,格式 yyyy-MM-dd HH:mm:ss;无数据时返回 null
|
* @return 最新上数时间字符串,格式 yyyy-MM-dd HH:mm:ss;无数据时返回 null
|
||||||
*/
|
*/
|
||||||
String getLatestReportTime(String serialNum);
|
String getLatestReportTime(String serialNum);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除设备子表(清除该设备的所有时序数据)
|
||||||
|
*
|
||||||
|
* @param serialNum 设备序列号
|
||||||
|
*/
|
||||||
|
void dropSubTable(String serialNum);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -296,4 +296,27 @@ public class DeviceSensorDataService implements IDeviceSensorDataService {
|
|||||||
default: return "未知";
|
default: return "未知";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除设备子表(清除该设备的所有时序数据)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void dropSubTable(String serialNum) {
|
||||||
|
if (serialNum == null || serialNum.isBlank()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
deviceSensorDataMapper.dropSubTable(serialNum);
|
||||||
|
// 清除建表缓存,下次插入数据时会重新建表
|
||||||
|
CREATED_TABLES.remove(serialNum);
|
||||||
|
log.info("已删除设备TDengine子表: serialNum={}", serialNum);
|
||||||
|
} catch (Exception e) {
|
||||||
|
String errorMsg = e.getMessage();
|
||||||
|
if (errorMsg != null && errorMsg.toLowerCase().contains("not exist")) {
|
||||||
|
log.debug("设备TDengine子表不存在,无需删除: serialNum={}", serialNum);
|
||||||
|
} else {
|
||||||
|
log.warn("删除设备TDengine子表失败: serialNum={}, error={}", serialNum, errorMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,4 +120,8 @@
|
|||||||
ORDER BY `time` DESC
|
ORDER BY `time` DESC
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<update id="dropSubTable">
|
||||||
|
DROP TABLE IF EXISTS `fishery`.`t_${serialNum}`
|
||||||
|
</update>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
Reference in New Issue
Block a user