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

# PisellRecordBoard 组件开发文档

## 1 组件信息

### 1.1 基本信息

- **组件名称**：PisellRecordBoard
- **组件分类**：Pro 容器 / 记录看板
- **入口**：`packages/materials/src/components/pisellRecordBoard/index.tsx`（默认导出 + 子组件挂载 + 类型再导出）
- **实现核心**：`PisellRecordBoard.tsx`（Context 组装）、`RecordBoardProvider`、`shellFrame/`、`layouts/`、
  `utils/recordBoardColumns.tsx`

### 1.2 职责边界

| 层级         | 职责                                                                                                        | 非职责                                  |
|------------|-----------------------------------------------------------------------------------------------------------|--------------------------------------|
| 根容器        | 合并打散 props → `RecordBoardContextValue`；内部维护多选（可被子 `grid` 受控覆盖）、列显隐/列序、`bodyView`、`filterResetKey`、滚动区高度占位 | 不负责发起请求；不内置业务接口                      |
| ShellFrame | PisellShellFrame 拼装：ToolBar、BatchActionBar、主内容分支（Grid 滚动测量 vs FloorMap）、Pagination                        | 不解析业务字段语义                            |
| Grid       | `processColumnsForGrid`、同值列折叠、`scroll.autoCalc` 与 `scrollAreaHeight` 联动                                   | 列筛选/排序 UI 在 ToolBar                  |
| ToolBar    | PisellFind / QuickFilter / Sort / PisellFilter / Reset / Segmented 视图切换 / ColumnSetting                   | 不直接持有 `data` 副本（除派生用 `grid.columns`） |

## 2 目录结构（与源码一致）

```
pisellRecordBoard/
├── index.tsx                    # 复合组件类型 + 子组件挂载 + 命名导出类型 / useRecordBoardContext
├── PisellRecordBoard.tsx       # 根容器：状态、mergeChildComponentProps、Provider
├── PisellRecordBoard.stories.tsx
├── types.ts                     # RecordBoardProps、Context、Column、Grid、ToolBar、FloorMap 等
├── context/
│   ├── RecordBoardContext.ts    # React.createContext
│   └── RecordBoardProvider.tsx  # Provider 薄封装
├── hooks/
│   └── useRecordBoardContext.ts # useContext；displayName 合并 childComponentProps
├── shellFrame/
│   ├── index.tsx                # ShellFrame + ScrollAreaMeasurer；Grid/FloorMap 分支
│   ├── ToolBar/index.tsx        # 工具栏主实现（Segmented、Find、Filter、Sort…）
│   ├── ToolBarReset/            # 重置筛选/排序 + setFilterResetKey
│   ├── ToolBarQuickFilter/      # 左侧内联快筛
│   ├── ColumnSetting/           # 列显隐 + 列顺序（Popover + 拖拽）
│   ├── BatchActionBar/          # 对接 PisellBatchActionBar
│   ├── Pagination/              # 对接 materials Pagination + less
│   └── Search/                  # 独立搜索槽
├── layouts/
│   ├── GridLayout/index.tsx     # 仅包一层 div + Grid
│   └── GridLayout/Grid.tsx      # Table：列处理、同值总结区、rowSelection
│   └── CardLayout/              # 卡片列表布局
├── utils/
│   ├── recordBoardColumns.tsx   # processColumnsForGrid、deriveFilterFromColumns、deriveSortFromColumns、computeUniformColumnSummary…
│   └── withRecordBoard.tsx      # HOC（如有业务包裹场景）
├── docs/                        # 本文档与同目录其它 md
└── README.md
```

## 3 核心实现要点

### 3.1 mergeChildComponentProps（PisellRecordBoard.tsx）

仅在以下任一语义存在时生成 `childComponentProps`：

`grid` | `toolBar` | `search` | `paginationConfig` | `batchActionBar` | `cardList`

合并结果注入 Context，供 `useRecordBoardContext({ displayName: 'grid' | 'toolBar' | … })` 展开。

### 3.2 多选：受控 vs 非受控

当 **`grid.selectedKeys`** 为数组且 **`grid.onSelectionChange`** 为函数时，Context 使用 **grid 侧** 的
keys/rows/onChange；否则使用容器内部 `useState`。

### 3.3 列显隐与列顺序

- 初始：`grid.defaultHiddenColumnKeys` + `columns[].hidden === true` → 写入 `columnVisibility` 初值。
- 持久化：`columnVisibilityStorageKey`（或 `__id`）存在时，`useEffect` 调用 `saveColumnVisibilityToLocal`；初始化时尝试
  `getRecordBoardColumnSettingFromLocal` / `getColumnVisibilityFromLocal`（兼容旧 key）。

### 3.4 bodyView 与平面图槽位

- `useState` 初值：由 `defaultBodyView` 决定 `'grid'` 或 `'floorMap'`（不再依赖根级是否传入 `floorMap`）。
- **ShellFrame** 通过 `partitionShellFrameChildren` 识别 **`RecordBoard.FloorMap`**，与 `ctx.floorMapProps`（根级兼容）合并为
  **effectiveFloorMapProps**，**子 props 优先**。
- **仅平面图**（有 Floor 槽位、无 Grid/Card 子内容）：`useLayoutEffect` 将 `bodyView` 置为 `'floorMap'`。
- **仅表格**：无平面图槽位时 `bodyView` 置为 `'grid'`。
- **双视图**：由 `bodyView` 与用户切换决定；ToolBar Segmented 仅此时显示（见 `RecordBoardShellBodyMetaContext`）。

### 3.5 ShellFrame 主内容分支（shellFrame/index.tsx）

伪代码：

```
partition(children) → gridChildren, hasFloorMapChild, floorProps
effective = hasFloorMapChild ? { ...ctx.floorMapProps, ...floorProps } : ctx.floorMapProps
hasFloorMapSlot = hasFloorMapChild || ctx.floorMapProps != null
hasGridContent = gridChildren 非空

showGrid =
  !hasFloorMapSlot → true
  !hasGridContent → false
  else → ctx.bodyView === 'grid'

若 fillHeight:
  若 showGrid:
    ScrollAreaMeasurer { gridChildren } + Pagination
  否则:
    PisellFloorMapLayout(effective, items/renderItem 默认补全)
```

`PisellFloorMapLayout` 外层 `flex:1; minHeight:0; overflow:hidden` 与内部 PisellFloorMap 编辑布局配合，避免双滚动条。

### 3.5.1 根级 `dataSources`、`gridDataSourceKey` 与平面图合并

- **Context**：根 props **`dataSources`**、**`gridDataSourceKey`** 原样进入 **`RecordBoardContextValue`**
  （平面图编辑、工具栏不直接依赖，ShellFrame 消费 `ctx.dataSources`）。
- **表格 `data`**：
  - 若 **`data` prop 已传**：与历史行为一致，**不**从 `dataSources` 推导。
  - 若 **`data` 未传**且存在 **`dataSources` + `gridDataSourceKey`**：取 **`raw = dataSources[key] ?? []`**，按 *
    *`pagination`** 做 **`raw.slice`** 写入 Context；**`total`** 默认 **`raw.length`**（可用 `total` prop 覆盖）。
  - 缺 key 或缺 `gridDataSourceKey` 时：`data` 保持默认空数组，避免静默误推导。
- **平面图**：`mergedFloorMapDataSources = { ...ctx.dataSources, ...effectiveFloorMapProps.dataSources }`（后者覆盖同
  key）；仅在合并结果非空时覆盖传入 `PisellFloorMapLayout` 的 **`dataSources`**，否则沿用 `effectiveFloorMapProps`
  原有字段。合并对象始终为**全量多 key**，与表格当前页切片无关。

### 3.6 ScrollAreaMeasurer 与 scroll.autoCalc

- `ResizeObserver` 监听 `.pisell-record-board-scroll-body` 的 `contentRect.height`，写入 `setScrollAreaHeight`。
- `autoCalc === true` 时该容器 `overflow: hidden`，仅 Table 内部滚动（与 materials 表格 `useGenScroll` 行为对齐）。
- Grid 内对「同值列总结区」高度二次测量，修正 `scroll.y` 计算（见 `Grid.tsx`）。

### 3.7 ToolBar 关键行为（shellFrame/ToolBar/index.tsx）

| 区域         | 实现要点                                                                                                                                           |
|------------|------------------------------------------------------------------------------------------------------------------------------------------------|
| 最左         | 存在 `floorMapProps` 时渲染 antd **Segmented**：`grid` / `floorMap`                                                                                  |
| 左侧         | **ToolBarQuickFilter**（`toolBar.quickFilter` 或列派生 quickFilter）+ **PisellFind**（`keyword` ↔ `searchParams.keyword`）+ `slots.topLeft`            |
| 右侧         | **ColumnSetting**（可关）+ **Sort**（`searchParams.sort`）+ **PisellFilter**（`hiddenQuickFilter: true`，只保留高级筛选）+ **ToolBarReset** + `slots.topRight` |
| Filter key | `key={\`record-board-filter-${filterResetKey}\`}` 强制重挂载                                                                                        |
| filter 合并  | `effectiveFilterValue` 合并 session 恢复与配置，补回 `otherFilter` 上丢失的 `component` 及 label                                                              |

**派生数据**：`deriveFilterFromColumns` / `deriveSortFromColumns` 仅依赖 **`ctx.childComponentProps?.grid?.columns`**（与
Shell 内是否实际挂载 **GridLayout** 无关；**仅平面图** 时仍可通过 **`grid.columns`** 仅用于 ToolBar 派生快筛，或改用 *
*`toolBar.quickFilter.filterList`** 手写；见使用文档「仅平面图：左侧快筛与搜索」）。

### 3.8 recordBoardColumns.tsx 工具函数

| 函数                            | 用途                                                          |
|-------------------------------|-------------------------------------------------------------|
| `getRecordBoardColumnKey`     | 列唯一 key（列设置、显隐 map）                                         |
| `processColumnsForGrid`       | 有 `type` 且无 `render` 时注入 Pisell 只读 render；处理异步 `getOptions` |
| `deriveFilterFromColumns`     | 生成 quickFilter / otherFilter 列表供 ToolBar 与 PisellFilter 使用  |
| `deriveSortFromColumns`       | 生成 Sort 的 list                                              |
| `computeUniformColumnSummary` | `collapseUniformColumns` 时计算隐藏列与总结区条目                       |

## 4 类型与扩展

### 4.1 RecordBoardGridProps

基于 antd `TableProps` ** Omit ** `dataSource` | `loading` | `pagination` | `columns` | `scroll` | `size` |
`rowSelection`，再交叉自有字段。因此 **`onRow`、`expandable`、`summary` 等均可透传**。

### 4.2 RecordBoardFloorMapProps

`Partial<PisellFloorMapLayoutProps>`。ShellFrame 会补默认：`items={[]}`，`renderItem={() => null}`（若业务未传）；业务应传入 *
*`floorMapConfig`**，以及 **`dataSources`**（可只写在根级、或只写在 `FloorMap`、或两处合并）。根级 **`dataSources`** 与 *
*`FloorMap.dataSources`** 合并规则见 **§3.5.1**。

### 4.3 新增列 type

1. 在 `RecordBoardFieldType` 增加枚举值（`types.ts`）。
2. 在 `recordBoardColumns` 中注册：`type → 只读渲染`、`type → filter 表单项`、`type → sort 项` 的映射。
3. 为对应 Pisell 只读组件补充 Story / 单测。

### 4.4 新增 Layout

在 `layouts/` 新建 `XxxLayout`，仅渲染内容区；在 `index.tsx` 挂到 `PisellRecordBoard.XxxLayout`。若需
ToolBar/Batch/Pagination，外层仍用 **ShellFrame**。

## 5 依赖与文案

- **布局**：`PisellShellFrame`、`PisellFloorMapLayout`（可选）
- **工具栏子件**：`PisellToolBar`、`PisellFind`、`PisellFilter`、`Sort`、BatchActionBar 等
- **文案**：`pisell2.recordBoard.toolbar.*` 等 key：优先 `@pisell/utils` locales，未命中回退 `materials` `getText`（见
  ToolBar 内 `getViewGridLabel` 等）

## 6 调试清单

- [ ] 父级是否有高度（`height: 100%` 链路）— `fillHeight` 布局依赖
- [ ] `onSearch` 是否合并 `searchParams`（避免丢失 `filter` / `sort`）
- [ ] 平面图与表格是否共用同一数据 key（`sceneElements[].dataBinding` 与行 id）
- [ ] 快筛与 Filter 弹层是否同时出现重复项 — 检查 `hiddenQuickFilter` 与 QuickFilter 配置

## 7 相关文档

- [使用文档](./PisellRecordBoard.md)
- [设计文档](./PisellRecordBoard.$tab-design.md)
- [Shell Frame](./ShellFrame.md)
- [测试文档](./PisellRecordBoard.$tab-test.md)
