1.问题:需要实现文件下载以及批量下载,前端多次调用后端接口把文件放在压缩包内
2.工具:
- 批量下载 - jszip
- ui框架-element-Plus
yarn add jszip
yarn add element-plus
3.HTML结构
使用的是元素的文件选择input
<div>
<span>会议文件</span>
<el-button
type="success"
:icon="Upload"
circle
size="small"
@click="openFileDialog(index)"
/>
</div>
<div>
<el-button
v-if="conference.documents.length > 1"
type="primary"
size="small"
@click="downloadSelectedFiles"
:disabled="batchDisabled"
>批量下载</el-button
>
</div>
<div class="file-header">
<input
type="file"
multiple
ref="fileInput"
hidden
@change="uploadConferenceFiles(conference.id, index)"
/>
</div>
<el-table :data="conference.documents" @selection-change="handleSelectionChange">
<template #empty>
<el-icon> <InfoFilled /> </el-icon>还未上传文件
</template>
<el-table-column type="selection" width="55" />
<el-table-column label="文件名" prop="name" />
<el-table-column label="操作" fixed="right" prop="id" width="100">
<template #default="scope">
<el-button
class="editButton-area"
:icon="Download"
type="primary"
circle
size="small"
@click="downloadDocument(scope.row.id, scope.row.name)"
/>
<el-button
:icon="Delete"
type="danger"
circle
size="small"
@click="deleteDocument(scope.row.id)"
/>
</template>
</el-table-column>
</el-table>
4.实现
import { Edit, Delete, Check, Close, Upload, Download } from '@element-plus/icons-vue'
// 数据
// ...省略
// 文件选择
const fileInput = ref<any>(null)
const openFileDialog = (index: number) => {
if (fileInput.value[index]) {
fileInput.value[index].click()
}
}
// 文件上传 - 要求formData格式
const uploadConferenceFiles = async (sectionId: number, index: number) => {
const documents = []
const files = fileInput.value[index].files
if (!files.length) return
const formData = new FormData()
for (let file of files) {
documents.push(file)
}
formData.append('sectionId', JSON.stringify(sectionId))
documents.map((document) => formData.append('documents', document))
await uploadFiles(formData)
setConferenceDeatilData()
}
// 单个文件下载
const downloadDocument = async (documentId: number, fileName: string) => {
const data = {
token: tokenCatch.get(),
documentId: documentId
}
const fileContent = downloadFile(data) // 文件
const blobUrl = window.URL.createObjectURL(fileContent)
const link = document.createElement('a')
link.href = blobUrl
link.setAttribute('download', fileName)
document.body.appendChild(link)
link.click()
}
// 批量文件下载
const batchDisabled = ref(true) // 默认禁用状态
const selectedFiles = ref([]) // 选中文件
const handleSelectionChange = (section: any) => {
selectedFiles.value = section
if (selectedFiles.value.length > 1) {
batchDisabled.value = false
} else {
batchDisabled.value = true
}
}
const downloadSelectedFiles = async () => {
const zip = new JSZip()
for (const file of selectedFiles.value) {
const { id: documentId, name: fileName } = file
const data = {
token: tokenCatch.get(),
documentId: documentId
}
const fileContent = await downloadFile(data)
// 将文件内容添加到ZIP文件夹中
zip.file(fileName, fileContent)
}
// 生成zip文件
const zipBlob = await zip.generateAsync({ type: 'blob' })
// 下载zip文件
const zipFileName = 'download.zip'
const zipBlobUrl = window.URL.createObjectURL(zipBlob)
const zipLink = document.createElement('a')
zipLink.href = zipBlobUrl
zipLink.setAttribute('download', zipFileName)
document.body.appendChild(zipLink)
zipLink.click()
}
// 文件下载api
// createParams方法:把对象转成后端要求的形式
downloadFile = async (data: DownloadFile) => {
try {
const response = await request.post({
url: '下载地址',
data: createParams([{ name: 'params', data: data }]),
responseType: 'blob'
})
return new Blob([response.data])
} catch (error) {
console.error('Error:', error)
}
}
5.效果
注意:代码仅为项目的部分片段,不可直接使用,仅供思路参考