diff --git a/internal/web/ui.go b/internal/web/ui.go index 56d1836..923536e 100644 --- a/internal/web/ui.go +++ b/internal/web/ui.go @@ -70,6 +70,7 @@ type PageData struct { Devices []*models.Device DeviceRows []DeviceOverviewRow + WizardStale map[string]bool AttentionDevices []*models.Device Found []*models.Device Device *models.Device @@ -109,6 +110,7 @@ type PageData struct { TodayAlarmCount int UnacknowledgedAlarmCount int DetectionChannelCount int + StaleCount int AlarmFilterDevices []string AlarmFilterRuleTypes []string SelectedAlarmDevice string @@ -971,6 +973,12 @@ func (u *UI) pageDashboard(w http.ResponseWriter, r *http.Request) { data.DetectionChannelCount = len(units) } } + // Count stale integration devices + for _, row := range data.DeviceRows { + if row.IntegrationStale { + data.StaleCount++ + } + } // Load device metrics if u.agent != nil { for _, dev := range data.Devices { @@ -1380,6 +1388,7 @@ func (u *UI) pageWizard(w http.ResponseWriter, r *http.Request) { u.ensureDevicesLoaded() data := PageData{Title: "部署向导"} data.Devices = u.registry.GetDevices() + data.WizardStale = u.integrationStaleMap() if u.preview != nil { if sources, err := u.preview.ListVideoSources(); err == nil { data.ConsoleAllVideoSources = sources @@ -5114,28 +5123,11 @@ func (u *UI) deviceOverviewPageData(r *http.Request, selectedIDs []string, errMs } selectedIDs = filterSelectedDeviceIDs(devices, selectedIDs) - // Check if integrations were updated after device's last deployment - if u.preview != nil { - if svcs, _ := u.preview.ListIntegrationServices(); len(svcs) > 0 { - maxUpdated := "" - for _, s := range svcs { - if s.UpdatedAt > maxUpdated { - maxUpdated = s.UpdatedAt - } - } - if maxUpdated != "" { - for i := range rows { - dev := rows[i].Device - if dev == nil || !dev.Online { - continue - } - status, _, _ := u.loadConfigStatus(dev) - if status == nil || status.Metadata.RenderedAt == "" { - continue - } - rows[i].IntegrationStale = maxUpdated > status.Metadata.RenderedAt - } - } + // Check integrations staleness + staleMap := u.integrationStaleMap() + for i := range rows { + if rows[i].Device != nil { + rows[i].IntegrationStale = staleMap[rows[i].Device.DeviceID] } } @@ -5279,6 +5271,39 @@ func profileAssetBusinessName(asset *service.ConfigProfileAsset) string { return strings.TrimSpace(asset.Name) } +func (u *UI) integrationStaleMap() map[string]bool { + stale := map[string]bool{} + if u.preview == nil { + return stale + } + svcs, _ := u.preview.ListIntegrationServices() + if len(svcs) == 0 { + return stale + } + maxUpdated := "" + for _, s := range svcs { + if s.UpdatedAt > maxUpdated { + maxUpdated = s.UpdatedAt + } + } + if maxUpdated == "" { + return stale + } + for _, dev := range u.registry.GetDevices() { + if dev == nil || !dev.Online { + continue + } + status, _, _ := u.loadConfigStatus(dev) + if status == nil || status.Metadata.RenderedAt == "" { + continue + } + if maxUpdated > status.Metadata.RenderedAt { + stale[dev.DeviceID] = true + } + } + return stale +} + func batchActionSummary(rows []DeviceOverviewRow, selectedIDs []string, action string) string { if len(selectedIDs) == 0 { return "" diff --git a/internal/web/ui/templates/dashboard.html b/internal/web/ui/templates/dashboard.html index 693558e..0e6e631 100644 --- a/internal/web/ui/templates/dashboard.html +++ b/internal/web/ui/templates/dashboard.html @@ -1,4 +1,10 @@ {{define "dashboard"}} +{{if gt .StaleCount 0}} +
+ ⚠ 第三方服务已更新,{{.StaleCount}} 台在线设备需重新下发配置以生效 + 前往部署向导 → +
+{{end}}
{{icon "bell"}}今日告警
diff --git a/internal/web/ui/templates/wizard.html b/internal/web/ui/templates/wizard.html index 045d06b..5f32d6f 100644 --- a/internal/web/ui/templates/wizard.html +++ b/internal/web/ui/templates/wizard.html @@ -32,7 +32,7 @@ {{if .Online}} {{$hasOnline = true}}
-
在线
+
在线{{if index $.WizardStale .DeviceID}}⚠ 需更新{{end}}
{{.DeviceName}}
{{.IP}}