first commit
This commit is contained in:
254
src/pages/auth/ResetPassword.vue
Normal file
254
src/pages/auth/ResetPassword.vue
Normal file
@@ -0,0 +1,254 @@
|
||||
<template>
|
||||
<div class="w-full auth-fade-in">
|
||||
<!-- 标题 -->
|
||||
<div class="text-center mb-8">
|
||||
<h2 class="auth-title">重置密码</h2>
|
||||
<p class="auth-subtitle">请输入手机号和验证码重置密码</p>
|
||||
</div>
|
||||
|
||||
<form class="space-y-4" @submit.prevent="onReset">
|
||||
<!-- 手机号输入 -->
|
||||
<div>
|
||||
<label class="auth-label">手机号</label>
|
||||
<el-input
|
||||
v-model="form.phone"
|
||||
name="reset-phone"
|
||||
placeholder="请输入手机号"
|
||||
size="large"
|
||||
clearable
|
||||
maxlength="11"
|
||||
:disabled="loading"
|
||||
class="auth-input"
|
||||
>
|
||||
<template #prefix>
|
||||
<svg class="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M2 3a1 1 0 011-1h2.153a1 1 0 01.986.836l.74 4.435a1 1 0 01-.54 1.06l-1.548.773a11.037 11.037 0 006.105 6.105l.774-1.548a1 1 0 011.059-.54l4.435.74a1 1 0 01.836.986V17a1 1 0 01-1 1h-2C7.82 18 2 12.18 2 5V3z"/>
|
||||
</svg>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
|
||||
<!-- 验证码输入 -->
|
||||
<div>
|
||||
<label class="auth-label">验证码</label>
|
||||
<div class="flex gap-3">
|
||||
<el-input
|
||||
v-model="form.code"
|
||||
name="reset-code"
|
||||
placeholder="请输入验证码"
|
||||
size="large"
|
||||
maxlength="6"
|
||||
:disabled="loading"
|
||||
class="auth-input"
|
||||
>
|
||||
<template #prefix>
|
||||
<svg class="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M18 8A6 6 0 006 8c0 3.314-4.03 6-6 6s6 2.686 6 6a6 6 0 0012 0c0-3.314 4.03-6 6-6s-6-2.686-6-6z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
:disabled="!canSendCode || loading"
|
||||
@click="sendCode"
|
||||
:loading="sendingCode"
|
||||
class="auth-button !px-6 !min-w-[120px]"
|
||||
>
|
||||
{{ countdown > 0 ? `${countdown}s` : '获取验证码' }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 新密码输入 -->
|
||||
<div>
|
||||
<label class="auth-label">新密码</label>
|
||||
<el-input
|
||||
v-model="form.newPassword"
|
||||
name="reset-new-password"
|
||||
type="password"
|
||||
placeholder="请输入新密码(至少6位)"
|
||||
size="large"
|
||||
show-password
|
||||
:disabled="loading"
|
||||
class="auth-input"
|
||||
>
|
||||
<template #prefix>
|
||||
<svg class="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
|
||||
<!-- 确认新密码输入 -->
|
||||
<div>
|
||||
<label class="auth-label">确认新密码</label>
|
||||
<el-input
|
||||
v-model="form.confirmNewPassword"
|
||||
name="reset-confirm-new-password"
|
||||
type="password"
|
||||
placeholder="请再次输入新密码"
|
||||
size="large"
|
||||
show-password
|
||||
:disabled="loading"
|
||||
class="auth-input"
|
||||
>
|
||||
<template #prefix>
|
||||
<svg class="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
|
||||
<!-- 操作链接 -->
|
||||
<div class="text-center py-2">
|
||||
<router-link to="/auth/login" class="auth-link text-sm">
|
||||
返回登录
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
<!-- 重置按钮 -->
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
class="auth-button w-full !h-12 !text-base !font-medium"
|
||||
native-type="submit"
|
||||
:loading="loading"
|
||||
:disabled="!canSubmit"
|
||||
>
|
||||
{{ loading ? '重置中...' : '重置密码' }}
|
||||
</el-button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="UserResetPassword">
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 表单数据
|
||||
const form = ref({
|
||||
phone: '',
|
||||
code: '',
|
||||
newPassword: '',
|
||||
confirmNewPassword: ''
|
||||
})
|
||||
|
||||
// 状态
|
||||
const loading = ref(false)
|
||||
const sendingCode = ref(false)
|
||||
const countdown = ref(0)
|
||||
let countdownTimer = null
|
||||
|
||||
// 计算属性
|
||||
const canSendCode = computed(() => {
|
||||
return form.value.phone && form.value.phone.length === 11 && countdown.value === 0
|
||||
})
|
||||
|
||||
const canSubmit = computed(() => {
|
||||
return form.value.phone && form.value.phone.length === 11 &&
|
||||
form.value.code && form.value.code.length === 6 &&
|
||||
form.value.newPassword && form.value.newPassword.length >= 6 &&
|
||||
form.value.confirmNewPassword && form.value.confirmNewPassword === form.value.newPassword
|
||||
})
|
||||
|
||||
// 发送验证码
|
||||
const sendCode = async () => {
|
||||
if (!canSendCode.value) return
|
||||
|
||||
sendingCode.value = true
|
||||
try {
|
||||
const result = await userStore.sendCode(form.value.phone, 'reset_password')
|
||||
if (result.success) {
|
||||
ElMessage.success('验证码发送成功')
|
||||
startCountdown()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('验证码发送失败:', error)
|
||||
} finally {
|
||||
sendingCode.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 开始倒计时
|
||||
const startCountdown = () => {
|
||||
countdown.value = 60
|
||||
countdownTimer = setInterval(() => {
|
||||
countdown.value--
|
||||
if (countdown.value <= 0) {
|
||||
clearInterval(countdownTimer)
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 重置密码
|
||||
const onReset = async () => {
|
||||
if (!canSubmit.value) return
|
||||
|
||||
if (form.value.newPassword !== form.value.confirmNewPassword) {
|
||||
ElMessage.error('两次密码不一致')
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
const resetData = {
|
||||
phone: form.value.phone,
|
||||
newPassword: form.value.newPassword,
|
||||
confirmNewPassword: form.value.confirmNewPassword,
|
||||
code: form.value.code
|
||||
}
|
||||
|
||||
const result = await userStore.resetPassword(resetData)
|
||||
if (result.success) {
|
||||
ElMessage.success('密码重置成功')
|
||||
router.push('/auth/login')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('密码重置失败:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 组件卸载时清理定时器
|
||||
onUnmounted(() => {
|
||||
if (countdownTimer) {
|
||||
clearInterval(countdownTimer)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 输入框样式优化 */
|
||||
:deep(.el-input__wrapper) {
|
||||
border-radius: 8px !important;
|
||||
transition: all 0.3s ease !important;
|
||||
}
|
||||
|
||||
:deep(.el-input__wrapper:hover) {
|
||||
border-color: #3b82f6 !important;
|
||||
}
|
||||
|
||||
:deep(.el-input__wrapper.is-focus) {
|
||||
border-color: #3b82f6 !important;
|
||||
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1) !important;
|
||||
}
|
||||
|
||||
/* 按钮样式优化 */
|
||||
:deep(.el-button--primary) {
|
||||
border-radius: 8px !important;
|
||||
font-weight: 500 !important;
|
||||
transition: all 0.3s ease !important;
|
||||
}
|
||||
|
||||
:deep(.el-button--primary:hover) {
|
||||
transform: translateY(-1px) !important;
|
||||
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3) !important;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user