From 17577ff734c941e302c864e9a3bd6bed80ec99b9 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Sun, 30 Aug 2026 19:44:01 +0800 Subject: [PATCH] =?UTF-8?q?type:=20=E6=B8=90=E8=BF=9B=E5=BC=8F=E6=8E=A5?= =?UTF-8?q?=E5=85=A5=20Pyright=20=E5=B9=B6=E7=B1=BB=E5=9E=8B=E5=8C=96=20OR?= =?UTF-8?q?M=20=E6=A8=A1=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .githooks/pre-push | 6 + README.md | 8 +- dev.sh | 5 + pyproject.toml | 1 + pyrightconfig.json | 14 + scripts/install-git-hooks.sh | 2 +- uv.lock | 24 ++ web/backend/models.py | 666 ++++++++++++++++++++--------------- 8 files changed, 431 insertions(+), 295 deletions(-) create mode 100644 pyrightconfig.json diff --git a/.githooks/pre-push b/.githooks/pre-push index cbeaa60..a7b068c 100755 --- a/.githooks/pre-push +++ b/.githooks/pre-push @@ -38,6 +38,12 @@ if [ "${#python_files[@]}" -gt 0 ]; then echo "[pre-push] Python 格式通过" fi +if [ "${TYPECHECK:-0}" = "1" ]; then + echo "[pre-push] 运行 Pyright 类型检查..." + uv run --group dev pyright + echo "[pre-push] Pyright 通过" +fi + echo "[pre-push] 运行 pytest..." ./dev.sh test -q echo "[pre-push] pytest 通过" diff --git a/README.md b/README.md index 1fae1cf..dacc8cb 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,9 @@ uv run --group dev pytest tests/test_cookie_operations.py ./dev.sh format tests conftest.py ./dev.sh format-check tests conftest.py +# 类型检查(当前为渐进式接入,先查看存量诊断) +./dev.sh type-check + # 容器内回归(镜像内为构建时代码,改动后需重新构建) docker compose --profile test run --rm test ``` @@ -135,8 +138,9 @@ docker compose --profile test run --rm test ./scripts/install-git-hooks.sh ``` -推送前自动跑全量测试,失败阻止推送(紧急绕过:`git push --no-verify` -或 `SKIP_TESTS=1 git push`)。 +推送前自动跑全量测试,失败阻止推送。需要将 Pyright 作为推送门禁时,使用 +`TYPECHECK=1 git push`;紧急绕过可使用 `git push --no-verify` 或 +`SKIP_TESTS=1 git push`。 ## 技术栈 diff --git a/dev.sh b/dev.sh index dc8ba90..a90537e 100755 --- a/dev.sh +++ b/dev.sh @@ -71,6 +71,11 @@ if [ "${1:-}" = "format-check" ]; then exec uv run --group dev ruff format --check "$@" fi +if [ "${1:-}" = "type-check" ]; then + shift + exec uv run --group dev pyright "$@" +fi + BACKEND_PID="" FRONTEND_PID="" WORKER_PID="" diff --git a/pyproject.toml b/pyproject.toml index 4949e6d..304507d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,6 +40,7 @@ testpaths = ["tests"] [dependency-groups] dev = [ + "pyright>=1.1.411", "pytest>=9.1.1", "ruff>=0.12.0", ] diff --git a/pyrightconfig.json b/pyrightconfig.json new file mode 100644 index 0000000..2a5cc81 --- /dev/null +++ b/pyrightconfig.json @@ -0,0 +1,14 @@ +{ + "include": ["core", "utils", "web", "tests"], + "exclude": [ + "**/__pycache__", + "artifacts", + "evidence", + "scripts", + "tools", + "work" + ], + "typeCheckingMode": "basic", + "reportMissingImports": "none", + "reportMissingModuleSource": "none" +} diff --git a/scripts/install-git-hooks.sh b/scripts/install-git-hooks.sh index c2ef33d..5f244cc 100755 --- a/scripts/install-git-hooks.sh +++ b/scripts/install-git-hooks.sh @@ -3,4 +3,4 @@ set -euo pipefail ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" git -C "$ROOT_DIR" config core.hooksPath .githooks -echo "已启用 .githooks(Ruff 格式检查 + pytest pre-push 门禁)" +echo "已启用 .githooks(Ruff 格式检查 + pytest pre-push 门禁;TYPECHECK=1 可启用 Pyright)" diff --git a/uv.lock b/uv.lock index 9feb71e..9b316af 100644 --- a/uv.lock +++ b/uv.lock @@ -254,6 +254,7 @@ dependencies = [ [package.dev-dependencies] dev = [ + { name = "pyright" }, { name = "pytest" }, { name = "ruff" }, ] @@ -285,6 +286,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ + { name = "pyright", specifier = ">=1.1.411" }, { name = "pytest", specifier = ">=9.1.1" }, { name = "ruff", specifier = ">=0.12.0" }, ] @@ -427,6 +429,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, ] +[[package]] +name = "nodeenv" +version = "1.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, +] + [[package]] name = "numpy" version = "2.4.6" @@ -643,6 +654,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c4/bd/2534e130295c8cfd4f0a2e31623baab7502278f1e97bcfe61db75656a77f/pymysql-1.2.0-py3-none-any.whl", hash = "sha256:62169ce6d5510f08e140c5e7990ee884a9764024e4a9a27b2cc11f1099322ae0", size = 45716, upload-time = "2026-05-19T08:26:20.974Z" }, ] +[[package]] +name = "pyright" +version = "1.1.411" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nodeenv" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7e/ab/265f7dc69d28113ebba19092e57b075f41543b2ed048429c5f56e2b88eac/pyright-1.1.411.tar.gz", hash = "sha256:d885a0551f2e763b089a02702174e7f4ba77548cddabc972ab86d1f7f1b0f998", size = 4112861, upload-time = "2026-06-25T02:14:06.37Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/49/385be530a6a5b78d1cbcd5c2e38debc8959a2fc6bdb716f4e581002979fc/pyright-1.1.411-py3-none-any.whl", hash = "sha256:dc7c72a8e2700c55baa127554040e067041ea53ccfd50bf96308cc4291c7d5d9", size = 6181526, upload-time = "2026-06-25T02:14:04.691Z" }, +] + [[package]] name = "pysocks" version = "1.7.1" diff --git a/web/backend/models.py b/web/backend/models.py index cab9fb3..05fcda0 100644 --- a/web/backend/models.py +++ b/web/backend/models.py @@ -1,5 +1,7 @@ """ORM 模型""" +from __future__ import annotations + from datetime import datetime, timezone from sqlalchemy import ( Column, @@ -12,7 +14,7 @@ from sqlalchemy import ( JSON, UniqueConstraint, ) -from sqlalchemy.orm import relationship +from sqlalchemy.orm import Mapped, mapped_column, relationship from .database import Base from .crypto_storage import EncryptedText from .huya_defaults import ( @@ -34,27 +36,33 @@ class User(Base): __tablename__ = "users" - id = Column(Integer, primary_key=True, autoincrement=True) - username = Column(String(64), unique=True, nullable=False, index=True) - password_hash = Column(String(256), nullable=False) - role = Column( + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + username: Mapped[str] = mapped_column( + String(64), unique=True, nullable=False, index=True + ) + password_hash: Mapped[str] = mapped_column(String(256), nullable=False) + role: Mapped[str] = mapped_column( String(32), nullable=False, default="support" ) # super_admin / operation / support - is_active = Column(Boolean, default=True) - remark = Column(String(256), default="") - custom_permissions = Column( + is_active: Mapped[bool] = mapped_column(Boolean, default=True) + remark: Mapped[str] = mapped_column(String(256), default="") + custom_permissions: Mapped[list[str] | None] = mapped_column( JSON, nullable=True, comment="自定义权限列表,null表示使用角色默认权限" ) - created_at = Column(DateTime, default=_utcnow) - updated_at = Column(DateTime, default=_utcnow, onupdate=_utcnow) - deleted_at = Column(DateTime, nullable=True, index=True) - deleted_username = Column(String(64), default="") + created_at: Mapped[datetime] = mapped_column(DateTime, default=_utcnow) + updated_at: Mapped[datetime] = mapped_column( + DateTime, default=_utcnow, onupdate=_utcnow + ) + deleted_at: Mapped[datetime | None] = mapped_column( + DateTime, nullable=True, index=True + ) + deleted_username: Mapped[str] = mapped_column(String(64), default="") # 客服被分配的账号 - assigned_accounts = relationship( + assigned_accounts: Mapped[list[Account]] = relationship( "Account", back_populates="assigned_user", foreign_keys="Account.assigned_to" ) - huya_accounts = relationship( + huya_accounts: Mapped[list[HuyaAccount]] = relationship( "HuyaAccount", back_populates="assigned_user", foreign_keys="HuyaAccount.assigned_to", @@ -66,48 +74,58 @@ class Account(Base): __tablename__ = "accounts" - id = Column(Integer, primary_key=True, autoincrement=True) - username = Column(String(128), nullable=False) - password = Column(EncryptedText(), nullable=False) - email = Column(EncryptedText(), nullable=False) - email_password = Column(EncryptedText(), nullable=False) - email_imap_server = Column(String(128), default="") - email_imap_port = Column(Integer, default=993) - email_imap_ssl = Column(Boolean, default=True) - assigned_to = Column(Integer, ForeignKey("users.id"), nullable=True, index=True) - tag = Column(String(64), default="") - remark = Column(String(256), default="") - uid = Column(String(32), default="", index=True) - nickname = Column(String(128), default="") - points = Column(Integer, nullable=True) - game_name = Column(String(128), default="") - game_channel = Column(String(128), default="") - gold_balance = Column(Integer, nullable=True) - exchange_balance = Column(Integer, nullable=True) - bind_status = Column(String(32), default="") - change_role_wait_time = Column(Integer, nullable=True) - esports_points = Column(Integer, nullable=True) - esports_game_name = Column(String(128), default="") - esports_game_channel = Column(String(128), default="") - esports_bind_status = Column(String(32), default="") - esports_change_role_wait_time = Column(Integer, nullable=True) - esports_can_change_time = Column(Integer, nullable=True) - xpd_game_name = Column(String(128), default="") - xpd_openid = Column(String(128), default="") - xpd_role_id = Column(String(64), default="") - xpd_plat_id = Column(Integer, nullable=True) - xpd_area_id = Column(Integer, nullable=True) - xpd_balance = Column(Integer, nullable=True) - xpd_fragments = Column(Integer, nullable=True) - xpd_bind_status = Column(String(32), default="") - created_at = Column(DateTime, default=_utcnow) - updated_at = Column(DateTime, default=_utcnow, onupdate=_utcnow) + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + username: Mapped[str] = mapped_column(String(128), nullable=False) + password: Mapped[str] = mapped_column(EncryptedText(), nullable=False) + email: Mapped[str] = mapped_column(EncryptedText(), nullable=False) + email_password: Mapped[str] = mapped_column(EncryptedText(), nullable=False) + email_imap_server: Mapped[str] = mapped_column(String(128), default="") + email_imap_port: Mapped[int] = mapped_column(Integer, default=993) + email_imap_ssl: Mapped[bool] = mapped_column(Boolean, default=True) + assigned_to: Mapped[int | None] = mapped_column( + ForeignKey("users.id"), nullable=True, index=True + ) + tag: Mapped[str] = mapped_column(String(64), default="") + remark: Mapped[str] = mapped_column(String(256), default="") + uid: Mapped[str] = mapped_column(String(32), default="", index=True) + nickname: Mapped[str] = mapped_column(String(128), default="") + points: Mapped[int | None] = mapped_column(Integer, nullable=True) + game_name: Mapped[str] = mapped_column(String(128), default="") + game_channel: Mapped[str] = mapped_column(String(128), default="") + gold_balance: Mapped[int | None] = mapped_column(Integer, nullable=True) + exchange_balance: Mapped[int | None] = mapped_column(Integer, nullable=True) + bind_status: Mapped[str] = mapped_column(String(32), default="") + change_role_wait_time: Mapped[int | None] = mapped_column(Integer, nullable=True) + esports_points: Mapped[int | None] = mapped_column(Integer, nullable=True) + esports_game_name: Mapped[str] = mapped_column(String(128), default="") + esports_game_channel: Mapped[str] = mapped_column(String(128), default="") + esports_bind_status: Mapped[str] = mapped_column(String(32), default="") + esports_change_role_wait_time: Mapped[int | None] = mapped_column( + Integer, nullable=True + ) + esports_can_change_time: Mapped[int | None] = mapped_column(Integer, nullable=True) + xpd_game_name: Mapped[str] = mapped_column(String(128), default="") + xpd_openid: Mapped[str] = mapped_column(String(128), default="") + xpd_role_id: Mapped[str] = mapped_column(String(64), default="") + xpd_plat_id: Mapped[int | None] = mapped_column(Integer, nullable=True) + xpd_area_id: Mapped[int | None] = mapped_column(Integer, nullable=True) + xpd_balance: Mapped[int | None] = mapped_column(Integer, nullable=True) + xpd_fragments: Mapped[int | None] = mapped_column(Integer, nullable=True) + xpd_bind_status: Mapped[str] = mapped_column(String(32), default="") + created_at: Mapped[datetime] = mapped_column(DateTime, default=_utcnow) + updated_at: Mapped[datetime] = mapped_column( + DateTime, default=_utcnow, onupdate=_utcnow + ) - assigned_user = relationship( + assigned_user: Mapped[User | None] = relationship( "User", back_populates="assigned_accounts", foreign_keys=[assigned_to] ) - login_tasks = relationship("LoginTask", back_populates="account") - douyu_tasks = relationship("DouyuTask", back_populates="account") + login_tasks: Mapped[list[LoginTask]] = relationship( + "LoginTask", back_populates="account" + ) + douyu_tasks: Mapped[list[DouyuTask]] = relationship( + "DouyuTask", back_populates="account" + ) class LoginTask(Base): @@ -115,25 +133,29 @@ class LoginTask(Base): __tablename__ = "login_tasks" - id = Column(Integer, primary_key=True, autoincrement=True) - batch_id = Column(String(64), nullable=False, index=True) # 批次ID - account_id = Column(Integer, ForeignKey("accounts.id"), nullable=False) - status = Column( + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + batch_id: Mapped[str] = mapped_column( + String(64), nullable=False, index=True + ) # 批次ID + account_id: Mapped[int] = mapped_column(ForeignKey("accounts.id"), nullable=False) + status: Mapped[str] = mapped_column( String(32), default="pending" ) # pending / running / success / failed / error - cookie = Column(EncryptedText(), default="") - message = Column(String(512), default="") - created_by = Column(Integer, ForeignKey("users.id"), nullable=False) - created_at = Column(DateTime, default=_utcnow) - finished_at = Column(DateTime, nullable=True) + cookie: Mapped[str] = mapped_column(EncryptedText(), default="") + message: Mapped[str] = mapped_column(String(512), default="") + created_by: Mapped[int] = mapped_column(ForeignKey("users.id"), nullable=False) + created_at: Mapped[datetime] = mapped_column(DateTime, default=_utcnow) + finished_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) # Cookie 有效性检测结果(持久化,刷新不丢失) - ck_check_status = Column(String(16), default="") # valid / invalid / 空=未检测 - ck_check_result = Column( + ck_check_status: Mapped[str] = mapped_column( + String(16), default="" + ) # valid / invalid / 空=未检测 + ck_check_result: Mapped[dict | None] = mapped_column( JSON, nullable=True ) # {fish_ball, nickname, level, message} - ck_checked_at = Column(DateTime, nullable=True) + ck_checked_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) - account = relationship("Account", back_populates="login_tasks") + account: Mapped[Account] = relationship("Account", back_populates="login_tasks") class DouyuTask(Base): @@ -141,22 +163,26 @@ class DouyuTask(Base): __tablename__ = "douyu_tasks" - id = Column(Integer, primary_key=True, autoincrement=True) - batch_id = Column(String(64), nullable=False, index=True) - account_id = Column(Integer, ForeignKey("accounts.id"), nullable=False) - task_type = Column(String(64), nullable=False, index=True) + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + batch_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True) + account_id: Mapped[int] = mapped_column(ForeignKey("accounts.id"), nullable=False) + task_type: Mapped[str] = mapped_column(String(64), nullable=False, index=True) # 任务归属工作台;避免同一账号的精英/电竞/小店任务在前端串行展示或串弹二维码。 - handbook_scope = Column(String(16), nullable=False, default="legacy", index=True) + handbook_scope: Mapped[str] = mapped_column( + String(16), nullable=False, default="legacy", index=True + ) # 供应商直充的来源订单号,用于轮询与异步回调的幂等关联。 - supplier_out_order_id = Column(String(64), nullable=True, unique=True, index=True) - status = Column(String(32), default="pending") - message = Column(String(512), default="") - result = Column(JSON, nullable=True) - created_by = Column(Integer, ForeignKey("users.id"), nullable=False) - created_at = Column(DateTime, default=_utcnow) - finished_at = Column(DateTime, nullable=True) + supplier_out_order_id: Mapped[str | None] = mapped_column( + String(64), nullable=True, unique=True, index=True + ) + status: Mapped[str] = mapped_column(String(32), default="pending") + message: Mapped[str] = mapped_column(String(512), default="") + result: Mapped[dict | None] = mapped_column(JSON, nullable=True) + created_by: Mapped[int] = mapped_column(ForeignKey("users.id"), nullable=False) + created_at: Mapped[datetime] = mapped_column(DateTime, default=_utcnow) + finished_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) - account = relationship("Account", back_populates="douyu_tasks") + account: Mapped[Account] = relationship("Account", back_populates="douyu_tasks") class DouyuWorkbenchAccount(Base): @@ -164,11 +190,15 @@ class DouyuWorkbenchAccount(Base): __tablename__ = "douyu_workbench_accounts" - id = Column(Integer, primary_key=True, autoincrement=True) - user_id = Column(Integer, ForeignKey("users.id"), nullable=False, index=True) - handbook_scope = Column(String(16), nullable=False, index=True) - account_id = Column(Integer, ForeignKey("accounts.id"), nullable=False, index=True) - created_at = Column(DateTime, default=_utcnow) + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + user_id: Mapped[int] = mapped_column( + ForeignKey("users.id"), nullable=False, index=True + ) + handbook_scope: Mapped[str] = mapped_column(String(16), nullable=False, index=True) + account_id: Mapped[int] = mapped_column( + ForeignKey("accounts.id"), nullable=False, index=True + ) + created_at: Mapped[datetime] = mapped_column(DateTime, default=_utcnow) __table_args__ = ( UniqueConstraint( @@ -182,10 +212,14 @@ class DouyuWorkbench(Base): __tablename__ = "douyu_workbenches" - id = Column(Integer, primary_key=True, autoincrement=True) - user_id = Column(Integer, ForeignKey("users.id"), nullable=False, index=True) - handbook_scope = Column(String(16), nullable=False, index=True) - updated_at = Column(DateTime, default=_utcnow, onupdate=_utcnow) + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + user_id: Mapped[int] = mapped_column( + ForeignKey("users.id"), nullable=False, index=True + ) + handbook_scope: Mapped[str] = mapped_column(String(16), nullable=False, index=True) + updated_at: Mapped[datetime] = mapped_column( + DateTime, default=_utcnow, onupdate=_utcnow + ) __table_args__ = ( UniqueConstraint("user_id", "handbook_scope", name="uq_douyu_workbench"), @@ -200,32 +234,40 @@ class YybRechargeTask(Base): __tablename__ = "yyb_recharge_tasks" - id = Column(Integer, primary_key=True, autoincrement=True) + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) # 唯一索引(uq_yyb_recharge_tasks_task_id)已覆盖 task_id 查询,无需重复普通索引; # 迁移 20260812_0020 也只建唯一索引,二者保持一致。 - task_id = Column(String(64), unique=True, nullable=False) - created_by = Column(Integer, ForeignKey("users.id"), nullable=False, index=True) - worker_job_id = Column(String(64), nullable=False, index=True) - provider = Column(String(16), default="", nullable=False) - platform = Column(String(16), default="android", nullable=False) - points = Column(Integer, nullable=True) - product_id = Column(String(128), default="") - zone_id = Column(String(64), default="") - zone_name = Column(String(128), default="") - role_id = Column(String(64), default="") - role_name = Column(String(128), default="") - price_fen = Column(Integer, nullable=True) - status = Column(String(32), default="created", nullable=False, index=True) - phase = Column(String(32), default="login", nullable=False) - message = Column(String(512), default="") - result = Column(JSON, nullable=True) - login_qr_data = Column(EncryptedText(), default="") - payment_qr_data = Column(EncryptedText(), default="") - payment_started_at = Column(DateTime, nullable=True) - payment_qr_created_at = Column(DateTime, nullable=True) - payment_last_checked_at = Column(DateTime, nullable=True) - created_at = Column(DateTime, default=_utcnow) - finished_at = Column(DateTime, nullable=True) + task_id: Mapped[str] = mapped_column(String(64), unique=True, nullable=False) + created_by: Mapped[int] = mapped_column( + ForeignKey("users.id"), nullable=False, index=True + ) + worker_job_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True) + provider: Mapped[str] = mapped_column(String(16), default="", nullable=False) + platform: Mapped[str] = mapped_column(String(16), default="android", nullable=False) + points: Mapped[int | None] = mapped_column(Integer, nullable=True) + product_id: Mapped[str] = mapped_column(String(128), default="") + zone_id: Mapped[str] = mapped_column(String(64), default="") + zone_name: Mapped[str] = mapped_column(String(128), default="") + role_id: Mapped[str] = mapped_column(String(64), default="") + role_name: Mapped[str] = mapped_column(String(128), default="") + price_fen: Mapped[int | None] = mapped_column(Integer, nullable=True) + status: Mapped[str] = mapped_column( + String(32), default="created", nullable=False, index=True + ) + phase: Mapped[str] = mapped_column(String(32), default="login", nullable=False) + message: Mapped[str] = mapped_column(String(512), default="") + result: Mapped[dict | None] = mapped_column(JSON, nullable=True) + login_qr_data: Mapped[str] = mapped_column(EncryptedText(), default="") + payment_qr_data: Mapped[str] = mapped_column(EncryptedText(), default="") + payment_started_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) + payment_qr_created_at: Mapped[datetime | None] = mapped_column( + DateTime, nullable=True + ) + payment_last_checked_at: Mapped[datetime | None] = mapped_column( + DateTime, nullable=True + ) + created_at: Mapped[datetime] = mapped_column(DateTime, default=_utcnow) + finished_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) class DouyuConfig(Base): @@ -233,31 +275,35 @@ class DouyuConfig(Base): __tablename__ = "douyu_config" - id = Column(Integer, primary_key=True, autoincrement=True) - manual_id = Column(String(64), default="G4KA4Qnz4LDp7") - rid = Column(String(64), default="9263298") - bind_act_alias = Column(String(64), default="20260120QYOOB") - confirm_act_alias = Column(String(64), default="20260120QYOOB") - legacy_act_alias = Column(String(64), default="cjm") - room_id = Column(String(64), default="9263298") - elite_amount = Column(Integer, default=3000) - esports_manual_id = Column(String(64), default="1W0yGkOdDbAXb") - esports_act_alias = Column(String(64), default="20260226ZMGDG") - esports_amount = Column(Integer, default=3000) - esports_chicken_gift_id = Column(String(64), default="24766") - esports_chicken_skin_id = Column(String(64), default="0") - esports_firework_gift_id = Column(String(64), default="24767") - esports_firework_skin_id = Column(String(64), default="3850") - xpd_act_alias = Column(String(64), default="20260623KDQFH") - xpd_act_id = Column(String(64), default="46195") - xpd_rid = Column(String(64), default="9263298") - gold_pay_type = Column(Integer, default=1) - gold_recharge_channel = Column(String(16), default="wechat_qr") - gold_api_product_id = Column(String(128), default="111570") - gold_api_account_template_name = Column(String(64), default="斗鱼昵称") - gift_id = Column(String(64), default="23643") - skin_id = Column(String(64), default="2942") - updated_at = Column(DateTime, default=_utcnow, onupdate=_utcnow) + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + manual_id: Mapped[str] = mapped_column(String(64), default="G4KA4Qnz4LDp7") + rid: Mapped[str] = mapped_column(String(64), default="9263298") + bind_act_alias: Mapped[str] = mapped_column(String(64), default="20260120QYOOB") + confirm_act_alias: Mapped[str] = mapped_column(String(64), default="20260120QYOOB") + legacy_act_alias: Mapped[str] = mapped_column(String(64), default="cjm") + room_id: Mapped[str] = mapped_column(String(64), default="9263298") + elite_amount: Mapped[int] = mapped_column(Integer, default=3000) + esports_manual_id: Mapped[str] = mapped_column(String(64), default="1W0yGkOdDbAXb") + esports_act_alias: Mapped[str] = mapped_column(String(64), default="20260226ZMGDG") + esports_amount: Mapped[int] = mapped_column(Integer, default=3000) + esports_chicken_gift_id: Mapped[str] = mapped_column(String(64), default="24766") + esports_chicken_skin_id: Mapped[str] = mapped_column(String(64), default="0") + esports_firework_gift_id: Mapped[str] = mapped_column(String(64), default="24767") + esports_firework_skin_id: Mapped[str] = mapped_column(String(64), default="3850") + xpd_act_alias: Mapped[str] = mapped_column(String(64), default="20260623KDQFH") + xpd_act_id: Mapped[str] = mapped_column(String(64), default="46195") + xpd_rid: Mapped[str] = mapped_column(String(64), default="9263298") + gold_pay_type: Mapped[int] = mapped_column(Integer, default=1) + gold_recharge_channel: Mapped[str] = mapped_column(String(16), default="wechat_qr") + gold_api_product_id: Mapped[str] = mapped_column(String(128), default="111570") + gold_api_account_template_name: Mapped[str] = mapped_column( + String(64), default="斗鱼昵称" + ) + gift_id: Mapped[str] = mapped_column(String(64), default="23643") + skin_id: Mapped[str] = mapped_column(String(64), default="2942") + updated_at: Mapped[datetime] = mapped_column( + DateTime, default=_utcnow, onupdate=_utcnow + ) class DouyuGoodsSnapshot(Base): @@ -265,13 +311,15 @@ class DouyuGoodsSnapshot(Base): __tablename__ = "douyu_goods_snapshot" - id = Column(Integer, primary_key=True, autoincrement=True) - commodity_id = Column(String(64), nullable=False, index=True) - name = Column(String(256), default="") - score = Column(Integer, nullable=True) - status = Column(String(32), default="") - raw = Column(JSON, nullable=True) - updated_at = Column(DateTime, default=_utcnow, onupdate=_utcnow) + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + commodity_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True) + name: Mapped[str] = mapped_column(String(256), default="") + score: Mapped[int | None] = mapped_column(Integer, nullable=True) + status: Mapped[str] = mapped_column(String(32), default="") + raw: Mapped[dict | None] = mapped_column(JSON, nullable=True) + updated_at: Mapped[datetime] = mapped_column( + DateTime, default=_utcnow, onupdate=_utcnow + ) class DouyuXpdGoodsSnapshot(Base): @@ -279,15 +327,17 @@ class DouyuXpdGoodsSnapshot(Base): __tablename__ = "douyu_xpd_goods_snapshot" - id = Column(Integer, primary_key=True, autoincrement=True) - commodity_id = Column(String(64), nullable=False, index=True) - name = Column(String(256), default="") - price = Column(Integer, nullable=True) - org_price = Column(Integer, nullable=True) - category = Column(String(32), default="") - goods_left = Column(Integer, nullable=True) - raw = Column(JSON, nullable=True) - updated_at = Column(DateTime, default=_utcnow, onupdate=_utcnow) + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + commodity_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True) + name: Mapped[str] = mapped_column(String(256), default="") + price: Mapped[int | None] = mapped_column(Integer, nullable=True) + org_price: Mapped[int | None] = mapped_column(Integer, nullable=True) + category: Mapped[str] = mapped_column(String(32), default="") + goods_left: Mapped[int | None] = mapped_column(Integer, nullable=True) + raw: Mapped[dict | None] = mapped_column(JSON, nullable=True) + updated_at: Mapped[datetime] = mapped_column( + DateTime, default=_utcnow, onupdate=_utcnow + ) class DouyuEsportsGoodsSnapshot(Base): @@ -295,13 +345,15 @@ class DouyuEsportsGoodsSnapshot(Base): __tablename__ = "douyu_esports_goods_snapshot" - id = Column(Integer, primary_key=True, autoincrement=True) - commodity_id = Column(String(64), nullable=False, index=True) - name = Column(String(256), default="") - score = Column(Integer, nullable=True) - status = Column(String(32), default="") - raw = Column(JSON, nullable=True) - updated_at = Column(DateTime, default=_utcnow, onupdate=_utcnow) + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + commodity_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True) + name: Mapped[str] = mapped_column(String(256), default="") + score: Mapped[int | None] = mapped_column(Integer, nullable=True) + status: Mapped[str] = mapped_column(String(32), default="") + raw: Mapped[dict | None] = mapped_column(JSON, nullable=True) + updated_at: Mapped[datetime] = mapped_column( + DateTime, default=_utcnow, onupdate=_utcnow + ) class HuyaAccount(Base): @@ -309,31 +361,35 @@ class HuyaAccount(Base): __tablename__ = "huya_accounts" - id = Column(Integer, primary_key=True, autoincrement=True) - uid = Column(String(32), default="", index=True) - yyuid = Column(String(32), default="", index=True) - username = Column(String(128), default="") - account_password = Column(EncryptedText(), default="") - nickname = Column(String(128), default="") - cookie = Column(EncryptedText(), nullable=False) - tag = Column(String(64), default="") - remark = Column(String(256), default="") - status = Column(String(32), default="imported") + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + uid: Mapped[str] = mapped_column(String(32), default="", index=True) + yyuid: Mapped[str] = mapped_column(String(32), default="", index=True) + username: Mapped[str] = mapped_column(String(128), default="") + account_password: Mapped[str] = mapped_column(EncryptedText(), default="") + nickname: Mapped[str] = mapped_column(String(128), default="") + cookie: Mapped[str] = mapped_column(EncryptedText(), nullable=False) + tag: Mapped[str] = mapped_column(String(64), default="") + remark: Mapped[str] = mapped_column(String(256), default="") + status: Mapped[str] = mapped_column(String(32), default="imported") # 上次成功登录渠道: web=旧版Web协议 / app=App协议(推荐) / sms=短信; 空=仅导入Cookie - login_channel = Column(String(16), default="", index=True) - points = Column(Integer, nullable=True) - game_name = Column(String(128), default="") - game_channel = Column(String(64), default="") - game_phone = Column(String(64), default="") - sms_url = Column(Text, default="") - assigned_to = Column(Integer, ForeignKey("users.id"), nullable=True, index=True) - created_at = Column(DateTime, default=_utcnow) - updated_at = Column(DateTime, default=_utcnow, onupdate=_utcnow) + login_channel: Mapped[str] = mapped_column(String(16), default="", index=True) + points: Mapped[int | None] = mapped_column(Integer, nullable=True) + game_name: Mapped[str] = mapped_column(String(128), default="") + game_channel: Mapped[str] = mapped_column(String(64), default="") + game_phone: Mapped[str] = mapped_column(String(64), default="") + sms_url: Mapped[str] = mapped_column(Text, default="") + assigned_to: Mapped[int | None] = mapped_column( + ForeignKey("users.id"), nullable=True, index=True + ) + created_at: Mapped[datetime] = mapped_column(DateTime, default=_utcnow) + updated_at: Mapped[datetime] = mapped_column( + DateTime, default=_utcnow, onupdate=_utcnow + ) - assigned_user = relationship( + assigned_user: Mapped[User | None] = relationship( "User", back_populates="huya_accounts", foreign_keys=[assigned_to] ) - tasks = relationship("HuyaTask", back_populates="account") + tasks: Mapped[list[HuyaTask]] = relationship("HuyaTask", back_populates="account") class HuyaRegisterBatch(Base): @@ -341,27 +397,31 @@ class HuyaRegisterBatch(Base): __tablename__ = "huya_register_batches" - id = Column(Integer, primary_key=True, autoincrement=True) - batch_id = Column(String(64), unique=True, nullable=False, index=True) - tag = Column(String(64), default="") - created_by = Column(Integer, ForeignKey("users.id"), nullable=False, index=True) - concurrency = Column(Integer, default=1) - wait_seconds = Column(Integer, default=180) - poll_interval = Column(Integer, default=5) - password_prefix = Column(String(16), default="hy") - fixed_password = Column(EncryptedText(), default="") - use_proxy = Column(Boolean, default=False) - status = Column(String(32), default="pending", index=True) - message = Column(String(512), default="") - total = Column(Integer, default=0) - success_count = Column(Integer, default=0) - failed_count = Column(Integer, default=0) - stopped_count = Column(Integer, default=0) - created_at = Column(DateTime, default=_utcnow) - started_at = Column(DateTime, nullable=True) - finished_at = Column(DateTime, nullable=True) + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + batch_id: Mapped[str] = mapped_column( + String(64), unique=True, nullable=False, index=True + ) + tag: Mapped[str] = mapped_column(String(64), default="") + created_by: Mapped[int] = mapped_column( + ForeignKey("users.id"), nullable=False, index=True + ) + concurrency: Mapped[int] = mapped_column(Integer, default=1) + wait_seconds: Mapped[int] = mapped_column(Integer, default=180) + poll_interval: Mapped[int] = mapped_column(Integer, default=5) + password_prefix: Mapped[str] = mapped_column(String(16), default="hy") + fixed_password: Mapped[str] = mapped_column(EncryptedText(), default="") + use_proxy: Mapped[bool] = mapped_column(Boolean, default=False) + status: Mapped[str] = mapped_column(String(32), default="pending", index=True) + message: Mapped[str] = mapped_column(String(512), default="") + total: Mapped[int] = mapped_column(Integer, default=0) + success_count: Mapped[int] = mapped_column(Integer, default=0) + failed_count: Mapped[int] = mapped_column(Integer, default=0) + stopped_count: Mapped[int] = mapped_column(Integer, default=0) + created_at: Mapped[datetime] = mapped_column(DateTime, default=_utcnow) + started_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) + finished_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) - items = relationship( + items: Mapped[list[HuyaRegisterItem]] = relationship( "HuyaRegisterItem", back_populates="batch", cascade="all, delete-orphan" ) @@ -371,31 +431,35 @@ class HuyaRegisterItem(Base): __tablename__ = "huya_register_items" - id = Column(Integer, primary_key=True, autoincrement=True) - batch_db_id = Column( + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + batch_db_id: Mapped[int] = mapped_column( Integer, ForeignKey("huya_register_batches.id"), nullable=False, index=True ) - batch_id = Column(String(64), nullable=False, index=True) - line = Column(Integer, nullable=False) - phone = Column(String(64), default="", index=True) - provider = Column(String(32), default="") - sms_url = Column(Text, default="") - status = Column(String(32), default="pending", index=True) - message = Column(String(512), default="") - code = Column(String(32), default="") - change_code = Column(String(32), default="") - attempts = Column(Integer, default=0) - change_attempts = Column(Integer, default=0) - account_id = Column(Integer, ForeignKey("huya_accounts.id"), nullable=True) - username = Column(String(128), default="") - uid = Column(String(32), default="") - password = Column(EncryptedText(), default="") - password_changed = Column(Boolean, default=False) - cookie = Column(EncryptedText(), default="") - started_at = Column(DateTime, nullable=True) - finished_at = Column(DateTime, nullable=True) + batch_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True) + line: Mapped[int] = mapped_column(Integer, nullable=False) + phone: Mapped[str] = mapped_column(String(64), default="", index=True) + provider: Mapped[str] = mapped_column(String(32), default="") + sms_url: Mapped[str] = mapped_column(Text, default="") + status: Mapped[str] = mapped_column(String(32), default="pending", index=True) + message: Mapped[str] = mapped_column(String(512), default="") + code: Mapped[str] = mapped_column(String(32), default="") + change_code: Mapped[str] = mapped_column(String(32), default="") + attempts: Mapped[int] = mapped_column(Integer, default=0) + change_attempts: Mapped[int] = mapped_column(Integer, default=0) + account_id: Mapped[int | None] = mapped_column( + ForeignKey("huya_accounts.id"), nullable=True + ) + username: Mapped[str] = mapped_column(String(128), default="") + uid: Mapped[str] = mapped_column(String(32), default="") + password: Mapped[str] = mapped_column(EncryptedText(), default="") + password_changed: Mapped[bool] = mapped_column(Boolean, default=False) + cookie: Mapped[str] = mapped_column(EncryptedText(), default="") + started_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) + finished_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) - batch = relationship("HuyaRegisterBatch", back_populates="items") + batch: Mapped[HuyaRegisterBatch] = relationship( + "HuyaRegisterBatch", back_populates="items" + ) class HuyaRegisterSuccessLog(Base): @@ -403,19 +467,23 @@ class HuyaRegisterSuccessLog(Base): __tablename__ = "huya_register_success_logs" - id = Column(Integer, primary_key=True, autoincrement=True) - batch_id = Column(String(64), default="", index=True) - item_id = Column(Integer, nullable=True) - account_id = Column(Integer, ForeignKey("huya_accounts.id"), nullable=True) - phone = Column(String(64), default="", index=True) - username = Column(String(128), default="") - uid = Column(String(32), default="") - password = Column(EncryptedText(), default="") - sms_url = Column(Text, default="") - tag = Column(String(64), default="", index=True) - provider = Column(String(32), default="") - created_by = Column(Integer, ForeignKey("users.id"), nullable=True) - created_at = Column(DateTime, default=_utcnow, index=True) + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + batch_id: Mapped[str] = mapped_column(String(64), default="", index=True) + item_id: Mapped[int | None] = mapped_column(Integer, nullable=True) + account_id: Mapped[int | None] = mapped_column( + ForeignKey("huya_accounts.id"), nullable=True + ) + phone: Mapped[str] = mapped_column(String(64), default="", index=True) + username: Mapped[str] = mapped_column(String(128), default="") + uid: Mapped[str] = mapped_column(String(32), default="") + password: Mapped[str] = mapped_column(EncryptedText(), default="") + sms_url: Mapped[str] = mapped_column(Text, default="") + tag: Mapped[str] = mapped_column(String(64), default="", index=True) + provider: Mapped[str] = mapped_column(String(32), default="") + created_by: Mapped[int | None] = mapped_column( + ForeignKey("users.id"), nullable=True + ) + created_at: Mapped[datetime] = mapped_column(DateTime, default=_utcnow, index=True) class HuyaTask(Base): @@ -423,18 +491,20 @@ class HuyaTask(Base): __tablename__ = "huya_tasks" - id = Column(Integer, primary_key=True, autoincrement=True) - batch_id = Column(String(64), nullable=False, index=True) - account_id = Column(Integer, ForeignKey("huya_accounts.id"), nullable=False) - task_type = Column(String(64), nullable=False, index=True) - status = Column(String(32), default="pending") - message = Column(String(512), default="") - result = Column(JSON, nullable=True) - created_by = Column(Integer, ForeignKey("users.id"), nullable=False) - created_at = Column(DateTime, default=_utcnow) - finished_at = Column(DateTime, nullable=True) + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + batch_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True) + account_id: Mapped[int] = mapped_column( + ForeignKey("huya_accounts.id"), nullable=False + ) + task_type: Mapped[str] = mapped_column(String(64), nullable=False, index=True) + status: Mapped[str] = mapped_column(String(32), default="pending") + message: Mapped[str] = mapped_column(String(512), default="") + result: Mapped[dict | None] = mapped_column(JSON, nullable=True) + created_by: Mapped[int] = mapped_column(ForeignKey("users.id"), nullable=False) + created_at: Mapped[datetime] = mapped_column(DateTime, default=_utcnow) + finished_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) - account = relationship("HuyaAccount", back_populates="tasks") + account: Mapped[HuyaAccount] = relationship("HuyaAccount", back_populates="tasks") class HuyaConfig(Base): @@ -442,13 +512,21 @@ class HuyaConfig(Base): __tablename__ = "huya_config" - id = Column(Integer, primary_key=True, autoincrement=True) - room_pid = Column(String(64), default=HUYA_DEFAULT_ROOM_PID) - sid = Column(String(32), default=HUYA_DEFAULT_SID) - outer_act_id = Column(String(32), default=HUYA_DEFAULT_OUTER_ACT_ID) - bind_act_id = Column(String(32), default=HUYA_DEFAULT_BIND_ACT_ID) - pay_channel = Column(String(16), default=HUYA_DEFAULT_PAY_CHANNEL) - updated_at = Column(DateTime, default=_utcnow, onupdate=_utcnow) + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + room_pid: Mapped[str] = mapped_column(String(64), default=HUYA_DEFAULT_ROOM_PID) + sid: Mapped[str] = mapped_column(String(32), default=HUYA_DEFAULT_SID) + outer_act_id: Mapped[str] = mapped_column( + String(32), default=HUYA_DEFAULT_OUTER_ACT_ID + ) + bind_act_id: Mapped[str] = mapped_column( + String(32), default=HUYA_DEFAULT_BIND_ACT_ID + ) + pay_channel: Mapped[str] = mapped_column( + String(16), default=HUYA_DEFAULT_PAY_CHANNEL + ) + updated_at: Mapped[datetime] = mapped_column( + DateTime, default=_utcnow, onupdate=_utcnow + ) class HuyaGoodsSnapshot(Base): @@ -456,13 +534,15 @@ class HuyaGoodsSnapshot(Base): __tablename__ = "huya_goods_snapshot" - id = Column(Integer, primary_key=True, autoincrement=True) - product_id = Column(String(64), nullable=False, index=True) - name = Column(String(256), default="") - price = Column(Integer, nullable=True) - remain_text = Column(String(64), default="") - raw = Column(JSON, nullable=True) - updated_at = Column(DateTime, default=_utcnow, onupdate=_utcnow) + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + product_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True) + name: Mapped[str] = mapped_column(String(256), default="") + price: Mapped[int | None] = mapped_column(Integer, nullable=True) + remain_text: Mapped[str] = mapped_column(String(64), default="") + raw: Mapped[dict | None] = mapped_column(JSON, nullable=True) + updated_at: Mapped[datetime] = mapped_column( + DateTime, default=_utcnow, onupdate=_utcnow + ) class HuyaRechargeGoodsSnapshot(Base): @@ -470,19 +550,21 @@ class HuyaRechargeGoodsSnapshot(Base): __tablename__ = "huya_recharge_goods_snapshot" - id = Column(Integer, primary_key=True, autoincrement=True) - spu_id = Column(String(64), nullable=False, index=True) - sku_id = Column(String(64), default="", index=True) - name = Column(String(256), default="") - price = Column(Integer, nullable=True) - stock = Column(Integer, nullable=True) - buy_limit = Column(Integer, nullable=True) - icon = Column(String(512), default="") - description = Column(String(512), default="") - task_id = Column(String(64), default="") - task_name = Column(String(256), default="") - raw = Column(JSON, nullable=True) - updated_at = Column(DateTime, default=_utcnow, onupdate=_utcnow) + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + spu_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True) + sku_id: Mapped[str] = mapped_column(String(64), default="", index=True) + name: Mapped[str] = mapped_column(String(256), default="") + price: Mapped[int | None] = mapped_column(Integer, nullable=True) + stock: Mapped[int | None] = mapped_column(Integer, nullable=True) + buy_limit: Mapped[int | None] = mapped_column(Integer, nullable=True) + icon: Mapped[str] = mapped_column(String(512), default="") + description: Mapped[str] = mapped_column(String(512), default="") + task_id: Mapped[str] = mapped_column(String(64), default="") + task_name: Mapped[str] = mapped_column(String(256), default="") + raw: Mapped[dict | None] = mapped_column(JSON, nullable=True) + updated_at: Mapped[datetime] = mapped_column( + DateTime, default=_utcnow, onupdate=_utcnow + ) class ProxyConfig(Base): @@ -490,18 +572,18 @@ class ProxyConfig(Base): __tablename__ = "proxy_config" - id = Column(Integer, primary_key=True, autoincrement=True) - enabled = Column(Boolean, default=False) - api_url = Column(EncryptedText(), default="") - http = Column(EncryptedText(), default="") - https = Column(EncryptedText(), default="") + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + enabled: Mapped[bool] = mapped_column(Boolean, default=False) + api_url: Mapped[str] = mapped_column(EncryptedText(), default="") + http: Mapped[str] = mapped_column(EncryptedText(), default="") + https: Mapped[str] = mapped_column(EncryptedText(), default="") # 白名单 - whitelist_enabled = Column(Boolean, default=False) - whitelist_platform = Column(String(32), default="xiequ") - whitelist_credentials = Column(JSON, nullable=True) + whitelist_enabled: Mapped[bool] = mapped_column(Boolean, default=False) + whitelist_platform: Mapped[str] = mapped_column(String(32), default="xiequ") + whitelist_credentials: Mapped[dict | None] = mapped_column(JSON, nullable=True) # 旧字段保留(向后兼容双写) - whitelist_uid = Column(EncryptedText(), default="") - whitelist_ukey = Column(EncryptedText(), default="") + whitelist_uid: Mapped[str] = mapped_column(EncryptedText(), default="") + whitelist_ukey: Mapped[str] = mapped_column(EncryptedText(), default="") class AuditLog(Base): @@ -509,12 +591,12 @@ class AuditLog(Base): __tablename__ = "audit_logs" - id = Column(Integer, primary_key=True, autoincrement=True) - user_id = Column(Integer, nullable=True) - username = Column(String(64), default="") - action = Column(String(128), nullable=False) - target = Column(String(256), default="") - detail = Column(Text, default="") + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + user_id: Mapped[int | None] = mapped_column(Integer, nullable=True) + username: Mapped[str] = mapped_column(String(64), default="") + action: Mapped[str] = mapped_column(String(128), nullable=False) + target: Mapped[str] = mapped_column(String(256), default="") + detail: Mapped[str] = mapped_column(Text, default="") # 旧记录未标记结果时为 NULL,避免把历史操作误判成失败。 - success = Column(Boolean, nullable=True, index=True) - created_at = Column(DateTime, default=_utcnow) + success: Mapped[bool | None] = mapped_column(Boolean, nullable=True, index=True) + created_at: Mapped[datetime] = mapped_column(DateTime, default=_utcnow)