Files
glt-taro/src/user/points/points.tsx

214 lines
6.8 KiB
TypeScript

import {useState, useEffect, CSSProperties} from 'react'
import Taro from '@tarojs/taro'
import {Cell, InfiniteLoading, Card, Empty, ConfigProvider} from '@nutui/nutui-react-taro'
import {pageUserPointsLog, getUserPointsStats} from "@/api/user/points";
import {UserPointsLog as UserPointsLogType, UserPointsStats} from "@/api/user/points/model";
import {View} from '@tarojs/components'
const InfiniteUlStyle: CSSProperties = {
height: '100vh',
width: '100%',
padding: '0',
overflowY: 'auto',
overflowX: 'hidden',
}
const UserPoints = () => {
const [list, setList] = useState<UserPointsLogType[]>([])
const [page, setPage] = useState(1)
const [hasMore, setHasMore] = useState(true)
const [stats, setStats] = useState<UserPointsStats>({})
useEffect(() => {
reload()
loadPointsStats()
}, [])
const loadMore = async () => {
setPage(page + 1)
reload();
}
const reload = () => {
const userId = Taro.getStorageSync('UserId')
if (!userId) {
Taro.showToast({
title: '请先登录',
icon: 'error'
});
return
}
pageUserPointsLog({
userId: parseInt(userId),
page
}).then(res => {
console.log(res)
const newList = res?.list || [];
setList([...list, ...newList])
setHasMore(newList.length > 0)
}).catch(error => {
console.error('Points log error:', error)
Taro.showToast({
title: error?.message || '获取失败',
icon: 'error'
});
})
}
const loadPointsStats = () => {
const userId = Taro.getStorageSync('UserId')
if (!userId) return
getUserPointsStats(parseInt(userId))
.then((res: any) => {
setStats(res)
})
.catch((error: any) => {
console.error('Points stats error:', error)
})
}
const getPointsTypeText = (type?: number) => {
switch (type) {
case 1: return '获得积分'
case 2: return '消费积分'
case 3: return '积分过期'
case 4: return '管理员调整'
default: return '积分变动'
}
}
const getPointsTypeColor = (type?: number) => {
switch (type) {
case 1: return 'text-green-500'
case 2: return 'text-red-500'
case 3: return 'text-gray-500'
case 4: return 'text-blue-500'
default: return 'text-gray-500'
}
}
return (
<ConfigProvider>
<View className="bg-gray-50 h-screen">
{/* 积分统计卡片 */}
<View className="p-4">
<Card className="points-stats-card">
<View className="text-center py-4">
<View className="text-3xl font-bold text-orange-500 mb-2">
{stats.currentPoints || 0}
</View>
<View className="text-sm text-gray-500 mb-4"></View>
<View className="flex justify-around text-center">
<View>
<View className="text-lg font-medium text-gray-800">
{stats.totalEarned || 0}
</View>
<View className="text-xs text-gray-500"></View>
</View>
<View>
<View className="text-lg font-medium text-gray-800">
{stats.totalUsed || 0}
</View>
<View className="text-xs text-gray-500"></View>
</View>
<View>
<View className="text-lg font-medium text-gray-800">
{stats.expiringSoon || 0}
</View>
<View className="text-xs text-gray-500"></View>
</View>
</View>
</View>
</Card>
</View>
{/* 积分记录 */}
<View className="px-4 flex-1">
<ul style={{...InfiniteUlStyle, height: 'calc(100vh - 200px)'}} id="scroll">
<InfiniteLoading
target="scroll"
hasMore={hasMore}
onLoadMore={loadMore}
onScroll={() => {
console.log('onScroll')
}}
onScrollToUpper={() => {
console.log('onScrollToUpper')
}}
loadingText={
<>
</>
}
loadMoreText={
<>
</>
}
>
<View className="p-4">
{list.length === 0 ? (
<div className={'h-full flex flex-col justify-center items-center'} style={{
height: 'calc(100vh - 500px)',
}}>
<Empty
style={{
backgroundColor: 'transparent'
}}
description="您还没有积分记录"
/>
</div>
) : (
list.map((item, index) => (
<Cell.Group key={`${item.logId}-${index}`} className="mb-3">
<Cell className="flex flex-col gap-2 p-4">
<View className="flex justify-between items-start">
<View className="flex-1">
<View className="font-medium text-base text-gray-800 mb-1">
{getPointsTypeText(item.type)}
</View>
<View className="text-sm text-gray-500">
{item.reason || '无备注'}
</View>
</View>
<View className={`text-lg font-bold ${getPointsTypeColor(item.type)}`}>
{item.type === 1 ? '+' : item.type === 2 ? '-' : ''}
{item.points || 0}
</View>
</View>
<View className="flex justify-between items-center text-xs text-gray-400 mt-2">
<View>
{item.createTime ? new Date(item.createTime).toLocaleString() : ''}
</View>
{item.orderId && (
<View>
: {item.orderId}
</View>
)}
</View>
{item.comments && (
<View className="text-xs text-gray-500 mt-1 p-2 bg-gray-50 rounded">
: {item.comments}
</View>
)}
</Cell>
</Cell.Group>
))
)}
</View>
</InfiniteLoading>
</ul>
</View>
</View>
</ConfigProvider>
);
};
export default UserPoints;