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)}}
- {{$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}}
-
-
-
-
-
-
-
-{{: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 @@
×
-
⚠️ 删除记录不会导致已上架商品内容变动。
-
若需要同步场馆信息到已发布商品,请编辑对应商品并保存。
+
⚠️ 删除后,关联商品的场馆信息将被自动清除。
+
删除前已购买的用户不受影响(已有购买快照)。