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:
@@ -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": ""
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
9
extension_clean/.vscodeignore
Normal file
9
extension_clean/.vscodeignore
Normal file
@@ -0,0 +1,9 @@
|
||||
hunter/**
|
||||
*.vsix
|
||||
node_modules/**
|
||||
src/**
|
||||
*.ts
|
||||
tsconfig.json
|
||||
.gitignore
|
||||
panel_formatted.html
|
||||
out/webview/panel_formatted.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);
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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": "",
|
||||
|
||||
Reference in New Issue
Block a user