feat(user): 添加用户卡片统计数据接口和优化性能

- 新增 UserCardStats 接口定义余额/积分/优惠券/礼品卡数据结构
- 实现 getUserCardStats 函数聚合返回用户卡片统计数据
- 替换原有多个独立请求为单一聚合接口提升性能
- 修改 useUserData Hook 使用新聚合接口并调整数据类型
- 移除废弃的 pageShopOrder 和相关 API 导入
- 优化用户登录后自动刷新卡片统计数据逻辑
This commit is contained in:
2026-01-20 12:47:22 +08:00
parent 0542b93dc7
commit 415e05cc4e
5 changed files with 45 additions and 35 deletions

View File

@@ -43,6 +43,15 @@ export interface UserOrderStats {
total: number total: number
} }
// 用户卡片统计(个人中心头部:余额/积分/优惠券/礼品卡)
export interface UserCardStats {
balance: string
points: number
coupons: number
giftCards: number
lastUpdateTime?: string
}
// 用户完整数据 // 用户完整数据
export interface UserDashboard { export interface UserDashboard {
balance: UserBalance balance: UserBalance
@@ -108,6 +117,17 @@ export async function getUserOrderStats() {
return Promise.reject(new Error(res.message)) return Promise.reject(new Error(res.message))
} }
/**
* 获取用户卡片统计(一次性返回余额/积分/可用优惠券/未使用礼品卡数量)
*/
export async function getUserCardStats() {
const res = await request.get<ApiResult<UserCardStats>>('/user/card/stats')
if (res.code === 0 && res.data) {
return res.data
}
return Promise.reject(new Error(res.message))
}
/** /**
* 获取用户完整仪表板数据(一次性获取所有数据) * 获取用户完整仪表板数据(一次性获取所有数据)
*/ */

View File

@@ -1,7 +1,6 @@
import { useState, useEffect, useCallback } from 'react'; import { useState, useEffect, useCallback } from 'react';
import { UserOrderStats } from '@/api/user'; import { getUserOrderStats, UserOrderStats } from '@/api/user';
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
import {pageShopOrder} from "@/api/shop/shopOrder";
/** /**
* 订单统计Hook * 订单统计Hook
@@ -31,20 +30,17 @@ export const useOrderStats = () => {
if(!Taro.getStorageSync('UserId')){ if(!Taro.getStorageSync('UserId')){
return false; return false;
} }
// TODO 读取订单数量
const pending = await pageShopOrder({ page: 1, limit: 1, userId: Taro.getStorageSync('UserId'), statusFilter: 0}) // 聚合接口:一次请求返回各状态数量(后台按用户做了缓存)
const paid = await pageShopOrder({ page: 1, limit: 1, userId: Taro.getStorageSync('UserId'), statusFilter: 1}) const stats = await getUserOrderStats();
const shipped = await pageShopOrder({ page: 1, limit: 1, userId: Taro.getStorageSync('UserId'), statusFilter: 3})
const completed = await pageShopOrder({ page: 1, limit: 1, userId: Taro.getStorageSync('UserId'), statusFilter: 5})
const refund = await pageShopOrder({ page: 1, limit: 1, userId: Taro.getStorageSync('UserId'), statusFilter: 6})
const total = await pageShopOrder({ page: 1, limit: 1, userId: Taro.getStorageSync('UserId')})
setOrderStats({ setOrderStats({
pending: pending?.count || 0, pending: stats?.pending || 0,
paid: paid?.count || 0, paid: stats?.paid || 0,
shipped: shipped?.count || 0, shipped: stats?.shipped || 0,
completed: completed?.count || 0, completed: stats?.completed || 0,
refund: refund?.count || 0, refund: stats?.refund || 0,
total: total?.count || 0 total: stats?.total || 0
}) })
if (showToast) { if (showToast) {

View File

@@ -1,12 +1,10 @@
import { useState, useEffect, useCallback } from 'react' import { useState, useEffect, useCallback } from 'react'
import {pageShopUserCoupon} from "@/api/shop/shopUserCoupon";
import {pageShopGift} from "@/api/shop/shopGift";
import {useUser} from "@/hooks/useUser"; import {useUser} from "@/hooks/useUser";
import Taro from '@tarojs/taro' import Taro from '@tarojs/taro'
import {getUserInfo} from "@/api/layout"; import { getUserCardStats } from '@/api/user'
interface UserData { interface UserData {
balance: number balance: string
points: number points: number
coupons: number coupons: number
giftCards: number giftCards: number
@@ -24,7 +22,7 @@ interface UseUserDataReturn {
loading: boolean loading: boolean
error: string | null error: string | null
refresh: () => Promise<void> refresh: () => Promise<void>
updateBalance: (newBalance: number) => void updateBalance: (newBalance: string) => void
updatePoints: (newPoints: number) => void updatePoints: (newPoints: number) => void
} }
@@ -43,18 +41,14 @@ export const useUserData = (): UseUserDataReturn => {
return; return;
} }
// 并发请求所有数据 // 聚合接口:一次请求返回余额/积分/优惠券/礼品卡统计(后端可按用户做缓存)
const [userDataRes, couponsRes, giftCardsRes] = await Promise.all([ const stats = await getUserCardStats()
getUserInfo(),
pageShopUserCoupon({ page: 1, limit: 1, userId: Taro.getStorageSync('UserId'), status: 0}),
pageShopGift({ page: 1, limit: 1, userId: Taro.getStorageSync('UserId'), status: 0})
])
const newData: UserData = { const newData: UserData = {
balance: userDataRes?.balance || 0.00, balance: stats?.balance || '0.00',
points: userDataRes?.points || 0, points: stats?.points || 0,
coupons: couponsRes?.count || 0, coupons: stats?.coupons || 0,
giftCards: giftCardsRes?.count || 0, giftCards: stats?.giftCards || 0,
orders: { orders: {
pending: 0, pending: 0,
paid: 0, paid: 0,
@@ -78,7 +72,7 @@ export const useUserData = (): UseUserDataReturn => {
}, [fetchUserData]) }, [fetchUserData])
// 更新余额(本地更新,避免频繁请求) // 更新余额(本地更新,避免频繁请求)
const updateBalance = useCallback((newBalance: number) => { const updateBalance = useCallback((newBalance: string) => {
setData(prev => prev ? { ...prev, balance: newBalance } : null) setData(prev => prev ? { ...prev, balance: newBalance } : null)
}, []) }, [])

View File

@@ -65,6 +65,8 @@ const UserCard = forwardRef<any, any>((_, ref) => {
setUserInfo(data) setUserInfo(data)
setIsLogin(true); setIsLogin(true);
Taro.setStorageSync('UserId', data.userId) Taro.setStorageSync('UserId', data.userId)
// 登录态已就绪后刷新卡片统计(余额/积分/券/礼品卡)
refresh().then()
// 获取openId // 获取openId
if (!data.openid) { if (!data.openid) {
@@ -162,6 +164,8 @@ const UserCard = forwardRef<any, any>((_, ref) => {
Taro.setStorageSync('UserId', res.data.data.user.userId) Taro.setStorageSync('UserId', res.data.data.user.userId)
setUserInfo(res.data.data.user) setUserInfo(res.data.data.user)
setIsLogin(true) setIsLogin(true)
// 登录态已就绪后刷新卡片统计(余额/积分/券/礼品卡)
refresh().then()
} }
}) })
} else { } else {

View File

@@ -3,7 +3,6 @@ import {PullToRefresh} from '@nutui/nutui-react-taro'
import UserCard from "./components/UserCard"; import UserCard from "./components/UserCard";
import UserOrder from "./components/UserOrder"; import UserOrder from "./components/UserOrder";
import UserFooter from "./components/UserFooter"; import UserFooter from "./components/UserFooter";
import {useUserData} from "@/hooks/useUserData";
import {View} from '@tarojs/components'; import {View} from '@tarojs/components';
import './user.scss' import './user.scss'
import IsDealer from "./components/IsDealer"; import IsDealer from "./components/IsDealer";
@@ -12,14 +11,11 @@ import UserGrid from "@/pages/user/components/UserGrid";
function User() { function User() {
const {refresh} = useUserData()
const userCardRef = useRef<any>() const userCardRef = useRef<any>()
const themeStyles = useThemeStyles(); const themeStyles = useThemeStyles();
// 下拉刷新处理 // 下拉刷新处理
const handleRefresh = async () => { const handleRefresh = async () => {
await refresh()
// 如果 UserCard 组件有自己的刷新方法,也可以调用
if (userCardRef.current?.handleRefresh) { if (userCardRef.current?.handleRefresh) {
await userCardRef.current.handleRefresh() await userCardRef.current.handleRefresh()
} }