add
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",
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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