feat(客户管理): 添加历史订单组件和地址展示优化
- 新增HistoryOrders组件用于展示客户历史订单及统计信息 - 创建Address组件统一处理地址展示逻辑 - 优化客户列表页的地址展示和操作列 - 更新API类型定义和批量操作接口 - 调整代码格式和样式
This commit is contained in:
parent
8524cc1ec0
commit
96cc6d3dda
|
|
@ -16,6 +16,7 @@ export default defineConfig({
|
||||||
layout: {
|
layout: {
|
||||||
title: 'YOONE',
|
title: 'YOONE',
|
||||||
},
|
},
|
||||||
|
esbuildMinifyIIFE: true,
|
||||||
define: {
|
define: {
|
||||||
UMI_APP_API_URL,
|
UMI_APP_API_URL,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface AddressProps {
|
||||||
|
address: {
|
||||||
|
address_1?: string;
|
||||||
|
address_2?: string;
|
||||||
|
city?: string;
|
||||||
|
state?: string;
|
||||||
|
postcode?: string;
|
||||||
|
country?: string;
|
||||||
|
phone?: string;
|
||||||
|
};
|
||||||
|
style?: React.CSSProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Address: React.FC<AddressProps> = ({ address, style }) => {
|
||||||
|
if (!address) {
|
||||||
|
return <span>-</span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { address_1, address_2, city, state, postcode, country, phone } =
|
||||||
|
address;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ fontSize: 12, ...style }}>
|
||||||
|
<div>
|
||||||
|
{address_1} {address_2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{city}, {state}, {postcode}
|
||||||
|
</div>
|
||||||
|
<div>{country}</div>
|
||||||
|
<div>{phone}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Address;
|
||||||
|
|
@ -0,0 +1,255 @@
|
||||||
|
import { ordercontrollerGetorders } from '@/servers/api/order';
|
||||||
|
import { siteapicontrollerGetorders } from '@/servers/api/siteApi';
|
||||||
|
import {
|
||||||
|
App,
|
||||||
|
Col,
|
||||||
|
Modal,
|
||||||
|
Row,
|
||||||
|
Spin,
|
||||||
|
Statistic,
|
||||||
|
Table,
|
||||||
|
Tag,
|
||||||
|
Typography,
|
||||||
|
} from 'antd';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
const { Text, Title } = Typography;
|
||||||
|
|
||||||
|
interface HistoryOrdersProps {
|
||||||
|
customer: API.UnifiedCustomerDTO;
|
||||||
|
siteId?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OrderStats {
|
||||||
|
totalOrders: number;
|
||||||
|
totalAmount: number;
|
||||||
|
yooneOrders: number;
|
||||||
|
yooneAmount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const HistoryOrders: React.FC<HistoryOrdersProps> = ({ customer, siteId }) => {
|
||||||
|
const { message } = App.useApp();
|
||||||
|
const [modalVisible, setModalVisible] = useState(false);
|
||||||
|
const [orders, setOrders] = useState<any[]>([]);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [stats, setStats] = useState<OrderStats>({
|
||||||
|
totalOrders: 0,
|
||||||
|
totalAmount: 0,
|
||||||
|
yooneOrders: 0,
|
||||||
|
yooneAmount: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 计算订单统计信息
|
||||||
|
const calculateStats = (orders: any[]) => {
|
||||||
|
let totalOrders = 0;
|
||||||
|
let totalAmount = 0;
|
||||||
|
let yooneOrders = 0;
|
||||||
|
let yooneAmount = 0;
|
||||||
|
|
||||||
|
orders.forEach((order) => {
|
||||||
|
totalOrders++;
|
||||||
|
// total是字符串,需要转换为数字
|
||||||
|
const orderTotal = parseFloat(order.total || '0');
|
||||||
|
totalAmount += orderTotal;
|
||||||
|
|
||||||
|
// 检查订单中是否包含yoone商品
|
||||||
|
let hasYoone = false;
|
||||||
|
let orderYooneAmount = 0;
|
||||||
|
|
||||||
|
// 优先使用line_items,如果没有则使用items
|
||||||
|
const items = order.line_items || order.items || [];
|
||||||
|
if (Array.isArray(items)) {
|
||||||
|
items.forEach((item: any) => {
|
||||||
|
// 检查商品名称或SKU是否包含yoone(不区分大小写)
|
||||||
|
const itemName = (item.name || '').toLowerCase();
|
||||||
|
const sku = (item.sku || '').toLowerCase();
|
||||||
|
|
||||||
|
if (itemName.includes('yoone') || sku.includes('yoone')) {
|
||||||
|
hasYoone = true;
|
||||||
|
const itemTotal = parseFloat(item.total || item.price || '0');
|
||||||
|
orderYooneAmount += itemTotal;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasYoone) {
|
||||||
|
yooneOrders++;
|
||||||
|
yooneAmount += orderYooneAmount;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
totalOrders,
|
||||||
|
totalAmount,
|
||||||
|
yooneOrders,
|
||||||
|
yooneAmount,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取客户订单数据
|
||||||
|
const fetchOrders = async () => {
|
||||||
|
|
||||||
|
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
const response = await ordercontrollerGetorders({
|
||||||
|
customer_email: customer.email,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
const orderList = response.items || [];
|
||||||
|
setOrders(orderList);
|
||||||
|
const calculatedStats = calculateStats(orderList);
|
||||||
|
setStats(calculatedStats);
|
||||||
|
} else {
|
||||||
|
message.error('获取订单数据失败');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取订单失败:', error);
|
||||||
|
message.error('获取订单失败');
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打开弹框时获取数据
|
||||||
|
const handleOpenModal = () => {
|
||||||
|
setModalVisible(true);
|
||||||
|
fetchOrders();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 订单表格列配置
|
||||||
|
const orderColumns = [
|
||||||
|
{
|
||||||
|
title: '订单号',
|
||||||
|
dataIndex: 'externalOrderId',
|
||||||
|
key: 'externalOrderId',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '订单状态',
|
||||||
|
dataIndex: 'status',
|
||||||
|
key: 'status',
|
||||||
|
width: 100,
|
||||||
|
render: (status: string) => {
|
||||||
|
const statusMap: Record<string, string> = {
|
||||||
|
pending: '待处理',
|
||||||
|
processing: '处理中',
|
||||||
|
'on-hold': '等待中',
|
||||||
|
completed: '已完成',
|
||||||
|
cancelled: '已取消',
|
||||||
|
refunded: '已退款',
|
||||||
|
failed: '失败',
|
||||||
|
};
|
||||||
|
return <Tag color="blue">{statusMap[status] || status}</Tag>;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '订单金额',
|
||||||
|
dataIndex: 'total',
|
||||||
|
key: 'total',
|
||||||
|
width: 100,
|
||||||
|
render: (total: string, record: any) => (
|
||||||
|
<Text>
|
||||||
|
{record.currency_symbol || '$'}
|
||||||
|
{parseFloat(total || '0').toFixed(2)}
|
||||||
|
</Text>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
dataIndex: 'date_created',
|
||||||
|
key: 'date_created',
|
||||||
|
width: 140,
|
||||||
|
render: (date: string) => (
|
||||||
|
<Text>{date ? dayjs(date).format('YYYY-MM-DD HH:mm') : '-'}</Text>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '包含Yoone',
|
||||||
|
key: 'hasYoone',
|
||||||
|
width: 80,
|
||||||
|
render: (_: any, record: any) => {
|
||||||
|
let hasYoone = false;
|
||||||
|
const items = record.line_items || record.items || [];
|
||||||
|
if (Array.isArray(items)) {
|
||||||
|
hasYoone = items.some((item: any) => {
|
||||||
|
const itemName = (item.name || '').toLowerCase();
|
||||||
|
const sku = (item.sku || '').toLowerCase();
|
||||||
|
return itemName.includes('yoone') || sku.includes('yoone');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return hasYoone ? <Tag color="green">是</Tag> : <Tag>否</Tag>;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<a onClick={handleOpenModal}>历史订单</a>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
title={`${customer.fullname || customer.email} 的历史订单`}
|
||||||
|
open={modalVisible}
|
||||||
|
onCancel={() => setModalVisible(false)}
|
||||||
|
footer={null}
|
||||||
|
width={1000}
|
||||||
|
>
|
||||||
|
<Spin spinning={loading}>
|
||||||
|
{/* 统计信息 */}
|
||||||
|
<Row gutter={16} style={{ marginBottom: 24 }}>
|
||||||
|
<Col span={6}>
|
||||||
|
<Statistic
|
||||||
|
title="总订单数"
|
||||||
|
value={stats.totalOrders}
|
||||||
|
prefix="#"
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col span={6}>
|
||||||
|
<Statistic
|
||||||
|
title="总金额"
|
||||||
|
value={stats.totalAmount}
|
||||||
|
precision={2}
|
||||||
|
prefix="$"
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col span={6}>
|
||||||
|
<Statistic
|
||||||
|
title="Yoone订单数"
|
||||||
|
value={stats.yooneOrders}
|
||||||
|
prefix="#"
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col span={6}>
|
||||||
|
<Statistic
|
||||||
|
title="Yoone金额"
|
||||||
|
value={stats.yooneAmount}
|
||||||
|
precision={2}
|
||||||
|
prefix="$"
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
|
||||||
|
{/* 订单列表 */}
|
||||||
|
<Title level={4} style={{ marginTop: 24 }}>
|
||||||
|
订单详情
|
||||||
|
</Title>
|
||||||
|
<Table
|
||||||
|
columns={orderColumns}
|
||||||
|
dataSource={orders}
|
||||||
|
rowKey="id"
|
||||||
|
pagination={{
|
||||||
|
pageSize: 10,
|
||||||
|
showSizeChanger: true,
|
||||||
|
showTotal: (total) => `共 ${total} 条`,
|
||||||
|
}}
|
||||||
|
scroll={{ x: 800 }}
|
||||||
|
/>
|
||||||
|
</Spin>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default HistoryOrders;
|
||||||
|
|
@ -16,8 +16,8 @@ import {
|
||||||
ProTable,
|
ProTable,
|
||||||
} from '@ant-design/pro-components';
|
} from '@ant-design/pro-components';
|
||||||
import { App, Avatar, Button, Rate, Space, Tag, Tooltip } from 'antd';
|
import { App, Avatar, Button, Rate, Space, Tag, Tooltip } from 'antd';
|
||||||
import dayjs from 'dayjs';
|
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
import HistoryOrders from './HistoryOrders';
|
||||||
|
|
||||||
// 地址格式化函数
|
// 地址格式化函数
|
||||||
const formatAddress = (address: any) => {
|
const formatAddress = (address: any) => {
|
||||||
|
|
@ -42,7 +42,7 @@ const formatAddress = (address: any) => {
|
||||||
postcode,
|
postcode,
|
||||||
country,
|
country,
|
||||||
phone: addressPhone,
|
phone: addressPhone,
|
||||||
email: addressEmail
|
email: addressEmail,
|
||||||
} = address;
|
} = address;
|
||||||
|
|
||||||
const parts = [];
|
const parts = [];
|
||||||
|
|
@ -73,7 +73,10 @@ const formatAddress = (address: any) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
// 地址卡片组件
|
// 地址卡片组件
|
||||||
const AddressCell: React.FC<{ address: any; title: string }> = ({ address, title }) => {
|
const AddressCell: React.FC<{ address: any; title: string }> = ({
|
||||||
|
address,
|
||||||
|
title,
|
||||||
|
}) => {
|
||||||
const formattedAddress = formatAddress(address);
|
const formattedAddress = formatAddress(address);
|
||||||
|
|
||||||
if (formattedAddress === '-') {
|
if (formattedAddress === '-') {
|
||||||
|
|
@ -91,13 +94,15 @@ const AddressCell: React.FC<{ address: any; title: string }> = ({ address, title
|
||||||
}
|
}
|
||||||
placement="topLeft"
|
placement="topLeft"
|
||||||
>
|
>
|
||||||
<div style={{
|
<div
|
||||||
maxWidth: 200,
|
style={{
|
||||||
overflow: 'hidden',
|
maxWidth: 200,
|
||||||
textOverflow: 'ellipsis',
|
overflow: 'hidden',
|
||||||
whiteSpace: 'nowrap',
|
textOverflow: 'ellipsis',
|
||||||
cursor: 'pointer'
|
whiteSpace: 'nowrap',
|
||||||
}}>
|
cursor: 'pointer',
|
||||||
|
}}
|
||||||
|
>
|
||||||
{formattedAddress}
|
{formattedAddress}
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
@ -126,8 +131,11 @@ const CustomerList: React.FC = () => {
|
||||||
// 根据站点ID获取站点名称
|
// 根据站点ID获取站点名称
|
||||||
const getSiteName = (siteId: number | undefined | null) => {
|
const getSiteName = (siteId: number | undefined | null) => {
|
||||||
if (!siteId) return '-';
|
if (!siteId) return '-';
|
||||||
const site = sites.find(s => s.id === siteId);
|
if (typeof siteId === 'string') {
|
||||||
console.log(`site`,site)
|
return siteId;
|
||||||
|
}
|
||||||
|
const site = sites.find((s) => s.id === siteId);
|
||||||
|
console.log(`site`, site);
|
||||||
return site ? site.name : String(siteId);
|
return site ? site.name : String(siteId);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -161,9 +169,8 @@ const CustomerList: React.FC = () => {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
render: (siteId, record) => {
|
render: (siteId: any) => {
|
||||||
return siteId
|
return <span>{getSiteName(siteId) || '-'}</span>;
|
||||||
return getSiteName(record.site_id) || '-';
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -187,8 +194,8 @@ const CustomerList: React.FC = () => {
|
||||||
sorter: true,
|
sorter: true,
|
||||||
render: (_, record) => {
|
render: (_, record) => {
|
||||||
return (
|
return (
|
||||||
record.fullName ||
|
record.fullname ||
|
||||||
`${record.firstName || ''} ${record.lastName || ''}`.trim() ||
|
`${record.first_name || ''} ${record.last_name || ''}`.trim() ||
|
||||||
record.username ||
|
record.username ||
|
||||||
'-'
|
'-'
|
||||||
);
|
);
|
||||||
|
|
@ -228,6 +235,7 @@ const CustomerList: React.FC = () => {
|
||||||
title: '评分',
|
title: '评分',
|
||||||
dataIndex: 'rate',
|
dataIndex: 'rate',
|
||||||
width: 120,
|
width: 120,
|
||||||
|
hideInSearch: true,
|
||||||
render: (_, record) => {
|
render: (_, record) => {
|
||||||
return (
|
return (
|
||||||
<Rate
|
<Rate
|
||||||
|
|
@ -246,7 +254,7 @@ const CustomerList: React.FC = () => {
|
||||||
message.error(e?.message || '设置评分失败');
|
message.error(e?.message || '设置评分失败');
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
value={record.rate}
|
value={record.raw?.rate || 0}
|
||||||
allowHalf
|
allowHalf
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
@ -257,9 +265,10 @@ const CustomerList: React.FC = () => {
|
||||||
dataIndex: 'tags',
|
dataIndex: 'tags',
|
||||||
hideInSearch: true,
|
hideInSearch: true,
|
||||||
render: (_, record) => {
|
render: (_, record) => {
|
||||||
|
const tags = record.raw?.tags || [];
|
||||||
return (
|
return (
|
||||||
<Space size={[0, 8]} wrap>
|
<Space size={[0, 8]} wrap>
|
||||||
{(record.tags || []).map((tag: string) => {
|
{tags.map((tag: string) => {
|
||||||
return (
|
return (
|
||||||
<Tag
|
<Tag
|
||||||
key={tag}
|
key={tag}
|
||||||
|
|
@ -302,7 +311,6 @@ const CustomerList: React.FC = () => {
|
||||||
hideInSearch: true,
|
hideInSearch: true,
|
||||||
sorter: true,
|
sorter: true,
|
||||||
width: 140,
|
width: 140,
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
|
|
@ -314,20 +322,12 @@ const CustomerList: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<Space direction="vertical" size="small">
|
<Space direction="vertical" size="small">
|
||||||
<AddTag
|
<AddTag
|
||||||
email={record.email}
|
email={record.email || ''}
|
||||||
tags={record.tags}
|
tags={record.raw?.tags || []}
|
||||||
tableRef={actionRef}
|
tableRef={actionRef}
|
||||||
/>
|
/>
|
||||||
<Button
|
{/* 订单 */}
|
||||||
type="link"
|
<HistoryOrders customer={record} siteId={record.raw?.site_id} />
|
||||||
size="small"
|
|
||||||
onClick={() => {
|
|
||||||
// 这里可以添加查看客户详情的逻辑
|
|
||||||
message.info('客户详情功能开发中...');
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
详情
|
|
||||||
</Button>
|
|
||||||
</Space>
|
</Space>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -347,7 +347,9 @@ const CustomerList: React.FC = () => {
|
||||||
...params,
|
...params,
|
||||||
current: params.current?.toString(),
|
current: params.current?.toString(),
|
||||||
pageSize: params.pageSize?.toString(),
|
pageSize: params.pageSize?.toString(),
|
||||||
...(key ? { sorterKey: key, sorterValue: sorter[key] as string } : {}),
|
...(key
|
||||||
|
? { sorterKey: key, sorterValue: sorter[key] as string }
|
||||||
|
: {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
@ -488,7 +490,11 @@ const SyncCustomersModal: React.FC<{
|
||||||
const handleSync = async (values: { siteId: number }) => {
|
const handleSync = async (values: { siteId: number }) => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const { success, message: msg, data } = await customercontrollerSynccustomers({
|
const {
|
||||||
|
success,
|
||||||
|
message: msg,
|
||||||
|
data,
|
||||||
|
} = await customercontrollerSynccustomers({
|
||||||
siteId: values.siteId,
|
siteId: values.siteId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -500,7 +506,7 @@ const SyncCustomersModal: React.FC<{
|
||||||
synced = 0,
|
synced = 0,
|
||||||
created = 0,
|
created = 0,
|
||||||
updated = 0,
|
updated = 0,
|
||||||
errors = []
|
errors = [],
|
||||||
} = result;
|
} = result;
|
||||||
|
|
||||||
let resultMessage = `同步完成!共处理 ${total} 个客户:`;
|
let resultMessage = `同步完成!共处理 ${total} 个客户:`;
|
||||||
|
|
@ -516,20 +522,24 @@ const SyncCustomersModal: React.FC<{
|
||||||
<div>
|
<div>
|
||||||
<div>{resultMessage}</div>
|
<div>{resultMessage}</div>
|
||||||
<div style={{ marginTop: 8, fontSize: 12, color: '#faad14' }}>
|
<div style={{ marginTop: 8, fontSize: 12, color: '#faad14' }}>
|
||||||
失败详情:{errors.slice(0, 3).map((err: any) => err.email || err.error).join(', ')}
|
失败详情:
|
||||||
|
{errors
|
||||||
|
.slice(0, 3)
|
||||||
|
.map((err: any) => err.email || err.error)
|
||||||
|
.join(', ')}
|
||||||
{errors.length > 3 && ` 等 ${errors.length - 3} 个错误...`}
|
{errors.length > 3 && ` 等 ${errors.length - 3} 个错误...`}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
duration: 8,
|
duration: 8,
|
||||||
key: 'sync-result'
|
key: 'sync-result',
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// 完全成功
|
// 完全成功
|
||||||
message.success({
|
message.success({
|
||||||
content: resultMessage,
|
content: resultMessage,
|
||||||
duration: 4,
|
duration: 4,
|
||||||
key: 'sync-result'
|
key: 'sync-result',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import Address from '@/components/Address';
|
||||||
import {
|
import {
|
||||||
DeleteFilled,
|
DeleteFilled,
|
||||||
EditOutlined,
|
EditOutlined,
|
||||||
|
|
@ -187,19 +188,15 @@ const CustomerPage: React.FC = () => {
|
||||||
hideInSearch: true,
|
hideInSearch: true,
|
||||||
render: (_, record) => {
|
render: (_, record) => {
|
||||||
const { billing } = record;
|
const { billing } = record;
|
||||||
if (!billing) return '-';
|
return <Address address={billing} />;
|
||||||
return (
|
},
|
||||||
<div style={{ fontSize: 12 }}>
|
},
|
||||||
<div>
|
{
|
||||||
{billing.address_1} {billing.address_2}
|
title: '物流地址',
|
||||||
</div>
|
dataIndex: 'shipping',
|
||||||
<div>
|
hideInSearch: true,
|
||||||
{billing.city}, {billing.state}, {billing.postcode}
|
render: (shipping) => {
|
||||||
</div>
|
return <Address address={shipping} />;
|
||||||
<div>{billing.country}</div>
|
|
||||||
<div>{billing.phone}</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -239,7 +239,10 @@ const WpToolPage: React.FC = () => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchAllConfigs = async () => {
|
const fetchAllConfigs = async () => {
|
||||||
try {
|
try {
|
||||||
message.loading({ content: '正在加载字典配置...', key: 'loading-config' });
|
message.loading({
|
||||||
|
content: '正在加载字典配置...',
|
||||||
|
key: 'loading-config',
|
||||||
|
});
|
||||||
|
|
||||||
// 1. 获取所有字典列表以找到对应的 ID
|
// 1. 获取所有字典列表以找到对应的 ID
|
||||||
const dictListResponse = await request('/dict/list');
|
const dictListResponse = await request('/dict/list');
|
||||||
|
|
@ -303,13 +306,22 @@ const WpToolPage: React.FC = () => {
|
||||||
message.success({ content: '字典配置加载成功', key: 'loading-config' });
|
message.success({ content: '字典配置加载成功', key: 'loading-config' });
|
||||||
|
|
||||||
// 显示加载结果统计
|
// 显示加载结果统计
|
||||||
const totalItems = brands.length + fruitKeys.length + mintKeys.length + flavorKeys.length +
|
const totalItems =
|
||||||
strengthKeys.length + sizeKeys.length + humidityKeys.length + categoryKeys.length;
|
brands.length +
|
||||||
|
fruitKeys.length +
|
||||||
|
mintKeys.length +
|
||||||
|
flavorKeys.length +
|
||||||
|
strengthKeys.length +
|
||||||
|
sizeKeys.length +
|
||||||
|
humidityKeys.length +
|
||||||
|
categoryKeys.length;
|
||||||
console.log(`字典配置加载完成: 共 ${totalItems} 个配置项`);
|
console.log(`字典配置加载完成: 共 ${totalItems} 个配置项`);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to fetch configs:', error);
|
console.error('Failed to fetch configs:', error);
|
||||||
message.error({ content: '获取字典配置失败,请刷新页面重试', key: 'loading-config' });
|
message.error({
|
||||||
|
content: '获取字典配置失败,请刷新页面重试',
|
||||||
|
key: 'loading-config',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -262,19 +262,22 @@ export async function siteapicontrollerCreateorder(
|
||||||
export async function siteapicontrollerBatchorders(
|
export async function siteapicontrollerBatchorders(
|
||||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||||
params: API.siteapicontrollerBatchordersParams,
|
params: API.siteapicontrollerBatchordersParams,
|
||||||
body: Record<string, any>,
|
body: API.BatchOperationDTO,
|
||||||
options?: { [key: string]: any },
|
options?: { [key: string]: any },
|
||||||
) {
|
) {
|
||||||
const { siteId: param0, ...queryParams } = params;
|
const { siteId: param0, ...queryParams } = params;
|
||||||
return request<Record<string, any>>(`/site-api/${param0}/orders/batch`, {
|
return request<API.BatchOperationResultDTO>(
|
||||||
method: 'POST',
|
`/site-api/${param0}/orders/batch`,
|
||||||
headers: {
|
{
|
||||||
'Content-Type': 'text/plain',
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
params: { ...queryParams },
|
||||||
|
data: body,
|
||||||
|
...(options || {}),
|
||||||
},
|
},
|
||||||
params: { ...queryParams },
|
);
|
||||||
data: body,
|
|
||||||
...(options || {}),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 此处后端没有提供注释 POST /site-api/${param0}/orders/batch-ship */
|
/** 此处后端没有提供注释 POST /site-api/${param0}/orders/batch-ship */
|
||||||
|
|
@ -381,19 +384,22 @@ export async function siteapicontrollerCreateproduct(
|
||||||
export async function siteapicontrollerBatchproducts(
|
export async function siteapicontrollerBatchproducts(
|
||||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||||
params: API.siteapicontrollerBatchproductsParams,
|
params: API.siteapicontrollerBatchproductsParams,
|
||||||
body: Record<string, any>,
|
body: API.BatchOperationDTO,
|
||||||
options?: { [key: string]: any },
|
options?: { [key: string]: any },
|
||||||
) {
|
) {
|
||||||
const { siteId: param0, ...queryParams } = params;
|
const { siteId: param0, ...queryParams } = params;
|
||||||
return request<Record<string, any>>(`/site-api/${param0}/products/batch`, {
|
return request<API.BatchOperationResultDTO>(
|
||||||
method: 'POST',
|
`/site-api/${param0}/products/batch`,
|
||||||
headers: {
|
{
|
||||||
'Content-Type': 'text/plain',
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
params: { ...queryParams },
|
||||||
|
data: body,
|
||||||
|
...(options || {}),
|
||||||
},
|
},
|
||||||
params: { ...queryParams },
|
);
|
||||||
data: body,
|
|
||||||
...(options || {}),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 此处后端没有提供注释 GET /site-api/${param0}/products/export */
|
/** 此处后端没有提供注释 GET /site-api/${param0}/products/export */
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,39 @@ declare namespace API {
|
||||||
ids: any[];
|
ids: any[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type BatchErrorItemDTO = {
|
||||||
|
/** 错误项标识(如ID、邮箱等) */
|
||||||
|
identifier?: string;
|
||||||
|
/** 错误信息 */
|
||||||
|
error?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type BatchOperationDTO = {
|
||||||
|
/** 要创建的数据列表 */
|
||||||
|
create?: any[];
|
||||||
|
/** 要更新的数据列表 */
|
||||||
|
update?: any[];
|
||||||
|
/** 要删除的ID列表 */
|
||||||
|
delete?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type BatchOperationResultDTO = {
|
||||||
|
/** 总处理数量 */
|
||||||
|
total?: number;
|
||||||
|
/** 成功处理数量 */
|
||||||
|
processed?: number;
|
||||||
|
/** 创建数量 */
|
||||||
|
created?: number;
|
||||||
|
/** 更新数量 */
|
||||||
|
updated?: number;
|
||||||
|
/** 删除数量 */
|
||||||
|
deleted?: number;
|
||||||
|
/** 跳过的数量 */
|
||||||
|
skipped?: number;
|
||||||
|
/** 错误列表 */
|
||||||
|
errors?: BatchErrorItemDTO[];
|
||||||
|
};
|
||||||
|
|
||||||
type BatchShipOrderItemDTO = {
|
type BatchShipOrderItemDTO = {
|
||||||
/** 订单ID */
|
/** 订单ID */
|
||||||
order_id?: string;
|
order_id?: string;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue