forked from gxwebsoft/mp-10550
875 lines
31 KiB
TypeScript
875 lines
31 KiB
TypeScript
import {Avatar, Cell, Space, Empty, Tabs, Button, TabPane, Image, Dialog} from '@nutui/nutui-react-taro'
|
||
import {useEffect, useState, useCallback, useRef, CSSProperties} from "react";
|
||
import {View, Text} from '@tarojs/components'
|
||
import Taro from '@tarojs/taro';
|
||
import {InfiniteLoading} from '@nutui/nutui-react-taro'
|
||
import dayjs from "dayjs";
|
||
import {pageShopOrder, updateShopOrder, createOrder} from "@/api/shop/shopOrder";
|
||
import {ShopOrder, ShopOrderParam} from "@/api/shop/shopOrder/model";
|
||
import {listShopOrderGoods} from "@/api/shop/shopOrderGoods";
|
||
import {copyText} from "@/utils/common";
|
||
import PaymentCountdown from "@/components/PaymentCountdown";
|
||
import {PaymentType} from "@/utils/payment";
|
||
import {goTo} from "@/utils/navigation";
|
||
|
||
// 判断订单是否支付已过期
|
||
const isPaymentExpired = (createTime: string, timeoutHours: number = 24): boolean => {
|
||
if (!createTime) return false;
|
||
const createTimeObj = dayjs(createTime);
|
||
const expireTime = createTimeObj.add(timeoutHours, 'hour');
|
||
const now = dayjs();
|
||
return now.isAfter(expireTime);
|
||
};
|
||
|
||
const getInfiniteUlStyle = (showSearch: boolean = false): CSSProperties => ({
|
||
marginTop: showSearch ? '0' : '0', // 如果显示搜索框,增加更多的上边距
|
||
height: showSearch ? '75vh' : '84vh', // 相应调整高度
|
||
width: '100%',
|
||
padding: '0',
|
||
overflowY: 'auto',
|
||
overflowX: 'hidden'
|
||
// 注意:小程序不支持 boxShadow
|
||
})
|
||
|
||
// 统一的订单状态标签配置,与后端 statusFilter 保持一致
|
||
const tabs = [
|
||
{
|
||
index: 0,
|
||
key: '全部',
|
||
title: '全部',
|
||
description: '所有订单',
|
||
statusFilter: -1 // 使用-1表示全部订单
|
||
},
|
||
{
|
||
index: 1,
|
||
key: '待付款',
|
||
title: '待付款',
|
||
description: '等待付款的订单',
|
||
statusFilter: 0 // 对应后端:pay_status = false
|
||
},
|
||
{
|
||
index: 2,
|
||
key: '待发货',
|
||
title: '待发货',
|
||
description: '已付款待发货的订单',
|
||
statusFilter: 1 // 对应后端:pay_status = true AND delivery_status = 10
|
||
},
|
||
{
|
||
index: 3,
|
||
key: '待收货',
|
||
title: '待收货',
|
||
description: '已发货待收货的订单',
|
||
statusFilter: 3 // 对应后端:pay_status = true AND delivery_status = 20
|
||
},
|
||
{
|
||
index: 4,
|
||
key: '已完成',
|
||
title: '已完成',
|
||
description: '已完成的订单',
|
||
statusFilter: 5 // 对应后端:order_status = 1
|
||
},
|
||
{
|
||
index: 5,
|
||
key: '退货/售后',
|
||
title: '退货/售后',
|
||
description: '退货/售后的订单',
|
||
statusFilter: 6 // 对应后端:order_status = 6 (已退款)
|
||
}
|
||
]
|
||
|
||
interface OrderListProps {
|
||
onReload?: () => void;
|
||
searchParams?: ShopOrderParam;
|
||
showSearch?: boolean;
|
||
onSearchParamsChange?: (params: ShopOrderParam) => void; // 新增:通知父组件参数变化
|
||
// 订单视图模式:用户/门店/骑手
|
||
mode?: 'user' | 'store' | 'rider';
|
||
// 固定过滤条件(例如 storeId / riderId),会合并到每次请求里
|
||
baseParams?: ShopOrderParam;
|
||
// 只读模式:隐藏“支付/取消/确认收货/退款”等用户操作按钮
|
||
readOnly?: boolean;
|
||
}
|
||
|
||
function OrderList(props: OrderListProps) {
|
||
const [list, setList] = useState<ShopOrder[]>([])
|
||
const pageRef = useRef(1)
|
||
const [hasMore, setHasMore] = useState(true)
|
||
const [payingOrderId, setPayingOrderId] = useState<number | null>(null)
|
||
// 根据传入的statusFilter设置初始tab索引
|
||
const getInitialTabIndex = () => {
|
||
if (props.searchParams?.statusFilter !== undefined) {
|
||
const tab = tabs.find(t => t.statusFilter === props.searchParams?.statusFilter);
|
||
return tab ? tab.index : 0;
|
||
}
|
||
return 0;
|
||
};
|
||
const [tapIndex, setTapIndex] = useState<number>(() => {
|
||
const initialIndex = getInitialTabIndex();
|
||
console.log('初始化tapIndex:', initialIndex, '对应statusFilter:', props.searchParams?.statusFilter);
|
||
return initialIndex;
|
||
})
|
||
const [loading, setLoading] = useState(false)
|
||
const [error, setError] = useState<string | null>(null)
|
||
const [cancelDialogVisible, setCancelDialogVisible] = useState(false)
|
||
const [orderToCancel, setOrderToCancel] = useState<ShopOrder | null>(null)
|
||
const [confirmReceiveDialogVisible, setConfirmReceiveDialogVisible] = useState(false)
|
||
const [orderToConfirmReceive, setOrderToConfirmReceive] = useState<ShopOrder | null>(null)
|
||
const isReadOnly = props.readOnly || props.mode === 'store' || props.mode === 'rider'
|
||
|
||
// 获取订单状态文本
|
||
const getOrderStatusText = (order: ShopOrder) => {
|
||
|
||
// 优先检查订单状态
|
||
if (order.orderStatus === 2) return '已取消';
|
||
if (order.orderStatus === 4) return '退款申请中';
|
||
if (order.orderStatus === 5) return '退款被拒绝';
|
||
if (order.orderStatus === 6) return '退款成功';
|
||
if (order.orderStatus === 7) return '客户端申请退款';
|
||
|
||
// 检查支付状态 (payStatus为boolean类型,false/0表示未付款,true/1表示已付款)
|
||
if (!order.payStatus) return '等待买家付款';
|
||
|
||
// 已付款后检查发货状态
|
||
if (order.deliveryStatus === 10) return '待发货';
|
||
if (order.formId === 10074) return '已完成';
|
||
if (order.deliveryStatus === 20) {
|
||
// 若订单没有配送员,沿用原“待收货”语义
|
||
if (!order.riderId) return '待收货';
|
||
// 配送员确认送达后(sendEndTime有值),才进入“待确认收货”
|
||
if (order.sendEndTime && order.orderStatus !== 1) return '待确认收货';
|
||
return '配送中';
|
||
}
|
||
if (order.deliveryStatus === 30) return '部分发货';
|
||
|
||
// 最后检查订单完成状态
|
||
if (order.orderStatus === 1) return '已完成';
|
||
if (order.orderStatus === 0) return '未使用';
|
||
|
||
return '未知状态';
|
||
};
|
||
|
||
// 获取订单状态颜色
|
||
const getOrderStatusColor = (order: ShopOrder) => {
|
||
// 优先检查订单状态
|
||
if (order.orderStatus === 2) return 'text-gray-500'; // 已取消
|
||
if (order.orderStatus === 4) return 'text-orange-500'; // 退款申请中
|
||
if (order.orderStatus === 5) return 'text-red-500'; // 退款被拒绝
|
||
if (order.orderStatus === 6) return 'text-green-500'; // 退款成功
|
||
if (order.orderStatus === 7) return 'text-orange-500'; // 客户端申请退款
|
||
|
||
// 检查支付状态
|
||
if (!order.payStatus) return 'text-orange-500'; // 等待买家付款
|
||
|
||
// 已付款后检查发货状态
|
||
if (order.deliveryStatus === 10) return 'text-blue-500'; // 待发货
|
||
if (order.deliveryStatus === 20) {
|
||
if (!order.riderId) return 'text-purple-500'; // 待收货
|
||
if (order.sendEndTime && order.orderStatus !== 1) return 'text-purple-500'; // 待确认收货
|
||
return 'text-blue-500'; // 配送中
|
||
}
|
||
if (order.deliveryStatus === 30) return 'text-blue-500'; // 部分发货
|
||
|
||
// 最后检查订单完成状态
|
||
if (order.orderStatus === 1) return 'text-green-600'; // 已完成
|
||
if (order.orderStatus === 0) return 'text-gray-500'; // 未使用
|
||
|
||
return 'text-gray-600'; // 默认颜色
|
||
};
|
||
|
||
// 使用后端统一的 statusFilter 进行筛选
|
||
const getOrderStatusParams = (index: string | number) => {
|
||
let params: ShopOrderParam = {
|
||
...(props.baseParams || {})
|
||
};
|
||
// 默认是用户视图:添加 userId 过滤;门店/骑手视图由 baseParams 控制
|
||
if (!props.mode || props.mode === 'user') {
|
||
params.userId = Taro.getStorageSync('UserId');
|
||
}
|
||
|
||
// 获取当前tab的statusFilter配置
|
||
const currentTab = tabs.find(tab => tab.index === Number(index));
|
||
if (currentTab && currentTab.statusFilter !== undefined) {
|
||
params.statusFilter = currentTab.statusFilter;
|
||
}
|
||
// 注意:当statusFilter为undefined时,不要添加到params中,这样API请求就不会包含这个参数
|
||
|
||
console.log(`Tab ${index} (${currentTab?.title}) 筛选参数:`, params);
|
||
return params;
|
||
};
|
||
|
||
const reload = useCallback(async (resetPage = false, targetPage?: number) => {
|
||
setLoading(true);
|
||
setError(null); // 清除之前的错误
|
||
const currentPage = resetPage ? 1 : (targetPage || pageRef.current);
|
||
const statusParams = getOrderStatusParams(tapIndex);
|
||
// 合并搜索条件,tab的statusFilter优先级更高
|
||
const searchConditions: any = {
|
||
page: currentPage,
|
||
...statusParams,
|
||
...props.searchParams, // 搜索关键词等其他条件
|
||
};
|
||
|
||
// statusFilter总是添加到搜索条件中(包括-1表示全部)
|
||
if (statusParams.statusFilter !== undefined) {
|
||
searchConditions.statusFilter = statusParams.statusFilter;
|
||
}
|
||
console.log('订单筛选条件:', {
|
||
tapIndex,
|
||
statusParams,
|
||
searchConditions,
|
||
finalStatusFilter: searchConditions.statusFilter
|
||
});
|
||
|
||
try {
|
||
const res = await pageShopOrder(searchConditions);
|
||
|
||
if (res?.list && res?.list.length > 0) {
|
||
// 订单分页接口已返回 orderGoods:列表直接使用该字段
|
||
const incoming = res.list as ShopOrder[];
|
||
|
||
// 使用函数式更新避免依赖 list
|
||
setList(prevList => {
|
||
const newList = resetPage ? incoming : (prevList || []).concat(incoming);
|
||
return newList;
|
||
});
|
||
|
||
// 正确判断是否还有更多数据
|
||
const hasMoreData = incoming.length >= 10; // 假设每页10条数据
|
||
setHasMore(hasMoreData);
|
||
} else {
|
||
setList(prevList => resetPage ? [] : prevList);
|
||
setHasMore(false);
|
||
}
|
||
|
||
pageRef.current = currentPage;
|
||
setLoading(false);
|
||
} catch (error) {
|
||
console.error('加载订单失败:', error);
|
||
setLoading(false);
|
||
setError('加载订单失败,请重试');
|
||
// 添加错误提示
|
||
Taro.showToast({
|
||
title: '加载失败,请重试',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
}, [tapIndex, props.searchParams]); // 移除 list/page 依赖,避免useEffect触发循环
|
||
|
||
const reloadMore = useCallback(async () => {
|
||
if (loading || !hasMore) return; // 防止重复加载
|
||
const nextPage = pageRef.current + 1;
|
||
pageRef.current = nextPage;
|
||
await reload(false, nextPage);
|
||
}, [loading, hasMore, reload]);
|
||
|
||
// 确认收货 - 显示确认对话框
|
||
const confirmReceive = (order: ShopOrder) => {
|
||
setOrderToConfirmReceive(order);
|
||
setConfirmReceiveDialogVisible(true);
|
||
};
|
||
|
||
// 确认收货 - 执行收货操作
|
||
const handleConfirmReceive = async () => {
|
||
if (!orderToConfirmReceive) return;
|
||
|
||
try {
|
||
setConfirmReceiveDialogVisible(false);
|
||
|
||
await updateShopOrder({
|
||
...orderToConfirmReceive,
|
||
deliveryStatus: orderToConfirmReceive.deliveryStatus, // 10未发货 20已发货 30部分发货(收货由orderStatus控制)
|
||
orderStatus: 1 // 已完成
|
||
});
|
||
|
||
Taro.showToast({
|
||
title: '确认收货成功',
|
||
icon: 'success'
|
||
});
|
||
|
||
await reload(true); // 重新加载列表
|
||
props.onReload?.(); // 通知父组件刷新
|
||
|
||
// 清空状态
|
||
setOrderToConfirmReceive(null);
|
||
} catch (error) {
|
||
console.error('确认收货失败:', error);
|
||
Taro.showToast({
|
||
title: '确认收货失败',
|
||
icon: 'none'
|
||
});
|
||
// 重新显示对话框
|
||
setConfirmReceiveDialogVisible(true);
|
||
}
|
||
};
|
||
|
||
// 取消确认收货对话框
|
||
const handleCancelReceiveDialog = () => {
|
||
setConfirmReceiveDialogVisible(false);
|
||
setOrderToConfirmReceive(null);
|
||
};
|
||
|
||
// 申请退款 (待发货状态)
|
||
const applyRefund = async (order: ShopOrder) => {
|
||
try {
|
||
// 更新订单状态为"退款申请中"
|
||
await updateShopOrder({
|
||
orderId: order.orderId,
|
||
orderStatus: 4 // 退款申请中
|
||
});
|
||
|
||
// 更新本地状态
|
||
setList(prev => prev.map(item =>
|
||
item.orderId === order.orderId ? {...item, orderStatus: 4} : item
|
||
));
|
||
|
||
// 跳转到退款申请页面
|
||
Taro.navigateTo({
|
||
url: `/user/order/refund/index?orderId=${order.orderId}&orderNo=${order.orderNo}`
|
||
});
|
||
} catch (error) {
|
||
console.error('更新订单状态失败:', error);
|
||
Taro.showToast({
|
||
title: '操作失败,请重试',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
};
|
||
|
||
// 查看物流 (待收货状态)
|
||
const viewLogistics = (order: ShopOrder) => {
|
||
// 跳转到物流查询页面
|
||
Taro.navigateTo({
|
||
url: `/user/order/logistics/index?orderId=${order.orderId}&orderNo=${order.orderNo}&expressNo=${order.transactionId || ''}&expressCompany=SF`
|
||
});
|
||
};
|
||
|
||
// 再次购买 (已完成状态)
|
||
const buyAgain = (order: ShopOrder) => {
|
||
console.log('再次购买:', order);
|
||
const goodsId = order.orderGoods?.[0]?.goodsId
|
||
if (!goodsId) {
|
||
Taro.showToast({
|
||
title: '订单商品信息缺失',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
goTo(`/shop/orderConfirm/index?goodsId=${goodsId}`)
|
||
// Taro.showToast({
|
||
// title: '再次购买功能开发中',
|
||
// icon: 'none'
|
||
// });
|
||
};
|
||
|
||
// 取消订单
|
||
const cancelOrder = (order: ShopOrder) => {
|
||
setOrderToCancel(order);
|
||
setCancelDialogVisible(true);
|
||
};
|
||
|
||
// 确认取消订单
|
||
const handleConfirmCancel = async () => {
|
||
if (!orderToCancel) return;
|
||
|
||
try {
|
||
setCancelDialogVisible(false);
|
||
|
||
// 更新订单状态为已取消,而不是删除订单
|
||
await updateShopOrder({
|
||
...orderToCancel,
|
||
orderStatus: 2 // 已取消
|
||
});
|
||
|
||
Taro.showToast({
|
||
title: '订单已取消',
|
||
icon: 'success'
|
||
});
|
||
void reload(true); // 重新加载列表
|
||
props.onReload?.(); // 通知父组件刷新
|
||
} catch (error) {
|
||
console.error('取消订单失败:', error);
|
||
Taro.showToast({
|
||
title: '取消订单失败',
|
||
icon: 'error'
|
||
});
|
||
} finally {
|
||
setOrderToCancel(null);
|
||
}
|
||
};
|
||
|
||
// 取消对话框的取消操作
|
||
const handleCancelDialog = () => {
|
||
setCancelDialogVisible(false);
|
||
setOrderToCancel(null);
|
||
};
|
||
|
||
// 立即支付
|
||
const payOrder = async (order: ShopOrder) => {
|
||
try {
|
||
if (!order.orderId || !order.orderNo) {
|
||
Taro.showToast({
|
||
title: '订单信息错误',
|
||
icon: 'error'
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (payingOrderId === order.orderId) {
|
||
return;
|
||
}
|
||
setPayingOrderId(order.orderId);
|
||
|
||
// 检查订单是否已过期
|
||
if (order.createTime && isPaymentExpired(order.createTime)) {
|
||
Taro.showToast({
|
||
title: '订单已过期,无法支付',
|
||
icon: 'error'
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 检查订单状态
|
||
if (order.payStatus) {
|
||
Taro.showToast({
|
||
title: '订单已支付',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (order.orderStatus === 2) {
|
||
Taro.showToast({
|
||
title: '订单已取消,无法支付',
|
||
icon: 'error'
|
||
});
|
||
return;
|
||
}
|
||
|
||
Taro.showLoading({title: '发起支付...'});
|
||
|
||
// 构建商品数据:优先使用订单分页接口返回的 orderGoods;缺失时再补拉一次,避免goodsItems为空导致后端拒绝/再次支付失败
|
||
let orderGoods = order.orderGoods || [];
|
||
if (!orderGoods.length) {
|
||
try {
|
||
orderGoods = (await listShopOrderGoods({orderId: order.orderId})) || [];
|
||
} catch (e) {
|
||
// 继续走下面的校验提示
|
||
console.error('补拉订单商品失败:', e);
|
||
}
|
||
}
|
||
|
||
const goodsItems = orderGoods
|
||
.filter(g => !!(g as any).goodsId || !!(g as any).itemId)
|
||
.map(goods => ({
|
||
goodsId: (goods.goodsId ?? (goods as any).itemId) as number,
|
||
quantity: ((goods as any).quantity ?? goods.totalNum ?? 1) as number,
|
||
// 若后端按SKU计算价格/库存,补齐SKU/规格信息更安全
|
||
skuId: (goods as any).skuId ?? (goods as any).sku_id,
|
||
specInfo: (goods as any).specInfo ?? (goods as any).spec
|
||
}));
|
||
|
||
if (!goodsItems.length) {
|
||
Taro.showToast({
|
||
title: '订单商品信息缺失,请稍后重试',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 对于已存在的订单,我们需要重新发起支付
|
||
// 构建支付请求数据,包含完整的商品信息
|
||
const paymentData = {
|
||
orderId: order.orderId,
|
||
orderNo: order.orderNo,
|
||
goodsItems: goodsItems,
|
||
addressId: order.addressId,
|
||
payType: PaymentType.WECHAT,
|
||
// 尽量携带原订单信息,避免后端重新计算/校验不一致(如使用了优惠券/自提等)
|
||
couponId: order.couponId,
|
||
deliveryType: order.deliveryType,
|
||
selfTakeMerchantId: order.selfTakeMerchantId,
|
||
comments: order.comments,
|
||
title: order.title
|
||
};
|
||
|
||
console.log('重新支付数据:', paymentData);
|
||
|
||
// 直接调用createOrder API进行重新支付
|
||
const result = await createOrder(paymentData as any);
|
||
|
||
if (!result) {
|
||
throw new Error('支付发起失败');
|
||
}
|
||
|
||
// 验证微信支付必要参数
|
||
if (!result.timeStamp || !result.nonceStr || !result.package || !result.paySign) {
|
||
throw new Error('微信支付参数不完整');
|
||
}
|
||
|
||
// 调用微信支付
|
||
try {
|
||
await Taro.requestPayment({
|
||
timeStamp: result.timeStamp,
|
||
nonceStr: result.nonceStr,
|
||
package: result.package,
|
||
signType: (result.signType || 'MD5') as 'MD5' | 'HMAC-SHA256',
|
||
paySign: result.paySign,
|
||
});
|
||
} catch (payError: any) {
|
||
const msg: string = payError?.errMsg || payError?.message || '';
|
||
if (msg.includes('cancel')) {
|
||
// 用户主动取消,不当作“失败”强提示
|
||
Taro.showToast({
|
||
title: '已取消支付',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
throw payError;
|
||
}
|
||
|
||
// 支付成功
|
||
Taro.showToast({
|
||
title: '支付成功',
|
||
icon: 'success'
|
||
});
|
||
|
||
// 重新加载订单列表
|
||
void reload(true);
|
||
props.onReload?.();
|
||
|
||
// 跳转到订单页面
|
||
setTimeout(() => {
|
||
Taro.navigateTo({url: '/user/order/order'});
|
||
}, 2000);
|
||
|
||
} catch (error: any) {
|
||
console.error('支付失败:', error);
|
||
|
||
let errorMessage = '支付失败,请重试';
|
||
const rawMsg: string = error?.errMsg || error?.message || '';
|
||
if (rawMsg) {
|
||
if (rawMsg.includes('cancel')) {
|
||
errorMessage = '用户取消支付';
|
||
} else if (rawMsg.includes('余额不足')) {
|
||
errorMessage = '账户余额不足';
|
||
} else {
|
||
errorMessage = rawMsg;
|
||
}
|
||
}
|
||
|
||
Taro.showToast({
|
||
title: errorMessage,
|
||
icon: 'error'
|
||
});
|
||
} finally {
|
||
Taro.hideLoading();
|
||
setPayingOrderId(null);
|
||
}
|
||
};
|
||
|
||
useEffect(() => {
|
||
void reload(true); // 首次加载、tab切换或搜索条件变化时重置页码
|
||
}, [reload]);
|
||
|
||
// 监听外部statusFilter变化,同步更新tab索引
|
||
useEffect(() => {
|
||
// 获取当前的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, tapIndex]); // 监听statusFilter变化
|
||
|
||
|
||
return (
|
||
<>
|
||
<Tabs
|
||
align={'left'}
|
||
className={'fixed left-0'}
|
||
style={{
|
||
zIndex: 998,
|
||
borderBottom: '1px solid #e5e5e5'
|
||
}}
|
||
tabStyle={{
|
||
backgroundColor: '#ffffff'
|
||
// 注意:小程序不支持 boxShadow
|
||
}}
|
||
value={tapIndex}
|
||
onChange={(paneKey) => {
|
||
console.log('Tab切换:', paneKey, '类型:', typeof paneKey);
|
||
const newTapIndex = Number(paneKey);
|
||
setTapIndex(newTapIndex);
|
||
|
||
// 通知父组件更新 searchParams.statusFilter
|
||
const currentTab = tabs.find(tab => tab.index === newTapIndex);
|
||
if (currentTab && props.onSearchParamsChange) {
|
||
const newSearchParams = {
|
||
...props.searchParams,
|
||
statusFilter: currentTab.statusFilter
|
||
};
|
||
console.log('通知父组件更新searchParams:', newSearchParams);
|
||
props.onSearchParamsChange(newSearchParams);
|
||
}
|
||
}}
|
||
>
|
||
{
|
||
tabs?.map((item, _) => {
|
||
return (
|
||
<TabPane
|
||
key={item.index}
|
||
title={loading && tapIndex === item.index ? `${item.title}...` : item.title}
|
||
></TabPane>
|
||
)
|
||
})
|
||
}
|
||
</Tabs>
|
||
<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>
|
||
)
|
||
}
|
||
>
|
||
|
||
{/* 订单列表 */}
|
||
{list.length > 0 && list
|
||
?.filter((item) => {
|
||
// 如果是待付款标签页(tapIndex === 1),过滤掉支付已过期的订单
|
||
if (tapIndex === 1 && !item.payStatus && item.orderStatus !== 2 && item.createTime) {
|
||
return !isPaymentExpired(item.createTime);
|
||
}
|
||
return true;
|
||
})
|
||
?.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={'flex items-center'}>
|
||
<Text className={'text-gray-600 font-bold text-sm'}
|
||
onClick={(e) => {
|
||
e.stopPropagation();
|
||
copyText(`${item.orderNo}`)
|
||
}}>{item.orderNo}</Text>
|
||
</View>
|
||
{/* 右侧显示合并的状态和倒计时 */}
|
||
<View className={`${getOrderStatusColor(item)} font-medium`}>
|
||
{!item.payStatus && item.orderStatus !== 2 ? (
|
||
<PaymentCountdown
|
||
createTime={item.createTime}
|
||
payStatus={item.payStatus}
|
||
realTime={false}
|
||
showSeconds={false}
|
||
mode={'badge'}
|
||
/>
|
||
) : (
|
||
getOrderStatusText(item)
|
||
)}
|
||
</View>
|
||
</View>
|
||
<View
|
||
className={'create-time text-gray-400 text-xs'}>{dayjs(item.createTime).format('YYYY年MM月DD日 HH:mm:ss')}</View>
|
||
|
||
{/* 商品信息 */}
|
||
<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-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>
|
||
<Button size={'small'} type="primary" onClick={(e) => {
|
||
e.stopPropagation();
|
||
void payOrder(item);
|
||
}}>立即支付</Button>
|
||
</Space>
|
||
)}
|
||
|
||
{/* 待发货状态:显示申请退款 */}
|
||
{item.payStatus && item.deliveryStatus === 10 && item.orderStatus !== 2 && item.orderStatus !== 4 && (
|
||
<Button size={'small'} onClick={(e) => {
|
||
e.stopPropagation();
|
||
applyRefund(item);
|
||
}}>申请退款</Button>
|
||
)}
|
||
|
||
{/* 待收货状态:显示查看物流和确认收货 */}
|
||
{item.deliveryStatus === 20 && (!item.riderId || !!item.sendEndTime) && item.orderStatus !== 2 && (
|
||
<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 === 1 && (
|
||
<Space>
|
||
<Button size={'small'} onClick={(e) => {
|
||
e.stopPropagation();
|
||
buyAgain(item);
|
||
}}>再次购买</Button>
|
||
{/*<Button size={'small'} onClick={(e) => {*/}
|
||
{/* e.stopPropagation();*/}
|
||
{/* evaluateGoods(item);*/}
|
||
{/*}}>评价商品</Button>*/}
|
||
|
||
<Button size={'small'} onClick={(e) => {
|
||
e.stopPropagation();
|
||
applyRefund(item);
|
||
}}>申请退款</Button>
|
||
</Space>
|
||
)}
|
||
|
||
{/* 退款/售后状态:显示查看进度和撤销申请 */}
|
||
{(item.orderStatus === 4 || item.orderStatus === 7) && (
|
||
<Space>
|
||
{/*<Button size={'small'} onClick={(e) => {*/}
|
||
{/* e.stopPropagation();*/}
|
||
{/* viewProgress(item);*/}
|
||
{/*}}>查看进度</Button>*/}
|
||
</Space>
|
||
)}
|
||
|
||
{/* 退款成功状态:显示再次购买 */}
|
||
{item.orderStatus === 6 && (
|
||
<Button size={'small'} type="primary" onClick={(e) => {
|
||
e.stopPropagation();
|
||
buyAgain(item);
|
||
}}>再次购买</Button>
|
||
)}
|
||
</Space>
|
||
)}
|
||
</Space>
|
||
</Cell>
|
||
)
|
||
})}
|
||
</InfiniteLoading>
|
||
)}
|
||
</View>
|
||
|
||
{/* 取消订单确认对话框 */}
|
||
<Dialog
|
||
title="确认取消"
|
||
visible={cancelDialogVisible}
|
||
confirmText="确认取消"
|
||
cancelText="我再想想"
|
||
onConfirm={handleConfirmCancel}
|
||
onCancel={handleCancelDialog}
|
||
>
|
||
确定要取消这个订单吗?
|
||
</Dialog>
|
||
|
||
{/* 确认收货确认对话框 */}
|
||
<Dialog
|
||
title="确认收货"
|
||
visible={confirmReceiveDialogVisible}
|
||
confirmText="确认收货"
|
||
cancelText="我再想想"
|
||
onConfirm={handleConfirmReceive}
|
||
onCancel={handleCancelReceiveDialog}
|
||
>
|
||
确定已经收到商品了吗?确认收货后订单将完成。
|
||
</Dialog>
|
||
</>
|
||
)
|
||
}
|
||
|
||
export default OrderList
|