mirror of
https://github.com/jiangrui1994/CloudSaver.git
synced 2026-01-10 15:18:46 +08:00
feat:移动端增加注册模块
This commit is contained in:
3
frontend/components.d.ts
vendored
3
frontend/components.d.ts
vendored
@@ -50,12 +50,15 @@ declare module 'vue' {
|
||||
VanCheckbox: typeof import('vant/es')['Checkbox']
|
||||
VanCheckboxGroup: typeof import('vant/es')['CheckboxGroup']
|
||||
VanEmpty: typeof import('vant/es')['Empty']
|
||||
VanField: typeof import('vant/es')['Field']
|
||||
VanForm: typeof import('vant/es')['Form']
|
||||
VanIcon: typeof import('vant/es')['Icon']
|
||||
VanImage: typeof import('vant/es')['Image']
|
||||
VanLoading: typeof import('vant/es')['Loading']
|
||||
VanOverlay: typeof import('vant/es')['Overlay']
|
||||
VanPopup: typeof import('vant/es')['Popup']
|
||||
VanSearch: typeof import('vant/es')['Search']
|
||||
VanSwitch: typeof import('vant/es')['Switch']
|
||||
VanTab: typeof import('vant/es')['Tab']
|
||||
VanTabbar: typeof import('vant/es')['Tabbar']
|
||||
VanTabbarItem: typeof import('vant/es')['TabbarItem']
|
||||
|
||||
@@ -11,64 +11,140 @@
|
||||
<h1 class="login__title">Cloud Saver</h1>
|
||||
</header>
|
||||
|
||||
<!-- 登录表单 -->
|
||||
<van-form class="login__form" @submit="handleSubmit">
|
||||
<van-cell-group inset class="login__form-group">
|
||||
<!-- 用户名输入框 -->
|
||||
<van-field
|
||||
v-model="formData.username"
|
||||
name="username"
|
||||
label="用户名"
|
||||
placeholder="请输入用户名"
|
||||
:rules="[{ required: true, message: '请填写用户名' }]"
|
||||
autocomplete="username"
|
||||
@keyup.enter="focusPassword"
|
||||
>
|
||||
<template #left-icon>
|
||||
<van-icon name="user-o" />
|
||||
</template>
|
||||
</van-field>
|
||||
<!-- 添加 Tab 切换 -->
|
||||
<van-tabs v-model:active="activeTab" class="login__tabs">
|
||||
<!-- 登录面板 -->
|
||||
<van-tab title="登录" name="login">
|
||||
<van-form class="login__form" @submit="handleLogin">
|
||||
<van-cell-group inset class="login__form-group">
|
||||
<!-- 用户名输入框 -->
|
||||
<van-field
|
||||
v-model="loginForm.username"
|
||||
name="username"
|
||||
label="用户名"
|
||||
placeholder="请输入用户名"
|
||||
:rules="[{ required: true, message: '请填写用户名' }]"
|
||||
autocomplete="username"
|
||||
@keyup.enter="focusLoginPassword"
|
||||
>
|
||||
<template #left-icon>
|
||||
<van-icon name="user-o" />
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<!-- 密码输入框 -->
|
||||
<van-field
|
||||
ref="passwordRef"
|
||||
v-model="formData.password"
|
||||
type="password"
|
||||
name="password"
|
||||
label="密码"
|
||||
placeholder="请输入密码"
|
||||
:rules="[{ required: true, message: '请填写密码' }]"
|
||||
autocomplete="current-password"
|
||||
@keyup.enter="handleSubmit"
|
||||
>
|
||||
<template #left-icon>
|
||||
<van-icon name="lock" />
|
||||
</template>
|
||||
</van-field>
|
||||
<!-- 密码输入框 -->
|
||||
<van-field
|
||||
ref="loginPasswordRef"
|
||||
v-model="loginForm.password"
|
||||
type="password"
|
||||
name="password"
|
||||
label="密码"
|
||||
placeholder="请输入密码"
|
||||
:rules="[{ required: true, message: '请填写密码' }]"
|
||||
autocomplete="current-password"
|
||||
@keyup.enter="handleLogin"
|
||||
>
|
||||
<template #left-icon>
|
||||
<van-icon name="lock" />
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<!-- 优化记住密码选项 -->
|
||||
<div class="login__remember">
|
||||
<van-checkbox v-model="rememberPassword" class="remember-checkbox">
|
||||
记住密码
|
||||
</van-checkbox>
|
||||
</div>
|
||||
</van-cell-group>
|
||||
<!-- 优化记住密码选项 -->
|
||||
<div class="login__remember">
|
||||
<van-checkbox v-model="rememberPassword" class="remember-checkbox">
|
||||
记住密码
|
||||
</van-checkbox>
|
||||
</div>
|
||||
</van-cell-group>
|
||||
|
||||
<!-- 登录按钮 -->
|
||||
<div class="login__submit">
|
||||
<van-button
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
round
|
||||
block
|
||||
type="primary"
|
||||
native-type="submit"
|
||||
class="login__button"
|
||||
>
|
||||
{{ isLoading ? "登录中..." : "登录" }}
|
||||
</van-button>
|
||||
</div>
|
||||
</van-form>
|
||||
<!-- 登录按钮 -->
|
||||
<div class="login__submit">
|
||||
<van-button
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
round
|
||||
block
|
||||
type="primary"
|
||||
native-type="submit"
|
||||
class="login__button"
|
||||
>
|
||||
{{ isLoading ? "登录中..." : "登录" }}
|
||||
</van-button>
|
||||
</div>
|
||||
</van-form>
|
||||
</van-tab>
|
||||
|
||||
<!-- 注册面板 -->
|
||||
<van-tab title="注册" name="register">
|
||||
<van-form class="login__form" @submit="handleRegister">
|
||||
<van-cell-group inset class="login__form-group">
|
||||
<van-field
|
||||
v-model="registerForm.username"
|
||||
name="username"
|
||||
label="用户名"
|
||||
placeholder="请输入用户名"
|
||||
:rules="usernameRules"
|
||||
>
|
||||
<template #left-icon>
|
||||
<van-icon name="user-o" />
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<van-field
|
||||
v-model="registerForm.password"
|
||||
type="password"
|
||||
name="password"
|
||||
label="密码"
|
||||
placeholder="请输入密码"
|
||||
:rules="passwordRules"
|
||||
>
|
||||
<template #left-icon>
|
||||
<van-icon name="lock" />
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<van-field
|
||||
v-model="registerForm.confirmPassword"
|
||||
type="password"
|
||||
name="confirmPassword"
|
||||
label="确认密码"
|
||||
placeholder="请确认密码"
|
||||
:rules="confirmPasswordRules"
|
||||
>
|
||||
<template #left-icon>
|
||||
<van-icon name="lock" />
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<van-field
|
||||
v-model="registerForm.registerCode"
|
||||
name="registerCode"
|
||||
label="注册码"
|
||||
placeholder="请输入注册码"
|
||||
:rules="registerCodeRules"
|
||||
>
|
||||
<template #left-icon>
|
||||
<van-icon name="certificate" />
|
||||
</template>
|
||||
</van-field>
|
||||
</van-cell-group>
|
||||
|
||||
<div class="login__submit">
|
||||
<van-button
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
round
|
||||
block
|
||||
type="primary"
|
||||
native-type="submit"
|
||||
class="login__button"
|
||||
>
|
||||
{{ isLoading ? "注册中..." : "注册" }}
|
||||
</van-button>
|
||||
</div>
|
||||
</van-form>
|
||||
</van-tab>
|
||||
</van-tabs>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
@@ -77,7 +153,7 @@
|
||||
import { ref, onMounted } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { showNotify } from "vant";
|
||||
import type { FieldInstance } from "vant";
|
||||
import type { FieldInstance, FieldRule } from "vant";
|
||||
import { userApi } from "@/api/user";
|
||||
import logo from "@/assets/images/logo.png";
|
||||
import { STORAGE_KEYS } from "@/constants/storage";
|
||||
@@ -88,21 +164,42 @@ interface LoginForm {
|
||||
password: string;
|
||||
}
|
||||
|
||||
interface RegisterForm {
|
||||
username: string;
|
||||
password: string;
|
||||
confirmPassword: string;
|
||||
registerCode: string;
|
||||
}
|
||||
|
||||
// 响应式数据
|
||||
const formData = ref<LoginForm>({
|
||||
const activeTab = ref("login");
|
||||
const isLoading = ref(false);
|
||||
const loginPasswordRef = ref<FieldInstance>();
|
||||
const rememberPassword = ref(false);
|
||||
|
||||
const loginForm = ref<LoginForm>({
|
||||
username: "",
|
||||
password: "",
|
||||
});
|
||||
const isLoading = ref(false);
|
||||
const passwordRef = ref<FieldInstance>();
|
||||
const rememberPassword = ref(false);
|
||||
|
||||
const registerForm = ref<RegisterForm>({
|
||||
username: "",
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
registerCode: "",
|
||||
});
|
||||
|
||||
// 工具函数
|
||||
const router = useRouter();
|
||||
|
||||
// 方法定义
|
||||
const focusPassword = () => {
|
||||
passwordRef.value?.focus();
|
||||
const focusLoginPassword = () => {
|
||||
loginPasswordRef.value?.focus();
|
||||
};
|
||||
|
||||
// 表单验证
|
||||
const validateConfirmPassword = (value: string) => {
|
||||
return value === registerForm.value.password;
|
||||
};
|
||||
|
||||
// 在组件加载时检查是否有保存的账号密码
|
||||
@@ -110,22 +207,22 @@ onMounted(() => {
|
||||
const savedUsername = localStorage.getItem(STORAGE_KEYS.USERNAME);
|
||||
const savedPassword = localStorage.getItem(STORAGE_KEYS.PASSWORD);
|
||||
if (savedUsername && savedPassword) {
|
||||
formData.value.username = savedUsername;
|
||||
formData.value.password = savedPassword;
|
||||
loginForm.value.username = savedUsername;
|
||||
loginForm.value.password = savedPassword;
|
||||
rememberPassword.value = true;
|
||||
}
|
||||
});
|
||||
|
||||
const handleSubmit = async () => {
|
||||
// 登录处理
|
||||
const handleLogin = async () => {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
const res = await userApi.login(formData.value);
|
||||
const res = await userApi.login(loginForm.value);
|
||||
|
||||
if (res.code === 0) {
|
||||
// 处理记住密码
|
||||
if (rememberPassword.value) {
|
||||
localStorage.setItem(STORAGE_KEYS.USERNAME, formData.value.username);
|
||||
localStorage.setItem(STORAGE_KEYS.PASSWORD, formData.value.password);
|
||||
localStorage.setItem(STORAGE_KEYS.USERNAME, loginForm.value.username);
|
||||
localStorage.setItem(STORAGE_KEYS.PASSWORD, loginForm.value.password);
|
||||
} else {
|
||||
localStorage.removeItem(STORAGE_KEYS.USERNAME);
|
||||
localStorage.removeItem(STORAGE_KEYS.PASSWORD);
|
||||
@@ -134,22 +231,65 @@ const handleSubmit = async () => {
|
||||
localStorage.setItem(STORAGE_KEYS.TOKEN, res.data.token);
|
||||
await router.push("/");
|
||||
} else {
|
||||
showNotify({
|
||||
type: "danger",
|
||||
message: res.message || "登录失败",
|
||||
duration: 2000,
|
||||
});
|
||||
showNotify({ type: "danger", message: res.message || "登录失败" });
|
||||
}
|
||||
} catch (error) {
|
||||
showNotify({
|
||||
type: "danger",
|
||||
message: "登录失败",
|
||||
duration: 2000,
|
||||
});
|
||||
showNotify({ type: "danger", message: "登录失败" });
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 注册处理
|
||||
const handleRegister = async () => {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
const res = await userApi.register({
|
||||
username: registerForm.value.username,
|
||||
password: registerForm.value.password,
|
||||
registerCode: registerForm.value.registerCode,
|
||||
});
|
||||
|
||||
if (res.code === 0) {
|
||||
showNotify({ type: "success", message: "注册成功" });
|
||||
// 自动填充登录表单
|
||||
loginForm.value.username = registerForm.value.username;
|
||||
loginForm.value.password = registerForm.value.password;
|
||||
activeTab.value = "login";
|
||||
// 清空注册表单
|
||||
registerForm.value = {
|
||||
username: "",
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
registerCode: "",
|
||||
};
|
||||
} else {
|
||||
showNotify({ type: "danger", message: res.message || "注册失败" });
|
||||
}
|
||||
} catch (error) {
|
||||
showNotify({ type: "danger", message: "注册失败" });
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 定义验证规则
|
||||
const usernameRules: FieldRule[] = [
|
||||
{ required: true, message: "请填写用户名" },
|
||||
{ pattern: /.{3,}/, message: "用户名至少3个字符" },
|
||||
];
|
||||
|
||||
const passwordRules: FieldRule[] = [
|
||||
{ required: true, message: "请填写密码" },
|
||||
{ pattern: /.{6,}/, message: "密码至少6个字符" },
|
||||
];
|
||||
|
||||
const confirmPasswordRules: FieldRule[] = [
|
||||
{ required: true, message: "请确认密码" },
|
||||
{ validator: validateConfirmPassword, message: "两次密码不一致" },
|
||||
];
|
||||
|
||||
const registerCodeRules: FieldRule[] = [{ required: true, message: "请填写注册码" }];
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -231,6 +371,32 @@ const handleSubmit = async () => {
|
||||
padding: 12px 16px;
|
||||
border-top: 0.5px solid #f5f5f5;
|
||||
}
|
||||
|
||||
&__tabs {
|
||||
:deep() {
|
||||
.van-tabs__wrap {
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.van-tabs__nav {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.van-tab {
|
||||
color: var(--theme-color);
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.van-tab--active {
|
||||
color: var(--theme-theme);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.van-tabs__line {
|
||||
background-color: var(--theme-theme);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Vant 组件样式优化
|
||||
|
||||
Reference in New Issue
Block a user