feat(Shop): 添加批量编辑功能和多处界面优化
refactor(Orders): 重构订单详情为编辑表单并添加批量编辑 feat(Customers): 实现客户批量编辑功能 feat(Logistics): 添加批量删除和批量打印功能 feat(SiteList): 实现站点数据同步功能 style(Forms): 优化表单按钮样式和布局
This commit is contained in:
parent
db0bea991c
commit
d40f157b78
|
|
@ -10,7 +10,7 @@ import {
|
|||
ProTable,
|
||||
} from '@ant-design/pro-components';
|
||||
import { request } from '@umijs/max';
|
||||
import { Button, message, Popconfirm, Space, Tag } from 'antd';
|
||||
import { Button, message, notification, Popconfirm, Space, Tag } from 'antd';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
|
||||
// 区域数据项类型
|
||||
|
|
@ -58,6 +58,62 @@ const SiteList: React.FC = () => {
|
|||
const formRef = useRef<ProFormInstance>();
|
||||
const [open, setOpen] = useState(false);
|
||||
const [editing, setEditing] = useState<SiteItem | null>(null);
|
||||
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
||||
|
||||
const handleSync = async (ids: number[]) => {
|
||||
if (!ids.length) return;
|
||||
const hide = message.loading('正在同步...', 0);
|
||||
|
||||
const stats = {
|
||||
products: { success: 0, fail: 0 },
|
||||
orders: { success: 0, fail: 0 },
|
||||
subscriptions: { success: 0, fail: 0 },
|
||||
};
|
||||
|
||||
try {
|
||||
for (const id of ids) {
|
||||
// 同步产品
|
||||
const prodRes = await request(`/wp_product/sync/${id}`, { method: 'POST' });
|
||||
if (prodRes) {
|
||||
stats.products.success += prodRes.successCount || 0;
|
||||
stats.products.fail += prodRes.failureCount || 0;
|
||||
}
|
||||
|
||||
// 同步订单
|
||||
const orderRes = await request(`/order/syncOrder/${id}`, { method: 'POST' });
|
||||
if (orderRes) {
|
||||
stats.orders.success += orderRes.successCount || 0;
|
||||
stats.orders.fail += orderRes.failureCount || 0;
|
||||
}
|
||||
|
||||
// 同步订阅
|
||||
const subRes = await request(`/subscription/sync/${id}`, { method: 'POST' });
|
||||
if (subRes) {
|
||||
stats.subscriptions.success += subRes.successCount || 0;
|
||||
stats.subscriptions.fail += subRes.failureCount || 0;
|
||||
}
|
||||
}
|
||||
hide();
|
||||
|
||||
notification.success({
|
||||
message: '同步完成',
|
||||
description: (
|
||||
<div>
|
||||
<p>产品: 成功 {stats.products.success}, 失败 {stats.products.fail}</p>
|
||||
<p>订单: 成功 {stats.orders.success}, 失败 {stats.orders.fail}</p>
|
||||
<p>订阅: 成功 {stats.subscriptions.success}, 失败 {stats.subscriptions.fail}</p>
|
||||
</div>
|
||||
),
|
||||
duration: null, // 不自动关闭
|
||||
});
|
||||
|
||||
setSelectedRowKeys([]);
|
||||
actionRef.current?.reload();
|
||||
} catch (error: any) {
|
||||
hide();
|
||||
message.error(error.message || '同步失败');
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
|
|
@ -174,6 +230,13 @@ const SiteList: React.FC = () => {
|
|||
hideInSearch: true,
|
||||
render: (_, row) => (
|
||||
<Space>
|
||||
<Button
|
||||
size="small"
|
||||
type="primary"
|
||||
onClick={() => handleSync([row.id])}
|
||||
>
|
||||
同步
|
||||
</Button>
|
||||
<Button
|
||||
size="small"
|
||||
onClick={() => {
|
||||
|
|
@ -321,6 +384,10 @@ const SiteList: React.FC = () => {
|
|||
rowKey="id"
|
||||
columns={columns}
|
||||
request={tableRequest}
|
||||
rowSelection={{
|
||||
selectedRowKeys,
|
||||
onChange: setSelectedRowKeys,
|
||||
}}
|
||||
toolBarRender={() => [
|
||||
<Button
|
||||
key="new"
|
||||
|
|
@ -333,10 +400,14 @@ const SiteList: React.FC = () => {
|
|||
新增站点
|
||||
</Button>,
|
||||
// 同步包括 orders subscriptions 等等
|
||||
<Button key='new' disabled type='primary' onClick={()=> {
|
||||
}}>
|
||||
<Button
|
||||
key="sync"
|
||||
disabled={!selectedRowKeys.length}
|
||||
type="primary"
|
||||
onClick={() => handleSync(selectedRowKeys as number[])}
|
||||
>
|
||||
同步站点数据
|
||||
</Button>
|
||||
</Button>,
|
||||
]}
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,60 @@
|
|||
import { ActionType, DrawerForm, PageContainer, ProColumns, ProFormText, ProTable } from '@ant-design/pro-components';
|
||||
import { ActionType, DrawerForm, ModalForm, PageContainer, ProColumns, ProFormText, ProTable } from '@ant-design/pro-components';
|
||||
import { request, useParams } from '@umijs/max';
|
||||
import { App, Avatar, Button, Popconfirm, Space, Tag } from 'antd';
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { DeleteFilled, EditOutlined, PlusOutlined, UserOutlined } from '@ant-design/icons';
|
||||
|
||||
const BatchEditCustomers: React.FC<{
|
||||
tableRef: React.MutableRefObject<ActionType | undefined>;
|
||||
selectedRowKeys: React.Key[];
|
||||
setSelectedRowKeys: (keys: React.Key[]) => void;
|
||||
siteId?: string;
|
||||
}> = ({ tableRef, selectedRowKeys, setSelectedRowKeys, siteId }) => {
|
||||
const { message } = App.useApp();
|
||||
return (
|
||||
<ModalForm
|
||||
title="批量编辑客户"
|
||||
trigger={
|
||||
<Button
|
||||
disabled={!selectedRowKeys.length}
|
||||
type="primary"
|
||||
icon={<EditOutlined />}
|
||||
>
|
||||
批量编辑
|
||||
</Button>
|
||||
}
|
||||
width={400}
|
||||
modalProps={{ destroyOnHidden: true }}
|
||||
onFinish={async (values) => {
|
||||
if (!siteId) return false;
|
||||
let ok = 0, fail = 0;
|
||||
for (const id of selectedRowKeys) {
|
||||
try {
|
||||
// Remove undefined values
|
||||
const data = Object.fromEntries(Object.entries(values).filter(([_, v]) => v !== undefined && v !== ''));
|
||||
if (Object.keys(data).length === 0) continue;
|
||||
|
||||
const res = await request(`/site-api/${siteId}/customers/${id}`, {
|
||||
method: 'PUT',
|
||||
data: data,
|
||||
});
|
||||
if (res.success) ok++;
|
||||
else fail++;
|
||||
} catch (e) {
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
message.success(`成功 ${ok}, 失败 ${fail}`);
|
||||
tableRef.current?.reload();
|
||||
setSelectedRowKeys([]);
|
||||
return true;
|
||||
}}
|
||||
>
|
||||
<ProFormText name="role" label="角色" placeholder="请输入角色,不修改请留空" />
|
||||
</ModalForm>
|
||||
);
|
||||
};
|
||||
|
||||
const CustomerPage: React.FC = () => {
|
||||
const { message } = App.useApp();
|
||||
const { siteId } = useParams<{ siteId: string }>();
|
||||
|
|
@ -167,10 +218,11 @@ const CustomerPage: React.FC = () => {
|
|||
<ProFormText name="last_name" label="姓" />
|
||||
<ProFormText name="username" label="用户名" />
|
||||
</DrawerForm>,
|
||||
<Button
|
||||
title="批量编辑"
|
||||
icon={<EditOutlined />}
|
||||
onClick={() => message.info('批量编辑暂未实现')}
|
||||
<BatchEditCustomers
|
||||
tableRef={actionRef}
|
||||
selectedRowKeys={selectedRowKeys}
|
||||
setSelectedRowKeys={setSelectedRowKeys}
|
||||
siteId={siteId}
|
||||
/>,
|
||||
<Button
|
||||
title="批量删除"
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import {
|
|||
ProTable,
|
||||
} from '@ant-design/pro-components';
|
||||
import { useParams } from '@umijs/max';
|
||||
import { App, Button, Divider, Popconfirm } from 'antd';
|
||||
import { App, Button, Divider, Popconfirm, Space } from 'antd';
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { ToastContainer } from 'react-toastify';
|
||||
|
||||
|
|
@ -198,16 +198,40 @@ const LogisticsPage: React.FC = () => {
|
|||
success: false,
|
||||
};
|
||||
}}
|
||||
// rowSelection={{
|
||||
// selectedRowKeys: selectedRows.map((row) => row.id),
|
||||
// onChange: (_, selectedRows) => setSelectedRows(selectedRows),
|
||||
// }}
|
||||
rowSelection={{
|
||||
selectedRowKeys: selectedRows.map((row) => row.id),
|
||||
onChange: (_, selectedRows) => setSelectedRows(selectedRows),
|
||||
}}
|
||||
columns={columns}
|
||||
tableAlertOptionRender={() => {
|
||||
return (
|
||||
<Space>
|
||||
<Button onClick={handleBatchPrint} type="primary">
|
||||
批量打印
|
||||
</Button>
|
||||
<Button
|
||||
danger
|
||||
type="primary"
|
||||
onClick={async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
let ok = 0;
|
||||
for (const row of selectedRows) {
|
||||
const { success } = await logisticscontrollerDeleteshipment({ id: row.id });
|
||||
if (success) ok++;
|
||||
}
|
||||
message.success(`成功删除 ${ok} 条`);
|
||||
setIsLoading(false);
|
||||
actionRef.current?.reload();
|
||||
setSelectedRows([]);
|
||||
} catch (e) {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
批量删除
|
||||
</Button>
|
||||
</Space>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import {
|
|||
Tag,
|
||||
} from 'antd';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { CreateOrder, Detail, OrderNote, Shipping } from '../components/Order/Forms';
|
||||
import { BatchEditOrders, CreateOrder, EditOrder, OrderNote, Shipping } from '../components/Order/Forms';
|
||||
import { DeleteFilled } from '@ant-design/icons';
|
||||
|
||||
const OrdersPage: React.FC = () => {
|
||||
|
|
@ -122,9 +122,20 @@ const OrdersPage: React.FC = () => {
|
|||
render: (_, record) => record.shipping?.phone || record.billing?.phone,
|
||||
},
|
||||
{
|
||||
title: '州',
|
||||
title: '账单地址',
|
||||
dataIndex: 'billing_full_address',
|
||||
hideInSearch: true,
|
||||
render: (_, record) => record.shipping?.state || record.billing?.state,
|
||||
width: 200,
|
||||
ellipsis: true,
|
||||
copyable: true,
|
||||
},
|
||||
{
|
||||
title: '收货地址',
|
||||
dataIndex: 'shipping_full_address',
|
||||
hideInSearch: true,
|
||||
width: 200,
|
||||
ellipsis: true,
|
||||
copyable: true,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
|
|
@ -135,7 +146,7 @@ const OrdersPage: React.FC = () => {
|
|||
render: (_, record) => {
|
||||
return (
|
||||
<>
|
||||
<Detail
|
||||
<EditOrder
|
||||
key={record.id}
|
||||
record={record}
|
||||
tableRef={actionRef}
|
||||
|
|
@ -152,7 +163,7 @@ const OrdersPage: React.FC = () => {
|
|||
key: 'history',
|
||||
label: (
|
||||
<HistoryOrder
|
||||
email={record.email}
|
||||
email={(record as any).email}
|
||||
tableRef={actionRef}
|
||||
/>
|
||||
),
|
||||
|
|
@ -165,10 +176,8 @@ const OrdersPage: React.FC = () => {
|
|||
}}
|
||||
>
|
||||
<a onClick={(e) => e.preventDefault()}>
|
||||
<Space>
|
||||
更多
|
||||
<DownOutlined />
|
||||
</Space>
|
||||
<Button type="link" icon={<DownOutlined />}>
|
||||
</Button>
|
||||
</a>
|
||||
</Dropdown>
|
||||
<Divider type="vertical" />
|
||||
|
|
@ -217,6 +226,12 @@ const OrdersPage: React.FC = () => {
|
|||
}}
|
||||
toolBarRender={() => [
|
||||
<CreateOrder tableRef={actionRef} siteId={siteId} />,
|
||||
<BatchEditOrders
|
||||
tableRef={actionRef}
|
||||
selectedRowKeys={selectedRowKeys}
|
||||
setSelectedRowKeys={setSelectedRowKeys}
|
||||
siteId={siteId}
|
||||
/>,
|
||||
<Button
|
||||
title="批量删除"
|
||||
danger
|
||||
|
|
|
|||
|
|
@ -216,7 +216,7 @@ const ProductsPage: React.FC = () => {
|
|||
];
|
||||
|
||||
return (
|
||||
<PageContainer>
|
||||
<PageContainer header={{ title: null, breadcrumb: undefined }}>
|
||||
<ProTable<any>
|
||||
scroll={{ x: 'max-content' }}
|
||||
pagination={{
|
||||
|
|
|
|||
|
|
@ -15,11 +15,13 @@ import {
|
|||
CodeSandboxOutlined,
|
||||
CopyOutlined,
|
||||
DeleteFilled,
|
||||
EditOutlined,
|
||||
FileDoneOutlined,
|
||||
TagsOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import {
|
||||
ActionType,
|
||||
DrawerForm,
|
||||
ModalForm,
|
||||
ProColumns,
|
||||
ProDescriptions,
|
||||
|
|
@ -78,7 +80,11 @@ export const OrderNote: React.FC<{
|
|||
return (
|
||||
<ModalForm
|
||||
title="添加备注"
|
||||
trigger={<Button type="primary" ghost title="备注" icon={<TagsOutlined />} />}
|
||||
trigger={
|
||||
<Button type="primary" ghost size="small" icon={<TagsOutlined />}>
|
||||
备注
|
||||
</Button>
|
||||
}
|
||||
onFinish={async (values: any) => {
|
||||
if (!siteId) {
|
||||
message.error('缺少站点ID');
|
||||
|
|
@ -236,12 +242,14 @@ export const Shipping: React.FC<{
|
|||
trigger={
|
||||
<Button
|
||||
type="primary"
|
||||
title="创建运单"
|
||||
size="small"
|
||||
icon={<CodeSandboxOutlined />}
|
||||
onClick={() => {
|
||||
setActiveLine(id);
|
||||
}}
|
||||
/>
|
||||
>
|
||||
发货
|
||||
</Button>
|
||||
}
|
||||
request={async () => {
|
||||
if (!siteId) return {};
|
||||
|
|
@ -569,7 +577,11 @@ export const CreateOrder: React.FC<{
|
|||
body: { maxHeight: '65vh', overflowY: 'auto', overflowX: 'hidden' },
|
||||
},
|
||||
}}
|
||||
trigger={<Button type="primary" title="创建订单" icon={<CodeSandboxOutlined />} />}
|
||||
trigger={
|
||||
<Button type="primary" size="small" icon={<CodeSandboxOutlined />}>
|
||||
创建订单
|
||||
</Button>
|
||||
}
|
||||
params={{
|
||||
source_type: 'admin',
|
||||
}}
|
||||
|
|
@ -618,26 +630,95 @@ export const CreateOrder: React.FC<{
|
|||
);
|
||||
};
|
||||
|
||||
export const Detail: React.FC<{
|
||||
export const BatchEditOrders: React.FC<{
|
||||
tableRef: React.MutableRefObject<ActionType | undefined>;
|
||||
selectedRowKeys: React.Key[];
|
||||
setSelectedRowKeys: (keys: React.Key[]) => void;
|
||||
siteId?: string;
|
||||
}> = ({ tableRef, selectedRowKeys, setSelectedRowKeys, siteId }) => {
|
||||
const { message } = App.useApp();
|
||||
return (
|
||||
<ModalForm
|
||||
title="批量编辑订单"
|
||||
trigger={
|
||||
<Button
|
||||
disabled={!selectedRowKeys.length}
|
||||
type="primary"
|
||||
icon={<EditOutlined />}
|
||||
>
|
||||
批量编辑
|
||||
</Button>
|
||||
}
|
||||
width={400}
|
||||
modalProps={{ destroyOnHidden: true }}
|
||||
onFinish={async (values) => {
|
||||
if (!siteId) return false;
|
||||
let ok = 0, fail = 0;
|
||||
for (const id of selectedRowKeys) {
|
||||
try {
|
||||
// Remove undefined values
|
||||
const data = Object.fromEntries(Object.entries(values).filter(([_, v]) => v !== undefined && v !== ''));
|
||||
if (Object.keys(data).length === 0) continue;
|
||||
|
||||
const res = await request(`/site-api/${siteId}/orders/${id}`, {
|
||||
method: 'PUT',
|
||||
data: data,
|
||||
});
|
||||
if (res.success) ok++;
|
||||
else fail++;
|
||||
} catch (e) {
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
message.success(`成功 ${ok}, 失败 ${fail}`);
|
||||
tableRef.current?.reload();
|
||||
setSelectedRowKeys([]);
|
||||
return true;
|
||||
}}
|
||||
>
|
||||
<ProFormSelect
|
||||
name="status"
|
||||
label="状态"
|
||||
valueEnum={ORDER_STATUS_ENUM}
|
||||
placeholder="不修改请留空"
|
||||
/>
|
||||
</ModalForm>
|
||||
);
|
||||
};
|
||||
|
||||
export const EditOrder: React.FC<{
|
||||
tableRef: React.MutableRefObject<ActionType | undefined>;
|
||||
orderId: number;
|
||||
record: API.Order;
|
||||
setActiveLine: Function;
|
||||
siteId?: string;
|
||||
}> = ({ tableRef, orderId, record, setActiveLine, siteId }) => {
|
||||
const [visiable, setVisiable] = useState(false);
|
||||
const { message } = App.useApp();
|
||||
const ref = useRef<ActionType>();
|
||||
const formRef = useRef<ProFormInstance>();
|
||||
|
||||
const initRequest = async () => {
|
||||
if (!siteId) return { data: {} };
|
||||
|
||||
// Fetch detail from site-api
|
||||
return (
|
||||
<DrawerForm
|
||||
formRef={formRef}
|
||||
title="编辑订单"
|
||||
trigger={
|
||||
<Button
|
||||
type="primary"
|
||||
size="small"
|
||||
icon={<EditOutlined />}
|
||||
onClick={() => setActiveLine(record.id)}
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
}
|
||||
drawerProps={{
|
||||
destroyOnHidden: true,
|
||||
width: '60vw',
|
||||
}}
|
||||
request={async () => {
|
||||
if (!siteId) return {};
|
||||
const { data, success } = await request(`/site-api/${siteId}/orders/${orderId}`);
|
||||
if (!success || !data) return {};
|
||||
|
||||
if (!success || !data) return { data: {} };
|
||||
|
||||
// Merge sales logic
|
||||
const sales = data.sales || [];
|
||||
const mergedSales = sales.reduce(
|
||||
(acc: any[], cur: any) => {
|
||||
|
|
@ -653,59 +734,90 @@ export const Detail: React.FC<{
|
|||
);
|
||||
data.sales = mergedSales;
|
||||
|
||||
return {
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
key="detail"
|
||||
type="primary"
|
||||
title="详情"
|
||||
icon={<FileDoneOutlined />}
|
||||
onClick={() => {
|
||||
setVisiable(true);
|
||||
setActiveLine(record.id);
|
||||
return data;
|
||||
}}
|
||||
onFinish={async (values) => {
|
||||
if (!siteId) return false;
|
||||
try {
|
||||
const res = await request(`/site-api/${siteId}/orders/${orderId}`, {
|
||||
method: 'PUT',
|
||||
data: values
|
||||
});
|
||||
if (res.success) {
|
||||
message.success('更新成功');
|
||||
tableRef.current?.reload();
|
||||
return true;
|
||||
}
|
||||
message.error(res.message || '更新失败');
|
||||
return false;
|
||||
} catch(e: any) {
|
||||
message.error(e.message || '更新失败');
|
||||
return false;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Drawer
|
||||
title="订单详情"
|
||||
open={visiable}
|
||||
destroyOnHidden
|
||||
size="large"
|
||||
onClose={() => setVisiable(false)}
|
||||
footer={[
|
||||
<OrderNote id={orderId} descRef={ref} siteId={siteId} />,
|
||||
// ... Removed Sync Button and Status change buttons (they used local controller)
|
||||
// We can re-enable them if we implement status change in site-api
|
||||
// I didn't implement status change (updateOrder) in controller yet.
|
||||
// Wait, I implemented `updateOrder`? No, I implemented `getOrders`, `getOrder`.
|
||||
// I missed `updateOrder`!
|
||||
// But I implemented `updateProduct`.
|
||||
// I should add `updateOrder` if I want to support status change.
|
||||
// The user said "Proxy unified forwarding (various CRUD)".
|
||||
// So I should have added `updateOrder`.
|
||||
// But time is tight.
|
||||
// I will disable the buttons for now or leave them (they will fail).
|
||||
// I'll disable them to be safe.
|
||||
]}
|
||||
>
|
||||
<ProDescriptions
|
||||
labelStyle={{ width: '100px' }}
|
||||
actionRef={ref}
|
||||
request={initRequest}
|
||||
<ProForm.Group title="基本信息">
|
||||
<ProFormText name="number" label="订单号" readonly />
|
||||
<ProFormSelect name="status" label="状态" valueEnum={ORDER_STATUS_ENUM} />
|
||||
<ProFormText name="currency" label="币种" readonly />
|
||||
<ProFormText name="payment_method" label="支付方式" readonly />
|
||||
<ProFormText name="transaction_id" label="交易ID" readonly />
|
||||
<ProFormDatePicker name="date_created" label="创建时间" readonly fieldProps={{style: {width: '100%'}}} />
|
||||
</ProForm.Group>
|
||||
|
||||
<Divider />
|
||||
|
||||
<ProForm.Group title="账单地址">
|
||||
<ProFormText name={['billing', 'first_name']} label="名" />
|
||||
<ProFormText name={['billing', 'last_name']} label="姓" />
|
||||
<ProFormText name={['billing', 'company']} label="公司" />
|
||||
<ProFormText name={['billing', 'address_1']} label="地址1" />
|
||||
<ProFormText name={['billing', 'address_2']} label="地址2" />
|
||||
<ProFormText name={['billing', 'city']} label="城市" />
|
||||
<ProFormText name={['billing', 'state']} label="省/州" />
|
||||
<ProFormText name={['billing', 'postcode']} label="邮编" />
|
||||
<ProFormText name={['billing', 'country']} label="国家" />
|
||||
<ProFormText name={['billing', 'email']} label="邮箱" />
|
||||
<ProFormText name={['billing', 'phone']} label="电话" />
|
||||
</ProForm.Group>
|
||||
|
||||
<Divider />
|
||||
|
||||
<ProForm.Group title="收货地址">
|
||||
<ProFormText name={['shipping', 'first_name']} label="名" />
|
||||
<ProFormText name={['shipping', 'last_name']} label="姓" />
|
||||
<ProFormText name={['shipping', 'company']} label="公司" />
|
||||
<ProFormText name={['shipping', 'address_1']} label="地址1" />
|
||||
<ProFormText name={['shipping', 'address_2']} label="地址2" />
|
||||
<ProFormText name={['shipping', 'city']} label="城市" />
|
||||
<ProFormText name={['shipping', 'state']} label="省/州" />
|
||||
<ProFormText name={['shipping', 'postcode']} label="邮编" />
|
||||
<ProFormText name={['shipping', 'country']} label="国家" />
|
||||
<ProFormText name={['shipping', 'phone']} label="电话" />
|
||||
</ProForm.Group>
|
||||
|
||||
<Divider />
|
||||
|
||||
<ProFormTextArea name="customer_note" label="客户备注" />
|
||||
|
||||
<Divider />
|
||||
|
||||
<ProFormList
|
||||
name="sales"
|
||||
label="商品列表"
|
||||
readonly
|
||||
actionRender={() => []}
|
||||
>
|
||||
{/* ... Fields ... */}
|
||||
<ProDescriptions.Item
|
||||
label="订单日期"
|
||||
dataIndex="date_created"
|
||||
valueType="dateTime"
|
||||
/>
|
||||
{/* ... */}
|
||||
</ProDescriptions>
|
||||
</Drawer>
|
||||
</>
|
||||
<ProForm.Group>
|
||||
<ProFormText name="name" label="商品名" />
|
||||
<ProFormText name="sku" label="SKU" />
|
||||
<ProFormDigit name="quantity" label="数量" />
|
||||
<ProFormText name="total" label="总价" />
|
||||
</ProForm.Group>
|
||||
</ProFormList>
|
||||
|
||||
<ProFormText name="total" label="订单总额" readonly />
|
||||
|
||||
</DrawerForm>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
{
|
||||
admin_id: 0,
|
||||
admin_name: "",
|
||||
birthday: 0,
|
||||
contact: "",
|
||||
country_id: 14,
|
||||
created_at: 1765351077,
|
||||
domain: "auspouches.com",
|
||||
email: "daniel.waring81@gmail.com",
|
||||
first_name: "Dan",
|
||||
first_pay_at: 1765351308,
|
||||
gender: 0,
|
||||
id: 44898147,
|
||||
ip: "1.146.111.163",
|
||||
is_cart: 0,
|
||||
is_event_sub: 1,
|
||||
is_sub: 1,
|
||||
is_verified: 1,
|
||||
last_name: "Waring",
|
||||
last_order_id: 236122,
|
||||
login_at: 1765351340,
|
||||
note: "",
|
||||
order_at: 1765351224,
|
||||
orders_count: 1,
|
||||
pay_at: 1765351308,
|
||||
source_device: "phone",
|
||||
tags: [
|
||||
],
|
||||
total_spent: "203.81",
|
||||
updated_at: 1765351515,
|
||||
utm_medium: "referral",
|
||||
utm_source: "checkout.cartadicreditopay.com",
|
||||
visit_at: 1765351513,
|
||||
country: {
|
||||
chinese_name: "澳大利亚",
|
||||
country_code2: "AU",
|
||||
country_name: "Australia",
|
||||
},
|
||||
sysinfo: {
|
||||
user_agent: "Mozilla/5.0 (Linux; Android 16; Pixel 8 Pro Build/BP3A.251105.015; ) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/142.0.7444.212 Mobile Safari/537.36 MetaIAB Facebook",
|
||||
timezone: "Etc/GMT-10",
|
||||
os: "Android",
|
||||
browser: "Pixel 8",
|
||||
language: "en-GB",
|
||||
screen_size: "528X1174",
|
||||
viewport_size: "527X1026",
|
||||
ip: "1.146.111.163",
|
||||
},
|
||||
default_address: [
|
||||
],
|
||||
addresses: [
|
||||
],
|
||||
}
|
||||
Loading…
Reference in New Issue