You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
109 lines
3.6 KiB
109 lines
3.6 KiB
|
2 months ago
|
import {
|
||
|
|
XAxis,
|
||
|
|
YAxis,
|
||
|
|
CartesianGrid,
|
||
|
|
Tooltip,
|
||
|
|
ResponsiveContainer,
|
||
|
|
ReferenceLine,
|
||
|
|
Area,
|
||
|
|
AreaChart
|
||
|
|
} from 'recharts';
|
||
|
|
import type { SentimentTrend } from '@/types';
|
||
|
|
|
||
|
|
interface SentimentTrendProps {
|
||
|
|
data: SentimentTrend[];
|
||
|
|
}
|
||
|
|
|
||
|
|
export function SentimentTrendChart({ data }: SentimentTrendProps) {
|
||
|
|
|
||
|
|
const CustomTooltip = ({ active, payload, label }: any) => {
|
||
|
|
if (active && payload && payload.length) {
|
||
|
|
const value = payload[0].value;
|
||
|
|
let sentiment = '中性';
|
||
|
|
let color = '#f97316';
|
||
|
|
|
||
|
|
if (value <= 20) { sentiment = '极度恐惧'; color = '#dc2626'; }
|
||
|
|
else if (value <= 40) { sentiment = '恐惧'; color = '#ef4444'; }
|
||
|
|
else if (value <= 60) { sentiment = '中性'; color = '#f97316'; }
|
||
|
|
else if (value <= 80) { sentiment = '贪婪'; color = '#22c55e'; }
|
||
|
|
else { sentiment = '极度贪婪'; color = '#16a34a'; }
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="bg-[#141414] border border-white/10 rounded-lg p-3 shadow-xl">
|
||
|
|
<p className="text-white/60 text-sm">{label}</p>
|
||
|
|
<p className="text-white font-bold text-lg">{value}</p>
|
||
|
|
<p style={{ color }} className="text-sm">{sentiment}</p>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="w-full h-[300px]">
|
||
|
|
<ResponsiveContainer width="100%" height="100%">
|
||
|
|
<AreaChart data={data} margin={{ top: 10, right: 10, left: 0, bottom: 0 }}>
|
||
|
|
<defs>
|
||
|
|
<linearGradient id="sentimentGradient" x1="0" y1="0" x2="0" y2="1">
|
||
|
|
<stop offset="5%" stopColor="#a855f7" stopOpacity={0.3}/>
|
||
|
|
<stop offset="95%" stopColor="#a855f7" stopOpacity={0}/>
|
||
|
|
</linearGradient>
|
||
|
|
</defs>
|
||
|
|
|
||
|
|
<CartesianGrid strokeDasharray="3 3" stroke="rgba(255,255,255,0.05)" />
|
||
|
|
|
||
|
|
<XAxis
|
||
|
|
dataKey="date"
|
||
|
|
stroke="rgba(255,255,255,0.3)"
|
||
|
|
tick={{ fill: 'rgba(255,255,255,0.5)', fontSize: 11 }}
|
||
|
|
tickLine={false}
|
||
|
|
/>
|
||
|
|
|
||
|
|
<YAxis
|
||
|
|
domain={[0, 100]}
|
||
|
|
stroke="rgba(255,255,255,0.3)"
|
||
|
|
tick={{ fill: 'rgba(255,255,255,0.5)', fontSize: 11 }}
|
||
|
|
tickLine={false}
|
||
|
|
tickFormatter={(value) => `${value}`}
|
||
|
|
/>
|
||
|
|
|
||
|
|
<Tooltip content={<CustomTooltip />} />
|
||
|
|
|
||
|
|
{/* 参考线 */}
|
||
|
|
<ReferenceLine y={20} stroke="#dc2626" strokeDasharray="3 3" opacity={0.5} />
|
||
|
|
<ReferenceLine y={40} stroke="#ef4444" strokeDasharray="3 3" opacity={0.5} />
|
||
|
|
<ReferenceLine y={60} stroke="#22c55e" strokeDasharray="3 3" opacity={0.5} />
|
||
|
|
<ReferenceLine y={80} stroke="#16a34a" strokeDasharray="3 3" opacity={0.5} />
|
||
|
|
|
||
|
|
<Area
|
||
|
|
type="monotone"
|
||
|
|
dataKey="value"
|
||
|
|
stroke="#a855f7"
|
||
|
|
strokeWidth={2}
|
||
|
|
fill="url(#sentimentGradient)"
|
||
|
|
animationDuration={1000}
|
||
|
|
/>
|
||
|
|
|
||
|
|
|
||
|
|
</AreaChart>
|
||
|
|
</ResponsiveContainer>
|
||
|
|
|
||
|
|
{/* 图例 */}
|
||
|
|
<div className="flex justify-center gap-6 mt-4 text-xs">
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<div className="w-3 h-3 rounded-full bg-red-600"></div>
|
||
|
|
<span className="text-white/50">极度恐惧</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<div className="w-3 h-3 rounded-full bg-orange-500"></div>
|
||
|
|
<span className="text-white/50">中性</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<div className="w-3 h-3 rounded-full bg-green-600"></div>
|
||
|
|
<span className="text-white/50">极度贪婪</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|