writeOff/frontend_style_analysis.md
haomingming 815aa04fe8 first
2026-05-20 18:21:39 +08:00

14 KiB
Raw Blame History

前端页面设计风格一致性分析报告

项目: 会议核销 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.vue156KB / ~4000+ 行,虽然已拆分子组件但主文件仍然庞大。


四、表单验证方式不一致

方式 页面 问题
手动 if 检查 ExpertPage (submitExpert, submitCard) 6 个连续 if + ElMessage.warning 全手工
ElMessageBox.prompt UserPage, RolePage 用于输入框式验证
无验证 DataPermissionPage, OperationsDashboardPage 直接提交,无需验证
未使用 el-formrulesref.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.ts

    export 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 处内联 stylemargin-top, margin-right, margin-bottom
  • [P2-03] ExpertPage.vue — 移除 8 处内联 stylecolor, margin-left, width, border-radius
  • [P2-04] DataPermissionPage.vue — 统一嵌套 card shadow 规则、移除内联 margin/line-height
  • [P2-05] FinancePage.vue — 移除 4 处内联 stylewidth, font-weight, margin
  • [P2-06] ObservabilityPage.vue — 移除 8 处内联 stylemargin-top, width, font-weight
  • [P2-07] NotificationPolicyPage.vue — 移除 10+ 处内联 style.preview-box 迁移到全局
  • [P2-08] PlatformSessionPage.vue — 统一 4 个 select/input 的宽度规格
  • [P2-09] PlatformRolePage.vue — 移除 4 处内联 stylemargin-right, margin-bottom, font-weight
  • [P2-10] PlatformMenuPage.vue — 移除 3 处内联 stylemargin-top, margin-right
  • [P2-11] OperationsDashboardPage.vue — 移除 1 处内联 stylemargin-bottom
  • [P2-12] PermissionPage.vue / PlatformPermissionPage.vue — 统一 margin-top 值
  • [P2-13] TemplatePage.vue — 移除 7 处内联 stylewidth, margin-top, margin-left
  • [P2-14] TenantPage.vue — 移除 3 处内联 styleobject-fit, margin-bottom, color
  • [P2-15] InAppNotificationPage.vue — 移除 1 处内联 stylemargin-bottom
  • [P2-16] AuditQueryToolbar.vue — 移除 3 处内联 stylemargin-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] #606266var(--el-text-color-regular) 5 处)
  • [P4-02] #909399var(--el-text-color-secondary) 4 处)
  • [P4-03] #f8f8f8var(--el-fill-color-lighter) 2 处)
  • [P4-04] #ebeef5var(--el-border-color-lighter) 2 处)
  • [P4-05] #c0c4ccvar(--el-text-color-placeholder) AppLayout scrollbar

P5 — 表单验证标准化

  • [P5-01] ExpertPage.vue — 用 el-formrules + 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 人日