235 lines
13 KiB
Python
Executable File
235 lines
13 KiB
Python
Executable File
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}" |