Files
NBATransfer/NBATransfer-backend/models.py
2025-12-14 15:40:49 +08:00

234 lines
8.9 KiB
Python

from datetime import datetime, timedelta
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash
import secrets
import string
from extensions import db
# db = SQLAlchemy() # Moved to extensions.py
class User(db.Model):
"""用户模型"""
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(120), unique=True, nullable=False, index=True)
password_hash = db.Column(db.String(255), nullable=False)
username = db.Column(db.String(80))
balance = db.Column(db.Float, default=0.0) # 账户余额
is_active = db.Column(db.Boolean, default=True)
is_admin = db.Column(db.Boolean, default=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# 关系
orders = db.relationship('Order', backref='user', lazy='dynamic', cascade='all, delete-orphan')
api_calls = db.relationship('ApiCall', backref='user', lazy='dynamic', cascade='all, delete-orphan')
transactions = db.relationship('Transaction', backref='user', lazy='dynamic', cascade='all, delete-orphan')
api_keys = db.relationship('APIKey', backref='user', lazy='dynamic', cascade='all, delete-orphan')
verification_codes = db.relationship('VerificationCode', backref='user', lazy='dynamic', cascade='all, delete-orphan')
# 验证状态
email_verified = db.Column(db.Boolean, default=False)
email_verified_at = db.Column(db.DateTime)
def set_password(self, password):
"""设置密码"""
self.password_hash = generate_password_hash(password)
def check_password(self, password):
"""验证密码"""
return check_password_hash(self.password_hash, password)
def to_dict(self):
"""转换为字典"""
return {
'id': self.id,
'email': self.email,
'username': self.username,
'balance': self.balance,
'is_active': self.is_active,
'is_admin': self.is_admin,
'created_at': self.created_at.isoformat(),
'updated_at': self.updated_at.isoformat()
}
class Order(db.Model):
"""订单模型"""
__tablename__ = 'orders'
id = db.Column(db.Integer, primary_key=True)
order_no = db.Column(db.String(50), unique=True, nullable=False, index=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
amount = db.Column(db.Float, nullable=False) # 充值金额
payment_method = db.Column(db.String(20)) # wechat, alipay
status = db.Column(db.String(20), default='pending') # pending, paid, cancelled, failed
transaction_id = db.Column(db.String(100)) # 第三方交易ID
created_at = db.Column(db.DateTime, default=datetime.utcnow)
paid_at = db.Column(db.DateTime)
def to_dict(self):
"""转换为字典"""
return {
'id': self.id,
'order_no': self.order_no,
'user_id': self.user_id,
'amount': self.amount,
'payment_method': self.payment_method,
'status': self.status,
'transaction_id': self.transaction_id,
'created_at': self.created_at.isoformat(),
'paid_at': self.paid_at.isoformat() if self.paid_at else None
}
class Transaction(db.Model):
"""交易记录模型"""
__tablename__ = 'transactions'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
type = db.Column(db.String(20), nullable=False) # recharge, consume, refund
amount = db.Column(db.Float, nullable=False)
balance_before = db.Column(db.Float, nullable=False)
balance_after = db.Column(db.Float, nullable=False)
description = db.Column(db.String(255))
order_id = db.Column(db.Integer, db.ForeignKey('orders.id'))
api_call_id = db.Column(db.Integer, db.ForeignKey('api_calls.id'))
created_at = db.Column(db.DateTime, default=datetime.utcnow)
def to_dict(self):
"""转换为字典"""
return {
'id': self.id,
'user_id': self.user_id,
'type': self.type,
'amount': self.amount,
'balance_before': self.balance_before,
'balance_after': self.balance_after,
'description': self.description,
'order_id': self.order_id,
'api_call_id': self.api_call_id,
'created_at': self.created_at.isoformat()
}
class ApiCall(db.Model):
"""API调用记录模型"""
__tablename__ = 'api_calls'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
api_type = db.Column(db.String(50), default='text_to_image') # text_to_image
prompt = db.Column(db.Text)
parameters = db.Column(db.Text) # JSON格式的参数
status = db.Column(db.String(20), default='pending') # pending, processing, success, failed
result_url = db.Column(db.String(500)) # 生成结果的URL
cost = db.Column(db.Float, default=0.0) # 本次调用费用
error_message = db.Column(db.Text)
request_time = db.Column(db.DateTime, default=datetime.utcnow)
response_time = db.Column(db.DateTime)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
def to_dict(self):
"""转换为字典"""
return {
'id': self.id,
'user_id': self.user_id,
'api_type': self.api_type,
'prompt': self.prompt,
'status': self.status,
'result_url': self.result_url,
'cost': self.cost,
'error_message': self.error_message,
'request_time': self.request_time.isoformat(),
'response_time': self.response_time.isoformat() if self.response_time else None,
'created_at': self.created_at.isoformat()
}
class SystemConfig(db.Model):
"""系统配置模型"""
__tablename__ = 'system_configs'
id = db.Column(db.Integer, primary_key=True)
key = db.Column(db.String(50), unique=True, nullable=False)
value = db.Column(db.Text)
description = db.Column(db.String(255))
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
def to_dict(self):
"""转换为字典"""
return {
'id': self.id,
'key': self.key,
'value': self.value,
'description': self.description,
'updated_at': self.updated_at.isoformat()
}
class VerificationCode(db.Model):
"""邮箱验证码模型"""
__tablename__ = 'verification_codes'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
email = db.Column(db.String(120), nullable=False)
code = db.Column(db.String(6), nullable=False) # 6位验证码
purpose = db.Column(db.String(20), default='register') # register, password_reset
used = db.Column(db.Boolean, default=False)
expired_at = db.Column(db.DateTime, nullable=False) # 过期时间
created_at = db.Column(db.DateTime, default=datetime.utcnow)
def is_valid(self):
"""检查验证码是否有效"""
return not self.used and datetime.utcnow() < self.expired_at
@staticmethod
def generate_code():
"""生成6位验证码"""
return ''.join(secrets.choice(string.digits) for _ in range(6))
def to_dict(self):
return {
'id': self.id,
'email': self.email,
'purpose': self.purpose,
'expired_at': self.expired_at.isoformat()
}
class APIKey(db.Model):
"""API密钥模型 - 用户可自己生成"""
__tablename__ = 'api_keys'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
name = db.Column(db.String(100), nullable=False) # API密钥名称
api_key = db.Column(db.String(100), unique=True, nullable=False, index=True) # 实际密钥
# secret_key 字段已移除
is_active = db.Column(db.Boolean, default=True)
last_used_at = db.Column(db.DateTime) # 最后使用时间
created_at = db.Column(db.DateTime, default=datetime.utcnow)
@staticmethod
def generate_key():
"""生成 API Key"""
api_key = 'sk_' + ''.join(secrets.choice(string.ascii_letters + string.digits) for _ in range(32))
return api_key
def to_dict(self):
"""转换为字典"""
data = {
'id': self.id,
'name': self.name,
'api_key': self.api_key,
'is_active': self.is_active,
'last_used_at': self.last_used_at.isoformat() if self.last_used_at else None,
'created_at': self.created_at.isoformat()
}
return data