add flowchart list
This commit is contained in:
@@ -17,19 +17,19 @@ from utils.shortcuts import get_env
|
|||||||
from account.models import User
|
from account.models import User
|
||||||
from problem.models import Problem
|
from problem.models import Problem
|
||||||
from submission.models import Submission, JudgeStatus
|
from submission.models import Submission, JudgeStatus
|
||||||
|
from flowchart.models import FlowchartSubmission, FlowchartSubmissionStatus
|
||||||
from account.decorators import login_required
|
from account.decorators import login_required
|
||||||
from ai.models import AIAnalysis
|
from ai.models import AIAnalysis
|
||||||
|
|
||||||
|
|
||||||
CACHE_TIMEOUT = 300
|
CACHE_TIMEOUT = 300
|
||||||
DIFFICULTY_MAP = {"Low": "简单", "Mid": "中等", "High": "困难"}
|
DIFFICULTY_MAP = {"Low": "简单", "Mid": "中等", "High": "困难"}
|
||||||
DEFAULT_CLASS_SIZE = 45
|
DEFAULT_CLASS_SIZE = 45
|
||||||
|
|
||||||
# 评级阈值配置:(百分位上限, 评级)
|
# 评级阈值配置:(百分位上限, 评级)
|
||||||
GRADE_THRESHOLDS = [
|
GRADE_THRESHOLDS = [
|
||||||
(10, "S"), # 前10%: S级 - 卓越
|
(10, "S"), # 前10%: S级 - 卓越
|
||||||
(35, "A"), # 前35%: A级 - 优秀
|
(35, "A"), # 前35%: A级 - 优秀
|
||||||
(75, "B"), # 前75%: B级 - 良好
|
(75, "B"), # 前75%: B级 - 良好
|
||||||
(100, "C"), # 其余: C级 - 及格
|
(100, "C"), # 其余: C级 - 及格
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -163,6 +163,7 @@ class AIDetailDataAPI(APIView):
|
|||||||
"start": start,
|
"start": start,
|
||||||
"end": end,
|
"end": end,
|
||||||
"solved": [],
|
"solved": [],
|
||||||
|
"flowcharts": [],
|
||||||
"grade": "",
|
"grade": "",
|
||||||
"tags": {},
|
"tags": {},
|
||||||
"difficulty": {},
|
"difficulty": {},
|
||||||
@@ -179,9 +180,79 @@ class AIDetailDataAPI(APIView):
|
|||||||
solved, contest_ids = self._build_solved_records(
|
solved, contest_ids = self._build_solved_records(
|
||||||
user_first_ac, by_problem, problems, user.id
|
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(
|
result.update(
|
||||||
{
|
{
|
||||||
"solved": solved,
|
"solved": solved,
|
||||||
|
"flowcharts": flowcharts_data,
|
||||||
"grade": self._calculate_average_grade(solved),
|
"grade": self._calculate_average_grade(solved),
|
||||||
"tags": self._calculate_top_tags(problems.values()),
|
"tags": self._calculate_top_tags(problems.values()),
|
||||||
"difficulty": self._calculate_difficulty_distribution(
|
"difficulty": self._calculate_difficulty_distribution(
|
||||||
@@ -572,9 +643,10 @@ class AIHeatmapDataAPI(APIView):
|
|||||||
submission_count = submission_dict.get(day_date, 0)
|
submission_count = submission_dict.get(day_date, 0)
|
||||||
heatmap_data.append(
|
heatmap_data.append(
|
||||||
{
|
{
|
||||||
"timestamp": int(datetime.combine(
|
"timestamp": int(
|
||||||
day_date, datetime.min.time()
|
datetime.combine(day_date, datetime.min.time()).timestamp()
|
||||||
).timestamp() * 1000),
|
* 1000
|
||||||
|
),
|
||||||
"value": submission_count,
|
"value": submission_count,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -41,14 +41,15 @@ class FlowchartSubmissionListSerializer(serializers.ModelSerializer):
|
|||||||
"""用于列表显示的简化序列化器"""
|
"""用于列表显示的简化序列化器"""
|
||||||
|
|
||||||
username = serializers.CharField(source="user.username")
|
username = serializers.CharField(source="user.username")
|
||||||
|
problem = serializers.CharField(source="problem._id")
|
||||||
problem_title = serializers.CharField(source="problem.title")
|
problem_title = serializers.CharField(source="problem.title")
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = FlowchartSubmission
|
model = FlowchartSubmission
|
||||||
fields = [
|
fields = [
|
||||||
"id",
|
"id",
|
||||||
"username",
|
"username",
|
||||||
"problem_title",
|
"problem_title",
|
||||||
|
"problem",
|
||||||
"status",
|
"status",
|
||||||
"create_time",
|
"create_time",
|
||||||
"ai_score",
|
"ai_score",
|
||||||
@@ -58,3 +59,33 @@ class FlowchartSubmissionListSerializer(serializers.ModelSerializer):
|
|||||||
"processing_time",
|
"processing_time",
|
||||||
"evaluation_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()
|
||||||
|
|||||||
@@ -65,32 +65,32 @@ class FlowchartSubmissionAPI(APIView):
|
|||||||
|
|
||||||
|
|
||||||
class FlowchartSubmissionListAPI(APIView):
|
class FlowchartSubmissionListAPI(APIView):
|
||||||
@login_required
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""获取流程图提交列表"""
|
"""获取流程图提交列表"""
|
||||||
user_id = request.GET.get("user_id")
|
username = request.GET.get("username")
|
||||||
problem_id = request.GET.get("problem_id")
|
problem_id = request.GET.get("problem_id")
|
||||||
offset = int(request.GET.get("offset", 0))
|
myself = request.GET.get("myself")
|
||||||
limit = int(request.GET.get("limit", 20))
|
|
||||||
|
|
||||||
queryset = FlowchartSubmission.objects.select_related("user", "problem")
|
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:
|
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()
|
data = self.paginate_data(request, queryset)
|
||||||
submissions = queryset[offset : offset + limit]
|
data["results"] = FlowchartSubmissionListSerializer(
|
||||||
|
data["results"], many=True
|
||||||
serializer = FlowchartSubmissionListSerializer(submissions, many=True)
|
).data
|
||||||
|
return self.success(data)
|
||||||
return self.success({"results": serializer.data, "total": total})
|
|
||||||
|
|
||||||
|
|
||||||
class FlowchartSubmissionRetryAPI(APIView):
|
class FlowchartSubmissionRetryAPI(APIView):
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ class SubmissionSafeModelSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
class SubmissionListSerializer(serializers.ModelSerializer):
|
class SubmissionListSerializer(serializers.ModelSerializer):
|
||||||
problem = serializers.SlugRelatedField(read_only=True, slug_field="_id")
|
problem = serializers.SlugRelatedField(read_only=True, slug_field="_id")
|
||||||
|
problem_title = serializers.CharField(source="problem.title")
|
||||||
show_link = serializers.SerializerMethodField()
|
show_link = serializers.SerializerMethodField()
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
|||||||
Reference in New Issue
Block a user