feat(src): 新增文章、经销商申请、用户地址和礼物添加功能

- 新增文章添加页面,支持文章基本信息、设置、高级设置和图片上传
- 新增经销商申请页面,支持申请信息填写和审核状态显示
- 新增用户地址添加页面,支持地址信息填写和地址识别功能
- 新增礼物添加页面,功能与文章添加类似
- 统一使用 .tsx 文件格式
- 添加 .editorconfig、.eslintrc 和 .gitignore 文件,规范代码风格和项目结构
This commit is contained in:
2025-08-20 14:56:38 +08:00
commit 217bfacadd
507 changed files with 70034 additions and 0 deletions

392
src/dealer/orders/index.tsx Normal file
View File

@@ -0,0 +1,392 @@
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