diff --git a/front/antigravity_credit_summary_preview.html b/front/antigravity_credit_summary_preview.html
new file mode 100644
index 000000000..8b11ef5b0
--- /dev/null
+++ b/front/antigravity_credit_summary_preview.html
@@ -0,0 +1,385 @@
+
+
+
+
+
+
+ Antigravity 总额度 UI 预览
+
+
+
+
+
+ Antigravity 总额度 UI 预览
+
+
+
+
+
+
+ 128,640
+ 启用号剩余积分
+
+
+ 8
+ 启用凭证
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/front/common.js b/front/common.js
index 12c75df94..2725de592 100644
--- a/front/common.js
+++ b/front/common.js
@@ -37,7 +37,12 @@ const AppState = {
usageStatsData: {},
// 冷却倒计时
- cooldownTimerInterval: null
+ cooldownTimerInterval: null,
+
+ // Antigravity total quota UI
+ antigravityCreditSummaryTimer: null,
+ antigravityCreditSummaryLoaded: false,
+ antigravityCreditSummaryLoading: false
};
// =====================================================================
@@ -1035,7 +1040,10 @@ function switchTab(tabName) {
// 标签页数据加载(从动画中分离出来)
function triggerTabDataLoad(tabName) {
if (tabName === 'manage') AppState.creds.refresh();
- if (tabName === 'antigravity-manage') AppState.antigravityCreds.refresh();
+ if (tabName === 'antigravity-manage') {
+ AppState.antigravityCreds.refresh();
+ startAntigravityCreditSummaryAutoRefresh(true);
+ }
if (tabName === 'config') loadConfig();
if (tabName === 'logs') connectWebSocket();
}
@@ -1455,7 +1463,215 @@ async function downloadAllCreds() {
}
// Antigravity凭证管理
-function refreshAntigravityCredsList() { AppState.antigravityCreds.refresh(); }
+function refreshAntigravityCredsList() {
+ AppState.antigravityCreds.refresh();
+ startAntigravityCreditSummaryAutoRefresh(false);
+ refreshAntigravityCreditSummary(true);
+}
+
+function getAntigravityCreditSummaryElement(id) {
+ return document.getElementById(id);
+}
+
+function setAntigravityCreditSummaryText(id, text) {
+ const element = getAntigravityCreditSummaryElement(id);
+ if (element) element.textContent = text;
+}
+
+function formatAntigravityCreditNumber(value) {
+ if (value === null || value === undefined || value === '' || Number.isNaN(Number(value))) {
+ return '--';
+ }
+
+ return Number(value).toLocaleString('zh-CN', {
+ maximumFractionDigits: 2
+ });
+}
+
+function formatAntigravityCreditPercent(value) {
+ if (value === null || value === undefined || value === '' || Number.isNaN(Number(value))) {
+ return '--%';
+ }
+
+ return `${Number(value).toLocaleString('zh-CN', {
+ maximumFractionDigits: 2
+ })}%`;
+}
+
+function formatAntigravitySummaryTime(timestamp) {
+ if (!timestamp) return '刚刚';
+
+ return new Date(timestamp * 1000).toLocaleTimeString('zh-CN', {
+ hour12: false,
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit'
+ });
+}
+
+function getAntigravityQuotaColor(percent) {
+ const safePercent = Number(percent);
+ if (safePercent >= 50) return '#28a745';
+ if (safePercent >= 20) return '#ffc107';
+ return '#dc3545';
+}
+
+function renderAntigravityCreditModelList(modelSummaries) {
+ const container = getAntigravityCreditSummaryElement('antigravityCreditModelList');
+ if (!container) return;
+
+ if (!Array.isArray(modelSummaries) || modelSummaries.length === 0) {
+ container.innerHTML = '暂无分模型额度数据
';
+ return;
+ }
+
+ container.innerHTML = modelSummaries.map(modelInfo => {
+ const percent = modelInfo.remaining_percent;
+ const safePercent = percent === null || percent === undefined
+ ? 0
+ : Math.max(0, Math.min(100, Number(percent)));
+ const percentText = formatAntigravityCreditPercent(percent);
+ const accountCount = modelInfo.account_count || 0;
+ const exhaustedAccounts = modelInfo.exhausted_accounts || 0;
+ const color = getAntigravityQuotaColor(safePercent);
+ const modelName = escapeHtml(modelInfo.model || 'unknown');
+
+ return `
+
+
+ ${modelName}
+ ${percentText}
+
+
+
覆盖 ${accountCount} 个启用号 · ${exhaustedAccounts} 个已耗尽
+
+ `;
+ }).join('');
+}
+
+function updateAntigravityCreditSummaryUI(data) {
+ const creditsText = formatAntigravityCreditNumber(data.total_remaining_credits);
+ const enabledAccounts = data.enabled_accounts || 0;
+ const creditAccounts = data.credit_accounts || 0;
+ const quotaAccounts = data.quota_accounts || 0;
+ const failedAccounts = data.failed_accounts || 0;
+
+ setAntigravityCreditSummaryText('antigravityCreditRemainingAmount', creditsText);
+ setAntigravityCreditSummaryText('antigravityCreditEnabledAccounts', enabledAccounts.toString());
+
+ if (enabledAccounts > 0) {
+ setAntigravityCreditSummaryText(
+ 'antigravityCreditSummaryCompact',
+ `${creditsText} 积分 · 启用 ${enabledAccounts} 个`
+ );
+ } else {
+ setAntigravityCreditSummaryText('antigravityCreditSummaryCompact', '没有启用凭证');
+ }
+
+ renderAntigravityCreditModelList(data.model_summaries || []);
+
+ const refreshTime = formatAntigravitySummaryTime(data.updated_at);
+ const metaParts = [
+ `启用 ${enabledAccounts} 个`,
+ `积分数据 ${creditAccounts} 个`,
+ `额度数据 ${quotaAccounts} 个`,
+ `刷新 ${refreshTime}`
+ ];
+ if (failedAccounts > 0) metaParts.push(`失败 ${failedAccounts} 个`);
+ setAntigravityCreditSummaryText('antigravityCreditSummaryMeta', metaParts.join(' · '));
+
+ const meta = getAntigravityCreditSummaryElement('antigravityCreditSummaryMeta');
+ if (meta && Array.isArray(data.errors) && data.errors.length > 0) {
+ meta.title = data.errors.map(item => `${item.filename}: ${item.error}`).join('\n');
+ } else if (meta) {
+ meta.removeAttribute('title');
+ }
+
+ AppState.antigravityCreditSummaryLoaded = true;
+}
+
+function setAntigravityCreditSummaryLoading(isLoading) {
+ AppState.antigravityCreditSummaryLoading = isLoading;
+ const refreshBtn = getAntigravityCreditSummaryElement('antigravityCreditSummaryRefreshBtn');
+ if (refreshBtn) {
+ refreshBtn.disabled = isLoading;
+ refreshBtn.textContent = isLoading ? '刷新中...' : '手动刷新';
+ }
+
+ if (isLoading && !AppState.antigravityCreditSummaryLoaded) {
+ setAntigravityCreditSummaryText('antigravityCreditSummaryCompact', '正在获取...');
+ setAntigravityCreditSummaryText('antigravityCreditSummaryMeta', '正在获取启用凭证额度...');
+ }
+}
+
+function toggleAntigravityCreditSummary() {
+ const body = getAntigravityCreditSummaryElement('antigravityCreditSummaryBody');
+ const card = getAntigravityCreditSummaryElement('antigravityCreditSummaryCard');
+ if (!body || !card) return;
+
+ const shouldOpen = body.style.display !== 'block';
+ body.style.display = shouldOpen ? 'block' : 'none';
+ card.classList.toggle('expanded', shouldOpen);
+ card.setAttribute('aria-expanded', shouldOpen ? 'true' : 'false');
+ setAntigravityCreditSummaryText('antigravityCreditSummaryToggleIcon', shouldOpen ? '收起' : '展开');
+
+ if (shouldOpen && !AppState.antigravityCreditSummaryLoaded) {
+ refreshAntigravityCreditSummary(false);
+ }
+}
+
+function startAntigravityCreditSummaryAutoRefresh(fetchNow = false) {
+ const card = getAntigravityCreditSummaryElement('antigravityCreditSummaryCard');
+ if (!card) return;
+
+ if (!AppState.antigravityCreditSummaryTimer) {
+ AppState.antigravityCreditSummaryTimer = setInterval(() => {
+ refreshAntigravityCreditSummary(true);
+ }, 10 * 60 * 1000);
+ }
+
+ if (fetchNow) {
+ refreshAntigravityCreditSummary(true);
+ }
+}
+
+async function refreshAntigravityCreditSummary(silent = false) {
+ const card = getAntigravityCreditSummaryElement('antigravityCreditSummaryCard');
+ if (!card || AppState.antigravityCreditSummaryLoading) return;
+
+ setAntigravityCreditSummaryLoading(true);
+
+ try {
+ const response = await fetch('./creds/antigravity-credit-summary', {
+ method: 'GET',
+ headers: getAuthHeaders()
+ });
+ const data = await response.json();
+
+ if (response.ok && data.success) {
+ updateAntigravityCreditSummaryUI(data);
+ if (!silent) showStatus('Antigravity 总额度已刷新', 'success');
+ } else {
+ const errorMsg = data.error || data.detail || '获取总额度失败';
+ setAntigravityCreditSummaryText('antigravityCreditSummaryCompact', '获取失败');
+ setAntigravityCreditSummaryText('antigravityCreditSummaryMeta', errorMsg);
+ if (!silent) showStatus(errorMsg, 'error');
+ }
+ } catch (error) {
+ setAntigravityCreditSummaryText('antigravityCreditSummaryCompact', '获取失败');
+ setAntigravityCreditSummaryText('antigravityCreditSummaryMeta', error.message);
+ if (!silent) showStatus(`获取总额度失败: ${error.message}`, 'error');
+ } finally {
+ setAntigravityCreditSummaryLoading(false);
+ }
+}
+
+window.toggleAntigravityCreditSummary = toggleAntigravityCreditSummary;
+window.refreshAntigravityCreditSummary = refreshAntigravityCreditSummary;
+window.startAntigravityCreditSummaryAutoRefresh = startAntigravityCreditSummaryAutoRefresh;
+
function applyAntigravityStatusFilter() { AppState.antigravityCreds.applyStatusFilter(); }
function changeAntigravityPage(direction) { AppState.antigravityCreds.changePage(direction); }
function changeAntigravityPageSize() { AppState.antigravityCreds.changePageSize(); }
diff --git a/front/control_panel.html b/front/control_panel.html
index 11bc986dd..3b1f96e08 100644
--- a/front/control_panel.html
+++ b/front/control_panel.html
@@ -638,6 +638,190 @@
box-shadow: 0 2px 8px rgba(23, 162, 184, 0.15);
}
+ .quota-summary-card {
+ background: #ffffff;
+ border: 1px solid #dce3ea;
+ border-left: 4px solid #17a2b8;
+ border-radius: 8px;
+ margin: 0 0 20px 0;
+ overflow: hidden;
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
+ }
+
+ .quota-summary-header {
+ width: 100%;
+ border: 0;
+ background: #f8fbfd;
+ color: #333;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
+ padding: 12px 16px;
+ text-align: left;
+ }
+
+ .quota-summary-title {
+ display: block;
+ font-size: 15px;
+ font-weight: 700;
+ }
+
+ .quota-summary-subtitle {
+ display: block;
+ color: #667085;
+ font-size: 12px;
+ margin-top: 3px;
+ }
+
+ .quota-summary-compact {
+ color: #0c5460;
+ font-size: 13px;
+ font-weight: 700;
+ white-space: nowrap;
+ }
+
+ .quota-summary-toggle {
+ color: #666;
+ font-size: 12px;
+ margin-left: 8px;
+ white-space: nowrap;
+ }
+
+ .quota-summary-body {
+ border-top: 1px solid #edf0f3;
+ padding: 14px 16px 16px;
+ }
+
+ .quota-summary-metrics {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 10px;
+ margin-bottom: 12px;
+ }
+
+ .quota-summary-metric {
+ background: #f8f9fa;
+ border-radius: 6px;
+ padding: 10px;
+ }
+
+ .quota-summary-metric strong {
+ color: #222;
+ display: block;
+ font-size: 22px;
+ line-height: 1.2;
+ word-break: break-word;
+ }
+
+ .quota-summary-metric span {
+ color: #667085;
+ display: block;
+ font-size: 12px;
+ margin-top: 4px;
+ }
+
+ .quota-model-list {
+ display: grid;
+ gap: 8px;
+ margin-top: 14px;
+ }
+
+ .quota-model-item {
+ background: #ffffff;
+ border: 1px solid #edf0f3;
+ border-radius: 6px;
+ padding: 10px;
+ }
+
+ .quota-model-row {
+ align-items: center;
+ display: flex;
+ gap: 10px;
+ justify-content: space-between;
+ }
+
+ .quota-model-name {
+ color: #333;
+ font-size: 13px;
+ font-weight: 700;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .quota-model-percent {
+ font-size: 13px;
+ font-weight: 700;
+ white-space: nowrap;
+ }
+
+ .quota-model-bar {
+ background: #e9ecef;
+ border-radius: 999px;
+ height: 7px;
+ margin: 8px 0 6px;
+ overflow: hidden;
+ }
+
+ .quota-model-fill {
+ height: 100%;
+ transition: width 0.25s ease;
+ width: 0;
+ }
+
+ .quota-model-meta,
+ .quota-model-empty {
+ color: #667085;
+ font-size: 12px;
+ }
+
+ .quota-summary-footer {
+ align-items: center;
+ display: flex;
+ gap: 10px;
+ justify-content: space-between;
+ margin-top: 10px;
+ }
+
+ .quota-summary-meta {
+ color: #667085;
+ font-size: 12px;
+ }
+
+ .quota-summary-refresh {
+ background: #17a2b8;
+ border: 0;
+ border-radius: 4px;
+ color: white;
+ cursor: pointer;
+ font-size: 13px;
+ padding: 7px 10px;
+ white-space: nowrap;
+ }
+
+ .quota-summary-refresh:disabled {
+ background: #9ab7c0;
+ cursor: not-allowed;
+ }
+
+ @media (max-width: 640px) {
+ .quota-summary-header,
+ .quota-summary-footer {
+ align-items: flex-start;
+ flex-direction: column;
+ }
+
+ .quota-summary-compact {
+ white-space: normal;
+ }
+
+ .quota-summary-metrics {
+ grid-template-columns: 1fr;
+ }
+ }
+
.manage-actions {
margin-bottom: 20px;
display: flex;
@@ -1870,6 +2054,40 @@ Antigravity凭证文件管理
+
+
+
+
+
+
+ --
+ 启用号剩余积分
+
+
+ 0
+ 启用凭证
+
+
+
+
+
+
+
@@ -2393,8 +2611,8 @@
📞 联系我们
-
+