forked from yoone/WEB
1
0
Fork 0
WEB/src/pages/Order/List/index.tsx

2376 lines
74 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import styles from '../../../style/order-list.css';
import InternationalPhoneInput from '@/components/InternationalPhoneInput';
import { HistoryOrder } from '@/pages/Statistics/Order';
import { ORDER_STATUS_ENUM } from '@/constants';
import {
logisticscontrollerCreateshipment,
logisticscontrollerGetshipmentfee,
logisticscontrollerDelshipment,
logisticscontrollerGetpaymentmethods,
logisticscontrollerGetratelist,
logisticscontrollerGetshippingaddresslist,
// logisticscontrollerGetshipmentlabel,
} from '@/servers/api/logistics';
import {
ordercontrollerCancelorder,
ordercontrollerChangestatus,
ordercontrollerCompletedorder,
ordercontrollerCreatenote,
ordercontrollerCreateorder,
ordercontrollerGetorderbynumber,
ordercontrollerGetorderdetail,
ordercontrollerGetorders,
ordercontrollerRefundorder,
ordercontrollerSyncorder,
ordercontrollerSyncorderbyid,
ordercontrollerUpdateorderitems,
} from '@/servers/api/order';
import { productcontrollerSearchproducts } from '@/servers/api/product';
import { wpproductcontrollerSearchproducts } from '@/servers/api/wpProduct';
import { sitecontrollerAll } from '@/servers/api/site';
import { stockcontrollerGetallstockpoints } from '@/servers/api/stock';
import { formatShipmentState, formatSource } from '@/utils/format';
import {
CodeSandboxOutlined,
CopyOutlined,
DeleteFilled,
DownOutlined,
FileDoneOutlined,
SyncOutlined,
TagsOutlined,
} from '@ant-design/icons';
import {
ActionType,
DrawerForm,
ModalForm,
PageContainer,
ProColumns,
ProDescriptions,
ProForm,
ProFormDatePicker,
ProFormDependency,
ProFormDigit,
ProFormInstance,
ProFormItem,
ProFormList,
ProFormRadio,
ProFormSelect,
ProFormText,
ProFormTextArea,
ProTable,
} from '@ant-design/pro-components';
import {
App,
Button,
Card,
Col,
Descriptions,
Divider,
Drawer,
Dropdown,
Empty,
message,
Popconfirm,
Radio,
Row,
Space,
Tabs,
TabsProps,
} from 'antd';
import Item from 'antd/es/list/Item';
import dayjs from 'dayjs';
import React, { useMemo, useRef, useState } from 'react';
import { printPDF } from '@/utils/util';
const ListPage: React.FC = () => {
const actionRef = useRef<ActionType>();
const [activeKey, setActiveKey] = useState<string>('all');
const [count, setCount] = useState<any[]>([]);
const [activeLine, setActiveLine] = useState<number>(-1);
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: '已取消退款',
},
// {
// key: 'pending_refund',
// 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 { message } = App.useApp();
const columns: ProColumns<API.Order>[] = [
{
title: 'ID',
dataIndex: 'id',
hideInSearch: true,
},
{
title: '日期',
dataIndex: 'date',
hideInTable: true,
valueType: 'dateRange',
},
{
title: '订单号',
dataIndex: 'externalOrderId',
},
{
title: '站点',
dataIndex: 'siteId',
valueType: 'select',
request: async () => {
const { data = [] } = await sitecontrollerAll();
return data.map((item) => ({
label: item.siteName,
value: item.id,
}));
},
},
{
title: '订单包含',
dataIndex: 'keyword',
hideInTable: true,
},
{
title: '订单日期',
dataIndex: 'date_created',
hideInSearch: true,
valueType: 'dateTime',
},
{
title: '金额',
dataIndex: 'total',
hideInSearch: true,
},
{
title: '支付方式',
dataIndex: 'payment_method',
},
{
title: '总订单数',
dataIndex: 'order_count',
hideInSearch: true,
},
{
title: '总订单金额',
dataIndex: 'total_spent',
hideInSearch: true,
},
{
title: '客户邮箱',
dataIndex: 'customer_email',
},
{
title: '联系电话',
dataIndex: 'billing_phone',
render: (_, record) => record.shipping?.phone || record.billing?.phone,
},
{
title: '换货次数',
dataIndex: 'exchange_frequency',
hideInSearch: true,
},
{
title: '州',
hideInSearch: true,
render: (_, record) => record.shipping?.state || record.billing?.state,
},
{
title: '状态',
dataIndex: 'orderStatus',
hideInSearch: true,
valueType: 'select',
valueEnum: ORDER_STATUS_ENUM,
},
{
title: '物流',
dataIndex: 'shipmentList',
hideInSearch: true,
render: (_, record) => {
return (
<div>
{record?.shipmentList?.map((item) => {
if (!item) return;
return (
<div>
{item.tracking_provider}:{item.primary_tracking_number} (
{formatShipmentState(item.state)})
</div>
);
})}
</div>
);
},
},
{
title: 'IP',
dataIndex: 'customer_ip_address',
hideInSearch: true,
},
{
title: '设备',
dataIndex: 'device_type',
hideInSearch: true,
},
{
title: '来源',
hideInSearch: true,
render: (_, record) =>
formatSource(record.source_type, record.utm_source),
},
{
title: '客户备注',
dataIndex: 'customer_note',
hideInSearch: true,
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
fixed: 'right',
width: '200',
render: (_, record) => {
return (
<>
{['processing', 'pending_reshipment'].includes(
record.orderStatus,
) ? (
<>
<Shipping id={record.id as number} tableRef={actionRef} setActiveLine={setActiveLine}/>
<Divider type="vertical" />
</>
) : (
<></>
)}
<Detail
key={record.id}
record={record}
tableRef={actionRef}
orderId={record.id as number}
setActiveLine={setActiveLine}
/>
<Divider type="vertical" />
<Dropdown
menu={{
items: [
{
key: 'sync',
label: (
<Button
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('同步成功');
actionRef.current?.reload();
} catch (error) {
message.error(error?.message || '同步失败');
}
}}
>
</Button>
),
style: {
display: [
'after_sale_pending',
'pending_reshipment',
].includes(record.orderStatus)
? 'none'
: 'block',
},
},
{
key: 'history',
label:
<HistoryOrder
email={record.customer_email}
tableRef={actionRef}
/>,
},
{
key: 'note',
label: <OrderNote id={record.id as number} />,
},
{
key: 'cancel',
label: (
<Popconfirm
title="转至售后"
description="确认转至售后?"
onConfirm={async () => {
try {
const { success, message: errMsg } =
await ordercontrollerChangestatus(
{
id: record.id,
},
{
status: 'after_sale_pending',
},
);
if (!success) {
throw new Error(errMsg);
}
actionRef.current?.reload();
} catch (error: any) {
message.error(error.message);
}
}}
>
<Button type="primary" ghost>
</Button>
</Popconfirm>
),
style: {
display: [
'processing',
'pending_reshipment',
'completed',
'pending_refund',
].includes(record.orderStatus)
? 'block'
: 'none',
},
},
],
}}
>
<a onClick={(e) => e.preventDefault()}>
<Space>
<DownOutlined />
</Space>
</a>
</Dropdown>
</>
);
},
},
];
return (
<PageContainer ghost>
<Tabs items={tabs} activeKey={activeKey} onChange={setActiveKey} />
<ProTable
params={{ status: activeKey }}
headerTitle="查询表格"
scroll={{ x: 'max-content' }}
actionRef={actionRef}
rowKey="id"
rowClassName={(record) => {
return record.id === activeLine ? styles['selected-line-order-protable']: '';
}}
toolBarRender={() => [
<CreateOrder tableRef={actionRef} />,
<SyncForm tableRef={actionRef} />,
]}
request={async ({ date, ...param }) => {
if (param.status === 'all') {
delete param.status;
}
if (date) {
const [startDate, endDate] = date;
param.startDate = `${startDate} 00:00:00`;
param.endDate = `${endDate} 23:59:59`;
}
const { data, success } = await ordercontrollerGetorders(param);
if (success) {
setCount(data?.count || []);
return {
total: data?.total || 0,
data: data?.items || [],
};
}
return {
data: [],
};
}}
columns={columns}
/>
</PageContainer>
);
};
const SyncForm: React.FC<{
tableRef: React.MutableRefObject<ActionType | undefined>;
}> = ({ tableRef }) => {
const { message } = App.useApp();
return (
<DrawerForm<API.ordercontrollerSyncorderParams>
title="同步订单"
trigger={
<Button key="syncSite" type="primary">
<SyncOutlined />
</Button>
}
autoFocusFirstInput
drawerProps={{
destroyOnHidden: true,
}}
onFinish={async (values) => {
try {
const { success, message: errMsg } = await ordercontrollerSyncorder(
values,
);
if (!success) {
throw new Error(errMsg);
}
message.success('同步成功');
tableRef.current?.reload();
return true;
} catch (error: any) {
message.error(error.message);
}
}}
>
<ProForm.Group>
<ProFormSelect
name="siteId"
width="lg"
label="站点"
placeholder="请选择站点"
request={async () => {
const { data = [] } = await sitecontrollerAll();
return data.map((item) => ({
label: item.siteName,
value: item.id,
}));
}}
/>
</ProForm.Group>
</DrawerForm>
);
};
const Detail: React.FC<{
tableRef: React.MutableRefObject<ActionType | undefined>;
orderId: number;
record: API.Order;
setActiveLine: Function
}> = ({ tableRef, orderId, record, setActiveLine }) => {
const [visiable, setVisiable] = useState(false);
const { message } = App.useApp();
const ref = useRef<ActionType>();
const initRequest = async () => {
const { data, success }: API.OrderDetailRes =
await ordercontrollerGetorderdetail({
orderId,
});
if (!success || !data) return { data: {} };
// 合并订单中相同的sku只显示一次记录总数
data.sales = data.sales?.reduce(
(acc: API.OrderSale[], cur: API.OrderSale) => {
let 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,
};
};
return (
<>
<Button key="detail" type="primary" onClick={() => {
setVisiable(true);
setActiveLine(record.id);
}}>
<FileDoneOutlined />
</Button>
<Drawer
title="订单详情"
open={visiable}
destroyOnHidden
size="large"
onClose={() => setVisiable(false)}
footer={[
<OrderNote id={orderId} descRef={ref} />,
...(['after_sale_pending', 'pending_reshipment'].includes(
record.orderStatus,
)
? []
: [
<Divider type="vertical" />,
<Button
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'].includes(record.orderStatus)
// ? [
// <Divider type="vertical" />,
// <Shipping
// id={record.id as number}
// tableRef={tableRef}
// descRef={ref}
// reShipping={true}
// />,
// ]
// : []),
...([
'processing',
'pending_reshipment',
'completed',
'pending_refund',
].includes(record.orderStatus)
? [
<Divider type="vertical" />,
<Popconfirm
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 type="vertical" />,
<Popconfirm
title="转至取消"
description="确认转至取消?"
onConfirm={async () => {
try {
const { success, message: errMsg } =
await ordercontrollerCancelorder({
id: record.id,
});
if (!success) {
throw new Error(errMsg);
}
tableRef.current?.reload();
} catch (error: any) {
message.error(error.message);
}
}}
>
<Button type="primary" ghost>
</Button>
</Popconfirm>,
<Divider type="vertical" />,
<Popconfirm
title="转至退款"
description="确认转至退款?"
onConfirm={async () => {
try {
const { success, message: errMsg } =
await ordercontrollerRefundorder({
id: record.id,
});
if (!success) {
throw new Error(errMsg);
}
tableRef.current?.reload();
} catch (error: any) {
message.error(error.message);
}
}}
>
<Button type="primary" ghost>
退
</Button>
</Popconfirm>,
<Divider type="vertical" />,
<Popconfirm
title="转至完成"
description="确认转至完成?"
onConfirm={async () => {
try {
const { success, message: errMsg } =
await ordercontrollerCompletedorder({
id: record.id,
});
if (!success) {
throw new Error(errMsg);
}
tableRef.current?.reload();
} catch (error: any) {
message.error(error.message);
}
}}
>
<Button type="primary" ghost>
</Button>
</Popconfirm>,
<Divider type="vertical" />,
<Popconfirm
title="转至待补发"
description="确认转至待补发?"
onConfirm={async () => {
try {
const { success, message: errMsg } =
await ordercontrollerChangestatus(
{
id: record.id,
},
{
status: 'pending_reshipment',
},
);
if (!success) {
throw new Error(errMsg);
}
tableRef.current?.reload();
} catch (error: any) {
message.error(error.message);
}
}}
>
<Button type="primary" ghost>
</Button>
</Popconfirm>,
]
: []),
]}
>
<ProDescriptions
labelStyle={{ width: '100px' }}
actionRef={ref}
request={initRequest}
>
<ProDescriptions.Item
label="站点"
dataIndex="siteId"
valueType="select"
request={async () => {
const { data = [] } = await sitecontrollerAll();
return data.map((item) => ({
label: item.siteName,
value: item.id,
}));
}}
/>
<ProDescriptions.Item
label="订单日期"
dataIndex="date_created"
valueType="dateTime"
/>
<ProDescriptions.Item
label="订单状态"
dataIndex="orderStatus"
valueType="select"
valueEnum={ORDER_STATUS_ENUM}
/>
<ProDescriptions.Item label="金额" dataIndex="total" />
<ProDescriptions.Item label="客户邮箱" dataIndex="customer_email" />
<ProDescriptions.Item label="联系电话" span={3}
render={(_, record) => { return (
<div>
<span>
{record?.shipping?.phone || record?.billing?.phone || '-'}
</span>
</div>
);
}} />
<ProDescriptions.Item label="交易Id" dataIndex="transaction_id" />
<ProDescriptions.Item label="IP" dataIndex="customer_id_address" />
<ProDescriptions.Item label="设备" dataIndex="device_type" />
<ProDescriptions.Item
label="来源"
render={(_, record) =>
formatSource(record.source_type, record.utm_source)
}
/>
<ProDescriptions.Item
label="原订单状态"
dataIndex="status"
valueType="select"
valueEnum={ORDER_STATUS_ENUM}
/>
<ProDescriptions.Item
label="支付链接"
dataIndex="payment_url"
span={3}
copyable
/>
<ProDescriptions.Item
label="客户备注"
dataIndex="customer_note"
span={3}
/>
<ProDescriptions.Item
label="发货信息"
span={3}
render={(_, record) => {
return (
<div>
<div>
company
<span>
{record?.shipping?.company ||
record?.billing?.company ||
'-'}
</span>
</div>
<div>
first_name
<span>
{record?.shipping?.first_name ||
record?.billing?.first_name ||
'-'}
</span>
</div>
<div>
last_name
<span>
{record?.shipping?.last_name ||
record?.billing?.last_name ||
'-'}
</span>
</div>
<div>
country
<span>
{record?.shipping?.country ||
record?.billing?.country ||
'-'}
</span>
</div>
<div>
state
<span>
{record?.shipping?.state || record?.billing?.state || '-'}
</span>
</div>
<div>
city
<span>
{record?.shipping?.city || record?.billing?.city || '-'}
</span>
</div>
<div>
postcode
<span>
{record?.shipping?.postcode ||
record?.billing?.postcode ||
'-'}
</span>
</div>
<div>
phone
<span>
{record?.shipping?.phone || record?.billing?.phone || '-'}
</span>
</div>
<div>
address_1
<span>
{record?.shipping?.address_1 ||
record?.billing?.address_1 ||
'-'}
</span>
</div>
</div>
);
}}
/>
<ProDescriptions.Item
label="原始订单"
span={3}
render={(_, record) => {
return (
<ul>
{record?.items?.map((item: any) => (
<li key={item.id}>
{item.name}{item.quantity}
</li>
))}
</ul>
);
}}
/>
<ProDescriptions.Item
label="订单内容"
span={3}
render={(_, record) => {
return (
<ul>
{record?.sales?.map((item: any) => (
<li key={item.id}>
{item.name}{item.quantity}
</li>
))}
</ul>
);
}}
/>
<ProDescriptions.Item
label="换货"
span={3}
render={(_, record) => {
return (
<SalesChange
detailRef={ref}
id={record.id as number}
/>
)
}}
/>
<ProDescriptions.Item
label="备注"
span={3}
render={(_, record) => {
if (!record.notes || record.notes.length === 0)
return <Empty description="暂无备注" />;
return (
<div style={{ width: '100%' }}>
{record.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>
);
}}
/>
<ProDescriptions.Item
label="物流信息"
span={3}
render={(_, record) => {
console.log('record', record);
if (!record.shipment || record.shipment.length === 0) {
return <Empty description="暂无物流信息" />;
}
return (
<div
style={{
display: 'flex',
flexDirection: 'column',
width: '100%',
}}
>
{record.shipment.map((v) => (
<Card
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
title="取消运单"
description="确认取消运单?"
onConfirm={async () => {
try {
const { success, message: errMsg } =
await logisticscontrollerDelshipment({
id: v.id,
});
if (!success) {
throw new Error(errMsg);
}
tableRef.current?.reload();
initRequest();
} catch (error: any) {
message.error(error.message);
}
}}
>
<DeleteFilled />
</Popconfirm>,
]
: []
}
>
<div> {v?.orderIds?.join(',')}</div>
{v?.items?.map((item) => (
<div>
{item.name}: {item.quantity}
</div>
))}
</Card>
))}
</div>
);
}}
/>
</ProDescriptions>
</Drawer>
</>
);
};
const OrderNote: React.FC<{
id: number;
descRef?: React.MutableRefObject<ActionType | undefined>;
}> = ({ id, descRef }) => {
const { message } = App.useApp();
return (
<ModalForm
title="添加备注"
trigger={
<Button type="primary" ghost>
<TagsOutlined />
</Button>
}
onFinish={async (values: any) => {
try {
const { success, message: errMsg } = await ordercontrollerCreatenote({
...values,
orderId: id,
});
if (!success) {
throw new Error(errMsg);
}
descRef?.current?.reload();
message.success('提交成功');
return true;
} catch (error: any) {
message.error(error.message);
}
}}
>
<ProFormTextArea
name="content"
label="内容"
width="lg"
placeholder="请输入备注"
rules={[{ required: true, message: '请输入备注' }]}
/>
</ModalForm>
);
};
const region = {
AB: 'Alberta',
BC: 'British',
MB: 'Manitoba',
NB: 'New',
NL: 'Newfoundland',
NS: 'Nova',
ON: 'Ontario',
PE: 'Prince',
QC: 'Quebec',
SK: 'Saskatchewan',
NT: 'Northwest',
NU: 'Nunavut',
YT: 'Yukon',
// 美国州名
// AL: 'Alabama',
// AK: 'Alaska',
// AZ: 'Arizona',
// AR: 'Arkansas',
// CA: 'California',
// CO: 'Colorado',
// CT: 'Connecticut',
// DE: 'Delaware',
// FL: 'Florida',
// GA: 'Georgia',
// HI: 'Hawaii',
// ID: 'Idaho',
// IL: 'Illinois',
// IN: 'Indiana',
// IA: 'Iowa',
// KS: 'Kansas',
// KY: 'Kentucky',
// LA: 'Louisiana',
// ME: 'Maine',
// MD: 'Maryland',
// MA: 'Massachusetts',
// MI: 'Michigan',
// MN: 'Minnesota',
// MS: 'Mississippi',
// MO: 'Missouri',
// MT: 'Montana',
// NE: 'Nebraska',
// NV: 'Nevada',
// NH: 'New Hampshire',
// NJ: 'New Jersey',
// NM: 'New Mexico',
// NY: 'New York',
// NC: 'North Carolina',
// ND: 'North Dakota',
// OH: 'Ohio',
// OK: 'Oklahoma',
// OR: 'Oregon',
// PA: 'Pennsylvania',
// RI: 'Rhode Island',
// SC: 'South Carolina',
// SD: 'South Dakota',
// TN: 'Tennessee',
// TX: 'Texas',
// UT: 'Utah',
// VT: 'Vermont',
// VA: 'Virginia',
// WA: 'Washington',
// WV: 'West Virginia',
// WI: 'Wisconsin',
// WY: 'Wyoming',
};
const Shipping: React.FC<{
id: number;
tableRef?: React.MutableRefObject<ActionType | undefined>;
descRef?: React.MutableRefObject<ActionType | undefined>;
reShipping?: boolean;
setActiveLine: Function;
}> = ({ id, tableRef, descRef, reShipping = false, setActiveLine }) => {
const [options, setOptions] = useState<any[]>([]);
const formRef = useRef<ProFormInstance>();
const [shipmentFee, setShipmentFee] = useState<number>(0);
const [rates, setRates] = useState<API.RateDTO[]>([]);
const [ratesLoading, setRatesLoading] = useState(false);
const { message } = App.useApp();
return (
<ModalForm
formRef={formRef}
title="创建运单"
size="large"
width="80vw"
modalProps={{
destroyOnHidden: true,
styles: {
body: { maxHeight: '65vh', overflowY: 'auto', overflowX: 'hidden' },
},
}}
trigger={
<Button type="primary"
onClick={() => {
setActiveLine(id);
}}
>
<CodeSandboxOutlined />
</Button>
}
request={async () => {
const { data, success }: API.OrderDetailRes =
await ordercontrollerGetorderdetail({
orderId: id,
});
if (!success || !data) return {};
data.sales = data.sales?.reduce(
(acc: API.OrderSale[], cur: API.OrderSale) => {
let idx = acc.findIndex((v: any) => v.productId === cur.productId);
if (idx === -1) {
acc.push(cur);
} else {
acc[idx].quantity += cur.quantity;
}
return acc;
},
[],
);
setOptions(
data.sales?.map((item) => ({
label: item.name,
value: item.sku,
})) || [],
);
if (reShipping) data.sales = [{}];
let shipmentInfo = localStorage.getItem('shipmentInfo');
if (shipmentInfo) shipmentInfo = JSON.parse(shipmentInfo);
return {
...data,
// payment_method_id: shipmentInfo?.payment_method_id,
stockPointId: shipmentInfo?.stockPointId,
details: {
destination: {
name: data?.shipping?.company || data?.billing?.company || ' ',
address: {
address_line_1:
data?.shipping?.address_1 || data?.billing?.address_1,
city: data?.shipping?.city || data?.billing?.city,
region: data?.shipping?.state || data?.billing?.state,
postal_code:
data?.shipping?.postcode || data?.billing?.postcode,
},
contact_name:
data?.shipping?.first_name || data?.shipping?.last_name
? `${data?.shipping?.first_name} ${data?.shipping?.last_name}`
: `${data?.billing?.first_name} ${data?.billing?.last_name}`,
phone_number: {
phone: data?.shipping?.phone || data?.billing?.phone,
},
email_addresses: data?.shipping?.email || data?.billing?.email,
signature_requirement: 'not-required',
},
origin: {
name: data?.siteName,
email_addresses: data?.email,
contact_name: data?.siteName,
phone_number: shipmentInfo?.phone_number,
address: {
region: shipmentInfo?.region,
city: shipmentInfo?.city,
postal_code: shipmentInfo?.postal_code,
address_line_1: shipmentInfo?.address_line_1,
},
},
packaging_type: 'package',
expected_ship_date: dayjs(),
packaging_properties: {
packages: [
{
measurements: {
weight: {
unit: 'LBS',
value: 1,
},
cuboid: {
unit: 'IN',
l: 6,
w: 4,
h: 4,
},
},
description: 'food',
},
],
},
},
};
}}
onFinish={async ({ customer_note, notes, items, details, externalOrderId, ...data }) => {
details.origin.email_addresses =
details.origin.email_addresses.split(',');
details.destination.email_addresses =
details.destination.email_addresses.split(',');
details.destination.phone_number.number =
details.destination.phone_number.phone;
details.origin.phone_number.number = details.origin.phone_number.phone;
try {
const { success, message: errMsg, ...resShipment } =
await logisticscontrollerCreateshipment(
{ orderId: id },
{
details,
...data,
},
);
if (!success) throw new Error(errMsg);
message.success('创建成功');
tableRef?.current?.reload();
descRef?.current?.reload();
localStorage.setItem(
'shipmentInfo',
JSON.stringify({
// payment_method_id: data.payment_method_id,
stockPointId: data.stockPointId,
region: details.origin.address.region,
city: details.origin.address.city,
postal_code: details.origin.address.postal_code,
address_line_1: details.origin.address.address_line_1,
phone_number: details.origin.phone_number,
}),
);
// todo, 直接打印label
// const { resLabel } = await logisticscontrollerGetShipmentLabel(resShipment.data.shipmentId);
// console.log('res', resShipment.data.shipmentId, resLabel);
// const labelContent = resLabel.content;
// printPDF([labelContent]);
return true;
} catch (error) {
message.error(error?.message || '创建失败');
}
}}
onFinishFailed={() => {
const element = document.querySelector('.ant-form-item-explain-error');
if (element) {
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
}}
>
<ProFormText
label="订单号"
readonly
name={"externalOrderId"}
/>
<ProFormText label="客户备注" readonly name="customer_note" />
<ProFormList
label="后台备注"
name="notes"
actionRender={() => []}
readonly
>
<ProFormText readonly name="content" />
</ProFormList>
<Row gutter={16}>
<Col span={12}>
<ProFormSelect
label="合并发货订单号"
name="orderIds"
showSearch
mode="multiple"
request={async ({ keyWords: number }) => {
if (!number) return [];
const { data, success } = await ordercontrollerGetorderbynumber({
number,
});
if (success) {
return data.map((v) => ({
label: `${v.siteName} ${v.externalOrderId}`,
value: v.id,
}));
}
return [];
}}
/>
</Col>
{/* <Col span={12}>
<ProFormSelect
label="付款方式"
name="payment_method_id"
rules={[{ required: true, message: '请选择付款方式' }]}
request={async () => {
const { data, success } =
await logisticscontrollerGetpaymentmethods();
if (success) {
return data.map((v) => ({
label: v.label,
value: v.id,
}));
}
return [];
}}
/>
</Col> */}
</Row>
<Row gutter={16}>
<Col span={12}>
<ProFormList
label="原始订单"
name="items"
readonly
actionRender={() => []}
>
<ProForm.Group>
<ProFormText name="name" readonly />
<ProFormDigit name="quantity" readonly />
</ProForm.Group>
</ProFormList>
</Col>
<Col span={12}>
<ProFormList
label="发货产品"
name="sales"
// rules={[
// {
// required: true,
// message: '至少需要一个商品',
// validator: (_, value) =>
// value && value.length > 0
// ? Promise.resolve()
// : Promise.reject('至少需要一个商品'),
// },
// ]}
>
<ProForm.Group>
<ProFormSelect
params={{ options }}
request={async ({ keyWords, options }) => {
if (!keyWords || keyWords.length < 2) return options;
try {
const { data } = await productcontrollerSearchproducts({
name: keyWords,
});
return (
data?.map((item) => {
return {
label: `${item.name} - ${item.nameCn}`,
value: item?.sku,
};
}) || options
);
} catch (error) {
return options;
}
}}
name="sku"
label="产品"
placeholder="请选择产品"
tooltip="至少输入3个字符"
fieldProps={{
showSearch: true,
filterOption: false,
}}
debounceTime={300} // 防抖减少请求频率
rules={[{ required: true, message: '请选择产品' }]}
/>
<ProFormDigit
name="quantity"
colProps={{ span: 12 }}
label="数量"
placeholder="请输入数量"
rules={[{ required: true, message: '请输入数量' }]}
fieldProps={{
precision: 0,
}}
/>
</ProForm.Group>
</ProFormList>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<ProForm.Group
title="发货信息"
extra={
<AddressPicker
onChange={({
address,
phone_number,
phone_number_extension,
stockPointId,
}) => {
formRef?.current?.setFieldsValue({
stockPointId,
details: {
origin: {
address,
phone_number: {
phone: phone_number,
extension: phone_number_extension,
},
},
},
});
}}
/>
}
>
<ProFormSelect
name="stockPointId"
width="md"
label="发货仓库点"
placeholder="请选择仓库点"
rules={[{ required: true, message: '请选择发货仓库点' }]}
request={async () => {
const { data = [] } = await stockcontrollerGetallstockpoints();
return data.map((item) => ({
label: item.name,
value: item.id,
}));
}}
/>
<ProFormText
label="公司名称"
name={['details', 'origin', 'name']}
rules={[{ required: true, message: '请输入公司名称' }]}
/>
<ProFormItem
name={['details', 'origin', 'address', 'country']}
label="国家"
initialValue={'CA'}
hidden
/>
<ProFormSelect
name={['details', 'origin', 'address', 'region']}
label="地区"
placeholder={'请选择地区'}
showSearch
required
valueEnum={region}
rules={[{ required: true, message: '请选择地区' }]}
/>
<ProFormText
name={['details', 'origin', 'address', 'city']}
label="城市"
placeholder="请输入城市"
required
rules={[{ required: true, message: '请输入城市' }]}
/>
<ProFormText
name={['details', 'origin', 'address', 'postal_code']}
label="邮编"
placeholder="请输入邮编"
required
rules={[{ required: true, message: '请输入邮编' }]}
/>
<ProFormText
name={['details', 'origin', 'address', 'address_line_1']}
label="详细地址"
placeholder="请输入详细地址"
width="lg"
required
rules={[{ required: true, message: '请输入详细地址' }]}
/>
<ProFormText
label="联系人"
name={['details', 'origin', 'contact_name']}
rules={[{ required: true, message: '请输入联系人' }]}
/>
<ProFormItem
name={['details', 'origin', 'phone_number']}
label="联系电话"
required
rules={[
{
required: true,
async validator(_, value) {
if (!value?.phone) {
return Promise.reject('请输入联系电话');
}
return Promise.resolve();
},
},
]}
>
<InternationalPhoneInput />
</ProFormItem>
<ProFormText
label="邮箱"
tooltip="多个邮箱用英文逗号隔开"
name={['details', 'origin', 'email_addresses']}
rules={[{ required: true, message: '请输入邮箱' }]}
/>
</ProForm.Group>
</Col>
<Col span={12}>
<ProForm.Group title="收货信息">
<ProFormText
label="公司名称"
name={['details', 'destination', 'name']}
rules={[{ required: true, message: '请输入公司名称' }]}
/>
<ProFormItem
name={['details', 'destination', 'address', 'country']}
label="国家"
initialValue={'CA'}
hidden
/>
<ProFormSelect
name={['details', 'destination', 'address', 'region']}
label="地区"
placeholder={'请选择地区'}
showSearch
required
valueEnum={region}
rules={[{ required: true, message: '请选择地区' }]}
/>
<ProFormText
name={['details', 'destination', 'address', 'city']}
label="城市"
placeholder="请输入城市"
required
rules={[{ required: true, message: '请输入城市' }]}
/>
<ProFormText
name={['details', 'destination', 'address', 'postal_code']}
label="邮编"
placeholder="请输入邮编"
required
rules={[{ required: true, message: '请输入邮编' }]}
/>
<ProFormText
name={['details', 'destination', 'address', 'address_line_1']}
label="详细地址1"
placeholder="请输入详细地址"
width="lg"
required
rules={[{ required: true, message: '请输入详细地址' }]}
/>
<ProFormText
name={['details', 'destination', 'address', 'address_line_2']}
label="详细地址2"
placeholder="请输入详细地址"
width="lg"
/>
<ProFormText
label="联系人"
name={['details', 'destination', 'contact_name']}
rules={[{ required: true, message: '请输入联系人' }]}
/>
<ProFormItem
name={['details', 'destination', 'phone_number']}
label="联系电话"
required
rules={[
{
required: true,
async validator(_, value) {
if (!value?.phone) {
return Promise.reject('请输入联系电话');
}
return Promise.resolve();
},
},
]}
>
<InternationalPhoneInput />
</ProFormItem>
<ProFormText
label="邮箱"
tooltip="多个邮箱用英文逗号隔开"
name={['details', 'destination', 'email_addresses']}
rules={[{ required: true, message: '请输入邮箱' }]}
/>
</ProForm.Group>
<ProFormRadio.Group
name={['details', 'destination', 'signature_requirement']}
label="签收"
options={[
{ label: '否', value: 'not-required' },
{ label: '是', value: 'required' },
{ label: '成人签收', value: 'adult-required' },
]}
/>
</Col>
</Row>
<ProFormDatePicker
name={['details', 'expected_ship_date']}
label="预计发货日期"
rules={[{ required: true, message: '请选择预计发货日期' }]}
fieldProps={{
disabledDate: (current) => {
return current && current < dayjs().startOf('day');
},
}}
transform={(value) => {
return {
details: {
expected_ship_date: {
year: dayjs(value).year(),
month: dayjs(value).month() + 1,
day: dayjs(value).date(),
},
},
};
}}
/>
<ProFormRadio.Group
name={['details', 'packaging_type']}
label="包装类型"
options={[
{ label: '木托', value: 'pallet', disabled: true },
{ label: '纸箱', value: 'package' },
{ label: '文件袋', value: 'courier-pak', disabled: true },
{ label: '信封', value: 'envelope', disabled: true },
]}
/>
<ProFormDependency name={[['details', 'packaging_type']]}>
{({ details: { packaging_type } }) => {
if (packaging_type === 'package') {
return (
<ProFormList
min={1}
max={1}
label="纸箱尺寸"
name={['details', 'packaging_properties', 'packages']}
rules={[
{
required: true,
validator: (_, value) =>
value && value.length > 0
? Promise.resolve()
: Promise.reject('至少选择一个包裹'),
},
]}
>
{(f, idx, action) => {
return (
<ProForm.Item label={`纸箱${idx + 1}`}>
<Radio.Group>
<Radio.Button
onClick={() => {
action.setCurrentRowData({
measurements: {
weight: {
unit: 'lb',
value: 1,
},
cuboid: {
unit: 'in',
l: 6,
w: 4,
h: 4,
},
},
});
}}
>
1
</Radio.Button>
<Radio.Button
onClick={() => {
action.setCurrentRowData({
measurements: {
weight: {
unit: 'lb',
value: 5,
},
cuboid: {
unit: 'in',
l: 8,
w: 6,
h: 6,
},
},
});
}}
>
2
</Radio.Button>
<Radio.Button
onClick={() => {
action.setCurrentRowData({
measurements: {
weight: {
unit: 'lb',
value: 5,
},
cuboid: {
unit: 'in',
l: 12,
w: 8,
h: 6,
},
},
});
}}
>
3
</Radio.Button>
</Radio.Group>
</ProForm.Item>
);
}}
<ProForm.Group>
<ProFormDigit
label="长"
name={['measurements', 'cuboid', 'l']}
placeholder="请输入长"
rules={[{ required: true, message: '请输入长' }]}
/>
<ProFormDigit
label="宽"
name={['measurements', 'cuboid', 'w']}
placeholder="请输入宽"
rules={[{ required: true, message: '请输入宽' }]}
/>
<ProFormDigit
label="高"
name={['measurements', 'cuboid', 'h']}
placeholder="请输入高"
rules={[{ required: true, message: '请输入高' }]}
/>
<ProFormSelect
label="单位"
name={['measurements', 'cuboid', 'unit']}
valueEnum={{
CM: '厘米',
IN: '英寸',
}}
placeholder="请输入单位"
rules={[{ required: true, message: '请输入单位' }]}
/>
</ProForm.Group>
<ProForm.Group>
<ProFormDigit
label="重量"
name={['measurements', 'weight', 'value']}
placeholder="请输入重量"
rules={[{ required: true, message: '请输入重量' }]}
/>
<ProFormSelect
label="单位"
name={['measurements', 'weight', 'unit']}
valueEnum={{ KGS: '千克', LBS: '磅' }}
// valueEnum={{ KGS: '千克', LBS: '磅', OZS: '盎司' }}
placeholder="请输入单位"
rules={[{ required: true, message: '请输入单位' }]}
/>
<ProFormText
label="描述"
name="description"
placeholder="请输入描述"
width="lg"
// rules={[{ required: true, message: '请输入描述' }]}
/>
</ProForm.Group>
</ProFormList>
);
}
if (packaging_type === 'courier-pak') {
return (
<ProFormList
label="文件袋"
name={['details', 'packaging_properties', 'courier_paks']}
rules={[
{
required: true,
validator: (_, value) =>
value && value.length > 0
? Promise.resolve()
: Promise.reject('至少选择一个'),
},
]}
>
<ProForm.Group>
<ProFormDigit
label="重量"
name={['weight', 'value']}
placeholder="请输入重量"
rules={[{ required: true, message: '请输入重量' }]}
/>
<ProFormSelect
label="单位"
name={['weight', 'unit']}
valueEnum={{ kg: '千克', lb: '磅' }}
// valueEnum={{ kg: '千克', lb: '磅', oz: '盎司' }}
placeholder="请输入单位"
rules={[{ required: true, message: '请输入单位' }]}
/>
<ProFormText
label="描述"
name="description"
placeholder="请输入描述"
width="lg"
rules={[{ required: true, message: '请输入描述' }]}
/>
</ProForm.Group>
</ProFormList>
);
}
}}
</ProFormDependency>
<Button
loading={ratesLoading}
onClick={async () => {
try {
const { customer_note, notes, items, details, externalOrderId, ...data } = formRef.current?.getFieldsValue();
const originEmail = details.origin.email_addresses;
const destinationEmail = details.destination.email_addresses;
details.origin.email_addresses =
details.origin.email_addresses.split(',');
details.destination.email_addresses =
details.destination.email_addresses.split(',');
details.destination.phone_number.number =
details.destination.phone_number.phone;
details.origin.phone_number.number = details.origin.phone_number.phone;
const res =
await logisticscontrollerGetshipmentfee(
{
stockPointId: data.stockPointId,
sender: details.origin.contact_name,
startPhone: details.origin.phone_number,
startPostalCode: details.origin.address.postal_code.replace(/\s/g, ''),
pickupAddress: details.origin.address.address_line_1,
shipperCountryCode: details.origin.address.country,
receiver: details.destination.contact_name,
city: details.destination.address.city,
province: details.destination.address.region,
country: details.destination.address.country,
postalCode: details.destination.address.postal_code.replace(/\s/g, ''),
deliveryAddress: details.destination.address.address_line_1,
receiverPhone: details.destination.phone_number.number,
receiverEmail: details.destination.email_addresses,
length: details.packaging_properties.packages[0].measurements.cuboid.l,
width: details.packaging_properties.packages[0].measurements.cuboid.w,
height: details.packaging_properties.packages[0].measurements.cuboid.h,
dimensionUom: details.packaging_properties.packages[0].measurements.cuboid.unit,
weight: details.packaging_properties.packages[0].measurements.weight.value,
weightUom: details.packaging_properties.packages[0].measurements.weight.unit,
},
);
if (!res?.success) throw new Error(res?.message);
const fee = res.data;
setShipmentFee(fee);
details.origin.email_addresses = originEmail;
details.destination.email_addresses = destinationEmail;
formRef.current?.setFieldValue("details", {
...details,
shipmentFee: fee
});
message.success('获取运费成功');
} catch (error) {
message.error(error?.message || '获取运费失败');
}
}}
>
</Button>
<ProFormText
readonly
name={["details", "shipmentFee"]}
fieldProps={{
value: (shipmentFee / 100.0).toFixed(2)
}}
/>
</ModalForm>
);
};
const SalesChange: React.FC<{
id: number;
detailRef?: React.MutableRefObject<ActionType | undefined>;
reShipping?: boolean;
}> = ({ id, detailRef }) => {
const formRef = useRef<ProFormInstance>();
return (
<ModalForm
formRef={formRef}
title="换货"
size="large"
width="80vw"
modalProps={{
destroyOnHidden: true,
styles: {
body: { maxHeight: '65vh', overflowY: 'auto', overflowX: 'hidden' },
},
}}
trigger={
<Button type="primary">
<CodeSandboxOutlined />
</Button>
}
request={async () => {
const { data, success }: API.OrderDetailRes =
await ordercontrollerGetorderdetail({
orderId: id,
});
if (!success || !data) return {};
data.sales = data.sales?.reduce((acc: API.OrderSale[], cur: API.OrderSale) => {
let idx = acc.findIndex((v: any) => v.productId === cur.productId);
if (idx === -1) {
acc.push(cur);
} else {
acc[idx].quantity += cur.quantity;
}
return acc;
},
[],
);
// setOptions(
// data.sales?.map((item) => ({
// label: item.name,
// value: item.sku,
// })) || [],
// );
return { ...data};
}}
onFinish={async (formData: any) => {
const { sales,items } = formData;
const data ={sales,items }
const res = await ordercontrollerUpdateorderitems({orderId:id}, data);
if (!res.success) {
message.error(`更新货物信息失败: ${res.message}`);
return false;
}
message.success('更新成功')
detailRef?.current?.reload();
return true;
}}
>
<ProFormList
label="换货订单"
name="items"
>
<ProForm.Group>
<ProFormSelect
params={{ }}
request={async ({ keyWords }) => {
try {
const { data } = await wpproductcontrollerSearchproducts({
name: keyWords,
});
return (
data?.map((item) => {
return {
label: `${item.name}`,
value: item?.sku,
};
})
);
} catch (error) {
return [];
}
}}
name="sku"
label="订单"
placeholder="请选择订单"
tooltip="至少输入3个字符"
fieldProps={{
showSearch: true,
filterOption: false,
}}
debounceTime={300} // 防抖减少请求频率
rules={[{ required: true, message: '请选择订单' }]}
/>
<ProFormDigit
name="quantity"
colProps={{ span: 12 }}
label="订单数量"
placeholder="请输入数量"
rules={[{ required: true, message: '请输入数量' }]}
fieldProps={{
precision: 0,
}}
/>
</ProForm.Group>
</ProFormList>
<ProFormList
label="换货产品"
name="sales"
>
<ProForm.Group>
<ProFormSelect
params={{ }}
request={async ({ keyWords }) => {
try {
const { data } = await productcontrollerSearchproducts({
name: keyWords,
});
return (
data?.map((item) => {
return {
label: `${item.name} - ${item.nameCn}`,
value: item?.sku,
};
})
);
} catch (error) {
return [];
}
}}
name="sku"
label="产品"
placeholder="请选择产品"
tooltip="至少输入3个字符"
fieldProps={{
showSearch: true,
filterOption: false,
}}
debounceTime={300} // 防抖减少请求频率
rules={[{ required: true, message: '请选择产品' }]}
/>
<ProFormDigit
name="quantity"
colProps={{ span: 12 }}
label="数量"
placeholder="请输入数量"
rules={[{ required: true, message: '请输入数量' }]}
fieldProps={{
precision: 0,
}}
/>
</ProForm.Group>
</ProFormList>
</ModalForm>
);
}
const CreateOrder: React.FC<{
tableRef?: React.MutableRefObject<ActionType | undefined>;
}> = ({ tableRef }) => {
const formRef = useRef<ProFormInstance>();
const { message } = App.useApp();
return (
<ModalForm
formRef={formRef}
title="创建订单"
size="large"
width="80vw"
modalProps={{
destroyOnHidden: true,
styles: {
body: { maxHeight: '65vh', overflowY: 'auto', overflowX: 'hidden' },
},
}}
trigger={
<Button type="primary">
<CodeSandboxOutlined />
</Button>
}
params={{
source_type: 'admin',
}}
onFinish={async ({ items, details, ...data }) => {
try {
const { success, message: errMsg } = await ordercontrollerCreateorder(
{
...data,
customer_email: data?.billing?.email,
billing_phone: data?.billing?.phone,
},
);
if (!success) throw new Error(errMsg);
message.success('创建成功');
tableRef?.current?.reload();
return true;
} catch (error) {
message.error(error?.message || '创建失败');
}
}}
onFinishFailed={() => {
const element = document.querySelector('.ant-form-item-explain-error');
if (element) {
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
}}
>
<ProFormList label="订单内容" name="sales">
<ProForm.Group>
<ProFormSelect
request={async ({ keyWords, options }) => {
if (!keyWords || keyWords.length < 2) return options;
try {
const { data } = await productcontrollerSearchproducts({
name: keyWords,
});
return (
data?.map((item) => {
return {
label: `${item.name} - ${item.nameCn}`,
value: item?.sku,
};
}) || options
);
} catch (error) {
return options;
}
}}
name="sku"
label="产品"
placeholder="请选择产品"
tooltip="至少输入3个字符"
fieldProps={{
showSearch: true,
filterOption: false,
}}
debounceTime={300} // 防抖减少请求频率
rules={[{ required: true, message: '请选择产品' }]}
/>
<ProFormDigit
name="quantity"
colProps={{ span: 12 }}
label="数量"
placeholder="请输入数量"
rules={[{ required: true, message: '请输入数量' }]}
fieldProps={{
precision: 0,
}}
/>
</ProForm.Group>
</ProFormList>
<ProFormDigit
label="金额"
name="total"
rules={[{ required: true, message: '请输入金额' }]}
/>
<ProForm.Group title="收货信息">
<ProFormText
label="公司名称"
name={['billing', 'company']}
rules={[{ required: true, message: '请输入公司名称' }]}
/>
<ProFormItem
name={['billing', 'country']}
label="国家"
initialValue={'CA'}
hidden
/>
<ProFormSelect
name={['billing', 'state']}
label="地区"
placeholder={'请选择地区'}
showSearch
required
valueEnum={region}
rules={[{ required: true, message: '请选择地区' }]}
/>
<ProFormText
name={['billing', 'city']}
label="城市"
placeholder="请输入城市"
required
rules={[{ required: true, message: '请输入城市' }]}
/>
<ProFormText
name={['billing', 'postcode']}
label="邮编"
placeholder="请输入邮编"
required
rules={[{ required: true, message: '请输入邮编' }]}
/>
<ProFormText
name={['billing', 'address_1']}
label="详细地址1"
placeholder="请输入详细地址"
width="lg"
required
rules={[{ required: true, message: '请输入详细地址' }]}
/>
<ProFormText
name={['billing', 'address_2']}
label="详细地址2"
placeholder="请输入详细地址"
width="lg"
/>
<ProFormText
label="联系人"
name={['billing', 'first_name']}
rules={[{ required: true, message: '请输入联系人' }]}
/>
<ProFormText
name={['billing', 'phone']}
label="联系电话"
required
rules={[{ required: true, message: '请输入联系电话' }]}
/>
<ProFormText
label="邮箱"
name={['billing', 'email']}
rules={[{ required: true, message: '请输入邮箱' }]}
/>
</ProForm.Group>
{/* <ProFormText label="客户邮箱" name="customer_email" /> */}
</ModalForm>
);
};
const AddressPicker: React.FC<{
value?: any;
onChange?: (value: any) => void;
}> = ({ onChange, value }) => {
const [selectedRow, setSelectedRow] = useState(null);
const { message } = App.useApp();
const columns: ProColumns<API.ShippingAddress>[] = [
{
title: '仓库点',
dataIndex: 'stockPointId',
hideInSearch: true,
valueType: 'select',
request: async () => {
const { data = [] } = await stockcontrollerGetallstockpoints();
return data.map((item) => ({
label: item.name,
value: item.id,
}));
},
},
{
title: '地区',
dataIndex: ['address', 'region'],
hideInSearch: true,
},
{
title: '城市',
dataIndex: ['address', 'city'],
hideInSearch: true,
},
{
title: '邮编',
dataIndex: ['address', 'postal_code'],
hideInSearch: true,
},
{
title: '详细地址',
dataIndex: ['address', 'address_line_1'],
hideInSearch: true,
},
{
title: '联系电话',
render: (_, record) =>
`+${record.phone_number_extension} ${record.phone_number}`,
hideInSearch: true,
},
];
return (
<ModalForm
title="选择地址"
trigger={<Button type="primary"></Button>}
modalProps={{ destroyOnHidden: true }}
onFinish={async () => {
if (!selectedRow) {
message.error('请选择地址');
return false;
}
if (onChange) onChange(selectedRow);
return true;
}}
>
<ProTable
rowKey="id"
request={async () => {
const { data, success } =
await logisticscontrollerGetshippingaddresslist();
if (success) {
return {
data: data,
};
}
return {
data: [],
};
}}
columns={columns}
search={false}
rowSelection={{
type: 'radio',
onChange: (_, selectedRows) => {
setSelectedRow(selectedRows[0]);
},
}}
/>
</ModalForm>
);
};
export default ListPage;