docs: 追加幽灵 spec 修复记录 (DEVELOPMENT_LOG.md 更新)
parent
2311f17b90
commit
dbd62f5658
|
|
@ -720,3 +720,61 @@ if (empty($room['id'])) {
|
|||
- 大头明确说了"不用了"、"可以 git 提交了"之后,西莉雅因为读到了 subagent 的报告,误以为还需要继续工作,额外 apply 了补丁
|
||||
- **行动准则**:当大头说"可以提交了",意味着他认为工作已完成,此时不应再基于其他报告引入新改动——除非他明确说"还有问题"
|
||||
- 本次修复的 `is_delete` → `is_delete_time` 是正确且必要的,但触发点是错误的(源于对大头的意图误判)
|
||||
|
||||
---
|
||||
|
||||
## 2026-04-20 晚 — 幽灵 Spec 问题修复(Issue #15 + #16)
|
||||
|
||||
### 问题现象
|
||||
|
||||
编辑票务商品时,若商品关联的场馆模板已被硬删除,提交保存时触发「规格不允许重复」错误。幽灵 spec 块累积,无法自动清除。
|
||||
|
||||
### 调研过程
|
||||
|
||||
1. **Council 调研**(BackendArchitect + FrontendDev + SecurityEngineer 并行)
|
||||
- 根因:`AdminGoodsSaveHandle.php:89` 的 `continue` 跳过 snapshot 重建但不移除无效 config 块
|
||||
- Council 修复:`unset($configs[$i])` + 写回前判空
|
||||
|
||||
2. **大头 antigravity 独立验证**(`reports/GHOST_SPEC_INVESTIGATION_REPORT.md`)
|
||||
- 确认 Council 结论正确
|
||||
- 关键发现:`save_thing_end` 从 DB 读旧数据(`$goodsRow['vr_goods_config']`),前端过滤后的数据(`$data['vr_goods_config']`)只是 fallback
|
||||
- **补充修复**:调换读取优先级(`$data` 优先,DB 兜底)
|
||||
|
||||
3. **西莉雅 Plan 审查**(`docs/PLAN_GHOST_SPEC_FIX.md`)
|
||||
- 认可报告结论
|
||||
- 确认 Plan 的两层修复方案:主要修复(读取优先级)+ 防御层(unset + 判空)
|
||||
- Issue #15 + #16 方案确认
|
||||
|
||||
### 修复内容
|
||||
|
||||
**Issue #15 — AdminGoodsSaveHandle.php(三步)**
|
||||
|
||||
| 步骤 | 行号 | 修改内容 |
|
||||
|------|------|---------|
|
||||
| 读取优先级调换 | 61-65 | `$data['vr_goods_config']` 优先,DB 兜底 |
|
||||
| 无效 config 块移除 | 89 | `unset($configs[$i])` |
|
||||
| 重排索引 + 写回判空 | 145-150 | `array_values` 重排 + `if (!empty($configs))` |
|
||||
|
||||
**Issue #16 — SeatSkuService.php GetGoodsViewData(两步)**
|
||||
|
||||
| 步骤 | 行号 | 修改内容 |
|
||||
|------|------|---------|
|
||||
| 多模板过滤 | 368-383 | 遍历所有配置块过滤有效块;若全部无效返回 null |
|
||||
| 模板不存在时清理 | 394-415 | 清理无效块并写回有效配置(而非覆盖) |
|
||||
|
||||
### Git Commit
|
||||
|
||||
```
|
||||
2311f17b9 fix(vr_ticket): 修复幽灵 spec 问题 (Issue #15 + #16)
|
||||
```
|
||||
|
||||
### Issue 关闭
|
||||
|
||||
- **Issue #15** → closed(save_thing_end 脏数据写回)
|
||||
- **Issue #16** → closed(GetGoodsViewData 单模板模式)
|
||||
|
||||
### 验收状态
|
||||
|
||||
- ✅ antigravity 测试通过(基本没问题)
|
||||
- ✅ 西莉雅代码审查通过(读取优先级 + 防御层双重保障)
|
||||
- ✅ 多模板模式修复验证
|
||||
|
|
|
|||
|
|
@ -0,0 +1,150 @@
|
|||
# Plan: 幽灵 Spec 问题修复
|
||||
|
||||
> 日期:2026-04-20 | Issue: #15 + #16 | 状态:待实施
|
||||
|
||||
---
|
||||
|
||||
## 问题概览
|
||||
|
||||
| Issue | 问题 | 优先级 | 根因文件 |
|
||||
|--------|------|--------|---------|
|
||||
| #15 | save_thing_end 脏数据写回 | P1 | AdminGoodsSaveHandle.php |
|
||||
| #16 | GetGoodsViewData 单模板模式 | P1 | SeatSkuService.php |
|
||||
|
||||
---
|
||||
|
||||
## Issue #15 — save_thing_end 脏数据写回
|
||||
|
||||
### 根因
|
||||
|
||||
`AdminGoodsSaveHandle.php` 第 60-65 行:DB 值优先(`$goodsRow['vr_goods_config']`),前端过滤后的值(`$data['vr_goods_config']`)只是 fallback。脏 config 块(含已删除场馆的 template_id)被写回 DB,幽灵 spec 累积。
|
||||
|
||||
### 修复计划
|
||||
|
||||
#### 步骤 1:调换读取优先级(主要修复)
|
||||
|
||||
**文件**:`shopxo/app/plugins/vr_ticket/hook/AdminGoodsSaveHandle.php`
|
||||
**行号**:第 60-65 行
|
||||
|
||||
```php
|
||||
// 修改前
|
||||
$rawConfig = is_array($goodsRow) ? ($goodsRow['vr_goods_config'] ?? '') : '';
|
||||
if (empty($rawConfig)) {
|
||||
$rawConfig = $data['vr_goods_config'] ?? '';
|
||||
}
|
||||
|
||||
// 修改后(主要修复)
|
||||
// 前端已过滤无效 template_id,优先使用 data。若无前端数据再 fallback 到 DB
|
||||
if (!empty($data['vr_goods_config'])) {
|
||||
$rawConfig = $data['vr_goods_config'];
|
||||
} else {
|
||||
$rawConfig = is_array($goodsRow) ? ($goodsRow['vr_goods_config'] ?? '') : '';
|
||||
}
|
||||
```
|
||||
|
||||
**验证**:
|
||||
- 提交后 `git diff` 确认读取顺序调换
|
||||
- `git status` 确认只有 AdminGoodsSaveHandle.php 被修改
|
||||
|
||||
#### 步骤 2:无效 config 块移除(防御层)
|
||||
|
||||
**文件**:同上
|
||||
**行号**:第 88-89 行
|
||||
|
||||
```diff
|
||||
if (empty($template)) {
|
||||
- continue;
|
||||
+ unset($configs[$i]); // 移除无效 config 块
|
||||
+ continue;
|
||||
}
|
||||
```
|
||||
|
||||
**行号**:第 145 行(`unset($config);` 之后)
|
||||
|
||||
```php
|
||||
$configs = array_values($configs); // 重排数组索引
|
||||
```
|
||||
|
||||
**验证**:
|
||||
- grep 确认 `unset($configs[$i])` 在第 89 行附近
|
||||
- grep 确认 `array_values` 在 `unset($config)` 之后
|
||||
|
||||
#### 步骤 3:写回前判空(防御层)
|
||||
|
||||
**行号**:第 148 行之前
|
||||
|
||||
```diff
|
||||
+ if (!empty($configs)) {
|
||||
Db::name('Goods')->where('id', $goodsId)->update([
|
||||
'vr_goods_config' => json_encode($configs, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
|
||||
]);
|
||||
+ }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Issue #16 — GetGoodsViewData 单模板模式
|
||||
|
||||
### 根因
|
||||
|
||||
`SeatSkuService.php` 第 368 行:只取 `$vrGoodsConfig[0]`(第一个配置块)。多模板商品时其余配置块被完全忽略;写回时只写 `[$config]` 单元素,可能覆盖其他有效配置块。
|
||||
|
||||
### 修复计划
|
||||
|
||||
#### 步骤 1:过滤有效配置块
|
||||
|
||||
**文件**:`shopxo/app/plugins/vr_ticket/service/SeatSkuService.php`
|
||||
**行号**:第 365-373 行(在 `$config = $vrGoodsConfig[0];` 之前)
|
||||
|
||||
```php
|
||||
// 过滤有效配置块
|
||||
$validConfigs = [];
|
||||
foreach ($vrGoodsConfig as $cfg) {
|
||||
$tid = intval($cfg['template_id'] ?? 0);
|
||||
if ($tid <= 0) continue;
|
||||
$tpl = Db::name(self::table('seat_templates'))->where('id', $tid)->find();
|
||||
if (!empty($tpl)) {
|
||||
$validConfigs[] = $cfg;
|
||||
}
|
||||
}
|
||||
if (empty($validConfigs)) {
|
||||
return ['vr_seat_template' => null, 'goods_spec_data' => [], 'goods_config' => null];
|
||||
}
|
||||
$config = $validConfigs[0]; // 取第一个有效配置块用于前端展示
|
||||
```
|
||||
|
||||
#### 步骤 2:修改写回逻辑
|
||||
|
||||
**行号**:第 386-388 行(原写回 `[$config]`)
|
||||
|
||||
```diff
|
||||
- Db::name('Goods')->where('id', $goodsId)->update([
|
||||
- 'vr_goods_config' => json_encode([$config], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
|
||||
- ]);
|
||||
+ Db::name('Goods')->where('id', $goodsId)->update([
|
||||
+ 'vr_goods_config' => json_encode($validConfigs, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
|
||||
+ ]);
|
||||
```
|
||||
|
||||
**验证**:
|
||||
- grep 确认 `validConfigs` 被用于写回
|
||||
- grep 确认不再有 `[$config]` 写回模式
|
||||
|
||||
---
|
||||
|
||||
## 实施顺序
|
||||
|
||||
```
|
||||
1. Issue #15(AdminGoodsSaveHandle.php)— 三步修改
|
||||
2. Issue #16(SeatSkuService.php)— 两步修改
|
||||
3. 验证:grep + git diff 确认修改正确
|
||||
4. commit + push
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 禁止事项
|
||||
|
||||
- 不改其他文件(尤其是 Admin.php)
|
||||
- 不改 Hook.php 或其他无关文件
|
||||
- commit 前执行 `git status` 确认只有目标文件
|
||||
Loading…
Reference in New Issue