longz
2026-06-29 9d4cbff7464ebfd7803c2ce53ded49d0f73fe011
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import type { ApiError } from '@/api/core/handlers'
import type { MiniLoginResponse, MiniOfficialLoginResponse } from '@/types/auth'
import { fetchMiniMe, fetchOfficialOAuthUrl, loginByOfficialCode } from '@/api/auth'
import { normalizeLoginProfile, normalizeMeProfile } from '@/types/auth'
import { useMiniAuthStore } from '@/store/auth'
 
export const MINI_PHONE_AUTH_REQUIRED = 10008
 
export function getApiErrorCode(error: unknown) {
  return typeof error === 'object' && error != null && 'code' in error
    ? Number((error as ApiError).code)
    : NaN
}
 
function getCurrentH5UrlWithoutOAuthParams() {
  // #ifdef H5
  const url = new URL(window.location.href)
  url.searchParams.delete('code')
  url.searchParams.delete('state')
  if (url.hash.includes('?')) {
    const [hashPath, hashQuery = ''] = url.hash.split('?')
    const hashParams = new URLSearchParams(hashQuery)
    hashParams.delete('code')
    hashParams.delete('state')
    const nextHashQuery = hashParams.toString()
    url.hash = nextHashQuery ? `${hashPath}?${nextHashQuery}` : hashPath
  }
  return url.toString()
  // #endif
  // #ifndef H5
  return ''
  // #endif
}
 
function normalizeOfficialOAuthUrl(rawUrl: unknown) {
  const value = typeof rawUrl === 'string' ? rawUrl.trim() : ''
  if (!value) {
    throw new Error('获取公众号授权出错 请确定已关注')
  }
 
  let parsedUrl: URL
  try {
    parsedUrl = new URL(value)
  }
  catch {
    throw new Error('获取公众号授权出错 请确定已关注')
  }
 
  if (!['http:', 'https:'].includes(parsedUrl.protocol)) {
    throw new Error('获取公众号授权出错 请确定已关注')
  }
 
  return parsedUrl.toString()
}
 
export function clearOfficialOAuthQuery() {
  // #ifdef H5
  const url = new URL(window.location.href)
  let changed = url.searchParams.has('code') || url.searchParams.has('state')
  if (url.hash.includes('?')) {
    const [hashPath, hashQuery = ''] = url.hash.split('?')
    const hashParams = new URLSearchParams(hashQuery)
    if (hashParams.has('code') || hashParams.has('state')) {
      changed = true
    }
    hashParams.delete('code')
    hashParams.delete('state')
    const nextHashQuery = hashParams.toString()
    url.hash = nextHashQuery ? `${hashPath}?${nextHashQuery}` : hashPath
  }
  if (!changed) {
    return
  }
  url.searchParams.delete('code')
  url.searchParams.delete('state')
  window.history.replaceState({}, document.title, url.toString())
  // #endif
}
 
export async function startOfficialOAuthLogin() {
  // #ifdef H5
  const redirectUri = getCurrentH5UrlWithoutOAuthParams()
  const state = `${Date.now()}`
  const response = await fetchOfficialOAuthUrl({ redirectUri, state })
  window.location.href = normalizeOfficialOAuthUrl(response?.url)
  return
  // #endif
  // #ifndef H5
  throw new Error('当前环境暂不支持公众号授权登录')
  // #endif
}
 
export async function handleOfficialOAuthCallback(): Promise<MiniOfficialLoginResponse | null> {
  // #ifdef H5
  const url = new URL(window.location.href)
  let code = url.searchParams.get('code')
  if (!code && url.hash.includes('?')) {
    const hashQuery = url.hash.split('?')[1] || ''
    code = new URLSearchParams(hashQuery).get('code')
  }
  if (!code) {
    return null
  }
  return await loginByOfficialCode({ code })
  // #endif
  // #ifndef H5
  return null
  // #endif
}
 
export async function finishMiniLogin(loginData: MiniLoginResponse) {
  const authStore = useMiniAuthStore()
  authStore.setSession({
    token: loginData.token,
    profile: normalizeLoginProfile(loginData),
  })
 
  try {
    const profile = await fetchMiniMe(loginData.token)
    authStore.setProfile(normalizeMeProfile(profile))
  }
  catch (error) {
    console.warn('load mini profile failed after login', error)
  }
}