Files
Scoring-System/backend/competition/admin.py
爽哒哒 96be8b9eee
All checks were successful
Deploy to Server / deploy (push) Successful in 1m56s
feat: 首页配置封面图上传预览,修复系列活动跳转,活动卡片样式优化
2026-03-22 00:31:34 +08:00

173 lines
6.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from django.contrib import admin
from django.utils.html import format_html
from unfold.admin import ModelAdmin
from unfold.decorators import display
from .models import Competition, CompetitionEnrollment, ScoreDimension, Project, ProjectFile, Score, Comment, HomePageConfig
@admin.register(HomePageConfig)
class HomePageConfigAdmin(ModelAdmin):
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', 'banner_preview'),
'description': '首页标题下方的封面图可上传本地图片或填写URL优先使用上传的图片'
}),
('标题设置', {
'fields': ('main_title',)
}),
('主办单位', {
'fields': ('organizer', 'undertaker')
}),
('状态', {
'fields': ('is_active',)
}),
)
@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('<img src="{}" style="max-height:120px;max-width:300px;border-radius:6px;object-fit:cover;" />', url)
return "暂无图片"
class ScoreDimensionInline(admin.TabularInline):
model = ScoreDimension
extra = 1
tab = True
fields = ('name', 'description', 'weight', 'max_score', 'is_public', 'is_peer_review', 'order')
class ProjectFileInline(admin.TabularInline):
model = ProjectFile
extra = 0
tab = True
@admin.register(Competition)
class CompetitionAdmin(ModelAdmin):
list_display = ['title', 'status', 'allow_contestant_grading', 'start_time', 'end_time', 'is_active', 'created_at']
list_filter = ['status', 'allow_contestant_grading', 'is_active']
search_fields = ['title', 'description']
inlines = [ScoreDimensionInline]
fieldsets = (
('基本信息', {
'fields': ('title', 'description', 'rule_description', 'condition_description')
}),
('封面设置', {
'fields': ('cover_image', 'cover_image_url'),
'description': '封面图可以上传本地图片,也可以填写外部链接,优先显示本地上传的图片'
}),
('时间和状态', {
'fields': ('start_time', 'end_time', 'status', 'project_visibility', 'allow_contestant_grading', 'is_active')
}),
)
actions = ['make_published', 'make_ended']
def make_published(self, request, queryset):
queryset.update(status='published')
make_published.short_description = "发布选中比赛"
def make_ended(self, request, queryset):
queryset.update(status='ended')
make_ended.short_description = "结束选中比赛"
@admin.register(CompetitionEnrollment)
class CompetitionEnrollmentAdmin(ModelAdmin):
list_display = ['competition', 'user_info_display', 'role', 'status', 'created_at']
list_filter = ['competition', 'role', 'status']
search_fields = ['user__nickname', 'user__phone_number', 'competition__title']
autocomplete_fields = ['user', 'competition']
actions = ['approve_enrollment', 'reject_enrollment']
@display(description="报名用户 (手机号/昵称)")
def user_info_display(self, obj):
if not obj.user:
return "-"
phone = obj.user.phone_number or "无手机号"
nickname = obj.user.nickname or "无昵称"
return f"{phone} ({nickname})"
def approve_enrollment(self, request, queryset):
queryset.update(status='approved')
approve_enrollment.short_description = "通过审核"
def reject_enrollment(self, request, queryset):
queryset.update(status='rejected')
reject_enrollment.short_description = "拒绝申请"
@admin.register(Project)
class ProjectAdmin(ModelAdmin):
list_display = ['id', 'title', 'competition', 'contestant_info_display', 'status', 'final_score', 'created_at']
list_filter = ['competition', 'status']
search_fields = ['id', 'title', 'contestant__user__nickname', 'contestant__user__phone_number']
autocomplete_fields = ['competition', 'contestant']
inlines = [ProjectFileInline]
readonly_fields = ['id', 'final_score']
fieldsets = (
('基本信息', {
'fields': ('competition', 'contestant', 'title', 'description', 'team_info')
}),
('封面设置', {
'fields': ('cover_image', 'cover_image_url'),
'description': '封面图可以上传本地图片,也可以填写外部链接,优先显示本地上传的图片'
}),
('状态和得分', {
'fields': ('status', 'final_score')
}),
)
@display(description="参赛人员 (手机号/昵称)")
def contestant_info_display(self, obj):
if not obj.contestant or not obj.contestant.user:
return "-"
user = obj.contestant.user
phone = user.phone_number or "无手机号"
nickname = user.nickname or "无昵称"
return f"{phone} ({nickname})"
@admin.register(Score)
class ScoreAdmin(ModelAdmin):
list_display = ['project', 'judge_info_display', 'dimension', 'score', 'created_at']
list_filter = ['project__competition', 'dimension']
search_fields = ['project__title', 'judge__user__nickname', 'judge__user__phone_number']
autocomplete_fields = ['project', 'judge']
@display(description="评委 (手机号/昵称)")
def judge_info_display(self, obj):
if not obj.judge or not obj.judge.user:
return "-"
user = obj.judge.user
phone = user.phone_number or "无手机号"
nickname = user.nickname or "无昵称"
return f"{phone} ({nickname})"
@admin.register(Comment)
class CommentAdmin(ModelAdmin):
list_display = ['project', 'judge_info_display', 'content_preview', 'created_at']
list_filter = ['project__competition']
search_fields = ['project__title', 'judge__user__nickname', 'judge__user__phone_number', 'content']
autocomplete_fields = ['project', 'judge']
@display(description="评委 (手机号/昵称)")
def judge_info_display(self, obj):
if not obj.judge or not obj.judge.user:
return "-"
user = obj.judge.user
phone = user.phone_number or "无手机号"
nickname = user.nickname or "无昵称"
return f"{phone} ({nickname})"
def content_preview(self, obj):
return obj.content[:50] + '...' if len(obj.content) > 50 else obj.content
content_preview.short_description = "评语内容"