Files
market_page/backend/competition/admin.py
jeremygan2021 c62c5b98ea
All checks were successful
Deploy to Server / deploy (push) Successful in 17s
new
2026-03-20 13:27:54 +08:00

203 lines
8.1 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 unfold.admin import ModelAdmin
from unfold.decorators import display
from .models import Competition, CompetitionEnrollment, ScoreDimension, Project, ProjectFile, Score, Comment, ScoreFormula
class ScoreDimensionInline(admin.TabularInline):
model = ScoreDimension
extra = 1
tab = True
fields = ('name', 'description', 'weight', 'max_score', 'formula_type', 'formula', 'is_public', 'is_peer_review', 'order')
@admin.display(description="算式预览")
def formula_preview(self, obj):
preview = obj.get_formula_preview()
return preview if preview else "-"
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')
}),
('评分计算设置', {
'fields': ('score_calculation_type', 'custom_score_formula'),
'description': '配置得分计算方式:默认模式使用(维度分数×权重)求和后取评委平均;自定义算式使用下方公式直接计算最终得分。变量格式: dimension_维度ID如 dimension_1, dimension_2'
}),
)
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 = "评语内容"
class ScoreFormulaAdmin(ModelAdmin):
"""
评分公式管理
提供可视化公式编辑功能
"""
list_display = ['name', 'competition', 'formula_preview_display', 'is_active', 'is_default', 'created_at']
list_filter = ['competition', 'is_active', 'is_default']
search_fields = ['name', 'description', 'formula', 'competition__title']
autocomplete_fields = ['competition']
fieldsets = (
('基本信息', {
'fields': ('competition', 'name', 'description')
}),
('公式配置', {
'fields': ('formula',),
'description': '使用维度名称作为变量,例如: 创新性 * 0.3 + 实用性 * 0.5 + 演示效果 * 0.2'
}),
('公式设置', {
'fields': ('is_active', 'is_default')
}),
)
@display(description="公式预览")
def formula_preview_display(self, obj):
preview = obj.get_formula_preview()
return preview[:100] + '...' if len(preview) > 100 else preview if preview else '-'
def get_form_kwargs(self, request, *args, **kwargs):
kwargs = super().get_form_kwargs(request, *args, **kwargs)
return kwargs
def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
extra_context = extra_context or {}
if request.method == 'GET' and not object_id:
competition_id = request.GET.get('competition')
if competition_id:
try:
from .models import ScoreDimension
dimensions = ScoreDimension.objects.filter(competition_id=competition_id)
extra_context['dimensions'] = dimensions
except:
pass
return super().changeform_view(request, object_id, form_url, extra_context)
class Media:
css = {
'all': ('competition/admin/css/formula-editor.css',)
}
js = ('competition/admin/js/formula-editor.js',)
admin.site.register(ScoreFormula, ScoreFormulaAdmin)