Files
shanxia2.0/docs/superpowers/specs/2026-06-20-web-admin-portal-layout-design.md
T
2026-06-21 09:19:07 +08:00

13 KiB
Raw Blame History

web-admin 门户化布局改造 — 设计文档

日期: 2026-06-20
状态: 已实现(2026-06-20)
范围: web-admin 管理端框架(布局 + 菜单展示 + 权限联动)
UI 规范: docs/web-admin-ui-spec-fresh-mint.md(主色 #10b981、Fresh Mint Token)

目标

将 web-admin 从「左侧全量菜单 + 顶栏工具条」改为 一体化门户布局:

  1. 顶栏展示 Logo、「一体化门户」、6 个一级模块卡片(icon 上 / 名称下),选中态绿底白字。
  2. 下方分左右:左侧为当前模块的二/三级菜单;右侧为 WorkTab + 内容区。
  3. 移除顶栏的菜单折叠、面包屑、刷新按钮;移除【控制台】一级菜单。
  4. 一级 / 二级 / 三级菜单仍按角色与 menuCode 权限过滤显示。

已确认决策

# 决策 说明
D1 实现方式 新增 MenuTypeEnum.PORTAL 专用布局模式(方案 A),不魔改 TOP_LEFT / DUAL_MENU
D2 权限边界(0/1 模块) 始终保留顶栏卡片区域:0 个可见模块时展示「暂无可用模块」空态;1 个模块时仍展示 1 张卡片
D3 一级菜单清单 CRM 管理、报销管理、地磅管理、运输管理、工作流管理、系统管理(共 6 个,不含控制台)
D4 一级展示顺序 CRM → 报销 → 地磅 → 运输 → 工作流 → 系统(前端常量排序,不依赖路由文件注册顺序)
D5 控制台 从侧栏与顶栏卡片中移除;默认首页改为第一个有权限模块的首个可访问叶子页
D6 顶栏右侧 保留用户菜单;全屏按钮保留;折叠 / 面包屑 / 刷新移除
D7 侧栏 去掉 Logo 与「一体化门户」品牌区;去掉顶栏式折叠 icon;侧栏本身不新增折叠按钮(固定展开,宽度沿用 menuOpenWidth 默认 230px)
D8 OpenSpec 侧栏 icon 一级卡片有 icon;左侧二/三级菜单仍遵守「仅一级有 icon、更深层仅文字」(SidebarSubmenu 现有 level === 0 规则)

非目标(本期不做)

  • 设置面板中保留/切换 Left、Top、Mixed、Dual 等旧布局(PORTAL 为唯一产品布局,设置项可隐藏或锁定)
  • 小程序端布局改造
  • 权限后端 API 改造(沿用 MenuProcessor + fetchGetMenuCodes)
  • 移动端完整适配(本期仅保证 <800px 不严重错位;横滑卡片 + 抽屉侧栏可作为 follow-up)
  • Demo 菜单独立提升为一级模块

一、目标布局

┌────────────────────────────────────────────────────────────────────────┐
│ [Logo] 一体化门户    [CRM] [报销] [地磅] [运输] [工作流] [系统]    [用户] │  ← ArtPortalHeader(全宽)
│                       ↑ 卡片:icon 上 / 名称下;选中 #10b981 底 + 白字      │
├──────────────┬─────────────────────────────────────────────────────────┤
│ 二级 / 三级   │ ArtWorkTab(标签页)                                       │
│ 菜单树       ├─────────────────────────────────────────────────────────┤
│ ArtPortal    │ ArtPageContent(业务页面)                                 │
│ Sidebar      │                                                         │
└──────────────┴─────────────────────────────────────────────────────────┘

DOM 结构(views/index/index.vue)

.app-layout-portal
├── #app-portal-header     → ArtPortalHeader
└── #app-portal-body       → flex row
    ├── #app-sidebar       → ArtPortalSidebar(改造 art-sidebar-menu)
    └── #app-workspace     → flex column
        ├── #app-worktab   → ArtWorkTab(从 art-header-bar 迁出)
        └── #app-content   → ArtPageContent

二、一级模块卡片(ArtPortalTopNav)

2.1 数据来源

  • 输入:menuStore.menuList 经 门户一级过滤器 处理后的列表。
  • 过滤器职责:
    1. 排除控制台(path === '/dashboard' 或 meta.title === '控制台')。
    2. 排除 meta.isHide === true 的项。
    3. 按 D4 常量顺序排序。
    4. 若项无可见子节点且自身不可导航 → 不渲染卡片(与 MenuProcessor.filterEmptyMenus 结果一致)。

2.2 卡片 UI

属性 值
布局 纵向 flex,居中;icon 在上(20–24px),标题在下(12–13px)
间距 卡片之间 gap: 8–12px;卡片内 padding 约 8px 12px
圆角 8px(与规范按钮/输入圆角一致)
默认 透明底;icon/文字 --text / --text-muted
选中 background: var(--primary);icon 与文字 #fff
激活判定 复用 ArtMixedMenu.isMenuItemActive:当前路由(或 meta.activePath)落在该模块子树内

2.3 交互

  • 点击卡片:router.push(module.redirect || firstAccessibleChildPath(module))。
  • 若当前路由已属于该模块:仅更新选中态,不强制跳转。
  • 0 个可见模块:顶栏卡片区展示 muted 文案「暂无可用模块」(不隐藏顶栏)。
  • 1 个可见模块:仍展示 1 张卡片(D2)。

2.4 一级模块与路由前缀映射

卡片名称 路由 path 前缀 路由模块
CRM 管理 /crm sqxp.ts
报销管理 /bx sqxp.ts
地磅管理 /db sqxp.ts
运输管理 /pl pl.ts
工作流管理 /workflow sqxp.ts
系统管理 /system sqxp.ts

三、左侧菜单(ArtPortalSidebar)

3.1 渲染范围

  • 仅渲染 当前激活一级模块 的 children(二/三级)。
  • 激活模块解析:const top = '/' + route.path.split('/')[1],在过滤后的一级列表中匹配。
  • iframe 路由:沿用 art-sidebar-menu 现有 findIframeMenuList 逻辑。

3.2 移除内容

  • 侧栏 header 区(Logo + 系统名)。
  • 双列菜单 / 折叠按钮 / menu-model 遮罩(PORTAL 模式不启用 DUAL_MENU / LEFT 分支)。
  • 顶栏菜单折叠联动(visibleMenu / menuOpen 切换对 PORTAL 无 UI 入口;menuOpen 保持 true)。

3.3 子菜单组件

  • 继续复用 SidebarSubmenu + filterSidebarRoutes。
  • ElMenu 默认展开:保留现有 syncExpandedMenus / defaultOpenedMenus 逻辑。

四、顶栏(ArtPortalHeader)

4.1 左侧

  • ArtLogo(点击跳转默认首页,见 §五)。
  • 文案「一体化门户」(AppConfig.systemInfo.name,已为该值)。

4.2 中间

  • ArtPortalTopNav(flex-1,卡片可横向滚动;模块多时可加 ElScrollbar)。

4.3 右侧

  • 全屏按钮(可选保留)。
  • ArtUserMenu。
  • 不渲染:折叠、刷新、面包屑、快速入口、通知、语言、主题切换(与现 header 隐藏项一致)。

4.4 WorkTab 迁移

  • 从 art-header-bar/index.vue 移除 <ArtWorkTab />。
  • 挂载到 #app-workspace 顶部(ArtWorkTab 组件本身不改业务逻辑)。
  • 样式:worktab-strip 的 mb-3 与 workspace padding 对齐 Fresh Mint 内容区 rhythm。

五、菜单数据与权限

5.1 现有链路(保持不变)

beforeEach → MenuProcessor.getMenuList()
           → filterMenuByRoles / filterMenuByCodes
           → filterEmptyMenus
           → menuStore.setMenuList
           → RouteRegistry.register

5.2 前端增强

位置 增强
MenuProcessor.processFrontendMenu 过滤掉 Dashboard / 控制台节点
新建 utils/router/portal-menu.ts PORTAL_TOP_MODULE_ORDER、filterPortalTopModules()、resolveActivePortalModule()、getFirstAccessiblePath()
menuStore.setMenuList 设置 homePath 时跳过 /dashboard,使用 getFirstSecondLevelMenuPath(已有)

5.3 三级权限行为

层级 机制
一级卡片 MenuProcessor 输出 + filterPortalTopModules;filterMenuByCodes level=1 保留「有可见子节点」的父级
二级 filterSidebarRoutes
三级 SidebarSubmenu 递归 + filterSidebarRoutes

5.4 后端菜单(backend 模式)

  • SQL 隐藏或删除 Dashboard 对应 sys_menu 记录(与前端路由同步)。
  • 确认 6 个一级菜单在 sys_menu 中 parent_id 指向门户 Web 根节点;运输管理已更名见 docs/sql/20260620_pl_menu_rename_hide.sql。
  • 新增迁移脚本:docs/sql/20260620_portal_hide_dashboard.sql(建议)。

六、配置与枚举

文件 变更
enums/appEnum.ts 新增 MenuTypeEnum.PORTAL = 'portal'
config/setting.ts 默认 menuType: MenuTypeEnum.PORTAL;showMenuButton/showRefreshButton/showCrumbs: false
config/modules/headerBar.ts menuButton/refreshButton/breadcrumb.enabled: false
store/modules/setting.ts 支持 PORTAL 分支(若 layout 判断分散在各组件,统一用 isPortalLayout computed)
views/index/index.vue PORTAL 时使用新 DOM 结构;旧 LEFT 结构可保留供模板升级对比或后续删除

七、路由与首页

7.1 控制台处理

  • sqxp.ts:Dashboard 路由设 meta.isHide: true 或整段注释/删除(与 SQL 同步)。
  • 登录后默认跳转:第一个有权限模块的首个叶子页(如 /crm/...)。

7.2 路由顺序

  • routeModules 合并顺序不影响 UI(由 PORTAL_TOP_MODULE_ORDER 控制)。
  • 文档注释更新:sqxp.ts 头部说明去掉「控制台」。

八、样式要点

  • 顶栏高度:建议 64–72px(略高于现 h-15 以容纳卡片)。
  • 顶栏背景:var(--default-bg-color) / 白底 + 底部分割线 var(--art-card-border)。
  • 一级卡片选中色:var(--primary) #10b981,勿使用小程序色 #0a9f6d。
  • 下方 body:height: calc(100vh - 顶栏高度);workspace 内容区 padding 沿用 --mint-content-padding。
  • 侧栏宽度:230px(menuOpenWidth 默认值)。

九、测试计划

场景 预期
super_admin 6 张卡片 + 对应侧栏全量
admin 仅有 bx 权限 顶栏仅 1 张「报销管理」卡片;侧栏仅 bx 子菜单
admin 无任何业务 menuCode 顶栏卡片区显示「暂无可用模块」
点击 CRM 卡片 路由进入 CRM 首个可访问页;卡片选中;侧栏切换为 CRM 树
从 CRM 页内跳转 bx 页 顶栏选中态自动切到报销
直接 URL 访问 /pl/plan 运输卡片选中;侧栏为 pl 子树
控制台 /dashboard 不可从菜单进入;直接访问按路由守卫处理(404 或重定向首页)
WorkTab 开/关/切换标签正常;位置在内容区上方
侧栏二/三级 无 icon,仅文字(OpenSpec)

十、影响文件清单

新建

  • components/core/layouts/art-portal-header/index.vue
  • components/core/layouts/art-portal-top-nav/index.vue
  • utils/router/portal-menu.ts
  • docs/sql/20260620_portal_hide_dashboard.sql(建议)

修改

  • views/index/index.vue、views/index/style.scss
  • components/core/layouts/art-menus/art-sidebar-menu/index.vue(PORTAL 分支)
  • components/core/layouts/art-header-bar/index.vue(移除 WorkTab;或 PORTAL 下不再使用此组件)
  • enums/appEnum.ts、config/setting.ts、config/modules/headerBar.ts
  • router/core/MenuProcessor.ts
  • router/modules/sqxp.ts

可选

  • components/core/layouts/art-settings-panel:隐藏菜单布局切换或锁定 PORTAL

十一、风险

  1. WorkTab 样式错位:迁移后需目视检查 tab-card / tab-google 两种 tabStyle。
  2. 跨模块 deep link:书签直达子页时,顶栏选中态依赖 isMenuItemActive,需覆盖 meta.activePath。
  3. 模板升级:Art Design Pro 上游更新 layout 时,PORTAL 为独立分支,合并冲突集中在 index.vue。
  4. 窄屏:6 卡片可能溢出,顶栏需横向滚动;侧栏 <800px 现有 fixed 策略待 follow-up。

十二、后续(非本期)

  • 移动端:顶栏卡片横滑 + 侧栏抽屉。
  • 设置面板清理旧 layout 选项。
  • OpenSpec ui-conventions 补充「门户布局」章节(若需长期规范)。