192 lines
5.2 KiB
TypeScript
192 lines
5.2 KiB
TypeScript
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<string[]>([]);
|
|
const menus = ref<RouteRecordRaw[]>([]);
|
|
const userInfo = ref<Partial<API.UserEntity>>({});
|
|
const serverConnected = ref(true);
|
|
const domain = ref<API.DomainType>(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);
|
|
}
|