
    /**
     * @notes 生成小程序码
     * @param array $params
     * @return array|false
     */
    public static function generateMiniProgramQrcode(array $params)
    {
        try {
            $diagnosisId = $params['diagnosis_id'];
            $patientId = $params['patient_id'];
            $shareUserId = $params['share_user_id'];
            
            // 获取小程序配置
            $config = self::getMiniProgramConfig();
            if (!$config) {
                throw new \Exception('小程序配置未设置');
            }
            
            // 构建小程序路径和参数
            $page = 'pages/order/monad/monad';
            $scene = "id={$diagnosisId}&share_user={$shareUserId}";
            
            // 调用微信接口生成小程序码
            $qrcodeUrl = self::generateWxQrcode($config, $page, $scene);
            
            if (!$qrcodeUrl) {
                throw new \Exception('生成小程序码失败: ' . self::getError());
            }
            
            return [
                'qrcode_url' => $qrcodeUrl,
                'diagnosis_id' => $diagnosisId,
                'patient_id' => $patientId
            ];
        } catch (\Exception $e) {
            self::setError($e->getMessage());
            return false;
        }
    }

    /**
     * @notes 获取小程序配置
     * @return array|null
     */
    private static function getMiniProgramConfig(): ?array
    {
        try {
            // 从配置表获取小程序配置
            $appId = \app\common\service\ConfigService::get('mnp_setting', 'app_id', '');
            $appSecret = \app\common\service\ConfigService::get('mnp_setting', 'app_secret', '');
            
            if (empty($appId) || empty($appSecret)) {
                return null;
            }
            
            return [
                'app_id' => $appId,
                'app_secret' => $appSecret
            ];
        } catch (\Exception $e) {
            return null;
        }
    }

    /**
     * @notes 生成微信小程序码
     * @param array $config
     * @param string $page
     * @param string $scene
     * @return string|false
     */
    private static function generateWxQrcode(array $config, string $page, string $scene)
    {
        try {
            // 记录请求参数
            \think\facade\Log::info('开始生成小程序码', [
                'page' => $page,
                'scene' => $scene,
                'app_id' => $config['app_id']
            ]);
            
            // 获取access_token
            $accessToken = self::getWxAccessToken($config['app_id'], $config['app_secret']);
            if (!$accessToken) {
                throw new \Exception('获取access_token失败: ' . self::getError());
            }
            
            // 调用微信接口生成小程序码
            $url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token={$accessToken}";
            
            $data = [
                'scene' => $scene,
                'page' => $page,
                'check_path' => false,
                'env_version' => 'release',
                'width' => 280
            ];
            
            \think\facade\Log::info('调用微信API生成小程序码', ['data' => $data]);
            
            $response = self::httpPost($url, json_encode($data));
            
            // 检查是否返回错误（JSON格式）
            $result = json_decode($response, true);
            if (is_array($result) && isset($result['errcode']) && $result['errcode'] != 0) {
                $errorMsg = "生成小程序码失败: errcode={$result['errcode']}, errmsg=" . ($result['errmsg'] ?? '未知错误');
                \think\facade\Log::error($errorMsg);
                
                // 如果是AccessToken错误，清除缓存
                if ($result['errcode'] == 40001 || $result['errcode'] == 42001) {
                    $cacheKey = 'wx_access_token_' . $config['app_id'];
                    cache($cacheKey, null);
                    \think\facade\Log::info('已清除无效的AccessToken缓存');
                }
                
                throw new \Exception($errorMsg);
            }
            
            // 如果不是JSON错误，说明返回的是图片二进制数据
            // 保存图片
            $filename = 'qrcode_' . $config['app_id'] . '_' . md5($scene) . '_' . time() . '.png';
            $savePath = 'uploads/qrcode/' . date('Ymd') . '/';
            $fullPath = public_path() . $savePath;
            
            if (!is_dir($fullPath)) {
                mkdir($fullPath, 0755, true);
            }
            
            $saved = file_put_contents($fullPath . $filename, $response);
            
            if (!$saved) {
                throw new \Exception('保存二维码图片失败');
            }
            
            $qrcodeUrl = request()->domain() . '/' . $savePath . $filename;
            \think\facade\Log::info('小程序码生成成功', ['url' => $qrcodeUrl]);
            
            return $qrcodeUrl;
        } catch (\Exception $e) {
            \think\facade\Log::error('generateWxQrcode异常: ' . $e->getMessage());
            self::setError($e->getMessage());
            return false;
        }
    }

    /**
     * @notes 获取微信access_token
     * @param string $appId
     * @param string $appSecret
     * @return string|false
     */
    private static function getWxAccessToken(string $appId, string $appSecret)
    {
        try {
            // 尝试从缓存获取
            $cacheKey = 'wx_access_token_' . $appId;
            $accessToken = cache($cacheKey);
            
            if ($accessToken) {
                return $accessToken;
            }
            
            // 从微信服务器获取
            $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appId}&secret={$appSecret}";
            $response = self::httpGet($url);
            
            // 记录原始响应用于调试
            \think\facade\Log::info('微信AccessToken响应: ' . $response);
            
            $result = json_decode($response, true);
            
            // 检查是否有错误
            if (isset($result['errcode']) && $result['errcode'] != 0) {
                $errorMsg = "获取AccessToken失败: errcode={$result['errcode']}, errmsg=" . ($result['errmsg'] ?? '未知错误');
                \think\facade\Log::error($errorMsg);
                throw new \Exception($errorMsg);
            }
            
            if (isset($result['access_token'])) {
                // 缓存access_token，有效期7000秒（微信官方7200秒，提前200秒过期）
                cache($cacheKey, $result['access_token'], 7000);
                \think\facade\Log::info('AccessToken获取成功并已缓存');
                return $result['access_token'];
            }
            
            throw new \Exception('获取access_token失败: 响应中没有access_token字段');
        } catch (\Exception $e) {
            \think\facade\Log::error('getWxAccessToken异常: ' . $e->getMessage());
            self::setError($e->getMessage());
            return false;
        }
    }
    
    /**
     * @notes HTTP GET请求
     * @param string $url
     * @return string|false
     */
    private static function httpGet(string $url)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $response = curl_exec($ch);
        curl_close($ch);
        return $response;
    }
    
    /**
     * @notes HTTP POST请求
     * @param string $url
     * @param string $data
     * @return string|false
     */
    private static function httpPost(string $url, string $data)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
        $response = curl_exec($ch);
        curl_close($ch);
        return $response;
    }
