<template>
  <div class="comp-file-info">
    <el-form ref="formRef" :model="form" :rules="formRules" size="small" label-position="top">
      <el-row>
        <el-col :span="24">
          <el-form-item :label="labelName" prop="fileList">
            <el-upload
              :limit="limit"
              :file-list="form.fileList"
              :before-upload="onBeforeUpload"
              :before-remove="onUploadBeforeRemove"
              :on-success="onUploadSuccess"
              :on-exceed="onUploadExceed"
              :on-preview="onUploadPreview"
              :accept="accept"
              :action="uploadParams.action"
              :headers="uploadParams.headers"
              :data="uploadParams.data"
              :multiple="limit > 1"
              :class="{'cfi-disable-upload': !enableUploadBtn}"
              class="file-uploader tip-nowrap"
            >
              <template v-if="enableUploadBtn">
                <el-button key="1" :icon="btnIcon" size="small" type="primary">{{ btnName }}</el-button>
              </template>
              <template v-else>
                <el-button key="2" :icon="btnIcon" disabled size="small" type="primary">{{ btnName }}</el-button>
              </template>
              <div slot="tip" class="el-upload__tip">{{ desc }}</div>
            </el-upload>
            <template #label>
              <div class="file-uploader-label">
                <span>{{ labelName }}</span>
              </div>
            </template>
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
    <comp-confirm
      :show.sync="showErrorConfirm"
      :desc="errorConfirmDesc"
      :show-cancel-btn="true"
      @on-sure="sureDelFile"
    />
    <comp-confirm
      :show.sync="showErrorTips"
      :desc="errorMsg"
    />
    <comp-file-preview :show.sync="showFilePreview" :url-list="previewFileList"/>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'
import { getToken } from '@/utils/auth'
import CompConfirm from '@/components/CompConfirm'
import CompFilePreview from '@/components/CompFilePreview'

export default {
  name: 'CompFileInfo',
  components: {
    CompConfirm,
    CompFilePreview
  },
  props: {
    data: {
      type: Object,
      default: () => ({})
    },
    btnIcon: {
      type: String,
      default: 'el-icon-upload2'
    },
    btnName: {
      type: String,
      default: '上传'
    },
    labelName: {
      type: String,
      default: ''
    },
    limit: {
      type: Number,
      default: 1
    },
    accept: {
      type: String,
      default: '.rar,.zip,.doc,.docx,.pdf,.jpg'
    },
    size: {
      type: Number,
      default: 20
    },
    desc: {
      type: String,
      default: ''
    },
    randomNum: {
      type: String,
      default: ''
    },
    uploadParams: {
      type: Object,
      default: () => ({
        data: {
          rootPath: '',
          path: ''
        },
        headers: {
          'Authorization': `bearer ${getToken()}`
        },
        action: `${process.env.VUE_APP_BASIC_API}file/upload`
      })
    },
    // 验证方式
    livenessType: {
      type: String,
      default: ''
    }
  },
  data() {
    const checkFileList = (rule, value, callback) => {
      if (!Array.isArray(value) || value.length === 0) {
        callback(new Error(`请选择${this.labelName}`))
      } else {
        callback()
      }
    }
    return {
      form: {
        fileList: []
      },
      formRules: {
        'fileList': [
          { required: true, validator: checkFileList, trigger: 'change' }
        ]
      },
      showDeviceVideo: false,
      showErrorConfirm: false,
      errorConfirmDesc: '',
      showFilePreview: false,
      previewFileList: [],
      showErrorTips: false,
      errorMsg: ''
    }
  },
  computed: {
    ...mapGetters(['device']),
    enableUploadBtn() {
      return this.form.fileList.length < this.limit
    }
  },
  watch: {
    data() {
      this.updateInternalData()
    },
    'form.fileList'() {
      if (this._fileListInitMount) {
        this._fileListInitMount = false
        return
      }
      this.validateFileList()
    }
  },
  created() {
    this.init()
  },
  methods: {
    errorTips(errMsg) {
      this.showErrorConfirm = true
      this.errorConfirmDesc = errMsg
    },
    errorTips2(errorMsg) {
      this.showErrorTips = true
      this.errorMsg = errorMsg
    },

    init() {
      this._fileListInitMount = true
      this.updateInternalData()
    },
    updateInternalData() {
      if (typeof this.data === 'object' && this.data !== null) {
        this.form.fileList = this.normalizeFileList(Array.isArray(this.data.fileList) ? [...this.data.fileList] : [])
      } else {
        this.form.fileList = []
      }
    },

    sureDelFile() {
      const delFile = this.form.fileList.filter(file => file.uid === this._curDelFile.uid)[0]
      if (delFile) {
        this.form.fileList.splice(this.form.fileList.indexOf(delFile), 1)
      }
    },

    makeAcceptReg() {
      const arr = this.accept.split(',').filter(item => item !== '').map(item => item.substring(1))
      return new RegExp(arr.join('|'), 'i')
    },

    onUploadExceed() {
      this.errorTips2(`上传文件数不能超过${this.limit}`)
    },
    onBeforeUpload(file) {
      const acceptReg = this.makeAcceptReg()
      if (!acceptReg.test(file.type)) {
        this.errorTips2('上传文件格式不正确')
        this._autoRemove = true
        return false
      }
      if (file.size > this.size * 1024 * 1024) {
        this.errorTips2(`文件大小不能超过${this.size}M`)
        this._autoRemove = true
        return false
      }
      return true
    },
    onUploadBeforeRemove(file, fileList) {
      if (this._autoRemove) {
        this._autoRemove = false
        return true
      }
      this.errorTips('确认删除当前文件吗？')
      this._curDelFile = file
      return false
    },
    onUploadSuccess(response, file, fileList) {
      if (response && response.code === 200) {
        if (response.data) {
          this.form.fileList = this.normalizeFileList(fileList)
        }
      }
    },

    onUploadPreview(file) {
      this.showFilePreview = true
      this.previewFileList = [{
        type: this.getFileTypeFromFileName(file.name),
        url: file.url
      }]
    },

    getFileTypeFromFileName(name) {
      const suffixIndex = name.indexOf('.')
      if (suffixIndex === -1) {
        return 'image'
      }
      const suffix = name.substring(suffixIndex + 1)
      if (suffix === 'mp4') {
        return 'video'
      }
      // todo 待续
      return 'image'
    },

    normalizeFileList(fileList = []) {
      return fileList.map(file => {
        return {
          uid: file.uid,
          name: file.name,
          uuid: file.uuid ? file.uuid : file.response.data.uuid,
          url: file.url ? file.url : file.response.data.accessUrl
        }
      })
    },

    validateFileList() {
      this.$refs.formRef.validateField('fileList')
    },

    // 校验
    async validate() {
      try {
        await this.$refs.formRef.validate()
        return true
      } catch (e) {
        let temp = {
          anchor: () => {
            this.$refs.formRef.fields.filter(item => item.validateState === 'error')[0].$el.scrollIntoView(true)
            temp = null
          }
        }
        throw temp
      }
    },
    // 获取数据
    getFormData() {
      return JSON.parse(JSON.stringify(this.form))
    },
    // 获取待缓存数据
    getPendingCacheData() {
      return this.getFormData()
    },

    /**
     * 追加一条文件数据
     * @param file 文件数据
     */
    appendFile(file) {
      // 开始在页面上渲染已经上传的文件样式
      this.form.fileList = this.normalizeFileList([file])
    }
  }
}
</script>

<style lang="scss">
.comp-file-info {
  .cfi-disable-upload {
    .el-upload {
      pointer-events: none;
    }
  }
  .file-uploader-label {
    display: inline-block;
    position: relative;
    .icon-device-video {
      position: absolute;
      left: 100px;
      top: 4px;
    }
  }
}
</style>
