From ab1a13d5b2eb05aa52f990b13bc1420cc2d0a325 Mon Sep 17 00:00:00 2001 From: dushixiang Date: Sun, 11 Jan 2026 11:43:39 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9C=A8=E7=AE=A1=E7=90=86=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=AE=BE=E5=A4=87=20IP=20=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/app.go | 1 + internal/handler/agent_admin_handler.go | 11 ++++++ internal/handler/agent_metrics_handler.go | 2 ++ internal/metric/agent.go | 1 + internal/service/metric_service.go | 1 + web/src/admin/pages/Agents/AgentDetail.tsx | 40 ++++++++++++++++++++-- web/src/api/agent.ts | 4 +++ web/src/types/index.ts | 11 ++++++ 8 files changed, 68 insertions(+), 3 deletions(-) diff --git a/internal/app.go b/internal/app.go index 2cc1344..e66cd8d 100644 --- a/internal/app.go +++ b/internal/app.go @@ -243,6 +243,7 @@ func setupApi(app *orz.App, components *AppComponents) { adminApi.GET("/agents/statistics", components.AgentHandler.GetStatistics) adminApi.GET("/agents/tags", components.AgentHandler.GetTags) adminApi.GET("/agents/:id", components.AgentHandler.GetForAdmin) + adminApi.GET("/agents/:id/metrics/latest", components.AgentHandler.GetAdminLatestMetrics) adminApi.PUT("/agents/:id", components.AgentHandler.UpdateInfo) adminApi.POST("/agents/batch/tags", components.AgentHandler.BatchUpdateTags) adminApi.DELETE("/agents/:id", components.AgentHandler.Delete) diff --git a/internal/handler/agent_admin_handler.go b/internal/handler/agent_admin_handler.go index 5479de6..87e777c 100644 --- a/internal/handler/agent_admin_handler.go +++ b/internal/handler/agent_admin_handler.go @@ -51,6 +51,17 @@ func (h *AgentHandler) GetForAdmin(c echo.Context) error { return orz.Ok(c, agent) } +// GetAdminLatestMetrics 获取探针最新指标(管理员接口,显示完整信息) +func (h *AgentHandler) GetAdminLatestMetrics(c echo.Context) error { + id := c.Param("id") + + metrics, ok := h.metricService.GetLatestMetrics(id) + if !ok { + return orz.NewError(404, "探针最新指标不存在") + } + return orz.Ok(c, metrics) +} + // SendCommand 向探针发送指令 func (h *AgentHandler) SendCommand(c echo.Context) error { agentID := c.Param("id") diff --git a/internal/handler/agent_metrics_handler.go b/internal/handler/agent_metrics_handler.go index 379e3bb..43eb6c8 100644 --- a/internal/handler/agent_metrics_handler.go +++ b/internal/handler/agent_metrics_handler.go @@ -142,6 +142,8 @@ func (h *AgentHandler) GetLatestMetrics(c echo.Context) error { if !ok { return orz.NewError(404, "探针最新指标不存在") } + // 清空网络接口指标,避免返回敏感信息 + metrics.NetworkInterfaces = nil return orz.Ok(c, metrics) } diff --git a/internal/metric/agent.go b/internal/metric/agent.go index 8bae9f9..83d5fec 100644 --- a/internal/metric/agent.go +++ b/internal/metric/agent.go @@ -26,6 +26,7 @@ type LatestMetrics struct { Memory *protocol.MemoryData `json:"memory,omitempty"` Disk *DiskSummary `json:"disk,omitempty"` Network *NetworkSummary `json:"network,omitempty"` + NetworkInterfaces []protocol.NetworkData `json:"networkInterfaces,omitempty"` NetworkConnection *protocol.NetworkConnectionData `json:"networkConnection,omitempty"` Host *protocol.HostInfoData `json:"host,omitempty"` GPU []protocol.GPUData `json:"gpu,omitempty"` diff --git a/internal/service/metric_service.go b/internal/service/metric_service.go index c9c52bb..60b73ea 100644 --- a/internal/service/metric_service.go +++ b/internal/service/metric_service.go @@ -127,6 +127,7 @@ func (s *MetricService) HandleMetricData(ctx context.Context, agentID string, me TotalBytesRecvTotal: totalRecvTotal, TotalInterfaces: len(networkDataList), } + latestMetrics.NetworkInterfaces = networkDataList // 更新流量统计 if err := s.trafficService.UpdateAgentTraffic(ctx, agentID, totalRecvTotal, totalSentTotal); err != nil { s.logger.Error("更新探针流量统计失败", diff --git a/web/src/admin/pages/Agents/AgentDetail.tsx b/web/src/admin/pages/Agents/AgentDetail.tsx index f93c108..858e3a9 100644 --- a/web/src/admin/pages/Agents/AgentDetail.tsx +++ b/web/src/admin/pages/Agents/AgentDetail.tsx @@ -6,8 +6,14 @@ import {Activity, ArrowLeft, Clock, FileWarning, Lock, RefreshCw, Shield, Termin import TamperProtection from './TamperProtection.tsx'; import SSHLoginMonitor from './SSHLoginMonitor.tsx'; import TrafficStats from './TrafficStats.tsx'; -import {getAgentForAdmin, getAuditResult, sendAuditCommand, type VPSAuditResult} from '@/api/agent.ts'; -import type {Agent} from '@/types'; +import { + getAgentForAdmin, + getAgentLatestMetricsForAdmin, + getAuditResult, + sendAuditCommand, + type VPSAuditResult +} from '@/api/agent.ts'; +import type {Agent, LatestMetrics} from '@/types'; import dayjs from 'dayjs'; import {getErrorMessage} from '@/lib/utils'; import AuditResultView from './AuditResultView'; @@ -19,6 +25,7 @@ const AgentDetail = () => { const {message: messageApi} = App.useApp(); const [loading, setLoading] = useState(false); const [agent, setAgent] = useState(null); + const [latestMetrics, setLatestMetrics] = useState(null); const [auditResult, setAuditResult] = useState(null); const [auditing, setAuditing] = useState(false); const [activeTab, setActiveTab] = useState(searchParams.get('tab') || 'info'); @@ -28,13 +35,15 @@ const AgentDetail = () => { setLoading(true); try { - const [agentRes, auditRes] = await Promise.all([ + const [agentRes, auditRes, latestMetricsRes] = await Promise.all([ getAgentForAdmin(id), getAuditResult(id).catch(() => ({data: null})), + getAgentLatestMetricsForAdmin(id).catch(() => ({data: null})), ]); setAgent(agentRes.data); setAuditResult(auditRes.data); + setLatestMetrics(latestMetricsRes.data || null); } catch (error: any) { messageApi.error(error.response?.data?.message || '获取探针信息失败'); } finally { @@ -104,6 +113,13 @@ const AgentDetail = () => { ]; + const deviceIpInterfaces = (latestMetrics?.networkInterfaces || []) + .map((netInterface) => ({ + name: netInterface.interface, + addrs: Array.from(new Set((netInterface.addrs || []).map((addr) => addr.trim()).filter(Boolean))), + })) + .filter((netInterface) => netInterface.addrs.length > 0); + // Tab 项配置 const tabItems: TabsProps['items'] = [ { @@ -120,6 +136,24 @@ const AgentDetail = () => { {agent?.id} {agent?.hostname} {agent?.ip} + + {deviceIpInterfaces.length > 0 ? ( +
+ {deviceIpInterfaces.map((netInterface) => ( +
+ {netInterface.name} +
+ {netInterface.addrs.map((addr) => ( + {addr} + ))} +
+
+ ))} +
+ ) : ( + '-' + )} +
{agent?.os} diff --git a/web/src/api/agent.ts b/web/src/api/agent.ts index e6ee9e0..b295c4e 100644 --- a/web/src/api/agent.ts +++ b/web/src/api/agent.ts @@ -78,6 +78,10 @@ export const getAgentForAdmin = (id: string) => { return get(`/admin/agents/${id}`); }; +export const getAgentLatestMetricsForAdmin = (agentId: string) => { + return get(`/admin/agents/${agentId}/metrics/latest`); +}; + export const getAgentMetrics = (params: GetAgentMetricsRequest) => { const {agentId, type, range = '1h', start, end, interface: interfaceName} = params; const query = new URLSearchParams(); diff --git a/web/src/types/index.ts b/web/src/types/index.ts index 417a818..a2bc33f 100644 --- a/web/src/types/index.ts +++ b/web/src/types/index.ts @@ -207,6 +207,16 @@ export interface NetworkSummary { totalInterfaces: number; // 网卡数量 } +export interface NetworkInterfaceMetric { + interface: string; + macAddress?: string; + addrs?: string[]; + bytesSentRate: number; + bytesRecvRate: number; + bytesSentTotal: number; + bytesRecvTotal: number; +} + // 主机信息 export interface HostInfo { hostname: string; @@ -416,6 +426,7 @@ export interface LatestMetrics { memory?: MemoryMetric; disk?: DiskSummary; // 改为汇总数据 network?: NetworkSummary; // 改为汇总数据 + networkInterfaces?: NetworkInterfaceMetric[]; networkConnection?: NetworkConnectionMetric; // 网络连接统计 host?: HostInfo; // 主机信息 gpu?: GPUMetric[]; // GPU 列表