import uuid from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.ext.asyncio import AsyncSession from app.core.deps import get_operator_role_label, get_current_user, get_db_session, require_study_not_locked, require_api_permission from app.crud import audit as audit_crud from app.crud import precaution as precaution_crud from app.crud import site as site_crud from app.crud import study as study_crud from app.schemas.precaution import PrecautionCreate, PrecautionRead, PrecautionUpdate router = APIRouter() async def _ensure_study_exists(db: AsyncSession, study_id: uuid.UUID): study = await study_crud.get(db, study_id) if not study: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="项目不存在") return study async def _ensure_site_name_active(db: AsyncSession, study_id: uuid.UUID, site_name: str | None): if not site_name: return active_names = await site_crud.list_active_names(db, study_id) if site_name not in active_names: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="中心已停用") @router.post( "/precautions", response_model=PrecautionRead, status_code=status.HTTP_201_CREATED, dependencies=[Depends(require_api_permission("precautions:create"))], ) async def create_precaution( study_id: uuid.UUID, precaution_in: PrecautionCreate, db: AsyncSession = Depends(get_db_session), current_user=Depends(get_current_user), ) -> PrecautionRead: await _ensure_study_exists(db, study_id) await _ensure_site_name_active(db, study_id, precaution_in.site_name) precaution = await precaution_crud.create_precaution(db, study_id, precaution_in, created_by=current_user.id) await audit_crud.log_action( db, study_id=study_id, entity_type="precaution", entity_id=precaution.id, action="CREATE_PRECAUTION", detail=f"注意事项 {precaution.title} 已创建", operator_id=current_user.id, operator_role=await get_operator_role_label(db, study_id, current_user), ) return PrecautionRead.model_validate(precaution) @router.get( "/precautions", response_model=list[PrecautionRead], dependencies=[Depends(require_api_permission("precautions:read"))], ) async def list_precautions( study_id: uuid.UUID, site_name: str | None = None, keyword: str | None = None, skip: int = 0, limit: int = 100, db: AsyncSession = Depends(get_db_session), ) -> list[PrecautionRead]: await _ensure_study_exists(db, study_id) items = await precaution_crud.list_precautions(db, study_id, site_name=site_name, keyword=keyword, skip=skip, limit=limit) return [PrecautionRead.model_validate(item) for item in items] @router.get( "/precautions/{precaution_id}", response_model=PrecautionRead, dependencies=[Depends(require_api_permission("precautions:read"))], ) async def get_precaution( study_id: uuid.UUID, precaution_id: uuid.UUID, db: AsyncSession = Depends(get_db_session), ) -> PrecautionRead: await _ensure_study_exists(db, study_id) precaution = await precaution_crud.get_precaution(db, precaution_id) if not precaution or precaution.study_id != study_id: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="注意事项不存在") return PrecautionRead.model_validate(precaution) @router.patch( "/precautions/{precaution_id}", response_model=PrecautionRead, dependencies=[Depends(require_api_permission("precautions:update"))], ) async def update_precaution( study_id: uuid.UUID, precaution_id: uuid.UUID, precaution_in: PrecautionUpdate, db: AsyncSession = Depends(get_db_session), current_user=Depends(get_current_user), ) -> PrecautionRead: await _ensure_study_exists(db, study_id) precaution = await precaution_crud.get_precaution(db, precaution_id) if not precaution or precaution.study_id != study_id: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="注意事项不存在") await _ensure_site_name_active(db, study_id, precaution.site_name) precaution = await precaution_crud.update_precaution(db, precaution, precaution_in) await audit_crud.log_action( db, study_id=study_id, entity_type="precaution", entity_id=precaution_id, action="UPDATE_PRECAUTION", detail=f"注意事项 {precaution_id} 已更新", operator_id=current_user.id, operator_role=await get_operator_role_label(db, study_id, current_user), ) return PrecautionRead.model_validate(precaution) @router.delete( "/precautions/{precaution_id}", status_code=status.HTTP_204_NO_CONTENT, dependencies=[Depends(require_api_permission("precautions:delete"))], ) async def delete_precaution( study_id: uuid.UUID, precaution_id: uuid.UUID, db: AsyncSession = Depends(get_db_session), current_user=Depends(get_current_user), ) -> None: await _ensure_study_exists(db, study_id) precaution = await precaution_crud.get_precaution(db, precaution_id) if not precaution or precaution.study_id != study_id: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="注意事项不存在") await _ensure_site_name_active(db, study_id, precaution.site_name) await precaution_crud.delete_precaution(db, precaution) await audit_crud.log_action( db, study_id=study_id, entity_type="precaution", entity_id=precaution_id, action="DELETE_PRECAUTION", detail=f"注意事项 {precaution_id} 已删除", operator_id=current_user.id, operator_role=await get_operator_role_label(db, study_id, current_user), )