refactor: server-side device metrics, no JS
This commit is contained in:
parent
0dede50f9e
commit
c2588e7785
@ -83,6 +83,7 @@ type PageData struct {
|
||||
ResourceStatusBoard *service.ResourceStatusBoard
|
||||
AlarmRecords []service.AlarmRecord
|
||||
TodayAlarmCount int
|
||||
DeviceMetrics []DeviceMetric
|
||||
FaceGalleryPersons []storage.PersonRecord
|
||||
Templates []service.Template
|
||||
Template *service.Template
|
||||
@ -777,6 +778,25 @@ func (u *UI) pageDashboard(w http.ResponseWriter, r *http.Request) {
|
||||
data.Tasks = u.tasks.ListTasks()
|
||||
}
|
||||
data.AttentionDevices = nil
|
||||
// Load device metrics
|
||||
if u.agent != nil {
|
||||
for _, dev := range data.Devices {
|
||||
if dev == nil || !dev.Online { continue }
|
||||
body, code, err := u.agent.Do("GET", dev.IP, dev.AgentPort, "/v1/metrics", nil)
|
||||
if err != nil || code != 200 { continue }
|
||||
var m struct {
|
||||
CPU struct{ UsagePct float64 } `json:"cpu"`
|
||||
Memory struct{ TotalKB, AvailableKB uint64 } `json:"memory"`
|
||||
NPU struct{ UsagePct float64 } `json:"npu"`
|
||||
}
|
||||
json.Unmarshal(body, &m)
|
||||
var mem float64
|
||||
if m.Memory.TotalKB > 0 { mem = float64(m.Memory.TotalKB-m.Memory.AvailableKB) / float64(m.Memory.TotalKB) * 100 }
|
||||
data.DeviceMetrics = append(data.DeviceMetrics, DeviceMetric{
|
||||
Name: dev.DisplayName(), CPU: m.CPU.UsagePct, Mem: mem, NPU: m.NPU.UsagePct,
|
||||
})
|
||||
}
|
||||
}
|
||||
for _, dev := range data.Devices {
|
||||
if dev != nil && !dev.Online {
|
||||
data.AttentionDevices = append(data.AttentionDevices, dev)
|
||||
@ -4191,3 +4211,10 @@ func (u *UI) apiDeviceMetrics(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(code)
|
||||
w.Write(body)
|
||||
}
|
||||
|
||||
type DeviceMetric struct {
|
||||
Name string `json:"name"`
|
||||
CPU float64 `json:"cpu"`
|
||||
Mem float64 `json:"mem"`
|
||||
NPU float64 `json:"npu"`
|
||||
}
|
||||
|
||||
@ -28,7 +28,20 @@
|
||||
<h3 class="title-with-icon" style="margin:0">{{icon "heartbeat"}}<span>设备负载</span></h3>
|
||||
<span class="muted small" id="metrics-time"></span>
|
||||
</div>
|
||||
<div id="metrics-body" style="display:flex;flex-wrap:wrap;gap:12px"><span class="muted">加载中…</span></div>
|
||||
<div id="metrics-body" style="display:flex;flex-wrap:wrap;gap:12px">
|
||||
{{range .DeviceMetrics}}
|
||||
<div style="padding:8px 12px;border:1px solid var(--border);border-radius:var(--radius);background:var(--surface-soft);min-width:160px">
|
||||
<div style="font-weight:500;font-size:12px;margin-bottom:4px">{{.Name}}</div>
|
||||
<div style="display:flex;gap:12px;font-size:11px">
|
||||
<span>CPU <strong>{{printf "%.0f%%" .CPU}}</strong></span>
|
||||
<span>内存 <strong>{{printf "%.0f%%" .Mem}}</strong></span>
|
||||
<span>NPU <strong>{{printf "%.0f%%" .NPU}}</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<span class="muted">无在线设备</span>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
@ -74,37 +87,4 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
var body=document.getElementById('metrics-body'),time=document.getElementById('metrics-time');
|
||||
function load(){
|
||||
time.textContent='加载中…';
|
||||
var devs=[{{range .Devices}}{{if .Online}}{id:"{{.DeviceID}}",name:"{{.DisplayName}}"},{{end}}{{end}}];
|
||||
if(!devs.length){body.innerHTML='<span class="muted">无在线设备</span>';return}
|
||||
Promise.all(devs.map(function(d){
|
||||
return fetch('/ui/api/device-metrics?device_id='+d.id).then(function(r){return r.json()}).catch(function(){return null}).then(function(m){return{name:d.name,data:m}});
|
||||
})).then(function(r){
|
||||
var html='';
|
||||
r.forEach(function(item){
|
||||
var m=item.data;
|
||||
var cpu=m&&m.cpu?m.cpu.usage_pct:'-';
|
||||
var mem=m&&m.memory?((m.memory.used_mb||0)/(m.memory.total_mb||1)*100).toFixed(0):'-';
|
||||
var npu=m&&m.npu?m.npu.usage_pct:'-';
|
||||
html+='<div style="padding:8px 12px;border:1px solid var(--border);border-radius:var(--radius);background:var(--surface-soft);min-width:160px">';
|
||||
html+='<div style="font-weight:500;font-size:12px;margin-bottom:4px">'+esc(item.name)+'</div>';
|
||||
html+='<div style="display:flex;gap:12px;font-size:11px">';
|
||||
html+='<span>CPU <strong>'+cpu+'%</strong></span>';
|
||||
html+='<span>内存 <strong>'+mem+'%</strong></span>';
|
||||
html+='<span>NPU <strong>'+npu+'%</strong></span>';
|
||||
html+='</div></div>';
|
||||
});
|
||||
body.innerHTML=html;
|
||||
var now=new Date();
|
||||
time.textContent=now.getHours()+':'+String(now.getMinutes()).padStart(2,'0')+':'+String(now.getSeconds()).padStart(2,'0');
|
||||
});
|
||||
}
|
||||
function esc(s){return(s||'').replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');}
|
||||
load();setInterval(load,10000);
|
||||
})();
|
||||
</script>
|
||||
{{end}}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user