feat: 添加用户认证功能,优化登录和注册流程,集成表单验证和加载状态

This commit is contained in:
2026-01-17 21:18:51 +07:00
parent 7ec2522fa0
commit 51719cd229
12 changed files with 252 additions and 73 deletions

View File

@@ -1,23 +1,65 @@
<script lang='ts' setup>
import { toastController } from "@ionic/vue";
import { safeClient } from "@/api";
import { authClient } from "@/auth";
import { LoginSchema } from "./schema";
const route = useRoute();
const router = useRouter();
const phoneNumber = ref("");
const password = ref("");
const form = ref({
phoneNumber: "",
password: "",
});
const agreed = ref(false);
const showPassword = ref(false);
const isLoading = ref(false);
function handleLogin() {
if (!phoneNumber.value || !password.value) {
// TODO: 显示提示信息
return;
}
async function showToast(message: string, color: "success" | "danger" | "warning" = "danger") {
const toast = await toastController.create({
message,
duration: 2000,
position: "top",
color,
});
await toast.present();
}
async function handleLogin() {
if (!agreed.value) {
// TODO: 提示需要同意条款
await showToast("请先阅读并同意服务条款和隐私政策", "warning");
return;
}
// TODO: 实现登录逻辑
console.log("登录", { phoneNumber: phoneNumber.value, password: password.value });
const result = LoginSchema.safeParse({ ...form.value });
if (!result.success) {
const first = result.error.issues[0];
await showToast(first.message);
return;
}
isLoading.value = true;
try {
const { data } = await safeClient(authClient.signIn.username({
username: form.value.phoneNumber,
password: form.value.password,
}));
if (!data.value?.token) {
toastController.create({
message: "登录失败,请检查手机号或密码",
duration: 2000,
color: "danger",
}).then(toast => toast.present());
}
else {
const userStore = useUserStore();
userStore.setToken(data.value.token);
await userStore.updateProfile();
await showToast("登录成功!", "success");
router.push(route.query.redirect as string || "/");
}
}
finally {
isLoading.value = false;
}
}
function handleSignup() {
@@ -71,7 +113,7 @@ function goToTerms(type: "service" | "privacy") {
<!-- 手机号输入 -->
<ion-item lines="none" class="input-item">
<ion-input
v-model="phoneNumber"
v-model="form.phoneNumber"
type="tel"
placeholder="请输入手机号"
class="custom-input"
@@ -82,7 +124,7 @@ function goToTerms(type: "service" | "privacy") {
<!-- 密码输入 -->
<ion-item lines="none" class="input-item">
<ion-input
v-model="password"
v-model="form.password"
:type="showPassword ? 'text' : 'password'"
placeholder="请输入密码"
class="custom-input"
@@ -110,9 +152,11 @@ function goToTerms(type: "service" | "privacy") {
<ion-button
expand="block"
class="login-button mt-2"
:disabled="isLoading"
@click="handleLogin"
>
登录
<ion-spinner v-if="isLoading" name="crescent" class="mr-2" />
{{ isLoading ? '登录中...' : '登录' }}
</ion-button>
<!-- 注册按钮 -->