feat: 添加注册界面
This commit is contained in:
288
src/views/AuthView.vue
Normal file
288
src/views/AuthView.vue
Normal file
@@ -0,0 +1,288 @@
|
||||
<template>
|
||||
<div class="flex items-center justify-center min-h-screen bg-base-200">
|
||||
<div class="relative w-full max-w-md">
|
||||
<!-- Login Card -->
|
||||
<div v-if="!showSignUp" class="card card-dash h-80 w-100 shadow-xl bg-base-100">
|
||||
<div class="card-body">
|
||||
<h1 class="card-title place-self-center my-3 text-2xl">用户登录</h1>
|
||||
<div class="flex flex-col w-full h-full">
|
||||
<label class="input w-full my-3">
|
||||
<User class="h-[1em] opacity-50" />
|
||||
<input
|
||||
type="text"
|
||||
class="grow"
|
||||
placeholder="用户名"
|
||||
v-model="username"
|
||||
@keyup.enter="handleLogin"
|
||||
/>
|
||||
</label>
|
||||
<label class="input w-full my-3">
|
||||
<Lock class="h-[1em] opacity-50" />
|
||||
<input
|
||||
type="password"
|
||||
class="grow"
|
||||
placeholder="密码"
|
||||
v-model="password"
|
||||
@keyup.enter="handleLogin"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex justify-end mx-3">
|
||||
<RouterLink to="/">忘记密码?</RouterLink>
|
||||
</div>
|
||||
<div class="card-actions flex items-end my-3">
|
||||
<button class="btn flex-1" @click="handleRegister">注册</button>
|
||||
<button
|
||||
class="btn btn-primary flex-3"
|
||||
@click="handleLogin"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
{{ isLoading ? "登录中..." : "登录" }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sign Up Card -->
|
||||
<div v-if="showSignUp" class="card card-dash h-96 w-100 shadow-xl bg-base-100">
|
||||
<div class="card-body">
|
||||
<h1 class="card-title place-self-center my-3 text-2xl">用户注册</h1>
|
||||
<div class="flex flex-col w-full h-full">
|
||||
<label class="input w-full my-2">
|
||||
<User class="h-[1em] opacity-50" />
|
||||
<input
|
||||
type="text"
|
||||
class="grow"
|
||||
placeholder="用户名"
|
||||
v-model="signUpData.username"
|
||||
@keyup.enter="handleSignUp"
|
||||
/>
|
||||
</label>
|
||||
<label class="input w-full my-2">
|
||||
<Mail class="h-[1em] opacity-50" />
|
||||
<input
|
||||
type="email"
|
||||
class="grow"
|
||||
placeholder="邮箱"
|
||||
v-model="signUpData.email"
|
||||
@keyup.enter="handleSignUp"
|
||||
/>
|
||||
</label>
|
||||
<label class="input w-full my-2">
|
||||
<Lock class="h-[1em] opacity-50" />
|
||||
<input
|
||||
type="password"
|
||||
class="grow"
|
||||
placeholder="密码"
|
||||
v-model="signUpData.password"
|
||||
@keyup.enter="handleSignUp"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div class="card-actions flex items-end my-3">
|
||||
<button class="btn flex-1" @click="backToLogin">返回登录</button>
|
||||
<button
|
||||
class="btn btn-primary flex-3"
|
||||
@click="handleSignUp"
|
||||
:disabled="isSignUpLoading"
|
||||
>
|
||||
{{ isSignUpLoading ? "注册中..." : "注册" }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { AuthManager } from "@/utils/AuthManager";
|
||||
import { useAlertStore } from "@/components/Alert";
|
||||
import { User, Lock, Mail } from "lucide-vue-next";
|
||||
import { DataClient } from "@/APIClient";
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
// 获取Alert store
|
||||
const alertStore = useAlertStore();
|
||||
|
||||
// 创建API客户端实例
|
||||
const dataClient = new DataClient();
|
||||
|
||||
// 响应式数据
|
||||
const username = ref("");
|
||||
const password = ref("");
|
||||
const isLoading = ref(false);
|
||||
|
||||
// 注册相关数据
|
||||
const showSignUp = ref(false);
|
||||
const isSignUpLoading = ref(false);
|
||||
const signUpData = ref({
|
||||
username: "",
|
||||
email: "",
|
||||
password: ""
|
||||
});
|
||||
|
||||
// 登录处理函数
|
||||
const handleLogin = async () => {
|
||||
// 验证输入
|
||||
if (!username.value.trim()) {
|
||||
alertStore?.show("请输入用户名", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!password.value.trim()) {
|
||||
alertStore?.show("请输入密码", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
isLoading.value = true;
|
||||
|
||||
try {
|
||||
// 调用AuthManager的登录函数
|
||||
await AuthManager.login(username.value.trim(), password.value.trim());
|
||||
|
||||
// 登录成功,显示成功消息并跳转
|
||||
alertStore?.show("登录成功", "success", 1000);
|
||||
|
||||
// 短暂延迟后跳转到project页面
|
||||
setTimeout(async () => {
|
||||
await router.push("/project");
|
||||
}, 1000);
|
||||
} catch (error: any) {
|
||||
console.error("Login error:", error);
|
||||
|
||||
// 处理不同类型的错误
|
||||
let errorMessage = "登录失败,请检查网络连接";
|
||||
|
||||
if (error.status === 400) {
|
||||
errorMessage = "用户名或密码错误";
|
||||
} else if (error.status === 401) {
|
||||
errorMessage = "用户名或密码错误";
|
||||
} else if (error.status === 500) {
|
||||
errorMessage = "服务器错误,请稍后重试";
|
||||
} else if (error.message) {
|
||||
errorMessage = error.message;
|
||||
}
|
||||
|
||||
alertStore?.show(errorMessage, "error");
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 注册处理函数
|
||||
const handleRegister = () => {
|
||||
showSignUp.value = true;
|
||||
// 清空注册表单
|
||||
signUpData.value = {
|
||||
username: "",
|
||||
email: "",
|
||||
password: ""
|
||||
};
|
||||
};
|
||||
|
||||
// 返回登录页面
|
||||
const backToLogin = () => {
|
||||
showSignUp.value = false;
|
||||
};
|
||||
|
||||
// 注册提交处理函数
|
||||
const handleSignUp = async () => {
|
||||
// 验证输入
|
||||
if (!signUpData.value.username.trim()) {
|
||||
alertStore?.show("请输入用户名", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!signUpData.value.email.trim()) {
|
||||
alertStore?.show("请输入邮箱", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
// 简单的邮箱格式验证
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(signUpData.value.email.trim())) {
|
||||
alertStore?.show("请输入有效的邮箱地址", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!signUpData.value.password.trim()) {
|
||||
alertStore?.show("请输入密码", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
// 密码长度验证
|
||||
if (signUpData.value.password.length < 6) {
|
||||
alertStore?.show("密码长度至少6位", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
isSignUpLoading.value = true;
|
||||
|
||||
try {
|
||||
// 调用注册API
|
||||
const result = await dataClient.signUpUser(
|
||||
signUpData.value.username.trim(),
|
||||
signUpData.value.email.trim(),
|
||||
signUpData.value.password.trim()
|
||||
);
|
||||
|
||||
if (result) {
|
||||
// 注册成功
|
||||
alertStore?.show("注册成功!请登录", "success", 2000);
|
||||
|
||||
// 延迟后返回登录页面
|
||||
setTimeout(() => {
|
||||
backToLogin();
|
||||
}, 2000);
|
||||
} else {
|
||||
alertStore?.show("注册失败,请重试", "error");
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error("Sign up error:", error);
|
||||
|
||||
let errorMessage = "注册失败,请检查网络连接";
|
||||
|
||||
if (error.status === 400) {
|
||||
// 检查是否有详细的错误信息
|
||||
if (error.result && error.result.detail) {
|
||||
errorMessage = error.result.detail;
|
||||
} else {
|
||||
errorMessage = "注册信息无效,请检查输入";
|
||||
}
|
||||
} else if (error.status === 500) {
|
||||
errorMessage = "服务器错误,请稍后重试";
|
||||
} else if (error.message) {
|
||||
errorMessage = error.message;
|
||||
}
|
||||
|
||||
alertStore?.show(errorMessage, "error");
|
||||
} finally {
|
||||
isSignUpLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 页面初始化时检查是否已有有效token
|
||||
const checkExistingToken = async () => {
|
||||
try {
|
||||
const isValid = await AuthManager.verifyToken();
|
||||
if (isValid) {
|
||||
// 如果token仍然有效,直接跳转到project页面
|
||||
await router.push("/project");
|
||||
}
|
||||
} catch (error) {
|
||||
// token无效或验证失败,继续显示登录页面
|
||||
console.log("Token verification failed, showing login page");
|
||||
}
|
||||
};
|
||||
|
||||
// 组件挂载时检查已存在的token
|
||||
onMounted(() => {
|
||||
checkExistingToken();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
Reference in New Issue
Block a user