| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- from typing import Optional
- from uuid import UUID
- from fastapi import APIRouter, Depends, HTTPException, Query
- from sqlalchemy import func, or_, select
- from sqlalchemy.ext.asyncio import AsyncSession
- from backend.app.core.dependencies import get_current_user, require_any_permissions, require_permissions
- from backend.app.core.security import hash_password
- from backend.app.db.session import get_db
- from backend.app.models import RolePermission, User
- from backend.app.schemas.pagination import PaginatedResponse
- from backend.app.schemas.user import CurrentUserResponse, UserCreate, UserResponse, UserUpdate
- router = APIRouter(prefix="/users", tags=["users"])
- def is_limited_scope(user: User) -> bool:
- return user.role and user.role.name not in {"管理员", "排班员"}
- @router.get("/me", response_model=CurrentUserResponse)
- async def get_current_user_profile(
- current_user: User = Depends(get_current_user),
- db: AsyncSession = Depends(get_db),
- ):
- result = await db.execute(
- select(RolePermission.permission_code).where(RolePermission.role_id == current_user.role_id)
- )
- permissions = [row[0] for row in result.fetchall()]
- return {
- "id": current_user.id,
- "name": current_user.name,
- "account": current_user.account,
- "phone": current_user.phone,
- "title": current_user.title,
- "avatar": current_user.avatar,
- "role_id": current_user.role_id,
- "campus_id": current_user.campus_id,
- "dept_id": current_user.dept_id,
- "status": current_user.status,
- "permissions": permissions,
- }
- @router.get(
- "",
- response_model=list[UserResponse] | PaginatedResponse[UserResponse],
- )
- async def list_users(
- db: AsyncSession = Depends(get_db),
- current_user: User = Depends(require_any_permissions(["users.view", "schedule.view", "duty.view"])),
- keyword: Optional[str] = Query(default=None),
- campus_id: Optional[UUID] = Query(default=None),
- dept_id: Optional[UUID] = Query(default=None),
- role_id: Optional[UUID] = Query(default=None),
- status: Optional[str] = Query(default=None),
- page: Optional[int] = Query(default=None, ge=1),
- page_size: Optional[int] = Query(default=None, ge=1, le=200, alias="pageSize"),
- size: Optional[int] = Query(default=None, ge=1, le=200),
- ):
- query = select(User)
- if is_limited_scope(current_user):
- if current_user.dept_id:
- dept_id = current_user.dept_id
- elif current_user.campus_id:
- campus_id = current_user.campus_id
- else:
- if page is None and page_size is None and size is None:
- return []
- return {"items": [], "total": 0, "page": page or 1, "pageSize": page_size or size or 10}
- if keyword:
- like = f"%{keyword.strip()}%"
- query = query.where(
- or_(
- User.name.ilike(like),
- User.account.ilike(like),
- User.phone.ilike(like),
- User.title.ilike(like),
- )
- )
- if campus_id:
- query = query.where(User.campus_id == campus_id)
- if dept_id:
- query = query.where(User.dept_id == dept_id)
- if role_id:
- query = query.where(User.role_id == role_id)
- if status:
- query = query.where(User.status == status)
- if page is None and page_size is None and size is None:
- result = await db.execute(query.order_by(User.created_at.desc()))
- return result.scalars().all()
- page_value = page or 1
- size_value = page_size or size or 10
- total = await db.scalar(select(func.count()).select_from(query.subquery()))
- result = await db.execute(
- query.order_by(User.created_at.desc())
- .offset((page_value - 1) * size_value)
- .limit(size_value)
- )
- return {
- "items": result.scalars().all(),
- "total": total or 0,
- "page": page_value,
- "pageSize": size_value,
- }
- @router.post("", response_model=UserResponse, dependencies=[Depends(require_permissions(["users.create"]))])
- async def create_user(payload: UserCreate, db: AsyncSession = Depends(get_db)):
- exists = await db.execute(select(User.id).where(User.account == payload.account))
- if exists.scalar_one_or_none():
- raise HTTPException(status_code=409, detail="账号已存在")
- user = User(
- name=payload.name,
- account=payload.account,
- phone=payload.phone,
- title=payload.title,
- avatar=payload.avatar,
- role_id=payload.role_id,
- campus_id=payload.campus_id,
- dept_id=payload.dept_id,
- status=payload.status,
- password_hash=hash_password(payload.password),
- token_version=1
- )
- db.add(user)
- await db.commit()
- await db.refresh(user)
- return user
- @router.put("/{user_id}", response_model=UserResponse, dependencies=[Depends(require_permissions(["users.edit"]))])
- async def update_user(user_id: UUID, payload: UserUpdate, db: AsyncSession = Depends(get_db)):
- result = await db.execute(select(User).where(User.id == user_id))
- user = result.scalar_one_or_none()
- if not user:
- raise HTTPException(status_code=404, detail="人员不存在")
- update_data = payload.model_dump(exclude_unset=True)
- bump_token = False
- if "password" in update_data:
- update_data["password_hash"] = hash_password(update_data.pop("password"))
- bump_token = True
- if "status" in update_data and update_data["status"] != user.status:
- bump_token = True
- if "role_id" in update_data and update_data["role_id"] != user.role_id:
- bump_token = True
- for key, value in update_data.items():
- setattr(user, key, value)
- if bump_token:
- user.token_version = (user.token_version or 1) + 1
- await db.commit()
- await db.refresh(user)
- return user
- @router.delete("/{user_id}", dependencies=[Depends(require_permissions(["users.delete"]))])
- async def delete_user(user_id: UUID, db: AsyncSession = Depends(get_db)):
- result = await db.execute(select(User).where(User.id == user_id))
- user = result.scalar_one_or_none()
- if not user:
- raise HTTPException(status_code=404, detail="人员不存在")
- await db.delete(user)
- await db.commit()
- return {"success": True}
|