本文档基于以下实现整理:
src/components/AttachmentUpload/file/index.vuesrc/components/AttachmentUpload/image/index.vuesrc/components/AttachmentPreview/image/index.vuesrc/components/Dialog/FileList.vuesrc/api/basicData/common.jssrc/api/publicApi/commonFile.js相关组件已在 src/main.js 中注册为全局组件,可直接在页面中使用:
FileUploadImageUploadImagePreviewFileListDialog当前这套上传能力主要分为 4 部分:
FileUpload:普通文件上传,支持拖拽、批量上传、预览、删除ImageUpload:图片上传,支持图片墙展示、预览、删除ImagePreview:图片列表预览展示FileListDialog:业务附件弹窗,支持查询、上传、删除、下载上传底层统一走接口:
POST /common/upload对应方法在 src/api/basicData/common.js:
uploadFile(data)
文件上传组件和图片上传组件都调用了:
import { uploadFile } from '@/api/basicData/common'
接口特征:
POST/common/uploadmultipart/form-dataFormData 批量上传files组件内部会这样组装参数:
const formData = new FormData()
validFiles.forEach((file) => {
formData.append(props.uploadFieldName, file.raw)
})
上传成功后,组件会尝试从以下结构中提取数组:
responseresponse.dataresponse.data.dataresponse.payloadresponse.payload.dataresponse.rowsresponse.result因此后端返回数组时,上面任意一种结构都可以被识别。
组件展示时常用到的字段有:
name / originalFilename / fileName / uidFilenameurl / downloadURLurl / previewURL / previewUrlid建议上传接口返回的单项对象尽量包含:
{
id: 1,
originalFilename: 'demo.pdf',
downloadURL: 'https://xxx/demo.pdf',
previewURL: 'https://xxx/demo.png'
}
组件路径:
src/components/AttachmentUpload/file/index.vue
<template>
<FileUpload v-model:file-list="fileList" />
</template>
<script setup>
import { ref } from 'vue'
const fileList = ref([])
</script>
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
fileList |
绑定文件列表 | Array |
[] |
limit |
最大上传数量 | Number |
10 |
fileSize |
单个文件大小限制,单位 MB | Number |
50 |
fileType |
允许上传的文件类型,如 ['pdf', 'docx'] |
Array |
[] |
buttonText |
上传提示文案 | String |
单击选择文件 |
disabled |
是否禁用 | Boolean |
false |
uploadFieldName |
FormData 字段名 |
String |
files |
index |
表格/列表行模式下的当前行索引 | Number |
-1 |
childrenKey |
行内挂载字段名 | String |
files |
| 事件 | 说明 |
|---|---|
update:fileList |
文件列表变化时触发 |
change |
文件列表变化时触发,返回最新列表 |
组件内已实现:
例如限制 PDF/Word:
<FileUpload
v-model:file-list="fileList"
:limit="5"
:file-size="20"
:file-type="['pdf', 'doc', 'docx']"
/>
FileUpload 更适合接收这样的列表:
[
{
id: 1,
originalFilename: '合同.pdf',
downloadURL: 'https://xxx/contract.pdf'
}
]
因为组件打开文件时会优先读取:
url || downloadURL || previewURL || previewUrl
如果上传组件放在表格某一行中,可配合 index 和 childrenKey 使用:
<FileUpload
v-model:file-list="tableData"
:index="scope.$index"
children-key="files"
/>
此时组件会自动读写:
tableData[scope.$index].files
组件路径:
src/components/AttachmentUpload/image/index.vue
<template>
<ImageUpload v-model:file-list="imageList" />
</template>
<script setup>
import { ref } from 'vue'
const imageList = ref([])
</script>
图片上传组件默认:
10 张10MBpng / jpg / jpeg / webppicture-card 风格展示<ImageUpload
v-model:file-list="imageList"
:limit="9"
:file-size="5"
:file-type="['png', 'jpg', 'jpeg']"
button-text="上传图片"
/>
ImageUpload 展示图片时优先读取:
url || previewURL || previewUrl
建议后端返回:
[
{
id: 1,
originalFilename: '现场图片.jpg',
previewURL: 'https://xxx/image.jpg'
}
]
图片组件同样支持行内字段写回:
<ImageUpload
v-model:file-list="tableData"
:index="scope.$index"
children-key="images"
/>
默认写回字段为 images。
组件路径:
src/components/AttachmentPreview/image/index.vue
<ImagePreview :file-list="imageList" />
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
fileList |
图片列表 | Array |
[] |
thumbSize |
缩略图大小 | Number |
72 |
gap |
缩略图间距 | Number |
10 |
组件会过滤没有 previewURL 的项,因此如果要正常显示,建议至少包含:
[
{
previewURL: 'https://xxx/image.jpg',
originalFilename: '图片1.jpg'
}
]
如果列表为空,组件显示“暂无图片”。
组件路径:
src/components/Dialog/FileList.vue
这个组件适合业务表单或详情页里的“附件管理”场景,能力包括:
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
visible |
是否显示弹窗 | Boolean |
必传 |
recordType |
业务类型 | String |
'' |
recordId |
业务主键 | Number |
0 |
title |
弹窗标题 | String |
附件 |
width |
弹窗宽度 | String |
50% |
showActions |
是否显示下载/删除操作列 | Boolean |
true |
<template>
<el-button @click="visible = true">查看附件</el-button>
<FileListDialog
v-model:visible="visible"
record-type="salesLedger"
:record-id="rowId"
title="附件列表"
/>
</template>
<script setup>
import { ref } from 'vue'
const visible = ref(false)
const rowId = ref(1001)
</script>
FileListDialog 本身不直接调用 commonFile.js,而是依赖:
attachmentListcreateAttachmentdeleteAttachment处理逻辑为:
recordType + recordId 查询附件AttachmentUpload/file 先上传到 /common/uploadcreateAttachmentdeleteAttachmentwindow.open(downloadURL, '_blank')因此这里要特别注意:
recordType 和 recordId 必须是有效业务标识createAttachment 直接接收downloadURL文件路径:
src/api/publicApi/commonFile.js
当前文件提供的是公共文件删除接口:
delCommonFile(ids)
delCommonFileInvoiceLedger(ids)
对应接口:
/commonFile/delCommonFile/invoiceLedger/delFile这两个方法更适合已经和具体业务绑定后的“删除已保存附件”场景,不负责上传文件本身。
示例:
import { delCommonFile } from '@/api/publicApi/commonFile'
await delCommonFile([1, 2, 3])
<FileUpload v-model:file-list="form.storageBlobDTOs" />
提交表单时直接带上:
{
...form,
storageBlobDTOs: form.storageBlobDTOs
}
<ImageUpload v-model:file-list="form.images" />
<ImagePreview :file-list="form.images" />
<FileListDialog
v-model:visible="dialogVisible"
:record-type="recordType"
:record-id="recordId"
/>
适合详情页、审批页、台账页这类“查看并维护当前业务附件”的场景。
FileUpload 和 ImageUpload 只是负责把文件先传到 /common/upload,不等于已经和业务数据绑定。ImagePreview 当前只识别 previewURL,如果后端只返回 url,预览组件将不会展示,最好统一补齐 previewURL。FileListDialog 依赖 recordType、recordId 查询和保存附件关系,新增业务时要先确认后端关联接口可用。commonFile.js / deleteAttachment:才是真正调用后端删除<template>
<el-form :model="form">
<el-form-item label="附件">
<FileUpload v-model:file-list="form.storageBlobDTOs" :limit="5" />
</el-form-item>
<el-form-item label="现场图片">
<ImageUpload v-model:file-list="form.images" :limit="9" />
</el-form-item>
<el-form-item label="图片预览">
<ImagePreview :file-list="form.images" />
</el-form-item>
</el-form>
</template>
<script setup>
import { ref } from 'vue'
const form = ref({
storageBlobDTOs: [],
images: [],
})
</script>
如果你的目标是“先上传,再跟业务一起保存”,这套写法可以直接作为基础模板使用。