useEnterpriseAuth.ts 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import { ref, computed } from 'vue';
  2. import { fetchEnterpriseInfo, fetchEnterpriseLogin, type EnterpriseInfo } from '@/network/api/enterprise';
  3. const TEMP_HISTORY_KEY = 'ba_temp_chat_history';
  4. const AUTH_HISTORY_KEY = 'ba_chat_history';
  5. const AUTH_CURRENT_SESSION_KEY = 'ba_current_session_id';
  6. const ENTERPRISE_INFO_KEY = 'ba_enterprise_info';
  7. const AUTH_TOKEN_KEY = 'ba_auth_token';
  8. export const enterpriseInfo = ref<EnterpriseInfo | null>(null);
  9. const authLoading = ref(false);
  10. const authError = ref(false);
  11. // Global fetch interceptor: any 401 response → clear enterprise info (logout)
  12. (function setupFetchInterceptor() {
  13. if (typeof window === 'undefined') return;
  14. const originalFetch = window.fetch.bind(window);
  15. window.fetch = async (...args: Parameters<typeof fetch>) => {
  16. const response = await originalFetch(...args);
  17. if (response.status === 401 && enterpriseInfo.value) {
  18. enterpriseInfo.value = null;
  19. globalThis.authToken = undefined;
  20. globalThis.token = undefined;
  21. localStorage.removeItem(ENTERPRISE_INFO_KEY);
  22. localStorage.removeItem(AUTH_TOKEN_KEY);
  23. }
  24. return response;
  25. };
  26. })();
  27. export function getQueryParamUniversal(key: string): string | null {
  28. const searchParams = new URLSearchParams(window.location.search);
  29. if (searchParams.has(key)) {
  30. return searchParams.get(key);
  31. }
  32. const hash = window.location.hash;
  33. const queryIndex = hash.indexOf('?');
  34. if (queryIndex !== -1) {
  35. const hashQuery = hash.substring(queryIndex + 1);
  36. const hashParams = new URLSearchParams(hashQuery);
  37. return hashParams.get(key);
  38. }
  39. return null;
  40. }
  41. export function getChatHistoryStorageKey(): string {
  42. return enterpriseInfo.value ? AUTH_HISTORY_KEY : TEMP_HISTORY_KEY;
  43. }
  44. export function getCurrentSessionStorageKey(): string {
  45. return AUTH_CURRENT_SESSION_KEY;
  46. }
  47. export function useEnterpriseAuth() {
  48. const isLoggedIn = computed(() => !!enterpriseInfo.value);
  49. const enterpriseName = computed(() => enterpriseInfo.value?.name || '');
  50. const creditCode = computed(() => enterpriseInfo.value?.credit_code || '');
  51. const initAuth = async () => {
  52. const creditCodeParam = getQueryParamUniversal('credit_code');
  53. const accessToken = getQueryParamUniversal('access_token');
  54. // 跟随 querystring 的 policyMode:A/B 测试变体(如 zhaoshang_staging_1)也需体现在 source 中
  55. globalThis.source = globalThis.policyMode || "zhaoshang";
  56. // 1. access_token 存在: 换取 credit_code + authToken, 再拉企业信息
  57. // [已移除] 开发环境的硬编码账号自动登录:它会让「没登录也进入登录态」,
  58. // 与真实用户路径不符(访客记录就验证不了)。要企业态请显式带
  59. // ?access_token=<token> 或 ?credit_code=<代码>。
  60. if (accessToken && !creditCodeParam) {
  61. authLoading.value = true;
  62. authError.value = false;
  63. try {
  64. const loginResult = await fetchEnterpriseLogin(accessToken);
  65. if (loginResult) {
  66. globalThis.authToken = loginResult.authToken;
  67. globalThis.token = loginResult.authToken;
  68. localStorage.setItem(AUTH_TOKEN_KEY, loginResult.authToken);
  69. authLoading.value = false;
  70. return await initAuthWithCreditCode(loginResult.creditCode);
  71. }
  72. } catch {
  73. authError.value = true;
  74. } finally {
  75. authLoading.value = false;
  76. }
  77. return;
  78. }
  79. // 2. credit_code 存在: 直接拉企业信息
  80. if (creditCodeParam) {
  81. return await initAuthWithCreditCode(creditCodeParam);
  82. }
  83. // 3. 无参数: 保持未登录状态
  84. };
  85. const initAuthWithCreditCode = async (creditCodeParam: string) => {
  86. authLoading.value = true;
  87. authError.value = false;
  88. try {
  89. const info = await fetchEnterpriseInfo(creditCodeParam);
  90. if (info) {
  91. enterpriseInfo.value = info;
  92. const cc = info.credit_code || creditCodeParam;
  93. (globalThis as any).credit_code = cc;
  94. (globalThis as any).transmission = {
  95. ...((globalThis as any).transmission || {}),
  96. credit_code: cc,
  97. };
  98. localStorage.setItem(ENTERPRISE_INFO_KEY, JSON.stringify(info));
  99. }
  100. } catch {
  101. authError.value = true;
  102. } finally {
  103. authLoading.value = false;
  104. }
  105. };
  106. const logout = () => {
  107. enterpriseInfo.value = null;
  108. globalThis.authToken = undefined;
  109. globalThis.token = undefined;
  110. localStorage.removeItem(ENTERPRISE_INFO_KEY);
  111. localStorage.removeItem(AUTH_TOKEN_KEY);
  112. };
  113. const redirectToLogin = () => {
  114. const isProduction = import.meta.env.MODE === 'production';
  115. const currentUrl = isProduction
  116. ? `https://aixq.shqp.gov.cn/zhaoshang/redirect.html#zhaoshang?mode=${globalThis.policyMode}`
  117. : `https://aixq.shqp.gov.cn/zhaoshang/#/?mode=zhaoshang`;
  118. const sourceLink = `https://zwdtuser.sh.gov.cn/uc/login/login.jsp?sendPost=false&type=2&redirect_uri=${encodeURIComponent(currentUrl)}`;
  119. window.location.href = sourceLink;
  120. };
  121. return {
  122. isLoggedIn,
  123. enterpriseName,
  124. creditCode,
  125. enterpriseInfo,
  126. authLoading,
  127. authError,
  128. initAuth,
  129. logout,
  130. redirectToLogin,
  131. };
  132. }