|
|
@@ -0,0 +1,105 @@
|
|
|
+import React from 'react';
|
|
|
+
|
|
|
+export function ProfitMetrics() {
|
|
|
+ const data = [
|
|
|
+ { year: '2021年', totalProfit: -1.5, netProfit: -1.7 },
|
|
|
+ { year: '2022年', totalProfit: 0.8, netProfit: 0.59 },
|
|
|
+ { year: '2023年', totalProfit: 1.28, netProfit: 0.6 },
|
|
|
+ { year: '2024年', totalProfit: 1.65, netProfit: 1.22 },
|
|
|
+ { year: '2025年', totalProfit: 1.34, netProfit: 1.00 },
|
|
|
+ ];
|
|
|
+
|
|
|
+ const maxPositive = Math.max(...data.map(d => Math.max(d.totalProfit, d.netProfit)).filter(v => v > 0));
|
|
|
+ const maxNegative = Math.min(...data.map(d => Math.min(d.totalProfit, d.netProfit)).filter(v => v < 0));
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div className="h-full">
|
|
|
+ {/* 模块标题 */}
|
|
|
+ <div className="flex justify-between items-center mb-6">
|
|
|
+ <div className="flex items-center gap-4">
|
|
|
+ <div className="flex items-center gap-2">
|
|
|
+ <div className="w-3 h-3 bg-cyan-500 rounded-sm"></div>
|
|
|
+ <span className="text-lg text-white">利润总额</span>
|
|
|
+ </div>
|
|
|
+ <div className="flex items-center gap-2">
|
|
|
+ <div className="w-3 h-3 bg-purple-500 rounded-sm"></div>
|
|
|
+ <span className="text-lg text-white">净利润</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <span className="text-sm text-slate-400">*数据截止至2025年9月</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {/* 单位 */}
|
|
|
+ <div className="text-sm text-slate-400 mb-4">单位:亿元</div>
|
|
|
+
|
|
|
+ {/* 图表区域 */}
|
|
|
+ <div className="relative h-64">
|
|
|
+ {/* Y轴刻度 */}
|
|
|
+ <div className="absolute left-0 top-0 bottom-0 w-12 flex flex-col justify-between text-sm text-slate-400">
|
|
|
+ {[2, 1.5, 1, 0.75, 0.5, 0.25, 0, -1, -2].map((value) => (
|
|
|
+ <div key={value} className="text-right pr-2">
|
|
|
+ {value}
|
|
|
+ </div>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {/* 图表内容 */}
|
|
|
+ <div className="ml-12 h-full relative">
|
|
|
+ {/* 网格线 */}
|
|
|
+ <div className="absolute inset-0 flex flex-col justify-between">
|
|
|
+ {[...Array(9)].map((_, i) => (
|
|
|
+ <div key={i} className="border-t border-slate-600/30"></div>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {/* 数据条 */}
|
|
|
+ <div className="flex items-end justify-between h-full px-4">
|
|
|
+ {data.map((item, index) => (
|
|
|
+ <div key={item.year} className="flex flex-col items-center gap-2">
|
|
|
+ {/* 数据标签 */}
|
|
|
+ <div className="text-center">
|
|
|
+ <div className="text-sm text-white">{item.totalProfit}</div>
|
|
|
+ <div className="text-sm text-white">{item.netProfit}</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {/* 数据条 */}
|
|
|
+ <div className="flex gap-2 items-end">
|
|
|
+ {/* 利润总额柱状图 */}
|
|
|
+ <div className="flex flex-col items-center">
|
|
|
+ <div
|
|
|
+ className={`w-8 rounded-t-sm ${
|
|
|
+ item.totalProfit >= 0
|
|
|
+ ? 'bg-gradient-to-b from-cyan-500 to-cyan-700'
|
|
|
+ : 'bg-gradient-to-b from-red-500 to-red-700'
|
|
|
+ }`}
|
|
|
+ style={{
|
|
|
+ height: `${Math.abs(item.totalProfit) / Math.max(maxPositive, Math.abs(maxNegative)) * 40}%`
|
|
|
+ }}
|
|
|
+ ></div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {/* 净利润柱状图 */}
|
|
|
+ <div className="flex flex-col items-center">
|
|
|
+ <div
|
|
|
+ className={`w-8 rounded-t-sm ${
|
|
|
+ item.netProfit >= 0
|
|
|
+ ? 'bg-gradient-to-b from-purple-500 to-purple-700'
|
|
|
+ : 'bg-gradient-to-b from-red-500 to-red-700'
|
|
|
+ }`}
|
|
|
+ style={{
|
|
|
+ height: `${Math.abs(item.netProfit) / Math.max(maxPositive, Math.abs(maxNegative)) * 40}%`
|
|
|
+ }}
|
|
|
+ ></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {/* 年份标签 */}
|
|
|
+ <div className="text-sm text-slate-400 mt-2">{item.year}</div>
|
|
|
+ </div>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+}
|