思路:
1、登录成功后,返回动态的路由信息,存储在本地localStorage中。
2、router.js中在路由守卫钩子函数中使用router.addRoute()进行动态路由添加。
具体代码:
login.vue中
<script setup> import {onMounted, reactive, ref} from 'vue'; import {KeyOutlined, SafetyOutlined, UserOutlined} from '@ant-design/icons-vue'; import sha1 from 'js-sha1'; import {useRoute, useRouter} from 'vue-router'; import appConstant from '../app-constant.js'; import commonService from '../service/common-service.js'; import sysUserService from '../service/sys-user-service.js'; const router = useRouter(); const route = useRoute(); const logoutAlert = ref(route.query.hasOwnProperty('logout')); const closeLogoutAlert = () => { logoutAlert.value = false; }; const formState = reactive({ account: '', password: '', captcha: '', }); const alertError = reactive({show: false, msg: ''}); const login = (data) => { loginLoading.value = true;
//sessionDtorage存储接口返回的动态路由地址 sysUserService.login(data).then(res => { sessionStorage.setItem(appConstant.SK_LOGIN_USER, JSON.stringify(res.data)); router.replace('/home'); }).catch(error => { alertError.show = true; alertError.msg = error.msg; }).finally(() => { getCaptcha(); loginLoading.value = false; }); }; const loginLoading = ref(false); const onFormFinish = (values) => { let password = ''; if (values.password) { password = sha1(sha1(values.password)); } const data = { account: values.account, password, captcha: values.captcha }; login(data); }; const captchaImgSrc = ref(null); const getCaptcha = () => { commonService.getCaptcha().then(res => { captchaImgSrc.value = res; }); }; onMounted(() => { getCaptcha(); }); const onCaptchaClick = () => { getCaptcha(); }; </script> <template> <div class="login"> <main> <section class="left"> <img src="../assets/yiyuan-logo.jpg" alt="logo"> <div class="title">管理系统</div> <div class="sub-title">System</div> </section> <section class="right"> <div> <span class="title">用户登录</span> <span class="sub-title">USER LOGIN</span> </div> <a-form :model="formState" @finish="onFormFinish"> <a-form-item name="account" :rules="[{ required: true, message: '用户名不能为空' }]"> <a-input v-model:value="formState.account" placeholder="请输入用户名" class="input" @click="closeLogoutAlert" > <template #prefix> <user-outlined class="input-icon"/> </template> </a-input> </a-form-item> <a-form-item name="password" :rules="[{ required: true, message: '密码不能为空' }]"> <a-input-password v-model:value="formState.password" placeholder="请输入登录密码" class="input" @click="closeLogoutAlert" > <template #prefix> <key-outlined class="input-icon"/> </template> </a-input-password> </a-form-item> <a-form-item name="captcha" :rules="[{ required: true, message: '校验码不能为空' }]"> <a-row> <a-col :span="16"> <a-input v-model:value="formState.captcha" placeholder="请输入校验码" class="input" style="width: 270px" @click="closeLogoutAlert" > <template #prefix> <safety-outlined class="input-icon"/> </template> </a-input> </a-col> <a-col :span="8" style="display: flex; justify-content: flex-end;"> <img class="captcha-img" :src="captchaImgSrc" alt="校验码" @click="onCaptchaClick"> </a-col> </a-row> </a-form-item> <a-form-item> <a-button type="primary" html-type="submit" block :loading="loginLoading" class="input" style="font-size: 18px;font-weight: bolder;" > 登录 </a-button> </a-form-item> </a-form> <!--错误反馈--> <a-alert v-if="alertError.show" :message="alertError.msg" type="error" show-icon style="border-radius: 6px;" /> <!--退出登录反馈--> <a-alert v-if="logoutAlert" message="您已成功退出" type="success" show-icon style="border-radius: 6px;" /> </section> </main> </div> </template> <style scoped lang="less"> @import "../assets/var"; .login { min-height: 100vh; display: flex; justify-content: center; align-items: center; background-color: #ecf5ff; main { width: 800px; height: 540px; background-color: white; border-radius: 8px; box-shadow: @box-shadow-base; display: flex; .left { width: 330px; background-image: url(../assets/login-bg-2.svg), url(../assets/login-bg-1.svg); background-position: left top, left top; background-repeat: no-repeat no-repeat; display: flex; flex-direction: column; align-items: center; color: white; border-top-left-radius: 8px; border-bottom-left-radius: 8px; .title { font-size: 20px; font-weight: bolder; } .sub-title { font-size: 12px; margin-top: 8px; } img { width: 80px; border-radius: 50%; margin: 32px 0 24px 0; } } .right { flex-grow: 1; padding: 32px; .title { font-size: 18px; color: #666; font-weight: bolder; display: inline-block; margin-right: 8px; } .sub-title { font-size: 14px; color: #999; } .ant-form { margin-top: 80px; .input { height: 50px; border-radius: 6px; .input-icon { font-size: 24px; color: #cccccc; } &.ant-input-affix-wrapper-focused { .input-icon { color: #409eff; } } } .captcha-img { width: 126px; height: 49px; border: 1px solid #d9d9d9; border-radius: 6px; cursor: pointer; } } } } } </style>
router.js中
import {createRouter, createWebHistory} from 'vue-router'; import routes from './routes.js'; import NProgress from 'nprogress'; import 'nprogress/nprogress.css'; import {getSessionStorage, isBlank, isNil} from './util/common-util.js'; import appConstant from './app-constant.js'; import {Modal} from 'ant-design-vue'; // modules全局使用,以免上生产后页面无法访问 const modules = import.meta.glob('./pages/**/*.vue'); const router = createRouter({ history: createWebHistory(), routes }); router.beforeEach(async (to, from) => { Modal.destroyAll(); NProgress.start(); if (to.path !== '/') { if (!hasNecessaryRoute(to)) { const routeObj = generateRoute(to); if (isNil(routeObj)) { return '/404' } else { router.addRoute('Layout', routeObj); return to.fullPath; } } } const loginUser = getSessionStorage(appConstant.SK_LOGIN_USER, false); const isLogin = !isBlank(loginUser); if (!isLogin) { // 未登录,只允许访问登录页面 if (to.path !== '/login') { return '/login'; } } else { // 已登录,不允许访问登录页面 if (to.path === '/login') { return from.path; } } if (to.path === '/') { // 不同登录状态下,对 / 路径的重定向 return isLogin ? '/home' : '/login'; } return true; }); router.afterEach(() => { NProgress.done(); }); // 判断当前跳转的路由是否在router.getRoutes()里面 function hasNecessaryRoute(to) { return router.getRoutes().findIndex(r => r.path === to.path) !== -1; } function generateRoute(to) { const menus = getSessionStorage(appConstant.SK_LOGIN_USER, true)?.menus; if (isBlank(menus)) { return null; } const find = menus.filter(m => m.menuType === 'MENU').find(m=>m.linkLocation === to.path); if (isNil(find)) { return null; } return { path: find.linkLocation, component: modules[`./${find.componentLocation}`] }; } export default router;
标签:const,vue3,js,return,router,import,login,动态,路由 From: https://www.cnblogs.com/evident/p/16868678.html