2026-03-27 16:56:06 +08:00
|
|
|
import {
|
|
|
|
|
useState,
|
|
|
|
|
useEffect,
|
|
|
|
|
useParams,
|
|
|
|
|
Card,
|
|
|
|
|
DatePicker,
|
|
|
|
|
Select,
|
|
|
|
|
Spin,
|
|
|
|
|
Statistic,
|
|
|
|
|
Row,
|
|
|
|
|
Col,
|
|
|
|
|
Tabs,
|
|
|
|
|
Button,
|
|
|
|
|
Table,
|
|
|
|
|
Tag,
|
|
|
|
|
Space,
|
|
|
|
|
Typography,
|
|
|
|
|
Line,
|
|
|
|
|
Column,
|
|
|
|
|
Pie,
|
|
|
|
|
Area,
|
|
|
|
|
DualAxes,
|
|
|
|
|
ReloadOutlined,
|
|
|
|
|
ExportOutlined,
|
|
|
|
|
DollarOutlined,
|
|
|
|
|
ShoppingCartOutlined,
|
|
|
|
|
TeamOutlined,
|
|
|
|
|
RiseOutlined,
|
|
|
|
|
RangePicker,
|
|
|
|
|
Option,
|
|
|
|
|
Title,
|
|
|
|
|
Text,
|
|
|
|
|
FC,
|
|
|
|
|
} from '@/imports';
|
2026-03-18 19:12:38 +08:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-23 12:41:35 +08:00
|
|
|
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' },
|
|
|
|
|
];
|
2026-03-18 19:12:38 +08:00
|
|
|
|
2026-03-27 16:56:06 +08:00
|
|
|
const IndependentSiteAnalytics: FC = () => {
|
2026-03-18 19:12:38 +08:00
|
|
|
const { id } = useParams<{ id: string }>();
|
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
|
const [dateRange, setDateRange] = useState<any>(null);
|
|
|
|
|
const [timeRange, setTimeRange] = useState('30d');
|
2026-03-23 12:41:35 +08:00
|
|
|
const [activeTab, setActiveTab] = useState('sales');
|
2026-03-18 19:12:38 +08:00
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
fetchAnalyticsData();
|
|
|
|
|
}, [id, timeRange, dateRange]);
|
|
|
|
|
|
|
|
|
|
const fetchAnalyticsData = async () => {
|
|
|
|
|
setLoading(true);
|
|
|
|
|
setTimeout(() => {
|
2026-03-23 12:41:35 +08:00
|
|
|
setLoading(false);
|
|
|
|
|
}, 500);
|
|
|
|
|
};
|
2026-03-18 19:12:38 +08:00
|
|
|
|
2026-03-23 12:41:35 +08:00
|
|
|
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` } },
|
|
|
|
|
};
|
2026-03-18 19:12:38 +08:00
|
|
|
|
2026-03-23 12:41:35 +08:00
|
|
|
const productSalesConfig = {
|
|
|
|
|
data: PRODUCT_DATA,
|
|
|
|
|
xField: 'name',
|
|
|
|
|
yField: 'sales',
|
|
|
|
|
color: '#1890ff',
|
|
|
|
|
label: { text: 'sales', position: 'top' as const },
|
|
|
|
|
};
|
2026-03-18 19:12:38 +08:00
|
|
|
|
2026-03-23 12:41:35 +08:00
|
|
|
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 },
|
|
|
|
|
};
|
2026-03-18 19:12:38 +08:00
|
|
|
|
2026-03-23 12:41:35 +08:00
|
|
|
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 },
|
2026-03-18 19:12:38 +08:00
|
|
|
};
|
|
|
|
|
|
2026-03-23 12:41:35 +08:00
|
|
|
const regionConfig = {
|
|
|
|
|
data: REGION_DATA,
|
|
|
|
|
xField: 'region',
|
|
|
|
|
yField: 'customers',
|
|
|
|
|
color: '#722ed1',
|
|
|
|
|
label: { text: 'customers', position: 'top' as const },
|
2026-03-18 19:12:38 +08:00
|
|
|
};
|
|
|
|
|
|
2026-03-23 12:41:35 +08:00
|
|
|
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 },
|
2026-03-18 19:12:38 +08:00
|
|
|
};
|
|
|
|
|
|
2026-03-23 12:41:35 +08:00
|
|
|
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>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
2026-03-18 19:12:38 +08:00
|
|
|
return (
|
2026-03-23 12:41:35 +08:00
|
|
|
<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>
|
2026-03-18 19:12:38 +08:00
|
|
|
|
|
|
|
|
{loading ? (
|
|
|
|
|
<div style={{ textAlign: 'center', padding: '50px 0' }}>
|
|
|
|
|
<Spin size="large" />
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<>
|
|
|
|
|
<Row gutter={16} style={{ marginBottom: 24 }}>
|
2026-03-23 12:41:35 +08:00
|
|
|
<Col xs={12} sm={6}>
|
2026-03-18 19:12:38 +08:00
|
|
|
<Card>
|
2026-03-23 12:41:35 +08:00
|
|
|
<Statistic title="总销售额" value={73800} precision={2} prefix={<DollarOutlined />} suffix="USD" valueStyle={{ color: '#3f8600' }} />
|
2026-03-18 19:12:38 +08:00
|
|
|
</Card>
|
|
|
|
|
</Col>
|
2026-03-23 12:41:35 +08:00
|
|
|
<Col xs={12} sm={6}>
|
2026-03-18 19:12:38 +08:00
|
|
|
<Card>
|
2026-03-23 12:41:35 +08:00
|
|
|
<Statistic title="总订单数" value={607} prefix={<ShoppingCartOutlined />} />
|
2026-03-18 19:12:38 +08:00
|
|
|
</Card>
|
|
|
|
|
</Col>
|
2026-03-23 12:41:35 +08:00
|
|
|
<Col xs={12} sm={6}>
|
2026-03-18 19:12:38 +08:00
|
|
|
<Card>
|
2026-03-23 12:41:35 +08:00
|
|
|
<Statistic title="总客户数" value={480} prefix={<TeamOutlined />} />
|
2026-03-18 19:12:38 +08:00
|
|
|
</Card>
|
|
|
|
|
</Col>
|
2026-03-23 12:41:35 +08:00
|
|
|
<Col xs={12} sm={6}>
|
2026-03-18 19:12:38 +08:00
|
|
|
<Card>
|
2026-03-23 12:41:35 +08:00
|
|
|
<Statistic title="转化率" value={4.2} precision={2} suffix="%" valueStyle={{ color: '#722ed1' }} prefix={<RiseOutlined />} />
|
2026-03-18 19:12:38 +08:00
|
|
|
</Card>
|
|
|
|
|
</Col>
|
|
|
|
|
</Row>
|
|
|
|
|
|
2026-03-23 12:41:35 +08:00
|
|
|
<Tabs activeKey={activeTab} onChange={setActiveTab} items={tabItems} />
|
2026-03-18 19:12:38 +08:00
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2026-03-23 12:41:35 +08:00
|
|
|
export default IndependentSiteAnalytics;
|