添加找回密码功能

This commit is contained in:
yzy committed 2026-01-21 11:34:37 +08:00
1 parent a4e01d96b8
commit d0b5a3d582
2 files changed
+314

No files matched your search

+7
View File
@@ -37,3 +37,10 @@ export const login = (params) => {
export const register = (params) => {
return get('/front/user/login/register', params);
};
/**
* @desc 忘记密码
*/
export const forgetPassword = (params) => {
return post('/app-api/member/auth/password-reset', params);
};
+307
View File
@@ -0,0 +1,307 @@
<script setup>
import { ref } from 'vue';
import { forgetPassword, sendCodeToEmail } from './api';
// Password reset related variables
const email = ref('');
const newPassword = ref('');
const confirmPassword = ref('');
const verificationCode = ref('');
const codeBtnText = ref('Get Code');
const codeBtnDisabled = ref(false);
let countdownTimer = null;
// Email format validation
const validateEmail = (email) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
// Get verification code
const getVerificationCode = async () => {
if (!email.value) {
uni.showToast({
title: 'Please enter email',
icon: 'none',
});
return;
}
if (!validateEmail(email.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: email.value,
register: false // Not for registration, but for password reset
};
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',
});
}
};
// Submit password reset
const onResetPassword = async () => {
if (!email.value) {
uni.showToast({
title: 'Please enter email',
icon: 'none',
});
return;
}
if (!validateEmail(email.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 (!newPassword.value) {
uni.showToast({
title: 'Please enter new password',
icon: 'none',
});
return;
}
if (newPassword.value !== confirmPassword.value) {
uni.showToast({
title: 'Passwords do not match',
icon: 'none',
});
return;
}
if (newPassword.value.length < 6) {
uni.showToast({
title: 'Password must be at least 6 characters',
icon: 'none',
});
return;
}
try {
uni.showLoading({
title: 'Resetting password...',
mask: true,
});
// Call password reset API
const resetParams = {
email: email.value,
verificationCode: verificationCode.value,
password: newPassword.value,
confirmPassword: confirmPassword.value
};
const res = await forgetPassword(resetParams);
if (res && res.code === 0) {
uni.hideLoading();
uni.showToast({
title: 'Password reset successful',
icon: 'success',
});
// Navigate back to login page after success
setTimeout(() => {
uni.navigateBack();
}, 1500);
} else {
uni.hideLoading();
uni.showToast({
title: res.msg || 'Password reset failed',
icon: 'error',
});
}
} catch (error) {
uni.hideLoading();
uni.showToast({
title: error.message || 'Password reset failed, please try again',
icon: 'error',
});
}
};
// Clear input field
const clearInput = (type) => {
if (type === 'email') {
email.value = '';
} else if (type === 'newPassword') {
newPassword.value = '';
} else if (type === 'confirmPassword') {
confirmPassword.value = '';
} else if (type === 'verificationCode') {
verificationCode.value = '';
}
};
// Go back to login page
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">
<!-- Title -->
<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">RESET PASSWORD</text>
<text class="text-sm text-gray-500">Enter your email and new password</text>
</view>
<!-- Email input -->
<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="email"
/>
<view
v-if="email"
class="absolute right-6 w-8 h-8 flex items-center justify-center bg-gray-400 rounded-full text-black font-bold"
@tap="clearInput('email')"
>
×
</view>
</view>
</view>
<!-- Verification code input -->
<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>
<!-- New password input -->
<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="New Password"
v-model="newPassword"
/>
<view
v-if="newPassword"
class="absolute right-6 w-8 h-8 flex items-center justify-center bg-gray-400 rounded-full text-white font-bold"
@tap="clearInput('newPassword')"
>
×
</view>
</view>
</view>
<!-- Confirm password input -->
<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>
<!-- Reset password button -->
<view
class="w-full h-12 bg-theme rounded-lg text-white text-xl flex items-center justify-center"
@click="onResetPassword"
>
<text>RESET PASSWORD</text>
</view>
<!-- Back to login link -->
<view class="flex justify-center items-center my-8 text-gray-500 text-sm">
<text>Remember your password?</text>
<text class="text-green-500 ml-2" @click="goLoginPage">Back to Sign in</text>
</view>
</view>
</template>