refactor(user): 优化用户订单相关功能

- 移除 coupon API 中的 SERVER_API_URL,直接使用相对路径
- 优化 order 页面的搜索和重置逻辑- 更新 OrderList 组件,支持空订单时显示 Empty 组件- 调整 UserCard 中的用户统计数据加载逻辑
- 修改 UserOrder 组件中的订单状态文本和链接
This commit is contained in:
2025-08-11 23:16:33 +08:00
parent f564703e51
commit 1802a27234
5 changed files with 159 additions and 138 deletions

View File

@@ -1,4 +1,4 @@
import {Avatar, Cell, Space, Tabs, Button, TabPane, Image} from '@nutui/nutui-react-taro'
import {Avatar, Cell, Space, Empty, Tabs, Button, TabPane, Image} from '@nutui/nutui-react-taro'
import {useEffect, useState, CSSProperties} from "react";
import {View} from '@tarojs/components'
import Taro from '@tarojs/taro';
@@ -27,7 +27,7 @@ const tabs = [
key: '全部',
title: '全部',
description: '所有订单',
statusFilter: undefined // 不传statusFilter显示所有订单
statusFilter: -1 // 使用-1表示全部订单
},
{
index: 1,
@@ -59,9 +59,9 @@ const tabs = [
},
{
index: 5,
key: '已取消',
title: '已取消',
description: '已取消/退款的订单',
key: '退货/售后',
title: '退货/售后',
description: '退货/售后的订单',
statusFilter: 6 // 对应后端order_status = 6 (已退款)
}
]
@@ -84,10 +84,6 @@ function OrderList(props: OrderListProps) {
// 根据传入的statusFilter设置初始tab索引
const getInitialTabIndex = () => {
if (props.searchParams?.statusFilter !== undefined) {
// 如果statusFilter为-1表示全部对应index为0
if (props.searchParams.statusFilter === -1) {
return 0;
}
const tab = tabs.find(t => t.statusFilter === props.searchParams?.statusFilter);
return tab ? tab.index : 0;
}
@@ -117,7 +113,7 @@ function OrderList(props: OrderListProps) {
// 已付款后检查发货状态
if (order.deliveryStatus === 10) return '待发货';
if (order.deliveryStatus === 20) return '待收货';
if (order.deliveryStatus === 30) return '已收货';
if (order.deliveryStatus === 30) return '已完成';
// 最后检查订单完成状态
if (order.orderStatus === 1) return '已完成';
@@ -161,6 +157,7 @@ function OrderList(props: OrderListProps) {
if (currentTab && currentTab.statusFilter !== undefined) {
params.statusFilter = currentTab.statusFilter;
}
// 注意当statusFilter为undefined时不要添加到params中这样API请求就不会包含这个参数
console.log(`Tab ${index} (${currentTab?.title}) 筛选参数:`, params);
return params;
@@ -172,16 +169,21 @@ function OrderList(props: OrderListProps) {
const currentPage = resetPage ? 1 : (targetPage || page);
const statusParams = getOrderStatusParams(tapIndex);
// 合并搜索条件tab的statusFilter优先级更高
const searchConditions = {
const searchConditions: any = {
page: currentPage,
userId: statusParams.userId, // 用户ID
...props.searchParams, // 搜索关键词等其他条件
statusFilter: statusParams.statusFilter // tab的statusFilter优先级最高
};
// statusFilter总是添加到搜索条件中包括-1表示全部
if (statusParams.statusFilter !== undefined) {
searchConditions.statusFilter = statusParams.statusFilter;
}
console.log('订单筛选条件:', {
tapIndex,
statusParams,
searchConditions
searchConditions,
finalStatusFilter: searchConditions.statusFilter
});
try {
@@ -198,7 +200,7 @@ function OrderList(props: OrderListProps) {
const batchResults = await Promise.all(
batch.map(async (order) => {
try {
const orderGoods = await listShopOrderGoods({ orderId: order.orderId });
const orderGoods = await listShopOrderGoods({orderId: order.orderId});
return {
...order,
orderGoods: orderGoods || []
@@ -306,10 +308,34 @@ function OrderList(props: OrderListProps) {
reload(true).then(); // 首次加载或tab切换时重置页码
}, [tapIndex]); // 监听tapIndex变化
// 监听外部statusFilter变化同步更新tab索引
useEffect(() => {
// 当外部传入的搜索参数变化时不包括statusFilter因为tab切换会处理
// 获取当前的statusFilter如果未定义则默认为-1全部
const currentStatusFilter = props.searchParams?.statusFilter !== undefined
? props.searchParams.statusFilter
: -1;
const tab = tabs.find(t => t.statusFilter === currentStatusFilter);
const targetTabIndex = tab ? tab.index : 0;
console.log('外部statusFilter变化:', {
statusFilter: currentStatusFilter,
originalStatusFilter: props.searchParams?.statusFilter,
currentTapIndex: tapIndex,
targetTabIndex,
shouldUpdate: targetTabIndex !== tapIndex
});
if (targetTabIndex !== tapIndex) {
setTapIndex(targetTabIndex);
// 不需要调用reload因为tapIndex变化会触发reload
}
}, [props.searchParams?.statusFilter]); // 监听statusFilter变化
useEffect(() => {
// 当外部传入的搜索参数变化时不包括statusFilter因为上面已经处理
// 只有当搜索关键词等其他条件变化时才重新加载
const { statusFilter, ...otherParams } = props.searchParams || {};
const {statusFilter, ...otherParams} = props.searchParams || {};
// 检查是否有除statusFilter外的其他搜索条件变化
const hasOtherSearchParams = Object.keys(otherParams).some(key =>
@@ -385,82 +411,104 @@ function OrderList(props: OrderListProps) {
</>
}
loadMoreText={
<View className={'h-24'}>
</View>
list.length === 0 ? (
<Empty style={{ backgroundColor: 'transparent' }} description="您还没有订单哦"/>
) : (
<View className={'h-24'}>
</View>
)
}
>
{list?.map((item, index) => {
return (
<Cell key={index} style={{padding: '16px'}} onClick={() => Taro.navigateTo({url: `/shop/orderDetail/index?orderId=${item.orderId}`})}>
<Space direction={'vertical'} className={'w-full flex flex-col'}>
<View className={'order-no flex justify-between'}>
<View className={'text-gray-600 font-bold text-sm'}
onClick={(e) => {e.stopPropagation(); copyText(`${item.orderNo}`)}}>{item.orderNo}</View>
<View className={`${getOrderStatusColor(item)} font-medium`}>{getOrderStatusText(item)}</View>
</View>
<div
className={'create-time text-gray-400 text-xs'}>{dayjs(item.createTime).format('YYYY年MM月DD日 HH:mm:ss')}</div>
{/* 商品信息 */}
<div className={'goods-info'}>
{item.orderGoods && item.orderGoods.length > 0 ? (
item.orderGoods.map((goods, goodsIndex) => (
<div key={goodsIndex} className={'flex items-center mb-2'}>
<Image
src={goods.image || '/default-goods.png'}
width="50"
height="50"
lazyLoad={false}
className={'rounded'}
/>
<div className={'ml-2 flex-1'}>
<div className={'text-sm font-bold'}>{goods.goodsName}</div>
{goods.spec && <div className={'text-gray-500 text-xs'}>{goods.spec}</div>}
<div className={'text-gray-500 text-xs'}>{goods.totalNum}</div>
{/* 订单列表 */}
{list.length > 0 && list?.map((item, index) => {
return (
<Cell key={index} style={{padding: '16px'}}
onClick={() => Taro.navigateTo({url: `/shop/orderDetail/index?orderId=${item.orderId}`})}>
<Space direction={'vertical'} className={'w-full flex flex-col'}>
<View className={'order-no flex justify-between'}>
<View className={'text-gray-600 font-bold text-sm'}
onClick={(e) => {
e.stopPropagation();
copyText(`${item.orderNo}`)
}}>{item.orderNo}</View>
<View className={`${getOrderStatusColor(item)} font-medium`}>{getOrderStatusText(item)}</View>
</View>
<div
className={'create-time text-gray-400 text-xs'}>{dayjs(item.createTime).format('YYYY年MM月DD日 HH:mm:ss')}</div>
{/* 商品信息 */}
<div className={'goods-info'}>
{item.orderGoods && item.orderGoods.length > 0 ? (
item.orderGoods.map((goods, goodsIndex) => (
<div key={goodsIndex} className={'flex items-center mb-2'}>
<Image
src={goods.image || '/default-goods.png'}
width="50"
height="50"
lazyLoad={false}
className={'rounded'}
/>
<div className={'ml-2 flex-1'}>
<div className={'text-sm font-bold'}>{goods.goodsName}</div>
{goods.spec && <div className={'text-gray-500 text-xs'}>{goods.spec}</div>}
<div className={'text-gray-500 text-xs'}>{goods.totalNum}</div>
</div>
<div className={'text-sm'}>{goods.price}</div>
</div>
))
) : (
<div className={'flex items-center'}>
<Avatar
src='/default-goods.png'
size={'50'}
shape={'square'}
/>
<div className={'ml-2'}>
<div className={'text-sm'}>{item.title || '订单商品'}</div>
<div className={'text-gray-400 text-xs'}>{item.totalNum}</div>
</div>
<div className={'text-sm'}>{goods.price}</div>
</div>
))
) : (
<div className={'flex items-center'}>
<Avatar
src='/default-goods.png'
size={'50'}
shape={'square'}
/>
<div className={'ml-2'}>
<div className={'text-sm'}>{item.title || '订单商品'}</div>
<div className={'text-gray-400 text-xs'}>{item.totalNum}</div>
</div>
</div>
)}
</div>
)}
</div>
<div className={'w-full text-right'}>{item.payPrice}</div>
<div className={'w-full text-right'}>{item.payPrice}</div>
{/* 操作按钮 */}
<Space className={'btn flex justify-end'}>
{/* 待付款状态:显示取消订单和立即支付 */}
{(!item.payStatus) && item.orderStatus !== 2 && (
<Space>
<Button size={'small'} onClick={(e) => {e.stopPropagation(); cancelOrder(item)}}></Button>
<Button size={'small'} type="primary" onClick={(e) => {e.stopPropagation(); console.log('立即支付')}}></Button>
</Space>
)}
{/* 待收货状态:显示确认收货 */}
{item.deliveryStatus === 20 && (
<Button size={'small'} type="primary" onClick={(e) => {e.stopPropagation(); confirmReceive(item)}}></Button>
)}
{/* 已完成状态:显示申请退款 */}
{item.orderStatus === 1 && (
<Button size={'small'} onClick={(e) => {e.stopPropagation(); console.log('申请退款')}}>退</Button>
)}
{/* 退款相关状态的按钮可以在这里添加 */}
{/* 操作按钮 */}
<Space className={'btn flex justify-end'}>
{/* 待付款状态:显示取消订单和立即支付 */}
{(!item.payStatus) && item.orderStatus !== 2 && (
<Space>
<Button size={'small'} onClick={(e) => {
e.stopPropagation();
cancelOrder(item)
}}></Button>
<Button size={'small'} type="primary" onClick={(e) => {
e.stopPropagation();
console.log('立即支付')
}}></Button>
</Space>
)}
{/* 待收货状态:显示确认收货 */}
{item.deliveryStatus === 20 && (
<Button size={'small'} type="primary" onClick={(e) => {
e.stopPropagation();
confirmReceive(item)
}}></Button>
)}
{/* 已完成状态:显示申请退款 */}
{item.orderStatus === 1 && (
<Button size={'small'} onClick={(e) => {
e.stopPropagation();
console.log('申请退款')
}}>退</Button>
)}
{/* 退款相关状态的按钮可以在这里添加 */}
</Space>
</Space>
</Space>
</Cell>
)
</Cell>
)
})}
</InfiniteLoading>
)}