feat: 添加手机号、邀请好友、邮件通知功能
- 用户模型添加:手机号、邀请码、邀请统计、邮件通知设置 - 邀请好友系统:专属邀请码、邀请奖励(¥5/人) - 邮件通知:翻译完成通知(含附件)、欢迎邮件、到期提醒 - 新增模型:UserInvitation, InviteRewardConfig, EmailNotification, EmailTemplateConfig - 个人中心添加:手机号绑定、通知设置、邀请好友模块 - email_service.py:邮件发送服务(支持附件) 新用户注册奖励:¥2 邀请人奖励:¥5/人
This commit is contained in:
196
models.py
196
models.py
@@ -41,8 +41,25 @@ class User(db.Model):
|
||||
# 余额
|
||||
balance = db.Column(db.Float, default=0.0) # 账户余额(元)
|
||||
|
||||
# 手机号
|
||||
phone = db.Column(db.String(20), nullable=True) # 手机号
|
||||
phone_verified = db.Column(db.Boolean, default=False) # 手机号已验证
|
||||
|
||||
# 邀请系统
|
||||
invite_code = db.Column(db.String(10), unique=True, nullable=True) # 用户专属邀请码
|
||||
invited_by = db.Column(db.Integer, nullable=True) # 邀请人ID
|
||||
invite_count = db.Column(db.Integer, default=0) # 已邀请人数
|
||||
invite_rewards = db.Column(db.Float, default=0.0) # 邀请奖励金额
|
||||
|
||||
# 邮件通知设置
|
||||
email_notify = db.Column(db.Boolean, default=True) # 邮件通知开关
|
||||
notify_on_complete = db.Column(db.Boolean, default=True) # 翻译完成通知
|
||||
notify_on_expire = db.Column(db.Boolean, default=True) # 会员到期提醒
|
||||
|
||||
# 关系
|
||||
translations = db.relationship('Translation', backref='user', lazy=True)
|
||||
invitations = db.relationship('UserInvitation', backref='inviter', lazy=True,
|
||||
foreign_keys='UserInvitation.inviter_id')
|
||||
recharges = db.relationship('UserRecharge', backref='user', lazy=True)
|
||||
refunds = db.relationship('UserRefund', backref='user', lazy=True)
|
||||
|
||||
@@ -103,11 +120,19 @@ class User(db.Model):
|
||||
'id': self.id,
|
||||
'username': self.username,
|
||||
'email': self.email,
|
||||
'phone': self.phone,
|
||||
'phone_verified': self.phone_verified,
|
||||
'user_type': self.user_type,
|
||||
'is_vip': self.is_vip(),
|
||||
'is_admin': self.is_admin,
|
||||
'is_active': self.is_active,
|
||||
'balance': self.balance,
|
||||
'invite_code': self.invite_code,
|
||||
'invite_count': self.invite_count,
|
||||
'invite_rewards': self.invite_rewards,
|
||||
'email_notify': self.email_notify,
|
||||
'notify_on_complete': self.notify_on_complete,
|
||||
'notify_on_expire': self.notify_on_expire,
|
||||
'daily_count': self.daily_count,
|
||||
'total_count': self.total_count,
|
||||
'created_at': self.created_at.isoformat() if self.created_at else None,
|
||||
@@ -709,4 +734,175 @@ class AccountTransaction(db.Model):
|
||||
'related_type': self.related_type,
|
||||
'description': self.description,
|
||||
'created_at': self.created_at.isoformat() if self.created_at else None,
|
||||
}
|
||||
|
||||
|
||||
# ==================== 用户邀请记录 ====================
|
||||
class UserInvitation(db.Model):
|
||||
"""用户邀请记录"""
|
||||
__tablename__ = 'user_invitations'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
|
||||
# 邀请人
|
||||
inviter_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
|
||||
invite_code = db.Column(db.String(10), nullable=False) # 使用的邀请码
|
||||
|
||||
# 被邀请人
|
||||
invitee_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True) # 注册后关联
|
||||
invitee_email = db.Column(db.String(120), nullable=True) # 被邀请人邮箱(注册前)
|
||||
|
||||
# 奖励
|
||||
reward_amount = db.Column(db.Float, default=0.0) # 奖励金额
|
||||
reward_given = db.Column(db.Boolean, default=False) # 是否已发放奖励
|
||||
|
||||
# 状态
|
||||
status = db.Column(db.String(20), default='pending') # pending, registered, rewarded
|
||||
|
||||
# 时间
|
||||
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
||||
registered_at = db.Column(db.DateTime, nullable=True) # 被邀请人注册时间
|
||||
rewarded_at = db.Column(db.DateTime, nullable=True) # 奖励发放时间
|
||||
|
||||
# 关系
|
||||
invitee = db.relationship('User', backref=db.backref('invited_by_record', lazy=True),
|
||||
foreign_keys=[invitee_id])
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
'inviter_id': self.inviter_id,
|
||||
'invite_code': self.invite_code,
|
||||
'invitee_id': self.invitee_id,
|
||||
'invitee_email': self.invitee_email,
|
||||
'reward_amount': self.reward_amount,
|
||||
'reward_given': self.reward_given,
|
||||
'status': self.status,
|
||||
'created_at': self.created_at.isoformat() if self.created_at else None,
|
||||
}
|
||||
|
||||
|
||||
# ==================== 邀请奖励配置 ====================
|
||||
class InviteRewardConfig(db.Model):
|
||||
"""邀请奖励配置"""
|
||||
__tablename__ = 'invite_reward_config'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
|
||||
# 奖励规则
|
||||
reward_amount = db.Column(db.Float, default=5.0) # 邀请奖励金额(元)
|
||||
invitee_bonus = db.Column(db.Float, default=2.0) # 被邀请人 bonus(元)
|
||||
min_invitee_user_type = db.Column(db.String(20), default='free') # 被邀请人最低等级才能奖励
|
||||
|
||||
# 限制
|
||||
max_daily_invites = db.Column(db.Integer, default=10) # 每日最大邀请次数
|
||||
max_total_invites = db.Column(db.Integer, default=100) # 总最大邀请次数
|
||||
|
||||
# 状态
|
||||
is_active = db.Column(db.Boolean, default=True)
|
||||
|
||||
# 时间
|
||||
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
||||
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
'reward_amount': self.reward_amount,
|
||||
'invitee_bonus': self.invitee_bonus,
|
||||
'min_invitee_user_type': self.min_invitee_user_type,
|
||||
'max_daily_invites': self.max_daily_invites,
|
||||
'max_total_invites': self.max_total_invites,
|
||||
'is_active': self.is_active,
|
||||
}
|
||||
|
||||
|
||||
# ==================== 邮件通知记录 ====================
|
||||
class EmailNotification(db.Model):
|
||||
"""邮件通知记录"""
|
||||
__tablename__ = 'email_notifications'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
|
||||
|
||||
# 邮件信息
|
||||
email_to = db.Column(db.String(120), nullable=False) # 收件人
|
||||
email_type = db.Column(db.String(30), nullable=False) # complete, expire, invoice, welcome
|
||||
|
||||
# 附件
|
||||
has_attachment = db.Column(db.Boolean, default=False)
|
||||
attachment_path = db.Column(db.String(255), nullable=True) # 附件文件路径
|
||||
attachment_name = db.Column(db.String(100), nullable=True) # 附件显示名称
|
||||
|
||||
# 内容
|
||||
subject = db.Column(db.String(200), nullable=True)
|
||||
body_preview = db.Column(db.Text, nullable=True) # 正文预览
|
||||
|
||||
# 状态
|
||||
status = db.Column(db.String(20), default='pending') # pending, sent, failed
|
||||
error_message = db.Column(db.String(255), nullable=True)
|
||||
|
||||
# 关联
|
||||
related_id = db.Column(db.Integer, nullable=True) # 关联ID(翻译ID、订单ID等)
|
||||
related_type = db.Column(db.String(30), nullable=True) # 关联类型
|
||||
|
||||
# 时间
|
||||
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
||||
sent_at = db.Column(db.DateTime, nullable=True)
|
||||
|
||||
# 关系
|
||||
user = db.relationship('User', backref=db.backref('email_notifications', lazy=True))
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
'user_id': self.user_id,
|
||||
'email_to': self.email_to,
|
||||
'email_type': self.email_type,
|
||||
'has_attachment': self.has_attachment,
|
||||
'subject': self.subject,
|
||||
'status': self.status,
|
||||
'created_at': self.created_at.isoformat() if self.created_at else None,
|
||||
'sent_at': self.sent_at.isoformat() if self.sent_at else None,
|
||||
}
|
||||
|
||||
|
||||
# ==================== 邮件模板配置 ====================
|
||||
class EmailTemplateConfig(db.Model):
|
||||
"""邮件模板配置"""
|
||||
__tablename__ = 'email_template_config'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
|
||||
template_key = db.Column(db.String(50), unique=True, nullable=False) # complete, expire, invoice, welcome, invite
|
||||
template_name = db.Column(db.String(100), nullable=False) # 显示名称
|
||||
|
||||
# 模板内容
|
||||
subject_template = db.Column(db.String(200), nullable=False) # 主题模板
|
||||
body_template = db.Column(db.Text, nullable=False) # 正文模板(支持变量)
|
||||
|
||||
# 支持变量说明
|
||||
variables = db.Column(db.Text, nullable=True) # JSON: ["username", "filename", ...]
|
||||
|
||||
# 状态
|
||||
is_active = db.Column(db.Boolean, default=True)
|
||||
|
||||
# 时间
|
||||
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
||||
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
|
||||
def get_variables(self):
|
||||
import json
|
||||
try:
|
||||
return json.loads(self.variables) if self.variables else []
|
||||
except:
|
||||
return []
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
'template_key': self.template_key,
|
||||
'template_name': self.template_name,
|
||||
'subject_template': self.subject_template,
|
||||
'is_active': self.is_active,
|
||||
}
|
||||
Reference in New Issue
Block a user