feat: 用户个人中心功能

- 账户余额显示和管理
- 充值功能(模拟模式)
- 退款申请功能(需管理员审核)
- 账户流水记录查看
- 会员购买记录查看
- 使用统计展示
- 新增模型:UserRecharge, UserRefund, MembershipPurchase, AccountTransaction
- User模型添加balance字段
- 导航栏添加个人中心入口
This commit is contained in:
2026-04-14 18:29:46 +08:00
parent 436ac2cb66
commit 4f33e92abf
5 changed files with 699 additions and 1 deletions

189
models.py
View File

@@ -38,8 +38,13 @@ class User(db.Model):
is_active = db.Column(db.Boolean, default=True) # 是否启用
is_admin = db.Column(db.Boolean, default=False) # 是否管理员
# 余额
balance = db.Column(db.Float, default=0.0) # 账户余额(元)
# 关系
translations = db.relationship('Translation', backref='user', lazy=True)
recharges = db.relationship('UserRecharge', backref='user', lazy=True)
refunds = db.relationship('UserRefund', backref='user', lazy=True)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
@@ -102,6 +107,7 @@ class User(db.Model):
'is_vip': self.is_vip(),
'is_admin': self.is_admin,
'is_active': self.is_active,
'balance': self.balance,
'daily_count': self.daily_count,
'total_count': self.total_count,
'created_at': self.created_at.isoformat() if self.created_at else None,
@@ -520,4 +526,187 @@ class MembershipPlanConfig(db.Model):
'is_active': self.is_active,
'is_recommended': self.is_recommended,
'is_system': self.is_system,
}
# ==================== 用户充值记录 ====================
class UserRecharge(db.Model):
"""用户充值记录"""
__tablename__ = 'user_recharges'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
# 充值信息
amount = db.Column(db.Float, nullable=False) # 充值金额
balance_before = db.Column(db.Float, default=0) # 充值前余额
balance_after = db.Column(db.Float, default=0) # 充值后余额
# 支付方式
payment_method = db.Column(db.String(20), default='balance') # balance, alipay, wechat, manual
# 状态
status = db.Column(db.String(20), default='pending') # pending, completed, failed, cancelled
order_no = db.Column(db.String(64), unique=True, nullable=True) # 订单号
# 备注
remark = db.Column(db.String(255), nullable=True) # 管理员备注
operator_id = db.Column(db.Integer, nullable=True) # 操作管理员ID
# 时间
created_at = db.Column(db.DateTime, default=datetime.utcnow)
completed_at = db.Column(db.DateTime, nullable=True)
def to_dict(self):
return {
'id': self.id,
'user_id': self.user_id,
'amount': self.amount,
'balance_before': self.balance_before,
'balance_after': self.balance_after,
'payment_method': self.payment_method,
'status': self.status,
'order_no': self.order_no,
'remark': self.remark,
'created_at': self.created_at.isoformat() if self.created_at else None,
'completed_at': self.completed_at.isoformat() if self.completed_at else None,
}
# ==================== 用户退款记录 ====================
class UserRefund(db.Model):
"""用户退款记录"""
__tablename__ = 'user_refunds'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
recharge_id = db.Column(db.Integer, db.ForeignKey('user_recharges.id'), nullable=True) # 关联充值记录
# 退款信息
amount = db.Column(db.Float, nullable=False) # 退款金额
balance_before = db.Column(db.Float, default=0) # 退款前余额
balance_after = db.Column(db.Float, default=0) # 退款后余额
# 原因
reason = db.Column(db.String(255), nullable=True) # 退款原因
reason_type = db.Column(db.String(20), default='user_request') # user_request, system_error, admin_initiated
# 状态
status = db.Column(db.String(20), default='pending') # pending, approved, completed, rejected
# 操作
operator_id = db.Column(db.Integer, nullable=True) # 处理管理员ID
operator_remark = db.Column(db.String(255), nullable=True) # 管理员处理备注
# 时间
created_at = db.Column(db.DateTime, default=datetime.utcnow)
processed_at = db.Column(db.DateTime, nullable=True)
completed_at = db.Column(db.DateTime, nullable=True)
def to_dict(self):
return {
'id': self.id,
'user_id': self.user_id,
'recharge_id': self.recharge_id,
'amount': self.amount,
'balance_before': self.balance_before,
'balance_after': self.balance_after,
'reason': self.reason,
'reason_type': self.reason_type,
'status': self.status,
'operator_remark': self.operator_remark,
'created_at': self.created_at.isoformat() if self.created_at else None,
'processed_at': self.processed_at.isoformat() if self.processed_at else None,
'completed_at': self.completed_at.isoformat() if self.completed_at else None,
}
# ==================== 会员购买记录 ====================
class MembershipPurchase(db.Model):
"""会员购买记录"""
__tablename__ = 'membership_purchases'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
# 套餐信息
plan_key = db.Column(db.String(50), nullable=False) # vip_basic, vip_pro, vip_enterprise
plan_name = db.Column(db.String(100), nullable=False) # 基础会员, 专业会员
# 价格
price = db.Column(db.Float, nullable=False) # 实付金额
original_price = db.Column(db.Float, nullable=True) # 原价
# 有效期
period_days = db.Column(db.Integer, default=30) # 购买天数
expire_before = db.Column(db.DateTime, nullable=True) # 购买前到期时间
expire_after = db.Column(db.DateTime, nullable=True) # 购买后到期时间
# 支付方式
payment_method = db.Column(db.String(20), default='balance') # balance, alipay, wechat
# 状态
status = db.Column(db.String(20), default='completed') # pending, completed, refunded
# 时间
created_at = db.Column(db.DateTime, default=datetime.utcnow)
# 关系
user = db.relationship('User', backref=db.backref('membership_purchases', lazy=True))
def to_dict(self):
return {
'id': self.id,
'user_id': self.user_id,
'plan_key': self.plan_key,
'plan_name': self.plan_name,
'price': self.price,
'original_price': self.original_price,
'period_days': self.period_days,
'expire_after': self.expire_after.isoformat() if self.expire_after else None,
'payment_method': self.payment_method,
'status': self.status,
'created_at': self.created_at.isoformat() if self.created_at else None,
}
# ==================== 账户流水记录 ====================
class AccountTransaction(db.Model):
"""账户流水记录"""
__tablename__ = 'account_transactions'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
# 流水信息
transaction_type = db.Column(db.String(20), nullable=False) # recharge, refund, purchase, consume, refund_purchase
amount = db.Column(db.Float, nullable=False) # 金额(正数加,负数减)
balance_before = db.Column(db.Float, default=0) # 操作前余额
balance_after = db.Column(db.Float, default=0) # 操作后余额
# 关联
related_id = db.Column(db.Integer, nullable=True) # 关联记录ID充值ID、退款ID等
related_type = db.Column(db.String(50), nullable=True) # 关联类型recharge, refund, membership_purchase等
# 描述
description = db.Column(db.String(255), nullable=True) # 流水描述
# 时间
created_at = db.Column(db.DateTime, default=datetime.utcnow)
# 关系
user = db.relationship('User', backref=db.backref('transactions', lazy=True))
def to_dict(self):
return {
'id': self.id,
'user_id': self.user_id,
'transaction_type': self.transaction_type,
'amount': self.amount,
'balance_before': self.balance_before,
'balance_after': self.balance_after,
'related_id': self.related_id,
'related_type': self.related_type,
'description': self.description,
'created_at': self.created_at.isoformat() if self.created_at else None,
}