[P0] vr_goods_config v3.0 落地实现 #13

Closed
opened 2026-04-20 00:30:38 +00:00 by sileya-ai · 2 comments

背景

vr_goods_config JSON 格式已更新为 v3.0(见 docs/VR_GOODS_CONFIG_SPEC.md),需落地实现。

v3.0 最终结构

version: 3.0
template_id: 4(发布/编辑时读取最新 vr_seat_templates 的依据)
selected_rooms: ["room_id_xxx"](用户选择:启用哪些演播)
selected_sections: { "room_id_xxx": ["A", "B"] }(用户选择:每个房间选哪些分区)
sessions: [{ "start": "15:00", "end": "16:59" }](用户管理:场次列表)
template_snapshot: { venue: {...}, rooms: [...] }(发布时从 vr_seat_templates 读取并存储的快照)

关键设计说明

template_snapshot 的前端职责 vs 后端职责

  • 前端(Admin 编辑页打开时):用 template_id 读最新 vr_seat_templates,填充 template_snapshot 到表单并提交;编辑过程中模板变化了以打开时的快照为准
  • 后端(AdminGoodsSaveHandle):检测 template_snapshot 是否缺失,若缺失则从 vr_seat_templates 读表填充(兜底),然后写回 goods 表,再 BatchGenerate
  • 数据层分离:template_snapshot → 前端渲染用;vr_seat_templates 实时读取 → BatchGenerate 生成 SKU

实现进度

Step 1:AdminGoodsSaveHandle — 保存时填充 template_snapshot

已实现(提交 bbea35d83):

  • 遍历 vr_goods_config[],检测 template_snapshot 是否缺失
  • 若缺失:从 vr_seat_templates 读最新 seat_map,按 selected_rooms 过滤 rooms
  • 写回 goods 表,再执行 BatchGenerate

Step 2:BatchGenerate — 写入 extends

insertGetId 中加入 extends.seat_key = roomId_rowLabel_colNum

Step 3:GetGoodsViewData — 重写

  • 读 vr_goods_config.template_snapshot(前端渲染用)
  • 从 goods_spec_base.extends 动态构建 spec_base_id_map
  • selected_sections 适配对象格式 { room_id: ["A","B"] }
  • goods_spec_data 按场次聚合

Step 4:ticket_detail.html JS — seatKey 格式

seatKey = seat.roomId + '' + seat.rowLabel + '' + seat.colNum

关联文档

docs/VR_GOODS_CONFIG_SPEC.md(v3.0 完整规格,已更新)
docs/PHASE2_PLAN.md v3.0

## 背景 vr_goods_config JSON 格式已更新为 v3.0(见 docs/VR_GOODS_CONFIG_SPEC.md),需落地实现。 ## v3.0 最终结构 version: 3.0 template_id: 4(发布/编辑时读取最新 vr_seat_templates 的依据) selected_rooms: [\"room_id_xxx\"](用户选择:启用哪些演播) selected_sections: { \"room_id_xxx\": [\"A\", \"B\"] }(用户选择:每个房间选哪些分区) sessions: [{ \"start\": \"15:00\", \"end\": \"16:59\" }](用户管理:场次列表) template_snapshot: { venue: {...}, rooms: [...] }(发布时从 vr_seat_templates 读取并存储的快照) ## 关键设计说明 ### template_snapshot 的前端职责 vs 后端职责 - 前端(Admin 编辑页打开时):用 template_id 读最新 vr_seat_templates,填充 template_snapshot 到表单并提交;编辑过程中模板变化了以打开时的快照为准 - 后端(AdminGoodsSaveHandle):检测 template_snapshot 是否缺失,若缺失则从 vr_seat_templates 读表填充(兜底),然后写回 goods 表,再 BatchGenerate - 数据层分离:template_snapshot → 前端渲染用;vr_seat_templates 实时读取 → BatchGenerate 生成 SKU ## 实现进度 ### ✅ Step 1:AdminGoodsSaveHandle — 保存时填充 template_snapshot 已实现(提交 bbea35d83): - 遍历 vr_goods_config[],检测 template_snapshot 是否缺失 - 若缺失:从 vr_seat_templates 读最新 seat_map,按 selected_rooms 过滤 rooms - 写回 goods 表,再执行 BatchGenerate ### ❌ Step 2:BatchGenerate — 写入 extends insertGetId 中加入 extends.seat_key = roomId_rowLabel_colNum ### ❌ Step 3:GetGoodsViewData — 重写 - 读 vr_goods_config.template_snapshot(前端渲染用) - 从 goods_spec_base.extends 动态构建 spec_base_id_map - selected_sections 适配对象格式 { room_id: [\"A\",\"B\"] } - goods_spec_data 按场次聚合 ### ❌ Step 4:ticket_detail.html JS — seatKey 格式 seatKey = seat.roomId + '_' + seat.rowLabel + '_' + seat.colNum ## 关联文档 docs/VR_GOODS_CONFIG_SPEC.md(v3.0 完整规格,已更新) docs/PHASE2_PLAN.md v3.0
Poster
Owner

Issue #13 进度更新 — 2026-04-20 10:40

本次修复

问题template_snapshot.rooms 为空,但 selected_rooms = ["room_1"] 有值。

根因:两重

  1. empty(template_snapshot){"venue":{...},"rooms":[]} 返回 false → DB 兜底被跳过
  2. 模板 ID=4 可能是 v1 旧格式(无 rooms 嵌套)→ 即使触发 DB 读取也拿不到 rooms

修复AdminGoodsSaveHandle.php):

  • 条件改为 empty(template_snapshot) || empty(template_snapshot[rooms])
  • 新增 v1→v3 迁移:检测 sections 存在但 rooms 为空时,自动构造 v3 rooms 数组

提交3f06f36e5 已推送


仍需处理

  • 确认模板 ID=4 实际 seat_map 格式
  • Issue #7 安全-P1(SecurityEngineer 分支未合并)
  • SeatSkuService.php 的 \think\xacade 字符损坏
## Issue #13 进度更新 — 2026-04-20 10:40 ### 本次修复 ✅ **问题**:`template_snapshot.rooms` 为空,但 `selected_rooms = ["room_1"]` 有值。 **根因**:两重 1. `empty(template_snapshot)` 对 `{"venue":{...},"rooms":[]}` 返回 false → DB 兜底被跳过 2. 模板 ID=4 可能是 v1 旧格式(无 rooms 嵌套)→ 即使触发 DB 读取也拿不到 rooms **修复**(`AdminGoodsSaveHandle.php`): - 条件改为 `empty(template_snapshot) || empty(template_snapshot[rooms])` - 新增 v1→v3 迁移:检测 sections 存在但 rooms 为空时,自动构造 v3 rooms 数组 **提交**:`3f06f36e5` ✅ 已推送 --- ### 仍需处理 - [ ] 确认模板 ID=4 实际 seat_map 格式 - [ ] Issue #7 安全-P1(SecurityEngineer 分支未合并) - [ ] SeatSkuService.php 的 `\think\xacade` 字符损坏
Poster
Owner

Issue #13 二次修复 — 2026-04-20 12:05

新发现问题

模板 ID=5 的 template_snapshot.rooms 仍为空,原因是:

  • 前端 outputBase64 根本不发送 template_snapshot(JSON 结构里没有这个字段)
  • 后端之前的条件 empty(template_snapshot){venue:{...},rooms:[]} 返回 false,DB 兜底被跳过

本次修复(合并远程冲突后的最终版本)

AdminGoodsSaveHandle.phpsave_thing_end 时机:

  • 条件升级:templateId > 0 && (selected_rooms 有值 || template_snapshot 为空 || template_snapshot.rooms 为空)
  • 从 DB 直接读取(绕过 $params[data] 值拷贝问题)
  • v1→v3 迁移保持
  • ID 匹配双向兼容:支持前端发 "room_0" 和 DB 里存 "0" 互相匹配(PHP 7.x strpos

AdminGoodsSave.php — 前端 config 加载时:

  • Set(validTemplateIds) 过滤掉软删除模板的配置,消除幽灵配置

提交da001797a 已推送

待测试

  1. 选中新场馆(模板5)→ 保存 → 重新编辑,rooms 是否正确填充
  2. 删除旧场馆(模板4)→ 编辑商品,幽灵配置是否消失
## Issue #13 二次修复 — 2026-04-20 12:05 ### 新发现问题 模板 ID=5 的 `template_snapshot.rooms` 仍为空,原因是: - 前端 `outputBase64` **根本不发送** `template_snapshot`(JSON 结构里没有这个字段) - 后端之前的条件 `empty(template_snapshot)` 对 `{venue:{...},rooms:[]}` 返回 `false`,DB 兜底被跳过 ### 本次修复(合并远程冲突后的最终版本) **AdminGoodsSaveHandle.php** — `save_thing_end` 时机: - 条件升级:`templateId > 0 && (selected_rooms 有值 || template_snapshot 为空 || template_snapshot.rooms 为空)` - 从 DB 直接读取(绕过 `$params[data]` 值拷贝问题) - v1→v3 迁移保持 - **ID 匹配双向兼容**:支持前端发 `"room_0"` 和 DB 里存 `"0"` 互相匹配(PHP 7.x `strpos`) **AdminGoodsSave.php** — 前端 config 加载时: - 用 `Set(validTemplateIds)` 过滤掉软删除模板的配置,消除幽灵配置 **提交**:`da001797a` ✅ 已推送 ### 待测试 1. 选中新场馆(模板5)→ 保存 → 重新编辑,rooms 是否正确填充 2. 删除旧场馆(模板4)→ 编辑商品,幽灵配置是否消失
Sign in to join this conversation.
No Label
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: sileya-ai/vr-shopxo-plugin#13
There is no content yet.