在依赖安装部分,我们使用更好用的 Pinia 替代 Vuex,并进行了基础的配置。

该部分我们添加一点些需要进行状态管理的对象。

常量

创建src/store/mutation-types.js,写入以下内容:

store/mutation-types.js
export const ACCESS_TOKEN = 'ACCESS-TOKEN'; // 用户token
export const CURRENT_USER = 'CURRENT-USER'; // 当前用户信息
export const TABS_ROUTES = 'TABS-ROUTES'; // 标签页

用户状态管理

值得注意的是,登陆和获取用户信息的请求是在此处发起的。

网络请求方法:getUserInfo, login将在网络配置部分予以实现,这里为了不报错可实现两个空方法。

创建src/store/modules/user.js,写入以下内容:

store/modules/user.js
import { storage } from '@/utils/Storage';
import { defineStore } from 'pinia';
import { store } from '@/store';
import { ACCESS_TOKEN, CURRENT_USER } from '../mutation-types';
import { getUserInfo, login } from '@/api/system/user';
import { ResultEnum } from '@/enums/httpEnum';

export const useUserStore = defineStore({
id: 'app-user',
state: () => ({
token: storage.get(ACCESS_TOKEN, ''),
username: '',
welcome: '',
avatar: '',
permissions: [],
info: storage.get(CURRENT_USER, {}),
}),
getters: {
getToken() {
return this.token;
},
getAvatar() {
return this.avatar;
},
getNickname() {
return this.username;
},
getPermissions() {
return this.permissions;
},
getUserInfo() {
return this.info;
},
},
actions: {
setToken(token) {
this.token = token;
},
setAvatar(avatar) {
this.avatar = avatar;
},
setPermissions(permissions) {
this.permissions = permissions;
},
setUserInfo(info) {
this.info = info;
},
// 登录
async login(userInfo) {
try {
const response = await login(userInfo);
const { data: result, code } = response;
if (code === ResultEnum.SUCCESS) {
const ex = 7 * 24 * 60 * 60;
storage.set(ACCESS_TOKEN, result.token, ex);
storage.set(CURRENT_USER, result, ex);
this.setToken(result.token);
this.setUserInfo(result);
}
return Promise.resolve(response);
} catch (e) {
return Promise.reject(e);
}
},

// 获取用户信息
GetInfo() {
const that = this;
return new Promise((resolve, reject) => {
getUserInfo()
.then((res) => {
const result = res;
if (result.permissions && result.permissions.length) {
const permissionsList = result.permissions;
that.setPermissions(permissionsList);
that.setUserInfo(result);
} else {
reject(
new Error('getInfo: permissionsList must be a non-null array !')
);
}
that.setAvatar(result.avatar);
resolve(res);
})
.catch((error) => {
reject(error);
});
});
},

// 登出
async logout() {
this.setPermissions([]);
this.setUserInfo('');
storage.remove(ACCESS_TOKEN);
storage.remove(CURRENT_USER);
return Promise.resolve('');
},
},
});

// Need to be used outside the setup
export function useUserStoreWidthOut() {
return useUserStore(store);
}

标签页状态管理

不使用标签页功能时,可不添加其状态管理

本项目实现了页面标签页以及组件缓存功能。

创建src/store/modules/tabsView.js,写入以下内容:

store/modules/tabsView.js
import { defineStore } from 'pinia';

// 不需要出现在标签页中的路由
const whiteList = ['Redirect', 'login'];

//保留固定路由
function retainAffixRoute(list) {
return list.filter((item) => item?.meta?.affix ?? false);
}

export const useTabsViewStore = defineStore({
id: 'app-tabs-view',
state: () => ({
tabsList: [],
}),
getters: {},
actions: {
initTabs(routes) {
// 初始化标签页
this.tabsList = routes;
},
addTabs(route) {
// 添加标签页
if (whiteList.includes(route.name)) return false;
const isExists = this.tabsList.some(
(item) => item.fullPath == route.fullPath
);
if (!isExists) {
this.tabsList.push(route);
}
return true;
},
closeLeftTabs(route) {
// 关闭左侧
const index = this.tabsList.findIndex(
(item) => item.fullPath == route.fullPath
);
this.tabsList = this.tabsList.filter(
(item, i) => i >= index || (item?.meta?.affix ?? false)
);
},
closeRightTabs(route) {
// 关闭右侧
const index = this.tabsList.findIndex(
(item) => item.fullPath == route.fullPath
);
this.tabsList = this.tabsList.filter(
(item, i) => i <= index || (item?.meta?.affix ?? false)
);
},
closeOtherTabs(route) {
// 关闭其他
this.tabsList = this.tabsList.filter(
(item) =>
item.fullPath == route.fullPath || (item?.meta?.affix ?? false)
);
},
closeCurrentTab(route) {
// 关闭当前页
const index = this.tabsList.findIndex(
(item) => item.fullPath == route.fullPath
);
this.tabsList.splice(index, 1);
},
closeAllTabs() {
// 关闭全部
console.log(retainAffixRoute(this.tabsList));
this.tabsList = retainAffixRoute(this.tabsList);
},
},
});