vr-shopxo-plugin/docs/VenueDelete_Bug_Fix.md

275 lines
9.3 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.

# VR-ShopXO-Plugin 删除逻辑审查报告
**审查时间:** 2026-04-20
**审查人:** 西莉雅审查助手
**审查文件:**
- `shopxo/app/plugins/vr_ticket/admin/Admin.php`
- `shopxo/app/plugins/vr_ticket/view/venue/list.html`
---
## 一、发现的问题列表
### 🔴 问题 1`SeatTemplateDelete` 中使用了不存在的 `is_delete` 列(严重)
| 属性 | 值 |
|------|-----|
| **文件** | `Admin.php` |
| **方法** | `SeatTemplateDelete` (第 227 行) |
| **行号** | 第 249-251 行 |
| **问题** | Goods 查询使用 `is_delete = 0`,但 ShopXO 的 Goods 表使用 `is_delete_time` 进行软删除判断 |
```php
// ❌ 错误代码(第 249-251 行)
$goods = \think\facade\Db::name('Goods')
->where('vr_goods_config', 'like', '%"template_id":' . $id . '%')
->where('is_delete', 0) // ← ShopXO 没有 is_delete 列!
->find();
```
**错误信息:**
```
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'is_delete' in 'where clause'
```
**根本原因:** 复制粘贴自 ShopXO 原型代码时遗留的错误字段名。ShopXO 的商品软删除使用 `is_delete_time`(时间戳),`is_delete` 列根本不存在。
---
### 🔴 问题 2`VenueDelete` 中同样使用了不存在的 `is_delete` 列
| 属性 | 值 |
|------|-----|
| **文件** | `Admin.php` |
| **方法** | `VenueDelete` (第 857 行) |
| **行号** | 第 885-889 行 |
| **问题** | 与 `SeatTemplateDelete` 相同的问题 |
```php
// ❌ 错误代码(第 885-889 行)
$goods = \think\facade\Db::name('Goods')
->where('vr_goods_config', 'like', '%"template_id":' . $id . '%')
->where('is_delete', 0) // ← 同样错误!
->find();
```
---
### 🟡 问题 3`list.html` 残留了旧的 custom JS 删除弹窗代码
| 属性 | 值 |
|------|-----|
| **文件** | `view/venue/list.html` |
| **行号** | 第 137-168 |
| **问题** | 删除按钮已改用 `submit-ajax`(正确),但旧的 custom JS 弹窗和 `.btn-open-delete-confirm` 处理器仍残留,造成代码污染 |
删除按钮已正确更新为:
```html
<!-- ✅ 正确:已使用 submit-ajax -->
<button class="am-btn am-btn-danger am-btn-xs am-radius am-margin-left-xs submit-ajax"
data-url="{{:PluginsAdminUrl('vr_ticket', 'admin', 'VenueDelete')}}"
data-id="{{$v.id}}"
data-value="hard"
data-view="reload"
data-msg="确定要删除此场馆?删除后关联商品的场馆信息将被自动清除。">
<i class="am-icon-trash-o"></i> 删除
</button>
```
但页面底部仍残留:
- `#venue-confirm-delete-modal` 弹窗 HTML第 137-151 行)
- `.btn-open-delete-confirm` 点击处理器(第 155-158 行)
- `.btn-do-real-delete` 弹窗确认处理器(第 160-175 行)
---
### 🟢 确认正常:方法命名问题(非 bug
| 观察 | 说明 |
|------|-----|
| `vr_seat_templates` 表 | 实际上存储的就是"场馆/场地模板"数据,不是"座位模板" |
| `VenueDelete` / `SeatTemplateDelete` | 两个方法名不同,但都操作同一张表 `vr_seat_templates` |
| **结论** | 表名和方法名的命名不一致是历史遗留的设计问题,但不影响功能 |
---
## 二、根本原因分析
### 为什么会发生?
1. **复制粘贴错误** — 两个方法从 ShopXO 原型代码复制过来时,`Goods` 表的软删除字段用了错误的名称 `is_delete`,而 ShopXO 实际使用 `is_delete_time`
2. **残留代码未清理** — 前端删除按钮从 custom JS 方式迁移到 `submit-ajax` 后,旧的弹窗 HTML 和 JS 事件处理器没有一起移除
3. **缺少 Code Review** — 没有在 PR 阶段发现字段名错误
### 软删除 vs 硬删除逻辑梳理
| 方法 | 软删除触发条件 | 硬删除触发条件 | 表 |
|------|---------------|---------------|-----|
| `SeatTemplateDelete` | `hard_delete=0`(默认) | `hard_delete=1``value=hard` | `vr_seat_templates` |
| `VenueDelete` | `hard_delete=0`(默认) | `hard_delete=1``value=hard` | `vr_seat_templates` |
| `VerifierDelete` | **仅软删除**(无硬删除选项) | 无 | `vr_verifiers` |
**注意:** `VerifierDelete` 只有软删除(设置 `status=0`),这是正确的业务设计。
---
## 三、修复代码diff 格式)
### 修复 1`SeatTemplateDelete` 的 `is_delete` 错误
**文件:** `Admin.php` 第 249-251 行
```diff
if ($hardDelete) {
- $goods = \think\facade\Db::name('Goods')
- ->where('vr_goods_config', 'like', '%"template_id":' . $id . '%')
- ->where('is_delete', 0)
+ // 检查是否有关联商品ShopXO 使用 is_delete_time 做软删除判断)
+ $goods = \think\facade\Db::name('Goods')
+ ->where('vr_goods_config', 'like', '%"template_id":' . $id . '%')
+ ->where('is_delete_time', 0)
->find();
```
### 修复 2`VenueDelete` 的 `is_delete` 错误
**文件:** `Admin.php` 第 885-889 行
```diff
if ($hardDelete) {
- $goods = \think\facade\Db::name('Goods')
- ->where('vr_goods_config', 'like', '%"template_id":' . $id . '%')
- ->where('is_delete', 0)
+ // 检查是否有关联商品ShopXO 使用 is_delete_time 做软删除判断)
+ $goods = \think\facade\Db::name('Goods')
+ ->where('vr_goods_config', 'like', '%"template_id":' . $id . '%')
+ ->where('is_delete_time', 0)
->find();
```
### 修复 3清理 `list.html` 残留的 old custom JS 代码
**文件:** `view/venue/list.html` 第 137-175 行
删除以下残留代码块:
```diff
- <!-- 全局删除确认弹窗(单个,供所有行共用) -->
- <div class="am-modal am-modal-confirm" id="venue-confirm-delete-modal">
- <div class="am-modal-dialog">
- ...
- </div>
- </div>
-
- <script>
- $(function() {
- // 删除按钮:打开弹窗并记录当前行 ID
- $(document).on('click', '.btn-open-delete-confirm', function() {
- ...
- });
- // 弹窗确认删除:构造 hard_delete=1 参数并提交
- $(document).on('click', '.btn-do-real-delete', function() {
- ...
- });
- });
- </script>
```
---
## 四、验证步骤
### Step 1: 本地验证
```bash
# 1. 应用修复
# - Admin.php 第 249-251 行is_delete → is_delete_time
# - Admin.php 第 885-889 行is_delete → is_delete_time
# - list.html 删除残留的 modal 和 JS 代码
# 2. 清除 ShopXO 缓存
cd /path/to/shopxo
php think clear
```
### Step 2: 功能测试
**测试用例 1场馆硬删除有关联商品**
1. 创建一个商品,关联到某场馆
2. 进入场馆列表,点击"删除"按钮
3. 确认弹窗出现,点击"确认删除"
4. **预期:** 删除成功,页面 reload商品 `vr_goods_config` 中的场馆信息被清除
5. **验证 SQL 无报错**
**测试用例 2场馆硬删除无关联商品**
1. 找一个没有任何商品关联的场馆
2. 点击删除 → 确认
3. **预期:** 删除成功,场馆记录从表中移除
**测试用例 3场馆软删除禁用**
1. 点击"禁用"按钮
2. **预期:** 场馆 `status` 变为 0页面 reload 后显示"禁用"状态
3. **验证:** 禁用后,删除按钮仍然显示(不再因条件判断消失)
**测试用例 4场馆启用**
1. 在已禁用的场馆行点击"启用"
2. **预期:** `status` 变为 1页面 reload
**测试用例 5Verifier 删除**
1. 进入核销员列表,点击某核销员的删除
2. **预期:** 软删除,`status` 变为 0无 SQL 报错
### Step 3: 数据库验证
```sql
-- 验证硬删除后商品表中的 vr_goods_config 已被清理
SELECT id, name, vr_goods_config FROM vrt_goods WHERE vr_goods_config LIKE '%template_id":X%';
-- 验证场馆软删除后 status 正确
SELECT id, name, status FROM vrt_vr_seat_templates WHERE id = X;
```
---
## 五、修复状态汇总
| # | 问题 | 严重度 | 状态 |
|---|------|--------|------|
| 1 | `SeatTemplateDelete` 使用错误的 `is_delete` 列 | 🔴 严重 | **待修复** |
| 2 | `VenueDelete` 使用错误的 `is_delete` 列 | 🔴 严重 | **待修复** |
| 3 | `list.html` 残留 old custom JS 代码 | 🟡 轻微 | **待清理** |
**注意:** 大头通过 antigravity 手动修复了前端删除按钮和 `VenueDelete``value=hard` 参数支持,这些部分已正确。但 `is_delete``is_delete_time` 的修复仍需应用。
---
## 六、完整修复后代码对照
### `SeatTemplateDelete` 硬删除块(修复后)
```php
if ($hardDelete) {
// 检查是否有关联商品ShopXO 使用 is_delete_time 做软删除判断)
$goods = \think\facade\Db::name('Goods')
->where('vr_goods_config', 'like', '%"template_id":' . $id . '%')
->where('is_delete_time', 0)
->find();
\think\facade\Db::name('vr_seat_templates')->where('id', $id)->delete();
// ... audit log
}
```
### `VenueDelete` 硬删除块(修复后)
```php
if ($hardDelete) {
// 检查是否有关联商品ShopXO 使用 is_delete_time 做软删除判断)
$goods = \think\facade\Db::name('Goods')
->where('vr_goods_config', 'like', '%"template_id":' . $id . '%')
->where('is_delete_time', 0)
->find();
\think\facade\Db::name('vr_seat_templates')->where('id', $id)->delete();
// ... audit log
}
```