feat(pages): 添加管理页面功能和配置
- 创建 .editorconfig 文件统一代码风格配置 - 配置 .eslintrc 使用 taro/react 规则集 - 完善 .gitignore 忽略编译产物和敏感文件 - 添加 admin/article/add 页面实现文章管理功能 - 添加 dealer/apply/add 页面实现经销商申请功能 - 添加 dealer/bank/add 页面实现银行卡管理功能 - 添加 dealer/customer/add 页面实现客户管理功能 - 添加 user/address/add 页面实现用户地址管理功能 - 添加 user/chat/message/add 页面实现消息功能 - 添加 user/gift/add 页面实现礼品管理功能 - 配置各页面导航栏标题和样式 - 实现表单验证和数据提交功能 - 集成图片上传和头像选择功能 - 添加日期选择和数据校验逻辑 - 实现编辑和新增模式切换 - 集成用户权限和角色管理功能
This commit is contained in:
4
src/user/points/points.config.ts
Normal file
4
src/user/points/points.config.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export default definePageConfig({
|
||||
navigationBarTitleText: '我的积分',
|
||||
navigationBarTextStyle: 'black'
|
||||
})
|
||||
213
src/user/points/points.tsx
Normal file
213
src/user/points/points.tsx
Normal file
@@ -0,0 +1,213 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user