---
description: "后台的地基形状：一屏列出资源的行，服务端分页/排序/搜索/筛选，勾选多行后出现上下文操作条做批量变更。数据要成行管理、要增删改查，就是它"
---

# 表格（CRUD 列表 + 批量操作）

后台的地基形状：一屏列出资源的行，服务端分页/排序/搜索/筛选，勾选多行后出现**上下文操作条**做批量变更。数据要成行管理、要增删改查，就是它。

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

试这几下：

- 点**姓名 / 加入日期**表头 —— 排序方向循环切换
- 勾选几行（或表头全选）—— 批量操作条出现，显示精确选中数；翻页后选择**不丢**
- **批量删除**会先弹确认；任何批量操作完成后 toast + 自动清空选择
- 搜索、状态筛选、分页组合使用，空结果有空态行

## 规矩

- **列表参数一个形状**：`{ page, pageSize, search?, sortBy?, sortDir?, filters? }` → `{ rows, total }`。demo 在内存里过滤排序，真实版把同一份参数交给 `Repository.list()`（服务端分页）
- **选择是瞬态 UI 状态**：放局部 state，不进 URL；靠稳定的行 id（`getRowId`）让选择跨页存活。列表/排序/筛选状态则相反 —— 真实版进 URL
- **操作条只在选中 ≥1 行时出现**，作用于精确的 id 集；成功后清空选择 + toast；破坏性操作先过确认弹窗
- 真实版的批量变更走一次批量调用（或 `Promise.all`），成功后失效该资源的查询键

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

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

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

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