基于 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 加密前缀保留(已加密凭证不受影响)。
12 KiB
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 / … │
└─────────────────────────────────────────────────┘
范式要点:
- 页面只做「编排」:容器 + 列表组件 + 子组件组合,本身 ≤400 行
- 数据获取走列表组件的 fetcher(内嵌「取消 + 版本号」双重防护,见 03 章)
- 表单弹窗独立成
components/XxxFormDialog.vue,通过 props/emit 通信 - 操作按钮逐个挂权限控制
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),布局组件只读状态不各自监听。弹窗移动端宽度走全局配置统一控制。
七、最佳实践清单
✅ 要做
- 业务页挂内容区(页面容器协议),禁止重写 layout/
- 页面标题来自
route.meta.title,不硬编码 - 可访问性:折叠钮/菜单项带 aria-label
- 布局状态(折叠)持久化,key 纳入全局命名空间(见 08 章双端一致)
- 路由切换动画统一一种(fade 150ms),
transition包router-view
❌ 不要
- 不要在业务页写 fixed 定位的伪头部(与 Topbar 层级打架)
- 不要侧栏菜单硬编码(数据源走菜单 store)
- 不要绕过页面容器自造页面容器(内边距/面包屑/页头规范会失控)
- 不要在移动端保留 hover-only 交互(用点击展开兜底)
- 不要保留空目录和过期布局文档
八、AI 检查清单(对比目标工程逐项核对)
P0
- 业务页面是否有绕过页面容器、直接改写布局层的代码?
- 页面标题是否单源(meta.title)?硬编码标题清单列出
P1
- 超过 500 行的 Layout / 超过 400 行的视图页面列出,并给拆分建议(参照 07 章)
- keepAlive 链路是否完整(meta + defineOptions name + include)?
- 响应式三断点行为是否齐全?弹窗移动端宽度是否有适配?
- ECharts 是否按需引入?WebSocket 是否有卸载断开与重连退避?
P2
- 是否值得引入标签页(多工位场景)?若引入,keep-alive 联动方案确认
- 是否值得布局引擎化(出现第二种布局模式时)
下一篇:06-主题系统与视觉设计 —— 换肤只改变量,不引第二套样式。