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

84 lines
3.2 KiB
Python

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()]