320 lines
12 KiB
Python
320 lines
12 KiB
Python
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, CarouselItem
|
|
from .serializers import (
|
|
CompetitionSerializer, CompetitionEnrollmentSerializer,
|
|
ProjectSerializer, ProjectFileSerializer,
|
|
ScoreSerializer, CommentSerializer, ScoreDimensionSerializer,
|
|
HomePageConfigSerializer, CarouselItemSerializer
|
|
)
|
|
|
|
from rest_framework.pagination import PageNumberPagination
|
|
|
|
|
|
@api_view(['GET'])
|
|
@permission_classes([permissions.AllowAny])
|
|
def get_homepage_config(request):
|
|
"""获取首页配置"""
|
|
try:
|
|
config = HomePageConfig.objects.filter(is_active=True).first()
|
|
if not config:
|
|
config = HomePageConfig.objects.create()
|
|
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 CarouselItemViewSet(viewsets.ModelViewSet):
|
|
"""轮播图项目管理"""
|
|
queryset = CarouselItem.objects.all()
|
|
serializer_class = CarouselItemSerializer
|
|
permission_classes = [permissions.AllowAny]
|
|
filter_backends = [filters.SearchFilter]
|
|
search_fields = ['title']
|
|
|
|
def get_queryset(self):
|
|
queryset = CarouselItem.objects.all()
|
|
carousel_type = self.request.query_params.get('carousel_type')
|
|
if carousel_type:
|
|
queryset = queryset.filter(carousel_type=carousel_type)
|
|
return queryset
|
|
|
|
|
|
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)
|