# 菜单结构调整实现计划 > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** 将 14 个一级菜单重组为 5 个一级菜单(市场、生产、质检、运营支撑、系统管理),新增菜单记录到 sys_menu 表并支持角色权限控制。 **Architecture:** 采用方案 A(一级菜单独立权限),每个新一级菜单设置独立 `perms`(如 `menu:market`),前端改造菜单组件支持两级菜单结构(顶部一级 + 左侧二级),后端同步改造菜单接口。 **Tech Stack:** Vue 3 + Element Plus + Pinia + FastAPI + SQLAlchemy --- ## 变更范围总览 | 层级 | 文件 | 变更类型 | |------|------|----------| | 前端路由 | `web-admin/src/router/modules/sqxp.ts` | 结构调整 | | 前端菜单组件 | `web-admin/src/components/core/layouts/art-menus/*` | 支持两级结构 | | 前端状态 | `web-admin/src/store/modules/menu.ts`, `setting.ts` | 新增一级菜单状态 | | 后端菜单接口 | `backend/app/api/menu.py` | 新增一级菜单数据 | | 后端权限服务 | `backend/app/services/web_auth_roles.py` | 支持一级菜单权限过滤 | | 数据库 | `sys_menu` 表 | 新增 5 个一级菜单记录 | --- ## Task 1: 后端 - 更新菜单接口数据 **Files:** - Modify: `backend/app/api/menu.py:10-773` - [ ] **Step 1: 添加新一级菜单定义** 在 `STATIC_MENU_TREE` 开头添加 5 个新一级菜单: ```python # 新增一级菜单定义(放在 STATIC_MENU_TREE 最前面) TOP_MENU_MARKET = { "id": "TOP00000000000000000000000000001", "name": "MarketTop", "path": "/market", "component": "/index/index", "meta": { "title": "市场", "icon": "ri:shopping-cart-line", "keepAlive": False, "isTopMenu": True, "menuCode": "menu:market", }, "children": [ # 细胞存储、科研捐赠、中试服务、基础实验、市场基础信息、临床应用 ], } TOP_MENU_PRODUCTION = { "id": "TOP00000000000000000000000000002", "name": "ProductionTop", "path": "/production-group", "component": "/index/index", "meta": { "title": "生产", "icon": "ri:factory-line", "keepAlive": False, "isTopMenu": True, "menuCode": "menu:production", }, "children": [ # 生产管理、生产基础信息 ], } TOP_MENU_QUALITY = { "id": "TOP00000000000000000000000000003", "name": "QualityTop", "path": "/quality-group", "component": "/index/index", "meta": { "title": "质检", "icon": "ri:shield-check-line", "keepAlive": False, "isTopMenu": True, "menuCode": "menu:quality", }, "children": [ # 质检管理、质检基础信息 ], } TOP_MENU_OPERATIONS = { "id": "TOP00000000000000000000000000004", "name": "OperationsTop", "path": "/operations-group", "component": "/index/index", "meta": { "title": "运营支撑", "icon": "ri:settings-3-line", "keepAlive": False, "isTopMenu": True, "menuCode": "menu:operations", }, "children": [ # 系统基础信息、运营支撑 ], } TOP_MENU_SYSTEM = { "id": "TOP00000000000000000000000000005", "name": "SystemTop", "path": "/system-manage", "component": "/index/index", "meta": { "title": "系统管理", "icon": "ri:server-line", "keepAlive": False, "isTopMenu": True, "menuCode": "menu:system-manage", }, "children": [ # 系统管理、工作流管理 ], } ``` - [ ] **Step 2: 调整原有菜单到新父级下** 将现有 14 个一级菜单作为二级菜单,重新分配 parent_id 和 path: | 原菜单 | 新父级 | 新 path | |--------|--------|---------| | 细胞存储 | TOP00000000000000000000000000001 | `/market/cell-storage` | | 科研捐赠 | TOP00000000000000000000000000001 | `/market/research-donation` | | 中试服务 | TOP00000000000000000000000000001 | `/market/pilot-service` | | 基础实验 | TOP00000000000000000000000000001 | `/market/basic-experiment` | | 市场基础信息 | TOP00000000000000000000000000001 | `/market/market-info` | | 临床应用 | TOP00000000000000000000000000002 | `/production-group/clinical-application` | | 生产管理 | TOP00000000000000000000000000002 | `/production-group/production` | | 生产基础信息 | TOP00000000000000000000000000002 | `/production-group/production-base` | | 质检管理 | TOP00000000000000000000000000003 | `/quality-group/quality-manage` | | 质检基础信息 | TOP00000000000000000000000000003 | `/quality-group/quality-base` | | 系统基础信息 | TOP00000000000000000000000000004 | `/operations-group/system-base` | | 运营支撑 | TOP00000000000000000000000000004 | `/operations-group/operations` | | 系统管理 | TOP00000000000000000000000000005 | `/system-manage/system` | | 工作流管理 | TOP00000000000000000000000000005 | `/system-manage/workflow` | - [ ] **Step 3: 更新 STATIC_MENU_TREE 结构** 将 STATIC_MENU_TREE 改为只包含 5 个新一级菜单,每个一级菜单的 children 包含对应的原菜单作为二级菜单。 - [ ] **Step 4: Commit** ```bash git add backend/app/api/menu.py git commit -m "feat(menu): 重构菜单为5个一级分组菜单结构" ``` --- ## Task 2: 后端 - 更新权限服务支持一级菜单过滤 **Files:** - Modify: `backend/app/services/web_auth_roles.py` - [ ] **Step 1: 添加一级菜单权限码常量** ```python # 一级菜单权限码 TOP_MENU_PERMS = {"menu:market", "menu:production", "menu:quality", "menu:operations", "menu:system-manage"} ``` - [ ] **Step 2: 确保 iter_user_menu_perm_codes 返回一级菜单 perms** 当前 `iter_user_menu_perm_codes` 通过 `sys_role_menu → sys_menu` 查询用户拥有的菜单权限。一级菜单的 `perms`(如 `menu:market`)已经在 sys_menu 表中定义,因此无需修改查询逻辑。只需确保 sys_menu 表中有这 5 个一级菜单的记录(Task 3 处理)。 - [ ] **Step 3: Commit** ```bash git add backend/app/services/web_auth_roles.py git commit -m "feat(auth): 支持一级菜单权限码过滤" ``` --- ## Task 3: 数据库 - 插入一级菜单数据到 sys_menu **Files:** - Create: `docs/sql/menu_restructuring.sql` - [ ] **Step 1: 编写 SQL 插入脚本** 创建 SQL 脚本,包含 5 个一级菜单的 INSERT 语句(menu_type = 'M' 表示目录): ```sql -- 一级菜单 INSERT INTO sys_menu (id, menu_name, parent_id, menu_type, path, component, perms, is_frame, visible, status, tenant_no, order_num, create_by, create_dept_id, create_time, update_by, update_time, del_flag) VALUES ('TOP00000000000000000000000000001', '市场', '0', 'M', '/market', '/index/index', 'menu:market', 1, '1', '1', 'zkxw', 1, 'system', '', NOW(), 'system', NOW(), 0), ('TOP00000000000000000000000000002', '生产', '0', 'M', '/production-group', '/index/index', 'menu:production', 1, '1', '1', 'zkxw', 2, 'system', '', NOW(), 'system', NOW(), 0), ('TOP00000000000000000000000000003', '质检', '0', 'M', '/quality-group', '/index/index', 'menu:quality', 1, '1', '1', 'zkxw', 3, 'system', '', NOW(), 'system', NOW(), 0), ('TOP00000000000000000000000000004', '运营支撑', '0', 'M', '/operations-group', '/index/index', 'menu:operations', 1, '1', '1', 'zkxw', 4, 'system', '', NOW(), 'system', NOW(), 0), ('TOP00000000000000000000000000005', '系统管理', '0', 'M', '/system-manage', '/index/index', 'menu:system-manage', 1, '1', '1', 'zkxw', 5, 'system', '', NOW(), 'system', NOW(), 0); ``` - [ ] **Step 2: Commit** ```bash git add docs/sql/menu_restructuring.sql git commit -m "feat(db): 添加5个一级菜单到sys_menu表" ``` --- ## Task 4: 前端 - 改造 sqxp.ts 路由结构 **Files:** - Modify: `web-admin/src/router/modules/sqxp.ts:1-1264` - [ ] **Step 1: 添加新一级菜单定义** 在文件开头添加 5 个新一级菜单(与后端对应): ```typescript // 新一级菜单 const MARKET_TOP_MENU: AppRouteRecord = { id: 'TOP00000000000000000000000000001', name: 'MarketTop', path: '/market', component: '/index/index', meta: { title: '市场', icon: 'ri:shopping-cart-line', keepAlive: false, isTopMenu: true, roles: ['admin'], menuCode: 'menu:market' }, children: [ // 细胞存储、科研捐赠、中试服务、基础实验、市场基础信息、临床应用 ] } const PRODUCTION_TOP_MENU: AppRouteRecord = { id: 'TOP00000000000000000000000000002', name: 'ProductionTop', path: '/production-group', component: '/index/index', meta: { title: '生产', icon: 'ri:factory-line', keepAlive: false, isTopMenu: true, roles: ['admin'], menuCode: 'menu:production' }, children: [ // 临床应用、生产管理、生产基础信息 ] } const QUALITY_TOP_MENU: AppRouteRecord = { id: 'TOP00000000000000000000000000003', name: 'QualityTop', path: '/quality-group', component: '/index/index', meta: { title: '质检', icon: 'ri:shield-check-line', keepAlive: false, isTopMenu: true, roles: ['admin'], menuCode: 'menu:quality' }, children: [ // 质检管理、质检基础信息 ] } const OPERATIONS_TOP_MENU: AppRouteRecord = { id: 'TOP00000000000000000000000000004', name: 'OperationsTop', path: '/operations-group', component: '/index/index', meta: { title: '运营支撑', icon: 'ri:settings-3-line', keepAlive: false, isTopMenu: true, roles: ['admin'], menuCode: 'menu:operations' }, children: [ // 系统基础信息、运营支撑 ] } const SYSTEM_TOP_MENU: AppRouteRecord = { id: 'TOP00000000000000000000000000005', name: 'SystemTop', path: '/system-manage', component: '/index/index', meta: { title: '系统管理', icon: 'ri:server-line', keepAlive: false, isTopMenu: true, roles: ['admin'], menuCode: 'menu:system-manage' }, children: [ // 系统管理、工作流管理 ] } ``` - [ ] **Step 2: 将原有 14 个菜单作为二级菜单移动到对应一级菜单下** 将细胞存储、科研捐赠、中试服务、基础实验、市场基础信息移到 MARKET_TOP_MENU.children 下; 将临床应用移到 PRODUCTION_TOP_MENU.children 下; 以此类推。 - [ ] **Step 3: 更新 export 导出** 将 sqxpAdminRoutes 改为只包含 5 个新一级菜单。 - [ ] **Step 4: Commit** ```bash git add web-admin/src/router/modules/sqxp.ts git commit -m "feat(router): 重构路由为5个一级菜单分组" ``` --- ## Task 5: 前端 - 改造菜单组件支持两级结构 **Files:** - Modify: `web-admin/src/components/core/layouts/art-menus/art-horizontal-menu/index.vue` - Modify: `web-admin/src/components/core/layouts/art-menus/art-mixed-menu/index.vue` - Modify: `web-admin/src/components/core/layouts/art-menus/art-sidebar-menu/index.vue` - [ ] **Step 1: 识别当前活跃的一级菜单** 新增逻辑:根据当前路由路径判断所属的一级菜单,提取出 `activeTopMenuId`。 ```typescript // 在组件中添加 computed const activeTopMenuId = computed(() => { const path = route.path // 从路径中提取一级菜单 path,如 /market/cell-storage → /market const topPath = '/' + path.split('/')[1] return topPath }) ``` - [ ] **Step 2: 分离一级菜单和二级菜单数据** ```typescript // 过滤出一级菜单(isTopMenu: true) const topMenus = computed(() => { return props.list.filter(item => item.meta?.isTopMenu) }) // 根据活跃的一级菜单获取二级菜单 const subMenus = computed(() => { const active = topMenus.value.find(item => item.path === activeTopMenuId.value) return active?.children || [] }) ``` - [ ] **Step 3: 修改模板** 水平菜单只显示一级菜单,点击后更新 activeTopMenuId,并触发侧边栏显示对应的二级菜单。 - [ ] **Step 4: Commit** ```bash git add web-admin/src/components/core/layouts/art-menus/art-horizontal-menu/index.vue git add web-admin/src/components/core/layouts/art-menus/art-mixed-menu/index.vue git commit -m "feat(menu): 改造顶部菜单支持两级结构" ``` --- ## Task 6: 前端 - 改造侧边栏组件 **Files:** - Modify: `web-admin/src/components/core/layouts/art-menus/art-sidebar-menu/index.vue` - [ ] **Step 1: 修改菜单列表计算逻辑** 当前 `menuList` computed 根据 `isTopLeftMenu` 或 `isDualMenu` 返回对应子菜单。改为: - 当存在活跃一级菜单时,返回该一级菜单的 children - 否则返回完整菜单列表(兼容一级菜单页面) ```typescript const menuList = computed(() => { const menuStore = useMenuStore() const allMenus = menuStore.menuList if (!isTopLeftMenu.value && !isDualMenu.value) { return allMenus } // 处理 iframe 路径 if (isIframe(route.path)) { return findIframeMenuList(route.path, allMenus) } // 一级菜单页面直接返回空 if (route.meta.isFirstLevel) { return [] } // 返回当前一级菜单的子菜单 const topPath = '/' + route.path.split('/')[1] const currentTopMenu = allMenus.find(menu => menu.meta?.isTopMenu && menu.path === topPath ) if (currentTopMenu?.children) { return currentTopMenu.children.filter((child: AppRouteRecord) => !child.meta?.isHide) } return [] }) ``` - [ ] **Step 2: Commit** ```bash git add web-admin/src/components/core/layouts/art-menus/art-sidebar-menu/index.vue git commit -m "feat(menu): 改造侧边栏显示二级菜单" ``` --- ## Task 7: 前端 - 更新菜单状态管理 **Files:** - Modify: `web-admin/src/store/modules/menu.ts` - Modify: `web-admin/src/store/modules/setting.ts` - [ ] **Step 1: 在 menu.ts 中添加活跃一级菜单状态** ```typescript /** 活跃的一级菜单路径 */ const activeTopMenuPath = ref('') /** 设置活跃一级菜单 */ const setActiveTopMenuPath = (path: string) => { activeTopMenuPath.value = path } ``` - [ ] **Step 2: Commit** ```bash git add web-admin/src/store/modules/menu.ts git commit -m "feat(store): 添加一级菜单活跃状态管理" ``` --- ## Task 8: 测试验证 - [ ] **Step 1: 启动后端服务** ```bash cd backend && ./start-local.sh ``` - [ ] **Step 2: 启动前端服务** ```bash cd web-admin && pnpm dev ``` - [ ] **Step 3: 验证菜单显示** 1. 登录管理端 2. 检查顶部是否显示 5 个一级菜单 3. 点击一级菜单,检查左侧是否显示对应的二级菜单 4. 验证权限控制:没有 `menu:market` 权限的角色不应看到「市场」菜单 - [ ] **Step 4: Commit** ```bash git add -A git commit -m "test: 验证菜单结构调整功能" ``` --- ## 执行方式 **Two execution options:** **1. Subagent-Driven (recommended)** - I dispatch a fresh subagent per task, review between tasks, fast iteration **2. Inline Execution** - Execute tasks in this session using executing-plans, batch execution with checkpoints **Which approach?**