蜂鸟Pro v2.0.1 - 基础框架版本 (待完善)
## 当前状态 - 插件界面已完成重命名 (cursorpro → hummingbird) - 双账号池 UI 已实现 (Auto/Pro 卡片) - 后端已切换到 MySQL 数据库 - 添加了 Cursor 官方用量 API 文档 ## 已知问题 (待修复) 1. 激活时检查账号导致无账号时激活失败 2. 未启用无感换号时不应获取账号 3. 账号用量模块不显示 (seamless 未启用时应隐藏) 4. 积分显示为 0 (后端未正确返回) 5. Auto/Pro 双密钥逻辑混乱,状态不同步 6. 账号添加后无自动分析功能 ## 下一版本计划 - 重构数据模型,优化账号状态管理 - 实现 Cursor API 自动分析账号 - 修复激活流程,不依赖账号 - 启用无感时才分配账号 - 完善账号用量实时显示 ## 文件说明 - docs/系统设计文档.md - 完整架构设计 - cursor 官方用量接口.md - Cursor API 文档 - 参考计费/ - Vibeviewer 开源项目参考 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -587,6 +587,101 @@ async def delete_key(
|
||||
return {"message": "删除成功"}
|
||||
|
||||
|
||||
@router.post("/keys/{key_id}/revoke")
|
||||
async def revoke_key(
|
||||
key_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""撤销激活码(从主密钥扣除资源)"""
|
||||
success, message = KeyService.revoke_key(db, key_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=400, detail=message)
|
||||
return {"success": True, "message": message}
|
||||
|
||||
|
||||
@router.get("/keys/by-device/{device_id}")
|
||||
async def get_keys_by_device(
|
||||
device_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
"""获取设备的所有密钥(管理后台用)"""
|
||||
keys_info = KeyService.get_device_keys(db, device_id)
|
||||
|
||||
result = {
|
||||
"device_id": device_id,
|
||||
"auto": None,
|
||||
"pro": None
|
||||
}
|
||||
|
||||
# Auto 密钥组
|
||||
if keys_info["auto"]:
|
||||
auto_data = keys_info["auto"]
|
||||
master = auto_data["master"]
|
||||
merged_keys = auto_data["merged_keys"]
|
||||
|
||||
all_keys = [{
|
||||
"id": master.id,
|
||||
"key": master.key,
|
||||
"is_master": True,
|
||||
"status": master.status.value,
|
||||
"duration_days": master.duration_days,
|
||||
"activated_at": master.first_activated_at.strftime("%Y-%m-%d %H:%M:%S") if master.first_activated_at else None
|
||||
}]
|
||||
for k in merged_keys:
|
||||
all_keys.append({
|
||||
"id": k.id,
|
||||
"key": k.key,
|
||||
"is_master": False,
|
||||
"status": k.status.value,
|
||||
"duration_days": k.duration_days,
|
||||
"merged_at": k.merged_at.strftime("%Y-%m-%d %H:%M:%S") if k.merged_at else None
|
||||
})
|
||||
|
||||
result["auto"] = {
|
||||
"total_keys": len(all_keys),
|
||||
"expire_at": master.expire_at.strftime("%Y-%m-%d %H:%M:%S") if master.expire_at else None,
|
||||
"current_account": master.current_account.email if master.current_account else None,
|
||||
"keys": all_keys
|
||||
}
|
||||
|
||||
# Pro 密钥组
|
||||
if keys_info["pro"]:
|
||||
pro_data = keys_info["pro"]
|
||||
master = pro_data["master"]
|
||||
merged_keys = pro_data["merged_keys"]
|
||||
|
||||
all_keys = [{
|
||||
"id": master.id,
|
||||
"key": master.key,
|
||||
"is_master": True,
|
||||
"status": master.status.value,
|
||||
"quota_contribution": master.quota_contribution,
|
||||
"activated_at": master.first_activated_at.strftime("%Y-%m-%d %H:%M:%S") if master.first_activated_at else None
|
||||
}]
|
||||
for k in merged_keys:
|
||||
all_keys.append({
|
||||
"id": k.id,
|
||||
"key": k.key,
|
||||
"is_master": False,
|
||||
"status": k.status.value,
|
||||
"quota_contribution": k.quota_contribution,
|
||||
"merged_at": k.merged_at.strftime("%Y-%m-%d %H:%M:%S") if k.merged_at else None
|
||||
})
|
||||
|
||||
result["pro"] = {
|
||||
"total_keys": len(all_keys),
|
||||
"quota": pro_data["quota"],
|
||||
"quota_used": pro_data["quota_used"],
|
||||
"quota_remaining": pro_data["quota_remaining"],
|
||||
"current_account": master.current_account.email if master.current_account else None,
|
||||
"keys": all_keys
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@router.get("/keys/{key_id}/usage-info")
|
||||
async def get_key_usage_info(
|
||||
key_id: int,
|
||||
|
||||
Reference in New Issue
Block a user