天行健,君子以自强不息;地势坤,君子以厚德载物。
每个人都有惰性,但不断学习是好好生活的根本,共勉!
文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。
燕草如碧丝,秦桑低绿枝。
------《春思》
文章目录
20. 找回密码功能实现
实现找回密码功能,此功能只在使用账号密码登录时可用,故在账号密码登录的页面中添加一个忘记密码的按钮即可
20.1 找回密码的布局开发
先对找回密码功能的页面进行布局
在src/views包中创建resetPassword包,在该包中创建ResetPwd.vue组件以及component包
以下为找回密码页面ResetPwd.vue的代码
20.1.1 ResetPwd.vue
重置密码页面
src/views/resetPassword/
ResetPwd.vue
<script setup lang="ts">
import {
ref, onMounted } from 'vue'
import EmailCodeSetPwdForm from './components/EmailCodeSetPwdForm.vue';
import PhoneCodeSetPwdForm from './components/PhoneCodeSetPwdForm.vue';
const curTab = ref(1);
const changeTab = (tab:any)=>{
curTab.value = tab;
}
// const bgColor = "linear-gradient(45deg, #5198d3, #0f9fe2, #61a2d6);";
// 样式变量
const setPwdPagePanelWidth = '40%';
const setPwdPagePanelHeight = '30%';
</script>
<template>
重置密码
<div class="resetpwd-page">
<div class="resetpwd-box">
<div class="tabs">
<div class="tab-item" :class="{'tab-item-selected':curTab==1}" @click="changeTab(1)">手机验证码找回密码</div>
<div class="tab-item" :class="{'tab-item-selected':curTab!=1}" @click="changeTab(2)">邮箱验证码找回密码</div>
</div>
<div class="tab-content">
<!-- <PhoneCodeSetPwdForm v-if="curTab == 1"></PhoneCodeSetPwdForm> -->
<!-- <EmailCodeSetPwdForm v-else></EmailCodeSetPwdForm> -->
</div>
</div>
<div class="resetpwd-footer">
密码重置页面
</div>
</div>
</template>
<style scoped>
.resetpwd-page{
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
/* background: v-bind(bgColor); */
background: linear-gradient(45deg, #5198d3, #0f9fe2, #61a2d6);
display: flex;
/* text-align: center; */
/* justify-items: center; */
/* justify-content: center; */
align-items: center;
}
.resetpwd-page .resetpwd-box{
background-color: #fff;
height: 50%;
/* height: v-bind(setPwdPagePanelWidth); */
width: 60%;
/* width: v-bind(setPwdPagePanelHeight); */
/* min-height: 800px; */
margin: 0 auto;
text-align: center;
border-radius: 10px;
/* box-shadow: var(--el-box-shadow); */
box-shadow: 0 0 10px 10px #00000055;
padding: 40px;
}
.resetpwd-page .resetpwd-box .tabs{
/* height:20px; */
height: 5%;
/* width: 400px; */
width: 40%;
line-height: 40px;
display: flex;
margin: 0 auto;
}
.resetpwd-page .resetpwd-box .tabs .tab-item{
/* width: 200px; */
width: 50%;
height: 40px;
/* height: 180%; */
text-align: center;
background-color: #00000055;
font-size: 16px;
cursor: pointer;
/* border-radius: 5px; */
}
.resetpwd-page .resetpwd-box .tabs .tab-item:first-child{
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
.resetpwd-page .resetpwd-box .tabs .tab-item:last-child{
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
.resetpwd-page .resetpwd-box .tabs .tab-item:hover,
.resetpwd-page .resetpwd-box .tabs .tab-item-selected{
color: white;
background-color: #0ba4eb;
}
.resetpwd-page .resetpwd-box .tab-content{
/* padding-top: 60px; */
padding-top: 5%;
/* display: flex=1; */
/* justify-content: center; */
/* padding-left: 10%; */
/* padding: 10%; */
/* padding: 50px; */
/* align-items: center; */
/* text-align: center; */
/* height: 400px; */
height: 100%;
/* width: 600px; */
width: 100%;
}
.resetpwd-page .resetpwd-footer{
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 10%;
text-align: center;
color: white;
font-size: 15px;
}
</style>
20.1.2 router/index.ts
在路由中引入新建的页面,然后才能全局跳转
{
path: '/ResetPwd',
component: ResetPwd
}
完整代码如下
src/router/
index.ts
import {
createRouter, createWebHistory } from 'vue-router'
// 自定义路由组件或从其他文件导入,这里选择从其他文件导入
import UserLogin from "../views/login/UserLogin.vue";
// import UserLogin from '@/views/login/UserLogin.vue';
import HomeIndex from '@/views/index/HomeIndex.vue';
import ResetPwd from '@/views/resetPassword/ResetPwd.vue';
// import ResetPwd from '../views/resetPassword/ResetPwd.vue';
// 定义一些路由,每个路由都需要映射到一个组件,
const routes = [
{
path: '/',
// component: UserLogin
redirect: "/HomeIndex"
},
{
path: '/UserLogin',
component: UserLogin
},
{
path: '/HomeIndex',
component: HomeIndex
},
{
path: '/ResetPwd',
component: ResetPwd
}
]
// 创建路由实例并传递'routes'配置 你可以在这里输入更多的配置
const router = createRouter({
history: createWebHistory(),
// routes:routes可以简写成routes,不会报错
// routes:[]
routes
})
export default router
20.1.3 UsernameForm.vue
在账号密码登录的页面中添加忘记密码的按钮,点击可跳转到重置密码页面
<div class="flexItem" >
<!-- <el-form-item prop="savePassword"> -->
<router-link to="/ResetPwd">忘记密码</router-link>
<!-- </el-form-item> -->
</div>
完整代码如下
src/views/login/components/
UsernameForm.vue
<script setup lang="ts">
import {
ref,reactive, onMounted } from 'vue'
// 引入状态存储store
import {
useStore } from 'vuex'
// 引入路由工具router
import {
useRouter } from 'vue-router'
// 引入工具方法
import utils from '../../../utils/utils'
import api from '../../../api/api'
// 登录表单的实例
// let loginFormRef = ref(null);
let loginFormRef = ref();
// 登录表单的数据
const loginForm = reactive({
// 用户名
username: '',
// 密码
password: '',
// 图片验证
imgcode: '',
// 记住用户名,默认否
saveUsername: false,
// 记住用户名,默认否
savePassword: false
});
// 登录验证规则
const rules = ({
username:[{
required: true,
message: '请输入用户名',
trigger: 'blur'
}],
password:[{
required: true,
message: '请输入密码',
trigger: 'blur'
}],
imgcode:[{
required: true,
message: '请输入图片验证码',
trigger: 'blur'
}]
});
const formSize = "";
// 图片验证码路径
let imgCodeSrc = new URL("../../../assets/code.png", import.meta.url).href;
// const imgCodeSrc = '../../../assets/code.png';
// 刷新图片验证码
const getImgCode = () => {
// 后续改为从服务器上获取动态图片
imgCodeSrc = new URL("../../../assets/code.png", import.meta.url).href;
};
// 全局状态存储
const store = useStore();
// 路由调用
const router = useRouter();
// 登录提交事件
const onSubmit = () => {
// form表单中的值,校验
loginFormRef.value.validate((valid:string, fileds:any)=>{
// 如果valid值为假,则遍历输出报错
if(!valid){
for(let key in fileds){
// 获取报错信息中的字段对应的key的索引为0的信息
utils.showError(fileds[key][0].message);
}
return;
}
// 登录表单的记住用户名如果被勾选
if(loginForm.saveUsername){
// 保存输入的用户名
utils.saveData('username', loginForm.username);
// 保存被勾选的操作
utils.saveData('saveUsername', loginForm.saveUsername);
}else{
// 如果记住用户名的勾选取消,则移除这两个存储的内容
utils.removeData('username');
utils.removeData('saveUsername');
}
// 登录表单的记住用户名如果被勾选
if(loginForm.savePassword){
// 保存输入的用户名
utils.saveData('password', loginForm.password);
// 保存被勾选的操作
utils.saveData('savePassword', loginForm.savePassword);
}else{
// 如果记住用户名的勾选取消,则移除这两个存储的内容
utils.removeData('password');
utils.removeData('savePassword');
}
// TODO 调用接口登录
utils.showLoadding("正在加载中");
api({
method: 'get',
url: '/login/login',
params: {
username: loginForm.username,
password: loginForm.password
}
}).then((res)=>{
utils.hideLoadding();
if(res.status != 200 || res.data.result != 200){
utils.showError("登录失败-请求数据返回有误");
return;
}
if(res.data.login == 1){
utils.showSuccess("登录成功");
// 存储用户信息
// let userInfoLogin = res.data.login;
let userInfoLogin = res.data;
let token = res.data.token;
console.log("usernamelogin:", token);
store.commit('setUserInfo', userInfoLogin);
store.commit('setToken', token);
console.log("----------------token: ", token);
// 登录成功后跳转主页
router.push('/HomeIndex');
}else if(res.data.login == 0){
utils.showError("登录失败-用户不存在");
return;
}else if(res.data.login == 2){
utils.showError("登录失败-密码错误");
return;
}
// utils.showError("登录失败-返回数据错误")
}).catch((error)=>{
console.log(error);
utils.showError("登录失败-发生异常");
});
// 登录成功提示
// utils.showSuccess("登录成功");
});
};
// 挂载
onMounted(() => {
// 获取记住用户名的值
loginForm.saveUsername = utils.getData('saveUsername');
// 如果记住用户名被勾选,则获取用户名显示
if(loginForm.saveUsername==true){
loginForm.username = utils.getData('username');
}
// 获取记住密码的值
loginForm.savePassword = utils.getData('savePassword');
// 如果记住密码被勾选,则获取密码
if(loginForm.savePassword==true){
loginForm.password = utils.getData('password');
}
});
</script>
<template>
<!-- 用户密码登录 -->
<div class="usernameLoginBox">
<el-form
ref="loginFormRef"
style="max-width: 600px"
:model="loginForm"
:rules="rules"
label-width="0"
class="loginFrom"
:size="formSize" status-icon>
<!-- 用户名 -->
<el-form-item prop="username">
<!-- 图标设置,动态绑定username,提示信息,设置输入框大小 -->
<el-input prefix-icon="UserFilled" v-model="loginForm.username" placeholder="请输入用户名" size='large' />
</el-form-item>
<!-- 密码 -->
<el-form-item prop="password">
<!-- 密码 -->
<div class="flexItem" >
<!-- show-password 属性表示是否显示切换显示密码的图标,true为显示 -->
<!-- <el-input prefix-icon="Lock" show-password="off" type="password" v-model="loginForm.password" placeholder="请输入密码" size='large' /> -->
<el-input prefix-icon="Lock" show-password type="password" v-model="loginForm.password" placeholder="请输入密码" size='large' />
</div>
</el-form-item>
<!-- 图片验证 -->
<el-form-item prop="imgcode">
<!-- 使用两个div块来左右布局验证码输入和获取验证码按钮的实现 -->
<div class="flex loginLine">
<div class="flexItem" >
<el-input prefix-icon="Picture" v-model="loginForm.imgcode" placeholder="请输入图片验证码" size='large' />
<!-- <el-input prefix-icon="Iphone" v-model="loginForm.smscode" placeholder="请输入验证码" size='large' /> -->
</div>
<div class="codeBtn" >
<el-image :src="imgCodeSrc" size='large' @click="getImgCode" ></el-image>
<!-- <el-button type="primary" size="large" @click="getSmsCode" class="" >获取验证码</el-button> -->
</div>
</div>
</el-form-item>
<!-- <el-form-item prop="saveUsername"> -->
<el-form-item >
<!-- 记住账号密码的勾选 -->
<div class="flex loginLine" >
<!-- 记住用户名 -->
<div class="flexItem" >
<el-form-item prop="saveUsername">
<el-checkbox v-model="loginForm.saveUsername">记住用户名</el-checkbox>
</el-form-item>
</div>
<!-- 记住密码 -->
<div class="flexItem" >
<el-form-item prop="savePassword">
<el-checkbox v-model="loginForm.savePassword">记住密码</el-checkbox>
</el-form-item>
</div>
<div class="flexItem" >
<!-- <el-form-item prop="savePassword"> -->
<router-link to="/ResetPwd">忘记密码</router-link>
<!-- </el-form-item> -->
</div>
</div>
</el-form-item>
<!-- <el-form-item prop="savePassword"> -->
<!-- </el-form-item> -->
<!-- 登录按钮 -->
<el-form-item>
<el-button class="loginBtn" type="danger" size='large' @click="onSubmit">登录</el-button>
</el-form-item>
</el-form>
</div>
</template>
<style scoped>
/* 按钮宽度设为最大 */
.loginBtn{
width: 100%;
/* 登录按钮圆角边框 */
border-radius: 20px;
}
/* 验证码按钮样式配置 */
.codeBtn{
width: 100px;
margin-left: 10px;
}
/* 按钮和图片宽度100px */
.codeBtn:deep(.el-button),
.codeBtn:deep(img){
width: 100px;
/* height: 40px; */
}
/* 验证码图片高度 */
.codeBtn:deep(img){
height: 40px;
/* 鼠标移上去会变成手型 */
cursor: pointer;
}
/* 这一行宽度占满 */
.loginLine{
width: 100%
}
</style>
20.1.4 页面效果
查看账号密码登录界面,出现忘记密码链接

点击忘记密码,跳转到密码重置界面

20.2 短信验证码找回密码
布局配置好后,进行短信验证功能的实现
20.2.1 PhoneCodeSetPwdForm.vue
使用短信验证码设置密码的页面
完整代码如下
src/views/resetPassword/components/
PhoneCodeSetPwdForm.vue
<script setup lang="ts">
// vue基础模块引入
import {
ref, reactive, onMounted, onUnmounted } from 'vue'
// 引入状态存储工具store
import {
useStore} from 'vuex'
// 引入工具方法
import utils from '../../../utils/utils'
import api from '../../../api/api'
// 路由引入
import {
useRoute, useRouter } from 'vue-router';
// 引入密码重置页面组件
import ResetPwdForm from './ResetPwdForm.vue';
//import ResetSuccess from './ResetSuccess.vue';
const formSize = ""
// 步骤选择
const setStep = ref(1);
// 表单数据对象
const resetPwdForm = reactive({
// 用户名
username: '',
// 短信验证码
smscode: '',
// 图片验证码
imgcode: '',
});
// 表单验证规则
const rules = ref({
username: [{
required: true,
message: '请输入用户名',
trigger: 'blur'
}],
smscode: [{
required: true,
message: '请输入短信验证码',
trigger: 'blur'
}],
imgcode: [{
required: true,
message: '请输入图片验证码',
trigger: 'blur'
}]
});
// 获取短信验证码的按钮文本值
let smsCodeBtnText = ref("获取验证码")
// 定时器
let timer:any = null;
// 短信验证码获取的间隔事件
let curTime = 0;
// 获取验证码按钮
const getSmsCode = ()=>{
if(!resetPwdForm.username){
utils.showError("请先输入用户名");
return;
}
// 发送请求生成短信验证码
api({
method: 'post',
url: '/login/redis/setMessageCode',
params: {
username: resetPwdForm.username
}
});
// 同时进行倒计时,读秒60,结束后可重新获取
curTime = 60
timer = setInterval(() => {
curTime--;
// 值重新赋值
smsCodeBtnText.value = curTime+'秒后重新获取';
// 当及时归零时,可重新获取,并将计时器重置
if(curTime<=0){
smsCodeBtnText.value = '获取验证码'
clearInterval(timer);
timer = null;
}
},1000);
}
// 图片验证码路径
let imageCodeSrc = new URL('../../../assets/code.png',import.meta.url).href
// 刷新图片验证码
const getImgCode = () => {
// 从服务器动态获取图片验证码
imageCodeSrc = new URL('../../../assets/code.png',import.meta.url).href
}
const resetPwdFormRef = ref();
// 下一步按钮
const nextSet = () => {
// 表单校验,校验所填表单中是否有值,无值则报错
resetPwdFormRef.value.validate((valid:string, fileds:any)=>{
// 如果valid值为假,则输出报错内容
if(!valid){
for(let key in fileds){
utils.showError(fileds[key][0].message);
return;
}
return;
}
// 加载效果
utils.showLoadding("正在加载中");
// if(resetPwdForm.smscode){
// utils.showError("验证码错误,请重新输入");
// }
// 校验填写的验证码是否一致
api({
method: 'get',
url: 'login/redis/getMessageCode',
params: {
username: resetPwdForm.username
}
}).then((res)=>{
utils.hideLoadding();
// 如果数据返回状态码不是200或请求结果返回不是200或者请求结果返回的短信验证码为空,验证失败
if(res.status!=200||res.data.result!=200||!res.data.msgCode){
utils.showError("验证失败-请求数据返回有误");
return;
}
// 如果填入的短信验证码和收到的短信验证码一致,则验证成功,跳转到修改密码界面
if(res.data.msgCode == resetPwdForm.smscode){
utils.showSuccess("验证成功");
setStep.value = 2;
}else{
utils.showError("验证失败-验证码错误");
}
}).catch((error)=>{
setStep.value = 2;
utils.hideLoadding();
console.log(error);
utils.showError("验证失败-出现异常");
});
});
}
// const systemToken = ref('');
// const toPhoneCodeSetPwdForm = ()=>{
// setStep.value = 1;
// }
// const toResetSuccess = ()=>{
// setStep.value = 3;
// }
</script>
<template>
<!-- <div class="stepLine"> -->
<el-steps style="max-width: 2000px" :active="setStep" align-center>
<el-step title="身份验证" description="请输入账号和验证码进行身份确认" />
<el-step title="密码重置" description="填写新密码并确认" />
<el-step title="重置成功" description="密码修改成功" />
</el-steps>
<!-- </div> -->
<div v-if="setStep == 1" class="phone-reset-password-form">
<el-form
ref="resetPwdFormRef"
style="max-width: 600px;"
:model="resetPwdForm"
:rules="rules"
label-width="0"
class="resetPwdForm"
:size="formSize"
status-icon
>
<!-- 用户名 -->
<el-form-item prop="username">
<el-input
prefix-icon="UserFilled"
v-model="resetPwdForm.username"
placeholder="用户名"
size="large"
/>
</el-form-item>
<!-- 获取验证码 -->
<el-form-item prop="smscode">
<div class="flex resetLine">
<div class="flexItem">
<el-input
prefix-icon="Iphone"
v-model="resetPwdForm.smscode"
placeholder="短信验证码"
size="large"
/>
</div>
<div class="codeBtn">
<el-button type="primary" size="large" @click="getSmsCode" :disabled="curTime>0">
{
{
smsCodeBtnText }}
</el-button>
</div>
</div>
</el-form-item>
<!-- 图片验证码 -->
<el-form-item prop="imgcode">
<div class="flex resetLine">
<div class="flexItem">
<el-input
prefix-icon="Picture"
v-model="resetPwdForm.imgcode"
placeholder="图片验证码"
size="large"
/>
</div>
<div class="codeBtn">
<el-image :src="imageCodeSrc" size="large" @click="getImgCode"></el-image>
</div>
</div>
</el-form-item>
<!-- 下一步按钮 -->
<el-form-item>
<!-- <div class="nextBtn"> -->
<el-button class="nextBtn" type="primary" size="large" @click="nextSet">下一步</el-button>
<!-- </div> -->
</el-form-item>
</el-form>
</div>
<!-- <ResetPwdForm v-else-if="setStep == 2"
:systemToken="systemToken"
@pre="toPhoneCodeSetPwdForm"
@next="toResetSuccess"
></ResetPwdForm> -->
<ResetPwdForm v-else-if="setStep == 2" ></ResetPwdForm>
<!-- <ResetSuccess v-else></ResetSuccess> -->
</template>
<style scoped>
.phone-reset-password-form{
padding: 5%;
/* margin-top: 2%; */
margin: 2% auto;
width: 60%;
height: 40%;
/* text-align: center; */
background-color: rgb(204, 240, 210);
display: flex;
justify-content: center;
/* justify-items: center; */
}
.codeBtn{
/* width: 100px; */
margin-left: 10px;
/* margin-bottom: 10px; */
}
/* .codeBtn:deep(.el-button),
.codeBtn:deep(img){
width: 100px;
} */
.codeBtn:deep(img){
height: 40px;
cursor: pointer;
}
.resetLine{
width: 100%;
}
.nextBtn{
width: 100%;
/* display: flex; */
/* justify-content: flex-end; */
/* justify-items: right; */
/* text-align: right; */
/* float: right; */
}
</style>
20.2.2 ResetPwd.vue密码重置页面中引入短信验证页
在ResetPwd.vue中引入PhoneCodeSetPwdForm.vue,在选择手机验证码重置密码时显示短信验证页面
完整代码
src/views/resetPassword/
ResetPwd.vue
<script setup lang="ts">
import {
ref, reactive, onMounted } from 'vue'
import utils from '@/utils/utils';
// 表单对象
const resetPwdForm = reactive({
newPassword: '',
reNewPassword: '',
});
// 检测两次密码是否一致
// const validatePassword = (rule, value, callback)=>{
const validatePassword = (rule:any, value:any, callback:any)=>{
if(value != resetPwdForm.newPassword){
callback(new Error('两次密码不一致'));
}else{
callback();
}
};
// 表单输入校验
const rules = reactive({
newPassword: [
{
required: true,
message: '请输入新密码',
trigger: 'blur'
},
{
// 定义输入内容长度
min: 6,
max: 12,
message: '密码长度6-12位',
trigger: 'blur'
}
],
reNewPassword: [
{
required: true,
message: '请再次输入新密码',
trigger: 'blur'
},
{
// 调用校验函数进行校验
validator: validatePassword,
trigger: 'blur'
}
]
});
// 表单校验对象
const resetPwdFormRef = ref();
// 当前页
let setStep = ref(2);
// 自定义事件
// const emits = defineEmits([
// 'pre',
// 'next'
// ]);
// 上一步
// const preSet = () =>{
// emits('pre');
// };
// 外部参数获取,传递上一步获取的用于账号验证的token信息
// const option = defineProps({
// systemToken: {
// type: String,
// required: true
// }
// });
// 下一步
const nextSet = () =>{
resetPwdFormRef.value.validate((valid:string, fields:any)=>{
if(!valid){
for(let key in fields){
utils.showError(fields[key][0].message);
}
return;
}
// 调用接口验证密码和用户,进行密码修改
// emits('next');
// if(resetPwdForm.newPassword == resetPwdForm.reNewPassword){
// // 调用接口进行修改
// utils.showSuccess("密码设置成功");
// setStep.value = 3
// }else{
// utils.showError("密码不一致,请重新输入");
// }
});
};
</script>
<template>
<div v-if="setStep == 2" class="resetPwdForm">
<el-form ref="resetPwdFormRef"
style="max-width: 600px; "
:model="resetPwdForm"
:rules="rules"
label-width="auto"
class="resetPwdForm"
status-icon
>
<!-- 新密码 -->
<el-form-item label="新的密码:" prop="newPassword">
<el-input
prefix-icon="Key"
type="password"
show-password
v-model="resetPwdForm.newPassword"
placeholder="请输入新密码"
size="large"
/>
</el-form-item>
<!-- 确认新密码 -->
<el-form-item label="确认密码:" prop="reNewPassword">
<el-input
prefix-icon="Key"
type="password"
show-password
v-model="resetPwdForm.reNewPassword"
placeholder="请再次输入新密码"
size="large"
/>
</el-form-item>
<el-form-item>
<div class="flex preNextLine">
<div class="flexItem">
<!-- 上一步按钮 -->
<el-button class="resetBtn" type="primary" size="large" @click="preSet">上一步</el-button>
</div>
<div class="middleBtn">
</div>
<div class="flexItem">
<!-- 下一步按钮 -->
<el-button class="resetBtn" type="primary" size="large" @click="nextSet">下一步</el-button>
</div>
</div>
</el-form-item>
</el-form>
</div>
<!-- <PhoneCodeSetPwdForm v-else-if="setStep == 1"></PhoneCodeSetPwdForm> -->
<!-- <ResetSuccess v-else></ResetSuccess> -->
</template>
<style scoped>
.resetPwdForm{
height: 50%;
width: 60%;
padding-top: 1%;
margin: 2% auto;
justify-content: center;
background-color: rgb(178, 189, 185)
}
.resetPwdForm .preNextLine{
width: 100%;
margin-top: 10%;
}
.resetPwdForm .preNextLine .resetBtn{
width: 80%;
}
.resetPwdForm .preNextLine .middleBtn{
width: 30%;
}
</style>
20.2.3 获取短信验证码页面的效果
此时页面如下,共两部分,进度提示和下方的信息验证

使用用户名和验证码验证身份,用户名是后台数据库中存储的账号名,我这里是libai,短信验证是通过点击按钮调用后台接口生成到redis中的临时六位数字,图片验证码可填任意字符,然后点击下一步

20.2.4 ResetPwdForm.vue重置密码页面的实现
该页面是在身份校验通过后跳转到的设置密码界面,输入密码后调用接口进行修改表中账号对应的密码
src/views/resetPassword/components/
ResetPwdForm.vue
<script setup lang="ts">
import {
ref, reactive, onMounted } from 'vue'
import utils from '@/utils/utils';
// 表单对象
const resetPwdForm = reactive({
newPassword: '',
reNewPassword: '',
});
// 检测两次密码是否一致
// const validatePassword = (rule, value, callback)=>{
const validatePassword = (rule:any, value:any, callback:any)=>{
if(value != resetPwdForm.newPassword){
callback(new Error('两次密码不一致'));
}else{
callback();
}
};
// 表单输入校验
const rules = reactive({
newPassword: [
{
required: true,
message: '请输入新密码',
trigger: 'blur'
},
{
// 定义输入内容长度
min: 6,
max: 12,
message: '密码长度6-12位',
trigger: 'blur'
}
],
reNewPassword: [
{
required: true,
message: '请再次输入新密码',
trigger: 'blur'
},
{
// 调用校验函数进行校验
validator: validatePassword,
trigger: 'blur'
}
]
});
// 表单校验对象
const resetPwdFormRef = ref();
// 当前页
let setStep = ref(2);
// 自定义事件
// const emits = defineEmits([
// 'pre',
// 'next'
// ]);
// 上一步
// const preSet = () =>{
// emits('pre');
// };
// 外部参数获取,传递上一步获取的用于账号验证的token信息
// const option = defineProps({
// systemToken: {
// type: String,
// required: true
// }
// });
// 下一步
const nextSet = () =>{
resetPwdFormRef.value.validate((valid:string, fields:any)=>{
if(!valid){
for(let key in fields){
utils.showError(fields[key][0].message);
}
return;
}
// 调用接口验证密码和用户,进行密码修改
// emits('next');
// if(resetPwdForm.newPassword == resetPwdForm.reNewPassword){
// // 调用接口进行修改
// utils.showSuccess("密码设置成功");
// setStep.value = 3
// }else{
// utils.showError("密码不一致,请重新输入");
// }
});
};
</script>
<template>
<div v-if="setStep == 2" class="resetPwdForm">
<el-form ref="resetPwdFormRef"
style="max-width: 600px; "
:model="resetPwdForm"
:rules="rules"
label-width="auto"
class="resetPwdForm"
status-icon
>
<!-- 新密码 -->
<el-form-item label="新的密码:" prop="newPassword">
<el-input
prefix-icon="Key"
type="password"
show-password
v-model="resetPwdForm.newPassword"
placeholder="请输入新密码"
size="large"
/>
</el-form-item>
<!-- 确认新密码 -->
<el-form-item label="确认密码:" prop="reNewPassword">
<el-input
prefix-icon="Key"
type="password"
show-password
v-model="resetPwdForm.reNewPassword"
placeholder="请再次输入新密码"
size="large"
/>
</el-form-item>
<el-form-item>
<div class="flex preNextLine">
<div class="flexItem">
<!-- 上一步按钮 -->
<el-button class="resetBtn" type="primary" size="large" @click="preSet">上一步</el-button>
</div>
<div class="middleBtn">
</div>
<div class="flexItem">
<!-- 下一步按钮 -->
<el-button class="resetBtn" type="primary" size="large" @click="nextSet">下一步</el-button>
</div>
</div>
</el-form-item>
</el-form>
</div>
<!-- <PhoneCodeSetPwdForm v-else-if="setStep == 1"></PhoneCodeSetPwdForm> -->
<!-- <ResetSuccess v-else></ResetSuccess> -->
</template>
<style scoped>
.resetPwdForm{
height: 50%;
width: 60%;
padding-top: 1%;
margin: 2% auto;
justify-content: center;
background-color: rgb(178, 189, 185)
}
.resetPwdForm .preNextLine{
width: 100%;
margin-top: 10%;
}
.resetPwdForm .preNextLine .resetBtn{
width: 80%;
}
.resetPwdForm .preNextLine .middleBtn{
width: 30%;
}
</style>
此刻同时先把设置成功后的界面也创建出来,
src/views/resetPassword/components/
ResetSuccess.vue
<script setup lang="ts">
</script>
<template>
重置密码成功
</template>
<style scoped>
</style>
20.2.5 设置密码的页面效果展示
身份验证通过后进入输入新密码的页面,如下

此时该页面的上一步和下一步还没生效,需要将上一步、下一步对应的页面和当前页面绑定
20.2.6 设置密码后的上一步和下一步配置
上一步和下一步需要在代码中使用defineEmits()进行事件传递,还有如果使用了token进行上一步和下一步的参数传递,会用到defineProps()
设置密码页面的代码新增如下
src/views/resetPassword/components/
ResetPwdForm.vue
<script setup lang="ts">
import {
ref, reactive } from 'vue'
import utils from '@/utils/utils';
import api from '@/api/api';
// 表单对象
const resetPwdForm = reactive({
newPassword: '',
reNewPassword: '',
});
// 检测两次密码是否一致
// const validatePassword = (rule, value, callback)=>{
const validatePassword = (rule:any, value:any, callback:any)=>{
if(value != resetPwdForm.newPassword){
callback(new Error('两次密码不一致'));
}else{
callback();
}
};
// 表单输入校验
const rules = reactive({
newPassword: [
{
required: true,
message: '请输入新密码',
trigger: 'blur'
},
{
// 定义输入内容长度
min: 6,
max: 12,
message: '密码长度6-12位',
trigger: 'blur'
}
],
reNewPassword: [
{
required: true,
message: '请再次输入新密码',
trigger: 'blur'
},
{
// 调用校验函数进行校验
validator: validatePassword,
trigger: 'blur'
}
]
});
// 表单校验对象
const resetPwdFormRef = ref();
// 当前页
//let setStep = ref(2);
// 自定义事件
const emits = defineEmits([
'pre',
'next'
]);
// 上一步
const preSet = () =>{
emits('pre');
};
// 外部参数获取,传递上一步获取的用于账号验证的token信息
const option = defineProps({
// 从上一步的组件中获取参数
usernames: String,
systemToken: {
type: String,
required: true
}
});
const username = option.usernames;
// 下一步
const nextSet = () =>{
resetPwdFormRef.value.validate((valid:string, fields:any)=>{
if(!valid){
for(let key in fields){
utils.showError(fields[key][0].message);
}
return;
}
utils.showLoadding("正在加载");
// 调用接口验证密码和用户,进行密码修改
api({
method: 'post',
url: '/user/changePassword',
params: {
username: username,
password: resetPwdForm.newPassword
}
}).then((res)=>{
utils.hideLoadding();
if( res.status!=200){
utils.showError("请求失败-请求返回有误");
return;
}
if(res.data.result==200){
utils.showSuccess("密码修改成功");
emits('next');
}
}).catch((error)=>{
utils.hideLoadding();
console.log(error);
utils.showError("密码修改失败-出现异常");
});
// emits('next');
});
};
</script>
<template>
<div class="resetPwdForm">
<el-form ref="resetPwdFormRef"
style="max-width: 600px; "
:model="resetPwdForm"
:rules="rules"
label-width="auto"
class="resetPwdForm"
status-icon
>
<!-- 新密码 -->
<el-form-item label="新的密码:" prop="newPassword">
<el-input
prefix-icon="Key"
type="password"
show-password
v-model="resetPwdForm.newPassword"
placeholder="请输入新密码"
size="large"
/>
</el-form-item>
<!-- 确认新密码 -->
<el-form-item label="确认密码:" prop="reNewPassword">
<el-input
prefix-icon="Key"
type="password"
show-password
v-model="resetPwdForm.reNewPassword"
placeholder="请再次输入新密码"
size="large"
/>
</el-form-item>
<el-form-item>
<div class="flex preNextLine">
<div class="flexItem">
<!-- 上一步按钮 -->
<el-button class="resetBtn" type="primary" size="large" @click="preSet">上一步</el-button>
</div>
<div class="middleBtn">
</div>
<div class="flexItem">
<!-- 下一步按钮 -->
<el-button class="resetBtn" type="primary" size="large" @click="nextSet">下一步</el-button>
</div>
</div>
</el-form-item>
</el-form>
</div>
</template>
<style scoped>
.resetPwdForm{
height: 50%;
width: 60%;
padding-top: 1%;
margin: 2% auto;
justify-content: center;
background-color: rgb(178, 189, 185)
}
.resetPwdForm .preNextLine{
width: 100%;
margin-top: 10%;
}
.resetPwdForm .preNextLine .resetBtn{
width: 80%;
}
.resetPwdForm .preNextLine .middleBtn{
width: 30%;
}
</style>
手机验证码修改密码的页面的代码新增如下
src/views/resetPassword/components/
PhoneCodeSetPwdForm.vue
<script setup lang="ts">
// vue基础模块引入
import {
ref, reactive, onMounted, onUnmounted } from 'vue'
// 引入状态存储工具store
// import {useStore} from 'vuex'
// 引入工具方法
import utils from '../../../utils/utils'
import api from '../../../api/api'
// 路由引入
// import { useRoute, useRouter } from 'vue-router';
// 引入密码重置页面组件
import ResetPwdForm from './ResetPwdForm.vue';
import ResetSuccess from './ResetSuccess.vue';
const formSize = ""
// 步骤选择
const setStep = ref(1);
// 表单数据对象
const resetPwdForm = reactive({
// 用户名
username: '',
// 短信验证码
smscode: '',
// 图片验证码
imgcode: '',
});
// 表单验证规则
const rules = ref({
username: [{
required: true,
message: '请输入用户名',
trigger: 'blur'
}],
smscode: [{
required: true,
message: '请输入短信验证码',
trigger: 'blur'
}],
imgcode: [{
required: true,
message: '请输入图片验证码',
trigger: 'blur'
}]
});
// 获取短信验证码的按钮文本值
let smsCodeBtnText = ref("获取验证码")
// 定时器
let timer:any = null;
// 短信验证码获取的间隔事件
let curTime = 0;
// 获取验证码按钮
const getSmsCode = ()=>{
if(!resetPwdForm.username){
utils.showError("请先输入用户名");
return;
}
// 发送请求生成短信验证码
api({
method: 'post',
url: '/login/redis/setMessageCode',
params: {
username: resetPwdForm.username
}
});
// 同时进行倒计时,读秒60,结束后可重新获取
curTime = 60
timer = setInterval(() => {
curTime--;
// 值重新赋值
smsCodeBtnText.value = curTime+'秒后重新获取';
// 当及时归零时,可重新获取,并将计时器重置
if(curTime<=0){
smsCodeBtnText.value = '获取验证码'
clearInterval(timer);
timer = null;
}
},1000);
}
// 图片验证码路径
let imageCodeSrc = new URL('../../../assets/code.png',import.meta.url).href
// 刷新图片验证码
const getImgCode = () => {
// 从服务器动态获取图片验证码
imageCodeSrc = new URL('../../../assets/code.png',import.meta.url).href
}
const resetPwdFormRef = ref();
// 下一步按钮
const nextSet = () => {
// 表单校验,校验所填表单中是否有值,无值则报错
resetPwdFormRef.value.validate((valid:string, fileds:any)=>{
// 如果valid值为假,则输出报错内容
if(!valid){
for(let key in fileds){
utils.showError(fileds[key][0].message);
return;
}
return;
}
// 加载效果
utils.showLoadding("正在加载中");
// if(resetPwdForm.smscode){
// utils.showError("验证码错误,请重新输入");
// }
// 校验填写的验证码是否一致
api({
method: 'get',
url: 'login/redis/getMessageCode',
params: {
username: resetPwdForm.username
}
}).then((res)=>{
utils.hideLoadding();
// 如果数据返回状态码不是200或请求结果返回不是200或者请求结果返回的短信验证码为空,验证失败
if(res.status!=200||res.data.result!=200||!res.data.msgCode){
utils.showError("验证失败-请求数据返回有误");
return;
}
// 如果填入的短信验证码和收到的短信验证码一致,则验证成功,跳转到修改密码界面
if(res.data.msgCode == resetPwdForm.smscode){
utils.showSuccess("验证成功");
setStep.value = 2;
}else{
utils.showError("验证失败-验证码错误");
}
}).catch((error)=>{
setStep.value = 2;
utils.hideLoadding();
console.log(error);
utils.showError("验证失败-出现异常");
});
});
}
const systemToken = ref('');
// const susername = resetPwdForm.username;
// systemToken.value = resetPwdForm.username;
const toPhoneCodeSetPwdForm = ()=>{
setStep.value = 1;
}
const toResetSuccess = ()=>{
setStep.value = 3;
}
</script>
<template>
<!-- <div class="stepLine"> -->
<el-steps style="max-width: 2000px" :active="setStep" align-center>
<el-step title="身份验证" description="请输入账号和验证码进行身份确认" />
<el-step title="密码重置" description="填写新密码并确认" />
<el-step title="重置成功" description="密码修改成功" />
</el-steps>
<!-- </div> -->
<div v-if="setStep == 1" class="phone-reset-password-form">
<el-form
ref="resetPwdFormRef"
style="max-width: 600px;"
:model="resetPwdForm"
:rules="rules"
label-width="0"
class="resetPwdForm"
:size="formSize"
status-icon
>
<!-- 用户名 -->
<el-form-item prop="username">
<el-input
prefix-icon="UserFilled"
v-model="resetPwdForm.username"
placeholder="用户名"
size="large"
/>
</el-form-item>
<!-- 获取验证码 -->
<el-form-item prop="smscode">
<div class="flex resetLine">
<div class="flexItem">
<el-input
prefix-icon="Iphone"
v-model="resetPwdForm.smscode"
placeholder="短信验证码"
size="large"
/>
</div>
<div class="codeBtn">
<el-button type="primary" size="large" @click="getSmsCode" :disabled="curTime>0">
{
{
smsCodeBtnText }}
</el-button>
</div>
</div>
</el-form-item>
<!-- 图片验证码 -->
<el-form-item prop="imgcode">
<div class="flex resetLine">
<div class="flexItem">
<el-input
prefix-icon="Picture"
v-model="resetPwdForm.imgcode"
placeholder="图片验证码"
size="large"
/>
</div>
<div class="codeBtn">
<el-image :src="imageCodeSrc" size="large" @click="getImgCode"></el-image>
</div>
</div>
</el-form-item>
<!-- 下一步按钮 -->
<el-form-item>
<!-- <div class="nextBtn"> -->
<el-button class="nextBtn" type="primary" size="large" @click="nextSet">下一步</el-button>
<!-- </div> -->
</el-form-item>
</el-form>
</div>
<!-- usernames表示将当前数据的只绑定到usernames中,通过在别的页面中使用defineProps获取 -->
<ResetPwdForm v-else-if="setStep == 2"
:systemToken="systemToken"
@pre="toPhoneCodeSetPwdForm"
@next="toResetSuccess"
:usernames = resetPwdForm.username
></ResetPwdForm>
<!-- <ResetPwdForm v-else-if="setStep == 2" ></ResetPwdForm> -->
<ResetSuccess v-else></ResetSuccess>
</template>
<style scoped>
.phone-reset-password-form{
padding: 5%;
/* margin-top: 2%; */
margin: 2% auto;
width: 60%;
height: 40%;
background-color: rgb(204, 240, 210);
display: flex;
justify-content: center;
}
.codeBtn{
margin-left: 10px;
}
.codeBtn:deep(img){
height: 40px;
cursor: pointer;
}
.resetLine{
width: 100%;
}
.nextBtn{
width: 100%;
}
</style>
以上实现后,在设置密码页面点击上一步会跳转到身份验证界面,点击下一步会跳转到密码设置成功界面,密码设置成功的界面下面接着完善
20.2.7 ResetSuccess.vue
在设置密码后,点击下一步,跳转到密码设置成功界面
在当前成功页面中,提示五秒后自动跳转到登录页面,密码设置成功的页面代码如下
src/views/resetPassword/components/
ResetSuccess.vue
<script setup lang="ts">
import {
onMounted } from 'vue';
import {
useRouter} from 'vue-router'
const router = useRouter()
let timer:any = null;
let curTime = 5;
const curTimeFun = ()=>{
timer = setInterval(()=>{
curTime--;
if(curTime<=0){
router.push("/UserLogin")
clearInterval(timer);
timer = null;
}
},1000);
}
onMounted(()=>{
curTimeFun();
})
</script>
<template>
<div class="tip">
重置密码成功
</div>
<div class="success">
<!-- <router-link to="/UserLogin" >点击跳转账号密码登录界面</router-link> -->
<router-link to="/UserLogin" :curtime="curTimeFun">点击跳转账号密码登录界面,{
{
curTime}} 后自动跳转</router-link>
</div>
</template>
<style scoped>
.tip{
width: 20%;
height: 10%;
margin: auto;
padding: 3%;
font-size: 20px;
/* background-color: aqua; */
}
.success{
width: 60%;
height: 20%;
margin: auto;
padding: 4%;
font-size: 15px;
font-style: italic;
/* display: flex; */
/* justify-content: center; */
background-color: bisque;
}
</style>
20.2.8 密码设置成功后的自动跳转效果
当密码设置好后,下一步,密码设置成功界面,提示5秒后自动跳转到登录界面
注:这里暂时还没有实现如何将5秒倒计时实时显示,后面再想怎么解决



20.3 邮箱找回密码
根据前面手机验证码找回密码的实现,一样的方式实现邮箱找回密码的功能
这里暂时使用相同的方式模拟邮箱验证码,即使用redis,在点击获取验证码时,发送请求,生成一个六位数字,并以用户名为键,数字为值的形式存储在redis中
随后输入正确的数字,填写完整信息,点击下一步,即可通过验证
20.3.1 引入邮箱找回密码的页面(ResetPwd.vue)
在找回密码对应的页面组件中引入邮箱找回密码的组件
即在src/views/resetPassword/ResetPwd.vue中引入src/views/resetPassword/components/EmailCodeSetPwdForm.vue
此时,完整的ResetPwd.vue代码如下
<script setup lang="ts">
import {
ref } from 'vue'
import EmailCodeSetPwdForm from './components/EmailCodeSetPwdForm.vue';
import PhoneCodeSetPwdForm from './components/PhoneCodeSetPwdForm.vue';
const curTab = ref(1);
const changeTab = (tab:any)=>{
curTab.value = tab;
}
// const bgColor = "linear-gradient(45deg, #5198d3, #0f9fe2, #61a2d6);";
// 样式变量
// const setPwdPagePanelWidth = '40%';
// const setPwdPagePanelHeight = '30%';
</script>
<template>
重置密码
<div class="resetpwd-page">
<div class="resetpwd-box">
<div class="tabs">
<div class="tab-item" :class="{'tab-item-selected':curTab==1}" @click="changeTab(1)">手机验证码找回密码</div>
<div class="tab-item" :class="{'tab-item-selected':curTab!=1}" @click="changeTab(2)">邮箱验证码找回密码</div>
</div>
<div class="tab-content">
<PhoneCodeSetPwdForm v-if="curTab == 1"></PhoneCodeSetPwdForm>
<EmailCodeSetPwdForm v-else></EmailCodeSetPwdForm>
</div>
</div>
<div class="resetpwd-footer">
密码重置页面
</div>
</div>
</template>
<style scoped>
.resetpwd-page{
min-width: 1024px;
min-height: 900px;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
/* background: v-bind(bgColor); */
background: linear-gradient(45deg, #5198d3, #0f9fe2, #61a2d6);
display: flex;
/* text-align: center; */
/* justify-items: center; */
/* justify-content: center; */
align-items: center;
}
.resetpwd-page .resetpwd-box{
background-color: #fff;
height: 50%;
/* height: v-bind(setPwdPagePanelWidth); */
width: 60%;
/* width: v-bind(setPwdPagePanelHeight); */
/* min-height: 800px; */
margin: 0 auto;
text-align: center;
border-radius: 10px;
/* box-shadow: var(--el-box-shadow); */
box-shadow: 0 0 10px 10px #00000055;
padding: 40px;
}
.resetpwd-page .resetpwd-box .tabs{
/* height:20px; */
height: 5%;
/* width: 400px; */
width: 40%;
line-height: 40px;
display: flex;
margin: 0 auto;
}
.resetpwd-page .resetpwd-box .tabs .tab-item{
/* width: 200px; */
width: 50%;
height: 40px;
/* height: 180%; */
text-align: center;
background-color: #00000055;
font-size: 16px;
cursor: pointer;
/* border-radius: 5px; */
}
.resetpwd-page .resetpwd-box .tabs .tab-item:first-child{
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
.resetpwd-page .resetpwd-box .tabs .tab-item:last-child{
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
.resetpwd-page .resetpwd-box .tabs .tab-item:hover,
.resetpwd-page .resetpwd-box .tabs .tab-item-selected{
color: white;
background-color: #0ba4eb;
}
.resetpwd-page .resetpwd-box .tab-content{
/* padding-top: 60px; */
padding-top: 5%;
/* display: flex=1; */
/* justify-content: center; */
/* padding-left: 10%; */
/* padding: 10%; */
/* padding: 50px; */
/* align-items: center; */
/* text-align: center; */
/* height: 400px; */
height: 100%;
/* width: 600px; */
width: 100%;
}
.resetpwd-page .resetpwd-footer{
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 10%;
text-align: center;
color: white;
font-size: 15px;
}
</style>
20.3.2 邮箱找回密码代码创建(EmailCodeSetPwdForm.vue)
将手机验证码找回密码的代码PhoneCodeSetPwdForm.vue完整复制过来即可
然后修改一下函数和变量的名字,将短信该位邮箱就行了
完整代码如下
src/views/resetPassword/components/
EmailCodeSetPwdForm.vue
<script setup lang="ts">
// vue基础模块引入
import {
ref, reactive } from 'vue'
// 引入状态存储工具store
// import {useStore} from 'vuex'
// 引入工具方法
import utils from '../../../utils/utils'
import api from '../../../api/api'
// 路由引入
// import { useRoute, useRouter } from 'vue-router';
// 引入密码重置页面组件
import ResetPwdForm from './ResetPwdForm.vue';
import ResetSuccess from './ResetSuccess.vue';
const formSize = ""
// 步骤选择
const setStep = ref(1);
// 表单数据对象
const resetPwdForm = reactive({
// 用户名
username: '',
// 邮箱验证码
emailcode: '',
// 图片验证码
imgcode: '',
});
// 表单验证规则
const rules = ref({
username: [{
required: true,
message: '请输入用户名',
trigger: 'blur'
}],
emailcode: [{
required: true,
message: '请输入邮箱验证码',
trigger: 'blur'
}],
imgcode: [{
required: true,
message: '请输入图片验证码',
trigger: 'blur'
}]
});
// 获取短信验证码的按钮文本值
let emailcodeBtnText = ref("获取验证码")
// 定时器
let timer:any = null;
// 邮箱验证码获取的间隔事件
let curTime = 0;
// 获取验证码按钮
const getEmailCode = ()=>{
if(!resetPwdForm.username){
utils.showError("请先输入用户名");
return;
}
// 发送请求生成邮箱验证码
api({
method: 'post',
url: '/login/redis/setMessageCode',
params: {
username: resetPwdForm.username
}
});
// 同时进行倒计时,读秒60,结束后可重新获取
curTime = 60
timer = setInterval(() => {
curTime--;
// 值重新赋值
emailcodeBtnText.value = curTime+'秒后重新获取';
// 当及时归零时,可重新获取,并将计时器重置
if(curTime<=0){
emailcodeBtnText.value = '获取验证码'
clearInterval(timer);
timer = null;
}
},1000);
}
// 图片验证码路径
let imageCodeSrc = new URL('../../../assets/code.png',import.meta.url).href
// 刷新图片验证码
const getImgCode = () => {
// 从服务器动态获取图片验证码
imageCodeSrc = new URL('../../../assets/code.png',import.meta.url).href
}
const resetPwdFormRef = ref();
// 下一步按钮
const nextSet = () => {
// 表单校验,校验所填表单中是否有值,无值则报错
resetPwdFormRef.value.validate((valid:string, fileds:any)=>{
// 如果valid值为假,则输出报错内容
if(!valid){
for(let key in fileds){
utils.showError(fileds[key][0].message);
return;
}
return;
}
// 加载效果
utils.showLoadding("正在加载中");
// if(resetPwdForm.emailcode){
// utils.showError("验证码错误,请重新输入");
// }
// 校验填写的验证码是否一致
api({
method: 'get',
url: 'login/redis/getMessageCode',
params: {
username: resetPwdForm.username
}
}).then((res)=>{
utils.hideLoadding();
// 如果数据返回状态码不是200或请求结果返回不是200或者请求结果返回的短信验证码为空,验证失败
if(res.status!=200||res.data.result!=200||!res.data.msgCode){
utils.showError("验证失败-请求数据返回有误");
return;
}
// 如果填入的邮箱验证码和收到的短信验证码一致,则验证成功,跳转到修改密码界面
if(res.data.msgCode == resetPwdForm.emailcode){
utils.showSuccess("验证成功");
setStep.value = 2;
}else{
utils.showError("验证失败-验证码错误");
}
}).catch((error)=>{
setStep.value = 2;
utils.hideLoadding();
console.log(error);
utils.showError("验证失败-出现异常");
});
});
}
const systemToken = ref('');
// const susername = resetPwdForm.username;
// systemToken.value = resetPwdForm.username;
const toPhoneCodeSetPwdForm = ()=>{
setStep.value = 1;
}
const toResetSuccess = ()=>{
setStep.value = 3;
}
</script>
<template>
<!-- <div class="stepLine"> -->
<el-steps style="max-width: 2000px" :active="setStep" align-center>
<el-step title="身份验证" description="请输入账号和验证码进行身份确认" />
<el-step title="密码重置" description="填写新密码并确认" />
<el-step title="重置成功" description="密码修改成功" />
</el-steps>
<!-- </div> -->
<div v-if="setStep == 1" class="phone-reset-password-form">
<el-form
ref="resetPwdFormRef"
style="max-width: 600px;"
:model="resetPwdForm"
:rules="rules"
label-width="0"
class="resetPwdForm"
:size="formSize"
status-icon
>
<!-- 用户名 -->
<el-form-item prop="username">
<el-input
prefix-icon="UserFilled"
v-model="resetPwdForm.username"
placeholder="用户名"
size="large"
/>
</el-form-item>
<!-- 获取验证码 -->
<el-form-item prop="emailcode">
<div class="flex resetLine">
<div class="flexItem">
<el-input
prefix-icon="Iphone"
v-model="resetPwdForm.emailcode"
placeholder="邮箱验证码"
size="large"
/>
</div>
<div class="codeBtn">
<el-button type="primary" size="large" @click="getEmailCode" :disabled="curTime>0">
{
{
emailcodeBtnText }}
</el-button>
</div>
</div>
</el-form-item>
<!-- 图片验证码 -->
<el-form-item prop="imgcode">
<div class="flex resetLine">
<div class="flexItem">
<el-input
prefix-icon="Picture"
v-model="resetPwdForm.imgcode"
placeholder="图片验证码"
size="large"
/>
</div>
<div class="codeBtn">
<el-image :src="imageCodeSrc" size="large" @click="getImgCode"></el-image>
</div>
</div>
</el-form-item>
<!-- 下一步按钮 -->
<el-form-item>
<!-- <div class="nextBtn"> -->
<el-button class="nextBtn" type="primary" size="large" @click="nextSet">下一步</el-button>
<!-- </div> -->
</el-form-item>
</el-form>
</div>
<!-- usernames表示将当前数据的只绑定到usernames中,通过在别的页面中使用defineProps获取 -->
<ResetPwdForm v-else-if="setStep == 2"
:systemToken="systemToken"
@pre="toPhoneCodeSetPwdForm"
@next="toResetSuccess"
:usernames = resetPwdForm.username
></ResetPwdForm>
<!-- <ResetPwdForm v-else-if="setStep == 2" ></ResetPwdForm> -->
<ResetSuccess v-else></ResetSuccess>
</template>
<style scoped>
.phone-reset-password-form{
padding: 5%;
/* margin-top: 2%; */
margin: 2% auto;
width: 60%;
height: 40%;
background-color: rgb(204, 240, 210);
display: flex;
justify-content: center;
}
.codeBtn{
margin-left: 10px;
}
.codeBtn:deep(img){
height: 40px;
cursor: pointer;
}
.resetLine{
width: 100%;
}
.nextBtn{
width: 100%;
}
</style>
20.3.3 密码设置成功页的页面优化(ResetSuccess.vue)
对密码设置成功的页面进行优化,做了一点修改
先不自动跳转,注掉了自动跳转的代码,添加了一个图标,将点击的链接下划线剔除了
完整代码如下
src/views/resetPassword/components/
ResetSuccess.vue
<script setup lang="ts">
import {
onMounted } from 'vue';
import {
useRouter} from 'vue-router'
const router = useRouter()
let timer:any = null;
let curTime = 5;
const curTimeFun = ()=>{
// timer = setInterval(()=>{
// curTime--;
// if(curTime<=0){
// router.push("/UserLogin")
// clearInterval(timer);
// timer = null;
// }
// },1000);
}
onMounted(()=>{
curTimeFun();
})
</script>
<template>
<div class="success-box">
<div class="success-box-icon">
<el-icon><CircleCheck /></el-icon>
</div>
<div class="success-box-link">
<!-- <router-link to="/UserLogin" >点击跳转登录界面</router-link> -->
<router-link to="/UserLogin" class="success-box-link-btn" :curtime="curTimeFun">点击跳转登录界面,{
{
curTime}} 后自动跳转</router-link>
</div>
</div>
</template>
<style scoped>
/* .success-box{
text-align: center;
} */
.success-box-icon{
width: 20%;
height: 10%;
margin: auto;
padding: 6%;
font-size: 60px;
color: #409eff;
}
/* .success-box-link{ */
/* width: 60%; */
/* height: 20%; */
/* margin: auto; */
/* padding: 1%; */
/* font-size: 20px; */
/* font-style: italic; */
/* background-color: rgb(184, 230, 190); */
/* } */
.success-box-link-btn{
/* width: 60%; */
/* margin: auto; */
padding: 1%;
font-size: 20px;
text-decoration: none;
background-color: rgb(184, 230, 190);
}
</style>
20.3.4 邮箱找回密码功能页面效果演示
忘记密码

选择邮箱找回密码

输入用户名、获取验证码,输入验证码,随便输入图片验证码,下一步

验证通过,输入新密码,下一步

密码修改成功,点击文字链接可跳转到登录界面

20.4 项目下载地址
此时的项目代码已上传,实现了目前文章中所实现的代码功能
前端项目下载地址:hslb-vue3-elementplus-admin 登录和找回密码功能实现
后端接口项目下载地址:java hslb-general-management-system 后端接口服务 登录和密码修改
注:后端接口项目需要配合mysql和数据库,可以根据需要自行实践,如已经有现成的接口可忽略这里的后端项目
感谢阅读,祝君暴富!
原文链接: https://hanshan.blog.csdn.net//article/details/141186149