mirror of
https://github.com/jiangrui1994/CloudSaver.git
synced 2026-01-11 07:38:45 +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']
|
VanCheckbox: typeof import('vant/es')['Checkbox']
|
||||||
VanCheckboxGroup: typeof import('vant/es')['CheckboxGroup']
|
VanCheckboxGroup: typeof import('vant/es')['CheckboxGroup']
|
||||||
VanEmpty: typeof import('vant/es')['Empty']
|
VanEmpty: typeof import('vant/es')['Empty']
|
||||||
|
VanField: typeof import('vant/es')['Field']
|
||||||
|
VanForm: typeof import('vant/es')['Form']
|
||||||
VanIcon: typeof import('vant/es')['Icon']
|
VanIcon: typeof import('vant/es')['Icon']
|
||||||
VanImage: typeof import('vant/es')['Image']
|
VanImage: typeof import('vant/es')['Image']
|
||||||
VanLoading: typeof import('vant/es')['Loading']
|
VanLoading: typeof import('vant/es')['Loading']
|
||||||
VanOverlay: typeof import('vant/es')['Overlay']
|
VanOverlay: typeof import('vant/es')['Overlay']
|
||||||
VanPopup: typeof import('vant/es')['Popup']
|
VanPopup: typeof import('vant/es')['Popup']
|
||||||
VanSearch: typeof import('vant/es')['Search']
|
VanSearch: typeof import('vant/es')['Search']
|
||||||
|
VanSwitch: typeof import('vant/es')['Switch']
|
||||||
VanTab: typeof import('vant/es')['Tab']
|
VanTab: typeof import('vant/es')['Tab']
|
||||||
VanTabbar: typeof import('vant/es')['Tabbar']
|
VanTabbar: typeof import('vant/es')['Tabbar']
|
||||||
VanTabbarItem: typeof import('vant/es')['TabbarItem']
|
VanTabbarItem: typeof import('vant/es')['TabbarItem']
|
||||||
|
|||||||
@@ -11,64 +11,140 @@
|
|||||||
<h1 class="login__title">Cloud Saver</h1>
|
<h1 class="login__title">Cloud Saver</h1>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<!-- 登录表单 -->
|
<!-- 添加 Tab 切换 -->
|
||||||
<van-form class="login__form" @submit="handleSubmit">
|
<van-tabs v-model:active="activeTab" class="login__tabs">
|
||||||
<van-cell-group inset class="login__form-group">
|
<!-- 登录面板 -->
|
||||||
<!-- 用户名输入框 -->
|
<van-tab title="登录" name="login">
|
||||||
<van-field
|
<van-form class="login__form" @submit="handleLogin">
|
||||||
v-model="formData.username"
|
<van-cell-group inset class="login__form-group">
|
||||||
name="username"
|
<!-- 用户名输入框 -->
|
||||||
label="用户名"
|
<van-field
|
||||||
placeholder="请输入用户名"
|
v-model="loginForm.username"
|
||||||
:rules="[{ required: true, message: '请填写用户名' }]"
|
name="username"
|
||||||
autocomplete="username"
|
label="用户名"
|
||||||
@keyup.enter="focusPassword"
|
placeholder="请输入用户名"
|
||||||
>
|
:rules="[{ required: true, message: '请填写用户名' }]"
|
||||||
<template #left-icon>
|
autocomplete="username"
|
||||||
<van-icon name="user-o" />
|
@keyup.enter="focusLoginPassword"
|
||||||
</template>
|
>
|
||||||
</van-field>
|
<template #left-icon>
|
||||||
|
<van-icon name="user-o" />
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
|
||||||
<!-- 密码输入框 -->
|
<!-- 密码输入框 -->
|
||||||
<van-field
|
<van-field
|
||||||
ref="passwordRef"
|
ref="loginPasswordRef"
|
||||||
v-model="formData.password"
|
v-model="loginForm.password"
|
||||||
type="password"
|
type="password"
|
||||||
name="password"
|
name="password"
|
||||||
label="密码"
|
label="密码"
|
||||||
placeholder="请输入密码"
|
placeholder="请输入密码"
|
||||||
:rules="[{ required: true, message: '请填写密码' }]"
|
:rules="[{ required: true, message: '请填写密码' }]"
|
||||||
autocomplete="current-password"
|
autocomplete="current-password"
|
||||||
@keyup.enter="handleSubmit"
|
@keyup.enter="handleLogin"
|
||||||
>
|
>
|
||||||
<template #left-icon>
|
<template #left-icon>
|
||||||
<van-icon name="lock" />
|
<van-icon name="lock" />
|
||||||
</template>
|
</template>
|
||||||
</van-field>
|
</van-field>
|
||||||
|
|
||||||
<!-- 优化记住密码选项 -->
|
<!-- 优化记住密码选项 -->
|
||||||
<div class="login__remember">
|
<div class="login__remember">
|
||||||
<van-checkbox v-model="rememberPassword" class="remember-checkbox">
|
<van-checkbox v-model="rememberPassword" class="remember-checkbox">
|
||||||
记住密码
|
记住密码
|
||||||
</van-checkbox>
|
</van-checkbox>
|
||||||
</div>
|
</div>
|
||||||
</van-cell-group>
|
</van-cell-group>
|
||||||
|
|
||||||
<!-- 登录按钮 -->
|
<!-- 登录按钮 -->
|
||||||
<div class="login__submit">
|
<div class="login__submit">
|
||||||
<van-button
|
<van-button
|
||||||
:loading="isLoading"
|
:loading="isLoading"
|
||||||
:disabled="isLoading"
|
:disabled="isLoading"
|
||||||
round
|
round
|
||||||
block
|
block
|
||||||
type="primary"
|
type="primary"
|
||||||
native-type="submit"
|
native-type="submit"
|
||||||
class="login__button"
|
class="login__button"
|
||||||
>
|
>
|
||||||
{{ isLoading ? "登录中..." : "登录" }}
|
{{ isLoading ? "登录中..." : "登录" }}
|
||||||
</van-button>
|
</van-button>
|
||||||
</div>
|
</div>
|
||||||
</van-form>
|
</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>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -77,7 +153,7 @@
|
|||||||
import { ref, onMounted } from "vue";
|
import { ref, onMounted } from "vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { showNotify } from "vant";
|
import { showNotify } from "vant";
|
||||||
import type { FieldInstance } from "vant";
|
import type { FieldInstance, FieldRule } from "vant";
|
||||||
import { userApi } from "@/api/user";
|
import { userApi } from "@/api/user";
|
||||||
import logo from "@/assets/images/logo.png";
|
import logo from "@/assets/images/logo.png";
|
||||||
import { STORAGE_KEYS } from "@/constants/storage";
|
import { STORAGE_KEYS } from "@/constants/storage";
|
||||||
@@ -88,21 +164,42 @@ interface LoginForm {
|
|||||||
password: string;
|
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: "",
|
username: "",
|
||||||
password: "",
|
password: "",
|
||||||
});
|
});
|
||||||
const isLoading = ref(false);
|
|
||||||
const passwordRef = ref<FieldInstance>();
|
const registerForm = ref<RegisterForm>({
|
||||||
const rememberPassword = ref(false);
|
username: "",
|
||||||
|
password: "",
|
||||||
|
confirmPassword: "",
|
||||||
|
registerCode: "",
|
||||||
|
});
|
||||||
|
|
||||||
// 工具函数
|
// 工具函数
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
// 方法定义
|
// 方法定义
|
||||||
const focusPassword = () => {
|
const focusLoginPassword = () => {
|
||||||
passwordRef.value?.focus();
|
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 savedUsername = localStorage.getItem(STORAGE_KEYS.USERNAME);
|
||||||
const savedPassword = localStorage.getItem(STORAGE_KEYS.PASSWORD);
|
const savedPassword = localStorage.getItem(STORAGE_KEYS.PASSWORD);
|
||||||
if (savedUsername && savedPassword) {
|
if (savedUsername && savedPassword) {
|
||||||
formData.value.username = savedUsername;
|
loginForm.value.username = savedUsername;
|
||||||
formData.value.password = savedPassword;
|
loginForm.value.password = savedPassword;
|
||||||
rememberPassword.value = true;
|
rememberPassword.value = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
// 登录处理
|
||||||
|
const handleLogin = async () => {
|
||||||
try {
|
try {
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
const res = await userApi.login(formData.value);
|
const res = await userApi.login(loginForm.value);
|
||||||
|
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
// 处理记住密码
|
|
||||||
if (rememberPassword.value) {
|
if (rememberPassword.value) {
|
||||||
localStorage.setItem(STORAGE_KEYS.USERNAME, formData.value.username);
|
localStorage.setItem(STORAGE_KEYS.USERNAME, loginForm.value.username);
|
||||||
localStorage.setItem(STORAGE_KEYS.PASSWORD, formData.value.password);
|
localStorage.setItem(STORAGE_KEYS.PASSWORD, loginForm.value.password);
|
||||||
} else {
|
} else {
|
||||||
localStorage.removeItem(STORAGE_KEYS.USERNAME);
|
localStorage.removeItem(STORAGE_KEYS.USERNAME);
|
||||||
localStorage.removeItem(STORAGE_KEYS.PASSWORD);
|
localStorage.removeItem(STORAGE_KEYS.PASSWORD);
|
||||||
@@ -134,22 +231,65 @@ const handleSubmit = async () => {
|
|||||||
localStorage.setItem(STORAGE_KEYS.TOKEN, res.data.token);
|
localStorage.setItem(STORAGE_KEYS.TOKEN, res.data.token);
|
||||||
await router.push("/");
|
await router.push("/");
|
||||||
} else {
|
} else {
|
||||||
showNotify({
|
showNotify({ type: "danger", message: res.message || "登录失败" });
|
||||||
type: "danger",
|
|
||||||
message: res.message || "登录失败",
|
|
||||||
duration: 2000,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showNotify({
|
showNotify({ type: "danger", message: "登录失败" });
|
||||||
type: "danger",
|
|
||||||
message: "登录失败",
|
|
||||||
duration: 2000,
|
|
||||||
});
|
|
||||||
} finally {
|
} finally {
|
||||||
isLoading.value = false;
|
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>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -231,6 +371,32 @@ const handleSubmit = async () => {
|
|||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
border-top: 0.5px solid #f5f5f5;
|
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 组件样式优化
|
// Vant 组件样式优化
|
||||||
|
|||||||
Reference in New Issue
Block a user