# Pydantic Schema - 使用字段编码并支持 camelCase from typing import Optional, List from pydantic import BaseModel, EmailStr, Field, ConfigDict from datetime import datetime # ============ 用户相关 ============ class UserBase(BaseModel): f01_01_name: str = Field(..., min_length=3, max_length=255, alias="username") email: Optional[EmailStr] = None phone: Optional[str] = None avatar: Optional[str] = None address: Optional[str] = None bio: Optional[str] = None model_config = ConfigDict(from_attributes=True, populate_by_name=True) class UserCreate(UserBase): password: str = Field(..., min_length=6) invite_code: Optional[str] = Field(None, alias="inviteCode") # 填写的邀请码(选填) # 移除手机号和短信验证(2026-06-13) class UserUpdate(BaseModel): f01_01_name: Optional[str] = Field(None, alias="username") email: Optional[EmailStr] = None phone: Optional[str] = None avatar: Optional[str] = None address: Optional[str] = None bio: Optional[str] = None password: Optional[str] = None model_config = ConfigDict(from_attributes=True, populate_by_name=True) class UserResponse(UserBase): # 新增字段 f99_94_level: Optional[str] = Field(None, alias="level") f99_95_ai_count: Optional[int] = Field(0, alias="aiCount") f99_96_search_count: Optional[int] = Field(0, alias="searchCount") f99_97_collection_count: Optional[int] = Field(0, alias="collectionCount") f01_06_phone_verified: Optional[bool] = Field(False, alias="phoneVerified") f99_98_login_count: Optional[int] = Field(0, alias="loginCount") f99_99_last_login: Optional[datetime] = Field(None, alias="lastLogin") f01_07_gender: Optional[str] = Field(None, alias="gender") f01_08_birthday: Optional[datetime] = Field(None, alias="birthday") f01_09_region: Optional[str] = Field(None, alias="region") f01_10_realname_verified: Optional[bool] = Field(False, alias="realnameVerified") f99_100_points: Optional[int] = Field(0, alias="points") f01_11_balance: Optional[float] = Field(0, alias="balance") f01_12_total_amount: Optional[float] = Field(0, alias="totalAmount") f01_13_invite_code: Optional[str] = Field(None, alias="inviteCode") f99_101_invited_count: Optional[int] = Field(0, alias="invitedCount") f99_90_id: str = Field(..., alias="id") f01_01_name: str = Field(..., alias="username") role: str user_code: Optional[str] = None f99_92_created_at: Optional[datetime] = Field(None, alias="created_at") f99_93_updated_at: Optional[datetime] = Field(None, alias="updated_at") model_config = ConfigDict(from_attributes=True, populate_by_name=True) # ============ 藏品相关 ============ class CollectionBase(BaseModel): # f01 基本信息 f01_01_name: str = Field(..., min_length=2, max_length=255, alias="name") f01_02_code: Optional[str] = Field(None, max_length=50, alias="code") f01_03_category: str = Field(..., max_length=100, alias="category") f01_04_status: Optional[str] = Field("in_collection", alias="status") f01_05_remark: Optional[str] = Field(None, alias="remark") # f02 详细字段 f02_10_prefix_serial: Optional[str] = Field(None, alias="prefixSerial") f02_11_version: Optional[str] = Field(None, alias="version") f02_12_packaging: Optional[str] = Field(None, alias="packaging") f02_13_rarity: Optional[str] = Field(None, alias="rarity") f02_14_number_category: Optional[str] = Field(None, alias="numberCategory") # f03 评级信息 f03_20_is_graded: Optional[bool] = Field(False, alias="isGraded") f03_21_grading_company: Optional[str] = Field(None, alias="gradingCompany") f03_22_grading_score: Optional[str] = Field(None, alias="gradingScore") f03_23_three_star: Optional[bool] = Field(False, alias="threeStar") # f04 特殊信息 f04_30_special_mark: Optional[str] = Field(None, alias="specialMark") f04_31_serial_feature: Optional[str] = Field(None, alias="serialFeature") f04_32_issuer: Optional[str] = Field(None, alias="issuer") f04_33_issue_year: Optional[str] = Field(None, alias="issueYear") f04_34_material: Optional[str] = Field(None, alias="material") f04_35_denomination: Optional[str] = Field(None, alias="denomination") f04_36_issue_quantity: Optional[str] = Field(None, alias="issueQuantity") # f05 价格信息 f05_40_cost_price: Optional[float] = Field(None, ge=0, alias="costPrice") f05_41_target_price: Optional[float] = Field(None, ge=0, alias="targetPrice") f05_42_goal_price: Optional[float] = Field(None, ge=0, alias="goalPrice") f05_43_repair_fee: Optional[float] = Field(None, ge=0, alias="repairFee") f05_44_grading_fee: Optional[float] = Field(None, ge=0, alias="gradingFee") # f06 其他信息 f06_50_purpose: Optional[str] = Field(None, alias="purpose") model_config = ConfigDict(from_attributes=True, populate_by_name=True) class CollectionCreate(CollectionBase): pass class CollectionUpdate(BaseModel): # f01 基本信息 f01_01_name: Optional[str] = Field(None, alias="name") f01_02_code: Optional[str] = Field(None, alias="code") f01_03_category: Optional[str] = Field(None, alias="category") f01_04_status: Optional[str] = Field(None, alias="status") f01_05_remark: Optional[str] = Field(None, alias="remark") # f02 详细字段 f02_10_prefix_serial: Optional[str] = Field(None, alias="prefixSerial") f02_11_version: Optional[str] = Field(None, alias="version") f02_12_packaging: Optional[str] = Field(None, alias="packaging") f02_13_rarity: Optional[str] = Field(None, alias="rarity") f02_14_number_category: Optional[str] = Field(None, alias="numberCategory") # f03 评级信息 f03_20_is_graded: Optional[bool] = Field(None, alias="isGraded") f03_21_grading_company: Optional[str] = Field(None, alias="gradingCompany") f03_22_grading_score: Optional[str] = Field(None, alias="gradingScore") f03_23_three_star: Optional[bool] = Field(None, alias="threeStar") # f04 特殊信息 f04_30_special_mark: Optional[str] = Field(None, alias="specialMark") f04_31_serial_feature: Optional[str] = Field(None, alias="serialFeature") f04_32_issuer: Optional[str] = Field(None, alias="issuer") f04_33_issue_year: Optional[str] = Field(None, alias="issueYear") f04_34_material: Optional[str] = Field(None, alias="material") f04_35_denomination: Optional[str] = Field(None, alias="denomination") f04_36_issue_quantity: Optional[str] = Field(None, alias="issueQuantity") # f05 价格信息 f05_40_cost_price: Optional[float] = Field(None, ge=0, alias="costPrice") f05_41_target_price: Optional[float] = Field(None, ge=0, alias="targetPrice") f05_42_goal_price: Optional[float] = Field(None, ge=0, alias="goalPrice") f05_43_repair_fee: Optional[float] = Field(None, ge=0, alias="repairFee") f05_44_grading_fee: Optional[float] = Field(None, ge=0, alias="gradingFee") # f06 其他信息 f06_50_purpose: Optional[str] = Field(None, alias="purpose") model_config = ConfigDict(from_attributes=True, populate_by_name=True) class CollectionImageResponse(BaseModel): f99_90_id: str filename: str original_name: Optional[str] = None path: Optional[str] = None f99_92_created_at: Optional[datetime] = None model_config = ConfigDict(from_attributes=True) class CollectionResponse(CollectionBase): f99_90_id: str = Field(..., alias="id") f99_91_user_id: str = Field(..., alias="userId") f99_92_created_at: Optional[datetime] = Field(None, alias="createdAt") f99_93_updated_at: Optional[datetime] = Field(None, alias="updatedAt") images: List[CollectionImageResponse] = [] model_config = ConfigDict(from_attributes=True, populate_by_name=True) class CollectionListResponse(BaseModel): data: List[CollectionResponse] pagination: dict # ============ 操作日志相关 ============ class OperationBase(BaseModel): type: str = Field(..., max_length=50) price: Optional[float] = None note: Optional[str] = None class OperationCreate(OperationBase): f99_91_user_id: str class OperationResponse(OperationBase): f99_90_id: str f99_91_user_id: str f99_93_created_at: Optional[datetime] = None model_config = ConfigDict(from_attributes=True) # ============ OCR 相关 ============ class OCRRequest(BaseModel): image: str ocr_provider: Optional[str] = "aliyun" class OCRResponse(BaseModel): text: str confidence: float fields: Optional[dict] = None # ============ 通用响应 ============ class Token(BaseModel): access_token: str token_type: str = "bearer" class TokenData(BaseModel): f99_90_user_id: Optional[str] = None class MessageResponse(BaseModel): message: str class ErrorResponse(BaseModel): detail: str