vr-shopxo-plugin/docs/VenueDelete_Bug_Fix.md

9.3 KiB
Raw Permalink Blame History

VR-ShopXO-Plugin 删除逻辑审查报告

审查时间: 2026-04-20 审查人: 西莉雅审查助手 审查文件:

  • shopxo/app/plugins/vr_ticket/admin/Admin.php
  • shopxo/app/plugins/vr_ticket/view/venue/list.html

一、发现的问题列表

🔴 问题 1SeatTemplateDelete 中使用了不存在的 is_delete 列(严重)

属性
文件 Admin.php
方法 SeatTemplateDelete (第 227 行)
行号 第 249-251 行
问题 Goods 查询使用 is_delete = 0,但 ShopXO 的 Goods 表使用 is_delete_time 进行软删除判断
// ❌ 错误代码(第 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 列根本不存在。


🔴 问题 2VenueDelete 中同样使用了不存在的 is_delete

属性
文件 Admin.php
方法 VenueDelete (第 857 行)
行号 第 885-889 行
问题 SeatTemplateDelete 相同的问题
// ❌ 错误代码(第 885-889 行)
$goods = \think\facade\Db::name('Goods')
    ->where('vr_goods_config', 'like', '%"template_id":' . $id . '%')
    ->where('is_delete', 0)   // ← 同样错误!
    ->find();

🟡 问题 3list.html 残留了旧的 custom JS 删除弹窗代码

属性
文件 view/venue/list.html
行号 第 137-168
问题 删除按钮已改用 submit-ajax(正确),但旧的 custom JS 弹窗和 .btn-open-delete-confirm 处理器仍残留,造成代码污染

删除按钮已正确更新为:

<!-- ✅ 正确:已使用 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=1value=hard vr_seat_templates
VenueDelete hard_delete=0(默认) hard_delete=1value=hard vr_seat_templates
VerifierDelete 仅软删除(无硬删除选项) vr_verifiers

注意: VerifierDelete 只有软删除(设置 status=0),这是正确的业务设计。


三、修复代码diff 格式)

修复 1SeatTemplateDeleteis_delete 错误

文件: Admin.php 第 249-251 行

         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();

修复 2VenueDeleteis_delete 错误

文件: Admin.php 第 885-889 行

         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 行

删除以下残留代码块:

-        <!-- 全局删除确认弹窗(单个,供所有行共用) -->
-        <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: 本地验证

# 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: 数据库验证

-- 验证硬删除后商品表中的 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 手动修复了前端删除按钮和 VenueDeletevalue=hard 参数支持,这些部分已正确。但 is_deleteis_delete_time 的修复仍需应用。


六、完整修复后代码对照

SeatTemplateDelete 硬删除块(修复后)

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 硬删除块(修复后)

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
}