1
0
Эх сурвалжийг харах

feat: improve code login demo (#5154)

* feat: add some method in formApi

* fix: VbenPinInput style with small screen

* chore: improve code login demo
Netfan 3 сар өмнө
parent
commit
38805a0e1f

+ 2 - 0
docs/src/components/common-ui/vben-form.md

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

+ 15 - 0
packages/@core/ui-kit/form-ui/src/form-api.ts

@@ -130,6 +130,11 @@ export class FormApi {
     return form.values;
   }
 
+  async isFieldValid(fieldName: string) {
+    const form = await this.getForm();
+    return form.isFieldValid(fieldName);
+  }
+
   merge(formApi: FormApi) {
     const chain = [this, formApi];
     const proxy = new Proxy(formApi, {
@@ -348,4 +353,14 @@ export class FormApi {
     }
     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;
+  }
 }

+ 2 - 2
packages/@core/ui-kit/shadcn-ui/src/ui/button/button.ts

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

+ 1 - 1
packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInputInput.vue

@@ -24,7 +24,7 @@ const forwardedProps = useForwardProps(delegatedProps);
     v-bind="forwardedProps"
     :class="
       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,
       )
     "

+ 3 - 1
playground/src/locales/langs/en-US/page.json

@@ -4,7 +4,9 @@
     "register": "Register",
     "codeLogin": "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": {
     "title": "Dashboard",

+ 3 - 1
playground/src/locales/langs/zh-CN/page.json

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

+ 42 - 2
playground/src/views/_core/authentication/code-login.vue

@@ -2,16 +2,36 @@
 import type { VbenFormSchema } from '@vben/common-ui';
 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 { $t } from '@vben/locales';
 
+import { message } from 'ant-design-vue';
+
 defineOptions({ name: 'CodeLogin' });
 
 const loading = ref(false);
 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[] => {
   return [
     {
@@ -39,6 +59,25 @@ const formSchema = computed((): VbenFormSchema[] => {
               : $t('authentication.sendCode');
           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'),
       },
       fieldName: 'code',
@@ -62,6 +101,7 @@ async function handleLogin(values: Recordable<any>) {
 
 <template>
   <AuthenticationCodeLogin
+    ref="loginRef"
     :form-schema="formSchema"
     :loading="loading"
     @submit="handleLogin"