diff --git a/backend/community/models.py b/backend/community/models.py index e8a1800..6c00bfa 100644 --- a/backend/community/models.py +++ b/backend/community/models.py @@ -50,10 +50,11 @@ class Activity(models.Model): @property def display_banner_url(self): """ - 获取Banner显示的URL,优先使用上传的图片 + 获取Banner显示的URL,优先使用上传的图片,返回相对路径避免容器内部地址 """ - if self.banner: - return self.banner.url + if self.banner and self.banner.name: + from django.conf import settings + return settings.MEDIA_URL + self.banner.name return self.banner_url @property diff --git a/backend/competition/admin.py b/backend/competition/admin.py index 31373f0..55dfdb6 100644 --- a/backend/competition/admin.py +++ b/backend/competition/admin.py @@ -7,12 +7,13 @@ from .models import Competition, CompetitionEnrollment, ScoreDimension, Project, @admin.register(HomePageConfig) class HomePageConfigAdmin(ModelAdmin): - list_display = ['id', 'main_title', 'organizer', 'undertaker', 'is_active'] + list_display = ['id', 'main_title', 'organizer', 'undertaker', 'is_active', 'banner_preview'] list_editable = ['main_title', 'organizer', 'undertaker', 'is_active'] + readonly_fields = ['banner_preview'] fieldsets = ( ('封面图', { - 'fields': ('banner_image', 'banner_image_url'), - 'description': '首页标题下方的封面图,可上传本地图片或填写URL' + 'fields': ('banner_image', 'banner_image_url', 'banner_preview'), + 'description': '首页标题下方的封面图,可上传本地图片或填写URL,优先使用上传的图片' }), ('标题设置', { 'fields': ('main_title',) @@ -25,6 +26,18 @@ class HomePageConfigAdmin(ModelAdmin): }), ) + @display(description="封面图预览") + def banner_preview(self, obj): + url = None + if obj.banner_image and obj.banner_image.name: + from django.conf import settings + url = settings.MEDIA_URL + obj.banner_image.name + elif obj.banner_image_url: + url = obj.banner_image_url + if url: + return format_html('', url) + return "暂无图片" + class ScoreDimensionInline(admin.TabularInline): model = ScoreDimension diff --git a/backend/competition/serializers.py b/backend/competition/serializers.py index bf2391e..c3c3937 100644 --- a/backend/competition/serializers.py +++ b/backend/competition/serializers.py @@ -17,7 +17,8 @@ class HomePageConfigSerializer(serializers.ModelSerializer): class Meta: model = HomePageConfig fields = ['id', 'banner_image', 'banner_image_url', 'display_banner', - 'main_title', 'organizer', 'undertaker'] + 'main_title', 'organizer', 'undertaker', 'is_active'] + def get_display_banner(self, obj): return _media_url(obj.banner_image) or obj.banner_image_url diff --git a/backend/competition/views.py b/backend/competition/views.py index 8abf7da..4ac2fe7 100644 --- a/backend/competition/views.py +++ b/backend/competition/views.py @@ -14,14 +14,24 @@ from .serializers import ( from rest_framework.pagination import PageNumberPagination -@api_view(['GET']) +@api_view(['GET', 'PATCH']) @permission_classes([permissions.AllowAny]) def get_homepage_config(request): - """获取首页配置""" + """获取或更新首页配置(PATCH 支持 multipart/form-data 上传图片)""" try: config = HomePageConfig.objects.filter(is_active=True).first() if not config: config = HomePageConfig.objects.create() + + if request.method == 'PATCH': + serializer = HomePageConfigSerializer( + config, data=request.data, partial=True, context={'request': request} + ) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + serializer = HomePageConfigSerializer(config, context={'request': request}) return Response(serializer.data) except Exception as e: diff --git a/frontend/src/components/activity/ActivityCard.jsx b/frontend/src/components/activity/ActivityCard.jsx index 0b04e00..c090dc5 100644 --- a/frontend/src/components/activity/ActivityCard.jsx +++ b/frontend/src/components/activity/ActivityCard.jsx @@ -7,9 +7,8 @@ const { Title } = Typography; const getImageUrl = (url) => { if (!url) return ''; - if (url.startsWith('http') || url.startsWith('//')) { - try { return new URL(url).pathname; } catch { return url; } - } + // 外部 URL 直接返回,不提取 pathname + if (url.startsWith('http') || url.startsWith('//')) return url; return url; }; diff --git a/frontend/src/pages/activity/Detail.jsx b/frontend/src/pages/activity/Detail.jsx index 8817d02..188396c 100644 --- a/frontend/src/pages/activity/Detail.jsx +++ b/frontend/src/pages/activity/Detail.jsx @@ -396,8 +396,7 @@ const ActivityDetail = () => { {/* Hero Image with LayoutId for shared transition */}
-