# 文件上传功能 - 前端联调方案 ## 涉及页面 - 文件上传组件(通用,可被任何业务页面引用) - 附件列表展示(通用,可被任何业务页面引用) - 文件预览/下载(通用) ## 业务流程与数据带入 1. **上传文件** → 拿到 `blobId`、`previewURL`、`downloadURL` 2. **保存业务** → 将 `blobId` 列表随业务表单一起提交,后端自动绑定附件关系 3. **查看业务详情** → 通过 `recordType` + `recordId` 查询附件列表,展示预览/下载链接 4. **删除业务** → 后端自动清理附件关系和文件 ## API | 方法 | 路径 | 说明 | |------|------|------| | POST | /admin-api/system/storage-blob/upload | 文件上传(token时效控制) | | POST | /admin-api/system/storage-blob/public-upload | 公共文件上传(永久有效,慎用) | | GET | /admin-api/system/storage-blob/preview/{fileName}?token=xxx | 文件预览(免登录) | | GET | /admin-api/system/storage-blob/preview/{fileName}?publicKey=xxx | 公共文件预览(免登录) | | GET | /admin-api/system/storage-blob/download/{fileName}?token=xxx | 文件下载(免登录) | | GET | /admin-api/system/storage-blob/download/{fileName}?publicKey=xxx | 公共文件下载(免登录) | | GET | /admin-api/system/storage-attachment/list | 查询附件列表 | | POST | /admin-api/system/storage-attachment/bind | 绑定附件到业务记录 | | DELETE | /admin-api/system/storage-attachment/delete | 批量删除附件 | ### 文件上传 **POST** `/admin-api/system/storage-blob/upload` 请求:`multipart/form-data`,字段名 `files`,支持多文件 **响应:** ```json { "code": 0, "data": [ { "id": 1, "resourceKey": "a1b2c3d4e5f6", "contentType": "image/jpeg", "originalFilename": "测试图片.jpg", "uidFilename": "550e8400-e29b-41d4-a716-446655440000_测试图片.jpg", "byteSize": 102400, "path": "2026/0720", "previewURL": "http://localhost:48080/admin-api/system/storage-blob/preview/550e8400-e29b-41d4-a716-446655440000_测试图片.jpg?token=eyJhbGciOiJIUzI1NiJ9...", "url": "http://localhost:48080/admin-api/system/storage-blob/preview/550e8400-e29b-41d4-a716-446655440000_测试图片.jpg?token=eyJhbGciOiJIUzI1NiJ9...", "name": "测试图片.jpg", "downloadURL": "http://localhost:48080/admin-api/system/storage-blob/download/550e8400-e29b-41d4-a716-446655440000_测试图片.jpg?token=eyJhbGciOiJIUzI1NiJ9..." } ] } ``` ### 公共文件上传 **POST** `/admin-api/system/storage-blob/public-upload` 请求同上,返回的 URL 使用 `publicKey` 参数,永久有效: ```json { "code": 0, "data": [ { "id": 2, "resourceKey": "f6e5d4c3b2a1", "previewURL": "http://localhost:48080/admin-api/system/storage-blob/preview/xxx_文件.jpg?publicKey=f6e5d4c3b2a1", "downloadURL": "http://localhost:48080/admin-api/system/storage-blob/download/xxx_文件.jpg?publicKey=f6e5d4c3b2a1" } ] } ``` ### 附件绑定 **POST** `/admin-api/system/storage-attachment/bind` **请求参数:** | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | application | String | 否 | 文件用途(file/image/avatar),不传则从每个 blobItem 中读取 | | recordType | String | 是 | 业务记录类型(对应 StorageRecordTypeEnum) | | recordId | Long | 是 | 业务记录ID | | blobItems | Array | 否 | 待绑定的文件列表 | **blobItems 子项:** | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | blobId | Long | 是 | 上传返回的文件ID | | application | String | 否 | 文件用途(可覆盖外层) | **请求示例:** ```json { "application": "file", "recordType": "common_file", "recordId": 1001, "blobItems": [ { "blobId": 1, "application": "file" }, { "blobId": 2, "application": "image" } ] } ``` **响应:** `{ "code": 0, "data": true }` ### 查询附件列表 **GET** `/admin-api/system/storage-attachment/list` | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | recordType | String | 是 | 业务记录类型 | | recordId | Long | 是 | 业务记录ID | | application | String | 否 | 文件用途(不传则查全部用途) | **响应:** ```json { "code": 0, "data": [ { "id": 1, "resourceKey": "a1b2c3d4e5f6", "contentType": "image/jpeg", "originalFilename": "测试图片.jpg", "uidFilename": "550e8400_测试图片.jpg", "byteSize": 102400, "path": "2026/0720", "previewURL": "http://localhost:48080/admin-api/system/storage-blob/preview/xxx?token=eyJ...", "url": "http://localhost:48080/admin-api/system/storage-blob/preview/xxx?token=eyJ...", "name": "测试图片.jpg", "downloadURL": "http://localhost:48080/admin-api/system/storage-blob/download/xxx?token=eyJ...", "storageAttachmentId": 10, "application": "file" } ] } ``` ### 批量删除附件 **DELETE** `/admin-api/system/storage-attachment/delete` 请求体:`[1, 2, 3]`(storage_attachment 的 ID 列表) **响应:** `{ "code": 0, "data": true }` ## 字段展示规则 | 字段 | 展示位置 | 说明 | |------|----------|------| | originalFilename / name | 文件列表 | 原始文件名,用于展示 | | previewURL / url | 图片缩略图、文件预览 | 点击可预览,浏览器直接打开 | | downloadURL | 下载按钮 | 点击触发下载 | | byteSize | 文件列表 | 文件大小,建议格式化显示(KB/MB) | | contentType | 文件列表 | 可根据类型显示不同图标 | | application | 文件列表分组 | 区分同一记录下不同用途的文件 | ## 业务记录类型枚举(recordType) | 枚举值 | 说明 | |--------|------| | common_file | 通用文件 | | production_order | 生产工单 | | quality_inspect | 质检 | | device_maintenance | 设备维护 | | notice | 通知公告 | | avatar | 头像 | > 后续业务模块如需新增 recordType,需在后端 `StorageRecordTypeEnum` 中添加枚举值。 ## 文件用途枚举(application) | 枚举值 | 说明 | |--------|------| | file | 通用文件 | | image | 图片 | | avatar | 头像 | ## 业务接入示例 ### 1. 上传 + 保存业务(两阶段模式) ``` 步骤1:用户选择文件 → 调用 /storage-blob/upload → 拿到 blobId 列表 步骤2:用户填写业务表单 → 提交时将 blobId 列表一起传给后端 步骤3:后端保存业务数据 + 调用 /storage-attachment/bind 绑定附件 ``` ### 2. 查看业务详情 + 展示附件 ``` 步骤1:加载业务详情 步骤2:调用 /storage-attachment/list?recordType=xxx&recordId=xxx → 获取附件列表 步骤3:展示附件列表(图片用 previewURL 预览,文件用 downloadURL 下载) ``` ### 3. 删除业务 + 清理附件 ``` 后端自动处理:删除业务数据时,同时删除关联的附件记录和磁盘文件 前端无需额外调用删除附件接口 ``` ## 注意事项 - **预览/下载接口免登录**:preview 和 download 接口使用 `@PermitAll`,通过 URL 中的 token 或 publicKey 鉴权,前端直接用 `` 或 `window.open(downloadURL)` 即可 - **token 时效**:普通上传的预览/下载链接默认 120 分钟有效,且限制使用 10 次。如需永久链接,使用 `/public-upload` 接口 - **图片压缩**:后端自动对超过 10MB 的 jpg/jpeg/png 图片进行压缩,预览时返回压缩版本,下载时返回原图 - **多文件上传**:upload 接口支持一次上传多个文件,字段名 `files` - **附件绑定是替换模式**:调用 bind 接口时,会先删除该记录下同用途的旧附件,再插入新附件 - **同一记录多组附件**:使用 `application` 字段区分,如同一工单下既有"图片"又有"文件" - **权限控制**:附件查询需要 `system:storage-attachment:query`,绑定需要 `system:storage-attachment:create`,删除需要 `system:storage-attachment:delete`