Files
makemd/dashboard/src/pages/IndependentSite/IndependentSiteAnalytics.tsx

284 lines
9.3 KiB
TypeScript
Raw Normal View History

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 { useParams } from 'react-router-dom';
import { independentSiteDataSource, SiteAnalytics } from '@/services/independentSiteDataSource';
const { RangePicker } = DatePicker;
const { Option } = Select;
const { TabPane } = Tabs;
interface SalesData {
date: string;
sales: number;
orders: number;
customers: number;
}
interface ProductData {
name: string;
sales: number;
quantity: number;
}
interface TrafficData {
date: string;
visitors: number;
pageViews: number;
bounceRate: number;
}
interface ConversionData {
name: string;
value: number;
}
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,
});
useEffect(() => {
fetchAnalyticsData();
}, [id, timeRange, dateRange]);
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);
};
const handleTimeRangeChange = (value: string) => {
setTimeRange(value);
};
const handleDateRangeChange = (dates: any) => {
setDateRange(dates);
};
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>
{loading ? (
<div style={{ textAlign: 'center', padding: '50px 0' }}>
<Spin size="large" />
</div>
) : (
<>
<Row gutter={16} style={{ marginBottom: 24 }}>
<Col span={6}>
<Card>
<Statistic
title="总销售额"
value={summary.totalSales}
precision={2}
prefix="$"
suffix="USD"
/>
</Card>
</Col>
<Col span={6}>
<Card>
<Statistic
title="总订单数"
value={summary.totalOrders}
/>
</Card>
</Col>
<Col span={6}>
<Card>
<Statistic
title="总客户数"
value={summary.totalCustomers}
/>
</Card>
</Col>
<Col span={6}>
<Card>
<Statistic
title="转化率"
value={summary.conversionRate}
precision={2}
suffix="%"
/>
</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>
</>
)}
</div>
);
};
export default IndependentSiteAnalytics;