# 任务交接简报：VR Tree API 实现

> 创建时间：2026-05-15
> 负责人：西莉雅（统筹），大头（产品决策）

---

## 目标

实现新 API `/api/goods/tree`，解决当前前端 O(n²) 重建层级的问题，同时消除座位模板数据冗余。

---

## 核心设计

### 扁平数据 + 查询管理器

```
扁平 SKU（spec_key 索引）
  → 查询管理器（按 group_by 聚合）
  → 层级树（叶节点含 template_key）+ 模板去重池 + 扁平 SKU 列表
  → 缓存（TTL=60s）
  → API 返回
```

### 模板去重原则

同一 `venue + room + section` 的座位图模板在所有场次下共享，只存一份，不按 session 重复。

### 前端交互（全程零额外 API 调用）

```
初始加载：GET /api/goods/tree → tree + seat_templates_flat + flat_inventory
用户选座：venue → session → room → section → 查 template_key → 查模板 → 渲染座位图
spec_key 前缀匹配：前端在 flat_inventory 里本地过滤
```

---

## 关键文件

| 文件 | 作用 |
|------|------|
| `docs/14_TREE_API_DESIGN.md` | 完整设计文档（必读） |
| `docs/TASK_TREE_API_IMPLEMENTATION.md` | 实施任务清单（执行依据） |
| `docs/15_FLAT_INVENTORY_QUERY_MANAGER.md` | 方案对比与决策记录 |
| `service/SeatSkuService.php` | 数据源（复用，不改） |
| `service/SeatMapService.php` | 数据源（复用，不改） |
| `api/Goods.php` | 新增 `tree()` 接口 |

---

## 技术要点

1. **spec_key 格式**：`$vr-场次=X|$vr-场馆=X|$vr-演播室=X|$vr-分区=X|$vr-座位号=X`（固定顺序，`|` 连接）
2. **template_key 格式**：`venue_room_section`（由后端生成，前端只引用）
3. **group_by 参数**：前端指定层级顺序，如 `venue,session,room,section`
4. **缓存失效**：订单支付成功后同时清除 tree 缓存

---

## 不需要改动的内容

- `vr_seat_templates` 表结构
- `vr_goods_config` 存储格式
- `SeatSkuService::BatchGenerate()` 逻辑
- 前端选座核心逻辑（只是数据源变了，渲染逻辑不变）

---

## 测试命令

```bash
curl "http://localhost:10000/api.php?s=plugins/index&pluginsname=vr_ticket&pluginscontrol=goods&pluginsaction=tree&goods_id=118&group_by=venue,session,room,section" \
  -H "X-Requested-With: XMLHttpRequest"
```

验证：
- `meta.flat_count` > 0（SKU 数量）
- `meta.template_count` > 0（模板数量，应 << flat_count）
- `tree` 有正确的嵌套层级结构
- `seat_templates_flat` 中每个模板只出现一次

---

## 如遇问题

1. **spec_key 格式不对**：检查 `SeatSkuService::makeSpecKey()` 的排序逻辑
2. **模板去重不生效**：检查 template_key 生成逻辑是否按 venue+room+section 组合
3. **前端匹配失败**：确认前端 spec_key 排序与后端一致