up
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
"""模型汇总(Alembic autogenerate 依赖全量导入)"""
|
||||
from app.models.base import Base
|
||||
from app.models.admin import AdminLog, AdminUser
|
||||
from app.models.billing import PointTransaction, RechargeOrder, RechargePackage, WatchRecord
|
||||
from app.models.common import Notification, Report, SensitiveWord, SystemConfig
|
||||
from app.models.incentive import (
|
||||
AssetTransaction,
|
||||
AssetWallet,
|
||||
Referral,
|
||||
VideoEarning,
|
||||
Withdrawal,
|
||||
)
|
||||
from app.models.interaction import Comment, Favorite, Like
|
||||
from app.models.user import MembershipOrder, User, UserMembership, UserWallet
|
||||
from app.models.video import Category, Tag, TranscodeTask, Video, VideoTag
|
||||
|
||||
__all__ = [
|
||||
"Base",
|
||||
"User", "UserWallet", "UserMembership", "MembershipOrder",
|
||||
"Video", "Category", "Tag", "VideoTag", "TranscodeTask",
|
||||
"Comment", "Like", "Favorite",
|
||||
"WatchRecord", "PointTransaction", "RechargeOrder", "RechargePackage",
|
||||
"Referral", "AssetWallet", "AssetTransaction", "Withdrawal", "VideoEarning",
|
||||
"Notification", "Report", "SensitiveWord", "SystemConfig",
|
||||
"AdminUser", "AdminLog",
|
||||
]
|
||||
@@ -0,0 +1,35 @@
|
||||
"""管理后台域:admin_users / admin_logs"""
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, Index, SmallInteger, String, func
|
||||
from sqlalchemy.dialects.mysql import BIGINT
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.models.base import Base
|
||||
|
||||
|
||||
class AdminUser(Base):
|
||||
__tablename__ = "admin_users"
|
||||
|
||||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True, autoincrement=True)
|
||||
username: Mapped[str] = mapped_column(String(50), unique=True)
|
||||
password_hash: Mapped[str] = mapped_column(String(255))
|
||||
name: Mapped[str] = mapped_column(String(50), default="")
|
||||
role: Mapped[str] = mapped_column(String(20), comment="super/reviewer/operator")
|
||||
status: Mapped[int] = mapped_column(SmallInteger, default=1, comment="1正常 0禁用")
|
||||
last_login_at: Mapped[datetime | None] = mapped_column(DateTime)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
|
||||
|
||||
class AdminLog(Base):
|
||||
__tablename__ = "admin_logs"
|
||||
|
||||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True, autoincrement=True)
|
||||
admin_id: Mapped[int] = mapped_column(BIGINT(unsigned=True))
|
||||
action: Mapped[str] = mapped_column(String(50))
|
||||
target: Mapped[str] = mapped_column(String(100), default="")
|
||||
detail: Mapped[str] = mapped_column(String(1000), default="")
|
||||
ip: Mapped[str] = mapped_column(String(45), default="")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
|
||||
__table_args__ = (Index("idx_admin_created", "admin_id", "created_at"),)
|
||||
@@ -0,0 +1,6 @@
|
||||
"""SQLAlchemy 声明式基类"""
|
||||
from sqlalchemy.orm import DeclarativeBase
|
||||
|
||||
|
||||
class Base(DeclarativeBase):
|
||||
pass
|
||||
@@ -0,0 +1,85 @@
|
||||
"""计费域:watch_records / point_transactions / recharge_orders / recharge_packages"""
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
|
||||
from sqlalchemy import Date, DateTime, Index, Numeric, SmallInteger, String, func
|
||||
from sqlalchemy.dialects.mysql import BIGINT, INTEGER
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.models.base import Base
|
||||
|
||||
|
||||
class WatchRecord(Base):
|
||||
__tablename__ = "watch_records"
|
||||
|
||||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True, autoincrement=True)
|
||||
subject_type: Mapped[int] = mapped_column(SmallInteger, comment="1用户 2游客")
|
||||
subject_id: Mapped[str] = mapped_column(String(64), comment="user_id或device_id")
|
||||
video_id: Mapped[int] = mapped_column(BIGINT(unsigned=True))
|
||||
watch_date: Mapped[date] = mapped_column(Date)
|
||||
cost_type: Mapped[int] = mapped_column(SmallInteger, comment="0免费 1积分 2会员 3本人")
|
||||
cost_points: Mapped[int] = mapped_column(default=0)
|
||||
watch_duration: Mapped[int] = mapped_column(default=0, comment="秒")
|
||||
position: Mapped[int] = mapped_column(default=0, comment="最后播放进度(秒),续播用")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
|
||||
__table_args__ = (
|
||||
Index("uk_dedup", "subject_type", "subject_id", "video_id", "watch_date", unique=True),
|
||||
Index("idx_subject", "subject_type", "subject_id", "created_at"),
|
||||
)
|
||||
|
||||
|
||||
class PointTransaction(Base):
|
||||
__tablename__ = "point_transactions"
|
||||
|
||||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(BIGINT(unsigned=True))
|
||||
change_amount: Mapped[int] = mapped_column(comment="正增负减")
|
||||
balance_after: Mapped[int] = mapped_column()
|
||||
biz_type: Mapped[int] = mapped_column(
|
||||
SmallInteger, comment="1充值 2观看 3评论奖励 4会员 5赠送 6调整 7扣回 8推荐奖励"
|
||||
)
|
||||
biz_id: Mapped[str] = mapped_column(String(64), default="")
|
||||
remark: Mapped[str] = mapped_column(String(200), default="")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
|
||||
__table_args__ = (
|
||||
Index("idx_user_created", "user_id", "created_at"),
|
||||
Index("idx_biz", "biz_type", "biz_id"),
|
||||
)
|
||||
|
||||
|
||||
class RechargeOrder(Base):
|
||||
__tablename__ = "recharge_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))
|
||||
amount_fen: Mapped[int] = mapped_column(comment="人民币金额(分)")
|
||||
points: Mapped[int] = mapped_column(comment="应到账积分")
|
||||
pay_method: Mapped[int] = mapped_column(SmallInteger, comment="1支付宝 2微信 3USDT")
|
||||
status: Mapped[int] = mapped_column(SmallInteger, default=0, comment="0待支付 1已支付 2已关闭 3已退款")
|
||||
third_trade_no: Mapped[str | None] = mapped_column(String(64), unique=True)
|
||||
usdt_amount: Mapped[Decimal | None] = mapped_column(Numeric(18, 6))
|
||||
usdt_rate: Mapped[Decimal | None] = mapped_column(Numeric(10, 4))
|
||||
paid_at: Mapped[datetime | None] = mapped_column(DateTime)
|
||||
expire_at: Mapped[datetime] = mapped_column(DateTime)
|
||||
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_user_status", "user_id", "status"),)
|
||||
|
||||
|
||||
class RechargePackage(Base):
|
||||
"""充值套餐档位(管理后台实时可配)"""
|
||||
|
||||
__tablename__ = "recharge_packages"
|
||||
|
||||
id: Mapped[int] = mapped_column(INTEGER(unsigned=True), primary_key=True, autoincrement=True)
|
||||
amount_yuan: Mapped[int] = mapped_column()
|
||||
points: Mapped[int] = mapped_column(comment="基础积分=金额x汇率")
|
||||
bonus_points: Mapped[int] = mapped_column(default=0)
|
||||
sort: Mapped[int] = mapped_column(default=0)
|
||||
status: Mapped[int] = mapped_column(SmallInteger, default=1, comment="1上架 0下架")
|
||||
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())
|
||||
@@ -0,0 +1,64 @@
|
||||
"""通用域:notifications / reports / sensitive_words / system_configs"""
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, 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 Notification(Base):
|
||||
__tablename__ = "notifications"
|
||||
|
||||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), comment="接收人")
|
||||
type: Mapped[int] = mapped_column(SmallInteger, comment="1审核结果 2提现进度 3系统公告 4评论回复")
|
||||
title: Mapped[str] = mapped_column(String(100), default="")
|
||||
content: Mapped[str] = mapped_column(String(500), default="")
|
||||
biz_id: Mapped[str] = mapped_column(String(64), default="")
|
||||
is_read: Mapped[int] = mapped_column(SmallInteger, default=0)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
|
||||
__table_args__ = (Index("idx_user_read", "user_id", "is_read", "id"),)
|
||||
|
||||
|
||||
class Report(Base):
|
||||
__tablename__ = "reports"
|
||||
|
||||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), comment="举报人")
|
||||
target_type: Mapped[int] = mapped_column(SmallInteger, comment="1视频 2评论")
|
||||
target_id: Mapped[int] = mapped_column(BIGINT(unsigned=True))
|
||||
reason_type: Mapped[int] = mapped_column(SmallInteger, comment="1色情低俗 2暴力血腥 3侵权 4广告营销 5其他")
|
||||
remark: Mapped[str] = mapped_column(String(200), default="")
|
||||
status: Mapped[int] = mapped_column(SmallInteger, default=0, comment="0待处理 1已处理 2已驳回")
|
||||
handle_result: Mapped[str] = mapped_column(String(50), default="")
|
||||
admin_id: Mapped[int | None] = mapped_column(BIGINT(unsigned=True))
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
handled_at: Mapped[datetime | None] = mapped_column(DateTime)
|
||||
|
||||
__table_args__ = (
|
||||
Index("uk_user_target", "user_id", "target_type", "target_id", unique=True),
|
||||
Index("idx_status", "status", "created_at"),
|
||||
)
|
||||
|
||||
|
||||
class SensitiveWord(Base):
|
||||
__tablename__ = "sensitive_words"
|
||||
|
||||
id: Mapped[int] = mapped_column(INTEGER(unsigned=True), primary_key=True, autoincrement=True)
|
||||
word: Mapped[str] = mapped_column(String(50), unique=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
|
||||
|
||||
class SystemConfig(Base):
|
||||
"""平台配置键值对(后台可改,Redis 缓存 60s)"""
|
||||
|
||||
__tablename__ = "system_configs"
|
||||
|
||||
config_key: Mapped[str] = mapped_column(String(50), primary_key=True)
|
||||
config_value: Mapped[str] = mapped_column(String(500), default="")
|
||||
description: Mapped[str] = mapped_column(String(200), default="")
|
||||
updated_by: Mapped[int | None] = mapped_column(BIGINT(unsigned=True))
|
||||
updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now())
|
||||
@@ -0,0 +1,98 @@
|
||||
"""激励域:referrals / asset_wallets / asset_transactions / withdrawals / video_earnings"""
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
|
||||
from sqlalchemy import DateTime, Index, Numeric, SmallInteger, String, func
|
||||
from sqlalchemy.dialects.mysql import BIGINT
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.models.base import Base
|
||||
|
||||
|
||||
class Referral(Base):
|
||||
__tablename__ = "referrals"
|
||||
|
||||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True, autoincrement=True)
|
||||
inviter_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), comment="推荐人")
|
||||
invitee_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), comment="被推荐人")
|
||||
invite_code: Mapped[str] = mapped_column(String(10))
|
||||
status: Mapped[int] = mapped_column(SmallInteger, default=0, comment="0待激活 1有效 2无效 3风控冻结")
|
||||
risk_flag: Mapped[str] = mapped_column(String(50), default="")
|
||||
register_ip: Mapped[str] = mapped_column(String(45), default="")
|
||||
activated_at: Mapped[datetime | None] = mapped_column(DateTime)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
|
||||
__table_args__ = (
|
||||
Index("uk_invitee", "invitee_id", unique=True),
|
||||
Index("idx_inviter", "inviter_id", "created_at"),
|
||||
Index("idx_status", "status", "created_at"),
|
||||
)
|
||||
|
||||
|
||||
class AssetWallet(Base):
|
||||
__tablename__ = "asset_wallets"
|
||||
|
||||
user_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True)
|
||||
assets: Mapped[Decimal] = mapped_column(Numeric(12, 1), default=0, comment="当前资产(允许为负)")
|
||||
total_earned: Mapped[Decimal] = mapped_column(Numeric(14, 1), default=0)
|
||||
total_withdrawn: Mapped[Decimal] = mapped_column(Numeric(14, 1), default=0)
|
||||
version: Mapped[int] = mapped_column(default=0)
|
||||
updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now())
|
||||
|
||||
|
||||
class AssetTransaction(Base):
|
||||
__tablename__ = "asset_transactions"
|
||||
|
||||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(BIGINT(unsigned=True))
|
||||
change_amount: Mapped[Decimal] = mapped_column(Numeric(12, 1))
|
||||
balance_after: Mapped[Decimal] = mapped_column(Numeric(12, 1))
|
||||
biz_type: Mapped[int] = mapped_column(
|
||||
SmallInteger, comment="1充值返利 2完整观看 3点赞 4提现 5提现退回 6返利扣回 7后台调整"
|
||||
)
|
||||
biz_id: Mapped[str] = mapped_column(String(64), default="")
|
||||
remark: Mapped[str] = mapped_column(String(200), default="")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
|
||||
__table_args__ = (
|
||||
Index("idx_user_created", "user_id", "created_at"),
|
||||
Index("idx_biz", "biz_type", "biz_id"),
|
||||
)
|
||||
|
||||
|
||||
class Withdrawal(Base):
|
||||
__tablename__ = "withdrawals"
|
||||
|
||||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True, autoincrement=True)
|
||||
withdraw_no: Mapped[str] = mapped_column(String(32), unique=True)
|
||||
user_id: Mapped[int] = mapped_column(BIGINT(unsigned=True))
|
||||
assets: Mapped[Decimal] = mapped_column(Numeric(12, 1))
|
||||
amount_fen: Mapped[int] = mapped_column(comment="折合人民币(分)")
|
||||
channel: Mapped[int] = mapped_column(SmallInteger, comment="1支付宝 2微信 3USDT")
|
||||
account: Mapped[str] = mapped_column(String(200))
|
||||
status: Mapped[int] = mapped_column(SmallInteger, default=0, comment="0待审核 1已打款 2已拒绝")
|
||||
reason: Mapped[str] = mapped_column(String(200), default="")
|
||||
admin_id: Mapped[int | None] = mapped_column(BIGINT(unsigned=True))
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
processed_at: Mapped[datetime | None] = mapped_column(DateTime)
|
||||
|
||||
__table_args__ = (
|
||||
Index("idx_user", "user_id", "created_at"),
|
||||
Index("idx_status", "status", "created_at"),
|
||||
)
|
||||
|
||||
|
||||
class VideoEarning(Base):
|
||||
"""视频收益结算刻度(完整观看/点赞按增量结算,余数保留)"""
|
||||
|
||||
__tablename__ = "video_earnings"
|
||||
|
||||
video_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True)
|
||||
author_id: Mapped[int] = mapped_column(BIGINT(unsigned=True))
|
||||
complete_views: Mapped[int] = mapped_column(default=0, comment="累计完整观看次数")
|
||||
views_settled: Mapped[int] = mapped_column(default=0, comment="已结算的完整观看刻度")
|
||||
likes_accrued: Mapped[int] = mapped_column(default=0, comment="累计点赞(取消会回退)")
|
||||
likes_settled: Mapped[int] = mapped_column(default=0, comment="已结算的点赞刻度")
|
||||
updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now())
|
||||
|
||||
__table_args__ = (Index("idx_author", "author_id"),)
|
||||
@@ -0,0 +1,56 @@
|
||||
"""互动域:comments / likes / favorites"""
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, Index, SmallInteger, String, func
|
||||
from sqlalchemy.dialects.mysql import BIGINT
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.models.base import Base
|
||||
|
||||
|
||||
class Comment(Base):
|
||||
__tablename__ = "comments"
|
||||
|
||||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True, autoincrement=True)
|
||||
video_id: Mapped[int] = mapped_column(BIGINT(unsigned=True))
|
||||
user_id: Mapped[int] = mapped_column(BIGINT(unsigned=True))
|
||||
parent_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), default=0, comment="0=一级评论")
|
||||
reply_to_user_id: Mapped[int | None] = mapped_column(BIGINT(unsigned=True))
|
||||
content: Mapped[str] = mapped_column(String(500))
|
||||
like_count: Mapped[int] = mapped_column(default=0)
|
||||
status: Mapped[int] = mapped_column(SmallInteger, default=1, comment="1正常 2已删除 3审核中")
|
||||
reward_counted: Mapped[int] = mapped_column(SmallInteger, default=0, comment="是否已计入评论奖励进度")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
|
||||
__table_args__ = (
|
||||
Index("idx_video", "video_id", "status", "created_at"),
|
||||
Index("idx_user_video", "user_id", "video_id"),
|
||||
)
|
||||
|
||||
|
||||
class Like(Base):
|
||||
__tablename__ = "likes"
|
||||
|
||||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(BIGINT(unsigned=True))
|
||||
video_id: Mapped[int] = mapped_column(BIGINT(unsigned=True))
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
|
||||
__table_args__ = (
|
||||
Index("uk_user_video", "user_id", "video_id", unique=True),
|
||||
Index("idx_video", "video_id"),
|
||||
)
|
||||
|
||||
|
||||
class Favorite(Base):
|
||||
__tablename__ = "favorites"
|
||||
|
||||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(BIGINT(unsigned=True))
|
||||
video_id: Mapped[int] = mapped_column(BIGINT(unsigned=True))
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
|
||||
__table_args__ = (
|
||||
Index("uk_user_video", "user_id", "video_id", unique=True),
|
||||
Index("idx_video", "video_id"),
|
||||
)
|
||||
@@ -0,0 +1,78 @@
|
||||
"""用户域: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"),)
|
||||
@@ -0,0 +1,91 @@
|
||||
"""视频域:videos / categories / tags / video_tags / transcode_tasks"""
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import BigInteger, DateTime, 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 Video(Base):
|
||||
__tablename__ = "videos"
|
||||
|
||||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(BIGINT(unsigned=True), comment="作者")
|
||||
category_id: Mapped[int] = mapped_column(default=0)
|
||||
title: Mapped[str] = mapped_column(String(100), default="")
|
||||
description: Mapped[str] = mapped_column(String(500), default="")
|
||||
cover_url: Mapped[str] = mapped_column(String(500), default="")
|
||||
video_url: Mapped[str] = mapped_column(String(500), default="", comment="m3u8地址")
|
||||
duration: Mapped[int] = mapped_column(default=0, comment="秒")
|
||||
file_size: Mapped[int] = mapped_column(BigInteger, default=0)
|
||||
width: Mapped[int] = mapped_column(default=0)
|
||||
height: Mapped[int] = mapped_column(default=0)
|
||||
status: Mapped[int] = mapped_column(
|
||||
SmallInteger, default=0, comment="0转码中 1待审核 2已发布 3拒绝 4下架 5转码失败/已删除"
|
||||
)
|
||||
reject_reason: Mapped[str] = mapped_column(String(200), default="")
|
||||
reviewer_id: Mapped[int | None] = mapped_column(BIGINT(unsigned=True))
|
||||
reviewed_at: Mapped[datetime | None] = mapped_column(DateTime)
|
||||
is_priority: Mapped[int] = mapped_column(SmallInteger, default=0)
|
||||
view_count: Mapped[int] = mapped_column(BigInteger, default=0)
|
||||
like_count: Mapped[int] = mapped_column(default=0)
|
||||
comment_count: Mapped[int] = mapped_column(default=0)
|
||||
favorite_count: Mapped[int] = mapped_column(default=0)
|
||||
published_at: Mapped[datetime | None] = mapped_column(DateTime)
|
||||
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_user_status", "user_id", "status"),
|
||||
Index("idx_feed", "status", "published_at"),
|
||||
Index("idx_category", "category_id", "status"),
|
||||
)
|
||||
|
||||
|
||||
class Category(Base):
|
||||
__tablename__ = "categories"
|
||||
|
||||
id: Mapped[int] = mapped_column(INTEGER(unsigned=True), primary_key=True, autoincrement=True)
|
||||
name: Mapped[str] = mapped_column(String(50))
|
||||
sort: Mapped[int] = mapped_column(default=0)
|
||||
status: Mapped[int] = mapped_column(SmallInteger, default=1, comment="1启用 0停用")
|
||||
|
||||
|
||||
class Tag(Base):
|
||||
__tablename__ = "tags"
|
||||
|
||||
id: Mapped[int] = mapped_column(INTEGER(unsigned=True), primary_key=True, autoincrement=True)
|
||||
name: Mapped[str] = mapped_column(String(20), unique=True)
|
||||
video_count: Mapped[int] = mapped_column(default=0, comment="冗余")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
|
||||
|
||||
class VideoTag(Base):
|
||||
__tablename__ = "video_tags"
|
||||
|
||||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True, autoincrement=True)
|
||||
video_id: Mapped[int] = mapped_column(BIGINT(unsigned=True))
|
||||
tag_id: Mapped[int] = mapped_column(INTEGER(unsigned=True))
|
||||
|
||||
__table_args__ = (
|
||||
Index("uk_video_tag", "video_id", "tag_id", unique=True),
|
||||
Index("idx_tag", "tag_id", "video_id"),
|
||||
)
|
||||
|
||||
|
||||
class TranscodeTask(Base):
|
||||
__tablename__ = "transcode_tasks"
|
||||
|
||||
id: Mapped[int] = mapped_column(BIGINT(unsigned=True), primary_key=True, autoincrement=True)
|
||||
video_id: Mapped[int] = mapped_column(BIGINT(unsigned=True))
|
||||
source_url: Mapped[str] = mapped_column(String(500))
|
||||
task_status: Mapped[int] = mapped_column(SmallInteger, default=0, comment="0排队 1转码中 2成功 3失败")
|
||||
priority: Mapped[int] = mapped_column(SmallInteger, default=0, comment="0普通 1优先(会员)")
|
||||
retry_count: Mapped[int] = mapped_column(default=0)
|
||||
error_msg: Mapped[str] = mapped_column(String(500), default="")
|
||||
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_pick", "task_status", "priority", "created_at"),)
|
||||
Reference in New Issue
Block a user