From 7a0ae54705816a52df07f5be7ff2fd794572aac6 Mon Sep 17 00:00:00 2001 From: wong <106998207@qq.com> Date: Sat, 20 Dec 2025 11:09:04 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=8F=90=E4=BA=A4=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E6=96=B0=E5=A2=9E=E7=9A=84=E6=B8=A0=E9=81=93=E7=A0=81?= =?UTF-8?q?=E9=99=90=E5=88=B624=E5=B0=8F=E6=97=B6=E6=9C=89=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../distribution/ChannelController.php | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/Server/application/cunkebao/controller/distribution/ChannelController.php b/Server/application/cunkebao/controller/distribution/ChannelController.php index 4e193db4..a58a5c04 100644 --- a/Server/application/cunkebao/controller/distribution/ChannelController.php +++ b/Server/application/cunkebao/controller/distribution/ChannelController.php @@ -9,6 +9,8 @@ use library\ResponseHelper; use think\Db; use think\Exception; use think\facade\Env; +use think\facade\Cache; +use think\facade\Log; use Endroid\QrCode\QrCode; use Endroid\QrCode\ErrorCorrectionLevel; use EasyWeChat\Factory; @@ -860,6 +862,43 @@ class ChannelController extends BaseController 'expireTime' => time() + 86400 // 24小时后过期 ]; $token = base64_encode(json_encode($tokenData)); + + // 如果是小程序码,提前计算scene并存储映射关系到数据库 + if ($type === 'miniprogram') { + $scene = substr(md5($token), 0, 32); + + // 使用数据库存储映射关系(更可靠) + try { + Db::name('distribution_channel_scene_token')->insert([ + 'scene' => $scene, + 'token' => $token, + 'companyId' => $companyId, + 'expireTime' => time() + 86400, + 'createTime' => time() + ]); + Log::info('生成小程序码 - 存储映射到数据库,scene: ' . $scene . ', companyId: ' . $companyId); + } catch (\Exception $e) { + // 如果表不存在,尝试创建表 + Log::warning('存储映射关系失败,尝试创建表: ' . $e->getMessage()); + $this->createSceneTokenTable(); + // 重试一次 + try { + Db::name('distribution_channel_scene_token')->insert([ + 'scene' => $scene, + 'token' => $token, + 'companyId' => $companyId, + 'expireTime' => time() + 86400, + 'createTime' => time() + ]); + } catch (\Exception $e2) { + Log::error('重试存储映射关系失败: ' . $e2->getMessage()); + } + } + + // 同时存储到缓存(双重保险) + $sceneCacheKey = 'channel_register_scene_' . $scene; + Cache::set($sceneCacheKey, $token, 86400); + } if ($type === 'h5') { // 生成H5二维码 @@ -905,6 +944,18 @@ class ChannelController extends BaseController // scene参数长度限制为32位,使用token的MD5值 $scene = substr(md5($token), 0, 32); + + // 再次确保映射关系已存储到数据库和缓存(双重保险) + $sceneCacheKey = 'channel_register_scene_' . $scene; + Cache::set($sceneCacheKey, $token, 86400); + + // 验证数据库和缓存是否存储成功 + $dbToken = Db::name('distribution_channel_scene_token') + ->where('scene', $scene) + ->where('expireTime', '>', time()) + ->value('token'); + $cacheToken = Cache::get($sceneCacheKey); + Log::info('生成小程序码 - scene: ' . $scene . ', 数据库验证: ' . ($dbToken ? '成功' : '失败') . ', 缓存验证: ' . ($cacheToken ? '成功' : '失败')); // 调用接口生成小程序码 // 注意:page 必须是小程序里已经存在且发布过的页面路径 @@ -1125,6 +1176,43 @@ class ChannelController extends BaseController ]); } + // 记录接收到的参数 + Log::info('registerByQrCode - 接收到的token参数: ' . $token . ', 长度: ' . strlen($token) . ', 是否为32位MD5: ' . (preg_match('/^[a-f0-9]{32}$/i', $token) ? '是' : '否')); + + // 判断传入的是scene(32位MD5)还是token(base64编码) + // 如果是32位MD5字符串,则从数据库或缓存中查找对应的token + if (strlen($token) == 32 && preg_match('/^[a-f0-9]{32}$/i', $token)) { + // 这是scene,先从数据库查找对应的token + $sceneData = Db::name('distribution_channel_scene_token') + ->where('scene', $token) + ->where('expireTime', '>', time()) + ->find(); + + if ($sceneData && !empty($sceneData['token'])) { + $realToken = $sceneData['token']; + Log::info('registerByQrCode - 从数据库获取token成功,scene: ' . $token); + } else { + // 如果数据库中没有,尝试从缓存获取 + $sceneCacheKey = 'channel_register_scene_' . $token; + $realToken = Cache::get($sceneCacheKey); + + if (empty($realToken)) { + Log::warning('registerByQrCode - 数据库和缓存中均未找到token,scene: ' . $token); + return json([ + 'code' => 400, + 'success' => false, + 'msg' => '二维码已过期,请重新生成', + 'data' => null + ]); + } + Log::info('registerByQrCode - 从缓存获取token成功,scene: ' . $token); + } + + $token = $realToken; + } else { + Log::info('registerByQrCode - 识别为token(非scene),直接使用,token长度: ' . strlen($token)); + } + // 解析token $tokenData = json_decode(base64_decode($token), true); if (!$tokenData || !isset($tokenData['companyId'])) { @@ -1307,5 +1395,31 @@ class ChannelController extends BaseController ]); } } + + /** + * 创建scene和token映射表(如果不存在) + */ + protected function createSceneTokenTable() + { + try { + $sql = "CREATE TABLE IF NOT EXISTS `ck_distribution_channel_scene_token` ( + `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `scene` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '小程序scene参数(MD5值)', + `token` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '原始token(base64编码)', + `companyId` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '公司ID', + `expireTime` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '过期时间戳', + `createTime` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '创建时间', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE KEY `uk_scene` (`scene`) USING BTREE, + INDEX `idx_companyId` (`companyId`) USING BTREE, + INDEX `idx_expireTime` (`expireTime`) USING BTREE + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='分销渠道小程序码scene和token映射表';"; + + Db::execute($sql); + Log::info('创建scene和token映射表成功'); + } catch (\Exception $e) { + Log::error('创建scene和token映射表失败: ' . $e->getMessage()); + } + } }