import uuid from datetime import datetime from typing import Literal from pydantic import BaseModel, ConfigDict, Field ConfirmStatus = Literal["待确认", "已确认", "退回"] MilestoneStatus = Literal["未开始", "进行中", "已完成", "延期"] class ProjectMilestoneItem(BaseModel): id: str name: str = "" planDate: str = "" startDate: str = "" endDate: str = "" durationDays: int = 1 owner: str = "" remark: str = "" status: MilestoneStatus = "未开始" class EnrollmentPlanItem(BaseModel): totalTarget: int = 0 startDate: str = "" endDate: str = "" monthlyGoalNote: str = "" stageBreakdown: str = "" class SiteMilestoneItem(BaseModel): id: str milestone: str = "" planDate: str = "" owner: str = "" remark: str = "" status: MilestoneStatus = "未开始" class SiteEnrollmentPlanItem(BaseModel): id: str siteId: str = "" siteName: str = "" target: int = 0 startDate: str = "" endDate: str = "" note: str = "" stageBreakdown: str = "" class MonitoringStrategyItem(BaseModel): id: str strategyType: str = "" detail: str = "" frequency: str = "" updatedAt: str = "" enabled: bool = True class CenterConfirmItem(BaseModel): id: str siteId: str = "" siteName: str = "" confirmer: str = "" confirmStatus: ConfirmStatus = "待确认" confirmDate: str = "" note: str = "" class StudySetupConfigData(BaseModel): projectMilestones: list[ProjectMilestoneItem] = Field(default_factory=list) enrollmentPlan: EnrollmentPlanItem = Field(default_factory=EnrollmentPlanItem) siteMilestones: list[SiteMilestoneItem] = Field(default_factory=list) siteEnrollmentPlans: list[SiteEnrollmentPlanItem] = Field(default_factory=list) monitoringStrategies: list[MonitoringStrategyItem] = Field(default_factory=list) centerConfirm: list[CenterConfirmItem] = Field(default_factory=list) class StudySetupConfigUpsert(BaseModel): expected_version: int | None = None data: StudySetupConfigData force_draft: bool = False class StudySetupConfigPublish(BaseModel): expected_version: int | None = None class StudySetupConfigRollback(BaseModel): expected_version: int | None = None target_version: int class StudySetupConfigCheckoutBranch(BaseModel): expected_version: int | None = None target_version: int class StudySetupConfigDraftAction(BaseModel): expected_version: int | None = None class StudySetupConfigMergeToMain(BaseModel): expected_version: int | None = None source_version: int class StudySetupConfigVersionRead(BaseModel): id: uuid.UUID study_id: uuid.UUID study_setup_config_id: uuid.UUID version: int display_version: int branch_name: str = "main" branch_seq: int = 1 version_label: str = "" source_version: int | None = None parent_version_id: uuid.UUID | None = None merged_from_version_id: uuid.UUID | None = None config: StudySetupConfigData published_project_snapshot: "ProjectPublishSnapshot | None" = None is_current_published: bool = False is_active_draft_base: bool = False published_by: uuid.UUID | None = None published_by_name: str | None = None published_at: datetime created_at: datetime model_config = ConfigDict(from_attributes=True) class SetupProjectionSkippedItem(BaseModel): site_id: str reason: str class SetupProjectionSummary(BaseModel): study_updated: bool = False site_updated_count: int = 0 site_skipped_count: int = 0 warnings: list[str] = Field(default_factory=list) skipped_items: list[SetupProjectionSkippedItem] = Field(default_factory=list) class ProjectPublishSnapshot(BaseModel): code: str = "" name: str = "" project_full_name: str = "" sponsor: str = "" protocol_no: str = "" lead_unit: str = "" principal_investigator: str = "" main_pm: str = "" research_analysis: str = "" research_product: str = "" control_product: str = "" indication: str = "" research_population: str = "" research_design: str = "" plan_start_date: str = "" plan_end_date: str = "" planned_site_count: int | None = None planned_enrollment_count: int | None = None summary_note: str = "" objective_note: str = "" status: str = "" visit_interval_days: int | None = None visit_total: int | None = None visit_window_start_offset: int | None = None visit_window_end_offset: int | None = None class StudySetupConfigRead(BaseModel): id: uuid.UUID study_id: uuid.UUID version: int current_branch_name: str = "main" current_published_version_id: uuid.UUID | None = None current_published_version_label: str | None = None active_branch_base_version_id: uuid.UUID | None = None active_branch_base_version_label: str | None = None data: StudySetupConfigData publish_status: str published_data: StudySetupConfigData | None = None published_project_snapshot: ProjectPublishSnapshot | None = None published_by: uuid.UUID | None = None published_by_name: str | None = None published_at: datetime | None = None saved_by: uuid.UUID | None saved_by_name: str | None = None projection_status: str | None = None projection_summary: SetupProjectionSummary | None = None created_at: datetime updated_at: datetime model_config = ConfigDict(from_attributes=True)