diff --git a/internal/service/resource_management.go b/internal/service/resource_management.go index c82b141..2efcad5 100644 --- a/internal/service/resource_management.go +++ b/internal/service/resource_management.go @@ -7,6 +7,8 @@ import ( "path/filepath" "sort" "strings" + "sync" + "time" "3588AdminBackend/internal/models" "3588AdminBackend/internal/storage" @@ -220,3 +222,57 @@ func BuildResourceStatusBoard(standardResources []storage.StandardResourceRecord }) return board } + +// FetchAndBuildResourceBoard 并发查询所有在线设备的资源状态并构建面板,总超时 5 秒。 +func FetchAndBuildResourceBoard(agent *AgentClient, devices []*models.Device, standardResources []storage.StandardResourceRecord) ResourceStatusBoard { + board := ResourceStatusBoard{ + Summary: ResourceStatusSummary{ + StandardResources: len(standardResources), + Devices: len(devices), + }, + Rows: make([]ResourceStatusRow, 0, len(devices)), + } + if agent == nil || len(standardResources) == 0 { + return board + } + + installed := make(map[string][]InstalledResourceStatus) + var mu sync.Mutex + var wg sync.WaitGroup + + // 总超时:最多等 5 秒 + done := make(chan struct{}) + go func() { + time.Sleep(5 * time.Second) + close(done) + }() + + for _, device := range devices { + if device == nil || !device.Online { + continue + } + wg.Add(1) + go func(dev *models.Device) { + defer wg.Done() + items, err := FetchInstalledResourceStatuses(agent, dev) + if err == nil { + mu.Lock() + installed[dev.DeviceID] = items + mu.Unlock() + } + }(device) + } + + // Wait with timeout + waitCh := make(chan struct{}) + go func() { + wg.Wait() + close(waitCh) + }() + select { + case <-waitCh: + case <-done: + } + + return BuildResourceStatusBoard(standardResources, devices, installed) +} diff --git a/internal/web/ui.go b/internal/web/ui.go index a896621..d475882 100644 --- a/internal/web/ui.go +++ b/internal/web/ui.go @@ -610,7 +610,6 @@ func (u *UI) Routes() (chi.Router, error) { r.Get("/system", u.pageSystem) r.Get("/system/db-backup", u.pageSystemDBBackup) r.Get("/resources", u.pageResources) - r.Get("/api/resources/device-status", u.apiResourceDeviceStatus) r.Post("/system/db-restore", u.actionSystemDBRestore) r.Get("/api/graph-node-types", u.apiGraphNodeTypes) r.Get("/device-config", u.pageDeviceConfig) @@ -1419,48 +1418,21 @@ func (u *UI) pageResources(w http.ResponseWriter, r *http.Request) { data.OnlineCount++ } } + board := service.ResourceStatusBoard{} if strings.TrimSpace(u.dbPath) != "" { if store, err := storage.OpenSQLite(u.dbPath); err == nil { resourcesRepo := storage.NewResourcesRepo(store.DB()) if items, err := resourcesRepo.List(); err == nil { data.StandardResources = items + board = service.FetchAndBuildResourceBoard(u.agent, data.Devices, items) } _ = store.Close() } } + data.ResourceStatusBoard = &board u.render(w, r, "resources", data) } -func (u *UI) apiResourceDeviceStatus(w http.ResponseWriter, r *http.Request) { - u.ensureDevicesLoaded() - devices := u.registry.GetDevices() - board := service.ResourceStatusBoard{ - Summary: service.ResourceStatusSummary{Devices: len(devices)}, - } - if strings.TrimSpace(u.dbPath) != "" { - if store, err := storage.OpenSQLite(u.dbPath); err == nil { - resourcesRepo := storage.NewResourcesRepo(store.DB()) - if items, err := resourcesRepo.List(); err == nil { - board.Summary.StandardResources = len(items) - installed := map[string][]service.InstalledResourceStatus{} - for _, device := range devices { - if device == nil || !device.Online { - continue - } - items, err := service.FetchInstalledResourceStatuses(u.agent, device) - if err == nil { - installed[device.DeviceID] = items - } - } - board = service.BuildResourceStatusBoard(items, devices, installed) - } - _ = store.Close() - } - } - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(board) -} - func (u *UI) actionResourceSync(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) diff --git a/internal/web/ui/templates/resources.html b/internal/web/ui/templates/resources.html index a3772b7..81258f0 100644 --- a/internal/web/ui/templates/resources.html +++ b/internal/web/ui/templates/resources.html @@ -1,4 +1,5 @@ {{define "resources"}} +{{$board := .ResourceStatusBoard}}
| 设备 | @@ -82,69 +83,42 @@非标资源 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 正在加载设备资源状态… | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
+ {{.DeviceName}}
+ {{.DeviceID}}
+ |
+ {{range .Cells}}
+ + {{if eq .Status "ok"}}一致 + {{else if eq .Status "mismatch"}}不一致 + {{else}}缺失{{end}} + | + {{end}} +
+ {{if gt .ExtraCount 0}}
+
+
+ {{else}}
+ 0
+ {{end}}
+ {{.ExtraCount}} 个 · 更多+
+ {{range .ExtraResources}}
+
+ {{.Name}}
+ {{end}}
+ |
+ ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 暂无设备资源状态。请先确保设备在线且 agent 实现了 GET /v1/resources/status 端点。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||