This commit is contained in:
root
2026-10-16 13:51:00 +08:00
parent 6bf949949c
commit 8fc899d0a9
3830 changed files with 11228 additions and 188377 deletions
+26
View File
@@ -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",
]
+35
View File
@@ -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"),)
+6
View File
@@ -0,0 +1,6 @@
"""SQLAlchemy 声明式基类"""
from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
pass
+85
View File
@@ -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())
+64
View File
@@ -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())
+98
View File
@@ -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"),
)
+78
View File
@@ -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"),)
+91
View File
@@ -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"),)