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

﻿# PisellRating 组件设计文档

## 组件概述

PisellRating 是基于 PisellNumber 派生的评分组件，专门用于处理用户评分、满意度、等级等评分场景。它继承了 PisellNumber
的数值处理能力，并使用星级图标等可视化方式替代纯数字输入，提供更直观的评分交互体验。

**设计原则**：

- 基于 PisellNumber 的数值管理能力
- 使用 Ant Design Rate 组件作为基础控件
- 参考 PisellSingleLineText 架构，采用三态视图
- 使用 @pisell/utils 中的公共状态管理逻辑
- 提供直观的星级评分交互

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

---

## 核心功能

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

- 数值管理（受控/非受控）
- 数值校验（范围验证）
- 状态管理
- 筛选与排序能力

### 2. 评分特有功能

**星级展示**：

- 默认使用星星图标
- 支持自定义图标
- 支持半星评分
- 支持只读展示

**交互体验**：

- 点击评分
- 悬停预览
- 键盘导航（左右箭头）
- 清除评分

**展示配置**：

- 可配置星星数量（默认 5 个）
- 可同时显示数值文本
- 可显示评分描述（如：很满意）
- 支持不同尺寸

---

## 接口定义

### Props 属性

继承部分 PisellNumber 的属性，并扩展评分特有属性：

| 属性名                  | 类型                                                     | 默认值              | 说明                                       |
|----------------------|--------------------------------------------------------|------------------|------------------------------------------|
| **继承自 PisellNumber** | -                                                      | -                | -                                        |
| `mode`               | `'read' \| 'edit'`                                     | `'edit'`         | 显示模式                                     |
| `disabled`           | `boolean`                                              | `false`          | 是否禁用                                     |
| `value`              | `number \| null`                                       | -                | 当前评分值（受控）                                |
| `defaultValue`       | `number \| null`                                       | -                | 默认评分值（非受控）                               |
| `onChange`           | `(value: number) => void`                              | -                | 评分变更回调                                   |
| `max`                | `number`                                               | `5`              | 最大评分值（星星数量）                              |
| **评分特有属性**           | -                                                      | -                | -                                        |
| `allowHalf`          | `boolean`                                              | `false`          | 是否允许半星评分                                 |
| `allowClear`         | `boolean`                                              | `true`           | 是否允许清除评分（再次点击清除）                         |
| `icon`               | `ReactNode \| (props: { index: number }) => ReactNode` | -                | 自定义图标                                    |
| `character`          | `ReactNode`                                            | `<StarFilled />` | 自定义字符（替代星星）                              |
| `showValue`          | `boolean`                                              | `false`          | 是否显示数值文本                                 |
| `showCount`          | `boolean`                                              | `false`          | 是否显示评分人数                                 |
| `count`              | `number`                                               | -                | 评分人数（showCount=true时）                    |
| `tooltips`           | `string[]`                                             | -                | 评分描述文本数组（如：['很差', '差', '一般', '好', '很好']） |
| `onHoverChange`      | `(value: number) => void`                              | -                | 悬停评分值变化回调                                |

### 只读态特有属性

| 属性名               | 类型                                | 默认值         | 说明        |
|-------------------|-----------------------------------|-------------|-----------|
| `size`            | `'small' \| 'default' \| 'large'` | `'default'` | 星星尺寸      |
| `color`           | `string`                          | `'#fadb14'` | 星星颜色（已选中） |
| `unselectedColor` | `string`                          | `'#d9d9d9'` | 星星颜色（未选中） |

---

## 组件架构

### 文件结构

```
pisellRating/
├── index.tsx                        # 组件导出
├── PisellRating.tsx                 # 组件主入口
├── PisellRating.less                # 组件样式
├── PisellRating.test.tsx            # 单元测试
├── PisellRating.stories.tsx         # Storybook 示例
├── types.ts                         # TypeScript 类型定义
├── components/                      # 子组件
│   ├── ReadOnlyView.tsx            # 只读态视图
│   ├── EditView.tsx                # 编辑态视图
│   └── DisabledView.tsx            # 禁用态视图
├── utils/                           # 工具函数
│   ├── index.ts                    # 工具函数导出
│   └── ratingValidator.ts          # 评分验证
├── constants/                       # 常量
│   └── defaultTooltips.ts          # 默认评分描述
└── docs/                            # 文档
    ├── pisellRating.md             # 组件使用文档
    ├── pisellRating.$tab-design.md     # 设计文档（本文件）
    ├── pisellRating.$tab-dev.md        # 开发文档
    └── pisellRating.$tab-test.md       # 测试文档
```

### 技术实现

**基础控件**：

- 编辑态：Ant Design Rate 组件
- 只读态：自定义星级展示或使用 Rate 的只读模式

**值的处理**：

- 整星：value 为整数（1, 2, 3, 4, 5）
- 半星：value 为 0.5 的倍数（0.5, 1, 1.5, 2, ..., 5）
- 验证：确保值不超过 `max`

---

## 使用示例

### 1. 基础评分（编辑态）

```
import { PisellRating } from '@pisell/components';
import { useState } from 'react';

function Example() {
  const [rating, setRating] = useState<number>(0);

  return (
    <PisellRating
      value={rating}
      onChange={setRating}
    />
  );
}
// 显示 5 个星星，可点击评分
```

### 2. 半星评分

```
<PisellRating
  value={rating}
  onChange={setRating}
  allowHalf
/>
// 支持 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5
```

### 3. 只读态展示（商品评分）

```
<PisellRating
  mode="read"
  value={4.2}
  allowHalf
/>
// 显示 4.5 颗星（四舍五入到 0.5）

// 同时显示数值
<PisellRating
  mode="read"
  value={4.2}
  allowHalf
  showValue
/>
// 显示: ★★★★☆ 4.2
```

### 4. 带评分描述

```
<PisellRating
  value={rating}
  onChange={setRating}
  tooltips={['很差', '差', '一般', '好', '很好']}
/>
// 悬停在不同星星上显示对应描述
```

### 5. 自定义星星数量

```
<PisellRating
  value={rating}
  onChange={setRating}
  max={10}
/>
// 显示 10 颗星
```

### 6. 自定义图标

```
import { HeartFilled } from '@ant-design/icons';

<PisellRating
  value={rating}
  onChange={setRating}
  character={<HeartFilled />}
/>
// 使用爱心代替星星
```

### 7. 商品评分展示

```
function ProductReview() {
  const [userRating, setUserRating] = useState<number>(0);
  const averageRating = 4.2;
  const reviewCount = 328;

  return (
    <div>
      {/* 只读态：显示平均分 */}
      <div style={{ marginBottom: 16 }}>
        <span>商品评分: </span>
        <PisellRating
          mode="read"
          value={averageRating}
          allowHalf
          showValue
        />
        <span style={{ marginLeft: 8, color: '#999' }}>
          ({reviewCount} 人评价)
        </span>
      </div>

      {/* 编辑态：用户打分 */}
      <Form.Item label="您的评分">
        <PisellRating
          value={userRating}
          onChange={setUserRating}
          allowHalf
          tooltips={['非常差', '差', '一般', '满意', '非常满意']}
        />
      </Form.Item>
    </div>
  );
}
```

### 8. 表格中展示评分

```
const columns = [
  {
    title: '商品名称',
    dataIndex: 'name',
  },
  {
    title: '评分',
    dataIndex: 'rating',
    render: (value: number) => (
      <PisellRating
        mode="read"
        value={value}
        allowHalf
        showValue
      />
    ),
    sorter: (a, b) => a.rating - b.rating,
  },
];
```

### 9. 满意度调查

```
const satisfactionLevels = [
  '非常不满意',
  '不满意',
  '一般',
  '满意',
  '非常满意'
];

<PisellRating
  value={satisfaction}
  onChange={setSatisfaction}
  tooltips={satisfactionLevels}
  max={5}
/>
```

---

## 评分值规则

### 整星评分（allowHalf=false）

```
可选值: 0, 1, 2, 3, 4, 5
点击行为: 
- 点击第 1 颗星 → value = 1
- 点击第 2 颗星 → value = 2
- 再次点击已选中的星 → value = 0 (清除)
```

### 半星评分（allowHalf=true）

```
可选值: 0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5
点击行为:
- 点击第 1 颗星左半部分 → value = 0.5
- 点击第 1 颗星右半部分 → value = 1
- 点击第 2 颗星左半部分 → value = 1.5
- 再次点击清除
```

---

## 视觉规范

### 星星样式

**已选中**：

- 颜色：`#fadb14`（金黄色）
- 填充：实心

**未选中**：

- 颜色：`#d9d9d9`（浅灰色）
- 填充：实心或空心

**悬停态**：

- 悬停位置及之前的星星高亮
- 颜色同已选中

**禁用态**：

- 颜色变为灰色 `#bfbfbf`
- 不响应交互

### 尺寸规范

| 尺寸      | 星星大小 | 间距  |
|---------|------|-----|
| small   | 16px | 4px |
| default | 20px | 8px |
| large   | 24px | 8px |

---

## 交互规范

### 鼠标交互

1. **悬停**：悬停位置及之前的星星高亮，显示 tooltip（如有）
2. **点击**：设置评分值
3. **再次点击**：清除评分（如 allowClear=true）

### 键盘交互

1. **左箭头 ←**：评分值 -1（或 -0.5）
2. **右箭头 →**：评分值 +1（或 +0.5）
3. **Home**：设置为最小值（0 或 0.5）
4. **End**：设置为最大值（max）

### 触摸交互（移动端）

- 支持触摸点击
- 半星模式下精确识别左右半部分

---

## 无障碍支持

- 支持键盘导航
- 提供 `aria-label`
- 星星可以被屏幕阅读器识别
- 评分值会被朗读

---

## 性能优化

1. 使用 React.memo 避免不必要的重渲染
2. 图标资源使用 SVG，性能更好
3. 事件处理函数使用 useCallback

---

## 最佳实践

1. **场景匹配**：用户评分、满意度调查、等级展示等场景使用
2. **半星使用**：允许用户更精细的评分时启用 allowHalf
3. **描述文本**：提供 tooltips 让用户明白每个评分的含义
4. **只读展示**：展示历史评分时使用 mode="read"
5. **自定义图标**：根据业务场景使用合适的图标（星星/爱心/笑脸等）
6. **评分范围**：一般使用 5 星制，特殊场景可调整 max 值

---

## 与 PisellNumber 的关系

PisellRating 虽然基于 PisellNumber 的概念，但在实现上有较大差异：

**继承的能力**：

- 数值管理（value/onChange）
- 受控/非受控模式
- 范围验证（min=0, max）
- 状态管理逻辑

**不同之处**：

- 输入方式：图标点击 vs 数字输入
- 展示方式：可视化图标 vs 纯文本
- 精度限制：0.5 的倍数 vs 任意精度
- 交互体验：点击图标 vs 输入框输入

因此 PisellRating 更像是受 PisellNumber 启发的独立组件，而非严格的派生组件。
