from __future__ import annotations import json from fastapi import APIRouter, Body, Depends, Query from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.dependencies import get_admin_user, get_db from app.models.team import Team from app.models.user import User from app.schemas.team import TeamCreate, TeamListOut, TeamOptionOut, TeamOut, TeamUpdate from app.schemas.team_manager import SetManagerRequest from app.services.operation_log import log_operation from app.services.team_manager_service import set_team_manager from app.services.team_service import create_team, list_team_options, list_teams, soft_delete_team, update_team router = APIRouter(prefix="/admin/teams", tags=["admin-teams"]) async def _team_detail_payload(db: AsyncSession, team: Team) -> dict: """构造返回团队详情,包含 manager_name。""" payload = { "id": team.id, "name": team.name, "code": getattr(team, "code", None), "description": getattr(team, "description", None), "status": getattr(team, "status", "active"), "sort_order": getattr(team, "sort_order", 0) or 0, "member_count": 0, "created_at": team.created_at, "updated_at": team.updated_at, "manager_id": getattr(team, "manager_id", None), "manager_name": None, } # 查询成员数和管理人用户名 from sqlalchemy import func from app.enums.user import UserType member_count = (await db.execute( select(func.count(User.id)).where( User.user_type == UserType.FRONTEND.value, User.team_id == team.id, ) )).scalar() or 0 payload["member_count"] = int(member_count) if getattr(team, "manager_id", None): mgr = await db.execute( select(User.username).where(User.id == team.manager_id).limit(1) ) payload["manager_name"] = mgr.scalar_one_or_none() return payload @router.get("", response_model=TeamListOut) async def list_admin_teams( page: int = Query(1, ge=1), page_size: int = Query(20, ge=1, le=500), keyword: str | None = Query(None), status: str | None = Query(None, pattern="^(active|disabled)$"), admin: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db), ): return await list_teams(db, page=page, page_size=page_size, keyword=keyword, status=status) @router.get("/options", response_model=list[TeamOptionOut]) async def list_admin_team_options( include_disabled: bool = Query(True), admin: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db), ): return await list_team_options(db, include_disabled=include_disabled) @router.post("", response_model=TeamOut) async def create_admin_team( req: TeamCreate, admin: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db), ): team = await create_team(db, req) await log_operation( db, admin.id, admin.username, f"创建团队 {team.name}", "POST", "/admin/teams", detail=json.dumps({"after": req.model_dump()}, ensure_ascii=False), ) return await _team_detail_payload(db, team) @router.put("/{team_id}", response_model=TeamOut) async def update_admin_team( team_id: str, req: TeamUpdate, admin: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db), ): team, before, after = await update_team(db, team_id, req) await log_operation( db, admin.id, admin.username, f"修改团队 {team.name}", "PUT", f"/admin/teams/{team_id}", detail=json.dumps({"before": before, "after": after}, ensure_ascii=False), ) return await _team_detail_payload(db, team) @router.put("/{team_id}/manager", response_model=TeamOut) async def set_team_manager_endpoint( team_id: str, req: SetManagerRequest = Body(...), admin: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db), ): team = await set_team_manager(db, team_id, req.user_id) manager_name = None if team.manager_id: mgr = await db.execute( select(User.username).where(User.id == team.manager_id).limit(1) ) manager_name = mgr.scalar_one_or_none() await log_operation( db, admin.id, admin.username, f"设置团队管理人 {team.name}: {manager_name or '取消'}", "PUT", f"/admin/teams/{team_id}/manager", detail=json.dumps({"manager_id": req.user_id}, ensure_ascii=False), ) return await _team_detail_payload(db, team) @router.delete("/{team_id}") async def delete_admin_team( team_id: str, admin: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db), ): team, before = await soft_delete_team(db, team_id) await log_operation( db, admin.id, admin.username, f"删除团队 {team.name}", "DELETE", f"/admin/teams/{team_id}", detail=json.dumps({"before": before, "after": {"deleted_at": str(team.deleted_at)}}, ensure_ascii=False), ) return {"message": "ok"}