chore(@vben/common-ui): add verify component (#4390)
* chore(@vben/common-ui): 增加拖拽校验组件 * chore: 增加样式 * Merge branch 'main' into wangjue-verify-comp * chore: 封装action组件 * chore: 拆分完成拖拽功能 * chore: 样式调整为tailwindcss语法 * chore: 导出check图标 * chore: 拖动的图标变为@vben/icons的 * chore: 完成插槽功能迁移 * fix: ci error * chore: 适配暗黑主题 * chore: 国际化 * chore: resolve conflict * chore: 迁移v2的图片旋转校验组件 * chore: 完善选择校验demo * chore: 转换为tailwindcss * chore: 替换为系统的颜色变量 * chore: 使用interface代替组件的props声明 * chore: 调整props * chore: 优化demo背景 * chore: follow suggest * chore: rm unnecessary style tag * chore: update demo * perf: improve the experience of Captcha components --------- Co-authored-by: vince <vince292007@gmail.com> Co-authored-by: Vben <ann.vben@gmail.com>
This commit is contained in:
@@ -83,6 +83,9 @@
|
||||
},
|
||||
"captcha": {
|
||||
"title": "Captcha",
|
||||
"pointSelection": "Point Selection Captcha",
|
||||
"sliderCaptcha": "Slider Captcha",
|
||||
"sliderRotateCaptcha": "Rotate Captcha",
|
||||
"captchaCardTitle": "Please complete the security verification",
|
||||
"pageDescription": "Verify user identity by clicking on specific locations in the image.",
|
||||
"pageTitle": "Captcha Component Example",
|
||||
|
@@ -83,6 +83,9 @@
|
||||
},
|
||||
"captcha": {
|
||||
"title": "验证码",
|
||||
"pointSelection": "点选验证",
|
||||
"sliderCaptcha": "滑块验证",
|
||||
"sliderRotateCaptcha": "旋转验证",
|
||||
"captchaCardTitle": "请完成安全验证",
|
||||
"pageDescription": "通过点击图片中的特定位置来验证用户身份。",
|
||||
"pageTitle": "验证码组件示例",
|
||||
|
@@ -42,15 +42,7 @@ const routes: RouteRecordRaw[] = [
|
||||
title: $t('page.examples.ellipsis.title'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'CaptchaExample',
|
||||
path: '/examples/captcha',
|
||||
component: () => import('#/views/examples/captcha/index.vue'),
|
||||
meta: {
|
||||
icon: 'logos:recaptcha',
|
||||
title: $t('page.examples.captcha.title'),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: 'FormExample',
|
||||
path: '/examples/form',
|
||||
@@ -109,6 +101,43 @@ const routes: RouteRecordRaw[] = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'CaptchaExample',
|
||||
path: '/examples/captcha',
|
||||
meta: {
|
||||
icon: 'logos:recaptcha',
|
||||
title: $t('page.examples.captcha.title'),
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'DragVerifyExample',
|
||||
path: '/examples/captcha/slider',
|
||||
component: () =>
|
||||
import('#/views/examples/captcha/slider-captcha.vue'),
|
||||
meta: {
|
||||
title: $t('page.examples.captcha.sliderCaptcha'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'RotateVerifyExample',
|
||||
path: '/examples/captcha/slider-rotate',
|
||||
component: () =>
|
||||
import('#/views/examples/captcha/slider-rotate-captcha.vue'),
|
||||
meta: {
|
||||
title: $t('page.examples.captcha.sliderRotateCaptcha'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'CaptchaPointSelectionExample',
|
||||
path: '/examples/captcha/point-selection',
|
||||
component: () =>
|
||||
import('#/views/examples/captcha/point-selection-captcha.vue'),
|
||||
meta: {
|
||||
title: $t('page.examples.captcha.pointSelection'),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
File diff suppressed because one or more lines are too long
@@ -9,20 +9,24 @@ import { Card, Input, InputNumber, message, Switch } from 'ant-design-vue';
|
||||
|
||||
import { $t } from '#/locales';
|
||||
|
||||
import { captchaImage, hintImage } from './base64';
|
||||
const DEFAULT_CAPTCHA_IMAGE =
|
||||
'https://unpkg.com/@vbenjs/static-source@0.1.7/source/default-captcha-image.jpeg';
|
||||
|
||||
const DEFAULT_HINT_IMAGE =
|
||||
'https://unpkg.com/@vbenjs/static-source@0.1.7/source/default-hint-image.png';
|
||||
|
||||
const selectedPoints = ref<CaptchaPoint[]>([]);
|
||||
const params = reactive({
|
||||
captchaImage,
|
||||
captchaImageUrl: '',
|
||||
captchaImage: '',
|
||||
captchaImageUrl: DEFAULT_CAPTCHA_IMAGE,
|
||||
height: undefined,
|
||||
hintImage,
|
||||
hintImageUrl: '',
|
||||
hintImage: '',
|
||||
hintImageUrl: DEFAULT_HINT_IMAGE,
|
||||
hintText: '唇,燕,碴,找',
|
||||
paddingX: undefined,
|
||||
paddingY: undefined,
|
||||
showConfirm: true,
|
||||
showHintImage: true,
|
||||
showHintImage: false,
|
||||
title: '',
|
||||
width: undefined,
|
||||
});
|
116
playground/src/views/examples/captcha/slider-captcha.vue
Normal file
116
playground/src/views/examples/captcha/slider-captcha.vue
Normal file
@@ -0,0 +1,116 @@
|
||||
<script lang="ts" setup>
|
||||
import type {
|
||||
CaptchaVerifyPassingData,
|
||||
SliderCaptchaActionType,
|
||||
} from '@vben/common-ui';
|
||||
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { Page, SliderCaptcha } from '@vben/common-ui';
|
||||
import { Bell, Sun } from '@vben/icons';
|
||||
|
||||
import { Button, Card, message } from 'ant-design-vue';
|
||||
|
||||
function handleSuccess(data: CaptchaVerifyPassingData) {
|
||||
const { time } = data;
|
||||
message.success(`校验成功,耗时${time}秒`);
|
||||
}
|
||||
function handleBtnClick(elRef?: SliderCaptchaActionType) {
|
||||
if (!elRef) {
|
||||
return;
|
||||
}
|
||||
elRef.resume();
|
||||
}
|
||||
|
||||
const el1 = ref<SliderCaptchaActionType>();
|
||||
const el2 = ref<SliderCaptchaActionType>();
|
||||
const el3 = ref<SliderCaptchaActionType>();
|
||||
const el4 = ref<SliderCaptchaActionType>();
|
||||
const el5 = ref<SliderCaptchaActionType>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page description="用于前端简单的拖动校验场景" title="滑块校验">
|
||||
<Card class="mb-5" title="基础示例">
|
||||
<div class="flex items-center justify-center p-4 px-[30%]">
|
||||
<SliderCaptcha ref="el1" @success="handleSuccess" />
|
||||
<Button class="ml-2" type="primary" @click="handleBtnClick(el1)">
|
||||
还原
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
<Card class="mb-5" title="自定义圆角">
|
||||
<div class="flex items-center justify-center p-4 px-[30%]">
|
||||
<SliderCaptcha
|
||||
ref="el2"
|
||||
class="rounded-full"
|
||||
@success="handleSuccess"
|
||||
/>
|
||||
<Button class="ml-2" type="primary" @click="handleBtnClick(el2)">
|
||||
还原
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
<Card class="mb-5" title="自定义背景色">
|
||||
<div class="flex items-center justify-center p-4 px-[30%]">
|
||||
<SliderCaptcha
|
||||
ref="el3"
|
||||
:bar-style="{
|
||||
backgroundColor: '#018ffb',
|
||||
}"
|
||||
success-text="校验成功"
|
||||
text="拖动以进行校验"
|
||||
@success="handleSuccess"
|
||||
/>
|
||||
<Button class="ml-2" type="primary" @click="handleBtnClick(el3)">
|
||||
还原
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
<Card class="mb-5" title="自定义拖拽图标">
|
||||
<div class="flex items-center justify-center p-4 px-[30%]">
|
||||
<SliderCaptcha ref="el4" @success="handleSuccess">
|
||||
<template #actionIcon="{ isPassing }">
|
||||
<Bell v-if="isPassing" />
|
||||
<Sun v-else />
|
||||
</template>
|
||||
</SliderCaptcha>
|
||||
<Button class="ml-2" type="primary" @click="handleBtnClick(el4)">
|
||||
还原
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
<Card class="mb-5" title="自定义文本">
|
||||
<div class="flex items-center justify-center p-4 px-[30%]">
|
||||
<SliderCaptcha
|
||||
ref="el5"
|
||||
success-text="成功"
|
||||
text="拖动"
|
||||
@success="handleSuccess"
|
||||
/>
|
||||
<Button class="ml-2" type="primary" @click="handleBtnClick(el5)">
|
||||
还原
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
<Card class="mb-5" title="自定义内容(slot)">
|
||||
<div class="flex items-center justify-center p-4 px-[30%]">
|
||||
<SliderCaptcha ref="el5" @success="handleSuccess">
|
||||
<template #text="{ isPassing }">
|
||||
<template v-if="isPassing">
|
||||
<Bell class="mr-2 size-4" />
|
||||
成功
|
||||
</template>
|
||||
<template v-else>
|
||||
拖动
|
||||
<Sun class="ml-2 size-4" />
|
||||
</template>
|
||||
</template>
|
||||
</SliderCaptcha>
|
||||
<Button class="ml-2" type="primary" @click="handleBtnClick(el5)">
|
||||
还原
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
</Page>
|
||||
</template>
|
@@ -0,0 +1,28 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
|
||||
import { Page, SliderRotateCaptcha } from '@vben/common-ui';
|
||||
import { preferences } from '@vben/preferences';
|
||||
import { useUserStore } from '@vben/stores';
|
||||
|
||||
import { Card, message } from 'ant-design-vue';
|
||||
|
||||
const userStore = useUserStore();
|
||||
function handleSuccess() {
|
||||
message.success('success!');
|
||||
}
|
||||
|
||||
const avatar = computed(() => {
|
||||
return userStore.userInfo?.avatar || preferences.app.defaultAvatar;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page description="用于前端简单的拖动校验场景" title="滑块旋转校验">
|
||||
<Card class="mb-5" title="基本示例">
|
||||
<div class="flex items-center justify-center p-4">
|
||||
<SliderRotateCaptcha :src="avatar" @success="handleSuccess" />
|
||||
</div>
|
||||
</Card>
|
||||
</Page>
|
||||
</template>
|
Reference in New Issue
Block a user