feat: 添加前端页面和业务说明书
refactor(server): 重构服务层代码结构 feat(server): 添加基础设施、跨境电商、AI决策等核心服务 docs: 完善前端业务说明书和开发进度文档 style: 格式化代码和文档
This commit is contained in:
325
dashboard/src/pages/Product/ROIAnalysis/index.tsx
Normal file
325
dashboard/src/pages/Product/ROIAnalysis/index.tsx
Normal file
@@ -0,0 +1,325 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Card, Layout, Typography, Row, Col, DatePicker, Select, Button, Table, Statistic, Spin, message } from 'antd';
|
||||
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, LineChart, Line } from 'recharts';
|
||||
import { ArrowUpOutlined, ArrowDownOutlined, ReloadOutlined } from '@ant-design/icons';
|
||||
import { Link } from 'umi';
|
||||
|
||||
const { Content } = Layout;
|
||||
const { Title, Text } = Typography;
|
||||
const { RangePicker } = DatePicker;
|
||||
const { Option } = Select;
|
||||
|
||||
interface ROIItem {
|
||||
id: string;
|
||||
productId: string;
|
||||
productName: string;
|
||||
cost: number;
|
||||
price: number;
|
||||
profit: number;
|
||||
roi: number;
|
||||
salesVolume: number;
|
||||
date: string;
|
||||
}
|
||||
|
||||
const ROIAnalysis: React.FC = () => {
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [roiData, setRoiData] = useState<ROIItem[]>([]);
|
||||
const [timeRange, setTimeRange] = useState<any>(null);
|
||||
const [productId, setProductId] = useState<string>('');
|
||||
const [summary, setSummary] = useState<{
|
||||
totalSales: number;
|
||||
totalProfit: number;
|
||||
averageROI: number;
|
||||
bestProduct: string;
|
||||
}>({
|
||||
totalSales: 0,
|
||||
totalProfit: 0,
|
||||
averageROI: 0,
|
||||
bestProduct: '',
|
||||
});
|
||||
|
||||
const mockROIData: ROIItem[] = [
|
||||
{
|
||||
id: '1',
|
||||
productId: 'P001',
|
||||
productName: '智能手表',
|
||||
cost: 150,
|
||||
price: 299,
|
||||
profit: 149,
|
||||
roi: 99.33,
|
||||
salesVolume: 120,
|
||||
date: '2026-03-01',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
productId: 'P001',
|
||||
productName: '智能手表',
|
||||
cost: 150,
|
||||
price: 299,
|
||||
profit: 149,
|
||||
roi: 99.33,
|
||||
salesVolume: 110,
|
||||
date: '2026-03-02',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
productId: 'P001',
|
||||
productName: '智能手表',
|
||||
cost: 150,
|
||||
price: 299,
|
||||
profit: 149,
|
||||
roi: 99.33,
|
||||
salesVolume: 130,
|
||||
date: '2026-03-03',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
productId: 'P002',
|
||||
productName: '无线耳机',
|
||||
cost: 80,
|
||||
price: 199,
|
||||
profit: 119,
|
||||
roi: 148.75,
|
||||
salesVolume: 200,
|
||||
date: '2026-03-01',
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
productId: 'P002',
|
||||
productName: '无线耳机',
|
||||
cost: 80,
|
||||
price: 199,
|
||||
profit: 119,
|
||||
roi: 148.75,
|
||||
salesVolume: 210,
|
||||
date: '2026-03-02',
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
productId: 'P002',
|
||||
productName: '无线耳机',
|
||||
cost: 80,
|
||||
price: 199,
|
||||
profit: 119,
|
||||
roi: 148.75,
|
||||
salesVolume: 190,
|
||||
date: '2026-03-03',
|
||||
},
|
||||
];
|
||||
|
||||
const fetchROIData = () => {
|
||||
setLoading(true);
|
||||
// 模拟API请求
|
||||
setTimeout(() => {
|
||||
setRoiData(mockROIData);
|
||||
// 计算汇总数据
|
||||
const totalSales = mockROIData.reduce((sum, item) => sum + item.salesVolume, 0);
|
||||
const totalProfit = mockROIData.reduce((sum, item) => sum + item.profit * item.salesVolume, 0);
|
||||
const averageROI = mockROIData.reduce((sum, item) => sum + item.roi, 0) / mockROIData.length;
|
||||
const bestProduct = mockROIData.reduce((best, current) =>
|
||||
current.roi > best.roi ? current : best
|
||||
).productName;
|
||||
|
||||
setSummary({
|
||||
totalSales,
|
||||
totalProfit,
|
||||
averageROI: parseFloat(averageROI.toFixed(2)),
|
||||
bestProduct,
|
||||
});
|
||||
setLoading(false);
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchROIData();
|
||||
}, []);
|
||||
|
||||
const handleTimeRangeChange = (dates: any) => {
|
||||
setTimeRange(dates);
|
||||
};
|
||||
|
||||
const handleProductChange = (value: string) => {
|
||||
setProductId(value);
|
||||
};
|
||||
|
||||
const handleRefresh = () => {
|
||||
fetchROIData();
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '商品ID',
|
||||
dataIndex: 'productId',
|
||||
key: 'productId',
|
||||
},
|
||||
{
|
||||
title: '商品名称',
|
||||
dataIndex: 'productName',
|
||||
key: 'productName',
|
||||
},
|
||||
{
|
||||
title: '成本',
|
||||
dataIndex: 'cost',
|
||||
key: 'cost',
|
||||
render: (text: number) => `¥${text}`,
|
||||
},
|
||||
{
|
||||
title: '售价',
|
||||
dataIndex: 'price',
|
||||
key: 'price',
|
||||
render: (text: number) => `¥${text}`,
|
||||
},
|
||||
{
|
||||
title: '利润',
|
||||
dataIndex: 'profit',
|
||||
key: 'profit',
|
||||
render: (text: number) => `¥${text}`,
|
||||
},
|
||||
{
|
||||
title: 'ROI',
|
||||
dataIndex: 'roi',
|
||||
key: 'roi',
|
||||
render: (text: number) => `${text}%`,
|
||||
},
|
||||
{
|
||||
title: '销量',
|
||||
dataIndex: 'salesVolume',
|
||||
key: 'salesVolume',
|
||||
},
|
||||
{
|
||||
title: '日期',
|
||||
dataIndex: 'date',
|
||||
key: 'date',
|
||||
},
|
||||
];
|
||||
|
||||
// 准备图表数据
|
||||
const chartData = mockROIData.map(item => ({
|
||||
date: item.date,
|
||||
销量: item.salesVolume,
|
||||
利润: item.profit * item.salesVolume,
|
||||
}));
|
||||
|
||||
const roiTrendData = mockROIData.map(item => ({
|
||||
date: item.date,
|
||||
ROI: item.roi,
|
||||
}));
|
||||
|
||||
return (
|
||||
<Content style={{ padding: 24, margin: 0, minHeight: 280, background: '#fff' }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 24 }}>
|
||||
<Title level={4}>商品ROI分析</Title>
|
||||
<div style={{ display: 'flex', gap: 12 }}>
|
||||
<Select
|
||||
placeholder="选择商品"
|
||||
style={{ width: 200 }}
|
||||
onChange={handleProductChange}
|
||||
>
|
||||
<Option value="">全部商品</Option>
|
||||
<Option value="P001">智能手表</Option>
|
||||
<Option value="P002">无线耳机</Option>
|
||||
</Select>
|
||||
<RangePicker onChange={handleTimeRangeChange} />
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<ReloadOutlined />}
|
||||
onClick={handleRefresh}
|
||||
loading={loading}
|
||||
>
|
||||
刷新
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 汇总统计 */}
|
||||
<Row gutter={[16, 16]} style={{ marginBottom: 24 }}>
|
||||
<Col span={6}>
|
||||
<Card>
|
||||
<Statistic
|
||||
title="总销量"
|
||||
value={summary.totalSales}
|
||||
prefix={<ArrowUpOutlined />}
|
||||
suffix="件"
|
||||
valueStyle={{ color: '#3f8600' }}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<Card>
|
||||
<Statistic
|
||||
title="总利润"
|
||||
value={summary.totalProfit}
|
||||
prefix="¥"
|
||||
valueStyle={{ color: '#3f8600' }}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<Card>
|
||||
<Statistic
|
||||
title="平均ROI"
|
||||
value={summary.averageROI}
|
||||
suffix="%"
|
||||
valueStyle={{ color: '#3f8600' }}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<Card>
|
||||
<Statistic
|
||||
title="最佳商品"
|
||||
value={summary.bestProduct}
|
||||
valueStyle={{ color: '#1890ff' }}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{/* 图表区域 */}
|
||||
<Row gutter={[16, 16]} style={{ marginBottom: 24 }}>
|
||||
<Col span={12}>
|
||||
<Card title="销量与利润趋势">
|
||||
<ResponsiveContainer width="100%" height={300}>
|
||||
<BarChart data={chartData}>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey="date" />
|
||||
<YAxis />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
<Bar dataKey="销量" fill="#1890ff" />
|
||||
<Bar dataKey="利润" fill="#52c41a" />
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Card title="ROI趋势">
|
||||
<ResponsiveContainer width="100%" height={300}>
|
||||
<LineChart data={roiTrendData}>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey="date" />
|
||||
<YAxis />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
<Line type="monotone" dataKey="ROI" stroke="#ff4d4f" strokeWidth={2} />
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{/* 详细数据表格 */}
|
||||
<Card title="ROI详细数据">
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={roiData}
|
||||
rowKey="id"
|
||||
loading={loading}
|
||||
pagination={{ pageSize: 10 }}
|
||||
/>
|
||||
</Card>
|
||||
</Content>
|
||||
);
|
||||
};
|
||||
|
||||
export default ROIAnalysis;
|
||||
Reference in New Issue
Block a user