82 lines
2.1 KiB
TypeScript
82 lines
2.1 KiB
TypeScript
import { ArrowUpOutlined, ArrowDownOutlined } from '@ant-design/icons'
|
|
import './StatCard.css'
|
|
import { ReactNode } from 'react'
|
|
|
|
export interface StatCardProps {
|
|
title: string
|
|
value: number | string
|
|
icon?: ReactNode
|
|
color?: string
|
|
trend?: { value: number; direction: 'up' | 'down' }
|
|
suffix?: string
|
|
layout?: 'column' | 'row'
|
|
gridColumn?: string
|
|
className?: string
|
|
onClick?: () => void
|
|
style?: React.CSSProperties
|
|
}
|
|
|
|
/**
|
|
* 统计卡片组件
|
|
*/
|
|
function StatCard({
|
|
title,
|
|
value,
|
|
icon,
|
|
color = 'blue',
|
|
trend,
|
|
suffix = '',
|
|
layout = 'column',
|
|
gridColumn,
|
|
className = '',
|
|
onClick,
|
|
style: customStyle = {},
|
|
}: StatCardProps) {
|
|
const colorMap: Record<string, string> = {
|
|
blue: '#1677ff',
|
|
green: '#52c41a',
|
|
orange: '#faad14',
|
|
red: '#ff4d4f',
|
|
purple: '#722ed1',
|
|
gray: '#8c8c8c',
|
|
}
|
|
|
|
const themeColor = colorMap[color] || color
|
|
|
|
const style = {
|
|
...(gridColumn ? { gridColumn } : {}),
|
|
...customStyle,
|
|
}
|
|
|
|
return (
|
|
<div className={`stat-card stat-card-${layout} ${className}`} style={style} onClick={onClick}>
|
|
<div className="stat-card-header">
|
|
<span className="stat-card-title">{title}</span>
|
|
{icon && (
|
|
<span className="stat-card-icon" style={{ color: themeColor }} aria-hidden="true">
|
|
{icon}
|
|
</span>
|
|
)}
|
|
</div>
|
|
|
|
<div className="stat-card-body">
|
|
<div className="stat-card-value tabular-nums" style={{ color: themeColor }}>
|
|
{value}
|
|
{suffix && <span className="stat-card-suffix">{suffix}</span>}
|
|
</div>
|
|
|
|
{trend && (
|
|
<div
|
|
className={`stat-card-trend ${trend.direction === 'up' ? 'trend-up' : 'trend-down'} tabular-nums`}
|
|
aria-label={`${trend.direction === 'up' ? 'Increase' : 'Decrease'} of ${trend.value}%`}
|
|
>
|
|
{trend.direction === 'up' ? <ArrowUpOutlined aria-hidden="true" /> : <ArrowDownOutlined aria-hidden="true" />}
|
|
<span>{Math.abs(trend.value)}%</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default StatCard |