From 63b01db83d9aad8a15276b4236a9a22e4aeef065 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期二, 05 五月 2026 12:30:59 +0800
Subject: [PATCH] # Agent数据分析V3.0.1.7

---
 src/main/java/com/zy/system/controller/DashboardController.java |  199 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 195 insertions(+), 4 deletions(-)

diff --git a/src/main/java/com/zy/system/controller/DashboardController.java b/src/main/java/com/zy/system/controller/DashboardController.java
index fa97e4d..974bfce 100644
--- a/src/main/java/com/zy/system/controller/DashboardController.java
+++ b/src/main/java/com/zy/system/controller/DashboardController.java
@@ -3,10 +3,15 @@
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.core.annotations.ManagerAuth;
 import com.core.common.R;
+import com.zy.ai.entity.AiAutoTuneJob;
 import com.zy.ai.entity.AiChatSession;
+import com.zy.ai.entity.AiTokenUsage;
 import com.zy.ai.entity.LlmCallLog;
 import com.zy.ai.entity.LlmRouteConfig;
+import com.zy.ai.enums.AiPromptScene;
 import com.zy.ai.mapper.AiChatSessionMapper;
+import com.zy.ai.mapper.AiTokenUsageMapper;
+import com.zy.ai.service.AiAutoTuneJobService;
 import com.zy.ai.service.LlmCallLogService;
 import com.zy.ai.service.LlmRouteConfigService;
 import com.zy.asrs.entity.*;
@@ -25,6 +30,7 @@
 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;
@@ -58,13 +64,29 @@
     @Autowired
     private LlmCallLogService llmCallLogService;
     @Autowired
+    private AiAutoTuneJobService aiAutoTuneJobService;
+    @Autowired
     private AiChatSessionMapper aiChatSessionMapper;
+    @Autowired
+    private AiTokenUsageMapper aiTokenUsageMapper;
+    @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<>();
@@ -82,6 +104,7 @@
         result.put("overview", overview);
         result.put("tasks", tasks);
         result.put("devices", devices);
+        result.put("network", network);
         result.put("ai", ai);
         return R.ok(result);
     }
@@ -308,20 +331,32 @@
     private Map<String, Object> buildAiStats() {
         Map<String, Object> result = new LinkedHashMap<>();
 
+        // 浠庣嫭绔嬬疮璁¤〃璇诲彇 token 缁熻
         long tokenTotal = 0L;
         long promptTokenTotal = 0L;
         long completionTokenTotal = 0L;
+        long llmCallCountTotal = 0L;
+        try {
+            AiTokenUsage tokenUsage = aiTokenUsageMapper.selectById(1);
+            if (tokenUsage != null) {
+                promptTokenTotal = safeCount(tokenUsage.getPromptTokens());
+                completionTokenTotal = safeCount(tokenUsage.getCompletionTokens());
+                tokenTotal = safeCount(tokenUsage.getTotalTokens());
+                llmCallCountTotal = safeCount(tokenUsage.getLlmCallCount());
+            }
+        } catch (Exception e) {
+            log.warn("dashboard ai token usage load failed: {}", safeMessage(e));
+        }
+
+        // 浼氳瘽缁熻锛堜繚鐣欑敤浜庢樉绀轰細璇濇暟鍜屾彁闂疆娆★級
         long askCount = 0L;
         long sessionCount = 0L;
         try {
             List<AiChatSession> sessions = aiChatSessionMapper.selectList(new QueryWrapper<AiChatSession>()
-                    .select("id", "sum_prompt_tokens", "sum_completion_tokens", "sum_total_tokens", "ask_count"));
+                    .select("id", "ask_count"));
             sessionCount = sessions == null ? 0L : sessions.size();
             if (sessions != null) {
                 for (AiChatSession session : sessions) {
-                    promptTokenTotal += safeCount(session == null ? null : session.getSumPromptTokens());
-                    completionTokenTotal += safeCount(session == null ? null : session.getSumCompletionTokens());
-                    tokenTotal += safeCount(session == null ? null : session.getSumTotalTokens());
                     askCount += safeCount(session == null ? null : session.getAskCount());
                 }
             }
@@ -401,6 +436,7 @@
         overview.put("tokenTotal", tokenTotal);
         overview.put("promptTokenTotal", promptTokenTotal);
         overview.put("completionTokenTotal", completionTokenTotal);
+        overview.put("llmCallCountTotal", llmCallCountTotal);
         overview.put("askCount", askCount);
         overview.put("sessionCount", sessionCount);
         overview.put("routeTotal", routeTotal);
@@ -424,6 +460,74 @@
         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("姝e父", 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("姝e父", 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>()
@@ -434,6 +538,93 @@
         }
     }
 
+    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;
     }

--
Gitblit v1.9.1