255 lines
11 KiB
Python
255 lines
11 KiB
Python
# 数据库模型 - 使用字段编码
|
||
from sqlalchemy import Column, String, Float, Boolean, DateTime, Integer, Text, ForeignKey, Date, UniqueConstraint
|
||
from sqlalchemy.orm import relationship
|
||
from sqlalchemy.sql import func
|
||
from app.core.database import Base
|
||
import uuid
|
||
|
||
|
||
def generate_uuid():
|
||
"""生成 UUID 字符串"""
|
||
return str(uuid.uuid4())
|
||
|
||
|
||
class User(Base):
|
||
__tablename__ = "users"
|
||
|
||
# f99 系统字段
|
||
f99_90_id = Column(String(36), primary_key=True, default=generate_uuid)
|
||
user_code = Column(String(10), unique=True, nullable=True, index=True) # 用户编码
|
||
f99_91_user_id = Column(String(36), unique=True, nullable=False, index=True)
|
||
f01_01_name = Column(String(255), unique=True, nullable=False, index=True) # username
|
||
email = Column(String(255), unique=True, nullable=True, index=True)
|
||
phone = Column(String(50), nullable=True)
|
||
avatar = Column(String(500), nullable=True)
|
||
address = Column(String(500), nullable=True)
|
||
bio = Column(Text, nullable=True)
|
||
password = Column(String(255), nullable=False)
|
||
role = Column(String(50), default="user")
|
||
# 时间字段
|
||
f99_92_created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||
f99_93_updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||
# 新增字段
|
||
f99_94_level = Column(String(20), default="青铜") # 会员等级
|
||
f99_95_ai_count = Column(Integer, default=0) # ai识别次数
|
||
f99_96_search_count = Column(Integer, default=0) # 寻号使用次数
|
||
f99_97_collection_count = Column(Integer, default=0) # 藏品数量
|
||
f01_06_phone_verified = Column(Boolean, default=False) # 手机号已核验
|
||
f99_98_login_count = Column(Integer, default=0) # 登录次数
|
||
f99_99_last_login = Column(DateTime(timezone=True), nullable=True) # 最后登录时间
|
||
f01_07_gender = Column(String(10), nullable=True) # 性别
|
||
f01_08_birthday = Column(Date, nullable=True) # 生日
|
||
f01_09_region = Column(String(100), nullable=True) # 地区
|
||
f01_10_realname_verified = Column(Boolean, default=False) # 实名认证
|
||
f99_100_points = Column(Integer, default=0) # 积分
|
||
f01_11_balance = Column(Float, default=0) # 余额
|
||
f01_12_total_amount = Column(Float, default=0) # 累计金额
|
||
f01_13_invite_code = Column(String(20), nullable=True) # 邀请码
|
||
|
||
collections = relationship("Collection", back_populates="user", cascade="all, delete-orphan")
|
||
operations = relationship("Operation", back_populates="user", cascade="all, delete-orphan")
|
||
custom_fields = relationship("CustomField", back_populates="user", cascade="all, delete-orphan")
|
||
|
||
|
||
class Collection(Base):
|
||
__tablename__ = "collections"
|
||
|
||
# f99 系统字段
|
||
f99_90_id = Column(String(36), primary_key=True, default=generate_uuid)
|
||
f99_91_user_id = Column(String(36), ForeignKey("users.f99_90_id", ondelete="CASCADE"), nullable=False, index=True)
|
||
f99_92_created_at = Column(DateTime(timezone=True), server_default=func.now(), index=True)
|
||
f99_93_updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||
|
||
# f01 基本信息
|
||
f01_01_name = Column(String(255), nullable=False)
|
||
f01_02_code = Column(String(50), nullable=True, index=True)
|
||
f01_03_category = Column(String(100), nullable=False, index=True)
|
||
f01_04_status = Column(String(50), default="in_collection", index=True)
|
||
f01_05_remark = Column(Text, nullable=True)
|
||
|
||
# f02 详细字段
|
||
f02_10_prefix_serial = Column(String(50), nullable=True, index=True)
|
||
f02_11_version = Column(String(100), nullable=True, index=True)
|
||
f02_12_packaging = Column(String(100), nullable=True, index=True)
|
||
f02_13_rarity = Column(String(50), nullable=True, index=True) # 珍惜度
|
||
f02_14_number_category = Column(String(20), nullable=True, index=True) # 号码分类
|
||
|
||
# f03 评级信息
|
||
f03_20_is_graded = Column(Boolean, default=False, index=True)
|
||
f03_21_grading_company = Column(String(100), nullable=True, index=True)
|
||
f03_22_grading_score = Column(String(20), nullable=True, index=True)
|
||
f03_23_three_star = Column(Boolean, default=False, index=True)
|
||
|
||
# f04 特殊信息
|
||
f04_30_special_mark = Column(String(200), nullable=True, index=True)
|
||
f04_31_serial_feature = Column(String(100), nullable=True, index=True)
|
||
f04_32_issuer = Column(String(100), nullable=True, index=True)
|
||
f04_33_issue_year = Column(String(20), nullable=True, index=True)
|
||
f04_34_material = Column(String(50), nullable=True)
|
||
f04_35_denomination = Column(String(20), nullable=True)
|
||
f04_36_issue_quantity = Column(String(50), nullable=True)
|
||
|
||
# f05 价格信息
|
||
f05_40_cost_price = Column(Float, nullable=True, index=True)
|
||
f05_41_target_price = Column(Float, nullable=True, index=True)
|
||
f05_42_goal_price = Column(Float, nullable=True)
|
||
f05_43_repair_fee = Column(Float, nullable=True)
|
||
f05_44_grading_fee = Column(Float, nullable=True)
|
||
|
||
# f06 其他信息
|
||
f06_50_purpose = Column(String(100), nullable=True)
|
||
|
||
user = relationship("User", back_populates="collections")
|
||
images = relationship("CollectionImage", back_populates="collection", cascade="all, delete-orphan")
|
||
operations = relationship("Operation", back_populates="collection", cascade="all, delete-orphan")
|
||
|
||
|
||
class CollectionImage(Base):
|
||
__tablename__ = "collection_images"
|
||
|
||
id = Column(String(36), primary_key=True, default=generate_uuid)
|
||
collection_id = Column(String(36), ForeignKey("collections.f99_90_id", ondelete="CASCADE"), nullable=False, index=True)
|
||
filename = Column(String(255), nullable=False)
|
||
original_name = Column(String(255), nullable=True)
|
||
path = Column(String(500), nullable=True)
|
||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||
|
||
collection = relationship("Collection", back_populates="images")
|
||
|
||
|
||
class Operation(Base):
|
||
__tablename__ = "operations"
|
||
|
||
f99_90_id = Column(String(36), primary_key=True, default=generate_uuid)
|
||
f99_91_user_id = Column(String(36), ForeignKey("collections.f99_90_id", ondelete="CASCADE"), nullable=False, index=True)
|
||
f99_92_user_id = Column(String(36), ForeignKey("users.f99_90_id", ondelete="CASCADE"), nullable=False, index=True)
|
||
type = Column(String(50), nullable=False, index=True)
|
||
price = Column(Float, nullable=True)
|
||
note = Column(Text, nullable=True)
|
||
f99_93_created_at = Column(DateTime(timezone=True), server_default=func.now(), index=True)
|
||
|
||
collection = relationship("Collection", back_populates="operations")
|
||
user = relationship("User", back_populates="operations")
|
||
|
||
|
||
class CustomField(Base):
|
||
__tablename__ = "custom_fields"
|
||
|
||
id = Column(String(36), primary_key=True, default=generate_uuid)
|
||
user_id = Column(String(36), ForeignKey("users.f99_90_id", ondelete="CASCADE"), nullable=False, index=True)
|
||
name = Column(String(100), nullable=False)
|
||
field_type = Column(String(50), default="text")
|
||
options = Column(Text, nullable=True)
|
||
required = Column(Boolean, default=False)
|
||
visible = Column(Boolean, default=True)
|
||
sort_order = Column(Integer, default=0)
|
||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||
|
||
user = relationship("User", back_populates="custom_fields")
|
||
|
||
|
||
# 资讯模型
|
||
class Information(Base):
|
||
__tablename__ = "information"
|
||
|
||
id = Column(String(36), primary_key=True, default=generate_uuid)
|
||
user_id = Column(String(36), ForeignKey("users.f99_90_id", ondelete="CASCADE"), nullable=False, index=True)
|
||
|
||
# 信息类型: seek-寻配号, deal-成交数据, publish-发布
|
||
info_type = Column(String(20), nullable=False, index=True)
|
||
|
||
# 标题
|
||
title = Column(String(255), nullable=False)
|
||
|
||
# 内容描述
|
||
content = Column(Text, nullable=True)
|
||
|
||
# 关联藏品ID
|
||
collection_id = Column(String(36), ForeignKey("collections.f99_90_id", ondelete="SET NULL"), nullable=True)
|
||
|
||
# 期望条件 (寻配号用)
|
||
expect_category = Column(String(100), nullable=True) # 期望类别
|
||
expect_version = Column(String(100), nullable=True) # 期望版别
|
||
expect_packaging = Column(String(100), nullable=True) # 期望包装
|
||
expect_number = Column(String(50), nullable=True) # 期望号码
|
||
expect_price_min = Column(Float, nullable=True) # 期望价格区间
|
||
expect_price_max = Column(Float, nullable=True)
|
||
|
||
# 成交价格 (成交数据用)
|
||
deal_price = Column(Float, nullable=True)
|
||
deal_date = Column(Date, nullable=True)
|
||
|
||
# 状态: active-有效, closed-已关闭, expired-已过期
|
||
status = Column(String(20), default="active", index=True)
|
||
|
||
# 匹配状态: pending-尚未匹配, matched-已经匹配
|
||
is_matched = Column(String(20), default="pending", index=True)
|
||
|
||
# 匹配的用户ID(当用户愿意交换联系方式时)
|
||
matched_user_id = Column(String(36), ForeignKey("users.f99_90_id", ondelete="SET NULL"), nullable=True)
|
||
|
||
# 浏览/联系次数
|
||
view_count = Column(Integer, default=0)
|
||
contact_count = Column(Integer, default=0)
|
||
|
||
created_at = Column(DateTime(timezone=True), server_default=func.now(), index=True)
|
||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||
|
||
user = relationship("User")
|
||
collection = relationship("Collection")
|
||
|
||
|
||
# 资讯评论/留言
|
||
class InformationComment(Base):
|
||
__tablename__ = "information_comments"
|
||
|
||
id = Column(String(36), primary_key=True, default=generate_uuid)
|
||
information_id = Column(String(36), ForeignKey("information.id", ondelete="CASCADE"), nullable=False, index=True)
|
||
user_id = Column(String(36), ForeignKey("users.f99_90_id", ondelete="CASCADE"), nullable=False, index=True)
|
||
content = Column(Text, nullable=False)
|
||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||
|
||
user = relationship("User")
|
||
|
||
|
||
# 资讯联系方式查看记录
|
||
class InformationContactView(Base):
|
||
__tablename__ = "information_contact_views"
|
||
|
||
id = Column(String(36), primary_key=True, default=generate_uuid)
|
||
information_id = Column(String(36), ForeignKey("information.id", ondelete="CASCADE"), nullable=False, index=True)
|
||
viewer_id = Column(String(36), ForeignKey("users.f99_90_id", ondelete="CASCADE"), nullable=False, index=True)
|
||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||
|
||
viewer = relationship("User")
|
||
|
||
|
||
# 资讯关联用户 (收藏/点赞)
|
||
class InformationLike(Base):
|
||
__tablename__ = "information_likes"
|
||
|
||
id = Column(String(36), primary_key=True, default=generate_uuid)
|
||
information_id = Column(String(36), ForeignKey("information.id", ondelete="CASCADE"), nullable=False, index=True)
|
||
user_id = Column(String(36), ForeignKey("users.f99_90_id", ondelete="CASCADE"), nullable=False, index=True)
|
||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||
|
||
__table_args__ = (
|
||
UniqueConstraint('information_id', 'user_id', name='uq_information_user'),
|
||
)
|
||
|
||
|
||
# 角色常量
|
||
class UserRole:
|
||
ADMIN = "admin" # 管理员:全部权限
|
||
EDITOR = "editor" # 信息员:可发布信息、管理资讯
|
||
USER = "user" # 普通用户:基本功能
|
||
|
||
@classmethod
|
||
def get_role_name(cls, role):
|
||
names = {
|
||
cls.ADMIN: "管理员",
|
||
cls.EDITOR: "信息员",
|
||
cls.USER: "用户"
|
||
}
|
||
return names.get(role, "用户")
|