forked from tools/tape-springboot-sysadmin
init
This commit is contained in:
171
src/store/user.js
Normal file
171
src/store/user.js
Normal file
@@ -0,0 +1,171 @@
|
||||
import { ref } from "vue";
|
||||
import { defineStore } from "pinia";
|
||||
import { apiRequest } from "@/iview/utils/request";
|
||||
import { toAny } from "@/iview/utils/toany";
|
||||
import { on } from "@/iview/utils/emitter";
|
||||
import config from "@/config/index";
|
||||
|
||||
const generateKey = (key) => {
|
||||
return `${config.APP_CACHE_PROFIX}_${key}`;
|
||||
};
|
||||
|
||||
const getStorageValue = (key) => {
|
||||
return Promise.resolve().then(() => {
|
||||
key = generateKey(key);
|
||||
const value = localStorage.getItem(key);
|
||||
return toAny(value, {}).value;
|
||||
});
|
||||
};
|
||||
|
||||
const setStorageValue = (key, value) => {
|
||||
return Promise.resolve().then(() => {
|
||||
key = generateKey(key);
|
||||
localStorage.setItem(
|
||||
key,
|
||||
toAny({ key, value }, "")
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const removeStorageValue = (key) => {
|
||||
return Promise.resolve().then(() => {
|
||||
key = generateKey(key);
|
||||
localStorage.removeItem(key);
|
||||
});
|
||||
};
|
||||
|
||||
const API_LOGIN = "api.system.admin.info.auth.login";
|
||||
const API_PROFILE = "api.system.admin.info.auth.profile";
|
||||
const API_REFRESH_TOKEN = `refreshToken`;
|
||||
const KEY_SIDEBAR_COLLAPSE = "state_collapseSidebar";
|
||||
const KEY_LAST_USERNAME = "state_lastUsername";
|
||||
const KEY_REFRESH_TOKEN = "state_refreshToken";
|
||||
const KEY_USER_TOKEN = "state_userToken";
|
||||
const KEY_USER_INFO = "state_userInfo";
|
||||
|
||||
/** 防止 103 / 刷新失败 连续触发时重复跳转 */
|
||||
let sessionExpiryHandling = false;
|
||||
|
||||
export const useUserStore = defineStore("user", {
|
||||
state: () => ({
|
||||
initialized: ref(false),
|
||||
collapseSidebar: ref(false),
|
||||
lastUsername: ref(null),
|
||||
refreshToken: ref(null),
|
||||
userToken: ref(null),
|
||||
userInfo: ref(null),
|
||||
}),
|
||||
|
||||
getters: {
|
||||
isLoggedIn: (state) => !!state.userToken,
|
||||
isInitialized: (state) => state.initialized,
|
||||
isCollapseSidebar: (state) => state.collapseSidebar,
|
||||
isSuper: (state) => state.userInfo?.optSuper === 1,
|
||||
username: (state) => state.userInfo?.username,
|
||||
nickname: (state) => state.userInfo?.nickname,
|
||||
},
|
||||
|
||||
actions: {
|
||||
async init() {
|
||||
const collapseSidebar = await getStorageValue(KEY_SIDEBAR_COLLAPSE);
|
||||
const lastUsername = await getStorageValue(KEY_LAST_USERNAME);
|
||||
const refreshToken = await getStorageValue(KEY_REFRESH_TOKEN);
|
||||
const userToken = await getStorageValue(KEY_USER_TOKEN);
|
||||
const userInfo = await getStorageValue(KEY_USER_INFO);
|
||||
this.initialized = true;
|
||||
this.collapseSidebar = collapseSidebar === "true";
|
||||
this.lastUsername = lastUsername;
|
||||
this.refreshToken = refreshToken;
|
||||
this.userToken = userToken;
|
||||
this.userInfo = userInfo;
|
||||
},
|
||||
// 登录
|
||||
async login(username, password) {
|
||||
const data = await apiRequest(API_LOGIN, {
|
||||
username,
|
||||
password,
|
||||
});
|
||||
this.userToken = data.token;
|
||||
this.refreshToken = data.refreshToken;
|
||||
this.lastUsername = username;
|
||||
await setStorageValue(KEY_LAST_USERNAME, username);
|
||||
await setStorageValue(KEY_REFRESH_TOKEN, data.refreshToken);
|
||||
await setStorageValue(KEY_USER_TOKEN, data.token);
|
||||
await this.getUserProfile();
|
||||
return { success: true };
|
||||
},
|
||||
|
||||
|
||||
// 刷新Token
|
||||
async refreshUserToken() {
|
||||
if (!this.refreshToken) {
|
||||
throw new Error("No refresh token available");
|
||||
}
|
||||
try {
|
||||
const data = await apiRequest(API_REFRESH_TOKEN, {
|
||||
refreshToken: this.refreshToken,
|
||||
});
|
||||
this.userToken = data.token;
|
||||
this.refreshToken = data.refreshToken;
|
||||
await setStorageValue(KEY_USER_TOKEN, data.token);
|
||||
await setStorageValue(KEY_REFRESH_TOKEN, data.refreshToken);
|
||||
return {
|
||||
success: true,
|
||||
token: data.token,
|
||||
refreshToken: data.refreshToken
|
||||
};
|
||||
} catch (error) {
|
||||
this.refreshToken = null;
|
||||
await removeStorageValue(KEY_REFRESH_TOKEN);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
// 获取用户信息
|
||||
async getUserProfile() {
|
||||
const userInfo = await apiRequest(API_PROFILE, {});
|
||||
this.userInfo = userInfo;
|
||||
await setStorageValue(KEY_USER_INFO, userInfo);
|
||||
return { success: true, data: userInfo };
|
||||
},
|
||||
|
||||
// 退出登录
|
||||
async logout() {
|
||||
this.userToken = "";
|
||||
this.refreshToken = "";
|
||||
this.userInfo = {};
|
||||
await removeStorageValue(KEY_USER_INFO);
|
||||
await removeStorageValue(KEY_USER_TOKEN);
|
||||
await removeStorageValue(KEY_REFRESH_TOKEN);
|
||||
},
|
||||
|
||||
async saveCollapseSidebar(collapse) {
|
||||
this.collapseSidebar = !!collapse;
|
||||
await setStorageValue(KEY_SIDEBAR_COLLAPSE, this.collapseSidebar ? "true" : "false");
|
||||
},
|
||||
|
||||
/** 登录失效:清状态并跳到登录(用动态 import router,避免与 request 循环依赖且保证能拿到路由器实例) */
|
||||
async handleSessionExpired() {
|
||||
if (sessionExpiryHandling) return;
|
||||
sessionExpiryHandling = true;
|
||||
try {
|
||||
await this.logout();
|
||||
const { default: router } = await import("@/config/router");
|
||||
const current = router.currentRoute.value;
|
||||
if (current.path === "/login") return;
|
||||
await router.replace({
|
||||
path: "/login",
|
||||
query: { redirect: current.fullPath },
|
||||
});
|
||||
} finally {
|
||||
sessionExpiryHandling = false;
|
||||
}
|
||||
},
|
||||
|
||||
initTokenExpirationListener() {
|
||||
on("auth:token-expired", () => {
|
||||
void this.handleSessionExpired();
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user