From bc883df6e80fa63063dd1de89fa0eeebc8b50876 Mon Sep 17 00:00:00 2001 From: huangzhenpc Date: Mon, 9 Mar 2026 23:20:06 +0800 Subject: [PATCH] =?UTF-8?q?v2.1.5:=20=E5=AF=86=E9=92=A5=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E4=BC=98=E5=8C=96=20+=20=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=8F=B7=E7=BB=9F=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 密钥无到期时间/积分数据时显示"待验证"而非"已激活" - 后端验证完成后自动更新为真实状态 - 版本号统一更新到2.1.5(provider/client/main) - 添加.vscodeignore排除大文件 Co-Authored-By: Claude Opus 4.6 --- backend/app/api/client.py | 4 +- backend/app/main.py | 2 +- extension_clean/.vscodeignore | 9 ++ extension_clean/out/webview/panel.html | 140 +++++++++++++++++++----- extension_clean/out/webview/provider.js | 15 ++- extension_clean/package.json | 7 +- 6 files changed, 143 insertions(+), 34 deletions(-) create mode 100644 extension_clean/.vscodeignore diff --git a/backend/app/api/client.py b/backend/app/api/client.py index 18e5baa..3ed64ec 100644 --- a/backend/app/api/client.py +++ b/backend/app/api/client.py @@ -726,8 +726,8 @@ async def get_version(): """获取版本信息""" return { "success": True, - "version": "2.1.0", - "latest_version": "2.1.0", + "version": "2.1.5", + "latest_version": "2.1.5", "has_update": False, "download_url": "", "changelog": "" diff --git a/backend/app/main.py b/backend/app/main.py index e071bed..7a06dca 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -37,7 +37,7 @@ async def lifespan(app: FastAPI): app = FastAPI( title="蜂鸟Pro 管理后台", description="蜂鸟Pro 账号管理系统 API v2.1", - version="2.1.0", + version="2.1.5", lifespan=lifespan ) diff --git a/extension_clean/.vscodeignore b/extension_clean/.vscodeignore new file mode 100644 index 0000000..1dab5b0 --- /dev/null +++ b/extension_clean/.vscodeignore @@ -0,0 +1,9 @@ +hunter/** +*.vsix +node_modules/** +src/** +*.ts +tsconfig.json +.gitignore +panel_formatted.html +out/webview/panel_formatted.html diff --git a/extension_clean/out/webview/panel.html b/extension_clean/out/webview/panel.html index a9484b8..6b96cde 100644 --- a/extension_clean/out/webview/panel.html +++ b/extension_clean/out/webview/panel.html @@ -1546,30 +1546,74 @@ } // 更新双密钥显示 + function isExpired(dateStr) { + if (!dateStr) return false; + try { + let utcStr = dateStr; + if (!dateStr.includes('T') && !dateStr.includes('Z') && !dateStr.includes('+')) { + utcStr = dateStr.replace(' ', 'T') + 'Z'; + } + return new Date(utcStr) < new Date(); + } catch (e) { return false; } + } + function updateDualKeyDisplay() { // Auto密钥显示 if (autoKey) { autoKeyDisplay.textContent = maskKey(autoKey); - autoKeyExpire.textContent = autoExpireDate ? '到期: ' + formatExpireDate(autoExpireDate) : ''; - autoPoolStatus.textContent = '已激活'; clearAutoKeyBtn.style.display = 'inline'; + if (autoExpireDate) { + // 有到期时间,判断是否过期 + autoKeyExpire.textContent = '到期: ' + formatExpireDate(autoExpireDate); + if (isExpired(autoExpireDate)) { + autoPoolStatus.textContent = '已过期'; + autoPoolStatus.style.color = '#f87171'; + autoKeyExpire.style.color = '#f87171'; + } else { + autoPoolStatus.textContent = '已激活'; + autoPoolStatus.style.color = '#4ade80'; + autoKeyExpire.style.color = ''; + } + } else { + // 有密钥但无到期时间 = 未经后端验证 + autoKeyExpire.textContent = ''; + autoPoolStatus.textContent = '待验证'; + autoPoolStatus.style.color = '#fbbf24'; + } } else { autoKeyDisplay.textContent = '未激活'; autoKeyExpire.textContent = ''; autoPoolStatus.textContent = '未激活'; + autoPoolStatus.style.color = ''; clearAutoKeyBtn.style.display = 'none'; } // Pro密钥显示 if (proKey) { proKeyDisplay.textContent = maskKey(proKey); - proKeyQuota.textContent = '积分: ' + (proQuota - proQuotaUsed) + '/' + proQuota; - proPoolStatus.textContent = '已激活'; clearProKeyBtn.style.display = 'inline'; + if (proQuota > 0) { + // 有积分数据,说明已经过后端验证 + const proRemaining = proQuota - (proQuotaUsed || 0); + proKeyQuota.textContent = '积分: ' + proRemaining + '/' + proQuota; + if (proRemaining <= 0) { + proPoolStatus.textContent = '已耗尽'; + proPoolStatus.style.color = '#f87171'; + } else { + proPoolStatus.textContent = '已激活'; + proPoolStatus.style.color = '#4ade80'; + } + } else { + // 有密钥但无积分数据 = 未经后端验证 + proKeyQuota.textContent = ''; + proPoolStatus.textContent = '待验证'; + proPoolStatus.style.color = '#fbbf24'; + } } else { proKeyDisplay.textContent = '未激活'; proKeyQuota.textContent = ''; proPoolStatus.textContent = '未激活'; + proPoolStatus.style.color = ''; clearProKeyBtn.style.display = 'none'; } @@ -1972,33 +2016,62 @@ } break; - // 激活码状态检查结果 + // 激活码状态检查结果(双密钥格式) case 'keyStatusChecked': - if (message.valid) { - // 激活码有效,更新显示 - currentExpireDate = message.expireDate || ''; - currentSwitchRemaining = message.switchRemaining || 0; - expireDate.textContent = formatExpireDate(currentExpireDate); - switchCount.textContent = message.switchRemaining + '/' + (message.switchLimit || 100); - } else if (message.expired) { - // 激活码已过期,显示提示并重置状态 - currentExpireDate = ''; - currentSwitchRemaining = 0; - authStatus.textContent = '已过期'; + // 处理 Auto 密钥验证结果 + if (message.auto) { + if (message.auto.valid) { + autoExpireDate = message.auto.expireDate || ''; + currentExpireDate = autoExpireDate; + expireDate.textContent = formatExpireDate(currentExpireDate); + if (message.auto.switchRemaining !== undefined) { + currentSwitchRemaining = message.auto.switchRemaining; + switchCount.textContent = currentSwitchRemaining + '/' + (message.auto.switchLimit || 100); + } + } else if (message.auto.cleared) { + // 后端确认无效,已自动清除 + autoKey = ''; + autoExpireDate = ''; + } + } + // 处理 Pro 密钥验证结果 + if (message.pro) { + if (message.pro.valid) { + proQuota = message.pro.quota || proQuota; + proQuotaUsed = message.pro.quotaUsed || proQuotaUsed; + } else if (message.pro.cleared) { + proKey = ''; + proQuota = 0; + proQuotaUsed = 0; + } + } + // 更新显示 + updateDualKeyDisplay(); + // 更新全局激活状态 + if (autoKey || proKey) { + authStatus.textContent = '已授权'; + authStatus.className = 'status-badge active'; + const hasVerifiedAuto = autoKey && autoExpireDate; + const hasVerifiedPro = proKey && proQuota > 0; + if (hasVerifiedAuto || hasVerifiedPro) { + accountStatus.textContent = '已激活'; + accountStatus.className = 'status-badge active'; + accountStatus.style.background = ''; + } + switchBtn.disabled = false; + enableSeamlessBtn.disabled = isKeyExpired(); + } else { + // 所有密钥都已失效 + authStatus.textContent = '未授权'; authStatus.className = 'status-badge inactive'; - authStatus.style.background = '#6e3232'; - authStatus.style.color = '#ff6b6b'; - expireDate.textContent = '已过期'; - expireDate.style.color = '#f87171'; + accountStatus.textContent = '未激活'; + accountStatus.className = 'status-badge inactive'; + accountStatus.style.background = ''; switchBtn.disabled = true; enableSeamlessBtn.disabled = true; - // 如果免魔法已开启,自动关闭 - if (seamlessProxySwitch.checked) { - seamlessProxySwitch.checked = false; - vscode.postMessage({ type: 'toggleProxy', enabled: false, url: '' }); - } - // 显示过期弹窗 - showExpiredModal(); + fullActivationKey = ''; + keyDisplay.textContent = '尚未激活'; + expireDate.textContent = '尚未激活'; } break; @@ -2316,8 +2389,17 @@ if (state.isActivated) { authStatus.textContent = '已授权'; authStatus.className = 'status-badge active'; - accountStatus.textContent = '已激活'; - accountStatus.className = 'status-badge active'; + // 根据是否有到期时间/积分来判断激活状态 + const hasVerifiedAuto = state.autoKey && state.autoExpireDate; + const hasVerifiedPro = state.proKey && state.proQuota > 0; + if (hasVerifiedAuto || hasVerifiedPro) { + accountStatus.textContent = '已激活'; + accountStatus.className = 'status-badge active'; + } else { + accountStatus.textContent = '待验证'; + accountStatus.className = 'status-badge'; + accountStatus.style.background = '#fbbf24'; + } switchBtn.disabled = false; fullActivationKey = state.key; keyDisplay.textContent = maskKey(fullActivationKey); diff --git a/extension_clean/out/webview/provider.js b/extension_clean/out/webview/provider.js index 50d0046..2059789 100644 --- a/extension_clean/out/webview/provider.js +++ b/extension_clean/out/webview/provider.js @@ -1971,14 +1971,27 @@ class HummingbirdProViewProvider { await this._context.globalState.update("hummingbird.autoKey", undefined); await this._context.globalState.update("hummingbird.autoExpireDate", undefined); await this._context.globalState.update("hummingbird.autoMergedCount", undefined); + await this._context.globalState.update("hummingbird.key", undefined); + await this._context.globalState.update("hummingbird.expireDate", undefined); } else if (keyType === "pro") { await this._context.globalState.update("hummingbird.proKey", undefined); await this._context.globalState.update("hummingbird.proQuota", undefined); await this._context.globalState.update("hummingbird.proQuotaUsed", undefined); await this._context.globalState.update("hummingbird.proMergedCount", undefined); } + // 如果两个池都空了,清理公共状态 + const remainingAuto = this._context.globalState.get("hummingbird.autoKey"); + const remainingPro = this._context.globalState.get("hummingbird.proKey"); + if (!remainingAuto && !remainingPro) { + await this._context.globalState.update("hummingbird.selectedPool", undefined); + await this._context.globalState.update("hummingbird.seamlessInjected", undefined); + await this._context.globalState.update("hummingbird.seamlessCurrentAccount", undefined); + await this._context.globalState.update("hummingbird.switchRemaining", undefined); + extension_1.hideStatusBar(); + } this._postMessage({ 'type': "keyCleared", + 'success': true, 'keyType': keyType }); // 刷新状态 @@ -2264,4 +2277,4 @@ class HummingbirdProViewProvider { // 以下为占位注释,保持文件结构不变 exports.HummingbirdProViewProvider = HummingbirdProViewProvider; -HummingbirdProViewProvider.CURRENT_VERSION = '2.1.0'; +HummingbirdProViewProvider.CURRENT_VERSION = '2.1.5'; diff --git a/extension_clean/package.json b/extension_clean/package.json index ac9abc4..b929e0e 100644 --- a/extension_clean/package.json +++ b/extension_clean/package.json @@ -2,7 +2,7 @@ "name": "hummingbird-pro", "displayName": "蜂鸟Pro", "description": "蜂鸟Pro - Cursor 账号管理与智能换号工具", - "version": "2.0.1", + "version": "2.1.5", "publisher": "hummingbird", "repository": { "type": "git", @@ -53,6 +53,11 @@ "configuration": { "title": "蜂鸟Pro", "properties": { + "hummingbird.apiUrl": { + "type": "string", + "default": "https://api.aicode.edu.pl", + "description": "后端 API 地址(支持自定义部署)" + }, "hummingbird.cursorPath": { "type": "string", "default": "",