feat(order): 添加下拉刷新功能到订单列表

- 引入 PullToRefresh 组件实现下拉刷新功能
- 将原有滚动容器包装到 PullToRefresh 组件内部
- 实现下拉刷新逻辑,重置分页数据并重新加载
- 设置刷新头部高度为 60
- 保留原有的无限滚动和上拉加载功能
This commit is contained in:
2026-02-10 13:00:24 +08:00
parent fc3b32215e
commit b22ff991f0

View File

@@ -1,8 +1,7 @@
import {Avatar, Cell, Space, Empty, Tabs, Button, TabPane, Image, Dialog} from '@nutui/nutui-react-taro' import {Avatar, Cell, Space, Empty, Tabs, Button, TabPane, Image, Dialog, PullToRefresh, InfiniteLoading} from '@nutui/nutui-react-taro'
import {useEffect, useState, useCallback, useRef, CSSProperties} from "react"; import {useEffect, useState, useCallback, useRef, CSSProperties} from "react";
import {View, Text} from '@tarojs/components' import {View, Text} from '@tarojs/components'
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
import {InfiniteLoading} from '@nutui/nutui-react-taro'
import dayjs from "dayjs"; import dayjs from "dayjs";
import { import {
pageShopOrder, pageShopOrder,
@@ -685,193 +684,202 @@ function OrderList(props: OrderListProps) {
}) })
} }
</Tabs> </Tabs>
<View style={getInfiniteUlStyle(props.showSearch)} id="scroll"> <PullToRefresh
{error ? ( onRefresh={async () => {
<View className="flex flex-col items-center justify-center h-64"> setHasMore(true)
<View className="text-gray-500 mb-4">{error}</View> await reload(true)
<Button props.onReload?.()
size="small" }}
type="primary" headHeight={60}
onClick={() => reload(true)} >
<View style={getInfiniteUlStyle(props.showSearch)} id="scroll">
{error ? (
<View className="flex flex-col items-center justify-center h-64">
<View className="text-gray-500 mb-4">{error}</View>
<Button
size="small"
type="primary"
onClick={() => reload(true)}
>
</Button>
</View>
) : (
<InfiniteLoading
target="scroll"
hasMore={hasMore}
onLoadMore={reloadMore}
onScroll={() => {
}}
onScrollToUpper={() => {
}}
loadingText={
<>
</>
}
loadMoreText={
list.length === 0 ? (
<Empty style={{backgroundColor: 'transparent'}} description="您还没有订单哦"/>
) : (
<View className={'h-24'}>
</View>
)
}
> >
</Button>
</View>
) : (
<InfiniteLoading
target="scroll"
hasMore={hasMore}
onLoadMore={reloadMore}
onScroll={() => {
}} {/* 订单列表 */}
onScrollToUpper={() => { {list.length > 0 && list
?.filter((item) => {
}} // “待收货”不展示退款中的/已退款订单,这些订单统一放到“退货/售后”
loadingText={ if (tapIndex === 3 && (item.orderStatus === 4 || item.orderStatus === 6)) {
<> return false;
}
</> // “退货/售后”只展示售后相关状态
} if (tapIndex === 5) {
loadMoreText={ return item.orderStatus === 4 || item.orderStatus === 5 || item.orderStatus === 6 || item.orderStatus === 7;
list.length === 0 ? ( }
<Empty style={{backgroundColor: 'transparent'}} description="您还没有订单哦"/> return true;
) : ( })
<View className={'h-24'}> ?.map((item, index) => {
return (
</View> <Cell key={item.orderId ?? item.orderNo ?? 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={'flex items-center'}>
{/* 订单列表 */} <Text className={'text-gray-600 font-bold text-sm'}
{list.length > 0 && list onClick={(e) => {
?.filter((item) => { e.stopPropagation();
// “待收货”不展示退款中的/已退款订单,这些订单统一放到“退货/售后” copyText(`${item.orderNo}`)
if (tapIndex === 3 && (item.orderStatus === 4 || item.orderStatus === 6)) { }}>{item.orderNo}</Text>
return false; </View>
} {/* 右侧显示合并的状态和倒计时 */}
// “退货/售后”只展示售后相关状态 <View className={`${getOrderStatusColor(item)} font-medium`}>
if (tapIndex === 5) { {!item.payStatus && item.orderStatus !== 2 ? (
return item.orderStatus === 4 || item.orderStatus === 5 || item.orderStatus === 6 || item.orderStatus === 7; <PaymentCountdown
} expirationTime={item.expirationTime}
return true; createTime={item.createTime}
}) payStatus={item.payStatus}
?.map((item, index) => { realTime={false}
return ( showSeconds={false}
<Cell key={item.orderId ?? item.orderNo ?? index} style={{padding: '16px'}} timeoutHours={24}
onClick={() => Taro.navigateTo({url: `/shop/orderDetail/index?orderId=${item.orderId}`})}> mode={'badge'}
<Space direction={'vertical'} className={'w-full flex flex-col'}> />
<View className={'order-no flex justify-between'}> ) : (
<View className={'flex items-center'}> getOrderStatusText(item)
<Text className={'text-gray-600 font-bold text-sm'} )}
onClick={(e) => { </View>
e.stopPropagation();
copyText(`${item.orderNo}`)
}}>{item.orderNo}</Text>
</View> </View>
{/* 右侧显示合并的状态和倒计时 */} <View
<View className={`${getOrderStatusColor(item)} font-medium`}> className={'create-time text-gray-400 text-xs'}>{dayjs(item.createTime).format('YYYY年MM月DD日 HH:mm:ss')}</View>
{!item.payStatus && item.orderStatus !== 2 ? (
<PaymentCountdown {/* 商品信息 */}
expirationTime={item.expirationTime} <View className={'goods-info'}>
createTime={item.createTime} {item.orderGoods && item.orderGoods.length > 0 ? (
payStatus={item.payStatus} item.orderGoods.map((goods, goodsIndex) => (
realTime={false} <View key={goodsIndex} className={'flex items-center mb-2'}>
showSeconds={false} <Image
timeoutHours={24} src={goods.image || '/default-goods.png'}
mode={'badge'} width="50"
/> height="50"
lazyLoad={false}
className={'rounded'}
/>
<View className={'ml-2 flex flex-col flex-1'}>
<Text className={'text-sm font-bold'}>
{goods.goodsName || (goods as any).goodsTitle || (goods as any).title || item.title || '订单商品'}
</Text>
{(goods.spec || (goods as any).specInfo) && (
<Text className={'text-gray-500 text-xs'}>{goods.spec || (goods as any).specInfo}</Text>
)}
<Text className={'text-gray-500 text-xs'}>{(goods as any).quantity ?? goods.totalNum}</Text>
</View>
<Text className={'text-gray-400 text-xs'}>x</Text>
<Text className={'text-sm'}>{goods.price || (goods as any).payPrice}</Text>
</View>
))
) : ( ) : (
getOrderStatusText(item) <View className={'flex items-center'}>
<Avatar
src='/default-goods.png'
size={'50'}
shape={'square'}
/>
<View className={'ml-2'}>
<Text className={'text-sm'}>{item.title || '订单商品'}</Text>
<Text className={'text-gray-400 text-xs'}>{item.totalNum}</Text>
</View>
</View>
)} )}
</View> </View>
</View>
<View
className={'create-time text-gray-400 text-xs'}>{dayjs(item.createTime).format('YYYY年MM月DD日 HH:mm:ss')}</View>
{/* 商品信息 */} <Text className={'w-full text-right'}>{item.payPrice}</Text>
<View className={'goods-info'}>
{item.orderGoods && item.orderGoods.length > 0 ? (
item.orderGoods.map((goods, goodsIndex) => (
<View key={goodsIndex} className={'flex items-center mb-2'}>
<Image
src={goods.image || '/default-goods.png'}
width="50"
height="50"
lazyLoad={false}
className={'rounded'}
/>
<View className={'ml-2 flex flex-col flex-1'}>
<Text className={'text-sm font-bold'}>
{goods.goodsName || (goods as any).goodsTitle || (goods as any).title || item.title || '订单商品'}
</Text>
{(goods.spec || (goods as any).specInfo) && (
<Text className={'text-gray-500 text-xs'}>{goods.spec || (goods as any).specInfo}</Text>
)}
<Text className={'text-gray-500 text-xs'}>{(goods as any).quantity ?? goods.totalNum}</Text>
</View>
<Text className={'text-gray-400 text-xs'}>x</Text>
<Text className={'text-sm'}>{goods.price || (goods as any).payPrice}</Text>
</View>
))
) : (
<View className={'flex items-center'}>
<Avatar
src='/default-goods.png'
size={'50'}
shape={'square'}
/>
<View className={'ml-2'}>
<Text className={'text-sm'}>{item.title || '订单商品'}</Text>
<Text className={'text-gray-400 text-xs'}>{item.totalNum}</Text>
</View>
</View>
)}
</View>
<Text className={'w-full text-right'}>{item.payPrice}</Text> {/* 操作按钮 */}
{!isReadOnly && (
<Space className={'btn flex justify-end'}>
{/* 待付款状态:显示取消订单和立即支付 */}
{(!item.payStatus) && item.orderStatus !== 2 && (
<Space>
<Button size={'small'} onClick={(e) => {
e.stopPropagation();
void cancelOrder(item);
}}></Button>
{(!item.createTime || !isPaymentExpired(item.createTime, 24)) && (
<Button size={'small'} type="primary" onClick={(e) => {
e.stopPropagation();
void payOrder(item);
}}></Button>
)}
</Space>
)}
{/* 操作按钮 */} {/* 待发货状态:显示申请退款 */}
{!isReadOnly && ( {item.payStatus && isWithinRefundWindow(item.payTime, 60) && item.deliveryStatus === 10 && item.orderStatus !== 2 && item.orderStatus !== 4 && !isOrderCompleted(item) && (
<Space className={'btn flex justify-end'}>
{/* 待付款状态:显示取消订单和立即支付 */}
{(!item.payStatus) && item.orderStatus !== 2 && (
<Space>
<Button size={'small'} onClick={(e) => { <Button size={'small'} onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
void cancelOrder(item); applyRefund(item);
}}></Button> }}>退</Button>
{(!item.createTime || !isPaymentExpired(item.createTime, 24)) && ( )}
{/* 待收货状态:显示查看物流和确认收货 */}
{item.deliveryStatus === 20 && (!item.riderId || !!item.sendEndTime) && item.orderStatus !== 2 && item.orderStatus !== 6 && !isOrderCompleted(item) && (
<Space>
{/*<Button size={'small'} onClick={(e) => {*/}
{/* e.stopPropagation();*/}
{/* viewLogistics(item);*/}
{/*}}>查看物流</Button>*/}
<Button size={'small'} type="primary" onClick={(e) => { <Button size={'small'} type="primary" onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
void payOrder(item); confirmReceive(item);
}}></Button> }}></Button>
)} </Space>
</Space> )}
)}
{/* 待发货状态:显示申请退款 */} {/* 退款/售后状态:显示查看进度和撤销申请 */}
{item.payStatus && isWithinRefundWindow(item.payTime, 60) && item.deliveryStatus === 10 && item.orderStatus !== 2 && item.orderStatus !== 4 && !isOrderCompleted(item) && ( {(item.orderStatus === 4 || item.orderStatus === 7) && (
<Button size={'small'} onClick={(e) => { <Space>
e.stopPropagation(); {/*<Button size={'small'} onClick={(e) => {*/}
applyRefund(item); {/* e.stopPropagation();*/}
}}>退</Button> {/* viewProgress(item);*/}
)} {/*}}>查看进度</Button>*/}
</Space>
)}
{/* 待收货状态:显示查看物流和确认收货 */} </Space>
{item.deliveryStatus === 20 && (!item.riderId || !!item.sendEndTime) && item.orderStatus !== 2 && item.orderStatus !== 6 && !isOrderCompleted(item) && (
<Space>
{/*<Button size={'small'} onClick={(e) => {*/}
{/* e.stopPropagation();*/}
{/* viewLogistics(item);*/}
{/*}}>查看物流</Button>*/}
<Button size={'small'} type="primary" onClick={(e) => {
e.stopPropagation();
confirmReceive(item);
}}></Button>
</Space>
)} )}
{/* 退款/售后状态:显示查看进度和撤销申请 */}
{(item.orderStatus === 4 || item.orderStatus === 7) && (
<Space>
{/*<Button size={'small'} onClick={(e) => {*/}
{/* e.stopPropagation();*/}
{/* viewProgress(item);*/}
{/*}}>查看进度</Button>*/}
</Space>
)}
</Space> </Space>
)} </Cell>
</Space> )
</Cell> })}
) </InfiniteLoading>
})} )}
</InfiniteLoading> </View>
)} </PullToRefresh>
</View>
{/* 取消订单确认对话框 */} {/* 取消订单确认对话框 */}
<Dialog <Dialog