SpringBoot+Vue3 企业云盘系统设计:文件上传+共享权限+收藏分类+5GB空间控制——从“网盘孤岛”到“企业知识底座”
🌐 文档地址:http://ruoyioffice.com | 📦 源码1·GitHub:ruoyi-office | 📦 源码2·GitCode:ruoyi-office | 📦 源码3·Gitee:ruoyi-office | 💬 微信:17156169080(备注「RuoYi Office」)
很多企业都有文件管理需求,但真正用起来时,最常见的状态却是:制度文档在网盘、会议纪要在群文件、模板在个人桌面、部门资料在共享盘、审批附件在流程系统。文件明明都“在线化”了,知识却依然是碎片化的。RuoYi Office 的企业云盘不是单纯提供一个上传下载页面,而是通过“文件主数据 + 分享权限 + 收藏视图 + 存储统计”把文件管理变成了企业协同办公的底层能力。
▲ 企业云盘架构全景:前台以我的文件、共享文件、我的收藏为入口,后台由文件主表、权限表、收藏表和统一存储服务协同支撑,兼顾个人管理与团队共享
引言:企业云盘到底难在哪?
“上传个文件还不简单吗?”如果只是个人网盘,这句话没错;但一旦进入企业场景,问题马上变得复杂。
文件不只是“存进去”就完了:企业需要知道文件属于谁、归属哪个部门、是不是共享过、能不能收藏、谁有管理权限。
共享不是简单发链接:有些文件只允许查看,有些允许协作者管理;有些共享的是单个文件,有些共享的是文件夹,还要决定子目录是否继承权限。
空间和权限要可控:如果没有存储配额控制,企业云盘很快就会变成“员工私人影视库”;如果没有所有者约束,任何人都能分享别人文件,安全边界会瞬间失守。
视图不是只有“我的文件”:员工还会关心“别人共享给我的文件”“我收藏过的高频文档”,如果系统只有目录树,没有多视图切换,使用体验会很差。
文件系统必须和 OA 场景打通:制度、模板、公文附件、会议纪要、审批材料,最终都应该在企业统一平台里沉淀,而不是继续散落在多个系统。
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
本文就从 RuoYi Office 的企业云盘模块出发,拆解一套真正适合企业协作的文件管理设计。
一、业务设计:云盘不是网盘,而是协同底座
1.1 企业云盘的三类核心视图
RuoYi Office 没把云盘只做成一个目录页,而是抽象成三种视图:
|
|
|
|---|---|
| 我的文件 |
|
| 共享文件 |
|
| 我的收藏 |
|
这三个视图解决的是三种完全不同的场景:
-
管理自己的资料 -
协同处理别人共享的资料 -
快速复用常用资料
1.2 共享权限为什么必须独立建模?
企业云盘最核心的不是文件本身,而是“谁能以什么方式接触到文件”。
RuoYi Office 专门设计了 oa_file_permission 来表达共享关系:
|
|
|
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
这样共享就从“发一个文件链接”升级成了“有治理能力的协同授权”。
1.3 文件主数据和二进制内容为什么分离?
系统里真正的“文件”其实有两部分:
-
二进制内容:真正的 PDF、Word、图片、视频。 -
元数据:名称、大小、后缀、类别、所有者、所属部门、共享状态等。
RuoYi Office 通过 FileApi 把内容写入统一文件存储,再把元数据写入 oa_file_info。这种做法让云盘既能复用已有存储能力,又能在业务层实现权限和统计。
二、系统设计:三张表如何协同支撑企业云盘?
2.1 模块组成
企业云盘位于 OA → 企业云盘 目录下,核心由三部分组成:
|
|
|
|
|---|---|---|
| 文件主表 |
|
|
| 共享权限表 |
|
|
| 收藏表 |
|
|
2.2 核心设计决策
|
|
|
|
|---|---|---|
|
|
|
|
fileType |
0=文件夹, 1=文件 |
|
|
|
FileApi
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2.3 数据结构关系
|
|
|
|
|---|---|---|
oa_file_info |
|
parent_id
file_type, file_name, file_url, owner_id, is_shared
|
oa_file_permission |
|
file_id
share_type, target_id, permission, inherit_permission, share_path, root_share_id
|
oa_file_favorite |
|
file_id
user_id
|
三、客户端功能实现:PC 主控台 + 移动端随身取用
企业云盘的「治理能力」(上传配额、批量整理、分享给组织/人员、文件夹继承等)主要体现在 PC 端的 Vue3 / Vben 管理中台;移动端则沿用同一套 OA 文件接口,把工作场景延伸到通勤、外出审批、现场确认等碎片化时间——一端治理、多端消费,避免再在微信群、个人盘里复制一份附件。
下方先覆盖 PC,再单独说明移动端能力边界与交互差异。
3.1 企业云盘主页面(PC)
▲ 企业云盘主页面:左侧展示存储空间、文件视图和按分类筛选,右侧是当前文件列表与操作区,同时具备“个人盘”和“团队协作空间”的双重属性
这个页面非常像大家熟悉的网盘产品,但它多了典型的企业属性:
-
左侧不只是目录树,还有空间统计、共享文件、我的收藏、分类筛选。 -
右侧不只是上传下载,还有打开、重命名、收藏、分享、删除等协作操作。 -
文件所有者、是否共享、创建时间等元数据都直接可见。
3.2 文件分享弹窗
▲ 文件分享弹窗:支持按人员或按组织分享,权限可设为仅查看或可管理,并可选择是否向子文件夹继承权限,这才是真正适合企业协作的共享模型
从这个弹窗就能看出它不是“发个链接”那么简单:
-
分享对象可以是员工,也可以是组织。 -
权限分为“仅查看”和“可管理”。 -
文件夹共享可以选择是否把权限继承到子节点。 -
支持备注,方便说明分享背景。
3.3 为什么这一页比普通网盘更像企业系统?
因为普通网盘关注的是“你自己怎么存”,企业云盘更关注的是“团队如何在安全边界内协作”。
3.4 移动端企业云盘(UniApp)
移动端实现位于 ruoyi-office-uniapp,页面 pages-oa/file,调用与 PC 一致的后端能力(/oa/file/... 列表、共享树根、共享子路径、收藏列表等)。数据模型与安全策略与上文三张表完全一致,只是把界面压缩成适合做「单手操作」的流程。
▲ 移动端企业云盘:顶部 我的文件 / 共享文件 / 我的收藏 与 PC 三类视图对齐;列表区展示图标、文件名、所有者与大小,文件夹进入下级,文件可走下载或系统预览链路
移动端当前重点能力与交互要点:
|
|
|
|---|---|
| 三视图 Tab |
|
| 面包屑 |
rootShareId / parentId 状态联动。
|
| 共享目录语义 |
|
| 收藏视图 |
|
| 下拉刷新 |
scroll-view 下拉刷新,弱网下也便于让用户主动重试加载。
|
| 文件取用 |
fileUrl 时:H5 可走新窗口打开直链(与 PC window.open 思路一致);小程序 / App 走 downloadFile + openDocument,由系统预览器接管常见 Office / PDF(具体格式支持取决于运行平台)。
|
| 图标与可读性 |
|
| 深链 Tab
|
onLoad 支持 `?tab=my
|
与 PC 有意区分的定位(可自行截屏配文说明):
- 上传新建、分享弹窗(按人员/组织、查看/管理、继承子目录)、重命名删除、左侧空间环形统计与分类筛选
等「管理类」交互,仍以 PC 为主;移动端不写第二套表单,可避免小屏校验与权限控件维护成本翻倍。 -
若产品后续要在 App 内补齐「拍照上传」「转发到会话」等能力,仍可复用同一套 uploadFile配额校验与FileApi存储,只要把入口收到独立页或浮动按钮即可。
▲ 共享视图下钻或面包屑导航:与 PC「共享路径」语义同源,便于在手机上核对他人共享的资料结构
四、后端核心实现
4.1 上传文件:先校验配额,再交给统一存储服务
FileInfoServiceImpl.uploadFile() 的开头几步非常关键:
public Long uploadFile(MultipartFile file, Long parentId) throws Exception {long maxSize = 100 * 1024 * 1024; // 100MBif (file.getSize() > maxSize) {throw new IllegalArgumentException("上传文件不能超过100M,请压缩后上传");}Long userId = SecurityFrameworkUtils.getLoginUserId();long maxStorageSize = 5L * 1024 * 1024 * 1024; // 5GBLong tenantId = TenantContextHolder.getTenantId();Long usedSize = fileInfoMapper.selectTotalFileSizeByOwnerId(userId, tenantId);if (usedSize + file.getSize() > maxStorageSize) {throw new IllegalArgumentException("存储空间不足");}byte[] content = IoUtil.readBytes(file.getInputStream());String fileUrl = fileApi.createFile(content, file.getOriginalFilename(),"oa/cloud", file.getContentType());}
这里体现了三个企业级设计点:
-
单文件限制,防止大文件滥用。 -
用户级总空间限制,防止整体存储失控。 -
二进制内容交给统一存储服务,不在业务库里硬塞大对象。
4.2 文件元数据建模:目录树、分类、所有者都在一张表里
上传完内容后,系统继续写入元数据:
FileInfoDO fileInfo = new FileInfoDO();fileInfo.setParentId(parentId);fileInfo.setFileType(1); // 1表示文件(0表示文件夹)fileInfo.setFileName(originalFilename);fileInfo.setFileExtension(fileExtension);fileInfo.setFileSuffix(fileSuffix);fileInfo.setFileCategory(fileCategory);fileInfo.setFileSize(file.getSize());fileInfo.setFileUrl(fileUrl);fileInfo.setOwnerId(userId);fileInfo.setOwnerName(systemService.getUserNickname(userId));fileInfoMapper.insert(fileInfo);
这说明云盘的关键不是“存了个 URL”,而是把企业管理真正关心的元信息一起结构化存下来。
4.3 分享文件:只有所有者才能分享
FileShareServiceImpl.shareFile() 的第一步不是插入权限,而是先做所有权校验:
public Integer shareFile(FileShareReqVO shareReqVO) {FileInfoDO fileInfo = fileInfoMapper.selectById(shareReqVO.getFileId());if (fileInfo == null) {throw ServiceExceptionUtil.exception(FILE_INFO_NOT_EXISTS);}Long currentUserId = SecurityFrameworkUtils.getLoginUserId();if (!fileInfo.getOwnerId().equals(currentUserId)) {throw ServiceExceptionUtil.exception(FILE_SHARE_NOT_OWNER);}// ...}
这条规则非常重要。企业协作可以灵活,但权限边界不能模糊。
4.4 分享记录不仅保存权限,还要计算共享路径
这段逻辑决定了共享视图能不能正确展示目录层级:
if (existingPermission != null) {existingPermission.setPermission(target.getPermission());existingPermission.setInheritPermission(shareReqVO.getInheritPermission());filePermissionMapper.updateById(existingPermission);} else {FilePermissionDO permission = new FilePermissionDO();permission.setFileId(shareReqVO.getFileId());permission.setShareType(target.getShareType());permission.setTargetId(target.getTargetId());permission.setPermission(target.getPermission());permission.setInheritPermission(shareReqVO.getInheritPermission());calculateSharePath(permission, fileInfo);filePermissionMapper.insert(permission);}
这不是简单的“授权一条记录”,而是在为后续共享目录浏览、继承权限和根共享节点定位打基础。
4.5 共享路径计算:支持“共享文件夹里的子文件”正确定位
calculateSharePath() 体现了共享目录语义:
private void calculateSharePath(FilePermissionDO permission, FileInfoDO fileInfo) {List<String> pathParts = new ArrayList<>();FileInfoDO current = fileInfo;while (current != null && current.getParentId() != 0) {pathParts.add(0, current.getFileName());FilePermissionDO parentShare = filePermissionMapper.selectByFileIdAndTarget(current.getId(), permission.getShareType(), permission.getTargetId());if (parentShare != null && parentShare.getRootShareId() == null) {permission.setRootShareId(current.getId());break;}current = fileInfoMapper.selectById(current.getParentId());}}
这意味着员工点开“共享文件”时,不会只看到一堆散乱文件,而能沿着共享路径继续下钻。
4.6 收藏逻辑:物理删除比逻辑删除更稳
收藏取消时,代码选择了物理删除:
public void unfavoriteFile(Long fileId, Long userId) {Long tenantId = TenantContextHolder.getTenantId();fileFavoriteMapper.physicalDeleteByFileIdAndUserId(fileId, userId, tenantId);}
为什么这么做?因为收藏关系通常带唯一索引,如果只是逻辑删除,后面再次收藏时很容易撞唯一约束。这个细节非常工程化。
五、前端交互实现:企业云盘为什么更好用?
5.1 三种视图共用一个页面状态机
前端通过 viewMode 区分 list / shared / favorite:
const viewMode = ref<'favorite' | 'list' | 'shared'>('list');const currentParentId = ref<number>(0);const pathStack = ref<Array<{ id: number; name: string }>>([{ id: 0, name: '我的文件' },]);const sharedFileState = ref({rootShareId: 0,parentId: 0,});
这让“我的文件”“共享文件”“我的收藏”三种完全不同的业务视图,可以在一个统一页面里自然切换。
5.2 下载逻辑很克制:文件直接打开,文件夹禁止下载
function handleDownload(row: FileApi.FileInfo) {if (row.fileType === 0) {message.warning('文件夹不支持下载');return;}if (row.fileUrl) {window.open(row.fileUrl, '_blank');}}
这段逻辑很朴素,但非常符合用户心智:文件夹不是下载对象,文件才是。
5.3 存储统计让云盘更像“可治理资源”
页面里直接展示了:
-
已用空间 -
总空间 -
文件数量 -
共享文件数量
这种设计会让员工天然意识到“企业云盘不是无限资源”,从产品层面就完成了一次轻量治理。
六、RuoYi Office 的创新设计
6.1 把“个人盘”和“团队协作盘”做在同一页面
不强迫用户在多个入口间切换,是企业级产品体验非常重要的一点。
6.2 分享权限不是布尔值,而是完整权限模型
按人员、按组织、仅查看、可管理、是否继承,这让云盘真正具备团队协作能力。
6.3 文件元数据天然带组织属性
所有者、部门、共享状态、分类都在元数据层显式保存,为后续统计、治理、审计和 AI 知识化打下基础。
6.4 云盘能力天生适合与 OA / AI 结合
一旦企业云盘建好,后续制度库、审批附件、知识库、AI 文档摘要、在线预览等能力都更容易叠加。
七、数据结构
7.1 oa_file_info
|
|
|
|
|---|---|---|
parent_id |
|
|
file_type |
|
0=文件夹, 1=文件 |
file_name |
|
|
file_category |
|
|
file_url |
|
|
owner_id |
|
|
is_shared |
|
|
7.2 oa_file_permission
|
|
|
|
|---|---|---|
share_type |
|
|
target_id |
|
|
permission |
|
|
inherit_permission |
|
|
share_path |
|
|
root_share_id |
|
|
7.3 oa_file_favorite
|
|
|
|
|---|---|---|
file_id |
|
|
user_id |
|
|
八、技术亮点总结
|
|
|
|
|---|---|---|
|
|
FileApi
|
|
|
|
oa_file_permission |
|
|
|
inheritPermission
|
|
|
|
|
|
|
|
oa_file_favorite |
|
|
|
|
|
|
|
pages-oa/file,复用 OA 接口 + Tab/面包屑/refresh
|
|
九、快速体验
9.1 操作路径
- PC 企业云盘
: OA → 企业云盘 - 移动端(UniApp)
:工作台或 OA 菜单进入 企业云盘(具体入口以各端菜单配置为准;页面路径 pages-oa/file)
9.2 推荐体验流程(PC)
-
上传一个测试文档到“我的文件”。 -
新建一个文件夹并整理资料目录。 -
对某个文件发起分享,分别尝试“按人员分享”和“按组织分享”。 -
在分享弹窗里切换“仅查看/可管理”权限。 -
收藏一个常用文件,切换到“我的收藏”视图查看。 -
查看左侧空间统计和分类筛选效果。
9.3 源码仓库
|
|
|
|---|---|
|
|
ruoyi-office-vben/apps/web-antd/src/views/oa/file |
|
|
ruoyi-office/****-module-oa/.../service/file |
|
|
ruoyi-office-uniapp/src/pages-oa/file |
9.4 移动端(UniApp)体验建议
-
编译运行 ruoyi-office-uniapp,从菜单进入企业云盘页。 -
在「我的文件 / 共享文件 / 我的收藏」三个 Tab 间切换,确认列表与 PC 同源。 -
在「共享文件」中进入被共享的文件夹,用面包屑返回上级,核对与 PC「共享视图」是否一致。 -
点击 PDF 或 Word:H5 观察新窗口或直链打开;微信小程序 观察是否可调起系统文档预览。 -
下拉刷新列表,确认可手动重载。
结语
企业云盘真正的价值,从来不是“能存文件”,而是把文件变成企业知识、协作和流程的底层载体。
RuoYi Office 这套设计之所以值得借鉴,不在于页面像不像某个成熟网盘,而在于它把企业真正关心的东西都做进去了:所有权、共享权限、继承策略、配额治理、多视图访问、跨端协同。也正因为如此,它才能继续往知识库、AI 助手、在线文档预览、审批附件联动这些更高层能力演进。
💡 想要体验 RuoYi Office 的强大功能?
🌐 在线演示:http://ruoyioffice.com/web/(账号 admin / admin123)
💬 技术咨询:添加💬 17156169080,备注「RuoYi Office」
⭐ 如果觉得不错,请给个 Star 支持一下!

