vr-shopxo-plugin/docs/VR_GOODS_CONFIG_SPEC.md

191 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 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 实现时确认