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 */}