"""资产相关 Schema(请求/响应模型) 设计说明: - *In 系列:详情表输入模型(不含 id/asset_id,由服务端填充) - AssetCreate/AssetUpdate:主表字段 + 按类型嵌套的可选 detail - AssetRead:完整输出,含计算字段 days_to_expiry(距到期天数) """ from datetime import date, datetime from typing import Optional from sqlmodel import SQLModel from app.models.asset import AssetStatus, AssetType # --------------------------------------------------------------------------- # # 详情表输入模型 # --------------------------------------------------------------------------- # class VPSDetailIn(SQLModel): """VPS 详情输入""" ip_address: str tailscale_ip: Optional[str] = None region: Optional[str] = None os: Optional[str] = None cpu_cores: int = 1 memory_gb: float = 1 disk_gb: int = 20 bandwidth_gb: Optional[int] = None ssh_port: int = 22 panel_url: Optional[str] = None ssh_user: Optional[str] = None login_method: Optional[str] = "key" ssh_key: Optional[str] = None # 明文输入,服务端加密存储 password: Optional[str] = None # 明文输入,服务端加密存储 purpose: Optional[str] = None class DomainDetailIn(SQLModel): """域名详情输入""" domain_name: str registrar: Optional[str] = None dns_provider: Optional[str] = None cloudflare_account: Optional[str] = None is_using: bool = True redirect_target: Optional[str] = None bind_asset_id: Optional[int] = None class AIAccountIn(SQLModel): """AI 账号详情输入""" provider: str api_key: Optional[str] = None plan: Optional[str] = None balance: Optional[float] = None currency: str = "USD" monthly_usage: Optional[float] = None monthly_limit: Optional[float] = None # --------------------------------------------------------------------------- # # 资产主表模型 # --------------------------------------------------------------------------- # class AssetBase(SQLModel): """资产主表公共字段""" name: str asset_type: AssetType provider: str provider_id: Optional[int] = None renewal_cycle: Optional[str] = None renew_url: Optional[str] = None cancel_url: Optional[str] = None account: Optional[str] = None expiry_date: Optional[date] = None auto_renew: bool = False cost: float = 0 currency: str = "USD" status: AssetStatus = AssetStatus.ACTIVE is_archived: bool = False remark: Optional[str] = None class AssetCreate(AssetBase): """创建资产:按 asset_type 携带对应 detail""" vps_detail: Optional[VPSDetailIn] = None domain_detail: Optional[DomainDetailIn] = None ai_detail: Optional[AIAccountIn] = None class AssetUpdate(SQLModel): """更新资产:所有字段可选,仅更新传入项""" name: Optional[str] = None asset_type: Optional[AssetType] = None provider: Optional[str] = None provider_id: Optional[int] = None renewal_cycle: Optional[str] = None renew_url: Optional[str] = None cancel_url: Optional[str] = None account: Optional[str] = None expiry_date: Optional[date] = None auto_renew: Optional[bool] = None cost: Optional[float] = None currency: Optional[str] = None status: Optional[AssetStatus] = None is_archived: Optional[bool] = None remark: Optional[str] = None vps_detail: Optional[VPSDetailIn] = None domain_detail: Optional[DomainDetailIn] = None ai_detail: Optional[AIAccountIn] = None # --------------------------------------------------------------------------- # # 输出模型 # --------------------------------------------------------------------------- # class VPSDetailRead(SQLModel): """VPS 详情输出(不含敏感明文,仅返回凭证存在标记)""" id: int asset_id: int ip_address: str tailscale_ip: Optional[str] = None region: Optional[str] = None os: Optional[str] = None cpu_cores: int = 1 memory_gb: float = 1 disk_gb: int = 20 bandwidth_gb: Optional[int] = None ssh_port: int = 22 panel_url: Optional[str] = None ssh_user: Optional[str] = None login_method: Optional[str] = "key" purpose: Optional[str] = None has_ssh_key: bool = False has_password: bool = False class DomainDetailRead(DomainDetailIn): id: int asset_id: int class AIAccountRead(SQLModel): """AI 账号输出(不暴露 API Key 明文,仅返回 has_api_key)""" id: int asset_id: int provider: str plan: Optional[str] = None balance: Optional[float] = None currency: str = "USD" monthly_usage: Optional[float] = None monthly_limit: Optional[float] = None last_synced_at: Optional[datetime] = None has_api_key: bool = False class AssetRead(AssetBase): """资产完整输出""" id: int created_at: datetime updated_at: datetime days_to_expiry: Optional[int] = None provider_name: Optional[str] = None vps_detail: Optional[VPSDetailRead] = None domain_detail: Optional[DomainDetailRead] = None ai_detail: Optional[AIAccountRead] = None