refactor(订单): 重构订单详情抽屉组件并移动相关文件
将订单详情抽屉组件从 Order/List 移动到 Subscription/Orders 目录 提取 RelatedOrders 组件为独立文件 重构订单详情逻辑,保持功能不变但提高可维护性
This commit is contained in:
parent
1ffeff514d
commit
37e999bef9
|
|
@ -1,381 +0,0 @@
|
||||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
|
||||||
import {
|
|
||||||
App,
|
|
||||||
Button,
|
|
||||||
Card,
|
|
||||||
Divider,
|
|
||||||
Drawer,
|
|
||||||
Empty,
|
|
||||||
Popconfirm,
|
|
||||||
Space,
|
|
||||||
Tag,
|
|
||||||
} from 'antd';
|
|
||||||
import { ActionType } from '@ant-design/pro-components';
|
|
||||||
import { CopyOutlined, DownOutlined, FileDoneOutlined } from '@ant-design/icons';
|
|
||||||
|
|
||||||
// 服务器 API 引用(保持与原 index.tsx 一致)
|
|
||||||
import {
|
|
||||||
ordercontrollerChangestatus,
|
|
||||||
ordercontrollerGetorderdetail,
|
|
||||||
ordercontrollerSyncorderbyid,
|
|
||||||
} from '@/servers/api/order';
|
|
||||||
import { logisticscontrollerDelshipment } from '@/servers/api/logistics';
|
|
||||||
|
|
||||||
// 工具与子组件
|
|
||||||
import { formatShipmentState, formatSource } from '@/utils/format';
|
|
||||||
import RelatedOrders from './RelatedOrders';
|
|
||||||
|
|
||||||
// 中文注释:为保持原文件结构简单,此处从 index.tsx 引入的子组件仍由原文件导出或保持原状
|
|
||||||
// 若后续需要彻底解耦,可将 OrderNote / Shipping / SalesChange 也独立到文件
|
|
||||||
// 当前按你的要求仅抽离详情 Drawer
|
|
||||||
|
|
||||||
type OrderRecord = API.Order;
|
|
||||||
|
|
||||||
interface OrderDetailDrawerProps {
|
|
||||||
tableRef: React.MutableRefObject<ActionType | undefined>; // 中文注释:列表刷新引用
|
|
||||||
orderId: number; // 中文注释:订单主键 ID
|
|
||||||
record: OrderRecord; // 中文注释:订单行记录
|
|
||||||
open: boolean; // 中文注释:是否打开抽屉
|
|
||||||
onClose: () => void; // 中文注释:关闭抽屉回调
|
|
||||||
setActiveLine: (id: number) => void; // 中文注释:高亮当前行
|
|
||||||
OrderNoteComponent: React.ComponentType<any>; // 中文注释:备注组件(从外部注入)
|
|
||||||
SalesChangeComponent: React.ComponentType<any>; // 中文注释:换货组件(从外部注入)
|
|
||||||
}
|
|
||||||
|
|
||||||
const OrderDetailDrawer: React.FC<OrderDetailDrawerProps> = ({
|
|
||||||
tableRef,
|
|
||||||
orderId,
|
|
||||||
record,
|
|
||||||
open,
|
|
||||||
onClose,
|
|
||||||
setActiveLine,
|
|
||||||
OrderNoteComponent,
|
|
||||||
SalesChangeComponent,
|
|
||||||
}) => {
|
|
||||||
const { message } = App.useApp();
|
|
||||||
const ref = useRef<ActionType>();
|
|
||||||
const [detail, setDetail] = useState<any | null>(null);
|
|
||||||
|
|
||||||
// 中文注释:加载详情数据(与 index.tsx 中完全保持一致)
|
|
||||||
const initRequest = async () => {
|
|
||||||
const { data, success }: API.OrderDetailRes =
|
|
||||||
await ordercontrollerGetorderdetail({ orderId });
|
|
||||||
if (!success || !data) return null;
|
|
||||||
// 中文注释:销售项合并 SKU,展示数量汇总
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
(async () => {
|
|
||||||
if (open && orderId) {
|
|
||||||
try {
|
|
||||||
const data = await initRequest();
|
|
||||||
setDetail(data);
|
|
||||||
} catch (e) {
|
|
||||||
setDetail(null);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setDetail(null);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
}, [open, orderId]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Drawer
|
|
||||||
title="订单详情"
|
|
||||||
open={open}
|
|
||||||
destroyOnHidden
|
|
||||||
size="large"
|
|
||||||
onClose={onClose}
|
|
||||||
footer={[
|
|
||||||
// 中文注释:备注组件(外部传入以避免循环依赖)
|
|
||||||
<OrderNoteComponent key="order-note" id={orderId} descRef={ref} />,
|
|
||||||
...(['after_sale_pending', 'pending_reshipment'].includes(
|
|
||||||
record.orderStatus,
|
|
||||||
)
|
|
||||||
? []
|
|
||||||
: [
|
|
||||||
<Divider key="divider-sync" type="vertical" />,
|
|
||||||
<Button
|
|
||||||
key="btn-sync"
|
|
||||||
type="primary"
|
|
||||||
onClick={async () => {
|
|
||||||
try {
|
|
||||||
const { success, message: errMsg } =
|
|
||||||
await ordercontrollerSyncorderbyid({
|
|
||||||
siteId: record.siteId as string,
|
|
||||||
orderId: record.externalOrderId as string,
|
|
||||||
});
|
|
||||||
if (!success) throw new Error(errMsg);
|
|
||||||
message.success('同步成功');
|
|
||||||
tableRef.current?.reload();
|
|
||||||
} catch (error) {
|
|
||||||
message.error(error?.message || '同步失败');
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
同步订单
|
|
||||||
</Button>,
|
|
||||||
]),
|
|
||||||
...([
|
|
||||||
'processing',
|
|
||||||
'pending_reshipment',
|
|
||||||
'completed',
|
|
||||||
'pending_refund',
|
|
||||||
].includes(record.orderStatus)
|
|
||||||
? [
|
|
||||||
<Divider key="divider-after-sale" type="vertical" />,
|
|
||||||
<Popconfirm
|
|
||||||
key="btn-after-sale"
|
|
||||||
title="转至售后"
|
|
||||||
description="确认转至售后?"
|
|
||||||
onConfirm={async () => {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Button type="primary" ghost>
|
|
||||||
转至售后
|
|
||||||
</Button>
|
|
||||||
</Popconfirm>,
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
...(record.orderStatus === 'after_sale_pending'
|
|
||||||
? [
|
|
||||||
<Divider key="divider-cancel" type="vertical" />,
|
|
||||||
<Popconfirm
|
|
||||||
key="btn-cancel"
|
|
||||||
title="转至取消"
|
|
||||||
description="确认转至取消?"
|
|
||||||
onConfirm={async () => {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Button type="primary" ghost>
|
|
||||||
转至取消
|
|
||||||
</Button>
|
|
||||||
</Popconfirm>,
|
|
||||||
<Divider key="divider-refund" type="vertical" />,
|
|
||||||
<Popconfirm
|
|
||||||
key="btn-refund"
|
|
||||||
title="转至退款"
|
|
||||||
description="确认转至退款?"
|
|
||||||
onConfirm={async () => {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Button type="primary" ghost>
|
|
||||||
转至退款
|
|
||||||
</Button>
|
|
||||||
</Popconfirm>,
|
|
||||||
<Divider key="divider-completed" type="vertical" />,
|
|
||||||
<Popconfirm
|
|
||||||
key="btn-completed"
|
|
||||||
title="转至完成"
|
|
||||||
description="确认转至完成?"
|
|
||||||
onConfirm={async () => {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Button type="primary" ghost>
|
|
||||||
转至完成
|
|
||||||
</Button>
|
|
||||||
</Popconfirm>,
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
{(() => { setActiveLine(record.id as number); return null; })()}
|
|
||||||
{/** 中文注释:优先使用详情数据,其次使用列表行数据 */}
|
|
||||||
{(() => {
|
|
||||||
const drec: any = detail || record;
|
|
||||||
{/* 中文注释:基本信息展示(保持原有格式) */}
|
|
||||||
return (<>
|
|
||||||
<div style={{ marginBottom: 12 }}>
|
|
||||||
<Space>
|
|
||||||
<Tag>{drec?.orderStatus}</Tag>
|
|
||||||
<Tag>{formatSource(drec.source_type, drec.utm_source)}</Tag>
|
|
||||||
</Space>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 中文注释:原始订单行项目 */}
|
|
||||||
<div style={{ marginBottom: 12 }}>
|
|
||||||
<div style={{ fontWeight: 600, marginBottom: 6 }}>原始订单</div>
|
|
||||||
{Array.isArray((drec as any)?.items) && drec.items.length > 0 ? (
|
|
||||||
<ul>
|
|
||||||
{drec.items.map((item: any) => (
|
|
||||||
<li key={item.id}>
|
|
||||||
{item.name}:{item.quantity}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
) : (
|
|
||||||
<Empty description="暂无数据" />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 中文注释:关联(订阅/订单),使用已存在的 RelatedOrders 组件 */}
|
|
||||||
<div style={{ marginBottom: 12 }}>
|
|
||||||
<div style={{ fontWeight: 600, marginBottom: 6 }}>关联</div>
|
|
||||||
<RelatedOrders data={(drec as any)?.related} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 中文注释:订单内容(销售项) */}
|
|
||||||
<div style={{ marginBottom: 12 }}>
|
|
||||||
<div style={{ fontWeight: 600, marginBottom: 6 }}>订单内容</div>
|
|
||||||
{Array.isArray((drec as any)?.sales) && drec.sales.length > 0 ? (
|
|
||||||
<ul>
|
|
||||||
{drec.sales.map((item: any) => (
|
|
||||||
<li key={item.id}>
|
|
||||||
{item.name}:{item.quantity}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
) : (
|
|
||||||
<Empty description="暂无数据" />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 中文注释:备注 */}
|
|
||||||
<div style={{ marginBottom: 12 }}>
|
|
||||||
<div style={{ fontWeight: 600, marginBottom: 6 }}>备注</div>
|
|
||||||
{Array.isArray((drec as any)?.notes) && drec.notes.length > 0 ? (
|
|
||||||
<div style={{ width: '100%' }}>
|
|
||||||
{drec.notes.map((note: any) => (
|
|
||||||
<div style={{ marginBottom: 10 }} key={note.id}>
|
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
|
||||||
<span>{note.username}</span>
|
|
||||||
<span>{note.createdAt}</span>
|
|
||||||
</div>
|
|
||||||
<div>{note.content}</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<Empty description="暂无备注" />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 中文注释:物流信息 */}
|
|
||||||
<div style={{ marginBottom: 12 }}>
|
|
||||||
<div style={{ fontWeight: 600, marginBottom: 6 }}>物流信息</div>
|
|
||||||
{Array.isArray((drec as any)?.shipment) && drec.shipment.length > 0 ? (
|
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', width: '100%' }}>
|
|
||||||
{(drec as any).shipment.map((v: any) => (
|
|
||||||
<Card
|
|
||||||
key={v.id}
|
|
||||||
style={{ marginBottom: '10px' }}
|
|
||||||
extra={formatShipmentState(v.state)}
|
|
||||||
title={
|
|
||||||
<>
|
|
||||||
{v.tracking_provider}
|
|
||||||
{v.primary_tracking_number}
|
|
||||||
<CopyOutlined
|
|
||||||
onClick={async () => {
|
|
||||||
try {
|
|
||||||
await navigator.clipboard.writeText(v.tracking_url);
|
|
||||||
message.success('复制成功!');
|
|
||||||
} catch (err) {
|
|
||||||
message.error('复制失败!');
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
actions={
|
|
||||||
v.state === 'waiting-for-scheduling' || v.state === 'waiting-for-transit'
|
|
||||||
? [
|
|
||||||
<Popconfirm
|
|
||||||
key="action-cancel"
|
|
||||||
title="取消运单"
|
|
||||||
description="确认取消运单?"
|
|
||||||
onConfirm={async () => {
|
|
||||||
try {
|
|
||||||
const { success, message: errMsg } = await logisticscontrollerDelshipment({ id: v.id });
|
|
||||||
if (!success) throw new Error(errMsg);
|
|
||||||
tableRef.current?.reload();
|
|
||||||
} catch (error: any) {
|
|
||||||
message.error(error.message);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
取消运单
|
|
||||||
</Popconfirm>,
|
|
||||||
]
|
|
||||||
: []
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div>订单号: {Array.isArray(v?.orderIds) ? v.orderIds.join(',') : '-'}</div>
|
|
||||||
{Array.isArray(v?.items) &&
|
|
||||||
v.items.map((item: any) => (
|
|
||||||
<div key={item.id}>
|
|
||||||
{item.name}: {item.quantity}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</Card>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<Empty description="暂无物流信息" />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 中文注释:换货(外部传入组件) */}
|
|
||||||
<div style={{ marginBottom: 12 }}>
|
|
||||||
<SalesChangeComponent detailRef={ref} id={drec.id as number} />
|
|
||||||
</div>
|
|
||||||
</>);
|
|
||||||
})()}
|
|
||||||
</Drawer>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default OrderDetailDrawer;
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import { Empty, Tag } from 'antd';
|
|
||||||
import dayjs from 'dayjs';
|
|
||||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
|
||||||
|
|
||||||
dayjs.extend(relativeTime);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RelatedOrders 表格组件
|
|
||||||
* 用于展示订单详情中的关联数据(订阅/订单),按统一表格样式渲染
|
|
||||||
* 中文注释:本组件将订阅与订单统一归一化为五列展示,便于快速浏览
|
|
||||||
*/
|
|
||||||
const RelatedOrders: React.FC<{ data?: any[] }> = ({ data = [] }) => {
|
|
||||||
const rows = (Array.isArray(data) ? data : []).map((it: any) => {
|
|
||||||
const isSubscription = !!it?.externalSubscriptionId || !!it?.billing_period || !!it?.line_items;
|
|
||||||
const number = isSubscription ? `#${it?.externalSubscriptionId || it?.id}` : `#${it?.externalOrderId || it?.id}`;
|
|
||||||
const relationship = isSubscription ? 'Subscription' : 'Order';
|
|
||||||
const dateRaw = it?.start_date || it?.date_created || it?.createdAt || it?.updatedAt;
|
|
||||||
const dateText = dateRaw ? dayjs(dateRaw).fromNow() : '-';
|
|
||||||
const status = (isSubscription ? it?.status : it?.orderStatus) || '-';
|
|
||||||
const statusLower = String(status).toLowerCase();
|
|
||||||
const color = statusLower === 'active' ? 'green' : statusLower === 'cancelled' ? 'red' : 'default';
|
|
||||||
const totalNum = Number(it?.total || 0);
|
|
||||||
const totalText = isSubscription ? `$${totalNum.toFixed(2)} / ${it?.billing_period || 'period'}` : `$${totalNum.toFixed(2)}`;
|
|
||||||
return { key: `${isSubscription ? 'sub' : 'order'}-${it?.id}`, number, relationship, dateText, status, color, totalText };
|
|
||||||
});
|
|
||||||
|
|
||||||
if (rows.length === 0) return <Empty description="暂无关联" />;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ width: '100%' }}>
|
|
||||||
{/* 表头(英文文案,符合国际化默认英文的要求) */}
|
|
||||||
<div style={{ display: 'grid', gridTemplateColumns: '1.5fr 1fr 1fr 1fr 1fr', padding: '8px 0', fontWeight: 600 }}>
|
|
||||||
<div>订单编号</div>
|
|
||||||
<div>关系</div>
|
|
||||||
<div>日期</div>
|
|
||||||
<div>状态</div>
|
|
||||||
<div>金额</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{rows.map((r) => (
|
|
||||||
<div key={r.key} style={{ display: 'grid', gridTemplateColumns: '1.5fr 1fr 1fr 1fr 1fr', padding: '6px 0', borderTop: '1px solid #f0f0f0' }}>
|
|
||||||
<div><a>{r.number}</a></div>
|
|
||||||
<div>{r.relationship}</div>
|
|
||||||
<div style={{ color: '#1677ff' }}>{r.dateText}</div>
|
|
||||||
<div><Tag color={r.color}>{r.status}</Tag></div>
|
|
||||||
<div>{r.totalText}</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default RelatedOrders;
|
|
||||||
|
|
@ -81,6 +81,7 @@ import {
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import Item from 'antd/es/list/Item';
|
import Item from 'antd/es/list/Item';
|
||||||
<<<<<<< HEAD
|
<<<<<<< HEAD
|
||||||
|
<<<<<<< HEAD
|
||||||
import RelatedOrders from '../../Subscription/Orders/RelatedOrders';
|
import RelatedOrders from '../../Subscription/Orders/RelatedOrders';
|
||||||
=======
|
=======
|
||||||
import RelatedOrders from './RelatedOrders';
|
import RelatedOrders from './RelatedOrders';
|
||||||
|
|
@ -89,6 +90,9 @@ import RelatedOrders from './RelatedOrders';
|
||||||
=======
|
=======
|
||||||
import OrderDetailDrawer from './OrderDetailDrawer';
|
import OrderDetailDrawer from './OrderDetailDrawer';
|
||||||
>>>>>>> 1f4128f (refactor(订单): 抽离订单详情抽屉为独立组件并复用)
|
>>>>>>> 1f4128f (refactor(订单): 抽离订单详情抽屉为独立组件并复用)
|
||||||
|
=======
|
||||||
|
import RelatedOrders from '../../Subscription/Orders/RelatedOrders';
|
||||||
|
>>>>>>> d98e843 (refactor(订单): 重构订单详情抽屉组件并移动相关文件)
|
||||||
import React, { useMemo, useRef, useState } from 'react';
|
import React, { useMemo, useRef, useState } from 'react';
|
||||||
import { printPDF } from '@/utils/util';
|
import { printPDF } from '@/utils/util';
|
||||||
|
|
||||||
|
|
@ -97,9 +101,6 @@ const ListPage: React.FC = () => {
|
||||||
const [activeKey, setActiveKey] = useState<string>('all');
|
const [activeKey, setActiveKey] = useState<string>('all');
|
||||||
const [count, setCount] = useState<any[]>([]);
|
const [count, setCount] = useState<any[]>([]);
|
||||||
const [activeLine, setActiveLine] = useState<number>(-1);
|
const [activeLine, setActiveLine] = useState<number>(-1);
|
||||||
const [detailOpen, setDetailOpen] = useState(false);
|
|
||||||
const [detailRecord, setDetailRecord] = useState<any | null>(null);
|
|
||||||
const [detailOrderId, setDetailOrderId] = useState<number | null>(null);
|
|
||||||
const tabs: TabsProps['items'] = useMemo(() => {
|
const tabs: TabsProps['items'] = useMemo(() => {
|
||||||
const total = count.reduce((acc, cur) => acc + Number(cur.count), 0);
|
const total = count.reduce((acc, cur) => acc + Number(cur.count), 0);
|
||||||
const tabs = [
|
const tabs = [
|
||||||
|
|
@ -323,31 +324,13 @@ const ListPage: React.FC = () => {
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
)}
|
)}
|
||||||
<Button
|
<Detail
|
||||||
key={record.id}
|
key={record.id}
|
||||||
type="primary"
|
record={record}
|
||||||
onClick={() => {
|
|
||||||
setDetailRecord(record);
|
|
||||||
setDetailOrderId(record.id as number);
|
|
||||||
setDetailOpen(true);
|
|
||||||
setActiveLine(record.id);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FileDoneOutlined />
|
|
||||||
详情
|
|
||||||
</Button>
|
|
||||||
{detailRecord && detailOrderId !== null && (
|
|
||||||
<OrderDetailDrawer
|
|
||||||
open={detailOpen}
|
|
||||||
onClose={() => setDetailOpen(false)}
|
|
||||||
tableRef={actionRef}
|
tableRef={actionRef}
|
||||||
orderId={detailOrderId as number}
|
orderId={record.id as number}
|
||||||
record={detailRecord as any}
|
|
||||||
setActiveLine={setActiveLine}
|
setActiveLine={setActiveLine}
|
||||||
OrderNoteComponent={OrderNote}
|
|
||||||
SalesChangeComponent={SalesChange}
|
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
<Divider type="vertical" />
|
<Divider type="vertical" />
|
||||||
<Dropdown
|
<Dropdown
|
||||||
menu={{
|
menu={{
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,11 @@ import {
|
||||||
import { ActionType, ProDescriptions } from '@ant-design/pro-components';
|
import { ActionType, ProDescriptions } from '@ant-design/pro-components';
|
||||||
import { CopyOutlined, DeleteFilled } from '@ant-design/icons';
|
import { CopyOutlined, DeleteFilled } from '@ant-design/icons';
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
// 服务器 API 引用(保持与原 index.tsx 一致)
|
// 服务器 API 引用(保持与原 index.tsx 一致)
|
||||||
|
=======
|
||||||
|
// 服务器 API 引用(保持与原 index.tsx 一致)
|
||||||
|
>>>>>>> d98e843 (refactor(订单): 重构订单详情抽屉组件并移动相关文件)
|
||||||
import {
|
import {
|
||||||
ordercontrollerChangestatus,
|
ordercontrollerChangestatus,
|
||||||
ordercontrollerGetorderdetail,
|
ordercontrollerGetorderdetail,
|
||||||
|
|
@ -27,13 +31,18 @@ import { formatShipmentState, formatSource } from '@/utils/format';
|
||||||
import RelatedOrders from './RelatedOrders';
|
import RelatedOrders from './RelatedOrders';
|
||||||
import { ORDER_STATUS_ENUM } from '@/constants';
|
import { ORDER_STATUS_ENUM } from '@/constants';
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
// 中文注释:为保持原文件结构简单,此处从 index.tsx 引入的子组件仍由原文件导出或保持原状
|
// 中文注释:为保持原文件结构简单,此处从 index.tsx 引入的子组件仍由原文件导出或保持原状
|
||||||
|
=======
|
||||||
|
// 中文注释:为保持原文件结构简单,此处从 index.tsx 引入的子组件仍由原文件导出或保持原状
|
||||||
|
>>>>>>> d98e843 (refactor(订单): 重构订单详情抽屉组件并移动相关文件)
|
||||||
// 若后续需要彻底解耦,可将 OrderNote / Shipping / SalesChange 也独立到文件
|
// 若后续需要彻底解耦,可将 OrderNote / Shipping / SalesChange 也独立到文件
|
||||||
// 当前按你的要求仅抽离详情 Drawer
|
// 当前按你的要求仅抽离详情 Drawer
|
||||||
|
|
||||||
type OrderRecord = API.Order;
|
type OrderRecord = API.Order;
|
||||||
|
|
||||||
interface OrderDetailDrawerProps {
|
interface OrderDetailDrawerProps {
|
||||||
|
<<<<<<< HEAD
|
||||||
tableRef: React.MutableRefObject<ActionType | undefined>; // 中文注释:列表刷新引用
|
tableRef: React.MutableRefObject<ActionType | undefined>; // 中文注释:列表刷新引用
|
||||||
orderId: number; // 中文注释:订单主键 ID
|
orderId: number; // 中文注释:订单主键 ID
|
||||||
record: OrderRecord; // 中文注释:订单行记录
|
record: OrderRecord; // 中文注释:订单行记录
|
||||||
|
|
@ -42,6 +51,16 @@ interface OrderDetailDrawerProps {
|
||||||
setActiveLine: (id: number) => void; // 中文注释:高亮当前行
|
setActiveLine: (id: number) => void; // 中文注释:高亮当前行
|
||||||
OrderNoteComponent: React.ComponentType<any>; // 中文注释:备注组件(从外部注入)
|
OrderNoteComponent: React.ComponentType<any>; // 中文注释:备注组件(从外部注入)
|
||||||
SalesChangeComponent: React.ComponentType<any>; // 中文注释:换货组件(从外部注入)
|
SalesChangeComponent: React.ComponentType<any>; // 中文注释:换货组件(从外部注入)
|
||||||
|
=======
|
||||||
|
tableRef: React.MutableRefObject<ActionType | undefined>; // 中文注释:列表刷新引用
|
||||||
|
orderId: number; // 中文注释:订单主键 ID
|
||||||
|
record: OrderRecord; // 中文注释:订单行记录
|
||||||
|
open: boolean; // 中文注释:是否打开抽屉
|
||||||
|
onClose: () => void; // 中文注释:关闭抽屉回调
|
||||||
|
setActiveLine: (id: number) => void; // 中文注释:高亮当前行
|
||||||
|
OrderNoteComponent: React.ComponentType<any>; // 中文注释:备注组件(从外部注入)
|
||||||
|
SalesChangeComponent: React.ComponentType<any>; // 中文注释:换货组件(从外部注入)
|
||||||
|
>>>>>>> d98e843 (refactor(订单): 重构订单详情抽屉组件并移动相关文件)
|
||||||
}
|
}
|
||||||
|
|
||||||
const OrderDetailDrawer: React.FC<OrderDetailDrawerProps> = ({
|
const OrderDetailDrawer: React.FC<OrderDetailDrawerProps> = ({
|
||||||
|
|
@ -57,7 +76,11 @@ const OrderDetailDrawer: React.FC<OrderDetailDrawerProps> = ({
|
||||||
const { message } = App.useApp();
|
const { message } = App.useApp();
|
||||||
const ref = useRef<ActionType>();
|
const ref = useRef<ActionType>();
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
// 中文注释:加载详情数据(与 index.tsx 中完全保持一致)
|
// 中文注释:加载详情数据(与 index.tsx 中完全保持一致)
|
||||||
|
=======
|
||||||
|
// 中文注释:加载详情数据(与 index.tsx 中完全保持一致)
|
||||||
|
>>>>>>> d98e843 (refactor(订单): 重构订单详情抽屉组件并移动相关文件)
|
||||||
const initRequest = async () => {
|
const initRequest = async () => {
|
||||||
const { data, success }: API.OrderDetailRes = await ordercontrollerGetorderdetail({ orderId });
|
const { data, success }: API.OrderDetailRes = await ordercontrollerGetorderdetail({ orderId });
|
||||||
if (!success || !data) return { data: {} } as any;
|
if (!success || !data) return { data: {} } as any;
|
||||||
|
|
@ -84,7 +107,11 @@ const OrderDetailDrawer: React.FC<OrderDetailDrawerProps> = ({
|
||||||
size="large"
|
size="large"
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
footer={[
|
footer={[
|
||||||
|
<<<<<<< HEAD
|
||||||
// 中文注释:备注组件(外部传入以避免循环依赖)
|
// 中文注释:备注组件(外部传入以避免循环依赖)
|
||||||
|
=======
|
||||||
|
// 中文注释:备注组件(外部传入以避免循环依赖)
|
||||||
|
>>>>>>> d98e843 (refactor(订单): 重构订单详情抽屉组件并移动相关文件)
|
||||||
<OrderNoteComponent key="order-note" id={orderId} descRef={ref} />,
|
<OrderNoteComponent key="order-note" id={orderId} descRef={ref} />,
|
||||||
...(['after_sale_pending', 'pending_reshipment'].includes(
|
...(['after_sale_pending', 'pending_reshipment'].includes(
|
||||||
record.orderStatus,
|
record.orderStatus,
|
||||||
|
|
@ -241,6 +268,7 @@ const OrderDetailDrawer: React.FC<OrderDetailDrawerProps> = ({
|
||||||
<ProDescriptions.Item label="客户备注" dataIndex="customer_note" span={3} />
|
<ProDescriptions.Item label="客户备注" dataIndex="customer_note" span={3} />
|
||||||
<ProDescriptions.Item label="发货信息" span={3} render={(_, r: any) => (
|
<ProDescriptions.Item label="发货信息" span={3} render={(_, r: any) => (
|
||||||
<div>
|
<div>
|
||||||
|
<<<<<<< HEAD
|
||||||
<div>company:<span>{r?.shipping?.company || r?.billing?.company || '-'}</span></div>
|
<div>company:<span>{r?.shipping?.company || r?.billing?.company || '-'}</span></div>
|
||||||
<div>first_name:<span>{r?.shipping?.first_name || r?.billing?.first_name || '-'}</span></div>
|
<div>first_name:<span>{r?.shipping?.first_name || r?.billing?.first_name || '-'}</span></div>
|
||||||
<div>last_name:<span>{r?.shipping?.last_name || r?.billing?.last_name || '-'}</span></div>
|
<div>last_name:<span>{r?.shipping?.last_name || r?.billing?.last_name || '-'}</span></div>
|
||||||
|
|
@ -250,12 +278,27 @@ const OrderDetailDrawer: React.FC<OrderDetailDrawerProps> = ({
|
||||||
<div>postcode:<span>{r?.shipping?.postcode || r?.billing?.postcode || '-'}</span></div>
|
<div>postcode:<span>{r?.shipping?.postcode || r?.billing?.postcode || '-'}</span></div>
|
||||||
<div>phone:<span>{r?.shipping?.phone || r?.billing?.phone || '-'}</span></div>
|
<div>phone:<span>{r?.shipping?.phone || r?.billing?.phone || '-'}</span></div>
|
||||||
<div>address_1:<span>{r?.shipping?.address_1 || r?.billing?.address_1 || '-'}</span></div>
|
<div>address_1:<span>{r?.shipping?.address_1 || r?.billing?.address_1 || '-'}</span></div>
|
||||||
|
=======
|
||||||
|
<div>company:<span>{r?.shipping?.company || r?.billing?.company || '-'}</span></div>
|
||||||
|
<div>first_name:<span>{r?.shipping?.first_name || r?.billing?.first_name || '-'}</span></div>
|
||||||
|
<div>last_name:<span>{r?.shipping?.last_name || r?.billing?.last_name || '-'}</span></div>
|
||||||
|
<div>country:<span>{r?.shipping?.country || r?.billing?.country || '-'}</span></div>
|
||||||
|
<div>state:<span>{r?.shipping?.state || r?.billing?.state || '-'}</span></div>
|
||||||
|
<div>city:<span>{r?.shipping?.city || r?.billing?.city || '-'}</span></div>
|
||||||
|
<div>postcode:<span>{r?.shipping?.postcode || r?.billing?.postcode || '-'}</span></div>
|
||||||
|
<div>phone:<span>{r?.shipping?.phone || r?.billing?.phone || '-'}</span></div>
|
||||||
|
<div>address_1:<span>{r?.shipping?.address_1 || r?.billing?.address_1 || '-'}</span></div>
|
||||||
|
>>>>>>> d98e843 (refactor(订单): 重构订单详情抽屉组件并移动相关文件)
|
||||||
</div>
|
</div>
|
||||||
)} />
|
)} />
|
||||||
<ProDescriptions.Item label="原始订单" span={3} render={(_, r: any) => (
|
<ProDescriptions.Item label="原始订单" span={3} render={(_, r: any) => (
|
||||||
<ul>
|
<ul>
|
||||||
{(r?.items || []).map((item: any) => (
|
{(r?.items || []).map((item: any) => (
|
||||||
|
<<<<<<< HEAD
|
||||||
<li key={item.id}>{item.name}:{item.quantity}</li>
|
<li key={item.id}>{item.name}:{item.quantity}</li>
|
||||||
|
=======
|
||||||
|
<li key={item.id}>{item.name}:{item.quantity}</li>
|
||||||
|
>>>>>>> d98e843 (refactor(订单): 重构订单详情抽屉组件并移动相关文件)
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
)} />
|
)} />
|
||||||
|
|
@ -265,7 +308,11 @@ const OrderDetailDrawer: React.FC<OrderDetailDrawerProps> = ({
|
||||||
<ProDescriptions.Item label="订单内容" span={3} render={(_, r: any) => (
|
<ProDescriptions.Item label="订单内容" span={3} render={(_, r: any) => (
|
||||||
<ul>
|
<ul>
|
||||||
{(r?.sales || []).map((item: any) => (
|
{(r?.sales || []).map((item: any) => (
|
||||||
|
<<<<<<< HEAD
|
||||||
<li key={item.id}>{item.name}:{item.quantity}</li>
|
<li key={item.id}>{item.name}:{item.quantity}</li>
|
||||||
|
=======
|
||||||
|
<li key={item.id}>{item.name}:{item.quantity}</li>
|
||||||
|
>>>>>>> d98e843 (refactor(订单): 重构订单详情抽屉组件并移动相关文件)
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
)} />
|
)} />
|
||||||
|
|
@ -310,7 +357,11 @@ const OrderDetailDrawer: React.FC<OrderDetailDrawerProps> = ({
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
] : [] }
|
] : [] }
|
||||||
>
|
>
|
||||||
|
<<<<<<< HEAD
|
||||||
<div>订单号: {Array.isArray(v?.orderIds) ? v.orderIds.join(',') : '-'}</div>
|
<div>订单号: {Array.isArray(v?.orderIds) ? v.orderIds.join(',') : '-'}</div>
|
||||||
|
=======
|
||||||
|
<div>订单号: {Array.isArray(v?.orderIds) ? v.orderIds.join(',') : '-'}</div>
|
||||||
|
>>>>>>> d98e843 (refactor(订单): 重构订单详情抽屉组件并移动相关文件)
|
||||||
{Array.isArray(v?.items) && v.items.map((item: any) => (
|
{Array.isArray(v?.items) && v.items.map((item: any) => (
|
||||||
<div key={item.id}>{item.name}: {item.quantity}</div>
|
<div key={item.id}>{item.name}: {item.quantity}</div>
|
||||||
))}
|
))}
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,13 @@ dayjs.extend(relativeTime);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RelatedOrders 表格组件
|
* RelatedOrders 表格组件
|
||||||
|
<<<<<<< HEAD
|
||||||
* 用于展示订单详情中的关联数据(订阅/订单),按统一表格样式渲染
|
* 用于展示订单详情中的关联数据(订阅/订单),按统一表格样式渲染
|
||||||
* 中文注释:本组件将订阅与订单统一归一化为五列展示,便于快速浏览
|
* 中文注释:本组件将订阅与订单统一归一化为五列展示,便于快速浏览
|
||||||
|
=======
|
||||||
|
* 用于展示订单详情中的关联数据(订阅/订单),按统一表格样式渲染
|
||||||
|
* 中文注释:本组件将订阅与订单统一归一化为五列展示,便于快速浏览
|
||||||
|
>>>>>>> d98e843 (refactor(订单): 重构订单详情抽屉组件并移动相关文件)
|
||||||
*/
|
*/
|
||||||
const RelatedOrders: React.FC<{ data?: any[] }> = ({ data = [] }) => {
|
const RelatedOrders: React.FC<{ data?: any[] }> = ({ data = [] }) => {
|
||||||
const rows = (Array.isArray(data) ? data : []).map((it: any) => {
|
const rows = (Array.isArray(data) ? data : []).map((it: any) => {
|
||||||
|
|
@ -29,7 +34,11 @@ const RelatedOrders: React.FC<{ data?: any[] }> = ({ data = [] }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ width: '100%' }}>
|
<div style={{ width: '100%' }}>
|
||||||
|
<<<<<<< HEAD
|
||||||
{/* 表头(英文文案,符合国际化默认英文的要求) */}
|
{/* 表头(英文文案,符合国际化默认英文的要求) */}
|
||||||
|
=======
|
||||||
|
{/* 表头(英文文案,符合国际化默认英文的要求) */}
|
||||||
|
>>>>>>> d98e843 (refactor(订单): 重构订单详情抽屉组件并移动相关文件)
|
||||||
<div style={{ display: 'grid', gridTemplateColumns: '1.5fr 1fr 1fr 1fr 1fr', padding: '8px 0', fontWeight: 600 }}>
|
<div style={{ display: 'grid', gridTemplateColumns: '1.5fr 1fr 1fr 1fr 1fr', padding: '8px 0', fontWeight: 600 }}>
|
||||||
<div>订单编号</div>
|
<div>订单编号</div>
|
||||||
<div>关系</div>
|
<div>关系</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue