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 {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
"version": "2.1.0",
|
"version": "2.1.5",
|
||||||
"latest_version": "2.1.0",
|
"latest_version": "2.1.5",
|
||||||
"has_update": False,
|
"has_update": False,
|
||||||
"download_url": "",
|
"download_url": "",
|
||||||
"changelog": ""
|
"changelog": ""
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ async def lifespan(app: FastAPI):
|
|||||||
app = FastAPI(
|
app = FastAPI(
|
||||||
title="蜂鸟Pro 管理后台",
|
title="蜂鸟Pro 管理后台",
|
||||||
description="蜂鸟Pro 账号管理系统 API v2.1",
|
description="蜂鸟Pro 账号管理系统 API v2.1",
|
||||||
version="2.1.0",
|
version="2.1.5",
|
||||||
lifespan=lifespan
|
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() {
|
function updateDualKeyDisplay() {
|
||||||
// Auto密钥显示
|
// Auto密钥显示
|
||||||
if (autoKey) {
|
if (autoKey) {
|
||||||
autoKeyDisplay.textContent = maskKey(autoKey);
|
autoKeyDisplay.textContent = maskKey(autoKey);
|
||||||
autoKeyExpire.textContent = autoExpireDate ? '到期: ' + formatExpireDate(autoExpireDate) : '';
|
|
||||||
autoPoolStatus.textContent = '已激活';
|
|
||||||
clearAutoKeyBtn.style.display = 'inline';
|
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 {
|
} else {
|
||||||
autoKeyDisplay.textContent = '未激活';
|
autoKeyDisplay.textContent = '未激活';
|
||||||
autoKeyExpire.textContent = '';
|
autoKeyExpire.textContent = '';
|
||||||
autoPoolStatus.textContent = '未激活';
|
autoPoolStatus.textContent = '未激活';
|
||||||
|
autoPoolStatus.style.color = '';
|
||||||
clearAutoKeyBtn.style.display = 'none';
|
clearAutoKeyBtn.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pro密钥显示
|
// Pro密钥显示
|
||||||
if (proKey) {
|
if (proKey) {
|
||||||
proKeyDisplay.textContent = maskKey(proKey);
|
proKeyDisplay.textContent = maskKey(proKey);
|
||||||
proKeyQuota.textContent = '积分: ' + (proQuota - proQuotaUsed) + '/' + proQuota;
|
|
||||||
proPoolStatus.textContent = '已激活';
|
|
||||||
clearProKeyBtn.style.display = 'inline';
|
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 {
|
} else {
|
||||||
proKeyDisplay.textContent = '未激活';
|
proKeyDisplay.textContent = '未激活';
|
||||||
proKeyQuota.textContent = '';
|
proKeyQuota.textContent = '';
|
||||||
proPoolStatus.textContent = '未激活';
|
proPoolStatus.textContent = '未激活';
|
||||||
|
proPoolStatus.style.color = '';
|
||||||
clearProKeyBtn.style.display = 'none';
|
clearProKeyBtn.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1972,33 +2016,62 @@
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// 激活码状态检查结果
|
// 激活码状态检查结果(双密钥格式)
|
||||||
case 'keyStatusChecked':
|
case 'keyStatusChecked':
|
||||||
if (message.valid) {
|
// 处理 Auto 密钥验证结果
|
||||||
// 激活码有效,更新显示
|
if (message.auto) {
|
||||||
currentExpireDate = message.expireDate || '';
|
if (message.auto.valid) {
|
||||||
currentSwitchRemaining = message.switchRemaining || 0;
|
autoExpireDate = message.auto.expireDate || '';
|
||||||
|
currentExpireDate = autoExpireDate;
|
||||||
expireDate.textContent = formatExpireDate(currentExpireDate);
|
expireDate.textContent = formatExpireDate(currentExpireDate);
|
||||||
switchCount.textContent = message.switchRemaining + '/' + (message.switchLimit || 100);
|
if (message.auto.switchRemaining !== undefined) {
|
||||||
} else if (message.expired) {
|
currentSwitchRemaining = message.auto.switchRemaining;
|
||||||
// 激活码已过期,显示提示并重置状态
|
switchCount.textContent = currentSwitchRemaining + '/' + (message.auto.switchLimit || 100);
|
||||||
currentExpireDate = '';
|
}
|
||||||
currentSwitchRemaining = 0;
|
} else if (message.auto.cleared) {
|
||||||
authStatus.textContent = '已过期';
|
// 后端确认无效,已自动清除
|
||||||
|
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.className = 'status-badge inactive';
|
||||||
authStatus.style.background = '#6e3232';
|
accountStatus.textContent = '未激活';
|
||||||
authStatus.style.color = '#ff6b6b';
|
accountStatus.className = 'status-badge inactive';
|
||||||
expireDate.textContent = '已过期';
|
accountStatus.style.background = '';
|
||||||
expireDate.style.color = '#f87171';
|
|
||||||
switchBtn.disabled = true;
|
switchBtn.disabled = true;
|
||||||
enableSeamlessBtn.disabled = true;
|
enableSeamlessBtn.disabled = true;
|
||||||
// 如果免魔法已开启,自动关闭
|
fullActivationKey = '';
|
||||||
if (seamlessProxySwitch.checked) {
|
keyDisplay.textContent = '尚未激活';
|
||||||
seamlessProxySwitch.checked = false;
|
expireDate.textContent = '尚未激活';
|
||||||
vscode.postMessage({ type: 'toggleProxy', enabled: false, url: '' });
|
|
||||||
}
|
|
||||||
// 显示过期弹窗
|
|
||||||
showExpiredModal();
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -2316,8 +2389,17 @@
|
|||||||
if (state.isActivated) {
|
if (state.isActivated) {
|
||||||
authStatus.textContent = '已授权';
|
authStatus.textContent = '已授权';
|
||||||
authStatus.className = 'status-badge active';
|
authStatus.className = 'status-badge active';
|
||||||
|
// 根据是否有到期时间/积分来判断激活状态
|
||||||
|
const hasVerifiedAuto = state.autoKey && state.autoExpireDate;
|
||||||
|
const hasVerifiedPro = state.proKey && state.proQuota > 0;
|
||||||
|
if (hasVerifiedAuto || hasVerifiedPro) {
|
||||||
accountStatus.textContent = '已激活';
|
accountStatus.textContent = '已激活';
|
||||||
accountStatus.className = 'status-badge active';
|
accountStatus.className = 'status-badge active';
|
||||||
|
} else {
|
||||||
|
accountStatus.textContent = '待验证';
|
||||||
|
accountStatus.className = 'status-badge';
|
||||||
|
accountStatus.style.background = '#fbbf24';
|
||||||
|
}
|
||||||
switchBtn.disabled = false;
|
switchBtn.disabled = false;
|
||||||
fullActivationKey = state.key;
|
fullActivationKey = state.key;
|
||||||
keyDisplay.textContent = maskKey(fullActivationKey);
|
keyDisplay.textContent = maskKey(fullActivationKey);
|
||||||
|
|||||||
@@ -1971,14 +1971,27 @@ class HummingbirdProViewProvider {
|
|||||||
await this._context.globalState.update("hummingbird.autoKey", undefined);
|
await this._context.globalState.update("hummingbird.autoKey", undefined);
|
||||||
await this._context.globalState.update("hummingbird.autoExpireDate", undefined);
|
await this._context.globalState.update("hummingbird.autoExpireDate", undefined);
|
||||||
await this._context.globalState.update("hummingbird.autoMergedCount", 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") {
|
} else if (keyType === "pro") {
|
||||||
await this._context.globalState.update("hummingbird.proKey", undefined);
|
await this._context.globalState.update("hummingbird.proKey", undefined);
|
||||||
await this._context.globalState.update("hummingbird.proQuota", undefined);
|
await this._context.globalState.update("hummingbird.proQuota", undefined);
|
||||||
await this._context.globalState.update("hummingbird.proQuotaUsed", undefined);
|
await this._context.globalState.update("hummingbird.proQuotaUsed", undefined);
|
||||||
await this._context.globalState.update("hummingbird.proMergedCount", 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({
|
this._postMessage({
|
||||||
'type': "keyCleared",
|
'type': "keyCleared",
|
||||||
|
'success': true,
|
||||||
'keyType': keyType
|
'keyType': keyType
|
||||||
});
|
});
|
||||||
// 刷新状态
|
// 刷新状态
|
||||||
@@ -2264,4 +2277,4 @@ class HummingbirdProViewProvider {
|
|||||||
// 以下为占位注释,保持文件结构不变
|
// 以下为占位注释,保持文件结构不变
|
||||||
|
|
||||||
exports.HummingbirdProViewProvider = HummingbirdProViewProvider;
|
exports.HummingbirdProViewProvider = HummingbirdProViewProvider;
|
||||||
HummingbirdProViewProvider.CURRENT_VERSION = '2.1.0';
|
HummingbirdProViewProvider.CURRENT_VERSION = '2.1.5';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "hummingbird-pro",
|
"name": "hummingbird-pro",
|
||||||
"displayName": "蜂鸟Pro",
|
"displayName": "蜂鸟Pro",
|
||||||
"description": "蜂鸟Pro - Cursor 账号管理与智能换号工具",
|
"description": "蜂鸟Pro - Cursor 账号管理与智能换号工具",
|
||||||
"version": "2.0.1",
|
"version": "2.1.5",
|
||||||
"publisher": "hummingbird",
|
"publisher": "hummingbird",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -53,6 +53,11 @@
|
|||||||
"configuration": {
|
"configuration": {
|
||||||
"title": "蜂鸟Pro",
|
"title": "蜂鸟Pro",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"hummingbird.apiUrl": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "https://api.aicode.edu.pl",
|
||||||
|
"description": "后端 API 地址(支持自定义部署)"
|
||||||
|
},
|
||||||
"hummingbird.cursorPath": {
|
"hummingbird.cursorPath": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "",
|
"default": "",
|
||||||
|
|||||||
Reference in New Issue
Block a user