File size: 6,937 Bytes
b4f2238 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | from __future__ import annotations
from typing import Any
from django.contrib import admin, messages
from django.db.models import QuerySet
from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
from django.urls import reverse
from django.utils.html import format_html
from django.utils.safestring import SafeString
from django.utils.translation import gettext_lazy as _
from apps.cases.admin.base_admin import BaseTabularInline
from apps.cases.admin.mixins import CaseAdminServiceMixin
from apps.cases.models import CaseChat
@admin.register(CaseChat)
class CaseChatAdmin(CaseAdminServiceMixin, admin.ModelAdmin[CaseChat]):
"""案件群聊管理"""
list_display = ("name", "chat_id_display", "platform_display", "case_link", "status_display", "created_at")
list_filter = ("platform", "is_active", "created_at")
search_fields = ("name", "chat_id", "case__name")
readonly_fields = ("chat_id", "created_at", "updated_at")
fields = ("case", "platform", "chat_id", "name", "is_active", "created_at", "updated_at")
ordering = ("-created_at",)
actions = ["unbind_selected_chats"]
change_form_template = "admin/cases/casechat/change_form.html"
def chat_id_display(self, obj: CaseChat) -> str:
"""显示群聊ID(截断显示)"""
chat_id: str = obj.chat_id
if chat_id:
if len(chat_id) > 20:
return f"{chat_id[:20]}..."
return chat_id
return "-"
chat_id_display.short_description = _("群聊ID") # type: ignore[attr-defined]
def platform_display(self, obj: CaseChat) -> str:
"""显示平台(带图标)"""
platform_icons = {"feishu": "🚀", "dingtalk": "📱", "wechat_work": "💬", "telegram": "✈️", "slack": "💼"}
platform_labels = {"feishu": "飞书", "dingtalk": "钉钉", "wechat_work": "企业微信", "telegram": "Telegram", "slack": "Slack"}
icon = platform_icons.get(obj.platform, "📢")
display = platform_labels.get(obj.platform, obj.platform)
return f"{icon} {display}"
platform_display.short_description = _("平台") # type: ignore[attr-defined]
def case_link(self, obj: CaseChat) -> SafeString:
"""案件链接"""
case_id = getattr(obj, "case_id", None)
if case_id:
url = reverse("admin:cases_case_change", args=[case_id])
case_name = getattr(obj.case, "name", str(case_id))
return format_html('<a href="{}" target="_blank">{}</a>', url, case_name)
return format_html("<span>{}</span>", "-")
case_link.short_description = _("关联案件") # type: ignore[attr-defined]
def status_display(self, obj: CaseChat) -> SafeString:
"""状态显示"""
if obj.is_active:
return format_html('<span style="color: green;">●</span> {}', "有效")
else:
return format_html('<span style="color: red;">●</span> {}', "已解绑")
status_display.short_description = _("状态") # type: ignore[attr-defined]
def unbind_selected_chats(self, request: HttpRequest, queryset: QuerySet[CaseChat, CaseChat]) -> None:
"""批量解除绑定群聊"""
service = self._get_case_chat_service()
success_count = 0
for chat in queryset.filter(is_active=True):
try:
if service.unbind_chat(chat.id):
success_count += 1
except Exception as e:
msg = _("解除绑定群聊 %(chat)s 失败: %(error)s") % {
"chat": chat.name,
"error": str(e),
}
messages.error(request, msg)
if success_count > 0:
messages.success(request, _("成功解除绑定 %d 个群聊") % success_count)
unbind_selected_chats.short_description = _("解除绑定选中的群聊") # type: ignore[attr-defined]
def has_add_permission(self, request: HttpRequest) -> bool:
"""禁止直接添加群聊记录"""
return False
def has_delete_permission(self, request: HttpRequest, obj: CaseChat | None = None) -> bool:
"""禁止删除群聊记录"""
return False
def response_change(self, request: HttpRequest, obj: CaseChat) -> HttpResponse:
"""处理自定义操作"""
if "_unbind_chat" in request.POST:
service = self._get_case_chat_service()
try:
if service.unbind_chat(obj.id):
messages.success(request, _("成功解除绑定群聊: %s") % obj.name)
else:
messages.error(request, _("解除绑定群聊失败: %s") % obj.name)
except Exception as e:
messages.error(request, _("解除绑定群聊时发生错误: %s") % str(e))
return HttpResponseRedirect(reverse("admin:cases_casechat_changelist"))
return super().response_change(request, obj)
class CaseChatInline(BaseTabularInline):
"""案件群聊内联管理"""
model = CaseChat
extra = 0
fields = ("platform_display", "name", "chat_id_display", "status_display", "created_at")
readonly_fields = ("platform_display", "name", "chat_id_display", "status_display", "created_at")
ordering = ("platform", "-created_at")
def platform_display(self, obj: CaseChat) -> str:
"""显示平台(带图标)"""
if not obj.pk:
return ""
platform_icons = {"feishu": "🚀", "dingtalk": "📱", "wechat_work": "💬", "telegram": "✈️", "slack": "💼"}
icon = platform_icons.get(obj.platform, "📢")
display = obj.get_platform_display()
return f"{icon} {display}"
platform_display.short_description = _("平台") # type: ignore[attr-defined]
def chat_id_display(self, obj: CaseChat) -> str:
"""显示群聊ID(截断显示)"""
if not obj.pk or not obj.chat_id:
return ""
chat_id: str = obj.chat_id
if len(chat_id) > 15:
return f"{chat_id[:15]}..."
return chat_id
chat_id_display.short_description = _("群聊ID") # type: ignore[attr-defined]
def status_display(self, obj: CaseChat) -> SafeString:
"""状态显示"""
if not obj.pk:
return format_html("<span>{}</span>", "")
if obj.is_active:
return format_html('<span style="color: green;">●</span> {}', "有效")
else:
return format_html('<span style="color: red;">●</span> {}', "已解绑")
status_display.short_description = _("状态") # type: ignore[attr-defined]
def has_add_permission(self, request: HttpRequest, obj: Any = None) -> bool:
"""禁止直接添加群聊记录"""
return False
def has_delete_permission(self, request: HttpRequest, obj: Any = None) -> bool:
"""禁止删除群聊记录"""
return False
|