|
@@ -1,8 +1,9 @@
|
|
|
-import { createContext, useContext, PropsWithChildren } from 'react'
|
|
|
|
|
|
|
+import { createContext, useContext, PropsWithChildren, useState } from 'react'
|
|
|
import Taro, { useLaunch } from '@tarojs/taro'
|
|
import Taro, { useLaunch } from '@tarojs/taro'
|
|
|
import { authClient } from '../api'
|
|
import { authClient } from '../api'
|
|
|
import { InferResponseType, InferRequestType } from 'hono'
|
|
import { InferResponseType, InferRequestType } from 'hono'
|
|
|
-import { QueryClient, useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
|
|
|
|
|
|
+import { useMutation } from '@tanstack/react-query'
|
|
|
|
|
+import { isWeapp, isH5 } from './platform'
|
|
|
|
|
|
|
|
// 用户类型定义
|
|
// 用户类型定义
|
|
|
export type User = InferResponseType<typeof authClient.me.$get, 200>
|
|
export type User = InferResponseType<typeof authClient.me.$get, 200>
|
|
@@ -22,73 +23,92 @@ interface AuthContextType {
|
|
|
|
|
|
|
|
const AuthContext = createContext<AuthContextType | undefined>(undefined)
|
|
const AuthContext = createContext<AuthContextType | undefined>(undefined)
|
|
|
|
|
|
|
|
-const queryClient = new QueryClient()
|
|
|
|
|
-
|
|
|
|
|
export const AuthProvider: React.FC<PropsWithChildren> = ({ children }) => {
|
|
export const AuthProvider: React.FC<PropsWithChildren> = ({ children }) => {
|
|
|
- const queryClient = useQueryClient()
|
|
|
|
|
|
|
|
|
|
- const { data: user, isLoading } = useQuery<User | null, Error>({
|
|
|
|
|
- queryKey: ['currentUser'],
|
|
|
|
|
- queryFn: async () => {
|
|
|
|
|
- const token = Taro.getStorageSync('mini_token')
|
|
|
|
|
- if (!token) {
|
|
|
|
|
- return null
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 用户状态
|
|
|
|
|
+ const [user, setUser] = useState<User | null>(() => {
|
|
|
|
|
+ // 从本地存储初始化用户信息
|
|
|
|
|
+ const userInfoStr = Taro.getStorageSync('userInfo')
|
|
|
|
|
+ if (userInfoStr) {
|
|
|
try {
|
|
try {
|
|
|
- const response = await authClient.me.$get({})
|
|
|
|
|
- if (response.status !== 200) {
|
|
|
|
|
- throw new Error('获取用户信息失败')
|
|
|
|
|
- }
|
|
|
|
|
- const user = await response.json()
|
|
|
|
|
- Taro.setStorageSync('userInfo', JSON.stringify(user))
|
|
|
|
|
- return user
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- Taro.removeStorageSync('mini_token')
|
|
|
|
|
- Taro.removeStorageSync('userInfo')
|
|
|
|
|
|
|
+ return JSON.parse(userInfoStr)
|
|
|
|
|
+ } catch {
|
|
|
return null
|
|
return null
|
|
|
}
|
|
}
|
|
|
- },
|
|
|
|
|
- staleTime: Infinity, // 用户信息不常变动,设为无限期
|
|
|
|
|
- refetchOnWindowFocus: false, // 失去焦点不重新获取
|
|
|
|
|
- refetchOnReconnect: false, // 网络重连不重新获取
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+ return null
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
- // 静默登录mutation - 应用启动时自动尝试登录
|
|
|
|
|
- const silentLoginMutation = useMutation<MiniLoginUser | null, Error, void>({
|
|
|
|
|
- mutationFn: async () => {
|
|
|
|
|
- try {
|
|
|
|
|
- // 尝试静默登录
|
|
|
|
|
- const loginRes = await Taro.login()
|
|
|
|
|
- if (!loginRes.code) {
|
|
|
|
|
- return null // 静默登录失败,但不抛出错误
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 使用小程序code进行静默登录
|
|
|
|
|
- const response = await authClient['mini-login'].$post({
|
|
|
|
|
- json: {
|
|
|
|
|
- code: loginRes.code,
|
|
|
|
|
- // 静默登录不请求用户信息
|
|
|
|
|
- tenantId: Number(process.env.TARO_APP_TENANT_ID) || 1
|
|
|
|
|
|
|
+ // 获取用户信息的通用函数
|
|
|
|
|
+ const fetchUserInfo = async (): Promise<User | null> => {
|
|
|
|
|
+ // const token = Taro.getStorageSync('mini_token')
|
|
|
|
|
+ // if (!token) {
|
|
|
|
|
+ // return null
|
|
|
|
|
+ // }
|
|
|
|
|
+ try {
|
|
|
|
|
+ const response = await authClient.me.$get({})
|
|
|
|
|
+ if (response.status !== 200) {
|
|
|
|
|
+ throw new Error('获取用户信息失败')
|
|
|
|
|
+ }
|
|
|
|
|
+ const user = await response.json()
|
|
|
|
|
+ Taro.setStorageSync('userInfo', JSON.stringify(user))
|
|
|
|
|
+ return user
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ // Token失效时的处理逻辑
|
|
|
|
|
+ console.debug('Token失效,开始处理重新登录逻辑')
|
|
|
|
|
+
|
|
|
|
|
+ if (isWeapp()) {
|
|
|
|
|
+ // 小程序环境:使用静默登录重新获取token
|
|
|
|
|
+ console.debug('小程序环境,尝试静默登录')
|
|
|
|
|
+ try {
|
|
|
|
|
+ const loginRes = await Taro.login()
|
|
|
|
|
+ if (loginRes.code) {
|
|
|
|
|
+ const response = await authClient['mini-login'].$post({
|
|
|
|
|
+ json: {
|
|
|
|
|
+ code: loginRes.code,
|
|
|
|
|
+ tenantId: Number(process.env.TARO_APP_TENANT_ID) || 1
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ if (response.status === 200) {
|
|
|
|
|
+ const { token: newToken } = await response.json()
|
|
|
|
|
+ Taro.setStorageSync('mini_token', newToken)
|
|
|
|
|
+
|
|
|
|
|
+ // 重新获取完整的用户信息
|
|
|
|
|
+ const meResponse = await authClient.me.$get({})
|
|
|
|
|
+ if (meResponse.status === 200) {
|
|
|
|
|
+ const user = await meResponse.json()
|
|
|
|
|
+ Taro.setStorageSync('userInfo', JSON.stringify(user))
|
|
|
|
|
+ console.debug('静默登录成功,返回新用户信息')
|
|
|
|
|
+ return user
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- if (response.status === 200) {
|
|
|
|
|
- const { token, user } = await response.json()
|
|
|
|
|
- Taro.setStorageSync('mini_token', token)
|
|
|
|
|
- Taro.setStorageSync('userInfo', JSON.stringify(user))
|
|
|
|
|
- return user
|
|
|
|
|
|
|
+ } catch (silentLoginError) {
|
|
|
|
|
+ console.debug('静默登录失败:', silentLoginError)
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- return null // 静默登录失败
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- // 静默登录失败不抛出错误,不影响用户体验
|
|
|
|
|
- console.debug('静默登录失败:', error)
|
|
|
|
|
- return null
|
|
|
|
|
|
|
+ } else if (isH5()) {
|
|
|
|
|
+ // H5环境:跳转到登录页
|
|
|
|
|
+ console.debug('H5环境,跳转到登录页')
|
|
|
|
|
+ Taro.redirectTo({ url: '/pages/login/index' })
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // 如果重新登录失败或不是小程序环境,清除token并返回null
|
|
|
|
|
+ Taro.removeStorageSync('mini_token')
|
|
|
|
|
+ Taro.removeStorageSync('userInfo')
|
|
|
|
|
+ return null
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 静默登录mutation - 应用启动时自动尝试登录
|
|
|
|
|
+ const silentLoginMutation = useMutation<User | null, Error, void>({
|
|
|
|
|
+ mutationFn: async () => {
|
|
|
|
|
+ // 使用统一的用户信息获取函数
|
|
|
|
|
+ return await fetchUserInfo()
|
|
|
},
|
|
},
|
|
|
onSuccess: (user) => {
|
|
onSuccess: (user) => {
|
|
|
if (user) {
|
|
if (user) {
|
|
|
- queryClient.setQueryData(['currentUser'], user)
|
|
|
|
|
|
|
+ setUser(user)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
@@ -113,7 +133,7 @@ export const AuthProvider: React.FC<PropsWithChildren> = ({ children }) => {
|
|
|
return user
|
|
return user
|
|
|
},
|
|
},
|
|
|
onSuccess: (newUser) => {
|
|
onSuccess: (newUser) => {
|
|
|
- queryClient.setQueryData(['currentUser'], newUser)
|
|
|
|
|
|
|
+ setUser(newUser)
|
|
|
},
|
|
},
|
|
|
onError: (error) => {
|
|
onError: (error) => {
|
|
|
Taro.showToast({
|
|
Taro.showToast({
|
|
@@ -136,7 +156,7 @@ export const AuthProvider: React.FC<PropsWithChildren> = ({ children }) => {
|
|
|
return user
|
|
return user
|
|
|
},
|
|
},
|
|
|
onSuccess: (newUser) => {
|
|
onSuccess: (newUser) => {
|
|
|
- queryClient.setQueryData(['currentUser'], newUser)
|
|
|
|
|
|
|
+ setUser(newUser)
|
|
|
},
|
|
},
|
|
|
onError: (error) => {
|
|
onError: (error) => {
|
|
|
Taro.showToast({
|
|
Taro.showToast({
|
|
@@ -162,7 +182,7 @@ export const AuthProvider: React.FC<PropsWithChildren> = ({ children }) => {
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
onSuccess: () => {
|
|
onSuccess: () => {
|
|
|
- queryClient.setQueryData(['currentUser'], null)
|
|
|
|
|
|
|
+ setUser(null)
|
|
|
Taro.redirectTo({ url: '/pages/login/index' })
|
|
Taro.redirectTo({ url: '/pages/login/index' })
|
|
|
},
|
|
},
|
|
|
onError: (error) => {
|
|
onError: (error) => {
|
|
@@ -185,7 +205,7 @@ export const AuthProvider: React.FC<PropsWithChildren> = ({ children }) => {
|
|
|
return updatedUser
|
|
return updatedUser
|
|
|
},
|
|
},
|
|
|
onSuccess: (updatedUser) => {
|
|
onSuccess: (updatedUser) => {
|
|
|
- queryClient.setQueryData(['currentUser'], updatedUser)
|
|
|
|
|
|
|
+ setUser(updatedUser)
|
|
|
Taro.showToast({
|
|
Taro.showToast({
|
|
|
title: '更新成功',
|
|
title: '更新成功',
|
|
|
icon: 'success',
|
|
icon: 'success',
|
|
@@ -203,27 +223,6 @@ export const AuthProvider: React.FC<PropsWithChildren> = ({ children }) => {
|
|
|
|
|
|
|
|
const updateUser = updateUserMutation.mutateAsync
|
|
const updateUser = updateUserMutation.mutateAsync
|
|
|
|
|
|
|
|
- // // 使用React Query获取用户信息
|
|
|
|
|
- // const { data: user } = useQuery<User | null>({
|
|
|
|
|
- // queryKey: ['currentUser'],
|
|
|
|
|
- // queryFn: async () => {
|
|
|
|
|
- // // 直接从本地存储获取用户信息
|
|
|
|
|
- // const userInfoStr = Taro.getStorageSync('userInfo')
|
|
|
|
|
- // if (userInfoStr) {
|
|
|
|
|
- // try {
|
|
|
|
|
- // return JSON.parse(userInfoStr)
|
|
|
|
|
- // } catch {
|
|
|
|
|
- // return null
|
|
|
|
|
- // }
|
|
|
|
|
- // }
|
|
|
|
|
- // return null
|
|
|
|
|
- // },
|
|
|
|
|
- // staleTime: Infinity, // 用户信息不常变动,设为无限期
|
|
|
|
|
- // refetchOnWindowFocus: false, // 失去焦点不重新获取
|
|
|
|
|
- // refetchOnReconnect: false, // 网络重连不重新获取
|
|
|
|
|
- // enabled: false, // 不自动执行,由静默登录和登录mutation更新
|
|
|
|
|
- // })
|
|
|
|
|
-
|
|
|
|
|
const value = {
|
|
const value = {
|
|
|
user: user || null,
|
|
user: user || null,
|
|
|
login: loginMutation.mutateAsync,
|
|
login: loginMutation.mutateAsync,
|
|
@@ -243,6 +242,4 @@ export const useAuth = () => {
|
|
|
throw new Error('useAuth must be used within an AuthProvider')
|
|
throw new Error('useAuth must be used within an AuthProvider')
|
|
|
}
|
|
}
|
|
|
return context
|
|
return context
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-export { queryClient }
|
|
|
|
|
|
|
+}
|