refactor(admin): 收敛后台接口封装与页面状态逻辑

- 简化绑定和日志接口的查询、序列化与前端数据请求路径
- 统一登录流程与前端 API 调用层,补充后台图标依赖
- 抽取通用异步状态处理,减少多个管理页面的重复逻辑
This commit is contained in:
2026-03-04 00:18:47 +08:00
parent ab1bd90c65
commit 0a1eeb9ddf
12 changed files with 556 additions and 305 deletions

View File

@@ -36,6 +36,21 @@ def to_binding_item(binding: TokenBinding, binding_service: BindingService) -> B
)
def apply_binding_filters(
statement,
token_suffix: str | None,
ip: str | None,
status_filter: int | None,
):
if token_suffix:
statement = statement.where(TokenBinding.token_display.ilike(f"%{token_suffix}%"))
if ip:
statement = statement.where(cast(TokenBinding.bound_ip, String).ilike(f"%{ip}%"))
if status_filter in {STATUS_ACTIVE, STATUS_BANNED}:
statement = statement.where(TokenBinding.status == status_filter)
return statement
async def get_binding_or_404(session: AsyncSession, binding_id: int) -> TokenBinding:
binding = await session.get(TokenBinding, binding_id)
if binding is None:
@@ -54,6 +69,21 @@ def log_admin_action(request: Request, settings: Settings, action: str, binding_
)
async def commit_binding_cache(binding: TokenBinding, binding_service: BindingService) -> None:
await binding_service.sync_binding_cache(binding.token_hash, str(binding.bound_ip), binding.status)
async def update_binding_status(
session: AsyncSession,
binding: TokenBinding,
status_code: int,
binding_service: BindingService,
) -> None:
binding.status = status_code
await session.commit()
await commit_binding_cache(binding, binding_service)
@router.get("", response_model=BindingListResponse)
async def list_bindings(
page: int = Query(default=1, ge=1),
@@ -64,13 +94,7 @@ async def list_bindings(
session: AsyncSession = Depends(get_db_session),
binding_service: BindingService = Depends(get_binding_service),
) -> BindingListResponse:
statement = select(TokenBinding)
if token_suffix:
statement = statement.where(TokenBinding.token_display.ilike(f"%{token_suffix}%"))
if ip:
statement = statement.where(cast(TokenBinding.bound_ip, String).ilike(f"%{ip}%"))
if status_filter in {STATUS_ACTIVE, STATUS_BANNED}:
statement = statement.where(TokenBinding.status == status_filter)
statement = apply_binding_filters(select(TokenBinding), token_suffix, ip, status_filter)
total_result = await session.execute(select(func.count()).select_from(statement.subquery()))
total = int(total_result.scalar_one())
@@ -116,7 +140,7 @@ async def update_bound_ip(
binding = await get_binding_or_404(session, payload.id)
binding.bound_ip = payload.bound_ip
await session.commit()
await binding_service.sync_binding_cache(binding.token_hash, str(binding.bound_ip), binding.status)
await commit_binding_cache(binding, binding_service)
log_admin_action(request, settings, "update_ip", payload.id)
return {"success": True}
@@ -130,9 +154,7 @@ async def ban_token(
binding_service: BindingService = Depends(get_binding_service),
):
binding = await get_binding_or_404(session, payload.id)
binding.status = STATUS_BANNED
await session.commit()
await binding_service.sync_binding_cache(binding.token_hash, str(binding.bound_ip), binding.status)
await update_binding_status(session, binding, STATUS_BANNED, binding_service)
log_admin_action(request, settings, "ban", payload.id)
return {"success": True}
@@ -146,8 +168,6 @@ async def unban_token(
binding_service: BindingService = Depends(get_binding_service),
):
binding = await get_binding_or_404(session, payload.id)
binding.status = STATUS_ACTIVE
await session.commit()
await binding_service.sync_binding_cache(binding.token_hash, str(binding.bound_ip), binding.status)
await update_binding_status(session, binding, STATUS_ACTIVE, binding_service)
log_admin_action(request, settings, "unban", payload.id)
return {"success": True}