<template>
  <div style="position: relative">
    <div v-if="type === '2'" class="verify-img-out" :style="{ height: parseInt(setSize.imgHeight) + vSpace + 'px' }">
      <div class="verify-img-panel" :style="{ width: setSize.imgWidth, height: setSize.imgHeight }">
        <img :src="'data:image/png;base64,' + backImgBase" alt="" style="width: 100%; height: 100%; display: block" />
        <div v-show="showRefresh" class="verify-refresh" @click="refresh">
          <i class="iconfont icon-refresh"></i>
        </div>
        <transition name="tips">
          <span v-if="tipWords" class="verify-tips" :class="passFlag ? 'suc-bg' : 'err-bg'">{{ tipWords }}</span>
        </transition>
      </div>
    </div>
    <!-- 公共部分 -->
    <div
      class="verify-bar-area"
      :style="{ width: setSize.imgWidth, height: barSize.height, 'line-height': barSize.height }"
    >
      <span class="verify-msg" v-text="text"></span>
      <div
        class="verify-left-bar"
        :style="{
          width: leftBarWidth !== undefined ? leftBarWidth : barSize.height,
          height: barSize.height,
          'border-color': leftBarBorderColor,
          transaction: transitionWidth
        }"
      >
        <span class="verify-msg" v-text="finishText"></span>
        <div
          class="verify-move-block"
          :style="{
            width: barSize.height,
            height: barSize.height,
            'background-color': moveBlockBackgroundColor,
            left: moveBlockLeft,
            transition: transitionLeft
          }"
          @touchstart="start"
          @mousedown="start"
        >
          <i :class="['verify-icon iconfont', iconClass]" :style="{ color: iconColor }"></i>
          <div
            v-if="type === '2'"
            class="verify-sub-block"
            :style="{
              width: Math.floor((parseInt(setSize.imgWidth) * 47) / 310) + 'px',
              height: setSize.imgHeight,
              top: '-' + (parseInt(setSize.imgHeight) + vSpace) + 'px',
              'background-size': setSize.imgWidth + ' ' + setSize.imgHeight
            }"
          >
            <img
              :src="'data:image/png;base64,' + blockBackImgBase"
              alt=""
              style="width: 100%; height: 100%; display: block; -webkit-user-drag: none"
            />
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script lang="js">
/**
 * VerifySlide
 * @description 滑块
 * */
import { computed, onMounted, reactive, ref, watch, nextTick, toRefs, getCurrentInstance } from 'vue';
import { aesEncrypt } from './../utils/ase';
import { resetSize } from './../utils/util';
import { reqGet, reqCheck } from './../api/index';
//  "captchaType":"blockPuzzle",
export default {
  name: 'VerifySlide',
  props: {
    captchaType: {
      type: String,
      default: 'blockPuzzle'
    },
		reGet: {
			type: Number,
      default: 1
		},
    type: {
      type: String,
      default: '2'
    },
    // 弹出式pop，固定fixed
    mode: {
      type: String,
      default: 'pop'
    },
    vSpace: {
      type: Number,
      default: 5
    },
    explain: {
      type: String,
      default: '向右滑动完成验证'
    },
    imgSize: {
      type: Object,
      default() {
        return {
          width: '310px',
          height: '155px'
        };
      }
    },
    blockSize: {
      type: Object,
      default() {
        return {
          width: '50px',
          height: '50px'
        };
      }
    },
    barSize: {
      type: Object,
      default() {
        return {
          width: '310px',
          height: '40px'
        };
      }
    }
  },
  setup(props) {
    const { mode, captchaType, type, explain, blockSize, reGet } = toRefs(props);

    const { proxy } = getCurrentInstance();
    const secretKey = ref(''); // 后端返回的ase加密秘钥
    const passFlag = ref(''); // 是否通过的标识
    const backImgBase = ref(''); // 验证码背景图片
    const blockBackImgBase = ref(''); // 验证滑块的背景图片
    const backToken = ref(''); // 后端返回的唯一token值
    const startMoveTime = ref(''); // 移动开始的时间
    const endMoveTime = ref(''); // 移动结束的时间
    const tipsBackColor = ref(''); // 提示词的背景颜色
    const tipWords = ref('');
    const text = ref('');
    const finishText = ref('');
    const setSize = reactive({
      imgHeight: 0,
      imgWidth: 0,
      barHeight: 0,
      barWidth: 0
    });
    const top = ref(0);
    const left = ref(0);
    const moveBlockLeft = ref(undefined);
    const leftBarWidth = ref(undefined);
    // 移动中样式
    const moveBlockBackgroundColor = ref(undefined);
    const leftBarBorderColor = ref('#ddd');
    const iconColor = ref(undefined);
    const iconClass = ref('icon-right');
    const status = ref(false); // 鼠标状态
    const isEnd = ref(false); // 是够验证完成
    const showRefresh = ref(true);
    const transitionLeft = ref('');
    const transitionWidth = ref('');
    const startLeft = ref(0);

    const barArea = computed(() => {
      return proxy.$el.querySelector('.verify-bar-area');
    });
    function init() {
      text.value = explain.value;
      getPicture();
      nextTick(() => {
				const { imgHeight, imgWidth, barHeight, barWidth } = resetSize(proxy);
        setSize.imgHeight = imgHeight;
        setSize.imgWidth = imgWidth;
        setSize.barHeight = barHeight;
        setSize.barWidth = barWidth;
        proxy.$emit('ready', proxy);
      });
      window.removeEventListener('touchmove', e => {
        move(e);
      });
      window.removeEventListener('mousemove', e => {
        move(e);
      });
      // 鼠标松开
      window.removeEventListener('touchend', () => {
        end();
      });
      window.removeEventListener('mouseup', () => {
        end();
      });

      window.addEventListener('touchmove', e => {
        move(e);
      });
      window.addEventListener('mousemove', e => {
        move(e);
      });

      // 鼠标松开
      window.addEventListener('touchend', () => {
        end();
      });
      window.addEventListener('mouseup', () => {
        end();
      });
    }

		const refresh = () => {
      showRefresh.value = true;
      finishText.value = '';
      transitionLeft.value = 'left .3s';
      moveBlockLeft.value = 0;
      leftBarWidth.value = undefined;
      transitionWidth.value = 'width .3s';
      leftBarBorderColor.value = '#ddd';
      moveBlockBackgroundColor.value = '#fff';
      iconColor.value = '#000';
      iconClass.value = 'icon-right';
      isEnd.value = false;
      getPicture();
      setTimeout(() => {
        transitionWidth.value = '';
        transitionLeft.value = '';
        text.value = explain.value;
      }, 300);
    };

		watch(reGet, () => {
			refresh()
			getPicture()
		});
    watch(type, () => {
      init();
    });
    onMounted(() => {
      // 禁止拖拽
      init();
      proxy.$el.onselectstart = () => {
        return false;
      };
    });
    // 鼠标按下
    function start(e) {
      let x = null;
      if (!e.touches) {
        // 兼容PC端
        x = e.clientX;
      } else {
        // 兼容移动端
        x = e.touches[0].pageX;
      }
      startLeft.value = Math.floor(x - barArea.value.getBoundingClientRect().left);
      startMoveTime.value = Number(new Date()); // 开始滑动的时间
      if (isEnd.value === false) {
        text.value = '';
        moveBlockBackgroundColor.value = '#337ab7';
        leftBarBorderColor.value = '#337AB7';
        iconColor.value = '#fff';
        e.stopPropagation();
        status.value = true;
      }
    }
    // 鼠标移动
    function move(e) {
      if (status.value && isEnd.value === false) {
        let x = null;
        if (!e.touches) {
          // 兼容PC端
          x = e.clientX;
        } else {
          // 兼容移动端
          x = e.touches[0].pageX;
        }
        const bar_area_left = barArea.value.getBoundingClientRect().left;
        let move_block_left = x - bar_area_left; // 小方块相对于父元素的left值
        if (move_block_left >= barArea.value.offsetWidth - parseInt(parseInt(blockSize.value.width, 10) / 2, 10) - 2) {
          move_block_left = barArea.value.offsetWidth - parseInt(parseInt(blockSize.value.width, 10) / 2, 10) - 2;
        }
        if (move_block_left <= 0) {
          move_block_left = parseInt(parseInt(blockSize.value.width, 10) / 2, 10);
        }
        // 拖动后小方块的left值
        moveBlockLeft.value = `${move_block_left - startLeft.value}px`;
        leftBarWidth.value = `${move_block_left - startLeft.value}px`;
      }
    }

    // 鼠标松开
    function end() {
      endMoveTime.value = Number(new Date());
      // 判断是否重合
      if (status.value && isEnd.value === false) {
        let moveLeftDistance = parseInt((moveBlockLeft.value || '').replace('px', ''), 10);
        moveLeftDistance = (moveLeftDistance * 310) / parseInt(setSize.imgWidth, 10);
        const data = {
          captchaType: captchaType.value,
          pointJson: secretKey.value
            ? aesEncrypt(JSON.stringify({ x: moveLeftDistance, y: 5.0 }), secretKey.value)
            : JSON.stringify({ x: moveLeftDistance, y: 5.0 }),
          token: backToken.value
        };
        reqCheck(data).then(res => {
          if (res.status === true) {
            moveBlockBackgroundColor.value = '#5cb85c';
            leftBarBorderColor.value = '#5cb85c';
            iconColor.value = '#fff';
            iconClass.value = 'icon-check';
            showRefresh.value = false;
            isEnd.value = true;
            if (mode.value === 'pop') {
              setTimeout(() => {
                proxy.$parent.clickShow = false;
                refresh();
              }, 1500);
            }
            passFlag.value = true;
            tipWords.value = `${((endMoveTime.value - startMoveTime.value) / 1000).toFixed(2)}s验证成功`;
            const captchaVerification = secretKey.value
              ? aesEncrypt(`${backToken.value}---${JSON.stringify({ x: moveLeftDistance, y: 5.0 })}`, secretKey.value)
              : `${backToken.value}---${JSON.stringify({ x: moveLeftDistance, y: 5.0 })}`;
            setTimeout(() => {
              tipWords.value = '';
              proxy.$emit('success', { captchaVerification });
            }, 1000);
          } else {
            moveBlockBackgroundColor.value = '#d9534f';
            leftBarBorderColor.value = '#d9534f';
            iconColor.value = '#fff';
            iconClass.value = 'icon-close';
            passFlag.value = false;
            setTimeout(() => {
              refresh();
            }, 1000);
            proxy.$emit('error', proxy);
            tipWords.value = '验证失败';
            setTimeout(() => {
              tipWords.value = '';
            }, 1000);
          }
        });
        status.value = false;
      }
    }

    // 请求背景图片和验证图片
    function getPicture() {
      const data = {
        captchaType: captchaType.value
      };
      reqGet(data).then(res => {
        if (res.status === true) {
          backImgBase.value = res.data.originalImageBase64;
          blockBackImgBase.value = res.data.jigsawImageBase64;
          backToken.value = res.data.token;
          secretKey.value = res.data.secretKey;
        } else {
          tipWords.value = res.repMsg;
        }
      });
    }
    return {
      secretKey, // 后端返回的ase加密秘钥
      passFlag, // 是否通过的标识
      backImgBase, // 验证码背景图片
      blockBackImgBase, // 验证滑块的背景图片
      backToken, // 后端返回的唯一token值
      startMoveTime, // 移动开始的时间
      endMoveTime, // 移动结束的时间
      tipsBackColor, // 提示词的背景颜色
      tipWords,
      text,
      finishText,
      setSize,
      top,
      left,
      moveBlockLeft,
      leftBarWidth,
      // 移动中样式
      moveBlockBackgroundColor,
      leftBarBorderColor,
      iconColor,
      iconClass,
      status, // 鼠标状态
      isEnd, // 是够验证完成
      showRefresh,
      transitionLeft,
      transitionWidth,
      barArea,
      refresh,
      start
    };
  }
};
</script>

<style>
.verify-tips {
  position: absolute;
  left: 0px;
  bottom: 0px;
  width: 100%;
  height: 30px;
  line-height: 30px;
  color: #fff;
}

.suc-bg {
  background-color: rgba(92, 184, 92, 0.5);
  filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#7f5CB85C, endcolorstr=#7f5CB85C);
}

.err-bg {
  background-color: rgba(217, 83, 79, 0.5);
  filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#7fD9534F, endcolorstr=#7fD9534F);
}

.tips-enter,
.tips-leave-to {
  bottom: -30px;
}

.tips-enter-active,
.tips-leave-active {
  transition: bottom 0.5s;
}

/*常规验证码*/
.verify-code {
  font-size: 20px;
  text-align: center;
  cursor: pointer;
  margin-bottom: 5px;
  border: 1px solid #ddd;
}

.cerify-code-panel {
  height: 100%;
  overflow: hidden;
}

.verify-code-area {
  float: left;
}

.verify-input-area {
  float: left;
  width: 60%;
  padding-right: 10px;
}

.verify-change-area {
  line-height: 30px;
  float: left;
}

.varify-input-code {
  display: inline-block;
  width: 100%;
  height: 25px;
}

.verify-change-code {
  color: #337ab7;
  cursor: pointer;
}

.verify-btn {
  width: 200px;
  height: 30px;
  background-color: #337ab7;
  color: #ffffff;
  border: none;
  margin-top: 10px;
}

/*滑动验证码*/
.verify-bar-area {
  position: relative;
  background: #ffffff;
  text-align: center;
  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  border: 1px solid #ddd;
  -webkit-border-radius: 4px;
  border-radius: 4px;
}

.verify-bar-area .verify-move-block {
  position: absolute;
  top: 0px;
  left: 0;
  background: #fff;
  cursor: pointer;
  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  box-shadow: 0 0 2px #888888;
  -webkit-border-radius: 1px;
  border-radius: 1px;
}

.verify-bar-area .verify-move-block:hover {
  background-color: #337ab7;
  color: #ffffff;
}

.verify-bar-area .verify-left-bar {
  position: absolute;
  top: -1px;
  left: -1px;
  background: #f0fff0;
  cursor: pointer;
  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  border: 1px solid #ddd;
}

.verify-img-panel {
  margin: 0;
  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  border-top: 1px solid #ddd;
  border-bottom: 1px solid #ddd;
  border-radius: 3px;
  position: relative;
}

.verify-img-panel .verify-refresh {
  width: 25px;
  height: 25px;
  text-align: center;
  padding: 5px;
  cursor: pointer;
  position: absolute;
  top: 0;
  right: 0;
  z-index: 2;
}

.verify-img-panel .icon-refresh {
  font-size: 20px;
  color: #fff;
}

.verify-img-panel .verify-gap {
  background-color: #fff;
  position: relative;
  z-index: 2;
  border: 1px solid #fff;
}

.verify-bar-area .verify-move-block .verify-sub-block {
  position: absolute;
  text-align: center;
  z-index: 3;
}

.verify-bar-area .verify-move-block .verify-icon {
  font-size: 18px;
}

.verify-bar-area .verify-msg {
  z-index: 3;
}

.icon-check:before {
  content: ' ';
  display: block;
  width: 16px;
  height: 16px;
  position: absolute;
  margin: auto;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  z-index: 9999;
  background-image: url('data:image/png;base64,[encoded data, 12188 characters]');
  background-size: contain;
}

.icon-right:before {
  content: ' ';
  display: block;
  width: 16px;
  height: 16px;
  position: absolute;
  margin: auto;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  background-size: cover;
  z-index: 9999;
  background-image: url('data:image/png;base64,[encoded data, 13972 characters]');
  background-size: contain;
}

.icon-refresh:before {
  content: ' ';
  display: block;
  width: 16px;
  height: 16px;
  position: absolute;
  margin: auto;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  z-index: 9999;
  background-image: url('data:image/png;base64,[encoded data, 17216 characters]');
  background-size: contain;
}
</style>
