| | |
| | | const router = useRouter(); |
| | | |
| | | const loginLoading = ref(false); |
| | | let sessionVersion = 0; |
| | | let logoutTask: Promise<void> | null = null; |
| | | |
| | | /** |
| | | * 异步处理登录操作 |
| | |
| | | ) { |
| | | // 异步处理用户登录操作并获取 accessToken |
| | | let userInfo: null | UserInfo = null; |
| | | const version = ++sessionVersion; |
| | | try { |
| | | let loginResult: AuthApi.LoginResult; |
| | | loginLoading.value = true; |
| | |
| | | } |
| | | } |
| | | const { accessToken, refreshToken } = loginResult; |
| | | if (version !== sessionVersion) return { userInfo: null }; |
| | | |
| | | // 如果成功获取到 accessToken |
| | | if (accessToken) { |
| | |
| | | // // getAccessCodesApi(), |
| | | // ]); |
| | | const fetchUserInfoResult = await fetchUserInfo(); |
| | | if (version !== sessionVersion) return { userInfo: null }; |
| | | |
| | | userInfo = fetchUserInfoResult.user; |
| | | |
| | |
| | | }); |
| | | } |
| | | } |
| | | } catch (error) { |
| | | if (version === sessionVersion) throw error; |
| | | return { userInfo: null }; |
| | | } finally { |
| | | loginLoading.value = false; |
| | | if (version === sessionVersion) loginLoading.value = false; |
| | | } |
| | | |
| | | return { |
| | |
| | | }; |
| | | } |
| | | |
| | | async function logout(redirect: boolean = true) { |
| | | function logout(redirect: boolean = true): Promise<void> { |
| | | if (logoutTask) return logoutTask; |
| | | const accessToken = accessStore.accessToken; |
| | | const tenant = { tenantId: accessStore.tenantId, visitTenantId: accessStore.visitTenantId }; |
| | | const fullPath = router.currentRoute.value.fullPath; |
| | | ++sessionVersion; |
| | | // 服务器注销独立执行,本地清理与跳转不等待网络。 |
| | | // 使用退出前的 token 和租户快照,避免清理后丢失注销上下文。 |
| | | if (accessToken) void logoutApi(accessToken, tenant).catch(() => {}); |
| | | logoutTask = clearSessionAndNavigate(redirect, fullPath).finally(() => { logoutTask = null; }); |
| | | return logoutTask; |
| | | } |
| | | |
| | | async function clearSessionAndNavigate(redirect: boolean, fullPath: string) { |
| | | try { |
| | | const accessToken = accessStore.accessToken as string; |
| | | if (accessToken) { |
| | | await logoutApi(accessToken); |
| | | } |
| | | } catch { |
| | | // 不做任何处理 |
| | | } |
| | | resetAllStores(); |
| | | } catch (error) { |
| | | console.error('Failed to reset business stores during logout', error); |
| | | } |
| | | // 认证清理不能依赖业务 store 的重置结果。 |
| | | accessStore.$reset(); |
| | | userStore.$reset(); |
| | | accessStore.setLoginExpired(false); |
| | | |
| | | // 回登录页带上当前路由地址 |
| | |
| | | path: LOGIN_PATH, |
| | | query: redirect |
| | | ? { |
| | | redirect: encodeURIComponent(router.currentRoute.value.fullPath), |
| | | redirect: encodeURIComponent(fullPath), |
| | | } |
| | | : {}, |
| | | }); |
| | | } |
| | | |
| | | async function fetchUserInfo() { |
| | | const version = sessionVersion; |
| | | const accessToken = accessStore.accessToken; |
| | | // 加载 |
| | | // eslint-disable-next-line no-useless-assignment |
| | | let authPermissionInfo: AuthPermissionInfo | null = null; |
| | | authPermissionInfo = await getAuthPermissionInfoApi(); |
| | | if (version !== sessionVersion || accessToken !== accessStore.accessToken) { |
| | | throw new Error('登录状态已变化,忽略旧会话的用户信息'); |
| | | } |
| | | await loadAuditPolicy(); |
| | | if (version !== sessionVersion || accessToken !== accessStore.accessToken) { |
| | | throw new Error('登录状态已变化,忽略旧会话的用户信息'); |
| | | } |
| | | // userStore |
| | | userStore.setUserInfo(authPermissionInfo.user); |
| | | userStore.setUserRoles(authPermissionInfo.roles); |