vr-shopxo-plugin/docs/VR_GOODS_CONFIG_SPEC.md

191 lines
6.2 KiB
Markdown
Raw Normal View History

# vr_goods_config JSON 规格说明
> 版本v2.0 | 日期2026-04-20 | 状态:已确认,待实现
---
## 一、设计原则
1. **商品发布时快照**:用户在后端选择场馆房间后,将完整的房间数据**复制一份**存入 `goods.vr_goods_config`。不从 `vr_seat_templates` 实时读取。
2. **绝对一致性**:修改 `vr_seat_templates` 不影响已发布的商品。SKUspec_base`vr_goods_config` 一起过时、一起更新。
3. **向下兼容**:保留 `template_id` 字段(用于标识来源),但不再用它去查 `vr_seat_templates` 表。
4. **单一真相源**:前端渲染所需的所有数据(座位图、场次、价格)全部来自 `vr_goods_config` 的快照,不跨表查询。
---
## 二、vr_goods_config JSON 结构
```json
[
{
"template_id": 4,
"selected_rooms": ["room_id_1776341371905"],
"selected_sections": {
"room_id_1776341371905": ["A", "B"]
},
"rooms": [
{
"id": "room_id_1776341371905",
"name": "1号放映室VV",
"map": [
"AAAAB__BBB_BAAAA",
"AAAAB__BBB_BAAAA",
"AAAAB__BBB_BAAAA"
],
"sections": [
{ "char": "A", "name": "VIP区", "price": 100, "color": "#f06292" },
{ "char": "B", "name": "看台区", "price": 50, "color": "#4fc3f7" }
],
"seats": {
"A": { "char": "A", "name": "VIP区", "price": 100, "color": "#f06292" },
"B": { "char": "B", "name": "看台区", "price": 50, "color": "#4fc3f7" }
}
}
],
"sessions": [
{ "start": "15:00", "end": "16:59" },
{ "start": "18:00", "end": "21:59" }
]
}
]
```
### 字段说明
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `template_id` | int | ✅ | 来源场馆模板 ID用于溯源不用于查询 |
| `selected_rooms` | string[] | ✅ | 本商品启用的房间 ID 列表 |
| `selected_sections` | object | ✅ | key=房间IDvalue=启用的分区字符列表(如 `["A","B"]` |
| `rooms` | object[] | ✅ | 房间完整数据快照(直接复制自 `vr_seat_templates.rooms` |
| `sessions` | object[] | ✅ | 本商品的场次列表 |
### rooms.seats 字段说明
`seats``sections` 的快捷索引key = `char`(座位字符),格式与 `sections` 条目相同:
```json
"seats": {
"A": { "char": "A", "name": "VIP区", "price": 100, "color": "#f06292" },
"B": { "char": "B", "name": "看台区", "price": 50, "color": "#4fc3f7" }
}
```
### 向下兼容(旧格式迁移)
旧格式(有 `vr_seat_templates` 表关联逻辑):
```json
{
"template_id": 4,
"sessions": [{"start": "...", "end": "..."}]
}
```
识别方式:`rooms` 字段不存在 → 降级读取 `vr_seat_templates` 表。
---
## 三、SKU 生成逻辑AdminGoodsSaveHandle Hook
商品保存时,根据 `selected_rooms` 数组,从 `vr_seat_templates.rooms` 取出对应房间,展开每个房间的 `map` 座位,生成 SKU 条目到 `goods_spec_base` + `goods_spec_value`
```
rooms[room_id].map
└─ 每行字符串(如 "AAAAB__BBB_BAAAA"
└─ 每个非 _ / - 的字符 → 一个 SKU
├─ goods_spec_base.id → 库存主键
├─ goods_spec_base.spec_name → "排:row, 座:colNum"
├─ goods_spec_base.price → seats[char].price
└─ goods_spec_base.spec_type → "vrseat:{room_id}:{char}"
```
**spec_base_id_map存到 vr_goods_config 的 rooms[] 中)格式:**
```json
{
"{room_id}_{row}_{colNum}": goods_spec_base.id
}
```
> 注:具体 SKU 生成字段名/存储位置待 AdminGoodsSaveHandle 实现时确认。
---
## 四、前端渲染数据流
```
goods.vr_goods_config快照
└─ [0].rooms[] → 前端 JS rooms[]
└─ [0].sessions[] → 场次卡片
└─ [0].selected_sections{} → 控制哪些分区渲染
```
### 前端数据结构
```javascript
// GetGoodsViewData() 注入给模板
{
vr_seat_template: {
rooms: [...], // rooms 快照数组
sessions: [...], // 场次列表
selected_sections: {} // 分区过滤
},
goods_spec_data: [...], // 场次规格price 来自 goods_spec_base
goods_config: { ... } // 原始 vr_goods_config[0]
}
```
### loadSoldSeats已选座位
`vr_tickets` 表查询该商品+当前场次已生成的票:
```sql
SELECT seat_info FROM vrt_vr_tickets
WHERE goods_id = :goods_id AND verify_status != 1
```
`seat_info` 格式:`"room_id/rowLabel/colNum"`(例:`room_id_xxx/A/3`
---
## 五、GetGoodsViewData() 重写要点
**输入**`goods_id`
**输出**
```php
[
'vr_seat_template' => [
'rooms' => [...], // 来自 vr_goods_config[0].rooms
'sessions' => [...], // 来自 vr_goods_config[0].sessions
'selected_sections' => {...}, // 来自 vr_goods_config[0].selected_sections
],
'goods_spec_data' => [...], // 场次+价格(用于前端场次卡片)
'goods_config' => {...} // 原始 vr_goods_config[0]
]
```
**逻辑**
1. 读取 `goods.vr_goods_config` JSON
2.`rooms` 字段存在 → 直接使用(新格式)
3.`rooms` 不存在 → 降级:按旧逻辑查 `vr_seat_templates` 表(旧格式兼容)
4. 场次价格从 `goods_spec_base` 表读取
---
## 六、需要更新的文件
| 文件 | 操作 | 说明 |
|------|------|------|
| `SeatSkuService.php` | 重写 GetGoodsViewData() | 新 JSON 格式解析 |
| `ticket_detail.html` | 更新 JS | rooms[] 结构渲染 + loadSoldSeats |
| `docs/VR_GOODS_CONFIG_SPEC.md` | 新建 | 本文档,记录 JSON 规格 |
| `docs/PHASE2_PLAN.md` | 更新 | 补充新格式 + 待办 |
| `docs/DEVELOPMENT_LOG.md` | 追加 | 记录本次 JSON 格式升级 |
---
## 七、已确认的设计决策
1. ✅ 商品发布时快照 `vr_seat_templates.rooms``goods.vr_goods_config.rooms`
2.`vr_goods_config` 包含完整的座位图+sections+seats 数据
3. ✅ 前端不跨表查询,全部数据来自 `vr_goods_config` 快照
4.`spec_base_id_map` 格式:`{room_id}_{row}_{colNum}` → `spec_base_id`
5. ✅ 座位已售状态:查 `vr_tickets.seat_info`(格式:`room_id/rowLabel/colNum`
6. ⚠️ SKU 生成字段名/存储位置:待 AdminGoodsSaveHandle 实现时确认