From 68156d14934ffb7d7b6e0dca63d3dcf3ed43c995 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期六, 05 九月 2026 18:01:40 +0800
Subject: [PATCH] 修复离线设备无法发现和登记的问题
---
battery-business/src/main/java/com/battery/business/service/impl/TCollectorServiceImpl.java | 5 +-
battery-business/src/main/java/com/battery/business/service/impl/TDetectionCabinetServiceImpl.java | 12 ++---
ruoyi-admin/src/main/java/com/battery/business/runtime/DevelopmentCollectorDiscoveryService.java | 7 +--
ruoyi-admin/src/test/java/com/battery/business/service/impl/TCollectorServiceImplTest.java | 12 ++++++
ruoyi-admin/src/test/java/com/battery/business/service/impl/CollectorDiscoveryServiceImplTest.java | 7 ++-
ruoyi-admin/src/test/java/com/battery/business/service/impl/TDetectionCabinetServiceImplTest.java | 19 +++++++++
6 files changed, 45 insertions(+), 17 deletions(-)
diff --git a/battery-business/src/main/java/com/battery/business/service/impl/TCollectorServiceImpl.java b/battery-business/src/main/java/com/battery/business/service/impl/TCollectorServiceImpl.java
index c3603a8..95fd84a 100644
--- a/battery-business/src/main/java/com/battery/business/service/impl/TCollectorServiceImpl.java
+++ b/battery-business/src/main/java/com/battery/business/service/impl/TCollectorServiceImpl.java
@@ -98,8 +98,7 @@
if (collector == null) throw new ServiceException("采集器信息不能为空");
collector.setCollectorCode(trimToNull(collector.getCollectorCode()));
CollectorCandidate candidate = candidateStore.findCollector(collector.getCollectorCode(), Instant.now())
- .filter(CollectorCandidate::online)
- .orElseThrow(() -> new ServiceException("请先选择在线的发现候选设备"));
+ .orElseThrow(() -> new ServiceException("请先选择有效的发现候选设备"));
collector.setIpAddress(candidate.ip());
collector.setMacAddress(candidate.mac());
collector.setChannelCount(candidate.channelCount());
@@ -120,7 +119,7 @@
collector.setDelFlag("0");
collector.setCreateTime(new Date());
int rows = collectorMapper.insertCollector(collector);
- // 登记瞬间同步候选事实,避免正式记录暂时显示为离线且没有最近观测时间。
+ // 登记只确认来源身份,在线与离线事实都按候选原样同步。
collectorMapper.updateRegisteredObservation(collector.getCollectorCode(),
candidate.online() ? "ONLINE" : "OFFLINE");
return rows;
diff --git a/battery-business/src/main/java/com/battery/business/service/impl/TDetectionCabinetServiceImpl.java b/battery-business/src/main/java/com/battery/business/service/impl/TDetectionCabinetServiceImpl.java
index fb49958..7e8ce2b 100644
--- a/battery-business/src/main/java/com/battery/business/service/impl/TDetectionCabinetServiceImpl.java
+++ b/battery-business/src/main/java/com/battery/business/service/impl/TDetectionCabinetServiceImpl.java
@@ -101,7 +101,7 @@
}
/**
- * 读取 Redis 在线候选供原选择设备弹窗展示,不生成模拟设备。
+ * 读取未过期且未登记的候选,离线设备仍保留身份并可选择。
* 测试占用状态由实时通道工作状态聚合;测试归属留待后续绑定闭环确认。
*
* @return 可供选择的检测柜设备摘要
@@ -111,13 +111,12 @@
{
Set<String> registeredCodes = Set.copyOf(detectionCabinetMapper.selectRegisteredCabinetCodes());
return candidateStore.snapshot(Instant.now()).cabinets().stream()
- .filter(CabinetCandidate::online)
.filter(candidate -> !registeredCodes.contains(candidate.deviceCode()))
.map(candidate -> {
- boolean active = isActive(candidate);
+ boolean active = candidate.online() && isActive(candidate);
return new DiscoveredCabinetVo(
candidate.deviceCode(), candidate.ip(), candidate.mac(), candidate.name(),
- candidate.manufacturer(), candidate.model(), candidate.channels().size(), "在线",
+ candidate.manufacturer(), candidate.model(), candidate.channels().size(), candidate.online() ? "在线" : "离线",
active ? "测试中" : "空闲",
active ? "待确认" : "-");
})
@@ -136,8 +135,7 @@
{
normalizeBasicFields(detectionCabinet);
CabinetCandidate candidate = candidateStore.findCabinet(detectionCabinet.getCabinetCode(), Instant.now())
- .filter(CabinetCandidate::online)
- .orElseThrow(() -> new ServiceException("请先选择在线的发现候选设备"));
+ .orElseThrow(() -> new ServiceException("请先选择有效的发现候选设备"));
detectionCabinet.setAdapterId(candidate.adapterId());
detectionCabinet.setAdapterCode(candidate.adapterCode());
detectionCabinet.setVendorDeviceType(candidate.devtype());
@@ -169,7 +167,7 @@
value.setLastSeenAtUtc(null);
detectionCabinetMapper.insertDetectionChannel(value);
}
- // 登记瞬间的候选也是一次有效观测,立即写入正式事实,避免等待下一轮轮询才显示在线。
+ // 登记只确认来源身份,在线与离线事实都按候选原样同步。
detectionCabinetMapper.updateRegisteredCabinetObservation(candidate.adapterCode(), candidate.devtype(),
candidate.devid(), candidate.online() ? "ONLINE" : "OFFLINE", candidate.observedAt(),
candidate.online());
diff --git a/ruoyi-admin/src/main/java/com/battery/business/runtime/DevelopmentCollectorDiscoveryService.java b/ruoyi-admin/src/main/java/com/battery/business/runtime/DevelopmentCollectorDiscoveryService.java
index e73a87d..6741cf1 100644
--- a/ruoyi-admin/src/main/java/com/battery/business/runtime/DevelopmentCollectorDiscoveryService.java
+++ b/ruoyi-admin/src/main/java/com/battery/business/runtime/DevelopmentCollectorDiscoveryService.java
@@ -23,17 +23,16 @@
this.collectorService = collectorService;
}
- /** 返回在线且未登记的独立采集器快照,不混入 BTS 检测柜设备。 */
+ /** 返回未过期且未登记的采集器,离线事实不影响发现展示或登记资格。 */
@Override
public List<DiscoveredCollectorVo> selectDiscoveredCollectorList()
{
Set<String> registeredCodes = collectorService.selectRegisteredCollectorCodes();
return candidateStore.snapshot(Instant.now()).collectors().stream()
- .filter(collector -> collector.online()
- && !registeredCodes.contains(collector.deviceCode()))
+ .filter(collector -> !registeredCodes.contains(collector.deviceCode()))
.map(collector -> new DiscoveredCollectorVo(collector.deviceCode(), collector.ip(), collector.mac(),
collector.name(), collector.manufacturer(), collector.model(), collector.channelCount(),
- "在线", "空闲", "-"))
+ collector.online() ? "在线" : "离线", "空闲", "-"))
.toList();
}
}
diff --git a/ruoyi-admin/src/test/java/com/battery/business/service/impl/CollectorDiscoveryServiceImplTest.java b/ruoyi-admin/src/test/java/com/battery/business/service/impl/CollectorDiscoveryServiceImplTest.java
index 273485c..c42ac66 100644
--- a/ruoyi-admin/src/test/java/com/battery/business/service/impl/CollectorDiscoveryServiceImplTest.java
+++ b/ruoyi-admin/src/test/java/com/battery/business/service/impl/CollectorDiscoveryServiceImplTest.java
@@ -50,7 +50,7 @@
}
@Test
- public void shouldHideOfflineCollectors() throws Exception
+ public void shouldReturnOfflineUnregisteredCollectors() throws Exception
{
try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0))
{
@@ -65,7 +65,9 @@
List<DiscoveredCollectorVo> result = service.selectDiscoveredCollectorList();
- assertEquals(0, result.size());
+ assertEquals(1, result.size());
+ assertEquals("dev-sim-collector-1", result.get(0).getDeviceCode());
+ assertEquals("离线", result.get(0).getOnlineStatus());
}
}
@@ -79,6 +81,7 @@
DevelopmentCollectorDiscoveryService service =
new DevelopmentCollectorDiscoveryService(store, collectorService);
TCollectorMapper collectorMapper = mock(TCollectorMapper.class);
+ simulator.updateCollector(1, "127.0.1.2", 4, false);
new DevelopmentCollectorStatusSynchronizer(simulator, store, collectorMapper).synchronizeOnlineStatus();
when(collectorService.selectRegisteredCollectorCodes())
.thenReturn(Set.of("dev-sim-collector-1"))
diff --git a/ruoyi-admin/src/test/java/com/battery/business/service/impl/TCollectorServiceImplTest.java b/ruoyi-admin/src/test/java/com/battery/business/service/impl/TCollectorServiceImplTest.java
index d87722e..3aef6e8 100644
--- a/ruoyi-admin/src/test/java/com/battery/business/service/impl/TCollectorServiceImplTest.java
+++ b/ruoyi-admin/src/test/java/com/battery/business/service/impl/TCollectorServiceImplTest.java
@@ -166,6 +166,18 @@
}
@Test
+ void offlineCollectorCanBeRegisteredWithoutChangingOnlineFact()
+ {
+ java.time.Instant now = java.time.Instant.now();
+ candidateStore.replaceCollectors("dev-sim", java.util.List.of(new CollectorCandidate(
+ "dev-sim", "COL-001", "192.168.1.10", "AA:BB:CC:DD:EE:FF", "一号采集器",
+ "开发模拟器", "Virtual Collector", 8, false, now, now.plusSeconds(60))));
+ when(collectorMapper.insertCollector(any(TCollector.class))).thenReturn(1);
+ assertEquals(1, collectorService.insertCollector(collector));
+ verify(collectorMapper).updateRegisteredObservation("COL-001", "OFFLINE");
+ }
+
+ @Test
void insertCollectorShouldRejectDuplicateCode()
{
collector.setCollectorId(null);
diff --git a/ruoyi-admin/src/test/java/com/battery/business/service/impl/TDetectionCabinetServiceImplTest.java b/ruoyi-admin/src/test/java/com/battery/business/service/impl/TDetectionCabinetServiceImplTest.java
index 26d0218..6a464b1 100644
--- a/ruoyi-admin/src/test/java/com/battery/business/service/impl/TDetectionCabinetServiceImplTest.java
+++ b/ruoyi-admin/src/test/java/com/battery/business/service/impl/TDetectionCabinetServiceImplTest.java
@@ -228,6 +228,23 @@
assertEquals(8, devices.get(0).getChannelCount());
}
+ @Test
+ void offlineCabinetRemainsDiscoverableAndCanBeRegistered()
+ {
+ var store = new InMemoryDeviceDiscoveryCandidateStore();
+ store.recordCabinets(List.of(candidate("CABINET-001", false, DeviceWorkStatus.UNOBSERVABLE)));
+ var service = new TDetectionCabinetServiceImpl(detectionCabinetMapper, store);
+ when(detectionCabinetMapper.selectRegisteredCabinetCodes()).thenReturn(List.of());
+ var devices = service.selectDiscoveredCabinetList();
+ assertEquals(1, devices.size());
+ assertEquals("离线", devices.get(0).getOnlineStatus());
+ when(detectionCabinetMapper.insertDetectionCabinet(any(TDetectionCabinet.class))).thenReturn(1);
+ assertEquals(1, service.insertDetectionCabinet(detectionCabinet));
+ assertEquals("OFFLINE", detectionCabinet.getOnlineStatus());
+ when(detectionCabinetMapper.selectRegisteredCabinetCodes()).thenReturn(List.of("CABINET-001"));
+ assertEquals(0, service.selectDiscoveredCabinetList().size());
+ }
+
/**
* 验证重复设备编码会阻止新增且不会执行写库操作。
*/
@@ -255,7 +272,7 @@
ServiceException exception = assertThrows(ServiceException.class,
() -> detectionCabinetService.insertDetectionCabinet(detectionCabinet));
- assertEquals("请先选择在线的发现候选设备", exception.getMessage());
+ assertEquals("请先选择有效的发现候选设备", exception.getMessage());
verify(detectionCabinetMapper, never()).insertDetectionCabinet(any());
}
--
Gitblit v1.7.1