<template>
  <div class="comp-certificate-upload-wrap">
    <PadBridge>
      <el-upload
        ref="uploadRef"
        :auto-upload="true"
        :show-file-list="false"
        :multiple="false"
        :on-success="onSuccess"
        :on-error="onUploadError"
        :before-upload="onBeforeUpload"
        :on-progress="onProgress"
        :data="reqParams"
        :headers="reqHeaders"
        :action="actionUrl"
        class="comp-certificate-upload"
        name="file"
        accept=".jpg,.jpeg,.png,.bmp"
      >
        <template v-if="state === 'init'">
          <div class="su-icon">
            <img :src="bgImgUrl">
          </div>
          <div class="su-text">{{ desc }}</div>
        </template>
        <template v-else-if="state === 'uploading'">
          <div class="su-loading-text">文件上传中</div>
          <div class="su-loading-bar">
            <div :style="{width: uploadPercent}" class="su-loading-bar-progress" />
          </div>
        </template>
        <template v-else-if="state === 'success'">
          <img :src="fileRemoteUrl.url" alt="" class="su-img">
          <div class="su-success-operate-wrapper">
            <i class="el-icon-delete su-operate-btn" @click.stop.prevent="clickDel"/>
            <i class="el-icon-zoom-in su-operate-btn zoom" @click.stop.prevent>
              <el-image
                :src="fileRemoteUrl.url"
                :preview-src-list="[fileRemoteUrl.url]"/>
            </i>
          </div>
        </template>
        <template v-else-if="state === 'error'">
          <div class="su-text">上传失败</div>
          <div class="su-success-operate-wrapper">
            <i class="el-icon-delete su-operate-btn" @click.stop.prevent="clickDel"/>
          </div>
        </template>
      </el-upload>
    </PadBridge>
    <div class="device-wrapper">
      <i v-if="device.showTakePhoto" class="icon-device-video" @click.stop="showDialog = true" />
    </div>
    <device-dialog :show.sync="showDialog" :security="true" :data="photoList" :limit="limit" @getPhoto="getPhoto" />
  </div>
</template>

<script>
import PadBridge from '@/components/PadBridge'
import { mapGetters } from 'vuex'
import CompressImg from '@/components/CompressImg'
import BlobUtil from '@/components/CompressImg/blobutil'
import { getToken } from '@/utils/auth'
import { getIdcardInfoByOcr } from '@/utils/upload'
import { imageViewer } from '@/utils/upload'
import defaultBgImgUrl from '@/assets/image/id_positive@2x.png'
import deviceDialog from '@/components/Device/dialog'

export default {
  name: 'CompCertificateUpload',
  components: {
    deviceDialog,
    PadBridge
  },
  props: {
    value: {
      type: Object,
      default: () => ({})
    },
    maxSize: {
      type: Number,
      default: 0.5
    },
    rootPath: {
      type: String,
      default: 'common/imgs'
    },
    bgImgUrl: {
      type: String,
      default: defaultBgImgUrl
    },
    desc: {
      type: String,
      default: '请上传人像面'
    },
    limit: {
      type: Number,
      default: 1
    },
    certs: {
      type: Array,
      default: () => ([])
    }
  },
  data() {
    return {
      showDialog: false,
      file: null,
      fileRemoteUrl: null,
      state: 'init',
      uploadPercent: '0%',
      actionUrl: `${process.env.VUE_APP_BASIC_API}cuscImage/upload`,
      reqParams: {
        rootPath: this.rootPath
      },
      reqHeaders: {
        'Authorization': ''
      }
    }
  },
  computed: {
    ...mapGetters(['device']),
    photoList() {
      const list = []
      this.certs.forEach(item => {
        if (item.url.url) {
          list.push({
            type: 'photo',
            accessUrl: item.url.url,
            uuid: item.url.id
          })
        }
      })
      return list
    }
  },
  watch: {
    'fileRemoteUrl.id'(v) {
      if (this._fileRemoteUrlInitMount) {
        this._fileRemoteUrlInitMount = false
        return
      }
      this.$emit('input', this.fileRemoteUrl)
    },
    value(v) {
      if (v && v.id !== this.fileRemoteUrl.id) {
        this.updateInternalData()
      }
    }
  },
  created() {
    this._fileRemoteUrlInitMount = true
    this.init()
  },
  methods: {
    /**
    * 获取图片
    * @time 2022-05-11 23:32:36
    */
    getPhoto(data) {
      if (data.length > 0) {
        this.$emit('take-photo-success', data)
        this.state = 'success'
        this.$emit('on-success')
      }
    },

    errorTips(msg) {
      this.$message.error(msg)
    },

    init() {
      this.updateInternalData()
    },
    updateInternalData() {
      if (typeof this.value === 'object' && this.value !== null) {
        const fileRemoteUrl = this.makeFileRemoteUrlTemplate()
        fileRemoteUrl.id = this.value.id || null
        fileRemoteUrl.url = this.value.url || ''
        if (fileRemoteUrl.id === null) {
          this.resetState()
          return
        }
        this.file = null
        this.fileRemoteUrl = fileRemoteUrl
        this.state = 'success'
        this.uploadPercent = '0%'
      } else {
        this.resetState()
      }
    },

    resetState() {
      this.file = null
      this.fileRemoteUrl = this.makeFileRemoteUrlTemplate()
      this.state = 'init'
      this.uploadPercent = '0%'
    },

    // 点击删除
    clickDel() {
      this.$emit('on-del')
      this.resetState()
    },

    makeExceedSizeTips() {
      if (this.maxSize >= 1) {
        return `上传文件大小不能超过${this.maxSize}M`
      }
      return `上传文件大小不能超过${this.maxSize * 1000}K`
    },

    // 上传前
    onBeforeUpload(file) {
      // 检查文件格式
      if (!/jpg|jpeg|png|bmp/i.test(file.type)) {
        this.errorTips('上传文件格式不正确')
        return false
      }
      if (file.size > 60 * 1024 * 1024) {
        this.errorTips(this.makeExceedSizeTips())
        return false
      }
      if (file.size > this.maxSize * 1024 * 1024) {
        return new Promise((resolve, reject) => {
          // 压缩
          CompressImg(file, {
            size: 850,
            quality: 70,
            cb: (dataURL) => {
              const abData = BlobUtil.base64ToArrayBuffer(dataURL)
              if (abData.length > this.maxSize * 1024 * 1024) {
                this.errorTips(this.makeExceedSizeTips())
                reject(false)
              } else {
                // 如果当前有正在上传的请求，取消这些请求
                if (this.state === 'uploading') {
                  this.$refs.uploadRef.abort()
                }
                // 设置token
                this.reqHeaders['Authorization'] = `bearer ${getToken()}`
                this.state = 'uploading'
                // 设置上传文件为压缩后的文件
                const compressedFile = BlobUtil.Blob([abData], { type: 'image/jpeg' })
                resolve(new File([compressedFile], file.name || '压缩后的文件.jpeg'))
              }
            }
          })
        })
      }
      // 如果当前有正在上传的请求，取消这些请求
      if (this.state === 'uploading') {
        this.$refs.uploadRef.abort()
      }
      // 设置token
      this.reqHeaders['Authorization'] = `bearer ${getToken()}`
      this.state = 'uploading'
      return true
    },
    // 上传中
    onProgress(ev, file) {
      if (ev.lengthComputable) {
        this.uploadPercent = `${(ev.loaded / ev.total) * 100}%`
      }
    },
    // 上传成功
    async onSuccess(res, file) {
      this.uploadPercent = '0%'
      try {
        res.data.accessUrl = await imageViewer(res.data.uuid)
      } catch (error) {
        console.error('加密图片加载失败：', error)
      }
      if (res && res.success && res.data && res.data.accessUrl) {
        const fileRemoteUrl = this.makeFileRemoteUrlTemplate()
        fileRemoteUrl.id = res.data.uuid
        fileRemoteUrl.url = res.data.accessUrl
        // 上传成功
        this.state = 'success'
        this.fileRemoteUrl = fileRemoteUrl
        this.file = file
        this.$emit('on-success')
      } else {
        // 上传失败
        this.state = 'error'
        this.fileRemoteUrl = this.makeFileRemoteUrlTemplate()
        this.file = null
        this.$emit('on-error')
      }
    },
    // 上传失败
    onUploadError(e) {
      this.uploadPercent = '0%'
      this.state = 'error'
      this.fileRemoteUrl = this.makeFileRemoteUrlTemplate()
      this.file = null
      this.$emit('on-error')
    },

    // 生成远程数据模板
    makeFileRemoteUrlTemplate() {
      return {
        id: null,
        url: ''
      }
    },

    /**
     * 身份证ocr识别
     */
    async handleIdcardOcr() {
      // 通过ocr读取证件信息
      const respData = await getIdcardInfoByOcr(this.file.raw)
      // 返回读取的证件信息
      this.$emit('on-cert', respData)
    }
  }
}
</script>

<style lang="scss">
.comp-certificate-upload-wrap {
  position: relative;
  width: 140px;
  .device-wrapper {
    position: absolute;
    bottom: 0;
    right: -36px;
  }
}
.comp-certificate-upload {
  width: 140px;
  .el-upload {
    box-sizing: border-box;
    position: relative;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    width: 140px;
    height: 96px;
    border: 1px dashed #DCDFE6;
    border-radius: 8px;
    background: #fff;
    .su-icon {
      width: 86px;
      height: 52px;
      margin: 0 auto 7px;
      > img {
        display: block;
        width: 100%;
        height: 100%;
      }
    }
    .su-text,
    .su-loading-text {
      font-size: 12px;
      line-height: 17px;
      color: #84858A;
      text-align: center;
    }
    .su-img {
      display: block;
      max-width: 100%;
      max-height: 100%;
    }
    .su-loading-bar {
      position: relative;
      width: 100%;
      height: 2px;
      .su-loading-bar-progress {
        position: absolute;
        left: 0;
        top: 0;
        bottom: 0;
        width: 0;
        background: blue;
      }
    }
    .su-success-operate-wrapper {
      position: absolute;
      left: 0;
      right: 0;
      bottom: 0;
      display: flex;
      justify-content: center;
      align-items: center;
      height: 22px;
      border-radius: 0 0 8px 8px;
      background: rgba(0, 0, 0, 0.5);
      transition: opacity .3s ease-out;
      opacity: 0;
      pointer-events: none;
      > .su-operate-btn {
        width: 50%;
        text-align: center;
        color: #fff;
        opacity: 0.7;
        &.zoom {
          position: relative;
          overflow: hidden;
          border-left: 1px solid #fff;
          .el-image {
            position: absolute;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            opacity: 0;
          }
        }
      }
    }
    &:hover {
      .su-success-operate-wrapper {
        pointer-events: auto;
        opacity: 1;
      }
    }
  }
}
</style>
