from rest_framework import viewsets, permissions, status, filters, serializers from rest_framework.decorators import action 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 from .serializers import ( CompetitionSerializer, CompetitionEnrollmentSerializer, ProjectSerializer, ProjectFileSerializer, ScoreSerializer, CommentSerializer, ScoreDimensionSerializer ) from rest_framework.pagination import PageNumberPagination 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_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) if user: # 查找用户在这个比赛中的角色 # 如果是评委,可以看到所有项目(包括草稿吗?通常评委只看提交的) # 这里简化:评委看所有submitted,用户看所有submitted + 自己的draft # 找到用户参与的所有比赛角色 enrollments = CompetitionEnrollment.objects.filter(user=user) judge_competitions = enrollments.filter(role='judge').values_list('competition_id', flat=True) # 基本查询:所有已提交的项目 q = Q(status='submitted') # 加上自己创建的项目 (即使是draft) q |= Q(contestant__user=user) # 加上自己是评委的比赛的所有项目 (通常评委只看submitted,但如果需要预审可以看draft,这里假设只看submitted) # q |= Q(competition__in=judge_competitions) queryset = queryset.filter(q) else: # 未登录用户只能看已提交 queryset = queryset.filter(status='submitted') 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)