diff --git a/SHA256SUMS b/SHA256SUMS index 1ffff6b..6ff5435 100644 --- a/SHA256SUMS +++ b/SHA256SUMS @@ -7,4 +7,4 @@ f9fbb4defa45b43abe0ce66973b1f4d553369b3a43c01d04f206c573f7dc96ca install.sh 4f6e8db3698a62f57823d3298a0e6814593de6fa3d31e4751b7ea4a76e553e35 systemd/pigway-pi-control.service aa21cef9a06593371ccff005335b6c0c826fbf4b5c48e4255b5f4b75ce6e9217 systemd/pigway-pi-control-api.service 9f59e7313ee58e687ae6dd29d175c67082674254ac5c5f54168b2735b64c20a4 uninstall.sh -da288d32bebc0892c0f401da37aa79e4e45dc41ad6d9deb0330dab743ce77591 web/index.html +16eacf89c50ae58bc4975c15fe6196cb7156cf367f987575dc18bff36e9ee413 web/index.html diff --git a/web/index.html b/web/index.html index de2f325..585d473 100644 --- a/web/index.html +++ b/web/index.html @@ -82,7 +82,8 @@ async function serviceAction(unit,action){if(!confirm(LANG==='zh'?`确定${actio function bytes(value){const n=Number(value||0);if(!n)return'--';const units=['B','KB','MB','GB','TB'];let x=n,i=0;while(x>=1024&&i=100||i===0?x.toFixed(0):x.toFixed(1)} ${units[i]}`} function meter(percent){const p=Math.max(0,Math.min(100,Number(percent||0)));return`
`} function hostCard(entry){const h=entry.host;if(!entry.online)return`

${esc(h.name||h.id)}

ID ${esc(h.id)}${esc(h.url||tr('本机'))}
${tr('离线')}
${esc(entry.error||tr('连接失败'))}
`;const s=entry.status,y=s.system||{},n=s.network||{},d=s.display||{},v=s.device||{},m=s.machine||h,signal=n.signal_percent,memUsed=y.memory_used_bytes,memTotal=y.memory_total_bytes,diskUsed=y.disk_used_bytes,diskTotal=y.disk_total_bytes;return`

${esc(m.name||h.name||m.id)}

ID ${esc(m.id||h.id)}${LANG==='zh'?'主机名':'Hostname'} ${esc(m.hostname||v.hostname||'--')}${esc(v.model||'--')}${LANG==='zh'?'序列号':'Serial'} ${esc(v.serial||'--')}${LANG==='zh'?'硬件版本':'Revision'} ${esc(v.revision||'--')}${esc(v.os||'--')}${LANG==='zh'?'内核':'Kernel'} ${esc(v.kernel||'--')}${esc(v.architecture||'--')} · CPU ${esc(v.cpu_count||'--')}${LANG==='zh'?'程序版本':'Agent'} ${esc(s.version||'--')}
${tr('在线')}
${tr('处理器负载')}
${esc(y.cpu_percent)}%
${LANG==='zh'?'频率':'Frequency'} ${esc(y.cpu_freq_mhz)} MHz · ${esc(y.temperature_c)}°C · ${LANG==='zh'?'风扇':'Fan'} ${esc(y.fan_name)}
${tr('内存占用')}
${esc(y.memory_percent)}%
${meter(y.memory_percent)}
${bytes(memUsed)} / ${bytes(memTotal)} · ${LANG==='zh'?'可用':'Available'} ${bytes(y.memory_available_bytes)}
${tr('磁盘占用')}
${esc(y.disk_percent)}%
${meter(y.disk_percent)}
${bytes(diskUsed)} / ${bytes(diskTotal)} · ${LANG==='zh'?'剩余':'Free'} ${bytes(y.disk_free_bytes)}
${tr('主网络')}
${n.kind==='WIF'&&signal!==null&&signal!==undefined?`${esc(signal)}%`:esc(n.kind||'--')}
${n.kind==='WIF'?meter(signal):''}
${esc(n.interface||'--')} · ${n.kind==='WIF'?`${esc(n.metric)} dBm · `:''}${esc(n.ip_label)} ${esc(n.ip)} · ${n.internet?(LANG==='zh'?'互联网正常':'Internet online'):(LANG==='zh'?'互联网断开':'Internet down')}
${tr('显示状态')}
${esc(ownerName(d.owner))}
OLED: ${esc(ownerName(d.oled_page))} · RGB: ${esc(rgbName(d.rgb_mode))}
${tr('当前告警')}
${(d.alerts||[]).length}
${(d.alerts||[]).map(a=>esc(ownerName(a.id))).join(' · ')||tr('无告警')}

${tr('服务与进程监控')}

${(s.watches||[]).map(w=>`
${esc(w.name)} · ${esc(w.target)}${tr(w.up?'正常':'停止')}
`).join('')||`
${tr('暂无数据')}
`}
`} -async function loadStatus(){try{const fleet=await get('/api/v1/fleet/status'),online=fleet.hosts.filter(x=>x.online);$('dot').classList.toggle('ok',online.length>0);$('liveText').textContent=LANG==='zh'?`${online.length}/${fleet.hosts.length} 在线`:`${online.length}/${fleet.hosts.length} online`;$('identity').textContent=LANG==='zh'?`多机监控 · ${fleet.hosts.length} 台设备 · ${new Date(fleet.timestamp*1000).toLocaleTimeString()}`:`Fleet monitoring · ${fleet.hosts.length} hosts · ${new Date(fleet.timestamp*1000).toLocaleTimeString()}`;$('hostCards').innerHTML=fleet.hosts.map(hostCard).join('');fleetHosts=fleet.hosts.map(x=>x.host);refreshHostSelectors()}catch(e){$('dot').classList.remove('ok');$('liveText').textContent=tr('离线');$('identity').textContent=e.message}} +function renderHostCards(entries){const root=$('hostCards'),seen=new Set;entries.forEach((entry,index)=>{const id=String(entry.host.id),template=document.createElement('template');template.innerHTML=hostCard(entry);const next=template.content.firstElementChild;next.dataset.hostId=id;let current=[...root.children].find(x=>x.dataset.hostId===id);if(current){current.className=next.className;current.innerHTML=next.innerHTML;if(root.children[index]!==current)root.insertBefore(current,root.children[index]||null)}else root.insertBefore(next,root.children[index]||null);seen.add(id)});[...root.children].forEach(x=>{if(!seen.has(x.dataset.hostId))x.remove()})} +async function loadStatus(){try{const fleet=await get('/api/v1/fleet/status'),online=fleet.hosts.filter(x=>x.online);$('dot').classList.toggle('ok',online.length>0);$('liveText').textContent=LANG==='zh'?`${online.length}/${fleet.hosts.length} 在线`:`${online.length}/${fleet.hosts.length} online`;$('identity').textContent=LANG==='zh'?`多机监控 · ${fleet.hosts.length} 台设备 · ${new Date(fleet.timestamp*1000).toLocaleTimeString()}`:`Fleet monitoring · ${fleet.hosts.length} hosts · ${new Date(fleet.timestamp*1000).toLocaleTimeString()}`;renderHostCards(fleet.hosts);fleetHosts=fleet.hosts.map(x=>x.host);refreshHostSelectors()}catch(e){$('dot').classList.remove('ok');$('liveText').textContent=tr('离线');$('identity').textContent=e.message}} const severityNames={DEBUG:'调试',INFO:'信息',NOTICE:'注意',WARN:'警告',ERROR:'错误',CRITICAL:'严重',ALERT:'紧急',EMERGENCY:'紧急'};let logState={sort:'timestamp',order:'desc',offset:0,limit:100,total:0}; function localDateValue(d){return`${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`} function setLogRange(range){const now=new Date(),today=new Date(now.getFullYear(),now.getMonth(),now.getDate()),start=new Date(today),end=new Date(today);if(range==='all'){$('logStart').value='';$('logEnd').value='';return}if(range==='yesterday'){start.setDate(start.getDate()-1);end.setDate(end.getDate()-1)}else if(range==='week'){start.setDate(start.getDate()-((start.getDay()+6)%7))}else if(range==='month'){start.setDate(1)}$('logStart').value=localDateValue(start);$('logEnd').value=localDateValue(end)}