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,12 +1,12 @@
import React, { useState, useEffect } from 'react';
import { Card, DatePicker, Select, Spin, Statistic, Row, Col, Tabs, Button } from 'antd';
import { Area, AreaChart, Bar, BarChart, Line, LineChart, Pie, PieChart, ResponsiveContainer, Tooltip, XAxis, YAxis, CartesianGrid, Legend } from 'recharts';
import { Card, DatePicker, Select, Spin, Statistic, Row, Col, Tabs, Button, Table, Tag, Space, Typography } from 'antd';
import { useParams } from 'react-router-dom';
import { independentSiteDataSource, SiteAnalytics } from '@/services/independentSiteDataSource';
import { Line, Column, Pie, Area, DualAxes } from '@ant-design/plots';
import { ReloadOutlined, ExportOutlined, DollarOutlined, ShoppingCartOutlined, TeamOutlined, RiseOutlined } from '@ant-design/icons';
const { RangePicker } = DatePicker;
const { Option } = Select;
const { TabPane } = Tabs;
const { Title, Text } = Typography;
interface SalesData {
date: string;
@@ -28,26 +28,67 @@ interface TrafficData {
bounceRate: number;
}
interface ConversionData {
name: string;
value: number;
}
const SALES_TREND_DATA: SalesData[] = [
{ date: '2026-03-01', sales: 5200, orders: 42, customers: 35 },
{ date: '2026-03-02', sales: 6100, orders: 51, customers: 42 },
{ date: '2026-03-03', sales: 4800, orders: 38, customers: 31 },
{ date: '2026-03-04', sales: 7500, orders: 62, customers: 48 },
{ date: '2026-03-05', sales: 6800, orders: 55, customers: 45 },
{ date: '2026-03-06', sales: 8200, orders: 68, customers: 52 },
{ date: '2026-03-07', sales: 9100, orders: 75, customers: 58 },
{ date: '2026-03-08', sales: 7800, orders: 64, customers: 49 },
{ date: '2026-03-09', sales: 8500, orders: 70, customers: 55 },
{ date: '2026-03-10', sales: 9800, orders: 82, customers: 65 },
];
const PRODUCT_DATA: ProductData[] = [
{ name: '无线蓝牙耳机', sales: 15800, quantity: 158 },
{ name: '智能手表', sales: 12500, quantity: 50 },
{ name: '便携充电宝', sales: 8900, quantity: 178 },
{ name: '手机支架', sales: 6200, quantity: 310 },
{ name: '数据线套装', sales: 4500, quantity: 450 },
];
const TRAFFIC_DATA: TrafficData[] = [
{ date: '2026-03-01', visitors: 1250, pageViews: 3800, bounceRate: 35 },
{ date: '2026-03-02', visitors: 1480, pageViews: 4200, bounceRate: 32 },
{ date: '2026-03-03', visitors: 1100, pageViews: 3200, bounceRate: 38 },
{ date: '2026-03-04', visitors: 1800, pageViews: 5500, bounceRate: 28 },
{ date: '2026-03-05', visitors: 1650, pageViews: 4800, bounceRate: 30 },
{ date: '2026-03-06', visitors: 2100, pageViews: 6200, bounceRate: 25 },
{ date: '2026-03-07', visitors: 2350, pageViews: 7100, bounceRate: 22 },
{ date: '2026-03-08', visitors: 1900, pageViews: 5600, bounceRate: 27 },
{ date: '2026-03-09', visitors: 2200, pageViews: 6500, bounceRate: 24 },
{ date: '2026-03-10', visitors: 2500, pageViews: 7500, bounceRate: 20 },
];
const CONVERSION_DATA = [
{ type: '直接购买', value: 35 },
{ type: '加购后购买', value: 28 },
{ type: '收藏后购买', value: 15 },
{ type: '未转化', value: 22 },
];
const REGION_DATA = [
{ region: '美国', customers: 450, percentage: 35 },
{ region: '欧洲', customers: 320, percentage: 25 },
{ region: '东南亚', customers: 280, percentage: 22 },
{ region: '中东', customers: 150, percentage: 12 },
{ region: '其他', customers: 80, percentage: 6 },
];
const DEVICE_DATA = [
{ device: '移动端', value: 65, color: '#1890ff' },
{ device: '桌面端', value: 30, color: '#52c41a' },
{ device: '平板', value: 5, color: '#faad14' },
];
const IndependentSiteAnalytics: React.FC = () => {
const { id } = useParams<{ id: string }>();
const [loading, setLoading] = useState(false);
const [dateRange, setDateRange] = useState<any>(null);
const [timeRange, setTimeRange] = useState('30d');
const [salesData, setSalesData] = useState<SalesData[]>([]);
const [productData, setProductData] = useState<ProductData[]>([]);
const [trafficData, setTrafficData] = useState<TrafficData[]>([]);
const [conversionData, setConversionData] = useState<ConversionData[]>([]);
const [summary, setSummary] = useState({
totalSales: 0,
totalOrders: 0,
totalCustomers: 0,
conversionRate: 0,
});
const [activeTab, setActiveTab] = useState('sales');
useEffect(() => {
fetchAnalyticsData();
@@ -55,85 +96,218 @@ const IndependentSiteAnalytics: React.FC = () => {
const fetchAnalyticsData = async () => {
setLoading(true);
// 模拟API调用
setTimeout(() => {
// 模拟销售数据
const mockSalesData: SalesData[] = Array.from({ length: 30 }, (_, i) => ({
date: `2026-03-${String(i + 1).padStart(2, '0')}`,
sales: Math.random() * 1000 + 500,
orders: Math.random() * 50 + 10,
customers: Math.random() * 30 + 5,
}));
// 模拟商品数据
const mockProductData: ProductData[] = [
{ name: 'Product 1', sales: 1500, quantity: 15 },
{ name: 'Product 2', sales: 2000, quantity: 20 },
{ name: 'Product 3', sales: 1000, quantity: 10 },
{ name: 'Product 4', sales: 500, quantity: 5 },
{ name: 'Product 5', sales: 800, quantity: 8 },
];
// 模拟流量数据
const mockTrafficData: TrafficData[] = Array.from({ length: 30 }, (_, i) => ({
date: `2026-03-${String(i + 1).padStart(2, '0')}`,
visitors: Math.random() * 500 + 100,
pageViews: Math.random() * 1000 + 500,
bounceRate: Math.random() * 50 + 20,
}));
// 模拟转化数据
const mockConversionData: ConversionData[] = [
{ name: '已转化', value: 20 },
{ name: '未转化', value: 80 },
];
// 模拟汇总数据
const mockSummary = {
totalSales: 5800,
totalOrders: 78,
totalCustomers: 55,
conversionRate: 20,
};
setSalesData(mockSalesData);
setProductData(mockProductData);
setTrafficData(mockTrafficData);
setConversionData(mockConversionData);
setSummary(mockSummary);
setLoading(false);
}, 1000);
}, 500);
};
const handleTimeRangeChange = (value: string) => {
setTimeRange(value);
const salesTrendConfig = {
data: SALES_TREND_DATA.flatMap(item => [
{ date: item.date, value: item.sales, type: '销售额' },
{ date: item.date, value: item.orders * 100, type: '订单数' },
]),
xField: 'date',
yField: 'value',
seriesField: 'type',
smooth: true,
legend: { position: 'top' as const },
yAxis: { label: { formatter: (v: number) => `$${v / 1000}k` } },
};
const handleDateRangeChange = (dates: any) => {
setDateRange(dates);
const productSalesConfig = {
data: PRODUCT_DATA,
xField: 'name',
yField: 'sales',
color: '#1890ff',
label: { text: 'sales', position: 'top' as const },
};
const trafficConfig = {
data: [TRAFFIC_DATA, TRAFFIC_DATA],
xField: 'date',
yField: ['visitors', 'pageViews'],
geometryOptions: [
{ geometry: 'line', color: '#1890ff', smooth: true },
{ geometry: 'line', color: '#52c41a', smooth: true },
],
legend: { position: 'top' as const },
};
const conversionConfig = {
data: CONVERSION_DATA,
angleField: 'value',
colorField: 'type',
radius: 0.8,
innerRadius: 0.6,
label: { text: 'type', position: 'outside' },
legend: { position: 'bottom' as const },
};
const regionConfig = {
data: REGION_DATA,
xField: 'region',
yField: 'customers',
color: '#722ed1',
label: { text: 'customers', position: 'top' as const },
};
const deviceConfig = {
data: DEVICE_DATA,
angleField: 'value',
colorField: 'device',
radius: 0.8,
innerRadius: 0.6,
label: { text: 'device', position: 'outside' },
legend: { position: 'bottom' as const },
};
const productColumns = [
{ title: '商品名称', dataIndex: 'name', key: 'name' },
{ title: '销售额', dataIndex: 'sales', key: 'sales', render: (v: number) => `$${v.toLocaleString()}` },
{ title: '销量', dataIndex: 'quantity', key: 'quantity' },
{ title: '占比', key: 'percentage', render: (_: any, record: ProductData) => {
const total = PRODUCT_DATA.reduce((sum, p) => sum + p.sales, 0);
return `${((record.sales / total) * 100).toFixed(1)}%`;
}},
];
const tabItems = [
{
key: 'sales',
label: '销售分析',
children: (
<Row gutter={16}>
<Col span={24}>
<Card title="销售趋势">
<Line {...salesTrendConfig} height={300} />
</Card>
</Col>
<Col xs={24} lg={16} style={{ marginTop: 16 }}>
<Card title="商品销售排行">
<Column {...productSalesConfig} height={280} />
</Card>
</Col>
<Col xs={24} lg={8} style={{ marginTop: 16 }}>
<Card title="转化漏斗">
<Pie {...conversionConfig} height={280} />
</Card>
</Col>
<Col span={24} style={{ marginTop: 16 }}>
<Card title="商品销售明细">
<Table columns={productColumns} dataSource={PRODUCT_DATA} rowKey="name" pagination={false} />
</Card>
</Col>
</Row>
),
},
{
key: 'traffic',
label: '流量分析',
children: (
<Row gutter={16}>
<Col span={24}>
<Card title="流量趋势">
<DualAxes {...trafficConfig} height={300} />
</Card>
</Col>
<Col xs={24} lg={12} style={{ marginTop: 16 }}>
<Card title="设备分布">
<Pie {...deviceConfig} height={280} />
</Card>
</Col>
<Col xs={24} lg={12} style={{ marginTop: 16 }}>
<Card title="流量来源">
<Table
columns={[
{ title: '来源', dataIndex: 'source', key: 'source' },
{ title: '访客数', dataIndex: 'visitors', key: 'visitors' },
{ title: '占比', dataIndex: 'percentage', key: 'percentage', render: (v: number) => `${v}%` },
]}
dataSource={[
{ key: '1', source: '搜索引擎', visitors: 3500, percentage: 42 },
{ key: '2', source: '社交媒体', visitors: 2100, percentage: 25 },
{ key: '3', source: '直接访问', visitors: 1500, percentage: 18 },
{ key: '4', source: '广告投放', visitors: 800, percentage: 10 },
{ key: '5', source: '其他', visitors: 400, percentage: 5 },
]}
pagination={false}
/>
</Card>
</Col>
</Row>
),
},
{
key: 'customer',
label: '客户分析',
children: (
<Row gutter={16}>
<Col xs={24} lg={16}>
<Card title="客户地域分布">
<Column {...regionConfig} height={300} />
</Card>
</Col>
<Col xs={24} lg={8}>
<Card title="客户类型">
<Pie
data={[
{ type: '新客户', value: 45 },
{ type: '回头客', value: 35 },
{ type: 'VIP客户', value: 20 },
]}
angleField="value"
colorField="type"
radius={0.8}
innerRadius={0.6}
label={{ text: 'type', position: 'outside' }}
height={280}
/>
</Card>
</Col>
<Col span={24} style={{ marginTop: 16 }}>
<Card title="客户购买行为分析">
<Row gutter={16}>
<Col span={6}>
<Statistic title="平均订单金额" value={125} prefix={<DollarOutlined />} suffix="USD" />
</Col>
<Col span={6}>
<Statistic title="复购率" value={35} suffix="%" valueStyle={{ color: '#52c41a' }} prefix={<RiseOutlined />} />
</Col>
<Col span={6}>
<Statistic title="平均购买频次" value={2.3} suffix="次/月" />
</Col>
<Col span={6}>
<Statistic title="客户满意度" value={4.8} suffix="/ 5.0" valueStyle={{ color: '#faad14' }} />
</Col>
</Row>
</Card>
</Col>
</Row>
),
},
];
return (
<div className="independent-site-analytics">
<div className="page-header">
<h1></h1>
<div style={{ display: 'flex', gap: 16 }}>
<Select
value={timeRange}
onChange={handleTimeRangeChange}
style={{ width: 120 }}
>
<Option value="7d">7</Option>
<Option value="30d">30</Option>
<Option value="90d">90</Option>
<Option value="1y">1</Option>
</Select>
<RangePicker onChange={handleDateRangeChange} />
<Button type="primary" onClick={fetchAnalyticsData}>
</Button>
</div>
</div>
<div className="independent-site-analytics" style={{ padding: 24 }}>
<Row justify="space-between" align="middle" style={{ marginBottom: 24 }}>
<Col>
<Title level={4}></Title>
<Text type="secondary">ID: {id}</Text>
</Col>
<Col>
<Space>
<Select value={timeRange} onChange={setTimeRange} style={{ width: 120 }}>
<Option value="7d">7</Option>
<Option value="30d">30</Option>
<Option value="90d">90</Option>
<Option value="1y">1</Option>
</Select>
<RangePicker onChange={setDateRange} />
<Button icon={<ReloadOutlined />} onClick={fetchAnalyticsData}></Button>
<Button type="primary" icon={<ExportOutlined />}></Button>
</Space>
</Col>
</Row>
{loading ? (
<div style={{ textAlign: 'center', padding: '50px 0' }}>
@@ -142,143 +316,33 @@ const IndependentSiteAnalytics: React.FC = () => {
) : (
<>
<Row gutter={16} style={{ marginBottom: 24 }}>
<Col span={6}>
<Col xs={12} sm={6}>
<Card>
<Statistic
title="总销售额"
value={summary.totalSales}
precision={2}
prefix="$"
suffix="USD"
/>
<Statistic title="总销售额" value={73800} precision={2} prefix={<DollarOutlined />} suffix="USD" valueStyle={{ color: '#3f8600' }} />
</Card>
</Col>
<Col span={6}>
<Col xs={12} sm={6}>
<Card>
<Statistic
title="总订单数"
value={summary.totalOrders}
/>
<Statistic title="总订单数" value={607} prefix={<ShoppingCartOutlined />} />
</Card>
</Col>
<Col span={6}>
<Col xs={12} sm={6}>
<Card>
<Statistic
title="总客户数"
value={summary.totalCustomers}
/>
<Statistic title="总客户数" value={480} prefix={<TeamOutlined />} />
</Card>
</Col>
<Col span={6}>
<Col xs={12} sm={6}>
<Card>
<Statistic
title="转化率"
value={summary.conversionRate}
precision={2}
suffix="%"
/>
<Statistic title="转化率" value={4.2} precision={2} suffix="%" valueStyle={{ color: '#722ed1' }} prefix={<RiseOutlined />} />
</Card>
</Col>
</Row>
<Tabs defaultActiveKey="sales">
<TabPane tab="销售分析" key="sales">
<Row gutter={16}>
<Col span={24}>
<Card title="销售趋势">
<ResponsiveContainer width="100%" height={400}>
<AreaChart data={salesData}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="date" />
<YAxis />
<Tooltip />
<Legend />
<Area type="monotone" dataKey="sales" stackId="1" stroke="#8884d8" fill="#8884d8" />
<Area type="monotone" dataKey="orders" stackId="2" stroke="#82ca9d" fill="#82ca9d" />
</AreaChart>
</ResponsiveContainer>
</Card>
</Col>
<Col span={12}>
<Card title="商品销售排行">
<ResponsiveContainer width="100%" height={400}>
<BarChart data={productData}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="name" />
<YAxis />
<Tooltip />
<Legend />
<Bar dataKey="sales" fill="#8884d8" />
</BarChart>
</ResponsiveContainer>
</Card>
</Col>
<Col span={12}>
<Card title="转化率">
<ResponsiveContainer width="100%" height={400}>
<PieChart>
<Pie
data={conversionData}
cx="50%"
cy="50%"
labelLine={false}
label={({ name, percent }) => `${name}: ${((percent || 0) * 100).toFixed(0)}%`}
outerRadius={150}
fill="#8884d8"
dataKey="value"
/>
<Tooltip />
</PieChart>
</ResponsiveContainer>
</Card>
</Col>
</Row>
</TabPane>
<TabPane tab="流量分析" key="traffic">
<Row gutter={16}>
<Col span={24}>
<Card title="流量趋势">
<ResponsiveContainer width="100%" height={400}>
<LineChart data={trafficData}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="date" />
<YAxis />
<Tooltip />
<Legend />
<Line type="monotone" dataKey="visitors" stroke="#8884d8" />
<Line type="monotone" dataKey="pageViews" stroke="#82ca9d" />
<Line type="monotone" dataKey="bounceRate" stroke="#ff7300" />
</LineChart>
</ResponsiveContainer>
</Card>
</Col>
</Row>
</TabPane>
<TabPane tab="客户分析" key="customer">
<Row gutter={16}>
<Col span={12}>
<Card title="客户地域分布">
<div style={{ textAlign: 'center', padding: '50px 0' }}>
<p></p>
</div>
</Card>
</Col>
<Col span={12}>
<Card title="客户购买行为">
<div style={{ textAlign: 'center', padding: '50px 0' }}>
<p></p>
</div>
</Card>
</Col>
</Row>
</TabPane>
</Tabs>
<Tabs activeKey={activeTab} onChange={setActiveTab} items={tabItems} />
</>
)}
</div>
);
};
export default IndependentSiteAnalytics;
export default IndependentSiteAnalytics;