diff --git a/cmd/client/main.go b/cmd/client/main.go index 3de857b..7bb8670 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -142,6 +142,7 @@ type GPUInfo struct { CoreClock float64 `json:"core_clock_mhz"` MemClock float64 `json:"mem_clock_mhz"` Power float64 `json:"power_watts"` + FanSpeed float64 `json:"fan_speed"` } // ═══════════════════════════════════════════════ @@ -1085,7 +1086,7 @@ func tryNvidiaSMI() []GPUInfo { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() out, err := exec.CommandContext(ctx, "nvidia-smi", - "--query-gpu=index,name,memory.total,memory.used,memory.free,temperature.gpu,utilization.gpu,clocks.current.graphics,clocks.current.memory,power.draw", + "--query-gpu=index,name,memory.total,memory.used,memory.free,temperature.gpu,utilization.gpu,clocks.current.graphics,clocks.current.memory,power.draw,fan.speed", "--format=csv,noheader,nounits", ).Output() if err != nil { @@ -1109,6 +1110,7 @@ func tryNvidiaSMI() []GPUInfo { CoreClock: parseFloat(parts[7]), MemClock: parseFloat(parts[8]), Power: parseFloat(parts[9]), + FanSpeed: parseFloat(parts[10]), }) } return gpus diff --git a/cmd/server/templates/index.html b/cmd/server/templates/index.html index bfa69a8..b16878c 100644 --- a/cmd/server/templates/index.html +++ b/cmd/server/templates/index.html @@ -678,60 +678,59 @@ } /* ═══ GPU ═══ */ - .gpu-item { - background: rgba(0, 0, 0, .18); - border-radius: 8px; - padding: 10px 12px + .gpu-table-wrap { + overflow-x: auto } - .gpu-item + .gpu-item { - margin-top: 6px - } - - .gpu-hdr { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 6px - } - - .gpu-nm { - font-size: 12px; - font-weight: 500 - } - - .gpu-tmp { - font-family: var(--mono); + .gpu-table { + width: 100%; + border-collapse: collapse; font-size: 11px; - font-weight: 500 + font-family: var(--mono) } - .gpu-rows { - display: grid; - grid-template-columns:1fr 1fr; - gap: 4px 14px; - font-size: 11px + .gpu-table th { + text-align: left; + font-size: 9px; + font-weight: 600; + letter-spacing: .8px; + text-transform: uppercase; + color: var(--dim); + padding: 6px 8px; + border-bottom: 1px solid var(--border); + white-space: nowrap } - .gr { - display: flex; - flex-direction: column; - gap: 1px + .gpu-table td { + padding: 7px 8px; + border-bottom: 1px solid rgba(30, 37, 58, .5); + white-space: nowrap } - .gr-l { + .gpu-table tr:last-child td { + border-bottom: none + } + + .gpu-table tr:hover td { + background: rgba(0, 229, 160, .03) + } + + .gpu-idx { color: var(--dim); font-size: 10px } - .gr-v { - font-family: var(--mono); - font-weight: 500 + .gpu-nm { + font-family: var(--font); + font-weight: 500; + font-size: 11px } - .gpu-vram { - grid-column: 1/-1; - margin-top: 4px + .gpu-vram-cell { + display: flex; + flex-direction: column; + gap: 3px; + min-width: 80px } /* ═══ Mining ═══ */ @@ -1418,20 +1417,34 @@ function buildGPU(gpus, infoGPUs, isOn) { var list = isOn ? gpus : (infoGPUs || []); if (!list.length) return '
| # | \u578B\u53F7 | \u8D1F\u8F7D | \u6E29\u5EA6 | \u529F\u8017 | \u6838\u5FC3 | \u663E\u5B58 | \u663E\u5B58\u7528\u91CF | \u98CE\u6247 | ' + + '|
|---|---|---|---|---|---|---|---|---|---|
| ' + (i + 1) + ' | ' + + '' + esc(g.name || 'N/A') + ' | ' + + '' + gl.toFixed(0) + '% | ' + + '' + tT(tmp > 0 ? tmp : null) + ' | ' + + '' + Math.round(pwr) + ' W | ' + + '' + Math.round(cc) + ' MHz | ' + + '' + Math.round(mc) + ' MHz | '; if (vt > 0) { var vp = vu / vt * 100; - h += '' + (vu / 1024).toFixed(1) + '/' + (vt / 1024).toFixed(1) + 'G'
+ + ' | ';
+ } else {
+ h += '\u2014 | '; } - h += ''; + h += '' + (fan > 0 ? Math.round(fan) + '%' : '\u2014') + ' | '; + h += '