---
description: "每个数据区域都逃不掉的四种样子：loading / empty / error / ready。这个形状把它们收进一个 StateView 组件，全应用共用一个形状 —— 白屏不再像坏了，出错永远有下一步。外加侧滑抽屉（Sheet）和 toast"
---

# 反馈状态（四态 + 抽屉）

每个数据区域都逃不掉的四种样子：**loading / empty / error / ready**。这个形状把它们收进一个 `StateView` 组件，全应用共用一个形状 —— 白屏不再像坏了，出错永远有下一步。外加侧滑抽屉（Sheet）和 toast。

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

试这几下：

- 用分段开关切**四态** —— demo 手动切，真实版由查询状态驱动，同一个区域同一个形状
- 空态再切**「还没有数据」/「筛选无结果」** —— 两种空各有各的文案和 CTA（新建/导入 vs 清空筛选）
- **出错 → 重试** —— 先回 loading 骨架屏，约 1 秒后恢复数据（不跳版式）
- **打开侧滑详情** —— 抽屉自包含、点遮罩即关，操作完 toast

## 规矩

- **每个数据视图显式处理 loading / empty / error**，`StateView` 是共用形状：`state` 分支渲染，`ready` 直通 children —— 真实版把查询的 `isLoading / data.length / error` 映射进来
- **空态必须给下一步动作**（CTA），且**区分**首用空（去创建/导入）和筛选空（清空筛选）—— 两种空文案混用是常见败笔
- 错误态给重试；loading 用骨架屏占位，重取时不闪不跳
- 抽屉内容自包含、可关闭；瞬时反馈一律 toast

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

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

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

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