<template>
  <div class="com-uploader">
    <!-- 显示单个文件 -->
    <template v-if="listType === 'picture'">
      <div v-if="image" class="el-upload">
        <div class="show-picture">
          <img :src="image">
          <div class="operate-mask" @click.stop>
            <i class="el-icon-zoom-in" @click.stop="() => onPreview(image, 0)" />
            <i v-if="mode === 'edit'" class="el-icon-delete" @click.stop="() => onRemove()" />
          </div>
        </div>
      </div>
      <PadBridge :upload-type="uploadType" :sign-key="signKey" :attachment-url="attachmentUrl" v-else>
        <el-upload
          ref="fileUpload"
          :class="image ? 'uploaded' : ''"
          :show-file-list="showFileList"
          :action="action"
          :accept="accept"
          :headers="headers"
          :data="postData"
          :name="name"
          :disabled="uploadLoading"
          :before-upload="beforeUpload"
          :on-progress="onUploading"
          :on-success="(res, file, fileList) => onSuccess(res, file, fileList)"
          :on-error="onError"
        >
          <div v-loading="uploadLoading" class="upload-text">
            <p class="desc">{{ placeholder }}</p>
          </div>
        </el-upload>
      </PadBridge>
    </template>

    <!-- 显示多个文件 -->
    <div v-else class="upload-list-drag">
      <draggable v-if="imageList.length > 0" v-model="imageList" group="people" class="el-upload-list el-upload-list--picture-card" @start="drag=true" @end="drag=false">
        <div v-for="(item, index) in imageList" :key="index" class="el-upload uploaded">
          <div class="show-picture">
            <div v-if="item.fileName && item.fileName.indexOf('.pdf') > 0" class="preview-pdf">
              <div class="pdf-container" />
            </div>
            <img v-else :src="item.accessUrl">
            <div class="operate-mask" @click.stop>
              <i class="el-icon-zoom-in" @click.stop="() => onPreview(item, index)" />
              <i v-if="mode === 'edit'" class="el-icon-delete" @click.stop="() => onRemove(index)" />
            </div>
          </div>
        </div>
      </draggable>
      <template v-if="imageList.length < limit">
        <PadBridge :upload-type="uploadType" :sign-key="signKey" :attachment-url="attachmentUrl">
          <el-upload
            ref="fileUpload"
            :show-file-list="showFileList"
            :action="action"
            :limit="limit"
            :accept="accept"
            :headers="headers"
            :data="postData"
            :name="name"
            :disabled="uploadLoading"
            :before-upload="beforeUpload"
            :on-progress="onUploading"
            :on-success="(res, file, fileList) => onSuccess(res, file, fileList)"
            :on-error="onError"
            :on-exceed="onExceed"
            list-type="picture-card"
          >
            <div v-loading="uploadLoading" slot="default" class="upload-text">
              <p class="desc">{{ placeholder }}</p>
            </div>
          </el-upload>
        </PadBridge>
      </template>
    </div>

    <image-viewer v-if="showViewer" :z-index="zIndex" :initial-index="imageIndex" :on-close="closeViewer" :url-list="previewList" />
  </div>
</template>

<script>
// 编辑使用示例
// <uploader v-model="form.picture" :data="{rootPath: 'user/', path: 'compnay/'}" @on-error="onUploadError" @on-success="onUploadSuccess" @on-remove="onUploadRemove" />
// 预览使用示例
// <uploader v-model="form.picture" mode="preview" />
import PadBridge from '@/components/PadBridge'
import draggable from 'vuedraggable'
import { getToken } from '@/utils/auth'
import ImageViewer from './image-viewer.vue'
import { imageViewer } from '@/utils/upload'

export default {
  name: 'Uploader',
  components: {
    draggable,
    ImageViewer,
    PadBridge
  },
  props: {
    // 文件列表的类型, picture: 单个文件上传, picture-card: 展示图片列表
    listType: {
      type: String,
      default: 'picture'
    },
    // 上传文件提示
    placeholder: {
      type: String,
      default: '上传文件'
    },
    // 是否显示已上传文件列表, 仅对listType = 'picture'有效
    showFileList: {
      type: Boolean,
      default: false
    },
    // 文件上传地址
    action: {
      type: String,
      default: `${process.env.VUE_APP_BASIC_API}file/upload`
    },
    // 文件上传类型
    accept: {
      type: String,
      default: 'image/png, image/jpeg, image/jpg'
    },
    // 是否需要加密
    security: {
      type: Boolean,
      default: false
    },
    // 设置上传的请求头部
    headers: {
      type: Object,
      default() {
        return {
          Authorization: `bearer ${getToken()}`
        }
      }
    },
    // 上传时附带的额外参数, 必填
    postData: {
      type: Object,
      default() {
        return {
          rootPath: '',
          path: ''
        }
      }
    },
    // 上传的文件字段名
    name: {
      type: String,
      default: 'file'
    },
    // 最大允许上传个数 仅对listType = 'picture-card'有效
    limit: {
      type: Number,
      default: 0
    },
    // v-model值
    value: {
      type: [String, Array],
      default: ''
    },
    // 展示方式 edit:编辑模式, preview:预览模式
    mode: {
      type: String,
      default: 'edit'
    },
    beforeUpload: {
      type: Function,
      default: function() { }
    },
    uploadType: {
      type: Array,
      default: undefined
    },
    signKey: {
      type: String,
      default: ''
    },
    // 附件信息
    attachmentUrl: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      image: '',
      imageList: [],

      previewList: [],
      showViewer: false,
      zIndex: 2000,
      imageIndex: 0,
      prevOverflow: '',
      uploadLoading: false
    }
  },
  watch: {
    value(val) {
      if (this.listType === 'picture') {
        this.image = val
      } else {
        this.imageList = val || []
      }
    }
  },
  created() {
    if (this.listType === 'picture') {
      this.image = this.value
    } else {
      this.imageList = this.value || []
    }
  },
  methods: {
    /**
     * 上传文件
     */
    onUploading() {
      // 设置当前正在loading中
      this.uploadLoading = true
    },

    // beforeUpload是props，不是$emit，使用成$meit会导致beforeUpload无法校验文件
    onBefore(file) {
      // const isLt10M = file.size / 1024 / 1024 < 10
      // if (!isLt10M) this.$message.error('上传图片大小不能超过 10MB!')
      // return isLt10M
      if (!this.data.rootPath || !this.data.path) {
        this.$message.error('rootPath或path参数未配置')
        return false
      } else if (this.listType === 'picture-card' && this.limit > 0 && this.imageList.length >= this.limit) {
        this.$message.error('已超过最大允许上传个数')
        return false
      }
      this.$emit('on-before', file)
    },

    async onSuccess(res, file, fileList) {
      const data = res.data || {}
      try {
        if (this.security) {
          data.accessUrl = await imageViewer(data.uuid)
        }
      } catch (error) {
        console.error('文件上传失败：', error)
      }
      // 关闭loading框
      this.uploadLoading = false
      if (res.success && data.accessUrl) {
        this.$emit('on-success', data, file, fileList)
        if (this.listType === 'picture') {
          this.image = data.accessUrl
          this.$emit('input', this.image)
        } else {
          this.imageList.push(data)
          this.$emit('input', this.imageList)
        }
        this.$emit('upload-success', data)
      } else {
        this.$emit('on-error')
      }
    },

    onError(err, file, fileList) {
      // 关闭loading框
      this.uploadLoading = false
      this.$emit('on-error', err, file, fileList)
    },

    onExceed(files, fileList) {
      this.$message.error('已超过最大允许上传个数')
      this.$emit('on-exceed', files, fileList)
    },

    onPreview(img, index) {
      // 如果当前是pdf
      if (img && img.fileName && img.fileName.indexOf('.pdf') > 0) {
        window.open(img.accessUrl, '_blank')
        return
      }
      this.imageIndex = index
      if (this.listType === 'picture') {
        this.previewList = [img]
      } else {
        this.previewList = this.imageList.map(item => {
          return item.accessUrl
        })
      }
      this.prevOverflow = document.body.style.overflow
      document.body.style.overflow = 'hidden'
      this.showViewer = true
    },

    closeViewer() {
      document.body.style.overflow = this.prevOverflow
      this.showViewer = false
    },

    onRemove(index) {
      if (this.listType === 'picture') {
        this.image = ''
        this.$emit('on-remove', '')
        this.$emit('input', this.image)
      } else {
        this.imageList.splice(index, 1)
        this.$emit('on-remove', index)
        this.$emit('input', this.imageList)
      }
    }
  }
}
</script>
<style lang="scss">
.com-uploader {
  .show-picture {
    display: flex;
    align-items: center;
    width: 68px;
    height: 68px;
    position: relative;
    > img {
      width: 100%;
      display: block;
    }
    &:hover {
      .operate-mask {
        opacity: 1;
        .el-icon-delete,
        .el-icon-zoom-in {
          display: inline-block;
          cursor: pointer;
          color: #fff;
        }
      }
    }
  }
  .operate-mask {
    position: absolute;
    width: 100%;
    height: 22px;
    left: 0;
    bottom: 0;
    cursor: default;
    text-align: center;
    color: #fff;
    opacity: 0;
    background-color: rgba(0, 0, 0, 0.5);
    transition: opacity 0.3s;
    display: flex;
    align-items: center;
    justify-content: center;
    .el-icon-delete,
    .el-icon-zoom-in {
      width: 50%;
      height: 22px;
      line-height: 22px;
      flex: 1;
      display: none;
      font-size: 12px;
      opacity: 0.8;
    }
    .el-icon-delete {
      border-left: 1px solid #fff;
    }
  }
  .uploaded {
    .el-upload {
      border-radius: 6px;
    }
  }
  .el-upload {
    background: #F7F8FA url(placeholder.svg) no-repeat center 11px;
    border: 1px dashed #D7DBDF;
    width: 68px;
    height: 68px;
    line-height: 1;
    border-radius: 4px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
    display: inline-block;
    &:hover {
      border-color: #ddd;
    }
  }
  .upload-text {
    margin: 0 auto;
    width: 68px;
    height: 68px;
    position: absolute;
    top: 0;
    left: 0;
    .desc {
      margin: 44px auto 0;
      font-size: 12px;
      color: #9c9d9d;
      font-family: PingFangSC-Regular, PingFang SC;
      font-weight: 400;
    }
  }
  .upload-list-drag {
    display: flex;
    flex-wrap: wrap;
    line-height: 1;
    .el-upload {
      margin: 0 10px 0 0;
    }
  }
  .el-icon-circle-close {
    color: #fff;
  }
  .preview-pdf {
    align-items: center;
    cursor: pointer;
    display: flex;
    width: 100%;
    height: 100%;
    justify-content: center;
    .pdf-container {
      align-items: center;
      background: #FF5F61;
      display: flex;
      width: 28px;
      height: 36px;
      justify-content: center;
      position: relative;
      &:before {
        color: #FFFFFF;
        content: "P";
        display: block;
        font-size: 16px;
        font-weight: 900;
      }
      &:after {
        background: linear-gradient(127deg, #FFE6E7 0%, #FFC5C6 100%);
        box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.12);
        content: "";
        display: block;
        width: 7px;
        height: 6px;
        position: absolute;
        right: 0;
        top: 0
      }
    }
  }
}
</style>
