erp-backend/app/Services/WeChatPlatformService.php
2026-04-01 17:07:04 +08:00

252 lines
7.9 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Services;
use App\Models\SystemConfig;
use App\Models\User;
use Illuminate\Support\Facades\Cache;
class WeChatPlatformService
{
/**
* 获取微信开放平台配置
*/
public function getConfig(): array
{
$cacheKey = 'wechat_platform_config';
return Cache::remember($cacheKey, 3600, function () {
return [
'enabled' => SystemConfig::getValue('wechat', 'enabled', false),
'app_id' => SystemConfig::getValue('wechat', 'app_id', ''),
'app_secret' => SystemConfig::getValue('wechat', 'app_secret', ''),
'token' => SystemConfig::getValue('wechat', 'token', ''),
'encoding_aes_key' => SystemConfig::getValue('wechat', 'encoding_aes_key', ''),
];
});
}
/**
* 小程序登录
*/
public function miniProgramLogin(string $code): array
{
$config = $this->getConfig();
if (!$config['enabled']) {
return ['success' => false, 'message' => '微信服务未启用'];
}
try {
$response = \Illuminate\Support\Facades\Http::get('https://api.weixin.qq.com/sns/jscode2session', [
'appid' => $config['app_id'],
'secret' => $config['app_secret'],
'js_code' => $code,
'grant_type' => 'authorization_code',
]);
$data = $response->json();
if (isset($data['errcode']) && $data['errcode'] !== 0) {
return ['success' => false, 'message' => $data['errmsg'] ?? '微信登录失败'];
}
return [
'success' => true,
'data' => [
'openid' => $data['openid'],
'unionid' => $data['unionid'] ?? null,
'session_key' => $data['session_key'] ?? null,
],
];
} catch (\Exception $e) {
\Log::error('微信小程序登录失败: ' . $e->getMessage());
return ['success' => false, 'message' => '微信登录失败'];
}
}
/**
* 公众号登录 - 获取授权URL
*/
public function getOauthUrl(string $redirectUri, string $state = ''): string
{
$config = $this->getConfig();
$state = $state ?: md5(uniqid());
$params = [
'appid' => $config['app_id'],
'redirect_uri' => $redirectUri,
'response_type' => 'code',
'scope' => 'snsapi_userinfo',
'state' => $state,
];
return 'https://open.weixin.qq.com/connect/oauth2/authorize?' . http_build_query($params) . '#wechat_redirect';
}
/**
* 公众号登录 - 通过code获取用户信息
*/
public function officialAccountCallback(string $code): array
{
$config = $this->getConfig();
if (!$config['enabled']) {
return ['success' => false, 'message' => '微信服务未启用'];
}
try {
// 获取 access_token
$tokenResponse = \Illuminate\Support\Facades\Http::get('https://api.weixin.qq.com/sns/oauth2/access_token', [
'appid' => $config['app_id'],
'secret' => $config['app_secret'],
'code' => $code,
'grant_type' => 'authorization_code',
]);
$tokenData = $tokenResponse->json();
if (isset($tokenData['errcode']) && $tokenData['errcode'] !== 0) {
return ['success' => false, 'message' => $tokenData['errmsg'] ?? '获取access_token失败'];
}
// 获取用户信息
$userResponse = \Illuminate\Support\Facades\Http::get('https://api.weixin.qq.com/sns/userinfo', [
'access_token' => $tokenData['access_token'],
'openid' => $tokenData['openid'],
'lang' => 'zh_CN',
]);
$userData = $userResponse->json();
return [
'success' => true,
'data' => [
'openid' => $userData['openid'],
'unionid' => $userData['unionid'] ?? null,
'nickname' => $userData['nickname'] ?? null,
'headimgurl' => $userData['headimgurl'] ?? null,
'sex' => $userData['sex'] ?? null,
'country' => $userData['country'] ?? null,
'province' => $userData['province'] ?? null,
'city' => $userData['city'] ?? null,
],
];
} catch (\Exception $e) {
\Log::error('微信公众号登录失败: ' . $e->getMessage());
return ['success' => false, 'message' => '微信登录失败'];
}
}
/**
* 获取用户信息通过openid
*/
public function getUserInfo(string $openid): ?array
{
$config = $this->getConfig();
try {
$response = \Illuminate\Support\Facades\Http::get('https://api.weixin.qq.com/cgi-bin/user/info', [
'access_token' => $this->getComponentAccessToken(),
'openid' => $openid,
'lang' => 'zh_CN',
]);
return $response->json();
} catch (\Exception $e) {
\Log::error('获取微信用户信息失败: ' . $e->getMessage());
return null;
}
}
/**
* 获取第三方平台 component_access_token
*/
private function getComponentAccessToken(): ?string
{
$cacheKey = 'wechat_component_access_token';
$token = Cache::get($cacheKey);
if ($token) {
return $token;
}
$config = $this->getConfig();
// 如果是第三方平台模式,需要使用 component_appid 和 component_appsecret
// 这里简化处理,假设使用的是独立应用
return null;
}
/**
* 发送模板消息
*/
public function sendTemplateMessage(string $openid, string $templateId, array $data, string $url = ''): bool
{
$config = $this->getConfig();
if (!$config['enabled']) {
return false;
}
try {
$accessToken = $this->getComponentAccessToken();
if (!$accessToken) {
// 使用小程序的 access_token
$accessToken = $this->getMiniProgramAccessToken();
}
$response = \Illuminate\Support\Facades\Http::post("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={$accessToken}", [
'touser' => $openid,
'template_id' => $templateId,
'url' => $url,
'data' => $data,
]);
$result = $response->json();
return ($result['errcode'] ?? 1) === 0;
} catch (\Exception $e) {
\Log::error('发送微信模板消息失败: ' . $e->getMessage());
return false;
}
}
/**
* 获取小程序 access_token
*/
private function getMiniProgramAccessToken(): ?string
{
$cacheKey = 'wechat_mini_program_access_token';
$token = Cache::get($cacheKey);
if ($token) {
return $token;
}
$config = $this->getConfig();
try {
$response = \Illuminate\Support\Facades\Http::get('https://api.weixin.qq.com/cgi-bin/token', [
'grant_type' => 'client_credential',
'appid' => $config['app_id'],
'secret' => $config['app_secret'],
]);
$data = $response->json();
if (isset($data['access_token'])) {
Cache::put($cacheKey, $data['access_token'], now()->addSeconds($data['expires_in'] - 200));
return $data['access_token'];
}
} catch (\Exception $e) {
\Log::error('获取小程序access_token失败: ' . $e->getMessage());
}
return null;
}
}