OMS_H5/src/views/ResetPassword/index.vue

294 lines
7.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div class="reset-page">
<div class="reset-container">
<div class="reset-header">
<h1 class="reset-title">修改密码</h1>
</div>
<van-form @submit="submitResetPwd" class="reset-form">
<van-cell-group inset>
<van-field
v-model="form.username"
name="username"
label="账号"
placeholder="请输入账号"
:rules="[{ required: true, message: '请输入账号' }]"
class="reset-input"
/>
<van-field
v-model="form.newPassword"
type="password"
name="newPassword"
label="新密码"
placeholder="请输入新密码"
:rules="newPasswordRules"
class="reset-input"
/>
<van-field
v-model="form.confirmPassword"
type="password"
name="confirmPassword"
label="确认密码"
placeholder="请确认新密码"
:rules="confirmPasswordRules"
class="reset-input"
/>
</van-cell-group>
<div class="reset-subtitle">
密码长度8-20位以下规则中至少满足 3 种:大写字母、小写字母、数字、特殊字符
</div>
<van-cell-group inset>
<van-field
v-model="form.emailCode"
name="emailCode"
label="邮箱验证码"
placeholder="请输入邮箱验证码"
maxlength="6"
:rules="emailCodeRules"
class="reset-input"
/>
</van-cell-group>
<div class="email-code-button">
<van-button
plain
type="primary"
native-type="button"
:loading="emailCodeLoading"
:disabled="emailCodeCountdown > 0"
@click="sendEmailCode"
>
{{ emailCodeCountdown > 0 ? `${emailCodeCountdown}秒后重发` : '发送验证码' }}
</van-button>
</div>
<div class="button-container">
<van-button round block type="primary" native-type="submit" :loading="resetPwdLoading" class="submit-button">
提交
</van-button>
<van-button round block plain type="primary" native-type="button" class="back-button" @click="backToLogin">
返回登录
</van-button>
</div>
</van-form>
</div>
</div>
</template>
<script setup lang="ts">
import { reactive, ref, onBeforeUnmount, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { showFailToast, showSuccessToast } from 'vant'
import { resetLoginPwd, sendResetPwdEmailCode } from '@/api/auth'
import type { ResetPwdParams } from '@/types'
const route = useRoute()
const router = useRouter()
const form = reactive<ResetPwdParams>({
username: '',
newPassword: '',
confirmPassword: '',
emailCode: ''
})
const resetPwdLoading = ref(false)
const emailCodeLoading = ref(false)
const emailCodeCountdown = ref(0)
let emailCodeTimer: ReturnType<typeof setInterval> | null = null
const passwordPattern = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^A-Za-z0-9]).{8,20}$/
const newPasswordRules = [
{ required: true, message: '请输入新密码' },
{ pattern: passwordPattern, message: '不符合密码规则' }
]
const confirmPasswordRules = [
{ required: true, message: '请确认新密码' },
{
validator: (value: string) => value === form.newPassword,
message: '两次输入的密码不一致'
}
]
const emailCodeRules = [
{ required: true, message: '请输入邮箱验证码' },
{ pattern: /^\d{6}$/, message: '邮箱验证码为6位数字' }
]
const clearEmailCodeTimer = () => {
if (emailCodeTimer) {
clearInterval(emailCodeTimer)
emailCodeTimer = null
}
emailCodeCountdown.value = 0
}
const startEmailCodeCountdown = () => {
clearEmailCodeTimer()
emailCodeCountdown.value = 60
emailCodeTimer = setInterval(() => {
if (emailCodeCountdown.value <= 1) {
clearEmailCodeTimer()
} else {
emailCodeCountdown.value--
}
}, 1000)
}
const getResponseMessage = (response: any, defaultMessage: string) => {
return response?.data?.msg || response?.msg || defaultMessage
}
const sendEmailCode = async () => {
if (!form.username) {
showFailToast('请输入账号')
return
}
emailCodeLoading.value = true
try {
const response: any = await sendResetPwdEmailCode(form.username)
if (response.data?.code !== 0) {
showFailToast(getResponseMessage(response, '发送验证码失败'))
return
}
showSuccessToast('验证码已发送')
startEmailCodeCountdown()
} catch (error: any) {
showFailToast(error.response?.data?.msg || error.message || '发送验证码失败')
} finally {
emailCodeLoading.value = false
}
}
const backToLogin = () => {
router.replace('/login')
}
const submitResetPwd = async () => {
resetPwdLoading.value = true
try {
const response: any = await resetLoginPwd(form)
if (response.data?.code !== 0) {
showFailToast(getResponseMessage(response, '密码修改失败'))
return
}
showSuccessToast('密码修改成功,请重新登录')
localStorage.removeItem('savedPassword')
router.replace({
path: '/login',
query: form.username ? { username: form.username } : undefined
})
} catch (error: any) {
showFailToast(error.response?.data?.msg || error.message || '密码修改失败')
} finally {
resetPwdLoading.value = false
}
}
onMounted(() => {
const username = route.query.username
if (typeof username === 'string') {
form.username = username
}
})
onBeforeUnmount(() => {
clearEmailCodeTimer()
})
</script>
<style lang="scss" scoped>
.reset-page {
min-height: 100vh;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
box-sizing: border-box;
}
.reset-container {
width: 100%;
max-width: 400px;
background: white;
border-radius: 16px;
padding: 36px 24px;
box-shadow: 0 15px 35px rgba(50, 50, 93, 0.1), 0 5px 15px rgba(0, 0, 0, 0.07);
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, #1989fa, #07c160, #ff6600);
}
}
.reset-header {
text-align: center;
margin-bottom: 24px;
}
.reset-title {
font-size: 24px;
font-weight: 600;
color: #333;
margin: 0 0 10px;
}
.reset-subtitle {
font-size: 13px;
color: #ee0a24;
line-height: 20px;
margin: 0 32px 12px;
text-align: left;
}
.reset-form {
margin-bottom: 10px;
}
.reset-input {
margin-bottom: 12px;
}
.email-code-button {
padding: 0 16px;
margin-top: 12px;
text-align: right;
.van-button {
height: 34px;
font-size: 14px;
border-radius: 6px;
background: #fff;
}
}
.button-container {
margin-top: 24px;
}
.submit-button,
.back-button {
height: 46px;
font-size: 16px;
}
.back-button {
margin-top: 12px;
}
</style>