用户接口系统(中文译文)
原始 DeepWiki 页面:https://deepwiki.com/mayan-edms/Mayan-EDMS/3.3-user-interface-system
翻译时间:2026-05-27T08:44:33.087Z
翻译模型:deepseek-chat
原文字符数:15739
项目:Mayan EDMS (mayan-edms)
---
用户界面系统
相关源文件
以下文件用于生成此维基页面:
mayan/apps/appearance/literals.pymayan/apps/appearance/settings.pymayan/apps/appearance/static/appearance/js/mayan_app.jsmayan/apps/appearance/static/appearance/js/partial_navigation.jsmayan/apps/appearance/templates/appearance/app/foot.htmlmayan/apps/appearance/templates/appearance/base.htmlmayan/apps/appearance/templates/appearance/base_plain.htmlmayan/apps/appearance/templates/appearance/generic_list_items_subtemplate.htmlmayan/apps/appearance/templates/appearance/generic_list_subtemplate.htmlmayan/apps/appearance/templates/appearance/partials/meta_tags.htmlmayan/apps/appearance/templates/appearance/root.htmlmayan/apps/common/menus.pymayan/apps/documents/templates/documents/invalid_document.htmlmayan/apps/navigation/classes.pymayan/apps/navigation/templatetags/navigation_tags.pymayan/apps/navigation/utils.pymayan/apps/redactions/templates/redactions/cropper.htmlmayan/apps/views/middleware/ajax_redirect.py
目的与范围
用户界面系统为 Mayan EDMS 提供基于 Web 的前端,实现了复杂的导航框架、基于 AJAX 的单页应用功能和动态内容渲染。该系统处理用户交互、菜单生成、链接解析、基于权限的导航和响应式列表视图。
关于 REST API 接口的信息,请参阅 REST API 架构。关于核心文档管理功能,请参阅 文档管理核心。
架构总览
UI 系统由多个相互连接的组件构建而成,这些组件协同工作以提供无缝的用户体验:
graph TB
subgraph "前端层"
TEMPLATES["Django 模板<br/>base.html, root.html"]
JS_APP["MayanApp<br/>JavaScript 应用"]
PARTIAL_NAV["PartialNavigation<br/>AJAX 导航"]
end
subgraph "导航框架"
LINK_CLASS["Link 类<br/>单个链接"]
MENU_CLASS["Menu 类<br/>链接容器"]
RESOLVED_LINK["ResolvedLink<br/>运行时解析"]
end
subgraph "内容渲染"
SOURCE_COL["SourceColumn<br/>列表视图列"]
TEMPLATE_TAGS["导航标签<br/>模板集成"]
LIST_VIEWS["通用列表视图<br/>表格/卡片渲染"]
end
subgraph "后端集成"
DJANGO_VIEWS["Django 视图"]
PERMISSIONS["权限系统"]
MODELS["Django 模型"]
end
TEMPLATES --> TEMPLATE_TAGS
TEMPLATE_TAGS --> MENU_CLASS
TEMPLATE_TAGS --> SOURCE_COL
JS_APP --> PARTIAL_NAV
PARTIAL_NAV --> DJANGO_VIEWS
MENU_CLASS --> LINK_CLASS
LINK_CLASS --> RESOLVED_LINK
RESOLVED_LINK --> PERMISSIONS
SOURCE_COL --> MODELS
LIST_VIEWS --> SOURCE_COL
LIST_VIEWS --> TEMPLATE_TAGS
来源:mayan/apps/navigation/classes.py:1-979, mayan/apps/appearance/templates/appearance/base.html:1-119, mayan/apps/appearance/static/appearance/js/mayan_app.js:1-439
导航框架
核心类
导航系统围绕三个主要类构建,这些类处理链接定义、组织和解析:
classDiagram
class Link {
+text: str
+view: str
+permissions: list
+condition: callable
+resolve() ResolvedLink
+check_condition() bool
}
class Menu {
+name: str
+label: str
+bound_links: dict
+excluded_links: dict
+bind_links()
+resolve() list
+get_links_for() set
}
class ResolvedLink {
+url: str
+active: bool
+disabled: bool
+context: dict
+link: Link
}
class SourceColumn {
+attribute: str
+label: str
+is_sortable: bool
+widget: class
+resolve() str
+get_sort_field_querystring() str
}
Link --> ResolvedLink : 创建
Menu --> Link : 包含
Menu --> ResolvedLink : 解析为
来源:mayan/apps/navigation/classes.py:34-241, mayan/apps/navigation/classes.py:242-598, mayan/apps/navigation/classes.py:600-653, mayan/apps/navigation/classes.py:669-962
链接解析过程
链接经过多步解析过程,处理权限、条件和上下文:
flowchart TD
START["Link.resolve()"] --> CONTEXT_CHECK{"上下文/请求<br/>可用?"}
CONTEXT_CHECK -->|否| ERROR["ImproperlyConfigured"]
CONTEXT_CHECK -->|是| PERM_CHECK{"需要权限?"}
PERM_CHECK -->|是| ACL_CHECK["AccessControlList.check_access()"]
PERM_CHECK -->|否| CONDITION_CHECK{"条件函数?"}
ACL_CHECK -->|拒绝| RETURN_NONE["返回 None"]
ACL_CHECK -->|授予| CONDITION_CHECK
CONDITION_CHECK -->|假| RETURN_NONE
CONDITION_CHECK -->|真| URL_RESOLVE["通过 URLNode<br/>解析 URL"]
URL_RESOLVE --> QUERY_BUILD["构建查询字符串<br/>keep_query, remove_from_query"]
QUERY_BUILD --> CREATE_RESOLVED["创建 ResolvedLink"]
CREATE_RESOLVED --> RETURN_RESOLVED["返回 ResolvedLink"]
来源:mayan/apps/navigation/classes.py:81-239
模板集成
导航菜单通过自定义模板标签集成到模板中:
| 模板标签 | 用途 | 关键参数 |
|---|---|---|
navigation_resolve_menu | 为上下文解析单个菜单 | name, source, sort_results |
navigation_resolve_menus | 解析多个菜单 | names(逗号分隔) |
navigation_get_source_columns | 获取列表视图的列 | exclude_identifier, only_identifier |
navigation_source_column_resolve | 解析列值 | column, context |
来源:mayan/apps/navigation/templatetags/navigation_tags.py:8-78
AJAX 导航系统
PartialNavigation 类
PartialNavigation 类通过拦截点击和表单提交来实现单页应用行为:
stateDiagram-v2
[*] --> 初始化
初始化 --> 设置锚点 : setupAjaxAnchors()
初始化 --> 设置表单 : setupAjaxForm()
初始化 --> 设置历史 : setupAjaxNavigation()
设置锚点 --> 锚点点击 : 用户点击链接
锚点点击 --> 过滤位置 : filterLocation()
过滤位置 --> 加载内容 : loadAjaxContent()
设置表单 --> 表单提交 : 用户提交表单
表单提交 --> 加载内容
加载内容 --> 处理响应 : AJAX 成功
处理响应 --> 更新历史 : history.pushState()
处理响应 --> 更新内容 : $("#ajax-content").html()
设置历史 --> 弹出状态 : 浏览器后退/前进
弹出状态 --> 加载内容
来源:mayan/apps/appearance/static/appearance/js/partial_navigation.js:17-396
AJAX 请求流程
系统处理 AJAX 请求时包含限流、错误处理和重定向:
sequenceDiagram
participant 用户
participant PartialNav as "PartialNavigation"
participant Django as "Django 后端"
participant 中间件 as "AjaxRedirect 中间件"
用户->>PartialNav: 点击链接/提交表单
PartialNav->>PartialNav: filterLocation()
PartialNav->>Django: AJAX 请求(X-Alt-Referer 请求头)
中间件->>Django: 从 X-Alt-Referer 设置 HTTP_REFERER
Django->>Django: 处理视图
alt 重定向响应
Django->>中间件: HttpResponseRedirect
中间件->>PartialNav: 状态码 278(AJAX 重定向代码)
PartialNav->>PartialNav: setLocation(newLocation)
else 正常响应
Django->>PartialNav: HTML 内容
PartialNav->>PartialNav: 更新 #ajax-content
PartialNav->>浏览器: history.pushState()
end
来源:mayan/apps/appearance/static/appearance/js/partial_navigation.js:87-152, mayan/apps/views/middleware/ajax_redirect.py:7-21
模板系统
基础模板结构
模板层级结构提供灵活的布局选项:
graph TD
ROOT["root.html<br/>主布局"] --> BASE["base.html<br/>内容区域"]
ROOT --> PLAIN["base_plain.html<br/>简单布局"]
BASE --> VIEWPORT["#appearance-main-viewport"]
VIEWPORT --> HEADER["#ajax-header"]
VIEWPORT --> CONTENT["#ajax-content"]
BASE --> SIDEBAR["侧边栏导航<br/>facet, list facet 菜单"]
BASE --> ACTIONS["操作菜单<br/>object, secondary 菜单"]
CONTENT --> LIST_TABLE["generic_list_subtemplate.html<br/>表格视图"]
CONTENT --> LIST_ITEMS["generic_list_items_subtemplate.html<br/>卡片视图"]
来源:mayan/apps/appearance/templates/appearance/root.html:1-71, mayan/apps/appearance/templates/appearance/base.html:1-119
模板中的菜单解析
模板使用特定的命名约定来解析菜单:
| 菜单名称 | 用途 | 模板上下文 |
|---|---|---|
facet | 侧边栏对象特定操作 | 对象详情视图 |
list facet | 列表项操作 | 列表视图 |
object | 主要对象操作 | 对象视图 |
secondary | 次要操作 | 所有视图 |
multi item | 批量操作 | 带选择的列表视图 |
来源:mayan/apps/common/menus.py:7-24, mayan/apps/appearance/templates/appearance/base.html:35-56
JavaScript 应用层
MayanApp 类结构
主 JavaScript 应用协调 UI 行为和 AJAX 功能:
graph LR
subgraph "初始化"
SETUP_AJAX["setupAJAXSpinner()"]
SETUP_FORMS["setupFormHotkeys()"]
SETUP_MULTI["setupMultiItemActions()"]
SETUP_NAV["setupNavbarCollapse()"]
end
subgraph "事件处理器"
DROPDOWN["setupDropdownDirectionChange()"]
ITEMS["setupItemsSelector()"]
PANELS["setupPanelSelection()"]
RESIZE["setupFullHeightResizing()"]
end
subgraph "动态内容"
AJAX_MENUS["doRefreshAJAXMenu()"]
TOASTR["doToastrMessages()"]
SELECT2["setupSelect2()"]
TOOLBAR["setupListToolbar()"]
end
SETUP_AJAX --> AJAX_MENUS
SETUP_MULTI --> ITEMS
SETUP_FORMS --> PANELS
来源:mayan/apps/appearance/static/appearance/js/mayan_app.js:3-439
多项目选择系统
系统通过复选框选择支持批量操作:
flowchart TD
CLICK_ITEM["点击面板项"] --> CHECK_TARGET{"目标是复选框<br/>或包含 href/src?"}
CHECK_TARGET -->|否| TOGGLE_CHECKBOX["切换复选框状态"]
CHECK_TARGET -->|是| FOLLOW_LINK["跟随链接/操作"]
TOGGLE_CHECKBOX --> SHIFT_CHECK{"按住 Shift 键?"}
SHIFT_CHECK -->|是| SELECT_RANGE["选择范围<br/>在 lastChecked 和当前之间"]
SHIFT_CHECK -->|否| UPDATE_LAST["更新 lastChecked"]
SELECT_RANGE --> UPDATE_PANEL["更新面板高亮"]
UPDATE_LAST --> UPDATE_PANEL
UPDATE_PANEL --> COUNT_CHECKED["countChecked()"]
COUNT_CHECKED --> SHOW_ACTIONS["显示/隐藏多项目操作"]
来源:mayan/apps/appearance/static/appearance/js/mayan_app.js:367-420, mayan/apps/appearance/static/appearance/js/mayan_app.js:53-69
列表视图和源列
SourceColumn 系统
SourceColumn 类为列表视图提供动态列生成:
graph TB
subgraph "列定义"
COLUMN_DEF["SourceColumn()<br/>attribute, label, widget"]
REGISTRY["_registry 字典<br/>source -> [columns]"]
MODEL_MATCH["get_column_matches()<br/>匹配 source 到 columns"]
end
subgraph "列解析"
GET_FOR_SOURCE["get_for_source()<br/>按条件过滤"]
RESOLVE["resolve()<br/>从对象提取值"]
WIDGET_RENDER["widget.render()<br/>格式化输出"]
end
subgraph "排序支持"
SORT_FIELD["get_sort_field()<br/>sort_field 或 attribute"]
SORT_QS["get_sort_field_querystring()<br/>构建排序 URL"]
SORT_ICON["get_sort_icon()<br/>升序/降序指示器"]
end
COLUMN_DEF --> REGISTRY
REGISTRY --> MODEL_MATCH
MODEL_MATCH --> GET_FOR_SOURCE
GET_FOR_SOURCE --> RESOLVE
RESOLVE --> WIDGET_RENDER
RESOLVE --> SORT_FIELD
SORT_FIELD --> SORT_QS
SORT_FIELD --> SORT_ICON
来源:mayan/apps/navigation/classes.py:669-962
列表视图模板
两个主要的列表视图模板处理不同的展示样式:
| 模板 | 使用场景 | 关键特性 |
|---|---|---|
generic_list_subtemplate.html | 表格视图 | 可排序列,紧凑显示 |
generic_list_items_subtemplate.html | 卡片视图 | 基于面板的布局,视觉突出 |
两个模板都支持:
- 多项目复选框选择
- 源列渲染
- facet 和对象操作菜单
- 使用 Bootstrap 类的响应式设计
来源:mayan/apps/appearance/templates/appearance/generic_list_subtemplate.html:1-188, mayan/apps/appearance/templates/appearance/generic_list_items_subtemplate.html:1-94
集成点
权限集成
导航系统在多个层级与 Mayan 的 ACL 系统集成:
# 链接级权限检查
AccessControlList.objects.check_access(
obj=resolved_object,
permissions=self.permissions,
user=request.user
)
# 视图级权限检查
Permission.check_user_permissions(
permissions=self.permissions,
user=request.user
)
来源:mayan/apps/navigation/classes.py:110-125
模型集成
源列自动内省 Django 模型以获取标签和帮助文本:
# 自动标签解析
name, model = SourceColumn.get_attribute_recursive(
attribute=self.attribute,
model=self.source._meta.model
)
self._label = label_for_field(name=name, model=model)
来源:mayan/apps/navigation/classes.py:847-870
配置集成
系统遵循智能设置以进行行为定制:
| 设置项 | 用途 | 默认值 |
|---|---|---|
APPEARANCE_AJAX_REDIRECTION_CODE | AJAX 重定向状态码 | 278 |
APPEARANCE_MENU_POLLING_INTERVAL | 菜单刷新间隔 | 5000ms |
COMMON_COLLAPSE_LIST_MENU_OBJECT | 在列表中折叠对象菜单 | 布尔值 |
COMMON_COLLAPSE_LIST_MENU_LIST_FACET | 在列表中折叠 facet 菜单 | 布尔值 |
来源:mayan/apps/appearance/settings.py:12-39, mayan/apps/appearance/templates/appearance/app/foot.html:31-63