云
19 小时以前 c2e8526f8f857be5e3a8c6f2b39c5efd424de33e
src/store/auth.ts
@@ -29,6 +29,8 @@
  const router = useRouter();
  const loginLoading = ref(false);
  let sessionVersion = 0;
  let logoutTask: Promise<void> | null = null;
  /**
   * 异步处理登录操作
@@ -44,6 +46,7 @@
  ) {
    // 异步处理用户登录操作并获取 accessToken
    let userInfo: null | UserInfo = null;
    const version = ++sessionVersion;
    try {
      let loginResult: AuthApi.LoginResult;
      loginLoading.value = true;
@@ -65,6 +68,7 @@
        }
      }
      const { accessToken, refreshToken } = loginResult;
      if (version !== sessionVersion) return { userInfo: null };
      // 如果成功获取到 accessToken
      if (accessToken) {
@@ -78,6 +82,7 @@
        //   // getAccessCodesApi(),
        // ]);
        const fetchUserInfoResult = await fetchUserInfo();
        if (version !== sessionVersion) return { userInfo: null };
        userInfo = fetchUserInfoResult.user;
@@ -98,8 +103,11 @@
          });
        }
      }
    } catch (error) {
      if (version === sessionVersion) throw error;
      return { userInfo: null };
    } finally {
      loginLoading.value = false;
      if (version === sessionVersion) loginLoading.value = false;
    }
    return {
@@ -107,16 +115,28 @@
    };
  }
  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);
    // 回登录页带上当前路由地址
@@ -124,18 +144,26 @@
      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);