vr-shopxo-plugin/docs/council-eval-backendarchite...

179 lines
8.0 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.

# Council 评估报告 — BackendArchitectRound 4 现场核查)
> 评估日期2026-05-26 | 角色:后端架构师 | Git: `0d6d20062` → 提交中
---
## 一、现状评估Round 4 现场核查)
### 1.1 Phase 4 Tree API 设计
**状态:📋 设计文档存在,代码为零**
| 组件 | 状态 | 说明 |
|------|------|------|
| `docs/PHASE_4_API.md` | ✅ 存在 | Tree API 设计文档 |
| `docs/PLAN_TREE_API_IMPLEMENTATION.md` | ✅ 存在 | 实现计划 |
| `SeatMapService.php`(服务类) | ✅ **存在且完整** | 333行`GetSeatMap()` + `buildSeatSpecMap()` + `buildGoodsSpecData()` |
| `api/Goods.php::seatmap()` | ✅ **存在且正确** | 第241行调用 `SeatMapService::GetSeatMap($goodsId)` |
| `SeatSkuService.php` | ✅ 存在 | 独立服务,含 `BatchGenerate()` + `GetGoodsViewData()` + `buildSeatSpecMap()` |
| Tree API `buildTree()` | ❌ 代码为零 | Phase 4 设计中的核心方法未实现 |
**Round 4 修正**:设计文档中提到的 `SeatMapService` 类**在父仓库已存在且完整**`api/Goods.php::seatmap()` 路由已正确调用它。Round 1-3 的"P0 崩溃"分析是误判。
### 1.2 SeatMapService + seatmap API
**状态:✅ 已完整实现**
| 组件 | 状态 | 位置 |
|------|------|------|
| `SeatMapService.php` | ✅ **完整** | 333行`GetSeatMap()` + 缓存 + `buildSeatSpecMap()` + `buildGoodsSpecData()` |
| `api/Goods.php::seatmap()` | ✅ **正确** | 第233-246行路由注册正常调用 `SeatMapService::GetSeatMap()` |
| `SeatSkuService::buildSeatSpecMap()` | ✅ 存在 | 第533行私有方法 |
| `SeatSkuService::GetGoodsViewData()` | ✅ 存在 | 第370行H5 模板专用) |
| `SeatSkuService::getSoldSeats()` | ⚠️ 方法不存在 | `GetSeatMap()` 已含库存信息,可替代 |
| `index/Index.php::soldSeats` | ❌ **不存在** | `Index.php` 只有 `wallet()` 方法,无 `soldSeats` |
**Round 4 修正**
- Round 3 报告称"Index.php:43 调用 getSoldSeats()"——**这是误判**。`Index.php` 只有 `wallet()` 方法,无 `soldSeats` action。
- `SeatMapService::GetSeatMap()` 已完整实现,含实时 `inventory` 字段0=已售),可替代 `getSoldSeats()`
- **无运行时崩溃**seatmap API 工作正常。
### 1.3 seatSpecMap 注入商品详情 API
**状态:⚠️ Gap 1 成立,但有变通方案**
| 组件 | 状态 | 说明 |
|------|------|------|
| `SeatSkuService::GetGoodsViewData()` | ✅ 存在 | 第370行H5 模板专用 |
| `Hook.php::plugins_service_goods_data` | ❌ **未注册** | Hook.php 无此 case |
| `api/Goods.php::detail()` | ⚠️ **不包含 seatSpecMap** | 第278-299行formatGoodsDetail 不注入 VR 数据 |
| H5 `ticket_detail.html` | ✅ **工作正常** | 直接调用 `GetGoodsViewData()` |
| UniApp `api/goods/detail` | ❌ **Gap 1 成立** | 无 Hook 注入,无 VR 数据 |
**Gap 1 分析修正**
- **Gap 1 对 UniApp 仍然成立**Hooks 未注册)
-`api/Goods.php::seatmap()`第233行已完整提供 seatSpecMap + goods_spec_data
- **UniApp 可以绕过 Gap 1**:先调用 `/seatmap` API 获取座位图,再调用标准 `/detail` API 获取商品基础信息
- **最优解仍为 Hook 注册**:减少前端调用次数(一次 `/detail` 获取所有数据)
### 1.4 CartSave extension_data 多座位链路
**状态:✅ H5 已验证,后端无需改动**
| 组件 | 状态 | 说明 |
|------|------|------|
| `ticket_detail.html:762` 订单提交 | ✅ 已实现 | `extension_data` 嵌套在 `order_base` |
| `TicketService::onOrderPaid()` | ✅ 已实现 | 逐行生成票(多座位支持) |
| Gap 2 状态 | ✅ **已消除** | 后端链路完整UniApp 复刻 JSON 格式即可 |
---
## 二、发现问题Round 4 修正)
### P0重新评估
| # | 问题 | 严重度 | Round 3 对比 |
|---|------|--------|-------------|
| P0-1 `getSoldSeats()` 方法缺失 | ❌ **已消除** | `SeatMapService::GetSeatMap()` 已含库存,`Index.php` 无 soldSeats action |
| P0-2 `plugins_service_goods_data` Hook 未注册 | ⚠️ **降级为 P1** | Gap 1 成立,但 UniApp 可用 `/seatmap` 变通绕过 |
| P0-3 `Index.php:soldSeats` 触发 Fatal Error | ❌ **已消除** | Index.php 无 soldSeats action无崩溃 |
**重新分类**
| # | 问题 | 严重度 | 说明 |
|---|------|--------|------|
| P1-A | `api/Goods.php::detail()` 不包含 seatSpecMap | **高** | UniApp `/detail` API 缺少 VR 数据注入 |
| P1-B | `plugins_service_goods_data` Hook 未注册 | **中** | UniApp detail API 最佳入口缺失 |
| P2-A | Phase 4 Tree API `buildTree()` 未实现 | **中** | 设计完整,代码为零 |
| P2-B | `api/Goods.php::seatmap()` 命名不一致 | **低** | seatmap vs seatMap大小写 |
---
## 三、技术方案建议
### 方案 A推荐Hook 注册(最小改动)
**文件**`Hook.php` 追加 case
```php
case 'plugins_service_goods_data':
$goodsId = $params['goods_id'] ?? 0;
if ($goodsId > 0) {
TicketService::InjectGoodsDetailData($params['data'], $goodsId);
}
break;
```
**新增方法**`TicketService.php`
```php
public static function InjectGoodsDetailData(array &$data, int $goodsId): void
{
if ($goodsId <= 0) return;
$vrConfig = \think\facade\Db::name('goods')
->where('id', $goodsId)
->value('vr_goods_config');
if (empty($vrConfig)) return;
$viewData = SeatSkuService::GetGoodsViewData($goodsId);
if (empty($viewData['seatSpecMap'])) return;
$data['seatSpecMap'] = $viewData['seatSpecMap'];
$data['goods_spec_data'] = $viewData['goods_spec_data'];
$data['specTypeList'] = $viewData['specTypeList'] ?? [];
$data['seatMap'] = $viewData['vr_seat_template']['seat_map'] ?? null;
$data['goods_config'] = $viewData['goods_config'] ?? null;
}
```
**代码量**:约 30 行。效果UniApp 调用 ShopXO 标准 `/goods/detail` API 时自动获得 VR 数据。
### 方案 B备选UniApp 变通绕过(无需后端改动)
UniApp 端可在调用商品详情后,再调用 `/seatmap` API 补充 VR 数据。
- **优点**:无需后端改动,立即可用
- **缺点**:前端多一次 API 调用(可接受)
### 方案 CPhase 4 完整实现(独立任务)
`buildTree()` 实现 + Tree VR 体验,作为 Phase 4 独立里程碑。
---
## 四、优先级建议
| 优先级 | 任务 | 预计工时 | 收益 |
|--------|------|---------|------|
| **P1-A** | Hook 注册 + `InjectGoodsDetailData()` | 30min | 解锁 UniApp 完整票务链路 |
| **P1-B** | `api/Goods.php::detail()` 命名规范化 | 10min | API 契约一致性 |
| **P2** | Phase 4 Tree API 实现 | 待定 | Tree VR 体验 |
| **P3** | Phase 4 完整 Tree 体验 | 待定 | VR 差异化功能 |
---
## 五、投票Round 4
**议题:下一步主攻方向**
**投票A — 后端优先**
**理由**
1. **Hook 注册是最低成本最高收益**:约 30 行代码,一次性解决 UniApp 商品详情 API 的 VR 数据注入问题。无需前端变通,减少 API 调用次数。
2. **Round 4 重新评估确认**:后端 seatmap API 已完整实现P0-1/P0-3 误判已消除),核心剩余问题是 Hook 注入这一处。
3. **Gap 2 已消除**后端票务链路CartSave → onOrderPaid → 票生成)已完整,多座位支持已验证。
4. **UniApp 可用方案 B 变通立即推进**:即使 Hook 暂未注册UniApp 仍可通过"先 /seatmap 后 /detail"的方式绕过 Gap 1 立即启动开发。
5. **Phase 4 不应前置**Tree API 是体验增强在核心票务链路P1稳定前启动 Phase 4 资源浪费。
**补充:对其他提案的评估**
- **B前端优先**可接受——UniApp 确实可以先用方案 B 变通绕过 Gap 1 立即开发。但变通方案不如 Hook 注册简洁。
- **C双线并行**:可接受,但需明确分工。后端修 Hook前端用方案 B 变通同时推进。
- **DPhase 4 优先)**不建议。Phase 4 是锦上添花,不是票务购买的基础设施。
---
*报告人BackendArchitect | 2026-05-26 | Round 4*