21 KiB
21 KiB
前端文件组件
**本文引用的文件** - [FmsFile.vue](file://fms-vue/src/components/fms-file/FmsFile.vue) - [FileCategoryPanel.vue](file://fms-vue/src/components/fms-file/FileCategoryPanel.vue) - [FileListPanel.vue](file://fms-vue/src/components/fms-file/FileListPanel.vue) - [FilePreviewPanel.vue](file://fms-vue/src/components/fms-file/FilePreviewPanel.vue) - [useFileCategory.js](file://fms-vue/src/components/fms-file/composables/useFileCategory.js) - [fileVisual.js](file://fms-vue/src/components/fms-file/fileVisual.js) - [fileService.js](file://fms-vue/src/services/fileService.js) - [api.js](file://fms-vue/src/services/api.js) - [index.vue(文件演示)](file://fms-vue/src/views/file-demo/index.vue)目录
简介
本组件是一套面向业务系统的“三栏布局”文件管理方案:左侧分类树、中间文件列表、右侧预览面板。通过 FmsFile 主组件编排,配合 FileCategoryPanel、FileListPanel、FilePreviewPanel 三个子组件以及 useFileCategory 组合式函数,实现分类加载、文件分页展示、拖拽/粘贴上传、批量选择与删除、在线预览等能力。整体设计强调低耦合、可复用、易扩展,并内置本地存储与阿里云 OSS 两种上传模式的自动适配。
项目结构
- 入口与编排:FmsFile.vue 负责模块解析、三栏布局、状态协调与事件透传。
- 分类管理:useFileCategory.js 提供分类数据获取、扁平转树、选中态管理;FileCategoryPanel.vue 基于 Tree 渲染分类树。
- 文件列表:FileListPanel.vue 负责分页查询、视图切换、选择/删除/下载、拖拽/粘贴上传、待上传队列与已上传列表合并展示。
- 预览面板:FilePreviewPanel.vue 根据文件类型进行图片直显或通用信息展示,并提供前后翻页导航。
- 工具与服务:fileVisual.js 提供扩展名颜色、大小格式化、图片类型判断;fileService.js 封装上传、凭证缓存、预览地址与删除;api.js 提供通用数据加载与分页接口。
graph TB
A["FmsFile.vue"] --> B["FileCategoryPanel.vue"]
A --> C["FileListPanel.vue"]
A --> D["FilePreviewPanel.vue"]
A --> E["useFileCategory.js"]
C --> F["fileService.js"]
C --> G["api.js"]
D --> F
B --> E
图表来源
- FmsFile.vue:1-134
- FileCategoryPanel.vue:1-48
- FileListPanel.vue:1-133
- FilePreviewPanel.vue:1-39
- useFileCategory.js:1-77
- fileService.js:1-149
- api.js:1-81
章节来源
- FmsFile.vue:1-134
- FileCategoryPanel.vue:1-48
- FileListPanel.vue:1-133
- FilePreviewPanel.vue:1-39
- useFileCategory.js:1-77
- fileService.js:1-149
- api.js:1-81
核心组件
- FmsFile.vue:主容器,负责模块编码到模块ID的解析、三栏 Splitter 布局、分类树展开态、当前选中文件、事件透传(uploaded/deleted/selected)。
- FileCategoryPanel.vue:封装 Tree 组件,处理根节点“全部分类”的特殊选择逻辑,向上抛出 select 与 expandedKeys 更新。
- FileListPanel.vue:文件列表核心,包含分页、选择、上传(拖拽/粘贴/选择)、删除、下载、网格/列表视图切换、空态与确认弹窗。
- FilePreviewPanel.vue:预览面板,支持图片直显与非图片类型的通用信息展示,提供上下翻页。
- useFileCategory.js:分类数据加载、扁平转树、选中键维护。
- fileVisual.js:扩展名颜色映射、图片类型判断、文件大小格式化。
- fileService.js:上传(本地/OSS自动适配)、凭证缓存、预览URL、删除。
- api.js:通用数据加载与分页接口封装。
章节来源
- FmsFile.vue:12-134
- FileCategoryPanel.vue:6-29
- FileListPanel.vue:35-133
- FilePreviewPanel.vue:8-39
- useFileCategory.js:9-77
- fileVisual.js:40-63
- fileService.js:20-149
- api.js:17-52
架构总览
FmsFile 作为编排者,将模块编码解析为模块ID后,驱动分类树与文件列表联动;FileListPanel 在父/模块/分类条件变化时重新拉取数据;FilePreviewPanel 根据当前选中文件计算预览URL与类型,提供导航。
sequenceDiagram
participant U as "用户"
participant MF as "FmsFile.vue"
participant FC as "FileCategoryPanel.vue"
participant FL as "FileListPanel.vue"
participant FP as "FilePreviewPanel.vue"
participant API as "api.js / fileService.js"
U->>MF : 传入 moduleCode/father
MF->>API : 解析模块ID
MF->>FC : 加载分类树
FC-->>MF : 选中分类key
MF->>FL : 传递 father/moduleId/cateId
FL->>API : 分页查询 bf_files
API-->>FL : rows/total
U->>FL : 点击文件
FL-->>MF : 触发 preview(file)
MF->>FP : 设置 selectedFile
FP->>API : getPreviewUrl(file)
API-->>FP : 预览URL
FP-->>U : 显示预览
图表来源
- FmsFile.vue:27-68
- FileCategoryPanel.vue:19-29
- FileListPanel.vue:91-133
- FilePreviewPanel.vue:27-39
- api.js:17-52
- fileService.js:135-143
详细组件分析
FmsFile.vue 主组件
- 职责
- 模块解析:根据 moduleCode 调用 loadDataApi 查询 s_module,得到 moduleId,失败则提示错误。
- 三栏布局:使用 Splitter 组件划分左(分类树)、中(文件列表)、右(预览),默认宽度分别为 220px、500px、剩余空间,支持最小宽度限制。
- 分类联动:监听分类选择,计算 activeCateId 并传递给 FileListPanel;维护分类树展开键。
- 预览联动:接收 FileListPanel 的 preview 事件,设置 selectedFile,并向 FilePreviewPanel 传递当前文件与文件列表,提供 prev/next 导航。
- 事件透传:将 uploaded/deleted/selected 事件向上传递给父级。
- 关键流程
- 挂载时解析模块并加载分类,若存在 initialCateId 则预选并展开对应节点。
- 通过 computed 派生 ready 状态控制加载与错误提示。
flowchart TD
Start(["组件挂载"]) --> Resolve["解析模块ID"]
Resolve --> LoadCate["加载分类树"]
LoadCate --> InitTree["初始化展开键"]
InitTree --> Render["渲染三栏布局"]
Render --> SelectCate{"分类选择?"}
SelectCate -- 是 --> UpdateCate["更新 activeCateId"]
UpdateCate --> RefreshList["刷新文件列表"]
SelectCate -- 否 --> WaitEvent["等待事件"]
RefreshList --> WaitEvent
WaitEvent --> Preview{"预览文件?"}
Preview -- 是 --> ShowPrev["设置 selectedFile<br/>通知预览面板"]
ShowPrev --> Nav{"上一个/下一个?"}
Nav -- 是 --> ChangeFile["切换文件并emit selected"]
Nav -- 否 --> End(["结束"])
图表来源
章节来源
FileCategoryPanel.vue 分类面板
- 职责
- 渲染 Tree,绑定 treeData、selectedKeys、expandedKeys。
- 特殊处理根节点“全部分类”:当选择根节点时,向上 emit('select', ''),表示不筛选分类。
- 同步展开态:通过 update:expanded-keys 将展开键回传给父组件。
- 数据结构
- treeData 由 useFileCategory 提供,包含一个固定根节点 key="fms_tree_root",其 children 为所有启用分类。
classDiagram
class FileCategoryPanel {
+props treeData : Array
+props loading : Boolean
+props selectedKey : String
+props expandedKeys : Array
+emit select(key)
+emit update : expandedKeys(keys)
}
class Tree {
+props tree-data
+props selected-keys
+props expanded-keys
}
FileCategoryPanel --> Tree : "渲染分类树"
图表来源
章节来源
FileListPanel.vue 文件列表
- 职责
- 数据加载:根据 father、moduleId、cateId 构建查询条件,调用 pageDataApi 分页加载 bf_files。
- 数据归一化:将 subid、father、mx_moduleid、mx_cate_id 统一转为字符串,mx_filesize 转为数字。
- 视图模式:支持网格(卡片)与列表(手写表格)两种展示。
- 选择与全选:维护 selectedFileIds Set,支持 indeterminate 状态。
- 上传:支持拖拽、粘贴、选择文件,生成 pendingFiles 队列与图片 blobUrl 预览;提交时调用 fileService.upload,成功后清空队列并刷新列表。
- 删除:支持批量与单项删除,待上传文件直接从队列移除,已上传文件调用 removeFile。
- 下载:通过 getPreviewUrl 生成链接并触发浏览器下载。
- 空态与加载态:Spin 包裹内容,无数据时显示空态提示。
- 关键流程
- 监听 father/moduleId/cateId 变化,重置选择与队列,重新加载数据。
- 上传完成后触发 uploaded 事件,供父组件刷新分类或列表。
sequenceDiagram
participant FL as "FileListPanel.vue"
participant API as "api.js"
participant FS as "fileService.js"
participant UI as "UI交互"
UI->>FL : 选择/拖拽/粘贴文件
FL->>FL : 加入 pendingFiles/blobs
UI->>FL : 点击上传
FL->>FS : upload({files, father, moduleId, cateId})
FS-->>FL : 返回记录列表
FL->>API : pageDataApi(刷新列表)
API-->>FL : rows/total
FL-->>UI : 显示新列表
图表来源
章节来源
FilePreviewPanel.vue 预览面板
- 职责
- 计算当前文件索引与总数,提供上一个/下一个导航。
- 根据扩展名判断是否为图片类型,若是则直接 img 显示;否则展示通用信息(文件名、大小、扩展名)。
- 通过 getPreviewUrl 获取预览地址。
- 交互
- 通过 prev/next 事件与父组件联动,实现连续浏览。
flowchart TD
PStart(["进入预览"]) --> CheckFile{"是否有选中文件?"}
CheckFile -- 否 --> Empty["显示空态提示"]
CheckFile -- 是 --> CalcIdx["计算当前索引"]
CalcIdx --> IsImage{"是否图片类型?"}
IsImage -- 是 --> Img["显示图片"]
IsImage -- 否 --> Generic["显示通用信息"]
Img --> Nav{"上一个/下一个?"}
Generic --> Nav
Nav -- 是 --> EmitNav["emit prev/next"]
Nav -- 否 --> End(["结束"])
图表来源
章节来源
useFileCategory.js 分类组合式
- 职责
- 加载启用分类:调用 loadDataApi 查询 bf_files_cateid,过滤 b_canuse=1,按排序返回。
- 扁平转树:将分类数组转换为 Tree 所需的 children,并在最外层添加固定根节点 key="fms_tree_root",title="全部分类"。
- 选中态管理:维护 selectedKey,提供 selectCategory 方法。
- 查找分类:提供 findCategory 方法用于按 key 查找原始数据。
- 数据流
- categories -> treeData(computed)-> FileCategoryPanel 渲染。
- selectedKey -> 父组件计算 activeCateId -> FileListPanel 过滤条件。
flowchart TD
CStart(["loadCategories"]) --> Fetch["请求 bf_files_cateid"]
Fetch --> Map["映射为树节点(children)"]
Map --> Root["前置根节点 '__fms_tree_root__'"]
Root --> TreeData["treeData(computed)"]
TreeData --> Panel["FileCategoryPanel 渲染"]
Panel --> Select{"选择分类?"}
Select -- 是 --> SelKey["selectCategory(key)"]
SelKey --> Parent["父组件计算 activeCateId"]
Parent --> List["FileListPanel 刷新"]
图表来源
章节来源
工具与服务
- fileVisual.js
- extFromName:从文件名提取扩展名。
- extColor:根据扩展名返回语义色。
- isImageType:判断是否为图片类型。
- formatSize:格式化文件大小。
- fileService.js
- initFileConfig/getStorageType:初始化并获取存储模式(local/aliyun-oss)。
- upload:根据存储模式选择本地或OSS上传;OSS路径会获取凭证并直传,再回调保存记录。
- getPreviewUrl:返回 mx_mapfilename 作为预览/下载地址。
- removeFile:删除文件记录。
- api.js
- loadDataApi/pageDataApi:通用数据加载与分页接口。
章节来源
依赖关系分析
- FmsFile.vue 依赖 Splitter、Spin、Tree、Message、Modal 等UI组件,以及 api.js、fileService.js。
- FileListPanel.vue 依赖 ui 组件库(Button、Checkbox、Pagination、Modal、Tooltip、Tag、Spin),fileService.js、api.js、fileVisual.js。
- FilePreviewPanel.vue 依赖 fileService.js、fileVisual.js。
- useFileCategory.js 依赖 api.js。
graph LR
F["FmsFile.vue"] --> S["Splitter/Spin"]
F --> T["Tree"]
F --> M["Modal/Message"]
F --> A["api.js"]
F --> FS["fileService.js"]
L["FileListPanel.vue"] --> UI["ui组件库"]
L --> FS
L --> A
L --> V["fileVisual.js"]
P["FilePreviewPanel.vue"] --> FS
P --> V
U["useFileCategory.js"] --> A
图表来源
章节来源
性能与响应式优化
- 分页加载:FileListPanel 使用 pageDataApi 分页,避免一次性加载大量数据。
- 虚拟滚动建议:若文件数量极大,可在列表层引入虚拟滚动策略(当前为原生滚动)。
- 图片预览优化:仅对图片类型创建 blobUrl,非图片不创建,减少内存占用。
- 上传队列:pendingFiles 与 pendingBlobUrls 分离管理,上传完成后统一清理,避免内存泄漏。
- 分隔条命中区:通过伪元素扩展 Splitter 拖拽热区,提升交互体验且不挤压面板。
- 样式变量:使用 CSS 变量(如 --fms-card、--fms-border)统一主题,便于深浅色切换。
- 响应式布局:Splitter 面板设置 min/max 尺寸,确保在不同屏幕下可用;Grid 布局自适应列数。
[本节为通用指导,不直接分析具体文件]
使用示例与配置
- 内嵌用法
- 在页面中引入 FmsFile,传入 moduleCode、father、showTree 等 props,并监听 uploaded/deleted/selected 事件。
- 示例参考:views/file-demo/index.vue 中的内嵌区域。
- 弹窗用法
- 声明式:使用 FmsFileModal 组件,通过 v-model:open 控制显示。
- 命令式:使用 useFileModal().open() 动态打开,支持 onUploaded/onDeleted/onSelected 回调。
- Props 说明
- moduleCode:必填,模块编码,用于解析 moduleId。
- father:必填,业务ID,用于文件归属。
- showTree:可选,是否显示分类树,默认 true。
- readonly:可选,只读模式,禁用上传/删除等操作。
- initialCateId:可选,初始选中的分类ID。
- 事件处理
- uploaded:文件上传成功。
- deleted:文件删除完成。
- selected:文件被选中预览。
- 样式定制
- 通过 CSS 变量覆盖主题色、边框、背景等。
- 调整 Splitter 面板默认尺寸与最小宽度以适配不同场景。
章节来源
故障排查
- 模块解析失败
- 现象:显示“未找到模块”或“模块解析失败”。
- 原因:moduleCode 无效或服务端异常。
- 处理:检查 moduleCode 是否正确,查看 loadDataApi 返回结果。
- 分类加载失败
- 现象:分类树为空或报错。
- 原因:bf_files_cateid 查询失败或无启用分类。
- 处理:检查 loadDataApi 调用与后端数据。
- 上传失败
- 现象:提示“上传失败”,或无消息。
- 原因:服务端不可达/5xx已由http拦截器统一弹 Message;OSS凭证过期或直传失败。
- 处理:检查网络、凭证缓存、fileService.upload 返回值。
- 删除失败
- 现象:提示“删除失败”。
- 原因:removeFile 调用失败。
- 处理:检查后端接口与权限。
- 预览空白
- 现象:预览面板无内容。
- 原因:文件非图片且无预览URL,或文件未选中。
- 处理:确认 selectedFile 与 getPreviewUrl 返回值。
章节来源
- FmsFile.vue:27-54
- useFileCategory.js:16-35
- FileListPanel.vue:233-258
- FileListPanel.vue:280-339
- fileService.js:87-108
结论
该文件管理组件通过清晰的三栏布局与模块化拆分,实现了分类筛选、文件列表操作与多格式预览的完整闭环。useFileCategory 将分类逻辑抽离,便于复用与维护;FileListPanel 兼顾多种交互方式与状态管理;FilePreviewPanel 聚焦预览体验。结合 fileService 的存储模式自动适配与凭证缓存,整体具备良好的可扩展性与稳定性。建议在大数据量场景下进一步引入虚拟滚动与懒加载,以提升性能。