diff --git a/problemset/models.py b/problemset/models.py index d148cba..e419eb8 100644 --- a/problemset/models.py +++ b/problemset/models.py @@ -168,6 +168,18 @@ class ProblemSetProgress(models.Model): ) self.total_problems_count = problemset_problems.count() + # 获取当前题单中所有题目的ID集合 + current_problem_ids = {str(psp.problem.id) for psp in problemset_problems} + + # 清理已删除题目的进度记录 + progress_detail_to_remove = [] + for problem_id in self.progress_detail.keys(): + if problem_id not in current_problem_ids: + progress_detail_to_remove.append(problem_id) + + for problem_id in progress_detail_to_remove: + del self.progress_detail[problem_id] + # 计算已完成题目数 completed_count = 0 total_score = 0 @@ -177,7 +189,8 @@ class ProblemSetProgress(models.Model): if problem_id in self.progress_detail: problem_progress = self.progress_detail[problem_id] completed_count += 1 - total_score += problem_progress.get("score", 0) + total_score += psp.score + problem_progress["score"] = psp.score self.completed_problems_count = completed_count self.total_score = total_score diff --git a/problemset/serializers.py b/problemset/serializers.py index a98a587..7eda797 100644 --- a/problemset/serializers.py +++ b/problemset/serializers.py @@ -214,10 +214,30 @@ class ProblemSetProgressSerializer(serializers.ModelSerializer): problemset = ProblemSetListSerializer() user = UsernameSerializer() + completed_problems = serializers.SerializerMethodField() class Meta: model = ProblemSetProgress fields = "__all__" + + def get_completed_problems(self, obj): + """获取已完成的题目列表""" + from problem.models import Problem + + completed_problems = [] + if obj.progress_detail: + for problem_id in obj.progress_detail.keys(): + try: + problem = Problem.objects.get(id=problem_id) + completed_problems.append({ + 'id': problem.id, + '_id': problem._id, + 'title': problem.title + }) + except Problem.DoesNotExist: + continue + + return completed_problems class UserBadgeSerializer(serializers.ModelSerializer): diff --git a/problemset/signals.py b/problemset/signals.py index 6cbfb64..265fe82 100644 --- a/problemset/signals.py +++ b/problemset/signals.py @@ -21,8 +21,13 @@ def sync_progress_on_problem_change(sender, instance, created, **kwargs): # 批量更新所有用户的进度 for progress in progresses: progress.update_progress() + + # 重新计算该题单的所有徽章资格 + badges = ProblemSetBadge.objects.filter(problemset=instance.problemset) + for badge in badges: + badge.recalculate_user_badges() - logger.info(f"已同步题单 {instance.problemset.id} 的所有用户进度") + logger.info(f"已同步题单 {instance.problemset.id} 的所有用户进度和徽章资格") except Exception as e: logger.error(f"同步题单进度时出错: {e}") @@ -48,8 +53,13 @@ def sync_progress_on_problem_delete(sender, instance, **kwargs): # 批量更新所有用户的进度 for progress in progresses: progress.update_progress() + + # 重新计算该题单的所有徽章资格 + badges = ProblemSetBadge.objects.filter(problemset=instance.problemset) + for badge in badges: + badge.recalculate_user_badges() - logger.info(f"已同步题单 {instance.problemset.id} 的所有用户进度(删除题目后)") + logger.info(f"已同步题单 {instance.problemset.id} 的所有用户进度和徽章资格(删除题目后)") except Exception as e: logger.error(f"同步题单进度时出错: {e}") diff --git a/problemset/urls/oj.py b/problemset/urls/oj.py index ec9449f..3fa8e4d 100644 --- a/problemset/urls/oj.py +++ b/problemset/urls/oj.py @@ -7,6 +7,7 @@ from problemset.views.oj import ( UserBadgeAPI, UserProgressAPI, ProblemSetBadgeAPI, + ProblemSetUserProgressAPI, ) urlpatterns = [ @@ -46,4 +47,9 @@ urlpatterns = [ ProblemSetBadgeAPI.as_view(), name="problemset_badges_api", ), + path( + "problemset//users_progress", + ProblemSetUserProgressAPI.as_view(), + name="problemset_user_progress_api", + ), ] diff --git a/problemset/views/oj.py b/problemset/views/oj.py index bf6ef5b..4ec6c85 100644 --- a/problemset/views/oj.py +++ b/problemset/views/oj.py @@ -183,7 +183,7 @@ class ProblemSetProgressAPI(APIView): problem_score = 0 progress.progress_detail[problem_id] = { - "score": problem_score, + "score": problem_score, # 题单中设置的分值 "submit_time": data.get("submit_time", timezone.now().isoformat()), } @@ -275,3 +275,29 @@ class ProblemSetBadgeAPI(APIView): badges = ProblemSetBadge.objects.filter(problemset=problem_set) serializer = ProblemSetBadgeSerializer(badges, many=True) return self.success(serializer.data) + + +class ProblemSetUserProgressAPI(APIView): + """题单用户进度列表API""" + + def get(self, request, problem_set_id: int): + """获取题单的用户进度列表""" + try: + problem_set = ( + ProblemSet.objects.filter(id=problem_set_id, visible=True) + .exclude(status="draft") + .get() + ) + except ProblemSet.DoesNotExist: + return self.error("题单不存在") + + # 获取所有参与该题单的用户进度 + progresses = ProblemSetProgress.objects.filter(problemset=problem_set).order_by( + "-is_completed", "-progress_percentage", "join_time" + ) + + try: + serializer = ProblemSetProgressSerializer(progresses, many=True) + return self.success(serializer.data) + except Exception as e: + return self.error(f"序列化错误: {str(e)}")