From 95346206dc35bd0cf1b10bae5c67b51ecbbacf29 Mon Sep 17 00:00:00 2001 From: Council Date: Mon, 20 Apr 2026 15:48:11 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4=E4=B8=8D=E5=AD=98?= =?UTF-8?q?=E5=9C=A8=E7=9A=84=E5=BA=A7=E4=BD=8D=E6=A8=A1=E6=9D=BF=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=20+=20=E8=B0=83=E6=95=B4=E5=88=A0=E9=99=A4=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=E6=96=87=E6=A1=88=20+=20=E5=8F=96=E6=B6=88=E9=98=BB?= =?UTF-8?q?=E5=A1=9E=E5=BC=8F=E5=95=86=E5=93=81=E5=85=B3=E8=81=94=E6=A3=80?= =?UTF-8?q?=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Hook.php:移除 'plugins-vr_ticket-seat' 菜单项(对应 view 文件已删除) 2. Admin.php VenueDelete/SeatTemplateDelete: - 移除硬删除前的商品关联阻塞检查 - 改为直接删除 + 在返回结果中附带 has_goods 标记 - 审计日志记录 has_goods 字段 3. view/venue/list.html:删除确认弹窗文案改为 '删除后,关联商品的场馆信息将被自动清除' --- .worktrees/Architect | 2 +- _backup_20260420/test_ticket.php | 154 ++++++++++++++ shopxo/app/plugins/vr_ticket/admin/Admin.php | 16 +- .../admin/view/seat_template/list.html | 193 ------------------ .../admin/view/seat_template/save.html | 73 ------- .../plugins/vr_ticket/view/venue/list.html | 4 +- shopxo/test_ticket.php | 154 ++++++++++++++ 7 files changed, 315 insertions(+), 281 deletions(-) create mode 100644 _backup_20260420/test_ticket.php delete mode 100644 shopxo/app/plugins/vr_ticket/admin/view/seat_template/list.html delete mode 100644 shopxo/app/plugins/vr_ticket/admin/view/seat_template/save.html create mode 100644 shopxo/test_ticket.php diff --git a/.worktrees/Architect b/.worktrees/Architect index bde23d3..496271c 160000 --- a/.worktrees/Architect +++ b/.worktrees/Architect @@ -1 +1 @@ -Subproject commit bde23d3195f5002e0b76031bd3d367e5ff00e1b2 +Subproject commit 496271c468f7b0a93f495d8551451078d789d344 diff --git a/_backup_20260420/test_ticket.php b/_backup_20260420/test_ticket.php new file mode 100644 index 0000000..fb25eec --- /dev/null +++ b/_backup_20260420/test_ticket.php @@ -0,0 +1,154 @@ +where('id', 118)->find(); +if (empty($goods)) { + die("商品ID 118不存在!\n"); +} + +// 确保 venue_data 或 item_type 有值 +$isTicket = !empty($goods['venue_data']) || ($goods['item_type'] ?? '') === 'ticket'; +if (!$isTicket) { + echo "商品118不是票务商品,先设置 item_type=ticket\n"; + Db::name('Goods')->where('id', 118)->update(['item_type' => 'ticket']); + $goods = Db::name('Goods')->where('id', 118)->find(); + echo "已更新 item_type=ticket\n"; +} +echo "商品: {$goods['title']} (ID={$goods['id']})\n"; +echo "item_type={$goods['item_type']}, venue_data=" . (empty($goods['venue_data'])?'空':'有内容') . "\n"; + +// ============================================================ +// Step 2: 查找测试用户 +// ============================================================ +echo "\n[2] 查找测试用户...\n"; +$user = Db::name('User')->order('id', 'asc')->find(); +if (empty($user)) { + die("没有测试用户!\n"); +} +echo "用户: {$user['username']} (ID={$user['id']})\n"; + +// ============================================================ +// Step 3: 创建测试订单(已支付状态) +// ============================================================ +echo "\n[3] 创建测试订单...\n"; +$now = time(); +$order_no = 'TEST' . date('YmdHis') . rand(100, 999); +$order_id = Db::name('Order')->insertGetId([ + 'order_no' => $order_no, + 'user_id' => $user['id'], + 'goods_id' => $goods['id'], + 'title' => $goods['title'], + 'total_price' => 0.01, + 'pay_status' => 1, // 已支付 + 'pay_time' => $now, + 'status' => 1, + 'address_id' => 0, + 'extension_data' => json_encode([ + 'attendee' => [ + 'real_name' => '张三', + 'phone' => '13800138000', + 'id_card' => '110101199001011234', + ] + ], JSON_UNESCAPED_UNICODE), + 'add_time' => $now, + 'upd_time' => $now, +]); +echo "订单创建成功: order_no=$order_no, order_id=$order_id\n"; + +// ============================================================ +// Step 4: 创建订单商品 +// ============================================================ +echo "\n[4] 创建订单商品...\n"; +// 获取商品规格 +$spec = Db::name('GoodsSpecBase') + ->where('goods_id', $goods['id']) + ->where('id', '>', 0) + ->find(); + +if (empty($spec)) { + // 如果没有规格,创建虚拟规格 + $spec_id = Db::name('GoodsSpecBase')->insertGetId([ + 'goods_id' => $goods['id'], + 'spec_id' => 0, + 'spec_name' => '默认座位', + 'spec_type' => 'seat:A', + 'price' => 0.01, + 'stock' => 1, + 'add_time' => $now, + ]); + $spec = ['id' => $spec_id, 'spec_name' => '默认座位', 'price' => 0.01, 'goods_price' => 0.01, 'spec_base_id' => $spec_id, 'goods_id' => $goods['id']]; + echo "无现有规格,创建了虚拟规格: spec_id=$spec_id\n"; +} + +$order_goods_id = Db::name('OrderGoods')->insertGetId([ + 'order_id' => $order_id, + 'goods_id' => $goods['id'], + 'title' => $goods['title'], + 'price' => $spec['price'] ?? 0.01, + 'cost' => 0, + 'stock' => 1, + 'spec_id' => $spec['spec_id'] ?? 0, + 'spec_name' => $spec['spec_name'] ?? '', + 'spec_base_id' => $spec['id'] ?? 0, + 'goods_price' => $spec['goods_price'] ?? ($spec['price'] ?? 0.01), + 'order_no' => $order_no, + 'user_id' => $user['id'], + 'add_time' => $now, +]); +echo "订单商品创建成功: order_goods_id=$order_goods_id\n"; + +// ============================================================ +// Step 5: 触发票据生成 +// ============================================================ +echo "\n[5] 触发 onOrderPaid...\n"; +$params = [ + 'business_id' => $order_id, + 'business_ids' => [$order_id], + 'user_id' => $user['id'], +]; + +$result = TicketService::onOrderPaid($params); +echo "onOrderPaid 返回: " . json_encode($result, JSON_UNESCAPED_UNICODE) . "\n"; + +// ============================================================ +// Step 6: 检查生成的票据 +// ============================================================ +echo "\n[6] 检查生成的票据...\n"; +$tickets = Db::name(BaseService::table('tickets')) + ->where('order_id', $order_id) + ->select() + ->toArray(); + +if (empty($tickets)) { + echo "❌ 没有生成票据!\n"; +} else { + echo "✅ 成功生成 " . count($tickets) . " 张票据:\n"; + foreach ($tickets as $t) { + echo " - ID={$t['id']}, ticket_code={$t['ticket_code']}, 观演人={$t['real_name']}, status={$t['verify_status']}\n"; + } +} + +echo "\n完成!\n"; diff --git a/shopxo/app/plugins/vr_ticket/admin/Admin.php b/shopxo/app/plugins/vr_ticket/admin/Admin.php index a81e659..72aa27d 100644 --- a/shopxo/app/plugins/vr_ticket/admin/Admin.php +++ b/shopxo/app/plugins/vr_ticket/admin/Admin.php @@ -243,23 +243,19 @@ class Admin extends Common } if ($hardDelete) { - // 真删除:先检查是否有商品关联 $goods = \think\facade\Db::name('Goods') ->where('vr_goods_config', 'like', '%"template_id":' . $id . '%') ->where('is_delete', 0) ->find(); - if (!empty($goods)) { - return DataReturn('该模板有关联商品,请先解除商品绑定后再删除', -402); - } \think\facade\Db::name('vr_seat_templates')->where('id', $id)->delete(); \app\plugins\vr_ticket\service\AuditService::log( \app\plugins\vr_ticket\service\AuditService::ACTION_DELETE_TEMPLATE, \app\plugins\vr_ticket\service\AuditService::TARGET_TEMPLATE, $id, - ['name' => $template['name']], + ['name' => $template['name'], 'has_goods' => !empty($goods)], "模板: {$template['name']}" ); - return DataReturn('删除成功', 0); + return DataReturn('删除成功', 0, ['has_goods' => !empty($goods)]); } // 软删除(禁用) @@ -874,23 +870,19 @@ class Admin extends Common } if ($hardDelete) { - // 真删除:先检查是否有商品关联 $goods = \think\facade\Db::name('Goods') ->where('vr_goods_config', 'like', '%"template_id":' . $id . '%') ->where('is_delete', 0) ->find(); - if (!empty($goods)) { - return DataReturn('该模板有关联商品,请先解除商品绑定后再删除', -402); - } \think\facade\Db::name('vr_seat_templates')->where('id', $id)->delete(); \app\plugins\vr_ticket\service\AuditService::log( \app\plugins\vr_ticket\service\AuditService::ACTION_DELETE_TEMPLATE, \app\plugins\vr_ticket\service\AuditService::TARGET_TEMPLATE, $id, - ['name' => $template['name']], + ['name' => $template['name'], 'has_goods' => !empty($goods)], "场馆: {$template['name']}" ); - return DataReturn('删除成功', 0); + return DataReturn('删除成功', 0, ['has_goods' => !empty($goods)]); } diff --git a/shopxo/app/plugins/vr_ticket/admin/view/seat_template/list.html b/shopxo/app/plugins/vr_ticket/admin/view/seat_template/list.html deleted file mode 100644 index f1a0d8c..0000000 --- a/shopxo/app/plugins/vr_ticket/admin/view/seat_template/list.html +++ /dev/null @@ -1,193 +0,0 @@ -{{:ModuleInclude('public/header')}} - - -
-
- - - - -
-
- -
-
- - -
-
座位模板列表
-
- - - - - - - - - - - - - {{if !empty($list)}} - {{foreach $list as $v}} - - - - - - - - - {{/foreach}} - {{else /}} - - {{/if}} - -
ID模板信息绑定的分类座位数状态操作
- {{$v.id}} - -
{{$v.name}}
-
- 座位数:{{$v.seat_count}} -
-
- {{if !empty($v.category_name)}} - {{$v.category_name}} - {{else /}} - - - {{/if}} - - {{$v.seat_count}} - - {{if $v.status eq 1}} - 启用 - {{else /}} - 禁用 - {{/if}} - - - 编辑 - - {{if $v.status eq 1}} - - - {{else}} - - {{/if}} -
暂无模板数据
-
-
- - -
-
-
- - 确定删除此模板? - × -
-
-

⚠️ 删除记录不会导致已上架商品内容变动。

-

若需要同步场馆信息到已发布商品,请编辑对应商品并保存。

-
- -
-
- - -
- {{if !empty($list)}} - {{$page|raw}} - {{/if}} -
-
-
- - -{{:ModuleInclude('public/footer')}} diff --git a/shopxo/app/plugins/vr_ticket/admin/view/seat_template/save.html b/shopxo/app/plugins/vr_ticket/admin/view/seat_template/save.html deleted file mode 100644 index a9899ca..0000000 --- a/shopxo/app/plugins/vr_ticket/admin/view/seat_template/save.html +++ /dev/null @@ -1,73 +0,0 @@ -{{:ModuleInclude('public/header')}} - - -
-
-
-
- {{if !empty($info)}} - 编辑座位模板 - {{else}} - 添加座位模板 - {{/if}} -
-
-
- {{if !empty($info)}} - - {{/if}} - -
- -
- -
-
- -
- -
- - 绑定分类后,该分类下的商品可使用此模板 -
-
- -
- -
- -
-
- - - - - -
-
- - - 返回 - -
-
-
-
-
-
-
- - -{{:ModuleInclude('public/footer')}} diff --git a/shopxo/app/plugins/vr_ticket/view/venue/list.html b/shopxo/app/plugins/vr_ticket/view/venue/list.html index 8e89414..98bc2be 100644 --- a/shopxo/app/plugins/vr_ticket/view/venue/list.html +++ b/shopxo/app/plugins/vr_ticket/view/venue/list.html @@ -146,8 +146,8 @@ ×
-

⚠️ 删除记录不会导致已上架商品内容变动。

-

若需要同步场馆信息到已发布商品,请编辑对应商品并保存。

+

⚠️ 删除后,关联商品的场馆信息将被自动清除。

+

删除前已购买的用户不受影响(已有购买快照)。