feat(keys): 新增 Provider Keys 批量删除 API

- 后端新增 POST /keys/batch-delete 接口,支持一次删除最多 100 个 Key
- 按 provider_id 聚合执行副作用,避免逐个删除导致的重复 Redis 操作
- 前端批量操作对话框中删除操作改用批量 API,按 100 个一批分批调用
This commit is contained in:
fawney19
2026-03-07 03:49:44 +08:00
parent 7b0908cd87
commit bb268310e2
5 changed files with 136 additions and 5 deletions

View File

@@ -16,6 +16,7 @@ if TYPE_CHECKING:
)
__all__ = [
"batch_delete_endpoint_keys_response",
"clear_oauth_invalid_response",
"create_provider_key_response",
"delete_endpoint_key_response",
@@ -46,6 +47,15 @@ async def create_provider_key_response(
return await _impl(db=db, provider_id=provider_id, key_data=key_data)
async def batch_delete_endpoint_keys_response(db: Session, key_ids: list[str]) -> dict:
"""批量删除 Keys 并返回统一响应(惰性导入实现)。"""
from src.services.provider_keys.key_command_service import (
batch_delete_endpoint_keys_response as _impl,
)
return await _impl(db=db, key_ids=key_ids)
async def delete_endpoint_key_response(db: Session, key_id: str) -> dict[str, str]:
"""删除 Key 并返回统一响应(惰性导入实现)。"""
from src.services.provider_keys.key_command_service import delete_endpoint_key_response as _impl

View File

@@ -497,3 +497,55 @@ async def delete_endpoint_key_response(db: Session, key_id: str) -> dict[str, st
)
logger.warning("[DELETE] 删除 Key: ID={}, Provider={}", key_id, delete_result.provider_id)
return {"message": f"Key {key_id} 已删除"}
async def batch_delete_endpoint_keys_response(db: Session, key_ids: list[str]) -> dict[str, Any]:
"""批量删除 Keys按 provider_id 聚合后仅执行一次副作用。"""
if not key_ids:
return {"success_count": 0, "failed_count": 0, "failed": []}
# 一次查询所有 Key
keys = db.query(ProviderAPIKey).filter(ProviderAPIKey.id.in_(key_ids)).all()
found_ids = {key.id for key in keys}
not_found_ids = [kid for kid in key_ids if kid not in found_ids]
failed: list[dict[str, str]] = [{"id": kid, "error": "not found"} for kid in not_found_ids]
# 收集受影响的 provider_id
affected_provider_ids = {key.provider_id for key in keys if key.provider_id}
# 批量删除,一次提交
success_count = 0
try:
for key in keys:
db.delete(key)
db.commit()
success_count = len(keys)
except Exception as exc:
db.rollback()
logger.error("批量删除 Key 提交失败: {}", exc)
failed.extend({"id": kid, "error": str(exc)} for kid in found_ids)
return {"success_count": 0, "failed_count": len(failed), "failed": failed}
# 按 provider_id 聚合,每个 provider 仅执行一次副作用
for provider_id in affected_provider_ids:
try:
await run_delete_key_side_effects(
db=db,
provider_id=provider_id,
deleted_key_allowed_models=None,
)
except Exception as exc:
logger.error("批量删除副作用执行失败: provider_id={}, Error={}", provider_id, exc)
logger.warning(
"[BATCH_DELETE] 批量删除 Keys: success={}, failed={}, providers={}",
success_count,
len(failed),
len(affected_provider_ids),
)
return {
"success_count": success_count,
"failed_count": len(failed),
"failed": failed,
}