From 95246fda4ec5a790cf13c688ef97d4716a6b131f Mon Sep 17 00:00:00 2001 From: wong <106998207@qq.com> Date: Fri, 2 May 2025 15:40:11 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/WebSocketController.php | 126 ++-- .../controller/WebSocketControllerCopy.php | 557 ++++++++++++++++++ .../api/model/WechatMomentsModel.php | 11 + Server/application/command.php | 1 + .../command/WechatMomentsCommand.php | 100 ++++ .../controller/ContentLibraryController.php | 86 +-- Server/application/job/WechatMomentsJob.php | 176 ++++++ 7 files changed, 953 insertions(+), 104 deletions(-) create mode 100644 Server/application/api/controller/WebSocketControllerCopy.php create mode 100644 Server/application/api/model/WechatMomentsModel.php create mode 100644 Server/application/command/WechatMomentsCommand.php create mode 100644 Server/application/job/WechatMomentsJob.php diff --git a/Server/application/api/controller/WebSocketController.php b/Server/application/api/controller/WebSocketController.php index fa59bb25..ff6f4167 100644 --- a/Server/application/api/controller/WebSocketController.php +++ b/Server/application/api/controller/WebSocketController.php @@ -6,9 +6,13 @@ namespace app\api\controller; use think\cache\driver\Redis; use think\Db; -use think\Log; +use think\facade\Log; use WebSocket\Client; use think\facade\Env; +use app\api\model\WechatFriendModel as WechatFriend; +use app\api\model\WechatMomentsModel as WechatMoments; + + class WebSocketController extends BaseController { @@ -48,7 +52,7 @@ class WebSocketController extends BaseController 'username' => $userData['userName'], 'password' => $userData['password'] ]; - + // 调用登录接口获取token $headerData = ['client:kefu-client']; $header = setHeader($headerData, '', 'plain'); @@ -71,7 +75,7 @@ class WebSocketController extends BaseController } $this->connect(); - } + } /** * 建立WebSocket连接 @@ -79,39 +83,39 @@ class WebSocketController extends BaseController protected function connect() { try { - //证书 - $context = stream_context_create(); - stream_context_set_option($context, 'ssl', 'verify_peer', false); - stream_context_set_option($context, 'ssl', 'verify_peer_name', false); + //证书 + $context = stream_context_create(); + stream_context_set_option($context, 'ssl', 'verify_peer', false); + stream_context_set_option($context, 'ssl', 'verify_peer_name', false); - //开启WS链接 - $result = [ - "accessToken" => $this->authorized, - "accountId" => $this->accountId, - "client" => "kefu-client", - "cmdType" => "CmdSignIn", - "seq" => 1, - ]; + //开启WS链接 + $result = [ + "accessToken" => $this->authorized, + "accountId" => $this->accountId, + "client" => "kefu-client", + "cmdType" => "CmdSignIn", + "seq" => 1, + ]; - $content = json_encode($result); - $this->client = new Client("wss://kf.quwanzhi.com:9993", - [ - 'filter' => ['text', 'binary', 'ping', 'pong', 'close','receive', 'send'], - 'context' => $context, - 'headers' => [ - 'Sec-WebSocket-Protocol' => 'soap', - 'origin' => 'localhost', - ], - 'timeout' => 86400, - ] - ); + $content = json_encode($result); + $this->client = new Client("wss://kf.quwanzhi.com:9993", + [ + 'filter' => ['text', 'binary', 'ping', 'pong', 'close','receive', 'send'], + 'context' => $context, + 'headers' => [ + 'Sec-WebSocket-Protocol' => 'soap', + 'origin' => 'localhost', + ], + 'timeout' => 86400, + ] + ); - $this->client->send($content); + $this->client->send($content); $this->isConnected = true; $this->lastHeartbeatTime = time(); // 启动心跳检测 - $this->startHeartbeat(); + //$this->startHeartbeat(); } catch (\Exception $e) { Log::error("WebSocket连接失败:" . $e->getMessage()); @@ -211,9 +215,9 @@ class WebSocketController extends BaseController { $count = !empty($data['count']) ? $data['count'] : 10; $wechatAccountId = !empty($data['wechatAccountId']) ? $data['wechatAccountId'] : ''; - $wechatFriendId = !empty($data['wechatFriendId']) ? $data['wechatFriendId'] : ''; + $wechatFriendId = !empty($data['wechatFriendId']) ? $data['wechatFriendId'] : 0; $prevSnsId = !empty($data['prevSnsId']) ? $data['prevSnsId'] : 0; - $maxPages = 10; // 最大页数 + $maxPages = 20; // 最大页数限制为20 $currentPage = 1; // 当前页码 $allMoments = []; // 存储所有朋友圈数据 @@ -221,9 +225,6 @@ class WebSocketController extends BaseController if (empty($wechatAccountId)) { return json_encode(['code'=>400,'msg'=>'指定账号不能为空']); } - if (empty($wechatFriendId)) { - return json_encode(['code'=>400,'msg'=>'指定好友不能为空']); - } try { do { @@ -238,13 +239,17 @@ class WebSocketController extends BaseController "seq" => time(), ]; + Log::info('获取朋友圈信:' . json_encode($params, 256)); $message = $this->sendMessage($params); + Log::info('获取朋友圈信成功:' . json_encode($message, 256)); // 检查返回结果 - if (!isset($message['result']) || empty($message['result'])) { + if (!isset($message['result']) || empty($message['result']) || !is_array($message['result'])) { break; } + + // 合并朋友圈数据 $allMoments = array_merge($allMoments, $message['result']); @@ -262,6 +267,7 @@ class WebSocketController extends BaseController // 如果已经达到最大页数,退出循环 if ($currentPage > $maxPages) { + Log::info('已达到最大页数限制(' . $maxPages . '页),结束本次任务'); break; } @@ -279,8 +285,6 @@ class WebSocketController extends BaseController 'data' => [ 'list' => $allMoments, 'total' => count($allMoments), - 'currentPage' => $currentPage - 1, - 'hasMore' => $currentPage > $maxPages || count($message['result']) >= $count, 'nextPrevSnsId' => $prevSnsId ] ]; @@ -291,7 +295,7 @@ class WebSocketController extends BaseController } } - /** + /** * 朋友圈点赞 * @return \think\response\Json */ @@ -313,14 +317,14 @@ class WebSocketController extends BaseController } try { - $result = [ - "cmdType" => "CmdMomentInteract", - "momentInteractType" => 1, - "seq" => time(), + $result = [ + "cmdType" => "CmdMomentInteract", + "momentInteractType" => 1, + "seq" => time(), "snsId" => $data['snsId'], "wechatAccountId" => $data['wechatAccountId'], - "wechatFriendId" => 0, - ]; + "wechatFriendId" => 0, + ]; $message = $this->sendMessage($result); return json_encode(['code'=>200,'msg'=>'点赞成功','data'=>$message]); @@ -332,7 +336,7 @@ class WebSocketController extends BaseController } } - /** + /** * 朋友圈取消点赞 * @return \think\response\Json */ @@ -354,16 +358,16 @@ class WebSocketController extends BaseController } try { - $result = [ - "CommentId2" => '', - "CommentTime" => 0, - "cmdType" => "CmdMomentCancelInteract", - "optType" => 1, - "seq" => time(), + $result = [ + "CommentId2" => '', + "CommentTime" => 0, + "cmdType" => "CmdMomentCancelInteract", + "optType" => 1, + "seq" => time(), "snsId" => $data['snsId'], "wechatAccountId" => $data['wechatAccountId'], - "wechatFriendId" => 0, - ]; + "wechatFriendId" => 0, + ]; $message = $this->sendMessage($result); return json_encode(['code'=>200,'msg'=>'取消点赞成功','data'=>$message]); @@ -415,10 +419,10 @@ class WebSocketController extends BaseController ]; $params = json_encode($params); $this->client->send($params); - $message = $this->client->receive(); + $message = $this->client->receive(); //Log::write('WS获取朋友圈图片/视频链接成功,结果:' . json_encode($message, 256)); - //关闭WS链接 - $this->client->close(); + //关闭WS链接 + $this->client->close(); } catch (\Exception $e) { $msg = $e->getMessage(); } @@ -441,6 +445,7 @@ class WebSocketController extends BaseController if (empty($momentList) || !is_array($momentList)) { return false; } + try { foreach ($momentList as $moment) { @@ -448,8 +453,7 @@ class WebSocketController extends BaseController $momentEntity = $moment['momentEntity'] ?? []; // 检查朋友圈数据是否已存在 - $momentId = Db::table('s2_wechat_moments') - ->where('snsId', $moment['snsId']) + $momentId = WechatMoments::where('snsId', $moment['snsId']) ->where('wechatAccountId', $wechatAccountId) ->value('id'); @@ -469,7 +473,7 @@ class WebSocketController extends BaseController 'update_time' => time() ]; - if ($momentId) { + if (!empty($momentId)) { // 如果已存在,则更新数据 Db::table('s2_wechat_moments')->where('id', $momentId)->update($dataToSave); } else { @@ -478,9 +482,9 @@ class WebSocketController extends BaseController } // 如果不存在,则插入新数据 $dataToSave['wechatAccountId'] = $wechatAccountId; - $dataToSave['wechatFriendId'] = $wechatFriendId; + $dataToSave['wechatFriendId'] = $wechatFriendId ?? 0; $dataToSave['create_time'] = time(); - Db::table('s2_wechat_moments')->insert($dataToSave); + $res = WechatMoments::create($dataToSave); } } diff --git a/Server/application/api/controller/WebSocketControllerCopy.php b/Server/application/api/controller/WebSocketControllerCopy.php new file mode 100644 index 00000000..60bb2fbd --- /dev/null +++ b/Server/application/api/controller/WebSocketControllerCopy.php @@ -0,0 +1,557 @@ +400,'msg'=>'参数缺失']); + } + $params = [ + 'grant_type' => 'password', + 'username' => $userData['userName'], + 'password' => $userData['password'] + ]; + + // 调用登录接口获取token + // 设置请求头 + $headerData = ['client:kefu-client']; + $header = setHeader($headerData, '', 'plain'); + $result = requestCurl('https://kf.quwanzhi.com:9991/token', $params, 'POST',$header); + $result_array = handleApiResponse($result); + + if (isset($result_array['access_token']) && !empty($result_array['access_token'])) { + $authorization = $result_array['access_token']; + $this->authorized = $authorization; + $this->accountId = $userData['accountId']; + + } else { + return json_encode(['code'=>400,'msg'=>'获取系统授权信息失败']); + } + }else{ + $this->authorized = $this->request->header('authorization', ''); + $this->accountId = $this->request->param('accountId', ''); + } + + + if (empty($this->authorized) || empty($this->accountId)) { + $data['authorized'] = $this->authorized; + $data['accountId'] = $this->accountId; + return json_encode(['code'=>400,'msg'=>'缺失关键参数']); + } + + //证书 + $context = stream_context_create(); + stream_context_set_option($context, 'ssl', 'verify_peer', false); + stream_context_set_option($context, 'ssl', 'verify_peer_name', false); + //开启WS链接 + $result = [ + "accessToken" => $this->authorized, + "accountId" => $this->accountId, + "client" => "kefu-client", + "cmdType" => "CmdSignIn", + "seq" => 1, + ]; + + + $content = json_encode($result); + $this->client = new Client("wss://kf.quwanzhi.com:9993", + [ + 'filter' => ['text', 'binary', 'ping', 'pong', 'close','receive', 'send'], + 'context' => $context, + 'headers' => [ + 'Sec-WebSocket-Protocol' => 'soap', + 'origin' => 'localhost', + ], + 'timeout' => 86400, + ] + ); + $this->client->send($content); + } + + /************************************ + * 朋友圈相关功能 + ************************************/ + + /** + * 获取指定账号朋友圈信息 + * @param array $data 请求参数 + * @return \think\response\Json + */ + public function getMoments($data = []) + { + + $count = !empty($data['count']) ? $data['count'] : 10; + $wechatAccountId = !empty($data['wechatAccountId']) ? $data['wechatAccountId'] : ''; + $wechatFriendId = !empty($data['id']) ? $data['id'] : ''; + + //过滤消息 + if (empty($wechatAccountId)) { + return json_encode(['code'=>400,'msg'=>'指定账号不能为空']); + } + if (empty($wechatFriendId)) { + return json_encode(['code'=>400,'msg'=>'指定好友不能为空']); + } + $msg = '获取朋友圈信息成功'; + $message = []; + try { + $params = [ + "cmdType" => "CmdFetchMoment", + "count" => $count, + "createTimeSec" => time(), + "isTimeline" => false, + "prevSnsId" => 0, + "wechatAccountId" => $wechatAccountId, + "wechatFriendId" => $wechatFriendId, + "seq" => time(), + ]; + $params = json_encode($params); + //Log::write('WS获取朋友圈信息参数:' . json_encode($params, 256)); + $this->client->send($params); + $message = $this->client->receive(); + //Log::write('WS获取朋友圈信息成功,结果:' . $message); + $message = json_decode($message, 1); + + // 存储朋友圈数据到数据库 + if (isset($message['result']) && !empty($message['result'])) { + $this->saveMomentsToDatabase($message['result'], $wechatAccountId, $wechatFriendId); + } + + //关闭WS链接 + $this->client->close(); + } catch (\Exception $e) { + $msg = $e->getMessage(); + } + + return json_encode(['code'=>200,'msg'=>$msg,'data'=>$message]); + } + + /** + * 朋友圈点赞 + * @return \think\response\Json + */ + public function momentInteract() + { + if ($this->request->isPost()) { + $data = $this->request->param(); + + if (empty($data)) { + return json_encode(['code'=>400,'msg'=>'参数缺失']); + } + $dataArray = $data; + if (!is_array($dataArray)) { + return json_encode(['code'=>400,'msg'=>'数据格式错误']); + } + + //过滤消息 + if (empty($dataArray['snsId'])) { + return json_encode(['code'=>400,'msg'=>'snsId不能为空']); + } + if (empty($dataArray['wechatAccountId'])) { + return json_encode(['code'=>400,'msg'=>'微信id不能为空']); + } + + + $result = [ + "cmdType" => "CmdMomentInteract", + "momentInteractType" => 1, + "seq" => time(), + "snsId" => $dataArray['snsId'], + "wechatAccountId" => $dataArray['wechatAccountId'], + "wechatFriendId" => 0, + ]; + + $result = json_encode($result); + $this->client->send($result); + $message = $this->client->receive(); + $message = json_decode($message, 1); + //关闭WS链接 + $this->client->close(); + //Log::write('WS个人消息发送'); + return json_encode(['code'=>200,'msg'=>'点赞成功','data'=>$message]); + } else { + return json_encode(['code'=>400,'msg'=>'非法请求']); + } + } + + /** + * 朋友圈取消点赞 + * @return \think\response\Json + */ + public function momentCancelInteract() + { + if ($this->request->isPost()) { + $data = $this->request->param(); + + if (empty($data)) { + return json_encode(['code'=>400,'msg'=>'参数缺失']); + } + $dataArray = $data; + if (!is_array($dataArray)) { + return json_encode(['code'=>400,'msg'=>'数据格式错误']); + } + + //过滤消息 + if (empty($dataArray['snsId'])) { + return json_encode(['code'=>400,'msg'=>'snsId不能为空']); + } + if (empty($dataArray['wechatAccountId'])) { + return json_encode(['code'=>400,'msg'=>'微信id不能为空']); + } + + + $result = [ + "CommentId2" => '', + "CommentTime" => 0, + "cmdType" => "CmdMomentCancelInteract", + "optType" => 1, + "seq" => time(), + "snsId" => $dataArray['snsId'], + "wechatAccountId" => $dataArray['wechatAccountId'], + "wechatFriendId" => 0, + ]; + + $result = json_encode($result); + $this->client->send($result); + $message = $this->client->receive(); + $message = json_decode($message, 1); + //关闭WS链接 + $this->client->close(); + //Log::write('WS个人消息发送'); + return json_encode(['code'=>200,'msg'=>'取消点赞成功','data'=>$message]); + } else { + return json_encode(['code'=>400,'msg'=>'非法请求']); + } + } + + /** + * 获取指定账号朋友圈图片地址 + * @return \think\response\Json + */ + public function getMomentSourceRealUrl() + { + if ($this->request->isPost()) { + $data = $this->request->param(); + + if (empty($data)) { + return json_encode(['code'=>400,'msg'=>'参数缺失']); + } + $dataArray = $data; + if (!is_array($dataArray)) { + return json_encode(['code'=>400,'msg'=>'数据格式错误']); + } + //获取数据条数 +// $count = isset($dataArray['count']) ? $dataArray['count'] : 10; + //过滤消息 + if (empty($dataArray['wechatAccountId'])) { + return json_encode(['code'=>400,'msg'=>'指定账号不能为空']); + } + if (empty($dataArray['snsId'])) { + return json_encode(['code'=>400,'msg'=>'指定消息ID不能为空']); + } + if (empty($dataArray['snsUrls'])) { + return json_encode(['code'=>400,'msg'=>'资源信息不能为空']); + } + $msg = '获取朋友圈资源链接成功'; + $message = []; + try { + $params = [ + "cmdType" => $dataArray['type'], + "snsId" => $dataArray['snsId'], + "urls" => $dataArray['snsUrls'], + "wechatAccountId" => $dataArray['wechatAccountId'], + "seq" => time(), + ]; + $params = json_encode($params); + $this->client->send($params); + $message = $this->client->receive(); + //Log::write('WS获取朋友圈图片/视频链接成功,结果:' . json_encode($message, 256)); + //关闭WS链接 + $this->client->close(); + } catch (\Exception $e) { + $msg = $e->getMessage(); + } + + return json_encode(['code'=>200,'msg'=>$msg,'data'=>$message]); + } else { + return json_encode(['code'=>400,'msg'=>'非法请求']); + } + } + + /** + * 保存朋友圈数据到数据库 + * @param array $momentList 朋友圈数据列表 + * @param int $wechatAccountId 微信账号ID + * @param string $wechatFriendId 微信好友ID + * @return bool + */ + protected function saveMomentsToDatabase($momentList, $wechatAccountId, $wechatFriendId) + { + if (empty($momentList) || !is_array($momentList)) { + return false; + } + + try { + foreach ($momentList as $moment) { + // 提取momentEntity中的数据 + $momentEntity = $moment['momentEntity'] ?? []; + + // 检查朋友圈数据是否已存在 + $momentId = Db::table('s2_wechat_moments') + ->where('snsId', $moment['snsId']) + ->where('wechatAccountId', $wechatAccountId) + ->value('id'); + + $dataToSave = [ + 'commentList' => json_encode($moment['commentList'] ?? [], 256), + 'createTime' => $moment['createTime'] ?? 0, + 'likeList' => json_encode($moment['likeList'] ?? [], 256), + 'content' => $momentEntity['content'] ?? '', + 'lat' => $momentEntity['lat'] ?? 0, + 'lng' => $momentEntity['lng'] ?? 0, + 'location' => $momentEntity['location'] ?? '', + 'picSize' => $momentEntity['picSize'] ?? 0, + 'resUrls' => json_encode($momentEntity['resUrls'] ?? [], 256), + 'userName' => $momentEntity['userName'] ?? '', + 'snsId' => $moment['snsId'] ?? '', + 'type' => $moment['type'] ?? 0, + 'update_time' => time() + ]; + + if ($momentId) { + // 如果已存在,则更新数据 + Db::table('s2_wechat_moments')->where('id', $momentId)->update($dataToSave); + } else { + if(empty($wechatFriendId)){ + $wechatFriendId = WechatFriend::where('wechatAccountId', $wechatAccountId)->where('wechatId', $momentEntity['userName'])->value('id'); + } + // 如果不存在,则插入新数据 + $dataToSave['wechatAccountId'] = $wechatAccountId; + $dataToSave['wechatFriendId'] = $wechatFriendId; + $dataToSave['create_time'] = time(); + Db::table('s2_wechat_moments')->insert($dataToSave); + } + } + + //Log::write('朋友圈数据已存入数据库,共' . count($momentList) . '条'); + return true; + } catch (\Exception $e) { + //Log::write('保存朋友圈数据失败:' . $e->getMessage(), 'error'); + return false; + } + } + + /************************************ + * 消息发送相关功能 + ************************************/ + + /** + * 个人消息发送 + * @return \think\response\Json + */ + public function sendPersonal() + { + if ($this->request->isPost()) { + $data = $this->request->param(); + + if (empty($data)) { + return json_encode(['code'=>400,'msg'=>'参数缺失']); + } + $dataArray = $data; + if (!is_array($dataArray)) { + return json_encode(['code'=>400,'msg'=>'数据格式错误']); + } + + //过滤消息 + if (empty($dataArray['content'])) { + return json_encode(['code'=>400,'msg'=>'内容缺失']); + } + if (empty($dataArray['wechatAccountId'])) { + return json_encode(['code'=>400,'msg'=>'微信id不能为空']); + } + if (empty($dataArray['wechatFriendId'])) { + return json_encode(['code'=>400,'msg'=>'接收人不能为空']); + } + + if (empty($dataArray['msgType'])) { + return json_encode(['code'=>400,'msg'=>'类型缺失']); + } + + //消息拼接 msgType(1:文本 3:图片 43:视频 47:动图表情包 49:小程序) + $result = [ + "cmdType" => "CmdSendMessage", + "content" => $dataArray['content'], + "msgSubType" => 0, + "msgType" => $dataArray['msgType'], + "seq" => time(), + "wechatAccountId" => $dataArray['wechatAccountId'], + "wechatChatroomId" => 0, + "wechatFriendId" => $dataArray['wechatFriendId'], + ]; + + $result = json_encode($result); + $this->client->send($result); + $message = $this->client->receive(); + $message = json_decode($message, 1); + //关闭WS链接 + $this->client->close(); + //Log::write('WS个人消息发送'); + return json_encode(['code'=>200,'msg'=>'消息成功发送','data'=>$message]); + //return successJson($message, '消息成功发送'); + } else { + return json_encode(['code'=>400,'msg'=>'非法请求']); + //return errorJson('非法请求'); + } + } + + /** + * 发送群消息 + * @return \think\response\Json + */ + public function sendCommunity() + { + if ($this->request->isPost()) { + $data = $this->request->post(); + if (empty($data)) { + return json_encode(['code'=>400,'msg'=>'参数缺失']); + } + $dataArray = $data; + if (!is_array($dataArray)) { + return json_encode(['code'=>400,'msg'=>'数据格式错误']); + } + + //过滤消息 + if (empty($dataArray['content'])) { + return json_encode(['code'=>400,'msg'=>'内容缺失']); + } + if (empty($dataArray['wechatAccountId'])) { + return json_encode(['code'=>400,'msg'=>'微信id不能为空']); + } + + if (empty($dataArray['msgType'])) { + return json_encode(['code'=>400,'msg'=>'类型缺失']); + } + if (empty($dataArray['wechatChatroomId'])) { + return json_encode(['code'=>400,'msg'=>'群id不能为空']); + } + + $msg = '消息成功发送'; + $message = []; + try { + //消息拼接 msgType(1:文本 3:图片 43:视频 47:动图表情包 49:小程序) + $result = [ + "cmdType" => "CmdSendMessage", + "content" => htmlspecialchars_decode($dataArray['content']), + "msgSubType" => 0, + "msgType" => $dataArray['msgType'], + "seq" => time(), + "wechatAccountId" => $dataArray['wechatAccountId'], + "wechatChatroomId" => $dataArray['wechatChatroomId'], + "wechatFriendId" => 0, + ]; + + $result = json_encode($result); + $this->client->send($result); + $message = $this->client->receive(); + //关闭WS链接 + $this->client->close(); + //Log::write('WS群消息发送'); + //Log::write($message); + $message = json_decode($message, 1); + } catch (\Exception $e) { + $msg = $e->getMessage(); + } + return json_encode(['code'=>200,'msg'=>$msg,'data'=>$message]); + + } else { + return json_encode(['code'=>400,'msg'=>'非法请求']); + //return errorJson('非法请求'); + } + } + + /** + * 发送群消息(内部调用版) + * @param array $data 消息数据 + * @return \think\response\Json + */ + public function sendCommunitys($data = []) + { + if (empty($data)) { + return json_encode(['code'=>400,'msg'=>'参数缺失']); + } + $dataArray = $data; + if (!is_array($dataArray)) { + return json_encode(['code'=>400,'msg'=>'数据格式错误']); + } + + //过滤消息 + if (empty($dataArray['content'])) { + return json_encode(['code'=>400,'msg'=>'内容缺失']); + } + if (empty($dataArray['wechatAccountId'])) { + return json_encode(['code'=>400,'msg'=>'微信id不能为空']); + } + + if (empty($dataArray['msgType'])) { + return json_encode(['code'=>400,'msg'=>'类型缺失']); + } + if (empty($dataArray['wechatChatroomId'])) { + return json_encode(['code'=>400,'msg'=>'群id不能为空']); + } + + $msg = '消息成功发送'; + $message = []; + try { + //消息拼接 msgType(1:文本 3:图片 43:视频 47:动图表情包 49:小程序) + $result = [ + "cmdType" => "CmdSendMessage", + "content" => $dataArray['content'], + "msgSubType" => 0, + "msgType" => $dataArray['msgType'], + "seq" => time(), + "wechatAccountId" => $dataArray['wechatAccountId'], + "wechatChatroomId" => $dataArray['wechatChatroomId'], + "wechatFriendId" => 0, + ]; + + $result = json_encode($result); + $this->client->send($result); + $message = $this->client->receive(); + //关闭WS链接 + $this->client->close(); + //Log::write('WS群消息发送'); + //Log::write($message); + $message = json_decode($message, 1); + } catch (\Exception $e) { + $msg = $e->getMessage(); + } + + return json_encode(['code'=>200,'msg'=>$msg,'data'=>$message]); + } +} \ No newline at end of file diff --git a/Server/application/api/model/WechatMomentsModel.php b/Server/application/api/model/WechatMomentsModel.php new file mode 100644 index 00000000..ad050ad5 --- /dev/null +++ b/Server/application/api/model/WechatMomentsModel.php @@ -0,0 +1,11 @@ + 'app\command\AllotRuleListCommand', // 分配规则列表 √ 'allotrule:autocreate' => 'app\command\AutoCreateAllotRulesCommand', // 自动创建分配规则 √ 'content:collect' => 'app\command\ContentCollectCommand', // 内容采集任务 √ + 'moments:collect' => 'app\command\WechatMomentsCommand', // 朋友圈采集任务 ]; diff --git a/Server/application/command/WechatMomentsCommand.php b/Server/application/command/WechatMomentsCommand.php new file mode 100644 index 00000000..cfcbe88c --- /dev/null +++ b/Server/application/command/WechatMomentsCommand.php @@ -0,0 +1,100 @@ +setName('wechatMoments:list') + ->setDescription('获取朋友圈列表,并根据分页自动处理下一页') + ->addOption('jobId', null, Option::VALUE_OPTIONAL, '任务ID,用于区分不同实例', date('YmdHis') . rand(1000, 9999)); + } + + protected function execute(Input $input, Output $output) + { + $output->writeln('开始处理朋友圈列表任务...'); + + try { + // 获取任务ID + $jobId = $input->getOption('jobId'); + + $output->writeln('任务ID: ' . $jobId); + + // 检查队列是否已经在运行 + $queueLockKey = "queue_lock:{$this->queueName}"; + Cache::rm($queueLockKey); + if (Cache::get($queueLockKey)) { + $output->writeln("队列 {$this->queueName} 已经在运行中,跳过执行"); + Log::warning("队列 {$this->queueName} 已经在运行中,跳过执行"); + return false; + } + + // 设置队列运行锁,有效期1小时 + Cache::set($queueLockKey, $jobId, 3600); + $output->writeln("已设置队列运行锁,键名:{$queueLockKey},值:{$jobId},有效期:1小时"); + + // 为不同的任务ID使用不同的缓存键名 + $pageIndexCacheKey = "momentsPage:{$jobId}"; + $preMomentIdCacheKey = "preMomentId:{$jobId}"; + + // 从缓存获取初始页码和上次处理的朋友圈ID + $pageIndex = Cache::get($pageIndexCacheKey, 0); + $preMomentId = Cache::get($preMomentIdCacheKey, ''); + + $output->writeln("从缓存获取页码: {$pageIndex}, 上次处理的朋友圈ID: {$preMomentId}"); + $output->writeln("缓存键: {$pageIndexCacheKey}, {$preMomentIdCacheKey}"); + + $pageSize = 100; // 每页获取100条记录 + + // 将任务添加到队列 + $this->addToQueue($pageIndex, $pageSize, $preMomentId, $jobId, $pageIndexCacheKey, $preMomentIdCacheKey, $queueLockKey); + + $output->writeln('朋友圈列表任务已添加到队列'); + } catch (\Exception $e) { + Log::error('朋友圈列表任务添加失败:' . $e->getMessage()); + $output->writeln('朋友圈列表任务添加失败:' . $e->getMessage()); + return false; + } + + return true; + } + + /** + * 添加任务到队列 + * @param int $pageIndex 页码 + * @param int $pageSize 每页大小 + * @param string $preMomentId 上一个朋友圈ID + * @param string $jobId 任务ID + * @param string $pageIndexCacheKey 页码缓存键名 + * @param string $preMomentIdCacheKey 朋友圈ID缓存键名 + * @param string $queueLockKey 队列锁键名 + */ + public function addToQueue($pageIndex, $pageSize, $preMomentId = '', $jobId = '', $pageIndexCacheKey = '', $preMomentIdCacheKey = '', $queueLockKey = '') + { + $data = [ + 'pageIndex' => $pageIndex, + 'pageSize' => $pageSize, + 'preMomentId' => $preMomentId, + 'jobId' => $jobId, + 'pageIndexCacheKey' => $pageIndexCacheKey, + 'preMomentIdCacheKey' => $preMomentIdCacheKey, + 'queueLockKey' => $queueLockKey + ]; + + // 添加到队列,设置任务名为 wechat_moments + Queue::push(WechatMomentsJob::class, $data, $this->queueName); + } +} \ No newline at end of file diff --git a/Server/application/cunkebao/controller/ContentLibraryController.php b/Server/application/cunkebao/controller/ContentLibraryController.php index 2dcc291a..a76a6a67 100644 --- a/Server/application/cunkebao/controller/ContentLibraryController.php +++ b/Server/application/cunkebao/controller/ContentLibraryController.php @@ -114,7 +114,7 @@ class ContentLibraryController extends Controller $where[] = ['name', 'like', '%' . $keyword . '%']; } - // 添加名称模糊搜索 + // 添加名称模糊搜索 if (!empty($sourceType)) { $where[] = ['sourceType', '=', $sourceType]; } @@ -222,49 +222,49 @@ class ContentLibraryController extends Controller $library['keywordExclude'] = json_decode($library['keywordExclude'] ?: '[]', true); $library['groupMembers'] = json_decode($library['groupMembers'] ?: '[]', true); - // 将时间戳转换为日期格式(精确到日) - if (!empty($library['timeStart'])) { - $library['timeStart'] = date('Y-m-d', $library['timeStart']); - } - if (!empty($library['timeEnd'])) { - $library['timeEnd'] = date('Y-m-d', $library['timeEnd']); - } + // 将时间戳转换为日期格式(精确到日) + if (!empty($library['timeStart'])) { + $library['timeStart'] = date('Y-m-d', $library['timeStart']); + } + if (!empty($library['timeEnd'])) { + $library['timeEnd'] = date('Y-m-d', $library['timeEnd']); + } - // 获取好友详细信息 - if (!empty($library['sourceFriends'])) { - $friendIds = $library['sourceFriends']; - $friendsInfo = []; - - if (!empty($friendIds)) { - // 查询好友信息,使用wechat_friend表 - $friendsInfo = Db::name('wechat_friend')->alias('wf') - ->field('wf.id,wf.wechatId, wa.nickname, wa.avatar') - ->join('wechat_account wa', 'wf.wechatId = wa.wechatId') - ->whereIn('wf.id', $friendIds) + // 获取好友详细信息 + if (!empty($library['sourceFriends'])) { + $friendIds = $library['sourceFriends']; + $friendsInfo = []; + + if (!empty($friendIds)) { + // 查询好友信息,使用wechat_friend表 + $friendsInfo = Db::name('wechat_friend')->alias('wf') + ->field('wf.id,wf.wechatId, wa.nickname, wa.avatar') + ->join('wechat_account wa', 'wf.wechatId = wa.wechatId') + ->whereIn('wf.id', $friendIds) + ->select(); + } + + // 将好友信息添加到返回数据中 + $library['selectedFriends'] = $friendsInfo; + } + + // 获取群组详细信息 + if (!empty($library['sourceGroups'])) { + $groupIds = $library['sourceGroups']; + $groupsInfo = []; + + if (!empty($groupIds)) { + // 查询群组信息 + $groupsInfo = Db::name('wechat_group')->alias('g') + ->field('g.id, g.chatroomId, g.name, g.avatar, g.ownerWechatId,wa.nickname as ownerNickname,wa.avatar as ownerAvatar,wa.alias as ownerAlias') + ->join('wechat_account wa', 'g.ownerWechatId = wa.wechatId') + ->whereIn('g.id', $groupIds) ->select(); - } - - // 将好友信息添加到返回数据中 - $library['selectedFriends'] = $friendsInfo; - } - - // 获取群组详细信息 - if (!empty($library['sourceGroups'])) { - $groupIds = $library['sourceGroups']; - $groupsInfo = []; - - if (!empty($groupIds)) { - // 查询群组信息 - $groupsInfo = Db::name('wechat_group')->alias('g') - ->field('g.id, g.chatroomId, g.name, g.avatar, g.ownerWechatId,wa.nickname as ownerNickname,wa.avatar as ownerAvatar,wa.alias as ownerAlias') - ->join('wechat_account wa', 'g.ownerWechatId = wa.wechatId') - ->whereIn('g.id', $groupIds) - ->select(); - } - - // 将群组信息添加到返回数据中 - $library['selectedGroups'] = $groupsInfo; } + + // 将群组信息添加到返回数据中 + $library['selectedGroups'] = $groupsInfo; + } return json([ 'code' => 200, @@ -272,7 +272,7 @@ class ContentLibraryController extends Controller 'data' => $library ]); } - + /** * 更新内容库 * @return \think\response\Json @@ -375,7 +375,7 @@ class ContentLibraryController extends Controller /************************************ * 内容项目管理相关功能 ************************************/ - + /** * 添加内容项目 * @return \think\response\Json diff --git a/Server/application/job/WechatMomentsJob.php b/Server/application/job/WechatMomentsJob.php new file mode 100644 index 00000000..dd5bda2c --- /dev/null +++ b/Server/application/job/WechatMomentsJob.php @@ -0,0 +1,176 @@ +getAccounts(); + if (empty($accounts)) { + Log::info("没有需要采集的账号"); + Cache::rm($queueLockKey); + return; + } + foreach ($accounts as $account) { + try { + Log::info("开始采集账号 {$account['userName']} 的朋友圈"); + + // 初始化WebSocket连接 + $wsController = new WebSocketController([ + 'userName' => $account['userName'], + 'password' => $account['password'], + 'accountId' => $account['id'] + ]); + + + // 获取好友列表 + $friends = $this->getFriends($account['id'],$account['wechatAccountId']); + if (empty($friends)) { + Log::info("账号 {$account['userName']} 没有好友数据"); + continue; + } + + // 遍历好友采集朋友圈 + foreach ($friends as $friend) { + try { + $this->collectMoments($wsController, $account['wechatAccountId'], $friend['id']); + } catch (\Exception $e) { + Log::error("采集好友 {$friend['id']} 的朋友圈失败:" . $e->getMessage()); + continue; + } + } + + } catch (\Exception $e) { + Log::error("处理账号 {$account['wechatAccountId']} 失败:" . $e->getMessage()); + continue; + } + } + + // 任务完成,释放队列锁 + Cache::rm($queueLockKey); + Log::info("朋友圈采集任务完成"); + + } catch (\Exception $e) { + Log::error("朋友圈采集任务异常:" . $e->getMessage()); + Cache::rm($queueLockKey); + } + + $job->delete(); + } + + /** + * 获取需要采集的账号列表 + * @return array + */ + private function getAccounts() + { + $accounts = Db::table('s2_company_account') + ->alias('ca') + ->join(['s2_wechat_account' => 'wa'], 'ca.id = wa.deviceAccountId') + ->join(['s2_wechat_friend' => 'wf'], 'ca.id = wf.accountId') + ->where('ca.passwordLocal', '<>', '') + ->where(['ca.status' => 0,'wf.isDeleted' => 0,'wa.deviceAlive' => 1,'wa.wechatAlive' => 1]) + ->field([ + 'ca.id', + 'ca.userName', + 'ca.passwordLocal', + 'wf.wechatAccountId' + ]) + ->group('wf.wechatAccountId DESC') + ->order('ca.id DESC') + ->select(); + + foreach ($accounts as &$value) { + $value['password'] = localDecrypt($value['passwordLocal']); + unset($value['passwordLocal']); + } + unset($value); + + return $accounts; + + + } + + /** + * 获取账号的好友列表 + * @param int $accountId 账号ID + * @return array + */ + private function getFriends($accountId,$wechatAccountId) + { + return Db::table('s2_wechat_friend') + ->where('wechatAccountId', $wechatAccountId) + ->where('accountId', $accountId) + ->where('isDeleted', 0) + ->field(['id', 'wechatId','wechatAccountId','alias']) + ->order('id DESC') + ->select(); + } + + /** + * 采集指定好友的朋友圈 + * @param WebSocketController $wsController WebSocket控制器 + * @param int $accountId 账号ID + * @param string $friendId 好友ID + */ + private function collectMoments($wsController, $accountId, $friendId) + { + $prevSnsId = 0; + $currentPage = 1; + + do { + $data = [ + 'wechatAccountId' => $accountId, + 'wechatFriendId' => $friendId, + 'count' => $this->pageSize, + 'prevSnsId' => $prevSnsId + ]; + + $result = $wsController->getMoments($data); + $result = json_decode($result, true); + + if ($result['code'] != 200 || empty($result['data']['list'])) { + break; + } + + // 更新最后一条数据的snsId + $lastMoment = end($result['data']['list']); + if (isset($lastMoment['snsId'])) { + $prevSnsId = $lastMoment['snsId']; + } + + $currentPage++; + + // 如果已经达到最大页数,退出循环 + if ($currentPage > $this->maxPages) { + break; + } + + // 如果返回的数据少于请求的数量,说明没有更多数据了 + if (count($result['data']['list']) < $this->pageSize) { + break; + } + + } while (true); + + Log::info("完成采集好友 {$friendId} 的朋友圈,共 {$currentPage} 页"); + } +} \ No newline at end of file