阿里华为云-简单文件上传实现

1.拖拽上传文件、文件夹,点击选择文件功能实现

直接上代码,

<template>
  <div class="upload">
    <div class="upload-content drop" v-show="list.length == 0" @dragover.prevent="ondragover" @drop="ondrop">
      <img src="../img/import.svg" />
      <div style="margin: 10px 0 12px 0">
        <span class="drop-info">拖拽本地文件或文件夹至此,或</span>
        <label for="customFileInput1" class="upload-drop-input" style="cursor: pointer">
          <span style="color: #3674ef">添加文件</span>
          <input type="file" id="customFileInput1" multiple class="fileInput1" @click="handleFileInputChange" />
        </label>
      </div>
      <div class="upload-content-info aliInfo" v-if="infoType">
        单次最多支持100个文件同时上传,总大小不超过5GB,请使用命令行工具ossutil、OSS SDK或OSS
        API等方式,通过分片上传的方式进行上传文件操作。
      </div>
      <div class="upload-content-info" v-else>单次最多支持100个文件同时上传,总大小不超过5GB。</div>
    </div>
    <div class="upload-list" v-show="list.length != 0">
      <div class="upload-list-header drop" @drop="ondrop" @dragover.prevent="ondragover">
        拖拽本地文件或文件夹至此上传
      </div>
      <div style="display: flex; justify-content: space-between; margin-bottom: 18px">
        <div class="upload-list-button">
          <div @click="clear()" style="margin-right: 12px">清空列表</div>
          <div>
            <label for="customFileInput2" class="upload-drop-input" style="cursor: pointer">
              <span>添加文件</span>
              <input type="file" id="customFileInput2" multiple class="fileInput2" @click="handleFileInputChange" />
            </label>
          </div>
        </div>
        <div class="upload-list-info">
          <div style="margin-right: 20px">
            <span :class="{ warn: fileNum > 100 }" style="margin-right: 4px">{{ fileNum }}/100</span>
            <span>文件</span>
          </div>
          <div>
            <span>大小</span>
            <span :class="{ warn: isLimit }" style="margin-left: 4px">{{ fileTotalSize }}</span>
          </div>
        </div>
      </div>
      <div class="listWarn" v-if="listWarn">
        <div>
          <img src="../img/warn.svg" />
          <span style="margin-left: 8px" v-if="fileNum > 100 && !isLimit">
            文件数量超过限制,单次上传文件的数量不能超过100,请先移除部分文件后再上传。</span
          >
          <span style="margin-left: 8px" v-if="isLimit && !(fileNum > 100)">
            文件总大小超过限制,单次上传文件的总大小不能超过5GB,请先移除部分文件后再上传。</span
          >
          <span style="margin-left: 8px" v-if="isLimit && fileNum > 100">
            文件总大小及数量超过限制,请先移除部分文件后再上传。</span
          >
        </div>
        <img src="../img/cancel.svg" @click="cancelWarn" />
      </div>

      <uploadList :dataSource="list" @fileDelete="fileDelete" />
    </div>
  </div>
</template>
<script>
import uploadList from './uploadList.vue'

export default {
  components: { uploadList },
  props: {
    version: {
      default: false,
    },
    infoType: {
      default: false,
    },
  },
  data() {
    return {
      list: [], //包含文件夹,不展开全部
      fileData: [], //全部已展开的文件
      fileNum: 0,
      fileTotalSize: 0,
      totalSize: 0,
      newArray: 0,
      isLimit: false,
      listWarn: false,
      // infoType: false,
    }
  },
  mounted() {
    this.init()
  },
  methods: {
    init() {
      const div = document.querySelector('.drop')
      div.ondragenter = e => {
        e.preventDefault()
      }
      div.ondragover = e => {
        e.preventDefault()
      }
      div.ondrop = e => {
        e.preventDefault()
      }
      // document.getElementById('customFileInput1').addEventListener('change', this.handleFileInputChange.bind(this))
      // document.getElementById('customFileInput2').addEventListener('change', this.handleFileInputChange.bind(this))
      this.handleFileInputChange()
    },
    handleFileInputChange() {
      console.log(1)
      const fileInput1 = document.querySelector('.fileInput1')
      const fileInput2 = document.querySelector('.fileInput2')
      fileInput1.value = ''
      fileInput2.value = ''
      if (fileInput1) {
        fileInput1.addEventListener('change', event => {
          const selectedFiles = event.target.files
          for (let i = 0; i < selectedFiles.length; i++) {
            const file = selectedFiles[i]
            console.log(i)
            const existingIndex = this.list.findIndex(item => item.name === file.name)
            if (existingIndex !== -1) {
              // 如果存在相同名称的数据,用新数据替换旧数据
              console.log('同名')
              this.$set(this.list, existingIndex, { name: file.name, size: file.size, file })
              this.$set(this.fileData, existingIndex, file)
              this.list.forEach((item, index) => {
                item.index = index
              })
              this.formatData()
            } else {
              // 如果不存在相同名称的数据,将新数据插入数组开头
              this.list.unshift({ name: file.name, size: file.size, file })
              this.fileData.unshift(file)
            }
            // }
            this.formatData()
          }
        })
      }
      if (fileInput2) {
        fileInput2.addEventListener('change', event => {
          const selectedFiles = event.target.files
          for (let i = 0; i < selectedFiles.length; i++) {
            const file = selectedFiles[i]
            const existingIndex = this.list.findIndex(item => item.name === file.name)
            if (existingIndex !== -1) {
              // 如果存在相同名称的数据,用新数据替换旧数据
              console.log('同名')
              this.$set(this.list, existingIndex, { name: file.name, size: file.size, file })
              this.$set(this.fileData, existingIndex, file)
              this.list.forEach((item, index) => {
                item.index = index
              })
              this.formatData()
            } else {
              // 如果不存在相同名称的数据,将新数据插入数组开头
              this.list.unshift({ name: file.name, size: file.size, file })
              this.fileData.unshift(file)
            }
          }
          this.formatData()
        })
      }
      // fileInput1.removeEventListener()
      // fileInput2.removeEventListener()

      console.log(fileInput1)
    },
    ondragover(e) {
      e.preventDefault()
    },
    async ondrop(e) {
      //处理子文件夹逻辑
      e.preventDefault()
      const traverseEntries = (entries, directoryName) => {
        for (const entry of entries) {
          if (entry.isDirectory) {
            // 处理目录
            // console.log(entry.name, '我是文件夹中的文件夹')
            const reader = entry.createReader()
            reader.readEntries(subEntries => {
              subEntries.forEach(subEntry => {
                traverseEntries([subEntry]) // 递归处理子目录
              })
            })
          } else {
            // 处理文件
            entry.file(file => {
              //   console.log(file.name, '我是文件夹中的子文件', file)
              file.directoryName = directoryName
              file.fullPath = entries[0].fullPath
              this.fileData.unshift(file)
            })
          }
        }
      }
      const array = Array.from(e.dataTransfer.items)
      // console.log(e.dataTransfer.items.length, ' 上传文件总数', array[0].webkitGetAsEntry())
      for (const index in array) {
        const entry = array[index].webkitGetAsEntry()
        // console.log(entry, 'entry')
        if (entry) {
          if (entry.isDirectory) {
            // 处理根目录
            // console.log(entry.name, '我是文件夹', entry)
            const reader = entry.createReader()
            reader.readEntries(subEntries => {
              subEntries.forEach(subEntry => {
                traverseEntries([subEntry], entry.name) // 开始递归处理目录
              })
            })
            this.getSize([entry]).then(total => {
              const reader = entry.createReader()
              reader.readEntries(subEntries => {
                // if (this.version) {
                //   this.list.unshift({
                //     name: entry.name,
                //     size: total,
                //     index: index,
                //     isDirectory: true,
                //     entry,
                //     subEntries: subEntries,
                //   })
                // } else {
                const existingIndex = this.list.findIndex(item => item.name === entry.name)
                if (existingIndex !== -1) {
                  // 如果存在相同名称的数据,用新数据替换旧数据
                  console.log('同名')
                  this.$set(this.list, existingIndex, {
                    name: entry.name,
                    size: total,
                    index: index,
                    isDirectory: true,
                    entry,
                    subEntries: subEntries,
                  })
                  // this.$set(this.fileData, existingIndex, file)
                  this.list.forEach((item, index) => {
                    item.index = index
                  })
                  this.formatData()
                  // this.formatSize(
                } else {
                  // 如果不存在相同名称的数据,将新数据插入数组开头
                  this.list.unshift({
                    name: entry.name,
                    size: total,
                    index: index,
                    isDirectory: true,
                    entry,
                    subEntries: subEntries,
                  })
                  // this.fileData.unshift(file)
                }
                // }
              })
            })
          } else {
            // 处理文件
            entry.file(file => {
              // if (this.version) {
              //   this.list.unshift({ name: file.name, size: file.size, file })
              //   this.fileData.unshift(file)
              // } else {
              console.log(file.name, '我是同名文件', file)
              const existingIndex = this.list.findIndex(item => item.name === file.name)
              if (existingIndex !== -1) {
                // 如果存在相同名称的数据,用新数据替换旧数据
                console.log('同名')
                this.$set(this.list, existingIndex, { name: file.name, size: file.size, file })
                this.$set(this.fileData, existingIndex, file)
                this.list.forEach((item, index) => {
                  item.index = index
                })
                this.formatData()
              } else {
                // 如果不存在相同名称的数据,将新数据插入数组开头
                this.list.unshift({ name: file.name, size: file.size, file })
                this.fileData.unshift(file)
              }
              // }
            })
          }
        }
      }
      // 等待list数组被填充
      await new Promise(resolve => {
        this.newArray += array.length
        const checkList = () => {
          if (this.list.length === this.newArray) {
            resolve()
          } else {
            setTimeout(checkList, 0)
          }
        }
        checkList()
      })
      // 为每个项添加索引
      this.list.forEach((item, index) => {
        item.index = index
      })
      this.formatData()
    },
    async getSize(entries) {
      let total = 0
      for (const entry of entries) {
        if (entry.isFile) {
          total += await this.getFileSize(entry)
        } else if (entry.isDirectory) {
          const reader = entry.createReader()
          const subEntries = await this.readEntries(reader)
          total += await this.getSize(subEntries) // 递归处理子目录
        }
      }
      return total
    },
    async getFileSize(fileEntry) {
      return new Promise(resolve => {
        fileEntry.file(file => {
          resolve(file.size)
        })
      })
    },
    async readEntries(reader) {
      return new Promise(resolve => {
        reader.readEntries(entries => {
          resolve(entries)
        })
      })
    },
    formatData() {
      let total = 0
      this.list.forEach(item => {
        total = total + item.size
      })
      // console.log(this.list)
      this.totalSize = total
      this.fileTotalSize = this.formatSize(total)
      // console.log(this.fileTotalSize, this.list)
      this.fileNum = this.list.length
      this.listWarn = this.isLimit || this.fileNum > 100
      const param = { fileList: this.list, fileData: this.fileData, limit: this.listWarn }
      this.$emit('getData', param)
      console.log(this.fileData, this.list, 6666666)
    },
    formatSize(sizeInBytes) {
      if (sizeInBytes > 5 * 1024 * 1024 * 1024) {
        // console.log(1, sizeInBytes)
        this.isLimit = true
      } else {
        // console.log(2, sizeInBytes)
        this.isLimit = false
      }
      // 定义换算单位
      const units = ['Bytes', 'KB', 'MB', 'GB']
      // 初始化大小和单位
      let size = sizeInBytes
      let unitIndex = 0
      // 循环换算,直到大小小于1或者单位达到GB
      while (size >= 1024 && unitIndex < units.length - 1) {
        size /= 1024
        unitIndex++
      }
      size = Math.round(size * 100) / 100
      return size.toFixed(2) + units[unitIndex]
    },

    fileDelete(record) {
      if (record.index >= 0 && record.index < this.list.length) {
        this.list.splice(record.index, 1)
      }
      if (record.isDirectory) {
        // 删除匹配项
        this.fileData = this.fileData.filter(item => item.directoryName !== record.name)
        // console.log(this.fileData, record.name)
      } else {
        this.fileData = this.fileData.filter(item => {
          if (item.directoryName) {
            // 如果是文件夹,保留
            return true
          } else {
            // 如果不是文件夹,删除同名文件
            return item.name !== record.name
          }
        })
        // this.fileData = this.fileData.filter(item => item.name != record.name)
      }
      if (this.list.length > 0) {
        this.list.forEach((item, index) => {
          item.index = index
        })
      }
      console.log(this.list, this.fileData, 'del')
      this.newArray = this.newArray - 1
      this.formatData()
    },
    clear() {
      this.newArray = 0
      this.list = []
      this.fileData = []
      this.listWarn = false
      this.isLimit = false
      this.fileNum = 0
      this.formatData()
    },
    cancelWarn() {
      this.listWarn = false
    },
  },
}
</script>

以上是拖拽功能简单实现,下面放文件上传列表功能实现(包含进度条、文件状态) 

<template>
  <a-modal :visible="taskVisible" :footer="null" title="任务列表" :width="920" @cancel="cancelModal">
    <div class="btn">
      <a-button :disabled="canClear" @click="clearAll" class="cancelbtn">清除记录</a-button>
      <a-button :disabled="canCancel" @click="cancelAll">全部取消</a-button>
      <!-- <a-button v-else @click="startAll">全部开始</a-button> -->
    </div>
    <a-table :columns="type == 'ali' ? aliColumns : huaweiColumns" :data-source="formattedDataSource">
      <template slot="name" slot-scope="item, record">
        <overflow :text="record.name"></overflow>
      </template>
      <template slot="size" slot-scope="item, record">
        <overflow :text="record.formattedSize"></overflow>
      </template>
      <template v-if="type == 'ali'" slot="uploadTo" slot-scope="item, record">
        <overflow :text="uploadTo(record)"></overflow>
      </template>
      <template v-if="type == 'huawei'" slot="backet">
        <overflow :text="bucketName"></overflow>
      </template>
      <template slot="status" slot-scope="item, record" class="status">
        <a-progress
          v-if="status[record.index] == '上传中'"
          :percent="percent[record.index] || 0"
          size="small"
          :showInfo="false"
          :strokeWidth="4"
          :strokeColor="'#52C41A'"
        />
        <img v-if="status[record.index] == '成功'" src="./compoment/img/success.svg" />
        <img v-if="status[record.index] == '准备'" src="./compoment/img/ready.svg" />
        <img v-if="status[record.index] == '失败'" src="./compoment/img/fail.svg" />
        <span v-if="status[record.index] == '上传中'">{{
          percent[record.index] != '' ? percent[record.index] + '%' : '0%'
        }}</span>
        <span v-if="status[record.index] != '上传中'">{{ status[record.index] }}</span>
      </template>
      <template slot="action" slot-scope="item, record">
        <span class="action" v-if="status[record.index] == '上传中'" @click="cancelUpload(record.index)">取消</span>
        <span
          class="action"
          v-if="status[record.index] == '失败'"
          @click="retry(record.index)"
          style="margin-right: 16px"
          >重试</span
        >
        <span
          class="action"
          v-if="status[record.index] !== '准备' && status[record.index] !== '上传中'"
          @click="clearFile(record.index)"
          >清除记录</span
        >
      </template>
    </a-table>
  </a-modal>
</template>
<script>
import { aliyun, huawei, refreshBucketStat } from './api'
import overflow from '@/components/tableEllipsis/isOverflow.vue'
export default {
  components: { overflow },
  props: {
    type: {
      type: String,
      default: 'ali',
    },
  },
  data() {
    return {
      aliColumns: [
        {
          title: '文件名称',
          width: '260px',
          dataIndex: 'name',
          scopedSlots: { customRender: 'name' },
        },
        {
          title: '上传到',
          width: '208px',
          dataIndex: 'uploadTo',
          scopedSlots: { customRender: 'uploadTo' },
        },
        {
          title: '文件大小',
          width: '124px',
          dataIndex: 'size',
          scopedSlots: { customRender: 'size' },
        },
        {
          title: '状态',
          width: '140px',
          dataIndex: 'status',
          scopedSlots: { customRender: 'status' },
        },
        {
          title: '操作',
          width: '128px',
          dataIndex: 'action',
          scopedSlots: { customRender: 'action' },
        },
      ],
      huaweiColumns: [
        {
          title: '文件名称',
          width: '260px',
          dataIndex: 'name',
          scopedSlots: { customRender: 'name' },
        },
        {
          title: '所属桶',
          width: '208px',
          dataIndex: 'backet',
          scopedSlots: { customRender: 'backet' },
        },
        {
          title: '文件大小',
          width: '124px',
          dataIndex: 'size',
          scopedSlots: { customRender: 'size' },
        },
        {
          title: '状态',
          width: '140px',
          dataIndex: 'status',
          scopedSlots: { customRender: 'status' },
        },
        {
          title: '操作',
          width: '128px',
          dataIndex: 'action',
          scopedSlots: { customRender: 'action' },
        },
      ],
      taskVisible: false,
      // fileList: [],
      fileData: [],
      aliUrl: '',
      huaweiUrl: '',
      aliHeaders: {},
      huaweiHeaders: {},
      huaweiSignature: '',
      percent: [],
      currentIndex: 0, // 当前上传的文件索引
      status: [],
      xhr: [],
      indexs: [],
      obsDate: '',
      storageType: '',
      docACL: 'default',
      bucketName: '',
      path: '',
    }
  },
  computed: {
    formattedDataSource() {
      // dataSource格式化
      return this.fileData.map((item, index) => ({
        name: item.name,
        index: index,
        ...item,
        formattedSize: this.formatSize(item.size),
        fullPath: this.path + (item.fullPath || '/' + item.name),
      }))
    },
    canClear() {
      return this.status.every(item => item === '上传中' || item === '准备')
    },
    canCancel() {
      return this.status.every(item => item !== '上传中')
    },
  },
  mounted() {},
  methods: {
    clearAll() {
      this.fileData = []
    },
    cancelAll() {
      for (const index in this.xhr) {
        if (this.xhr[index] && this.xhr[index].readyState === 1) {
          this.xhr[index].abort() // 中止请求
        }
      }
      for (const i in this.status) {
        if (this.status[i] != '成功') {
          this.$set(this.status, i, '失败')
        }
      }
    },
    showTask() {
      this.taskVisible = true
    },
    showModal(fileData, fileList, storageType, bucketName, path, version) {
      this.path = path.slice(0, -1)
      this.bucketName = bucketName
      this.storageType = storageType
      this.taskVisible = true
      // debugger
      if (this.fileData.length > 0) {
        if (version) {
          const initialStatus = Array(fileData.length).fill('准备')
          const initialPercent = Array(fileData.length).fill('')
          this.fileData = [...this.fileData, ...fileData]
          this.status = [...this.status, ...initialStatus]
          this.percent = [...this.percent, ...initialPercent]
          const hasUploadingStatus = this.status.some(status => status === '上传中')
          console.log(this.status, this.fileData)
          // 如果没有上传中的状态,调用this.uploadNextFile()
          if (!hasUploadingStatus) {
            this.uploadNextFile()
          }
          //console.log('任务列表version', version)
        } else {
          //校验fileData是否和旧的this.fileData中有重名的file.name,去掉新的fileData中重名文件,将其他的拼接到this.fileData中
          const uniqueFileData = fileData.filter(newFile => {
            return !this.fileData.some(existingFile => existingFile.name === newFile.name)
          })
          const initialStatus = Array(uniqueFileData.length).fill('准备')
          const initialPercent = Array(uniqueFileData.length).fill('')
          this.fileData = [...this.fileData, ...uniqueFileData]
          this.status = [...this.status, ...initialStatus]
          this.percent = [...this.percent, ...initialPercent]
          const hasUploadingStatus = this.status.some(status => status === '上传中')
          // 如果没有上传中的状态,调用this.uploadNextFile()
          if (!hasUploadingStatus) {
            this.uploadNextFile()
          }
        }
      } else {
        this.status = Array(fileData.length).fill('准备')
        this.percent = Array(fileData.length).fill('')
        this.xhr = []
        this.currentIndex = 0
        this.fileData = fileData
        // this.fileList = fileList
        this.uploadNextFile()
      }
    },
    alirefreshBucketStat() {
      const param = {
        accountId: this.$store.state.user.curAccount.id,
        bucketId: this.$route.query.id,
      }
      refreshBucketStat(param).then(res => {
        //console.log(res)
      })
    },
    uploadNextFile() {
      this.$parent.update()
      // console.log(this.status, 'ssssssssssss', this.fileData)
      const index = this.status.findIndex(status => status == '准备')
      console.log(index, 'uploadNextFile indexindexindex')
      if (index !== -1) {
        const file = this.fileData[index]
        this.status[index] = '上传中'
        if (this.type == 'huawei') {
          this.getHuawei(file, index)
        }
        if (this.type == 'ali') {
          this.getAli(file, index)
        }
        this.alirefreshBucketStat()
        // //console.log(index, '走到了下一个不是失败或者成功的文件', file)
      }
    },
    getAli(file, index) {
      const fileUrl = file.fullPath
      const url = this.path ? this.path + '/' : this.path
      const fileName = this.path ? this.path + '/' + file.name : file.name
      const param = {
        fileKey: fileUrl ? url + fileUrl.slice(1) : fileName,
        bucketId: this.$route.query.id,
        accountId: this.$store.state.user.curAccount.id,
        fileAcl: this.docACL,
        fileStorageClass: this.storageType,
        contentType: file.type || 'application/octet-stream',
        // contentType: 'application/x-png'',
      }

      aliyun(param).then(res => {
        if (res.statusCode == 200) {
          this.aliUrl = res.data.url
          this.aliHeaders = res.data.headers
          this.aliUpload(file, index)
        } else {
          for (const i in this.status) {
            this.$set(this.status, i, '失败')
          }
          this.$message.error(res.message)
        }
      })
    },
    getHuawei(file, index) {
      // //console.log(file, getContentType('png'), 123)
      this.obsDate = this.getFormattedDate()
      const fileUrl = file.fullPath ? file.fullPath.slice(1) : file.fullPath
      const path = this.path ? this.path + '/' + fileUrl : fileUrl
      const param2 = {
        accountId: this.$store.state.user.curAccount.id,
        bucketId: this.$route.query.id,
        httpMethod: 'PUT',
        objectKey: fileUrl ? path : (this.path ? this.path + '/' : '') + file.name,
        // date: '',
        contentType: file.type || 'application/octet-stream',
        xObsHeaders: {
          'x-obs-date': [this.obsDate],
          'x-obs-storage-class': [this.storageType],
        },
      }
      huawei(param2).then(res => {
        this.huaweiUrl = res.data.domain
        this.huaweiSignature = res.data.signature
        this.huaweiUpload(file, index)
      })
      // huaweiBucket({ accountId: 1, limit: 10, page: 1 }).then(res => {
      //   //console.log(res)
      // })
    },
    aliUpload(file, index) {
      // //console.log(file, this.fileData, 6655, this.fileList)
      const xhr = new XMLHttpRequest()
      xhr.onerror = () => {
        // 请求发生错误时,这里会执行
        const index = this.fileData.findIndex(
          item => item.name === file.name && item.directoryName === file.directoryName
        )
        this.$set(this.status, index, '失败')
        console.error('请求发生错误', index)
        this.uploadNextFile() // 上传下一个文件
      }
      xhr.onload = () => {
        const index = this.fileData.findIndex(
          item => item.name === file.name && item.directoryName === file.directoryName
        )
        if (xhr.status === 200) {
          //console.log('文件上传成功!')
          this.$set(this.status, index, '成功')
          this.uploadNextFile() // 上传下一个文件
        } else {
          this.$set(this.status, index, '失败')
          console.error('文件上传失败:', xhr.statusText)
          this.uploadNextFile() // 上传下一个文件
        }
      }
      xhr.upload.onprogress = e => {
        const index = this.fileData.findIndex(
          item => item.name === file.name && item.directoryName === file.directoryName
        )
        this.$set(this.percent, index, Math.floor((e.loaded / e.total) * 100))
      }
      const fullPath = file.fullPath
      const fileNamePath = '/' + file.name
      const url = fullPath ? '/' + this.path + fullPath : '/' + this.path + fileNamePath
      xhr.open('PUT', this.aliUrl + url, true)
      xhr.setRequestHeader('Authorization', this.aliHeaders.Authorization)
      xhr.setRequestHeader('x-oss-date', this.aliHeaders['x-oss-date'])
      xhr.setRequestHeader('Content-Type', file.type || 'application/octet-stream')
      // xhr.setRequestHeader('x-oss-content-type', file.type || 'application/octet-stream')
      // xhr.setRequestHeader('Content-Type', 'application/x-png')
      xhr.setRequestHeader('x-oss-object-acl', this.aliHeaders['x-oss-object-acl'])
      xhr.setRequestHeader('x-oss-storage-class', this.aliHeaders['x-oss-storage-class'])
      this.xhr[index] = xhr
      xhr.send(file)
    },
    huaweiUpload(file, index) {
      const xhr = new XMLHttpRequest()
      xhr.onerror = () => {
        // const index = this.fileData.findIndex(
        //   item => item.name === file.name && item.directoryName === file.directoryName
        // )
        this.$set(this.status, index, '失败')
        console.error('请求发生错误', index)
        this.uploadNextFile() // 上传下一个文件
      }
      xhr.onload = () => {
        // const index = this.fileData.findIndex(
        //   item => item.name === file.name && item.directoryName === file.directoryName
        // )
        if (xhr.status === 200) {
          this.$set(this.status, index, '成功')
          this.uploadNextFile() // 上传下一个文件
        } else {
          this.$set(this.status, index, '失败')
          console.error('文件上传失败:', xhr.statusText)
          this.uploadNextFile() // 上传下一个文件
        }
      }
      xhr.upload.onprogress = e => {
        // const index = this.fileData.findIndex(
        //   item => item.name === file.name && item.directoryName === file.directoryName
        // )
        this.$set(this.percent, index, Math.floor((e.loaded / e.total) * 100))
      }
      const fullPath = file.fullPath
      const fileNamePath = '/' + file.name
      const path = this.path ? '/' + this.path : this.path
      const url = fullPath ? path + fullPath : path + fileNamePath
      const encodedString = url.replace(/%/g, '%25').replace(/#/g, '%23')
      xhr.open('PUT', this.huaweiUrl + encodedString, true)
      xhr.setRequestHeader('Authorization', this.huaweiSignature)
      xhr.setRequestHeader('x-obs-date', this.obsDate)
      xhr.setRequestHeader('Content-Type', file.type || 'application/octet-stream')
      xhr.setRequestHeader('x-obs-storage-class', this.storageType)
      this.xhr[index] = xhr
      xhr.send(file)
    },
    cancelUpload(index) {
      this.$set(this.status, index, '失败')
      this.$set(this.percent, index, 0)
      const xhr = this.xhr[index]
      if (xhr && xhr.readyState === 1) {
        this.xhr[index].abort() // 中止请求
        this.uploadNextFile()
      }
      //console.log(this.xhr, this.status, index, '取消上传')
    },
    clearFile(index1) {
      this.fileData = this.fileData.filter((item, index) => index != index1)
      this.status = this.status.filter((item, index) => index != index1)
      this.percent = this.percent.filter((item, index) => index != index1)
      this.xhr = this.xhr.filter((item, index) => index != index1)
      //console.log(this.fileData)
    },
    retry(index) {
      if (this.xhr.some(xhr => xhr && xhr.readyState === 1)) {
        this.$set(this.status, index, '准备')
        //console.log('retry', index, this.status, this.xhr, '准备重新上传')
        this.$set(this.percent, index, 0)
      } else {
        this.$set(this.status, index, '上传中')
        console.log('retry', index, this.status, this.xhr, '重新上传')
        const file = this.fileData[index]
        this.$set(this.percent, index, 0)
        if (this.type == 'ali') {
          const param = {
            fileKey: file.directoryName ? file.directoryName + '/' + file.name : file.name,
            accountId: this.$store.state.user.curAccount.id,
            bucketId: this.$route.query.id,
            fileAcl: this.docACL,
            fileStorageClass: this.storageType,
            contentType: file.type || 'application/octet-stream',
          }
          aliyun(param).then(res => {
            if (res.statusCode == 200) {
              this.aliUrl = res.data.url
              this.aliHeaders = res.data.headers
              this.xhr[index] = new XMLHttpRequest()
              const xhr = this.xhr[index]
              const fullPath = file.fullPath
              const fileNamePath = '/' + file.name
              const url = fullPath ? fullPath : fileNamePath
              xhr.open('PUT', this.aliUrl + url, true)
              xhr.setRequestHeader('Authorization', this.aliHeaders.Authorization)
              xhr.setRequestHeader('x-oss-date', this.aliHeaders['x-oss-date'])
              xhr.setRequestHeader('Content-Type', file.type || 'application/octet-stream')
              xhr.setRequestHeader('x-oss-object-acl', this.aliHeaders['x-oss-object-acl'])
              xhr.setRequestHeader('x-oss-storage-class', this.aliHeaders['x-oss-storage-class'])
              xhr.onload = () => {
                // const index = this.fileData.findIndex(
                //   item => item.name === file.name && item.directoryName === file.directoryName
                // )
                if (xhr.status === 200) {
                  this.$set(this.status, index, '成功')
                  this.$parent.update()
                } else {
                  this.$set(this.status, index, '失败')
                }
              }
              xhr.upload.onprogress = e => {
                // const index = this.fileData.findIndex(
                //   item => item.name === file.name && item.directoryName === file.directoryName
                // )
                this.$set(this.percent, index, Math.floor((e.loaded / e.total) * 100))
                //console.log(this.percent, '重新上传')
              }
              const form = new FormData()
              form.append(file.name, file)
              xhr.send(form)
            } else {
              this.$set(this.status, index, '失败')
              this.$message.error(res.message)
            }
          })
        }
        if (this.type == 'huawei') {
          this.obsDate = this.getFormattedDate()
          const fileUrl = file.fullPath
          const param2 = {
            accountId: this.$store.state.user.curAccount.id,
            bucketId: this.$route.query.id,
            httpMethod: 'PUT',
            objectKey: fileUrl ? fileUrl.slice(1) : file.name,
            contentType: 'application/octet-stream',
            xObsHeaders: {
              'x-obs-date': [this.obsDate],
              'x-obs-storage-class': [this.storageType],
            },
          }
          huawei(param2).then(res => {
            this.huaweiUrl = res.data.domain
            this.huaweiSignature = res.data.signature
            this.xhr[index] = new XMLHttpRequest()
            const xhr = this.xhr[index]
            xhr.onerror = () => {
              // 请求发生错误时,这里会执行
              // const index = this.fileData.findIndex(
              //   item => item.name === file.name && item.directoryName === file.directoryName
              // )
              this.$set(this.status, index, '失败')
              console.error('请求发生错误', index)
              // this.uploadNextFile() // 上传下一个文件
            }
            xhr.onload = () => {
              // const index = this.fileData.findIndex(
              //   item => item.name === file.name && item.directoryName === file.directoryName
              // )
              if (xhr.status === 200) {
                this.$set(this.status, index, '成功')
                this.$parent.update()
                // this.uploadNextFile() // 上传下一个文件
              } else {
                this.$set(this.status, index, '失败')
                console.error('文件上传失败:', xhr.statusText)
                // this.uploadNextFile() // 上传下一个文件
              }
            }
            xhr.upload.onprogress = e => {
              // const index = this.fileData.findIndex(
              //   item => item.name === file.name && item.directoryName === file.directoryName
              // )
              this.$set(this.percent, index, Math.floor((e.loaded / e.total) * 100))
              //console.log(this.percent, '正常上传')
            }

            const form = new FormData()
            form.append(file.name, file)
            const fullPath = file.fullPath
            const fileNamePath = '/' + file.name
            const url = fullPath ? fullPath : fileNamePath
            const encodedString = url.replace(/%/g, '%25').replace(/#/g, '%23')
            xhr.open('PUT', this.huaweiUrl + encodedString, true)
            xhr.open('PUT', this.huaweiUrl + encodedString, true)
            xhr.setRequestHeader('Authorization', this.huaweiSignature)
            xhr.setRequestHeader('x-obs-date', this.obsDate)
            xhr.setRequestHeader('Content-Type', 'application/octet-stream')
            xhr.setRequestHeader('x-obs-storage-class', this.storageType)
            this.xhr[index] = xhr
            xhr.send(form)
          })
        }
      }
    },
    cancelModal() {
      this.taskVisible = false
    },
    formatSize(sizeInBytes) {
      const units = ['Bytes', 'KB', 'MB', 'GB']
      let size = sizeInBytes
      let unitIndex = 0
      while (size >= 1024 && unitIndex < units.length - 1) {
        size /= 1024
        unitIndex++
      }
      size = Math.round(size * 100) / 100
      return size.toFixed(2) + ' ' + units[unitIndex]
    },
    getFormattedDate() {
      const now = new Date()
      const daysOfWeek = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
      const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
      const dayOfWeek = daysOfWeek[now.getUTCDay()]
      const day = now.getUTCDate().toString().padStart(2, '0')
      const month = months[now.getUTCMonth()]
      const year = now.getUTCFullYear()
      const time =
        now.getUTCHours().toString().padStart(2, '0') +
        ':' +
        now.getUTCMinutes().toString().padStart(2, '0') +
        ':' +
        now.getUTCSeconds().toString().padStart(2, '0')
      return `${dayOfWeek}, ${day} ${month} ${year} ${time} GMT`
    },
    uploadTo(record) {
      const path = this.path ? record.fullPath : '/' + record.fullPath
      return 'oss://' + this.bucketName + path
    },
    // containsChineseCharacters(str) {
    //   const chineseRegex = /[\u4e00-\u9fa5]/
    //   return chineseRegex.test(str)
    // },
  },
}
</script>

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值