vr-shopxo-plugin/docs/15_FLAT_INVENTORY_QUERY_MAN...

4.5 KiB
Raw Blame History

扁平数据 + 查询管理器 方案

讨论日期2026-05-15 参与:西莉雅、大头


一、核心思想

后端做计算,前端做渲染。

  • 扁平数据层Flat Inventory所有 SKU 以 spec_key 为索引,不预设层级
  • 查询管理器Query Managergroup_by 参数聚合,生成层级树
  • 缓存层:结果缓存,避免重复计算
  • 前端:通过 group_by 参数指定想要的层级顺序,收到树后直接渲染

二、关键设计决策

2.1 模板去重

原则:同一 venue + room + section 的座位图模板在所有场次下共享,与 session 无关。

例如:鸟巢 + 主厅 + A区
  → 6 个场次 × 1 个模板 = 1 份模板数据(不是 6 份)
  → template_key = "鸟巢_主厅_A"
  → 在 seat_templates_flat 中只存 1 份

优势

  • 消除跨场次的模板数据冗余
  • 前端只需按 key 引用,无需处理重复模板

2.2 层级顺序由前端控制

group_by=venue,session,room,section  →  场馆优先Joery 场景)
group_by=session,venue,room,section  →  场次优先(当前实现)

后端不在意顺序,只负责聚合。

2.3 扁平数据全量返回

API 返回:
  ├── tree层级含 section 聚合)
  ├── seat_templates_flat模板去重池
  └── flat_inventory所有 SKU前端本地筛选

前端选座流程(全程零额外 API
  venue → session → room → section
       ↓
  查 template_key → 查 seat_templates_flat → 渲染座位图
       ↓
  spec_key 前缀匹配 flat_inventory → 标记可选座位

2.4 实时查询接口(复用查询管理器)

查询管理器同时支持实时查询:

GET /api/goods/inventory?goods_id=118&spec=venue:鸟巢,session:15:00-16:59
→ 返回该条件下的总库存

三、API 接口

GET /api/goods/tree
    ?goods_id=118
    &group_by=venue,session,room,section
    &cache_ttl=120

返回结构:

{
  "goods_id": 118,
  "title": "VR演唱会",
  "group_by": ["venue", "session", "room", "section"],
  "tree": {
    "鸟巢": {
      "name": "鸟巢",
      "min_price": 280,
      "has_available": true,
      "rooms": { "主厅": { "sections": { "A": { "template_key": "鸟巢_主厅_A", "price": 680, "inventory": 12 } } } },
      "sessions": { "15:00-16:59": { "min_price": 380, "has_available": true } }
    }
  },
  "seat_templates_flat": {
    "鸟巢_主厅_A": { "map": [...], "sections": [...], "seats": {...} }
  },
  "flat_inventory": [
    { "spec_key": "$vr-场次=15:00-16:59|...|$vr-座位号=1排1座", "price": 680, "inventory": 1, "seat_key": "room_0_A_1" }
  ],
  "meta": { "flat_count": 120, "template_count": 4, "cache_hit": false }
}

四、与现有系统衔接

vr_goods_config
  ↓
SeatSkuService::buildSeatSpecMap() → 扁平 SKU不预设层级
  ↓
QueryManager新增
  ├── buildTree():按 group_by 聚合
  ├── buildTemplatePool():模板去重
  └── buildFlatInventory():返回扁平 SKU 列表
  ↓
缓存层TTL=60s
  ↓
API Response

现有组件不变

  • SeatMapService / SeatSkuService继续作为数据源
  • vr_seat_templates 表:继续存储座位模板
  • vr_goods_config继续作为商品配置

五、与"层级 JSON 树方案"的关系

维度 层级 JSON 树(方案 A 扁平 + 查询管理器(方案 B采纳
前端复杂度 低(直接用树) 中(本地筛选 + 模板引用)
后端复杂度 中(预计算固定结构) 中(查询管理器,按参数聚合)
灵活性 差(固定层级) 好(前端指定 group_by
模板去重 支持(但实现复杂) 原生支持
数据冗余 高(模板重复) 低(去重池)
实时查询 不支持 支持

结论Joery 的方案更优,采纳方案 B。


六、注意事项

  1. template_key 生成算法:由后端统一生成,格式为 venue_room_section,前端不感知算法
  2. spec_key 排序:前端匹配时必须使用与后端相同的排序规则(固定顺序,用 | 连接)
  3. 缓存失效:订单支付成功后同时清除 SeatMapService 缓存和 tree 缓存
  4. inventory=0 的座位flat_inventory 需要包含已售座位(用于前端标记"已售"状态)
  5. 缓存 TTL:默认 60s可通过 cache_ttl 参数调整