未知(继上次中断)

This commit is contained in:
Cheng Zhou
2026-02-04 10:52:34 +08:00
parent 8e258d21a7
commit 737f84bf54
99 changed files with 5497 additions and 2143 deletions
+89 -1
View File
@@ -3,9 +3,13 @@ from fastapi import APIRouter, Depends
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.deps import get_db_session, require_study_member
from app.core.deps import get_cra_site_scope, get_current_user, get_db_session, require_study_member
from app.models.milestone import Milestone
from app.schemas.progress import StudyProgressRead
from app.schemas.visit import VisitLostItem
from app.crud import visit as visit_crud
from app.schemas.dashboard import CenterSummaryItem
from app.crud import overview as overview_crud
router = APIRouter()
@@ -30,3 +34,87 @@ async def get_progress(
milestones_done=milestone_done,
completion_rate=completion_rate,
)
@router.get("/lost-visits", response_model=list[VisitLostItem], dependencies=[Depends(require_study_member())])
async def list_lost_visits(
study_id: uuid.UUID,
limit: int = 20,
db: AsyncSession = Depends(get_db_session),
current_user=Depends(get_current_user),
) -> list[VisitLostItem]:
cra_scope = await get_cra_site_scope(db, study_id, current_user)
site_ids = cra_scope[0] if cra_scope else None
rows = await visit_crud.list_lost_visits(db, study_id, site_ids=site_ids, limit=limit)
items: list[VisitLostItem] = []
for visit, subject_no, site_id in rows:
items.append(
VisitLostItem(
visit_id=visit.id,
subject_id=visit.subject_id,
subject_no=subject_no,
site_id=site_id,
visit_code=visit.visit_code,
status=visit.status,
updated_at=visit.updated_at,
)
)
return items
@router.get("/center-summary", response_model=list[CenterSummaryItem], dependencies=[Depends(require_study_member())])
async def get_center_summary(
study_id: uuid.UUID,
db: AsyncSession = Depends(get_db_session),
current_user=Depends(get_current_user),
) -> list[CenterSummaryItem]:
role_value = current_user.role.value if hasattr(current_user.role, "value") else current_user.role
if role_value not in {"ADMIN", "PM", "CRA"}:
return []
cra_scope = await get_cra_site_scope(db, study_id, current_user)
scope_ids = cra_scope[0] if cra_scope else None
scope_id_strs = {str(cid) for cid in scope_ids} if scope_ids is not None else None
overview = await overview_crud.get_project_overview(db, study_id)
centers = overview.get("centers") or []
stage_order = [
("institution_initiation_status", "机构立项"),
("ethics_status", "伦理审批"),
("contract_sign_status", "合同签署"),
("startup_status", "启动"),
("enrollment_status", "入组"),
("inspection_status", "末次稽查"),
("closeout_status", "关中心"),
]
summary_list: list[CenterSummaryItem] = []
for center in centers:
center_id = center.get("center_id")
if scope_id_strs is not None and center_id not in scope_id_strs:
continue
stage_label = "未开始"
stage_status = "NOT_STARTED"
for key, label in stage_order:
status = (center.get(key) or "NOT_STARTED").upper()
if status in ("IN_PROGRESS", "BLOCKED"):
stage_label = label
stage_status = status
break
if status == "COMPLETED":
stage_label = label
stage_status = status
continue
summary_list.append(
CenterSummaryItem(
id=center_id,
name=center.get("center_name") or "",
stage=stage_label,
stage_status=stage_status,
actual_enrolled=center.get("enrollment_actual") or 0,
planned_enrolled=center.get("enrollment_target") or 0,
)
)
return summary_list