fix(plugins): quota 页面加载时不再自动探测全部上游

首屏 19.1 秒 → 1.0 秒(生产实测)。

症状是"页面出来了但数据卡在加载"。量出来的原因不是渲染,也不是后端:
所有接口都在 0.4–2ms,而 Network 事件显示页面在头 70 毫秒内并发发出了 21 个
/api/plugins/quota/call/collect_source —— 每个源一次。CPU 采样 98% 空闲,说明
主线程不是在算,是在等。

插件页面的脚本里有 mount(); refresh();,而 refresh 会为每个源发一次探测。
探测要出网,且每次调用都持插件写锁,于是 21 次串行排队;冷启动实测 100 秒,
有缓存后 22 秒。WebUI 的首屏就这么被堵住了。

改动:
- 页面加载时不再自动探测。运维没要求的余额不值得用它换首屏。
- 改为先渲染上次的快照(pluginAPI.fetchState),标题栏标注"快照 HH:MM(点刷新
  取实时)"。点刷新才真探测。这样打开页面立刻有内容,实时数字在后面更新。
- billing 页面同样有 refresh(),但它只读本机 state(1.5ms),无害,保留。

判据:首屏填充时间实测 19.1s → 1.0s,且首屏请求里不再出现 collect_source。

Co-Authored-By: ModelRouter <noreply@modelrouter.dev>
This commit is contained in:
JianFeeeee
2026-10-04 11:11:16 +08:00
parent a6c6e6e5c7
commit c17a851ec1

View File

@ -682,6 +682,23 @@ PLUGIN.ui = {
if(meta.length) h+='<div class="qa-meta">'+meta.map(escH).join(" · ")+'</div>';
return h+"</div>";
}
// paintSnapshot renders the persisted snapshot WITHOUT touching the network.
// Called on load so the page has content immediately.
async function showSnapshot(){
try{
var st = await pluginAPI.fetchState("quota");
var rs = (st && st.reports) || [];
if(!rs.length) return false;
var real = rs.filter(function(r){ return r && !r.skipped; });
var skipped = rs.filter(function(r){ return r && r.skipped; }).map(function(r){ return r.name; });
render(real, skipped);
var sub=document.getElementById("qa-sub");
if(sub && st.updated_at){
sub.textContent = real.length+" 个源 · 快照 "+new Date(st.updated_at).toLocaleTimeString()+"(点刷新取实时)";
}
return true;
}catch(e){ return false; }
}
function render(reports, skipped){
var host=document.getElementById("qa-list"); if(!host) return;
var real=(reports||[]).filter(function(r){return !r.skipped;});
@ -754,7 +771,18 @@ PLUGIN.ui = {
var b=document.getElementById("qa-refresh");
if(b && !b.__qaWired){ b.__qaWired=true; b.addEventListener("click",refresh); }
}
mount(); refresh();
mount();
showSnapshot();
// Do NOT auto-refresh on load.
//
// Probing is network-bound and every request takes the plugin's write lock, so
// a page open that fires one call per source serialises them: measured 19s to
// first paint and 22-100s to finish, with the whole WebUI held in its loading
// state meanwhile. A balance the operator did not ask for is not worth the
// first paint of the page they opened.
//
// What IS shown automatically is the last snapshot, so an operator who hits
// refresh once sees a card immediately and a fresh number behind it.
if (window.pluginAPI && pluginAPI.onTabShown) pluginAPI.onTabShown(mount);
window.__qaRefresh=refresh; window.__qaRender=render;
})();