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,
|
ProTable,
|
||||||
} from '@ant-design/pro-components';
|
} from '@ant-design/pro-components';
|
||||||
import { request } from '@umijs/max';
|
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';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
// 区域数据项类型
|
// 区域数据项类型
|
||||||
|
|
@ -58,6 +58,62 @@ const SiteList: React.FC = () => {
|
||||||
const formRef = useRef<ProFormInstance>();
|
const formRef = useRef<ProFormInstance>();
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [editing, setEditing] = useState<SiteItem | null>(null);
|
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(() => {
|
useEffect(() => {
|
||||||
if (!open) return;
|
if (!open) return;
|
||||||
|
|
@ -174,6 +230,13 @@ const SiteList: React.FC = () => {
|
||||||
hideInSearch: true,
|
hideInSearch: true,
|
||||||
render: (_, row) => (
|
render: (_, row) => (
|
||||||
<Space>
|
<Space>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
onClick={() => handleSync([row.id])}
|
||||||
|
>
|
||||||
|
同步
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -321,6 +384,10 @@ const SiteList: React.FC = () => {
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
columns={columns}
|
columns={columns}
|
||||||
request={tableRequest}
|
request={tableRequest}
|
||||||
|
rowSelection={{
|
||||||
|
selectedRowKeys,
|
||||||
|
onChange: setSelectedRowKeys,
|
||||||
|
}}
|
||||||
toolBarRender={() => [
|
toolBarRender={() => [
|
||||||
<Button
|
<Button
|
||||||
key="new"
|
key="new"
|
||||||
|
|
@ -333,10 +400,14 @@ const SiteList: React.FC = () => {
|
||||||
新增站点
|
新增站点
|
||||||
</Button>,
|
</Button>,
|
||||||
// 同步包括 orders subscriptions 等等
|
// 同步包括 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 { request, useParams } from '@umijs/max';
|
||||||
import { App, Avatar, Button, Popconfirm, Space, Tag } from 'antd';
|
import { App, Avatar, Button, Popconfirm, Space, Tag } from 'antd';
|
||||||
import React, { useRef, useState } from 'react';
|
import React, { useRef, useState } from 'react';
|
||||||
import { DeleteFilled, EditOutlined, PlusOutlined, UserOutlined } from '@ant-design/icons';
|
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 CustomerPage: React.FC = () => {
|
||||||
const { message } = App.useApp();
|
const { message } = App.useApp();
|
||||||
const { siteId } = useParams<{ siteId: string }>();
|
const { siteId } = useParams<{ siteId: string }>();
|
||||||
|
|
@ -167,10 +218,11 @@ const CustomerPage: React.FC = () => {
|
||||||
<ProFormText name="last_name" label="姓" />
|
<ProFormText name="last_name" label="姓" />
|
||||||
<ProFormText name="username" label="用户名" />
|
<ProFormText name="username" label="用户名" />
|
||||||
</DrawerForm>,
|
</DrawerForm>,
|
||||||
<Button
|
<BatchEditCustomers
|
||||||
title="批量编辑"
|
tableRef={actionRef}
|
||||||
icon={<EditOutlined />}
|
selectedRowKeys={selectedRowKeys}
|
||||||
onClick={() => message.info('批量编辑暂未实现')}
|
setSelectedRowKeys={setSelectedRowKeys}
|
||||||
|
siteId={siteId}
|
||||||
/>,
|
/>,
|
||||||
<Button
|
<Button
|
||||||
title="批量删除"
|
title="批量删除"
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import {
|
||||||
ProTable,
|
ProTable,
|
||||||
} from '@ant-design/pro-components';
|
} from '@ant-design/pro-components';
|
||||||
import { useParams } from '@umijs/max';
|
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 React, { useRef, useState } from 'react';
|
||||||
import { ToastContainer } from 'react-toastify';
|
import { ToastContainer } from 'react-toastify';
|
||||||
|
|
||||||
|
|
@ -198,16 +198,40 @@ const LogisticsPage: React.FC = () => {
|
||||||
success: false,
|
success: false,
|
||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
// rowSelection={{
|
rowSelection={{
|
||||||
// selectedRowKeys: selectedRows.map((row) => row.id),
|
selectedRowKeys: selectedRows.map((row) => row.id),
|
||||||
// onChange: (_, selectedRows) => setSelectedRows(selectedRows),
|
onChange: (_, selectedRows) => setSelectedRows(selectedRows),
|
||||||
// }}
|
}}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
tableAlertOptionRender={() => {
|
tableAlertOptionRender={() => {
|
||||||
return (
|
return (
|
||||||
|
<Space>
|
||||||
<Button onClick={handleBatchPrint} type="primary">
|
<Button onClick={handleBatchPrint} type="primary">
|
||||||
批量打印
|
批量打印
|
||||||
</Button>
|
</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,
|
Tag,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
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';
|
import { DeleteFilled } from '@ant-design/icons';
|
||||||
|
|
||||||
const OrdersPage: React.FC = () => {
|
const OrdersPage: React.FC = () => {
|
||||||
|
|
@ -122,9 +122,20 @@ const OrdersPage: React.FC = () => {
|
||||||
render: (_, record) => record.shipping?.phone || record.billing?.phone,
|
render: (_, record) => record.shipping?.phone || record.billing?.phone,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '州',
|
title: '账单地址',
|
||||||
|
dataIndex: 'billing_full_address',
|
||||||
hideInSearch: true,
|
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: '操作',
|
title: '操作',
|
||||||
|
|
@ -135,7 +146,7 @@ const OrdersPage: React.FC = () => {
|
||||||
render: (_, record) => {
|
render: (_, record) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Detail
|
<EditOrder
|
||||||
key={record.id}
|
key={record.id}
|
||||||
record={record}
|
record={record}
|
||||||
tableRef={actionRef}
|
tableRef={actionRef}
|
||||||
|
|
@ -152,7 +163,7 @@ const OrdersPage: React.FC = () => {
|
||||||
key: 'history',
|
key: 'history',
|
||||||
label: (
|
label: (
|
||||||
<HistoryOrder
|
<HistoryOrder
|
||||||
email={record.email}
|
email={(record as any).email}
|
||||||
tableRef={actionRef}
|
tableRef={actionRef}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
|
@ -165,10 +176,8 @@ const OrdersPage: React.FC = () => {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<a onClick={(e) => e.preventDefault()}>
|
<a onClick={(e) => e.preventDefault()}>
|
||||||
<Space>
|
<Button type="link" icon={<DownOutlined />}>
|
||||||
更多
|
</Button>
|
||||||
<DownOutlined />
|
|
||||||
</Space>
|
|
||||||
</a>
|
</a>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
<Divider type="vertical" />
|
<Divider type="vertical" />
|
||||||
|
|
@ -217,6 +226,12 @@ const OrdersPage: React.FC = () => {
|
||||||
}}
|
}}
|
||||||
toolBarRender={() => [
|
toolBarRender={() => [
|
||||||
<CreateOrder tableRef={actionRef} siteId={siteId} />,
|
<CreateOrder tableRef={actionRef} siteId={siteId} />,
|
||||||
|
<BatchEditOrders
|
||||||
|
tableRef={actionRef}
|
||||||
|
selectedRowKeys={selectedRowKeys}
|
||||||
|
setSelectedRowKeys={setSelectedRowKeys}
|
||||||
|
siteId={siteId}
|
||||||
|
/>,
|
||||||
<Button
|
<Button
|
||||||
title="批量删除"
|
title="批量删除"
|
||||||
danger
|
danger
|
||||||
|
|
|
||||||
|
|
@ -216,7 +216,7 @@ const ProductsPage: React.FC = () => {
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainer>
|
<PageContainer header={{ title: null, breadcrumb: undefined }}>
|
||||||
<ProTable<any>
|
<ProTable<any>
|
||||||
scroll={{ x: 'max-content' }}
|
scroll={{ x: 'max-content' }}
|
||||||
pagination={{
|
pagination={{
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,13 @@ import {
|
||||||
CodeSandboxOutlined,
|
CodeSandboxOutlined,
|
||||||
CopyOutlined,
|
CopyOutlined,
|
||||||
DeleteFilled,
|
DeleteFilled,
|
||||||
|
EditOutlined,
|
||||||
FileDoneOutlined,
|
FileDoneOutlined,
|
||||||
TagsOutlined,
|
TagsOutlined,
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import {
|
import {
|
||||||
ActionType,
|
ActionType,
|
||||||
|
DrawerForm,
|
||||||
ModalForm,
|
ModalForm,
|
||||||
ProColumns,
|
ProColumns,
|
||||||
ProDescriptions,
|
ProDescriptions,
|
||||||
|
|
@ -78,7 +80,11 @@ export const OrderNote: React.FC<{
|
||||||
return (
|
return (
|
||||||
<ModalForm
|
<ModalForm
|
||||||
title="添加备注"
|
title="添加备注"
|
||||||
trigger={<Button type="primary" ghost title="备注" icon={<TagsOutlined />} />}
|
trigger={
|
||||||
|
<Button type="primary" ghost size="small" icon={<TagsOutlined />}>
|
||||||
|
备注
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
onFinish={async (values: any) => {
|
onFinish={async (values: any) => {
|
||||||
if (!siteId) {
|
if (!siteId) {
|
||||||
message.error('缺少站点ID');
|
message.error('缺少站点ID');
|
||||||
|
|
@ -236,12 +242,14 @@ export const Shipping: React.FC<{
|
||||||
trigger={
|
trigger={
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
title="创建运单"
|
size="small"
|
||||||
icon={<CodeSandboxOutlined />}
|
icon={<CodeSandboxOutlined />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setActiveLine(id);
|
setActiveLine(id);
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
|
发货
|
||||||
|
</Button>
|
||||||
}
|
}
|
||||||
request={async () => {
|
request={async () => {
|
||||||
if (!siteId) return {};
|
if (!siteId) return {};
|
||||||
|
|
@ -569,7 +577,11 @@ export const CreateOrder: React.FC<{
|
||||||
body: { maxHeight: '65vh', overflowY: 'auto', overflowX: 'hidden' },
|
body: { maxHeight: '65vh', overflowY: 'auto', overflowX: 'hidden' },
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
trigger={<Button type="primary" title="创建订单" icon={<CodeSandboxOutlined />} />}
|
trigger={
|
||||||
|
<Button type="primary" size="small" icon={<CodeSandboxOutlined />}>
|
||||||
|
创建订单
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
params={{
|
params={{
|
||||||
source_type: 'admin',
|
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>;
|
tableRef: React.MutableRefObject<ActionType | undefined>;
|
||||||
orderId: number;
|
orderId: number;
|
||||||
record: API.Order;
|
record: API.Order;
|
||||||
setActiveLine: Function;
|
setActiveLine: Function;
|
||||||
siteId?: string;
|
siteId?: string;
|
||||||
}> = ({ tableRef, orderId, record, setActiveLine, siteId }) => {
|
}> = ({ tableRef, orderId, record, setActiveLine, siteId }) => {
|
||||||
const [visiable, setVisiable] = useState(false);
|
|
||||||
const { message } = App.useApp();
|
const { message } = App.useApp();
|
||||||
const ref = useRef<ActionType>();
|
const formRef = useRef<ProFormInstance>();
|
||||||
|
|
||||||
const initRequest = async () => {
|
return (
|
||||||
if (!siteId) return { data: {} };
|
<DrawerForm
|
||||||
|
formRef={formRef}
|
||||||
// Fetch detail from site-api
|
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}`);
|
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 sales = data.sales || [];
|
||||||
const mergedSales = sales.reduce(
|
const mergedSales = sales.reduce(
|
||||||
(acc: any[], cur: any) => {
|
(acc: any[], cur: any) => {
|
||||||
|
|
@ -653,59 +734,90 @@ export const Detail: React.FC<{
|
||||||
);
|
);
|
||||||
data.sales = mergedSales;
|
data.sales = mergedSales;
|
||||||
|
|
||||||
return {
|
return data;
|
||||||
data,
|
}}
|
||||||
};
|
onFinish={async (values) => {
|
||||||
};
|
if (!siteId) return false;
|
||||||
|
try {
|
||||||
return (
|
const res = await request(`/site-api/${siteId}/orders/${orderId}`, {
|
||||||
<>
|
method: 'PUT',
|
||||||
<Button
|
data: values
|
||||||
key="detail"
|
});
|
||||||
type="primary"
|
if (res.success) {
|
||||||
title="详情"
|
message.success('更新成功');
|
||||||
icon={<FileDoneOutlined />}
|
tableRef.current?.reload();
|
||||||
onClick={() => {
|
return true;
|
||||||
setVisiable(true);
|
}
|
||||||
setActiveLine(record.id);
|
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
|
<ProForm.Group title="基本信息">
|
||||||
labelStyle={{ width: '100px' }}
|
<ProFormText name="number" label="订单号" readonly />
|
||||||
actionRef={ref}
|
<ProFormSelect name="status" label="状态" valueEnum={ORDER_STATUS_ENUM} />
|
||||||
request={initRequest}
|
<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 ... */}
|
<ProForm.Group>
|
||||||
<ProDescriptions.Item
|
<ProFormText name="name" label="商品名" />
|
||||||
label="订单日期"
|
<ProFormText name="sku" label="SKU" />
|
||||||
dataIndex="date_created"
|
<ProFormDigit name="quantity" label="数量" />
|
||||||
valueType="dateTime"
|
<ProFormText name="total" label="总价" />
|
||||||
/>
|
</ProForm.Group>
|
||||||
{/* ... */}
|
</ProFormList>
|
||||||
</ProDescriptions>
|
|
||||||
</Drawer>
|
<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