- 新增邀请统计页面,包含统计概览、邀请记录和排行榜三个标签页 - 实现邀请统计数据的获取和展示,包括总邀请数、成功注册数、转化率等 - 添加邀请记录的查询和展示功能 - 实现邀请排行榜的查询和展示功能 - 新增生成小程序码和处理邀请场景值的接口
393 lines
13 KiB
TypeScript
393 lines
13 KiB
TypeScript
import React, { useState, useEffect, useCallback } from 'react'
|
||
import { View, Text } from '@tarojs/components'
|
||
import { Empty, Tabs, Tag, PullToRefresh, Loading } from '@nutui/nutui-react-taro'
|
||
import Taro from '@tarojs/taro'
|
||
import { pageShopDealerOrder } from '@/api/shop/shopDealerOrder'
|
||
import { useDealerUser } from '@/hooks/useDealerUser'
|
||
import type { ShopDealerOrder } from '@/api/shop/shopDealerOrder/model'
|
||
|
||
interface OrderWithDetails extends ShopDealerOrder {
|
||
orderNo?: string
|
||
customerName?: string
|
||
totalCommission?: string
|
||
// 当前用户在此订单中的层级和佣金
|
||
userLevel?: 1 | 2 | 3
|
||
userCommission?: string
|
||
}
|
||
|
||
const DealerOrders: React.FC = () => {
|
||
const [activeTab, setActiveTab] = useState<string>('0')
|
||
const [loading, setLoading] = useState<boolean>(false)
|
||
const [orders, setOrders] = useState<OrderWithDetails[]>([])
|
||
const [statistics, setStatistics] = useState({
|
||
totalOrders: 0,
|
||
totalCommission: '0.00',
|
||
pendingCommission: '0.00',
|
||
// 分层统计
|
||
level1: { orders: 0, commission: '0.00' },
|
||
level2: { orders: 0, commission: '0.00' },
|
||
level3: { orders: 0, commission: '0.00' }
|
||
})
|
||
|
||
const { dealerUser } = useDealerUser()
|
||
|
||
// 获取订单数据 - 查询当前用户作为各层级分销商的所有订单
|
||
const fetchOrders = useCallback(async () => {
|
||
if (!dealerUser?.userId) return
|
||
|
||
try {
|
||
setLoading(true)
|
||
|
||
// 并行查询三个层级的订单
|
||
const [level1Result, level2Result, level3Result] = await Promise.all([
|
||
// 一级分销商订单
|
||
pageShopDealerOrder({
|
||
page: 1,
|
||
limit: 100,
|
||
firstUserId: dealerUser.userId
|
||
}),
|
||
// 二级分销商订单
|
||
pageShopDealerOrder({
|
||
page: 1,
|
||
limit: 100,
|
||
secondUserId: dealerUser.userId
|
||
}),
|
||
// 三级分销商订单
|
||
pageShopDealerOrder({
|
||
page: 1,
|
||
limit: 100,
|
||
thirdUserId: dealerUser.userId
|
||
})
|
||
])
|
||
|
||
const allOrders: OrderWithDetails[] = []
|
||
const stats = {
|
||
totalOrders: 0,
|
||
totalCommission: '0.00',
|
||
pendingCommission: '0.00',
|
||
level1: { orders: 0, commission: '0.00' },
|
||
level2: { orders: 0, commission: '0.00' },
|
||
level3: { orders: 0, commission: '0.00' }
|
||
}
|
||
|
||
// 处理一级分销订单
|
||
if (level1Result?.list) {
|
||
const level1Orders = level1Result.list.map(order => ({
|
||
...order,
|
||
orderNo: `DD${order.orderId}`,
|
||
customerName: `用户${order.userId}`,
|
||
userLevel: 1 as const,
|
||
userCommission: order.firstMoney || '0.00',
|
||
totalCommission: (
|
||
parseFloat(order.firstMoney || '0') +
|
||
parseFloat(order.secondMoney || '0') +
|
||
parseFloat(order.thirdMoney || '0')
|
||
).toFixed(2)
|
||
}))
|
||
|
||
allOrders.push(...level1Orders)
|
||
stats.level1.orders = level1Orders.length
|
||
stats.level1.commission = level1Orders.reduce((sum, order) =>
|
||
sum + parseFloat(order.userCommission || '0'), 0
|
||
).toFixed(2)
|
||
}
|
||
|
||
// 处理二级分销订单
|
||
if (level2Result?.list) {
|
||
const level2Orders = level2Result.list.map(order => ({
|
||
...order,
|
||
orderNo: `DD${order.orderId}`,
|
||
customerName: `用户${order.userId}`,
|
||
userLevel: 2 as const,
|
||
userCommission: order.secondMoney || '0.00',
|
||
totalCommission: (
|
||
parseFloat(order.firstMoney || '0') +
|
||
parseFloat(order.secondMoney || '0') +
|
||
parseFloat(order.thirdMoney || '0')
|
||
).toFixed(2)
|
||
}))
|
||
|
||
allOrders.push(...level2Orders)
|
||
stats.level2.orders = level2Orders.length
|
||
stats.level2.commission = level2Orders.reduce((sum, order) =>
|
||
sum + parseFloat(order.userCommission || '0'), 0
|
||
).toFixed(2)
|
||
}
|
||
|
||
// 处理三级分销订单
|
||
if (level3Result?.list) {
|
||
const level3Orders = level3Result.list.map(order => ({
|
||
...order,
|
||
orderNo: `DD${order.orderId}`,
|
||
customerName: `用户${order.userId}`,
|
||
userLevel: 3 as const,
|
||
userCommission: order.thirdMoney || '0.00',
|
||
totalCommission: (
|
||
parseFloat(order.firstMoney || '0') +
|
||
parseFloat(order.secondMoney || '0') +
|
||
parseFloat(order.thirdMoney || '0')
|
||
).toFixed(2)
|
||
}))
|
||
|
||
allOrders.push(...level3Orders)
|
||
stats.level3.orders = level3Orders.length
|
||
stats.level3.commission = level3Orders.reduce((sum, order) =>
|
||
sum + parseFloat(order.userCommission || '0'), 0
|
||
).toFixed(2)
|
||
}
|
||
|
||
// 去重(同一个订单可能在多个层级中出现)
|
||
const uniqueOrders = allOrders.filter((order, index, self) =>
|
||
index === self.findIndex(o => o.orderId === order.orderId)
|
||
)
|
||
|
||
// 计算总统计
|
||
stats.totalOrders = uniqueOrders.length
|
||
stats.totalCommission = (
|
||
parseFloat(stats.level1.commission) +
|
||
parseFloat(stats.level2.commission) +
|
||
parseFloat(stats.level3.commission)
|
||
).toFixed(2)
|
||
stats.pendingCommission = allOrders
|
||
.filter(order => order.isSettled === 0)
|
||
.reduce((sum, order) => sum + parseFloat(order.userCommission || '0'), 0)
|
||
.toFixed(2)
|
||
|
||
setOrders(uniqueOrders)
|
||
setStatistics(stats)
|
||
|
||
} catch (error) {
|
||
console.error('获取分销订单失败:', error)
|
||
Taro.showToast({
|
||
title: '获取订单失败',
|
||
icon: 'error'
|
||
})
|
||
} finally {
|
||
setLoading(false)
|
||
}
|
||
}, [dealerUser?.userId])
|
||
|
||
// 刷新数据
|
||
const handleRefresh = async () => {
|
||
await fetchOrders()
|
||
}
|
||
|
||
// 初始化加载数据
|
||
useEffect(() => {
|
||
if (dealerUser?.userId) {
|
||
fetchOrders().then()
|
||
}
|
||
}, [fetchOrders])
|
||
|
||
const getStatusText = (isSettled?: number, isInvalid?: number) => {
|
||
if (isInvalid === 1) return '已失效'
|
||
if (isSettled === 1) return '已结算'
|
||
return '待结算'
|
||
}
|
||
|
||
const getStatusColor = (isSettled?: number, isInvalid?: number) => {
|
||
if (isInvalid === 1) return 'danger'
|
||
if (isSettled === 1) return 'success'
|
||
return 'warning'
|
||
}
|
||
|
||
const renderOrderItem = (order: OrderWithDetails) => (
|
||
<View key={order.id} className="bg-white rounded-lg p-4 mb-3 shadow-sm">
|
||
<View className="flex justify-between items-start mb-3">
|
||
<View>
|
||
<Text className="font-semibold text-gray-800 mb-1">
|
||
订单号:{order.orderNo}
|
||
</Text>
|
||
<Text className="text-sm text-gray-500">
|
||
客户:{order.customerName}
|
||
</Text>
|
||
{/* 显示用户在此订单中的层级 */}
|
||
<Text className="text-xs text-blue-500">
|
||
{order.userLevel === 1 && '一级分销'}
|
||
{order.userLevel === 2 && '二级分销'}
|
||
{order.userLevel === 3 && '三级分销'}
|
||
</Text>
|
||
</View>
|
||
<Tag type={getStatusColor(order.isSettled, order.isInvalid)}>
|
||
{getStatusText(order.isSettled, order.isInvalid)}
|
||
</Tag>
|
||
</View>
|
||
|
||
<View className="flex justify-between items-center">
|
||
<View>
|
||
<Text className="text-sm text-gray-600">
|
||
订单金额:¥{order.orderPrice || '0.00'}
|
||
</Text>
|
||
<Text className="text-sm text-orange-500 font-semibold">
|
||
我的佣金:¥{order.userCommission}
|
||
</Text>
|
||
<Text className="text-xs text-gray-400">
|
||
总佣金:¥{order.totalCommission}
|
||
</Text>
|
||
</View>
|
||
<Text className="text-xs text-gray-400">
|
||
{order.createTime}
|
||
</Text>
|
||
</View>
|
||
</View>
|
||
)
|
||
|
||
// 根据状态和层级过滤订单
|
||
const getFilteredOrders = (filter: string) => {
|
||
switch (filter) {
|
||
case '1': // 一级分销
|
||
return orders.filter(order => order.userLevel === 1)
|
||
case '2': // 二级分销
|
||
return orders.filter(order => order.userLevel === 2)
|
||
case '3': // 三级分销
|
||
return orders.filter(order => order.userLevel === 3)
|
||
case '4': // 待结算
|
||
return orders.filter(order => order.isSettled === 0 && order.isInvalid === 0)
|
||
case '5': // 已结算
|
||
return orders.filter(order => order.isSettled === 1)
|
||
case '6': // 已失效
|
||
return orders.filter(order => order.isInvalid === 1)
|
||
default: // 全部
|
||
return orders
|
||
}
|
||
}
|
||
|
||
if (!dealerUser) {
|
||
return (
|
||
<View className="bg-gray-50 min-h-screen flex items-center justify-center">
|
||
<Loading />
|
||
<Text className="text-gray-500 mt-2">加载中...</Text>
|
||
</View>
|
||
)
|
||
}
|
||
|
||
return (
|
||
<View className="bg-gray-50 min-h-screen">
|
||
{/* 统计卡片 */}
|
||
<View className="bg-white p-4 mb-4">
|
||
{/* 总体统计 */}
|
||
<View className="grid grid-cols-3 gap-4 mb-4">
|
||
<View className="text-center">
|
||
<Text className="text-lg font-bold text-blue-500">{statistics.totalOrders}</Text>
|
||
<Text className="text-xs text-gray-500">总订单</Text>
|
||
</View>
|
||
<View className="text-center">
|
||
<Text className="text-lg font-bold text-green-500">¥{statistics.totalCommission}</Text>
|
||
<Text className="text-xs text-gray-500">总佣金</Text>
|
||
</View>
|
||
<View className="text-center">
|
||
<Text className="text-lg font-bold text-orange-500">¥{statistics.pendingCommission}</Text>
|
||
<Text className="text-xs text-gray-500">待结算</Text>
|
||
</View>
|
||
</View>
|
||
|
||
{/* 分层统计 */}
|
||
<View className="border-t pt-3">
|
||
<Text className="text-sm text-gray-600 mb-2">分层统计</Text>
|
||
<View className="grid grid-cols-3 gap-2">
|
||
<View className="text-center bg-gray-50 rounded p-2">
|
||
<Text className="text-sm font-semibold text-red-500">{statistics.level1.orders}</Text>
|
||
<Text className="text-xs text-gray-500">一级订单</Text>
|
||
<Text className="text-xs text-red-500">¥{statistics.level1.commission}</Text>
|
||
</View>
|
||
<View className="text-center bg-gray-50 rounded p-2">
|
||
<Text className="text-sm font-semibold text-blue-500">{statistics.level2.orders}</Text>
|
||
<Text className="text-xs text-gray-500">二级订单</Text>
|
||
<Text className="text-xs text-blue-500">¥{statistics.level2.commission}</Text>
|
||
</View>
|
||
<View className="text-center bg-gray-50 rounded p-2">
|
||
<Text className="text-sm font-semibold text-purple-500">{statistics.level3.orders}</Text>
|
||
<Text className="text-xs text-gray-500">三级订单</Text>
|
||
<Text className="text-xs text-purple-500">¥{statistics.level3.commission}</Text>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
|
||
{/* 订单列表 */}
|
||
<Tabs value={activeTab} onChange={() => setActiveTab}>
|
||
<Tabs.TabPane title="全部" value="0">
|
||
<PullToRefresh
|
||
onRefresh={handleRefresh}
|
||
>
|
||
<View className="p-4">
|
||
{loading ? (
|
||
<View className="text-center py-8">
|
||
<Loading />
|
||
<Text className="text-gray-500 mt-2">加载中...</Text>
|
||
</View>
|
||
) : getFilteredOrders('0').length > 0 ? (
|
||
getFilteredOrders('0').map(renderOrderItem)
|
||
) : (
|
||
<Empty description="暂无分销订单" />
|
||
)}
|
||
</View>
|
||
</PullToRefresh>
|
||
</Tabs.TabPane>
|
||
|
||
<Tabs.TabPane title="一级分销" value="1">
|
||
<View className="p-4">
|
||
{getFilteredOrders('1').length > 0 ? (
|
||
getFilteredOrders('1').map(renderOrderItem)
|
||
) : (
|
||
<Empty description="暂无一级分销订单" />
|
||
)}
|
||
</View>
|
||
</Tabs.TabPane>
|
||
|
||
<Tabs.TabPane title="二级分销" value="2">
|
||
<View className="p-4">
|
||
{getFilteredOrders('2').length > 0 ? (
|
||
getFilteredOrders('2').map(renderOrderItem)
|
||
) : (
|
||
<Empty description="暂无二级分销订单" />
|
||
)}
|
||
</View>
|
||
</Tabs.TabPane>
|
||
|
||
<Tabs.TabPane title="三级分销" value="3">
|
||
<View className="p-4">
|
||
{getFilteredOrders('3').length > 0 ? (
|
||
getFilteredOrders('3').map(renderOrderItem)
|
||
) : (
|
||
<Empty description="暂无三级分销订单" />
|
||
)}
|
||
</View>
|
||
</Tabs.TabPane>
|
||
|
||
<Tabs.TabPane title="待结算" value="4">
|
||
<View className="p-4">
|
||
{getFilteredOrders('4').length > 0 ? (
|
||
getFilteredOrders('4').map(renderOrderItem)
|
||
) : (
|
||
<Empty description="暂无待结算订单" />
|
||
)}
|
||
</View>
|
||
</Tabs.TabPane>
|
||
|
||
<Tabs.TabPane title="已结算" value="5">
|
||
<View className="p-4">
|
||
{getFilteredOrders('5').length > 0 ? (
|
||
getFilteredOrders('5').map(renderOrderItem)
|
||
) : (
|
||
<Empty description="暂无已结算订单" />
|
||
)}
|
||
</View>
|
||
</Tabs.TabPane>
|
||
|
||
<Tabs.TabPane title="已失效" value="6">
|
||
<View className="p-4">
|
||
{getFilteredOrders('6').length > 0 ? (
|
||
getFilteredOrders('6').map(renderOrderItem)
|
||
) : (
|
||
<Empty description="暂无失效订单" />
|
||
)}
|
||
</View>
|
||
</Tabs.TabPane>
|
||
</Tabs>
|
||
</View>
|
||
)
|
||
}
|
||
|
||
export default DealerOrders
|