Selaa lähdekoodia

feat:新增输入字母数字类型的验证码Verify子组件

tsui 6 kuukautta sitten
vanhempi
commit
4002d00672

+ 4 - 3
src/components/Verifition/src/Verify.vue

@@ -36,14 +36,15 @@
  * Verify 验证码组件
  * @description 分发验证码使用
  * */
-import { VerifyPoints, VerifySlide } from './Verify'
+import {VerifyPictureWord, VerifyPoints, VerifySlide} from './Verify'
 import { computed, ref, toRefs, watchEffect } from 'vue'
 
 export default {
   name: 'Vue3Verify',
   components: {
     VerifySlide,
-    VerifyPoints
+    VerifyPoints,
+    VerifyPictureWord
   },
   props: {
     captchaType: {
@@ -438,4 +439,4 @@ export default {
   content: ' ';
   inset: 0;
 }
-</style>
+</style>

+ 194 - 0
src/components/Verifition/src/Verify/VerifyPictureWord.vue

@@ -0,0 +1,194 @@
+<template>
+  <div style="position: relative">
+    <div class="verify-img-out">
+      <div
+        :style="{
+          width: setSize.imgWidth,
+          height: setSize.imgHeight,
+          'background-size': setSize.imgWidth + ' ' + setSize.imgHeight,
+          'margin-bottom': vSpace + 'px'
+        }"
+        class="verify-img-panel"
+      >
+        <div v-show="showRefresh" class="verify-refresh" style="z-index: 3" @click="refresh">
+          <i class="iconfont icon-refresh"></i>
+        </div>
+        <img
+          @click="refresh"
+          ref="canvas"
+          :src="'data:image/png;base64,' + verificationCodeImg"
+          alt=""
+          style="display: block; width: 100%; height: 100%"
+        />
+      </div>
+    </div>
+    <div
+      :style="{
+        width: setSize.imgWidth,
+        color: barAreaColor,
+        'border-color': barAreaBorderColor,
+        // 'line-height': barSize.height
+      }"
+      class="verify-bar-area"
+    >
+      <div class="verify-msg">{{ text }}</div>
+      <div :style="{
+        'line-height': barSize.height
+      }">
+        <input class="verify-input" type="text" v-model="userCode" />
+      </div>
+      <button class="verify-btn" @click="submit" @disabled="checking">{{ t('captcha.verify') }}</button>
+    </div>
+  </div>
+</template>
+<script setup type="text/babel">
+/**
+ * VerifyPictureWord
+ * @description 输入文字
+ * */
+import { resetSize } from '../utils/util';
+import { aesEncrypt } from '../utils/ase';
+import { getCode, reqCheck } from 'src/api/login';
+import { getCurrentInstance, nextTick, onMounted, reactive, ref, toRefs } from 'vue';
+
+const props = defineProps({
+  //弹出式pop,固定fixed
+  mode: {
+    type: String,
+    default: 'fixed'
+  },
+  captchaType: {
+    type: String
+  },
+  //间隔
+  vSpace: {
+    type: Number,
+    default: 5
+  },
+  imgSize: {
+    type: Object,
+    default() {
+      return {
+        width: '310px',
+        height: '155px'
+      };
+    }
+  },
+  barSize: {
+    type: Object,
+    default() {
+      return {
+        width: '310px',
+        height: '40px'
+      };
+    }
+  }
+});
+
+const { t } = useI18n();
+const { mode, captchaType } = toRefs(props);
+const { proxy } = getCurrentInstance();
+let secretKey = ref(''), //后端返回的ase加密秘钥
+
+  userCode = ref(''), // 用户输入的验证码 暂存至pointJson,无需加密
+
+  verificationCodeImg = ref(''), //后端获取到的背景图片
+  backToken = ref(''), //后端返回的token值
+  setSize = reactive({
+    imgHeight: 0,
+    imgWidth: 0,
+    barHeight: 0,
+    barWidth: 0
+  }),
+  text = ref(''),
+  barAreaColor = ref('#000'),
+  barAreaBorderColor = ref('#ddd'),
+  showRefresh = ref(true),
+// bindingClick = ref(true)
+  checking = ref(false);
+
+const init = () => {
+  //加载页面
+  getPicture();
+  nextTick(() => {
+    let { imgHeight, imgWidth, barHeight, barWidth } = resetSize(proxy);
+    setSize.imgHeight = imgHeight;
+    setSize.imgWidth = imgWidth;
+    setSize.barHeight = barHeight;
+    setSize.barWidth = barWidth;
+    proxy.$parent.$emit('ready', proxy);
+  });
+};
+onMounted(() => {
+  // 禁止拖拽
+  init();
+  proxy.$el.onselectstart = function() {
+    return false;
+  };
+});
+const canvas = ref(null);
+
+const submit = () => {
+  checking.value = true;
+  //发送后端请求
+  var captchaVerification = secretKey.value
+    ? aesEncrypt(backToken.value + '---' + userCode.value, secretKey.value)
+    : backToken.value + '---' + userCode.value;
+  let data = {
+    captchaType: captchaType.value,
+    pointJson: userCode.value,
+    token: backToken.value
+  };
+  reqCheck(data).then((res) => {
+    if (res.repCode == '0000') {
+      barAreaColor.value = '#4cae4c';
+      barAreaBorderColor.value = '#5cb85c';
+      text.value = t('captcha.success');
+      // bindingClick.value = false
+      if (mode.value == 'pop') {
+        setTimeout(() => {
+          proxy.$parent.clickShow = false;
+          refresh();
+        }, 1500);
+      }
+      proxy.$parent.$emit('success', { captchaVerification });
+    } else {
+      proxy.$parent.$emit('error', proxy);
+      barAreaColor.value = '#d9534f';
+      barAreaBorderColor.value = '#d9534f';
+      text.value = t('captcha.fail');
+      setTimeout(() => {
+        refresh();
+      }, 700);
+    }
+    checking.value = false;
+  });
+};
+
+const refresh = async function() {
+  barAreaColor.value = '#000';
+  barAreaBorderColor.value = '#ddd';
+  checking.value = false;
+
+  userCode.value = '';
+
+  await getPicture();
+  showRefresh.value = true;
+};
+
+// 请求背景图片和验证图片
+const getPicture = async () => {
+  let data = {
+    captchaType: captchaType.value
+  };
+  const res = await getCode(data);
+  if (res.repCode == '0000') {
+    verificationCodeImg.value = res.repData.originalImageBase64;
+    backToken.value = res.repData.token;
+    secretKey.value = res.repData.secretKey;
+    text.value = t('captcha.code');
+  } else {
+    text.value = res.repMsg;
+  }
+};
+</script>

+ 2 - 1
src/components/Verifition/src/Verify/index.ts

@@ -1,4 +1,5 @@
 import VerifySlide from './VerifySlide.vue'
 import VerifyPoints from './VerifyPoints.vue'
+import VerifyPictureWord from './VerifyPictureWord.vue'
 
-export { VerifySlide, VerifyPoints }
+export { VerifySlide, VerifyPoints, VerifyPictureWord }

+ 3 - 1
src/locales/en.ts

@@ -146,9 +146,11 @@ export default {
     invalidTenantName:"Invalid Tenant Name"
   },
   captcha: {
+    verify: 'Verify',
     verification: 'Please complete security verification',
     slide: 'Swipe right to complete verification',
     point: 'Please click',
+    code: 'Please enter the verification code',
     success: 'Verification succeeded',
     fail: 'verification failed'
   },
@@ -457,4 +459,4 @@ export default {
     btn_zoom_out: 'Zoom out',
     preview: 'Preivew'
   }
-}
+}

+ 3 - 1
src/locales/zh-CN.ts

@@ -147,9 +147,11 @@ export default {
     invalidTenantName: '无效的租户名称'
   },
   captcha: {
+    verify: '验证',
     verification: '请完成安全验证',
     slide: '向右滑动完成验证',
     point: '请依次点击',
+    code: '请输入验证码',
     success: '验证成功',
     fail: '验证失败'
   },
@@ -453,4 +455,4 @@ export default {
     preview: '预览'
   },
   'OAuth 2.0': 'OAuth 2.0' // 避免菜单名是 OAuth 2.0 时,一直 warn 报错
-}
+}