feat: 大部分注册登录功能

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
2026-04-24 18:02:42 +08:00
parent 5ab74ad9dd
commit 5294528148
23 changed files with 858 additions and 167 deletions
+188
View File
@@ -0,0 +1,188 @@
<script setup lang="ts">
import { reactive, ref } from "vue";
import type {
ICommonResponse,
IUserRegisterData,
IUserRegisterRequest
} from "#shared/types";
import { useUserStore } from "~/stores";
type FormRef = {
validate: () => Promise<boolean>;
resetFields: () => void;
};
type RegisterForm = Required<
Pick<IUserRegisterRequest, "username" | "password" | "email">
> &
Pick<IUserRegisterRequest, "verification_code" | "aff_code"> & {
confirmPassword: string;
};
const emit = defineEmits<{
success: [response: ICommonResponse<IUserRegisterData>];
}>();
const route = useRoute();
const router = useRouter();
const userStore = useUserStore();
const formRef = ref<FormRef>();
const form = reactive<RegisterForm>({
username: "",
password: "",
confirmPassword: "",
email: "",
verification_code: "",
aff_code: ""
});
const validateConfirmPassword = (
_rule: unknown,
value: string,
callback: (error?: Error) => void
) => {
if (!value) {
callback(new Error("请再次输入密码"));
return;
}
if (value !== form.password) {
callback(new Error("两次输入的密码不一致"));
return;
}
callback();
};
const rules = {
username: [{ required: true, message: "请输入用户名", trigger: "blur" }],
email: [
{ required: true, message: "请输入邮箱", trigger: "blur" },
{ type: "email", message: "邮箱格式不正确", trigger: ["blur", "change"] }
],
password: [
{ required: true, message: "请输入密码", trigger: "blur" },
{ min: 6, message: "密码至少 6 位", trigger: "blur" }
],
confirmPassword: [{ validator: validateConfirmPassword, trigger: "blur" }]
};
const submit = async () => {
const valid = await formRef.value?.validate().catch(() => false);
if (!valid) return;
const payload: IUserRegisterRequest = {
username: form.username.trim(),
password: form.password,
email: form.email.trim()
};
if (form.verification_code?.trim()) {
payload.verification_code = form.verification_code.trim();
}
if (form.aff_code?.trim()) {
payload.aff_code = form.aff_code.trim();
}
const response = await userStore.register(payload);
if (response?.code === 0) {
emit("success", response);
}
};
const resetForm = () => {
formRef.value?.resetFields();
};
const goToLogin = () => {
const { _loginAction, ...query } = route.query;
router.replace({ query });
};
defineExpose({
resetForm
});
</script>
<template>
<div class="w-full max-w-sm">
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-position="top"
@submit.prevent="submit"
>
<el-form-item label="用户名" prop="username">
<el-input
v-model="form.username"
autocomplete="username"
placeholder="请输入用户名"
size="large"
/>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input
v-model="form.email"
autocomplete="email"
placeholder="请输入邮箱"
size="large"
/>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input
v-model="form.password"
autocomplete="new-password"
placeholder="请输入密码"
show-password
size="large"
type="password"
/>
</el-form-item>
<el-form-item label="确认密码" prop="confirmPassword">
<el-input
v-model="form.confirmPassword"
autocomplete="new-password"
placeholder="请再次输入密码"
show-password
size="large"
type="password"
@keyup.enter="submit"
/>
</el-form-item>
<el-form-item label="邮箱验证码" prop="verification_code">
<el-input
v-model="form.verification_code"
placeholder="如需验证请填写"
size="large"
/>
</el-form-item>
<el-form-item label="邀请码" prop="aff_code">
<el-input v-model="form.aff_code" placeholder="选填" size="large" />
</el-form-item>
<el-button
class="w-full"
native-type="submit"
size="large"
type="primary"
:loading="userStore.registerLoading"
>
注册
</el-button>
</el-form>
<div class="mt-4 text-center text-sm">
已有账户
<span class="cursor-pointer text-blue-600" @click="goToLogin">登录</span>
</div>
</div>
</template>