"use client" import { Bar, BarChart, CartesianGrid, XAxis, YAxis, Cell } from "recharts" import { useTranslations } from "next-intl" import { ChartContainer, ChartTooltip, ChartTooltipContent, type ChartConfig, } from "@/shared/components/ui/chart" import { Card, CardContent, CardHeader, CardTitle } from "@/shared/components/ui/card" import { cn } from "@/shared/lib/utils" import type { SubjectErrorDistribution } from "@/modules/error-book/types" interface SubjectDistributionChartProps { data: SubjectErrorDistribution[] className?: string } interface SubjectDistChartPayload { name: string errorCount: number masteredCount: number masteryRate: number } function isSubjectDistChartPayload(v: unknown): v is SubjectDistChartPayload { if (typeof v !== "object" || v === null) return false // 从 unknown 转换:类型守卫内需要属性访问来校验字段类型 const obj = v as Record return ( typeof obj.name === "string" && typeof obj.errorCount === "number" && typeof obj.masteredCount === "number" && typeof obj.masteryRate === "number" ) } const SUBJECT_COLORS = [ "var(--color-chart-1)", "var(--color-chart-2)", "var(--color-chart-3)", "var(--color-chart-4)", "var(--color-chart-5)", ] /** * 学科错题分布柱状图(管理员视图) * 横轴:学科名称,纵轴:错题数 * tooltip 显示已掌握/掌握率 */ export function SubjectDistributionChart({ data, className, }: SubjectDistributionChartProps) { const t = useTranslations("error-book") if (data.length === 0) return null const chartData = data.map((d) => ({ name: d.subjectName, errorCount: d.errorCount, masteredCount: d.masteredCount, masteryRate: Number((d.masteryRate * 100).toFixed(0)), })) const chartConfig: ChartConfig = { errorCount: { label: t("subjectDistChart.errorCount"), color: "var(--color-chart-1)", }, } return ( {t("subjectDistChart.title")} value.length > 6 ? `${value.slice(0, 6)}...` : value } /> { if (!isSubjectDistChartPayload(payload)) return null return (
{payload.name}
{t("subjectDistChart.errorCount")}: {payload.errorCount}
{t("subjectDistChart.masteredLabel")}: {payload.masteredCount}
{t("subjectDistChart.masteryRateLabel")}: {payload.masteryRate}%
) }} /> } /> {chartData.map((_, idx) => ( ))}
) }