---
nav:
  title: 组件
  order: 1
group:
  title: Data Entry
  order: 2
title: Pisell Procedure
order: 1
category: pro
---

# PisellProcedure 流程容器

用于管理多步骤流程的复合容器组件。

## 何时使用

- 需要引导用户完成多步骤流程时（如订单创建、用户注册、产品配置）
- 需要在流程中实时展示信息摘要或预览效果
- 需要固定底部操作区，确保主要动作始终可访问
- 需要响应式适配，支持 PC 端和移动端

## 代码演示

### 基础用法

最简单的用法，包含步骤条、内容区、信息区和操作按钮。

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

export default () => {
  return (
    <PisellProcedure
      headerProps={{
        left: <Button icon={<ArrowLeftOutlined />}>返回</Button>,
        right: <Button icon={<CloseOutlined />}>关闭</Button>,
        stepsProps: {
          items: [
            { title: '第一步', description: '基础信息' },
            { title: '第二步', description: '详细配置' },
            { title: '第三步', description: '确认提交' },
          ],
        },
      }}
      bodyProps={{
        contentSlot: <div style={{ padding: 24 }}>主要内容区域</div>,
        sidebarSlot: <div style={{ padding: 24 }}>信息摘要区域</div>,
      }}
      footerProps={{
        actions: <Button type="primary">下一步</Button>,
      }}
    />
  );
};
```

### 步骤控制

通过事件回调管理步骤状态，支持步骤验证和拦截。

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

const validateBasicInfo = () => {
  /* 在此实现基础信息校验，返回 true 表示通过 */
  return true;
};

export default () => {
  const [currentStep, setCurrentStep] = useState(0);

  return (
    <PisellProcedure
      defaultCurrent={currentStep}
      headerProps={{
        stepsProps: {
          items: [
            { title: '基础信息' },
            { title: '详细配置' },
            { title: '确认提交' },
          ],
        },
      }}
      footerProps={{
        actions: (
          <>
            <Button data-action="prev" disabled={currentStep === 0}>
              上一步
            </Button>
            <Button type="primary">
              {currentStep === 2 ? '提交' : '下一步'}
            </Button>
          </>
        ),
      }}
      onStepsChange={(result) => {
        console.log('步骤变化:', result);
        setCurrentStep(result.currentStep);
      }}
      onNext={(current) => {
        // 步骤验证
        if (current === 0 && !validateBasicInfo()) {
          message.error('请完成基础信息填写');
          return false;
        }
      }}
      onPrev={(current) => {
        console.log('返回上一步，当前步骤:', current);
      }}
    />
  );
};
```

### 确认弹窗

支持返回和关闭确认弹窗，避免误操作。

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

export default () => {
  return (
    <PisellProcedure
      headerProps={{
        left: <Button>返回</Button>,
        right: <Button>关闭</Button>,
        stepsProps: {
          items: [{ title: '步骤1' }, { title: '步骤2' }, { title: '步骤3' }],
        },
        // 返回确认弹窗（默认启用）
        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);
      }}
    />
  );
};
```

### 比例布局

支持固定宽度和比例两种布局模式。

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

export default () => {
  return (
    <PisellProcedure
      bodyProps={{
        layoutMode: 'ratio', // 比例模式
        layoutRatio: '7:3', // 内容区 70%，信息区 30%
        contentSlot: <div>内容区（70%）</div>,
        sidebarSlot: <div>信息区（30%）</div>,
      }}
    />
  );
};
```

### 纵向排列

支持内容区和信息区纵向排列（上下布局）。

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

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

### 自定义底部位置

支持多种底部操作区位置模式。

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

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

### 移动端适配

小于 744px 时，信息区隐藏，通过总结按钮打开弹窗展示。底部操作区自动改为吸底悬浮模式。

```tsx
import { PisellProcedure } from '@pisell/materials';
import { Button } from 'antd';
import { ShoppingCartOutlined } from '@ant-design/icons';

export default () => {
  return (
    <PisellProcedure
      bodyProps={{
        sidebarSlot: (
          <div>
            <h3>订单摘要</h3>
            <p>商品总额：¥100</p>
            <p>运费：¥10</p>
            <p>总计：¥110</p>
          </div>
        ),
      }}
      footerProps={{
        summaryButton: (
          <Button icon={<ShoppingCartOutlined />} shape="circle" />
        ),
        summaryModalTitle: '订单摘要',
        actions: <Button type="primary">提交订单</Button>,
        // PC 端可以配置 position，移动端会自动改为 'float-all'
        position: 'float-sidebar',
      }}
    />
  );
};
```

**移动端特性：**

- 信息区自动隐藏
- 底部操作区自动改为 `position: 'float-all'`（吸底悬浮）
- 显示总结按钮（购物车图标）
- 内容区自动添加底部内边距，避免被操作区遮挡

### 弹窗模式

在弹窗中使用 PisellProcedure 时，设置 `mode="modal"` 可禁用移动端响应式行为。

```tsx
import { PisellProcedure } from '@pisell/materials';
import { Modal, Button } from 'antd';
import { useState } from 'react';

export default () => {
  const [open, setOpen] = useState(false);

  return (
    <>
      <Button onClick={() => setOpen(true)}>打开弹窗</Button>
      <Modal
        open={open}
        onCancel={() => setOpen(false)}
        width={800}
        footer={null}
      >
        <PisellProcedure
          mode="modal"
          headerProps={{
            stepsProps: {
              items: [
                { title: '步骤1' },
                { title: '步骤2' },
                { title: '步骤3' },
              ],
            },
          }}
          bodyProps={{
            contentSlot: <div>内容区域</div>,
            sidebarSlot: <div>信息区域</div>,
          }}
          footerProps={{
            actions: <Button type="primary">下一步</Button>,
          }}
        />
      </Modal>
    </>
  );
};
```

**弹窗模式特性：**

- 不应用移动端响应式模式
- 不隐藏信息区
- 不自动改为吸底悬浮底部
- 不显示移动端总结按钮
- 不执行媒体查询响应式类名

### 通过 Ref 调用方法

可以通过 `ref` 获取组件实例，调用内部方法进行步骤控制。

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

export default () => {
  const procedureRef = useRef<PisellProcedureRef>(null);

  const handleNext = () => {
    const result = procedureRef.current?.goNext();
    console.log('跳转结果:', result);
  };

  const handlePrev = () => {
    procedureRef.current?.goPrev();
  };

  const handleGoToStep = (step: number) => {
    procedureRef.current?.goToStep(step);
  };

  const getCurrentStep = () => {
    const step = procedureRef.current?.getCurrentStep();
    console.log('当前步骤:', step);
  };

  return (
    <>
      <div style={{ marginBottom: 16 }}>
        <Button onClick={handlePrev}>上一步</Button>
        <Button onClick={handleNext}>下一步</Button>
        <Button onClick={() => handleGoToStep(0)}>跳转到第一步</Button>
        <Button onClick={getCurrentStep}>获取当前步骤</Button>
      </div>
      <PisellProcedure
        ref={procedureRef}
        headerProps={{
          stepsProps: {
            items: [{ title: '步骤1' }, { title: '步骤2' }, { title: '步骤3' }],
          },
        }}
        bodyProps={{
          contentSlot: <div>内容区域</div>,
        }}
      />
    </>
  );
};
```

## API

### PisellProcedureProps

| 参数            | 说明                              | 类型                                 | 默认值 |
| --------------- | --------------------------------- | ------------------------------------ | ------ |
| className       | 自定义类名                        | string                               | -      |
| style           | 自定义样式                        | CSSProperties                        | -      |
| mode            | 组件使用模式                      | 'page' \| 'modal'                    | 'page' |
| showHeader      | 是否显示头部区域                  | boolean                              | true   |
| showSidebar     | 是否显示信息区                    | boolean                              | true   |
| showFooter      | 是否显示底部区域                  | boolean                              | true   |
| defaultCurrent  | 初始步骤索引（从 0 开始）         | number                               | 0      |
| headerProps     | 头部区域配置                      | ProcedureHeaderProps                 | -      |
| bodyProps       | 主体区域配置                      | ProcedureBodyProps                   | -      |
| footerProps     | 底部区域配置                      | ProcedureFooterProps                 | -      |
| onStepsChange   | 步骤变化回调                      | (result: StepChangeResult) => void   | -      |
| onPrev          | 上一步事件回调，返回 false 可阻止 | (current: number) => boolean \| void | -      |
| onNext          | 下一步事件回调，返回 false 可阻止 | (current: number) => boolean \| void | -      |
| onFirstStepBack | 首步返回回调，不传递则跳转首页    | () => void                           | -      |
| onClose         | 关闭按钮点击回调                  | () => void                           | -      |
| onBackConfirm   | 返回确认弹窗按钮回调              | (action) => void                     | -      |
| onCloseConfirm  | 关闭确认弹窗按钮回调              | (action) => void                     | -      |

### ProcedureHeaderProps

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

### ProcedureBodyProps

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

### ProcedureFooterProps

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

### BackConfirmModalConfig

| 参数     | 说明                 | 类型    | 默认值                      |
| -------- | -------------------- | ------- | --------------------------- |
| enabled  | 是否启用确认弹窗     | boolean | true（返回）/ false（关闭） |
| title    | 弹窗标题             | string  | -                           |
| describe | 弹窗描述内容         | string  | -                           |
| footer   | 弹窗底部按钮配置数组 | array   | -                           |

### FooterPositionMode

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

### PisellProcedureRef

通过 `ref` 可以调用以下方法：

| 方法              | 说明               | 类型                                         |
| ----------------- | ------------------ | -------------------------------------------- |
| goPrev            | 跳转到上一步       | `() => StepChangeResult \| null`             |
| goNext            | 跳转到下一步       | `() => StepChangeResult \| null`             |
| goToStep          | 跳转到指定步骤     | `(step: number) => StepChangeResult \| null` |
| getCurrentStep    | 获取当前步骤索引   | `() => number`                               |
| openSummaryModal  | 打开移动端总结弹窗 | `() => void`                                 |
| closeSummaryModal | 关闭移动端总结弹窗 | `() => void`                                 |

## 步骤导航

### 步骤条点击

点击头部步骤条可以直接跳转到对应步骤，支持确认弹窗：

- **点击步骤条**：跳转到指定步骤（如果启用了确认弹窗，会先显示确认弹窗）
- **返回按钮**：返回上一步（如果启用了确认弹窗，会先显示确认弹窗）
- **统一处理**：返回按钮和步骤条点击都走相同的确认逻辑，确认后执行对应的操作

```
<PisellProcedure
  headerProps={{
    stepsProps: {
      clickable: true,
      items: [
        { title: '第一步' },
        { title: '第二步' },
        { title: '第三步' },
      ],
    },
    // 返回和步骤跳转都使用同一个确认弹窗
    backConfirmModal: {
      enabled: true,
      title: '确认跳转',
      describe: '确定要跳转到该步骤吗？当前步骤的数据将不会保存',
    },
  }}
  onStepsChange={(result) => {
    console.log('步骤变化:', result.currentStep);
  }}
/>
```

### 底部按钮事件

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

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

```
<PisellProcedure
  footerProps={{
    actions: (
      <>
        <Button data-action="prev">上一步</Button>
        <Button onClick={() => save()}>保存草稿</Button>
      </>
    ),
  }}
/>
```

## 响应式断点

| 屏幕宽度    | 信息区宽度 | 底部操作区 | 说明       |
| ----------- | ---------- | ---------- | ---------- |
| ≥1366px     | 405px      | 可配置     | 标准布局   |
| 1133-1366px | 405px      | 可配置     | -          |
| 960-1133px  | 376px      | 可配置     | -          |
| 744-960px   | 290px      | 可配置     | -          |
| <744px      | 隐藏       | 吸底悬浮   | 移动端模式 |

## 布局和滚动行为

### 内容区滚动

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

### 信息区滚动

- 信息区使用 `position: sticky` 定位，固定在视口顶部
- 信息区高度通过 `useElementHeight` Hook 动态计算：`视口高度 - header高度 - footer高度 - body padding`
- 信息区内容区域有独立的滚动条（`overflow-y: auto`）
- 信息区不跟随整体页面滚动，始终保持可见状态
- 当信息区内容超出高度时，在信息区内滚动

## 注意事项

1. 组件是纯容器，不包含业务逻辑，所有内容通过插槽配置
2. 步骤控制需要配合 `onStepsChange` 事件管理状态
3. 底部按钮原有的 `onClick` 会先执行，再触发步骤控制
4. 确认弹窗的按钮需要设置 `action` 字段（'confirm' / 'cancel'）
5. 首步返回不传递 `onFirstStepBack` 时默认跳转首页（/）
6. `onPrev` / `onNext` 返回 false 可以阻止步骤更新
7. 移动端总结按钮只在 < 744px 时显示
8. **移动端（< 744px）时，底部操作区自动改为吸底悬浮模式**（`position: 'float-all'`），无视用户配置的 `footerProps.position` 参数，确保良好的移动端体验
9. **信息区使用 sticky 定位**，需要浏览器支持，现代浏览器均已支持
10. **信息区高度动态计算**，会根据 header 和 footer 的高度自动调整，确保始终在视口内可见
11. **步骤条点击和返回按钮统一处理**：点击步骤条跳转和点击返回按钮都走相同的确认逻辑，如果启用了确认弹窗，会先显示弹窗，确认后再执行对应的操作（`goToStep` 或 `goPrev`）
12. **弹窗模式**：设置 `mode="modal"` 时，组件会禁用移动端响应式行为，适用于在 Modal/Drawer 等容器中使用
13. **通过 ref 调用方法**：可以通过 `ref` 获取组件实例，调用 `goPrev`、`goNext`、`goToStep`、`getCurrentStep` 等方法进行外部控制

## 常见问题

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

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

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

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

### 如何自定义确认弹窗？

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