Files
LokiStack/docs/web-ui-guide/05-布局系统与导航设计.md
T
logan f9c6c1d826 feat: opsx-loki 全面升级 — 前端重构/用户与LDAP/部署向导/日志查询
基于 WEB-UI-Development-Guide 标准的整体升级,并更名 LokiDeploy → opsx-loki。

前端(Gin+React+shadcn/ui):
- 按 02/07 章重构:页面域化拆分(无超 400 行文件)、PageContainer/ListQuery、
  反馈分级(成功静默/失败 toast/危险确认)、401 单飞刷新+队列重放
- 暗色模式(next-themes)+ 语义 Token(--primary 品牌色/success/warning/info)
- 部署向导(状态推导四步:环境→存储→Loki→采集,内嵌表单闭环)
- 日志查询页:LogQL 标签构建器/拖拽直方图/日志上下文/Live Tail/查询历史
- 按用户+标签策略的查询授权(服务端强制合并策略)

后端(Go+Gin+JSON DB):
- 简单用户管理(仅 admin,无 RBAC)+ TokenVersion 会话吊销 + 登录 IP 限流
- LDAP 接入:配置(AES 加密存储/hasPassword 脱敏)/测试连接/批量导入/登录
- 存储配置测试连接(SigV4 零依赖)+ 桶不存在自动创建
- Loki 三模式部署修复:SSH 密钥认证、3.x 配置模板、ruler 对象存储嵌套块、
  凭证解密、孤儿 deploying 状态恢复、Grafana 部署(可选默认关)+面板导入
- DaemonSet 采集纯 YAML(去 helm 依赖)+ DNS 自愈回退 ClusterIP + 集群名标签
- 日志查询代理:cluster-svc 经 kube-apiserver proxy/url 直连 + cursor 翻页
- 统一 log 命名空间;部署就绪探活;Grafana 访问地址自动记录

修复:run.sh 增量编译检测、Sanitized 脱敏补全、LokiDeployment Update 白名单、
健康检查 CreatedAt 零值等 10+ 存量 bug。

数据兼容:DB 沿用旧 lokideploy.json(新名优先);localStorage 一次性迁移;
HKDF 加密前缀保留(已加密凭证不受影响)。
2026-10-24 13:20:12 +08:00

235 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 05 — 布局系统与导航设计
> 参考:vue-vben-admin(三层布局架构)、soybean-admin(layouts/modules 按功能拆分)、ant-design-pro(ProLayout 运行时配置)、vue-pure-admin(布局三模式);补充:gin-vue-admin(侧栏模式/标签页/水印)
---
## 一、布局的分层架构
### 1.1 vben 三层模型(理解布局复杂度的标尺)
```
┌─ 内核层 @core/ui-kit/layout-ui ──────────────────────┐
│ headless 布局引擎:40 个 props + defineModel │
│ (布局模式/头部模式/侧栏宽度折叠悬停),不认识 store │
├─ 业务层 effects/layouts ─────────────────────────────┤
│ 把 preferences 逐项映射为内核 props; │
│ 组装 15 个可插拔部件(面包屑/主题切换/搜索/锁屏…) │
├─ App 层 layouts/basic.vue ───────────────────────────┤
│ 只用插槽填内容(#user-dropdown #notification …) │
└──────────────────────────────────────────────────────┘
```
soybean 的同构做法:布局引擎抽成 `packages/materials`(AdminLayout/PageTab/SimpleScrollbar),`src/layouts/base-layout/` 只是配置消费者,`layouts/modules/global-*` 按功能拆分(header/sider/tab/breadcrumb/search/footer/theme-drawer)。pure 提供 vertical/horizontal/mix 三种布局模式运行时可切。
**设计要义**:布局引擎与业务解耦(内核不依赖状态库),布局模式是**运行时偏好**而非构建期选择。
### 1.2 单文件 Layout 的取舍(中小工程)
300 行左右的单文件 Layout(el-container 侧栏 + 顶栏 + main)对单布局产品是**正确选择**——不要为了架构美引入三层。分层触发条件:
- 出现第 2 种布局模式(如「无侧栏全屏监控大屏」)
- 布局配置需要用户可调(折叠宽度/头部固定/水印)
- 布局代码超过 500 行开始挤压可读性
无论哪种形态:**业务页挂在内容区(页面容器组件协议),禁止重写布局层**。
---
## 二、布局骨架与尺寸规范
### 2.1 管理端标准骨架
```
┌──────────────────────────────────────────────────────┐
│ Topbar 48px │ 页标题 · 面包屑 │ 暗色切换 · 用户下拉 │
├──────────┬───────────────────────────────────────────┤
│ Sidebar │ │
│ 220px │ main │
│ (折叠64) │ <router-view> │
│ │ PageContainer │
│ 分组: │ │
│ 按层定序 │ 页头(标题/描述/操作按钮) │
│ │ 内容卡片(24px 内边距) │
└──────────┴───────────────────────────────────────────┘
```
### 2.2 尺寸规范表(推荐值)
```
侧栏宽度 220px(折叠 64px,<1200px 自动折叠)
顶栏高度 48-56px
页面内边距 24px(紧凑模式 16px)
卡片间距 16px
卡片圆角 8px(--el-border-radius-base 级)
按钮/输入高度 32px(default size)
图标 16px 主图标 / 12px 辅助
正文字号 14px;辅助 12px;页面标题 18-20px
移动端断点 <768px 侧栏变覆盖式抽屉 + backdrop
```
### 2.3 卡片构成规范(视觉一致性的最小单位)
页面 = 卡片的组合,卡片写法全站统一:
```
构成 背景 bg-card + 描边 border-base 或 阴影 shadow-1(全站二选一,禁止混用)
内边距 20-24px;卡片内区块间距 16px;卡片之间间距 16px
标题区 卡片标题 16px/600 + 右侧操作区(同一基线对齐)
页头 页面标题 18-20px/600 + 副标题 13px 次要色;页头与内容区间距 16px
指标卡 数字 24-28px/600 + tabular-nums + 环比箭头(涨跌语义色,方向全站统一)
```
---
## 三、侧栏与导航
### 3.1 侧栏必备能力清单
| 能力 | 实现要点 | 出处 |
|------|----------|------|
| 折叠 | 图标态切换;`<1200px` 自动折叠;移动端强制抽屉 | gva/pure |
| 高亮 | 路由激活态;外链/iframe 用 `meta.activePath` 指回 | vben `activePath` |
| 分组 | 前端按 layer 分组 + 常量定序,服务端菜单为准 | 常见底座实现 |
| 图标 | icon 名是数据(菜单表字段),前端映射渲染 | gva/pure/soybean |
| 失败重试 | 菜单接口失败显示重试入口,不留空白 | 通行要求 |
| 外链 | `window.open` 新窗;不注册路由 | gva `link` |
### 3.2 可选演进:标签页(tabs)
功能完整参照(gva 280 行 / pure multiTags / vben tabs-ui):sessionStorage 持久化、tab key = `name + query + params`(同路由不同参数多开)、右键菜单(关左/关右/关其他)、中键关闭、首页不可关、`meta.closeTab` 不留痕;vben 再加 affixTab 固定、maxNumOfOpenTab 上限、拖拽排序。
**引入判断**:运维/排障类平台(多工位切换频繁)收益大;配置型后台收益小。做了标签页**必须**解决 keep-alive 联动(否则切 tab 丢状态)。
---
## 四、Keep-Alive 链路(做对了很隐形,做错了很诡异)
```
路由 meta.keepAlive: true
→ 页面组件 defineOptions({ name: 'UserList' }) ← 强约定!
→ layout 中 <keep-alive :include="cachedNames">
→ 刷新:keepAlive 页销毁重建 toggle;非缓存页跳隐藏 Reload 路由(gva 双轨)
```
**为什么必须 defineOptions name**:keep-alive 的 include 匹配的是**组件名**而非路由名。script setup 组件默认匿名,不写 name 缓存必然失效。gva/pure 以 Vite 插件扫描生成「路径→组件名」映射做校验——**推荐**「组件 name 与路由 name 同名」并用 lint 守住(`vue/name` 规则)。
pure 的补充经验:**三级以上路由拍平成二级**再注册(keep-alive 只对二级稳定生效,社区已知问题)。
---
## 五、页面模板(新页面从这里复制起步)
### 5.1 列表页(最高频模板)
```
┌─────────────────────────────────────────────────┐
│ PageContainer #header │
│ 批量删除 · 导入 · [+ 新增] ← 按钮级权限 │
├─────────────────────────────────────────────────┤
│ ListPage │
│ ├ filters slot:关键字/状态/日期筛选 [查询][重置] │
│ ├ el-table(操作列 fixed right,状态列 tag 化) │
│ └ el-pagination(10/30/50/100) │
├─────────────────────────────────────────────────┤
│ 对话框子组件:XxxFormDialog / ResetDialog / … │
└─────────────────────────────────────────────────┘
```
范式要点:
1. 页面只做「编排」:容器 + 列表组件 + 子组件组合,本身 ≤400 行
2. 数据获取走列表组件的 fetcher(内嵌「取消 + 版本号」双重防护,见 03 章)
3. 表单弹窗独立成 `components/XxxFormDialog.vue`,通过 props/emit 通信
4. 操作按钮逐个挂权限控制
### 5.2 详情/编辑页
```
┌─────────────────────────────────────────────┐
│ ← 返回 编辑用户 [保存] │
├─────────────────────────────────────────────┤
│ ┌─ 基本信息 ────────────────────────────┐ │
│ │ 分组卡片:descriptions 只读态 │ │
│ └───────────────────────────────────────┘ │
│ ┌─ 高级设置 ────────────────────────────┐ │
│ │ 表单区:危险操作独立分区(红色警示卡) │ │
│ └───────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
```
### 5.3 仪表盘页
```
┌─────────────────────────────────────────────┐
│ 4-6 张指标卡(数字 + 环比箭头) │
├──────────────────┬──────────────────────────┤
│ 折线图(趋势) │ 饼图/柱状(分布) │
├──────────────────┴──────────────────────────┤
│ 最近活动列表 / 快捷入口 │
└─────────────────────────────────────────────┘
```
图表规范:ECharts **按需引入**(`echarts/core` + 按需 register,**禁止**全量 import echarts);图表区懒加载 + loading 占位;WebSocket 实时图必须处理「组件卸载断开连接 + 重连退避」;图表色板从主题变量读取(见 06 章)。
### 5.4 空态页
图标 + 一句话 + 引导动作(如「模块未启用 → 查看启用步骤」)是「功能未开启」的统一形态。
---
## 六、响应式策略
| 断点 | 行为 |
|------|------|
| ≥1200px | 完整布局 |
| 768-1200px | 侧栏自动折叠为图标态 |
| <768px | 侧栏变覆盖式抽屉 + backdrop;表格横向滚动;弹窗宽度 90% |
实现参照(gva `hooks/responsive.js`、soybean 断点写回 store):resize 监听 + **100ms debounce** 写入全局 device 状态(`desktop | mobile`),布局组件只读状态不各自监听。弹窗移动端宽度走全局配置统一控制。
---
## 七、最佳实践清单
✅ **要做**
1. 业务页挂内容区(页面容器协议),**禁止重写 layout/**
2. 页面标题来自 `route.meta.title`,不硬编码
3. 可访问性:折叠钮/菜单项带 aria-label
4. 布局状态(折叠)持久化,key 纳入全局命名空间(见 08 章双端一致)
5. 路由切换动画统一一种(fade 150ms),`transition` 包 `router-view`
❌ **不要**
1. 不要在业务页写 fixed 定位的伪头部(与 Topbar 层级打架)
2. 不要侧栏菜单硬编码(数据源走菜单 store)
3. 不要绕过页面容器自造页面容器(内边距/面包屑/页头规范会失控)
4. 不要在移动端保留 hover-only 交互(用点击展开兜底)
5. 不要保留空目录和过期布局文档
---
## 八、AI 检查清单(对比目标工程逐项核对)
**P0**
1. 业务页面是否有绕过页面容器、直接改写布局层的代码?
2. 页面标题是否单源(meta.title)?硬编码标题清单列出
**P1**
3. 超过 500 行的 Layout / 超过 400 行的视图页面列出,并给拆分建议(参照 07 章)
4. keepAlive 链路是否完整(meta + defineOptions name + include)?
5. 响应式三断点行为是否齐全?弹窗移动端宽度是否有适配?
6. ECharts 是否按需引入?WebSocket 是否有卸载断开与重连退避?
**P2**
7. 是否值得引入标签页(多工位场景)?若引入,keep-alive 联动方案确认
8. 是否值得布局引擎化(出现第二种布局模式时)
---
> 下一篇:[06-主题系统与视觉设计](06-主题系统与视觉设计.md) —— 换肤只改变量,不引第二套样式。