feat: 资产 CRUD API + 统计接口 + Vue3 管理前端(可选 API Key 鉴权)
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
"""资产相关 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
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
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
|
||||
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
|
||||
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(VPSDetailIn):
|
||||
id: int
|
||||
asset_id: int
|
||||
|
||||
|
||||
class DomainDetailRead(DomainDetailIn):
|
||||
id: int
|
||||
asset_id: int
|
||||
|
||||
|
||||
class AIAccountRead(AIAccountIn):
|
||||
id: int
|
||||
asset_id: int
|
||||
last_synced_at: Optional[datetime] = None
|
||||
|
||||
|
||||
class AssetRead(AssetBase):
|
||||
"""资产完整输出"""
|
||||
|
||||
id: int
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
days_to_expiry: Optional[int] = None
|
||||
vps_detail: Optional[VPSDetailRead] = None
|
||||
domain_detail: Optional[DomainDetailRead] = None
|
||||
ai_detail: Optional[AIAccountRead] = None
|
||||
Reference in New Issue
Block a user