From aa47dd342dd0926c8031bd0e05d1fc9a9bd99999 Mon Sep 17 00:00:00 2001 From: tamakyi Date: Fri, 25 Sep 2026 21:14:59 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=EF=BC=9A=E9=80=89=E4=BA=86=E3=80=8C?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E3=80=8D=E5=8D=B4=E7=9C=8B=E4=B8=8D?= =?UTF-8?q?=E5=88=B0=E7=A0=81=E7=8E=87=E6=A1=86=EF=BC=88=E7=84=A6=E7=82=B9?= =?UTF-8?q?=E8=BF=98=E5=9C=A8=E4=B8=8B=E6=8B=89=E4=B8=8A=EF=BC=8C=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E4=B8=8D=E9=87=8D=E5=BB=BA=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 页面为了让定时刷新不冲掉用户正在填的内容,列表在「焦点还在列表里」时不重建。 但原生 select 选完一项后焦点会留在下拉上,于是选了「自定义」以后列表一直不重建, 那个码率框要等用户点到别处才出现 —— 看起来就是「选了自定义根本没地方填」。 - 选到「自定义」时当场把码率框建出来并聚焦(不用等服务端回来和下一次重建), 切走时当场收掉。 - 顺带把「不重建」的条件收紧成「只有正在列表里的文本框里打字时才跳过」: 下拉和勾选都是改完立即提交的,之前它们也会一直卡住重建, 连带「录播中/弹幕中」的徽标也要点到别处才刷新。 - 框里的初始值:填过自定义就用上次那个数(切走再切回来不会被改成当前档位), 没填过才用现在实际在用的那一档。 验证方式也换了:回归脚本里改用「点开下拉 + 键盘选最后一项」这种真实操作 (Playwright 的 select_option 不保留焦点,正是它让这个 bug 漏了过去), 新增「选完立刻就有框」「焦点直接落在框里」「切走即收掉」「切回带着上次的值」四条断言; verify_streamer_br.py 33 项、verify_qualities.py 全过,verify_settings.py / verify_danmu_match.py 无回归,go test ./...、gofmt、go vet 干净。 --- webui.go | 50 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/webui.go b/webui.go index a307943..a421198 100644 --- a/webui.go +++ b/webui.go @@ -746,8 +746,11 @@ async function refresh(){ }).join(""); var list = document.getElementById("st"); var sig = JSON.stringify(st.streamers); - // 数据没变化不重建;正在列表里操作时也跳过 - if(sig !== stSig && !list.contains(document.activeElement)){ + // 只有「正在列表里的文本框里打字」才跳过重建:下拉和勾选都是改完立即提交的, + // 一直卡着不重建会让「选了自定义该出现的码率框」「录播中的徽标」迟迟不刷新 + var ae = document.activeElement; + var typing = !!(ae && list.contains(ae) && ae.tagName === "INPUT" && ae.type !== "checkbox"); + if(sig !== stSig && !typing){ stSig = sig; // 重建前记下用户改过、还没提交的自定义码率,建完抄回去(填错的不用留) var keepNum = {}; @@ -1289,6 +1292,36 @@ async function delUid(uid){ if(!confirm("确定删除 uid " + uid + " 并停止其录制?")) return; post("/api/streamer/remove", {uid: uid}); } +// 选到「自定义」时当场把码率框建出来:列表在「正在文本框里打字」时不会重建, +// 光等服务端回来是看不到输入框的,用户会以为没地方填。顺带把焦点放进去,直接就能敲数字 +function showBrNum(row, sel, focus){ + var el = row.querySelector("input.brnum"); + if(el){ + if(focus){ el.focus(); el.select(); } + return el; + } + var uid = parseInt(sel.dataset.uid, 10); + var cur = (lastSt && lastSt.streamers ? lastSt.streamers : []).filter(function(s){ return s.uid === uid; })[0]; + el = document.createElement("input"); + el.type = "text"; + el.className = "brnum"; + el.dataset.uid = String(uid); + el.inputMode = "numeric"; + el.placeholder = "Kbps"; + el.title = "自定义:取不超过这个码率的最高档"; + // 初始值:填过自定义就用上次那个数(切走再切回来不该被改掉),没填过就用现在实际在用的那一档, + // 免得切过去的一瞬间变成最低档 + var v = cur ? (cur.bitrate || 0) : 0; + if(!(v > 0) && cur) v = cur.qualityBitrate || 0; + el.value = v; + sel.parentNode.insertBefore(el, sel.nextSibling); + if(focus){ el.focus(); el.select(); } + return el; +} +function hideBrNum(row){ + var el = row.querySelector("input.brnum"); + if(el && el.parentNode) el.parentNode.removeChild(el); +} // 读一行里选的档位:pref 是下拉的值;自定义时把输入框里的码率一起带上, // 输入框不在(刚切到自定义、或不是自定义)就不带 bitrate,服务端会保留原来填的值 function rowQuality(row){ @@ -1302,11 +1335,11 @@ function rowQuality(row){ v = parseInt(num.value.trim(), 10); if(isNaN(v) || v < 0) return null; }else{ - // 刚切到自定义、输入框还没建出来:用「现在实际用到的档位码率」当起点, - // 免得切过去的一瞬间掉到最低档(uid 可能还没设过自定义值) - var uid = parseInt(sel.dataset.uid, 10); - var cur = (lastSt && lastSt.streamers ? lastSt.streamers : []).filter(function(s){ return s.uid === uid; })[0]; - v = cur ? (cur.qualityBitrate || cur.bitrate || 0) : 0; + // 兜底:填过自定义就用上次那个数,没填过就用现在实际在用的那一档 + var uid0 = parseInt(sel.dataset.uid, 10); + var cur0 = (lastSt && lastSt.streamers ? lastSt.streamers : []).filter(function(s){ return s.uid === uid0; })[0]; + v = cur0 ? (cur0.bitrate || 0) : 0; + if(!(v > 0) && cur0) v = cur0.qualityBitrate || 0; } out.bitrate = v; } @@ -1328,6 +1361,9 @@ document.addEventListener("change", async function(e){ // 档位下拉是选完立即生效的(正在录制时会自动换档重录) var uid3 = parseInt(t.dataset.uid, 10); var row3 = t.closest(".row"); + // 选到「自定义」当场把码率框建出来并聚焦,切走就收掉(不依赖列表重建,见 showBrNum) + if(t.value === "custom") showBrNum(row3, t, true); + else hideBrNum(row3); var q3 = rowQuality(row3); if(!q3){ showMsg(false, "自定义档位的码率必须是大于等于 0 的数字"); return; } q3.uid = uid3;