Files
template-10584/src/pages/user/components/UserCard.tsx
赵忠林 1b24a611a8 docs: 更新优惠券相关文档- 新增优惠券API集成文档
- 新增优惠券卡片对齐修复文档
- 新增优惠券状态显示调试文档
- 新增优惠券组件警告修复文档- 更新用ShopInfo Hook字段迁移文档
- 更新Arguments关键字修复文档
2025-08-15 01:52:36 +08:00

250 lines
8.3 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 {Button} from '@nutui/nutui-react-taro'
import {Avatar, Tag} from '@nutui/nutui-react-taro'
import {getUserInfo, getWxOpenId} from '@/api/layout';
import Taro from '@tarojs/taro';
import {useEffect, useState} from "react";
import {User} from "@/api/system/user/model";
import navTo from "@/utils/common";
import {TenantId} from "@/config/app";
import {getMyAvailableCoupons} from "@/api/shop/shopUserCoupon";
import {getUserPointsStats} from "@/api/user/points";
import {useUser} from "@/hooks/useUser";
function UserCard() {
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)
useEffect(() => {
// Taro.getSetting获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限。
Taro.getSetting({
success: (res) => {
if (res.authSetting['scope.userInfo']) {
// 用户已经授权过,可以直接获取用户信息
console.log('用户已经授权过,可以直接获取用户信息')
reload();
} else {
// 用户未授权,需要弹出授权窗口
console.log('用户未授权,需要弹出授权窗口')
showAuthModal();
}
}
});
}, []);
const loadUserStats = (userId: number) => {
// 加载优惠券数量
getMyAvailableCoupons()
.then((coupons: any) => {
setCouponCount(coupons?.length || 0)
})
.catch((error: any) => {
console.error('Coupon count error:', error)
})
// 加载积分数量
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 = () => {
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('未登录')
});
}
});
};
const showAuthModal = () => {
Taro.showModal({
title: '授权提示',
content: '需要获取您的用户信息',
confirmText: '去授权',
cancelText: '取消',
success: (res) => {
if (res.confirm) {
// 用户点击确认,打开授权设置页面
openSetting();
}
}
});
};
const openSetting = () => {
// Taro.openSetting调起客户端小程序设置界面返回用户设置的操作结果。设置界面只会出现小程序已经向用户请求过的权限。
Taro.openSetting({
success: (res) => {
if (res.authSetting['scope.userInfo']) {
// 用户授权成功,可以获取用户信息
reload();
} else {
// 用户拒绝授权,提示授权失败
Taro.showToast({
title: '授权失败',
icon: 'none'
});
}
}
});
};
/* 获取用户手机号 */
const handleGetPhoneNumber = ({detail}: {detail: {code?: string, encryptedData?: string, iv?: string}}) => {
const {code, encryptedData, iv} = detail
Taro.login({
success: function () {
if (code) {
Taro.request({
url: 'https://server.websoft.top/api/wx-login/loginByMpWxPhone',
method: 'POST',
data: {
code,
encryptedData,
iv,
notVerifyPhone: true,
refereeId: 0,
sceneType: 'save_referee',
tenantId: TenantId
},
header: {
'content-type': 'application/json',
TenantId
},
success: function (res) {
if (res.data.code == 1) {
Taro.showToast({
title: res.data.message,
icon: 'error',
duration: 2000
})
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)
}
})
} else {
console.log('登录失败!')
}
}
})
}
return (
<div className={'header-bg pt-20'}>
<div className={'p-4'}>
<div
className={'user-card w-full flex flex-col justify-around rounded-xl shadow-sm'}
style={{
background: 'linear-gradient(to bottom, #ffffff, #ffffff)', // 这种情况建议使用类名来控制样式(引入外联样式)
// width: '720rpx',
// margin: '10px auto 0px auto',
height: '170px',
// borderRadius: '22px 22px 0 0',
}}
>
<div className={'user-card-header flex w-full justify-between items-center pt-4'}>
<div className={'flex items-center mx-4'}>
{
IsLogin ? (
<Avatar size="large" src={userInfo?.avatar} shape="round"/>
) : (
<Button className={'text-black'} open-type="getPhoneNumber" onGetPhoneNumber={handleGetPhoneNumber}>
<Avatar size="large" src={userInfo?.avatar} shape="round"/>
</Button>
)
}
<div className={'user-info flex flex-col px-2'}>
<div className={'py-1 text-black font-bold'}>{getDisplayName()}</div>
{IsLogin ? (
<div className={'grade text-xs py-1'}>
<Tag type="success" round>
<div className={'p-1'}>
{getRoleName()}
</div>
</Tag>
</div>
) : ''}
</div>
</div>
<div className={'mx-4 text-sm px-3 py-1 text-black border-gray-400 border-solid border-2 rounded-3xl'}
onClick={() => navTo('/user/profile/profile', true)}>
{'个人资料'}
</div>
</div>
<div className={'flex justify-around mt-1'}>
<div className={'item flex justify-center flex-col items-center'}
onClick={() => navTo('/user/wallet/wallet', true)}>
<span className={'text-sm text-gray-500'}></span>
<span className={'text-xl'}>¥ {userInfo?.balance || '0.00'}</span>
</div>
<div className={'item flex justify-center flex-col items-center'}
onClick={() => navTo('/user/coupon/index', true)}>
<span className={'text-sm text-gray-500'}></span>
<span className={'text-xl'}>{couponCount}</span>
</div>
<div className={'item flex justify-center flex-col items-center'}
onClick={() => navTo('/user/gift/index', true)}>
<span className={'text-sm text-gray-500'}></span>
<span className={'text-xl'}>{giftCount}</span>
</div>
<div className={'item flex justify-center flex-col items-center'}>
<span className={'text-sm text-gray-500'}></span>
<span className={'text-xl'}>{pointsCount}</span>
</div>
</div>
</div>
</div>
</div>
)
}
export default UserCard;