Files
lanecarford_front/src/views/login/LoginPage.vue

334 lines
7.6 KiB
Vue
Raw Normal View History

<template>
<div class="login-page">
<div class="content">
<div class="back-button" @click="goBack">
2025-12-23 15:52:20 +08:00
<SvgIcon name="left" size="50" color="#fff" />
</div>
<div class="header">
2025-12-23 15:52:20 +08:00
<div class="title">Staff Login.</div>
<p class="subtitle">
<span>Experience our personalised styling journey with</span>
<br />
<span>Lane Crawford.</span>
</p>
</div>
<div class="login-container">
2025-10-22 14:03:57 +08:00
<div class="login-form">
<div class="input-group">
2025-10-22 14:03:57 +08:00
<input type="email" v-model="formData.email" placeholder="Email" class="input-field" />
</div>
<div class="input-group pwd">
<input
type="password"
v-model="formData.password"
placeholder="Your Password"
class="input-field"
/>
</div>
2025-10-22 14:03:57 +08:00
<div class="login-button" @click="handleLogin">Log in</div>
<div class="forgot-password" @click="handleForgotPassword">Forgot password?</div>
2025-11-04 16:47:17 +08:00
<!-- <div type="button" class="google-button" @click="handleGoogleLogin">
<img :src="google" class="google-icon" />
Sign in with Google
2025-11-04 16:47:17 +08:00
</div> -->
2025-12-23 15:52:20 +08:00
<GoogleLogin
@googelLogin="handleGoogleLogin"
ref="googleLoginRef"
@click="clickGooleLogin"
></GoogleLogin>
<div class="sign-up-button" @click="handleSignup">Dont have an account? Sign Up</div>
2025-10-22 14:03:57 +08:00
</div>
</div>
</div>
<div class="footer">
<p>Powered by AiDLab for Lane Crawford</p>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, computed } from 'vue'
import { useRouter } from 'vue-router'
2025-10-27 11:08:26 +08:00
import { useUserInfoStore } from '@/stores'
import { showToast } from 'vant'
2025-11-04 16:47:17 +08:00
import { fetchRegisterOrLogin, googleAuth } from '@/api/login'
2025-10-31 14:36:23 +08:00
import { encryptPassword } from '@/utils/tools'
2025-11-04 16:47:17 +08:00
import GoogleLogin from './components/GoogleLogin.vue'
const router = useRouter()
2025-10-27 11:08:26 +08:00
const userInfoStore = useUserInfoStore()
// 表单数据
2025-10-27 11:08:26 +08:00
const formData = reactive({
email: '',
password: ''
})
// 加载状态
const isLoading = ref(false)
// 表单验证规则
const validateEmail = (email: string) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
return emailRegex.test(email)
}
const validatePassword = (password: string) => {
return password.length >= 6
}
// 验证表单
const validateForm = () => {
// 验证邮箱
if (!formData.email) {
2025-10-31 11:42:15 +08:00
showToast('Please input your email')
return false
} else if (!validateEmail(formData.email)) {
2025-10-31 11:42:15 +08:00
showToast('Please input valid email')
return false
}
// 验证密码
if (!formData.password) {
2025-10-31 11:42:15 +08:00
showToast('Please input password')
return false
} else if (!validatePassword(formData.password)) {
2025-10-31 11:42:15 +08:00
showToast('Please input correct password')
return false
}
return true
}
// 返回上一页
const goBack = () => {
router.go(-1)
}
// 处理登录
const handleLogin = async () => {
if (!validateForm()) {
return
}
isLoading.value = true
2025-10-31 14:36:23 +08:00
const encryptedPassword = encryptPassword(formData.password)
2025-11-04 16:47:17 +08:00
fetchRegisterOrLogin({ ...formData, password: encryptedPassword, operationType: 'LOGIN' }).then(
(response) => {
console.log('登录成功', response)
userInfoStore.setToken(response.token)
userInfoStore.setUserInfo(response.user)
showToast('login success')
router.replace('/customer')
2025-11-04 16:47:17 +08:00
}
)
}
// 处理忘记密码
const handleForgotPassword = () => {
// 这里可以跳转到忘记密码页面
2025-10-22 14:03:57 +08:00
router.push('/reset')
}
2025-11-05 13:41:12 +08:00
const googleLoginRef = ref(null)
const clickGooleLogin = () => {
googleLoginRef.value?.login()
}
// 处理Google登录
2025-11-06 15:03:42 +08:00
const handleGoogleLogin = async (accessToken: string) => {
try {
isLoading.value = true
2025-11-06 15:03:42 +08:00
const result = await googleAuth({ accessToken })
2025-11-04 16:47:17 +08:00
// console.log('result', result)
userInfoStore.setToken(result.token)
userInfoStore.setUserInfo(result.user)
showToast('Google login successful')
router.replace('/customer')
} catch (error) {
console.error('Google登录失败:', error)
2025-10-31 11:42:15 +08:00
showToast('Google login failed, please try again')
} finally {
isLoading.value = false
}
}
// 处理注册
const handleSignup = () => {
router.push('/signup')
}
// 移除实时验证输入的错误显示逻辑,改用表单提交时统一验证
</script>
<style scoped lang="less">
.login-page {
position: relative;
color: #fff;
width: 100%;
height: 100vh;
overflow: hidden;
display: flex;
flex-direction: column;
background-image: url('@/assets/images/login_bg.png');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
padding-top: 12rem;
font-family: 'satoshiRegular';
}
.back-button {
margin-top: 2.4rem;
margin-left: 6.1rem;
display: flex;
align-items: center;
cursor: pointer;
z-index: 3;
font-size: 3.4rem;
2025-12-23 15:52:20 +08:00
.c-svg {
2025-12-01 11:30:31 +08:00
width: initial;
height: initial;
}
}
.header {
margin-top: 1.42rem;
2025-12-23 15:52:20 +08:00
padding-left: 14.5rem;
padding-right: 14.3rem;
color: white;
2025-10-13 10:13:54 +08:00
font-family: 'satoshiRegular';
.title {
font-size: 11rem;
font-weight: bold;
2025-12-23 15:52:20 +08:00
font-weight: 700;
margin-bottom: 0.8rem;
color: white;
font-family: 'satoshiBold';
}
.subtitle {
font-size: 3rem;
color: white;
font-weight: 400;
line-height: 141%;
letter-spacing: 0.08rem;
}
}
.content {
position: relative;
// z-index: 2;
flex: 1;
}
.login-container {
display: flex;
align-items: center;
justify-content: center;
margin-top: 7.2rem;
.login-form {
position: relative;
width: calc(100% - 28.4rem);
height: 107.8rem;
2025-12-23 15:52:20 +08:00
background: radial-gradient(100% 100% at 0% 0%, rgba(0, 0, 0, 0.4) 0%, rgba(0, 0, 0, 0.2) 100%);
backdrop-filter: blur(35px);
2025-10-30 16:55:44 +08:00
-webkit-backdrop-filter: blur(35px);
-moz-backdrop-filter: blur(35px);
-ms-backdrop-filter: blur(35px);
-o-backdrop-filter: blur(35px);
2025-11-04 16:47:17 +08:00
border: 0.2rem solid rgba(255, 255, 255, 0.15);
border-radius: 4.79rem;
padding: 11.2rem 8.62rem 14.28rem 7.18rem;
box-shadow: 0 0.8rem 3.2rem rgba(0, 0, 0, 0.1);
overflow: hidden;
2025-11-04 16:47:17 +08:00
border: 0.2rem solid #fff;
font-size: 3.83rem;
}
.input-field {
width: 100%;
height: 10rem;
2025-10-30 16:28:28 +08:00
padding: 1.6rem 2rem;
2025-11-04 16:47:17 +08:00
border: 0.2rem solid #fff;
background: transparent;
border-radius: 7.1rem;
color: white;
outline: none;
font-size: 3.83rem;
padding: 0 5.5rem;
}
.input-field::placeholder {
color: rgba(255, 255, 255, 0.6);
font-size: 3.83rem;
}
.input-group {
margin-bottom: 4rem;
&.pwd {
margin-bottom: 6.7rem;
}
}
.login-button {
width: 100%;
height: 10rem;
background: #000;
color: white;
border: none;
border-radius: 7rem;
font-size: 4rem;
margin-bottom: 1.67rem;
2025-10-22 14:03:57 +08:00
text-align: center;
line-height: 10rem;
}
.forgot-password {
font-family: 'satoshiRegular';
font-size: 2.39rem;
font-weight: 400;
text-align: center;
text-decoration: underline;
text-decoration-style: bold;
margin-bottom: 21.47rem;
}
}
.google-button {
width: 100%;
2025-10-30 16:28:28 +08:00
padding: 1.6rem;
2025-11-04 16:47:17 +08:00
border: 0.2rem solid #fff;
border-radius: 7rem;
font-size: 3.83rem;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
column-gap: 3.1rem;
margin-bottom: 1.67rem;
}
2025-11-04 16:47:17 +08:00
.google-icon {
width: 4.8rem;
height: 4.8rem;
}
.sign-up-button {
font-family: 'satoshiRegular';
font-size: 2.39rem;
font-weight: 400;
text-align: center;
}
.footer {
position: relative;
text-align: center;
color: white;
font-size: 3rem;
margin-bottom: 15.5rem;
}
</style>