This commit is contained in:
李志强 2025-06-06 18:18:31 +08:00
parent b5ac7e8f32
commit 7b4e41efc4
4 changed files with 771 additions and 98 deletions

View File

@ -5,22 +5,101 @@ use think\facade\Request;
use think\facade\Log; use think\facade\Log;
use think\facade\Cache; use think\facade\Cache;
use GuzzleHttp\Client; use GuzzleHttp\Client;
use app\index\model\User;
use app\index\model\AdminConfig; use app\index\model\AdminConfig;
class WechatController extends BaseController class WechatController extends BaseController
{ {
/**
* 测试接口是否正常工作
*/
public function test()
{
try {
// 设置响应头
header('Content-Type: application/json; charset=utf-8');
$data = [
'time' => date('Y-m-d H:i:s'),
'status' => 'ok',
'server' => [
'REQUEST_METHOD' => $_SERVER['REQUEST_METHOD'] ?? '',
'REQUEST_URI' => $_SERVER['REQUEST_URI'] ?? '',
'HTTP_HOST' => $_SERVER['HTTP_HOST'] ?? '',
'REMOTE_ADDR' => $_SERVER['REMOTE_ADDR'] ?? '',
]
];
// 记录详细日志
Log::info('接口测试 - 请求信息:' . json_encode($data, JSON_UNESCAPED_UNICODE));
return json($data, JSON_UNESCAPED_UNICODE);
} catch (\Exception $e) {
$error = [
'error' => $e->getMessage(),
'time' => date('Y-m-d H:i:s')
];
Log::error('接口测试错误:' . json_encode($error, JSON_UNESCAPED_UNICODE));
return json($error, JSON_UNESCAPED_UNICODE);
}
}
public function index() public function index()
{ {
// 检查请求方法 try {
if (Request::method() == 'GET') { // 设置响应头
// 首次验证服务器地址的有效性 header('Content-Type: text/html; charset=utf-8');
$this->checkSignature();
} elseif (Request::method() == 'POST') { // 记录原始请求信息
// 接收消息并回复 $requestInfo = [
$response = $this->receiveMessage(); 'time' => date('Y-m-d H:i:s'),
// 直接输出回复的XML字符串 'method' => Request::method(),
echo $response; 'url' => Request::url(true),
'ip' => Request::ip(),
'params' => Request::param(),
'headers' => getallheaders(),
'server' => [
'REQUEST_METHOD' => $_SERVER['REQUEST_METHOD'] ?? '',
'REQUEST_URI' => $_SERVER['REQUEST_URI'] ?? '',
'HTTP_HOST' => $_SERVER['HTTP_HOST'] ?? '',
'REMOTE_ADDR' => $_SERVER['REMOTE_ADDR'] ?? '',
'QUERY_STRING' => $_SERVER['QUERY_STRING'] ?? '',
'HTTP_USER_AGENT' => $_SERVER['HTTP_USER_AGENT'] ?? '',
'HTTP_REFERER' => $_SERVER['HTTP_REFERER'] ?? '',
]
];
Log::info('微信接口访问请求信息:' . json_encode($requestInfo, JSON_UNESCAPED_UNICODE));
// 获取原始数据
$rawData = file_get_contents("php://input");
if (!empty($rawData)) {
$rawData = mb_convert_encoding($rawData, 'UTF-8', 'UTF-8,GBK,GB2312');
Log::info('微信接口原始数据:' . $rawData);
}
// 检查请求方法
if (Request::method() == 'GET') {
Log::info('微信接口GET请求进行签名验证');
// 首次验证服务器地址的有效性
$this->checkSignature();
} elseif (Request::method() == 'POST') {
Log::info('微信接口POST请求处理消息');
// 接收消息并回复
$response = $this->receiveMessage();
// 直接输出回复的XML字符串
echo $response;
exit;
} else {
Log::error('微信接口:不支持的请求方法 - ' . Request::method());
echo '';
exit;
}
} catch (\Exception $e) {
Log::error('微信接口错误:' . $e->getMessage());
Log::error('错误堆栈:' . $e->getTraceAsString());
// 返回空字符串,避免微信服务器重试
echo '';
exit; exit;
} }
} }
@ -28,18 +107,62 @@ class WechatController extends BaseController
// 验证签名 // 验证签名
protected function checkSignature() protected function checkSignature()
{ {
$signature = Request::get('signature'); try {
$timestamp = Request::get('timestamp'); $signature = Request::get('signature');
$nonce = Request::get('nonce'); $timestamp = Request::get('timestamp');
$echostr = Request::get('echostr'); $nonce = Request::get('nonce');
$token = AdminConfig::where('config_name', 'wechat_token')->value('config_value'); $echostr = Request::get('echostr');
$tmpArr = array($token, $timestamp, $nonce);
sort($tmpArr, SORT_STRING); $debugInfo = [
$tmpStr = implode($tmpArr); 'signature' => $signature,
$tmpStr = sha1($tmpStr); 'timestamp' => $timestamp,
'nonce' => $nonce,
'echostr' => $echostr,
'url' => Request::url(true),
'time' => date('Y-m-d H:i:s')
];
Log::info('微信验证参数:', $debugInfo);
if (empty($signature) || empty($timestamp) || empty($nonce)) {
Log::error('微信验证参数缺失', $debugInfo);
exit;
}
if ($tmpStr == $signature) { $token = AdminConfig::where('config_name', 'wechat_token')->value('config_value');
echo $echostr; if (empty($token)) {
Log::error('微信token未配置');
exit;
}
Log::info('微信token' . $token);
$tmpArr = array($token, $timestamp, $nonce);
sort($tmpArr, SORT_STRING);
$tmpStr = implode($tmpArr);
$tmpStr = sha1($tmpStr);
$verifyInfo = [
'tmpStr' => $tmpStr,
'signature' => $signature,
'token' => $token,
'timestamp' => $timestamp,
'nonce' => $nonce
];
Log::info('签名验证:', $verifyInfo);
if ($tmpStr == $signature) {
Log::info('微信签名验证成功');
echo $echostr;
exit;
} else {
Log::error('微信签名验证失败', $verifyInfo);
exit;
}
} catch (\Exception $e) {
Log::error('微信验证签名错误:' . $e->getMessage());
Log::error('错误堆栈:' . $e->getTraceAsString());
exit; exit;
} }
} }
@ -47,45 +170,128 @@ class WechatController extends BaseController
// 接收消息 // 接收消息
protected function receiveMessage() protected function receiveMessage()
{ {
$postStr = file_get_contents("php://input"); try {
if (empty($postStr)) { $postStr = file_get_contents("php://input");
return ''; if (empty($postStr)) {
Log::error('微信消息:接收数据为空');
return '';
}
// 转换编码
$postStr = mb_convert_encoding($postStr, 'UTF-8', 'UTF-8,GBK,GB2312');
Log::info('微信消息:' . $postStr);
libxml_disable_entity_loader(true);
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
if ($postObj === false) {
Log::error('微信消息XML解析失败');
return '';
}
// 检查消息类型
$msgType = strtolower((string) $postObj->MsgType);
Log::info('微信消息类型:' . $msgType);
// 处理事件消息
if ($msgType == 'event') {
$event = strtolower((string) $postObj->Event);
Log::info('微信事件类型:' . $event);
// 处理扫码事件和关注事件
if ($event == 'scan' || $event == 'subscribe') {
$scene_str = trim((string) $postObj->EventKey);
// 如果是关注事件,需要去掉前缀 'qrscene_'
if ($event == 'subscribe' && strpos($scene_str, 'qrscene_') === 0) {
$scene_str = substr($scene_str, 8);
}
$fromUsername = trim((string) $postObj->FromUserName);
$toUsername = trim((string) $postObj->ToUserName);
$ticket = (string) $postObj->Ticket;
Log::info('微信扫码/关注事件', [
'event' => $event,
'scene_str' => $scene_str,
'fromUsername' => $fromUsername,
'toUsername' => $toUsername,
'ticket' => $ticket,
'time' => date('Y-m-d H:i:s')
]);
// 创建票据保存目录
$upload_dir = 'public/storage/uploads/ticket/';
if (!is_dir($upload_dir)) {
mkdir($upload_dir, 0755, true);
Log::info('创建票据保存目录:' . $upload_dir);
}
// 保存扫码数据
$data = [
'openid' => $fromUsername,
'scene_str' => $scene_str,
'ticket' => $ticket,
'scan_time' => time(),
'event' => $event
];
$content = json_encode($data, JSON_UNESCAPED_UNICODE);
$file = $upload_dir . $scene_str . "_" . $ticket . ".json";
file_put_contents($file, $content);
Log::info('保存扫码数据到文件:' . $file);
// 获取用户信息
try {
$accessToken = $this->getGZHAccessToken();
$url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token={$accessToken}&openid={$fromUsername}&lang=zh_CN";
$client = new Client(['verify' => false]);
$response = $client->get($url);
$userInfo = json_decode($response->getBody(), true);
Log::info('获取用户信息结果:' . json_encode($userInfo, JSON_UNESCAPED_UNICODE));
if (isset($userInfo['openid'])) {
// 保存用户信息到数据库
$user = User::where('openid', $fromUsername)->find();
if (!$user) {
$user = new User;
$user->openid = $fromUsername;
$user->name = $userInfo['nickname'] ?? '';
$user->avatar = $userInfo['headimgurl'] ?? '';
$user->save();
Log::info('创建新用户', ['user' => $user->toArray()]);
} else {
// 更新用户信息
$user->name = $userInfo['nickname'] ?? $user->name;
$user->avatar = $userInfo['headimgurl'] ?? $user->avatar;
$user->save();
Log::info('更新用户信息', ['user' => $user->toArray()]);
}
// 更新票据文件中的用户信息
$data['user_info'] = [
'uid' => $user->uid,
'name' => $user->name,
'avatar' => $user->avatar,
'openid' => $user->openid
];
file_put_contents($file, json_encode($data, JSON_UNESCAPED_UNICODE));
Log::info('更新票据文件中的用户信息');
}
} catch (\Exception $e) {
Log::error('获取用户信息失败:' . $e->getMessage());
Log::error('错误堆栈:' . $e->getTraceAsString());
}
return 'success';
}
}
return 'success';
} catch (\Exception $e) {
Log::error('处理微信消息错误:' . $e->getMessage());
Log::error('错误堆栈:' . $e->getTraceAsString());
return 'success';
} }
libxml_disable_entity_loader(true);
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
Log::write($postObj);
// 检查消息类型
$msgType = strtolower((string) $postObj->MsgType);
if ($msgType == 'text') {
// 提取消息内容
$fromUsername = (string) $postObj->FromUserName; // 微信用户openid
$toUsername = (string) $postObj->ToUserName; // 公众号id
$keyword = trim((string) $postObj->Content);
// 构造自动回复的文本消息
$time = time();
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[%s]]></Content>
<FuncFlag>0</FuncFlag>
</xml>";
$responseContent = "消息标题";
$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $responseContent);
// 假设已经确定要发送小程序卡片消息
$this->sendMiniProgramCard((string) $postObj->FromUserName);
return $resultStr;
}
// 如果需要处理其他类型的消息,可以在这里添加相应的逻辑
// 如果不是文本消息,可以返回一个空字符串或错误消息
return '';
} }
// 发送小程序卡片消息的方法 // 发送小程序卡片消息的方法
@ -165,19 +371,113 @@ class WechatController extends BaseController
public function getLoginTicket() public function getLoginTicket()
{ {
try { try {
Log::info('开始获取微信登录二维码');
// 获取access_token // 获取access_token
$access_token = $this->getGZHAccessToken(); $access_token = $this->getGZHAccessToken();
Log::info('获取access_token成功' . $access_token);
// 构建请求URL - 使用正确的接口生成临时二维码 // 构建请求URL - 使用正确的接口生成临时二维码
$url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={$access_token}"; $url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={$access_token}";
// 生成唯一场景值
$scene_str = md5(uniqid() . time());
Log::info('生成场景值:' . $scene_str);
// 准备请求数据 - 生成临时二维码有效期5分钟 // 准备请求数据 - 生成临时二维码有效期5分钟
$postData = json_encode([ $postData = json_encode([
'expire_seconds' => 300, // 5分钟有效期 'expire_seconds' => 300, // 5分钟有效期
'action_name' => 'QR_STR_SCENE', 'action_name' => 'QR_STR_SCENE',
'action_info' => [ 'action_info' => [
'scene' => [ 'scene' => [
'scene_str' => md5(uniqid() . time()) // 生成唯一场景值 'scene_str' => $scene_str
]
]
]);
// 发送请求获取ticket
$client = new Client(['verify' => false]);
$response = $client->post($url, [
'body' => $postData,
'headers' => [
'Content-Type' => 'application/json'
]
]);
$result = json_decode($response->getBody(), true);
Log::info('微信返回结果:' . json_encode($result, JSON_UNESCAPED_UNICODE));
if (isset($result['errcode']) && $result['errcode'] != 0) {
Log::error('获取二维码失败:' . $result['errmsg']);
return json(['code' => 1, 'msg' => '获取二维码失败:' . $result['errmsg']]);
}
// 使用ticket获取二维码图片URL
$ticket = urlencode($result['ticket']);
$qrcodeUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={$ticket}";
// 将场景值保存到缓存中,用于后续验证
Cache::set('wx_login_scene_' . $result['ticket'], [
'scene_str' => $scene_str,
'create_time' => time(),
'expire_time' => time() + 300
], 300);
Log::info('二维码生成成功', [
'ticket' => $result['ticket'],
'scene_str' => $scene_str,
'expire_time' => time() + 300
]);
return json([
'code' => 0,
'msg' => '获取二维码成功',
'data' => [
'ticket' => $result['ticket'],
'expire_seconds' => $result['expire_seconds'],
'url' => $qrcodeUrl,
'scene_str' => $scene_str
]
]);
} catch (\Exception $e) {
Log::error('获取微信登录二维码失败:' . $e->getMessage());
Log::error('错误堆栈:' . $e->getTraceAsString());
return json(['code' => 1, 'msg' => '获取二维码失败:' . $e->getMessage()]);
}
}
/**
* 重新生成二维码
* @return \think\response\Json
*/
public function reGenerateQrcode()
{
try {
$scene_str = Request::post('scene_str');
if (empty($scene_str)) {
return json(['code' => 1, 'msg' => '参数错误']);
}
// 清除旧的缓存
Cache::delete('wx_login_scene_' . $scene_str);
// 获取access_token
$access_token = $this->getGZHAccessToken();
// 构建请求URL
$url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={$access_token}";
// 生成新的场景值
$new_scene_str = md5(uniqid() . time());
// 准备请求数据
$postData = json_encode([
'expire_seconds' => 300,
'action_name' => 'QR_STR_SCENE',
'action_info' => [
'scene' => [
'scene_str' => $new_scene_str
] ]
] ]
]); ]);
@ -201,9 +501,9 @@ class WechatController extends BaseController
$ticket = urlencode($result['ticket']); $ticket = urlencode($result['ticket']);
$qrcodeUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={$ticket}"; $qrcodeUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={$ticket}";
// 将场景值保存到缓存中,用于后续验证 // 将新的场景值保存到缓存中
Cache::set('wx_login_scene_' . $result['ticket'], [ Cache::set('wx_login_scene_' . $new_scene_str, [
'scene_str' => $postData['action_info']['scene']['scene_str'], 'scene_str' => $new_scene_str,
'create_time' => time(), 'create_time' => time(),
'expire_time' => time() + 300 'expire_time' => time() + 300
], 300); ], 300);
@ -215,13 +515,176 @@ class WechatController extends BaseController
'ticket' => $result['ticket'], 'ticket' => $result['ticket'],
'expire_seconds' => $result['expire_seconds'], 'expire_seconds' => $result['expire_seconds'],
'url' => $qrcodeUrl, 'url' => $qrcodeUrl,
'scene_str' => $postData['action_info']['scene']['scene_str'] 'scene_str' => $new_scene_str
] ]
]); ]);
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('获取微信登录二维码失败:' . $e->getMessage()); Log::error('重新生成二维码失败:' . $e->getMessage());
return json(['code' => 1, 'msg' => '获取二维码失败:' . $e->getMessage()]); return json(['code' => 1, 'msg' => '重新生成二维码失败:' . $e->getMessage()]);
}
}
/**
* 检查微信扫码登录状态
* @return \think\response\Json
*/
public function checkLoginStatus()
{
try {
$scene_str = Request::post('scene_str');
$ticket = Request::post('ticket');
Log::info('检查登录状态', [
'scene_str' => $scene_str,
'ticket' => $ticket,
'time' => date('Y-m-d H:i:s')
]);
if (empty($scene_str) || empty($ticket)) {
Log::warning('检查登录状态参数错误', [
'scene_str' => $scene_str,
'ticket' => $ticket
]);
return json(['code' => 0, 'msg' => '参数错误']);
}
// 检查票据文件
$file = 'public/storage/uploads/ticket/' . $scene_str . "_" . $ticket . ".json";
Log::info('检查票据文件:' . $file);
if (file_exists($file)) {
$loginData = json_decode(file_get_contents($file), true);
Log::info('票据文件内容:' . json_encode($loginData, JSON_UNESCAPED_UNICODE));
if ($loginData) {
// 检查是否包含用户信息
if (isset($loginData['user_info'])) {
Log::info('用户已扫码登录', [
'user_info' => $loginData['user_info']
]);
// 设置登录session
session('user_id', $loginData['user_info']['uid']);
session('user_info', $loginData['user_info']);
session('openid', $loginData['user_info']['openid']);
// 删除临时文件
unlink($file);
return json(['code' => 1, 'msg' => '登录成功']);
} else {
Log::info('等待获取用户信息');
return json(['code' => 0, 'msg' => '正在获取用户信息,请稍候...']);
}
}
}
Log::info('等待扫码');
return json(['code' => 0, 'msg' => '等待扫码']);
} catch (\Exception $e) {
Log::error('检查登录状态失败:' . $e->getMessage());
Log::error('错误堆栈:' . $e->getTraceAsString());
return json(['code' => 0, 'msg' => '系统错误']);
}
}
/**
* 根据openid获取用户信息
* @param string $openid
* @return array|null
*/
private function getUserInfoByOpenid($openid)
{
try {
// 这里需要根据你的用户表结构来实现
// 示例从用户表中查询openid对应的用户信息
$user = User::where('openid', $openid)->find();
if ($user) {
return $user->toArray();
}
return null;
} catch (\Exception $e) {
Log::error('获取用户信息失败:' . $e->getMessage());
return null;
}
}
/**
* 测试微信服务器访问
*/
public function testWechat()
{
try {
// 记录所有请求信息
$requestInfo = [
'time' => date('Y-m-d H:i:s'),
'method' => Request::method(),
'url' => Request::url(true),
'ip' => Request::ip(),
'params' => Request::param(),
'headers' => getallheaders(),
'server' => [
'REQUEST_METHOD' => $_SERVER['REQUEST_METHOD'] ?? '',
'REQUEST_URI' => $_SERVER['REQUEST_URI'] ?? '',
'HTTP_HOST' => $_SERVER['HTTP_HOST'] ?? '',
'REMOTE_ADDR' => $_SERVER['REMOTE_ADDR'] ?? '',
'QUERY_STRING' => $_SERVER['QUERY_STRING'] ?? '',
'HTTP_USER_AGENT' => $_SERVER['HTTP_USER_AGENT'] ?? '',
'HTTP_REFERER' => $_SERVER['HTTP_REFERER'] ?? '',
]
];
Log::info('微信测试接口访问:' . json_encode($requestInfo, JSON_UNESCAPED_UNICODE));
// 获取原始数据
$rawData = file_get_contents("php://input");
if (!empty($rawData)) {
$rawData = mb_convert_encoding($rawData, 'UTF-8', 'UTF-8,GBK,GB2312');
Log::info('微信测试接口原始数据:' . $rawData);
}
// 如果是GET请求进行签名验证
if (Request::method() == 'GET') {
$signature = Request::get('signature');
$timestamp = Request::get('timestamp');
$nonce = Request::get('nonce');
$echostr = Request::get('echostr');
Log::info('微信测试接口验证参数:', [
'signature' => $signature,
'timestamp' => $timestamp,
'nonce' => $nonce,
'echostr' => $echostr
]);
if (!empty($signature) && !empty($timestamp) && !empty($nonce)) {
$token = AdminConfig::where('config_name', 'wechat_token')->value('config_value');
if (empty($token)) {
Log::error('微信token未配置');
return 'token not configured';
}
$tmpArr = array($token, $timestamp, $nonce);
sort($tmpArr, SORT_STRING);
$tmpStr = implode($tmpArr);
$tmpStr = sha1($tmpStr);
if ($tmpStr == $signature) {
Log::info('微信测试接口验证成功');
return $echostr;
} else {
Log::error('微信测试接口验证失败');
return 'signature verification failed';
}
}
}
return 'success';
} catch (\Exception $e) {
Log::error('微信测试接口错误:' . $e->getMessage());
Log::error('错误堆栈:' . $e->getTraceAsString());
return 'error';
} }
} }
} }

View File

@ -112,11 +112,12 @@
.wechat-login { .wechat-login {
text-align: center; text-align: center;
padding: 30px 0; padding: 30px 0;
padding-bottom: 60px;
} }
.wechat-login img { .wechat-login img {
width: 60px; width: 200px;
height: 60px; height: 200px;
transition: transform 0.3s; transition: transform 0.3s;
} }
@ -129,6 +130,30 @@
color: #666; color: #666;
} }
#qrcode-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
#qrcode-loading {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
#qrcode-loading .layui-icon {
font-size: 40px;
color: #409eff;
}
#qrcode-loading p {
margin-top: 10px;
color: #666;
}
.layui-input-inline { .layui-input-inline {
margin-right: 0px !important; margin-right: 0px !important;
} }
@ -144,6 +169,33 @@
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
} }
.container {
width: 100%;
max-width: 400px;
/* margin: 50px auto; */
text-align: center;
}
.qrcode-container {
margin: 20px 0;
}
.qrcode-container img {
max-width: 200px;
cursor: pointer;
}
.qrcode-container p {
color: #666;
font-size: 14px;
margin-top: 10px;
}
.status {
color: #666;
margin: 10px 0;
}
.error {
color: #ff4d4f;
margin: 10px 0;
}
</style> </style>
</head> </head>
@ -220,8 +272,15 @@
</div> --> </div> -->
<div class="layui-tab-item" id="wechat"> <div class="layui-tab-item" id="wechat">
<div class="wechat-login"> <div class="wechat-login">
<img src="" alt="微信登录" class="layui-img"> <div class="container">
<p>点击使用微信登录</p> <h2>微信扫码登录</h2>
<div class="qrcode-container">
<img id="qrcode" src="" alt="微信登录二维码" onclick="reGenerateQrcode()">
<p>点击二维码可刷新</p>
</div>
<div id="status" class="status">正在加载二维码...</div>
<div id="error" class="error"></div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -232,6 +291,131 @@
var form = layui.form; var form = layui.form;
var element = layui.element; var element = layui.element;
var $ = layui.jquery; var $ = layui.jquery;
var layer = layui.layer;
// 微信登录相关变量
var checkLoginTimer = null;
var currentSceneStr = '';
var currentTicket = '';
var qrcodeExpireTime = 0; // 二维码过期时间
// 获取微信登录二维码
function getQrcode() {
$.ajax({
url: '/index/wechat/getLoginTicket',
type: 'GET',
success: function(res) {
if (res.code === 0) {
$('#qrcode').attr('src', res.data.url);
currentSceneStr = res.data.scene_str;
currentTicket = res.data.ticket;
// 设置二维码过期时间5分钟
qrcodeExpireTime = new Date().getTime() + (res.data.expire_seconds * 1000);
$('#status').text('等待扫码...');
$('#error').text('');
// 开始检查登录状态
startCheckLogin();
} else {
$('#error').text('获取二维码失败:' + res.msg);
}
},
error: function() {
$('#error').text('获取二维码失败,请刷新页面重试');
}
});
}
// 重新生成二维码
function reGenerateQrcode() {
if (!currentSceneStr) {
getQrcode();
return;
}
// 清除之前的定时器
if (checkLoginTimer) {
clearInterval(checkLoginTimer);
checkLoginTimer = null;
}
$.ajax({
url: '/index/wechat/reGenerateQrcode',
type: 'POST',
data: {
scene_str: currentSceneStr
},
success: function(res) {
if (res.code === 0) {
$('#qrcode').attr('src', res.data.url);
currentSceneStr = res.data.scene_str;
currentTicket = res.data.ticket;
// 设置新的二维码过期时间5分钟
qrcodeExpireTime = new Date().getTime() + (res.data.expire_seconds * 1000);
$('#status').text('等待扫码...');
$('#error').text('');
// 开始检查登录状态
startCheckLogin();
} else {
$('#error').text('刷新二维码失败:' + res.msg);
}
},
error: function() {
$('#error').text('刷新二维码失败,请重试');
}
});
}
// 开始检查登录状态
function startCheckLogin() {
if (checkLoginTimer) {
clearInterval(checkLoginTimer);
}
checkLoginTimer = setInterval(function() {
// 检查二维码是否过期
if (new Date().getTime() > qrcodeExpireTime) {
clearInterval(checkLoginTimer);
$('#status').text('二维码已过期,请点击刷新');
$('#qrcode').css('opacity', '0.5');
return;
}
$.ajax({
url: '/index/wechat/checkLoginStatus',
type: 'POST',
data: {
scene_str: currentSceneStr,
ticket: currentTicket
},
success: function(res) {
if (res.code === 1) {
// 登录成功
clearInterval(checkLoginTimer);
$('#status').text('登录成功,正在跳转...');
// 保存用户信息到localStorage
if (res.data && res.data.user_info) {
localStorage.setItem('user_info', JSON.stringify(res.data.user_info));
}
// 跳转到首页或其他页面
setTimeout(function() {
window.location.href = '/';
}, 1000);
} else if (res.code === 0) {
// 更新状态信息
$('#status').text(res.msg);
}
},
error: function() {
$('#error').text('检查登录状态失败,请重试');
}
});
}, 2000); // 每2秒检查一次
}
// 页面加载完成后获取二维码
$(document).ready(function() {
getQrcode();
});
// 检查极验验证是否开启 // 检查极验验证是否开启
<?php if ($config['geetest_open'] == 1): ?> <?php if ($config['geetest_open'] == 1): ?>
@ -327,17 +511,12 @@
}); });
// 点击获取验证码按钮时验证 // 点击获取验证码按钮时验证
document.getElementById('getCode').addEventListener('click', function () { var getCodeBtn = document.getElementById('getCode');
var validate = captchaObj.getValidate(); if (getCodeBtn) {
if (!validate) { getCodeBtn.addEventListener('click', function () {
layer.msg('请完成验证码验证', { console.log('获取验证码');
icon: 2, });
time: 2000 }
});
return;
}
console.log('获取验证码');
});
}; };
// 直接使用配置初始化极验验证,并添加错误处理 // 直接使用配置初始化极验验证,并添加错误处理
@ -418,9 +597,12 @@
}); });
// 移除获取验证码按钮的验证码验证逻辑 // 移除获取验证码按钮的验证码验证逻辑
document.getElementById('getCode').addEventListener('click', function () { var getCodeBtn = document.getElementById('getCode');
console.log('获取验证码'); if (getCodeBtn) {
}); getCodeBtn.addEventListener('click', function () {
console.log('获取验证码');
});
}
<?php endif; ?> <?php endif; ?>
// 页面加载时检查是否有保存的登录数据 // 页面加载时检查是否有保存的登录数据

View File

@ -5,11 +5,16 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
return [ return [
// 默认日志记录通道 // 默认日志记录通道
'default' => env('log.channel', 'file'), 'default' => 'file',
// 日志记录级别 // 日志记录级别
'level' => [], 'level' => ['error', 'warning', 'info', 'debug'],
// 日志类型记录的通道 ['error'=>'email',...] // 日志类型记录的通道
'type_channel' => [], 'type_channel' => [
'error' => 'file',
'warning' => 'file',
'info' => 'file',
'debug' => 'file',
],
// 关闭全局日志写入 // 关闭全局日志写入
'close' => false, 'close' => false,
// 全局日志处理 支持闭包 // 全局日志处理 支持闭包
@ -17,27 +22,27 @@ return [
// 日志通道列表 // 日志通道列表
'channels' => [ 'channels' => [
'file' => [ 'file' => [
// 日志记录方式 // 日志记录方式
'type' => 'File', 'type' => 'File',
// 日志保存目录 // 日志保存目录
'path' => '', 'path' => runtime_path() . 'log',
// 单文件日志写入 // 单文件日志写入
'single' => false, 'single' => false,
// 独立日志级别 // 独立日志级别
'apart_level' => [], 'apart_level' => ['error', 'warning', 'info', 'debug'],
// 最大日志文件数量 // 最大日志文件数量
'max_files' => 0, 'max_files' => 30,
// 使用JSON格式记录 // 使用JSON格式记录
'json' => false, 'json' => false,
// 日志处理 // 日志处理
'processor' => null, 'processor' => null,
// 关闭通道日志写入 // 关闭通道日志写入
'close' => false, 'close' => false,
// 日志输出格式化 // 日志输出格式化
'format' => '[%s][%s] %s', 'format' => '[%s][%s] %s',
// 是否实时写入 // 是否实时写入
'realtime_write' => false, 'realtime_write' => true,
], ],
// 其它日志通道配置 // 其它日志通道配置
], ],

View File

@ -0,0 +1,23 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
use think\facade\Route;
// 微信接口路由
Route::get('index/wechat/index', 'index/wechat/index');
Route::post('index/wechat/index', 'index/wechat/index');
Route::get('index/wechat/test', 'index/wechat/test');
Route::get('index/wechat/getLoginTicket', 'index/wechat/getLoginTicket');
Route::post('index/wechat/checkLoginStatus', 'index/wechat/checkLoginStatus');
Route::post('index/wechat/reGenerateQrcode', 'index/wechat/reGenerateQrcode');
Route::get('index/wechat/testWechat', 'index/wechat/testWechat');
Route::post('index/wechat/testWechat', 'index/wechat/testWechat');
// ... existing code ...