---

## title: PisellReservation 深入：架构与数据流

order: 8
category: plus

本文整合 **模块为何拆分**、**数据如何流转**，以及原 **[平面图多数据源](./pisell-reservation-multi-datasource.md)** 专题的全文（见 §3），便于一份文档读完预约页实现脉络。

---

## 纯文本结构图

### 1）源码目录（按职责，非完整树）

```
packages/private-materials/src/plus/pisellReservation/
│
├── README.md                      # 目录说明
├── PisellReservation.tsx          # 页面壳：RecordBoard + 时间轴 + dataSources 合并 + floorMap
├── index.tsx
├── types.ts                       # PisellReservationTableRow、Props、floorMapBookingClickMode 等
├── reservationConstants.ts        # GRID_DS_KEY、合并进 locales 的 PISELL_RESERVATION_PAGE_LOCALES
│
├── data/                          # 表格行合并与预约数据变换
│   ├── reservationTablesMerge.ts
│   ├── bookingToReservationTables.ts
│   ├── formResourceToReservationTables.ts
│   ├── salesEmbeddedResourceToTableRows.ts
│   ├── reservationDataUtils.ts
│   ├── filterBookingsAtTimeCursor.ts
│   └── reservationDensity.ts
│
├── floorMap/                      # 平面图方案、绑定、HUD
│   ├── useReservationFloorPlan.ts
│   ├── useReservationFloorMapMerged.tsx
│   ├── floorPlanApi.ts
│   ├── reservationMock.ts
│   ├── reservationCards.tsx
│   ├── floorMapHostCheckout.ts
│   ├── ReservationFloorMapHud.tsx
│   └── …
│
├── hooks/
│   ├── usePisellReservationResourceTableData.ts
│   └── usePisellReservationBookingData.ts
│
├── grid/
│   └── reservationResourceGridColumns.tsx
│
├── locales/
│   ├── locales.ts | locales-ja.ts | locales-pt.ts
│
├── components/
│   ├── PisellReservationSubcomponents.tsx
│   └── bookingDetailModal/        # 只读点击：预约详情弹窗（detailModal 模式）
│
├── floorRoomCard/
├── docs/
├── serve/
└── api/
```

### 2）内置列表模式下的数据流（简化）

```
                    ┌─────────────────────────────────────┐
                    │  PisellReservation（引擎 locale 等）  │
                    └─────────────────────────────────────┘
                                        │
          ┌─────────────────────────────┼─────────────────────────────┐
          ▼                             ▼                             ▼
   resource 请求                  day booking 请求          debounced 时间轴
   (usePisellReservation           (usePisellReservation     (schedule.at)
    ResourceTableData)             BookingData)
          │                             │
          └──────────────┬──────────────┘
                         ▼
              二者就绪后（可选）
              sales.getResourceBookingList(时刻, 当日 list)
                         │
                         ▼
              buildReservationMergedTableRows …
              （reservationTablesMerge 等）
                         │
                         ▼
              dataSources[ gridDataSourceKey ]   ← 默认 key = "tables"
              （与 dataSourcesProp 展开合并，同名 key 被覆盖）
                         │
          ┌─────────────┴─────────────┐
          ▼                           ▼
   RecordBoard 表格视图          平面图 FloorMapLayout
   （分页、列、筛排）              dataBinding → 按 key 查行
          │                           │
          │                           ├── useReservationFloorPlan → floorMapConfig
          │                           └── useReservationFloorMapMerged → labels/forms/onSave
          └───────────────────────────┴── 同源 PisellReservationTableRow[]
```

### 3）平面图配置与持久化（简化）

```
  reservationMock（默认壳 + elementKinds）
           +
  floorMapProp.floorMapConfig（低代码/父级）
           +
  GET shop floor-plan/code（layout 字段）
           │
           ▼
  useReservationFloorPlan → baseFloorConfig
           │
           ▼
  useReservationFloorMapMerged → RecordBoard.floorMap
           │
           ├── 编辑保存 → saveViewConfigToShopFloorPlan（有效 id 时）
           └── 只读/编辑 UI → @pisell/materials PisellFloorMapLayout
```

---

## 1. 为何 `pisellReservation` 里文件多？

这不是「单页单文件」，而是一个 **业务闭环页**，在 **RecordBoard** 上叠了：

- 与 Sales Monitor 对齐的 **预约列表**（筛排、列、分页）；
- **顶栏时间轴 + 营业日**；
- **表格 ⟷ 平面图** 双视图；
- **店铺平面图方案** 拉取与保存；
- 与 **PisellOS / sales 模块**（如 `getResourceBookingList`）的衔接；
- **Room 卡片** 与宿主 **结账抽屉** 等交互。

因此按 **数据拉取 / 合并 / 平面图 / 渲染 / 常量文案** 拆成多文件，改合并逻辑或画布时不至于全部挤在
`PisellReservation.tsx`。**文件多 ≈ 职责拆分 + 功能面宽**，不是冗余拷贝。

---

## 2. 数据架构要点（与类型）

### 2.1 核心类型

- `**PisellReservationTableRow`**（`types.ts`）：「一桌 / 一资源」一行，含 `code`、`cardStatus`、`floorMapSourceBookings`
  等，供表格与平面图共用。
- `**dataSources`**：`Record<string, PisellReservationTableRow[]>`（第二路若类型不同可考虑放宽，见 §3.7）。

### 2.2 `tables` 与 `gridDataSourceKey`

- `**GRID_DS_KEY**`（`reservationConstants.ts`）默认为 `**'tables'**`。
- `**gridDataSourceKey**`：RecordBoard **表格**从 `dataSources` 的哪一个 key 做客户端分页。
- `**dataSources` 合并**：先展开外部 `dataSources` prop，再用内置算好的 `**mergedTables`** 写入 `**[gridDataSourceKey]`**
  ，其它 key 保留给平面图多数据源（详见 §3）。

### 2.3 内置模式下的主链路（代码注释摘要）

1. `GET form/resource/page`（或等价）→ 当前资源台列表；
2. `GET schedule/booking`（带 `form_record_ids` 等）→ 当日预约，非全量；
3. 资源与 booking 的 loading 结束后，可选调用 `**sales.getResourceBookingList(时间字符串, 当日 list)**` → 游标时刻仍有效的预约集合；
4. `**buildReservationMergedTableRows**`：资源行（`id = recordId`）与预约按 resource 合并 → 写入 `**dataSources.tables**`
   （或你配置的 key）；
5. 平面图渲染时 `**renderItemByKind**` 只读 `dataSources`，每桌已带合并字段。

### 2.4 受控列表

传入 `**data**` 时走受控路径，booking 内置请求关闭；`tables` 映射与分页需与父级约定（见 `**PisellReservation.md**`）。

---

## 3. 平面图多数据源（与 `tables` 同级）【全文收录】

以下与原 `**pisell-reservation-multi-datasource.md**` 一致，便于单文档维护时对照；若专篇有更新，建议与此处同步或改为专篇链接。

### 3.1 概念：`tables` 是什么

- `**tables` 只是 `dataSources` 对象里的一个 key**。工程里默认常量见 `reservationConstants.ts` 的
  `GRID_DS_KEY = 'tables'`。
- `**gridDataSourceKey`**（默认 `'tables'`）主要决定 RecordBoard 表格从 `dataSources` 的**哪一个 key** 做客户端分页（见
  `@pisell/materials` 的 `PisellRecordBoard`）。
- **平面图底层**（`PisellFloorMapLayout`）支持 **多个 key 并存**：`dataSources` 可以是 `{ tables: Row[], yourKey: Row[] }`。

参考实现：`**packages/materials/src/components/pisellRecordBoard/PisellRecordBoard.stories.tsx`** 中 **Default**
故事（餐桌 + 蘸料摆台）：表格只绑一路，`dataSources` 同时包含两路，平面图可同时渲染两类图元。

### 3.2 数据如何进入平面图：三条路径

**路径 A：受控传入（最简单）**

向 `PisellReservation` 传入：

```tsx
dataSources={{
  tables: [...],
  yourKey: [...],
}}
```

组件内合并逻辑（`PisellReservation.tsx`）大致为：

- 先展开 `**dataSourcesProp**`（你传入的对象）；
- 再用内置算好的 `**tables**` 覆盖 `**[gridDataSourceKey]**`（通常为 `tables`）。

因此：**你在 prop 里多写的 key 会保留**，与内置合并后的 `tables` **同级**进入平面图；只有与 `gridDataSourceKey` 同名的 key
会被覆盖。

**路径 B：内置合并只负责「一桌」这一路**

`reservationTablesMerge.ts` 中的 `**buildReservationMergedTableRows`** 只返回**一个数组**，用于写入 `gridDataSourceKey`
对应的那一列（资源 + 预约合并、`sales.getResourceBookingList` 等逻辑都在这条链路上）。

第二路若也要「请求 + 合并」：**需要自行增加**数据获取与 `useMemo`，最后在组装根级 `dataSources` 时写入第二个 key，例如：

```ts
{
  ...dataSourcesProp,
  [gridDataSourceKey]: mergedTables,
  [YOUR_SECOND_KEY]: secondList,
}
```

注意合并顺序，避免被后续展开覆盖。

**路径 C：表格不必绑第二路**

第二路可以**仅给平面图用**：`gridDataSourceKey` 仍指向 `tables`，表格继续只展示资源列表。

### 3.3 平面图：图元能绑定哪些数据源

图元种类配置类型在 materials 中为 `**FloorMapElementKindConfig`**，字段 `**allowedDataSourceKeys`** 列出该种类在侧栏可选的数据源
key。

默认预约 mock（`reservationMock.ts` → `getReservationPaletteElementKinds`）里，绑定资源一般为
`allowedDataSourceKeys: ['tables']`（常量 `DS === 'tables'`）。

要让图元能绑第二路，需要其一：

- 把 `**allowedDataSourceKeys**` 扩成 `['tables', 'yourKey']`；或
- **新增**一个 `elementKind`，只允许 `['yourKey']`，并在 `renderItemByKind` 里用对应渲染函数。

绑定合法性校验见：`packages/materials/src/components/pisellFloorMapLayout/utils/floorMapElementKindUtils.ts`

### 3.4 侧栏：标签与表单列（易漏）

`useReservationFloorMapMerged.tsx` 中当前对 `**dataSourceLabels`**、`**dataSourceFormColumns`** 往往只配置了
`**gridDataSourceKey**` 一项。

仅增加 `dataSources.yourKey` 而不补充这两项时，侧栏可能显示 **raw key** 或 **缺少表单列**。

处理方式任选：

- 在上述两个对象中**为 `yourKey` 增加** `label` 与 `columns`（建议走 `locales` + 独立列配置）；或
- 通过 `**floorMap` 透传** `dataSourceLabels` / `dataSourceFormColumns`（注意与 `return { ... }` 里 `...floorRest`
  的字段顺序，避免被意外覆盖）。

### 3.5 渲染：如何根据绑定取行

`reservationCards.tsx` 中的 `**findReservationRow`** 会根据图元上的 `**dataBinding.dataSourceKey`** 到
`**dataSources[key]**` 中查找记录。

- 若第二路行结构与 `**PisellReservationTableRow**` 兼容，可继续复用 `**ReservationFloorRoomCard**` 与现有
  `renderItemByKind` 分支。
- 若结构不同：为**新 elementKind** 注册新的 `renderItemByKind` 实现，内部按你的类型读取 `dataSources[yourKey]`。

### 3.6 业务分支：HUD、点击、淡化等

- `**ReservationFloorMapHud`** 等统计若只统计「桌位/资源」，通常会按 `elementKind` 或 `dataSourceKey === 'tables'`
  过滤；第二路若要进统计需改条件。
- `**floorMapItemClickBefore`**（`PisellReservation.tsx`）中打开宿主抽屉等逻辑，若仅针对主数据源，需按 `**dataSourceKey**`
  分支处理。

### 3.7 类型（TypeScript）

`types.ts` 中当前为：

```ts
dataSources?: Record<string, PisellReservationTableRow[]>;
```

第二路若不是桌位行类型，可改为更宽类型（如 `Record<string, unknown[]>`），或拆成多个 prop，避免类型误报。

### 3.8 实施 Checklist（推荐顺序）

| 步骤 | 内容                                                                                               |
|----|--------------------------------------------------------------------------------------------------|
| 1  | 确定 **key 字符串**（如 `yourKey`），与低代码、已保存 layout、`allowedDataSourceKeys` 一致。                          |
| 2  | 确定 **数据来源**：仅 `dataSources` prop，或新增请求 + 合并进根 `dataSources`。                                     |
| 3  | 修改 `**floorMapConfig.elementKinds`**（mock 合并或接口 layout）：`allowedDataSourceKeys` 或新 kind。         |
| 4  | 补 `**dataSourceLabels` / `dataSourceFormColumns`**（`useReservationFloorMapMerged` 或 `floorMap`）。 |
| 5  | 补 `**renderItemByKind**`（新 kind 或扩展查找逻辑）。                                                        |
| 6  | 检查 **HUD / onItemClick / getMergedItemWrapperStyle** 等是否需按 `dataSourceKey` 分支。                   |

### 3.9 关键文件索引

| 模块                              | 路径                                                              |
|---------------------------------|-----------------------------------------------------------------|
| 根级 `dataSources` 合并             | `PisellReservation.tsx`（`dataSources` 的 `useMemo`）              |
| 内置桌位合并                          | `reservationTablesMerge.ts` → `buildReservationMergedTableRows` |
| 默认 `GRID_DS_KEY`                | `reservationConstants.ts`                                       |
| 平面图 props 合并（labels/forms）      | `useReservationFloorMapMerged.tsx`                              |
| 默认图元种类与 `allowedDataSourceKeys` | `reservationMock.ts` → `getReservationPaletteElementKinds` 等    |
| 卡片占位与按 key 查行                   | `reservationCards.tsx`                                          |
| 多数据源 Story 参考                   | `pisellRecordBoard/PisellRecordBoard.stories.tsx` → `Default`   |
| 绑定校验                            | `pisellFloorMapLayout/utils/floorMapElementKindUtils.ts`        |

---

## 4. 与其它文档的关系

| 文档                                            | 用途                             |
|-----------------------------------------------|--------------------------------|
| `**PisellReservation.md`**                    | Props、视图切换、floorPlan、受控列表等行为说明 |
| `**pisell-reservation-multi-datasource.md`**  | 与 §3 同源专题（可择一维护）               |
| **本文 `pisell-reservation-deep-dive.md`**      | 目录结构 + 数据流图 + 多数据源全文 + 为何拆文件   |
| `**pisell-reservation-feature-inventory.md**` | 功能点表格（对照 RecordBoard 是否下沉，可自填） |


