126 lines
4.2 KiB
Markdown
126 lines
4.2 KiB
Markdown
# vr-shopxo-plugin P0 修复执行计划 — plan.md
|
||
|
||
> 版本:v1.0 | 日期:2026-04-15 | Agent:BackendArchitect + FrontendDev
|
||
> 关联:Issue #9 | 状态:执行中
|
||
|
||
---
|
||
|
||
## 任务背景
|
||
|
||
方案 A 已全票通过(见 `council-output/ARCHITECTURE_DECISION.md`)。现在进入**执行阶段**,按优先级实施三个任务。
|
||
|
||
---
|
||
|
||
## 任务清单
|
||
|
||
- [ ] **P0-A**: `BaseService::initGoodsSpecs()` — 商品 112 最小修复集 `[Claimed: BackendArchitect]`
|
||
- [ ] **P0-B**: `SeatSkuService::BatchGenerate()` — 批量生成座位级 SKU `[Claimed: BackendArchitect]`
|
||
- [ ] **P1**: `ticket_detail.html` submit() 重构 — seat-level 逐座提交 `[Claimed: FrontendDev]`
|
||
|
||
---
|
||
|
||
## 阶段划分
|
||
|
||
| 阶段 | 内容 | 负责 |
|
||
|------|------|------|
|
||
| Draft | 各成员编写执行代码 | BackendArchitect (P0-A/P0-B), FrontendDev (P1) |
|
||
| Review | 代码互审,验证 SQL 正确性 | BackendArchitect 审 P1, FrontendDev 审 P0-A/P0-B |
|
||
| Finalize | 合并到 main,实测验证 | 所有成员 |
|
||
|
||
---
|
||
|
||
## P0-A 详细设计
|
||
|
||
**文件**: `plugins/vr_ticket/service/BaseService.php`
|
||
|
||
**方法**: `public static function initGoodsSpecs(int $goodsId): bool`
|
||
|
||
**逻辑**:
|
||
1. UPDATE `is_exist_many_spec=1` WHERE `id=$goodsId`(幂等)
|
||
2. 检查 `$vr-场馆`/`$vr-分区`/`$vr-时段` 是否存在(按 name 查 `goods_spec_type`),不存在则 INSERT
|
||
3. 使用 `INSERT IGNORE` 或 `ON DUPLICATE KEY` 防止重复
|
||
|
||
**关键 SQL**:
|
||
```sql
|
||
UPDATE sxo_goods SET is_exist_many_spec = 1 WHERE id = $goodsId;
|
||
|
||
INSERT IGNORE INTO sxo_goods_spec_type (goods_id, name, value, add_time) VALUES
|
||
($goodsId, '$vr-场馆', '[{"name":"国家体育馆","images":""}]', UNIX_TIMESTAMP()),
|
||
($goodsId, '$vr-分区', '[{"name":"A区","images":""},{"name":"B区","images":""},{"name":"C区","images":""}]', UNIX_TIMESTAMP()),
|
||
($goodsId, '$vr-时段', '[{"name":"2026-05-01 19:00","images":""}]', UNIX_TIMESTAMP());
|
||
```
|
||
|
||
**验证**: 执行后 `SELECT * FROM sxo_goods_spec_type WHERE goods_id=112` 确认 3 条 spec_type 记录。
|
||
|
||
---
|
||
|
||
## P0-B 详细设计
|
||
|
||
**文件**: `plugins/vr_ticket/service/SeatSkuService.php`(新建)
|
||
|
||
**方法**: `public static function BatchGenerate(int $goodsId, int $seatTemplateId): array`
|
||
|
||
**返回值**:
|
||
```php
|
||
[
|
||
'total' => 100, // 生成的 SKU 总数
|
||
'batch' => 1, // 批次数
|
||
'spec_base_id_map' => ['A1_1' => 2001, 'A1_2' => 2002, ...] // seatId => spec_base_id
|
||
]
|
||
```
|
||
|
||
**核心逻辑**:
|
||
1. 从 `vr_seat_template` 读取 seat_map(zones → rows → seats)
|
||
2. 从 zone 配置获取 price
|
||
3. 遍历每个座位,生成 `goods_spec_base` 行(inventory=1,price 从 zone.price 获取)
|
||
4. 同时写入 `goods_spec_value`(spec_type_id × 4 维度 = 4 行/座位)
|
||
5. **必须旁路 `GoodsSpecificationsInsert()`** — 直接 SQL INSERT
|
||
6. 分批:500 条/批,10000 座位约 20 批
|
||
|
||
**关键表结构**:
|
||
- `sxo_goods_spec_base`: id (PK auto), goods_id, spec_base, price, inventory, color, images, weight, stock
|
||
- `sxo_goods_spec_value`: id (PK auto), goods_id, spec_base_id (FK), spec_type_id (FK), `spec_value` (JSON)
|
||
|
||
**幂等**: 先 DELETE 已存在的座位级 SKU(spec_type_id IN (venue,zone,time,seat_num)),再重建。
|
||
|
||
---
|
||
|
||
## P1 详细设计(FrontendDev)
|
||
|
||
**文件**: `plugins/vr_ticket/view/goods/ticket_detail.html`
|
||
|
||
**逻辑**:
|
||
1. `submit()` 改为遍历 `this.selectedSeats`
|
||
2. 每个座位从 `app.specBaseIdMap[seatId]` 获取 `spec_base_id`
|
||
3. 构造 `goods_params` 数组,每个座位一行
|
||
4. 降级策略:`spec_base_id` 不存在时走原 Plan B 逻辑
|
||
|
||
---
|
||
|
||
## 依赖关系
|
||
|
||
- P0-A 和 P0-B 可并行开发
|
||
- P1 依赖 P0-B 完成后注入 `specBaseIdMap` 数据
|
||
- P0-A 完成后需在 ShopXO 容器实测验证
|
||
|
||
---
|
||
|
||
## Claim 状态
|
||
|
||
| 任务 | Claim 状态 |
|
||
|------|-----------|
|
||
| P0-A | [Claimed: BackendArchitect] |
|
||
| P0-B | [Claimed: BackendArchitect] |
|
||
| P1 | [Claimed: FrontendDev] |
|
||
|
||
---
|
||
|
||
## 执行顺序
|
||
|
||
1. BackendArchitect: P0-A 代码 + SQL 验证
|
||
2. BackendArchitect: P0-B SeatSkuService::BatchGenerate()
|
||
3. FrontendDev: P1 submit() 重构
|
||
4. BackendArchitect: 合并到 main
|
||
5. 容器实测:商品 112 `initGoodsSpecs(112)` → 验证 is_exist_many_spec=1 + 3条spec_type
|
||
6. 容器实测:`BatchGenerate(112, $templateId)` → 验证座位级 SKU 生成
|