add flowchart list

This commit is contained in:
2025-10-20 20:05:10 +08:00
parent 6465f8fab2
commit a103dd6b38
4 changed files with 156 additions and 52 deletions

View File

@@ -17,10 +17,10 @@ from utils.shortcuts import get_env
from account.models import User
from problem.models import Problem
from submission.models import Submission, JudgeStatus
from flowchart.models import FlowchartSubmission, FlowchartSubmissionStatus
from account.decorators import login_required
from ai.models import AIAnalysis
CACHE_TIMEOUT = 300
DIFFICULTY_MAP = {"Low": "简单", "Mid": "中等", "High": "困难"}
DEFAULT_CLASS_SIZE = 45
@@ -163,6 +163,7 @@ class AIDetailDataAPI(APIView):
"start": start,
"end": end,
"solved": [],
"flowcharts": [],
"grade": "",
"tags": {},
"difficulty": {},
@@ -179,9 +180,79 @@ class AIDetailDataAPI(APIView):
solved, contest_ids = self._build_solved_records(
user_first_ac, by_problem, problems, user.id
)
# 查找 flowchart submissions
flowcharts_query = FlowchartSubmission.objects.filter(
user_id=user,
status=FlowchartSubmissionStatus.COMPLETED,
)
# 添加时间范围过滤
if start:
flowcharts_query = flowcharts_query.filter(create_time__gte=start)
if end:
flowcharts_query = flowcharts_query.filter(create_time__lte=end)
flowcharts = flowcharts_query.select_related("problem").only(
"id",
"create_time",
"ai_score",
"ai_grade",
"problem___id",
"problem__title",
)
# 按problem分组
problem_groups = defaultdict(list)
for flowchart in flowcharts:
problem_id = flowchart.problem._id
problem_groups[problem_id].append(flowchart)
flowcharts_data = []
for problem_id, submissions in problem_groups.items():
if not submissions:
continue
# 获取第一个提交的基本信息
first_submission = submissions[0]
# 计算统计数据
scores = [s.ai_score for s in submissions if s.ai_score is not None]
times = [s.create_time for s in submissions]
# 找到最高分和对应的等级
best_score = max(scores) if scores else 0
best_submission = next(
(s for s in submissions if s.ai_score == best_score), submissions[0]
)
best_grade = best_submission.ai_grade or ""
# 计算平均分
avg_score = sum(scores) / len(scores) if scores else 0
# 最新提交时间
latest_time = max(times) if times else first_submission.create_time
merged_item = {
"problem__id": problem_id,
"problem_title": first_submission.problem.title,
"submission_count": len(submissions),
"best_score": best_score,
"best_grade": best_grade,
"latest_submission_time": latest_time.isoformat() if latest_time else None,
"avg_score": round(avg_score, 0),
}
flowcharts_data.append(merged_item)
# 按最新提交时间排序
flowcharts_data.sort(
key=lambda x: x["latest_submission_time"] or "", reverse=True
)
result.update(
{
"solved": solved,
"flowcharts": flowcharts_data,
"grade": self._calculate_average_grade(solved),
"tags": self._calculate_top_tags(problems.values()),
"difficulty": self._calculate_difficulty_distribution(
@@ -572,9 +643,10 @@ class AIHeatmapDataAPI(APIView):
submission_count = submission_dict.get(day_date, 0)
heatmap_data.append(
{
"timestamp": int(datetime.combine(
day_date, datetime.min.time()
).timestamp() * 1000),
"timestamp": int(
datetime.combine(day_date, datetime.min.time()).timestamp()
* 1000
),
"value": submission_count,
}
)

View File

@@ -41,14 +41,15 @@ class FlowchartSubmissionListSerializer(serializers.ModelSerializer):
"""用于列表显示的简化序列化器"""
username = serializers.CharField(source="user.username")
problem = serializers.CharField(source="problem._id")
problem_title = serializers.CharField(source="problem.title")
class Meta:
model = FlowchartSubmission
fields = [
"id",
"username",
"problem_title",
"problem",
"status",
"create_time",
"ai_score",
@@ -58,3 +59,33 @@ class FlowchartSubmissionListSerializer(serializers.ModelSerializer):
"processing_time",
"evaluation_time",
]
class FlowchartSubmissionSummarySerializer(serializers.ModelSerializer):
"""用于AI详情页面的极简序列化器只包含必要字段"""
problem_title = serializers.CharField(source="problem.title")
problem__id = serializers.CharField(source="problem._id")
class Meta:
model = FlowchartSubmission
fields = [
"id",
"problem__id",
"problem_title",
"ai_score",
"ai_grade",
"create_time",
]
class FlowchartSubmissionMergedSerializer(serializers.Serializer):
"""合并后的流程图提交序列化器"""
problem__id = serializers.CharField()
problem_title = serializers.CharField()
submission_count = serializers.IntegerField()
best_score = serializers.FloatField()
best_grade = serializers.CharField()
latest_submission_time = serializers.DateTimeField()
avg_score = serializers.FloatField()

View File

@@ -65,32 +65,32 @@ class FlowchartSubmissionAPI(APIView):
class FlowchartSubmissionListAPI(APIView):
@login_required
def get(self, request):
"""获取流程图提交列表"""
user_id = request.GET.get("user_id")
username = request.GET.get("username")
problem_id = request.GET.get("problem_id")
offset = int(request.GET.get("offset", 0))
limit = int(request.GET.get("limit", 20))
myself = request.GET.get("myself")
queryset = FlowchartSubmission.objects.select_related("user", "problem")
# 权限过滤
if not request.user.is_admin_role():
queryset = queryset.filter(user=request.user)
# 其他过滤条件
if user_id:
queryset = queryset.filter(user_id=user_id)
if problem_id:
queryset = queryset.filter(problem_id=problem_id)
try:
problem = Problem.objects.get(
_id=problem_id, contest_id__isnull=True, visible=True
)
except Problem.DoesNotExist:
return self.error("Problem doesn't exist")
queryset = queryset.filter(problem=problem)
if myself and myself == "1":
queryset = queryset.filter(user=request.user)
if username:
queryset = queryset.filter(user__username__icontains=username)
total = queryset.count()
submissions = queryset[offset : offset + limit]
serializer = FlowchartSubmissionListSerializer(submissions, many=True)
return self.success({"results": serializer.data, "total": total})
data = self.paginate_data(request, queryset)
data["results"] = FlowchartSubmissionListSerializer(
data["results"], many=True
).data
return self.success(data)
class FlowchartSubmissionRetryAPI(APIView):

View File

@@ -34,6 +34,7 @@ class SubmissionSafeModelSerializer(serializers.ModelSerializer):
class SubmissionListSerializer(serializers.ModelSerializer):
problem = serializers.SlugRelatedField(read_only=True, slug_field="_id")
problem_title = serializers.CharField(source="problem.title")
show_link = serializers.SerializerMethodField()
def __init__(self, *args, **kwargs):