From bc9a169ce3648467136a279d167f72c4fbab9595 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期六, 05 九月 2026 00:53:48 +0800
Subject: [PATCH] 完成设备发现登记与状态事实

---
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TDetectionCabinetServiceImpl.java |   41 ++++++++++++++++++++++++++++++++++++-----
 1 files changed, 36 insertions(+), 5 deletions(-)

diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TDetectionCabinetServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TDetectionCabinetServiceImpl.java
index ee7e3df..680fcaf 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TDetectionCabinetServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TDetectionCabinetServiceImpl.java
@@ -164,11 +164,20 @@
                 value.setSubdevid(channel.identity().subdevid());
                 value.setChlid(channel.identity().chlid());
                 value.setDisplayNo(channel.identity().subdevid() + "-" + channel.identity().chlid());
-                value.setOnlineStatus("UNKNOWN");
-                value.setWorkStatus("UNKNOWN");
+                value.setOnlineStatus(channel.online() ? "ONLINE" : "OFFLINE");
+                value.setWorkStatus(persistedWorkStatus(channel.workStatus(), channel.online()));
                 value.setLastSeenAtUtc(null);
                 detectionCabinetMapper.insertDetectionChannel(value);
             }
+            // 登记瞬间的候选也是一次有效观测,立即写入正式事实,避免等待下一轮轮询才显示在线。
+            detectionCabinetMapper.updateRegisteredCabinetObservation(candidate.adapterCode(), candidate.devtype(),
+                    candidate.devid(), candidate.online() ? "ONLINE" : "OFFLINE", candidate.observedAt(),
+                    candidate.online());
+            candidate.channels().forEach(channel -> detectionCabinetMapper.updateRegisteredChannelObservation(
+                    candidate.adapterCode(), channel.identity().devtype(), channel.identity().devid(),
+                    channel.identity().subdevid(), channel.identity().chlid(), channel.online() ? "ONLINE" : "OFFLINE",
+                    channel.online() ? persistedWorkStatus(channel.workStatus(), true) : "UNOBSERVABLE",
+                    channel.observedAt(), channel.online()));
             return rows;
         }
         catch (DuplicateKeyException exception)
@@ -369,16 +378,24 @@
 
     private Map<String, CabinetCandidate> candidatesByCode()
     {
-        return candidateStore.snapshot(Instant.now()).cabinets().stream()
-                .collect(java.util.stream.Collectors.toMap(CabinetCandidate::deviceCode, item -> item));
+        return candidateStore.snapshot(Instant.now()).cabinets().stream().collect(java.util.stream.Collectors.toMap(
+                item -> stableCandidateKey(item.adapterCode(), item.devtype(), item.devid()), item -> item,
+                (left, right) -> right));
     }
 
     private TDetectionCabinet applyRealtimeState(TDetectionCabinet cabinet,
             Map<String, CabinetCandidate> candidates)
     {
-        CabinetCandidate candidate = candidates.get(cabinet.getCabinetCode());
+        CabinetCandidate candidate = candidates.get(stableCandidateKey(cabinet.getAdapterCode(),
+                cabinet.getVendorDeviceType(), cabinet.getVendorDeviceId()));
+        if (candidate == null) candidate = candidateStore.findCabinet(cabinet.getCabinetCode(), Instant.now()).orElse(null);
         cabinet.setOnlineStatus(candidate != null && candidate.online() ? ONLINE : OFFLINE);
         return cabinet;
+    }
+
+    private String stableCandidateKey(String adapterCode, Integer devtype, Integer devid)
+    {
+        return adapterCode + "-" + devtype + "-" + devid;
     }
 
     private boolean isActive(CabinetCandidate candidate)
@@ -386,6 +403,20 @@
         return candidate.channels().stream().anyMatch(channel -> ACTIVE_WORK_STATUSES.contains(channel.workStatus()));
     }
 
+    /** 将设备观测状态转换为最终数据库允许的通道事实状态。 */
+    private String persistedWorkStatus(DeviceWorkStatus status, boolean online)
+    {
+        if (!online || status == null || status == DeviceWorkStatus.UNKNOWN
+                || status == DeviceWorkStatus.UNOBSERVABLE) return "UNOBSERVABLE";
+        return switch (status)
+        {
+            case PAUSED -> "PAUSED";
+            case PROTECTED -> "ABNORMAL";
+            case FINISHED, STOPPED -> "ENDED";
+            default -> "RUNNING";
+        };
+    }
+
     private ServiceException buildDuplicateException(TDetectionCabinet detectionCabinet, DuplicateKeyException cause)
     {
         String message = checkCabinetCodeUnique(detectionCabinet) ? "MAC地址已存在" : "设备编码已存在";

--
Gitblit v1.7.1