mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 09:38:02 +00:00
fix: 修复API Keys页面时间窗口进度条和Token数值显示问题
- 修复时间窗口限制的请求次数和Token使用量进度条不更新的问题 - 在apiKeyService.getAllApiKeys()中添加获取当前窗口统计数据的逻辑 - 从Redis读取rate_limit:requests和rate_limit:tokens键的值 - 优化Token数值展示,添加K/M单位格式化 - UsageDetailModal组件中5处Token数值改用formatTokenCount - ApiKeysView模型统计中5处Token数值改用formatTokenCount - 统一使用K/M单位简化大数字显示 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -192,6 +192,7 @@ class ApiKeyService {
|
|||||||
async getAllApiKeys() {
|
async getAllApiKeys() {
|
||||||
try {
|
try {
|
||||||
const apiKeys = await redis.getAllApiKeys();
|
const apiKeys = await redis.getAllApiKeys();
|
||||||
|
const client = redis.getClientSafe();
|
||||||
|
|
||||||
// 为每个key添加使用统计和当前并发数
|
// 为每个key添加使用统计和当前并发数
|
||||||
for (const key of apiKeys) {
|
for (const key of apiKeys) {
|
||||||
@@ -207,6 +208,19 @@ class ApiKeyService {
|
|||||||
key.permissions = key.permissions || 'all'; // 兼容旧数据
|
key.permissions = key.permissions || 'all'; // 兼容旧数据
|
||||||
key.dailyCostLimit = parseFloat(key.dailyCostLimit || 0);
|
key.dailyCostLimit = parseFloat(key.dailyCostLimit || 0);
|
||||||
key.dailyCost = await redis.getDailyCost(key.id) || 0;
|
key.dailyCost = await redis.getDailyCost(key.id) || 0;
|
||||||
|
|
||||||
|
// 获取当前时间窗口的请求次数和Token使用量
|
||||||
|
if (key.rateLimitWindow > 0) {
|
||||||
|
const requestCountKey = `rate_limit:requests:${key.id}`;
|
||||||
|
const tokenCountKey = `rate_limit:tokens:${key.id}`;
|
||||||
|
|
||||||
|
key.currentWindowRequests = parseInt(await client.get(requestCountKey) || '0');
|
||||||
|
key.currentWindowTokens = parseInt(await client.get(tokenCountKey) || '0');
|
||||||
|
} else {
|
||||||
|
key.currentWindowRequests = 0;
|
||||||
|
key.currentWindowTokens = 0;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
key.restrictedModels = key.restrictedModels ? JSON.parse(key.restrictedModels) : [];
|
key.restrictedModels = key.restrictedModels ? JSON.parse(key.restrictedModels) : [];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -46,10 +46,10 @@
|
|||||||
<i class="fas fa-coins text-green-500" />
|
<i class="fas fa-coins text-green-500" />
|
||||||
</div>
|
</div>
|
||||||
<div class="text-2xl font-bold text-gray-900">
|
<div class="text-2xl font-bold text-gray-900">
|
||||||
{{ formatNumber(totalTokens) }}
|
{{ formatTokenCount(totalTokens) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-xs text-gray-600 mt-1">
|
<div class="text-xs text-gray-600 mt-1">
|
||||||
今日: {{ formatNumber(dailyTokens) }}
|
今日: {{ formatTokenCount(dailyTokens) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@
|
|||||||
<span class="text-sm text-gray-600">输入 Token</span>
|
<span class="text-sm text-gray-600">输入 Token</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="text-sm font-semibold text-gray-900">
|
<span class="text-sm font-semibold text-gray-900">
|
||||||
{{ formatNumber(inputTokens) }}
|
{{ formatTokenCount(inputTokens) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
@@ -108,7 +108,7 @@
|
|||||||
<span class="text-sm text-gray-600">输出 Token</span>
|
<span class="text-sm text-gray-600">输出 Token</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="text-sm font-semibold text-gray-900">
|
<span class="text-sm font-semibold text-gray-900">
|
||||||
{{ formatNumber(outputTokens) }}
|
{{ formatTokenCount(outputTokens) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -120,7 +120,7 @@
|
|||||||
<span class="text-sm text-gray-600">缓存创建 Token</span>
|
<span class="text-sm text-gray-600">缓存创建 Token</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="text-sm font-semibold text-purple-600">
|
<span class="text-sm font-semibold text-purple-600">
|
||||||
{{ formatNumber(cacheCreateTokens) }}
|
{{ formatTokenCount(cacheCreateTokens) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -132,7 +132,7 @@
|
|||||||
<span class="text-sm text-gray-600">缓存读取 Token</span>
|
<span class="text-sm text-gray-600">缓存读取 Token</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="text-sm font-semibold text-purple-600">
|
<span class="text-sm font-semibold text-purple-600">
|
||||||
{{ formatNumber(cacheReadTokens) }}
|
{{ formatTokenCount(cacheReadTokens) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -546,7 +546,7 @@
|
|||||||
<i class="fas fa-coins text-yellow-500 mr-1 text-xs" />
|
<i class="fas fa-coins text-yellow-500 mr-1 text-xs" />
|
||||||
总Token:
|
总Token:
|
||||||
</span>
|
</span>
|
||||||
<span class="font-semibold text-gray-900">{{ formatNumber(stat.allTokens) }}</span>
|
<span class="font-semibold text-gray-900">{{ formatTokenCount(stat.allTokens) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between items-center text-sm">
|
<div class="flex justify-between items-center text-sm">
|
||||||
<span class="text-gray-600 flex items-center">
|
<span class="text-gray-600 flex items-center">
|
||||||
@@ -561,14 +561,14 @@
|
|||||||
<i class="fas fa-arrow-down text-green-500 mr-1" />
|
<i class="fas fa-arrow-down text-green-500 mr-1" />
|
||||||
输入:
|
输入:
|
||||||
</span>
|
</span>
|
||||||
<span class="font-medium">{{ formatNumber(stat.inputTokens) }}</span>
|
<span class="font-medium">{{ formatTokenCount(stat.inputTokens) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between items-center text-xs text-gray-500">
|
<div class="flex justify-between items-center text-xs text-gray-500">
|
||||||
<span class="flex items-center">
|
<span class="flex items-center">
|
||||||
<i class="fas fa-arrow-up text-blue-500 mr-1" />
|
<i class="fas fa-arrow-up text-blue-500 mr-1" />
|
||||||
输出:
|
输出:
|
||||||
</span>
|
</span>
|
||||||
<span class="font-medium">{{ formatNumber(stat.outputTokens) }}</span>
|
<span class="font-medium">{{ formatTokenCount(stat.outputTokens) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="stat.cacheCreateTokens > 0"
|
v-if="stat.cacheCreateTokens > 0"
|
||||||
@@ -578,7 +578,7 @@
|
|||||||
<i class="fas fa-save mr-1" />
|
<i class="fas fa-save mr-1" />
|
||||||
缓存创建:
|
缓存创建:
|
||||||
</span>
|
</span>
|
||||||
<span class="font-medium">{{ formatNumber(stat.cacheCreateTokens) }}</span>
|
<span class="font-medium">{{ formatTokenCount(stat.cacheCreateTokens) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="stat.cacheReadTokens > 0"
|
v-if="stat.cacheReadTokens > 0"
|
||||||
@@ -588,7 +588,7 @@
|
|||||||
<i class="fas fa-download mr-1" />
|
<i class="fas fa-download mr-1" />
|
||||||
缓存读取:
|
缓存读取:
|
||||||
</span>
|
</span>
|
||||||
<span class="font-medium">{{ formatNumber(stat.cacheReadTokens) }}</span>
|
<span class="font-medium">{{ formatTokenCount(stat.cacheReadTokens) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -623,7 +623,7 @@
|
|||||||
总请求: <span class="font-semibold text-gray-800">{{ apiKeyModelStats[key.id].reduce((sum, stat) => sum + stat.requests, 0) }}</span>
|
总请求: <span class="font-semibold text-gray-800">{{ apiKeyModelStats[key.id].reduce((sum, stat) => sum + stat.requests, 0) }}</span>
|
||||||
</span>
|
</span>
|
||||||
<span class="text-gray-600">
|
<span class="text-gray-600">
|
||||||
总Token: <span class="font-semibold text-gray-800">{{ formatNumber(apiKeyModelStats[key.id].reduce((sum, stat) => sum + stat.allTokens, 0)) }}</span>
|
总Token: <span class="font-semibold text-gray-800">{{ formatTokenCount(apiKeyModelStats[key.id].reduce((sum, stat) => sum + stat.allTokens, 0)) }}</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user