286 lines
13 KiB
Markdown
286 lines
13 KiB
Markdown
# 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` 补充「门户布局」章节(若需长期规范)。
|