| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- import { createContext, useContext, PropsWithChildren, useState } from 'react'
- import Taro from '@tarojs/taro'
- import { authClient } from '../api'
- import { InferResponseType, InferRequestType } from 'hono'
- import { QueryClient, QueryClientProvider, useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
- // 用户类型定义
- export type User = InferResponseType<typeof authClient.me.$get, 200>
- type LoginRequest = InferRequestType<typeof authClient.login.$post>['json']
- type RegisterRequest = InferRequestType<typeof authClient.register.$post>['json']
- interface AuthContextType {
- user: User | null
- login: (data: LoginRequest) => Promise<User>
- logout: () => Promise<void>
- register: (data: RegisterRequest) => Promise<User>
- updateUser: (userData: Partial<User>) => void
- isLoading: boolean
- isLoggedIn: boolean
- }
- const AuthContext = createContext<AuthContextType | undefined>(undefined)
- const queryClient = new QueryClient()
- 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
- }
- 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 null
- }
- },
- staleTime: Infinity, // 用户信息不常变动,设为无限期
- refetchOnWindowFocus: false, // 失去焦点不重新获取
- refetchOnReconnect: false, // 网络重连不重新获取
- })
- const loginMutation = useMutation<User, Error, LoginRequest>({
- mutationFn: async (data) => {
- const response = await authClient.login.$post({ json: data })
- if (response.status !== 200) {
- throw new Error('登录失败')
- }
- const { token, user } = await response.json()
- Taro.setStorageSync('mini_token', token)
- Taro.setStorageSync('userInfo', JSON.stringify(user))
- return user
- },
- onSuccess: (newUser) => {
- queryClient.setQueryData(['currentUser'], newUser)
- },
- onError: (error) => {
- Taro.showToast({
- title: error.message || '登录失败,请检查用户名和密码',
- icon: 'none',
- duration: 2000,
- })
- },
- })
- const registerMutation = useMutation<User, Error, RegisterRequest>({
- mutationFn: async (data) => {
- const response = await authClient.register.$post({ json: data })
- if (response.status !== 201) {
- throw new Error('注册失败')
- }
- const { token, user } = await response.json()
- Taro.setStorageSync('mini_token', token)
- Taro.setStorageSync('userInfo', JSON.stringify(user))
- return user
- },
- onSuccess: (newUser) => {
- queryClient.setQueryData(['currentUser'], newUser)
- },
- onError: (error) => {
- Taro.showToast({
- title: error.message || '注册失败,请重试',
- icon: 'none',
- duration: 2000,
- })
- },
- })
- const logoutMutation = useMutation<void, Error>({
- mutationFn: async () => {
- try {
- const response = await authClient.logout.$post({})
- if (response.status !== 200) {
- throw new Error('登出失败')
- }
- } catch (error) {
- console.error('Logout error:', error)
- } finally {
- Taro.removeStorageSync('mini_token')
- Taro.removeStorageSync('userInfo')
- }
- },
- onSuccess: () => {
- queryClient.setQueryData(['currentUser'], null)
- Taro.redirectTo({ url: '/pages/login/index' })
- },
- onError: (error) => {
- Taro.showToast({
- title: error.message || '登出失败',
- icon: 'none',
- duration: 2000,
- })
- },
- })
- const updateUserMutation = useMutation<User, Error, Partial<User>>({
- mutationFn: async (userData) => {
- const response = await authClient.me.$put({ json: userData })
- if (response.status !== 200) {
- throw new Error('更新用户信息失败')
- }
- const updatedUser = await response.json()
- Taro.setStorageSync('userInfo', JSON.stringify(updatedUser))
- return updatedUser
- },
- onSuccess: (updatedUser) => {
- queryClient.setQueryData(['currentUser'], updatedUser)
- Taro.showToast({
- title: '更新成功',
- icon: 'success',
- duration: 2000,
- })
- },
- onError: (error) => {
- Taro.showToast({
- title: error.message || '更新失败,请重试',
- icon: 'none',
- duration: 2000,
- })
- },
- })
- const updateUser = updateUserMutation.mutateAsync
- const value = {
- user: user || null,
- login: loginMutation.mutateAsync,
- logout: logoutMutation.mutateAsync,
- register: registerMutation.mutateAsync,
- updateUser,
- isLoading: isLoading || loginMutation.isPending || registerMutation.isPending || logoutMutation.isPending,
- isLoggedIn: !!user,
- }
- return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
- }
- export const useAuth = () => {
- const context = useContext(AuthContext)
- if (context === undefined) {
- throw new Error('useAuth must be used within an AuthProvider')
- }
- return context
- }
- export { queryClient }
|