@@ -21,7 +21,7 @@ document.getElementById("themeToggle").onclick = () =>
2121const state = {
2222 stations : [ ] , settings : { refreshIntervalSec : 60 , lowBalanceUsd : 5 } ,
2323 types : [ ] , channelTypes : [ ] , channels : [ ] , rules : { } ,
24- view : "dashboard" , user : null ,
24+ view : "dashboard" , user : null , app : null ,
2525 trendHours : 24 , overview : null , // 总览趋势图的时间范围与数据缓存 {hours, series, at}
2626} ;
2727let autoTimer = null ;
@@ -68,6 +68,13 @@ const api = {
6868const $ = ( s ) => document . querySelector ( s ) ;
6969const esc = ( s ) => String ( s ?? "" ) . replace ( / [ & < > " ' ] / g, ( c ) => ( { "&" : "&" , "<" : "<" , ">" : ">" , '"' : """ , "'" : "'" } [ c ] ) ) ;
7070const usd = ( n ) => "$" + Number ( n ?? 0 ) . toLocaleString ( "en-US" , { minimumFractionDigits : 2 , maximumFractionDigits : 2 } ) ;
71+ const fmtTokens = ( n ) => {
72+ n = Number ( n ) || 0 ;
73+ if ( n >= 1e9 ) return + ( n / 1e9 ) . toFixed ( 1 ) + "B" ;
74+ if ( n >= 1e6 ) return + ( n / 1e6 ) . toFixed ( 1 ) + "M" ;
75+ if ( n >= 1e3 ) return + ( n / 1e3 ) . toFixed ( 1 ) + "K" ;
76+ return String ( n ) ;
77+ } ;
7178const typeLabel = ( v ) => ( state . types . find ( ( t ) => t . value === v ) ?. label || v ) ;
7279
7380function threshold ( s ) {
@@ -180,6 +187,7 @@ function stationRow(s) {
180187 const pieces = [ ] ;
181188 if ( b && b . ok && s . todayUsed != null ) {
182189 pieces . push ( `<span>今日消耗 ${ s . todayIsEstimate ? "≈" : "" } ${ usd ( s . todayUsed ) } </span>` ) ;
190+ if ( s . todayTokens != null ) pieces . push ( `<span>${ fmtTokens ( s . todayTokens ) } tokens</span>` ) ;
183191 }
184192 if ( eta ) pieces . push ( `<span class="${ eta . cls } ">${ eta . text } </span>` ) ;
185193 if ( pieces . length ) pieces . push ( "<span>点击查看趋势</span>" ) ;
@@ -221,11 +229,19 @@ function renderDashboard() {
221229 const lowCount = list . filter ( ( s ) => [ "warn" , "danger" ] . includes ( statusOf ( s ) ) ) . length ;
222230 const errCount = list . filter ( ( s ) => statusOf ( s ) === "error" ) . length ;
223231
232+ // 今日 tokens / 请求数:只有 sub2api 站点能提供,有数据才显示
233+ const tokList = list . filter ( ( s ) => s . todayTokens != null ) ;
234+ const reqList = list . filter ( ( s ) => s . todayRequests != null ) ;
235+ const subBits = [ ] ;
236+ if ( tokList . length ) subBits . push ( `${ fmtTokens ( tokList . reduce ( ( a , s ) => a + s . todayTokens , 0 ) ) } tokens` ) ;
237+ if ( reqList . length ) subBits . push ( `${ reqList . reduce ( ( a , s ) => a + s . todayRequests , 0 ) . toLocaleString ( "en-US" ) } 次请求` ) ;
238+ const todaySub = subBits . length ? `<div class="stat-sub">${ subBits . join ( " · " ) } </div>` : "" ;
239+
224240 $ ( "#headerActions" ) . innerHTML = HDR_BTNS ;
225241 const stats = `
226242 <div class="stats stats-5">
227243 <div class="stat-card"><div class="label">总剩余余额</div><div class="value">${ usd ( totalRemaining ) } </div></div>
228- <div class="stat-card"><div class="label">今日总消耗</div><div class="value">${ todayApprox ? "≈ " : "" } ${ usd ( todayTotal ) } </div></div>
244+ <div class="stat-card"><div class="label">今日总消耗</div><div class="value">${ todayApprox ? "≈ " : "" } ${ usd ( todayTotal ) } </div>${ todaySub } </div>
229245 <div class="stat-card"><div class="label">日均消耗(估算)</div><div class="value">${ totalBurn > 0 ? usd ( totalBurn ) : "—" } </div></div>
230246 <div class="stat-card"><div class="label">低余额 / 耗尽</div><div class="value ${ lowCount ? "warn" : "" } ">${ lowCount } <small>个</small></div></div>
231247 <div class="stat-card"><div class="label">查询异常</div><div class="value ${ errCount ? "danger" : "" } ">${ errCount } <small>个</small></div></div>
@@ -570,7 +586,7 @@ function renderSettings() {
570586 </div>
571587 <div class="section-head" style="margin-top:20px"><h2>关于</h2></div>
572588 <div class="panel"><div class="st-row"><div class="st-main" style="cursor:default">
573- <div class="st-name">中转站余额监控</div>
589+ <div class="st-name">中转站余额监控${ state . app ? ` <span class="demo-tag">v ${ esc ( state . app . version ) } ${ state . app . commit ? " · " + esc ( state . app . commit ) : "" } </span>` : "" } </div>
574590 <div class="st-meta">支持 New API(访问令牌 / sk 密钥)与 Sub2API(登录令牌 / 账号密码自动续期)。界面基于 app-shell-ui 设计语言构建。凭证仅存储于本机 data/ 目录。</div>
575591 </div></div></div>` ;
576592
@@ -609,7 +625,8 @@ function render() {
609625 else if ( state . view === "stations" ) renderStations ( ) ;
610626 else if ( state . view === "notify" ) renderNotify ( ) ;
611627 else renderSettings ( ) ;
612- $ ( "#lastSync" ) . textContent = "自动刷新:每 " + state . settings . refreshIntervalSec + " 秒" ;
628+ const ver = state . app ? `v${ state . app . version } ${ state . app . commit ? ` (${ state . app . commit } )` : "" } ` : "" ;
629+ $ ( "#lastSync" ) . innerHTML = `自动刷新:每 ${ state . settings . refreshIntervalSec } 秒${ ver ? `<br>${ esc ( ver ) } ` : "" } ` ;
613630}
614631
615632// ---- 中转站弹窗 --------------------------------------------------------------
@@ -768,7 +785,13 @@ async function openTrend(station) {
768785 const eta = etaText ( prediction ) ;
769786 $ ( "#trendStats" ) . innerHTML = `
770787 <div class="stat-card"><div class="label">当前余额</div><div class="value">${ b ?. ok ? usd ( b . remaining ) : "—" } </div></div>
771- <div class="stat-card"><div class="label">今日消耗</div><div class="value">${ station . todayUsed != null ? ( station . todayIsEstimate ? "≈ " : "" ) + usd ( station . todayUsed ) : "—" } </div></div>
788+ <div class="stat-card"><div class="label">今日消耗</div><div class="value">${ station . todayUsed != null ? ( station . todayIsEstimate ? "≈ " : "" ) + usd ( station . todayUsed ) : "—" } </div>${
789+ station . todayTokens != null || station . todayRequests != null
790+ ? `<div class="stat-sub">${ [
791+ station . todayTokens != null ? fmtTokens ( station . todayTokens ) + " tokens" : null ,
792+ station . todayRequests != null ? station . todayRequests . toLocaleString ( "en-US" ) + " 次" : null ,
793+ ] . filter ( Boolean ) . join ( " · " ) } </div>` : ""
794+ } </div>
772795 <div class="stat-card"><div class="label">日均消耗(估算)</div><div class="value">${ prediction ?. burnPerDay > 0 ? usd ( prediction . burnPerDay ) : "—" } </div></div>
773796 <div class="stat-card"><div class="label">预计耗尽</div><div class="value ${ eta ?. cls || "" } ">${ prediction ?. etaDays != null ? fmtEtaText ( prediction . etaDays ) : "—" } </div></div>` ;
774797 drawChart ( $ ( "#trendChart" ) , points , prediction ) ;
@@ -1041,6 +1064,7 @@ async function bootData() {
10411064 state . channelTypes = meta . channelTypes ;
10421065 state . settings = meta . settings ;
10431066 state . rules = meta . rules ;
1067+ state . app = meta . app || null ;
10441068 await Promise . all ( [ reload ( ) , loadNotifications ( ) ] ) ;
10451069 render ( ) ;
10461070 startAuto ( ) ;
0 commit comments