---
title: 设计文档
order: 2
category: pro
---

﻿# PisellPercent 组件设计文档

## 组件概述

PisellPercent 是基于 PisellNumber 派生的百分比组件，专门用于处理比例、完成度、增长率等百分比数据场景。它继承了 PisellNumber
的所有基础能力，并添加了百分号显示、进度条可视化等百分比特有的语义化扩展。

**设计原则**：

- 基于 PisellNumber 组件进行扩展
- 使用 Ant Design InputNumber 作为底层控件
- 参考 PisellSingleLineText 架构，采用三态视图
- 使用 @pisell/utils 中的公共状态管理逻辑
- 支持文本、进度条、环形进度多种展示方式

**Figma 设计链接**：
https://www.figma.com/design/pM8Ho6d7kCMv9vIBvFHUlj/Pisell-2.0-Component-Library?node-id=3803-7115&m=dev

---

## 核心功能

### 1. 继承 PisellNumber 的基础能力

- 三种交互状态（只读/编辑/禁用）
- 数值校验（范围、精度）
- 受控和非受控模式
- 筛选与排序能力

### 2. 百分比特有功能

**百分号显示**：

- 自动在数值后添加 `%` 符号
- 可配置是否显示百分号

**范围配置**：

- 支持 [0, 100] 范围（常用）
- 支持 [0, 1] 范围（小数表示）
- 自动进行范围转换

**多种展示变体**：

- `text`：纯文本展示（如：85.5%）
- `progress`：进度条展示（Ant Design Progress）
- `circle`：环形进度展示

**范围转换示例**：

```
range: [0, 100]
输入值: 85.5 → 显示: 85.5%

range: [0, 1]
输入值: 0.855 → 转换: 85.5 → 显示: 85.5%
```

---

## 接口定义

### Props 属性

继承 PisellNumber 的所有属性，并扩展以下百分比特有属性：

| 属性名                  | 类型                                 | 默认值        | 说明                           |
|----------------------|------------------------------------|------------|------------------------------|
| **继承自 PisellNumber** | -                                  | -          | -                            |
| `mode`               | `'read' \| 'edit'`                 | `'edit'`   | 显示模式                         |
| `disabled`           | `boolean`                          | `false`    | 是否禁用                         |
| `value`              | `number \| null`                   | -          | 当前值（受控）                      |
| `defaultValue`       | `number \| null`                   | -          | 默认值（非受控）                     |
| `onChange`           | `(value: number \| null) => void`  | -          | 值变更回调                        |
| `min`                | `number`                           | `0`        | 最小值                          |
| `max`                | `number`                           | `100`      | 最大值                          |
| `precision`          | `number`                           | `1`        | 小数精度                         |
| **百分比特有属性**          | -                                  | -          | -                            |
| `showPercentSymbol`  | `boolean`                          | `true`     | 是否显示百分号 %                    |
| `range`              | `[number, number]`                 | `[0, 100]` | 百分比范围                        |
| `variant`            | `'text' \| 'progress' \| 'circle'` | `'text'`   | 展示变体                         |
| `progressProps`      | `ProgressProps`                    | -          | 进度条额外配置（variant='progress'时） |
| `circleProps`        | `ProgressProps`                    | -          | 环形进度额外配置（variant='circle'时）  |
| `showSlider`         | `boolean`                          | `false`    | 编辑态是否显示滑块（配合输入框）             |
| `sliderProps`        | `SliderProps`                      | -          | 滑块额外配置                       |

---

## 组件架构

### 文件结构

```
pisellPercent/
├── index.tsx                        # 组件导出
├── PisellPercent.tsx                # 组件主入口
├── PisellPercent.less               # 组件样式
├── PisellPercent.test.tsx           # 单元测试
├── PisellPercent.stories.tsx        # Storybook 示例
├── types.ts                         # TypeScript 类型定义
├── components/                      # 子组件
│   ├── ReadOnlyView.tsx            # 只读态视图
│   ├── EditView.tsx                # 编辑态视图
│   └── DisabledView.tsx            # 禁用态视图
├── utils/                           # 工具函数
│   ├── index.ts                    # 工具函数导出
│   ├── percentFormatter.ts         # 百分比格式化
│   ├── percentValidator.ts         # 百分比验证
│   └── rangeConverter.ts           # 范围转换
└── docs/                            # 文档
    ├── pisellPercent.md            # 组件使用文档
    ├── pisellPercent.$tab-design.md    # 设计文档（本文件）
    ├── pisellPercent.$tab-dev.md       # 开发文档
    └── pisellPercent.$tab-test.md      # 测试文档
```

### 技术实现

**格式化系统**：

```
数值 → 范围转换 → 精度处理 → 添加 % 符号 → 最终显示
或
数值 → 范围转换 → 渲染进度条/环形进度
```

**示例**：

```
输入值: 0.855
range: [0, 1]
处理流程:
1. 范围转换: 0.855 × 100 = 85.5
2. 精度处理: 85.5 (precision: 1)
3. 添加符号: 85.5%
```

---

## 使用示例

### 1. 基础百分比显示（文本）

```
import { PisellPercent } from '@pisell/components';

// 默认 [0, 100] 范围
<PisellPercent
  mode="read"
  value={85.5}
/>
// 显示: 85.5%

// [0, 1] 范围
<PisellPercent
  mode="read"
  value={0.855}
  range={[0, 1]}
/>
// 显示: 85.5%
```

### 2. 进度条展示

```
<PisellPercent
  mode="read"
  value={65.5}
  variant="progress"
  style={{ width: 300 }}
/>
// 显示为进度条

// 自定义进度条颜色
<PisellPercent
  mode="read"
  value={85}
  variant="progress"
  progressProps={{
    strokeColor: '#52c41a',
    showInfo: true,
  }}
/>
```

### 3. 环形进度展示

```
<PisellPercent
  mode="read"
  value={75}
  variant="circle"
  circleProps={{
    width: 120,
    strokeWidth: 8,
  }}
/>
```

### 4. 编辑态（输入框）

```
function Example() {
  const [completion, setCompletion] = useState<number>(65.5);

  return (
    <PisellPercent
      value={completion}
      onChange={setCompletion}
      min={0}
      max={100}
      step={0.1}
      precision={1}
    />
  );
}
```

### 5. 编辑态（滑块 + 输入框）

```
<PisellPercent
  value={completion}
  onChange={setCompletion}
  showSlider
  sliderProps={{
    marks: {
      0: '0%',
      50: '50%',
      100: '100%',
    },
  }}
/>
```

### 6. 项目进度看板

```
function ProjectDashboard() {
  return (
    <div>
      {/* 只读态：文本 + 进度条组合 */}
      <div style={{ marginBottom: 16 }}>
        <div>
          <span>前端开发: </span>
          <PisellPercent mode="read" value={85.5} variant="text" />
        </div>
        <PisellPercent
          mode="read"
          value={85.5}
          variant="progress"
          style={{ width: 300 }}
        />
      </div>

      {/* 编辑态：调整进度 */}
      <Form.Item label="后端开发进度">
        <PisellPercent
          value={completionRate}
          onChange={setCompletionRate}
          showSlider
          precision={1}
        />
      </Form.Item>
    </div>
  );
}
```

### 7. 表格中使用

```
const columns = [
  {
    title: '任务名称',
    dataIndex: 'name',
  },
  {
    title: '完成度',
    dataIndex: 'completion',
    render: (value: number) => (
      <PisellPercent
        mode="read"
        value={value}
        variant="progress"
        style={{ width: 200 }}
      />
    ),
    sorter: (a, b) => a.completion - b.completion,
  },
];
```

---

## 展示变体详解

### 1. text 变体（纯文本）

最简单的展示方式，仅显示数值 + 百分号。

```
<PisellPercent mode="read" value={85.5} variant="text" />
// 显示: 85.5%
```

**适用场景**：

- 表格单元格
- 标签文本
- 简单数据展示

### 2. progress 变体（进度条）

使用 Ant Design Progress 组件展示，直观显示完成进度。

```
<PisellPercent
  mode="read"
  value={75}
  variant="progress"
  progressProps={{
    strokeColor: '#1890ff',
    showInfo: true, // 显示百分比文字
    status: 'active', // 动画效果
  }}
/>
```

**适用场景**：

- 任务进度
- 文件上传进度
- 目标完成度

### 3. circle 变体（环形进度）

使用环形进度条，适合仪表盘等场景。

```
<PisellPercent
  mode="read"
  value={80}
  variant="circle"
  circleProps={{
    width: 120,
    strokeColor: '#52c41a',
    format: (percent) => `${percent}%`,
  }}
/>
```

**适用场景**：

- 数据大屏
- 仪表盘
- KPI 展示

---

## 范围转换规则

### [0, 100] 范围（默认）

```
<PisellPercent value={85.5} range={[0, 100]} />
```

- 输入值直接作为百分比
- 无需转换
- 最常用的方式

### [0, 1] 范围

```
<PisellPercent value={0.855} range={[0, 1]} />
```

- 输入值 × 100 转换为百分比
- 适合接收小数比例的场景
- 例：0.855 → 85.5%

### 自定义范围

```
<PisellPercent value={855} range={[0, 1000]} />
```

- 按比例计算：(value / max) × 100
- 例：855 / 1000 × 100 = 85.5%

---

## 视觉规范

### text 变体

- 字号：继承父容器
- 颜色：`rgba(0, 0, 0, 0.85)`
- % 符号与数值之间无空格

### progress 变体

- 高度：8px（默认）
- 进度条颜色：`#1890ff`（正常）、`#52c41a`（成功）、`#ff4d4f`（异常）
- 背景色：`#f5f5f5`

### circle 变体

- 直径：120px（默认）
- 线宽：6px（默认）
- 颜色：同 progress

---

## 编辑态交互

### 仅输入框

```
<PisellPercent
  value={value}
  onChange={setValue}
/>
```

- 使用 InputNumber
- 后缀显示 %
- 支持步进器

### 滑块 + 输入框组合

```
<PisellPercent
  value={value}
  onChange={setValue}
  showSlider
/>
```

- 滑块和输入框双向同步
- 滑块适合快速调整
- 输入框适合精确输入

---

## 性能优化

1. 继承 PisellNumber 的优化策略
2. 进度条组件使用 React.memo
3. 格式化和转换函数使用 useMemo

---

## 最佳实践

1. **语义正确**：比例、完成度、增长率等场景使用 PisellPercent
2. **选择合适的变体**：简单展示用 text，直观展示用 progress/circle
3. **范围匹配**：根据数据源选择合适的 range
4. **精度设置**：一般 1 位小数即可，避免过高精度
5. **编辑体验**：复杂场景使用滑块+输入框组合，提升用户体验
