当前位置:   article > 正文

vue3+ts+axios+pinia动态路由_vue3 ts pinia axios 获取token

vue3 ts pinia axios 获取token

项目结构介绍

                                  

模块名说明
views页面
storespinia全局状态管理
router路由
requestaxios请求封装
modules模块数据格式封装
directive自定义指令
components组件

 请求封装

        request工具类封装

  1. //导入axios
  2. import axios from "axios";
  3. import type{ AxiosInstance, AxiosResponse, InternalAxiosRequestConfig, AxiosRequestConfig,AxiosError } from "axios"
  4. //element-plus 弹窗
  5. import { ElMessage } from 'element-plus'
  6. //响应结果类型
  7. import type{result} from '@/modules/base/Base.ts'
  8. //导入路由对象
  9. import router from '@/router/index'
  10. //导入token状态管理
  11. import {useUserInfoStore} from '@/stores/UserInfo'
  12. //根路径
  13. export const config={
  14. baseURL: 'http://localhost:9001',
  15. timeout: 10000,
  16. headers:{
  17. 'Content-Type':'application/json'
  18. }
  19. }
  20. //请求类
  21. export class HttpBase{
  22. // axios的实例
  23. private instance: AxiosInstance;
  24. // 初始化的作用
  25. constructor(configs: AxiosRequestConfig) {
  26. // 创建axios的实例
  27. this.instance = axios.create(configs)
  28. // 配置拦截器
  29. this.interceptors()
  30. }
  31. private interceptors() {
  32. // 拦截请求
  33. this.instance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
  34. //获取token
  35. const token=useUserInfoStore().getToken
  36. if(token){
  37. config.headers.token=token
  38. }
  39. return config
  40. }), (error: any) => {
  41. error.data = {}
  42. error.data.message = '服务器异常请联系管理员'
  43. return error
  44. }
  45. // 拦截响应
  46. this.instance.interceptors.response.use((res: AxiosResponse) => {
  47. //获取token
  48. const token=res.headers.token;
  49. if(token){
  50. useUserInfoStore().setToken(token)
  51. }
  52. // 这里面可以做一些接口返回状态的判断
  53. //执行成功返回状态码以2开头,主要作用对于修改成功、新增成功等操作的消息提醒
  54. if ( /^2/.test(res.data.code)) {
  55. if(res.data.code!=200){
  56. ElMessage.success(res.data.message)
  57. }
  58. return Promise.resolve(res.data)
  59. } else {
  60. //执行异常的消息提醒
  61. ElMessage.error(res.data.message)
  62. return Promise.reject(res.data.message || '接口报错')
  63. }
  64. },(error: AxiosError) => {
  65. if(error.code==="ERR_NETWORK"){
  66. ElMessage.error('请检查您的网络')
  67. }else{
  68. const status=error.response.status;
  69. HttpBase.errorHandle(status)
  70. }
  71. return Promise.reject(error)
  72. })
  73. }
  74. // 下面是对几个请求方式的封装
  75. // post
  76. protected post<T = result>(url: string, data?: object): Promise<T> {
  77. return this.instance.post(url, data)
  78. }
  79. //put
  80. protected put<T = result>(url: string, data?: object): Promise<T> {
  81. return this.instance.put(url, data)
  82. }
  83. // get
  84. protected get<T = result>(url: string, params?: object): Promise<T> {
  85. return this.instance.get(url, { params })
  86. }
  87. // delete
  88. protected delete<T = result>(url: string): Promise<T> {
  89. return this.instance.delete(url)
  90. }
  91. // 图片上传
  92. protected upload<T = result>(url: string, params?: object): Promise<T> {
  93. return this.instance.post(url, params, {
  94. headers: {
  95. 'Content-Type': 'multipart/form-data'
  96. }
  97. })
  98. }
  99. private static errorHandle(status:number) {
  100. // 状态码判断
  101. switch (status) {
  102. case 404:
  103. router.push('/404')
  104. break
  105. case 500:
  106. router.push('/500')
  107. break
  108. default:
  109. }
  110. }
  111. }

         菜单请求封装

  1. import {HttpBase,config} from '@/request/base/index'
  2. import type{ListMenu} from '@/modules/menu/MenuInfo'
  3. // axios的配置项
  4. const BaseUrl=config.baseURL+'/auth/menu'
  5. class HttpMenu extends HttpBase{
  6. /**
  7. * 获取用户可访问权限
  8. * @returns
  9. */
  10. async getMenuByUser():Promise<Array<ListMenu>>{
  11. //获取用户可访问菜单
  12. const url=BaseUrl+'/getMenuByUserId'
  13. return (await super.get(url)).data
  14. }
  15. }
  16. export default new HttpMenu(config);

数据实体封装

  1. import type{BaseModule} from '@/modules/base/Base'
  2. interface ListMenu extends BaseModule{
  3. menuName:string,//菜单名称
  4. menuCode:string,//菜单编码
  5. parentId:number,//菜单父id
  6. routerPath:string,//路由地址
  7. componentPath:string,//组件所在位置
  8. menuType:number,//菜单类型
  9. authorityCode:string,//权限编码
  10. requestUrl:string,//请求路径
  11. children:Array<ListMenu>//子级
  12. icon:string//菜单图标
  13. }
  14. export type{ListMenu}

pinia全局状态管理封装

  1. import { defineStore } from 'pinia'
  2. import {computed, reactive, ref} from 'vue'
  3. import type{ListMenu} from '@/modules/menu/MenuInfo'
  4. import HttpMenu from '@/request/menu/Menu';
  5. export const useMenuInfoStore = defineStore('menuInfo', () => {
  6. //获取标识符
  7. const menuFlag=ref<Boolean>(false)
  8. //获取菜单是否获取标识符
  9. const getMenuFlag=computed(()=>menuFlag.value)
  10. //响应式菜单集合数据
  11. const menuListInfo=reactive<Array<ListMenu>>([]);
  12. //获取菜单权限
  13. const getMenu=computed(async ()=>{
  14. //判断是否有权限
  15. if(!menuFlag.value){
  16. await getMenuByUser();
  17. }
  18. menuFlag.value=true;
  19. return menuListInfo;
  20. })
  21. //发送请求获取用户可访问菜单权限
  22. async function getMenuByUser(){
  23. try{
  24. const result=await HttpMenu.getMenuByUser()
  25. menuListInfo.push(...result)
  26. }catch(e){
  27. console.log(e)
  28. }
  29. }
  30. return {getMenu,getMenuFlag}
  31. })

路由封装

  1. import { createRouter, createWebHistory } from 'vue-router'
  2. //登录页
  3. import LoginView from '@/views/login/LoginView.vue'
  4. //首页
  5. import IndexView from '@/views/index/IndexView.vue'
  6. //导入token 状态管理
  7. import {useUserInfoStore} from '@/stores/UserInfo'
  8. //导入获取权限状态管理
  9. import { useMenuInfoStore } from '@/stores/MenuInfo'
  10. const router = createRouter({
  11. history: createWebHistory(import.meta.env.BASE_URL),
  12. routes: [
  13. {
  14. path:'/',
  15. redirect:'/login'
  16. },
  17. {
  18. path:'/login',
  19. name:'login',
  20. component: LoginView
  21. },
  22. {
  23. path:'/index',
  24. name:'index',
  25. component: IndexView
  26. }
  27. ]
  28. })
  29. router.beforeEach( async (to,from,next)=>{
  30. const userStore=useUserInfoStore();
  31. const menuStore=useMenuInfoStore();
  32. //验证是否登录
  33. if(to.path!='/login'){
  34. //获取token
  35. const token=userStore.getToken
  36. if(!token){
  37. router.push('/login')
  38. return ;
  39. }
  40. const menuFlag=menuStore.getMenuFlag;
  41. //判断是否为首页并且没有获取过菜单权限
  42. if(!menuFlag ){
  43. const modules = import.meta.glob("@/views/*/*.vue");
  44. //获取菜单权限
  45. const menuList= await menuStore.getMenu
  46. //循环遍历菜单
  47. for(const menuInfo of menuList){
  48. const children=menuInfo.children
  49. if(children){
  50. for(const childrenInfo of children){
  51. const menu={
  52. path:childrenInfo.routerPath,
  53. name:childrenInfo.menuCode,
  54. // component :() => import(`..${childrenInfo.componentPath}.vue`)
  55. component :modules[`/src${childrenInfo.componentPath}.vue`]
  56. }
  57. router.addRoute('index',menu)
  58. }
  59. }
  60. }
  61. next({...to,replace:true})
  62. return
  63. }
  64. }
  65. next()
  66. })
  67. export default router

菜单渲染

  1. <template>
  2. <el-row class="tac">
  3. <el-col >
  4. <el-menu class="el-menu-vertical-demo" :router="true">
  5. <el-menu-item index="/index">
  6. <el-icon><House /></el-icon>
  7. <span>首页</span>
  8. </el-menu-item>
  9. <el-sub-menu v-for="menu in menuList" :key="menu.id" :index="menu.id">
  10. <template #title>
  11. <el-icon><component :is="menu.icon"></component></el-icon>
  12. <span>{{ menu.menuName }}</span>
  13. </template><el-menu-item-group>
  14. <template v-for="children in menu.children" :key="children.id">
  15. <el-menu-item :index="children.id" :route="children.routerPath">
  16. {{ children.menuName }}
  17. </el-menu-item>
  18. </template>
  19. </el-menu-item-group>
  20. </el-sub-menu>
  21. </el-menu>
  22. </el-col>
  23. </el-row>
  24. </template>
  25. <script lang="ts" setup>
  26. import { useMenuInfoStore } from '@/stores/MenuInfo'
  27. import { reactive } from 'vue'
  28. import type { ListMenu } from '@/modules/menu/MenuInfo'
  29. import { onMounted } from 'vue'
  30. //菜单集合
  31. let menuList = reactive<Array<ListMenu>>([])
  32. //菜单全局管理对象
  33. const menuStore=useMenuInfoStore();
  34. //获取菜单集合
  35. const getMenu = async () => {
  36. const menuInfoList = await menuStore.getMenu
  37. menuList.push(...menuInfoList)
  38. }
  39. onMounted(() => {
  40. getMenu()
  41. })
  42. </script>
  43. <style scoped>
  44. .el-row {
  45. height: 100%;
  46. }
  47. .el-menu {
  48. height: 100%;
  49. }
  50. </style>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/225636
推荐阅读
相关标签
  

闽ICP备14008679号