From d16b75293d7f46e4e9247f614cb1bc955319dda2 Mon Sep 17 00:00:00 2001 From: gaozitian Date: Sat, 24 Jan 2026 12:06:09 +0800 Subject: [PATCH] fix: optimize Claude Console quota exceeded status display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Keep account status as 'active' when quota exceeded (not 'quota_exceeded') - Keep isActive as true, only use quotaStoppedAt to mark quota exceeded - Show green status in UI for quota exceeded accounts (normal state) - Show '余额不足' as unschedulable reason instead of '已暂停' - Simplify resetDailyUsage() to only check quotaStoppedAt field Co-Authored-By: Claude Opus 4.5 --- src/services/claudeConsoleAccountService.js | 37 +++++---------------- web/admin-spa/package-lock.json | 2 +- web/admin-spa/src/views/AccountsView.vue | 29 +++++++++++++--- 3 files changed, 33 insertions(+), 35 deletions(-) diff --git a/src/services/claudeConsoleAccountService.js b/src/services/claudeConsoleAccountService.js index c0770f34..e6c25c24 100644 --- a/src/services/claudeConsoleAccountService.js +++ b/src/services/claudeConsoleAccountService.js @@ -1295,7 +1295,7 @@ class ClaudeConsoleAccountService { } // 检查是否已经因额度停用(避免重复操作) - if (!accountData.isActive && accountData.quotaStoppedAt) { + if (accountData.quotaStoppedAt) { return } @@ -1311,9 +1311,9 @@ class ClaudeConsoleAccountService { return // 已经被其他进程处理 } - // 超过额度,停用账户 + // 超过额度,停止调度但保持账户状态正常 + // 不修改 isActive 和 status,只用独立字段标记配额超限 const updates = { - isActive: false, quotaStoppedAt: new Date().toISOString(), errorMessage: `Daily quota exceeded: $${currentDailyCost.toFixed(2)} / $${dailyQuota.toFixed(2)}`, schedulable: false, // 停止调度 @@ -1321,13 +1321,6 @@ class ClaudeConsoleAccountService { quotaAutoStopped: 'true' } - // 只有当前状态是active时才改为quota_exceeded - // 如果是rate_limited等其他状态,保持原状态不变 - const currentStatus = await client.hget(accountKey, 'status') - if (currentStatus === 'active') { - updates.status = 'quota_exceeded' - } - await this.updateAccount(accountId, updates) logger.warn( @@ -1371,15 +1364,10 @@ class ClaudeConsoleAccountService { lastResetDate: today } - // 如果账户是因为超额被停用的,恢复账户 - // 注意:状态可能是 quota_exceeded 或 rate_limited(如果429错误时也超额了) - if ( - accountData.quotaStoppedAt && - accountData.isActive === false && - (accountData.status === 'quota_exceeded' || accountData.status === 'rate_limited') - ) { - updates.isActive = true - updates.status = 'active' + // 如果账户因配额超限被停用,恢复账户 + // 新逻辑:不再依赖 isActive === false 和 status 判断 + // 只要有 quotaStoppedAt 就说明是因配额超限被停止的 + if (accountData.quotaStoppedAt) { updates.errorMessage = '' updates.quotaStoppedAt = '' @@ -1389,16 +1377,7 @@ class ClaudeConsoleAccountService { updates.quotaAutoStopped = '' } - // 如果是rate_limited状态,也清除限流相关字段 - if (accountData.status === 'rate_limited') { - const client = redis.getClientSafe() - const accountKey = `${this.ACCOUNT_KEY_PREFIX}${accountId}` - await client.hdel(accountKey, 'rateLimitedAt', 'rateLimitStatus', 'rateLimitAutoStopped') - } - - logger.info( - `✅ Restored account ${accountId} after daily reset (was ${accountData.status})` - ) + logger.info(`✅ Restored account ${accountId} after daily quota reset`) } await this.updateAccount(accountId, updates) diff --git a/web/admin-spa/package-lock.json b/web/admin-spa/package-lock.json index 481df56a..7aa4b2e1 100644 --- a/web/admin-spa/package-lock.json +++ b/web/admin-spa/package-lock.json @@ -3789,7 +3789,7 @@ }, "node_modules/prettier-plugin-tailwindcss": { "version": "0.6.14", - "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.14.tgz", + "resolved": "https://registry.npmmirror.com/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.14.tgz", "integrity": "sha512-pi2e/+ZygeIqntN+vC573BcW5Cve8zUB0SSAGxqpB4f96boZF4M3phPVoOFCeypwkpRYdi7+jQ5YJJUwrkGUAg==", "dev": true, "license": "MIT", diff --git a/web/admin-spa/src/views/AccountsView.vue b/web/admin-spa/src/views/AccountsView.vue index 7147b3fd..b29960fd 100644 --- a/web/admin-spa/src/views/AccountsView.vue +++ b/web/admin-spa/src/views/AccountsView.vue @@ -4125,6 +4125,14 @@ const getSchedulableReason = (account) => { if (account.rateLimitStatus === 'limited') { return '触发限流(429错误)' } + // 检查配额超限状态(quotaAutoStopped 或 quotaStoppedAt 任一存在即表示配额超限) + if ( + account.quotaAutoStopped === 'true' || + account.quotaAutoStopped === true || + account.quotaStoppedAt + ) { + return '余额不足' + } if (account.status === 'blocked' && account.errorMessage) { return account.errorMessage } @@ -4203,6 +4211,15 @@ const getSchedulableReason = (account) => { return '手动停止调度' } +// 检查是否是配额超限状态(用于状态显示判断) +const isQuotaExceeded = (account) => { + return ( + account.quotaAutoStopped === 'true' || + account.quotaAutoStopped === true || + !!account.quotaStoppedAt + ) +} + // 获取账户状态文本 const getAccountStatusText = (account) => { // 检查是否被封锁 @@ -4221,9 +4238,9 @@ const getAccountStatusText = (account) => { if (account.status === 'temp_error') return '临时异常' // 检查是否错误 if (account.status === 'error' || !account.isActive) return '错误' - // 检查是否可调度 - if (account.schedulable === false) return '已暂停' - // 否则正常 + // 配额超限时显示"正常"(不显示"已暂停") + if (account.schedulable === false && !isQuotaExceeded(account)) return '已暂停' + // 否则正常(包括配额超限状态) return '正常' } @@ -4249,7 +4266,8 @@ const getAccountStatusClass = (account) => { if (account.status === 'error' || !account.isActive) { return 'bg-red-100 text-red-800' } - if (account.schedulable === false) { + // 配额超限时显示绿色(正常) + if (account.schedulable === false && !isQuotaExceeded(account)) { return 'bg-gray-100 text-gray-800' } return 'bg-green-100 text-green-800' @@ -4277,7 +4295,8 @@ const getAccountStatusDotClass = (account) => { if (account.status === 'error' || !account.isActive) { return 'bg-red-500' } - if (account.schedulable === false) { + // 配额超限时显示绿色(正常) + if (account.schedulable === false && !isQuotaExceeded(account)) { return 'bg-gray-500' } return 'bg-green-500'