<template>
  <!-- 外层容器，使用v-show控制显示与否 -->
  <div v-show="showBox" :class="mode==='pop'?'mask':''">
    <!-- 验证框容器，根据mode属性添加特定类名 -->
    <div :class="mode==='pop'?'verifybox':''" :style="{'max-width':parseInt(imgSize.width)+30+'px'}">
      <!-- 如果是弹出模式，则显示顶部标题栏 -->
      <div v-if="mode==='pop'" class="verifybox-top">
        请完成安全验证
        <!-- 关闭按钮，点击时调用closeBox方法 -->
        <span class="verifybox-close" @click="closeBox">
          <i class="iconfont icon-close"/>
        </span>
      </div>
      <!-- 底部内容区，包含验证码组件 -->
      <div class="verifybox-bottom" :style="{padding: mode==='pop'?'15px':'0'}">
        <!-- 动态组件，根据componentType决定渲染哪个组件 -->
        <component
          :is="componentType"
          v-if="componentType"
          ref="instance"
          :captcha-type="captchaType"
          :type="verifyType"
          :figure="figure"
          :arith="arith"
          :mode="mode"
          :v-space="vSpace"
          :explain="explain"
          :img-size="imgSize"
          :block-size="blockSize"
          :bar-size="barSize"
        />
      </div>
    </div>
  </div>
</template>
<script type="text/babel">
/**
 * Verify 验证码组件
 * @description 分发验证码使用，根据传入的参数动态选择不同的验证码类型（如滑动验证、点选验证等）
 */
import VerifySlide from './Verify/VerifySlide.vue' // 引入滑动验证组件
import VerifyPoints from './Verify/VerifyPoints.vue' // 引入点选验证组件
import { computed, ref, toRefs, watchEffect } from 'vue' // 导入Vue组合式API

export default {
  name: 'Vue2Verify', // 组件名称
  components: {
    VerifySlide, // 注册滑动验证组件
    VerifyPoints // 注册点选验证组件
  },
  props: {
    captchaType: {
      type: String,
      required: true // 必填属性，用于指定验证码类型
    },
    figure: {
      type: Number // 图形配置项，可能用于特定类型的验证码
    },
    arith: {
      type: Number // 算术题配置项，可能用于特定类型的验证码
    },
    mode: {
      type: String,
      default: 'pop' // 显示模式，默认为弹出模式
    },
    vSpace: {
      type: Number // 滑块与图片之间的间距
    },
    explain: {
      type: String // 提示信息文本
    },
    imgSize: {
      type: Object,
      default () {
        return {
          width: '310px',
          height: '155px'
        }
      } // 验证码图片大小
    },
    blockSize: {
      type: Object // 滑块大小
    },
    barSize: {
      type: Object // 滑动条大小
    }
  },
  setup (props) {
    const { captchaType, mode } = toRefs(props); // 将props中的captchaType和mode转换为响应式引用

    // 控制是否显示验证框的布尔值
    const clickShow = ref(false);

    // 动态决定验证方式的变量
    const verifyType = ref(undefined);

    // 动态组件类型，由父组件或其他逻辑确定
    const componentType = ref(undefined);

    // 存储子组件实例的引用
    const instance = ref({});

    // 计算属性，用于判断是否显示验证框
    const showBox = computed(() => {
      if (mode.value === 'pop') {
        return clickShow.value; // 如果是弹出模式，则依据clickShow来决定是否显示
      } else {
        return true; // 如果不是弹出模式，则始终显示
      }
    });

    /**
     * refresh
     * @description 刷新验证码
     */
    const refresh = () => {
      console.log(instance.value);
      if (instance.value && typeof instance.value.refresh === 'function') {
        instance.value.refresh(); // 调用子组件的刷新方法
      }
    };

    /**
     * closeBox
     * @description 关闭验证框并刷新验证码
     */
    const closeBox = () => {
      clickShow.value = false;
      refresh();
    };

    /**
     * show
     * @description 显示验证框并生成UUID
     */
    const show = () => {
      if (mode.value === 'pop') {
        clickShow.value = true; // 如果是弹出模式，设置为显示
      }
      uuid(); // 生成UUID
    };

    // 监听captchaType变化，并更新verifyType和componentType
    watchEffect(() => {
      switch (captchaType.value) {
        case 'blockPuzzle':
          verifyType.value = '2';
          componentType.value = VerifySlide; // 设置为滑动验证组件
          break;
        case 'clickWord':
          verifyType.value = ''; // 可能需要具体定义
          componentType.value = VerifyPoints; // 设置为点选验证组件
          break;
        default:
          verifyType.value = undefined;
          componentType.value = undefined;
      }
    });

    /**
     * uuid
     * @description 生成一个随机UUID，并存储到localStorage中
     */
    const uuid = () => {
      const s = [];
      const hexDigits = '0123456789abcdef';
      for (let i = 0; i < 36; i++) {
        s[i] = hexDigits[Math.floor(Math.random() * 0x10)];
      }
      s[14] = '4'; // bits 12-15 of the time_hi_and_version field to 0010
      s[19] = hexDigits[(s[19] & 0x3) | 0x8]; // bits 6-7 of the clock_seq_hi_and_reserved to 01
      s[8] = s[13] = s[18] = s[23] = '-';

      const slider = `slider-${s.join('')}`;
      const point = `point-${s.join('')}`;

      // 判断下是否存在 slider 和 point 的UUID
      if (!localStorage.getItem('b2cSlider')) {
        localStorage.setItem('b2cSlider', slider);
      }
      if (!localStorage.getItem('b2cPoint')) {
        localStorage.setItem('b2cPoint', point);
      }
    };

    // 返回需要在模板中使用的变量和方法
    return {
      clickShow,
      verifyType,
      componentType,
      instance,
      showBox,
      closeBox,
      show,
      uuid,
      refresh
    };
  }
};
</script>
<style>
/* 验证码框的整体样式 */
.verifybox {
  position: relative; /* 设置相对定位，使内部的绝对定位元素能够相对于验证码框定位 */
  box-sizing: border-box; /* 确保内边距和边框包含在元素的总宽度和高度之内 */
  border-radius: 2px; /* 给验证码框添加轻微的圆角效果 */
  border: 1px solid #e4e7eb; /* 定义边框的宽度、样式和颜色 */
  background-color: #fff; /* 设置背景颜色为白色 */
  box-shadow: 0 0 10px rgba(0, 0, 0, .3); /* 添加阴影以增强视觉深度 */
  left: 50%; /* 将验证码框水平居中于其容器 */
  top: 50%; /* 将验证码框垂直居中于其容器 */
  transform: translate(-50%, -50%); /* 调整验证码框位置，实现完美居中 */
}

/* 验证码框顶部区域（标题栏）样式 */
.verifybox-top {
  padding: 0 15px; /* 设置左右内边距 */
  height: 50px; /* 固定高度 */
  line-height: 50px; /* 行高与高度相同，确保文本垂直居中 */
  text-align: left; /* 文本左对齐 */
  font-size: 16px; /* 设置字体大小 */
  color: #45494c; /* 设置文字颜色 */
  border-bottom: 1px solid #e4e7eb; /* 底部细线边框 */
  box-sizing: border-box; /* 确保padding和border不会增加元素宽度 */
}

/* 验证码框底部内容区样式 */
.verifybox-bottom {
  padding: 15px; /* 设置四周内边距 */
  box-sizing: border-box; /* 确保padding和border不会增加元素宽度 */
}

/* 关闭按钮样式 */
.verifybox-close {
  position: absolute; /* 绝对定位，使其相对于最近的非static定位祖先元素定位 */
  top: 13px; /* 从顶部偏移量 */
  right: 9px; /* 从右侧偏移量 */
  width: 24px; /* 按钮宽度 */
  height: 24px; /* 按钮高度 */
  text-align: center; /* 文字居中 */
  cursor: pointer; /* 更改鼠标指针为手型，表示可点击 */
}

/* 弹出模式下的遮罩层样式 */
.mask {
  position: fixed; /* 固定定位，相对于浏览器窗口 */
  top: 0;
  left: 0;
  z-index: 1001; /* 确保遮罩层位于其他页面元素之上 */
  width: 100%; /* 宽度覆盖整个屏幕 */
  height: 100vh; /* 高度覆盖整个视口 */
  background: rgba(0, 0, 0, .3); /* 半透明黑色背景，略微遮挡背后的内容 */
  transition: all .5s; /* 所有属性的变化都将应用平滑过渡效果 */
}

/* 提示信息样式 */
.verify-tips {
  position: absolute; /* 绝对定位，相对于最近的非static定位祖先元素 */
  left: 0;
  bottom: 0; /* 固定在验证码框的底部 */
  width: 100%; /* 宽度与验证码框一致 */
  height: 30px; /* 固定高度 */
  line-height: 30px; /* 行高与高度相同，确保文本垂直居中 */
  color: #fff; /* 文字颜色为白色 */
}

/* 成功提示背景色 */
.suc-bg {
  background-color: rgba(92, 184, 92, .5); /* 半透明的成功绿色 */
  filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#7f5CB85C, endcolorstr=#7f5CB85C); /* IE滤镜，用于IE浏览器兼容性 */
}

/* 错误提示背景色 */
.err-bg {
  background-color: rgba(217, 83, 79, .5); /* 半透明的错误红色 */
  filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#7fD9534F, endcolorstr=#7fD9534F); /* IE滤镜，用于IE浏览器兼容性 */
}

/* 提示信息进入和离开动画 */
.tips-enter,
.tips-leave-to {
  bottom: -30px; /* 动画开始或结束时的位置 */
}

.tips-enter-active,
.tips-leave-active {
  transition: bottom .5s; /* 动画持续时间为.5秒 */
}
/* ---------------------------- */
/* 常规验证码相关样式 */

.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%; /* 设置宽度为父元素的60% */
  padding-right: 10px; /* 右侧内边距 */
}

.verify-change-area {
  line-height: 30px; /* 行高设置为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; /* 内容居中 */
  box-sizing: content-box; /* 内容盒模型 */
  border: 1px solid #ddd; /* 边框 */
  -webkit-border-radius: 4px; /* 圆角，针对Webkit浏览器 */
}

.verify-bar-area .verify-move-block {
  position: absolute; /* 绝对定位 */
  top: 0;
  left: 0;
  background: #fff; /* 白色背景 */
  cursor: pointer; /* 更改鼠标指针为手型 */
  box-sizing: content-box; /* 内容盒模型 */
  box-shadow: 0 0 2px #888888; /* 添加阴影 */
  -webkit-border-radius: 1px; /* 圆角，针对Webkit浏览器 */
}

.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; /* 更改鼠标指针为手型 */
  box-sizing: content-box; /* 内容盒模型 */
  border: 1px solid #ddd; /* 边框 */
}

.verify-img-panel {
  margin: 0; /* 移除外边距 */
  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;
    }


.iconfont {
  font-family: "iconfont" !important; /* 指定字体系列为 "iconfont"，并使用 !important 确保优先级最高 */
  font-size: 16px; /* 设置图标的基本字体大小 */
  font-style: normal; /* 设置字体样式为正常，防止浏览器默认斜体 */
  -webkit-font-smoothing: antialiased; /* 为 WebKit 浏览器（如 Chrome 和 Safari）设置字体平滑效果，使图标更加清晰 */
  -moz-osx-font-smoothing: grayscale; /* 为 Mozilla Firefox 在 macOS 上设置字体平滑效果，增强图标显示质量 */
}

.icon-check:before{
  content: " "; /* 定义伪元素的内容为空格，确保元素存在但不显示文本 */
  display: block; /* 将伪元素显示为块级元素 */
  width: 16px; /* 设置宽度 */
  height: 16px; /* 设置高度 */
  position: absolute; /* 绝对定位，相对于最近的非static定位祖先元素 */
  margin: auto; /* 自动调整外边距，使元素水平和垂直居中 */
  left: 0;
  right: 0;
  top: 0;
  bottom: 0; /* 使用四个方向的位置属性配合margin:auto实现元素在其容器中的精确居中 */
  z-index: 9999; /* 设置层叠顺序，确保伪元素位于其他内容之上 */
  background-image: url("data:image/png;base64,[encoded data, 12188 characters]");
  background-size: contain; /* 确保背景图像按比例缩放以适应元素大小 */
}

.icon-close:before {
  content: " "; /* 定义伪元素的内容为空格，确保元素存在但不显示文本 */
  display: block; /* 将伪元素显示为块级元素 */
  width: 16px; /* 设置宽度 */
  height: 16px; /* 设置高度 */
  position: absolute; /* 绝对定位，相对于最近的非static定位祖先元素 */
  margin: auto; /* 自动调整外边距，使元素水平和垂直居中 */
  left: 0;
  right: 0;
  top: 0;
  bottom: 0; /* 使用四个方向的位置属性配合margin:auto实现元素在其容器中的精确居中 */
  z-index: 9999; /* 设置层叠顺序，确保伪元素位于其他内容之上 */
  background-image: url("data:image/png;base64,[encoded data, 5600 characters]");
  background-size: contain; /* 确保背景图像按比例缩放以适应元素大小 */
}

.icon-right:before {
  content: " "; /* 定义伪元素的内容为空格，确保元素存在但不显示文本 */
  display: block; /* 将伪元素显示为块级元素 */
  width: 16px; /* 设置宽度 */
  height: 16px; /* 设置高度 */
  position: absolute; /* 绝对定位，相对于最近的非static定位祖先元素 */
  margin: auto; /* 自动调整外边距，使元素水平和垂直居中 */
  left: 0;
  right: 0;
  top: 0;
  bottom: 0; /* 使用四个方向的位置属性配合margin:auto实现元素在其容器中的精确居中 */
  z-index: 9999; /* 设置层叠顺序，确保伪元素位于其他内容之上 */
  background-image: url("data:image/png;base64,[encoded data, 5600 characters]");
  background-size: contain; /* 确保背景图像按比例缩放以适应元素大小 */
}

.icon-refresh:before {
  content: " "; /* 定义伪元素的内容为空格，确保元素存在但不显示文本 */
  display: block; /* 将伪元素显示为块级元素 */
  width: 16px; /* 设置宽度 */
  height: 16px; /* 设置高度 */
  position: absolute; /* 绝对定位，相对于最近的非static定位祖先元素 */
  margin: auto; /* 自动调整外边距，使元素水平和垂直居中 */
  left: 0;
  right: 0;
  top: 0;
  bottom: 0; /* 使用四个方向的位置属性配合margin:auto实现元素在其容器中的精确居中 */
  z-index: 9999; /* 设置层叠顺序，确保伪元素位于其他内容之上 */
  background-image: url("data:image/png;base64,[encoded data, 5600 characters]");
  background-size: contain; /* 确保背景图像按比例缩放以适应元素大小 */
}
</style>
