From d9106dde6eb5d7976d1c4f46acdb7e7388d3f706 Mon Sep 17 00:00:00 2001 From: "Logan.Li" Date: Sat, 25 Jul 2026 15:51:12 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=81=A2=E5=A4=8DAgent=E6=8C=87?= =?UTF-8?q?=E6=A0=87=E5=B9=B6=E4=BF=AE=E5=A4=8D=E6=97=B6=E9=97=B4=E5=BC=B9?= =?UTF-8?q?=E5=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 使用按主键更新避免SQLite字段错误 - 自定义时间选择器改用Portal避免卡片遮挡 --- backend/controller/agent.go | 43 +++++------------ .../host-monitor/HostTimeRangePicker.tsx | 47 ++++++++----------- 2 files changed, 32 insertions(+), 58 deletions(-) diff --git a/backend/controller/agent.go b/backend/controller/agent.go index e11674b..01da678 100644 --- a/backend/controller/agent.go +++ b/backend/controller/agent.go @@ -127,51 +127,34 @@ func (h *AgentHandler) ReceiveReport(c *gin.Context) { memMB := int64(memGB * 1024) // GB → MB diskGB := int64(totalDiskGB + 0.5) // 39.99 → 40 - // 直接 SQL 更新 asset_servers 监控字段 - // 若 AgentVersion 非空则同步写入,否则保留数据库中已有版本号(防止旧版Agent空字段覆盖已设置的版本) - updateSQL := `UPDATE asset_servers SET - cpu_usage = ?, cpu_iowait = ?, memory_usage = ?, disk_usage = ?, - cpu = ?, memory = ?, disk = ?, - status = ?, agent_status = ?` + func() string { - if req.AgentVersion != "" { - return `, agent_version = ?` - } - return `` - }() - args := []interface{}{ - req.CPU.UsagePercent, req.CPU.IOWait, req.Memory.UsagePercent, diskAvg, - req.CPU.CoreCount, memMB, diskGB, - "running", "online", + // 使用 map 按主键更新,避免可选系统字段导致原始 SQL 占位参数错位。 // Logan.Li + updates := map[string]interface{}{ + "cpu_usage": req.CPU.UsagePercent, "memory_usage": req.Memory.UsagePercent, + "disk_usage": diskAvg, + "cpu": req.CPU.CoreCount, "memory": memMB, "disk": diskGB, + "status": "running", "agent_status": "online", "updated_at": time.Now(), } if req.AgentVersion != "" { - args = append(args, req.AgentVersion) + updates["agent_version"] = req.AgentVersion } if req.System != nil { if req.System.OSVersion != "" { - updateSQL += ", os = ?" - args = append(args, req.System.OSVersion) + updates["os"] = req.System.OSVersion } if req.System.Kernel != "" { - updateSQL += ", kernel = ?" - args = append(args, req.System.Kernel) + updates["kernel"] = req.System.Kernel } if req.System.Uptime > 0 { - updateSQL += ", uptime = ?" - args = append(args, req.System.Uptime) + updates["uptime"] = req.System.Uptime } } - updateSQL += ", updated_at = ?" - args = append(args, time.Now()) + var result *gorm.DB if assetMatched { - updateSQL += " WHERE id = ?" - args = append(args, matchedServer.ID) + result = h.db.Model(&model.Server{}).Where("id = ?", matchedServer.ID).Updates(updates) } else { - updateSQL += " WHERE hostname = ? OR ip = ?" - args = append(args, req.Hostname, matchIP) + result = h.db.Model(&model.Server{}).Where("hostname = ? OR ip = ?", req.Hostname, matchIP).Updates(updates) } - result := h.db.Exec(updateSQL, args...) - // 如果还是没匹配到 —— 按 hostname 显式查重后再注册 // Logan.Li // asset_servers.hostname 无 UNIQUE 索引,OnConflict 不可靠,故先 First 查重, // 避免 Agent 每次上报(10s)都新建记录导致资产越来越多。 diff --git a/frontend/src/pages/monitor/host-monitor/HostTimeRangePicker.tsx b/frontend/src/pages/monitor/host-monitor/HostTimeRangePicker.tsx index 50d04fe..50f6df8 100644 --- a/frontend/src/pages/monitor/host-monitor/HostTimeRangePicker.tsx +++ b/frontend/src/pages/monitor/host-monitor/HostTimeRangePicker.tsx @@ -1,8 +1,9 @@ // 主机监控时间范围选择器 — 预设 + 自定义 // Logan.Li -import { useState, useRef, useEffect } from 'react'; +import { useState } from 'react'; import { Calendar, ChevronDown, Timer } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; +import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { TIME_RANGE_PRESETS, type HostMonitorTimeRange, @@ -21,15 +22,6 @@ export function HostTimeRangePicker({ value, onChange }: Props) { const now = new Date(); const [customStart, setCustomStart] = useState(toDatetimeLocalValue(new Date(now.getTime() - 3600_000))); const [customEnd, setCustomEnd] = useState(toDatetimeLocalValue(now)); - const popRef = useRef(null); - - useEffect(() => { - const handler = (e: MouseEvent) => { - if (popRef.current && !popRef.current.contains(e.target as Node)) setCustomOpen(false); - }; - document.addEventListener('mousedown', handler); - return () => document.removeEventListener('mousedown', handler); - }, []); const selectPreset = (id: TimeRangePresetId) => { if (id === 'custom') return; @@ -72,20 +64,20 @@ export function HostTimeRangePicker({ value, onChange }: Props) { {p.label} ))} -
- - {customOpen && ( -
+ + + + +

{i18n.t('monitor.hosttimerangepi.s0122e022')}

@@ -115,13 +107,12 @@ export function HostTimeRangePicker({ value, onChange }: Props) { 应用
-
- )} -
+ +
{formatRangeSummary(value)} ); -} \ No newline at end of file +}