验证码接口适配调整
This commit is contained in:
parent
f9b0b05c7e
commit
25e80d73ae
4
components.d.ts
vendored
4
components.d.ts
vendored
@ -11,6 +11,8 @@ declare module '@vue/runtime-core' {
|
||||
ElAside: typeof import('element-plus/es')['ElAside']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElCard: typeof import('element-plus/es')['ElCard']
|
||||
ElCheckboxButton: typeof import('element-plus/es')['ElCheckboxButton']
|
||||
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
||||
ElCol: typeof import('element-plus/es')['ElCol']
|
||||
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
||||
ElContainer: typeof import('element-plus/es')['ElContainer']
|
||||
@ -34,8 +36,6 @@ declare module '@vue/runtime-core' {
|
||||
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
||||
ElOption: typeof import('element-plus/es')['ElOption']
|
||||
ElPagination: typeof import('element-plus/es')['ElPagination']
|
||||
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
|
||||
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
||||
ElRow: typeof import('element-plus/es')['ElRow']
|
||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div ref="captchaBoxRef" class="captcha-panel"></div>
|
||||
<div ref="captchaBoxRef"></div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onBeforeUnmount, ref } from 'vue'
|
||||
import { nextTick, onBeforeUnmount, ref } from 'vue'
|
||||
import {
|
||||
createTianAiCaptcha,
|
||||
type TianAiCaptchaConfig,
|
||||
@ -13,17 +13,15 @@ import {
|
||||
} from '@/vendor/tianai-captcha'
|
||||
|
||||
type CaptchaMode = 'data' | 'validate'
|
||||
type CaptchaType = 'RANDOM' | 'SLIDER' | 'ROTATE' | 'CONCAT' | 'WORD_IMAGE_CLICK'
|
||||
type CaptchaType = 'SLIDER' | 'ROTATE' | 'CONCAT' | 'WORD_IMAGE_CLICK'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
mode?: CaptchaMode
|
||||
type?: CaptchaType
|
||||
validCaptchaUrl?: string
|
||||
requestHeaders?: Record<string, string>
|
||||
types?: CaptchaType[]
|
||||
styleConfig?: TianAiCaptchaStyle
|
||||
}>(), {
|
||||
mode: 'data',
|
||||
type: 'RANDOM'
|
||||
types: () => []
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
@ -38,17 +36,8 @@ const emit = defineEmits<{
|
||||
const captchaBoxRef = ref<HTMLElement | null>(null)
|
||||
const captchaInstance = ref<TianAiCaptchaInstance | null>(null)
|
||||
const active = ref(false)
|
||||
const requestCaptchaBaseUrl = buildCaptchaApiUrl('/captcha/gen')
|
||||
const resolvedValidCaptchaUrl = computed(() => {
|
||||
return props.validCaptchaUrl || buildCaptchaApiUrl('/captcha/check')
|
||||
})
|
||||
const requestCaptchaDataUrl = computed(() => {
|
||||
if (props.type === 'RANDOM') {
|
||||
return requestCaptchaBaseUrl
|
||||
}
|
||||
|
||||
return `${requestCaptchaBaseUrl}?type=${encodeURIComponent(props.type)}`
|
||||
})
|
||||
const requestCaptchaDataUrl = buildCaptchaApiUrl('/captcha/generate')
|
||||
const validCaptchaUrl = buildCaptchaApiUrl('/captcha/check')
|
||||
|
||||
async function init() {
|
||||
await nextTick()
|
||||
@ -62,8 +51,8 @@ async function init() {
|
||||
|
||||
const config: TianAiCaptchaConfig = {
|
||||
bindEl: captchaBoxRef.value,
|
||||
requestCaptchaDataUrl: requestCaptchaDataUrl.value,
|
||||
requestHeaders: props.requestHeaders,
|
||||
requestCaptchaDataUrl,
|
||||
types: props.types,
|
||||
btnRefreshFun: (_el, tac) => {
|
||||
tac.reloadCaptcha()
|
||||
},
|
||||
@ -74,7 +63,7 @@ async function init() {
|
||||
}
|
||||
switch (props.mode) {
|
||||
case 'validate':
|
||||
config.validCaptchaUrl = resolvedValidCaptchaUrl.value
|
||||
config.validCaptchaUrl = validCaptchaUrl
|
||||
config.validSuccess = res => emit('valid-success', res)
|
||||
config.validFail = res => emit('valid-fail', res)
|
||||
break
|
||||
|
||||
@ -14,6 +14,7 @@ class CaptchaConfig {
|
||||
this.bindEl = args.bindEl;
|
||||
this.domBindEl = Dom(args.bindEl);
|
||||
this.requestCaptchaDataUrl = args.requestCaptchaDataUrl;
|
||||
this.types = Array.isArray(args.types) ? args.types.filter(Boolean) : [];
|
||||
this.validCaptchaUrl = args.validCaptchaUrl;
|
||||
if (args.validSuccess) {
|
||||
this.validSuccess = args.validSuccess;
|
||||
@ -64,7 +65,7 @@ class CaptchaConfig {
|
||||
requestCaptchaData() {
|
||||
const requestParam = {};
|
||||
requestParam.headers = this.requestHeaders || {};
|
||||
requestParam.data = {};
|
||||
requestParam.data = { types: this.types };
|
||||
// 设置默认值
|
||||
requestParam.headers["Content-Type"] = "application/json;charset=UTF-8";
|
||||
requestParam.method = "POST";
|
||||
|
||||
2
src/vendor/tianai-captcha/index.ts
vendored
2
src/vendor/tianai-captcha/index.ts
vendored
@ -17,8 +17,8 @@ export interface TianAiCaptchaStyle {
|
||||
export interface TianAiCaptchaConfig {
|
||||
bindEl: TianAiCaptchaBindTarget
|
||||
requestCaptchaDataUrl: string
|
||||
types?: string[]
|
||||
validCaptchaUrl?: string
|
||||
requestHeaders?: Record<string, string>
|
||||
timeToTimestamp?: boolean
|
||||
validSuccess?: (res: any, captcha: any, tac: TianAiCaptchaInstance) => void
|
||||
validFail?: (res: any, captcha: any, tac: TianAiCaptchaInstance) => void
|
||||
|
||||
@ -10,11 +10,19 @@
|
||||
<el-card shadow="never">
|
||||
<template #header>验证码类型</template>
|
||||
|
||||
<el-radio-group v-model="selectedType" size="large">
|
||||
<el-radio-button v-for="item in captchaTypeOptions" :key="item.value" :label="item.value">
|
||||
<p class="type-hint">
|
||||
可同时勾选多种类型;不选时将按随机类型请求。
|
||||
</p>
|
||||
|
||||
<el-checkbox-group v-model="selectedTypes" size="large">
|
||||
<el-checkbox-button v-for="item in captchaTypeOptions" :key="item.value" :value="item.value">
|
||||
{{ item.label }}
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-checkbox-button>
|
||||
</el-checkbox-group>
|
||||
|
||||
<div class="type-actions">
|
||||
<el-button link type="primary" @click="clearTypes" :disabled="selectedTypes.length === 0">恢复随机</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card class="preview-card" shadow="never">
|
||||
@ -23,7 +31,7 @@
|
||||
ref="captchaRef"
|
||||
class="captcha-box"
|
||||
mode="validate"
|
||||
:type="selectedType"
|
||||
:types="selectedTypes"
|
||||
@close="handleCaptchaClose"
|
||||
@state-change="handleCaptchaStateChange"
|
||||
@valid-fail="handleValidFail"
|
||||
@ -38,7 +46,7 @@
|
||||
import { onBeforeUnmount, ref } from 'vue'
|
||||
import CaptchaPanel from '@/components/CaptchaPanel.vue'
|
||||
|
||||
type CaptchaType = 'RANDOM' | 'SLIDER' | 'ROTATE' | 'CONCAT' | 'WORD_IMAGE_CLICK'
|
||||
type CaptchaType = 'SLIDER' | 'ROTATE' | 'CONCAT' | 'WORD_IMAGE_CLICK'
|
||||
|
||||
type CaptchaPanelRef = {
|
||||
destroy: () => void
|
||||
@ -47,7 +55,6 @@ type CaptchaPanelRef = {
|
||||
}
|
||||
|
||||
const captchaTypeOptions: Array<{ label: string, value: CaptchaType }> = [
|
||||
{ label: '随机', value: 'RANDOM' },
|
||||
{ label: '滑块拼图', value: 'SLIDER' },
|
||||
{ label: '旋转', value: 'ROTATE' },
|
||||
{ label: '拼接', value: 'CONCAT' },
|
||||
@ -56,17 +63,21 @@ const captchaTypeOptions: Array<{ label: string, value: CaptchaType }> = [
|
||||
|
||||
const captchaRef = ref<CaptchaPanelRef | null>(null)
|
||||
const captchaActive = ref(false)
|
||||
const selectedType = ref<CaptchaType>('RANDOM')
|
||||
const selectedTypes = ref<CaptchaType[]>([])
|
||||
|
||||
async function startCaptcha() {
|
||||
console.info('[captcha sandbox] init captcha', {
|
||||
type: selectedType.value,
|
||||
types: selectedTypes.value,
|
||||
mode: 'validate'
|
||||
})
|
||||
|
||||
await captchaRef.value?.init()
|
||||
}
|
||||
|
||||
function clearTypes() {
|
||||
selectedTypes.value = []
|
||||
}
|
||||
|
||||
function reloadCaptcha() {
|
||||
if (!captchaActive.value) return
|
||||
console.info('[captcha sandbox] manual reload')
|
||||
@ -107,6 +118,16 @@ onBeforeUnmount(() => captchaRef.value?.destroy())
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.type-hint {
|
||||
margin: 0 0 16px;
|
||||
color: #606266;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.type-actions {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.sandbox-grid {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user