Files
Scoring-System/backend/competition/admin.py

199 lines
7.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, CarouselItem
class CarouselItemInline(admin.TabularInline):
model = CarouselItem
extra = 1
tab = True
fields = ('carousel_type', 'image', 'image_url', 'title', 'subtitle', 'status', 'status_color', 'date', 'location', 'order', 'is_active')
autocomplete_fields = []
@admin.register(HomePageConfig)
class HomePageConfigAdmin(ModelAdmin):
list_display = ['id', 'main_title', 'carousel1_title', 'carousel2_title', 'organizer', 'undertaker', 'is_active']
list_editable = ['main_title', 'carousel1_title', 'carousel2_title', 'organizer', 'undertaker', 'is_active']
fieldsets = (
('首页Banner', {
'fields': ('banner_image', 'banner_image_url'),
'description': '首页顶部Banner图片可以上传本地图片或填写URL'
}),
('标题设置', {
'fields': ('main_title', 'carousel1_title', 'carousel2_title')
}),
('主办单位', {
'fields': ('organizer', 'undertaker')
}),
('状态', {
'fields': ('is_active',)
}),
)
@admin.register(CarouselItem)
class CarouselItemAdmin(ModelAdmin):
list_display = ['title', 'carousel_type', 'status', 'location', 'order', 'is_active', 'created_at']
list_filter = ['carousel_type', 'status', 'is_active']
search_fields = ['title', 'subtitle', 'location']
readonly_fields = ['image_preview']
fieldsets = (
('轮播图类型', {
'fields': ('carousel_type',)
}),
('图片设置', {
'fields': ('image', 'image_preview', 'image_url'),
'description': '优先使用本地上传的图片,上传后可预览'
}),
('内容设置', {
'fields': ('title', 'subtitle', 'status', 'status_color', 'date', 'location')
}),
('显示设置', {
'fields': ('order', 'is_active')
}),
)
@display(description='图片预览')
def image_preview(self, obj):
if obj.image:
return format_html('<img src="{}" style="max-width: 400px; max-height: 200px; border-radius: 8px;" />', obj.image.url)
elif obj.image_url:
return format_html('<img src="{}" style="max-width: 400px; max-height: 200px; border-radius: 8px;" />', obj.image_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 = "评语内容"