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

77 lines
2.0 KiB
TypeScript

"use client"
import type { ReactNode } from "react"
import { Card, CardContent, CardHeader, CardTitle } from "@/app/components/ui/card"
import { TrendingUp, TrendingDown, Minus } from "lucide-react"
interface StatCardProps {
title: string
value: string | number
icon?: ReactNode
change?: {
value: string | number
type: "increase" | "decrease" | "neutral"
label?: string
}
description?: string
}
export function StatCard({ title, value, icon, change, description }: StatCardProps) {
const getChangeIcon = () => {
switch (change?.type) {
case "increase":
return <TrendingUp className="h-3 w-3" />
case "decrease":
return <TrendingDown className="h-3 w-3" />
default:
return <Minus className="h-3 w-3" />
}
}
const getChangeColor = () => {
switch (change?.type) {
case "increase":
return "text-green-600"
case "decrease":
return "text-red-600"
default:
return "text-muted-foreground"
}
}
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">{title}</CardTitle>
{icon && <div className="text-muted-foreground">{icon}</div>}
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{value}</div>
{change && (
<div className={`flex items-center text-xs ${getChangeColor()}`}>
{getChangeIcon()}
<span className="ml-1">
{change.value} {change.label}
</span>
</div>
)}
{description && <p className="text-xs text-muted-foreground mt-1">{description}</p>}
</CardContent>
</Card>
)
}
interface StatCardGroupProps {
cards: StatCardProps[]
}
export function StatCardGroup({ cards }: StatCardGroupProps) {
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
{cards.map((card, index) => (
<StatCard key={index} {...card} />
))}
</div>
)
}