from django.db import models from django.utils.timezone import now from account.models import User from problem.models import Problem from utils.models import RichTextField, JSONField class ProblemSet(models.Model): """题单模型""" title = models.TextField(verbose_name="题单标题") description = RichTextField(verbose_name="题单描述") # 创建者 created_by = models.ForeignKey( User, on_delete=models.CASCADE, verbose_name="创建者" ) # 创建时间 create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") # 更新时间 last_update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间") # 是否可见 visible = models.BooleanField(default=True, verbose_name="是否可见") # 是否公开(所有用户都可以看到) is_public = models.BooleanField(default=True, verbose_name="是否公开") # 题单难度等级 difficulty = models.TextField(default="Easy", verbose_name="难度等级") # 题单状态 status = models.TextField( default="active", verbose_name="状态" ) # active, archived, draft class Meta: db_table = "problemset" ordering = ("-create_time",) verbose_name = "题单" verbose_name_plural = "题单" def __str__(self): return self.title class ProblemSetProblem(models.Model): """题单题目关联模型""" problemset = models.ForeignKey( ProblemSet, on_delete=models.CASCADE, verbose_name="题单" ) problem = models.ForeignKey(Problem, on_delete=models.CASCADE, verbose_name="题目") # 在题单中的顺序 order = models.IntegerField(default=0, verbose_name="顺序") # 是否为必做题 is_required = models.BooleanField(default=True, verbose_name="是否必做") # 题目在题单中的分值 score = models.IntegerField(default=0, verbose_name="分值") # 题目提示信息 hint = models.TextField(null=True, blank=True, verbose_name="提示") class Meta: db_table = "problemset_problem" unique_together = (("problemset", "problem"),) ordering = ("order",) verbose_name = "题单题目" verbose_name_plural = "题单题目" def __str__(self): return f"{self.problemset.title} - {self.problem.title}" class ProblemSetBadge(models.Model): """题单奖章模型""" problemset = models.ForeignKey( ProblemSet, on_delete=models.CASCADE, verbose_name="题单" ) name = models.TextField(verbose_name="奖章名称") description = models.TextField(verbose_name="奖章描述") # 奖章图标路径 icon = models.TextField(verbose_name="奖章图标") # 获得条件:完成所有题目、完成指定数量题目、达到指定分数等 condition_type = models.TextField( verbose_name="获得条件类型" ) # all_problems, problem_count, score condition_value = models.IntegerField(default=0, verbose_name="条件值") # 奖章等级 level = models.IntegerField(default=1, verbose_name="奖章等级") class Meta: db_table = "problemset_badge" verbose_name = "题单奖章" verbose_name_plural = "题单奖章" def __str__(self): return f"{self.problemset.title} - {self.name}" class ProblemSetProgress(models.Model): """题单进度模型""" problemset = models.ForeignKey( ProblemSet, on_delete=models.CASCADE, verbose_name="题单" ) user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="用户") # 加入时间 join_time = models.DateTimeField(auto_now_add=True, verbose_name="加入时间") # 完成时间 complete_time = models.DateTimeField(null=True, blank=True, verbose_name="完成时间") # 是否完成 is_completed = models.BooleanField(default=False, verbose_name="是否完成") # 完成进度百分比 progress_percentage = models.FloatField(default=0.0, verbose_name="完成进度") # 已完成的题目数量 completed_problems_count = models.IntegerField( default=0, verbose_name="已完成题目数" ) # 总题目数量 total_problems_count = models.IntegerField(default=0, verbose_name="总题目数") # 获得的总分 total_score = models.IntegerField(default=0, verbose_name="总分") # 用户在该题单中的详细进度信息 # {"problem_id": {"status": "completed", "score": 100, "submit_time": "2024-01-01T00:00:00Z"}} progress_detail = JSONField(default=dict, verbose_name="详细进度") class Meta: db_table = "problemset_progress" unique_together = (("problemset", "user"),) verbose_name = "题单进度" verbose_name_plural = "题单进度" def __str__(self): return f"{self.user.username} - {self.problemset.title}" def update_progress(self): """更新进度信息""" # 获取题单中的所有题目 problemset_problems = ProblemSetProblem.objects.filter( problemset=self.problemset ) self.total_problems_count = problemset_problems.count() # 计算已完成题目数 completed_count = 0 total_score = 0 for psp in problemset_problems: problem_id = str(psp.problem.id) if problem_id in self.progress_detail: problem_progress = self.progress_detail[problem_id] if problem_progress.get("status") == "completed": completed_count += 1 total_score += problem_progress.get("score", 0) self.completed_problems_count = completed_count self.total_score = total_score # 计算完成百分比 if self.total_problems_count > 0: self.progress_percentage = ( completed_count / self.total_problems_count ) * 100 else: self.progress_percentage = 0 # 检查是否完成 self.is_completed = completed_count == self.total_problems_count if self.is_completed and not self.complete_time: self.complete_time = now() self.save() class UserBadge(models.Model): """用户奖章模型""" user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="用户") badge = models.ForeignKey( ProblemSetBadge, on_delete=models.CASCADE, verbose_name="奖章" ) # 获得时间 earned_time = models.DateTimeField(auto_now_add=True, verbose_name="获得时间") # 是否已展示给用户 is_displayed = models.BooleanField(default=False, verbose_name="是否已展示") class Meta: db_table = "user_badge" unique_together = (("user", "badge"),) verbose_name = "用户奖章" verbose_name_plural = "用户奖章" def __str__(self): return f"{self.user.username} - {self.badge.name}"