<template>
  <el-dialog
    :destroy-on-close="true"
    append-to-body
    title="获取人脸信息"
    :visible.sync="visible"
    width="460px"
    @close="handleClose">
    <div
      class="container"
      v-loading="loading">
      <video
        :id="videoID"
        class="video"
        :class="{reverse:isReverse}"
        preload
        autoplay
        loop
        muted></video>

      <!-- 基准识别框 -->
      <div
        class="box"
        :class="{valid:valid}"
        ref="box">
      </div>

      <canvas
        style="opacity:0"
        class="canvas"
        ref="bg"></canvas>
      <img
        class="canvas"
        :id="faceID"
        :style="{opacity:getImgSuccess?1:0}"
        :src="currentImg">
      <!-- 识别标识 -->
      <div
        ref="mask"
        v-for="(item,index) in masks"
        :key="index"
        class="mask"
        :style="[item,{borderColor:valid?'#1fd83e':'#f8e71c'}]">
      </div>
    </div>

    <div
      class="msg"
      v-if="msg">
      <el-alert
        :type="msg.type"
        effect="dark">
        {{ msg.text }}
      </el-alert>
    </div>

    <span slot="footer">
      <el-switch
        style="float:left"
        @change="track"
        v-model="isReverse"
        active-text="翻转图像"
        inactive-text="不翻转图像">
      </el-switch>

      <el-button @click="track">重拍</el-button>
      <el-button
        type="primary"
        @click="trackImg">拍照</el-button>
      <el-button
        v-if="getImgSuccess && success && valid"
        type="primary"
        @click="handleSubmit">提交</el-button>
    </span>
  </el-dialog>
</template>

<script>
import { checkIntersection } from '@/utils'
import { faceidentify11 } from '@/api/face'

export default {
  data () {
    return {
      masks: [],
      currentImg: '',
      loading: false,
      success: false,
      visible: false,
      isReverse: true,
      valid: false,
      getImgSuccess: false,
      trackFinish: false,
      msg: null,
      videoID: 'video' + this._uid,
      faceID: 'face' + this._uid
    }
  },
  inject: ['skipCheck'],
  methods: {
    show () {
      this.visible = true
      this.msg = null
      this.masks = []

      this.$nextTick(() => {
        this.track()
      })
    },
    stopTrack () {
      var video = document.getElementById(this.videoID)
      video.pause()

      if (video.srcObject) {
        let tracks = video.srcObject.getVideoTracks()
        tracks.length > 0 && (tracks.forEach(i => i.stop()))
      }

      this.tracker && this.tracker.removeAllListeners()
      this.tracker = null

      this.trackVideoTask && this.trackVideoTask.stop()
      this.trackImgTask && this.trackImgTask.stop()

      this.trackVideoTask = null
      this.trackImgTask = null
    },
    // 人脸比对API
    faceidentify11 (face) {
      if (this.skipCheck) return face
      this.loading = true

      return faceidentify11({ img1: face.split(',')[1], img2: face.split(',')[1] }).then(res => {
        if (res.errInfo === '成功') {
          return face
        } else {
          this.$message({
            showClose: true,
            message: '人脸模糊，请重新拍照',
            type: 'error'
          })
          return false
        }
      }).catch(() => {
        this.$message({
          showClose: true,
          message: '人脸模糊，请重新拍照',
          type: 'error'
        })
        return false
      }).finally(() => {
        this.loading = false
      })
    },
    handleClose () {
      this.stopTrack()
      this.$nextTick(() => {
        this.visible = false
        this.$emit('close')
      })
    },
    plot (x, y, w, h, color, reverse) {
      console.log(color)
      return {
        width: w + 'px',
        height: h + 'px',
        // left: x + 'px',
        right: x + 'px',
        top: y + 'px',
        borderColor: color || '#ff0'
      }
    },
    trackImg () {
      this.getImgSuccess = true
      this.valid = false
      this.video = document.getElementById(this.videoID)
      this.bg = this.$refs.bg

      let vW = this.video.videoWidth || this.video.width
      let vH = this.video.videoHeight || this.video.height

      // 设置模糊背景图
      this.bg.width = vW
      this.bg.height = vH

      let context = this.bg.getContext('2d')

      if (this.isReverse) {
        // 镜像翻转
        context.translate(this.bg.width, 0)
        context.scale(-1, 1)
        context.drawImage(this.video, 0, 0, vW, vH)
        // 坐标参考还原
        context.setTransform(1, 0, 0, 1, 0, 0)
      } else {
        context.drawImage(this.video, 0, 0, vW, vH)
      }

      this.currentImg = this.bg.toDataURL('image/jpeg', 0.92)

      this.timer && clearTimeout(this.timer)

      setTimeout(() => {
        this.trackImgTask = tracking.track(`#${this.faceID}`, this.tracker)
        this.tracker.on('track', (event) => {
          this.masks = []

          event.data.forEach((rect) => {
            this.masks.push(this.plot(rect.x, rect.y, rect.width, rect.height, 'green', true))

            let maskEl = this.$refs.mask && this.$refs.mask[0]
            let boxEl = this.$refs.box
            if (maskEl && boxEl) {
              let inter = checkIntersection(boxEl, maskEl).inter
              console.log(inter)
              if (inter >= 0.35) {
                this.valid = true
              } else {
                this.valid = false
              }
            }
          })

          if (event.data.length === 0) {
            this.msg = {
              type: 'error',
              text: '人脸识别失败，请点击重新截取。'
            }
          }

          if (event.data.length === 1) {
            if (this.valid) {
              this.success = true
              this.msg = {
                type: 'success',
                text: '人脸识别成功，点击确认按钮提交。'
              }
            } else {
              this.msg = {
                type: 'warning',
                text: '人脸照片太小，请重新拍照'
              }
            }
          }

          if (event.data.length > 1) {
            this.valid = false
            this.msg = {
              type: 'warning',
              text: '人脸识别成功，但人数大于1'
            }
          }

          this.trackFinish = true
          this.stopTrack()
        })
      }, 500)
    },
    track () {
      this.stopTrack()
      this.masks = []
      this.loading = false
      this.success = false
      this.getImgSuccess = false
      this.trackFinish = false
      this.msg = null

      !this.tracker && (this.tracker = new tracking.ObjectTracker('face'))
      this.tracker.setEdgesDensity(0.05)
      this.tracker.setInitialScale(1)
      this.tracker.setStepSize(1.5)

      // 追踪任务
      this.trackVideoTask = tracking.track(`#${this.videoID}`, this.tracker, {
        camera: true,
        vue: this // hack 打开摄像头后，如果visible为false,关闭摄像头。已改tracking源码
      })

      this.tracker.on('track', event => {
        if (this.getImgSuccess) return

        this.timer = setTimeout(() => {
          this.masks = []

          if (event.data.length === 0) {
            this.valid = false
          }

          event.data.forEach((rect) => {
            if (this.trackFinish) return
            this.masks.push(this.plot(rect.x, rect.y, rect.width, rect.height))
            let maskEl = this.$refs.mask && this.$refs.mask[0]
            let boxEl = this.$refs.box
            if (maskEl && boxEl) {
              let inter = checkIntersection(boxEl, maskEl).inter
              if (inter >= 0.35) {
                this.valid = true
              } else {
                this.valid = false
              }
            }
          })
        }, 500)
      })
    },
    async handleSubmit () {
      let validFace = await this.faceidentify11(this.currentImg)

      if (validFace) {
        this.$emit('change', validFace)

        this.$message.success('人脸校验成功。')
        this.visible = false
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.msg{
  padding: 10px
}
.container{
    width: 100%; padding-bottom: 90%; background: rgba(0, 0, 0, 0.384); position: relative; overflow: hidden;
}
.reverse{
  transform: rotateY(180deg)
}
.canvas,
.video{
    position: absolute;  top: 0;  left: 0;  object-fit: cover; width: 100%; height: 100%;
}
.mask {
  position: absolute; border:5px dashed #f8e71c;
}
.box {
  position: absolute;  top: 50%;  left: 50%;  width: 60%;  overflow: hidden;  background: rgba(0, 0, 0, .3);  transform: translate(-50%, -50%);
  &:before {
    display: block; padding-bottom: 100%;  content: '';
  }
  &:after {
    position: absolute; top: 0;left: 0; width: 100%;  height: 100%;  content: '';  background: linear-gradient(to left, #f8e71c, #f8e71c) left top no-repeat, linear-gradient(to bottom, #f8e71c, #f8e71c) left top no-repeat, linear-gradient(to left, #f8e71c, #f8e71c) right top no-repeat, linear-gradient(to bottom, #f8e71c, #f8e71c) right top no-repeat, linear-gradient(to left, #f8e71c, #f8e71c) left bottom no-repeat, linear-gradient(to bottom, #f8e71c, #f8e71c) left bottom no-repeat, linear-gradient(to left, #f8e71c, #f8e71c) right bottom no-repeat, linear-gradient(to left, #f8e71c, #f8e71c) right bottom no-repeat;  background-size: 2px 20%, 20% 2px, 2px 20%, 20% 2px;
  }
}
.valid{
  &:after {
    position: absolute; top: 0;left: 0; width: 100%;  height: 100%;  content: '';  background: linear-gradient(to left, #1fd83e, #1fd83e) left top no-repeat, linear-gradient(to bottom, #1fd83e, #1fd83e) left top no-repeat, linear-gradient(to left, #1fd83e, #1fd83e) right top no-repeat, linear-gradient(to bottom, #1fd83e, #1fd83e) right top no-repeat, linear-gradient(to left, #1fd83e, #1fd83e) left bottom no-repeat, linear-gradient(to bottom, #1fd83e, #1fd83e) left bottom no-repeat, linear-gradient(to left, #1fd83e, #1fd83e) right bottom no-repeat, linear-gradient(to left, #1fd83e, #1fd83e) right bottom no-repeat;  background-size: 2px 20%, 20% 2px, 2px 20%, 20% 2px;
  }
}
</style>
