---
nav:
  title: 组件
  order: 1
group:
  title: Display
  order: 1
title: PisellMetricCard
order: 1
category: atom
---

# PisellMetricCard 指标卡片组件

## 组件介绍

PisellMetricCard 是用于展示单一核心指标的专业卡片组件，适用于数据看板、项目概览、业务总览等场景。它支持展示主数值、环比变化、趋势箭头、标签等丰富的信息，并提供高度可配置的样式系统。

**核心特性**：

- ✅ 丰富的数据展示能力（标题、副标题、数值、环比、标签）
- ✅ 自动趋势计算（根据环比自动显示上升/下降箭头）
- ✅ 强大的格式化能力（千分位、货币符号、小数精度）
- ✅ 高度可配置的样式系统
- ✅ 基于 PisellCard 封装，继承卡片容器能力

---

## 基础用法

### 简单示例

```tsx
import { PisellMetricCard } from '@pisell/materials';

export default () => {
  return (
    <PisellMetricCard
      title="Total Sales"
      value={1580}
    />
  );
};
```

### 带货币符号

```tsx
import { PisellMetricCard } from '@pisell/materials';

export default () => {
  return (
    <PisellMetricCard
      title="Revenue"
      value={1580}
      format={{
        showCurrencySymbol: true,
        currencySymbol: '$'
      }}
    />
  );
};
```

---

## 环比与趋势

### 正向趋势

```tsx
import { PisellMetricCard } from '@pisell/materials';

export default () => {
  return (
    <PisellMetricCard
      title="Total Orders"
      value={50}
      comparison={{ value: 12 }}
    />
  );
};
```

### 负向趋势

```tsx
import { PisellMetricCard } from '@pisell/materials';

export default () => {
  return (
    <PisellMetricCard
      title="Total Items"
      value={3249}
      comparison={{ value: -230 }}
    />
  );
};
```

### 带货币的环比

```tsx
import { PisellMetricCard } from '@pisell/materials';

export default () => {
  return (
    <PisellMetricCard
      title="Total Sales"
      value={1580}
      format={{
        showCurrencySymbol: true,
        currencySymbol: '$'
      }}
      comparison={{ value: 120 }}
    />
  );
};
```

### 自定义环比前缀

```tsx
import { PisellMetricCard } from '@pisell/materials';

export default () => {
  return (
    <PisellMetricCard
      title="Monthly Revenue"
      value={125000}
      format={{
        showCurrencySymbol: true,
        currencySymbol: '$'
      }}
      comparison={{
        value: 15000,
        text: 'vs. last month'
      }}
    />
  );
};
```

### 隐藏趋势箭头

```tsx
import { PisellMetricCard } from '@pisell/materials';

export default () => {
  return (
    <PisellMetricCard
      title="Completion Rate"
      value={85.5}
      format={{
        formatter: (value) => `${value}%`
      }}
      comparison={{
        value: 5.3,
        showTrendIcon: false
      }}
    />
  );
};
```

---

## 数值格式化

### 千分位分隔符

```tsx
import { PisellMetricCard } from '@pisell/materials';

export default () => {
  return (
    <PisellMetricCard
      title="Total Revenue"
      value={1234567}
      format={{ useGrouping: true }}
    />
  );
};
```

### 小数精度

```tsx
import { PisellMetricCard } from '@pisell/materials';

export default () => {
  return (
    <div style={{ display: 'flex', gap: 16 }}>
      <PisellMetricCard
        title="Conversion Rate"
        value={18.567}
        format={{ precision: 2 }}
      />
      <PisellMetricCard
        title="Growth Rate"
        value={5.123}
        format={{ 
          precision: 1,
          formatter: (value) => `${value}%`
        }}
      />
    </div>
  );
};
```

### 货币格式化

```tsx
import { PisellMetricCard } from '@pisell/materials';

export default () => {
  return (
    <div style={{ display: 'flex', gap: 16 }}>
      {/* 美元 */}
      <PisellMetricCard
        title="Revenue (USD)"
        value={1234567.89}
        format={{
          showCurrencySymbol: true,
          currencySymbol: '$',
          useGrouping: true,
          precision: 2
        }}
      />
      
      {/* 人民币 */}
      <PisellMetricCard
        title="Revenue (CNY)"
        value={8888888.88}
        format={{
          showCurrencySymbol: true,
          currencySymbol: '¥',
          useGrouping: true,
          precision: 2
        }}
      />
    </div>
  );
};
```

### 自定义格式化

```tsx
import { PisellMetricCard } from '@pisell/materials';

export default () => {
  return (
    <div style={{ display: 'flex', gap: 16 }}>
      {/* 百分比 */}
      <PisellMetricCard
        title="Success Rate"
        value={95.5}
        format={{
          formatter: (value) => `${value}%`
        }}
      />
      
      {/* 单位 */}
      <PisellMetricCard
        title="Storage Used"
        value={256}
        format={{
          formatter: (value) => `${value} GB`
        }}
      />
    </div>
  );
};
```

---

## 扩展信息

### 副标题

```tsx
import { PisellMetricCard } from '@pisell/materials';

export default () => {
  return (
    <PisellMetricCard
      title="Active Users"
      subtitle="Last 30 days"
      value={1128}
      showSubtitle
    />
  );
};
```

### 标签

```tsx
import { PisellMetricCard, Tag } from '@pisell/materials';

export default () => {
  return (
    <div style={{ display: 'flex', gap: 16 }}>
      <PisellMetricCard
        title="Revenue"
        value={125000}
        format={{
          showCurrencySymbol: true,
          currencySymbol: '$'
        }}
        tag={<Tag color="green">+15%</Tag>}
        showTag
      />
      
      <PisellMetricCard
        title="Orders"
        value={850}
        tag={<Tag color="orange">Hot</Tag>}
        showTag
      />
    </div>
  );
};
```

### 提示信息

```tsx
import { PisellMetricCard } from '@pisell/materials';

export default () => {
  return (
    <PisellMetricCard
      title="Conversion Rate"
      value={18.5}
      format={{
        formatter: (value) => `${value}%`
      }}
      tooltip="The percentage of visitors who completed a purchase"
      showTooltip
    />
  );
};
```

### 完整配置

```tsx
import { PisellMetricCard, Tag } from '@pisell/materials';

export default () => {
  return (
    <PisellMetricCard
      title="Monthly Revenue"
      subtitle="Last 30 days"
      value={125000}
      tooltip="Total revenue from all sales channels"
      tag={<Tag color="green">High</Tag>}
      showSubtitle
      showTag
      showTooltip
      format={{
        showCurrencySymbol: true,
        currencySymbol: '$',
        useGrouping: true,
        precision: 2
      }}
      comparison={{
        value: 15000,
        text: 'v.s. pre'
      }}
    />
  );
};
```

---

## 样式配置

### 卡片容器样式

```tsx
import { PisellMetricCard } from '@pisell/materials';

export default () => {
  return (
    <div style={{ display: 'flex', gap: 16 }}>
      {/* 自定义圆角和内边距 */}
      <PisellMetricCard
        title="Sales"
        value={1580}
        styleConfig={{
          card: { 
            borderRadius: 8, 
            padding: 24 
          }
        }}
      />
      
      {/* 自定义背景色和宽度 */}
      <PisellMetricCard
        title="Revenue"
        value={12345}
        format={{ showCurrencySymbol: true, currencySymbol: '$' }}
        styleConfig={{
          card: { 
            background: '#f5f5f5',
            width: 280
          }
        }}
      />
    </div>
  );
};
```

### 标题和数值样式

```tsx
import { PisellMetricCard } from '@pisell/materials';

export default () => {
  return (
    <PisellMetricCard
      title="Custom Styled Card"
      value={1580}
      styleConfig={{
        title: { 
          size: 16, 
          weight: 600, 
          color: '#1890ff' 
        },
        value: { 
          size: 36, 
          weight: 700, 
          color: '#52c41a' 
        }
      }}
    />
  );
};
```

### 环比样式

```tsx
import { PisellMetricCard } from '@pisell/materials';

export default () => {
  return (
    <PisellMetricCard
      title="Custom Comparison Style"
      value={1580}
      comparison={{
        value: 120,
        size: 16,
        positiveColor: '#00ff00',
        negativeColor: '#ff0000'
      }}
    />
  );
};
```

---

## 特殊场景

### 加载状态

```tsx
import { PisellMetricCard } from '@pisell/materials';
import { useState, useEffect } from 'react';

export default () => {
  const [loading, setLoading] = useState(true);
  const [value, setValue] = useState<number | null>(null);
  
  useEffect(() => {
    setTimeout(() => {
      setValue(1580);
      setLoading(false);
    }, 2000);
  }, []);
  
  return (
    <PisellMetricCard
      title="Total Sales"
      value={value}
      loading={loading}
    />
  );
};
```

### 空值处理

```tsx
import { PisellMetricCard } from '@pisell/materials';

export default () => {
  return (
    <PisellMetricCard
      title="No Data"
      value={null}
    />
  );
};
```

### 点击交互

```tsx
import { PisellMetricCard } from '@pisell/materials';
import { message } from 'antd';

export default () => {
  const handleClick = () => {
    message.info('Card clicked!');
  };
  
  return (
    <PisellMetricCard
      title="Clickable Card"
      value={1580}
      onClick={handleClick}
    />
  );
};
```

### 多卡片布局

```tsx
import { PisellMetricCard } from '@pisell/materials';

export default () => {
  return (
    <div style={{ 
      display: 'grid', 
      gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', 
      gap: 16 
    }}>
      <PisellMetricCard
        title="Total Orders"
        value={50}
        comparison={{ value: 12 }}
      />
      <PisellMetricCard
        title="Total Sales"
        value={1580}
        format={{ showCurrencySymbol: true, currencySymbol: '$' }}
        comparison={{ value: 120 }}
      />
      <PisellMetricCard
        title="Total Discount"
        value={230}
        format={{ showCurrencySymbol: true, currencySymbol: '$' }}
        comparison={{ value: 80 }}
      />
      <PisellMetricCard
        title="Total Items"
        value={3249}
        comparison={{ value: -230 }}
      />
    </div>
  );
};
```

---

## API

### PisellMetricCardProps

#### 核心 Props（推荐使用）

| 参数 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| **基础数据** |
| title | 标题文本 | `string \| ReactNode` | - |
| value | 主数值 | `number \| string \| null` | - |
| subtitle | 副标题文本 | `string \| ReactNode` | - |
| tag | 标签内容 | `ReactNode` | - |
| tooltip | 提示信息内容 | `string \| ReactNode` | - |
| **配置对象** |
| format | 数值格式化配置 | `ValueFormatConfig` | - |
| comparison | 环比配置 | `ComparisonConfig` | - |
| styleConfig | 样式配置 | `MetricCardStyleConfig` | - |
| **功能开关** |
| showSubtitle | 是否显示副标题 | `boolean` | `false` |
| showTag | 是否显示标签 | `boolean` | `false` |
| showTooltip | 是否显示提示信息 | `boolean` | `false` |
| loading | 是否显示加载状态 | `boolean` | `false` |
| hoverable | 鼠标悬停是否有交互效果 | `boolean` | `true` |
| **通用** |
| className | 自定义类名 | `string` | - |
| style | 自定义样式 | `CSSProperties` | - |
| onClick | 点击卡片回调 | `() => void` | - |

#### ValueFormatConfig（数值格式化配置）

| 参数 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| precision | 小数精度 | `number` | `0` |
| useGrouping | 是否使用千分位 | `boolean` | `false` |
| showCurrencySymbol | 是否显示货币符号 | `boolean` | `false` |
| currencySymbol | 货币符号 | `string` | `''` |
| formatter | 自定义格式化函数 | `(value: number \| null) => string` | - |
| hideDecimalForWholeNumbers | 整数时隐藏小数 | `boolean` | `true` |

#### ComparisonConfig（环比配置）

| 参数 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| value | 环比数值 | `number \| string \| null` | - |
| text | 环比前缀文本 | `string` | `'v.s. pre'` |
| showTrendIcon | 是否显示趋势箭头 | `boolean` | `true` |
| positiveColor | 正向趋势颜色 | `string` | `'#52c41a'` |
| negativeColor | 负向趋势颜色 | `string` | `'#ff4d4f'` |
| size | 环比字号 | `number \| string` | `14` |

#### MetricCardStyleConfig（样式配置）

| 参数 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| card | 卡片容器样式 | `CardStyle` | - |
| title | 标题样式 | `TextStyle` | - |
| value | 数值样式 | `TextStyle` | - |

**CardStyle**：
- `bordered?: boolean` - 是否显示边框，默认 true
- `borderRadius?: number` - 圆角大小，默认 12
- `padding?: number` - 内边距，默认 16
- `shadow?: boolean | string` - 阴影效果，默认 true
- `background?: string` - 背景色，默认 '#ffffff'
- `width?: string | number` - 宽度，默认 'auto'

**TextStyle**：
- `size?: number | string` - 字号
- `weight?: number | string` - 字重
- `color?: string` - 颜色

---

## 设计理念

### 扁平 + 对象组合

采用**扁平 + 对象组合**的设计模式，兼顾简洁性和可扩展性：

**核心数据扁平化**（常用且简单）：
```
title, value, subtitle, tag, tooltip
```

**相关配置对象化**（聚合相关配置）：
```
format: { precision, useGrouping, currencySymbol, ... }
comparison: { value, text, showTrendIcon, ... }
styleConfig: { card, title, value }
```

**简单开关扁平化**（boolean 类型）：
```
showSubtitle, showTag, showTooltip, loading, hoverable
```

### 设计优势

对比传统的扁平设计（40+ 个 Props）：
- ✅ **高内聚**：相关配置聚合在一起（如格式化相关的 6 个配置聚合为 format 对象）
- ✅ **低耦合**：核心数据与配置分离，职责清晰
- ✅ **易维护**：配置结构清晰，扩展不会导致 Props 膨胀
- ✅ **易使用**：简单场景更简洁，复杂场景更清晰

### 使用对比

**简单场景（基础用法）**：
```
<PisellMetricCard title="Sales" value={1580} />
```

**复杂场景（配置对象让结构更清晰）**：
```
<PisellMetricCard
  title="Revenue"
  value={125000}
  format={{
    precision: 2,
    useGrouping: true,
    showCurrencySymbol: true,
    currencySymbol: '$'
  }}
  comparison={{
    value: 15000,
    text: 'v.s. pre'
  }}
  styleConfig={{
    card: { borderRadius: 12, padding: 16 },
    value: { size: 36, color: '#52c41a' }
  }}
/>
```

---

## 最佳实践

### 1. 合理使用环比

环比信息适合展示短期变化趋势，建议：
- 使用清晰的环比前缀（如 "v.s. last month"）
- 对正负趋势使用不同颜色
- 环比数值与主数值保持一致的格式化规则

### 2. 数值格式化

根据场景选择合适的格式化方式：
- 金额：使用货币符号 + 千分位 + 2位小数
- 百分比：使用自定义 formatter 添加 % 符号
- 整数：使用千分位分隔符提高可读性

### 3. 样式配置

- 保持同一页面中多个卡片的样式一致
- 使用主题色系统，避免硬编码颜色
- 根据内容长度调整卡片宽度

### 4. 信息密度

根据使用场景控制信息密度：
- 看板场景：仅展示标题和数值
- 详情页面：展示完整信息（副标题、环比、标签等）
- 避免信息过载，影响用户理解

---

## 常见问题

### 1. 为什么环比不显示？

确保 `comparison.value` 有值且不为 0：
```
<PisellMetricCard
  comparison={{ value: 120 }}  // ✅ 正确
/>
```

### 2. 如何自定义环比格式？

环比会自动使用与主数值相同的格式化规则，包括：
- `precision`
- `showCurrencySymbol`
- `currencySymbol`

示例：
```
<PisellMetricCard
  value={1580}
  format={{ precision: 2, currencySymbol: '$' }}
  comparison={{ value: 120 }}
/>
// 主数值：$1,580.00
// 环比：v.s. pre +$120.00
```

### 3. 趋势箭头颜色如何配置？

通过 `comparison` 对象配置颜色：
```
<PisellMetricCard
  comparison={{
    value: 120,
    positiveColor: '#00ff00',
    negativeColor: '#ff0000'
  }}
/>
```

### 4. 如何让卡片填满容器？

通过 `styleConfig` 设置宽度：
```
<PisellMetricCard
  styleConfig={{
    card: { width: '100%' }
  }}
/>
```

---

## 更新日志

### v1.0.0 (2026-01-28)

- ✨ 首次发布
- ✅ 支持标题、数值、环比、趋势箭头等功能
- ✅ 提供丰富的格式化选项
- ✅ 高度可配置的样式系统
- ✅ 基于 PisellCard 封装
