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}"