fileUpload

98 阅读1分钟
<template>
  <div>
    <!-- 块展示模式 -->
    <Row style="display:inline-block;">
      <viewer :options="options" @inited="inited">
        <div v-for="(item,index) in uploadList" :key="index" class="demo-upload-list" :style="styleDesign">
          <template v-if="item.status === 'finished'">
            <!-- 图片类型的渲染方式 -->
            <Row
              v-if="item.mediaType.indexOf('image')!=-1"
            >
              <img :ref="'img'+index" :src="item.smallUrl" data-enable="1" :data-source="item.url">
              <div class="demo-upload-list-cover">
                <Icon title="预览" type="ios-eye-outline" @click.native="handleView(item.url,index)" />
                <Icon v-if="!uploadConfig.readOnly" title="删除" type="ios-trash-outline" @click.native="handleRemove(item,index)" />
              </div>
            </Row>
            <!-- 非图片外的渲染方式 -->
            <Row v-else>
              <file-image :media-type="item.mediaType" :file-name="item.fileName" :size="size || 80" />
              <div class="demo-upload-list-cover" :title="item.fileName">
                <Icon title="预览" type="ios-eye-outline" @click.native="handleLinkView(item)" />
                <Icon v-if="uploadConfig.readOnly" title="下载" type="ios-cloud-download-outline" @click.native="handleDownload(item.url)" />
                <Icon v-if="!uploadConfig.readOnly" title="删除" type="ios-trash-outline" @click.native="handleRemove(item,index)" />
              </div>
            </Row>
          </template>
          <!-- 进度条展示 -->
          <template v-else>
            <Progress v-if="item.showProgress" :percent="item.percentage" hide-info />
          </template>
        </div>
        <div v-if="!uploadConfig.readOnly" class="my-upload" style="display:inline-block;">
          <div :class="myUploadClass"
               @drop.prevent="onDrop"
               @dragover.prevent="dragOver = true"
               @dragleave.prevent="dragOver = false"
               @click="handleClick"
          >
            <input ref="input" type="file"
                   :accept="acceptType"
                   :multiple="multiple" style="display:none;" @change="handleChange"
            >
            <div :style="styleDesign">
              <Icon type="ios-add" size="20" />
            </div>
          </div>
        </div>
      </viewer>
    </Row>
    <preview-file ref="perviewFile" :read-only="wpsReadOnly" />

    <Modal
      v-model="viedoCtrl"
      title="视频播放"
      :width="540"
      :mask-closable="false"
      :footer-hide="true"
      @on-cancel="cancel"
    >
      <video :src="videoUrl" width="500px" height="400px" controls="controls">
        您的浏览器不支持 video 标签。
      </video>
    </Modal>
  </div>
</template>
<script>
import COS from 'cos-js-sdk-v5'
import fileImage from './../fileImage/fileImage.vue'
export default {
  components: {
    fileImage
  },
  props: {
    defaultList: {
      type: Array,
      default() {
        return []
      }
    },
    multiple: {
      type: Boolean,
      default: true
    },
    uploadConfig: {
      type: Object,
      default() {
        return { fileName: 'base', readOnly: false, maxNum: 100 }
      }
    },
    acceptType: {
      type: String,
      default: '*'
    },
    format: {
      type: Array,
      default () {
        return []
      }
    },
    size: {
      type: String || Number,
      default: ''
    },
    // uploadType:{
    //     type: String,
    //     default:"public"
    // },
    wpsReadOnly: {
      type: Boolean,
      default: true
    },
    hrefUrl: {
      type: Boolean || String,
      default: false
    }
  },
  data() {
    return {
      uploadList: [],
      type: '',
      cos: '',
      // multiple:true, //多文件上传
      dragOver: false, // 允许拖拽
      viedoCtrl: false,
      videoUrl: '',
      styleDesign: {
        width: this.size ? this.size + 'px' : '80px',
        height: this.size ? this.size + 'px' : '80px',
        lineHeight: this.size ? this.size + 'px' : '80px'
      },
      options: { // viewer的配置
        url: 'data-source',
        filter (image) {
          return image.dataset.enable === '1'
        }
      },
      uploadType: 'public'
    }
  },
  computed: {
    myUploadClass() {
      return [
        `my-upload my-upload-drag`,
        {
          'my-upload-dragOver': this.dragOver
        }
      ]
    }
  },
  watch: {
    defaultList: {
      immediate: true,
      handler(fileList) {
        this.uploadList = fileList && fileList.map(item => {
          if (typeof (item) === 'string') {
            return {
              url: item,
              // smallUrl:item+'?imageView2/1/w/80/h/80',
              smallUrl: item,
              status: 'finished',
              mediaType: 'image'
            }
          } else {
            const obj = {
              fileName: item.fileName,
              url: item.url,
              // smallUrl:item.url+'?imageView2/1/w/80/h/80',
              smallUrl: item.url,
              status: 'finished',
              mediaType: item.mediaType || 'image'
            }
            item.id ? obj.id = item.id : ''
            item.fileId ? obj.fileId = item.fileId : ''
            return obj
          }
        })
        this.$nextTick(() => {
          this.updateViewer()
        })
      }
    }
  },
  mounted: function() {
    const path = '/base/cos/sesseionToken/ap-guangzhou/' + (this.uploadType == 'public' ? this.config.uploadPublicUrl : this.config.uploadPrivateUrl)
    // console.log('upload创建');
    const _this = this
    var COS = require('cos-js-sdk-v5')
    this.cos = new COS({
      // 必选参数
      getAuthorization: function (options, callback) {
        // 服务端 JS 和 PHP 例子:https://github.com/tencentyun/cos-js-sdk-v5/blob/master/server/
        // 服务端其他语言参考 COS STS SDK :https://github.com/tencentyun/qcloud-cos-sts-sdk
        // STS 详细文档指引看:https://cloud.tencent.com/document/product/436/14048
        _this.$get(path).then(res => {
          callback({
            TmpSecretId: res.data.tmpSecretId,
            TmpSecretKey: res.data.tmpSecretKey,
            XCosSecurityToken: res.data.token,
            // 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
            StartTime: new Date().getTime() / 1000, // 单位是秒
            ExpiredTime: res.data.expiredTime // SDK 在 ExpiredTime 时间前,不会再次调用 getAuthorization
          })
        })
      }
    })
  },
  methods: {
    // 监听viewer组件
    inited(viewer) {
      this.$viewer = viewer
    },
    // 更新viewer组件
    updateViewer() {
      if (this.$viewer) {
        this.$viewer.update()
      }
    },
    // 判断文件后缀名称
    getFileType(name) {
      let fileType = ''
      // 判断上传文件类型
      if (name.lastIndexOf('.') != -1) {
        const places = name.lastIndexOf('.') + 1
        fileType = name.substring(places).toLowerCase()
      }
      const archiveArr = ['arj', 'cab', 'rar', 'tar', 'zip', '7z', 'gzip', 'jar', 'z', 'ace']
      if (archiveArr.indexOf(fileType) != -1) {
        return fileType
      } else {
        return false
      }
    },
    /* ======================上传图片start=======================*/
    // 预览
    handleView (url, index) {
      this.$refs[`img${index}`][0].click()
    },
    // 打开链接
    handleLinkView(item) {
      if (item.mediaType.includes('video')) {
        this.videoUrl = item.url
        this.viedoCtrl = true
      } else {
        if (this.hrefUrl) {
          const url = Object.prototype.toString.call(this.hrefUrl) == '[object String]' ? this.hrefUrl : item.url
          window.open(url, '_blank')
          return
        }
        this.$refs.perviewFile.preview(item)
      }
    },
    // 关闭视频
    cancel() {
      this.videoUrl = ''
      this.viedoCtrl = false
    },
    handleDownload(url) {
      window.open(url)
    },
    // 点击上传事件
    handleClick () {
      if (this.itemDisabled) { return }
      if (this.uploadList.length >= this.uploadConfig.maxNum) {
        this.$Message.error(`最多上传${this.uploadConfig.maxNum}份附件`)
        return
      }
      this.$refs.input.click()
    },
    // 拖拽事件
    onDrop(e) {
      this.dragOver = false
      if (this.itemDisabled) return
      this.uploadFiles(e.dataTransfer.files)
    },
    // input change事件
    handleChange(e) {
      const files = e.target.files
      if (!files) { return }
      this.uploadFiles(files)
      this.$refs.input.value = null
    },
    formatFile(file) {
      if (this.format.length) {
        const _file_format = file.name.split('.').pop().toLocaleLowerCase()
        const checked = this.format.some(item => item.toLocaleLowerCase() === _file_format)
        if (!checked) {
          this.onFormatError(file)
          return false
        }
      }
      this.upload(file)
    },
    onFormatError(file) {
      this.$Message.error(file.name + '的文件格式不正确,请选择' + this.acceptType + '格式的文件。')
    },
    uploadFiles(files) {
      let postFiles = Array.prototype.slice.call(files)
      if (!this.multiple) postFiles = postFiles.slice(0, 1)
      if (postFiles.length === 0) return
      postFiles.forEach(file => {
        this.formatFile(file)
      })
    },
    // 上传
    upload (file) {
      const fileSplitArr = file.name.split('.')
      const key = file.lastModified + Math.floor(Math.random() * 9999) + '.' + fileSplitArr[fileSplitArr.length - 1]
      const _this = this
      const index = _this.uploadList.length
      const json = { key: key }
      this.cos.putObject({
        Bucket: _this.uploadType == 'public' ? _this.config.uploadPublicUrl : _this.config.uploadPrivateUrl, /* 必须 */
        Region: 'ap-guangzhou', /* 存储桶所在地域,必须字段 */
        Key: key, /* 必须 */
        StorageClass: 'STANDARD',
        Body: file, // 上传文件对象
        onProgress: function(progressData) {
          // console.log(progressData);
          json.status = 'unFinished'
          json.showProgress = true
          json.percentage = (progressData.percent) * 100
          _this.$set(_this.uploadList, index, json)
        }
      }, function(err, data) {
        if (data.statusCode == 200) {
          json.status = 'finished'
          json.showProgress = false
          json.percentage = 100
          json.mediaType = file.type && file.type.length > 0 ? file.type : `.${file.name.split('.').pop().toLocaleLowerCase()}`
          json.fileName = file.name
          json.smallUrl = 'http://' + data.Location + '?imageView2/1/w/80/h/80'
          json.url = 'http://' + data.Location
          if (_this.uploadType != 'public') {
            _this.getPublicUrl(key, json, index)
          } else {
            _this.$set(_this.uploadList, index, json)
            _this.$emit('getFileList', _this.uploadList)
          }
        } else {
          _this.uploadList.splice(index, 1)
        }
        _this.$nextTick(() => {
          _this.updateViewer()
        })
      })
    },
    // 删除
    handleRemove (file, index) {
      this.uploadList.splice(index, 1)
      this.$emit('getFileList', this.uploadList)
      this.$nextTick(() => {
        this.updateViewer()
      })
    },
    getPublicUrl(key, json, index) {
      const url = '/base/cos/presigned-url/ap-guangzhou/' + this.config.uploadPrivateUrl + '?keys=' + key
      this.$get(url).then(res => {
        if (res.code == 0) {
          const pubUrl = res.data[0]
          json.smallUrl = pubUrl
          json.url = pubUrl
          this.$set(this.uploadList, index, json)
          this.$emit('getFileList', this.uploadList)
        }
      })
    }
    /* ======================上传图片  end=======================*/
  }
}
</script>
<style scoped lang="scss">
@import "./fileUpload.scss";
</style>

@import '@/assets/globalStyle.scss';
.demo-upload-list{
    display: inline-block;
    text-align: center;
    border: 1px solid transparent;
    border-radius: 4px;
    overflow: hidden;
    background: #fff;
    position: relative;
    box-shadow: 0 1px 1px rgba(0,0,0,.2);
    margin-right: 4px;
}
.demo-upload-list img{
    width: 100%;
    height: 100%;
}
.demo-upload-list-cover{
    display: none;
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    background: rgba(0,0,0,.6);
}
.demo-upload-list:hover .demo-upload-list-cover{
    display: block;
}
.demo-upload-list-cover i{
    color: #fff;
    font-size: 20px;
    cursor: pointer;
    margin: 0 2px;
}
.my-upload-drag{
    background: #fff;
    border: 1px dashed $borderColor;
    border-radius: 4px;
    text-align: center;
    cursor: pointer;
    position: relative;
    overflow: hidden;
    -webkit-transition: border-color 0.2s ease;
    transition: border-color 0.2s ease;
}
.my-upload-drag:hover {
    border: 1px dashed $globalMainColor;
}
.my-upload-dragOver{
    border: 2px dashed $globalMainColor;
}