| | |
| | | import com.zy.core.thread.StationThread; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | |
| | | private LlmCallLogService llmCallLogService; |
| | | @Autowired |
| | | private AiChatSessionMapper aiChatSessionMapper; |
| | | @Autowired |
| | | private DevicePingFileStorageService devicePingFileStorageService; |
| | | |
| | | @Value("${devicePingStorage.intervalMs:1000}") |
| | | private int devicePingIntervalMs; |
| | | @Value("${devicePingStorage.timeoutMs:800}") |
| | | private int devicePingTimeoutMs; |
| | | @Value("${devicePingStorage.probeCount:3}") |
| | | private int devicePingProbeCount; |
| | | @Value("${devicePingStorage.packetSize:-1}") |
| | | private int devicePingPacketSize; |
| | | |
| | | @GetMapping("/summary/auth") |
| | | @ManagerAuth(memo = "系统仪表盘统计") |
| | | public R summary() { |
| | | Map<String, Object> tasks = buildTaskStats(); |
| | | Map<String, Object> devices = buildDeviceStats(); |
| | | Map<String, Object> network = buildNetworkStats(); |
| | | Map<String, Object> ai = buildAiStats(); |
| | | |
| | | Map<String, Object> overview = new LinkedHashMap<>(); |
| | |
| | | result.put("overview", overview); |
| | | result.put("tasks", tasks); |
| | | result.put("devices", devices); |
| | | result.put("network", network); |
| | | result.put("ai", ai); |
| | | return R.ok(result); |
| | | } |
| | |
| | | return result; |
| | | } |
| | | |
| | | @SuppressWarnings("unchecked") |
| | | private Map<String, Object> buildNetworkStats() { |
| | | Map<String, Object> result = new LinkedHashMap<>(); |
| | | Map<String, Object> overview = new LinkedHashMap<>(); |
| | | overview.put("totalDevices", 0L); |
| | | overview.put("okDevices", 0L); |
| | | overview.put("unstableDevices", 0L); |
| | | overview.put("offlineDevices", 0L); |
| | | overview.put("noDataDevices", 0L); |
| | | overview.put("attentionDevices", 0L); |
| | | overview.put("avgLatencyMs", null); |
| | | overview.put("maxLatencyMs", null); |
| | | |
| | | Map<String, Object> samplingConfig = new LinkedHashMap<>(); |
| | | samplingConfig.put("intervalMs", devicePingIntervalMs); |
| | | samplingConfig.put("timeoutMs", devicePingTimeoutMs); |
| | | samplingConfig.put("probeCount", devicePingProbeCount); |
| | | samplingConfig.put("packetSize", Math.max(devicePingPacketSize, -1)); |
| | | |
| | | List<Map<String, Object>> statusStats = new ArrayList<>(); |
| | | statusStats.add(metric("正常", 0L)); |
| | | statusStats.add(metric("波动", 0L)); |
| | | statusStats.add(metric("超时/异常", 0L)); |
| | | statusStats.add(metric("暂无数据", 0L)); |
| | | |
| | | List<Map<String, Object>> focusDevices = new ArrayList<>(); |
| | | |
| | | try { |
| | | Map<String, Object> overviewResult = devicePingFileStorageService.queryOverview(listPingConfigs()); |
| | | Map<String, Object> summary = overviewResult.get("summary") instanceof Map |
| | | ? (Map<String, Object>) overviewResult.get("summary") |
| | | : Collections.emptyMap(); |
| | | List<Map<String, Object>> devices = overviewResult.get("devices") instanceof List |
| | | ? (List<Map<String, Object>>) overviewResult.get("devices") |
| | | : Collections.emptyList(); |
| | | |
| | | long okDevices = toLong(summary.get("okDevices")); |
| | | long unstableDevices = toLong(summary.get("unstableDevices")); |
| | | long offlineDevices = toLong(summary.get("offlineDevices")); |
| | | long noDataDevices = toLong(summary.get("noDataDevices")); |
| | | |
| | | overview.put("totalDevices", toLong(summary.get("totalDevices"))); |
| | | overview.put("okDevices", okDevices); |
| | | overview.put("unstableDevices", unstableDevices); |
| | | overview.put("offlineDevices", offlineDevices); |
| | | overview.put("noDataDevices", noDataDevices); |
| | | overview.put("attentionDevices", unstableDevices + offlineDevices + noDataDevices); |
| | | overview.put("avgLatencyMs", summary.get("avgLatencyMs")); |
| | | overview.put("maxLatencyMs", summary.get("maxLatencyMs")); |
| | | |
| | | statusStats = new ArrayList<>(); |
| | | statusStats.add(metric("正常", okDevices)); |
| | | statusStats.add(metric("波动", unstableDevices)); |
| | | statusStats.add(metric("超时/异常", offlineDevices)); |
| | | statusStats.add(metric("暂无数据", noDataDevices)); |
| | | |
| | | focusDevices = buildNetworkFocusDevices(devices); |
| | | } catch (Exception e) { |
| | | log.warn("dashboard network stats load failed: {}", safeMessage(e)); |
| | | } |
| | | |
| | | result.put("overview", overview); |
| | | result.put("samplingConfig", samplingConfig); |
| | | result.put("statusStats", statusStats); |
| | | result.put("focusDevices", focusDevices); |
| | | return result; |
| | | } |
| | | |
| | | private List<DeviceConfig> listDeviceConfig(SlaveType type) { |
| | | try { |
| | | return deviceConfigService.list(new QueryWrapper<DeviceConfig>() |
| | |
| | | } |
| | | } |
| | | |
| | | private List<DeviceConfig> listPingConfigs() { |
| | | try { |
| | | return deviceConfigService.list(new QueryWrapper<DeviceConfig>() |
| | | .isNotNull("ip") |
| | | .ne("ip", "") |
| | | .orderBy(true, true, "device_type", "device_no")); |
| | | } catch (Exception e) { |
| | | log.warn("dashboard ping device config load failed: {}", safeMessage(e)); |
| | | return Collections.emptyList(); |
| | | } |
| | | } |
| | | |
| | | private List<Map<String, Object>> buildNetworkFocusDevices(List<Map<String, Object>> devices) { |
| | | if (devices == null || devices.isEmpty()) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | List<Map<String, Object>> candidates = new ArrayList<>(); |
| | | for (Map<String, Object> row : devices) { |
| | | if (resolveNetworkFocusRank(row) < 3) { |
| | | candidates.add(row); |
| | | } |
| | | } |
| | | if (candidates.isEmpty()) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | candidates.sort((left, right) -> { |
| | | int rankDiff = Integer.compare(resolveNetworkFocusRank(left), resolveNetworkFocusRank(right)); |
| | | if (rankDiff != 0) { |
| | | return rankDiff; |
| | | } |
| | | int latencyDiff = Long.compare(toLong(right.get("avgLatencyMs")), toLong(left.get("avgLatencyMs"))); |
| | | if (latencyDiff != 0) { |
| | | return latencyDiff; |
| | | } |
| | | return Long.compare(toLong(right.get("latestTime")), toLong(left.get("latestTime"))); |
| | | }); |
| | | |
| | | List<Map<String, Object>> result = new ArrayList<>(); |
| | | for (Map<String, Object> item : candidates) { |
| | | if (item == null) { |
| | | continue; |
| | | } |
| | | Map<String, Object> focus = new LinkedHashMap<>(); |
| | | focus.put("name", toText(item.get("deviceType")) + "-" + toText(item.get("deviceNo"))); |
| | | focus.put("ip", toText(item.get("ip"))); |
| | | focus.put("statusText", defaultText(toText(item.get("statusText")), "未知")); |
| | | focus.put("statusType", resolveNetworkStatusTagType(toText(item.get("status")))); |
| | | focus.put("avgLatencyMs", item.get("avgLatencyMs")); |
| | | focus.put("latestTimeLabel", defaultText(toText(item.get("latestTimeLabel")), "--")); |
| | | focus.put("message", defaultText(toText(item.get("message")), "暂无额外说明")); |
| | | result.add(focus); |
| | | if (result.size() >= 4) { |
| | | break; |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private int resolveNetworkFocusRank(Map<String, Object> row) { |
| | | String status = row == null ? "" : toText(row.get("status")); |
| | | if ("TIMEOUT".equalsIgnoreCase(status) || "ERROR".equalsIgnoreCase(status)) { |
| | | return 0; |
| | | } |
| | | if ("UNSTABLE".equalsIgnoreCase(status)) { |
| | | return 1; |
| | | } |
| | | if ("NO_DATA".equalsIgnoreCase(status)) { |
| | | return 2; |
| | | } |
| | | return 3; |
| | | } |
| | | |
| | | private String resolveNetworkStatusTagType(String status) { |
| | | if ("TIMEOUT".equalsIgnoreCase(status) || "ERROR".equalsIgnoreCase(status)) { |
| | | return "danger"; |
| | | } |
| | | if ("UNSTABLE".equalsIgnoreCase(status)) { |
| | | return "warning"; |
| | | } |
| | | if ("OK".equalsIgnoreCase(status)) { |
| | | return "success"; |
| | | } |
| | | return "info"; |
| | | } |
| | | |
| | | private boolean isInboundTask(Long wrkSts) { |
| | | return wrkSts != null && wrkSts > 0 && wrkSts < 100; |
| | | } |