文件下载和批量下载

280 阅读2分钟

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.效果

image.png

注意:代码仅为项目的部分片段,不可直接使用,仅供思路参考