feat: 订阅/付费管理(续费/取消网址+订阅视图+月度年度支出统计)

This commit is contained in:
gouki
2026-08-02 21:01:34 +00:00
parent 99349875ae
commit e53361d1e4
4 changed files with 89 additions and 3 deletions
+4
View File
@@ -60,6 +60,10 @@ def _migrate_assets_db() -> None:
cols = {c["name"] for c in insp.get_columns("assets")}
if "external_id" not in cols:
conn.execute(sa.text("ALTER TABLE assets ADD COLUMN external_id VARCHAR"))
if "renew_url" not in cols:
conn.execute(sa.text("ALTER TABLE assets ADD COLUMN renew_url VARCHAR"))
if "cancel_url" not in cols:
conn.execute(sa.text("ALTER TABLE assets ADD COLUMN cancel_url VARCHAR"))
if insp.has_table("providers"):
cols = {c["name"] for c in insp.get_columns("providers")}
if "last_synced_at" not in cols:
+6
View File
@@ -52,6 +52,12 @@ class Asset(SQLModel, table=True):
renewal_cycle: Optional[str] = Field(
default=None, description="续费周期:monthly/quarterly/yearly"
)
renew_url: Optional[str] = Field(
default=None, description="续费网址(去哪续费)"
)
cancel_url: Optional[str] = Field(
default=None, description="取消订阅网址(去哪取消)"
)
account: Optional[str] = Field(
default=None, description="所属账号标识(如 Cloudflare 账号邮箱)"
)
+4
View File
@@ -72,6 +72,8 @@ class AssetBase(SQLModel):
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
@@ -98,6 +100,8 @@ class AssetUpdate(SQLModel):
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