import { nextTick, ref, watch } from 'vue'; import { defineStore } from 'pinia'; import { useDictStore } from './dict'; import { useRouter, type RouteRecordRaw, useRoute } from 'vue-router'; import { store } from '@/store'; import Api from '@/api/'; import { ACCESS_TOKEN_KEY, DOMAIN_KEY } from '@/enums/cacheEnum'; import { Storage } from '@/utils/Storage'; import { resetRouter } from '@/router'; import { generateDynamicRoutes } from '@/router/helper/routeHelper'; import { uniqueSlash } from '@/utils/urlUtils'; import { useKeepAliveStore } from './keepAlive'; import { message } from 'ant-design-vue'; import { LOGIN_NAME } from '@/router/constant'; export type MessageEvent = { data?: any; type?: 'ping' | 'close' | 'updatePermsAndMenus'; }; export const useUserStore = defineStore('user', () => { let eventSource: EventSource | null = null; const token = ref(Storage.get(ACCESS_TOKEN_KEY, null)); const name = ref('admin'); const perms = ref([]); const menus = ref([]); const userInfo = ref>({}); const serverConnected = ref(true); const domain = ref(Storage.get(DOMAIN_KEY, null)); watch(serverConnected, (val) => { if (val) { initServerMsgListener(); } }); const closeEventSource = () => { serverConnected.value = false; eventSource?.close(); eventSource = null; }; /** 监听来自服务端推送的消息 */ const initServerMsgListener = async () => { if (eventSource) { eventSource.close(); } const uid = userInfo.value.id; const sseUrl = uniqueSlash( `${import.meta.env.VITE_BASE_API_URL}/api/sse/${uid}?token=${token.value}`, ); eventSource = new EventSource(sseUrl); // 处理 SSE 传递的数据 eventSource.onmessage = (event) => { const { type } = JSON.parse(event.data) as MessageEvent; // 服务器关闭 SSE 连接 if (type === 'close') { closeEventSource(); } // 当用户的权限及菜单有变更时,重新获取权限及菜单 else if (type === 'updatePermsAndMenus') { fetchPermsAndMenus(); } // console.log('eventSource', event.data); }; eventSource.onerror = (err) => { console.log('eventSource err', err); closeEventSource(); }; }; const setServerConnectStatus = (isConnect: boolean) => { serverConnected.value = isConnect; }; /** 清空token及用户信息 */ const resetToken = () => { token.value = name.value = ''; perms.value = []; menus.value = []; userInfo.value = {}; Storage.clear(); }; /** 登录成功保存token */ const setToken = (_token: string) => { token.value = _token; // const ex = 7 * 24 * 60 * 60 * 1000; Storage.set(ACCESS_TOKEN_KEY, token.value); }; /** 登录 */ const login = async (params: API.LoginDto) => { try { const data = await Api.auth.authLogin(params); setToken(data.token); return afterLogin(); } catch (error) { return Promise.reject(error); } }; /** 解锁屏幕 */ const unlock = async (params: API.LoginDto) => { try { const data = await Api.auth.unlock(params); return data; } catch (error) { return Promise.reject(error); } }; /** 切换domain */ const changeDomain = (value) => { domain.value = value; Storage.set(DOMAIN_KEY, value); setTimeout(() => { // 刷新页面 window.location.reload(); }, 200); }; /** 登录成功之后, 获取用户信息以及生成权限路由 */ const afterLogin = async () => { try { const { accountProfile } = Api.account; useDictStore(); // const wsStore = useWsStore(); const userInfoData = await accountProfile(); userInfo.value = userInfoData; if (!Storage.get(DOMAIN_KEY)) { domain.value = userInfoData.domain; Storage.set(DOMAIN_KEY, domain.value); } await fetchPermsAndMenus(); initServerMsgListener(); } catch (error) { return Promise.reject(error); // return logout(); } }; /** 获取权限及菜单 */ const fetchPermsAndMenus = async () => { const { accountPermissions, accountMenu } = Api.account; // const wsStore = useWsStore(); const [menusData, permsData] = await Promise.all([accountMenu(), accountPermissions()]); perms.value = permsData; menus.value = generateDynamicRoutes(menusData as unknown as RouteRecordRaw[]); }; const keepAliveStore = useKeepAliveStore(); const router = useRouter(); const route = useRoute(); /** 登出 */ const logout = async () => { await Api.account.accountLogout(); closeEventSource(); resetToken(); resetRouter(); keepAliveStore.clear(); // 移除标签页 localStorage.clear(); await nextTick(); router.replace({ name: LOGIN_NAME, query: { redirect: route.fullPath, }, }); }; return { token, name, perms, menus, userInfo, domain, changeDomain, login, unlock, afterLogin, logout, resetToken, setServerConnectStatus, }; }); // 在组件setup函数外使用 export function useUserStoreWithOut() { return useUserStore(store); }