Compare commits

...

7 Commits

Author SHA1 Message Date
tikkhun 3129b9f281 style: 统一中文标点符号为英文格式 2025-11-25 10:07:27 +08:00
tikkhun ea9c95c72f refactor(Subscription/Orders): 使用相对路径导入OrderDetailDrawer组件 2025-11-25 10:06:50 +08:00
tikkhun 37e999bef9 refactor(订单): 重构订单详情抽屉组件并移动相关文件
将订单详情抽屉组件从 Order/List 移动到 Subscription/Orders 目录
提取 RelatedOrders 组件为独立文件
重构订单详情逻辑,保持功能不变但提高可维护性
2025-11-25 10:06:35 +08:00
tikkhun 1ffeff514d refactor(订单): 抽离订单详情抽屉为独立组件并复用
将订单列表页的详情抽屉抽离为独立组件 OrderDetailDrawer
在订阅订单页面复用该组件,替换原有实现
2025-11-25 10:06:19 +08:00
tikkhun 66ba46e4d0 feat(订单列表): 添加关联订单组件并优化订阅显示
添加 RelatedOrders 组件用于统一展示关联订单和订阅信息
在订单列表中增加订阅标签显示
移除未使用的 request 导入
2025-11-25 10:05:37 +08:00
tikkhun 67b5684025 feat(订单): 添加关联订单显示功能并创建订单商品和订阅订单页面
feat(订阅): 增加订阅订单关联功能及详情查看
feat(商品): 新增订单商品概览页面
style(订单): 优化订单详情显示格式
2025-11-25 10:04:58 +08:00
tikkhun a6e569c50b refactor(docs): 移除旧版项目文档和优化订单状态标签
删除不再使用的项目文档中心和相关技术文档
在订单列表页面添加退款状态标签的空行以改善代码可读性
2025-11-25 10:01:13 +08:00
6 changed files with 388 additions and 0 deletions

View File

@ -7,6 +7,8 @@ import dayjs from 'dayjs';
import { ordercontrollerGetordersales } from '@/servers/api/order'; import { ordercontrollerGetordersales } from '@/servers/api/order';
import { sitecontrollerAll } from '@/servers/api/site'; import { sitecontrollerAll } from '@/servers/api/site';
<<<<<<< HEAD
<<<<<<< HEAD
// 列表行数据结构(订单商品聚合) // 列表行数据结构(订单商品聚合)
interface OrderItemAggRow { interface OrderItemAggRow {
externalProductId: number; // 商品ID(来自 WooCommerce 产品ID) externalProductId: number; // 商品ID(来自 WooCommerce 产品ID)
@ -18,13 +20,46 @@ interface OrderItemAggRow {
secondOrderCount: number; // 客户第二次购买次数(该商品) secondOrderCount: number; // 客户第二次购买次数(该商品)
thirdOrderCount: number; // 客户第三次购买次数(该商品) thirdOrderCount: number; // 客户第三次购买次数(该商品)
moreThirdOrderCount: number; // 客户超过三次购买次数(该商品) moreThirdOrderCount: number; // 客户超过三次购买次数(该商品)
=======
// 列表行数据结构(订单商品聚合)
=======
// 列表行数据结构(订单商品聚合)
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
interface OrderItemAggRow {
externalProductId: number; // 商品ID(来自 WooCommerce 产品ID)
externalVariationId: number; // 变体ID(来自 WooCommerce 变体ID)
name: string; // 商品名称
<<<<<<< HEAD
totalQuantity: number; // 总售出数量(时间范围内)
totalOrders: number; // 涉及订单数(去重)
firstOrderCount: number; // 客户首单次数(该商品)
secondOrderCount: number; // 客户第二次购买次数(该商品)
thirdOrderCount: number; // 客户第三次购买次数(该商品)
moreThirdOrderCount: number; // 客户超过三次购买次数(该商品)
>>>>>>> 90ea0f5 (feat(): )
=======
totalQuantity: number; // 总售出数量(时间范围内)
totalOrders: number; // 涉及订单数(去重)
firstOrderCount: number; // 客户首单次数(该商品)
secondOrderCount: number; // 客户第二次购买次数(该商品)
thirdOrderCount: number; // 客户第三次购买次数(该商品)
moreThirdOrderCount: number; // 客户超过三次购买次数(该商品)
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
} }
const OrderItemsPage: React.FC = () => { const OrderItemsPage: React.FC = () => {
const actionRef = useRef<ActionType>(); const actionRef = useRef<ActionType>();
const { message } = App.useApp(); const { message } = App.useApp();
<<<<<<< HEAD
<<<<<<< HEAD
// 列配置(中文标题,符合当前项目风格;显示英文默认语言可后续走国际化) // 列配置(中文标题,符合当前项目风格;显示英文默认语言可后续走国际化)
=======
// 列配置(中文标题,符合当前项目风格;显示英文默认语言可后续走国际化)
>>>>>>> 90ea0f5 (feat(): )
=======
// 列配置(中文标题,符合当前项目风格;显示英文默认语言可后续走国际化)
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
const columns: ProColumns<OrderItemAggRow>[] = [ const columns: ProColumns<OrderItemAggRow>[] = [
{ {
title: '商品名称', title: '商品名称',
@ -85,7 +120,15 @@ const OrderItemsPage: React.FC = () => {
dataIndex: 'siteId', dataIndex: 'siteId',
valueType: 'select', valueType: 'select',
request: async () => { request: async () => {
<<<<<<< HEAD
<<<<<<< HEAD
// 拉取站点列表(后台 /site/all) // 拉取站点列表(后台 /site/all)
=======
// 拉取站点列表(后台 /site/all
>>>>>>> 90ea0f5 (feat(): )
=======
// 拉取站点列表(后台 /site/all)
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
const { data = [] } = await sitecontrollerAll(); const { data = [] } = await sitecontrollerAll();
return (data || []).map((item: any) => ({ label: item.siteName, value: item.id })); return (data || []).map((item: any) => ({ label: item.siteName, value: item.id }));
}, },
@ -103,12 +146,28 @@ const OrderItemsPage: React.FC = () => {
}, },
]; ];
<<<<<<< HEAD
<<<<<<< HEAD
// 表格请求方法:调用 /order/getOrderSales 接口并设置 isSource=true 获取订单项聚合 // 表格请求方法:调用 /order/getOrderSales 接口并设置 isSource=true 获取订单项聚合
=======
// 表格请求方法:调用 /order/getOrderSales 接口并设置 isSource=true 获取订单项聚合
>>>>>>> 90ea0f5 (feat(): )
=======
// 表格请求方法:调用 /order/getOrderSales 接口并设置 isSource=true 获取订单项聚合
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
const request: ProTableProps<OrderItemAggRow>['request'] = async (params:any) => { const request: ProTableProps<OrderItemAggRow>['request'] = async (params:any) => {
try { try {
const { current = 1, pageSize = 10, siteId, name } = params as any; const { current = 1, pageSize = 10, siteId, name } = params as any;
const [startDate, endDate] = (params as any).dateRange || []; const [startDate, endDate] = (params as any).dateRange || [];
<<<<<<< HEAD
<<<<<<< HEAD
// 调用后端接口(isSource=true 表示按订单项聚合) // 调用后端接口(isSource=true 表示按订单项聚合)
=======
// 调用后端接口isSource=true 表示按订单项聚合)
>>>>>>> 90ea0f5 (feat(): )
=======
// 调用后端接口(isSource=true 表示按订单项聚合)
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
const resp = await ordercontrollerGetordersales({ const resp = await ordercontrollerGetordersales({
current, current,
pageSize, pageSize,

View File

@ -80,7 +80,19 @@ import {
Tag, Tag,
} from 'antd'; } from 'antd';
import Item from 'antd/es/list/Item'; import Item from 'antd/es/list/Item';
<<<<<<< HEAD
<<<<<<< HEAD
import RelatedOrders from '../../Subscription/Orders/RelatedOrders'; import RelatedOrders from '../../Subscription/Orders/RelatedOrders';
=======
import RelatedOrders from './RelatedOrders';
<<<<<<< HEAD
>>>>>>> 43be89b (feat(): )
=======
import OrderDetailDrawer from './OrderDetailDrawer';
>>>>>>> 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';
@ -902,13 +914,40 @@ const Detail: React.FC<{
<ul> <ul>
{record?.items?.map((item: any) => ( {record?.items?.map((item: any) => (
<li key={item.id}> <li key={item.id}>
<<<<<<< HEAD
<<<<<<< HEAD
{item.name}:{item.quantity} {item.name}:{item.quantity}
=======
{item.name}{item.quantity}
=======
{item.name}:{item.quantity}
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
</li> </li>
))} ))}
</ul> </ul>
); );
}} }}
/> />
<<<<<<< HEAD
{/* TODO 显示 related order */}
<ProDescriptions.Item
label="关联订单"
span={3}
render={(_, record) => {
return (
<ul>
{record?.related?.map((item: any) => (
<li key={item.id}>
{JSON.stringify(item)}
>>>>>>> 90ea0f5 (feat(): )
</li>
))}
</ul>
);
}}
/>
=======
>>>>>>> 43be89b (feat(): )
{/* 显示 related order */} {/* 显示 related order */}
<ProDescriptions.Item <ProDescriptions.Item
label="关联" label="关联"

View File

@ -35,6 +35,14 @@ const ListPage: React.FC = () => {
// 表格操作引用:用于在同步后触发表格刷新 // 表格操作引用:用于在同步后触发表格刷新
const actionRef = useRef<ActionType>(); const actionRef = useRef<ActionType>();
const { message } = App.useApp(); const { message } = App.useApp();
<<<<<<< HEAD
=======
// 关联订单抽屉状态
const [drawerOpen, setDrawerOpen] = useState(false);
const [drawerTitle, setDrawerTitle] = useState('详情');
const [relatedOrders, setRelatedOrders] = useState<any[]>([]);
>>>>>>> 90ea0f5 (feat(): )
// 关联订单抽屉状态 // 关联订单抽屉状态
const [drawerOpen, setDrawerOpen] = useState(false); const [drawerOpen, setDrawerOpen] = useState(false);
@ -144,14 +152,30 @@ const ListPage: React.FC = () => {
message.warning('该订阅缺少父订单号'); message.warning('该订阅缺少父订单号');
return; return;
} }
<<<<<<< HEAD
<<<<<<< HEAD
// 通过父订单号查询关联订单(模糊匹配) // 通过父订单号查询关联订单(模糊匹配)
=======
// 通过父订单号查询关联订单(模糊匹配)
>>>>>>> 90ea0f5 (feat(): )
=======
// 通过父订单号查询关联订单(模糊匹配)
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
const resp = await request('/order/getOrderByNumber', { const resp = await request('/order/getOrderByNumber', {
method: 'POST', method: 'POST',
data: { number: parentNumber }, data: { number: parentNumber },
}); });
const { success, data, message: errMsg } = resp as any; const { success, data, message: errMsg } = resp as any;
if (!success) throw new Error(errMsg || '获取失败'); if (!success) throw new Error(errMsg || '获取失败');
<<<<<<< HEAD
<<<<<<< HEAD
// 仅保留与父订单号完全一致的订单(避免模糊匹配误入) // 仅保留与父订单号完全一致的订单(避免模糊匹配误入)
=======
// 仅保留与父订单号完全一致的订单(避免模糊匹配误入)
>>>>>>> 90ea0f5 (feat(): )
=======
// 仅保留与父订单号完全一致的订单(避免模糊匹配误入)
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
const candidates: any[] = (Array.isArray(data) ? data : []).filter( const candidates: any[] = (Array.isArray(data) ? data : []).filter(
(c: any) => String(c?.externalOrderId) === parentNumber (c: any) => String(c?.externalOrderId) === parentNumber
); );
@ -216,7 +240,15 @@ const ListPage: React.FC = () => {
// 工具栏:订阅同步入口 // 工具栏:订阅同步入口
toolBarRender={() => [<SyncForm key="sync" tableRef={actionRef} />]} toolBarRender={() => [<SyncForm key="sync" tableRef={actionRef} />]}
/> />
<<<<<<< HEAD
<<<<<<< HEAD
{/* 关联订单抽屉:展示订单号、关系、时间、状态与金额 */} {/* 关联订单抽屉:展示订单号、关系、时间、状态与金额 */}
=======
{/* 关联订单抽屉:展示订单号、关系、时间、状态与金额 */}
>>>>>>> 90ea0f5 (feat(): )
=======
{/* 关联订单抽屉:展示订单号、关系、时间、状态与金额 */}
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
<Drawer <Drawer
open={drawerOpen} open={drawerOpen}
title={drawerTitle} title={drawerTitle}
@ -230,7 +262,15 @@ const ListPage: React.FC = () => {
<List.Item> <List.Item>
<List.Item.Meta <List.Item.Meta
title={`#${item?.externalOrderId || '-'}`} title={`#${item?.externalOrderId || '-'}`}
<<<<<<< HEAD
<<<<<<< HEAD
description={`关系:${item?.relationship || '-'},站点:${item?.siteName || '-'}`} description={`关系:${item?.relationship || '-'},站点:${item?.siteName || '-'}`}
=======
description={`关系:${item?.relationship || '-'},站点:${item?.siteName || '-'}`}
>>>>>>> 90ea0f5 (feat(): )
=======
description={`关系:${item?.relationship || '-'},站点:${item?.siteName || '-'}`}
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
/> />
<div style={{ display: 'flex', gap: 12, alignItems: 'center' }}> <div style={{ display: 'flex', gap: 12, alignItems: 'center' }}>
<span>{item?.date_created ? dayjs(item.date_created).format('YYYY-MM-DD HH:mm') : '-'}</span> <span>{item?.date_created ? dayjs(item.date_created).format('YYYY-MM-DD HH:mm') : '-'}</span>

View File

@ -13,7 +13,15 @@ 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
<<<<<<< HEAD
// 服务器 API 引用(保持与原 index.tsx 一致) // 服务器 API 引用(保持与原 index.tsx 一致)
=======
// 服务器 API 引用(保持与原 index.tsx 一致)
>>>>>>> d98e843 (refactor(): )
=======
// 服务器 API 引用(保持与原 index.tsx 一致)
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
import { import {
ordercontrollerChangestatus, ordercontrollerChangestatus,
ordercontrollerGetorderdetail, ordercontrollerGetorderdetail,
@ -27,13 +35,25 @@ 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
<<<<<<< HEAD
// 中文注释:为保持原文件结构简单,此处从 index.tsx 引入的子组件仍由原文件导出或保持原状 // 中文注释:为保持原文件结构简单,此处从 index.tsx 引入的子组件仍由原文件导出或保持原状
=======
// 中文注释:为保持原文件结构简单,此处从 index.tsx 引入的子组件仍由原文件导出或保持原状
>>>>>>> d98e843 (refactor(): )
=======
// 中文注释:为保持原文件结构简单,此处从 index.tsx 引入的子组件仍由原文件导出或保持原状
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
// 若后续需要彻底解耦,可将 OrderNote / Shipping / SalesChange 也独立到文件 // 若后续需要彻底解耦,可将 OrderNote / Shipping / SalesChange 也独立到文件
// 当前按你的要求仅抽离详情 Drawer // 当前按你的要求仅抽离详情 Drawer
type OrderRecord = API.Order; type OrderRecord = API.Order;
interface OrderDetailDrawerProps { interface OrderDetailDrawerProps {
<<<<<<< HEAD
<<<<<<< HEAD
=======
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
tableRef: React.MutableRefObject<ActionType | undefined>; // 中文注释:列表刷新引用 tableRef: React.MutableRefObject<ActionType | undefined>; // 中文注释:列表刷新引用
orderId: number; // 中文注释:订单主键 ID orderId: number; // 中文注释:订单主键 ID
record: OrderRecord; // 中文注释:订单行记录 record: OrderRecord; // 中文注释:订单行记录
@ -42,6 +62,19 @@ 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>; // 中文注释:换货组件(从外部注入)
<<<<<<< HEAD
=======
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(): )
=======
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
} }
const OrderDetailDrawer: React.FC<OrderDetailDrawerProps> = ({ const OrderDetailDrawer: React.FC<OrderDetailDrawerProps> = ({
@ -57,7 +90,15 @@ const OrderDetailDrawer: React.FC<OrderDetailDrawerProps> = ({
const { message } = App.useApp(); const { message } = App.useApp();
const ref = useRef<ActionType>(); const ref = useRef<ActionType>();
<<<<<<< HEAD
<<<<<<< HEAD
// 中文注释:加载详情数据(与 index.tsx 中完全保持一致) // 中文注释:加载详情数据(与 index.tsx 中完全保持一致)
=======
// 中文注释:加载详情数据(与 index.tsx 中完全保持一致)
>>>>>>> d98e843 (refactor(): )
=======
// 中文注释:加载详情数据(与 index.tsx 中完全保持一致)
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
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 +125,15 @@ const OrderDetailDrawer: React.FC<OrderDetailDrawerProps> = ({
size="large" size="large"
onClose={onClose} onClose={onClose}
footer={[ footer={[
<<<<<<< HEAD
<<<<<<< HEAD
// 中文注释:备注组件(外部传入以避免循环依赖) // 中文注释:备注组件(外部传入以避免循环依赖)
=======
// 中文注释:备注组件(外部传入以避免循环依赖)
>>>>>>> d98e843 (refactor(): )
=======
// 中文注释:备注组件(外部传入以避免循环依赖)
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
<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 +290,10 @@ 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
<<<<<<< HEAD
=======
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
<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 +303,34 @@ 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>
<<<<<<< HEAD
=======
<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(): )
=======
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
</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
<<<<<<< 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(): )
=======
<li key={item.id}>{item.name}:{item.quantity}</li>
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
))} ))}
</ul> </ul>
)} /> )} />
@ -265,7 +340,15 @@ 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
<<<<<<< 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(): )
=======
<li key={item.id}>{item.name}:{item.quantity}</li>
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
))} ))}
</ul> </ul>
)} /> )} />
@ -310,7 +393,15 @@ const OrderDetailDrawer: React.FC<OrderDetailDrawerProps> = ({
</Popconfirm> </Popconfirm>
] : [] } ] : [] }
> >
<<<<<<< HEAD
<<<<<<< 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(): )
=======
<div>: {Array.isArray(v?.orderIds) ? v.orderIds.join(',') : '-'}</div>
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
{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>
))} ))}

View File

@ -7,8 +7,18 @@ dayjs.extend(relativeTime);
/** /**
* RelatedOrders * RelatedOrders
<<<<<<< HEAD
<<<<<<< HEAD
* (/) * (/)
* 中文注释:本组件将订阅与订单统一归一化为五列展示便 * 中文注释:本组件将订阅与订单统一归一化为五列展示便
=======
* /
* 便
>>>>>>> d98e843 (refactor(): )
=======
* (/)
* 中文注释:本组件将订阅与订单统一归一化为五列展示便
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
*/ */
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 +39,15 @@ const RelatedOrders: React.FC<{ data?: any[] }> = ({ data = [] }) => {
return ( return (
<div style={{ width: '100%' }}> <div style={{ width: '100%' }}>
<<<<<<< HEAD
<<<<<<< HEAD
{/* 表头(英文文案,符合国际化默认英文的要求) */} {/* 表头(英文文案,符合国际化默认英文的要求) */}
=======
{/* 表头(英文文案,符合国际化默认英文的要求) */}
>>>>>>> d98e843 (refactor(): )
=======
{/* 表头(英文文案,符合国际化默认英文的要求) */}
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
<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>

View File

@ -2,11 +2,30 @@ import React, { useRef, useState } from 'react';
import { PageContainer } from '@ant-design/pro-layout'; import { PageContainer } from '@ant-design/pro-layout';
import type { ProColumns, ActionType, ProTableProps } from '@ant-design/pro-components'; import type { ProColumns, ActionType, ProTableProps } from '@ant-design/pro-components';
import { ProTable } from '@ant-design/pro-components'; import { ProTable } from '@ant-design/pro-components';
<<<<<<< HEAD
<<<<<<< HEAD
import { App, Tag, Button } from 'antd'; import { App, Tag, Button } from 'antd';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { ordercontrollerGetorders } from '@/servers/api/order'; import { ordercontrollerGetorders } from '@/servers/api/order';
import OrderDetailDrawer from './OrderDetailDrawer'; import OrderDetailDrawer from './OrderDetailDrawer';
<<<<<<< HEAD
import { sitecontrollerAll } from '@/servers/api/site'; import { sitecontrollerAll } from '@/servers/api/site';
=======
import { App, Tag, Button, Drawer, List } from 'antd';
=======
import { App, Tag, Button } from 'antd';
>>>>>>> 1f4128f (refactor(): )
import dayjs from 'dayjs';
import { ordercontrollerGetorders } from '@/servers/api/order';
import OrderDetailDrawer from '@/pages/Order/List/OrderDetailDrawer';
=======
>>>>>>> 502cd0c (refactor(Subscription/Orders): 使OrderDetailDrawer组件)
import { sitecontrollerAll } from '@/servers/api/site';
<<<<<<< HEAD
import { request } from 'umi';
>>>>>>> 90ea0f5 (feat(): )
=======
>>>>>>> 43be89b (feat(): )
interface OrderItemRow { interface OrderItemRow {
id: number; id: number;
@ -22,11 +41,31 @@ interface OrderItemRow {
const OrdersPage: React.FC = () => { const OrdersPage: React.FC = () => {
const actionRef = useRef<ActionType>(); const actionRef = useRef<ActionType>();
const { message } = App.useApp(); const { message } = App.useApp();
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
// 抽屉状态:改为复用订单详情抽屉组件 // 抽屉状态:改为复用订单详情抽屉组件
=======
// 抽屉状态:改为复用订单详情抽屉组件
>>>>>>> 1f4128f (refactor(): )
=======
// 抽屉状态:改为复用订单详情抽屉组件
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
const [detailOpen, setDetailOpen] = useState(false); const [detailOpen, setDetailOpen] = useState(false);
const [detailRecord, setDetailRecord] = useState<any | null>(null); const [detailRecord, setDetailRecord] = useState<any | null>(null);
const [detailOrderId, setDetailOrderId] = useState<number | null>(null); const [detailOrderId, setDetailOrderId] = useState<number | null>(null);
const Noop: React.FC<any> = () => null; const Noop: React.FC<any> = () => null;
<<<<<<< HEAD
=======
// 抽屉状态用于展示与订阅相关的订单详情含行项目meta
const [drawerOpen, setDrawerOpen] = useState(false);
const [drawerTitle, setDrawerTitle] = useState<string>('订阅关联');
const [drawerItems, setDrawerItems] = useState<any[]>([]);
const [drawerMeta, setDrawerMeta] = useState<any[]>([]);
const [isSubscription, setIsSubscription] = useState<boolean>(false);
>>>>>>> 90ea0f5 (feat(): )
=======
>>>>>>> 1f4128f (refactor(): )
const columns: ProColumns<OrderItemRow>[] = [ const columns: ProColumns<OrderItemRow>[] = [
{ {
@ -84,10 +123,54 @@ const OrdersPage: React.FC = () => {
render: (_, row) => ( render: (_, row) => (
<Button <Button
size="small" size="small"
<<<<<<< HEAD
<<<<<<< HEAD
=======
>>>>>>> 1f4128f (refactor(): )
onClick={() => { onClick={() => {
setDetailRecord(row as any); setDetailRecord(row as any);
setDetailOrderId(row.id as number); setDetailOrderId(row.id as number);
setDetailOpen(true); setDetailOpen(true);
<<<<<<< HEAD
=======
onClick={async () => {
try {
// 拉取订单详情(包含 items 与 meta_data用于判断是否为订阅订单
const resp = await request(`/order/${row.id}`, { method: 'GET' });
const { success, data, message: errMsg } = resp as any;
if (!success) throw new Error(errMsg || '获取失败');
const items: any[] = data?.items || [];
const orderMeta: any[] = data?.meta_data || [];
// 订阅识别:检查行项目 meta_data 中的关键键
const keys = [
'is_subscription',
'_wcs_bought_as_subscription',
'subscription_product_type',
'subscription_period',
'subscription_interval',
'_subscription',
'_subscription_period',
'_subscription_interval',
];
let detected = false;
for (const it of items) {
const md = Array.isArray(it?.meta_data) ? it.meta_data : [];
if (md.some((m: any) => keys.includes(String(m?.key)))) {
detected = true;
break;
}
}
setIsSubscription(detected);
setDrawerItems(items);
setDrawerMeta(orderMeta);
setDrawerTitle(`订阅关联(订单号:${row.externalOrderId}`);
setDrawerOpen(true);
} catch (e: any) {
message.error(e?.message || '获取失败');
}
>>>>>>> 90ea0f5 (feat(): )
=======
>>>>>>> 1f4128f (refactor(): )
}} }}
> >
@ -149,7 +232,16 @@ const OrdersPage: React.FC = () => {
}} }}
toolBarRender={false} toolBarRender={false}
/> />
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
{/* 订阅关联:直接使用订单详情抽屉组件 */} {/* 订阅关联:直接使用订单详情抽屉组件 */}
=======
{/* 订阅关联:直接使用订单详情抽屉组件 */}
>>>>>>> 1f4128f (refactor(): )
=======
{/* 订阅关联:直接使用订单详情抽屉组件 */}
>>>>>>> 3ac2724 (style: 统一中文标点符号为英文格式)
{detailRecord && detailOrderId !== null && ( {detailRecord && detailOrderId !== null && (
<OrderDetailDrawer <OrderDetailDrawer
open={detailOpen} open={detailOpen}
@ -160,8 +252,57 @@ const OrdersPage: React.FC = () => {
setActiveLine={() => {}} setActiveLine={() => {}}
OrderNoteComponent={Noop} OrderNoteComponent={Noop}
SalesChangeComponent={Noop} SalesChangeComponent={Noop}
<<<<<<< HEAD
/> />
)} )}
=======
{/* 订阅关联抽屉:展示行项目与订单元数据,标注是否订阅 */}
<Drawer
open={drawerOpen}
title={drawerTitle}
width={720}
onClose={() => setDrawerOpen(false)}
>
<div style={{ marginBottom: 12 }}>
<Tag color={isSubscription ? 'green' : 'default'}>
{isSubscription ? '订阅订单' : '非订阅订单'}
</Tag>
</div>
{/* 行项目列表,展示 meta_data 关键键值 */}
<List
header={<div></div>}
dataSource={drawerItems}
renderItem={(item: any) => (
<List.Item>
<List.Item.Meta
title={`${item?.name || '-'}(数量:${item?.quantity || 0}`}
description={`SKU${item?.sku || '-'}产品ID${item?.externalProductId || '-'}变体ID${item?.externalVariationId || '-'}`}
/>
<div style={{ maxWidth: 420 }}>
{(Array.isArray(item?.meta_data) ? item.meta_data : []).map((m: any) => (
<Tag key={`${m?.key}-${m?.id}`}>{`${m?.key}: ${m?.value}`}</Tag>
))}
</div>
</List.Item>
)}
/>
{/* 订单级元数据 */}
<List
style={{ marginTop: 16 }}
header={<div></div>}
dataSource={drawerMeta}
renderItem={(m: any) => (
<List.Item>
<Tag>{`${m?.key}: ${m?.value}`}</Tag>
</List.Item>
)}
/>
</Drawer>
>>>>>>> 90ea0f5 (feat(): )
=======
/>
)}
>>>>>>> 1f4128f (refactor(): )
</PageContainer> </PageContainer>
); );
}; };