402 lines
11 KiB
Vue
402 lines
11 KiB
Vue
<script setup>
|
||
import { ref } from 'vue';
|
||
import { register, sendCodeToEmail, loginByEmail } from './api';
|
||
import { useUserStore } from '@/store/user.js';
|
||
|
||
const userStore = useUserStore();
|
||
|
||
// Registration related variables
|
||
const registerEmail = ref(''); // Email for registration
|
||
const registerPassword = ref(''); // Password for registration
|
||
const confirmPassword = ref(''); // Confirm password
|
||
const verificationCode = ref(''); // Verification code
|
||
const codeBtnText = ref('Get Code');
|
||
const codeBtnDisabled = ref(false);
|
||
const checked = ref(true); // Agree to terms, default checked
|
||
let countdownTimer = null;
|
||
|
||
// Email format validation
|
||
const validateEmail = (email) => {
|
||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||
return emailRegex.test(email);
|
||
};
|
||
|
||
// Toggle agreement to terms
|
||
const onChange = (e) => {
|
||
checked.value = e.detail.value; // Update checked value
|
||
};
|
||
|
||
// 显示用户协议
|
||
const showAgreement = () => {
|
||
uni.showModal({
|
||
title: 'User Agreement',
|
||
content: 'Welcome to our service!\n\nThis agreement sets forth the terms and conditions for your use of our services, please read carefully.\n\n1. Terms of Service\n2. Privacy Policy\n3. Account Security\n4. Disclaimer\n\nContinuing to use means you agree to comply with these terms.',
|
||
showCancel: true,
|
||
confirmText: 'Agree',
|
||
cancelText: 'Cancel',
|
||
success: (res) => {
|
||
if (res.confirm) {
|
||
checked.value = true;
|
||
}
|
||
}
|
||
});
|
||
};
|
||
|
||
// 获取验证码
|
||
const getVerificationCode = async () => {
|
||
if (!registerEmail.value) {
|
||
uni.showToast({
|
||
title: 'Please enter email',
|
||
icon: 'none',
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (!validateEmail(registerEmail.value)) {
|
||
uni.showToast({
|
||
title: 'Please enter a valid email',
|
||
icon: 'none',
|
||
});
|
||
return;
|
||
}
|
||
|
||
// Send verification code
|
||
try {
|
||
uni.showLoading({
|
||
title: 'Sending...',
|
||
mask: true,
|
||
});
|
||
|
||
const params = {
|
||
email: registerEmail.value,
|
||
register: true
|
||
};
|
||
|
||
const res = await sendCodeToEmail(params);
|
||
|
||
if (res && res.code === 0) {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: 'Verification code sent',
|
||
icon: 'success',
|
||
});
|
||
|
||
// Start countdown
|
||
let timeLeft = 60;
|
||
codeBtnDisabled.value = true;
|
||
codeBtnText.value = `${timeLeft}s`;
|
||
|
||
countdownTimer = setInterval(() => {
|
||
timeLeft--;
|
||
codeBtnText.value = `${timeLeft}s`;
|
||
|
||
if (timeLeft <= 0) {
|
||
clearInterval(countdownTimer);
|
||
codeBtnText.value = 'Resend';
|
||
codeBtnDisabled.value = false;
|
||
}
|
||
}, 1000);
|
||
} else {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: res.msg || 'Send failed',
|
||
icon: 'error',
|
||
});
|
||
}
|
||
} catch (error) {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: error.message || 'Send failed, please try again',
|
||
icon: 'error',
|
||
});
|
||
}
|
||
};
|
||
|
||
// 注册提交
|
||
const onRegister = async () => {
|
||
if (!registerEmail.value) {
|
||
uni.showToast({
|
||
title: 'Please enter email',
|
||
icon: 'none',
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (!validateEmail(registerEmail.value)) {
|
||
uni.showToast({
|
||
title: 'Please enter a valid email',
|
||
icon: 'none',
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (!verificationCode.value) {
|
||
uni.showToast({
|
||
title: 'Please enter verification code',
|
||
icon: 'none',
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (!registerPassword.value) {
|
||
uni.showToast({
|
||
title: 'Please enter password',
|
||
icon: 'none',
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (registerPassword.value !== confirmPassword.value) {
|
||
uni.showToast({
|
||
title: 'Passwords do not match',
|
||
icon: 'none',
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (registerPassword.value.length < 6) {
|
||
uni.showToast({
|
||
title: 'Password must be at least 6 characters',
|
||
icon: 'none',
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (!checked.value) {
|
||
uni.showToast({
|
||
title: 'Please agree to the user agreement',
|
||
icon: 'none',
|
||
duration: 2000,
|
||
});
|
||
return;
|
||
}
|
||
|
||
try {
|
||
uni.showLoading({
|
||
title: 'Registering...',
|
||
mask: true,
|
||
});
|
||
|
||
// Call registration API
|
||
const registerParams = {
|
||
email: registerEmail.value,
|
||
verificationCode: verificationCode.value,
|
||
password: registerPassword.value,
|
||
confirmPassword: confirmPassword.value
|
||
};
|
||
|
||
const res = await register(registerParams);
|
||
|
||
if (res && res.code === 0) {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: 'Registration successful',
|
||
icon: 'success',
|
||
});
|
||
|
||
// Auto login after successful registration
|
||
setTimeout(async () => {
|
||
try {
|
||
const loginRes = await loginByEmail({
|
||
email: registerEmail.value,
|
||
password: registerPassword.value
|
||
});
|
||
|
||
if (loginRes && loginRes.code === 0) {
|
||
// Store user info to global state
|
||
userStore.setUserInfo(loginRes.data);
|
||
userStore.setToken(loginRes.data.accessToken);
|
||
userStore.setLoginStatus(true);
|
||
|
||
uni.showToast({
|
||
title: 'Login successful',
|
||
icon: 'success',
|
||
});
|
||
|
||
// Navigate to home page
|
||
uni.switchTab({
|
||
url: '/pages/mine/index'
|
||
});
|
||
} else {
|
||
uni.showToast({
|
||
title: loginRes.msg || 'Auto login failed',
|
||
icon: 'none',
|
||
});
|
||
|
||
// Navigate to home page even if auto login fails, so user can login manually
|
||
uni.switchTab({
|
||
url: '/pages/mine/index'
|
||
});
|
||
}
|
||
} catch (error) {
|
||
console.error('Auto login failed:', error);
|
||
uni.showToast({
|
||
title: 'Auto login failed, please login manually',
|
||
icon: 'none',
|
||
});
|
||
|
||
// Navigate to home page
|
||
uni.switchTab({
|
||
url: '/pages/mine/index'
|
||
});
|
||
}
|
||
}, 1000);
|
||
} else {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: res.msg || 'Registration failed',
|
||
icon: 'error',
|
||
});
|
||
}
|
||
} catch (error) {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: error.message || 'Registration failed, please try again',
|
||
icon: 'error',
|
||
});
|
||
}
|
||
};
|
||
|
||
// Clear input field
|
||
const clearInput = (type) => {
|
||
if (type === 'registerEmail') {
|
||
registerEmail.value = '';
|
||
} else if (type === 'registerPassword') {
|
||
registerPassword.value = '';
|
||
} else if (type === 'confirmPassword') {
|
||
confirmPassword.value = '';
|
||
} else if (type === 'verificationCode') {
|
||
verificationCode.value = '';
|
||
}
|
||
};
|
||
|
||
//跳转到登录页面
|
||
//跳转到注册页面
|
||
const goLoginPage = function() {
|
||
uni.navigateTo({
|
||
url:'/pages/login/index'
|
||
})
|
||
}
|
||
|
||
</script>
|
||
|
||
<template>
|
||
<view class="p-4 min-h-screen bg-white flex flex-col justify-center">
|
||
<!-- 标题 -->
|
||
<view class="mb-12 text-center">
|
||
<image src="/static/tabbar/find.png" class="w-20 h-20 mb-8" mode="aspectFit"></image>
|
||
<text class="block text-3xl font-bold text-gray-800 mb-4">CREATE ACCOUNT</text>
|
||
<text class="text-sm text-gray-500">Join Sweekar to get started</text>
|
||
</view>
|
||
|
||
<!-- 注册邮箱输入 -->
|
||
<view class="mb-6">
|
||
<view class=" flex items-center h-12 bg-gray-100 rounded-lg px-6 gap-1 border border-solid border-round-theme">
|
||
<u-icon name="email" class="h-10" color="black" bold="true"></u-icon>
|
||
<input
|
||
class="w-full text-base text-gray-800 bg-transparent"
|
||
type="email"
|
||
placeholder="Email Address"
|
||
v-model="registerEmail"
|
||
/>
|
||
<view
|
||
v-if="registerEmail"
|
||
class="absolute right-6 w-8 h-8 flex items-center justify-center bg-gray-400 rounded-full text-black font-bold"
|
||
@tap="clearInput('registerEmail')"
|
||
>
|
||
×
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 验证码输入 -->
|
||
<view class="mb-6 relative">
|
||
<view class=" flex items-center h-12 bg-gray-100 rounded-lg px-6 gap-1 border border-solid border-round-theme">
|
||
<u-icon name="chat" class="h-10" color="black" bold="true"></u-icon>
|
||
<input
|
||
class="w-full text-base text-gray-800 bg-transparent pr-32"
|
||
type="text"
|
||
placeholder="Verification Code"
|
||
v-model="verificationCode"
|
||
/>
|
||
|
||
</view>
|
||
<button
|
||
class="absolute right-2 top-1/2 transform -translate-y-1/2 h-10 px-4 bg-theme text-white text-xs rounded-full disabled:bg-gray-400 disabled:text-gray-300 flex items-center justify-center"
|
||
:disabled="codeBtnDisabled"
|
||
@tap="getVerificationCode"
|
||
>
|
||
{{ codeBtnText }}
|
||
</button>
|
||
</view>
|
||
|
||
<!-- 注册密码输入 -->
|
||
<view class="mb-6">
|
||
<view class=" flex items-center h-12 bg-gray-100 rounded-lg px-6 gap-1 border border-solid border-round-theme">
|
||
<u-icon name="lock" class="h-10" color="black" bold="true"></u-icon>
|
||
<input
|
||
class="w-full text-base text-gray-800 bg-transparent"
|
||
type="password"
|
||
placeholder="Password"
|
||
v-model="registerPassword"
|
||
/>
|
||
<view
|
||
v-if="registerPassword"
|
||
class="absolute right-6 w-8 h-8 flex items-center justify-center bg-gray-400 rounded-full text-white font-bold"
|
||
@tap="clearInput('registerPassword')"
|
||
>
|
||
×
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 确认密码输入 -->
|
||
<view class="mb-8">
|
||
<view class=" flex items-center h-12 bg-gray-100 rounded-lg px-6 gap-1 border border-solid border-round-theme">
|
||
<u-icon name="lock" class="h-10" color="black" bold="true"></u-icon>
|
||
<input
|
||
class="w-full text-base text-gray-800 bg-transparent"
|
||
type="password"
|
||
placeholder="Confirm Password"
|
||
v-model="confirmPassword"
|
||
/>
|
||
<view
|
||
v-if="confirmPassword"
|
||
class="absolute right-6 w-8 h-8 flex items-center justify-center bg-gray-400 rounded-full text-white font-bold"
|
||
@tap="clearInput('confirmPassword')"
|
||
>
|
||
×
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 注册按钮 -->
|
||
<view
|
||
class="w-full h-12 bg-theme rounded-lg text-white text-xl flex items-center justify-center"
|
||
@click="onRegister"
|
||
>
|
||
<text>SIGN UP</text>
|
||
</view>
|
||
|
||
<!-- 登录链接 -->
|
||
<view class="flex justify-center items-center my-8 text-gray-500 text-sm">
|
||
<text>Already have an account?</text>
|
||
<text class="text-green-500 ml-2" @click="goLoginPage">Sign in</text>
|
||
</view>
|
||
|
||
<!-- 同意条款 -->
|
||
<!-- <view class="mt-auto text-center">
|
||
<label class="flex items-center justify-center text-xs text-gray-500 leading-loose">
|
||
<checkbox
|
||
class="scale-75 mr-2"
|
||
:checked="checked"
|
||
@change="onChange"
|
||
/>
|
||
I have read and agree to the
|
||
<text class="text-green-500 underline" @tap="showAgreement"> User Agreement</text>
|
||
and
|
||
<text class="text-green-500 underline" @tap="showAgreement"> Privacy Policy</text>
|
||
</label>
|
||
</view> -->
|
||
</view>
|
||
</template> |