From fcb8121f0a8b80c140fec7e7a7f4828a2d24a59d Mon Sep 17 00:00:00 2001 From: hailin Date: Thu, 16 Jul 2026 17:15:51 +0800 Subject: [PATCH] feat: reorganize platform navigation menus --- backend/apps/accounts/menus.py | 58 ++-- .../0002_reorganize_navigation_menus.py | 258 ++++++++++++++++++ .../tests/test_bootstrap_governance.py | 15 + 3 files changed, 311 insertions(+), 20 deletions(-) create mode 100644 backend/apps/accounts/migrations/0002_reorganize_navigation_menus.py diff --git a/backend/apps/accounts/menus.py b/backend/apps/accounts/menus.py index dda8e22..6017663 100644 --- a/backend/apps/accounts/menus.py +++ b/backend/apps/accounts/menus.py @@ -15,9 +15,18 @@ class MenuSpec: DEFAULT_MENUS: tuple[MenuSpec, ...] = ( - MenuSpec("workbench", "工作台", icon="home", sort_order=10), - MenuSpec("workbench.overview", "运营总览", "#/", "home", "workbench", 10), - MenuSpec("business", "业务处理", icon="ticket", sort_order=20), + MenuSpec("workbench", "工作台", "#/", "home", sort_order=10), + MenuSpec( + "workbench.overview", + "运营总览", + "#/", + "home", + "workbench", + 10, + is_visible=False, + is_enabled=False, + ), + MenuSpec("business", "工单", icon="ticket", sort_order=20), MenuSpec("business.tickets", "工单中心", "#/tickets", "ticket", "business", 10, "ticket.view"), MenuSpec( "business.ticket_create", @@ -28,33 +37,42 @@ DEFAULT_MENUS: tuple[MenuSpec, ...] = ( 20, "ticket.create", ), - MenuSpec( - "business.solutions", - "解决方案库", - "#/solutions", - "library", - "business", - 30, - "solution.view", - ), - MenuSpec("platform", "平台能力", icon="bot", sort_order=30), + MenuSpec("knowledge", "知识与方案", icon="book_open", sort_order=30), MenuSpec( "platform.knowledge", "知识库", "#/knowledge", "database", - "platform", + "knowledge", 10, "knowledge.view", - is_enabled=False, ), + MenuSpec( + "knowledge.search", + "知识检索", + "#/knowledge/search", + "search", + "knowledge", + 20, + "knowledge.view", + ), + MenuSpec( + "business.solutions", + "解决方案库", + "#/solutions", + "library", + "knowledge", + 30, + "solution.view", + ), + MenuSpec("platform", "AI 平台", icon="bot", sort_order=40), MenuSpec( "platform.agents", "Agent 配置", "#/agents", "bot", "platform", - 20, + 10, "agent.manage", ), MenuSpec( @@ -63,7 +81,7 @@ DEFAULT_MENUS: tuple[MenuSpec, ...] = ( "#/modelhub/providers", "settings", "platform", - 30, + 20, "model.manage", ), MenuSpec( @@ -72,7 +90,7 @@ DEFAULT_MENUS: tuple[MenuSpec, ...] = ( "#/skills", "settings", "platform", - 40, + 30, "skill.manage", ), MenuSpec( @@ -81,10 +99,10 @@ DEFAULT_MENUS: tuple[MenuSpec, ...] = ( "#/agent-runs", "audit", "platform", - 50, + 40, "agent.run.view", ), - MenuSpec("system", "系统治理", icon="shield", sort_order=40), + MenuSpec("system", "系统治理", icon="shield", sort_order=50), MenuSpec( "system.users", "用户管理", "#/system/users", "users", "system", 10, "system.user.view" ), diff --git a/backend/apps/accounts/migrations/0002_reorganize_navigation_menus.py b/backend/apps/accounts/migrations/0002_reorganize_navigation_menus.py new file mode 100644 index 0000000..e1d8d74 --- /dev/null +++ b/backend/apps/accounts/migrations/0002_reorganize_navigation_menus.py @@ -0,0 +1,258 @@ +from django.db import migrations + +NEW_MENUS = ( + ("workbench", "工作台", "#/", "home", "", 10, "", True, True), + ("workbench.overview", "运营总览", "#/", "home", "workbench", 10, "", False, False), + ("business", "工单", "", "ticket", "", 20, "", True, True), + ( + "business.tickets", + "工单中心", + "#/tickets", + "ticket", + "business", + 10, + "ticket.view", + True, + True, + ), + ( + "business.ticket_create", + "创建工单", + "#/tickets/new", + "briefcase", + "business", + 20, + "ticket.create", + True, + True, + ), + ("knowledge", "知识与方案", "", "book_open", "", 30, "", True, True), + ( + "platform.knowledge", + "知识库", + "#/knowledge", + "database", + "knowledge", + 10, + "knowledge.view", + True, + True, + ), + ( + "knowledge.search", + "知识检索", + "#/knowledge/search", + "search", + "knowledge", + 20, + "knowledge.view", + True, + True, + ), + ( + "business.solutions", + "解决方案库", + "#/solutions", + "library", + "knowledge", + 30, + "solution.view", + True, + True, + ), + ("platform", "AI 平台", "", "bot", "", 40, "", True, True), + ( + "platform.agents", + "Agent 配置", + "#/agents", + "bot", + "platform", + 10, + "agent.manage", + True, + True, + ), + ( + "platform.models", + "模型渠道", + "#/modelhub/providers", + "settings", + "platform", + 20, + "model.manage", + True, + True, + ), + ( + "platform.skills", + "Skill 配置", + "#/skills", + "settings", + "platform", + 30, + "skill.manage", + True, + True, + ), + ( + "platform.agent_runs", + "运行记录", + "#/agent-runs", + "audit", + "platform", + 40, + "agent.run.view", + True, + True, + ), + ("system", "系统治理", "", "shield", "", 50, "", True, True), +) + +OLD_MENUS = ( + ("workbench", "工作台", "", "home", "", 10, "", True, True), + ("workbench.overview", "运营总览", "#/", "home", "workbench", 10, "", True, True), + ("business", "业务处理", "", "ticket", "", 20, "", True, True), + ( + "business.tickets", + "工单中心", + "#/tickets", + "ticket", + "business", + 10, + "ticket.view", + True, + True, + ), + ( + "business.ticket_create", + "创建工单", + "#/tickets/new", + "briefcase", + "business", + 20, + "ticket.create", + True, + True, + ), + ( + "business.solutions", + "解决方案库", + "#/solutions", + "library", + "business", + 30, + "solution.view", + True, + True, + ), + ("platform", "平台能力", "", "bot", "", 30, "", True, True), + ( + "platform.knowledge", + "知识库", + "#/knowledge", + "database", + "platform", + 10, + "knowledge.view", + True, + False, + ), + ( + "platform.agents", + "Agent 配置", + "#/agents", + "bot", + "platform", + 20, + "agent.manage", + True, + True, + ), + ( + "platform.models", + "模型渠道", + "#/modelhub/providers", + "settings", + "platform", + 30, + "model.manage", + True, + True, + ), + ( + "platform.skills", + "Skill 配置", + "#/skills", + "settings", + "platform", + 40, + "skill.manage", + True, + True, + ), + ( + "platform.agent_runs", + "运行记录", + "#/agent-runs", + "audit", + "platform", + 50, + "agent.run.view", + True, + True, + ), + ("system", "系统治理", "", "shield", "", 40, "", True, True), +) + + +def apply_menu_specs(apps, specs): + menu_item = apps.get_model("accounts", "MenuItem") + menus_by_code = {} + for ( + code, + title, + path, + icon, + parent_code, + sort_order, + permission_code, + is_visible, + is_enabled, + ) in specs: + parent = menus_by_code.get(parent_code) + if parent is None and parent_code: + parent = menu_item.objects.filter(code=parent_code).first() + menu, _ = menu_item.objects.update_or_create( + code=code, + defaults={ + "title": title, + "path": path, + "icon": icon, + "parent": parent, + "sort_order": sort_order, + "permission_code": permission_code, + "is_visible": is_visible, + "is_enabled": is_enabled, + }, + ) + menus_by_code[code] = menu + + +def forwards(apps, schema_editor): + apply_menu_specs(apps, NEW_MENUS) + + +def backwards(apps, schema_editor): + apply_menu_specs(apps, OLD_MENUS) + menu_item = apps.get_model("accounts", "MenuItem") + menu_item.objects.filter(code="knowledge.search").delete() + knowledge = menu_item.objects.filter(code="knowledge").first() + if knowledge is not None: + knowledge.children.update(parent=None) + knowledge.delete() + + +class Migration(migrations.Migration): + dependencies = [("accounts", "0001_initial")] + + operations = [migrations.RunPython(forwards, backwards)] diff --git a/backend/apps/accounts/tests/test_bootstrap_governance.py b/backend/apps/accounts/tests/test_bootstrap_governance.py index 3409ec3..0ac4cb1 100644 --- a/backend/apps/accounts/tests/test_bootstrap_governance.py +++ b/backend/apps/accounts/tests/test_bootstrap_governance.py @@ -21,6 +21,21 @@ def test_bootstrap_governance_seeds_admin_roles_groups_permissions_and_menus(db, assert UserGroup.objects.filter(code="default").exists() assert MenuItem.objects.filter(code="system.users", title="用户管理").exists() assert MenuItem.objects.filter(code="system.roles", permission_code="system.role.view").exists() + assert MenuItem.objects.filter(code="workbench", path="#/", parent=None).exists() + assert MenuItem.objects.filter( + code="workbench.overview", is_visible=False, is_enabled=False + ).exists() + assert MenuItem.objects.filter(code="business", title="工单", sort_order=20).exists() + knowledge = MenuItem.objects.get(code="knowledge") + assert knowledge.title == "知识与方案" + assert list(knowledge.children.order_by("sort_order").values_list("code", flat=True)) == [ + "platform.knowledge", + "knowledge.search", + "business.solutions", + ] + assert MenuItem.objects.filter(code="platform.knowledge", is_enabled=True).exists() + assert MenuItem.objects.filter(code="platform", title="AI 平台", sort_order=40).exists() + assert MenuItem.objects.filter(code="system", sort_order=50).exists() def test_bootstrap_governance_migrates_legacy_english_roles(db, settings):