import { useEffect, useMemo, useState } from 'react'; import { View, Text } from '@tarojs/components'; import Taro, { useDidShow, useRouter, useShareAppMessage, useShareTimeline } from '@tarojs/taro'; import PageShell from '../../components/PageShell'; import SubPageHeader from '../../components/SubPageHeader'; import ShareNavButton from '../../components/ShareNavButton'; import WechatShareReady from '../../components/WechatShareReady'; import ContactCsButton from '../../components/ContactCsButton'; import LogisticsRichText from '../../components/LogisticsRichText'; import { request, toast } from '../../lib/api'; import { buildPayUrl } from '../../lib/checkout-nav'; import { formatEstimatedArrival, isLogisticsNotArrived, latestTrackNode, ORDER_LOGISTICS_PREVIEW_STATUSES, shouldLoadOrderTrack, type OrderTrackEstimatedArrival, type OrderTrackNode, } from '../../lib/order-logistics-utils'; import { fetchOrderTrack } from '../../lib/order-logistics'; import { maskPhone } from '../../lib/phone'; import { confirmOrderReceive, type WechatConfirmPayload } from '../../lib/wechat-order-confirm'; import { buildSceneSharePayload, toWeappShareMessage, toWeappShareTimeline, } from '../../lib/wechat-share'; import { usePageView } from '../../lib/usePageView'; const isWeapp = process.env.TARO_ENV === 'weapp'; type OrderItem = { productName?: string; productSpec?: string; quantity?: number; }; type OrderDetail = { id: string; orderNo?: string; status?: string; payAmount?: number; productName?: string; quantity?: number; qty?: number; receiverName?: string; receiverPhone?: string; receiverProvince?: string; receiverCity?: string; receiverDistrict?: string; receiverAddress?: string; createdAt?: string; originOrderId?: string | null; orderType?: string; isProxyOrder?: boolean; proxyPartnerName?: string | null; deliveryType?: string; items?: OrderItem[]; wechatConfirm?: WechatConfirmPayload | null; delivery?: { provider?: string; trackingNo?: string; logisticsCompany?: string; manualQueryUrl?: string; } | null; }; const STATUS_LABELS: Record = { PENDING_PAY: '待付款', PENDING_SHIP: '待发货', OUT_WAREHOUSE: '出库中', SHIPPING: '配送中', SHIPPED: '配送中', PENDING_RECEIVE: '待签收', DELIVERED: '待签收', COMPLETED: '已完成', CANCELLED: '已取消', REFUNDING: '退款中', REFUNDED: '已退款', }; function fullReceiverAddress(order: OrderDetail) { const detail = (order.receiverAddress || '').trim(); const region = [order.receiverProvince, order.receiverCity, order.receiverDistrict] .filter(Boolean) .join(''); if (!region && !detail) return ''; if (region && detail.startsWith(region)) return detail; return `${region}${detail}`; } export default function OrderDetailPage() { const router = useRouter(); const orderId = router.params.id ?? ''; usePageView('order_detail_view', orderId ? { orderId } : undefined); const [order, setOrder] = useState(null); const [confirming, setConfirming] = useState(false); const [latestTrack, setLatestTrack] = useState(null); const [estimatedArrival, setEstimatedArrival] = useState(null); const [trackLoading, setTrackLoading] = useState(false); async function loadOrderTrack(delivery: OrderDetail['delivery'], orderStatus?: string) { if (!orderId || !shouldLoadOrderTrack(delivery)) { setLatestTrack(null); setEstimatedArrival(null); return; } setTrackLoading(true); try { const track = await fetchOrderTrack(orderId); const nodes = track.nodes ?? []; setLatestTrack(latestTrackNode(nodes)); setEstimatedArrival( isLogisticsNotArrived(nodes, orderStatus) && track.estimatedArrival ? track.estimatedArrival : null, ); } catch { setLatestTrack(null); setEstimatedArrival(null); } finally { setTrackLoading(false); } } useEffect(() => { if (!orderId) return; request(`/trade/orders/${orderId}`) .then((data) => { setOrder(data); void loadOrderTrack(data.delivery, data.status); }) .catch((e) => toast(e instanceof Error ? e.message : '加载失败')); }, [orderId]); useDidShow(() => { if (!orderId) return; // 从微信确认收货组件返回后刷新 request(`/trade/orders/${orderId}`) .then((data) => { setOrder(data); void loadOrderTrack(data.delivery, data.status); }) .catch(() => {}); }); const isReship = !!order?.originOrderId; const isProxy = !!order && (order.isProxyOrder || order.orderType === 'PROXY'); const canPay = !!order && order.status === 'PENDING_PAY' && !isReship; const canConfirmReceive = !!order && !isReship && !isProxy && ['PENDING_RECEIVE', 'DELIVERED'].includes(order.status || ''); const canViewLogistics = !!order && order.deliveryType !== 'ON_SITE_PICKUP' && !isReship && ['PENDING_SHIP', 'OUT_WAREHOUSE', 'SHIPPING', 'SHIPPED', 'PENDING_RECEIVE', 'DELIVERED', 'COMPLETED'].includes( order.status || '', ); const showLogisticsPreview = canViewLogistics && ORDER_LOGISTICS_PREVIEW_STATUSES.includes( (order?.status || '') as (typeof ORDER_LOGISTICS_PREVIEW_STATUSES)[number], ); const item = order?.items?.[0]; const productName = item?.productName || order?.productName || '杜康商品'; const quantity = item?.quantity ?? order?.quantity ?? order?.qty ?? 1; const addressText = order ? fullReceiverAddress(order) : ''; const receiverLine = order ? [order.receiverName, order.receiverPhone ? maskPhone(String(order.receiverPhone)) : ''] .filter(Boolean) .join(' ') : ''; const sharePayload = useMemo( () => buildSceneSharePayload('orderDetail', { path: orderId ? `/pages/order-detail/index?id=${orderId}` : '/pages/home/index', titleVars: { productName: productName && productName !== '杜康商品' ? productName : '', }, }), [productName, orderId], ); useShareAppMessage(() => toWeappShareMessage(sharePayload)); useShareTimeline(() => toWeappShareTimeline(sharePayload, orderId ? `id=${orderId}` : ''), ); function goPay() { if (!order) return; Taro.navigateTo({ url: buildPayUrl({ orderId: order.id }) }); } function goCustomerService() { Taro.navigateTo({ url: '/pages/customer-service/index' }); } function goLogistics() { if (!order) return; Taro.navigateTo({ url: `/pages/order-logistics/index?id=${order.id}` }); } async function confirmReceive() { if (!order || !canConfirmReceive || confirming) return; const { confirm } = await Taro.showModal({ title: '确认收货?', content: isWeapp ? '将打开微信确认收货,完成后订单即完结,无需再点服务通知。' : '请确认已收到商品。确认后订单将完成,好客权益可正常使用。', confirmText: '确认收货', cancelText: '再想想', }); if (!confirm) return; setConfirming(true); try { const mode = await confirmOrderReceive({ orderId: order.id, wechatConfirm: order.wechatConfirm, onLocalSuccess: async () => { const updated = await request(`/trade/orders/${order.id}`); setOrder(updated); toast('已确认收货'); }, }); if (mode === 'wechat') { // 回跳后由 App.onShow / 本页 useDidShow 处理 return; } } catch (e) { toast(e instanceof Error ? e.message : '确认收货失败'); } finally { setConfirming(false); } } const pageClass = [ 'order-detail-page', order ? 'order-detail-page--with-actions' : '', canPay || canConfirmReceive ? 'order-detail-page--with-pay' : '', ] .filter(Boolean) .join(' '); return ( { // 支付完成后 reLaunch 进详情:栈仅一页时 navigateBack 会退出小程序,统一回首页 const fromPay = String(router.params.from || '') === 'pay'; if (fromPay || Taro.getCurrentPages().length <= 1) { Taro.switchTab({ url: '/pages/home/index' }).catch(() => { Taro.reLaunch({ url: '/pages/home/index' }); }); return; } Taro.navigateBack(); }} right={} /> {!order ? ( 加载中… ) : ( <> 订单状态 {STATUS_LABELS[order.status || ''] || order.status || '处理中'} {isProxy ? 代下单 : null} {isProxy && order.proxyPartnerName ? ( 由合伙人 {order.proxyPartnerName} 代下 ) : null} {showLogisticsPreview ? ( {trackLoading ? ( 物流信息加载中… ) : latestTrack?.trackInfo ? ( ) : order.delivery?.manualQueryUrl ? ( 物流已更新,点击查看详情 ) : ( 物流信息待更新,请稍后查看 )} 物流详情 {estimatedArrival ? ( {formatEstimatedArrival(estimatedArrival)} ) : null} ) : canViewLogistics ? ( 查看物流追踪 ) : null} 商品信息 {productName} x{quantity} 实付金额 ¥{Number(order.payAmount ?? 0).toFixed(2)} 收货信息 {receiverLine || addressText ? ( <> {receiverLine ? ( 收货人 {receiverLine} ) : null} {addressText ? ( 收货地址 {addressText} ) : null} ) : ( 地址信息待完善 )} 订单信息 订单编号 {order.orderNo || order.id} 下单时间 {order.createdAt ? String(order.createdAt).slice(0, 19).replace('T', ' ') : '-'} )} {order ? ( {isWeapp ? ( 联系客服 ) : ( 联系客服 )} {canPay ? ( <> 待支付 ¥{Number(order.payAmount ?? 0).toFixed(2)} 去付款 ) : null} {canConfirmReceive ? ( void confirmReceive()} > {confirming ? '提交中…' : '确认收货'} ) : null} ) : null} ); }