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

# PisellProcedure 开发文档

## 1. 组件基本信息

### 1.1 组件名称

- **中文名称**：流程容器
- **英文名称**：PisellProcedure
- **组件编号**：pcp_de_procedure_V1.0

### 1.2 组件版本

- **当前版本**：1.0.0
- **更新日期**：2025-12-11
- **版本说明**：首次发布

### 1.3 组件分类

- **类型**：Pro Components
- **分类**：Data Entry（数据录入）
- **依赖**：PisellLayout、PisellSteps、PisellModal、Ant Design Button/Dropdown

## 2. 组件描述

PisellProcedure 是一个用于管理多步骤流程的复合容器组件。它通过三段式布局（头部步骤区、主体内容区、底部操作区）引导用户完成复杂流程，如订单创建、数据配置、多步骤表单等场景。

### 2.1 核心能力

1. **步骤导航**：通过 PisellSteps 组件展示流程进度
2. **内容分区**：左右分栏布局，支持内容区与信息摘要区
3. **滚动行为**：
   - 内容区跟随整体页面滚动，不设置独立滚动条
   - 信息区使用 sticky 定位，有独立滚动条，不跟随页面滚动
4. **响应式适配**：根据屏幕宽度自动调整布局和信息区宽度
5. **操作区管理**：底部固定操作区，支持按钮溢出自动收纳
6. **移动端适配**：信息区隐藏，通过弹窗方式展示
7. **步骤控制**：支持上一步/下一步事件拦截和确认弹窗

### 2.2 适用场景

- 多步骤流程页：商品配置、下单、审批、注册引导
- 复杂表单提交：分阶段信息填写
- 电商结账流程：地址确认 → 支付方式 → 订单预览
- 配置向导：系统设置、产品配置

## 3. API 文档

### 3.1 PisellProcedureProps

#### 通用属性

| 属性           | 类型                    | 默认值 | 说明                      |
| -------------- | ----------------------- | ------ | ------------------------- |
| className      | string                  | -      | 自定义类名                |
| style          | CSSProperties           | -      | 自定义样式                |
| mode           | 'page' \| 'modal'       | 'page' | 组件使用模式              |
| showHeader     | boolean                 | true   | 是否显示头部区域          |
| showSidebar    | boolean                 | true   | 是否显示信息区            |
| showFooter     | boolean                 | true   | 是否显示底部区域          |
| defaultCurrent | number                  | 0      | 初始步骤索引（从 0 开始） |

#### 区域配置

| 属性        | 类型                 | 说明         |
| ----------- | -------------------- | ------------ |
| headerProps | ProcedureHeaderProps | 头部区域配置 |
| bodyProps   | ProcedureBodyProps   | 主体区域配置 |
| footerProps | ProcedureFooterProps | 底部区域配置 |

#### 事件回调

| 事件            | 类型                                            | 说明                                                     |
| --------------- | ----------------------------------------------- | -------------------------------------------------------- |
| onStepsChange   | (result: StepChangeResult) => void              | 步骤变化回调，返回 { success, currentStep, currentItem } |
| onPrev          | (current: number) => boolean \| void            | 上一步事件回调，返回 false 可阻止步骤更新                |
| onNext          | (current: number) => boolean \| void            | 下一步事件回调，返回 false 可阻止步骤更新                |
| onFirstStepBack | () => void                                      | 首步返回按钮点击回调，不传递则默认跳转首页（/）          |
| onClose         | () => void                                      | 关闭按钮点击回调                                         |
| onBackConfirm   | (action: 'cancel' \| 'ok' \| 'confirm') => void | 返回确认弹窗按钮回调                                     |
| onCloseConfirm  | (action: 'cancel' \| 'ok' \| 'confirm') => void | 关闭确认弹窗按钮回调                                     |

### 3.2 ProcedureHeaderProps（头部区域配置）

| 属性                | 类型                   | 默认值 | 说明                           |
| ------------------- | ---------------------- | ------ | ------------------------------ |
| className           | string                 | -      | 自定义类名                     |
| style               | CSSProperties          | -      | 自定义样式                     |
| left                | ReactNode              | -      | 左侧插槽（返回按钮等）         |
| right               | ReactNode              | -      | 右侧插槽（关闭按钮等）         |
| stepsProps          | PisellStepsProps       | -      | 步骤条配置，透传给 PisellSteps |
| showBackOnFirstStep | boolean                | false  | 第一步时是否显示返回按钮       |
| backConfirmModal    | BackConfirmModalConfig | -      | 返回确认弹窗配置               |
| closeConfirmModal   | BackConfirmModalConfig | -      | 关闭确认弹窗配置               |

### 3.3 ProcedureBodyProps（主体区域配置）

| 属性             | 类型                       | 默认值       | 说明                      |
| ---------------- | -------------------------- | ------------ | ------------------------- |
| className        | string                     | -            | 自定义类名                |
| style            | CSSProperties              | -            | 自定义样式                |
| direction        | 'horizontal' \| 'vertical' | 'horizontal' | 排列方向（横向/纵向）     |
| layoutMode       | 'fixed' \| 'ratio'         | 'fixed'      | 布局模式                  |
| layoutRatio      | string                     | '7:3'        | 比例配置（仅 ratio 模式） |
| contentSlot      | ReactNode                  | -            | 内容区插槽                |
| contentClassName | string                     | -            | 内容区类名                |
| contentStyle     | CSSProperties              | -            | 内容区样式                |
| sidebarSlot      | ReactNode                  | -            | 信息区插槽                |
| sidebarClassName | string                     | -            | 信息区类名                |
| sidebarStyle     | CSSProperties              | -            | 信息区样式                |

### 3.4 ProcedureFooterProps（底部区域配置）

| 属性              | 类型               | 默认值          | 说明             |
| ----------------- | ------------------ | --------------- | ---------------- |
| className         | string             | -               | 自定义类名       |
| style             | CSSProperties      | -               | 自定义样式       |
| leftSlot          | ReactNode          | -               | 左侧插槽         |
| summaryButton     | ReactNode          | -               | 移动端总结按钮   |
| actions           | ReactNode          | -               | 右侧操作按钮组   |
| position          | FooterPositionMode | 'float-sidebar' | 底部位置模式     |
| enableOverflow    | boolean            | true            | 是否启用溢出收纳 |
| moreText          | string             | 'More'          | More 按钮文案    |
| summaryModalTitle | string             | '详情'          | 移动端弹窗标题   |

### 3.5 BackConfirmModalConfig（确认弹窗配置）

| 属性     | 类型    | 默认值 | 说明                   |
| -------- | ------- | ------ | ---------------------- |
| enabled  | boolean | true   | 是否启用确认弹窗       |
| title    | string  | -      | 弹窗标题（支持多语言） |
| describe | string  | -      | 弹窗描述内容           |
| footer   | array   | -      | 弹窗底部按钮配置数组   |

**footer 按钮配置：**

```typescript
{
  text: string;      // 按钮文本
  type?: 'primary' | 'default' | 'dashed' | 'link' | 'text';
  onClick?: () => void;  // 自定义点击回调
}
```

## 4. 使用示例

### 4.1 基础用法

```
import { PisellProcedure } from '@pisell/materials';
import { Button } from 'antd';
import { ArrowLeftOutlined, CloseOutlined } from '@ant-design/icons';

function App() {
  return (
    <PisellProcedure
      defaultCurrent={0}
      headerProps={{
        left: <Button icon={<ArrowLeftOutlined />}>返回</Button>,
        right: <Button icon={<CloseOutlined />}>关闭</Button>,
        stepsProps: {
          items: [
            { title: '第一步', description: '基础信息' },
            { title: '第二步', description: '详细配置' },
            { title: '第三步', description: '确认提交' },
          ],
        },
      }}
      bodyProps={{
        contentSlot: <div>主要内容区域</div>,
        sidebarSlot: <div>信息摘要区域</div>,
      }}
      footerProps={{
        leftSlot: <div>总价：¥100</div>,
        summaryButton: <Button icon={<ShoppingCartOutlined />} shape="circle" />,
        actions: (
          <>
            <Button data-action="prev">上一步</Button>
            <Button type="primary">下一步</Button>
          </>
        ),
      }}
      onStepsChange={(result) => {
        console.log('步骤变化:', result.currentStep, result.currentItem);
      }}
      onClose={() => {
        console.log('关闭流程');
      }}
    />
  );
}
```

### 4.2 启用确认弹窗

```
<PisellProcedure
  headerProps={{
    // 返回确认弹窗（默认启用）
    backConfirmModal: {
      enabled: true,
      title: '确认返回',
      describe: '确定要返回上一步吗？当前填写的内容将不会保存',
      footer: [
        { text: '取消', action: 'cancel' },
        { text: '确认返回', type: 'primary', action: 'confirm' },
      ],
    },
    // 关闭确认弹窗
    closeConfirmModal: {
      enabled: true,
      title: '确认关闭',
      describe: '确定要关闭吗？所有未保存的数据将丢失',
      footer: [
        { text: '继续编辑', action: 'cancel' },
        { text: '确认关闭', type: 'primary', action: 'confirm' },
      ],
    },
  }}
  onBackConfirm={(action) => {
    console.log('返回确认:', action);
    if (action === 'confirm') {
      // 用户点击了"确认返回"，可以清除当前步骤数据
    }
  }}
  onCloseConfirm={(action) => {
    console.log('关闭确认:', action);
  }}
/>
```

### 4.3 步骤验证拦截

```
<PisellProcedure
  onPrev={(current) => {
    console.log('准备返回上一步，当前步骤:', current);
    // 可以在这里进行验证，返回 false 阻止步骤更新
    if (hasUnsavedData()) {
      message.warning('请先保存当前数据');
      return false;
    }
  }}
  onNext={(current) => {
    console.log('准备进入下一步，当前步骤:', current);
    // 可以在这里进行验证，返回 false 阻止步骤更新
    if (!validateCurrentStep()) {
      message.error('请填写必填项');
      return false;
    }
  }}
/>
```

### 4.4 首步返回自定义

```
<PisellProcedure
  headerProps={{
    showBackOnFirstStep: true,  // 第一步显示返回按钮
  }}
  onFirstStepBack={() => {
    // 自定义首步返回逻辑
    router.push('/home');
  }}
/>
```

### 4.5 比例布局模式

```
<PisellProcedure
  bodyProps={{
    layoutMode: 'ratio',  // 使用比例模式
    layoutRatio: '7:3',   // 内容区 70%，信息区 30%
    contentSlot: <div>内容区</div>,
    sidebarSlot: <div>信息区</div>,
  }}
/>
```

### 4.6 纵向排列模式

```
<PisellProcedure
  bodyProps={{
    direction: 'vertical',  // 纵向排列（上下布局）
    contentSlot: <div>内容区（上方）</div>,
    sidebarSlot: <div>信息区（下方）</div>,
  }}
/>
```

### 4.7 自定义底部位置

```
<PisellProcedure
  footerProps={{
    position: 'fixed-bottom',  // 固定在整体底部
    leftSlot: <div>总价：¥100</div>,
    actions: (
      <>
        <Button>保存草稿</Button>
        <Button data-action="prev">上一步</Button>
        <Button type="primary">下一步</Button>
      </>
    ),
  }}
/>
```

### 4.8 弹窗模式

```
<Modal open={open} onCancel={() => setOpen(false)} width={800} footer={null}>
  <PisellProcedure
    mode="modal"  // 弹窗模式，禁用移动端响应式
    headerProps={{
      stepsProps: {
        items: [{ title: '步骤1' }, { title: '步骤2' }],
      },
    }}
    bodyProps={{
      contentSlot: <div>内容区域</div>,
      sidebarSlot: <div>信息区域</div>,
    }}
  />
</Modal>
```

### 4.9 通过 Ref 调用方法

```
import { PisellProcedure, PisellProcedureRef } from '@pisell/materials';
import { useRef } from 'react';

function App() {
  const procedureRef = useRef<PisellProcedureRef>(null);

  const handleExternalControl = () => {
    // 跳转到下一步
    const result = procedureRef.current?.goNext();
    console.log('跳转结果:', result);

    // 获取当前步骤
    const currentStep = procedureRef.current?.getCurrentStep();
    console.log('当前步骤:', currentStep);

    // 跳转到指定步骤
    procedureRef.current?.goToStep(0);

    // 打开/关闭总结弹窗
    procedureRef.current?.openSummaryModal();
    procedureRef.current?.closeSummaryModal();
  };

  return (
    <PisellProcedure
      ref={procedureRef}
      headerProps={{
        stepsProps: {
          items: [{ title: '步骤1' }, { title: '步骤2' }],
        },
      }}
    />
  );
}
```

## 5. 类型定义

### 5.1 StepItem（步骤项）

```typescript
interface StepItem {
  index?: number;
  title?: ReactNode;
  description?: ReactNode;
  [key: string]: any;
}
```

### 5.2 StepChangeResult（步骤变化结果）

```typescript
interface StepChangeResult {
  success: boolean; // 是否成功
  currentStep: number; // 当前步骤索引
  currentItem: StepItem | null; // 当前步骤数据
}
```

### 5.3 BackConfirmModalConfig（确认弹窗配置）

```typescript
interface BackConfirmModalConfig {
  enabled?: boolean; // 是否启用
  title?: string; // 弹窗标题
  describe?: string; // 弹窗描述
  footer?: Array<{
    // 底部按钮配置
    text?: string;
    type?: 'primary' | 'default' | 'dashed' | 'link' | 'text';
    action?: 'confirm' | 'cancel';
    onClick?: () => void;
  }>;
}
```

### 5.4 FooterPositionMode（底部位置模式）

```typescript
type FooterPositionMode =
  | 'fixed-bottom' // 固定在整体底部
  | 'fixed-content-bottom' // 内嵌在 content 区域底部
  | 'fixed-sidebar-bottom' // 内嵌在 sidebar 区域底部
  | 'float-all' // 悬浮在整体区域
  | 'float-content' // 悬浮在 content 区域
  | 'float-sidebar'; // 悬浮在 sidebar 区域（默认）
```

### 5.5 BodyLayoutMode（布局模式）

```typescript
type BodyLayoutMode = 'fixed' | 'ratio';
```

### 5.6 BodyLayoutRatio（布局比例）

```typescript
type BodyLayoutRatio = `${number}:${number}`;
// 示例：'7:3' | '6:4'
```

### 5.7 ProcedureMode（组件模式）

```typescript
type ProcedureMode = 'page' | 'modal';
// 'page' - 页面模式（默认），应用移动端响应式
// 'modal' - 弹窗模式，禁用移动端响应式行为
```

### 5.8 PisellProcedureRef（Ref 方法）

```typescript
interface PisellProcedureRef {
  /** 跳转到上一步 */
  goPrev: () => StepChangeResult | null;
  /** 跳转到下一步 */
  goNext: () => StepChangeResult | null;
  /** 跳转到指定步骤 */
  goToStep: (step: number) => StepChangeResult | null;
  /** 获取当前步骤索引 */
  getCurrentStep: () => number;
  /** 打开移动端总结弹窗 */
  openSummaryModal: () => void;
  /** 关闭移动端总结弹窗 */
  closeSummaryModal: () => void;
}
```

## 6. 事件详解

### 6.1 onStepsChange（步骤变化）

**触发时机**：步骤更新后

**参数**：

```typescript
{
  success: boolean; // 是否成功
  currentStep: number; // 当前步骤索引
  currentItem: StepItem | null; // 当前步骤数据
}
```

**示例**：

```
onStepsChange={(result) => {
  console.log('步骤变化:', result.currentStep);
  console.log('当前步骤数据:', result.currentItem);
}}
```

### 6.2 onPrev / onNext（步骤控制）

**触发时机**：步骤更新之前

**参数**：`current: number` - 当前步骤索引

**返回值**：`boolean | void` - 返回 false 可阻止步骤更新

**示例**：

```
onPrev={(current) => {
  console.log('准备返回，当前步骤:', current);
  if (!confirmBack()) {
    return false;  // 阻止返回
  }
}}

onNext={(current) => {
  console.log('准备前进，当前步骤:', current);
  if (!validateStep(current)) {
    message.error('请完成必填项');
    return false;  // 阻止前进
  }
}}
```

### 6.3 onFirstStepBack（首步返回）

**触发时机**：第一步且显示返回按钮时点击

**参数**：无

**说明**：如果不传递，默认跳转到首页（/）

**示例**：

```
onFirstStepBack={() => {
  router.push('/dashboard');
}}
```

### 6.4 onBackConfirm / onCloseConfirm（确认弹窗）

**触发时机**：点击确认弹窗的按钮

**参数**：`action: 'cancel' | 'ok' | 'confirm'`

- `'cancel'` - 点击取消/清除按钮
- `'ok'` / `'confirm'` - 点击确认/保留按钮

**示例**：

```
onBackConfirm={(action) => {
  if (action === 'confirm') {
    console.log('用户点击了确认返回');
    clearCurrentStepData();  // 清除数据
  }
}}

onCloseConfirm={(action) => {
  if (action === 'confirm') {
    console.log('用户确认关闭');
    router.push('/home');
  }
}}
```

## 7. 步骤导航机制

### 7.1 步骤条点击

**功能**：点击头部步骤条可以直接跳转到指定步骤

**处理逻辑**：

- 步骤条点击和返回按钮点击统一走 `handleBackClick` 方法
- 步骤条点击传递步骤索引参数：`handleBackClick(step)`
- 返回按钮点击不传参数：`handleBackClick()`
- 根据参数区分是步骤跳转（`step >= 0`）还是返回上一步（`step < 0`）

**确认弹窗**：

- 如果启用了 `backConfirmModal.enabled`，会先显示确认弹窗
- 确认后根据保存的目标步骤决定调用 `goToStep(step)` 还是 `goPrev()`
- 步骤跳转和返回上一步使用同一个确认弹窗配置

**示例**：

```
<PisellProcedure
  headerProps={{
    stepsProps: {
      clickable: true,
      items: [
        { title: '第一步' },
        { title: '第二步' },
        { title: '第三步' },
      ],
    },
    backConfirmModal: {
      enabled: true,
      title: '确认跳转',
      describe: '确定要跳转到该步骤吗？',
    },
  }}
  onStepsChange={(result) => {
    console.log('跳转到步骤:', result.currentStep);
  }}
/>
```

### 7.2 底部按钮事件注入

组件会自动为底部按钮注入步骤控制事件：

1. **最后一个按钮**：默认触发下一步（goNext）
2. **data-action="prev"**：触发上一步（goPrev）
3. **data-action="next"**：触发下一步（goNext）

### 7.3 底部按钮示例

```
<PisellProcedure
  footerProps={{
    actions: (
      <>
        <Button data-action="prev">上一步</Button>
        <Button onClick={() => saveDraft()}>保存草稿</Button>
        <Button type="primary">下一步</Button>  {/* 最后一个，自动触发 goNext */}
      </>
    ),
  }}
/>
```

### 7.4 显式指定底部按钮 action

```
<Button data-action="next">提交</Button>  {/* 显式指定触发下一步 */}
```

## 8. 响应式设计

### 8.1 信息区自适应

| 屏幕宽度    | 信息区宽度 | 说明       |
| ----------- | ---------- | ---------- |
| ≥1366px     | 405px      | 标准布局   |
| 1133-1366px | 405px      | -          |
| 960-1133px  | 376px      | -          |
| 744-960px   | 290px      | -          |
| <744px      | 隐藏       | 移动端模式 |

### 8.2 移动端适配

**< 744px 时：**

- 信息区（sidebar）隐藏
- 显示移动端总结按钮（summaryButton）
- 点击总结按钮打开 PisellModal 展示信息区内容
- **底部操作区自动改为吸底悬浮模式**（`position: 'float-all'`）
  - 固定在屏幕底部（`position: fixed`）
  - 带顶部阴影效果
  - 无视用户配置的 `footerProps.position` 参数
- 主体内容区自动添加底部内边距，避免内容被操作区遮挡

**示例：**

```
<PisellProcedure
  bodyProps={{
    sidebarSlot: <OrderSummary />,
  }}
  footerProps={{
    summaryButton: <Button icon={<ShoppingCartOutlined />} shape="circle" />,
    summaryModalTitle: '订单摘要',
  }}
/>
```

## 9. 最佳实践

### 9.1 步骤管理

```
function MyProcedure() {
  const [stepData, setStepData] = useState({});

  return (
    <PisellProcedure
      defaultCurrent={0}
      onStepsChange={(result) => {
        console.log('步骤变化:', result);
      }}
      onNext={(current) => {
        // 步骤前进前验证
        const valid = validateStep(current);
        if (!valid) {
          message.error('请完成必填项');
          return false;
        }
      }}
    />
  );
}
```

### 9.2 数据流管理

```
function OrderProcedure() {
  const [orderData, setOrderData] = useState({});

  return (
    <PisellProcedure
      bodyProps={{
        contentSlot: (
          <OrderForm
            data={orderData}
            onChange={setOrderData}
          />
        ),
        sidebarSlot: (
          <OrderSummary data={orderData} />
        ),
      }}
      onBackConfirm={(action) => {
        if (action === 'confirm') {
          // 用户选择清除数据
          setOrderData({});
        }
      }}
    />
  );
}
```

### 9.3 完整示例

```
import { PisellProcedure } from '@pisell/materials';
import { Button, message } from 'antd';

function CompleteExample() {
  return (
    <PisellProcedure
      defaultCurrent={0}
      showHeader={true}
      showSidebar={true}
      showFooter={true}

      // 头部配置
      headerProps={{
        left: <Button icon={<ArrowLeftOutlined />}>返回</Button>,
        right: <Button icon={<CloseOutlined />}>关闭</Button>,
        stepsProps: {
          items: [
            { title: '基础信息', description: '填写基本信息' },
            { title: '详细配置', description: '完善详细配置' },
            { title: '确认提交', description: '确认并提交' },
          ],
        },
        showBackOnFirstStep: false,
        backConfirmModal: {
          enabled: true,
        },
        closeConfirmModal: {
          enabled: true,
        },
      }}

      // 主体配置
      bodyProps={{
        layoutMode: 'ratio',
        layoutRatio: '7:3',
        contentSlot: <div>主要内容</div>,
        sidebarSlot: <div>信息摘要</div>,
      }}

      // 底部配置
      footerProps={{
        position: 'float-sidebar',
        leftSlot: <div>总价: ¥100</div>,
        summaryButton: <Button icon={<ShoppingCartOutlined />} shape="circle" />,
        summaryModalTitle: '订单摘要',
        actions: (
          <>
            <Button data-action="prev">上一步</Button>
            <Button onClick={() => saveDraft()}>保存草稿</Button>
            <Button type="primary">下一步</Button>
          </>
        ),
      }}

      // 事件回调
      onStepsChange={(result) => {
        console.log('步骤变化:', result);
      }}
      onPrev={(current) => {
        console.log('返回上一步，当前:', current);
        return true;
      }}
      onNext={(current) => {
        console.log('进入下一步，当前:', current);
        if (!validate(current)) {
          return false;
        }
      }}
      onFirstStepBack={() => {
        router.push('/home');
      }}
      onClose={() => {
        router.push('/dashboard');
      }}
      onBackConfirm={(action) => {
        if (action === 'confirm') {
          clearStepData();
        }
      }}
      onCloseConfirm={(action) => {
        if (action === 'confirm') {
          clearAllData();
        }
      }}
    />
  );
}
```

## 10. 注意事项

### 10.1 步骤数据管理

- 组件内部只管理 `currentStep` 状态
- 步骤数据需要外部通过 `onStepsChange` 事件管理
- 使用 `result.currentItem` 获取当前步骤配置

### 10.2 事件触发顺序

**下一步操作顺序：**

1. 触发 `onNext(current)` - 可阻止
2. 更新 `currentStep`
3. 触发 `onStepsChange(result)`

**返回操作顺序（有确认弹窗）：**

1. 显示确认弹窗
2. 用户点击按钮，触发 `onBackConfirm(action)`
3. 执行 `goPrev()` - 可被 `onPrev` 阻止
4. 更新 `currentStep`
5. 触发 `onStepsChange(result)`

### 10.3 底部按钮配置

- **不设置 data-action**：最后一个按钮自动触发下一步
- **设置 data-action="prev"**：触发上一步
- **设置 data-action="next"**：显式触发下一步
- 按钮原有的 `onClick` 会先执行，再触发步骤控制

### 10.4 确认弹窗按钮

- 弹窗按钮需要设置 `action` 字段
- `action: 'confirm'` / `'ok'` - 确认操作
- `action: 'cancel'` - 取消操作
- 点击右上角 X 只关闭弹窗，不触发回调

### 10.5 移动端总结按钮

- 只在 < 744px 时显示
- 点击打开 PisellModal 展示信息区内容
- 默认配置为购物车图标按钮
- 弹窗标题通过 `summaryModalTitle` 配置

### 10.6 首步返回逻辑

- 默认不显示首步返回按钮
- `showBackOnFirstStep: true` 时显示
- 点击触发 `onFirstStepBack` 回调
- 不传递回调时默认跳转首页（`window.location.href = '/'`）
- 首步返回不会触发返回确认弹窗

## 11. 常见问题

### Q1: 如何控制步骤不允许返回？

```
<PisellProcedure
  onPrev={() => {
    message.warning('当前步骤不允许返回');
    return false;  // 阻止返回
  }}
/>
```

### Q2: 如何在最后一步隐藏下一步按钮？

```
<PisellProcedure
  headerProps={{
    stepsProps: {
      items: steps,
    },
  }}
  footerProps={{
    actions: currentStep === steps.length - 1 ? (
      <Button type="primary" onClick={handleSubmit}>提交</Button>
    ) : (
      <>
        <Button data-action="prev">上一步</Button>
        <Button type="primary">下一步</Button>
      </>
    ),
  }}
/>
```

### Q3: 如何自定义确认弹窗的按钮？

```
<PisellProcedure
  headerProps={{
    backConfirmModal: {
      enabled: true,
      title: '自定义标题',
      describe: '自定义描述',
      footer: [
        { text: '取消', action: 'cancel' },
        { text: '确定', type: 'primary', action: 'confirm' },
      ],
    },
  }}
/>
```

### Q4: 如何禁用溢出收纳功能？

```
<PisellProcedure
  footerProps={{
    enableOverflow: false,  // 禁用溢出收纳
    actions: <>{/* 按钮 */}</>,
  }}
/>
```

### Q5: 如何在步骤条点击时拦截？

```
<PisellProcedure
  headerProps={{
    stepsProps: {
      items: steps,
      onChange: (step) => {
        // 拦截步骤条点击
        if (!validateStep(currentStep)) {
          message.error('请完成当前步骤');
          return;
        }
        // 允许跳转，由组件内部处理
      },
    },
  }}
/>
```

## 12. 组件架构

### 12.1 组件结构

```
PisellProcedure
├── ProcedureHeader（头部区域）
│   ├── left（左侧插槽）
│   ├── PisellSteps（步骤条）
│   └── right（右侧插槽）
├── ProcedureBody（主体区域）
│   ├── ProcedureContent（内容区）
│   │   ├── contentSlot（内容插槽）
│   │   └── contentFooter（底部，条件渲染）
│   └── ProcedureSidebar（信息区）
│       ├── sidebarSlot（信息插槽）
│       └── sidebarFooter（底部，条件渲染）
└── ProcedureFooter（底部操作区，条件渲染）
    ├── summaryButton（移动端总结按钮）
    ├── leftSlot（左侧插槽）
    └── actions（操作按钮组）
        ├── FooterActions（溢出收纳）
        └── More 菜单
```

### 12.2 状态管理

- **currentStep**：当前步骤索引（内部 useState）
- **summaryModalOpen**：移动端弹窗状态（内部 useState）
- **backModalType**：确认弹窗类型（Header 内部 useState）

### 12.3 数据流向

```
用户操作
  ↓
事件触发（onPrev / onNext）
  ↓
验证拦截（return false 可阻止）
  ↓
更新 currentStep
  ↓
触发 onStepsChange
  ↓
外部更新业务数据
```

## 13. 多语言支持

组件内置多语言支持，包含以下文案：

**返回确认弹窗：**

- `pisell-procedure-header-back-confirm-title` - 标题
- `pisell-procedure-header-back-confirm-desc` - 描述
- `pisell-procedure-header-back-confirm-no` - 取消按钮
- `pisell-procedure-header-back-confirm-yes` - 确认按钮

**关闭确认弹窗：**

- `pisell-procedure-header-close-confirm-title` - 标题
- `pisell-procedure-header-close-confirm-desc` - 描述
- `pisell-procedure-header-close-confirm-no` - 取消按钮
- `pisell-procedure-header-close-confirm-yes` - 确认按钮

支持语言：zh-CN、en-US、zh-TW、zh-HK

## 14. 自定义 Hooks

### 14.1 useStepManager（步骤管理）

管理步骤状态和操作的 Hook。

**接口定义：**

```typescript
interface UseStepManagerOptions {
  stepsProps?: PisellStepsProps;
  defaultCurrent?: number;
  onPrev?: (current: number) => boolean | void;
  onNext?: (current: number) => boolean | void;
  onStepsChange?: (result: StepChangeResult) => void;
}

interface UseStepManagerReturn {
  currentStep: number;
  items: any[];
  totalSteps: number;
  goPrev: () => StepChangeResult | null;
  goNext: () => StepChangeResult | null;
}
```

**使用示例：**

```typescript
const { currentStep, goPrev, goNext } = useStepManager({
  stepsProps: headerProps?.stepsProps,
  defaultCurrent: 0,
  onPrev: (current) => {
    console.log('上一步前', current);
    return validateStep(current);
  },
  onNext: (current) => {
    console.log('下一步前', current);
    return validateStep(current);
  },
  onStepsChange: (result) => {
    console.log('步骤变化', result);
  },
});
```

**返回值说明：**

- `goPrev()` / `goNext()` 返回 `StepChangeResult | null`
  - 返回 `StepChangeResult` - 步骤更新成功
  - 返回 `null` - 步骤未更新（已是边界或被拦截）

### 14.2 useMobile（移动端检测）

检测是否是移动端的 Hook（从 `@pisell/materials/hooks` 导入）。

**使用示例：**

```typescript
// 无条件调用 Hook（遵循 React Hooks 规则）
const isMobileDetected = useMobile(744);
// 弹窗模式下始终返回 false，忽略移动端检测结果
const isMobile = mode === 'modal' ? false : isMobileDetected;

// 移动端强制使用 float-all 模式
const footerPosition = useMemo(() => {
  if (isMobile) return 'float-all';
  return footerProps?.position || 'float-sidebar';
}, [isMobile, footerProps?.position]);
```

**注意事项：**

- 在弹窗模式（`mode="modal"`）下，`isMobile` 始终返回 `false`
- 确保无条件调用 Hook，然后在使用结果时进行条件判断

### 14.3 useElementHeight（元素高度计算）

计算指定元素高度的 Hook，用于动态计算信息区的最大高度。

**接口定义：**

```typescript
interface UseElementHeightOptions {
  selector: string; // 元素选择器（类名、ID 或其他 CSS 选择器）
  enabled?: boolean; // 是否启用监听（默认 true）
  defaultHeight?: number; // 默认高度（元素不存在时使用，默认 0）
}

const height: number = useElementHeight(options);
```

**使用示例：**

```typescript
// 计算 header 高度
const headerHeight = useElementHeight({
  selector: '.pisell-procedure-header',
  defaultHeight: 64,
});

// 计算 footer 高度（仅在 float-all 模式下）
const footerHeight = useElementHeight({
  selector: '.pisell-procedure-footer--float-all',
  enabled: footerIsGlobal,
  defaultHeight: 0,
});

// 计算信息区高度：视口高度 - header高度 - footer高度 - body padding
const siderHeight = useMemo(() => {
  if (typeof window === 'undefined') return undefined;
  const viewportHeight = window.innerHeight;
  const bodyPadding = 16 * 2; // 上下各16px
  const calculatedHeight =
    viewportHeight - headerHeight - footerHeight - bodyPadding - 1;
  return calculatedHeight > 0 ? calculatedHeight : undefined;
}, [headerHeight, footerHeight]);
```

**特性：**

- 自动监听窗口大小变化（resize 事件）
- 自动监听 DOM 变化（MutationObserver）
- 返回元素的实际高度（使用 `offsetHeight`，包含 padding、border、滚动条）

## 15. 布局和滚动行为

### 15.1 主体区域布局

- **主体区域**：使用 `height: 100%` 填满父容器
- **内部 Layout**：使用 `align-items: stretch` 让子元素拉伸填满高度
- **内容区**：跟随整体页面滚动，不设置独立滚动条
- **信息区**：使用 `position: sticky` 定位，有独立滚动条

### 15.2 信息区滚动机制

**信息区定位：**

- 使用 `position: sticky` 和 `top` 属性固定在视口顶部
- 高度通过 `useElementHeight` Hook 动态计算
- 计算公式：`视口高度 - header高度 - footer高度 - body padding - 1px`

**信息区滚动：**

- 信息区容器设置 `overflow: hidden`
- 信息区内容区域（`.pisell-procedure-sider-content-top`）设置 `overflow-y: auto`
- 当内容超出信息区高度时，在信息区内滚动，不跟随整体页面滚动

**内容区滚动：**

- 内容区不设置 `overflow`，跟随整体页面滚动
- 内容高度由内容自然撑开，不限制最大高度
- 当内容超出视口时，通过整体页面滚动查看

### 15.3 高度计算

信息区高度通过 `useElementHeight` Hook 动态计算：

```typescript
// 获取 header 和 footer 高度
const headerHeight = useElementHeight({
  selector: '.pisell-procedure-header',
});

const footerHeight = useElementHeight({
  selector: '.pisell-procedure-footer--float-all',
  enabled: footerIsGlobal,
});

// 计算信息区高度
const siderHeight = useMemo(() => {
  if (typeof window === 'undefined') return undefined;
  const viewportHeight = window.innerHeight;
  const bodyPadding = 16 * 2; // 上下各16px
  const calculatedHeight =
    viewportHeight - headerHeight - footerHeight - bodyPadding - 1;
  return calculatedHeight > 0 ? calculatedHeight : undefined;
}, [headerHeight, footerHeight]);
```

## 16. 性能优化

- 使用 `useMemo` 缓存样式和配置对象
- 使用 `useCallback` 缓存事件处理函数
- 避免不必要的组件重渲染
- 底部按钮溢出采用动态计算，避免固定配置
- 移动端检测使用防抖优化（通过 resize 事件）
- `useElementHeight` Hook 自动监听窗口大小和 DOM 变化，确保高度计算准确

## 17. 浏览器兼容性

- Chrome ≥ 90
- Safari ≥ 14
- Firefox ≥ 88
- Edge ≥ 90

**注意：** `position: sticky` 需要浏览器支持，现代浏览器均已支持。

## 18. 相关组件

- PisellLayout - 布局组件
- PisellSteps - 步骤条组件
- PisellModal - 弹窗组件
- PisellHeader - 头部组件
- PisellFooter - 底部组件
