geo/frontend/components/charts/CompetitorRadarChart.tsx

102 lines
2.5 KiB
TypeScript

"use client";
import {
RadarChart,
Radar,
PolarGrid,
PolarAngleAxis,
PolarRadiusAxis,
ResponsiveContainer,
Legend,
Tooltip,
} from "recharts";
interface RadarDataItem {
platform?: string;
dimension?: string;
label: string;
[brand: string]: string | number | undefined;
}
interface CompetitorRadarChartProps {
data: RadarDataItem[];
brandName: string;
competitors: { name: string; color: string }[];
}
const DEFAULT_COLORS = [
"hsl(221.2 83.2% 53.3%)",
"hsl(346.8 77.2% 49.8%)",
"hsl(24.6 95% 53.1%)",
"hsl(142.1 76.2% 36.3%)",
"hsl(262.1 83.3% 57.8%)",
];
export function CompetitorRadarChart({
data,
brandName,
competitors,
}: CompetitorRadarChartProps) {
return (
<ResponsiveContainer width="100%" height={400}>
<RadarChart
data={data}
margin={{ top: 20, right: 20, bottom: 20, left: 20 }}
>
<PolarGrid stroke="hsl(var(--border))" />
<PolarAngleAxis
dataKey="label"
tick={{ fontSize: 12, fill: "hsl(var(--foreground))" }}
/>
<PolarRadiusAxis
angle={30}
domain={[0, 100]}
tick={{ fontSize: 10, fill: "hsl(var(--muted-foreground))" }}
/>
<Tooltip
contentStyle={{
backgroundColor: "hsl(var(--card))",
border: "1px solid hsl(var(--border))",
borderRadius: "var(--radius)",
}}
formatter={(value: number) => [`评分: ${value}`, ""]}
/>
<Legend
wrapperStyle={{ fontSize: 12 }}
formatter={(value) => (
<span style={{ color: "hsl(var(--foreground))" }}>{value}</span>
)}
/>
{/* 己方品牌 - 使用主色调 */}
<Radar
name={brandName}
dataKey={brandName}
stroke="hsl(221.2 83.2% 53.3%)"
fill="hsl(221.2 83.2% 53.3%)"
fillOpacity={0.3}
strokeWidth={2}
/>
{/* 竞品 */}
{competitors.map((competitor, index) => (
<Radar
key={competitor.name}
name={competitor.name}
dataKey={competitor.name}
stroke={
competitor.color ||
DEFAULT_COLORS[(index + 1) % DEFAULT_COLORS.length]
}
fill={
competitor.color ||
DEFAULT_COLORS[(index + 1) % DEFAULT_COLORS.length]
}
fillOpacity={0.15}
strokeWidth={2}
strokeDasharray="4 4"
/>
))}
</RadarChart>
</ResponsiveContainer>
);
}