from pydantic import BaseModel, Field, field_validator from datetime import datetime, date from typing import Optional, List # ============ 习惯分组 Schemas ============ class HabitGroupBase(BaseModel): """习惯分组基础模型""" name: str = Field(..., max_length=100) color: str = Field(default="#FFB7C5", max_length=20) icon: str = Field(default="flag", max_length=50) sort_order: int = Field(default=0) class HabitGroupCreate(HabitGroupBase): """创建习惯分组请求模型""" pass class HabitGroupUpdate(BaseModel): """更新习惯分组请求模型""" name: Optional[str] = Field(None, max_length=100) color: Optional[str] = Field(None, max_length=20) icon: Optional[str] = Field(None, max_length=50) sort_order: Optional[int] = None class HabitGroupResponse(HabitGroupBase): """习惯分组响应模型""" id: int class Config: from_attributes = True # ============ 习惯 Schemas ============ class HabitBase(BaseModel): """习惯基础模型""" name: str = Field(..., max_length=200) description: Optional[str] = None group_id: Optional[int] = None target_count: int = Field(default=1, ge=1) frequency: str = Field(default="daily", pattern="^(daily|weekly)$") active_days: Optional[str] = None class HabitCreate(HabitBase): """创建习惯请求模型""" pass class HabitUpdate(BaseModel): """更新习惯请求模型""" name: Optional[str] = Field(None, max_length=200) description: Optional[str] = None group_id: Optional[int] = None target_count: Optional[int] = Field(None, ge=1) frequency: Optional[str] = Field(None, pattern="^(daily|weekly)$") active_days: Optional[str] = None @property def clearable_fields(self) -> set: return {"description", "group_id", "active_days"} class HabitResponse(HabitBase): """习惯响应模型""" id: int is_archived: bool created_at: datetime updated_at: datetime group: Optional[HabitGroupResponse] = None class Config: from_attributes = True # ============ 打卡 Schemas ============ class CheckinCreate(BaseModel): """打卡请求模型""" count: Optional[int] = Field(default=1, ge=1) class CheckinResponse(BaseModel): """打卡记录响应模型""" id: int habit_id: int checkin_date: date count: int created_at: datetime class Config: from_attributes = True class HabitStatsResponse(BaseModel): """习惯统计响应模型""" total_days: int = 0 current_streak: int = 0 longest_streak: int = 0 today_count: int = 0 today_completed: bool = False