From faaa68cae1d34c1cf79a046bfb8de4fede991296 Mon Sep 17 00:00:00 2001 From: dsh Date: Mon, 17 Aug 2026 23:25:58 -0400 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=8D=95=E4=BD=8D=E5=88=87=E6=8D=A2?= =?UTF-8?q?=E6=8C=89=E9=92=AE=EF=BC=88Mbps=20/=20MB/s=EF=BC=8C=E4=BB=85?= =?UTF-8?q?=E5=BD=B1=E5=93=8D=E6=98=BE=E7=A4=BA=EF=BC=8C=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93=E4=BB=8D=E5=AD=98=20Mbps=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/web/templates/index.html | 82 ++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 7 deletions(-) diff --git a/internal/web/templates/index.html b/internal/web/templates/index.html index b77cdcb..0745853 100644 --- a/internal/web/templates/index.html +++ b/internal/web/templates/index.html @@ -63,8 +63,25 @@ #startBtn:hover { transform: translateY(-1px); filter: brightness(1.08); } #startBtn:disabled { opacity: .55; cursor: not-allowed; transform: none; } + /* ---------- 单位切换 ---------- */ + .toolbar { display: flex; justify-content: flex-end; margin-top: 16px; } + .unit-switch { + display: inline-flex; gap: 2px; padding: 3px; + background: var(--card); border: 1px solid var(--border); border-radius: 999px; + } + .unit-btn { + padding: 5px 16px; font-size: 13px; color: var(--muted); + background: transparent; border: none; border-radius: 999px; + cursor: pointer; transition: all .15s; + } + .unit-btn:hover { color: var(--text); } + .unit-btn.active { + color: #06121f; font-weight: 700; + background: linear-gradient(90deg, var(--accent1), var(--accent2)); + } + /* ---------- 统计卡片 ---------- */ - .stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-top: 18px; } + .stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-top: 12px; } .stat { background: var(--card); border: 1px solid var(--border); border-radius: 14px; padding: 16px 10px; text-align: center; @@ -160,6 +177,14 @@ + +
+
+ + +
+
+
@@ -221,6 +246,44 @@ const statUpload = document.getElementById('statUpload'); let running = false; let gaugeMode = 'speed'; // speed | latency +/* ================= 单位切换 ================= + * 显示单位:Mbps(兆比特/秒,默认)或 MB/s(兆字节/秒 = Mbps ÷ 8) + * 数据库始终以 Mbps 存储,仅影响显示。 + */ +let unit = localStorage.getItem('speedtest_unit') === 'MB/s' ? 'MB/s' : 'Mbps'; +let lastGaugeMbps = 0; // 仪表盘当前速率(Mbps 原值) +let lastResult = null; // 最近一次测速结果(Mbps 原值) + +function fmtSpeed(mbps) { + const v = unit === 'MB/s' ? mbps / 8 : mbps; + return v.toFixed(2); +} + +function updateUnitButtons() { + document.querySelectorAll('.unit-btn').forEach(b => { + b.classList.toggle('active', b.dataset.unit === unit); + }); +} + +// 切换单位后刷新所有速度显示(仪表盘 / 统计卡 / 排行榜) +function refreshSpeedDisplays() { + if (gaugeMode === 'speed') updateGaugeSpeed(lastGaugeMbps); + if (lastResult) { + statDownload.textContent = fmtSpeed(lastResult.download); + statUpload.textContent = fmtSpeed(lastResult.upload); + } + loadRankings(false); +} + +document.querySelectorAll('.unit-btn').forEach(b => { + b.addEventListener('click', () => { + unit = b.dataset.unit; + localStorage.setItem('speedtest_unit', unit); + updateUnitButtons(); + refreshSpeedDisplays(); + }); +}); + /* ================= 仪表盘 ================= */ function drawGauge(frac) { const ctx = gauge.getContext('2d'); @@ -267,8 +330,10 @@ function speedFrac(mbps) { function updateGaugeSpeed(mbps) { gaugeMode = 'speed'; - gaugeValue.textContent = (mbps >= 100 ? mbps.toFixed(0) : mbps.toFixed(1)); - gaugeUnit.textContent = 'Mbps'; + lastGaugeMbps = mbps; + const v = unit === 'MB/s' ? mbps / 8 : mbps; + gaugeValue.textContent = (v >= 100 ? v.toFixed(0) : v.toFixed(1)); + gaugeUnit.textContent = unit; drawGauge(speedFrac(mbps)); } @@ -550,8 +615,8 @@ function renderRanking(rows) { '' + r.rank + '' + '' + user + (r.is_mine ? '我的成绩' : '') + '' + '' + r.latency_ms.toFixed(1) + ' ms' + - '' + r.download_mbps.toFixed(2) + ' Mbps' + - '' + r.upload_mbps.toFixed(2) + ' Mbps' + + '' + fmtSpeed(r.download_mbps) + ' ' + unit + '' + + '' + fmtSpeed(r.upload_mbps) + ' ' + unit + '' + '' + r.created_at + '' + ''; }).join(''); @@ -606,14 +671,16 @@ async function runTest() { // 2. 下载(固定 10 秒) setPhase('下载测速准备中…'); const download = await downloadTest(); - statDownload.textContent = download.toFixed(2); + lastResult = { download, upload: 0 }; + statDownload.textContent = fmtSpeed(download); updateGaugeSpeed(download); markDone(document.getElementById('cardDownload')); // 3. 上传(固定 10 秒) setPhase('上传测速准备中…'); const upload = await uploadTest(); - statUpload.textContent = upload.toFixed(2); + lastResult = { download, upload }; + statUpload.textContent = fmtSpeed(upload); updateGaugeSpeed(upload); markDone(document.getElementById('cardUpload')); @@ -640,6 +707,7 @@ startBtn.addEventListener('click', runTest); /* ================= 初始化 ================= */ drawGauge(0); +updateUnitButtons(); updateSortHeaders(); loadRankings(false);