el-upload 上传组件封装

631 阅读1分钟

可以预览,只需要修改一下api就好了。

<template>
  <section class="user-upload">
    <el-upload
      multiple
      list-type="picture-card"
      accept=".pdf, .jpg, .jpeg, .png, .mp4"
      :auto-upload="false"
      :on-change="handleChange"
      :file-list="fileList"
    >
      <div slot="tip" class="el-upload__tip">
        {{ `${$t('支持pdf/jpeg/jpg/png/mp4文件,不超过')}${limitSize}MB` }}
      </div>
      <i slot="default" class="el-icon-plus"></i>
      <div
        slot="file"
        v-loading="file.status === 'ready'"
        slot-scope="{ file }"
        style="height: 100%;width: 100%"
      >
        <i
          v-show="file.status === 'ready'"
          class="el-icon-circle-close"
          style="cursor:pointer;position: absolute;right: 0;top: 0;z-index: 3000;"
          @click="handleUploadingRemove(file)"
        ></i>
        <img
          v-if="/.jpg|.jpeg|.png$/gi.test(file.name)"
          class="el-upload-list__item-thumbnail"
          :src="file.url"
          alt=""
        />
        <div
          v-else-if="/.pdf$/gi.test(file.name)"
          style="text-align: center;position:absolute;top:0;left:0;display: flex;align-items: center;justify-content: center"
          class="el-upload-list__item-thumbnail"
        >
          {{ file.name.slice(-50) }}
        </div>
        <video
          v-else-if="file.name.endsWith('.mp4')"
          class="el-upload-list__item-thumbnail"
          :src="file.url"
        ></video>
        <span class="el-upload-list__item-actions">
          <span
            class="el-upload-list__item-preview"
            @click="handlePictureCardPreview(file)"
          >
            <i class="el-icon-zoom-in"></i>
          </span>
          <span
            v-if="!disabled"
            class="el-upload-list__item-delete"
            @click="handleDownload(file)"
          >
            <i class="el-icon-download"></i>
          </span>
          <span
            v-if="!disabled"
            class="el-upload-list__item-delete"
            @click="handleRemove(file)"
          >
            <i class="el-icon-delete"></i>
          </span>
        </span>
        <span v-show="file.name" class="fileName">{{ file.name }}</span>
      </div>
    </el-upload>
    <el-dialog :before-close="beforeClose" :visible.sync="dialogVisible">
      <section>
        <img
          v-if="dialogVisible && imgShow"
          width="100%"
          :src="dialogSourceUrl"
          alt=""
        />
        <video
          v-if="dialogVisible && videoShow"
          style="width: 100%;"
          autoplay="autoplay"
          controls="controls"
          controlslist="nodownload noremoteplayback"
          :src="dialogSourceUrl"
          muted="muted"
        ></video>
        <div v-show="dialogSourceName" style="text-align: center">
          {{ dialogSourceName }}
        </div>
      </section>
    </el-dialog>
  </section>
</template>

<script>
//注意修改api
//import { fileDownload, fileUpload } from 'api'
import { saveAs } from 'file-saver'

/**
 * emit:
 *    event=input,value=fileList
 * props:
 *    value:{
 *      require:true,
 *      type:[]
 *    }
 *
 * usage:
 *   <Upload v-model='fileList' path='risk' />
 *   fileList must be a array
 *   path is optional
 */
export default {
  props: {
    path: {
      default: 'risk',
      type: String
    },
    value: {
      default() {
        return []
      },
      type: Array,
      require: true
    }
  },
  data() {
    return {
      tempRemoveList: [], // 上传中文件删除
      dialogSourceUrl: '',
      dialogVisible: false,
      disabled: false,
      imgShow: false,
      videoShow: false,
      dialogSourceName: '',
      limitSize: 50, // 单位是MB
      fileList: []
    }
  },
  watch: {
    value(newVal) {
      if ((newVal).length > 0) {
        this.fileList = newVal
      }
    }
  },
  created() {
    this.translateFn()
  },
  methods: {
    translateFn() {
      // 中英文转换,cn是的key是英文  {'english':'英文'}
      // 中英文转换,en是的key是中文  {'英文':'english'}
      const enObj = {
        '文件下载中': 'File downloading',
        '您上传的': 'You uploading',
        '该文件大于': 'The file is larger than',
        '请您重新上传。': 'Please upload again.',
        '该文件有重名文件,请您重新上传。': 'This file has a duplicate name. Please upload it again.',
        '支持pdf/jpeg/jpg/png/mp4文件,不超过': 'Support PDF / jpeg / JPG / PNG / MP4 files, no more than'
      }
      this.$i18n.mergeLocaleMessage('en', enObj)
    },
    beforeClose() {
      this.imgShow = false
      this.videoShow = false
      this.dialogVisible = false
      this.dialogSourceName = ''
    },

    handlePictureCardPreview(file) {
      const surpportReg = /.mp4|.jpg|.jpeg|.png$/gi
      if (!surpportReg.test(file.name)) {
        this.$message.error('The current file does not support preview')
        return
      }

      const reg = /.jpg|.jpeg|.png$/gi
      this.dialogSourceUrl = file.url
      this.dialogSourceName = file.name
      if (reg.test(file.name)) {
        this.imgShow = true
        this.dialogVisible = true
      }
      if (file.name.endsWith('.mp4')) {
        this.videoShow = true
        this.dialogVisible = true
      }
    },

    handleDownload({ url, status, name }) {
      if (status === 'ready' || /^blob/gi.test(url)) {
        return
      }
      this.$message({
        message: this.$t('文件下载中'),
        type: 'success'
      })
      saveAs(url, name)
    },

    beforeCheck(file) {
      const num = this.limitSize
      const isLt = file.size / 1024 / 1024 < num
      if (!isLt) {
        const msg = `${this.$t('您上传的')}[${file.name}],${this.$t('该文件大于')}${num}MB,${this.$t('请您重新上传。')}`
        this.$message.error(msg)
        return false
      }
      // 判断重名文件
      const repeat_judge = this.fileList.find(item => {
        return item.name === file.name
      })
      if (repeat_judge) {
        const msg_repeat = `${this.$t('您上传的')}[${file.name}],${this.$t('该文件有重名文件,请您重新上传。')}`
        this.$message.error(msg_repeat)
        return false
      }
      return true
    },

    handleChange(file) {
      if (!this.beforeCheck(file)) {
        const newFileList = this.fileList.filter(item => item.uid !== file.uid)
        this.updateFileList(newFileList)
        return
      }

      this.fileList.push(file)

      const formData = new FormData()
      formData.append('file', file.raw)
      formData.append('name', file.name)
      formData.append('uid', file.uid)
      formData.append('path', 'risk')
      fileUpload(formData).then(
        res => {
          let newFileList = []
          if (res.code === 200) {
            const removeIndex = this.tempRemoveList.findIndex(item => item.uid === file.uid)
            if (removeIndex !== -1) {
              this.tempRemoveList.splice(removeIndex, 1)
              return
            }
            newFileList = this.fileList.map(item => {
              if (item.uid === file.uid) {
                return {
                  ...file,
                  url: res.data.url,
                  status: 'success'
                }
              }
              return item
            })
          } else {
            newFileList = this.fileList.filter(item => file.uid !== item.uid)
            if (res.errorData) this.$message.error(res.errorData)
          }
          this.updateFileList(newFileList)
        },
        () => {
          const newFileList = this.fileList.filter(item => file.uid !== item.uid)
          this.updateFileList(newFileList)
        }
      )
    },

    handleRemove(file) {
      const newFileList = this.fileList.filter(item => item.uid !== file.uid)
      this.fileList = newFileList
      this.updateFileList(newFileList)
    },

    handleUploadingRemove(file) {
      this.tempRemoveList.push(file)
      this.handleRemove(file)
    },

    updateFileList(newFileList) {
      this.$emit('input', newFileList)
    }
  }
}
</script>

<style lang="scss" scoped>
.fileName {
  position: absolute;
  z-index: 10;
  bottom: 0;
  left: 0;
  right: 0;
  text-align: center;
  color: gray;
  font-size: 12px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  background: rgba(255, 255, 255, 0.6);
}
</style>