import React, { useEffect, useRef, useState } from 'react'; import { App, Button, Card, Divider, Drawer, Empty, Popconfirm, Space, Tag, } from 'antd'; import { ActionType, ProDescriptions } from '@ant-design/pro-components'; import { CopyOutlined, DeleteFilled } from '@ant-design/icons'; // 服务器 API 引用(保持与原 index.tsx 一致) import { ordercontrollerChangestatus, ordercontrollerGetorderdetail, ordercontrollerSyncorderbyid, } from '@/servers/api/order'; import { logisticscontrollerDelshipment } from '@/servers/api/logistics'; import { sitecontrollerAll } from '@/servers/api/site'; // 工具与子组件 import { formatShipmentState, formatSource } from '@/utils/format'; import RelatedOrders from './RelatedOrders'; import { ORDER_STATUS_ENUM } from '@/constants'; // 中文注释:为保持原文件结构简单,此处从 index.tsx 引入的子组件仍由原文件导出或保持原状 // 若后续需要彻底解耦,可将 OrderNote / Shipping / SalesChange 也独立到文件 // 当前按你的要求仅抽离详情 Drawer type OrderRecord = API.Order; interface OrderDetailDrawerProps { tableRef: React.MutableRefObject; // 中文注释:列表刷新引用 orderId: number; // 中文注释:订单主键 ID record: OrderRecord; // 中文注释:订单行记录 open: boolean; // 中文注释:是否打开抽屉 onClose: () => void; // 中文注释:关闭抽屉回调 setActiveLine: (id: number) => void; // 中文注释:高亮当前行 OrderNoteComponent: React.ComponentType; // 中文注释:备注组件(从外部注入) SalesChangeComponent: React.ComponentType; // 中文注释:换货组件(从外部注入) } const OrderDetailDrawer: React.FC = ({ tableRef, orderId, record, open, onClose, setActiveLine, OrderNoteComponent, SalesChangeComponent, }) => { const { message } = App.useApp(); const ref = useRef(); // 中文注释:加载详情数据(与 index.tsx 中完全保持一致) const initRequest = async () => { const { data, success }: API.OrderDetailRes = await ordercontrollerGetorderdetail({ orderId }); if (!success || !data) return { data: {} } as any; data.sales = data.sales?.reduce((acc: API.OrderSale[], cur: API.OrderSale) => { const idx = acc.findIndex((v: any) => v.productId === cur.productId); if (idx === -1) acc.push(cur); else acc[idx].quantity += cur.quantity; return acc; }, []); return { data } as any; }; useEffect(() => { if (open && record?.id) { setActiveLine(record.id as number); } }, [open, record?.id]); return ( , ...(['after_sale_pending', 'pending_reshipment'].includes( record.orderStatus, ) ? [] : [ , , ]), ...([ 'processing', 'pending_reshipment', 'completed', 'pending_refund', ].includes(record.orderStatus) ? [ , { try { const { success, message: errMsg } = await ordercontrollerChangestatus( { id: record.id }, { status: 'after_sale_pending' }, ); if (!success) throw new Error(errMsg); tableRef.current?.reload(); } catch (error: any) { message.error(error.message); } }} > , ] : []), ...(record.orderStatus === 'after_sale_pending' ? [ , { try { const { success, message: errMsg } = await ordercontrollerChangestatus( { id: record.id }, { status: 'cancelled' }, ); if (!success) throw new Error(errMsg); tableRef.current?.reload(); } catch (error: any) { message.error(error.message); } }} > , , { try { const { success, message: errMsg } = await ordercontrollerChangestatus( { id: record.id }, { status: 'refund_requested' }, ); if (!success) throw new Error(errMsg); tableRef.current?.reload(); } catch (error: any) { message.error(error.message); } }} > , , { try { const { success, message: errMsg } = await ordercontrollerChangestatus( { id: record.id }, { status: 'completed' }, ); if (!success) throw new Error(errMsg); tableRef.current?.reload(); } catch (error: any) { message.error(error.message); } }} > , ] : []), ]} > { const { data = [] } = await sitecontrollerAll(); return data.map((item) => ({ label: item.siteName, value: item.id })); }} /> (
{r?.shipping?.phone || r?.billing?.phone || '-'}
)} /> formatSource(r.source_type, r.utm_source)} /> (
company:{r?.shipping?.company || r?.billing?.company || '-'}
first_name:{r?.shipping?.first_name || r?.billing?.first_name || '-'}
last_name:{r?.shipping?.last_name || r?.billing?.last_name || '-'}
country:{r?.shipping?.country || r?.billing?.country || '-'}
state:{r?.shipping?.state || r?.billing?.state || '-'}
city:{r?.shipping?.city || r?.billing?.city || '-'}
postcode:{r?.shipping?.postcode || r?.billing?.postcode || '-'}
phone:{r?.shipping?.phone || r?.billing?.phone || '-'}
address_1:{r?.shipping?.address_1 || r?.billing?.address_1 || '-'}
)} /> (
    {(r?.items || []).map((item: any) => (
  • {item.name}:{item.quantity}
  • ))}
)} /> ( )} /> (
    {(r?.sales || []).map((item: any) => (
  • {item.name}:{item.quantity}
  • ))}
)} /> ( )} /> { if (!r.notes || r.notes.length === 0) return (); return (
{r.notes.map((note: any) => (
{note.username} {note.createdAt}
{note.content}
))}
); }} /> { if (!r.shipment || r.shipment.length === 0) return (); return (
{r.shipment.map((v: any) => ( {v.tracking_provider} {v.primary_tracking_number} { try { await navigator.clipboard.writeText(v.tracking_url); message.success('复制成功!'); } catch { message.error('复制失败!'); } }} /> } actions={ (v.state === 'waiting-for-scheduling' || v.state === 'waiting-for-transit') ? [ { try { const { success, message: errMsg } = await logisticscontrollerDelshipment({ id: v.id }); if (!success) throw new Error(errMsg); tableRef.current?.reload(); ref.current?.reload?.(); } catch (error: any) { message.error(error.message); } }}> 取消运单 ] : [] } >
订单号: {Array.isArray(v?.orderIds) ? v.orderIds.join(',') : '-'}
{Array.isArray(v?.items) && v.items.map((item: any) => (
{item.name}: {item.quantity}
))}
))}
); }} />
); }; export default OrderDetailDrawer;