feat: 修复服务器硬件规格(CPU核/内存/磁盘) + Top 5 资源排行

修复:
- agent.go ReceiveReport 写入 cpu(核数)/memory(总内存MB)/disk(总磁盘GB) 到 servers 表
- 之前 Agent 上报只写了 cpu_usage/memory_usage/disk_usage 使用率,硬件规格始终为 0

新功能:
- GET /api/v1/metrics/top?metric=cpu|memory|disk&limit=5 主机排行 API
- HostMonitor 新增 Top 5 排行面板: CPU/内存/磁盘 使用率排名
- TopRankCard 组件: 排名号+主机名+进度条+百分比
This commit is contained in:
attacker committed 2026-06-18 13:13:03 +00:00
1 parent 06d7451cf9
commit 737f00169f
8 files changed
+150 -567

No files matched your search

+11
View File
@@ -76,12 +76,23 @@ func (h *AgentHandler) ReceiveReport(c *gin.Context) {
// 同步更新 servers 表的实时指标(通过 hostname 匹配)
diskAvg := avgDiskUsage(req.Disks)
// 计算硬件规格
totalDiskGB := 0.0
for _, d := range req.Disks {
totalDiskGB += d.TotalGB
}
memMB := int64(req.Memory.TotalGB * 1024) // GB → MB
result := h.db.Model(&models.Server{}).
Where("hostname = ? OR ip = ?", req.Hostname, req.Hostname).
Updates(map[string]interface{}{
"cpu_usage": req.CPU.UsagePercent,
"memory_usage": req.Memory.UsagePercent,
"disk_usage": diskAvg,
"cpu": req.CPU.CoreCount,
"memory": memMB,
"disk": int64(totalDiskGB),
"status": "running",
})
+56
View File
@@ -127,6 +127,62 @@ func (h *MetricsHandler) ListMetricNames(c *gin.Context) {
c.JSON(http.StatusOK, models.Response{Code: 200, Data: names})
}
// TopHosts 返回指定指标的 Top N 主机排行
// GET /api/v1/metrics/top?metric=cpu&limit=5
func (h *MetricsHandler) TopHosts(c *gin.Context) {
metric := c.DefaultQuery("metric", "cpu")
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "5"))
type HostRank struct {
Hostname string `json:"hostname"`
IP string `json:"ip"`
CPUUsage float64 `json:"cpu_usage"`
MemUsage float64 `json:"memory_usage"`
DiskUsage float64 `json:"disk_usage"`
CPUCores int `json:"cpu_cores"`
MemMB int64 `json:"memory_mb"`
DiskGB int64 `json:"disk_gb"`
Status string `json:"status"`
}
var servers []models.Server
orderField := "cpu_usage DESC"
switch metric {
case "cpu":
orderField = "cpu_usage DESC"
case "mem", "memory":
orderField = "memory_usage DESC"
case "disk":
orderField = "disk_usage DESC"
default:
orderField = "cpu_usage DESC"
}
h.db.Where("agent_status = ?", "online").
Order(orderField).
Limit(limit).
Find(&servers)
result := make([]HostRank, len(servers))
for i, s := range servers {
result[i] = HostRank{
Hostname: s.Hostname,
IP: s.IP,
CPUUsage: s.CPUUsage,
MemUsage: s.MemoryUsage,
DiskUsage: s.DiskUsage,
CPUCores: s.CPU,
MemMB: s.Memory,
DiskGB: s.Disk,
Status: s.Status,
}
}
if result == nil {
result = []HostRank{}
}
c.JSON(http.StatusOK, models.Response{Code: 200, Data: result})
}
func now() int64 {
return time.Now().Unix()
}
+1
View File
@@ -473,6 +473,7 @@ func Register(r *gin.Engine, db *gorm.DB, log *zap.Logger, cfg *config.Config, c
metricsGroup.GET("/list", metricsHandler.ListMetrics)
metricsGroup.GET("/query", metricsHandler.QueryValues)
metricsGroup.GET("/names", metricsHandler.ListMetricNames)
metricsGroup.GET("/top", metricsHandler.TopHosts)
}
// SNMP 设备管理 — 网络设备/服务器硬件 // Logan.Li