refactor: 优化代码结构并修复类型问题

- 移除未使用的TabPane组件
- 修复类型定义和导入方式
- 优化mock数据源的环境变量判断逻辑
- 更新文档结构并归档旧文件
- 添加新的UI组件和Memo组件
- 调整API路径和响应处理
This commit is contained in:
2026-03-23 12:41:35 +08:00
parent a037843851
commit 2b86715c09
363 changed files with 39305 additions and 40622 deletions

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect, useCallback } from 'react';
import React, { useState, useEffect, useCallback, useMemo } from 'react';
import {
Card,
Table,
@@ -11,7 +11,6 @@ import {
Select,
DatePicker,
message,
Tooltip,
Row,
Col,
Statistic,
@@ -50,15 +49,19 @@ import {
PrinterOutlined,
MessageOutlined,
ExclamationCircleOutlined,
AmazonOutlined,
GlobalOutlined,
ShopOutlined,
AppstoreOutlined,
} from '@ant-design/icons';
import type { ColumnsType, TablePaginationConfig } from 'antd/es/table';
import type { FilterValue, SorterResult, TableCurrentDataSource } from 'antd/es/table/interface';
import moment from 'moment';
import { Line, LineChart, Pie, Bar, BarChart, ResponsiveContainer, Tooltip, Legend, XAxis, YAxis, CartesianGrid, Cell } from 'recharts';
const { Title, Text } = Typography;
const { Option } = Select;
const { RangePicker } = DatePicker;
const { TabPane } = Tabs;
const { Step } = Steps;
const { Search } = Input;
@@ -120,12 +123,58 @@ const STATUS_CONFIG: Record<string, { color: string; text: string; icon: React.R
REFUNDED: { color: 'default', text: '已退款', icon: <UndoOutlined />, step: -1 },
};
const PLATFORM_CONFIG: Record<string, { color: string; text: string }> = {
AMAZON: { color: 'orange', text: 'Amazon' },
EBAY: { color: 'blue', text: 'eBay' },
SHOPIFY: { color: 'green', text: 'Shopify' },
SHOPEE: { color: 'red', text: 'Shopee' },
LAZADA: { color: 'purple', text: 'Lazada' },
const PLATFORM_CONFIG: Record<string, { color: string; text: string; icon: React.ReactNode }> = {
// TikTok系列
TIKTOK: { color: 'cyan', text: 'TikTok', icon: <ShopOutlined /> },
TIKTOK_FULL: { color: 'cyan', text: 'TikTok全托管', icon: <ShopOutlined /> },
// Shopee系列
SHOPEE: { color: 'red', text: 'Shopee', icon: <ShopOutlined /> },
SHOPEE_FULL: { color: 'red', text: 'Shopee全托管', icon: <ShopOutlined /> },
SHOPEE_LIGHT: { color: 'red', text: 'Shopee轻出海', icon: <ShopOutlined /> },
// Lazada系列
LAZADA: { color: 'purple', text: 'Lazada', icon: <ShopOutlined /> },
LAZADA_FULL: { color: 'purple', text: 'Lazada全托管', icon: <ShopOutlined /> },
// Temu
TEMU_FULL: { color: 'green', text: 'Temu全托管', icon: <ShopOutlined /> },
// SHEIN系列
SHEIN: { color: 'pink', text: 'SHEIN', icon: <ShopOutlined /> },
SHEIN_HALF: { color: 'pink', text: 'SHEIN半托管', icon: <ShopOutlined /> },
// 其他平台
OZON: { color: 'yellow', text: 'Ozon', icon: <ShopOutlined /> },
YANDEX: { color: 'blue', text: 'Yandex', icon: <ShopOutlined /> },
ALIEXPRESS: { color: 'orange', text: 'AliExpress', icon: <ShopOutlined /> },
ALIEXPRESS_HALF: { color: 'orange', text: '速卖通半托管', icon: <ShopOutlined /> },
ALIEXPRESS_POP: { color: 'orange', text: '速卖通本土POP', icon: <ShopOutlined /> },
COUPANG: { color: 'red', text: 'Coupang', icon: <ShopOutlined /> },
WALMART: { color: 'blue', text: 'Walmart', icon: <ShopOutlined /> },
WILDBERRIES: { color: 'purple', text: 'Wildberries', icon: <ShopOutlined /> },
ALLEGRO: { color: 'green', text: 'Allegro', icon: <ShopOutlined /> },
MERCADO_LIBRE: { color: 'yellow', text: 'Mercado Libre', icon: <ShopOutlined /> },
JUMIA: { color: 'blue', text: 'Jumia', icon: <ShopOutlined /> },
JOOM: { color: 'purple', text: 'Joom', icon: <ShopOutlined /> },
AMAZON: { color: 'orange', text: 'Amazon', icon: <AmazonOutlined /> },
WISH: { color: 'blue', text: 'Wish', icon: <ShopOutlined /> },
EMAG: { color: 'green', text: 'eMAG', icon: <ShopOutlined /> },
MIRAVIA: { color: 'pink', text: 'Miravia', icon: <ShopOutlined /> },
DARAZ: { color: 'blue', text: 'Daraz', icon: <ShopOutlined /> },
JOYBUY: { color: 'red', text: 'Joybuy', icon: <ShopOutlined /> },
ALIBABA: { color: 'orange', text: 'Alibaba', icon: <ShopOutlined /> },
QOO10: { color: 'red', text: 'Qoo10', icon: <ShopOutlined /> },
SHOPIFY: { color: 'green', text: 'Shopify', icon: <ShopOutlined /> },
SHOPLAZZA: { color: 'blue', text: 'Shoplazza', icon: <ShopOutlined /> },
SHOPYY_V1: { color: 'purple', text: 'SHOPYY v1.0', icon: <ShopOutlined /> },
SHOPYY_V2: { color: 'purple', text: 'SHOPYY v2.0', icon: <ShopOutlined /> },
SHOPLINE: { color: 'green', text: 'SHOPLINE', icon: <ShopOutlined /> },
GREATBOSS: { color: 'blue', text: 'GreatBoss', icon: <ShopOutlined /> },
OTHER: { color: 'default', text: '其他', icon: <ShopOutlined /> },
// 原有平台
EBAY: { color: 'blue', text: 'eBay', icon: <GlobalOutlined /> },
};
const MOCK_ORDERS: Order[] = [
@@ -459,6 +508,79 @@ export const OrderList: React.FC = () => {
setDetailDrawerVisible(true);
};
const handleBatchConfirm = () => {
if (selectedRows.length === 0) {
message.warning('请先选择要确认的订单');
return;
}
const pendingOrders = selectedRows.filter(order => order.status === 'PENDING');
if (pendingOrders.length === 0) {
message.warning('选中的订单中没有待处理的订单');
return;
}
Modal.confirm({
title: '确认批量确认',
content: `确定要确认选中的 ${pendingOrders.length} 个订单吗?`,
onOk: () => {
pendingOrders.forEach(order => updateOrderStatus(order.id, 'CONFIRMED'));
setSelectedRows([]);
message.success(`成功确认 ${pendingOrders.length} 个订单`);
},
});
};
const handleBatchShip = () => {
if (selectedRows.length === 0) {
message.warning('请先选择要发货的订单');
return;
}
const confirmedOrders = selectedRows.filter(order => order.status === 'CONFIRMED');
if (confirmedOrders.length === 0) {
message.warning('选中的订单中没有已确认的订单');
return;
}
Modal.confirm({
title: '确认批量发货',
content: `确定要发货选中的 ${confirmedOrders.length} 个订单吗?`,
onOk: () => {
confirmedOrders.forEach(order => updateOrderStatus(order.id, 'SHIPPED'));
setSelectedRows([]);
message.success(`成功发货 ${confirmedOrders.length} 个订单`);
},
});
};
const handleBatchCancel = () => {
if (selectedRows.length === 0) {
message.warning('请先选择要取消的订单');
return;
}
const cancellableOrders = selectedRows.filter(order =>
order.status === 'PENDING' || order.status === 'CONFIRMED'
);
if (cancellableOrders.length === 0) {
message.warning('选中的订单中没有可取消的订单');
return;
}
Modal.confirm({
title: '确认批量取消',
content: `确定要取消选中的 ${cancellableOrders.length} 个订单吗?`,
onOk: () => {
cancellableOrders.forEach(order => updateOrderStatus(order.id, 'CANCELLED'));
setSelectedRows([]);
message.success(`成功取消 ${cancellableOrders.length} 个订单`);
},
});
};
const handleBatchExport = () => {
if (selectedRows.length === 0) {
message.warning('请先选择要导出的订单');
return;
}
message.success(`成功导出 ${selectedRows.length} 个订单数据`);
};
const updateOrderStatus = (orderId: string, status: Order['status']) => {
setOrders(orders.map(o =>
o.id === orderId ? { ...o, status, updatedAt: moment().format('YYYY-MM-DD HH:mm:ss') } : o
@@ -488,6 +610,9 @@ export const OrderList: React.FC = () => {
if (filters.paymentStatus.length > 0 && !filters.paymentStatus.includes(order.paymentStatus)) {
return false;
}
if (activePlatformTab !== 'all' && order.platform !== activePlatformTab) {
return false;
}
return true;
});
@@ -512,6 +637,71 @@ export const OrderList: React.FC = () => {
totalAmount: orders.reduce((sum, o) => sum + o.totalAmount, 0),
};
const platformStats = useMemo(() => {
const stats: Record<string, { total: number; amount: number; pending: number }> = {
all: { total: orders.length, amount: 0, pending: 0 },
};
orders.forEach(order => {
const platform = order.platform;
if (!stats[platform]) {
stats[platform] = { total: 0, amount: 0, pending: 0 };
}
stats[platform].total++;
stats[platform].amount += order.totalAmount;
if (order.status === 'PENDING') {
stats[platform].pending++;
stats.all.pending++;
}
stats.all.amount += order.totalAmount;
});
return stats;
}, [orders]);
const [activePlatformTab, setActivePlatformTab] = useState<string>('all');
const [activeStatsTab, setActiveStatsTab] = useState<string>('overview');
// 计算订单趋势数据最近7天
const orderTrendData = useMemo(() => {
const last7Days = Array.from({ length: 7 }, (_, i) => {
const date = moment().subtract(i, 'days').format('MM-DD');
return {
date,
orders: orders.filter(o => moment(o.createdAt).format('MM-DD') === date).length,
amount: orders.filter(o => moment(o.createdAt).format('MM-DD') === date)
.reduce((sum, o) => sum + o.totalAmount, 0),
};
}).reverse();
return last7Days;
}, [orders]);
// 计算平台分布数据
const platformDistributionData = useMemo(() => {
const platformCount: Record<string, number> = {};
orders.forEach(order => {
platformCount[order.platform] = (platformCount[order.platform] || 0) + 1;
});
return Object.entries(platformCount).map(([platform, count]) => ({
name: PLATFORM_CONFIG[platform].text,
value: count,
color: PLATFORM_CONFIG[platform].color,
}));
}, [orders]);
// 计算订单状态分布数据
const statusDistributionData = useMemo(() => {
const statusCount: Record<string, number> = {};
orders.forEach(order => {
statusCount[order.status] = (statusCount[order.status] || 0) + 1;
});
return Object.entries(statusCount).map(([status, count]) => ({
name: STATUS_CONFIG[status].text,
value: count,
color: STATUS_CONFIG[status].color,
}));
}, [orders]);
const columns: ColumnsType<Order> = [
{
title: '订单号',
@@ -520,7 +710,7 @@ export const OrderList: React.FC = () => {
render: (text, record) => (
<Space direction="vertical" size={0}>
<Text strong>{text}</Text>
<Tag color={PLATFORM_CONFIG[record.platform].color}>
<Tag color={PLATFORM_CONFIG[record.platform].color} icon={PLATFORM_CONFIG[record.platform].icon}>
{PLATFORM_CONFIG[record.platform].text}
</Tag>
</Space>
@@ -737,13 +927,170 @@ export const OrderList: React.FC = () => {
</Col>
</Row>
<Tabs activeKey={activeTab} onChange={handleTabChange} style={{ marginBottom: 16 }}>
<TabPane tab="全部" key="all" />
<TabPane tab={`待处理 (${stats.pending})`} key="pending" />
<TabPane tab={`处理中 (${stats.processing})`} key="processing" />
<TabPane tab={`已完成 (${stats.completed})`} key="completed" />
<TabPane tab={`异常 (${stats.exception})`} key="exception" />
</Tabs>
<Card style={{ marginBottom: 16 }}>
<Tabs
activeKey={activeStatsTab}
onChange={setActiveStatsTab}
items={[
{ key: 'overview', label: '订单概览' },
{ key: 'trend', label: '订单趋势' },
{ key: 'distribution', label: '分布分析' },
]}
>
<Tabs.TabPane key="overview">
<Row gutter={16}>
<Col span={12}>
<Card title="订单趋势最近7天" size="small">
<ResponsiveContainer width="100%" height={300}>
<LineChart
data={orderTrendData}
margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="date" />
<YAxis yAxisId="left" />
<YAxis yAxisId="right" orientation="right" />
<Tooltip />
<Legend />
<Line yAxisId="left" type="monotone" dataKey="orders" name="订单数" stroke="#1890ff" activeDot={{ r: 8 }} />
<Line yAxisId="right" type="monotone" dataKey="amount" name="金额" stroke="#52c41a" />
</LineChart>
</ResponsiveContainer>
</Card>
</Col>
<Col span={12}>
<Card title="平台分布" size="small">
<ResponsiveContainer width="100%" height={300}>
<Pie
data={platformDistributionData}
cx="50%"
cy="50%"
labelLine={false}
outerRadius={100}
fill="#8884d8"
dataKey="value"
label={({ name, percent }) => `${name}: ${((percent || 0) * 100).toFixed(0)}%`}
>
{platformDistributionData.map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.color} />
))}
</Pie>
</ResponsiveContainer>
</Card>
</Col>
</Row>
</Tabs.TabPane>
<Tabs.TabPane key="trend">
<Card title="订单趋势分析" size="small">
<ResponsiveContainer width="100%" height={400}>
<BarChart
data={orderTrendData}
margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="date" />
<YAxis yAxisId="left" />
<YAxis yAxisId="right" orientation="right" />
<Tooltip />
<Legend />
<Bar yAxisId="left" dataKey="orders" name="订单数" fill="#1890ff" />
<Bar yAxisId="right" dataKey="amount" name="金额" fill="#52c41a" />
</BarChart>
</ResponsiveContainer>
</Card>
</Tabs.TabPane>
<Tabs.TabPane key="distribution">
<Row gutter={16}>
<Col span={12}>
<Card title="平台分布" size="small">
<ResponsiveContainer width="100%" height={300}>
<Pie
data={platformDistributionData}
cx="50%"
cy="50%"
labelLine={false}
outerRadius={100}
fill="#8884d8"
dataKey="value"
label={({ name, percent }) => `${name}: ${((percent || 0) * 100).toFixed(0)}%`}
>
{platformDistributionData.map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.color} />
))}
</Pie>
</ResponsiveContainer>
</Card>
</Col>
<Col span={12}>
<Card title="状态分布" size="small">
<ResponsiveContainer width="100%" height={300}>
<Pie
data={statusDistributionData}
cx="50%"
cy="50%"
labelLine={false}
outerRadius={100}
fill="#8884d8"
dataKey="value"
label={({ name, percent }) => `${name}: ${((percent || 0) * 100).toFixed(0)}%`}
>
{statusDistributionData.map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.color} />
))}
</Pie>
</ResponsiveContainer>
</Card>
</Col>
</Row>
</Tabs.TabPane>
</Tabs>
</Card>
<Tabs
activeKey={activeTab}
onChange={handleTabChange}
items={[
{ key: 'all', label: '全部' },
{ key: 'pending', label: `待处理 (${stats.pending})` },
{ key: 'processing', label: `处理中 (${stats.processing})` },
{ key: 'completed', label: `已完成 (${stats.completed})` },
{ key: 'exception', label: `异常 (${stats.exception})` },
]}
tabBarExtraContent={
<Tabs
activeKey={activePlatformTab}
onChange={setActivePlatformTab}
size="small"
style={{ marginBottom: 0 }}
items={[
{
key: 'all',
label: (
<span>
<AppstoreOutlined />
</span>
),
},
...Object.entries(PLATFORM_CONFIG).map(([key, config]) => {
const stat = platformStats[key] || { total: 0, amount: 0, pending: 0 };
return {
key,
label: (
<span>
{config.icon}
{config.text} ({stat.total})
{stat.pending > 0 && (
<Badge count={stat.pending} size="small" style={{ marginLeft: 4 }} />
)}
</span>
),
};
}),
]}
/>
}
/>
<Row gutter={[16, 16]} style={{ marginBottom: 16 }}>
<Col span={24}>
@@ -770,15 +1117,18 @@ export const OrderList: React.FC = () => {
<Space>
{selectedRows.length > 0 && (
<Space>
<Button onClick={() => message.info('批量确认功能开发中')}>
<Button onClick={handleBatchConfirm}>
</Button>
<Button onClick={() => message.info('批量发货功能开发中')}>
<Button onClick={handleBatchShip}>
</Button>
<Button danger onClick={() => message.info('批量取消功能开发中')}>
<Button danger onClick={handleBatchCancel}>
</Button>
<Button onClick={handleBatchExport}>
</Button>
</Space>
)}
<Button icon={<ExportOutlined />}>