""" 資料模型定義 (Data Schemas) 本模組定義 TimeLine Designer 所有資料結構。 遵循 Pydantic BaseModel 進行嚴格型別驗證。 """ from datetime import datetime from typing import Optional, Literal, List from pydantic import BaseModel, Field, field_validator from enum import Enum class EventType(str, Enum): """事件類型枚舉""" POINT = "point" # 時間點事件 RANGE = "range" # 時間區間事件 MILESTONE = "milestone" # 里程碑 class Event(BaseModel): """ 時間軸事件模型 對應 SDD.md - 2. 資料模型 - Event 用於表示時間軸上的單一事件或時間區間。 """ id: str = Field(..., description="事件唯一識別碼") title: str = Field(..., min_length=1, max_length=200, description="事件標題") start: datetime = Field(..., description="開始時間") end: Optional[datetime] = Field(None, description="結束時間(可選)") group: Optional[str] = Field(None, description="事件群組/分類") description: Optional[str] = Field(None, max_length=1000, description="事件詳細描述") color: str = Field(default='#3B82F6', pattern=r'^#[0-9A-Fa-f]{6}$', description="事件顏色(HEX格式)") event_type: EventType = Field(EventType.POINT, description="事件類型") @field_validator('end') @classmethod def validate_end_after_start(cls, end, info): """驗證結束時間必須晚於開始時間""" if end and info.data.get('start') and end < info.data['start']: raise ValueError('結束時間必須晚於開始時間') return end class Config: json_schema_extra = { "example": { "id": "evt-001", "title": "專案啟動", "start": "2024-01-01T09:00:00", "end": "2024-01-01T17:00:00", "group": "Phase 1", "description": "專案正式啟動會議", "color": "#3B82F6", "event_type": "range" } } class ThemeStyle(str, Enum): """主題樣式枚舉""" MODERN = "modern" CLASSIC = "classic" MINIMAL = "minimal" CORPORATE = "corporate" class TimelineConfig(BaseModel): """ 時間軸配置模型 對應 SDD.md - 2. 資料模型 - TimelineConfig 控制時間軸的顯示方式與視覺樣式。 """ direction: Literal['horizontal', 'vertical'] = Field( 'horizontal', description="時間軸方向" ) theme: ThemeStyle = Field( ThemeStyle.MODERN, description="視覺主題" ) show_grid: bool = Field( True, description="是否顯示網格線" ) show_tooltip: bool = Field( True, description="是否顯示提示訊息" ) enable_zoom: bool = Field( True, description="是否啟用縮放功能" ) enable_drag: bool = Field( True, description="是否啟用拖曳功能" ) class Config: json_schema_extra = { "example": { "direction": "horizontal", "theme": "modern", "show_grid": True, "show_tooltip": True, "enable_zoom": True, "enable_drag": True } } class ExportFormat(str, Enum): """匯出格式枚舉""" PNG = "png" PDF = "pdf" SVG = "svg" class ExportOptions(BaseModel): """ 匯出選項模型 對應 SDD.md - 2. 資料模型 - ExportOptions 控制時間軸圖檔的匯出格式與品質。 """ fmt: ExportFormat = Field(..., description="匯出格式") dpi: int = Field( 300, ge=72, le=600, description="解析度(DPI)" ) width: Optional[int] = Field( 1920, ge=800, le=4096, description="圖片寬度(像素)" ) height: Optional[int] = Field( 1080, ge=600, le=4096, description="圖片高度(像素)" ) transparent_background: bool = Field( False, description="是否使用透明背景" ) class Config: json_schema_extra = { "example": { "fmt": "pdf", "dpi": 300, "width": 1920, "height": 1080, "transparent_background": False } } class Theme(BaseModel): """ 主題定義模型 用於 /themes API 回傳主題列表。 """ name: str = Field(..., description="主題名稱") style: ThemeStyle = Field(..., description="主題樣式識別碼") primary_color: str = Field(..., pattern=r'^#[0-9A-Fa-f]{6}$', description="主要顏色") background_color: str = Field(..., pattern=r'^#[0-9A-Fa-f]{6}$', description="背景顏色") text_color: str = Field(..., pattern=r'^#[0-9A-Fa-f]{6}$', description="文字顏色") class Config: json_schema_extra = { "example": { "name": "現代風格", "style": "modern", "primary_color": "#3B82F6", "background_color": "#FFFFFF", "text_color": "#1F2937" } } class ImportResult(BaseModel): """ 匯入結果模型 用於 /import API 回傳匯入結果。 """ success: bool = Field(..., description="是否成功") events: List[Event] = Field(default_factory=list, description="成功匯入的事件列表") errors: List[str] = Field(default_factory=list, description="錯誤訊息列表") total_rows: int = Field(0, description="總行數") imported_count: int = Field(0, description="成功匯入數量") class Config: json_schema_extra = { "example": { "success": True, "events": [], "errors": [], "total_rows": 100, "imported_count": 98 } } class RenderResult(BaseModel): """ 渲染結果模型 用於 /render API 回傳 Plotly JSON 格式的時間軸資料。 """ success: bool = Field(..., description="是否成功") data: dict = Field(..., description="Plotly 圖表資料(JSON格式)") layout: dict = Field(..., description="Plotly 佈局設定") config: dict = Field(default_factory=dict, description="Plotly 配置") class Config: json_schema_extra = { "example": { "success": True, "data": {}, "layout": {}, "config": {} } } class APIResponse(BaseModel): """ 通用 API 回應模型 用於標準化 API 回應格式,提供一致的錯誤處理。 """ success: bool = Field(..., description="操作是否成功") message: str = Field("", description="回應訊息") data: Optional[dict] = Field(None, description="回應資料") error_code: Optional[str] = Field(None, description="錯誤代碼(如有)") class Config: json_schema_extra = { "example": { "success": True, "message": "操作成功", "data": None, "error_code": None } }