Files
xinlong-shop-taro/src_bak/contexts/UserContext.tsx
赵忠林 1fa58040f3 feat(user): 新增收货地址管理及售后申请页面
- 新增地址类型定义,增强前端地址数据结构
- 新增地址编辑页面,支持地址智能识别和定位选点功能
- 地址编辑支持省市区选择及默认地址设置
- 新增地址列表页面,支持地址展示、删除、编辑和选择功能
- 实现售后申请页面,支持选择售后类型和退款原因
- 售后申请支持商品选择、退款金额计算和凭证上传
- 新增售后详情页面,支持售后状态展示及申请取消
- 优化页面加载和用户交互体验,增加错误提示和权限处理
2026-07-01 12:11:56 +08:00

136 lines
4.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { createContext, useContext, useState, useEffect, type ReactNode } from 'react'
import Taro from '@tarojs/taro'
import type { User } from '@/api/system/user/model'
import { getUserInfo, loginByOpenId } from '@/api/layout'
import { saveStorageByLoginUser, clearStorageByLoginUser } from '@/utils/server'
import { TenantId } from '@/config/app'
interface UserContextType {
user: User | null
isLoggedIn: boolean
loading: boolean
loginUser: (token: string, userInfo: User) => void
logoutUser: () => void
refreshUser: () => Promise<User | null>
syncFromStorage: () => boolean
}
const UserContext = createContext<UserContextType | undefined>(undefined)
export const UserProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
const [user, setUser] = useState<User | null>(null)
const [loading, setLoading] = useState(true)
useEffect(() => {
const init = async () => {
const token = Taro.getStorageSync('access_token')
const userData = Taro.getStorageSync('User')
// 情况1: 有本地token和用户数据直接使用
if (token && userData) {
const parsed = typeof userData === 'string' ? JSON.parse(userData) : userData
setUser(parsed as User)
setLoading(false)
return
}
// 情况2: 有token但没有用户数据尝试从接口获取
if (token) {
try {
const userInfo = await getUserInfo()
setUser(userInfo)
setLoading(false)
return
} catch {
// token无效清除并尝试静默登录
clearStorageByLoginUser()
}
}
// 情况3: 没有本地token尝试静默登录老用户自动登录
try {
const loginResult = await new Promise<{ access_token?: string; user?: User }>((resolve, reject) => {
Taro.login({
success: (res) => {
if (res.code) {
loginByOpenId({ code: res.code, tenantId: TenantId })
.then(resolve)
.catch(reject)
} else {
reject(new Error('no code'))
}
},
fail: reject,
})
})
// 静默登录成功(老用户),自动完成登录
if (loginResult?.access_token && loginResult?.user) {
saveStorageByLoginUser(loginResult.access_token, loginResult.user)
setUser(loginResult.user)
}
} catch {
// 静默登录失败(非老用户或网络问题),保持未登录状态
}
setLoading(false)
}
init()
}, [])
const loginUser = (token: string, userInfo: User) => {
saveStorageByLoginUser(token, userInfo)
setUser(userInfo)
}
const logoutUser = () => {
clearStorageByLoginUser()
setUser(null)
}
/** 从 storage 快速同步用户状态(无需网络请求),供页面 useDidShow 调用 */
const syncFromStorage = (): boolean => {
const token = Taro.getStorageSync('access_token')
const userData = Taro.getStorageSync('User')
if (token && userData) {
const parsed = typeof userData === 'string' ? JSON.parse(userData) : userData
setUser(parsed as User)
return true
}
if (!token) {
setUser(null)
}
return false
}
const refreshUser = async (): Promise<User | null> => {
if (!Taro.getStorageSync('access_token')) return null
try {
const userInfo = await getUserInfo()
const token = Taro.getStorageSync('access_token')
if (token) {
saveStorageByLoginUser(token, userInfo)
}
setUser(userInfo)
return userInfo
} catch {
return null
}
}
return (
<UserContext.Provider
value={{ user, isLoggedIn: !!user, loading, loginUser, logoutUser, refreshUser, syncFromStorage }}
>
{children}
</UserContext.Provider>
)
}
export const useUserContext = (): UserContextType => {
const context = useContext(UserContext)
if (!context) {
throw new Error('useUserContext must be used within UserProvider')
}
return context
}