From 610402d47f3803c3074f0afb5c9ca811388014a7 Mon Sep 17 00:00:00 2001 From: "Logan.Li" Date: Mon, 14 Sep 2026 08:29:56 +0000 Subject: [PATCH] =?UTF-8?q?fix(dashboard):=20=E4=BF=AE=E5=A4=8D=E5=A4=A7?= =?UTF-8?q?=E5=B1=8F=E4=B8=BB=E6=9C=BA=E5=88=97=E8=A1=A8=E6=81=92=E4=B8=BA?= =?UTF-8?q?=E7=A9=BA=20=E2=80=94=E2=80=94=20=E5=8C=BA=E5=9F=9F=E8=A1=A8?= =?UTF-8?q?=E5=90=8D=E9=94=99=E8=AF=AF=E4=B8=94=E9=94=99=E8=AF=AF=E8=A2=AB?= =?UTF-8?q?=E9=9D=99=E9=BB=98=E5=90=9E=E6=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 现象:/servers 资产里有 31 台,/dashboards 大屏一台都不显示。 根因:GetLatestReports 的 SQL 中 JOIN 了不存在的表 asset_regions, 实际表名是 asset_cloud_regions(见 model/server.go 的 Region.TableName())。 查询直接报 Error 1146,但 Scan() 的错误未校验,函数静默返回空数组, 接口始终 200 + data:[],因此前端无任何报错可循。 - agent.go: JOIN 改为 asset_cloud_regions,并补上错误校验与 500 响应 - agent_report_test.go: 移除手工创建的 asset_regions, 改由 AutoMigrate(&model.Server{}) 级联建立 asset_cloud_regions, 避免测试用错误表名掩盖生产问题 验证:/agent/latest 由 0 台恢复为 31 台(含未装 Agent 的 not_installed 主机)。 // Logan.Li --- backend/controller/agent.go | 14 +++++++++++--- backend/controller/agent_report_test.go | 5 ++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/backend/controller/agent.go b/backend/controller/agent.go index 615e307..8970506 100644 --- a/backend/controller/agent.go +++ b/backend/controller/agent.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "log" "math" "net/http" "sort" @@ -289,7 +290,9 @@ func (h *AgentHandler) GetLatestReports(c *gin.Context) { threeMinAgo := time.Now().UTC().Add(-3 * time.Minute) // 以 servers 表为主,LEFT JOIN 最近 3 分钟内的 Agent 上报 // 未装 Agent 的主机也会显示(agent_status='not_installed'),打破"不显示→无法安装"的循环 - h.db.Raw(` + // 必须检查错误:此前未校验导致 asset_regions 表名错误被静默吞掉, + // 接口稳定返回空数组,表现为"资产有主机、大屏没主机"却无任何报错。 // Logan.Li + if err := h.db.Raw(` SELECT s.id as server_id, s.hostname, @@ -330,9 +333,14 @@ func (h *AgentHandler) GetLatestReports(c *gin.Context) { GROUP BY hostname ) ) a ON a.hostname = s.hostname - LEFT JOIN asset_regions r ON r.id = s.region_id + LEFT JOIN asset_cloud_regions r ON r.id = s.region_id ORDER BY a.report_time DESC, s.id ASC - `, threeMinAgo).Scan(&results) + `, threeMinAgo).Scan(&results).Error; err != nil { + log.Printf("[GetLatestReports] 查询主机最新上报失败: %v", err) + c.JSON(http.StatusInternalServerError, model.Response{ + Code: 500, Message: "查询主机列表失败: " + err.Error()}) + return + } if results == nil { results = []model.AgentLatestResponse{} diff --git a/backend/controller/agent_report_test.go b/backend/controller/agent_report_test.go index a3a5793..8143a5d 100644 --- a/backend/controller/agent_report_test.go +++ b/backend/controller/agent_report_test.go @@ -135,9 +135,8 @@ func TestGetLatestReportsUsesUTCTimeBoundary(t *testing.T) { if err := db.AutoMigrate(&model.Server{}, &model.AgentReport{}); err != nil { t.Fatalf("迁移测试表失败: %v", err) } - if err := db.Exec("CREATE TABLE asset_regions (id INTEGER PRIMARY KEY, name TEXT)").Error; err != nil { - t.Fatalf("创建区域测试表失败: %v", err) - } + // asset_cloud_regions 由上面的 AutoMigrate(&model.Server{}) 级联建立, + // 无需手工建表;此前手工建 asset_regions 反而掩盖了生产侧同名的错误 join。 // Logan.Li server := model.Server{ Hostname: "c-redis-cluster-3",