import { useCallback, useEffect, useMemo, useState } from 'react'; import { Button, Descriptions, Drawer, Empty, Image, Space, Spin, Timeline, Typography, message, } from 'antd'; import type { OrderTrackDto, OrderTrackNodeDto } from '@dukang/shared-types'; import { isXfxProviderCode } from '@dukang/shared-types'; import { request } from '../lib/api'; import { DELIVERY_PROVIDER_LABELS, fmtTime } from '../lib/constants'; type Props = { open: boolean; orderId: string | null; orderNo?: string | null; orderStatus?: string | null; onClose: () => void; }; function providerLabel(provider?: string | null, company?: string | null) { if (company) return company; if (!provider) return '—'; if (DELIVERY_PROVIDER_LABELS[provider]) return DELIVERY_PROVIDER_LABELS[provider]; if (isXfxProviderCode(provider)) return '小飞侠'; return provider; } function sortOldestFirst(nodes: OrderTrackNodeDto[]) { return [...nodes].sort((a, b) => { const ta = new Date(a.createTime).getTime(); const tb = new Date(b.createTime).getTime(); if (Number.isNaN(ta) && Number.isNaN(tb)) return 0; if (Number.isNaN(ta)) return 1; if (Number.isNaN(tb)) return -1; return ta - tb; }); } export default function OrderTrackDrawer({ open, orderId, orderNo, orderStatus, onClose, }: Props) { const [loading, setLoading] = useState(false); const [track, setTrack] = useState(null); const load = useCallback(async () => { if (!orderId) return; setLoading(true); try { const data = await request(`/admin/orders/${orderId}/track`); setTrack(data); } catch (e) { setTrack(null); message.error(e instanceof Error ? e.message : '加载路由失败'); } finally { setLoading(false); } }, [orderId]); useEffect(() => { if (!open || !orderId) { setTrack(null); return; } void load(); }, [open, orderId, load]); const nodes = useMemo( () => (track?.nodes?.length ? sortOldestFirst(track.nodes) : []), [track?.nodes], ); const timelineComplete = ['PENDING_RECEIVE', 'DELIVERED', 'COMPLETED'].includes( orderStatus || '', ); return ( void load()} loading={loading} disabled={!orderId}> 刷新 } > {(orderNo || track?.trackingNo || track?.provider) && ( {orderNo ? {orderNo} : null} {providerLabel(track?.provider, track?.logisticsCompany)} {track?.trackingNo || '—'} {track?.manualQueryUrl ? ( 打开物流查询 ) : null} {track?.estimatedArrival?.arriveTime ? ( {fmtTime(track.estimatedArrival.arriveTime)} {track.estimatedArrival.siteName ? `(${track.estimatedArrival.siteName})` : ''} ) : null} )} {track?.signPhotoUrls && track.signPhotoUrls.length > 0 ? (
签收照片 {track.signPhotoUrls.map((url) => ( ))}
) : null} 物流动态 {nodes.length > 0 ? ( { const isLatest = index === nodes.length - 1; return { color: isLatest ? (timelineComplete ? 'green' : 'blue') : 'gray', children: (
{node.statusName ? ( {node.statusName} ) : null} {node.trackInfo || '—'} {fmtTime(node.createTime)}
), }; })} /> ) : ( )}
); }