|
|
|
|
@ -55,13 +55,20 @@
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes float {
|
|
|
|
|
0%, 100% { transform: translate(0, 0); }
|
|
|
|
|
50% { transform: translate(30px, 20px); }
|
|
|
|
|
|
|
|
|
|
0%,
|
|
|
|
|
100% {
|
|
|
|
|
transform: translate(0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
50% {
|
|
|
|
|
transform: translate(30px, 20px);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 主容器 */
|
|
|
|
|
.container {
|
|
|
|
|
background-color: var(--bg-color);
|
|
|
|
|
background-color: var(--color-primary-text);
|
|
|
|
|
border-radius: var(--radius-xl);
|
|
|
|
|
box-shadow: var(--shadow-xl);
|
|
|
|
|
position: relative;
|
|
|
|
|
@ -77,7 +84,7 @@
|
|
|
|
|
top: 0;
|
|
|
|
|
height: 100%;
|
|
|
|
|
transition: all 0.6s ease-in-out;
|
|
|
|
|
background: var(--bg-color);
|
|
|
|
|
background: var(--color-primary-text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.sign-in-container {
|
|
|
|
|
@ -105,8 +112,18 @@
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes show {
|
|
|
|
|
0%, 49.99% { opacity: 0; z-index: 1; }
|
|
|
|
|
50%, 100% { opacity: 1; z-index: 5; }
|
|
|
|
|
|
|
|
|
|
0%,
|
|
|
|
|
49.99% {
|
|
|
|
|
opacity: 0;
|
|
|
|
|
z-index: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
50%,
|
|
|
|
|
100% {
|
|
|
|
|
opacity: 1;
|
|
|
|
|
z-index: 5;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.form-container-inner {
|
|
|
|
|
@ -151,7 +168,7 @@
|
|
|
|
|
transition: all 0.3s;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.social-btn:hover {
|
|
|
|
|
border-color: var(--color-primary);
|
|
|
|
|
color: var(--color-primary);
|
|
|
|
|
@ -184,7 +201,7 @@
|
|
|
|
|
|
|
|
|
|
.tab-item.active {
|
|
|
|
|
color: var(--color-primary);
|
|
|
|
|
background: var(--bg-color);
|
|
|
|
|
background: var(--color-primary-text);
|
|
|
|
|
box-shadow: var(--shadow-sm);
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
}
|
|
|
|
|
@ -198,15 +215,11 @@
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.input-wrapper {
|
|
|
|
|
width: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.phone-row {
|
|
|
|
|
display: flex;
|
|
|
|
|
gap: 10px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.verify-row {
|
|
|
|
|
display: flex;
|
|
|
|
|
gap: 10px;
|
|
|
|
|
@ -221,7 +234,7 @@
|
|
|
|
|
align-self: flex-end;
|
|
|
|
|
transition: color 0.3s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.forgot-password:hover {
|
|
|
|
|
color: var(--color-primary);
|
|
|
|
|
}
|
|
|
|
|
@ -259,7 +272,7 @@
|
|
|
|
|
background-repeat: no-repeat;
|
|
|
|
|
background-size: cover;
|
|
|
|
|
background-position: 0 0;
|
|
|
|
|
color: #fff;
|
|
|
|
|
color: var(--color-primary-text);
|
|
|
|
|
position: relative;
|
|
|
|
|
left: -100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
@ -288,7 +301,7 @@
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.overlay-panel h1 {
|
|
|
|
|
color: #fff;
|
|
|
|
|
color: var(--color-primary-text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.overlay-panel p {
|
|
|
|
|
@ -296,7 +309,7 @@
|
|
|
|
|
font-weight: 300;
|
|
|
|
|
line-height: 24px;
|
|
|
|
|
margin: 20px 0 30px;
|
|
|
|
|
color: rgba(255, 255, 255, 0.9);
|
|
|
|
|
color: color-mix(in srgb, var(--color-primary-text), transparent 10%);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.overlay-left {
|
|
|
|
|
@ -316,24 +329,9 @@
|
|
|
|
|
transform: translateX(20%);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 按钮覆盖样式 */
|
|
|
|
|
.btn-ghost {
|
|
|
|
|
background-color: transparent;
|
|
|
|
|
border-color: #fff;
|
|
|
|
|
color: #fff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.btn-ghost:hover {
|
|
|
|
|
background-color: rgba(255, 255, 255, 0.1);
|
|
|
|
|
color: #fff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* v-btn 通用样式微调 */
|
|
|
|
|
v-btn {
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
letter-spacing: 0.5px;
|
|
|
|
|
}
|
|
|
|
|
/* 按钮覆盖样式 - REMOVED to avoid conflict with internal styles */
|
|
|
|
|
|
|
|
|
|
/* v-btn 通用样式微调 - REMOVED to avoid conflict with internal styles */
|
|
|
|
|
</style>
|
|
|
|
|
</head>
|
|
|
|
|
|
|
|
|
|
@ -345,53 +343,44 @@
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="container" :class="{ 'right-panel-active': isSignUp }" id="container">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 注册表单 -->
|
|
|
|
|
<div class="form-container sign-up-container">
|
|
|
|
|
<div class="form-container-inner">
|
|
|
|
|
<h1>创建账户</h1>
|
|
|
|
|
<div class="subtitle">填写以下信息开始您的旅程</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div class="social-container">
|
|
|
|
|
<div class="social-btn" @click="handleSocialLogin('github')"><i class="fa-brands fa-github"></i></div>
|
|
|
|
|
<div class="social-btn" @click="handleSocialLogin('weixin')"><i class="fa-brands fa-weixin"></i></div>
|
|
|
|
|
<div class="social-btn" @click="handleSocialLogin('google')"><i class="fa-brands fa-google"></i></div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div class="subtitle" style="margin: 0 0 15px; font-size: 12px;">或使用手机/邮箱注册</div>
|
|
|
|
|
|
|
|
|
|
<div class="input-group">
|
|
|
|
|
<div class="input-wrapper">
|
|
|
|
|
<v-input v:value="signUpForm.username" placeholder="用户名" prefix-icon="fa fa-user"></v-input>
|
|
|
|
|
</div>
|
|
|
|
|
<v-input v:value="signUpForm.username" placeholder="用户名"></v-input>
|
|
|
|
|
|
|
|
|
|
<!-- 手机号输入框带区域选择 -->
|
|
|
|
|
<div v-if='$G.cfg.sms' class="phone-row">
|
|
|
|
|
<div style="width: 110px;">
|
|
|
|
|
<v-input type="select" v:value="signUpForm.region" :opts="{options: regions}" :clearable="false"></v-input>
|
|
|
|
|
</div>
|
|
|
|
|
<div style="flex: 1;">
|
|
|
|
|
<v-input v:value="signUpForm.phone" placeholder="手机号" prefix-icon="fa fa-mobile"></v-input>
|
|
|
|
|
</div>
|
|
|
|
|
<v-input type="select" v:value="signUpForm.region" :opts="{options: regions}"></v-input>
|
|
|
|
|
<v-input v:value="signUpForm.phone" placeholder="手机号"></v-input>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div v-if='$G.cfg.sms' class="verify-row">
|
|
|
|
|
<div style="flex: 1;">
|
|
|
|
|
<v-input v:value="signUpForm.verifyCode" placeholder="验证码" prefix-icon="fa fa-shield"></v-input>
|
|
|
|
|
</div>
|
|
|
|
|
<v-btn variant="outline" :disabled="smsCountdown > 0 || smsLoading" :click="() => sendVerifyCode('signup')" style="min-width: 100px;">
|
|
|
|
|
<v-input v:value="signUpForm.verifyCode" placeholder="验证码"></v-input>
|
|
|
|
|
<v-btn variant="outline" :disabled="smsCountdown > 0 || smsLoading" :click="() => sendVerifyCode('signup')"
|
|
|
|
|
style="min-width: 100px;">
|
|
|
|
|
{{ smsCountdown > 0 ? `${smsCountdown}s` : '获取验证码' }}
|
|
|
|
|
</v-btn>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="input-wrapper">
|
|
|
|
|
<v-input type="password" v:value="signUpForm.password" placeholder="密码" prefix-icon="fa fa-lock"></v-input>
|
|
|
|
|
</div>
|
|
|
|
|
<v-input type="password" v:value="signUpForm.password" placeholder="密码"></v-input>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="error-message">{{ signUpError }}</div>
|
|
|
|
|
|
|
|
|
|
<v-btn round block size="large" :loading="signUpLoading" :click="handleSignUp">立即注册</v-btn>
|
|
|
|
|
|
|
|
|
|
<v-btn round block size="lg" :loading="signUpLoading" :click="handleSignUp">立即注册</v-btn>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
@ -406,7 +395,7 @@
|
|
|
|
|
<div class="social-btn" @click="handleSocialLogin('weixin')"><i class="fa-brands fa-weixin"></i></div>
|
|
|
|
|
<div class="social-btn" @click="handleSocialLogin('google')"><i class="fa-brands fa-google"></i></div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div class="subtitle" style="margin: 0 0 15px; font-size: 12px;">或使用您的账户</div>
|
|
|
|
|
|
|
|
|
|
<!-- 登录方式选择 -->
|
|
|
|
|
@ -421,30 +410,21 @@
|
|
|
|
|
|
|
|
|
|
<!-- 用户名登录 -->
|
|
|
|
|
<div v-if="loginType === 'username'" class="input-group">
|
|
|
|
|
<div class="input-wrapper">
|
|
|
|
|
<v-input v:value="signInForm.username" placeholder="用户名" prefix-icon="fa fa-user"></v-input>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="input-wrapper">
|
|
|
|
|
<v-input type="password" v:value="signInForm.password" placeholder="密码" prefix-icon="fa fa-lock"></v-input>
|
|
|
|
|
</div>
|
|
|
|
|
<v-input v:value="signInForm.username" placeholder="用户名"></v-input>
|
|
|
|
|
<v-input type="password" v:value="signInForm.password" placeholder="密码"></v-input>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 手机号登录 -->
|
|
|
|
|
<div v-if="loginType === 'phone'" class="input-group">
|
|
|
|
|
<div class="phone-row">
|
|
|
|
|
<div style="width: 110px;">
|
|
|
|
|
<v-input type="select" v:value="signInForm.region" :opts="{options: regions}" :clearable="false"></v-input>
|
|
|
|
|
</div>
|
|
|
|
|
<div style="flex: 1;">
|
|
|
|
|
<v-input v:value="signInForm.phone" placeholder="手机号" prefix-icon="fa fa-mobile"></v-input>
|
|
|
|
|
</div>
|
|
|
|
|
<v-input type="select" v:value="signInForm.region" :opts="{options: regions}"></v-input>
|
|
|
|
|
<v-input v:value="signInForm.phone" placeholder="手机号"></v-input>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="verify-row">
|
|
|
|
|
<div style="flex: 1;">
|
|
|
|
|
<v-input v:value="signInForm.verifyCode" placeholder="验证码" prefix-icon="fa fa-shield"></v-input>
|
|
|
|
|
</div>
|
|
|
|
|
<v-btn variant="outline" :disabled="smsCountdown > 0 || smsLoading" :click="() => sendVerifyCode('signin')" style="min-width: 100px;">
|
|
|
|
|
<v-input v:value="signInForm.verifyCode" placeholder="验证码"></v-input>
|
|
|
|
|
<v-btn variant="outline" :disabled="smsCountdown > 0 || smsLoading" :click="() => sendVerifyCode('signin')"
|
|
|
|
|
style="min-width: 100px;">
|
|
|
|
|
{{ smsCountdown > 0 ? `${smsCountdown}s` : '获取验证码' }}
|
|
|
|
|
</v-btn>
|
|
|
|
|
</div>
|
|
|
|
|
@ -452,8 +432,8 @@
|
|
|
|
|
|
|
|
|
|
<a href="#" class="forgot-password">忘记密码?</a>
|
|
|
|
|
<div class="error-message">{{ signInError }}</div>
|
|
|
|
|
|
|
|
|
|
<v-btn round block size="large" :loading="signInLoading" :click="handleSignIn">登 录</v-btn>
|
|
|
|
|
|
|
|
|
|
<v-btn round block size="lg" :loading="signInLoading" :click="handleSignIn">登 录</v-btn>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
@ -463,12 +443,14 @@
|
|
|
|
|
<div class="overlay-panel overlay-left">
|
|
|
|
|
<h1>已有账户?</h1>
|
|
|
|
|
<p>请使用您的个人信息登录,保持连接。</p>
|
|
|
|
|
<v-btn variant="outline" round class="btn-ghost" :click="switchToSignIn" size="large" style="width: 120px;">去登录</v-btn>
|
|
|
|
|
<v-btn variant="outline" round class="btn-ghost" :click="switchToSignIn" size="lg"
|
|
|
|
|
style="width: 120px;">去登录</v-btn>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="overlay-panel overlay-right">
|
|
|
|
|
<h1>新朋友?</h1>
|
|
|
|
|
<p>输入您的个人信息,开始您的旅程。</p>
|
|
|
|
|
<v-btn variant="outline" round class="btn-ghost" :click="switchToSignUp" size="large" style="width: 120px;">去注册</v-btn>
|
|
|
|
|
<v-btn variant="outline" round class="btn-ghost" :click="switchToSignUp" size="lg"
|
|
|
|
|
style="width: 120px;">去注册</v-btn>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
@ -581,7 +563,7 @@
|
|
|
|
|
smsLoading = true;
|
|
|
|
|
try {
|
|
|
|
|
type === 'signup' ? signUpError = '' : signInError = '';
|
|
|
|
|
await $axios.post('/api/sms', { phone, region, purpose: type });
|
|
|
|
|
await $axios.post('/api/sms', {phone, region, purpose: type});
|
|
|
|
|
$message.success('验证码已发送');
|
|
|
|
|
smsCountdown = 60;
|
|
|
|
|
const timer = setInterval(() => {
|
|
|
|
|
@ -611,7 +593,7 @@
|
|
|
|
|
signUpError = '用户名必须大于5位。';
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ($G.cfg.sms) {
|
|
|
|
|
if (!validatePhone(signUpForm.phone, signUpForm.region)) {
|
|
|
|
|
signUpError = '请输入正确的手机号格式。';
|
|
|
|
|
@ -637,7 +619,7 @@
|
|
|
|
|
verify_code: signUpForm.verifyCode,
|
|
|
|
|
code: btoa(signUpForm.password),
|
|
|
|
|
}, {noretry: true});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$message.success('注册成功!');
|
|
|
|
|
signUpForm = {username: '', phone: '', verifyCode: '', password: '', region: '+86'};
|
|
|
|
|
switchToSignIn();
|
|
|
|
|
@ -657,13 +639,13 @@
|
|
|
|
|
try {
|
|
|
|
|
let loginData = {};
|
|
|
|
|
if (loginType === 'username') {
|
|
|
|
|
if (!signInForm.username) { signInError = '请输入用户名'; return; }
|
|
|
|
|
if (!signInForm.password) { signInError = '请输入密码'; return; }
|
|
|
|
|
loginData = { username: signInForm.username, code: btoa(signInForm.password), type: 'username' };
|
|
|
|
|
if (!signInForm.username) {signInError = '请输入用户名'; return;}
|
|
|
|
|
if (!signInForm.password) {signInError = '请输入密码'; return;}
|
|
|
|
|
loginData = {username: signInForm.username, code: btoa(signInForm.password), type: 'username'};
|
|
|
|
|
} else {
|
|
|
|
|
if (!signInForm.phone) { signInError = '请输入手机号'; return; }
|
|
|
|
|
if (!signInForm.verifyCode) { signInError = '请输入验证码'; return; }
|
|
|
|
|
loginData = { phone: signInForm.phone, region: signInForm.region, verify_code: signInForm.verifyCode, type: 'phone' };
|
|
|
|
|
if (!signInForm.phone) {signInError = '请输入手机号'; return;}
|
|
|
|
|
if (!signInForm.verifyCode) {signInError = '请输入验证码'; return;}
|
|
|
|
|
loginData = {phone: signInForm.phone, region: signInForm.region, verify_code: signInForm.verifyCode, type: 'phone'};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
signInLoading = true;
|
|
|
|
|
@ -679,4 +661,5 @@
|
|
|
|
|
};
|
|
|
|
|
</script>
|
|
|
|
|
</body>
|
|
|
|
|
|
|
|
|
|
</html>
|
|
|
|
|
|