Files
tp-ems/core/backend/app/api/v1/users.py

84 lines
3.2 KiB
Python
Raw Normal View History

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from pydantic import BaseModel
from app.core.database import get_db
from app.core.deps import get_current_user, require_roles
from app.core.security import hash_password
from app.models.user import User, Role
from app.services.audit import log_audit
router = APIRouter(prefix="/users", tags=["用户管理"])
class UserCreate(BaseModel):
username: str
password: str
full_name: str | None = None
email: str | None = None
phone: str | None = None
role: str = "visitor"
class UserUpdate(BaseModel):
full_name: str | None = None
email: str | None = None
phone: str | None = None
role: str | None = None
is_active: bool | None = None
@router.get("")
async def list_users(
page: int = Query(1, ge=1),
page_size: int = Query(20, ge=1, le=100),
db: AsyncSession = Depends(get_db),
user: User = Depends(require_roles("admin", "energy_manager")),
):
count_q = select(func.count(User.id))
total = (await db.execute(count_q)).scalar()
result = await db.execute(select(User).offset((page - 1) * page_size).limit(page_size).order_by(User.id))
return {
"total": total,
"items": [{
"id": u.id, "username": u.username, "full_name": u.full_name,
"email": u.email, "phone": u.phone, "role": u.role,
"is_active": u.is_active, "last_login": str(u.last_login) if u.last_login else None,
} for u in result.scalars().all()]
}
@router.post("")
async def create_user(data: UserCreate, db: AsyncSession = Depends(get_db), user: User = Depends(require_roles("admin"))):
existing = await db.execute(select(User).where(User.username == data.username))
if existing.scalar_one_or_none():
raise HTTPException(status_code=400, detail="用户名已存在")
new_user = User(
username=data.username, hashed_password=hash_password(data.password),
full_name=data.full_name, email=data.email, phone=data.phone, role=data.role,
)
db.add(new_user)
await db.flush()
await log_audit(db, user.id, "create", "user", detail=f"创建用户 {data.username}")
return {"id": new_user.id, "username": new_user.username}
@router.put("/{user_id}")
async def update_user(user_id: int, data: UserUpdate, db: AsyncSession = Depends(get_db), admin: User = Depends(require_roles("admin"))):
result = await db.execute(select(User).where(User.id == user_id))
target = result.scalar_one_or_none()
if not target:
raise HTTPException(status_code=404, detail="用户不存在")
updates = data.model_dump(exclude_unset=True)
for k, v in updates.items():
setattr(target, k, v)
await log_audit(db, admin.id, "update", "user", detail=f"更新用户 {target.username}: {', '.join(updates.keys())}")
return {"message": "已更新"}
@router.get("/roles")
async def list_roles(db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user)):
result = await db.execute(select(Role).order_by(Role.id))
return [{"id": r.id, "name": r.name, "display_name": r.display_name, "description": r.description}
for r in result.scalars().all()]