<!--
  @description：上传组件
-->
<template>
  <!-- code 01 展示 00或空 不展示 -->
  <div v-if="codeData[code]==='01'||!code" class="file">
    <ul class="file-list clearfix">
      <li v-if="title" class="name fl">
        {{ title }}
      </li>
      <div v-if="isUpload">
        <div class="fileBtn" :style="{display:(fileList.length<limit?'block':'none')}">
          <el-upload
            :ref="fileRef"
            :name="name"
            :action="action+createURL(data)"
            :headers="importHeaders"
            :accept="accept"
            :multiple="multiple"
            :limit="limit"
            :auto-upload="autoUpload"
            :disabled="disabled"
            :show-file-list="false"
            :file-list="fileList"
            :before-upload="beforeUploadFile"
            :on-exceed="onExceed"
            :on-success="onSuccess"
            :on-change="onFileChange"
            :on-error="onError"
            :on-progress="handlePreview"
          >
            <template v-if="fileList.length<limit">
              <el-button
                slot="trigger"
                v-loading.fullscreen.lock="fullscreenLoading"
                element-loading-text="附件上传中，请稍后"
                element-loading-spinner="el-icon-loading"
                element-loading-background="rgba(255, 255, 255, 0.2)"
                :size="size"
                :type="butType"
                icon="iconfont icon-icon_upload"
              >
                {{ butText }}
              </el-button>
              <div v-if="tipText!==''" slot="tip" :style="{display:tipIsBlock}" class="tipText" v-text="tipText" />
            </template>
          </el-upload>
        </div>
      </div>
      <!--已上传列表-->
      <template v-if="showFileList">
        <li v-for="(item,index) in fileList" :key="index" class="fl">
          <!--文件展示样式-->
          <div v-if="listType==='text'" class="file-other clearfix">
            <span class="inline-file pointer" @click="handDownLoad(item)">
              <i class="iconfont icon-icon_file" />
              {{ item.name }}
            </span>
            <span v-if="!item.look" class="delete fr pointer" @click="onFileDelete(item,index)">
              <i class="iconfont icon-guanbi" />
            </span>
            <el-progress v-if="item.progressFlag" :percentage="item.progressPercent" :stroke-width="3" />
          </div>
          <!--图片展示样式-->
          <div v-if="listType==='picture' && itemType(item.name)" title="点击查看大图" class="file-image clearfix">
            <el-image
              class="image"
              :src="item.imgUrl || readImageUrl + item.url"
              :preview-src-list="[item.imgUrl || readImageUrl + item.url]"
            />
            <div class="bottom">
              <span class="img_delete pointer" title="删除图片" @click="onFileDelete(item,index)">
                <i class="el-icon-delete" />
              </span>
            </div>
          </div>
        </li>
      </template>
    </ul>
  </div>
</template>

<script>
import { readImageRoot } from '@api/common/uploadCenter'
import { delFile, upLoadFileUrl, downLoadFileUrl, getFileDetail, downLoadFile } from '@/api/common/uploadCenter'
/* 公用方法*/
import { createURL, download } from '@assets/js/utils'// 常用方法
import Cookies from 'js-cookie'
/* Vuex */
import { mapState, mapGetters, mapMutations } from 'vuex'
//  函数
function noop() {
}

export default {
  name: 'Upload',
  props: {
    title: {
      type: String,
      default: '附件'
    },
    // 按钮编码（控制该按钮显隐）
    code: {
      type: [String, undefined],
      default: undefined
    },
    // 按鈕文字
    butText: {
      type: String,
      default: '点击上传'
    },
    // 按钮状态样式
    butType: {
      type: String,
      default: 'upload'
    },
    // ref元素
    fileRef: {
      type: String,
      default: 'fileRef'
    },
    // 提示文字
    tipText: {
      type: String,
      default: ''
    },
    // 提示文字是否块级显示 默认 行内
    // inline 行内 block 块级
    tipIsBlock: {
      type: String,
      default: 'inline'
    },
    // 上传地址
    action: {
      type: String,
      default: upLoadFileUrl
    },
    // 上传的文件字段名
    name: {
      type: String,
      default: 'file'
    },
    // 是否展示 上传列表 true展示 false 不展示
    showFileList: {
      type: Boolean,
      default: true
    },
    // 上传文件类型
    accept: {
      type: String,
      default: ''
    },
    // 上传附件大小 单位 MB
    fileSize: {
      type: Number,
      default: 500
    },
    // 上传按钮大小
    size: {
      type: String,
      default: 'medium'
    },
    // 上传个数 默认最多20个
    limit: {
      type: Number,
      default: 20
    },
    // 是否支持多选文件
    multiple: {
      type: Boolean,
      default: true
    },
    // 是否启用自动上传
    autoUpload: {
      type: Boolean,
      default: false
    },
    // 是否使用组件内删除
    autoDelete: {
      type: Boolean,
      default: false
    },
    // 是否禁用上传
    disabled: {
      type: Boolean,
      default: false
    },
    // 上传参数
    data: {
      type: Object,
      default() {
        return {}
      }
    },
    // 上传成功
    success: {
      type: Function,
      default: noop
    },
    // 上传文件之前的钩子，参数为上传的文件，若返回 false 或者返回 Promise 且被 reject，则停止上传。
    beforeUpload: {
      type: Function,
      default: noop
    },
    // 文件状态改变时的钩子，添加文件、上传成功和上传失败时都会被调用
    onChange: {
      type: Function,
      default: noop
    },
    onDelete: {
      type: Function,
      default: noop
    },
    // 文件类型 text/picture
    listType: {
      type: String,
      default: 'text'
    },
    // 是否可以上传
    isUpload: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      readImageUrl: readImageRoot, // 预览图片
      fullscreenLoading: false,
      dataUrl: '', // 上传地址+参数
      downLoadFileUrl: downLoadFileUrl,
      createURL: createURL,
      importHeaders: {},
      fileList: [],
      progress: 0,
      loadingDialogVisible: false
    }
  },
  computed: {
    /* langcommon 国际化*/
    ...mapGetters(['language']),
    ...mapState({
      codeData: state => state.user.userButtonAuthority // 用户按钮权限数据
    })
  },
  watch: {
    // 监听userUploadProgress的变化并实时更新到变量progress
    '$store.getters.userUploadProgress': function(val) {
      this.progress = val
    },
    // 上传参数
    'data.bizId'() {
      this.getFile()// 获取附件
    }
  },
  created() {
    this.importHeaders['X-AUTH-TOKEN'] = Cookies.get('X-AUTH-TOKEN')// token
    this.getFile()// 获取附件
  },
  methods: {
    ...mapMutations(['UPLOAD_USER_PROGRESS']),
    // 上传之前
    beforeUploadFile(file) {
      this.beforeUpload(file)
      this.dataUrl = this.data // 更新上传参数
      let isType = true // 是否可以上传 布尔值
      isType = this.fileAccept(file)// 文件类型校验
      if (isType) isType = this.fileSizeUp(file)// 上传附件大小限制
      return isType
    },
    // 文件类型校验
    fileAccept(file) {
      /* 校验上传类型*/
      let isType = true // 是否可以上传 布尔值
      if (this.accept) {
        let type = file.name.slice(file.name.lastIndexOf('.') + 1, file.name.length)// 截取得到后缀
        type = type.toLowerCase()// 转小写
        if (!this.accept.includes(type)) {
          this.$message({
            type: 'warning',
            message: '不支持的文件类型'
          })
          isType = false
          //  不可以上传
        } else {
          // 可以上传
          isType = true
        }
      }
      return isType
    },
    // 附件上传大小限制
    fileSizeUp(file) {
      const isLt2M = file.size / 1024 / 1024 < this.fileSize
      if (!isLt2M) {
        this.$message.warning('上传文件大小不能超过 ' + this.fileSize + 'MB!')
      }
      return isLt2M
    },
    // 当选择手动上传时
    submitUpload() {
      setTimeout(() => {
        this.$refs[this.fileRef].submit()
      }, 400)
    },
    // 判断是否为图片
    itemType(type) {
      const fileend = type.substr(type.lastIndexOf('.') + 1)
      return ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'webp', 'psd', 'svg', 'tiff'].indexOf(fileend.toLowerCase()) !== -1
    },
    // 文件超出个数限制时的钩子
    onExceed(files, fileList) {
      this.$message.warning(`最大不能超过 ${this.limit} 个文件`)
    },
    // 文件状态改变时的钩子，添加文件、上传成功和上传失败和删除时都会被调用
    onFileChange(file, fileList) {
      this.fileList = fileList
      this.onChange(file, fileList)
    },
    // 文件上传时的钩子
    handlePreview(event, file, fileList) {
      this.fileList = fileList
      for (let i = 0; i < this.fileList.length; i++) {
        if (this.fileList[i].percentage < 100 && this.fileList[i].percentage > 0) {
          this.fileList[i].progressFlag = true
          this.fileList[i].progressPercent = Math.floor(this.fileList[i].percentage)
          this.fullscreenLoading = true
        }
      }
    },
    // 上传成功
    onSuccess(response, file, fileList) {
      // 判断附件上传未成功的情况
      if (response.header.ret === '-1') {
        for (let i = 0; i < this.fileList.length; i++) {
          if (fileList[i].name === file.name) {
            fileList.splice(i, 1)
          }
        }
        return this.$message.error(response.header.msg)
      }
      file.fileData = response.data
      file.fileData = {
        fileId: response.data.fileId, // 附件主键Id
        fileType: response.data.fileType// 文件类型
      }
      for (let i = 0; i < this.fileList.length; i++) {
        this.fileList[i].progressFlag = false
        if (this.fileList[i].status === 'success') {
          // 如果上传是图片 转换文件为blob
          if (!this.fileList[i].url) {
            const imgUrl = window.URL.createObjectURL(new Blob([fileList[i].raw]))
            this.fileList[i].imgUrl = imgUrl
          }
          this.$message.success(response.header.msg)
          this.success(response, file, fileList)
          this.fullscreenLoading = false
          this.$emit('onSuccess', fileList)
        }
      }
    },
    // 文件上传失败时的钩子
    onError(err, file) {
      this.$message.warning(err)
      this.fullscreenLoading = false
    },
    // 删除
    onFileDelete(file, index) {
      if (this.autoDelete) {
        // 使用组件内的删
        if (file.fileData) { // 判断是否有Id
          const data = { fileId: file.fileData.fileId, fileType: file.fileData.fileType }
          delFile(data).then(response => {
            this.fileList.splice(index, 1)
            this.$message.success(`删除成功`)
            this.$emit('onFileDelete')
            this.onChange(file, this.fileList) // 文件状态改变时的钩子，添加文件、上传成功和上传失败和删除时都会被调用
          })
        } else {
          this.fileList.splice(index, 1)
          this.$message.success(`删除成功`)
          this.$emit('onFileDelete')
          this.onChange(file, this.fileList) // 文件状态改变时的钩子，添加文件、上传成功和上传失败和删除时都会被调用
        }
      } else {
        if (this.onDelete(file)) {
          this.fileList.splice(index, 1)
          this.$emit('onFileDelete')
          this.$message.success(`删除成功`)
          this.onChange(file, this.fileList) // 文件状态改变时的钩子，添加文件、上传成功和上传失败和删除时都会被调用
        }
      }
    },
    // 获取附件信息
    getFile() {
      if (this.data.bizId) {
        getFileDetail(this.data).then(response => {
          const fileListData = response.data
          const len = fileListData.length
          for (let i = 0; i < len; i++) {
            const fileData = {
              name: fileListData[i].title + '.' + fileListData[i].extend,
              url: fileListData[i].path,
              fileData: {
                fileId: fileListData[i].fileId,
                fileType: fileListData[i].fileType
              },
              downLoadFileUrl: this.downLoadFileUrl + '?fileId=' + fileListData[i].fileId + '&fileType=' + fileListData[i].fileType,
              raw: {
                type: fileListData[i].extend
              }
            }
            this.fileList.push(fileData)
            // this.handDownLoad()
          }
          this.onChange('', this.fileList) // 文件状态改变时的钩子，添加文件、上传成功和上传失败和删除时都会被调用
        }).catch(() => {
        })
      }
    },
    // 下载
    handDownLoad(item) {
      if (item) {
        this.loadingDialogVisible = true
      }
      this.UPLOAD_USER_PROGRESS(0)
      const params = {
        fileId: item.fileData.fileId,
        fileType: item.fileData.fileType
      }
      this.$nextTick(() => {
        downLoadFile(params).then((res) => {
          download(res, item.name)
          this.loadingDialogVisible = false
        }).catch(() => {
          this.loadingDialogVisible = false
        })
      })
    }
  }
}
</script>

<style lang="less" scoped>
  @import '~@assets/style/common/public.less';
  /*提示文字样式*/
  .tipText {
    margin-left: 12px;
  }
  /*上传按钮*/
  .fileBtn {
    margin-bottom: 16px;
    margin-right: 16px;
    display: block;
  }
  /*文件样式*/
  .file-list {
    color: @blue;
    width: 100%;
    li.name {
      color: #606266;
    }
    li {
      display: inline-block;
      margin-bottom: 16px;
      margin-right: 16px;
      line-height: 30px;
      font-size: 14px;
      font-weight: normal;
      display: inline-block;
      /*文件展示样式*/
      .file-other {
        padding: 0 16px;
        background-color: @french-grey;
        border-radius: 4px;
      }
      /*图片展示样式*/
      .file-image {
        display: flex;
        flex-wrap: wrap;
        justify-content: flex-start;
        align-items: flex-end;
        position: relative;
        &:hover .bottom {
          display: block;
        }
        .bottom{
          display: none;
          width: 100%;
          height: 24px;
          background-color: rgba(0,0,0,.5);
          bottom: 0;
          position: absolute;
          text-align: right;
          .img_delete{
            position: absolute;
            right: 6px;
            bottom: 3px;
            line-height: normal;
            color: white;
          }
        }
        .image {
          height: 100px;
          width: 100px;
          border-radius: 4px;
          background-color: @french-grey;
          background-repeat: no-repeat;
          background-position: center;
          background-size: 100% 100%;
          img{
            width: 100%!important;
          }
        }
      }
      .name {
        color: @font;
      }
      .delete {
        margin-left: 8px;
        margin-right: 8px;
      }
    }
    li:last-child {
      margin-right: 0;
    }
  }
  /deep/.el-progress-bar__inner{
    background-color:#67C23A
  }
</style>
