Skip to content
本页目录

基于el-upload 封装的文件上传

vue
<div>
    <el-upload
      class="ape-uploader"
      :class="{'ape-uploader-image':isImage, 'ape-uploader-disabled':disabledUpload}"
      name="file"
      :action="uploadToken.host"
      :headers="uploadHeaders"
      :data="uploadData"
      :on-preview="handlePictureCardPreview"
      :before-upload="beforeUpload"
      :on-success="afterUpload"
      :on-remove="removeUpload"
      :list-type="listType"
      :on-error="onError"
      :file-list="uploadFileList"
      :limit="limit"
      :on-exceed="onExceed"
    >
      <el-button v-if="listType === 'text' && !disabledUpload" size="mini" type="success" icon="el-icon-upload" plain>点击上传</el-button>
      <i v-if="listType === 'picture-card' && !disabledUpload" class="el-icon-plus"></i>
    </el-upload>
    <div slot="tip" class="el-upload__tip">{{ uploadTip ? uploadTip : `提示:单次可上传1个文件,单个文件≤50M,最多可上传${limit}个` }}</div>
    <el-dialog :visible.sync="dialogVisible" append-to-body>
      <img width="100%" :src="dialogImageUrl" alt="">
    </el-dialog>
  </div>
javascript
import Cookies from 'js-cookie'

export default {
  model: {
    prop: 'value',
    event: 'update'
  },
  props: {
    value: {
      type: Array,
      required: true,
      default: () => []
    },
    isImage: {
      type: Boolean,
      default: false
    },
    limit: {
      type: Number,
      default: 1
    },
    uploadTip: {
      type: String,
      default: ''
    },
    allowTypeList: {
      type: Array,
      default: function() {
        //支持格式:doc .docx .pdf .xls .xlsx .csv  .ppt .pptx .txt .xmind .mmap .zip .jpeg .png
        return [
          'application/msword',
          'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
          'application/pdf',
          'application/vnd.ms-excel',
          'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
          'text/csv',
          'application/vnd.ms-powerpoint',
          'application/vnd.openxmlformats-officedocument.presentationml.presentation',
          'text/plain',
          'application/x-zip-compressed',
          'application/zip',
          'application/x-zip',
          'image/jpeg',
          'image/png',
          'application/wps-office.doc',
          'application/wps-office.xlsx',
          'application/wps-office.docx',
          'application/wps-office.pptx',
          'application/wps-office.ppt',
          'application/wps-office.xls',
          'application/wps-office.xlsx'
        ]
      }
    },
    allowSize: {
      type: Number,
      default: 1024 * 1024 * 50 //默认50MB
    }
  },
  data() {
    return {
      uploadFileList: [],
      imageUrl: '',
      fileType: '',
      dialogVisible: false,
      dialogImageUrl: '',
      uploadHeaders: {},
      uploadData: {},
      uploadToken: {
        accessid: '',
        host: '',
        policy: '',
        signature: '',
        expire: 0,
        callback: '',
        dir: '',
        upload_save: 'local',
        filename: ''
      }
    }
  },
  created() {
  },
  computed: {
    listType: function() {
      if (this.isImage) {
        return 'picture-card'
      } else {
        return 'text'
      }
    },
    disabledUpload() {
      return this.uploadFileList.length >= this.limit
    }
  },
  methods: {
    /**
     * 点击文件列表中已上传的文件时的钩子
     */
    handlePictureCardPreview(file) {
      if (this.isImage) {
        this.dialogImageUrl = file.url
        this.dialogVisible = true
      }
    },
    /**
     * 超过文件最多数量
     */
    onExceed(files, fileList) {
      let length = fileList.length
      let msg = '最多上传' + length + '个文件'
      this.$message.error(msg)
    },
    /**
     * 获取上传凭证
     */
    async getOssToken() {
      // this.uploadToken = await this.$api.getOssToken()
      //开发环境,正向代理使用
      const BASE_API = process.env.NODE_ENV === 'production' ? localStorage.getItem('BASE_API') : process.env.VUE_APP_BASE_API
      this.uploadToken.host = BASE_API + 'common/file/upload'
    },
    /**
     * 上传完成
     */
    afterUpload(res, file, fileList) {
      console.log(res)
      console.log(file)
      console.log(fileList)
      if (res.code === 200) {
        // this.imageUrl = URL.createObjectURL(file.raw)
        // this.$emit('handleUploadSuccess', res.data[0], this.formatFileList(fileList))
        const arr = fileList.map(item => {
          return item.response?.data ?? {}
        })
        this.uploadFileList = fileList
        this.$emit('update', arr)
      } else {
        this.$message.error(res.message)
        this.uploadFileList = fileList.filter(item => {
          return item['uid'] !== file['uid']
        })
      }

    },
    /**
     * 删除文件
     */
    removeUpload(file, fileList) {
      const arr = fileList.map(item => {
        return item.response?.data ?? {}
      })
      this.uploadFileList = fileList
      this.$emit('update', arr)

      // this.$emit('handleUploadRemove', file, this.formatFileList(fileList))
    },
    /**
     * 上传失败
     */
    onError(err, file, fileList) {
      this.$message.error(err)
      // this.$emit('handleUploadError', err, file, fileList)
    },
    /**
     * 上传前
     */
    async beforeUpload(file) {
      let checkType = this.allowTypeList.includes(file.type)
      let checkSize = file.size > this.allowSize

      if (!checkType) {
        this.$message.error('文件类型不合法,支持格式:doc .docx .pdf .xls .xlsx .csv  .ppt .pptx .txt .zip .jpeg .png')
        throw '文件类型不合法'
      }
      if (checkSize) {
        this.$message.error('文件大小超过限制')
        throw '文件大小超过限制'
      }
      const suffix_index = file.name.lastIndexOf('.')
      this.fileType = file.name.substring(suffix_index)
      //上传配置
      await this.setOssParams()
      await this.$emit('handleUploadBefore', file)
      return true
    },
    /**
     * 设置上传参数
     */
    async setOssParams() {
      await this.getOssToken()
      const urlInfo = JSON.parse(Cookies.get('urlInfo'))
      let fileKey = this.uploadToken.dir + this.uploadToken.filename
      if (this.fileType) {
        fileKey += this.fileType
      }
      if (this.uploadToken.upload_save === 'oss') {
        this.uploadData = {
          key: fileKey,
          policy: this.uploadToken.policy,
          OSSAccessKeyId: this.uploadToken.accessid,
          success_action_status: '200', //让服务端返回200,不然,默认会返回204
          callback: this.uploadToken.callback,
          signature: this.uploadToken.signature
        }
      }
      if (this.uploadToken.upload_save === 'local') {
        this.uploadHeaders = {
          'Authorization': `Bearer ${urlInfo.token}`,
          'systemCode': urlInfo.systemCode
        }
        // this.uploadData = {
        //   upload_path: this.uploadToken.dir
        // }
      }
    },
    /**
     * 格式化文件列表
     */
    formatFileList(fileList) {
      let result = []
      for (let i = 0; i < fileList.length; i++) {
        if (fileList[i].response === undefined) {
          result.push(fileList[i])
        } else {
          let resData = fileList[i].response.data[0]
          let item = {
            id: resData.id,
            name: resData.title,
            path: resData.path,
            url: resData.full_path,
            size: resData.size
          }
          result.push(item)
        }
      }
      return result
    }
  }
}
text
<style rel="stylesheet/scss" lang="scss" scoped>
//按钮宽度
$icon-width: 100px;
//按钮高度
$icon-height: 100px;
.ape-uploader-image {
  .el-upload-dragger {
    width: $icon-width;
    height: $icon-height;
  }
}

.ape-uploader-image {
  .el-upload--picture-card {
    width: $icon-width;
    height: $icon-height;
    line-height: $icon-height;
  }
}

.ape-uploader-image {
  .el-upload-list--picture-card {
    .el-upload-list__item {
      width: $icon-width;
      height: $icon-height;
    }
  }
}

.ape-uploader-disabled {
  .el-upload--picture-card {
    display: none;
  }

}

.el-progress--circle {
  width: 80px !important;

}

.el-progress-circle {
  width: 80px !important;
  height: 80px !important;

}

</style>

基于原生组件+element样式的上传组件

vue
// 使用
<el-form-item label="附件" prop="file">
  <file-upload v-model="Form.file" ref="upload" :limit="1" :voucherNumber="voucherNumber" @restart="onClose"></file-upload>
</el-form-item>
vue
<!--组件-->
<template>
  <div>
    <form enctype="multipart/form-data">
      <label for="file" class="filelabel el-button el-button--mini el-button--success">
        <el-icon class="el-icon-upload"></el-icon>
        选择文件
      </label>
      <input type="file"
             ref="input_file"
             id="file"
             style="display: none"
             @change="handleFileChange"
      />
      <div class="info" v-if="value">
        <div>{{ value }}</div>
        <el-icon class="el-icon-close info-icon" @click.native="close"></el-icon>
      </div>
    </form>
  </div>
</template>

<script>
  import { apiUploadFile } from '@/api/finacial'

  export default {
    model: {
      prop: 'value',
      event: 'update'
    },
    props: {
      value: {
        type: String,
        required: true,
        default: ''
      },
      limit: {
        type: Number,
        default: 1
      },
      uploadTip: {
        type: String,
        default: ''
      },
      voucherNumber: {
        type: String,
        default: ''
      },
      allowTypeList: {
        type: Array,
        default: function() {
          //支持格式:doc .docx .pdf .xls .xlsx .csv  .ppt .pptx .xmind .mmap .zip .jpeg .png
          return [
            'application/msword',
            'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            'application/pdf',
            'application/vnd.ms-excel',
            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            'text/csv',
            'application/vnd.ms-powerpoint',
            'application/vnd.openxmlformats-officedocument.presentationml.presentation',
            'application/x-zip-compressed',
            'application/zip',
            'application/x-zip',
            'image/jpeg',
            'image/png',
            'application/wps-office.doc',
            'application/wps-office.xlsx',
            'application/wps-office.docx',
            'application/wps-office.pptx',
            'application/wps-office.ppt',
            'application/wps-office.xls',
            'application/wps-office.xlsx'
          ]
        }
      },
      allowSize: {
        type: Number,
        default: 1024 * 1024 * 10 //默认10MB
      },
      userOptions: {
        type: Array,
        default: () => []
      },
      permissions: {
        type: Boolean,
        default: false
      }
    },
    data() {
      return {
        query:undefined
      }
    },
    created() {
    },
    computed: {
      listType: function() {
        if (this.isImage) {
          return 'picture-card'
        } else {
          return 'text'
        }
      }
    },
    methods: {
      close() {
        this.$emit('update','')
      },
      check(file) {
        let checkType = this.allowTypeList.includes(file.type)
        let checkSize = file.size > 1024 * 1024 * 10 //默认10MB
        // let length = fileList.length
        // let msg = '最多上传' + length + '个文件'
        // this.$message.error(msg)
        if (!checkType) {
          throw '文件类型不合法,支持格式:doc .docx .pdf .xls .xlsx .csv .ppt .pptx .zip .jpeg .png'
        }
        if (checkSize) {
          throw '文件大小超过限制'
        }
      },

      async handleFileChange(e) {
        const files = e.target.files[0]
        try {
          await this.check(files)
          this.query = await this.setOssParams(files)
          this.$emit('update',files.name)
          this.$refs.input_file.value = ''
        } catch (e) {
          this.$message.error(e)
        }
      },
      // 参数组装
      setOssParams(files) {
        let query = new FormData()
        query.append('file', files)
        query.append('voucherNumber', this.voucherNumber)
        return query
      },
      /**
       * 上传完成
       */
      afterUpload(res, file, fileList) {
        console.log(res)
        console.log(file)
        console.log(fileList)
        if (res.code === '000000') {
          // const arr = fileList.map(item => {
          //   if (item['uid'] === file['uid'] && this.permissions) {
          //     item['response']['data']['permission'] = {
          //       'type': 0, //0=》默认所有上级可见,1 =》360评估人可见,2=》指定用户可见
          //       'designate_user': [] //当type=2时存在并必须有值
          //     }
          //   }
          //   return item.response?.data ?? {}
          // })
          this.uploadFileList = fileList
          // this.$emit('update', arr)
          this.$emit('restart')
        } else {
          this.$message.error(res.message)
          this.uploadFileList = fileList.filter(item => {
            return item['uid'] !== file['uid']
          })
        }

      },
      /**
       * 删除文件
       */

      submit() {
        apiUploadFile(this.query).then(res => {
          this.$message.success(res.message)
          this.$emit('restart')
        }).catch(err=>{
          this.$message.error(err.message)
        }).finally(()=>{
          this.close()
        })
      }
    }
  }
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
  .info{
    background-color: #f4f4f5;
    color: #909399;
    padding: 0 4px;
    color: #909399;
    opacity: 1;
    display: flex;
    justify-content: space-between;
    align-items: center;
    transition: opacity .2s;
    .info-icon{
      cursor: pointer;
    }
  }
</style>