前后端分离项目实战-通用管理系统搭建(前端Vue3+ElementPlus,后端Springboot+Mysql+Redis)第三篇:登录功能优化


天行健,君子以自强不息;地势坤,君子以厚德载物。


每个人都有惰性,但不断学习是好好生活的根本,共勉!


文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。


仰天大笑出门去,我辈岂是蓬蒿人。

------《南陵别儿童入京》


文章目录

    • [19. 登录优化(记住用户名和密码)](#19. 登录优化(记住用户名和密码))
      • [19.1 api/api.ts](#19.1 api/api.ts)
      • [19.2 store/index.ts](#19.2 store/index.ts)
      • [19.3 index/HomeIndex.vue](#19.3 index/HomeIndex.vue)
      • [19.4 PhoneCodeForm.vue](#19.4 PhoneCodeForm.vue)
      • [19.5 QcodeForm.vue](#19.5 QcodeForm.vue)
      • [19.6 UsernameForm.vue](#19.6 UsernameForm.vue)
      • [19.7 App.vue](#19.7 App.vue)
      • [19.8 页面效果展示](#19.8 页面效果展示)
        • [19.8.1 使用短信验证码登录的展示](#19.8.1 使用短信验证码登录的展示)
        • [19.8.2 使用账号密码登录的展示](#19.8.2 使用账号密码登录的展示)
        • [19.8.3 使用二维码登录的展示](#19.8.3 使用二维码登录的展示)


先进行上一篇最后一部分登录问题进行优化

优化内容如下:

1.部分警告,虽然不影响项目正常使用,但控制台输出的警告看着还是比较难受的

2.取消勾选记住用户名和密码操作,用户名密码依旧显示,该问题是因为当记住用户名密码对应的值移除后,其值变为undefined,而代码中的判断在其为undefined时依旧满足条件执行,需要将其值与ture进行比较

19. 登录优化(记住用户名和密码)

部分其他代码也进行了优化,以下代码基于上一篇最后下载的项目进行改动

改动如下

19.1 api/api.ts

src/api/api.ts 注掉了一部分无用代码

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 新增了登出时清除缓存数据的代码,此处为缓存校验时使用

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 未做改变,但也列出来看一下

ts 复制代码
<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 对登录缓存校验进行了优化

ts 复制代码
<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 对二维码生成部分进行了优化

ts 复制代码
<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 对登录缓存校验进行了优化

ts 复制代码
<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 对登录缓存校验进行了优化

ts 复制代码
<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秒后刷新页面会跳转到短信登录


感谢阅读,祝君暴富!


相关推荐
逊嘘8 分钟前
【Java语言】抽象类与接口
java·开发语言·jvm
morris13115 分钟前
【SpringBoot】Xss的常见攻击方式与防御手段
java·spring boot·xss·csp
别拿曾经看以后~17 分钟前
【el-form】记一例好用的el-input输入框回车调接口和el-button按钮防重点击
javascript·vue.js·elementui
我要洋人死20 分钟前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人32 分钟前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人32 分钟前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR38 分钟前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香40 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
Jacob程序员41 分钟前
java导出word文件(手绘)
java·开发语言·word
ZHOUPUYU41 分钟前
IntelliJ IDEA超详细下载安装教程(附安装包)
java·ide·intellij-idea