ruoyi-admin/src/main/java/com/ruoyi/web/controller/device/DeviceAdapterController.java
@@ -31,6 +31,7 @@ @PreAuthorize("@ss.hasPermi('system:deviceAdapter:list')") @GetMapping("/list") /** 分页查询适配器配置及其最近运行状态。 */ public TableDataInfo list() { startPage(); @@ -39,11 +40,13 @@ @PreAuthorize("@ss.hasPermi('system:deviceAdapter:query')") @GetMapping("/{adapterId}") /** 查询指定适配器详情;适配器必须存在。 */ public AjaxResult getInfo(@PathVariable Long adapterId) { return success(service.selectById(adapterId)); } @PreAuthorize("@ss.hasPermi('system:deviceAdapter:add')") @Log(title = "设备适配器实例", businessType = BusinessType.INSERT) @PostMapping /** 新增默认禁用的只读适配器配置。 */ public AjaxResult add(@Validated @RequestBody TDeviceAdapter adapter) { adapter.setCreateBy(getUsername()); @@ -53,6 +56,7 @@ @PreAuthorize("@ss.hasPermi('system:deviceAdapter:edit')") @Log(title = "设备适配器实例", businessType = BusinessType.UPDATE) @PutMapping /** 修改适配器配置;启用实例会同步替换运行时连接。 */ public AjaxResult edit(@Validated @RequestBody TDeviceAdapter adapter) { adapter.setUpdateBy(getUsername()); @@ -62,6 +66,7 @@ @PreAuthorize("@ss.hasPermi('system:deviceAdapter:changeStatus')") @Log(title = "设备适配器实例启停", businessType = BusinessType.UPDATE) @PutMapping("/{adapterId}/status") /** 启用或停用适配器;启用前配置必须通过只读校验。 */ public AjaxResult changeStatus(@PathVariable Long adapterId, @RequestBody StatusCommand command) { return toAjax(service.changeStatus(adapterId, command.enabled(), getUsername())); @@ -70,10 +75,12 @@ @PreAuthorize("@ss.hasPermi('system:deviceAdapter:discover')") @Log(title = "设备适配器发现", businessType = BusinessType.OTHER) @PostMapping("/{adapterId}/discover") /** 执行一次 getdevinfo 与实时 inquire,并返回本轮发现摘要。 */ public AjaxResult discover(@PathVariable Long adapterId) { return success(service.discover(adapterId)); } @PreAuthorize("@ss.hasPermi('system:deviceAdapter:list')") @GetMapping("/{adapterId}/channels") /** 查询适配器已持久化的通道事实,不因本轮缺失而删除。 */ public AjaxResult channels(@PathVariable Long adapterId) { return success(service.selectChannels(adapterId)); } public record StatusCommand(boolean enabled) { } ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceAdapterServiceImpl.java
@@ -54,9 +54,11 @@ } @Override /** 按管理端筛选条件查询适配器及其运行状态。 */ public List<TDeviceAdapter> selectList(TDeviceAdapter query) { return mapper.selectDeviceAdapterList(query); } @Override /** 查询适配器详情;实例不存在时抛出稳定业务错误。 */ public TDeviceAdapter selectById(Long adapterId) { TDeviceAdapter adapter = mapper.selectDeviceAdapterById(adapterId); @@ -65,6 +67,7 @@ } @Override /** 新增默认禁用的只读适配器配置。 */ public int insert(TDeviceAdapter adapter) { normalizeAndValidate(adapter); @@ -79,6 +82,7 @@ } @Override /** 更新配置;已启用实例会同步运行时注册表。 */ public int update(TDeviceAdapter adapter) { TDeviceAdapter current = selectById(adapter.getAdapterId()); @@ -95,6 +99,7 @@ } @Override /** 启停适配器并同步其运行时实例。 */ public int changeStatus(Long adapterId, boolean enabled, String updateBy) { TDeviceAdapter adapter = selectById(adapterId); @@ -107,6 +112,7 @@ } @Override /** 执行一次发现和实时观测,并事务性写入通道事实。 */ public AdapterDiscoveryResult discover(Long adapterId) { TDeviceAdapter adapter = selectById(adapterId); @@ -140,6 +146,7 @@ } @Override /** 查询指定适配器已发现且未删除的通道。 */ public List<TDetectionChannel> selectChannels(Long adapterId) { selectById(adapterId); @@ -147,12 +154,14 @@ } @Override /** 启动时恢复所有已启用适配器的运行时注册。 */ public void synchronizeEnabledAdapters() { mapper.selectEnabledDeviceAdapters().forEach(adapter -> registry.synchronize(toRuntimeConfig(adapter))); } @Override /** 轮询达到周期的已启用适配器,并持久化失败状态后继续调度。 */ public void pollDueAdapters() { Instant now = Instant.now(); ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceDiscoveryPersistenceService.java
@@ -27,7 +27,7 @@ this.mapper = mapper; } /** 在一个事务内 upsert 本轮观测事实;未返回通道保持原记录不变。 */ /** 在事务内 upsert 本轮发现和实时观测;未返回通道保持原记录不变。 */ @Transactional(rollbackFor = Exception.class) public AdapterDiscoveryResult persist(TDeviceAdapter adapter, List<DetectedChannel> detected, Map<ChannelIdentity, RealtimeSnapshot> snapshots, Instant observedAt)