From 2104e7b7dc82577b98d0a3c2712b3fd80f93b069 Mon Sep 17 00:00:00 2001 From: jeremygan2021 Date: Sun, 22 Mar 2026 22:04:13 +0800 Subject: [PATCH] new --- backend/competition/admin.py | 26 ++ .../0011_increase_file_url_length.py | 18 ++ backend/competition/models.py | 2 +- backend/competition/serializers.py | 19 ++ .../templates/judge/dashboard.html | 282 +++++++++++++++++- backend/competition/views.py | 17 +- frontend/src/api.js | 2 +- .../competition/ProjectSubmission.jsx | 271 +++++++++++------ 8 files changed, 525 insertions(+), 112 deletions(-) create mode 100644 backend/competition/migrations/0011_increase_file_url_length.py diff --git a/backend/competition/admin.py b/backend/competition/admin.py index 324e83e..d766c9e 100644 --- a/backend/competition/admin.py +++ b/backend/competition/admin.py @@ -1,4 +1,5 @@ from django.contrib import admin +from django.utils.safestring import mark_safe from unfold.admin import ModelAdmin from unfold.decorators import display from .models import Competition, CompetitionEnrollment, ScoreDimension, Project, ProjectFile, Score, Comment, ScoreFormula @@ -37,6 +38,31 @@ class ProjectFileInline(admin.TabularInline): model = ProjectFile extra = 0 tab = True + readonly_fields = ('file_url_display',) + + def file_url_display(self, obj): + if obj.file_url: + return mark_safe(f'{obj.file_url[:50]}...') + elif obj.file: + return obj.file.url + return "-" + file_url_display.short_description = "文件链接" + + +@admin.register(ProjectFile) +class ProjectFileAdmin(ModelAdmin): + list_display = ['id', 'project', 'name', 'file_type', 'file_url_display', 'created_at'] + list_filter = ['file_type', 'created_at'] + search_fields = ['name', 'project__title'] + readonly_fields = ('file_url_display',) + + def file_url_display(self, obj): + if obj.file_url: + return mark_safe(f'打开文件') + elif obj.file: + return obj.file.url + return "-" + file_url_display.short_description = "文件链接" @admin.register(Competition) diff --git a/backend/competition/migrations/0011_increase_file_url_length.py b/backend/competition/migrations/0011_increase_file_url_length.py new file mode 100644 index 0000000..8821f60 --- /dev/null +++ b/backend/competition/migrations/0011_increase_file_url_length.py @@ -0,0 +1,18 @@ +# Generated by Django 6.0.1 on 2026-03-22 13:58 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('competition', '0010_remove_competition_custom_score_formula'), + ] + + operations = [ + migrations.AlterField( + model_name='projectfile', + name='file_url', + field=models.TextField(blank=True, help_text='OSS URL或外部链接', null=True, verbose_name='文件链接'), + ), + ] diff --git a/backend/competition/models.py b/backend/competition/models.py index 397666a..0142478 100644 --- a/backend/competition/models.py +++ b/backend/competition/models.py @@ -296,7 +296,7 @@ class ProjectFile(models.Model): file_type = models.CharField(max_length=20, choices=FILE_TYPE_CHOICES, default='other', verbose_name="文件类型") file = models.FileField(upload_to='competitions/projects/files/', verbose_name="文件", null=True, blank=True) - file_url = models.URLField(verbose_name="文件链接", null=True, blank=True, help_text="视频等大文件建议使用外部链接") + file_url = models.TextField(verbose_name="文件链接", null=True, blank=True, help_text="OSS URL或外部链接") name = models.CharField(max_length=100, verbose_name="文件名称", blank=True) diff --git a/backend/competition/serializers.py b/backend/competition/serializers.py index e220480..77ab292 100644 --- a/backend/competition/serializers.py +++ b/backend/competition/serializers.py @@ -1,6 +1,7 @@ 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: @@ -53,7 +54,9 @@ class ProjectFileSerializer(serializers.ModelSerializer): return value def create(self, validated_data): + from django.conf import settings file_obj = validated_data.get('file') + if file_obj: ext = file_obj.name.split('.')[-1].lower() if '.' in file_obj.name else '' if ext in ['ppt', 'pptx']: @@ -69,6 +72,22 @@ class ProjectFileSerializer(serializers.ModelSerializer): if not validated_data.get('name'): validated_data['name'] = file_obj.name + + 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): diff --git a/backend/competition/templates/judge/dashboard.html b/backend/competition/templates/judge/dashboard.html index efc61b5..1474c36 100644 --- a/backend/competition/templates/judge/dashboard.html +++ b/backend/competition/templates/judge/dashboard.html @@ -352,11 +352,253 @@ + + + {% endblock %} {% block extra_js %} + +