235 lines
13 KiB
Python
235 lines
13 KiB
Python
![]() |
from datetime import datetime, timedelta
|
|||
|
import random
|
|||
|
import string
|
|||
|
from django.contrib.auth.models import AbstractUser
|
|||
|
from django.db import models
|
|||
|
from datetime import datetime
|
|||
|
|
|||
|
def generate_unique_referral_code():
|
|||
|
while True:
|
|||
|
referral_code = ''.join(random.choices(string.ascii_uppercase + string.digits, k=8))
|
|||
|
if not User.objects.filter(referral_code=referral_code).exists():
|
|||
|
return referral_code
|
|||
|
|
|||
|
class User(AbstractUser):
|
|||
|
phone = models.CharField(max_length=20, unique=True, null=True, blank=True) # 手机号,唯一,可以为空
|
|||
|
google_id = models.CharField(max_length=50, unique=True, null=True, blank=True) # Google ID,唯一,可以为空
|
|||
|
is_member = models.BooleanField(default=False) # 是否是会员
|
|||
|
points = models.IntegerField(default=0) # 用户积分
|
|||
|
invited_by = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, related_name='invitees') # 邀请人
|
|||
|
referral_code = models.CharField(max_length=50, unique=True) # 推荐码,唯一
|
|||
|
commission_rate = models.DecimalField(max_digits=5, decimal_places=2, default=0.00) # 返佣比例
|
|||
|
created_at = models.DateTimeField(default=datetime.now) # 创建时间
|
|||
|
updated_at = models.DateTimeField(auto_now=True) # 更新时间
|
|||
|
login_count = models.IntegerField(default=0) # 登录次数
|
|||
|
last_login_ip = models.GenericIPAddressField(null=True, blank=True) # 最后登录IP
|
|||
|
membership_start = models.DateTimeField(null=True, blank=True) # 会员开始时间
|
|||
|
membership_end = models.DateTimeField(null=True, blank=True) # 会员到期时间
|
|||
|
openid_used = models.CharField(max_length=150, null=True, blank=True, unique=True) # 已用的 openid,确保每个 openid 只能使用一次
|
|||
|
source = models.CharField(max_length=50, default='web') # 用户来源,默认为 'web'
|
|||
|
|
|||
|
def save(self, *args, **kwargs):
|
|||
|
if not self.referral_code:
|
|||
|
self.referral_code = generate_unique_referral_code()
|
|||
|
super().save(*args, **kwargs)
|
|||
|
|
|||
|
def __str__(self):
|
|||
|
return self.username
|
|||
|
|
|||
|
class Referral(models.Model):
|
|||
|
referrer = models.ForeignKey(User, on_delete=models.CASCADE, related_name='referrals_made') # 邀请人ID,外键,引用User模型
|
|||
|
referee = models.ForeignKey(User, on_delete=models.CASCADE, related_name='referrals_received') # 被邀请人ID,外键,引用User模型
|
|||
|
commission_amount = models.DecimalField(max_digits=10, decimal_places=2) # 返佣金额,最大值为99999999.99
|
|||
|
created_at = models.DateTimeField(default=datetime.now) # 创建时间,默认当前时间
|
|||
|
|
|||
|
def __str__(self):
|
|||
|
return f'{self.referrer} invited {self.referee}'
|
|||
|
|
|||
|
class UserSource(models.Model):
|
|||
|
user = models.ForeignKey(User, on_delete=models.CASCADE) # 用户ID,外键,引用User模型
|
|||
|
source = models.CharField(max_length=50) # 用户来源,最大长度50
|
|||
|
created_at = models.DateTimeField(default=datetime.now) # 创建时间,默认当前时间
|
|||
|
|
|||
|
def __str__(self):
|
|||
|
return f'{self.user} - {self.source}'
|
|||
|
|
|||
|
class SMSVerificationCode(models.Model):
|
|||
|
phone_number = models.CharField(max_length=15) # 手机号
|
|||
|
code = models.CharField(max_length=6) # 验证码
|
|||
|
created_at = models.DateTimeField(auto_now_add=True) # 创建时间,自动设置为当前时间
|
|||
|
is_used = models.BooleanField(default=False) # 是否已使用
|
|||
|
|
|||
|
def is_expired(self):
|
|||
|
return self.created_at < datetime.now() - timedelta(minutes=5) # 判断验证码是否已过期
|
|||
|
|
|||
|
def __str__(self):
|
|||
|
return f"{self.phone_number} - {self.code}"
|
|||
|
|
|||
|
class EmailVerificationCode(models.Model):
|
|||
|
email = models.EmailField() # 邮箱地址
|
|||
|
code = models.CharField(max_length=6) # 验证码
|
|||
|
created_at = models.DateTimeField(auto_now_add=True) # 创建时间,自动设置为当前时间
|
|||
|
is_used = models.BooleanField(default=False) # 是否已使用
|
|||
|
|
|||
|
def is_expired(self):
|
|||
|
return self.created_at < datetime.now() - timedelta(minutes=5) # 判断验证码是否已过期
|
|||
|
|
|||
|
def __str__(self):
|
|||
|
return f"{self.email} - {self.code}"
|
|||
|
|
|||
|
class VideoGeneration(models.Model):
|
|||
|
STATUS_CHOICES = [
|
|||
|
('pending', 'Pending'),
|
|||
|
('in_progress', 'In Progress'),
|
|||
|
('completed', 'Completed'),
|
|||
|
('failed', 'Failed'),
|
|||
|
]
|
|||
|
|
|||
|
video_id = models.CharField(max_length=255, unique=True, default='')
|
|||
|
user = models.ForeignKey(User, on_delete=models.CASCADE) # 生成请求的用户
|
|||
|
text = models.TextField(null=True) # 输入文本
|
|||
|
voice_name = models.CharField(max_length=50, null=True) # 选择的语音
|
|||
|
style = models.CharField(max_length=50, default='general', null=True) # 语音风格
|
|||
|
rate = models.IntegerField(default=0, null=True) # 语速
|
|||
|
media_type = models.CharField(max_length=50, null=True) # 媒体类型
|
|||
|
ratio = models.CharField(max_length=10) # 视频比例
|
|||
|
audio_url = models.URLField(null=True, blank=True) # 生成的音频URL
|
|||
|
video_url = models.URLField(null=True, blank=True) # 生成的视频URL
|
|||
|
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending') # 生成状态
|
|||
|
created_at = models.DateTimeField(default=datetime.now) # 创建时间
|
|||
|
updated_at = models.DateTimeField(auto_now=True) # 更新时间
|
|||
|
slug = models.CharField(max_length=50) # 生成视频的类型
|
|||
|
pid = models.CharField(max_length=50, null=True, default='') # 生成视频的ID
|
|||
|
extension_count = models.IntegerField(default=0) # 延长次数,最多3次
|
|||
|
time_duration = models.IntegerField(default=0) # 生成时长
|
|||
|
|
|||
|
def __str__(self):
|
|||
|
return f'{self.video_id} - {self.user.username} - {self.status} - {self.created_at}'
|
|||
|
|
|||
|
class Plan(models.Model):
|
|||
|
"""
|
|||
|
存放套餐信息的数据库模型
|
|||
|
"""
|
|||
|
title = models.CharField(max_length=100, unique=True) # 套餐标题,标识套餐的名称(如 HOBBY、GROWTH、GROWTH PLUS)
|
|||
|
description = models.TextField() # 套餐描述,详细说明套餐中包含的所有功能和服务
|
|||
|
price = models.DecimalField(max_digits=10, decimal_places=2) # 套餐价格,表示套餐的费用,保留两位小数
|
|||
|
credits_per_month = models.IntegerField(default=0) # 每月积分,套餐中包含的每月 AI 积分数
|
|||
|
created_at = models.DateTimeField(default=datetime.now) # 创建时间,记录套餐的创建时间
|
|||
|
updated_at = models.DateTimeField(auto_now=True) # 更新时间,记录套餐信息的最后更新时间
|
|||
|
is_promotional = models.BooleanField(default=False) # 是否为促销活动,用于标识该套餐是否属于促销套餐
|
|||
|
unlimited_exports = models.BooleanField(default=False) # 是否允许无限导出功能,适用于一些高级套餐
|
|||
|
smart_music_sync = models.BooleanField(default=False) # 是否包含智能音乐同步功能,用于标识该套餐是否包含此项服务
|
|||
|
|
|||
|
def __str__(self):
|
|||
|
return self.title
|
|||
|
|
|||
|
class Order(models.Model):
|
|||
|
PAYMENT_METHOD_CHOICES = [
|
|||
|
('alipay', 'Alipay'),
|
|||
|
('paypal', 'PayPal'),
|
|||
|
]
|
|||
|
|
|||
|
ORDER_STATUS_CHOICES = [
|
|||
|
('pending', 'Pending'),
|
|||
|
('completed', 'Completed'),
|
|||
|
('canceled', 'Canceled'),
|
|||
|
('failed', 'Failed'),
|
|||
|
]
|
|||
|
|
|||
|
order_id = models.CharField(max_length=100, unique=True) # 订单唯一标识符
|
|||
|
user = models.ForeignKey('User', on_delete=models.CASCADE) # 用户外键
|
|||
|
username = models.CharField(max_length=150) # 用户名(邮箱或手机号)
|
|||
|
plan = models.ForeignKey('Plan', on_delete=models.CASCADE) # 关联套餐
|
|||
|
amount = models.DecimalField(max_digits=10, decimal_places=2,default=0.00) # 订单金额
|
|||
|
payment_method = models.CharField(max_length=10, choices=PAYMENT_METHOD_CHOICES) # 支付方式
|
|||
|
status = models.CharField(max_length=10, choices=ORDER_STATUS_CHOICES, default='pending') # 订单状态
|
|||
|
created_at = models.DateTimeField(default=datetime.now) # 创建时间
|
|||
|
updated_at = models.DateTimeField(auto_now=True) # 更新时间
|
|||
|
|
|||
|
def __str__(self):
|
|||
|
return f"Order {self.order_id} - {self.status}"
|
|||
|
|
|||
|
class Meta:
|
|||
|
verbose_name = 'Order'
|
|||
|
verbose_name_plural = 'Orders'
|
|||
|
ordering = ['-created_at']
|
|||
|
|
|||
|
|
|||
|
class TransactionHistory(models.Model):
|
|||
|
"""
|
|||
|
记录用户的积分消费明细
|
|||
|
"""
|
|||
|
FEATURE_CHOICES = [
|
|||
|
('text-to-video', 'AI文生视频'),
|
|||
|
('img-to-video', 'AI图生视频'),
|
|||
|
('create-tiktok-video', 'AI长视频生成'),
|
|||
|
('music-to-video', '音乐视频生成'),
|
|||
|
('create-avatar-video', '虚拟形象视频生成'),
|
|||
|
]
|
|||
|
|
|||
|
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='transactions', verbose_name='用户') # 关联用户
|
|||
|
feature = models.CharField(max_length=50, choices=FEATURE_CHOICES, verbose_name='功能类型') # 功能类型
|
|||
|
points_spent = models.IntegerField(verbose_name='消费积分') # 消费的积分数量
|
|||
|
char_count = models.IntegerField(blank=True, null=True, verbose_name='字符数量') # 记录字符数量(如果是文本相关的功能)
|
|||
|
description = models.TextField(blank=True, null=True, verbose_name='操作描述') # 记录操作的详细描述
|
|||
|
transaction_date = models.DateTimeField(default=datetime.now, verbose_name='消费时间') # 消费时间
|
|||
|
previous_points_balance = models.IntegerField(verbose_name='消费前积分') # 用户消费前的积分余额
|
|||
|
new_points_balance = models.IntegerField(verbose_name='消费后积分') # 用户消费后的积分余额
|
|||
|
success = models.BooleanField(default=True, verbose_name='是否成功') # 记录是否成功扣费
|
|||
|
|
|||
|
class Meta:
|
|||
|
db_table = 'transaction_history'
|
|||
|
verbose_name = '消费明细'
|
|||
|
verbose_name_plural = '消费明细'
|
|||
|
ordering = ['-transaction_date'] # 按消费时间倒序排列
|
|||
|
|
|||
|
def __str__(self):
|
|||
|
return f'用户 {self.user.username} 消费 {self.points_spent} 积分 ({self.feature})'
|
|||
|
|
|||
|
|
|||
|
class WebsiteInfo(models.Model):
|
|||
|
"""
|
|||
|
用于存储网站的域名、标题、关键词和描述,包括中英文版本。
|
|||
|
"""
|
|||
|
domain_en = models.CharField(max_length=255,default=True, verbose_name='域名') # 网站域名
|
|||
|
domain_zh = models.CharField(max_length=255,default=True, verbose_name='域名') # 网站域名
|
|||
|
title_en = models.CharField(max_length=255,default=True, verbose_name='英文标题') # 英文标题
|
|||
|
title_zh = models.CharField(max_length=255,default=True, verbose_name='中文标题') # 中文标题
|
|||
|
keywords_en = models.TextField(verbose_name='英文关键词',default=True) # 英文关键词
|
|||
|
keywords_zh = models.TextField(verbose_name='中文关键词',default=True) # 中文关键词
|
|||
|
description_en = models.TextField(verbose_name='英文描述',default=True) # 英文描述
|
|||
|
description_zh = models.TextField(verbose_name='中文描述',default=True) # 中文描述
|
|||
|
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间') # 创建时间
|
|||
|
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间') # 更新时间
|
|||
|
|
|||
|
class Meta:
|
|||
|
db_table = 'website_info'
|
|||
|
verbose_name = '网站信息'
|
|||
|
verbose_name_plural = '网站信息'
|
|||
|
ordering = ['-created_at'] # 按照创建时间倒序排列
|
|||
|
|
|||
|
|
|||
|
class WebsiteAccessLog(models.Model):
|
|||
|
"""
|
|||
|
用于记录网站访问的IP、浏览器语言、来源URL、请求路径、访问时间等信息。
|
|||
|
"""
|
|||
|
ip_address = models.GenericIPAddressField(verbose_name='访问IP')
|
|||
|
browser_language = models.CharField(max_length=200, verbose_name='浏览器语言', blank=True, null=True)
|
|||
|
referrer = models.TextField(verbose_name='来源URL', blank=True, null=True)
|
|||
|
request_path = models.CharField(max_length=255, verbose_name='请求路径')
|
|||
|
request_method = models.CharField(max_length=10, verbose_name='请求方法')
|
|||
|
user_agent = models.TextField(verbose_name='用户代理', blank=True, null=True)
|
|||
|
device_type = models.CharField(max_length=50, verbose_name='设备类型', blank=True, null=True)
|
|||
|
access_time = models.DateTimeField(verbose_name='访问时间', auto_now_add=True)
|
|||
|
access_time_bj = models.DateTimeField(verbose_name='北京时间', blank=True, null=True)
|
|||
|
access_date = models.DateField(verbose_name='访问日期', blank=True, null=True)
|
|||
|
|
|||
|
class Meta:
|
|||
|
db_table = 'website_access_log'
|
|||
|
verbose_name = '网站访问日志'
|
|||
|
verbose_name_plural = '网站访问日志'
|
|||
|
unique_together = ('ip_address', 'access_date') # 确保同一IP在同一天只能记录一次
|
|||
|
|
|||
|
def __str__(self):
|
|||
|
access_time_str = self.access_time_bj.strftime('%Y-%m-%d %H:%M:%S') if self.access_time_bj else 'N/A'
|
|||
|
return f"{self.ip_address} - {access_time_str}"
|