193 lines
6.3 KiB
Python
193 lines
6.3 KiB
Python
from django.contrib import admin
|
|
from django.utils.html import format_html
|
|
from django.urls import reverse
|
|
from django.utils.safestring import mark_safe
|
|
from .models import Food, UserFood, FoodUsageLog
|
|
|
|
|
|
@admin.register(Food)
|
|
class FoodAdmin(admin.ModelAdmin):
|
|
"""食物管理后台"""
|
|
|
|
list_display = [
|
|
'name', 'food_type', 'rarity', 'status', 'is_limited',
|
|
'calories', 'created_at', 'image_preview', 'action_buttons'
|
|
]
|
|
list_filter = [
|
|
'food_type', 'rarity', 'status', 'is_limited', 'created_at'
|
|
]
|
|
search_fields = ['name', 'description', 'taste_tags']
|
|
list_editable = ['status']
|
|
ordering = ['-created_at']
|
|
|
|
fieldsets = [
|
|
('基本信息', {
|
|
'fields': ['name', 'food_type', 'description', 'rarity']
|
|
}),
|
|
('多媒体资源', {
|
|
'fields': ['image', 'animation_file', 'sound_effect'],
|
|
'classes': ['collapse']
|
|
}),
|
|
('营养信息', {
|
|
'fields': ['calories', 'taste_tags', 'cooking_methods', 'nutritional_value'],
|
|
'classes': ['collapse']
|
|
}),
|
|
('游戏属性', {
|
|
'fields': ['effect_description', 'boost_attributes', 'unlock_condition', 'usage_limit'],
|
|
'classes': ['collapse']
|
|
}),
|
|
('发布设置', {
|
|
'fields': ['status', 'is_limited', 'available_from', 'available_until']
|
|
}),
|
|
('时间信息', {
|
|
'fields': ['created_at', 'updated_at', 'published_at'],
|
|
'classes': ['collapse']
|
|
})
|
|
]
|
|
readonly_fields = ['created_at', 'updated_at', 'published_at']
|
|
|
|
def image_preview(self, obj):
|
|
"""显示图片预览"""
|
|
if obj.image:
|
|
return format_html(
|
|
'<img src="{}" style="max-height: 50px; max-width: 80px; border-radius: 4px;"/>',
|
|
obj.image
|
|
)
|
|
return "无图片"
|
|
image_preview.short_description = "图片预览"
|
|
|
|
def action_buttons(self, obj):
|
|
"""操作按钮"""
|
|
buttons = []
|
|
|
|
if obj.status == 'draft':
|
|
buttons.append(
|
|
f'<a class="button" href="#" onclick="publishFood({obj.pk})">发布</a>'
|
|
)
|
|
elif obj.status == 'published':
|
|
buttons.append(
|
|
f'<a class="button" href="#" onclick="archiveFood({obj.pk})">归档</a>'
|
|
)
|
|
|
|
# 查看详情按钮
|
|
detail_url = reverse('admin:food_app_food_change', args=[obj.pk])
|
|
buttons.append(f'<a class="button" href="{detail_url}">编辑</a>')
|
|
|
|
return format_html(' '.join(buttons))
|
|
action_buttons.short_description = "操作"
|
|
|
|
actions = ['publish_foods', 'archive_foods']
|
|
|
|
def publish_foods(self, request, queryset):
|
|
"""批量发布食物"""
|
|
count = 0
|
|
for food in queryset:
|
|
if food.status == 'draft':
|
|
food.publish()
|
|
count += 1
|
|
self.message_user(request, f'成功发布了 {count} 个食物')
|
|
publish_foods.short_description = "发布选中的食物"
|
|
|
|
def archive_foods(self, request, queryset):
|
|
"""批量归档食物"""
|
|
count = 0
|
|
for food in queryset:
|
|
if food.status == 'published':
|
|
food.archive()
|
|
count += 1
|
|
self.message_user(request, f'成功归档了 {count} 个食物')
|
|
archive_foods.short_description = "归档选中的食物"
|
|
|
|
|
|
@admin.register(UserFood)
|
|
class UserFoodAdmin(admin.ModelAdmin):
|
|
"""用户食物管理后台"""
|
|
|
|
list_display = [
|
|
'user', 'food', 'quantity', 'used_count', 'obtained_method',
|
|
'obtained_at', 'last_used_at', 'can_use_display'
|
|
]
|
|
list_filter = [
|
|
'obtained_method', 'obtained_at', 'food__food_type', 'food__rarity'
|
|
]
|
|
search_fields = ['user__username', 'food__name', 'obtained_method']
|
|
ordering = ['-obtained_at']
|
|
|
|
fieldsets = [
|
|
('关联信息', {
|
|
'fields': ['user', 'food']
|
|
}),
|
|
('数量信息', {
|
|
'fields': ['quantity', 'used_count']
|
|
}),
|
|
('获得信息', {
|
|
'fields': ['obtained_at', 'obtained_method']
|
|
}),
|
|
('使用信息', {
|
|
'fields': ['last_used_at']
|
|
})
|
|
]
|
|
readonly_fields = ['obtained_at']
|
|
|
|
def can_use_display(self, obj):
|
|
"""显示是否可使用"""
|
|
if obj.can_use():
|
|
return format_html('<span style="color: green;">✓ 可使用</span>')
|
|
else:
|
|
return format_html('<span style="color: red;">✗ 不可使用</span>')
|
|
can_use_display.short_description = "状态"
|
|
|
|
def get_queryset(self, request):
|
|
"""优化查询"""
|
|
return super().get_queryset(request).select_related('user', 'food')
|
|
|
|
|
|
@admin.register(FoodUsageLog)
|
|
class FoodUsageLogAdmin(admin.ModelAdmin):
|
|
"""食物使用记录管理后台"""
|
|
|
|
list_display = [
|
|
'user', 'food', 'used_at', 'usage_context', 'effect_preview'
|
|
]
|
|
list_filter = [
|
|
'used_at', 'usage_context', 'food__food_type', 'food__rarity'
|
|
]
|
|
search_fields = ['user__username', 'food__name', 'usage_context', 'notes']
|
|
ordering = ['-used_at']
|
|
date_hierarchy = 'used_at'
|
|
|
|
fieldsets = [
|
|
('基本信息', {
|
|
'fields': ['user', 'food', 'used_at']
|
|
}),
|
|
('使用详情', {
|
|
'fields': ['usage_context', 'effect_applied', 'notes']
|
|
})
|
|
]
|
|
readonly_fields = ['used_at']
|
|
|
|
def effect_preview(self, obj):
|
|
"""效果预览"""
|
|
if obj.effect_applied:
|
|
# 简化显示JSON内容
|
|
import json
|
|
try:
|
|
effect_str = json.dumps(obj.effect_applied, ensure_ascii=False)
|
|
if len(effect_str) > 50:
|
|
effect_str = effect_str[:50] + '...'
|
|
return effect_str
|
|
except:
|
|
return str(obj.effect_applied)[:50] + '...'
|
|
return "-"
|
|
effect_preview.short_description = "应用效果"
|
|
|
|
def get_queryset(self, request):
|
|
"""优化查询"""
|
|
return super().get_queryset(request).select_related('user', 'food')
|
|
|
|
|
|
# 自定义管理后台标题
|
|
admin.site.site_header = 'QY LTY 后台管理'
|
|
admin.site.site_title = 'QY LTY Admin'
|
|
admin.site.index_title = '欢迎使用 QY LTY 管理后台'
|