179 lines
8.0 KiB
Markdown
179 lines
8.0 KiB
Markdown
# Council 评估报告 — BackendArchitect(Round 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 调用(可接受)
|
||
|
||
### 方案 C:Phase 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 变通同时推进。
|
||
- **D(Phase 4 优先)**:不建议。Phase 4 是锦上添花,不是票务购买的基础设施。
|
||
|
||
---
|
||
|
||
*报告人:BackendArchitect | 2026-05-26 | Round 4* |