基于 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 加密前缀保留(已加密凭证不受影响)。
235 lines
12 KiB
Markdown
235 lines
12 KiB
Markdown
# 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) —— 换肤只改变量,不引第二套样式。
|