jiachenlong/backend/app/models/models.py

269 lines
12 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 数据库模型 - 使用字段编码
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) # 邀请码(自己的邀请码)
f99_101_invited_count = Column(Integer, default=0) # 通过自己邀请码注册的用户数量
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)
# 评级相关字段
packaging = Column(String(50), nullable=True)
is_graded = Column(Boolean, default=False)
grading_company = Column(String(100), nullable=True)
grading_score = Column(String(50), nullable=True)
category = Column(String(100), nullable=True)
# 行情编号
deal_no = Column(String(50), nullable=True, index=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)
# 匹配者的联系方式(只有发布者和匹配者可见)
matched_contact = Column(String(100), 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", foreign_keys=[user_id])
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", foreign_keys=[user_id])
# 资讯联系方式查看记录
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", foreign_keys=[viewer_id])
# 资讯关联用户 (收藏/点赞)
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, "用户")