v2.1.5: 密钥状态显示优化 + 版本号统一

- 密钥无到期时间/积分数据时显示"待验证"而非"已激活"
- 后端验证完成后自动更新为真实状态
- 版本号统一更新到2.1.5(provider/client/main)
- 添加.vscodeignore排除大文件

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-09 23:20:06 +08:00
parent cd427ede80
commit bc883df6e8
6 changed files with 143 additions and 34 deletions

View File

@@ -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": ""

View File

@@ -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
)

View File

@@ -0,0 +1,9 @@
hunter/**
*.vsix
node_modules/**
src/**
*.ts
tsconfig.json
.gitignore
panel_formatted.html
out/webview/panel_formatted.html

View File

@@ -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);

View File

@@ -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';

View File

@@ -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": "",