---
title: 开发文档
order: 3
category: pro
---

# PisellLookup 组件开发文档

## 1. 组件基本信息

| 项目       | 内容                                     |
|----------|----------------------------------------|
| **组件名称** | PisellLookup                           |
| **组件版本** | 1.0.0                                  |
| **组件分类** | Pro Components / Data Entry            |
| **组件编号** | pcp_de_lookup_V1.0                     |
| **技术栈**  | React + TypeScript + Ant Design + Less |
| **开发日期** | 2026-02-02                             |

## 2. 组件概述

### 2.1 组件定位

PisellLookup 是一个**搜索交互协议组件**，提供统一的搜索入口、状态管理和结果承载能力。它采用"容器 + 插槽"
设计模式，将搜索交互与业务逻辑完全解耦。

**组件职责：**

- ✅ 搜索入口交互（输入框、按钮、图标、自定义触发器）
- ✅ 搜索状态管理（关键词、可见性、加载状态）
- ✅ 结果承载容器（Inline、Popup、Modal、Drawer、Detached）
- ✅ 辅助功能（搜索历史、联想词、热门搜索）
- ✅ 扫码功能集成
- ✅ 搜索行为控制（实时/确认触发、防抖、清除）

**组件不负责：**

- ❌ 数据请求与处理（由外部通过回调处理）
- ❌ 搜索结果渲染（通过 `resultRender` 由外部注入）
- ❌ 结果的选择、多选、确认等业务逻辑（由外部实现）

### 2.2 设计理念

```
┌─────────────────────────────────────┐
│      PisellLookup (Pro)             │
│  职责：交互协议、状态流转、UI容器    │
│  ────────────────────────────────   │
│  • 搜索入口的多种形态                │
│  • 搜索过程的状态管理                │
│  • 结果容器的展示方式                │
│  • 辅助功能（历史/联想/热词）        │
└─────────────────────────────────────┘
              ↕ (事件 & 插槽)
┌─────────────────────────────────────┐
│      Plus Components / 业务层       │
│  职责：数据获取、结果渲染、业务逻辑  │
│  ────────────────────────────────   │
│  • 调用 API 获取搜索结果             │
│  • 渲染商品卡片/用户列表/订单表格    │
│  • 处理选择、多选、确认等业务行为    │
└─────────────────────────────────────┘
```

### 2.3 核心价值

1. **统一体验**：避免每个页面自己实现搜索 UI，确保交互一致性
2. **降低成本**：拖拽即用，配置数据源即可完成搜索功能
3. **灵活适配**：通过 `resultRender` 适配任何业务实体（商品、用户、订单等）
4. **防止误用**：通过组件边界约束，避免将搜索逻辑与列表逻辑混在一起

## 3. 组件需求点罗列

### 3.1 功能需求

#### 3.1.1 触发器功能

- [ ] 支持 Input 输入框触发器
- [ ] 支持 Button 按钮触发器
- [ ] 支持 Icon 图标触发器
- [ ] 支持 Text 文本触发器
- [ ] 支持自定义 ReactNode 触发器
- [ ] 触发器支持禁用状态
- [ ] 触发器支持自定义样式

#### 3.1.2 搜索功能

- [ ] 支持实时搜索模式（输入即触发）
- [ ] 支持确认触发模式（点击按钮触发）
- [ ] 支持防抖配置
- [ ] 支持清除按钮
- [ ] 支持前缀图标配置
- [ ] 支持占位符文本配置
- [ ] 支持输入框尺寸配置（默认/大号）

#### 3.1.3 扫码功能

- [ ] 集成现有扫码组件（PisellQRScanner/PisellScan）
- [ ] 扫码结果自动填入搜索框
- [ ] 扫码后自动触发搜索
- [ ] 支持禁用扫码功能

#### 3.1.4 搜索历史

- [ ] 搜索历史存储在 localStorage
- [ ] 支持配置历史记录数量上限
- [ ] 支持显示/隐藏历史记录
- [ ] 支持点击历史记录快速搜索
- [ ] 支持清除单条历史记录
- [ ] 支持清除全部历史记录
- [ ] 支持自定义历史记录存储 key

#### 3.1.5 联想词功能

- [ ] 支持显示/隐藏联想词
- [ ] 联想词数据由外部提供（onLoadSuggestions 回调）
- [ ] 支持点击联想词快速搜索
- [ ] 支持自定义联想词渲染

#### 3.1.6 热门搜索

- [ ] 支持显示/隐藏热门搜索
- [ ] 热门搜索数据由外部提供（onLoadHotWords 回调）
- [ ] 支持点击热门搜索快速搜索
- [ ] 支持自定义热门搜索渲染

#### 3.1.7 结果承载

- [ ] 支持 Inline 内联展示模式
- [ ] 支持 Popup 浮层展示模式
- [ ] 支持 Modal 弹窗展示模式
- [ ] 支持 Drawer 抽屉展示模式
- [ ] 支持 Detached 独立展示模式
- [ ] 根据触发器类型智能选择默认展示模式
- [ ] 结果内容通过 resultRender 由外部注入

### 3.2 样式需求

#### 3.2.1 触发器样式

- [ ] 支持自定义触发器尺寸
- [ ] 支持自定义触发器颜色
- [ ] 支持自定义触发器图标
- [ ] 支持自定义触发器文本

#### 3.2.2 容器样式

- [ ] Modal 默认宽度 834px，支持自定义
- [ ] Modal 支持自定义挂载点
- [ ] Drawer 默认宽度 378px，支持自定义
- [ ] 支持自定义容器背景色
- [ ] 支持自定义容器圆角
- [ ] 支持自定义容器内边距
- [ ] 支持自定义容器间距
- [ ] 支持自定义容器边框
- [ ] 支持自定义容器阴影

### 3.3 交互需求

#### 3.3.1 打开/关闭

- [ ] Input 类型：聚焦时打开
- [ ] Button/Icon/Text/ReactNode 类型：点击时打开
- [ ] 支持点击关闭按钮关闭
- [ ] 支持点击遮罩层关闭（可配置）
- [ ] 支持 ESC 键关闭
- [ ] 支持通过 visible 受控

#### 3.3.2 输入交互

- [ ] Input 聚焦时自动拉起键盘
- [ ] 支持键盘导航（上下键选择历史/联想词）
- [ ] 支持 Enter 键触发搜索
- [ ] 输入内容时显示清除按钮

#### 3.3.3 状态流转

- [ ] Idle（空闲态）：未打开搜索
- [ ] Active（激活态）：打开搜索，显示辅助信息
- [ ] Searching（搜索中）：输入内容，触发搜索
- [ ] Results（结果展示）：显示搜索结果

### 3.4 响应式需求

- [ ] 容器宽度自适应
- [ ] 移动端优化（大号输入框、大点击目标）
- [ ] 支持横竖屏切换

## 4. 组件 API 设计

### 4.1 Ref 方法定义

```
interface PisellLookupRef {
  /** 打开搜索 */
  open: () => void;
  
  /** 关闭搜索 */
  close: () => void;
  
  /** 获取当前关键词 */
  getKeyword: () => string;
  
  /** 设置关键词 */
  setKeyword: (keyword: string) => void;
}
```

### 4.2 Props 定义

```
interface PisellLookupProps {
  // ============ 触发器配置 ============
  
  /** 预设触发器类型（与 trigger 互斥） */
  triggerType?: 'input' | 'button' | 'icon' | 'text';
  
  /** 自定义触发器（与 triggerType 互斥） */
  trigger?: React.ReactNode;
  
  /** 触发器文本（triggerType='text' 时） */
  triggerText?: string;
  
  /** 触发器图标（triggerType='icon' 时） */
  triggerIcon?: React.ReactNode;
  
  /** 按钮文本（triggerType='button' 时） */
  buttonText?: string;
  
  /** 是否禁用 */
  disabled?: boolean;
  
  // ============ 输入框配置 ============
  
  /** 占位符文本 */
  placeholder?: string;
  
  /** 输入框尺寸 */
  size?: 'large' | 'middle' | 'small';
  
  /** 是否显示前缀图标 */
  showPrefixIcon?: boolean;
  
  /** 前缀图标 */
  prefixIcon?: React.ReactNode;
  
  /** 是否显示清除按钮 */
  showClear?: boolean;
  
  /** 是否显示确认触发按钮 */
  showConfirmButton?: boolean;
  
  /** 确认按钮文本 */
  confirmButtonText?: string;
  
  // ============ 搜索行为配置 ============
  
  /** 搜索触发模式 */
  searchMode?: 'realtime' | 'confirm';
  
  /** 防抖时间（毫秒） */
  debounceTime?: number;
  
  /** 搜索关键词（受控） */
  value?: string;
  
  /** 关键词变化回调 */
  onChange?: (value: string) => void;
  
  /** 搜索触发回调 */
  onSearch?: (keyword: string) => void;
  
  // ============ 扫码配置 ============
  
  /** 是否显示扫码按钮 */
  showScan?: boolean;
  
  /** 扫码完成回调 */
  onScan?: (code: string) => void;
  
  // ============ 搜索历史配置 ============
  
  /** 是否显示搜索历史 */
  showHistory?: boolean;
  
  /** 历史记录存储 key */
  historyKey?: string;
  
  /** 历史记录数量上限 */
  maxHistoryCount?: number;
  
  /** 加载历史记录回调（用于自定义存储） */
  onLoadHistory?: () => string[];
  
  /** 保存历史记录回调（用于自定义存储） */
  onSaveHistory?: (history: string[]) => void;
  
  /** 自定义历史记录渲染 */
  historyRender?: (history: string[], onSelect: (keyword: string) => void) => React.ReactNode;
  
  // ============ 联想词配置 ============
  
  /** 是否显示联想词 */
  showSuggestions?: boolean;
  
  /** 加载联想词回调 */
  onLoadSuggestions?: (keyword: string) => Promise<string[]> | string[];
  
  /** 自定义联想词渲染 */
  suggestionsRender?: (suggestions: string[], onSelect: (keyword: string) => void) => React.ReactNode;
  
  // ============ 热门搜索配置 ============
  
  /** 是否显示热门搜索 */
  showHotWords?: boolean;
  
  /** 加载热门搜索回调 */
  onLoadHotWords?: () => Promise<string[]> | string[];
  
  /** 自定义热门搜索渲染 */
  hotWordsRender?: (hotWords: string[], onSelect: (keyword: string) => void) => React.ReactNode;
  
  // ============ 结果展示配置 ============
  
  /** 结果展示方式 */
  displayType?: 'inline' | 'popup' | 'modal' | 'drawer' | 'detached';
  
  /** 结果渲染函数 */
  resultRender?: (keyword: string, onClose?: () => void) => React.ReactNode;
  
  /** 是否显示加载状态 */
  loading?: boolean;
  
  /** 空状态渲染 */
  emptyRender?: () => React.ReactNode;
  
  // ============ 容器样式配置 ============
  
  /** Modal 宽度（默认 834px） */
  modalWidth?: number | string;
  
  /** Modal 自定义样式 */
  modalStyle?: React.CSSProperties;
  
  /** Modal 挂载节点 */
  getContainer?: HTMLElement | (() => HTMLElement) | false;
  
  /** Drawer 宽度（默认 378px） */
  drawerWidth?: number | string;
  
  /** Drawer 位置 */
  drawerPlacement?: 'left' | 'right' | 'top' | 'bottom';
  
  /** Popup 宽度 */
  popupWidth?: number | string;
  
  /** 容器自定义样式 */
  containerStyle?: React.CSSProperties;
  
  /** 容器自定义类名 */
  containerClassName?: string;
  
  // ============ 可见性控制 ============
  
  /** 是否可见（受控） */
  visible?: boolean;
  
  /** 可见性变化回调 */
  onVisibleChange?: (visible: boolean) => void;
  
  /** 
   * 打开回调
   * 当搜索面板从关闭变为打开时触发
   * 适用于所有展示类型（Inline、Popup、Modal、Drawer、Detached）
   */
  onOpen?: () => void;
  
  /** 
   * 关闭回调
   * 当搜索面板从打开变为关闭时触发
   * 适用于所有展示类型（Inline、Popup、Modal、Drawer、Detached）
   */
  onClose?: () => void;
  
  /** 是否显示遮罩层（仅 Modal/Drawer） */
  mask?: boolean;
  
  /** 点击遮罩是否关闭（仅 Modal/Drawer） */
  maskClosable?: boolean;
  
  /** 关闭时是否清空关键词 */
  clearOnClose?: boolean;
  
  // ============ 其他配置 ============
  
  /** 自定义类名 */
  className?: string;
  
  /** 自定义样式 */
  style?: React.CSSProperties;
  
  /** 层级 */
  zIndex?: number;
}
```

### 4.3 默认值

```
{
  triggerType: 'input',
  size: 'middle',
  placeholder: '请输入搜索内容',
  showClear: true,
  showConfirmButton: true,
  confirmButtonText: 'Lookup',
  searchMode: 'realtime',
  debounceTime: 300,
  showScan: true,
  showHistory: false,
  historyKey: 'pisell_lookup_history',
  maxHistoryCount: 10,
  showSuggestions: false,
  showHotWords: false,
  displayType: undefined, // 根据 triggerType 智能判断
  modalWidth: 834,
  getContainer: undefined, // 默认挂载到 document.body
  drawerWidth: 378,
  drawerPlacement: 'right',
  mask: false, // 默认不显示遮罩层
  maskClosable: true,
  clearOnClose: false, // 默认保留搜索内容
}
```

### 4.4 智能默认值逻辑

```
displayType 智能判断规则：
- triggerType === 'input' → 'inline'
- triggerType === 'button' | 'icon' | 'text' | trigger 存在 → 'modal'
- 未指定 triggerType 且无 trigger → 'detached'

searchMode 智能判断规则：
- showConfirmButton === false → 强制使用 'realtime' 模式
- showConfirmButton === true → 使用配置的 searchMode
```

### 4.5 使用场景示例

#### 场景 1：默认 Modal（挂载到 body）

```
<PisellLookup
  triggerType="button"
  buttonText="搜索"
  displayType="modal"
  onSearch={handleSearch}
  resultRender={(keyword) => <SearchResults keyword={keyword} />}
/>
```

#### 场景 2：Modal 自定义挂载点（解决层级问题）

```
// 挂载到指定容器，解决在某些容器内层级被遮挡的问题
<PisellLookup
  triggerType="button"
  buttonText="搜索"
  displayType="modal"
  getContainer={() => document.getElementById('modal-root')}
  onSearch={handleSearch}
  resultRender={(keyword) => <SearchResults keyword={keyword} />}
/>
```

#### 场景 3：Modal 挂载到父元素（局部弹窗）

```
// getContainer={false} 将 Modal 挂载到触发器的父节点
// 适用于需要 Modal 在特定区域内展示的场景
<div className="search-container">
  <PisellLookup
    triggerType="button"
    buttonText="搜索"
    displayType="modal"
    getContainer={false}
    onSearch={handleSearch}
    resultRender={(keyword) => <SearchResults keyword={keyword} />}
  />
</div>
```

#### 场景 4：Modal 挂载到容器并使用 100% 宽度

```
// 挂载到指定容器，并使用 100% 宽度填满容器
<div id="search-container" style={{ width: 800 }}>
  <PisellLookup
    triggerType="button"
    buttonText="搜索"
    displayType="modal"
    getContainer={() => document.getElementById('search-container')}
    modalWidth="100%"
    onSearch={handleSearch}
    resultRender={(keyword) => <SearchResults keyword={keyword} />}
  />
</div>
```

#### 场景 4：Input 模式 + Inline 展示

```
<PisellLookup
  triggerType="input"
  placeholder="搜索商品"
  // displayType 自动为 'inline'
  onSearch={handleSearch}
  resultRender={(keyword) => <ProductList keyword={keyword} />}
/>
```

#### 场景 5：自定义触发器 + Drawer

```
<PisellLookup
  trigger={
    <Card hoverable style={{ width: 200 }}>
      <Space>
        <SearchOutlined />
        <Text>高级搜索</Text>
      </Space>
    </Card>
  }
  displayType="drawer"
  drawerPlacement="right"
  onSearch={handleAdvancedSearch}
  resultRender={(keyword) => <AdvancedResults keyword={keyword} />}
/>
```

## 5. 组件模块拆解

### 5.1 组件结构层次

```
PisellLookup (主容器)
├── LookupTrigger (触发器层)
│   ├── InputTrigger (输入框触发器)
│   ├── ButtonTrigger (按钮触发器)
│   ├── IconTrigger (图标触发器)
│   ├── TextTrigger (文本触发器)
│   └── CustomTrigger (自定义触发器)
│
├── LookupAuxiliary (辅助层)
│   ├── SearchHistory (搜索历史)
│   ├── SuggestWords (联想词)
│   └── HotWords (热门搜索)
│
└── LookupResultHost (结果承载层)
    ├── InlineHost (内联展示)
    ├── PopupHost (浮层展示)
    ├── ModalHost (弹窗展示)
    ├── DrawerHost (抽屉展示)
    └── DetachedHost (独立展示)
```

### 5.2 核心子组件说明

#### 5.2.1 LookupTrigger（触发器层）

**职责：**

- 渲染不同类型的触发器
- 处理触发事件（点击、聚焦）
- 管理触发器状态（禁用、加载）

**输入：**

```
{
  type: 'input' | 'button' | 'icon' | 'text' | 'custom',
  trigger?: ReactNode,
  disabled: boolean,
  onClick: () => void,
  onFocus: () => void,
  // ... 其他触发器配置
}
```

**子组件：**

- `InputTrigger`：基于 Ant Design Input，支持扫码、清除、确认按钮
- `ButtonTrigger`：基于 Ant Design Button
- `IconTrigger`：自定义图标容器
- `TextTrigger`：文本链接触发器
- `CustomTrigger`：包装自定义 ReactNode，注入点击事件

#### 5.2.2 LookupAuxiliary（辅助层）

**职责：**

- 展示搜索历史、联想词、热门搜索
- 处理点击选择事件
- 管理 localStorage 存储

**输入：**

```
{
  keyword: string,
  showHistory: boolean,
  showSuggestions: boolean,
  showHotWords: boolean,
  onSelect: (keyword: string) => void,
  // ... 其他辅助配置
}
```

**子组件：**

- `SearchHistory`：历史记录列表（使用 Ant Design Tag 或 List）
- `SuggestWords`：联想词列表（使用 Ant Design List）
- `HotWords`：热门搜索标签（使用 Ant Design Space + Tag）

#### 5.2.3 LookupResultHost（结果承载层）

**职责：**

- 根据 displayType 渲染不同承载容器
- 管理容器的打开/关闭状态
- 渲染搜索输入区和结果区

**输入：**

```
{
  displayType: 'inline' | 'popup' | 'modal' | 'drawer' | 'detached',
  visible: boolean,
  onClose: () => void,
  children: ReactNode, // 输入区 + 辅助区 + 结果区
  // ... 样式配置
}
```

**子组件：**

- `InlineHost`：直接渲染在触发器下方
- `PopupHost`：基于 Ant Design Dropdown 或 Popover
- `ModalHost`：基于 Ant Design Modal
- `DrawerHost`：基于 Ant Design Drawer
- `DetachedHost`：独立渲染，不与触发器绑定

### 5.3 工具函数模块（utils/）

#### 5.3.1 storage.ts

```
- loadHistory(key: string): string[]
- saveHistory(key: string, history: string[], maxCount: number): void
- clearHistory(key: string): void
- addHistoryItem(key: string, item: string, maxCount: number): void
- removeHistoryItem(key: string, item: string): void
```

#### 5.3.2 trigger.ts

```
- getDefaultDisplayType(triggerType?: string, hasTrigger?: boolean): DisplayType
- isInputTrigger(triggerType?: string): boolean
- isButtonLikeTrigger(triggerType?: string, hasTrigger?: boolean): boolean
```

### 5.4 自定义 Hooks（hooks/）

#### 5.4.1 useSearchState.ts

```
管理搜索状态：
- keyword: string
- visible: boolean
- loading: boolean
- suggestions: string[]
- hotWords: string[]
```

#### 5.4.2 useSearchHistory.ts

```
管理搜索历史：
- history: string[]
- addHistory(keyword: string): void
- removeHistory(keyword: string): void
- clearHistory(): void
```

#### 5.4.3 useDebounceSearch.ts

```
防抖搜索：
- debouncedKeyword: string
- onSearch(keyword: string): void
```

## 6. 组件实现方案

### 6.1 技术选型

| 技术项   | 选型                           | 说明                                                 |
|-------|------------------------------|----------------------------------------------------|
| UI 框架 | Ant Design                   | 使用 Input、Button、Modal、Drawer、Dropdown、Tag、List 等组件 |
| 状态管理  | React Hooks                  | useState、useEffect、useMemo、useCallback             |
| 样式方案  | Less                         | 支持主题定制                                             |
| 存储方案  | localStorage                 | 搜索历史存储                                             |
| 扫码集成  | PisellQRScanner / PisellScan | 复用现有扫码组件                                           |

### 6.2 状态管理方案

#### 6.2.1 内部状态

```
const [visible, setVisible] = useState(false);           // 是否显示结果区
const [keyword, setKeyword] = useState('');              // 当前搜索关键词
const [searchHistory, setSearchHistory] = useState([]); // 搜索历史
const [suggestions, setSuggestions] = useState([]);     // 联想词列表
const [hotWords, setHotWords] = useState([]);           // 热门搜索列表
const [loading, setLoading] = useState(false);          // 加载状态
```

#### 6.2.2 受控模式

```
支持 value + onChange 受控关键词
支持 visible + onVisibleChange 受控可见性
```

### 6.3 核心逻辑实现

#### 6.3.1 触发器逻辑

```
1. 判断触发器类型（triggerType 或 trigger）
2. 渲染对应的触发器组件
3. 绑定触发事件：
   - Input: onFocus → 打开结果区
   - Button/Icon/Text/Custom: onClick → 打开结果区
4. 根据触发器类型智能判断 displayType
```

#### 6.3.2 搜索触发逻辑

```
1. 实时搜索模式（searchMode='realtime'）：
   - 监听 keyword 变化
   - 使用 useDebounce 防抖
   - 调用 onSearch 回调

2. 确认触发模式（searchMode='confirm'）：
   - 点击确认按钮触发
   - Enter 键触发
   - 调用 onSearch 回调

3. 扫码触发：
   - 打开扫码组件
   - 扫码完成 → 填入 keyword
   - 自动触发搜索
```

#### 6.3.3 搜索历史逻辑

```
1. 组件挂载时从 localStorage 加载历史
2. 搜索触发时保存关键词到历史（去重、限制数量）
3. 点击历史记录 → 填入 keyword → 触发搜索
4. 支持删除单条历史
5. 支持清除全部历史
```

#### 6.3.4 联想词逻辑

```
1. 监听 keyword 变化
2. 调用 onLoadSuggestions 回调获取联想词
3. 渲染联想词列表
4. 点击联想词 → 填入 keyword → 触发搜索
```

#### 6.3.5 热门搜索逻辑

```
1. 组件打开时调用 onLoadHotWords 回调获取热门搜索
2. 渲染热门搜索标签
3. 点击热门搜索 → 填入 keyword → 触发搜索
```

#### 6.3.6 结果承载逻辑

```
根据 displayType 渲染不同容器：

1. Inline:
   - 直接在触发器下方渲染
   - 支持展开/收起动画

2. Popup:
   - 使用 Ant Design Dropdown
   - 定位在触发器下方
   - 支持自定义宽度

3. Modal:
   - 使用 Ant Design Modal
   - 默认宽度 834px
   - 支持自定义样式
   - 支持自定义挂载点（getContainer）
   - 内部渲染：输入区 + 辅助区 + 结果区

4. Drawer:
   - 使用 Ant Design Drawer
   - 默认宽度 378px
   - 支持四个方向
   - 内部渲染：输入区 + 辅助区 + 结果区

5. Detached:
   - 独立渲染，不与触发器绑定
   - 适用于移动端全屏搜索
```

### 6.4 样式实现方案

#### 6.4.1 主题适配

```
使用 Ant Design ConfigProvider 读取主题 token：
- colorPrimary: 主色
- colorPrimaryBg: 主色浅色背景
- borderRadius: 圆角
- padding: 内边距
```

#### 6.4.2 样式结构

```
.pisell-lookup
  ├── .pisell-lookup-trigger
  │   ├── .pisell-lookup-trigger-input
  │   ├── .pisell-lookup-trigger-button
  │   └── .pisell-lookup-trigger-custom
  │
  ├── .pisell-lookup-container
  │   ├── .pisell-lookup-input-area
  │   ├── .pisell-lookup-auxiliary
  │   │   ├── .pisell-lookup-history
  │   │   ├── .pisell-lookup-suggestions
  │   │   └── .pisell-lookup-hotwords
  │   └── .pisell-lookup-result
  │
  └── .pisell-lookup-[displayType]
      ├── .pisell-lookup-inline
      ├── .pisell-lookup-popup
      ├── .pisell-lookup-modal
      ├── .pisell-lookup-drawer
      └── .pisell-lookup-detached
```

### 6.5 性能优化方案

1. **防抖优化**：搜索输入使用防抖，默认 300ms
2. **组件缓存**：使用 React.memo 缓存子组件
3. **回调缓存**：使用 useCallback 缓存事件处理函数
4. **计算缓存**：使用 useMemo 缓存计算结果
5. **按需渲染**：根据配置项按需渲染辅助功能
6. **虚拟滚动**：历史记录、联想词列表过长时使用虚拟滚动（可选）

### 6.6 可访问性方案

1. **键盘导航**：支持 Tab、Enter、Esc、上下方向键
2. **ARIA 属性**：添加 role、aria-label 等属性
3. **焦点管理**：打开时自动聚焦输入框
4. **屏幕阅读器**：支持屏幕阅读器读取

## 7. 组件依赖关系

### 7.1 依赖的现有组件

```
PisellLookup
  ├── Ant Design
  │   ├── Input (输入框)
  │   ├── Button (按钮)
  │   ├── Modal (弹窗)
  │   ├── Drawer (抽屉)
  │   ├── Dropdown (下拉)
  │   ├── Popover (气泡)
  │   ├── Tag (标签)
  │   ├── List (列表)
  │   ├── Space (间距)
  │   └── Empty (空状态)
  │
  └── Pisell Components
      ├── PisellQRScanner (扫码)
      └── PisellScan (扫码)
```

### 7.2 可配合使用的组件（结果渲染）

```
结果渲染层（由外部通过 resultRender 注入）：
  ├── PisellCards (卡片列表)
  ├── PisellBasicGrid (网格布局)
  ├── PisellScrollView (滚动视图)
  ├── Table (表格)
  └── 自定义组件
```

### 7.3 依赖的工具函数

```
从 @pisell/utils 导入（如有）：
  ├── debounce (防抖)
  ├── throttle (节流)
  └── classNames (类名合并)
```

## 8. 组件结构图

### 8.1 组件层级关系图

```
┌────────────────────────────────────────────────────────────┐
│                      PisellLookup                          │
│                     (主容器组件)                            │
└────────────────────────────────────────────────────────────┘
                            │
        ┌───────────────────┼───────────────────┐
        │                   │                   │
        ▼                   ▼                   ▼
┌──────────────┐  ┌──────────────────┐  ┌──────────────────┐
│LookupTrigger │  │ LookupAuxiliary  │  │LookupResultHost  │
│  (触发器层)   │  │   (辅助层)       │  │  (结果承载层)     │
└──────────────┘  └──────────────────┘  └──────────────────┘
      │                    │                      │
      │                    │                      │
┌─────┴─────┐      ┌──────┴──────┐      ┌────────┴────────┐
│           │      │             │      │                 │
▼           ▼      ▼             ▼      ▼                 ▼
Input    Button  History   Suggestions  Inline         Modal
Icon     Text    HotWords               Popup          Drawer
Custom                                  Detached
```

### 8.2 数据流转图

```
┌──────────┐
│   User   │
│  (用户)   │
└──────────┘
     │
     │ 触发动作 (点击/输入)
     ▼
┌──────────────────────────────────────┐
│        LookupTrigger                 │
│     (触发器，捕获事件)                │
└──────────────────────────────────────┘
     │
     │ 打开搜索 / 输入关键词
     ▼
┌──────────────────────────────────────┐
│     PisellLookup (主组件)            │
│   • 管理 visible 状态                │
│   • 管理 keyword 状态                │
│   • 管理搜索历史                     │
└──────────────────────────────────────┘
     │
     │ 触发回调
     ▼
┌──────────────────────────────────────┐
│      外部业务层                       │
│   • onSearch(keyword)                │
│   • onLoadSuggestions(keyword)       │
│   • onLoadHotWords()                 │
└──────────────────────────────────────┘
     │
     │ 返回数据
     ▼
┌──────────────────────────────────────┐
│     resultRender(keyword)            │
│   (外部注入的结果渲染函数)            │
└──────────────────────────────────────┘
     │
     │ 渲染结果
     ▼
┌──────────────────────────────────────┐
│    LookupResultHost                  │
│   (结果承载容器，展示结果)            │
└──────────────────────────────────────┘
```

### 8.3 状态流转图

```
┌─────────┐
│  Idle   │ ← 组件初始化
│ (空闲)  │
└─────────┘
     │
     │ 点击触发器 / 输入框聚焦
     ▼
┌─────────┐
│ Active  │ ← 显示辅助信息 (历史/热词)
│ (激活)  │
└─────────┘
     │
     │ 输入关键词
     ▼
┌──────────┐
│Searching │ ← 触发 onSearch 回调
│ (搜索中) │    显示 loading 状态
└──────────┘
     │
     │ 回调完成
     ▼
┌──────────┐
│ Results  │ ← 调用 resultRender 渲染结果
│ (结果)   │
└──────────┘
     │
     │ 关闭搜索
     ▼
┌─────────┐
│  Idle   │
│ (空闲)  │
└─────────┘
```

## 9. 扩展性设计

### 9.1 当前版本支持（V1.0）

- ✅ 多种触发器类型
- ✅ 多种结果承载方式
- ✅ 搜索历史、联想词、热门搜索
- ✅ 扫码功能
- ✅ 实时/确认触发模式
- ✅ 样式自定义

### 9.2 预留扩展能力（V2.0+）

- 🔮 搜索结果的筛选、排序、分组（由外部 resultRender 实现）
- 🔮 搜索结果 Tab 切换（商品/订单/客户）
- 🔮 上一条/下一条快捷导航
- 🔮 语音搜索、图片搜索
- 🔮 搜索联想词智能匹配算法
- 🔮 搜索历史云端同步
- 🔮 搜索分析与统计

### 9.3 自定义渲染能力

```
通过 render props 支持完全自定义：
- triggerRender: 自定义触发器
- historyRender: 自定义历史记录
- suggestionsRender: 自定义联想词
- hotWordsRender: 自定义热门搜索
- resultRender: 自定义搜索结果
- emptyRender: 自定义空状态
```

## 10. 开发计划

### 10.1 开发阶段划分

#### 阶段一：类型定义 & 基础框架

- [ ] 编写 TypeScript 类型定义（types.ts）
- [ ] 搭建组件主结构（PisellLookup.tsx）
- [ ] 实现基础状态管理

#### 阶段二：触发器层开发

- [ ] 实现 InputTrigger
- [ ] 实现 ButtonTrigger
- [ ] 实现 IconTrigger
- [ ] 实现 TextTrigger
- [ ] 实现 CustomTrigger
- [ ] 实现触发器智能判断逻辑

#### 阶段三：辅助层开发

- [ ] 实现搜索历史功能
- [ ] 实现联想词功能
- [ ] 实现热门搜索功能
- [ ] 实现 localStorage 工具函数

#### 阶段四：结果承载层开发

- [ ] 实现 InlineHost
- [ ] 实现 PopupHost
- [ ] 实现 ModalHost
- [ ] 实现 DrawerHost
- [ ] 实现 DetachedHost

#### 阶段五：扫码功能集成

- [x] ✅ 集成 PisellQRScanner
- [x] ✅ 实现扫码结果自动填入
- [x] ✅ 实现扫码触发搜索

#### 阶段六：样式开发

- [ ] 编写 Less 样式文件
- [ ] 适配 Ant Design 主题
- [ ] 实现响应式布局
- [ ] 支持样式自定义

#### 阶段七：测试 & 文档

- [ ] 编写单元测试
- [ ] 编写 Storybook 示例
- [ ] 编写使用文档
- [ ] 编写 LowCode Meta

### 10.2 关键里程碑

- 🎯 类型定义完成
- 🎯 基础功能完成（Input + Inline）
- 🎯 完整功能完成（所有触发器 + 所有承载方式）
- 🎯 测试完成
- 🎯 发布 V1.0

## 11. 风险点与注意事项

### 11.1 技术风险

1. **扫码组件集成**：需要确认 PisellQRScanner/PisellScan 的 API 是否支持
2. **Modal/Drawer 内的输入框自动聚焦**：需要处理 Ant Design Modal 的 focus 逻辑
3. **Popup 定位**：输入框下方浮层定位可能在某些场景下出现遮挡

### 11.2 兼容性风险

1. **localStorage 兼容性**：需要处理 localStorage 不可用的情况
2. **移动端键盘**：需要处理移动端键盘弹出导致的布局问题
3. **浏览器差异**：需要测试不同浏览器的兼容性

### 11.3 性能风险

1. **搜索频率过高**：需要合理设置防抖时间
2. **历史记录过多**：需要限制历史记录数量
3. **结果渲染性能**：结果渲染由外部负责，需要在文档中提醒性能优化

### 11.4 开发注意事项

1. **受控 vs 非受控**：明确支持受控和非受控两种模式
2. **事件冒泡**：注意处理点击事件冒泡，避免误触发
3. **内存泄漏**：注意清理定时器、监听器
4. **可访问性**：确保键盘导航和屏幕阅读器支持
5. **类型安全**：严格的 TypeScript 类型检查

## 12. 总结

PisellLookup 是一个**高度解耦、灵活可扩展**的搜索交互协议组件：

- ✅ **职责清晰**：只负责交互，不负责业务
- ✅ **灵活适配**：通过 resultRender 适配任意业务场景
- ✅ **易于使用**：拖拽即用，配置驱动
- ✅ **可扩展性强**：支持多种自定义渲染
- ✅ **性能优良**：防抖优化、组件缓存
- ✅ **低代码友好**：可视化配置，无需编码

通过这种设计，我们可以在保证统一用户体验的同时，最大化组件的复用性和灵活性。
