ruoyi-geek-App/pages_system/pages/forget/index.vue

314 lines
6.5 KiB
Vue
Raw Normal View History

2025-11-26 15:41:57 +00:00
<template>
<view class="forget-container">
<view class="forget-header">
<text class="back-btn" @click="goBack"></text>
<text class="title">忘记密码</text>
<view class="placeholder"></view>
</view>
<view class="forget-content">
<view class="forget-form">
<view class="form-item">
<text class="label">手机号</text>
<input
v-model="forgetForm.phone"
class="input"
type="number"
placeholder="请输入注册手机号"
placeholder-class="placeholder"
/>
</view>
<view class="form-item">
<text class="label">验证码</text>
<view class="code-input">
<input
v-model="forgetForm.code"
class="input"
type="number"
placeholder="请输入验证码"
placeholder-class="placeholder"
/>
<button
class="send-code-btn"
:disabled="countdown > 0"
@click="sendCode"
>
{{ countdown > 0 ? `${countdown}s` : '获取验证码' }}
</button>
</view>
</view>
<view class="form-item">
<text class="label">新密码</text>
<input
v-model="forgetForm.newPassword"
class="input"
password
placeholder="请输入新密码"
placeholder-class="placeholder"
/>
</view>
<view class="form-item">
<text class="label">确认密码</text>
<input
v-model="forgetForm.confirmPassword"
class="input"
password
placeholder="请再次输入新密码"
placeholder-class="placeholder"
/>
</view>
<button class="confirm-btn" @click="handleResetPassword" :disabled="resetting">
{{ resetting ? '重置中...' : '重置密码' }}
</button>
</view>
</view>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue'
import modal from '@/plugins/modal'
import { sendPhoneCode, verifyPhoneCode } from '@/api/login'
import { resetUserPwd } from '@/api/system/user'
// 响应式数据
const resetting = ref(false)
const countdown = ref(0)
let countdownTimer = null
// 忘记密码表单
const forgetForm = reactive({
phone: '',
code: '',
newPassword: '',
confirmPassword: ''
})
// 发送验证码
const sendCode = async () => {
if (!forgetForm.phone) {
modal.alert('请输入手机号')
return
}
if (!/^1[3-9]\d{9}$/.test(forgetForm.phone)) {
modal.alert('请输入正确的手机号')
return
}
try {
await sendPhoneCode({ phone: forgetForm.phone }, 'reset')
modal.alert('验证码已发送')
// 开始倒计时
countdown.value = 60
countdownTimer = setInterval(() => {
countdown.value--
if (countdown.value <= 0) {
clearInterval(countdownTimer)
}
}, 1000)
} catch (error) {
modal.alert(error.message || '验证码发送失败')
}
}
// 处理密码重置
const handleResetPassword = async () => {
if (!validateForm()) return
resetting.value = true
try {
// 验证验证码
await verifyPhoneCode({
phone: forgetForm.phone,
code: forgetForm.code
}, 'reset')
// 执行密码重置
// 这里需要先找到用户ID实际项目中可能需要根据手机号查询用户信息
// 假设我们已经获得了userId
const userId = await getUserIdByPhone(forgetForm.phone)
if (!userId) {
modal.alert('未找到该手机号对应的用户')
return
}
await resetUserPwd(userId, forgetForm.newPassword)
modal.alert('密码重置成功', () => {
uni.redirectTo({
url: '/pages/login'
})
})
} catch (error) {
modal.alert(error.message || '密码重置失败')
} finally {
resetting.value = false
}
}
// 根据手机号获取用户ID模拟实现
const getUserIdByPhone = async (phone) => {
// 实际项目中需要调用API查询用户信息
// 这里返回一个模拟的userId
return '123' // 实际应该从API获取
}
// 表单验证
const validateForm = () => {
if (!forgetForm.phone) {
modal.alert('请输入手机号')
return false
}
if (!/^1[3-9]\d{9}$/.test(forgetForm.phone)) {
modal.alert('请输入正确的手机号')
return false
}
if (!forgetForm.code) {
modal.alert('请输入验证码')
return false
}
if (!forgetForm.newPassword) {
modal.alert('请输入新密码')
return false
}
if (forgetForm.newPassword.length < 6) {
modal.alert('密码长度不能少于6位')
return false
}
if (forgetForm.newPassword !== forgetForm.confirmPassword) {
modal.alert('两次输入的密码不一致')
return false
}
return true
}
// 返回登录页面
const goBack = () => {
uni.navigateBack()
}
// 清理计时器
import { onUnmounted } from 'vue'
onUnmounted(() => {
if (countdownTimer) {
clearInterval(countdownTimer)
}
})
</script>
<style scoped>
.forget-container {
min-height: 100vh;
background: #f5f5f5;
}
.forget-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 40rpx 30rpx;
background: #fff;
border-bottom: 1rpx solid #e0e0e0;
}
.back-btn {
font-size: 50rpx;
color: #333;
width: 60rpx;
height: 60rpx;
line-height: 60rpx;
text-align: center;
}
.title {
font-size: 36rpx;
color: #333;
font-weight: bold;
}
.placeholder {
width: 60rpx;
}
.forget-content {
padding: 40rpx;
}
.forget-form {
background: #fff;
border-radius: 20rpx;
padding: 40rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
}
.form-item {
margin-bottom: 30rpx;
}
.label {
display: block;
font-size: 28rpx;
color: #333;
margin-bottom: 10rpx;
}
.input {
width: 100%;
height: 80rpx;
border: 2rpx solid #e0e0e0;
border-radius: 10rpx;
padding: 0 20rpx;
font-size: 28rpx;
box-sizing: border-box;
}
.code-input {
display: flex;
align-items: center;
gap: 20rpx;
}
.send-code-btn {
width: 200rpx;
height: 80rpx;
background: #007aff;
color: #fff;
border: none;
border-radius: 10rpx;
font-size: 24rpx;
white-space: nowrap;
}
.send-code-btn[disabled] {
background: #ccc;
}
.confirm-btn {
width: 100%;
height: 88rpx;
background: #007aff;
color: #fff;
border: none;
border-radius: 44rpx;
font-size: 32rpx;
margin-top: 20rpx;
}
.confirm-btn[disabled] {
background: #ccc;
}
</style>