<!--
  * @File 基于Antd的显示、下载组件
  * @FileDescription 用于上传的数据显示使用
  * String type: 使用类型 图片、文件、视频或者其他 img||file||video||other 默认值: img
  * fileShowType: 文件列表的显示类型 none: 不显示, name: 直接显示名称
  * String(required) src: 组件显示]或下载的地址
  * (String, Object) styleFile: 自定义样式
  * String tokenUser: 用户token
  * Object objApiPermission: 权限申请api 如果不传该值 则无法申请权限文件访问
  *                               String(required) url（必填）: 'https://api.ii-park.com/files/permissions'
  *                               String methods: 请求列表 默认值：'POST'
  *                               Object params: body参数
  *                               Object headers: 头部参数
  * @click 点击事件
  * @Author 佟春晓
  * @Date 2021-10-29
  * @Update 佟春晓(2022-03-07)
-->
<template>
  <!-- 图片类型显示 -->
  <img
    v-if="type === 'img' && strFilePermissionStatus == 'AUTHORIZED'"
    :style=" styleFile || 'width: 100%'"
    :title='strFileName'
    :src='showUrl'
    @load='load'
    :alt='strFileName'
    @click="handleClick()"
  />
  <!-- 视频类型显示 -->
  <video
    v-else-if="type === 'video' && strFilePermissionStatus == 'AUTHORIZED'"
    :style=" styleFile || 'width: 100%'"
    :title='strFileName'
    :src="showUrl"
    :alt='strFileName'
    controls
    @click="handleClick()"
  />
  <!-- 文件类型显示 -->
  <span v-else-if="type === 'file'" style='cursor: pointer;' :style="styleFile" @click="handleClick('download')"><slot :fileName="strFileName">{{ strFileName }}</slot></span>
  <!-- 其他文件类型显示 -->
  <span v-else-if="type === 'other'" style='cursor: pointer;' :style="styleFile" @click="handleClick('download')"><slot :fileName="strFileName">{{ strFileName }}</slot></span>
  <!-- 视图类型无权限提示 -->
  <div class="background-box" v-else-if="['img','video'].includes(type) && strFilePermissionStatus !== 'AUTHORIZED'" :style="styleFile" @click="handleClick()">
    <div class="background-message" v-if='tokenUser'>
      <span class="background-text">
        {{ strFilePermissionStatus == 'NONE' ? '您尚未拥有该文件的权限' : strFilePermissionStatus == 'REJECT' ? '申请已驳回，请重新申请' : '权限正在申请中...'}}
      </span>
      <a-button type='primary' v-if="objApiPermission && ['NONE', 'REJECT'].includes(strFilePermissionStatus)" class="background-box-btn" @click="handleGetPermission">申请访问</a-button>
    </div>
    <div class="background-message" v-else>
      <span class="background-text">
        该文件需要登录后访问
      </span>
    </div>
  </div>
</template>
<script>
export default {
  components: {},
  name: 'ShowFile',
  props: {
    /* type: 使用类型 图片、文件、视频或者其他 img||file||video||other */
    type: {
      type: String,
      default: 'img',
      validator: (value) => ['img', 'file', 'video', 'other'].includes(value)
    },
    /* fileShowType: 文件列表的显示类型 none: 不显示, name: 直接显示名称 */
    fileShowType: {
      type: String,
      default: 'none',
      validator: (value) => ['none', 'name'].includes(value)
    },
    /* src: 组件显示地址 */
    src: {
      type: String,
      required: true
    },
    /* styleFile: 自定义样式 */
    styleFile: {
      type: [String, Object],
      default: null
    },
    /* tokenUser: 用户token */
    tokenUser: {
      type: String,
      default: ''
    },
    /* objApiPermission: 权限申请api url(String)（必填）: 'https://api.ii-park.com/files/permissions' methods(String): 默认：'POST' params(Object) headers(Object) */
    objApiPermission: {
      type: Object,
      default: () => null
    }
  },
  data () {
    return {
      showUrl: null, // 文件缓存地址
      strFileName: '', // 文件名称
      strFilePermissionStatus: 'AUTHORIZED' // 当前文件权限类型 "NONE" 无 "CHECKING" 申请中 "REJECT" 请求驳回 "AUTHORIZED" 拥有权限
    }
  },
  mounted () {
    // 默认显示时获取图片
    if (['img', 'video'].includes(this.type)) this.getFileUrl()
  },
  watch: {
    // 路由变更时 获取图片
    src (value) {
      if (['img', 'video'].includes(this.type) && this.src) {
        this.getFileUrl()
      }
    }
  },
  methods: {
    // 图片加载完成 销毁缓存
    load () {
      const _URL = window.URL || window.webkitURL
      _URL.revokeObjectURL(this.showUrl)
    },
    // 点击事件
    handleClick (type) {
      // 判断是否
      if (this.$listeners['click']) {
        this.$emit('click')
        return
      }
      if (['file', 'other'].includes(this.type)) this.getFileUrl(type)
    },
    // 申请权限
    handleGetPermission () {
      // 无用户信息和请求信息 返回
      if (!this.tokenUser) return
      if (!this.objApiPermission) return
      // 设置头部信息
      const headers = {
        'authorization': 'Bearer ' + this.tokenUser,
        'content-type': 'application/json'
      }
      // 设置参数信息
      const body = JSON.stringify(this.objApiPermission.params)
      // 根据请求信息发起请求
      fetch(this.objApiPermission.url, {
        method: this.objApiPermission.methods || 'POST',
        headers: { ...headers, ...this.objApiPermission.headers },
        body: body
      }).then(res => {
        res.text().then((data) => {
          try {
            if (data && JSON.parse(data) && JSON.parse(data).data) {
              // 设置当前文件状态
              const status = JSON.parse(data).data.status
              this.strFilePermissionStatus = status
              // 如果文件状态直接通过 则获取文件
              if (status === 'AUTHORIZED') {
                this.getFileUrl()
              }
            } else {
              // reject(new Error('获取上传信息失败'))
            }
          } catch (e) {
            // reject(e)
          }
        })
      })
    },
    // 获取文件
    getFileUrl (type) {
      if (!this.src) return
      const _this = this
      const headers = {}
      let strFileName = ''
      if (_this.tokenUser) headers['authorization'] = 'Bearer ' + _this.tokenUser
      // 根据链接地址 请求文件
      fetch(_this.src, {
        method: 'GET',
        headers: headers,
        responseType: 'blob'
      }).then(res => {
        // 如果状态:200 返回文件
        if (res.status === 200) {
          // 获取文件名
          strFileName = res.headers.get('Content-Disposition') ? res.headers.get('Content-Disposition').split('filename=')[1] : ''
          const arrStrFileName = strFileName.split('.')
          _this.strFileName = strFileName ? `${decodeURI(arrStrFileName[0])}.${arrStrFileName[1]}`.replace(/"/g, '') : ''
          // 获取文件数据流
          res.blob().then((blob) => {
            // 生成缓存文件
            const _URL = window.URL || window.webkitURL
            const src = _URL.createObjectURL(blob)
            // 视图文件显示缓存文件
            if (['img', 'video'].includes(_this.type)) {
              _this.showUrl = src
            } else {
              if (type === 'download') {
                // 文本文件直接进行下载
                const domA = window.document.createElement('a')
                domA.href = src
                domA.download = _this.strFileName
                domA.click()
                domA.remove()
                window.URL.revokeObjectURL(src)
              }
            }
          })
        // 如果状态:412 则获取文件状态
        } else if (res.status === 412) {
          res.text().then((data) => {
            if (data && JSON.parse(data) && JSON.parse(data).data) {
              _this.strFilePermissionStatus = JSON.parse(data).data.permission_status
              // 文件根据不同状态进行提示
              if (['file', 'other'].includes(_this.type)) {
                if (_this.strFilePermissionStatus === 'NONE') {
                  _this.$confirm({
                    content: '您尚未拥有该文件的权限，如需下载请申请',
                    okText: null,
                    onOk () {
                      _this.handleGetPermission()
                    }
                  })
                } else if (_this.strFilePermissionStatus === 'REJECT') {
                  _this.$confirm({
                    content: '申请已驳回，如需要请重新申请',
                    okText: null,
                    onOk () {
                      _this.handleGetPermission()
                    }
                  })
                } else {
                  _this.$info({
                    title: '提示',
                    content: '权限正在申请中，请耐心等待...'
                  })
                }
              }
            }
          })
        } else {
          return Promise.reject(new Error(res.status))
        }
      }).catch(err => {
        if (err.message === 401) {
          this.$notification.warning('当前文件需要登录，当前用户状态尚未登录或登录已过期。')
        }
      })
    }
  }
}
</script>
<style scoped>
.background-box {
  --color: #ddd;
  background-size: 15px 15px;
  width: 100%;
  height: 100%;
  text-align: center;
  align-items: center;
  font-size: 16px;
  position: relative;
  background-image:
    linear-gradient( 45deg, var(--color) var(25%), transparent var(25%), transparent var(75%), var(--color) var(75%) ),
    linear-gradient( -45deg, var(--color) var(25%), transparent var(25%), transparent var(75%), var(--color) var(75%) );
}
.background-message {
  background: #FFF;
  position: absolute;
  width: 70%;
  padding: 20px;
  box-shadow: 0px 0px 12px 3px rgba(0,0,0,0.3);
  top:50%;
  left:50%;
  min-width: 140px;
  border-radius: 5px;
  -webkit-transform: translate(-50%,-50%);
  -moz-transform: translate(-50%,-50%);
  transform:translate(-50%,-50%);
}
.background-text{
  font-size: 14px;
}
.background-box-btn {
  margin-top: 20px;
}
</style>
