diff --git a/src/routes/admin.js b/src/routes/admin.js index e908dfe1..7280af03 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -531,7 +531,34 @@ router.post('/claude-accounts/exchange-code', authenticateAdmin, async (req, res router.get('/claude-accounts', authenticateAdmin, async (req, res) => { try { const accounts = await claudeAccountService.getAllAccounts(); - res.json({ success: true, data: accounts }); + + // 为每个账户添加使用统计信息 + const accountsWithStats = await Promise.all(accounts.map(async (account) => { + try { + const usageStats = await redis.getAccountUsageStats(account.id); + return { + ...account, + usage: { + daily: usageStats.daily, + total: usageStats.total, + averages: usageStats.averages + } + }; + } catch (statsError) { + logger.warn(`⚠️ Failed to get usage stats for account ${account.id}:`, statsError.message); + // 如果获取统计失败,返回空统计 + return { + ...account, + usage: { + daily: { tokens: 0, requests: 0, allTokens: 0 }, + total: { tokens: 0, requests: 0, allTokens: 0 }, + averages: { rpm: 0, tpm: 0 } + } + }; + } + })); + + res.json({ success: true, data: accountsWithStats }); } catch (error) { logger.error('❌ Failed to get Claude accounts:', error); res.status(500).json({ error: 'Failed to get Claude accounts', message: error.message }); @@ -718,7 +745,18 @@ router.post('/gemini-accounts/exchange-code', authenticateAdmin, async (req, res router.get('/gemini-accounts', authenticateAdmin, async (req, res) => { try { const accounts = await geminiAccountService.getAllAccounts(); - res.json({ success: true, data: accounts }); + + // 为Gemini账户添加空的使用统计(暂时) + const accountsWithStats = accounts.map(account => ({ + ...account, + usage: { + daily: { tokens: 0, requests: 0, allTokens: 0 }, + total: { tokens: 0, requests: 0, allTokens: 0 }, + averages: { rpm: 0, tpm: 0 } + } + })); + + res.json({ success: true, data: accountsWithStats }); } catch (error) { logger.error('❌ Failed to get Gemini accounts:', error); res.status(500).json({ error: 'Failed to get accounts', message: error.message }); diff --git a/web/admin/app.js b/web/admin/app.js index be8421cd..41a4bbb1 100644 --- a/web/admin/app.js +++ b/web/admin/app.js @@ -192,6 +192,7 @@ const app = createApp({ // 账户 accounts: [], accountsLoading: false, + accountSortBy: 'dailyTokens', // 默认按今日Token排序 showCreateAccountModal: false, createAccountLoading: false, accountForm: { @@ -1868,6 +1869,9 @@ const app = createApp({ account.boundApiKeysCount = this.apiKeys.filter(key => key.geminiAccountId === account.id).length; } }); + + // 加载完成后自动排序 + this.sortAccounts(); } catch (error) { console.error('Failed to load accounts:', error); } finally { @@ -1875,6 +1879,35 @@ const app = createApp({ } }, + // 账户排序 + sortAccounts() { + if (!this.accounts || this.accounts.length === 0) return; + + this.accounts.sort((a, b) => { + switch (this.accountSortBy) { + case 'name': + return a.name.localeCompare(b.name); + case 'dailyTokens': + const aTokens = (a.usage && a.usage.daily && a.usage.daily.allTokens) || 0; + const bTokens = (b.usage && b.usage.daily && b.usage.daily.allTokens) || 0; + return bTokens - aTokens; // 降序 + case 'dailyRequests': + const aRequests = (a.usage && a.usage.daily && a.usage.daily.requests) || 0; + const bRequests = (b.usage && b.usage.daily && b.usage.daily.requests) || 0; + return bRequests - aRequests; // 降序 + case 'totalTokens': + const aTotalTokens = (a.usage && a.usage.total && a.usage.total.allTokens) || 0; + const bTotalTokens = (b.usage && b.usage.total && b.usage.total.allTokens) || 0; + return bTotalTokens - aTotalTokens; // 降序 + case 'lastUsed': + const aLastUsed = a.lastUsedAt ? new Date(a.lastUsedAt) : new Date(0); + const bLastUsed = b.lastUsedAt ? new Date(b.lastUsedAt) : new Date(0); + return bLastUsed - aLastUsed; // 降序(最近使用的在前) + default: + return 0; + } + }); + }, async loadModelStats() { this.modelStatsLoading = true; diff --git a/web/admin/index.html b/web/admin/index.html index 8003b1b3..656e8f39 100644 --- a/web/admin/index.html +++ b/web/admin/index.html @@ -922,12 +922,21 @@

账户管理

管理您的 Claude 和 Gemini 账户及代理配置

- +
+ + +
@@ -952,6 +961,7 @@ 类型 状态 代理 + 今日使用 最后使用 操作 @@ -1024,6 +1034,22 @@
无代理
+ +
+
+
+ {{ account.usage.daily.requests || 0 }} 次 +
+
+
+ {{ formatNumber(account.usage.daily.allTokens || 0) }} tokens +
+
+ 平均 {{ account.usage.averages.rpm.toFixed(2) }} RPM +
+
+
暂无数据
+ {{ account.lastUsedAt ? new Date(account.lastUsedAt).toLocaleDateString() : '从未使用' }}