20260823210241

This commit is contained in:
oneao committed 2026-08-23 21:02:41 +08:00
1 parent 5ff4583aeb
commit f4c7413dc6
2766 files changed
+1836409 -94689

No files matched your search

@@ -0,0 +1,446 @@
# UI基础组件
<cite>
**本文引用的文件**
- [Button.vue](file://fms-vue/src/components/ui/button/Button.vue)
- [Input.vue](file://fms-vue/src/components/ui/input/Input.vue)
- [Form.vue](file://fms-vue/src/components/ui/form/Form.vue)
- [Checkbox.vue](file://fms-vue/src/components/ui/checkbox/Checkbox.vue)
- [Select.vue](file://fms-vue/src/components/ui/select/Select.vue)
- [date-picker.vue](file://fms-vue/src/components/ui/date/date-picker.vue)
- [Modal.vue](file://fms-vue/src/components/ui/modal/Modal.vue)
- [Drawer.vue](file://fms-vue/src/components/ui/drawer/Drawer.vue)
- [index.js](file://fms-vue/src/theme/index.js)
- [tokens.css](file://fms-vue/src/theme/tokens.css)
- [package.json](file://fms-vue/package.json)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件为 FMS Vue UI 基础组件库的权威文档,覆盖 Button、Input、Form、Checkbox、Select、DatePicker、Modal、Drawer 等核心组件。内容包含设计原则、API 属性、事件与插槽、可访问性(a11y)、响应式与主题适配、组合使用模式、最佳实践、测试策略与性能优化建议。目标是帮助开发者快速理解并高质量地使用这些组件。
## 项目结构
FMS Vue 的基础组件位于 fms-vue/src/components/ui 下,按功能模块划分目录;主题系统通过 CSS 变量与 JS 工具函数在运行时切换主色与深浅模式;表单体系由 Form 提供上下文与校验能力,子项通过 provide/inject 协作。
```mermaid
graph TB
subgraph "UI 组件"
B["Button"]
I["Input"]
Cb["Checkbox"]
S["Select"]
Dp["DatePicker"]
M["Modal"]
Dr["Drawer"]
F["Form"]
end
subgraph "主题系统"
TJS["theme/index.js"]
TTOK["theme/tokens.css"]
end
subgraph "通用能力"
Pop["Popover(浮层)"]
Drag["拖拽/缩放工具"]
Focus["焦点管理"]
Scroll["滚动锁定"]
end
S --> Pop
Dp --> Pop
M --> Drag
M --> Focus
M --> Scroll
Dr --> Drag
Dr --> Focus
Dr --> Scroll
F --> |provide/inject| 各FormItem
B --> |"样式类名"| TTOK
I --> |"样式类名"| TTOK
Cb --> |"样式类名"| TTOK
S --> |"样式类名"| TTOK
Dp --> |"样式类名"| TTOK
M --> |"样式类名"| TTOK
Dr --> |"样式类名"| TTOK
TJS --> TTOK
```
图表来源
- [Button.vue:1-69](file://fms-vue/src/components/ui/button/Button.vue#L1-L69)
- [Input.vue:1-370](file://fms-vue/src/components/ui/input/Input.vue#L1-L370)
- [Checkbox.vue:1-91](file://fms-vue/src/components/ui/checkbox/Checkbox.vue#L1-L91)
- [Select.vue:1-526](file://fms-vue/src/components/ui/select/Select.vue#L1-L526)
- [date-picker.vue:1-187](file://fms-vue/src/components/ui/date/date-picker.vue#L1-L187)
- [Modal.vue:1-291](file://fms-vue/src/components/ui/modal/Modal.vue#L1-L291)
- [Drawer.vue:1-219](file://fms-vue/src/components/ui/drawer/Drawer.vue#L1-L219)
- [index.js:1-16](file://fms-vue/src/theme/index.js#L1-L16)
- [tokens.css:1-152](file://fms-vue/src/theme/tokens.css#L1-L152)
章节来源
- [package.json:1-48](file://fms-vue/package.json#L1-L48)
## 核心组件
- Button:提供多种视觉变体、禁用/加载态、块级按钮与原生 type 支持,具备无障碍提示。
- Input:统一输入控件,支持密码可见切换、数字输入、字数统计、清除、前/后缀插槽、文本域自适应高度与拖拽调整。
- Checkbox:支持半选状态、名称与值提交、聚焦/失焦事件。
- Select:下拉选择器,支持本地/远程筛选、键盘导航、自由输入、无匹配文案、清除与加载态。
- DatePicker:日期/时间选择器,支持格式解析、值格式化、禁用日期、清空与键盘交互。
- Modal:对话框,支持受控/非受控打开、遮罩、Esc关闭、全屏、拖拽与四边缩放、焦点陷阱与滚动锁定。
- Drawer:抽屉面板,支持多方向滑出、尺寸调整、遮罩与键盘交互、焦点与滚动管理。
- Form:表单容器,提供布局、网格列数、标签宽度、必填标记、校验时机与全量校验,并通过 provide/inject 向子项下发上下文。
章节来源
- [Button.vue:1-69](file://fms-vue/src/components/ui/button/Button.vue#L1-L69)
- [Input.vue:1-370](file://fms-vue/src/components/ui/input/Input.vue#L1-L370)
- [Checkbox.vue:1-91](file://fms-vue/src/components/ui/checkbox/Checkbox.vue#L1-L91)
- [Select.vue:1-526](file://fms-vue/src/components/ui/select/Select.vue#L1-L526)
- [date-picker.vue:1-187](file://fms-vue/src/components/ui/date/date-picker.vue#L1-L187)
- [Modal.vue:1-291](file://fms-vue/src/components/ui/modal/Modal.vue#L1-L291)
- [Drawer.vue:1-219](file://fms-vue/src/components/ui/drawer/Drawer.vue#L1-L219)
- [Form.vue:1-128](file://fms-vue/src/components/ui/form/Form.vue#L1-L128)
## 架构总览
组件间通过“轻量原子 + 组合”的方式构建复杂交互:
- 浮层能力由 Popover 抽象,Select 与 DatePicker 复用其触发与定位。
- 弹窗/抽屉共享焦点陷阱、滚动锁定与拖拽/缩放工具,保证一致的可访问性与交互体验。
- 主题系统以 CSS 变量为核心,JS 仅负责写入主色与切换深色 class,组件通过语义化类名与变量实现风格统一。
```mermaid
sequenceDiagram
participant U as "用户"
participant Sel as "Select"
participant Pop as "Popover"
participant List as "选项列表"
U->>Sel : 点击/聚焦触发器
Sel->>Pop : 打开浮层(open=true)
Pop-->>Sel : 更新open状态
Sel->>List : 渲染可见选项(过滤/远程)
U->>List : 键盘/鼠标选择
List-->>Sel : 选中回调(update : modelValue, change)
Sel->>Pop : 关闭浮层
```
图表来源
- [Select.vue:1-526](file://fms-vue/src/components/ui/select/Select.vue#L1-L526)
章节来源
- [Select.vue:1-526](file://fms-vue/src/components/ui/select/Select.vue#L1-L526)
- [date-picker.vue:1-187](file://fms-vue/src/components/ui/date/date-picker.vue#L1-L187)
## 详细组件分析
### Button
- 设计要点
- 视觉变体:primary/secondary/outline/ghost/danger/link,通过类名注入样式。
- 状态:disabled/loading/block,loading 时禁用交互并显示加载图标。
- 可访问性:aria-busy 指示加载状态。
- API
- 属性:type、disabled、loading、block、htmlType
- 事件:透传原生 button 事件
- 插槽:默认插槽用于按钮内容
- 样式定制
- 通过类名 button/button-{type}/button-block/button-loading 控制外观
- 主题变量影响颜色与尺寸
- 示例路径
- [Button.vue:11-41](file://fms-vue/src/components/ui/button/Button.vue#L11-L41)
- [Button.vue:43-63](file://fms-vue/src/components/ui/button/Button.vue#L43-L63)
章节来源
- [Button.vue:1-69](file://fms-vue/src/components/ui/button/Button.vue#L1-L69)
- [tokens.css:1-152](file://fms-vue/src/theme/tokens.css#L1-L152)
### Input
- 设计要点
- 多模式:default/password/number/textarea,统一交互与样式。
- 辅助能力:allowClear、showCount、maxlength、rows、autocomplete。
- 文本域:自动测量初始高度、拖拽调整高度、键盘微调、防抖刷新。
- 数字输入:中间态保留小数点,提交时转为 Number,空值保留为空字符串。
- API
- 属性:modelValue、type、disabled、readonly、status、allowClear、showCount、maxlength、rows、autocomplete
- 事件:update:modelValue、change、blur、focus、clear
- 插槽:prefix、suffix
- 可访问性
- aria-invalid 根据 status 设置;密码切换按钮具备 aria-label 与 aria-pressed。
- 示例路径
- [Input.vue:6-28](file://fms-vue/src/components/ui/input/Input.vue#L6-L28)
- [Input.vue:76-97](file://fms-vue/src/components/ui/input/Input.vue#L76-L97)
- [Input.vue:107-150](file://fms-vue/src/components/ui/input/Input.vue#L107-L150)
- [Input.vue:152-277](file://fms-vue/src/components/ui/input/Input.vue#L152-L277)
- [Input.vue:280-364](file://fms-vue/src/components/ui/input/Input.vue#L280-L364)
```mermaid
flowchart TD
Start(["输入事件"]) --> Mode{"是否数字模式?"}
Mode -- 否 --> UpdateText["更新 modelValue"]
Mode -- 是 --> Normalize["规范化输入<br/>保留中间态小数点"]
Normalize --> Commit{"失焦或确认?"}
Commit -- 是 --> ToNumber["转换为 Number<br/>空值保持空串"]
Commit -- 否 --> Wait["等待继续输入"]
ToNumber --> UpdateNum["更新 modelValue"]
UpdateText --> End(["结束"])
UpdateNum --> End
Wait --> End
```
图表来源
- [Input.vue:107-150](file://fms-vue/src/components/ui/input/Input.vue#L107-L150)
- [Input.vue:76-97](file://fms-vue/src/components/ui/input/Input.vue#L76-L97)
章节来源
- [Input.vue:1-370](file://fms-vue/src/components/ui/input/Input.vue#L1-L370)
### Checkbox
- 设计要点
- 支持 indeterminate 半选,勾选优先于半选显示。
- 原生 name/value 便于表单提交分组与取值。
- API
- 属性:modelValue、indeterminate、disabled、name、value
- 事件:update:modelValue、change、focus、blur
- 插槽:默认插槽作为标签文本
- 可访问性
- 内部 input 类型 checkbox,配合 label 包裹提升可访问性。
- 示例路径
- [Checkbox.vue:6-17](file://fms-vue/src/components/ui/checkbox/Checkbox.vue#L6-L17)
- [Checkbox.vue:21-63](file://fms-vue/src/components/ui/checkbox/Checkbox.vue#L21-L63)
- [Checkbox.vue:65-85](file://fms-vue/src/components/ui/checkbox/Checkbox.vue#L65-L85)
章节来源
- [Checkbox.vue:1-91](file://fms-vue/src/components/ui/checkbox/Checkbox.vue#L1-L91)
### Select
- 设计要点
- 本地/远程筛选:filterable/filterOption/remote/search。
- 键盘导航:上下移动、Home/End、Enter 选择、Esc 取消。
- 自由输入:allowFreeInput 允许将当前文本作为值提交。
- 缓存显示:selectedCache 避免选项替换后显示丢失。
- API
- 属性:modelValue、options、disabled、clearable、filterable、filterOption、remote、loading、notFoundText、allowFreeInput、labelKey、valueKey
- 事件:update:modelValue、change、search
- 插槽:默认插槽用于自定义选项,暴露 select/close 方法
- 可访问性
- role="combobox"/role="listbox"/role="option",aria-expanded、aria-controls、aria-activedescendant、aria-selected、aria-disabled、aria-busy。
- 示例路径
- [Select.vue:7-35](file://fms-vue/src/components/ui/select/Select.vue#L7-L35)
- [Select.vue:52-144](file://fms-vue/src/components/ui/select/Select.vue#L52-L144)
- [Select.vue:160-205](file://fms-vue/src/components/ui/select/Select.vue#L160-L205)
- [Select.vue:207-407](file://fms-vue/src/components/ui/select/Select.vue#L207-L407)
- [Select.vue:410-526](file://fms-vue/src/components/ui/select/Select.vue#L410-L526)
```mermaid
sequenceDiagram
participant U as "用户"
participant Sel as "Select"
participant Opt as "选项集合"
U->>Sel : 键入筛选词
Sel->>Sel : 更新 filterQuery
alt 远程模式
Sel-->>U : 触发 search(query)
U-->>Sel : 父层更新 options
else 本地模式
Sel->>Opt : 计算 visibleOptions
end
U->>Sel : 方向键/Enter 选择
Sel-->>U : update : modelValue / change
```
图表来源
- [Select.vue:253-290](file://fms-vue/src/components/ui/select/Select.vue#L253-L290)
- [Select.vue:326-407](file://fms-vue/src/components/ui/select/Select.vue#L326-L407)
章节来源
- [Select.vue:1-526](file://fms-vue/src/components/ui/select/Select.vue#L1-L526)
### DatePicker
- 设计要点
- format/valueFormat 分离展示与绑定值格式,自动解析精度。
- 支持 disabledDate、clearable、键盘打开/关闭、回车/空格切换。
- 基于 Popover 弹出 CalendarPanel,支持时间/日期/混合模式。
- API
- 属性:modelValue、format、valueFormat、clearable、disabled、disabledDate
- 事件:update:modelValue、change
- 可访问性
- 输入框 readonly,具备 aria-haspopup/dialog、aria-expanded。
- 示例路径
- [date-picker.vue:16-27](file://fms-vue/src/components/ui/date/date-picker.vue#L16-L27)
- [date-picker.vue:46-74](file://fms-vue/src/components/ui/date/date-picker.vue#L46-L74)
- [date-picker.vue:76-129](file://fms-vue/src/components/ui/date/date-picker.vue#L76-L129)
- [date-picker.vue:132-187](file://fms-vue/src/components/ui/date/date-picker.vue#L132-L187)
章节来源
- [date-picker.vue:1-187](file://fms-vue/src/components/ui/date/date-picker.vue#L1-L187)
### Modal
- 设计要点
- 受控/非受控 open,支持 maskClosable、keyboard、closable、fullscreen、resizable。
- 打开时记录触发元素、锁定滚动、焦点陷阱、拖拽标题栏、四边缩放手柄。
- 关闭时恢复焦点、清理监听与句柄。
- API
- 属性:open/defaultOpen、title、width、centered、mask、maskClosable、keyboard、closable、fullscreen、resizable、footer、okText、cancelText、confirmLoading
- 事件:update:open、ok、cancel
- 插槽:默认内容区、footer 自定义底部按钮
- 可访问性
- role="dialog"、aria-modal、aria-labelledby/aria-label、Tab 循环。
- 示例路径
- [Modal.vue:10-43](file://fms-vue/src/components/ui/modal/Modal.vue#L10-L43)
- [Modal.vue:66-116](file://fms-vue/src/components/ui/modal/Modal.vue#L66-L116)
- [Modal.vue:118-198](file://fms-vue/src/components/ui/modal/Modal.vue#L118-L198)
- [Modal.vue:201-285](file://fms-vue/src/components/ui/modal/Modal.vue#L201-L285)
```mermaid
sequenceDiagram
participant U as "用户"
participant M as "Modal"
participant F as "焦点/滚动工具"
U->>M : 触发打开
M->>F : lockScroll()
M->>M : 记录触发元素
M->>F : focusFirst(panel)
M->>M : 绑定拖拽/缩放句柄
U->>M : Esc/遮罩/取消
M->>F : unlockScroll()
M->>M : 恢复焦点到触发元素
```
图表来源
- [Modal.vue:118-198](file://fms-vue/src/components/ui/modal/Modal.vue#L118-L198)
- [Modal.vue:201-285](file://fms-vue/src/components/ui/modal/Modal.vue#L201-L285)
章节来源
- [Modal.vue:1-291](file://fms-vue/src/components/ui/modal/Modal.vue#L1-L291)
### Drawer
- 设计要点
- placement 支持 left/right/top/bottom,对应不同方向与尺寸轴。
- resizable 支持边缘拖拽调整尺寸,限制不超过视口。
- 打开/关闭生命周期与 Modal 类似:焦点陷阱、滚动锁定、句柄清理。
- API
- 属性:open/defaultOpen、title、placement、width/height、mask、maskClosable、keyboard、closable、resizable
- 事件:update:open、cancel
- 插槽:extra、footer
- 可访问性
- role="dialog"、aria-modal、aria-labelledby/aria-label。
- 示例路径
- [Drawer.vue:9-38](file://fms-vue/src/components/ui/drawer/Drawer.vue#L9-L38)
- [Drawer.vue:53-113](file://fms-vue/src/components/ui/drawer/Drawer.vue#L53-L113)
- [Drawer.vue:115-154](file://fms-vue/src/components/ui/drawer/Drawer.vue#L115-L154)
- [Drawer.vue:157-213](file://fms-vue/src/components/ui/drawer/Drawer.vue#L157-L213)
章节来源
- [Drawer.vue:1-219](file://fms-vue/src/components/ui/drawer/Drawer.vue#L1-L219)
### Form
- 设计要点
- 布局:horizontal/vertical,columns>1 启用网格布局。
- 字段注册:registerField/unregisterField 维护字段校验能力。
- 全量校验:validateAll 并行校验所有已注册字段,返回错误字段列表。
- 提交/重置:submit/submitFailed/reset 事件,重置时同步清除校验状态。
- API
- 属性:model、rules、layout、labelAlign、labelWidth、columns、maxWidth、requiredMark、validateTrigger
- 事件:submit、submitFailed、reset
- 方法:validateAll(defineExpose)
- 示例路径
- [Form.vue:5-38](file://fms-vue/src/components/ui/form/Form.vue#L5-L38)
- [Form.vue:40-92](file://fms-vue/src/components/ui/form/Form.vue#L40-L92)
- [Form.vue:94-110](file://fms-vue/src/components/ui/form/Form.vue#L94-L110)
- [Form.vue:113-123](file://fms-vue/src/components/ui/form/Form.vue#L113-L123)
章节来源
- [Form.vue:1-128](file://fms-vue/src/components/ui/form/Form.vue#L1-L128)
## 依赖分析
- 外部依赖
- Vue 3、@lucide/vue 图标、dayjs(日期处理)、pinia(状态)、axios(网络)等。
- 组件内依赖
- Select/DatePicker 依赖 Popover 进行浮层展示。
- Modal/Drawer 依赖焦点管理、滚动锁定、拖拽/缩放工具。
- 所有组件通过 tokens.css 的 CSS 变量实现主题一致性。
- 主题系统
- index.js 提供 applyPrimaryColor 与 applyDarkMode,操作 <html> 上的 class 与 CSS 变量。
- tokens.css 定义浅色/深色两套变量,主色通过 JS 动态写入。
```mermaid
graph LR
Pkg["package.json"] --> Vue["Vue 3"]
Pkg --> Icons["@lucide/vue"]
Pkg --> Dayjs["dayjs"]
Pkg --> Pinia["pinia"]
Pkg --> Axios["axios"]
Comp["UI 组件"] --> Tokens["tokens.css"]
Theme["theme/index.js"] --> Tokens
Comp --> Tools["焦点/滚动/拖拽工具"]
```
图表来源
- [package.json:1-48](file://fms-vue/package.json#L1-L48)
- [index.js:1-16](file://fms-vue/src/theme/index.js#L1-L16)
- [tokens.css:1-152](file://fms-vue/src/theme/tokens.css#L1-L152)
章节来源
- [package.json:1-48](file://fms-vue/package.json#L1-L48)
- [index.js:1-16](file://fms-vue/src/theme/index.js#L1-L16)
- [tokens.css:1-152](file://fms-vue/src/theme/tokens.css#L1-L152)
## 性能考虑
- 列表渲染优化
- Select 使用 v-memo 对选项列表进行稳定渲染,减少重绘。
- 高频交互节流
- Input 文本域拖拽高度时使用 requestAnimationFrame 合并更新,避免频繁重排。
- 事件与监听
- Modal/Drawer 在打开时绑定键盘事件,关闭时及时移除,防止内存泄漏。
- 浮层与滚动
- 弹窗/抽屉打开时锁定页面滚动,避免背景滚动带来的抖动与重绘。
- 远程搜索
- Select 开启 remote 时由父层控制数据源,避免前端大数据集筛选开销。
[本节为通用指导,不直接分析具体文件]
## 故障排查指南
- 表单校验未生效
- 检查 Form 是否正确 provide 上下文,FormItem 是否完成 registerField。
- validateTrigger 为 blur 时,确保在失焦后再触发校验。
- 数字输入异常
- Input number 模式会保留中间态小数点,提交时才转 Number;如需严格整数,请在父层做二次校验。
- 选择器显示值丢失
- Select 在 options 被替换时会清空 selectedCache,需确保 valueKey 指向正确且值稳定。
- 弹窗/抽屉焦点丢失
- 确认组件处于打开状态,焦点陷阱已绑定;关闭后会自动恢复触发元素焦点。
- 主题色不生效
- 调用 applyPrimaryColor 写入 --fms-primary,并确保 tokens.css 已被引入。
章节来源
- [Form.vue:94-110](file://fms-vue/src/components/ui/form/Form.vue#L94-L110)
- [Input.vue:107-150](file://fms-vue/src/components/ui/input/Input.vue#L107-L150)
- [Select.vue:146-158](file://fms-vue/src/components/ui/select/Select.vue#L146-L158)
- [Modal.vue:118-198](file://fms-vue/src/components/ui/modal/Modal.vue#L118-L198)
- [Drawer.vue:115-154](file://fms-vue/src/components/ui/drawer/Drawer.vue#L115-L154)
- [index.js:1-16](file://fms-vue/src/theme/index.js#L1-L16)
## 结论
FMS UI 基础组件以一致的 API 设计、完善的可访问性、灵活的样式与主题机制,以及健壮的交互逻辑,为业务应用提供了可靠的前端基石。通过 Form 的组合能力与 Select/DatePicker 的灵活扩展,能够覆盖大多数常见场景。建议在项目中统一采用该组件库,并结合主题系统与测试策略,持续提升用户体验与开发效率。
## 附录
- 主题与样式
- 通过 theme/index.js 的 applyPrimaryColor 与 applyDarkMode 控制主色与深浅模式。
- 所有组件通过 tokens.css 中的 CSS 变量保持一致的视觉语言。
- 组合使用模式
- Form + Input/Select/DatePicker/Checkbox 构建复杂表单,利用 validateTrigger 与 rules 实现精细化校验。
- Modal/Drawer 承载表单或详情,结合 confirmLoading 与异步流程控制。
- 测试策略
- 单元测试:验证 props/emits/插槽行为,如 Input 的数字模式、Select 的键盘导航。
- 集成测试:模拟用户交互(点击、键盘),断言 DOM 状态与事件触发。
- 可访问性测试:检查 role/aria 属性与键盘可达性。
- 最佳实践
- 使用受控模式管理 open/modelValue,避免状态不一致。
- 合理使用远程搜索与分页,避免大数据集在前端筛选。
- 通过 slots 与 CSS 变量进行最小侵入的样式定制。
[本节为通用指导,不直接分析具体文件]
@@ -0,0 +1,365 @@
# 业务组件
<cite>
**本文引用的文件**
- [FmsTable.vue](file://fms-vue/src/components/fms-table/FmsTable.vue)
- [createCellRenderer.js](file://fms-vue/src/components/fms-table/utils/createCellRenderer.js)
- [createEditableCellRenderer.js](file://fms-vue/src/components/fms-table/utils/createEditableCellRenderer.js)
- [createSelectionCellRenderers.js](file://fms-vue/src/components/fms-table/utils/createSelectionCellRenderers.js)
- [FmsFile.vue](file://fms-vue/src/components/fms-file/FmsFile.vue)
- [FileListPanel.vue](file://fms-vue/src/components/fms-file/FileListPanel.vue)
- [FileCard.vue](file://fms-vue/src/components/fms-file/FileCard.vue)
- [FilePreviewPanel.vue](file://fms-vue/src/components/fms-file/FilePreviewPanel.vue)
- [useFileCategory.js](file://fms-vue/src/components/fms-file/composables/useFileCategory.js)
- [fileService.js](file://fms-vue/src/services/fileService.js)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录:使用示例与配置方案](#附录使用示例与配置方案)
## 简介
本文件面向 FMS 业务组件,重点围绕以下能力展开:
- FmsTable 高性能表格:虚拟滚动、行内编辑、列配置、数据绑定、选择与拖拽排序等。
- FmsFile 文件管理:上传(本地/OSS)、预览、分类树、批量操作(多选/删除/下载)。
- 与 UI 基础组件的集成模式,以及与后端服务的交互方式。
- 复杂场景下的配置与最佳实践,以及性能优化与错误处理策略。
## 项目结构
FmsTable 位于 fms-vue/src/components/fms-table,核心由主组件与工具函数组成;FmsFile 位于 fms-vue/src/components/fms-file,包含三栏布局(分类树、文件列表、预览)及组合式逻辑。
```mermaid
graph TB
subgraph "表格组件"
A["FmsTable.vue"]
B["createCellRenderer.js"]
C["createEditableCellRenderer.js"]
D["createSelectionCellRenderers.js"]
end
subgraph "文件组件"
E["FmsFile.vue"]
F["FileListPanel.vue"]
G["FileCard.vue"]
H["FilePreviewPanel.vue"]
I["useFileCategory.js"]
end
J["fileService.js"]
K["UI 基础组件<br/>Button/Modal/Dropdown/Input/Select..."]
A --> B
A --> C
A --> D
E --> F
E --> H
E --> I
F --> G
F --> J
H --> J
```
图表来源
- [FmsTable.vue:1-800](file://fms-vue/src/components/fms-table/FmsTable.vue#L1-L800)
- [createCellRenderer.js:1-229](file://fms-vue/src/components/fms-table/utils/createCellRenderer.js#L1-L229)
- [createEditableCellRenderer.js:1-212](file://fms-vue/src/components/fms-table/utils/createEditableCellRenderer.js#L1-L212)
- [createSelectionCellRenderers.js:1-135](file://fms-vue/src/components/fms-table/utils/createSelectionCellRenderers.js#L1-L135)
- [FmsFile.vue:1-262](file://fms-vue/src/components/fms-file/FmsFile.vue#L1-L262)
- [FileListPanel.vue:1-800](file://fms-vue/src/components/fms-file/FileListPanel.vue#L1-L800)
- [FileCard.vue:1-296](file://fms-vue/src/components/fms-file/FileCard.vue#L1-L296)
- [FilePreviewPanel.vue:1-247](file://fms-vue/src/components/fms-file/FilePreviewPanel.vue#L1-L247)
- [useFileCategory.js:1-77](file://fms-vue/src/components/fms-file/composables/useFileCategory.js#L1-L77)
- [fileService.js:1-149](file://fms-vue/src/services/fileService.js#L1-L149)
章节来源
- [FmsTable.vue:1-800](file://fms-vue/src/components/fms-table/FmsTable.vue#L1-L800)
- [FmsFile.vue:1-262](file://fms-vue/src/components/fms-file/FmsFile.vue#L1-L262)
## 核心组件
- FmsTable:基于 StkTable 的高性能表格封装,提供虚拟滚动、行内编辑、列头拖拽、选择列、拖拽排序、主题切换、键盘导航与编辑激活优化等。
- FmsFile:三栏文件管理器,支持分类树、文件列表(网格/列表视图)、预览面板、批量操作、上传(本地/OSS)、分页与粘贴/拖拽上传。
章节来源
- [FmsTable.vue:10-37](file://fms-vue/src/components/fms-table/FmsTable.vue#L10-L37)
- [FmsFile.vue:12-20](file://fms-vue/src/components/fms-file/FmsFile.vue#L12-L20)
## 架构总览
FmsTable 通过 props 暴露行为开关(如 virtual、editable、rowSelection),内部将列配置标准化并注入自定义渲染器(actions、可编辑单元格、选择列),再交给底层表格库渲染。FmsFile 通过 Splitter 组织三栏,左侧分类树由 useFileCategory 驱动,中间 FileListPanel 负责数据加载与批量操作,右侧 FilePreviewPanel 负责预览。
```mermaid
sequenceDiagram
participant U as "父组件"
participant FT as "FmsTable.vue"
participant CR as "createCellRenderer.js"
participant EC as "createEditableCellRenderer.js"
participant SC as "createSelectionCellRenderers.js"
participant ST as "StkTable(底层)"
U->>FT : 传入 columns/dataSource/props
FT->>CR : resolveCustomCell(col, ctx, editingActive)
alt 有 actions
CR-->>ST : 注入 actions 自定义单元格
else 可编辑列且处于编辑态或特殊类型
CR->>EC : createEditableCell(...)
EC-->>ST : 返回输入/选择/复选框渲染
end
FT->>SC : createSelectionColumn(...)
SC-->>ST : 注入选择列
FT->>ST : 渲染 displayColumns + dataSource
```
图表来源
- [FmsTable.vue:273-334](file://fms-vue/src/components/fms-table/FmsTable.vue#L273-L334)
- [createCellRenderer.js:208-229](file://fms-vue/src/components/fms-table/utils/createCellRenderer.js#L208-L229)
- [createEditableCellRenderer.js:195-212](file://fms-vue/src/components/fms-table/utils/createEditableCellRenderer.js#L195-L212)
- [createSelectionCellRenderers.js:18-129](file://fms-vue/src/components/fms-table/utils/createSelectionCellRenderers.js#L18-L129)
## 详细组件分析
### FmsTable 高性能表格
- 虚拟滚动
- 当数据行数超过阈值时启用虚拟滚动,避免大表渲染开销;宽度变化仅重算 X 方向以提升性能。
- 尺寸变更防抖合并 ResizeObserver 通知,减少重复计算。
- 行内编辑
- 通过 WeakMap 维护每行的编辑状态,仅在活动编辑行存在时注入编辑器渲染,降低滚动时的组件创建成本。
- 键盘导航期间延迟激活编辑器,合并连续按键,避免频繁挂载/卸载导致的掉帧。
- 支持 Input、Select、Checkbox 三种编辑器,统一焦点管理与值变更回调。
- 列配置
- 自动注入序号列、选择列、拖拽列;支持列头拖拽排序与列宽调整。
- actions 列支持按钮与“更多”下拉菜单,内置确认弹窗。
- 数据绑定
- rowKey 支持字符串或函数;activeRowKey 控制高亮行;change 事件回传行、列与新值。
- 其他特性
- 主题跟随应用深浅色;区域选择用于编辑态;导出 scrollToRow/editRow/getSelectedArea 等方法供外部调用。
```mermaid
flowchart TD
Start(["进入编辑流程"]) --> CheckNav{"是否键盘导航中?"}
CheckNav --> |是| Repeat{"是否按住方向键 repeat?"}
Repeat --> |是| Defer["延迟激活编辑器<br/>等待松手后提交"]
Repeat --> |否| Fast{"快速连按?"}
Fast --> |是| Debounce["防抖合并激活"]
Fast --> |否| Activate["立即激活编辑器"]
CheckNav --> |否| Activate
Defer --> Commit["松手后提交目标行"]
Debounce --> Commit
Activate --> Focus["聚焦并选中内容"]
Commit --> Focus
Focus --> End(["完成"])
```
图表来源
- [FmsTable.vue:373-505](file://fms-vue/src/components/fms-table/FmsTable.vue#L373-L505)
章节来源
- [FmsTable.vue:41-47](file://fms-vue/src/components/fms-table/FmsTable.vue#L41-L47)
- [FmsTable.vue:70-96](file://fms-vue/src/components/fms-table/FmsTable.vue#L70-L96)
- [FmsTable.vue:98-126](file://fms-vue/src/components/fms-table/FmsTable.vue#L98-L126)
- [FmsTable.vue:176-220](file://fms-vue/src/components/fms-table/FmsTable.vue#L176-L220)
- [FmsTable.vue:273-334](file://fms-vue/src/components/fms-table/FmsTable.vue#L273-L334)
- [createEditableCellRenderer.js:17-49](file://fms-vue/src/components/fms-table/utils/createEditableCellRenderer.js#L17-L49)
- [createEditableCellRenderer.js:78-127](file://fms-vue/src/components/fms-table/utils/createEditableCellRenderer.js#L78-L127)
- [createEditableCellRenderer.js:129-193](file://fms-vue/src/components/fms-table/utils/createEditableCellRenderer.js#L129-L193)
- [createCellRenderer.js:9-43](file://fms-vue/src/components/fms-table/utils/createCellRenderer.js#L9-L43)
- [createCellRenderer.js:102-206](file://fms-vue/src/components/fms-table/utils/createCellRenderer.js#L102-L206)
- [createSelectionCellRenderers.js:18-129](file://fms-vue/src/components/fms-table/utils/createSelectionCellRenderers.js#L18-L129)
### FmsFile 文件管理组件
- 功能特性
- 分类管理:加载 bf_files_cateid 扁平数据并转换为树形结构,支持“全部分类”根节点。
- 文件列表:网格/列表双视图,支持全选、批量删除/下载、分页、拖拽/粘贴上传。
- 预览面板:图片直显,非图片显示类型标签与元信息,支持前后翻页。
- 上传机制:根据后端配置选择本地直传或阿里云 OSS 直传;OSS 凭证缓存与过期刷新。
- 交互流程
- 选择分类 → 加载对应文件 → 选择文件 → 右侧预览 → 批量操作。
```mermaid
sequenceDiagram
participant P as "父组件"
participant FF as "FmsFile.vue"
participant FC as "useFileCategory.js"
participant FL as "FileListPanel.vue"
participant FS as "fileService.js"
participant FP as "FilePreviewPanel.vue"
P->>FF : 传入 moduleCode/father/initialCateId
FF->>FC : loadCategories()
FC-->>FF : treeData/selectedKey
FF->>FL : 传递 moduleId/cateId/readonly
FL->>FS : pageDataApi / upload / removeFile
FS-->>FL : 文件列表/上传结果
FL->>FP : selectedFile
FP-->>P : 预览/上下页事件
```
图表来源
- [FmsFile.vue:22-80](file://fms-vue/src/components/fms-file/FmsFile.vue#L22-L80)
- [useFileCategory.js:15-64](file://fms-vue/src/components/fms-file/composables/useFileCategory.js#L15-L64)
- [FileListPanel.vue:90-133](file://fms-vue/src/components/fms-file/FileListPanel.vue#L90-L133)
- [fileService.js:25-85](file://fms-vue/src/services/fileService.js#L25-L85)
- [FilePreviewPanel.vue:15-39](file://fms-vue/src/components/fms-file/FilePreviewPanel.vue#L15-L39)
章节来源
- [FmsFile.vue:22-133](file://fms-vue/src/components/fms-file/FmsFile.vue#L22-L133)
- [FileListPanel.vue:45-133](file://fms-vue/src/components/fms-file/FileListPanel.vue#L45-L133)
- [FileListPanel.vue:155-258](file://fms-vue/src/components/fms-file/FileListPanel.vue#L155-L258)
- [FileListPanel.vue:280-364](file://fms-vue/src/components/fms-file/FileListPanel.vue#L280-L364)
- [FilePreviewPanel.vue:15-39](file://fms-vue/src/components/fms-file/FilePreviewPanel.vue#L15-L39)
- [useFileCategory.js:15-64](file://fms-vue/src/components/fms-file/composables/useFileCategory.js#L15-L64)
- [fileService.js:25-143](file://fms-vue/src/services/fileService.js#L25-L143)
### 对象模型与关系(代码级)
```mermaid
classDiagram
class FmsTable {
+props : virtual/virtualX/colResizable/bordered/noDataFull/showOverflow/columns/seq/columnDraggable/rowSelection/dataSource/rowKey/activeRowKey/rowDraggable/editable/theme
+emit : update : columns/change/row-order-change
+methods : scrollToRow/editRow/getSelectedArea/clearSelectedArea/setRowExpand/initVirtualScroll
}
class CreateCellRenderer {
+resolveCustomCell(col, ctx, editingActive)
}
class EditableCellRenderer {
+createEditableCell(col, ctx)
}
class SelectionCellRenderer {
+createSelectionColumn(options)
+isSelectionColumn(col)
}
class FmsFile {
+props : moduleCode/father/showTree/readonly/initialCateId
+emit : uploaded/deleted/selected
}
class FileListPanel {
+props : moduleCode/moduleId/father/cateId/readonly
+emit : preview/uploaded/deleted
}
class FilePreviewPanel {
+props : file/fileList
+emit : prev/next
}
class UseFileCategory {
+treeData/loading/error/selectedKey
+loadCategories/selectCategory/findCategory
}
class FileService {
+upload(opts)
+getPreviewUrl(fileRow)
+removeFile(subid)
}
FmsTable --> CreateCellRenderer : "生成列渲染"
FmsTable --> EditableCellRenderer : "行内编辑"
FmsTable --> SelectionCellRenderer : "选择列"
FmsFile --> UseFileCategory : "分类树"
FmsFile --> FileListPanel : "列表/上传/批量"
FmsFile --> FilePreviewPanel : "预览"
FileListPanel --> FileService : "上传/删除/预览URL"
FilePreviewPanel --> FileService : "预览URL"
```
图表来源
- [FmsTable.vue:10-37](file://fms-vue/src/components/fms-table/FmsTable.vue#L10-L37)
- [createCellRenderer.js:208-229](file://fms-vue/src/components/fms-table/utils/createCellRenderer.js#L208-L229)
- [createEditableCellRenderer.js:195-212](file://fms-vue/src/components/fms-table/utils/createEditableCellRenderer.js#L195-L212)
- [createSelectionCellRenderers.js:18-135](file://fms-vue/src/components/fms-table/utils/createSelectionCellRenderers.js#L18-L135)
- [FmsFile.vue:12-20](file://fms-vue/src/components/fms-file/FmsFile.vue#L12-L20)
- [FileListPanel.vue:35-43](file://fms-vue/src/components/fms-file/FileListPanel.vue#L35-L43)
- [FilePreviewPanel.vue:8-13](file://fms-vue/src/components/fms-file/FilePreviewPanel.vue#L8-L13)
- [useFileCategory.js:9-75](file://fms-vue/src/components/fms-file/composables/useFileCategory.js#L9-L75)
- [fileService.js:25-143](file://fms-vue/src/services/fileService.js#L25-L143)
## 依赖关系分析
- FmsTable 依赖 StkTable 进行虚拟化与渲染,并通过 utils 中的三个模块分别处理 actions、可编辑单元格、选择列。
- FmsFile 依赖 Splitter 布局组件与 UI 基础组件(Button/Modal/Dropdown/Input/Select/Checkbox/Pagination/Spin/Tag/Tooltip),并通过 services 层与后端交互。
- 文件服务 fileService.js 抽象了本地与 OSS 两种上传路径,并提供凭证缓存与预览 URL 获取。
```mermaid
graph LR
FT["FmsTable.vue"] --> STK["stk-table-vue"]
FT --> U1["createCellRenderer.js"]
FT --> U2["createEditableCellRenderer.js"]
FT --> U3["createSelectionCellRenderers.js"]
FF["FmsFile.vue"] --> SPLIT["Splitter"]
FF --> UI["UI 基础组件"]
FF --> SVC["fileService.js"]
FL["FileListPanel.vue"] --> SVC
FP["FilePreviewPanel.vue"] --> SVC
```
图表来源
- [FmsTable.vue:1-8](file://fms-vue/src/components/fms-table/FmsTable.vue#L1-L8)
- [FmsFile.vue:1-10](file://fms-vue/src/components/fms-file/FmsFile.vue#L1-L10)
- [fileService.js:1-149](file://fms-vue/src/services/fileService.js#L1-L149)
章节来源
- [FmsTable.vue:1-8](file://fms-vue/src/components/fms-table/FmsTable.vue#L1-L8)
- [FmsFile.vue:1-10](file://fms-vue/src/components/fms-file/FmsFile.vue#L1-L10)
- [fileService.js:1-149](file://fms-vue/src/services/fileService.js#L1-L149)
## 性能考量
- 表格虚拟滚动
- 数据量大于阈值才开启虚拟滚动,避免小数据量的额外开销。
- 尺寸变化时仅重算 X 方向(高度未变),减少 Y 方向重排。
- ResizeObserver 防抖合并,动画期间不频繁触发 initVirtualScroll。
- 编辑态优化
- 仅在存在活动编辑行时注入 customCell,非编辑态走原生 td,减少函数式组件数量。
- 键盘导航期间延迟激活编辑器,合并连续按键,避免频繁挂载/卸载。
- 使用 WeakMap 存储草稿值,卸载前兜底写入,避免整表更新。
- 文件列表
- 网格/列表双视图,避免引入重型表格库;分页加载减少首屏压力。
- 图片缩略图使用 Blob URL 并适时释放,防止内存泄漏。
- OSS 直传凭证缓存,减少鉴权请求频率。
[本节为通用性能建议,不直接分析具体文件]
## 故障排查指南
- 表格编辑异常
- 检查 editable 与 column.editor 配置是否正确;确认 editingActive 与活动行状态迁移逻辑。
- 关注键盘导航期间的延迟激活与防抖逻辑,避免误判 repeat 导致编辑器未激活。
- 选择列状态不一致
- 确认 getSelectedRowKeys 与 onChange 回调是否同步更新;过滤禁用行后的全选统计是否正确。
- 文件上传失败
- 检查 storageType 初始化与凭证缓存是否过期;OSS 直传需确保 host/policy/signature 正确。
- 本地上传需确保 FormData 字段名与后端一致;Content-Type 不应被覆盖。
- 预览不可用
- 确认 mx_mapfilename 是否存在;图片类型判断是否匹配扩展名。
章节来源
- [FmsTable.vue:176-220](file://fms-vue/src/components/fms-table/FmsTable.vue#L176-L220)
- [createSelectionCellRenderers.js:26-56](file://fms-vue/src/components/fms-table/utils/createSelectionCellRenderers.js#L26-L56)
- [fileService.js:8-32](file://fms-vue/src/services/fileService.js#L8-L32)
- [fileService.js:87-108](file://fms-vue/src/services/fileService.js#L87-L108)
- [FilePreviewPanel.vue:27-39](file://fms-vue/src/components/fms-file/FilePreviewPanel.vue#L27-L39)
## 结论
FmsTable 与 FmsFile 在 FMS 业务中承担数据展示与文件管理的核心职责。前者通过精细化的虚拟滚动与编辑态优化实现高性能表格体验;后者以模块化拆分与组合式逻辑提供完整的文件生命周期管理能力。两者均与 UI 基础组件与服务层解耦,便于复用与扩展。
[本节为总结性内容,不直接分析具体文件]
## 附录:使用示例与配置方案
- FmsTable 常用配置
- 虚拟滚动:virtual=true(默认),数据量大时自动生效;可通过 effectiveVirtual 逻辑控制。
- 行内编辑:editable=true(默认),列定义 editor={type:'input'|'select'|'checkbox'}。
- 选择列:传入 rowSelection={selectedRowKeys, onChange, getCheckboxProps}。
- 拖拽排序:rowDraggable=true,监听 row-order-change 事件。
- 列头拖拽:columnDraggable=true(默认),可配置 disabled 函数限制特定列。
- 主题:theme='light'|'dark',默认跟随应用深浅色。
- FmsFile 常用配置
- 模块解析:moduleCode 必填,组件会自动查询模块 ID。
- 初始分类:initialCateId 指定默认选中分类。
- 只读模式:readonly=true 隐藏上传/删除等操作。
- 事件:uploaded/deleted/selected 用于与父组件联动。
- 复杂场景
- 大数据表格:结合分页或懒加载数据源,启用虚拟滚动;避免同时大量编辑。
- 多文件批量操作:使用 FileListPanel 的多选与批量删除/下载;注意 pending 文件的本地状态清理。
- 混合编辑器:同一表格混用 input/select/checkbox,注意 select 的 label 映射与空值处理。
章节来源
- [FmsTable.vue:10-37](file://fms-vue/src/components/fms-table/FmsTable.vue#L10-L37)
- [FmsTable.vue:273-334](file://fms-vue/src/components/fms-table/FmsTable.vue#L273-L334)
- [createEditableCellRenderer.js:97-147](file://fms-vue/src/components/fms-table/utils/createEditableCellRenderer.js#L97-L147)
- [FmsFile.vue:12-20](file://fms-vue/src/components/fms-file/FmsFile.vue#L12-L20)
- [FileListPanel.vue:393-636](file://fms-vue/src/components/fms-file/FileListPanel.vue#L393-L636)
@@ -0,0 +1,375 @@
# 组件系统
<cite>
**本文引用的文件**
- [fms-vue/src/components/ui/button/Button.vue](file://fms-vue/src/components/ui/button/Button.vue)
- [fms-vue/src/components/ui/form/Form.vue](file://fms-vue/src/components/ui/form/Form.vue)
- [fms-vue/src/components/fms-table/FmsTable.vue](file://fms-vue/src/components/fms-table/FmsTable.vue)
- [fms-vue/src/components/fms-file/FmsFile.vue](file://fms-vue/src/components/fms-file/FmsFile.vue)
- [fms-vue/src/components/fms-table/utils/createCellRenderer.js](file://fms-vue/src/components/fms-table/utils/createCellRenderer.js)
- [fms-vue/src/components/fms-file/composables/useFileCategory.js](file://fms-vue/src/components/fms-file/composables/useFileCategory.js)
- [fms-vue/src/theme/index.js](file://fms-vue/src/theme/index.js)
- [fms-vue/package.json](file://fms-vue/package.json)
- [fms-vue/tests/components/basic.spec.js](file://fms-vue/tests/components/basic.spec.js)
- [fms-vue/tests/components/form.spec.js](file://fms-vue/tests/components/form.spec.js)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件面向 FMS 前端组件系统的工程化文档,聚焦于组件分层、职责分离与复用策略;系统化阐述 UI 基础组件(如 Button、Form)的设计模式与实现规范;深入解析业务级复杂组件(FmsTable、FmsFile)的架构设计;说明组件间通信机制(props、事件、状态共享);给出样式组织与主题定制方案;并提供组件测试策略与文档生成方法建议。
## 项目结构
FMS Vue 应用采用“UI 基础组件 + 业务组件 + 布局/服务/状态”的分层组织方式:
- UI 基础组件位于 components/ui,提供通用原子能力(按钮、表单、选择器、消息等)。
- 业务组件位于 components/fms-*,封装领域场景(表格、文件管理等)。
- 主题与样式集中在 theme 与 styles,通过 CSS 变量驱动深浅色与品牌色。
- 服务与状态在 services 与 stores,统一数据访问与全局状态。
- 测试位于 tests,基于 Vitest 与 @vue/test-utils。
```mermaid
graph TB
subgraph "UI 基础组件"
B["Button"]
Fm["Form"]
end
subgraph "业务组件"
T["FmsTable"]
FF["FmsFile"]
end
subgraph "主题与样式"
TH["theme/index.js"]
end
subgraph "服务与状态"
API["services/api.js"]
STORE["stores/app.js"]
end
T --> B
T --> TH
T --> STORE
FF --> API
FF --> TH
Fm --> TH
```
图表来源
- [fms-vue/src/components/ui/button/Button.vue:1-69](file://fms-vue/src/components/ui/button/Button.vue#L1-L69)
- [fms-vue/src/components/ui/form/Form.vue:1-128](file://fms-vue/src/components/ui/form/Form.vue#L1-L128)
- [fms-vue/src/components/fms-table/FmsTable.vue:1-800](file://fms-vue/src/components/fms-table/FmsTable.vue#L1-L800)
- [fms-vue/src/components/fms-file/FmsFile.vue:1-262](file://fms-vue/src/components/fms-file/FmsFile.vue#L1-L262)
- [fms-vue/src/theme/index.js:1-16](file://fms-vue/src/theme/index.js#L1-L16)
- [fms-vue/src/stores/app.js](file://fms-vue/src/stores/app.js)
章节来源
- [fms-vue/package.json:1-48](file://fms-vue/package.json#L1-L48)
## 核心组件
- Button:统一的视觉变体、加载态、禁用态与原生类型透传,保证交互一致性与可访问性。
- Form:提供 model/rules 驱动的校验、多列网格布局、提交/重置事件与字段注册表,支撑复杂表单场景。
- FmsTable:基于 stk-table-vue 的高性能表格,支持虚拟滚动、行编辑、多选、拖拽排序、列头拖拽、主题跟随与应用状态。
- FmsFile:三栏分割式文件管理(分类树、列表、预览),封装模块解析、分类加载、预览导航与上传/删除事件。
章节来源
- [fms-vue/src/components/ui/button/Button.vue:1-69](file://fms-vue/src/components/ui/button/Button.vue#L1-L69)
- [fms-vue/src/components/ui/form/Form.vue:1-128](file://fms-vue/src/components/ui/form/Form.vue#L1-L128)
- [fms-vue/src/components/fms-table/FmsTable.vue:1-800](file://fms-vue/src/components/fms-table/FmsTable.vue#L1-L800)
- [fms-vue/src/components/fms-file/FmsFile.vue:1-262](file://fms-vue/src/components/fms-file/FmsFile.vue#L1-L262)
## 架构总览
组件系统遵循以下原则:
- 分层清晰:UI 基础组件不感知业务上下文;业务组件组合基础组件并封装领域逻辑。
- 职责单一:每个组件只负责一个明确职责(如 Form 负责校验与布局,FmsTable 负责表格渲染与交互)。
- 配置优先:通过 props 暴露能力边界,避免内部硬编码;插槽与自定义渲染函数扩展展示。
- 主题解耦:通过 CSS 变量与主题工具函数切换深浅色与主色,组件仅消费变量。
- 通信契约:以 props 向下传递、事件向上冒泡、provide/inject 或 store 进行跨层级状态共享。
```mermaid
sequenceDiagram
participant Parent as "父组件"
participant Form as "Form"
participant Item as "FormItem"
participant API as "API/Store"
Parent->>Form : 传入 model/rules/layout
Form->>Item : provide(fms-form)
Item-->>Form : registerField(name, field)
Parent->>Form : 触发 submit
Form->>Form : validateAll()
Form->>Item : 调用 field.validate()
Item-->>Form : errors[]
alt 无错误
Form-->>Parent : emit('submit', values)
else 有错误
Form-->>Parent : emit('submitFailed', {values, errorFields})
end
```
图表来源
- [fms-vue/src/components/ui/form/Form.vue:52-110](file://fms-vue/src/components/ui/form/Form.vue#L52-L110)
## 详细组件分析
### Button 组件
- 设计要点
- 视觉变体:primary/secondary/outline/ghost/danger/link,通过 class 映射。
- 状态控制:disabled/loading/block,loading 时禁用并显示加载图标。
- 原生兼容:htmlType 透传 button/submit/reset,便于表单集成。
- 可访问性:aria-busy 随 loading 动态设置。
- 使用建议
- 表单内提交/重置按钮使用 htmlType="submit"/"reset"。
- 异步操作时使用 loading,避免重复提交。
```mermaid
classDiagram
class Button {
+type : string
+disabled : boolean
+loading : boolean
+block : boolean
+htmlType : string
+render()
}
```
图表来源
- [fms-vue/src/components/ui/button/Button.vue:11-63](file://fms-vue/src/components/ui/button/Button.vue#L11-L63)
章节来源
- [fms-vue/src/components/ui/button/Button.vue:1-69](file://fms-vue/src/components/ui/button/Button.vue#L1-L69)
### Form 组件
- 设计要点
- 表单模型:model 为对象,rules 为按字段名组织的规则集合。
- 布局:horizontal/vertical,columns 启用网格布局,maxWidth 限制最大宽度。
- 校验:validateTrigger 支持 change/blur;validateAll 并行校验所有已注册字段。
- 事件:submit/submitFailed/reset,提交失败返回 errorFields。
- 上下文:provide fms-form,供子项读取布局、对齐、label 宽度等。
- 使用建议
- 将复杂表单拆分为多个 FormItem,集中维护 rules。
- 需要程序化校验时通过 expose 的 validateAll 获取错误字段。
```mermaid
flowchart TD
Start(["提交"]) --> Prevent["阻止默认提交"]
Prevent --> Validate["并行校验所有字段"]
Validate --> HasError{"存在错误?"}
HasError -- 是 --> EmitFail["emit('submitFailed', {values, errorFields})"]
HasError -- 否 --> EmitSubmit["emit('submit', values)"]
EmitFail --> End(["结束"])
EmitSubmit --> End
```
图表来源
- [fms-vue/src/components/ui/form/Form.vue:64-92](file://fms-vue/src/components/ui/form/Form.vue#L64-L92)
章节来源
- [fms-vue/src/components/ui/form/Form.vue:1-128](file://fms-vue/src/components/ui/form/Form.vue#L1-L128)
### FmsTable 组件
- 设计要点
- 虚拟滚动:行数超过阈值时启用虚拟滚动,ResizeObserver + rAF 防抖刷新布局,减少重排。
- 行编辑:WeakMap 存储每行编辑态,editingActive 控制是否注入编辑器渲染,避免整表重建。
- 键盘导航:捕获方向键与 Tab,合并长按与快速连按,延迟激活编辑器以提升流畅度。
- 列处理:根据 editor/actions 动态注入 customCell;序号列、选择列、拖拽列自动插入。
- 主题:跟随 appStore.darkMode,或通过 theme prop 覆盖。
- 事件:change、row-order-change、update:columns,暴露 scrollToRow/editRow/getSelectedArea 等方法。
- 使用建议
- 大列表务必开启 virtual/virtualX;合理设置 rowKey。
- 编辑列仅在需要时启用,减少渲染开销。
- 通过 actions 配置行内操作,支持确认弹窗与更多菜单。
```mermaid
sequenceDiagram
participant User as "用户"
participant Table as "FmsTable"
participant Stk as "StkTable"
participant Utils as "createCellRenderer"
User->>Table : 点击/键盘导航
Table->>Table : 计算 displayColumns / editingActive
Table->>Utils : resolveCustomCell(col, ctx)
Utils-->>Table : 返回 customCell(可选)
Table->>Stk : 渲染 columns/data-source
Stk-->>Table : area-selection-change / row-order-change
Table-->>User : change / row-order-change
```
图表来源
- [fms-vue/src/components/fms-table/FmsTable.vue:273-314](file://fms-vue/src/components/fms-table/FmsTable.vue#L273-L314)
- [fms-vue/src/components/fms-table/utils/createCellRenderer.js:208-229](file://fms-vue/src/components/fms-table/utils/createCellRenderer.js#L208-L229)
```mermaid
flowchart TD
A["尺寸变化 ResizeObserver"] --> B["记录宽高 lastSize"]
B --> C{"高度未变且宽度变化?"}
C -- 是 --> D["仅刷新 X 方向虚拟滚动"]
C -- 否 --> E["刷新全量虚拟滚动"]
D --> F["等待稳定后执行一次"]
E --> F
```
图表来源
- [fms-vue/src/components/fms-table/FmsTable.vue:70-96](file://fms-vue/src/components/fms-table/FmsTable.vue#L70-L96)
章节来源
- [fms-vue/src/components/fms-table/FmsTable.vue:1-800](file://fms-vue/src/components/fms-table/FmsTable.vue#L1-L800)
- [fms-vue/src/components/fms-table/utils/createCellRenderer.js:1-229](file://fms-vue/src/components/fms-table/utils/createCellRenderer.js#L1-L229)
### FmsFile 组件
- 设计要点
- 模块解析:根据 moduleCode 查询模块信息,失败时提示错误。
- 分类树:useFileCategory 拉取分类并转换为树形数据,支持全选根节点。
- 三栏布局:Splitter 分隔分类、列表、预览面板,支持最小/默认尺寸。
- 预览导航:上一份/下一份切换,选中文件通过 selected 事件上报。
- 事件代理:uploaded/deleted 透传给父组件。
- 使用建议
- initialCateId 可用于初始化展开与选中。
- readonly 模式下隐藏上传/删除等操作。
```mermaid
sequenceDiagram
participant Parent as "父组件"
participant File as "FmsFile"
participant Cat as "useFileCategory"
participant List as "FileListPanel"
participant Prev as "FilePreviewPanel"
Parent->>File : moduleCode/father/showTree/readonly
File->>Cat : loadCategories()
Cat-->>File : treeData/loading/selectedKey
File->>List : 传入 moduleCode/moduleId/cateId/readonly
List-->>File : preview/uploaded/deleted
File-->>Prev : 选中文件 prev/next
File-->>Parent : uploaded/deleted/selected
```
图表来源
- [fms-vue/src/components/fms-file/FmsFile.vue:22-133](file://fms-vue/src/components/fms-file/FmsFile.vue#L22-L133)
- [fms-vue/src/components/fms-file/composables/useFileCategory.js:1-77](file://fms-vue/src/components/fms-file/composables/useFileCategory.js#L1-L77)
章节来源
- [fms-vue/src/components/fms-file/FmsFile.vue:1-262](file://fms-vue/src/components/fms-file/FmsFile.vue#L1-L262)
- [fms-vue/src/components/fms-file/composables/useFileCategory.js:1-77](file://fms-vue/src/components/fms-file/composables/useFileCategory.js#L1-L77)
## 依赖关系分析
- 外部依赖
- stk-table-vue:高性能表格内核,提供虚拟滚动、区域选择、拖拽排序等能力。
- lucide/vue:图标库,用于按钮加载态等。
- axios:HTTP 请求。
- pinia:状态管理。
- sortablejs/vuedraggable:拖拽相关。
- 内部依赖
- FmsTable 依赖 createCellRenderer 动态生成单元格渲染逻辑。
- FmsFile 依赖 useFileCategory 管理分类数据与树结构。
- 主题通过 theme/index.js 写入 CSS 变量与 dark class,被各组件消费。
```mermaid
graph LR
Btn["Button"] --> Theme["theme/index.js"]
Form["Form"] --> Theme
Table["FmsTable"] --> Cell["createCellRenderer.js"]
Table --> Store["stores/app.js"]
File["FmsFile"] --> Cat["useFileCategory.js"]
File --> Theme
```
图表来源
- [fms-vue/src/theme/index.js:1-16](file://fms-vue/src/theme/index.js#L1-L16)
- [fms-vue/src/components/fms-table/utils/createCellRenderer.js:1-229](file://fms-vue/src/components/fms-table/utils/createCellRenderer.js#L1-L229)
- [fms-vue/src/components/fms-file/composables/useFileCategory.js:1-77](file://fms-vue/src/components/fms-file/composables/useFileCategory.js#L1-L77)
章节来源
- [fms-vue/package.json:21-34](file://fms-vue/package.json#L21-L34)
## 性能考量
- 表格虚拟滚动
- 行数超过阈值才启用虚拟滚动,避免小数据量下的额外开销。
- 使用 requestAnimationFrame 合并多次尺寸变化,避免动画期间频繁重排。
- 仅宽度变化时只刷新 X 方向虚拟滚动,降低 Y 方向重算成本。
- 编辑态优化
- 使用 WeakMap 存储行编辑态,editingActive 控制是否注入编辑器,减少非编辑态的函数式组件数量。
- 键盘导航期间延迟激活编辑器,合并连续按键,避免频繁挂载/卸载导致掉帧。
- 选择列渲染
- 选择列使用纯 CSS checkbox 模拟,避免每行创建 Checkbox 组件实例,提升滚动性能。
- 表单校验
- validateAll 并行校验,缩短整体校验耗时。
[本节为通用性能指导,无需特定文件引用]
## 故障排查指南
- 表单校验不生效
- 检查 Form 是否正确 provide fms-form,FormItem 是否注册字段。
- 确认 rules 结构与 name 对应,validateTrigger 是否符合预期。
- 表格编辑卡顿
- 确认 large data 场景下 virtual/virtualX 已开启。
- 检查是否频繁更新 columns 或 dataSource 导致整表重建。
- 文件模块解析失败
- 检查 moduleCode 是否存在且可用,查看 moduleError 提示信息。
- 主题不生效
- 确认 applyDarkMode 与 applyPrimaryColor 已调用,CSS 变量已写入 :root。
章节来源
- [fms-vue/src/components/ui/form/Form.vue:94-110](file://fms-vue/src/components/ui/form/Form.vue#L94-L110)
- [fms-vue/src/components/fms-table/FmsTable.vue:41-96](file://fms-vue/src/components/fms-table/FmsTable.vue#L41-L96)
- [fms-vue/src/components/fms-file/FmsFile.vue:27-54](file://fms-vue/src/components/fms-file/FmsFile.vue#L27-L54)
- [fms-vue/src/theme/index.js:1-16](file://fms-vue/src/theme/index.js#L1-L16)
## 结论
FMS 组件系统通过清晰的层次划分、严格的职责边界与完善的通信契约,实现了高内聚、低耦合的可复用组件体系。UI 基础组件提供一致的交互与样式基线,业务组件在此基础上封装领域能力;主题与样式通过 CSS 变量统一管理,便于深浅色与品牌定制;性能优化贯穿关键路径,保障大数据量场景下的流畅体验。配合完善的单元测试与可扩展的文档策略,组件系统具备良好的可维护性与演进能力。
## 附录
### 组件间通信机制
- Props 传递:从父到子的配置型数据(如 type、layout、columns、moduleCode)。
- 事件发射:从子到父的状态变更与用户动作(如 submit、change、uploaded、selected)。
- 状态共享:
- provide/inject:Form 向 FormItem 下发布局与校验上下文。
- Store:FmsTable 读取应用主题状态(darkMode)。
- Composable:useFileCategory 封装分类数据与树转换逻辑。
章节来源
- [fms-vue/src/components/ui/form/Form.vue:94-110](file://fms-vue/src/components/ui/form/Form.vue#L94-L110)
- [fms-vue/src/components/fms-table/FmsTable.vue:52-53](file://fms-vue/src/components/fms-table/FmsTable.vue#L52-L53)
- [fms-vue/src/components/fms-file/composables/useFileCategory.js:1-77](file://fms-vue/src/components/fms-file/composables/useFileCategory.js#L1-L77)
### 样式组织与主题定制
- 样式组织
- 组件级样式使用 scoped SCSS,局部作用域隔离。
- 表格边框与选择框样式通过非 scoped 样式精准覆盖第三方库默认样式。
- 主题定制
- 通过 theme/index.js 的 applyPrimaryColor 与 applyDarkMode 修改 CSS 变量与 dark class。
- 组件消费 --fms-primary、--fms-border、--fms-card 等变量,确保主题一致性。
章节来源
- [fms-vue/src/theme/index.js:1-16](file://fms-vue/src/theme/index.js#L1-L16)
- [fms-vue/src/components/fms-table/FmsTable.vue:600-800](file://fms-vue/src/components/fms-table/FmsTable.vue#L600-L800)
### 组件测试策略
- 框架与工具
- 使用 Vitest 作为测试运行器,@vue/test-utils 进行组件挂载与断言。
- 测试范围
- UI 基础组件:验证 props 映射、事件发射、可访问性属性。
- 表单组件:验证网格布局、span 跨列、必填校验与错误展示。
- 实践建议
- 对交互类组件编写行为测试(点击、输入、键盘)。
- 对渲染类组件断言 class、文本与 DOM 结构。
- 对异步流程使用 flushPromises 与 nextTick 同步状态。
章节来源
- [fms-vue/tests/components/basic.spec.js:1-150](file://fms-vue/tests/components/basic.spec.js#L1-L150)
- [fms-vue/tests/components/form.spec.js:1-128](file://fms-vue/tests/components/form.spec.js#L1-L128)
### 文档生成方法
- 当前仓库未内置自动化文档站点(如 Storybook/VuePress),建议在开发过程中:
- 为每个组件编写 README 或使用 JSDoc 注释描述 props/emits/slots。
- 结合 demo 页面与示例代码,形成可视化文档。
- 参考参考组件库中的文档构建思路,逐步引入文档站点与示例渲染管线。
[本节为通用建议,无需特定文件引用]