From c7c499f0063b0962528e32c4b6a2281dcb912173 Mon Sep 17 00:00:00 2001 From: Ghost <106998207@qq.com> Date: Wed, 9 Apr 2025 09:11:20 +0800 Subject: [PATCH] =?UTF-8?q?coze=E4=BC=98=E5=8C=96=20+=20=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E5=A5=BD=E5=8F=8B=E5=BE=AE=E4=BF=A1=E7=BE=A4=E8=81=8A=E5=A4=A9?= =?UTF-8?q?=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/controller/AdminController.php | 169 ++++++ .../admin/controller/BaseController.php | 69 +++ .../application/admin/model/Administrator.php | 122 +++++ Server/application/api/config/route.php | 6 + .../api/controller/FriendTaskController.php | 27 +- .../api/controller/MessageController.php | 479 ++++++++++++++++++ .../api/model/WechatMessageModel.php | 11 + Server/application/command.php | 2 + .../command/MessageChatroomListCommand.php | 57 +++ .../command/MessageFriendsListCommand.php | 57 +++ Server/application/job/FriendTaskJob.php | 2 +- .../job/MessageChatroomListJob.php | 123 +++++ .../application/job/MessageFriendsListJob.php | 124 +++++ Server/application/store/config/route.php | 8 + .../store/controller/BaseController.php | 5 +- .../store/controller/StatisticsController.php | 392 ++++++++++++++ .../store/model/WechatFriendModel.php | 11 + .../store/model/WechatMessageModel.php | 11 + 18 files changed, 1663 insertions(+), 12 deletions(-) create mode 100644 Server/application/admin/controller/AdminController.php create mode 100644 Server/application/admin/controller/BaseController.php create mode 100644 Server/application/admin/model/Administrator.php create mode 100644 Server/application/api/controller/MessageController.php create mode 100644 Server/application/api/model/WechatMessageModel.php create mode 100644 Server/application/command/MessageChatroomListCommand.php create mode 100644 Server/application/command/MessageFriendsListCommand.php create mode 100644 Server/application/job/MessageChatroomListJob.php create mode 100644 Server/application/job/MessageFriendsListJob.php create mode 100644 Server/application/store/controller/StatisticsController.php create mode 100644 Server/application/store/model/WechatFriendModel.php create mode 100644 Server/application/store/model/WechatMessageModel.php diff --git a/Server/application/admin/controller/AdminController.php b/Server/application/admin/controller/AdminController.php new file mode 100644 index 000000000..652305beb --- /dev/null +++ b/Server/application/admin/controller/AdminController.php @@ -0,0 +1,169 @@ + 400, 'msg' => '账号和密码不能为空']); + } + + try { + // 查询管理员 + $admin = Administrator::where('account', $account)->find(); + + // 验证账号是否存在及密码是否正确 + if (empty($admin) || md5($password) != $admin['password']) { + return errorJson('账号或密码错误',400); + } + + // 验证账号状态 + if ($admin['status'] != 1) { + return errorJson('账号已被禁用',400); + } + + // 更新登录信息 + $admin->lastLoginIp = Request::ip(); + $admin->lastLoginTime = time(); + $admin->save(); + + // 构建用户数据 + $userData = [ + 'id' => $admin['id'], + 'account' => $admin['account'], + 'name' => $admin['name'], + 'type' => 'admin' // 标记用户类型为管理员 + ]; + + // 生成JWT令牌 + $token = JwtUtil::createToken($userData, self::TOKEN_EXPIRE); + $expireTime = time() + self::TOKEN_EXPIRE; + + // 缓存用户信息,方便后续验证 + Session::set('admin_auth', [ + 'id' => $admin['id'], + 'account' => $admin['account'], + 'name' => $admin['name'], + 'token' => $token + ]); + + // 返回登录成功数据 + return successJson([ + 'id' => $admin['id'], + 'account' => $admin['account'], + 'name' => $admin['name'], + 'token' => $token, + 'token_expired' => $expireTime, + 'lastLoginTime' => date('Y-m-d H:i:s', $admin['lastLoginTime']) + ]); + } catch (\Exception $e) { + return errorJson('登录失败:' . $e->getMessage(),500); + } + } + + /** + * 刷新令牌 + * @return \think\response\Json + */ + public function refreshToken() + { + // 获取Session中保存的管理员信息 + $adminAuth = Session::get('admin_auth'); + if (empty($adminAuth)) { + return errorJson('未登录或登录已过期',401); + } + + try { + // 查询管理员信息 + $admin = Administrator::where('id', $adminAuth['id'])->find(); + if (empty($admin)) { + Session::delete('admin_auth'); + return errorJson('管理员不存在',401); + } + + // 构建用户数据 + $userData = [ + 'id' => $admin['id'], + 'account' => $admin['account'], + 'name' => $admin['name'], + 'type' => 'admin' // 标记用户类型为管理员 + ]; + + // 生成新令牌 + $token = JwtUtil::createToken($userData, self::TOKEN_EXPIRE); + $expireTime = time() + self::TOKEN_EXPIRE; + + // 更新Session中的令牌 + $adminAuth['token'] = $token; + + return successJson([ + 'token' => $token, + 'token_expired' => $expireTime + ]); + } catch (\Exception $e) { + return errorJson('刷新令牌失败:' . $e->getMessage(),500); + } + } + + /** + * 退出登录 + * @return \think\response\Json + */ + public function logout() + { + Session::delete('admin_auth'); + return successJson('退出成功'); + } + + /** + * 获取当前登录管理员信息 + * @return \think\response\Json + */ + public function getInfo() + { + // 获取Session中保存的管理员信息 + $adminAuth = Session::get('admin_auth'); + if (empty($adminAuth)) { + return errorJson('未登录或登录已过期',401); + } + + // 查询管理员信息 + $admin = Administrator::where('id', $adminAuth['id'])->find(); + if (empty($admin)) { + Session::delete('admin_auth'); + return errorJson('管理员不存在',401); + } + + return successJson([ + 'id' => $admin['id'], + 'account' => $admin['account'], + 'name' => $admin['name'], + 'lastLoginTime' => date('Y-m-d H:i:s', $admin['lastLoginTime']), + 'lastLoginIp' => $admin['lastLoginIp'] + ]); + } +} \ No newline at end of file diff --git a/Server/application/admin/controller/BaseController.php b/Server/application/admin/controller/BaseController.php new file mode 100644 index 000000000..2900fd152 --- /dev/null +++ b/Server/application/admin/controller/BaseController.php @@ -0,0 +1,69 @@ +action(); + + // 验证登录 + if (!in_array($action, $noNeedLogin)) { + $this->checkLogin(); + } + } + + /** + * 验证登录 + */ + protected function checkLogin() + { + // 获取请求头中的Authorization + $token = Request::header('Authorization', ''); + if (empty($token)) { + // 尝试从请求参数中获取token + $token = Request::param('token', ''); + } + + if (empty($token)) { + $this->error('未登录或登录已过期', null, ['code' => 401]); + } + + try { + // 验证JWT令牌 + $userInfo = JwtUtil::verifyToken($token); + + // 验证用户类型 + if (empty($userInfo) || $userInfo['type'] !== 'admin') { + $this->error('无效的登录凭证', null, ['code' => 401]); + } + + $this->adminInfo = $userInfo; + } catch (\Exception $e) { + $this->error('登录已过期,请重新登录', null, ['code' => 401]); + } + } + + +} \ No newline at end of file diff --git a/Server/application/admin/model/Administrator.php b/Server/application/admin/model/Administrator.php new file mode 100644 index 000000000..23f728622 --- /dev/null +++ b/Server/application/admin/model/Administrator.php @@ -0,0 +1,122 @@ +count(); + $list = self::where($where) + ->page($page, $limit) + ->order('id', 'desc') + ->select(); + + $data = []; + foreach ($list as $item) { + $data[] = [ + 'id' => $item['id'], + 'name' => $item['name'], + 'account' => $item['account'], + 'status' => $item['status'], + 'lastLoginTime' => $item['lastLoginTime'] ? date('Y-m-d H:i:s', $item['lastLoginTime']) : '', + 'lastLoginIp' => $item['lastLoginIp'], + 'createTime' => date('Y-m-d H:i:s', $item['createTime']), + 'updateTime' => date('Y-m-d H:i:s', $item['updateTime']) + ]; + } + + return [ + 'count' => $count, + 'list' => $data + ]; + } + + /** + * 创建管理员 + * @param array $data 管理员数据 + * @return array + */ + public static function createAdmin($data) + { + // 检查账号是否已存在 + $exists = self::where('account', $data['account'])->find(); + if ($exists) { + return ['code' => 400, 'msg' => '账号已存在']; + } + + // 创建管理员 + $admin = new self; + $admin->name = $data['name']; + $admin->account = $data['account']; + $admin->password = md5($data['password']); + $admin->status = isset($data['status']) ? $data['status'] : 1; + $admin->save(); + + return ['code' => 200, 'msg' => '创建成功', 'data' => $admin]; + } + + /** + * 修改管理员信息 + * @param int $id 管理员ID + * @param array $data 管理员数据 + * @return array + */ + public static function updateAdmin($id, $data) + { + // 查询管理员 + $admin = self::where('id', $id)->find(); + if (!$admin) { + return ['code' => 400, 'msg' => '管理员不存在']; + } + + // 如果修改账号,检查账号是否已存在 + if (isset($data['account']) && $data['account'] != $admin['account']) { + $exists = self::where('account', $data['account'])->find(); + if ($exists) { + return ['code' => 400, 'msg' => '账号已存在']; + } + $admin->account = $data['account']; + } + + // 修改信息 + if (isset($data['name'])) { + $admin->name = $data['name']; + } + + if (isset($data['password']) && !empty($data['password'])) { + $admin->password = md5($data['password']); + } + + if (isset($data['status'])) { + $admin->status = $data['status']; + } + + $admin->save(); + + return ['code' => 200, 'msg' => '修改成功']; + } +} \ No newline at end of file diff --git a/Server/application/api/config/route.php b/Server/application/api/config/route.php index 75855dcf3..c2e7ca77b 100755 --- a/Server/application/api/config/route.php +++ b/Server/application/api/config/route.php @@ -73,5 +73,11 @@ Route::group('v1', function () { Route::group('friend', function () { Route::get('list', 'app\\api\\controller\\WechatFriendController@getList'); // 获取微信好友列表数据 √ }); + + // Message控制器路由 + Route::group('message', function () { + Route::get('getFriendsList', 'app\\api\\controller\\MessageController@getFriendsList'); // 获取微信好友列表 √ + Route::get('getChatroomList', 'app\\api\\controller\\MessageController@getChatroomList'); // 同步群聊消息 √ + }); }); }); \ No newline at end of file diff --git a/Server/application/api/controller/FriendTaskController.php b/Server/application/api/controller/FriendTaskController.php index 5c4200567..c9fbdbf54 100755 --- a/Server/application/api/controller/FriendTaskController.php +++ b/Server/application/api/controller/FriendTaskController.php @@ -11,12 +11,16 @@ class FriendTaskController extends BaseController * 获取添加好友记录列表 * @return \think\response\Json */ - public function getlist() + public function getlist($pageIndex,$pageSize,$authorization,$isJob = false) { // 获取授权token - $authorization = trim($this->request->header('authorization', '')); + $authorization = !empty($authorization) ? $authorization : trim($this->request->header('authorization', '')); if (empty($authorization)) { - return errorJson('缺少授权信息'); + if($isJob){ + return json_encode(['code'=>500,'msg'=>'缺少授权信息']); + }else{ + return errorJson('缺少授权信息'); + } } try { @@ -24,8 +28,8 @@ class FriendTaskController extends BaseController $params = [ 'keyword' => $this->request->param('keyword', ''), 'status' => $this->request->param('status', ''), - 'pageIndex' => $this->request->param('pageIndex', 0), - 'pageSize' => $this->request->param('pageSize', 20) + 'pageIndex' => !empty($pageIndex) ? $pageIndex : $this->request->param('pageIndex', 0), + 'pageSize' => !empty($pageSize) ? $pageSize : $this->request->param('pageSize', 20), ]; // 设置请求头 @@ -43,10 +47,17 @@ class FriendTaskController extends BaseController $this->saveFriendTask($item); } } - - return successJson($response); + if($isJob){ + return json_encode(['code'=>200,'msg'=>'获取添加好友记录列表成功','data'=>$response]); + }else{ + return successJson($response); + } } catch (\Exception $e) { - return errorJson('获取添加好友记录列表失败:' . $e->getMessage()); + if($isJob){ + return json_encode(['code'=>500,'msg'=>'获取添加好友记录列表失败:' . $e->getMessage()]); + }else{ + return errorJson('获取添加好友记录列表失败:' . $e->getMessage()); + } } } diff --git a/Server/application/api/controller/MessageController.php b/Server/application/api/controller/MessageController.php new file mode 100644 index 000000000..b76e05f7b --- /dev/null +++ b/Server/application/api/controller/MessageController.php @@ -0,0 +1,479 @@ +request->header('authorization', '')); + if (empty($authorization)) { + if($isJob){ + return json_encode(['code'=>500,'msg'=>'缺少授权信息']); + }else{ + return errorJson('缺少授权信息'); + } + } + + $fromTime = $this->request->param('fromTime', date('Y-m-d 00:00:00', strtotime('-1 days'))); + $toTime = $this->request->param('toTime', date('Y-m-d 00:00:00')); + + try { + // 构建请求参数 + $params = [ + 'chatroomKeyword' => $this->request->param('chatroomKeyword', ''), + 'friendKeyword' => $this->request->param('friendKeyword', ''), + 'friendPhoneKeyword' => $this->request->param('friendPhoneKeyword', ''), + 'friendPinYinKeyword' => $this->request->param('friendPinYinKeyword', ''), + 'friendRegionKeyword' => $this->request->param('friendRegionKeyword', ''), + 'friendRemarkKeyword' => $this->request->param('friendRemarkKeyword', ''), + 'groupId' => $this->request->param('groupId', null), + 'kefuId' => $this->request->param('kefuId', null), + 'labels' => $this->request->param('labels', []), + 'msgFrom' => $fromTime, + 'msgKeyword' => $this->request->param('msgKeyword', ''), + 'msgTo' => $toTime, + 'msgType' => $this->request->param('msgType', ''), + 'pageIndex' => !empty($pageIndex) ? $pageIndex : input('pageIndex', 0), + 'pageSize' => !empty($pageSize) ? $pageSize : input('pageSize', 20), + 'reverse' => $this->request->param('reverse', false), + 'type' => $this->request->param('type', 'friend'), + 'wechatAccountIds' => $this->request->param('wechatAccountIds', []) + ]; + + + // 设置请求头 + $headerData = ['client:system']; + $header = setHeader($headerData, $authorization, 'json'); + + // 发送请求获取好友列表 + $result = requestCurl($this->baseUrl . 'api/WechatFriend/listWechatFriendForMsgPagination', $params, 'POST', $header, 'json'); + $response = handleApiResponse($result); + + // 获取同步消息标志 + $syncMessages = $this->request->param('syncMessages', true); + + // 如果需要同步消息,则获取每个好友的消息 + if ($syncMessages && !empty($response['results'])) { + $from = strtotime($fromTime) * 1000; + $to = strtotime($toTime) * 1000; + + + foreach ($response['results'] as &$friend) { + // 构建获取消息的参数 + $messageParams = [ + 'keyword' => '', + 'msgType' => '', + 'accountId' => '', + 'count' => 100, + 'messageId' => '', + 'olderData' => true, + 'wechatAccountId' => $friend['wechatAccountId'], + 'wechatFriendId' => $friend['wechatFriendId'], + 'from' => $from, + 'to' => $to, + 'searchFrom' => 'admin' + ]; + + // 调用获取消息的接口 + $messageResult = requestCurl($this->baseUrl . 'api/FriendMessage/searchMessage', $messageParams, 'GET', $header, 'json'); + $messageResponse = handleApiResponse($messageResult); + + // 保存消息到数据库 + if (!empty($messageResponse)) { + foreach ($messageResponse as $item) { + $this->saveMessage($item); + } + } + + // 将消息列表添加到好友数据中 + $friend['messages'] = $messageResponse ?? []; + } + unset($friend); + } + if($isJob){ + return json_encode(['code'=>200,'msg'=>'获取好友列表成功','data'=>$response]); + }else{ + return successJson($response); + } + } catch (\Exception $e) { + if($isJob){ + return json_encode(['code'=>500,'msg'=>'获取好友列表失败:' . $e->getMessage()]); + }else{ + return errorJson('获取好友列表失败:' . $e->getMessage()); + } + } + } + + + + + /** + * 保存消息记录到数据库 + * @param array $item 消息记录数据 + */ + private function saveMessage($item) + { + // 检查消息是否已存在 + $exists = WechatMessageModel::where('id', $item['id']) ->find(); + + // 如果消息已存在,直接返回 + if ($exists) { + return; + } + + // 将毫秒时间戳转换为秒级时间戳 + $createTime = isset($item['createTime']) ? strtotime($item['createTime']) : null; + $deleteTime = !empty($item['isDeleted']) ? strtotime($item['deleteTime']) : null; + $wechatTime = isset($item['wechatTime']) ? floor($item['wechatTime'] / 1000) : null; + + $data = [ + 'id' => $item['id'], + 'type' => 1, + 'accountId' => $item['accountId'], + 'content' => $item['content'], + 'createTime' => $createTime, + 'deleteTime' => $deleteTime, + 'isDeleted' => $item['isDeleted'] ?? false, + 'isSend' => $item['isSend'] ?? true, + 'msgId' => $item['msgId'], + 'msgSubType' => $item['msgSubType'] ?? 0, + 'msgSvrId' => $item['msgSvrId'] ?? '', + 'msgType' => $item['msgType'], + 'origin' => $item['origin'] ?? 0, + 'recallId' => $item['recallId'] ?? false, + 'sendStatus' => $item['sendStatus'] ?? 0, + 'synergyAccountId' => $item['synergyAccountId'] ?? 0, + 'tenantId' => $item['tenantId'], + 'wechatAccountId' => $item['wechatAccountId'], + 'wechatFriendId' => $item['wechatFriendId'], + 'wechatTime' => $wechatTime + ]; + + // 创建新记录 + WechatMessageModel::create($data); + } + + /** + * 获取微信群聊列表 + * @return \think\response\Json + */ + public function getChatroomList($pageIndex = '',$pageSize = '',$authorization = '',$isJob = false) + { + // 获取授权token + $authorization = !empty($authorization) ? $authorization : trim($this->request->header('authorization', '')); + if (empty($authorization)) { + if($isJob){ + return json_encode(['code'=>500,'msg'=>'缺少授权信息']); + }else{ + return errorJson('缺少授权信息'); + } + } + + $fromTime = $this->request->param('fromTime', date('Y-m-d 00:00:00', strtotime('-1 days'))); + $toTime = $this->request->param('toTime', date('Y-m-d 00:00:00')); + + try { + // 构建请求参数 + $params = [ + 'chatroomKeyword' => $this->request->param('chatroomKeyword', ''), + 'friendKeyword' => $this->request->param('friendKeyword', ''), + 'friendInKeyword' => $this->request->param('friendInKeyword', ''), + 'friendInTimeKeyword' => $this->request->param('friendInTimeKeyword', ''), + 'friendOutKeyword' => $this->request->param('friendOutKeyword', ''), + 'friendRemarkKeyword' => $this->request->param('friendRemarkKeyword', ''), + 'groupId' => $this->request->param('groupId', null), + 'kefuId' => $this->request->param('kefuId', null), + 'labels' => $this->request->param('labels', []), + 'msgFrom' => $fromTime, + 'msgKeyword' => $this->request->param('msgKeyword', ''), + 'msgTo' => $toTime, + 'msgType' => $this->request->param('msgType', ''), + 'pageIndex' => $this->request->param('pageIndex', 0), + 'pageSize' => $this->request->param('pageSize', 100), + 'reverse' => $this->request->param('reverse', false), + 'type' => $this->request->param('type', 'chatroom'), + 'wechatAccountIds' => $this->request->param('wechatAccountIds', []) + ]; + + // 设置请求头 + $headerData = ['client:system']; + $header = setHeader($headerData, $authorization, 'json'); + + // 发送请求获取群聊列表 + $result = requestCurl($this->baseUrl . 'api/WechatChatroom/listWechatChatroomForMsgPagination', $params, 'POST', $header, 'json'); + $response = handleApiResponse($result); + + // 获取同步消息标志 + $syncMessages = $this->request->param('syncMessages', true); + + // 如果需要同步消息,则获取每个群的消息 + if ($syncMessages && !empty($response)) { + $from = strtotime($fromTime) * 1000; + $to = strtotime($toTime) * 1000; + foreach ($response['results'] as &$chatroom) { + + // 构建获取消息的参数 + $messageParams = [ + 'keyword' => '', + 'msgType' =>'', + 'accountId' => '', + 'count' => 100, + 'messageId' => '', + 'olderData' => true, + 'wechatId' => '', + 'wechatAccountId' => $chatroom['wechatAccountId'], + 'wechatChatroomId' => $chatroom['wechatChatroomId'], + 'from' => $from, + 'to' => $to, + 'searchFrom' => 'admin' + ]; + + // 调用获取消息的接口 + $messageResult = requestCurl($this->baseUrl . 'api/ChatroomMessage/searchMessage', $messageParams, 'GET', $header, 'json'); + $messageResponse = handleApiResponse($messageResult); + + // 保存消息到数据库 + if (!empty($messageResponse)) { + foreach ($messageResponse as $item) { + $this->saveChatroomMessage($item); + } + } + + // 将消息列表添加到群聊数据中 + $chatroom['messages'] = $messageResponse ?? []; + } + unset($chatroom); + } + if($isJob){ + return json_encode(['code'=>200,'msg'=>'获取群聊列表成功','data'=>$response]); + }else{ + return successJson($response); + } + } catch (\Exception $e) { + if($isJob){ + return json_encode(['code'=>500,'msg'=>'获取群聊列表失败:' . $e->getMessage()]); + }else{ + return errorJson('获取群聊列表失败:' . $e->getMessage()); + } + } + } + + + + + /** + * 保存群聊消息记录到数据库 + * @param array $item 消息记录数据 + */ + private function saveChatroomMessage($item) + { + + + // 检查消息是否已存在 + $exists = WechatMessageModel::where('id', $item['id']) ->find(); + + // 如果消息已存在,直接返回 + if ($exists) { + return; + } + + // 处理发送者信息 + $sender = $item['sender'] ?? []; + + // 处理消息内容,提取真正的消息内容 + $originalContent = $item['content'] ?? ''; + $processedContent = $this->processMessageContent($originalContent); + + // 将毫秒时间戳转换为秒级时间戳 + $createTime = isset($item['createTime']) ? strtotime($item['createTime']) : null; + $deleteTime = !empty($item['isDeleted']) ? strtotime($item['deleteTime']) : null; + $wechatTime = isset($item['wechatTime']) ? floor($item['wechatTime'] / 1000) : null; + + $data = [ + 'id' => $item['id'], + 'type' => 2, + 'wechatChatroomId' => $item['wechatChatroomId'], + // sender信息,添加sender前缀 + 'senderNickname' => $sender['nickname'] ?? '', + 'senderWechatId' => $sender['wechatId'] ?? '', + 'senderIsAdmin' => $sender['isAdmin'] ?? false, + 'senderIsDeleted' => $sender['isDeleted'] ?? false, + 'senderChatroomNickname' => $sender['chatroomNickname'] ?? '', + 'senderWechatAccountId' => $sender['wechatAccountId'] ?? '', + // 其他字段 + 'wechatAccountId' => $item['wechatAccountId'], + 'tenantId' => $item['tenantId'], + 'accountId' => $item['accountId'], + 'synergyAccountId' => $item['synergyAccountId'] ?? 0, + 'content' => $processedContent, // 使用处理后的内容 + 'originalContent' => $originalContent, // 保存原始内容 + 'msgType' => $item['msgType'], + 'msgSubType' => $item['msgSubType'] ?? 0, + 'msgSvrId' => $item['msgSvrId'] ?? '', + 'isSend' => $item['isSend'] ?? true, + 'createTime' => $createTime, + 'isDeleted' => $item['isDeleted'] ?? false, + 'deleteTime' => $deleteTime, + 'sendStatus' => $item['sendStatus'] ?? 0, + 'wechatTime' => $wechatTime, + 'origin' => $item['origin'] ?? 0, + 'msgId' => $item['msgId'], + 'recallId' => $item['recallId'] ?? false + ]; + + // 创建新记录 + WechatMessageModel::create($data); + } + + /** + * 处理消息内容,提取真正的消息内容 + * @param string $content 原始内容 + * @return string 处理后的内容 + */ + private function processMessageContent($content) + { + if (empty($content)) { + return ''; + } + + // 处理普通消息格式:wxid_vr2qafb1vg0d22:\n安德玛儿童 + if (preg_match('/^[^:]+:\n(.+)$/s', $content, $matches)) { + return trim($matches[1]); + } + + // 如果没有匹配到格式,则返回原始内容 + return $content; + } + + + /** + * 用户聊天记录 + * @return \think\response\Json + */ + public function getMessageList() + { + // 获取授权token + $authorization = trim($this->request->header('authorization', '')); + if (empty($authorization)) { + return errorJson('缺少授权信息'); + } + + try { + // 构建请求参数 + $params = [ + 'keyword' => $this->request->param('keyword', ''), + 'msgType' => $this->request->param('msgType', ''), + 'accountId' => $this->request->param('accountId', ''), + 'count' => $this->request->param('count', 100), + 'messageId' => $this->request->param('messageId', ''), + 'olderData' => $this->request->param('olderData', true), + 'wechatAccountId' => $this->request->param('wechatAccountId', ''), + 'wechatFriendId' => $this->request->param('wechatFriendId', ''), + 'from' => $this->request->param('from', ''), + 'to' => $this->request->param('to', ''), + 'searchFrom' => $this->request->param('searchFrom', 'admin') + ]; + + // 参数验证 + if (empty($params['wechatAccountId'])) { + return errorJson('微信账号ID不能为空'); + } + if (empty($params['wechatFriendId'])) { + return errorJson('好友ID不能为空'); + } + + // 设置请求头 + $headerData = ['client:system']; + $header = setHeader($headerData, $authorization, 'json'); + + // 发送请求获取聊天记录 + $result = requestCurl($this->baseUrl . 'api/FriendMessage/searchMessage', $params, 'GET', $header, 'json'); + $response = handleApiResponse($result); + + // 保存数据到数据库 + if (!empty($response)) { + foreach ($response as $item) { + $this->saveMessage($item); + } + } + + return successJson($response); + } catch (\Exception $e) { + return errorJson('获取聊天记录失败:' . $e->getMessage()); + } + } + + + + /** + * 获取群聊消息列表 + * @return \think\response\Json + */ + public function getChatroomMessages() + { + // 获取授权token + $authorization = trim($this->request->header('authorization', '')); + if (empty($authorization)) { + return errorJson('缺少授权信息'); + } + + try { + // 构建请求参数 + $params = [ + 'keyword' => $this->request->param('keyword', ''), + 'msgType' => $this->request->param('msgType', ''), + 'accountId' => $this->request->param('accountId', ''), + 'count' => $this->request->param('count', 100), + 'messageId' => $this->request->param('messageId', ''), + 'olderData' => $this->request->param('olderData', true), + 'wechatId' => $this->request->param('wechatId', ''), + 'wechatAccountId' => $this->request->param('wechatAccountId', ''), + 'wechatChatroomId' => $this->request->param('wechatChatroomId', ''), + 'from' => $this->request->param('from', strtotime(date('Y-m-d 00:00:00', strtotime('-1 days')))), + 'to' => $this->request->param('to', strtotime(date('Y-m-d 00:00:00'))), + 'searchFrom' => $this->request->param('searchFrom', 'admin') + ]; + + // 参数验证 + if (empty($params['wechatAccountId'])) { + return errorJson('微信账号ID不能为空'); + } + if (empty($params['wechatChatroomId'])) { + return errorJson('群聊ID不能为空'); + } + + // 设置请求头 + $headerData = ['client:system']; + $header = setHeader($headerData, $authorization, 'json'); + + // 发送请求获取群聊消息 + $result = requestCurl($this->baseUrl . 'api/ChatroomMessage/searchMessage', $params, 'GET', $header, 'json'); + $response = handleApiResponse($result); + + // 保存数据到数据库 + if (!empty($response)) { + foreach ($response as $item) { + $res = $this->saveChatroomMessage($item); + if(!$res){ + return errorJson('保存群聊消息失败'); + } + } + } + + return successJson($response); + } catch (\Exception $e) { + return errorJson('获取群聊消息失败:' . $e->getMessage()); + } + } + +} \ No newline at end of file diff --git a/Server/application/api/model/WechatMessageModel.php b/Server/application/api/model/WechatMessageModel.php new file mode 100644 index 000000000..ad01b2c63 --- /dev/null +++ b/Server/application/api/model/WechatMessageModel.php @@ -0,0 +1,11 @@ + 'app\command\FriendTaskCommand', // 添加好友任务列表 'wechatList:list' => 'app\command\WechatListCommand', // 微信客服列表 'account:list' => 'app\command\AccountListCommand', // 公司账号列表 + 'message:friendsList' => 'app\command\MessageFriendsListCommand', // 微信好友列表 + 'message:chatroomList' => 'app\command\MessageChatroomListCommand', // 微信群聊列表 ]; diff --git a/Server/application/command/MessageChatroomListCommand.php b/Server/application/command/MessageChatroomListCommand.php new file mode 100644 index 000000000..7ee0cf43a --- /dev/null +++ b/Server/application/command/MessageChatroomListCommand.php @@ -0,0 +1,57 @@ +setName('message:chatroomList') + ->setDescription('获取微信群聊消息列表,并根据分页自动处理下一页'); + } + + protected function execute(Input $input, Output $output) + { + $output->writeln('开始处理微信群聊消息列表...'); + + try { + // 初始页码 + $pageIndex = 0; + $pageSize = 100; // 每页获取100条记录 + + // 将第一页任务添加到队列 + $this->addToQueue($pageIndex, $pageSize); + + $output->writeln('微信群聊消息列表任务已添加到队列'); + } catch (\Exception $e) { + Log::error('微信群聊消息列表任务添加失败:' . $e->getMessage()); + $output->writeln('微信群聊消息列表任务添加失败:' . $e->getMessage()); + return false; + } + + return true; + } + + /** + * 添加任务到队列 + * @param int $pageIndex 页码 + * @param int $pageSize 每页大小 + */ + protected function addToQueue($pageIndex, $pageSize) + { + $data = [ + 'pageIndex' => $pageIndex, + 'pageSize' => $pageSize + ]; + + // 添加到队列,设置任务名为 friend_task + Queue::push(MessageChatroomListJob::class, $data, 'message_chatroom_list'); + } +} \ No newline at end of file diff --git a/Server/application/command/MessageFriendsListCommand.php b/Server/application/command/MessageFriendsListCommand.php new file mode 100644 index 000000000..e7df57b5b --- /dev/null +++ b/Server/application/command/MessageFriendsListCommand.php @@ -0,0 +1,57 @@ +setName('message:friendsList') + ->setDescription('获取好友消息列表,并根据分页自动处理下一页'); + } + + protected function execute(Input $input, Output $output) + { + $output->writeln('开始处理好友消息列表...'); + + try { + // 初始页码 + $pageIndex = 0; + $pageSize = 100; // 每页获取100条记录 + + // 将第一页任务添加到队列 + $this->addToQueue($pageIndex, $pageSize); + + $output->writeln('好友消息列表任务已添加到队列'); + } catch (\Exception $e) { + Log::error('好友消息列表任务添加失败:' . $e->getMessage()); + $output->writeln('好友消息列表任务添加失败:' . $e->getMessage()); + return false; + } + + return true; + } + + /** + * 添加任务到队列 + * @param int $pageIndex 页码 + * @param int $pageSize 每页大小 + */ + protected function addToQueue($pageIndex, $pageSize) + { + $data = [ + 'pageIndex' => $pageIndex, + 'pageSize' => $pageSize + ]; + + // 添加到队列,设置任务名为 friend_task + Queue::push(MessageFriendsListJob::class, $data, 'message_friends_list'); + } +} \ No newline at end of file diff --git a/Server/application/job/FriendTaskJob.php b/Server/application/job/FriendTaskJob.php index f1f43b1aa..6ad03f407 100755 --- a/Server/application/job/FriendTaskJob.php +++ b/Server/application/job/FriendTaskJob.php @@ -81,7 +81,7 @@ class FriendTaskJob } // 调用添加好友任务获取方法 - $result = $friendTaskController->getlist($pageIndex,$pageSize,$authorization); + $result = $friendTaskController->getlist($pageIndex,$pageSize,$authorization,true); $response = json_decode($result,true); diff --git a/Server/application/job/MessageChatroomListJob.php b/Server/application/job/MessageChatroomListJob.php new file mode 100644 index 000000000..6e6c4c1ab --- /dev/null +++ b/Server/application/job/MessageChatroomListJob.php @@ -0,0 +1,123 @@ +processMessageChatroomList($data, $job->attempts())) { + $job->delete(); + Log::info('微信群聊消息列表任务执行成功,页码:' . $data['pageIndex']); + } else { + if ($job->attempts() > 3) { + // 超过重试次数,删除任务 + Log::error('微信群聊消息列表任务执行失败,已超过重试次数,页码:' . $data['pageIndex']); + $job->delete(); + } else { + // 任务失败,重新放回队列 + Log::warning('微信群聊消息列表任务执行失败,重试次数:' . $job->attempts() . ',页码:' . $data['pageIndex']); + $job->release(Config::get('queue.failed_delay', 10)); + } + } + } catch (\Exception $e) { + // 出现异常,记录日志 + Log::error('微信群聊消息列表任务异常:' . $e->getMessage()); + if ($job->attempts() > 3) { + $job->delete(); + } else { + $job->release(Config::get('queue.failed_delay', 10)); + } + } + } + + /** + * 处理微信群聊消息列表获取 + * @param array $data 任务数据 + * @param int $attempts 重试次数 + * @return bool + */ + protected function processMessageChatroomList($data, $attempts) + { + // 获取参数 + $pageIndex = isset($data['pageIndex']) ? $data['pageIndex'] : 0; + $pageSize = isset($data['pageSize']) ? $data['pageSize'] : 100; + + Log::info('开始获取微信群聊消息列表,页码:' . $pageIndex . ',页大小:' . $pageSize); + + // 实例化控制器 + $messageController = new MessageController(); + + // 构建请求参数 + $params = [ + 'pageIndex' => $pageIndex, + 'pageSize' => $pageSize + ]; + + // 设置请求信息 + $request = request(); + $request->withGet($params); + + // 获取系统授权信息 + $authorization = AuthService::getSystemAuthorization(); + if (empty($authorization)) { + Log::error('获取系统授权信息失败'); + return false; + } + + // 调用添加好友任务获取方法 + $result = $messageController->getChatroomList($pageIndex,$pageSize,$authorization,true); + $response = json_decode($result,true); + + + // 判断是否成功 + if ($response['code'] == 200) { + $data = $response['data']; + + // 判断是否有下一页 + if (!empty($data) && count($data['results']) > 0) { + // 有下一页,将下一页任务添加到队列 + $nextPageIndex = $pageIndex + 1; + $this->addNextPageToQueue($nextPageIndex, $pageSize); + Log::info('添加下一页任务到队列,页码:' . $nextPageIndex); + } + + return true; + } else { + $errorMsg = isset($response['msg']) ? $response['msg'] : '未知错误'; + Log::error('获取微信群聊消息列表失败:' . $errorMsg); + return false; + } + } + + /** + * 添加下一页任务到队列 + * @param int $pageIndex 页码 + * @param int $pageSize 每页大小 + */ + protected function addNextPageToQueue($pageIndex, $pageSize) + { + $data = [ + 'pageIndex' => $pageIndex, + 'pageSize' => $pageSize + ]; + + // 添加到队列,设置任务名为 message_chatroom_list + Queue::push(self::class, $data, 'message_chatroom_list'); + } +} \ No newline at end of file diff --git a/Server/application/job/MessageFriendsListJob.php b/Server/application/job/MessageFriendsListJob.php new file mode 100644 index 000000000..185d0d929 --- /dev/null +++ b/Server/application/job/MessageFriendsListJob.php @@ -0,0 +1,124 @@ +processMessageFriendsList($data, $job->attempts())) { + $job->delete(); + Log::info('好友消息列表任务执行成功,页码:' . $data['pageIndex']); + } else { + if ($job->attempts() > 3) { + // 超过重试次数,删除任务 + Log::error('好友消息列表任务执行失败,已超过重试次数,页码:' . $data['pageIndex']); + $job->delete(); + } else { + // 任务失败,重新放回队列 + Log::warning('好友消息列表任务执行失败,重试次数:' . $job->attempts() . ',页码:' . $data['pageIndex']); + $job->release(Config::get('queue.failed_delay', 10)); + } + } + } catch (\Exception $e) { + // 出现异常,记录日志 + Log::error('好友消息列表任务异常:' . $e->getMessage()); + if ($job->attempts() > 3) { + $job->delete(); + } else { + $job->release(Config::get('queue.failed_delay', 10)); + } + } + } + + /** + * 处理好友消息列表获取 + * @param array $data 任务数据 + * @param int $attempts 重试次数 + * @return bool + */ + protected function processMessageFriendsList($data, $attempts) + { + // 获取参数 + $pageIndex = isset($data['pageIndex']) ? $data['pageIndex'] : 0; + $pageSize = isset($data['pageSize']) ? $data['pageSize'] : 100; + + Log::info('开始获取好友消息列表,页码:' . $pageIndex . ',页大小:' . $pageSize); + + // 实例化控制器 + $messageController = new MessageController(); + + // 构建请求参数 + $params = [ + 'pageIndex' => $pageIndex, + 'pageSize' => $pageSize + ]; + + // 设置请求信息 + $request = request(); + $request->withGet($params); + + // 获取系统授权信息 + $authorization = AuthService::getSystemAuthorization(); + if (empty($authorization)) { + Log::error('获取系统授权信息失败'); + return false; + } + + + // 调用添加好友任务获取方法 + $result = $messageController->getFriendsList($pageIndex,$pageSize,$authorization,true); + $response = json_decode($result,true); + + + // 判断是否成功 + if ($response['code'] == 200) { + $data = $response['data']; + + // 判断是否有下一页 + if (!empty($data) && count($data['results']) > 0) { + // 有下一页,将下一页任务添加到队列 + $nextPageIndex = $pageIndex + 1; + $this->addNextPageToQueue($nextPageIndex, $pageSize); + Log::info('添加下一页任务到队列,页码:' . $nextPageIndex); + } + + return true; + } else { + $errorMsg = isset($response['msg']) ? $response['msg'] : '未知错误'; + Log::error('获取好友消息列表失败:' . $errorMsg); + return false; + } + } + + /** + * 添加下一页任务到队列 + * @param int $pageIndex 页码 + * @param int $pageSize 每页大小 + */ + protected function addNextPageToQueue($pageIndex, $pageSize) + { + $data = [ + 'pageIndex' => $pageIndex, + 'pageSize' => $pageSize + ]; + + // 添加到队列,设置任务名为 message_friends_list + Queue::push(self::class, $data, 'message_friends_list'); + } +} \ No newline at end of file diff --git a/Server/application/store/config/route.php b/Server/application/store/config/route.php index 4e0b1b94e..e683b0f02 100755 --- a/Server/application/store/config/route.php +++ b/Server/application/store/config/route.php @@ -30,4 +30,12 @@ Route::group('v1/store', function () { Route::get('switch-status', 'app\\store\\controller\\SystemConfigController@getSwitchStatus'); // 获取系统开关状态 Route::post('update-switch-status', 'app\\store\\controller\\SystemConfigController@updateSwitchStatus'); // 更新系统开关状态 }); + + + // 数据统计相关路由 + Route::group('statistics', function () { + Route::get('overview', 'app\\store\\controller\\StatisticsController@getOverview'); // 获取数据概览 + Route::get('customer-analysis', 'app\\store\\controller\\StatisticsController@getCustomerAnalysis'); // 获取客户分析数据 + Route::get('interaction-analysis', 'app\\store\\controller\\StatisticsController@getInteractionAnalysis'); // 获取互动分析数据 + }); })->middleware(['jwt']); \ No newline at end of file diff --git a/Server/application/store/controller/BaseController.php b/Server/application/store/controller/BaseController.php index 79e368570..5f236cd90 100755 --- a/Server/application/store/controller/BaseController.php +++ b/Server/application/store/controller/BaseController.php @@ -38,19 +38,18 @@ class BaseController extends Api $device = Db::name('device_user') ->alias('du') ->join('device d', 'd.id = du.deviceId','left') + ->join('wechat_account wa', 'd.id = wa.currentDeviceId','left') ->where([ 'du.userId' => $this->userInfo['id'], 'du.companyId' => $this->userInfo['companyId'] ]) - ->field('d.*') + ->field('d.*,wa.id as wechatAccountId,wa.wechatId,wa.alias') ->find(); - // 将设备信息存入缓存 if ($device) { Cache::set($cacheKey, $device, $this->cacheExpire); } } - $this->device = $device; } diff --git a/Server/application/store/controller/StatisticsController.php b/Server/application/store/controller/StatisticsController.php new file mode 100644 index 000000000..91fcb50b5 --- /dev/null +++ b/Server/application/store/controller/StatisticsController.php @@ -0,0 +1,392 @@ +userInfo['companyId']; + $wechatAccountId = $this->device['wechatAccountId']; + + // 获取时间范围 + $timeRange = $this->getTimeRange(); + $startTime = $timeRange['start_time']; + $endTime = $timeRange['end_time']; + $lastStartTime = $timeRange['last_start_time']; + $lastEndTime = $timeRange['last_end_time']; + + // 1. 总客户数 + $totalCustomers = WechatFriendModel::where(['wechatAccountId'=> $wechatAccountId]) + ->whereTime('createTime', '>=', $startTime) + ->whereTime('createTime', '<', $endTime) + ->count(); + + // 上期总客户数 + $lastTotalCustomers = WechatFriendModel::where(['wechatAccountId'=> $wechatAccountId]) + ->whereTime('createTime', '>=', $lastStartTime) + ->whereTime('createTime', '<', $lastEndTime) + ->count(); + + // 2. 新增客户数 + $newCustomers = WechatFriendModel::where(['wechatAccountId'=> $wechatAccountId]) + ->whereTime('createTime', '>=', $startTime) + ->whereTime('createTime', '<', $endTime) + ->count(); + + // 上期新增客户数 + $lastNewCustomers = WechatFriendModel::where(['wechatAccountId'=> $wechatAccountId]) + ->whereTime('createTime', '>=', $lastStartTime) + ->whereTime('createTime', '<', $lastEndTime) + ->count(); + + //3. 互动次数 + $interactionCount = WechatMessageModel::where(['wechatAccountId'=> $wechatAccountId]) + ->where('createTime', '>=', strtotime($startTime)) + ->where('createTime', '<', strtotime($endTime)) + ->count(); + + // 上期互动次数 + $lastInteractionCount = WechatMessageModel::where(['wechatAccountId'=> $wechatAccountId]) + ->where('createTime', '>=', strtotime($lastStartTime)) + ->where('createTime', '<', strtotime($lastEndTime)) + ->count(); + + + + + // 计算环比增长率 + $customerGrowth = $this->calculateGrowth($totalCustomers, $lastTotalCustomers); + $newCustomerGrowth = $this->calculateGrowth($newCustomers, $lastNewCustomers); + $interactionGrowth = $this->calculateGrowth($interactionCount, $lastInteractionCount); + $data = [ + 'total_customers' => [ + 'value' => $totalCustomers, + 'growth' => $customerGrowth + ], + 'new_customers' => [ + 'value' => $newCustomers, + 'growth' => $newCustomerGrowth + ], + 'interaction_count' => [ + 'value' => $interactionCount, + 'growth' => $interactionGrowth + ] + ]; + + return successJson($data); + } catch (\Exception $e) { + return errorJson('获取数据概览失败:' . $e->getMessage()); + } + } + + /** + * 获取客户分析数据 + */ + public function getCustomerAnalysis() + { + try { + $companyId = $this->userInfo['companyId']; + $wechatAccountId = $this->device['wechatAccountId']; + + // 获取时间范围 + $timeRange = $this->getTimeRange(); + $startTime = $timeRange['start_time']; + $endTime = $timeRange['end_time']; + + // 1. 客户增长趋势数据 + $totalCustomers = WechatFriendModel::where(['wechatAccountId'=> $wechatAccountId]) + ->whereTime('createTime', '<', $endTime) + ->count(); + + $newCustomers = WechatFriendModel::where(['wechatAccountId'=> $wechatAccountId]) + ->whereTime('createTime', '>=', $startTime) + ->whereTime('createTime', '<', $endTime) + ->count(); + + // 计算流失客户数(假设超过30天未互动的客户为流失客户) + $lostCustomers = WechatFriendModel::where(['wechatAccountId'=> $wechatAccountId,'isDeleted'=> 1]) + ->whereTime('deleteTime', '<', date('Y-m-d', strtotime('-30 days'))) + ->count(); + + // 2. 客户来源分布数据 + // 朋友推荐 + $friendRecommend = WechatFriendModel::where(['wechatAccountId'=> $wechatAccountId]) + ->whereIn('addFrom', [17, 1000017]) + ->count(); + + // 微信搜索 + $wechatSearch = WechatFriendModel::where(['wechatAccountId'=> $wechatAccountId]) + ->whereIn('addFrom', [3, 15, 1000003, 1000015]) + ->count(); + + // 微信群 + $wechatGroup = WechatFriendModel::where(['wechatAccountId'=> $wechatAccountId]) + ->whereIn('addFrom', [14, 1000014]) + ->count(); + + // 其他渠道(总数减去已知渠道) + $otherSource = $totalCustomers - $friendRecommend - $wechatSearch - $wechatGroup; + $otherSource = max(0, $otherSource); // 确保不会出现负数 + + // 计算百分比 + $calculatePercentage = function($value) use ($totalCustomers) { + if ($totalCustomers <= 0) return 0; + return round(($value / $totalCustomers) * 100, 2); + }; + + $sourceDistribution = [ + [ + 'name' => '朋友推荐', + 'value' => $calculatePercentage($friendRecommend) . '%', + 'count' => $friendRecommend + ], + [ + 'name' => '微信搜索', + 'value' => $calculatePercentage($wechatSearch) . '%', + 'count' => $wechatSearch + ], + [ + 'name' => '微信群', + 'value' => $calculatePercentage($wechatGroup) . '%', + 'count' => $wechatGroup + ], + [ + 'name' => '其他渠道', + 'value' => $calculatePercentage($otherSource) . '%', + 'count' => $otherSource + ] + ]; + + $data = [ + 'trend' => [ + 'total' => $totalCustomers, + 'new' => $newCustomers, + 'lost' => $lostCustomers + ], + 'source_distribution' => $sourceDistribution + ]; + + return successJson($data); + } catch (\Exception $e) { + return errorJson('获取客户分析数据失败:' . $e->getMessage()); + } + } + + /** + * 获取互动分析数据 + */ + public function getInteractionAnalysis() + { + try { + $companyId = $this->userInfo['companyId']; + $wechatAccountId = $this->device['wechatAccountId']; + + // 获取时间范围 + $timeRange = $this->getTimeRange(); + $startTime = $timeRange['start_time']; + $endTime = $timeRange['end_time']; + + // 转换为时间戳 + $startTimestamp = strtotime($startTime); + $endTimestamp = strtotime($endTime); + + // 1. 互动频率分析 + // 高频互动用户数(每天3次以上) + $highFrequencyUsers = WechatMessageModel::where(['wechatAccountId' => $wechatAccountId]) + ->where('createTime', '>=', $startTimestamp) + ->where('createTime', '<', $endTimestamp) + ->field('wechatFriendId, COUNT(*) as count') + ->group('wechatFriendId') + ->having('count > 3') + ->count(); + + // 中频互动用户数(每天1-3次) + $midFrequencyUsers = WechatMessageModel::where(['wechatAccountId' => $wechatAccountId]) + ->where('createTime', '>=', $startTimestamp) + ->where('createTime', '<', $endTimestamp) + ->field('wechatFriendId, COUNT(*) as count') + ->group('wechatFriendId') + ->having('count >= 1 AND count <= 3') + ->count(); + + // 低频互动用户数(仅有1次) + $lowFrequencyUsers = WechatMessageModel::where(['wechatAccountId' => $wechatAccountId]) + ->where('createTime', '>=', $startTimestamp) + ->where('createTime', '<', $endTimestamp) + ->field('wechatFriendId, COUNT(*) as count') + ->group('wechatFriendId') + ->having('count = 1') + ->count(); + + // 2. 互动内容分析 + // 文字消息数量 + $textMessages = WechatMessageModel::where([ + 'wechatAccountId' => $wechatAccountId, + 'msgType' => 1 + ]) + ->where('createTime', '>=', $startTimestamp) + ->where('createTime', '<', $endTimestamp) + ->count(); + + // 图片互动数量 + $imgInteractions = WechatMessageModel::where([ + 'wechatAccountId' => $wechatAccountId, + 'msgType' => 3 + ]) + ->where('createTime', '>=', $startTimestamp) + ->where('createTime', '<', $endTimestamp) + ->count(); + + // 群聊互动数量 + $groupInteractions = WechatMessageModel::where([ + 'wechatAccountId' => $wechatAccountId, + 'type' => 2 + ]) + ->where('createTime', '>=', $startTimestamp) + ->where('createTime', '<', $endTimestamp) + ->count(); + + // 产品咨询数量 (通过消息内容模糊查询) + $productInquiries = WechatMessageModel::where([ + 'wechatAccountId' => $wechatAccountId + ]) + ->where('createTime', '>=', $startTimestamp) + ->where('createTime', '<', $endTimestamp) + ->where('content', 'like', '%产品%') + ->whereOr('content', 'like', '%价格%') + ->whereOr('content', 'like', '%购买%') + ->whereOr('content', 'like', '%优惠%') + ->count(); + + // 构建返回数据 + $data = [ + 'frequency_analysis' => [ + 'high_frequency' => $highFrequencyUsers, + 'mid_frequency' => $midFrequencyUsers, + 'low_frequency' => $lowFrequencyUsers, + 'chart_data' => [ + ['name' => '高频互动', 'value' => $highFrequencyUsers], + ['name' => '中频互动', 'value' => $midFrequencyUsers], + ['name' => '低频互动', 'value' => $lowFrequencyUsers] + ] + ], + 'content_analysis' => [ + 'text_messages' => $textMessages, + 'img_interactions' => $imgInteractions, + 'group_interactions' => $groupInteractions, + 'product_inquiries' => $productInquiries, + 'chart_data' => [ + ['name' => '文字互动', 'value' => $textMessages], + ['name' => '图片互动', 'value' => $imgInteractions], + ['name' => '群聊互动', 'value' => $groupInteractions], + ['name' => '产品咨询', 'value' => $productInquiries] + ] + ] + ]; + + return successJson($data); + } catch (\Exception $e) { + return errorJson('获取互动分析数据失败:' . $e->getMessage()); + } + } + + /** + * 获取时间范围 + */ + private function getTimeRange() + { + // 可选:today, yesterday, this_week, last_week, this_month, this_quarter, this_year + $timeType = input('time_type', 'this_week'); + + switch ($timeType) { + case 'today': // 今日 + $startTime = date('Y-m-d'); + $endTime = date('Y-m-d', strtotime('+1 day')); + $lastStartTime = date('Y-m-d', strtotime('-1 day')); // 昨日 + $lastEndTime = $startTime; + break; + + case 'yesterday': // 昨日 + $startTime = date('Y-m-d', strtotime('-1 day')); + $endTime = date('Y-m-d'); + $lastStartTime = date('Y-m-d', strtotime('-2 day')); // 前日 + $lastEndTime = $startTime; + break; + + case 'this_week': // 本周 + $startTime = date('Y-m-d', strtotime('monday this week')); + $endTime = date('Y-m-d', strtotime('monday next week')); + $lastStartTime = date('Y-m-d', strtotime('monday last week')); // 上周一 + $lastEndTime = $startTime; + break; + + case 'last_week': // 上周 + $startTime = date('Y-m-d', strtotime('monday last week')); + $endTime = date('Y-m-d', strtotime('monday this week')); + $lastStartTime = date('Y-m-d', strtotime('monday last week', strtotime('last week'))); // 上上周一 + $lastEndTime = $startTime; + break; + + case 'this_month': // 本月 + $startTime = date('Y-m-01'); + $endTime = date('Y-m-d', strtotime(date('Y-m-01') . ' +1 month')); + $lastStartTime = date('Y-m-01', strtotime('-1 month')); // 上月初 + $lastEndTime = $startTime; + break; + + case 'this_quarter': // 本季度 + $month = date('n'); + $quarter = ceil($month / 3); + $startMonth = ($quarter - 1) * 3 + 1; + $startTime = date('Y-') . str_pad($startMonth, 2, '0', STR_PAD_LEFT) . '-01'; + $endTime = date('Y-m-d', strtotime($startTime . ' +3 month')); + // 上季度 + $lastStartTime = date('Y-m-d', strtotime($startTime . ' -3 month')); + $lastEndTime = $startTime; + break; + + case 'this_year': // 本年度 + $startTime = date('Y-01-01'); + $endTime = (date('Y') + 1) . '-01-01'; + $lastStartTime = (date('Y') - 1) . '-01-01'; // 去年初 + $lastEndTime = $startTime; + break; + + default: + $startTime = date('Y-m-d', strtotime('monday this week')); + $endTime = date('Y-m-d', strtotime('monday next week')); + $lastStartTime = date('Y-m-d', strtotime('monday last week')); + $lastEndTime = $startTime; + } + + return [ + 'start_time' => $startTime, + 'end_time' => $endTime, + 'last_start_time' => $lastStartTime, + 'last_end_time' => $lastEndTime + ]; + } + + /** + * 计算环比增长率 + */ + private function calculateGrowth($current, $last) + { + if ($last == 0) { + return $current > 0 ? 100 : 0; + } + return round((($current - $last) / $last) * 100, 1); + } +} \ No newline at end of file diff --git a/Server/application/store/model/WechatFriendModel.php b/Server/application/store/model/WechatFriendModel.php new file mode 100644 index 000000000..f0e376573 --- /dev/null +++ b/Server/application/store/model/WechatFriendModel.php @@ -0,0 +1,11 @@ +