14 KiB
前端页面设计风格一致性分析报告
项目: 会议核销 SaaS 系统 Frontend
技术栈: Vue 3 + Element Plus + Vite + TypeScript
分析范围:frontend/src/views/下的 31 个页面组件 + 20 个子组件
分析日期: 2026-04-03
一、核心发现总览
pie title 风格不一致分布
"内联样式泛滥" : 35
"工具栏/搜索区布局混乱" : 20
"弹窗/抽屉尺寸不统一" : 15
"表格与按钮间距不一致" : 12
"CSS 管理缺失" : 10
"颜色/字号硬编码" : 8
Warning
在 31 个页面组件中,仅有 5 个 使用了
<style scoped>块,其余全部依赖内联style=""控制间距和布局。这严重影响后续维护和全局主题切换能力。
二、逐项分析
1. 页面容器结构 — <el-card> 使用方式不一致
所有 31 个功能页面都以 <el-card> 作为根容器,但细节差异如下:
| 类型 | 页面 | 使用方式 | 问题 |
|---|---|---|---|
| ✅ 标准模式 | UserPage, RolePage, MenuPage, PermissionPage 等 25 个 |
<el-card> (默认 shadow) |
一致 |
| ⚠️ 嵌套卡片 | DataPermissionPage |
外层 <el-card> + 内层 <el-card shadow="never"> |
嵌套层级不统一 |
| ⚠️ 多卡片网格 | OperationsDashboardPage |
外层 <el-card> + 9 个内嵌 <el-card> |
独特网格布局,无复用 |
| ⚠️ 弹窗嵌套 | MeetingAuditProgressDialog |
<el-card shadow="never"> 在 dialog 内 |
扁平卡片仅此一处 |
| 🔴 登录页独立 | PlatformLoginPage, TenantLoginPage |
<el-card class="login-card"> |
独立设计,与后台页面完全脱离 |
Important
建议: 创建统一的
<PageContainer>包裹组件,标准化 shadow 规则和 padding 规范。
2. 工具栏/搜索区域 — 布局方案碎片化
搜索栏和操作区的布局方式至少有 4 种不同范式:
#### 方案 A: `<el-space wrap>` (7 个页面)
```
UserPage, RolePage, DataPermissionPage,
NotificationPolicyPage, TemplatePage,
PlatformDictionaryPage 等
```
使用 `<el-space wrap>` 包裹按钮组
---
#### 方案 B: `<el-form :inline="true">` (8 个页面)
```
ExpertPage, FinancePage, ObservabilityPage,
PlatformSessionPage, MeetingQueryToolbar 等
```
使用内联表单包裹搜索字段和按钮
---
#### 方案 C: 裸按钮 (3 个页面)
```
PermissionPage, OperationsDashboardPage,
AuditQueryToolbar
```
直接将 `<el-button>` 放在卡片内,无任何包裹容器
---
#### 方案 D: 自定义 header-row (1 个页面)
```
InAppNotificationPage
```
使用自定义 CSS class `.header-row` 实现 flex 布局
在 card header slot 中排列控件
Important
建议: 统一使用方案 A(
<el-space wrap>)或方案 B(<el-form :inline="true">)二选一,并封装为<QueryToolbar>组件。
3. 表格与上方控件的间距 — 值不统一
当搜索栏与表格之间需要间距时,各页面的做法五花八门:
| 间距方式 | 页面 | 间距值 |
|---|---|---|
style="margin-top: 12px" |
RolePage, PermissionPage, PlatformPermissionPage, DataPermissionPage |
12px |
style="margin-top: 8px" |
ObservabilityPage (×3 处) |
8px |
| 无间距(紧贴搜索栏) | UserPage, ExpertPage, MeetingPage, FinancePage |
0 |
style="margin-bottom: 12px" (反向) |
OperationsDashboardPage |
12px (apply on button instead) |
<el-divider /> |
MeetingQueryToolbar, FinancePage, ObservabilityPage |
Element 默认 |
Note
同一个系统内出现
0px,8px,12px以及<el-divider>四种不同间距方案来处理同一类场景。
4. 弹窗 / 抽屉尺寸 — 宽度规格混乱
graph LR
subgraph Drawer尺寸
D1["520px — RolePage"]
D2["560px — UserPage, ExpertPage ×2"]
D3["680px — DataPermissionPage, NotificationPolicyPage"]
D4["80% — ExpertPage (银行卡列表)"]
end
subgraph Dialog宽度
W1["500px — DataPermissionPage (分配角色)"]
W2["520px — ExpertPage (合并)"]
W3["560px — ObservabilityPage, ExpertPage (OCR)"]
W4["620px — ExpertPage (身份证OCR)"]
W5["680px — RolePage (权限绑定)"]
W6["700px — NotificationPolicyPage (触发发送)"]
W7["720px — UserPage (历史), NotificationPolicyPage (编辑)"]
W8["860px — UserPage (代理授权)"]
end
统计: 抽屉有 4 种宽度规格,对话框有 8 种宽度规格,总计 12 种不同尺寸,严重缺乏统一的尺寸档位体系。
Important
建议: 定义 3 个标准 Drawer 尺寸 (
small: 480px,medium: 640px,large: 80%)
定义 3 个标准 Dialog 尺寸 (small: 520px,medium: 680px,large: 860px)
5. 表单控件宽度 — 硬编码且无统一标准
在内联 style 中给 <el-select>, <el-input> 等设置的宽度值收集如下:
| 控件场景 | 出现的宽度值 |
|---|---|
| 搜索栏 Select | 90px, 110px, 140px, 150px, 160px, 180px |
| 表单 Select | 220px, 240px, 260px, 280px |
| 搜索栏 Input | 180px, 190px, 200px, 260px |
| 全宽 Select | 100% |
| 弹窗内 Select | 100%, 220px |
统计: 光
<el-select>的宽度就出现了 10 种 不同的硬编码值。
6. CSS 管理 — <style scoped> 严重缺失
| 分类 | 页面数 | 比例 |
|---|---|---|
✅ 使用 <style scoped> |
5 个 (PlatformLoginPage, TenantLoginPage, NotificationPolicyPage, InAppNotificationPage, AppLayout) |
16% |
✅ 子组件使用 <style scoped> |
6 个 (MeetingListTable, MeetingMaterialDrawer, MeetingDocPreviewDialog, MeetingCreatePlatformExpertDialog, MeetingBindExpertDialog, MaterialPictureCardFileItem) |
— |
🔴 完全无 <style> 块 |
26 个页面 | 84% |
Caution
84% 的页面组件没有任何 CSS 管理方案,全靠内联
style=""支撑,极度不利于:
- 全局主题切换 / 暗色模式适配
- 设计 Token 标准化
- 多人协作维护
7. 颜色与字体硬编码
在模板中直接内联的颜色和字号值:
| 硬编码值 | 出处 | 场景 |
|---|---|---|
color: #606266 |
TenantLoginPage, AuditQueryToolbar, AppLayout |
提示文字颜色 |
color: #909399 |
ExpertPage ×4 |
辅助说明 |
font-weight: 600 |
RolePage, PlatformRolePage, FinancePage, ObservabilityPage, NotificationPolicyPage |
小标题 |
font-size: 12px |
NotificationPolicyPage |
提示文字 |
font-size: 13px |
AppLayout |
登录信息 |
line-height: 1.8 / 1.9 |
ExpertPage, DataPermissionPage, NotificationPolicyPage |
详情 |
background: #f8f8f8 |
NotificationPolicyPage, AppLayout |
预览盒 / 主内容区 |
border: 1px solid #ebeef5 |
NotificationPolicyPage, AppLayout |
边框 |
Note
这些颜色值实际上都对应 Element Plus 的设计变量(
--el-text-color-regular,--el-text-color-secondary等),应该改用 CSS 变量引用。
三、已有组件拆分的一致性
| 模块 | 是否拆分子组件 | 子组件数 | 评价 |
|---|---|---|---|
| MeetingPage | ✅ 已拆分 | 17 个 | 拆分合理,但子组件之间也存在细微风格差异 |
| AuditPage | ✅ 已拆分 | 3 个 | 基本一致 |
| ProjectPage | ⚠️ 部分拆分 | 1 个 (ProjectEditDrawer) | 主页面和抽屉风格有差异 |
| 其余 28 个页面 | 🔴 未拆分 | 0 个 | 全部为单文件巨型组件 |
最大的单文件组件
MeetingPage.vue达 156KB / ~4000+ 行,虽然已拆分子组件但主文件仍然庞大。
四、表单验证方式不一致
| 方式 | 页面 | 问题 |
|---|---|---|
手动 if 检查 |
ExpertPage (submitExpert, submitCard) |
6 个连续 if + ElMessage.warning 全手工 |
ElMessageBox.prompt |
UserPage, RolePage |
用于输入框式验证 |
| 无验证 | DataPermissionPage, OperationsDashboardPage |
直接提交,无需验证 |
❌ 未使用 el-form 的 rules 和 ref.validate() |
全部页面 | 没有一个页面使用 Element Plus 原生的表单验证 |
五、TODO 清单(按优先级排列)
P0 — 基础设施(先行完成,为后续改造铺路)
-
[P0-01] 创建全局 CSS 变量文件
src/styles/variables.css
定义间距 Token (--spacing-xs: 4px,--spacing-sm: 8px,--spacing-md: 12px,--spacing-lg: 16px,--spacing-xl: 24px) -
[P0-02] 创建全局工具类文件
src/styles/utilities.css
定义.mt-sm,.mt-md,.mb-md,.gap-sm等常用间距类 -
[P0-03] 定义弹窗/抽屉尺寸常量
src/constants/ui.tsexport const DRAWER_SIZE = { sm: '480px', md: '640px', lg: '80%' } export const DIALOG_WIDTH = { sm: '520px', md: '680px', lg: '860px' } -
[P0-04] 定义表单控件标准宽度常量
export const INPUT_WIDTH = { xs: '100px', sm: '160px', md: '220px', lg: '280px', full: '100%' }
P1 — 公共组件封装
-
[P1-01] 封装
<PageContainer>组件
统一<el-card>+ header slot + 标准 padding/shadow 行为 -
[P1-02] 封装
<QueryToolbar>组件
统一搜索栏布局、按钮排列方式、与下方表格的间距 -
[P1-03] 封装
<ActionButtons>组件
统一操作列按钮的间距和视觉风格 -
[P1-04] 封装
<SectionTitle>组件
替换<div style="font-weight: 600; margin-bottom: 8px">这类重复标题
P2 — 各页面样式迁移(消灭内联 style)
- [P2-01]
UserPage.vue— 移除 4 处内联 style,改用工具类;select/input 改用标准宽度 - [P2-02]
RolePage.vue— 移除 5 处内联 style(margin-top, margin-right, margin-bottom) - [P2-03]
ExpertPage.vue— 移除 8 处内联 style(color, margin-left, width, border-radius) - [P2-04]
DataPermissionPage.vue— 统一嵌套 card shadow 规则、移除内联 margin/line-height - [P2-05]
FinancePage.vue— 移除 4 处内联 style(width, font-weight, margin) - [P2-06]
ObservabilityPage.vue— 移除 8 处内联 style(margin-top, width, font-weight) - [P2-07]
NotificationPolicyPage.vue— 移除 10+ 处内联 style,.preview-box迁移到全局 - [P2-08]
PlatformSessionPage.vue— 统一 4 个 select/input 的宽度规格 - [P2-09]
PlatformRolePage.vue— 移除 4 处内联 style(margin-right, margin-bottom, font-weight) - [P2-10]
PlatformMenuPage.vue— 移除 3 处内联 style(margin-top, margin-right) - [P2-11]
OperationsDashboardPage.vue— 移除 1 处内联 style(margin-bottom) - [P2-12]
PermissionPage.vue/PlatformPermissionPage.vue— 统一 margin-top 值 - [P2-13]
TemplatePage.vue— 移除 7 处内联 style(width, margin-top, margin-left) - [P2-14]
TenantPage.vue— 移除 3 处内联 style(object-fit, margin-bottom, color) - [P2-15]
InAppNotificationPage.vue— 移除 1 处内联 style(margin-bottom) - [P2-16]
AuditQueryToolbar.vue— 移除 3 处内联 style(margin-left, margin-bottom, color)
P3 — 弹窗/抽屉标准化
- [P3-01] 全部 Drawer 改用
DRAWER_SIZE常量(统一归档到 sm/md/lg) - [P3-02] 全部 Dialog 改用
DIALOG_WIDTH常量(统一归档到 sm/md/lg) - [P3-03] 统一 Drawer 的
destroy-on-close行为(目前部分有、部分无) - [P3-04] 统一 footer 按钮排列方式(目前 [取消 + 确定] vs [关闭 + 保存] 命名不统一)
P4 — 颜色与硬编码值替换
- [P4-01]
#606266→var(--el-text-color-regular)(5 处) - [P4-02]
#909399→var(--el-text-color-secondary)(4 处) - [P4-03]
#f8f8f8→var(--el-fill-color-lighter)(2 处) - [P4-04]
#ebeef5→var(--el-border-color-lighter)(2 处) - [P4-05]
#c0c4cc→var(--el-text-color-placeholder)(AppLayout scrollbar)
P5 — 表单验证标准化
- [P5-01]
ExpertPage.vue— 用el-form的rules+formRef.validate()替换手动 if 校验 - [P5-02]
UserPage.vue— 添加rules验证(姓名、手机号必填等) - [P5-03]
NotificationPolicyPage.vue— 添加表单 rules - [P5-04] 所有有 required 标记的表单字段实际加上
rules规则
P6 — 长期优化
- [P6-01]
MeetingPage.vue(156KB) 进一步拆分,将 dialog/drawer 独立为子组件 - [P6-02] 建立 ESLint 规则禁止新增内联
style="" - [P6-03] 统一
<el-form>的label-width值(当前70px / 90px / 100px / 110px四种) - [P6-04] 抽取公共的
statusFormatter/toZhStatus为 composable - [P6-05] 考虑引入全局暗色模式支持
六、改造优先级路线图
gantt
title 前端风格统一改造路线图
dateFormat YYYY-MM-DD
section P0 基础设施
CSS 变量 & 工具类 :p0, 2026-04-07, 2d
尺寸/宽度常量 :after p0, 1d
section P1 公共组件
PageContainer :p1a, after p0, 2d
QueryToolbar :p1b, after p1a, 2d
SectionTitle & ActionButtons :after p1b, 1d
section P2-P4 样式迁移
高频页面 (User/Role/Expert) :p2, after p1b, 3d
中频页面 (Finance/Audit/Obs) :after p2, 3d
低频页面 (Platform/Template) :after p2, 3d
颜色硬编码替换 :after p2, 1d
section P5-P6 深度优化
表单验证标准化 :p5, after p2, 3d
MeetingPage 拆分 :after p5, 3d
ESLint 规则 & 暗色模式 :after p5, 2d
Tip
建议按 P0 → P1 → P2(高频页面优先)→ P3 → P4 → P5 → P6 的顺序执行,预计总工作量约 15-20 人日。