Files
sweekar-app/pages/login/register.vue
T
2026-01-21 11:32:19 +08:00

402 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>