import { ORDER_STATUS_ENUM } from '@/constants'; import { HistoryOrder } from '@/pages/Statistics/Order'; import styles from '@/style/order-list.css'; import { DeleteFilled, EllipsisOutlined } from '@ant-design/icons'; import { ActionType, ModalForm, PageContainer, ProColumns, ProFormTextArea, ProTable, } from '@ant-design/pro-components'; import { request, useParams } from '@umijs/max'; import { App, Button, Dropdown, Popconfirm, Tabs, TabsProps } from 'antd'; import React, { useEffect, useMemo, useRef, useState } from 'react'; import { BatchEditOrders, CreateOrder, EditOrder, OrderNote, } from '../components/Order/Forms'; const OrdersPage: React.FC = () => { const actionRef = useRef(); const [selectedRowKeys, setSelectedRowKeys] = useState([]); const [activeKey, setActiveKey] = useState('all'); const [count, setCount] = useState([]); const [activeLine, setActiveLine] = useState(-1); const { siteId } = useParams<{ siteId: string }>(); const { message } = App.useApp(); useEffect(() => { actionRef.current?.reload(); }, [siteId]); const tabs: TabsProps['items'] = useMemo(() => { // 统计全部数量,依赖状态统计数组 const total = count.reduce((acc, cur) => acc + Number(cur.count), 0); const tabs = [ { key: 'pending', label: '待确认' }, { key: 'processing', label: '待发货' }, { key: 'completed', label: '已完成' }, { key: 'cancelled', label: '已取消' }, { key: 'refunded', label: '已退款' }, { key: 'failed', label: '失败' }, { key: 'after_sale_pending', label: '售后处理中' }, { key: 'pending_reshipment', label: '待补发' }, // 退款相关状态 { key: 'refund_requested', label: '已申请退款' }, { key: 'refund_approved', label: '退款申请已通过' }, { key: 'refund_cancelled', label: '已取消退款' }, ].map((v) => { // 根据状态键匹配统计数量 const number = count.find((el) => el.status === v.key)?.count || '0'; return { label: `${v.label}(${number})`, key: v.key, }; }); return [{ key: 'all', label: `全部(${total})` }, ...tabs]; }, [count]); const columns: ProColumns[] = [ { title: '订单号', dataIndex: 'id', hideInSearch: true, }, { title: '状态', dataIndex: 'status', valueType: 'select', valueEnum: ORDER_STATUS_ENUM, }, { title: '订单日期', dataIndex: 'date_created', hideInSearch: true, valueType: 'dateTime', }, { title: '金额', dataIndex: 'total', hideInSearch: true, }, { title: '币种', dataIndex: 'currency', hideInSearch: true, }, { title: '客户邮箱', dataIndex: 'email', }, { title: '客户姓名', dataIndex: 'customer_name', hideInSearch: true, }, { title: '商品', dataIndex: 'line_items', hideInSearch: true, width: 200, ellipsis: true, render: (_, record) => { // 检查 record.line_items 是否是数组并且有内容 if (Array.isArray(record.line_items) && record.line_items.length > 0) { // 遍历 line_items 数组, 显示每个商品的名称和数量 return (
{record.line_items.map((item: any) => (
{`${item.name} x ${item.quantity}`}
))}
); } // 如果 line_items 不存在或不是数组, 则显示占位符 return '-'; }, }, { title: '支付方式', dataIndex: 'payment_method', }, { title: '联系电话', hideInSearch: true, render: (_, record) => record.shipping?.phone || record.billing?.phone, }, { title: '账单地址', dataIndex: 'billing_full_address', hideInSearch: true, width: 200, ellipsis: true, copyable: true, }, { title: '收货地址', dataIndex: 'shipping_full_address', hideInSearch: true, width: 200, ellipsis: true, copyable: true, }, { title: '操作', dataIndex: 'option', valueType: 'option', fixed: 'right', width: '200', render: (_, record) => { return ( <> ), }, { key: 'note', label: ( ), }, ], }} > , 批量导入 } width={600} modalProps={{ destroyOnHidden: true }} onFinish={async (values) => { if (!siteId) return false; const csv = values.csv || ''; const items = values.items || []; const res = await request(`/site-api/${siteId}/orders/import`, { method: 'POST', data: { csv, items }, }); if (res.success) { message.success('导入完成'); actionRef.current?.reload(); return true; } message.error(res.message || '导入失败'); return false; }} > , ]} request={async (params, sort, filter) => { const p: any = params || {}; const current = p.current; const pageSize = p.pageSize; const date = p.date; const status = p.status; const { current: _c, pageSize: _ps, date: _d, status: _s, ...rest } = p; const where: Record = { ...(filter || {}), ...rest }; if (status && status !== 'all') { where.status = status; } if (date) { const [startDate, endDate] = date; // 将日期范围转为后端筛选参数 where.startDate = `${startDate} 00:00:00`; where.endDate = `${endDate} 23:59:59`; } let orderObj: Record | undefined = undefined; if (sort && typeof sort === 'object') { const [field, dir] = Object.entries(sort)[0] || []; if (field && dir) { orderObj = { [field]: dir === 'descend' ? 'desc' : 'asc' }; } } const response = await request(`/site-api/${siteId}/orders`, { params: { page: current, page_size: pageSize, where, ...(orderObj ? { order: orderObj } : {}), }, }); if (!response.success) { message.error(response.message || '获取订单列表失败'); return { data: [], success: false, }; } const { data } = response; // 计算顶部状态数量,通过按状态并发查询站点接口 if (siteId) { try { // 定义需要统计的状态键集合 const statusKeys: string[] = [ 'pending', 'processing', 'completed', 'cancelled', 'refunded', 'failed', // 站点接口不支持的扩展状态,默认统计为0 'after_sale_pending', 'pending_reshipment', 'refund_requested', 'refund_approved', 'refund_cancelled', ]; // 构造基础筛选参数,移除当前状态避免重复过滤 const { status: _status, ...baseWhere } = where; // 并发请求各状态的总数,对站点接口不支持的状态使用0 const results = await Promise.all( statusKeys.map(async (key) => { // 将前端退款状态映射为站点接口可能识别的原始状态 const mapToRawStatus: Record = { refund_requested: 'return-requested', refund_approved: 'return-approved', refund_cancelled: 'return-cancelled', }; const rawStatus = mapToRawStatus[key] || key; // 对扩展状态直接返回0,减少不必要的请求 const unsupported = [ 'after_sale_pending', 'pending_reshipment', ]; if (unsupported.includes(key)) { return { status: key, count: 0 }; } try { const res = await request(`/site-api/${siteId}/orders`, { params: { page: 1, per_page: 1, where: { ...baseWhere, status: rawStatus }, }, }); const totalCount = Number(res?.data?.total || 0); return { status: key, count: totalCount }; } catch (err) { // 请求失败时该状态数量记为0 return { status: key, count: 0 }; } }), ); setCount(results); } catch (e) { // 统计失败时不影响列表展示 } } if (data) { return { total: data?.total || 0, data: data?.items || [], success: true, }; } return { data: [], success: false, }; }} /> ); }; export default OrdersPage;