Files
Scoring-System/backend/competition/views.py
爽哒哒 96be8b9eee
All checks were successful
Deploy to Server / deploy (push) Successful in 1m56s
feat: 首页配置封面图上传预览,修复系列活动跳转,活动卡片样式优化
2026-03-22 00:31:34 +08:00

314 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from rest_framework import viewsets, permissions, status, filters, serializers
from rest_framework.decorators import action, api_view, permission_classes
from rest_framework.response import Response
from django.db.models import Q
from shop.utils import get_current_wechat_user
from .models import Competition, CompetitionEnrollment, Project, ProjectFile, Score, Comment, ScoreDimension, HomePageConfig
from .serializers import (
CompetitionSerializer, CompetitionEnrollmentSerializer,
ProjectSerializer, ProjectFileSerializer,
ScoreSerializer, CommentSerializer, ScoreDimensionSerializer,
HomePageConfigSerializer
)
from rest_framework.pagination import PageNumberPagination
@api_view(['GET', 'PATCH'])
@permission_classes([permissions.AllowAny])
def get_homepage_config(request):
"""获取或更新首页配置PATCH 支持 multipart/form-data 上传图片)"""
try:
config = HomePageConfig.objects.filter(is_active=True).first()
if not config:
config = HomePageConfig.objects.create()
if request.method == 'PATCH':
serializer = HomePageConfigSerializer(
config, data=request.data, partial=True, context={'request': request}
)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializer = HomePageConfigSerializer(config, context={'request': request})
return Response(serializer.data)
except Exception as e:
return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
class StandardResultsSetPagination(PageNumberPagination):
page_size = 10
page_size_query_param = 'page_size'
max_page_size = 100
class CompetitionViewSet(viewsets.ReadOnlyModelViewSet):
"""
比赛视图集
"""
queryset = Competition.objects.filter(is_active=True).order_by('created_at')
serializer_class = CompetitionSerializer
permission_classes = [permissions.AllowAny]
pagination_class = StandardResultsSetPagination
filter_backends = [filters.SearchFilter]
search_fields = ['title', 'description']
def get_serializer_context(self):
context = super().get_serializer_context()
context['request'] = self.request
return context
def get_queryset(self):
"""
获取比赛查询集,支持根据查询参数进行动态过滤
"""
queryset = super().get_queryset()
# 状态过滤
status_param = self.request.query_params.get('status')
if status_param and status_param != 'all':
queryset = queryset.filter(status=status_param)
return queryset
@action(detail=True, methods=['post'], permission_classes=[permissions.AllowAny])
def enroll(self, request, pk=None):
"""
报名参加比赛
"""
competition = self.get_object()
user = get_current_wechat_user(request)
if not user:
return Response({"detail": "未登录"}, status=status.HTTP_401_UNAUTHORIZED)
role = request.data.get('role', 'contestant')
# 检查是否已报名
if CompetitionEnrollment.objects.filter(competition=competition, user=user).exists():
return Response({"detail": "您已报名该比赛"}, status=status.HTTP_400_BAD_REQUEST)
enrollment = CompetitionEnrollment.objects.create(
competition=competition,
user=user,
role=role,
status='pending' # 默认待审核
)
return Response(CompetitionEnrollmentSerializer(enrollment).data, status=status.HTTP_201_CREATED)
@action(detail=True, methods=['get'])
def my_enrollment(self, request, pk=None):
"""
获取我的报名信息
"""
competition = self.get_object()
user = get_current_wechat_user(request)
if not user:
return Response({"detail": "未登录"}, status=status.HTTP_401_UNAUTHORIZED)
try:
enrollment = CompetitionEnrollment.objects.get(competition=competition, user=user)
return Response(CompetitionEnrollmentSerializer(enrollment).data)
except CompetitionEnrollment.DoesNotExist:
return Response({"detail": "未报名"}, status=status.HTTP_404_NOT_FOUND)
@action(detail=False, methods=['get'])
def my_enrollments(self, request):
"""
获取我的所有报名信息
"""
user = get_current_wechat_user(request)
if not user:
return Response([])
enrollments = CompetitionEnrollment.objects.filter(user=user)
return Response(CompetitionEnrollmentSerializer(enrollments, many=True).data)
class ProjectViewSet(viewsets.ModelViewSet):
"""
参赛项目视图集
"""
serializer_class = ProjectSerializer
permission_classes = [permissions.AllowAny]
pagination_class = StandardResultsSetPagination
def get_queryset(self):
queryset = Project.objects.all()
competition_id = self.request.query_params.get('competition')
if competition_id:
queryset = queryset.filter(competition_id=competition_id)
contestant_id = self.request.query_params.get('contestant')
if contestant_id:
queryset = queryset.filter(contestant_id=contestant_id)
user = get_current_wechat_user(self.request)
# 1. 基础条件:公开可见且已提交的项目
q = Q(competition__project_visibility='public', status='submitted')
if user:
# 2. 用户自己的项目(始终可见,包括草稿)
q |= Q(contestant__user=user)
# 3. 基于角色的可见性
# 获取用户已通过审核的报名信息
enrollments = CompetitionEnrollment.objects.filter(user=user, status='approved')
# 获取各角色的比赛ID集合
judge_comp_ids = set(enrollments.filter(role='judge').values_list('competition_id', flat=True))
guest_comp_ids = set(enrollments.filter(role='guest').values_list('competition_id', flat=True))
contestant_comp_ids = set(enrollments.filter(role='contestant').values_list('competition_id', flat=True))
# 'judge' 可见性:仅评委可见
if judge_comp_ids:
q |= Q(competition__project_visibility='judge', competition__in=judge_comp_ids, status='submitted')
# 'guest' 可见性:嘉宾及评委可见
guest_access_ids = judge_comp_ids | guest_comp_ids
if guest_access_ids:
q |= Q(competition__project_visibility='guest', competition__in=guest_access_ids, status='submitted')
# 'contestant' 可见性:选手及以上可见(包括评委、嘉宾)
contestant_access_ids = judge_comp_ids | guest_comp_ids | contestant_comp_ids
if contestant_access_ids:
q |= Q(competition__project_visibility='contestant', competition__in=contestant_access_ids, status='submitted')
queryset = queryset.filter(q)
return queryset.order_by('-final_score', '-created_at')
def perform_create(self, serializer):
user = get_current_wechat_user(self.request)
if not user:
raise serializers.ValidationError("请先登录")
competition = serializer.validated_data['competition']
# 检查是否有参赛资格
try:
enrollment = CompetitionEnrollment.objects.get(
competition=competition,
user=user,
role='contestant',
status='approved'
)
except CompetitionEnrollment.DoesNotExist:
raise serializers.ValidationError("您没有参赛资格或审核未通过")
# 检查是否已提交过项目
if Project.objects.filter(competition=competition, contestant=enrollment).exists():
raise serializers.ValidationError("您已提交过该比赛的项目,请勿重复提交")
serializer.save(contestant=enrollment)
@action(detail=True, methods=['post'])
def submit(self, request, pk=None):
"""
提交项目(从草稿转为已提交)
"""
project = self.get_object()
user = get_current_wechat_user(request)
if project.contestant.user != user:
return Response({"detail": "无权操作"}, status=status.HTTP_403_FORBIDDEN)
project.status = 'submitted'
project.save()
return Response({"status": "submitted"})
class ProjectFileViewSet(viewsets.ModelViewSet):
"""
项目附件管理
"""
serializer_class = ProjectFileSerializer
permission_classes = [permissions.AllowAny]
def get_queryset(self):
return ProjectFile.objects.all()
def perform_create(self, serializer):
# 简单权限控制:只有项目拥有者可以上传
project = serializer.validated_data['project']
user = get_current_wechat_user(self.request)
if not user or project.contestant.user != user:
raise serializers.ValidationError("无权上传文件")
serializer.save()
class ScoreViewSet(viewsets.ModelViewSet):
"""
评分管理
"""
serializer_class = ScoreSerializer
permission_classes = [permissions.AllowAny]
def get_queryset(self):
project_id = self.request.query_params.get('project')
if project_id:
return Score.objects.filter(project_id=project_id)
return Score.objects.all()
def perform_create(self, serializer):
user = get_current_wechat_user(self.request)
if not user:
raise serializers.ValidationError("请先登录")
project = serializer.validated_data['project']
# 检查是否是评委
try:
enrollment = CompetitionEnrollment.objects.get(
competition=project.competition,
user=user,
role='judge',
status='approved'
)
except CompetitionEnrollment.DoesNotExist:
raise serializers.ValidationError("您不是该比赛的评委")
# 检查是否重复打分
dimension = serializer.validated_data['dimension']
if Score.objects.filter(project=project, judge=enrollment, dimension=dimension).exists():
raise serializers.ValidationError("您已对该维度打分")
serializer.save(judge=enrollment)
class CommentViewSet(viewsets.ModelViewSet):
"""
评语管理
"""
serializer_class = CommentSerializer
permission_classes = [permissions.AllowAny]
def get_queryset(self):
project_id = self.request.query_params.get('project')
if project_id:
return Comment.objects.filter(project_id=project_id)
return Comment.objects.all()
def perform_create(self, serializer):
user = get_current_wechat_user(self.request)
if not user:
raise serializers.ValidationError("请先登录")
project = serializer.validated_data['project']
# 检查是否是评委
try:
enrollment = CompetitionEnrollment.objects.get(
competition=project.competition,
user=user,
role='judge',
status='approved'
)
except CompetitionEnrollment.DoesNotExist:
raise serializers.ValidationError("您不是该比赛的评委")
serializer.save(judge=enrollment)