diff --git a/shopxo/app/plugins/vr_ticket/install.sql b/shopxo/app/plugins/vr_ticket/install.sql index bc63bcd..4fc6db1 100644 --- a/shopxo/app/plugins/vr_ticket/install.sql +++ b/shopxo/app/plugins/vr_ticket/install.sql @@ -20,8 +20,7 @@ CREATE TABLE IF NOT EXISTS `{{prefix}}vr_tickets` ( `goods_snapshot` TEXT DEFAULT NULL COMMENT '商品快照JSON', `user_id` BIGINT UNSIGNED NOT NULL COMMENT '用户ID', `ticket_code` CHAR(36) NOT NULL COMMENT 'UUID票码', - `short_code` VARCHAR(16) DEFAULT NULL COMMENT '短码(Feistel混淆)', - `qr_payload` TEXT DEFAULT NULL COMMENT 'QR签名payload(Base64)', + `qr_data` TEXT DEFAULT NULL COMMENT '加密QR内容', `seat_info` VARCHAR(255) DEFAULT NULL COMMENT '座位信息', `spec_base_id` BIGINT UNSIGNED DEFAULT 0 COMMENT 'spec_base_id', `real_name` VARCHAR(60) DEFAULT NULL COMMENT '观演人姓名', @@ -35,7 +34,6 @@ CREATE TABLE IF NOT EXISTS `{{prefix}}vr_tickets` ( `updated_at` INT UNSIGNED DEFAULT 0 COMMENT '更新时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_ticket_code` (`ticket_code`), - UNIQUE KEY `uk_short_code` (`short_code`), KEY `idx_order_id` (`order_id`), KEY `idx_user_id` (`user_id`), KEY `idx_goods_id` (`goods_id`), diff --git a/shopxo/app/plugins/vr_ticket/service/TicketService.php b/shopxo/app/plugins/vr_ticket/service/TicketService.php index ff9a00b..63d923c 100644 --- a/shopxo/app/plugins/vr_ticket/service/TicketService.php +++ b/shopxo/app/plugins/vr_ticket/service/TicketService.php @@ -128,9 +128,9 @@ class TicketService extends BaseService } $ticket_code = BaseService::generateUuid(); + $now = BaseService::now(); // Step 1: 先插入获取 ticket_id(用于 short_code 生成) - $now = BaseService::now(); $ticket_id = \think\facade\Db::name(BaseService::table('tickets'))->insertGetId([ 'order_id' => $order['id'], 'order_no' => $order['order_no'], @@ -142,6 +142,7 @@ class TicketService extends BaseService ], JSON_UNESCAPED_UNICODE), 'user_id' => $order['user_id'], 'ticket_code' => $ticket_code, + 'qr_data' => '', // 占位,生成后更新 'seat_info' => $spec_name, 'spec_base_id' => $spec_base_id, 'real_name' => '', @@ -159,6 +160,7 @@ class TicketService extends BaseService } // Step 2: 生成短码(goods_id 明文 + ticket_id 混淆) + // 短码存储在 qr_data 中,供前端展示 $short_code = BaseService::shortCodeEncode($order['goods_id'], $ticket_id); // Step 3: 生成 QR payload(HMAC-SHA256 签名,30分钟有效) @@ -169,13 +171,13 @@ class TicketService extends BaseService 'exp' => $now + 1800, // 30分钟 ]); - // Step 4: 更新 short_code 和 qr_payload + // qr_data 格式:短码|QR_payload(竖线分隔) + $qr_data = $short_code . '|' . $qr_payload; + + // Step 4: 更新 qr_data \think\facade\Db::name(BaseService::table('tickets')) ->where('id', $ticket_id) - ->update([ - 'short_code' => $short_code, - 'qr_payload' => $qr_payload, - ]); + ->update(['qr_data' => $qr_data]); // Step 5: 写入观演人信息 $extension_data = json_decode($order['extension_data'] ?? '{}', true); @@ -449,13 +451,15 @@ class TicketService extends BaseService } /** - * 获取票的 QR payload(带动态刷新) + * 获取票的 QR 数据(短码 + payload) + * + * qr_data 格式:短码|payload * * @param int $ticket_id 票ID * @param int $user_id 用户ID(校验归属) * @return array [code, data] */ - public static function getQrPayload($ticket_id, $user_id) + public static function getQrData($ticket_id, $user_id) { $ticket = \think\facade\Db::name(BaseService::table('tickets')) ->where('id', $ticket_id) @@ -476,19 +480,26 @@ class TicketService extends BaseService return ['code' => -3, 'msg' => '该票已退款']; } + $qr_data = $ticket['qr_data'] ?? ''; + if (empty($qr_data) || strpos($qr_data, '|') === false) { + return ['code' => -4, 'msg' => 'QR数据异常']; + } + + [$short_code, $payload] = explode('|', $qr_data, 2); + // 检查是否需要刷新 QR(剩余有效期 < 15分钟) - $qr_payload = $ticket['qr_payload']; - if (!empty($qr_payload)) { - $decoded = BaseService::verifyQrPayload($qr_payload); + if (!empty($payload)) { + $decoded = BaseService::verifyQrPayload($payload); if ($decoded !== null && $decoded['exp'] - time() > 900) { // 有效期 > 15分钟,返回缓存 return [ 'code' => 0, 'msg' => 'success', 'data' => [ - 'payload' => $qr_payload, - 'cached' => true, - 'expires_in'=> $decoded['exp'] - time(), + 'short_code' => $short_code, + 'payload' => $payload, + 'cached' => true, + 'expires_in' => $decoded['exp'] - time(), ], ]; } @@ -504,17 +515,19 @@ class TicketService extends BaseService ]); // 更新缓存 + $new_qr_data = $short_code . '|' . $new_payload; \think\facade\Db::name(BaseService::table('tickets')) ->where('id', $ticket_id) - ->update(['qr_payload' => $new_payload, 'updated_at' => $now]); + ->update(['qr_data' => $new_qr_data, 'updated_at' => $now]); return [ 'code' => 0, 'msg' => 'success', 'data' => [ - 'payload' => $new_payload, - 'cached' => false, - 'expires_in'=> 1800, + 'short_code' => $short_code, + 'payload' => $new_payload, + 'cached' => false, + 'expires_in' => 1800, ], ]; }