Files
video/server/app/models/user.py
T
2026-10-15 20:36:59 +08:00

79 lines
4.2 KiB
Python

"""用户域:users / user_wallets / user_membership / membership_orders"""
from datetime import datetime
from sqlalchemy import DateTime, ForeignKey, Index, SmallInteger, String, func
from sqlalchemy.dialects.mysql import BIGINT, INTEGER
from sqlalchemy.orm import Mapped, mapped_column
from app.models.base import Base
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True, autoincrement=True)
phone: Mapped[str | None] = mapped_column(String(20), unique=True, comment="手机号")
email: Mapped[str | None] = mapped_column(String(100), unique=True, comment="邮箱")
password_hash: Mapped[str] = mapped_column(String(255))
nickname: Mapped[str] = mapped_column(String(50), default="")
avatar_url: Mapped[str] = mapped_column(String(500), default="")
gender: Mapped[int] = mapped_column(SmallInteger, default=0, comment="0未知 1男 2女")
bio: Mapped[str] = mapped_column(String(200), default="")
status: Mapped[int] = mapped_column(SmallInteger, default=1, comment="1正常 2封禁 3已注销")
register_type: Mapped[int] = mapped_column(SmallInteger, comment="1手机 2邮箱")
invite_code: Mapped[str] = mapped_column(String(10), unique=True, default="", comment="我的邀请码")
register_ip: Mapped[str] = mapped_column(String(45), default="")
last_login_at: Mapped[datetime | None] = mapped_column(DateTime)
last_login_ip: Mapped[str] = mapped_column(String(45), default="")
deactivate_at: Mapped[datetime | None] = mapped_column(DateTime, comment="注销发起时间(7天冻结期)")
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now())
__table_args__ = (Index("idx_status_created", "status", "created_at"),)
class UserWallet(Base):
__tablename__ = "user_wallets"
user_id: Mapped[int] = mapped_column(
BIGINT(unsigned=True), ForeignKey("users.id"), primary_key=True
)
points: Mapped[int] = mapped_column(INTEGER(unsigned=True), default=0)
total_recharge: Mapped[int] = mapped_column(INTEGER(unsigned=True), default=0)
total_earned: Mapped[int] = mapped_column(INTEGER(unsigned=True), default=0)
total_consumed: Mapped[int] = mapped_column(INTEGER(unsigned=True), default=0)
version: Mapped[int] = mapped_column(default=0, comment="乐观锁")
updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now())
class UserMembership(Base):
"""用户当前会员状态(冗余加速查询,以 expire_at 判定为准)"""
__tablename__ = "user_membership"
user_id: Mapped[int] = mapped_column(
BIGINT(unsigned=True), ForeignKey("users.id"), primary_key=True
)
is_member: Mapped[int] = mapped_column(SmallInteger, default=0)
current_plan: Mapped[str] = mapped_column(String(20), default="", comment="trial/month/year/lifetime")
is_lifetime: Mapped[int] = mapped_column(SmallInteger, default=0)
expire_at: Mapped[datetime | None] = mapped_column(DateTime, comment="终身卡为 NULL")
updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now())
class MembershipOrder(Base):
__tablename__ = "membership_orders"
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True, autoincrement=True)
order_no: Mapped[str] = mapped_column(String(32), unique=True)
user_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), ForeignKey("users.id"))
plan_code: Mapped[str] = mapped_column(String(20), comment="trial/month/year/lifetime")
points_cost: Mapped[int] = mapped_column(default=0, comment="赠送为 0")
duration_days: Mapped[int] = mapped_column(default=0, comment="0=终身")
start_at: Mapped[datetime] = mapped_column(DateTime)
end_at: Mapped[datetime | None] = mapped_column(DateTime, comment="终身为 NULL")
source: Mapped[int] = mapped_column(SmallInteger, default=1, comment="1积分购买 2活动赠送")
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
__table_args__ = (Index("idx_user", "user_id", "created_at"),)