Vue3 中使用axios、vuex等

发布于:2025-02-11 ⋅ 阅读:(33) ⋅ 点赞:(0)

1.安装vuex、axios、js-cookie、vue-router

vuex命令行:

npm install vuex@next --save

axios命令行:

npm install axios

js-cookie命令行:

npm install js-cookie

vue-router命令行:

npm install vue-router

2.配置文件

(1)缓存文件配置

src/plugins/auth.js

const sessionCache = {
  set (key, value) {
    if (!sessionStorage) {
      return
    }
    if (key != null && value != null) {
      sessionStorage.setItem(key, value)
    }
  },
  get (key) {
    if (!sessionStorage) {
      return null
    }
    if (key == null) {
      return null
    }
    return sessionStorage.getItem(key)
  },
  setJSON (key, jsonValue) {
    if (jsonValue != null) {
      this.set(key, JSON.stringify(jsonValue))
    }
  },
  getJSON (key) {
    const value = this.get(key)
    if (value != null) {
      return JSON.parse(value)
    }
  },
  remove (key) {
    sessionStorage.removeItem(key);
  }
}
const localCache = {
  set (key, value) {
    if (!localStorage) {
      return
    }
    if (key != null && value != null) {
      localStorage.setItem(key, value)
    }
  },
  get (key) {
    if (!localStorage) {
      return null
    }
    if (key == null) {
      return null
    }
    return localStorage.getItem(key)
  },
  setJSON (key, jsonValue) {
    if (jsonValue != null) {
      this.set(key, JSON.stringify(jsonValue))
    }
  },
  getJSON (key) {
    const value = this.get(key)
    if (value != null) {
      return JSON.parse(value)
    }
  },
  remove (key) {
    localStorage.removeItem(key);
  }
}

export default {
  /**
   * 会话级缓存
   */
  session: sessionCache,
  /**
   * 本地缓存
   */
  local: localCache
}

(2)js-cookie文件配置

src/utils/auth.js

import Cookies from 'js-cookie'

const TokenKey = 'Admin-gis-jcpt-Token'

export function getToken() {
  return Cookies.get(TokenKey)
}

export function setToken(token) {
  return Cookies.set(TokenKey, token)
}

export function removeToken() {
  return Cookies.remove(TokenKey)
}

(3)axios文件配置

src/utils/axiosHttp.js

import axios from "axios";
import { getToken } from '@/utils/auth';
import cache from '@/plugins/cache';
import store from "@/store";

axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8';// 传参方式json
//axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded';//传参方式表单
// 设置接口超时时间
const timeout = 60000;
// 设置请求地址
const baseURL = 'http://192.168.1.167:8080/gis_jcpt';

// 创建axios实例
const service = axios.create({
    // axios中请求配置有baseURL选项,表示请求URL公共部分
    //baseURL: process.env.VUE_APP_BASE_API,
    baseURL:baseURL,
    // 超时
    timeout: timeout
  })

// http request 请求拦截器
service.interceptors.request.use(config =>{
         // 是否需要设置 token
        const isToken = (config.headers || {}).isToken === false
        // 是否需要防止数据重复提交
        const isRepeatSubmit = (config.headers || {}).repeatSubmit === false;
        if (getToken() && !isToken) {
            //console.log("getToken",getToken());
            config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
        }
        
         // get请求映射params参数
        if (config.method === 'get' && config.params) {
            let url = config.url + '?' + tansParams(config.params);
            url = url.slice(0, -1);
            config.params = {};
            config.url = url;
        }

        if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
            const requestObj = {
              url: config.url,
              data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
              time: new Date().getTime()
            }
            const requestSize = Object.keys(JSON.stringify(requestObj)).length; // 请求数据大小
            const limitSize = 5 * 1024 * 1024; // 限制存放数据5M
            if (requestSize >= limitSize) {
              console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制,无法进行防重复提交验证。')
              return config;
            }
            const sessionObj = cache.session.getJSON('sessionObj')
            if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
              cache.session.setJSON('sessionObj', requestObj)
            } else {
              const s_url = sessionObj.url;                  // 请求地址
              const s_data = sessionObj.data;                // 请求数据
              const s_time = sessionObj.time;                // 请求时间
              const interval = 1000;                         // 间隔时间(ms),小于此时间视为重复提交
              if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
                const message = '数据正在处理,请勿重复提交';
                console.warn(`[${s_url}]: ` + message)
                return Promise.reject(new Error(message))
              } else {
                cache.session.setJSON('sessionObj', requestObj)
              }
            }
          }
    
        return config;
    },
    error =>{
        console.log(error)
        return Promise.reject(error);
    }
)

// http response 响应拦截器
service.interceptors.response.use(response =>{
         // 未设置状态码则默认成功状态
         const code = response.data.code || 200;
         const msg = response.data.msg || '请求错误';
         if(code === 401){
            // 登录状态过期-退出
            store.dispatch('Logout').then(()=>{
                location.href = '/';
            })
         }else if(code === 500){
            return Promise.reject(new Error(msg));
         }else if(code === 601){
            //
            return Promise.reject('error');
         }else if(code !== 200){
            return Promise.reject('error');    
         }else {
            return response.data;
         }

    },
    error =>{
        console.log('err' + error)
        let { message } = error;
        if (message == "Network Error") {
          message = "后端接口连接异常";
        } else if (message.includes("timeout")) {
          message = "系统接口请求超时";
        } else if (message.includes("Request failed with status code")) {
          message = "系统接口" + message.substr(message.length - 3) + "异常";
        }
        console.log("message",message);
        return Promise.reject(error)
    }
)

export default service;

登录请求为例:

src/api/login.js

import request  from "@/utils/axiosHttp";

// 登录方法
export function login(username, password, code, uuid) {
    const data = {
      username,
      password,
      code,
      uuid
    }
    return request({
      url: '/login',
      headers: {
        isToken: false,
        repeatSubmit: false
      },
      method: 'post',
      data: data
    })
  }
  
// 获取用户详细信息
export function getInfo() {
    return request({
      url: '/getInfo',
      method: 'get'
    })
  }
  
  // 退出方法
  export function logout() {
    return request({
      url: '/logout',
      method: 'post'
    })
  }

// 获取验证码
export function getCodeImg() {
    return request({
      url: '/captchaImage',
      headers: {
        isToken: false,

      },
      method: 'get',
      timeout: 20000
    })
  }

(4)vuex文件配置:

src/store/index.js

// store/index.js
import { createStore } from 'vuex';
import {login, logout, getInfo} from '@/api/login';
import { getToken, setToken, removeToken } from '@/utils/auth'

export default createStore({
  state: {
    token: null,
    isLoggedIn: false, // 初始状态为未登录
    user: null // 存储用户信息
  },
  getters: {
    token: state => state.token,
    isLoggedIn: state => state.isLoggedIn,
    user: state => state.user,
  },
  mutations: {
    SET_TOKEN: (state, token) => {
      state.token = token
    },
    SET_ID: (state, id) => {
      state.id = id
    },
    SET_NAME: (state, name) => {
      state.name = name
    },
    SET_AVATAR: (state, avatar) => {
      state.avatar = avatar
    },
    SET_ROLES: (state, roles) => {
      state.roles = roles
    },
    SET_PERMISSIONS: (state, permissions) => {
      state.permissions = permissions
    },
    setLoginStatus(state, status) {  
      state.isLoggedIn = status;
    },
    setUser(state, user) {
      state.user = user;
    }
  },
  actions: {
    Login({ commit }, user) {
      const username = user.username.trim();
      const password = user.password;
      const code = user.code;
      const uuid = user.uuid;

      return new Promise((resolve,reject)=>{
          login(username,password,code,uuid).then(res =>{
            if(res.code === 200){
              setToken(res.token);
              commit('SET_TOKEN', res.token);
              
              commit('setLoginStatus', true);
              // 不保存到localStorage,刷新浏览器token、isLoggedIn、user信息重置为空
              localStorage.setItem('auth', JSON.stringify(user)); // 用户信息保存到localStorage
              localStorage.setItem('setLoginStatus', true); // 登录成功状态保存到localStorage

              resolve(true);
            }else{
              alert(res.data.msg);
            }
           
          }).catch(error =>{
            reject(error);
          })
      })


    },

     // 获取用户信息
     GetInfo({ commit, state }) {
      return new Promise((resolve, reject) => {
        getInfo().then(res => {
          const user = res.user;
          // 获取头像
          //const avatar = (user.avatar == "" || user.avatar == null) ? "@/assets/images/figure-1.png" : process.env.VUE_APP_BASE_API + user.avatar;
          const avatar = "@/assets/images/figure-1.png"; 
          if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
            commit('SET_ROLES', res.roles)
            commit('SET_PERMISSIONS', res.permissions)
          } else {
            commit('SET_ROLES', ['ROLE_DEFAULT'])
          }
          commit('SET_ID', user.userId)
          commit('SET_NAME', user.userName)
          commit('SET_AVATAR', avatar)
          resolve(res)
        }).catch(error => {
          reject(error)
        })
      })
    },
    // 退出系统
    Logout({ commit }) {
      const logoutToken = {
        token:getToken(),
      }
      return new Promise((resolve,reject)=>{
        logout(logoutToken).then(() => {
          commit('SET_TOKEN', '')
          commit('SET_ROLES', [])
          commit('SET_PERMISSIONS', [])
          removeToken()

          commit('setLoginStatus', false);
          localStorage.removeItem('auth');// 从localStorage移除
          localStorage.removeItem('setLoginStatus');// 从localStorage移除
          
          resolve()
        }).catch(error => {
          reject(error)
        })
      })
    }
  }
});

(5)main.js重新配置登录状态 

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
//使用mitt插件
import mitt from 'mitt'
// Vue Router
import router from '@/router'

import store from './store';

//openlayers
import 'ol/ol.css';
// 通用字体
import 'vfonts/Lato.css'
//windiCss
import 'virtual:windi.css'

const app = createApp(App);
// 从localStorage获取数据
const isLoggedIn = localStorage.getItem('setLoginStatus');// 获取登录状态
const savedUser = localStorage.getItem('auth');// 获取登录用户信息
if (savedUser) {
  store.commit('setLoginStatus', isLoggedIn);
  store.commit('setUser', JSON.parse(savedUser));
}
//挂载全局属性
app.config.globalProperties.$eventBus = mitt();
app.use(router)
app.use(store)
app.mount('#app')

(6)router页面

 

src/router/index.js

// 该文件是专门用于创建整个应用的路由器
import { createRouter, createWebHistory } from "vue-router";
import Home from "@/views/Home.vue";

import Login from "@/views/Login.vue";
import store from '@/store'; // 引入 Vuex store


const routes = [
  { path: "/", component: Login},
  { path: "/login",name: "login", component: Login },
  // { path: "/login", name: "login", component: Login },
  { path: "/index", name: "index", component: Home,meta: { requiresAuth: true }  },
];
const router = createRouter({
  history: createWebHistory(),
  routes,
});

router.beforeEach((to, from, next) => {
  if (to.matched.some(record => record.meta.requiresAuth)) {
    if (!store.getters.isLoggedIn) {
      next({ path: '/login' }); // 如果用户未认证,则重定向到登录页面
    } else {
      next(); // 如果用户已认证,则允许访问该页面
    }
  } else {
    next(); // 确保其他不需要认证的页面可以正常访问
  }
})

// 创建router实例对象并暴露
export default router;

3.使用示例

登录:

***
***
<script setup>
import {onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { useStore } from 'vuex';
import { _service } from '@/api';
import { useRequest } from 'alova/client';
import {getCodeImg} from '@/api/login';

const router = useRouter()
const store = useStore();
const code = ref('');
const codeUrl = ref('');
const uuid = ref('');
const username = ref('admin');
const password = ref('xxzxadmin');
// 验证码开关
const captchaEnabled = ref('');

onMounted(()=>{
    getCode();
});

// 获取验证码
const getCode = async() =>{
    getCodeImg().then(res => {
        //console.log("res",res);
        captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled;
        if (captchaEnabled.value) {
          codeUrl.value = "data:image/gif;base64," + res.img;
          uuid.value = res.uuid;
        }
      });
}

// 登录方法
const loginHandle = () => {
    // router.push('/')
    const user = {
        username: username.value,
        password: password.value,
        code: code.value,
        uuid: uuid.value
      };
    store.dispatch('Login', user).then((isLogin) => {
        if(isLogin){
            // 登录成功后跳转到首页或其他页面
            router.push('/index');
        }
      }).catch((error) => { 
        console.error('Login failed:', error);
        alert(error);
        // 调用获取验证码方法
        getCode();
        
      });
    
}
</script>
***
***

获取用户信息:

onMounted(()=>{
    // 获取用户信息
    store.dispatch('GetInfo').then((res)=>{
        console.log("GetInfo",res);
    })
})

退出:

***
***
<script setup>
import { useRouter } from 'vue-router';
import store from "@/store";

const router = useRouter()

// 退出按钮
const logout = () =>{
    // 退出
    store.dispatch('Logout').then(()=>{
         // 退出成功后跳转到登录页面
         //router.push('/');
         // 跳转到退出页面(当前页面打开URL页面)
         location.href = '/';
    })
}

</script>
***
***

后台为若依


网站公告

今日签到

点亮在社区的每一天
去签到