Files
cunkebao_v3/Cunkebao/app/components/common/Charts.tsx
笔记本里的永平 5ff15472f5 feat: 本次提交更新内容如下
场景获客列表搞定
2025-07-07 17:08:27 +08:00

243 lines
7.3 KiB
TypeScript

"use client"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/app/components/ui/card"
import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@/app/components/ui/chart"
import {
LineChart,
Line,
AreaChart,
Area,
BarChart,
Bar,
PieChart,
Pie,
Cell,
XAxis,
YAxis,
CartesianGrid,
ResponsiveContainer,
Legend,
} from "recharts"
export interface ChartData {
[key: string]: any
}
export interface ChartConfig {
[key: string]: {
label: string
color: string
}
}
export interface BaseChartProps {
title?: string
description?: string
data: ChartData[]
config: ChartConfig
className?: string
height?: number
}
// 折线图组件
export function LineChartComponent({ title, description, data, config, className, height = 300 }: BaseChartProps) {
return (
<Card className={className}>
{(title || description) && (
<CardHeader>
{title && <CardTitle>{title}</CardTitle>}
{description && <CardDescription>{description}</CardDescription>}
</CardHeader>
)}
<CardContent>
<ChartContainer config={config} className={`h-[${height}px]`}>
<ResponsiveContainer width="100%" height="100%">
<LineChart data={data} margin={{ top: 5, right: 30, left: 20, bottom: 5 }}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="name" />
<YAxis />
<ChartTooltip content={<ChartTooltipContent />} />
<Legend />
{Object.entries(config).map(([key, { color }]) => (
<Line
key={key}
type="monotone"
dataKey={key}
stroke={color}
strokeWidth={2}
dot={{ fill: color, strokeWidth: 2, r: 4 }}
activeDot={{ r: 6 }}
/>
))}
</LineChart>
</ResponsiveContainer>
</ChartContainer>
</CardContent>
</Card>
)
}
// 面积图组件
export function AreaChartComponent({ title, description, data, config, className, height = 300 }: BaseChartProps) {
return (
<Card className={className}>
{(title || description) && (
<CardHeader>
{title && <CardTitle>{title}</CardTitle>}
{description && <CardDescription>{description}</CardDescription>}
</CardHeader>
)}
<CardContent>
<ChartContainer config={config} className={`h-[${height}px]`}>
<ResponsiveContainer width="100%" height="100%">
<AreaChart data={data} margin={{ top: 5, right: 30, left: 20, bottom: 5 }}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="name" />
<YAxis />
<ChartTooltip content={<ChartTooltipContent />} />
<Legend />
{Object.entries(config).map(([key, { color }]) => (
<Area
key={key}
type="monotone"
dataKey={key}
stackId="1"
stroke={color}
fill={color}
fillOpacity={0.6}
/>
))}
</AreaChart>
</ResponsiveContainer>
</ChartContainer>
</CardContent>
</Card>
)
}
// 柱状图组件
export function BarChartComponent({ title, description, data, config, className, height = 300 }: BaseChartProps) {
return (
<Card className={className}>
{(title || description) && (
<CardHeader>
{title && <CardTitle>{title}</CardTitle>}
{description && <CardDescription>{description}</CardDescription>}
</CardHeader>
)}
<CardContent>
<ChartContainer config={config} className={`h-[${height}px]`}>
<ResponsiveContainer width="100%" height="100%">
<BarChart data={data} margin={{ top: 5, right: 30, left: 20, bottom: 5 }}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="name" />
<YAxis />
<ChartTooltip content={<ChartTooltipContent />} />
<Legend />
{Object.entries(config).map(([key, { color }]) => (
<Bar key={key} dataKey={key} fill={color} radius={[4, 4, 0, 0]} />
))}
</BarChart>
</ResponsiveContainer>
</ChartContainer>
</CardContent>
</Card>
)
}
// 饼图组件
export function PieChartComponent({
title,
description,
data,
config,
className,
height = 300,
}: BaseChartProps & { dataKey?: string; nameKey?: string }) {
const COLORS = Object.values(config).map((item) => item.color)
return (
<Card className={className}>
{(title || description) && (
<CardHeader>
{title && <CardTitle>{title}</CardTitle>}
{description && <CardDescription>{description}</CardDescription>}
</CardHeader>
)}
<CardContent>
<ChartContainer config={config} className={`h-[${height}px]`}>
<ResponsiveContainer width="100%" height="100%">
<PieChart>
<Pie
data={data}
cx="50%"
cy="50%"
labelLine={false}
label={({ name, percent }) => `${name} ${(percent * 100).toFixed(0)}%`}
outerRadius={80}
fill="#8884d8"
dataKey="value"
>
{data.map((entry, index) => (
<Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
))}
</Pie>
<ChartTooltip content={<ChartTooltipContent />} />
<Legend />
</PieChart>
</ResponsiveContainer>
</ChartContainer>
</CardContent>
</Card>
)
}
// 组合图表组件
export function ComboChartComponent({
title,
description,
data,
config,
className,
height = 300,
lineKeys = [],
barKeys = [],
}: BaseChartProps & { lineKeys?: string[]; barKeys?: string[] }) {
return (
<Card className={className}>
{(title || description) && (
<CardHeader>
{title && <CardTitle>{title}</CardTitle>}
{description && <CardDescription>{description}</CardDescription>}
</CardHeader>
)}
<CardContent>
<ChartContainer config={config} className={`h-[${height}px]`}>
<ResponsiveContainer width="100%" height="100%">
<LineChart data={data} margin={{ top: 5, right: 30, left: 20, bottom: 5 }}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="name" />
<YAxis />
<ChartTooltip content={<ChartTooltipContent />} />
<Legend />
{barKeys.map((key) => (
<Bar key={key} dataKey={key} fill={config[key]?.color} radius={[4, 4, 0, 0]} />
))}
{lineKeys.map((key) => (
<Line
key={key}
type="monotone"
dataKey={key}
stroke={config[key]?.color}
strokeWidth={2}
dot={{ fill: config[key]?.color, strokeWidth: 2, r: 4 }}
/>
))}
</LineChart>
</ResponsiveContainer>
</ChartContainer>
</CardContent>
</Card>
)
}