@@ -431,17 +431,18 @@ def _build_favicon() -> bytes:
431431 .session-table tr.row-detail.open { display: table-row; }
432432 .session-table tr.row-detail td { padding: 0; }
433433 .detail-card {
434- padding: 14px 20px; margin: 4px 0;
435- background: rgba(18,22,30,.9); border: 1px solid var(--border);
436- border-radius: 10px; display: grid;
437- grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
438- gap: 10px 24px; font-size: 13px;
434+ padding: 16px 24px; margin: 6px 0;
435+ background: linear-gradient(135deg, rgba(30,37,54,.95), rgba(22,28,40,.95));
436+ border: 1px solid rgba(88,166,255,.15); border-radius: 12px;
437+ display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
438+ gap: 14px 28px; font-size: 13px;
439+ box-shadow: 0 4px 16px rgba(0,0,0,.3);
439440 }
440441 .detail-card .detail-item { display: flex; flex-direction: column; gap: 2px; }
441442 .detail-card .detail-label { font-size: 11px; color: var(--text-tertiary); text-transform: uppercase; letter-spacing: .3px; }
442443 .detail-card .detail-value { color: var(--text-primary); line-height: 1.4; word-break: break-all; }
443444 .session-table tbody tr[data-row]:not(.row-detail) { cursor: pointer; }
444- .success-bar { width: 56px; height: 4px; border-radius: 2px; background: rgba(255,255,255,.06 ); display: inline-block; vertical-align: middle; margin-left: 6px; }
445+ .success-bar { width: 56px; height: 4px; border-radius: 2px; background: rgba(255,255,255,.12 ); display: inline-block; vertical-align: middle; margin-left: 6px; }
445446 .success-bar-fill { height: 100%; border-radius: 2px; }
446447 /* ── Vendor Bind 选择器 ── */
447448 .bind-select {
@@ -551,7 +552,7 @@ def _build_favicon() -> bytes:
551552 <div class="header-right">
552553 <nav class="tabs" role="tablist" aria-label="Dashboard sections">
553554 <button type="button" class="tab-btn active" id="tab-btn-overview" role="tab" aria-controls="tab-pane-overview" aria-selected="true" data-tab="overview" onclick="switchTab('overview')">Overview</button>
554- <button type="button" class="tab-btn" id="tab-btn-sessions" role="tab" aria-controls="tab-pane-sessions" aria-selected="false" data-tab="sessions" onclick="switchTab('sessions')">Recent Active Sessions</button>
555+ <button type="button" class="tab-btn" id="tab-btn-sessions" role="tab" aria-controls="tab-pane-sessions" aria-selected="false" data-tab="sessions" onclick="switchTab('sessions')">Sessions</button>
555556 </nav>
556557 <span class="refresh-time" id="refresh-time">正在加载…</span>
557558 <button class="btn-refresh" onclick="refresh()">⟳ 刷新</button>
@@ -652,12 +653,12 @@ def _build_favicon() -> bytes:
652653 </div>
653654 </section>
654655
655- <!-- Recent Active Sessions 页签 -->
656+ <!-- Sessions 页签 -->
656657 <section class="tab-pane" id="tab-pane-sessions" role="tabpanel" aria-labelledby="tab-btn-sessions" data-tab="sessions">
657- <!-- Recent Active Sessions -->
658+ <!-- Sessions -->
658659 <div class="card sessions-card">
659660 <div class="card-title">
660- <span>Recent Active Sessions</span>
661+ <span>Sessions</span>
661662 <span style="font-size:12px;color:var(--text-tertiary)" id="sessions-subtitle">Last 24h</span>
662663 </div>
663664 <div class="session-table-wrap" id="sessions-table-wrap">
@@ -743,7 +744,8 @@ def _build_favicon() -> bytes:
743744 return String(n);
744745}
745746function fmtNum(n) { return n == null ? '–' : n.toLocaleString(); }
746- function copyText(btn, text) {
747+ function copyFromParent(btn) {
748+ var text = btn.parentElement.getAttribute('data-key') || btn.parentElement.getAttribute('title') || '';
747749 navigator.clipboard.writeText(text).then(function() {
748750 btn.classList.add('copied');
749751 btn.textContent = '✓';
@@ -1571,9 +1573,9 @@ def _build_favicon() -> bytes:
15711573 var sr = s.success_rate != null ? Math.round(s.success_rate) : null;
15721574 return '<tr data-row onclick="toggleRow(this)">' +
15731575 '<td class="session-key" onclick="event.stopPropagation()">' +
1574- '<div class="session-id" title="' + escapeHtml(s.session_key) + '">' +
1576+ '<div class="session-id" data-key="' + escapeHtml(s.session_key) + '" title="' + escapeHtml(s.session_key) + '">' +
15751577 '<span class="session-id-text">' + escapeHtml(parsed.session_id || s.session_key) + '</span>' +
1576- '<button class="copy-btn" onclick="copyText (this, \' ' + escapeHtml(s.session_key) + ' \' )" title="Copy Session ID">⧉</button>' +
1578+ '<button class="copy-btn" onclick="copyFromParent (this)" title="Copy Session ID">⧉</button>' +
15771579 '</div>' +
15781580 '<div class="session-meta" title="device: ' + escapeHtml(parsed.device_id) + ' | account: ' + escapeHtml(parsed.account_uuid) + '">' +
15791581 'dev:' + escapeHtml(shortId(parsed.device_id, 8)) + ' · acct:' + escapeHtml(shortId(parsed.account_uuid, 8)) +
@@ -1672,7 +1674,7 @@ def _build_favicon() -> bytes:
16721674let refreshing = false;
16731675let currentTab = 'overview';
16741676const tabLoaded = { overview: false, sessions: false };
1675- const TAB_LABELS = { overview: 'Overview', sessions: 'Recent Active Sessions' };
1677+ const TAB_LABELS = { overview: 'Overview', sessions: 'Sessions' };
16761678
16771679async function refreshOverview() {
16781680 const days = currentDays > 0 ? currentDays : 7;
@@ -1778,6 +1780,10 @@ def _build_favicon() -> bytes:
17781780 currentTab = initial;
17791781 applyTabState(initial);
17801782 syncTabUrl(initial);
1783+ // Load version immediately regardless of active tab
1784+ fetchJSON('/api/dashboard/summary?days=7').then(function(s) {
1785+ if (s && s.version) document.getElementById('version-badge').textContent = 'v' + s.version;
1786+ }).catch(function(){});
17811787 refresh(); // 仅加载初始页签的数据
17821788 setInterval(refresh, 600000); // 每 10 分钟刷新当前页签
17831789})();
0 commit comments