<template>
  <div class="file-label" @click="handleUpload">
    <slot>
      <div class="tips-box">
        <!-- <m-button type="success" :icon="
          hashProgress > 0 && uploadProgress < 100
            ? 'el-icon-loading'
            : 'el-icon-upload'
        ">
          上传文件
        </m-button> -->
        <el-button type="primary">上传文件</el-button>
        <div class="progress" :style="{ width: uploadProgress + '%' }"></div>
      </div>
    </slot>
    <input type="file" name="file" id="fileid" ref="inputFile" class="file-input" @change="handleInputFileChange"
           :accept="accept" />
  </div>
</template>
<style lang="scss" scoped>
  .file-label {
    display: inline-block;
    color: #FFF;
    background-color: #4178D5;
    border-color: #4178D5;
    padding: 0 15px;
    border-radius: 4px;
    cursor: pointer;
  }

  .file-input {
    display: none;
  }

  .tips-box {
    position: relative;
    display: inline-block;
  }

  .progress {
    position: absolute;
    left: 0;
    bottom: 0;
    width: 0%;
    height: 3px;
    background-color: #409eff;
  }

</style>
<script>
  import axios from 'axios'
  import { useStore } from 'vuex'
  import BMF from 'browser-md5-file'
  import MButton from '../components/m-button/index.vue'
  export default {
    name: 'MChunkUpload',
    components: {
      'm-button': MButton
    },
    data() {
      return {
        file: {},
        store: useStore(),
        hashProgress: 0,
        uploadProgress: 0
      }
    },
    props: {
      filemaxsize: {
        type: Number,
        default: null
      },
      chunkSize: {
        type: Number,
        default: 1
      },
      accept: {
        type: String,
        default: '*'
      },
      requestLimit: {
        type: Number,
        default: 3
      },
      customField: {
        type: Array,
        default: function () {
          return []
        }
      }
    },
    methods: {
      // 点击按钮，模拟点击input[type="file"]
      handleUpload() {
        this.$refs.inputFile.click()
      },
      // 选定文件，触发上传
      handleInputFileChange(event) {
        const file = event.target.files[0]
        console.log(event.target.files[0])
        var index = file.name.lastIndexOf('.')
        // 获取后缀
        var ext = file.name.substr(index + 1)
        // 输出结果
        if (this.accept.indexOf(ext) === -1 && this.accept !== '*') {
          this.$message.error('文件上传的格式不对,请重新上传')
          return false
        }
        // 限制文件大小上传
        if (this.filemaxsize) {
          if ((file.size / 1024 / 1024) > this.filemaxsize) {
            this.$message.error('文件上传大小不能大于' + this.filemaxsize + 'M！')
            return false
          }
        }
        const bmf = new BMF()
        bmf.md5(
          file,
          (err, md5) => {
            if (err !== null) console.error(err)
            // 上传文件
            this.chunkFileUpload(file, md5)
          },
          progress => {
            this.hashProgress = Math.ceil(progress * 100)
            this.uploadProgress = 0
            this.$emit('hashProgress', this.hashProgress)
          }
        )
        // 清空，防止文件不能重复上传
        event.target.value = ''
      },
      // 服务器检测文件是否已上传及上传过哪些分片
      async chunkFileCheck(md5, chunks, file) {
        console.log(md5, chunks, file)
        const formData1 = new FormData()
        // blob组装file对象
        formData1.append('language_id', this.store.state.user.language.id)
        formData1.append('chunks', chunks)
        formData1.append('hash', md5)
        return this.http().post('/driver/check_chunk_file', formData1).then(r => {
          return []
          // const result = r.data
          // if (result.errno !== 0) {
          //   console.error(result.errmsg)
          //   return []
          // }
          // if (r.status == 200) {
          //   this.$emit('successed', r.data)
          //   this.uploadProgress = 100
          //   this.$emit('uploadProgress', 100)
          //   return [...new Array(chunks)].map((it, k) => k)
          // }
          // return r.data.uploaded
        })
      },
      // 计算文件分片数
      async chunkFileUpload(file, hash) {
        console.log(file, hash)
        let uploadedProgress = 0
        const chunkSize = this.chunkSize * 1024 * 1024
        const fileSize = file.size

        // 计算文件分片总数
        const chunks = Math.ceil(fileSize / chunkSize)

        // 分片组大小
        const groupSize = this.requestLimit

        // 分片索引
        let chunksArray = [...new Array(chunks)].map((it, k) => k)

        // 检查文件是否上传过
        const uploaded = await this.chunkFileCheck(hash, chunks, file)
        chunksArray = chunksArray.filter((it, k) => uploaded.includes(it) === false)
        if (chunksArray.length === 0) {
          return false
        }
        // 分片索引分组，解决浏览器同域名最大并发请求数问题
        const chunksGroups = [...new Array(Math.ceil(chunksArray.length / groupSize))].map((it, k) => chunksArray
          .slice(k * groupSize, k * groupSize + groupSize))
        for (let i = 0; i < chunksGroups.length; i++) {
          let computed = 0
          // 利用promise控制并发请求连接数
          await new Promise((resolve, reject) => {
            const group = chunksGroups[i]
            for (let k = 0; k < group.length; k++) {
              const it = group[k]
              // 分片文件
              const sPos = chunkSize * it
              const chunk = file.slice(sPos, sPos + chunkSize)
              const formData = new FormData()
              // blob组装file对象
              formData.append('file', new File([chunk], file.name, {
                type: file.type
              }), file.name)
              formData.append('type', 'drivers')
              formData.append('language_id', this.store.state.user.language.id)
              formData.append('file_name', file.name)
              formData.append('chunks', chunks)
              formData.append('chunk', it)
              formData.append('hash', hash)
              // 自定义字段
              if (this.customField.length > 0) {
                this.customField.forEach(field => {
                  formData.append(Object.keys(field)[0], Object.values(field)[0])
                })
              }
              this.http().post('/driver/upload_chunk_file', formData).then(r => {
                computed += 1
                if (computed === group.length) {
                  resolve('success')
                }
                // 计算上传进度
                this.uploadProgress = Math.ceil((uploadedProgress += 1) / chunks * 100)
                this.$emit('uploadProgress', this.uploadProgress)
                // 上传完成
                if (r.data.status == 200) {
                  this.$emit('successed', r.data)
                  this.uploadProgress = 100
                  this.$emit('uploadProgress', 100)
                  return false
                }
              }).catch(e => {
                reject(e)
              })
            }
          })
        }
      },
      // 请求配置项
      http() {
        const baseURL = process.env.VUE_APP_API_BASEURL
        // const apiVersion = process.env.VUE_APP_API_VERSION.replace(/\./g, '_')
        return axios.create({
          baseURL: baseURL + 'admin/v1/',
          timeout: 0,
          withCredentials: true
        })
      }
    }
  }

</script>
