18 KiB
18 KiB
组件设计模式
**本文引用的文件** - [frontend/src/App.vue](file://frontend/src/App.vue) - [frontend/src/main.js](file://frontend/src/main.js) - [frontend/src/router/index.js](file://frontend/src/router/index.js) - [frontend/src/views/Layout.vue](file://frontend/src/views/Layout.vue) - [frontend/src/views/Login.vue](file://frontend/src/views/Login.vue) - [frontend/src/views/Dashboard.vue](file://frontend/src/views/Dashboard.vue) - [frontend/src/views/basic/Departments.vue](file://frontend/src/views/basic/Departments.vue) - [frontend/src/views/assessment/Assessments.vue](file://frontend/src/views/assessment/Assessments.vue) - [frontend/src/views/assessment/AssessmentDetail.vue](file://frontend/src/views/assessment/AssessmentDetail.vue) - [frontend/src/stores/user.js](file://frontend/src/stores/user.js) - [frontend/src/stores/app.js](file://frontend/src/stores/app.js) - [frontend/src/stores/index.js](file://frontend/src/stores/index.js) - [frontend/src/api/index.js](file://frontend/src/api/index.js) - [frontend/vite.config.js](file://frontend/vite.config.js) - [frontend/package.json](file://frontend/package.json)目录
引言
本指南围绕 Vue 组件设计模式,结合仓库中的前端实现,系统阐述组件拆分原则、单一职责与高内聚低耦合理念;容器组件与展示组件的分离;组件抽象与复用策略;组件通信(父子、兄弟、跨级、事件总线);状态管理(全局与局部);组件边界与接口设计;以及测试策略与 Mock 数据实践。目标是帮助读者在实际项目中构建清晰、可维护、可扩展的组件体系。
项目结构
前端采用典型的单页应用结构:入口应用、路由、布局、业务视图、状态管理与 API 层。整体遵循“关注点分离”和“按功能域组织”的原则,便于团队协作与长期演进。
graph TB
A["main.js<br/>应用入口"] --> B["App.vue<br/>根组件"]
A --> C["router/index.js<br/>路由配置"]
A --> D["stores/*<br/>Pinia 状态"]
A --> E["api/*<br/>API 导出聚合"]
B --> F["router-view<br/>动态渲染视图"]
F --> G["Layout.vue<br/>布局容器"]
G --> H["views/*<br/>业务视图"]
subgraph "业务视图"
H1["Login.vue"]
H2["Dashboard.vue"]
H3["basic/Departments.vue"]
H4["assessment/Assessments.vue"]
H5["assessment/AssessmentDetail.vue"]
end
G --> H1
G --> H2
G --> H3
G --> H4
G --> H5
图表来源
- frontend/src/main.js
- frontend/src/App.vue
- frontend/src/router/index.js
- frontend/src/views/Layout.vue
章节来源
核心组件
- 应用入口与根组件
- 入口负责注册插件、挂载应用;根组件提供语言环境与路由出口。
- 路由层
- 定义页面级路由、嵌套路由与导航守卫,统一设置标题与鉴权跳转。
- 布局容器
- 提供侧边栏、面包屑、头部用户信息与主内容区,承载业务视图切换与动画。
- 业务视图
- 各功能域页面(如登录、仪表盘、基础数据、考核管理等),承担数据加载、交互与展示。
- 状态管理
- Pinia Store 提供用户态与应用态(如侧边栏折叠、科室树)管理。
- API 聚合
- 统一导出各模块 API 方法,便于视图组件按需引入。
章节来源
- frontend/src/App.vue
- frontend/src/main.js
- frontend/src/router/index.js
- frontend/src/views/Layout.vue
- frontend/src/stores/user.js
- frontend/src/stores/app.js
- frontend/src/api/index.js
架构总览
系统采用“布局容器 + 页面视图 + 状态管理 + API 调用”的分层架构。路由驱动视图切换,Pinia 管理共享状态,Element Plus 提供 UI 基础能力,Vite 提供开发与代理能力。
graph TB
subgraph "运行时"
R["浏览器"]
V["Vue 3 运行时"]
P["Pinia 状态"]
E["Element Plus UI"]
AX["Axios 请求"]
end
R --> V
V --> E
V --> P
V --> AX
AX --> S["后端服务<br/>http://localhost:8000"]
图表来源
组件详解
布局容器组件(Layout)
- 角色定位
- 容器组件:负责页面骨架、菜单渲染、侧边栏折叠、面包屑与用户下拉。
- 设计要点
- 通过 Pinia 管理侧边栏折叠状态;从 API 加载菜单树并映射为前端菜单项。
- 使用路由元信息设置页面标题;在登出时清理状态并跳转登录。
- 边界与接口
- 依赖:路由实例、用户与应用 Store、菜单 API。
- 输出:菜单项数组、折叠状态、路由元信息标题。
- 复用策略
- 将菜单加载逻辑抽离为可复用的工具函数;对菜单树转换逻辑进行单元测试。
sequenceDiagram
participant U as "用户"
participant L as "Layout.vue"
participant S as "Store(user/app)"
participant A as "API(menu)"
participant R as "Router"
U->>L : 打开页面
L->>S : 读取折叠状态/用户信息
L->>A : 加载菜单树
A-->>L : 返回菜单数据
L->>L : 转换为前端菜单项
L->>R : 设置页面标题
U->>L : 点击菜单/折叠按钮
L->>S : 更新折叠状态
L->>R : 导航到目标路由
图表来源
- frontend/src/views/Layout.vue
- frontend/src/stores/user.js
- frontend/src/stores/app.js
- frontend/src/router/index.js
章节来源
- frontend/src/views/Layout.vue
- frontend/src/stores/user.js
- frontend/src/stores/app.js
- frontend/src/router/index.js
登录组件(Login)
- 角色定位
- 展示组件:负责表单输入、校验与登录交互。
- 设计要点
- 表单校验规则;调用用户 Store 的登录方法;成功后提示与路由跳转;失败提示。
- 边界与接口
- 输入:表单数据(用户名/密码);输出:登录结果与路由跳转。
- 复用策略
- 将表单校验规则与消息提示封装为可复用的组合式函数;对登录流程进行单元测试。
sequenceDiagram
participant U as "用户"
participant L as "Login.vue"
participant S as "Store(user)"
participant R as "Router"
U->>L : 输入用户名/密码
U->>L : 点击登录
L->>L : 校验表单
alt 校验通过
L->>S : 调用 login(username,password)
S-->>L : 返回布尔结果
alt 成功
L->>U : 显示成功消息
L->>R : 跳转 /
else 失败
L->>U : 显示失败消息
end
else 校验失败
L->>U : 显示校验提示
end
图表来源
章节来源
仪表盘组件(Dashboard)
- 角色定位
- 容器组件:负责多维度数据加载、图表初始化与渲染、告警提示与表格展示。
- 设计要点
- 多个图表(趋势、饼图、科室排名、仪表盘)的初始化与响应式适配;计算属性用于派生指标;异常数据兜底。
- 边界与接口
- 输入:周期参数;输出:统计卡片、图表数据、告警集合。
- 复用策略
- 将图表配置与更新函数抽取为可复用的工具;对数据格式化与图表选项生成进行单元测试。
flowchart TD
Start(["进入 Dashboard"]) --> LoadStats["加载统计数据"]
LoadStats --> LoadRanking["加载员工排名"]
LoadRanking --> LoadTrend["加载趋势数据"]
LoadTrend --> LoadDeptRanking["加载科室排名"]
LoadDeptRanking --> LoadFinance["加载财务趋势"]
LoadFinance --> LoadKpi["加载关键指标仪表盘"]
LoadKpi --> InitCharts["初始化图表实例"]
InitCharts --> RenderCharts["渲染图表与告警"]
RenderCharts --> End(["完成渲染"])
图表来源
章节来源
基础数据组件(Departments)
- 角色定位
- 容器组件:负责列表查询、分页、新增/编辑弹窗、状态切换与树形选择。
- 设计要点
- 搜索条件与分页参数传递至 API;树形选择使用树形数据;状态变更即时同步。
- 边界与接口
- 输入:搜索条件、分页参数;输出:表格数据、树形数据、提交结果。
- 复用策略
- 将 CRUD API 调用封装为独立函数;对表单校验与提交流程进行单元测试。
章节来源
考核管理组件(Assessments)
- 角色定位
- 容器组件:负责列表筛选、分页、批量创建、状态流转(提交/审核/确认)。
- 设计要点
- 多条件筛选与分页;批量创建弹窗;根据状态显示不同操作按钮。
- 边界与接口
- 输入:筛选条件、分页参数;输出:列表数据、批量创建结果。
- 复用策略
- 将状态标签映射与分数等级样式抽离为工具;对状态流转流程进行集成测试。
章节来源
考核详情组件(AssessmentDetail)
- 角色定位
- 容器组件:负责详情展示、草稿编辑、状态流转(保存/提交/审核/确认)。
- 设计要点
- 根据状态决定可编辑字段与操作按钮;状态标签与类型标签映射。
- 边界与接口
- 输入:路由参数(id);输出:详情数据、状态更新结果。
- 复用策略
- 将状态与类型映射封装为纯函数;对详情加载与状态更新进行单元测试。
章节来源
状态管理(Pinia Store)
- 用户 Store(useUserStore)
- 负责登录、获取用户信息、登出与 Token 管理;与路由联动。
- 应用 Store(useAppStore)
- 负责侧边栏折叠状态与科室树加载。
- 导出聚合
- 在 stores/index.js 中集中导出,便于视图组件按需引入。
classDiagram
class UserStore {
+string token
+object userInfo
+login(username,password) Promise<bool>
+getUserInfo() Promise<object>
+logout() void
}
class AppStore {
+boolean collapsed
+array departmentTree
+toggleSidebar() void
+loadDepartmentTree() Promise<void>
}
class StoresIndex {
+useUserStore()
+useAppStore()
}
StoresIndex --> UserStore : "导出"
StoresIndex --> AppStore : "导出"
图表来源
章节来源
API 聚合与请求
- API 聚合
- 在 api/index.js 中统一导出各模块 API,便于视图组件按需引入。
- 请求配置
- Vite 开发服务器配置了 /api 代理到后端服务地址,便于前后端联调。
章节来源
依赖关系分析
- 组件依赖
- 视图组件依赖路由、状态与 API;布局组件依赖菜单 API 与用户/应用 Store。
- 状态依赖
- 用户 Store 与路由守卫配合实现鉴权;应用 Store 管理 UI 状态。
- 外部依赖
- Element Plus 提供图标、表单、表格、图表等 UI 能力;ECharts 用于可视化;Axios 用于网络请求。
graph LR
V_Login["Login.vue"] --> S_User["useUserStore"]
V_Dash["Dashboard.vue"] --> API_Stats["stats API"]
V_Dash --> ECharts["ECharts"]
V_Dept["Departments.vue"] --> API_Dept["department API"]
V_Asm["Assessments.vue"] --> API_Asm["assessment API"]
V_AsmD["AssessmentDetail.vue"] --> API_Asm["assessment API"]
Layout["Layout.vue"] --> S_App["useAppStore"]
Layout --> API_Menu["menu API"]
Main["main.js"] --> Router["router/index.js"]
Main --> Stores["stores/*"]
Main --> App["App.vue"]
图表来源
- frontend/src/views/Login.vue
- frontend/src/views/Dashboard.vue
- frontend/src/views/basic/Departments.vue
- frontend/src/views/assessment/Assessments.vue
- frontend/src/views/assessment/AssessmentDetail.vue
- frontend/src/views/Layout.vue
- frontend/src/main.js
章节来源
性能考量
- 路由懒加载
- 路由组件使用动态导入,减少首屏体积,提升初始加载速度。
- 图表性能
- 仅在需要时初始化图表实例;监听窗口 resize 事件进行自适应;避免重复 setOption。
- 状态缓存
- 对于不频繁变化的数据(如菜单树、科室树)进行本地缓存,减少重复请求。
- 交互反馈
- 使用加载状态与防抖,避免频繁触发请求;对大列表使用分页与虚拟滚动(如后续扩展)。
章节来源
故障排查指南
- 登录失败
- 检查用户 Store 的登录返回值与错误处理;确认路由守卫是否正确拦截未登录访问。
- 菜单加载失败
- 检查菜单 API 返回结构与转换逻辑;确保降级菜单可用。
- 图表空白或不更新
- 检查图表实例是否初始化;确认数据源是否存在;验证 resize 事件绑定。
- 鉴权失效
- 检查本地 Token 是否存在;确认登出时是否清除 Token 并跳转登录。
章节来源
- frontend/src/views/Login.vue
- frontend/src/views/Layout.vue
- frontend/src/views/Dashboard.vue
- frontend/src/stores/user.js
结论
本项目在组件设计上体现了清晰的分层与职责划分:布局容器负责页面骨架与状态,业务视图承担数据与交互,Pinia 管理共享状态,API 聚合提供稳定接口。通过路由懒加载、图表性能优化与状态缓存等手段,兼顾了可维护性与用户体验。建议在后续迭代中进一步完善单元测试与集成测试,强化组件边界与接口契约,持续提升系统的稳定性与可扩展性。
附录
- 组件拆分原则
- 单一职责:每个组件只负责一个功能域内的展示与交互。
- 高内聚:组件内部逻辑紧密相关,减少外部依赖。
- 低耦合:通过明确的 props 与事件进行通信,避免直接依赖 DOM 或全局变量。
- 容器与展示组件
- 容器组件:负责数据加载、状态管理与流程控制;展示组件:负责具体 UI 渲染与用户交互。
- 组件抽象与复用
- 将通用逻辑(如表单校验、状态映射、图表配置)抽离为可复用函数或组合式工具。
- 组件通信
- 父子通信:通过 props 下传与 emits 上抛;兄弟通信:通过共同父组件或事件总线;跨级通信:通过事件总线或全局状态;事件总线:谨慎使用,建议优先选择 Pinia。
- 状态管理
- 局部状态:组件内部使用 ref/reactive;全局状态:Pinia Store;持久化:Token 存储于 localStorage。
- 接口与边界
- 明确输入输出类型;对异常情况进行降级处理;对外暴露稳定的 API 接口。
- 测试策略
- 单元测试:针对纯函数与组合式逻辑;集成测试:针对组件生命周期与交互流程;Mock 数据:使用静态 JSON 或模拟 API 返回。