# 前端文件组件 **本文引用的文件** - [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) ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖关系分析](#依赖关系分析) 7. [性能与响应式优化](#性能与响应式优化) 8. [使用示例与配置](#使用示例与配置) 9. [故障排查](#故障排查) 10. [结论](#结论) ## 简介 本组件是一套面向业务系统的“三栏布局”文件管理方案:左侧分类树、中间文件列表、右侧预览面板。通过 FmsFile 主组件编排,配合 FileCategoryPanel、FileListPanel、FilePreviewPanel 三个子组件以及 useFileCategory 组合式函数,实现分类加载、文件分页展示、拖拽/粘贴上传、批量选择与删除、在线预览等能力。整体设计强调低耦合、可复用、易扩展,并内置本地存储与阿里云 OSS 两种上传模式的自动适配。 ## 项目结构 - 入口与编排:FmsFile.vue 负责模块解析、三栏布局、状态协调与事件透传。 - 分类管理:useFileCategory.js 提供分类数据获取、扁平转树、选中态管理;FileCategoryPanel.vue 基于 Tree 渲染分类树。 - 文件列表:FileListPanel.vue 负责分页查询、视图切换、选择/删除/下载、拖拽/粘贴上传、待上传队列与已上传列表合并展示。 - 预览面板:FilePreviewPanel.vue 根据文件类型进行图片直显或通用信息展示,并提供前后翻页导航。 - 工具与服务:fileVisual.js 提供扩展名颜色、大小格式化、图片类型判断;fileService.js 封装上传、凭证缓存、预览地址与删除;api.js 提供通用数据加载与分页接口。 ```mermaid 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](file://fms-vue/src/components/fms-file/FmsFile.vue#L1-L134) - [FileCategoryPanel.vue:1-48](file://fms-vue/src/components/fms-file/FileCategoryPanel.vue#L1-L48) - [FileListPanel.vue:1-133](file://fms-vue/src/components/fms-file/FileListPanel.vue#L1-L133) - [FilePreviewPanel.vue:1-39](file://fms-vue/src/components/fms-file/FilePreviewPanel.vue#L1-L39) - [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) - [api.js:1-81](file://fms-vue/src/services/api.js#L1-L81) 章节来源 - [FmsFile.vue:1-134](file://fms-vue/src/components/fms-file/FmsFile.vue#L1-L134) - [FileCategoryPanel.vue:1-48](file://fms-vue/src/components/fms-file/FileCategoryPanel.vue#L1-L48) - [FileListPanel.vue:1-133](file://fms-vue/src/components/fms-file/FileListPanel.vue#L1-L133) - [FilePreviewPanel.vue:1-39](file://fms-vue/src/components/fms-file/FilePreviewPanel.vue#L1-L39) - [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) - [api.js:1-81](file://fms-vue/src/services/api.js#L1-L81) ## 核心组件 - 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](file://fms-vue/src/components/fms-file/FmsFile.vue#L12-L134) - [FileCategoryPanel.vue:6-29](file://fms-vue/src/components/fms-file/FileCategoryPanel.vue#L6-L29) - [FileListPanel.vue:35-133](file://fms-vue/src/components/fms-file/FileListPanel.vue#L35-L133) - [FilePreviewPanel.vue:8-39](file://fms-vue/src/components/fms-file/FilePreviewPanel.vue#L8-L39) - [useFileCategory.js:9-77](file://fms-vue/src/components/fms-file/composables/useFileCategory.js#L9-L77) - [fileVisual.js:40-63](file://fms-vue/src/components/fms-file/fileVisual.js#L40-L63) - [fileService.js:20-149](file://fms-vue/src/services/fileService.js#L20-L149) - [api.js:17-52](file://fms-vue/src/services/api.js#L17-L52) ## 架构总览 FmsFile 作为编排者,将模块编码解析为模块ID后,驱动分类树与文件列表联动;FileListPanel 在父/模块/分类条件变化时重新拉取数据;FilePreviewPanel 根据当前选中文件计算预览URL与类型,提供导航。 ```mermaid 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](file://fms-vue/src/components/fms-file/FmsFile.vue#L27-L68) - [FileCategoryPanel.vue:19-29](file://fms-vue/src/components/fms-file/FileCategoryPanel.vue#L19-L29) - [FileListPanel.vue:91-133](file://fms-vue/src/components/fms-file/FileListPanel.vue#L91-L133) - [FilePreviewPanel.vue:27-39](file://fms-vue/src/components/fms-file/FilePreviewPanel.vue#L27-L39) - [api.js:17-52](file://fms-vue/src/services/api.js#L17-L52) - [fileService.js:135-143](file://fms-vue/src/services/fileService.js#L135-L143) ## 详细组件分析 ### FmsFile.vue 主组件 - 职责 - 模块解析:根据 moduleCode 调用 loadDataApi 查询 s_module,得到 moduleId,失败则提示错误。 - 三栏布局:使用 Splitter 组件划分左(分类树)、中(文件列表)、右(预览),默认宽度分别为 220px、500px、剩余空间,支持最小宽度限制。 - 分类联动:监听分类选择,计算 activeCateId 并传递给 FileListPanel;维护分类树展开键。 - 预览联动:接收 FileListPanel 的 preview 事件,设置 selectedFile,并向 FilePreviewPanel 传递当前文件与文件列表,提供 prev/next 导航。 - 事件透传:将 uploaded/deleted/selected 事件向上传递给父级。 - 关键流程 - 挂载时解析模块并加载分类,若存在 initialCateId 则预选并展开对应节点。 - 通过 computed 派生 ready 状态控制加载与错误提示。 ```mermaid 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
通知预览面板"] ShowPrev --> Nav{"上一个/下一个?"} Nav -- 是 --> ChangeFile["切换文件并emit selected"] Nav -- 否 --> End(["结束"]) ``` 图表来源 - [FmsFile.vue:27-68](file://fms-vue/src/components/fms-file/FmsFile.vue#L27-L68) - [FmsFile.vue:78-129](file://fms-vue/src/components/fms-file/FmsFile.vue#L78-L129) - [FmsFile.vue:147-193](file://fms-vue/src/components/fms-file/FmsFile.vue#L147-L193) 章节来源 - [FmsFile.vue:12-134](file://fms-vue/src/components/fms-file/FmsFile.vue#L12-L134) - [FmsFile.vue:136-193](file://fms-vue/src/components/fms-file/FmsFile.vue#L136-L193) ### FileCategoryPanel.vue 分类面板 - 职责 - 渲染 Tree,绑定 treeData、selectedKeys、expandedKeys。 - 特殊处理根节点“全部分类”:当选择根节点时,向上 emit('select', ''),表示不筛选分类。 - 同步展开态:通过 update:expanded-keys 将展开键回传给父组件。 - 数据结构 - treeData 由 useFileCategory 提供,包含一个固定根节点 key="__fms_tree_root__",其 children 为所有启用分类。 ```mermaid 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 : "渲染分类树" ``` 图表来源 - [FileCategoryPanel.vue:6-29](file://fms-vue/src/components/fms-file/FileCategoryPanel.vue#L6-L29) - [useFileCategory.js:37-54](file://fms-vue/src/components/fms-file/composables/useFileCategory.js#L37-L54) 章节来源 - [FileCategoryPanel.vue:6-48](file://fms-vue/src/components/fms-file/FileCategoryPanel.vue#L6-L48) ### 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 事件,供父组件刷新分类或列表。 ```mermaid 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 : 显示新列表 ``` 图表来源 - [FileListPanel.vue:91-133](file://fms-vue/src/components/fms-file/FileListPanel.vue#L91-L133) - [FileListPanel.vue:167-258](file://fms-vue/src/components/fms-file/FileListPanel.vue#L167-L258) - [fileService.js:20-85](file://fms-vue/src/services/fileService.js#L20-L85) 章节来源 - [FileListPanel.vue:35-133](file://fms-vue/src/components/fms-file/FileListPanel.vue#L35-L133) - [FileListPanel.vue:155-258](file://fms-vue/src/components/fms-file/FileListPanel.vue#L155-L258) - [FileListPanel.vue:280-369](file://fms-vue/src/components/fms-file/FileListPanel.vue#L280-L369) ### FilePreviewPanel.vue 预览面板 - 职责 - 计算当前文件索引与总数,提供上一个/下一个导航。 - 根据扩展名判断是否为图片类型,若是则直接 img 显示;否则展示通用信息(文件名、大小、扩展名)。 - 通过 getPreviewUrl 获取预览地址。 - 交互 - 通过 prev/next 事件与父组件联动,实现连续浏览。 ```mermaid 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(["结束"]) ``` 图表来源 - [FilePreviewPanel.vue:15-39](file://fms-vue/src/components/fms-file/FilePreviewPanel.vue#L15-L39) - [FilePreviewPanel.vue:41-95](file://fms-vue/src/components/fms-file/FilePreviewPanel.vue#L41-L95) 章节来源 - [FilePreviewPanel.vue:8-39](file://fms-vue/src/components/fms-file/FilePreviewPanel.vue#L8-L39) - [FilePreviewPanel.vue:41-95](file://fms-vue/src/components/fms-file/FilePreviewPanel.vue#L41-L95) ### 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 过滤条件。 ```mermaid 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 刷新"] ``` 图表来源 - [useFileCategory.js:16-54](file://fms-vue/src/components/fms-file/composables/useFileCategory.js#L16-L54) - [useFileCategory.js:62-64](file://fms-vue/src/components/fms-file/composables/useFileCategory.js#L62-L64) 章节来源 - [useFileCategory.js:9-77](file://fms-vue/src/components/fms-file/composables/useFileCategory.js#L9-L77) ### 工具与服务 - fileVisual.js - extFromName:从文件名提取扩展名。 - extColor:根据扩展名返回语义色。 - isImageType:判断是否为图片类型。 - formatSize:格式化文件大小。 - fileService.js - initFileConfig/getStorageType:初始化并获取存储模式(local/aliyun-oss)。 - upload:根据存储模式选择本地或OSS上传;OSS路径会获取凭证并直传,再回调保存记录。 - getPreviewUrl:返回 mx_mapfilename 作为预览/下载地址。 - removeFile:删除文件记录。 - api.js - loadDataApi/pageDataApi:通用数据加载与分页接口。 章节来源 - [fileVisual.js:40-63](file://fms-vue/src/components/fms-file/fileVisual.js#L40-L63) - [fileService.js:8-149](file://fms-vue/src/services/fileService.js#L8-L149) - [api.js:17-52](file://fms-vue/src/services/api.js#L17-L52) ## 依赖关系分析 - 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。 ```mermaid 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 ``` 图表来源 - [FmsFile.vue:1-10](file://fms-vue/src/components/fms-file/FmsFile.vue#L1-L10) - [FileListPanel.vue:1-34](file://fms-vue/src/components/fms-file/FileListPanel.vue#L1-L34) - [FilePreviewPanel.vue:1-7](file://fms-vue/src/components/fms-file/FilePreviewPanel.vue#L1-L7) - [useFileCategory.js:1-3](file://fms-vue/src/components/fms-file/composables/useFileCategory.js#L1-L3) 章节来源 - [FmsFile.vue:1-10](file://fms-vue/src/components/fms-file/FmsFile.vue#L1-L10) - [FileListPanel.vue:1-34](file://fms-vue/src/components/fms-file/FileListPanel.vue#L1-L34) - [FilePreviewPanel.vue:1-7](file://fms-vue/src/components/fms-file/FilePreviewPanel.vue#L1-L7) - [useFileCategory.js:1-3](file://fms-vue/src/components/fms-file/composables/useFileCategory.js#L1-L3) ## 性能与响应式优化 - 分页加载: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 面板默认尺寸与最小宽度以适配不同场景。 章节来源 - [index.vue(文件演示):13-151](file://fms-vue/src/views/file-demo/index.vue#L13-L151) - [FmsFile.vue:12-18](file://fms-vue/src/components/fms-file/FmsFile.vue#L12-L18) - [FmsFile.vue:147-193](file://fms-vue/src/components/fms-file/FmsFile.vue#L147-L193) ## 故障排查 - 模块解析失败 - 现象:显示“未找到模块”或“模块解析失败”。 - 原因:moduleCode 无效或服务端异常。 - 处理:检查 moduleCode 是否正确,查看 loadDataApi 返回结果。 - 分类加载失败 - 现象:分类树为空或报错。 - 原因:bf_files_cateid 查询失败或无启用分类。 - 处理:检查 loadDataApi 调用与后端数据。 - 上传失败 - 现象:提示“上传失败”,或无消息。 - 原因:服务端不可达/5xx已由http拦截器统一弹 Message;OSS凭证过期或直传失败。 - 处理:检查网络、凭证缓存、fileService.upload 返回值。 - 删除失败 - 现象:提示“删除失败”。 - 原因:removeFile 调用失败。 - 处理:检查后端接口与权限。 - 预览空白 - 现象:预览面板无内容。 - 原因:文件非图片且无预览URL,或文件未选中。 - 处理:确认 selectedFile 与 getPreviewUrl 返回值。 章节来源 - [FmsFile.vue:27-54](file://fms-vue/src/components/fms-file/FmsFile.vue#L27-L54) - [useFileCategory.js:16-35](file://fms-vue/src/components/fms-file/composables/useFileCategory.js#L16-L35) - [FileListPanel.vue:233-258](file://fms-vue/src/components/fms-file/FileListPanel.vue#L233-L258) - [FileListPanel.vue:280-339](file://fms-vue/src/components/fms-file/FileListPanel.vue#L280-L339) - [fileService.js:87-108](file://fms-vue/src/services/fileService.js#L87-L108) ## 结论 该文件管理组件通过清晰的三栏布局与模块化拆分,实现了分类筛选、文件列表操作与多格式预览的完整闭环。useFileCategory 将分类逻辑抽离,便于复用与维护;FileListPanel 兼顾多种交互方式与状态管理;FilePreviewPanel 聚焦预览体验。结合 fileService 的存储模式自动适配与凭证缓存,整体具备良好的可扩展性与稳定性。建议在大数据量场景下进一步引入虚拟滚动与懒加载,以提升性能。