---
description: "一份长表单拆成几步填：进度指示 + 分步校验拦住「下一步」+ 最后一步 review 过目再提交。字段多到一屏压迫、或有天然先后（开通流程、建活动、入驻申请）时用它"
---

# 向导表单

一份长表单拆成几步填：进度指示 + 分步校验拦住「下一步」+ 最后一步 **review 过目**再提交。字段多到一屏压迫、或有天然先后（开通流程、建活动、入驻申请）时用它。

<iframe src="/skills/dashboard/assets/demo-wizard.html"
        style="width:100%;height:560px;border:1px solid #8884;border-radius:10px"
        loading="lazy" title="形状 demo：向导表单"></iframe>

试这几下：

- 什么都不填直接点**下一步** —— 被当前步校验拦住，错误就地显示
- 填好走到第 2 步再**上一步** —— 已填的值一个不丢
- 最后一步是 **review**：所有值列出来过目，确认才真正提交（成功面板 + toast）

## 规矩

- **一份表单状态贯穿整个向导**（蓝本是一个 TanStack Form 的 `useForm`），步骤只是它的视图切片 —— 绝不一步一个表单再手工拼合
- **「下一步」被当前步的校验拦住**：只校验本步字段（蓝本按 zod `schema.shape[name]` 逐字段 `safeParse`），错误就地显示
- 最后一步 review 展示全部值；真实版提交走该资源的 `Repository` mutation，服务端校验失败把错误回填到表单
- 提交结果必反馈：成功 toast/面板，失败 `setServerError`

> 蓝本：`add-wizard-form.md`[^add-wizard-form]（open-dashboard @ `aa9815f`，MIT，Invariants 已消化进上面「规矩」）

??? abstract "demo 源码：`assets/demo-wizard.html`（自包含、未压缩）"

    ```html
    --8<-- "skills/dashboard/assets/demo-wizard.html"
    ```

[^add-wizard-form]: [`add-wizard-form.md`](https://github.com/ahpxex/open-dashboard/blob/aa9815f426e9520841c4aa15a341bfd9f866091f/.claude/skills/add-component/references/add-wizard-form.md)，2026-07-28 读。
