Files
fzjg_local/fzjgact/huodong/admin.py
2025-12-03 17:17:17 +08:00

288 lines
11 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.contrib.admin.actions import delete_selected
from django.urls import reverse
from django.utils.html import format_html
from .models import Branch, EquipmentImage, Drawing, PublicScreen
from .models import Activity, Branch, Event, Contact, VideoTerminal, Budget, EquipmentBudget, InfrastructureBudget, BudgetTemplate, TemplateEquipmentItem, TemplateInfrastructureItem
from django_select2.forms import Select2Widget
from unfold.admin import ModelAdmin
from django.contrib.admin import AdminSite
from django.contrib.auth.models import User, Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.admin import GroupAdmin as BaseGroupAdmin
from django.db.models import Count, Q
from django.utils.html import format_html
from django.urls import reverse
from django import forms
# 定义Activity的内联admin类
class ActivityInline(admin.TabularInline): # 改为更紧凑的表格形式内联原StackedInline为堆叠形式
model = Activity
extra = 1 # 在Branch表单中默认显示1个额外的Activity表单可根据需求调整数值
fields = ('name', 'scope', 'start_time', 'end_time') # 限制内联表单显示的字段
readonly_fields = ('start_time',) # 可选:将开始时间设为只读字段(避免误修改)
# 可选:添加帮助文本提示
help_texts = {
'name': '请输入活动名称(必填)',
'scope': '选择活动范围(内部/外部)'
}
admin.site.unregister(User)
admin.site.unregister(Group)
@admin.register(User)
class UserAdmin(BaseUserAdmin, ModelAdmin):
pass
@admin.register(Group)
class GroupAdmin(BaseGroupAdmin, ModelAdmin):
pass
@admin.register(Branch)
class BranchAdmin(ModelAdmin):
inlines = [ActivityInline]
list_display = ('name', 'location', 'category', 'display_mature_status', 'background_color')
search_fields = ['name', 'location']
fieldsets = (
(None, {
'fields': ('name', 'location', 'contact_info', 'description', 'category', 'is_mature', 'background_color')
}),
)
def display_mature_status(self, obj):
return '💼' if obj.is_mature else '📒'
display_mature_status.short_description = '是否成熟'
def activity_count(self, obj):
return obj.activity_set.count()
activity_count.short_description = '活动数量'
def get_queryset(self, request):
queryset = super().get_queryset(request)
queryset = queryset.annotate(
inspection_person_count=Count('contact', filter=Q(contact__category='机房/设备间巡检人')))
return queryset
actions = ['set_branches_to_type_b']
def set_branches_to_type_b(self, request, queryset):
queryset.update(category='B型')
set_branches_to_type_b.short_description = '将选中的分支机构统一改为B型'
# 注册Activity模型如果需要的话虽然在这个示例中我们主要关注Branch
@admin.register(Activity)
class ActivityAdmin(ModelAdmin):
list_display = ('branch', 'scope', 'name', 'start_time', 'end_time')
search_fields = ["branch__name"] # 改为关联Branch模型的name字段
add_form_template = 'admin/huodong/add_form.html'
autocomplete_fields = ['branch']
@admin.register(Event)
class EventAdmin(ModelAdmin):
list_display = ('name', 'start_time', 'end_time', 'description')
filter_horizontal = ('branches',)
class ContactAdminForm(forms.ModelForm):
class Meta:
model = Contact
fields = '__all__'
widgets = {
# 使用复选框实现多选
'category': forms.CheckboxSelectMultiple(choices=Contact.CATEGORY_CHOICES)
}
class EquipmentImageAdmin(admin.ModelAdmin):
def bulk_delete_selected(self, request, queryset):
count = queryset.count()
queryset.delete()
self.message_user(request, f'已成功删除{count}条设备图片记录')
bulk_delete_selected.short_description = '批量删除选中的设备图片'
actions = ['bulk_delete_selected']
list_display = ['id', 'branch', 'uploaded_at', 'delete_link']
def delete_link(self, obj):
url = reverse('admin:huodong_equipmentimage_delete', args=[obj.id])
return format_html('<a class="deletelink" href="{}">删除</a>', url)
delete_link.short_description = '操作'
list_filter = ['branch']
search_fields = ['branch__name']
autocomplete_fields = ['branch']
def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs)
# 设置默认分支机构为最后一个设备间图片的分支机构
try:
latest_image = EquipmentImage.objects.latest('uploaded_at')
form.base_fields['branch'].initial = latest_image.branch_id
except EquipmentImage.DoesNotExist:
pass
return form
def save_model(self, request, obj, form, change):
super().save_model(request, obj, form, change)
# Count images for the current branch
count = EquipmentImage.objects.filter(branch=obj.branch).count()
self.message_user(request, f"{obj.branch.name}】已经有{count}张设备间图片。")
admin.site.register(EquipmentImage, EquipmentImageAdmin)
class DrawingAdmin(admin.ModelAdmin):
def bulk_delete_selected(self, request, queryset):
count = queryset.count()
queryset.delete()
self.message_user(request, f'已成功删除{count}条图纸记录')
bulk_delete_selected.short_description = '批量删除选中的图纸'
actions = ['bulk_delete_selected']
list_display = ('id', 'branch', 'uploaded_at', 'delete_link')
def delete_link(self, obj):
url = reverse('admin:huodong_drawing_delete', args=[obj.id])
return format_html('<a class="deletelink" href="{}">删除</a>', url)
delete_link.short_description = '操作'
list_filter = ('branch', 'uploaded_at')
search_fields = ('branch__name',)
autocomplete_fields = ['branch']
admin.site.register(Drawing, DrawingAdmin)
class PublicScreenAdmin(ModelAdmin):
def delete_link(self, obj):
if obj.id:
delete_url = reverse('admin:huodong_publicscreen_delete', args=[obj.id])
return format_html('<a href="{}" class="text-red-600 hover:text-red-900">删除</a>', delete_url)
return '-'
delete_link.short_description = '操作'
def bulk_delete_selected(self, request, queryset):
count = queryset.count()
queryset.delete()
self.message_user(request, f'已成功删除{count}条公共电子屏记录')
bulk_delete_selected.short_description = '批量删除选中的公共电子屏'
list_display = ('id', 'branch', 'screen_type', 'last_drill', 'delete_link')
list_filter = ['branch', 'screen_type']
autocomplete_fields = ['branch']
actions = ['bulk_delete_selected']
admin.site.register(PublicScreen, PublicScreenAdmin)
@admin.register(Contact)
class ContactAdmin(ModelAdmin):
form = ContactAdminForm # 指定自定义表单
list_display = ('branch', 'category', 'name', 'phone', 'email') # 可选:显示分类字段
autocomplete_fields = ['branch']
@admin.register(VideoTerminal)
class VideoTerminalAdmin(ModelAdmin):
list_display = ('branch', 'terminal_type', 'description', 'created_at')
list_filter = ('terminal_type', 'branch')
search_fields = ('branch__name', 'description')
autocomplete_fields = ['branch']
# 预算相关Admin配置
# 设备预算内联
class EquipmentBudgetInline(admin.TabularInline):
model = EquipmentBudget
extra = 1
fields = ('project', 'model', 'unit_price', 'procurement_method', 'quantity', 'subtotal')
readonly_fields = ('subtotal',) # 小计自动计算,设为只读
# 基础设施预算内联
class InfrastructureBudgetInline(admin.TabularInline):
model = InfrastructureBudget
extra = 1
fields = ('name', 'remarks', 'unit_price', 'unit', 'quantity', 'subtotal', 'description')
readonly_fields = ('subtotal',) # 小计自动计算,设为只读
# 预算Admin
@admin.register(Budget)
class BudgetAdmin(ModelAdmin):
list_display = ('branch', 'name', 'total_budget', 'created_at')
list_filter = ('branch',)
search_fields = ('branch__name', 'name')
autocomplete_fields = ['branch']
readonly_fields = ('total_budget',) # 总预算自动计算,设为只读
inlines = [EquipmentBudgetInline, InfrastructureBudgetInline]
def save_model(self, request, obj, form, change):
super().save_model(request, obj, form, change)
# 保存后重新计算总预算
obj.update_total_budget()
# 设备预算Admin如果需要单独管理
@admin.register(EquipmentBudget)
class EquipmentBudgetAdmin(ModelAdmin):
list_display = ('budget', 'project', 'model', 'unit_price', 'procurement_method', 'quantity', 'subtotal')
list_filter = ('budget__branch', 'project', 'procurement_method')
search_fields = ('budget__branch__name', 'project', 'model')
autocomplete_fields = ['budget']
readonly_fields = ('subtotal',)
# 基础设施预算Admin如果需要单独管理
@admin.register(InfrastructureBudget)
class InfrastructureBudgetAdmin(ModelAdmin):
list_display = ('budget', 'name', 'unit_price', 'unit', 'quantity', 'subtotal')
list_filter = ('budget__branch', 'name')
search_fields = ('budget__branch__name', 'name', 'description')
autocomplete_fields = ['budget']
readonly_fields = ('subtotal',)
# 预算模板相关Admin配置
# 模板设备项内联
class TemplateEquipmentItemInline(admin.TabularInline):
model = TemplateEquipmentItem
extra = 1
# 模板基础设施项内联
class TemplateInfrastructureItemInline(admin.TabularInline):
model = TemplateInfrastructureItem
extra = 1
# 模板设备项Admin如果需要单独管理
@admin.register(TemplateEquipmentItem)
class TemplateEquipmentItemAdmin(ModelAdmin):
list_display = ('template', 'project', 'model', 'unit_price', 'procurement_method')
list_filter = ('template', 'project', 'procurement_method')
search_fields = ('template__name', 'project', 'model')
autocomplete_fields = ['template']
# 模板基础设施项Admin如果需要单独管理
@admin.register(TemplateInfrastructureItem)
class TemplateInfrastructureItemAdmin(ModelAdmin):
list_display = ('template', 'name', 'unit_price', 'unit')
list_filter = ('template', 'unit')
search_fields = ('template__name', 'name', 'description')
autocomplete_fields = ['template']
# 预算模板Admin
@admin.register(BudgetTemplate)
class BudgetTemplateAdmin(ModelAdmin):
list_display = ('name', 'description', 'is_default', 'created_at')
list_filter = ('is_default',)
search_fields = ('name', 'description')
inlines = [TemplateEquipmentItemInline, TemplateInfrastructureItemInline]
def save_model(self, request, obj, form, change):
# 如果设置为默认模板,将其他模板的默认状态取消
if obj.is_default:
BudgetTemplate.objects.exclude(id=obj.id).update(is_default=False)
super().save_model(request, obj, form, change)