File size: 5,452 Bytes
f8b03c1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
文书模板文件夹绑定 Admin 配置
"""

from __future__ import annotations

from typing import Any, ClassVar

from django import forms
from django.contrib import admin
from django.http import HttpRequest
from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _

from apps.core.exceptions import NotFoundError
from apps.documents.models import DocumentTemplateFolderBinding, FolderTemplate


def _get_folder_template_admin_service() -> Any:
    from ..services import FolderTemplateAdminService

    return FolderTemplateAdminService()


class FolderNodeChoiceField(forms.ChoiceField):
    """动态加载文件夹节点的选择字段"""

    def __init__(self, *args: Any, **kwargs: Any) -> None:
        kwargs.setdefault("choices", [("", "---------")])
        super().__init__(*args, **kwargs)


class DocumentTemplateFolderBindingForm(forms.ModelForm[DocumentTemplateFolderBinding]):
    """文书模板文件夹绑定表单"""

    folder_node_id = FolderNodeChoiceField(
        label=_("目标文件夹"),
        help_text=_("选择文书生成后存放的文件夹位置"),
    )

    class Meta:
        model = DocumentTemplateFolderBinding
        fields: str = "__all__"

    def __init__(self, *args: Any, **kwargs: Any) -> None:
        super().__init__(*args, **kwargs)

        # 如果已选择文件夹模板,加载其节点选项
        folder_template_id: int | str | None = None
        if self.instance and self.instance.pk:
            folder_template_id = self.instance.folder_template_id
        elif self.data.get("folder_template"):
            folder_template_id = self.data.get("folder_template")

        if folder_template_id:
            try:
                service = _get_folder_template_admin_service()
                folder_template: FolderTemplate = service.get_folder_template_by_pk(folder_template_id)
                choices = self._get_folder_choices(folder_template)
                self.fields["folder_node_id"].choices = choices  # type: ignore[attr-defined]
            except NotFoundError:
                pass

    def _get_folder_choices(self, folder_template: FolderTemplate) -> list[tuple[str, str]]:
        """从文件夹模板结构中提取所有节点作为选项"""
        choices: list[tuple[str, str]] = [("", "---------")]
        structure = folder_template.structure
        if structure:
            self._extract_nodes(structure.get("children", []), choices, "")
        return choices

    def _extract_nodes(self, children: list[Any], choices: list[tuple[str, str]], prefix: str) -> None:
        """递归提取节点"""
        for child in children:
            node_id = child.get("id", "")
            node_name = child.get("name", "")
            display_name = f"{prefix}{node_name}" if prefix else node_name
            if node_id:
                choices.append((node_id, display_name))
            # 递归处理子节点
            sub_children = child.get("children", [])
            if sub_children:
                new_prefix = f"{display_name} / "
                self._extract_nodes(sub_children, choices, new_prefix)


@admin.register(DocumentTemplateFolderBinding)
class DocumentTemplateFolderBindingAdmin(admin.ModelAdmin[DocumentTemplateFolderBinding]):
    """文书模板文件夹绑定管理"""

    form = DocumentTemplateFolderBindingForm
    change_form_template = "admin/documents/documenttemplatefolderbinding/change_form.html"
    change_list_template = "admin/documents/documenttemplatefolderbinding/change_list.html"

    list_display = (
        "document_template",
        "folder_template",
        "folder_path_display",
        "is_active",
        "updated_at",
    )

    list_filter = (
        "folder_template",
        "is_active",
        "document_template__template_type",
    )

    search_fields = (
        "document_template__name",
        "folder_template__name",
        "folder_node_path",
    )

    autocomplete_fields: ClassVar[list[str]] = ["document_template", "folder_template"]
    list_select_related: ClassVar[tuple[str, ...]] = ("document_template", "folder_template")

    readonly_fields = ("folder_node_path", "created_at", "updated_at")

    fieldsets = (
        (None, {"fields": ("document_template", "folder_template", "folder_node_id")}),
        (
            _("位置信息"),
            {
                "fields": ("folder_node_path",),
                "classes": ("collapse",),
            },
        ),
        (_("设置"), {"fields": ("is_active",)}),
        (
            _("时间信息"),
            {
                "fields": ("created_at", "updated_at"),
                "classes": ("collapse",),
            },
        ),
    )

    class Media:
        js: ClassVar[tuple[str, ...]] = ("documents/js/folder_binding_admin.js",)

    @admin.display(description=_("文件夹路径"))
    def folder_path_display(self, obj: DocumentTemplateFolderBinding) -> Any:
        """显示文件夹路径"""
        if obj.folder_node_path:
            return format_html('<span style="color: #666; font-family: monospace;">{}</span>', obj.folder_node_path)
        return "-"

    def save_model(self, request: HttpRequest, obj: DocumentTemplateFolderBinding, form: Any, change: bool) -> None:
        """保存时自动计算路径"""
        # 路径会在模型的save方法中自动计算
        super().save_model(request, obj, form, change)