180 lines
7.2 KiB
Python
180 lines
7.2 KiB
Python
from rest_framework import serializers
|
|
from .models import Competition, CompetitionEnrollment, ScoreDimension, Project, ProjectFile, Score, Comment
|
|
from shop.serializers import WeChatUserSerializer
|
|
import uuid
|
|
|
|
class ScoreDimensionSerializer(serializers.ModelSerializer):
|
|
class Meta:
|
|
model = ScoreDimension
|
|
fields = ['id', 'name', 'description', 'weight', 'max_score', 'order']
|
|
|
|
class CompetitionSerializer(serializers.ModelSerializer):
|
|
score_dimensions = ScoreDimensionSerializer(many=True, read_only=True)
|
|
display_cover_image = serializers.SerializerMethodField()
|
|
status_display = serializers.CharField(source='get_status_display', read_only=True)
|
|
|
|
class Meta:
|
|
model = Competition
|
|
fields = ['id', 'title', 'description', 'rule_description', 'condition_description',
|
|
'cover_image', 'cover_image_url', 'display_cover_image',
|
|
'start_time', 'end_time', 'status', 'project_visibility', 'status_display', 'is_active',
|
|
'score_dimensions', 'created_at']
|
|
|
|
def get_display_cover_image(self, obj):
|
|
if obj.cover_image:
|
|
return obj.cover_image.url
|
|
return obj.cover_image_url
|
|
|
|
class CompetitionEnrollmentSerializer(serializers.ModelSerializer):
|
|
user = WeChatUserSerializer(read_only=True)
|
|
competition_title = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = CompetitionEnrollment
|
|
fields = ['id', 'competition', 'competition_title', 'user', 'role', 'status', 'created_at']
|
|
read_only_fields = ['status']
|
|
|
|
def get_competition_title(self, obj):
|
|
return obj.competition.title if obj.competition else ''
|
|
|
|
class ProjectFileSerializer(serializers.ModelSerializer):
|
|
file_url_display = serializers.SerializerMethodField()
|
|
file_size_display = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = ProjectFile
|
|
fields = ['id', 'project', 'file_type', 'file', 'file_url', 'file_size', 'name', 'created_at', 'file_url_display', 'file_size_display']
|
|
|
|
def get_file_url_display(self, obj):
|
|
if obj.file:
|
|
return obj.file.url
|
|
return obj.file_url
|
|
|
|
def get_file_size_display(self, obj):
|
|
if not obj.file_size:
|
|
return None
|
|
size = obj.file_size
|
|
if size < 1024:
|
|
return f"{size} B"
|
|
elif size < 1024 * 1024:
|
|
return f"{size / 1024:.1f} KB"
|
|
elif size < 1024 * 1024 * 1024:
|
|
return f"{size / (1024 * 1024):.1f} MB"
|
|
else:
|
|
return f"{size / (1024 * 1024 * 1024):.2f} GB"
|
|
|
|
def validate_file(self, value):
|
|
if not value:
|
|
return value
|
|
limit_mb = 50
|
|
if value.size > limit_mb * 1024 * 1024:
|
|
raise serializers.ValidationError(f"文件大小不能超过 {limit_mb}MB")
|
|
return value
|
|
|
|
def create(self, validated_data):
|
|
from django.conf import settings
|
|
from shop.utils import get_current_wechat_user
|
|
|
|
request = self.context.get('request')
|
|
user = get_current_wechat_user(request) if request else None
|
|
|
|
print(f"=== File Upload Debug ===")
|
|
print(f"User: {user}")
|
|
print(f"Validated data keys: {validated_data.keys()}")
|
|
|
|
file_obj = validated_data.get('file')
|
|
|
|
if file_obj:
|
|
print(f"File name: {file_obj.name}, size: {file_obj.size}")
|
|
ext = file_obj.name.split('.')[-1].lower() if '.' in file_obj.name else ''
|
|
if ext in ['ppt', 'pptx']:
|
|
validated_data['file_type'] = 'ppt'
|
|
elif ext == 'pdf':
|
|
validated_data['file_type'] = 'pdf'
|
|
elif ext in ['jpg', 'jpeg', 'png', 'gif', 'webp']:
|
|
validated_data['file_type'] = 'image'
|
|
elif ext in ['mp4', 'mov', 'avi', 'webm']:
|
|
validated_data['file_type'] = 'video'
|
|
elif ext in ['doc', 'docx']:
|
|
validated_data['file_type'] = 'doc'
|
|
|
|
if not validated_data.get('name'):
|
|
validated_data['name'] = file_obj.name
|
|
|
|
validated_data['file_size'] = file_obj.size
|
|
|
|
try:
|
|
from ai_services.services import AliyunTingwuService
|
|
service = AliyunTingwuService()
|
|
if service.bucket:
|
|
project = validated_data.get('project')
|
|
file_name = f"competitions/projects/{project.id}/{uuid.uuid4()}.{ext}"
|
|
oss_url = service.upload_to_oss(file_obj, file_name, day=30)
|
|
validated_data['file_url'] = oss_url
|
|
validated_data['file'] = None
|
|
print(f"OSS upload success: {oss_url}")
|
|
else:
|
|
print("OSS bucket is None, OSS not configured properly")
|
|
except Exception as e:
|
|
print(f"OSS upload failed in serializer: {e}")
|
|
|
|
return super().create(validated_data)
|
|
|
|
class ProjectSerializer(serializers.ModelSerializer):
|
|
files = ProjectFileSerializer(many=True, read_only=True)
|
|
contestant_info = serializers.SerializerMethodField()
|
|
display_cover_image = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = Project
|
|
fields = ['id', 'competition', 'contestant', 'title', 'description', 'team_info',
|
|
'cover_image', 'cover_image_url', 'display_cover_image',
|
|
'status', 'final_score', 'files', 'contestant_info', 'created_at']
|
|
read_only_fields = ['final_score', 'contestant']
|
|
|
|
def get_contestant_info(self, obj):
|
|
return {
|
|
"nickname": obj.contestant.user.nickname,
|
|
"avatar_url": obj.contestant.user.avatar_url
|
|
}
|
|
|
|
def get_display_cover_image(self, obj):
|
|
if obj.cover_image:
|
|
return obj.cover_image.url
|
|
return obj.cover_image_url
|
|
|
|
class ScoreSerializer(serializers.ModelSerializer):
|
|
judge_name = serializers.CharField(source='judge.user.nickname', read_only=True)
|
|
dimension_name = serializers.CharField(source='dimension.name', read_only=True)
|
|
|
|
class Meta:
|
|
model = Score
|
|
fields = ['id', 'project', 'judge', 'dimension', 'score', 'judge_name', 'dimension_name', 'created_at']
|
|
read_only_fields = ['judge']
|
|
|
|
class CommentSerializer(serializers.ModelSerializer):
|
|
judge_name = serializers.CharField(source='judge.user.nickname', read_only=True)
|
|
score = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = Comment
|
|
fields = ['id', 'project', 'judge', 'content', 'judge_name', 'created_at', 'score']
|
|
read_only_fields = ['judge']
|
|
|
|
def get_score(self, obj):
|
|
scores = Score.objects.filter(project=obj.project, judge=obj.judge)
|
|
if not scores.exists():
|
|
return None
|
|
|
|
current_judge_total_score = 0
|
|
current_judge_total_weight = 0
|
|
|
|
for score in scores:
|
|
current_judge_total_score += score.score * score.dimension.weight
|
|
current_judge_total_weight += score.dimension.weight
|
|
|
|
if current_judge_total_weight > 0:
|
|
judge_score = current_judge_total_score / current_judge_total_weight
|
|
return round(judge_score, 1)
|
|
return None
|