refactor(user): 重构用户卡片组件并优化登录状态更新逻辑- 重构了 UserCard 组件,统一了前端和后台的实现
- 移除了冗余的数据获取逻辑,统一使用 useUserData Hook - 优化了登录状态更新流程,使用 loginUser 方法统一处理登录 - 添加了登录成功后的提示和页面数据刷新
This commit is contained in:
@@ -8,6 +8,14 @@
|
|||||||
|
|
||||||
1. **Header组件** (`src/pages/index/Header.tsx`)
|
1. **Header组件** (`src/pages/index/Header.tsx`)
|
||||||
2. **UserCard组件** (`src/pages/user/components/UserCard.tsx`)
|
2. **UserCard组件** (`src/pages/user/components/UserCard.tsx`)
|
||||||
|
3. **Admin UserCard组件** (`src/admin/components/UserCard.tsx`)
|
||||||
|
|
||||||
|
## 额外优化:清理冗余代码
|
||||||
|
发现 UserCard 组件中存在冗余的数据获取逻辑:
|
||||||
|
- `useUserData` Hook 已经动态获取了优惠券、礼品卡、积分、余额等数据
|
||||||
|
- 删除了重复的本地状态:`couponCount`, `pointsCount`, `giftCount`
|
||||||
|
- 删除了重复的数据获取方法:`loadUserStats`
|
||||||
|
- 统一使用 `useUserData` 提供的数据
|
||||||
|
|
||||||
### 主要修改内容
|
### 主要修改内容
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,23 @@
|
|||||||
import {Button} from '@nutui/nutui-react-taro'
|
import {Button} from '@nutui/nutui-react-taro'
|
||||||
import {Avatar, Tag} from '@nutui/nutui-react-taro'
|
import {Avatar, Tag} from '@nutui/nutui-react-taro'
|
||||||
import {getUserInfo, getWxOpenId} from '@/api/layout';
|
import {getWxOpenId} from '@/api/layout';
|
||||||
import Taro from '@tarojs/taro';
|
import Taro from '@tarojs/taro';
|
||||||
import {useEffect, useState} from "react";
|
import {useEffect} from "react";
|
||||||
import {User} from "@/api/system/user/model";
|
|
||||||
import navTo from "@/utils/common";
|
import navTo from "@/utils/common";
|
||||||
import {TenantId} from "@/config/app";
|
import {TenantId} from "@/config/app";
|
||||||
import {getMyAvailableCoupons} from "@/api/shop/shopUserCoupon";
|
|
||||||
import {useUser} from "@/hooks/useUser";
|
import {useUser} from "@/hooks/useUser";
|
||||||
|
import {useUserData} from "@/hooks/useUserData";
|
||||||
|
|
||||||
function UserCard() {
|
function UserCard() {
|
||||||
const {getDisplayName, getRoleName} = useUser();
|
const {
|
||||||
const [IsLogin, setIsLogin] = useState<boolean>(false)
|
user,
|
||||||
const [userInfo, setUserInfo] = useState<User>()
|
isLoggedIn,
|
||||||
const [couponCount, setCouponCount] = useState(0)
|
loginUser,
|
||||||
// const [pointsCount, setPointsCount] = useState(0)
|
fetchUserInfo,
|
||||||
const [giftCount, setGiftCount] = useState(0)
|
getDisplayName,
|
||||||
|
getRoleName
|
||||||
|
} = useUser();
|
||||||
|
const {data} = useUserData()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Taro.getSetting:获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限。
|
// Taro.getSetting:获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限。
|
||||||
@@ -34,67 +36,27 @@ function UserCard() {
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const loadUserStats = (userId: number) => {
|
|
||||||
// 加载优惠券数量
|
|
||||||
getMyAvailableCoupons()
|
|
||||||
.then((coupons: any) => {
|
|
||||||
setCouponCount(coupons?.length || 0)
|
|
||||||
})
|
|
||||||
.catch((error: any) => {
|
|
||||||
console.error('Coupon count error:', error)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 加载积分数量
|
const reload = async () => {
|
||||||
console.log(userId)
|
// 如果已登录,获取最新用户信息
|
||||||
// getUserPointsStats(userId)
|
if (isLoggedIn) {
|
||||||
// .then((res: any) => {
|
try {
|
||||||
// setPointsCount(res.currentPoints || 0)
|
const data = await fetchUserInfo();
|
||||||
// })
|
if (data) {
|
||||||
// .catch((error: any) => {
|
// 获取openId
|
||||||
// console.error('Points stats error:', error)
|
if (!data.openid) {
|
||||||
// })
|
Taro.login({
|
||||||
// 加载礼品劵数量
|
success: (res) => {
|
||||||
setGiftCount(0)
|
getWxOpenId({code: res.code}).then(() => {
|
||||||
// pageUserGiftLog({userId, page: 1, limit: 1}).then(res => {
|
})
|
||||||
// setGiftCount(res.count || 0)
|
}
|
||||||
// })
|
})
|
||||||
}
|
|
||||||
|
|
||||||
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(() => {
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}).catch(() => {
|
}
|
||||||
console.log('未登录')
|
} catch (error) {
|
||||||
});
|
console.error('获取用户信息失败:', error)
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const showAuthModal = () => {
|
const showAuthModal = () => {
|
||||||
@@ -132,7 +94,7 @@ function UserCard() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* 获取用户手机号 */
|
/* 获取用户手机号 */
|
||||||
const handleGetPhoneNumber = ({detail}: {detail: {code?: string, encryptedData?: string, iv?: string}}) => {
|
const handleGetPhoneNumber = ({detail}: { detail: { code?: string, encryptedData?: string, iv?: string } }) => {
|
||||||
const {code, encryptedData, iv} = detail
|
const {code, encryptedData, iv} = detail
|
||||||
Taro.login({
|
Taro.login({
|
||||||
success: function () {
|
success: function () {
|
||||||
@@ -163,10 +125,21 @@ function UserCard() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// 登录成功
|
// 登录成功
|
||||||
Taro.setStorageSync('access_token', res.data.data.access_token)
|
const token = res.data.data.access_token;
|
||||||
Taro.setStorageSync('UserId', res.data.data.user.userId)
|
const userData = res.data.data.user;
|
||||||
setUserInfo(res.data.data.user)
|
|
||||||
setIsLogin(true)
|
// 使用useUser Hook的loginUser方法更新状态
|
||||||
|
loginUser(token, userData);
|
||||||
|
|
||||||
|
// 显示登录成功提示
|
||||||
|
Taro.showToast({
|
||||||
|
title: '登录成功',
|
||||||
|
icon: 'success',
|
||||||
|
duration: 1500
|
||||||
|
})
|
||||||
|
|
||||||
|
// 刷新页面数据
|
||||||
|
reload();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@@ -192,17 +165,17 @@ function UserCard() {
|
|||||||
<div className={'user-card-header flex w-full justify-between items-center pt-4'}>
|
<div className={'user-card-header flex w-full justify-between items-center pt-4'}>
|
||||||
<div className={'flex items-center mx-4'}>
|
<div className={'flex items-center mx-4'}>
|
||||||
{
|
{
|
||||||
IsLogin ? (
|
isLoggedIn ? (
|
||||||
<Avatar size="large" src={userInfo?.avatar} shape="round"/>
|
<Avatar size="large" src={user?.avatar} shape="round"/>
|
||||||
) : (
|
) : (
|
||||||
<Button className={'text-black'} open-type="getPhoneNumber" onGetPhoneNumber={handleGetPhoneNumber}>
|
<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>
|
</Button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
<div className={'user-info flex flex-col px-2'}>
|
<div className={'user-info flex flex-col px-2'}>
|
||||||
<div className={'py-1 text-black font-bold'}>{getDisplayName()}</div>
|
<div className={'py-1 text-black font-bold'}>{getDisplayName()}</div>
|
||||||
{IsLogin ? (
|
{isLoggedIn ? (
|
||||||
<div className={'grade text-xs py-1'}>
|
<div className={'grade text-xs py-1'}>
|
||||||
<Tag type="success" round>
|
<Tag type="success" round>
|
||||||
<div className={'p-1'}>
|
<div className={'p-1'}>
|
||||||
@@ -222,17 +195,17 @@ function UserCard() {
|
|||||||
<div className={'item flex justify-center flex-col items-center'}
|
<div className={'item flex justify-center flex-col items-center'}
|
||||||
onClick={() => navTo('/user/wallet/wallet', true)}>
|
onClick={() => navTo('/user/wallet/wallet', true)}>
|
||||||
<span className={'text-sm text-gray-500'}>余额</span>
|
<span className={'text-sm text-gray-500'}>余额</span>
|
||||||
<span className={'text-xl'}>¥ {userInfo?.balance || '0.00'}</span>
|
<span className={'text-xl'}>¥ {data?.balance || '0.00'}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={'item flex justify-center flex-col items-center'}
|
<div className={'item flex justify-center flex-col items-center'}
|
||||||
onClick={() => navTo('/user/coupon/index', true)}>
|
onClick={() => navTo('/user/coupon/index', true)}>
|
||||||
<span className={'text-sm text-gray-500'}>优惠券</span>
|
<span className={'text-sm text-gray-500'}>优惠券</span>
|
||||||
<span className={'text-xl'}>{couponCount}</span>
|
<span className={'text-xl'}>{data?.coupons || 0}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={'item flex justify-center flex-col items-center'}
|
<div className={'item flex justify-center flex-col items-center'}
|
||||||
onClick={() => navTo('/user/gift/index', true)}>
|
onClick={() => navTo('/user/gift/index', true)}>
|
||||||
<span className={'text-sm text-gray-500'}>礼品卡</span>
|
<span className={'text-sm text-gray-500'}>礼品卡</span>
|
||||||
<span className={'text-xl'}>{giftCount}</span>
|
<span className={'text-xl'}>{data?.giftCards || 0}</span>
|
||||||
</div>
|
</div>
|
||||||
{/*<div className={'item flex justify-center flex-col items-center'}>*/}
|
{/*<div className={'item flex justify-center flex-col items-center'}>*/}
|
||||||
{/* <span className={'text-sm text-gray-500'}>积分</span>*/}
|
{/* <span className={'text-sm text-gray-500'}>积分</span>*/}
|
||||||
|
|||||||
@@ -2,13 +2,11 @@ import {Button} from '@nutui/nutui-react-taro'
|
|||||||
import {Avatar, Tag} from '@nutui/nutui-react-taro'
|
import {Avatar, Tag} from '@nutui/nutui-react-taro'
|
||||||
import {View, Text} from '@tarojs/components'
|
import {View, Text} from '@tarojs/components'
|
||||||
import {Scan} from '@nutui/icons-react-taro';
|
import {Scan} from '@nutui/icons-react-taro';
|
||||||
import {getUserInfo, getWxOpenId} from '@/api/layout';
|
import {getWxOpenId} from '@/api/layout';
|
||||||
import Taro from '@tarojs/taro';
|
import Taro from '@tarojs/taro';
|
||||||
import {useEffect, useState} from "react";
|
import {useEffect} from "react";
|
||||||
import {User} from "@/api/system/user/model";
|
|
||||||
import navTo from "@/utils/common";
|
import navTo from "@/utils/common";
|
||||||
import {TenantId} from "@/config/app";
|
import {TenantId} from "@/config/app";
|
||||||
import {getMyAvailableCoupons} from "@/api/shop/shopUserCoupon";
|
|
||||||
import {useUser} from "@/hooks/useUser";
|
import {useUser} from "@/hooks/useUser";
|
||||||
import {useUserData} from "@/hooks/useUserData";
|
import {useUserData} from "@/hooks/useUserData";
|
||||||
|
|
||||||
@@ -22,19 +20,7 @@ function UserCard() {
|
|||||||
getDisplayName,
|
getDisplayName,
|
||||||
getRoleName
|
getRoleName
|
||||||
} = useUser();
|
} = useUser();
|
||||||
const { data, refresh } = useUserData()
|
const {data} = useUserData()
|
||||||
const [couponCount, setCouponCount] = useState(0)
|
|
||||||
const [pointsCount, setPointsCount] = useState(0)
|
|
||||||
const [giftCount, setGiftCount] = useState(0)
|
|
||||||
|
|
||||||
// 下拉刷新
|
|
||||||
const handleRefresh = async () => {
|
|
||||||
await refresh()
|
|
||||||
Taro.showToast({
|
|
||||||
title: '刷新成功',
|
|
||||||
icon: 'success'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Taro.getSetting:获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限。
|
// Taro.getSetting:获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限。
|
||||||
@@ -53,32 +39,6 @@ function UserCard() {
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const loadUserStats = (userId: number) => {
|
|
||||||
// 加载优惠券数量
|
|
||||||
getMyAvailableCoupons()
|
|
||||||
.then((coupons: any) => {
|
|
||||||
setCouponCount(coupons?.length || 0)
|
|
||||||
})
|
|
||||||
.catch((error: any) => {
|
|
||||||
console.error('Coupon count error:', error)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 加载积分数量
|
|
||||||
console.log(userId)
|
|
||||||
setPointsCount(0)
|
|
||||||
// getUserPointsStats(userId)
|
|
||||||
// .then((res: any) => {
|
|
||||||
// setPointsCount(res.currentPoints || 0)
|
|
||||||
// })
|
|
||||||
// .catch((error: any) => {
|
|
||||||
// console.error('Points stats error:', error)
|
|
||||||
// })
|
|
||||||
// 加载礼品劵数量
|
|
||||||
setGiftCount(0)
|
|
||||||
// pageUserGiftLog({userId, page: 1, limit: 1}).then(res => {
|
|
||||||
// setGiftCount(res.count || 0)
|
|
||||||
// })
|
|
||||||
}
|
|
||||||
|
|
||||||
const reload = async () => {
|
const reload = async () => {
|
||||||
// 如果已登录,获取最新用户信息
|
// 如果已登录,获取最新用户信息
|
||||||
@@ -86,11 +46,6 @@ function UserCard() {
|
|||||||
try {
|
try {
|
||||||
const data = await fetchUserInfo();
|
const data = await fetchUserInfo();
|
||||||
if (data) {
|
if (data) {
|
||||||
// 加载用户统计数据
|
|
||||||
if (data.userId) {
|
|
||||||
loadUserStats(data.userId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取openId
|
// 获取openId
|
||||||
if (!data.openid) {
|
if (!data.openid) {
|
||||||
Taro.login({
|
Taro.login({
|
||||||
@@ -142,7 +97,7 @@ function UserCard() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* 获取用户手机号 */
|
/* 获取用户手机号 */
|
||||||
const handleGetPhoneNumber = ({detail}: {detail: {code?: string, encryptedData?: string, iv?: string}}) => {
|
const handleGetPhoneNumber = ({detail}: { detail: { code?: string, encryptedData?: string, iv?: string } }) => {
|
||||||
const {code, encryptedData, iv} = detail
|
const {code, encryptedData, iv} = detail
|
||||||
Taro.login({
|
Taro.login({
|
||||||
success: function () {
|
success: function () {
|
||||||
@@ -234,15 +189,15 @@ function UserCard() {
|
|||||||
) : ''}
|
) : ''}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
{isAdmin() && <Scan onClick={() => navTo('/user/store/verification', true)} />}
|
{isAdmin() && <Scan onClick={() => navTo('/user/store/verification', true)}/>}
|
||||||
<View className={'mr-4 text-sm px-3 py-1 text-black border-gray-400 border-solid border-2 rounded-3xl'}
|
<View className={'mr-4 text-sm px-3 py-1 text-black border-gray-400 border-solid border-2 rounded-3xl'}
|
||||||
onClick={() => navTo('/user/profile/profile', true)}>
|
onClick={() => navTo('/user/profile/profile', true)}>
|
||||||
{'个人资料'}
|
{'个人资料'}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View className={'flex justify-around mt-1'}>
|
<View className={'flex justify-around mt-1'}>
|
||||||
<View className={'item flex justify-center flex-col items-center'}
|
<View className={'item flex justify-center flex-col items-center'}
|
||||||
onClick={() => navTo('/user/wallet/wallet', true)}>
|
onClick={() => navTo('/user/wallet/wallet', true)}>
|
||||||
<Text className={'text-sm text-gray-500'}>余额</Text>
|
<Text className={'text-sm text-gray-500'}>余额</Text>
|
||||||
<Text className={'text-xl'}>{data?.balance || '0.00'}</Text>
|
<Text className={'text-xl'}>{data?.balance || '0.00'}</Text>
|
||||||
</View>
|
</View>
|
||||||
@@ -251,12 +206,12 @@ function UserCard() {
|
|||||||
<Text className={'text-xl'}>{data?.points || 0}</Text>
|
<Text className={'text-xl'}>{data?.points || 0}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View className={'item flex justify-center flex-col items-center'}
|
<View className={'item flex justify-center flex-col items-center'}
|
||||||
onClick={() => navTo('/user/coupon/index', true)}>
|
onClick={() => navTo('/user/coupon/index', true)}>
|
||||||
<Text className={'text-sm text-gray-500'}>优惠券</Text>
|
<Text className={'text-sm text-gray-500'}>优惠券</Text>
|
||||||
<Text className={'text-xl'}>{data?.coupons || 0}</Text>
|
<Text className={'text-xl'}>{data?.coupons || 0}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View className={'item flex justify-center flex-col items-center'}
|
<View className={'item flex justify-center flex-col items-center'}
|
||||||
onClick={() => navTo('/user/gift/index', true)}>
|
onClick={() => navTo('/user/gift/index', true)}>
|
||||||
<Text className={'text-sm text-gray-500'}>礼品卡</Text>
|
<Text className={'text-sm text-gray-500'}>礼品卡</Text>
|
||||||
<Text className={'text-xl'}>{data?.giftCards || 0}</Text>
|
<Text className={'text-xl'}>{data?.giftCards || 0}</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
Reference in New Issue
Block a user