feat: 添加电子邮件和密码登录及注册功能,包含表单验证和用户状态管理

This commit is contained in:
2026-01-15 02:59:23 +07:00
parent 5a40945206
commit 53135e13ad
5 changed files with 246 additions and 5 deletions

View File

@@ -1,7 +1,51 @@
<script lang='ts' setup>
import { toastController } from "@ionic/vue";
import { Field, Form } from "vee-validate";
import IconParkOutlineInfo from "~icons/icon-park-outline/info";
import { authClient, emailSignupSchema } from "@/auth";
const { t } = useI18n();
const agreeToTerms = ref(false);
const route = useRoute();
async function handleSubmit(values: Record<string, any>) {
if (!agreeToTerms.value) {
toastController.create({
message: t("auth.signup.agreeTermsError"),
duration: 2000,
color: "danger",
}).then(toast => toast.present());
return;
}
try {
const { data } = await authClient.signUp.email({
name: values.name,
email: values.email,
password: values.password,
});
if (!data?.token) {
toastController.create({
message: "注册失败,请重试",
duration: 2000,
color: "danger",
}).then(toast => toast.present());
}
else {
const userStore = useUserStore();
userStore.setToken(data.token);
userStore.updateProfile();
useNavigateToRedirect(route.query.redirect as string);
}
}
catch (err) {
toastController.create({
message: "注册失败,请重试",
duration: 2000,
color: "danger",
}).then(toast => toast.present());
}
}
</script>
<template>
@@ -16,7 +60,19 @@ const { t } = useI18n();
{{ t('auth.signup.title') }}
</div>
<Form>
<Form :validation-schema="emailSignupSchema" class="mt-5" @submit="handleSubmit">
<Field v-slot="{ field, errorMessage }" name="name" type="text">
<div class="mb-4">
<ui-input
v-bind="field"
:placeholder="t('auth.signup.enterName')"
type="text"
/>
<div v-if="errorMessage" class="text-xs text-red-500 mt-1">
{{ errorMessage }}
</div>
</div>
</Field>
<Field v-slot="{ field, errorMessage }" name="email" type="email">
<div class="mb-4">
<ui-input
@@ -29,9 +85,53 @@ const { t } = useI18n();
</div>
</div>
</Field>
<Field v-slot="{ field, errorMessage }" name="password" type="password">
<div class="mb-4">
<ui-input
v-bind="field"
:placeholder="t('auth.signup.enterPassword')"
type="password"
/>
<div v-if="errorMessage" class="text-xs text-red-500 mt-1">
{{ errorMessage }}
</div>
</div>
</Field>
<ion-button
expand="block"
class="ion-margin-top"
shape="round"
type="submit"
>
{{ t('auth.login.signUpAndLogin') }}
</ion-button>
<ion-checkbox v-model="agreeToTerms" label-placement="end" class="mt-8 text-sm">
<span>{{ t('auth.login.agreeText') }}</span>
<a href="/auth/term" class="text-primary underline mx-2 underline-offset-3">
{{ t('auth.login.termsLink') }}
</a>
</ion-checkbox>
<div class="text-sm text-text-300 mt-1 flex items-center">
<IconParkOutlineInfo class="inline-block mr-1" />
{{ t('auth.login.autoRegisterTip') }}
</div>
</Form>
</IonContent>
</IonPage>
</template>
<style lang='css' scoped></style>
<style lang='css' scoped>
ion-checkbox {
--size: 18px;
}
ion-checkbox::part(label) {
margin-left: 4px;
}
.title {
margin-bottom: 30px;
}
</style>