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

314 lines
6.5 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.

<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>