天行健,君子以自强不息;地势坤,君子以厚德载物。
每个人都有惰性,但不断学习是好好生活的根本,共勉!
文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。
仰天大笑出门去,我辈岂是蓬蒿人。
——《南陵别儿童入京》
文章目录
- 19. 登录优化(记住用户名和密码)
- 19.1 api/api.ts
- 19.2 store/index.ts
- 19.3 index/HomeIndex.vue
- 19.4 PhoneCodeForm.vue
- 19.5 QcodeForm.vue
- 19.6 UsernameForm.vue
- 19.7 App.vue
- 19.8 页面效果展示
- 19.8.1 使用短信验证码登录的展示
- 19.8.2 使用账号密码登录的展示
- 19.8.3 使用二维码登录的展示
先进行上一篇最后一部分登录问题进行优化
优化内容如下:
1.部分警告,虽然不影响项目正常使用,但控制台输出的警告看着还是比较难受的
2.取消勾选记住用户名和密码操作,用户名密码依旧显示,该问题是因为当记住用户名密码对应的值移除后,其值变为undefined,而代码中的判断在其为undefined时依旧满足条件执行,需要将其值与ture进行比较
19. 登录优化(记住用户名和密码)
部分其他代码也进行了优化,以下代码基于上一篇最后下载的项目进行改动
改动如下
19.1 api/api.ts
src/api/api.ts 注掉了一部分无用代码
// 引入axios
import axios from 'axios'
// 引入store
import store from '@/store';
import { useRouter } from 'vue-router';
// 数据请求自定义配置(实例)
// console.log(import.meta.url,"------------");
const api = axios.create({
// baseURL: 'https://mo_sss.blog.csdn.net.cn',
// baseURL: import.meta.BaseURL,
// baseURL: 'https://hanshanlibai.gms.com',
baseURL: 'http://127.0.0.1:8888/',
timeout: 1000,
headers: {
// 'X-Custom-Header': 'foobar'
'Content-Type': 'application/json;charset=UTF-8'
}
// withCredentials 表示跨域请求时是否需要使用凭证,默认是true
// withCredentials: true,
// responseType 表示浏览器将要响应的数据类型,包括arraybuffer、document、json、text、stream
// 浏览器专属类型: blob
// 默认值就是json
// responseType: 'json',
// responseEncoding 表示用于解码响应的编码(Node.js专属),注意,忽略responseType值为stream或者客户端请求
// 默认值为utf-8
// responseEncoding: 'utf-8'
});
// const router = useRouter();
// 添加请求拦截器
api.interceptors.request.use(function (config) {
console.log("request------------------->")
// 在发送请求之前做些什么
// 获取缓存中的token
const token = store.getters.getToken;
if(token){
// 如果token为真值,则将其赋值赋给请求头
config.headers.token = token;
}
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
api.interceptors.response.use(function (response) {
console.log("response-------------------> code",response.status)
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
// store.commit("logout");
// router.push('/UserLogin')
return response;
}, function (error) {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
if(error.response){
console.log(error.response.status)
switch(error.response.status){
case 401:
// case 200:
store.commit("logout");
// router.replace({
// path: '/UserLogin',
// query: {
// redirect: router.currentRoute.value.fullPath
// }
// })
break;
default:
store.commit("logout");
// router.replace({
// path: "/UserLogin",
// query: {
// redirect: router.currentRoute.value.fullPath
// }
// })
}
}
return Promise.reject(error);
});
export default api;
19.2 store/index.ts
src/store/index.ts 新增了登出时清除缓存数据的代码,此处为缓存校验时使用
// 引入, 用于存储全局的状态数据,可供其他地方调用
import { createStore } from "vuex";
// 引入工具方法
import utils from "@/utils/utils";
// 创建一个新的store实例
const store = createStore({
state() {
return{
// count: 0
// 当前登录的用户信息
userInfo: {},
// 当前登录的标识token
token: null,
}
},
getters: {
getUserInfo(state:any){
return state.userInfo;
},
getToken(state:any){
return state.token;
}
},
mutations: {
// 登出,清除缓存中的数据
logout: function(state:any){
console.log("---111---")
state.userInfo = null;
utils.removeData("userInfo");
utils.removeData("token");
// utils.removeData("username");
// utils.saveData("username","");
// utils.removeData("saveUsername");
// utils.removeData("password");
// utils.removeData("savePassword");
},
// 存储用户信息
setUserInfo: function(state:any, userInfo:any){
state.userInfo = userInfo;
utils.saveData('userInfo', userInfo);
},
// 存储token
setToken: function(state:any, token:any){
state.toekn = token;
utils.saveData('token', token);
}
}
})
export default store;
19.3 index/HomeIndex.vue
src/views/index/HomeIndex.vue 未做改变,但也列出来看一下
<script setup lang="ts">
import utils from '@/utils/utils';
import { onMounted } from 'vue';
</script>
<template>
后台主页
</template>
<style scoped>
</style>
19.4 PhoneCodeForm.vue
src/views/login/components/PhoneCodeForm.vue 对登录缓存校验进行了优化
<script setup lang="ts">
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';
// 登录表单的实例
// let loginFormRef = ref(null);
let loginFormRef = ref()
// 登录表单的数据
const loginForm = reactive({
// 用户名
username: '',
// 手机验证码
smscode: '',
// 图片验证
imgcode: '',
// 记住用户名,默认否
saveUsername: false
})
// 登录验证规则
const rules = {
username: [
{
required: true,
message: '请输入用户名',
trigger: 'blur'
}
],
smscode: [
{
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
}
// 定时器
let timer: any = null
// 获取短信验证码的间隔时间
let curTime = 0
// 获取短信验证码按钮的文本显示内容
let smsCodeBtnText = ref('获取验证码')
// 获取短信验证码
const getSmsCode = () => {
// 当点击获取短信验证码时,如果其他信息没填则提示输入
if (!loginForm.username) {
utils.showError('请输入用户名')
return
}
// if(!loginForm.smscode){
// utils.showError('请输入短信验证码');
// return;
// }
// TODO 从后台获取短信验证码
// 调用接口生成短信验证码
// 1 直接使用axios请求后端完整地址请求
// axios({
// method: 'post',
// url: 'http://127.0.0.1:8888/login/redis/setMessageCode',
// // url: 'login/redis/setMessageCode',
// // 这里需要注意,不管请求方式是什么,这里是根据后端传参方式来定的,如果后端使用@RequestParam则这里使用params作为key
// params: {
// username: loginForm.username
// }
// });
// 2 使用axios实例传参请求后端接口地址的用法
api({
method: 'post',
url: '/login/redis/setMessageCode',
params: {
username: loginForm.username
}
})
curTime = 60
timer = setInterval(() => {
curTime--;
smsCodeBtnText.value = curTime + '秒后重新获取';
if (curTime <= 0) {
smsCodeBtnText.value = '获取验证码'
clearInterval(timer)
// 清除时,值为空,防止重复点击触发多次
timer = null
}
}, 1000)
}
// 状态存储的store
const store = useStore();
// 路由,转到指定页面,使用push
// const route = useRoute();
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==true) {
console.log("短信验证登录1:",loginForm.saveUsername);
// 保存输入的用户名
utils.saveData('username', loginForm.username)
// 保存被勾选的操作
utils.saveData('saveUsername', loginForm.saveUsername)
} else {
console.log("短信验证登录2:",loginForm.saveUsername);
// 如果记住用户名的勾选取消,则移除这两个存储的内容
utils.removeData('username')
utils.removeData('saveUsername')
}
// TODO 调用接口登录
// 因为太快了,所以可能看不到效果,可以将下方的hideLoading方法注掉,可以看到效果
utils.showLoadding('正在加载中')
api({
method: 'get',
url: '/login/redis/getMessageCode',
params: {
username: loginForm.username,
smscode: loginForm.smscode
// imgcode: loginForm.imgcode
}
})
.then((res) => {
utils.hideLoadding()
console.log(res)
// console.log(res.status)
// if (!res || res.status != 200 || !res.data || res.data.result != 200 || !res.data.data) {
if (res.status != 200 || res.data.result != 200 || !res.data.msgCode) {
utils.showError('登录失败-请求数据返回有误');
return;
}
// console.log(res.data.data, loginForm.smscode);
if(res.data.msgCode == loginForm.smscode){
utils.showSuccess('登陆成功')
// 存储用户token信息并转到主页
// let userInfo = res.data.data
let userInfo = res.data
let token = res.data.token
// 状态数据存储
store.commit('setUserInfo', userInfo);
store.commit('setToken', token);
// 登录成功后将页面转到主页
router.push('/HomeIndex')
}else if(res.data.msgCode != loginForm.smscode){
utils.showError('登录失败-验证码错误');
return;
}
// utils.showError('登录失败')
})
.catch((error) => {
// utils.hideLoadding();
console.log(error);
utils.showError('登录失败-出现异常')
})
// api.post("/api/login/code",{
// username: loginForm.username,
// smscode: loginForm.smscode,
// imgcode: loginForm.imgcode
// }).then((res)=>{
// utils.hideLoadding();
// console.log(res);
// console.log(res.status);
// if(!res || res.status != 200 || !res.data || res.data.code != 8888 || !res.data.data){
// if(res.data.message){
// utils.showError(res.data.message);
// return;
// }
// utils.showError('登录失败');
// return;
// }
// // 存储用户token信息并转到主页
// let userInfo = res.data.data;
// let token = res.data.token;
// utils.showSuccess('登陆成功');
// }).catch((error)=>{
// // utils.hideLoadding();
// utils.showError('登录失败');
// });
// 登录成功信息提示
// utils.showSuccess("登录成功");
})
}
// 挂载
onMounted(() => {
// 获取记住用户名的值
loginForm.saveUsername = utils.getData('saveUsername')
// 如果记住用户名被勾选,则获取用户名显示(saveUsername可能会是undefined,当为undefined时也是真,故这里不能直接使用saveUsername,而是要判断是否为true)
if (loginForm.saveUsername==true) {
loginForm.username = utils.getData('username')
}
})
// 清空定时器
onUnmounted(() => {
timer && clearInterval(timer)
})
</script>
<template>
<!-- 手机验证码登录 -->
<div class="phoneCodeLoginBox">
<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="smscode">
<!-- 使用两个div块来左右布局验证码输入和获取验证码按钮的实现 -->
<div class="flex loginLine">
<div class="flexItem">
<el-input
prefix-icon="Iphone"
v-model="loginForm.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块来左右布局验证码输入和获取验证码按钮的实现 -->
<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-checkbox v-model="loginForm.saveUsername">记住用户名</el-checkbox>
</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>
19.5 QcodeForm.vue
src/views/login/components/QcodeForm.vue 对二维码生成部分进行了优化
<script setup lang="ts">
import { ref,reactive, onMounted, onUnmounted } from 'vue'
// 引入工具方法
import utils from '../../../utils/utils'
import api from '../../../api/api'
// 引入store
import {useStore} from 'vuex'
// 引入router
import {useRouter} from 'vue-router'
const store = useStore();
const router = useRouter();
// 二维码
// let qcodePath:any = null;
// 二维码对应的token, 用于判断当前二维码是否已经被扫码登录
let qrToken:string = "";
// 第一次获取验证码
// api({
// method: 'post',
// url: 'login/qr/generateQrCodeAsFile'
// }).then((res)=>{
// if(res.data.result != 200){
// utils.showError("登录失败");
// }
// utils.showSuccess("登录成功");
// qcodePath = res.data.data
// qrToken = res.data.token
// });
// qcodePath = 'E:\\WORKPROJECTS\\MySelfPro\\hslb-general-management-system\\src\\main\resources\\login_qr_pngs\\QRCode.png';
// 二维码
let qcodeSrc = new URL("../../../assets/hslb-qcode.png", import.meta.url).href;
// let qcodeSrc = new URL(qcodePath, import.meta.url).href;
// let qcodeSrc = qcodePath;
const qcodeToken = ref('');
// 当前定时器事件
const curTime = ref(0);
let timer:any = null;
let username:string = utils.getData("username");
const qrString = "100100100222";
// 后台更新获取二维码
const loadQcode = () => {
// 后续改为从服务器上获取动态图片
// const qrString = "100100100222";
console.log("9999999====== "+qrString);
// let username:string = utils.getData("username");
api({
method: 'post',
url: 'login/qr/generateQrCodeAsFile',
params: {
username: username,
qrContent: qrString
}
}).then((res)=>{
// if(res.data.result != 200){
// utils.showError("登录失败");
// }
// utils.showSuccess("登录成功");
// qcodePath = res.data.data
qrToken = res.data.token
});
qcodeSrc = new URL("../../../assets/hslb-qcode.png", import.meta.url).href;
// qcodeSrc = new URL(qcodePath, import.meta.url).href;
// qcodeSrc = qcodePath;
// 初始化token的值
qcodeToken.value = qrToken;
// 设定定时时间
// curTime.value = 60;
// 为了让二维码失效的效果及时,这里暂时设置10秒,后续改回60秒即可
curTime.value = 10;
// 定义定时器,倒计时
timer = setInterval(() => {
curTime.value--;
// 这里获取toekn,校验是否已经被登陆过
checkLogin();
if(curTime.value<=0){
// 事件为0则清空定时器
clearInterval(timer);
timer = null;
}
}, 1000);
};
// 登录提交事件
// const onSubmit = () => {
// };
// 挂载
onMounted(() => {
// 获取二维码
loadQcode();
});
// 清空计时器
onUnmounted(()=>{
timer && clearInterval(timer);
});
// 使用qcodeToken判断当前二维码是否已经被扫码登录
const checkLogin = () => {
// TODO
api({
method: 'post',
url: 'login/qr/generateQrCodeAsFile',
params: {
username: username,
qrContent: qrString
}
}).then((res)=>{
if(res.data.token){
utils.showSuccess("登录成功");
store.commit('setUserInfo',res.data);
store.commit('setToken',res.data.token);
router.push('/HomeIndex');
}
// res.data.token;
}).catch((error)=>{
console.log(error);
// utils.showError("登录失败")
});
}
</script>
<template>
<!-- 扫码登录 -->
<div class="qcodeLoginBox">
<div class="qcodeBox" >
<img class="qcodeImg" :class="{'endImg':curTime<=0}" :src="qcodeSrc" alt="无法获取二维码,请联系客服解决">
<div v-if="curTime<=0" class="endBox" @click="loadQcode" >
当前二维码失效,点击重新加载{{ curTime }}秒
</div>
</div>
<div class="tipInfo" >
使用微信或移动端扫码登录 此二维码将在{{ curTime }}秒后刷新
</div>
</div>
</template>
<style scoped>
/* 二维码窗口样式 */
.qcodeBox{
width: 80%;
height: 80%;
position: relative;
/* 边框自动 */
margin: 0 auto;
}
/* 二维码图片样式 */
.qcodeBox .qcodeImg{
width: 100%;
height: 100%;
}
.qcodeBox .endBox{
width: 100%;
height: 100%;
/* 悬浮显示 */
position: absolute;
/* 靠左 */
/* left: 0%; */
/* 靠上 */
top: 0;
/* 居中 */
/* text-align: center; */
/* 字体大小 */
font-size: 14px;
/* 字体颜色 */
color: red;
display: flex;
/* 上下居中 */
align-items: center;
/* justify-items: center; */
/* 左右居中 */
justify-content: center;
/* 背景色为灰色 */
background-color: #00000055;
}
/* .endImg{
filter: brightness(10%);
} */
/* 提示信息样式 */
.tipInfo{
/* 行高 */
line-height: 30px;
/* 字体大小 */
font-size: 14px;
/* 居中 */
text-align: center;
/* 颜色 */
color: var(--el-text-color-placeholder);
}
</style>
19.6 UsernameForm.vue
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>
</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>
19.7 App.vue
src/App.vue 对登录缓存校验进行了优化
<script setup lang="ts">
import { onMounted } from 'vue';
import { useStore } from 'vuex';
import { useRouter } from 'vue-router';
import utils from './utils/utils';
import api from './api/api';
// // // 引入暗黑主题的动态切换
// import { useDark, useToggle } from '@vueuse/core'
// const isDark = useDark()
// // // 切换主题函数
// const toggleDark = useToggle(isDark)
// 状态存储
let store = useStore();
// 路由使用
const router = useRouter();
onMounted(()=>{
// let tt = localStorage.getItem("token");
// console.log("tt: ",tt);
console.log("=== ===");
let token = "";
// 由于token可能返回undefined报错,需要进行报错处理
try {
token = utils.getData("token");
} catch (error) {
error;
}
console.log("store-token",token);
let userInfo = utils.getData('userInfo');
console.log("userInfoL: "+userInfo)
console.log("userInfoL: "+token&&userInfo)
if(token && userInfo){
console.log("token userInfo :",token," -- ", userInfo);
// 登录成功,验证
utils.showLoadding("正在加载")
const username = utils.getData('username');
if(!username){
// 登录失败,跳转到登录页
if(username===undefined){
utils.saveData("username","");
}
// token验证失败
utils.showError("用户名过期-请重新登录");
router.push('/UserLogin');
utils.hideLoadding();
}else{
console.log("username-", username);
api.get('/login/tokenCheck',{
params:{username}
}).then((res)=>{
console.log("res.data.token",res.data);
utils.hideLoadding();
if(res.data.token==token){
// 登陆成功
// store.commit('setUserInfo', userInfo);
// store.commit('setToken', token);
router.push('/HomeIndex');
utils.showSuccess("登录成功");
}else{
// if(username===undefined){
// utils.saveData("username","");
// }
// 登录失败
utils.showError("Token已过期,请重新登录");
// 登录失败,跳转到登录页
router.push('/UserLogin');
}
});
utils.hideLoadding();
}
}else{
// 登录失败,跳转到登录页
utils.showError("用户登录缓存过期,请重新登录");
router.push('/UserLogin');
utils.hideLoadding();
}
});
</script>
<template>
<!-- 暗黑主题动态切换按钮实现 -->
<!-- <button @click="toggleDark()">
<i inline-block align-middle i="dark:carbon-moon carbon-sun"/>
<span class="ml-2">{{ isDark ? 'Dark' : 'Light' }}</span>
</button> -->
<RouterView></RouterView>
</template>
<style scoped>
</style>
19.8 页面效果展示
19.8.1 使用短信验证码登录的展示
登录前
不勾选记住用户名登录
输入用户名,点击获取验证码按钮,获取验证码后填入(redis中查看),并填写图片验证码(此项随机填写即可)不勾选记住用户名
登录成功界面
60秒内刷新页面如下
等待60秒后刷新界面(token设定的是60秒过期,故过期后需要重新登录)
勾选记住用户名登录
输入用户名,点击获取验证码按钮,获取验证码后填入(redis中查看),并填写图片验证码(此项随机填写即可),勾选记住用户名
登录成功界面
60秒内刷新页面如下
60秒后刷新界面
19.8.2 使用账号密码登录的展示
登录前
不勾选记住用户名密码登录
登录成功后
60秒后刷新页面
勾选记住用户名密码登录
登录成功
60秒后刷新页面
19.8.3 使用二维码登录的展示
这里没有做任何逻辑进行用户的登录,只是生成了一个token,并且当前用户名是另外两种登录方式存储的缓存,此时直接验证通过
登录成功
60秒后刷新页面会跳转到短信登录
感谢阅读,祝君暴富!