Files
springboot-shop-sysadmin/src/store/user.js
iqudoo eb4e8f1a04 init
2026-06-05 17:22:32 +08:00

172 lines
5.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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();
});
},
},
});