feat: improve code login demo (#5154)

* feat: add some method in formApi

* fix: VbenPinInput style with small screen

* chore: improve code login demo
This commit is contained in:
Netfan 2024-12-16 20:48:51 +08:00 committed by GitHub
parent 0f756503ff
commit 38805a0e1f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 68 additions and 7 deletions

View File

@ -287,6 +287,8 @@ useVbenForm 返回的第二个参数,是一个对象,包含了一些表单
| setValues | 设置表单值, 默认会过滤不在schema中定义的field, 可通过filterFields形参关闭过滤 | `(fields: Record<string, any>, filterFields?: boolean, shouldValidate?: boolean) => Promise<void>` | | setValues | 设置表单值, 默认会过滤不在schema中定义的field, 可通过filterFields形参关闭过滤 | `(fields: Record<string, any>, filterFields?: boolean, shouldValidate?: boolean) => Promise<void>` |
| getValues | 获取表单值 | `(fields:Record<string, any>,shouldValidate: boolean = false)=>Promise<void>` | | getValues | 获取表单值 | `(fields:Record<string, any>,shouldValidate: boolean = false)=>Promise<void>` |
| validate | 表单校验 | `()=>Promise<void>` | | validate | 表单校验 | `()=>Promise<void>` |
| validateField | 校验指定字段 | `(fieldName: string)=>Promise<ValidationResult<unknown>>` |
| isFieldValid | 检查某个字段是否已通过校验 | `(fieldName: string)=>Promise<boolean>` |
| resetValidate | 重置表单校验 | `()=>Promise<void>` | | resetValidate | 重置表单校验 | `()=>Promise<void>` |
| updateSchema | 更新formSchema | `(schema:FormSchema[])=>void` | | updateSchema | 更新formSchema | `(schema:FormSchema[])=>void` |
| setFieldValue | 设置字段值 | `(field: string, value: any, shouldValidate?: boolean)=>Promise<void>` | | setFieldValue | 设置字段值 | `(field: string, value: any, shouldValidate?: boolean)=>Promise<void>` |

View File

@ -130,6 +130,11 @@ export class FormApi {
return form.values; return form.values;
} }
async isFieldValid(fieldName: string) {
const form = await this.getForm();
return form.isFieldValid(fieldName);
}
merge(formApi: FormApi) { merge(formApi: FormApi) {
const chain = [this, formApi]; const chain = [this, formApi];
const proxy = new Proxy(formApi, { const proxy = new Proxy(formApi, {
@ -348,4 +353,14 @@ export class FormApi {
} }
return await this.submitForm(); return await this.submitForm();
} }
async validateField(fieldName: string, opts?: Partial<ValidationOptions>) {
const form = await this.getForm();
const validateResult = await form.validateField(fieldName, opts);
if (Object.keys(validateResult?.errors ?? {}).length > 0) {
console.error('validate error', validateResult?.errors);
}
return validateResult;
}
} }

View File

@ -11,8 +11,8 @@ export const buttonVariants = cva(
size: { size: {
default: 'h-9 px-4 py-2', default: 'h-9 px-4 py-2',
icon: 'h-8 w-8 rounded-sm px-1 text-lg', icon: 'h-8 w-8 rounded-sm px-1 text-lg',
lg: 'h-10 rounded-md px-8', lg: 'h-10 rounded-md px-4',
sm: 'h-8 rounded-md px-3 text-xs', sm: 'h-8 rounded-md px-2 text-xs',
xs: 'h-8 w-8 rounded-sm px-1 text-xs', xs: 'h-8 w-8 rounded-sm px-1 text-xs',
}, },
variant: { variant: {

View File

@ -24,7 +24,7 @@ const forwardedProps = useForwardProps(delegatedProps);
v-bind="forwardedProps" v-bind="forwardedProps"
:class=" :class="
cn( cn(
'border-input bg-background relative flex h-10 w-10 items-center justify-center border-y border-r text-center text-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md focus:relative focus:z-10 focus:outline-none focus:ring-2', 'border-input bg-background relative flex h-10 w-8 items-center justify-center border-y border-r text-center text-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md focus:relative focus:z-10 focus:outline-none focus:ring-2 md:w-10',
props.class, props.class,
) )
" "

View File

@ -4,7 +4,9 @@
"register": "Register", "register": "Register",
"codeLogin": "Code Login", "codeLogin": "Code Login",
"qrcodeLogin": "Qr Code Login", "qrcodeLogin": "Qr Code Login",
"forgetPassword": "Forget Password" "forgetPassword": "Forget Password",
"sendingCode": "SMS Code is sending...",
"codeSentTo": "Code has been sent to {0}"
}, },
"dashboard": { "dashboard": {
"title": "Dashboard", "title": "Dashboard",

View File

@ -4,7 +4,9 @@
"register": "注册", "register": "注册",
"codeLogin": "验证码登录", "codeLogin": "验证码登录",
"qrcodeLogin": "二维码登录", "qrcodeLogin": "二维码登录",
"forgetPassword": "忘记密码" "forgetPassword": "忘记密码",
"sendingCode": "正在发送验证码",
"codeSentTo": "验证码已发送至{0}"
}, },
"dashboard": { "dashboard": {
"title": "概览", "title": "概览",

View File

@ -2,16 +2,36 @@
import type { VbenFormSchema } from '@vben/common-ui'; import type { VbenFormSchema } from '@vben/common-ui';
import type { Recordable } from '@vben/types'; import type { Recordable } from '@vben/types';
import { computed, ref } from 'vue'; import { computed, ref, useTemplateRef } from 'vue';
import { AuthenticationCodeLogin, z } from '@vben/common-ui'; import { AuthenticationCodeLogin, z } from '@vben/common-ui';
import { $t } from '@vben/locales'; import { $t } from '@vben/locales';
import { message } from 'ant-design-vue';
defineOptions({ name: 'CodeLogin' }); defineOptions({ name: 'CodeLogin' });
const loading = ref(false); const loading = ref(false);
const CODE_LENGTH = 6; const CODE_LENGTH = 6;
const loginRef =
useTemplateRef<InstanceType<typeof AuthenticationCodeLogin>>('loginRef');
function sendCodeApi(phoneNumber: string) {
message.loading({
content: $t('page.auth.sendingCode'),
duration: 0,
key: 'sending-code',
});
return new Promise((resolve) => {
setTimeout(() => {
message.success({
content: $t('page.auth.codeSentTo', [phoneNumber]),
duration: 3,
key: 'sending-code',
});
resolve({ code: '123456', phoneNumber });
}, 3000);
});
}
const formSchema = computed((): VbenFormSchema[] => { const formSchema = computed((): VbenFormSchema[] => {
return [ return [
{ {
@ -39,6 +59,25 @@ const formSchema = computed((): VbenFormSchema[] => {
: $t('authentication.sendCode'); : $t('authentication.sendCode');
return text; return text;
}, },
handleSendCode: async () => {
//
// Simulate sending verification code
loading.value = true;
const formApi = loginRef.value?.getFormApi();
if (!formApi) {
loading.value = false;
throw new Error('formApi is not ready');
}
await formApi.validateField('phoneNumber');
const isPhoneReady = await formApi.isFieldValid('phoneNumber');
if (!isPhoneReady) {
loading.value = false;
throw new Error('Phone number is not Ready');
}
const { phoneNumber } = await formApi.getValues();
await sendCodeApi(phoneNumber);
loading.value = false;
},
placeholder: $t('authentication.code'), placeholder: $t('authentication.code'),
}, },
fieldName: 'code', fieldName: 'code',
@ -62,6 +101,7 @@ async function handleLogin(values: Recordable<any>) {
<template> <template>
<AuthenticationCodeLogin <AuthenticationCodeLogin
ref="loginRef"
:form-schema="formSchema" :form-schema="formSchema"
:loading="loading" :loading="loading"
@submit="handleLogin" @submit="handleLogin"