创赢未来评分系统 - 初始化提交(移除大文件)
All checks were successful
Deploy to Server / deploy (push) Successful in 18s
All checks were successful
Deploy to Server / deploy (push) Successful in 18s
This commit is contained in:
198
backend/competition/admin.py
Normal file
198
backend/competition/admin.py
Normal file
@@ -0,0 +1,198 @@
|
||||
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 = "评语内容"
|
||||
Reference in New Issue
Block a user