274 lines
10 KiB
Python
274 lines
10 KiB
Python
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)
|