1
0
forked from erp-dev/erp
Files
erpnew/stateflow/admin.py

225 lines
8.1 KiB
Python

from django.contrib import admin
from django.contrib.admin import action
from django.utils.safestring import mark_safe
from . import models
@admin.register(models.StateParameter)
class StateParameterAdmin(admin.ModelAdmin):
"""工艺参数管理"""
list_display = (
'id',
'key',
'value',
'is_required',
'is_image_path',
'state_list',
'description',
'attachment_preview',
)
search_fields = ('key', 'description')
list_filter = ('is_required', 'is_image_path', 'created_at', 'updated_at', 'states__processes__name')
readonly_fields = ('attachment_preview_detail', 'value_preview')
@admin.display(description='附件')
def attachment_preview(self, obj):
"""列表中显示是否有附件"""
if obj.attachment:
return ''
return ''
@admin.display(description='所属节点')
def state_list(self, obj):
"""显示关联的状态节点"""
states = obj.states.all()
if states:
return mark_safe('<br>'.join([f"{state.name}" for state in states]))
return '-'
def attachment_preview_detail(self, obj):
"""详情页显示附件预览"""
if obj.attachment:
if obj.attachment.name.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp')):
return mark_safe(f'<img src="{obj.attachment.url}" style="max-width: 400px; max-height: 400px;" />')
else:
return mark_safe(f'<a href="{obj.attachment.url}" target="_blank">下载附件</a>')
return "-"
attachment_preview_detail.short_description = '附件预览'
def value_preview(self, obj):
"""如果标记为图片路径,则显示图片预览"""
if obj.is_image_path and obj.value:
# 假设 value 是图片 URL
return mark_safe(f'<img src="{obj.value}" style="max-width: 400px; max-height: 400px;" onerror="this.style.display=\'none\'; this.parentNode.innerHTML+=\'<span>(图片加载失败)</span>\';" />')
return obj.value or "-"
value_preview.short_description = 'Value预览'
class ProcessNodeInline(admin.StackedInline):
model = models.ProcessNode
extra = 1
autocomplete_fields = ('state',)
ordering = ('order',)
@admin.register(models.State)
class StateAdmin(admin.ModelAdmin):
list_display = (
'id',
'name',
'description',
'created_at',
'updated_at',
'parameter_count',
)
search_fields = ('name', 'description')
list_filter = ('created_at', 'updated_at', 'processes__name')
filter_horizontal = ('parameters',)
@admin.display(description='参数数量')
def parameter_count(self, obj: models.State):
count = obj.parameters.count()
if count > 0:
params = obj.parameters.all()[:3]
keys = ', '.join([p.key for p in params])
if count > 3:
keys += f'{count}'
return f"{count} ({keys})"
return "0"
@admin.register(models.Process)
class ProcessAdmin(admin.ModelAdmin):
list_display = (
'id',
'name',
'node_count',
'description',
'updated_at',
)
search_fields = ('name', 'description')
list_filter = ('created_at', 'updated_at')
inlines = [ProcessNodeInline]
@admin.display(description='节点数量')
def node_count(self, obj: models.Process):
return obj.process_nodes.count()
class StateFlowRecordInline(admin.StackedInline):
model = models.StateFlowRecord
extra = 0
fields = ('state', 'completed_at', 'completed_by', 'is_cancelled', 'cancelled_at')
readonly_fields = ('completed_at', 'completed_by', 'cancelled_at')
can_delete = False
ordering = ('completed_at',)
@admin.register(models.BusinessObject)
class BusinessObjectAdmin(admin.ModelAdmin):
list_display = (
'id',
'name',
'process',
'content_object_display',
'current_state_display',
'progress',
'params',
'updated_at',
)
search_fields = ('name', 'description')
list_filter = ('process', 'created_at', 'updated_at')
actions = ['advance_to_next_state_action', 'step_back_one_state_action', 'reset_progress_action']
autocomplete_fields = ('process',)
inlines = [StateFlowRecordInline]
fieldsets = [
('基本信息', {
'fields': ['name', 'process', 'description']
}),
('关联对象(可选)', {
'fields': ['content_type', 'object_id'],
'description': '可选择关联到实际的业务对象,如订单、工单等'
}),
]
@admin.display(description='关联对象')
def content_object_display(self, obj: models.BusinessObject):
"""显示关联对象"""
if obj.content_object:
return f"{obj.content_type} #{obj.object_id}"
return "-"
@action(description='前进到下一个状态')
def advance_to_next_state_action(self, request, queryset):
from . import services
success_count = 0
messages = []
for obj in queryset:
success, message, _ = services.advance_to_next_state(obj, request.user)
if success:
success_count += 1
messages.append(f"{obj.name}: {message}")
self.message_user(request, f'成功推进 {success_count}/{queryset.count()} 个业务对象。详情: {"; ".join(messages[:5])}')
@action(description='回退一步')
def step_back_one_state_action(self, request, queryset):
from . import services
success_count = 0
messages = []
for obj in queryset:
success, message = services.step_back_one_state(obj, request.user)
if success:
success_count += 1
messages.append(f"{obj.name}: {message}")
self.message_user(request, f'成功回退 {success_count}/{queryset.count()} 个业务对象。详情: {"; ".join(messages[:5])}')
@action(description='重置进度')
def reset_progress_action(self, request, queryset):
from . import services
for obj in queryset:
services.reset_business_object_progress(obj)
self.message_user(request, f'已重置 {queryset.count()} 个业务对象的进度。')
@admin.display(description='当前状态', ordering='process')
def current_state_display(self, obj: models.BusinessObject):
from . import services
current_state = obj.get_current_state()
overall_status = services.get_overall_status(obj)
if overall_status == 'not_started':
return '未开始'
elif overall_status == 'completed':
return f'已完成 ({current_state.name if current_state else "-"})'
elif current_state:
# 显示最后完成的状态
return f'进行中 (已完成: {current_state.name})'
return '-'
@admin.display(description='进度')
def progress(self, obj: models.BusinessObject):
return f"{obj.get_progress_percentage():.1f}%"
@admin.display(description='最后完成状态参数')
def params(self, obj: models.BusinessObject):
"""显示最后完成状态的参数"""
current_state = obj.get_current_state()
if current_state:
params = current_state.parameters.all()
if params:
return ", ".join([f"{param.key}={param.value}" for param in params])
return "-"
@admin.register(models.StateFlowRecord)
class StateFlowRecordAdmin(admin.ModelAdmin):
list_display = ('id', 'business_object', 'state', 'completed_at', 'completed_by', 'is_cancelled', 'cancelled_at')
search_fields = ('business_object__name', 'state__name')
list_filter = ('state', 'is_cancelled', 'completed_at', 'completed_by')
readonly_fields = ('business_object', 'state', 'completed_at', 'completed_by', 'cancelled_at')
fields = ('business_object', 'state', 'completed_at', 'completed_by', 'is_cancelled', 'cancelled_at')
autocomplete_fields = ('business_object', 'state', 'completed_by')