docs: Issue #7 重新评估 — 修正超卖防护错误描述
全面核实后发现: - M-04 loadSoldSeats() ✅ 已实现(seatSpecMap.inventory,无需API) - M-01 TOCTOU ✅ 已修复(FOR UPDATE + 事务) - M-08 issueTicket二次写入 ✅ 已修复 更新了12个文档的错误描述: - PHASE_4_PLAN.md: M-04从'未实现'→'已实现' - PHASE2_PLAN.md: 安全问题状态同步 - SPEC_SELECTOR_DESIGN.md: loadSoldSeats P2→已完成 - SPEC_DESIGN_DECISION.md: M-04备注更新 - DEVELOPMENT_LOG.md: loadSoldSeats两处状态更新 - FULL_PLAN.md: Issue 3标记已完成 - 14_TEMPLATE_RENDER_INVESTIGATION.md: loadSoldSeats TODO→已完成 - PLAN_PHASE3_FRONTEND.md: loadSoldSeats P1→已完成 - PLAN_PHASE3_EXECUTION.md: loadSoldSeats无实现→已实现 - AGENT_PROMPT.md: sold_seats API→已完成 - council-research-output.md: loadSoldSeats待实现→已实现 - 08_SHOPXO_REQUIREMENTS_MAPPING.md: 标记为已过时文档 Issue #7追加详细重新评估报告(M-01/04/08已修复,M-02/05/06 B端时处理,M-03快速,M-07低风险)feat/phase-b-verification
parent
dcf7354473
commit
a647b6f37f
|
|
@ -1,5 +1,8 @@
|
||||||
# vr-shopxo-plugin 需求对照分析
|
# vr-shopxo-plugin 需求对照分析
|
||||||
|
|
||||||
|
> ⚠️ **本文档已过时**。本文档描述的早期设计(独立 vr_events/vr_sessions 表、支付回调自建等)已被废弃。
|
||||||
|
> 当前实现使用 ShopXO 原生 BuyService + vr_tickets 单表方案,详见 ARCHITECTURE.md 和 PHASE_4_PLAN.md。
|
||||||
|
>
|
||||||
> ShopXO 插件机制 vs VR 演唱会票务需求
|
> ShopXO 插件机制 vs VR 演唱会票务需求
|
||||||
> 基于 shopxo-plugin-dev.md 整理
|
> 基于 shopxo-plugin-dev.md 整理
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ if (($goods['item_type'] ?? '') === 'ticket') {
|
||||||
**已知待解决问题(P1):**
|
**已知待解决问题(P1):**
|
||||||
1. `{include}` 标签在容器内是否能正确解析到 ShopXO 公共模板
|
1. `{include}` 标签在容器内是否能正确解析到 ShopXO 公共模板
|
||||||
2. `plugins_service_goods_spec_data` 钩子 vr_ticket 未实现
|
2. `plugins_service_goods_spec_data` 钩子 vr_ticket 未实现
|
||||||
3. `loadSoldSeats()` 函数为空(TODO)
|
3. `loadSoldSeats()` ✅ 已实现(seatSpecMap.inventory 反推已售座位)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ VR 演唱会票务微信小程序插件。用户选座 → 填观演人 → 微
|
||||||
|
|
||||||
5. **前端**:`ticket_detail.html` 新增场次/场馆/分区选择器 UI + `filterSeatMap()` 联动过滤
|
5. **前端**:`ticket_detail.html` 新增场次/场馆/分区选择器 UI + `filterSeatMap()` 联动过滤
|
||||||
6. **前端**:缩放时舞台跟随(zoom wrapper 方案)
|
6. **前端**:缩放时舞台跟随(zoom wrapper 方案)
|
||||||
7. **后端**:新增 `sold_seats` API 端点 + 前端 `loadSoldSeats()` 调用
|
7. **前端**:`loadSoldSeats()` ✅ 已实现(seatSpecMap.inventory,无需后端 API)
|
||||||
|
|
||||||
### P2
|
### P2
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -435,7 +435,7 @@ dc63cff77 chore: clean up my_test_plugin residual hooks
|
||||||
| 任务 | 状态 |
|
| 任务 | 状态 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| 模板渲染实测(容器内) | ⚠️ 待大头操作 |
|
| 模板渲染实测(容器内) | ⚠️ 待大头操作 |
|
||||||
| loadSoldSeats() 实现 | ❌ 未开始 |
|
| loadSoldSeats() 实现 | ✅ 已实现(seatSpecMap.inventory,ShopXO原生) |
|
||||||
| vr_ticket Hook.php 补充 | ❌ 未开始 |
|
| vr_ticket Hook.php 补充 | ❌ 未开始 |
|
||||||
| 4 个后台控制器联调 | ❌ 未开始 |
|
| 4 个后台控制器联调 | ❌ 未开始 |
|
||||||
| 核销 API | ❌ 未开始 |
|
| 核销 API | ❌ 未开始 |
|
||||||
|
|
@ -503,7 +503,7 @@ c894e7018 fix: 复制 ShopXO public 模板
|
||||||
| 重写 GetGoodsViewData() 适配新格式 | 待定 | VR_GOODS_CONFIG_SPEC.md 已确认 |
|
| 重写 GetGoodsViewData() 适配新格式 | 待定 | VR_GOODS_CONFIG_SPEC.md 已确认 |
|
||||||
| 更新 ticket_detail.html JS(rooms[] 结构) | 待定 | GetGoodsViewData() 输出确定后 |
|
| 更新 ticket_detail.html JS(rooms[] 结构) | 待定 | GetGoodsViewData() 输出确定后 |
|
||||||
| AdminGoodsSaveHandle SKU 生成 | 待定 | 新格式已确认 |
|
| AdminGoodsSaveHandle SKU 生成 | 待定 | 新格式已确认 |
|
||||||
| loadSoldSeats() 实现 | 待定 | vr_tickets 有数据后 |
|
| loadSoldSeats() 实现 | ✅ 已实现(见 ticket_detail.html,seatSpecMap.inventory) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ seatKey 对应 `GoodsSpecBase.extends.seat_key`,用于关联 GoodsSpecBase 和
|
||||||
|---|------|--------|------|
|
|---|------|--------|------|
|
||||||
| Issue 1 | 购买提交流程失效(GET→POST 机制错误 + spec 格式错误 + 缺 seatSpecMap) | **P0** | 待修复 |
|
| Issue 1 | 购买提交流程失效(GET→POST 机制错误 + spec 格式错误 + 缺 seatSpecMap) | **P0** | 待修复 |
|
||||||
| Issue 2 | 缩放时舞台不跟随 | **P1** | 待修复 |
|
| Issue 2 | 缩放时舞台不跟随 | **P1** | 待修复 |
|
||||||
| Issue 3 | spec 加载(loadSoldSeats 空 stub + 无 sold_seats API) | **P1** | 待修复 |
|
| ~~Issue 3~~ | ~~spec 加载(loadSoldSeats 空 stub + 无 sold_seats API)~~ ✅ | **已完成** | seatSpecMap.inventory 反推已售座位,ShopXO原生防超卖 |
|
||||||
| Issue 4 | 商品详情/图片加载 | **P2** | 待修复 |
|
| Issue 4 | 商品详情/图片加载 | **P2** | 待修复 |
|
||||||
| Issue 5 | GetGoodsViewData 只返回第一个场次 | **P2** | 待修复 |
|
| Issue 5 | GetGoodsViewData 只返回第一个场次 | **P2** | 待修复 |
|
||||||
|
|
||||||
|
|
@ -633,7 +633,7 @@ submit() POST goods_data(含 4维spec + extension_data)
|
||||||
| **P1** | Issue 1 | `selectSession()` / `selectVenue()` / `selectSection()` 联动逻辑 | P1 前置 | FrontendDev |
|
| **P1** | Issue 1 | `selectSession()` / `selectVenue()` / `selectSection()` 联动逻辑 | P1 前置 | FrontendDev |
|
||||||
| **P1** | Issue 2 | 缩放时舞台跟随(zoom wrapper 方案) | 无 | FrontendDev |
|
| **P1** | Issue 2 | 缩放时舞台跟随(zoom wrapper 方案) | 无 | FrontendDev |
|
||||||
| **P1** | Issue 3 | 新增 `sold_seats` API 端点 | 无 | BackendArchitect |
|
| **P1** | Issue 3 | 新增 `sold_seats` API 端点 | 无 | BackendArchitect |
|
||||||
| **P1** | Issue 3 | 前端 `loadSoldSeats()` 调用 API + 标记 `.sold` | P1 前置 | FrontendDev |
|
| ~~**P1**~~ | ~~Issue 3~~ | ~~前端 `loadSoldSeats()` 调用 API + 标记 `.sold`~~ ✅ | 已完成 | seatSpecMap.inventory 前端推导,无需额外API | FrontendDev |
|
||||||
| **P2** | Issue 4 | 商品详情图片展示(确认需求,补充 CSS) | 无 | FrontendDev |
|
| **P2** | Issue 4 | 商品详情图片展示(确认需求,补充 CSS) | 无 | FrontendDev |
|
||||||
| **P2** | Issue 5 | `GetGoodsViewData()` 返回数组而非 `validConfigs[0]` | 无 | BackendArchitect |
|
| **P2** | Issue 5 | `GetGoodsViewData()` 返回数组而非 `validConfigs[0]` | 无 | BackendArchitect |
|
||||||
| **P2** | 审计 | 验证 `onOrderPaid` spec 匹配 + 幂等保护(FOR UPDATE) | 无 | BackendArchitect |
|
| **P2** | 审计 | 验证 `onOrderPaid` spec 匹配 + 幂等保护(FOR UPDATE) | 无 | BackendArchitect |
|
||||||
|
|
|
||||||
|
|
@ -77,4 +77,4 @@ var specBaseId = self.specBaseIdMap[seatKey] || 0;
|
||||||
| Issue #13 实现(v3.0 落地) | ⚠️ 待动手 |
|
| Issue #13 实现(v3.0 落地) | ⚠️ 待动手 |
|
||||||
| B端核销 API + 页面 | ❌ 未开始(Issue #21 状态有误,已关闭,正确状态见 Issue #22) |
|
| B端核销 API + 页面 | ❌ 未开始(Issue #21 状态有误,已关闭,正确状态见 Issue #22) |
|
||||||
| 后台 4 控制器联调 | ❌ 未开始 |
|
| 后台 4 控制器联调 | ❌ 未开始 |
|
||||||
| Issue #7 安全问题(M-04/M-06优先) | ⚠️ B端开发前必须处理 |
|
| Issue #7 安全问题(M-04/M-06优先) | ⚠️ M-04/M-01/M-08已修复,M-06为B端前置,其余B端开发时处理 |
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
> 规划日期:2026-04-22
|
> 规划日期:2026-04-22
|
||||||
> 最后更新:2026-04-25(JsBarcode本地化修复 + 状态追踪重置)
|
> 最后更新:2026-04-25(JsBarcode本地化修复 + 状态追踪重置)
|
||||||
> 状态:**Phase 4.1/4.2/4.3 完成,B端核销待开发,安全问题M-04/M-06优先**
|
> 状态:**Phase 4.1/4.2/4.3 完成,B端核销待开发,M-06权限为B端前置**
|
||||||
> 进度追踪:[Issue #22](http://xmhome.gitop.top:3000/sileya-ai/vr-shopxo-plugin/issues/22) | 安全问题:[Issue #7](http://xmhome.gitop.top:3000/sileya-ai/vr-shopxo-plugin/issues/7)(全未修复)
|
> 进度追踪:[Issue #22](http://xmhome.gitop.top:3000/sileya-ai/vr-shopxo-plugin/issues/22) | 安全问题:[Issue #7](http://xmhome.gitop.top:3000/sileya-ai/vr-shopxo-plugin/issues/7)(全未修复)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -505,9 +505,13 @@ Phase 4.3 — C端票夹 ✅(2026-04-24)
|
||||||
├─ QR本地缓存逻辑 ✅
|
├─ QR本地缓存逻辑 ✅
|
||||||
└─ JsBarcode本地化 ✅(2026-04-25,cdn.jsdelivr → ShopXO自带)
|
└─ JsBarcode本地化 ✅(2026-04-25,cdn.jsdelivr → ShopXO自带)
|
||||||
|
|
||||||
**⚠️ 安全问题先修(Issue #7,全未修复)**:
|
**⚠️ 安全问题(Issue #7,已重新评估 2026-04-25)**:
|
||||||
├─ M-04: loadSoldSeats()未实现 → 超卖风险 ✅
|
├─ M-01 ✅ 已修复(FOR UPDATE + 事务)
|
||||||
└─ M-06: Admin控制器无权限校验 → B端安全基线
|
├─ M-04 ✅ 已实现(seatSpecMap.inventory 反推已售座位,ShopXO原生防超卖)
|
||||||
|
├─ M-08 ✅ 已修复(无占位符写入)
|
||||||
|
├─ M-03 🟢 快速修复(ALTER TABLE条件bug,2行)
|
||||||
|
├─ M-07 🟢 低风险(QR payload无害)
|
||||||
|
└─ M-02/M-05/M-06 ⚠️ B端开发时处理(M-06为B端安全基线)
|
||||||
|
|
||||||
Phase 4.4 — B端核销 ❌ 未开始
|
Phase 4.4 — B端核销 ❌ 未开始
|
||||||
├─ admin/controller/Ticket.php: verifySubmit
|
├─ admin/controller/Ticket.php: verifySubmit
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
| 文件 | 当前状态 | 问题 |
|
| 文件 | 当前状态 | 问题 |
|
||||||
|------|---------|------|
|
|------|---------|------|
|
||||||
| `ticket_detail.html` | Plan A 代码有 bug | `submit()` URL 编码只传第一座、`selectSession()` 未重置座位 |
|
| `ticket_detail.html` | Plan A 代码有 bug | `submit()` URL 编码只传第一座、`selectSession()` 未重置座位 |
|
||||||
| `ticket_detail.html` | 桩代码 | `loadSoldSeats()` 无实现 |
|
| `ticket_detail.html` | ✅ 已实现 | `loadSoldSeats()` 使用 seatSpecMap.inventory 反推已售座位 |
|
||||||
| `ticket_detail.html` | 内联样式 | CSS 未分离,色值硬编码 |
|
| `ticket_detail.html` | 内联样式 | CSS 未分离,色值硬编码 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ ticket_detail.html
|
||||||
|
|
||||||
- `ticket_detail.html` 已有 Plan A 代码(submit 函数存在 URL 编码 bug)
|
- `ticket_detail.html` 已有 Plan A 代码(submit 函数存在 URL 编码 bug)
|
||||||
- 座位图渲染正常(A/B/C 三排 + 舞台 + 颜色分区 + 选座 UI + 观演人表单)
|
- 座位图渲染正常(A/B/C 三排 + 舞台 + 颜色分区 + 选座 UI + 观演人表单)
|
||||||
- `loadSoldSeats()` 是 TODO,需要后端配合
|
- `loadSoldSeats()` ✅ 已实现(seatSpecMap.inventory,无需后端 API)
|
||||||
|
|
||||||
### Demo 交付清单
|
### Demo 交付清单
|
||||||
|
|
||||||
|
|
@ -138,7 +138,7 @@ ticket_detail.html
|
||||||
|
|
||||||
| 任务 | 文件 | 说明 | 优先级 |
|
| 任务 | 文件 | 说明 | 优先级 |
|
||||||
|------|------|------|--------|
|
|------|------|------|--------|
|
||||||
| **loadSoldSeats() 实现** | `ticket_detail.html` + 后端 | AJAX 调用后端接口,标记已售座位 | 🟡 P1 |
|
| ~~**loadSoldSeats() 实现**~~ ✅ | `ticket_detail.html` + 前端 seatSpecMap | seatSpecMap.inventory 反推已售座位,无需后端 | 已完成 |
|
||||||
| **座位图缩放/拖拽交互** | `ticket_detail.html` | 原生 JS < 200 行实现 | 🟡 P1 |
|
| **座位图缩放/拖拽交互** | `ticket_detail.html` | 原生 JS < 200 行实现 | 🟡 P1 |
|
||||||
| **CSS 样式文件分离** | `static/vr_ticket/css/ticket.css` | 从内联 `<style>` 抽离,通过 `plugins_css_data` 钩子注册 | 🟡 P1 |
|
| **CSS 样式文件分离** | `static/vr_ticket/css/ticket.css` | 从内联 `<style>` 抽离,通过 `plugins_css_data` 钩子注册 | 🟡 P1 |
|
||||||
| **甲方主题色变量接入** | `ticket_detail.html` <style> | 将硬编码色值改为 `var(--color-main)` 等变量 | 🟡 P1 |
|
| **甲方主题色变量接入** | `ticket_detail.html` <style> | 将硬编码色值改为 `var(--color-main)` 等变量 | 🟡 P1 |
|
||||||
|
|
|
||||||
|
|
@ -86,4 +86,4 @@ BuyService.php:94 GoodsSpecificationsHandle($v)
|
||||||
|
|
||||||
## 关联
|
## 关联
|
||||||
- Issue #6:P0-2 价格验证(相关)
|
- Issue #6:P0-2 价格验证(相关)
|
||||||
- Issue #7:M-04 loadSoldSeats 未实现(取决于 SPEC 方向)
|
- Issue #7:M-04 loadSoldSeats ✅ 已实现(seatSpecMap.inventory 反推已售座位,ShopXO原生防超卖)
|
||||||
|
|
|
||||||
|
|
@ -332,4 +332,4 @@ ShopXO 的 `GoodsSpecificationsHandle` 通过 4 个 type-value 组合在 GoodsSp
|
||||||
| P0 | `submit()` 使用 `seatSpecMap[seatKey].spec` | 前端 |
|
| P0 | `submit()` 使用 `seatSpecMap[seatKey].spec` | 前端 |
|
||||||
| P1 | 实现场次/场馆/分区选择器 UI + 联动逻辑 | 前端 |
|
| P1 | 实现场次/场馆/分区选择器 UI + 联动逻辑 | 前端 |
|
||||||
| P1 | `filterSeatMap()` 实现灰色/隐藏过滤 | 前端 |
|
| P1 | `filterSeatMap()` 实现灰色/隐藏过滤 | 前端 |
|
||||||
| P2 | `loadSoldSeats()` → 使用 `seatSpecMap` + inventory 字段 | 前端 |
|
| ~~P2~~ ✅ | `loadSoldSeats()` → 使用 `seatSpecMap` + inventory 字段 | 前端(已完成,2026-04前) |
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ plugins_service_buy_group_goods_handle:
|
||||||
|
|
||||||
**H5 端**:在现有 `ticket_detail.html` 基础上增强,引入:
|
**H5 端**:在现有 `ticket_detail.html` 基础上增强,引入:
|
||||||
- 座位类型图例(已完成)
|
- 座位类型图例(已完成)
|
||||||
- 已售座位 AJAX 实时标记(待实现 `loadSoldSeats()`)
|
- 已售座位 ✅ 已实现(`loadSoldSeats()` 使用 seatSpecMap.inventory,无需AJAX)
|
||||||
- 座位缩放/拖拽交互(原生 JS,<200 行)
|
- 座位缩放/拖拽交互(原生 JS,<200 行)
|
||||||
- 动态场次切换时重置已选座位(已写但未调用)
|
- 动态场次切换时重置已选座位(已写但未调用)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue