feat(user): 实现登录状态实时更新

- 使用 useUser Hook集中管理用户状态
- 登录成功后实时更新 Header 和 UserCard 组件
- 移除页面刷新操作,提升用户体验- 添加登录成功提示
This commit is contained in:
2025-09-05 12:14:46 +08:00
parent 0494fd01d0
commit 4ae36bc727
3 changed files with 218 additions and 112 deletions

View File

@@ -3,31 +3,33 @@ import Taro from '@tarojs/taro';
import {Button, Space} from '@nutui/nutui-react-taro'
import {TriangleDown} from '@nutui/icons-react-taro'
import {Avatar, NavBar} from '@nutui/nutui-react-taro'
import {getUserInfo, getWxOpenId} from "@/api/layout";
import {getWxOpenId} from "@/api/layout";
import {TenantId} from "@/config/app";
import {getOrganization} from "@/api/system/organization";
import {myUserVerify} from "@/api/system/userVerify";
import {useShopInfo} from '@/hooks/useShopInfo';
import {useUser} from '@/hooks/useUser';
import {handleInviteRelation} from "@/utils/invite";
import {View, Text} from '@tarojs/components'
import MySearch from "./MySearch";
import './Header.scss';
import navTo from "@/utils/common";
import {User} from "@/api/system/user/model";
const Header = (props: any) => {
// 使用新的useShopInfo Hook
const {
getWebsiteName,
getWebsiteLogo
} = useShopInfo();
const [IsLogin, setIsLogin] = useState<boolean>(true)
// 使用useUser Hook管理用户状态
const {
user,
isLoggedIn,
loginUser,
fetchUserInfo
} = useUser();
const [statusBarHeight, setStatusBarHeight] = useState<number>()
const [userInfo, setUserInfo] = useState<User>({
avatar: '',
mobile: '未登录'
})
const reload = async () => {
Taro.getSystemInfo({
@@ -35,56 +37,58 @@ const Header = (props: any) => {
setStatusBarHeight(res.statusBarHeight)
},
})
// 注意商店信息现在通过useShopInfo自动管理不需要手动获取
// 获取用户信息
const data = await getUserInfo();
if (data) {
setIsLogin(true);
console.log('用户信息>>>', data.phone)
// 保存userId
Taro.setStorageSync('UserId', data.userId)
// 获取openId
if (!data.openid) {
Taro.login({
success: (res) => {
getWxOpenId({code: res.code}).then(() => {
// 如果已登录,获取最新用户信息
if (isLoggedIn) {
try {
const data = await fetchUserInfo();
if (data) {
console.log('用户信息>>>', data.phone)
// 获取openId
if (!data.openid) {
Taro.login({
success: (res) => {
getWxOpenId({code: res.code}).then(() => {
})
}
})
}
})
}
// 是否已认证
if (data.certification) {
Taro.setStorageSync('Certification', '1')
}
// 机构ID
Taro.setStorageSync('OrganizationId', data.organizationId)
// 父级机构ID
if (Number(data.organizationId) > 0) {
getOrganization(Number(data.organizationId)).then(res => {
Taro.setStorageSync('OrganizationParentId', res.parentId)
})
}
// 管理员
const isKdy = data.roles?.findIndex(item => item.roleCode == 'admin')
if (isKdy != -1) {
Taro.setStorageSync('RoleName', '管理')
Taro.setStorageSync('RoleCode', 'admin')
return false;
}
// 注册用户
const isUser = data.roles?.findIndex(item => item.roleCode == 'user')
if (isUser != -1) {
Taro.setStorageSync('RoleName', '注册用户')
Taro.setStorageSync('RoleCode', 'user')
return false;
}
// 认证信息
myUserVerify({status: 1}).then(data => {
if (data?.realName) {
Taro.setStorageSync('RealName', data.realName)
// 是否已认证
if (data.certification) {
Taro.setStorageSync('Certification', '1')
}
// 机构ID
Taro.setStorageSync('OrganizationId', data.organizationId)
// 父级机构ID
if (Number(data.organizationId) > 0) {
getOrganization(Number(data.organizationId)).then(res => {
Taro.setStorageSync('OrganizationParentId', res.parentId)
})
}
// 管理员
const isKdy = data.roles?.findIndex(item => item.roleCode == 'admin')
if (isKdy != -1) {
Taro.setStorageSync('RoleName', '管理')
Taro.setStorageSync('RoleCode', 'admin')
return false;
}
// 注册用户
const isUser = data.roles?.findIndex(item => item.roleCode == 'user')
if (isUser != -1) {
Taro.setStorageSync('RoleName', '注册用户')
Taro.setStorageSync('RoleCode', 'user')
return false;
}
// 认证信息
myUserVerify({status: 1}).then(data => {
if (data?.realName) {
Taro.setStorageSync('RealName', data.realName)
}
})
}
})
setUserInfo(data)
} catch (error) {
console.error('获取用户信息失败:', error)
}
}
}
@@ -120,14 +124,16 @@ const Header = (props: any) => {
return false;
}
// 登录成功
Taro.setStorageSync('access_token', res.data.data.access_token)
Taro.setStorageSync('UserId', res.data.data.user.userId)
setIsLogin(true)
const token = res.data.data.access_token;
const userData = res.data.data.user;
// 使用useUser Hook的loginUser方法更新状态
loginUser(token, userData);
// 处理邀请关系
if (res.data.data.user?.userId) {
if (userData?.userId) {
try {
const inviteSuccess = await handleInviteRelation(res.data.data.user.userId)
const inviteSuccess = await handleInviteRelation(userData.userId)
if (inviteSuccess) {
Taro.showToast({
title: '邀请关系建立成功',
@@ -140,10 +146,16 @@ const Header = (props: any) => {
}
}
// 重新加载小程序
Taro.reLaunch({
url: '/pages/index/index'
// 显示登录成功提示
Taro.showToast({
title: '登录成功',
icon: 'success',
duration: 1500
})
// 不需要重新启动小程序状态已经通过useUser更新
// 可以选择性地刷新当前页面数据
reload();
}
})
} else {
@@ -170,13 +182,13 @@ const Header = (props: any) => {
onBackClick={() => {
}}
left={
IsLogin ? (
isLoggedIn ? (
<View style={{display: 'flex', alignItems: 'center', gap: '8px'}} onClick={() => navTo(`/user/profile/profile`,true)}>
<Avatar
size="22"
src={userInfo?.avatar}
src={user?.avatar}
/>
<Text className={'text-white'}>{userInfo?.mobile}</Text>
<Text className={'text-white'}>{user?.nickname || '已登录'}</Text>
<TriangleDown className={'text-white'} size={9}/>
</View>
) : (
@@ -187,7 +199,7 @@ const Header = (props: any) => {
size="22"
src={getWebsiteLogo()}
/>
<Text style={{color: '#ffffff'}}>{getWebsiteName()}</Text>
<Text style={{color: '#ffffff'}}></Text>
<TriangleDown size={9} className={'text-white'}/>
</Space>
</Button>

View File

@@ -14,12 +14,15 @@ import {useUserData} from "@/hooks/useUserData";
function UserCard() {
const {
isAdmin
user,
isLoggedIn,
loginUser,
fetchUserInfo,
isAdmin,
getDisplayName,
getRoleName
} = useUser();
const { data, refresh } = useUserData()
const {getDisplayName, getRoleName} = useUser();
const [IsLogin, setIsLogin] = useState<boolean>(false)
const [userInfo, setUserInfo] = useState<User>()
const [couponCount, setCouponCount] = useState(0)
const [pointsCount, setPointsCount] = useState(0)
const [giftCount, setGiftCount] = useState(0)
@@ -77,41 +80,31 @@ function UserCard() {
// })
}
const reload = () => {
Taro.getUserInfo({
success: (res) => {
const avatar = res.userInfo.avatarUrl;
setUserInfo({
avatar,
nickname: res.userInfo.nickName,
sexName: res.userInfo.gender == 1 ? '男' : '女'
})
getUserInfo().then((data) => {
if (data) {
setUserInfo(data)
setIsLogin(true);
Taro.setStorageSync('UserId', data.userId)
// 加载用户统计数据
if (data.userId) {
loadUserStats(data.userId)
}
// 获取openId
if (!data.openid) {
Taro.login({
success: (res) => {
getWxOpenId({code: res.code}).then(() => {
})
}
})
}
const reload = async () => {
// 如果已登录,获取最新用户信息
if (isLoggedIn) {
try {
const data = await fetchUserInfo();
if (data) {
// 加载用户统计数据
if (data.userId) {
loadUserStats(data.userId)
}
}).catch(() => {
console.log('未登录')
});
// 获取openId
if (!data.openid) {
Taro.login({
success: (res) => {
getWxOpenId({code: res.code}).then(() => {
})
}
})
}
}
} catch (error) {
console.error('获取用户信息失败:', error)
}
});
}
};
const showAuthModal = () => {
@@ -180,10 +173,21 @@ function UserCard() {
return false;
}
// 登录成功
Taro.setStorageSync('access_token', res.data.data.access_token)
Taro.setStorageSync('UserId', res.data.data.user.userId)
setUserInfo(res.data.data.user)
setIsLogin(true)
const token = res.data.data.access_token;
const userData = res.data.data.user;
// 使用useUser Hook的loginUser方法更新状态
loginUser(token, userData);
// 显示登录成功提示
Taro.showToast({
title: '登录成功',
icon: 'success',
duration: 1500
})
// 刷新页面数据
reload();
}
})
} else {
@@ -209,17 +213,17 @@ function UserCard() {
<View className={'user-card-header flex w-full justify-between items-center pt-4'}>
<View className={'flex items-center mx-4'}>
{
IsLogin ? (
<Avatar size="large" src={userInfo?.avatar} shape="round"/>
isLoggedIn ? (
<Avatar size="large" src={user?.avatar} shape="round"/>
) : (
<Button className={'text-black'} open-type="getPhoneNumber" onGetPhoneNumber={handleGetPhoneNumber}>
<Avatar size="large" src={userInfo?.avatar} shape="round"/>
<Avatar size="large" src={user?.avatar} shape="round"/>
</Button>
)
}
<View className={'user-info flex flex-col px-2'}>
<View className={'py-1 text-black font-bold'}>{getDisplayName()}</View>
{IsLogin ? (
{isLoggedIn ? (
<View className={'grade text-xs py-1'}>
<Tag type="success" round>
<Text className={'p-1'}>