diff --git a/src/main/java/com/gameplatform/server/controller/admin/DeviceStatusController.java b/src/main/java/com/gameplatform/server/controller/admin/DeviceStatusController.java new file mode 100644 index 0000000..66af8ce --- /dev/null +++ b/src/main/java/com/gameplatform/server/controller/admin/DeviceStatusController.java @@ -0,0 +1,52 @@ +package com.gameplatform.server.controller.admin; + +import com.gameplatform.server.device.Detection; +import com.gameplatform.server.device.DeviceStats; +import com.gameplatform.server.model.dto.device.DeviceStatusResponse; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/admin/devices") +@Tag(name = "设备状态", description = "获取所有设备的实时状态") +public class DeviceStatusController { + + private static final Logger log = LoggerFactory.getLogger(DeviceStatusController.class); + + private final Detection detection; + private final DeviceStats deviceStats; + + public DeviceStatusController(Detection detection, DeviceStats deviceStats) { + this.detection = detection; + this.deviceStats = deviceStats; + } + + @GetMapping("/status") + @Operation(summary = "获取设备分组状态", description = "返回最近一次分组统计快照(含 categoryToDevices 与计数)。必要时会基于最新快照即时计算一次,不触发脚本刷新。") + public ResponseEntity getAllDeviceStatus() { + DeviceStats.Snapshot stats = deviceStats.getLastComputedSnapshot(); + if (stats == null) { + // 优先使用检测缓存,其次拉取一次(带TTL),并计算分组 + DeviceStatusResponse latest = detection.getLastSnapshot(); + if (latest == null) { + latest = detection.listAllDevices(); + } + if (latest != null) { + stats = deviceStats.updateWithSnapshot(latest); + } + } + if (stats == null) { + log.warn("getAllDeviceStatus: 未获取到分组统计快照,返回204"); + return ResponseEntity.noContent().build(); + } + return ResponseEntity.ok(stats); + } +} + + diff --git a/src/main/java/com/gameplatform/server/device/Detection.java b/src/main/java/com/gameplatform/server/device/Detection.java index 36cbcca..304a52d 100644 --- a/src/main/java/com/gameplatform/server/device/Detection.java +++ b/src/main/java/com/gameplatform/server/device/Detection.java @@ -103,6 +103,13 @@ public class Detection { return resp; } + /** + * 获取最近一次缓存的全量设备快照(不触发刷新,不受TTL约束)。 + */ + public DeviceStatusResponse getLastSnapshot() { + return this.lastSnapshot; + } + /** * 定时任务:全量拉取并交由 DeviceStats 更新内存分类与审计。 * 默认每 30 秒执行一次,可通过配置覆盖:detection.poll.cron 或 detection.poll.fixedDelayMs diff --git a/src/main/java/com/gameplatform/server/device/DeviceStats.java b/src/main/java/com/gameplatform/server/device/DeviceStats.java index 1594276..045a752 100644 --- a/src/main/java/com/gameplatform/server/device/DeviceStats.java +++ b/src/main/java/com/gameplatform/server/device/DeviceStats.java @@ -9,6 +9,7 @@ import com.gameplatform.server.mapper.agent.LinkTaskMapper; import com.gameplatform.server.mapper.history.DeviceStatusTransitionMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.gameplatform.server.service.admin.SystemConfigService; import org.springframework.stereotype.Service; import java.util.*; @@ -67,6 +68,7 @@ public class DeviceStats { private final MemoryMachineCooldownService cooldownService; private final DeviceStatusTransitionMapper transitionMapper; private final DeviceAllocationService deviceAllocationService; + private final SystemConfigService systemConfigService; // 记录上一次统计时每台设备的分类结果,用于检测状态变更 private final Map lastStatusByDevice = new ConcurrentHashMap<>(); @@ -74,11 +76,13 @@ public class DeviceStats { public DeviceStats(LinkTaskMapper linkTaskMapper, MemoryMachineCooldownService cooldownService, DeviceStatusTransitionMapper transitionMapper, - DeviceAllocationService deviceAllocationService) { + DeviceAllocationService deviceAllocationService, + SystemConfigService systemConfigService) { this.linkTaskMapper = linkTaskMapper; this.cooldownService = cooldownService; this.transitionMapper = transitionMapper; this.deviceAllocationService = deviceAllocationService; + this.systemConfigService = systemConfigService; } /** @@ -112,6 +116,7 @@ public class DeviceStats { boolean usingTask = hasUsingTask(deviceId); boolean cooldown = cooldownService.isMachineInCooldown(deviceId); boolean numeric = isNumeric(v); + String configuredIdle = systemConfigService.getDeviceIdleStatus(); // log.debug("设备[{}] 原始脚本值='{}' | LOGGED_IN={} USING={} COOLDOWN={} NUMERIC={}", // deviceId, v, loggedIn, usingTask, cooldown, numeric); @@ -128,6 +133,9 @@ public class DeviceStats { } else if ("已打完".equals(v) || cooldown) { newCategory = Category.IDLE_COOLDOWN; reason = "已打完".equals(v) ? "脚本值=已打完" : "处于冷却服务中"; + } else if (v != null && configuredIdle != null && configuredIdle.equals(v)) { + newCategory = Category.IDLE_FREE; + reason = "脚本值=配置的空闲标识"; } else { newCategory = Category.RUNNING; reason = "默认运行中/未知状态"; diff --git a/src/main/java/com/gameplatform/server/service/admin/SystemConfigService.java b/src/main/java/com/gameplatform/server/service/admin/SystemConfigService.java index ce5bf0c..c81fb80 100644 --- a/src/main/java/com/gameplatform/server/service/admin/SystemConfigService.java +++ b/src/main/java/com/gameplatform/server/service/admin/SystemConfigService.java @@ -110,7 +110,7 @@ public class SystemConfigService { // 获取设备检测相关配置 public String getDeviceIdleStatus() { - return getConfigValue("device.idle_status", "空闲"); + return getConfigValue("device.idle_status", "空的"); } // 获取首次选区后链接过期时间(秒)