feat: 验证码登录

This commit is contained in:
dap 2024-10-13 10:45:17 +08:00
parent 89047a7dde
commit 6677d5cfa8
4 changed files with 101 additions and 22 deletions

View File

@ -5,6 +5,7 @@
- 用户管理 新增从参数取默认密码 - 用户管理 新增从参数取默认密码
- 全局表格加上id 方便进行缓存列排序的操作 - 全局表格加上id 方便进行缓存列排序的操作
- 支持菜单名称i18n - 支持菜单名称i18n
- 登录页 验证码登录
**BUG FIXES** **BUG FIXES**

View File

@ -1,17 +1,61 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { LoginCodeParams, VbenFormSchema } from '@vben/common-ui'; import type { LoginCodeParams, VbenFormSchema } from '@vben/common-ui';
import { computed, ref } from 'vue'; import { computed, onMounted, 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 { Alert, message } from 'ant-design-vue';
import { tenantList, type TenantResp } from '#/api';
import { sendSmsCode } from '#/api/core/captcha';
import { useAuthStore } from '#/store';
defineOptions({ name: 'CodeLogin' }); defineOptions({ name: 'CodeLogin' });
const loading = ref(false); const loading = ref(false);
const tenantInfo = ref<TenantResp>({
tenantEnabled: false,
voList: [],
});
const codeLoginRef = useTemplateRef('codeLoginRef');
async function loadTenant() {
const resp = await tenantList();
tenantInfo.value = resp;
//
if (resp.tenantEnabled && resp.voList.length > 0) {
const firstTenantId = resp.voList[0]!.tenantId;
codeLoginRef.value?.setFieldValue('tenantId', firstTenantId);
}
}
onMounted(loadTenant);
const formSchema = computed((): VbenFormSchema[] => { const formSchema = computed((): VbenFormSchema[] => {
return [ return [
{
component: 'VbenSelect',
componentProps: {
class: 'bg-background h-[40px] focus:border-primary',
contentClass: 'max-h-[256px] overflow-y-auto',
options: tenantInfo.value.voList?.map((item) => ({
label: item.companyName,
value: item.tenantId,
})),
placeholder: $t('authentication.selectAccount'),
},
defaultValue: '000000',
dependencies: {
if: () => tenantInfo.value.tenantEnabled,
triggerFields: [''],
},
fieldName: 'tenantId',
label: $t('authentication.selectAccount'),
rules: z.string().min(1, { message: $t('authentication.selectAccount') }),
},
{ {
component: 'VbenInput', component: 'VbenInput',
componentProps: { componentProps: {
@ -28,7 +72,8 @@ const formSchema = computed((): VbenFormSchema[] => {
}, },
{ {
component: 'VbenPinInput', component: 'VbenPinInput',
componentProps: { componentProps(_, form) {
return {
createText: (countdown: number) => { createText: (countdown: number) => {
const text = const text =
countdown > 0 countdown > 0
@ -36,7 +81,20 @@ const formSchema = computed((): VbenFormSchema[] => {
: $t('authentication.sendCode'); : $t('authentication.sendCode');
return text; return text;
}, },
//
codeLength: 4,
placeholder: $t('authentication.code'), placeholder: $t('authentication.code'),
handleSendCode: async () => {
const { valid, value } = await form.validateField('phoneNumber');
if (!valid) {
// return
throw new Error('未填写手机号');
}
//
await sendSmsCode(value);
message.success('验证码发送成功');
},
};
}, },
fieldName: 'code', fieldName: 'code',
label: $t('authentication.code'), label: $t('authentication.code'),
@ -44,20 +102,36 @@ const formSchema = computed((): VbenFormSchema[] => {
}, },
]; ];
}); });
/**
* 异步处理登录操作 const authStore = useAuthStore();
* Asynchronously handle the login process
* @param values 登录表单数据
*/
async function handleLogin(values: LoginCodeParams) { async function handleLogin(values: LoginCodeParams) {
console.log(values); try {
const requestParams: any = {
tenantId: values.tenantId,
phonenumber: values.phoneNumber,
smsCode: values.code,
grantType: 'sms',
};
await authStore.authLogin(requestParams);
} catch (error) {
console.error(error);
}
} }
</script> </script>
<template> <template>
<div>
<Alert
class="mb-4"
how-icon
message="测试手机号: 15888888888 正确验证码: 1234 演示使用 不会真的发送"
type="info"
/>
<AuthenticationCodeLogin <AuthenticationCodeLogin
ref="codeLoginRef"
:form-schema="formSchema" :form-schema="formSchema"
:loading="loading" :loading="loading"
@submit="handleLogin" @submit="handleLogin"
/> />
</div>
</template> </template>

View File

@ -54,7 +54,7 @@ const emit = defineEmits<{
const router = useRouter(); const router = useRouter();
const [Form, { validate }] = useVbenForm( const [Form, { validate, setFieldValue }] = useVbenForm(
reactive({ reactive({
commonConfig: { commonConfig: {
hideLabel: true, hideLabel: true,
@ -70,6 +70,7 @@ async function handleSubmit() {
if (valid) { if (valid) {
emit('submit', { emit('submit', {
tenantId: values?.tenantId,
code: values?.code, code: values?.code,
phoneNumber: values?.phoneNumber, phoneNumber: values?.phoneNumber,
}); });
@ -79,6 +80,8 @@ async function handleSubmit() {
function goToLogin() { function goToLogin() {
router.push(props.loginPath); router.push(props.loginPath);
} }
defineExpose({ setFieldValue });
</script> </script>
<template> <template>

View File

@ -89,6 +89,7 @@ interface LoginAndRegisterParams {
} }
interface LoginCodeParams { interface LoginCodeParams {
tenantId: string;
code: string; code: string;
phoneNumber: string; phoneNumber: string;
} }