From d2b53841c31b82df4f71b800ad18a323694c10d7 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期六, 29 八月 2026 23:13:40 +0800
Subject: [PATCH] 修复设备发现状态同步与开始接收边界
---
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceDiscoveryPersistenceService.java | 40 ++++++++++++++++++++++++++++++++++++++--
1 files changed, 38 insertions(+), 2 deletions(-)
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceDiscoveryPersistenceService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceDiscoveryPersistenceService.java
index 08582ef..87a4392 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceDiscoveryPersistenceService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceDiscoveryPersistenceService.java
@@ -17,18 +17,24 @@
import com.ruoyi.device.model.RealtimeSnapshot;
import com.ruoyi.device.registry.DeviceAdapterRegistry;
import com.ruoyi.system.domain.vo.AdapterDiscoveryResult;
+import com.ruoyi.system.mapper.TDetectionCabinetMapper;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-/** 将适配器观测写入 Redis 候选存储,不创建正式 MySQL 设备或通道。 */
+/** 将适配器观测写入 Redis 候选,并同步已登记设备的实时事实。 */
@Service
public class DeviceDiscoveryPersistenceService
{
private static final Duration MINIMUM_CANDIDATE_LIFETIME = Duration.ofSeconds(30);
private final DeviceDiscoveryCandidateStore candidateStore;
+ private final TDetectionCabinetMapper detectionCabinetMapper;
- public DeviceDiscoveryPersistenceService(DeviceDiscoveryCandidateStore candidateStore)
+ @Autowired
+ public DeviceDiscoveryPersistenceService(DeviceDiscoveryCandidateStore candidateStore,
+ TDetectionCabinetMapper detectionCabinetMapper)
{
this.candidateStore = candidateStore;
+ this.detectionCabinetMapper = detectionCabinetMapper;
}
/** 执行设备发现和可用通道查询,并将本轮观测写入 Redis 候选。 */
@@ -63,9 +69,39 @@
observedAt, observedAt.plus(lifetime)))
.toList();
candidateStore.recordCabinets(candidates);
+ synchronizeRegisteredFacts(source, detected, snapshots, observedAt);
return new AdapterDiscoveryResult(grouped.size(), detected.size(), observedAt);
}
+ /**
+ * 发现候选与正式设备是两份事实;正式登记后仍需把成功观测同步到 MySQL,
+ * 否则开始接收无法取得可靠边界。离线轮询只更新当前状态,不覆盖最后成功观测时间。
+ */
+ private void synchronizeRegisteredFacts(DiscoverySource source, List<DetectedChannel> detected,
+ Map<ChannelIdentity, RealtimeSnapshot> snapshots, Instant observedAt)
+ {
+ Map<CabinetKey, Boolean> cabinetOnline = new LinkedHashMap<>();
+ for (DetectedChannel channel : detected)
+ {
+ ChannelIdentity identity = channel.identity();
+ boolean successfulObservation = channel.available() && snapshots.containsKey(identity);
+ RealtimeSnapshot snapshot = snapshots.get(identity);
+ DeviceWorkStatus workStatus = snapshot == null || snapshot.workStatus() == null
+ ? DeviceWorkStatus.UNKNOWN : snapshot.workStatus();
+ detectionCabinetMapper.updateRegisteredChannelObservation(source.adapterCode(), identity.devtype(),
+ identity.devid(), identity.subdevid(), identity.chlid(), channel.available() ? "ONLINE" : "OFFLINE",
+ workStatus.name(), observedAt, successfulObservation);
+ CabinetKey cabinet = new CabinetKey(identity.devtype(), identity.devid());
+ cabinetOnline.merge(cabinet, channel.available(), Boolean::logicalOr);
+ }
+ cabinetOnline.forEach((cabinet, online) -> detectionCabinetMapper.updateRegisteredCabinetObservation(
+ source.adapterCode(), cabinet.devtype(), cabinet.devid(), online ? "ONLINE" : "OFFLINE", observedAt,
+ online && detected.stream().anyMatch(channel -> channel.available()
+ && channel.identity().devtype() == cabinet.devtype()
+ && channel.identity().devid() == cabinet.devid()
+ && snapshots.containsKey(channel.identity()))));
+ }
+
private CabinetCandidate toCandidate(DiscoverySource source, CabinetKey key, List<DetectedChannel> channels,
Map<ChannelIdentity, RealtimeSnapshot> snapshots, Instant observedAt, Instant expiresAt)
{
--
Gitblit v1.7.1